3

Assume the following git history

 M (master) <- merge that required resolving a conflict, e.g. coming from F and G
 | \
 |  |
 F  G
 |  | 
 C  D  <- commit to edit (D), unrelated to the merge conflict (e.g. adding a new file)
 |  |
 | /
 B
 |
 A  <- initial commit

What I'm trying to achieve is to edit the commit D (with rewriting the history). I'm using the command git rebase --interactive --preserve-merges A master, marking the commit D to be edited, edit it when rebasing stops, amend the commit and git rebase --continue.

What I'm receiving on the point before the M commit is a request to resolve conflicts. The same conflicts were already resolved when merging branches to M, thus I expected the rebase to go smoothly.

$ git rebase --continue
Auto-merging yet-another-test.txt
CONFLICT (content): Merge conflict in yet-another-test.txt
Automatic merge failed; fix conflicts and then commit the result.
Error redoing merge d01ffb203aae9ef450ae7a863de5fce2ed5184bb

You can find the example here, you can try e.g. git rebase -i -p 8b58 master and edit the 30c7 commit

The reason I'm asking is because the git history of my real repo is quite complicated with a lot of merges along the way (around 300 commits in total) and the commit I need to edit is close to the initial commit, so I'd like to preserve the history (avoid squashing) but I'd rather not resolve all the conflicts again.

Is there a better way of doing this?

Tried on git for windows 2.17.1 (recent).

patryk
  • 651
  • 12
  • 30
  • 1
    Rewritting in this manner is going to be complicated, if not impossible. Why don't you just fix whatever it is you need to fix on a branch and then merge it in? The nett result is the same? – Liam Jun 15 '18 at 13:13
  • The reason is I _want_ the history to be rewritten - to hide the data that was put in the commit in the first place from viewing but still keep the whole changes history – patryk Jun 15 '18 at 13:15
  • *quite complicated with a lot of merges along the way and the commit I need to edit is close to the initial commit*. When you do a rewrite you need to reapply all the changes upstream, not just the revision your re-writing. so all those 300 commits are going to need to be redone. This really isn't going to be practical. – Liam Jun 15 '18 at 13:28
  • I know, if it doesn't work, I will need another way to get rid of the changes history. Still, what this question comes down to is: why git fails to reapply merge commits that contain resolved conflicts? – patryk Jun 15 '18 at 13:31

1 Answers1

2

Git doesn't record previous merge resolutions by default, which is why you are presented with the exact same conflict when rebase has to recreate a merge commit:

Error redoing merge d01ffb203aae9ef450ae7a863de5fce2ed5184bb

This is where git-rerere (reuse recorded resolution) comes in:

This command assists the developer in this process by recording conflicted automerge results and corresponding hand resolve results on the initial manual merge, and applying previously recorded hand resolutions to their corresponding automerge results.

For Git to start recording merge resolutions, you first to need to enable rerere in your repository (or globally) by saying:

git config rerere.enabled true

or

git config --global rerere.enabled true

Unfortunately, it won't help you save time in this particular instance—since you've already resolved the conflicts in the various merge commits while it was off—but it will make a difference going forward.

Edit: actually, there seems to be a way to record previous resolutions from existing merge commits by running a shell script called rerere-train. I haven't tried this myself though, so YMMV.

Enrico Campidoglio
  • 56,676
  • 12
  • 126
  • 154
  • what would it take to have it working for the entire repo? should all contributors enable `rerere` on their machines? how about merging on remote server, e.g. github? – patryk Jun 15 '18 at 14:05
  • The resolutions recorded by `rerere` are stored locally (in the `.git/rr-cache` directory) and are never transferred to a remote. So _yes_, every contributor has to enable it on their machines and _no_, the recorded resolutions aren't automatically shared with the rest of team. _However_, there are [a few workarounds](https://stackoverflow.com/q/12566023/26396). – Enrico Campidoglio Jun 15 '18 at 14:20
  • without such a workaround - remote merges on e.g. github would be discouraged given `rerere`, is that correct? – patryk Jun 15 '18 at 14:23
  • I'm not sure I follow – what do you mean by discouraged? – Enrico Campidoglio Jun 15 '18 at 14:27
  • would `rerere` data be recorded if I merged pull requests in github? – patryk Jun 15 '18 at 14:28
  • I would say no, although I couldn't find any documentation to confirm it. In any case, I wouldn't expect GitHub to have enabled `rerere` on their server-side repositories. – Enrico Campidoglio Jun 15 '18 at 14:36