branch --merged/--no-merged: allow specifying arbitrary commit
"git-branch --merged" is a handy way to list all the branches that have already been merged to the current branch, but it did not allow checking against anything but the current branch. Having to switch branches only to list the branches that are merged with another branch made the feature practically useless. This updates the option parser so that "git branch --merged next" is accepted when you are on 'master' branch. Signed-off-by: Junio C Hamano <gitster@pobox.com>
Junio C Hamano committed
Jul 8, 2008 at 17:55 UTC
049716b370f2cebdbdeb278eb2a8c4eff8ed0acd
2 files changed
+57
-20
Documentation/git-branch.txt
+15
-12
@@ -8,24 +8,27 @@ git-branch - List, create, or delete branches
8
SYNOPSIS
9
--------
10
[verse]
11
-'git-branch' [--color | --no-color] [-r | -a] [--merged | --no-merged]
12
- [-v [--abbrev=<length> | --no-abbrev]]
13
- [--contains <commit>]
11
+'git-branch' [--color | --no-color] [-r | -a]
12
+ [-v [--abbrev=<length> | --no-abbrev]]
13
+ [(--merged | --no-merged | --contains) [<commit>]]
14
'git-branch' [--track | --no-track] [-l] [-f] <branchname> [<start-point>]
15
'git-branch' (-m | -M) [<oldbranch>] <newbranch>
16
'git-branch' (-d | -D) [-r] <branchname>...
17
18
DESCRIPTION
19
-----------
20
-With no arguments given a list of existing branches
21
-will be shown, the current branch will be highlighted with an asterisk.
22
-Option `-r` causes the remote-tracking branches to be listed,
23
-and option `-a` shows both.
24
-With `--contains <commit>`, shows only the branches that
25
-contains the named commit (in other words, the branches whose
26
-tip commits are descendant of the named commit).
27
-With `--merged`, only branches merged into HEAD will be listed, and
28
-with `--no-merged` only branches not merged into HEAD will be listed.
20
+
21
+With no arguments, existing branches are listed, the current branch will
22
+be highlighted with an asterisk. Option `-r` causes the remote-tracking
23
+branches to be listed, and option `-a` shows both.
24
+
25
+With `--contains`, shows only the branches that contains the named commit
26
+(in other words, the branches whose tip commits are descendant of the
27
+named commit). With `--merged`, only branches merged into the named
28
+commit (i.e. the branches whose tip commits are reachable from the named
29
+commit) will be listed. With `--no-merged` only branches not merged into
30
+the named commit will be listed. Missing <commit> argument defaults to
31
+'HEAD' (i.e. the tip of the current branch).
32
33
In its second form, a new branch named <branchname> will be created.
34
It will start out with a head equal to the one given as <start-point>.
builtin-branch.c
+42
-8
@@ -46,7 +46,12 @@ enum color_branch {
46
COLOR_BRANCH_CURRENT = 4,
47
};
48
49
-static int mergefilter = -1;
49
+static enum merge_filter {
50
+ NO_FILTER = 0,
51
+ SHOW_NOT_MERGED,
52
+ SHOW_MERGED,
53
+} merge_filter;
54
+static unsigned char merge_filter_ref[20];
55
56
static int parse_branch_color_slot(const char *var, int ofs)
57
{
@@ -234,13 +239,15 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags,
239
if ((kind & ref_list->kinds) == 0)
240
return 0;
241
237
- if (mergefilter > -1) {
242
+ if (merge_filter != NO_FILTER) {
243
branch.item = lookup_commit_reference_gently(sha1, 1);
244
if (!branch.item)
245
die("Unable to lookup tip of branch %s", refname);
241
- if (mergefilter == 0 && has_commit(head_sha1, &branch))
246
+ if (merge_filter == SHOW_NOT_MERGED &&
247
+ has_commit(merge_filter_ref, &branch))
248
return 0;
243
- if (mergefilter == 1 && !has_commit(head_sha1, &branch))
249
+ if (merge_filter == SHOW_MERGED &&
250
+ !has_commit(merge_filter_ref, &branch))
251
return 0;
252
}
253
@@ -421,6 +428,20 @@ static int opt_parse_with_commit(const struct option *opt, const char *arg, int
428
return 0;
429
}
430
431
+static int opt_parse_merge_filter(const struct option *opt, const char *arg, int unset)
432
+{
433
+ merge_filter = ((opt->long_name[0] == 'n')
434
+ ? SHOW_NOT_MERGED
435
+ : SHOW_MERGED);
436
+ if (unset)
437
+ merge_filter = SHOW_NOT_MERGED; /* b/c for --no-merged */
438
+ if (!arg)
439
+ arg = "HEAD";
440
+ if (get_sha1(arg, merge_filter_ref))
441
+ die("malformed object name %s", arg);
442
+ return 0;
443
+}
444
+
445
int cmd_branch(int argc, const char **argv, const char *prefix)
446
{
447
int delete = 0, rename = 0, force_create = 0;
@@ -461,7 +482,18 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
482
OPT_BIT('M', NULL, &rename, "move/rename a branch, even if target exists", 2),
483
OPT_BOOLEAN('l', NULL, &reflog, "create the branch's reflog"),
484
OPT_BOOLEAN('f', NULL, &force_create, "force creation (when already exists)"),
464
- OPT_SET_INT(0, "merged", &mergefilter, "list only merged branches", 1),
485
+ {
486
+ OPTION_CALLBACK, 0, "no-merged", &merge_filter_ref,
487
+ "commit", "print only not merged branches",
488
+ PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NONEG,
489
+ opt_parse_merge_filter, (intptr_t) "HEAD",
490
+ },
491
+ {
492
+ OPTION_CALLBACK, 0, "merged", &merge_filter_ref,
493
+ "commit", "print only merged branches",
494
+ PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NONEG,
495
+ opt_parse_merge_filter, (intptr_t) "HEAD",
496
+ },
497
OPT_END(),
498
};
499
@@ -471,9 +503,6 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
503
branch_use_color = git_use_color_default;
504
505
track = git_branch_track;
474
- argc = parse_options(argc, argv, options, builtin_branch_usage, 0);
475
- if (!!delete + !!rename + !!force_create > 1)
476
- usage_with_options(builtin_branch_usage, options);
506
507
head = resolve_ref("HEAD", head_sha1, 0, NULL);
508
if (!head)
@@ -486,6 +515,11 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
515
die("HEAD not found below refs/heads!");
516
head += 11;
517
}
518
+ hashcpy(merge_filter_ref, head_sha1);
519
+
520
+ argc = parse_options(argc, argv, options, builtin_branch_usage, 0);
521
+ if (!!delete + !!rename + !!force_create > 1)
522
+ usage_with_options(builtin_branch_usage, options);
523
524
if (delete)
525
return delete_branches(argc, argv, delete > 1, kinds);