##// END OF EJS Templates
fetch: fix and document exit codes (issue2356)
Matt Mackall -
r12711:b885f28f default
parent child Browse files
Show More
@@ -1,148 +1,152
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 of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 '''pull, update and merge in one command'''
9 9
10 10 from mercurial.i18n import _
11 11 from mercurial.node import nullid, short
12 12 from mercurial import commands, cmdutil, hg, util, url, error
13 13 from mercurial.lock import release
14 14
15 15 def fetch(ui, repo, source='default', **opts):
16 16 '''pull changes from a remote repository, merge new changes if needed.
17 17
18 18 This finds all changes from the repository at the specified path
19 19 or URL and adds them to the local repository.
20 20
21 21 If the pulled changes add a new branch head, the head is
22 22 automatically merged, and the result of the merge is committed.
23 23 Otherwise, the working directory is updated to include the new
24 24 changes.
25 25
26 26 When a merge occurs, the newly pulled changes are assumed to be
27 27 "authoritative". The head of the new changes is used as the first
28 28 parent, with local changes as the second. To switch the merge
29 29 order, use --switch-parent.
30 30
31 31 See :hg:`help dates` for a list of formats valid for -d/--date.
32
33 Returns 0 on success.
32 34 '''
33 35
34 36 date = opts.get('date')
35 37 if date:
36 38 opts['date'] = util.parsedate(date)
37 39
38 40 parent, p2 = repo.dirstate.parents()
39 41 branch = repo.dirstate.branch()
40 42 branchnode = repo.branchtags().get(branch)
41 43 if parent != branchnode:
42 44 raise util.Abort(_('working dir not at branch tip '
43 45 '(use "hg update" to check out branch tip)'))
44 46
45 47 if p2 != nullid:
46 48 raise util.Abort(_('outstanding uncommitted merge'))
47 49
48 50 wlock = lock = None
49 51 try:
50 52 wlock = repo.wlock()
51 53 lock = repo.lock()
52 54 mod, add, rem, del_ = repo.status()[:4]
53 55
54 56 if mod or add or rem:
55 57 raise util.Abort(_('outstanding uncommitted changes'))
56 58 if del_:
57 59 raise util.Abort(_('working directory is missing some files'))
58 60 bheads = repo.branchheads(branch)
59 61 bheads = [head for head in bheads if len(repo[head].children()) == 0]
60 62 if len(bheads) > 1:
61 63 raise util.Abort(_('multiple heads in this branch '
62 64 '(use "hg heads ." and "hg merge" to merge)'))
63 65
64 66 other = hg.repository(hg.remoteui(repo, opts),
65 67 ui.expandpath(source))
66 68 ui.status(_('pulling from %s\n') %
67 69 url.hidepassword(ui.expandpath(source)))
68 70 revs = None
69 71 if opts['rev']:
70 72 try:
71 73 revs = [other.lookup(rev) for rev in opts['rev']]
72 74 except error.CapabilityError:
73 75 err = _("Other repository doesn't support revision lookup, "
74 76 "so a rev cannot be specified.")
75 77 raise util.Abort(err)
76 78
77 79 # Are there any changes at all?
78 80 modheads = repo.pull(other, heads=revs)
79 81 if modheads == 0:
80 82 return 0
81 83
82 84 # Is this a simple fast-forward along the current branch?
83 85 newheads = repo.branchheads(branch)
84 86 newchildren = repo.changelog.nodesbetween([parent], newheads)[2]
85 87 if len(newheads) == 1:
86 88 if newchildren[0] != parent:
87 89 return hg.clean(repo, newchildren[0])
88 90 else:
89 return
91 return 0
90 92
91 93 # Are there more than one additional branch heads?
92 94 newchildren = [n for n in newchildren if n != parent]
93 95 newparent = parent
94 96 if newchildren:
95 97 newparent = newchildren[0]
96 98 hg.clean(repo, newparent)
97 99 newheads = [n for n in newheads if n != newparent]
98 100 if len(newheads) > 1:
99 101 ui.status(_('not merging with %d other new branch heads '
100 102 '(use "hg heads ." and "hg merge" to merge them)\n') %
101 103 (len(newheads) - 1))
102 return
104 return 1
103 105
104 106 # Otherwise, let's merge.
105 107 err = False
106 108 if newheads:
107 109 # By default, we consider the repository we're pulling
108 110 # *from* as authoritative, so we merge our changes into
109 111 # theirs.
110 112 if opts['switch_parent']:
111 113 firstparent, secondparent = newparent, newheads[0]
112 114 else:
113 115 firstparent, secondparent = newheads[0], newparent
114 116 ui.status(_('updating to %d:%s\n') %
115 117 (repo.changelog.rev(firstparent),
116 118 short(firstparent)))
117 119 hg.clean(repo, firstparent)
118 120 ui.status(_('merging with %d:%s\n') %
119 121 (repo.changelog.rev(secondparent), short(secondparent)))
120 122 err = hg.merge(repo, secondparent, remind=False)
121 123
122 124 if not err:
123 125 # we don't translate commit messages
124 126 message = (cmdutil.logmessage(opts) or
125 127 ('Automated merge with %s' %
126 128 url.removeauth(other.url())))
127 129 editor = cmdutil.commiteditor
128 130 if opts.get('force_editor') or opts.get('edit'):
129 131 editor = cmdutil.commitforceeditor
130 132 n = repo.commit(message, opts['user'], opts['date'], editor=editor)
131 133 ui.status(_('new changeset %d:%s merges remote changes '
132 134 'with local\n') % (repo.changelog.rev(n),
133 135 short(n)))
134 136
137 return err
138
135 139 finally:
136 140 release(lock, wlock)
137 141
138 142 cmdtable = {
139 143 'fetch':
140 144 (fetch,
141 145 [('r', 'rev', [],
142 146 _('a specific revision you would like to pull'), _('REV')),
143 147 ('e', 'edit', None, _('edit commit message')),
144 148 ('', 'force-editor', None, _('edit commit message (DEPRECATED)')),
145 149 ('', 'switch-parent', None, _('switch parents when merging')),
146 150 ] + commands.commitopts + commands.commitopts2 + commands.remoteopts,
147 151 _('hg fetch [SOURCE]')),
148 152 }
@@ -1,417 +1,418
1 1 adjust to non-default HGPORT, e.g. with run-tests.py -j
2 2
3 3 $ echo "[extensions]" >> $HGRCPATH
4 4 $ echo "fetch=" >> $HGRCPATH
5 5
6 6 test fetch with default branches only
7 7
8 8 $ hg init a
9 9 $ echo a > a/a
10 10 $ hg --cwd a commit -d '1 0' -Ama
11 11 adding a
12 12 $ hg clone a b
13 13 updating to branch default
14 14 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
15 15 $ hg clone a c
16 16 updating to branch default
17 17 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
18 18 $ echo b > a/b
19 19 $ hg --cwd a commit -d '2 0' -Amb
20 20 adding b
21 21 $ hg --cwd a parents -q
22 22 1:97d72e5f12c7
23 23
24 24 should pull one change
25 25
26 26 $ hg --cwd b fetch ../a
27 27 pulling from ../a
28 28 searching for changes
29 29 adding changesets
30 30 adding manifests
31 31 adding file changes
32 32 added 1 changesets with 1 changes to 1 files
33 33 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
34 34 $ hg --cwd b parents -q
35 35 1:97d72e5f12c7
36 36 $ echo c > c/c
37 37 $ hg --cwd c commit -d '3 0' -Amc
38 38 adding c
39 39 $ hg clone c d
40 40 updating to branch default
41 41 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
42 42 $ hg clone c e
43 43 updating to branch default
44 44 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
45 45
46 46 We cannot use the default commit message if fetching from a local
47 47 repo, because the path of the repo will be included in the commit
48 48 message, making every commit appear different.
49 49 should merge c into a
50 50
51 51 $ hg --cwd c fetch -d '4 0' -m 'automated merge' ../a
52 52 pulling from ../a
53 53 searching for changes
54 54 adding changesets
55 55 adding manifests
56 56 adding file changes
57 57 added 1 changesets with 1 changes to 1 files (+1 heads)
58 58 updating to 2:97d72e5f12c7
59 59 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
60 60 merging with 1:5e056962225c
61 61 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
62 62 new changeset 3:cd3a41621cf0 merges remote changes with local
63 63 $ ls c
64 64 a
65 65 b
66 66 c
67 67 $ netstat -tnap 2>/dev/null | grep $HGPORT | grep LISTEN
68 68 [1]
69 69 $ hg --cwd a serve -a localhost -p $HGPORT -d --pid-file=hg.pid
70 70 $ cat a/hg.pid >> "$DAEMON_PIDS"
71 71
72 72 fetch over http, no auth
73 73
74 74 $ hg --cwd d fetch -d '5 0' http://localhost:$HGPORT/
75 75 pulling from http://localhost:$HGPORT/
76 76 searching for changes
77 77 adding changesets
78 78 adding manifests
79 79 adding file changes
80 80 added 1 changesets with 1 changes to 1 files (+1 heads)
81 81 updating to 2:97d72e5f12c7
82 82 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
83 83 merging with 1:5e056962225c
84 84 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
85 85 new changeset 3:* merges remote changes with local (glob)
86 86 $ hg --cwd d tip --template '{desc}\n'
87 87 Automated merge with http://localhost:$HGPORT/
88 88
89 89 fetch over http with auth (should be hidden in desc)
90 90
91 91 $ hg --cwd e fetch -d '5 0' http://user:password@localhost:$HGPORT/
92 92 pulling from http://user:***@localhost:$HGPORT/
93 93 searching for changes
94 94 adding changesets
95 95 adding manifests
96 96 adding file changes
97 97 added 1 changesets with 1 changes to 1 files (+1 heads)
98 98 updating to 2:97d72e5f12c7
99 99 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
100 100 merging with 1:5e056962225c
101 101 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
102 102 new changeset 3:* merges remote changes with local (glob)
103 103 $ hg --cwd e tip --template '{desc}\n'
104 104 Automated merge with http://localhost:$HGPORT/
105 105 $ hg clone a f
106 106 updating to branch default
107 107 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
108 108 $ hg clone a g
109 109 updating to branch default
110 110 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
111 111 $ echo f > f/f
112 112 $ hg --cwd f ci -d '6 0' -Amf
113 113 adding f
114 114 $ echo g > g/g
115 115 $ hg --cwd g ci -d '6 0' -Amg
116 116 adding g
117 117 $ hg clone -q f h
118 118 $ hg clone -q g i
119 119
120 120 should merge f into g
121 121
122 122 $ hg --cwd g fetch -d '7 0' --switch -m 'automated merge' ../f
123 123 pulling from ../f
124 124 searching for changes
125 125 adding changesets
126 126 adding manifests
127 127 adding file changes
128 128 added 1 changesets with 1 changes to 1 files (+1 heads)
129 129 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
130 130 merging with 3:cc6a3744834d
131 131 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
132 132 new changeset 4:55aa4f32ec59 merges remote changes with local
133 133 $ rm i/g
134 134
135 135 should abort, because i is modified
136 136
137 137 $ hg --cwd i fetch ../h
138 138 abort: working directory is missing some files
139 139 [255]
140 140
141 141 test fetch with named branches
142 142
143 143 $ hg init nbase
144 144 $ echo base > nbase/a
145 145 $ hg -R nbase ci -d '1 0' -Am base
146 146 adding a
147 147 $ hg -R nbase branch a
148 148 marked working directory as branch a
149 149 $ echo a > nbase/a
150 150 $ hg -R nbase ci -d '2 0' -m a
151 151 $ hg -R nbase up -C 0
152 152 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
153 153 $ hg -R nbase branch b
154 154 marked working directory as branch b
155 155 $ echo b > nbase/b
156 156 $ hg -R nbase ci -Ad '3 0' -m b
157 157 adding b
158 158 $ echo
159 159
160 160
161 161 pull in change on foreign branch
162 162
163 163 $ hg clone nbase n1
164 164 updating to branch default
165 165 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
166 166 $ hg clone nbase n2
167 167 updating to branch default
168 168 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
169 169 $ hg -R n1 up -C a
170 170 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
171 171 $ echo aa > n1/a
172 172 $ hg -R n1 ci -d '4 0' -m a1
173 173 $ hg -R n2 up -C b
174 174 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
175 175 $ hg -R n2 fetch -d '9 0' -m 'merge' n1
176 176 pulling from n1
177 177 searching for changes
178 178 adding changesets
179 179 adding manifests
180 180 adding file changes
181 181 added 1 changesets with 1 changes to 1 files
182 182
183 183 parent should be 2 (no automatic update)
184 184
185 185 $ hg -R n2 parents --template '{rev}\n'
186 186 2
187 187 $ rm -fr n1 n2
188 188 $ echo
189 189
190 190
191 191 pull in changes on both foreign and local branches
192 192
193 193 $ hg clone nbase n1
194 194 updating to branch default
195 195 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
196 196 $ hg clone nbase n2
197 197 updating to branch default
198 198 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
199 199 $ hg -R n1 up -C a
200 200 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
201 201 $ echo aa > n1/a
202 202 $ hg -R n1 ci -d '4 0' -m a1
203 203 $ hg -R n1 up -C b
204 204 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
205 205 $ echo bb > n1/b
206 206 $ hg -R n1 ci -d '5 0' -m b1
207 207 $ hg -R n2 up -C b
208 208 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
209 209 $ hg -R n2 fetch -d '9 0' -m 'merge' n1
210 210 pulling from n1
211 211 searching for changes
212 212 adding changesets
213 213 adding manifests
214 214 adding file changes
215 215 added 2 changesets with 2 changes to 2 files
216 216 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
217 217
218 218 parent should be 4 (fast forward)
219 219
220 220 $ hg -R n2 parents --template '{rev}\n'
221 221 4
222 222 $ rm -fr n1 n2
223 223 $ echo
224 224
225 225
226 226 pull changes on foreign (2 new heads) and local (1 new head) branches
227 227 with a local change
228 228
229 229 $ hg clone nbase n1
230 230 updating to branch default
231 231 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
232 232 $ hg clone nbase n2
233 233 updating to branch default
234 234 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
235 235 $ hg -R n1 up -C a
236 236 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
237 237 $ echo a1 > n1/a
238 238 $ hg -R n1 ci -d '4 0' -m a1
239 239 $ hg -R n1 up -C b
240 240 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
241 241 $ echo bb > n1/b
242 242 $ hg -R n1 ci -d '5 0' -m b1
243 243 $ hg -R n1 up -C 1
244 244 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
245 245 $ echo a2 > n1/a
246 246 $ hg -R n1 ci -d '6 0' -m a2
247 247 created new head
248 248 $ hg -R n2 up -C b
249 249 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
250 250 $ echo change >> n2/c
251 251 $ hg -R n2 ci -Ad '7 0' -m local
252 252 adding c
253 253 $ hg -R n2 fetch -d '9 0' -m 'merge' n1
254 254 pulling from n1
255 255 searching for changes
256 256 adding changesets
257 257 adding manifests
258 258 adding file changes
259 259 added 3 changesets with 3 changes to 2 files (+2 heads)
260 260 updating to 5:708c6cce3d26
261 261 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
262 262 merging with 3:d83427717b1f
263 263 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
264 264 new changeset 7:48f1a33f52af merges remote changes with local
265 265
266 266 parent should be 7 (new merge changeset)
267 267
268 268 $ hg -R n2 parents --template '{rev}\n'
269 269 7
270 270 $ rm -fr n1 n2
271 271
272 272 pull in changes on foreign (merge of local branch) and local (2 new
273 273 heads) with a local change
274 274
275 275 $ hg clone nbase n1
276 276 updating to branch default
277 277 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
278 278 $ hg clone nbase n2
279 279 updating to branch default
280 280 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
281 281 $ hg -R n1 up -C a
282 282 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
283 283 $ hg -R n1 merge b
284 284 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
285 285 (branch merge, don't forget to commit)
286 286 $ hg -R n1 ci -d '4 0' -m merge
287 287 $ hg -R n1 up -C 2
288 288 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
289 289 $ echo c > n1/a
290 290 $ hg -R n1 ci -d '5 0' -m c
291 291 $ hg -R n1 up -C 2
292 292 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
293 293 $ echo cc > n1/a
294 294 $ hg -R n1 ci -d '6 0' -m cc
295 295 created new head
296 296 $ hg -R n2 up -C b
297 297 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
298 298 $ echo change >> n2/b
299 299 $ hg -R n2 ci -Ad '7 0' -m local
300 300 $ hg -R n2 fetch -d '9 0' -m 'merge' n1
301 301 pulling from n1
302 302 searching for changes
303 303 adding changesets
304 304 adding manifests
305 305 adding file changes
306 306 added 3 changesets with 2 changes to 1 files (+2 heads)
307 307 not merging with 1 other new branch heads (use "hg heads ." and "hg merge" to merge them)
308 [1]
308 309
309 310 parent should be 3 (fetch did not merge anything)
310 311
311 312 $ hg -R n2 parents --template '{rev}\n'
312 313 3
313 314 $ rm -fr n1 n2
314 315
315 316 pull in change on different branch than dirstate
316 317
317 318 $ hg init n1
318 319 $ echo a > n1/a
319 320 $ hg -R n1 ci -Am initial
320 321 adding a
321 322 $ hg clone n1 n2
322 323 updating to branch default
323 324 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
324 325 $ echo b > n1/a
325 326 $ hg -R n1 ci -m next
326 327 $ hg -R n2 branch topic
327 328 marked working directory as branch topic
328 329 $ hg -R n2 fetch -d '0 0' -m merge n1
329 330 abort: working dir not at branch tip (use "hg update" to check out branch tip)
330 331 [255]
331 332
332 333 parent should be 0 (fetch did not update or merge anything)
333 334
334 335 $ hg -R n2 parents --template '{rev}\n'
335 336 0
336 337 $ rm -fr n1 n2
337 338
338 339 test fetch with inactive branches
339 340
340 341 $ hg init ib1
341 342 $ echo a > ib1/a
342 343 $ hg --cwd ib1 ci -Am base
343 344 adding a
344 345 $ hg --cwd ib1 branch second
345 346 marked working directory as branch second
346 347 $ echo b > ib1/b
347 348 $ hg --cwd ib1 ci -Am onsecond
348 349 adding b
349 350 $ hg --cwd ib1 branch -f default
350 351 marked working directory as branch default
351 352 $ echo c > ib1/c
352 353 $ hg --cwd ib1 ci -Am newdefault
353 354 adding c
354 355 created new head
355 356 $ hg clone ib1 ib2
356 357 updating to branch default
357 358 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
358 359
359 360 fetch should succeed
360 361
361 362 $ hg --cwd ib2 fetch ../ib1
362 363 pulling from ../ib1
363 364 searching for changes
364 365 no changes found
365 366 $ rm -fr ib1 ib2
366 367
367 368 test issue1726
368 369
369 370 $ hg init i1726r1
370 371 $ echo a > i1726r1/a
371 372 $ hg --cwd i1726r1 ci -Am base
372 373 adding a
373 374 $ hg clone i1726r1 i1726r2
374 375 updating to branch default
375 376 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
376 377 $ echo b > i1726r1/a
377 378 $ hg --cwd i1726r1 ci -m second
378 379 $ echo c > i1726r2/a
379 380 $ hg --cwd i1726r2 ci -m third
380 381 $ HGMERGE=true hg --cwd i1726r2 fetch ../i1726r1
381 382 pulling from ../i1726r1
382 383 searching for changes
383 384 adding changesets
384 385 adding manifests
385 386 adding file changes
386 387 added 1 changesets with 1 changes to 1 files (+1 heads)
387 388 updating to 2:7837755a2789
388 389 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
389 390 merging with 1:d1f0c6c48ebd
390 391 merging a
391 392 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
392 393 new changeset 3:* merges remote changes with local (glob)
393 394 $ hg --cwd i1726r2 heads default --template '{rev}\n'
394 395 3
395 396 $ echo
396 397
397 398
398 399 test issue2047
399 400
400 401 $ hg -q init i2047a
401 402 $ cd i2047a
402 403 $ echo a > a
403 404 $ hg -q ci -Am a
404 405 $ hg -q branch stable
405 406 $ echo b > b
406 407 $ hg -q ci -Am b
407 408 $ cd ..
408 409 $ hg -q clone -r 0 i2047a i2047b
409 410 $ cd i2047b
410 411 $ hg fetch ../i2047a
411 412 pulling from ../i2047a
412 413 searching for changes
413 414 adding changesets
414 415 adding manifests
415 416 adding file changes
416 417 added 1 changesets with 1 changes to 1 files
417 418 $ "$TESTDIR/killdaemons.py"
General Comments 0
You need to be logged in to leave comments. Login now