Skip to content

pr create: respect git @{push} configuration for the current branch #1645

Description

@gibfahn

Describe the feature or problem you’d like to solve

For PRs, if you use git's @{push} branches feature, you can have a much nicer workflow, and also automatically know which branch to raise PRs against.

For example, before I raise PRs:

$ git rev-parse --abbrev-ref --symbolic-full-name @
my_new_feature

$ git rev-parse --abbrev-ref --symbolic-full-name @{push}
fork/my_new_feature

$ git rev-parse --abbrev-ref --symbolic-full-name @{upstream}
up/master

However I may be on a different branch with a different remote in the same repo (for things with both public and private pairs of fork/upstream remotes, one in github.com and one in GHE):

$ git rev-parse --abbrev-ref --symbolic-full-name @
upstreaming_my_new_feature

$ git rev-parse --abbrev-ref --symbolic-full-name @{push}
pubfork/upstreaming_my_new_feature

$ git rev-parse --abbrev-ref --symbolic-full-name @{upstream}
pubup/master

As I already have these configured, it's painful to have to have gh guess them, and in cases where the --branch is ambiguous (e.g. up and pubup both have a master branch), it seems to pick one at random (and setting GH_REPO doesn't help).

Proposed solution

Ideally these would just be used as defaults, and gh pr create would just work with the above configuration.

However what might also be useful (and more flexible) would be to allow passing refs as the --base and --head branch refs (I know the latter doesn't exist right now).

That way it could be gh pr create --base=@{upstream} --head=@{push}

Additional context

Right now things sometimes work if you only have two remotes, depending on whether the heuristics in context.go work:

cli/context/context.go

Lines 83 to 94 in 74614b1

// BaseRepo is the first found repository in the "upstream", "github", "origin"
// git remote order, resolved to the parent repo if the git remote points to a fork
func (r ResolvedRemotes) BaseRepo() (*api.Repository, error) {
if r.BaseOverride != nil {
for _, repo := range r.Network.Repositories {
if repo != nil && ghrepo.IsSame(repo, r.BaseOverride) {
return repo, nil
}
}
return nil, fmt.Errorf("failed looking up information about the '%s' repository",
ghrepo.FullName(r.BaseOverride))
}

Activity

  1. mislav commented on Sep 9, 2020

    @mislav
    Contributor

    Thank you for the suggestions and additional resources to read!

    We are currently in the process of improving base/head branch heuristics for pr create; stay tuned! We might take these git features into account too. 🙇

  2. gibfahn commented on Sep 9, 2020

    @gibfahn
    Author

    We are currently in the process of improving base/head branch heuristics for pr create; stay tuned! We might take these git features into account too. 🙇

    Makes sense, thanks!

    FWIW my main aim is to have something that allows me to fully move from hub to gh (currently gh works about 40% of the time, hub works 99% of the time):

    https://github.com/gibfahn/dot/blob/efd52aa23505e2febc00f9c5d9ab4a864de77d36/dotfiles/.config/git/config#L142-L144

    I'd take anything that works in the short term over something perfect in the long term 😁 .

  3. mislav commented on Sep 10, 2020

    @mislav
    Contributor

    However what might also be useful (and more flexible) would be to allow passing refs as the --base and --head branch refs (I know the latter doesn't exist right now).

    That way it could be gh pr create --base=@{upstream} --head=@{push}

    As you noticed, we don't yet allow specifying the head branch, but gh pr create will try to respect the remote that the current branch is already (fully) pushed to. So if you configure your aliases to do git push <remote> HEAD && gh pr create, gh is going to auto-detect the push target for the branch. This only works as long as the remote branch name has the same name as the current tracking branch.

  4. gibfahn commented on Sep 10, 2020

    @gibfahn
    Author

    That's what I thought would happen, but not the behaviour I'm seeing. Here's a slightly-redacted example:

    Here are my remotes:

    $ git remote -v
    fork	[email protected]:internal-me/some-repo.git (fetch)
    fork	[email protected]:internal-me/some-repo.git (push)
    pub	https://github.com/public-org/some-repo (fetch)
    pub	https://github.com/public-org/some-repo (push)
    pubfork	[email protected]:public-me/some-repo.git (fetch)
    pubfork	[email protected]:public-me/some-repo.git (push)
    up	[email protected]:internal-org/some-repo (fetch)
    up	[email protected]:internal-org/some-repo (push)
    • pub and pubfork are github.com remotes
    • up and fork are GHE remotes.
    • pubfork is a fork of pub
    • fork is a fork of up

    I want to raise a PR against github.com.

    I have pushed my current branch to pubfork:

    $ git s
    On branch my-branch
    Your branch and 'pub/master' have diverged,
    and have 2 and 2 different commits each, respectively.
      (use "git pull" to merge the remote branch into yours)
    
    nothing to commit, working tree clean
    Your branch is up to date with push branch pubfork/my-branch.
    
    $ git branch -a | grep my-branch
    * my-branch
      remotes/pubfork/my-branch

    And the upstream is set to the branch I want to create the PR against:

    $ git rev-parse --abbrev-ref --symbolic-full-name @{upstream}
    pub/master

    However when I run gh pr create, it always tries to create the PR against the internal GHE repo (fork -> up), not the external repo (pubfork -> pub).

    $ gh pr create
    
    Creating pull request for my-branch into master in internal-org/some-repo
    
    ? Title (my title)
    
    $ gh pr create --base=master
    
    Creating pull request for my-branch into master in internal-org/some-repo

    Setting GH_REPO and GH_HOST doesn't seem to help either:

    $ GH_REPO=https://github.com/public-org/some-repo gh pr create
    
    Creating pull request for my-branch into master in internal-org/some-repo
    
    $ GH_HOST=https://github.com gh pr create
    
    Creating pull request for my-branch into master in internal-org/some-repo
    
    $ GH_REPO=public-org/some-repo gh pr create
    
    Creating pull request for my-branch into master in internal-org/some-repo
  5. mislav commented on Sep 10, 2020

    @mislav
    Contributor

    @gibfahn Ah, so it's a mixed GHE + github.com setup. Thanks for the detailed info!

    Right now, we don't know how to support mixed git remotes (for example, we can't let you push a head branch to a GHE remote, but open a PR to a github.com base remote), so we select the 1st host that we find in remotes and ignore all others. https://github.com/cli/cli/pull/1258/files#diff-15cce7299aae8810bcab9b0bf9a2fdb1R36

    That's why you are seeing the limitation you're describing, and neither GH_REPO nor GH_HOST currently override that. I would say that the latter is a bug! #1668

    How do you envision working with mixed git remotes? What would your ideal interface be?

    Thanks for all the feedback so far! 🌟

  6. gibfahn commented on Sep 11, 2020

    @gibfahn
    Author

    Right now, we don't know how to support mixed git remotes (for example, we can't let you push a head branch to a GHE remote, but open a PR to a github.com base remote), so we select the 1st host that we find in remotes and ignore all others. #1258 (files)
    How do you envision working with mixed git remotes? What would your ideal interface be?

    I can't say I understand all the permutations of how gh works, but I think at least:

    1. If the current branch exists on exactly 1 remote, and that remote is a GitHub fork of another remote, assume PR will be raised from fork/branch -> upstream/branch
    2. If a GH_HOST is specified, only consider remotes matching that host
    3. If a GH_REPO is specified, only that repo and its forks should be considered

    And long-term have a --head and a --base that can both take git refs and:

    1. If @{upstream} and @{push} both exist, default to raising PR from @{push} to @{upstream}
    2. If only @{upstream} exists:
      1. If it has the same name as @ (current branch) it's probably the PR branch, raise PR from @{upstream} to the autocalculated base branch.
    3. If neither exist:
      1. If there are two remotes and they are part of the same fork set (a main repo and forks of that repo) then push to fork repo (with current branch name) and raise against main repo (default branch)
      2. Otherwise instead of guessing, prompt the user to choose the base branch, allowing them to specify:
        1. A remote name (upstream, fork), in which case you choose the default branch
        2. A ref (upstream/master) in which case you use that branch.

    Feels like for these flags (in this command and others) users might want to pass any combination of optional repo and optional branch, e.g.: branch, remote, remote/branch, github.com/org/repo/branch, ghe.com/org/repo/branch, [email protected]:org/repo.git/branch, and finding an easy way to specify them that isn't ambiguous to parse would be tough.

    Also raising a PR can be quite dangerous, as it's irreversible, and it can involve pushing private code somewhere public. So I'd rather gh did less guessing unless it's really unambiguous, even it if means I have to create aliases for my workflows.

    IDK about other folks, but I rarely remember the user:org github syntax for my remotes, because I set them up once and that's it. However I know what my remote names, because they're the same standard names in every repo.

  7. added
    coreThis issue is not accepting PRs from outside contributors
    on Sep 30, 2020
  8. phil-blain commented on Jan 14, 2021

    @phil-blain

    For cross-references purposes, I think this is possibly related to #575.

  9. mislav commented on Jan 14, 2021

    @mislav
    Contributor

    @phil-blain Thanks! It's loosely related. But I would say that the basis of this issue was:

    1. “If a GH_HOST is specified, only consider remotes matching that host” - we now respect this. @gibfahn Can you check?
    2. That we don't support git's @{push} feature. This is why I'm keeping the issue open.
  10. gibfahn commented on Jan 14, 2021

    @gibfahn
    Author

    “If a GH_HOST is specified, only consider remotes matching that host” - we now respect this. @gibfahn Can you check?

    I've been using GH_REPO for that purpose and it seems to be working now, assuming that is the same fix thank you!

  11. gibfahn commented on Jan 14, 2021

    @gibfahn
    Author

    I think that supporting @{push} would actually be a way nicer workflow for most github users, so would be worth supporting here, but I'm unblocked now.

  12. gibfahn commented on Jan 26, 2021

    @gibfahn
    Author

    “If a GH_HOST is specified, only consider remotes matching that host” - we now respect this. @gibfahn Can you check?

    Just checked creating a PR to a github.com repo and it's actually not working (I guess it was just defaulting to my GHE remote and I assumed that meant things were good).

    ❯ GH_HOST=github.com DEBUG=true gh pr create --base master
    [git remote -v]
    [git config --get-regexp ^remote\..*\.gh-resolved$]
    * Request at 2021-01-26 10:24:14.524125 +0000 GMT m=+0.027934825
    * Request to https://github.mycorp.com/api/graphql
    * Request took 863.425548ms
    # [...]
    pull request create failed: GraphQL error: Head sha can't be blank, Base sha can't be blank, No commits between master and update_deps, Head ref must be a branch

    The gh pr command is assuming I want to raise the PR against the GHE repo. I tried setting GH_HOST=github.com and GH_REPO=https://github.com/publicorg/somerepo.

    ❯ g rv
    fork	[email protected]:gib/somerepo.git (fetch)
    fork	[email protected]:gib/somerepo.git (push)
    pub	https://github.com/publicorg/somerepo (fetch)
    pub	https://github.com/publicorg/somerepo (push)
    pubfork	[email protected]:gibfahn/somerepo.git (fetch)
    pubfork	[email protected]:gibfahn/somerepo.git (push)
    up	[email protected]:myorg/somerepo (fetch)
    up	[email protected]:myorg/somerepo (push)
  13. ElijahLynn commented on Jun 1, 2021

    @ElijahLynn

    gh version 1.10.3 (2021-05-22)

    I am seeing a branch fully pushed to a remote and it is tracked to that branch but a gh pr create still makes the PR against a different remote.

  14. ElijahLynn commented on Jun 1, 2021

    @ElijahLynn

    gh version 1.10.3 (2021-05-22)

    I am seeing a branch fully pushed to a remote and it is tracked to that branch but a gh pr create still makes the PR against a different remote.

    Just figured my issue out though with #1864. I was able to specify a different remote with --host OWNER/REPO, so gh pr create --repo department-of-veterans-affairs/va.gov-cms-test --web worked for me.

  15. changed the title [-]Handle multiple remotes with `gh pr create`[/-] [+]pr create: respect git `@{push}` configuration for the current branch[/+] on Dec 22, 2022
  16. added
    gh-prrelating to the gh pr command
    on Oct 2, 2023
  17. andyfeller commented on Dec 16, 2024

    @andyfeller
    Contributor

    @gibfahn : how relevant would the work in #9208 be here?

    I saw this issue while reviewing our backlog for any issues about cross repo pull requests related to to it and #575. This felt closely related, so I wanted to see if you had any interested testing out the changes locally to see if it will satisfy this use case. If so, I'd suggest we close this issue as a duplicate of #575 or the related #9363

    cc: @williammartin

  18. gibfahn commented on Dec 19, 2024

    @gibfahn
    Author

    #9208 does seem like it would fix this issue (which is exciting!)

    I'd suggest we close this issue as a duplicate of #575 or the related #9363

    Closing this as a duplicate of #575 seems reasonable. The original issue message isn't exactly the same, but all the discussion in that issue seems relevant otherwise.

  19. gibfahn commented on Jan 3, 2025

    @gibfahn
    Author

    Actually I think it makes sense to keep this issue open. It very specifically tracks gh pr create using @{push}.

    So if we close this as a dup I think there's a decent chance this won't get fixed.

    Worth noting that extending the approach in #9208 to handle gh pr create seems like it would be sufficient to fix this.

  20. jtmcg commented on Jan 17, 2025

    @jtmcg
    Contributor

    Update!!

    After a lot of digging, we're going to respect @{push} first. See this comment on #9208.

    I think this simplification should allow us to address gh pr create mentioned here fairly simply as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    coreThis issue is not accepting PRs from outside contributorsenhancementa request to improve CLIgh-prrelating to the gh pr command

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions