Merge branch 'jc/rebase-orig-head'
[gitweb.git] / builtin-branch.c
index 5bc4526f645d40a4a32c50240975ad26f49b8e3b..ff71f3d8a6dd784ae08f89b8a98136e4cd369295 100644 (file)
@@ -15,7 +15,7 @@
 #include "branch.h"
 
 static const char * const builtin_branch_usage[] = {
-       "git-branch [options] [-r | -a]",
+       "git-branch [options] [-r | -a] [--merged | --no-merged]",
        "git-branch [options] [-l] [-f] <branchname> [<start-point>]",
        "git-branch [options] [-r] (-d | -D) <branchname>",
        "git-branch [options] (-m | -M) [<oldbranch>] <newbranch>",
@@ -46,6 +46,8 @@ enum color_branch {
        COLOR_BRANCH_CURRENT = 4,
 };
 
+static int mergefilter = -1;
+
 static int parse_branch_color_slot(const char *var, int ofs)
 {
        if (!strcasecmp(var+ofs, "plain"))
@@ -61,7 +63,7 @@ static int parse_branch_color_slot(const char *var, int ofs)
        die("bad config variable '%s'", var);
 }
 
-static int git_branch_config(const char *var, const char *value)
+static int git_branch_config(const char *var, const char *value, void *cb)
 {
        if (!strcmp(var, "color.branch")) {
                branch_use_color = git_config_colorbool(var, value, -1);
@@ -74,7 +76,7 @@ static int git_branch_config(const char *var, const char *value)
                color_parse(value, var, branch_colors[slot]);
                return 0;
        }
-       return git_color_default_config(var, value);
+       return git_color_default_config(var, value, cb);
 }
 
 static const char *branch_get_color(enum color_branch ix)
@@ -210,6 +212,7 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags,
        struct ref_item *newitem;
        int kind = REF_UNKNOWN_TYPE;
        int len;
+       static struct commit_list branch;
 
        /* Detect kind */
        if (!prefixcmp(refname, "refs/heads/")) {
@@ -231,6 +234,16 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags,
        if ((kind & ref_list->kinds) == 0)
                return 0;
 
+       if (mergefilter > -1) {
+               branch.item = lookup_commit_reference_gently(sha1, 1);
+               if (!branch.item)
+                       die("Unable to lookup tip of branch %s", refname);
+               if (mergefilter == 0 && has_commit(head_sha1, &branch))
+                       return 0;
+               if (mergefilter == 1 && !has_commit(head_sha1, &branch))
+                       return 0;
+       }
+
        /* Resize buffer */
        if (ref_list->index >= ref_list->alloc) {
                ref_list->alloc = alloc_nr(ref_list->alloc);
@@ -269,6 +282,21 @@ static int ref_cmp(const void *r1, const void *r2)
        return strcmp(c1->name, c2->name);
 }
 
+static void fill_tracking_info(char *stat, const char *branch_name)
+{
+       int ours, theirs;
+       struct branch *branch = branch_get(branch_name);
+
+       if (!stat_tracking_info(branch, &ours, &theirs) || (!ours && !theirs))
+               return;
+       if (!ours)
+               sprintf(stat, "[behind %d] ", theirs);
+       else if (!theirs)
+               sprintf(stat, "[ahead %d] ", ours);
+       else
+               sprintf(stat, "[ahead %d, behind %d] ", ours, theirs);
+}
+
 static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
                           int abbrev, int current)
 {
@@ -297,8 +325,10 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
        if (verbose) {
                struct strbuf subject;
                const char *sub = " **** invalid ref ****";
+               char stat[128];
 
                strbuf_init(&subject, 0);
+               stat[0] = '\0';
 
                commit = lookup_commit(item->sha1);
                if (commit && !parse_commit(commit)) {
@@ -306,10 +336,15 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
                                            &subject, 0, NULL, NULL, 0, 0);
                        sub = subject.buf;
                }
-               printf("%c %s%-*s%s %s %s\n", c, branch_get_color(color),
+
+               if (item->kind == REF_LOCAL_BRANCH)
+                       fill_tracking_info(stat, item->name);
+
+               printf("%c %s%-*s%s %s %s%s\n", c, branch_get_color(color),
                       maxwidth, item->name,
                       branch_get_color(COLOR_BRANCH_RESET),
-                      find_unique_abbrev(item->sha1, abbrev), sub);
+                      find_unique_abbrev(item->sha1, abbrev),
+                      stat, sub);
                strbuf_release(&subject);
        } else {
                printf("%c %s%s%s\n", c, branch_get_color(color), item->name,
@@ -444,10 +479,11 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                OPT_BIT('M', NULL, &rename, "move/rename a branch, even if target exists", 2),
                OPT_BOOLEAN('l', NULL, &reflog, "create the branch's reflog"),
                OPT_BOOLEAN('f', NULL, &force_create, "force creation (when already exists)"),
+               OPT_SET_INT(0, "merged", &mergefilter, "list only merged branches", 1),
                OPT_END(),
        };
 
-       git_config(git_branch_config);
+       git_config(git_branch_config, NULL);
 
        if (branch_use_color == -1)
                branch_use_color = git_use_color_default;