rev-parse --branches/--tags/--remotes=pattern

Since local branch, tags and remote tracking branch namespaces are
most often used, add shortcut notations for globbing those in
manner similar to --glob option.

With this, one can express the "what I have but origin doesn't?"
as:

'git log --branches --not --remotes=origin'

Original-idea-by: Johannes Sixt <j6t@kdbg.org>
Signed-off-by: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Ilari Liusvaara 2010-01-20 11:48:26 +02:00 committed by Junio C Hamano
parent d08bae7e22
commit b09fe971de
9 changed files with 139 additions and 20 deletions

View File

@ -107,13 +107,13 @@ git log --follow builtin-rev-list.c::
those commits that occurred before the file was given its those commits that occurred before the file was given its
present name. present name.
git log --branches --not --glob=remotes/origin/*:: git log --branches --not --remotes=origin::
Shows all commits that are in any of local branches but not in Shows all commits that are in any of local branches but not in
any of remote tracking branches for 'origin' (what you have that any of remote tracking branches for 'origin' (what you have that
origin doesn't). origin doesn't).
git log master --not --glob=remotes/*/master:: git log master --not --remotes=*/master::
Shows all commits that are in local master but not in any remote Shows all commits that are in local master but not in any remote
repository master branches. repository master branches.

View File

@ -21,9 +21,9 @@ SYNOPSIS
[ \--full-history ] [ \--full-history ]
[ \--not ] [ \--not ]
[ \--all ] [ \--all ]
[ \--branches ] [ \--branches[=pattern] ]
[ \--tags ] [ \--tags=[pattern] ]
[ \--remotes ] [ \--remotes=[pattern] ]
[ \--glob=glob-pattern ] [ \--glob=glob-pattern ]
[ \--stdin ] [ \--stdin ]
[ \--quiet ] [ \--quiet ]

View File

@ -103,14 +103,21 @@ OPTIONS
--all:: --all::
Show all refs found in `$GIT_DIR/refs`. Show all refs found in `$GIT_DIR/refs`.
--branches:: --branches[=pattern]::
Show branch refs found in `$GIT_DIR/refs/heads`. Show branch refs found in `$GIT_DIR/refs/heads`. If `pattern`
is given, only branches matching given shell glob are shown.
If pattern lacks '?', '*', or '[', '/*' at the end is impiled.
--tags:: --tags[=pattern]::
Show tag refs found in `$GIT_DIR/refs/tags`. Show tag refs found in `$GIT_DIR/refs/tags`. If `pattern`
is given, only tags matching given shell glob are shown.
If pattern lacks '?', '*', or '[', '/*' at the end is impiled.
--remotes:: --remotes[=pattern]::
Show tag refs found in `$GIT_DIR/refs/remotes`. Show tag refs found in `$GIT_DIR/refs/remotes`. If `pattern`
is given, only remote tracking branches matching given shell glob
are shown. If pattern lacks '?', '*', or '[', '/*' at the end is
impiled.
--glob=glob-pattern:: --glob=glob-pattern::
Show refs matching shell glob pattern `glob-pattern`. If pattern Show refs matching shell glob pattern `glob-pattern`. If pattern

View File

@ -228,20 +228,26 @@ endif::git-rev-list[]
Pretend as if all the refs in `$GIT_DIR/refs/` are listed on the Pretend as if all the refs in `$GIT_DIR/refs/` are listed on the
command line as '<commit>'. command line as '<commit>'.
--branches:: --branches[=pattern]::
Pretend as if all the refs in `$GIT_DIR/refs/heads` are listed Pretend as if all the refs in `$GIT_DIR/refs/heads` are listed
on the command line as '<commit>'. on the command line as '<commit>'. If `pattern` is given, limit
branches to ones matching given shell glob. If pattern lacks '?',
'*', or '[', '/*' at the end is impiled.
--tags:: --tags[=pattern]::
Pretend as if all the refs in `$GIT_DIR/refs/tags` are listed Pretend as if all the refs in `$GIT_DIR/refs/tags` are listed
on the command line as '<commit>'. on the command line as '<commit>'. If `pattern` is given, limit
tags to ones matching given shell glob. If pattern lacks '?', '*',
or '[', '/*' at the end is impiled.
--remotes:: --remotes[=pattern]::
Pretend as if all the refs in `$GIT_DIR/refs/remotes` are listed Pretend as if all the refs in `$GIT_DIR/refs/remotes` are listed
on the command line as '<commit>'. on the command line as '<commit>'. If `pattern`is given, limit
remote tracking branches to ones matching given shell glob.
If pattern lacks '?', '*', or '[', '/*' at the end is impiled.
--glob=glob-pattern:: --glob=glob-pattern::
Pretend as if all the refs matching shell glob `glob-pattern` Pretend as if all the refs matching shell glob `glob-pattern`

View File

@ -41,6 +41,7 @@ static int is_rev_argument(const char *arg)
"--all", "--all",
"--bisect", "--bisect",
"--dense", "--dense",
"--branches=",
"--branches", "--branches",
"--header", "--header",
"--max-age=", "--max-age=",
@ -51,9 +52,11 @@ static int is_rev_argument(const char *arg)
"--objects-edge", "--objects-edge",
"--parents", "--parents",
"--pretty", "--pretty",
"--remotes=",
"--remotes", "--remotes",
"--glob=", "--glob=",
"--sparse", "--sparse",
"--tags=",
"--tags", "--tags",
"--topo-order", "--topo-order",
"--date-order", "--date-order",
@ -570,10 +573,20 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
for_each_ref_in("refs/bisect/good", anti_reference, NULL); for_each_ref_in("refs/bisect/good", anti_reference, NULL);
continue; continue;
} }
if (!prefixcmp(arg, "--branches=")) {
for_each_glob_ref_in(show_reference, arg + 11,
"refs/heads/", NULL);
continue;
}
if (!strcmp(arg, "--branches")) { if (!strcmp(arg, "--branches")) {
for_each_branch_ref(show_reference, NULL); for_each_branch_ref(show_reference, NULL);
continue; continue;
} }
if (!prefixcmp(arg, "--tags=")) {
for_each_glob_ref_in(show_reference, arg + 7,
"refs/tags/", NULL);
continue;
}
if (!strcmp(arg, "--tags")) { if (!strcmp(arg, "--tags")) {
for_each_tag_ref(show_reference, NULL); for_each_tag_ref(show_reference, NULL);
continue; continue;
@ -582,6 +595,11 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
for_each_glob_ref(show_reference, arg + 7, NULL); for_each_glob_ref(show_reference, arg + 7, NULL);
continue; continue;
} }
if (!prefixcmp(arg, "--remotes=")) {
for_each_glob_ref_in(show_reference, arg + 10,
"refs/remotes/", NULL);
continue;
}
if (!strcmp(arg, "--remotes")) { if (!strcmp(arg, "--remotes")) {
for_each_remote_ref(show_reference, NULL); for_each_remote_ref(show_reference, NULL);
continue; continue;

12
refs.c
View File

@ -690,15 +690,18 @@ int for_each_replace_ref(each_ref_fn fn, void *cb_data)
return do_for_each_ref("refs/replace/", fn, 13, 0, cb_data); return do_for_each_ref("refs/replace/", fn, 13, 0, cb_data);
} }
int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data) int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,
const char *prefix, void *cb_data)
{ {
struct strbuf real_pattern = STRBUF_INIT; struct strbuf real_pattern = STRBUF_INIT;
struct ref_filter filter; struct ref_filter filter;
const char *has_glob_specials; const char *has_glob_specials;
int ret; int ret;
if (prefixcmp(pattern, "refs/")) if (!prefix && prefixcmp(pattern, "refs/"))
strbuf_addstr(&real_pattern, "refs/"); strbuf_addstr(&real_pattern, "refs/");
else if (prefix)
strbuf_addstr(&real_pattern, prefix);
strbuf_addstr(&real_pattern, pattern); strbuf_addstr(&real_pattern, pattern);
has_glob_specials = strpbrk(pattern, "?*["); has_glob_specials = strpbrk(pattern, "?*[");
@ -719,6 +722,11 @@ int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data)
return ret; return ret;
} }
int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data)
{
return for_each_glob_ref_in(fn, pattern, NULL, cb_data);
}
int for_each_rawref(each_ref_fn fn, void *cb_data) int for_each_rawref(each_ref_fn fn, void *cb_data)
{ {
return do_for_each_ref("refs/", fn, 0, return do_for_each_ref("refs/", fn, 0,

1
refs.h
View File

@ -26,6 +26,7 @@ extern int for_each_branch_ref(each_ref_fn, void *);
extern int for_each_remote_ref(each_ref_fn, void *); extern int for_each_remote_ref(each_ref_fn, void *);
extern int for_each_replace_ref(each_ref_fn, void *); extern int for_each_replace_ref(each_ref_fn, void *);
extern int for_each_glob_ref(each_ref_fn, const char *pattern, void *); extern int for_each_glob_ref(each_ref_fn, const char *pattern, void *);
extern int for_each_glob_ref_in(each_ref_fn, const char *pattern, const char* prefix, void *);
/* can be used to learn about broken ref and symref */ /* can be used to learn about broken ref and symref */
extern int for_each_rawref(each_ref_fn, void *); extern int for_each_rawref(each_ref_fn, void *);

View File

@ -1364,6 +1364,24 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
for_each_glob_ref(handle_one_ref, arg + 7, &cb); for_each_glob_ref(handle_one_ref, arg + 7, &cb);
continue; continue;
} }
if (!prefixcmp(arg, "--branches=")) {
struct all_refs_cb cb;
init_all_refs_cb(&cb, revs, flags);
for_each_glob_ref_in(handle_one_ref, arg + 11, "refs/heads/", &cb);
continue;
}
if (!prefixcmp(arg, "--tags=")) {
struct all_refs_cb cb;
init_all_refs_cb(&cb, revs, flags);
for_each_glob_ref_in(handle_one_ref, arg + 7, "refs/tags/", &cb);
continue;
}
if (!prefixcmp(arg, "--remotes=")) {
struct all_refs_cb cb;
init_all_refs_cb(&cb, revs, flags);
for_each_glob_ref_in(handle_one_ref, arg + 10, "refs/remotes/", &cb);
continue;
}
if (!strcmp(arg, "--reflog")) { if (!strcmp(arg, "--reflog")) {
handle_reflog(revs, flags); handle_reflog(revs, flags);
continue; continue;

View File

@ -32,7 +32,9 @@ test_expect_success 'setup' '
git checkout -b someref master && git checkout -b someref master &&
commit some && commit some &&
git checkout master && git checkout master &&
commit master2 commit master2 &&
git tag foo/bar master &&
git update-ref refs/remotes/foo/baz master
' '
test_expect_success 'rev-parse --glob=refs/heads/subspace/*' ' test_expect_success 'rev-parse --glob=refs/heads/subspace/*' '
@ -65,6 +67,24 @@ test_expect_success 'rev-parse --glob=heads/subspace' '
' '
test_expect_success 'rev-parse --branches=subspace/*' '
compare rev-parse "subspace/one subspace/two" "--branches=subspace/*"
'
test_expect_success 'rev-parse --branches=subspace/' '
compare rev-parse "subspace/one subspace/two" "--branches=subspace/"
'
test_expect_success 'rev-parse --branches=subspace' '
compare rev-parse "subspace/one subspace/two" "--branches=subspace"
'
test_expect_success 'rev-parse --glob=heads/subspace/* --glob=heads/other/*' ' test_expect_success 'rev-parse --glob=heads/subspace/* --glob=heads/other/*' '
compare rev-parse "subspace/one subspace/two other/three" "--glob=heads/subspace/* --glob=heads/other/*" compare rev-parse "subspace/one subspace/two other/three" "--glob=heads/subspace/* --glob=heads/other/*"
@ -83,6 +103,18 @@ test_expect_success 'rev-parse --glob=heads/*' '
' '
test_expect_success 'rev-parse --tags=foo' '
compare rev-parse "foo/bar" "--tags=foo"
'
test_expect_success 'rev-parse --remotes=foo' '
compare rev-parse "foo/baz" "--remotes=foo"
'
test_expect_success 'rev-list --glob=refs/heads/subspace/*' ' test_expect_success 'rev-list --glob=refs/heads/subspace/*' '
compare rev-list "subspace/one subspace/two" "--glob=refs/heads/subspace/*" compare rev-list "subspace/one subspace/two" "--glob=refs/heads/subspace/*"
@ -113,6 +145,23 @@ test_expect_success 'rev-list --glob=heads/subspace' '
' '
test_expect_success 'rev-list --branches=subspace/*' '
compare rev-list "subspace/one subspace/two" "--branches=subspace/*"
'
test_expect_success 'rev-list --branches=subspace/' '
compare rev-list "subspace/one subspace/two" "--branches=subspace/"
'
test_expect_success 'rev-list --branches=subspace' '
compare rev-list "subspace/one subspace/two" "--branches=subspace"
'
test_expect_success 'rev-list --glob=heads/someref/* master' ' test_expect_success 'rev-list --glob=heads/someref/* master' '
compare rev-list "master" "--glob=heads/someref/* master" compare rev-list "master" "--glob=heads/someref/* master"
@ -131,4 +180,16 @@ test_expect_success 'rev-list --glob=heads/*' '
' '
test_expect_success 'rev-list --tags=foo' '
compare rev-list "foo/bar" "--tags=foo"
'
test_expect_success 'rev-list --remotes=foo' '
compare rev-list "foo/baz" "--remotes=foo"
'
test_done test_done