Commit 4911781b authored by Sushil Khanchi's avatar Sushil Khanchi 🐨
Browse files

divergence-resolution: use last evolution date to choose p1 when merging

Before this patch, we choose the minimum revision as p1 while merging the
two divergent csets which had a drawback that if independent user resolve
the same divergence, their final resolved cset would have different hashes
(because of 'divergence_source_local' and 'divergence_source_other' extras).

Now, we decide the p1 on the basis of which of the two divergent cset
was rewritten more recently. This new logic removes the "different hash"
problem.

To save us from big output changes in the tests due to this change, I also
added the second factor i.e revision_number while sorting the csets wrt dates
(as date is same for all the csets in tests) to fallback to the old way of
picking the revision i.e choosing the minimum rev number.

And to demonstrate that now divergence resolution is independent of which
side user run the `hg evolve --content-div` resolved cset id won't change,
I have added a separate test file.
Flag --config devel.default-date='...' is being used here to record a
custom date in the obsmarkers.
parent ad7c9c0b7a63
Pipeline #19733 passed with stage
in 5 minutes and 6 seconds
......@@ -1119,8 +1119,8 @@ def _selectrevs(repo, allopt, revopt, anyopt, targetcat):
return revs
def _dedupedivergents(repo, revs):
"""Dedupe the divergents revs in revs to get one from each group with the
lowest revision numbers
"""Dedupe the divergents revs in revs to get one from each group which
will be used as p1 while merging the divergent csets
"""
repo = repo.unfiltered()
res = set()
......@@ -1132,10 +1132,42 @@ def _dedupedivergents(repo, revs):
divergent = repo[rev]
base, others = divergentdata(divergent)
othersrevs = [o.rev() for o in others]
res.add(min([divergent.rev()] + othersrevs))
discarded.update(othersrevs)
all_divergents = othersrevs + [divergent.rev()]
pick, discard = _pick_latest_divergent(repo, all_divergents)
res.add(pick)
discarded.update(discard)
return res
def _pick_latest_divergent(repo, divergent_revs):
"""On the basis of evolution date, pick out a latest evolved revision
from all the `divergent_revs` (which are divergent with each other)
Return a tuple (latest_evolved, others)
"""
mapping = []
for rev in divergent_revs:
led = latest_evolution_date(repo, repo[rev])
# For purpose of comparing, from `led` which is (unixtime, offset)
# we only need `unixtime`.
mapping.append((led[0], rev))
# Sorting by negating the `rev` in key func, to fallback to the old way
# of selecting revision, in case when `led` is same while comparing.
# Old way: was to select the one with minimum revision number
mapping = sorted(mapping, key=lambda v: (v[0], -v[1]))
latest_evolved = mapping[-1][1]
others = mapping[:-1]
others = [val[1] for val in others[:]]
return latest_evolved, others
def latest_evolution_date(repo, ctx):
"""Return latest evolution date of a changeset <ctx>"""
node = ctx.node()
pred = list(obsutil.closestpredecessors(repo, node))
pred.append(node)
markers = obsutil.getmarkers(repo, nodes=pred, exclusive=True)
markers_dates = (m.date() for m in markers)
return max(markers_dates)
def divergentdata(ctx):
"""return base, other part of a conflict
......
......@@ -35,7 +35,7 @@ Archiving to a separate location to avoid hardlink mess when the repo is shared
$ tar -tzf hg-evolve-*.tar.gz | sed 's|^hg-evolve-[^/]*/||' | sort > files
$ wc -l files
347 files
348 files
$ fgrep debian files
tests/test-check-debian.t
$ fgrep __init__.py files
......
=====================================
Testing content-divergence resolution
=====================================
Independent rewrites of same changeset can lead to content-divergence. In most
common cases, it can occur when multiple users rewrite the same changeset
independently and push it.
This test aims to check that the resolution of content-divergent changesets is
independent of the user resolving the divergence. In other words, the two user
resolving the same divergence should end up with the same result.
Setup
-----
$ . $TESTDIR/testlib/content-divergence-util.sh
$ setuprepos user-independent-resolution
creating test repo for test case user-independent-resolution
- upstream
- local
- other
cd into `local` and proceed with env setup
initial
$ cd upstream
$ mkcommit A0
$ cd ../local
$ hg pull -uq
$ hg amend -m "A1" --config devel.default-date='1 1'
$ cd ../other
$ hg pull -uq
$ hg amend -d '2 0' --config devel.default-date='2 0'
$ hg push -q
$ cd ../local
$ hg push -q
2 new content-divergent changesets
$ hg pull -q
2 new content-divergent changesets
Variant_a: 'local' amended desc change, 'other' amended date change
-------------------------------------------------------------------
$ hg log -G
* 3:1a0af03d20ad (draft): A0 [content-divergent]
|
| @ 2:0d8c87cec5fc (draft): A1 [content-divergent]
|/
o 0:a9bdc8b26820 (public): O
$ hg evolve --content-div
merge:[3] A0
with: [2] A1
base: [1] A0
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
working directory is now at 031b925bbd02
$ hg log -G
@ 4:031b925bbd02 (draft): A1
|
o 0:a9bdc8b26820 (public): O
$ hg evolve -l
Variant_b: 'local' amended date change, 'other' amended desc change
-------------------------------------------------------------------
$ cd ../other
$ hg pull -q
2 new content-divergent changesets
$ hg log -G
* 3:0d8c87cec5fc (draft): A1 [content-divergent]
|
| @ 2:1a0af03d20ad (draft): A0 [content-divergent]
|/
o 0:a9bdc8b26820 (public): O
$ hg evolve --content-div
merge:[2] A0
with: [3] A1
base: [1] A0
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
working directory is now at 031b925bbd02
$ hg log -G
@ 4:031b925bbd02 (draft): A1
|
o 0:a9bdc8b26820 (public): O
$ hg evolve -l
Final_check: both user can push/pull without any issue
------------------------------------------------------
$ hg push
pushing to $TESTTMP/user-independent-resolution/upstream
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 0 changes to 1 files (+1 heads)
2 new obsolescence markers
obsoleted 2 changesets
$ hg pull ../local
pulling from ../local
searching for changes
no changes found
$ hg debugobsolete -r tip
0d8c87cec5fc1540b7c0324332375d530856fb56 031b925bbd02244f79e9977ea90f9703d1fe71ae 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '32', 'operation': 'evolve', 'user': 'test'}
1a0af03d20ad8b4e3a99d30620c8734efe076900 031b925bbd02244f79e9977ea90f9703d1fe71ae 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'evolve', 'user': 'test'}
28b51eb45704506b5c603decd6bf7ac5e0f6a52f 0d8c87cec5fc1540b7c0324332375d530856fb56 0 (Thu Jan 01 00:00:01 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
28b51eb45704506b5c603decd6bf7ac5e0f6a52f 1a0af03d20ad8b4e3a99d30620c8734efe076900 0 (Thu Jan 01 00:00:02 1970 +0000) {'ef1': '32', 'operation': 'amend', 'user': 'test'}
$ cd ../local
$ hg push
pushing to $TESTTMP/user-independent-resolution/upstream
searching for changes
no changes found
[1]
$ hg pull ../other
pulling from ../other
searching for changes
no changes found
$ hg debugobsolete -r tip
0d8c87cec5fc1540b7c0324332375d530856fb56 031b925bbd02244f79e9977ea90f9703d1fe71ae 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '32', 'operation': 'evolve', 'user': 'test'}
1a0af03d20ad8b4e3a99d30620c8734efe076900 031b925bbd02244f79e9977ea90f9703d1fe71ae 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'evolve', 'user': 'test'}
28b51eb45704506b5c603decd6bf7ac5e0f6a52f 0d8c87cec5fc1540b7c0324332375d530856fb56 0 (Thu Jan 01 00:00:01 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
28b51eb45704506b5c603decd6bf7ac5e0f6a52f 1a0af03d20ad8b4e3a99d30620c8734efe076900 0 (Thu Jan 01 00:00:02 1970 +0000) {'ef1': '32', 'operation': 'amend', 'user': 'test'}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment