19

I'm trying to merge a big topic branch into the master, but I want a separate commit that shows how the conflict resolution happened. The goal is to have one commit that shows "these files conflicted and how they conflicted" and the next commit would show "this is how the conflicts were resolved". I.e. the first commit would contain the conflict markers.

The reason for this is that the big topic branch has been reviewed and tested, as has the master branch. Of the merge, we want to review only the parts that needed some work (conflicts and other merge work).

Here's what I'm doing this far:

git checkout master
git checkout -b merge-from-topic
git merge topic

To record the files that have conflicts, I use a temporary file:

git diff --name-only --diff-filter=U >conflicts.txt

First I simply add those files, with the conflict markers, to a commit:

xargs git add <conflicts.txt
git commit

Then I create another branch (for review purposes) in which I'd like to do the conflict resolution:

git checkout -b resolve-merge-from-topic

To restore the conflicts, I tried

xargs git reset HEAD^ -- <conflicts.txt

but then git mergetool said that none of the files need merging although files in my working tree had conflict markers.

How do I restore files listed in conflicts.txt, so that I can use git mergetool on them?

I'm also open to other ways of getting the "separate commit for conflict resolution" effect.

vmj
  • 13,283
  • 3
  • 18
  • 14
  • 4
    Remind me to not work on your project. The merge commit itself should be sufficient evidence of what had to be tweaked. If you ever need more than what the merge commit indicates via `git log -p`, you can always do `git diff sha_of_merge sha_of_merge^1` or `git diff sha_of_merge sha_of_merge^2` to see the changes introduced with respect to the two parents of your merge. In other words, use the tools `git` gives you, don't clutter up your repository with unnecessary and broken stuff... – twalberg Sep 19 '13 at 15:30
  • 2
    I'm trying to "use the tools git gives" me, the mergetool. But it doesn't seem to be possible. All the suggestions about git log with options requires detective work from reviewers. – vmj Sep 20 '13 at 08:01
  • `git show #mergeCommit` may be the answer, as I learned here https://haacked.com/archive/2014/02/21/reviewing-merge-commits/ Basically it should be able to show only the changes that are not in any of the "parent" commits of the merge commit (both the source and target branch). This is basically conflict resolution changes (hunks). I know it's not exactly what you asked for, but maybe the goal is the same - to be able to review merge commit. – LordMsz Feb 28 '23 at 13:45

3 Answers3

4

git merge will leave conflict markers.

You then (usually) invoke git mergetool (with the --tool of your preference) to resolve the conflicts. Most of the time, this will result in staged changes. This you want to change (e.g. using git reset).

Now commit the 'raw' merge in isolation, and subsequently git add . && git commit -m 'resolutions' or git commit -am 'resolutions' to add the conflict resolutions.

Note this leaves you with a 'broken' build at the merge boundary revision.

In steps:

git checkout -b be_merged       # start a temp branch for the merge (safety)

git merge --no-commit diverge   # initiate merge from a diverged branch
git status                      # shows conflicts
git mergetool                   # resolve them as always
git status                      # shows resolutions as staged
git reset                       # unstage the changes
git status                      # shows unstaged changes (good!)
git commit -m 'merge, conflicts pending'   # commit the merge
git commit -am 'conflicts resolved'        # commit the resolutions
sehe
  • 374,641
  • 47
  • 450
  • 633
  • 2
    Doesn't seem to work for me. After the 'git reset', all modified files are unstaged and all added files are untracked, so the following 'git commit' does nothing. And the final 'git commit -a' only commits the modified files, no sign of conflict markers in the commit, leaving all new files untracked. – vmj Sep 18 '13 at 08:26
  • Btw, the 'broken' build is ok. – vmj Sep 18 '13 at 08:31
  • Updated the question to (hopefully) clarify that I actually want the conflict markers in the first commit. – vmj Sep 18 '13 at 08:35
  • If the first commit there fails because there's "nothing to commit", add --allow-empty to record the merge, but no changes. – Boyd Stephen Smith Jr. Sep 19 '13 at 16:09
  • The --allow-empty side steps the issue, the first commit should contain all the work that was done by "git merge", including the conflict markers. The question was about restoring the state needed by git-mergetool. – vmj Sep 20 '13 at 08:03
2

if you are really insistent on getting the merge history, then your best bet is to use git-imerge

AFAIK the git imerge gives you a choice if the merging history should be preserved or not

REF:

  1. http://softwareswirl.blogspot.de/2013/05/git-imerge-practical-introduction.html

an exert from the author's blog:

git merge pain

  • You need to resolve one big conflict that mixes up a lot of little changes on both sides of the merge. (Resolving big conflicts is hard!)
  • Merging is all-or-nothing:
    1. There is no way to save a partly-done merge, so
      • You can't record your progress.
      • You can't switch to another branch temporarily.
      • If you make a mistake, you cannot revert only part of the merge.
      • If you cannot resolve the whole conflict, there is nothing to do but start over.
    2. There is no way to test a partly-done merge--the code won't even build until the conflict is completely resolved.
  • It is difficult to collaborate on a merge with a colleague.

which may be exactly why you require a conflict-commit in the first place.


On another hand, a different perspective:

The merging changes should be kept as minimal as possible on an trivial project Why this is being said is that a merge touching all of the files in the repository will make you have a real pain in the future. As if you are to merge your branch with some major branch , lets say you work on the production branch, while the releases are done from the release branch, a branch maintainer will just try to rebase your branch with his branch.

Now if you had a commit which touched all the files in the place, this is going to be a read bad stuff as the merge will most likely to have conflict (major one, probably the conflict-commit you made) so the maintainer will have 2 options:

  1. merge it himself/herself
  2. reject the merge and let you do the dirty work

its more likely that maintainer will be opting the latter as it's the easier one for him.

So this you'll be spending more time in resolving the conflicts than doing some productive work.

NOTE:

The second perspective is only applicable when you have feature topics that have simple span. When merging the feature topics having larger span, it's better to use imerge and keep the history, that way you'll have smaller commits and rebase will not be painful.

Avinash R
  • 3,101
  • 1
  • 27
  • 47
1

this is a very bad idea. You want a stable code base at all times. Why would you ever push a code in a state where its conflicted.

If you want to see how conflict was resolved, do a diff on the file and see the history of it.

  • 1
    I want stable code base in the master branch, yes. But other branches, not so important. – vmj Sep 19 '13 at 14:46
  • 6
    Normally, when you commit a merge after resolving conflicts, git history does not show where the conflicts were. So diff only shows the whole change, not the conflict. – vmj Sep 19 '13 at 14:48
  • Update the question to (hopefully) clarify on the reason why I tolerate a broken build in the merge branch. – vmj Sep 19 '13 at 14:58
  • 1
    @vmj You want to use one or more of the `-c`, `--cc` or `-m` options to `git log -p` to get different/better information on merge commits. `git help log` will give you more information. – twalberg Sep 19 '13 at 15:35
  • 2
    then why not do a merge. stash your stuff. create a new branch called "broken". Pop your stash. Commit it. Push to master. Never merge back. – AntoineDeSaintExupery Sep 19 '13 at 16:37
  • master and topic branches should not be broken in any state, only the merge-from-topic branch is broken after the first commit, and unbroken after the second. The second commit would be the parent of the next merge commit in master. – vmj Sep 20 '13 at 08:04