0

I follow the generic OSS structure:

  1. the OSS' remote repository hosted on GitHub
  2. a fork of the OSS remote repository to my own remote repository
  3. a clone of the fork on my remote repository to create a local repository

Thus, a contributor would create a new branch locally, push the changes to his/her remote repository, and then open a pull request to the OSS' remote repository.

This has been working well. However, the main issue comes when I try to review another contributor's pull request by fiddling with it locally.

So I have fetched a pull request made to the OSS' remote repository using this command:

git fetch upstream pull/<PR#>/head:<branchName>

followed by git checkout <branchName>

and it was successful. I played around with the PR, and reviewed it on GitHub. Then, the contributor updated the PR by pushing new commits to their branch (on their remote repo), which was automatically reflected in the PR.

Now, I want to be able to get the updates locally so that I can try the changes again. I understand that my copy of the PR branch does not track the remote branch by default, so I tried to set it to track the PR:

git branch --set-upstream upstream/pull/<PR#>/head:<branchName>

like how I have done when I first fetched the branch. However, I got the response that

error: the requested upstream branch 'pull//head:' does not exist

I tried again with:

git branch --set-upstream-to upstream/pull/<PR#>/head:<branchName>

which also failed with the same error.

Then, I thought, is it because a PR is like a 'reflection' of the branch on someone's remote repository, so if I want to track an upstream branch I should track from the person's remote repository?

So I added the contributors' remote repository as a remote, and tried again:

git branch --set-upstream-to <newRemote> <branchName>

and I still faced the same error.

I did some Googling, and I found this, but I do not want to get all the pull requests. I also found links like this one but nope, not the help that I need there.

Can anyone point out what is wrong with the way that I am doing things now? Thanks!

Edit: Is there an easier way to do things aside from what has been proposed by Marina Liu - MSFT below?

umop apisdn
  • 653
  • 9
  • 20

2 Answers2

1

The problem—or at least the first one—here is that you cannot use an upstream to refer to a GitHub pull request reference.

In Git, an upstream on a branch consists of two parts:

  • The name of a remote, such as origin
  • The name of a branch on that remote, such as master

Git puts these two together to get refs/heads/master—this is the name on the remote—then runs this string through the fetch setting(s) for the remote. The standard fetch setting for the remote named origin is +refs/heads/*:refs/remotes/origin/*, so if the upstream is currently set to the pair <origin, master>, the name that Git looks up in your own repository is refs/remotes/origin/master, which is your remote-tracking name for their master.

Note the assumption in here that the name on the remote begins with refs/heads/.

The actual name of a pull reference on GitHub begins with refs/pull/, not refs/heads/, so that the full name of the commit you want for pull request #123 is refs/pull/123/head. There is no way to spell this that starts with refs/heads/ because this is not a branch name.

Now, you can—as suggested in your first linkadd an extra fetch setting:

[remote "origin"]
    fetch = +refs/heads/*:refs/remotes/origin/*
    fetch = +refs/pull/*/head:refs/remotes/origin/pr/*

which causes their refs/pull/123/head to associate with your refs/remotes/origin/pr/123. Depending on your particular Git version, some of this sometimes or even mostly works. Some Git versions get rather confused at times. If you try it and it works for you, that's great, just be prepared to clean up a bit of a mess if you upgrade or downgrade Git versions for some reason.

The aliases found via your second link are better. These fetch from one specific pull request, creating a local branch name (or overwriting it if it already exists—this is a bit dangerous but as long as you don't name your own branches pr/integer you will be fine). You could improve them, writing a real git-pr script that creates a local branch—be sure to use the full name format, refs/heads/pr/number, to guarantee correctness—and sets some additional information so that, when you are on that branch, git pr updates the branch automatically.

(If I get some spare time, I might write my own script, because this would be pretty handy.)

torek
  • 448,244
  • 59
  • 642
  • 775
  • Looking forward to the day you create a script for this. Right now I think I may lack the ability to write such a script :/ – umop apisdn Apr 11 '18 at 06:51
1

You can use any of below options to update the PR in local repo.

Option 1: delete the local source branch and recreate to get the update

As you use the commands to get the source branch of the PR locally:

git fetch upstream pull/<PR#>/head:<branchName>
git checkout <branchname>

If the PR is updated (new commits are pushed to the fork repo), you can delete and recreate by:

git checkout master
git branch -D <branchname>
git fetch upstream pull/<PR#>/head:<branchName>
git checkout <branchname>

Option 2: add the fork repo as a remote for your local repo

You can add the fork repo as a remote for your local repo by

git remote add fork1 <URL for the fork repo> -f

Then you can create a local branch for the PR source branch by

git checkout -b <branchname> fork1/<branchname>

If the PR has been updated, you just need to execute below commands to get the update:

git fetch fork1
git checkout <branchname> #If HEAD is not on the <branchname>
git reset --hard fork1/<branchname>
Marina Liu
  • 36,876
  • 5
  • 61
  • 74
  • Thanks for the suggestions! Interestingly both sound like quite a hassle - imagine if I have to review many different contributor's PRs, some of whom may only open one PR ever, then I would have to keep updating my remotes :( but great suggestions nevertheless! – umop apisdn Apr 11 '18 at 06:42
  • You just need to update only one remote which you want to update as the command `git fetch fork1` (or use `git fetch fork1 ` to update only one remote branch). – Marina Liu Apr 11 '18 at 06:47
  • By fork repo, do you mean the original OSS repo? – umop apisdn Apr 11 '18 at 06:50
  • No, the fork repo means the fork of OSS repo. – Marina Liu Apr 11 '18 at 06:53
  • but...but...I already have it as a remote (`origin`) that is usually created by default when I clone the fork repository...Am I misunderstanding something here? – umop apisdn Apr 11 '18 at 06:55
  • Since you are the approver (personal who has permission to commit and push to OSS repo) for the PR to merge into OSS repo, I will suggest you clone the OSS repo (instead of the fork repo), and then add the fork repo as a remote for your local OSS repo. – Marina Liu Apr 11 '18 at 07:00
  • Any way, if you still want to treat the fork repo as origin remote (clone from the fork repo), the option2 in my answer still suitable. Just replace `fork1` with `origin`. – Marina Liu Apr 11 '18 at 07:02
  • you mean `git reset --hard origin/` ? I don't have the branch in my remote repository because I do not intend to modify the branch, just to test it. – umop apisdn Apr 11 '18 at 07:09
  • The purpose of the command `git reset --hard remotename/branchname` is to update the local `` same as the fork repo is. It just make change for the local ``. – Marina Liu Apr 11 '18 at 07:16