[prev in list] [next in list] [prev in thread] [next in thread] 

List:       git
Subject:    [PATCH v2] status: display "doing what" information in git status
From:       Pierre Habouzit <madcoder () debian ! org>
Date:       2011-05-06 7:38:55
Message-ID: 1304667535-4787-1-git-send-email-madcoder () debian ! org
[Download RAW message or body]

This provides the same information as the git bash prompt about the
current operation that is going on: rebase, merge, am, cherry-pick or
bisect.

This is very useful for "beginners" who don't have their shell prompt set
up for git.

The logic has been largely borrowed from
contrib/completion/git-completion.bash

when hints are enabled, it also gives hints on how to abort or resolve
that pending situation. For example, with this patch and hints activated,
being in the middle of a `git rebase -i` looks like:

	$ git status
	# in the middle of a git rebase -i of master (detached head)
	#   (use "git rebase --abort" to abort current rebase or proceed)
	# Changes not staged for commit:
	#   (use "git add <file>..." to update what will be committed)
	#   (use "git checkout -- <file>..." to discard changes in working directory)
	#
	#       modified:   lib-common (new commits)
	#
	# Submodules changed but not updated:
	#
	# * lib-common 0b07a6b...11cdf27 (1):
	#   > Add t_sb_init().
	#
	# Untracked files:
	#   (use "git add <file>..." to include in what will be committed)
	#
	#       qdb/a/
	#       qkv/A/
	no changes added to commit (use "git add" and/or "git commit -a")

If we have an ongoing operation then:
- if we are on a branch it displays:
  # On branch $branch ($what_is_ongoing)
  #   ($ongoing_hint)
- if we are on a detached head it displays:
  # $what_is_ongoing (detached head)
  #   ($ongoing_hint)

If we have no ongoing operation the git status does as before:
- if we are on a branch it displays:
  # On branch $branch
- if we are on a detached head it displays:
  # Not currently on any branch.

Since the ongoing operation is usually something to be done with before
continuing with further git operations, the hint and ongoing operations
are displayed with the "WT_STATUS_NOBRANCH" color to be easy to spot.

Signed-off-by: Pierre Habouzit <madcoder@debian.org>
---
 wt-status.c |  138 ++++++++++++++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 123 insertions(+), 15 deletions(-)

diff --git a/wt-status.c b/wt-status.c
index 9f4e0ba..91f6c7c 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -527,6 +527,128 @@ static void wt_status_print_unmerged(struct wt_status *s)
 
 }
 
+static int wt_has_file(const char *what)
+{
+	char path[PATH_MAX];
+
+	return access(git_snpath(path, sizeof(path), "%s", what), F_OK) == 0;
+}
+
+static void wt_status_print_doingwhat(struct wt_status *s)
+{
+	const char *status_nobranch = color(WT_STATUS_NOBRANCH, s);
+	const char *branch_name = s->branch;
+	const char *advice = NULL;
+
+	const char * const rebase_advice =
+		_("use \"git rebase --abort\" to abort current rebase or proceed");
+	const char * const am_advice =
+		_("use \"git am --abort\" to abort current mailbox apply or proceed");
+	const char * const merge_advice =
+		_("use \"git reset --hard\" to abort, or resolve conflicts and commit");
+
+	struct strbuf sb = STRBUF_INIT;
+	char path[PATH_MAX];
+
+	if (!prefixcmp(branch_name, "refs/heads/"))
+		branch_name += 11;
+	else if (!strcmp(branch_name, "HEAD")) {
+		branch_name = NULL;
+	}
+
+	status_printf(s, color(WT_STATUS_HEADER, s), "");
+	if (branch_name) {
+		const char *status_onbranch = color(WT_STATUS_ONBRANCH, s);
+
+		status_printf_more(s, status_onbranch, _("On branch "));
+		status_printf_more(s, status_onbranch, "%s", branch_name);
+	}
+	if (wt_has_file("rebase-merge")) {
+		git_snpath(path, sizeof(path), "%s", "rebase-merge/head-name");
+		strbuf_read_file(&sb, path, 0);
+		strbuf_rtrim(&sb);
+
+		if (branch_name)
+			status_printf_more(s, status_nobranch, " (");
+		status_printf_more(s, status_nobranch,
+				   _("in the middle of a git rebase -%c of %s"),
+				   wt_has_file("rebase-merge/interactive") ? 'i' : 'm',
+				   prefixcmp(sb.buf, "refs/heads/") == 0 ?
+				   sb.buf + 11 : sb.buf);
+		advice = rebase_advice;
+	} else if (wt_has_file("rebase-apply")) {
+		if (branch_name)
+			status_printf_more(s, status_nobranch, " (");
+		if (wt_has_file("rebase-apply/rebasing")) {
+			status_printf_more(s, status_nobranch,
+					   _("in the middle of a git rebase"));
+			advice = rebase_advice;
+		} else if (wt_has_file("rebase-apply/applying")) {
+			status_printf_more(s, status_nobranch,
+					   _("in the middle of a git am"));
+			advice = am_advice;
+		} else {
+			status_printf_more(s, status_nobranch,
+					   _("in the middle of a git rebase/am"));
+			advice = am_advice;
+		}
+	} else if (wt_has_file("MERGE_HEAD")) {
+		git_snpath(path, sizeof(path), "%s", "MERGE_HEAD");
+		strbuf_read_file(&sb, path, 0);
+		strbuf_rtrim(&sb);
+
+		if (branch_name)
+			status_printf_more(s, status_nobranch, " (");
+		status_printf_more(s, status_nobranch,
+				   _("resolving merge with %s"),
+				   prefixcmp(sb.buf, "refs/heads/") == 0 ?
+				   sb.buf + 11 : sb.buf);
+		advice = merge_advice;
+	} else if (wt_has_file("CHERRY_PICK_HEAD")) {
+		unsigned char sha1buf[20];
+
+		git_snpath(path, sizeof(path), "%s", "CHERRY_PICK_HEAD");
+		strbuf_read_file(&sb, path, 0);
+		strbuf_rtrim(&sb);
+
+		if (branch_name)
+			status_printf_more(s, status_nobranch, " (");
+		if (sb.len == 40 && get_sha1_hex(sb.buf, sha1buf) == 0) {
+			status_printf_more(s, status_nobranch,
+					   _("resolving cherry-pick of %s"),
+					   find_unique_abbrev(sha1buf, DEFAULT_ABBREV));
+		} else {
+			status_printf_more(s, status_nobranch,
+					   _("resolving cherry-pick of %s"),
+					   sb.buf);
+		}
+		advice = merge_advice;
+	} else if (wt_has_file("BISECT_LOG")) {
+		if (branch_name)
+			status_printf_more(s, status_nobranch, " (");
+		status_printf_more(s, status_nobranch,
+					   _("in the middle of a git bisect"));
+	} else {
+		if (!branch_name) {
+			status_printf_more(s, status_nobranch,
+					   _("Not currently on any branch."));
+		}
+		status_printf_more(s, "", "\n");
+		return;
+	}
+
+	if (branch_name) {
+		status_printf_more(s, status_nobranch, ")\n");
+	} else {
+		status_printf_more(s, status_nobranch, _(" (detached head)\n"));
+	}
+	if (advice && advice_status_hints) {
+		status_printf(s, color(WT_STATUS_HEADER, s), "");
+		status_printf_more(s, status_nobranch, "  (%s)\n", advice);
+	}
+	strbuf_release(&sb);
+}
+
 static void wt_status_print_updated(struct wt_status *s)
 {
 	int shown_header = 0;
@@ -706,22 +828,8 @@ static void wt_status_print_tracking(struct wt_status *s)
 
 void wt_status_print(struct wt_status *s)
 {
-	const char *branch_color = color(WT_STATUS_ONBRANCH, s);
-	const char *branch_status_color = color(WT_STATUS_HEADER, s);
-
 	if (s->branch) {
-		const char *on_what = _("On branch ");
-		const char *branch_name = s->branch;
-		if (!prefixcmp(branch_name, "refs/heads/"))
-			branch_name += 11;
-		else if (!strcmp(branch_name, "HEAD")) {
-			branch_name = "";
-			branch_status_color = color(WT_STATUS_NOBRANCH, s);
-			on_what = _("Not currently on any branch.");
-		}
-		status_printf(s, color(WT_STATUS_HEADER, s), "");
-		status_printf_more(s, branch_status_color, "%s", on_what);
-		status_printf_more(s, branch_color, "%s\n", branch_name);
+		wt_status_print_doingwhat(s);
 		if (!s->is_initial)
 			wt_status_print_tracking(s);
 	}
-- 
1.7.5.1.290.gfe86e2.dirty

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic