285

I forked a project on github and am successfully making changes to my local master and pushing to origin on github. I want to send a pull request, but only want to include the last commit. The pull request UI on github.com shows the last 9 commits and I don't know how to filter that down.

I was trying to understand if I should create a new local branch, check that out and somehow reset or rebase to upstream? Then apply my last commit from my master by id to the new local branch and use that for the pull request?

I'm trying to get the concepts right and figure out the right command lines to do what I need.

random
  • 9,774
  • 10
  • 66
  • 83
Kevin Hakanson
  • 41,386
  • 23
  • 126
  • 155
  • And what happens if you do a pull request with all other commits? I thought git is clever enough to ignore (or pass) the commits that it already pulled in? – jayarjo Jun 29 '12 at 09:38
  • 3
    Presumably the upstream hasn't accepted yet, or does not want, the intervening commits. – Michael Scott Asato Cuthbert Jun 08 '14 at 21:31
  • @jayarjo I for example made other changes I don't want to send upstream. Changes to git ignore the main repository won't need for example. Nothing easy with git. – Martin Jul 01 '17 at 09:17
  • Related: Some good details on [how the pull requests are different](https://stackoverflow.com/q/6235379/465053) in Git (the software) and GitHub (the web service) – RBT Aug 12 '17 at 03:21

7 Answers7

310

You need to basically create a new branch & cherry-pick the commits you want to add to it.

Note: you might need these before the checkout/cherry-pick commands

git remote add upstream <git repository>

git remote update

git checkout -b <new-branch-name> upstream/master

git cherry-pick <SHA hash of commit>

git push origin <new-branch-name>

Afterwards, you will see <new-branch-name> branch on github, switch to it and can submit the pull request with the changes you want.

Community
  • 1
  • 1
Kevin Hakanson
  • 41,386
  • 23
  • 126
  • 155
  • Thank you, this solution helped me as well. Here is a link that explains how cherry-picking works in git: http://technosophos.com/content/git-cherry-picking-move-small-code-patches-across-branches (scroll down and ignore the PHP-errormessages). – dubbaluga Dec 23 '12 at 20:35
  • 32
    I also need to ```git remote add upstream ``` and ```git remote update``` before running git checkout -b upstream upstream/master. – plainjimbo May 07 '13 at 21:13
  • This worked for me as well. Stupid Github's new interface. I can't understand how to select a specific commit and create a new pull request. Luckily this worked. – firesofmay Jul 03 '13 at 21:51
  • 6
    This works, but is not how you are supposed to do it, because now your upstream branch and upstream/master are different and will always be different if merging your pull request is not the first thing upstream does. For that reason you should prefer doing http://stackoverflow.com/a/5256304/1904815. – JonnyJD Aug 07 '13 at 06:55
  • 2
    To elaborate: This isn't a technical problem, but a logical one. When you want to do anything with upstream (like merging from there) you need to add a branch "real-upstream" or reset your upstream (leaving no local branch for your pull request for additional changes). – JonnyJD Aug 07 '13 at 07:01
  • 1
    Git newbie here. Thanks @Jimbo for the comment about `git remote add upstream `; just want to add that the `` should be the the one you cloned from, I initially used my own one and found not working. – wangzq Apr 03 '15 at 04:50
  • 17
    Why on earth do I need an extra branch, only to create a PR for a single changed line of code?! Did anyone at github think this through? – CodeManX Aug 20 '15 at 01:31
  • @CoDEmanX why do you need an extra branch to request that a branch be merged in? That answers itself. – Jon Hanna Mar 23 '16 at 10:49
  • 2
    @JonHanna No... why do you have to merge a branch at all? Why can't you just merge a commit? – Kevin Krumwiede Aug 18 '16 at 15:27
  • @KevinKrumwiede you can, but you aren't at that point yet; you're at the point of asking for something to be merged in. The user in question may have one commit they want merged, but they may have several, so github needs a way to group together one or more commits for that request. There's already a facility in git for having a group of one or more commits, which is a branch, so build on that. Also, the user is going to have to have another branch to do any more work on the project in the meantime anyway. – Jon Hanna Aug 18 '16 at 15:55
  • 1
    @JonHanna You are guessing quite a lot for the fact that we simply know that the user in question just asked for the merge of exactly one commit, not necessarily a branch. So wondering why one needs to deal with branches is totally comprehensible. – Thorsten Schöning Dec 12 '16 at 18:52
  • 1
    @ThorstenSchöning I'm guessing nothing beyond that a user wants one or more commits merged in, which is a valid assumption and a concept for which git has a mechanism (branch). A user guessing they only want one commit merged in is the one doing guessing (how do they know they won't be asked for a further modification before the PR is accepted?). It's not like branches cost anything. – Jon Hanna Dec 12 '16 at 18:55
  • It seems somewhat of a tedious waste to have to create a branch before every commit - just to ensure that commits are separate. You'd have as many branches as commits - and then branches and commits are two required steps for one logical operation. Is there a way to have the GitHub desktop client automatically create the required branch before committing? – Ian Boyd Nov 13 '18 at 21:30
59

Create a new branch starting from the latest commit, which is also in the origin repository:

git branch new-branch origin/master
git checkout new-branch

Then use git cherry-pick to get the single commit you want the pull request for. If the branch with this commit is called feature and the commit you want is the latest commit in this branch, this will be

git cherry-pick feature

Assuming this patch applies without conflict, you got now a branch for which you can do your pull request.

In a second step, you now need to decide what to do with your feature branch. If you haven't published your changes on this branch yet, the best procedure is probably rebasing this branch upon new-branch (and removing the last commit, if this is not done automatically by git rebase).

Lars Noschinski
  • 3,667
  • 16
  • 29
  • I get this message after the cherry-pick. nothing added to commit but untracked files present (use "git add" to track). Everything is in my master, but I need to make my branch from the upstream. – Kevin Hakanson Mar 10 '11 at 13:22
  • 5
    If the `feature` is already committed in `origin/master`, nothing happens during `cherry-pick`. The new branch should be from `upstream/master` (i.e., Kevin Hakanson's answer) – ohho Jan 31 '13 at 10:32
26

I ended up in a situation where I had forked a fork and wanted to submit a pull request back to the original project.

I had:

  • orignal_project
  • forked_project (created from original project at SHA: 9685770)
  • my_fork (created from forked project at SHA: 207e29b)
  • a commit in my fork (SHA: b67627b) that I wanted to submit back to original project

To do this, I:

  1. created a new branch from the SHA where the original project was forked
  2. pulled all from the original project
  3. cherry picked the commit I wanted to submit as a pull request
  4. pushed it all up to github

The git commands were something like:

  1. git branch my-feature-request 9685770
  2. git checkout my-feature-request
  3. git pull https://github.com/original_project/original_project.git
  4. git cherry-pick b67627b
  5. git push origin my-feature-request

Then I picked my-feature-request as the branch for my pull request to the original project.

John Naegle
  • 8,077
  • 3
  • 38
  • 47
6

This almost worked for me:

git checkout -b upstream upstream/master

git cherry-pick <SHA hash of commit>

git push origin upstream

The only difference was this:

git push origin upstream:upstream

I needed to change that last line so that git push would make the upstream branch in my GitHub repo so that I could make PR from it.

6

I had already made the commit which I wanted to be able to isolate as a pull request back onto the current branch.

So I checked out a new branch

git checkout -b isolated-pull

And here's where my solution differs from @Kevin Hakanson's, as I need to reset this branch to the place in the history I want to diff from

git reset --hard [sha-to-diff-by]

And cherry-pick the commit from which I want to create an isolated pull request

git cherry-pick [my-isolated-commit-sha]

Finally push it up to the remote

git push origin isolated-pull

And pull request dat shi.

irbanana
  • 860
  • 12
  • 19
  • Thanks, I really hate Git and all the other answers were throwing error I was too lazy to fix, but your answer worked right away. Thank you a lot – Sasino Jan 10 '21 at 01:40
1

The solution to create a new (temporary) branch, cherry-pick and creating the pull request for that branch did not satisfy me. I did not want to change my repository to make a set of commits available, so I came up with the following alternative:

First create patch files for all commits of interest:

git format-patch -1 <sha>

If the commit of interest happens to be the last one you can use HEAD instead <sha>.

Now, you can send the patches to the maintainer of the source repository, who can apply them:

git branch new-branch <master or some older commit where the fork diverged>
git checkout new-branch

git am < <the patch>
...

git checkout master
git merge new-branch

Finally this should look the same as if a temporary branch was merged by a pull request, but without having that additional branch in the fork-repository.

Johannes Jendersie
  • 980
  • 10
  • 16
0

Based on @kevin-hakanson's answer, I wrote this little bash script to make this process easier. It will add the upstream repo if it doesn't already exist (prompting you for the URL) then prompt for both the name of the new branch to create and the tag / SHA of the commit to cherry pick onto that branch. It checks what branch or commit you're currently on then stashes any changes so you can checkout the new branch. The merge strategy keeps the changes from the cherry-picked commit. After pushing the new branch to origin (assumed to be the name of your remote repo), the branch or commit you were on before is checked out again and your previous changes popped from the stash.

if ! git remote | grep -q upstream; then
    read -p "Upstream git repo URL: " upstream
    git remote add upstream $upstream
    git remote update
fi

read -p "Feature branch name: " feature_branch
# note: giving "master" is the same as giving the SHA it points to
read -p "SHA of commit to put on branch: " sha

current_branch=$(git rev-parse --abbrev-ref HEAD)
if [ "$current_branch" == "HEAD" ]; then
    # detached HEAD; just get the commit SHA
    current_branch=$(git rev-parse --short HEAD)
fi
git stash
git checkout -b $feature_branch upstream/master
git cherry-pick --strategy=recursive -X theirs $sha
git push origin $feature_branch
git checkout $current_branch
git stash pop

(This has worked for me in a couple of simple tests, but I'm not a bash programmer or git expert, so let me know if there are cases I've missed that could be automated better!)

Nathan
  • 9,651
  • 4
  • 45
  • 65