##// END OF EJS Templates
fetch: added support for named branches...
Sune Foldager -
r7007:a6b74fbb default
parent child Browse files
Show More
@@ -1,132 +1,141
1 1 # fetch.py - pull and merge remote changes
2 2 #
3 3 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 4 #
5 5 # This software may be used and distributed according to the terms
6 6 # of the GNU General Public License, incorporated herein by reference.
7 7 '''pulling, updating and merging in one command'''
8 8
9 9 from mercurial.i18n import _
10 10 from mercurial.node import nullid, short
11 11 from mercurial import commands, cmdutil, hg, util
12 12
13 13 def fetch(ui, repo, source='default', **opts):
14 14 '''Pull changes from a remote repository, merge new changes if needed.
15 15
16 16 This finds all changes from the repository at the specified path
17 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 20 merged, and the result of the merge is committed. Otherwise, the
21 21 working directory is updated to include the new changes.
22 22
23 23 When a merge occurs, the newly pulled changes are assumed to be
24 24 "authoritative". The head of the new changes is used as the first
25 25 parent, with local changes as the second. To switch the merge
26 26 order, use --switch-parent.
27 27
28 28 See 'hg help dates' for a list of formats valid for -d/--date.
29 29 '''
30 30
31 31 date = opts.get('date')
32 32 if date:
33 33 opts['date'] = util.parsedate(date)
34 34
35 35 parent, p2 = repo.dirstate.parents()
36 if parent != repo.changelog.tip():
37 raise util.Abort(_('working dir not at tip '
38 '(use "hg update" to check out tip)'))
36 branch = repo[parent].branch()
37 if parent != repo[branch].node():
38 raise util.Abort(_('working dir not at branch tip '
39 '(use "hg update" to check out branch tip)'))
39 40
40 41 if p2 != nullid:
41 42 raise util.Abort(_('outstanding uncommitted merge'))
42 43
43 44 wlock = lock = None
44 45 try:
45 46 wlock = repo.wlock()
46 47 lock = repo.lock()
47 48 mod, add, rem, del_ = repo.status()[:4]
48 49
49 50 if mod or add or rem:
50 51 raise util.Abort(_('outstanding uncommitted changes'))
51 52 if del_:
52 53 raise util.Abort(_('working directory is missing some files'))
53 if len(repo.heads()) > 1:
54 raise util.Abort(_('multiple heads in this repository '
55 '(use "hg heads" and "hg merge" to merge)'))
54 if len(repo.branchheads(branch)) > 1:
55 raise util.Abort(_('multiple heads in this branch '
56 '(use "hg heads ." and "hg merge" to merge)'))
56 57
57 58 cmdutil.setremoteconfig(ui, opts)
58 59
59 60 other = hg.repository(ui, ui.expandpath(source))
60 61 ui.status(_('pulling from %s\n') %
61 62 util.hidepassword(ui.expandpath(source)))
62 63 revs = None
63 64 if opts['rev']:
64 65 if not other.local():
65 66 raise util.Abort(_("fetch -r doesn't work for remote "
66 67 "repositories yet"))
67 68 else:
68 69 revs = [other.lookup(rev) for rev in opts['rev']]
69 70
71 # Are there any changes at all?
70 72 modheads = repo.pull(other, heads=revs)
71 73 if modheads == 0:
72 74 return 0
73 if modheads == 1:
74 return hg.clean(repo, repo.changelog.tip())
75 75
76 newheads = repo.heads(parent)
77 newchildren = [n for n in repo.heads(parent) if n != parent]
76 # Is this a simple fast-forward along the current branch?
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 87 newparent = parent
79 88 if newchildren:
80 89 newparent = newchildren[0]
81 90 hg.clean(repo, newparent)
82
83 newheads = [n for n in repo.heads() if n != newparent]
91 newheads = [n for n in newheads if n != newparent]
84 92 if len(newheads) > 1:
85 ui.status(_('not merging with %d other new heads '
86 '(use "hg heads" and "hg merge" to merge them)') %
93 ui.status(_('not merging with %d other new branch heads '
94 '(use "hg heads ." and "hg merge" to merge them)\n') %
87 95 (len(newheads) - 1))
88 96 return
97
98 # Otherwise, let's merge.
89 99 err = False
90
91 100 if newheads:
92 101 # By default, we consider the repository we're pulling
93 102 # *from* as authoritative, so we merge our changes into
94 103 # theirs.
95 104 if opts['switch_parent']:
96 105 firstparent, secondparent = newparent, newheads[0]
97 106 else:
98 107 firstparent, secondparent = newheads[0], newparent
99 108 ui.status(_('updating to %d:%s\n') %
100 109 (repo.changelog.rev(firstparent),
101 110 short(firstparent)))
102 111 hg.clean(repo, firstparent)
103 112 ui.status(_('merging with %d:%s\n') %
104 113 (repo.changelog.rev(secondparent), short(secondparent)))
105 114 err = hg.merge(repo, secondparent, remind=False)
106 115
107 116 if not err:
108 117 mod, add, rem = repo.status()[:3]
109 118 message = (cmdutil.logmessage(opts) or
110 119 (_('Automated merge with %s') %
111 120 util.removeauth(other.url())))
112 121 force_editor = opts.get('force_editor') or opts.get('edit')
113 122 n = repo.commit(mod + add + rem, message,
114 123 opts['user'], opts['date'], force=True,
115 124 force_editor=force_editor)
116 125 ui.status(_('new changeset %d:%s merges remote changes '
117 126 'with local\n') % (repo.changelog.rev(n),
118 127 short(n)))
119 128
120 129 finally:
121 130 del lock, wlock
122 131
123 132 cmdtable = {
124 133 'fetch':
125 134 (fetch,
126 135 [('r', 'rev', [], _('a specific revision you would like to pull')),
127 136 ('e', 'edit', None, _('edit commit message')),
128 137 ('', 'force-editor', None, _('edit commit message (DEPRECATED)')),
129 138 ('', 'switch-parent', None, _('switch parents when merging')),
130 139 ] + commands.commitopts + commands.commitopts2 + commands.remoteopts,
131 140 _('hg fetch [SOURCE]')),
132 141 }
@@ -1,69 +1,159
1 1 #!/bin/sh
2 2
3 3 # adjust to non-default HGPORT, e.g. with run-tests.py -j
4 4 hideport() { sed "s/localhost:$HGPORT/localhost:20059/"; }
5 5 hidehash() { sed "s/changeset 3:............ merges/changeset 3:... merges/"; }
6 6
7 7 echo "[extensions]" >> $HGRCPATH
8 8 echo "fetch=" >> $HGRCPATH
9 9
10 echo % test fetch with default branches only
10 11 hg init a
11 12 echo a > a/a
12 13 hg --cwd a commit -d '1 0' -Ama
13 14
14 15 hg clone a b
15 16 hg clone a c
16 17
17 18 echo b > a/b
18 19 hg --cwd a commit -d '2 0' -Amb
19 20 hg --cwd a parents -q
20 21
21 22 echo % should pull one change
22 23 hg --cwd b fetch ../a
23 24 hg --cwd b parents -q
24 25
25 26 echo c > c/c
26 27 hg --cwd c commit -d '3 0' -Amc
27 28
28 29 hg clone c d
29 30 hg clone c e
30 31
31 32 # We cannot use the default commit message if fetching from a local
32 33 # repo, because the path of the repo will be included in the commit
33 34 # message, making every commit appear different.
34 35
35 36 echo % should merge c into a
36 37 hg --cwd c fetch -d '4 0' -m 'automated merge' ../a
37 38 ls c
38 39
39 40 hg --cwd a serve -a localhost -p $HGPORT -d --pid-file=hg.pid
40 41 cat a/hg.pid >> "$DAEMON_PIDS"
41 42
42 43 echo '% fetch over http, no auth'
43 44 hg --cwd d fetch -d '5 0' http://localhost:$HGPORT/ | hideport | hidehash
44 45 hg --cwd d tip --template '{desc}\n' | hideport
45 46
46 47 echo '% fetch over http with auth (should be hidden in desc)'
47 48 hg --cwd e fetch -d '5 0' http://user:password@localhost:$HGPORT/ | hideport | hidehash
48 49 hg --cwd e tip --template '{desc}\n' | hideport
49 50
50 51 hg clone a f
51 52 hg clone a g
52 53
53 54 echo f > f/f
54 55 hg --cwd f ci -d '6 0' -Amf
55 56
56 57 echo g > g/g
57 58 hg --cwd g ci -d '6 0' -Amg
58 59
59 60 hg clone -q f h
60 61 hg clone -q g i
61 62
62 63 echo % should merge f into g
63 64 hg --cwd g fetch -d '7 0' --switch -m 'automated merge' ../f
64 65
65 66 rm i/g
66 67 echo % should abort, because i is modified
67 68 hg --cwd i fetch ../h
68 69
70
71 echo % test fetch with named branches
72 hg init nbase
73 echo base > nbase/a
74 hg -R nbase ci -d '1 0' -Am base
75 hg -R nbase branch a
76 echo a > nbase/a
77 hg -R nbase ci -d '2 0' -m a
78 hg -R nbase up -C 0
79 hg -R nbase branch b
80 echo b > nbase/b
81 hg -R nbase ci -Ad '3 0' -m b
82
83 echo
84 echo % pull in change on foreign branch
85 hg clone nbase n1
86 hg clone nbase n2
87 hg -R n1 up -C a
88 echo aa > n1/a
89 hg -R n1 ci -d '4 0' -m a1
90
91 hg -R n2 up -C b
92 hg -R n2 fetch -d '9 0' -m 'merge' n1
93 echo '% parent should be 2 (no automatic update)'
94 hg -R n2 parents --template '{rev}\n'
95 rm -fr n1 n2
96
97 echo
98 echo % pull in changes on both foreign and local branches
99 hg clone nbase n1
100 hg clone nbase n2
101 hg -R n1 up -C a
102 echo aa > n1/a
103 hg -R n1 ci -d '4 0' -m a1
104 hg -R n1 up -C b
105 echo bb > n1/b
106 hg -R n1 ci -d '5 0' -m b1
107
108 hg -R n2 up -C b
109 hg -R n2 fetch -d '9 0' -m 'merge' n1
110 echo '% parent should be 4 (fast forward)'
111 hg -R n2 parents --template '{rev}\n'
112 rm -fr n1 n2
113
114 echo
115 echo '% pull changes on foreign (2 new heads) and local (1 new head) branches'
116 echo % with a local change
117 hg clone nbase n1
118 hg clone nbase n2
119 hg -R n1 up -C a
120 echo a1 > n1/a
121 hg -R n1 ci -d '4 0' -m a1
122 hg -R n1 up -C b
123 echo bb > n1/b
124 hg -R n1 ci -d '5 0' -m b1
125 hg -R n1 up -C 1
126 echo a2 > n1/a
127 hg -R n1 ci -d '6 0' -m a2
128
129 hg -R n2 up -C b
130 echo change >> n2/c
131 hg -R n2 ci -Ad '7 0' -m local
132 hg -R n2 fetch -d '9 0' -m 'merge' n1
133 echo '% parent should be 7 (new merge changeset)'
134 hg -R n2 parents --template '{rev}\n'
135 rm -fr n1 n2
136
137 echo '% pull in changes on foreign (merge of local branch) and local (2 new'
138 echo '% heads) with a local change'
139 hg clone nbase n1
140 hg clone nbase n2
141 hg -R n1 up -C a
142 hg -R n1 merge b
143 hg -R n1 ci -d '4 0' -m merge
144 hg -R n1 up -C 2
145 echo c > n1/a
146 hg -R n1 ci -d '5 0' -m c
147 hg -R n1 up -C 2
148 echo cc > n1/a
149 hg -R n1 ci -d '6 0' -m cc
150
151 hg -R n2 up -C b
152 echo change >> n2/b
153 hg -R n2 ci -Ad '7 0' -m local
154 hg -R n2 fetch -d '9 0' -m 'merge' n1
155 echo '% parent should be 3 (fetch did not merge anything)'
156 hg -R n2 parents --template '{rev}\n'
157 rm -fr n1 n2
158
69 159 true
@@ -1,81 +1,172
1 % test fetch with default branches only
1 2 adding a
2 3 updating working directory
3 4 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
4 5 updating working directory
5 6 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
6 7 adding b
7 8 1:97d72e5f12c7
8 9 % should pull one change
9 10 pulling from ../a
10 11 searching for changes
11 12 adding changesets
12 13 adding manifests
13 14 adding file changes
14 15 added 1 changesets with 1 changes to 1 files
15 16 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
16 17 1:97d72e5f12c7
17 18 adding c
18 19 updating working directory
19 20 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
20 21 updating working directory
21 22 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
22 23 % should merge c into a
23 24 pulling from ../a
24 25 searching for changes
25 26 adding changesets
26 27 adding manifests
27 28 adding file changes
28 29 added 1 changesets with 1 changes to 1 files (+1 heads)
29 30 updating to 2:97d72e5f12c7
30 31 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
31 32 merging with 1:5e056962225c
32 33 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
33 34 new changeset 3:cd3a41621cf0 merges remote changes with local
34 35 a
35 36 b
36 37 c
37 38 % fetch over http, no auth
38 39 pulling from http://localhost:20059/
39 40 searching for changes
40 41 adding changesets
41 42 adding manifests
42 43 adding file changes
43 44 added 1 changesets with 1 changes to 1 files (+1 heads)
44 45 updating to 2:97d72e5f12c7
45 46 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
46 47 merging with 1:5e056962225c
47 48 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
48 49 new changeset 3:... merges remote changes with local
49 50 Automated merge with http://localhost:20059/
50 51 % fetch over http with auth (should be hidden in desc)
51 52 pulling from http://user:***@localhost:20059/
52 53 searching for changes
53 54 adding changesets
54 55 adding manifests
55 56 adding file changes
56 57 added 1 changesets with 1 changes to 1 files (+1 heads)
57 58 updating to 2:97d72e5f12c7
58 59 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
59 60 merging with 1:5e056962225c
60 61 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
61 62 new changeset 3:... merges remote changes with local
62 63 Automated merge with http://localhost:20059/
63 64 updating working directory
64 65 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
65 66 updating working directory
66 67 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
67 68 adding f
68 69 adding g
69 70 % should merge f into g
70 71 pulling from ../f
71 72 searching for changes
72 73 adding changesets
73 74 adding manifests
74 75 adding file changes
75 76 added 1 changesets with 1 changes to 1 files (+1 heads)
76 77 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
77 78 merging with 3:cc6a3744834d
78 79 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
79 80 new changeset 4:55aa4f32ec59 merges remote changes with local
80 81 % should abort, because i is modified
81 82 abort: working directory is missing some files
83 % test fetch with named branches
84 adding a
85 marked working directory as branch a
86 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
87 marked working directory as branch b
88 adding b
89 created new head
90
91 % pull in change on foreign branch
92 updating working directory
93 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
94 updating working directory
95 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
96 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
97 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
98 pulling from n1
99 searching for changes
100 adding changesets
101 adding manifests
102 adding file changes
103 added 1 changesets with 1 changes to 1 files
104 % parent should be 2 (no automatic update)
105 2
106
107 % pull in changes on both foreign and local branches
108 updating working directory
109 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
110 updating working directory
111 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
112 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
113 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
114 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
115 pulling from n1
116 searching for changes
117 adding changesets
118 adding manifests
119 adding file changes
120 added 2 changesets with 2 changes to 2 files
121 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
122 % parent should be 4 (fast forward)
123 4
124
125 % pull changes on foreign (2 new heads) and local (1 new head) branches
126 % with a local change
127 updating working directory
128 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
129 updating working directory
130 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
131 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
132 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
133 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
134 created new head
135 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
136 adding c
137 pulling from n1
138 searching for changes
139 adding changesets
140 adding manifests
141 adding file changes
142 added 3 changesets with 3 changes to 2 files (+2 heads)
143 updating to 5:708c6cce3d26
144 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
145 merging with 3:d83427717b1f
146 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
147 new changeset 7:48f1a33f52af merges remote changes with local
148 % parent should be 7 (new merge changeset)
149 7
150 % pull in changes on foreign (merge of local branch) and local (2 new
151 % heads) with a local change
152 updating working directory
153 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
154 updating working directory
155 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
156 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
157 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
158 (branch merge, don't forget to commit)
159 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
160 created new head
161 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
162 created new head
163 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
164 pulling from n1
165 searching for changes
166 adding changesets
167 adding manifests
168 adding file changes
169 added 3 changesets with 2 changes to 1 files (+2 heads)
170 not merging with 1 other new branch heads (use "hg heads ." and "hg merge" to merge them)
171 % parent should be 3 (fetch did not merge anything)
172 3
General Comments 0
You need to be logged in to leave comments. Login now