`git show-branch --upstream` is equivalent to `git show-branch
$(git for-each-ref refs/heads --format '%(refname:short)')
$(git for-each-ref refs/heads --format '%(upstream:short)')`

`git show-branch --upstream foo bar` is equivalent to `git show-branch
foo bar $(git for-each-ref refs/heads/foo refs/heads/bar
--format '%(upstream:short)')`

Combined with --topics, it shows commits that are NOT on any of
the upstream branches.

Signed-off-by: Mike Hommey <m...@glandium.org>
---

Note that in the --topics --upstream case, when there are different
upstreams branches involved, only the merge-base of all of them is
shown. I'm not sure if it's desirable to show more. The output as it
is works for my own use cases.

 Documentation/git-show-branch.txt |  6 ++++++
 builtin/show-branch.c             | 42 +++++++++++++++++++++++++++++++++++++--
 2 files changed, 46 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-show-branch.txt 
b/Documentation/git-show-branch.txt
index b91d4e5..fd29c8d 100644
--- a/Documentation/git-show-branch.txt
+++ b/Documentation/git-show-branch.txt
@@ -53,6 +53,10 @@ OPTIONS
        branch to the list of revs to be shown when it is not
        given on the command line.
 
+--upstream::
+       With this option, the command includes the upstream
+       branch of each rev to be shown.
+
 --topo-order::
         By default, the branches and their commits are shown in
         reverse chronological order.  This option makes them
@@ -102,6 +106,8 @@ OPTIONS
 
 --topics::
        Shows only commits that are NOT on the first branch given.
+       When used with `--upstream`, shows only commits that are NOT
+       on any upstream branch.
        This helps track topic branches by hiding any commit that
        is already in the main line of development.  When given
        "git show-branch --topics master topic1 topic2", this
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index 270e39c..90e2ac3 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -4,9 +4,10 @@
 #include "builtin.h"
 #include "color.h"
 #include "parse-options.h"
+#include "remote.h"
 
 static const char* show_branch_usage[] = {
-    N_("git show-branch [-a|--all] [-r|--remotes] [--topo-order | 
--date-order] [--current] [--color[=<when>] | --no-color] [--sparse] 
[--more=<n> | --list | --independent | --merge-base] [--no-name | --sha1-name] 
[--topics] [(<rev> | <glob>)...]"),
+    N_("git show-branch [-a|--all] [-r|--remotes] [--topo-order | 
--date-order] [--current] [--upstream] [--color[=<when>] | --no-color] 
[--sparse] [--more=<n> | --list | --independent | --merge-base] [--no-name | 
--sha1-name] [--topics] [(<rev> | <glob>)...]"),
     N_("git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]"),
     NULL
 };
@@ -640,6 +641,7 @@ int cmd_show_branch(int ac, const char **av, const char 
*prefix)
        int sha1_name = 0;
        int shown_merge_point = 0;
        int with_current_branch = 0;
+       int with_upstream_branches = 0;
        int head_at = -1;
        int topics = 0;
        int dense = 1;
@@ -658,6 +660,8 @@ int cmd_show_branch(int ac, const char **av, const char 
*prefix)
                OPT_BOOL(0, "no-name", &no_name, N_("suppress naming strings")),
                OPT_BOOL(0, "current", &with_current_branch,
                         N_("include the current branch")),
+               OPT_BOOL(0, "upstream", &with_upstream_branches,
+                        N_("include upstream branches")),
                OPT_BOOL(0, "sha1-name", &sha1_name,
                         N_("name commits with their object names")),
                OPT_BOOL(0, "merge-base", &merge_base,
@@ -848,7 +852,41 @@ int cmd_show_branch(int ac, const char **av, const char 
*prefix)
                if (commit->object.flags == flag)
                        commit_list_insert_by_date(commit, &list);
                rev[num_rev] = commit;
+
+               if (with_upstream_branches) {
+                       unsigned char branch_sha1[20];
+                       struct branch *branch;
+                       int current_ref_name_cnt = ref_name_cnt;
+
+                       /* If this ref is already marked as an upstream, skip */
+                       if (topics & flag)
+                               continue;
+
+                       branch = branch_get(ref_name[num_rev]);
+
+                       if (!branch || !branch->merge || !branch->merge[0] ||
+                           !branch->merge[0]->dst)
+                               continue;
+                       if (get_sha1(branch->merge[0]->dst, branch_sha1))
+                               continue;
+                       append_remote_ref(branch->merge[0]->dst, branch_sha1, 
0, 0);
+                       /* If append_remote_ref didn't add a ref, it's either
+                        * because it's an upstream of a previous ref, or 
because
+                        * it was given on the command line. In neither case we
+                        * want the bit being set. */
+                       if (topics && current_ref_name_cnt != ref_name_cnt)
+                               topics |= 1u << (ref_name_cnt + REV_SHIFT - 1);
+               } else if (topics && num_rev == 0) {
+                       topics |= flag;
+               }
        }
+       /* topics is filled above with a mask of refs corresponding to
+        * upstream branches, or the first given ref. It also still contains
+        * the original bool value, which may match some bookkeeping flags,
+        * so filter that out.
+        */
+       topics &= ~0u << REV_SHIFT;
+
        for (i = 0; i < num_rev; i++)
                rev_mask[i] = rev[i]->object.flags;
 
@@ -925,7 +963,7 @@ int cmd_show_branch(int ac, const char **av, const char 
*prefix)
                                          commit->parents->next);
                        if (topics &&
                            !is_merge_point &&
-                           (this_flag & (1u << REV_SHIFT)))
+                           (this_flag & topics))
                                continue;
                        if (dense && is_merge &&
                            omit_in_dense(commit, rev, num_rev))
-- 
2.2.1.4.g99d39fe.dirty

--
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