82

Take this scenario:

  1. I decide to 'fork' a codebase on github.com, and start doing my routine: Edit - Commit - Push; aka hack hack hack.
  2. After I made some changes, I see some changes another person has made on the same project, and I like them!
  3. I decide I want to merge them into mine. Problem is, I only want a 'portion' of one particular commit, out of several commits he has made.

What would be the most efficient method of getting these select amount of changes, merged into my 'fork'?

Inigo
  • 12,186
  • 5
  • 41
  • 70
Tim
  • 2,051
  • 2
  • 14
  • 9
  • Possible duplicate of [How to selectively merge or pick changes from another branch in Git?](https://stackoverflow.com/questions/449541/how-to-selectively-merge-or-pick-changes-from-another-branch-in-git) – Inigo May 01 '18 at 03:33
  • Possible duplicate of [Partly cherry-picking a commit with Git](https://stackoverflow.com/questions/1526044/partly-cherry-picking-a-commit-with-git) – Inigo Oct 07 '18 at 18:32

4 Answers4

119

After trolling the waves of the IRC world, someone gave a great solution:

git cherry-pick SHA1 --no-commit
git add --patch

Hopefully that helps anyone else with the same question!

EDIT: OK, maybe it isn't quite that simple. Here are the full steps:

  1. First you have to be in your repository, do the necessary cd-ing to get to your working directory.

  2. You now need to add the remote branch, and then fetch it. Do this by:

    git remote add someUser git://github.com/someUser/someRepo.git

    git fetch someUser

  3. You can now run commands such as git log someUser/master to find the commit SHA1 you want to merge in 'partially'.

  4. Once you have the SHA, you can now run:

    git cherry-pick -n SHA1

    where SHA1 is the commit SHA, duh!

  5. There quite possibly will be conflicts, depending how old the commit is, and how often that particular area of the project changes. Sorry, but you have to manually resolve these with your trusty editor. So pull out VIM, or whatever else you use, and hack away at the conflicts until you get to the stage where you like the changes.

  6. You now have to reset the index to the HEAD revision, then you can then use the trusty GIT add --patch command to pick and choose what changes you want:

    git reset HEAD

    git add --patch or git add -p

  7. Yay! Commit time:

    git commit -m "I merged a select amount of changes"

  8. To clean up the mess (The stuff you said no to in git add --patch) and only keep the selected changes in your working repository, run:

    git reset --hard HEAD

    Apparently git checkout -f is another option as well.

Tim
  • 2,051
  • 2
  • 14
  • 9
  • I'm glad you found `git add -p`; it's extremely powerful. If you already have the commit in question (e.g. didn't use `--no-commit` on the cherry-pick, or it's one of your commits), you can use `git reset HEAD^` to rewind the index a commit back, then add the changes back in with `git add -p`, committing in steps. If the commit's not at the branch tip, you can use `git rebase -i` and choose to edit the commit in question. – Cascabel Sep 10 '09 at 16:11
  • 3
    nice walk-through. remember if you just want the **entire** commit, you just emit the `-n` in step 4. Like this: `git cherry-pick SHA1` – Hulvej Oct 17 '14 at 08:01
  • The key bit here is `git remote add ` - then you can `git cherry-pick` as normal. – Tom Mar 06 '15 at 10:12
3

I really like Tim's solution, however sometimes I like tinkering in vimdiff. My solution to this problem is crude, but it works for me because I like vim.

I have vimdiff set as my difftool, and then to selectively merge I diff the branch:

git difftool <branch> <file>

Then I go to the pane with the current branch's version and edit the original in vim (sometimes this isn't necessary, but sometimes vimdiff opens a version in /tmp) and disable read-only mode:

:e <file>
:set readonly!

Now I can use vim's patch tools such as do and dp to apply what I want, and make other little edits as I go. When I am done, I save the file, exit out of vim, and then stage and commit the file in git like a regular edit.

As I said, this isn't particularly sophisticated, but it is very powerful, and still purely in the command line. Just be sure to add a clear commit message, as git won't automatically include a merge message for you.

vimdiff example

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Mike D
  • 727
  • 2
  • 10
  • 26
  • I don't think this answer fully qualifies as worthy to be an independent fully-fledged answer. Useful information, but not particularly relevant. (why is this at the top of the answers?) – Mike Kormendy Jul 13 '15 at 03:20
2

I'm not clear on what you want. If you want to bring in only certain commits from the other forks, you can use git cherry-pick SHA. Full explanation on gitready.

hgmnz
  • 13,208
  • 4
  • 37
  • 41
  • I am only after a 'portion' / 'section' / 'a few lines' of one particular commit, merged into my repository. Not particularly file specific. – Tim Sep 10 '09 at 12:45
  • In that case, git format-patch SHA, git apply is an option – hgmnz Sep 10 '09 at 13:00
1

If you only want a port of a commit, you’re probably best off by cherry-picking the commit you want and resetting files you don’t want touched.

git cherry-pick SHA1
git checkout HEAD file1 file2 ... fileN

Of course, if you have several modified parts in a file and only want to keep some of them you have no choice but to edit the file manually, cutting out their changes.

Bombe
  • 81,643
  • 20
  • 123
  • 127