show-branch: optionally use unique prefix as name.

git-show-branch acquires two new options. --sha1-name to name
commits using the unique prefix of their object names, and
--no-name to not to show names at all.

This was outlined in <7vk6gpyuyr.fsf@assigned-by-dhcp.cox.net>

Signed-off-by: Junio C Hamano <junkio@cox.net>
This commit is contained in:
Junio C Hamano 2005-10-11 15:22:48 -07:00
parent f2d6a25627
commit 013f276eb7
4 changed files with 82 additions and 44 deletions

View file

@ -7,7 +7,7 @@ git-show-branch - Show branches and their commits.
SYNOPSIS
--------
'git-show-branch [--all] [--heads] [--tags] [--more=<n> | --list | --independent | --merge-base] <reference>...'
'git-show-branch [--all] [--heads] [--tags] [--more=<n> | --list | --independent | --merge-base] [--no-name | --sha1-name] <reference>...'
DESCRIPTION
-----------
@ -44,6 +44,15 @@ OPTIONS
Among the <reference>s given, display only the ones that
cannot be reached from any other <reference>.
--no-name::
Do not show naming strings for each commit.
--sha1-name::
Instead of naming the commits using the path to reach
them from heads (e.g. "master~2" to mean the grandparent
of "master"), name them with the unique prefix of their
object names.
Note that --more, --list, --independent and --merge-base options
are mutually exclusive.
@ -88,21 +97,6 @@ whose commit message is "Add 'git show-branch'. "fixes" branch
adds one commit 'Introduce "reset type"'. "mhf" branch has many
other commits.
When only one head is given, the output format changes slightly
to conserve space. The '+' sign to show which commit is
reachable from which head and the first N lines to show the list
of heads being displayed are both meaningless so they are
omitted. Also the label given to each commit does not repeat
the name of the branch because it is obvious.
------------------------------------------------
$ git show-branch --more=4 master
[master] Add 'git show-branch'.
[~1] Add a new extended SHA1 syntax <name>~<num>
[~2] Fix "git-diff A B"
[~3] git-ls-files: generalized pathspecs
[~4] Make "git-ls-files" work in subdirectories
------------------------------------------------
Author
------

View file

@ -194,6 +194,7 @@ extern char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)
extern char *sha1_file_name(const unsigned char *sha1);
extern char *sha1_pack_name(const unsigned char *sha1);
extern char *sha1_pack_index_name(const unsigned char *sha1);
extern const char *find_unique_abbrev(const unsigned char *sha1, int);
extern const unsigned char null_sha1[20];
int git_mkstemp(char *path, size_t n, const char *template);

View file

@ -119,6 +119,9 @@ static int find_short_packed_object(int len, const unsigned char *match, unsigne
return found;
}
#define SHORT_NAME_NOT_FOUND (-1)
#define SHORT_NAME_AMBIGUOUS (-2)
static int find_unique_short_object(int len, char *canonical,
unsigned char *res, unsigned char *sha1)
{
@ -128,23 +131,24 @@ static int find_unique_short_object(int len, char *canonical,
has_unpacked = find_short_object_filename(len, canonical, unpacked_sha1);
has_packed = find_short_packed_object(len, res, packed_sha1);
if (!has_unpacked && !has_packed)
return -1;
return SHORT_NAME_NOT_FOUND;
if (1 < has_unpacked || 1 < has_packed)
return error("short SHA1 %.*s is ambiguous.", len, canonical);
return SHORT_NAME_AMBIGUOUS;
if (has_unpacked != has_packed) {
memcpy(sha1, (has_packed ? packed_sha1 : unpacked_sha1), 20);
return 0;
}
/* Both have unique ones -- do they match? */
if (memcmp(packed_sha1, unpacked_sha1, 20))
return error("short SHA1 %.*s is ambiguous.", len, canonical);
return -2;
memcpy(sha1, packed_sha1, 20);
return 0;
}
static int get_short_sha1(const char *name, int len, unsigned char *sha1)
static int get_short_sha1(const char *name, int len, unsigned char *sha1,
int quietly)
{
int i;
int i, status;
char canonical[40];
unsigned char res[20];
@ -171,7 +175,29 @@ static int get_short_sha1(const char *name, int len, unsigned char *sha1)
res[i >> 1] |= val;
}
return find_unique_short_object(i, canonical, res, sha1);
status = find_unique_short_object(i, canonical, res, sha1);
if (!quietly && (status == SHORT_NAME_AMBIGUOUS))
return error("short SHA1 %.*s is ambiguous.", len, canonical);
return status;
}
const char *find_unique_abbrev(const unsigned char *sha1, int len)
{
int status;
static char hex[41];
memcpy(hex, sha1_to_hex(sha1), 40);
while (len < 40) {
unsigned char sha1_ret[20];
status = get_short_sha1(hex, len, sha1_ret, 1);
if (!status) {
hex[len] = 0;
return hex;
}
if (status != SHORT_NAME_AMBIGUOUS)
return NULL;
len++;
}
return NULL;
}
static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
@ -292,7 +318,7 @@ static int get_sha1_1(const char *name, int len, unsigned char *sha1)
ret = get_sha1_basic(name, len, sha1);
if (!ret)
return 0;
return get_short_sha1(name, len, sha1);
return get_short_sha1(name, len, sha1, 0);
}
/*

View file

@ -133,25 +133,28 @@ static void name_commits(struct commit_list *list,
nth = 0;
while (parents) {
struct commit *p = parents->item;
char newname[1000];
char newname[1000], *en;
parents = parents->next;
nth++;
if (p->object.util)
continue;
en = newname;
switch (n->generation) {
case 0:
sprintf(newname, "%s^%d",
n->head_name, nth);
en += sprintf(en, "%s", n->head_name);
break;
case 1:
sprintf(newname, "%s^^%d",
n->head_name, nth);
en += sprintf(en, "%s^", n->head_name);
break;
default:
sprintf(newname, "%s~%d^%d",
n->head_name, n->generation,
nth);
en += sprintf(en, "%s~%d",
n->head_name, n->generation);
break;
}
if (nth == 1)
en += sprintf(en, "^");
else
en += sprintf(en, "^%d", nth);
name_commit(p, strdup(newname), 0);
i++;
name_first_parent_chain(p);
@ -205,7 +208,7 @@ static void join_revs(struct commit_list **list_p,
}
}
static void show_one_commit(struct commit *commit)
static void show_one_commit(struct commit *commit, int no_name)
{
char pretty[128], *cp;
struct commit_name *name = commit->object.util;
@ -218,11 +221,21 @@ static void show_one_commit(struct commit *commit)
cp = pretty + 8;
else
cp = pretty;
if (name && name->head_name) {
printf("[%s", name->head_name);
if (name->generation)
printf("~%d", name->generation);
printf("] ");
if (!no_name) {
if (name && name->head_name) {
printf("[%s", name->head_name);
if (name->generation) {
if (name->generation == 1)
printf("^");
else
printf("~%d", name->generation);
}
printf("] ");
}
else
printf("[%s] ",
find_unique_abbrev(commit->object.sha1, 7));
}
puts(cp);
}
@ -354,7 +367,8 @@ int main(int ac, char **av)
unsigned char head_sha1[20];
int merge_base = 0;
int independent = 0;
char **label;
int no_name = 0;
int sha1_name = 0;
setup_git_directory();
@ -370,6 +384,10 @@ int main(int ac, char **av)
extra = 1;
else if (!strcmp(arg, "--list"))
extra = -1;
else if (!strcmp(arg, "--no-name"))
no_name = 1;
else if (!strcmp(arg, "--sha1-name"))
sha1_name = 1;
else if (!strncmp(arg, "--more=", 7))
extra = atoi(arg + 7);
else if (!strcmp(arg, "--merge-base"))
@ -465,7 +483,8 @@ int main(int ac, char **av)
printf("%c [%s] ",
is_head ? '*' : '!', ref_name[i]);
}
show_one_commit(rev[i]);
/* header lines never need name */
show_one_commit(rev[i], 1);
}
if (0 <= extra) {
for (i = 0; i < num_rev; i++)
@ -480,7 +499,8 @@ int main(int ac, char **av)
sort_in_topological_order(&seen);
/* Give names to commits */
name_commits(seen, rev, ref_name, num_rev);
if (!sha1_name && !no_name)
name_commits(seen, rev, ref_name, num_rev);
all_mask = ((1u << (REV_SHIFT + num_rev)) - 1);
all_revs = all_mask & ~((1u << REV_SHIFT) - 1);
@ -490,7 +510,6 @@ int main(int ac, char **av)
struct commit *commit = pop_one_commit(&seen);
int this_flag = commit->object.flags;
int is_merge_point = (this_flag & all_revs) == all_revs;
static char *obvious[] = { "" };
if (is_merge_point)
shown_merge_point = 1;
@ -501,9 +520,7 @@ int main(int ac, char **av)
? '+' : ' ');
putchar(' ');
}
show_one_commit(commit);
if (num_rev == 1)
label = obvious;
show_one_commit(commit, no_name);
if (shown_merge_point && is_merge_point)
if (--extra < 0)
break;