Introduce %(upstream:track) to display "[ahead M, behind N]" and
%(upstream:trackshort) to display "=", ">", "<", or "<>"
appropriately (inspired by the contrib/completion/git-prompt.sh).

Now you can use the following format in for-each-ref:

  %C(green)%(refname:short)%C(reset)%(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 <artag...@gmail.com>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclo...@gmail.com>
---
 Documentation/git-for-each-ref.txt |  6 +++++-
 builtin/for-each-ref.c             | 42 ++++++++++++++++++++++++++++++++++++--
 2 files changed, 45 insertions(+), 3 deletions(-)

diff --git a/Documentation/git-for-each-ref.txt 
b/Documentation/git-for-each-ref.txt
index 8d982e3..d666ebd 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -119,7 +119,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 (like the prompt) ">", "<", "<>", or "=".  Has no
+       effect if the ref does not have tracking information
+       associated with it.
 
 HEAD::
        Useful to indicate the currently checked out branch.  Is '*'
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index 3d357a9..72b33ee 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -628,6 +628,7 @@ static void populate_value(struct refinfo *ref)
        int eaten, i;
        unsigned long size;
        const unsigned char *tagged;
+       int upstream_present = 0;
 
        ref->value = xcalloc(sizeof(struct atom_value), used_atom_cnt);
 
@@ -645,6 +646,7 @@ static void populate_value(struct refinfo *ref)
                int deref = 0;
                const char *refname;
                const char *formatp;
+               struct branch *branch;
 
                if (*name == '*') {
                        deref = 1;
@@ -656,7 +658,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;
@@ -666,6 +667,7 @@ static void populate_value(struct refinfo *ref)
                            !branch->merge[0]->dst)
                                continue;
                        refname = branch->merge[0]->dst;
+                       upstream_present = 1;
                }
                else if (!strcmp(name, "flag")) {
                        char buf[256], *cp = buf;
@@ -683,6 +685,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 = "*";
@@ -695,11 +698,46 @@ static void populate_value(struct refinfo *ref)
                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];
+
+                               if (!upstream_present)
+                                       continue;
+                               if (!stat_tracking_info(branch, &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")) {
+                               if (!upstream_present)
+                                       continue;
+                               if (!stat_tracking_info(branch, &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);
                }
-- 
1.8.3.2.736.g869de25

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to