зеркало из https://github.com/microsoft/git.git
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:
Коммит
b773fc34a0
|
@ -8,24 +8,27 @@ git-branch - List, create, or delete branches
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
[verse]
|
[verse]
|
||||||
'git branch' [--color | --no-color] [-r | -a] [--merged | --no-merged]
|
'git branch' [--color | --no-color] [-r | -a]
|
||||||
[-v [--abbrev=<length> | --no-abbrev]]
|
[-v [--abbrev=<length> | --no-abbrev]]
|
||||||
[--contains <commit>]
|
[(--merged | --no-merged | --contains) [<commit>]]
|
||||||
'git branch' [--track | --no-track] [-l] [-f] <branchname> [<start-point>]
|
'git branch' [--track | --no-track] [-l] [-f] <branchname> [<start-point>]
|
||||||
'git branch' (-m | -M) [<oldbranch>] <newbranch>
|
'git branch' (-m | -M) [<oldbranch>] <newbranch>
|
||||||
'git branch' (-d | -D) [-r] <branchname>...
|
'git branch' (-d | -D) [-r] <branchname>...
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
With no arguments given a list of existing branches
|
|
||||||
will be shown, the current branch will be highlighted with an asterisk.
|
With no arguments, existing branches are listed, the current branch will
|
||||||
Option `-r` causes the remote-tracking branches to be listed,
|
be highlighted with an asterisk. Option `-r` causes the remote-tracking
|
||||||
and option `-a` shows both.
|
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
|
With `--contains`, shows only the branches that contains the named commit
|
||||||
tip commits are descendant of the named commit).
|
(in other words, the branches whose tip commits are descendant of the
|
||||||
With `--merged`, only branches merged into HEAD will be listed, and
|
named commit). With `--merged`, only branches merged into the named
|
||||||
with `--no-merged` only branches not merged into HEAD will be listed.
|
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.
|
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>.
|
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,
|
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)
|
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)
|
if ((kind & ref_list->kinds) == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (mergefilter > -1) {
|
if (merge_filter != NO_FILTER) {
|
||||||
branch.item = lookup_commit_reference_gently(sha1, 1);
|
branch.item = lookup_commit_reference_gently(sha1, 1);
|
||||||
if (!branch.item)
|
if (!branch.item)
|
||||||
die("Unable to lookup tip of branch %s", refname);
|
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;
|
return 0;
|
||||||
if (mergefilter == 1 && !has_commit(head_sha1, &branch))
|
if (merge_filter == SHOW_MERGED &&
|
||||||
|
!has_commit(merge_filter_ref, &branch))
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -443,6 +450,20 @@ static int opt_parse_with_commit(const struct option *opt, const char *arg, int
|
||||||
return 0;
|
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 cmd_branch(int argc, const char **argv, const char *prefix)
|
||||||
{
|
{
|
||||||
int delete = 0, rename = 0, force_create = 0;
|
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_BOOLEAN( 0 , "color", &branch_use_color, "use colored output"),
|
||||||
OPT_SET_INT('r', NULL, &kinds, "act on remote-tracking branches",
|
OPT_SET_INT('r', NULL, &kinds, "act on remote-tracking branches",
|
||||||
REF_REMOTE_BRANCH),
|
REF_REMOTE_BRANCH),
|
||||||
OPT_CALLBACK(0, "contains", &with_commit, "commit",
|
{
|
||||||
"print only branches that contain the commit",
|
OPTION_CALLBACK, 0, "contains", &with_commit, "commit",
|
||||||
opt_parse_with_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",
|
OPTION_CALLBACK, 0, "with", &with_commit, "commit",
|
||||||
"print only branches that contain the 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),
|
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_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('l', NULL, &reflog, "create the branch's reflog"),
|
||||||
OPT_BOOLEAN('f', NULL, &force_create, "force creation (when already exists)"),
|
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(),
|
OPT_END(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -489,9 +525,6 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
|
||||||
branch_use_color = git_use_color_default;
|
branch_use_color = git_use_color_default;
|
||||||
|
|
||||||
track = git_branch_track;
|
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);
|
head = resolve_ref("HEAD", head_sha1, 0, NULL);
|
||||||
if (!head)
|
if (!head)
|
||||||
|
@ -504,6 +537,11 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
|
||||||
die("HEAD not found below refs/heads!");
|
die("HEAD not found below refs/heads!");
|
||||||
head += 11;
|
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)
|
if (delete)
|
||||||
return delete_branches(argc, argv, delete > 1, kinds);
|
return delete_branches(argc, argv, delete > 1, kinds);
|
||||||
|
|
|
@ -5,17 +5,6 @@
|
||||||
#define OPT_SHORT 1
|
#define OPT_SHORT 1
|
||||||
#define OPT_UNSET 2
|
#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)
|
static inline const char *skip_prefix(const char *str, const char *prefix)
|
||||||
{
|
{
|
||||||
size_t len = strlen(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);
|
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,
|
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 char *s, *arg;
|
||||||
const int unset = flags & OPT_UNSET;
|
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) {
|
switch (opt->type) {
|
||||||
case OPTION_BIT:
|
case OPTION_BIT:
|
||||||
if (unset)
|
if (unset)
|
||||||
|
@ -80,17 +84,12 @@ static int get_value(struct parse_opt_ctx_t *p,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case OPTION_STRING:
|
case OPTION_STRING:
|
||||||
if (unset) {
|
if (unset)
|
||||||
*(const char **)opt->value = NULL;
|
*(const char **)opt->value = NULL;
|
||||||
return 0;
|
else if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
|
||||||
}
|
|
||||||
if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
|
|
||||||
*(const char **)opt->value = (const char *)opt->defval;
|
*(const char **)opt->value = (const char *)opt->defval;
|
||||||
return 0;
|
else
|
||||||
}
|
return get_arg(p, opt, flags, (const char **)opt->value);
|
||||||
if (!arg)
|
|
||||||
return opterror(opt, "requires a value", flags);
|
|
||||||
*(const char **)opt->value = get_arg(p);
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case OPTION_CALLBACK:
|
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;
|
return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
|
||||||
if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
|
if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
|
||||||
return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
|
return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
|
||||||
if (!arg)
|
if (get_arg(p, opt, flags, &arg))
|
||||||
return opterror(opt, "requires a value", flags);
|
return -1;
|
||||||
return (*opt->callback)(opt, get_arg(p), 0) ? (-1) : 0;
|
return (*opt->callback)(opt, arg, 0) ? (-1) : 0;
|
||||||
|
|
||||||
case OPTION_INTEGER:
|
case OPTION_INTEGER:
|
||||||
if (unset) {
|
if (unset) {
|
||||||
|
@ -113,9 +112,9 @@ static int get_value(struct parse_opt_ctx_t *p,
|
||||||
*(int *)opt->value = opt->defval;
|
*(int *)opt->value = opt->defval;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (!arg)
|
if (get_arg(p, opt, flags, &arg))
|
||||||
return opterror(opt, "requires a value", flags);
|
return -1;
|
||||||
*(int *)opt->value = strtol(get_arg(p), (char **)&s, 10);
|
*(int *)opt->value = strtol(arg, (char **)&s, 10);
|
||||||
if (*s)
|
if (*s)
|
||||||
return opterror(opt, "expects a numerical value", flags);
|
return opterror(opt, "expects a numerical value", flags);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -28,6 +28,7 @@ enum parse_opt_option_flags {
|
||||||
PARSE_OPT_NOARG = 2,
|
PARSE_OPT_NOARG = 2,
|
||||||
PARSE_OPT_NONEG = 4,
|
PARSE_OPT_NONEG = 4,
|
||||||
PARSE_OPT_HIDDEN = 8,
|
PARSE_OPT_HIDDEN = 8,
|
||||||
|
PARSE_OPT_LASTARG_DEFAULT = 16,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct option;
|
struct option;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче