diff --git a/hgext/shelve.py b/hgext/shelve.py --- a/hgext/shelve.py +++ b/hgext/shelve.py @@ -432,6 +432,17 @@ cmdutil.exportfile(repo, [node], fp, opts=mdiff.diffopts(git=True), match=match) +def _storeunresolvedmerge(repo, name): + """Move the usual mergestate information from `.hg/merge` to + `.hg/merge-unresolved/`. + + This will clear the mergestate and also stores the mergestate + information for later restoration. + """ + if not repo.vfs.exists('merge-unresolved'): + repo.vfs.mkdir('merge-unresolved') + repo.vfs.rename('merge', 'merge-unresolved/%s' % name) + def _includeunknownfiles(repo, pats, opts, extra): s = repo.status(match=scmutil.match(repo[None], pats, opts), unknown=True) @@ -439,6 +450,10 @@ extra['shelve_unknown'] = '\0'.join(s.unknown) repo[None].add(s.unknown) +def _isunresolvedshelve(repo, sname): + """Checks whether the given shelve is unresolved or not""" + return repo.vfs.exists('merge-unresolved/%s' % sname) + def _finishshelve(repo, tr): if phases.supportinternal(repo): tr.close() @@ -454,10 +469,19 @@ def _docreatecmd(ui, repo, pats, opts): wctx = repo[None] parents = wctx.parents() - if len(parents) > 1: - raise error.Abort(_('cannot shelve while merging')) + unresolved = opts.get('unresolved') parent = parents[0] origbranch = wctx.branch() + ms = merge.mergestate.read(repo) + if unresolved: + if not ms.active(): + raise error.Abort(_('no active mergestate found')) + elif not list(ms.unresolved()): + raise error.Abort(_('no unresolved ' + 'files found in the mergestate')) + elif ms.active(): + raise error.Abort(_('mergestate found\n' + 'try with --unresolved to shelve conflicts')) if parent.node() != nodemod.nullid: desc = "changes to: %s" % parent.description().split('\n', 1)[0] @@ -482,6 +506,9 @@ name = getshelvename(repo, parent, opts) activebookmark = _backupactivebookmark(repo) extra = {'internal': 'shelve'} + if unresolved: + extra['unresolved-merge'] = True + _storeunresolvedmerge(repo, name) if includeunknown: _includeunknownfiles(repo, pats, opts, extra) @@ -577,6 +604,7 @@ """subcommand that displays the list of shelves""" pats = set(pats) width = 80 + namewidth = 16 if not ui.plain(): width = ui.termwidth() namelabel = 'shelve.newest' @@ -585,13 +613,16 @@ sname = util.split(name)[1] if pats and sname not in pats: continue + if _isunresolvedshelve(repo, sname): + sname += ' (unresolved)' + namewidth += 13 ui.write(sname, label=namelabel) namelabel = 'shelve.name' if ui.quiet: ui.write('\n') continue - ui.write(' ' * (16 - len(sname))) - used = 16 + ui.write(' ' * (namewidth - len(sname))) + used = namewidth date = dateutil.makedate(mtime) age = '(%s)' % templatefilters.age(date, abbrev=True) ui.write(age, label='shelve.age') @@ -1068,7 +1099,9 @@ _('interactive mode, only works while creating a shelve')), ('', 'stat', None, _('output diffstat-style summary of changes (provide the names of ' - 'the shelved changes as positional arguments)') + 'the shelved changes as positional arguments)')), + ('', 'unresolved', None, + _('unshelve mergestate with unresolved files') )] + cmdutil.walkopts, _('hg shelve [OPTION]... [FILE]...'), helpcategory=command.CATEGORY_WORKING_DIRECTORY) diff --git a/tests/test-shelve-unresolved.t b/tests/test-shelve-unresolved.t new file mode 100644 --- /dev/null +++ b/tests/test-shelve-unresolved.t @@ -0,0 +1,158 @@ +Test shelve with unresolved mergestate + + $ cat >> $HGRCPATH < [extensions] + > shelve = + > EOF + + $ hg init shelve-unresolved + $ cd shelve-unresolved + $ echo A >> file1 + $ echo A >> file2 + $ hg ci -Am A + adding file1 + adding file2 + $ echo foo >> bar + $ hg add bar + +-- should abort on absence of mergestate + $ hg shelve --unresolved + abort: no active mergestate found + [255] + + $ hg forget bar + $ echo B >> file1 + $ echo B >> file2 + $ hg ci -m B + $ hg up 0 + 2 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ echo C >> file1 + $ echo C >> file2 + $ hg ci -m C + created new head + $ hg merge + merging file1 + merging file2 + warning: conflicts while merging file1! (edit, then use 'hg resolve --mark') + warning: conflicts while merging file2! (edit, then use 'hg resolve --mark') + 0 files updated, 0 files merged, 0 files removed, 2 files unresolved + use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon + [1] + +-- let's partially solve the conflicts + $ cat > file1 < A + > B + > C + > EOF + $ hg resolve -m file1 + +-- mark file2 as resolved to check abort + $ hg resolve -m file2 + (no more unresolved files) + $ hg log -G + @ changeset: 2:69004294ad57 + | tag: tip + | parent: 0:c32ef6121744 + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: C + | + | @ changeset: 1:fd9a4049234b + |/ user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: B + | + o changeset: 0:c32ef6121744 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: A + + $ cat file1 + A + B + C + $ hg diff + diff -r 69004294ad57 file1 + --- a/file1 Thu Jan 01 00:00:00 1970 +0000 + +++ b/file1 Thu Jan 01 00:00:00 1970 +0000 + @@ -1,2 +1,3 @@ + A + +B + C + diff -r 69004294ad57 file2 + --- a/file2 Thu Jan 01 00:00:00 1970 +0000 + +++ b/file2 Thu Jan 01 00:00:00 1970 +0000 + @@ -1,2 +1,6 @@ + A + +<<<<<<< working copy: 69004294ad57 - test: C + C + +======= + +B + +>>>>>>> merge rev: fd9a4049234b - test: B + +-- should abort on absence of conflicts + $ hg shelve + abort: mergestate found + try with --unresolved to shelve conflicts + [255] + $ hg shelve --unresolved + abort: no unresolved files found in the mergestate + [255] + $ hg resolve -u file2 + $ hg resolve -l + R file1 + U file2 + +-- should suggest --unresolved on shelving with mergestate + $ hg shelve + abort: mergestate found + try with --unresolved to shelve conflicts + [255] + + $ hg shelve --unresolved + shelved as default + 2 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ cat file1 + A + C + $ hg log -G + @ changeset: 2:69004294ad57 + | tag: tip + | parent: 0:c32ef6121744 + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: C + | + | o changeset: 1:fd9a4049234b + |/ user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: B + | + o changeset: 0:c32ef6121744 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: A + + $ hg shelve --list + default (unresolved) (1s ago) changes to: C + $ hg shelve --patch + default (unresolved) (1s ago) changes to: C + + diff --git a/file1 b/file1 + --- a/file1 + +++ b/file1 + @@ -1,2 +1,3 @@ + A + +B + C + diff --git a/file2 b/file2 + --- a/file2 + +++ b/file2 + @@ -1,2 +1,6 @@ + A + +<<<<<<< working copy: 69004294ad57 - test: C + C + +======= + +B + +>>>>>>> merge rev: fd9a4049234b - test: B diff --git a/tests/test-shelve.t b/tests/test-shelve.t --- a/tests/test-shelve.t +++ b/tests/test-shelve.t @@ -85,6 +85,7 @@ --stat output diffstat-style summary of changes (provide the names of the shelved changes as positional arguments) + --unresolved unshelve mergestate with unresolved files -I --include PATTERN [+] include names matching the given patterns -X --exclude PATTERN [+] exclude names matching the given patterns --mq operate on patch repository