# HG changeset patch # User Thomas Arendsen Hein # Date 2008-04-01 06:33:17 # Node ID a60b711c7ac40d253d3629a4abf1c5ddd9fe95de # Parent 6e4f7170734c4b5c6b1e980972b02b16431917d7 # Parent a42d8d3e6ea920b26bbd53edf14b4f4c9913e4e4 merge with hg-stable diff --git a/hgext/churn.py b/hgext/churn.py --- a/hgext/churn.py +++ b/hgext/churn.py @@ -155,7 +155,7 @@ def churn(ui, repo, **opts): for l in f.readlines(): l = l.strip() - alias, actual = l.split(" ") + alias, actual = l.split() aliases[alias] = actual return aliases diff --git a/mercurial/ancestor.py b/mercurial/ancestor.py --- a/mercurial/ancestor.py +++ b/mercurial/ancestor.py @@ -81,54 +81,3 @@ def ancestor(a, b, pfunc): gx = x.next() except StopIteration: return None - -def symmetricdifference(a, b, pfunc): - """symmetric difference of the sets of ancestors of a and b - - I.e. revisions that are ancestors of a or b, but not both. - """ - # basic idea: - # - mark a and b with different colors - # - walk the graph in topological order with the help of a heap; - # for each revision r: - # - if r has only one color, we want to return it - # - add colors[r] to its parents - # - # We keep track of the number of revisions in the heap that - # we may be interested in. We stop walking the graph as soon - # as this number reaches 0. - if a == b: - return [a] - - WHITE = 1 - BLACK = 2 - ALLCOLORS = WHITE | BLACK - colors = {a: WHITE, b: BLACK} - - visit = [-a, -b] - heapq.heapify(visit) - n_wanted = len(visit) - ret = [] - - while n_wanted: - r = -heapq.heappop(visit) - wanted = colors[r] != ALLCOLORS - n_wanted -= wanted - if wanted: - ret.append(r) - - for p in pfunc(r): - if p not in colors: - # first time we see p; add it to visit - n_wanted += wanted - colors[p] = colors[r] - heapq.heappush(visit, -p) - elif colors[p] != ALLCOLORS and colors[p] != colors[r]: - # at first we thought we wanted p, but now - # we know we don't really want it - n_wanted -= 1 - colors[p] |= colors[r] - - del colors[r] - - return ret diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -227,7 +227,10 @@ def backout(ui, repo, node=None, rev=Non raise util.Abort(_('cannot use --parent on non-merge changeset')) parent = p1 + # the backout should appear on the same branch + branch = repo.dirstate.branch() hg.clean(repo, node, show_stats=False) + repo.dirstate.setbranch(branch) revert_opts = opts.copy() revert_opts['date'] = None revert_opts['all'] = True diff --git a/mercurial/copies.py b/mercurial/copies.py --- a/mercurial/copies.py +++ b/mercurial/copies.py @@ -7,7 +7,7 @@ from node import nullid, nullrev from i18n import _ -import util, ancestor +import util, heapq def _nonoverlap(d1, d2, d3): "Return list of elements in d1 not in d2 or d3" @@ -35,40 +35,81 @@ def _findoldnames(fctx, limit): old = {} seen = {} orig = fctx.path() - visit = [fctx] + visit = [(fctx, 0)] while visit: - fc = visit.pop() + fc, depth = visit.pop() s = str(fc) if s in seen: continue seen[s] = 1 if fc.path() != orig and fc.path() not in old: - old[fc.path()] = 1 + old[fc.path()] = (depth, fc.path()) # remember depth if fc.rev() < limit and fc.rev() is not None: continue - visit += fc.parents() + visit += [(p, depth - 1) for p in fc.parents()] - old = old.keys() + # return old names sorted by depth + old = old.values() old.sort() - return old + return [o[1] for o in old] + +def _findlimit(repo, a, b): + "find the earliest revision that's an ancestor of a or b but not both" + # basic idea: + # - mark a and b with different sides + # - if a parent's children are all on the same side, the parent is + # on that side, otherwise it is on no side + # - walk the graph in topological order with the help of a heap; + # - add unseen parents to side map + # - clear side of any parent that has children on different sides + # - track number of interesting revs that might still be on a side + # - track the lowest interesting rev seen + # - quit when interesting revs is zero + + cl = repo.changelog + working = cl.count() # pseudo rev for the working directory + if a is None: + a = working + if b is None: + b = working -def copies(repo, c1, c2, ca): + side = {a: -1, b: 1} + visit = [-a, -b] + heapq.heapify(visit) + interesting = len(visit) + limit = working + + while interesting: + r = -heapq.heappop(visit) + if r == working: + parents = [cl.rev(p) for p in repo.dirstate.parents()] + else: + parents = cl.parentrevs(r) + for p in parents: + if p not in side: + # first time we see p; add it to visit + side[p] = side[r] + if side[p]: + interesting += 1 + heapq.heappush(visit, -p) + elif side[p] and side[p] != side[r]: + # p was interesting but now we know better + side[p] = 0 + interesting -= 1 + if side[r]: + limit = r # lowest rev visited + interesting -= 1 + return limit + +def copies(repo, c1, c2, ca, checkdirs=False): """ Find moves and copies between context c1 and c2 """ # avoid silly behavior for update from empty dir - if not c1 or not c2: + if not c1 or not c2 or c1 == c2: return {}, {} - rev1, rev2 = c1.rev(), c2.rev() - if rev1 is None: # c1 is a workingctx - rev1 = c1.parents()[0].rev() - if rev2 is None: # c2 is a workingctx - rev2 = c2.parents()[0].rev() - pr = repo.changelog.parentrevs - def parents(rev): - return [p for p in pr(rev) if p != nullrev] - limit = min(ancestor.symmetricdifference(rev1, rev2, parents)) + limit = _findlimit(repo, c1.rev(), c2.rev()) m1 = c1.manifest() m2 = c2.manifest() ma = ca.manifest() @@ -97,15 +138,12 @@ def copies(repo, c1, c2, ca): c2 = ctx(of, m2[of]) ca = c1.ancestor(c2) # related and named changed on only one side? - if ca and ca.path() == f or ca.path() == c2.path(): + if ca and (ca.path() == f or ca.path() == c2.path()): if c1 != ca or c2 != ca: # merge needed? copy[f] = of elif of in ma: diverge.setdefault(of, []).append(f) - if not repo.ui.configbool("merge", "followcopies", True): - return {}, {} - repo.ui.debug(_(" searching for copies back to rev %d\n") % limit) u1 = _nonoverlap(m1, m2, ma) @@ -139,7 +177,7 @@ def copies(repo, c1, c2, ca): repo.ui.debug(_(" %s -> %s %s\n") % (f, fullcopy[f], note)) del diverge2 - if not fullcopy or not repo.ui.configbool("merge", "followdirs", True): + if not fullcopy or not checkdirs: return copy, diverge repo.ui.debug(_(" checking for directory renames\n")) @@ -186,8 +224,10 @@ def copies(repo, c1, c2, ca): for d in dirmove: if f.startswith(d): # new file added in a directory that was moved, move it - copy[f] = dirmove[d] + f[len(d):] - repo.ui.debug(_(" file %s -> %s\n") % (f, copy[f])) + df = dirmove[d] + f[len(d):] + if df not in copy: + copy[f] = df + repo.ui.debug(_(" file %s -> %s\n") % (f, copy[f])) break return copy, diverge diff --git a/mercurial/merge.py b/mercurial/merge.py --- a/mercurial/merge.py +++ b/mercurial/merge.py @@ -101,7 +101,9 @@ def manifestmerge(repo, p1, p2, pa, over action.append((f, m) + args) if pa and not (backwards or overwrite): - copy, diverge = copies.copies(repo, p1, p2, pa) + if repo.ui.configbool("merge", "followcopies", True): + dirs = repo.ui.configbool("merge", "followdirs", True) + copy, diverge = copies.copies(repo, p1, p2, pa, dirs) copied = dict.fromkeys(copy.values()) for of, fl in diverge.items(): act("divergent renames", "dr", of, fl) diff --git a/tests/test-backout.out b/tests/test-backout.out --- a/tests/test-backout.out +++ b/tests/test-backout.out @@ -74,7 +74,7 @@ marked working directory as branch branc adding file2 removing file1 created new head -changeset 3:f1c642b1d8e5 backs out changeset 1:bf1602f437f3 +changeset 3:d4e8f6db59fb backs out changeset 1:bf1602f437f3 the backout changeset is a new head - do not forget to merge (use "backout --merge" if you want to auto-merge) % on branch2 with branch1 not merged, so file1 should still exist: @@ -85,10 +85,11 @@ C file2 % on branch2 with branch1 merged, so file1 should be gone: 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (branch merge, don't forget to commit) -21d4dc6f9a41 (branch2) tip +22149cdde76d (branch2) tip C default C file2 % on branch1, so no file1 and file2: -0 files updated, 0 files merged, 1 files removed, 0 files unresolved -f1c642b1d8e5 (branch1) +1 files updated, 0 files merged, 1 files removed, 0 files unresolved +bf1602f437f3 (branch1) C default +C file1 diff --git a/tests/test-diff-copy-depth b/tests/test-diff-copy-depth new file mode 100644 --- /dev/null +++ b/tests/test-diff-copy-depth @@ -0,0 +1,31 @@ +#!/bin/bash + +for i in aaa zzz; do + hg init t + cd t + + echo "-- With $i" + + touch file + hg add file + hg ci -m "Add" + + hg cp file $i + hg ci -m "a -> $i" + + hg cp $i other-file + echo "different" >> $i + hg ci -m "$i -> other-file" + + hg cp other-file somename + + echo "Status": + hg st -C + echo + echo "Diff:" + hg diff -g + echo + + cd .. + rm -rf t +done diff --git a/tests/test-diff-copy-depth.out b/tests/test-diff-copy-depth.out new file mode 100644 --- /dev/null +++ b/tests/test-diff-copy-depth.out @@ -0,0 +1,20 @@ +-- With aaa +Status: +A somename + other-file + +Diff: +diff --git a/other-file b/somename +copy from other-file +copy to somename + +-- With zzz +Status: +A somename + other-file + +Diff: +diff --git a/other-file b/somename +copy from other-file +copy to somename + diff --git a/tests/test-mv-cp-st-diff b/tests/test-mv-cp-st-diff --- a/tests/test-mv-cp-st-diff +++ b/tests/test-mv-cp-st-diff @@ -11,12 +11,17 @@ cd t # set up a boring main branch add a a hg add a +mkdir x +add x/x x +hg add x/x hg ci -m0 add a m1 hg ci -m1 add a m2 +add x/y y1 +hg add x/y hg ci -m2 show() @@ -59,6 +64,7 @@ tb() echo } + tb "add a a1" "add a a2" "hg mv a b" "rename in working dir" tb "add a a1" "add a a2" "hg cp a b" "copy in working dir" tb "hg mv a b" "add b b1" "add b w" "single rename" @@ -66,3 +72,5 @@ tb "hg cp a b" "add b b1" "add a w" "sin tb "hg mv a b" "hg mv b c" "hg mv c d" "rename chain" tb "hg cp a b" "hg cp b c" "hg cp c d" "copy chain" tb "add a a1" "hg mv a b" "hg mv b a" "circular rename" + +tb "hg mv x y" "add y/x x1" "add y/x x2" "directory move" diff --git a/tests/test-mv-cp-st-diff.out b/tests/test-mv-cp-st-diff.out --- a/tests/test-mv-cp-st-diff.out +++ b/tests/test-mv-cp-st-diff.out @@ -30,6 +30,7 @@ rename to b A b a R a +R x/y diff --git a/a b/b rename from a @@ -43,6 +44,12 @@ rename to b +0 +a1 +a2 +diff --git a/x/y b/x/y +deleted file mode 100644 +--- a/x/y ++++ /dev/null +@@ -1,1 +0,0 @@ +-y1 - root to parent: --rev 0 --rev . M a @@ -70,6 +77,7 @@ diff --git a/a b/a - branch to parent: --rev 2 --rev . M a +R x/y diff --git a/a b/a --- a/a @@ -81,9 +89,16 @@ diff --git a/a b/a +0 +a1 +a2 +diff --git a/x/y b/x/y +deleted file mode 100644 +--- a/x/y ++++ /dev/null +@@ -1,1 +0,0 @@ +-y1 - parent to branch: --rev . --rev 2 M a +A x/y diff --git a/a b/a --- a/a @@ -95,6 +110,12 @@ diff --git a/a b/a -a2 +m1 +m2 +diff --git a/x/y b/x/y +new file mode 100644 +--- /dev/null ++++ b/x/y +@@ -0,0 +1,1 @@ ++y1 created new head @@ -136,6 +157,7 @@ copy to b M a A b a +R x/y diff --git a/a b/a --- a/a @@ -159,6 +181,12 @@ copy to b +1 +a1 +a2 +diff --git a/x/y b/x/y +deleted file mode 100644 +--- a/x/y ++++ /dev/null +@@ -1,1 +0,0 @@ +-y1 - root to parent: --rev 0 --rev . M a @@ -186,6 +214,7 @@ diff --git a/a b/a - branch to parent: --rev 2 --rev . M a +R x/y diff --git a/a b/a --- a/a @@ -197,9 +226,16 @@ diff --git a/a b/a +1 +a1 +a2 +diff --git a/x/y b/x/y +deleted file mode 100644 +--- a/x/y ++++ /dev/null +@@ -1,1 +0,0 @@ +-y1 - parent to branch: --rev . --rev 2 M a +A x/y diff --git a/a b/a --- a/a @@ -211,6 +247,12 @@ diff --git a/a b/a -a2 +m1 +m2 +diff --git a/x/y b/x/y +new file mode 100644 +--- /dev/null ++++ b/x/y +@@ -0,0 +1,1 @@ ++y1 created new head @@ -248,6 +290,7 @@ rename to b A b a R a +R x/y diff --git a/a b/b rename from a @@ -261,6 +304,12 @@ rename to b +2 +b1 +w +diff --git a/x/y b/x/y +deleted file mode 100644 +--- a/x/y ++++ /dev/null +@@ -1,1 +0,0 @@ +-y1 - root to parent: --rev 0 --rev . A b @@ -296,6 +345,7 @@ rename to a A b a R a +R x/y diff --git a/a b/b rename from a @@ -308,10 +358,17 @@ rename to b -m2 +2 +b1 +diff --git a/x/y b/x/y +deleted file mode 100644 +--- a/x/y ++++ /dev/null +@@ -1,1 +0,0 @@ +-y1 - parent to branch: --rev . --rev 2 A a b +A x/y R b diff --git a/b b/a @@ -325,6 +382,12 @@ rename to a -b1 +m1 +m2 +diff --git a/x/y b/x/y +new file mode 100644 +--- /dev/null ++++ b/x/y +@@ -0,0 +1,1 @@ ++y1 created new head @@ -367,6 +430,7 @@ copy to b M a A b a +R x/y diff --git a/a b/a --- a/a @@ -388,6 +452,12 @@ copy to b -m2 +3 +b1 +diff --git a/x/y b/x/y +deleted file mode 100644 +--- a/x/y ++++ /dev/null +@@ -1,1 +0,0 @@ +-y1 - root to parent: --rev 0 --rev . M a @@ -433,6 +503,7 @@ deleted file mode 100644 M a A b a +R x/y diff --git a/a b/a --- a/a @@ -453,9 +524,16 @@ copy to b -m2 +3 +b1 +diff --git a/x/y b/x/y +deleted file mode 100644 +--- a/x/y ++++ /dev/null +@@ -1,1 +0,0 @@ +-y1 - parent to branch: --rev . --rev 2 M a +A x/y R b diff --git a/a b/a @@ -474,6 +552,12 @@ deleted file mode 100644 -a -3 -b1 +diff --git a/x/y b/x/y +new file mode 100644 +--- /dev/null ++++ b/x/y +@@ -0,0 +1,1 @@ ++y1 created new head @@ -506,6 +590,7 @@ rename to d A d a R a +R x/y diff --git a/a b/d rename from a @@ -517,6 +602,12 @@ rename to d -m1 -m2 +4 +diff --git a/x/y b/x/y +deleted file mode 100644 +--- a/x/y ++++ /dev/null +@@ -1,1 +0,0 @@ +-y1 - root to parent: --rev 0 --rev . A c @@ -550,6 +641,7 @@ rename to a A c a R a +R x/y diff --git a/a b/c rename from a @@ -561,10 +653,17 @@ rename to c -m1 -m2 +4 +diff --git a/x/y b/x/y +deleted file mode 100644 +--- a/x/y ++++ /dev/null +@@ -1,1 +0,0 @@ +-y1 - parent to branch: --rev . --rev 2 A a c +A x/y R c diff --git a/c b/a @@ -577,6 +676,12 @@ rename to a -4 +m1 +m2 +diff --git a/x/y b/x/y +new file mode 100644 +--- /dev/null ++++ b/x/y +@@ -0,0 +1,1 @@ ++y1 created new head @@ -638,6 +743,7 @@ A c a A d a +R x/y diff --git a/a b/a --- a/a @@ -677,6 +783,12 @@ copy to d -m1 -m2 +5 +diff --git a/x/y b/x/y +deleted file mode 100644 +--- a/x/y ++++ /dev/null +@@ -1,1 +0,0 @@ +-y1 - root to parent: --rev 0 --rev . M a @@ -740,6 +852,7 @@ A b a A c a +R x/y diff --git a/a b/a --- a/a @@ -769,9 +882,16 @@ copy to c -m1 -m2 +5 +diff --git a/x/y b/x/y +deleted file mode 100644 +--- a/x/y ++++ /dev/null +@@ -1,1 +0,0 @@ +-y1 - parent to branch: --rev . --rev 2 M a +A x/y R b R c @@ -797,6 +917,12 @@ deleted file mode 100644 @@ -1,2 +0,0 @@ -a -5 +diff --git a/x/y b/x/y +new file mode 100644 +--- /dev/null ++++ b/x/y +@@ -0,0 +1,1 @@ ++y1 created new head @@ -824,6 +950,7 @@ diff --git a/a b/a - working to branch: --rev 2 M a +R x/y diff --git a/a b/a --- a/a @@ -834,6 +961,12 @@ diff --git a/a b/a -m2 +6 +a1 +diff --git a/x/y b/x/y +deleted file mode 100644 +--- a/x/y ++++ /dev/null +@@ -1,1 +0,0 @@ +-y1 - root to parent: --rev 0 --rev . A b @@ -869,6 +1002,7 @@ rename to a A b a R a +R x/y diff --git a/a b/b rename from a @@ -881,10 +1015,17 @@ rename to b -m2 +6 +a1 +diff --git a/x/y b/x/y +deleted file mode 100644 +--- a/x/y ++++ /dev/null +@@ -1,1 +0,0 @@ +-y1 - parent to branch: --rev . --rev 2 A a b +A x/y R b diff --git a/b b/a @@ -898,5 +1039,182 @@ rename to a -a1 +m1 +m2 +diff --git a/x/y b/x/y +new file mode 100644 +--- /dev/null ++++ b/x/y +@@ -0,0 +1,1 @@ ++y1 +created new head +moving x/x to y/x +** directory move ** +** hg mv x y / add y/x x1 / add y/x x2 +- working to parent: +M y/x + +diff --git a/y/x b/y/x +--- a/y/x ++++ b/y/x +@@ -1,2 +1,3 @@ + x + x1 ++x2 + +- working to root: --rev 0 +M a +A y/x + x/x +R x/x + +diff --git a/a b/a +--- a/a ++++ b/a +@@ -1,1 +1,2 @@ + a ++7 +diff --git a/x/x b/y/x +rename from x/x +rename to y/x +--- a/x/x ++++ b/y/x +@@ -1,1 +1,3 @@ + x ++x1 ++x2 + +- working to branch: --rev 2 +M a +A y/x + x/x +R x/x +R x/y + +diff --git a/a b/a +--- a/a ++++ b/a +@@ -1,3 +1,2 @@ + a +-m1 +-m2 ++7 +diff --git a/x/y b/x/y +deleted file mode 100644 +--- a/x/y ++++ /dev/null +@@ -1,1 +0,0 @@ +-y1 +diff --git a/x/x b/y/x +rename from x/x +rename to y/x +--- a/x/x ++++ b/y/x +@@ -1,1 +1,3 @@ + x ++x1 ++x2 + +- root to parent: --rev 0 --rev . +M a +A y/x + x/x +R x/x + +diff --git a/a b/a +--- a/a ++++ b/a +@@ -1,1 +1,2 @@ + a ++7 +diff --git a/x/x b/y/x +rename from x/x +rename to y/x +--- a/x/x ++++ b/y/x +@@ -1,1 +1,2 @@ + x ++x1 + +- parent to root: --rev . --rev 0 +M a +A x/x + y/x +R y/x + +diff --git a/a b/a +--- a/a ++++ b/a +@@ -1,2 +1,1 @@ + a +-7 +diff --git a/y/x b/x/x +rename from y/x +rename to x/x +--- a/y/x ++++ b/x/x +@@ -1,2 +1,1 @@ + x +-x1 + +- branch to parent: --rev 2 --rev . +M a +A y/x + x/x +R x/x +R x/y + +diff --git a/a b/a +--- a/a ++++ b/a +@@ -1,3 +1,2 @@ + a +-m1 +-m2 ++7 +diff --git a/x/y b/x/y +deleted file mode 100644 +--- a/x/y ++++ /dev/null +@@ -1,1 +0,0 @@ +-y1 +diff --git a/x/x b/y/x +rename from x/x +rename to y/x +--- a/x/x ++++ b/y/x +@@ -1,1 +1,2 @@ + x ++x1 + +- parent to branch: --rev . --rev 2 +M a +A x/x + y/x +A x/y +R y/x + +diff --git a/a b/a +--- a/a ++++ b/a +@@ -1,2 +1,3 @@ + a +-7 ++m1 ++m2 +diff --git a/y/x b/x/x +rename from y/x +rename to x/x +--- a/y/x ++++ b/x/x +@@ -1,2 +1,1 @@ + x +-x1 +diff --git a/x/y b/x/y +new file mode 100644 +--- /dev/null ++++ b/x/y +@@ -0,0 +1,1 @@ ++y1 + +