Merge branch 'jc/branch-merged'
* jc/branch-merged: branch --merged/--no-merged: allow specifying arbitrary commit branch --contains: default to HEAD parse-options: add PARSE_OPT_LASTARG_DEFAULT flag Conflicts: Documentation/git-branch.txt
This commit is contained in:
commit
b773fc34a0
@ -8,24 +8,27 @@ git-branch - List, create, or delete branches
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git branch' [--color | --no-color] [-r | -a] [--merged | --no-merged]
|
||||
[-v [--abbrev=<length> | --no-abbrev]]
|
||||
[--contains <commit>]
|
||||
'git branch' [--color | --no-color] [-r | -a]
|
||||
[-v [--abbrev=<length> | --no-abbrev]]
|
||||
[(--merged | --no-merged | --contains) [<commit>]]
|
||||
'git branch' [--track | --no-track] [-l] [-f] <branchname> [<start-point>]
|
||||
'git branch' (-m | -M) [<oldbranch>] <newbranch>
|
||||
'git branch' (-d | -D) [-r] <branchname>...
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
With no arguments given a list of existing branches
|
||||
will be shown, the current branch will be highlighted with an asterisk.
|
||||
Option `-r` causes the remote-tracking branches to be listed,
|
||||
and option `-a` shows both.
|
||||
With `--contains <commit>`, shows only the branches that
|
||||
contains the named commit (in other words, the branches whose
|
||||
tip commits are descendant of the named commit).
|
||||
With `--merged`, only branches merged into HEAD will be listed, and
|
||||
with `--no-merged` only branches not merged into HEAD will be listed.
|
||||
|
||||
With no arguments, existing branches are listed, the current branch will
|
||||
be highlighted with an asterisk. Option `-r` causes the remote-tracking
|
||||
branches to be listed, and option `-a` shows both.
|
||||
|
||||
With `--contains`, shows only the branches that contains the named commit
|
||||
(in other words, the branches whose tip commits are descendant of the
|
||||
named commit). With `--merged`, only branches merged into the named
|
||||
commit (i.e. the branches whose tip commits are reachable from the named
|
||||
commit) will be listed. With `--no-merged` only branches not merged into
|
||||
the named commit will be listed. Missing <commit> argument defaults to
|
||||
'HEAD' (i.e. the tip of the current branch).
|
||||
|
||||
In its second form, a new branch named <branchname> will be created.
|
||||
It will start out with a head equal to the one given as <start-point>.
|
||||
|
@ -46,7 +46,12 @@ enum color_branch {
|
||||
COLOR_BRANCH_CURRENT = 4,
|
||||
};
|
||||
|
||||
static int mergefilter = -1;
|
||||
static enum merge_filter {
|
||||
NO_FILTER = 0,
|
||||
SHOW_NOT_MERGED,
|
||||
SHOW_MERGED,
|
||||
} merge_filter;
|
||||
static unsigned char merge_filter_ref[20];
|
||||
|
||||
static int parse_branch_color_slot(const char *var, int ofs)
|
||||
{
|
||||
@ -234,13 +239,15 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags,
|
||||
if ((kind & ref_list->kinds) == 0)
|
||||
return 0;
|
||||
|
||||
if (mergefilter > -1) {
|
||||
if (merge_filter != NO_FILTER) {
|
||||
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))
|
||||
if (merge_filter == SHOW_NOT_MERGED &&
|
||||
has_commit(merge_filter_ref, &branch))
|
||||
return 0;
|
||||
if (mergefilter == 1 && !has_commit(head_sha1, &branch))
|
||||
if (merge_filter == SHOW_MERGED &&
|
||||
!has_commit(merge_filter_ref, &branch))
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -443,6 +450,20 @@ static int opt_parse_with_commit(const struct option *opt, const char *arg, int
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opt_parse_merge_filter(const struct option *opt, const char *arg, int unset)
|
||||
{
|
||||
merge_filter = ((opt->long_name[0] == 'n')
|
||||
? SHOW_NOT_MERGED
|
||||
: SHOW_MERGED);
|
||||
if (unset)
|
||||
merge_filter = SHOW_NOT_MERGED; /* b/c for --no-merged */
|
||||
if (!arg)
|
||||
arg = "HEAD";
|
||||
if (get_sha1(arg, merge_filter_ref))
|
||||
die("malformed object name %s", arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmd_branch(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int delete = 0, rename = 0, force_create = 0;
|
||||
@ -460,13 +481,17 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
|
||||
OPT_BOOLEAN( 0 , "color", &branch_use_color, "use colored output"),
|
||||
OPT_SET_INT('r', NULL, &kinds, "act on remote-tracking branches",
|
||||
REF_REMOTE_BRANCH),
|
||||
OPT_CALLBACK(0, "contains", &with_commit, "commit",
|
||||
"print only branches that contain the commit",
|
||||
opt_parse_with_commit),
|
||||
{
|
||||
OPTION_CALLBACK, 0, "contains", &with_commit, "commit",
|
||||
"print only branches that contain the commit",
|
||||
PARSE_OPT_LASTARG_DEFAULT,
|
||||
opt_parse_with_commit, (intptr_t)"HEAD",
|
||||
},
|
||||
{
|
||||
OPTION_CALLBACK, 0, "with", &with_commit, "commit",
|
||||
"print only branches that contain the commit",
|
||||
PARSE_OPT_HIDDEN, opt_parse_with_commit,
|
||||
PARSE_OPT_HIDDEN | PARSE_OPT_LASTARG_DEFAULT,
|
||||
opt_parse_with_commit, (intptr_t) "HEAD",
|
||||
},
|
||||
OPT__ABBREV(&abbrev),
|
||||
|
||||
@ -479,7 +504,18 @@ 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),
|
||||
{
|
||||
OPTION_CALLBACK, 0, "no-merged", &merge_filter_ref,
|
||||
"commit", "print only not merged branches",
|
||||
PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NONEG,
|
||||
opt_parse_merge_filter, (intptr_t) "HEAD",
|
||||
},
|
||||
{
|
||||
OPTION_CALLBACK, 0, "merged", &merge_filter_ref,
|
||||
"commit", "print only merged branches",
|
||||
PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NONEG,
|
||||
opt_parse_merge_filter, (intptr_t) "HEAD",
|
||||
},
|
||||
OPT_END(),
|
||||
};
|
||||
|
||||
@ -489,9 +525,6 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
|
||||
branch_use_color = git_use_color_default;
|
||||
|
||||
track = git_branch_track;
|
||||
argc = parse_options(argc, argv, options, builtin_branch_usage, 0);
|
||||
if (!!delete + !!rename + !!force_create > 1)
|
||||
usage_with_options(builtin_branch_usage, options);
|
||||
|
||||
head = resolve_ref("HEAD", head_sha1, 0, NULL);
|
||||
if (!head)
|
||||
@ -504,6 +537,11 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
|
||||
die("HEAD not found below refs/heads!");
|
||||
head += 11;
|
||||
}
|
||||
hashcpy(merge_filter_ref, head_sha1);
|
||||
|
||||
argc = parse_options(argc, argv, options, builtin_branch_usage, 0);
|
||||
if (!!delete + !!rename + !!force_create > 1)
|
||||
usage_with_options(builtin_branch_usage, options);
|
||||
|
||||
if (delete)
|
||||
return delete_branches(argc, argv, delete > 1, kinds);
|
||||
|
@ -5,17 +5,6 @@
|
||||
#define OPT_SHORT 1
|
||||
#define OPT_UNSET 2
|
||||
|
||||
static inline const char *get_arg(struct parse_opt_ctx_t *p)
|
||||
{
|
||||
if (p->opt) {
|
||||
const char *res = p->opt;
|
||||
p->opt = NULL;
|
||||
return res;
|
||||
}
|
||||
p->argc--;
|
||||
return *++p->argv;
|
||||
}
|
||||
|
||||
static inline const char *skip_prefix(const char *str, const char *prefix)
|
||||
{
|
||||
size_t len = strlen(prefix);
|
||||
@ -31,8 +20,24 @@ static int opterror(const struct option *opt, const char *reason, int flags)
|
||||
return error("option `%s' %s", opt->long_name, reason);
|
||||
}
|
||||
|
||||
static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
|
||||
int flags, const char **arg)
|
||||
{
|
||||
if (p->opt) {
|
||||
*arg = p->opt;
|
||||
p->opt = NULL;
|
||||
} else if (p->argc == 1 && (opt->flags & PARSE_OPT_LASTARG_DEFAULT)) {
|
||||
*arg = (const char *)opt->defval;
|
||||
} else if (p->argc) {
|
||||
p->argc--;
|
||||
*arg = *++p->argv;
|
||||
} else
|
||||
return opterror(opt, "requires a value", flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_value(struct parse_opt_ctx_t *p,
|
||||
const struct option *opt, int flags)
|
||||
const struct option *opt, int flags)
|
||||
{
|
||||
const char *s, *arg;
|
||||
const int unset = flags & OPT_UNSET;
|
||||
@ -58,7 +63,6 @@ static int get_value(struct parse_opt_ctx_t *p,
|
||||
}
|
||||
}
|
||||
|
||||
arg = p->opt ? p->opt : (p->argc > 1 ? p->argv[1] : NULL);
|
||||
switch (opt->type) {
|
||||
case OPTION_BIT:
|
||||
if (unset)
|
||||
@ -80,17 +84,12 @@ static int get_value(struct parse_opt_ctx_t *p,
|
||||
return 0;
|
||||
|
||||
case OPTION_STRING:
|
||||
if (unset) {
|
||||
if (unset)
|
||||
*(const char **)opt->value = NULL;
|
||||
return 0;
|
||||
}
|
||||
if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
|
||||
else if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
|
||||
*(const char **)opt->value = (const char *)opt->defval;
|
||||
return 0;
|
||||
}
|
||||
if (!arg)
|
||||
return opterror(opt, "requires a value", flags);
|
||||
*(const char **)opt->value = get_arg(p);
|
||||
else
|
||||
return get_arg(p, opt, flags, (const char **)opt->value);
|
||||
return 0;
|
||||
|
||||
case OPTION_CALLBACK:
|
||||
@ -100,9 +99,9 @@ static int get_value(struct parse_opt_ctx_t *p,
|
||||
return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
|
||||
if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
|
||||
return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
|
||||
if (!arg)
|
||||
return opterror(opt, "requires a value", flags);
|
||||
return (*opt->callback)(opt, get_arg(p), 0) ? (-1) : 0;
|
||||
if (get_arg(p, opt, flags, &arg))
|
||||
return -1;
|
||||
return (*opt->callback)(opt, arg, 0) ? (-1) : 0;
|
||||
|
||||
case OPTION_INTEGER:
|
||||
if (unset) {
|
||||
@ -113,9 +112,9 @@ static int get_value(struct parse_opt_ctx_t *p,
|
||||
*(int *)opt->value = opt->defval;
|
||||
return 0;
|
||||
}
|
||||
if (!arg)
|
||||
return opterror(opt, "requires a value", flags);
|
||||
*(int *)opt->value = strtol(get_arg(p), (char **)&s, 10);
|
||||
if (get_arg(p, opt, flags, &arg))
|
||||
return -1;
|
||||
*(int *)opt->value = strtol(arg, (char **)&s, 10);
|
||||
if (*s)
|
||||
return opterror(opt, "expects a numerical value", flags);
|
||||
return 0;
|
||||
|
@ -28,6 +28,7 @@ enum parse_opt_option_flags {
|
||||
PARSE_OPT_NOARG = 2,
|
||||
PARSE_OPT_NONEG = 4,
|
||||
PARSE_OPT_HIDDEN = 8,
|
||||
PARSE_OPT_LASTARG_DEFAULT = 16,
|
||||
};
|
||||
|
||||
struct option;
|
||||
|
Loading…
Reference in New Issue
Block a user