changeset 7007:a6b74fbb5ce0

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.
author Sune Foldager <cryo@cyanite.org>
date Mon, 08 Sep 2008 12:55:46 +0200
parents 92d44ec32430
children 8fee8ff13d37
files hgext/fetch.py tests/test-fetch tests/test-fetch.out
diffstat 3 files changed, 206 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- 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
--- 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
--- 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