# HG changeset patch # User Stuart W Marks # Date 2009-11-05 09:53:36 # Node ID ea8c207a0f78f1f79725c75fcd27bc9a57f6b24d # Parent f0e99a2eac76cfff7be69b584d3c825ff9e1b467 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. diff --git a/mercurial/merge.py b/mercurial/merge.py --- a/mercurial/merge.py +++ b/mercurial/merge.py @@ -397,9 +397,37 @@ def update(repo, node, branchmerge, forc """ 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() diff --git a/tests/test-update-branches b/tests/test-update-branches new file mode 100755 --- /dev/null +++ b/tests/test-update-branches @@ -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 diff --git a/tests/test-update-branches.out b/tests/test-update-branches.out new file mode 100644 --- /dev/null +++ b/tests/test-update-branches.out @@ -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