6
0
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:
Grzegorz Dlugoszewski
2020-06-08 21:37:26 +02:00
parent 919359f26f
commit dfef6151d1
5 changed files with 72 additions and 12 deletions

View File

@@ -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"
) )

View File

@@ -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)
} }

View File

@@ -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,

View File

@@ -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

View File

@@ -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)
} }
} }
} }