PizzaBeer
PizzaBeer

Reputation: 183

Recalculate merge conflicts (ie. how to generate conflict markers)

I have a merge conflict where most conflicts are due to code formatting.

My code has the

<<<
===
>>>

markers inserted by git, to help me resolve the conflicts.

While in this state, I want to reformat the code corresponding to the commit to be applied, and then recalculate the merge conflicts and re-insert the markers, and I imagine the conflicts would be easier to look at.

If it matters, this is part of a rebase.

I imagine something like checkout the conflicting file at the commit to be applied, reformat it, then "recalculate conflicts", resolve the conflicts, then git rebase --continue

Is this possible or something related possible?

Upvotes: 0

Views: 418

Answers (1)

torek
torek

Reputation: 487725

I imagine something like checkout the conflicting file at the commit to be applied, reformat it, then "recalculate conflicts", resolve the conflicts, then git rebase --continue

Is this possible

Not directly, no, but:

or something related possible?

The something-related part is possible. The trick is to use git merge-file, and to use git merge-file, you need three input files.

For concreteness, let's call the file f.py. That is, you've started a rebase and have a conflict with f.py. You want to run:

git checkout --theirs f.py

to get your version, or:

git checkout --ours f.py

to get the version-so-far-in-the-rebase, into your working tree. Then you want to edit this one, and try merging it with the other one.

The three input files that Git uses initially are:

  • the copy of f.py in the merge base commit;
  • the copy of f.py in the --ours commit (one of the two above); and
  • the copy of f.py in the --theirs commit (the other of the two above).

Git then, by default in this case,1 runs these three files through git merge-file as if by:

git show :1:f.py > f.py.BASE
git checkout --ours f.py         # or git show :2:f.py > f.py
git show :3:f.py > f.py.REMOTE
git merge-file f.py f.py.BASE f.py.REMOTE
rm f.py.BASE f.py.REMOTE

more or less.2

You can do this same action yourself. Extract all three files—you can call the middle one f.py.OURS or f.py.LOCAL, for instance, to help keep track of which is which, although the "ours/theirs" "local/remote" distinction falls apart for git rebase; you can use any names you like here—and do whatever you want to each one. Then use git merge-file: it will overwrite the first named file with the merge result.


1If there is no possible conflict, Git doesn't have to do any of this at all: Git figures out which file will be the result of the three-way merge and puts it in place directly. If there is a possible conflict, Git does extract all three files and merge them. If you have a defined merge driver, Git will use your merge driver. Otherwise Git will use a built-in merge driver that uses the same code as git merge-file.

2The "more or less" part is because these files have carefully-non-conflicting temporary names, e.g., .gittmp0133145a or whatever, even when using your own merge driver. When doing the merge internally, Git typically doesn't need any temporary files at all. For what you want to do, you will probably need to make up some temporary file names.


git checkout -m

Note that the above differs from using git checkout -m path, which simply re-creates the original merge conflicts in a particular file. That is, after having a merge conflict in f.py, you might run:

vim f.py

and make (and write out) some changes to it in an attempt to resolve the conflict, then realize that what you just did is completely wrong. To put the file back into the state Git had it initially—with the original merge conflicts restored—you can run:

git checkout -m f.py

or (since Git 2.23) git restore -m f.py to get back the f.py from before you overwrote it in your editor.

You can also use:

git restore --conflict=diff3 f.py

(or similar with git checkout); see below.

Building what you want using git mergetool

The git mergetool command extracts the three input files that git merge-file needs, then runs some chosen merge tool—any program you like—on those files. You may be able to use this to good effect. I have not experimented with this, but see this comment on my answer to git cherry-pick: manually accept "our" or "their" hunks in conflicted files. Some careful pre-git mergetool commands with the current working tree copy of the file in question, followed by use of git mergetool with git merge-file, might get you what you want.

Consider diff3 style

Your situation (code formatting) may not be one that lends itself to this, but I find that setting merge.conflictStyle to diff3 makes cherry-pick conflicts much easier to follow. If you have a conflict that's unreadable due to the lack of the merge base context, this diff3 style helps a lot. If you don't like it globally, or want to just use it on one conflict, both git checkout -m (the old way) and git restore -m (the new way) work with --conflict=diff3. (The --conflict part implies the -m part, so you can use just the --conflict option, or you can use both if you're in that habit, as I am from ancient Git 1.6 days.)

Upvotes: 1

Related Questions