* Re: Editing Git Log
From: Matthias Kestenholz @ 2008-09-18 6:21 UTC (permalink / raw)
To: Piet Delaney; +Cc: Git Mailing List
In-Reply-To: <48D1ECB4.9080808@tensilica.com>
On Thu, Sep 18, 2008 at 7:52 AM, Piet Delaney
<piet.delaney@tensilica.com> wrote:
> I think I recall reading that a feature of git was the prevention of the git
> commits
> from being changed. I noticed today that a couple of us have checked in
> files
> without our customary [XTENSA] architecture prefixed to the 1st line of our
> Commit Messages.
>
> I couldn't find a way to do this, other than our reverting back to a earlier
> repository
> and recommitting (each?) change with the slightly changed Commit Message;
> not an attractive investment of our time.
>
> Any suggestions?
>
You have to create new commits, but you do not have to do it by hand. See
filter-branch[1]
The example given in the manpage removes the git-svn identifiers:
git filter-branch --msg-filter '
sed -e "/^git-svn-id:/d"
'
You can probably modify the sed expression and use it nearly as is (of course
you would not want to filter the whole history, only the handful commits that
came from you or your team.
[1]: http://www.kernel.org/pub/software/scm/git/docs/git-filter-branch.html
^ permalink raw reply
* Re: Editing Git Log
From: Björn Steinbrink @ 2008-09-18 6:21 UTC (permalink / raw)
To: Boaz Harrosh; +Cc: Piet Delaney, Git Mailing List
In-Reply-To: <48D1F19E.60907@panasas.com>
On 2008.09.18 09:13:50 +0300, Boaz Harrosh wrote:
> Piet Delaney wrote:
> > I think I recall reading that a feature of git was the prevention of the
> > git commits
> > from being changed. I noticed today that a couple of us have checked in
> > files
> > without our customary [XTENSA] architecture prefixed to the 1st line of our
> > Commit Messages.
> >
> > I couldn't find a way to do this, other than our reverting back to a
> > earlier repository
> > and recommitting (each?) change with the slightly changed Commit Message;
> > not an attractive investment of our time.
> >
> > Any suggestions?
> >
> > -piet
> > --
>
> git rebase --interactive FIRST_BAD_COMMIT^ will effectively do the same
> as above but in a nice automated way. Just change pick => edit on these
> patches that need fixing, you'll see.
git filter-branch with a suited msg-filter is even more automated :-)
Björn
^ permalink raw reply
* Re: combined diff, but not condensed, howto?
From: Junio C Hamano @ 2008-09-18 6:14 UTC (permalink / raw)
To: Johannes Sixt; +Cc: Git Mailing List
In-Reply-To: <48D1EDB7.5070107@viscovery.net>
Johannes Sixt <j.sixt@viscovery.net> writes:
> Junio C Hamano schrieb:
>> Johannes Sixt <j.sixt@viscovery.net> writes:
>>
>>> After a merge conflict, 'git diff' shows a combined diff, which presents
>>> only the parts that conflicted or where there are near-by changes from
>>> different parents (potential conflicts). Is there a command line switch so
>>> that *all* changes are shown, even non-conflicting ones?
>>
>> Like "git diff HEAD"?
>
> No. Something that produces
...
Ah, I see what you mean.
It all happens inside combine-diff.c::make_hunks(). If you pass dense==0,
you should be able to get all the uninteresting hunks, I think.
Perhaps
$ git diff --base -c
???
^ permalink raw reply
* Re: Editing Git Log
From: Boaz Harrosh @ 2008-09-18 6:13 UTC (permalink / raw)
To: Piet Delaney; +Cc: Git Mailing List
In-Reply-To: <48D1ECB4.9080808@tensilica.com>
Piet Delaney wrote:
> I think I recall reading that a feature of git was the prevention of the
> git commits
> from being changed. I noticed today that a couple of us have checked in
> files
> without our customary [XTENSA] architecture prefixed to the 1st line of our
> Commit Messages.
>
> I couldn't find a way to do this, other than our reverting back to a
> earlier repository
> and recommitting (each?) change with the slightly changed Commit Message;
> not an attractive investment of our time.
>
> Any suggestions?
>
> -piet
> --
git rebase --interactive FIRST_BAD_COMMIT^ will effectively do the same
as above but in a nice automated way. Just change pick => edit on these
patches that need fixing, you'll see.
Boaz
^ permalink raw reply
* Re: combined diff, but not condensed, howto?
From: Johannes Sixt @ 2008-09-18 5:57 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Git Mailing List
In-Reply-To: <7vwsha6761.fsf@gitster.siamese.dyndns.org>
Junio C Hamano schrieb:
> Johannes Sixt <j.sixt@viscovery.net> writes:
>
>> After a merge conflict, 'git diff' shows a combined diff, which presents
>> only the parts that conflicted or where there are near-by changes from
>> different parents (potential conflicts). Is there a command line switch so
>> that *all* changes are shown, even non-conflicting ones?
>
> Like "git diff HEAD"?
No. Something that produces
@@@ -23,5 -23,5 +23,7 @@@
A
B
++<<<<<<< HEAD:foo
+C
++=======
+ D
++>>>>>>> 97d7fee2cb068f215a593c6e5623b265db45d3bc:foo
E
F
@@@ -50,4 -50,5 +53,5 @@@
G
H
+I
J
K
@@@ -60,5 -61,4 +63,4 @@@
L
M
- N
O
P
^ permalink raw reply
* Re: Help using Git(-svn) for specific use case
From: Dmitry Potapov @ 2008-09-18 5:56 UTC (permalink / raw)
To: Pico Geyer; +Cc: git
In-Reply-To: <aa2b76740809170709y77275473k93d48e354bea55e5@mail.gmail.com>
Hi Pico,
I will try answer your question, but unfortunately I don't have much
time for detail explanations, so maybe someone else will add a few
more comments.
On Wed, Sep 17, 2008 at 04:09:51PM +0200, Pico Geyer wrote:
>
> I'm going to give example commands to confirm my understanding of the
> git-svn workflow you described.
> Any comments or corrections are welcome.
>
> On the local server, get a clone of the repository:
> srvA# git svn clone http://server.com/repo/proj/trunk proj
> srvA# cd proj
>
> Create a local branch, where developers will push to
> srvA# git branch integration
>
> Now a developer clones the repository on the server, and makes a local
> branch for developement:
> dev1# git clone ssh://svrA/path/to/repo
> dev1# git checkout -b new_featureX
> (Developer makes some changes and commits to the new_featureX branch)
I believe developers should start from the integration branch, i.e.:
git checkout -b new_featureX origin/integration
>
> Developer now pushes the changes to the integration branch
> dev1# git push origin new_featureX:integration
If someone already push there, push will refuse saying that it is
non-fast forward update. So, the developer will have to rebase his/her
branch on top of origin/integration:
git fetch && git rebase origin/integration
or provided that you created your branch from origin/integration,
you can run:
git pull --rebase
which does git fetch and rebase on the top of the original branch.
>
> The merge master now rebases the changes on to the master branch:
> srvA# git rebase integration
What this commands does is to rebase your current branch on top
of the integration branch. I suppose you have something like
this before running it:
master integration
o------o-----o-------o
If you are staying at the master, it will advance master to
integration. So, yes, it does what you need, but your wording:
"rebases the changes on to the master branch" is not correct,
because it is master is rebased on top of integration, which
in your case is just fast-forward update of it to integration:
integration=master
o------o-----o-------o
you can have the same effect by "git merge integration".
>
> Now push the changes to the upstream subversion server:
> srvA# git svn dcommit
I usually run "git svn dcommit --dry-run" first to make sure that it
will commit what I want. It is very useful when you try a new setup.
>
> At some stage svn users will commit to the subversion repository, and
> we will need to pull changes into srvA:
> srvA# git svn rebase
Yes, but you usually do that before git svn dcommit...
>
> Now the integration branch does not include the changes in master, so
> rebase the changes to integration:
> srvA# git rebase master integration
That is okay but may lead to the situation that conflicts that were
already resolved during git svn rebase will be re-emerge again.
You can force integration branch to be the same master after you
have dcommited changes to SVN using the following command:
git branch -f integration master
but if someone push into repository after the point where 'master' was
equal to 'integration' then those changes may be lost. To prevent this
from happening, you can lock repository (or only this particular branch)
from being push into when you dcommit changes to svn. Then when you have
finished, you can safely use the above command. The lock can be
implemented using the 'update' hook (for instance, the hook verifies
whether the "integration.lock" tag exists, if it does then the hook
exists with non-zero value).
>
> Finally the developer needs those changes too, so on his master branch:
> dev1# git rebase origin
No, it is
git fetch && git rebase origin/integration
or just
git pull --rebase
provided that you started your branch from origin/integration.
>
> Is this the process that you were trying to describe?
> Any additional steps that need to be added?
Yes, basically, it is. It could be some variations though. Instead of
having the integration branch in the repository that you use to sync
with SVN, you can have a separate bare repository where 'master' will
represent the integration branch, while git-svn repository is private to
the merge master. The advantage is that merge master does not need the
shell access to the server. Also, developers see only one branch 'master'
(less confusion about what to use as the starting point). In this setup,
you need to allow to the merge master non-fast forward update to the
bare repository (to update 'master' after commiting changes to SVN),
while the rest developers should have only fast-forward update.
>
> And how do I make sure that when developers push to the server that it
> results in a fast-forward merge? Do I do that with commit hooks?
No, all commits and merges are purely local things. git push never
merges anything, it only propogates changes and update the branch
references. The only thing you should guarantee that no one (except
the merge master if necessary) can do non-fast forward push to server.
To disable to all users non-fast forward update, you can set
receive.denyNonFastForwards = true
If you disable to some users but not to others then you can use
either $GIT_DIR/hooks/pre-receive or $GIT_DIR/hooks/update.
See man git-receive-pack for more information, and examples
of the update hook included in Git.
Dmitry
^ permalink raw reply
* Editing Git Log
From: Piet Delaney @ 2008-09-18 5:52 UTC (permalink / raw)
To: Git Mailing List; +Cc: Piet Delaney
I think I recall reading that a feature of git was the prevention of the
git commits
from being changed. I noticed today that a couple of us have checked in
files
without our customary [XTENSA] architecture prefixed to the 1st line of our
Commit Messages.
I couldn't find a way to do this, other than our reverting back to a
earlier repository
and recommitting (each?) change with the slightly changed Commit Message;
not an attractive investment of our time.
Any suggestions?
-piet
^ permalink raw reply
* Re: git equivalent to svn info?
From: Junio C Hamano @ 2008-09-18 5:50 UTC (permalink / raw)
To: public-git-users-/JYPxA39Uh5TLH3MbocFFw; +Cc: git
In-Reply-To: <20080917224856.GT10360@machine.or.cz>
Petr Baudis <pasky-+ZI9xUNit7I@public.gmane.org> writes:
> On Thu, Sep 18, 2008 at 10:13:34AM +1200, Francois Marier wrote:
>> On Wed, 2008-09-17 at 14:46 -0700, skillzero-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org wrote:
>> > Is there an easy way with git to get the URL of the repository that
>> > you cloned from, similar to what svn info shows for a subversion
>> > repository? I see it's stored in [remote "origin"]->url section of
>> > the .git/config, but I was hoping for an easy-to-remember command to
>> > display it.
>>
>> I normally use "git remote show origin"
>
> You can also get a quick overview with git remote -v.
Ah, that reminds me...
It is Ok to have more than one URL defined for a remote if you use that
remote for push, but "git remote -v" complains, like this:
$ git remote -v
warning: Remote builders has more than one URL
builders box-fc5:git/
ko-private m.kernel.org:git/
when I have 3 URLs (box-fc5, box-fc7 and box-fc9) for "builders" remote to
push into.
Could somebody fix this, please?
^ permalink raw reply
* Re: [PATCH 2/4] diff.c: associate a flag with each pattern and use it for compiling regex
From: Junio C Hamano @ 2008-09-18 4:14 UTC (permalink / raw)
To: Brandon Casey
Cc: Arjen Laarhoven, Mike Ralphson, Johannes Sixt, Jeff King,
Boyd Lynn Gerber, Git Mailing List
In-Reply-To: <GZAEBf1BcP9-dznrIesxaE4Rb8bim6DpwDWCb9yWl99UVoQC9Dog0A@cipher.nrlssc.navy.mil>
Brandon Casey <casey@nrlssc.navy.mil> writes:
> This is in preparation for allowing extended regular expression patterns.
> ...
> @@ -100,10 +100,11 @@ static int parse_lldiff_command(const char *var, const char *ep, const char *val
> static struct funcname_pattern {
> char *name;
> char *pattern;
> + int cflags;
What does "C" stand for?
^ permalink raw reply
* [PATCH 4/4 v2] diff.c: convert builtin funcname patterns to extended regular expressions
From: Brandon Casey @ 2008-09-18 0:33 UTC (permalink / raw)
To: Junio C Hamano, Arjen Laarhoven, Mike Ralphson, Johannes Sixt,
Jeff King, Boyd
In-Reply-To: <-f-gqL4SkA8Uh7hSuKT-JDY0g26jHn3fDQCE24MB1nKWUMLZWuSseg@cipher.nrlssc.navy.mil>
Signed-off-by: Brandon Casey <casey@nrlssc.navy.mil>
---
The original version changed the cflags parameter from '0' to '1'
rather than to the macro REG_EXTENDED as it should have been.
This version is corrected.
-brandon
diff.c | 35 ++++++++++++++++++-----------------
1 files changed, 18 insertions(+), 17 deletions(-)
diff --git a/diff.c b/diff.c
index ad5e551..8018544 100644
--- a/diff.c
+++ b/diff.c
@@ -1401,23 +1401,24 @@ static struct funcname_pattern_entry {
const char *pattern;
const int cflags;
} builtin_funcname_pattern[] = {
- { "bibtex", "\\(@[a-zA-Z]\\{1,\\}[ \t]*{\\{0,1\\}[ \t]*[^ \t\"@',\\#}{~%]*\\).*$", 0 },
- { "html", "^\\s*\\(<[Hh][1-6]\\s.*>.*\\)$", 0 },
- { "java", "!^[ ]*\\(catch\\|do\\|for\\|if\\|instanceof\\|"
- "new\\|return\\|switch\\|throw\\|while\\)\n"
- "^[ ]*\\(\\([ ]*"
- "[A-Za-z_][A-Za-z_0-9]*\\)\\{2,\\}"
- "[ ]*([^;]*\\)$", 0 },
- { "pascal", "^\\(\\(procedure\\|function\\|constructor\\|"
- "destructor\\|interface\\|implementation\\|"
- "initialization\\|finalization\\)[ \t]*.*\\)$"
- "\\|"
- "^\\(.*=[ \t]*\\(class\\|record\\).*\\)$",
- 0 },
- { "php", "^[\t ]*\\(\\(function\\|class\\).*\\)", 0 },
- { "python", "^\\s*\\(\\(class\\|def\\)\\s.*\\)$", 0 },
- { "ruby", "^\\s*\\(\\(class\\|module\\|def\\)\\s.*\\)$", 0 },
- { "tex", "^\\(\\\\\\(\\(sub\\)*section\\|chapter\\|part\\)\\*\\{0,1\\}{.*\\)$", 0 },
+ { "bibtex", "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#\\}\\{~%]*).*$", REG_EXTENDED },
+ { "html", "^\\s*(<[Hh][1-6]\\s.*>.*)$", REG_EXTENDED },
+ { "java", "!^[ ]*(catch|do|for|if|instanceof|"
+ "new|return|switch|throw|while)\n"
+ "^[ ]*(([ ]*"
+ "[A-Za-z_][A-Za-z_0-9]*){2,}"
+ "[ ]*\\([^;]*)$", REG_EXTENDED },
+ { "pascal", "^((procedure|function|constructor|"
+ "destructor|interface|implementation|"
+ "initialization|finalization)[ \t]*.*)$"
+ "|"
+ "^(.*=[ \t]*(class|record).*)$",
+ REG_EXTENDED },
+ { "php", "^[\t ]*((function|class).*)", REG_EXTENDED },
+ { "python", "^\\s*((class|def)\\s.*)$", REG_EXTENDED },
+ { "ruby", "^\\s*((class|module|def)\\s.*)$", REG_EXTENDED },
+ { "tex", "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$",
+ REG_EXTENDED },
};
static const struct funcname_pattern_entry *funcname_pattern(const char *ident)
--
1.6.0.1.244.gdc19
^ permalink raw reply related
* [PATCH 4/4] diff.c: convert builtin funcname patterns to extended regular expressions
From: Brandon Casey @ 2008-09-18 0:21 UTC (permalink / raw)
To: Junio C Hamano, Arjen Laarhoven, Mike Ralphson, Johannes Sixt,
Jeff King, Boyd
In-Reply-To: <7v3ak06jzj.fsf@gitster.siamese.dyndns.org>
Signed-off-by: Brandon Casey <casey@nrlssc.navy.mil>
---
This is a blind conversion removing \\ before ( and { etc.
and adding \\ before naked ( and { etc.
I hope the authors who last touched these patterns will help with testing:
bibtex: Johan Herland
html: Johan Herland
java: Junio Hamano, Jeff King
pascal: Avery Pennarun
php: Andreas Ericsson
python: Kirill Smelkov
ruby: Giuseppe Bilotta
tex: Johan Herland
thanks,
-brandon
diff.c | 34 +++++++++++++++++-----------------
1 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/diff.c b/diff.c
index ad5e551..25d2259 100644
--- a/diff.c
+++ b/diff.c
@@ -1401,23 +1401,23 @@ static struct funcname_pattern_entry {
const char *pattern;
const int cflags;
} builtin_funcname_pattern[] = {
- { "bibtex", "\\(@[a-zA-Z]\\{1,\\}[ \t]*{\\{0,1\\}[ \t]*[^ \t\"@',\\#}{~%]*\\).*$", 0 },
- { "html", "^\\s*\\(<[Hh][1-6]\\s.*>.*\\)$", 0 },
- { "java", "!^[ ]*\\(catch\\|do\\|for\\|if\\|instanceof\\|"
- "new\\|return\\|switch\\|throw\\|while\\)\n"
- "^[ ]*\\(\\([ ]*"
- "[A-Za-z_][A-Za-z_0-9]*\\)\\{2,\\}"
- "[ ]*([^;]*\\)$", 0 },
- { "pascal", "^\\(\\(procedure\\|function\\|constructor\\|"
- "destructor\\|interface\\|implementation\\|"
- "initialization\\|finalization\\)[ \t]*.*\\)$"
- "\\|"
- "^\\(.*=[ \t]*\\(class\\|record\\).*\\)$",
- 0 },
- { "php", "^[\t ]*\\(\\(function\\|class\\).*\\)", 0 },
- { "python", "^\\s*\\(\\(class\\|def\\)\\s.*\\)$", 0 },
- { "ruby", "^\\s*\\(\\(class\\|module\\|def\\)\\s.*\\)$", 0 },
- { "tex", "^\\(\\\\\\(\\(sub\\)*section\\|chapter\\|part\\)\\*\\{0,1\\}{.*\\)$", 0 },
+ { "bibtex", "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#\\}\\{~%]*).*$", 1 },
+ { "html", "^\\s*(<[Hh][1-6]\\s.*>.*)$", 1 },
+ { "java", "!^[ ]*(catch|do|for|if|instanceof|"
+ "new|return|switch|throw|while)\n"
+ "^[ ]*(([ ]*"
+ "[A-Za-z_][A-Za-z_0-9]*){2,}"
+ "[ ]*\\([^;]*)$", 1 },
+ { "pascal", "^((procedure|function|constructor|"
+ "destructor|interface|implementation|"
+ "initialization|finalization)[ \t]*.*)$"
+ "|"
+ "^(.*=[ \t]*(class|record).*)$",
+ 1 },
+ { "php", "^[\t ]*((function|class).*)", 1 },
+ { "python", "^\\s*((class|def)\\s.*)$", 1 },
+ { "ruby", "^\\s*((class|module|def)\\s.*)$", 1 },
+ { "tex", "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$", 1 },
};
static const struct funcname_pattern_entry *funcname_pattern(const char *ident)
--
1.6.0.1.244.gdc19
^ permalink raw reply related
* [PATCH 3/4] diff.*.xfuncname which uses "extended" regex's for hunk header selection
From: Brandon Casey @ 2008-09-18 0:10 UTC (permalink / raw)
To: Junio C Hamano, Arjen Laarhoven, Mike Ralphson, Johannes Sixt,
Jeff King, Boyd
In-Reply-To: <7v3ak06jzj.fsf@gitster.siamese.dyndns.org>
Currently, the hunk headers produced by 'diff -p' are customizable by
setting the diff.*.funcname option in the config file. The 'funcname' option
takes a basic regular expression. This functionality was designed using the
GNU regex library which, by default, allows using backslashed versions of
some extended regular expression operators, even in Basic Regular Expression
mode. For example, the following characters, when backslashed, are
interpreted according to the extended regular expression rules: ?, +, and |.
As such, the builtin funcname patterns were created using some extended
regular expression operators.
Other platforms which adhere more strictly to the POSIX spec do not
interpret the backslashed extended RE operators in Basic Regular Expression
mode. This causes the pattern matching for the builtin funcname patterns to
fail on those platforms.
Introduce a new option 'xfuncname' which uses extended regular expressions,
and advertise it _instead_ of funcname. Since most users are on GNU
platforms, the majority of funcname patterns are created and tested there.
Advertising only xfuncname should help to avoid the creation of non-portable
patterns which work with GNU regex but not elsewhere.
Additionally, the extended regular expressions may be less ugly and
complicated compared to the basic RE since many common special operators do
not need to be backslashed.
For example, the GNU Basic RE:
^[ ]*\\(\\(public\\|static\\).*\\)$
becomes the following Extended RE:
^[ ]*((public|static).*)$
Signed-off-by: Brandon Casey <casey@nrlssc.navy.mil>
---
Documentation/gitattributes.txt | 4 ++--
diff.c | 5 +++++
t/t4018-diff-funcname.sh | 2 +-
3 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index 6f3551d..fa04eca 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -288,13 +288,13 @@ for paths.
*.tex diff=tex
------------------------
-Then, you would define "diff.tex.funcname" configuration to
+Then, you would define "diff.tex.xfuncname" configuration to
specify a regular expression that matches a line that you would
want to appear as the hunk header, like this:
------------------------
[diff "tex"]
- funcname = "^\\(\\\\\\(sub\\)*section{.*\\)$"
+ xfuncname = "^(\\\\(sub)*section{.*)$"
------------------------
Note. A single level of backslashes are eaten by the
diff --git a/diff.c b/diff.c
index 4363d0d..ad5e551 100644
--- a/diff.c
+++ b/diff.c
@@ -195,6 +195,11 @@ int git_diff_basic_config(const char *var, const char *value, void *cb)
return config_error_nonbool(var);
return parse_funcname_pattern(var, ep, value,
0);
+ } else if (!strcmp(ep, ".xfuncname")) {
+ if (!value)
+ return config_error_nonbool(var);
+ return parse_funcname_pattern(var, ep, value,
+ REG_EXTENDED);
}
}
}
diff --git a/t/t4018-diff-funcname.sh b/t/t4018-diff-funcname.sh
index 18bcd97..602d68f 100755
--- a/t/t4018-diff-funcname.sh
+++ b/t/t4018-diff-funcname.sh
@@ -58,7 +58,7 @@ test_expect_success 'last regexp must not be negated' '
'
test_expect_success 'alternation in pattern' '
- git config diff.java.funcname "^[ ]*\\(\\(public\\|static\\).*\\)$"
+ git config diff.java.xfuncname "^[ ]*((public|static).*)$" &&
git diff --no-index Beer.java Beer-correct.java |
grep "^@@.*@@ public static void main("
'
--
1.6.0.1.244.gdc19
^ permalink raw reply related
* [PATCH 2/4] diff.c: associate a flag with each pattern and use it for compiling regex
From: Brandon Casey @ 2008-09-18 0:10 UTC (permalink / raw)
To: Junio C Hamano, Arjen Laarhoven, Mike Ralphson, Johannes Sixt,
Jeff King, Boyd
In-Reply-To: <7v3ak06jzj.fsf@gitster.siamese.dyndns.org>
This is in preparation for allowing extended regular expression patterns.
Signed-off-by: Brandon Casey <casey@nrlssc.navy.mil>
---
diff.c | 28 ++++++++++++++++------------
xdiff-interface.c | 4 ++--
xdiff-interface.h | 2 +-
3 files changed, 19 insertions(+), 15 deletions(-)
diff --git a/diff.c b/diff.c
index e040088..4363d0d 100644
--- a/diff.c
+++ b/diff.c
@@ -100,10 +100,11 @@ static int parse_lldiff_command(const char *var, const char *ep, const char *val
static struct funcname_pattern {
char *name;
char *pattern;
+ int cflags;
struct funcname_pattern *next;
} *funcname_pattern_list;
-static int parse_funcname_pattern(const char *var, const char *ep, const char *value)
+static int parse_funcname_pattern(const char *var, const char *ep, const char *value, int cflags)
{
const char *name;
int namelen;
@@ -123,6 +124,7 @@ static int parse_funcname_pattern(const char *var, const char *ep, const char *v
}
free(pp->pattern);
pp->pattern = xstrdup(value);
+ pp->cflags = cflags;
return 0;
}
@@ -191,7 +193,8 @@ int git_diff_basic_config(const char *var, const char *value, void *cb)
if (!strcmp(ep, ".funcname")) {
if (!value)
return config_error_nonbool(var);
- return parse_funcname_pattern(var, ep, value);
+ return parse_funcname_pattern(var, ep, value,
+ 0);
}
}
}
@@ -1391,24 +1394,25 @@ int diff_filespec_is_binary(struct diff_filespec *one)
static struct funcname_pattern_entry {
const char *name;
const char *pattern;
+ const int cflags;
} builtin_funcname_pattern[] = {
- { "bibtex", "\\(@[a-zA-Z]\\{1,\\}[ \t]*{\\{0,1\\}[ \t]*[^ \t\"@',\\#}{~%]*\\).*$" },
- { "html", "^\\s*\\(<[Hh][1-6]\\s.*>.*\\)$" },
+ { "bibtex", "\\(@[a-zA-Z]\\{1,\\}[ \t]*{\\{0,1\\}[ \t]*[^ \t\"@',\\#}{~%]*\\).*$", 0 },
+ { "html", "^\\s*\\(<[Hh][1-6]\\s.*>.*\\)$", 0 },
{ "java", "!^[ ]*\\(catch\\|do\\|for\\|if\\|instanceof\\|"
"new\\|return\\|switch\\|throw\\|while\\)\n"
"^[ ]*\\(\\([ ]*"
"[A-Za-z_][A-Za-z_0-9]*\\)\\{2,\\}"
- "[ ]*([^;]*\\)$" },
+ "[ ]*([^;]*\\)$", 0 },
{ "pascal", "^\\(\\(procedure\\|function\\|constructor\\|"
"destructor\\|interface\\|implementation\\|"
"initialization\\|finalization\\)[ \t]*.*\\)$"
"\\|"
- "^\\(.*=[ \t]*\\(class\\|record\\).*\\)$"
- },
- { "php", "^[\t ]*\\(\\(function\\|class\\).*\\)" },
- { "python", "^\\s*\\(\\(class\\|def\\)\\s.*\\)$" },
- { "ruby", "^\\s*\\(\\(class\\|module\\|def\\)\\s.*\\)$" },
- { "tex", "^\\(\\\\\\(\\(sub\\)*section\\|chapter\\|part\\)\\*\\{0,1\\}{.*\\)$" },
+ "^\\(.*=[ \t]*\\(class\\|record\\).*\\)$",
+ 0 },
+ { "php", "^[\t ]*\\(\\(function\\|class\\).*\\)", 0 },
+ { "python", "^\\s*\\(\\(class\\|def\\)\\s.*\\)$", 0 },
+ { "ruby", "^\\s*\\(\\(class\\|module\\|def\\)\\s.*\\)$", 0 },
+ { "tex", "^\\(\\\\\\(\\(sub\\)*section\\|chapter\\|part\\)\\*\\{0,1\\}{.*\\)$", 0 },
};
static const struct funcname_pattern_entry *funcname_pattern(const char *ident)
@@ -1544,7 +1548,7 @@ static void builtin_diff(const char *name_a,
xecfg.ctxlen = o->context;
xecfg.flags = XDL_EMIT_FUNCNAMES;
if (pe)
- xdiff_set_find_func(&xecfg, pe->pattern);
+ xdiff_set_find_func(&xecfg, pe->pattern, pe->cflags);
if (!diffopts)
;
else if (!prefixcmp(diffopts, "--unified="))
diff --git a/xdiff-interface.c b/xdiff-interface.c
index 944ad98..7f1a7d3 100644
--- a/xdiff-interface.c
+++ b/xdiff-interface.c
@@ -218,7 +218,7 @@ static long ff_regexp(const char *line, long len,
return result;
}
-void xdiff_set_find_func(xdemitconf_t *xecfg, const char *value)
+void xdiff_set_find_func(xdemitconf_t *xecfg, const char *value, int cflags)
{
int i;
struct ff_regs *regs;
@@ -243,7 +243,7 @@ void xdiff_set_find_func(xdemitconf_t *xecfg, const char *value)
expression = buffer = xstrndup(value, ep - value);
else
expression = value;
- if (regcomp(®->re, expression, 0))
+ if (regcomp(®->re, expression, cflags))
die("Invalid regexp to look for hunk header: %s", expression);
free(buffer);
value = ep + 1;
diff --git a/xdiff-interface.h b/xdiff-interface.h
index 558492b..23c49b9 100644
--- a/xdiff-interface.h
+++ b/xdiff-interface.h
@@ -16,6 +16,6 @@ int parse_hunk_header(char *line, int len,
int read_mmfile(mmfile_t *ptr, const char *filename);
int buffer_is_binary(const char *ptr, unsigned long size);
-extern void xdiff_set_find_func(xdemitconf_t *xecfg, const char *line);
+extern void xdiff_set_find_func(xdemitconf_t *xecfg, const char *line, int cflags);
#endif
--
1.6.0.1.244.gdc19
^ permalink raw reply related
* [PATCH 1/4] diff.c: return pattern entry pointer rather than just the hunk header pattern
From: Brandon Casey @ 2008-09-18 0:08 UTC (permalink / raw)
To: Git Mailing List
In-Reply-To: <7v3ak06jzj.fsf@gitster.siamese.dyndns.org>
This is in preparation for associating a flag with each pattern which will
control how the pattern is interpreted. For example, as a basic or extended
regular expression.
Signed-off-by: Brandon Casey <casey@nrlssc.navy.mil>
---
Sorry for the dup, I forgot to add the list.
Junio C Hamano wrote:
> Brandon Casey <casey@nrlssc.navy.mil> writes:
>
>> It's too late to change diff.*.funcname now, but an alternative fix
>> which would probably not require every other platform to use GNU regex,
>> is to introduce a new funcname option which would allow extended regular
>> expression syntax and to convert the internal regular expressions to
>> that format.
>
> That's a very sensible approach, I would agree.
diff.c | 53 ++++++++++++++++++++++++++++++-----------------------
1 files changed, 30 insertions(+), 23 deletions(-)
diff --git a/diff.c b/diff.c
index 998dcaa..e040088 100644
--- a/diff.c
+++ b/diff.c
@@ -94,6 +94,8 @@ static int parse_lldiff_command(const char *var, const char *ep, const char *val
* 'diff.<what>.funcname' attribute can be specified in the configuration
* to define a customized regexp to find the beginning of a function to
* be used for hunk header lines of "diff -p" style output.
+ * Note: If this structure is modified, it must retain the ability to be cast
+ * to a struct funcname_pattern_entry, defined elsewhere.
*/
static struct funcname_pattern {
char *name;
@@ -1382,17 +1384,11 @@ int diff_filespec_is_binary(struct diff_filespec *one)
return one->is_binary;
}
-static const char *funcname_pattern(const char *ident)
-{
- struct funcname_pattern *pp;
-
- for (pp = funcname_pattern_list; pp; pp = pp->next)
- if (!strcmp(ident, pp->name))
- return pp->pattern;
- return NULL;
-}
-
-static struct builtin_funcname_pattern {
+/*
+ * Note: The elements of this structure must be arranged so that they are
+ * compatible with the elements of the funcname_pattern structure.
+ */
+static struct funcname_pattern_entry {
const char *name;
const char *pattern;
} builtin_funcname_pattern[] = {
@@ -1415,9 +1411,20 @@ static struct builtin_funcname_pattern {
{ "tex", "^\\(\\\\\\(\\(sub\\)*section\\|chapter\\|part\\)\\*\\{0,1\\}{.*\\)$" },
};
-static const char *diff_funcname_pattern(struct diff_filespec *one)
+static const struct funcname_pattern_entry *funcname_pattern(const char *ident)
+{
+ struct funcname_pattern *pp;
+
+ for (pp = funcname_pattern_list; pp; pp = pp->next)
+ if (!strcmp(ident, pp->name))
+ return (struct funcname_pattern_entry*) pp;
+ return NULL;
+}
+
+static const struct funcname_pattern_entry *diff_funcname_pattern(struct diff_filespec *one)
{
- const char *ident, *pattern;
+ const char *ident;
+ const struct funcname_pattern_entry *pe;
int i;
diff_filespec_check_attr(one);
@@ -1432,9 +1439,9 @@ static const char *diff_funcname_pattern(struct diff_filespec *one)
return funcname_pattern("default");
/* Look up custom "funcname.$ident" regexp from config. */
- pattern = funcname_pattern(ident);
- if (pattern)
- return pattern;
+ pe = funcname_pattern(ident);
+ if (pe)
+ return pe;
/*
* And define built-in fallback patterns here. Note that
@@ -1442,7 +1449,7 @@ static const char *diff_funcname_pattern(struct diff_filespec *one)
*/
for (i = 0; i < ARRAY_SIZE(builtin_funcname_pattern); i++)
if (!strcmp(ident, builtin_funcname_pattern[i].name))
- return builtin_funcname_pattern[i].pattern;
+ return &builtin_funcname_pattern[i];
return NULL;
}
@@ -1520,11 +1527,11 @@ static void builtin_diff(const char *name_a,
xdemitconf_t xecfg;
xdemitcb_t ecb;
struct emit_callback ecbdata;
- const char *funcname_pattern;
+ const struct funcname_pattern_entry *pe;
- funcname_pattern = diff_funcname_pattern(one);
- if (!funcname_pattern)
- funcname_pattern = diff_funcname_pattern(two);
+ pe = diff_funcname_pattern(one);
+ if (!pe)
+ pe = diff_funcname_pattern(two);
memset(&xecfg, 0, sizeof(xecfg));
memset(&ecbdata, 0, sizeof(ecbdata));
@@ -1536,8 +1543,8 @@ static void builtin_diff(const char *name_a,
xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
xecfg.ctxlen = o->context;
xecfg.flags = XDL_EMIT_FUNCNAMES;
- if (funcname_pattern)
- xdiff_set_find_func(&xecfg, funcname_pattern);
+ if (pe)
+ xdiff_set_find_func(&xecfg, pe->pattern);
if (!diffopts)
;
else if (!prefixcmp(diffopts, "--unified="))
--
1.6.0.1.244.gdc19
^ permalink raw reply related
* Re: [PATCH] Teach git diff about Objective-C syntax
From: Jonathan del Strother @ 2008-09-17 23:30 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Miklos Vajna, Andreas Ericsson, git, Johannes.Schindelin
In-Reply-To: <7vljxq4i5p.fsf@gitster.siamese.dyndns.org>
On Wed, Sep 17, 2008 at 9:44 PM, Junio C Hamano <gitster@pobox.com> wrote:
> Are you sure the regexp you have for Objective-C methods quotes a dot "."
> correctly, by the way? It appears to match almost anything enclosed in a
> pair of parentheses, as long as you have two alpha after open paren.
It could be a little more restrictive, but I'm not sure how much
further it could be taken without it getting ridiculous. Just as some
examples, it needs to match :
+(id)someClassMethod
-(id)someInstanceMethod
-(NSNumber*)numberWithNumerator:(int)n denominator:(int)d
-(NSString*)stringWithVariableArguments:(NSString*)format ...
(I seem to remember that if your method returns 'id' you can skip the
return type, eg "- someInstanceMethod", but I don't think there's any
hope for people that use that notation...)
^[ \t]*\\([-+][ \t]*([ \t]*[A-Za-z_][A-Za-z_0-9* \t]*)[ \t]*_?[A-Za-z]*\\)$
would be a small improvement - that is, a plus or minus, brackets
around the return type, then at least one letter for the method name,
potentially preceded by an underscore. Can anyone suggest anything
better?
Also, why can't I use \s for whitespace, \w for word characters etc?
I thought we were using the gnu regex library?
> Also I am not sure if you can do the pattern alternates the way you did.
> If you have this:
>
> "...\\(A\\|B\\)$"
> "\\|"
> "...\\(C\\|D\\)$"
>
> A and B will be captured as $1 but wouldn't C or D captured as $2?
Hmm, hadn't considered that. It appears to work fine, but I haven't
yet had chance to track down exactly where the funcname regexp match
occurs to see what the code is doing with the different matches. I'll
try and take a look tomorrow, unless someone can enlighten me before
then...
^ permalink raw reply
* [RFC PATCH] fetch-pack: log(n)-transmission find_common()
From: Thomas Rast @ 2008-09-17 23:01 UTC (permalink / raw)
To: git
In-Reply-To: <200809180100.32626.trast@student.ethz.ch>
See thread starter for discussion.
Signed-off-by: Thomas Rast <trast@student.ethz.ch>
---
builtin-fetch-pack.c | 333 +++++++++++++++++++++++++++++++++++++++++++------
upload-pack.c | 4 +-
2 files changed, 294 insertions(+), 43 deletions(-)
diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c
index 4dfef29..9f010fe 100644
--- a/builtin-fetch-pack.c
+++ b/builtin-fetch-pack.c
@@ -25,6 +25,11 @@ static const char fetch_pack_usage[] =
#define COMMON_REF (1U << 2)
#define SEEN (1U << 3)
#define POPPED (1U << 4)
+#define BISECTED_FW (1U << 5)
+#define BISECTED_BW (1U << 6)
+#define NOTCOMMON (1U << 7)
+#define HAS_INFO (1U << 8)
+#define CLEAN_MARKS (COMMON | COMMON_REF | SEEN | POPPED | BISECTED_FW | BISECTED_BW | NOTCOMMON)
static int marked;
@@ -34,19 +39,78 @@ static int marked;
*/
#define MAX_IN_VAIN 256
-static struct commit_list *rev_list;
+struct work_list
+{
+ struct work_list *next;
+ struct commit *commit;
+ unsigned int stride; /* current stride length between commits */
+ unsigned int steps; /* steps left to go before emitting again */
+ unsigned int bisect;
+ unsigned int is_ref :1; /* prioritise refs */
+};
+
+static struct work_list *work_list = NULL;
+
+static struct commit_list *outstanding = NULL; /* list of commits not ACKed yet */
+static struct commit_list *outstanding_end = NULL;
+
+struct commit_info
+{
+ struct commit_list *children;
+};
+
+
static int non_common_revs, multi_ack, use_sideband;
-static void rev_list_push(struct commit *commit, int mark)
+static struct commit_info *get_commit_info(struct commit *commit)
+{
+ if (commit->object.flags & HAS_INFO)
+ return commit->util;
+
+ struct commit_info *info = xmalloc(sizeof(struct commit_info));
+ info->children = NULL;
+ commit->util = info;
+ commit->object.flags |= HAS_INFO;
+ return info;
+}
+
+static void work_list_insert(struct work_list *work_item)
{
+ struct work_list **pp = &work_list;
+ struct work_list *p;
+
+ while ((p = *pp)) {
+ if ((work_item->is_ref && (!p->is_ref || p->commit->date < work_item->commit->date))
+ || (!work_item->bisect && (p->bisect || p->commit->date < work_item->commit->date))
+ || p->bisect > work_item->bisect)
+ break;
+ pp = &p->next;
+ }
+
+ work_item->next = p;
+ *pp = work_item;
+}
+
+
+static void rev_list_push(struct commit *commit, int mark, unsigned int stride, unsigned int steps, unsigned int is_ref)
+{
+ struct work_list *work_item;
+
if (!(commit->object.flags & mark)) {
commit->object.flags |= mark;
- if (!(commit->object.parsed))
+ if (!(commit->object.parsed)) {
if (parse_commit(commit))
return;
+ }
- insert_by_date(commit, &rev_list);
+ work_item = xmalloc(sizeof(struct work_list));
+ work_item->commit = commit;
+ work_item->stride = stride;
+ work_item->steps = steps;
+ work_item->bisect = 0;
+ work_item->is_ref = is_ref;
+ work_list_insert(work_item);
if (!(commit->object.flags & COMMON))
non_common_revs++;
@@ -58,7 +122,7 @@ static int rev_list_insert_ref(const char *path, const unsigned char *sha1, int
struct object *o = deref_tag(parse_object(sha1), path, 0);
if (o && o->type == OBJ_COMMIT)
- rev_list_push((struct commit *)o, SEEN);
+ rev_list_push((struct commit *)o, SEEN, 1, 1, 1);
return 0;
}
@@ -68,8 +132,7 @@ static int clear_marks(const char *path, const unsigned char *sha1, int flag, vo
struct object *o = deref_tag(parse_object(sha1), path, 0);
if (o && o->type == OBJ_COMMIT)
- clear_commit_marks((struct commit *)o,
- COMMON | COMMON_REF | SEEN | POPPED);
+ clear_commit_marks((struct commit *)o, CLEAN_MARKS);
return 0;
}
@@ -89,7 +152,7 @@ static void mark_common(struct commit *commit,
o->flags |= COMMON;
if (!(o->flags & SEEN))
- rev_list_push(commit, SEEN);
+ rev_list_push(commit, SEEN, 1, 1, 0);
else {
struct commit_list *parents;
@@ -111,49 +174,216 @@ static void mark_common(struct commit *commit,
Get the next rev to send, ignoring the common.
*/
-static const unsigned char* get_rev(void)
+
+static void get_rev_queue_parents(struct commit *commit, int mark, unsigned int stride, unsigned int steps)
+{
+ struct commit_list *parents = commit->parents;
+
+ while (parents) {
+ struct commit_info *info = get_commit_info(parents->item);
+ struct commit_list *entry;
+ for (entry = info->children; entry; entry = entry->next)
+ if (entry->item == commit)
+ break;
+ if (!entry)
+ commit_list_insert(commit, &(info->children));
+ if (!(parents->item->object.flags & SEEN))
+ rev_list_push(parents->item, mark, stride, steps, 0);
+ if (mark & COMMON)
+ mark_common(parents->item, 1, 0);
+ parents = parents->next;
+ }
+}
+
+
+static struct commit* get_rev_stride_skip(struct work_list *work_item)
+{
+ get_rev_queue_parents(work_item->commit, SEEN, work_item->stride,
+ work_item->steps + 1);
+
+ free(work_item);
+ return NULL;
+}
+
+static void setup_bisect(struct commit *commit, int depth)
+{
+ struct work_list *work_item = xmalloc(sizeof(struct work_list));
+
+ work_item->commit = commit;
+ work_item->bisect = 1+depth;
+ work_item->is_ref = 0;
+ work_list_insert(work_item);
+}
+
+static void setup_bisect_all (struct commit_list* list, int depth)
+{
+ while (list) {
+ setup_bisect(list->item, depth);
+ list = list->next;
+ }
+}
+
+static struct commit* get_rev_stride_emit(struct work_list *work_item)
+{
+ struct commit *commit = work_item->commit;
+ unsigned int mark;
+
+ commit->object.flags |= POPPED;
+
+ /* This one got hit by our walk! */
+ if (!(commit->object.flags & COMMON))
+ non_common_revs--;
+
+ if (commit->object.flags & COMMON) {
+ /* do not send "have", and ignore ancestors */
+ commit = NULL;
+ mark = COMMON | SEEN;
+ } else if (commit->object.flags & COMMON_REF) {
+ /* send "have", and ignore ancestors */
+ mark = COMMON | SEEN;
+ } else {
+ /* send "have", also for its ancestors */
+ mark = SEEN;
+ setup_bisect(commit, 0);
+ }
+
+ if (commit)
+ get_rev_queue_parents(commit, mark, work_item->stride*2, 0);
+
+ free(work_item);
+
+ return commit;
+}
+
+static struct commit* get_rev_bisect(struct work_list *work_item)
+{
+ struct commit *full;
+ struct commit *half;
+ int half_step;
+ struct commit_info *info;
+ unsigned int flags = work_item->commit->object.flags;
+
+ if (flags & NOTCOMMON) {
+ /* we inferred that this side of the bisection is not
+ * interesting any longer */
+ free(work_item);
+ return NULL;
+ }
+
+
+ if (!(flags & (COMMON|BISECTED_BW))) {
+ /* Server does not have this. Search backward in history */
+
+ full = work_item->commit;
+ full->object.flags |= BISECTED_BW;
+ half = work_item->commit;
+ half_step = 0;
+
+ while (full && full->parents) {
+ setup_bisect_all(full->parents->next, work_item->bisect);
+ full = full->parents->item;
+ half_step ^= 1;
+ if (half_step)
+ half = half->parents->item;
+ if (full->object.flags & (POPPED|COMMON))
+ break;
+ }
+
+ /* also insert the same bisection again so we can try forward too */
+ work_list_insert(work_item);
+
+ if (full->object.flags & POPPED
+ && !(full->object.flags & NOTCOMMON)
+ && !(half->object.flags & (COMMON|POPPED))) {
+ setup_bisect(half, work_item->bisect);
+ half->object.flags |= POPPED;
+ info = get_commit_info(half);
+ return half;
+ } else {
+ return NULL;
+ }
+ }
+
+ if (!(flags & (NOTCOMMON|BISECTED_FW))) {
+ /* We have not seen this yet when bisecting, search forward */
+
+ full = work_item->commit;
+ full->object.flags |= BISECTED_FW;
+ half = work_item->commit;
+ half_step = 0;
+
+ while (full && (info=get_commit_info(full))->children) {
+ setup_bisect_all(info->children->next, work_item->bisect);
+ full = info->children->item;
+ half_step ^= 1;
+ if (half_step) {
+ info = get_commit_info(half);
+ half = info->children->item;
+ }
+ if (full->object.flags & (POPPED|NOTCOMMON))
+ break;
+ }
+
+ if (full->object.flags & POPPED
+ && !(full->object.flags & COMMON)
+ && !(half->object.flags & POPPED)) {
+ setup_bisect(half, work_item->bisect);
+ half->object.flags |= POPPED;
+ info = get_commit_info(half);
+ free(work_item);
+ return half;
+ }
+ }
+
+ free(work_item);
+ return NULL;
+}
+
+
+static void mark_not_common(struct commit *commit)
+{
+ struct commit_info *info = get_commit_info(commit);
+ struct commit_list *child;
+
+ if (commit->object.flags & COMMON)
+ /* this has already been acked earlier */
+ return;
+
+ commit->object.flags |= NOTCOMMON;
+
+ for (child = info->children; child; child = child->next)
+ mark_not_common(child->item);
+}
+
+static struct commit *get_rev(void)
{
struct commit *commit = NULL;
while (commit == NULL) {
- unsigned int mark;
- struct commit_list *parents;
+ struct work_list *work_item = NULL;
- if (rev_list == NULL || non_common_revs == 0)
+ if (work_list == NULL || non_common_revs == 0)
return NULL;
- commit = rev_list->item;
- if (!commit->object.parsed)
+ work_item = work_list;
+ work_list = work_item->next;
+
+ commit = work_item->commit;
+
+ if (commit && !commit->object.parsed)
parse_commit(commit);
- parents = commit->parents;
- commit->object.flags |= POPPED;
- if (!(commit->object.flags & COMMON))
- non_common_revs--;
-
- if (commit->object.flags & COMMON) {
- /* do not send "have", and ignore ancestors */
- commit = NULL;
- mark = COMMON | SEEN;
- } else if (commit->object.flags & COMMON_REF)
- /* send "have", and ignore ancestors */
- mark = COMMON | SEEN;
- else
- /* send "have", also for its ancestors */
- mark = SEEN;
-
- while (parents) {
- if (!(parents->item->object.flags & SEEN))
- rev_list_push(parents->item, mark);
- if (mark & COMMON)
- mark_common(parents->item, 1, 0);
- parents = parents->next;
+ if (work_item->bisect) {
+ commit = get_rev_bisect(work_item);
+ } else if (work_item->steps >= work_item->stride-1
+ || (commit && !commit->parents)) {
+ commit = get_rev_stride_emit(work_item);
+ } else {
+ commit = get_rev_stride_skip(work_item);
}
-
- rev_list = rev_list->next;
}
- return commit->object.sha1;
+ return commit;
}
static int find_common(int fd[2], unsigned char *result_sha1,
@@ -161,6 +391,7 @@ static int find_common(int fd[2], unsigned char *result_sha1,
{
int fetching;
int count = 0, flushes = 0, retval;
+ struct commit *commit;
const unsigned char *sha1;
unsigned in_vain = 0;
int got_continue = 0;
@@ -243,11 +474,21 @@ static int find_common(int fd[2], unsigned char *result_sha1,
flushes = 0;
retval = -1;
- while ((sha1 = get_rev())) {
+ while ((commit = get_rev())) {
+ sha1 = commit->object.sha1;
packet_write(fd[1], "have %s\n", sha1_to_hex(sha1));
if (args.verbose)
fprintf(stderr, "have %s\n", sha1_to_hex(sha1));
in_vain++;
+
+ if (outstanding) {
+ commit_list_insert(commit, &(outstanding_end->next));
+ outstanding_end = outstanding_end->next;
+ } else {
+ commit_list_insert(commit, &outstanding);
+ outstanding_end = outstanding;
+ }
+
if (!(31 & ++count)) {
int ack;
@@ -274,6 +515,16 @@ static int find_common(int fd[2], unsigned char *result_sha1,
} else if (ack == 2) {
struct commit *commit =
lookup_commit(result_sha1);
+ struct commit_list *item;
+ while (commit != outstanding->item) {
+ mark_not_common(commit);
+ item = outstanding;
+ outstanding = item->next;
+ free(item);
+ }
+ item = outstanding;
+ outstanding = item->next;
+ free(item);
mark_common(commit, 0, 1);
retval = 0;
in_vain = 0;
@@ -445,7 +696,7 @@ static int everything_local(struct ref **refs, int nr_match, char **match)
continue;
if (!(o->flags & SEEN)) {
- rev_list_push((struct commit *)o, COMMON_REF | SEEN);
+ rev_list_push((struct commit *)o, COMMON_REF | SEEN, 1, 1, 1);
mark_common((struct commit *)o, 1, 1);
}
diff --git a/upload-pack.c b/upload-pack.c
index e5adbc0..c6dfb32 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -414,9 +414,9 @@ static int get_common_commits(void)
if (!prefixcmp(line, "have ")) {
switch (got_sha1(line+5, sha1)) {
case -1: /* they have what we do not */
- if (multi_ack && ok_to_give_up())
+/* if (multi_ack && ok_to_give_up())
packet_write(1, "ACK %s continue\n",
- sha1_to_hex(sha1));
+ sha1_to_hex(sha1));*/
break;
default:
memcpy(hex, sha1_to_hex(sha1), 41);
--
tg: (1293c95..) t/fetch-pack-speedup (depends on: origin/master)
^ permalink raw reply related
* [RFC] log(n)-transmissions common commit handshake
From: Thomas Rast @ 2008-09-17 23:00 UTC (permalink / raw)
To: git
[-- Attachment #1: Type: text/plain, Size: 8601 bytes --]
Hi *
This is a fairly long mail, so here's a brief abstract:
Using two passes, first exponential stride through history, then
bisection on the "right" windows, we implement the find_common
handshake in log(history_size) many transmissions. The followup
patch partially achieves that, but a few points are open and strict
backwards compatibility is missing (but its absence is Mostly
Harmless).
Terminology
===========
The sending side (running upload-pack) is called server, and the
receiving side (running fetch-pack) is the client. Commits fall into
the following categories:
'want':
Requested by the client for transmission.
'have':
In the client's object storage.
'common':
In both client's and server's object storage.
'private':
have, but not in the server's storage.
'required':
Part of the history graph "between" commons and wants; minimal
subset that needs to be sent over the wire as part of the
transmission.
("Verbing weirds language." -- Calvin)
When I say "a commit is not _yet_ X", I mean "it is not yet known to
be X", usually from the client's POV.
Motivation
==========
This spawned out of the O(#haves*#wants*#history) analysis late last
week. As a brief summary, the server uses the fairly expensive test
ok_to_give_up() to check whether it can cut the handshake short since
it knows enough commons to cover all wants. The thread is here:
http://article.gmane.org/gmane.comp.version-control.git/95787
(Be sure to read the follow-up regarding the first '*' bullet point.)
It does this shortcut because the client risks getting side-tracked on
a private chunk of history leading to a private root. (According to
the commit message. I'm not sure how effective it really is.)
This check by far dominates the rest of the server's work, which is
mostly lookup_object(): it only has to take each "have" line sha1, see
if it is present, and if so, ACK it. The client announces when it
considers the handshake finished, so there is no other requirement to
test for it.
A more efficient handshake could -- in addition to being more
efficient :-) -- solve this problem simply by hitting the private root
very quickly and proceeding elsewhere, avoiding the server-side check.
Outline of current algorithm
============================
The client sends all its 'have' sha1s, ordered by date, in chunks of
32. The server replies with an ACK for each 'common', i.e., for any
sha1 it finds in its own object store.
[This is complicated a bit by the exchange of refs, see "Open
questions".]
As it goes, the client marks the commons, and as soon as it runs out
of unmarket commits, it sends a "done". The server then knows the
entire set of commons too, and can proceed to generate a pack file of
the requireds.
There is a hard limit of 256 commits that go un-ACKed until the client
gives up and declares that there are no common commits.
Idea
====
The proposed algorithm scans the haves in a different order, using two
stages: exponential stride and bisection.
(1) Exponential stride:
-----------------------
Emit the first commit, then the 2nd from that, then the 4th from that,
and so on. As a boundary case, always emit the root.
If the history has "bounded width" (the meaning should be fairly
obvious), then this stage emits O(log(n)) commits up to the root.
(2) Bisection:
--------------
Call a pair of (A,B) where A is an ancestor of B "interesting" if B is
not yet common and A is not yet private.
Then the bisection step is: between any interesting pair of commits
(A,B) emitted so far, emit the one in the middle M=M(A,B).
["Cut points" between last common and first private commits clearly
lie only between such pairs.]
Assuming for a moment that the server responds immediately, this also
takes only O(log(n)) commits since M must be either common or private,
and thus A..M or M..B is no longer interesting, respectively.
To deal with the delayed responses in the actual protocol, at each
pass 'i' emit M(A,B) for all (A,B) in pairs(i) only if the pair is
still interesting. Add both (A,M) and (M,B) to pairs(i+1). Iterate.
pairs(0) is constructed from pass (1).
Intuitively, this means we emit more than log(n) only if we have
nothing else left to do.
----
Between the two stages, we achieve O(log(n)) complexity. (This
notably means that we hit private roots in far less transmitted sha1s
than the chunk size of 32.)
Unfortunately, this ordering sometimes conflicts with the server's
ok_to_give_up() shortcut mentioned in "Motivation": Consider a linear
branch 'master', and suppose the only 'common' sent out in the first
batch was the root. ok_to_give_up() detects that it has a common on
the only ancestry line of the want, and trigger a fake ACK for all
further commits. This becomes a problem when we later emit, say,
'master~1' and the server ACKs it even though it is private. (It does
not affect correctness, but can increase the depth of history
transmitted by a factor of 2 at worst.)
RFC Implementation
==================
I'll just highlight a few design decisions. It's my first serious C
coding in years, so warm up the flamethrowers...
* The work_list (replacing rev_list) is the "recursion stack" for
get_rev(). New "frames" are inserted such that the order of emitted
commits is
(a) refs
(b) stage (1) in date order
(b) stage (2) in bisection depth order
get_rev() is split across functions for each case.
Refs are moved to front because the current code emits them anyway
(see "Open questions" below), mostly to help fill the first 64
"have" lines with things we are going to send anyway, as opposed to
the "real" walk where we make choices.
* The bisection does not actually remember pairs, but flags commits
with the directions it has already started a bisection from them.
Combined with the existing POPPED flag for commits that were
emitted, the pair (A,B) can be determined from (A,direction) by a
parent/children search through the history. This simplifies the
implementation.
The idea is then to scan with two pointers 'half' and 'full' in
parallel, where the first one makes only half as many steps, until
we hit a POPPED commit. This must then be the interval we want to
bisect, and we can check whether it is still interesting, emit M,
and queue it for recursion at one level deeper.
* We maintain a list 'outstanding' of all commits that have been sent,
so that an "implied not-ACK" can be inferred from the next ACK.
This is used to do a child-recursive NOTCOMMON flagging, analogous
to the parent-recursive COMMON flagging on an ACK. The bisection
uses these flags to determine ranges.
* Yes, commit_info is a pointless level of indirection. I had more
tracking information in it before the last draft, and left it in for
the time being.
[Hint: when playing with the patch, command lines such as
git fetch-pack -v -k <url> <head> 2>&1 | git name-rev --stdin
help see the effects.]
Open Problems
=============
* Effect of branch/merge points
I do not see a better solution to deal with branch/merge points than
recursing into them. There may be examples of history where this
extra level of recursion spoils the log(n) bound. Carefully
choosing which side to scan first might help.
* Impact/clever use of refs
For some reason, current git sends all refs to the server, even if
the server should already know about lots of them. For example, in
git.git, emitting v1.6.0.2 covers almost all tags in the repository
by simple ancestor scanning.
Is there a reason for this behaviour? Otherwise it would be better
to emit them in date order and intelligently handle commons. (In
fact this does not depend on the discussed change.)
* Backwards compatibility
As mentioned above, ok_to_give_up() is not really compatible with
this algorithm. I suppose we should introduce a new capability
identifier that has the client enable the log(n) walker, and the
server disable ok_to_give_up()? Is there a better approach, or are
there problems with it? (I haven't worked with the protocol enough
to say, though it seems harmless.)
... and of course everything that I missed. ;-)
I'd greatly appreciate comments, especially from people who know the
protocol side of git.
- Thomas
--
Thomas Rast
trast@student.ethz.ch
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 197 bytes --]
^ permalink raw reply
* Re: [PATCH/RFC 0/2] git-gui: issues with merge tool series
From: Alexander Gavrilov @ 2008-09-17 22:24 UTC (permalink / raw)
To: Johannes Sixt; +Cc: git, Shawn O. Pearce
In-Reply-To: <200809172340.16367.johannes.sixt@telecom.at>
On Thursday 18 September 2008 01:40:16 Johannes Sixt wrote:
> On Mittwoch, 17. September 2008, Alexander Gavrilov wrote:
> > By the way, is there a simple way to re-create a conflict file from
> > the saved multistage index entries?
>
> There's 0cf8581e (checkout -m: recreate merge when checking out of unmerged
> index) in 'next'. But that does not address how the unmerged entries get into
> the index.
If everything else fails, the entries can be fetched from the index and
cached in RAM by git-gui itself. Then it will be able to put them back
via update-index --index-info.
Alexander
^ permalink raw reply
* Re: [PATCH (GIT-GUI,GITK) 0/8] Encoding support in GUI
From: Paul Mackerras @ 2008-09-17 21:45 UTC (permalink / raw)
To: Alexander Gavrilov; +Cc: git, Shawn O. Pearce
In-Reply-To: <1221685659-476-1-git-send-email-angavrilov@gmail.com>
Alexander Gavrilov writes:
> Currently GUI tools don't provide any support for
> viewing files that contain non-ASCII characters.
Well, that's just not true, at least as far as gitk is concerned.
If you feel there are deficiencies in how gitk handles encodings (and
I'm quite willing to believe there are, since ASCII is sufficient for
my needs), then please give us a detailed explanation of what you
would like it to do or specifically what is wrong with what it does at
the moment. I'd like to see several paragraphs, not just the one or
two sentences you have put in the descriptions for patches 6-8.
Thanks,
Paul.
^ permalink raw reply
* Re: [PATCH/RFC 0/2] git-gui: issues with merge tool series
From: Johannes Sixt @ 2008-09-17 21:40 UTC (permalink / raw)
To: Alexander Gavrilov; +Cc: git, Shawn O. Pearce
In-Reply-To: <bb6f213e0809170550q5be339d1s825f95b1165e6507@mail.gmail.com>
On Mittwoch, 17. September 2008, Alexander Gavrilov wrote:
> On Wed, Sep 17, 2008 at 3:40 PM, Johannes Sixt <johannes.sixt@telecom.at>
wrote:
> > 1. The inability to stage a conflicted file by clicking the icon is
> > *very* disruptive. The new menu entry "Stage Working Copy" is
> > really only a workaround, and it shows.
>
> I can see two ways to fix it:
>
> 1) Allow that icon to work only if the diff is currently displayed,
> and also ask for confirmation if there are any conflict markers
> present.
Good.
> Problem: What should it do with modify/delete conflicts, which
> don't have any conflict markers?
Stage the file, i.e. pick the 'modify' part (perhaps with confirmation).
Rationale: That's what the user sees in the diff pane. Additionally, keep
the "Use local/remote version" entries so that the 'delete' part can be
chosen from the context menu.
> 2) Much harder: implement complete one-click undo. This involves
> saving information from the index somewhere, and forcing such items to
> remain in the 'staged' list, even if the index isn't different from
> the tree version any more.
>
> By the way, is there a simple way to re-create a conflict file from
> the saved multistage index entries?
There's 0cf8581e (checkout -m: recreate merge when checking out of unmerged
index) in 'next'. But that does not address how the unmerged entries get into
the index.
-- Hannes
^ permalink raw reply
* Re: [PATCH 15/16] checkout: add new options to support narrow checkout
From: Jakub Narebski @ 2008-09-17 21:31 UTC (permalink / raw)
To: Nguyen Thai Ngoc Duy; +Cc: git
In-Reply-To: <fcaeb9bf0809170649w418f4af5x3055c04994c694dc@mail.gmail.com>
On Wed, 17 Sep 2008, Nguyen Thai Ngoc Duy wrote:
> On 9/17/08, Jakub Narebski <jnareb@gmail.com> wrote:
>>
>> Well, what I wanted to ask is if --remove-path starts from fully
>> checked out repository, for example if
>>
>> $ git checkout --remove-path=some_large_file
>>
>> would checkout all files _except_ 'some_large_file'.
>
> No, there is no negative spec. Like I said above, --remove-path is to
> remove some files based on the given spec.
So "git checkout --path/--add-path/--remove-path" is porcelain
interface to use (git-update-index is plumbing)?
>>>> And is <pathspec> matched against full pathname, or like .gitignore
>>>> rules, i.e. as full pathname if it has at least one '/' in it?
>>>
>>> like shell wildcard, full pathname must match. On my way back home, I
>>> thought I should have removed mention of "pathspec", which behaves a
>>> little bit different.
>>>
>>> Also those specs are relative to working directory though, so if you
>>> are in b/c and want to match d, you only need to type --add-path=d
>>> instead of --add-path=b/c/d. Will add this to doc.
>>
>> I would have thought that you follow the same rules (perhaps with
>> exception of !path excluding rule) like for gitignore and gitattributes.
>
> Um.. never thought of gitignores/gitattributes rules before. It's a
> good idea all narrowspec/gitignore/gitattributes using the same rules.
Perhaps you would be able to even reuse some of implementation?...
--
Jakub Narebski
Poland
^ permalink raw reply
* [PATCH (GIT-GUI,GITK) 7/8] gitk: Implement file contents encoding support.
From: Alexander Gavrilov @ 2008-09-17 21:07 UTC (permalink / raw)
To: git; +Cc: Shawn O. Pearce, Paul Mackerras
In-Reply-To: <1221685659-476-7-git-send-email-angavrilov@gmail.com>
Use new functions to support using explicit encoding
configuration for file contents.
Signed-off-by: Alexander Gavrilov <angavrilov@gmail.com>
---
gitk | 19 ++++++++++++++++---
1 files changed, 16 insertions(+), 3 deletions(-)
diff --git a/gitk b/gitk
index b210f79..98923e7 100755
--- a/gitk
+++ b/gitk
@@ -6295,7 +6295,7 @@ proc showfile {f} {
return
}
}
- fconfigure $bf -blocking 0
+ fconfigure $bf -blocking 0 -encoding [get_cached_encoding $f]
filerun $bf [list getblobline $bf $diffids]
$ctext config -state normal
clear_ctext $commentend
@@ -6333,6 +6333,7 @@ proc mergediff {id} {
global diffids
global parents
global diffcontext
+ global diffencoding
global limitdiffs vfilelimit curview
set diffmergeid $id
@@ -6346,9 +6347,10 @@ proc mergediff {id} {
error_popup "[mc "Error getting merge diffs:"] $err"
return
}
- fconfigure $mdf -blocking 0
+ fconfigure $mdf -blocking 0 -encoding binary
set mdifffd($id) $mdf
set np [llength $parents($curview,$id)]
+ set diffencoding [get_cached_encoding {}]
settabs $np
filerun $mdf [list getmergediffline $mdf $id $np]
}
@@ -6356,6 +6358,7 @@ proc mergediff {id} {
proc getmergediffline {mdf id np} {
global diffmergeid ctext cflist mergemax
global difffilestart mdifffd
+ global diffencoding
$ctext conf -state normal
set nr 0
@@ -6371,14 +6374,17 @@ proc getmergediffline {mdf id np} {
set here [$ctext index "end - 1c"]
lappend difffilestart $here
add_flist [list $fname]
+ set diffencoding [get_cached_encoding $fname]
set l [expr {(78 - [string length $fname]) / 2}]
set pad [string range "----------------------------------------" 1 $l]
$ctext insert end "$pad $fname $pad\n" filesep
} elseif {[regexp {^@@} $line]} {
+ set line [encoding convertfrom $diffencoding $line]
$ctext insert end "$line\n" hunksep
} elseif {[regexp {^[0-9a-f]{40}$} $line] || [regexp {^index} $line]} {
# do nothing
} else {
+ set line [encoding convertfrom $diffencoding $line]
# parse the prefix - one ' ', '-' or '+' for each parent
set spaces {}
set minuses {}
@@ -6586,6 +6592,7 @@ proc getblobdiffs {ids} {
global diffcontext
global ignorespace
global limitdiffs vfilelimit curview
+ global diffencoding
set cmd [diffcmd $ids "-p -C --no-commit-id -U$diffcontext"]
if {$ignorespace} {
@@ -6599,7 +6606,8 @@ proc getblobdiffs {ids} {
return
}
set diffinhdr 0
- fconfigure $bdf -blocking 0
+ set diffencoding [get_cached_encoding {}]
+ fconfigure $bdf -blocking 0 -encoding binary
set blobdifffd($ids) $bdf
filerun $bdf [list getblobdiffline $bdf $diffids]
}
@@ -6633,6 +6641,7 @@ proc getblobdiffline {bdf ids} {
global diffids blobdifffd ctext curdiffstart
global diffnexthead diffnextnote difffilestart
global diffinhdr treediffs
+ global diffencoding
set nr 0
$ctext conf -state normal
@@ -6670,10 +6679,12 @@ proc getblobdiffline {bdf ids} {
} else {
set fname [string range $line 2 [expr {$i - 1}]]
}
+ set diffencoding [get_cached_encoding $fname]
makediffhdr $fname $ids
} elseif {[regexp {^@@ -([0-9]+)(,[0-9]+)? \+([0-9]+)(,[0-9]+)? @@(.*)} \
$line match f1l f1c f2l f2c rest]} {
+ set line [encoding convertfrom $diffencoding $line]
$ctext insert end "$line\n" hunksep
set diffinhdr 0
@@ -6693,6 +6704,7 @@ proc getblobdiffline {bdf ids} {
if {[string index $fname 0] eq "\""} {
set fname [lindex $fname 0]
}
+ set diffencoding [get_cached_encoding $fname]
makediffhdr $fname $ids
} elseif {[string compare -length 3 $line "---"] == 0} {
# do nothing
@@ -6704,6 +6716,7 @@ proc getblobdiffline {bdf ids} {
$ctext insert end "$line\n" filesep
} else {
+ set line [encoding convertfrom $diffencoding $line]
set x [string range $line 0 0]
if {$x == "-" || $x == "+"} {
set tag [expr {$x == "+"}]
--
1.6.0.20.g6148bc
^ permalink raw reply related
* [PATCH (GIT-GUI,GITK) 8/8] gitk: Support filenames in the locale encoding.
From: Alexander Gavrilov @ 2008-09-17 21:07 UTC (permalink / raw)
To: git; +Cc: Shawn O. Pearce, Paul Mackerras
In-Reply-To: <1221685659-476-8-git-send-email-angavrilov@gmail.com>
Ensure that gitk works properly with non-ASCII names
in the system encoding. Apparently git does not support
using file names encoded differently from the current
locale.
Signed-off-by: Alexander Gavrilov <angavrilov@gmail.com>
---
gitk | 16 +++++++++++-----
1 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/gitk b/gitk
index 98923e7..254faa1 100755
--- a/gitk
+++ b/gitk
@@ -6228,7 +6228,7 @@ proc gettree {id} {
set treepending $id
set treefilelist($id) {}
set treeidlist($id) {}
- fconfigure $gtf -blocking 0
+ fconfigure $gtf -blocking 0 -encoding binary
filerun $gtf [list gettreeline $gtf $id]
}
} else {
@@ -6250,11 +6250,12 @@ proc gettreeline {gtf id} {
set line [string range $line 0 [expr {$i-1}]]
if {$diffids ne $nullid2 && [lindex $line 1] ne "blob"} continue
set sha1 [lindex $line 2]
- if {[string index $fname 0] eq "\""} {
- set fname [lindex $fname 0]
- }
lappend treeidlist($id) $sha1
}
+ if {[string index $fname 0] eq "\""} {
+ set fname [lindex $fname 0]
+ }
+ set fname [encoding convertfrom $fname]
lappend treefilelist($id) $fname
}
if {![eof $gtf]} {
@@ -6370,6 +6371,7 @@ proc getmergediffline {mdf id np} {
}
if {[regexp {^diff --cc (.*)} $line match fname]} {
# start of a new file
+ set fname [encoding convertfrom $fname]
$ctext insert end "\n"
set here [$ctext index "end - 1c"]
lappend difffilestart $here
@@ -6519,7 +6521,7 @@ proc gettreediffs {ids} {
set treepending $ids
set treediff {}
- fconfigure $gdtf -blocking 0
+ fconfigure $gdtf -blocking 0 -encoding binary
filerun $gdtf [list gettreediffline $gdtf $ids]
}
@@ -6535,6 +6537,7 @@ proc gettreediffline {gdtf ids} {
if {[string index $file 0] eq "\""} {
set file [lindex $file 0]
}
+ set file [encoding convertfrom $file]
lappend treediff $file
}
}
@@ -6679,6 +6682,7 @@ proc getblobdiffline {bdf ids} {
} else {
set fname [string range $line 2 [expr {$i - 1}]]
}
+ set fname [encoding convertfrom $fname]
set diffencoding [get_cached_encoding $fname]
makediffhdr $fname $ids
@@ -6694,6 +6698,7 @@ proc getblobdiffline {bdf ids} {
if {[string index $fname 0] eq "\""} {
set fname [lindex $fname 0]
}
+ set fname [encoding convertfrom $fname]
set i [lsearch -exact $treediffs($ids) $fname]
if {$i >= 0} {
setinlist difffilestart $i $curdiffstart
@@ -6704,6 +6709,7 @@ proc getblobdiffline {bdf ids} {
if {[string index $fname 0] eq "\""} {
set fname [lindex $fname 0]
}
+ set fname [encoding convertfrom $fname]
set diffencoding [get_cached_encoding $fname]
makediffhdr $fname $ids
} elseif {[string compare -length 3 $line "---"] == 0} {
--
1.6.0.20.g6148bc
^ permalink raw reply related
* [PATCH (GIT-GUI,GITK) 6/8] gitk: Port new encoding logic from git-gui.
From: Alexander Gavrilov @ 2008-09-17 21:07 UTC (permalink / raw)
To: git; +Cc: Shawn O. Pearce, Paul Mackerras
In-Reply-To: <1221685659-476-6-git-send-email-angavrilov@gmail.com>
Add functions that implement the same logic for file
contents encoding as git-gui uses:
- Defaults to the system encoding.
- Overridden by setting the gui.encoding option.
- Further overridden on per-file basis by gitattributes.
Also extends the range of supported encoding names.
Signed-off-by: Alexander Gavrilov <angavrilov@gmail.com>
---
gitk | 50 +++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 47 insertions(+), 3 deletions(-)
diff --git a/gitk b/gitk
index 546627f..b210f79 100755
--- a/gitk
+++ b/gitk
@@ -9726,7 +9726,7 @@ set encoding_aliases {
{ ISO-8859-16 iso-ir-226 ISO_8859-16:2001 ISO_8859-16 latin10 l10 }
{ GBK CP936 MS936 windows-936 }
{ JIS_Encoding csJISEncoding }
- { Shift_JIS MS_Kanji csShiftJIS }
+ { Shift_JIS MS_Kanji csShiftJIS ShiftJIS Shift-JIS }
{ Extended_UNIX_Code_Packed_Format_for_Japanese csEUCPkdFmtJapanese
EUC-JP }
{ Extended_UNIX_Code_Fixed_Width_for_Japanese csEUCFixWidJapanese }
@@ -9768,7 +9768,7 @@ proc tcl_encoding {enc} {
set i [lsearch -exact $lcnames $enc]
if {$i < 0} {
# look for "isonnn" instead of "iso-nnn" or "iso_nnn"
- if {[regsub {^iso[-_]} $enc iso encx]} {
+ if {[regsub {^(iso|cp|ibm|jis)[-_]} $enc {\1} encx]} {
set i [lsearch -exact $lcnames $encx]
}
}
@@ -9780,7 +9780,7 @@ proc tcl_encoding {enc} {
foreach e $ll {
set i [lsearch -exact $lcnames $e]
if {$i < 0} {
- if {[regsub {^iso[-_]} $e iso ex]} {
+ if {[regsub {^(iso|cp|ibm|jis)[-_]} $e {\1} ex]} {
set i [lsearch -exact $lcnames $ex]
}
}
@@ -9795,6 +9795,45 @@ proc tcl_encoding {enc} {
return {}
}
+proc gitattr {path attr default} {
+ if {[catch {set r [exec git check-attr $attr -- $path]}]} {
+ set r unspecified
+ } else {
+ set r [join [lrange [split $r :] 2 end] :]
+ regsub {^ } $r {} r
+ }
+ if {$r eq {unspecified}} {
+ return $default
+ }
+ return $r
+}
+
+proc get_path_encoding {path} {
+ global gui_encoding
+ set tcl_enc [tcl_encoding $gui_encoding]
+ if {$tcl_enc eq {}} {
+ set tcl_enc [encoding system]
+ }
+ if {$path ne {}} {
+ set enc2 [tcl_encoding [gitattr $path encoding $tcl_enc]]
+ if {$enc2 ne {}} {
+ set tcl_enc $enc2
+ }
+ }
+ return $tcl_enc
+}
+
+proc get_cached_encoding {path} {
+ global path_encoding_cache
+ if {[info exists path_encoding_cache($path)]} {
+ return $path_encoding_cache($path)
+ } else {
+ set enc [get_path_encoding $path]
+ set path_encoding_cache($path) $enc
+ return $enc
+ }
+}
+
# First check that Tcl/Tk is recent enough
if {[catch {package require Tk 8.4} err]} {
show_error {} . [mc "Sorry, gitk cannot run with this version of Tcl/Tk.\n\
@@ -9817,6 +9856,11 @@ if {$tclencoding == {}} {
puts stderr "Warning: encoding $gitencoding is not supported by Tcl/Tk"
}
+set gui_encoding [encoding system]
+catch {
+ set gui_encoding [exec git config --get gui.encoding]
+}
+
set mainfont {Helvetica 9}
set textfont {Courier 9}
set uifont {Helvetica 9 bold}
--
1.6.0.20.g6148bc
^ permalink raw reply related
* [PATCH (GIT-GUI,GITK) 4/8] git-gui: Optimize encoding name resolution using a lookup table.
From: Alexander Gavrilov @ 2008-09-17 21:07 UTC (permalink / raw)
To: git; +Cc: Shawn O. Pearce, Paul Mackerras
In-Reply-To: <1221685659-476-4-git-send-email-angavrilov@gmail.com>
Encoding menu construction does almost a hundred of encoding
resolutions, which with the old implementation led to a
small but noticeable delay.
Signed-off-by: Alexander Gavrilov <angavrilov@gmail.com>
---
lib/encoding.tcl | 82 +++++++++++++++++++++++++++++++++++-------------------
1 files changed, 53 insertions(+), 29 deletions(-)
diff --git a/lib/encoding.tcl b/lib/encoding.tcl
index b2ee38c..32668fc 100644
--- a/lib/encoding.tcl
+++ b/lib/encoding.tcl
@@ -286,39 +286,63 @@ set encoding_groups {
{"Symbol" Symbol Dingbats MacDingbats MacCentEuro}}
}
+proc build_encoding_table {} {
+ global encoding_aliases encoding_lookup_table
+
+ # Prepare the lookup list; cannot use lsort -nocase because
+ # of compatibility issues with older Tcl (e.g. in msysgit)
+ set names [list]
+ foreach item [encoding names] {
+ lappend names [list [string tolower $item] $item]
+ }
+ set names [lsort -ascii -index 0 $names]
+ # neither can we use lsearch -index
+ set lnames [list]
+ foreach item $names {
+ lappend lnames [lindex $item 0]
+ }
+
+ foreach grp $encoding_aliases {
+ set target {}
+ foreach item $grp {
+ set i [lsearch -sorted -ascii $lnames \
+ [string tolower $item]]
+ if {$i >= 0} {
+ set target [lindex $names $i 1]
+ break
+ }
+ }
+ if {$target eq {}} continue
+ foreach item $grp {
+ set encoding_lookup_table([string tolower $item]) $target
+ }
+ }
+
+ foreach item $names {
+ set encoding_lookup_table([lindex $item 0]) [lindex $item 1]
+ }
+}
+
proc tcl_encoding {enc} {
- global encoding_aliases
- set names [encoding names]
- set lcnames [string tolower $names]
- set enc [string tolower $enc]
- set i [lsearch -exact $lcnames $enc]
- if {$i < 0} {
- # look for "isonnn" instead of "iso-nnn" or "iso_nnn"
- if {[regsub {^(iso|cp|ibm|jis)[-_]} $enc {\1} encx]} {
- set i [lsearch -exact $lcnames $encx]
+ global encoding_lookup_table
+ if {$enc eq {}} {
+ return {}
+ }
+ if {![info exists encoding_lookup_table]} {
+ build_encoding_table
}
- }
- if {$i < 0} {
- foreach l $encoding_aliases {
- set ll [string tolower $l]
- if {[lsearch -exact $ll $enc] < 0} continue
- # look through the aliases for one that tcl knows about
- foreach e $ll {
- set i [lsearch -exact $lcnames $e]
- if {$i < 0} {
- if {[regsub {^(iso|cp|ibm|jis)[-_]} $e {\1} ex]} {
- set i [lsearch -exact $lcnames $ex]
- }
+ set enc [string tolower $enc]
+ if {![info exists encoding_lookup_table($enc)]} {
+ # look for "isonnn" instead of "iso-nnn" or "iso_nnn"
+ if {[regsub {^(iso|cp|ibm|jis)[-_]} $enc {\1} encx]} {
+ set enc $encx
}
- if {$i >= 0} break
- }
- break
}
- }
- if {$i >= 0} {
- return [lindex $names $i]
- }
- return {}
+ if {[info exists encoding_lookup_table($enc)]} {
+ return $encoding_lookup_table($enc)
+ } else {
+ return {}
+ }
}
proc force_path_encoding {path enc} {
--
1.6.0.20.g6148bc
^ permalink raw reply related
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