$ cat >> $HGRCPATH < [extensions] > rebase= > mq= > drawdag=$TESTDIR/drawdag.py > > [phases] > publish=False > > [alias] > tglog = log -G --template "{rev}: {node|short} '{desc}' {branches}\n" > tglogp = log -G --template "{rev}: {node|short} {phase} '{desc}' {branches}\n" > EOF Highest phase of source commits is used: $ hg init phase $ cd phase $ hg debugdrawdag << 'EOF' > D > | > F C > | | > E B > |/ > A > EOF $ hg phase --force --secret D $ cat > $TESTTMP/editor.sh < echo "==== before editing" > cat \$1 > echo "====" > echo "edited manually" >> \$1 > EOF $ HGEDITOR="sh $TESTTMP/editor.sh" hg rebase --collapse --keepbranches -e --source B --dest F rebasing 1:112478962961 B "B" rebasing 3:26805aba1e60 C "C" rebasing 5:f585351a92f8 D tip "D" ==== before editing Collapsed revision * B * C * D HG: Enter commit message. Lines beginning with 'HG:' are removed. HG: Leave message empty to abort commit. HG: -- HG: user: test HG: branch 'default' HG: added B HG: added C HG: added D ==== saved backup bundle to $TESTTMP/phase/.hg/strip-backup/112478962961-cb2a9b47-rebase.hg $ hg tglogp o 3: 92fa5f5fe108 secret 'Collapsed revision | * B | * C | * D | | | edited manually' o 2: 64a8289d2492 draft 'F' | o 1: 7fb047a69f22 draft 'E' | o 0: 426bada5c675 draft 'A' $ hg manifest --rev tip A B C D E F $ cd .. Merge gets linearized: $ hg init linearized-merge $ cd linearized-merge $ hg debugdrawdag << 'EOF' > F D > |/| > C B > |/ > A > EOF $ hg phase --force --secret D $ hg rebase --source B --collapse --dest F rebasing 1:112478962961 B "B" rebasing 3:4e4f9194f9f1 D "D" saved backup bundle to $TESTTMP/linearized-merge/.hg/strip-backup/112478962961-e389075b-rebase.hg $ hg tglog o 3: 5bdc08b7da2b 'Collapsed revision | * B | * D' o 2: afc707c82df0 'F' | o 1: dc0947a82db8 'C' | o 0: 426bada5c675 'A' $ hg manifest --rev tip A B C F $ cd .. Custom message: $ hg init message $ cd message $ hg debugdrawdag << 'EOF' > C > | > D B > |/ > A > EOF $ hg rebase --base B -m 'custom message' abort: message can only be specified with collapse [10] $ cat > $TESTTMP/checkeditform.sh < env | grep HGEDITFORM > true > EOF $ HGEDITOR="sh $TESTTMP/checkeditform.sh" hg rebase --source B --collapse -m 'custom message' -e --dest D rebasing 1:112478962961 B "B" rebasing 3:26805aba1e60 C tip "C" HGEDITFORM=rebase.collapse saved backup bundle to $TESTTMP/message/.hg/strip-backup/112478962961-f4131707-rebase.hg $ hg tglog o 2: 2f197b9a08f3 'custom message' | o 1: b18e25de2cf5 'D' | o 0: 426bada5c675 'A' $ hg manifest --rev tip A B C D $ cd .. Rebase and collapse - more than one external (fail): $ hg init multiple-external-parents $ cd multiple-external-parents $ hg debugdrawdag << 'EOF' > G > |\ > | F > | | > D E > |\| > H C B > \|/ > A > EOF $ hg rebase -s C --dest H --collapse abort: unable to collapse on top of 3, there is more than one external parent: 1, 6 [20] Rebase and collapse - E onto H: $ hg rebase -s E --dest H --collapse # root (E) is not a merge rebasing 5:49cb92066bfd E "E" rebasing 6:11abe3fb10b8 F "F" rebasing 7:64e264db77f0 G tip "G" saved backup bundle to $TESTTMP/multiple-external-parents/.hg/strip-backup/49cb92066bfd-ee8a8a79-rebase.hg $ hg tglog o 5: 8b2315790719 'Collapsed revision |\ * E | | * F | | * G' | o 4: 4e4f9194f9f1 'D' | |\ o | | 3: 575c4b5ec114 'H' | | | +---o 2: dc0947a82db8 'C' | | | o 1: 112478962961 'B' |/ o 0: 426bada5c675 'A' $ hg manifest --rev tip A C E F H $ cd .. Test that branchheads cache is updated correctly when doing a strip in which the parent of the ancestor node to be stripped does not become a head and also, the parent of a node that is a child of the node stripped becomes a head (node 3). The code is now much simpler and we could just test a simpler scenario We keep it the test this way in case new complexity is injected. Create repo b: $ hg init branch-heads $ cd branch-heads $ hg debugdrawdag << 'EOF' > G > |\ > | F > | | > D E > |\| > H C B > \|/ > A > EOF $ hg heads --template="{rev}:{node} {branch}\n" 7:64e264db77f061f16d9132b70c5a58e2461fb630 default 3:575c4b5ec114d64b681d33f8792853568bfb2b2c default $ cat $TESTTMP/branch-heads/.hg/cache/branch2-served 64e264db77f061f16d9132b70c5a58e2461fb630 7 575c4b5ec114d64b681d33f8792853568bfb2b2c o default 64e264db77f061f16d9132b70c5a58e2461fb630 o default $ hg strip 4 saved backup bundle to $TESTTMP/branch-heads/.hg/strip-backup/4e4f9194f9f1-5ec4b5e6-backup.hg $ cat $TESTTMP/branch-heads/.hg/cache/branch2-served 11abe3fb10b8689b560681094b17fe161871d043 5 dc0947a82db884575bb76ea10ac97b08536bfa03 o default 575c4b5ec114d64b681d33f8792853568bfb2b2c o default 11abe3fb10b8689b560681094b17fe161871d043 o default $ hg heads --template="{rev}:{node} {branch}\n" 5:11abe3fb10b8689b560681094b17fe161871d043 default 3:575c4b5ec114d64b681d33f8792853568bfb2b2c default 2:dc0947a82db884575bb76ea10ac97b08536bfa03 default $ cd .. Preserves external parent $ hg init external-parent $ cd external-parent $ hg debugdrawdag << 'EOF' > H > |\ > | G > | | > | F # F/E = F\n > | | > D E # D/D = D\n > |\| > I C B > \|/ > A > EOF $ hg rebase -s F --dest I --collapse # root (F) is not a merge rebasing 6:c82b08f646f1 F "F" file 'E' was deleted in local [dest] but was modified in other [source]. You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved. What do you want to do? u unresolved conflicts (see 'hg resolve', then 'hg rebase --continue') [240] $ echo F > E $ hg resolve -m (no more unresolved files) continue: hg rebase --continue $ hg rebase -c rebasing 6:c82b08f646f1 F "F" rebasing 7:a6db7fa104e1 G "G" rebasing 8:e1d201b72d91 H tip "H" saved backup bundle to $TESTTMP/external-parent/.hg/strip-backup/c82b08f646f1-f2721fbf-rebase.hg $ hg tglog o 6: 681daa3e686d 'Collapsed revision |\ * F | | * G | | * H' | | o 5: 49cb92066bfd 'E' | | | | o | 4: 09143c0bf13e 'D' | |\| o | | 3: 08ebfeb61bac 'I' | | | | o | 2: dc0947a82db8 'C' |/ / | o 1: 112478962961 'B' |/ o 0: 426bada5c675 'A' $ hg manifest --rev tip A C D E F G I $ hg up tip -q $ cat E F $ cd .. Rebasing from multiple bases: $ hg init multiple-bases $ cd multiple-bases $ hg debugdrawdag << 'EOF' > C B > D |/ > |/ > A > EOF $ hg rebase --collapse -r 'B+C' -d D rebasing 1:fc2b737bb2e5 B "B" rebasing 2:dc0947a82db8 C "C" saved backup bundle to $TESTTMP/multiple-bases/.hg/strip-backup/dc0947a82db8-b0c1a7ea-rebase.hg $ hg tglog o 2: 2127ae44d291 'Collapsed revision | * B | * C' o 1: b18e25de2cf5 'D' | o 0: 426bada5c675 'A' $ cd .. With non-contiguous commits: $ hg init non-contiguous $ cd non-contiguous $ cat >> .hg/hgrc < [experimental] > evolution=all > EOF $ hg debugdrawdag << 'EOF' > F > | > E > | > D > | > C > | > B G > |/ > A > EOF BROKEN: should be allowed $ hg rebase --collapse -r 'B+D+F' -d G abort: unable to collapse on top of 2, there is more than one external parent: 3, 5 [20] $ cd .. $ hg init multiple-external-parents-2 $ cd multiple-external-parents-2 $ hg debugdrawdag << 'EOF' > D G > |\ /| > B C E F > \| |/ > \ H / > \|/ > A > EOF $ hg rebase --collapse -d H -s 'B+F' abort: unable to collapse on top of 5, there is more than one external parent: 1, 3 [20] $ cd .. With internal merge: $ hg init internal-merge $ cd internal-merge $ hg debugdrawdag << 'EOF' > E > |\ > C D > |/ > F B > |/ > A > EOF $ hg rebase -s B --collapse --dest F rebasing 1:112478962961 B "B" rebasing 3:26805aba1e60 C "C" rebasing 4:be0ef73c17ad D "D" rebasing 5:02c4367d6973 E tip "E" saved backup bundle to $TESTTMP/internal-merge/.hg/strip-backup/112478962961-1dfb057b-rebase.hg $ hg tglog o 2: c0512a1797b0 'Collapsed revision | * B | * C | * D | * E' o 1: 8908a377a434 'F' | o 0: 426bada5c675 'A' $ hg manifest --rev tip A B C D F $ cd .. Interactions between collapse and keepbranches $ hg init e $ cd e $ echo 'a' > a $ hg ci -Am 'A' adding a $ hg branch 'one' marked working directory as branch one (branches are permanent and global, did you want a bookmark?) $ echo 'b' > b $ hg ci -Am 'B' adding b $ hg branch 'two' marked working directory as branch two $ echo 'c' > c $ hg ci -Am 'C' adding c $ hg up -q 0 $ echo 'd' > d $ hg ci -Am 'D' adding d $ hg tglog @ 3: 41acb9dca9eb 'D' | | o 2: 8ac4a08debf1 'C' two | | | o 1: 1ba175478953 'B' one |/ o 0: 1994f17a630e 'A' $ hg rebase --keepbranches --collapse -s 1 -d 3 abort: cannot collapse multiple named branches [10] $ cd .. Rebase, collapse and copies $ hg init copies $ cd copies $ hg unbundle "$TESTDIR/bundles/renames.hg" adding changesets adding manifests adding file changes added 4 changesets with 11 changes to 7 files (+1 heads) new changesets f447d5abf5ea:338e84e2e558 (4 drafts) (run 'hg heads' to see heads, 'hg merge' to merge) $ hg up -q tip $ hg tglog @ 3: 338e84e2e558 'move2' | o 2: 6e7340ee38c0 'move1' | | o 1: 1352765a01d4 'change' |/ o 0: f447d5abf5ea 'add' $ hg rebase --collapse -d 1 rebasing 2:6e7340ee38c0 "move1" merging a and d to d merging b and e to e merging c and f to f rebasing 3:338e84e2e558 tip "move2" merging f and c to c merging e and g to g saved backup bundle to $TESTTMP/copies/.hg/strip-backup/6e7340ee38c0-ef8ef003-rebase.hg $ hg st $ hg st --copies --change tip A d a A g b R b $ hg up tip -q $ cat c c c $ cat d a a $ cat g b b $ hg log -r . --template "{file_copies}\n" d (a)g (b) Test collapsing a middle revision in-place $ hg tglog @ 2: 64b456429f67 'Collapsed revision | * move1 | * move2' o 1: 1352765a01d4 'change' | o 0: f447d5abf5ea 'add' $ hg rebase --collapse -r 1 -d 0 abort: cannot rebase changeset with children (use --keep to keep original changesets) [10] Test collapsing in place $ hg rebase --collapse -b . -d 0 rebasing 1:1352765a01d4 "change" rebasing 2:64b456429f67 tip "Collapsed revision" saved backup bundle to $TESTTMP/copies/.hg/strip-backup/1352765a01d4-45a352ea-rebase.hg $ hg st --change tip --copies M a M c A d a A g b R b $ hg up tip -q $ cat a a a $ cat c c c $ cat d a a $ cat g b b $ cd .. Test stripping a revision with another child $ hg init f $ cd f $ hg debugdrawdag << 'EOF' > C B > |/ > A > EOF $ hg heads --template="{rev}:{node} {branch}: {desc}\n" 2:dc0947a82db884575bb76ea10ac97b08536bfa03 default: C 1:112478962961147124edd43549aedd1a335e44bf default: B $ hg strip C saved backup bundle to $TESTTMP/f/.hg/strip-backup/dc0947a82db8-d21b92a4-backup.hg $ hg tglog o 1: 112478962961 'B' | o 0: 426bada5c675 'A' $ hg heads --template="{rev}:{node} {branch}: {desc}\n" 1:112478962961147124edd43549aedd1a335e44bf default: B $ cd .. Test collapsing changes that add then remove a file $ hg init collapseaddremove $ cd collapseaddremove $ touch base $ hg commit -Am base adding base $ touch a $ hg commit -Am a adding a $ hg rm a $ touch b $ hg commit -Am b adding b $ hg book foo $ hg rebase -d 0 -r "1::2" --collapse -m collapsed rebasing 1:6d8d9f24eec3 "a" rebasing 2:1cc73eca5ecc foo tip "b" saved backup bundle to $TESTTMP/collapseaddremove/.hg/strip-backup/6d8d9f24eec3-77d3b6e2-rebase.hg $ hg log -G --template "{rev}: '{desc}' {bookmarks}" @ 1: 'collapsed' foo | o 0: 'base' $ hg manifest --rev tip b base $ cd .. Test that rebase --collapse will remember message after running into merge conflict and invoking rebase --continue. $ hg init collapse_remember_message $ cd collapse_remember_message $ hg debugdrawdag << 'EOF' > C B # B/A = B\n > |/ # C/A = C\n > A > EOF $ hg rebase --collapse -m "new message" -b B -d C rebasing 1:81e5401e4d37 B "B" merging A warning: conflicts while merging A! (edit, then use 'hg resolve --mark') unresolved conflicts (see 'hg resolve', then 'hg rebase --continue') [240] $ rm A.orig $ hg resolve --mark A (no more unresolved files) continue: hg rebase --continue $ hg rebase --continue rebasing 1:81e5401e4d37 B "B" saved backup bundle to $TESTTMP/collapse_remember_message/.hg/strip-backup/81e5401e4d37-96c3dd30-rebase.hg $ hg log changeset: 2:17186933e123 tag: tip user: test date: Thu Jan 01 00:00:00 1970 +0000 summary: new message changeset: 1:043039e9df84 tag: C user: test date: Thu Jan 01 00:00:00 1970 +0000 summary: C changeset: 0:426bada5c675 tag: A user: test date: Thu Jan 01 00:00:00 1970 +0000 summary: A $ cd .. Test aborted editor on final message $ HGMERGE=:merge3 $ export HGMERGE $ hg init aborted-editor $ cd aborted-editor $ hg debugdrawdag << 'EOF' > C # D/A = D\n > | # C/A = C\n > B D # B/A = B\n > |/ # A/A = A\n > A > EOF $ hg rebase --collapse -t internal:merge3 -s B -d D rebasing 1:f899f3910ce7 B "B" merging A warning: conflicts while merging A! (edit, then use 'hg resolve --mark') unresolved conflicts (see 'hg resolve', then 'hg rebase --continue') [240] $ hg tglog o 3: 63668d570d21 'C' | | @ 2: 82b8abf9c185 'D' | | % | 1: f899f3910ce7 'B' |/ o 0: 4a2df7238c3b 'A' $ cat A <<<<<<< dest: 82b8abf9c185 D - test: D D ||||||| base A ======= B >>>>>>> source: f899f3910ce7 B - test: B $ echo BC > A $ hg resolve -m (no more unresolved files) continue: hg rebase --continue $ hg rebase --continue rebasing 1:f899f3910ce7 B "B" rebasing 3:63668d570d21 C tip "C" merging A warning: conflicts while merging A! (edit, then use 'hg resolve --mark') unresolved conflicts (see 'hg resolve', then 'hg rebase --continue') [240] $ hg tglog % 3: 63668d570d21 'C' | | @ 2: 82b8abf9c185 'D' | | o | 1: f899f3910ce7 'B' |/ o 0: 4a2df7238c3b 'A' $ cat A <<<<<<< dest: 82b8abf9c185 D - test: D BC ||||||| base B ======= C >>>>>>> source: 63668d570d21 C tip - test: C $ echo BD > A $ hg resolve -m (no more unresolved files) continue: hg rebase --continue $ HGEDITOR=false hg rebase --continue --config ui.interactive=1 already rebased 1:f899f3910ce7 B "B" as 82b8abf9c185 rebasing 3:63668d570d21 C tip "C" abort: edit failed: false exited with status 1 [250] $ hg tglog o 3: 63668d570d21 'C' | | @ 2: 82b8abf9c185 'D' | | o | 1: f899f3910ce7 'B' |/ o 0: 4a2df7238c3b 'A' $ hg rebase --continue already rebased 1:f899f3910ce7 B "B" as 82b8abf9c185 already rebased 3:63668d570d21 C tip "C" as 82b8abf9c185 saved backup bundle to $TESTTMP/aborted-editor/.hg/strip-backup/f899f3910ce7-7cab5e15-rebase.hg