Commits

Anonymous committed 76a44c5

show-branch --reflog: show the reflog message at the top.

This changes the output so the list at the top shows the reflog
message, along with their relative timestamps.

You can use --reflog=<n> to show <n> most recent log entries, or
use --reflog=<n>,<b> to show <n> entries going back from the
entry <b>. <b> can be either a number (so --reflog=4,20 shows 4
records starting from @{20}) or a timestamp (e.g. --reflog='4,1 day').

Here is a sample output (with --list option):

$ git show-branch --reflog=10 --list jc/show-reflog
[jc/show-reflog@{0}] (3 minutes ago) commit (amend): show-branch --ref
[jc/show-reflog@{1}] (5 minutes ago) reset HEAD^
[jc/show-reflog@{2}] (14 minutes ago) commit: show-branch --reflog: sho
[jc/show-reflog@{3}] (14 minutes ago) commit: show-branch --reflog: sho
[jc/show-reflog@{4}] (18 minutes ago) commit (amend): Extend read_ref_a
[jc/show-reflog@{5}] (18 minutes ago) commit (amend): Extend read_ref_a
[jc/show-reflog@{6}] (18 minutes ago) commit (amend): Extend read_ref_a
[jc/show-reflog@{7}] (18 minutes ago) am: read_ref_at(): allow retrievi
[jc/show-reflog@{8}] (18 minutes ago) reset --hard HEAD~4
[jc/show-reflog@{9}] (61 minutes ago) commit: show-branch --reflog: use

This shows what I did more cleanly:

$ git show-branch --reflog=10 jc/show-reflog
! [jc/show-reflog@{0}] (3 minutes ago) commit (amend): show-branch --ref
! [jc/show-reflog@{1}] (5 minutes ago) reset HEAD^
! [jc/show-reflog@{2}] (14 minutes ago) commit: show-branch --reflog:
! [jc/show-reflog@{3}] (14 minutes ago) commit: show-branch --reflog:
! [jc/show-reflog@{4}] (18 minutes ago) commit (amend): Extend read_
! [jc/show-reflog@{5}] (18 minutes ago) commit (amend): Extend read
! [jc/show-reflog@{6}] (18 minutes ago) commit (amend): Extend rea
! [jc/show-reflog@{7}] (18 minutes ago) am: read_ref_at(): allow
! [jc/show-reflog@{8}] (18 minutes ago) reset --hard HEAD~4
! [jc/show-reflog@{9}] (61 minutes ago) commit: show-branch --r
----------
+ [jc/show-reflog@{0}] show-branch --reflog: show the reflog
+ [jc/show-reflog@{2}] show-branch --reflog: show the reflog
+++ [jc/show-reflog@{1}] show-branch --reflog: show the reflog
+++++ [jc/show-reflog@{4}] Extend read_ref_at() to be usable fro
+ [jc/show-reflog@{5}] Extend read_ref_at() to be usable fro
+ [jc/show-reflog@{6}] Extend read_ref_at() to be usable fro
+ [jc/show-reflog@{7}] read_ref_at(): allow retrieving the r
+ [jc/show-reflog@{9}] show-branch --reflog: use updated rea
+ [jc/show-reflog@{9}^] read_ref_at(): allow reporting the c
+ [jc/show-reflog@{9}~2] show-branch --reflog: show the refl
+ [jc/show-reflog@{9}~3] read_ref_at(): allow retrieving the
++++++++++ [jc/show-reflog@{8}] dwim_ref(): Separate name-to-ref DWIM

At @{9}, I had a commit to complete 5 patch series, but I wanted
to consolidate two commits that enhances read_ref_at() into one
(they were @{9}^ and @{9}~3), and another two that touch show-branch
into one (@{9} and @{9}~2).

I first saved them with "format-patch -4", and then did a reset
at @{8}. At @{7}, I applied one of them with "am", and then
used "git-apply" on the other one, and amended the commit at
@{6} (so @{6} and @{7} has the same parent). I did not like the
log message, so I amended again at @{5}.

Then I cherry-picked @{9}~2 to create @{3} (the log message
shows that it needs to learn to set GIT_REFLOG_ACTION -- it uses
"git-commit" and the log entry is attributed for it). Another
cherry-pick built @{2} out of @{9}, but what I wanted to do was
to squash these two into one, so I did a "reset HEAD^" at @{1}
and then made the final commit by amending what was at the top.

Signed-off-by: Junio C Hamano <junkio@cox.net>

Comments (0)

Files changed (3)

Documentation/git-show-branch.txt

 'git-show-branch' [--all] [--remotes] [--topo-order] [--current]
 		[--more=<n> | --list | --independent | --merge-base]
 		[--no-name | --sha1-name] [--topics] [<rev> | <glob>]...
-'git-show-branch' --reflog[=<n>] <ref>
+'git-show-branch' --reflog[=<n>[,<base>]] [--list] <ref>
 
 DESCRIPTION
 -----------
 	will show the revisions given by "git rev-list {caret}master
 	topic1 topic2"
 
---reflog[=<n>] <ref>::
-	Shows <n> most recent ref-log entries for the given ref.
+--reflog[=<n>[,<base>]] <ref>::
+	Shows <n> most recent ref-log entries for the given
+	ref.  If <base> is given, <n> entries going back from
+	that entry.  <base> can be specified as count or date
 
 
 Note that --more, --list, --independent and --merge-base options
 only the primary branches.  In addition, if you happen to be on
 your topic branch, it is shown as well.
 
+------------
+$ git show-branch --reflog='10,1 hour ago' --list master
+------------
+
+shows 10 reflog entries going back from the tip as of 1 hour ago.
+Without `--list`, the output also shows how these tips are
+topologically related with each other.
 
 
 Author

builtin-show-branch.c

 	      compare_ref_name);
 }
 
-static int append_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
+static int append_ref(const char *refname, const unsigned char *sha1,
+		      int allow_dups)
 {
 	struct commit *commit = lookup_commit_reference_gently(sha1, 1);
 	int i;
 
 	if (!commit)
 		return 0;
-	/* Avoid adding the same thing twice */
-	for (i = 0; i < ref_name_cnt; i++)
-		if (!strcmp(refname, ref_name[i]))
-			return 0;
 
+	if (!allow_dups) {
+		/* Avoid adding the same thing twice */
+		for (i = 0; i < ref_name_cnt; i++)
+			if (!strcmp(refname, ref_name[i]))
+				return 0;
+	}
 	if (MAX_REVS <= ref_name_cnt) {
 		fprintf(stderr, "warning: ignoring %s; "
 			"cannot handle more than %d refs\n",
 	 */
 	if (get_sha1(refname + ofs, tmp) || hashcmp(tmp, sha1))
 		ofs = 5;
-	return append_ref(refname + ofs, sha1, flag, cb_data);
+	return append_ref(refname + ofs, sha1, 0);
 }
 
 static int append_remote_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
 	 */
 	if (get_sha1(refname + ofs, tmp) || hashcmp(tmp, sha1))
 		ofs = 5;
-	return append_ref(refname + ofs, sha1, flag, cb_data);
+	return append_ref(refname + ofs, sha1, 0);
 }
 
 static int append_tag_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
 {
 	if (strncmp(refname, "refs/tags/", 10))
 		return 0;
-	return append_ref(refname + 5, sha1, flag, cb_data);
+	return append_ref(refname + 5, sha1, 0);
 }
 
 static const char *match_ref_pattern = NULL;
 		return append_head_ref(refname, sha1, flag, cb_data);
 	if (!strncmp("refs/tags/", refname, 10))
 		return append_tag_ref(refname, sha1, flag, cb_data);
-	return append_ref(refname, sha1, flag, cb_data);
+	return append_ref(refname, sha1, 0);
 }
 
 static void snarf_refs(int head, int remotes)
 {
 	unsigned char revkey[20];
 	if (!get_sha1(av, revkey)) {
-		append_ref(av, revkey, 0, NULL);
+		append_ref(av, revkey, 0);
 		return;
 	}
 	if (strchr(av, '*') || strchr(av, '?') || strchr(av, '[')) {
 	return 0;
 }
 
+static void parse_reflog_param(const char *arg, int *cnt, const char **base)
+{
+	char *ep;
+	*cnt = strtoul(arg, &ep, 10);
+	if (*ep == ',')
+		*base = ep + 1;
+	else if (*ep)
+		die("unrecognized reflog param '%s'", arg + 9);
+	else
+		*base = NULL;
+	if (*cnt <= 0)
+		*cnt = DEFAULT_REFLOG;
+}
+
 int cmd_show_branch(int ac, const char **av, const char *prefix)
 {
 	struct commit *rev[MAX_REVS], *commit;
+	char *reflog_msg[MAX_REVS];
 	struct commit_list *list = NULL, *seen = NULL;
 	unsigned int rev_mask[MAX_REVS];
 	int num_rev, i, extra = 0;
 	int topics = 0;
 	int dense = 1;
 	int reflog = 0;
+	const char *reflog_base = NULL;
 
 	git_config(git_show_branch_config);
 
 		else if (!strcmp(arg, "--reflog")) {
 			reflog = DEFAULT_REFLOG;
 		}
-		else if (!strncmp(arg, "--reflog=", 9)) {
-			char *end;
-			reflog = strtoul(arg + 9, &end, 10);
-			if (*end != '\0')
-				die("unrecognized reflog count '%s'", arg + 9);
-		}
+		else if (!strncmp(arg, "--reflog=", 9))
+			parse_reflog_param(arg + 9, &reflog, &reflog_base);
 		else
 			usage(show_branch_usage);
 		ac--; av++;
 	}
 	ac--; av++;
 
-	/* Only one of these is allowed */
-	if (1 < independent + merge_base + (extra != 0) + (!!reflog))
-		usage(show_branch_usage);
+	if (!!extra || !!reflog) {
+		/* "listing" mode is incompatible with
+		 * independent nor merge-base modes.
+		 */
+		if (independent || merge_base)
+			usage(show_branch_usage);
+		if (!!reflog && (0 < extra))
+			/*
+			 * Asking for --more in reflog mode does not
+			 * make sense.
+			 */
+			usage(show_branch_usage);
+	}
 
 	/* If nothing is specified, show all branches by default */
 	if (ac + all_heads + all_remotes == 0)
 	if (all_heads + all_remotes)
 		snarf_refs(all_heads, all_remotes);
 	if (reflog) {
-		int reflen;
-		if (!ac)
+		unsigned char sha1[20];
+		char nth_desc[256];
+		char *ref;
+		int base = 0;
+		if (ac != 1)
 			die("--reflog option needs one branch name");
-		reflen = strlen(*av);
+		if (!dwim_ref(*av, strlen(*av), sha1, &ref))
+			die("No such ref %s", *av);
+
+		/* Has the base been specified? */
+		if (reflog_base) {
+			char *ep;
+			base = strtoul(reflog_base, &ep, 10);
+			if (*ep) {
+				/* Ah, that is a date spec... */
+				unsigned long at;
+				at = approxidate(reflog_base);
+				read_ref_at(ref, at, -1, sha1, NULL,
+					    NULL, NULL, &base);
+			}
+		}
+
 		for (i = 0; i < reflog; i++) {
-			char *name = xmalloc(reflen + 20);
-			sprintf(name, "%s@{%d}", *av, i);
-			append_one_rev(name);
+			char *logmsg, *msg, *m;
+			unsigned long timestamp;
+			int tz;
+
+			if (read_ref_at(ref, 0, base+i, sha1, &logmsg,
+					&timestamp, &tz, NULL)) {
+				reflog = i;
+				break;
+			}
+			msg = strchr(logmsg, '\t');
+			if (!msg)
+				msg = "(none)";
+			else
+				msg++;
+			m = xmalloc(strlen(msg) + 200);
+			sprintf(m, "(%s) %s",
+				show_date(timestamp, 0, 1),
+				msg);
+			reflog_msg[i] = m;
+			free(logmsg);
+			sprintf(nth_desc, "%s@{%d}", *av, base+i);
+			append_ref(nth_desc, sha1, 1);
 		}
 	}
 	else {
 				printf("%c [%s] ",
 				       is_head ? '*' : '!', ref_name[i]);
 			}
-			/* header lines never need name */
-			show_one_commit(rev[i], 1);
+
+			if (!reflog) {
+				/* header lines never need name */
+				show_one_commit(rev[i], 1);
+			}
+			else
+				puts(reflog_msg[i]);
+
 			if (is_head)
 				head_at = i;
 		}
 			die("Log %s is corrupt.", logfile);
 		date = strtoul(lastgt + 1, &tz_c, 10);
 		if (date <= at_time || cnt == 0) {
+			tz = strtoul(tz_c, NULL, 10);
 			if (msg)
 				*msg = ref_msg(rec, logend);
 			if (cutoff_time)
 			if (cutoff_tz)
 				*cutoff_tz = tz;
 			if (cutoff_cnt)
-				*cutoff_cnt = reccnt;
+				*cutoff_cnt = reccnt - 1;
 			if (lastrec) {
 				if (get_sha1_hex(lastrec, logged_sha1))
 					die("Log %s is corrupt.", logfile);
 				if (get_sha1_hex(rec + 41, sha1))
 					die("Log %s is corrupt.", logfile);
 				if (hashcmp(logged_sha1, sha1)) {
-					tz = strtoul(tz_c, NULL, 10);
 					fprintf(stderr,
 						"warning: Log %s has gap after %s.\n",
 						logfile, show_rfc2822_date(date, tz));
 				if (get_sha1_hex(rec + 41, logged_sha1))
 					die("Log %s is corrupt.", logfile);
 				if (hashcmp(logged_sha1, sha1)) {
-					tz = strtoul(tz_c, NULL, 10);
 					fprintf(stderr,
 						"warning: Log %s unexpectedly ended on %s.\n",
 						logfile, show_rfc2822_date(date, tz));