Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
git selective merge

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
@kpobococ

This comment has been minimized.

Copy link

kpobococ commented Jul 24, 2012

Oh wow, exactly what I needed! Thanks!

@katylava

This comment has been minimized.

Copy link
Owner Author

katylava commented Jul 25, 2012

Cool, I didn't know anyone actually ever saw this. I made it prettier.

@michaw

This comment has been minimized.

Copy link

michaw commented Sep 13, 2012

Seriously, THIS is the workflow I have been looking for. Thanks!

@chrisvarns

This comment has been minimized.

Copy link

chrisvarns commented Oct 10, 2012

This uses an intermediate branch to merge changes interactively into, has the problem of creating one commit representing all desired changes to be merged. Is there a way to selectively choose commits made to a branch to merge to another? Could this be done by rebasing a temporary branch, and merging that?

@chrisvarns

This comment has been minimized.

Copy link

chrisvarns commented Oct 10, 2012

To clarify, I don't want to remove all the commits/logs from the other branch, which this does. I think rebase would keep the relevant commits and logs, and the target branch after a subsequent merge would therefore keep them also?

@katylava

This comment has been minimized.

Copy link
Owner Author

katylava commented Oct 24, 2012

@jasonwbarnett

This comment has been minimized.

Copy link

jasonwbarnett commented Nov 30, 2012

This is seriously awesome... Thank you

@pappelt

This comment has been minimized.

Copy link

pappelt commented Jan 14, 2013

thx for sharing your workflow

@robotfelix

This comment has been minimized.

Copy link

robotfelix commented May 24, 2013

git merge --no-commit --no-ff refactor was a gem! Staged everything nicely for me to go through the changes in RubyMine and the unwanted ones!

@aarti

This comment has been minimized.

Copy link

aarti commented Aug 26, 2013

Awesome!
I had to do one more thing at the step
Revert the unstaged changes
git checkout .
git clean -f ( to remove files not used)

@kambala-decapitator

This comment has been minimized.

Copy link

kambala-decapitator commented Oct 14, 2013

thanks man!

@ebelew

This comment has been minimized.

Copy link

ebelew commented Jan 3, 2014

This is neat, but it clobbers the original change author(s).

@katylava

This comment has been minimized.

Copy link
Owner Author

katylava commented Jan 7, 2014

@ebelew Yes that's important to know. I've added a note about it to the gist, thanks.

@stupidnetizen

This comment has been minimized.

Copy link

stupidnetizen commented Mar 2, 2014

wow, thanks so much

@yobert

This comment has been minimized.

Copy link

yobert commented Jul 3, 2014

So great

@flash42

This comment has been minimized.

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

This comment has been minimized.

Copy link

hrchu commented Nov 21, 2014

%s/git reset head/git reset HEAD/

@Geruhn

This comment has been minimized.

Copy link

Geruhn commented Jul 31, 2015

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

@Nocturnhabeo

This comment has been minimized.

Copy link

Nocturnhabeo commented May 11, 2016

Nice thanks.

@Henry0422

This comment has been minimized.

Copy link

Henry0422 commented Jun 17, 2016

👍👍

@yduman

This comment has been minimized.

Copy link

yduman commented Nov 18, 2016

Lifesaver!

@mfurlend

This comment has been minimized.

Copy link

mfurlend commented Jan 28, 2017

Excellent, thanks!

@DaoyuT

This comment has been minimized.

Copy link

DaoyuT commented Apr 28, 2017

This is so great, thanks a lot!

@nhovratov

This comment has been minimized.

Copy link

nhovratov commented May 10, 2017

Thanks this helped a lot!

@tsutsarin-fuib

This comment has been minimized.

Copy link

tsutsarin-fuib commented Jun 2, 2017

Awesome workflow!

Note, if we deleting merged branch better to use:

git branch -d test

Instead of -D option.

@Fedreg

This comment has been minimized.

Copy link

Fedreg commented Jul 19, 2017

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

@nondeterministic

This comment has been minimized.

Copy link

nondeterministic commented Jan 28, 2018

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

@sstadelman

This comment has been minimized.

Copy link

sstadelman commented Feb 12, 2018

huge help!

@bimlas

This comment has been minimized.

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

This comment has been minimized.

Copy link

karthik4 commented Jun 2, 2018

Thanks! Exactly what I was looking for!

@nateyoder

This comment has been minimized.

Copy link

nateyoder commented Jun 5, 2018

Thanks this is super helpful!

@dylantuxsimpson

This comment has been minimized.

Copy link

dylantuxsimpson commented Dec 21, 2018

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

This comment has been minimized.

Copy link

SaganRitual commented Mar 30, 2019

Thank you so much!

@Orangetronic

This comment has been minimized.

Copy link

Orangetronic commented Apr 24, 2019

Thanks for this! mega handy

@PhanaThor

This comment has been minimized.

Copy link

PhanaThor commented May 14, 2019

Thank you for this. It helped me a lot!

@nlpsuge

This comment has been minimized.

Copy link

nlpsuge commented Aug 5, 2019

Hi guys:

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

@nlpsuge

This comment has been minimized.

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

This comment has been minimized.

Copy link

rakisomaiah commented Aug 29, 2019

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

@nlpsuge

This comment has been minimized.

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.