diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py --- a/mercurial/cmdutil.py +++ b/mercurial/cmdutil.py @@ -572,6 +572,111 @@ return finalrs +def _commentlines(raw): + '''Surround lineswith a comment char and a new line''' + lines = raw.splitlines() + commentedlines = ['# %s' % line for line in lines] + return '\n'.join(commentedlines) + '\n' + +def _conflictsmsg(repo): + # avoid merge cycle + from . import merge as mergemod + mergestate = mergemod.mergestate.read(repo) + if not mergestate.active(): + return + + m = scmutil.match(repo[None]) + unresolvedlist = [f for f in mergestate if m(f) and mergestate[f] == 'u'] + if unresolvedlist: + mergeliststr = '\n'.join( + [' %s' % os.path.relpath( + os.path.join(repo.root, path), + pycompat.getcwd()) for path in unresolvedlist]) + msg = _('''Unresolved merge conflicts: + +%s + +To mark files as resolved: hg resolve --mark FILE''') % mergeliststr + else: + msg = _('No unresolved merge conflicts.') + + return _commentlines(msg) + +def _helpmessage(continuecmd, abortcmd): + msg = _('To continue: %s\n' + 'To abort: %s') % (continuecmd, abortcmd) + return _commentlines(msg) + +def _rebasemsg(): + return _helpmessage('hg rebase --continue', 'hg rebase --abort') + +def _histeditmsg(): + return _helpmessage('hg histedit --continue', 'hg histedit --abort') + +def _unshelvemsg(): + return _helpmessage('hg unshelve --continue', 'hg unshelve --abort') + +def _updatecleanmsg(dest=None): + warning = _('warning: this will discard uncommitted changes') + return 'hg update --clean %s (%s)' % (dest or '.', warning) + +def _graftmsg(): + # tweakdefaults requires `update` to have a rev hence the `.` + return _helpmessage('hg graft --continue', _updatecleanmsg()) + +def _mergemsg(): + # tweakdefaults requires `update` to have a rev hence the `.` + return _helpmessage('hg commit', _updatecleanmsg()) + +def _bisectmsg(): + msg = _('To mark the changeset good: hg bisect --good\n' + 'To mark the changeset bad: hg bisect --bad\n' + 'To abort: hg bisect --reset\n') + return _commentlines(msg) + +def fileexistspredicate(filename): + return lambda repo: repo.vfs.exists(filename) + +def _mergepredicate(repo): + return len(repo[None].parents()) > 1 + +STATES = ( + # (state, predicate to detect states, helpful message function) + ('histedit', fileexistspredicate('histedit-state'), _histeditmsg), + ('bisect', fileexistspredicate('bisect.state'), _bisectmsg), + ('graft', fileexistspredicate('graftstate'), _graftmsg), + ('unshelve', fileexistspredicate('unshelverebasestate'), _unshelvemsg), + ('rebase', fileexistspredicate('rebasestate'), _rebasemsg), + # The merge state is part of a list that will be iterated over. + # They need to be last because some of the other unfinished states may also + # be in a merge or update state (eg. rebase, histedit, graft, etc). + # We want those to have priority. + ('merge', _mergepredicate, _mergemsg), +) + +def _getrepostate(repo): + # experimental config: morestatus.skipstates + skip = set(repo.ui.configlist('commands', 'status.skipstates')) + for state, statedetectionpredicate, msgfn in STATES: + if state in skip: + continue + if statedetectionpredicate(repo): + return (state, statedetectionpredicate, msgfn) + +def morestatus(repo, fm): + statetuple = _getrepostate(repo) + label = 'status.morestatus' + if statetuple: + fm.startitem() + state, statedetectionpredicate, helpfulmsg = statetuple + statemsg = _('The repository is in an unfinished *%s* state.') % state + fm.write('statemsg', '%s\n', _commentlines(statemsg), label=label) + conmsg = _conflictsmsg(repo) + fm.write('conflictsmsg', '%s\n', conmsg, label=label) + if helpfulmsg: + helpmsg = helpfulmsg() + fm.write('helpmsg', '%s\n', helpmsg, label=label) + def findpossible(cmd, table, strict=False): """ Return cmd -> (aliases, command table entry) diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -4710,6 +4710,19 @@ files are not considered while tersing until 'i' is there in --terse value or the --ignored option is used. + --verbose option shows more context about the state of the repo + like the repository is in unfinised merge, shelve, rebase state etc. + You can have this behaviour turned on by default by following config: + + [commands] + status.verbose = true + + You can also skip some states like bisect by adding following in + configuration file. + + [commands] + status.skipstates = bisect + Examples: - show changes in the working directory relative to a @@ -4799,6 +4812,10 @@ if f in copy: fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd), label='status.copied') + + if ((ui.verbose or ui.configbool('commands', 'status.verbose')) + and not ui.plain()): + cmdutil.morestatus(repo, fm) fm.end() @command('^summary|sum', diff --git a/mercurial/configitems.py b/mercurial/configitems.py --- a/mercurial/configitems.py +++ b/mercurial/configitems.py @@ -97,6 +97,12 @@ coreconfigitem('commands', 'status.relative', default=False, ) +coreconfigitem('commands', 'status.skipstates', + default=[], +) +coreconfigitem('commands', 'status.verbose', + default=False, +) coreconfigitem('commands', 'update.requiredest', default=False, ) diff --git a/tests/test-bisect.t b/tests/test-bisect.t --- a/tests/test-bisect.t +++ b/tests/test-bisect.t @@ -184,6 +184,15 @@ $ hg bisect -r $ hg bisect -b + $ hg status -v + # The repository is in an unfinished *bisect* state. + + None + # To mark the changeset good: hg bisect --good + # To mark the changeset bad: hg bisect --bad + # To abort: hg bisect --reset + + $ hg status -v --config morestatus.skipstates=bisect $ hg summary parent: 31:58c80a7c8a40 tip msg 31 diff --git a/tests/test-conflict.t b/tests/test-conflict.t --- a/tests/test-conflict.t +++ b/tests/test-conflict.t @@ -44,6 +44,23 @@ $ hg id 618808747361+c0c68e4fe667+ tip + $ echo "[commands]" >> $HGRCPATH + $ echo "status.verbose=true" >> $HGRCPATH + $ hg status + M a + ? a.orig + # The repository is in an unfinished *merge* state. + + # Unresolved merge conflicts: + # + # a + # + # To mark files as resolved: hg resolve --mark FILE + + # To continue: hg commit + # To abort: hg update --clean . (warning: this will discard uncommitted changes) + + $ cat a Small Mathematical Series. 1 @@ -58,7 +75,7 @@ >>>>>>> merge rev: c0c68e4fe667 - test: branch1 Hop we are done. - $ hg status + $ hg status --config commands.status.verbose=0 M a ? a.orig diff --git a/tests/test-graft.t b/tests/test-graft.t --- a/tests/test-graft.t +++ b/tests/test-graft.t @@ -221,6 +221,25 @@ $ hg summary |grep graft commit: 2 modified, 2 unknown, 1 unresolved (graft in progress) +Using status to get more context + + $ hg status --verbose + M d + M e + ? a.orig + ? e.orig + # The repository is in an unfinished *graft* state. + + # Unresolved merge conflicts: + # + # e + # + # To mark files as resolved: hg resolve --mark FILE + + # To continue: hg graft --continue + # To abort: hg update --clean . (warning: this will discard uncommitted changes) + + Commit while interrupted should fail: $ hg ci -m 'commit interrupted graft' diff --git a/tests/test-histedit-fold.t b/tests/test-histedit-fold.t --- a/tests/test-histedit-fold.t +++ b/tests/test-histedit-fold.t @@ -294,9 +294,21 @@ [1] There were conflicts, we keep P1 content. This should effectively drop the changes from +6. - $ hg status + + $ hg status -v M file ? file.orig + # The repository is in an unfinished *histedit* state. + + # Unresolved merge conflicts: + # + # file + # + # To mark files as resolved: hg resolve --mark FILE + + # To continue: hg histedit --continue + # To abort: hg histedit --abort + $ hg resolve -l U file $ hg revert -r 'p1()' file diff --git a/tests/test-rebase-conflicts.t b/tests/test-rebase-conflicts.t --- a/tests/test-rebase-conflicts.t +++ b/tests/test-rebase-conflicts.t @@ -71,6 +71,21 @@ unresolved conflicts (see hg resolve, then hg rebase --continue) [1] + $ hg status --config commands.status.verbose=1 + M common + ? common.orig + # The repository is in an unfinished *rebase* state. + + # Unresolved merge conflicts: + # + # common + # + # To mark files as resolved: hg resolve --mark FILE + + # To continue: hg rebase --continue + # To abort: hg rebase --abort + + Try to continue without solving the conflict: $ hg rebase --continue diff --git a/tests/test-shelve.t b/tests/test-shelve.t --- a/tests/test-shelve.t +++ b/tests/test-shelve.t @@ -342,6 +342,23 @@ warning: conflicts while merging a/a! (edit, then use 'hg resolve --mark') unresolved conflicts (see 'hg resolve', then 'hg unshelve --continue') [1] + $ hg status -v + M a/a + M b.rename/b + M c.copy + R b/b + ? a/a.orig + # The repository is in an unfinished *unshelve* state. + + # Unresolved merge conflicts: + # + # a/a + # + # To mark files as resolved: hg resolve --mark FILE + + # To continue: hg unshelve --continue + # To abort: hg unshelve --abort + ensure that we have a merge with unresolved conflicts