fetch.py
152 lines
| 5.8 KiB
| text/x-python
|
PythonLexer
/ hgext / fetch.py
Vadim Gelfer
|
r2800 | # fetch.py - pull and merge remote changes | ||
# | ||||
# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com> | ||||
# | ||||
Martin Geisler
|
r8225 | # This software may be used and distributed according to the terms of the | ||
Matt Mackall
|
r10263 | # GNU General Public License version 2 or any later version. | ||
Martin Geisler
|
r8228 | |||
Cédric Duval
|
r8894 | '''pull, update and merge in one command''' | ||
Vadim Gelfer
|
r2800 | |||
Matt Mackall
|
r3891 | from mercurial.i18n import _ | ||
Joel Rosdahl
|
r6211 | from mercurial.node import nullid, short | ||
Benoit Boissinot
|
r8532 | from mercurial import commands, cmdutil, hg, util, url, error | ||
Ronny Pfannschmidt
|
r8112 | from mercurial.lock import release | ||
Vadim Gelfer
|
r2800 | |||
def fetch(ui, repo, source='default', **opts): | ||||
Martin Geisler
|
r7598 | '''pull changes from a remote repository, merge new changes if needed. | ||
Vadim Gelfer
|
r2800 | |||
Martin Geisler
|
r9258 | This finds all changes from the repository at the specified path | ||
or URL and adds them to the local repository. | ||||
Vadim Gelfer
|
r2800 | |||
Martin Geisler
|
r9258 | 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. | ||||
Bryan O'Sullivan
|
r6206 | |||
When a merge occurs, the newly pulled changes are assumed to be | ||||
Martin Geisler
|
r9258 | "authoritative". The head of the new changes is used as the first | ||
parent, with local changes as the second. To switch the merge | ||||
order, use --switch-parent. | ||||
Thomas Arendsen Hein
|
r6163 | |||
Martin Geisler
|
r10973 | See :hg:`help dates` for a list of formats valid for -d/--date. | ||
Matt Mackall
|
r12711 | |||
Returns 0 on success. | ||||
Thomas Arendsen Hein
|
r6163 | ''' | ||
Vadim Gelfer
|
r2800 | |||
Dirkjan Ochtman
|
r6941 | date = opts.get('date') | ||
if date: | ||||
opts['date'] = util.parsedate(date) | ||||
parent, p2 = repo.dirstate.parents() | ||||
Sune Foldager
|
r7049 | branch = repo.dirstate.branch() | ||
branchnode = repo.branchtags().get(branch) | ||||
if parent != branchnode: | ||||
Sune Foldager
|
r7007 | raise util.Abort(_('working dir not at branch tip ' | ||
'(use "hg update" to check out branch tip)')) | ||||
Dirkjan Ochtman
|
r6941 | |||
if p2 != nullid: | ||||
raise util.Abort(_('outstanding uncommitted merge')) | ||||
wlock = lock = None | ||||
try: | ||||
wlock = repo.wlock() | ||||
lock = repo.lock() | ||||
mod, add, rem, del_ = repo.status()[:4] | ||||
if mod or add or rem: | ||||
raise util.Abort(_('outstanding uncommitted changes')) | ||||
if del_: | ||||
raise util.Abort(_('working directory is missing some files')) | ||||
Benjamin Pollack
|
r7854 | bheads = repo.branchheads(branch) | ||
bheads = [head for head in bheads if len(repo[head].children()) == 0] | ||||
if len(bheads) > 1: | ||||
Sune Foldager
|
r7007 | raise util.Abort(_('multiple heads in this branch ' | ||
'(use "hg heads ." and "hg merge" to merge)')) | ||||
Dirkjan Ochtman
|
r6941 | |||
Matt Mackall
|
r11273 | other = hg.repository(hg.remoteui(repo, opts), | ||
Matt Mackall
|
r8188 | ui.expandpath(source)) | ||
Dirkjan Ochtman
|
r6941 | ui.status(_('pulling from %s\n') % | ||
Benoit Boissinot
|
r7270 | url.hidepassword(ui.expandpath(source))) | ||
Dirkjan Ochtman
|
r6941 | revs = None | ||
if opts['rev']: | ||||
Benoit Boissinot
|
r8532 | try: | ||
Dirkjan Ochtman
|
r6941 | revs = [other.lookup(rev) for rev in opts['rev']] | ||
Benoit Boissinot
|
r8532 | except error.CapabilityError: | ||
err = _("Other repository doesn't support revision lookup, " | ||||
"so a rev cannot be specified.") | ||||
raise util.Abort(err) | ||||
Dirkjan Ochtman
|
r6941 | |||
Sune Foldager
|
r7007 | # Are there any changes at all? | ||
Dirkjan Ochtman
|
r6941 | modheads = repo.pull(other, heads=revs) | ||
Vadim Gelfer
|
r2800 | if modheads == 0: | ||
return 0 | ||||
Dirkjan Ochtman
|
r6941 | |||
Sune Foldager
|
r7007 | # 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: | ||||
Matt Mackall
|
r12711 | return 0 | ||
Sune Foldager
|
r7007 | |||
# Are there more than one additional branch heads? | ||||
newchildren = [n for n in newchildren if n != parent] | ||||
Vadim Gelfer
|
r2800 | newparent = parent | ||
if newchildren: | ||||
newparent = newchildren[0] | ||||
Matt Mackall
|
r4917 | hg.clean(repo, newparent) | ||
Sune Foldager
|
r7007 | newheads = [n for n in newheads if n != newparent] | ||
Bryan O'Sullivan
|
r6206 | if len(newheads) > 1: | ||
Sune Foldager
|
r7007 | ui.status(_('not merging with %d other new branch heads ' | ||
'(use "hg heads ." and "hg merge" to merge them)\n') % | ||||
Vadim Gelfer
|
r2800 | (len(newheads) - 1)) | ||
Matt Mackall
|
r12711 | return 1 | ||
Sune Foldager
|
r7007 | |||
# Otherwise, let's merge. | ||||
Bryan O'Sullivan
|
r6206 | err = False | ||
if newheads: | ||||
# By default, we consider the repository we're pulling | ||||
# *from* as authoritative, so we merge our changes into | ||||
# theirs. | ||||
if opts['switch_parent']: | ||||
firstparent, secondparent = newparent, newheads[0] | ||||
else: | ||||
firstparent, secondparent = newheads[0], newparent | ||||
ui.status(_('updating to %d:%s\n') % | ||||
(repo.changelog.rev(firstparent), | ||||
short(firstparent))) | ||||
hg.clean(repo, firstparent) | ||||
ui.status(_('merging with %d:%s\n') % | ||||
(repo.changelog.rev(secondparent), short(secondparent))) | ||||
err = hg.merge(repo, secondparent, remind=False) | ||||
Dirkjan Ochtman
|
r6941 | |||
Vadim Gelfer
|
r2800 | if not err: | ||
Martin Geisler
|
r9183 | # we don't translate commit messages | ||
Matt Mackall
|
r4549 | message = (cmdutil.logmessage(opts) or | ||
Martin Geisler
|
r9183 | ('Automated merge with %s' % | ||
Benoit Boissinot
|
r7270 | url.removeauth(other.url()))) | ||
Matt Mackall
|
r8407 | editor = cmdutil.commiteditor | ||
if opts.get('force_editor') or opts.get('edit'): | ||||
editor = cmdutil.commitforceeditor | ||||
Matt Mackall
|
r9185 | n = repo.commit(message, opts['user'], opts['date'], editor=editor) | ||
Vadim Gelfer
|
r2800 | ui.status(_('new changeset %d:%s merges remote changes ' | ||
'with local\n') % (repo.changelog.rev(n), | ||||
short(n))) | ||||
Bryan O'Sullivan
|
r6206 | |||
Matt Mackall
|
r12711 | return err | ||
Vadim Gelfer
|
r2825 | finally: | ||
Ronny Pfannschmidt
|
r8112 | release(lock, wlock) | ||
Vadim Gelfer
|
r2800 | |||
cmdtable = { | ||||
'fetch': | ||||
Thomas Arendsen Hein
|
r4730 | (fetch, | ||
FUJIWARA Katsunori
|
r11321 | [('r', 'rev', [], | ||
_('a specific revision you would like to pull'), _('REV')), | ||||
Bryan O'Sullivan
|
r6225 | ('e', 'edit', None, _('edit commit message')), | ||
('', 'force-editor', None, _('edit commit message (DEPRECATED)')), | ||||
Bryan O'Sullivan
|
r6206 | ('', 'switch-parent', None, _('switch parents when merging')), | ||
Benoit Boissinot
|
r5147 | ] + commands.commitopts + commands.commitopts2 + commands.remoteopts, | ||
Thomas Arendsen Hein
|
r4730 | _('hg fetch [SOURCE]')), | ||
} | ||||