I thought that my scenario should be fairly common, and there must be a simpler way of doing what I do. Suppose there are two branches, current and next, for two lines of development. next at this stage receives all changes from the current branch. Being maintainer of the next branch I am syncing the changes (as necessary for alpha releases) like this:
$ git co origin/next -b next
$ git merge origin/current
Some files changed their format on the next, and every change to these few files made since the last sync-merge results in a conflict. To resolve this conflict, I need to see the changes on the current branch since the previous merge. Usually many files have changed, but only 1 or 2 files like those I mentioned are conflicting.
Suppose that the file baz.dat on the current branch contains words in square brackets, like
[real]
[programmers]
[use]
[pascal]
On the next branch, the syntax change demands that the words be surrounded with colons instead
:real:
:programmers:
:use:
:pascal:
A change on the current branch has added a line to the file:
[real]
[programmers]
[don't]
[use]
[pascal]
Every time a merge conflict results in the following diff merge marks:
<<<<<<< ours
:real:
:programmers:
:use:
:pascal:
=======
[real]
[programmers]
[don't]
[use]
[pascal]
>>>>>>>> theirs
Whole file content deleted and replaced, because it, in a sense, is.
Similarly, just git diff shows all incoming, "their" lines as deleted and "our" lines as added:
$ git diff
<usual unified diff preamble>
+ :real:
... more lines with "+ " (our new) or " -" (their deleted) mark,
- [pascal]
A way to see what changed on the current ("their") branch since I last merged, so I can manually incorporate the change into the next ("our") branch
$ git diff --magically-from-merge-point --theirs
<usual unified diff preamble>
+ [don't]
In other words, I want to see in this example case that only one line was added, so I can insert it in the new format as well.
(My real case is a change in a domain-specific language, but it essentially very similar to this trivial example).
What I am resorting to do is a rather unwieldy series of commands:
$ git status
. . . .
both modified: foo/bar/baz.dat <== copy/paste every conflict filename
$ git diff `git merge-base HEAD origin/current`..origin/current -- foo/bar/baz.dat
This shows what I want, but rather complex, and I construct and type it every time. It is easy enough to script in bash, but before I do that I want to ask is there a simpler way to see the conflicting changes from merge base? I. e.
(next)$ git merge origin/current
. . .
CONFLICT (content): foo/bar/baz.dat
(next|MERGING)$ git diff --magic-switch
and diff would show changes only for conflicting files as a delta between the merge base and the point of merge (which I would, in the ideal case, further restrict with e. g. --magic-switch --theirs)
Does such a magic switch exist? Looks like I am missing something obvious!
git mergetool will open the conflicting files, one by one, in your diff editor of choice (meld, vimdiff, kdiff3, winmerge ...), as a 3 way merge between the 3 versions :
local : version in the current branch (in your case : next's version)base : version in the merge-base commitremote : version in the merged branch (in your case : origin/current's version)If you edit + save the central file, git will mark this conflict as solved, an stage what you saved in the index.
If your merge halted due to conflict, git stores a ref to the merged commit in .git/MERGE_HEAD. This means that you can use the string "MERGE_HEAD" as a valid reference in git commands :
git log -1 MERGE_HEAD # view last commit on the merged branch
git merge-base MERGE_HEAD HEAD # no need for the name of the branch
You can then build a simpler alias :
theirs = 'git diff $(git merge-base MERGE_HEAD HEAD) MERGE_HEAD'
# usage :
git theirs # complete diff between 'base' and 'theirs'
git theirs -w -- this/file # you can add any option you would pass to 'git diff'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With