From 6028094e6bb94c562554d4abc7f0a702fcb1c2b8 Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Thu, 30 Nov 2023 22:07:50 -0800 Subject: [PATCH] gitutil: find default remote by tracking branch Using this command resolves remote based on remote tracking branch of the curently selected branch and should be more precise in case we can't predict if user uses origin to mark upstream or their fork. Signed-off-by: Tonis Tiigi --- util/gitutil/gitutil.go | 24 ++++++++++++++++++++++- util/gitutil/gitutil_test.go | 38 ++++++++++++++++++++++++++++++++++-- util/gitutil/testutil.go | 9 +++++++++ 3 files changed, 68 insertions(+), 3 deletions(-) diff --git a/util/gitutil/gitutil.go b/util/gitutil/gitutil.go index 22aa72ee0094..c781311e19ec 100644 --- a/util/gitutil/gitutil.go +++ b/util/gitutil/gitutil.go @@ -78,7 +78,13 @@ func (c *Git) GitDir() (string, error) { } func (c *Git) RemoteURL() (string, error) { - // Try to get the remote URL from the origin remote first + // Try default remote based on remote tracking branch + if remote, err := c.currentRemote(); err == nil && remote != "" { + if ru, err := c.clean(c.run("remote", "get-url", remote)); err == nil && ru != "" { + return stripCredentials(ru), nil + } + } + // Next try to get the remote URL from the origin remote first if ru, err := c.clean(c.run("remote", "get-url", "origin")); err == nil && ru != "" { return stripCredentials(ru), nil } @@ -149,6 +155,22 @@ func (c *Git) clean(out string, err error) (string, error) { return out, err } +func (c *Git) currentRemote() (string, error) { + symref, err := c.clean(c.run("symbolic-ref", "-q", "HEAD")) + if err != nil { + return "", err + } + if symref == "" { + return "", nil + } + // git for-each-ref --format='%(upstream:remotename)' + remote, err := c.clean(c.run("for-each-ref", "--format=%(upstream:remotename)", symref)) + if err != nil { + return "", err + } + return remote, nil +} + func IsUnknownRevision(err error) bool { if err == nil { return false diff --git a/util/gitutil/gitutil_test.go b/util/gitutil/gitutil_test.go index 991cd32ee611..06c6fa454d9c 100644 --- a/util/gitutil/gitutil_test.go +++ b/util/gitutil/gitutil_test.go @@ -106,8 +106,9 @@ func TestGitDescribeTags(t *testing.T) { func TestGitRemoteURL(t *testing.T) { type remote struct { - name string - url string + name string + url string + tracking string } cases := []struct { @@ -165,6 +166,36 @@ func TestGitRemoteURL(t *testing.T) { }, fail: true, }, + { + name: "single tracking branch", + remotes: []remote{ + { + name: "foo", + url: "https://github.com/tonistiigi/buildx.git", + tracking: "master", + }, + }, + expected: "https://github.com/tonistiigi/buildx.git", + }, + { + name: "fork tracking branch", + remotes: []remote{ + { + name: "origin", + url: "git@github.com:crazy-max/buildx.git", + }, + { + name: "foobranch", + url: "https://github.com/tonistiigi/buildx.git", + tracking: "master", + }, + { + name: "crazymax", + url: "git@github.com:crazy-max/buildx.git", + }, + }, + expected: "https://github.com/tonistiigi/buildx.git", + }, } for _, tt := range cases { tt := tt @@ -177,6 +208,9 @@ func TestGitRemoteURL(t *testing.T) { GitCommit(c, t, "initial commit") for _, r := range tt.remotes { GitSetRemote(c, t, r.name, r.url) + if r.tracking != "" { + GitSetMainUpstream(c, t, r.name, r.tracking) + } } ru, err := c.RemoteURL() diff --git a/util/gitutil/testutil.go b/util/gitutil/testutil.go index ea9dd058eabb..d0de8970a36e 100644 --- a/util/gitutil/testutil.go +++ b/util/gitutil/testutil.go @@ -52,6 +52,15 @@ func GitSetRemote(c *Git, tb testing.TB, name string, url string) { require.NoError(tb, err) } +func GitSetMainUpstream(c *Git, tb testing.TB, remote, target string) { + tb.Helper() + _, err := fakeGit(c, "fetch", "--depth", "1", remote, target) + require.NoError(tb, err) + + _, err = fakeGit(c, "branch", "--set-upstream-to", remote+"/"+target, "main") + require.NoError(tb, err) +} + func Mktmp(tb testing.TB) string { tb.Helper() folder := tb.TempDir()