Re: git reflog delete HEAD@{1} HEAD@{2} caught me by surprise...
> I would actually call that behaviour a bug. Well, yes, that was my inclination, too. But writing documentation was easier than writing a code patch. :-) Even when it is fixed, a comment about when it was fixed and what the buggy version did should live in the BUGS section for a while, to warn people writing portable scripts. > Perhaps it should grab > all the command line arguments first, group them per the ref the > reflog entries are based on, and expire _all_ reflog entries from > the same reflog in one go? Two other options are to sort them in decreasing entry order (which you could do either per-reflog, or simply globally), or to remember previous deletions so you can adjust the numbers of later ones. One tricky point is whether it's possible for a reflog to have two names, via a symlink or something. That definitely complicates collision detection. > Until that happens, it may make sense to error it out when more than > one entries are given from the command line, at least for the same > ref. Detecting this seems like half the implementation work of fixing it, so I'm not sure it's worth bothering. Looking at the code (builtin/reflog.c), I notice that expire_reflog() takes a lock on the ref, but the previous count_reflog_ent code doesn't, so things aren't necessarily race-proof. I haven't figured out if the race is a problem (i.e. does expire_reflog do something nasty if the struct cmd_reflog_expire_cb holds stale data?), but I noticed... -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/2] config: treat user and xdg config permission problems as errors
Jeff King wrote: > For example, servers may depend on /etc/gitconfig to enforce security > policy (e.g., setting transfer.fsckObjects or receive.deny*). Perhaps > our default should be safe, and people can use GIT_CONFIG_NOSYSTEM to > work around a broken machine. Very good point. How about these patches on top? Jonathan Nieder (2): config doc: advertise GIT_CONFIG_NOSYSTEM config: exit on error accessing any config file Documentation/git-config.txt | 8 config.c | 6 +++--- 2 files changed, 11 insertions(+), 3 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 3/2] config doc: advertise GIT_CONFIG_NOSYSTEM
When a syntax error or other problem renders /etc/gitconfig buggy on a multiuser system where mortals do not have write access to /etc, the GIT_CONFIG_NOSYSTEM variable is the best tool we have to keep getting work done until the sysadmin sorts the problem out. Noticed while experimenting with teaching git to error out when /etc/gitconfig is unreadable. Signed-off-by: Jonathan Nieder --- Documentation/git-config.txt | 8 1 file changed, 8 insertions(+) diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt index eaea0791..907a1fd5 100644 --- a/Documentation/git-config.txt +++ b/Documentation/git-config.txt @@ -240,6 +240,14 @@ GIT_CONFIG:: Using the "--global" option forces this to ~/.gitconfig. Using the "--system" option forces this to $(prefix)/etc/gitconfig. +GIT_CONFIG_NOSYSTEM:: + Whether to skip reading settings from the system-wide + $(prefix)/etc/gitconfig file. This environment variable can + be used along with HOME and XDG_CONFIG_HOME to create a + predictable environment for a picky script, or you can set it + temporarily to avoid using a buggy /etc/gitconfig file while + waiting for someone with sufficient permissions to fix it. + See also <>. -- 1.8.0.rc2 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 4/2] config: exit on error accessing any config file
There is convenience in warning and moving on when somebody has a bogus permissions on /etc/gitconfig and cannot do anything about it. But the cost in predictability and security is too high --- when unreadable config files are skipped, it means an I/O error or permissions problem causes important configuration to be bypassed. For example, servers may depend on /etc/gitconfig to enforce security policy (setting transfer.fsckObjects or receive.deny*). Best to always error out when encountering trouble accessing a config file. This may add inconvenience in some cases: 1. You are inspecting somebody else's repo, and you do not have access to their .git/config file. Git typically dies in this case already since we cannot read core.repositoryFormatVersion, so the change should not be too noticeable. 2. You have used "sudo -u" or a similar tool to switch uid, and your environment still points Git at your original user's global config, which is not readable. In this case people really would be inconvenienced (they would rather see the harmless warning and continue the operation) but they can work around it by setting HOME appropriately after switching uids. 3. You do not have access to /etc/gitconfig due to a broken setup. In this case, erroring out is a good way to put pressure on the sysadmin to fix the setup. While they wait for a reply, users can set GIT_CONFIG_NOSYSTEM to true to keep Git working without complaint. After this patch, errors accessing the repository-local and systemwide config files and files requested in include directives cause Git to exit, just like errors accessing ~/.gitconfig. Explained-by: Jeff King Signed-off-by: Jonathan Nieder --- config.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config.c b/config.c index e8875b8a..a4d153f6 100644 --- a/config.c +++ b/config.c @@ -60,7 +60,7 @@ static int handle_path_include(const char *path, struct config_include_data *inc path = buf.buf; } - if (!access_or_warn(path, R_OK)) { + if (!access_or_die(path, R_OK)) { if (++inc->depth > MAX_INCLUDE_DEPTH) die(include_depth_advice, MAX_INCLUDE_DEPTH, path, cf && cf->name ? cf->name : "the command line"); @@ -939,7 +939,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config) home_config_paths(&user_config, &xdg_config, "config"); - if (git_config_system() && !access_or_warn(git_etc_gitconfig(), R_OK)) { + if (git_config_system() && !access_or_die(git_etc_gitconfig(), R_OK)) { ret += git_config_from_file(fn, git_etc_gitconfig(), data); found += 1; @@ -955,7 +955,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config) found += 1; } - if (repo_config && !access_or_warn(repo_config, R_OK)) { + if (repo_config && !access_or_die(repo_config, R_OK)) { ret += git_config_from_file(fn, repo_config, data); found += 1; } -- 1.8.0.rc2 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 3/2] doc: advertise GIT_CONFIG_NOSYSTEM
On a multiuser system where mortals do not have write access to /etc, the GIT_CONFIG_NOSYSTEM variable is the best tool we have to keep getting work done when a syntax error or other problem renders /etc/gitconfig buggy, until the sysadmin sorts the problem out. Noticed while experimenting with teaching git to error out when /etc/gitconfig is unreadable. Signed-off-by: Jonathan Nieder --- Jonathan Nieder wrote: > --- a/Documentation/git-config.txt > +++ b/Documentation/git-config.txt > @@ -240,6 +240,14 @@ GIT_CONFIG:: > Using the "--global" option forces this to ~/.gitconfig. Using the > "--system" option forces this to $(prefix)/etc/gitconfig. > > +GIT_CONFIG_NOSYSTEM:: Hm, unlike GIT_CONFIG this applies to all git commands (not just "git config"), so it is misleading to document them in the same place. Here's a better patch. Documentation/git-config.txt | 4 Documentation/git.txt| 8 2 files changed, 12 insertions(+) diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt index eaea0791..9ae2508f 100644 --- a/Documentation/git-config.txt +++ b/Documentation/git-config.txt @@ -240,6 +240,10 @@ GIT_CONFIG:: Using the "--global" option forces this to ~/.gitconfig. Using the "--system" option forces this to $(prefix)/etc/gitconfig. +GIT_CONFIG_NOSYSTEM:: + Whether to skip reading settings from the system-wide + $(prefix)/etc/gitconfig file. See linkgit:git[1] for details. + See also <>. diff --git a/Documentation/git.txt b/Documentation/git.txt index d1d227a3..ae1f833a 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -757,6 +757,14 @@ for further details. and read the password from its STDOUT. See also the 'core.askpass' option in linkgit:git-config[1]. +'GIT_CONFIG_NOSYSTEM':: + Whether to skip reading settings from the system-wide + `$(prefix)/etc/gitconfig` file. This environment variable can + be used along with `$HOME` and `$XDG_CONFIG_HOME` to create a + predictable environment for a picky script, or you can set it + temporarily to avoid using a buggy `/etc/gitconfig` file while + waiting for someone with sufficient permissions to fix it. + 'GIT_FLUSH':: If this environment variable is set to "1", then commands such as 'git blame' (in incremental mode), 'git rev-list', 'git log', -- 1.8.0.rc2 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [RFC/PATCH 0/2] Re: [PATCH] config: warn on inaccessible files
Junio C Hamano wrote: > If the config side can > be switched to unconditionally attempt to fopen and then deal with > an error when it happens, we can get rid of access_or_{warn,die} > and replace them with fopen_or_{warn,die} and use them from the two > places (attr.c:read_attr_from_file() and the configuration stuff). > > I haven't looked to see if that a too intrusive refactoring to be > worth it, though. That sounds reasonable, but I'm punting on it. The first step would be tweaking the git_config_from_file() calling convention to convey "missing file" errors specially, perhaps by making sure errno is meaningful when the return value is -1, and that already sounds like work. ;-) Thanks, Jonathan -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: A design for subrepositories
Quoting "Junio C Hamano" : If the submodules ever get reorganized and foo is moved to ./bar, then it is impossible to check out older versions or alternate branches, since the submodule is no longer where it is expected to be at the origin. Isn't that exactly what the "module name" vs "module path" mapping in .gitmodules file is meant to address? Yes, and as I showed after the part you quoted, it is possible to refer to a module by name, although it looks like such a hack that I can't imagine it's currently something that git-submodule is intended to support. But still, "git submodule update" only looks at the modules in the currently checked-out tree. If we have other branches or old tags that refer to other submodules, there's no simple way to fetch those, too. Didn't I already suggest you to think about how you can improve existing "git submodule" to suit your use case better? Yes, and I listed three possible ways. Two of them seem technically unattractive, whereas one of them (submodules as ref directories) seems like a huge change that could introduce incompatibilities. That is why a separate tool seems like a cleaner choice. If you want enhancements to git-submodule, at least deign to comment on the issues above. There is actually a fourth alternative: extend the git protocol so that a remote repository could be queried for its list of submodules. But this seems particularly icky: git is at its core such a low-level framework. Nested repositories are such a high-level concept that something is wrong if the core needs specialized support for it. The ref directories approach, on the other hand, is completely transparent to standard tools. Lauri -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v5 05/12] Integrate wildmatch to git
diff --git a/t/t3070-wildmatch.sh b/t/t3070-wildmatch.sh new file mode 100755 index 000..dbd3c8b --- /dev/null +++ b/t/t3070-wildmatch.sh @@ -0,0 +1,188 @@ +#!/bin/sh +#else +#test_expect_success BROKEN_FNMATCH "fnmatch: '$3' '$4'" " +#! test-wildmatch fnmatch '$3' '$4' +#" +fi +} + Thanks: On my Mac OS X box: # passed all 259 test(s) And a quick test on cygwin: $ ./t3070-wildmatch.sh 2>&1 | grep "not ok" not ok - 148 fnmatch: match '5' '[[:xdigit:]]' not ok - 150 fnmatch: match 'f' '[[:xdigit:]]' not ok - 152 fnmatch: match 'D' '[[:xdigit:]]' And 2 micronits: a) Commented out code b) Whithespace damage ( 4 spaces used for an indent of 1, TAB for indent of 2) /Torsten -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] exclude: fix a bug in prefix comparison optimization
When "namelen" becomes zero at this stage, we have matched the fixed part, but whether it actually matches the pattern still depends on the pattern in "exclude". As demonstrated in t3001, path "three/a.3" exists and it matches the "three/a.3" part in pattern "three/a.3[abc]", but that does not mean a true match. Don't be too optimistic and let fnmatch() do the job. Signed-off-by: Nguyễn Thái Ngọc Duy --- dir.c | 2 +- t/t3001-ls-files-others-exclude.sh | 6 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/dir.c b/dir.c index 4868339..90bf3a4 100644 --- a/dir.c +++ b/dir.c @@ -575,7 +575,7 @@ int excluded_from_list(const char *pathname, namelen -= prefix; } - if (!namelen || !fnmatch_icase(exclude, name, FNM_PATHNAME)) + if (!fnmatch_icase(exclude, name, FNM_PATHNAME)) return to_exclude; } return -1; /* undecided */ diff --git a/t/t3001-ls-files-others-exclude.sh b/t/t3001-ls-files-others-exclude.sh index c8fe978..dc2f045 100755 --- a/t/t3001-ls-files-others-exclude.sh +++ b/t/t3001-ls-files-others-exclude.sh @@ -214,4 +214,10 @@ test_expect_success 'subdirectory ignore (l1)' ' test_cmp expect actual ' +test_expect_success 'pattern matches prefix completely' ' + : >expect && + git ls-files -i -o --exclude "/three/a.3[abc]" >actual && + test_cmp expect actual +' + test_done -- 1.8.0.rc2.11.g2b79d01 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH/RFC 0/2] Re: [PATCH 2/7] Change canonicalize_url() to use the SVN 1.7 API when available.
Hi Eric, Michael G Schwern wrote: > On 2012.7.28 6:50 AM, Jonathan Nieder wrote: >> Michael G Schwern wrote: >>> --- a/perl/Git/SVN/Utils.pm >>> +++ b/perl/Git/SVN/Utils.pm >> [...] >>> @@ -100,6 +102,20 @@ API as a URL. >>> =cut >>> >>> sub canonicalize_url { >>> + my $url = shift; >>> + >>> + # The 1.7 way to do it >>> + if ( defined &SVN::_Core::svn_uri_canonicalize ) { >>> + return SVN::_Core::svn_uri_canonicalize($url); >>> + } >>> + # There wasn't a 1.6 way to do it, so we do it ourself. >>> + else { >>> + return _canonicalize_url_ourselves($url); [...] >> Leaves me a bit nervous. > > As it should, SVN dumped a mess on us. Here's a pair of patches that address some of the bugs I was alluding to. Patch 1 makes _canonicalize_url_ourselves() match Subversion's own canonicalization behavior more closely, though even with that patch it still does not meet Subversion's requirements perfectly (e.g., "%ab" is not canonicalized to "%AB"). Patch 2 makes that not matter by using svn_path_canonicalize() when possible, which is the standard way to do this kind of thing. Sorry for the lack of clarity before. Jonathan Nieder (2): git svn: do not overescape URLs (fallback case) Git::SVN::Utils::canonicalize_url: use svn_path_canonicalize when available perl/Git/SVN/Utils.pm | 14 +- 1 file changed, 9 insertions(+), 5 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/2] git svn: do not overescape URLs (fallback case)
Subversion's canonical URLs are intended to make URL comparison easy and therefore have strict rules about what characters are special enough to urlencode and what characters should be left alone. When in the fallback codepath because unable to use libsvn's own canonicalization function for some reason, escape special characters in URIs according to the svn_uri__char_validity[] table in subversion/libsvn_subr/path.c (r935829). The libsvn versions that trigger this code path are not likely to be strict enough to care, but it's nicer to be consistent. Noticed by using SVN 1.6.17 perl bindings, which do not provide SVN::_Core::svn_uri_canonicalize (triggering the fallback code), with libsvn 1.7.5, whose do_switch is fussy enough to care: Committing to file:///home/jrn/src/git/t/trash%20directory.\ t9118-git-svn-funky-branch-names/svnrepo/pr%20ject/branches\ /more%20fun%20plugin%21 ... svn: E235000: In file '[...]/subversion/libsvn_subr/dirent_uri.c' \ line 2291: assertion failed (svn_uri_is_canonical(url, pool)) error: git-svn died of signal 6 not ok - 3 test dcommit to funky branch After this change, the '!' in 'more%20fun%20plugin!' is not urlencoded and t9118 passes again. Signed-off-by: Jonathan Nieder --- perl/Git/SVN/Utils.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/perl/Git/SVN/Utils.pm b/perl/Git/SVN/Utils.pm index 8b8cf375..3d1a0933 100644 --- a/perl/Git/SVN/Utils.pm +++ b/perl/Git/SVN/Utils.pm @@ -155,7 +155,7 @@ sub _canonicalize_url_path { my @parts; foreach my $part (split m{/+}, $uri_path) { - $part =~ s/([^~\w.%+-]|%(?![a-fA-F0-9]{2}))/sprintf("%%%02X",ord($1))/eg; + $part =~ s/([^!\$%&'()*+,.\/\w:=\@_`~-]|%(?![a-fA-F0-9]{2}))/sprintf("%%%02X",ord($1))/eg; push @parts, $part; } -- 1.8.0.rc2 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 2/2] git svn: canonicalize_url(): use svn_path_canonicalize when available
Until Subversion 1.7 (more precisely r873487), the standard way to canonicalize a URI was to call svn_path_canonicalize(). Use it. This saves "git svn" from having to rely on our imperfect reimplementation of the same. If the function doesn't exist or returns undef, though, it can use the fallback code, which we keep to be conservative. Since svn_path_canonicalize() was added before Subversion 1.1, hopefully that doesn't happen often. Signed-off-by: Jonathan Nieder --- perl/Git/SVN/Utils.pm | 12 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/perl/Git/SVN/Utils.pm b/perl/Git/SVN/Utils.pm index 3d1a0933..40f7c799 100644 --- a/perl/Git/SVN/Utils.pm +++ b/perl/Git/SVN/Utils.pm @@ -138,15 +138,19 @@ API as a URL. sub canonicalize_url { my $url = shift; + my $rv; # The 1.7 way to do it if ( defined &SVN::_Core::svn_uri_canonicalize ) { - return SVN::_Core::svn_uri_canonicalize($url); + $rv = SVN::_Core::svn_uri_canonicalize($url); } - # There wasn't a 1.6 way to do it, so we do it ourself. - else { - return _canonicalize_url_ourselves($url); + # The 1.6 way to do it + elsif ( defined &SVN::_Core::svn_path_canonicalize ) { + $rv = SVN::_Core::svn_path_canonicalize($url); } + return $rv if defined $rv; + + return _canonicalize_url_ourselves($url); } -- 1.8.0.rc2 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 0/4] nd/attr-match-optim-more updates
This is on top of nd/attr-match-optim-more to fix the bug I sent recently [1] sharing the code, thus sharing any fixes. [1] http://thread.gmane.org/gmane.comp.version-control.git/207652 Nguyễn Thái Ngọc Duy (4): exclude: stricten a length check in EXC_FLAG_ENDSWITH case exclude: fix a bug in prefix compare optimization exclude/attr: share basename matching code exclude/attr: share full pathname matching code attr.c | 50 +++ dir.c | 121 +++-- dir.h | 5 ++ t/t3001-ls-files-others-exclude.sh | 6 ++ 4 files changed, 95 insertions(+), 87 deletions(-) -- 1.8.0.rc2.11.g2b79d01 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/4] exclude: stricten a length check in EXC_FLAG_ENDSWITH case
This block of code deals with the "basename" part only, which has the length of "pathlen - (basename - pathname)". Stricten the length check and remove "pathname" from the main expression to avoid confusion. Signed-off-by: Nguyễn Thái Ngọc Duy --- dir.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dir.c b/dir.c index cddf043..d81498e 100644 --- a/dir.c +++ b/dir.c @@ -561,8 +561,9 @@ int excluded_from_list(const char *pathname, if (!strcmp_icase(exclude, basename)) return to_exclude; } else if (x->flags & EXC_FLAG_ENDSWITH) { - if (x->patternlen - 1 <= pathlen && - !strcmp_icase(exclude + 1, pathname + pathlen - x->patternlen + 1)) + int len = pathlen - (basename - pathname); + if (x->patternlen - 1 <= len && + !strcmp_icase(exclude + 1, basename + len - x->patternlen + 1)) return to_exclude; } else { if (fnmatch_icase(exclude, basename, 0) == 0) -- 1.8.0.rc2.11.g2b79d01 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 2/4] exclude: fix a bug in prefix compare optimization
When "namelen" becomes zero at this stage, we have matched the fixed part, but whether it actually matches the pattern still depends on the pattern in "exclude". As demonstrated in t3001, path "three/a.3" exists and it matches the "three/a.3" part in pattern "three/a.3[abc]", but that does not mean a true match. Don't be too optimistic and let fnmatch() do the job. Signed-off-by: Nguyễn Thái Ngọc Duy --- dir.c | 2 +- t/t3001-ls-files-others-exclude.sh | 6 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/dir.c b/dir.c index d81498e..0f4aea6 100644 --- a/dir.c +++ b/dir.c @@ -601,7 +601,7 @@ int excluded_from_list(const char *pathname, namelen -= prefix; } - if (!namelen || !fnmatch_icase(exclude, name, FNM_PATHNAME)) + if (!fnmatch_icase(exclude, name, FNM_PATHNAME)) return to_exclude; } return -1; /* undecided */ diff --git a/t/t3001-ls-files-others-exclude.sh b/t/t3001-ls-files-others-exclude.sh index c8fe978..dc2f045 100755 --- a/t/t3001-ls-files-others-exclude.sh +++ b/t/t3001-ls-files-others-exclude.sh @@ -214,4 +214,10 @@ test_expect_success 'subdirectory ignore (l1)' ' test_cmp expect actual ' +test_expect_success 'pattern matches prefix completely' ' + : >expect && + git ls-files -i -o --exclude "/three/a.3[abc]" >actual && + test_cmp expect actual +' + test_done -- 1.8.0.rc2.11.g2b79d01 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 3/4] exclude/attr: share basename matching code
match_basename's declaration in dir.h does not have any description to discourage the use of this function elsewhere as this function is highly tied to how excluded_from_list and path_matches work. Signed-off-by: Nguyễn Thái Ngọc Duy --- attr.c | 15 --- dir.c | 37 - dir.h | 2 ++ 3 files changed, 30 insertions(+), 24 deletions(-) diff --git a/attr.c b/attr.c index 0964033..a28ce0d 100644 --- a/attr.c +++ b/attr.c @@ -663,17 +663,10 @@ static int path_matches(const char *pathname, int pathlen, int namelen; if (pat->flags & EXC_FLAG_NODIR) { - if (prefix == pat->patternlen && - !strcmp_icase(pattern, basename)) - return 1; - - if (pat->flags & EXC_FLAG_ENDSWITH && - pat->patternlen - 1 <= pathlen && - !strcmp_icase(pattern + 1, pathname + - pathlen - pat->patternlen + 1)) - return 1; - - return (fnmatch_icase(pattern, basename, 0) == 0); + return match_basename(basename, + pathlen - (basename - pathname), + pattern, prefix, + pat->patternlen, pat->flags); } /* * match with FNM_PATHNAME; the pattern has base implicitly diff --git a/dir.c b/dir.c index 0f4aea6..42c42cd 100644 --- a/dir.c +++ b/dir.c @@ -530,6 +530,25 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen) dir->basebuf[baselen] = '\0'; } +int match_basename(const char *basename, int basenamelen, + const char *pattern, int prefix, int patternlen, + int flags) +{ + if (prefix == patternlen) { + if (!strcmp_icase(pattern, basename)) + return 1; + } else if (flags & EXC_FLAG_ENDSWITH) { + if (patternlen - 1 <= basenamelen && + !strcmp_icase(pattern + 1, + basename + basenamelen - patternlen + 1)) + return 1; + } else { + if (fnmatch_icase(pattern, basename, 0) == 0) + return 1; + } + return 0; +} + /* Scan the list and let the last match determine the fate. * Return 1 for exclude, 0 for include and -1 for undecided. */ @@ -556,19 +575,11 @@ int excluded_from_list(const char *pathname, } if (x->flags & EXC_FLAG_NODIR) { - /* match basename */ - if (prefix == x->patternlen) { - if (!strcmp_icase(exclude, basename)) - return to_exclude; - } else if (x->flags & EXC_FLAG_ENDSWITH) { - int len = pathlen - (basename - pathname); - if (x->patternlen - 1 <= len && - !strcmp_icase(exclude + 1, basename + len - x->patternlen + 1)) - return to_exclude; - } else { - if (fnmatch_icase(exclude, basename, 0) == 0) - return to_exclude; - } + if (match_basename(basename, + pathlen - (basename - pathname), + exclude, prefix, x->patternlen, + x->flags)) + return to_exclude; continue; } diff --git a/dir.h b/dir.h index fd5c2aa..d416c5a 100644 --- a/dir.h +++ b/dir.h @@ -78,6 +78,8 @@ extern int read_directory(struct dir_struct *, const char *path, int len, const extern int excluded_from_list(const char *pathname, int pathlen, const char *basename, int *dtype, struct exclude_list *el); +extern int match_basename(const char *, int, + const char *, int, int, int); struct dir_entry *dir_add_ignored(struct dir_struct *dir, const char *pathname, int len); /* -- 1.8.0.rc2.11.g2b79d01 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 4/4] exclude/attr: share full pathname matching code
match_pathname's declaration in dir.h does not have any description to discourage the use of this function elsewhere as this function is highly tied to how excluded_from_list and path_matches work. Signed-off-by: Nguyễn Thái Ngọc Duy --- attr.c | 35 +++ dir.c | 85 +- dir.h | 3 +++ 3 files changed, 59 insertions(+), 64 deletions(-) diff --git a/attr.c b/attr.c index a28ce0d..2fc6353 100644 --- a/attr.c +++ b/attr.c @@ -659,8 +659,6 @@ static int path_matches(const char *pathname, int pathlen, { const char *pattern = pat->pattern; int prefix = pat->nowildcardlen; - const char *name; - int namelen; if (pat->flags & EXC_FLAG_NODIR) { return match_basename(basename, @@ -668,36 +666,9 @@ static int path_matches(const char *pathname, int pathlen, pattern, prefix, pat->patternlen, pat->flags); } - /* -* match with FNM_PATHNAME; the pattern has base implicitly -* in front of it. -*/ - if (*pattern == '/') { - pattern++; - prefix--; - } - - /* -* note: unlike excluded_from_list, baselen here does not -* count the trailing slash, and base[] does not end with -* a trailing slash, either. -*/ - if (pathlen < baselen + 1 || - (baselen && pathname[baselen] != '/') || - strncmp_icase(pathname, base, baselen)) - return 0; - - namelen = baselen ? pathlen - baselen - 1 : pathlen; - name = pathname + pathlen - namelen; - - /* -* if the non-wildcard part is longer than the remaining -* pathname, surely it cannot match. -*/ - if (!namelen || prefix > namelen) - return 0; - - return fnmatch_icase(pattern, name, FNM_PATHNAME) == 0; + return match_pathname(pathname, pathlen, + base, baselen, + pattern, prefix, pat->patternlen, pat->flags); } static int macroexpand_one(int attr_nr, int rem); diff --git a/dir.c b/dir.c index 42c42cd..ee8e711 100644 --- a/dir.c +++ b/dir.c @@ -549,6 +549,53 @@ int match_basename(const char *basename, int basenamelen, return 0; } +int match_pathname(const char *pathname, int pathlen, + const char *base, int baselen, + const char *pattern, int prefix, int patternlen, + int flags) +{ + const char *name; + int namelen; + + /* +* match with FNM_PATHNAME; the pattern has base implicitly +* in front of it. +*/ + if (*pattern == '/') { + pattern++; + prefix--; + } + + /* +* baselen does not count the trailing slash. base[] may or +* may not end with a trailing slash though. +*/ + if (pathlen < baselen + 1 || + (baselen && pathname[baselen] != '/') || + strncmp_icase(pathname, base, baselen)) + return 0; + + namelen = baselen ? pathlen - baselen - 1 : pathlen; + name = pathname + pathlen - namelen; + + if (prefix) { + /* +* if the non-wildcard part is longer than the +* remaining pathname, surely it cannot match. +*/ + if (prefix > namelen) + return 0; + + if (strncmp_icase(pattern, name, prefix)) + return 0; + pattern += prefix; + name+= prefix; + namelen -= prefix; + } + + return fnmatch_icase(pattern, name, FNM_PATHNAME) == 0; +} + /* Scan the list and let the last match determine the fate. * Return 1 for exclude, 0 for include and -1 for undecided. */ @@ -563,9 +610,9 @@ int excluded_from_list(const char *pathname, for (i = el->nr - 1; 0 <= i; i--) { struct exclude *x = el->excludes[i]; - const char *name, *exclude = x->pattern; + const char *exclude = x->pattern; int to_exclude = x->flags & EXC_FLAG_NEGATIVE ? 0 : 1; - int namelen, prefix = x->nowildcardlen; + int prefix = x->nowildcardlen; if (x->flags & EXC_FLAG_MUSTBEDIR) { if (*dtype == DT_UNKNOWN) @@ -583,36 +630,10 @@ int excluded_from_list(const char *pathname, continue; } - /* match with FNM_PATHNAME: -* exclude has base (baselen long) implicitly in front of it. -*/ - if (*exclude == '/') { - exclude++; - prefix--; - } - - if (pathlen < x->baselen || - (x->baselen && pathname[x->baselen-1] !
Re: [PATCH v5 02/12] ctype: support iscntrl, ispunct, isxdigit and isprint
Am 14.10.2012 04:35, schrieb Nguyễn Thái Ngọc Duy: Signed-off-by: Nguyễn Thái Ngọc Duy --- ctype.c | 18 ++ git-compat-util.h | 13 + 2 files changed, 31 insertions(+) diff --git a/ctype.c b/ctype.c index faeaf34..b4bf48a 100644 --- a/ctype.c +++ b/ctype.c @@ -26,6 +26,24 @@ const unsigned char sane_ctype[256] = { /* Nothing in the 128.. range */ }; +enum { + CN = GIT_CNTRL, + PU = GIT_PUNCT, + XD = GIT_XDIGIT, +}; + +const unsigned char sane_ctype2[256] = { + CN, CN, CN, CN, CN, CN, CN, CN, CN, CN, CN, CN, CN, CN, CN, CN, /* 0..15 */ + CN, CN, CN, CN, CN, CN, CN, CN, CN, CN, CN, CN, CN, CN, CN, CN, /* 16..31 */ + 0, PU, PU, PU, PU, PU, PU, PU, PU, PU, PU, PU, PU, PU, PU, PU, /* 32..47 */ + XD, XD, XD, XD, XD, XD, XD, XD, XD, XD, PU, PU, PU, PU, PU, PU, /* 48..63 */ + PU, 0, XD, 0, XD, 0, XD, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 64..79 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, PU, PU, PU, PU, PU, /* 80..95 */ + PU, 0, XD, 0, XD, 0, XD, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 96..111 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, PU, PU, PU, PU, CN, /* 112..127 */ Shouldn't [ace] (65, 67, 69) and [ACE] (97, 99, 101) be xdigits as well? But how about using the existing hexval_table instead, like this: #define isxdigit(x) (hexval_table[(x)] != -1) With that, couldn't you squeeze the other two classes into the existing sane_type? By the way, I'm working on a patch series for implementing a lot more character classes with table lookups. It grew out of a desire to make bad_ref_char() faster but perhaps got a bit out of hand by now; it's at 24 patches and still not finished. I'm curious how long we have until it escapes. ;-) #define is_regex_special(x) sane_istest(x,GIT_GLOB_SPECIAL | GIT_REGEX_SPECIAL) +#define iscntrl(x) sane_istest2(x, GIT_CNTRL) +#define ispunct(x) sane_istest2(x, GIT_PUNCT) +#define isxdigit(x) sane_istest2(x, GIT_XDIGIT) +#define isprint(x) (isalnum(x) || isspace(x) || ispunct(x)) If a single table is used, you can do with a single table lookup by adding the bits for the component classes, like isalnum and is_regex_special do. René -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v5 02/12] ctype: support iscntrl, ispunct, isxdigit and isprint
On Sun, Oct 14, 2012 at 7:59 PM, René Scharfe wrote: >> +const unsigned char sane_ctype2[256] = { >> + CN, CN, CN, CN, CN, CN, CN, CN, CN, CN, CN, CN, CN, CN, CN, CN, /* >> 0..15 */ >> + CN, CN, CN, CN, CN, CN, CN, CN, CN, CN, CN, CN, CN, CN, CN, CN, /* >> 16..31 */ >> + 0, PU, PU, PU, PU, PU, PU, PU, PU, PU, PU, PU, PU, PU, PU, PU, /* >> 32..47 */ >> + XD, XD, XD, XD, XD, XD, XD, XD, XD, XD, PU, PU, PU, PU, PU, PU, /* >> 48..63 */ >> + PU, 0, XD, 0, XD, 0, XD, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* >> 64..79 */ >> + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, PU, PU, PU, PU, PU, /* >> 80..95 */ >> + PU, 0, XD, 0, XD, 0, XD, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* >> 96..111 */ >> + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, PU, PU, PU, PU, CN, /* >> 112..127 */ > > > Shouldn't [ace] (65, 67, 69) and [ACE] (97, 99, 101) be xdigits as well? Hmm.. I generated it from LANG=C. I wonder where I got it wrong.. > But how about using the existing hexval_table instead, like this: > > #define isxdigit(x) (hexval_table[(x)] != -1) > > With that, couldn't you squeeze the other two classes into the existing > sane_type? No there are still conflicts: 9, 10 and 13 as spaces (vs controls) and 123, 124 and 126 as regex/pathspec special (vs punctuation). > By the way, I'm working on a patch series for implementing a lot more > character classes with table lookups. It grew out of a desire to make > bad_ref_char() faster but perhaps got a bit out of hand by now; it's at 24 > patches and still not finished. I'm curious how long we have until it > escapes. ;-) I don't think the series is going to graduate any time soon :) -- Duy -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: A design for subrepositories
Am 14.10.2012 12:19, schrieb Lauri Alanko: > Quoting "Junio C Hamano" : > >>> If the >>> submodules ever get reorganized and foo is moved to ./bar, then it is >>> impossible to check out older versions or alternate branches, since >>> the submodule is no longer where it is expected to be at the origin. >> >> Isn't that exactly what the "module name" vs "module path" mapping >> in .gitmodules file is meant to address? > > Yes, and as I showed after the part you quoted, it is possible to refer to a > module by name, although it looks like such a hack that I can't imagine it's > currently something that git-submodule is intended to support. Your initial statement is not correct. It is possible to check out older versions or alternate branches (at least since we moved the .git directory into the .git directory of the superproject). So no improvement gained here by your proposal (although I concede that the current user experience is suboptimal until my recursive submodule update work hits mainline). >>> But still, "git submodule update" only looks at the modules in the >>> currently checked-out tree. If we have other branches or old tags that >>> refer to other submodules, there's no simple way to fetch those, too. Did you notice that "git fetch" fetches all those submodules too which have been updated in the commits fetched for the superproject, no matter on what branch they are on? >> Didn't I already suggest you to think about how you can improve >> existing "git submodule" to suit your use case better? > > Yes, and I listed three possible ways. Two of them seem technically > unattractive, whereas one of them (submodules as ref directories) seems like > a huge change that could introduce incompatibilities. That is why a separate > tool seems like a cleaner choice. What's wrong with making git clone all submodules together with the superproject (when the user said he wants to update all submodules on clone too by setting a - still to be added - config option)? That's my plan to make automagic recursive submodule cloning work and it would clone all submodules seen in the history of the superproject to .git/modules so they could easily be checked out later (and those present in the HEAD of the superproject will be checked out immediately like "git clone --recurse-submodules" does right now). Were not there yet, but that's how I believe that should work. > There is actually a fourth alternative: extend the git protocol so that a > remote repository could be queried for its list of submodules. That information is contained in the different versions of the .gitmodules file, so no need to extend anything here. I saw nothing in your proposal which couldn't been handled by submodules, and for every issue there already have been proposals on how to do that. So adding another tool doesn't make any sense here. But you are welcome helping us to improve the submodule script (and some core commands too) to make submodules cover your use case too. -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
fixes of previous commit
--- > Hi Ralf > Hi Thomas, thanks for your work! All your suggestions are very good. > I just realized that, unfortunately, your original message is far beyond > the message size limit on vger (10 bytes according to [1]). So > nobody outside of the Cc list has seen it... > Oops, I didn't notice that and can't remember of a hint from vger. Next time I'll check the mailing list whether the mail is there. >> +msgstr "kopiert Dateien von einer benannten Bereitstellung" > > "Stage" in this context means the 0/1/2/3 thing where unmerged entries > differ from normal entries. Thank the Git gods for overloading yet > another term heavily. > > We don't have a translation for "stage" in the glossary. The best I can > come up with is "Stufe", but if you can find something that evokes the > mental image of the "sides" of a merge, that would be better IMO. What about "Stand"? >> +msgstr "checkt ihre Version für nicht zusammengeführte Dateien aus" > > You're translating 'our/their version' -> unsere/ihre Version. Taken > just by itself I think it would be okay or at worst mildly confusing > (how about "unsere/ihre Seite [der Zusammenführung]"?). > > However, in the wider context it is actually dangerous, because you are > overloading the (German) Version here. It already means 'commit'! > I've changed it to "Variante", what do you think? > entfernt -> gelöscht avoids the ambiguity with the whole remote > branch/repo business. > Thanks, I've changed also other messages this way. >> #: builtin/fast-export.c:643 >> msgid "Dump marks to this file" >> -msgstr "" >> +msgstr "Anzeige von Kennzeichen für diese Datei" > [...] >> #: builtin/fast-export.c:645 >> msgid "Import marks from this file" >> -msgstr "" >> +msgstr "Importiert Kennzeichen von dieser Datei" > > How did you manage to nail the second one, but get the first one wrong? > :-) Gaahh, how embarrassing :) po/de.po | 157 +++ 1 file changed, 78 insertions(+), 79 deletions(-) diff --git a/po/de.po b/po/de.po index 9ffe4f2..796ada1 100644 --- a/po/de.po +++ b/po/de.po @@ -50,12 +50,12 @@ msgstr "git archive --list" msgid "" "git archive --remote [--exec ] [options] [...]" msgstr "" -"git archive --remote [--exec ] [Optionen] " +"git archive --remote [--exec ] [Optionen] " " [Pfad...]" #: archive.c:13 msgid "git archive --remote [--exec ] --list" -msgstr "git archive --remote [--exec ] --list" +msgstr "git archive --remote [--exec ] --list" #: archive.c:322 msgid "fmt" @@ -63,7 +63,7 @@ msgstr "Format" #: archive.c:322 msgid "archive format" -msgstr "Archivformat" +msgstr "Ausgabeformat" #: archive.c:323 builtin/log.c:1079 msgid "prefix" @@ -71,7 +71,7 @@ msgstr "Prefix" #: archive.c:324 msgid "prepend prefix to each pathname in the archive" -msgstr "stellt einen Prefix vor jeden Pfadnamen in dem Archiv" +msgstr "stellt einen Präfix vor jeden Pfadnamen in der Ausgabe" #: archive.c:325 builtin/archive.c:91 builtin/blame.c:2332 #: builtin/blame.c:2333 builtin/config.c:56 builtin/fast-export.c:642 @@ -83,7 +83,7 @@ msgstr "Datei" #: archive.c:326 builtin/archive.c:92 msgid "write the archive to this file" -msgstr "schreibt das Archiv in diese Datei" +msgstr "schreibt die Ausgabe in diese Datei" #: archive.c:328 msgid "read .gitattributes in working directory" @@ -107,7 +107,7 @@ msgstr "besser komprimieren" #: archive.c:342 msgid "list supported archive formats" -msgstr "listet unterstützte Archivformate auf" +msgstr "listet unterstützte Ausgabeformate auf" #: archive.c:344 builtin/archive.c:93 builtin/clone.c:85 msgid "repo" @@ -119,11 +119,11 @@ msgstr "ruft das Archiv von externem Projektarchiv ab" #: archive.c:346 builtin/archive.c:95 builtin/notes.c:616 msgid "command" -msgstr "Kommando" +msgstr "Programm" #: archive.c:347 builtin/archive.c:96 msgid "path to the remote git-upload-archive command" -msgstr "Pfad zum externen \"git-upload-archive\" Kommando" +msgstr "Pfad zum externen \"git-upload-archive\"-Programm" #: bundle.c:36 #, c-format @@ -1346,25 +1346,25 @@ msgstr "nichts zum Eintragen hinzugefügt, aber es gibt unbeobachtete Dateien\n" #, c-format msgid "nothing to commit (create/copy files and use \"git add\" to track)\n" msgstr "" -"nichts zum Eintragen (Erstelle/Kopiere Dateien und benutze \"git add\" zum " +"nichts einzutragen (Erstelle/Kopiere Dateien und benutze \"git add\" zum " "Beobachten)\n" #: wt-status.c:1043 wt-status.c:1048 #, c-format msgid "nothing to commit\n" -msgstr "nichts zum Eintragen\n" +msgstr "nichts einzutragen\n" #: wt-status.c:1046 #, c-format msgid "nothing to commit (use -u to show untracked files)\n" msgstr "" -"nichts zum Eintragen (benutze die Option -u, um unbeobachtete Dateien " +"nichts einzutragen (benutze die Option -u, um unbeobachtete Dateien " "anzuzeigen)\n" #: wt-status.c:1050 #, c-format msgid "nothing to commit, working directory clean\n" -msgst
Re: [PATCH v5 02/12] ctype: support iscntrl, ispunct, isxdigit and isprint
Am 14.10.2012 15:25, schrieb Nguyen Thai Ngoc Duy: On Sun, Oct 14, 2012 at 7:59 PM, René Scharfe wrote: With that, couldn't you squeeze the other two classes into the existing sane_type? No there are still conflicts: 9, 10 and 13 as spaces (vs controls) and 123, 124 and 126 as regex/pathspec special (vs punctuation). That's not a problem, an entry in the table can have more than one bit set -- just OR them together in ctype.c. It may not look as nice, but that's OK. You could also define a character for GIT_SPACE | GIT_CNTRL etc. for cosmetic reasons. René -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v5 02/12] ctype: support iscntrl, ispunct, isxdigit and isprint
On Sun, Oct 14, 2012 at 03:59:31PM +0200, René Scharfe wrote: > Am 14.10.2012 15:25, schrieb Nguyen Thai Ngoc Duy: > > On Sun, Oct 14, 2012 at 7:59 PM, René Scharfe > > wrote: > >> With that, couldn't you squeeze the other two classes into the existing > >> sane_type? > > > > No there are still conflicts: 9, 10 and 13 as spaces (vs controls) and > > 123, 124 and 126 as regex/pathspec special (vs punctuation). > > That's not a problem, an entry in the table can have more than one bit > set -- just OR them together in ctype.c. It may not look as nice, but > that's OK. You could also define a character for GIT_SPACE | GIT_CNTRL > etc. for cosmetic reasons. Only space chars is not a subset of control chars, which needs a new combination. So the result does not look as bad as I thought: -- 8< -- diff --git a/ctype.c b/ctype.c index faeaf34..0bfebb4 100644 --- a/ctype.c +++ b/ctype.c @@ -11,18 +11,21 @@ enum { D = GIT_DIGIT, G = GIT_GLOB_SPECIAL, /* *, ?, [, \\ */ R = GIT_REGEX_SPECIAL, /* $, (, ), +, ., ^, {, | */ - P = GIT_PATHSPEC_MAGIC /* other non-alnum, except for ] and } */ + P = GIT_PATHSPEC_MAGIC, /* other non-alnum, except for ] and } */ + X = GIT_CNTRL, + U = GIT_PUNCT, + Z = GIT_CNTRL | GIT_SPACE }; const unsigned char sane_ctype[256] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, S, S, 0, 0, S, 0, 0, /* 0.. 15 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16.. 31 */ + X, X, X, X, X, X, X, X, X, Z, Z, X, X, Z, X, X, /* 0.. 15 */ + X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, /* 16.. 31 */ S, P, P, P, R, P, P, P, R, R, G, R, P, P, R, P, /* 32.. 47 */ D, D, D, D, D, D, D, D, D, D, P, P, P, P, P, G, /* 48.. 63 */ P, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, /* 64.. 79 */ - A, A, A, A, A, A, A, A, A, A, A, G, G, 0, R, P, /* 80.. 95 */ + A, A, A, A, A, A, A, A, A, A, A, G, G, U, R, P, /* 80.. 95 */ P, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, /* 96..111 */ - A, A, A, A, A, A, A, A, A, A, A, R, R, 0, P, 0, /* 112..127 */ + A, A, A, A, A, A, A, A, A, A, A, R, R, U, P, X, /* 112..127 */ /* Nothing in the 128.. range */ }; diff --git a/git-compat-util.h b/git-compat-util.h index f8b859c..db77f3e 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -510,6 +510,10 @@ extern const char tolower_trans_tbl[256]; #undef isupper #undef tolower #undef toupper +#undef iscntrl +#undef ispunct +#undef isxdigit +#undef isprint extern const unsigned char sane_ctype[256]; #define GIT_SPACE 0x01 #define GIT_DIGIT 0x02 @@ -517,6 +521,8 @@ extern const unsigned char sane_ctype[256]; #define GIT_GLOB_SPECIAL 0x08 #define GIT_REGEX_SPECIAL 0x10 #define GIT_PATHSPEC_MAGIC 0x20 +#define GIT_CNTRL 0x40 +#define GIT_PUNCT 0x80 #define sane_istest(x,mask) ((sane_ctype[(unsigned char)(x)] & (mask)) != 0) #define isascii(x) (((x) & ~0x7f) == 0) #define isspace(x) sane_istest(x,GIT_SPACE) @@ -527,6 +533,13 @@ extern const unsigned char sane_ctype[256]; #define isupper(x) sane_iscase(x, 0) #define is_glob_special(x) sane_istest(x,GIT_GLOB_SPECIAL) #define is_regex_special(x) sane_istest(x,GIT_GLOB_SPECIAL | GIT_REGEX_SPECIAL) +#define iscntrl(x) (sane_istest(x,GIT_CNTRL)) +#define ispunct(x) sane_istest(x, GIT_PUNCT | GIT_REGEX_SPECIAL | \ + GIT_GLOB_SPECIAL | GIT_PATHSPEC_MAGIC) +#define isxdigit(x) (hexval_table[x] != -1) +#define isprint(x) (sane_istest(x, GIT_ALPHA | GIT_DIGIT | GIT_SPACE | \ + GIT_PUNCT | GIT_REGEX_SPECIAL | GIT_GLOB_SPECIAL | \ + GIT_PATHSPEC_MAGIC)) #define tolower(x) sane_case((unsigned char)(x), 0x20) #define toupper(x) sane_case((unsigned char)(x), 0) #define is_pathspec_magic(x) sane_istest(x,GIT_PATHSPEC_MAGIC) -- 8< -- -- Duy -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: A design for subrepositories
Quoting "Jens Lehmann" : If the submodules ever get reorganized and foo is moved to ./bar, then it is impossible to check out older versions or alternate branches, since the submodule is no longer where it is expected to be at the origin. Your initial statement is not correct. Please elaborate. My initial statement was about "git submodule add ./foo", and this is what I get: la@bq:~/tmp$ git --version git version 1.8.0.rc2.2.gfc364c7 la@bq:~/tmp$ git init super Initialized empty Git repository in /home/la/tmp/super/.git/ la@bq:~/tmp$ cd super la@bq:~/tmp/super$ echo foo > foo la@bq:~/tmp/super$ git add foo la@bq:~/tmp/super$ git ci -m foo [master (root-commit) a0dd543] foo 1 file changed, 1 insertion(+) create mode 100644 foo la@bq:~/tmp/super$ git init sub Initialized empty Git repository in /home/la/tmp/super/sub/.git/ la@bq:~/tmp/super$ cd sub la@bq:~/tmp/super/sub$ echo bar > bar la@bq:~/tmp/super/sub$ git add bar la@bq:~/tmp/super/sub$ git ci -m bar [master (root-commit) a6ee6d6] bar 1 file changed, 1 insertion(+) create mode 100644 bar la@bq:~/tmp/super/sub$ cd .. la@bq:~/tmp/super$ git submodule add ./sub Adding existing repo at 'sub' to the index la@bq:~/tmp/super$ git ci -m sub [master cb289e8] sub 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 16 sub la@bq:~/tmp/super$ git branch old la@bq:~/tmp/super$ git mv sub movedsub fatal: source directory is empty, source=sub, destination=movedsub la@bq:~/tmp/super$ mv sub movedsub la@bq:~/tmp/super$ git rm sub rm 'sub' la@bq:~/tmp/super$ git add movedsub la@bq:~/tmp/super$ git config -f .gitmodules submodule.sub.path movedsub la@bq:~/tmp/super$ git config -f .gitmodules submodule.sub.url ./movedsub la@bq:~/tmp/super$ git ci -am movedsub [master 5598bc0] movedsub 2 files changed, 2 insertions(+), 2 deletions(-) rename sub => movedsub (100%) la@bq:~/tmp/super$ cd .. la@bq:~/tmp$ git clone super superc Cloning into 'superc'... done. la@bq:~/tmp$ cd superc la@bq:~/tmp/superc$ git co old Branch old set up to track remote branch old from origin. Switched to a new branch 'old' la@bq:~/tmp/superc$ git submodule update --init Submodule 'sub' (/home/la/tmp/super/sub) registered for path 'sub' fatal: repository '/home/la/tmp/super/sub' does not exist Clone of '/home/la/tmp/super/sub' into submodule path 'sub' failed So a normal relative path in .gitmodules to inside the tree is fragile, since the location of the submodule can change. Did you notice that "git fetch" fetches all those submodules too which have been updated in the commits fetched for the superproject, no matter on what branch they are on? No. This would be great, but this is what I get: la@bq:~/tmp$ git init super Initialized empty Git repository in /home/la/tmp/super/.git/ la@bq:~/tmp$ cd super la@bq:~/tmp/super$ echo foo > foo la@bq:~/tmp/super$ git add foo la@bq:~/tmp/super$ git ci -m foo [master (root-commit) 0f207c9] foo 1 file changed, 1 insertion(+) create mode 100644 foo la@bq:~/tmp/super$ git branch nosubs la@bq:~/tmp/super$ git init sub Initialized empty Git repository in /home/la/tmp/super/sub/.git/ la@bq:~/tmp/super$ cd sub la@bq:~/tmp/super/sub$ echo bar > bar la@bq:~/tmp/super/sub$ git add bar la@bq:~/tmp/super/sub$ git ci -m bar [master (root-commit) 180c6c9] bar 1 file changed, 1 insertion(+) create mode 100644 bar la@bq:~/tmp/super/sub$ cd .. la@bq:~/tmp/super$ git submodule add ./sub Adding existing repo at 'sub' to the index la@bq:~/tmp/super$ git ci -m sub [master 16cff18] sub 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 16 sub la@bq:~/tmp/super$ cd .. la@bq:~/tmp$ git clone super superc Cloning into 'superc'... done. la@bq:~/tmp$ cd superc la@bq:~/tmp/superc$ git submodule update --init Submodule 'sub' (/home/la/tmp/super/sub) registered for path 'sub' Cloning into 'sub'... done. Submodule path 'sub': checked out '180c6c979289f4e25525003673e51d0e39dab8f6' la@bq:~/tmp/superc$ cd ../super/sub la@bq:~/tmp/super/sub$ echo baz >> bar la@bq:~/tmp/super/sub$ git ci -am baz [master 652c8b3] baz 1 file changed, 1 insertion(+) la@bq:~/tmp/super/sub$ cd .. la@bq:~/tmp/super$ git ci -am subbaz [master c7c3bfc] subbaz 1 file changed, 1 insertion(+), 1 deletion(-) la@bq:~/tmp/super$ cd ../superc la@bq:~/tmp/superc$ git co nosubs warning: unable to rmdir sub: Directory not empty Branch nosubs set up to track remote branch nosubs from origin. Switched to a new branch 'nosubs' la@bq:~/tmp/superc$ git fetch --recurse-submodules=yes remote: Counting objects: 3, done. remote: Compressing objects: 100% (2/2), done. remote: Total 2 (delta 1), reused 0 (delta 0) Unpacking objects: 100% (2/2), done. From /home/la/tmp/super 16cff18..c7c3bfc master -> origin/master la@bq:~/tmp/superc$ git co master Switched to branch 'master' Your branch is behind 'origin/master' by 1 commit, and can be fast-forwarded. la@bq:~/tmp/superc$ git fetch --recurse-submodules=yes Fetching submodule sub remote: Countin
[PATCH v5 0/3] completion: refactor and zsh wrapper
Hi, Here's a bit of reorganition. I'm introducing a new __gitcompadd helper that is useful to wrapp all changes to COMPREPLY. 2nd and 3rd patches show how it's useful. The zsh wrapper is now very very simple, but I haven't received much feedback yet. I hope it will get in at some point in time. Felipe Contreras (3): completion: add new __gitcompadd helper tests: use __gitcompadd to simplify completion tests completion: add new zsh completion contrib/completion/git-completion.bash | 65 ++ contrib/completion/git-completion.zsh | 48 + t/t9902-completion.sh | 29 +-- 3 files changed, 91 insertions(+), 51 deletions(-) create mode 100644 contrib/completion/git-completion.zsh -- 1.7.12.1 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v5 1/3] completion: add new __gitcompadd helper
The idea is to never touch the COMPREPLY variable directly. This allows other completion systems override __gitcompadd, and do something different instead. Also, this allows the simplifcation of the completino tests (separate patch). There should be no functional changes. Signed-off-by: Felipe Contreras --- contrib/completion/git-completion.bash | 65 ++ 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index d743e56..01325de 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -225,6 +225,11 @@ _get_comp_words_by_ref () fi fi +__gitcompadd () +{ + COMPREPLY=($(compgen -W "$1" -P "$2" -S "$4" -- "$3")) +} + # Generates completion reply with compgen, appending a space to possible # completion words, if necessary. # It accepts 1 to 4 arguments: @@ -238,13 +243,11 @@ __gitcomp () case "$cur_" in --*=) - COMPREPLY=() + __gitcompadd ;; *) local IFS=$'\n' - COMPREPLY=($(compgen -P "${2-}" \ - -W "$(__gitcomp_1 "${1-}" "${4-}")" \ - -- "$cur_")) + __gitcompadd "$(__gitcomp_1 "${1-}" "${4-}")" "${2-}" "$cur_" "" ;; esac } @@ -261,7 +264,7 @@ __gitcomp () __gitcomp_nl () { local IFS=$'\n' - COMPREPLY=($(compgen -P "${2-}" -S "${4- }" -W "$1" -- "${3-$cur}")) + __gitcompadd "$1" "${2-}" "${3-$cur}" "${4- }" } __git_heads () @@ -486,7 +489,7 @@ __git_complete_remote_or_refspec () case "$cmd" in push) no_complete_refspec=1 ;; fetch) - COMPREPLY=() + __gitcompadd return ;; *) ;; @@ -502,7 +505,7 @@ __git_complete_remote_or_refspec () return fi if [ $no_complete_refspec = 1 ]; then - COMPREPLY=() + __gitcompadd return fi [ "$remote" = "." ] && remote= @@ -776,7 +779,7 @@ _git_am () " return esac - COMPREPLY=() + __gitcompadd } _git_apply () @@ -796,7 +799,7 @@ _git_apply () " return esac - COMPREPLY=() + __gitcompadd } _git_add () @@ -811,7 +814,7 @@ _git_add () " return esac - COMPREPLY=() + __gitcompadd } _git_archive () @@ -856,7 +859,7 @@ _git_bisect () __gitcomp_nl "$(__git_refs)" ;; *) - COMPREPLY=() + __gitcompadd ;; esac } @@ -965,7 +968,7 @@ _git_clean () return ;; esac - COMPREPLY=() + __gitcompadd } _git_clone () @@ -989,7 +992,7 @@ _git_clone () return ;; esac - COMPREPLY=() + __gitcompadd } _git_commit () @@ -1023,7 +1026,7 @@ _git_commit () " return esac - COMPREPLY=() + __gitcompadd } _git_describe () @@ -1154,7 +1157,7 @@ _git_fsck () return ;; esac - COMPREPLY=() + __gitcompadd } _git_gc () @@ -1165,7 +1168,7 @@ _git_gc () return ;; esac - COMPREPLY=() + __gitcompadd } _git_gitk () @@ -1242,7 +1245,7 @@ _git_init () return ;; esac - COMPREPLY=() + __gitcompadd } _git_ls_files () @@ -1261,7 +1264,7 @@ _git_ls_files () return ;; esac - COMPREPLY=() + __gitcompadd } _git_ls_remote () @@ -1377,7 +1380,7 @@ _git_mergetool () return ;; esac - COMPREPLY=() + __gitcompadd } _git_merge_base () @@ -1393,7 +1396,7 @@ _git_mv () return ;; esac - COMPREPLY=() + __gitcompadd } _git_name_rev () @@ -1563,7 +1566,7 @@ _git_send_email () return ;; esac - COMPREPLY=() + __gitcompadd } _git_stage () @@ -1616,7 +1619,7 @@ _git_config () local remote="${prev#remote.}" remote="${remote%.fetch}" if [ -z "$cur" ]; then - COMPREPLY=("refs/heads/") + __gitcompadd "refs/heads/" return fi __gitcomp_nl "$(__git_refs_remotes "$remote")" @@ -1676,7 +1679,7 @@ _git_config () return ;; *.*) - COMPREPLY
[PATCH v5 2/3] tests: use __gitcompadd to simplify completion tests
Signed-off-by: Felipe Contreras --- t/t9902-completion.sh | 29 + 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index 92d7eb4..49c6eb4 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -39,19 +39,18 @@ _get_comp_words_by_ref () done } -print_comp () +__gitcompadd () { - local IFS=$'\n' - echo "${COMPREPLY[*]}" > out + compgen -P "${2-}" -S "${4- }" -W "$1" -- "${3-$cur}" > out } run_completion () { - local -a COMPREPLY _words + local -a _words local _cword _words=( $1 ) (( _cword = ${#_words[@]} - 1 )) - __git_wrap__git_main && print_comp + __git_wrap__git_main } test_completion () @@ -70,12 +69,10 @@ test_expect_success '__gitcomp - trailing space - options' ' --reset-author Z EOF ( - local -a COMPREPLY && cur="--re" && __gitcomp "--dry-run --reuse-message= --reedit-message= --reset-author" && - IFS="$newline" && - echo "${COMPREPLY[*]}" > out + IFS="$newline" ) && test_cmp expected out ' @@ -88,12 +85,10 @@ test_expect_success '__gitcomp - trailing space - config keys' ' browser.Z EOF ( - local -a COMPREPLY && cur="br" && __gitcomp "branch. branch.autosetupmerge branch.autosetuprebase browser." && - IFS="$newline" && - echo "${COMPREPLY[*]}" > out + IFS="$newline" ) && test_cmp expected out ' @@ -104,12 +99,10 @@ test_expect_success '__gitcomp - option parameter' ' resolve Z EOF ( - local -a COMPREPLY && cur="--strategy=re" && __gitcomp "octopus ours recursive resolve subtree " "" "re" && - IFS="$newline" && - echo "${COMPREPLY[*]}" > out + IFS="$newline" ) && test_cmp expected out ' @@ -120,12 +113,10 @@ test_expect_success '__gitcomp - prefix' ' branch.maint.mergeoptions Z EOF ( - local -a COMPREPLY && cur="branch.me" && __gitcomp "remote merge mergeoptions rebase " "branch.maint." "me" && - IFS="$newline" && - echo "${COMPREPLY[*]}" > out + IFS="$newline" ) && test_cmp expected out ' @@ -136,12 +127,10 @@ test_expect_success '__gitcomp - suffix' ' branch.maint.Z EOF ( - local -a COMPREPLY && cur="branch.me" && __gitcomp "master maint next pu " "branch." "ma" "." && - IFS="$newline" && - echo "${COMPREPLY[*]}" > out + IFS="$newline" ) && test_cmp expected out ' -- 1.7.12.1 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v5 3/3] completion: add new zsh completion
It seems there's always issues with zsh's bash completion emulation. I've tried to fix as many as I could and most of the fixes are already in the latest version of zsh, but still, there are issues. There is no point in going through all that pain; the emulation is easy to achieve, and this patch works better than zsh's emulation. Signed-off-by: Felipe Contreras --- v5: * Even more simplification by using __gitcompadd v4: * Simplification updates for the latest bash completion v3: * Simplification * Avoid COMPREPLY; call compadd directly * Fix _get_comp_words_by_ref contrib/completion/git-completion.zsh | 48 +++ 1 file changed, 48 insertions(+) create mode 100644 contrib/completion/git-completion.zsh diff --git a/contrib/completion/git-completion.zsh b/contrib/completion/git-completion.zsh new file mode 100644 index 000..dbb5261 --- /dev/null +++ b/contrib/completion/git-completion.zsh @@ -0,0 +1,48 @@ +#compdef git gitk + +# zsh completion wrapper for git +# +# You need git's bash completion script installed somewhere, by default on the +# same directory as this script. +# +# If your script is on ~/.git-completion.sh instead, you can configure it on +# your ~/.zshrc: +# +# zstyle ':completion:*:*:git:*' script ~/.git-completion.sh +# +# The recommended way to install this script is to copy to +# '~/.zsh/completion/_git', and then add the following to your ~/.zshrc file: +# +# fpath=(~/.zsh/completion $fpath) + +complete () +{ + # do nothing + return 0 +} + +zstyle -s ":completion:*:*:git:*" script script +test -z "$script" && script="$(dirname ${funcsourcetrace[1]%:*})"/git-completion.bash +ZSH_VERSION='' . "$script" + +__gitcompadd () +{ + compadd -Q -S "$4" -P "$2" -p "${(M)cur#*[=:]}" -- ${=1} && _ret=0 +} + +_git () +{ + local _ret=1 + () { + emulate -L ksh + local cur cword prev + cur=${words[CURRENT-1]} + prev=${words[CURRENT-2]} + let cword=CURRENT-1 + __${service}_main + } + let _ret && _default -S '' && _ret=0 + return _ret +} + +_git -- 1.7.12.1 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: A design for subrepositories
Am 14.10.2012 17:27, schrieb Lauri Alanko: > Quoting "Jens Lehmann" : > > If the > submodules ever get reorganized and foo is moved to ./bar, then it is > impossible to check out older versions or alternate branches, since > the submodule is no longer where it is expected to be at the origin. > >> Your initial statement is not correct. > > Please elaborate. My initial statement was about "git submodule add ./foo", > and this is what I get: > > la@bq:~/tmp$ git --version > git version 1.8.0.rc2.2.gfc364c7 > la@bq:~/tmp$ git init super > Initialized empty Git repository in /home/la/tmp/super/.git/ > la@bq:~/tmp$ cd super > la@bq:~/tmp/super$ echo foo > foo > la@bq:~/tmp/super$ git add foo > la@bq:~/tmp/super$ git ci -m foo > [master (root-commit) a0dd543] foo > 1 file changed, 1 insertion(+) > create mode 100644 foo > la@bq:~/tmp/super$ git init sub > Initialized empty Git repository in /home/la/tmp/super/sub/.git/ > la@bq:~/tmp/super$ cd sub > la@bq:~/tmp/super/sub$ echo bar > bar > la@bq:~/tmp/super/sub$ git add bar > la@bq:~/tmp/super/sub$ git ci -m bar > [master (root-commit) a6ee6d6] bar > 1 file changed, 1 insertion(+) > create mode 100644 bar > la@bq:~/tmp/super/sub$ cd .. > la@bq:~/tmp/super$ git submodule add ./sub > Adding existing repo at 'sub' to the index > la@bq:~/tmp/super$ git ci -m sub > [master cb289e8] sub > 2 files changed, 4 insertions(+) > create mode 100644 .gitmodules > create mode 16 sub > la@bq:~/tmp/super$ git branch old > la@bq:~/tmp/super$ git mv sub movedsub > fatal: source directory is empty, source=sub, destination=movedsub This error here indicates that we didn't teach git to properly move a submodule yet. It is one of my next goals to make "git [submodule] mv sub movedsub" do the right thing here. To do these steps manually you'll additionally have to do the following before moving the submodule (because after moving it the relative paths will be broken): $ HASH=$(cd sub; git rev-parse HEAD) > la@bq:~/tmp/super$ mv sub movedsub Currently it is better to remove the submodule here, as recreating it with a "git submodule update" later will get the relative paths right. > la@bq:~/tmp/super$ git rm sub > rm 'sub' > la@bq:~/tmp/super$ git add movedsub And to git this adds a completely different submodule (as its name is not "sub"), which breaks your expectation. To do what you intended use this line instead: $ git update-index --add --cacheinfo 16 $HASH movedsub (With the "--next" option currently in the "next" branch of Junio's repo a "git submodule add --name sub movedsub" should do the job. Until then a bit more magic is necessary). > la@bq:~/tmp/super$ git config -f .gitmodules submodule.sub.path movedsub > la@bq:~/tmp/super$ git config -f .gitmodules submodule.sub.url ./movedsub > la@bq:~/tmp/super$ git ci -am movedsub > [master 5598bc0] movedsub > 2 files changed, 2 insertions(+), 2 deletions(-) > rename sub => movedsub (100%) > la@bq:~/tmp/super$ cd .. > la@bq:~/tmp$ git clone super superc > Cloning into 'superc'... > done. > la@bq:~/tmp$ cd superc > la@bq:~/tmp/superc$ git co old > Branch old set up to track remote branch old from origin. > Switched to a new branch 'old' > la@bq:~/tmp/superc$ git submodule update --init > Submodule 'sub' (/home/la/tmp/super/sub) registered for path 'sub' > fatal: repository '/home/la/tmp/super/sub' does not exist > Clone of '/home/la/tmp/super/sub' into submodule path 'sub' failed And that fails because to be able to clone a submodule it has to be pushed into its own repo first, so it can be cloned from there somewhere else. After doing that this will work. > So a normal relative path in .gitmodules to inside the tree is fragile, since > the location of the submodule can change. As I said, the current user experience is suboptimal. The test case 'submodule update properly revives a moved submodule' in t7406 shows what has to be done with current git to properly move a submodule, which is way too much to remember for a regular git user. -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] completion: add format-patch options to send-email
Signed-off-by: Felipe Contreras --- contrib/completion/git-completion.bash | 35 +- t/t9902-completion.sh | 21 2 files changed, 39 insertions(+), 17 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index d743e56..2a83504 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1112,6 +1112,14 @@ _git_fetch () __git_complete_remote_or_refspec } +__git_format_patch_options=" + --stdout --attach --no-attach --thread --thread= --output-directory + --numbered --start-number --numbered-files --keep-subject --signoff + --signature --no-signature --in-reply-to= --cc= --full-index --binary + --not --all --cover-letter --no-prefix --src-prefix= --dst-prefix= + --inline --suffix= --ignore-if-in-upstream --subject-prefix= +" + _git_format_patch () { case "$cur" in @@ -1122,21 +1130,7 @@ _git_format_patch () return ;; --*) - __gitcomp " - --stdout --attach --no-attach --thread --thread= - --output-directory - --numbered --start-number - --numbered-files - --keep-subject - --signoff --signature --no-signature - --in-reply-to= --cc= - --full-index --binary - --not --all - --cover-letter - --no-prefix --src-prefix= --dst-prefix= - --inline --suffix= --ignore-if-in-upstream - --subject-prefix= - " + __gitcomp "$__git_format_patch_options" return ;; esac @@ -1550,6 +1544,12 @@ _git_send_email () __gitcomp "ssl tls" "" "${cur##--smtp-encryption=}" return ;; + --thread=*) + __gitcomp " + deep shallow + " "" "${cur##--thread=}" + return + ;; --*) __gitcomp "--annotate --bcc --cc --cc-cmd --chain-reply-to --compose --confirm= --dry-run --envelope-sender @@ -1559,11 +1559,12 @@ _git_send_email () --signed-off-by-cc --smtp-pass --smtp-server --smtp-server-port --smtp-encryption= --smtp-user --subject --suppress-cc= --suppress-from --thread --to - --validate --no-validate" + --validate --no-validate + $__git_format_patch_options" return ;; esac - COMPREPLY=() + __git_complete_revlist_file } _git_stage () diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index 92d7eb4..c4b6c13 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -146,6 +146,22 @@ test_expect_success '__gitcomp - suffix' ' test_cmp expected out ' +setup_repository () +{ + mkdir "$1" && ( + cd "$1" && + git init && + test_tick && + git commit --allow-empty -m "Initial" + ) +} + +test_expect_success 'prepare' ' + setup_repository one && + git clone one test && + cd test +' + test_expect_success 'basic' ' run_completion "git \"\"" && # built-in @@ -228,4 +244,9 @@ test_expect_success 'general options plus command' ' test_completion "git --no-replace-objects check" "checkout " ' +test_expect_success 'send-email' ' + test_completion "git send-email --cov" "--cover-letter " && + test_completion "git send-email ma" "master " +' + test_done -- 1.7.12.1 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: A design for subrepositories
Am 14.10.2012 17:27, schrieb Lauri Alanko: > Quoting "Jens Lehmann" : >> What's wrong with making git clone all submodules together with the >> superproject (when the user said he wants to update all submodules on >> clone too by setting a - still to be added - config option)? > > Depends on how it's done. In a previous mail I just considered various ways > to do it. If I see correctly, your choice is to read .gitmodules from every > branch and every tag to find the total set of submodules used by the > repository. As I said already, that is certainly possible, but it's just not > very scalable, if fetch operations slow down linearly in the number of tags. Currently "git fetch" checks all newly fetched commits for changes in gitlinks too, so that would just add another file to that. And as a fetch is pretty much linear in the number of newly fetched commits anyway, its performance impact should be minimal. -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: A design for subrepositories
Am 14.10.2012 17:27, schrieb Lauri Alanko: > Quoting "Jens Lehmann" : >> Did you notice that "git fetch" fetches all those submodules too which >> have been updated in the commits fetched for the superproject, no matter >> on what branch they are on? > > No. This would be great, but this is what I get: > > la@bq:~/tmp$ git init super > Initialized empty Git repository in /home/la/tmp/super/.git/ > la@bq:~/tmp$ cd super > la@bq:~/tmp/super$ echo foo > foo > la@bq:~/tmp/super$ git add foo > la@bq:~/tmp/super$ git ci -m foo > [master (root-commit) 0f207c9] foo > 1 file changed, 1 insertion(+) > create mode 100644 foo > la@bq:~/tmp/super$ git branch nosubs > la@bq:~/tmp/super$ git init sub > Initialized empty Git repository in /home/la/tmp/super/sub/.git/ > la@bq:~/tmp/super$ cd sub > la@bq:~/tmp/super/sub$ echo bar > bar > la@bq:~/tmp/super/sub$ git add bar > la@bq:~/tmp/super/sub$ git ci -m bar > [master (root-commit) 180c6c9] bar > 1 file changed, 1 insertion(+) > create mode 100644 bar > la@bq:~/tmp/super/sub$ cd .. > la@bq:~/tmp/super$ git submodule add ./sub > Adding existing repo at 'sub' to the index > la@bq:~/tmp/super$ git ci -m sub > [master 16cff18] sub > 2 files changed, 4 insertions(+) > create mode 100644 .gitmodules > create mode 16 sub > la@bq:~/tmp/super$ cd .. > la@bq:~/tmp$ git clone super superc > Cloning into 'superc'... > done. > la@bq:~/tmp$ cd superc > la@bq:~/tmp/superc$ git submodule update --init > Submodule 'sub' (/home/la/tmp/super/sub) registered for path 'sub' > Cloning into 'sub'... > done. > Submodule path 'sub': checked out '180c6c979289f4e25525003673e51d0e39dab8f6' > la@bq:~/tmp/superc$ cd ../super/sub > la@bq:~/tmp/super/sub$ echo baz >> bar > la@bq:~/tmp/super/sub$ git ci -am baz > [master 652c8b3] baz > 1 file changed, 1 insertion(+) > la@bq:~/tmp/super/sub$ cd .. > la@bq:~/tmp/super$ git ci -am subbaz > [master c7c3bfc] subbaz > 1 file changed, 1 insertion(+), 1 deletion(-) > la@bq:~/tmp/super$ cd ../superc > la@bq:~/tmp/superc$ git co nosubs > warning: unable to rmdir sub: Directory not empty > Branch nosubs set up to track remote branch nosubs from origin. > Switched to a new branch 'nosubs' > la@bq:~/tmp/superc$ git fetch --recurse-submodules=yes > remote: Counting objects: 3, done. > remote: Compressing objects: 100% (2/2), done. > remote: Total 2 (delta 1), reused 0 (delta 0) > Unpacking objects: 100% (2/2), done. > From /home/la/tmp/super >16cff18..c7c3bfc master -> origin/master > la@bq:~/tmp/superc$ git co master > Switched to branch 'master' > Your branch is behind 'origin/master' by 1 commit, and can be fast-forwarded. > la@bq:~/tmp/superc$ git fetch --recurse-submodules=yes > Fetching submodule sub > remote: Counting objects: 5, done. > remote: Total 3 (delta 0), reused 0 (delta 0) > Unpacking objects: 100% (3/3), done. > From /home/la/tmp/super/sub >180c6c9..652c8b3 master -> origin/master > > So I had to checkout master in order to fetch the updates to the submodule > used by master. Yes, when you switch to a branch which hasn't got that submodule at all that is the case (as currently the .gitmodules found in the work tree is used to do the path -> name mapping). The culprit is the "git fetch" does not yet examine the .gitmodules file of the commit it finds a submodule change in, but uses the one currently found inside the work tree. But I'll have to tackle too soon, as that also poses a problem when the submodule was moved. So "no matter what branch they are on" is not always correct at the moment ;-) Again, the user experience is currently suboptimal. -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/2] config: treat user and xdg config permission problems as errors
On Sun, Oct 14, 2012 at 01:42:44AM -0700, Jonathan Nieder wrote: > Jeff King wrote: > > > For example, servers may depend on /etc/gitconfig to enforce security > > policy (e.g., setting transfer.fsckObjects or receive.deny*). Perhaps > > our default should be safe, and people can use GIT_CONFIG_NOSYSTEM to > > work around a broken machine. > > Very good point. How about these patches on top? > > Jonathan Nieder (2): > config doc: advertise GIT_CONFIG_NOSYSTEM > config: exit on error accessing any config file > > Documentation/git-config.txt | 8 > config.c | 6 +++--- > 2 files changed, 11 insertions(+), 3 deletions(-) This is my absolute favorite type of reply: the kind that you can apply with "git am". The direction and the patches themselves look good to me. I agree with your reasoning in v2 of 3/2; it makes much more sense than v1. Thanks. -Peff -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: Why git shows staging area to users?
David Aguilar writes: > On Sat, Oct 13, 2012 at 2:08 PM, Yi, EungJun wrote: >> Hi, all. >> >> Why git shows staging area to users, compared with the other scms hide >> it? What benefits users get? > > http://thkoch2001.github.com/whygitisbetter/#the-staging-area > http://tomayko.com/writings/the-thing-about-git > http://gitready.com/beginner/2009/01/18/the-staging-area.html > > Other scms do not "hide"; other scms lack this feature altogether. More precisely: there are several things in what git calls "the index" or "the staging area" (i.e. .git/index): 1) a list of files tracked by Git 2) a record of the last known meta-data of the file, used to avoid re-reading unmodified files content each time one runs "diff", "commit" or so. 3) a record of the file's staged *content* (possible several records in case a merge is going on) Any decent revision control has the equivalent of 1) and 2), but AFAIK, 3) is a unique feature of Git. There is a frequent confusion between 2) and 3) that leads to people (often other revision-control users/developers) wonder why this is visible to the user. 2) is a performance optimization that can be hidden to the user (it is with Git's porcelain commands), but 3) is user-visible. -- Matthieu Moy http://www-verimag.imag.fr/~moy/ -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] exclude: fix a bug in prefix comparison optimization
Nguyễn Thái Ngọc Duy writes: > When "namelen" becomes zero at this stage, we have matched the fixed > part, but whether it actually matches the pattern still depends on the > pattern in "exclude". As demonstrated in t3001, path "three/a.3" > exists and it matches the "three/a.3" part in pattern "three/a.3[abc]", > but that does not mean a true match. > > Don't be too optimistic and let fnmatch() do the job. Yeah, the existing code is correct _only_ if the pattern part can match an empty string (e.g. "three/a.3*") and this is a correct fix. With your "teach attr.c match the same optimization as dir.c" series, you would need something like this diff --git i/attr.c w/attr.c index 6d39406..528e935 100644 --- i/attr.c +++ w/attr.c @@ -710,7 +710,7 @@ static int path_matches(const char *pathname, int pathlen, * if the non-wildcard part is longer than the remaining * pathname, surely it cannot match. */ - if (!namelen || prefix > namelen) + if (prefix > namelen) return 0; if (baselen != 0) baselen++; Comparing the corresponding code in dir.c, there is no "compare the literal prefix part with strcmp() before doing the fnmatch()" optimization. Intended? (warning: I haven't had my caffeine yet) -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: A design for subrepositories
Jens Lehmann writes: > Again, the user experience is currently suboptimal. You mentioned multiple things in your responses that you are planning to address, but I am wondering if the first step before doing anything else is to have a list of known-to-be-suboptimal things and publish it somewhere other people can find it. Then Lauri or others may able to help code the design of the approach to address them for items you already have designs for, and they may even be able to help designing the approach for the ones you don't. More importantly, they do not have to waste time coming up with incompatible tools. Adding "works in this scenario that is different from those other slightly different tools" to the mix of third-party tool set would fragment and confuse the user base ("which one of 47 different tools, all of which are incomplete, should I use?") and dilute developer attention. They all at some point want to interact with the core side, and without an overall consistent design and coordination, some of their demand on the core side would end up being imcompatible. The "just let .gitmodules record which branch is of interest, without checking out a specific commit bound to the superproject tree and using as a base for diff" (aka floating submodule) could be one of the items on the list, for example; to support it, we should not have to throw the entire "git submodule" with the bathwater. Thanks. -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 3/4] exclude/attr: share basename matching code
Nguyễn Thái Ngọc Duy writes: > match_basename's declaration in dir.h does not have any description to > discourage the use of this function elsewhere as this function is > highly tied to how excluded_from_list and path_matches work. If you do want to discourage, please explicitly describe it as such. I actually think it should have an API description. The meaning of its parameters and how you would formulate them is fairly clear and this is a good example of a simple-and-stupid function that is designed to do one thing and do it well. > > Signed-off-by: Nguyễn Thái Ngọc Duy > --- > attr.c | 15 --- > dir.c | 37 - > dir.h | 2 ++ > 3 files changed, 30 insertions(+), 24 deletions(-) > > diff --git a/attr.c b/attr.c > index 0964033..a28ce0d 100644 > --- a/attr.c > +++ b/attr.c > @@ -663,17 +663,10 @@ static int path_matches(const char *pathname, int > pathlen, > int namelen; > > if (pat->flags & EXC_FLAG_NODIR) { > - if (prefix == pat->patternlen && > - !strcmp_icase(pattern, basename)) > - return 1; > - > - if (pat->flags & EXC_FLAG_ENDSWITH && > - pat->patternlen - 1 <= pathlen && > - !strcmp_icase(pattern + 1, pathname + > - pathlen - pat->patternlen + 1)) > - return 1; > - > - return (fnmatch_icase(pattern, basename, 0) == 0); > + return match_basename(basename, > + pathlen - (basename - pathname), > + pattern, prefix, > + pat->patternlen, pat->flags); > } > /* >* match with FNM_PATHNAME; the pattern has base implicitly > diff --git a/dir.c b/dir.c > index 0f4aea6..42c42cd 100644 > --- a/dir.c > +++ b/dir.c > @@ -530,6 +530,25 @@ static void prep_exclude(struct dir_struct *dir, const > char *base, int baselen) > dir->basebuf[baselen] = '\0'; > } > > +int match_basename(const char *basename, int basenamelen, > +const char *pattern, int prefix, int patternlen, > +int flags) > +{ > + if (prefix == patternlen) { > + if (!strcmp_icase(pattern, basename)) > + return 1; > + } else if (flags & EXC_FLAG_ENDSWITH) { > + if (patternlen - 1 <= basenamelen && > + !strcmp_icase(pattern + 1, > + basename + basenamelen - patternlen + 1)) > + return 1; > + } else { > + if (fnmatch_icase(pattern, basename, 0) == 0) > + return 1; > + } > + return 0; > +} > + > /* Scan the list and let the last match determine the fate. > * Return 1 for exclude, 0 for include and -1 for undecided. > */ > @@ -556,19 +575,11 @@ int excluded_from_list(const char *pathname, > } > > if (x->flags & EXC_FLAG_NODIR) { > - /* match basename */ > - if (prefix == x->patternlen) { > - if (!strcmp_icase(exclude, basename)) > - return to_exclude; > - } else if (x->flags & EXC_FLAG_ENDSWITH) { > - int len = pathlen - (basename - pathname); > - if (x->patternlen - 1 <= len && > - !strcmp_icase(exclude + 1, basename + len - > x->patternlen + 1)) > - return to_exclude; > - } else { > - if (fnmatch_icase(exclude, basename, 0) == 0) > - return to_exclude; > - } > + if (match_basename(basename, > +pathlen - (basename - pathname), > +exclude, prefix, x->patternlen, > +x->flags)) > + return to_exclude; > continue; > } > > diff --git a/dir.h b/dir.h > index fd5c2aa..d416c5a 100644 > --- a/dir.h > +++ b/dir.h > @@ -78,6 +78,8 @@ extern int read_directory(struct dir_struct *, const char > *path, int len, const > > extern int excluded_from_list(const char *pathname, int pathlen, const char > *basename, > int *dtype, struct exclude_list *el); > +extern int match_basename(const char *, int, > + const char *, int, int, int); > struct dir_entry *dir_add_ignored(struct dir_struct *dir, const char > *pathname, int len); > > /* -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Planning to pass the baton to an interim maintainer
I am planning to * tag 1.8.0 final on Oct 21st (Sun); * go offline on Oct 22nd (Mon); and * come back online on Nov 12th (Mon). Peff, could you be the interim maintainer as you've done in earlier years while I was away? Thanks. -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] exclude: fix a bug in prefix comparison optimization
Junio C Hamano writes: > Comparing the corresponding code in dir.c, there is no "compare the > literal prefix part with strcmp() before doing the fnmatch()" > optimization. Intended? > > (warning: I haven't had my caffeine yet) And it turns out that at the point I wrote the response, I still had the attr-match-optim-more updates to be read in my mailbox ;-) -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: A design for subrepositories
Am 14.10.2012 20:04, schrieb Junio C Hamano: > Jens Lehmann writes: > >> Again, the user experience is currently suboptimal. > > You mentioned multiple things in your responses that you are > planning to address, but I am wondering if the first step before > doing anything else is to have a list of known-to-be-suboptimal > things and publish it somewhere other people can find it. Then > Lauri or others may able to help code the design of the approach to > address them for items you already have designs for, and they may > even be able to help designing the approach for the ones you don't. I'm keeping such a list in the "Issues still to be tackled in this repo" section of the Wiki page of my github repo: https://github.com/jlehmann/git-submod-enhancements/wiki Currently that's just a collection of things to do and bugs to fix, but if people are interested I'm willing to add descriptions of the solutions I have in mind for those topics. > More importantly, they do not have to waste time coming up with > incompatible tools. Adding "works in this scenario that is > different from those other slightly different tools" to the mix of > third-party tool set would fragment and confuse the user base > ("which one of 47 different tools, all of which are incomplete, > should I use?") and dilute developer attention. They all at some > point want to interact with the core side, and without an overall > consistent design and coordination, some of their demand on the core > side would end up being imcompatible. > > The "just let .gitmodules record which branch is of interest, > without checking out a specific commit bound to the superproject > tree and using as a base for diff" (aka floating submodule) could be > one of the items on the list, for example; to support it, we should > not have to throw the entire "git submodule" with the bathwater. Yup, that's also on that list under "always tip" mode. -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2 2/2] git-cvsimport: allow local timezone for commits
On Sun, Oct 14, 2012 at 1:04 AM, Junio C Hamano wrote: > Chris Rorvick writes: > >> CVS patches are imported with the timezone offset of + (UTC). >> Allow timezone offsets to be calculated from the the local timezone by >> adding -l to the command line or specifying cvsimport.l in the config. > > A single "I do not like everybody's timestamp is in GMT, so instead > use the local timezone I the importer happen to be in" sounds more > like an uninteresting hack with limited application than a useful > new feature. Even back in CVS days, many projects and repositories > worth converting to Git were multi-people projects that span across > timezones. > > I am wondering if it is sufficient to enhance existing cvs-authors > file to tie a person to a timezone to add a feature like this in a > more sensible manner. I'd assume that in many multi-person project, > one person, even when travelling, tend to record commits in a single > timezone (i.e. his or her home timezone). Even for a single-person > project, adding a single entry ot the file is not too much to ask to > the user. Being able to view his human-readable name and timezone > would be good value for the amount of trouble. This sounds pretty straight forward. It had crossed my mind that using the cvs-authors file like this would be a more general solution, but I thought that what I proposed was at least a step in the right direction. But since anyone that cares about this is almost certainly putting together a cvs-authors file anyway, I agree that being able to set an alternate default timezone probably isn't a very useful addition. I'll resubmit when I have something working. -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: A design for subrepositories
la@bq:~/tmp/super$ git mv sub movedsub fatal: source directory is empty, source=sub, destination=movedsub This error here indicates that we didn't teach git to properly move a submodule yet. It is one of my next goals to make "git [submodule] mv sub movedsub" do the right thing here. I'll digress here a bit: I'm not really fond of the idea of adding special-purpose support into the core git commands. It just makes them messier, and there will always be other tools that won't be supported by git directly. I'd much rather see an mv-hook that arbitrary extensions could use to update metadata associated with a tree entry. Indeed, one of the reasons a separate tool seemed attractive to me was that that way I could be sure that the tool was a high-level utility that was completely implemented on top of basic low-level git operations. The fact that git's submodule support manifests as bits and pieces in various parts of the core seems a bit worrisome to me. (Moreover, it's confusing to the user. I read the git-submodule man page and thought that that described all the available submodule operations. Only now did I find out that clone and fetch also have built-in submodule functionality.) la@bq:~/tmp/super$ mv sub movedsub Currently it is better to remove the submodule here, as recreating it with a "git submodule update" later will get the relative paths right. This was a bit of a special case, as this was the original directory where we did "git init sub" and "git submodule add ./sub". So "sub" actually contains the real repository, not a gitlink to .git/modules/sub. Arguably "git submodule add" should move the local submodule's repository there. la@bq:~/tmp/super$ git rm sub rm 'sub' la@bq:~/tmp/super$ git add movedsub And to git this adds a completely different submodule (as its name is not "sub"), which breaks your expectation. Submodule? This is just a normal git add, not git submodule add. I thought this just adds to the index a gitlink with the head revision in movedsub, which is the same as the head revision was in sub, so it's detected as a move of a gitlink. To do what you intended use this line instead: $ git update-index --add --cacheinfo 16 $HASH movedsub Doesn't this do exactly the same thing as "git add" for a directory containing a repository? la@bq:~/tmp/superc$ git submodule update --init Submodule 'sub' (/home/la/tmp/super/sub) registered for path 'sub' fatal: repository '/home/la/tmp/super/sub' does not exist Clone of '/home/la/tmp/super/sub' into submodule path 'sub' failed And that fails because to be able to clone a submodule it has to be pushed into its own repo first, so it can be cloned from there somewhere else. After doing that this will work. Sorry, but I can't get this to work. To me it seems that when fetching submodules from the origin, submodule.sub.url has to point to the actual location of the repository, and if this is outdated or missing, the fetch won't work. It would make sense that if the url is missing, the submodule repo inside origin's .git/modules would be used, but this doesn't seem to be the case currently. Currently "git fetch" checks all newly fetched commits for changes in gitlinks too, so that would just add another file to that. I only now realized that it is indeed enough to check .gitmodules only in the _updated_ refs. The older refs are interested in their submodules only up to a certain commit, and even if those submodules have been updated upstream, we won't be interested in them until we have trees with gitlinks pointing to the newer revisions. So it turns out that my main technical argument against git-submodule's potential scalability was false, and it is indeed feasible to make it support all the features I require. However, "always tip" mode would break this, since then even non-updated branches might be interested in upstream changes to a submodule. Anyway, I am a bit surprised to hear of such active development for git-submodule. It's pretty old now (the shell script says 2007), and I thought that if it were to ever support the kind of basic functionality I require, it would do so already. How soon do you envision support for bare repositories with submodules? Lauri -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] git-cvsimport: allow author-specific timezones
From: Chris Rorvick CVS patchsets are imported with timestamps having an offset of + (UTC). The cvs-authors file is already used to translate the CVS username to full name and email in the corresponding commit. Extend this file to support an optional timezone for calculating a user- specific timestamp offset. Signed-off-by: Chris Rorvick --- This supercedes the patches submitted for using the local timezone in commits. Documentation/git-cvsimport.txt| 5 +- git-cvsimport.perl | 22 ++- t/t9604-cvsimport-timestamps.sh| 92 + t/t9604/cvsroot/.gitattributes | 1 + t/t9604/cvsroot/CVSROOT/.gitignore | 2 + t/t9604/cvsroot/module/a,v | 265 + 6 files changed, 381 insertions(+), 6 deletions(-) create mode 100775 t/t9604-cvsimport-timestamps.sh create mode 100664 t/t9604/cvsroot/.gitattributes create mode 100664 t/t9604/cvsroot/CVSROOT/.gitignore create mode 100664 t/t9604/cvsroot/module/a,v diff --git a/Documentation/git-cvsimport.txt b/Documentation/git-cvsimport.txt index 6695ab3..35dc636 100644 --- a/Documentation/git-cvsimport.txt +++ b/Documentation/git-cvsimport.txt @@ -141,13 +141,14 @@ This option can be used several times to provide several detection regexes. + - exon=Andreas Ericsson - spawn=Simon Pawn + spawn=Simon Pawn America/Chicago - + 'git cvsimport' will make it appear as those authors had their GIT_AUTHOR_NAME and GIT_AUTHOR_EMAIL set properly -all along. +all along. If a timezone is specified, GIT_AUTHOR_DATE will +have the corresponding offset applied. + For convenience, this data is saved to `$GIT_DIR/cvs-authors` each time the '-A' option is provided and read from that same diff --git a/git-cvsimport.perl b/git-cvsimport.perl index 8032f23..ceb119d 100755 --- a/git-cvsimport.perl +++ b/git-cvsimport.perl @@ -31,7 +31,7 @@ $SIG{'PIPE'}="IGNORE"; $ENV{'TZ'}="UTC"; our ($opt_h,$opt_o,$opt_v,$opt_k,$opt_u,$opt_d,$opt_p,$opt_C,$opt_z,$opt_i,$opt_P, $opt_s,$opt_m,@opt_M,$opt_A,$opt_S,$opt_L, $opt_a, $opt_r, $opt_R); -my (%conv_author_name, %conv_author_email); +my (%conv_author_name, %conv_author_email, %conv_author_tz); sub usage(;$) { my $msg = shift; @@ -59,6 +59,14 @@ sub read_author_info($) { $conv_author_name{$user} = $2; $conv_author_email{$user} = $3; } + # or with an optional timezone: + # spawn=Simon Pawn America/Chicago + elsif (m/^(\S+?)\s*=\s*(.+?)\s*<(.+)>\s*(\S+?)\s*$/) { + $user = $1; + $conv_author_name{$user} = $2; + $conv_author_email{$user} = $3; + $conv_author_tz{$user} = $4; + } # However, we also read from CVSROOT/users format # to ease migration. elsif (/^(\w+):(['"]?)(.+?)\2\s*$/) { @@ -84,7 +92,9 @@ sub write_author_info($) { die("Failed to open $file for writing: $!"); foreach (keys %conv_author_name) { - print $f "$_=$conv_author_name{$_} <$conv_author_email{$_}>\n"; + print $f "$_=$conv_author_name{$_} <$conv_author_email{$_}>"; + print $f " $conv_author_tz{$_}" if ($conv_author_tz{$_}); + print $f "\n"; } close ($f); } @@ -795,7 +805,7 @@ sub write_tree () { return $tree; } -my ($patchset,$date,$author_name,$author_email,$branch,$ancestor,$tag,$logmsg); +my ($patchset,$date,$author_name,$author_email,$author_tz,$branch,$ancestor,$tag,$logmsg); my (@old,@new,@skipped,%ignorebranch,@commit_revisions); # commits that cvsps cannot place anywhere... @@ -844,7 +854,9 @@ sub commit { } } - my $commit_date = strftime("+ %Y-%m-%d %H:%M:%S",gmtime($date)); + $ENV{'TZ'}=$author_tz; + my $commit_date = strftime("%s %z", localtime($date)); + $ENV{'TZ'}="UTC"; $ENV{GIT_AUTHOR_NAME} = $author_name; $ENV{GIT_AUTHOR_EMAIL} = $author_email; $ENV{GIT_AUTHOR_DATE} = $commit_date; @@ -945,12 +957,14 @@ while () { } $state=3; } elsif ($state == 3 and s/^Author:\s+//) { + $author_tz = "UTC"; s/\s+$//; if (/^(.*?)\s+<(.*)>/) { ($author_name, $author_email) = ($1, $2); } elsif ($conv_author_name{$_}) { $author_name = $conv_author_name{$_}; $author_email = $conv_author_email{$_}; + $author_tz = $conv_author_tz{$_} if ($conv_author_tz{$_}); } else { $author_name = $author_email = $_; } diff --git a/t/t9604-cvsimport-timestamps.sh b/t/t9604-cvsimport-timestamps.sh new file mode 100644 index 000..fb7459c --- /dev/null +++ b/t/t9604-cvsimp
[PATCH v2] git-cvsimport: allow author-specific timezones
CVS patchsets are imported with timestamps having an offset of + (UTC). The cvs-authors file is already used to translate the CVS username to full name and email in the corresponding commit. Extend this file to support an optional timezone for calculating a user- specific timestamp offset. Signed-off-by: Chris Rorvick --- This supersedes the patches submitted for using the local timezone in commits. (sorry for the noise, I messed up sending the patch previously) Documentation/git-cvsimport.txt| 5 +- git-cvsimport.perl | 22 ++- t/t9604-cvsimport-timestamps.sh| 92 + t/t9604/cvsroot/.gitattributes | 1 + t/t9604/cvsroot/CVSROOT/.gitignore | 2 + t/t9604/cvsroot/module/a,v | 265 + 6 files changed, 381 insertions(+), 6 deletions(-) create mode 100755 t/t9604-cvsimport-timestamps.sh create mode 100644 t/t9604/cvsroot/.gitattributes create mode 100644 t/t9604/cvsroot/CVSROOT/.gitignore create mode 100644 t/t9604/cvsroot/module/a,v diff --git a/Documentation/git-cvsimport.txt b/Documentation/git-cvsimport.txt index 6695ab3..35dc636 100644 --- a/Documentation/git-cvsimport.txt +++ b/Documentation/git-cvsimport.txt @@ -141,13 +141,14 @@ This option can be used several times to provide several detection regexes. + - exon=Andreas Ericsson - spawn=Simon Pawn + spawn=Simon Pawn America/Chicago - + 'git cvsimport' will make it appear as those authors had their GIT_AUTHOR_NAME and GIT_AUTHOR_EMAIL set properly -all along. +all along. If a timezone is specified, GIT_AUTHOR_DATE will +have the corresponding offset applied. + For convenience, this data is saved to `$GIT_DIR/cvs-authors` each time the '-A' option is provided and read from that same diff --git a/git-cvsimport.perl b/git-cvsimport.perl index 8032f23..ceb119d 100755 --- a/git-cvsimport.perl +++ b/git-cvsimport.perl @@ -31,7 +31,7 @@ $SIG{'PIPE'}="IGNORE"; $ENV{'TZ'}="UTC"; our ($opt_h,$opt_o,$opt_v,$opt_k,$opt_u,$opt_d,$opt_p,$opt_C,$opt_z,$opt_i,$opt_P, $opt_s,$opt_m,@opt_M,$opt_A,$opt_S,$opt_L, $opt_a, $opt_r, $opt_R); -my (%conv_author_name, %conv_author_email); +my (%conv_author_name, %conv_author_email, %conv_author_tz); sub usage(;$) { my $msg = shift; @@ -59,6 +59,14 @@ sub read_author_info($) { $conv_author_name{$user} = $2; $conv_author_email{$user} = $3; } + # or with an optional timezone: + # spawn=Simon Pawn America/Chicago + elsif (m/^(\S+?)\s*=\s*(.+?)\s*<(.+)>\s*(\S+?)\s*$/) { + $user = $1; + $conv_author_name{$user} = $2; + $conv_author_email{$user} = $3; + $conv_author_tz{$user} = $4; + } # However, we also read from CVSROOT/users format # to ease migration. elsif (/^(\w+):(['"]?)(.+?)\2\s*$/) { @@ -84,7 +92,9 @@ sub write_author_info($) { die("Failed to open $file for writing: $!"); foreach (keys %conv_author_name) { - print $f "$_=$conv_author_name{$_} <$conv_author_email{$_}>\n"; + print $f "$_=$conv_author_name{$_} <$conv_author_email{$_}>"; + print $f " $conv_author_tz{$_}" if ($conv_author_tz{$_}); + print $f "\n"; } close ($f); } @@ -795,7 +805,7 @@ sub write_tree () { return $tree; } -my ($patchset,$date,$author_name,$author_email,$branch,$ancestor,$tag,$logmsg); +my ($patchset,$date,$author_name,$author_email,$author_tz,$branch,$ancestor,$tag,$logmsg); my (@old,@new,@skipped,%ignorebranch,@commit_revisions); # commits that cvsps cannot place anywhere... @@ -844,7 +854,9 @@ sub commit { } } - my $commit_date = strftime("+ %Y-%m-%d %H:%M:%S",gmtime($date)); + $ENV{'TZ'}=$author_tz; + my $commit_date = strftime("%s %z", localtime($date)); + $ENV{'TZ'}="UTC"; $ENV{GIT_AUTHOR_NAME} = $author_name; $ENV{GIT_AUTHOR_EMAIL} = $author_email; $ENV{GIT_AUTHOR_DATE} = $commit_date; @@ -945,12 +957,14 @@ while () { } $state=3; } elsif ($state == 3 and s/^Author:\s+//) { + $author_tz = "UTC"; s/\s+$//; if (/^(.*?)\s+<(.*)>/) { ($author_name, $author_email) = ($1, $2); } elsif ($conv_author_name{$_}) { $author_name = $conv_author_name{$_}; $author_email = $conv_author_email{$_}; + $author_tz = $conv_author_tz{$_} if ($conv_author_tz{$_}); } else { $author_name = $author_email = $_; } diff --git a/t/t9604-cvsimport-timestamps.sh b/t/t9604-cvsimport-timestamps.sh new file mode 100755 index 000.
Re: [PATCH] exclude: fix a bug in prefix comparison optimization
On Mon, Oct 15, 2012 at 12:36 AM, Junio C Hamano wrote: > With your "teach attr.c match the same optimization as dir.c" > series, you would need something like this > > diff --git i/attr.c w/attr.c > index 6d39406..528e935 100644 > --- i/attr.c > +++ w/attr.c > @@ -710,7 +710,7 @@ static int path_matches(const char *pathname, int pathlen, > * if the non-wildcard part is longer than the remaining > * pathname, surely it cannot match. > */ > - if (!namelen || prefix > namelen) > + if (prefix > namelen) > return 0; > if (baselen != 0) > baselen++; If there's still a chance to rewrite attr-match-optim-more series (I see it's in next now), then I could reorder the patches so that excluded_from_list code refactoring goes first, then rewrite "teach attr.c match... as dir.c" patch makes use of the new functions without code duplication. The end result would be the same, except that we won't see this bug in attr.c's history. Not much value so if it may take a lot of your time, don't bother. -- Duy -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] exclude: fix a bug in prefix comparison optimization
Nguyen Thai Ngoc Duy writes: > On Mon, Oct 15, 2012 at 12:36 AM, Junio C Hamano wrote: >> With your "teach attr.c match the same optimization as dir.c" >> series, you would need something like this >> >> diff --git i/attr.c w/attr.c >> index 6d39406..528e935 100644 >> --- i/attr.c >> +++ w/attr.c >> @@ -710,7 +710,7 @@ static int path_matches(const char *pathname, int >> pathlen, >> * if the non-wildcard part is longer than the remaining >> * pathname, surely it cannot match. >> */ >> - if (!namelen || prefix > namelen) >> + if (prefix > namelen) >> return 0; >> if (baselen != 0) >> baselen++; > > If there's still a chance to rewrite attr-match-optim-more series (I > see it's in next now), then I could reorder the patches so that > excluded_from_list code refactoring goes first, then rewrite "teach > attr.c match... as dir.c" patch makes use of the new functions without > code duplication. The end result would be the same, except that we > won't see this bug in attr.c's history. Not much value so if it may > take a lot of your time, don't bother. Actually it started to become nuisance to deal with conflicts among as/check-ignore and the attr/dir/wildmatch series, and I've been wondering if it makes sense to eject all of these out of 'next' (as they won't advance beyond 'next' until the next release anyway). So please go ahead and reroll the whole thing if you think the end result would be a history with better organization. -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: Planning to pass the baton to an interim maintainer
On Sun, Oct 14, 2012 at 11:23:07AM -0700, Junio C Hamano wrote: > I am planning to > > * tag 1.8.0 final on Oct 21st (Sun); > * go offline on Oct 22nd (Mon); and > * come back online on Nov 12th (Mon). > > Peff, could you be the interim maintainer as you've done in earlier > years while I was away? Sure, I look forward to ruling the list with an iron fist...er, helping contributors review their patches. -Peff -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2 2/2] grep: stop looking at random places for .gitattributes
Am 10/14/2012 6:29, schrieb Junio C Hamano: > Johannes Sixt writes: > >> It might be worth it. We already have a similar special case in >> write_or_die.c:maybe_flush_or_die() for Windows, although it is not about >> a colon in a path name. >> >> Perhaps like this. > > Hrm, the "we already have" one b2f5e26 (Windows: Work around an > oddity when a pipe with no reader is written to., 2007-08-17) was > what you added while I was looking the other way ;-) as a part of > Windows specific pull. > > That change, and this patch, seem to cover the cases to be ignored > with a bit too wide a net to my taste. On other systems, and even > on Windows if the path does not have any colon, EINVAL is something > we would want to noticbbe and report, as a potential problem, no? For fopen(), EINVAL should occur only if the mode argument is wrong, which it isn't. For fflush() (as in write_or_die.c), EINVAL is not even listed as possible error code. Therefore, catching EINVAL wholesale should not be a problem, IMO, at least not "on other systems". On Windows, it is more problematic because there is a table of "customary" Windows API error codes, which are mapped to errno values, and EINVAL is used for all other Windows error codes (and for a few listed ones), and ignoring EINVAL might indeed miss something worth to be reported. Sooo... I don't mind if you do not pick up this patch because it handles a rather theoretic case, i.e., where a project with strange paths somehow ended up on a Windows drive. But reverting the EINVAL check from write_or_die.c is out of question, because that handles a real case. -- Hannes -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
nd/attr-match-more-optim, nd/wildmatch and as/check-ignore
I promise I won't send anything dir.c-related till the end of this month :) These three series all touch the same code in dir.c and cause a bunch of conflicts. So I rebase nd/wildmatch and as/check-ignore on top of nd/attr-match-more-optim and resolve all conflicts. nd/attr-match-more-optim A lot of refactoring in dir.c leads to a cleaner last patch to port many exclude optimizations to attr. We can extend EXC_FLAGS_ENDSWITH optimization further, from "^*.[ch]" to "path/to/*.[ch]", but not in this series. Nguyễn Thái Ngọc Duy (6): exclude: stricten a length check in EXC_FLAG_ENDSWITH case exclude: split basename matching code into a separate function exclude: fix a bug in prefix compare optimization exclude: split pathname matching code into a separate function gitignore: make pattern parsing code a separate function attr: more matching optimizations from .gitignore Documentation/gitattributes.txt| 1 + attr.c | 52 ++ dir.c | 192 - dir.h | 13 ++- t/t0003-attributes.sh | 10 ++ t/t3001-ls-files-others-exclude.sh | 6 ++ 6 files changed, 186 insertions(+), 88 deletions(-) nd/wildmatch new ctype patches that no longer introduce sane_ctype2[]. I also re-indent wildmatch.c to follow Git's coding style with the intention of making more changes in future (e.g. case insensitive support in pathspec means we cannot rely on GNU extension FNM_CASEFOLD). Thanks to nd/attr-match-more-optim we don't need to make any changes to attr.c. Depends on nd/attr-match-more-optim. Nguyễn Thái Ngọc Duy (13): ctype: make sane_ctype[] const array ctype: support iscntrl, ispunct, isxdigit and isprint Import wildmatch from rsync wildmatch: remove unnecessary functions wildmatch: follow Git's coding convention Integrate wildmatch to git t3070: disable unreliable fnmatch tests wildmatch: make wildmatch's return value compatible with fnmatch wildmatch: remove static variable force_lower_case wildmatch: fix case-insensitive matching wildmatch: adjust "**" behavior wildmatch: make /**/ match zero or more directories Support "**" wildcard in .gitignore and .gitattributes .gitignore | 1 + Documentation/gitignore.txt| 19 +++ Makefile | 3 + ctype.c| 15 ++- dir.c | 4 +- git-compat-util.h | 15 ++- t/t0003-attributes.sh | 37 ++ t/t3001-ls-files-others-exclude.sh | 18 +++ t/t3070-wildmatch.sh | 195 +++ test-wildmatch.c | 14 +++ wildmatch.c| 234 + wildmatch.h| 9 ++ 12 files changed, 556 insertions(+), 8 deletions(-) create mode 100755 t/t3070-wildmatch.sh create mode 100644 test-wildmatch.c create mode 100644 wildmatch.c create mode 100644 wildmatch.h as/check-ignore --- Conflict resolution and cleanups. A lot of matching code sharing between exclude and attr means we might be able to bring check-ignore functionality to check-attr. But let's leave it for now. Depends on nd/attr-match-more-optim. Adam Spiers (12): dir.c: rename cryptic 'which' variable to more consistent name dir.c: rename path_excluded() to is_path_excluded() dir.c: rename excluded_from_list() to is_excluded_from_list() dir.c: rename excluded() to is_excluded() dir.c: refactor is_excluded_from_list() dir.c: refactor is_excluded() dir.c: refactor is_path_excluded() dir.c: keep track of where patterns came from dir.c: refactor treat_gitlinks() pathspec.c: move reusable code from builtin/add.c dir.c: provide free_directory() for reclaiming dir_struct memory Add git-check-ignore sub-command .gitignore| 1 + Documentation/git-check-ignore.txt| 85 Documentation/gitignore.txt | 6 +- Documentation/technical/api-directory-listing.txt | 2 + Makefile | 3 + attr.c| 2 +- builtin.h | 1 + builtin/add.c | 84 +--- builtin/check-ignore.c| 170 +++ builtin/clean.c | 2 +- builtin/ls-files.c| 5 +- command-list.txt | 1 + contrib/completion/git-completion.bash| 1 + dir.c | 185 +-- dir.h | 21 +- git.c | 1 + pathspec.c|
[PATCH 1/6] exclude: stricten a length check in EXC_FLAG_ENDSWITH case
This block of code deals with the "basename" part only, which has the length of "pathlen - (basename - pathname)". Stricten the length check and remove "pathname" from the main expression to avoid confusion. Signed-off-by: Nguyễn Thái Ngọc Duy --- dir.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dir.c b/dir.c index 0015cc5..b0ae417 100644 --- a/dir.c +++ b/dir.c @@ -534,8 +534,9 @@ int excluded_from_list(const char *pathname, if (!strcmp_icase(exclude, basename)) return to_exclude; } else if (x->flags & EXC_FLAG_ENDSWITH) { - if (x->patternlen - 1 <= pathlen && - !strcmp_icase(exclude + 1, pathname + pathlen - x->patternlen + 1)) + int len = pathlen - (basename - pathname); + if (x->patternlen - 1 <= len && + !strcmp_icase(exclude + 1, basename + len - x->patternlen + 1)) return to_exclude; } else { if (fnmatch_icase(exclude, basename, 0) == 0) -- 1.8.0.rc0.29.g1fdd78f -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 2/6] exclude: split basename matching code into a separate function
Signed-off-by: Nguyễn Thái Ngọc Duy --- dir.c | 37 - 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/dir.c b/dir.c index b0ae417..d9b5561 100644 --- a/dir.c +++ b/dir.c @@ -503,6 +503,25 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen) dir->basebuf[baselen] = '\0'; } +static int match_basename(const char *basename, int basenamelen, + const char *pattern, int prefix, int patternlen, + int flags) +{ + if (prefix == patternlen) { + if (!strcmp_icase(pattern, basename)) + return 1; + } else if (flags & EXC_FLAG_ENDSWITH) { + if (patternlen - 1 <= basenamelen && + !strcmp_icase(pattern + 1, + basename + basenamelen - patternlen + 1)) + return 1; + } else { + if (fnmatch_icase(pattern, basename, 0) == 0) + return 1; + } + return 0; +} + /* Scan the list and let the last match determine the fate. * Return 1 for exclude, 0 for include and -1 for undecided. */ @@ -529,19 +548,11 @@ int excluded_from_list(const char *pathname, } if (x->flags & EXC_FLAG_NODIR) { - /* match basename */ - if (prefix == x->patternlen) { - if (!strcmp_icase(exclude, basename)) - return to_exclude; - } else if (x->flags & EXC_FLAG_ENDSWITH) { - int len = pathlen - (basename - pathname); - if (x->patternlen - 1 <= len && - !strcmp_icase(exclude + 1, basename + len - x->patternlen + 1)) - return to_exclude; - } else { - if (fnmatch_icase(exclude, basename, 0) == 0) - return to_exclude; - } + if (match_basename(basename, + pathlen - (basename - pathname), + exclude, prefix, x->patternlen, + x->flags)) + return to_exclude; continue; } -- 1.8.0.rc0.29.g1fdd78f -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 3/6] exclude: fix a bug in prefix compare optimization
When "namelen" becomes zero at this stage, we have matched the fixed part, but whether it actually matches the pattern still depends on the pattern in "exclude". As demonstrated in t3001, path "three/a.3" exists and it matches the "three/a.3" part in pattern "three/a.3[abc]", but that does not mean a true match. Don't be too optimistic and let fnmatch() do the job. Signed-off-by: Nguyễn Thái Ngọc Duy --- dir.c | 2 +- t/t3001-ls-files-others-exclude.sh | 6 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/dir.c b/dir.c index d9b5561..22d0b7b 100644 --- a/dir.c +++ b/dir.c @@ -585,7 +585,7 @@ int excluded_from_list(const char *pathname, namelen -= prefix; } - if (!namelen || !fnmatch_icase(exclude, name, FNM_PATHNAME)) + if (!fnmatch_icase(exclude, name, FNM_PATHNAME)) return to_exclude; } return -1; /* undecided */ diff --git a/t/t3001-ls-files-others-exclude.sh b/t/t3001-ls-files-others-exclude.sh index c8fe978..dc2f045 100755 --- a/t/t3001-ls-files-others-exclude.sh +++ b/t/t3001-ls-files-others-exclude.sh @@ -214,4 +214,10 @@ test_expect_success 'subdirectory ignore (l1)' ' test_cmp expect actual ' +test_expect_success 'pattern matches prefix completely' ' + : >expect && + git ls-files -i -o --exclude "/three/a.3[abc]" >actual && + test_cmp expect actual +' + test_done -- 1.8.0.rc0.29.g1fdd78f -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 4/6] exclude: split pathname matching code into a separate function
Signed-off-by: Nguyễn Thái Ngọc Duy --- dir.c | 85 ++- 1 file changed, 53 insertions(+), 32 deletions(-) diff --git a/dir.c b/dir.c index 22d0b7b..32d1c90 100644 --- a/dir.c +++ b/dir.c @@ -522,6 +522,53 @@ static int match_basename(const char *basename, int basenamelen, return 0; } +static int match_pathname(const char *pathname, int pathlen, + const char *base, int baselen, + const char *pattern, int prefix, int patternlen, + int flags) +{ + const char *name; + int namelen; + + /* +* match with FNM_PATHNAME; the pattern has base implicitly +* in front of it. +*/ + if (*pattern == '/') { + pattern++; + prefix--; + } + + /* +* baselen does not count the trailing slash. base[] may or +* may not end with a trailing slash though. +*/ + if (pathlen < baselen + 1 || + (baselen && pathname[baselen] != '/') || + strncmp_icase(pathname, base, baselen)) + return 0; + + namelen = baselen ? pathlen - baselen - 1 : pathlen; + name = pathname + pathlen - namelen; + + if (prefix) { + /* +* if the non-wildcard part is longer than the +* remaining pathname, surely it cannot match. +*/ + if (prefix > namelen) + return 0; + + if (strncmp_icase(pattern, name, prefix)) + return 0; + pattern += prefix; + name+= prefix; + namelen -= prefix; + } + + return fnmatch_icase(pattern, name, FNM_PATHNAME) == 0; +} + /* Scan the list and let the last match determine the fate. * Return 1 for exclude, 0 for include and -1 for undecided. */ @@ -536,9 +583,9 @@ int excluded_from_list(const char *pathname, for (i = el->nr - 1; 0 <= i; i--) { struct exclude *x = el->excludes[i]; - const char *name, *exclude = x->pattern; + const char *exclude = x->pattern; int to_exclude = x->to_exclude; - int namelen, prefix = x->nowildcardlen; + int prefix = x->nowildcardlen; if (x->flags & EXC_FLAG_MUSTBEDIR) { if (*dtype == DT_UNKNOWN) @@ -556,36 +603,10 @@ int excluded_from_list(const char *pathname, continue; } - /* match with FNM_PATHNAME: -* exclude has base (baselen long) implicitly in front of it. -*/ - if (*exclude == '/') { - exclude++; - prefix--; - } - - if (pathlen < x->baselen || - (x->baselen && pathname[x->baselen-1] != '/') || - strncmp_icase(pathname, x->base, x->baselen)) - continue; - - namelen = x->baselen ? pathlen - x->baselen : pathlen; - name = pathname + pathlen - namelen; - - /* if the non-wildcard part is longer than the - remaining pathname, surely it cannot match */ - if (prefix > namelen) - continue; - - if (prefix) { - if (strncmp_icase(exclude, name, prefix)) - continue; - exclude += prefix; - name+= prefix; - namelen -= prefix; - } - - if (!fnmatch_icase(exclude, name, FNM_PATHNAME)) + assert(x->baselen == 0 || x->base[x->baselen - 1] == '/'); + if (match_pathname(pathname, pathlen, + x->base, x->baselen ? x->baselen - 1 : 0, + exclude, prefix, x->patternlen, x->flags)) return to_exclude; } return -1; /* undecided */ -- 1.8.0.rc0.29.g1fdd78f -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 5/6] gitignore: make pattern parsing code a separate function
This function can later be reused by attr.c. Also turn to_exclude field into a flag. Signed-off-by: Junio C Hamano Signed-off-by: Nguyễn Thái Ngọc Duy --- dir.c | 71 ++- dir.h | 2 +- 2 files changed, 50 insertions(+), 23 deletions(-) diff --git a/dir.c b/dir.c index 32d1c90..c4e64a5 100644 --- a/dir.c +++ b/dir.c @@ -308,42 +308,69 @@ static int no_wildcard(const char *string) return string[simple_length(string)] == '\0'; } +static void parse_exclude_pattern(const char **pattern, + int *patternlen, + int *flags, + int *nowildcardlen) +{ + const char *p = *pattern; + size_t i, len; + + *flags = 0; + if (*p == '!') { + *flags |= EXC_FLAG_NEGATIVE; + p++; + } + len = strlen(p); + if (len && p[len - 1] == '/') { + len--; + *flags |= EXC_FLAG_MUSTBEDIR; + } + for (i = 0; i < len; i++) { + if (p[i] == '/') + break; + } + if (i == len) + *flags |= EXC_FLAG_NODIR; + *nowildcardlen = simple_length(p); + /* +* we should have excluded the trailing slash from 'p' too, +* but that's one more allocation. Instead just make sure +* nowildcardlen does not exceed real patternlen +*/ + if (*nowildcardlen > len) + *nowildcardlen = len; + if (*p == '*' && no_wildcard(p + 1)) + *flags |= EXC_FLAG_ENDSWITH; + *pattern = p; + *patternlen = len; +} + void add_exclude(const char *string, const char *base, int baselen, struct exclude_list *which) { struct exclude *x; - size_t len; - int to_exclude = 1; - int flags = 0; + int patternlen; + int flags; + int nowildcardlen; - if (*string == '!') { - to_exclude = 0; - string++; - } - len = strlen(string); - if (len && string[len - 1] == '/') { + parse_exclude_pattern(&string, &patternlen, &flags, &nowildcardlen); + if (flags & EXC_FLAG_MUSTBEDIR) { char *s; - x = xmalloc(sizeof(*x) + len); + x = xmalloc(sizeof(*x) + patternlen + 1); s = (char *)(x+1); - memcpy(s, string, len - 1); - s[len - 1] = '\0'; - string = s; + memcpy(s, string, patternlen); + s[patternlen] = '\0'; x->pattern = s; - flags = EXC_FLAG_MUSTBEDIR; } else { x = xmalloc(sizeof(*x)); x->pattern = string; } - x->to_exclude = to_exclude; - x->patternlen = strlen(string); + x->patternlen = patternlen; + x->nowildcardlen = nowildcardlen; x->base = base; x->baselen = baselen; x->flags = flags; - if (!strchr(string, '/')) - x->flags |= EXC_FLAG_NODIR; - x->nowildcardlen = simple_length(string); - if (*string == '*' && no_wildcard(string+1)) - x->flags |= EXC_FLAG_ENDSWITH; ALLOC_GROW(which->excludes, which->nr + 1, which->alloc); which->excludes[which->nr++] = x; } @@ -584,7 +611,7 @@ int excluded_from_list(const char *pathname, for (i = el->nr - 1; 0 <= i; i--) { struct exclude *x = el->excludes[i]; const char *exclude = x->pattern; - int to_exclude = x->to_exclude; + int to_exclude = x->flags & EXC_FLAG_NEGATIVE ? 0 : 1; int prefix = x->nowildcardlen; if (x->flags & EXC_FLAG_MUSTBEDIR) { diff --git a/dir.h b/dir.h index 893465a..41ea32d 100644 --- a/dir.h +++ b/dir.h @@ -11,6 +11,7 @@ struct dir_entry { #define EXC_FLAG_NODIR 1 #define EXC_FLAG_ENDSWITH 4 #define EXC_FLAG_MUSTBEDIR 8 +#define EXC_FLAG_NEGATIVE 16 struct exclude_list { int nr; @@ -21,7 +22,6 @@ struct exclude_list { int nowildcardlen; const char *base; int baselen; - int to_exclude; int flags; } **excludes; }; -- 1.8.0.rc0.29.g1fdd78f -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 6/6] attr: more matching optimizations from .gitignore
.gitattributes and .gitignore share the same pattern syntax but has separate matching implementation. Over the years, ignore's implementation accumulates more optimizations while attr's stays the same. This patch reuses the core matching functions that are also used by excluded_from_list. excluded_from_list and path_matches can't be merged due to differences in exclude and attr, for example: * "!pattern" syntax is forbidden in .gitattributes. As an attribute can be unset (i.e. set to a special value "false") or made back to unspecified (i.e. not even set to "false"), "!pattern attr" is unclear which one it means. * we support attaching attributes to directories, but git-core internally does not currently make use of attributes on directories. Signed-off-by: Nguyễn Thái Ngọc Duy --- Documentation/gitattributes.txt | 1 + attr.c | 52 - dir.c | 22 - dir.h | 11 + t/t0003-attributes.sh | 10 5 files changed, 64 insertions(+), 32 deletions(-) diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt index 80120ea..b7c0e65 100644 --- a/Documentation/gitattributes.txt +++ b/Documentation/gitattributes.txt @@ -56,6 +56,7 @@ When more than one pattern matches the path, a later line overrides an earlier line. This overriding is done per attribute. The rules how the pattern matches paths are the same as in `.gitignore` files; see linkgit:gitignore[5]. +Unlike `.gitignore`, negative patterns are forbidden. When deciding what attributes are assigned to a path, git consults `$GIT_DIR/info/attributes` file (which has the highest diff --git a/attr.c b/attr.c index e7caee4..2fc6353 100644 --- a/attr.c +++ b/attr.c @@ -115,6 +115,13 @@ struct attr_state { const char *setto; }; +struct pattern { + const char *pattern; + int patternlen; + int nowildcardlen; + int flags; /* EXC_FLAG_* */ +}; + /* * One rule, as from a .gitattributes file. * @@ -131,7 +138,7 @@ struct attr_state { */ struct match_attr { union { - char *pattern; + struct pattern pat; struct git_attr *attr; } u; char is_macro; @@ -241,9 +248,16 @@ static struct match_attr *parse_attr_line(const char *line, const char *src, if (is_macro) res->u.attr = git_attr_internal(name, namelen); else { - res->u.pattern = (char *)&(res->state[num_attr]); - memcpy(res->u.pattern, name, namelen); - res->u.pattern[namelen] = 0; + char *p = (char *)&(res->state[num_attr]); + memcpy(p, name, namelen); + res->u.pat.pattern = p; + parse_exclude_pattern(&res->u.pat.pattern, + &res->u.pat.patternlen, + &res->u.pat.flags, + &res->u.pat.nowildcardlen); + if (res->u.pat.flags & EXC_FLAG_NEGATIVE) + die(_("Negative patterns are forbidden in git attributes\n" + "Use '\\!' for literal leading exclamation.")); } res->is_macro = is_macro; res->num_attr = num_attr; @@ -640,25 +654,21 @@ static void prepare_attr_stack(const char *path) static int path_matches(const char *pathname, int pathlen, const char *basename, - const char *pattern, + const struct pattern *pat, const char *base, int baselen) { - if (!strchr(pattern, '/')) { - return (fnmatch_icase(pattern, basename, 0) == 0); + const char *pattern = pat->pattern; + int prefix = pat->nowildcardlen; + + if (pat->flags & EXC_FLAG_NODIR) { + return match_basename(basename, + pathlen - (basename - pathname), + pattern, prefix, + pat->patternlen, pat->flags); } - /* -* match with FNM_PATHNAME; the pattern has base implicitly -* in front of it. -*/ - if (*pattern == '/') - pattern++; - if (pathlen < baselen || - (baselen && pathname[baselen] != '/') || - strncmp(pathname, base, baselen)) - return 0; - if (baselen != 0) - baselen++; - return fnmatch_icase(pattern, pathname + baselen, FNM_PATHNAME) == 0; + return match_pathname(pathname, pathlen, + base, baselen, + pattern, prefix, pat->patternlen, pat->flags); } static int macroexpand_one(int attr_nr, int rem); @@ -696,7 +706,7 @@ static int fill(const char *path, int pathlen, const char *basename,
[PATCH 01/13] ctype: make sane_ctype[] const array
Signed-off-by: Nguyễn Thái Ngọc Duy --- ctype.c | 2 +- git-compat-util.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ctype.c b/ctype.c index 9353271..faeaf34 100644 --- a/ctype.c +++ b/ctype.c @@ -14,7 +14,7 @@ enum { P = GIT_PATHSPEC_MAGIC /* other non-alnum, except for ] and } */ }; -unsigned char sane_ctype[256] = { +const unsigned char sane_ctype[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, S, S, 0, 0, S, 0, 0, /* 0.. 15 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16.. 31 */ S, P, P, P, R, P, P, P, R, R, G, R, P, P, R, P, /* 32.. 47 */ diff --git a/git-compat-util.h b/git-compat-util.h index 5bd9ad7..80767ff 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -470,7 +470,7 @@ extern const char tolower_trans_tbl[256]; #undef isupper #undef tolower #undef toupper -extern unsigned char sane_ctype[256]; +extern const unsigned char sane_ctype[256]; #define GIT_SPACE 0x01 #define GIT_DIGIT 0x02 #define GIT_ALPHA 0x04 -- 1.8.0.rc0.29.g1fdd78f -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 02/13] ctype: support iscntrl, ispunct, isxdigit and isprint
Signed-off-by: Nguyễn Thái Ngọc Duy --- ctype.c | 13 - git-compat-util.h | 13 + 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/ctype.c b/ctype.c index faeaf34..0bfebb4 100644 --- a/ctype.c +++ b/ctype.c @@ -11,18 +11,21 @@ enum { D = GIT_DIGIT, G = GIT_GLOB_SPECIAL, /* *, ?, [, \\ */ R = GIT_REGEX_SPECIAL, /* $, (, ), +, ., ^, {, | */ - P = GIT_PATHSPEC_MAGIC /* other non-alnum, except for ] and } */ + P = GIT_PATHSPEC_MAGIC, /* other non-alnum, except for ] and } */ + X = GIT_CNTRL, + U = GIT_PUNCT, + Z = GIT_CNTRL | GIT_SPACE }; const unsigned char sane_ctype[256] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, S, S, 0, 0, S, 0, 0, /* 0.. 15 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16.. 31 */ + X, X, X, X, X, X, X, X, X, Z, Z, X, X, Z, X, X, /* 0.. 15 */ + X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, /* 16.. 31 */ S, P, P, P, R, P, P, P, R, R, G, R, P, P, R, P, /* 32.. 47 */ D, D, D, D, D, D, D, D, D, D, P, P, P, P, P, G, /* 48.. 63 */ P, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, /* 64.. 79 */ - A, A, A, A, A, A, A, A, A, A, A, G, G, 0, R, P, /* 80.. 95 */ + A, A, A, A, A, A, A, A, A, A, A, G, G, U, R, P, /* 80.. 95 */ P, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, /* 96..111 */ - A, A, A, A, A, A, A, A, A, A, A, R, R, 0, P, 0, /* 112..127 */ + A, A, A, A, A, A, A, A, A, A, A, R, R, U, P, X, /* 112..127 */ /* Nothing in the 128.. range */ }; diff --git a/git-compat-util.h b/git-compat-util.h index 80767ff..02f48f6 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -470,6 +470,10 @@ extern const char tolower_trans_tbl[256]; #undef isupper #undef tolower #undef toupper +#undef iscntrl +#undef ispunct +#undef isxdigit +#undef isprint extern const unsigned char sane_ctype[256]; #define GIT_SPACE 0x01 #define GIT_DIGIT 0x02 @@ -477,6 +481,8 @@ extern const unsigned char sane_ctype[256]; #define GIT_GLOB_SPECIAL 0x08 #define GIT_REGEX_SPECIAL 0x10 #define GIT_PATHSPEC_MAGIC 0x20 +#define GIT_CNTRL 0x40 +#define GIT_PUNCT 0x80 #define sane_istest(x,mask) ((sane_ctype[(unsigned char)(x)] & (mask)) != 0) #define isascii(x) (((x) & ~0x7f) == 0) #define isspace(x) sane_istest(x,GIT_SPACE) @@ -487,6 +493,13 @@ extern const unsigned char sane_ctype[256]; #define isupper(x) sane_iscase(x, 0) #define is_glob_special(x) sane_istest(x,GIT_GLOB_SPECIAL) #define is_regex_special(x) sane_istest(x,GIT_GLOB_SPECIAL | GIT_REGEX_SPECIAL) +#define iscntrl(x) (sane_istest(x,GIT_CNTRL)) +#define ispunct(x) sane_istest(x, GIT_PUNCT | GIT_REGEX_SPECIAL | \ + GIT_GLOB_SPECIAL | GIT_PATHSPEC_MAGIC) +#define isxdigit(x) (hexval_table[x] != -1) +#define isprint(x) (sane_istest(x, GIT_ALPHA | GIT_DIGIT | GIT_SPACE | \ + GIT_PUNCT | GIT_REGEX_SPECIAL | GIT_GLOB_SPECIAL | \ + GIT_PATHSPEC_MAGIC)) #define tolower(x) sane_case((unsigned char)(x), 0x20) #define toupper(x) sane_case((unsigned char)(x), 0) #define is_pathspec_magic(x) sane_istest(x,GIT_PATHSPEC_MAGIC) -- 1.8.0.rc0.29.g1fdd78f -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 03/13] Import wildmatch from rsync
These files are from rsync.git commit f92f5b166e3019db42bc7fe1aa2f1a9178cd215d, which was the last commit before rsync turned GPL-3. All files are imported as-is and no-op. Adaptation is done in a separate patch. rsync.git -> git.git lib/wildmatch.[ch] wildmatch.[ch] wildtest.txtt/t3070/wildtest.txt Signed-off-by: Nguyễn Thái Ngọc Duy --- t/t3070/wildtest.txt | 165 +++ wildmatch.c | 368 +++ wildmatch.h | 6 + 3 files changed, 539 insertions(+) create mode 100644 t/t3070/wildtest.txt create mode 100644 wildmatch.c create mode 100644 wildmatch.h diff --git a/t/t3070/wildtest.txt b/t/t3070/wildtest.txt new file mode 100644 index 000..42c1678 --- /dev/null +++ b/t/t3070/wildtest.txt @@ -0,0 +1,165 @@ +# Input is in the following format (all items white-space separated): +# +# The first two items are 1 or 0 indicating if the wildmat call is expected to +# succeed and if fnmatch works the same way as wildmat, respectively. After +# that is a text string for the match, and a pattern string. Strings can be +# quoted (if desired) in either double or single quotes, as well as backticks. +# +# MATCH FNMATCH_SAME "text to match" 'pattern to use' + +# Basic wildmat features +1 1 foofoo +0 1 foobar +1 1 '' "" +1 1 foo??? +0 1 foo?? +1 1 foo* +1 1 foof* +0 1 foo*f +1 1 foo*foo* +1 1 foobar *ob*a*r* +1 1 aaabababab *ab +1 1 foo* foo\* +0 1 foobar foo\*bar +1 1 f\oo f\\oo +1 1 ball *[al]? +0 1 ten[ten] +1 1 ten**[!te] +0 1 ten**[!ten] +1 1 tent[a-g]n +0 1 tent[!a-g]n +1 1 tont[!a-g]n +1 1 tont[^a-g]n +1 1 a]ba[]]b +1 1 a-ba[]-]b +1 1 a]ba[]-]b +0 1 aaba[]-]b +1 1 aaba[]a-]b +1 1 ] ] + +# Extended slash-matching features +0 1 foo/baz/barfoo*bar +1 1 foo/baz/barfoo**bar +0 1 foo/barfoo?bar +0 1 foo/barfoo[/]bar +0 1 foo/barf[^eiu][^eiu][^eiu][^eiu][^eiu]r +1 1 foo-barf[^eiu][^eiu][^eiu][^eiu][^eiu]r +0 1 foo**/foo +1 1 /foo **/foo +1 1 bar/baz/foo**/foo +0 1 bar/baz/foo*/foo +0 0 foo/bar/baz**/bar* +1 1 deep/foo/bar/baz **/bar/* +0 1 deep/foo/bar/baz/ **/bar/* +1 1 deep/foo/bar/baz/ **/bar/** +0 1 deep/foo/bar **/bar/* +1 1 deep/foo/bar/ **/bar/** +1 1 foo/bar/baz**/bar** +1 1 foo/bar/baz/x */bar/** +0 0 deep/foo/bar/baz/x */bar/** +1 1 deep/foo/bar/baz/x **/bar/*/* + +# Various additional tests +0 1 acrt a[c-c]st +1 1 acrt a[c-c]rt +0 1 ] [!]-] +1 1 a [!]-] +0 1 '' \ +0 1 \ \ +0 1 /\ */\ +1 1 /\ */\\ +1 1 foofoo +1 1 @foo @foo +0 1 foo@foo +1 1 [ab] \[ab] +1 1 [ab] [[]ab] +1 1 [ab] [[:]ab] +0 1 [ab] [[::]ab] +1 1 [ab] [[:digit]ab] +1 1 [ab] [\[:]ab] +1 1 ?a?b \??\?b +1 1 abc\a\b\c +0 1 foo'' +1 1 foo/bar/baz/to **/t[o] + +# Character class tests +1 1 a1B[[:alpha:]][[:digit:]][[:upper:]] +0 1 a [[:digit:][:upper:][:space:]] +1 1 A [[:digit:][:upper:][:space:]] +1 1 1 [[:digit:][:upper:][:space:]] +0 1 1 [[:digit:][:upper:][:spaci:]] +1 1 ' '[[:digit:][:upper:][:space:]] +0 1 . [[:digit:][:upper:][:space:]] +1 1 . [[:digit:][:punct:][:space:]] +1 1 5 [[:xdigit:]] +1 1 f [[:xdigit:]] +1 1 D [[:xdigit:]] +1 1 _ [[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]] +#1 1 � [^[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]] +1 1 [^[:alnum:][:alpha:][:blank:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]] +1 1 . [^[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:lower:][:space:][:upper:][:xdigit:]] +1 1 5 [a-c[:digit:]x-z] +1 1 b [a-c[:digit:]x-z] +1 1 y [a-c[:digit:]x-z] +0 1 q [a-c[:digit:]x-z] + +# Additional tests, including some malformed wildmats +1 1 ]
[PATCH 04/13] wildmatch: remove unnecessary functions
Signed-off-by: Nguyễn Thái Ngọc Duy --- wildmatch.c | 164 wildmatch.h | 2 - 2 files changed, 10 insertions(+), 156 deletions(-) diff --git a/wildmatch.c b/wildmatch.c index f3a1731..fae7397 100644 --- a/wildmatch.c +++ b/wildmatch.c @@ -53,33 +53,18 @@ #define ISUPPER(c) (ISASCII(c) && isupper(c)) #define ISXDIGIT(c) (ISASCII(c) && isxdigit(c)) -#ifdef WILD_TEST_ITERATIONS -int wildmatch_iteration_count; -#endif - static int force_lower_case = 0; -/* Match pattern "p" against the a virtually-joined string consisting - * of "text" and any strings in array "a". */ -static int dowild(const uchar *p, const uchar *text, const uchar*const *a) +/* Match pattern "p" against "text" */ +static int dowild(const uchar *p, const uchar *text) { uchar p_ch; -#ifdef WILD_TEST_ITERATIONS -wildmatch_iteration_count++; -#endif - for ( ; (p_ch = *p) != '\0'; text++, p++) { int matched, special; uchar t_ch, prev_ch; - while ((t_ch = *text) == '\0') { - if (*a == NULL) { - if (p_ch != '*') - return ABORT_ALL; - break; - } - text = *a++; - } + if ((t_ch = *text) == '\0' && p_ch != '*') + return ABORT_ALL; if (force_lower_case && ISUPPER(t_ch)) t_ch = tolower(t_ch); switch (p_ch) { @@ -107,21 +92,15 @@ static int dowild(const uchar *p, const uchar *text, const uchar*const *a) /* Trailing "**" matches everything. Trailing "*" matches * only if there are no more slash characters. */ if (!special) { - do { if (strchr((char*)text, '/') != NULL) return FALSE; - } while ((text = *a++) != NULL); } return TRUE; } while (1) { - if (t_ch == '\0') { - if ((text = *a++) == NULL) - break; - t_ch = *text; - continue; - } - if ((matched = dowild(p, text, a)) != FALSE) { + if (t_ch == '\0') + break; + if ((matched = dowild(p, text)) != FALSE) { if (!special || matched != ABORT_TO_STARSTAR) return matched; } else if (!special && t_ch == '/') @@ -225,144 +204,21 @@ static int dowild(const uchar *p, const uchar *text, const uchar*const *a) } } -do { - if (*text) - return FALSE; -} while ((text = *a++) != NULL); - -return TRUE; -} - -/* Match literal string "s" against the a virtually-joined string consisting - * of "text" and any strings in array "a". */ -static int doliteral(const uchar *s, const uchar *text, const uchar*const *a) -{ -for ( ; *s != '\0'; text++, s++) { - while (*text == '\0') { - if ((text = *a++) == NULL) - return FALSE; - } - if (*text != *s) - return FALSE; -} - -do { - if (*text) - return FALSE; -} while ((text = *a++) != NULL); - -return TRUE; -} - -/* Return the last "count" path elements from the concatenated string. - * We return a string pointer to the start of the string, and update the - * array pointer-pointer to point to any remaining string elements. */ -static const uchar *trailing_N_elements(const uchar*const **a_ptr, int count) -{ -const uchar*const *a = *a_ptr; -const uchar*const *first_a = a; - -while (*a) - a++; - -while (a != first_a) { - const uchar *s = *--a; - s += strlen((char*)s); - while (--s >= *a) { - if (*s == '/' && !--count) { - *a_ptr = a+1; - return s+1; - } - } -} - -if (count == 1) { - *a_ptr = a+1; - return *a; -} - -return NULL; +return *text ? FALSE : TRUE; } /* Match the "pattern" against the "text" string. */ int wildmatch(const char *pattern, const char *text) { -static const uchar *nomore[1]; /* A NULL pointer. */ -#ifdef WILD_TEST_ITERATIONS -wildmatch_iteration_count = 0; -#endif -return dowild((const uchar*)pattern, (const uchar*)text, nomore) == TRUE; +return dowild((const uchar*)pattern, (const uchar*)text) == TRUE; } /* Match the "pattern" against the forced-to-lower-case "text" string. */ int iwildmatch(const char *pattern, const char *text) { -static const uchar *nomore[1]; /* A NULL pointer. */ int ret; -#ifdef WILD_TEST_ITERATIONS -wildmatch_iteration_count = 0; -#endif force_lower_case = 1; -ret = dowild((const uchar*)pattern, (const uchar*)text, nomore) == TRUE; +ret = dowild((const uchar*)pattern, (const uchar*)text) == TRUE; force_lower_case = 0; return ret; } - -/* Match pattern "p" against the a virtu
[PATCH 05/13] wildmatch: follow Git's coding convention
wildmatch's coding style is pretty close to Git's except the use of 4 space indentation instead of 8. This patch should produce empty diff with "git diff -b" Signed-off-by: Nguyễn Thái Ngọc Duy --- wildmatch.c | 292 ++-- 1 file changed, 146 insertions(+), 146 deletions(-) diff --git a/wildmatch.c b/wildmatch.c index fae7397..4653dd6 100644 --- a/wildmatch.c +++ b/wildmatch.c @@ -58,167 +58,167 @@ static int force_lower_case = 0; /* Match pattern "p" against "text" */ static int dowild(const uchar *p, const uchar *text) { -uchar p_ch; + uchar p_ch; -for ( ; (p_ch = *p) != '\0'; text++, p++) { - int matched, special; - uchar t_ch, prev_ch; - if ((t_ch = *text) == '\0' && p_ch != '*') - return ABORT_ALL; - if (force_lower_case && ISUPPER(t_ch)) - t_ch = tolower(t_ch); - switch (p_ch) { - case '\\': - /* Literal match with following character. Note that the test -* in "default" handles the p[1] == '\0' failure case. */ - p_ch = *++p; - /* FALLTHROUGH */ - default: - if (t_ch != p_ch) - return FALSE; - continue; - case '?': - /* Match anything but '/'. */ - if (t_ch == '/') - return FALSE; - continue; - case '*': - if (*++p == '*') { - while (*++p == '*') {} - special = TRUE; - } else - special = FALSE; - if (*p == '\0') { - /* Trailing "**" matches everything. Trailing "*" matches -* only if there are no more slash characters. */ - if (!special) { - if (strchr((char*)text, '/') != NULL) - return FALSE; - } - return TRUE; - } - while (1) { - if (t_ch == '\0') - break; - if ((matched = dowild(p, text)) != FALSE) { - if (!special || matched != ABORT_TO_STARSTAR) - return matched; - } else if (!special && t_ch == '/') - return ABORT_TO_STARSTAR; - t_ch = *++text; - } - return ABORT_ALL; - case '[': - p_ch = *++p; -#ifdef NEGATE_CLASS2 - if (p_ch == NEGATE_CLASS2) - p_ch = NEGATE_CLASS; -#endif - /* Assign literal TRUE/FALSE because of "matched" comparison. */ - special = p_ch == NEGATE_CLASS? TRUE : FALSE; - if (special) { - /* Inverted character class. */ - p_ch = *++p; - } - prev_ch = 0; - matched = FALSE; - do { - if (!p_ch) - return ABORT_ALL; - if (p_ch == '\\') { - p_ch = *++p; - if (!p_ch) + for ( ; (p_ch = *p) != '\0'; text++, p++) { + int matched, special; + uchar t_ch, prev_ch; + if ((t_ch = *text) == '\0' && p_ch != '*') return ABORT_ALL; - if (t_ch == p_ch) - matched = TRUE; - } else if (p_ch == '-' && prev_ch && p[1] && p[1] != ']') { - p_ch = *++p; - if (p_ch == '\\') { + if (force_lower_case && ISUPPER(t_ch)) + t_ch = tolower(t_ch); + switch (p_ch) { + case '\\': + /* Literal match with following character. Note that the test +* in "default" handles the p[1] == '\0' failure case. */ p_ch = *++p; - if (!p_ch) - return ABORT_ALL; - } - if (t_ch <= p_ch && t_ch >= prev_ch) - matched = TRUE; - p_ch = 0; /* This makes "prev_ch" get set to 0. */ - } else if (p_ch == '[' && p[1] == ':') { - const uchar *s; - int i; - for (s = p += 2; (p_ch = *p) && p_ch != ']'; p++) {} /*SHARED ITERATOR*/ - if (!p_ch) - return ABORT_ALL; - i = p - s - 1; - if (i < 0 || p[-1] != ':') { - /* Didn't find ":]", so treat like a normal set. */ - p = s - 2; - p_ch = '['; - if (t_ch == p_ch) - matched = TRUE; + /* FALLTHROUGH */ + default: + if (t_ch != p_ch) + return FALSE; + continue; + case '?': + /* Match anything but '/'. */ + if (t_ch
[PATCH 06/13] Integrate wildmatch to git
Signed-off-by: Nguyễn Thái Ngọc Duy --- .gitignore | 1 + Makefile | 3 + t/t3070-wildmatch.sh | 188 +++ t/t3070/wildtest.txt | 165 test-wildmatch.c | 14 wildmatch.c | 5 +- 6 files changed, 210 insertions(+), 166 deletions(-) create mode 100755 t/t3070-wildmatch.sh delete mode 100644 t/t3070/wildtest.txt create mode 100644 test-wildmatch.c diff --git a/.gitignore b/.gitignore index f1acd3e..1153a4b 100644 --- a/.gitignore +++ b/.gitignore @@ -193,6 +193,7 @@ /test-sigchain /test-subprocess /test-svn-fe +/test-wildmatch /common-cmds.h *.tar.gz *.dsc diff --git a/Makefile b/Makefile index 13293d3..bc868d1 100644 --- a/Makefile +++ b/Makefile @@ -503,6 +503,7 @@ TEST_PROGRAMS_NEED_X += test-sha1 TEST_PROGRAMS_NEED_X += test-sigchain TEST_PROGRAMS_NEED_X += test-subprocess TEST_PROGRAMS_NEED_X += test-svn-fe +TEST_PROGRAMS_NEED_X += test-wildmatch TEST_PROGRAMS = $(patsubst %,%$X,$(TEST_PROGRAMS_NEED_X)) @@ -674,6 +675,7 @@ LIB_H += unpack-trees.h LIB_H += userdiff.h LIB_H += utf8.h LIB_H += varint.h +LIB_H += wildmatch.h LIB_H += xdiff-interface.h LIB_H += xdiff/xdiff.h @@ -803,6 +805,7 @@ LIB_OBJS += userdiff.o LIB_OBJS += utf8.o LIB_OBJS += varint.o LIB_OBJS += walker.o +LIB_OBJS += wildmatch.o LIB_OBJS += wrapper.o LIB_OBJS += write_or_die.o LIB_OBJS += ws.o diff --git a/t/t3070-wildmatch.sh b/t/t3070-wildmatch.sh new file mode 100755 index 000..dbd3c8b --- /dev/null +++ b/t/t3070-wildmatch.sh @@ -0,0 +1,188 @@ +#!/bin/sh + +test_description='wildmatch tests' + +. ./test-lib.sh + +match() { +if [ $1 = 1 ]; then + test_expect_success "wildmatch:match '$3' '$4'" " + test-wildmatch wildmatch '$3' '$4' + " +else + test_expect_success "wildmatch: no match '$3' '$4'" " + ! test-wildmatch wildmatch '$3' '$4' + " +fi +if [ $2 = 1 ]; then + test_expect_success "fnmatch: match '$3' '$4'" " + test-wildmatch fnmatch '$3' '$4' + " +elif [ $2 = 0 ]; then + test_expect_success "fnmatch: no match '$3' '$4'" " + ! test-wildmatch fnmatch '$3' '$4' + " +#else +# test_expect_success BROKEN_FNMATCH "fnmatch: '$3' '$4'" " +# ! test-wildmatch fnmatch '$3' '$4' +# " +fi +} + +# Basic wildmat features +match 1 1 foo foo +match 0 0 foo bar +match 1 1 '' "" +match 1 1 foo '???' +match 0 0 foo '??' +match 1 1 foo '*' +match 1 1 foo 'f*' +match 0 0 foo '*f' +match 1 1 foo '*foo*' +match 1 1 foobar '*ob*a*r*' +match 1 1 aaabababab '*ab' +match 1 1 'foo*' 'foo\*' +match 0 0 foobar 'foo\*bar' +match 1 1 'f\oo' 'f\\oo' +match 1 1 ball '*[al]?' +match 0 0 ten '[ten]' +match 1 1 ten '**[!te]' +match 0 0 ten '**[!ten]' +match 1 1 ten 't[a-g]n' +match 0 0 ten 't[!a-g]n' +match 1 1 ton 't[!a-g]n' +match 1 1 ton 't[^a-g]n' +match 1 1 'a]b' 'a[]]b' +match 1 1 a-b 'a[]-]b' +match 1 1 'a]b' 'a[]-]b' +match 0 0 aab 'a[]-]b' +match 1 1 aab 'a[]a-]b' +match 1 1 ']' ']' + +# Extended slash-matching features +match 0 0 'foo/baz/bar' 'foo*bar' +match 1 0 'foo/baz/bar' 'foo**bar' +match 0 0 'foo/bar' 'foo?bar' +match 0 0 'foo/bar' 'foo[/]bar' +match 0 0 'foo/bar' 'f[^eiu][^eiu][^eiu][^eiu][^eiu]r' +match 1 1 'foo-bar' 'f[^eiu][^eiu][^eiu][^eiu][^eiu]r' +match 0 0 'foo' '**/foo' +match 1 1 '/foo' '**/foo' +match 1 0 'bar/baz/foo' '**/foo' +match 0 0 'bar/baz/foo' '*/foo' +match 0 0 'foo/bar/baz' '**/bar*' +match 1 0 'deep/foo/bar/baz' '**/bar/*' +match 0 0 'deep/foo/bar/baz/' '**/bar/*' +match 1 0 'deep/foo/bar/baz/' '**/bar/**' +match 0 0 'deep/foo/bar' '**/bar/*' +match 1 0 'deep/foo/bar/' '**/bar/**' +match 1 0 'foo/bar/baz' '**/bar**' +match 1 0 'foo/bar/baz/x' '*/bar/**' +match 0 0 'deep/foo/bar/baz/x' '*/bar/**' +match 1 0 'deep/foo/bar/baz/x' '**/bar/*/*' + +# Various additional tests +match 0 0 'acrt' 'a[c-c]st' +match 1 1 'acrt' 'a[c-c]rt' +match 0 0 ']' '[!]-]' +match 1 1 'a' '[!]-]' +match 0 0 '' '\' +match 0 0 '\' '\' +match 0 0 '/\' '*/\' +match 1 1 '/\' '*/\\' +match 1 1 'foo' 'foo' +match 1 1 '@foo' '@foo' +match 0 0 'foo' '@foo' +match 1 1 '[ab]' '\[ab]' +match 1 1 '[ab]' '[[]ab]' +match 1 1 '[ab]' '[[:]ab]' +match 0 0 '[ab]' '[[::]ab]' +match 1 1 '[ab]' '[[:digit]ab]' +match 1 1 '[ab]' '[\[:]ab]' +match 1 1 '?a?b' '\??\?b' +match 1 1 'abc' '\a\b\c' +match 0 0 'foo' '' +match 1 0 'foo/bar/baz/to' '**/t[o]' + +# Character class tests +match 1 1 'a1B' '[[:alpha:]][[:digit:]][[:upper:]]' +match 0 0 'a' '[[:digit:][:upper:][:space:]]' +match 1 1 'A' '[[:digit:][:upper:][:space:]]' +match 1 0 '1' '[[:digit:][:upper:][:space:]]' +match 0 0 '1' '[[:digit:][:upper:][:spaci:]]' +match 1 1 ' ' '[[:digit:][:upper:][:space:]]' +match 0 0 '.' '[[:digit:][:upper:][:space:]]' +match 1 1 '.' '[[:digit:][:punct:][:space:]]' +match 1 1 '5' '[[:xdigit:]]' +match 1 1 'f' '[[:xdigit:]]' +match 1 1 'D' '[[:xdigit:]]' +match 1 0 '_
[PATCH 07/13] t3070: disable unreliable fnmatch tests
These tests show different results on different fnmatch() versions. We don't want to test fnmatch here. We want to make sure wildmatch behavior matches fnmatch and that only makes sense in cases when fnmatch() behaves consistently. Signed-off-by: Nguyễn Thái Ngọc Duy --- t/t3070-wildmatch.sh | 86 ++-- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/t/t3070-wildmatch.sh b/t/t3070-wildmatch.sh index dbd3c8b..dd95b00 100755 --- a/t/t3070-wildmatch.sh +++ b/t/t3070-wildmatch.sh @@ -52,11 +52,11 @@ match 1 1 ten 't[a-g]n' match 0 0 ten 't[!a-g]n' match 1 1 ton 't[!a-g]n' match 1 1 ton 't[^a-g]n' -match 1 1 'a]b' 'a[]]b' -match 1 1 a-b 'a[]-]b' -match 1 1 'a]b' 'a[]-]b' -match 0 0 aab 'a[]-]b' -match 1 1 aab 'a[]a-]b' +match 1 x 'a]b' 'a[]]b' +match 1 x a-b 'a[]-]b' +match 1 x 'a]b' 'a[]-]b' +match 0 x aab 'a[]-]b' +match 1 x aab 'a[]a-]b' match 1 1 ']' ']' # Extended slash-matching features @@ -67,7 +67,7 @@ match 0 0 'foo/bar' 'foo[/]bar' match 0 0 'foo/bar' 'f[^eiu][^eiu][^eiu][^eiu][^eiu]r' match 1 1 'foo-bar' 'f[^eiu][^eiu][^eiu][^eiu][^eiu]r' match 0 0 'foo' '**/foo' -match 1 1 '/foo' '**/foo' +match 1 x '/foo' '**/foo' match 1 0 'bar/baz/foo' '**/foo' match 0 0 'bar/baz/foo' '*/foo' match 0 0 'foo/bar/baz' '**/bar*' @@ -85,77 +85,77 @@ match 1 0 'deep/foo/bar/baz/x' '**/bar/*/*' match 0 0 'acrt' 'a[c-c]st' match 1 1 'acrt' 'a[c-c]rt' match 0 0 ']' '[!]-]' -match 1 1 'a' '[!]-]' +match 1 x 'a' '[!]-]' match 0 0 '' '\' -match 0 0 '\' '\' -match 0 0 '/\' '*/\' -match 1 1 '/\' '*/\\' +match 0 x '\' '\' +match 0 x '/\' '*/\' +match 1 x '/\' '*/\\' match 1 1 'foo' 'foo' match 1 1 '@foo' '@foo' match 0 0 'foo' '@foo' match 1 1 '[ab]' '\[ab]' match 1 1 '[ab]' '[[]ab]' -match 1 1 '[ab]' '[[:]ab]' -match 0 0 '[ab]' '[[::]ab]' -match 1 1 '[ab]' '[[:digit]ab]' -match 1 1 '[ab]' '[\[:]ab]' +match 1 x '[ab]' '[[:]ab]' +match 0 x '[ab]' '[[::]ab]' +match 1 x '[ab]' '[[:digit]ab]' +match 1 x '[ab]' '[\[:]ab]' match 1 1 '?a?b' '\??\?b' match 1 1 'abc' '\a\b\c' match 0 0 'foo' '' match 1 0 'foo/bar/baz/to' '**/t[o]' # Character class tests -match 1 1 'a1B' '[[:alpha:]][[:digit:]][[:upper:]]' -match 0 0 'a' '[[:digit:][:upper:][:space:]]' -match 1 1 'A' '[[:digit:][:upper:][:space:]]' -match 1 0 '1' '[[:digit:][:upper:][:space:]]' -match 0 0 '1' '[[:digit:][:upper:][:spaci:]]' -match 1 1 ' ' '[[:digit:][:upper:][:space:]]' -match 0 0 '.' '[[:digit:][:upper:][:space:]]' -match 1 1 '.' '[[:digit:][:punct:][:space:]]' +match 1 x 'a1B' '[[:alpha:]][[:digit:]][[:upper:]]' +match 0 x 'a' '[[:digit:][:upper:][:space:]]' +match 1 x 'A' '[[:digit:][:upper:][:space:]]' +match 1 x '1' '[[:digit:][:upper:][:space:]]' +match 0 x '1' '[[:digit:][:upper:][:spaci:]]' +match 1 x ' ' '[[:digit:][:upper:][:space:]]' +match 0 x '.' '[[:digit:][:upper:][:space:]]' +match 1 x '.' '[[:digit:][:punct:][:space:]]' match 1 1 '5' '[[:xdigit:]]' match 1 1 'f' '[[:xdigit:]]' match 1 1 'D' '[[:xdigit:]]' -match 1 0 '_' '[[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]]' -match 1 0 '_' '[[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]]' -match 1 1 '.' '[^[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:lower:][:space:][:upper:][:xdigit:]]' -match 1 1 '5' '[a-c[:digit:]x-z]' -match 1 1 'b' '[a-c[:digit:]x-z]' -match 1 1 'y' '[a-c[:digit:]x-z]' -match 0 0 'q' '[a-c[:digit:]x-z]' +match 1 x '_' '[[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]]' +match 1 x '_' '[[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]]' +match 1 x '.' '[^[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:lower:][:space:][:upper:][:xdigit:]]' +match 1 x '5' '[a-c[:digit:]x-z]' +match 1 x 'b' '[a-c[:digit:]x-z]' +match 1 x 'y' '[a-c[:digit:]x-z]' +match 0 x 'q' '[a-c[:digit:]x-z]' # Additional tests, including some malformed wildmats -match 1 1 ']' '[\\-^]' +match 1 x ']' '[\\-^]' match 0 0 '[' '[\\-^]' -match 1 1 '-' '[\-_]' -match 1 1 ']' '[\]]' +match 1 x '-' '[\-_]' +match 1 x ']' '[\]]' match 0 0 '\]' '[\]]' match 0 0 '\' '[\]]' match 0 0 'ab' 'a[]b' -match 0 1 'a[]b' 'a[]b' -match 0 1 'ab[' 'ab[' +match 0 x 'a[]b' 'a[]b' +match 0 x 'ab[' 'ab[' match 0 0 'ab' '[!' match 0 0 'ab' '[-' match 1 1 '-' '[-]' match 0 0 '-' '[a-' match 0 0 '-' '[!a-' -match 1 1 '-' '[--A]' -match 1 1 '5' '[--A]' +match 1 x '-' '[--A]' +match 1 x '5' '[--A]' match 1 1 ' ' '[ --]' match 1 1 '$' '[ --]' match 1 1 '-' '[ --]' match 0 0 '0' '[ --]' -match 1 1 '-' '[---]' -match 1 1 '-' '[--]' +match 1 x '-' '[---]' +match 1 x '-' '[--]' match 0 0 'j' '[a-e-n]' -match 1 1 '-' '[a-e-n]' -match 1 1 'a' '[!--]' +match 1 x '-' '[a-e-n]' +match 1 x 'a' '[!--]' match 0 0 '[' '[]-a]' -match 1 1 '^' '[]-a]' +match 1 x '^' '[]-a]' match 0 0 '
[PATCH 08/13] wildmatch: make wildmatch's return value compatible with fnmatch
wildmatch returns non-zero if matched, zero otherwise. This patch makes it return zero if matches, non-zero otherwise, like fnmatch(). Signed-off-by: Nguyễn Thái Ngọc Duy --- test-wildmatch.c | 4 ++-- wildmatch.c | 21 - 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/test-wildmatch.c b/test-wildmatch.c index ac56420..77014e9 100644 --- a/test-wildmatch.c +++ b/test-wildmatch.c @@ -4,9 +4,9 @@ int main(int argc, char **argv) { if (!strcmp(argv[1], "wildmatch")) - return wildmatch(argv[3], argv[2]) ? 0 : 1; + return !!wildmatch(argv[3], argv[2]); else if (!strcmp(argv[1], "iwildmatch")) - return iwildmatch(argv[3], argv[2]) ? 0 : 1; + return !!iwildmatch(argv[3], argv[2]); else if (!strcmp(argv[1], "fnmatch")) return !!fnmatch(argv[3], argv[2], FNM_PATHNAME); else diff --git a/wildmatch.c b/wildmatch.c index ac29471..6d992d3 100644 --- a/wildmatch.c +++ b/wildmatch.c @@ -20,6 +20,9 @@ typedef unsigned char uchar; #define FALSE 0 #define TRUE 1 + +#define NOMATCH 1 +#define MATCH 0 #define ABORT_ALL -1 #define ABORT_TO_STARSTAR -2 @@ -78,12 +81,12 @@ static int dowild(const uchar *p, const uchar *text) /* FALLTHROUGH */ default: if (t_ch != p_ch) - return FALSE; + return NOMATCH; continue; case '?': /* Match anything but '/'. */ if (t_ch == '/') - return FALSE; + return NOMATCH; continue; case '*': if (*++p == '*') { @@ -96,14 +99,14 @@ static int dowild(const uchar *p, const uchar *text) * only if there are no more slash characters. */ if (!special) { if (strchr((char*)text, '/') != NULL) - return FALSE; + return NOMATCH; } - return TRUE; + return MATCH; } while (1) { if (t_ch == '\0') break; - if ((matched = dowild(p, text)) != FALSE) { + if ((matched = dowild(p, text)) != NOMATCH) { if (!special || matched != ABORT_TO_STARSTAR) return matched; } else if (!special && t_ch == '/') @@ -202,18 +205,18 @@ static int dowild(const uchar *p, const uchar *text) matched = TRUE; } while (prev_ch = p_ch, (p_ch = *++p) != ']'); if (matched == special || t_ch == '/') - return FALSE; + return NOMATCH; continue; } } - return *text ? FALSE : TRUE; + return *text ? NOMATCH : MATCH; } /* Match the "pattern" against the "text" string. */ int wildmatch(const char *pattern, const char *text) { - return dowild((const uchar*)pattern, (const uchar*)text) == TRUE; + return dowild((const uchar*)pattern, (const uchar*)text); } /* Match the "pattern" against the forced-to-lower-case "text" string. */ @@ -221,7 +224,7 @@ int iwildmatch(const char *pattern, const char *text) { int ret; force_lower_case = 1; - ret = dowild((const uchar*)pattern, (const uchar*)text) == TRUE; + ret = dowild((const uchar*)pattern, (const uchar*)text); force_lower_case = 0; return ret; } -- 1.8.0.rc0.29.g1fdd78f -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 09/13] wildmatch: remove static variable force_lower_case
One place less to worry about thread safety. Also combine wildmatch and iwildmatch into one. Signed-off-by: Nguyễn Thái Ngọc Duy --- test-wildmatch.c | 4 ++-- wildmatch.c | 21 + wildmatch.h | 3 +-- 3 files changed, 8 insertions(+), 20 deletions(-) diff --git a/test-wildmatch.c b/test-wildmatch.c index 77014e9..74c0864 100644 --- a/test-wildmatch.c +++ b/test-wildmatch.c @@ -4,9 +4,9 @@ int main(int argc, char **argv) { if (!strcmp(argv[1], "wildmatch")) - return !!wildmatch(argv[3], argv[2]); + return !!wildmatch(argv[3], argv[2], 0); else if (!strcmp(argv[1], "iwildmatch")) - return !!iwildmatch(argv[3], argv[2]); + return !!wildmatch(argv[3], argv[2], FNM_CASEFOLD); else if (!strcmp(argv[1], "fnmatch")) return !!fnmatch(argv[3], argv[2], FNM_PATHNAME); else diff --git a/wildmatch.c b/wildmatch.c index 6d992d3..eef7b13 100644 --- a/wildmatch.c +++ b/wildmatch.c @@ -59,10 +59,8 @@ typedef unsigned char uchar; #define ISUPPER(c) (ISASCII(c) && isupper(c)) #define ISXDIGIT(c) (ISASCII(c) && isxdigit(c)) -static int force_lower_case = 0; - /* Match pattern "p" against "text" */ -static int dowild(const uchar *p, const uchar *text) +static int dowild(const uchar *p, const uchar *text, int force_lower_case) { uchar p_ch; @@ -106,7 +104,7 @@ static int dowild(const uchar *p, const uchar *text) while (1) { if (t_ch == '\0') break; - if ((matched = dowild(p, text)) != NOMATCH) { + if ((matched = dowild(p, text, force_lower_case)) != NOMATCH) { if (!special || matched != ABORT_TO_STARSTAR) return matched; } else if (!special && t_ch == '/') @@ -214,17 +212,8 @@ static int dowild(const uchar *p, const uchar *text) } /* Match the "pattern" against the "text" string. */ -int wildmatch(const char *pattern, const char *text) -{ - return dowild((const uchar*)pattern, (const uchar*)text); -} - -/* Match the "pattern" against the forced-to-lower-case "text" string. */ -int iwildmatch(const char *pattern, const char *text) +int wildmatch(const char *pattern, const char *text, int flags) { - int ret; - force_lower_case = 1; - ret = dowild((const uchar*)pattern, (const uchar*)text); - force_lower_case = 0; - return ret; + return dowild((const uchar*)pattern, (const uchar*)text, + flags & FNM_CASEFOLD ? 1 :0); } diff --git a/wildmatch.h b/wildmatch.h index 562faa3..e974f9a 100644 --- a/wildmatch.h +++ b/wildmatch.h @@ -1,4 +1,3 @@ /* wildmatch.h */ -int wildmatch(const char *pattern, const char *text); -int iwildmatch(const char *pattern, const char *text); +int wildmatch(const char *pattern, const char *text, int flags); -- 1.8.0.rc0.29.g1fdd78f -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 10/13] wildmatch: fix case-insensitive matching
dowild() does case insensitive matching by lower-casing the text. That means lower case letters in patterns imply case-insensitive matching, but upper case means exact matching. We do not want that subtlety. Lower case pattern too so iwildmatch() always does what we expect it to do. Signed-off-by: Nguyễn Thái Ngọc Duy --- wildmatch.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/wildmatch.c b/wildmatch.c index eef7b13..5469866 100644 --- a/wildmatch.c +++ b/wildmatch.c @@ -71,6 +71,8 @@ static int dowild(const uchar *p, const uchar *text, int force_lower_case) return ABORT_ALL; if (force_lower_case && ISUPPER(t_ch)) t_ch = tolower(t_ch); + if (force_lower_case && ISUPPER(p_ch)) + p_ch = tolower(p_ch); switch (p_ch) { case '\\': /* Literal match with following character. Note that the test -- 1.8.0.rc0.29.g1fdd78f -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 11/13] wildmatch: adjust "**" behavior
Standard wildmatch() sees consecutive asterisks as "*" that can also match slashes. But that may be hard to explain to users as "abc/**/def" can match "abcdef", "abcxyzdef", "abc/def", "abc/x/def", "abc/x/y/def"... This patch changes wildmatch so that users can do - "**/def" -> all paths ending with file/directory 'def' - "abc/**" - equivalent to "/abc/" - "abc/**/def" -> "abc/x/def", "abc/x/y/def"... - otherwise consider the pattern malformed if "**" is found Basically the magic of "**" only remains if it's wrapped around by slashes. Signed-off-by: Nguyễn Thái Ngọc Duy --- t/t3070-wildmatch.sh | 5 +++-- wildmatch.c | 13 +++-- wildmatch.h | 6 ++ 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/t/t3070-wildmatch.sh b/t/t3070-wildmatch.sh index dd95b00..15848d5 100755 --- a/t/t3070-wildmatch.sh +++ b/t/t3070-wildmatch.sh @@ -46,7 +46,7 @@ match 0 0 foobar 'foo\*bar' match 1 1 'f\oo' 'f\\oo' match 1 1 ball '*[al]?' match 0 0 ten '[ten]' -match 1 1 ten '**[!te]' +match 0 1 ten '**[!te]' match 0 0 ten '**[!ten]' match 1 1 ten 't[a-g]n' match 0 0 ten 't[!a-g]n' @@ -61,7 +61,8 @@ match 1 1 ']' ']' # Extended slash-matching features match 0 0 'foo/baz/bar' 'foo*bar' -match 1 0 'foo/baz/bar' 'foo**bar' +match 0 0 'foo/baz/bar' 'foo**bar' +match 0 1 'foobazbar' 'foo**bar' match 0 0 'foo/bar' 'foo?bar' match 0 0 'foo/bar' 'foo[/]bar' match 0 0 'foo/bar' 'f[^eiu][^eiu][^eiu][^eiu][^eiu]r' diff --git a/wildmatch.c b/wildmatch.c index 5469866..85bc0df 100644 --- a/wildmatch.c +++ b/wildmatch.c @@ -21,11 +21,6 @@ typedef unsigned char uchar; #define FALSE 0 #define TRUE 1 -#define NOMATCH 1 -#define MATCH 0 -#define ABORT_ALL -1 -#define ABORT_TO_STARSTAR -2 - #define CC_EQ(class, len, litmatch) ((len) == sizeof (litmatch)-1 \ && *(class) == *(litmatch) \ && strncmp((char*)class, litmatch, len) == 0) @@ -90,8 +85,14 @@ static int dowild(const uchar *p, const uchar *text, int force_lower_case) continue; case '*': if (*++p == '*') { + const uchar *prev_p = p - 2; while (*++p == '*') {} - special = TRUE; + if ((prev_p == text || *prev_p == '/') || + (*p == '\0' || *p == '/' || +(p[0] == '\\' && p[1] == '/'))) { + special = TRUE; + } else + return ABORT_MALFORMED; } else special = FALSE; if (*p == '\0') { diff --git a/wildmatch.h b/wildmatch.h index e974f9a..984a38c 100644 --- a/wildmatch.h +++ b/wildmatch.h @@ -1,3 +1,9 @@ /* wildmatch.h */ +#define ABORT_MALFORMED 2 +#define NOMATCH 1 +#define MATCH 0 +#define ABORT_ALL -1 +#define ABORT_TO_STARSTAR -2 + int wildmatch(const char *pattern, const char *text, int flags); -- 1.8.0.rc0.29.g1fdd78f -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 12/13] wildmatch: make /**/ match zero or more directories
"foo/**/bar" matches "foo/x/bar", "foo/x/y/bar"... but not "foo/bar". We make a special case, when foo/**/ is detected (and "foo/" part is already matched), try matching "bar" with the rest of the string. "Match one or more directories" semantics can be easily achieved using "foo/*/**/bar". This also makes "**/foo" match "foo" in addition to "x/foo", "x/y/foo".. Signed-off-by: Nguyễn Thái Ngọc Duy --- t/t3070-wildmatch.sh | 8 +++- wildmatch.c | 12 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/t/t3070-wildmatch.sh b/t/t3070-wildmatch.sh index 15848d5..e6ad6f4 100755 --- a/t/t3070-wildmatch.sh +++ b/t/t3070-wildmatch.sh @@ -63,11 +63,17 @@ match 1 1 ']' ']' match 0 0 'foo/baz/bar' 'foo*bar' match 0 0 'foo/baz/bar' 'foo**bar' match 0 1 'foobazbar' 'foo**bar' +match 1 1 'foo/baz/bar' 'foo/**/bar' +match 1 0 'foo/baz/bar' 'foo/**/**/bar' +match 1 0 'foo/b/a/z/bar' 'foo/**/bar' +match 1 0 'foo/b/a/z/bar' 'foo/**/**/bar' +match 1 0 'foo/bar' 'foo/**/bar' +match 1 0 'foo/bar' 'foo/**/**/bar' match 0 0 'foo/bar' 'foo?bar' match 0 0 'foo/bar' 'foo[/]bar' match 0 0 'foo/bar' 'f[^eiu][^eiu][^eiu][^eiu][^eiu]r' match 1 1 'foo-bar' 'f[^eiu][^eiu][^eiu][^eiu][^eiu]r' -match 0 0 'foo' '**/foo' +match 1 0 'foo' '**/foo' match 1 x '/foo' '**/foo' match 1 0 'bar/baz/foo' '**/foo' match 0 0 'bar/baz/foo' '*/foo' diff --git a/wildmatch.c b/wildmatch.c index 85bc0df..3972e26 100644 --- a/wildmatch.c +++ b/wildmatch.c @@ -90,6 +90,18 @@ static int dowild(const uchar *p, const uchar *text, int force_lower_case) if ((prev_p == text || *prev_p == '/') || (*p == '\0' || *p == '/' || (p[0] == '\\' && p[1] == '/'))) { + /* +* Assuming we already match 'foo/' and are at +* , just assume it matches +* nothing and go ahead match the rest of the +* pattern with the remaining string. This +* helps make foo/<*><*>/bar (<> because +* otherwise it breaks C comment syntax) match +* both foo/bar and foo/a/bar. +*/ + if (p[0] == '/' && + dowild(p + 1, text, force_lower_case) == MATCH) + return MATCH; special = TRUE; } else return ABORT_MALFORMED; -- 1.8.0.rc0.29.g1fdd78f -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 13/13] Support "**" wildcard in .gitignore and .gitattributes
Signed-off-by: Nguyễn Thái Ngọc Duy --- Documentation/gitignore.txt| 19 +++ dir.c | 4 +++- t/t0003-attributes.sh | 37 + t/t3001-ls-files-others-exclude.sh | 18 ++ 4 files changed, 77 insertions(+), 1 deletion(-) diff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt index 2e7328b..d4747ce 100644 --- a/Documentation/gitignore.txt +++ b/Documentation/gitignore.txt @@ -96,6 +96,25 @@ PATTERN FORMAT For example, "/{asterisk}.c" matches "cat-file.c" but not "mozilla-sha1/sha1.c". +Two consecutive asterisks ("`**`") in patterns matched against +full pathname may have special meaning: + + - A leading "`**`" followed by a slash means match in all + directories. For example, "`**/foo`" matches file or directory + "`foo`" anywhere, the same as pattern "`foo`". "**/foo/bar" + matches file or directory "`bar`" anywhere that is directly + under directory "`foo`". + + - A trailing "/**" matches everything inside. For example, + "abc/**" matches all files inside directory "abc", relative + to the location of the `.gitignore` file, with infinite depth. + + - A slash followed by two consecutive asterisks then a slash + matches zero or more directories. For example, "`a/**/b`" + matches "`a/b`", "`a/x/b`", "`a/x/y/b`" and so on. + + - Other consecutive asterisks are considered invalid. + NOTES - diff --git a/dir.c b/dir.c index ee8e711..cb7328b 100644 --- a/dir.c +++ b/dir.c @@ -8,6 +8,7 @@ #include "cache.h" #include "dir.h" #include "refs.h" +#include "wildmatch.h" struct path_simplify { int len; @@ -593,7 +594,8 @@ int match_pathname(const char *pathname, int pathlen, namelen -= prefix; } - return fnmatch_icase(pattern, name, FNM_PATHNAME) == 0; + return wildmatch(pattern, name, +ignore_case ? FNM_CASEFOLD : 0) == 0; } /* Scan the list and let the last match determine the fate. diff --git a/t/t0003-attributes.sh b/t/t0003-attributes.sh index f6c21ea..c962403 100755 --- a/t/t0003-attributes.sh +++ b/t/t0003-attributes.sh @@ -216,6 +216,43 @@ test_expect_success 'patterns starting with exclamation' ' attr_check "!f" foo ' +test_expect_success '"**" test' ' + echo "**/f foo=bar" >.gitattributes && + cat <<\EOF >expect && +f: foo: bar +a/f: foo: bar +a/b/f: foo: bar +a/b/c/f: foo: bar +EOF + git check-attr foo -- "f" >actual 2>err && + git check-attr foo -- "a/f" >>actual 2>>err && + git check-attr foo -- "a/b/f" >>actual 2>>err && + git check-attr foo -- "a/b/c/f" >>actual 2>>err && + test_cmp expect actual && + test_line_count = 0 err +' + +test_expect_success '"**" with no slashes test' ' + echo "a**f foo=bar" >.gitattributes && + git check-attr foo -- "f" >actual && + cat <<\EOF >expect && +f: foo: unspecified +af: foo: bar +axf: foo: bar +a/f: foo: unspecified +a/b/f: foo: unspecified +a/b/c/f: foo: unspecified +EOF + git check-attr foo -- "f" >actual 2>err && + git check-attr foo -- "af" >>actual 2>err && + git check-attr foo -- "axf" >>actual 2>err && + git check-attr foo -- "a/f" >>actual 2>>err && + git check-attr foo -- "a/b/f" >>actual 2>>err && + git check-attr foo -- "a/b/c/f" >>actual 2>>err && + test_cmp expect actual && + test_line_count = 0 err +' + test_expect_success 'setup bare' ' git clone --bare . bare.git && cd bare.git diff --git a/t/t3001-ls-files-others-exclude.sh b/t/t3001-ls-files-others-exclude.sh index dc2f045..efb7ebc 100755 --- a/t/t3001-ls-files-others-exclude.sh +++ b/t/t3001-ls-files-others-exclude.sh @@ -220,4 +220,22 @@ test_expect_success 'pattern matches prefix completely' ' test_cmp expect actual ' +test_expect_success 'ls-files with "**" patterns' ' + cat <<\EOF >expect && +a.1 +one/a.1 +one/two/a.1 +three/a.1 +EOF + git ls-files -o -i --exclude "**/a.1" >actual + test_cmp expect actual +' + + +test_expect_success 'ls-files with "**" patterns and no slashes' ' + : >expect && + git ls-files -o -i --exclude "one**a.1" >actual && + test_cmp expect actual +' + test_done -- 1.8.0.rc0.29.g1fdd78f -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 01/12] dir.c: rename cryptic 'which' variable to more consistent name
From: Adam Spiers 'el' is only *slightly* less cryptic, but is already used as the variable name for a struct exclude_list pointer in numerous other places, so this reduces the number of cryptic variable names in use by one :-) Signed-off-by: Adam Spiers Signed-off-by: Junio C Hamano Signed-off-by: Nguyễn Thái Ngọc Duy --- dir.c | 10 +- dir.h | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/dir.c b/dir.c index ee8e711..f7219b5 100644 --- a/dir.c +++ b/dir.c @@ -347,7 +347,7 @@ void parse_exclude_pattern(const char **pattern, } void add_exclude(const char *string, const char *base, -int baselen, struct exclude_list *which) +int baselen, struct exclude_list *el) { struct exclude *x; int patternlen; @@ -371,8 +371,8 @@ void add_exclude(const char *string, const char *base, x->base = base; x->baselen = baselen; x->flags = flags; - ALLOC_GROW(which->excludes, which->nr + 1, which->alloc); - which->excludes[which->nr++] = x; + ALLOC_GROW(el->excludes, el->nr + 1, el->alloc); + el->excludes[el->nr++] = x; } static void *read_skip_worktree_file_from_index(const char *path, size_t *size) @@ -414,7 +414,7 @@ int add_excludes_from_file_to_list(const char *fname, const char *base, int baselen, char **buf_p, - struct exclude_list *which, + struct exclude_list *el, int check_index) { struct stat st; @@ -461,7 +461,7 @@ int add_excludes_from_file_to_list(const char *fname, if (buf[i] == '\n') { if (entry != buf + i && entry[0] != '#') { buf[i - (i && buf[i-1] == '\r')] = 0; - add_exclude(entry, base, baselen, which); + add_exclude(entry, base, baselen, el); } entry = buf + i + 1; } diff --git a/dir.h b/dir.h index f5c89e3..69cc7d2 100644 --- a/dir.h +++ b/dir.h @@ -105,11 +105,11 @@ extern int path_excluded(struct path_exclude_check *, const char *, int namelen, extern int add_excludes_from_file_to_list(const char *fname, const char *base, int baselen, - char **buf_p, struct exclude_list *which, int check_index); + char **buf_p, struct exclude_list *el, int check_index); extern void add_excludes_from_file(struct dir_struct *, const char *fname); extern void parse_exclude_pattern(const char **string, int *patternlen, int *flags, int *nowildcardlen); extern void add_exclude(const char *string, const char *base, - int baselen, struct exclude_list *which); + int baselen, struct exclude_list *el); extern void free_excludes(struct exclude_list *el); extern int file_exists(const char *); -- 1.8.0.rc0.29.g1fdd78f -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 02/12] dir.c: rename path_excluded() to is_path_excluded()
From: Adam Spiers Start adopting clearer names for exclude functions. This 'is_*' naming pattern for functions returning booleans was agreed here: http://thread.gmane.org/gmane.comp.version-control.git/204661/focus=204924 Signed-off-by: Adam Spiers Signed-off-by: Junio C Hamano Signed-off-by: Nguyễn Thái Ngọc Duy --- builtin/add.c | 2 +- builtin/ls-files.c | 2 +- dir.c | 4 ++-- dir.h | 2 +- unpack-trees.c | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/builtin/add.c b/builtin/add.c index 89dce56..c689f37 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -453,7 +453,7 @@ int cmd_add(int argc, const char **argv, const char *prefix) && !file_exists(pathspec[i])) { if (ignore_missing) { int dtype = DT_UNKNOWN; - if (path_excluded(&check, pathspec[i], -1, &dtype)) + if (is_path_excluded(&check, pathspec[i], -1, &dtype)) dir_add_ignored(&dir, pathspec[i], strlen(pathspec[i])); } else die(_("pathspec '%s' did not match any files"), diff --git a/builtin/ls-files.c b/builtin/ls-files.c index 31b3f2d..ef7f99a 100644 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@ -203,7 +203,7 @@ static void show_ru_info(void) static int ce_excluded(struct path_exclude_check *check, struct cache_entry *ce) { int dtype = ce_to_dtype(ce); - return path_excluded(check, ce->name, ce_namelen(ce), &dtype); + return is_path_excluded(check, ce->name, ce_namelen(ce), &dtype); } static void show_files(struct dir_struct *dir) diff --git a/dir.c b/dir.c index f7219b5..6dfb815 100644 --- a/dir.c +++ b/dir.c @@ -679,8 +679,8 @@ void path_exclude_check_clear(struct path_exclude_check *check) * A path to a directory known to be excluded is left in check->path to * optimize for repeated checks for files in the same excluded directory. */ -int path_excluded(struct path_exclude_check *check, - const char *name, int namelen, int *dtype) +int is_path_excluded(struct path_exclude_check *check, +const char *name, int namelen, int *dtype) { int i; struct strbuf *path = &check->path; diff --git a/dir.h b/dir.h index 69cc7d2..d40aeea 100644 --- a/dir.h +++ b/dir.h @@ -101,7 +101,7 @@ struct path_exclude_check { }; extern void path_exclude_check_init(struct path_exclude_check *, struct dir_struct *); extern void path_exclude_check_clear(struct path_exclude_check *); -extern int path_excluded(struct path_exclude_check *, const char *, int namelen, int *dtype); +extern int is_path_excluded(struct path_exclude_check *, const char *, int namelen, int *dtype); extern int add_excludes_from_file_to_list(const char *fname, const char *base, int baselen, diff --git a/unpack-trees.c b/unpack-trees.c index 33a5819..3ac6370 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -1372,7 +1372,7 @@ static int check_ok_to_remove(const char *name, int len, int dtype, return 0; if (o->dir && - path_excluded(o->path_exclude_check, name, -1, &dtype)) + is_path_excluded(o->path_exclude_check, name, -1, &dtype)) /* * ce->name is explicitly excluded, so it is Ok to * overwrite it. -- 1.8.0.rc0.29.g1fdd78f -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 03/12] dir.c: rename excluded_from_list() to is_excluded_from_list()
From: Adam Spiers Continue adopting clearer names for exclude functions. This 'is_*' naming pattern for functions returning booleans was discussed here: http://thread.gmane.org/gmane.comp.version-control.git/204661/focus=204924 Also adjust their callers as necessary. Signed-off-by: Adam Spiers Signed-off-by: Junio C Hamano Signed-off-by: Nguyễn Thái Ngọc Duy --- dir.c | 11 ++- dir.h | 4 ++-- unpack-trees.c | 8 +--- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/dir.c b/dir.c index 6dfb815..7e1a23b 100644 --- a/dir.c +++ b/dir.c @@ -599,9 +599,9 @@ int match_pathname(const char *pathname, int pathlen, /* Scan the list and let the last match determine the fate. * Return 1 for exclude, 0 for include and -1 for undecided. */ -int excluded_from_list(const char *pathname, - int pathlen, const char *basename, int *dtype, - struct exclude_list *el) +int is_excluded_from_list(const char *pathname, + int pathlen, const char *basename, int *dtype, + struct exclude_list *el) { int i; @@ -648,8 +648,9 @@ static int excluded(struct dir_struct *dir, const char *pathname, int *dtype_p) prep_exclude(dir, pathname, basename-pathname); for (st = EXC_CMDL; st <= EXC_FILE; st++) { - switch (excluded_from_list(pathname, pathlen, basename, - dtype_p, &dir->exclude_list[st])) { + switch (is_excluded_from_list(pathname, pathlen, + basename, dtype_p, + &dir->exclude_list[st])) { case 0: return 0; case 1: diff --git a/dir.h b/dir.h index d40aeea..2fce4bf 100644 --- a/dir.h +++ b/dir.h @@ -76,8 +76,8 @@ extern int within_depth(const char *name, int namelen, int depth, int max_depth) extern int fill_directory(struct dir_struct *dir, const char **pathspec); extern int read_directory(struct dir_struct *, const char *path, int len, const char **pathspec); -extern int excluded_from_list(const char *pathname, int pathlen, const char *basename, - int *dtype, struct exclude_list *el); +extern int is_excluded_from_list(const char *pathname, int pathlen, const char *basename, +int *dtype, struct exclude_list *el); struct dir_entry *dir_add_ignored(struct dir_struct *dir, const char *pathname, int len); /* diff --git a/unpack-trees.c b/unpack-trees.c index 3ac6370..c0da094 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -836,7 +836,8 @@ static int clear_ce_flags_dir(struct cache_entry **cache, int nr, { struct cache_entry **cache_end; int dtype = DT_DIR; - int ret = excluded_from_list(prefix, prefix_len, basename, &dtype, el); + int ret = is_excluded_from_list(prefix, prefix_len, + basename, &dtype, el); prefix[prefix_len++] = '/'; @@ -855,7 +856,7 @@ static int clear_ce_flags_dir(struct cache_entry **cache, int nr, * with ret (iow, we know in advance the incl/excl * decision for the entire directory), clear flag here without * calling clear_ce_flags_1(). That function will call -* the expensive excluded_from_list() on every entry. +* the expensive is_excluded_from_list() on every entry. */ return clear_ce_flags_1(cache, cache_end - cache, prefix, prefix_len, @@ -938,7 +939,8 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr, /* Non-directory */ dtype = ce_to_dtype(ce); - ret = excluded_from_list(ce->name, ce_namelen(ce), name, &dtype, el); + ret = is_excluded_from_list(ce->name, ce_namelen(ce), + name, &dtype, el); if (ret < 0) ret = defval; if (ret > 0) -- 1.8.0.rc0.29.g1fdd78f -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 04/12] dir.c: rename excluded() to is_excluded()
From: Adam Spiers Continue adopting clearer names for exclude functions. This is_* naming pattern for functions returning booleans was discussed here: http://thread.gmane.org/gmane.comp.version-control.git/204661/focus=204924 Signed-off-by: Adam Spiers Signed-off-by: Junio C Hamano Signed-off-by: Nguyễn Thái Ngọc Duy --- attr.c | 2 +- dir.c | 10 +- dir.h | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/attr.c b/attr.c index 2fc6353..5362563 100644 --- a/attr.c +++ b/attr.c @@ -284,7 +284,7 @@ static struct match_attr *parse_attr_line(const char *line, const char *src, * (reading the file from top to bottom), .gitattribute of the root * directory (again, reading the file from top to bottom) down to the * current directory, and then scan the list backwards to find the first match. - * This is exactly the same as what excluded() does in dir.c to deal with + * This is exactly the same as what is_excluded() does in dir.c to deal with * .gitignore */ diff --git a/dir.c b/dir.c index 7e1a23b..50381f8 100644 --- a/dir.c +++ b/dir.c @@ -639,7 +639,7 @@ int is_excluded_from_list(const char *pathname, return -1; /* undecided */ } -static int excluded(struct dir_struct *dir, const char *pathname, int *dtype_p) +static int is_excluded(struct dir_struct *dir, const char *pathname, int *dtype_p) { int pathlen = strlen(pathname); int st; @@ -689,7 +689,7 @@ int is_path_excluded(struct path_exclude_check *check, /* * we allow the caller to pass namelen as an optimization; it * must match the length of the name, as we eventually call -* excluded() on the whole name string. +* is_excluded() on the whole name string. */ if (namelen < 0) namelen = strlen(name); @@ -706,7 +706,7 @@ int is_path_excluded(struct path_exclude_check *check, if (ch == '/') { int dt = DT_DIR; - if (excluded(check->dir, path->buf, &dt)) + if (is_excluded(check->dir, path->buf, &dt)) return 1; } strbuf_addch(path, ch); @@ -715,7 +715,7 @@ int is_path_excluded(struct path_exclude_check *check, /* An entry in the index; cannot be a directory with subentries */ strbuf_setlen(path, 0); - return excluded(check->dir, name, dtype); + return is_excluded(check->dir, name, dtype); } static struct dir_entry *dir_entry_new(const char *pathname, int len) @@ -1015,7 +1015,7 @@ static enum path_treatment treat_one_path(struct dir_struct *dir, const struct path_simplify *simplify, int dtype, struct dirent *de) { - int exclude = excluded(dir, path->buf, &dtype); + int exclude = is_excluded(dir, path->buf, &dtype); if (exclude && (dir->flags & DIR_COLLECT_IGNORED) && exclude_matches_pathspec(path->buf, path->len, simplify)) dir_add_ignored(dir, path->buf, path->len); diff --git a/dir.h b/dir.h index 2fce4bf..4b887cc 100644 --- a/dir.h +++ b/dir.h @@ -91,8 +91,8 @@ extern int match_pathname(const char *, int, const char *, int, int, int); /* - * The excluded() API is meant for callers that check each level of leading - * directory hierarchies with excluded() to avoid recursing into excluded + * The is_excluded() API is meant for callers that check each level of leading + * directory hierarchies with is_excluded() to avoid recursing into excluded * directories. Callers that do not do so should use this API instead. */ struct path_exclude_check { -- 1.8.0.rc0.29.g1fdd78f -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 05/12] dir.c: refactor is_excluded_from_list()
From: Adam Spiers The excluded function uses a new helper function called last_exclude_matching_from_list() to perform the inner loop over all of the exclude patterns. The helper just tells us whether the path is included, excluded, or undecided. However, it may be useful to know _which_ pattern was triggered. So let's pass out the entire exclude match, which contains the status information we were already passing out. Further patches can make use of this. This is a modified forward port of a patch from 2009 by Jeff King: http://article.gmane.org/gmane.comp.version-control.git/108815 Signed-off-by: Adam Spiers Signed-off-by: Junio C Hamano Signed-off-by: Nguyễn Thái Ngọc Duy --- dir.c | 37 - 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/dir.c b/dir.c index 50381f8..859e0f9 100644 --- a/dir.c +++ b/dir.c @@ -596,22 +596,26 @@ int match_pathname(const char *pathname, int pathlen, return fnmatch_icase(pattern, name, FNM_PATHNAME) == 0; } -/* Scan the list and let the last match determine the fate. - * Return 1 for exclude, 0 for include and -1 for undecided. +/* + * Scan the given exclude list in reverse to see whether pathname + * should be ignored. The first match (i.e. the last on the list), if + * any, determines the fate. Returns the exclude_list element which + * matched, or NULL for undecided. */ -int is_excluded_from_list(const char *pathname, - int pathlen, const char *basename, int *dtype, - struct exclude_list *el) +static struct exclude *last_exclude_matching_from_list(const char *pathname, + int pathlen, + const char *basename, + int *dtype, + struct exclude_list *el) { int i; if (!el->nr) - return -1; /* undefined */ + return NULL;/* undefined */ for (i = el->nr - 1; 0 <= i; i--) { struct exclude *x = el->excludes[i]; const char *exclude = x->pattern; - int to_exclude = x->flags & EXC_FLAG_NEGATIVE ? 0 : 1; int prefix = x->nowildcardlen; if (x->flags & EXC_FLAG_MUSTBEDIR) { @@ -626,7 +630,7 @@ int is_excluded_from_list(const char *pathname, pathlen - (basename - pathname), exclude, prefix, x->patternlen, x->flags)) - return to_exclude; + return x; continue; } @@ -634,8 +638,23 @@ int is_excluded_from_list(const char *pathname, if (match_pathname(pathname, pathlen, x->base, x->baselen ? x->baselen - 1 : 0, exclude, prefix, x->patternlen, x->flags)) - return to_exclude; + return x; } + return NULL; /* undecided */ +} + +/* + * Scan the list and let the last match determine the fate. + * Return 1 for exclude, 0 for include and -1 for undecided. + */ +int is_excluded_from_list(const char *pathname, + int pathlen, const char *basename, int *dtype, + struct exclude_list *el) +{ + struct exclude *exclude; + exclude = last_exclude_matching_from_list(pathname, pathlen, basename, dtype, el); + if (exclude) + return exclude->flags & EXC_FLAG_NEGATIVE ? 0 : 1; return -1; /* undecided */ } -- 1.8.0.rc0.29.g1fdd78f -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 06/12] dir.c: refactor is_excluded()
From: Adam Spiers In a similar way to the previous commit, this extracts a new helper function last_exclude_matching() which returns the last exclude_list element which matched, or NULL if no match was found. is_excluded() becomes a wrapper around this, and just returns 0 or 1 depending on whether any matching exclude_list element was found. This allows callers to find out _why_ a given path was excluded, rather than just whether it was or not, paving the way for a new git sub-command which allows users to test their exclude lists from the command line. Signed-off-by: Adam Spiers Signed-off-by: Junio C Hamano Signed-off-by: Nguyễn Thái Ngọc Duy --- dir.c | 38 +- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/dir.c b/dir.c index 859e0f9..c91a2f6 100644 --- a/dir.c +++ b/dir.c @@ -658,24 +658,44 @@ int is_excluded_from_list(const char *pathname, return -1; /* undecided */ } -static int is_excluded(struct dir_struct *dir, const char *pathname, int *dtype_p) +/* + * Loads the exclude lists for the directory containing pathname, then + * scans all exclude lists to determine whether pathname is excluded. + * Returns the exclude_list element which matched, or NULL for + * undecided. + */ +static struct exclude *last_exclude_matching(struct dir_struct *dir, +const char *pathname, +int *dtype_p) { int pathlen = strlen(pathname); int st; + struct exclude *exclude; const char *basename = strrchr(pathname, '/'); basename = (basename) ? basename+1 : pathname; prep_exclude(dir, pathname, basename-pathname); for (st = EXC_CMDL; st <= EXC_FILE; st++) { - switch (is_excluded_from_list(pathname, pathlen, - basename, dtype_p, - &dir->exclude_list[st])) { - case 0: - return 0; - case 1: - return 1; - } + exclude = last_exclude_matching_from_list( + pathname, pathlen, basename, dtype_p, + &dir->exclude_list[st]); + if (exclude) + return exclude; } + return NULL; +} + +/* + * Loads the exclude lists for the directory containing pathname, then + * scans all exclude lists to determine whether pathname is excluded. + * Returns 1 if true, otherwise 0. + */ +static int is_excluded(struct dir_struct *dir, const char *pathname, int *dtype_p) +{ + struct exclude *exclude = + last_exclude_matching(dir, pathname, dtype_p); + if (exclude) + return exclude->flags & EXC_FLAG_NEGATIVE ? 0 : 1; return 0; } -- 1.8.0.rc0.29.g1fdd78f -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 07/12] dir.c: refactor is_path_excluded()
From: Adam Spiers In a similar way to the previous commit, this extracts a new helper function last_exclude_matching_path() which return the last exclude_list element which matched, or NULL if no match was found. is_path_excluded() becomes a wrapper around this, and just returns 0 or 1 depending on whether any matching exclude_list element was found. This allows callers to find out _why_ a given path was excluded, rather than just whether it was or not, paving the way for a new git sub-command which allows users to test their exclude lists from the command line. Signed-off-by: Adam Spiers Signed-off-by: Junio C Hamano Signed-off-by: Nguyễn Thái Ngọc Duy --- dir.c | 47 ++- dir.h | 3 +++ 2 files changed, 41 insertions(+), 9 deletions(-) diff --git a/dir.c b/dir.c index c91a2f6..84ab826 100644 --- a/dir.c +++ b/dir.c @@ -703,6 +703,7 @@ void path_exclude_check_init(struct path_exclude_check *check, struct dir_struct *dir) { check->dir = dir; + check->exclude = NULL; strbuf_init(&check->path, 256); } @@ -712,18 +713,21 @@ void path_exclude_check_clear(struct path_exclude_check *check) } /* - * Is this name excluded? This is for a caller like show_files() that - * do not honor directory hierarchy and iterate through paths that are - * possibly in an ignored directory. + * For each subdirectory in name, starting with the top-most, checks + * to see if that subdirectory is excluded, and if so, returns the + * corresponding exclude structure. Otherwise, checks whether name + * itself (which is presumably a file) is excluded. * * A path to a directory known to be excluded is left in check->path to * optimize for repeated checks for files in the same excluded directory. */ -int is_path_excluded(struct path_exclude_check *check, -const char *name, int namelen, int *dtype) +struct exclude *last_exclude_matching_path(struct path_exclude_check *check, + const char *name, int namelen, + int *dtype) { int i; struct strbuf *path = &check->path; + struct exclude *exclude; /* * we allow the caller to pass namelen as an optimization; it @@ -733,11 +737,17 @@ int is_path_excluded(struct path_exclude_check *check, if (namelen < 0) namelen = strlen(name); + /* +* If path is non-empty, and name is equal to path or a +* subdirectory of path, name should be excluded, because +* it's inside a directory which is already known to be +* excluded and was previously left in check->path. +*/ if (path->len && path->len <= namelen && !memcmp(name, path->buf, path->len) && (!name[path->len] || name[path->len] == '/')) - return 1; + return check->exclude; strbuf_setlen(path, 0); for (i = 0; name[i]; i++) { @@ -745,8 +755,12 @@ int is_path_excluded(struct path_exclude_check *check, if (ch == '/') { int dt = DT_DIR; - if (is_excluded(check->dir, path->buf, &dt)) - return 1; + exclude = last_exclude_matching(check->dir, + path->buf, &dt); + if (exclude) { + check->exclude = exclude; + return exclude; + } } strbuf_addch(path, ch); } @@ -754,7 +768,22 @@ int is_path_excluded(struct path_exclude_check *check, /* An entry in the index; cannot be a directory with subentries */ strbuf_setlen(path, 0); - return is_excluded(check->dir, name, dtype); + return last_exclude_matching(check->dir, name, dtype); +} + +/* + * Is this name excluded? This is for a caller like show_files() that + * do not honor directory hierarchy and iterate through paths that are + * possibly in an ignored directory. + */ +int is_path_excluded(struct path_exclude_check *check, + const char *name, int namelen, int *dtype) +{ + struct exclude *exclude = + last_exclude_matching_path(check, name, namelen, dtype); + if (exclude) + return exclude->flags & EXC_FLAG_NEGATIVE ? 0 : 1; + return 0; } static struct dir_entry *dir_entry_new(const char *pathname, int len) diff --git a/dir.h b/dir.h index 4b887cc..02ac0bf 100644 --- a/dir.h +++ b/dir.h @@ -97,10 +97,13 @@ extern int match_pathname(const char *, int, */ struct path_exclude_check { struct dir_struct *dir; + struct exclude *exclude; struct strbuf path; }; extern void path_exclude_check_init(struct path_exclude_check *, struct dir_struct *); extern void path_exclude_check_cl
[PATCH 08/12] dir.c: keep track of where patterns came from
From: Adam Spiers For exclude patterns read in from files, the filename is stored together with the corresponding line number (counting starting at 1). For exclude patterns provided on the command line, the sequence number is negative, with counting starting at -1, so for example the 2nd pattern provided via --exclude would be numbered -2. This allows any future consumers of that data to easily distinguish between exclude patterns from files vs. from the CLI. Signed-off-by: Adam Spiers Signed-off-by: Junio C Hamano Signed-off-by: Nguyễn Thái Ngọc Duy --- builtin/clean.c| 2 +- builtin/ls-files.c | 3 ++- dir.c | 26 -- dir.h | 5 - 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/builtin/clean.c b/builtin/clean.c index 0c7b3d0..f618231 100644 --- a/builtin/clean.c +++ b/builtin/clean.c @@ -99,7 +99,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix) for (i = 0; i < exclude_list.nr; i++) add_exclude(exclude_list.items[i].string, "", 0, - &dir.exclude_list[EXC_CMDL]); + &dir.exclude_list[EXC_CMDL], "--exclude option", -(i+1)); pathspec = get_pathspec(prefix, argv); diff --git a/builtin/ls-files.c b/builtin/ls-files.c index ef7f99a..db3c081 100644 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@ -35,6 +35,7 @@ static int error_unmatch; static char *ps_matched; static const char *with_tree; static int exc_given; +static int exclude_args; static const char *tag_cached = ""; static const char *tag_unmerged = ""; @@ -423,7 +424,7 @@ static int option_parse_exclude(const struct option *opt, struct exclude_list *list = opt->value; exc_given = 1; - add_exclude(arg, "", 0, list); + add_exclude(arg, "", 0, list, "--exclude option", --exclude_args); return 0; } diff --git a/dir.c b/dir.c index 84ab826..81a5dd5 100644 --- a/dir.c +++ b/dir.c @@ -347,7 +347,8 @@ void parse_exclude_pattern(const char **pattern, } void add_exclude(const char *string, const char *base, -int baselen, struct exclude_list *el) +int baselen, struct exclude_list *el, +const char *src, int srcpos) { struct exclude *x; int patternlen; @@ -371,6 +372,8 @@ void add_exclude(const char *string, const char *base, x->base = base; x->baselen = baselen; x->flags = flags; + x->src = src; + x->srcpos = srcpos; ALLOC_GROW(el->excludes, el->nr + 1, el->alloc); el->excludes[el->nr++] = x; } @@ -418,7 +421,7 @@ int add_excludes_from_file_to_list(const char *fname, int check_index) { struct stat st; - int fd, i; + int fd, i, lineno = 1; size_t size = 0; char *buf, *entry; @@ -461,8 +464,10 @@ int add_excludes_from_file_to_list(const char *fname, if (buf[i] == '\n') { if (entry != buf + i && entry[0] != '#') { buf[i - (i && buf[i-1] == '\r')] = 0; - add_exclude(entry, base, baselen, el); + add_exclude(entry, base, baselen, el, + fname, lineno); } + lineno++; entry = buf + i + 1; } } @@ -493,8 +498,10 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen) !strncmp(dir->basebuf, base, stk->baselen)) break; dir->exclude_stack = stk->prev; - while (stk->exclude_ix < el->nr) - free(el->excludes[--el->nr]); + while (stk->exclude_ix < el->nr) { + struct exclude *exclude = el->excludes[--el->nr]; + free(exclude); + } free(stk->filebuf); free(stk); } @@ -521,7 +528,14 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen) memcpy(dir->basebuf + current, base + current, stk->baselen - current); strcpy(dir->basebuf + stk->baselen, dir->exclude_per_dir); - add_excludes_from_file_to_list(dir->basebuf, + + /* +* dir->basebuf gets reused by the traversal, but we +* need fname to remain unchanged to ensure the src +* member of each struct exclude correctly back-references +* its source file. +*/ + add_excludes_from_file_to_list(strdup(dir->basebuf), dir->basebuf, stk->baselen, &stk->filebuf, el, 1); dir->exclude_stack = stk; diff --git a/dir.h
[PATCH 09/12] dir.c: refactor treat_gitlinks()
From: Adam Spiers Extract the body of the for loop in treat_gitlinks() into a separate treat_gitlink() function so that it can be reused elsewhere. This paves the way for a new check-ignore sub-command. Signed-off-by: Adam Spiers Signed-off-by: Junio C Hamano Signed-off-by: Nguyễn Thái Ngọc Duy --- builtin/add.c | 49 +++-- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/builtin/add.c b/builtin/add.c index c689f37..6d2fb0c 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -153,31 +153,44 @@ static char *prune_directory(struct dir_struct *dir, const char **pathspec, int return seen; } -static void treat_gitlinks(const char **pathspec) +/* + * Check whether path refers to a submodule, or something inside a + * submodule. If the former, returns the path with any trailing slash + * stripped. If the latter, dies with an error message. + */ +const char *treat_gitlink(const char *path) { - int i; - - if (!pathspec || !*pathspec) - return; - + int i, path_len = strlen(path); for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; if (S_ISGITLINK(ce->ce_mode)) { - int len = ce_namelen(ce), j; - for (j = 0; pathspec[j]; j++) { - int len2 = strlen(pathspec[j]); - if (len2 <= len || pathspec[j][len] != '/' || - memcmp(ce->name, pathspec[j], len)) - continue; - if (len2 == len + 1) - /* strip trailing slash */ - pathspec[j] = xstrndup(ce->name, len); - else - die (_("Path '%s' is in submodule '%.*s'"), - pathspec[j], len, ce->name); + int ce_len = ce_namelen(ce); + if (path_len <= ce_len || path[ce_len] != '/' || + memcmp(ce->name, path, ce_len)) + /* path does not refer to this +* submodule or anything inside it */ + continue; + if (path_len == ce_len + 1) { + /* path refers to submodule; +* strip trailing slash */ + return xstrndup(ce->name, ce_len); + } else { + die (_("Path '%s' is in submodule '%.*s'"), +path, ce_len, ce->name); } } } + return path; +} + +void treat_gitlinks(const char **pathspec) +{ + if (!pathspec || !*pathspec) + return; + + int i; + for (i = 0; pathspec[i]; i++) + pathspec[i] = treat_gitlink(pathspec[i]); } static void refresh(int verbose, const char **pathspec) -- 1.8.0.rc0.29.g1fdd78f -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 10/12] pathspec.c: move reusable code from builtin/add.c
From: Adam Spiers This is in preparation for reuse by a new git check-ignore command. Signed-off-by: Adam Spiers Signed-off-by: Junio C Hamano Signed-off-by: Nguyễn Thái Ngọc Duy --- Makefile | 2 ++ builtin/add.c | 95 ++--- pathspec.c| 98 +++ pathspec.h| 6 4 files changed, 109 insertions(+), 92 deletions(-) create mode 100644 pathspec.c create mode 100644 pathspec.h diff --git a/Makefile b/Makefile index 13293d3..48facad 100644 --- a/Makefile +++ b/Makefile @@ -645,6 +645,7 @@ LIB_H += pack-refs.h LIB_H += pack-revindex.h LIB_H += parse-options.h LIB_H += patch-ids.h +LIB_H += pathspec.h LIB_H += pkt-line.h LIB_H += progress.h LIB_H += prompt.h @@ -758,6 +759,7 @@ LIB_OBJS += parse-options-cb.o LIB_OBJS += patch-delta.o LIB_OBJS += patch-ids.o LIB_OBJS += path.o +LIB_OBJS += pathspec.o LIB_OBJS += pkt-line.o LIB_OBJS += preload-index.o LIB_OBJS += pretty.o diff --git a/builtin/add.c b/builtin/add.c index 6d2fb0c..927b0f2 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -6,6 +6,7 @@ #include "cache.h" #include "builtin.h" #include "dir.h" +#include "pathspec.h" #include "exec_cmd.h" #include "cache-tree.h" #include "run-command.h" @@ -97,39 +98,6 @@ int add_files_to_cache(const char *prefix, const char **pathspec, int flags) return !!data.add_errors; } -static void fill_pathspec_matches(const char **pathspec, char *seen, int specs) -{ - int num_unmatched = 0, i; - - /* -* Since we are walking the index as if we were walking the directory, -* we have to mark the matched pathspec as seen; otherwise we will -* mistakenly think that the user gave a pathspec that did not match -* anything. -*/ - for (i = 0; i < specs; i++) - if (!seen[i]) - num_unmatched++; - if (!num_unmatched) - return; - for (i = 0; i < active_nr; i++) { - struct cache_entry *ce = active_cache[i]; - match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen); - } -} - -static char *find_used_pathspec(const char **pathspec) -{ - char *seen; - int i; - - for (i = 0; pathspec[i]; i++) - ; /* just counting */ - seen = xcalloc(i, 1); - fill_pathspec_matches(pathspec, seen, i); - return seen; -} - static char *prune_directory(struct dir_struct *dir, const char **pathspec, int prefix) { char *seen; @@ -153,46 +121,6 @@ static char *prune_directory(struct dir_struct *dir, const char **pathspec, int return seen; } -/* - * Check whether path refers to a submodule, or something inside a - * submodule. If the former, returns the path with any trailing slash - * stripped. If the latter, dies with an error message. - */ -const char *treat_gitlink(const char *path) -{ - int i, path_len = strlen(path); - for (i = 0; i < active_nr; i++) { - struct cache_entry *ce = active_cache[i]; - if (S_ISGITLINK(ce->ce_mode)) { - int ce_len = ce_namelen(ce); - if (path_len <= ce_len || path[ce_len] != '/' || - memcmp(ce->name, path, ce_len)) - /* path does not refer to this -* submodule or anything inside it */ - continue; - if (path_len == ce_len + 1) { - /* path refers to submodule; -* strip trailing slash */ - return xstrndup(ce->name, ce_len); - } else { - die (_("Path '%s' is in submodule '%.*s'"), -path, ce_len, ce->name); - } - } - } - return path; -} - -void treat_gitlinks(const char **pathspec) -{ - if (!pathspec || !*pathspec) - return; - - int i; - for (i = 0; pathspec[i]; i++) - pathspec[i] = treat_gitlink(pathspec[i]); -} - static void refresh(int verbose, const char **pathspec) { char *seen; @@ -210,23 +138,6 @@ static void refresh(int verbose, const char **pathspec) free(seen); } -static const char **validate_pathspec(int argc, const char **argv, const char *prefix) -{ - const char **pathspec = get_pathspec(prefix, argv); - - if (pathspec) { - const char **p; - for (p = pathspec; *p; p++) { - if (has_symlink_leading_path(*p, strlen(*p))) { - int len = prefix ? strlen(prefix) : 0; - die(_("'%s' is beyond a symbolic link"), *p + len); - } - } - } - - return pathspec; -} - int run_add_
[PATCH 11/12] dir.c: provide free_directory() for reclaiming dir_struct memory
From: Adam Spiers Signed-off-by: Adam Spiers Signed-off-by: Junio C Hamano Signed-off-by: Nguyễn Thái Ngọc Duy --- Documentation/technical/api-directory-listing.txt | 2 ++ dir.c | 28 +-- dir.h | 1 + 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/Documentation/technical/api-directory-listing.txt b/Documentation/technical/api-directory-listing.txt index add6f43..ca571a8 100644 --- a/Documentation/technical/api-directory-listing.txt +++ b/Documentation/technical/api-directory-listing.txt @@ -76,4 +76,6 @@ marked. If you to exclude files, make sure you have loaded index first. * Use `dir.entries[]`. +* Call `free_directory()` when none of the contained elements are no longer in use. + (JC) diff --git a/dir.c b/dir.c index 81a5dd5..d50634d 100644 --- a/dir.c +++ b/dir.c @@ -481,6 +481,16 @@ void add_excludes_from_file(struct dir_struct *dir, const char *fname) die("cannot use %s as an exclude file", fname); } +static void free_exclude_stack(struct exclude_stack *stk) +{ + free(stk->filebuf); + free(stk); +} + +/* + * Loads the per-directory exclude list for the substring of base + * which has a char length of baselen. + */ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen) { struct exclude_list *el; @@ -502,8 +512,7 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen) struct exclude *exclude = el->excludes[--el->nr]; free(exclude); } - free(stk->filebuf); - free(stk); + free_exclude_stack(stk); } /* Read from the parent directories and push them down. */ @@ -1521,3 +1530,18 @@ void free_pathspec(struct pathspec *pathspec) free(pathspec->items); pathspec->items = NULL; } + +void free_directory(struct dir_struct *dir) +{ + struct exclude_stack *stk; + int st; + for (st = EXC_CMDL; st <= EXC_FILE; st++) + free_excludes(&dir->exclude_list[st]); + + stk = dir->exclude_stack; + while (stk) { + struct exclude_stack *prev = stk->prev; + free_exclude_stack(stk); + stk = prev; + } +} diff --git a/dir.h b/dir.h index 3921aa9..fb57c66 100644 --- a/dir.h +++ b/dir.h @@ -117,6 +117,7 @@ extern void parse_exclude_pattern(const char **string, int *patternlen, int *fla extern void add_exclude(const char *string, const char *base, int baselen, struct exclude_list *el, const char *src, int srcpos); extern void free_excludes(struct exclude_list *el); +extern void free_directory(struct dir_struct *dir); extern int file_exists(const char *); extern int is_inside_dir(const char *dir); -- 1.8.0.rc0.29.g1fdd78f -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 12/12] Add git-check-ignore sub-command
From: Adam Spiers This works in a similar manner to git-check-attr. Some code was reused from add.c by refactoring out into pathspec.c. Thanks to Jeff King and Junio C Hamano for the idea: http://thread.gmane.org/gmane.comp.version-control.git/108671/focus=108815 Signed-off-by: Adam Spiers Signed-off-by: Junio C Hamano Signed-off-by: Nguyễn Thái Ngọc Duy --- .gitignore | 1 + Documentation/git-check-ignore.txt | 85 + Documentation/gitignore.txt| 6 +- Makefile | 1 + builtin.h | 1 + builtin/check-ignore.c | 170 ++ command-list.txt | 1 + contrib/completion/git-completion.bash | 1 + git.c | 1 + t/t0007-ignores.sh | 587 + 10 files changed, 852 insertions(+), 2 deletions(-) create mode 100644 Documentation/git-check-ignore.txt create mode 100644 builtin/check-ignore.c create mode 100755 t/t0007-ignores.sh diff --git a/.gitignore b/.gitignore index f1acd3e..20ef4e8 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ /git-bundle /git-cat-file /git-check-attr +/git-check-ignore /git-check-ref-format /git-checkout /git-checkout-index diff --git a/Documentation/git-check-ignore.txt b/Documentation/git-check-ignore.txt new file mode 100644 index 000..96fa7bc --- /dev/null +++ b/Documentation/git-check-ignore.txt @@ -0,0 +1,85 @@ +git-check-ignore(1) +=== + +NAME + +git-check-ignore - Debug gitignore / exclude files + + +SYNOPSIS + +[verse] +'git check-ignore' [options] pathname... +'git check-ignore' [options] --stdin < + +DESCRIPTION +--- + +For each pathname given via the command-line or from a file via +`--stdin`, this command will list the first exclude pattern found (if +any) which explicitly excludes or includes that pathname. Note that +within any given exclude file, later patterns take precedence over +earlier ones, so any matching pattern which this command outputs may +not be the one you would immediately expect. + +OPTIONS +--- +-q, --quiet:: + Don't output anything, just set exit status. This is only + valid with a single pathname. + +-v, --verbose:: + Also output details about the matching pattern (if any) + for each given pathname. + +--stdin:: + Read file names from stdin instead of from the command-line. + +-z:: + The output format is modified to be machine-parseable (see + below). If `--stdin` is also given, input paths are separated + with a NUL character instead of a linefeed character. + +OUTPUT +-- + +By default, any of the given pathnames which match an ignore pattern +will be output, one per line. If no pattern matches a given path, +nothing will be output for that path; this means that path will not be +ignored. + +If `--verbose` is specified, the output is a series of lines of the form: + + + + is the path of a file being queried, is the +matching pattern, is the pattern's source file, and +is the line number of the pattern within that source. If the pattern +contained a `!` prefix or `/` suffix, it will be preserved in the +output. will be an absolute path when referring to the file +configured by `core.excludesfile`, or relative to the repository root +when referring to `.git/info/exclude` or a per-directory exclude file. + +If `-z` is specified, the output is a series of lines of the form: + +EXIT STATUS +--- + +0:: + One or more of the provided paths is ignored. + +1:: + None of the provided paths are ignored. + +128:: + A fatal error was encountered. + +SEE ALSO + +linkgit:gitignore[5] +linkgit:gitconfig[5] +linkgit:git-ls-files[5] + +GIT +--- +Part of the linkgit:git[1] suite diff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt index 2e7328b..f401b8c 100644 --- a/Documentation/gitignore.txt +++ b/Documentation/gitignore.txt @@ -153,8 +153,10 @@ The second .gitignore prevents git from ignoring SEE ALSO -linkgit:git-rm[1], linkgit:git-update-index[1], -linkgit:gitrepository-layout[5] +linkgit:git-rm[1], +linkgit:git-update-index[1], +linkgit:gitrepository-layout[5], +linkgit:git-check-ignore[1] GIT --- diff --git a/Makefile b/Makefile index 48facad..8476fc8 100644 --- a/Makefile +++ b/Makefile @@ -822,6 +822,7 @@ BUILTIN_OBJS += builtin/branch.o BUILTIN_OBJS += builtin/bundle.o BUILTIN_OBJS += builtin/cat-file.o BUILTIN_OBJS += builtin/check-attr.o +BUILTIN_OBJS += builtin/check-ignore.o BUILTIN_OBJS += builtin/check-ref-format.o BUILTIN_OBJS += builtin/checkout-index.o BUILTIN_OBJS += builtin/checkout.o diff --git a/builtin.h b/builtin.h index dffb34e..d57faf4 100644 --- a/builtin.h +++ b/builtin.h @@ -58,6 +58,7 @@ extern int cmd_cat_file(int argc, const char **argv, const char *prefix); extern int cmd_checkout(int ar