# HG changeset patch # User Sune Foldager # Date 1220871346 -7200 # Node ID a6b74fbb5ce097616b88068640333844c3d77eb2 # Parent 92d44ec32430f014511b91c997c198f04d4de0f0 fetch: added support for named branches Previously, fetch didn't really work when there were multiple named branches in the repository. Now it tries to do the right thing(tm) in all situations. diff -r 92d44ec32430 -r a6b74fbb5ce0 hgext/fetch.py --- a/hgext/fetch.py Mon Sep 08 12:55:27 2008 +0200 +++ b/hgext/fetch.py Mon Sep 08 12:55:46 2008 +0200 @@ -16,7 +16,7 @@ This finds all changes from the repository at the specified path or URL and adds them to the local repository. - If the pulled changes add a new head, the head is automatically + If the pulled changes add a new branch head, the head is automatically merged, and the result of the merge is committed. Otherwise, the working directory is updated to include the new changes. @@ -33,9 +33,10 @@ opts['date'] = util.parsedate(date) parent, p2 = repo.dirstate.parents() - if parent != repo.changelog.tip(): - raise util.Abort(_('working dir not at tip ' - '(use "hg update" to check out tip)')) + branch = repo[parent].branch() + if parent != repo[branch].node(): + raise util.Abort(_('working dir not at branch tip ' + '(use "hg update" to check out branch tip)')) if p2 != nullid: raise util.Abort(_('outstanding uncommitted merge')) @@ -50,9 +51,9 @@ raise util.Abort(_('outstanding uncommitted changes')) if del_: raise util.Abort(_('working directory is missing some files')) - if len(repo.heads()) > 1: - raise util.Abort(_('multiple heads in this repository ' - '(use "hg heads" and "hg merge" to merge)')) + if len(repo.branchheads(branch)) > 1: + raise util.Abort(_('multiple heads in this branch ' + '(use "hg heads ." and "hg merge" to merge)')) cmdutil.setremoteconfig(ui, opts) @@ -67,27 +68,35 @@ else: revs = [other.lookup(rev) for rev in opts['rev']] + # Are there any changes at all? modheads = repo.pull(other, heads=revs) if modheads == 0: return 0 - if modheads == 1: - return hg.clean(repo, repo.changelog.tip()) - newheads = repo.heads(parent) - newchildren = [n for n in repo.heads(parent) if n != parent] + # Is this a simple fast-forward along the current branch? + newheads = repo.branchheads(branch) + newchildren = repo.changelog.nodesbetween([parent], newheads)[2] + if len(newheads) == 1: + if newchildren[0] != parent: + return hg.clean(repo, newchildren[0]) + else: + return + + # Are there more than one additional branch heads? + newchildren = [n for n in newchildren if n != parent] newparent = parent if newchildren: newparent = newchildren[0] hg.clean(repo, newparent) - - newheads = [n for n in repo.heads() if n != newparent] + newheads = [n for n in newheads if n != newparent] if len(newheads) > 1: - ui.status(_('not merging with %d other new heads ' - '(use "hg heads" and "hg merge" to merge them)') % + ui.status(_('not merging with %d other new branch heads ' + '(use "hg heads ." and "hg merge" to merge them)\n') % (len(newheads) - 1)) return + + # Otherwise, let's merge. err = False - if newheads: # By default, we consider the repository we're pulling # *from* as authoritative, so we merge our changes into diff -r 92d44ec32430 -r a6b74fbb5ce0 tests/test-fetch --- a/tests/test-fetch Mon Sep 08 12:55:27 2008 +0200 +++ b/tests/test-fetch Mon Sep 08 12:55:46 2008 +0200 @@ -7,6 +7,7 @@ echo "[extensions]" >> $HGRCPATH echo "fetch=" >> $HGRCPATH +echo % test fetch with default branches only hg init a echo a > a/a hg --cwd a commit -d '1 0' -Ama @@ -66,4 +67,93 @@ echo % should abort, because i is modified hg --cwd i fetch ../h + +echo % test fetch with named branches +hg init nbase +echo base > nbase/a +hg -R nbase ci -d '1 0' -Am base +hg -R nbase branch a +echo a > nbase/a +hg -R nbase ci -d '2 0' -m a +hg -R nbase up -C 0 +hg -R nbase branch b +echo b > nbase/b +hg -R nbase ci -Ad '3 0' -m b + +echo +echo % pull in change on foreign branch +hg clone nbase n1 +hg clone nbase n2 +hg -R n1 up -C a +echo aa > n1/a +hg -R n1 ci -d '4 0' -m a1 + +hg -R n2 up -C b +hg -R n2 fetch -d '9 0' -m 'merge' n1 +echo '% parent should be 2 (no automatic update)' +hg -R n2 parents --template '{rev}\n' +rm -fr n1 n2 + +echo +echo % pull in changes on both foreign and local branches +hg clone nbase n1 +hg clone nbase n2 +hg -R n1 up -C a +echo aa > n1/a +hg -R n1 ci -d '4 0' -m a1 +hg -R n1 up -C b +echo bb > n1/b +hg -R n1 ci -d '5 0' -m b1 + +hg -R n2 up -C b +hg -R n2 fetch -d '9 0' -m 'merge' n1 +echo '% parent should be 4 (fast forward)' +hg -R n2 parents --template '{rev}\n' +rm -fr n1 n2 + +echo +echo '% pull changes on foreign (2 new heads) and local (1 new head) branches' +echo % with a local change +hg clone nbase n1 +hg clone nbase n2 +hg -R n1 up -C a +echo a1 > n1/a +hg -R n1 ci -d '4 0' -m a1 +hg -R n1 up -C b +echo bb > n1/b +hg -R n1 ci -d '5 0' -m b1 +hg -R n1 up -C 1 +echo a2 > n1/a +hg -R n1 ci -d '6 0' -m a2 + +hg -R n2 up -C b +echo change >> n2/c +hg -R n2 ci -Ad '7 0' -m local +hg -R n2 fetch -d '9 0' -m 'merge' n1 +echo '% parent should be 7 (new merge changeset)' +hg -R n2 parents --template '{rev}\n' +rm -fr n1 n2 + +echo '% pull in changes on foreign (merge of local branch) and local (2 new' +echo '% heads) with a local change' +hg clone nbase n1 +hg clone nbase n2 +hg -R n1 up -C a +hg -R n1 merge b +hg -R n1 ci -d '4 0' -m merge +hg -R n1 up -C 2 +echo c > n1/a +hg -R n1 ci -d '5 0' -m c +hg -R n1 up -C 2 +echo cc > n1/a +hg -R n1 ci -d '6 0' -m cc + +hg -R n2 up -C b +echo change >> n2/b +hg -R n2 ci -Ad '7 0' -m local +hg -R n2 fetch -d '9 0' -m 'merge' n1 +echo '% parent should be 3 (fetch did not merge anything)' +hg -R n2 parents --template '{rev}\n' +rm -fr n1 n2 + true diff -r 92d44ec32430 -r a6b74fbb5ce0 tests/test-fetch.out --- a/tests/test-fetch.out Mon Sep 08 12:55:27 2008 +0200 +++ b/tests/test-fetch.out Mon Sep 08 12:55:46 2008 +0200 @@ -1,3 +1,4 @@ +% test fetch with default branches only adding a updating working directory 1 files updated, 0 files merged, 0 files removed, 0 files unresolved @@ -79,3 +80,93 @@ new changeset 4:55aa4f32ec59 merges remote changes with local % should abort, because i is modified abort: working directory is missing some files +% test fetch with named branches +adding a +marked working directory as branch a +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +marked working directory as branch b +adding b +created new head + +% pull in change on foreign branch +updating working directory +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +updating working directory +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +pulling from n1 +searching for changes +adding changesets +adding manifests +adding file changes +added 1 changesets with 1 changes to 1 files +% parent should be 2 (no automatic update) +2 + +% pull in changes on both foreign and local branches +updating working directory +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +updating working directory +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +2 files updated, 0 files merged, 0 files removed, 0 files unresolved +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +pulling from n1 +searching for changes +adding changesets +adding manifests +adding file changes +added 2 changesets with 2 changes to 2 files +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +% parent should be 4 (fast forward) +4 + +% pull changes on foreign (2 new heads) and local (1 new head) branches +% with a local change +updating working directory +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +updating working directory +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +2 files updated, 0 files merged, 0 files removed, 0 files unresolved +1 files updated, 0 files merged, 1 files removed, 0 files unresolved +created new head +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +adding c +pulling from n1 +searching for changes +adding changesets +adding manifests +adding file changes +added 3 changesets with 3 changes to 2 files (+2 heads) +updating to 5:708c6cce3d26 +1 files updated, 0 files merged, 1 files removed, 0 files unresolved +merging with 3:d83427717b1f +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +new changeset 7:48f1a33f52af merges remote changes with local +% parent should be 7 (new merge changeset) +7 +% pull in changes on foreign (merge of local branch) and local (2 new +% heads) with a local change +updating working directory +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +updating working directory +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +(branch merge, don't forget to commit) +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +created new head +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +created new head +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +pulling from n1 +searching for changes +adding changesets +adding manifests +adding file changes +added 3 changesets with 2 changes to 1 files (+2 heads) +not merging with 1 other new branch heads (use "hg heads ." and "hg merge" to merge them) +% parent should be 3 (fetch did not merge anything) +3