Reputation: 877
Using git checkout --theirs
or --ours
is handy for resolving conflicts, but they either take the full "theirs" file or the full "ours" file. It does not merge anything, even in areas where it is easy to merge (i.e. areas where the conflicted file does not show any >>>> and <<<<).
Is it possible to do a kind of checkout --theirs
where there are conflicts but keep merged areas of the file that where correctly merged?
Said differently, I am looking for something that behaves like git merge --strategy-option theirs
but at the scale of a single file (because for some other files I'd like to use other merging strategies).
Here is a minimal example to reproduce my issue:
a.txt
:$ git init
$ cat > a.txt
lorem
ipsum
dolor
sit
amet
consectatur
adipiscing
elit
some
area
to
change
$ git add a.txt
$ git commit -m 'A'
$ git checkout -b branch
$ cat > a.txt
lorem
ipsum
dolorB
sit
amet
consectatur
adipiscing
elit
B
some
areaB
change
$ git add a.txt
$ git commit -m 'B'
$ git checkout master
$ cat > a.txt
lorem
ipsumA
dolorA
sitA
amet
consectatur
adipiscing
elit
some
area
to
change
$ git add a.txt
$ git commit -m 'C'
$ git merge branch
CONFLICT (content): Merge conflict in a.txt
$ cat a.txt
lorem
<<<<<<< HEAD
ipsumA
dolorA
sitA
=======
ipsum
dolorB
sit
>>>>>>> branch
amet
consectatur
adipiscing
elit
B
some
areaB
change
What I would like to have is a merged a.txt
where each time there is a conflict the HEAD block is used (master) but still merge areas where there is no conflict.
Neither git checkout --theirs
nor git checkout --ours
works here:
$ git checkout --theirs a.txt
$ cat a.txt
lorem
ipsum
dolorB <--- NOPE!
sit
amet
consectatur
adipiscing
elit
B
some
areaB
change
$ git checkout --ours a.txt
$ cat a.txt
lorem
ipsumA
dolorA
sitA
amet
consectatur
adipiscing
elit
some
area <--- NOPE!
to
change
What I would like to have is:
lorem
ipsumA
dolorA
sitA
amet
consectatur
adipiscing
elit
B
some
areaB
change
Upvotes: 2
Views: 5612
Reputation: 487883
Is it possible to do a kind of
checkout --theirs
where there are conflicts but keep merged areas of the file that where correctly merged?
No, but fortunately:
Said differently, I am looking for something that behaves like
git merge --strategy-option theirs
but at the scale of a single file (because for some other files I'd like to use other merging strategies).
Here the answer is "yes". It's just not git checkout
at all.
The first step is to extract all three input files: merge base version, ours
version, and theirs
version. You can do this manually with:
git show :1:path/to/file > path/to/file.base
git show :2:path/to/file > path/to/file.ours
git show :3:path/to/file > path/to/file.theirs
(If you're in the appropriate subdirectory already, you can just use file
three time with the three numbered index slots, and file.base
etc with the names for the redirections.)
Side note: the git mergetool
command knows how to do this on its own but might be impractical to use here, as it attempts to one particular command—your chosen merge tool—on all remaining conflicted files. That is, it does the equivalent of running git status
and checking for unresolved files, and then does the three-checkouts thing for each such file, but then immediately wants to run the (single) tool on those three files. (Ideally this particular part of git mergetool
, i.e., the "get three versions" part, ought to be provided as a separate Git command, but it isn't.)
Now that you have the three files, the command that lets you do git merge -X theirs
on them is not actually git merge
but rather git merge-file
:
git merge-file --theirs file.ours file.base file.theirs
(note that the option is spelled slightly differently, but is still "theirs"). The order of the three named files matters: the first one must be the current or ours
version and the last one must be the theirs
version, leaving the base in the middle.
The program writes its output back to the first named file, but in this case if something goes wrong and you want to start over, you can just git show
again. If you like the result, move it into place and git add
it:
mv file.ours file; git add file
for instance (assuming no path/to/
part needed).
Upvotes: 2