changeset 9716:ea8c207a0f78

update: add comments and test cases for updating across branches Add comment to merge.py:update() showing various cases of 'hg update': to a descendant, crossing named branches, and crossing branches within a named branch; with no option, -c or -C; with or without uncommitted changes; and with or without a specific revision. Add tests for all of these cases.
author Stuart W Marks <smarks@smarks.org>
date Thu, 05 Nov 2009 10:53:36 +0100
parents f0e99a2eac76
children 68a1b9d0663e
files mercurial/merge.py tests/test-update-branches tests/test-update-branches.out
diffstat 3 files changed, 164 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/merge.py	Thu Nov 05 10:49:28 2009 +0100
+++ b/mercurial/merge.py	Thu Nov 05 10:53:36 2009 +0100
@@ -397,9 +397,37 @@
     """
     Perform a merge between the working directory and the given node
 
+    node = the node to update to, or None if unspecified
     branchmerge = whether to merge between branches
     force = whether to force branch merging or file overwriting
     partial = a function to filter file lists (dirstate not updated)
+
+    The table below shows all the behaviors of the update command
+    given the -c and -C or no options, whether the working directory
+    is dirty, whether a revision is specified, and the relationship of
+    the parent rev to the target rev (linear, on the same named
+    branch, or on another named branch).
+
+    This logic is tested by test-update-branches.
+
+    -c  -C  dirty  rev  |  linear   same  cross
+     n   n    n     n   |    ok     (1)     x
+     n   n    n     y   |    ok     (1)    ok
+     n   n    y     *   |   merge   (2)    (3)
+     n   y    *     *   |    ---  discard  ---
+     y   n    y     *   |    ---    (4)    ---
+     y   n    n     *   |    ---    ok     ---
+     y   y    *     *   |    ---    (5)    ---
+
+    x = can't happen
+    * = don't-care
+    1 = abort: crosses branches (use 'hg merge' or 'hg update -C')
+    2 = abort: crosses branches (use 'hg merge' or 'hg update -C'
+                 to discard changes)
+    3 = abort: crosses named branches (use 'hg update -C' to
+                 discard changes)
+    4 = abort: uncommitted local changes
+    5 = incompatible options (checked in commands.py)
     """
 
     wlock = repo.wlock()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-update-branches	Thu Nov 05 10:53:36 2009 +0100
@@ -0,0 +1,81 @@
+#!/bin/sh
+
+# Construct the following history tree:
+#
+# @  5:e1bb631146ca  b1
+# |
+# o  4:a4fdb3b883c4 0:b608b9236435  b1
+# |
+# | o  3:4b57d2520816 1:44592833ba9f
+# | |
+# | | o  2:063f31070f65
+# | |/
+# | o  1:44592833ba9f
+# |/
+# o  0:b608b9236435
+
+hg init
+echo foo > foo
+echo zero > a
+hg ci -qAm0
+echo one > a ; hg ci -m1
+echo two > a ; hg ci -m2
+hg up -q 1
+echo three > a ; hg ci -qm3
+hg up -q 0
+hg branch -q b1
+echo four > a ; hg ci -qm4
+echo five > a ; hg ci -qm5
+
+echo % initial repo state
+echo
+hg --config 'extensions.graphlog=' \
+    glog --template '{rev}:{node|short} {parents} {branches}\n'
+
+# Test helper functions.
+
+revtest () {
+    msg=$1
+    dirtyflag=$2   # 'clean' or 'dirty'
+    startrev=$3
+    targetrev=$4
+    opt=$5
+    echo % revtest $msg $startrev $targetrev
+    hg up -qC $startrev
+    test $dirtyflag = dirty && echo dirty > foo
+    hg up $opt $targetrev
+    hg parent --template 'parent={rev}\n'
+    hg stat
+}    
+
+norevtest () {
+    msg=$1
+    dirtyflag=$2   # 'clean' or 'dirty'
+    startrev=$3
+    opt=$4
+    echo % norevtest $msg $startrev
+    hg up -qC $startrev
+    test $dirtyflag = dirty && echo dirty > foo
+    hg up $opt
+    hg parent --template 'parent={rev}\n'
+    hg stat
+}    
+
+# Test cases are documented in a table in the update function of merge.py.
+# Cases are run as shown in that table, row by row.
+
+norevtest 'none clean linear' clean 4
+norevtest 'none clean same'   clean 2
+
+revtest 'none clean linear' clean 1 2
+revtest 'none clean same'   clean 2 3
+revtest 'none clean cross'  clean 3 4
+
+revtest 'none dirty linear' dirty 1 2
+revtest 'none dirty same'   dirty 2 3
+revtest 'none dirty cross'  dirty 3 4
+
+revtest '-C dirty linear'   dirty 1 2 -C
+revtest '-c dirty linear'   dirty 1 2 -c
+norevtest '-c clean same'   clean 2 -c
+revtest '-cC dirty linear'  dirty 1 2 -cC
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-update-branches.out	Thu Nov 05 10:53:36 2009 +0100
@@ -0,0 +1,55 @@
+% initial repo state
+
+@  5:e1bb631146ca  b1
+|
+o  4:a4fdb3b883c4 0:b608b9236435  b1
+|
+| o  3:4b57d2520816 1:44592833ba9f
+| |
+| | o  2:063f31070f65
+| |/
+| o  1:44592833ba9f
+|/
+o  0:b608b9236435
+
+% norevtest none clean linear 4
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+parent=5
+% norevtest none clean same 2
+abort: crosses branches (use 'hg merge' or 'hg update -C')
+parent=2
+% revtest none clean linear 1 2
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+parent=2
+% revtest none clean same 2 3
+abort: crosses branches (use 'hg merge' or 'hg update -C')
+parent=2
+% revtest none clean cross 3 4
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+parent=4
+% revtest none dirty linear 1 2
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+parent=2
+M foo
+% revtest none dirty same 2 3
+abort: crosses branches (use 'hg merge' or 'hg update -C' to discard changes)
+parent=2
+M foo
+% revtest none dirty cross 3 4
+abort: crosses named branches (use 'hg update -C' to discard changes)
+parent=3
+M foo
+% revtest -C dirty linear 1 2
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+parent=2
+% revtest -c dirty linear 1 2
+abort: uncommitted local changes
+parent=1
+M foo
+% norevtest -c clean same 2
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+parent=3
+% revtest -cC dirty linear 1 2
+abort: cannot specify both -c/--check and -C/--clean
+parent=1
+M foo