* [PATCH v3 06/10] wildmatch: support "no FNM_PATHNAME" mode
From: Nguyễn Thái Ngọc Duy @ 2013-01-01 2:44 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy
In-Reply-To: <1357008251-10014-1-git-send-email-pclouds@gmail.com>
So far, wildmatch() has always honoured directory boundary and there
was no way to turn it off. Make it behave more like fnmatch() by
requiring all callers that want the FNM_PATHNAME behaviour to pass
that in the equivalent flag WM_PATHNAME. Callers that do not specify
WM_PATHNAME will get wildcards like ? and * in their patterns matched
against '/', just like not passing FNM_PATHNAME to fnmatch().
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
dir.c | 2 +-
t/t3070-wildmatch.sh | 27 +++++++++++++++++++++++++++
test-wildmatch.c | 6 ++++--
wildmatch.c | 13 +++++++++----
wildmatch.h | 1 +
5 files changed, 42 insertions(+), 7 deletions(-)
diff --git a/dir.c b/dir.c
index 175a182..6ef0396 100644
--- a/dir.c
+++ b/dir.c
@@ -595,7 +595,7 @@ int match_pathname(const char *pathname, int pathlen,
}
return wildmatch(pattern, name,
- ignore_case ? WM_CASEFOLD : 0,
+ WM_PATHNAME | (ignore_case ? WM_CASEFOLD : 0),
NULL) == 0;
}
diff --git a/t/t3070-wildmatch.sh b/t/t3070-wildmatch.sh
index af54c83..5c9601a 100755
--- a/t/t3070-wildmatch.sh
+++ b/t/t3070-wildmatch.sh
@@ -29,6 +29,18 @@ match() {
fi
}
+pathmatch() {
+ if [ $1 = 1 ]; then
+ test_expect_success "pathmatch: match '$2' '$3'" "
+ test-wildmatch pathmatch '$2' '$3'
+ "
+ else
+ test_expect_success "pathmatch: no match '$2' '$3'" "
+ ! test-wildmatch pathmatch '$2' '$3'
+ "
+ fi
+}
+
# Basic wildmat features
match 1 1 foo foo
match 0 0 foo bar
@@ -192,4 +204,19 @@ match 0 0 'XXX/adobe/courier/bold/o/normal//12/120/75/75/X/70/iso8859/1' 'XXX/*/
match 1 0 'abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txt' '**/*a*b*g*n*t'
match 0 0 'abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txtz' '**/*a*b*g*n*t'
+pathmatch 1 foo foo
+pathmatch 0 foo fo
+pathmatch 1 foo/bar foo/bar
+pathmatch 1 foo/bar 'foo/*'
+pathmatch 1 foo/bba/arr 'foo/*'
+pathmatch 1 foo/bba/arr 'foo/**'
+pathmatch 1 foo/bba/arr 'foo*'
+pathmatch 1 foo/bba/arr 'foo**'
+pathmatch 1 foo/bba/arr 'foo/*arr'
+pathmatch 1 foo/bba/arr 'foo/**arr'
+pathmatch 0 foo/bba/arr 'foo/*z'
+pathmatch 0 foo/bba/arr 'foo/**z'
+pathmatch 1 foo/bar 'foo?bar'
+pathmatch 1 foo/bar 'foo[/]bar'
+
test_done
diff --git a/test-wildmatch.c b/test-wildmatch.c
index 4bb23b4..a5f4833 100644
--- a/test-wildmatch.c
+++ b/test-wildmatch.c
@@ -12,9 +12,11 @@ int main(int argc, char **argv)
argv[i] += 3;
}
if (!strcmp(argv[1], "wildmatch"))
- return !!wildmatch(argv[3], argv[2], 0, NULL);
+ return !!wildmatch(argv[3], argv[2], WM_PATHNAME, NULL);
else if (!strcmp(argv[1], "iwildmatch"))
- return !!wildmatch(argv[3], argv[2], WM_CASEFOLD, NULL);
+ return !!wildmatch(argv[3], argv[2], WM_PATHNAME | WM_CASEFOLD, NULL);
+ else if (!strcmp(argv[1], "pathmatch"))
+ return !!wildmatch(argv[3], argv[2], 0, NULL);
else if (!strcmp(argv[1], "fnmatch"))
return !!fnmatch(argv[3], argv[2], FNM_PATHNAME);
else
diff --git a/wildmatch.c b/wildmatch.c
index 1b5bbac..536470b 100644
--- a/wildmatch.c
+++ b/wildmatch.c
@@ -78,14 +78,17 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)
continue;
case '?':
/* Match anything but '/'. */
- if (t_ch == '/')
+ if ((flags & WM_PATHNAME) && t_ch == '/')
return WM_NOMATCH;
continue;
case '*':
if (*++p == '*') {
const uchar *prev_p = p - 2;
while (*++p == '*') {}
- if ((prev_p < pattern || *prev_p == '/') &&
+ if (!(flags & WM_PATHNAME))
+ /* without WM_PATHNAME, '*' == '**' */
+ match_slash = 1;
+ else if ((prev_p < pattern || *prev_p == '/') &&
(*p == '\0' || *p == '/' ||
(p[0] == '\\' && p[1] == '/'))) {
/*
@@ -104,7 +107,8 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)
} else
return WM_ABORT_MALFORMED;
} else
- match_slash = 0;
+ /* without WM_PATHNAME, '*' == '**' */
+ match_slash = flags & WM_PATHNAME ? 0 : 1;
if (*p == '\0') {
/* Trailing "**" matches everything. Trailing "*" matches
* only if there are no more slash characters. */
@@ -215,7 +219,8 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)
} else if (t_ch == p_ch)
matched = 1;
} while (prev_ch = p_ch, (p_ch = *++p) != ']');
- if (matched == negated || t_ch == '/')
+ if (matched == negated ||
+ ((flags & WM_PATHNAME) && t_ch == '/'))
return WM_NOMATCH;
continue;
}
diff --git a/wildmatch.h b/wildmatch.h
index 1c814fd..4090c8f 100644
--- a/wildmatch.h
+++ b/wildmatch.h
@@ -2,6 +2,7 @@
#define WILDMATCH_H
#define WM_CASEFOLD 1
+#define WM_PATHNAME 2
#define WM_ABORT_MALFORMED 2
#define WM_NOMATCH 1
--
1.8.0.rc2.23.g1fb49df
^ permalink raw reply related
* [PATCH v3 07/10] test-wildmatch: add "perf" command to compare wildmatch and fnmatch
From: Nguyễn Thái Ngọc Duy @ 2013-01-01 2:44 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy
In-Reply-To: <1357008251-10014-1-git-send-email-pclouds@gmail.com>
It takes a text file, a pattern, a number <n> and pathname flag. Each
line in the text file is matched against the pattern <n> times. If
"pathname" is given, FNM_PATHNAME is used.
test-wildmatch is built with -O2 and tested against glibc 2.14.1 (also
-O2) and compat/fnmatch. The input file is linux-2.6.git file list.
<n> is 2000. The complete command list is at the end.
wildmatch is beaten in the following cases. Apparently it needs some
improvement in FNM_PATHNAME case:
glibc, '*/*/*' with FNM_PATHNAME:
wildmatch 8s 1559us
fnmatch 1s 11877us or 12.65% faster
compat, '*/*/*' with FNM_PATHNAME:
wildmatch 7s 922458us
fnmatch 2s 905111us or 36.67% faster
compat, '*/*/*' without FNM_PATHNAME:
wildmatch 7s 264201us
fnmatch 2s 1897us or 27.56% faster
compat, '[a-z]*/[a-z]*/[a-z]*' with FNM_PATHNAME:
wildmatch 8s 742827us
fnmatch 0s 922943us or 10.56% faster
compat, '[a-z]*/[a-z]*/[a-z]*' without FNM_PATHNAME:
wildmatch 8s 284520us
fnmatch 0s 6936us or 0.08% faster
The rest of glibc numbers
-------------------------
'Documentation/*'
wildmatch 1s 529479us
fnmatch 1s 98263us or 71.81% slower
'drivers/*'
wildmatch 1s 988288us
fnmatch 1s 192049us or 59.95% slower
'Documentation/*' pathname
wildmatch 1s 557507us
fnmatch 1s 93696us or 70.22% slower
'drivers/*' pathname
wildmatch 2s 161626us
fnmatch 1s 230372us or 56.92% slower
'[Dd]ocu[Mn]entation/*'
wildmatch 1s 776581us
fnmatch 1s 471693us or 82.84% slower
'[Dd]o?u[Mn]en?ati?n/*'
wildmatch 1s 770770us
fnmatch 1s 555727us or 87.86% slower
'[Dd]o?u[Mn]en?ati?n/*' pathname
wildmatch 1s 783507us
fnmatch 1s 537029us or 86.18% slower
'[A-Za-z][A-Za-z]??*'
wildmatch 4s 110386us
fnmatch 4s 926306us or 119.85% slower
'[A-Za-z][A-Za-z]??'
wildmatch 3s 918114us
fnmatch 3s 686175us or 94.08% slower
'[A-Za-z][A-Za-z]??*' pathname
wildmatch 4s 453746us
fnmatch 4s 955856us or 111.27% slower
'[A-Za-z][A-Za-z]??' pathname
wildmatch 3s 896646us
fnmatch 3s 733828us or 95.82% slower
'*/*/*'
wildmatch 7s 287985us
fnmatch 1s 74083us or 14.74% slower
'[a-z]*/[a-z]*/[a-z]*' pathname
wildmatch 8s 796659us
fnmatch 1s 568409us or 17.83% slower
'[a-z]*/[a-z]*/[a-z]*'
wildmatch 8s 316559us
fnmatch 3s 430652us or 41.25% slower
The rest of compat numbers
--------------------------
'Documentation/*'
wildmatch 1s 520389us
fnmatch 0s 62579us or 4.12% slower
'drivers/*'
wildmatch 1s 955354us
fnmatch 0s 190109us or 9.72% slower
'Documentation/*' pathname
wildmatch 1s 561675us
fnmatch 0s 55336us or 3.54% slower
'drivers/*' pathname
wildmatch 2s 106100us
fnmatch 0s 219680us or 10.43% slower
'[Dd]ocu[Mn]entation/*'
wildmatch 1s 750810us
fnmatch 0s 542721us or 31.00% slower
'[Dd]o?u[Mn]en?ati?n/*'
wildmatch 1s 724791us
fnmatch 0s 538948us or 31.25% slower
'[Dd]o?u[Mn]en?ati?n/*' pathname
wildmatch 1s 731403us
fnmatch 0s 537474us or 31.04% slower
'[A-Za-z][A-Za-z]??*'
wildmatch 4s 28555us
fnmatch 1s 67297us or 26.49% slower
'[A-Za-z][A-Za-z]??'
wildmatch 3s 838279us
fnmatch 0s 880005us or 22.93% slower
'[A-Za-z][A-Za-z]??*' pathname
wildmatch 4s 379476us
fnmatch 1s 55643us or 24.10% slower
'[A-Za-z][A-Za-z]??' pathname
wildmatch 3s 830910us
fnmatch 0s 849699us or 22.18% slower
The following commands are used:
LANG=C ./test-wildmatch perf /tmp/filelist.txt 'Documentation/*' 2000
LANG=C ./test-wildmatch perf /tmp/filelist.txt 'drivers/*' 2000
LANG=C ./test-wildmatch perf /tmp/filelist.txt 'Documentation/*' 2000 pathname
LANG=C ./test-wildmatch perf /tmp/filelist.txt 'drivers/*' 2000 pathname
LANG=C ./test-wildmatch perf /tmp/filelist.txt '[Dd]ocu[Mn]entation/*' 2000
LANG=C ./test-wildmatch perf /tmp/filelist.txt '[Dd]o?u[Mn]en?ati?n/*' 2000
LANG=C ./test-wildmatch perf /tmp/filelist.txt '[Dd]o?u[Mn]en?ati?n/*' 2000 pathname
LANG=C ./test-wildmatch perf /tmp/filelist.txt '[A-Za-z][A-Za-z]??*' 2000
LANG=C ./test-wildmatch perf /tmp/filelist.txt '[A-Za-z][A-Za-z]??' 2000
LANG=C ./test-wildmatch perf /tmp/filelist.txt '[A-Za-z][A-Za-z]??*' 2000 pathname
LANG=C ./test-wildmatch perf /tmp/filelist.txt '[A-Za-z][A-Za-z]??' 2000 pathname
LANG=C ./test-wildmatch perf /tmp/filelist.txt '*/*/*' 2000
LANG=C ./test-wildmatch perf /tmp/filelist.txt '*/*/*' 2000 pathname
LANG=C ./test-wildmatch perf /tmp/filelist.txt '[a-z]*/[a-z]*/[a-z]*' 2000 pathname
LANG=C ./test-wildmatch perf /tmp/filelist.txt '[a-z]*/[a-z]*/[a-z]*' 2000
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
test-wildmatch.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 73 insertions(+)
diff --git a/test-wildmatch.c b/test-wildmatch.c
index a5f4833..ac86800 100644
--- a/test-wildmatch.c
+++ b/test-wildmatch.c
@@ -1,9 +1,82 @@
#include "cache.h"
#include "wildmatch.h"
+static int perf(int ac, char **av)
+{
+ struct timeval tv1, tv2;
+ struct stat st;
+ int fd, i, n, flags1 = 0, flags2 = 0;
+ char *buffer, *p;
+ uint32_t usec1, usec2;
+ const char *lang;
+ const char *file = av[0];
+ const char *pattern = av[1];
+
+ lang = getenv("LANG");
+ if (lang && strcmp(lang, "C"))
+ die("Please test it on C locale.");
+
+ if ((fd = open(file, O_RDONLY)) == -1 || fstat(fd, &st))
+ die_errno("file open");
+
+ buffer = xmalloc(st.st_size + 2);
+ if (read(fd, buffer, st.st_size) != st.st_size)
+ die_errno("read");
+
+ buffer[st.st_size] = '\0';
+ buffer[st.st_size + 1] = '\0';
+ for (i = 0; i < st.st_size; i++)
+ if (buffer[i] == '\n')
+ buffer[i] = '\0';
+
+ n = atoi(av[2]);
+ if (av[3] && !strcmp(av[3], "pathname")) {
+ flags1 = WM_PATHNAME;
+ flags2 = FNM_PATHNAME;
+ }
+
+ gettimeofday(&tv1, NULL);
+ for (i = 0; i < n; i++) {
+ for (p = buffer; *p; p += strlen(p) + 1)
+ wildmatch(pattern, p, flags1, NULL);
+ }
+ gettimeofday(&tv2, NULL);
+
+ usec1 = (uint32_t)tv2.tv_sec * 1000000 + tv2.tv_usec;
+ usec1 -= (uint32_t)tv1.tv_sec * 1000000 + tv1.tv_usec;
+ printf("wildmatch %ds %dus\n",
+ (int)(usec1 / 1000000),
+ (int)(usec1 % 1000000));
+
+ gettimeofday(&tv1, NULL);
+ for (i = 0; i < n; i++) {
+ for (p = buffer; *p; p += strlen(p) + 1)
+ fnmatch(pattern, p, flags2);
+ }
+ gettimeofday(&tv2, NULL);
+
+ usec2 = (uint32_t)tv2.tv_sec * 1000000 + tv2.tv_usec;
+ usec2 -= (uint32_t)tv1.tv_sec * 1000000 + tv1.tv_usec;
+ if (usec2 > usec1)
+ printf("fnmatch %ds %dus or %.2f%% slower\n",
+ (int)((usec2 - usec1) / 1000000),
+ (int)((usec2 - usec1) % 1000000),
+ (float)(usec2 - usec1) / usec1 * 100);
+ else
+ printf("fnmatch %ds %dus or %.2f%% faster\n",
+ (int)((usec1 - usec2) / 1000000),
+ (int)((usec1 - usec2) % 1000000),
+ (float)(usec1 - usec2) / usec1 * 100);
+ return 0;
+}
+
int main(int argc, char **argv)
{
int i;
+
+ if (!strcmp(argv[1], "perf"))
+ return perf(argc - 2, argv + 2);
+
for (i = 2; i < argc; i++) {
if (argv[i][0] == '/')
die("Forward slash is not allowed at the beginning of the\n"
--
1.8.0.rc2.23.g1fb49df
^ permalink raw reply related
* [PATCH v3 08/10] wildmatch: make a special case for "*/" with FNM_PATHNAME
From: Nguyễn Thái Ngọc Duy @ 2013-01-01 2:44 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy
In-Reply-To: <1357008251-10014-1-git-send-email-pclouds@gmail.com>
Normally we need recursion for "*". In this case we know that it
matches everything until "/" so we can skip the recursion.
glibc, '*/*/*' on linux-2.6.git file list 2000 times
before:
wildmatch 8s 74513us
fnmatch 1s 97042us or 13.59% faster
after:
wildmatch 3s 521862us
fnmatch 3s 488616us or 99.06% slower
Same test with compat/fnmatch:
wildmatch 8s 110763us
fnmatch 2s 980845us or 36.75% faster
wildmatch 3s 522156us
fnmatch 1s 544487us or 43.85% slower
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
t/t3070-wildmatch.sh | 8 ++++++++
wildmatch.c | 12 ++++++++++++
2 files changed, 20 insertions(+)
diff --git a/t/t3070-wildmatch.sh b/t/t3070-wildmatch.sh
index 5c9601a..97f1daf 100755
--- a/t/t3070-wildmatch.sh
+++ b/t/t3070-wildmatch.sh
@@ -203,6 +203,10 @@ match 1 1 'XXX/adobe/courier/bold/o/normal//12/120/75/75/m/70/iso8859/1' 'XXX/*/
match 0 0 'XXX/adobe/courier/bold/o/normal//12/120/75/75/X/70/iso8859/1' 'XXX/*/*/*/*/*/*/12/*/*/*/m/*/*/*'
match 1 0 'abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txt' '**/*a*b*g*n*t'
match 0 0 'abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txtz' '**/*a*b*g*n*t'
+match 0 x foo '*/*/*'
+match 0 x foo/bar '*/*/*'
+match 1 x foo/bba/arr '*/*/*'
+match 0 x foo/bb/aa/rr '*/*/*'
pathmatch 1 foo foo
pathmatch 0 foo fo
@@ -218,5 +222,9 @@ pathmatch 0 foo/bba/arr 'foo/*z'
pathmatch 0 foo/bba/arr 'foo/**z'
pathmatch 1 foo/bar 'foo?bar'
pathmatch 1 foo/bar 'foo[/]bar'
+pathmatch 0 foo '*/*/*'
+pathmatch 0 foo/bar '*/*/*'
+pathmatch 1 foo/bba/arr '*/*/*'
+pathmatch 1 foo/bb/aa/rr '*/*/*'
test_done
diff --git a/wildmatch.c b/wildmatch.c
index 536470b..bb42522 100644
--- a/wildmatch.c
+++ b/wildmatch.c
@@ -117,6 +117,18 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)
return WM_NOMATCH;
}
return WM_MATCH;
+ } else if (!match_slash && *p == '/') {
+ /*
+ * _one_ asterisk followed by a slash
+ * with WM_PATHNAME matches the next
+ * directory
+ */
+ const char *slash = strchr((char*)text, '/');
+ if (!slash)
+ return WM_NOMATCH;
+ text = (const uchar*)slash;
+ /* the slash is consumed by the top-level for loop */
+ break;
}
while (1) {
if (t_ch == '\0')
--
1.8.0.rc2.23.g1fb49df
^ permalink raw reply related
* [PATCH v3 09/10] wildmatch: advance faster in <asterisk> + <literal> patterns
From: Nguyễn Thái Ngọc Duy @ 2013-01-01 2:44 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy
In-Reply-To: <1357008251-10014-1-git-send-email-pclouds@gmail.com>
Normally when we match "*X" on "abcX", we call dowild("X", "abcX"),
dowild("X", "bcX"), dowild("X", "cX") and dowild("X", "X"). Only the
last call may have a chance of matching. By skipping the text before
"X", we can eliminate the first three useless calls.
compat, '*/*/*' on linux-2.6.git file list 2000 times, before:
wildmatch 7s 985049us
fnmatch 2s 735541us or 34.26% faster
and after:
wildmatch 4s 492549us
fnmatch 0s 888263us or 19.77% slower
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
t/t3070-wildmatch.sh | 8 ++++++++
wildmatch.c | 23 +++++++++++++++++++++++
2 files changed, 31 insertions(+)
diff --git a/t/t3070-wildmatch.sh b/t/t3070-wildmatch.sh
index 97f1daf..4c37057 100755
--- a/t/t3070-wildmatch.sh
+++ b/t/t3070-wildmatch.sh
@@ -207,6 +207,11 @@ match 0 x foo '*/*/*'
match 0 x foo/bar '*/*/*'
match 1 x foo/bba/arr '*/*/*'
match 0 x foo/bb/aa/rr '*/*/*'
+match 1 x foo/bb/aa/rr '**/**/**'
+match 1 x abcXdefXghi '*X*i'
+match 0 x ab/cXd/efXg/hi '*X*i'
+match 1 x ab/cXd/efXg/hi '*/*X*/*/*i'
+match 1 x ab/cXd/efXg/hi '**/*X*/**/*i'
pathmatch 1 foo foo
pathmatch 0 foo fo
@@ -226,5 +231,8 @@ pathmatch 0 foo '*/*/*'
pathmatch 0 foo/bar '*/*/*'
pathmatch 1 foo/bba/arr '*/*/*'
pathmatch 1 foo/bb/aa/rr '*/*/*'
+pathmatch 1 abcXdefXghi '*X*i'
+pathmatch 1 ab/cXd/efXg/hi '*/*X*/*/*i'
+pathmatch 1 ab/cXd/efXg/hi '*Xg*i'
test_done
diff --git a/wildmatch.c b/wildmatch.c
index bb42522..7192bdc 100644
--- a/wildmatch.c
+++ b/wildmatch.c
@@ -133,6 +133,29 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)
while (1) {
if (t_ch == '\0')
break;
+ /*
+ * Try to advance faster when an asterisk is
+ * followed by a literal. We know in this case
+ * that the the string before the literal
+ * must belong to "*".
+ * If match_slash is false, do not look past
+ * the first slash as it cannot belong to '*'.
+ */
+ if (!is_glob_special(*p)) {
+ p_ch = *p;
+ if ((flags & WM_CASEFOLD) && ISUPPER(p_ch))
+ p_ch = tolower(p_ch);
+ while ((t_ch = *text) != '\0' &&
+ (match_slash || t_ch != '/')) {
+ if ((flags & WM_CASEFOLD) && ISUPPER(t_ch))
+ t_ch = tolower(t_ch);
+ if (t_ch == p_ch)
+ break;
+ text++;
+ }
+ if (t_ch != p_ch)
+ return WM_NOMATCH;
+ }
if ((matched = dowild(p, text, flags)) != WM_NOMATCH) {
if (!match_slash || matched != WM_ABORT_TO_STARSTAR)
return matched;
--
1.8.0.rc2.23.g1fb49df
^ permalink raw reply related
* [PATCH v3 10/10] Makefile: add USE_WILDMATCH to use wildmatch as fnmatch
From: Nguyễn Thái Ngọc Duy @ 2013-01-01 2:44 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy
In-Reply-To: <1357008251-10014-1-git-send-email-pclouds@gmail.com>
This is similar to NO_FNMATCH but it uses wildmatch instead of
compat/fnmatch. This is an intermediate step to let wildmatch be used
as fnmatch replacement for wider audience before it replaces fnmatch
completely and compat/fnmatch is removed.
fnmatch in test-wildmatch is not impacted by this and is the only
place that NO_FNMATCH or NO_FNMATCH_CASEFOLD remain active when
USE_WILDMATCH is set.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
Makefile | 6 ++++++
git-compat-util.h | 13 +++++++++++++
test-wildmatch.c | 3 +++
3 files changed, 22 insertions(+)
diff --git a/Makefile b/Makefile
index bc868d1..24e2774 100644
--- a/Makefile
+++ b/Makefile
@@ -99,6 +99,9 @@ all::
# Define NO_FNMATCH_CASEFOLD if your fnmatch function doesn't have the
# FNM_CASEFOLD GNU extension.
#
+# Define USE_WILDMATCH if you want to use Git's wildmatch
+# implementation as fnmatch
+#
# Define NO_GECOS_IN_PWENT if you don't have pw_gecos in struct passwd
# in the C library.
#
@@ -1625,6 +1628,9 @@ ifdef NO_FNMATCH_CASEFOLD
COMPAT_OBJS += compat/fnmatch/fnmatch.o
endif
endif
+ifdef USE_WILDMATCH
+ COMPAT_CFLAGS += -DUSE_WILDMATCH
+endif
ifdef NO_SETENV
COMPAT_CFLAGS += -DNO_SETENV
COMPAT_OBJS += compat/setenv.o
diff --git a/git-compat-util.h b/git-compat-util.h
index 02f48f6..b2c7638 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -106,7 +106,9 @@
#include <sys/time.h>
#include <time.h>
#include <signal.h>
+#ifndef USE_WILDMATCH
#include <fnmatch.h>
+#endif
#include <assert.h>
#include <regex.h>
#include <utime.h>
@@ -238,6 +240,17 @@ extern char *gitbasename(char *);
#include "compat/bswap.h"
+#ifdef USE_WILDMATCH
+#include "wildmatch.h"
+#define FNM_PATHNAME WM_PATHNAME
+#define FNM_CASEFOLD WM_CASEFOLD
+#define FNM_NOMATCH WM_NOMATCH
+static inline int fnmatch(const char *pattern, const char *string, int flags)
+{
+ return wildmatch(pattern, string, flags, NULL);
+}
+#endif
+
/* General helper functions */
extern void vreportf(const char *prefix, const char *err, va_list params);
extern void vwritef(int fd, const char *prefix, const char *err, va_list params);
diff --git a/test-wildmatch.c b/test-wildmatch.c
index ac86800..a3e2643 100644
--- a/test-wildmatch.c
+++ b/test-wildmatch.c
@@ -1,3 +1,6 @@
+#ifdef USE_WILDMATCH
+#undef USE_WILDMATCH /* We need real fnmatch implementation here */
+#endif
#include "cache.h"
#include "wildmatch.h"
--
1.8.0.rc2.23.g1fb49df
^ permalink raw reply related
* Re: [DOCBUG] git subtree synopsis needs updating
From: greened @ 2013-01-01 2:51 UTC (permalink / raw)
To: Yann Dirson; +Cc: git list
In-Reply-To: <20121019152158.4297707b@chalon.bertin.fr>
Yann Dirson <dirson@bertin.fr> writes:
> As the examples in git-subtree.txt show, the synopsis in the same file should
> surely get a patch along the lines of:
>
> -'git subtree' add -P <prefix> <commit>
> +'git subtree' add -P <prefix> <repository> <commit>
>
> Failure to specify the repository (by just specifying a local commit) fails with
> the cryptic:
>
> warning: read-tree: emptying the index with no arguments is deprecated; use --empty
> fatal: just how do you expect me to merge 0 trees?
Specifying a local branch works fine, though, as does a raw commit
hash. What do you mean by "local commit?"
I have updated the documentation and will submit it tonight or tomorrow.
Any invalid refspec should be caught early and a more useful message
will be displayed.
> Furthermore, the doc paragraph for add, aside from mentionning <repository>, also
> mentions a <refspec> which the synopsis does not show either.
Fixed.
> As a sidenote it someone wants to do some maintainance, using "." as repository when
> the branch to subtree-add is already locally available does not work well either
> (fails with "could not find ref myremote/myhead").
Seems to work for me. Can you give me the command you're using when you
see the problem?
Thanks for the report!
-David
^ permalink raw reply
* Re: [PATCH] DESTDIR support in contrib/subtree/Makefile
From: greened @ 2013-01-01 2:58 UTC (permalink / raw)
To: Adam Tkac; +Cc: git
In-Reply-To: <20121129154057.GA4300@redhat.com>
Adam Tkac <atkac@redhat.com> writes:
> Signed-off-by: Adam Tkac <atkac@redhat.com>
> ---
>
> It is a good habit in Makefiles to honor DESTDIR variable to support
>
> `make DESTDIR=/instalroot install`
>
> syntax.
>
> Comments are welcomed.
Applied. I'll be sending this to the mailing list tonight or tomorrow.
-David
^ permalink raw reply
* Re: [PATCH] For git-subtree, when installing docs (make install-doc), create man1 folder first.
From: greened @ 2013-01-01 3:01 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Jesper L. Nielsen, git
In-Reply-To: <7v8v91y97f.fsf@alter.siamese.dyndns.org>
Junio C Hamano <gitster@pobox.com> writes:
> "Jesper L. Nielsen" <lyager@gmail.com> writes:
>
>> From: "Jesper L. Nielsen" <lyager@gmail.com>
>>
>> Hi..
>>
>> I installed Git subtree and discovered that the if the man1dir doesn't exist the man-page for Git Subtree is just called man1.
>>
>> So, small patch to create the folder first in the Makefile. Hope everything is right with the patch and submitting of the patch.
>>
>> Best Regards
>> Jesper
>>
>> Signed-off-by: Jesper L. Nielsen <lyager@gmail.com>
>> ---
>
> Thanks. David, Ack?
Yep. I can add it to my queue which I'll send to you tomorrow.
Otherwise, feel free to apply it to your copy.
-David
^ permalink raw reply
* Re: [PATCH 0/7] format-patch --reroll-count
From: Duy Nguyen @ 2013-01-01 3:04 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <1356165212-5611-1-git-send-email-gitster@pobox.com>
On Sat, Dec 22, 2012 at 3:33 PM, Junio C Hamano <gitster@pobox.com> wrote:
> The --reroll-count=$N option, when given a positive integer:
>
> - Adds " v$N" to the subject prefix specified. As the default
> subject prefix string is "PATCH", --reroll-count=2 makes it
> "PATCH v2".
>
> - Prefixes "v$N-" to the names used for output files. The cover
> letter, whose name is usually 0000-cover-letter.patch, becomes
> v2-0000-cover-letter.patch when given --reroll-count=2.
On the same subject of format-patch improvements, perhaps we should also:
- Keep subject line in branch.%s.description too. No point in
keeping writing the subject on every reroll.
- Perhaps an option to save the current tip in reflog with reroll
count so one can easily diff between two rerolls.
--
Duy
^ permalink raw reply
* Re: [PATCH] For git-subtree, when installing docs (make install-doc), create man1 folder first.
From: greened @ 2013-01-01 3:06 UTC (permalink / raw)
To: Jesper L. Nielsen; +Cc: git, gitster
In-Reply-To: <1355429376-4192-1-git-send-email-lyager@gmail.com>
"Jesper L. Nielsen" <lyager@gmail.com> writes:
> So, small patch to create the folder first in the Makefile. Hope
> everything is right with the patch and submitting of the patch.
I've applied this to my local copy and will send it to the list for
integration.
Thanks for fixing this!
-David
^ permalink raw reply
* Re: [PATCH] git-subtree: ignore git-subtree executable
From: greened @ 2013-01-01 3:08 UTC (permalink / raw)
To: Michael Schubert; +Cc: git
In-Reply-To: <50D5C794.4070400@elegosoft.com>
Michael Schubert <mschub@elegosoft.com> writes:
> Signed-off-by: Michael Schubert <mschub@elegosoft.com>
Obviously good. Applied and will send for integration.
-David
^ permalink raw reply
* Re: git subtree error (just how do you expect me to merge 0 trees?)
From: Junio C Hamano @ 2013-01-01 3:16 UTC (permalink / raw)
To: greened; +Cc: Drew Crawford, git@vger.kernel.org
In-Reply-To: <87licd3b7w.fsf@waller.obbligato.org>
greened@obbligato.org writes:
> git-subtree add accepts either a refspec or a path to a repository and a
> refspec.
> With one positional option, git-subtree add simply assumes
> it's a refspec. Is there an easy way to check whether a string is a
> proper refspec? Even better would be a way to check if a string is a
> path to a git repository.
Do you literally mean "a path to a repository" in the above, or do
you mean "a remote that is like what is accepted by 'git fetch'"?
If you literary mean it is is a path to a git repository, you could
obviously use "cd $there && git rev-parse --git-dir" or something.
On the other hand, if you mean the command takes a remote and an
optional list of refspecs just like "git fetch" does, then I am not
sure it is a good design in the first place to allow "refspecs
only", if only to keep the interface similar to "git fetch" (you
cannot omit remote and give refspecs, as you cannot interpret
refspecs without knowing in the context of which remote they are to
be interpreted).
I would imagine you could disambiguate and default to "origin" or
something when you guessed that remote was omitted if you really
wanted to, with a syntacitical heuristics, such as "a refspec will
never have two colons in it", "a URL tends to begin with a short
alphabet word, a colon and double-slash", etc.
^ permalink raw reply
* git-subtree Patches to Apply
From: David A. Greene @ 2013-01-01 3:57 UTC (permalink / raw)
To: git
Here are all of the patches for git-subtree that have been posted to
the mailing list that I could apply and test in a reasonable amount of
time. These are all rebased from trunk as of tonight.
Many apologies for being *so* behind. Work has been a bear but I'm
hoping things will ease up in the new year and I can be more regularly
active. But still, don't expect same-day service. :)
These are also available on branch "toupstream" via
git clone gitolite@sources.obbligato.org:git.git
and
http://sources.obbligato.org
http://sources.obbligato.org/?p=git.git;a=summary
Junio, can you apply these? Thanks!
-David
^ permalink raw reply
* [PATCH 1/8] Use %B for Split Subject/Body
From: David A. Greene @ 2013-01-01 3:57 UTC (permalink / raw)
To: git; +Cc: Techlive Zheng, David A. Greene
In-Reply-To: <1357012655-24974-1-git-send-email-greened@obbligato.org>
From: Techlive Zheng <techlivezheng@gmail.com>
Use %B to format the commit message and body to avoid an extra newline
if a commit only has a subject line.
Author: Techlive Zheng <techlivezheng@gmail.com>
Signed-off-by: David A. Greene <greened@obbligato.org>
---
contrib/subtree/git-subtree.sh | 5 +++
contrib/subtree/t/t7900-subtree.sh | 73 ++++++++++++++++++++++--------------
2 files changed, 49 insertions(+), 29 deletions(-)
diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 920c664..f2b6d4a 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -296,7 +296,12 @@ copy_commit()
# We're going to set some environment vars here, so
# do it in a subshell to get rid of them safely later
debug copy_commit "{$1}" "{$2}" "{$3}"
+ # Use %B rather than %s%n%n%b to handle the special case of a
+ # commit that only has a subject line. We don't want to
+ # introduce a newline after the subject, causing generation of
+ # a new hash.
git log -1 --pretty=format:'%an%n%ae%n%ad%n%cn%n%ce%n%cd%n%s%n%n%b' "$1" |
+# git log -1 --pretty=format:'%an%n%ae%n%ad%n%cn%n%ce%n%cd%n%B' "$1" |
(
read GIT_AUTHOR_NAME
read GIT_AUTHOR_EMAIL
diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index bc2eeb0..93eeb09 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -76,6 +76,10 @@ test_expect_success 'add sub1' '
git branch -m master subproj
'
+# Save this hash for testing later.
+
+subdir_hash=`git rev-parse HEAD`
+
# 3
test_expect_success 'add sub2' '
create sub2 &&
@@ -155,7 +159,6 @@ test_expect_success 'add main-sub5' '
create subdir/main-sub5 &&
git commit -m "main-sub5"
'
-
# 15
test_expect_success 'add main6' '
create main6 &&
@@ -235,7 +238,19 @@ test_expect_success 'check split with --branch' '
check_equal ''"$(git rev-parse splitbr1)"'' "$spl1"
'
-# 25
+#25
+test_expect_success 'check hash of split' '
+ spl1=$(git subtree split --prefix subdir) &&
+ undo &&
+ git subtree split --prefix subdir --branch splitbr1test &&
+ check_equal ''"$(git rev-parse splitbr1test)"'' "$spl1"
+ git checkout splitbr1test &&
+ new_hash=$(git rev-parse HEAD~2) &&
+ git checkout mainline &&
+ check_equal ''"$new_hash"'' "$subdir_hash"
+'
+
+# 26
test_expect_success 'check split with --branch for an existing branch' '
spl1=''"$(git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --message "Split & rejoin" --rejoin)"'' &&
undo &&
@@ -244,13 +259,13 @@ test_expect_success 'check split with --branch for an existing branch' '
check_equal ''"$(git rev-parse splitbr2)"'' "$spl1"
'
-# 26
+# 27
test_expect_success 'check split with --branch for an incompatible branch' '
test_must_fail git subtree split --prefix subdir --onto FETCH_HEAD --branch subdir
'
-# 27
+# 28
test_expect_success 'check split+rejoin' '
spl1=''"$(git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --message "Split & rejoin" --rejoin)"'' &&
undo &&
@@ -258,7 +273,7 @@ test_expect_success 'check split+rejoin' '
check_equal ''"$(last_commit_message)"'' "Split '"'"'subdir/'"'"' into commit '"'"'"$spl1"'"'"'"
'
-# 28
+# 29
test_expect_success 'add main-sub8' '
create subdir/main-sub8 &&
git commit -m "main-sub8"
@@ -267,14 +282,14 @@ test_expect_success 'add main-sub8' '
# To the subproject!
cd ./subproj
-# 29
+# 30
test_expect_success 'merge split into subproj' '
git fetch .. spl1 &&
git branch spl1 FETCH_HEAD &&
git merge FETCH_HEAD
'
-# 30
+# 31
test_expect_success 'add sub9' '
create sub9 &&
git commit -m "sub9"
@@ -283,19 +298,19 @@ test_expect_success 'add sub9' '
# Back to mainline
cd ..
-# 31
+# 32
test_expect_success 'split for sub8' '
split2=''"$(git subtree split --annotate='"'*'"' --prefix subdir/ --rejoin)"''
git branch split2 "$split2"
'
-# 32
+# 33
test_expect_success 'add main-sub10' '
create subdir/main-sub10 &&
git commit -m "main-sub10"
'
-# 33
+# 34
test_expect_success 'split for sub10' '
spl3=''"$(git subtree split --annotate='"'*'"' --prefix subdir --rejoin)"'' &&
git branch spl3 "$spl3"
@@ -304,7 +319,7 @@ test_expect_success 'split for sub10' '
# To the subproject!
cd ./subproj
-# 34
+# 35
test_expect_success 'merge split into subproj' '
git fetch .. spl3 &&
git branch spl3 FETCH_HEAD &&
@@ -318,13 +333,13 @@ chkms_sub=$(echo $chkms | multiline | sed 's,^,subdir/,' | fixnl)
chks="sub1 sub2 sub3 sub9"
chks_sub=$(echo $chks | multiline | sed 's,^,subdir/,' | fixnl)
-# 35
+# 36
test_expect_success 'make sure exactly the right set of files ends up in the subproj' '
subfiles=''"$(git ls-files | fixnl)"'' &&
check_equal "$subfiles" "$chkms $chks"
'
-# 36
+# 37
test_expect_success 'make sure the subproj history *only* contains commits that affect the subdir' '
allchanges=''"$(git log --name-only --pretty=format:'"''"' | sort | fixnl)"'' &&
check_equal "$allchanges" "$chkms $chks"
@@ -333,20 +348,20 @@ test_expect_success 'make sure the subproj history *only* contains commits that
# Back to mainline
cd ..
-# 37
+# 38
test_expect_success 'pull from subproj' '
git fetch ./subproj subproj-merge-spl3 &&
git branch subproj-merge-spl3 FETCH_HEAD &&
git subtree pull --prefix=subdir ./subproj subproj-merge-spl3
'
-# 38
+# 39
test_expect_success 'make sure exactly the right set of files ends up in the mainline' '
mainfiles=''"$(git ls-files | fixnl)"'' &&
check_equal "$mainfiles" "$chkm $chkms_sub $chks_sub"
'
-# 39
+# 40
test_expect_success 'make sure each filename changed exactly once in the entire history' '
# main-sub?? and /subdir/main-sub?? both change, because those are the
# changes that were split into their own history. And subdir/sub?? never
@@ -355,12 +370,12 @@ test_expect_success 'make sure each filename changed exactly once in the entire
check_equal "$allchanges" ''"$(echo $chkms $chkm $chks $chkms_sub | multiline | sort | fixnl)"''
'
-# 40
+# 41
test_expect_success 'make sure the --rejoin commits never make it into subproj' '
check_equal ''"$(git log --pretty=format:'"'%s'"' HEAD^2 | grep -i split)"'' ""
'
-# 41
+# 42
test_expect_success 'make sure no "git subtree" tagged commits make it into subproj' '
# They are meaningless to subproj since one side of the merge refers to the mainline
check_equal ''"$(git log --pretty=format:'"'%s%n%b'"' HEAD^2 | grep "git-subtree.*:")"'' ""
@@ -370,14 +385,14 @@ test_expect_success 'make sure no "git subtree" tagged commits make it into subp
mkdir test2
cd test2
-# 42
+# 43
test_expect_success 'init main' '
test_create_repo main
'
cd main
-# 43
+# 44
test_expect_success 'add main1' '
create main1 &&
git commit -m "main1"
@@ -385,14 +400,14 @@ test_expect_success 'add main1' '
cd ..
-# 44
+# 45
test_expect_success 'init sub' '
test_create_repo sub
'
cd sub
-# 45
+# 46
test_expect_success 'add sub2' '
create sub2 &&
git commit -m "sub2"
@@ -402,7 +417,7 @@ cd ../main
# check if split can find proper base without --onto
-# 46
+# 47
test_expect_success 'add sub as subdir in main' '
git fetch ../sub master &&
git branch sub2 FETCH_HEAD &&
@@ -411,7 +426,7 @@ test_expect_success 'add sub as subdir in main' '
cd ../sub
-# 47
+# 48
test_expect_success 'add sub3' '
create sub3 &&
git commit -m "sub3"
@@ -419,20 +434,20 @@ test_expect_success 'add sub3' '
cd ../main
-# 48
+# 49
test_expect_success 'merge from sub' '
git fetch ../sub master &&
git branch sub3 FETCH_HEAD &&
git subtree merge --prefix subdir sub3
'
-# 49
+# 50
test_expect_success 'add main-sub4' '
create subdir/main-sub4 &&
git commit -m "main-sub4"
'
-# 50
+# 51
test_expect_success 'split for main-sub4 without --onto' '
git subtree split --prefix subdir --branch mainsub4
'
@@ -442,12 +457,12 @@ test_expect_success 'split for main-sub4 without --onto' '
# have been sub3, but it was not, because its cache was not set to
# itself)
-# 51
+# 52
test_expect_success 'check that the commit parent is sub3' '
check_equal ''"$(git log --pretty=format:%P -1 mainsub4)"'' ''"$(git rev-parse sub3)"''
'
-# 52
+# 53
test_expect_success 'add main-sub5' '
mkdir subdir2 &&
create subdir2/main-sub5 &&
--
1.7.10.4
^ permalink raw reply related
* [PATCH 3/8] Better Error Handling for add
From: David A. Greene @ 2013-01-01 3:57 UTC (permalink / raw)
To: git; +Cc: David A. Greene
In-Reply-To: <1357012655-24974-1-git-send-email-greened@obbligato.org>
From: "David A. Greene" <greened@obbligato.org>
Check refspecs for validity before passing them on to other commands.
This lets us generate more helpful error messages.
Signed-off-by: David A. Greene <greened@obbligato.org>
---
contrib/subtree/git-subtree.sh | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 7ceb413..b8a807a 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -509,8 +509,20 @@ cmd_add()
ensure_clean
if [ $# -eq 1 ]; then
+ ref=$(git check-ref-format --normalize "refs/heads/$1") ||
+ die "'$1' is not a valid refspec. Are you missing a branch?"
+
+ rev=$(git rev-parse --verify $1) ||
+ die "'$1' is not a valid refspec. Are you missing a branch?"
+
"cmd_add_commit" "$@"
elif [ $# -eq 2 ]; then
+ ref=$(git check-ref-format --normalize "refs/heads/$2") ||
+ die "'$2' is not a valid refspec."
+
+ rev=$(git rev-parse --verify $2) ||
+ die "'$2' is not a valid refspec."
+
"cmd_add_repository" "$@"
else
say "error: parameters were '$@'"
--
1.7.10.4
^ permalink raw reply related
* [PATCH 2/8] Add --unannotate
From: David A. Greene @ 2013-01-01 3:57 UTC (permalink / raw)
To: git; +Cc: James Nylen, David A. Greene
In-Reply-To: <1357012655-24974-1-git-send-email-greened@obbligato.org>
From: James Nylen <jnylen@gmail.com>
Teach git-subtree about --unannotate. This option strips a prefix
from a commit message when doing a subtree split.
Author: James Nylen <jnylen@gmail.com>
Signed-off-by: David A. Greene <greened@obbligato.org>
---
contrib/subtree/git-subtree.sh | 11 +++++-
contrib/subtree/git-subtree.txt | 15 ++++++++
contrib/subtree/t/t7900-subtree.sh | 73 ++++++++++++++++++++----------------
3 files changed, 65 insertions(+), 34 deletions(-)
diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index f2b6d4a..7ceb413 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -21,6 +21,7 @@ P,prefix= the name of the subdir to split out
m,message= use the given message as the commit message for the merge commit
options for 'split'
annotate= add a prefix to commit message of new commits
+unannotate= remove a prefix from new commit messages (supports bash globbing)
b,branch= create a new branch from the split subtree
ignore-joins ignore prior --rejoin commits
onto= try connecting new tree to an existing one
@@ -43,6 +44,7 @@ onto=
rejoin=
ignore_joins=
annotate=
+unannotate=
squash=
message=
@@ -80,6 +82,8 @@ while [ $# -gt 0 ]; do
-d) debug=1 ;;
--annotate) annotate="$1"; shift ;;
--no-annotate) annotate= ;;
+ --unannotate) unannotate="$1"; shift ;;
+ --no-unannotate) unannotate= ;;
-b) branch="$1"; shift ;;
-P) prefix="$1"; shift ;;
-m) message="$1"; shift ;;
@@ -315,8 +319,11 @@ copy_commit()
GIT_COMMITTER_NAME \
GIT_COMMITTER_EMAIL \
GIT_COMMITTER_DATE
- (echo -n "$annotate"; cat ) |
- git commit-tree "$2" $3 # reads the rest of stdin
+ (
+ read FIRST_LINE
+ echo "$annotate${FIRST_LINE#$unannotate}"
+ cat # reads the rest of stdin
+ ) | git commit-tree "$2" $3
) || die "Can't copy commit $1"
}
diff --git a/contrib/subtree/git-subtree.txt b/contrib/subtree/git-subtree.txt
index 0c44fda..ae420aa 100644
--- a/contrib/subtree/git-subtree.txt
+++ b/contrib/subtree/git-subtree.txt
@@ -198,6 +198,21 @@ OPTIONS FOR split
git subtree tries to make it work anyway, particularly
if you use --rejoin, but it may not always be effective.
+--unannotate=<annotation>::
+ This option is only valid for the split command.
+
+ When generating synthetic history, try to remove the prefix
+ <annotation> from each commit message (using bash's "strip
+ shortest match from beginning" command, which supports
+ globbing). This makes sense if you format library commits
+ like "library: Change something or other" when you're working
+ in your project's repository, but you want to remove this
+ prefix when pushing back to the library's upstream repository.
+ (In this case --unannotate='*: ' would work well.)
+
+ Like --annotate, you need to use the same <annotation>
+ whenever you split, or you may run into problems.
+
-b <branch>::
--branch=<branch>::
This option is only valid for the split command.
diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 93eeb09..9816da5 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -157,7 +157,7 @@ test_expect_success 'merge fetched subproj' '
# 14
test_expect_success 'add main-sub5' '
create subdir/main-sub5 &&
- git commit -m "main-sub5"
+ git commit -m "subproj: main-sub5"
'
# 15
test_expect_success 'add main6' '
@@ -168,7 +168,7 @@ test_expect_success 'add main6' '
# 16
test_expect_success 'add main-sub7' '
create subdir/main-sub7 &&
- git commit -m "main-sub7"
+ git commit -m "subproj: main-sub7"
'
# 17
@@ -238,7 +238,7 @@ test_expect_success 'check split with --branch' '
check_equal ''"$(git rev-parse splitbr1)"'' "$spl1"
'
-#25
+# 25
test_expect_success 'check hash of split' '
spl1=$(git subtree split --prefix subdir) &&
undo &&
@@ -251,6 +251,15 @@ test_expect_success 'check hash of split' '
'
# 26
+test_expect_success 'check --unannotate' '
+ spl1=$(git subtree split --unannotate='"subproj:"' --prefix subdir --onto FETCH_HEAD --message "Split & rejoin" --rejoin) &&
+ undo &&
+ git subtree split --unannotate='"subproj:"' --prefix subdir --onto FETCH_HEAD --branch splitunann &&
+ check_equal ''"$(git rev-parse splitunann)"'' "$spl1" &&
+ check_equal ''"$(git log splitunann | grep subproj)"'' ""
+'
+
+# 27
test_expect_success 'check split with --branch for an existing branch' '
spl1=''"$(git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --message "Split & rejoin" --rejoin)"'' &&
undo &&
@@ -259,13 +268,13 @@ test_expect_success 'check split with --branch for an existing branch' '
check_equal ''"$(git rev-parse splitbr2)"'' "$spl1"
'
-# 27
+# 28
test_expect_success 'check split with --branch for an incompatible branch' '
test_must_fail git subtree split --prefix subdir --onto FETCH_HEAD --branch subdir
'
-# 28
+# 29
test_expect_success 'check split+rejoin' '
spl1=''"$(git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --message "Split & rejoin" --rejoin)"'' &&
undo &&
@@ -273,7 +282,7 @@ test_expect_success 'check split+rejoin' '
check_equal ''"$(last_commit_message)"'' "Split '"'"'subdir/'"'"' into commit '"'"'"$spl1"'"'"'"
'
-# 29
+# 30
test_expect_success 'add main-sub8' '
create subdir/main-sub8 &&
git commit -m "main-sub8"
@@ -282,14 +291,14 @@ test_expect_success 'add main-sub8' '
# To the subproject!
cd ./subproj
-# 30
+# 31
test_expect_success 'merge split into subproj' '
git fetch .. spl1 &&
git branch spl1 FETCH_HEAD &&
git merge FETCH_HEAD
'
-# 31
+# 32
test_expect_success 'add sub9' '
create sub9 &&
git commit -m "sub9"
@@ -298,19 +307,19 @@ test_expect_success 'add sub9' '
# Back to mainline
cd ..
-# 32
+# 33
test_expect_success 'split for sub8' '
split2=''"$(git subtree split --annotate='"'*'"' --prefix subdir/ --rejoin)"''
git branch split2 "$split2"
'
-# 33
+# 34
test_expect_success 'add main-sub10' '
create subdir/main-sub10 &&
git commit -m "main-sub10"
'
-# 34
+# 35
test_expect_success 'split for sub10' '
spl3=''"$(git subtree split --annotate='"'*'"' --prefix subdir --rejoin)"'' &&
git branch spl3 "$spl3"
@@ -319,7 +328,7 @@ test_expect_success 'split for sub10' '
# To the subproject!
cd ./subproj
-# 35
+# 36
test_expect_success 'merge split into subproj' '
git fetch .. spl3 &&
git branch spl3 FETCH_HEAD &&
@@ -333,13 +342,13 @@ chkms_sub=$(echo $chkms | multiline | sed 's,^,subdir/,' | fixnl)
chks="sub1 sub2 sub3 sub9"
chks_sub=$(echo $chks | multiline | sed 's,^,subdir/,' | fixnl)
-# 36
+# 37
test_expect_success 'make sure exactly the right set of files ends up in the subproj' '
subfiles=''"$(git ls-files | fixnl)"'' &&
check_equal "$subfiles" "$chkms $chks"
'
-# 37
+# 38
test_expect_success 'make sure the subproj history *only* contains commits that affect the subdir' '
allchanges=''"$(git log --name-only --pretty=format:'"''"' | sort | fixnl)"'' &&
check_equal "$allchanges" "$chkms $chks"
@@ -348,20 +357,20 @@ test_expect_success 'make sure the subproj history *only* contains commits that
# Back to mainline
cd ..
-# 38
+# 39
test_expect_success 'pull from subproj' '
git fetch ./subproj subproj-merge-spl3 &&
git branch subproj-merge-spl3 FETCH_HEAD &&
git subtree pull --prefix=subdir ./subproj subproj-merge-spl3
'
-# 39
+# 40
test_expect_success 'make sure exactly the right set of files ends up in the mainline' '
mainfiles=''"$(git ls-files | fixnl)"'' &&
check_equal "$mainfiles" "$chkm $chkms_sub $chks_sub"
'
-# 40
+# 41
test_expect_success 'make sure each filename changed exactly once in the entire history' '
# main-sub?? and /subdir/main-sub?? both change, because those are the
# changes that were split into their own history. And subdir/sub?? never
@@ -370,12 +379,12 @@ test_expect_success 'make sure each filename changed exactly once in the entire
check_equal "$allchanges" ''"$(echo $chkms $chkm $chks $chkms_sub | multiline | sort | fixnl)"''
'
-# 41
+# 42
test_expect_success 'make sure the --rejoin commits never make it into subproj' '
check_equal ''"$(git log --pretty=format:'"'%s'"' HEAD^2 | grep -i split)"'' ""
'
-# 42
+# 43
test_expect_success 'make sure no "git subtree" tagged commits make it into subproj' '
# They are meaningless to subproj since one side of the merge refers to the mainline
check_equal ''"$(git log --pretty=format:'"'%s%n%b'"' HEAD^2 | grep "git-subtree.*:")"'' ""
@@ -385,14 +394,14 @@ test_expect_success 'make sure no "git subtree" tagged commits make it into subp
mkdir test2
cd test2
-# 43
+# 44
test_expect_success 'init main' '
test_create_repo main
'
cd main
-# 44
+# 45
test_expect_success 'add main1' '
create main1 &&
git commit -m "main1"
@@ -400,14 +409,14 @@ test_expect_success 'add main1' '
cd ..
-# 45
+# 46
test_expect_success 'init sub' '
test_create_repo sub
'
cd sub
-# 46
+# 47
test_expect_success 'add sub2' '
create sub2 &&
git commit -m "sub2"
@@ -417,7 +426,7 @@ cd ../main
# check if split can find proper base without --onto
-# 47
+# 48
test_expect_success 'add sub as subdir in main' '
git fetch ../sub master &&
git branch sub2 FETCH_HEAD &&
@@ -426,7 +435,7 @@ test_expect_success 'add sub as subdir in main' '
cd ../sub
-# 48
+# 49
test_expect_success 'add sub3' '
create sub3 &&
git commit -m "sub3"
@@ -434,20 +443,20 @@ test_expect_success 'add sub3' '
cd ../main
-# 49
+# 50
test_expect_success 'merge from sub' '
git fetch ../sub master &&
git branch sub3 FETCH_HEAD &&
git subtree merge --prefix subdir sub3
'
-# 50
+# 51
test_expect_success 'add main-sub4' '
create subdir/main-sub4 &&
git commit -m "main-sub4"
'
-# 51
+# 52
test_expect_success 'split for main-sub4 without --onto' '
git subtree split --prefix subdir --branch mainsub4
'
@@ -457,19 +466,19 @@ test_expect_success 'split for main-sub4 without --onto' '
# have been sub3, but it was not, because its cache was not set to
# itself)
-# 52
+# 53
test_expect_success 'check that the commit parent is sub3' '
check_equal ''"$(git log --pretty=format:%P -1 mainsub4)"'' ''"$(git rev-parse sub3)"''
'
-# 53
+# 54
test_expect_success 'add main-sub5' '
mkdir subdir2 &&
create subdir2/main-sub5 &&
git commit -m "main-sub5"
'
-# 53
+# 55
test_expect_success 'split for main-sub5 without --onto' '
# also test that we still can split out an entirely new subtree
# if the parent of the first commit in the tree is not empty,
@@ -502,7 +511,7 @@ joincommits()
echo "$commit $all"
}
-# 54
+# 56
test_expect_success 'verify one file change per commit' '
x= &&
list=''"$(git log --pretty=format:'"'commit: %H'"' | joincommits)"'' &&
--
1.7.10.4
^ permalink raw reply related
* [PATCH 4/8] Fix Synopsis
From: David A. Greene @ 2013-01-01 3:57 UTC (permalink / raw)
To: git; +Cc: David A. Greene
In-Reply-To: <1357012655-24974-1-git-send-email-greened@obbligato.org>
From: "David A. Greene" <greened@obbligato.org>
Fix the documentation of add to show that a repository can be
specified along with a commit.
Change "commit" to "refspec" in the synopsis for add.
Suggested by Yann Dirson <dirson@bertin.fr>.
Signed-off-by: David A. Greene <greened@obbligato.org>
---
contrib/subtree/git-subtree.sh | 3 ++-
contrib/subtree/git-subtree.txt | 3 ++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index b8a807a..ad62dfb 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -8,7 +8,8 @@ if [ $# -eq 0 ]; then
set -- -h
fi
OPTS_SPEC="\
-git subtree add --prefix=<prefix> <commit>
+git subtree add --prefix=<prefix> <refspec>
+git subtree add --prefix=<prefix> <repository> <refspec>
git subtree merge --prefix=<prefix> <commit>
git subtree pull --prefix=<prefix> <repository> <refspec...>
git subtree push --prefix=<prefix> <repository> <refspec...>
diff --git a/contrib/subtree/git-subtree.txt b/contrib/subtree/git-subtree.txt
index ae420aa..89c2d6e 100644
--- a/contrib/subtree/git-subtree.txt
+++ b/contrib/subtree/git-subtree.txt
@@ -9,7 +9,8 @@ git-subtree - Merge subtrees together and split repository into subtrees
SYNOPSIS
--------
[verse]
-'git subtree' add -P <prefix> <commit>
+'git subtree' add -P <prefix> <refspec>
+'git subtree' add -P <prefix> <repository> <refspec>
'git subtree' pull -P <prefix> <repository> <refspec...>
'git subtree' push -P <prefix> <repository> <refspec...>
'git subtree' merge -P <prefix> <commit>
--
1.7.10.4
^ permalink raw reply related
* [PATCH 5/8] Honor DESTDIR
From: David A. Greene @ 2013-01-01 3:57 UTC (permalink / raw)
To: git; +Cc: Adam Tkac, David A. Greene
In-Reply-To: <1357012655-24974-1-git-send-email-greened@obbligato.org>
From: Adam Tkac <atkac@redhat.com>
Teach git-subtree's Makefile to honor DESTDIR.
Author: Adam Tkac <atkac@redhat.com>
Signed-off-by: Adam Tkac <atkac@redhat.com>
Signed-off-by: David A. Greene <greened@obbligato.org>
---
contrib/subtree/Makefile | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/contrib/subtree/Makefile b/contrib/subtree/Makefile
index 05cdd5c..36ae3e4 100644
--- a/contrib/subtree/Makefile
+++ b/contrib/subtree/Makefile
@@ -30,12 +30,12 @@ $(GIT_SUBTREE): $(GIT_SUBTREE_SH)
doc: $(GIT_SUBTREE_DOC)
install: $(GIT_SUBTREE)
- $(INSTALL) -m 755 $(GIT_SUBTREE) $(libexecdir)
+ $(INSTALL) -m 755 $(GIT_SUBTREE) $(DESTDIR)$(libexecdir)
install-doc: install-man
install-man: $(GIT_SUBTREE_DOC)
- $(INSTALL) -m 644 $^ $(man1dir)
+ $(INSTALL) -m 644 $^ $(DESTDIR)$(man1dir)
$(GIT_SUBTREE_DOC): $(GIT_SUBTREE_XML)
xmlto -m $(MANPAGE_NORMAL_XSL) man $^
--
1.7.10.4
^ permalink raw reply related
* [PATCH 6/8] Make the Manual Directory if Needed
From: David A. Greene @ 2013-01-01 3:57 UTC (permalink / raw)
To: git; +Cc: Jesper L. Nielsen, David A. Greene
In-Reply-To: <1357012655-24974-1-git-send-email-greened@obbligato.org>
From: "Jesper L. Nielsen" <lyager@gmail.com>
Before install git-subtree documentation, make sure the manpage
directory exists.
Author: Jesper L. Nielsen <lyager@gmail.com>
Signed-off-by: Jesper L. Nielsen <lyager@gmail.com>
Signed-off-by: David A. Greene <greened@obbligato.org>
---
contrib/subtree/Makefile | 1 +
1 file changed, 1 insertion(+)
diff --git a/contrib/subtree/Makefile b/contrib/subtree/Makefile
index 36ae3e4..52d6fb9 100644
--- a/contrib/subtree/Makefile
+++ b/contrib/subtree/Makefile
@@ -35,6 +35,7 @@ install: $(GIT_SUBTREE)
install-doc: install-man
install-man: $(GIT_SUBTREE_DOC)
+ mkdir -p $(man1dir)
$(INSTALL) -m 644 $^ $(DESTDIR)$(man1dir)
$(GIT_SUBTREE_DOC): $(GIT_SUBTREE_XML)
--
1.7.10.4
^ permalink raw reply related
* [PATCH 8/8] Fix Documentation Typo
From: David A. Greene @ 2013-01-01 3:57 UTC (permalink / raw)
To: git; +Cc: Michael Schubert, David A. Greene
In-Reply-To: <1357012655-24974-1-git-send-email-greened@obbligato.org>
From: Michael Schubert <mschub@elegosoft.com>
"split" is documented below "push" so fix the reference to it in
push's documentation.
Author: Michael Schubert <mschub@elegosoft.com>
Signed-off-by: Michael Schubert <mschub@elegosoft.com>
Signed-off-by: David A. Greene <greened@obbligato.org>
---
contrib/subtree/git-subtree.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/contrib/subtree/git-subtree.txt b/contrib/subtree/git-subtree.txt
index 89c2d6e..078d4ac 100644
--- a/contrib/subtree/git-subtree.txt
+++ b/contrib/subtree/git-subtree.txt
@@ -94,7 +94,7 @@ pull::
repository.
push::
- Does a 'split' (see above) using the <prefix> supplied
+ Does a 'split' (see below) using the <prefix> supplied
and then does a 'git push' to push the result to the
repository and refspec. This can be used to push your
subtree to different branches of the remote repository.
--
1.7.10.4
^ permalink raw reply related
* [PATCH 7/8] Ignore git-subtree
From: David A. Greene @ 2013-01-01 3:57 UTC (permalink / raw)
To: git; +Cc: Michael Schubert, David A. Greene
In-Reply-To: <1357012655-24974-1-git-send-email-greened@obbligato.org>
From: Michael Schubert <mschub@elegosoft.com>
Add the git-subtree command executable to .gitignore.
Author: Michael Schubert <mschub@elegosoft.com>
Signed-off-by: Michael Schubert <mschub@elegosoft.com>
Signed-off-by: David A. Greene <greened@obbligato.org>
---
contrib/subtree/.gitignore | 1 +
1 file changed, 1 insertion(+)
diff --git a/contrib/subtree/.gitignore b/contrib/subtree/.gitignore
index 7e77c9d..91360a3 100644
--- a/contrib/subtree/.gitignore
+++ b/contrib/subtree/.gitignore
@@ -1,4 +1,5 @@
*~
+git-subtree
git-subtree.xml
git-subtree.1
mainline
--
1.7.10.4
^ permalink raw reply related
* Re: [PATCH] subtree.sh: Use raw subject and body modifier "%B" instead of "%s%n%n%b"
From: greened @ 2013-01-01 3:59 UTC (permalink / raw)
To: Techlive Zheng; +Cc: git, gitster, apenwarr
In-Reply-To: <87mwwt4yp4.fsf@waller.obbligato.org>
greened@obbligato.org writes:
> I've applied this patch to my working copy but I'm not finding that I
> can recreate the original problem when the patch is disabled.
^ not
-David
^ permalink raw reply
* Re: git subtree error (just how do you expect me to merge 0 trees?)
From: greened @ 2013-01-01 4:04 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Drew Crawford, git@vger.kernel.org
In-Reply-To: <7v7gnxd24h.fsf@alter.siamese.dyndns.org>
Junio C Hamano <gitster@pobox.com> writes:
>> With one positional option, git-subtree add simply assumes
>> it's a refspec. Is there an easy way to check whether a string is a
>> proper refspec? Even better would be a way to check if a string is a
>> path to a git repository.
>
> Do you literally mean "a path to a repository" in the above, or do
> you mean "a remote that is like what is accepted by 'git fetch'"?
It's the latter as git-subtree calls git-fetch to do the work of
getting revisions.
> On the other hand, if you mean the command takes a remote and an
> optional list of refspecs just like "git fetch" does, then I am not
> sure it is a good design in the first place to allow "refspecs
> only", if only to keep the interface similar to "git fetch" (you
> cannot omit remote and give refspecs, as you cannot interpret
> refspecs without knowing in the context of which remote they are to
> be interpreted).
If just a refspec is given, git-subtree does a rev-parse in the current
directory and that seems to work fine. It's what I as a user would
expect to happen.
> I would imagine you could disambiguate and default to "origin" or
> something when you guessed that remote was omitted if you really
> wanted to, with a syntacitical heuristics, such as "a refspec will
> never have two colons in it", "a URL tends to begin with a short
> alphabet word, a colon and double-slash", etc.
Hmm...I haven't added code to verify the repository/remote argument if
given. I suppose a rev-parse --verify would suffice?
-David
^ permalink raw reply
* Re: [PATCH 1/8] Use %B for Split Subject/Body
From: greened @ 2013-01-01 4:06 UTC (permalink / raw)
To: git; +Cc: Techlive Zheng
In-Reply-To: <1357012655-24974-2-git-send-email-greened@obbligato.org>
"David A. Greene" <greened@obbligato.org> writes:
> From: Techlive Zheng <techlivezheng@gmail.com>
>
> Use %B to format the commit message and body to avoid an extra newline
> if a commit only has a subject line.
Wow. So that was a spectacular fail. Sorry about th duplicate patch
e-mails. I have no idea how that happened.
-David
^ permalink raw reply
* Re: [RFC] pack-objects: compression level for non-blobs
From: Duy Nguyen @ 2013-01-01 4:15 UTC (permalink / raw)
To: Jeff King; +Cc: Shawn Pearce, David Michael Barr, Git Mailing List
In-Reply-To: <CAJo=hJtjtpiPVd6Koy9q5je7s7A4EyDa-CptJNCnHLSLgd9W7g@mail.gmail.com>
On Tue, Jan 1, 2013 at 1:06 AM, Shawn Pearce <spearce@spearce.org> wrote:
>> 3. Dropping the "commits" file and just using the pack-*.idx as the
>> index. The problem is that it is sparse in the commit space. So
>> just naively storing 40 bytes per entry is going to waste a lot of
>> space. If we had a separate index as in (1) above, that could be
>> dropped to (say) 4 bytes of offset per object. But still, right now
>> the commits file for linux-2.6 is about 7.2M (20 bytes times ~376K
>> commits). There are almost 3 million total objects, so even storing
>> 4 bytes per object is going to be worse.
>
> Fix pack-objects to behave the way JGit does, cluster commits first in
> the pack stream. Now you have a dense space of commits. If I remember
> right this has a tiny positive improvement for most rev-list
> operations with very little downside.
I was going to suggest a similar thing. The current state of C Git's
pack writing is not bad. We mix commits and tags together, but tags
are few usually. Once we get the upper and lower bound, in terms of
object position in the pack, of the commit+tag region, we could reduce
the waste significantly. That is if you sort the cache by the object
order in the pack.
--
Duy
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox