barrymoo
barrymoo

Reputation: 140

Can I make `git merge` always conflict on file changes?

I am hoping I have a simple question for you, but I can't find an answer anywhere (I have been searching for 2 days, maybe I am dumb?). I am trying to develop a git workflow to collaboratively edit LaTeX files with my PhD adviser. The problem we face is due to the behavior of git merge (because it merges automagically). I want git to conflict anytime it sees a file change, even if it is an addition, subtraction, or minuscule change, is this possible? This way we can both pick and choose changes and continually push to master.

I am not opposed to using another tool, but I would prefer not to create a complicated branching system. I assume branching is unnecessary when 2-3 people are working on the same file. Thank you so much for your help!

Upvotes: 4

Views: 860

Answers (2)

Andrew C
Andrew C

Reputation: 14883

Stop the merge from completing with --no-commit

Get a list of files that were changed on both sides by performing git diff --name-only HEAD...MERGE_HEAD and git diff --name-only MERGE_HEAD...HEAD

Redirect the two lists of files to comm -12 to get just files that were modified by both branches.

Note the following

::, e.g. :0:README, :README A colon, optionally followed by a stage number (0 to 3) and a colon, followed by a path, names a blob object in the index at the given path. A missing stage number (and the colon that follows it) names a stage 0 entry. During a merge, stage 1 is the common ancestor, stage 2 is the target branch’s version (typically the current branch), and stage 3 is the version from the branch which is being merged.

For each file listed in the comm output you can then call git difftool (presuming that will invoke vimdiff for you) and specify any combination of :0:, :1:, :2:, :3: that you want to see various diffs.

Upvotes: 1

torek
torek

Reputation: 489848

As vcsjones noted in a comment, you pretty much have to use --no-commit here, to stop the merge even when git thinks it went well.

Regarding your subsequent question, you can get git to extract the two being-merged versions of the file in a number of ways. The simplest is probably to use git show. (Note that this bypasses smudge filters, though.)

When the merge stops, HEAD names the current commit and MERGE_HEAD names the commit being merged-in (this assumes a two-parent merge in progress; I've never tried this with an octopus merge), so if you have file foo.tex that git thinks it has merged correctly, and you want to inspect it yourself, you could do this:

$ git show HEAD:foo.tex > foo.tex.head
$ git show MERGE_HEAD:foo.tex > foo.tex.merge_head
$ vimdiff foo.tex foo.tex.head foo.tex.merge_head

This particular naming scheme (adding .head and .merge_head suffixes) is not very clever and could fail if you actually have a "real" file named foo.tex.head, of course, so for a robust tool you'd want to make temporary directories instead. This could actually make the process easier as you could use git checkout (which does apply smudge filters) to populate the temporary directories. For instance, this is a bit wasteful (checks out the entire HEAD and MERGE_HEAD trees rather than each file as you go):

$ hd_tree=/tmp/head.$$ mhd_tree=/tmp/merge_head.$$
$ index=/tmp/index.$$
$ mkdir $hd_tree $mhd_tree
$ GIT_INDEX_FILE=$index GIT_WORK_TREE=$hd_tree git checkout HEAD -- .
$ GIT_INDEX_FILE=$index GIT_WORK_TREE=$mhd_tree git checkout MERGE_HEAD -- .

Now for each file $f that you wish to hand-inspect:

$ vimdiff $f $hd_tree/$f $mhd_tree/$f

When all done, rm -rf $hd_tree $mhd_tree $index to discard the temporary work-trees, and the dummy index.

To be less wasteful of file space (but use more processes), check out each file $f one at a time as you go, using the GIT_WORK_TREE environment setting as above. (The GIT_INDEX_FILE is here because checkout writes through the index and you really don't want to overwrite git's merged version in .git/index.)

[Note that none of the above is tested; caveat emptor.]

Upvotes: 0

Related Questions