I have a conflict during a merge. The file contains some regions where code has been merged correctly and an area where there is a choice between HEAD (ours) and the branch being merged in (theirs). I would like to accept the successfully merged region AND the HEAD part of the conflict.
Can that be done on the command line?
If I do
git merge -s ours incomingbranch
it appears to NOT merge the file. It just replaces the file with the current branch's (ours) version.
If I do
git merge incomingbranch
git checkout --ours path/to/conflict/file
it appears to also replace the file with the current branch's (ours) version.
What I would like is something that automatically fixes just the conflict areas and keeps the merged parts too.
Obviously the easy way to do this is to
git merge incomingbranch
(edit the conflictedfile and remove the relevant conflict chunks)
git add conflictedfile
git commit -m "fixed"
but I am looking for a command line option to do this preferably for individual files.
Git's options are kind of confusing here.
The -s
flag to Git merge sets the merge strategy. This strategy is responsible for taking all the commits that are to be merged and figuring out how to merge them: what files to use from which commits, how to combine their contents, and so on. There are essentially only two strategies that users should pick from in real cases: -s ours
, which as you found out, means ignore the other commits entirely, and the default -s recursive
, which is what you want to behave differently.1
But besides the -s
flag, there is a -X
flag. Git calls the arguments to -X
"strategy options" (see the git merge
documentation), but I like to call them eXtended options, both because that has the letter X in it, and because they work as extensions to the strategy. So what you may want here is -X ours
. This is very different from -s ours
! You're still using -s recursive
, you're just telling the recursive strategy that, in the case of a conflict, it should automatically choose the HEAD side.
That's not quite what you want, because:
preferably for individual files
... -X ours
applies to all file-level merge conflicts.2
To get what you want, you'll need to allow the merge conflicts to happen, then:
Use the three copies of the file that are in the three staging slots to extract all three inputs for that file, to the work-tree, so that you can see and work on them.
Run git merge-file
on the three files, with the --ours
option.
Put the resolved file in place and use git add
to copy it into index staging slot zero, wiping out the three copies that were in slots 1-3 that you used in step 1.
To understand step 1 completely, see other SO postings (I don't have time to find one right now) and consider using git checkout-index --stage=all
. See the git checkout-index
documentation for details.
1There is a third strategy, -s resolve
, that acts differently when there are multiple merge bases. Normal users never really need -s resolve
. There is an octopus strategy that Git uses on its own when you merge more than two commits. Expert Git users might use the octopus strategy, but that happens automatically when they run the right kind of git merge
, so they don't really need the -s
option for it.
2I put the adjective file-level in here because these are low-level, within-one-file conflicts. Git also has high-level conflicts, which occur when, e.g., one side of the merge modifies or renames a file, and the other side simply deletes the file entirely. Extended options to -s resolve
never solve any high-level conflicts; they only affect these low-level conflicts.