Merge branch 'mg/branch-list'

* mg/branch-list:
  t3200: clean up checks for file existence
  branch: -v does not automatically imply --list
  branch: allow pattern arguments
  branch: introduce --list option
  git-branch: introduce missing long forms for the options
  git-tag: introduce long forms for the options
  t6040: test branch -vv

Conflicts:
	Documentation/git-tag.txt
	t/t3200-branch.sh
This commit is contained in:
Junio C Hamano 2011-10-05 12:36:23 -07:00
commit 1077bf1ff6
7 changed files with 160 additions and 39 deletions

View File

@ -9,8 +9,8 @@ SYNOPSIS
--------
[verse]
'git branch' [--color[=<when>] | --no-color] [-r | -a]
[-v [--abbrev=<length> | --no-abbrev]]
[(--merged | --no-merged | --contains) [<commit>]]
[--list] [-v [--abbrev=<length> | --no-abbrev]]
[(--merged | --no-merged | --contains) [<commit>]] [<pattern>...]
'git branch' [--set-upstream | --track | --no-track] [-l] [-f] <branchname> [<start-point>]
'git branch' (-m | -M) [<oldbranch>] <newbranch>
'git branch' (-d | -D) [-r] <branchname>...
@ -20,7 +20,11 @@ DESCRIPTION
With no arguments, existing branches are listed and the current branch will
be highlighted with an asterisk. Option `-r` causes the remote-tracking
branches to be listed, and option `-a` shows both.
branches to be listed, and option `-a` shows both. This list mode is also
activated by the `--list` option (see below).
<pattern> restricts the output to matching branches, the pattern is a shell
wildcard (i.e., matched using fnmatch(3))
Multiple patterns may be given; if any of them matches, the tag is shown.
With `--contains`, shows only the branches that contain the named commit
(in other words, the branches whose tip commits are descendants of the
@ -64,6 +68,7 @@ way to clean up all obsolete remote-tracking branches.
OPTIONS
-------
-d::
--delete::
Delete a branch. The branch must be fully merged in its
upstream branch, or in `HEAD` if no upstream was set with
`--track` or `--set-upstream`.
@ -72,6 +77,7 @@ OPTIONS
Delete a branch irrespective of its merged status.
-l::
--create-reflog::
Create the branch's reflog. This activates recording of
all changes made to the branch ref, enabling use of date
based sha1 expressions such as "<branchname>@\{yesterday}".
@ -84,6 +90,7 @@ OPTIONS
already. Without `-f` 'git branch' refuses to change an existing branch.
-m::
--move::
Move/rename a branch and the corresponding reflog.
-M::
@ -100,14 +107,21 @@ OPTIONS
Same as `--color=never`.
-r::
--remotes::
List or delete (if used with -d) the remote-tracking branches.
-a::
--all::
List both remote-tracking branches and local branches.
--list::
Activate the list mode. `git branch <pattern>` would try to create a branch,
use `git branch --list <pattern>` to list matching branches.
-v::
--verbose::
Show sha1 and commit subject line for each head, along with
When in list mode,
show sha1 and commit subject line for each head, along with
relationship to upstream branch (if any). If given twice, print
the name of the upstream branch, as well.

View File

@ -43,12 +43,15 @@ GnuPG key for signing.
OPTIONS
-------
-a::
--annotate::
Make an unsigned, annotated tag object
-s::
--sign::
Make a GPG-signed tag, using the default e-mail address's key
-u <key-id>::
--local-user=<key-id>::
Make a GPG-signed tag, using the given key
-f::
@ -56,9 +59,11 @@ OPTIONS
Replace an existing tag with the given name (instead of failing)
-d::
--delete::
Delete existing tags with the given names.
-v::
--verify::
Verify the gpg signature of the given tag names.
-n<num>::
@ -69,6 +74,7 @@ OPTIONS
If the tag is not annotated, the commit message is displayed instead.
-l <pattern>::
--list <pattern>::
List tags with names that match the given pattern (or all if no
pattern is given). Running "git tag" without arguments also
lists all tags. The pattern is a shell wildcard (i.e., matched
@ -79,6 +85,7 @@ OPTIONS
Only list tags which contain the specified commit.
-m <msg>::
--message=<msg>::
Use the given tag message (instead of prompting).
If multiple `-m` options are given, their values are
concatenated as separate paragraphs.
@ -86,6 +93,7 @@ OPTIONS
is given.
-F <file>::
--file=<file>::
Take the tag message from the given file. Use '-' to
read the message from the standard input.
Implies `-a` if none of `-a`, `-s`, or `-u <key-id>`

View File

@ -260,9 +260,22 @@ static char *resolve_symref(const char *src, const char *prefix)
struct append_ref_cb {
struct ref_list *ref_list;
const char **pattern;
int ret;
};
static int match_patterns(const char **pattern, const char *refname)
{
if (!*pattern)
return 1; /* no pattern always matches */
while (*pattern) {
if (!fnmatch(*pattern, refname, 0))
return 1;
pattern++;
}
return 0;
}
static int append_ref(const char *refname, const unsigned char *sha1, int flags, void *cb_data)
{
struct append_ref_cb *cb = (struct append_ref_cb *)(cb_data);
@ -297,6 +310,9 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags,
if ((kind & ref_list->kinds) == 0)
return 0;
if (!match_patterns(cb->pattern, refname))
return 0;
commit = NULL;
if (ref_list->verbose || ref_list->with_commit || merge_filter != NO_FILTER) {
commit = lookup_commit_reference_gently(sha1, 1);
@ -492,7 +508,7 @@ static void show_detached(struct ref_list *ref_list)
}
}
static int print_ref_list(int kinds, int detached, int verbose, int abbrev, struct commit_list *with_commit)
static int print_ref_list(int kinds, int detached, int verbose, int abbrev, struct commit_list *with_commit, const char **pattern)
{
int i;
struct append_ref_cb cb;
@ -506,6 +522,7 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru
if (merge_filter != NO_FILTER)
init_revisions(&ref_list.revs, NULL);
cb.ref_list = &ref_list;
cb.pattern = pattern;
cb.ret = 0;
for_each_rawref(append_ref, &cb);
if (merge_filter != NO_FILTER) {
@ -523,7 +540,7 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru
qsort(ref_list.list, ref_list.index, sizeof(struct ref_item), ref_cmp);
detached = (detached && (kinds & REF_LOCAL_BRANCH));
if (detached)
if (detached && match_patterns(pattern, "HEAD"))
show_detached(&ref_list);
for (i = 0; i < ref_list.index; i++) {
@ -608,7 +625,7 @@ static int opt_parse_merge_filter(const struct option *opt, const char *arg, int
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, list = 0;
int verbose = 0, abbrev = -1, detached = 0;
int reflog = 0;
enum branch_track track;
@ -624,7 +641,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
OPT_SET_INT( 0, "set-upstream", &track, "change upstream info",
BRANCH_TRACK_OVERRIDE),
OPT__COLOR(&branch_use_color, "use colored output"),
OPT_SET_INT('r', NULL, &kinds, "act on remote-tracking branches",
OPT_SET_INT('r', "remotes", &kinds, "act on remote-tracking branches",
REF_REMOTE_BRANCH),
{
OPTION_CALLBACK, 0, "contains", &with_commit, "commit",
@ -641,13 +658,14 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
OPT__ABBREV(&abbrev),
OPT_GROUP("Specific git-branch actions:"),
OPT_SET_INT('a', NULL, &kinds, "list both remote-tracking and local branches",
OPT_SET_INT('a', "all", &kinds, "list both remote-tracking and local branches",
REF_REMOTE_BRANCH | REF_LOCAL_BRANCH),
OPT_BIT('d', NULL, &delete, "delete fully merged branch", 1),
OPT_BIT('d', "delete", &delete, "delete fully merged branch", 1),
OPT_BIT('D', NULL, &delete, "delete branch (even if not merged)", 2),
OPT_BIT('m', NULL, &rename, "move/rename a branch and its reflog", 1),
OPT_BIT('m', "move", &rename, "move/rename a branch and its reflog", 1),
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(0, "list", &list, "list branch names"),
OPT_BOOLEAN('l', "create-reflog", &reflog, "create the branch's reflog"),
OPT__FORCE(&force_create, "force creation (when already exists)"),
{
OPTION_CALLBACK, 0, "no-merged", &merge_filter_ref,
@ -686,7 +704,11 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, options, builtin_branch_usage,
0);
if (!!delete + !!rename + !!force_create > 1)
if (!delete && !rename && !force_create && argc == 0)
list = 1;
if (!!delete + !!rename + !!force_create + !!list > 1)
usage_with_options(builtin_branch_usage, options);
if (abbrev == -1)
@ -694,8 +716,9 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
if (delete)
return delete_branches(argc, argv, delete > 1, kinds);
else if (argc == 0)
return print_ref_list(kinds, detached, verbose, abbrev, with_commit);
else if (list)
return print_ref_list(kinds, detached, verbose, abbrev,
with_commit, argv);
else if (rename && (argc == 1))
rename_branch(head, argv[0], rename > 1);
else if (rename && (argc == 2))

View File

@ -429,21 +429,21 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
struct msg_arg msg = { 0, STRBUF_INIT };
struct commit_list *with_commit = NULL;
struct option options[] = {
OPT_BOOLEAN('l', NULL, &list, "list tag names"),
OPT_BOOLEAN('l', "list", &list, "list tag names"),
{ OPTION_INTEGER, 'n', NULL, &lines, "n",
"print <n> lines of each tag message",
PARSE_OPT_OPTARG, NULL, 1 },
OPT_BOOLEAN('d', NULL, &delete, "delete tags"),
OPT_BOOLEAN('v', NULL, &verify, "verify tags"),
OPT_BOOLEAN('d', "delete", &delete, "delete tags"),
OPT_BOOLEAN('v', "verify", &verify, "verify tags"),
OPT_GROUP("Tag creation options"),
OPT_BOOLEAN('a', NULL, &annotate,
OPT_BOOLEAN('a', "annotate", &annotate,
"annotated tag, needs a message"),
OPT_CALLBACK('m', NULL, &msg, "message",
OPT_CALLBACK('m', "message", &msg, "message",
"tag message", parse_msg_arg),
OPT_FILENAME('F', NULL, &msgfile, "read message from file"),
OPT_BOOLEAN('s', NULL, &sign, "annotated and GPG-signed tag"),
OPT_STRING('u', NULL, &keyid, "key-id",
OPT_FILENAME('F', "file", &msgfile, "read message from file"),
OPT_BOOLEAN('s', "sign", &sign, "annotated and GPG-signed tag"),
OPT_STRING('u', "local-user", &keyid, "key-id",
"use another key to sign the tag"),
OPT__FORCE(&force, "replace the tag if exists"),

View File

@ -23,7 +23,7 @@ test_expect_success \
test_expect_success \
'git branch --help should not have created a bogus branch' '
git branch --help </dev/null >/dev/null 2>/dev/null;
! test -f .git/refs/heads/--help
test_path_is_missing .git/refs/heads/--help
'
test_expect_success 'branch -h in broken repository' '
@ -39,11 +39,11 @@ test_expect_success 'branch -h in broken repository' '
test_expect_success \
'git branch abc should create a branch' \
'git branch abc && test -f .git/refs/heads/abc'
'git branch abc && test_path_is_file .git/refs/heads/abc'
test_expect_success \
'git branch a/b/c should create a branch' \
'git branch a/b/c && test -f .git/refs/heads/a/b/c'
'git branch a/b/c && test_path_is_file .git/refs/heads/a/b/c'
cat >expect <<EOF
$_z40 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 branch: Created from master
@ -52,15 +52,15 @@ test_expect_success \
'git branch -l d/e/f should create a branch and a log' \
'GIT_COMMITTER_DATE="2005-05-26 23:30" \
git branch -l d/e/f &&
test -f .git/refs/heads/d/e/f &&
test -f .git/logs/refs/heads/d/e/f &&
test_path_is_file .git/refs/heads/d/e/f &&
test_path_is_file .git/logs/refs/heads/d/e/f &&
test_cmp expect .git/logs/refs/heads/d/e/f'
test_expect_success \
'git branch -d d/e/f should delete a branch and a log' \
'git branch -d d/e/f &&
test ! -f .git/refs/heads/d/e/f &&
test ! -f .git/logs/refs/heads/d/e/f'
test_path_is_missing .git/refs/heads/d/e/f &&
test_path_is_missing .git/logs/refs/heads/d/e/f'
test_expect_success \
'git branch j/k should work after branch j has been deleted' \
@ -78,13 +78,13 @@ test_expect_success \
'git branch -m m m/m should work' \
'git branch -l m &&
git branch -m m m/m &&
test -f .git/logs/refs/heads/m/m'
test_path_is_file .git/logs/refs/heads/m/m'
test_expect_success \
'git branch -m n/n n should work' \
'git branch -l n/n &&
git branch -m n/n n
test -f .git/logs/refs/heads/n'
test_path_is_file .git/logs/refs/heads/n'
test_expect_success 'git branch -m o/o o should fail when o/p exists' '
git branch o/o &&
@ -110,6 +110,38 @@ test_expect_success 'git branch -M baz bam should succeed when baz is checked ou
git branch -M baz bam
'
test_expect_success 'git branch -v -d t should work' '
git branch t &&
test_path_is_file .git/refs/heads/t &&
git branch -v -d t &&
test_path_is_missing .git/refs/heads/t
'
test_expect_success 'git branch -v -m t s should work' '
git branch t &&
test_path_is_file .git/refs/heads/t &&
git branch -v -m t s &&
test_path_is_missing .git/refs/heads/t &&
test_path_is_file .git/refs/heads/s &&
git branch -d s
'
test_expect_success 'git branch -m -d t s should fail' '
git branch t &&
test_path_is_file .git/refs/heads/t &&
test_must_fail git branch -m -d t s &&
git branch -d t &&
test_path_is_missing .git/refs/heads/t
'
test_expect_success 'git branch --list -d t should fail' '
git branch t &&
test_path_is_file .git/refs/heads/t &&
test_must_fail git branch --list -d t &&
git branch -d t &&
test_path_is_missing .git/refs/heads/t
'
mv .git/config .git/config-saved
test_expect_success 'git branch -m q q2 without config should succeed' '
@ -124,12 +156,12 @@ git config branch.s/s.dummy Hello
test_expect_success \
'git branch -m s/s s should work when s/t is deleted' \
'git branch -l s/s &&
test -f .git/logs/refs/heads/s/s &&
test_path_is_file .git/logs/refs/heads/s/s &&
git branch -l s/t &&
test -f .git/logs/refs/heads/s/t &&
test_path_is_file .git/logs/refs/heads/s/t &&
git branch -d s/t &&
git branch -m s/s s &&
test -f .git/logs/refs/heads/s'
test_path_is_file .git/logs/refs/heads/s'
test_expect_success 'config information was renamed, too' \
"test $(git config branch.s.dummy) = Hello &&
@ -140,8 +172,8 @@ test_expect_success 'renaming a symref is not allowed' \
git symbolic-ref refs/heads/master2 refs/heads/master &&
test_must_fail git branch -m master2 master3 &&
git symbolic-ref refs/heads/master2 &&
test -f .git/refs/heads/master &&
! test -f .git/refs/heads/master3
test_path_is_file .git/refs/heads/master &&
test_path_is_missing .git/refs/heads/master3
'
test_expect_success SYMLINKS \
@ -250,8 +282,8 @@ test_expect_success \
'git checkout -b g/h/i -l should create a branch and a log' \
'GIT_COMMITTER_DATE="2005-05-26 23:30" \
git checkout -b g/h/i -l master &&
test -f .git/refs/heads/g/h/i &&
test -f .git/logs/refs/heads/g/h/i &&
test_path_is_file .git/refs/heads/g/h/i &&
test_path_is_file .git/logs/refs/heads/g/h/i &&
test_cmp expect .git/logs/refs/heads/g/h/i'
test_expect_success 'checkout -b makes reflog by default' '

View File

@ -32,6 +32,20 @@ test_expect_success 'git branch shows local branches' '
test_cmp expect actual
'
test_expect_success 'git branch --list shows local branches' '
git branch --list >actual &&
test_cmp expect actual
'
cat >expect <<'EOF'
branch-one
branch-two
EOF
test_expect_success 'git branch --list pattern shows matching local branches' '
git branch --list branch* >actual &&
test_cmp expect actual
'
cat >expect <<'EOF'
origin/HEAD -> origin/branch-one
origin/branch-one
@ -66,6 +80,20 @@ test_expect_success 'git branch -v shows branch summaries' '
test_cmp expect actual
'
cat >expect <<'EOF'
two
one
EOF
test_expect_success 'git branch --list -v pattern shows branch summaries' '
git branch --list -v branch* >tmp &&
awk "{print \$NF}" <tmp >actual &&
test_cmp expect actual
'
test_expect_success 'git branch -v pattern does not show branch summaries' '
test_must_fail git branch -v branch*
'
cat >expect <<'EOF'
* (no branch)
branch-one

View File

@ -51,6 +51,22 @@ test_expect_success 'branch -v' '
test_i18ncmp expect actual
'
cat >expect <<\EOF
b1 origin/master: ahead 1, behind 1
b2 origin/master: ahead 1, behind 1
b3 origin/master: behind 1
b4 origin/master: ahead 2
EOF
test_expect_success 'branch -vv' '
(
cd test &&
git branch -vv
) |
sed -n -e "$script" >actual &&
test_i18ncmp expect actual
'
test_expect_success 'checkout' '
(
cd test && git checkout b1