|hg rename|d files no longer |hg merge|ing [(k)eep or (d)elete?]
Alexis S. L. Carvalho
alexis at cecm.usp.br
Tue Aug 7 23:51:15 UTC 2007
Thus spake Matt Mackall:
> On Tue, Aug 07, 2007 at 03:08:58AM -0700, Edward Lee wrote:
> > On 8/7/07, Edward Lee <edilee at mozilla.com> wrote:
> > > Are there any known issues with rename
> > Good news and bad news. Seems like it's an issue of |hg merge| and not
> > |hg rename|. By renaming the files back to original, commit, rename to
> > the new name, commit, mercurial is able to merge the files correctly
> > when pulling changes. However, this problem of mercurial forgetting
> > about the rename can occur again fairly easily.
> >
> > > some reason after merging [6] some changes from (1) into (2), pulling
> > > new changes results in "[(k)eep or (d)elete?]"
> > > [6] http://hg.mozilla.org/mozilla-central/?rev/d7e93861f3f3
> > The interesting thing here is that it turns out the merge just
> > happened to not touch any of the renamed files. So any merges that
> > don't involve the renamed files will have mercurial forgetting about
> > the rename. Similarly, even if some of the renamed files are touched,
> > the remaining renamed files that are untouched are also forgotten in
> > the merge.
>
> Hmmm, you've found a case I hadn't considered.
>
> Your changeset graph looks like:
>
> 0-2-4
> \ \ \
> 1-3-5
>
> where the rename happens in 1, and the change to the rename happens in
> 4. But Mercurial currently only looks back as far as the least common
> ancestor when looking for renames, so when merging 3 and 4, it only
> looks back to 2. But the rename in question happened in 1, so it's not
> visible at 2. Clearly it should search for renames all the way back to
> 0 in this case.
>
> But if we look at another graph:
>
> 0-1-2
> \ \
> 3-4
>
> ..it's clear that there's no point in looking back any further than 1,
> as any change in one is visible to both branches that get merged at 4.
>
> And if we take our first graph and add an edge:
>
> 0-2-x-4
> \ \ / \
> 1-3-y-5 (extra changesets added to make merges meaningful)
>
> ..then we can stop our search when merging y and 4 at 3, because the
> rename was already visible to both sides.
>
> So we have to include all changesets that aren't common to both sides
> in our rename search. Fun, a new graph algorithm.
I was playing a bit with that test case and came up with this:
diff -r dc2e512cb89a mercurial/merge.py
--- a/mercurial/merge.py Tue Aug 07 15:56:26 2007 +0200
+++ b/mercurial/merge.py Tue Aug 07 20:41:58 2007 -0300
@@ -133,6 +133,9 @@ def findcopies(repo, m1, m2, ma, limit):
return wctx.filectx(f)
ctx = util.cachefunc(makectx)
+ limitnode = repo.changelog.node(limit)
+ reachable = repo.changelog.reachable(limitnode)
+ del reachable[limitnode]
def findold(fctx):
"find files that path was copied from, back to linkrev limit"
old = {}
@@ -147,7 +150,7 @@ def findcopies(repo, m1, m2, ma, limit):
seen[s] = 1
if fc.path() != orig and fc.path() not in old:
old[fc.path()] = 1
- if fc.rev() < limit:
+ if fc.node() in reachable:
continue
visit += fc.parents()
Calling reachable is somewhat heavy-handed, but this apparently fixes
things.
After reading your last comment I'm not sure how it would cope with
merges that have more than one greatest common ancestor
Alexis
More information about the Mercurial
mailing list