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 <tonistiigi@gmail.com>
This commit is contained in:
Tonis Tiigi 2023-11-30 22:07:50 -08:00
parent d82637582c
commit 6028094e6b
No known key found for this signature in database
GPG Key ID: AFA9DE5F8AB7AF39
3 changed files with 68 additions and 3 deletions

View File

@ -78,7 +78,13 @@ func (c *Git) GitDir() (string, error) {
} }
func (c *Git) RemoteURL() (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 != "" { if ru, err := c.clean(c.run("remote", "get-url", "origin")); err == nil && ru != "" {
return stripCredentials(ru), nil return stripCredentials(ru), nil
} }
@ -149,6 +155,22 @@ func (c *Git) clean(out string, err error) (string, error) {
return out, err 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 { func IsUnknownRevision(err error) bool {
if err == nil { if err == nil {
return false return false

View File

@ -106,8 +106,9 @@ func TestGitDescribeTags(t *testing.T) {
func TestGitRemoteURL(t *testing.T) { func TestGitRemoteURL(t *testing.T) {
type remote struct { type remote struct {
name string name string
url string url string
tracking string
} }
cases := []struct { cases := []struct {
@ -165,6 +166,36 @@ func TestGitRemoteURL(t *testing.T) {
}, },
fail: true, 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 { for _, tt := range cases {
tt := tt tt := tt
@ -177,6 +208,9 @@ func TestGitRemoteURL(t *testing.T) {
GitCommit(c, t, "initial commit") GitCommit(c, t, "initial commit")
for _, r := range tt.remotes { for _, r := range tt.remotes {
GitSetRemote(c, t, r.name, r.url) GitSetRemote(c, t, r.name, r.url)
if r.tracking != "" {
GitSetMainUpstream(c, t, r.name, r.tracking)
}
} }
ru, err := c.RemoteURL() ru, err := c.RemoteURL()

View File

@ -52,6 +52,15 @@ func GitSetRemote(c *Git, tb testing.TB, name string, url string) {
require.NoError(tb, err) 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 { func Mktmp(tb testing.TB) string {
tb.Helper() tb.Helper()
folder := tb.TempDir() folder := tb.TempDir()