Skip to content

Commit

Permalink
wt-status.*: better advices for git status added
Browse files Browse the repository at this point in the history
This patch provides new informative help messages in the display of
'git status' (at the top) during conflicts, rebase, am, bisect or
cherry-pick process.

The new messages are not shown when using options such as -s or
--porcelain. The messages about the current situation of the user are
always displayed but the advices on what the user needs to do in order
to resume a rebase/bisect/am/commit after resolving conflicts can be
hidden by setting advice.statushints to 'false' in the config file.

Thus, information about the updated advice.statushints key are added
in Documentation/config.txt.

Also, the test t7060-wt-status.sh is now working with the new help
messages. Tests about suggestions of "git rm" are also added.

Signed-off-by: Lucien Kong <Lucien.Kong@ensimag.imag.fr>
Signed-off-by: Valentin Duperray <Valentin.Duperray@ensimag.imag.fr>
Signed-off-by: Franck Jonas <Franck.Jonas@ensimag.imag.fr>
Signed-off-by: Thomas Nguy <Thomas.Nguy@ensimag.imag.fr>
Signed-off-by: Huynh Khoi Nguyen Nguyen <Huynh-Khoi-Nguyen.Nguyen@ensimag.imag.fr>
Signed-off-by: Matthieu Moy <Matthieu.Moy@grenoble-inp.fr>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
Lucien Kong authored and Junio C Hamano committed Jun 14, 2012
1 parent 3fe4498 commit 83c750a
Show file tree
Hide file tree
Showing 4 changed files with 235 additions and 3 deletions.
7 changes: 4 additions & 3 deletions Documentation/config.txt
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,10 @@ advice.*::
specified a refspec that isn't your current branch) and
it resulted in a non-fast-forward error.
statusHints::
Directions on how to stage/unstage/add shown in the
output of linkgit:git-status[1] and the template shown
when writing commit messages.
Show directions on how to proceed from the current
state in the output of linkgit:git-status[1] and in
the template shown when writing commit messages in
linkgit:git-commit[1].
commitBeforeMerge::
Advice shown when linkgit:git-merge[1] refuses to
merge to avoid overwriting local changes.
Expand Down
64 changes: 64 additions & 0 deletions t/t7060-wtstatus.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ test_expect_success 'Report new path with conflict' '

cat >expect <<EOF
# On branch side
# You have unmerged paths.
# (fix conflicts and run "git commit")
#
# Unmerged paths:
# (use "git add/rm <file>..." as appropriate to mark resolution)
#
Expand Down Expand Up @@ -118,4 +121,65 @@ test_expect_success 'git diff-index --cached -C shows 2 copies + 1 unmerged' '
test_cmp expected actual
'


test_expect_success 'status when conflicts with add and rm advice (deleted by them)' '
git reset --hard &&
git checkout master &&
test_commit init main.txt init &&
git checkout -b second_branch &&
git rm main.txt &&
git commit -m "main.txt deleted on second_branch" &&
test_commit second conflict.txt second &&
git checkout master &&
test_commit on_second main.txt on_second &&
test_commit master conflict.txt master &&
test_must_fail git merge second_branch &&
cat >expected <<-\EOF &&
# On branch master
# You have unmerged paths.
# (fix conflicts and run "git commit")
#
# Unmerged paths:
# (use "git add/rm <file>..." as appropriate to mark resolution)
#
# both added: conflict.txt
# deleted by them: main.txt
#
no changes added to commit (use "git add" and/or "git commit -a")
EOF
git status --untracked-files=no >actual &&
test_i18ncmp expected actual
'


test_expect_success 'status when conflicts with add and rm advice (both deleted)' '
git reset --hard &&
git checkout -b conflict &&
test_commit one main.txt one &&
git branch conflict_second &&
git mv main.txt sub_master.txt &&
git commit -m "main.txt renamed in sub_master.txt" &&
git checkout conflict_second &&
git mv main.txt sub_second.txt &&
git commit -m "main.txt renamed in sub_second.txt" &&
test_must_fail git merge conflict &&
cat >expected <<-\EOF &&
# On branch conflict_second
# You have unmerged paths.
# (fix conflicts and run "git commit")
#
# Unmerged paths:
# (use "git add/rm <file>..." as appropriate to mark resolution)
#
# both deleted: main.txt
# added by them: sub_master.txt
# added by us: sub_second.txt
#
no changes added to commit (use "git add" and/or "git commit -a")
EOF
git status --untracked-files=no >actual &&
test_i18ncmp expected actual
'


test_done
156 changes: 156 additions & 0 deletions wt-status.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ static char default_wt_status_colors[][COLOR_MAXLEN] = {
GIT_COLOR_GREEN, /* WT_STATUS_LOCAL_BRANCH */
GIT_COLOR_RED, /* WT_STATUS_REMOTE_BRANCH */
GIT_COLOR_NIL, /* WT_STATUS_ONBRANCH */
GIT_COLOR_NORMAL, /* WT_STATUS_IN_PROGRESS */
};

static const char *color(int slot, struct wt_status *s)
Expand Down Expand Up @@ -728,6 +729,160 @@ static void wt_status_print_tracking(struct wt_status *s)
color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#");
}

static int has_unmerged(struct wt_status *s)
{
int i;

for (i = 0; i < s->change.nr; i++) {
struct wt_status_change_data *d;
d = s->change.items[i].util;
if (d->stagemask)
return 1;
}
return 0;
}

static void show_merge_in_progress(struct wt_status *s,
struct wt_status_state *state,
const char *color)
{
if (has_unmerged(s)) {
status_printf_ln(s, color, _("You have unmerged paths."));
if (advice_status_hints)
status_printf_ln(s, color,
_(" (fix conflicts and run \"git commit\")"));
} else {
status_printf_ln(s, color,
_("All conflicts fixed but you are still merging."));
if (advice_status_hints)
status_printf_ln(s, color,
_(" (use \"git commit\" to conclude merge)"));
}
wt_status_print_trailer(s);
}

static void show_am_in_progress(struct wt_status *s,
struct wt_status_state *state,
const char *color)
{
status_printf_ln(s, color,
_("You are in the middle of an am session."));
if (state->am_empty_patch)
status_printf_ln(s, color,
_("The current patch is empty."));
if (advice_status_hints) {
if (!state->am_empty_patch)
status_printf_ln(s, color,
_(" (fix conflicts and then run \"git am --resolved\")"));
status_printf_ln(s, color,
_(" (use \"git am --skip\" to skip this patch)"));
status_printf_ln(s, color,
_(" (use \"git am --abort\" to restore the original branch)"));
}
wt_status_print_trailer(s);
}

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)) {
status_printf_ln(s, color, _("You are currently rebasing."));
if (advice_status_hints) {
status_printf_ln(s, color,
_(" (fix conflicts and then run \"git rebase --continue\")"));
status_printf_ln(s, color,
_(" (use \"git rebase --skip\" to skip this patch)"));
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)) {
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 {
status_printf_ln(s, color, _("You are currently editing a commit during a rebase."));
if (advice_status_hints && !s->amend) {
status_printf_ln(s, color,
_(" (use \"git commit --amend\" to amend the current commit)"));
status_printf_ln(s, color,
_(" (use \"git rebase --continue\" once you are satisfied with your changes)"));
}
}
wt_status_print_trailer(s);
}

static void show_cherry_pick_in_progress(struct wt_status *s,
struct wt_status_state *state,
const char *color)
{
status_printf_ln(s, color, _("You are currently cherry-picking."));
if (advice_status_hints) {
if (has_unmerged(s))
status_printf_ln(s, color,
_(" (fix conflicts and run \"git commit\")"));
else
status_printf_ln(s, color,
_(" (all conflicts fixed: run \"git commit\")"));
}
wt_status_print_trailer(s);
}

static void show_bisect_in_progress(struct wt_status *s,
struct wt_status_state *state,
const char *color)
{
status_printf_ln(s, color, _("You are currently bisecting."));
if (advice_status_hints)
status_printf_ln(s, color,
_(" (use \"git bisect reset\" to get back to the original branch)"));
wt_status_print_trailer(s);
}

static void wt_status_print_state(struct wt_status *s)
{
const char *state_color = color(WT_STATUS_IN_PROGRESS, s);
struct wt_status_state state;
struct stat st;

memset(&state, 0, sizeof(state));

if (!stat(git_path("MERGE_HEAD"), &st)) {
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;
} else {
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;
else
state.rebase_in_progress = 1;
} else if (!stat(git_path("CHERRY_PICK_HEAD"), &st)) {
state.cherry_pick_in_progress = 1;
}
if (!stat(git_path("BISECT_LOG"), &st))
state.bisect_in_progress = 1;

if (state.merge_in_progress)
show_merge_in_progress(s, &state, state_color);
else if (state.am_in_progress)
show_am_in_progress(s, &state, state_color);
else if (state.rebase_in_progress || state.rebase_interactive_in_progress)
show_rebase_in_progress(s, &state, state_color);
else if (state.cherry_pick_in_progress)
show_cherry_pick_in_progress(s, &state, state_color);
if (state.bisect_in_progress)
show_bisect_in_progress(s, &state, state_color);
}

void wt_status_print(struct wt_status *s)
{
const char *branch_color = color(WT_STATUS_ONBRANCH, s);
Expand All @@ -750,6 +905,7 @@ void wt_status_print(struct wt_status *s)
wt_status_print_tracking(s);
}

wt_status_print_state(s);
if (s->is_initial) {
status_printf_ln(s, color(WT_STATUS_HEADER, s), "");
status_printf_ln(s, color(WT_STATUS_HEADER, s), _("Initial commit"));
Expand Down
11 changes: 11 additions & 0 deletions wt-status.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ enum color_wt_status {
WT_STATUS_LOCAL_BRANCH,
WT_STATUS_REMOTE_BRANCH,
WT_STATUS_ONBRANCH,
WT_STATUS_IN_PROGRESS,
WT_STATUS_MAXSLOT
};

Expand Down Expand Up @@ -71,6 +72,16 @@ struct wt_status {
struct string_list ignored;
};

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;
};

void wt_status_prepare(struct wt_status *s);
void wt_status_print(struct wt_status *s);
void wt_status_collect(struct wt_status *s);
Expand Down

0 comments on commit 83c750a

Please sign in to comment.