diff --git a/internal/app/help_topics.go b/internal/app/help_topics.go index 7005d8ca..a76dbffe 100644 --- a/internal/app/help_topics.go +++ b/internal/app/help_topics.go @@ -292,9 +292,11 @@ func helpTopics(globals *pflag.FlagSet) []*cobra.Command { ` + indent(flagUsages(flags)) + ` -tea selects the repository from --repo, TEA_REPO, git config tea.repository or a -Git remote (--remote, else the current branch's remote, upstream or origin, skipping -remotes on instances without an account, or not on --host or the GITEA_TOKEN instance), +tea selects the repository from --repo, TEA_REPO, git config tea.repository (tea repo +set-default) or a Git remote (--remote, else the base remote pr checkout recorded, the +current branch's remote, upstream or origin, skipping remotes on instances without an +account, or not on --host or the GITEA_TOKEN instance). Like gh, a clone with upstream +and origin targets upstream: a branch tracking origin does not select the fork, and the instance from the repository URL, --host, TEA_HOST or GITEA_INSTANCE_URL, default_host, or the only configured instance. diff --git a/internal/git/discover.go b/internal/git/discover.go index ec095880..4d5279ab 100644 --- a/internal/git/discover.go +++ b/internal/git/discover.go @@ -16,7 +16,7 @@ var ErrAmbiguousRemote = errors.New("ambiguous repository: select --remote or -- // DiscoverRemote names the remote used for repository discovery: preferred when set, otherwise // the base remote pr checkout recorded for the current branch, the current branch's upstream -// remote unless it is a pulls// head remote, then upstream, origin, or the only remote. +// remote unless it is a pulls// head remote or origin beside an upstream remote (a fork clone), then upstream, origin, or the only remote. // When repository is not nil, it names the repository of a remote tea can act on, or returns "" // for one on another forge. Those steps then skip such remotes, and the other remotes decide when // they name exactly one repository; with none of them usable the choice is the name-based one. @@ -43,19 +43,23 @@ func DiscoverRemote(ctx context.Context, runner Runner, dir, preferred string, r if strings.HasPrefix(tracking, "pulls/") { tracking = "" } + names, namesErr := runner.Output(ctx, dir, false, "remote") + available := strings.Fields(names) + // In a fork clone, branches pushed to the fork track origin, but the base repository is upstream. + if tracking == "origin" && slices.Contains(available, "upstream") { + tracking = "" + } for _, remote := range []string{pullBaseRemote(ctx, runner, dir, branch), tracking} { if try(remote) { return remote, nil } } - names, err := runner.Output(ctx, dir, false, "remote") - if err != nil { + if namesErr != nil { if fallback != "" { return fallback, nil } - return "", err + return "", namesErr } - available := strings.Fields(names) for _, name := range []string{"upstream", "origin"} { if slices.Contains(available, name) && try(name) { return name, nil diff --git a/internal/git/discover_test.go b/internal/git/discover_test.go index 6a133399..c6f2f0fb 100644 --- a/internal/git/discover_test.go +++ b/internal/git/discover_test.go @@ -38,6 +38,8 @@ func TestDiscoverRemote(t *testing.T) { {name: "recorded pull base", runner: discoverRunner{head: "main", tracking: "fork", base: "upstream", "remote": "origin\nupstream\nfork"}, want: "upstream"}, {name: "removed pull base", runner: discoverRunner{head: "main", tracking: "fork", base: "gone", "remote": "origin\nfork"}, want: "fork"}, {name: "local branch upstream", runner: discoverRunner{head: "main", tracking: ".", "remote": "origin\nfork"}, want: "origin"}, + {name: "fork clone branch tracking origin", runner: discoverRunner{head: "main", tracking: "origin", "remote": "origin\nupstream"}, want: "upstream"}, + {name: "branch tracking origin without upstream", runner: discoverRunner{head: "main", tracking: "origin", "remote": "origin\nfork"}, want: "origin"}, {name: "upstream remote", runner: discoverRunner{"remote": "origin\nupstream"}, want: "upstream"}, {name: "origin remote", runner: discoverRunner{"remote": "fork\norigin"}, want: "origin"}, {name: "sole remote", runner: discoverRunner{"remote": "fork"}, want: "fork"},