Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitaly.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Fargher <jfargher@gitlab.com>2021-11-12 06:19:28 +0300
committerJames Fargher <jfargher@gitlab.com>2021-11-15 04:41:13 +0300
commitfbe4bbf8651afefba566455f88738908a440270f (patch)
treec55748b1c271dfa961b4dacadf6d8efa8cb80b3e
parentb1d5dafcf488f8c48531e2a82dd7a568f01a3b7b (diff)
git: Implement HEAD guessing logicbackup_set_default_branch
-rw-r--r--internal/git/reference.go48
-rw-r--r--internal/git/reference_test.go73
2 files changed, 121 insertions, 0 deletions
diff --git a/internal/git/reference.go b/internal/git/reference.go
index 96a32190d..5966cc5c5 100644
--- a/internal/git/reference.go
+++ b/internal/git/reference.go
@@ -3,6 +3,7 @@ package git
import (
"bytes"
"context"
+ "errors"
"strings"
)
@@ -120,3 +121,50 @@ func CheckRefFormat(ctx context.Context, gitCmdFactory CommandFactory, refName s
return true, nil
}
+
+// GuessHead tries to guess what branch HEAD would be pointing at given a list
+// of references. The references are assumed to be ordered by name.
+//
+// This function should match the corresponding function in git:
+// https://github.com/git/git/blob/2a97289ad8b103625d3a1a12f66c27f50df822ce/remote.c#L2198
+func GuessHead(refs []Reference) (ReferenceName, error) {
+ head := findRefByName(refs, "HEAD")
+ if head == nil {
+ return "", errors.New("missing HEAD ref")
+ }
+ if head.IsSymbolic {
+ return ReferenceName(head.Target), nil
+ }
+
+ main := findRefByName(refs, ReferenceName(DefaultRef))
+ if main != nil && head.Target == main.Target {
+ return main.Name, nil
+ }
+
+ master := findRefByName(refs, ReferenceName(LegacyDefaultRef))
+ if master != nil && head.Target == master.Target {
+ return master.Name, nil
+ }
+
+ for i := range refs {
+ if _, ok := refs[i].Name.Branch(); !ok {
+ continue
+ }
+ if refs[i].Target == head.Target {
+ return refs[i].Name, nil
+ }
+ }
+
+ return "", errors.New("no matching ref")
+}
+
+// findRefByName filters through refs and returns the first ref where name
+// matches exactly. nil is returned when no match is found.
+func findRefByName(refs []Reference, name ReferenceName) *Reference {
+ for i := range refs {
+ if refs[i].Name == name {
+ return &refs[i]
+ }
+ }
+ return nil
+}
diff --git a/internal/git/reference_test.go b/internal/git/reference_test.go
index 745b182da..05da8bf48 100644
--- a/internal/git/reference_test.go
+++ b/internal/git/reference_test.go
@@ -131,3 +131,76 @@ func TestReferenceName_Branch(t *testing.T) {
})
}
}
+
+func TestGuessHead(t *testing.T) {
+ for _, tc := range []struct {
+ desc string
+ refs []git.Reference
+ expectedErr string
+ expectedHead git.ReferenceName
+ }{
+ {
+ desc: "no refs",
+ expectedErr: "missing HEAD ref",
+ },
+ {
+ desc: "symbolic HEAD in refs",
+ refs: []git.Reference{
+ git.NewSymbolicReference("HEAD", "refs/heads/banana"),
+ git.NewReference("refs/heads/master", "5da601ef10e314884bbade9d5b063be37579ccf9"),
+ },
+ expectedHead: "refs/heads/banana",
+ },
+ {
+ desc: "matching default branch",
+ refs: []git.Reference{
+ git.NewReference("HEAD", "5da601ef10e314884bbade9d5b063be37579ccf9"),
+ git.NewReference("refs/heads/apple", "5da601ef10e314884bbade9d5b063be37579ccf9"),
+ git.NewReference("refs/heads/banana", "5da601ef10e314884bbade9d5b063be37579ccf9"),
+ git.NewReference("refs/heads/main", "5da601ef10e314884bbade9d5b063be37579ccf9"),
+ },
+ expectedHead: "refs/heads/main",
+ },
+ {
+ desc: "matching legacy default branch",
+ refs: []git.Reference{
+ git.NewReference("HEAD", "5da601ef10e314884bbade9d5b063be37579ccf9"),
+ git.NewReference("refs/heads/apple", "5da601ef10e314884bbade9d5b063be37579ccf9"),
+ git.NewReference("refs/heads/banana", "5da601ef10e314884bbade9d5b063be37579ccf9"),
+ git.NewReference("refs/heads/master", "5da601ef10e314884bbade9d5b063be37579ccf9"),
+ },
+ expectedHead: "refs/heads/master",
+ },
+ {
+ desc: "other matches",
+ refs: []git.Reference{
+ git.NewReference("HEAD", "5da601ef10e314884bbade9d5b063be37579ccf9"),
+ git.NewReference("refs/heads/apple", "5da601ef10e314884bbade9d5b063be37579ccf9"),
+ git.NewReference("refs/heads/banana", "5da601ef10e314884bbade9d5b063be37579ccf9"),
+ git.NewReference("refs/heads/carrot", "5da601ef10e314884bbade9d5b063be37579ccf9"),
+ git.NewReference("refs/heads/main", "5da601ef10e314884bbade9d5b063be37579ccf0"),
+ },
+ expectedHead: "refs/heads/apple",
+ },
+ {
+ desc: "no matches",
+ refs: []git.Reference{
+ git.NewReference("HEAD", "5da601ef10e314884bbade9d5b063be37579ccf9"),
+ git.NewReference("refs/heads/apple", "5da601ef10e314884bbade9d5b063be37579ccf0"),
+ git.NewReference("refs/heads/banana", "5da601ef10e314884bbade9d5b063be37579ccf0"),
+ git.NewReference("refs/heads/carrot", "5da601ef10e314884bbade9d5b063be37579ccf0"),
+ },
+ expectedErr: "no matching ref",
+ },
+ } {
+ t.Run(tc.desc, func(t *testing.T) {
+ head, err := git.GuessHead(tc.refs)
+ if tc.expectedErr == "" {
+ require.NoError(t, err)
+ } else {
+ require.EqualError(t, err, tc.expectedErr)
+ }
+ require.Equal(t, tc.expectedHead, head)
+ })
+ }
+}