Mercurial > public > mercurial-scm > hg
comparison hgext/fetch.py @ 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 | b2bc2d984bac |
children | 6489ee64b522 |
comparison
equal
deleted
inserted
replaced
7006:92d44ec32430 | 7007:a6b74fbb5ce0 |
---|---|
14 '''Pull changes from a remote repository, merge new changes if needed. | 14 '''Pull changes from a remote repository, merge new changes if needed. |
15 | 15 |
16 This finds all changes from the repository at the specified path | 16 This finds all changes from the repository at the specified path |
17 or URL and adds them to the local repository. | 17 or URL and adds them to the local repository. |
18 | 18 |
19 If the pulled changes add a new head, the head is automatically | 19 If the pulled changes add a new branch head, the head is automatically |
20 merged, and the result of the merge is committed. Otherwise, the | 20 merged, and the result of the merge is committed. Otherwise, the |
21 working directory is updated to include the new changes. | 21 working directory is updated to include the new changes. |
22 | 22 |
23 When a merge occurs, the newly pulled changes are assumed to be | 23 When a merge occurs, the newly pulled changes are assumed to be |
24 "authoritative". The head of the new changes is used as the first | 24 "authoritative". The head of the new changes is used as the first |
31 date = opts.get('date') | 31 date = opts.get('date') |
32 if date: | 32 if date: |
33 opts['date'] = util.parsedate(date) | 33 opts['date'] = util.parsedate(date) |
34 | 34 |
35 parent, p2 = repo.dirstate.parents() | 35 parent, p2 = repo.dirstate.parents() |
36 if parent != repo.changelog.tip(): | 36 branch = repo[parent].branch() |
37 raise util.Abort(_('working dir not at tip ' | 37 if parent != repo[branch].node(): |
38 '(use "hg update" to check out tip)')) | 38 raise util.Abort(_('working dir not at branch tip ' |
39 '(use "hg update" to check out branch tip)')) | |
39 | 40 |
40 if p2 != nullid: | 41 if p2 != nullid: |
41 raise util.Abort(_('outstanding uncommitted merge')) | 42 raise util.Abort(_('outstanding uncommitted merge')) |
42 | 43 |
43 wlock = lock = None | 44 wlock = lock = None |
48 | 49 |
49 if mod or add or rem: | 50 if mod or add or rem: |
50 raise util.Abort(_('outstanding uncommitted changes')) | 51 raise util.Abort(_('outstanding uncommitted changes')) |
51 if del_: | 52 if del_: |
52 raise util.Abort(_('working directory is missing some files')) | 53 raise util.Abort(_('working directory is missing some files')) |
53 if len(repo.heads()) > 1: | 54 if len(repo.branchheads(branch)) > 1: |
54 raise util.Abort(_('multiple heads in this repository ' | 55 raise util.Abort(_('multiple heads in this branch ' |
55 '(use "hg heads" and "hg merge" to merge)')) | 56 '(use "hg heads ." and "hg merge" to merge)')) |
56 | 57 |
57 cmdutil.setremoteconfig(ui, opts) | 58 cmdutil.setremoteconfig(ui, opts) |
58 | 59 |
59 other = hg.repository(ui, ui.expandpath(source)) | 60 other = hg.repository(ui, ui.expandpath(source)) |
60 ui.status(_('pulling from %s\n') % | 61 ui.status(_('pulling from %s\n') % |
65 raise util.Abort(_("fetch -r doesn't work for remote " | 66 raise util.Abort(_("fetch -r doesn't work for remote " |
66 "repositories yet")) | 67 "repositories yet")) |
67 else: | 68 else: |
68 revs = [other.lookup(rev) for rev in opts['rev']] | 69 revs = [other.lookup(rev) for rev in opts['rev']] |
69 | 70 |
71 # Are there any changes at all? | |
70 modheads = repo.pull(other, heads=revs) | 72 modheads = repo.pull(other, heads=revs) |
71 if modheads == 0: | 73 if modheads == 0: |
72 return 0 | 74 return 0 |
73 if modheads == 1: | |
74 return hg.clean(repo, repo.changelog.tip()) | |
75 | 75 |
76 newheads = repo.heads(parent) | 76 # Is this a simple fast-forward along the current branch? |
77 newchildren = [n for n in repo.heads(parent) if n != parent] | 77 newheads = repo.branchheads(branch) |
78 newchildren = repo.changelog.nodesbetween([parent], newheads)[2] | |
79 if len(newheads) == 1: | |
80 if newchildren[0] != parent: | |
81 return hg.clean(repo, newchildren[0]) | |
82 else: | |
83 return | |
84 | |
85 # Are there more than one additional branch heads? | |
86 newchildren = [n for n in newchildren if n != parent] | |
78 newparent = parent | 87 newparent = parent |
79 if newchildren: | 88 if newchildren: |
80 newparent = newchildren[0] | 89 newparent = newchildren[0] |
81 hg.clean(repo, newparent) | 90 hg.clean(repo, newparent) |
82 | 91 newheads = [n for n in newheads if n != newparent] |
83 newheads = [n for n in repo.heads() if n != newparent] | |
84 if len(newheads) > 1: | 92 if len(newheads) > 1: |
85 ui.status(_('not merging with %d other new heads ' | 93 ui.status(_('not merging with %d other new branch heads ' |
86 '(use "hg heads" and "hg merge" to merge them)') % | 94 '(use "hg heads ." and "hg merge" to merge them)\n') % |
87 (len(newheads) - 1)) | 95 (len(newheads) - 1)) |
88 return | 96 return |
97 | |
98 # Otherwise, let's merge. | |
89 err = False | 99 err = False |
90 | |
91 if newheads: | 100 if newheads: |
92 # By default, we consider the repository we're pulling | 101 # By default, we consider the repository we're pulling |
93 # *from* as authoritative, so we merge our changes into | 102 # *from* as authoritative, so we merge our changes into |
94 # theirs. | 103 # theirs. |
95 if opts['switch_parent']: | 104 if opts['switch_parent']: |