Skip to content

Commit 3707986

Browse files
committed
Merge branch 'dl/includeif-onbranch'
The conditional inclusion mechanism learned to base the choice on the branch the HEAD currently is on. * dl/includeif-onbranch: config: learn the "onbranch:" includeIf condition
2 parents 88f95e4 + 07b2c0e commit 3707986

File tree

3 files changed

+87
-2
lines changed

3 files changed

+87
-2
lines changed

Documentation/config.txt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,20 @@ refer to linkgit:gitignore[5] for details. For convenience:
144144
This is the same as `gitdir` except that matching is done
145145
case-insensitively (e.g. on case-insensitive file sytems)
146146

147+
`onbranch`::
148+
The data that follows the keyword `onbranch:` is taken to be a
149+
pattern with standard globbing wildcards and two additional
150+
ones, `**/` and `/**`, that can match multiple path components.
151+
If we are in a worktree where the name of the branch that is
152+
currently checked out matches the pattern, the include condition
153+
is met.
154+
+
155+
If the pattern ends with `/`, `**` will be automatically added. For
156+
example, the pattern `foo/` becomes `foo/**`. In other words, it matches
157+
all branches that begin with `foo/`. This is useful if your branches are
158+
organized hierarchically and you would like to apply a configuration to
159+
all the branches in that hierarchy.
160+
147161
A few more notes on matching via `gitdir` and `gitdir/i`:
148162

149163
* Symlinks in `$GIT_DIR` are not resolved before matching.
@@ -206,6 +220,11 @@ Example
206220
[includeIf "gitdir:/path/to/group/"]
207221
path = foo.inc
208222

223+
; include only if we are in a worktree where foo-branch is
224+
; currently checked out
225+
[includeIf "onbranch:foo-branch"]
226+
path = foo.inc
227+
209228
Values
210229
~~~~~~
211230

config.c

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "utf8.h"
2020
#include "dir.h"
2121
#include "color.h"
22+
#include "refs.h"
2223

2324
struct config_source {
2425
struct config_source *prev;
@@ -170,6 +171,12 @@ static int handle_path_include(const char *path, struct config_include_data *inc
170171
return ret;
171172
}
172173

174+
static void add_trailing_starstar_for_dir(struct strbuf *pat)
175+
{
176+
if (pat->len && is_dir_sep(pat->buf[pat->len - 1]))
177+
strbuf_addstr(pat, "**");
178+
}
179+
173180
static int prepare_include_condition_pattern(struct strbuf *pat)
174181
{
175182
struct strbuf path = STRBUF_INIT;
@@ -199,8 +206,7 @@ static int prepare_include_condition_pattern(struct strbuf *pat)
199206
} else if (!is_absolute_path(pat->buf))
200207
strbuf_insert(pat, 0, "**/", 3);
201208

202-
if (pat->len && is_dir_sep(pat->buf[pat->len - 1]))
203-
strbuf_addstr(pat, "**");
209+
add_trailing_starstar_for_dir(pat);
204210

205211
strbuf_release(&path);
206212
return prefix;
@@ -264,6 +270,25 @@ static int include_by_gitdir(const struct config_options *opts,
264270
return ret;
265271
}
266272

273+
static int include_by_branch(const char *cond, size_t cond_len)
274+
{
275+
int flags;
276+
int ret;
277+
struct strbuf pattern = STRBUF_INIT;
278+
const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, &flags);
279+
const char *shortname;
280+
281+
if (!refname || !(flags & REF_ISSYMREF) ||
282+
!skip_prefix(refname, "refs/heads/", &shortname))
283+
return 0;
284+
285+
strbuf_add(&pattern, cond, cond_len);
286+
add_trailing_starstar_for_dir(&pattern);
287+
ret = !wildmatch(pattern.buf, shortname, WM_PATHNAME);
288+
strbuf_release(&pattern);
289+
return ret;
290+
}
291+
267292
static int include_condition_is_true(const struct config_options *opts,
268293
const char *cond, size_t cond_len)
269294
{
@@ -272,6 +297,8 @@ static int include_condition_is_true(const struct config_options *opts,
272297
return include_by_gitdir(opts, cond, cond_len, 0);
273298
else if (skip_prefix_mem(cond, cond_len, "gitdir/i:", &cond, &cond_len))
274299
return include_by_gitdir(opts, cond, cond_len, 1);
300+
else if (skip_prefix_mem(cond, cond_len, "onbranch:", &cond, &cond_len))
301+
return include_by_branch(cond, cond_len);
275302

276303
/* unknown conditionals are always false */
277304
return 0;

t/t1305-config-include.sh

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,45 @@ test_expect_success SYMLINKS 'conditional include, gitdir matching symlink, icas
309309
)
310310
'
311311

312+
test_expect_success 'conditional include, onbranch' '
313+
echo "[includeIf \"onbranch:foo-branch\"]path=bar9" >>.git/config &&
314+
echo "[test]nine=9" >.git/bar9 &&
315+
git checkout -b master &&
316+
test_must_fail git config test.nine &&
317+
git checkout -b foo-branch &&
318+
echo 9 >expect &&
319+
git config test.nine >actual &&
320+
test_cmp expect actual
321+
'
322+
323+
test_expect_success 'conditional include, onbranch, wildcard' '
324+
echo "[includeIf \"onbranch:?oo-*/**\"]path=bar10" >>.git/config &&
325+
echo "[test]ten=10" >.git/bar10 &&
326+
git checkout -b not-foo-branch/a &&
327+
test_must_fail git config test.ten &&
328+
329+
echo 10 >expect &&
330+
git checkout -b foo-branch/a/b/c &&
331+
git config test.ten >actual &&
332+
test_cmp expect actual &&
333+
334+
git checkout -b moo-bar/a &&
335+
git config test.ten >actual &&
336+
test_cmp expect actual
337+
'
338+
339+
test_expect_success 'conditional include, onbranch, implicit /** for /' '
340+
echo "[includeIf \"onbranch:foo-dir/\"]path=bar11" >>.git/config &&
341+
echo "[test]eleven=11" >.git/bar11 &&
342+
git checkout -b not-foo-dir/a &&
343+
test_must_fail git config test.eleven &&
344+
345+
echo 11 >expect &&
346+
git checkout -b foo-dir/a/b/c &&
347+
git config test.eleven >actual &&
348+
test_cmp expect actual
349+
'
350+
312351
test_expect_success 'include cycles are detected' '
313352
cat >.gitconfig <<-\EOF &&
314353
[test]value = gitconfig

0 commit comments

Comments
 (0)