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>
This commit is contained in:
Junio C Hamano 2007-01-19 01:20:23 -08:00
Родитель 16d7cc90dd
Коммит 76a44c5c0b
3 изменённых файлов: 109 добавлений и 33 удалений

Просмотреть файл

@ -11,7 +11,7 @@ SYNOPSIS
'git-show-branch' [--all] [--remotes] [--topo-order] [--current] 'git-show-branch' [--all] [--remotes] [--topo-order] [--current]
[--more=<n> | --list | --independent | --merge-base] [--more=<n> | --list | --independent | --merge-base]
[--no-name | --sha1-name] [--topics] [<rev> | <glob>]... [--no-name | --sha1-name] [--topics] [<rev> | <glob>]...
'git-show-branch' --reflog[=<n>] <ref> 'git-show-branch' --reflog[=<n>[,<base>]] [--list] <ref>
DESCRIPTION DESCRIPTION
----------- -----------
@ -97,8 +97,10 @@ OPTIONS
will show the revisions given by "git rev-list {caret}master will show the revisions given by "git rev-list {caret}master
topic1 topic2" topic1 topic2"
--reflog[=<n>] <ref>:: --reflog[=<n>[,<base>]] <ref>::
Shows <n> most recent ref-log entries for the given 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 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 only the primary branches. In addition, if you happen to be on
your topic branch, it is shown as well. 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 Author

Просмотреть файл

@ -346,18 +346,21 @@ static void sort_ref_range(int bottom, int top)
compare_ref_name); 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); struct commit *commit = lookup_commit_reference_gently(sha1, 1);
int i; int i;
if (!commit) if (!commit)
return 0; return 0;
if (!allow_dups) {
/* Avoid adding the same thing twice */ /* Avoid adding the same thing twice */
for (i = 0; i < ref_name_cnt; i++) for (i = 0; i < ref_name_cnt; i++)
if (!strcmp(refname, ref_name[i])) if (!strcmp(refname, ref_name[i]))
return 0; return 0;
}
if (MAX_REVS <= ref_name_cnt) { if (MAX_REVS <= ref_name_cnt) {
fprintf(stderr, "warning: ignoring %s; " fprintf(stderr, "warning: ignoring %s; "
"cannot handle more than %d refs\n", "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)) if (get_sha1(refname + ofs, tmp) || hashcmp(tmp, sha1))
ofs = 5; 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) 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)) if (get_sha1(refname + ofs, tmp) || hashcmp(tmp, sha1))
ofs = 5; 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) static int append_tag_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
{ {
if (strncmp(refname, "refs/tags/", 10)) if (strncmp(refname, "refs/tags/", 10))
return 0; 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; 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); return append_head_ref(refname, sha1, flag, cb_data);
if (!strncmp("refs/tags/", refname, 10)) if (!strncmp("refs/tags/", refname, 10))
return append_tag_ref(refname, sha1, flag, cb_data); 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) static void snarf_refs(int head, int remotes)
@ -507,7 +510,7 @@ static void append_one_rev(const char *av)
{ {
unsigned char revkey[20]; unsigned char revkey[20];
if (!get_sha1(av, revkey)) { if (!get_sha1(av, revkey)) {
append_ref(av, revkey, 0, NULL); append_ref(av, revkey, 0);
return; return;
} }
if (strchr(av, '*') || strchr(av, '?') || strchr(av, '[')) { 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; 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) int cmd_show_branch(int ac, const char **av, const char *prefix)
{ {
struct commit *rev[MAX_REVS], *commit; struct commit *rev[MAX_REVS], *commit;
char *reflog_msg[MAX_REVS];
struct commit_list *list = NULL, *seen = NULL; struct commit_list *list = NULL, *seen = NULL;
unsigned int rev_mask[MAX_REVS]; unsigned int rev_mask[MAX_REVS];
int num_rev, i, extra = 0; 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 topics = 0;
int dense = 1; int dense = 1;
int reflog = 0; int reflog = 0;
const char *reflog_base = NULL;
git_config(git_show_branch_config); 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")) { else if (!strcmp(arg, "--reflog")) {
reflog = DEFAULT_REFLOG; reflog = DEFAULT_REFLOG;
} }
else if (!strncmp(arg, "--reflog=", 9)) { else if (!strncmp(arg, "--reflog=", 9))
char *end; parse_reflog_param(arg + 9, &reflog, &reflog_base);
reflog = strtoul(arg + 9, &end, 10);
if (*end != '\0')
die("unrecognized reflog count '%s'", arg + 9);
}
else else
usage(show_branch_usage); usage(show_branch_usage);
ac--; av++; ac--; av++;
} }
ac--; av++; ac--; av++;
/* Only one of these is allowed */ if (!!extra || !!reflog) {
if (1 < independent + merge_base + (extra != 0) + (!!reflog)) /* "listing" mode is incompatible with
* independent nor merge-base modes.
*/
if (independent || merge_base)
usage(show_branch_usage); 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 nothing is specified, show all branches by default */
if (ac + all_heads + all_remotes == 0) 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) if (all_heads + all_remotes)
snarf_refs(all_heads, all_remotes); snarf_refs(all_heads, all_remotes);
if (reflog) { if (reflog) {
int reflen; unsigned char sha1[20];
if (!ac) char nth_desc[256];
char *ref;
int base = 0;
if (ac != 1)
die("--reflog option needs one branch name"); 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++) { for (i = 0; i < reflog; i++) {
char *name = xmalloc(reflen + 20); char *logmsg, *msg, *m;
sprintf(name, "%s@{%d}", *av, i); unsigned long timestamp;
append_one_rev(name); 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 { else {
@ -760,8 +822,14 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
printf("%c [%s] ", printf("%c [%s] ",
is_head ? '*' : '!', ref_name[i]); is_head ? '*' : '!', ref_name[i]);
} }
if (!reflog) {
/* header lines never need name */ /* header lines never need name */
show_one_commit(rev[i], 1); show_one_commit(rev[i], 1);
}
else
puts(reflog_msg[i]);
if (is_head) if (is_head)
head_at = i; head_at = i;
} }

5
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); die("Log %s is corrupt.", logfile);
date = strtoul(lastgt + 1, &tz_c, 10); date = strtoul(lastgt + 1, &tz_c, 10);
if (date <= at_time || cnt == 0) { if (date <= at_time || cnt == 0) {
tz = strtoul(tz_c, NULL, 10);
if (msg) if (msg)
*msg = ref_msg(rec, logend); *msg = ref_msg(rec, logend);
if (cutoff_time) 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) if (cutoff_tz)
*cutoff_tz = tz; *cutoff_tz = tz;
if (cutoff_cnt) if (cutoff_cnt)
*cutoff_cnt = reccnt; *cutoff_cnt = reccnt - 1;
if (lastrec) { if (lastrec) {
if (get_sha1_hex(lastrec, logged_sha1)) if (get_sha1_hex(lastrec, logged_sha1))
die("Log %s is corrupt.", logfile); die("Log %s is corrupt.", logfile);
if (get_sha1_hex(rec + 41, sha1)) if (get_sha1_hex(rec + 41, sha1))
die("Log %s is corrupt.", logfile); die("Log %s is corrupt.", logfile);
if (hashcmp(logged_sha1, sha1)) { if (hashcmp(logged_sha1, sha1)) {
tz = strtoul(tz_c, NULL, 10);
fprintf(stderr, fprintf(stderr,
"warning: Log %s has gap after %s.\n", "warning: Log %s has gap after %s.\n",
logfile, show_rfc2822_date(date, tz)); 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)) if (get_sha1_hex(rec + 41, logged_sha1))
die("Log %s is corrupt.", logfile); die("Log %s is corrupt.", logfile);
if (hashcmp(logged_sha1, sha1)) { if (hashcmp(logged_sha1, sha1)) {
tz = strtoul(tz_c, NULL, 10);
fprintf(stderr, fprintf(stderr,
"warning: Log %s unexpectedly ended on %s.\n", "warning: Log %s unexpectedly ended on %s.\n",
logfile, show_rfc2822_date(date, tz)); logfile, show_rfc2822_date(date, tz));