87

I am trying to merge a local branch into the master branch without having Git to do an automerge. I would like to “hand pick” what I would like to be merged into master.

When I use Git’s difftool command, I am able to diff and select what I want to be added into the master branch. But then when I do a merge, I will lose what I selected prior because Git will do an automerge. I can commit the changes into master prior to the merge, but doing so seems unnatural.

And Git’s mergetool is only available when there are conflicts from a merge. But if Git does an automerge then usually there aren’t conflicts, so I am unable to run the mergetool command.

Update:

I am starting to think what I am trying to accomplish is bad practice or it’s just not possible. That is, to merge a topic branch and only have it merge what I need from diffing. And in an addition, to have this reflected in history. At any rate, the question I posted surfaced when experimenting with Git.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
marckassay
  • 1,350
  • 1
  • 11
  • 19
  • Where are these changes you're "selecting prior" coming from? They're local modifications in your work tree before you do the merge? Are you trying to merge a branch and keep only some of the changes from it? – Cascabel Mar 08 '11 at 18:51
  • Jefromi, to answer your first question, they’re changes from diffing the topic branch. Its what I mentioned in the second paragraph, first sentence. An answer to your second question, yes they’re local modifications. That’s why if I do a merge (without a commit first) I will lose those diffs. And to answer your third question, yes. I am trying to merge a branch and keep only some of the changes from it by picking what I want by using a diff tool (eg. KDiff3). – marckassay Mar 09 '11 at 14:47
  • With respect to your update: this is indeed bad practice if you ever intend to merge the rest of that branch. Once you record a merge, it's an indication that you have the content of the merged commit(s). You can certainly do what you were starting to do, though - selectively apply a few lines of the diff with the topic branch, and commit those directly (not as a merge). That should (hopefully) not result in conflicts if you later merge the whole topic. – Cascabel Mar 09 '11 at 14:55
  • 1
    Please accept an answer here. – mega6382 Nov 20 '17 at 08:20

5 Answers5

103

You are trying to bypass Git from getting involved in the merge process and to hand-pick each line of each modified file to be merged. This not the same as git cherry-pick. Neither will git merge --no-commit, etc. help. You will need to do:

$ git checkout master
$ git difftool -t kdiff3 local-branch HEAD

In the KDiff3 window, the left hand side (A) is your local-branch and the right hand side (B) is your current branch (master).

Select Merge | Merge Current File from the menu (or press the colorful diamond shaped icon with the same title).

You will then be shown a diff and conflicts (if any) for each file. And you will have the ability to pick left or right side (A or B), or both, and/or manually tweak the merged file.

On another note, something is telling me you have some bigger issues with your workflow.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
FractalSpace
  • 5,577
  • 3
  • 42
  • 47
  • 2
    Choose as THE answer! – Lordbalmon Mar 18 '15 at 13:45
  • 4
    -t kdiff3 is not required or useful if you have already properly set up your difftool using git config. – digory doo May 20 '15 at 05:14
  • 62
    There's nothing necessarily wrong with OP's workflow. He could just be facing a complicated merge. Git likes to decide that some merges are "safe" and perform them silently when they're really not safe at all. – Rag Jul 06 '15 at 23:46
  • 1
    @BrianGordon This is not a proper workflow in git to manually move contents from one branch to the other on regular basis. This will make both branches diverge and make git lose any ability to track change history in relationship to the other branch. There are however cases when you do want to do this this, e.g the old branch becomes obsolete and you need to salvage some part of the code. – FractalSpace Jul 29 '15 at 13:09
  • 9
    @FractalSpace when you get a merge conflict, you are picking and choosing as well. If you think picking and choosing is a flawed process, it is no worse (and possibly better) than "hope for the best" auto-merge. – Apprentice Queue Jan 17 '16 at 02:56
  • 5
    @Apprentice Queue you are missing the point. When git does merge and there are no conflicts, you don't get to pick and choose anything. git magically merges the files, which is what op wants to avoid. – FractalSpace Mar 24 '17 at 15:19
  • Which is the merge "direction" in this answer? Does it merge master into local-branch or local-branch into master? – Szczepan Hołyszewski Jan 11 '18 at 17:48
  • How can I improve this so that new files (created in the "local-branch") are always transferred to the merge result, bypassing the difftool? – Szczepan Hołyszewski Jan 11 '18 at 17:53
  • 2
    @SzczepanHołyszewski The merge direction is `local-branch` to `master` – FractalSpace Jan 11 '18 at 21:46
  • This works fine if I merge files that already exisit in both branches, but what if I have completely new files in the branch I want to merge? If I copy the files using the difftool (I use bcompare) they are not taken over from the temp to the working directory. – Dill Oct 26 '18 at 09:21
  • You will have to manually copy all new files to the destination. e.g you can use the difftool by itself (without git) to do a directory compare and copy over files as needed. – FractalSpace Oct 26 '18 at 14:06
  • 1
    On Windows, I use `vsdiffmerge` instead of `kdiff3`. – KaiserKatze Jul 29 '19 at 01:31
27
git merge --no-commit --no-ff <local-branch>

does it.

When you executed it, the changes from local-branch are applied but not yet staged.

Then, you could look at the changes to be applied and –  in case that you want to take them all  – apply them with

git commit -a 

Otherwise, select the files to be taken, stage them with git add and finally commit them with git commit. Restore the unwanted files then with git checkout -- filename.

eckes
  • 64,417
  • 29
  • 168
  • 201
  • 7
    I tried that command and it seems that it did an automerge and staged the file. After running the first command I got the following message: Automatic merge went well; stopped before committing as requested – marckassay Mar 09 '11 at 14:48
  • 3
    @marckassy: But you could then `git reset HEAD` and `git add -p` to select what you want. – Cascabel Mar 09 '11 at 15:12
  • 3
    To shut off the initial merge completely, add `-s ours`. – jthill Nov 28 '13 at 01:56
  • 3
    I wanted to achieve the same goal and, after `git merge --no-commit --no-ff ` I ran a `git reset HEAD`. In this way, all changes "staged for commit" became "unstaged". Now with `git diff` I can see the full diff, I can `add` and `commit` what I want and discard the unwanted changes – Davide Mar 04 '14 at 15:00
8

I can see you may wish to do this if you do not trust auto-merge, because two edits in different places in a file (which are done on different branches) may not cause auto-merge to raise a conflict but may not actually work together.

You may want to look at using a custom merge driver. This page describes how to go about it.

Git - how to force merge conflict and manual merge on selected file

An alternative would be to find the files that differ between the branches first, before performing the merge, then checkout the file into the appropriate branch to ensure you get a clean merge and functional code that contains either one or the other of the two edits.

git diff --name-only <branch1> <branch2> 
git checkout <branch1> -- <paths>
Community
  • 1
  • 1
andrew pate
  • 3,833
  • 36
  • 28
  • 3
    It is not about not trusting automerge. It is about it giving me no information at all as to what git did to the file. – Scott Franco Aug 29 '21 at 17:18
  • I guess one way would be to see what files are different on the other branch then examine what is different about each one before you merge ***What files are different on the other branch*** git diff --name-only otherbranch ***What is different about a particular file, in the other branch*** git diff -p master someotherbranch -- the_specific_file.txt – andrew pate Sep 09 '21 at 16:45
  • Of course that is the fallback. What I was talking about is that git gives you a message "refs could not be pushed, execute pull", then if you do that it says "automerge" (with no details about what is going to be "automerged". Its a terrible error message. – Scott Franco Sep 10 '21 at 17:26
1

For vim & vim-fugitive users:

Add the following to ~/.gitconfig

[difftool "fugitive"]
  cmd = vimdiff $LOCAL $MERGED $REMOTE
  trustExitCode = false
  keepBackup = false

Now use Fugitive for a 3 way diff

$ git checkout master
$ git difftool -t fugitive somebranch HEAD

Note on $LOCAL, $MERGED, $REMOTE:

$LOCAL The file on the branch where you are merging; untouched by the merge process when shown to you

$MERGED The partially merged file, with conflicts; this is the only file touched by the merge process and, actually, never shown to you in meld

$REMOTE The file on the branch from where you are merging; untouched by the merge process when shown to you

Community
  • 1
  • 1
user3751385
  • 3,752
  • 2
  • 24
  • 24
0

I think you want to cherry-pick individual changes:

git checkout master
git log --reverse --oneline topic ^master

and then invoke git cherry-pick for each commit you want to have in the master branch.

If the remaining changes in the topic branch should be preserved, you may also want to rebase this branch on top of the new master:

git rebase master topic
Simon Richter
  • 28,572
  • 1
  • 42
  • 64
  • Interesting, I never knew of the cherry-pick command. I was hoping to manually select a few lines of code from a commit with a diff tool (eg. KDiff3). It seems that this merges the entire commit. – marckassay Mar 09 '11 at 14:48
  • 1
    @marckassy: If you do `git cherry-pick --no-commit; git reset HEAD` you could then stage only what you want with `git add -p`. – Cascabel Mar 09 '11 at 15:13