Skip to content

Commit

Permalink
Merge branch 'jk/show-upstream'
Browse files Browse the repository at this point in the history
* jk/show-upstream:
  branch: show upstream branch when double verbose
  make get_short_ref a public function
  for-each-ref: add "upstream" format field
  for-each-ref: refactor refname handling
  for-each-ref: refactor get_short_ref function
  • Loading branch information
Junio C Hamano committed Apr 12, 2009
2 parents c276857 + 2d8a7f0 commit 3e52eff
Show file tree
Hide file tree
Showing 7 changed files with 187 additions and 131 deletions.
4 changes: 3 additions & 1 deletion Documentation/git-branch.txt
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,9 @@ OPTIONS

-v::
--verbose::
Show sha1 and commit subject line for each head.
Show sha1 and commit subject line for each head, along with
relationship to upstream branch (if any). If given twice, print
the name of the upstream branch, as well.

--abbrev=<length>::
Alter the sha1's minimum display length in the output listing.
Expand Down
5 changes: 5 additions & 0 deletions Documentation/git-for-each-ref.txt
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ objectsize::
objectname::
The object name (aka SHA-1).

upstream::
The name of a local ref which can be considered ``upstream''
from the displayed ref. Respects `:short` in the same way as
`refname` above.

In addition to the above, for commit and tag objects, the header
field names (`tree`, `parent`, `object`, `type`, and `tag`) can
be used to specify the value in the header field.
Expand Down
23 changes: 17 additions & 6 deletions builtin-branch.c
Original file line number Diff line number Diff line change
Expand Up @@ -301,19 +301,30 @@ static int ref_cmp(const void *r1, const void *r2)
return strcmp(c1->name, c2->name);
}

static void fill_tracking_info(struct strbuf *stat, const char *branch_name)
static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
int show_upstream_ref)
{
int ours, theirs;
struct branch *branch = branch_get(branch_name);

if (!stat_tracking_info(branch, &ours, &theirs) || (!ours && !theirs))
if (!stat_tracking_info(branch, &ours, &theirs)) {
if (branch && branch->merge && branch->merge[0]->dst &&
show_upstream_ref)
strbuf_addf(stat, "[%s] ",
shorten_unambiguous_ref(branch->merge[0]->dst));
return;
}

strbuf_addch(stat, '[');
if (show_upstream_ref)
strbuf_addf(stat, "%s: ",
shorten_unambiguous_ref(branch->merge[0]->dst));
if (!ours)
strbuf_addf(stat, "[behind %d] ", theirs);
strbuf_addf(stat, "behind %d] ", theirs);
else if (!theirs)
strbuf_addf(stat, "[ahead %d] ", ours);
strbuf_addf(stat, "ahead %d] ", ours);
else
strbuf_addf(stat, "[ahead %d, behind %d] ", ours, theirs);
strbuf_addf(stat, "ahead %d, behind %d] ", ours, theirs);
}

static int matches_merge_filter(struct commit *commit)
Expand Down Expand Up @@ -379,7 +390,7 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
}

if (item->kind == REF_LOCAL_BRANCH)
fill_tracking_info(&stat, item->name);
fill_tracking_info(&stat, item->name, verbose > 1);

strbuf_addf(&out, " %s %s%s",
find_unique_abbrev(item->commit->object.sha1, abbrev),
Expand Down
164 changes: 40 additions & 124 deletions builtin-for-each-ref.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "blob.h"
#include "quote.h"
#include "parse-options.h"
#include "remote.h"

/* Quoting styles */
#define QUOTE_NONE 0
Expand Down Expand Up @@ -66,6 +67,7 @@ static struct {
{ "subject" },
{ "body" },
{ "contents" },
{ "upstream" },
};

/*
Expand Down Expand Up @@ -543,109 +545,6 @@ static void grab_values(struct atom_value *val, int deref, struct object *obj, v
}
}

/*
* generate a format suitable for scanf from a ref_rev_parse_rules
* rule, that is replace the "%.*s" spec with a "%s" spec
*/
static void gen_scanf_fmt(char *scanf_fmt, const char *rule)
{
char *spec;

spec = strstr(rule, "%.*s");
if (!spec || strstr(spec + 4, "%.*s"))
die("invalid rule in ref_rev_parse_rules: %s", rule);

/* copy all until spec */
strncpy(scanf_fmt, rule, spec - rule);
scanf_fmt[spec - rule] = '\0';
/* copy new spec */
strcat(scanf_fmt, "%s");
/* copy remaining rule */
strcat(scanf_fmt, spec + 4);

return;
}

/*
* Shorten the refname to an non-ambiguous form
*/
static char *get_short_ref(struct refinfo *ref)
{
int i;
static char **scanf_fmts;
static int nr_rules;
char *short_name;

/* pre generate scanf formats from ref_rev_parse_rules[] */
if (!nr_rules) {
size_t total_len = 0;

/* the rule list is NULL terminated, count them first */
for (; ref_rev_parse_rules[nr_rules]; nr_rules++)
/* no +1 because strlen("%s") < strlen("%.*s") */
total_len += strlen(ref_rev_parse_rules[nr_rules]);

scanf_fmts = xmalloc(nr_rules * sizeof(char *) + total_len);

total_len = 0;
for (i = 0; i < nr_rules; i++) {
scanf_fmts[i] = (char *)&scanf_fmts[nr_rules]
+ total_len;
gen_scanf_fmt(scanf_fmts[i], ref_rev_parse_rules[i]);
total_len += strlen(ref_rev_parse_rules[i]);
}
}

/* bail out if there are no rules */
if (!nr_rules)
return ref->refname;

/* buffer for scanf result, at most ref->refname must fit */
short_name = xstrdup(ref->refname);

/* skip first rule, it will always match */
for (i = nr_rules - 1; i > 0 ; --i) {
int j;
int short_name_len;

if (1 != sscanf(ref->refname, scanf_fmts[i], short_name))
continue;

short_name_len = strlen(short_name);

/*
* check if the short name resolves to a valid ref,
* but use only rules prior to the matched one
*/
for (j = 0; j < i; j++) {
const char *rule = ref_rev_parse_rules[j];
unsigned char short_objectname[20];
char refname[PATH_MAX];

/*
* the short name is ambiguous, if it resolves
* (with this previous rule) to a valid ref
* read_ref() returns 0 on success
*/
mksnpath(refname, sizeof(refname),
rule, short_name_len, short_name);
if (!read_ref(refname, short_objectname))
break;
}

/*
* short name is non-ambiguous if all previous rules
* haven't resolved to a valid ref
*/
if (j == i)
return short_name;
}

free(short_name);
return ref->refname;
}


/*
* Parse the object referred by ref, and grab needed value.
*/
Expand All @@ -672,32 +571,49 @@ static void populate_value(struct refinfo *ref)
const char *name = used_atom[i];
struct atom_value *v = &ref->value[i];
int deref = 0;
const char *refname;
const char *formatp;

if (*name == '*') {
deref = 1;
name++;
}
if (!prefixcmp(name, "refname")) {
const char *formatp = strchr(name, ':');
const char *refname = ref->refname;

/* look for "short" refname format */
if (formatp) {
formatp++;
if (!strcmp(formatp, "short"))
refname = get_short_ref(ref);
else
die("unknown refname format %s",
formatp);
}

if (!deref)
v->s = refname;
else {
int len = strlen(refname);
char *s = xmalloc(len + 4);
sprintf(s, "%s^{}", refname);
v->s = s;
}
if (!prefixcmp(name, "refname"))
refname = ref->refname;
else if(!prefixcmp(name, "upstream")) {
struct branch *branch;
/* only local branches may have an upstream */
if (prefixcmp(ref->refname, "refs/heads/"))
continue;
branch = branch_get(ref->refname + 11);

if (!branch || !branch->merge || !branch->merge[0] ||
!branch->merge[0]->dst)
continue;
refname = branch->merge[0]->dst;
}
else
continue;

formatp = strchr(name, ':');
/* look for "short" refname format */
if (formatp) {
formatp++;
if (!strcmp(formatp, "short"))
refname = shorten_unambiguous_ref(refname);
else
die("unknown %.*s format %s",
(int)(formatp - name), name, formatp);
}

if (!deref)
v->s = refname;
else {
int len = strlen(refname);
char *s = xmalloc(len + 4);
sprintf(s, "%s^{}", refname);
v->s = s;
}
}

Expand Down
99 changes: 99 additions & 0 deletions refs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1657,3 +1657,102 @@ struct ref *find_ref_by_name(const struct ref *list, const char *name)
return (struct ref *)list;
return NULL;
}

/*
* generate a format suitable for scanf from a ref_rev_parse_rules
* rule, that is replace the "%.*s" spec with a "%s" spec
*/
static void gen_scanf_fmt(char *scanf_fmt, const char *rule)
{
char *spec;

spec = strstr(rule, "%.*s");
if (!spec || strstr(spec + 4, "%.*s"))
die("invalid rule in ref_rev_parse_rules: %s", rule);

/* copy all until spec */
strncpy(scanf_fmt, rule, spec - rule);
scanf_fmt[spec - rule] = '\0';
/* copy new spec */
strcat(scanf_fmt, "%s");
/* copy remaining rule */
strcat(scanf_fmt, spec + 4);

return;
}

char *shorten_unambiguous_ref(const char *ref)
{
int i;
static char **scanf_fmts;
static int nr_rules;
char *short_name;

/* pre generate scanf formats from ref_rev_parse_rules[] */
if (!nr_rules) {
size_t total_len = 0;

/* the rule list is NULL terminated, count them first */
for (; ref_rev_parse_rules[nr_rules]; nr_rules++)
/* no +1 because strlen("%s") < strlen("%.*s") */
total_len += strlen(ref_rev_parse_rules[nr_rules]);

scanf_fmts = xmalloc(nr_rules * sizeof(char *) + total_len);

total_len = 0;
for (i = 0; i < nr_rules; i++) {
scanf_fmts[i] = (char *)&scanf_fmts[nr_rules]
+ total_len;
gen_scanf_fmt(scanf_fmts[i], ref_rev_parse_rules[i]);
total_len += strlen(ref_rev_parse_rules[i]);
}
}

/* bail out if there are no rules */
if (!nr_rules)
return xstrdup(ref);

/* buffer for scanf result, at most ref must fit */
short_name = xstrdup(ref);

/* skip first rule, it will always match */
for (i = nr_rules - 1; i > 0 ; --i) {
int j;
int short_name_len;

if (1 != sscanf(ref, scanf_fmts[i], short_name))
continue;

short_name_len = strlen(short_name);

/*
* check if the short name resolves to a valid ref,
* but use only rules prior to the matched one
*/
for (j = 0; j < i; j++) {
const char *rule = ref_rev_parse_rules[j];
unsigned char short_objectname[20];
char refname[PATH_MAX];

/*
* the short name is ambiguous, if it resolves
* (with this previous rule) to a valid ref
* read_ref() returns 0 on success
*/
mksnpath(refname, sizeof(refname),
rule, short_name_len, short_name);
if (!read_ref(refname, short_objectname))
break;
}

/*
* short name is non-ambiguous if all previous rules
* haven't resolved to a valid ref
*/
if (j == i)
return short_name;
}

free(short_name);
return xstrdup(ref);
}
1 change: 1 addition & 0 deletions refs.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ extern int for_each_reflog(each_ref_fn, void *);
extern int check_ref_format(const char *target);

extern const char *prettify_ref(const struct ref *ref);
extern char *shorten_unambiguous_ref(const char *ref);

/** rename ref, return 0 on success **/
extern int rename_ref(const char *oldref, const char *newref, const char *logmsg);
Expand Down
Loading

0 comments on commit 3e52eff

Please sign in to comment.