aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/git-show-branch.txt15
-rw-r--r--builtin-show-branch.c122
-rw-r--r--refs.c5
3 files changed, 109 insertions, 33 deletions
diff --git a/Documentation/git-show-branch.txt b/Documentation/git-show-branch.txt
index 912e15bcb..529f3a648 100644
--- a/Documentation/git-show-branch.txt
+++ b/Documentation/git-show-branch.txt
@@ -11,7 +11,7 @@ SYNOPSIS
'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
-----------
@@ -97,8 +97,10 @@ OPTIONS
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
@@ -165,6 +167,13 @@ With this, `git show-branch` without extra parameters would show
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
diff --git a/builtin-show-branch.c b/builtin-show-branch.c
index c67f2fa2f..452c15fd1 100644
--- a/builtin-show-branch.c
+++ b/builtin-show-branch.c
@@ -346,18 +346,21 @@ static void sort_ref_range(int bottom, int top)
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",
@@ -380,7 +383,7 @@ static int append_head_ref(const char *refname, const unsigned char *sha1, int f
*/
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)
@@ -394,14 +397,14 @@ static int append_remote_ref(const char *refname, const unsigned char *sha1, int
*/
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;
@@ -434,7 +437,7 @@ static int append_matching_ref(const char *refname, const unsigned char *sha1, i
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)
@@ -507,7 +510,7 @@ static void append_one_rev(const char *av)
{
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, '[')) {
@@ -562,9 +565,24 @@ static int omit_in_dense(struct commit *commit, struct commit **rev, int n)
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;
@@ -585,6 +603,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
int topics = 0;
int dense = 1;
int reflog = 0;
+ const char *reflog_base = NULL;
git_config(git_show_branch_config);
@@ -631,21 +650,27 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
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)
@@ -654,14 +679,51 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
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 {
@@ -760,8 +822,14 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
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;
}
diff --git a/refs.c b/refs.c
index 60375a786..81173282f 100644
--- a/refs.c
+++ b/refs.c
@@ -1068,6 +1068,7 @@ int read_ref_at(const char *ref, unsigned long at_time, int cnt, unsigned char *
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)
@@ -1075,14 +1076,13 @@ int read_ref_at(const char *ref, unsigned long at_time, int cnt, unsigned char *
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));
@@ -1096,7 +1096,6 @@ int read_ref_at(const char *ref, unsigned long at_time, int cnt, unsigned char *
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));