* [PATCH] git-status: show short sequencer state
@ 2012-10-22 23:29 Phil Hord
2012-10-23 6:05 ` Matthieu Moy
0 siblings, 1 reply; 5+ messages in thread
From: Phil Hord @ 2012-10-22 23:29 UTC (permalink / raw)
To: hordp
Cc: phil.hord, Junio C Hamano, konglu, Matthieu Moy, Kong Lucien, git,
Duperray Valentin, Jonas Franck, Nguy Thomas,
Nguyen Huynh Khoi Nguyen
Recently git-status learned to display the state of the git
sequencer in long form to help the user remember an interrupted
command. This information is also useful in short form to
humans and scripts, but no option is available to boil it down.
Teach git-status to report the sequencer state in short form
using a new --sequencer (-S) switch. Output zero or more
simple state token strings indicating the deduced state of the
git sequencer.
Introduce a common function to determine the current sequencer
state so the regular status function and this short version can
share common code.
Add a substate to wt_status_state to track more detailed
information about a state, such as "conflicted" or "resolved".
Move the am_empty_patch flage out of wt_status_state and into
this new substate.
State token strings which may be emitted and their meanings:
merge a git-merge is in progress
am a git-am is in progress
rebase a git-rebase is in progress
rebase-interactive a git-rebase--interactive is in progress
cherry-pick a git-cherry-pick is in progress
bisect a git-bisect is in progress
conflicted there are unresolved conflicts
resolved conflicts have been resolved
editing interactive rebase stopped to edit a commit
edited interactive rebase edit has been edited
splitting interactive rebase, commit is being split
I also considered adding these tokens, but I decided it was not
appropriate since these changes are not sequencer-related. But
it is possible I am being too short-sighted or have chosen the
switch name poorly.
clean
index
modified
untracked
---
Documentation/git-status.txt | 18 ++++++
builtin/commit.c | 12 +++-
wt-status.c | 128 +++++++++++++++++++++++++++++++++++--------
wt-status.h | 13 ++++-
4 files changed, 146 insertions(+), 25 deletions(-)
diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt
index 67e5f53..200a8e2 100644
--- a/Documentation/git-status.txt
+++ b/Documentation/git-status.txt
@@ -38,6 +38,24 @@ OPTIONS
across git versions and regardless of user configuration. See
below for details.
+-S::
+--sequence::
+ Show the git sequencer status. This shows zero or more tokens
+ describing the state of several git sequence operations. Each
+ token is separated by a newline.
++
+ merge a git-merge is in progress
+ am a git-am is in progress
+ rebase a git-rebase is in progress
+ rebase-interactive a git-rebase--interactive is in progress
+ cherry-pick a git-cherry-pick is in progress
+ bisect a git-bisect is in progress
+ conflicted there are unresolved conflicts
+ resolved conflicts have been resolved
+ editing interactive rebase stopped to edit a commit
+ edited interactive rebase edit has been edited
+ splitting interactive rebase, commit is being split
+
-u[<mode>]::
--untracked-files[=<mode>]::
Show untracked files.
diff --git a/builtin/commit.c b/builtin/commit.c
index a17a5df..9706ed9 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -114,7 +114,8 @@ static struct strbuf message = STRBUF_INIT;
static enum {
STATUS_FORMAT_LONG,
STATUS_FORMAT_SHORT,
- STATUS_FORMAT_PORCELAIN
+ STATUS_FORMAT_PORCELAIN,
+ STATUS_FORMAT_SEQUENCER
} status_format = STATUS_FORMAT_LONG;
static int opt_parse_m(const struct option *opt, const char *arg, int unset)
@@ -454,6 +455,9 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int
case STATUS_FORMAT_PORCELAIN:
wt_porcelain_print(s);
break;
+ case STATUS_FORMAT_SEQUENCER:
+ wt_sequencer_print(s);
+ break;
case STATUS_FORMAT_LONG:
wt_status_print(s);
break;
@@ -1156,6 +1160,9 @@ int cmd_status(int argc, const char **argv, const char *prefix)
N_("show status concisely"), STATUS_FORMAT_SHORT),
OPT_BOOLEAN('b', "branch", &s.show_branch,
N_("show branch information")),
+ OPT_SET_INT('S', "sequence", &status_format,
+ N_("show sequencer state"),
+ STATUS_FORMAT_SEQUENCER),
OPT_SET_INT(0, "porcelain", &status_format,
N_("machine-readable output"),
STATUS_FORMAT_PORCELAIN),
@@ -1216,6 +1223,9 @@ int cmd_status(int argc, const char **argv, const char *prefix)
case STATUS_FORMAT_PORCELAIN:
wt_porcelain_print(&s);
break;
+ case STATUS_FORMAT_SEQUENCER:
+ wt_sequencer_print(&s);
+ break;
case STATUS_FORMAT_LONG:
s.verbose = verbose;
s.ignore_submodule_arg = ignore_submodule_arg;
diff --git a/wt-status.c b/wt-status.c
index 2a9658b..996b454 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -781,7 +781,7 @@ static void show_merge_in_progress(struct wt_status *s,
struct wt_status_state *state,
const char *color)
{
- if (has_unmerged(s)) {
+ if (state->substate == WT_SUBSTATE_CONFLICTED) {
status_printf_ln(s, color, _("You have unmerged paths."));
if (advice_status_hints)
status_printf_ln(s, color,
@@ -802,11 +802,11 @@ static void show_am_in_progress(struct wt_status *s,
{
status_printf_ln(s, color,
_("You are in the middle of an am session."));
- if (state->am_empty_patch)
+ if (state->substate==WT_SUBSTATE_NOMINAL)
status_printf_ln(s, color,
_("The current patch is empty."));
if (advice_status_hints) {
- if (!state->am_empty_patch)
+ if (state->substate==WT_SUBSTATE_CONFLICTED)
status_printf_ln(s, color,
_(" (fix conflicts and then run \"git am --resolved\")"));
status_printf_ln(s, color,
@@ -867,9 +867,7 @@ static void show_rebase_in_progress(struct wt_status *s,
struct wt_status_state *state,
const char *color)
{
- struct stat st;
-
- if (has_unmerged(s)) {
+ if (state->substate == WT_SUBSTATE_CONFLICTED) {
status_printf_ln(s, color, _("You are currently rebasing."));
if (advice_status_hints) {
status_printf_ln(s, color,
@@ -879,19 +877,19 @@ static void show_rebase_in_progress(struct wt_status *s,
status_printf_ln(s, color,
_(" (use \"git rebase --abort\" to check out the original branch)"));
}
- } else if (state->rebase_in_progress || !stat(git_path("MERGE_MSG"), &st)) {
+ } else if (state->substate == WT_SUBSTATE_RESOLVED) {
status_printf_ln(s, color, _("You are currently rebasing."));
if (advice_status_hints)
status_printf_ln(s, color,
_(" (all conflicts fixed: run \"git rebase --continue\")"));
- } else if (split_commit_in_progress(s)) {
+ } else if (state->substate == WT_SUBSTATE_SPLITTING) {
status_printf_ln(s, color, _("You are currently splitting a commit during a rebase."));
if (advice_status_hints)
status_printf_ln(s, color,
_(" (Once your working directory is clean, run \"git rebase --continue\")"));
} else {
status_printf_ln(s, color, _("You are currently editing a commit during a rebase."));
- if (advice_status_hints && !s->amend) {
+ if (advice_status_hints && state->substate == WT_SUBSTATE_EDITING) {
status_printf_ln(s, color,
_(" (use \"git commit --amend\" to amend the current commit)"));
status_printf_ln(s, color,
@@ -907,7 +905,7 @@ static void show_cherry_pick_in_progress(struct wt_status *s,
{
status_printf_ln(s, color, _("You are currently cherry-picking."));
if (advice_status_hints) {
- if (has_unmerged(s))
+ if (state->substate == WT_SUBSTATE_CONFLICTED)
status_printf_ln(s, color,
_(" (fix conflicts and run \"git commit\")"));
else
@@ -928,34 +926,66 @@ static void show_bisect_in_progress(struct wt_status *s,
wt_status_print_trailer(s);
}
-static void wt_status_print_state(struct wt_status *s)
+static void wt_status_get_state(struct wt_status *s , struct wt_status_state *state)
{
- const char *state_color = color(WT_STATUS_HEADER, s);
- struct wt_status_state state;
struct stat st;
- memset(&state, 0, sizeof(state));
+ memset(state, 0, sizeof(*state));
+ // Determine main sequencer activity
if (!stat(git_path("MERGE_HEAD"), &st)) {
- state.merge_in_progress = 1;
+ state->merge_in_progress = 1;
} else if (!stat(git_path("rebase-apply"), &st)) {
if (!stat(git_path("rebase-apply/applying"), &st)) {
- state.am_in_progress = 1;
- if (!stat(git_path("rebase-apply/patch"), &st) && !st.st_size)
- state.am_empty_patch = 1;
+ state->am_in_progress = 1;
+ if (stat(git_path("rebase-apply/patch"), &st) || st.st_size)
+ state->substate = WT_SUBSTATE_CONFLICTED;
} else {
- state.rebase_in_progress = 1;
+ state->rebase_in_progress = 1;
}
} else if (!stat(git_path("rebase-merge"), &st)) {
if (!stat(git_path("rebase-merge/interactive"), &st))
- state.rebase_interactive_in_progress = 1;
+ state->rebase_interactive_in_progress = 1;
else
- state.rebase_in_progress = 1;
+ state->rebase_in_progress = 1;
} else if (!stat(git_path("CHERRY_PICK_HEAD"), &st)) {
- state.cherry_pick_in_progress = 1;
+ state->cherry_pick_in_progress = 1;
}
if (!stat(git_path("BISECT_LOG"), &st))
- state.bisect_in_progress = 1;
+ state->bisect_in_progress = 1;
+
+ // Check for unmerged files
+ if (state->rebase_in_progress || state->rebase_interactive_in_progress ||
+ state->cherry_pick_in_progress || state->merge_in_progress) {
+ if (has_unmerged(s)) {
+ state->substate = WT_SUBSTATE_CONFLICTED;
+ } else {
+ state->substate = WT_SUBSTATE_RESOLVED;
+ }
+ }
+
+ // Interactive Rebase is more nuanced
+ if (state->rebase_interactive_in_progress && state->substate != WT_SUBSTATE_CONFLICTED) {
+ if (!stat(git_path("MERGE_MSG"), &st)) {
+ state->substate = WT_SUBSTATE_RESOLVED;
+ } else if (split_commit_in_progress(s)) {
+ state->substate = WT_SUBSTATE_SPLITTING;
+ } else {
+ if (s->amend) {
+ state->substate = WT_SUBSTATE_EDITED;
+ } else {
+ state->substate = WT_SUBSTATE_EDITING;
+ }
+ }
+ }
+}
+
+static void wt_status_print_state(struct wt_status *s)
+{
+ const char *state_color = color(WT_STATUS_HEADER, s);
+ struct wt_status_state state;
+
+ wt_status_get_state(s, &state);
if (state.merge_in_progress)
show_merge_in_progress(s, &state, state_color);
@@ -1192,6 +1222,53 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
fputc(s->null_termination ? '\0' : '\n', s->fp);
}
+static void wt_print_token(struct wt_status *s, const char *color, const char *token)
+{
+ color_fprintf(s->fp, color, "%s", token);
+ fputc(s->null_termination ? '\0' : '\n', s->fp);
+}
+
+static void wt_shortstatus_print_sequencer(struct wt_status *s)
+{
+ struct wt_status_state state;
+ const char *state_color = color(WT_STATUS_HEADER, s);
+
+ wt_status_get_state(s, &state);
+
+ if (state.merge_in_progress)
+ wt_print_token(s, state_color, "merge");
+ if (state.am_in_progress)
+ wt_print_token(s, state_color, "am");
+ if (state.rebase_in_progress)
+ wt_print_token(s, state_color, "rebase");
+ if (state.rebase_interactive_in_progress)
+ wt_print_token(s, state_color, "rebase-interactive");
+ if (state.cherry_pick_in_progress)
+ wt_print_token(s, state_color, "cherry-pick");
+ if (state.bisect_in_progress)
+ wt_print_token(s, state_color, "bisect");
+
+ switch (state.substate) {
+ case WT_SUBSTATE_NOMINAL:
+ break;
+ case WT_SUBSTATE_CONFLICTED:
+ wt_print_token(s, state_color, "conflicted");
+ break;
+ case WT_SUBSTATE_RESOLVED:
+ wt_print_token(s, state_color, "resolved");
+ break;
+ case WT_SUBSTATE_EDITED:
+ wt_print_token(s, state_color, "edited");
+ break;
+ case WT_SUBSTATE_EDITING:
+ wt_print_token(s, state_color, "editing");
+ break;
+ case WT_SUBSTATE_SPLITTING:
+ wt_print_token(s, state_color, "splitting");
+ break;
+ }
+}
+
void wt_shortstatus_print(struct wt_status *s)
{
int i;
@@ -1224,6 +1301,11 @@ void wt_shortstatus_print(struct wt_status *s)
}
}
+void wt_sequencer_print(struct wt_status *s)
+{
+ wt_shortstatus_print_sequencer(s);
+}
+
void wt_porcelain_print(struct wt_status *s)
{
s->use_color = 0;
diff --git a/wt-status.h b/wt-status.h
index 236b41f..3de4b26 100644
--- a/wt-status.h
+++ b/wt-status.h
@@ -59,6 +59,7 @@ struct wt_status {
unsigned colopts;
int null_termination;
int show_branch;
+ int show_sequencer;
/* These are computed during processing of the individual sections */
int commitable;
@@ -71,14 +72,23 @@ struct wt_status {
struct string_list ignored;
};
+enum wt_status_substate {
+ WT_SUBSTATE_NOMINAL = 0,
+ WT_SUBSTATE_CONFLICTED,
+ WT_SUBSTATE_RESOLVED,
+ WT_SUBSTATE_SPLITTING,
+ WT_SUBSTATE_EDITING,
+ WT_SUBSTATE_EDITED,
+};
+
struct wt_status_state {
int merge_in_progress;
int am_in_progress;
- int am_empty_patch;
int rebase_in_progress;
int rebase_interactive_in_progress;
int cherry_pick_in_progress;
int bisect_in_progress;
+ enum wt_status_substate substate;
};
void wt_status_prepare(struct wt_status *s);
@@ -86,6 +96,7 @@ void wt_status_print(struct wt_status *s);
void wt_status_collect(struct wt_status *s);
void wt_shortstatus_print(struct wt_status *s);
+void wt_sequencer_print(struct wt_status *s);
void wt_porcelain_print(struct wt_status *s);
void status_printf_ln(struct wt_status *s, const char *color, const char *fmt, ...)
--
1.8.0.2.ge1a3bdd
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH] git-status: show short sequencer state
2012-10-22 23:29 [PATCH] git-status: show short sequencer state Phil Hord
@ 2012-10-23 6:05 ` Matthieu Moy
2012-10-23 18:03 ` Phil Hord
0 siblings, 1 reply; 5+ messages in thread
From: Matthieu Moy @ 2012-10-23 6:05 UTC (permalink / raw)
To: Phil Hord
Cc: phil.hord, Junio C Hamano, konglu, Kong Lucien, git,
Duperray Valentin, Jonas Franck, Nguy Thomas,
Nguyen Huynh Khoi Nguyen
Phil Hord <hordp@cisco.com> writes:
> + merge a git-merge is in progress
> + am a git-am is in progress
> + rebase a git-rebase is in progress
> + rebase-interactive a git-rebase--interactive is in progress
> + cherry-pick a git-cherry-pick is in progress
> + bisect a git-bisect is in progress
Avoid using git-foo syntax in documentation, it suggests that this is
valid command, which isn't true anymore. `git foo` seems the most common
syntax. Also, git-rebase--interactive is not user-visible => `git rebase
--interactive`.
> - if (state->am_empty_patch)
> + if (state->substate==WT_SUBSTATE_NOMINAL)
> status_printf_ln(s, color,
> _("The current patch is empty."));
This looks weird. First, spaces around == (here and below). Then, the
logic is unintuitive. The "if" suggests everything is allright, and the
message below is very specific. This at least deserves a comment.
> if (advice_status_hints) {
> - if (!state->am_empty_patch)
> + if (state->substate==WT_SUBSTATE_CONFLICTED)
Spaces around ==.
> +static void wt_print_token(struct wt_status *s, const char *color, const char *token)
> +{
> + color_fprintf(s->fp, color, "%s", token);
> + fputc(s->null_termination ? '\0' : '\n', s->fp);
> +}
The output format seems to be meant only for machine-consumption. Is
there any case when we'd want color? I'd say we can disable coloring
completely for this format (normally, color=auto does the right thing,
but I prefer being 100% sure I'll get no color when writing scripts)
> +static void wt_shortstatus_print_sequencer(struct wt_status *s)
[...]
> +void wt_sequencer_print(struct wt_status *s)
> +{
> + wt_shortstatus_print_sequencer(s);
> +}
> +
Why do you need this trivial wrapper?
Other than that, I like the idea (although I have no concrete use-case
in mind), but I didn't actually test the patch.
--
Matthieu Moy
http://www-verimag.imag.fr/~moy/
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] git-status: show short sequencer state
2012-10-23 6:05 ` Matthieu Moy
@ 2012-10-23 18:03 ` Phil Hord
2012-10-24 8:15 ` Matthieu Moy
0 siblings, 1 reply; 5+ messages in thread
From: Phil Hord @ 2012-10-23 18:03 UTC (permalink / raw)
To: Matthieu Moy
Cc: phil.hord@gmail.com, Junio C Hamano, konglu@minatec.inpg.fr,
Kong Lucien, git@vger.kernel.org, Duperray Valentin, Jonas Franck,
Nguy Thomas, Nguyen Huynh Khoi Nguyen
Matthieu Moy wrote:
> Phil Hord <hordp@cisco.com> writes:
>
>> + merge a git-merge is in progress
>> + am a git-am is in progress
>> + rebase a git-rebase is in progress
>> + rebase-interactive a git-rebase--interactive is in progress
>> + cherry-pick a git-cherry-pick is in progress
>> + bisect a git-bisect is in progress
> Avoid using git-foo syntax in documentation, it suggests that this is
> valid command, which isn't true anymore. `git foo` seems the most common
> syntax. Also, git-rebase--interactive is not user-visible => `git rebase
> --interactive`.
Thanks.
>> - if (state->am_empty_patch)
>> + if (state->substate==WT_SUBSTATE_NOMINAL)
>> status_printf_ln(s, color,
>> _("The current patch is empty."));
> This looks weird. First, spaces around == (here and below). Then, the
> logic is unintuitive. The "if" suggests everything is allright, and the
> message below is very specific. This at least deserves a comment.
Yes, I agree. It was less clear but more reasonable before I tried to
clear it up some. It's driven by the short-token printer. The state is
"you're in a 'git am' but I do not see any conflicted files. Therefore,
your patch must be empty." I suspect this may be a leaving from the
git-am machinery where it did not choose to clean up after itself if the
patch was empty, but perhaps it should have. I seldom use git-am, so I
do not know if this code reflects a common and useful state.
I'll try to make this more explicit. Currently the short-status
version will say either "am" or "am \n conflicted" when a 'git am' is in
progress. The logical path to follow if I re-add 'git-am-empty' state
tracker is for this to now show either "am \n am-is-empty" or "am \n
conflicted". But I think I should suppress the "am-is-empty" report in
that case. What do you think
>> if (advice_status_hints) {
>> - if (!state->am_empty_patch)
>> + if (state->substate==WT_SUBSTATE_CONFLICTED)
> Spaces around ==.
>
>> +static void wt_print_token(struct wt_status *s, const char *color, const char *token)
>> +{
>> + color_fprintf(s->fp, color, "%s", token);
>> + fputc(s->null_termination ? '\0' : '\n', s->fp);
>> +}
> The output format seems to be meant only for machine-consumption. Is
> there any case when we'd want color? I'd say we can disable coloring
> completely for this format (normally, color=auto does the right thing,
> but I prefer being 100% sure I'll get no color when writing scripts)
Originally I had this output nested in the normal 'git status --short'
output, like a shortened form of the "advice". Then, 'git-status
--porcelain' would show the tokens without color, but 'git status
--short' would show them with color. I thought I might be going back
there, or that I might combine this with full 'git status' again
somehow, and colors seemed appropriate still.
The --short status report is too confusing when tokens may or may-not
appear, and it would likely break some scripts, even though they should
be using --porcelain. And the full status already has its long versions
of the same text. So I can remove this color decorator until someone
finds a need for it.
>> +static void wt_shortstatus_print_sequencer(struct wt_status *s)
> [...]
>> +void wt_sequencer_print(struct wt_status *s)
>> +{
>> + wt_shortstatus_print_sequencer(s);
>> +}
>> +
> Why do you need this trivial wrapper?
Another left-over from its previous multiple versions. I'll simplify it.
> Other than that, I like the idea (although I have no concrete use-case
> in mind), but I didn't actually test the patch.
My own use-case involves $PS1. I keep running into "you cannot
cherry-pick because you are in the middle of a rebase" in submodules in
which I have long forgotten about the failed action and have gone on to
write many new commits, or switched branches, or worse. I do not know
what 'git rebase --abort' will give me in those cases, and I wonder what
work I might have lost for having been interrupted in the middle of that
action in the past. These tokens will help me decorate my prompt to
remind me I left some baggage untended.
Thanks for the feedback.
Phil
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] git-status: show short sequencer state
2012-10-23 18:03 ` Phil Hord
@ 2012-10-24 8:15 ` Matthieu Moy
0 siblings, 0 replies; 5+ messages in thread
From: Matthieu Moy @ 2012-10-24 8:15 UTC (permalink / raw)
To: Phil Hord
Cc: phil.hord@gmail.com, Junio C Hamano, konglu@minatec.inpg.fr,
Kong Lucien, git@vger.kernel.org, Duperray Valentin, Jonas Franck,
Nguy Thomas, Nguyen Huynh Khoi Nguyen
Phil Hord <hordp@cisco.com> writes:
>>> + if (state->substate==WT_SUBSTATE_NOMINAL)
>>> status_printf_ln(s, color,
>>> _("The current patch is empty."));
>> This looks weird. First, spaces around == (here and below). Then, the
>> logic is unintuitive. The "if" suggests everything is allright, and the
>> message below is very specific. This at least deserves a comment.
>
> Yes, I agree. It was less clear but more reasonable before I tried to
> clear it up some. It's driven by the short-token printer. The state is
> "you're in a 'git am' but I do not see any conflicted files. Therefore,
> your patch must be empty."
This was my guess, but I wouldn't have needed to guess if there was a
comment in the code ;-).
> I'll try to make this more explicit. Currently the short-status
> version will say either "am" or "am \n conflicted" when a 'git am' is in
> progress. The logical path to follow if I re-add 'git-am-empty' state
> tracker is for this to now show either "am \n am-is-empty" or "am \n
> conflicted". But I think I should suppress the "am-is-empty" report in
> that case. What do you think
I don't think you should remove it from the output (no strong opinion).
My point was just that the code looked weird.
>>> +static void wt_print_token(struct wt_status *s, const char *color, const char *token)
>>> +{
>>> + color_fprintf(s->fp, color, "%s", token);
>>> + fputc(s->null_termination ? '\0' : '\n', s->fp);
>>> +}
>> The output format seems to be meant only for machine-consumption. Is
>> there any case when we'd want color? [...]
> > [...]I thought I might be going back there, or that I might combine this
> > with full 'git status' again somehow, and colors seemed appropriate
> > still.
> > [...]
> > So I can remove this color decorator until someone finds a need for
> > it.
I'm fine with both options, with a slight preference for removing them.
> My own use-case involves $PS1.
That makes sense (indeed, the implementation of status hints was
slightly inspired from what the bash prompt in
contrib/completion/git-prompt.sh does). The next step could be to use
your porcelain there instead of checking manually file existance.
You may want to add a short note about this motivation in the commit
message.
--
Matthieu Moy
http://www-verimag.imag.fr/~moy/
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH] git-status: show short sequencer state
@ 2012-10-23 18:58 Phil Hord
0 siblings, 0 replies; 5+ messages in thread
From: Phil Hord @ 2012-10-23 18:58 UTC (permalink / raw)
To: hordp
Cc: phil.hord, Junio C Hamano, konglu, Matthieu Moy, Kong Lucien, git,
Duperray Valentin, Jonas Franck, Nguy Thomas,
Nguyen Huynh Khoi Nguyen
Recently git-status learned to display the state of the git
sequencer in long form to help the user remember an interrupted
command. This information is also useful in short form to
humans and scripts, but no option is available to boil it down.
Teach git-status to report the sequencer state in short form
using a new --sequencer (-S) switch. Output zero or more
simple state token strings indicating the deduced state of the
git sequencer.
Introduce a common function to determine the current sequencer
state so the regular status function and this short version can
share common code.
Add a substate to wt_status_state to track more detailed
information about a state, such as "conflicted" or "resolved".
Move the am_empty_patch flage out of wt_status_state and into
this new substate.
State token strings which may be emitted and their meanings:
merge a git-merge is in progress
am a git-am is in progress
rebase a git-rebase is in progress
rebase-interactive a git-rebase--interactive is in progress
cherry-pick a git-cherry-pick is in progress
bisect a git-bisect is in progress
conflicted there are unresolved conflicts
resolved conflicts have been resolved
editing interactive rebase stopped to edit a commit
edited interactive rebase edit has been edited
splitting interactive rebase, commit is being split
I also considered adding these tokens, but I decided it was not
appropriate since these changes are not sequencer-related. But
it is possible I am being too short-sighted or have chosen the
switch name poorly.
clean
index
modified
untracked
---
Documentation/git-status.txt | 18 +++++++
builtin/commit.c | 12 ++++-
wt-status.c | 125 +++++++++++++++++++++++++++++++++++--------
wt-status.h | 14 ++++-
4 files changed, 145 insertions(+), 24 deletions(-)
diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt
index 67e5f53..31ffabd 100644
--- a/Documentation/git-status.txt
+++ b/Documentation/git-status.txt
@@ -38,6 +38,24 @@ OPTIONS
across git versions and regardless of user configuration. See
below for details.
+-S::
+--sequence::
+ Show the git sequencer status. This shows zero or more tokens
+ describing the state of several git sequence operations. Each
+ token is separated by a newline.
++
+ merge a merge is in progress
+ am an am is in progress
+ rebase a rebase is in progress
+ rebase-interactive an interactive rebase is in progress
+ cherry-pick a cherry-pick is in progress
+ bisect a bisect is in progress
+ conflicted there are unresolved conflicts
+ resolved conflicts have been resolved
+ editing interactive rebase stopped to edit a commit
+ edited interactive rebase edit has been edited
+ splitting interactive rebase, commit is being split
+
-u[<mode>]::
--untracked-files[=<mode>]::
Show untracked files.
diff --git a/builtin/commit.c b/builtin/commit.c
index a17a5df..9706ed9 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -114,7 +114,8 @@ static struct strbuf message = STRBUF_INIT;
static enum {
STATUS_FORMAT_LONG,
STATUS_FORMAT_SHORT,
- STATUS_FORMAT_PORCELAIN
+ STATUS_FORMAT_PORCELAIN,
+ STATUS_FORMAT_SEQUENCER
} status_format = STATUS_FORMAT_LONG;
static int opt_parse_m(const struct option *opt, const char *arg, int unset)
@@ -454,6 +455,9 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int
case STATUS_FORMAT_PORCELAIN:
wt_porcelain_print(s);
break;
+ case STATUS_FORMAT_SEQUENCER:
+ wt_sequencer_print(s);
+ break;
case STATUS_FORMAT_LONG:
wt_status_print(s);
break;
@@ -1156,6 +1160,9 @@ int cmd_status(int argc, const char **argv, const char *prefix)
N_("show status concisely"), STATUS_FORMAT_SHORT),
OPT_BOOLEAN('b', "branch", &s.show_branch,
N_("show branch information")),
+ OPT_SET_INT('S', "sequence", &status_format,
+ N_("show sequencer state"),
+ STATUS_FORMAT_SEQUENCER),
OPT_SET_INT(0, "porcelain", &status_format,
N_("machine-readable output"),
STATUS_FORMAT_PORCELAIN),
@@ -1216,6 +1223,9 @@ int cmd_status(int argc, const char **argv, const char *prefix)
case STATUS_FORMAT_PORCELAIN:
wt_porcelain_print(&s);
break;
+ case STATUS_FORMAT_SEQUENCER:
+ wt_sequencer_print(&s);
+ break;
case STATUS_FORMAT_LONG:
s.verbose = verbose;
s.ignore_submodule_arg = ignore_submodule_arg;
diff --git a/wt-status.c b/wt-status.c
index 2a9658b..81d91e3 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -781,7 +781,7 @@ static void show_merge_in_progress(struct wt_status *s,
struct wt_status_state *state,
const char *color)
{
- if (has_unmerged(s)) {
+ if (state->substate == WT_SUBSTATE_CONFLICTED) {
status_printf_ln(s, color, _("You have unmerged paths."));
if (advice_status_hints)
status_printf_ln(s, color,
@@ -802,11 +802,11 @@ static void show_am_in_progress(struct wt_status *s,
{
status_printf_ln(s, color,
_("You are in the middle of an am session."));
- if (state->am_empty_patch)
+ if (state->substate == WT_SUBSTATE_AM_EMPTY)
status_printf_ln(s, color,
_("The current patch is empty."));
if (advice_status_hints) {
- if (!state->am_empty_patch)
+ if (state->substate == WT_SUBSTATE_CONFLICTED)
status_printf_ln(s, color,
_(" (fix conflicts and then run \"git am --resolved\")"));
status_printf_ln(s, color,
@@ -867,9 +867,7 @@ static void show_rebase_in_progress(struct wt_status *s,
struct wt_status_state *state,
const char *color)
{
- struct stat st;
-
- if (has_unmerged(s)) {
+ if (state->substate == WT_SUBSTATE_CONFLICTED) {
status_printf_ln(s, color, _("You are currently rebasing."));
if (advice_status_hints) {
status_printf_ln(s, color,
@@ -879,19 +877,19 @@ static void show_rebase_in_progress(struct wt_status *s,
status_printf_ln(s, color,
_(" (use \"git rebase --abort\" to check out the original branch)"));
}
- } else if (state->rebase_in_progress || !stat(git_path("MERGE_MSG"), &st)) {
+ } else if (state->substate == WT_SUBSTATE_RESOLVED) {
status_printf_ln(s, color, _("You are currently rebasing."));
if (advice_status_hints)
status_printf_ln(s, color,
_(" (all conflicts fixed: run \"git rebase --continue\")"));
- } else if (split_commit_in_progress(s)) {
+ } else if (state->substate == WT_SUBSTATE_SPLITTING) {
status_printf_ln(s, color, _("You are currently splitting a commit during a rebase."));
if (advice_status_hints)
status_printf_ln(s, color,
_(" (Once your working directory is clean, run \"git rebase --continue\")"));
} else {
status_printf_ln(s, color, _("You are currently editing a commit during a rebase."));
- if (advice_status_hints && !s->amend) {
+ if (advice_status_hints && state->substate == WT_SUBSTATE_EDITING) {
status_printf_ln(s, color,
_(" (use \"git commit --amend\" to amend the current commit)"));
status_printf_ln(s, color,
@@ -907,7 +905,7 @@ static void show_cherry_pick_in_progress(struct wt_status *s,
{
status_printf_ln(s, color, _("You are currently cherry-picking."));
if (advice_status_hints) {
- if (has_unmerged(s))
+ if (state->substate == WT_SUBSTATE_CONFLICTED)
status_printf_ln(s, color,
_(" (fix conflicts and run \"git commit\")"));
else
@@ -928,34 +926,68 @@ static void show_bisect_in_progress(struct wt_status *s,
wt_status_print_trailer(s);
}
-static void wt_status_print_state(struct wt_status *s)
+static void wt_status_get_state(struct wt_status *s , struct wt_status_state *state)
{
- const char *state_color = color(WT_STATUS_HEADER, s);
- struct wt_status_state state;
struct stat st;
- memset(&state, 0, sizeof(state));
+ memset(state, 0, sizeof(*state));
+ // Determine main sequencer activity
if (!stat(git_path("MERGE_HEAD"), &st)) {
- state.merge_in_progress = 1;
+ state->merge_in_progress = 1;
} else if (!stat(git_path("rebase-apply"), &st)) {
if (!stat(git_path("rebase-apply/applying"), &st)) {
- state.am_in_progress = 1;
+ state->am_in_progress = 1;
if (!stat(git_path("rebase-apply/patch"), &st) && !st.st_size)
- state.am_empty_patch = 1;
+ state->substate = WT_SUBSTATE_AM_EMPTY;
+ else
+ state->substate = WT_SUBSTATE_CONFLICTED;
} else {
- state.rebase_in_progress = 1;
+ state->rebase_in_progress = 1;
}
} else if (!stat(git_path("rebase-merge"), &st)) {
if (!stat(git_path("rebase-merge/interactive"), &st))
- state.rebase_interactive_in_progress = 1;
+ state->rebase_interactive_in_progress = 1;
else
- state.rebase_in_progress = 1;
+ state->rebase_in_progress = 1;
} else if (!stat(git_path("CHERRY_PICK_HEAD"), &st)) {
- state.cherry_pick_in_progress = 1;
+ state->cherry_pick_in_progress = 1;
}
if (!stat(git_path("BISECT_LOG"), &st))
- state.bisect_in_progress = 1;
+ state->bisect_in_progress = 1;
+
+ // Check for unmerged files
+ if (state->rebase_in_progress || state->rebase_interactive_in_progress ||
+ state->cherry_pick_in_progress || state->merge_in_progress) {
+ if (has_unmerged(s)) {
+ state->substate = WT_SUBSTATE_CONFLICTED;
+ } else {
+ state->substate = WT_SUBSTATE_RESOLVED;
+ }
+ }
+
+ // Interactive Rebase is more nuanced
+ if (state->rebase_interactive_in_progress && state->substate != WT_SUBSTATE_CONFLICTED) {
+ if (!stat(git_path("MERGE_MSG"), &st)) {
+ state->substate = WT_SUBSTATE_RESOLVED;
+ } else if (split_commit_in_progress(s)) {
+ state->substate = WT_SUBSTATE_SPLITTING;
+ } else {
+ if (s->amend) {
+ state->substate = WT_SUBSTATE_EDITED;
+ } else {
+ state->substate = WT_SUBSTATE_EDITING;
+ }
+ }
+ }
+}
+
+static void wt_status_print_state(struct wt_status *s)
+{
+ const char *state_color = color(WT_STATUS_HEADER, s);
+ struct wt_status_state state;
+
+ wt_status_get_state(s, &state);
if (state.merge_in_progress)
show_merge_in_progress(s, &state, state_color);
@@ -1192,6 +1224,55 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
fputc(s->null_termination ? '\0' : '\n', s->fp);
}
+static void wt_print_token(struct wt_status *s, const char *token)
+{
+ fprintf(s->fp, "%s", token);
+ fputc(s->null_termination ? '\0' : '\n', s->fp);
+}
+
+void wt_sequencer_print(struct wt_status *s)
+{
+ struct wt_status_state state;
+
+ wt_status_get_state(s, &state);
+
+ if (state.merge_in_progress)
+ wt_print_token(s, "merge");
+ if (state.am_in_progress)
+ wt_print_token(s, "am");
+ if (state.rebase_in_progress)
+ wt_print_token(s, "rebase");
+ if (state.rebase_interactive_in_progress)
+ wt_print_token(s, "rebase-interactive");
+ if (state.cherry_pick_in_progress)
+ wt_print_token(s, "cherry-pick");
+ if (state.bisect_in_progress)
+ wt_print_token(s, "bisect");
+
+ switch (state.substate) {
+ case WT_SUBSTATE_NOMINAL:
+ break;
+ case WT_SUBSTATE_CONFLICTED:
+ wt_print_token(s, "conflicted");
+ break;
+ case WT_SUBSTATE_RESOLVED:
+ wt_print_token(s, "resolved");
+ break;
+ case WT_SUBSTATE_EDITED:
+ wt_print_token(s, "edited");
+ break;
+ case WT_SUBSTATE_EDITING:
+ wt_print_token(s, "editing");
+ break;
+ case WT_SUBSTATE_SPLITTING:
+ wt_print_token(s, "splitting");
+ break;
+ case WT_SUBSTATE_AM_EMPTY:
+ wt_print_token(s, "am-empty");
+ break;
+ }
+}
+
void wt_shortstatus_print(struct wt_status *s)
{
int i;
diff --git a/wt-status.h b/wt-status.h
index 236b41f..900889c 100644
--- a/wt-status.h
+++ b/wt-status.h
@@ -59,6 +59,7 @@ struct wt_status {
unsigned colopts;
int null_termination;
int show_branch;
+ int show_sequencer;
/* These are computed during processing of the individual sections */
int commitable;
@@ -71,14 +72,24 @@ struct wt_status {
struct string_list ignored;
};
+enum wt_status_substate {
+ WT_SUBSTATE_NOMINAL = 0,
+ WT_SUBSTATE_CONFLICTED,
+ WT_SUBSTATE_RESOLVED,
+ WT_SUBSTATE_SPLITTING,
+ WT_SUBSTATE_EDITING,
+ WT_SUBSTATE_EDITED,
+ WT_SUBSTATE_AM_EMPTY,
+};
+
struct wt_status_state {
int merge_in_progress;
int am_in_progress;
- int am_empty_patch;
int rebase_in_progress;
int rebase_interactive_in_progress;
int cherry_pick_in_progress;
int bisect_in_progress;
+ enum wt_status_substate substate;
};
void wt_status_prepare(struct wt_status *s);
@@ -86,6 +97,7 @@ void wt_status_print(struct wt_status *s);
void wt_status_collect(struct wt_status *s);
void wt_shortstatus_print(struct wt_status *s);
+void wt_sequencer_print(struct wt_status *s);
void wt_porcelain_print(struct wt_status *s);
void status_printf_ln(struct wt_status *s, const char *color, const char *fmt, ...)
--
1.8.0.2.gc921d59.dirty
^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2012-10-24 8:16 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-10-22 23:29 [PATCH] git-status: show short sequencer state Phil Hord
2012-10-23 6:05 ` Matthieu Moy
2012-10-23 18:03 ` Phil Hord
2012-10-24 8:15 ` Matthieu Moy
-- strict thread matches above, loose matches on Subject: below --
2012-10-23 18:58 Phil Hord
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).