Re: git reflog delete HEAD@{1} HEAD@{2} caught me by surprise...

2012-10-14 Thread George Spelvin
> 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

2012-10-14 Thread Jonathan Nieder
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

2012-10-14 Thread Jonathan Nieder
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

2012-10-14 Thread Jonathan Nieder
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

2012-10-14 Thread Jonathan Nieder
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

2012-10-14 Thread Jonathan Nieder
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

2012-10-14 Thread 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.



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

2012-10-14 Thread Torsten Bögershausen
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

2012-10-14 Thread Nguyễn Thái Ngọc Duy
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.

2012-10-14 Thread Jonathan Nieder
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)

2012-10-14 Thread Jonathan Nieder
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

2012-10-14 Thread Jonathan Nieder
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

2012-10-14 Thread Nguyễn Thái Ngọc Duy
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

2012-10-14 Thread Nguyễn Thái Ngọc Duy
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

2012-10-14 Thread Nguyễn Thái Ngọc Duy
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

2012-10-14 Thread Nguyễn Thái Ngọc Duy
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

2012-10-14 Thread Nguyễn Thái Ngọc Duy
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

2012-10-14 Thread René Scharfe

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

2012-10-14 Thread Nguyen Thai Ngoc Duy
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

2012-10-14 Thread Jens Lehmann
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

2012-10-14 Thread Ralf Thielow
---

> 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

2012-10-14 Thread René Scharfe

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

2012-10-14 Thread Nguyen Thai Ngoc Duy
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

2012-10-14 Thread 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
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

2012-10-14 Thread Felipe Contreras
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

2012-10-14 Thread Felipe Contreras
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

2012-10-14 Thread Felipe Contreras
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

2012-10-14 Thread Felipe Contreras
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

2012-10-14 Thread Jens Lehmann
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

2012-10-14 Thread Felipe Contreras
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

2012-10-14 Thread Jens Lehmann
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

2012-10-14 Thread Jens Lehmann
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

2012-10-14 Thread Jeff King
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?

2012-10-14 Thread Matthieu Moy
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

2012-10-14 Thread Junio C Hamano
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

2012-10-14 Thread 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.

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

2012-10-14 Thread Junio C Hamano
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

2012-10-14 Thread Junio C Hamano
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

2012-10-14 Thread Junio C Hamano
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

2012-10-14 Thread Jens Lehmann
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

2012-10-14 Thread Christopher Rorvick
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

2012-10-14 Thread Lauri Alanko

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

2012-10-14 Thread Chris Rorvick
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

2012-10-14 Thread 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 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

2012-10-14 Thread Nguyen Thai Ngoc Duy
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

2012-10-14 Thread Junio C Hamano
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

2012-10-14 Thread Jeff King
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

2012-10-14 Thread Johannes Sixt
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

2012-10-14 Thread Nguyễn Thái Ngọc Duy
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

2012-10-14 Thread Nguyễn Thái Ngọc Duy
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

2012-10-14 Thread Nguyễn Thái Ngọc Duy

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

2012-10-14 Thread Nguyễn Thái Ngọc Duy
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

2012-10-14 Thread Nguyễn Thái Ngọc Duy

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

2012-10-14 Thread Nguyễn Thái Ngọc Duy
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

2012-10-14 Thread Nguyễn Thái Ngọc Duy
.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

2012-10-14 Thread Nguyễn Thái Ngọc Duy

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

2012-10-14 Thread Nguyễn Thái Ngọc Duy

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

2012-10-14 Thread Nguyễn Thái Ngọc Duy
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

2012-10-14 Thread Nguyễn Thái Ngọc Duy

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

2012-10-14 Thread Nguyễn Thái Ngọc Duy
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

2012-10-14 Thread Nguyễn Thái Ngọc Duy
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

2012-10-14 Thread Nguyễn Thái Ngọc Duy
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

2012-10-14 Thread Nguyễn Thái Ngọc Duy
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

2012-10-14 Thread Nguyễn Thái Ngọc Duy
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

2012-10-14 Thread Nguyễn Thái Ngọc Duy
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

2012-10-14 Thread Nguyễn Thái Ngọc Duy
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

2012-10-14 Thread Nguyễn Thái Ngọc Duy
"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

2012-10-14 Thread Nguyễn Thái Ngọc Duy

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

2012-10-14 Thread Nguyễn Thái Ngọc Duy
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()

2012-10-14 Thread Nguyễn Thái Ngọc Duy
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()

2012-10-14 Thread Nguyễn Thái Ngọc Duy
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()

2012-10-14 Thread Nguyễn Thái Ngọc Duy
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()

2012-10-14 Thread Nguyễn Thái Ngọc Duy
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()

2012-10-14 Thread Nguyễn Thái Ngọc Duy
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()

2012-10-14 Thread Nguyễn Thái Ngọc Duy
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

2012-10-14 Thread Nguyễn Thái Ngọc Duy
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()

2012-10-14 Thread Nguyễn Thái Ngọc Duy
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

2012-10-14 Thread Nguyễn Thái Ngọc Duy
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

2012-10-14 Thread Nguyễn Thái Ngọc Duy
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

2012-10-14 Thread Nguyễn Thái Ngọc Duy
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