* Re: [PATCH v2] wt-status: Show ignored files in untracked dirs
From: Antoine Pelisse @ 2012-12-27 17:35 UTC (permalink / raw)
To: Jeff King; +Cc: Junio C Hamano, git
In-Reply-To: <20121227161920.GA28162@sigill.intra.peff.net>
> By "committed", I assume you meat that you have "dirA/unco" as an
> untracked file, and "dirA/committed" as a file in the index?
Of course,
> Thanks for putting this together. I agree with the expected output in
> each case, and I think this covers the cases we have seen (case 1 is
> Michael's original report, case 2 is what I wrote in my mail, and case 3
> is the one you just came up with). I can't think offhand of any others.
Great, so I can build some tests reflecting those behaviors while
waiting more inputs
^ permalink raw reply
* "fatal: git-write-tree: error building trees" from `git stash`
From: Alex Vandiver @ 2012-12-27 18:07 UTC (permalink / raw)
To: git discussion list
Heya,
I just ran into the following with `git stash`. The set-up:
git init
echo "Initial" > foo
git add .
git commit -m 'Initial commit'
echo "Rewrite" > foo
git commit -am 'Second commit, rewrites content'
echo "Stashed changes" >> foo
git stash
git co HEAD~
$ git stash pop
Auto-merging foo
CONFLICT (content): Merge conflict in foo
Recorded preimage for 'foo'
$ git stash
foo: needs merge
foo: needs merge
foo: unmerged (aeaa7e5e87cf309a7368d5d92a71c1f9e6a8c9e7)
foo: unmerged (a77fa514de2720c72c1a861de098595959a2c97a)
foo: unmerged (4a622d2b991f1a19ba7be313a46dc6f03692cd0a)
fatal: git-write-tree: error building trees
Cannot save the current index state
- Alex
^ permalink raw reply
* Re: [PATCH v2] log: grep author/committer using mailmap
From: Junio C Hamano @ 2012-12-27 18:45 UTC (permalink / raw)
To: Antoine Pelisse; +Cc: git
In-Reply-To: <1356622318-19523-1-git-send-email-apelisse@gmail.com>
Antoine Pelisse <apelisse@gmail.com> writes:
> Currently you can use mailmap to display log authors and committers
> but you can't use the mailmap to find commits with mapped values.
>
> This commit allows you to run:
>
> git log --use-mailmap --author mapped_name_or_email
> git log --use-mailmap --committer mapped_name_or_email
>
> Of course it only works if the --use-mailmap option is used.
>
> Signed-off-by: Antoine Pelisse <apelisse@gmail.com>
> ---
Thanks. I'll queue this on top.
-- >8 --
Subject: [PATCH] log --use-mailmap: optimize for cases without --author/--committer search
When we taught the commit_match() mechanism to pay attention to the
new --use-mailmap option, we started to unconditionally copy the
commit object to a temporary buffer, just in case we need the author
and committer lines updated via the mailmap mechanism.
It turns out that this has a rather unpleasant performance
implications. In the linux kernel repository, running
$ git log --author='Junio C Hamano' --pretty=short >/dev/null
under /usr/bin/time, with and without --use-mailmap (the .mailmap
file is 118 entries long, the particular author does not appear in
it), cost (with warm cache):
[without --use-mailmap]
5.34user 0.25system 0:05.60elapsed 100%CPU (0avgtext+0avgdata 2004832maxresident)k
0inputs+0outputs (0major+137600minor)pagefaults 0swaps
[with --use-mailmap]
6.87user 0.24system 0:07.11elapsed 99%CPU (0avgtext+0avgdata 2006352maxresident)k
0inputs+0outputs (0major+137696minor)pagefaults 0swaps
which is with about 29% overhead. The command is doing extra work,
so the extra cost may be justified.
But it is inexcusable to pay the cost when we do not need
author/committer match. In the same repository,
$ git log --grep='fix menuconfig on debian lenny' --pretty=short >/dev/null
shows very similar numbers as the above:
[without --use-mailmap]
5.30user 0.24system 0:05.55elapsed 99%CPU (0avgtext+0avgdata 2004896maxresident)k
0inputs+0outputs (0major+137604minor)pagefaults 0swaps
[with --use-mailmap]
6.82user 0.26system 0:07.07elapsed 100%CPU (0avgtext+0avgdata 2006352maxresident)k
0inputs+0outputs (0major+137697minor)pagefaults 0swaps
The latter case is an unnecessary performance regression. We may
want to _show_ the result with mailmap applied, but we do not have
to copy and rewrite the author/committer of all commits we try to
match if we do not query for these fields.
Trivially optimize this performace regression by limiting the
rewrites for only when we are matching with author/committer fields.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
revision.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/revision.c b/revision.c
index fa16b9d..56b72f7 100644
--- a/revision.c
+++ b/revision.c
@@ -2283,7 +2283,7 @@ static int commit_match(struct commit *commit, struct rev_info *opt)
if (buf.len)
strbuf_addstr(&buf, commit->buffer);
- if (opt->mailmap) {
+ if (opt->grep_filter.header_list && opt->mailmap) {
if (!buf.len)
strbuf_addstr(&buf, commit->buffer);
--
1.8.1.rc3.221.g8d09d94
^ permalink raw reply related
* Re: [PATCH v2] log: grep author/committer using mailmap
From: Junio C Hamano @ 2012-12-27 18:48 UTC (permalink / raw)
To: Antoine Pelisse; +Cc: git
In-Reply-To: <7v1uebmizx.fsf@alter.siamese.dyndns.org>
Junio C Hamano <gitster@pobox.com> writes:
> Thanks. I'll queue this on top.
>
> -- >8 --
> Subject: [PATCH] log --use-mailmap: optimize for cases without --author/--committer search
And this I will *not* queue further on top.
-- >8 --
Subject: [PATCH] [DO NOT USE] log --use-mailmap --author/--committer: further
optimize identity rewriting
We used to always allocate a temporary buffer to search for
author/committer names even when the author/committer does not
appear in the mailmap. Update the logic to do the allocation
on demand to reduce needless malloc()/free() calls.
It turns out that this does not affect performance at all; all the
time is spent in map_user() which is a look-up in string_list, so
let's not use this patch in the production, but it illustrates an
interesting point.
In map_identities() function, we already know who the author
recorded in the commit is, either in "author" strbuf, or in buffer
between [a_at..a_len], so we could grep_buffer() the author
regexp(s) specified from the command line right there, and combine
that result with the main grep_buffer() done for the --grep= option
at the end of the commit_match() function.
That may essentially amount to going in the totally opposite
direction from what 2d10c55 (git log: Unify header_filter and
message_filter into one., 2006-09-20) attempted to do. We used to
have two grep expressions (one for header, the other one for body)
commit_match() runs grep_buffer() on and combined the results.
2d10c55 merged them into one grep expression by introducing a term
that matches only header elements. But we would instead split the
"header" expression into "author" and "committer" expressions
(making it three from one) if we go that route.
In any case, I *think* the bottleneck is in map_user() so until that
is solved, such an update (or this patch) is not very useful.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
revision.c | 95 +++++++++++++++++++++++++++++++++++++-------------------------
1 file changed, 57 insertions(+), 38 deletions(-)
diff --git a/revision.c b/revision.c
index 56b72f7..4b66598 100644
--- a/revision.c
+++ b/revision.c
@@ -2220,49 +2220,73 @@ static int rewrite_parents(struct rev_info *revs, struct commit *commit)
return 0;
}
-static int commit_rewrite_person(struct strbuf *buf, const char *what, struct string_list *mailmap)
+static void map_person(const char *buf, size_t len, const char *head, int headlen,
+ struct strbuf *result, struct string_list *mailmap,
+ int *matchofs, int *matchlen)
{
- char *person, *endp;
- size_t len;
+ struct ident_split ident;
+ const char *endp, *person;
struct strbuf name = STRBUF_INIT;
struct strbuf mail = STRBUF_INIT;
- struct ident_split ident;
- person = strstr(buf->buf, what);
+ person = memmem(buf, len, head, headlen);
if (!person)
- goto left_intact;
-
- person += strlen(what);
+ return;
+ person += headlen;
endp = strchr(person, '\n');
if (!endp)
- goto left_intact;
-
- len = endp - person;
-
- if (split_ident_line(&ident, person, len))
- goto left_intact;
-
+ return;
+ *matchofs = person - buf;
+ *matchlen = endp - person;
+ if (split_ident_line(&ident, person, *matchlen))
+ return;
strbuf_add(&name, ident.name_begin, ident.name_end - ident.name_begin);
strbuf_add(&mail, ident.mail_begin, ident.mail_end - ident.mail_begin);
-
- if (map_user(mailmap, &mail, &name)) {
- strbuf_addf(&name, " <%s>", mail.buf);
-
- strbuf_splice(buf, ident.name_begin - buf->buf,
- ident.mail_end - ident.name_begin + 1,
- name.buf, name.len);
-
- strbuf_release(&name);
- strbuf_release(&mail);
-
- return 1;
- }
-
-left_intact:
+ if (map_user(mailmap, &mail, &name))
+ strbuf_addf(result, "%s <%s>", name.buf, mail.buf);
strbuf_release(&name);
strbuf_release(&mail);
+}
- return 0;
+static void map_identities(struct strbuf *buf, const char *buffer, struct string_list *mailmap)
+{
+ const char *eob;
+ struct strbuf author = STRBUF_INIT;
+ struct strbuf committer = STRBUF_INIT;
+ int a_at = -1, a_len, c_at = -1, c_len;
+
+ eob = strstr(buffer, "\n\n");
+ if (!eob)
+ eob = buffer + strlen(buffer);
+ map_person(buffer, eob - buffer, "\nauthor ", 8, &author, mailmap,
+ &a_at, &a_len);
+ map_person(buffer, eob - buffer, "\ncommitter ", 11, &committer, mailmap,
+ &c_at, &c_len);
+ if (!author.len && !committer.len)
+ goto done;
+
+ /* Now, we know we need rewriting */
+ if (!buf->len)
+ strbuf_addstr(buf, buffer);
+
+ if (c_at < 0 || !committer.len) {
+ strbuf_splice(buf, a_at, a_len, author.buf, author.len);
+ } else if (a_at < 0 || !author.len) {
+ strbuf_splice(buf, c_at, c_len, committer.buf, committer.len);
+ } else if (a_at < c_at) {
+ strbuf_splice(buf, c_at, c_len, committer.buf, committer.len);
+ strbuf_splice(buf, a_at, a_len, author.buf, author.len);
+ } else {
+ /*
+ * The commit records committer before the author, which is malformed,
+ * which we may want to warn about.
+ */
+ strbuf_splice(buf, a_at, a_len, author.buf, author.len);
+ strbuf_splice(buf, c_at, c_len, committer.buf, committer.len);
+ }
+ done:
+ strbuf_release(&author);
+ strbuf_release(&committer);
}
static int commit_match(struct commit *commit, struct rev_info *opt)
@@ -2283,13 +2307,8 @@ static int commit_match(struct commit *commit, struct rev_info *opt)
if (buf.len)
strbuf_addstr(&buf, commit->buffer);
- if (opt->grep_filter.header_list && opt->mailmap) {
- if (!buf.len)
- strbuf_addstr(&buf, commit->buffer);
-
- commit_rewrite_person(&buf, "\nauthor ", opt->mailmap);
- commit_rewrite_person(&buf, "\ncommitter ", opt->mailmap);
- }
+ if (opt->grep_filter.header_list && opt->mailmap)
+ map_identities(&buf, commit->buffer, opt->mailmap);
/* Append "fake" message parts as needed */
if (opt->show_notes) {
--
1.8.1.rc3.221.g8d09d94
^ permalink raw reply related
* Re: "fatal: git-write-tree: error building trees" from `git stash`
From: Junio C Hamano @ 2012-12-27 18:51 UTC (permalink / raw)
To: Alex Vandiver; +Cc: git discussion list
In-Reply-To: <1356631626.13818.126.camel@umgah.localdomain>
Alex Vandiver <alex@chmrr.net> writes:
> Heya,
> I just ran into the following with `git stash`. The set-up:
> ...
> $ git stash pop
> Auto-merging foo
> CONFLICT (content): Merge conflict in foo
> Recorded preimage for 'foo'
>
> $ git stash
> foo: needs merge
> foo: needs merge
> foo: unmerged (aeaa7e5e87cf309a7368d5d92a71c1f9e6a8c9e7)
> foo: unmerged (a77fa514de2720c72c1a861de098595959a2c97a)
> foo: unmerged (4a622d2b991f1a19ba7be313a46dc6f03692cd0a)
> fatal: git-write-tree: error building trees
> Cannot save the current index state
This is totally expected, isn't it?
You do not save state in the middle of a conflict with "git stash"
(instead, you would "git stash" away your own work in progress
before you start operation that may create and leave conflicts).
^ permalink raw reply
* Re: "fatal: git-write-tree: error building trees" from `git stash`
From: Alex Vandiver @ 2012-12-27 18:55 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git discussion list
In-Reply-To: <7vsj6rl456.fsf@alter.siamese.dyndns.org>
On Thu, 2012-12-27 at 10:51 -0800, Junio C Hamano wrote:
> > $ git stash
> > foo: needs merge
> > foo: needs merge
> > foo: unmerged (aeaa7e5e87cf309a7368d5d92a71c1f9e6a8c9e7)
> > foo: unmerged (a77fa514de2720c72c1a861de098595959a2c97a)
> > foo: unmerged (4a622d2b991f1a19ba7be313a46dc6f03692cd0a)
> > fatal: git-write-tree: error building trees
> > Cannot save the current index state
>
> This is totally expected, isn't it?
>
> You do not save state in the middle of a conflict with "git stash"
> (instead, you would "git stash" away your own work in progress
> before you start operation that may create and leave conflicts).
Apologies for not being clear. While being unable to stash is not
unexpected, perhaps, "Cannot stash while resolving conflicts" or similar
would be more understandable to the end user than the above.
- Alex
^ permalink raw reply
* Re: "fatal: git-write-tree: error building trees" from `git stash`
From: Jeff King @ 2012-12-27 19:05 UTC (permalink / raw)
To: Alex Vandiver; +Cc: Junio C Hamano, git discussion list
In-Reply-To: <1356634556.13818.136.camel@umgah.localdomain>
On Thu, Dec 27, 2012 at 01:55:56PM -0500, Alex Vandiver wrote:
> On Thu, 2012-12-27 at 10:51 -0800, Junio C Hamano wrote:
> > > $ git stash
> > > foo: needs merge
> > > foo: needs merge
> > > foo: unmerged (aeaa7e5e87cf309a7368d5d92a71c1f9e6a8c9e7)
> > > foo: unmerged (a77fa514de2720c72c1a861de098595959a2c97a)
> > > foo: unmerged (4a622d2b991f1a19ba7be313a46dc6f03692cd0a)
> > > fatal: git-write-tree: error building trees
> > > Cannot save the current index state
> >
> > This is totally expected, isn't it?
> >
> > You do not save state in the middle of a conflict with "git stash"
> > (instead, you would "git stash" away your own work in progress
> > before you start operation that may create and leave conflicts).
>
> Apologies for not being clear. While being unable to stash is not
> unexpected, perhaps, "Cannot stash while resolving conflicts" or similar
> would be more understandable to the end user than the above.
Yeah, I think the outcome is reasonable, but that message is just
horrible. Something like this might be better:
diff --git a/git-stash.sh b/git-stash.sh
index 688e259..7ea425c 100755
--- a/git-stash.sh
+++ b/git-stash.sh
@@ -217,6 +217,12 @@ save_stash () {
stash_msg="$*"
+ if ! git diff-index --cached --diff-filter=U --quiet HEAD; then
+ echo >&2 "fatal: unable to stash unmerged entries:"
+ git diff-index --cached --diff-filter=U --name-status HEAD
+ exit 1
+ fi
+
git update-index -q --refresh
if no_changes
then
but I suspect it is not sufficient:
1. There are other code paths that will end up in write-tree which
should probably be protected, too.
2. Unmerged entries are only one reason that write-tree might fail.
It's OK not to catch them all (since ultimately write-tree will
complain if need be), but we may want to also handle intent-to-add
entries with a nicer message.
-Peff
^ permalink raw reply related
* Re: "fatal: git-write-tree: error building trees" from `git stash`
From: Junio C Hamano @ 2012-12-27 19:21 UTC (permalink / raw)
To: Alex Vandiver; +Cc: git discussion list
In-Reply-To: <1356634556.13818.136.camel@umgah.localdomain>
Alex Vandiver <alex@chmrr.net> writes:
> ... "Cannot stash while resolving conflicts" or similar would be
> more understandable to the end user than the above.
Interestingly enough, the "apply" side is protected with this one
liner:
# current index state
c_tree=$(git write-tree) ||
die "$(gettext "Cannot apply a stash in the middle of a merge")"
since 5fd448f (git stash: Give friendlier errors when there is
nothing to apply, 2009-08-11). I would think something in line with
that change on the "create" side is a welcome one.
Thanks.
^ permalink raw reply
* Re: "fatal: git-write-tree: error building trees" from `git stash`
From: Junio C Hamano @ 2012-12-27 20:11 UTC (permalink / raw)
To: Jeff King; +Cc: Alex Vandiver, git discussion list
In-Reply-To: <20121227190542.GB28811@sigill.intra.peff.net>
Jeff King <peff@peff.net> writes:
> but I suspect it is not sufficient:
>
> 1. There are other code paths that will end up in write-tree which
> should probably be protected, too.
Among 6 calls to write-tree, only the first ones in create_stash and
apply_stash are about the index the user originally had. If the
only expected failure case is unmerged entries, it should be
sufficient to protect these two (and the one in apply_stash is
already covered, I think).
> 2. Unmerged entries are only one reason that write-tree might fail.
> It's OK not to catch them all (since ultimately write-tree will
> complain if need be), but we may want to also handle intent-to-add
> entries with a nicer message.
Hrmph.
We used to fail write-tree when I-T-A entries existed and relied on
that behaviour to implement "no state lost"; as we broke write-tree
recently by allowing to write a tree out by pretending that I-T-A
entries do not exist, I think we broke it. Stashing with I-T-A and
then unstashing it may lose the file. Sigh...
^ permalink raw reply
* Re: Python version auditing followup
From: Dennis Kaarsemaker @ 2012-12-27 21:57 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Eric S. Raymond, git
In-Reply-To: <7vobho60fs.fsf@alter.siamese.dyndns.org>
On do, 2012-12-20 at 10:30 -0800, Junio C Hamano wrote:
> Which platforms that are long-term-maintained by their vendors still
> pin their Python at 2.4.X?
RHEL 5.x and its clones still use python 2.4. It is supported by red hat
until at least 2017 (though end of production phase two, Q1 2014, seems
like a reasonable cut-off point).
--
Dennis Kaarsemaker
^ permalink raw reply
* Lockless Refs? (Was [PATCH] refs: do not use cached refs in repack_without_ref)
From: Martin Fick @ 2012-12-27 23:11 UTC (permalink / raw)
To: Michael Haggerty; +Cc: Jeff King, git, Junio C Hamano
In-Reply-To: <50DAB447.8000101@alum.mit.edu>
On Wednesday, December 26, 2012 01:24:39 am Michael Haggerty
wrote:
> ... lots of discussion about ref locking...
It concerns me that git uses any locking at all, even for
refs since it has the potential to leave around stale locks.
For a single user repo this is not a big deal, the lock can
always be cleaned up manually (and it is a rare occurrence).
However, in a multi user server environment, possibly even
from multiple hosts over a shared filesystem such as NFS,
stale locks could lead to serious downtime and risky recovery
(since it is currently hard to figure out if a lock really is
stale). Even though stale locks are probably rare even today
in the larger shared repo case, as git scales to even larger
shared repositories, this will eventually become more of a
problem *1. Naturally, this has me thinking that git should
possibly consider moving towards a lockless design for refs
in the long term.
I realize this is hard and that git needs to support many
different filesystems with different semantics. I had an idea I
think may be close to a functional lockless design for loose
refs (one piece at a time) that I thought I should propose,
just to get the ball rolling, even if it is just going to be
found to be flawed (I realize that history suggests that such
schemes usually are). I hope that it does not make use of
any semantics which are not currently expected from git of
filesystems. I think it relies only on the ability to rename
a file atomically, and the ability to scan the contents of a
directory reliably to detect the "ordered" existence of files.
My idea is based on using filenames to store sha1s instead of
file contents. To do this, the sha1 one of a ref would be
stored in a file in a directory named after the loose ref. I
believe this would then make it possible to have lockless
atomic ref updates by renaming the file.
To more fully illustrate the idea, imagine that any file
(except for the null file) in the directory will represent the
value of the ref with its name, then the following
transitions can represent atomic state changes to a refs
value and existence:
1) To update the value from a known value to a new value
atomically, simply rename the file to the new value. This
operation should only succeed if the file exists and is still
named old value before the rename. This should even be
faster than today's approach, especially on remote filesystems
since it would require only 1 round trip in the success case
instead of 3!
2) To delete the ref, simply delete the filename representing
the current value of the ref. This ensures that you are
deleting the ref from a specific value. I am not sure if git
needs to be able to delete refs without knowing their values?
If so, this would require reading the value and looping until
the delete succeeds, this may be a bit slow for a constantly
updated ref, but likely a rare situation (and not likely
worse than trying to acquire the ref-lock today). Overall,
this again would likely be faster than today's approach.
3) To create a ref, it must be renamed from the null file (sha
0000...) to the new value just as if it were being updated
from any other value, but there is one extra condition:
before renaming the null file, a full directory scan must be
done to ensure that the null file is the only file in the
directory (this condition exists because creating the
directory and null file cannot be atomic unless the filesystem
supports atomic directory renames, an expectation git does
not currently make). I am not sure how this compares to
today's approach, but including the setup costs (described
below), I suspect it is slower.
While this outlines the state changes, some additional
operations may be needed to setup some starting conditions
and to clean things up. But these operations could/should be
performed by any process/thread and would not cause any state
changes to the ref existence or value. For example, when
creating a ref, the ref directory would need to be created
and the null file needs to be created. Whenever a null file is
detected in the directory at the same time as another file, it
should be deleted. Whenever the directory is empty, it may
be deleted (perhaps after a grace period to reduce retries
during ref creation unless the process just deleted the ref).
I don't know how this new scheme could be made to work with
the current scheme, it seems like perhaps new git releases
could be made to understand both the old and the new, and a
config option could be used to tell it which method to write
new refs with. Since in this new scheme ref directory names
would conflict with old ref filenames, this would likely
prevent both schemes from erroneously being used
simultaneously (so they shouldn't corrupt each other), except
for the fact that refs can be nested in directories which
confuses things a bit. I am not sure what a good solution to
this is?
What did I miss, where are my flaws? Does anyone else share
my concern for stale locks? How could we similarly eliminate
locks for the packed-refs file?
-Martin
*1 We have been concerned with stale locks in the Gerrit
community when trying to design atomic cross repository
updates. Of course, while a lockless solution eliminates
stale locks, it might make it impossible to do atomic cross
repository updates since all of our solutions so far need
locks. :(
^ permalink raw reply
* [ANNOUNCE] Git v1.8.0.3
From: Junio C Hamano @ 2012-12-28 0:48 UTC (permalink / raw)
To: git; +Cc: Linux Kernel
The latest maintenance release Git v1.8.0.3 is now available at
the usual places.
This is primarily to down-merge documentation updates that have been
accumulating to the 'master' front for the upcoming 1.8.1 to the
maintenance series.
The release tarballs are found at:
http://code.google.com/p/git-core/downloads/list
and their SHA-1 checksums are:
b1695f28448c00e61e110b3c7bcd66c8047ef176 git-1.8.0.3.tar.gz
83c46b62e0c3979c5ef77a407ca41507658b5726 git-htmldocs-1.8.0.3.tar.gz
63df55f90b9c6c11dd827ce1880b5b5fdf79c1c1 git-manpages-1.8.0.3.tar.gz
Also the following public repositories all have a copy of the v1.8.0.3
tag and the maint branch that the tag points at:
url = git://repo.or.cz/alt-git.git
url = https://code.google.com/p/git-core/
url = git://git.sourceforge.jp/gitroot/git-core/git.git
url = git://git-core.git.sourceforge.net/gitroot/git-core/git-core
url = https://github.com/gitster/git
Git v1.8.0.3 Release Notes
==========================
Fixes since v1.8.0.2
--------------------
* "git log -p -S<string>" did not apply the textconv filter while
looking for the <string>.
* In the documentation, some invalid example e-mail addresses were
formatted into mailto: links.
Also contains many documentation updates backported from the 'master'
branch that is preparing for the upcoming 1.8.1 release.
----------------------------------------------------------------
Changes since v1.8.0.2 are as follows:
Adam Spiers (2):
SubmittingPatches: add convention of prefixing commit messages
Documentation: move support for old compilers to CodingGuidelines
Anders Kaseorg (1):
git-prompt: Document GIT_PS1_DESCRIBE_STYLE
Chris Rorvick (2):
Documentation/git-checkout.txt: clarify usage
Documentation/git-checkout.txt: document 70c9ac2 behavior
Gunnlaugur Þór Briem (1):
Document git-svn fetch --log-window-size parameter
Jeff King (7):
pickaxe: hoist empty needle check
pickaxe: use textconv for -S counting
.mailmap: match up some obvious names/emails
.mailmap: fix broken entry for Martin Langhoff
.mailmap: normalize emails for Jeff King
.mailmap: normalize emails for Linus Torvalds
contrib: update stats/mailmap script
John Keeping (1):
Documentation: don't link to example mail addresses
Junio C Hamano (6):
fetch --tags: clarify documentation
README: it does not matter who the current maintainer is
t7004: do not create unneeded gpghome/gpg.conf when GPG is not used
Documentation: Describe "git diff <blob> <blob>" separately
git(1): show link to contributor summary page
Git 1.8.0.3
Krzysztof Mazur (1):
doc: git-reset: make "<mode>" optional
Manlio Perillo (1):
git.txt: add missing info about --git-dir command-line option
Matthew Daley (1):
Fix sizeof usage in get_permutations
Max Horn (1):
git-remote-helpers.txt: document invocation before input format
Nguyễn Thái Ngọc Duy (1):
index-format.txt: clarify what is "invalid"
Ramkumar Ramachandra (1):
Documentation: move diff.wordRegex from config.txt to diff-config.txt
Sebastian Leske (4):
git-svn: Document branches with at-sign(@).
git-svn: Recommend use of structure options.
git-svn: Expand documentation for --follow-parent
git-svn: Note about tags.
Sitaram Chamarty (1):
clarify -M without % symbol in diff-options
Stefano Lattarini (1):
README: Git is released under the GPLv2, not just "the GPL"
Thomas Ackermann (8):
Split over-long synopsis in git-fetch-pack.txt into several lines
Shorten two over-long lines in git-bisect-lk2009.txt by abbreviating some sha1
Change headline of technical/send-pack-pipeline.txt to not confuse its content with content from git-send-pack.txt
Documentation/technical: convert plain text files to asciidoc
Documentation/howto: convert plain text files to asciidoc
Documentation: build html for all files in technical and howto
Remove misleading date from api-index-skel.txt
Sort howto documents in howto-index.txt
Tom Jones (1):
Add -S, --gpg-sign option to manpage of "git commit"
^ permalink raw reply
* git log commit limiting "show commits with >1 child" possible?
From: David @ 2012-12-28 3:12 UTC (permalink / raw)
To: git
My branches are very long so for years I have been doing a lot of scrolling
when using gitk. I have just now discovered how to see a simplified history.
For this example history where commits were added in alphabetical order:
A--B--C--D--H
\
E--F--G--I
\
J
I do this:
$ git log --graph --branches --simplify-by-decoration --source --oneline
* 00a27e0 J
| * 160d232 I
|/
| * daa5b69 H
|/
* 734db0c A
and similar in gitk using the View > Edit View > Simple History = 1
This is a great step forward for me! I am very happy with it.
Is there any way to ask git log to additionally display all commits with
more than one child, to show where each branch diverges?
So I hope to see:
* 00a27e0 J
| * 160d232 I
|/
* b981ea0 G
| * daa5b69 H
|/
* 546ae44 C
* 734db0c A
I have read man git-log but I do not understand it all. If there is a way to
achieve this then I am not seeing it.
I notice that there is commit limiting by --merges and --no-merges.
If --merges means "show only commits with more than one parent", and
--no-merges means "show only commits with only one parent", what I
want is "show also commits with more than one child".
Or perhaps "show only commits with more than one parent or child".
Is there a way to do this? It will be nice if it also works in gitk.
Presently I have git version 1.7.2.3
^ permalink raw reply
* Re: git log commit limiting "show commits with >1 child" possible?
From: David @ 2012-12-28 3:15 UTC (permalink / raw)
To: git
In-Reply-To: <CAMPXz=rQxh3niOKiASZE3qqbYUEKXN6TscPsjPPoZjZLnCRpFA@mail.gmail.com>
CORRECTION:
So I hope to see:
* 00a27e0 J
| * 160d232 I
|/
* b981ea0 F
| * daa5b69 H
|/
* 546ae44 B
* 734db0c A
On 28/12/2012, David <bouncingcats@gmail.com> wrote:
> My branches are very long so for years I have been doing a lot of scrolling
> when using gitk. I have just now discovered how to see a simplified
> history.
>
> For this example history where commits were added in alphabetical order:
>
> A--B--C--D--H
> \
> E--F--G--I
> \
> J
>
> I do this:
>
> $ git log --graph --branches --simplify-by-decoration --source --oneline
> * 00a27e0 J
> | * 160d232 I
> |/
> | * daa5b69 H
> |/
> * 734db0c A
>
> and similar in gitk using the View > Edit View > Simple History = 1
> This is a great step forward for me! I am very happy with it.
>
> Is there any way to ask git log to additionally display all commits with
> more than one child, to show where each branch diverges?
>
> So I hope to see:
>
> * 00a27e0 J
> | * 160d232 I
> |/
> * b981ea0 G
> | * daa5b69 H
> |/
> * 546ae44 C
> * 734db0c A
>
> I have read man git-log but I do not understand it all. If there is a way
> to
> achieve this then I am not seeing it.
>
> I notice that there is commit limiting by --merges and --no-merges.
> If --merges means "show only commits with more than one parent", and
> --no-merges means "show only commits with only one parent", what I
> want is "show also commits with more than one child".
>
> Or perhaps "show only commits with more than one parent or child".
>
> Is there a way to do this? It will be nice if it also works in gitk.
> Presently I have git version 1.7.2.3
>
^ permalink raw reply
* [PATCH v2 0/9] fnmatch replacement step 1
From: Nguyễn Thái Ngọc Duy @ 2012-12-28 4:10 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy
v2 has no big changes:
- 'special' variable in dowild() is removed in favor of two
new, better named ones
- fix TRUE/FALSE in comments as well as code in the rename patch
- some tests for "*/" and "*<literal>" optimizations
- USE_WILDMATCH patch is moved to the end of the series
Nguyễn Thái Ngọc Duy (9):
compat/fnmatch: respect NO_FNMATCH* even on glibc
wildmatch: replace variable 'special' with better named ones
wildmatch: rename constants and update prototype
wildmatch: make dowild() take arbitrary flags
wildmatch: support "no FNM_PATHNAME" mode
test-wildmatch: add "perf" command to compare wildmatch and fnmatch
wildmatch: make a special case for "*/" with FNM_PATHNAME
wildmatch: advance faster in <asterisk> + <literal> patterns
Makefile: add USE_WILDMATCH to use wildmatch as fnmatch
Makefile | 6 ++
compat/fnmatch/fnmatch.c | 3 +-
dir.c | 3 +-
git-compat-util.h | 13 +++++
t/t3070-wildmatch.sh | 41 +++++++++++++
test-wildmatch.c | 82 +++++++++++++++++++++++++-
wildmatch.c | 147 +++++++++++++++++++++++++++++------------------
wildmatch.h | 23 +++++---
8 files changed, 251 insertions(+), 67 deletions(-)
--
1.8.0.rc2.23.g1fb49df
^ permalink raw reply
* [PATCH v2 1/9] compat/fnmatch: respect NO_FNMATCH* even on glibc
From: Nguyễn Thái Ngọc Duy @ 2012-12-28 4:10 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy
In-Reply-To: <1356667854-8686-1-git-send-email-pclouds@gmail.com>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
compat/fnmatch/fnmatch.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/compat/fnmatch/fnmatch.c b/compat/fnmatch/fnmatch.c
index 9473aed..6f7387d 100644
--- a/compat/fnmatch/fnmatch.c
+++ b/compat/fnmatch/fnmatch.c
@@ -55,7 +55,8 @@
program understand `configure --with-gnu-libc' and omit the object files,
it is simpler to just do this in the source for each such file. */
-#if defined _LIBC || !defined __GNU_LIBRARY__
+#if defined NO_FNMATCH || defined NO_FNMATCH_CASEFOLD || \
+ defined _LIBC || !defined __GNU_LIBRARY__
# if defined STDC_HEADERS || !defined isascii
--
1.8.0.rc2.23.g1fb49df
^ permalink raw reply related
* [PATCH v2 2/9] wildmatch: replace variable 'special' with better named ones
From: Nguyễn Thái Ngọc Duy @ 2012-12-28 4:10 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy
In-Reply-To: <1356667854-8686-1-git-send-email-pclouds@gmail.com>
'special' is too generic and is used for two different purposes.
Replace it with 'match_slash' to indicate "**" pattern and 'negated'
for "[!...]" and "[^...]".
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
wildmatch.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/wildmatch.c b/wildmatch.c
index 3972e26..8a58ad4 100644
--- a/wildmatch.c
+++ b/wildmatch.c
@@ -60,7 +60,7 @@ static int dowild(const uchar *p, const uchar *text, int force_lower_case)
uchar p_ch;
for ( ; (p_ch = *p) != '\0'; text++, p++) {
- int matched, special;
+ int matched, match_slash, negated;
uchar t_ch, prev_ch;
if ((t_ch = *text) == '\0' && p_ch != '*')
return ABORT_ALL;
@@ -102,15 +102,15 @@ static int dowild(const uchar *p, const uchar *text, int force_lower_case)
if (p[0] == '/' &&
dowild(p + 1, text, force_lower_case) == MATCH)
return MATCH;
- special = TRUE;
+ match_slash = TRUE;
} else
return ABORT_MALFORMED;
} else
- special = FALSE;
+ match_slash = FALSE;
if (*p == '\0') {
/* Trailing "**" matches everything. Trailing "*" matches
* only if there are no more slash characters. */
- if (!special) {
+ if (!match_slash) {
if (strchr((char*)text, '/') != NULL)
return NOMATCH;
}
@@ -120,9 +120,9 @@ static int dowild(const uchar *p, const uchar *text, int force_lower_case)
if (t_ch == '\0')
break;
if ((matched = dowild(p, text, force_lower_case)) != NOMATCH) {
- if (!special || matched != ABORT_TO_STARSTAR)
+ if (!match_slash || matched != ABORT_TO_STARSTAR)
return matched;
- } else if (!special && t_ch == '/')
+ } else if (!match_slash && t_ch == '/')
return ABORT_TO_STARSTAR;
t_ch = *++text;
}
@@ -134,8 +134,8 @@ static int dowild(const uchar *p, const uchar *text, int force_lower_case)
p_ch = NEGATE_CLASS;
#endif
/* Assign literal TRUE/FALSE because of "matched" comparison. */
- special = p_ch == NEGATE_CLASS? TRUE : FALSE;
- if (special) {
+ negated = p_ch == NEGATE_CLASS? TRUE : FALSE;
+ if (negated) {
/* Inverted character class. */
p_ch = *++p;
}
@@ -217,7 +217,7 @@ static int dowild(const uchar *p, const uchar *text, int force_lower_case)
} else if (t_ch == p_ch)
matched = TRUE;
} while (prev_ch = p_ch, (p_ch = *++p) != ']');
- if (matched == special || t_ch == '/')
+ if (matched == negated || t_ch == '/')
return NOMATCH;
continue;
}
--
1.8.0.rc2.23.g1fb49df
^ permalink raw reply related
* [PATCH v2 3/9] wildmatch: rename constants and update prototype
From: Nguyễn Thái Ngọc Duy @ 2012-12-28 4:10 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy
In-Reply-To: <1356667854-8686-1-git-send-email-pclouds@gmail.com>
- All exported constants now have a prefix WM_
- Do not rely on FNM_* constants, use the WM_ counterparts
- Remove TRUE and FALSE to follow Git's coding style
- While at it, turn flags type from int to unsigned int
- Add an (unused yet) argument to carry extra information
so that we don't have to change the prototype again later
when we need to pass other stuff to wildmatch
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
dir.c | 3 +-
test-wildmatch.c | 4 +--
wildmatch.c | 88 +++++++++++++++++++++++++++-----------------------------
wildmatch.h | 22 +++++++++-----
4 files changed, 62 insertions(+), 55 deletions(-)
diff --git a/dir.c b/dir.c
index cb7328b..175a182 100644
--- a/dir.c
+++ b/dir.c
@@ -595,7 +595,8 @@ int match_pathname(const char *pathname, int pathlen,
}
return wildmatch(pattern, name,
- ignore_case ? FNM_CASEFOLD : 0) == 0;
+ ignore_case ? WM_CASEFOLD : 0,
+ NULL) == 0;
}
/* Scan the list and let the last match determine the fate.
diff --git a/test-wildmatch.c b/test-wildmatch.c
index e384c8e..4bb23b4 100644
--- a/test-wildmatch.c
+++ b/test-wildmatch.c
@@ -12,9 +12,9 @@ int main(int argc, char **argv)
argv[i] += 3;
}
if (!strcmp(argv[1], "wildmatch"))
- return !!wildmatch(argv[3], argv[2], 0);
+ return !!wildmatch(argv[3], argv[2], 0, NULL);
else if (!strcmp(argv[1], "iwildmatch"))
- return !!wildmatch(argv[3], argv[2], FNM_CASEFOLD);
+ return !!wildmatch(argv[3], argv[2], WM_CASEFOLD, NULL);
else if (!strcmp(argv[1], "fnmatch"))
return !!fnmatch(argv[3], argv[2], FNM_PATHNAME);
else
diff --git a/wildmatch.c b/wildmatch.c
index 8a58ad4..f9b6451 100644
--- a/wildmatch.c
+++ b/wildmatch.c
@@ -18,9 +18,6 @@ typedef unsigned char uchar;
#define NEGATE_CLASS '!'
#define NEGATE_CLASS2 '^'
-#define FALSE 0
-#define TRUE 1
-
#define CC_EQ(class, len, litmatch) ((len) == sizeof (litmatch)-1 \
&& *(class) == *(litmatch) \
&& strncmp((char*)class, litmatch, len) == 0)
@@ -63,7 +60,7 @@ static int dowild(const uchar *p, const uchar *text, int force_lower_case)
int matched, match_slash, negated;
uchar t_ch, prev_ch;
if ((t_ch = *text) == '\0' && p_ch != '*')
- return ABORT_ALL;
+ return WM_ABORT_ALL;
if (force_lower_case && ISUPPER(t_ch))
t_ch = tolower(t_ch);
if (force_lower_case && ISUPPER(p_ch))
@@ -76,12 +73,12 @@ static int dowild(const uchar *p, const uchar *text, int force_lower_case)
/* FALLTHROUGH */
default:
if (t_ch != p_ch)
- return NOMATCH;
+ return WM_NOMATCH;
continue;
case '?':
/* Match anything but '/'. */
if (t_ch == '/')
- return NOMATCH;
+ return WM_NOMATCH;
continue;
case '*':
if (*++p == '*') {
@@ -100,135 +97,136 @@ static int dowild(const uchar *p, const uchar *text, int force_lower_case)
* both foo/bar and foo/a/bar.
*/
if (p[0] == '/' &&
- dowild(p + 1, text, force_lower_case) == MATCH)
- return MATCH;
- match_slash = TRUE;
+ dowild(p + 1, text, force_lower_case) == WM_MATCH)
+ return WM_MATCH;
+ match_slash = 1;
} else
- return ABORT_MALFORMED;
+ return WM_ABORT_MALFORMED;
} else
- match_slash = FALSE;
+ match_slash = 0;
if (*p == '\0') {
/* Trailing "**" matches everything. Trailing "*" matches
* only if there are no more slash characters. */
if (!match_slash) {
if (strchr((char*)text, '/') != NULL)
- return NOMATCH;
+ return WM_NOMATCH;
}
- return MATCH;
+ return WM_MATCH;
}
while (1) {
if (t_ch == '\0')
break;
- if ((matched = dowild(p, text, force_lower_case)) != NOMATCH) {
- if (!match_slash || matched != ABORT_TO_STARSTAR)
+ if ((matched = dowild(p, text, force_lower_case)) != WM_NOMATCH) {
+ if (!match_slash || matched != WM_ABORT_TO_STARSTAR)
return matched;
} else if (!match_slash && t_ch == '/')
- return ABORT_TO_STARSTAR;
+ return WM_ABORT_TO_STARSTAR;
t_ch = *++text;
}
- return ABORT_ALL;
+ return WM_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. */
- negated = p_ch == NEGATE_CLASS? TRUE : FALSE;
+ /* Assign literal 1/0 because of "matched" comparison. */
+ negated = p_ch == NEGATE_CLASS ? 1 : 0;
if (negated) {
/* Inverted character class. */
p_ch = *++p;
}
prev_ch = 0;
- matched = FALSE;
+ matched = 0;
do {
if (!p_ch)
- return ABORT_ALL;
+ return WM_ABORT_ALL;
if (p_ch == '\\') {
p_ch = *++p;
if (!p_ch)
- return ABORT_ALL;
+ return WM_ABORT_ALL;
if (t_ch == p_ch)
- matched = TRUE;
+ matched = 1;
} else if (p_ch == '-' && prev_ch && p[1] && p[1] != ']') {
p_ch = *++p;
if (p_ch == '\\') {
p_ch = *++p;
if (!p_ch)
- return ABORT_ALL;
+ return WM_ABORT_ALL;
}
if (t_ch <= p_ch && t_ch >= prev_ch)
- matched = TRUE;
+ matched = 1;
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;
+ return WM_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;
+ matched = 1;
continue;
}
if (CC_EQ(s,i, "alnum")) {
if (ISALNUM(t_ch))
- matched = TRUE;
+ matched = 1;
} else if (CC_EQ(s,i, "alpha")) {
if (ISALPHA(t_ch))
- matched = TRUE;
+ matched = 1;
} else if (CC_EQ(s,i, "blank")) {
if (ISBLANK(t_ch))
- matched = TRUE;
+ matched = 1;
} else if (CC_EQ(s,i, "cntrl")) {
if (ISCNTRL(t_ch))
- matched = TRUE;
+ matched = 1;
} else if (CC_EQ(s,i, "digit")) {
if (ISDIGIT(t_ch))
- matched = TRUE;
+ matched = 1;
} else if (CC_EQ(s,i, "graph")) {
if (ISGRAPH(t_ch))
- matched = TRUE;
+ matched = 1;
} else if (CC_EQ(s,i, "lower")) {
if (ISLOWER(t_ch))
- matched = TRUE;
+ matched = 1;
} else if (CC_EQ(s,i, "print")) {
if (ISPRINT(t_ch))
- matched = TRUE;
+ matched = 1;
} else if (CC_EQ(s,i, "punct")) {
if (ISPUNCT(t_ch))
- matched = TRUE;
+ matched = 1;
} else if (CC_EQ(s,i, "space")) {
if (ISSPACE(t_ch))
- matched = TRUE;
+ matched = 1;
} else if (CC_EQ(s,i, "upper")) {
if (ISUPPER(t_ch))
- matched = TRUE;
+ matched = 1;
} else if (CC_EQ(s,i, "xdigit")) {
if (ISXDIGIT(t_ch))
- matched = TRUE;
+ matched = 1;
} else /* malformed [:class:] string */
- return ABORT_ALL;
+ return WM_ABORT_ALL;
p_ch = 0; /* This makes "prev_ch" get set to 0. */
} else if (t_ch == p_ch)
- matched = TRUE;
+ matched = 1;
} while (prev_ch = p_ch, (p_ch = *++p) != ']');
if (matched == negated || t_ch == '/')
- return NOMATCH;
+ return WM_NOMATCH;
continue;
}
}
- return *text ? NOMATCH : MATCH;
+ return *text ? WM_NOMATCH : WM_MATCH;
}
/* Match the "pattern" against the "text" string. */
-int wildmatch(const char *pattern, const char *text, int flags)
+int wildmatch(const char *pattern, const char *text,
+ unsigned int flags, struct wildopts *wo)
{
return dowild((const uchar*)pattern, (const uchar*)text,
- flags & FNM_CASEFOLD ? 1 :0);
+ flags & WM_CASEFOLD ? 1 :0);
}
diff --git a/wildmatch.h b/wildmatch.h
index 984a38c..1c814fd 100644
--- a/wildmatch.h
+++ b/wildmatch.h
@@ -1,9 +1,17 @@
-/* wildmatch.h */
+#ifndef WILDMATCH_H
+#define WILDMATCH_H
-#define ABORT_MALFORMED 2
-#define NOMATCH 1
-#define MATCH 0
-#define ABORT_ALL -1
-#define ABORT_TO_STARSTAR -2
+#define WM_CASEFOLD 1
-int wildmatch(const char *pattern, const char *text, int flags);
+#define WM_ABORT_MALFORMED 2
+#define WM_NOMATCH 1
+#define WM_MATCH 0
+#define WM_ABORT_ALL -1
+#define WM_ABORT_TO_STARSTAR -2
+
+struct wildopts;
+
+int wildmatch(const char *pattern, const char *text,
+ unsigned int flags,
+ struct wildopts *wo);
+#endif
--
1.8.0.rc2.23.g1fb49df
^ permalink raw reply related
* [PATCH v2 4/9] wildmatch: make dowild() take arbitrary flags
From: Nguyễn Thái Ngọc Duy @ 2012-12-28 4:10 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy
In-Reply-To: <1356667854-8686-1-git-send-email-pclouds@gmail.com>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
wildmatch.c | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/wildmatch.c b/wildmatch.c
index f9b6451..68e4213 100644
--- a/wildmatch.c
+++ b/wildmatch.c
@@ -52,7 +52,7 @@ typedef unsigned char uchar;
#define ISXDIGIT(c) (ISASCII(c) && isxdigit(c))
/* Match pattern "p" against "text" */
-static int dowild(const uchar *p, const uchar *text, int force_lower_case)
+static int dowild(const uchar *p, const uchar *text, unsigned int flags)
{
uchar p_ch;
@@ -61,9 +61,9 @@ static int dowild(const uchar *p, const uchar *text, int force_lower_case)
uchar t_ch, prev_ch;
if ((t_ch = *text) == '\0' && p_ch != '*')
return WM_ABORT_ALL;
- if (force_lower_case && ISUPPER(t_ch))
+ if ((flags & WM_CASEFOLD) && ISUPPER(t_ch))
t_ch = tolower(t_ch);
- if (force_lower_case && ISUPPER(p_ch))
+ if ((flags & WM_CASEFOLD) && ISUPPER(p_ch))
p_ch = tolower(p_ch);
switch (p_ch) {
case '\\':
@@ -97,7 +97,7 @@ static int dowild(const uchar *p, const uchar *text, int force_lower_case)
* both foo/bar and foo/a/bar.
*/
if (p[0] == '/' &&
- dowild(p + 1, text, force_lower_case) == WM_MATCH)
+ dowild(p + 1, text, flags) == WM_MATCH)
return WM_MATCH;
match_slash = 1;
} else
@@ -116,7 +116,7 @@ static int dowild(const uchar *p, const uchar *text, int force_lower_case)
while (1) {
if (t_ch == '\0')
break;
- if ((matched = dowild(p, text, force_lower_case)) != WM_NOMATCH) {
+ if ((matched = dowild(p, text, flags)) != WM_NOMATCH) {
if (!match_slash || matched != WM_ABORT_TO_STARSTAR)
return matched;
} else if (!match_slash && t_ch == '/')
@@ -227,6 +227,5 @@ static int dowild(const uchar *p, const uchar *text, int force_lower_case)
int wildmatch(const char *pattern, const char *text,
unsigned int flags, struct wildopts *wo)
{
- return dowild((const uchar*)pattern, (const uchar*)text,
- flags & WM_CASEFOLD ? 1 :0);
+ return dowild((const uchar*)pattern, (const uchar*)text, flags);
}
--
1.8.0.rc2.23.g1fb49df
^ permalink raw reply related
* [PATCH v2 5/9] wildmatch: support "no FNM_PATHNAME" mode
From: Nguyễn Thái Ngọc Duy @ 2012-12-28 4:10 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy
In-Reply-To: <1356667854-8686-1-git-send-email-pclouds@gmail.com>
So far, wildmatch() has always honoured directory boundary and there
was no way to turn it off. Make it behave more like fnmatch() by
requiring all callers that want the FNM_PATHNAME behaviour to pass
that in the equivalent flag WM_PATHNAME. Callers that do not specify
WM_PATHNAME will get wildcards like ? and * in their patterns matched
against '/', just like not passing FNM_PATHNAME to fnmatch().
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
dir.c | 2 +-
t/t3070-wildmatch.sh | 27 +++++++++++++++++++++++++++
test-wildmatch.c | 6 ++++--
wildmatch.c | 13 +++++++++----
wildmatch.h | 1 +
5 files changed, 42 insertions(+), 7 deletions(-)
diff --git a/dir.c b/dir.c
index 175a182..6ef0396 100644
--- a/dir.c
+++ b/dir.c
@@ -595,7 +595,7 @@ int match_pathname(const char *pathname, int pathlen,
}
return wildmatch(pattern, name,
- ignore_case ? WM_CASEFOLD : 0,
+ WM_PATHNAME | (ignore_case ? WM_CASEFOLD : 0),
NULL) == 0;
}
diff --git a/t/t3070-wildmatch.sh b/t/t3070-wildmatch.sh
index d5bafef..dbfa903 100755
--- a/t/t3070-wildmatch.sh
+++ b/t/t3070-wildmatch.sh
@@ -29,6 +29,18 @@ match() {
fi
}
+pathmatch() {
+ if [ $1 = 1 ]; then
+ test_expect_success "pathmatch: match '$2' '$3'" "
+ test-wildmatch pathmatch '$2' '$3'
+ "
+ else
+ test_expect_success "pathmatch: no match '$2' '$3'" "
+ ! test-wildmatch pathmatch '$2' '$3'
+ "
+ fi
+}
+
# Basic wildmat features
match 1 1 foo foo
match 0 0 foo bar
@@ -192,4 +204,19 @@ match 0 0 'XXX/adobe/courier/bold/o/normal//12/120/75/75/X/70/iso8859/1' 'XXX/*/
match 1 0 'abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txt' '**/*a*b*g*n*t'
match 0 0 'abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txtz' '**/*a*b*g*n*t'
+pathmatch 1 foo foo
+pathmatch 0 foo fo
+pathmatch 1 foo/bar foo/bar
+pathmatch 1 foo/bar 'foo/*'
+pathmatch 1 foo/bba/arr 'foo/*'
+pathmatch 1 foo/bba/arr 'foo/**'
+pathmatch 1 foo/bba/arr 'foo*'
+pathmatch 1 foo/bba/arr 'foo**'
+pathmatch 1 foo/bba/arr 'foo/*arr'
+pathmatch 1 foo/bba/arr 'foo/**arr'
+pathmatch 0 foo/bba/arr 'foo/*z'
+pathmatch 0 foo/bba/arr 'foo/**z'
+pathmatch 1 foo/bar 'foo?bar'
+pathmatch 1 foo/bar 'foo[/]bar'
+
test_done
diff --git a/test-wildmatch.c b/test-wildmatch.c
index 4bb23b4..a5f4833 100644
--- a/test-wildmatch.c
+++ b/test-wildmatch.c
@@ -12,9 +12,11 @@ int main(int argc, char **argv)
argv[i] += 3;
}
if (!strcmp(argv[1], "wildmatch"))
- return !!wildmatch(argv[3], argv[2], 0, NULL);
+ return !!wildmatch(argv[3], argv[2], WM_PATHNAME, NULL);
else if (!strcmp(argv[1], "iwildmatch"))
- return !!wildmatch(argv[3], argv[2], WM_CASEFOLD, NULL);
+ return !!wildmatch(argv[3], argv[2], WM_PATHNAME | WM_CASEFOLD, NULL);
+ else if (!strcmp(argv[1], "pathmatch"))
+ return !!wildmatch(argv[3], argv[2], 0, NULL);
else if (!strcmp(argv[1], "fnmatch"))
return !!fnmatch(argv[3], argv[2], FNM_PATHNAME);
else
diff --git a/wildmatch.c b/wildmatch.c
index 68e4213..0c8edb8 100644
--- a/wildmatch.c
+++ b/wildmatch.c
@@ -77,14 +77,17 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)
continue;
case '?':
/* Match anything but '/'. */
- if (t_ch == '/')
+ if ((flags & WM_PATHNAME) && t_ch == '/')
return WM_NOMATCH;
continue;
case '*':
if (*++p == '*') {
const uchar *prev_p = p - 2;
while (*++p == '*') {}
- if ((prev_p == text || *prev_p == '/') ||
+ if (!(flags & WM_PATHNAME))
+ /* without WM_PATHNAME, '*' == '**' */
+ match_slash = 1;
+ else if ((prev_p == text || *prev_p == '/') ||
(*p == '\0' || *p == '/' ||
(p[0] == '\\' && p[1] == '/'))) {
/*
@@ -103,7 +106,8 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)
} else
return WM_ABORT_MALFORMED;
} else
- match_slash = 0;
+ /* without WM_PATHNAME, '*' == '**' */
+ match_slash = flags & WM_PATHNAME ? 0 : 1;
if (*p == '\0') {
/* Trailing "**" matches everything. Trailing "*" matches
* only if there are no more slash characters. */
@@ -214,7 +218,8 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)
} else if (t_ch == p_ch)
matched = 1;
} while (prev_ch = p_ch, (p_ch = *++p) != ']');
- if (matched == negated || t_ch == '/')
+ if (matched == negated ||
+ ((flags & WM_PATHNAME) && t_ch == '/'))
return WM_NOMATCH;
continue;
}
diff --git a/wildmatch.h b/wildmatch.h
index 1c814fd..4090c8f 100644
--- a/wildmatch.h
+++ b/wildmatch.h
@@ -2,6 +2,7 @@
#define WILDMATCH_H
#define WM_CASEFOLD 1
+#define WM_PATHNAME 2
#define WM_ABORT_MALFORMED 2
#define WM_NOMATCH 1
--
1.8.0.rc2.23.g1fb49df
^ permalink raw reply related
* [PATCH v2 6/9] test-wildmatch: add "perf" command to compare wildmatch and fnmatch
From: Nguyễn Thái Ngọc Duy @ 2012-12-28 4:10 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy
In-Reply-To: <1356667854-8686-1-git-send-email-pclouds@gmail.com>
It takes a text file, a pattern, a number <n> and pathname flag. Each
line in the text file is matched against the pattern <n> times. If
"pathname" is given, FNM_PATHNAME is used.
test-wildmatch is built with -O2 and tested against glibc 2.14.1 (also
-O2) and compat/fnmatch. The input file is linux-2.6.git file list.
<n> is 2000. The complete command list is at the end.
wildmatch is beaten in the following cases. Apparently it needs some
improvement in FNM_PATHNAME case:
glibc, '*/*/*' with FNM_PATHNAME:
wildmatch 8s 1559us
fnmatch 1s 11877us or 12.65% faster
compat, '*/*/*' with FNM_PATHNAME:
wildmatch 7s 922458us
fnmatch 2s 905111us or 36.67% faster
compat, '*/*/*' without FNM_PATHNAME:
wildmatch 7s 264201us
fnmatch 2s 1897us or 27.56% faster
compat, '[a-z]*/[a-z]*/[a-z]*' with FNM_PATHNAME:
wildmatch 8s 742827us
fnmatch 0s 922943us or 10.56% faster
compat, '[a-z]*/[a-z]*/[a-z]*' without FNM_PATHNAME:
wildmatch 8s 284520us
fnmatch 0s 6936us or 0.08% faster
The rest of glibc numbers
-------------------------
'Documentation/*'
wildmatch 1s 529479us
fnmatch 1s 98263us or 71.81% slower
'drivers/*'
wildmatch 1s 988288us
fnmatch 1s 192049us or 59.95% slower
'Documentation/*' pathname
wildmatch 1s 557507us
fnmatch 1s 93696us or 70.22% slower
'drivers/*' pathname
wildmatch 2s 161626us
fnmatch 1s 230372us or 56.92% slower
'[Dd]ocu[Mn]entation/*'
wildmatch 1s 776581us
fnmatch 1s 471693us or 82.84% slower
'[Dd]o?u[Mn]en?ati?n/*'
wildmatch 1s 770770us
fnmatch 1s 555727us or 87.86% slower
'[Dd]o?u[Mn]en?ati?n/*' pathname
wildmatch 1s 783507us
fnmatch 1s 537029us or 86.18% slower
'[A-Za-z][A-Za-z]??*'
wildmatch 4s 110386us
fnmatch 4s 926306us or 119.85% slower
'[A-Za-z][A-Za-z]??'
wildmatch 3s 918114us
fnmatch 3s 686175us or 94.08% slower
'[A-Za-z][A-Za-z]??*' pathname
wildmatch 4s 453746us
fnmatch 4s 955856us or 111.27% slower
'[A-Za-z][A-Za-z]??' pathname
wildmatch 3s 896646us
fnmatch 3s 733828us or 95.82% slower
'*/*/*'
wildmatch 7s 287985us
fnmatch 1s 74083us or 14.74% slower
'[a-z]*/[a-z]*/[a-z]*' pathname
wildmatch 8s 796659us
fnmatch 1s 568409us or 17.83% slower
'[a-z]*/[a-z]*/[a-z]*'
wildmatch 8s 316559us
fnmatch 3s 430652us or 41.25% slower
The rest of compat numbers
--------------------------
'Documentation/*'
wildmatch 1s 520389us
fnmatch 0s 62579us or 4.12% slower
'drivers/*'
wildmatch 1s 955354us
fnmatch 0s 190109us or 9.72% slower
'Documentation/*' pathname
wildmatch 1s 561675us
fnmatch 0s 55336us or 3.54% slower
'drivers/*' pathname
wildmatch 2s 106100us
fnmatch 0s 219680us or 10.43% slower
'[Dd]ocu[Mn]entation/*'
wildmatch 1s 750810us
fnmatch 0s 542721us or 31.00% slower
'[Dd]o?u[Mn]en?ati?n/*'
wildmatch 1s 724791us
fnmatch 0s 538948us or 31.25% slower
'[Dd]o?u[Mn]en?ati?n/*' pathname
wildmatch 1s 731403us
fnmatch 0s 537474us or 31.04% slower
'[A-Za-z][A-Za-z]??*'
wildmatch 4s 28555us
fnmatch 1s 67297us or 26.49% slower
'[A-Za-z][A-Za-z]??'
wildmatch 3s 838279us
fnmatch 0s 880005us or 22.93% slower
'[A-Za-z][A-Za-z]??*' pathname
wildmatch 4s 379476us
fnmatch 1s 55643us or 24.10% slower
'[A-Za-z][A-Za-z]??' pathname
wildmatch 3s 830910us
fnmatch 0s 849699us or 22.18% slower
The following commands are used:
LANG=C ./test-wildmatch perf /tmp/filelist.txt 'Documentation/*' 2000
LANG=C ./test-wildmatch perf /tmp/filelist.txt 'drivers/*' 2000
LANG=C ./test-wildmatch perf /tmp/filelist.txt 'Documentation/*' 2000 pathname
LANG=C ./test-wildmatch perf /tmp/filelist.txt 'drivers/*' 2000 pathname
LANG=C ./test-wildmatch perf /tmp/filelist.txt '[Dd]ocu[Mn]entation/*' 2000
LANG=C ./test-wildmatch perf /tmp/filelist.txt '[Dd]o?u[Mn]en?ati?n/*' 2000
LANG=C ./test-wildmatch perf /tmp/filelist.txt '[Dd]o?u[Mn]en?ati?n/*' 2000 pathname
LANG=C ./test-wildmatch perf /tmp/filelist.txt '[A-Za-z][A-Za-z]??*' 2000
LANG=C ./test-wildmatch perf /tmp/filelist.txt '[A-Za-z][A-Za-z]??' 2000
LANG=C ./test-wildmatch perf /tmp/filelist.txt '[A-Za-z][A-Za-z]??*' 2000 pathname
LANG=C ./test-wildmatch perf /tmp/filelist.txt '[A-Za-z][A-Za-z]??' 2000 pathname
LANG=C ./test-wildmatch perf /tmp/filelist.txt '*/*/*' 2000
LANG=C ./test-wildmatch perf /tmp/filelist.txt '*/*/*' 2000 pathname
LANG=C ./test-wildmatch perf /tmp/filelist.txt '[a-z]*/[a-z]*/[a-z]*' 2000 pathname
LANG=C ./test-wildmatch perf /tmp/filelist.txt '[a-z]*/[a-z]*/[a-z]*' 2000
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
test-wildmatch.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 73 insertions(+)
diff --git a/test-wildmatch.c b/test-wildmatch.c
index a5f4833..ac86800 100644
--- a/test-wildmatch.c
+++ b/test-wildmatch.c
@@ -1,9 +1,82 @@
#include "cache.h"
#include "wildmatch.h"
+static int perf(int ac, char **av)
+{
+ struct timeval tv1, tv2;
+ struct stat st;
+ int fd, i, n, flags1 = 0, flags2 = 0;
+ char *buffer, *p;
+ uint32_t usec1, usec2;
+ const char *lang;
+ const char *file = av[0];
+ const char *pattern = av[1];
+
+ lang = getenv("LANG");
+ if (lang && strcmp(lang, "C"))
+ die("Please test it on C locale.");
+
+ if ((fd = open(file, O_RDONLY)) == -1 || fstat(fd, &st))
+ die_errno("file open");
+
+ buffer = xmalloc(st.st_size + 2);
+ if (read(fd, buffer, st.st_size) != st.st_size)
+ die_errno("read");
+
+ buffer[st.st_size] = '\0';
+ buffer[st.st_size + 1] = '\0';
+ for (i = 0; i < st.st_size; i++)
+ if (buffer[i] == '\n')
+ buffer[i] = '\0';
+
+ n = atoi(av[2]);
+ if (av[3] && !strcmp(av[3], "pathname")) {
+ flags1 = WM_PATHNAME;
+ flags2 = FNM_PATHNAME;
+ }
+
+ gettimeofday(&tv1, NULL);
+ for (i = 0; i < n; i++) {
+ for (p = buffer; *p; p += strlen(p) + 1)
+ wildmatch(pattern, p, flags1, NULL);
+ }
+ gettimeofday(&tv2, NULL);
+
+ usec1 = (uint32_t)tv2.tv_sec * 1000000 + tv2.tv_usec;
+ usec1 -= (uint32_t)tv1.tv_sec * 1000000 + tv1.tv_usec;
+ printf("wildmatch %ds %dus\n",
+ (int)(usec1 / 1000000),
+ (int)(usec1 % 1000000));
+
+ gettimeofday(&tv1, NULL);
+ for (i = 0; i < n; i++) {
+ for (p = buffer; *p; p += strlen(p) + 1)
+ fnmatch(pattern, p, flags2);
+ }
+ gettimeofday(&tv2, NULL);
+
+ usec2 = (uint32_t)tv2.tv_sec * 1000000 + tv2.tv_usec;
+ usec2 -= (uint32_t)tv1.tv_sec * 1000000 + tv1.tv_usec;
+ if (usec2 > usec1)
+ printf("fnmatch %ds %dus or %.2f%% slower\n",
+ (int)((usec2 - usec1) / 1000000),
+ (int)((usec2 - usec1) % 1000000),
+ (float)(usec2 - usec1) / usec1 * 100);
+ else
+ printf("fnmatch %ds %dus or %.2f%% faster\n",
+ (int)((usec1 - usec2) / 1000000),
+ (int)((usec1 - usec2) % 1000000),
+ (float)(usec1 - usec2) / usec1 * 100);
+ return 0;
+}
+
int main(int argc, char **argv)
{
int i;
+
+ if (!strcmp(argv[1], "perf"))
+ return perf(argc - 2, argv + 2);
+
for (i = 2; i < argc; i++) {
if (argv[i][0] == '/')
die("Forward slash is not allowed at the beginning of the\n"
--
1.8.0.rc2.23.g1fb49df
^ permalink raw reply related
* [PATCH v2 7/9] wildmatch: make a special case for "*/" with FNM_PATHNAME
From: Nguyễn Thái Ngọc Duy @ 2012-12-28 4:10 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy
In-Reply-To: <1356667854-8686-1-git-send-email-pclouds@gmail.com>
Normally we need recursion for "*". In this case we know that it
matches everything until "/" so we can skip the recursion.
glibc, '*/*/*' on linux-2.6.git file list 2000 times
before:
wildmatch 8s 74513us
fnmatch 1s 97042us or 13.59% faster
after:
wildmatch 3s 521862us
fnmatch 3s 488616us or 99.06% slower
Same test with compat/fnmatch:
wildmatch 8s 110763us
fnmatch 2s 980845us or 36.75% faster
wildmatch 3s 522156us
fnmatch 1s 544487us or 43.85% slower
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
t/t3070-wildmatch.sh | 8 ++++++++
wildmatch.c | 12 ++++++++++++
2 files changed, 20 insertions(+)
diff --git a/t/t3070-wildmatch.sh b/t/t3070-wildmatch.sh
index dbfa903..4cdb13b 100755
--- a/t/t3070-wildmatch.sh
+++ b/t/t3070-wildmatch.sh
@@ -203,6 +203,10 @@ match 1 1 'XXX/adobe/courier/bold/o/normal//12/120/75/75/m/70/iso8859/1' 'XXX/*/
match 0 0 'XXX/adobe/courier/bold/o/normal//12/120/75/75/X/70/iso8859/1' 'XXX/*/*/*/*/*/*/12/*/*/*/m/*/*/*'
match 1 0 'abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txt' '**/*a*b*g*n*t'
match 0 0 'abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txtz' '**/*a*b*g*n*t'
+match 0 x foo '*/*/*'
+match 0 x foo/bar '*/*/*'
+match 1 x foo/bba/arr '*/*/*'
+match 0 x foo/bb/aa/rr '*/*/*'
pathmatch 1 foo foo
pathmatch 0 foo fo
@@ -218,5 +222,9 @@ pathmatch 0 foo/bba/arr 'foo/*z'
pathmatch 0 foo/bba/arr 'foo/**z'
pathmatch 1 foo/bar 'foo?bar'
pathmatch 1 foo/bar 'foo[/]bar'
+pathmatch 0 foo '*/*/*'
+pathmatch 0 foo/bar '*/*/*'
+pathmatch 1 foo/bba/arr '*/*/*'
+pathmatch 1 foo/bb/aa/rr '*/*/*'
test_done
diff --git a/wildmatch.c b/wildmatch.c
index 0c8edb8..f6d45d5 100644
--- a/wildmatch.c
+++ b/wildmatch.c
@@ -116,6 +116,18 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)
return WM_NOMATCH;
}
return WM_MATCH;
+ } else if (*p == '/' && (flags & WM_PATHNAME) && !match_slash) {
+ /*
+ * an asterisk followed by a slash
+ * with WM_PATHNAME matches the next
+ * directory
+ */
+ const char *slash = strchr((char*)text, '/');
+ if (!slash)
+ return WM_NOMATCH;
+ text = (const uchar*)slash;
+ /* the slash is consumed by the top-level for loop */
+ break;
}
while (1) {
if (t_ch == '\0')
--
1.8.0.rc2.23.g1fb49df
^ permalink raw reply related
* [PATCH v2 8/9] wildmatch: advance faster in <asterisk> + <literal> patterns
From: Nguyễn Thái Ngọc Duy @ 2012-12-28 4:10 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy
In-Reply-To: <1356667854-8686-1-git-send-email-pclouds@gmail.com>
compat, '*/*/*' on linux-2.6.git file list 2000 times, before:
wildmatch 7s 985049us
fnmatch 2s 735541us or 34.26% faster
and after:
wildmatch 4s 492549us
fnmatch 0s 888263us or 19.77% slower
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
t/t3070-wildmatch.sh | 6 ++++++
wildmatch.c | 21 +++++++++++++++++++++
2 files changed, 27 insertions(+)
diff --git a/t/t3070-wildmatch.sh b/t/t3070-wildmatch.sh
index 4cdb13b..dcbc8bc 100755
--- a/t/t3070-wildmatch.sh
+++ b/t/t3070-wildmatch.sh
@@ -207,6 +207,9 @@ match 0 x foo '*/*/*'
match 0 x foo/bar '*/*/*'
match 1 x foo/bba/arr '*/*/*'
match 0 x foo/bb/aa/rr '*/*/*'
+match 1 x abcXdefXghi '*X*i'
+match 0 x ab/cXd/efXg/hi '*X*i'
+match 1 x ab/cXd/efXg/hi '*/*X*/*/*i'
pathmatch 1 foo foo
pathmatch 0 foo fo
@@ -226,5 +229,8 @@ pathmatch 0 foo '*/*/*'
pathmatch 0 foo/bar '*/*/*'
pathmatch 1 foo/bba/arr '*/*/*'
pathmatch 1 foo/bb/aa/rr '*/*/*'
+pathmatch 1 abcXdefXghi '*X*i'
+pathmatch 1 ab/cXd/efXg/hi '*/*X*/*/*i'
+pathmatch 1 ab/cXd/efXg/hi '*Xg*i'
test_done
diff --git a/wildmatch.c b/wildmatch.c
index f6d45d5..40eda08 100644
--- a/wildmatch.c
+++ b/wildmatch.c
@@ -132,6 +132,27 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)
while (1) {
if (t_ch == '\0')
break;
+ /*
+ * Try to advance faster when an asterisk is
+ * followed by a literal. We know in this case
+ * that the the string before the literal
+ * must belong to "*".
+ */
+ if (!is_glob_special(*p)) {
+ p_ch = *p;
+ if ((flags & WM_CASEFOLD) && ISUPPER(p_ch))
+ p_ch = tolower(p_ch);
+ while ((t_ch = *text) != '\0' &&
+ (!(flags & WM_PATHNAME) || t_ch != '/')) {
+ if ((flags & WM_CASEFOLD) && ISUPPER(t_ch))
+ t_ch = tolower(t_ch);
+ if (t_ch == p_ch)
+ break;
+ text++;
+ }
+ if (t_ch != p_ch)
+ return WM_NOMATCH;
+ }
if ((matched = dowild(p, text, flags)) != WM_NOMATCH) {
if (!match_slash || matched != WM_ABORT_TO_STARSTAR)
return matched;
--
1.8.0.rc2.23.g1fb49df
^ permalink raw reply related
* [PATCH v2 9/9] Makefile: add USE_WILDMATCH to use wildmatch as fnmatch
From: Nguyễn Thái Ngọc Duy @ 2012-12-28 4:10 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy
In-Reply-To: <1356667854-8686-1-git-send-email-pclouds@gmail.com>
This is similar to NO_FNMATCH but it uses wildmatch instead of
compat/fnmatch. This is an intermediate step to let wildmatch be used
as fnmatch replacement for wider audience before it replaces fnmatch
completely and compat/fnmatch is removed.
fnmatch in test-wildmatch is not impacted by this and is the only
place that NO_FNMATCH or NO_FNMATCH_CASEFOLD remain active when
USE_WILDMATCH is set.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
Makefile | 6 ++++++
git-compat-util.h | 13 +++++++++++++
test-wildmatch.c | 3 +++
3 files changed, 22 insertions(+)
diff --git a/Makefile b/Makefile
index bc868d1..24e2774 100644
--- a/Makefile
+++ b/Makefile
@@ -99,6 +99,9 @@ all::
# Define NO_FNMATCH_CASEFOLD if your fnmatch function doesn't have the
# FNM_CASEFOLD GNU extension.
#
+# Define USE_WILDMATCH if you want to use Git's wildmatch
+# implementation as fnmatch
+#
# Define NO_GECOS_IN_PWENT if you don't have pw_gecos in struct passwd
# in the C library.
#
@@ -1625,6 +1628,9 @@ ifdef NO_FNMATCH_CASEFOLD
COMPAT_OBJS += compat/fnmatch/fnmatch.o
endif
endif
+ifdef USE_WILDMATCH
+ COMPAT_CFLAGS += -DUSE_WILDMATCH
+endif
ifdef NO_SETENV
COMPAT_CFLAGS += -DNO_SETENV
COMPAT_OBJS += compat/setenv.o
diff --git a/git-compat-util.h b/git-compat-util.h
index 02f48f6..b2c7638 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -106,7 +106,9 @@
#include <sys/time.h>
#include <time.h>
#include <signal.h>
+#ifndef USE_WILDMATCH
#include <fnmatch.h>
+#endif
#include <assert.h>
#include <regex.h>
#include <utime.h>
@@ -238,6 +240,17 @@ extern char *gitbasename(char *);
#include "compat/bswap.h"
+#ifdef USE_WILDMATCH
+#include "wildmatch.h"
+#define FNM_PATHNAME WM_PATHNAME
+#define FNM_CASEFOLD WM_CASEFOLD
+#define FNM_NOMATCH WM_NOMATCH
+static inline int fnmatch(const char *pattern, const char *string, int flags)
+{
+ return wildmatch(pattern, string, flags, NULL);
+}
+#endif
+
/* General helper functions */
extern void vreportf(const char *prefix, const char *err, va_list params);
extern void vwritef(int fd, const char *prefix, const char *err, va_list params);
diff --git a/test-wildmatch.c b/test-wildmatch.c
index ac86800..a3e2643 100644
--- a/test-wildmatch.c
+++ b/test-wildmatch.c
@@ -1,3 +1,6 @@
+#ifdef USE_WILDMATCH
+#undef USE_WILDMATCH /* We need real fnmatch implementation here */
+#endif
#include "cache.h"
#include "wildmatch.h"
--
1.8.0.rc2.23.g1fb49df
^ permalink raw reply related
* Re: Find the starting point of a local branch
From: Woody Wu @ 2012-12-28 5:15 UTC (permalink / raw)
To: Martin von Zweigbergk; +Cc: Seth Robertson, git
In-Reply-To: <CANiSa6iSYvLbp1s8h9pwi=P1m0QdZPqf06hAm+4muChgJUuj=g@mail.gmail.com>
On Mon, Dec 24, 2012 at 09:24:39AM -0800, Martin von Zweigbergk wrote:
> On Sun, Dec 23, 2012 at 11:31 PM, Woody Wu <narkewoody@gmail.com> wrote:
> > On Sun, Dec 23, 2012 at 11:09:58PM -0500, Seth Robertson wrote:
> >>
> >> In message <20121224035825.GA17203@zuhnb712>, Woody Wu writes:
> >>
> >> How can I find out what's the staring reference point (a commit number
> >> or tag name) of a locally created branch? I can use gitk to find out it
> >> but this method is slow, I think there might be a command line to do it
> >> quickly.
> >>
> >> The answer is more complex than you probably suspected.
> >>
> >> Technically, `git log --oneline mybranch | tail -n 1` will tell you
> >> the starting point of any branch. But...I'm sure that isn't what you
> >> want to know.
> >>
> >> You want to know "what commit was I at when I typed `git branch
> >> mybranch`"?
> >
> > Yes, this is exactly I want to know.
> >
> >>The problem is git doesn't record this information and
> >> doesn't have the slightest clue.
> >>
> >> But, you say, I can use `gitk` and see it. See? Right there. That
> >> isn't (necessarily) the "starting point" of the branch, it is the
> >> place where your branch diverged from some other branch. Git is
> >> actually quite able to tell you when the last time your branch
> >> diverged from some other branch. `git merge-base mybranch master`
> >> will tell you this, and is probably the answer you were looking for.
> >
> > This is not working to me since I have more than one local branch that
> > diverged from the master, and in fact, the branch I have in question was
> > diverged from another local branch.
>
> As Jeff mentions in a later message, "git pull --rebase" would
> probably do what you want. It works with local branches too.
>
I think what 'git pull --rebase' would do is to fetch from the origin
and do a 'git rebase'. On one hand, I don't understand 'git rebase' so
much from the manual, ont the other hand, I did not get the point why
'git rebase' has something to do with the thing I want to do (what I
want is just query some kind of history information).
I know, my knowledge about git is still so limit. I will keep study from
the man pages.
> I once tried to add the same cleverness that "git pull --rebase"
> directly in "git rebase" [1], but there were several issues with those
> patches, one of was regarding the performance ("git pull --rebase" can
> be equally slow, but since it often involves network, users probably
> rarely notice). I think it would be nice to at least add it as an
> option to "git rebase" some day. Until then, "git pull --rebase" works
> fine.
>
> [1] http://thread.gmane.org/gmane.comp.version-control.git/166710
--
woody
I can't go back to yesterday - because I was a different person then.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox