Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

imerge sometimes reports a conflict, leaving unmerged files with zero conflicts #161

Open
dabrahams opened this issue Sep 10, 2020 · 10 comments

Comments

@dabrahams
Copy link

The unmerged files have changes in them that just need to be staged, but no conflict markers

It's not terrible, but it's confusing, and it wastes time and energy in a process that is already, often, laborious… which is the whole reason we need git imerge!

@mhagger
Copy link
Owner

mhagger commented Sep 22, 2020

If you could reproduce this problem in the form of a failing unit test, that would be a helpful step towards solving it.

@dabrahams
Copy link
Author

dabrahams commented Sep 25, 2020 via email

@jmah
Copy link

jmah commented Sep 25, 2020

@dabrahams Are you aware of git rerere? That facility can sometimes produce the situation you describe — if you've already resolved conflicts in a 'similar' merge situation, git rerere will re-apply the recorded resolution to the merged result, but leave the result unstaged (expecting manual verification).

@mhagger
Copy link
Owner

mhagger commented Sep 26, 2020

Are you aware of git rerere?

This is a possibility for merges done outside of git-imerge, but git-imerge should always temporarily disable rerere whenever it initiates a merge itself. (Of course it's possible that I missed a spot, but that's the intention anyway.)

@dabrahams
Copy link
Author

Also, I pretty much always keep rerere disabled, because I often have to go back over a complicated merge and rerere just perpetuates my mistakes.

@CmdQ
Copy link

CmdQ commented Sep 3, 2021

The same for me even multiple times for that specific merge, number 4 or 5 then has a real conflict. Unfortunately the commits are too big and too proprietary to give out.

But I can show you some anonymized…

Output

> git imerge rebase master
Attempting automerge of 6-7...failure.
Attempting automerge of 1-1...success.
Attempting automerge of 1-5...failure.
Attempting automerge of 1-3...failure.
Attempting automerge of 1-2...failure.
Attempting automerge of 6-1...success.
Autofilling 1-1...success.
Autofilling 2-1...success.
Autofilling 3-1...success.
Autofilling 4-1...success.
Autofilling 5-1...success.
Autofilling 6-1...success.
Recording autofilled block MergeState('gerrit-topic', tip1='master', tip2='gerrit-topic', goal='rebase')[0:7,0:2].
Attempting automerge of 6-7...failure.
Attempting automerge of 1-2...failure.
Switched to branch 'imerge/gerrit-topic'
Auto-merging path/to/some/file.py
Auto-merging path/to/another/file.py
CONFLICT (content): Merge conflict in path/to/conflict.py
Removing setup.py
Removing setup.cfg
Removing requirements.txt
Staged 'path/to/conflict.py' using previous resolution.
Automatic merge failed; fix conflicts and then commit the result.

Original first commit:
commit 31d79731505113fc03c73601a660d30bc94ddb37 (refs/imerge/gerrit-topic/manual/1-0)
Author: Me <[email protected]>
Date:   Mon Aug 23 16:01:59 2021 +0200

    some commit message

Original second commit:
commit 5471e7539dbef11ce7eb854f98847d1e586266a3 (refs/imerge/gerrit-topic/manual/0-2)
Author: Me <[email protected]>
Date:   Mon Jun 21 10:19:31 2021 +0200

    another commit message

There was a conflict merging commit 1-2, shown above.
Please resolve the conflict, commit the result, then type

    git-imerge continue

> git status
On branch imerge/gerrit-topic
All conflicts fixed but you are still merging.
  (use "git commit" to conclude merge)

Changes to be committed:
        modified:   .gitignore
        new file:   .python-version
        new file:   .readthedocs.yaml
        modified:   Jenkinsfile
        new file:   scripts/build_docs.sh
        deleted:    setup.cfg
        deleted:    setup.py
        modified:   path/to/some/file.py
        modified:   path/to/another/file.py
        modified:   path/to/conflict.py

Config

> git --version
git version 2.25.1
> git config --get rerere.enabled
true
> git config --get rerere.autoupdate
true

@mhagger
Copy link
Owner

mhagger commented Sep 3, 2021

@CmdQ:

Staged 'path/to/conflict.py' using previous resolution.

☝️ I believe that this message comes from rerere. git-imerge must not be turning it off correctly.

git-imerge does set rerere.enabled to false when running automerges. But it could be that the rerere.autoupdate setting that you have turned on is enough to make rerere do its thing, even if rerere.enabled is false.

You could test this theory by trying the same merge, with and without the following diff applied to git-imerge:

diff --git a/gitimerge.py b/gitimerge.py
index 90997ba..f481800 100644
--- a/gitimerge.py
+++ b/gitimerge.py
@@ -653,7 +653,7 @@ class GitRepository(object):
         worktree."""
 
         call_silently(['git', 'checkout', '-f', commit1])
-        cmd = ['git', '-c', 'rerere.enabled=false', 'merge']
+        cmd = ['git', '-c', 'rerere.enabled=false', '-c', 'rerere.autoupdate=false', 'merge']
         if msg is not None:
             cmd += ['-m', msg]
         cmd += [commit2]

If it succeeds with this patch but fails without it, then we should merge that patch in.

But when testing, please remember that rerere stores "hidden" information, so it would be best to test repeatedly (or reset the rerere cache between tests) to be sure of getting a reproducible result.

Thanks!

@CmdQ
Copy link

CmdQ commented Sep 17, 2021

Sorry for the late reply, I was on vacation.

Just to see if I applied to the correct change:

> which git-imerge
/home/linuxbrew/.linuxbrew/bin/git-imerge
> readlink -f /home/linuxbrew/.linuxbrew/bin/git-imerge
/home/linuxbrew/.linuxbrew/Cellar/git-imerge/1.2.0/libexec/bin/git-imerge
> find /home/linuxbrew/.linuxbrew/Cellar/git-imerge/1.2.0 -name gitimerge.py
/home/linuxbrew/.linuxbrew/Cellar/git-imerge/1.2.0/libexec/lib/python3.9/site-packages/gitimerge.py

So that's what I edited. Added the second -c option with parameter to the list but it didn't seem to solve the issue:

> git imerge rebase master
Attempting automerge of 6-7...failure.
Attempting automerge of 1-1...success.
Attempting automerge of 1-5...failure.
Attempting automerge of 1-3...failure.
Attempting automerge of 1-2...failure.
Attempting automerge of 6-1...success.
Autofilling 1-1...success.
Autofilling 2-1...success.
Autofilling 3-1...success.
Autofilling 4-1...success.
Autofilling 5-1...success.
Autofilling 6-1...success.
Recording autofilled block MergeState('gerrit-topic', tip1='master', tip2='gerrit-topic', goal='rebase')[0:7,0:2].
Attempting automerge of 6-7...failure.
Attempting automerge of 1-2...failure.
Switched to branch 'imerge/gerrit-topic'
Auto-merging path/to/some/file.py
Auto-merging path/to/another/file.py
CONFLICT (content): Merge conflict in path/to/conflict.py
Removing setup.py
Removing setup.cfg
Removing requirements.txt
Staged 'path/to/conflict.py' using previous resolution.
Automatic merge failed; fix conflicts and then commit the result.

Original first commit:
…

Original second commit:
…

There was a conflict merging commit 1-2, shown above.
Please resolve the conflict, commit the result, then type

    git-imerge continue

So it seems pretty much the same to me.

Maybe it's because rerere still remembers stuff from before I had installed git-imerge and uses that even if it's now allowed to record new stuff?

@CmdQ
Copy link

CmdQ commented Sep 17, 2021

After I deleted everything that rerere had recorded I arrive this behavior

> rm -rf .git/rr-cache
> git imerge rebase master
Attempting automerge of 6-7...failure.
Attempting automerge of 1-1...success.
Attempting automerge of 1-5...failure.
Attempting automerge of 1-3...failure.
Attempting automerge of 1-2...failure.
Attempting automerge of 6-1...success.
Autofilling 1-1...success.
Autofilling 2-1...success.
Autofilling 3-1...success.
Autofilling 4-1...success.
Autofilling 5-1...success.
Autofilling 6-1...success.
Recording autofilled block MergeState('gerrit-topic', tip1='master', tip2='gerrit-topic', goal='rebase')[0:7,0:2].
Attempting automerge of 6-7...failure.
Attempting automerge of 1-2...failure.
Switched to branch 'imerge/gerrit-topic'
Auto-merging path/to/some/file.py
Auto-merging path/to/conflict.py
CONFLICT (content): Merge conflict in path/to/conflict.py
Removing setup.py
Removing setup.cfg
Removing requirements.txt
Recorded preimage for 'path/to/conflict.py'
Automatic merge failed; fix conflicts and then commit the result.

Original first commit:
…

Original second commit:
…

There was a conflict merging commit 1-2, shown above.
Please resolve the conflict, commit the result, then type

    git-imerge continue

It tells me there's a conflict in one file and git status finally says the same.

Note the line Automatic merge failed; fix conflicts and then commit the result. though, which happened both with the diff and without.

@CmdQ
Copy link

CmdQ commented Sep 17, 2021

I find at least one other git merge call where it possibly should also be set, namely in

def manualmerge(self, commit, msg):
    """Initiate a merge of commit into the current HEAD."""

Maybe extract a git-calling function that simply always passes the -c flags. It probably doesn't hurt for ones that don't touch rerere.


Another idea I had: Before starting rename the current .git/rr-cache to something special, do all the work (still with the -c) and afterwards restore the directory (deleting what may have come to exist in its place).

Maybe it's a workaround, but if git rerere doesn't respect that config…

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants