Partly cherry-picking a commit with Git

GitGit Cherry-Pick

Git Problem Overview


I'm working on 2 different branches: release and development.

I noticed I still need to integrate some changes that were committed to the release branch back into the development branch.

The problem is I don't need all of the commit, only some hunks in certain files, so a simple

git cherry-pick bc66559

does not do the trick.

When I do a

git show bc66559

I can see the diff but don't really know a good way of applying that partially to my current working tree.

Git Solutions


Solution 1 - Git

The core thing you're going to want here is git add -p (-p is a synonym for --patch). This provides an interactive way to add in content, letting you decide whether each hunk should go in or not, and even letting you manually edit the patch if necessary.

To use it in combination with cherry-pick:

git cherry-pick -n <commit> # get your patch, but don't commit (-n = --no-commit)
git reset                   # unstage the changes from the cherry-picked commit
git add -p                  # make all your choices (add the changes you do want)
git commit                  # make the commit!

(Thanks to Tim Henigan for reminding me that git-cherry-pick has a --no-commit option, and thanks to Felix Rabe for pointing out that you need to git reset. If you only want to leave a few things out of the commit, you could use git reset <path>... to unstage just those files.)

You can provide specific paths to add -p if necessary. If you're starting with a patch you could replace the cherry-pick with apply.


If you really want to git cherry-pick -p <commit> (that option does not exist), you can use

git checkout -p <commit>

That will diff the current commit against the commit you specify, and allow you to apply hunks from that diff individually. This option may be more useful if the commit you're pulling in has merge conflicts in part of the commit you're not interested in. (Note, however, that checkout differs from cherry-pick: checkout tries to apply <commit>'s contents entirely, while cherry-pick applies the diff of the specified commit from it's parent. This means that checkout can apply more than just that commit, which might be more than you want.)

Solution 2 - Git

I know I'm answering an old question, but it looks like there's a new way to do this with interactively checking out:

git checkout -p bc66559

Credit to https://stackoverflow.com/questions/5865439/can-i-interactively-pick-hunks-from-another-git-commit

Solution 3 - Git

Assuming the changes you want are at the head of the branch you want the changes from, use git checkout

for a single file :

git checkout branch_that_has_the_changes_you_want path/to/file.rb

for multiple files just daisy chain :

git checkout branch_that_has_the_changes_you_want path/to/file.rb path/to/other_file.rb

Solution 4 - Git

Building on Mike Monkiewicz answer you can also specify a single or more files to checkout from the supplied sha1/branch.

git checkout -p bc66559 -- path/to/file.java 

This will allow you to interactively pick the changes you want to have applied to your current version of the file.

Solution 5 - Git

If you want to specify a list of files on the command line, and get the whole thing done in a single atomic command, try:

git apply --3way <(git show -- list-of-files)

--3way: If a patch does not apply cleanly, Git will create a merge conflict so you can run git mergetool. Omitting --3way will make Git give up on patches which don't apply cleanly.

Solution 6 - Git

Use git format-patch to slice out the part of the commit you care about and git am to apply it to another branch

git format-patch <sha> -- path/to/file
git checkout other-branch
git am *.patch

Solution 7 - Git

If "partly cherry picking" means "within files, choosing some changes but discarding others", it can be done by bringing in git stash:

  1. Do the full cherry pick.
  2. git reset HEAD^ to convert the entire cherry-picked commit into unstaged working changes.
  3. Now git stash save --patch: interactively select unwanted material to stash.
  4. Git rolls back the stashed changes from your working copy.
  5. git commit
  6. Throw away the stash of unwanted changes: git stash drop.

Tip: if you give the stash of unwanted changes a name: git stash save --patch junk then if you forget to do (6) now, later you will recognize the stash for what it is.

Solution 8 - Git

Actually, the best solution for this question is to use checkout commend

git checkout <branch> <path1>,<path2> ..

For example, assume you are in master, you want to the changes from dev1 on project1/Controller/WebController1.java and project1/Service/WebService1.java, you can use this:

git checkout dev1 project1/Controller/WebController1.java project1/Service/WebService1.java

That means the master branch only updates from dev1 on those two paths.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionoliverView Question on Stackoverflow
Solution 1 - GitCascabelView Answer on Stackoverflow
Solution 2 - GitMike MonkiewiczView Answer on Stackoverflow
Solution 3 - GitJay SwainView Answer on Stackoverflow
Solution 4 - GitChristian.DView Answer on Stackoverflow
Solution 5 - Gitnyanpasu64View Answer on Stackoverflow
Solution 6 - Gitadrock20View Answer on Stackoverflow
Solution 7 - GitKazView Answer on Stackoverflow
Solution 8 - Git无名小路View Answer on Stackoverflow