summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRamkumar Ramachandra <artagnon@gmail.com>2013-11-18 23:09:11 +0530
committerJunio C Hamano <gitster@pobox.com>2013-11-19 10:14:15 -0800
commitb28061ce0d2e31d390fee5a5724b8a061d0492a7 (patch)
treeffd06a2811065c442744dee721f0646fb0592092
parent7a48b8321934384098a8392b3c4c814ec5058d00 (diff)
downloadgit-b28061ce0d2e31d390fee5a5724b8a061d0492a7.tar.gz
for-each-ref: introduce %(upstream:track[short])
Introduce %(upstream:track) to display "[ahead M, behind N]" and %(upstream:trackshort) to display "=", ">", "<", or "<>" appropriately (inspired by contrib/completion/git-prompt.sh). Now you can use the following format in for-each-ref: %(refname:short)%(upstream:trackshort) to display refs with terse tracking information. Note that :track and :trackshort only work with "upstream", and error out when used with anything else. Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
-rw-r--r--Documentation/git-for-each-ref.txt6
-rw-r--r--builtin/for-each-ref.c40
-rwxr-xr-xt/t6300-for-each-ref.sh27
3 files changed, 69 insertions, 4 deletions
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 8f87c9a1ef..92e82fdb02 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -91,7 +91,11 @@ objectname::
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.
+ `refname` above. Additionally respects `:track` to show
+ "[ahead N, behind M]" and `:trackshort` to show the terse
+ version: ">" (ahead), "<" (behind), "<>" (ahead and behind),
+ or "=" (in sync). Has no effect if the ref does not have
+ tracking information associated with it.
HEAD::
'*' if HEAD matches current ref (the checked out branch), ' '
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index 5f1842f48f..9e45abd40a 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -641,6 +641,7 @@ static void populate_value(struct refinfo *ref)
int deref = 0;
const char *refname;
const char *formatp;
+ struct branch *branch = NULL;
if (*name == '*') {
deref = 1;
@@ -652,7 +653,6 @@ static void populate_value(struct refinfo *ref)
else if (!prefixcmp(name, "symref"))
refname = ref->symref ? ref->symref : "";
else if (!prefixcmp(name, "upstream")) {
- struct branch *branch;
/* only local branches may have an upstream */
if (prefixcmp(ref->refname, "refs/heads/"))
continue;
@@ -679,6 +679,7 @@ static void populate_value(struct refinfo *ref)
} else if (!strcmp(name, "HEAD")) {
const char *head;
unsigned char sha1[20];
+
head = resolve_ref_unsafe("HEAD", sha1, 1, NULL);
if (!strcmp(ref->refname, head))
v->s = "*";
@@ -689,13 +690,46 @@ static void populate_value(struct refinfo *ref)
continue;
formatp = strchr(name, ':');
- /* look for "short" refname format */
if (formatp) {
+ int num_ours, num_theirs;
+
formatp++;
if (!strcmp(formatp, "short"))
refname = shorten_unambiguous_ref(refname,
warn_ambiguous_refs);
- else
+ else if (!strcmp(formatp, "track") &&
+ !prefixcmp(name, "upstream")) {
+ char buf[40];
+
+ stat_tracking_info(branch, &num_ours, &num_theirs);
+ if (!num_ours && !num_theirs)
+ v->s = "";
+ else if (!num_ours) {
+ sprintf(buf, "[behind %d]", num_theirs);
+ v->s = xstrdup(buf);
+ } else if (!num_theirs) {
+ sprintf(buf, "[ahead %d]", num_ours);
+ v->s = xstrdup(buf);
+ } else {
+ sprintf(buf, "[ahead %d, behind %d]",
+ num_ours, num_theirs);
+ v->s = xstrdup(buf);
+ }
+ continue;
+ } else if (!strcmp(formatp, "trackshort") &&
+ !prefixcmp(name, "upstream")) {
+ assert(branch);
+ stat_tracking_info(branch, &num_ours, &num_theirs);
+ if (!num_ours && !num_theirs)
+ v->s = "=";
+ else if (!num_ours)
+ v->s = "<";
+ else if (!num_theirs)
+ v->s = ">";
+ else
+ v->s = "<>";
+ continue;
+ } else
die("unknown %.*s format %s",
(int)(formatp - name), name, formatp);
}
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index 1d998f8550..d88d7acbdd 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -303,6 +303,33 @@ test_expect_success 'Check short upstream format' '
test_cmp expected actual
'
+test_expect_success 'setup for upstream:track[short]' '
+ test_commit two
+'
+
+cat >expected <<EOF
+[ahead 1]
+EOF
+
+test_expect_success 'Check upstream:track format' '
+ git for-each-ref --format="%(upstream:track)" refs/heads >actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<EOF
+>
+EOF
+
+test_expect_success 'Check upstream:trackshort format' '
+ git for-each-ref --format="%(upstream:trackshort)" refs/heads >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'Check that :track[short] cannot be used with other atoms' '
+ test_must_fail git for-each-ref --format="%(refname:track)" 2>/dev/null &&
+ test_must_fail git for-each-ref --format="%(refname:trackshort)" 2>/dev/null
+'
+
cat >expected <<EOF
$(git rev-parse --short HEAD)
EOF