1140

I have forked a branch from a repository in GitHub and committed something specific to me. Now I found the original repository had a good feature which was at HEAD.

I want to merge it only without previous commits. What should I do? I know how to merge all commits:

git branch -b a-good-feature
git pull repository master
git checkout master
git merge a-good-feature
git commit -a
git push
A_P
  • 323
  • 1
  • 15
netawater
  • 13,382
  • 4
  • 21
  • 20
  • If you're trying to do this in relation to github, this article will step you through it. http://markosullivan.ca/how-to-handle-a-pull-request-from-github/ – johndpope May 23 '11 at 01:10

9 Answers9

1271

'git cherry-pick' should be your answer here.

Apply the change introduced by an existing commit.

Do not forget to read bdonlan's answer about the consequence of cherry-picking in this post:
"Pull all commits from a branch, push specified commits to another", where:

A-----B------C
 \
  \
   D

becomes:

A-----B------C
 \
  \
   D-----C'

The problem with this commit is that git considers commits to include all history before them

Where C' has a different SHA-1 ID.
Likewise, cherry picking a commit from one branch to another basically involves generating a patch, then applying it, thus losing history that way as well.

This changing of commit IDs breaks git's merging functionality among other things (though if used sparingly there are heuristics that will paper over this).
More importantly though, it ignores functional dependencies - if C actually used a function defined in B, you'll never know.

Legorooj
  • 2,310
  • 2
  • 10
  • 28
VonC
  • 1,042,979
  • 435
  • 3,649
  • 4,283
  • 1
    @openid000: "more fine grained branches": which is indeed exactly what bdonlan suggested in his answer. – VonC May 22 '09 at 08:47
  • 9
    Note: "git rebase" also changes SHA-1. See also "git rebase vs. git merge ( http://stackoverflow.com/questions/804115/git-rebase-vs-git-merge ) and "git workflow" ( http://stackoverflow.com/questions/457927/git-workflow-and-rebase-vs-merge-questions ) for cases where "git rebase" is legitimate. – VonC May 22 '09 at 08:50
  • 1
    Between "fine grained branches", "cherry-pick" and "rebase", you will then have all the possibilities for managing code in branches with git. – VonC May 22 '09 at 08:51
  • @VonC "fine grained branches" yes. I had two branches and I had made upgrades to a particular visualization module in one branch. This module was independent of all other code, so cherry-pick was damn convenient to apply these changes to other branch as well – Cheeku Sep 29 '15 at 07:08
  • 1
    But note that when you merge, both the commits C' and C will prevail in the commit history. – Rahul Shah Jul 11 '17 at 00:12
  • 4
    This answer is not a merge: the resulting commit doesn't have ancestry pointing back to the merged commit. Maybe the OP didn't care about creating a *merge* per se, but the difference does matter sometimes. – LarsH Feb 22 '20 at 03:19
816

You can use git cherry-pick to apply a single commit by itself to your current branch.

Example: git cherry-pick d42c389f

null
  • 3,195
  • 1
  • 17
  • 27
bdonlan
  • 205,037
  • 27
  • 244
  • 316
  • 73
    +1 for your former post on cherry picking ( http://stackoverflow.com/questions/880957/pull-all-commits-from-a-branch-push-specified-commits-to-another/881014#881014 ). I took the liberty to copy an extract of it in my own answer above. – VonC May 19 '09 at 10:24
  • 5
    Probably `git cherry-pick d42c` or `git cherry-pick d42c3` will work. Git is smart. ;) – guneysus Feb 11 '15 at 21:46
  • 3
    fatal: bad revision – Ievgen Naida Jan 25 '19 at 19:31
  • 3
    I just performed this command and it seems to have worked, but when I do git status, it says "nothing to commit, working tree clean". When I refresh the Commits page in my bitbucket web page, it does not show up. But it appears when I execute git log. And I see the modified code. Can someone explain if I have to do any additional steps? – Ray Jan 29 '19 at 18:36
  • git reset --soft HEAD~1 will remove the commit and shows the files which are added. – Aslam anwer Apr 30 '19 at 09:28
  • I used this.. https://www.hacksparrow.com/git/how-to-merge-a-specific-commit-in-git.html – Ziggler Oct 09 '19 at 15:48
  • 4
    Unfortunately this doesn't answer the question: It doesn't actually create a merge. There's no ancestry pointing to `d42c389f`. Maybe the OP didn't care about creating a *merge* per se, but the difference does matter sometimes. – LarsH Feb 22 '20 at 03:22
31

Let's try to take an example and understand:

I have a branch, say master, pointing to X <commit-id>, and I have a new branch pointing to Y <sha1>.

Where Y <commit-id> = <master> branch commits - few commits

Now say for Y branch I have to gap-close the commits between the master branch and the new branch. Below is the procedure we can follow:

Step 1:

git checkout -b local origin/new

where local is the branch name. Any name can be given.

Step 2:

  git merge origin/master --no-ff --stat -v --log=300

Merge the commits from master branch to new branch and also create a merge commit of log message with one-line descriptions from at most <n> actual commits that are being merged.

For more information and parameters about Git merge, please refer to:

git merge --help

Also if you need to merge a specific commit, then you can use:

git cherry-pick <commit-id>
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Spyder
  • 724
  • 1
  • 11
  • 17
  • did you change the definition of `Y` in your 3d sentence? "I have a new branch pointing to Y" vs "Now say for Y branch", sounds like Y used to be a commit and then it became a branch – Purefan May 08 '18 at 10:48
  • how i can do that from a certain commit point of a branch which i want to merge – Kulbhushan Singh Oct 22 '18 at 07:04
13

Let's say you want to merge commit e27af03 from branch X to master.

git checkout master
git cherry-pick e27af03
git push
Shital Shah
  • 47,549
  • 10
  • 193
  • 157
11

The leading answers describe how to apply the changes from a specific commit to the current branch. If that's what you mean by "how to merge," then just use cherry-pick as they suggest.

But if you actually want a merge, i.e. you want a new commit with two parents -- the existing commit on the current branch, and the commit you wanted to apply changes from -- then a cherry-pick will not accomplish that.

Having true merge history may be desirable, for example, if your build process takes advantage of git ancestry to automatically set version strings based on the latest tag (using git describe).

Instead of cherry-pick, you can do an actual git merge --no-commit, and then manually adjust the index to remove any changes you don't want.

Suppose you're on branch A and you want to merge the commit at the tip of branch B:

git checkout A
git merge --no-commit B

Now you're set up to create a commit with two parents, the current tip commits of A and B. However you may have more changes applied than you want, including changes from earlier commits on the B branch. You need to undo these unwanted changes, then commit.

(There may be an easy way to set the state of the working directory and the index back to way it was before the merge, so that you have a clean slate onto which to cherry-pick the commit you wanted in the first place. But I don't know how to achieve that clean slate. git checkout HEAD and git reset HEAD will both remove the merge state, defeating the purpose of this method.)

So manually undo the unwanted changes. For example, you could

git revert --no-commit 012ea56

for each unwanted commit 012ea56.

When you're finished adjusting things, create your commit:

git commit -m "Merge in commit 823749a from B which tweaked the timeout code"

Now you have only the change you wanted, and the ancestry tree shows that you technically merged from B.

LarsH
  • 25,732
  • 8
  • 77
  • 136
10

I used to cherry pick, but found I had some mysterious issues from time to time. I came across a blog by Raymond Chen, a 25 year veteran at Microsoft, that describes some scenarios where cherry picking can cause issues in certain cases.

One of the rules of thumb is, if you cherry pick from one branch into another, then later merge between those branches, you're likely sooner or later going to experience issues.

Here's a reference to Raymond Chen's blogs on this topic: https://devblogs.microsoft.com/oldnewthing/20180312-00/?p=98215

The only issue I had with Raymond's blog is he did not provide a full working example. So I will attempt to provide one here.

The question above asks how to merge only the commit pointed to by the HEAD in the a-good-feature branch over to master.

Here is how that would be done:

  1. Find the common ancestor between the master and a-good-feature branches.
  2. Create a new branch from that ancestor, we'll call this new branch patch.
  3. Cherry pick one or more commits into this new patch branch.
  4. Merge the patch branch into both the master and a-good-feature branches.
  5. The master branch will now contain the commits, and both master and a-good-feature branches will also have a new common ancestor, which will resolve any future issues if further merging is performed later on.

Here is an example of those commands:

git checkout master...a-good-feature  [checkout the common ancestor]
git checkout -b patch
git cherry-pick a-good-feature  [this is not only the branch name, but also the commit we want]
git checkout master
git merge patch
git checkout a-good-feature
git merge -s ours patch

It might be worth noting that the last line that merged into the a-good-feature branch used the "-s ours" merge strategy. The reason for this is because we simply need to create a commit in the a-good-feature branch that points to a new common ancestor, and since the code is already in that branch, we want to make sure there isn't any chance of a merge conflict. This becomes more important if the commit(s) you are merging are not the most recent.

The scenarios and details surrounding partial merges can get pretty deep, so I recommend reading through all 10 parts of Raymond Chen's blog to gain a full understanding of what can go wrong, how to avoid it, and why this works.

Brain2000
  • 3,807
  • 2
  • 24
  • 32
  • I think this is the perfect answer. Thank you. Cherry-pick is very risky. If you cherry-pick a commit X from branchB to branchA, and later if you make commit Y in branchB that changes what commit X did, and you later try to merge branchB to branchA , you will surely get merge conflict. – Sagar Kumar Adhikari Apr 24 '21 at 18:18
5

In my use case we had a similar need for CI CD. We used git flow with develop and master branches. Developers are free to merge their changes directly to develop or via a pull request from a feature branch. However to master we merge only the stable commits from the develop branch in an automated way via Jenkins.

In this case doing cherry-pick is not a good option. However we create a local-branch from the commit-id then merge that local-branch to master and perform mvn clean verify(we use maven). If success then release production version artifact to nexus using maven release plugin with localCheckout=true option and pushChanges=false. Finally when everything is success then push the changes and tag to origin.

A sample code snippet:

Assuming you are on master if done manually. However on jenkins, when you checkout the repo you will be on the default branch(master if configured).

git pull  // Just to pull any changes.
git branch local-<commitd-id> <commit-id>  // Create a branch from the given commit-id
git merge local-<commit-id>  // Merge that local branch to master.
mvn clean verify   // Verify if the code is build able
mvn <any args> release:clean release:prepare release:perform // Release artifacts
git push origin/master  // Push the local changes performed above to origin.
git push origin <tag>  // Push the tag to origin

This will give you a full control with a fearless merge or conflict hell.

Feel free to advise in case there is any better option.

bobbogo
  • 13,257
  • 3
  • 44
  • 53
nrkkalyan
  • 139
  • 2
  • 5
2

If you have committed changes to master branch. Now you want to move that same commit to release-branch. Check the commit id(Eg:xyzabc123) for the commit.

Now try following commands

git checkout release-branch
git cherry-pick xyzabc123
git push origin release-branch
0

We will have to use git cherry-pick <commit-number>

Scenario: I am on a branch called release and I want to add only few changes from master branch to release branch.

Step 1: checkout the branch where you want to add the changes

git checkout release

Step 2: get the commit number of the changes u want to add

for example

git cherry-pick 634af7b56ec

Step 3: git push

Note: Every time your merge there is a separate commit number create. Do not take the commit number for merge that won't work. Instead, the commit number for any regular commit u want to add.

Rishabh Agarwal
  • 1,109
  • 1
  • 9
  • 19