@matheusbsbs / matheus-bagliano / commits / d08bae7e22
Fork 0

rev-parse --glob

Add --glob=<glob-pattern> option to rev-parse and everything that accepts its options. This option matches all refs that match given shell glob pattern (complete with some DWIM logic). Example: 'git log --branches --not --glob=remotes/origin' To show what you have that origin doesn't. Signed-off-by: Ilari Liusvaara <ilari.liusvaara@elisanet.fi> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Ilari Liusvaara committed Jan 20, 2010 at 11:48 UTC d08bae7e221727e26baab984b792854b842130d7
9 files changed +223 -2
Documentation/git-log.txt
+11
@@ -107,6 +107,17 @@ git log --follow builtin-rev-list.c::
107 those commits that occurred before the file was given its
108 present name.
109
110 +git log --branches --not --glob=remotes/origin/*::
111 +
112 + Shows all commits that are in any of local branches but not in
113 + any of remote tracking branches for 'origin' (what you have that
114 + origin doesn't).
115 +
116 +git log master --not --glob=remotes/*/master::
117 +
118 + Shows all commits that are in local master but not in any remote
119 + repository master branches.
120 +
121 Discussion
122 ----------
123
Documentation/git-rev-list.txt
+1
@@ -24,6 +24,7 @@ SYNOPSIS
24 [ \--branches ]
25 [ \--tags ]
26 [ \--remotes ]
27 + [ \--glob=glob-pattern ]
28 [ \--stdin ]
29 [ \--quiet ]
30 [ \--topo-order ]
Documentation/git-rev-parse.txt
+5
@@ -112,6 +112,11 @@ OPTIONS
112 --remotes::
113 Show tag refs found in `$GIT_DIR/refs/remotes`.
114
115 +--glob=glob-pattern::
116 + Show refs matching shell glob pattern `glob-pattern`. If pattern
117 + specified lacks leading 'refs/', it is automatically prepended.
118 + If pattern lacks '?', '*', or '[', '/*' at the end is impiled.
119 +
120 --show-prefix::
121 When the command is invoked from a subdirectory, show the
122 path of the current directory relative to the top-level
Documentation/rev-list-options.txt
+7
@@ -243,6 +243,13 @@ endif::git-rev-list[]
243 Pretend as if all the refs in `$GIT_DIR/refs/remotes` are listed
244 on the command line as '<commit>'.
245
246 +--glob=glob-pattern::
247 + Pretend as if all the refs matching shell glob `glob-pattern`
248 + are listed on the command line as '<commit>'. Leading 'refs/',
249 + is automatically prepended if missing. If pattern lacks '?', '*',
250 + or '[', '/*' at the end is impiled.
251 +
252 +
253 ifndef::git-rev-list[]
254 --bisect::
255
builtin-rev-parse.c
+5
@@ -52,6 +52,7 @@ static int is_rev_argument(const char *arg)
52 "--parents",
53 "--pretty",
54 "--remotes",
55 + "--glob=",
56 "--sparse",
57 "--tags",
58 "--topo-order",
@@ -577,6 +578,10 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
578 for_each_tag_ref(show_reference, NULL);
579 continue;
580 }
581 + if (!prefixcmp(arg, "--glob=")) {
582 + for_each_glob_ref(show_reference, arg + 7, NULL);
583 + continue;
584 + }
585 if (!strcmp(arg, "--remotes")) {
586 for_each_remote_ref(show_reference, NULL);
587 continue;
refs.c
+45
@@ -519,6 +519,13 @@ const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *
519 return ref;
520 }
521
522 +/* The argument to filter_refs */
523 +struct ref_filter {
524 + const char *pattern;
525 + each_ref_fn *fn;
526 + void *cb_data;
527 +};
528 +
529 int read_ref(const char *ref, unsigned char *sha1)
530 {
531 if (resolve_ref(ref, sha1, 1, NULL))
@@ -545,6 +552,15 @@ static int do_one_ref(const char *base, each_ref_fn fn, int trim,
552 return fn(entry->name + trim, entry->sha1, entry->flag, cb_data);
553 }
554
555 +static int filter_refs(const char *ref, const unsigned char *sha, int flags,
556 + void *data)
557 +{
558 + struct ref_filter *filter = (struct ref_filter *)data;
559 + if (fnmatch(filter->pattern, ref, 0))
560 + return 0;
561 + return filter->fn(ref, sha, flags, filter->cb_data);
562 +}
563 +
564 int peel_ref(const char *ref, unsigned char *sha1)
565 {
566 int flag;
@@ -674,6 +690,35 @@ int for_each_replace_ref(each_ref_fn fn, void *cb_data)
690 return do_for_each_ref("refs/replace/", fn, 13, 0, cb_data);
691 }
692
693 +int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data)
694 +{
695 + struct strbuf real_pattern = STRBUF_INIT;
696 + struct ref_filter filter;
697 + const char *has_glob_specials;
698 + int ret;
699 +
700 + if (prefixcmp(pattern, "refs/"))
701 + strbuf_addstr(&real_pattern, "refs/");
702 + strbuf_addstr(&real_pattern, pattern);
703 +
704 + has_glob_specials = strpbrk(pattern, "?*[");
705 + if (!has_glob_specials) {
706 + /* Append impiled '/' '*' if not present. */
707 + if (real_pattern.buf[real_pattern.len - 1] != '/')
708 + strbuf_addch(&real_pattern, '/');
709 + /* No need to check for '*', there is none. */
710 + strbuf_addch(&real_pattern, '*');
711 + }
712 +
713 + filter.pattern = real_pattern.buf;
714 + filter.fn = fn;
715 + filter.cb_data = cb_data;
716 + ret = for_each_ref(filter_refs, &filter);
717 +
718 + strbuf_release(&real_pattern);
719 + return ret;
720 +}
721 +
722 int for_each_rawref(each_ref_fn fn, void *cb_data)
723 {
724 return do_for_each_ref("refs/", fn, 0,
refs.h
+1
@@ -25,6 +25,7 @@ extern int for_each_tag_ref(each_ref_fn, void *);
25 extern int for_each_branch_ref(each_ref_fn, void *);
26 extern int for_each_remote_ref(each_ref_fn, void *);
27 extern int for_each_replace_ref(each_ref_fn, void *);
28 +extern int for_each_glob_ref(each_ref_fn, const char *pattern, void *);
29
30 /* can be used to learn about broken ref and symref */
31 extern int for_each_rawref(each_ref_fn, void *);
revision.c
+14 -2
@@ -699,12 +699,18 @@ static int handle_one_ref(const char *path, const unsigned char *sha1, int flag,
699 return 0;
700 }
701
702 +static void init_all_refs_cb(struct all_refs_cb *cb, struct rev_info *revs,
703 + unsigned flags)
704 +{
705 + cb->all_revs = revs;
706 + cb->all_flags = flags;
707 +}
708 +
709 static void handle_refs(struct rev_info *revs, unsigned flags,
710 int (*for_each)(each_ref_fn, void *))
711 {
712 struct all_refs_cb cb;
706 - cb.all_revs = revs;
707 - cb.all_flags = flags;
713 + init_all_refs_cb(&cb, revs, flags);
714 for_each(handle_one_ref, &cb);
715 }
716
@@ -1352,6 +1358,12 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
1358 handle_refs(revs, flags, for_each_remote_ref);
1359 continue;
1360 }
1361 + if (!prefixcmp(arg, "--glob=")) {
1362 + struct all_refs_cb cb;
1363 + init_all_refs_cb(&cb, revs, flags);
1364 + for_each_glob_ref(handle_one_ref, arg + 7, &cb);
1365 + continue;
1366 + }
1367 if (!strcmp(arg, "--reflog")) {
1368 handle_reflog(revs, flags);
1369 continue;
t/t6018-rev-list-glob.sh new
+134
@@ -0,0 +1,134 @@
1 +#!/bin/sh
2 +
3 +test_description='rev-list/rev-parse --glob'
4 +
5 +. ./test-lib.sh
6 +
7 +commit () {
8 + test_tick &&
9 + echo $1 > foo &&
10 + git add foo &&
11 + git commit -m "$1"
12 +}
13 +
14 +compare () {
15 + # Split arguments on whitespace.
16 + git $1 $2 >expected &&
17 + git $1 $3 >actual &&
18 + test_cmp expected actual
19 +}
20 +
21 +test_expect_success 'setup' '
22 +
23 + commit master &&
24 + git checkout -b subspace/one master &&
25 + commit one &&
26 + git checkout -b subspace/two master &&
27 + commit two &&
28 + git checkout -b subspace-x master &&
29 + commit subspace-x &&
30 + git checkout -b other/three master &&
31 + commit three &&
32 + git checkout -b someref master &&
33 + commit some &&
34 + git checkout master &&
35 + commit master2
36 +'
37 +
38 +test_expect_success 'rev-parse --glob=refs/heads/subspace/*' '
39 +
40 + compare rev-parse "subspace/one subspace/two" "--glob=refs/heads/subspace/*"
41 +
42 +'
43 +
44 +test_expect_success 'rev-parse --glob=heads/subspace/*' '
45 +
46 + compare rev-parse "subspace/one subspace/two" "--glob=heads/subspace/*"
47 +
48 +'
49 +
50 +test_expect_success 'rev-parse --glob=refs/heads/subspace/' '
51 +
52 + compare rev-parse "subspace/one subspace/two" "--glob=refs/heads/subspace/"
53 +
54 +'
55 +
56 +test_expect_success 'rev-parse --glob=heads/subspace/' '
57 +
58 + compare rev-parse "subspace/one subspace/two" "--glob=heads/subspace/"
59 +
60 +'
61 +
62 +test_expect_success 'rev-parse --glob=heads/subspace' '
63 +
64 + compare rev-parse "subspace/one subspace/two" "--glob=heads/subspace"
65 +
66 +'
67 +
68 +test_expect_success 'rev-parse --glob=heads/subspace/* --glob=heads/other/*' '
69 +
70 + compare rev-parse "subspace/one subspace/two other/three" "--glob=heads/subspace/* --glob=heads/other/*"
71 +
72 +'
73 +
74 +test_expect_success 'rev-parse --glob=heads/someref/* master' '
75 +
76 + compare rev-parse "master" "--glob=heads/someref/* master"
77 +
78 +'
79 +
80 +test_expect_success 'rev-parse --glob=heads/*' '
81 +
82 + compare rev-parse "master other/three someref subspace-x subspace/one subspace/two" "--glob=heads/*"
83 +
84 +'
85 +
86 +test_expect_success 'rev-list --glob=refs/heads/subspace/*' '
87 +
88 + compare rev-list "subspace/one subspace/two" "--glob=refs/heads/subspace/*"
89 +
90 +'
91 +
92 +test_expect_success 'rev-list --glob=heads/subspace/*' '
93 +
94 + compare rev-list "subspace/one subspace/two" "--glob=heads/subspace/*"
95 +
96 +'
97 +
98 +test_expect_success 'rev-list --glob=refs/heads/subspace/' '
99 +
100 + compare rev-list "subspace/one subspace/two" "--glob=refs/heads/subspace/"
101 +
102 +'
103 +
104 +test_expect_success 'rev-list --glob=heads/subspace/' '
105 +
106 + compare rev-list "subspace/one subspace/two" "--glob=heads/subspace/"
107 +
108 +'
109 +
110 +test_expect_success 'rev-list --glob=heads/subspace' '
111 +
112 + compare rev-list "subspace/one subspace/two" "--glob=heads/subspace"
113 +
114 +'
115 +
116 +test_expect_success 'rev-list --glob=heads/someref/* master' '
117 +
118 + compare rev-list "master" "--glob=heads/someref/* master"
119 +
120 +'
121 +
122 +test_expect_success 'rev-list --glob=heads/subspace/* --glob=heads/other/*' '
123 +
124 + compare rev-list "subspace/one subspace/two other/three" "--glob=heads/subspace/* --glob=heads/other/*"
125 +
126 +'
127 +
128 +test_expect_success 'rev-list --glob=heads/*' '
129 +
130 + compare rev-list "master other/three someref subspace-x subspace/one subspace/two" "--glob=heads/*"
131 +
132 +'
133 +
134 +test_done