Git development
 help / color / mirror / Atom feed
* Re: Corruption in the repository
From: Christian Couder @ 2010-12-13 16:34 UTC (permalink / raw)
  To: Sylvestre Ledru; +Cc: git, Simon Gareste, Bruno JOFRET
In-Reply-To: <1292255990.25237.27642.camel@korcula.inria.fr>

Hi,

On Mon, Dec 13, 2010 at 4:59 PM, Sylvestre Ledru
<sylvestre.ledru@scilab.org> wrote:
> Hello guys,
>
> I have a small problem with a git repository and I haven't find a way to
> fix my problem.
> I am using git with gerrit [1] as frontend (even if I don't think it is
> related here).
> For an unknown reason, the repository just became corrupted.
>
> When I try to clone the repository straight with the file system, the
> following error is displayed:
> error: refs/changes/98/398/1 does not point to a valid object!
> error: refs/changes/98/398/2 does not point to a valid object!
> fatal: object cff52c24fba28408e7d021a8f35a717bef31521d is corrupted
> fatal: The remote end hung up unexpectedly
>
> git-prune & git-fsck both fail.
>
> Does anyone know how to repair this error ?

Did you try what the FAQ suggests:

https://git.wiki.kernel.org/index.php/GitFaq#How_to_fix_a_broken_repository.3F

?

Regards,
Christian.

^ permalink raw reply

* Re: native-style key bindings for gitk on Mac OS X
From: Hans-Christoph Steiner @ 2010-12-13 16:28 UTC (permalink / raw)
  To: Andreas Ericsson; +Cc: git
In-Reply-To: <4D05D998.5080107@op5.se>


On Dec 13, 2010, at 3:30 AM, Andreas Ericsson wrote:

> On 12/12/2010 11:08 PM, Hans-Christoph Steiner wrote:
>>
>> Hey all,
>>
>> This is my first post here, hopefully I'm not doing anything stupid
>> ;) I use gitk on Debian, Ubuntu, and Mac OS X. I'm big on having apps
>> feel native on each platform. Currently gitk's key bindings are very
>> GNU/Linux-ish when using gitk on Mac OS X. I'd like to submit a patch
>> to make gitk use native-style key bindings and re-use common key
>> bindings.
>
> So long as the patch lets the original keys work (ie, people who are
> used to them as they are now aren't suddenly hit by a nasty surprise),
> I think it's a great idea.
>
>> Before starting this, I just wanted to make sure this isn't some
>> hotly debated political issue.
>>
>
> It will be if the old keys stop working or all of a sudden do  
> something
> different. Especially if the new thing it does isn't exactly harmless
> but the old thing was.


I think that's a good idea.  The only problem is Cmd-F5 (i.e. Reload)  
is already globally claimed in Mac OS X to turn on the accessibility  
voiceover reader.  So all you get is a robot voice reading your GUI to  
you.  This could be Ctrl-F5 instead, then it'd be the same as on GNU/ 
Linux.

.hc




----------------------------------------------------------------------------

"[T]he greatest purveyor of violence in the world today [is] my own  
government." - Martin Luther King, Jr.

^ permalink raw reply

* Re: developing a modified Linux-style workflow
From: Neal Kreitzinger @ 2010-12-13 16:15 UTC (permalink / raw)
  To: git
In-Reply-To: <7EAE16CF-A9A8-47A6-9294-3646CCDB0E9C@at.or.at>

"Hans-Christoph Steiner" <hans@at.or.at> wrote in message 
news:7EAE16CF-A9A8-47A6-9294-3646CCDB0E9C@at.or.at...
>
> Hey all,
>
> (and my second post on this list...)
>
> I've gotten pretty good at git, and its helping me already with  managing 
> the very odd workflows I have with the software I work a lot  on called Pd 
> (http://puredata.info).  My role in Pd development is  like a Linux 
> lieutenant.
>
> I also the main dev for an app called Pd-extended, which is based on  Pd. 
> Now I'm stuck trying to figure out how to use git to match my  current 
> workflow for Pd-extended, which is a kind of long-lived  branch, almost 
> like a friendly fork.  So its kind of close to the  Linux workflow with me 
> as a lieutenant, but not quite.
>
> What makes it tricky is that I make releases directly from my repo  that 
> are widely used.  So my repo is both lieutenant and dictator at  the same 
> time.  So that's where I am stumped.  I want to be able to  rebase and 
> push to a public repo, but that would be stupid.  So there  has got to be 
> another way.
>
> .hc
>
I don't think pushing to a public repo is stupid.  You could create a bare 
repo with a Pd branch and Pd-extended branch that contain the production 
versions of Pd and Pd-extended.  The main reason our shop chose git is 
because it allows us to easily have multiple concurrent versions of 
production by having a branch for each of our custom versions.  These 
versions eventually get merged together into a major release, but in the 
meantime they are longlived branches representing the productional 
customized system for each major customer.

*If* you end up merging Pd and Pd-extended at some point, then you could 
have another branch for that, e.g. master or Pd-master or whatever.  BTW, 
you do not have to use master as the representative of your final merged 
work so don't think that is the way you HAVE to do it.  It's just the 
default, and a common practice for systems with a single version of 
production.  Master can become vestigial or secondary, if you choose to 
create a new branch called Pd-master, etc. to represent your eventual merges 
of Pd and Pd-extended.


v/r,
Neal 

^ permalink raw reply

* [PATCH/RFC] t800?-blame.sh: retitle uniquely
From: Michael J Gruber @ 2010-12-13 16:12 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Johannes Sixt
In-Reply-To: <4D05F1EA.9000403@viscovery.net>

Currently we have three test files matching t800?-blame.sh.

Rename the latter two to make it easier to spot where additions would
go.

Signed-off-by: Michael J Gruber <git@drmicha.warpmail.net>
---
On a related note to J6t's patch, how's the stance on unique titles?
Unique numbers are important for partial test runs, of course,
but unique titles help finding you way through the test.
There are more than the blame.sh ones.

 t/{t8003-blame.sh => t8003-blame-corner-cases.sh}  |    0
 ...8004-blame.sh => t8004-blame-with-conflicts.sh} |    0
 2 files changed, 0 insertions(+), 0 deletions(-)
 rename t/{t8003-blame.sh => t8003-blame-corner-cases.sh} (100%)
 rename t/{t8004-blame.sh => t8004-blame-with-conflicts.sh} (100%)

diff --git a/t/t8003-blame.sh b/t/t8003-blame-corner-cases.sh
similarity index 100%
rename from t/t8003-blame.sh
rename to t/t8003-blame-corner-cases.sh
diff --git a/t/t8004-blame.sh b/t/t8004-blame-with-conflicts.sh
similarity index 100%
rename from t/t8004-blame.sh
rename to t/t8004-blame-with-conflicts.sh
-- 
1.7.3.3.738.g018bc

^ permalink raw reply

* Corruption in the repository
From: Sylvestre Ledru @ 2010-12-13 15:59 UTC (permalink / raw)
  To: git; +Cc: Simon Gareste, Bruno JOFRET

Hello guys,

I have a small problem with a git repository and I haven't find a way to
fix my problem.
I am using git with gerrit [1] as frontend (even if I don't think it is
related here).
For an unknown reason, the repository just became corrupted.

When I try to clone the repository straight with the file system, the
following error is displayed:
error: refs/changes/98/398/1 does not point to a valid object!
error: refs/changes/98/398/2 does not point to a valid object!
fatal: object cff52c24fba28408e7d021a8f35a717bef31521d is corrupted
fatal: The remote end hung up unexpectedly

git-prune & git-fsck both fail.

Does anyone know how to repair this error ?

Thanks
Sylvestre

[1] http://code.google.com/p/gerrit/

^ permalink raw reply

* Re: APIs for automatic patch generation
From: Markus Elfring @ 2010-12-13 16:00 UTC (permalink / raw)
  To: git, libgit2
In-Reply-To: <4B840AA2.3010604@web.de>

> The commands "git diff" and "git format-patch" contain functionality that I
> would like to reuse for my little application in a C++ class library.

Which functions exist in the recently published C API 
(http://libgit2.github.com/) that can provide the following data?
* a line like "index 8d16832..358c98b 100644"
* range specifications for difference hunks
* mail construction

Regards,
Markus

^ permalink raw reply

* Git silently ignores --date when data is not in the correct format
From: Sergio @ 2010-12-13 15:20 UTC (permalink / raw)
  To: git

Hi,

on 1.7.3.3, I have noticed that git --commit silently ignores the 
--date=<date> switch if <date> is not in the current format.

for instance

git --commit --amend --date="10.11.2010" creates a commit with the current
date and time, because the --date argument misses the time.

possibly, it would be better to stop with an error message.

^ permalink raw reply

* Re: Git SVN non-standard branch/tag/trunk layout
From: Stephen Bash @ 2010-12-13 14:23 UTC (permalink / raw)
  To: Albert Krawczyk; +Cc: git
In-Reply-To: <006c01cb9a44$8407d2f0$8c1778d0$@optusnet.com.au>

----- Original Message -----
> From: "Albert Krawczyk" <pro-logic@optusnet.com.au>
> To: git@vger.kernel.org
> Sent: Sunday, December 12, 2010 4:35:34 PM
> Subject: Git SVN non-standard branch/tag/trunk layout
> 
> The SVN repo I am now faced with has the trunk/branch/tag folders on
> selected folders in the tree.
> 
> Essentially instead of having one project per repo, there are multiple
> projects in the repo. So the repo looks like this
> 
> ---SVN Root --- Folder(Proj1) ---- Files
> \
> ---- Folder(Proj2) --- Trunk - Files
> |	       \
> |		- Branch - Files
> |		|
> |		- Tag - ...
> |
> |- Proj3 - Files
> |- Proj4 - Trunk
> |-Branch
> | - Tag
> 
> The question is, is there a way I can get Git SVN to understand and
> replicate this layout in a git repo? I don't mind if I have to import
> the entire repo again into git.

When I have to deal with non-standard SVN layouts I do the following:
 1) git svn init tgtDir
 2) Edit the config file (see below)
 3) cd tgtDir
 4) git svn fetch

Basically the svn-remote section of the config file allows you to play games with the translation of SVN paths to Git branches.  Basically each line is of the form svnPath:gitRef.

'fetch' lines are fixed SVN paths that map to a fixed Git ref.  You can have zero or more fetch lines as long as the Git refs are unambiguous (add to the static portion of each ref name to make it unambiguous).  

'branches' and 'tags' lines are each allowed to have a single asterisk (*) on either side of the colon (:) that acts like a wildcard -- the SVN directory name at the position of the asterisk will take the place of the asterisk on the right hand side (which must be the end of the line).  Again, you can have zero or more of each of these as long as the left hand side of each is unambiguous.

So taking a SWAG at your project layout (I'm assuming 'Branch' is the actual branch name, not a directory called 'Branch', similar for 'Tag', and I don't know where proj3 and proj4 are -- are they under Proj2 or back in the SVN root?):

[svn-remote "svn"]
        url = http://server.org/svn

        # Project 1 (note use of the name 'trunk' in Git is a personal choice)
        fetch = proj1:refs/remotes/proj1/trunk

        # Project 2
        branches = proj2/*:refs/remotes/proj2/*

        # Project 3 (note use of the name 'trunk' in Git is a personal choice)
        fetch = proj3:refs/remotes/proj3/trunk

        # Project 4 (note use of the name 'trunk' in Git is a personal choice)
        fetch = proj4/trunk:refs/remotes/proj4/trunk

        # etc...

Project 2 is an interesting one because it looks like the trunk is at the same level as branches/tags.  If that's the case, the 'branches' line above will work (it will treat the trunk like any other branch -- a very Git-like approach).  Also note that those projects that didn't have a 'trunk' directory in SVN I added a 'trunk' on the Git side to keep things consistent -- this is completely optional.

Once you get comfortable with the rules governing the config lines, you can pretty much untangle any SVN layout.

HTH,
Stephen

^ permalink raw reply

* Re: [ANNOUNCE] GitJungle is out!
From: Jakub Narebski @ 2010-12-13 13:12 UTC (permalink / raw)
  To: psantosl@codicesoftware.com; +Cc: git
In-Reply-To: <4D05FF8D.7080306@codicesoftware.com>

"psantosl@codicesoftware.com" <psantosl@codicesoftware.com> writes:

> We've just released GitJungle
> (http://www.plasticscm.com/labs/gitjungle.aspx), a git branch explorer
> based on the same codebase we use in our version control product,
> plastic scm.
> 
> We wanted to call it something like GitForest (you know, so many
> branches and trees :P) but the name was already reserved...
> 
> GitJungle is a beta and works on Linux, Mac and Windows and basically
> we'd love to get feedback. The drawing approach we use is a little bit
> different from what other git tools are using: we draw horizontally
> instead of vertically, we think it is a better way but, you know, it is
> probably a matter of preference.
> 
> I'd really like if you could give it a try and of course any feedback
> (including tough critics) will be more than welcome.

Could you add information about GitJungle in the correct place at
https://git.wiki.kernel.org/index.php/InterfacesFrontendsAndTools
page on Git Wiki?

Thanks in advance
-- 
Jakub Narebski
Poland
ShadeHawk on #git

^ permalink raw reply

* [ANNOUNCE] GitJungle is out!
From: psantosl @ 2010-12-13 11:12 UTC (permalink / raw)
  To: git

Hi all,

We've just released GitJungle
(http://www.plasticscm.com/labs/gitjungle.aspx), a git branch explorer
based on the same codebase we use in our version control product,
plastic scm.

We wanted to call it something like GitForest (you know, so many
branches and trees :P) but the name was already reserved...

GitJungle is a beta and works on Linux, Mac and Windows and basically
we'd love to get feedback. The drawing approach we use is a little bit
different from what other git tools are using: we draw horizontally
instead of vertically, we think it is a better way but, you know, it is
probably a matter of preference.

I'd really like if you could give it a try and of course any feedback
(including tough critics) will be more than welcome.

Thanks,

pablo

^ permalink raw reply

* Re: What's cooking in git.git (Dec 2010, #04; Mon, 13)
From: Ævar Arnfjörð Bjarmason @ 2010-12-13 11:47 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7v7hfe5awz.fsf@alter.siamese.dyndns.org>

On Mon, Dec 13, 2010 at 09:34, Junio C Hamano <gitster@pobox.com> wrote:

> Needs a bit more minor work to get the basic code structure right.

And I'm still not sure (see earlier replies to "What's Cooking" posts)
what needs to be done to make it better.

^ permalink raw reply

* [PATCH] Avoid duplicate test number t7609
From: Johannes Sixt @ 2010-12-13 10:14 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git Mailing List

From: Johannes Sixt <j6t@kdbg.org>

Signed-off-by: Johannes Sixt <j6t@kdbg.org>
---
 t/{t7609-merge-abort.sh => t7611-merge-abort.sh} |    0
 1 files changed, 0 insertions(+), 0 deletions(-)
 rename t/{t7609-merge-abort.sh => t7611-merge-abort.sh} (100%)

diff --git a/t/t7609-merge-abort.sh b/t/t7611-merge-abort.sh
similarity index 100%
rename from t/t7609-merge-abort.sh
rename to t/t7611-merge-abort.sh
-- 
1.7.3.3.1800.g26f22

^ permalink raw reply

* [PATCH 14/19] Convert ce_path_match() use to match_pathspec()
From: Nguyễn Thái Ngọc Duy @ 2010-12-13  9:46 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy
In-Reply-To: <1292233616-27692-1-git-send-email-pclouds@gmail.com>

Previously ce_path_match() is used together with tree_entry_interesting().
Both do not support wildcards. tree_entry_interesting() understands
wildcards now, so it's time to teach ce_path_match() to do the same.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 read-cache.c |   20 +-------------------
 1 files changed, 1 insertions(+), 19 deletions(-)

diff --git a/read-cache.c b/read-cache.c
index 1f42473..cbabd8b 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -685,28 +685,10 @@ int ce_same_name(struct cache_entry *a, struct cache_entry *b)
 
 int ce_path_match(const struct cache_entry *ce, const char **pathspec)
 {
-	const char *match, *name;
-	int len;
-
 	if (!pathspec)
 		return 1;
 
-	len = ce_namelen(ce);
-	name = ce->name;
-	while ((match = *pathspec++) != NULL) {
-		int matchlen = strlen(match);
-		if (matchlen > len)
-			continue;
-		if (memcmp(name, match, matchlen))
-			continue;
-		if (matchlen && name[matchlen-1] == '/')
-			return 1;
-		if (name[matchlen] == '/' || !name[matchlen])
-			return 1;
-		if (!matchlen)
-			return 1;
-	}
-	return 0;
+	return match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, NULL);
 }
 
 /*
-- 
1.7.3.3.476.g10a82

^ permalink raw reply related

* [PATCH 04/19] Convert struct diff_options to use struct pathspec
From: Nguyễn Thái Ngọc Duy @ 2010-12-13  9:46 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy
In-Reply-To: <1292233616-27692-1-git-send-email-pclouds@gmail.com>

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/diff-files.c |    2 +-
 builtin/diff.c       |    4 ++--
 builtin/log.c        |    2 +-
 diff-lib.c           |    2 +-
 diff-no-index.c      |    4 ++--
 diff.h               |    4 +---
 revision.c           |    6 +-----
 tree-diff.c          |   46 +++++++++++-----------------------------------
 8 files changed, 20 insertions(+), 50 deletions(-)

diff --git a/builtin/diff-files.c b/builtin/diff-files.c
index 951c7c8..46085f8 100644
--- a/builtin/diff-files.c
+++ b/builtin/diff-files.c
@@ -61,7 +61,7 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
 	    (rev.diffopt.output_format & DIFF_FORMAT_PATCH))
 		rev.combine_merges = rev.dense_combined_merges = 1;
 
-	if (read_cache_preload(rev.diffopt.paths) < 0) {
+	if (read_cache_preload(rev.diffopt.pathspec.raw) < 0) {
 		perror("read_cache_preload");
 		return -1;
 	}
diff --git a/builtin/diff.c b/builtin/diff.c
index a43d326..76c42d8 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -135,7 +135,7 @@ static int builtin_diff_index(struct rev_info *revs,
 	    revs->max_count != -1 || revs->min_age != -1 ||
 	    revs->max_age != -1)
 		usage(builtin_diff_usage);
-	if (read_cache_preload(revs->diffopt.paths) < 0) {
+	if (read_cache_preload(revs->diffopt.pathspec.raw) < 0) {
 		perror("read_cache_preload");
 		return -1;
 	}
@@ -237,7 +237,7 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv
 		revs->combine_merges = revs->dense_combined_merges = 1;
 
 	setup_work_tree();
-	if (read_cache_preload(revs->diffopt.paths) < 0) {
+	if (read_cache_preload(revs->diffopt.pathspec.raw) < 0) {
 		perror("read_cache_preload");
 		return -1;
 	}
diff --git a/builtin/log.c b/builtin/log.c
index eaa1ee0..92779a5 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -89,7 +89,7 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
 		rev->always_show_header = 0;
 	if (DIFF_OPT_TST(&rev->diffopt, FOLLOW_RENAMES)) {
 		rev->always_show_header = 0;
-		if (rev->diffopt.nr_paths != 1)
+		if (rev->diffopt.pathspec.nr != 1)
 			usage("git logs can only follow renames on one pathname at a time");
 	}
 	for (i = 1; i < argc; i++) {
diff --git a/diff-lib.c b/diff-lib.c
index 392ce2b..3b809f2 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -501,7 +501,7 @@ int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt)
 	active_nr = dst - active_cache;
 
 	init_revisions(&revs, NULL);
-	revs.prune_data = opt->paths;
+	revs.prune_data = opt->pathspec.raw;
 	tree = parse_tree_indirect(tree_sha1);
 	if (!tree)
 		die("bad tree object %s", sha1_to_hex(tree_sha1));
diff --git a/diff-no-index.c b/diff-no-index.c
index e48ab92..3a36144 100644
--- a/diff-no-index.c
+++ b/diff-no-index.c
@@ -260,8 +260,8 @@ void diff_no_index(struct rev_info *revs,
 	if (diff_setup_done(&revs->diffopt) < 0)
 		die("diff_setup_done failed");
 
-	if (queue_diff(&revs->diffopt, revs->diffopt.paths[0],
-		       revs->diffopt.paths[1]))
+	if (queue_diff(&revs->diffopt, revs->diffopt.pathspec.raw[0],
+		       revs->diffopt.pathspec.raw[1]))
 		exit(1);
 	diff_set_mnemonic_prefix(&revs->diffopt, "1/", "2/");
 	diffcore_std(&revs->diffopt);
diff --git a/diff.h b/diff.h
index bf2f44d..6497b71 100644
--- a/diff.h
+++ b/diff.h
@@ -133,9 +133,7 @@ struct diff_options {
 	FILE *file;
 	int close_file;
 
-	int nr_paths;
-	const char **paths;
-	int *pathlens;
+	struct pathspec pathspec;
 	change_fn_t change;
 	add_remove_fn_t add_remove;
 	diff_format_fn_t format_callback;
diff --git a/revision.c b/revision.c
index b1c1890..b2a5867 100644
--- a/revision.c
+++ b/revision.c
@@ -553,11 +553,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)
 
 	left_first = left_count < right_count;
 	init_patch_ids(&ids);
-	if (revs->diffopt.nr_paths) {
-		ids.diffopts.nr_paths = revs->diffopt.nr_paths;
-		ids.diffopts.paths = revs->diffopt.paths;
-		ids.diffopts.pathlens = revs->diffopt.pathlens;
-	}
+	ids.diffopts.pathspec = revs->diffopt.pathspec;
 
 	/* Compute patch-ids for one side */
 	for (p = list; p; p = p->next) {
diff --git a/tree-diff.c b/tree-diff.c
index cd659c6..986c0f4 100644
--- a/tree-diff.c
+++ b/tree-diff.c
@@ -100,16 +100,16 @@ static int tree_entry_interesting(struct tree_desc *desc, const char *base, int
 	int pathlen;
 	int never_interesting = -1;
 
-	if (!opt->nr_paths)
+	if (!opt->pathspec.nr)
 		return 1;
 
 	sha1 = tree_entry_extract(desc, &path, &mode);
 
 	pathlen = tree_entry_len(path, sha1);
 
-	for (i = 0; i < opt->nr_paths; i++) {
-		const char *match = opt->paths[i];
-		int matchlen = opt->pathlens[i];
+	for (i = 0; i < opt->pathspec.nr; i++) {
+		const char *match = opt->pathspec.raw[i];
+		int matchlen = opt->pathspec.items[i].len;
 		int m = -1; /* signals that we haven't called strncmp() */
 
 		if (baselen >= matchlen) {
@@ -289,7 +289,7 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, stru
 		if (DIFF_OPT_TST(opt, QUICK) &&
 		    DIFF_OPT_TST(opt, HAS_CHANGES))
 			break;
-		if (opt->nr_paths) {
+		if (opt->pathspec.nr) {
 			skip_uninteresting(t1, base, baselen, opt);
 			skip_uninteresting(t2, base, baselen, opt);
 		}
@@ -348,7 +348,7 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co
 	DIFF_OPT_SET(&diff_opts, RECURSIVE);
 	DIFF_OPT_SET(&diff_opts, FIND_COPIES_HARDER);
 	diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
-	diff_opts.single_follow = opt->paths[0];
+	diff_opts.single_follow = opt->pathspec.raw[0];
 	diff_opts.break_opt = opt->break_opt;
 	paths[0] = NULL;
 	diff_tree_setup_paths(paths, &diff_opts);
@@ -368,15 +368,15 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co
 		 * diff_queued_diff, we will also use that as the path in
 		 * the future!
 		 */
-		if ((p->status == 'R' || p->status == 'C') && !strcmp(p->two->path, opt->paths[0])) {
+		if ((p->status == 'R' || p->status == 'C') && !strcmp(p->two->path, opt->pathspec.raw[0])) {
 			/* Switch the file-pairs around */
 			q->queue[i] = choice;
 			choice = p;
 
 			/* Update the path we use from now on.. */
 			diff_tree_release_paths(opt);
-			opt->paths[0] = xstrdup(p->one->path);
-			diff_tree_setup_paths(opt->paths, opt);
+			opt->pathspec.raw[0] = xstrdup(p->one->path);
+			diff_tree_setup_paths(opt->pathspec.raw, opt);
 
 			/*
 			 * The caller expects us to return a set of vanilla
@@ -451,36 +451,12 @@ int diff_root_tree_sha1(const unsigned char *new, const char *base, struct diff_
 	return retval;
 }
 
-static int count_paths(const char **paths)
-{
-	int i = 0;
-	while (*paths++)
-		i++;
-	return i;
-}
-
 void diff_tree_release_paths(struct diff_options *opt)
 {
-	free(opt->pathlens);
+	free_pathspec(&opt->pathspec);
 }
 
 void diff_tree_setup_paths(const char **p, struct diff_options *opt)
 {
-	opt->nr_paths = 0;
-	opt->pathlens = NULL;
-	opt->paths = NULL;
-
-	if (p) {
-		int i;
-
-		opt->paths = p;
-		opt->nr_paths = count_paths(p);
-		if (opt->nr_paths == 0) {
-			opt->pathlens = NULL;
-			return;
-		}
-		opt->pathlens = xmalloc(opt->nr_paths * sizeof(int));
-		for (i=0; i < opt->nr_paths; i++)
-			opt->pathlens[i] = strlen(p[i]);
-	}
+	init_pathspec(&opt->pathspec, p);
 }
-- 
1.7.3.3.476.g10a82

^ permalink raw reply related

* [PATCH 11/19] tree_entry_interesting: support depth limit
From: Nguyễn Thái Ngọc Duy @ 2010-12-13  9:46 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy
In-Reply-To: <1292233616-27692-1-git-send-email-pclouds@gmail.com>

This is needed to replace pathspec_matches() in builtin/grep.c. Depth
limit is only effective when pathspec.recursive == 1

max_depth == -1 means unlimited depth.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 pathspec.recursive is also needed for wildcard matching later on.

 cache.h     |    2 ++
 dir.c       |   15 +++++++++++++++
 dir.h       |    1 +
 tree-diff.c |    2 ++
 tree-walk.c |   19 +++++++++++++++++--
 5 files changed, 37 insertions(+), 2 deletions(-)

diff --git a/cache.h b/cache.h
index 3a1acf1..56da281 100644
--- a/cache.h
+++ b/cache.h
@@ -497,6 +497,8 @@ struct pathspec {
 	const char **raw; /* get_pathspec() result, not freed by free_pathspec() */
 	int nr;
 	int has_wildcard:1;
+	int recursive:1;
+	int max_depth;
 	struct pathspec_item {
 		int len, prefix_len;
 		int has_wildcard:1;
diff --git a/dir.c b/dir.c
index 0987d0c..bb5076c 100644
--- a/dir.c
+++ b/dir.c
@@ -71,6 +71,21 @@ int fill_directory(struct dir_struct *dir, const char **pathspec)
 	return len;
 }
 
+int within_depth(const char *name, int namelen,
+			int depth, int max_depth)
+{
+	const char *cp = name, *cpe = name + namelen;
+
+	while (cp < cpe) {
+		if (*cp++ != '/')
+			continue;
+		depth++;
+		if (depth > max_depth)
+			return 0;
+	}
+	return 1;
+}
+
 /*
  * Does 'match' match the given name?
  * A match is found if
diff --git a/dir.h b/dir.h
index 278d84c..c71de08 100644
--- a/dir.h
+++ b/dir.h
@@ -65,6 +65,7 @@ struct dir_struct {
 #define MATCHED_FNMATCH 2
 #define MATCHED_EXACTLY 3
 extern int match_pathspec(const char **pathspec, const char *name, int namelen, int prefix, char *seen);
+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);
diff --git a/tree-diff.c b/tree-diff.c
index a870f6c..7c3b770 100644
--- a/tree-diff.c
+++ b/tree-diff.c
@@ -165,6 +165,8 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2,
 	int baselen = strlen(base_);
 
 	memcpy(base, base_, baselen+1);
+	opt->pathspec.recursive = DIFF_OPT_TST(opt, RECURSIVE);
+	opt->pathspec.max_depth = -1;
 	for (;;) {
 		if (DIFF_OPT_TST(opt, QUICK) &&
 		    DIFF_OPT_TST(opt, HAS_CHANGES))
diff --git a/tree-walk.c b/tree-walk.c
index 40a4657..d28de30 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -1,6 +1,7 @@
 #include "cache.h"
 #include "tree-walk.h"
 #include "unpack-trees.h"
+#include "dir.h"
 #include "tree.h"
 
 static const char *get_mode(const char *str, unsigned int *modep)
@@ -558,9 +559,17 @@ int tree_entry_interesting(const struct name_entry *entry,
 	int pathlen;
 	int never_interesting = -1;
 
-	if (!ps || !ps->nr)
+	if (!ps)
 		return 1;
 
+	if (!ps->nr) {
+		if (!ps->recursive || ps->max_depth == -1)
+			return 1;
+		return !!within_depth(base, baselen,
+				      !!S_ISDIR(entry->mode),
+				      ps->max_depth);
+	}
+
 	pathlen = tree_entry_len(entry->path, entry->sha1);
 
 	for (i = 0; i < ps->nr; i++) {
@@ -571,7 +580,13 @@ int tree_entry_interesting(const struct name_entry *entry,
 			if (!match_dir_prefix(base, baselen, match, matchlen))
 				/* Just a random prefix match */
 				continue;
-			return 2;
+
+			if (!ps->recursive || ps->max_depth == -1)
+				return 2;
+
+			return !!within_depth(base+matchlen+1, baselen-matchlen-1,
+					      !!S_ISDIR(entry->mode),
+					      ps->max_depth);
 		}
 
 		/* Does the base match? */
-- 
1.7.3.3.476.g10a82

^ permalink raw reply related

* [PATCH 13/19] tree_entry_interesting(): optimize fnmatch when base is matched
From: Nguyễn Thái Ngọc Duy @ 2010-12-13  9:46 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy
In-Reply-To: <1292233616-27692-1-git-send-email-pclouds@gmail.com>

If base is already matched, skip that part when calling
fnmatch(). This happens quite often when users start a command from
worktree's subdirectory and prefix is usually prepended to all
pathspecs.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 t/t4010-diff-pathspec.sh |   14 ++++++++++++++
 tree-walk.c              |   15 +++++++++++++++
 2 files changed, 29 insertions(+), 0 deletions(-)

diff --git a/t/t4010-diff-pathspec.sh b/t/t4010-diff-pathspec.sh
index 94df7ae..4b120f8 100755
--- a/t/t4010-diff-pathspec.sh
+++ b/t/t4010-diff-pathspec.sh
@@ -70,4 +70,18 @@ test_expect_success 'diff-tree pathspec' '
 	test_cmp expected current
 '
 
+EMPTY_TREE=4b825dc642cb6eb9a060e54bf8d69288fbee4904
+
+test_expect_success 'diff-tree with wildcard shows dir also matches' '
+	git diff-tree --name-only $EMPTY_TREE $tree -- "f*" >result &&
+	echo file0 >expected &&
+	test_cmp expected result
+'
+
+test_expect_success 'diff-tree -r with wildcard' '
+	git diff-tree -r --name-only $EMPTY_TREE $tree -- "*file1" >result &&
+	echo path1/file1 >expected &&
+	test_cmp expected result
+'
+
 test_done
diff --git a/tree-walk.c b/tree-walk.c
index b5ad42b..e1a18fc 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -597,6 +597,21 @@ int tree_entry_interesting(const struct name_entry *entry,
 					match + baselen, matchlen - baselen,
 					&never_interesting))
 				return 1;
+
+			if (item->has_wildcard) {
+				never_interesting = 0;
+				if (!fnmatch(match + baselen, entry->path, 0))
+					return 1;
+
+				/*
+				 * Match all directories. We'll try to
+				 * match files later on.
+				 */
+				if (ps->recursive && S_ISDIR(entry->mode))
+					return 1;
+			}
+
+			continue;
 		}
 
 match_wildcards:
-- 
1.7.3.3.476.g10a82

^ permalink raw reply related

* [PATCH 19/19] grep: drop pathspec_matches() in favor of tree_entry_interesting()
From: Nguyễn Thái Ngọc Duy @ 2010-12-13  9:46 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy
In-Reply-To: <1292233616-27692-1-git-send-email-pclouds@gmail.com>


Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/grep.c |  130 ++++++-------------------------------------------------
 1 files changed, 15 insertions(+), 115 deletions(-)

diff --git a/builtin/grep.c b/builtin/grep.c
index 6bd5728..a56cdd6 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -333,106 +333,6 @@ static int grep_config(const char *var, const char *value, void *cb)
 	return 0;
 }
 
-/*
- * Return non-zero if max_depth is negative or path has no more then max_depth
- * slashes.
- */
-static int accept_subdir(const char *path, int max_depth)
-{
-	if (max_depth < 0)
-		return 1;
-
-	while ((path = strchr(path, '/')) != NULL) {
-		max_depth--;
-		if (max_depth < 0)
-			return 0;
-		path++;
-	}
-	return 1;
-}
-
-/*
- * Return non-zero if name is a subdirectory of match and is not too deep.
- */
-static int is_subdir(const char *name, int namelen,
-		const char *match, int matchlen, int max_depth)
-{
-	if (matchlen > namelen || strncmp(name, match, matchlen))
-		return 0;
-
-	if (name[matchlen] == '\0') /* exact match */
-		return 1;
-
-	if (!matchlen || match[matchlen-1] == '/' || name[matchlen] == '/')
-		return accept_subdir(name + matchlen + 1, max_depth);
-
-	return 0;
-}
-
-/*
- * git grep pathspecs are somewhat different from diff-tree pathspecs;
- * pathname wildcards are allowed.
- */
-static int pathspec_matches(const char **paths, const char *name, int max_depth)
-{
-	int namelen, i;
-	if (!paths || !*paths)
-		return accept_subdir(name, max_depth);
-	namelen = strlen(name);
-	for (i = 0; paths[i]; i++) {
-		const char *match = paths[i];
-		int matchlen = strlen(match);
-		const char *cp, *meta;
-
-		if (is_subdir(name, namelen, match, matchlen, max_depth))
-			return 1;
-		if (!fnmatch(match, name, 0))
-			return 1;
-		if (name[namelen-1] != '/')
-			continue;
-
-		/* We are being asked if the directory ("name") is worth
-		 * descending into.
-		 *
-		 * Find the longest leading directory name that does
-		 * not have metacharacter in the pathspec; the name
-		 * we are looking at must overlap with that directory.
-		 */
-		for (cp = match, meta = NULL; cp - match < matchlen; cp++) {
-			char ch = *cp;
-			if (ch == '*' || ch == '[' || ch == '?') {
-				meta = cp;
-				break;
-			}
-		}
-		if (!meta)
-			meta = cp; /* fully literal */
-
-		if (namelen <= meta - match) {
-			/* Looking at "Documentation/" and
-			 * the pattern says "Documentation/howto/", or
-			 * "Documentation/diff*.txt".  The name we
-			 * have should match prefix.
-			 */
-			if (!memcmp(match, name, namelen))
-				return 1;
-			continue;
-		}
-
-		if (meta - match < namelen) {
-			/* Looking at "Documentation/howto/" and
-			 * the pattern says "Documentation/h*";
-			 * match up to "Do.../h"; this avoids descending
-			 * into "Documentation/technical/".
-			 */
-			if (!memcmp(match, name, meta - match))
-				return 1;
-			continue;
-		}
-	}
-	return 0;
-}
-
 static void *lock_and_read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size)
 {
 	void *data;
@@ -632,39 +532,37 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
 		     struct tree_desc *tree, char *base,
 		     int baselen, int tree_name_len)
 {
-	int hit = 0;
+	int hit = 0, matched = 0;
 	struct name_entry entry;
 
 	while (tree_entry(tree, &entry)) {
 		int te_len = tree_entry_len(entry.path, entry.sha1);
-		int len = baselen;
-		memcpy(base + baselen, entry.path, te_len+1);
 
-		len += te_len;
-		if (S_ISDIR(entry.mode)) {
-			/* Match "abc/" against pathspec to
-			 * decide if we want to descend into "abc"
-			 * directory.
-			 */
-			base[len++] = '/';
-			base[len] = 0;
+		if (matched != 2) {
+			matched = tree_entry_interesting(&entry, base, baselen, pathspec);
+			if (matched == -1)
+				break; /* no more matches */
+			if (!matched)
+				continue;
 		}
 
-		if (!pathspec_matches(pathspec->raw, base, opt->max_depth))
-			;
-		else if (S_ISREG(entry.mode)) {
+		memcpy(base + baselen, entry.path, te_len+1);
+		if (S_ISREG(entry.mode))
 			hit |= grep_sha1(opt, entry.sha1, base-tree_name_len, tree_name_len);
-		}
 		else if (S_ISDIR(entry.mode)) {
 			enum object_type type;
 			struct tree_desc sub;
 			void *data;
 			unsigned long size;
+			int len = baselen + te_len;
 
 			data = lock_and_read_sha1_file(entry.sha1, &type, &size);
 			if (!data)
 				die("unable to read tree (%s)",
 				    sha1_to_hex(entry.sha1));
+
+			base[len++] = '/';
+			base[len] = 0;
 			init_tree_desc(&sub, data, size);
 			hit |= grep_tree(opt, pathspec, &sub, base, len, tree_name_len);
 			free(data);
@@ -1069,6 +967,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		paths[1] = NULL;
 	}
 	init_pathspec(&pathspec, paths);
+	pathspec.max_depth = opt.max_depth;
+	pathspec.recursive = 1;
 
 	if (show_in_pager && (cached || list.nr))
 		die("--open-files-in-pager only works on the worktree");
-- 
1.7.3.3.476.g10a82

^ permalink raw reply related

* [PATCH 18/19] grep: use preallocated buffer for grep_tree()
From: Nguyễn Thái Ngọc Duy @ 2010-12-13  9:46 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy
In-Reply-To: <1292233616-27692-1-git-send-email-pclouds@gmail.com>


Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 because tree_entry_interesting() will need writable "base".

 builtin/grep.c |   59 +++++++++++++++++++++++++++++--------------------------
 1 files changed, 31 insertions(+), 28 deletions(-)

diff --git a/builtin/grep.c b/builtin/grep.c
index 1646e15..6bd5728 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -623,44 +623,38 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int
 	return hit;
 }
 
+/*
+ * "base" is a writable buffer where
+ * - base[-tree_name_len..-1] contains tree_name
+ * - base[0..baselen-1] contains tree base
+ */
 static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
-		     struct tree_desc *tree,
-		     const char *tree_name, const char *base)
+		     struct tree_desc *tree, char *base,
+		     int baselen, int tree_name_len)
 {
-	int len;
 	int hit = 0;
 	struct name_entry entry;
-	char *down;
-	int tn_len = strlen(tree_name);
-	struct strbuf pathbuf;
-
-	strbuf_init(&pathbuf, PATH_MAX + tn_len);
-
-	if (tn_len) {
-		strbuf_add(&pathbuf, tree_name, tn_len);
-		strbuf_addch(&pathbuf, ':');
-		tn_len = pathbuf.len;
-	}
-	strbuf_addstr(&pathbuf, base);
-	len = pathbuf.len;
 
 	while (tree_entry(tree, &entry)) {
 		int te_len = tree_entry_len(entry.path, entry.sha1);
-		pathbuf.len = len;
-		strbuf_add(&pathbuf, entry.path, te_len);
+		int len = baselen;
+		memcpy(base + baselen, entry.path, te_len+1);
 
-		if (S_ISDIR(entry.mode))
+		len += te_len;
+		if (S_ISDIR(entry.mode)) {
 			/* Match "abc/" against pathspec to
 			 * decide if we want to descend into "abc"
 			 * directory.
 			 */
-			strbuf_addch(&pathbuf, '/');
+			base[len++] = '/';
+			base[len] = 0;
+		}
 
-		down = pathbuf.buf + tn_len;
-		if (!pathspec_matches(pathspec->raw, down, opt->max_depth))
+		if (!pathspec_matches(pathspec->raw, base, opt->max_depth))
 			;
-		else if (S_ISREG(entry.mode))
-			hit |= grep_sha1(opt, entry.sha1, pathbuf.buf, tn_len);
+		else if (S_ISREG(entry.mode)) {
+			hit |= grep_sha1(opt, entry.sha1, base-tree_name_len, tree_name_len);
+		}
 		else if (S_ISDIR(entry.mode)) {
 			enum object_type type;
 			struct tree_desc sub;
@@ -672,13 +666,12 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
 				die("unable to read tree (%s)",
 				    sha1_to_hex(entry.sha1));
 			init_tree_desc(&sub, data, size);
-			hit |= grep_tree(opt, pathspec, &sub, tree_name, down);
+			hit |= grep_tree(opt, pathspec, &sub, base, len, tree_name_len);
 			free(data);
 		}
 		if (hit && opt->status_only)
 			break;
 	}
-	strbuf_release(&pathbuf);
 	return hit;
 }
 
@@ -691,13 +684,23 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
 		struct tree_desc tree;
 		void *data;
 		unsigned long size;
-		int hit;
+		int hit, len;
+		char *base;
+
 		data = read_object_with_reference(obj->sha1, tree_type,
 						  &size, NULL);
 		if (!data)
 			die("unable to read tree (%s)", sha1_to_hex(obj->sha1));
 		init_tree_desc(&tree, data, size);
-		hit = grep_tree(opt, pathspec, &tree, name, "");
+		len = name ? strlen(name) : 0;
+		base = xmalloc(PATH_MAX + len + 1);
+		if (len) {
+			memcpy(base, name, len);
+			base[len++] = ':';
+		}
+		base[len] = 0;
+		hit = grep_tree(opt, pathspec, &tree, base+len, 0, len);
+		free(base);
 		free(data);
 		return hit;
 	}
-- 
1.7.3.3.476.g10a82

^ permalink raw reply related

* [PATCH 17/19] grep: use match_pathspec_depth() for cache/worktree grepping
From: Nguyễn Thái Ngọc Duy @ 2010-12-13  9:46 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy
In-Reply-To: <1292233616-27692-1-git-send-email-pclouds@gmail.com>


Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/grep.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/builtin/grep.c b/builtin/grep.c
index 4179af8..1646e15 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -595,7 +595,8 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int
 		struct cache_entry *ce = active_cache[nr];
 		if (!S_ISREG(ce->ce_mode))
 			continue;
-		if (!pathspec_matches(pathspec->raw, ce->name, opt->max_depth))
+		if (!match_pathspec_depth(pathspec->raw, opt->max_depth,
+					  ce->name, ce_namelen(ce), 0, NULL))
 			continue;
 		/*
 		 * If CE_VALID is on, we assume worktree file and its cache entry
-- 
1.7.3.3.476.g10a82

^ permalink raw reply related

* [PATCH 16/19] grep: convert to use struct pathspec
From: Nguyễn Thái Ngọc Duy @ 2010-12-13  9:46 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy
In-Reply-To: <1292233616-27692-1-git-send-email-pclouds@gmail.com>


Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/grep.c |   30 ++++++++++++++++--------------
 1 files changed, 16 insertions(+), 14 deletions(-)

diff --git a/builtin/grep.c b/builtin/grep.c
index da32f3d..4179af8 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -585,7 +585,7 @@ static void run_pager(struct grep_opt *opt, const char *prefix)
 	free(argv);
 }
 
-static int grep_cache(struct grep_opt *opt, const char **paths, int cached)
+static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int cached)
 {
 	int hit = 0;
 	int nr;
@@ -595,7 +595,7 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached)
 		struct cache_entry *ce = active_cache[nr];
 		if (!S_ISREG(ce->ce_mode))
 			continue;
-		if (!pathspec_matches(paths, ce->name, opt->max_depth))
+		if (!pathspec_matches(pathspec->raw, ce->name, opt->max_depth))
 			continue;
 		/*
 		 * If CE_VALID is on, we assume worktree file and its cache entry
@@ -622,7 +622,7 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached)
 	return hit;
 }
 
-static int grep_tree(struct grep_opt *opt, const char **paths,
+static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
 		     struct tree_desc *tree,
 		     const char *tree_name, const char *base)
 {
@@ -656,7 +656,7 @@ static int grep_tree(struct grep_opt *opt, const char **paths,
 			strbuf_addch(&pathbuf, '/');
 
 		down = pathbuf.buf + tn_len;
-		if (!pathspec_matches(paths, down, opt->max_depth))
+		if (!pathspec_matches(pathspec->raw, down, opt->max_depth))
 			;
 		else if (S_ISREG(entry.mode))
 			hit |= grep_sha1(opt, entry.sha1, pathbuf.buf, tn_len);
@@ -671,7 +671,7 @@ static int grep_tree(struct grep_opt *opt, const char **paths,
 				die("unable to read tree (%s)",
 				    sha1_to_hex(entry.sha1));
 			init_tree_desc(&sub, data, size);
-			hit |= grep_tree(opt, paths, &sub, tree_name, down);
+			hit |= grep_tree(opt, pathspec, &sub, tree_name, down);
 			free(data);
 		}
 		if (hit && opt->status_only)
@@ -681,7 +681,7 @@ static int grep_tree(struct grep_opt *opt, const char **paths,
 	return hit;
 }
 
-static int grep_object(struct grep_opt *opt, const char **paths,
+static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
 		       struct object *obj, const char *name)
 {
 	if (obj->type == OBJ_BLOB)
@@ -696,14 +696,14 @@ static int grep_object(struct grep_opt *opt, const char **paths,
 		if (!data)
 			die("unable to read tree (%s)", sha1_to_hex(obj->sha1));
 		init_tree_desc(&tree, data, size);
-		hit = grep_tree(opt, paths, &tree, name, "");
+		hit = grep_tree(opt, pathspec, &tree, name, "");
 		free(data);
 		return hit;
 	}
 	die("unable to grep from object of type %s", typename(obj->type));
 }
 
-static int grep_objects(struct grep_opt *opt, const char **paths,
+static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec,
 			const struct object_array *list)
 {
 	unsigned int i;
@@ -713,7 +713,7 @@ static int grep_objects(struct grep_opt *opt, const char **paths,
 	for (i = 0; i < nr; i++) {
 		struct object *real_obj;
 		real_obj = deref_tag(list->objects[i].item, NULL, 0);
-		if (grep_object(opt, paths, real_obj, list->objects[i].name)) {
+		if (grep_object(opt, pathspec, real_obj, list->objects[i].name)) {
 			hit = 1;
 			if (opt->status_only)
 				break;
@@ -722,7 +722,7 @@ static int grep_objects(struct grep_opt *opt, const char **paths,
 	return hit;
 }
 
-static int grep_directory(struct grep_opt *opt, const char **paths)
+static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec)
 {
 	struct dir_struct dir;
 	int i, hit = 0;
@@ -730,7 +730,7 @@ static int grep_directory(struct grep_opt *opt, const char **paths)
 	memset(&dir, 0, sizeof(dir));
 	setup_standard_excludes(&dir);
 
-	fill_directory(&dir, paths);
+	fill_directory(&dir, pathspec->raw);
 	for (i = 0; i < dir.nr; i++) {
 		hit |= grep_file(opt, dir.entries[i]->name);
 		if (hit && opt->status_only)
@@ -836,6 +836,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 	struct grep_opt opt;
 	struct object_array list = OBJECT_ARRAY_INIT;
 	const char **paths = NULL;
+	struct pathspec pathspec;
 	struct string_list path_list = STRING_LIST_INIT_NODUP;
 	int i;
 	int dummy;
@@ -1063,6 +1064,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 		paths[0] = prefix;
 		paths[1] = NULL;
 	}
+	init_pathspec(&pathspec, paths);
 
 	if (show_in_pager && (cached || list.nr))
 		die("--open-files-in-pager only works on the worktree");
@@ -1093,16 +1095,16 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 			die("--cached cannot be used with --no-index.");
 		if (list.nr)
 			die("--no-index cannot be used with revs.");
-		hit = grep_directory(&opt, paths);
+		hit = grep_directory(&opt, &pathspec);
 	} else if (!list.nr) {
 		if (!cached)
 			setup_work_tree();
 
-		hit = grep_cache(&opt, paths, cached);
+		hit = grep_cache(&opt, &pathspec, cached);
 	} else {
 		if (cached)
 			die("both --cached and trees are given.");
-		hit = grep_objects(&opt, paths, &list);
+		hit = grep_objects(&opt, &pathspec, &list);
 	}
 
 	if (use_threads)
-- 
1.7.3.3.476.g10a82

^ permalink raw reply related

* [PATCH 15/19] pathspec: add match_pathspec_depth()
From: Nguyễn Thái Ngọc Duy @ 2010-12-13  9:46 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy
In-Reply-To: <1292233616-27692-1-git-send-email-pclouds@gmail.com>

match_pathspec_depth() is similar to match_pathspec() except that it
can take depth limit.

In long term, match_pathspec() should be removed in favor of this
function.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 dir.c |   45 +++++++++++++++++++++++++++++++++++++++++++++
 dir.h |    3 +++
 2 files changed, 48 insertions(+), 0 deletions(-)

diff --git a/dir.c b/dir.c
index bb5076c..e12dbdd 100644
--- a/dir.c
+++ b/dir.c
@@ -169,6 +169,51 @@ int match_pathspec(const char **pathspec, const char *name, int namelen,
 	return retval;
 }
 
+int match_pathspec_depth(const char **pathspec, int max_depth,
+			 const char *name, int namelen,
+			 int prefix, char *seen)
+{
+	int i, retval = 0;
+
+	if (!pathspec) {
+		if (max_depth == -1)
+			return MATCHED_RECURSIVELY;
+
+		if (within_depth(name, namelen, 0, max_depth))
+			return MATCHED_EXACTLY;
+		else
+			return 0;
+	}
+
+	name += prefix;
+	namelen -= prefix;
+
+	for (i = 0; pathspec[i] != NULL; i++) {
+		int how;
+		const char *match = pathspec[i] + prefix;
+		if (seen && seen[i] == MATCHED_EXACTLY)
+			continue;
+		how = match_one(match, name, namelen);
+		if (max_depth != -1 &&
+		    how && how != MATCHED_FNMATCH) {
+			int len = strlen(match);
+			if (name[len] == '/')
+				len++;
+			if (within_depth(name+len, namelen-len, 0, max_depth))
+				how = MATCHED_EXACTLY;
+			else
+				how = 0;
+		}
+		if (how) {
+			if (retval < how)
+				retval = how;
+			if (seen && seen[i] < how)
+				seen[i] = how;
+		}
+	}
+	return retval;
+}
+
 static int no_wildcard(const char *string)
 {
 	return string[strcspn(string, "*?[{\\")] == '\0';
diff --git a/dir.h b/dir.h
index c71de08..9dc9592 100644
--- a/dir.h
+++ b/dir.h
@@ -65,6 +65,9 @@ struct dir_struct {
 #define MATCHED_FNMATCH 2
 #define MATCHED_EXACTLY 3
 extern int match_pathspec(const char **pathspec, const char *name, int namelen, int prefix, char *seen);
+extern int match_pathspec_depth(const char **pathspec, int max_depth,
+				const char *name, int namelen,
+				int prefix, char *seen);
 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);
-- 
1.7.3.3.476.g10a82

^ permalink raw reply related

* [PATCH 12/19] tree_entry_interesting(): support wildcard matching
From: Nguyễn Thái Ngọc Duy @ 2010-12-13  9:46 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy
In-Reply-To: <1292233616-27692-1-git-send-email-pclouds@gmail.com>


Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 tree-walk.c |   33 ++++++++++++++++++++++++++++++---
 tree-walk.h |    2 +-
 2 files changed, 31 insertions(+), 4 deletions(-)

diff --git a/tree-walk.c b/tree-walk.c
index d28de30..b5ad42b 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -552,7 +552,7 @@ static int match_dir_prefix(const char *base, int baselen,
  *  - negative for "no, and no subsequent entries will be either"
  */
 int tree_entry_interesting(const struct name_entry *entry,
-			   const char *base, int baselen,
+			   char *base, int baselen,
 			   const struct pathspec *ps)
 {
 	int i;
@@ -573,13 +573,15 @@ int tree_entry_interesting(const struct name_entry *entry,
 	pathlen = tree_entry_len(entry->path, entry->sha1);
 
 	for (i = 0; i < ps->nr; i++) {
+		const struct pathspec_item *item = ps->items+i;
+
 		const char *match = ps->raw[i];
-		int matchlen = ps->items[i].len;
+		int matchlen = item->len;
 
 		if (baselen >= matchlen) {
 			if (!match_dir_prefix(base, baselen, match, matchlen))
 				/* Just a random prefix match */
-				continue;
+				goto match_wildcards;
 
 			if (!ps->recursive || ps->max_depth == -1)
 				return 2;
@@ -596,6 +598,31 @@ int tree_entry_interesting(const struct name_entry *entry,
 					&never_interesting))
 				return 1;
 		}
+
+match_wildcards:
+		/*
+		 * Concatenate base and entry->path into one and do
+		 * fnmatch() on it.
+		 */
+
+		if (!item->has_wildcard)
+			continue;
+
+		never_interesting = 0;
+		memcpy(base + baselen, entry->path, pathlen+1);
+
+		if (!fnmatch(match, base, 0)) {
+			base[baselen] = 0;
+			return 1;
+		}
+		base[baselen] = 0;
+
+		/*
+		 * Match all directories. We'll try to match files
+		 * later on.
+		 */
+		if (ps->recursive && S_ISDIR(entry->mode))
+			return 1;
 	}
 	return never_interesting; /* No matches */
 }
diff --git a/tree-walk.h b/tree-walk.h
index c12f0a2..94e0ef4 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -60,6 +60,6 @@ static inline int traverse_path_len(const struct traverse_info *info, const stru
 	return info->pathlen + tree_entry_len(n->path, n->sha1);
 }
 
-extern int tree_entry_interesting(const struct name_entry *, const char *, int, const struct pathspec *ps);
+extern int tree_entry_interesting(const struct name_entry *, char *, int, const struct pathspec *ps);
 
 #endif
-- 
1.7.3.3.476.g10a82

^ permalink raw reply related

* [PATCH 10/19] tree_entry_interesting(): factor out most matching logic
From: Nguyễn Thái Ngọc Duy @ 2010-12-13  9:46 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy
In-Reply-To: <1292233616-27692-1-git-send-email-pclouds@gmail.com>


Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 tree-walk.c |  168 ++++++++++++++++++++++++++++++++--------------------------
 1 files changed, 93 insertions(+), 75 deletions(-)

diff --git a/tree-walk.c b/tree-walk.c
index 01168ea..40a4657 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -456,6 +456,91 @@ int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned ch
 	return retval;
 }
 
+static int match_entry(const struct name_entry *entry, int pathlen,
+		       const char *match, int matchlen,
+		       int *never_interesting)
+{
+	int m = -1; /* signals that we haven't called strncmp() */
+
+	if (*never_interesting) {
+		/*
+		 * We have not seen any match that sorts later
+		 * than the current path.
+		 */
+
+		/*
+		 * Does match sort strictly earlier than path
+		 * with their common parts?
+		 */
+		m = strncmp(match, entry->path,
+			    (matchlen < pathlen) ? matchlen : pathlen);
+		if (m < 0)
+			return 0;
+
+		/*
+		 * If we come here even once, that means there is at
+		 * least one pathspec that would sort equal to or
+		 * later than the path we are currently looking at.
+		 * In other words, if we have never reached this point
+		 * after iterating all pathspecs, it means all
+		 * pathspecs are either outside of base, or inside the
+		 * base but sorts strictly earlier than the current
+		 * one.  In either case, they will never match the
+		 * subsequent entries.  In such a case, we initialized
+		 * the variable to -1 and that is what will be
+		 * returned, allowing the caller to terminate early.
+		 */
+		*never_interesting = 0;
+	}
+
+	if (pathlen > matchlen)
+		return 0;
+
+	if (matchlen > pathlen) {
+		if (match[pathlen] != '/')
+			return 0;
+		if (!S_ISDIR(entry->mode))
+			return 0;
+	}
+
+	if (m == -1)
+		/*
+		 * we cheated and did not do strncmp(), so we do
+		 * that here.
+		 */
+		m = strncmp(match, entry->path, pathlen);
+
+	/*
+	 * If common part matched earlier then it is a hit,
+	 * because we rejected the case where path is not a
+	 * leading directory and is shorter than match.
+	 */
+	if (!m)
+		return 1;
+
+	return 0;
+}
+
+static int match_dir_prefix(const char *base, int baselen,
+			    const char *match, int matchlen)
+{
+	/* If it doesn't match, move along... */
+	if (strncmp(base, match, matchlen))
+		return 0;
+
+	/*
+	 * If the base is a subdirectory of a path which
+	 * was specified, all of them are interesting.
+	 */
+	if (!matchlen ||
+	    base[matchlen] == '/' ||
+	    match[matchlen - 1] == '/')
+		return 1;
+
+	/* Just a random prefix match */
+	return 0;
+}
+
 /*
  * Is a tree entry interesting given the pathspec we have?
  *
@@ -481,88 +566,21 @@ int tree_entry_interesting(const struct name_entry *entry,
 	for (i = 0; i < ps->nr; i++) {
 		const char *match = ps->raw[i];
 		int matchlen = ps->items[i].len;
-		int m = -1; /* signals that we haven't called strncmp() */
 
 		if (baselen >= matchlen) {
-			/* If it doesn't match, move along... */
-			if (strncmp(base, match, matchlen))
+			if (!match_dir_prefix(base, baselen, match, matchlen))
+				/* Just a random prefix match */
 				continue;
-
-			/*
-			 * If the base is a subdirectory of a path which
-			 * was specified, all of them are interesting.
-			 */
-			if (!matchlen ||
-			    base[matchlen] == '/' ||
-			    match[matchlen - 1] == '/')
-				return 2;
-
-			/* Just a random prefix match */
-			continue;
+			return 2;
 		}
 
 		/* Does the base match? */
-		if (strncmp(base, match, baselen))
-			continue;
-
-		match += baselen;
-		matchlen -= baselen;
-
-		if (never_interesting) {
-			/*
-			 * We have not seen any match that sorts later
-			 * than the current path.
-			 */
-
-			/*
-			 * Does match sort strictly earlier than path
-			 * with their common parts?
-			 */
-			m = strncmp(match, entry->path,
-				    (matchlen < pathlen) ? matchlen : pathlen);
-			if (m < 0)
-				continue;
-
-			/*
-			 * If we come here even once, that means there is at
-			 * least one pathspec that would sort equal to or
-			 * later than the path we are currently looking at.
-			 * In other words, if we have never reached this point
-			 * after iterating all pathspecs, it means all
-			 * pathspecs are either outside of base, or inside the
-			 * base but sorts strictly earlier than the current
-			 * one.  In either case, they will never match the
-			 * subsequent entries.  In such a case, we initialized
-			 * the variable to -1 and that is what will be
-			 * returned, allowing the caller to terminate early.
-			 */
-			never_interesting = 0;
+		if (!strncmp(base, match, baselen)) {
+			if (match_entry(entry, pathlen,
+					match + baselen, matchlen - baselen,
+					&never_interesting))
+				return 1;
 		}
-
-		if (pathlen > matchlen)
-			continue;
-
-		if (matchlen > pathlen) {
-			if (match[pathlen] != '/')
-				continue;
-			if (!S_ISDIR(entry->mode))
-				continue;
-		}
-
-		if (m == -1)
-			/*
-			 * we cheated and did not do strncmp(), so we do
-			 * that here.
-			 */
-			m = strncmp(match, entry->path, pathlen);
-
-		/*
-		 * If common part matched earlier then it is a hit,
-		 * because we rejected the case where path is not a
-		 * leading directory and is shorter than match.
-		 */
-		if (!m)
-			return 1;
 	}
 	return never_interesting; /* No matches */
 }
-- 
1.7.3.3.476.g10a82

^ permalink raw reply related

* [PATCH 09/19] tree-diff.c: reserve space in "base" for pathname concatenation
From: Nguyễn Thái Ngọc Duy @ 2010-12-13  9:46 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy
In-Reply-To: <1292233616-27692-1-git-send-email-pclouds@gmail.com>

This patch make sure that "base" parameter is writable. The callees
are free to modify it as long as base remains the same before
entering and after leaving the callee.

This avoids quite a bit of malloc and memcpy().

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 tree-diff.c |   87 +++++++++++++++++++++++++++-------------------------------
 1 files changed, 41 insertions(+), 46 deletions(-)

diff --git a/tree-diff.c b/tree-diff.c
index 50d7e6d..a870f6c 100644
--- a/tree-diff.c
+++ b/tree-diff.c
@@ -6,34 +6,17 @@
 #include "diffcore.h"
 #include "tree.h"
 
-static char *malloc_base(const char *base, int baselen, const char *path, int pathlen)
-{
-	char *newbase = xmalloc(baselen + pathlen + 2);
-	memcpy(newbase, base, baselen);
-	memcpy(newbase + baselen, path, pathlen);
-	memcpy(newbase + baselen + pathlen, "/", 2);
-	return newbase;
-}
+static void show_entry(struct diff_options *opt, const char *prefix,
+		       struct tree_desc *desc, char *base, int baselen);
 
-static char *malloc_fullname(const char *base, int baselen, const char *path, int pathlen)
-{
-	char *fullname = xmalloc(baselen + pathlen + 1);
-	memcpy(fullname, base, baselen);
-	memcpy(fullname + baselen, path, pathlen);
-	fullname[baselen + pathlen] = 0;
-	return fullname;
-}
-
-static void show_entry(struct diff_options *opt, const char *prefix, struct tree_desc *desc,
-		       const char *base, int baselen);
-
-static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const char *base, int baselen, struct diff_options *opt)
+static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2,
+			      char *base, int baselen,
+			      struct diff_options *opt)
 {
 	unsigned mode1, mode2;
 	const char *path1, *path2;
 	const unsigned char *sha1, *sha2;
 	int cmp, pathlen1, pathlen2;
-	char *fullname;
 
 	sha1 = tree_entry_extract(t1, &path1, &mode1);
 	sha2 = tree_entry_extract(t2, &path2, &mode2);
@@ -64,26 +47,31 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const
 
 	if (DIFF_OPT_TST(opt, RECURSIVE) && S_ISDIR(mode1)) {
 		int retval;
-		char *newbase = malloc_base(base, baselen, path1, pathlen1);
+
+		memcpy(base + baselen, path1, pathlen1);
+		memcpy(base + baselen + pathlen1, "/", 2);
+
 		if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE)) {
-			newbase[baselen + pathlen1] = 0;
+			base[baselen + pathlen1] = 0;
 			opt->change(opt, mode1, mode2,
-				    sha1, sha2, newbase, 0, 0);
-			newbase[baselen + pathlen1] = '/';
+				    sha1, sha2, base, 0, 0);
+			base[baselen + pathlen1] = '/';
 		}
-		retval = diff_tree_sha1(sha1, sha2, newbase, opt);
-		free(newbase);
+		retval = diff_tree_sha1(sha1, sha2, base, opt);
+		base[baselen] = 0;
 		return retval;
 	}
 
-	fullname = malloc_fullname(base, baselen, path1, pathlen1);
-	opt->change(opt, mode1, mode2, sha1, sha2, fullname, 0, 0);
-	free(fullname);
+	memcpy(base + baselen, path1, pathlen1);
+	base[baselen + pathlen1] = 0;
+	opt->change(opt, mode1, mode2, sha1, sha2, base, 0, 0);
+	base[baselen] = 0;
 	return 0;
 }
 
 /* A whole sub-tree went away or appeared */
-static void show_tree(struct diff_options *opt, const char *prefix, struct tree_desc *desc, const char *base, int baselen)
+static void show_tree(struct diff_options *opt, const char *prefix,
+		      struct tree_desc *desc, char *base, int baselen)
 {
 	int all_interesting = 0;
 	while (desc->size) {
@@ -105,8 +93,8 @@ static void show_tree(struct diff_options *opt, const char *prefix, struct tree_
 }
 
 /* A file entry went away or appeared */
-static void show_entry(struct diff_options *opt, const char *prefix, struct tree_desc *desc,
-		       const char *base, int baselen)
+static void show_entry(struct diff_options *opt, const char *prefix,
+		       struct tree_desc *desc, char *base, int baselen)
 {
 	unsigned mode;
 	const char *path;
@@ -115,34 +103,38 @@ static void show_entry(struct diff_options *opt, const char *prefix, struct tree
 
 	if (DIFF_OPT_TST(opt, RECURSIVE) && S_ISDIR(mode)) {
 		enum object_type type;
-		char *newbase = malloc_base(base, baselen, path, pathlen);
 		struct tree_desc inner;
 		void *tree;
 		unsigned long size;
 
+		memcpy(base + baselen, path, pathlen);
+		memcpy(base + baselen + pathlen, "/", 2);
+
 		tree = read_sha1_file(sha1, &type, &size);
 		if (!tree || type != OBJ_TREE)
 			die("corrupt tree sha %s", sha1_to_hex(sha1));
 
 		if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE)) {
-			newbase[baselen + pathlen] = 0;
-			opt->add_remove(opt, *prefix, mode, sha1, newbase, 0);
-			newbase[baselen + pathlen] = '/';
+			base[baselen + pathlen] = 0;
+			opt->add_remove(opt, *prefix, mode, sha1, base, 0);
+			base[baselen + pathlen] = '/';
 		}
 
 		init_tree_desc(&inner, tree, size);
-		show_tree(opt, prefix, &inner, newbase, baselen + 1 + pathlen);
+		show_tree(opt, prefix, &inner, base, baselen + 1 + pathlen);
 
+		base[baselen] = 0;
 		free(tree);
-		free(newbase);
 	} else {
-		char *fullname = malloc_fullname(base, baselen, path, pathlen);
-		opt->add_remove(opt, prefix[0], mode, sha1, fullname, 0);
-		free(fullname);
+		memcpy(base + baselen, path, pathlen);
+		base[baselen + pathlen] = 0;
+		opt->add_remove(opt, prefix[0], mode, sha1, base, 0);
+		base[baselen] = 0;
 	}
 }
 
-static void skip_uninteresting(struct tree_desc *t, const char *base, int baselen, struct diff_options *opt)
+static void skip_uninteresting(struct tree_desc *t, char *base,
+			       int baselen, struct diff_options *opt)
 {
 	int all_interesting = 0;
 	while (t->size) {
@@ -166,10 +158,13 @@ static void skip_uninteresting(struct tree_desc *t, const char *base, int basele
 	}
 }
 
-int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, struct diff_options *opt)
+int diff_tree(struct tree_desc *t1, struct tree_desc *t2,
+	      const char *base_, struct diff_options *opt)
 {
-	int baselen = strlen(base);
+	char base[PATH_MAX];
+	int baselen = strlen(base_);
 
+	memcpy(base, base_, baselen+1);
 	for (;;) {
 		if (DIFF_OPT_TST(opt, QUICK) &&
 		    DIFF_OPT_TST(opt, HAS_CHANGES))
-- 
1.7.3.3.476.g10a82

^ permalink raw reply related

* [PATCH 08/19] pathspec: mark wildcard pathspecs from the beginning
From: Nguyễn Thái Ngọc Duy @ 2010-12-13  9:46 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy
In-Reply-To: <1292233616-27692-1-git-send-email-pclouds@gmail.com>

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 prefix_len was used, but no longer. Still hesitate to remove it. It
 might get used again..

 cache.h |    4 +++-
 dir.c   |   13 +++++++++++--
 2 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/cache.h b/cache.h
index 36819b6..3a1acf1 100644
--- a/cache.h
+++ b/cache.h
@@ -496,8 +496,10 @@ extern int ie_modified(const struct index_state *, struct cache_entry *, struct
 struct pathspec {
 	const char **raw; /* get_pathspec() result, not freed by free_pathspec() */
 	int nr;
+	int has_wildcard:1;
 	struct pathspec_item {
-		int len;
+		int len, prefix_len;
+		int has_wildcard:1;
 	} *items;
 };
 
diff --git a/dir.c b/dir.c
index 646c79f..0987d0c 100644
--- a/dir.c
+++ b/dir.c
@@ -1089,8 +1089,17 @@ int init_pathspec(struct pathspec *pathspec, const char **paths)
 	pathspec->items = xmalloc(sizeof(struct pathspec_item)*pathspec->nr);
 	for (i = 0; i < pathspec->nr; i++) {
 		struct pathspec_item *item = pathspec->items+i;
-
-		item->len = strlen(paths[i]);
+		const char *path = paths[i];
+
+		item->len = strlen(path);
+		item->has_wildcard = !no_wildcard(path);
+		if (item->has_wildcard) {
+			pathspec->has_wildcard = 1;
+			item->prefix_len = 0;
+			while (item->prefix_len < item->len &&
+			       strchr("*?[{\\", path[item->prefix_len]) == NULL)
+				item->prefix_len++;
+		}
 	}
 	return 0;
 }
-- 
1.7.3.3.476.g10a82

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox