summaryrefslogtreecommitdiff
path: root/wt-status.c
diff options
context:
space:
mode:
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>2013-03-13 18:42:52 +0700
committerJunio C Hamano <gitster@pobox.com>2013-03-16 22:11:02 -0700
commitb397ea4863a143e97cb9da76c6c18cc555537d64 (patch)
tree3b3c8fdaca654e980e4dc108b0d8674c4220c9fa /wt-status.c
parent3b691cccb02e660002a7ff414ad21ddac932dc6c (diff)
downloadgit-b397ea4863a143e97cb9da76c6c18cc555537d64.tar.gz
status: show more info than "currently not on any branch"
When a remote ref or a tag is checked out, HEAD is automatically detached. There is no user-friendly way to find out what ref is checked out in this case. This patch digs in reflog for this information and shows "HEAD detached from origin/master" or "HEAD detached at v1.8.0" instead of "currently not on any branch". When it cannot figure out the original ref, it shows an abbreviated SHA-1. "Currently not on any branch" would never display (unless reflog is pruned to near empty that the last checkout entry is lost). Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'wt-status.c')
-rw-r--r--wt-status.c89
1 files changed, 85 insertions, 4 deletions
diff --git a/wt-status.c b/wt-status.c
index 40dced3ef9..32a51e1323 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -999,7 +999,73 @@ got_nothing:
return NULL;
}
-void wt_status_get_state(struct wt_status_state *state)
+struct grab_1st_switch_cbdata {
+ int found;
+ struct strbuf buf;
+ unsigned char nsha1[20];
+};
+
+static int grab_1st_switch(unsigned char *osha1, unsigned char *nsha1,
+ const char *email, unsigned long timestamp, int tz,
+ const char *message, void *cb_data)
+{
+ struct grab_1st_switch_cbdata *cb = cb_data;
+ const char *target = NULL, *end;
+
+ if (prefixcmp(message, "checkout: moving from "))
+ return 0;
+ message += strlen("checkout: moving from ");
+ target = strstr(message, " to ");
+ if (!target)
+ return 0;
+ target += strlen(" to ");
+ strbuf_reset(&cb->buf);
+ hashcpy(cb->nsha1, nsha1);
+ for (end = target; *end && *end != '\n'; end++)
+ ;
+ strbuf_add(&cb->buf, target, end - target);
+ cb->found = 1;
+ return 1;
+}
+
+static void wt_status_get_detached_from(struct wt_status_state *state)
+{
+ struct grab_1st_switch_cbdata cb;
+ struct commit *commit;
+ unsigned char sha1[20];
+ char *ref = NULL;
+
+ strbuf_init(&cb.buf, 0);
+ if (for_each_reflog_ent_reverse("HEAD", grab_1st_switch, &cb) <= 0) {
+ strbuf_release(&cb.buf);
+ return;
+ }
+
+ if (dwim_ref(cb.buf.buf, cb.buf.len, sha1, &ref) == 1 &&
+ /* sha1 is a commit? match without further lookup */
+ (!hashcmp(cb.nsha1, sha1) ||
+ /* perhaps sha1 is a tag, try to dereference to a commit */
+ ((commit = lookup_commit_reference_gently(sha1, 1)) != NULL &&
+ !hashcmp(cb.nsha1, commit->object.sha1)))) {
+ int ofs;
+ if (!prefixcmp(ref, "refs/tags/"))
+ ofs = strlen("refs/tags/");
+ else if (!prefixcmp(ref, "refs/remotes/"))
+ ofs = strlen("refs/remotes/");
+ else
+ ofs = 0;
+ state->detached_from = xstrdup(ref + ofs);
+ } else
+ state->detached_from =
+ xstrdup(find_unique_abbrev(cb.nsha1, DEFAULT_ABBREV));
+ hashcpy(state->detached_sha1, cb.nsha1);
+
+ free(ref);
+ strbuf_release(&cb.buf);
+}
+
+void wt_status_get_state(struct wt_status_state *state,
+ int get_detached_from)
{
struct stat st;
@@ -1029,6 +1095,9 @@ void wt_status_get_state(struct wt_status_state *state)
state->bisect_in_progress = 1;
state->branch = read_and_strip_branch("BISECT_START");
}
+
+ if (get_detached_from)
+ wt_status_get_detached_from(state);
}
static void wt_status_print_state(struct wt_status *s,
@@ -1054,7 +1123,8 @@ void wt_status_print(struct wt_status *s)
struct wt_status_state state;
memset(&state, 0, sizeof(state));
- wt_status_get_state(&state);
+ wt_status_get_state(&state,
+ s->branch && !strcmp(s->branch, "HEAD"));
if (s->branch) {
const char *on_what = _("On branch ");
@@ -1062,9 +1132,19 @@ void wt_status_print(struct wt_status *s)
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.");
+ if (state.detached_from) {
+ unsigned char sha1[20];
+ branch_name = state.detached_from;
+ if (!get_sha1("HEAD", sha1) &&
+ !hashcmp(sha1, state.detached_sha1))
+ on_what = _("HEAD detached at ");
+ else
+ on_what = _("HEAD detached from ");
+ } else {
+ branch_name = "";
+ 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);
@@ -1076,6 +1156,7 @@ void wt_status_print(struct wt_status *s)
wt_status_print_state(s, &state);
free(state.branch);
free(state.onto);
+ free(state.detached_from);
if (s->is_initial) {
status_printf_ln(s, color(WT_STATUS_HEADER, s), "");