Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
testdata/commits_on_branch/
testdata/git_tags/
testdata/annotated_git_tags_mix/
testdata/detached_head/
2 changes: 1 addition & 1 deletion branch_diff_commits.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ func (g *Git) BranchDiffCommits(branchA string, branchB string) ([]Hash, error)
// The ^branchB syntax excludes all commits reachable from branchB
output, err := g.runGitCommand("log", "--format=%H", branchA, "^"+branchB)
if err != nil {
return nil, fmt.Errorf("Failed comparing branches %v and %v: %v", branchA, branchB, err)
return nil, fmt.Errorf("failed comparing branches %v and %v: %v", branchA, branchB, err)
}

var diffCommits []Hash
Expand Down
22 changes: 22 additions & 0 deletions branch_diff_commits_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,25 @@ func TestBranchDiffCommitsWithMasterMerge(t *testing.T) {
assert.Equal(t, err, nil)

}

func TestBranchDiffCommitsDetachedHead(t *testing.T) {
testGit, err := OpenGit("./testdata/detached_head")
assert.NoError(t, err)

// Verify we're in detached HEAD state
currentBranch, err := testGit.CurrentBranch()
assert.NoError(t, err)
assert.Equal(t, "HEAD", currentBranch.Name())

// BranchDiffCommits should work even in detached HEAD state
// Compare origin/master (which is ahead) to HEAD (which is at second commit)
commits, err := testGit.BranchDiffCommits("origin/master", "HEAD")

assert.NoError(t, err)
// origin/master has one commit ahead of HEAD (the third commit)
assert.Equal(t, 1, len(commits))

commit, err := testGit.Commit(commits[0])
assert.NoError(t, err)
assert.Equal(t, "third commit\n", commit.Message)
}
31 changes: 31 additions & 0 deletions commits_between_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,34 @@ func TestToFromEqual(t *testing.T) {
assert.Equal(t, 0, len(commits))
assert.NoError(t, err)
}

func TestCommitsBetweenDetachedHead(t *testing.T) {
testGit, err := OpenGit("./testdata/detached_head")
assert.NoError(t, err)

// Verify we're in detached HEAD state
currentBranch, err := testGit.CurrentBranch()
assert.NoError(t, err)
assert.Equal(t, "HEAD", currentBranch.Name())

// Get HEAD commit hash (second commit)
headHash := currentBranch.Hash()

// Get origin/master commit hash (third commit)
masterHashStr, err := testGit.runGitCommand("rev-parse", "origin/master")
assert.NoError(t, err)
masterHash, err := NewHash(masterHashStr)
assert.NoError(t, err)

// CommitsBetween should work even in detached HEAD state
// Get commits between HEAD (second commit) and origin/master (third commit)
commits, err := testGit.CommitsBetween(masterHash, headHash)

assert.NoError(t, err)
// Should have 1 commit (the third commit)
assert.Equal(t, 1, len(commits))

commit, err := testGit.Commit(commits[0])
assert.NoError(t, err)
assert.Equal(t, "third commit\n", commit.Message)
}
29 changes: 29 additions & 0 deletions commits_on_branch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,32 @@ func TestCommitsOnBranch(t *testing.T) {

assert.Equal(t, "test commit on master\n", lastCommit.Message)
}

func TestCommitsOnBranchDetachedHead(t *testing.T) {
testGit, err := OpenGit("./testdata/detached_head")
assert.NoError(t, err)

// Verify we're in detached HEAD state
currentBranch, err := testGit.CurrentBranch()
assert.NoError(t, err)
assert.Equal(t, "HEAD", currentBranch.Name())

// Get HEAD commit hash
headHash := currentBranch.Hash()

// CommitsOnBranch should work even in detached HEAD state
// It takes a commit hash, so HEAD state doesn't matter
commits, err := testGit.CommitsOnBranch(headHash)

assert.NoError(t, err)
// Should have 2 commits (second commit and first commit)
assert.Equal(t, 2, len(commits))

commit, err := testGit.Commit(commits[0])
assert.NoError(t, err)
assert.Equal(t, "second commit\n", commit.Message)

lastCommit, err := testGit.Commit(commits[1])
assert.NoError(t, err)
assert.Equal(t, "first commit\n", lastCommit.Message)
}
16 changes: 9 additions & 7 deletions current_branch.go
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
package git

// CurrentBranch returns the reference HEAD is at right now
// CurrentBranch returns the reference HEAD is at right now.
// In detached HEAD state, it returns a reference with name "HEAD".
func (g *Git) CurrentBranch() (*Reference, error) {
// Get the symbolic ref name
refName, err := g.runGitCommand("symbolic-ref", "HEAD")
// Get the commit hash first (works in both normal and detached HEAD state)
hashStr, err := g.runGitCommand("rev-parse", "HEAD")
if err != nil {
return nil, err
}

// Get the commit hash
hashStr, err := g.runGitCommand("rev-parse", "HEAD")
hash, err := NewHash(hashStr)
if err != nil {
return nil, err
}

hash, err := NewHash(hashStr)
// Try to get the symbolic ref name (fails in detached HEAD state)
refName, err := g.runGitCommand("symbolic-ref", "HEAD")
if err != nil {
return nil, err
// In detached HEAD state, use "HEAD" as the reference name
refName = "HEAD"
}

return NewReference(refName, hash), nil
Expand Down
13 changes: 13 additions & 0 deletions current_branch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,16 @@ func TestCurrentBranch(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, "refs/heads/my-branch", currentBranch.Name())
}

func TestCurrentBranchDetachedHead(t *testing.T) {
testGit, err := OpenGit("./testdata/detached_head")
assert.NoError(t, err)

currentBranch, err := testGit.CurrentBranch()

assert.NoError(t, err)
assert.Equal(t, "HEAD", currentBranch.Name())

// Verify it has a valid commit hash
assert.NotEmpty(t, currentBranch.Hash().String())
}
16 changes: 16 additions & 0 deletions latest_commit_on_branch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,19 @@ func TestLatestCommitOnBranch(t *testing.T) {
assert.Equal(t, "third commit on new branch\n", commit.Message)
assert.Equal(t, err, nil)
}

func TestLatestCommitOnBranchDetachedHead(t *testing.T) {
testGit, err := OpenGit("./testdata/detached_head")
assert.NoError(t, err)

// Verify we're in detached HEAD state
currentBranch, err := testGit.CurrentBranch()
assert.NoError(t, err)
assert.Equal(t, "HEAD", currentBranch.Name())

// LatestCommitOnBranch should work even in detached HEAD state
commit, err := testGit.LatestCommitOnBranch("origin/master")

assert.NoError(t, err)
assert.Equal(t, "third commit\n", commit.Message)
}
Binary file added testdata/detached_head.bundle
Binary file not shown.
5 changes: 5 additions & 0 deletions testdata/setup_test_repos.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,8 @@ echo 'testdata/annotated_git_tags_mix/ directory does not exist at the root; cre
rm -rf annotated_git_tags_mix
git clone annotated_git_tags_mix.bundle
echo 'done'

echo 'testdata/detached_head/ directory does not exist at the root; creating...'
rm -rf detached_head
git clone detached_head.bundle
echo 'done'