Re: feature request: git-config: Add conditional include for gitbranch

2018-03-08 Thread Duy Nguyen
On Thu, Mar 08, 2018 at 07:23:00PM -0500, Jeremy Bicha wrote:
> Use Case
> ==
> Jeremy is a developer for Debian and Ubuntu. The same repository is
> used for both Debian and Ubuntu packaging but with different branches.
> For commits to the debian/master branch, Jeremy wants to use his
> @debian.org email address. For commits to the ubuntu/master branch,
> Jeremy wants to use his @ubuntu.com email.
> 
> Proposal
> ===
> The includeIf feature of git-config could be extended to offer a
> gitbranch conditional include in addition to the gitdir conditional
> include it already offers.

Interesting. It looks quite simple to do this. My prototype looks like
this.

-- 8< --
Subject: [PATCH] config: support conditional include by matching ref pattern

Signed-off-by: Nguyễn Thái Ngọc Duy 
---
 Documentation/config.txt  | 12 
 config.c  | 30 ++
 t/t1305-config-include.sh | 26 ++
 3 files changed, 68 insertions(+)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index ce9102cea8..4e8fb6d99c 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -143,6 +143,18 @@ refer to linkgit:gitignore[5] for details. For convenience:
This is the same as `gitdir` except that matching is done
case-insensitively (e.g. on case-insensitive file sytems)
 
+`ref`::
+   The data that follows the keyword `ref:` is used as a glob
+   pattern that matches against the current branch. `*` in the
+   pattern does not match `/` and `**` matches multiple levels,
+   the same as .gitignore syntax. The branch is a full reference
+   (i.e. with `refs/heads/` prefix). If HEAD is detached, the
+   pattern will be matched against the value "HEAD".
+
+`ref/i`::
+   This is the same as `ref` except that matching is done
+   case-insensitively
+
 A few more notes on matching via `gitdir` and `gitdir/i`:
 
  * Symlinks in `$GIT_DIR` are not resolved before matching.
diff --git a/config.c b/config.c
index b0c20e6cb8..72ff2da667 100644
--- a/config.c
+++ b/config.c
@@ -16,6 +16,7 @@
 #include "string-list.h"
 #include "utf8.h"
 #include "dir.h"
+#include "refs.h"
 
 struct config_source {
struct config_source *prev;
@@ -202,6 +203,31 @@ static int prepare_include_condition_pattern(struct strbuf 
*pat)
return prefix;
 }
 
+static int include_by_ref(const struct config_options *opts,
+ const char *cond, size_t cond_len, int icase)
+{
+   struct strbuf pattern = STRBUF_INIT;
+   char *branch;
+   unsigned flags = WM_PATHNAME;
+   int ret;
+
+   if (!opts->git_dir)
+   return 0;
+
+   branch = resolve_refdup("HEAD", 0, NULL, NULL);
+   if (!branch)
+   return 0;
+
+   if (icase)
+   flags |= WM_CASEFOLD;
+   strbuf_add(,  cond, cond_len);
+   ret = !wildmatch(pattern.buf, branch, flags);
+
+   free(branch);
+   strbuf_release();
+   return ret;
+}
+
 static int include_by_gitdir(const struct config_options *opts,
 const char *cond, size_t cond_len, int icase)
 {
@@ -268,6 +294,10 @@ static int include_condition_is_true(const struct 
config_options *opts,
return include_by_gitdir(opts, cond, cond_len, 0);
else if (skip_prefix_mem(cond, cond_len, "gitdir/i:", , _len))
return include_by_gitdir(opts, cond, cond_len, 1);
+   else if (skip_prefix_mem(cond, cond_len, "ref:", , _len))
+   return include_by_ref(opts, cond, cond_len, 0);
+   else if (skip_prefix_mem(cond, cond_len, "ref/i:", , _len))
+   return include_by_ref(opts, cond, cond_len, 1);
 
/* unknown conditionals are always false */
return 0;
diff --git a/t/t1305-config-include.sh b/t/t1305-config-include.sh
index d9d2f545a4..27ecfc74b7 100755
--- a/t/t1305-config-include.sh
+++ b/t/t1305-config-include.sh
@@ -296,6 +296,32 @@ test_expect_success SYMLINKS 'conditional include, gitdir 
matching symlink, icas
)
 '
 
+test_expect_success 'conditional include by refs' '
+   git init inc-by-ref &&
+   (
+   check() {
+   echo "ref: $1" >.git/HEAD &&
+   echo "[includeIf \"ref:$2\"]path=bar8" >.git/config &&
+   git config test.var >actual &&
+   test_cmp expect actual
+   }
+   cd inc-by-ref &&
+   echo "[test]var=matched" >.git/bar8 &&
+   echo matched >expect &&
+
+   check refs/heads/foo refs/heads/foo &&
+   check refs/heads/foo "refs/heads/*" &&
+   check refs/heads/foo "refs/heads/f*" &&
+   check refs/heads/deep/in/foo "refs/heads/**/foo" &&
+
+   test_commit one &&
+   git checkout --detach &&
+   echo "[includeIf \"ref:HEAD\"]path=bar8" 

feature request: git-config: Add conditional include for gitbranch

2018-03-08 Thread Jeremy Bicha
Use Case
==
Jeremy is a developer for Debian and Ubuntu. The same repository is
used for both Debian and Ubuntu packaging but with different branches.
For commits to the debian/master branch, Jeremy wants to use his
@debian.org email address. For commits to the ubuntu/master branch,
Jeremy wants to use his @ubuntu.com email.

Proposal
===
The includeIf feature of git-config could be extended to offer a
gitbranch conditional include in addition to the gitdir conditional
include it already offers.

Thanks,
Jeremy Bicha