Skip to content

Instantly share code, notes, and snippets.

@katylava
Last active February 27, 2024 10:18
Show Gist options
  • Save katylava/564416 to your computer and use it in GitHub Desktop.
Save katylava/564416 to your computer and use it in GitHub Desktop.
git selective merge

Update 2022: git checkout -p <other-branch> is basically a shortcut for all this.

FYI This was written in 2010, though I guess people still find it useful at least as of 2021. I haven't had to do it ever again, so if it goes out of date I probably won't know.

Example: You have a branch refactor that is quite different from master. You can't merge all of the commits, or even every hunk in any single commit or master will break, but you have made a lot of improvements there that you would like to bring over to master.

Note: This will not preserve the original change authors. Only use if necessary, or if you don't mind losing that information, or if you are only merging your own work.

On master:

> git co -b temp

On temp:

> git merge --no-commit --no-ff refactor

… which stages everything, so:

> git reset HEAD

Then begin adding the pieces you want:

> git add --interactive

The following is from an actual merge.

           staged     unstaged path
  1:    unchanged        +1/-1 deploy_settings.py
  2:    unchanged        +4/-3 requirements.txt
  3:    unchanged        +2/-1 settings/defaults.py
  4:    unchanged        +1/-1 settings/production.py.example

*** Commands ***
  1: status	  2: update	  3: revert	  4: add untracked
  5: patch	  6: diff	  7: quit	  8: help
What now> 

Choose p for patch.

           staged     unstaged path
  1:    unchanged        +1/-1 deploy_settings.py
  2:    unchanged        +4/-3 requirements.txt
  3:    unchanged        +2/-1 settings/defaults.py
  4:    unchanged        +1/-1 settings/production.py.example
Patch update>> 

Enter the number next to the file you want to process first. You can keep entering numbers until you've selected all the files, or you can do them one at a time. An asterisk will appear next to the files you select.

When you are finished selecting files, press 'enter' without entering a number (or anything) to continue to the next step.

You will see a single diff hunk and it will ask you whether to stage it or not.

diff --git a/deploy_settings.py b/deploy_settings.py
index 9b110f4..c5b228e 100644
--- a/deploy_settings.py
+++ b/deploy_settings.py
@@ -4,7 +4,7 @@ This file holds the Fabric deployment settings for this project
 from fabric.state import env

 #env.project = 'my_project'   #The name of this project
-#env.repo_base = 'git@git.oldsite.com:%s.git' % env.project
+#env.repo_base = 'git@git.newsite.com:%s.git' % env.project

Stage this hunk [y,n,q,a,d,/,e,?]? 

Enter y to stage or n to skip. This will go on for every diff hunk in the selected files until you get back to:

*** Commands ***
  1: status	  2: update	  3: revert	  4: add untracked
  5: patch	  6: diff	  7: quit	  8: help
What now> 

You can enter s to see what you changed

           staged     unstaged path
  1:    unchanged        +1/-1 deploy_settings.py
  2:        +4/-3      nothing requirements.txt
  3:        +2/-1      nothing settings/defaults.py
  4:    unchanged        +1/-1 settings/production.py.example

*** Commands ***
  1: status	  2: update	  3: revert	  4: add untracked
  5: patch	  6: diff	  7: quit	  8: help
What now> 

You can quit now, so enter q, Then do some status and diff commands to explore the staged vs unstaged changes and make sure it looks like you expected.

Don't forget to git add any untracked files as appropriate.

Commit the staged changes:

> git commit -m "merged selected patches from refactor branch"
# don't do commit -a here… you only want to commit the staged changes

Revert the unstaged changes

> git checkout .

And finally, merge to master:

> git checkout master
> git merge temp
> git branch -D temp
@flash42
Copy link

flash42 commented Aug 26, 2014

Nice! When you want to move some files to another branch there is an alternative way though:

$ git checkout mergeTo
$ git checkout mergeFrom list of files to move

At this point files are staged and can be committed simply to mergeTo branch

@hrchu
Copy link

hrchu commented Nov 21, 2014

%s/git reset head/git reset HEAD/

@Geruhn
Copy link

Geruhn commented Jul 31, 2015

Thanks a lot! This was what I was looking for!

@Nocturnhabeo
Copy link

Nice thanks.

@Henry0422
Copy link

👍👍

@yduman
Copy link

yduman commented Nov 18, 2016

Lifesaver!

@mfurlend
Copy link

Excellent, thanks!

@DaoyuT
Copy link

DaoyuT commented Apr 28, 2017

This is so great, thanks a lot!

@nhovratov
Copy link

Thanks this helped a lot!

@tsutsarin-fuib
Copy link

Awesome workflow!

Note, if we deleting merged branch better to use:

git branch -d test

Instead of -D option.

@Fedreg
Copy link

Fedreg commented Jul 19, 2017

REALLY helpful today! Thanks for writing this up!! Learned a ton.

@nondeterministic
Copy link

Thanks so much! That was a very helpful article. Minor typo: head -> HEAD.

@sstadelman
Copy link

huge help!

@bimlas
Copy link

bimlas commented May 29, 2018

⚠️ NO! Don't do any kind of partial merge! Chekout the files or hunks from another branch, but don't do it as git merge! Here's the reason:
https://github.com/bimlas/learning-by-testing-git-partial-merge/tree/doc

@karthik4
Copy link

karthik4 commented Jun 2, 2018

Thanks! Exactly what I was looking for!

@nateyoder
Copy link

Thanks this is super helpful!

@dylantuxsimpson
Copy link

This was super helpful! A modification I found to be helpful: If you create two 'dummy branches' (so to speak), one at master and one at refactor, then merge these using the --no-commit --no-ff command, your original refactor branch will remain with a record of your commit history. It's not pretty because you have an unresolved branch, but it retains the info if you need it.

@SaganRitual
Copy link

Thank you so much!

@Orangetronic
Copy link

Thanks for this! mega handy

@PhanaThor
Copy link

Thank you for this. It helped me a lot!

@nlpsuge
Copy link

nlpsuge commented Aug 5, 2019

Hi guys:

Can merging partially lead to lost commits or files in any cases?

@nlpsuge
Copy link

nlpsuge commented Aug 6, 2019

NO! Don't do any kind of partial merge! Chekout the files or hunks from another branch, but don't do it as git merge! Here's the reason:
https://github.com/bimlas/learning-by-testing-git-partial-merge/tree/doc

Hi, the link is dead. PLEASE update it.
Any way I lost several commits after partial merge... I'm looking and thinking why...

@rakisomaiah
Copy link

@nlpsuge - were you able to find why you lost those commits from partial merge

@nlpsuge
Copy link

nlpsuge commented Aug 30, 2019

@rakisomaiah

Step 1: Switch to the branch you want to merge with, for example, dev_target_branch

Step 2: Merge a branch with dev_target_branch, for example, dev_another_branch
git merge --no-commit --no-ff dev_another_branch

Step 3:
In IDEA, go to Project -> Git, click 'Commit Directory...'. Only choose those files/directories you want to commit, then Commit.

Step 4:Override those files/directories you don't want to commit.
git checkout -- files_or_directories_you_do_not_want_to_commit

Step 5:Commit and push partial commits

Step 6:
In IDEA, merge origin/master with dev_target_branch, then commit and push.

After a few days, I found some codes in files_or_directories_you_do_not_want_to_commit no in the branch dev_another_branch.

Unfortunately, I can't reproduce this issue according above steps. I don't know exactly why this happens.

@lacivert
Copy link

lacivert commented May 7, 2020

NO! Don't do any kind of partial merge! Chekout the files or hunks from another branch, but don't do it as git merge! Here's the reason:
https://github.com/bimlas/learning-by-testing-git-partial-merge/tree/doc

Hi, the link is dead. PLEASE update it.
Any way I lost several commits after partial merge... I'm looking and thinking why...

Not sure but this may be the same link in gitlab
https://gitlab.com/bimlas/learning-by-testing-git-partial-merge/-/tree/doc

@v-stickykeys
Copy link

I love that this is still dead useful 8 years later

@myudkowsky
Copy link

Thanks very much!

Please fix this small error:
git reset head
to
git reset HEAD

@Maaxion
Copy link

Maaxion commented Feb 9, 2021

Thanks a lot, very helpful guide to clean up messy branches!

@dewanggasurya
Copy link

wooooo thanks a lot

@jslevin4
Copy link

Anyone know, if say you have a branch main and a branch dev with more changes, and you do a partial merge of changes from dev into main. If in the future, you want to merge dev into main, will there be merge conflicts, or does it know some changes have already been merged in? Would be pretty easy to test I guess. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment