From 8a79dcfd9fa9abebcecffe43bebd7b6af28c654b Mon Sep 17 00:00:00 2001 From: Grzegorz Dlugoszewski Date: Tue, 2 Jun 2020 16:46:10 +0200 Subject: [PATCH] Add checking what is the current branch and if HEAD is detached --- pkg/helpers_test.go | 46 ++++++++++++++++++++++++++++++++++++++++----- pkg/list.go | 6 ------ pkg/status.go | 23 +++++++++++++++++++++++ pkg/status_test.go | 24 +++++++++++++++++++++++ 4 files changed, 88 insertions(+), 11 deletions(-) diff --git a/pkg/helpers_test.go b/pkg/helpers_test.go index 1ed4a41..4b10d84 100644 --- a/pkg/helpers_test.go +++ b/pkg/helpers_test.go @@ -83,6 +83,19 @@ func newRepoWithClonedBranch(t *testing.T) *Repo { r := origin.clone(t) r.newBranch(t, "local") + r.checkoutBranch(t, "local") + + return r +} + +func newRepoWithDetachedHead(t *testing.T) *Repo { + r := newRepoWithCommit(t) + + r.writeFile(t, "new", "I'm a new file") + r.addFile(t, "new") + hash := r.newCommit(t, "new commit") + + r.checkoutHash(t, hash) return r } @@ -144,7 +157,7 @@ func newTempDir(t *testing.T) string { func (r *Repo) writeFile(t *testing.T, name string, content string) { wt, err := r.repo.Worktree() - checkFatal(t, errors.Wrap(err, "Failed getting workree")) + checkFatal(t, errors.Wrap(err, "Failed getting worktree")) file, err := wt.Filesystem.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) checkFatal(t, errors.Wrap(err, "Failed opening a file")) @@ -155,15 +168,15 @@ func (r *Repo) writeFile(t *testing.T, name string, content string) { func (r *Repo) addFile(t *testing.T, name string) { wt, err := r.repo.Worktree() - checkFatal(t, errors.Wrap(err, "Failed getting workree")) + checkFatal(t, errors.Wrap(err, "Failed getting worktree")) _, err = wt.Add(name) checkFatal(t, errors.Wrap(err, "Failed adding file to index")) } -func (r *Repo) newCommit(t *testing.T, msg string) { +func (r *Repo) newCommit(t *testing.T, msg string) plumbing.Hash { wt, err := r.repo.Worktree() - checkFatal(t, errors.Wrap(err, "Failed getting workree")) + checkFatal(t, errors.Wrap(err, "Failed getting worktree")) opts := &git.CommitOptions{ Author: &object.Signature{ @@ -173,8 +186,9 @@ func (r *Repo) newCommit(t *testing.T, msg string) { }, } - _, err = wt.Commit(msg, opts) + hash, err := wt.Commit(msg, opts) checkFatal(t, errors.Wrap(err, "Failed creating commit")) + return hash } func (r *Repo) newBranch(t *testing.T, name string) { @@ -203,6 +217,28 @@ func (r *Repo) fetch(t *testing.T) { checkFatal(t, err) } +func (r *Repo) checkoutBranch(t *testing.T, name string) { + wt, err := r.repo.Worktree() + checkFatal(t, errors.Wrap(err, "Failed getting worktree")) + + opts := &git.CheckoutOptions{ + Branch: plumbing.NewBranchReferenceName(name), + } + err = wt.Checkout(opts) + checkFatal(t, errors.Wrap(err, "Failed checking out branch")) +} + +func (r *Repo) checkoutHash(t *testing.T, hash plumbing.Hash) { + wt, err := r.repo.Worktree() + checkFatal(t, errors.Wrap(err, "Failed getting worktree")) + + opts := &git.CheckoutOptions{ + Hash: hash, + } + err = wt.Checkout(opts) + checkFatal(t, errors.Wrap(err, "Failed checking out hash")) +} + func checkFatal(t *testing.T, err error) { if err != nil { t.Fatalf("%+v", err) diff --git a/pkg/list.go b/pkg/list.go index 68501d5..515106d 100644 --- a/pkg/list.go +++ b/pkg/list.go @@ -140,12 +140,6 @@ const ( ColorYellow = "\033[1;33m%s\033[0m" ) -const ( - StatusOk = "ok" - StatusUncommitted = "uncommitted" - StatusUntracked = "untracked" -) - func PrintRepoStatus(repo *Repo) string { status := fmt.Sprintf(ColorGreen, StatusOk) diff --git a/pkg/status.go b/pkg/status.go index 9ea7f3b..9e362b9 100644 --- a/pkg/status.go +++ b/pkg/status.go @@ -13,9 +13,18 @@ import ( "github.com/pkg/errors" ) +const ( + StatusUnknown = "unknown" + StatusDetached = "detached HEAD" + StatusOk = "ok" + StatusUncommitted = "uncommitted" + StatusUntracked = "untracked" +) + type RepoStatus struct { HasUntrackedFiles bool HasUncommittedChanges bool + Current string Branches []*BranchStatus } @@ -54,6 +63,7 @@ func (r *Repo) LoadStatus() error { r.Status.HasUncommittedChanges = hasUncommitted(status) r.Status.HasUntrackedFiles = hasUntracked(status) + r.Status.Current = currentBranch(r) err = r.loadBranchesStatus() if err != nil { @@ -91,6 +101,19 @@ func hasUncommitted(status git.Status) bool { return false } +func currentBranch(r *Repo) string { + head, err := r.repo.Head() + if err != nil { + return StatusUnknown + } + + if head.Name().Short() == plumbing.HEAD.String() { + return StatusDetached + } + + return head.Name().Short() +} + func (r *Repo) loadBranchesStatus() error { iter, err := r.repo.Branches() if err != nil { diff --git a/pkg/status_test.go b/pkg/status_test.go index 9f9ff8e..aa3b4cd 100644 --- a/pkg/status_test.go +++ b/pkg/status_test.go @@ -13,21 +13,25 @@ func TestStatus(t *testing.T) { {newRepoEmpty, &RepoStatus{ HasUntrackedFiles: false, HasUncommittedChanges: false, + Current: StatusUnknown, Branches: nil, }}, {newRepoWithUntracked, &RepoStatus{ HasUntrackedFiles: true, HasUncommittedChanges: false, + Current: StatusUnknown, Branches: nil, }}, {newRepoWithStaged, &RepoStatus{ HasUntrackedFiles: false, HasUncommittedChanges: true, + Current: StatusUnknown, Branches: nil, }}, {newRepoWithCommit, &RepoStatus{ HasUntrackedFiles: false, HasUncommittedChanges: false, + Current: "master", Branches: []*BranchStatus{ { Name: "master", @@ -40,6 +44,7 @@ func TestStatus(t *testing.T) { {newRepoWithModified, &RepoStatus{ HasUntrackedFiles: false, HasUncommittedChanges: true, + Current: "master", Branches: []*BranchStatus{ { Name: "master", @@ -52,6 +57,7 @@ func TestStatus(t *testing.T) { {newRepoWithIgnored, &RepoStatus{ HasUntrackedFiles: false, HasUncommittedChanges: false, + Current: "master", Branches: []*BranchStatus{ { Name: "master", @@ -64,6 +70,7 @@ func TestStatus(t *testing.T) { {newRepoWithLocalBranch, &RepoStatus{ HasUntrackedFiles: false, HasUncommittedChanges: false, + Current: "master", Branches: []*BranchStatus{ { Name: "local", @@ -81,6 +88,7 @@ func TestStatus(t *testing.T) { {newRepoWithClonedBranch, &RepoStatus{ HasUntrackedFiles: false, HasUncommittedChanges: false, + Current: "local", Branches: []*BranchStatus{ { Name: "local", @@ -95,9 +103,23 @@ func TestStatus(t *testing.T) { }, }, }}, + {newRepoWithDetachedHead, &RepoStatus{ + HasUntrackedFiles: false, + HasUncommittedChanges: false, + Current: StatusDetached, + Branches: []*BranchStatus{ + { + Name: "master", + Upstream: "", + NeedsPull: false, + NeedsPush: false, + }, + }, + }}, {newRepoWithBranchAhead, &RepoStatus{ HasUntrackedFiles: false, HasUncommittedChanges: false, + Current: "master", Branches: []*BranchStatus{ { Name: "master", @@ -110,6 +132,7 @@ func TestStatus(t *testing.T) { {newRepoWithBranchBehind, &RepoStatus{ HasUntrackedFiles: false, HasUncommittedChanges: false, + Current: "master", Branches: []*BranchStatus{ { Name: "master", @@ -122,6 +145,7 @@ func TestStatus(t *testing.T) { {newRepoWithBranchAheadAndBehind, &RepoStatus{ HasUntrackedFiles: false, HasUncommittedChanges: false, + Current: "master", Branches: []*BranchStatus{ { Name: "master",