simple euristic for further free packing improvements
[gitweb.git] / show-branch.c
index 7a0dcc649edaf6a823e15f60d04c6ce67348dc42..268c57b180627f7d8ba3a3a754210a37d420fb0d 100644 (file)
@@ -5,7 +5,7 @@
 #include "refs.h"
 
 static const char show_branch_usage[] =
-"git-show-branch [--current] [--all] [--heads] [--tags] [--topo-order] [--more=count | --list | --independent | --merge-base ] [<refs>...]";
+"git-show-branch [--dense] [--current] [--all] [--heads] [--tags] [--topo-order] [--more=count | --list | --independent | --merge-base ] [--topics] [<refs>...]";
 
 static int default_num = 0;
 static int default_alloc = 0;
@@ -258,8 +258,8 @@ static void show_one_commit(struct commit *commit, int no_name)
        char pretty[256], *cp;
        struct commit_name *name = commit->object.util;
        if (commit->object.parsed)
-               pretty_print_commit(CMIT_FMT_ONELINE, commit->buffer, ~0,
-                                   pretty, sizeof(pretty));
+               pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0,
+                                   pretty, sizeof(pretty), 0);
        else
                strcpy(pretty, "(unavailable)");
        if (!strncmp(pretty, "[PATCH] ", 8))
@@ -527,6 +527,27 @@ static int git_show_branch_config(const char *var, const char *value)
        return git_default_config(var, value);
 }
 
+static int omit_in_dense(struct commit *commit, struct commit **rev, int n)
+{
+       /* If the commit is tip of the named branches, do not
+        * omit it.
+        * Otherwise, if it is a merge that is reachable from only one
+        * tip, it is not that interesting.
+        */
+       int i, flag, count;
+       for (i = 0; i < n; i++)
+               if (rev[i] == commit)
+                       return 0;
+       flag = commit->object.flags;
+       for (i = count = 0; i < n; i++) {
+               if (flag & (1u << (i + REV_SHIFT)))
+                       count++;
+       }
+       if (count == 1)
+               return 1;
+       return 0;
+}
+
 int main(int ac, char **av)
 {
        struct commit *rev[MAX_REVS], *commit;
@@ -535,6 +556,7 @@ int main(int ac, char **av)
        int num_rev, i, extra = 0;
        int all_heads = 0, all_tags = 0;
        int all_mask, all_revs;
+       int lifo = 1;
        char head_path[128];
        const char *head_path_p;
        int head_path_len;
@@ -544,12 +566,13 @@ int main(int ac, char **av)
        int no_name = 0;
        int sha1_name = 0;
        int shown_merge_point = 0;
-       int topo_order = 0;
        int with_current_branch = 0;
        int head_at = -1;
+       int topics = 0;
+       int dense = 1;
 
-       git_config(git_show_branch_config);
        setup_git_directory();
+       git_config(git_show_branch_config);
 
        /* If nothing is specified, try the default first */
        if (ac == 1 && default_num) {
@@ -586,7 +609,13 @@ int main(int ac, char **av)
                else if (!strcmp(arg, "--independent"))
                        independent = 1;
                else if (!strcmp(arg, "--topo-order"))
-                       topo_order = 1;
+                       lifo = 1;
+               else if (!strcmp(arg, "--topics"))
+                       topics = 1;
+               else if (!strcmp(arg, "--sparse"))
+                       dense = 0;
+               else if (!strcmp(arg, "--date-order"))
+                       lifo = 0;
                else
                        usage(show_branch_usage);
                ac--; av++;
@@ -710,8 +739,7 @@ int main(int ac, char **av)
                exit(0);
 
        /* Sort topologically */
-       if (topo_order)
-               sort_in_topological_order(&seen);
+       sort_in_topological_order(&seen, lifo);
 
        /* Give names to commits */
        if (!sha1_name && !no_name)
@@ -723,11 +751,20 @@ int main(int ac, char **av)
        while (seen) {
                struct commit *commit = pop_one_commit(&seen);
                int this_flag = commit->object.flags;
+               int is_merge_point = ((this_flag & all_revs) == all_revs);
 
-               shown_merge_point |= ((this_flag & all_revs) == all_revs);
+               shown_merge_point |= is_merge_point;
 
                if (1 < num_rev) {
-                       int is_merge = !!(commit->parents && commit->parents->next);
+                       int is_merge = !!(commit->parents &&
+                                         commit->parents->next);
+                       if (topics &&
+                           !is_merge_point &&
+                           (this_flag & (1u << REV_SHIFT)))
+                               continue;
+                       if (dense && is_merge &&
+                           omit_in_dense(commit, rev, num_rev))
+                               continue;
                        for (i = 0; i < num_rev; i++) {
                                int mark;
                                if (!(this_flag & (1u << (i + REV_SHIFT))))