Merge branch 'jw/git-add-attr-pathspec'
"git add" and "git stash" learned to support the ":(attr:...)" magic pathspec. * jw/git-add-attr-pathspec: attr: enable attr pathspec magic for git-add and git-stashmaint
commit
d8b0ec44b1
|
@ -424,7 +424,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
|
|||
* Check the "pathspec '%s' did not match any files" block
|
||||
* below before enabling new magic.
|
||||
*/
|
||||
parse_pathspec(&pathspec, PATHSPEC_ATTR,
|
||||
parse_pathspec(&pathspec, 0,
|
||||
PATHSPEC_PREFER_FULL |
|
||||
PATHSPEC_SYMLINK_LEADING_PATH,
|
||||
prefix, argv);
|
||||
|
@ -433,7 +433,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
|
|||
if (pathspec.nr)
|
||||
die(_("'%s' and pathspec arguments cannot be used together"), "--pathspec-from-file");
|
||||
|
||||
parse_pathspec_file(&pathspec, PATHSPEC_ATTR,
|
||||
parse_pathspec_file(&pathspec, 0,
|
||||
PATHSPEC_PREFER_FULL |
|
||||
PATHSPEC_SYMLINK_LEADING_PATH,
|
||||
prefix, pathspec_from_file, pathspec_file_nul);
|
||||
|
@ -504,7 +504,8 @@ int cmd_add(int argc, const char **argv, const char *prefix)
|
|||
PATHSPEC_LITERAL |
|
||||
PATHSPEC_GLOB |
|
||||
PATHSPEC_ICASE |
|
||||
PATHSPEC_EXCLUDE);
|
||||
PATHSPEC_EXCLUDE |
|
||||
PATHSPEC_ATTR);
|
||||
|
||||
for (i = 0; i < pathspec.nr; i++) {
|
||||
const char *path = pathspec.items[i].match;
|
||||
|
|
3
dir.c
3
dir.c
|
@ -2179,7 +2179,8 @@ static int exclude_matches_pathspec(const char *path, int pathlen,
|
|||
PATHSPEC_LITERAL |
|
||||
PATHSPEC_GLOB |
|
||||
PATHSPEC_ICASE |
|
||||
PATHSPEC_EXCLUDE);
|
||||
PATHSPEC_EXCLUDE |
|
||||
PATHSPEC_ATTR);
|
||||
|
||||
for (i = 0; i < pathspec->nr; i++) {
|
||||
const struct pathspec_item *item = &pathspec->items[i];
|
||||
|
|
39
pathspec.c
39
pathspec.c
|
@ -109,16 +109,37 @@ static struct pathspec_magic {
|
|||
{ PATHSPEC_ATTR, '\0', "attr" },
|
||||
};
|
||||
|
||||
static void prefix_magic(struct strbuf *sb, int prefixlen, unsigned magic)
|
||||
static void prefix_magic(struct strbuf *sb, int prefixlen,
|
||||
unsigned magic, const char *element)
|
||||
{
|
||||
int i;
|
||||
strbuf_addstr(sb, ":(");
|
||||
for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)
|
||||
if (magic & pathspec_magic[i].bit) {
|
||||
if (sb->buf[sb->len - 1] != '(')
|
||||
strbuf_addch(sb, ',');
|
||||
strbuf_addstr(sb, pathspec_magic[i].name);
|
||||
/* No magic was found in element, just add prefix magic */
|
||||
if (!magic) {
|
||||
strbuf_addf(sb, ":(prefix:%d)", prefixlen);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point, we know that parse_element_magic() was able
|
||||
* to extract some pathspec magic from element. So we know
|
||||
* element is correctly formatted in either shorthand or
|
||||
* longhand form
|
||||
*/
|
||||
if (element[1] != '(') {
|
||||
/* Process an element in shorthand form (e.g. ":!/<match>") */
|
||||
strbuf_addstr(sb, ":(");
|
||||
for (int i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {
|
||||
if ((magic & pathspec_magic[i].bit) &&
|
||||
pathspec_magic[i].mnemonic) {
|
||||
if (sb->buf[sb->len - 1] != '(')
|
||||
strbuf_addch(sb, ',');
|
||||
strbuf_addstr(sb, pathspec_magic[i].name);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* For the longhand form, we copy everything up to the final ')' */
|
||||
size_t len = strchr(element, ')') - element;
|
||||
strbuf_add(sb, element, len);
|
||||
}
|
||||
strbuf_addf(sb, ",prefix:%d)", prefixlen);
|
||||
}
|
||||
|
||||
|
@ -493,7 +514,7 @@ static void init_pathspec_item(struct pathspec_item *item, unsigned flags,
|
|||
struct strbuf sb = STRBUF_INIT;
|
||||
|
||||
/* Preserve the actual prefix length of each pattern */
|
||||
prefix_magic(&sb, prefixlen, element_magic);
|
||||
prefix_magic(&sb, prefixlen, element_magic, elt);
|
||||
|
||||
strbuf_addstr(&sb, match);
|
||||
item->original = strbuf_detach(&sb, NULL);
|
||||
|
|
|
@ -64,12 +64,24 @@ test_expect_success 'setup .gitattributes' '
|
|||
fileSetLabel label
|
||||
fileValue label=foo
|
||||
fileWrongLabel label☺
|
||||
newFileA* labelA
|
||||
newFileB* labelB
|
||||
EOF
|
||||
echo fileSetLabel label1 >sub/.gitattributes &&
|
||||
git add .gitattributes sub/.gitattributes &&
|
||||
git commit -m "add attributes"
|
||||
'
|
||||
|
||||
test_expect_success 'setup .gitignore' '
|
||||
cat <<-\EOF >.gitignore &&
|
||||
actual
|
||||
expect
|
||||
pathspec_file
|
||||
EOF
|
||||
git add .gitignore &&
|
||||
git commit -m "add gitignore"
|
||||
'
|
||||
|
||||
test_expect_success 'check specific set attr' '
|
||||
cat <<-\EOF >expect &&
|
||||
fileSetLabel
|
||||
|
@ -150,6 +162,7 @@ test_expect_success 'check specific value attr (2)' '
|
|||
test_expect_success 'check unspecified attr' '
|
||||
cat <<-\EOF >expect &&
|
||||
.gitattributes
|
||||
.gitignore
|
||||
fileA
|
||||
fileAB
|
||||
fileAC
|
||||
|
@ -175,6 +188,7 @@ test_expect_success 'check unspecified attr' '
|
|||
test_expect_success 'check unspecified attr (2)' '
|
||||
cat <<-\EOF >expect &&
|
||||
HEAD:.gitattributes
|
||||
HEAD:.gitignore
|
||||
HEAD:fileA
|
||||
HEAD:fileAB
|
||||
HEAD:fileAC
|
||||
|
@ -200,6 +214,7 @@ test_expect_success 'check unspecified attr (2)' '
|
|||
test_expect_success 'check multiple unspecified attr' '
|
||||
cat <<-\EOF >expect &&
|
||||
.gitattributes
|
||||
.gitignore
|
||||
fileC
|
||||
fileNoLabel
|
||||
fileWrongLabel
|
||||
|
@ -239,16 +254,99 @@ test_expect_success 'fail on multiple attr specifiers in one pathspec item' '
|
|||
test_grep "Only one" actual
|
||||
'
|
||||
|
||||
test_expect_success 'fail if attr magic is used places not implemented' '
|
||||
test_expect_success 'fail if attr magic is used in places not implemented' '
|
||||
# The main purpose of this test is to check that we actually fail
|
||||
# when you attempt to use attr magic in commands that do not implement
|
||||
# attr magic. This test does not advocate git-add to stay that way,
|
||||
# though, but git-add is convenient as it has its own internal pathspec
|
||||
# parsing.
|
||||
test_must_fail git add ":(attr:labelB)" 2>actual &&
|
||||
# attr magic. This test does not advocate check-ignore to stay that way.
|
||||
# When you teach the command to grok the pathspec, you need to find
|
||||
# another command to replace it for the test.
|
||||
test_must_fail git check-ignore ":(attr:labelB)" 2>actual &&
|
||||
test_grep "magic not supported" actual
|
||||
'
|
||||
|
||||
test_expect_success 'check that attr magic works for git stash push' '
|
||||
cat <<-\EOF >expect &&
|
||||
A sub/newFileA-foo
|
||||
EOF
|
||||
>sub/newFileA-foo &&
|
||||
>sub/newFileB-foo &&
|
||||
git stash push --include-untracked -- ":(exclude,attr:labelB)" &&
|
||||
git stash show --include-untracked --name-status >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'check that attr magic works for git add --all' '
|
||||
cat <<-\EOF >expect &&
|
||||
sub/newFileA-foo
|
||||
EOF
|
||||
>sub/newFileA-foo &&
|
||||
>sub/newFileB-foo &&
|
||||
git add --all ":(exclude,attr:labelB)" &&
|
||||
git diff --name-only --cached >actual &&
|
||||
git restore -W -S . &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'check that attr magic works for git add -u' '
|
||||
cat <<-\EOF >expect &&
|
||||
sub/fileA
|
||||
EOF
|
||||
>sub/newFileA-foo &&
|
||||
>sub/newFileB-foo &&
|
||||
>sub/fileA &&
|
||||
>sub/fileB &&
|
||||
git add -u ":(exclude,attr:labelB)" &&
|
||||
git diff --name-only --cached >actual &&
|
||||
git restore -S -W . && rm sub/new* &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'check that attr magic works for git add <path>' '
|
||||
cat <<-\EOF >expect &&
|
||||
fileA
|
||||
fileB
|
||||
sub/fileA
|
||||
EOF
|
||||
>fileA &&
|
||||
>fileB &&
|
||||
>sub/fileA &&
|
||||
>sub/fileB &&
|
||||
git add ":(exclude,attr:labelB)sub/*" &&
|
||||
git diff --name-only --cached >actual &&
|
||||
git restore -S -W . &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'check that attr magic works for git -add .' '
|
||||
cat <<-\EOF >expect &&
|
||||
sub/fileA
|
||||
EOF
|
||||
>fileA &&
|
||||
>fileB &&
|
||||
>sub/fileA &&
|
||||
>sub/fileB &&
|
||||
cd sub &&
|
||||
git add . ":(exclude,attr:labelB)" &&
|
||||
cd .. &&
|
||||
git diff --name-only --cached >actual &&
|
||||
git restore -S -W . &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'check that attr magic works for git add --pathspec-from-file' '
|
||||
cat <<-\EOF >pathspec_file &&
|
||||
:(exclude,attr:labelB)
|
||||
EOF
|
||||
cat <<-\EOF >expect &&
|
||||
sub/newFileA-foo
|
||||
EOF
|
||||
>sub/newFileA-foo &&
|
||||
>sub/newFileB-foo &&
|
||||
git add --all --pathspec-from-file=pathspec_file &&
|
||||
git diff --name-only --cached >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'abort on giving invalid label on the command line' '
|
||||
test_must_fail git ls-files . ":(attr:☺)"
|
||||
'
|
||||
|
|
Loading…
Reference in New Issue