Home > Enterprise >  How to save merge state in Git?
How to save merge state in Git?

Time:11-23

We are using Gitlab free self-hosted 13.8.4-ee. During merge conflicts, we would like Git to save the state of unresolved conflicts in a merge as it is, so that we are able to continue resolving the conflicts at a later time.

We checked that in Gitlab UI's Merge tool, it is not possible. The 'Draft' option in 'Merge Requests' only makes the merge in a non-ready state, but we are unable to save resolved and unresolved conflicts, since git mergetool would resolve the unresolved conflicts with the version from BASE (common ancestor) rather than keep the local copy. We also checked that this is not possible in external merge tools like Beyond Compare or Meld. Even when checked in Github's free version, it is not allowing to save/close the merge until all conflict markers are removed.

Is there a way where we can save the current merge state in Git? In TFS, it is possible to save the current merge state as it is.

Please check the answer from previous question : Git merge for conflict cases replaces local copy with the common ancestor copy

CodePudding user response:

You can't.

More precisely, the way you save anything permanently (or even for just a day or so, or for transport purposes, etc.) in Git is by making commits. But when you're in the middle of a conflicted merge, you cannot make any new commits. You want to save stuff so that the merge can be continued elsewhere. So you're in a Catch-22 situation: you want to save the conflict, but to do that, you must first completely resolve the conflict, after which there's no conflict to save.

Git does need a facility for this, and there are several possible approaches for adding one, but—as far as I know at least—nobody has made it all the way through adding one.

(It's not a matter of whether files have conflict markers in them, though ideally the "preserve partial but conflicted merge" would preserve and then restore these conflict markers too. The actual problem is that the index has nonzero staging numbers in it. These nonzero staging numbers are what prevents writing out a tree, and without the ability to write trees, there's no way to save the various files.)

CodePudding user response:

You're looking for git rerere. Whether and how any web front-ends implement this I don't know, but from the command line it's very easy.

Here's the command-line version of getting into the situation you've described:

git checkout main
git merge feature    # has conflicts
resolve resolve
oops, cannot continue because reasons

and the question is, how do you suspend the merge and go do other stuff without losing the resolutions you've already done?

The simplest way is to have already done git config rerere.enabled true before the git merge (by e.g. including it in your standard template's config). Then the way to save your merge state is just

git rerere

which will notice and remember any new conflicts or resolutions; you can then git merge --abort. Since Git now remembers the resolutions you just recorded, when you rerun the merge, the same conflicts show up, git runs git rerere for you, and that sees the conflicts and applies your recorded resolutions from its rr-cache to the your work tree. You're back right where you left off.

   rerere.enabled
       Activate recording of resolved conflicts, so that identical
       conflict hunks can be resolved automatically, should they be
       encountered again. By default, git-rerere(1) is enabled if there is
       an rr-cache directory under the $GIT_DIR, e.g. if "rerere" was
       previously used in the repository.

If you're already there, if you're merging and have some added resolutions and and hadn't turned rerere on yet, it's pretty easy to do it retroactively. For an inflight merge,

git config rerere.enabled true
git worktree add scratch @
git -C scratch merge feature
git worktree remove -f scratch

and now you can git rerere to record the resolutions you've already made.

  • Related