Partly cherry-picking a commit with Git

135,767

Solution 1

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

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 Can I interactively pick hunks from another git commit?

Solution 3

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

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

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.

Share:
135,767
oliver
Author by

oliver

I'm not a ruby on rails developer! I don't know why I keep getting offers by recruiters about this but I honestly never wrote more than a hello world app in rails. What I'm interested in is building scalable concurrent systems, good user experiences and in general good programming languages (e.g. rust).

Updated on July 08, 2022

Comments

  • oliver
    oliver almost 2 years

    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.

  • Felix Rabe
    Felix Rabe over 12 years
    Actually, if I follow the advice with git 1.7.5.4, 'git add -p' says 'No changes' because it's all already in the index. I need to do a 'git reset HEAD' before 'git add' - any way to avoid that reset with some option?
  • Cascabel
    Cascabel over 12 years
    @FelixRabe: I'm actually surprised that at some point cherry-pick -n apparently didn't leave the changes staged - the convention is definitely that --no-commit options stop right before the commit, i.e. with all the changes staged. I'll add the reset into the answer.
  • Jeremy List
    Jeremy List over 10 years
    That copies the whole file: not only the changes.
  • Pierre-Olivier Vares
    Pierre-Olivier Vares over 9 years
    If you just cherry-pick, then reset... you won't anything to stash. As said above, you have either to do a cherry-pick with --no-commit, or a reset --hard HEAD~. Note that you are proceding negatively (selecting what you don't want). The above accepted solution allow either a positive or a negative approach.
  • Cascabel
    Cascabel over 9 years
    @Blixt That is, if the commits that are on the other branch but not your current branch are A-B-C-D-E-F, git checkout -p <F> does not just get you the changes from F, it gets you ABCDEF all mashed together and lets you sort out what part of that you want. Paring that down to just some of the changes from F is a pain. On the other hand, git cherry-pick -n <F> gets you only the changes from F - and if some of those changes conflict, it helpfully tells you so that you can figure out how to merge properly.
  • Kaz
    Kaz about 9 years
    This is problematic if the current version of the file is significantly different from that version. You will be prompted with numerous irrelevant changes (which do not appear in the commit). Also, the changes you really want may appear in a "disguised form" as a difference to the current, not the original difference. It's possible that the original difference you want conflicts, and has to be properly merged; you won't have that opportunity here.
  • pfalcon
    pfalcon over 8 years
    This answer, just as any other answer here so far, has a big drawback: it doesn't preserve the original author of the change, instead committing under your name. If a change is good, you're stealing somebody's credit, if a change is bad, you're putting yourself on the fire. It seems there's no way around having git cherry-pick -p, and shame it's still not there.
  • Auguste Van Nieuwenhuyzen
    Auguste Van Nieuwenhuyzen almost 8 years
    I had problems with this when the change was a file addition. The git reset would remove the staged files and the add -p would just say 'nothing to add'.
  • Tim Visée
    Tim Visée over 3 years
    Note that this method doesn't retain the original commit author and commit date. You can set these with git commit --author="USER <MAIL>" --date="DATE", use the author and date details shown on top of git show CHERRY_PICK_SHA.
  • Fizz
    Fizz over 2 years
    It's ridiculous it (still) has to be done like this in 2022, and that there's no cherry-pick -i.
  • Fizz
    Fizz over 2 years
    Yeah, I've used/discovered this method already. Note that it doesn't create a commit, you have to do that yourself, and there's no quick way to make it auto-record in the commit msg what stuff was cherry picked (this way). Kludgy, kludgy git.
  • raphinesse
    raphinesse over 2 years
    Use the equivalent git show -- list-of-files | git apply --3way - if your shell chokes on <(...)