mirror of
https://github.com/grdl/git-get.git
synced 2026-02-10 09:04:25 +00:00
Add a --branch flag that specifies which branch or tag to check out after cloning
This commit is contained in:
@@ -23,6 +23,8 @@ const (
|
|||||||
DefPrivateKey = "id_rsa"
|
DefPrivateKey = "id_rsa"
|
||||||
KeyOutput = "out"
|
KeyOutput = "out"
|
||||||
DefOutput = OutFlat
|
DefOutput = OutFlat
|
||||||
|
KeyBranch = "branch"
|
||||||
|
DefBranch = "master"
|
||||||
KeyFetch = "fetch"
|
KeyFetch = "fetch"
|
||||||
KeyList = "list"
|
KeyList = "list"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -34,12 +34,14 @@ func init() {
|
|||||||
cmd.PersistentFlags().StringP(cfg.KeyReposRoot, "r", "", "repos root")
|
cmd.PersistentFlags().StringP(cfg.KeyReposRoot, "r", "", "repos root")
|
||||||
cmd.PersistentFlags().StringP(cfg.KeyPrivateKey, "p", "", "SSH private key path")
|
cmd.PersistentFlags().StringP(cfg.KeyPrivateKey, "p", "", "SSH private key path")
|
||||||
cmd.PersistentFlags().StringP(cfg.KeyOutput, "o", cfg.DefOutput, "output format.")
|
cmd.PersistentFlags().StringP(cfg.KeyOutput, "o", cfg.DefOutput, "output format.")
|
||||||
|
cmd.PersistentFlags().StringP(cfg.KeyBranch, "b", cfg.DefBranch, "Branch (or tag) to checkout after cloning")
|
||||||
|
|
||||||
viper.BindPFlag(cfg.KeyList, cmd.PersistentFlags().Lookup(cfg.KeyList))
|
viper.BindPFlag(cfg.KeyList, cmd.PersistentFlags().Lookup(cfg.KeyList))
|
||||||
viper.BindPFlag(cfg.KeyFetch, cmd.PersistentFlags().Lookup(cfg.KeyFetch))
|
viper.BindPFlag(cfg.KeyFetch, cmd.PersistentFlags().Lookup(cfg.KeyFetch))
|
||||||
viper.BindPFlag(cfg.KeyReposRoot, cmd.PersistentFlags().Lookup(cfg.KeyReposRoot))
|
viper.BindPFlag(cfg.KeyReposRoot, cmd.PersistentFlags().Lookup(cfg.KeyReposRoot))
|
||||||
viper.BindPFlag(cfg.KeyPrivateKey, cmd.PersistentFlags().Lookup(cfg.KeyReposRoot))
|
viper.BindPFlag(cfg.KeyPrivateKey, cmd.PersistentFlags().Lookup(cfg.KeyReposRoot))
|
||||||
viper.BindPFlag(cfg.KeyOutput, cmd.PersistentFlags().Lookup(cfg.KeyOutput))
|
viper.BindPFlag(cfg.KeyOutput, cmd.PersistentFlags().Lookup(cfg.KeyOutput))
|
||||||
|
viper.BindPFlag(cfg.KeyBranch, cmd.PersistentFlags().Lookup(cfg.KeyBranch))
|
||||||
}
|
}
|
||||||
|
|
||||||
func Run(cmd *cobra.Command, args []string) {
|
func Run(cmd *cobra.Command, args []string) {
|
||||||
@@ -74,9 +76,10 @@ func Run(cmd *cobra.Command, args []string) {
|
|||||||
|
|
||||||
url, err := path.ParseURL(args[0])
|
url, err := path.ParseURL(args[0])
|
||||||
exitIfError(err)
|
exitIfError(err)
|
||||||
repoPath := pathpkg.Join(root, path.URLToPath(url))
|
|
||||||
|
|
||||||
_, err = git.CloneRepo(url, repoPath, false)
|
branch := viper.GetString(cfg.KeyBranch)
|
||||||
|
repoPath := pathpkg.Join(root, path.URLToPath(url))
|
||||||
|
_, err = git.CloneRepo(url, repoPath, branch, false)
|
||||||
exitIfError(err)
|
exitIfError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
13
git/repo.go
13
git/repo.go
@@ -4,6 +4,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"git-get/cfg"
|
"git-get/cfg"
|
||||||
|
|
||||||
|
"github.com/go-git/go-git/v5/plumbing"
|
||||||
|
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/url"
|
"net/url"
|
||||||
@@ -24,7 +26,7 @@ type Repo struct {
|
|||||||
Status *RepoStatus
|
Status *RepoStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
func CloneRepo(url *url.URL, path string, quiet bool) (*Repo, error) {
|
func CloneRepo(url *url.URL, path string, branch string, quiet bool) (*Repo, error) {
|
||||||
var progress io.Writer
|
var progress io.Writer
|
||||||
if !quiet {
|
if !quiet {
|
||||||
progress = os.Stdout
|
progress = os.Stdout
|
||||||
@@ -40,11 +42,18 @@ func CloneRepo(url *url.URL, path string, quiet bool) (*Repo, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If branch name is actually a tag (ie. is prefixed with refs/tags) - check out that tag.
|
||||||
|
// Otherwise, assume it's a branch name and check it out.
|
||||||
|
refName := plumbing.ReferenceName(branch)
|
||||||
|
if !refName.IsTag() {
|
||||||
|
refName = plumbing.NewBranchReferenceName(branch)
|
||||||
|
}
|
||||||
|
|
||||||
opts := &git.CloneOptions{
|
opts := &git.CloneOptions{
|
||||||
URL: url.String(),
|
URL: url.String(),
|
||||||
Auth: auth,
|
Auth: auth,
|
||||||
RemoteName: git.DefaultRemoteName,
|
RemoteName: git.DefaultRemoteName,
|
||||||
ReferenceName: "",
|
ReferenceName: refName,
|
||||||
SingleBranch: false,
|
SingleBranch: false,
|
||||||
NoCheckout: false,
|
NoCheckout: false,
|
||||||
Depth: 0,
|
Depth: 0,
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ func newRepoWithLocalBranch(t *testing.T) *Repo {
|
|||||||
func newRepoWithClonedBranch(t *testing.T) *Repo {
|
func newRepoWithClonedBranch(t *testing.T) *Repo {
|
||||||
origin := newRepoWithCommit(t)
|
origin := newRepoWithCommit(t)
|
||||||
|
|
||||||
r := origin.clone(t)
|
r := origin.clone(t, "master")
|
||||||
r.newBranch(t, "local")
|
r.newBranch(t, "local")
|
||||||
r.checkoutBranch(t, "local")
|
r.checkoutBranch(t, "local")
|
||||||
|
|
||||||
@@ -105,7 +105,7 @@ func newRepoWithDetachedHead(t *testing.T) *Repo {
|
|||||||
func newRepoWithBranchAhead(t *testing.T) *Repo {
|
func newRepoWithBranchAhead(t *testing.T) *Repo {
|
||||||
origin := newRepoWithCommit(t)
|
origin := newRepoWithCommit(t)
|
||||||
|
|
||||||
r := origin.clone(t)
|
r := origin.clone(t, "master")
|
||||||
r.writeFile(t, "new", "I'm a new file")
|
r.writeFile(t, "new", "I'm a new file")
|
||||||
r.addFile(t, "new")
|
r.addFile(t, "new")
|
||||||
r.newCommit(t, "new commit")
|
r.newCommit(t, "new commit")
|
||||||
@@ -116,7 +116,7 @@ func newRepoWithBranchAhead(t *testing.T) *Repo {
|
|||||||
func newRepoWithBranchBehind(t *testing.T) *Repo {
|
func newRepoWithBranchBehind(t *testing.T) *Repo {
|
||||||
origin := newRepoWithCommit(t)
|
origin := newRepoWithCommit(t)
|
||||||
|
|
||||||
r := origin.clone(t)
|
r := origin.clone(t, "master")
|
||||||
|
|
||||||
origin.writeFile(t, "origin.new", "I'm a new file on origin")
|
origin.writeFile(t, "origin.new", "I'm a new file on origin")
|
||||||
origin.addFile(t, "origin.new")
|
origin.addFile(t, "origin.new")
|
||||||
@@ -130,7 +130,7 @@ func newRepoWithBranchBehind(t *testing.T) *Repo {
|
|||||||
func newRepoWithBranchAheadAndBehind(t *testing.T) *Repo {
|
func newRepoWithBranchAheadAndBehind(t *testing.T) *Repo {
|
||||||
origin := newRepoWithCommit(t)
|
origin := newRepoWithCommit(t)
|
||||||
|
|
||||||
r := origin.clone(t)
|
r := origin.clone(t, "master")
|
||||||
r.writeFile(t, "local.new", "local 1")
|
r.writeFile(t, "local.new", "local 1")
|
||||||
r.addFile(t, "local.new")
|
r.addFile(t, "local.new")
|
||||||
r.newCommit(t, "1st local commit")
|
r.newCommit(t, "1st local commit")
|
||||||
@@ -155,6 +155,22 @@ func newRepoWithBranchAheadAndBehind(t *testing.T) *Repo {
|
|||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newRepoWithCheckedOutBranch(t *testing.T) *Repo {
|
||||||
|
origin := newRepoWithCommit(t)
|
||||||
|
origin.newBranch(t, "feature/branch1")
|
||||||
|
|
||||||
|
r := origin.clone(t, "feature/branch1")
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func newRepoWithCheckedOutTag(t *testing.T) *Repo {
|
||||||
|
origin := newRepoWithCommit(t)
|
||||||
|
origin.newTag(t, "v1.0.0")
|
||||||
|
|
||||||
|
r := origin.clone(t, "refs/tags/v1.0.0")
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
func newTempDir(t *testing.T) string {
|
func newTempDir(t *testing.T) string {
|
||||||
dir, err := ioutil.TempDir("", "git-get-repo-")
|
dir, err := ioutil.TempDir("", "git-get-repo-")
|
||||||
checkFatal(t, errors.Wrap(err, "Failed creating test repo directory"))
|
checkFatal(t, errors.Wrap(err, "Failed creating test repo directory"))
|
||||||
@@ -216,12 +232,22 @@ func (r *Repo) newBranch(t *testing.T, name string) {
|
|||||||
checkFatal(t, err)
|
checkFatal(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repo) clone(t *testing.T) *Repo {
|
func (r *Repo) newTag(t *testing.T, name string) {
|
||||||
|
head, err := r.Head()
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
ref := plumbing.NewHashReference(plumbing.NewTagReferenceName(name), head.Hash())
|
||||||
|
|
||||||
|
err = r.Storer.SetReference(ref)
|
||||||
|
checkFatal(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Repo) clone(t *testing.T, branch string) *Repo {
|
||||||
dir := newTempDir(t)
|
dir := newTempDir(t)
|
||||||
repoURL, err := url.Parse("file://" + r.Path)
|
repoURL, err := url.Parse("file://" + r.Path)
|
||||||
checkFatal(t, err)
|
checkFatal(t, err)
|
||||||
|
|
||||||
repo, err := CloneRepo(repoURL, dir, true)
|
repo, err := CloneRepo(repoURL, dir, branch, true)
|
||||||
checkFatal(t, err)
|
checkFatal(t, err)
|
||||||
|
|
||||||
return repo
|
return repo
|
||||||
|
|||||||
@@ -155,16 +155,36 @@ func TestStatus(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
|
{newRepoWithCheckedOutBranch, &RepoStatus{
|
||||||
|
HasUntrackedFiles: false,
|
||||||
|
HasUncommittedChanges: false,
|
||||||
|
CurrentBranch: "feature/branch1",
|
||||||
|
Branches: []*BranchStatus{
|
||||||
|
{
|
||||||
|
Name: "feature/branch1",
|
||||||
|
Upstream: "origin/feature/branch1",
|
||||||
|
Behind: 0,
|
||||||
|
Ahead: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
{newRepoWithCheckedOutTag, &RepoStatus{
|
||||||
|
HasUntrackedFiles: false,
|
||||||
|
HasUncommittedChanges: false,
|
||||||
|
// TODO: is this correct? Can we show tag name instead of "detached HEAD"?
|
||||||
|
CurrentBranch: StatusDetached,
|
||||||
|
Branches: nil,
|
||||||
|
}},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for i, test := range tests {
|
||||||
repo := test.makeTestRepo(t)
|
repo := test.makeTestRepo(t)
|
||||||
|
|
||||||
err := repo.LoadStatus()
|
err := repo.LoadStatus()
|
||||||
checkFatal(t, err)
|
checkFatal(t, err)
|
||||||
|
|
||||||
if !reflect.DeepEqual(repo.Status, test.want) {
|
if !reflect.DeepEqual(repo.Status, test.want) {
|
||||||
t.Errorf("Wrong repo status, got: %+v; want: %+v", repo.Status, test.want)
|
t.Errorf("Failed test case %d, got: %+v; want: %+v", i, repo.Status, test.want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user