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@xxxxxxxx> Signed-off-by: Ilari Liusvaara <ilari.liusvaara@xxxxxxxxxxx> --- Builds on top of --glob patch. Documentation/git-log.txt | 4 +- Documentation/git-rev-list.txt | 6 ++-- Documentation/git-rev-parse.txt | 19 +++++++--- Documentation/rev-list-options.txt | 18 +++++++--- builtin-rev-parse.c | 18 ++++++++++ refs.c | 12 ++++++- refs.h | 1 + revision.c | 18 ++++++++++ t/t6018-rev-list-glob.sh | 62 +++++++++++++++++++++++++++++++++++- 9 files changed, 138 insertions(+), 20 deletions(-) diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt index 0b874e3..0acd526 100644 --- a/Documentation/git-log.txt +++ b/Documentation/git-log.txt @@ -107,13 +107,13 @@ git log --follow builtin-rev-list.c:: those commits that occurred before the file was given its 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 any of remote tracking branches for 'origin' (what you have that 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 repository master branches. diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt index 33122a3..f857116 100644 --- a/Documentation/git-rev-list.txt +++ b/Documentation/git-rev-list.txt @@ -21,9 +21,9 @@ SYNOPSIS [ \--full-history ] [ \--not ] [ \--all ] - [ \--branches ] - [ \--tags ] - [ \--remotes ] + [ \--branches[=pattern] ] + [ \--tags=[pattern] ] + [ \--remotes=[pattern] ] [ \--glob=glob-pattern ] [ \--stdin ] [ \--quiet ] diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt index 6eb8c14..afe8699 100644 --- a/Documentation/git-rev-parse.txt +++ b/Documentation/git-rev-parse.txt @@ -103,14 +103,21 @@ OPTIONS --all:: Show all refs found in `$GIT_DIR/refs`. ---branches:: - Show branch refs found in `$GIT_DIR/refs/heads`. +--branches[=pattern]:: + 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:: - Show tag refs found in `$GIT_DIR/refs/tags`. +--tags[=pattern]:: + 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:: - Show tag refs found in `$GIT_DIR/refs/remotes`. +--remotes[=pattern]:: + 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:: Show refs matching shell glob pattern `glob-pattern`. If pattern diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt index 6d03c17..3ef7117 100644 --- a/Documentation/rev-list-options.txt +++ b/Documentation/rev-list-options.txt @@ -228,20 +228,26 @@ endif::git-rev-list[] Pretend as if all the refs in `$GIT_DIR/refs/` are listed on the command line as '<commit>'. ---branches:: +--branches[=pattern]:: 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 - 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 - 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:: Pretend as if all the refs matching shell glob `glob-pattern` diff --git a/builtin-rev-parse.c b/builtin-rev-parse.c index a635dde..d14fe20 100644 --- a/builtin-rev-parse.c +++ b/builtin-rev-parse.c @@ -41,6 +41,7 @@ static int is_rev_argument(const char *arg) "--all", "--bisect", "--dense", + "--branches=", "--branches", "--header", "--max-age=", @@ -51,9 +52,11 @@ static int is_rev_argument(const char *arg) "--objects-edge", "--parents", "--pretty", + "--remotes=", "--remotes", "--glob=", "--sparse", + "--tags=", "--tags", "--topo-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); continue; } + if (!prefixcmp(arg, "--branches=")) { + for_each_glob_ref_in(show_reference, arg + 11, + "refs/heads/", NULL); + continue; + } if (!strcmp(arg, "--branches")) { for_each_branch_ref(show_reference, NULL); continue; } + if (!prefixcmp(arg, "--tags=")) { + for_each_glob_ref_in(show_reference, arg + 7, + "refs/tags/", NULL); + continue; + } if (!strcmp(arg, "--tags")) { for_each_tag_ref(show_reference, NULL); 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); continue; } + if (!prefixcmp(arg, "--remotes=")) { + for_each_glob_ref_in(show_reference, arg + 10, + "refs/remotes/", NULL); + continue; + } if (!strcmp(arg, "--remotes")) { for_each_remote_ref(show_reference, NULL); continue; diff --git a/refs.c b/refs.c index 5adf69c..af78c31 100644 --- a/refs.c +++ b/refs.c @@ -691,15 +691,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); } -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 ref_filter filter; const char *has_glob_specials; int ret; - if (prefixcmp(pattern, "refs/")) + if (!prefix && prefixcmp(pattern, "refs/")) strbuf_addstr(&real_pattern, "refs/"); + else if (prefix) + strbuf_addstr(&real_pattern, prefix); strbuf_addstr(&real_pattern, pattern); has_glob_specials = strpbrk(pattern, "?*["); @@ -720,6 +723,11 @@ int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data) 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) { return do_for_each_ref("refs/", fn, 0, diff --git a/refs.h b/refs.h index 78ad173..f7648b9 100644 --- a/refs.h +++ b/refs.h @@ -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_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_in(each_ref_fn, const char *pattern, const char* prefix, void *); /* can be used to learn about broken ref and symref */ extern int for_each_rawref(each_ref_fn, void *); diff --git a/revision.c b/revision.c index 162b182..1e9277d 100644 --- a/revision.c +++ b/revision.c @@ -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); 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")) { handle_reflog(revs, flags); continue; diff --git a/t/t6018-rev-list-glob.sh b/t/t6018-rev-list-glob.sh index 0d7e4bc..bf85e0c 100755 --- a/t/t6018-rev-list-glob.sh +++ b/t/t6018-rev-list-glob.sh @@ -33,7 +33,9 @@ test_expect_success 'setup' ' git checkout -b someref master && commit some && 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/*' ' @@ -66,6 +68,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/*' ' compare rev-parse "subspace/one subspace/two other/three" "--glob=heads/subspace/* --glob=heads/other/*" @@ -84,6 +104,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/*' ' compare rev-list "subspace/one subspace/two" "--glob=refs/heads/subspace/*" @@ -114,6 +146,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' ' compare rev-list "master" "--glob=heads/someref/* master" @@ -132,5 +181,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 -- 1.6.6.199.gff4b0 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html