cli icon indicating copy to clipboard operation
cli copied to clipboard

`gh pr checkout` should add the fork as a remote

Open leobalter opened this issue 4 years ago • 34 comments

CLI Feedback

What have you loved?

gh pr checkout is one of the best features of this tool, thanks!

What was confusing or gave you pause?

I had a PR I created elsewhere to an org repo, requesting changes from my own fork's branch, e.g.:

upstream has PR #2 with changes from origin:patch-1 branch to upstream:main.

In a new computer I clone the repo with gh clone org/project, then on the project's folder, I checkout the PR's work with gh pr checkout 2. It gets me on the patch-1 branch, but my git remote still points only the the org's remote, not to my fork's remote.

My issue happened when I applied changes to the branch and tried to push it back. It's a minor problem but I can tell that using git remote add leobalter [email protected]:leobalter/<project>.git is something that I'd love to avoid when I use gh pr checkout.

Are there features you'd like to see added?

I'd love if gh pr checkout could add the remote by default if it's not listed in the known remotes, or at least offer me an option to add it. This would allow a quick way to set the new branch to track the proper remote branch as well.

leobalter avatar Feb 10 '21 01:02 leobalter

Thank you for writing in!

My issue happened when I applied changes to the branch and tried to push it back.

Can you tell us more about what happened when you tried to push it back? Have you tried regular git push?

The gh pr checkout command automatically sets up upstream configuration to enable you to push back to the head branch of the PR, even if it's on the fork. No git remote needed.

mislav avatar Feb 10 '21 14:02 mislav

@mislav, that is not the case for me. It checks it out with no tracking at all. No new remotes are added to my copy of the repo at all.

NSExceptional avatar May 18 '21 18:05 NSExceptional

I'm sorry I missed answering this before.

@mislav, that is not the case for me. It checks it out with no tracking at all. No new remotes are added to my copy of the repo at all.

Yes, the problem I reported here is that git pr checkout <number> did not add the source remote used in the PR.

leobalter avatar May 18 '21 20:05 leobalter

This also does not work for me:

$ gh pr checkout 1234 # A PR from a fork
$ touch foo
$ git add -A
$ git commit -a -m "Some changes"
$ git push # Pushes to upstream, not fork

Also no remotes are set up:

$ gh pr checkout 1234 # A PR from a fork
$ git remote
origin

aeneasr avatar Jun 03 '21 08:06 aeneasr

Yes, the problem I reported here is that git pr checkout <number> did not add the source remote used in the PR.

To add some context: Currently, to push changes to a PR, the maintainer must manually navigate to the fork, copy the clone address, and manually add the remote. So, adding a remote automatically (or having an option to do so) would eliminate this step from the common PR review process.

jaredbeck avatar Jul 25 '21 03:07 jaredbeck

@mislav Is this being looked at? It makes editing PRs reaaaaaally tedious and time consuming

NSExceptional avatar Jul 25 '21 23:07 NSExceptional

$ git push # Pushes to upstream, not fork

@aeneasr: That doesn't sound right. Can you tell us the configuration of your branch that was created by gh pr checkout and your push configuration? (You may anonymize branch/repository names.)

git config --get-regexp "^branch\\.$(git branch --show-current)\\."
git config push.default

@jaredbeck: git push without arguments should push changes back to the PR, even if the PR comes from a fork, and even if there is no git remote for that fork. If the motivation for adding the git remote is solely to be able to push changes back, then please try git push. If it doesn't work, then please share with us the information I've requested above in this comment.

mislav avatar Jul 26 '21 13:07 mislav

@jaredbeck: git push without arguments should push changes back to the PR, even if the PR comes from a fork, and even if there is no git remote for that fork.

Thanks Mislav, I've confirmed that a simple git push works, exactly the way I wanted it to! I'm not sure how I missed that 🤦 I guess I just assumed it would push to origin, so I never tried it.

If I understand the following config correctly, it seems that gh pr checkout sets the branch's remote, rather than a repository-level remote?

gh pr checkout 1333
git config --get-regexp "^branch\\.$(git branch --show-current)\\."
pr.remote [email protected]:hschne/paper_trail.git

This is ideal, actually, to avoid cluttering up the repo-level remotes.

If this works for others as well as it did for me today, I'd say this issue can be closed.

jaredbeck avatar Jul 26 '21 16:07 jaredbeck

Oh wow, I didn't even know that was a thing… Could this be better documented?

NSExceptional avatar Jul 26 '21 16:07 NSExceptional

Could this be better documented?

It'd be nice if gh pr checkout printed something like:

"This new branch's config will track the fork at __. You can push to that fork with a simple git push."

jaredbeck avatar Jul 26 '21 16:07 jaredbeck

I am getting a similar situation, where I first checkout a PR via

gh pr checkout <number>

and make some changes + commit them. Then, when I run git push I get

fatal: The upstream branch of your current branch does not match
the name of your current branch.  To push to the upstream branch
on the remote, use

    git push <remote> HEAD:refs/pull/<number>/head

To push to the branch of the same name on the remote, use

    git push <remote> HEAD

To choose either option permanently, see push.default in 'git help config'.

If I try the first option (which seems more like what I wanted to do), I get

! [remote rejected] HEAD -> refs/pull/<number>/head (deny updating a hidden ref)
error: failed to push some refs to '<remote-repo>.git'

ewu63 avatar Jul 26 '21 20:07 ewu63

@nwu63 What does the following command print?

git config --get-regexp "^branch\\.$(git branch --show-current)\\."

jaredbeck avatar Jul 26 '21 21:07 jaredbeck

@nwu63 What does the following command print?

git config --get-regexp "^branch\\.$(git branch --show-current)\\."

It shows

branch.<branch>.remote origin
branch.<branch>.merge refs/pull/<number>/head

ewu63 avatar Jul 26 '21 21:07 ewu63

@jaredbeck Agreed that printing a note like that would improve visibility of this feature.

Note that we are also considering offering a gh pr push in the future #2189

mislav avatar Jul 27 '21 14:07 mislav

@nwu63 Sorry, this is not very clear from the error message (since the error comes from git), but it looks like the author of the PR in question did not enable you to push changes to their branch.

mislav avatar Jul 27 '21 14:07 mislav

@nwu63 Sorry, this is not very clear from the error message (since the error comes from git), but it looks like the author of the PR in question did not enable you to push changes to their branch.

@mislav I do have push access to that PR though, I was able to push up changes after adding a remote manually to their fork and running git push <remote> <branch> -u. It would be great if gh can skip this step for me.

ewu63 avatar Jul 27 '21 16:07 ewu63

@nwu63 Ah, so you have push access to this PR! Can you try upgrading gh to the latest version, deleting the local branch for the PR, then doing gh pr checkout again and checking upstream configuration for this branch as per my above comment? Thank you!

mislav avatar Jul 27 '21 16:07 mislav

@mislav Ah I apologize! Should've tried that as the first thing. Yes after updating my installation everything works. Thanks again :)

ewu63 avatar Jul 27 '21 17:07 ewu63

CLI Feedback

What have you loved?

gh pr checkout is one of the best features of this tool, thanks!

What was confusing or gave you pause?

I had a PR I created elsewhere to an org repo, requesting changes from my own fork's branch, e.g.:

upstream has PR #2 with changes from origin:patch-1 branch to upstream:main.

In a new computer I clone the repo with gh clone org/project, then on the project's folder, I checkout the PR's work with gh pr checkout 2. It gets me on the patch-1 branch, but my git remote still points only the the org's remote, not to my fork's remote.

My issue happened when I applied changes to the branch and tried to push it back. It's a minor problem but I can tell that using git remote add leobalter [email protected]:leobalter/<project>.git is something that I'd love to avoid when I use gh pr checkout.

Are there features you'd like to see added?

I'd love if gh pr checkout could add the remote by default if it's not listed in the known remotes, or at least offer me an option to add it. This would allow a quick way to set the new branch to track the proper remote branch as well.

gh pr checkout gh pr checkout

  • [ ]

myat-bot avatar Sep 17 '21 18:09 myat-bot

That doesn't sound right. Can you tell us the configuration of your branch that was created by gh pr checkout and your push configuration? (You may anonymize branch/repository names.)

I'm experiencing the same behavior. I wish that pushing would push to the fork's branch, not create a new branch with the same name under our repo.

➜  code-server git:(main) gh pr checkout 4281
remote: Enumerating objects: 7, done.
remote: Counting objects: 100% (7/7), done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 4 (delta 3), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (4/4), 1.36 KiB | 348.00 KiB/s, done.
From https://github.com/cdr/code-server
 * [new ref]           refs/pull/4281/head -> patch-1
Switched to branch 'patch-1'


A new release of gh is available: 1.10.3 → v2.0.0
To upgrade, run: brew update && brew upgrade gh
https://github.com/cli/cli/releases/tag/v2.0.0

➜  code-server git:(patch-1) yarn fmt
yarn run v1.22.11
$ ./ci/dev/fmt.sh
✨  Done in 25.10s.
# commit, etc.

Alias tip: gp
fatal: The upstream branch of your current branch does not match
the name of your current branch.  To push to the upstream branch
on the remote, use

    git push origin HEAD:refs/pull/4281/head

To push to the branch of the same name on the remote, use

    git push origin HEAD

To choose either option permanently, see push.default in 'git help config'.
➜  code-server git:(patch-1) git push origin HEAD                   
Alias tip: gp origin HEAD
Enumerating objects: 11, done.
Counting objects: 100% (11/11), done.
Delta compression using up to 16 threads
Compressing objects: 100% (8/8), done.
Writing objects: 100% (8/8), 2.34 KiB | 2.34 MiB/s, done.
Total 8 (delta 6), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (6/6), completed with 3 local objects.
remote: 
remote: Create a pull request for 'patch-1' on GitHub by visiting:
remote:      https://github.com/cdr/code-server/pull/new/patch-1
remote: 
To https://github.com/cdr/code-server.git
 * [new branch]        HEAD -> patch-1

➜  code-server git:(patch-1) git push origin HEAD:refs/pull/4281/head
Alias tip: gp origin HEAD:refs/pull/4281/head
Total 0 (delta 0), reused 0 (delta 0), pack-reused 0
To https://github.com/cdr/code-server.git
 ! [remote rejected]   HEAD -> refs/pull/4281/head (deny updating a hidden ref)
error: failed to push some refs to 'https://github.com/cdr/code-server.git'
➜  code-server git:(patch-1) 

jsjoeio avatar Sep 30 '21 22:09 jsjoeio

Seems what is described here as solution (add remote) is my feature request ist https://github.com/cli/cli/issues/4997? If I follow the discussion correctly then @mislav seems to suggest that this should already be supported and to check repository config.

andig avatar Jan 06 '22 07:01 andig

Seems what is described here as solution (add remote) is my feature request ist #4997? If I follow the discussion correctly then @mislav seems to suggest that this should already be supported and to check repository config.

I can confirm this works as expected. I'm unsure why it didn't in other tests. It probably makes a difference if the PR creator has not given permission to his repo/branch? What would happen in that case?

andig avatar Jan 06 '22 08:01 andig

It probably makes a difference if the PR creator has not given permission to his repo/branch? What would happen in that case?

gh pr checkout then creates your local branch that is able to git pull from the PR, but is not able to push to it.

mislav avatar Jan 07 '22 13:01 mislav

I think it would be helpful to show a message what the expected push behaviour will be upon checkout.

andig avatar Jan 07 '22 19:01 andig

@andig Agreed:

  • Many users reported that they didn't understand how to push back to the PR after gh pr checkout. In most cases a simple git push would have worked, but gh does not make this clear. We could improve this by printing push instructions after a gh pr checkout. If the PR author does not allow pushing, the output could indicate that too.

  • It might be beneficial that gh pr checkout adds a git remote for every unique fork that a PR comes from. This would enable us to set up remote tracking branches and for the git tooling to be able to display “ahead/behind” information such as in git status. However, we would have to additionally address the rampant accumulation of mostly one-off git remotes in one's local repository. If gh automatically adds them, what would clean them up after they're no longer needed?

  • To address some limitations with git push not working for some branch setups after gh pr checkout, we were considering adding a dedicated gh pr push command to complement gh pr checkout: https://github.com/cli/cli/issues/2189

mislav avatar Jan 07 '22 19:01 mislav

However, we would have to additionally address the rampant accumulation of mostly one-off git remotes in one's local repository. If gh automatically adds them, what would clean them up after they're no longer needed?

Me personally I wouldn't be bothered. I can always easily delete remotes- much easier than to remember how to properly checkout remote branches ;)

andig avatar Jan 07 '22 19:01 andig

we were considering adding a dedicated gh pr push command

As a gh newbie, I have to admit the lack of symmetric gh pr push confused me. I worked out the following tiny workflow to update a contributor's PR from upstream branch

gh pr checkout 1234
git merge origin/main
git push
git switch -
git branch -D $(git rev-parse --symbolic-full-name @{-1} | sed -re 's%^refs/heads/%%')

and it took me long until I found this discussion to understand why the plain git push works without contributor's fork added as a remote.

To sum it up, I think most users would expect gh pr push for symmetry and self-descriptive interface :)

mloskot avatar Jun 26 '22 11:06 mloskot

@mislav issue is waiting on feedback- anything we could specifically provide to move this further? Much appreciated!

andig avatar Jun 26 '22 15:06 andig

@andig It's not waiting on anything anymore. We're pretty sure we want to do this, so I've labeled it "help wanted".

Note that gh pr checkout starting to add a git remote for every new fork will lead to many git remotes created for maintainers of open source projects that receive PRs from forks. This feature will need to be paired with an additional command to help maintainers clean up unused git remotes. Any ideas around that?

mislav avatar Jun 27 '22 10:06 mislav

Any ideas around that?

Maybe commands to allow to:

  • delete branches of merged or otherwise closed PRs
  • delete remotes without existing branches

andig avatar Jun 27 '22 11:06 andig