* Re: Improved git-gui blame viewer
From: Matthijs Melchior @ 2007-06-02 10:44 UTC (permalink / raw)
To: git
In-Reply-To: <20070602041723.GD7044@spearce.org>
Shawn O. Pearce wrote:
> A long time ago Linus Torvalds <torvalds@linux-foundation.org> wrote:
>> On Sun, 18 Mar 2007, Shawn O. Pearce wrote:
>>> Linus Torvalds <torvalds@linux-foundation.org> wrote:
>>>> Of course, the git gui blame colorization is clearly done by somebody who
>>>> is still actively popping LSD with both fists and didn't realize that the
>>>> 60's are long done, but that's another issue.
>>> git-gui is open source. I'd be happy to take a patch. Or,
>>> since that is horribly messy Tcl/Tk code, just a better color
>>> suggestion. :-)
>> I would suggest:
>>
>> - some special color for "currently selected" (which defaults to being
>> the first one coming out of the blame thing, of course).
>>
>> I'd suggest "black text on pale green background", but that may be just
>> me.
>>
>> - some *stable* graduated color for the rest. I don't think it
>> necessarily needs to be "older" vs "newer", and in fact I'd suggest
>> just two slightly different shades of gray for the background - just
>> pick alternating shades for each blame entry that comes in (and leave
>> un-blamed lines white).
>
> I finally got the git-gui code to the point where cleaning up the
> user interface was possible without sending myself to the nut house.
>
> I tried out Linus' suggestions for coloring, and I like them. Enough
> that they are now sitting in my `pu` branch on repo.or.cz/git-gui.git.
>
> There's also a whole slew of other improvements to the blame viewer,
> like being able to dig through history by clicking on commit ids,
> and tooltips when you mouse over a region of the file.
>
> Behavior on Windows is actually quite good; its less so on Mac
> OS X. I'm fighting Tk there a little bit more than I should be.
> Untested on Linux, so I'd love to hear some feedback on it.
>
> git://repo.or.cz/git-gui.git pu
> http://repo.or.cz/r/git-gui.git pu
>
I have got this on Debian Etch and given the command 'make install'
in the pu branch while git-core 1.5.2 is installed.
About git-gui says:
git-gui version 0.7.2.39.ge6a1
git version 1.5.2
Tcl/Tk version 8.4.12
The colors look much better.
The behavior has some rough edges. I don't like the following:
When clicking on a link in the left column, the file as present in
that commit is loaded, positioned at the top. I would like for the
line where I clicked is to stay at the same position on the screen,
so I do not have to find it again.
Also, when returning I would like most lines on the screen stay the
same.
When clicking on a light gray line to become a green line, then
adjacent areas are not correctly colored. A few adjacent entries
become all same gray... [Look around git-gui.sh:340]
Something I want for the normal window, in the Staged and Unstaged
file lists, high-lite the last entry selected so it becomes easy to
click on the next one and I can see more clearly what is displayed
in the bottom area.
Thanks for your efforts!
Regards,
Matthijs Melchior.
^ permalink raw reply
* Re: [PATCH] gitweb: use decode_utf8 directly
From: Jakub Narebski @ 2007-06-02 8:22 UTC (permalink / raw)
To: Alexandre Julliard; +Cc: Junio C Hamano, Ismail Dönmez, git
In-Reply-To: <87zm3ju6tg.fsf@wine.dyndns.org>
On Fri, 1 Jun 2007, Alexandre Julliard wrote:
> The cause is apparently that decode_utf8() returns undef for invalid
> sequences instead of substituting a replacement char like
> decode("utf8") does.
>
> That may be considered an Encode bug since we are running a fairly old
> version (1.99, coming with Debian 3.1), but I'd rather not upgrade
> perl on the server. Could the patch be reverted, or done differently?
Could you put modern (without this decode_utf8 bug) version of Encode.pm
in the directory with gitweb.cgi, so gitweb uses new local version and
not the one that is installed system-wide?
--
Jakub Narebski
Poland
^ permalink raw reply
* Re: [PATCH] Create a new manpage for the gitignore format, and reference it elsewhere
From: Frank Lichtenheld @ 2007-06-02 10:56 UTC (permalink / raw)
To: Josh Triplett; +Cc: git, Junio C Hamano
In-Reply-To: <4660BF65.3000605@freedesktop.org>
On Fri, Jun 01, 2007 at 05:52:53PM -0700, Josh Triplett wrote:
> Frank Lichtenheld wrote:
> > On Fri, Jun 01, 2007 at 03:20:52PM -0700, Josh Triplett wrote:
> >> + - Otherwise, git treats the pattern as a shell glob suitable
> >> + for consumption by fnmatch(3) with the FNM_PATHNAME flag: any
> >> + slash in the pattern must match a slash in the pathname. For
> >> + example, "Documentation/\*.html" matches
> >> + "Documentation/git.html" but not "ppc/ppc.html". A leading
> >> + slash matches the beginning of the pathname; for example,
> >> + "/*.c" matches "cat-file.c" but not "mozilla-sha1/sha1.c".
> >
> > I realise this is copy&paste but shouldn't that read:
> > "Documentation/\*.html" matches "Documentation/git.html"
> > but not "Documentation/ppc/ppc.html"
> > ?
>
> I don't know. Neither file seems to exist in current Git.
The point I was trying to make is that "Documentation/*.html" _of
course_ doesn't match ppc/ppc.html. What we try to tell the user here
is that * doesn't match /
So I think it should definetly read Documentation/ppc/ppc.html
FWIW, I find the sentence
"any slash in the pattern must match a slash in the pathname"
very confusing too. The sentence in fnmatch(3) is much more precise:
"match a slash in string only with a slash in pattern and not by an
asterisk (*) or a question mark (?) metacharacter, nor by a bracket
expression ([]) containing a slash"
Anyway, if you prefer (and if it is okay with Junio) I can send a
patch of my own for this single issue to not hinder the commit of
your big patch as the issue is equally present in the old and the
new text.
Gruesse,
--
Frank Lichtenheld <djpig@debian.org>
www: http://www.djpig.de/
^ permalink raw reply
* Re: [PATCH] Let .git/config specify the url for submodules
From: Lars Hjemli @ 2007-06-02 10:38 UTC (permalink / raw)
To: Junio C Hamano; +Cc: skimo, Linus Torvalds, git
In-Reply-To: <7vbqfyvf5o.fsf@assigned-by-dhcp.cox.net>
On 6/2/07, Junio C Hamano <junkio@cox.net> wrote:
> "Lars Hjemli" <hjemli@gmail.com> writes:
>
> > So I'll make 'git-submodule' expect the .gitmodules layout to be like this:
> >
> > [submodule 'xyz']
> > url=git://example.com/xyz.git
> > path=xyz1
> > path=xyz2
> >
> > And submodule.$name.path should be optional: if no submodule.*.path
> > entry exists for a given $path, submodule $name == $path.
> >
> > Ok?
>
> I do not think having more than one path for a given submodule
> makes much sense
Me neither, but it was mentioned as a possibility to have the same
repo checked out in multiple paths simultaneously. It does raise an
issue of how to push changes back into .git/submodules/$name.git tough
(git-submodule push). My initial plan for this was to push into the
branch registered for each path:
[submodule 'xyz']
url=git://example.com/xyz.git
[path 'xyz1']
submodule=xyz
branch=stable
[path 'xyz2']
submodule=xyz
branch=bleedingedge
but there is probably other/better solutions.
>but other than that yes.
Thanks
--
larsh
^ permalink raw reply
* Re: [PATCH] Let .git/config specify the url for submodules
From: Junio C Hamano @ 2007-06-02 10:12 UTC (permalink / raw)
To: Lars Hjemli; +Cc: Junio C Hamano, skimo, Linus Torvalds, git
In-Reply-To: <8c5c35580706020253j4e24785cyce712460d8d1a1b8@mail.gmail.com>
"Lars Hjemli" <hjemli@gmail.com> writes:
> So I'll make 'git-submodule' expect the .gitmodules layout to be like this:
>
> [submodule 'xyz']
> url=git://example.com/xyz.git
> path=xyz1
> path=xyz2
>
> And submodule.$name.path should be optional: if no submodule.*.path
> entry exists for a given $path, submodule $name == $path.
>
> Ok?
I do not think having more than one path for a given submodule
makes much sense, but other than that yes.
^ permalink raw reply
* Re: [PATCH] Add option -L to git-tag.
From: Junio C Hamano @ 2007-06-02 10:10 UTC (permalink / raw)
To: Matthijs Melchior; +Cc: git
In-Reply-To: <1180773465209-git-send-email-mmelchior@xs4all.nl>
Matthijs Melchior <mmelchior@xs4all.nl> writes:
> This will list the selected tags and include annotations, if any.
>
> Signed-off-by: Matthijs Melchior <mmelchior@xs4all.nl>
> ---
>
> This patch has been created to allow me to easily see the annotations with tags.
> I have not found any other way to do this...
Hmmmm. This feature ought to belong to git-show, but that
command already has its own interpretation of how a tag should
be shown.
Do we care about the "one line summary"? Perhaps...
$ git tag --pretty=short -L v2.6.11-tree
v2.6.11-tree
This is the 2.6.11 tree object.
$ git tag -L v2.6.11-tree
v2.6.11-tree
This is the 2.6.11 tree object.
NOTE! There's no commit for this, since it happened...
The answer to this question would really depend on why we would
want to have this feature. "git-tag" started as a way to
"create", and then it gained -l to "list" and -v to "verify". I
think your -L is meant to be an extension to "list", but I
suspect that while you are listing many things you would keep
the annotation short-and-sweet, and you would want to view the
full description when your interest is focused at a single one.
Maybe we would want a separate "print" action for the full
contents and use the short one for "list but more verbosely than
usual"?
I dunno; I've never been very good at the user interfaces.
> - Sorting the tag names resulting from git-rev-parse is not nessecary since
> the list of tags is already deliverd in sorted order.
This I am a bit reluctant about, as that sorting done by
rev-parse is purely by accident (i.e. it is an implementation
detail).
> - Using git-cat-file -t on every tag is expensive, but there is no alternative
This is Ok, as we have somebody working on doing git-tag as a
built-in, and once that happens, we do not have to pay the
performance penalty. So I would think at this point we should
concentrate on discussing the usefulness of this new feature and
correctness of your implementation, as that would set the course
for the future. On the other hand, "cat-file -t" performance
issues will not stay with us forever.
> @@ -26,13 +26,23 @@ do
> -f)
> force=1
> ;;
> - -l)
> - case "$#" in
> - 1)
> - set x . ;;
> - esac
> + -l|-L)
> + TAGSONLY=true
> + [ "$1" = -L ] && TAGSONLY=false
> + [ "$#" = 1 ] && set x .
> shift
> + git rev-parse --symbolic --tags | grep "$@" |
> + while read TAG
> + do
> + echo "$TAG"
> + $TAGSONLY && continue
> + OBJTYPE=$(git cat-file -t "$TAG")
> + case $OBJTYPE in
> + tag) git cat-file $OBJTYPE "$TAG" |
> + sed '1,/^$/d;/^-----BEGIN PGP SIGNATURE-----$/Q;s/^/ /'
> + ;;
> + esac
Micronit. If you already know it is a tag, you do not have to
say "cat-file $OBJTYPE".
Style. Please indent the case arm to the same level as, not
deeper than, case/esac.
This is the same as C's switch() { case ...: } indentation rule.
Please do not feed multiple expressions concatenated with
semicolon to sed, as it is one of the often observed portability
issues (not all the world is GNU yet). Write it like this
instead:
case "$OBJTYPE" in
tag)
git cat-file tag "$TAG" |
sed -e '1,/^$/d' \
-e '/^-----BEGIN PGP SIGNATURE-----$/Q' \
-e s/^/ /'
;;
esac
> + done
> exit $?
What does this command exit with now? It used to be that
$ git tag -l no-such-tag-at-all ; echo $?
said "1", I think, because grep did not match.
^ permalink raw reply
* Re: [PATCH] Let .git/config specify the url for submodules
From: Lars Hjemli @ 2007-06-02 9:53 UTC (permalink / raw)
To: Junio C Hamano; +Cc: skimo, Linus Torvalds, git
In-Reply-To: <7vejkuyaxq.fsf@assigned-by-dhcp.cox.net>
On 6/2/07, Junio C Hamano <junkio@cox.net> wrote:
> "Lars Hjemli" <hjemli@gmail.com> writes:
>
> > But why would we want to design .gitmodules in a way that makes it
> > hard to do the mapping from path to url?
>
> Perhaps because "path" is not the "identity" of the subproject, but
> the (logical) subproject name is?
>
>
Ok.
So I'll make 'git-submodule' expect the .gitmodules layout to be like this:
[submodule 'xyz']
url=git://example.com/xyz.git
path=xyz1
path=xyz2
And submodule.$name.path should be optional: if no submodule.*.path
entry exists for a given $path, submodule $name == $path.
Ok?
--
larsh
^ permalink raw reply
* Re: [PATCH 1/2] gitview: Use new-style classes
From: Junio C Hamano @ 2007-06-02 9:38 UTC (permalink / raw)
To: aneesh.kumar; +Cc: Michael Ellerman, git
In-Reply-To: <f623da83269ba030fabc64777cdb1071e5ab00bf.1180500418.git.michael@ellerman.id.au>
Michael Ellerman <michael@ellerman.id.au> writes:
> Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
Aneesh, this one is in your bailiwick.
Michael, it would have been nicer to have a real log message,
not just the Subject line, in your message. The Subject line
says what the patch does in what subarea of the git.git tree,
which is very appropriate, but that can be seen from the diff
even if you did not say so. The log message (before your
Signed-off-by line) is where you describe _why_ you would think
it is a good change. "What" and "how" are usually evident in
well written code without much explanation, but "why" is often
more useful when reviewing the patch, and reading and studying
the history of the code.
I would have written something like:
This changes the Commit class to use new-style class,
which has been available since Python 2.2 (Dec 2001).
This is a necessary step in order to use __slots__
declaration so that we can reduce the memory footprint
with my next patch.
I have no strong preference on this change myself. "Classes
that derive from type" are relatively recent invention but I
would personally feel that Python 2.2 is ancient enough that
using it would not pose any practical portability issues, but
what would I know...
The __slots__ patch depends on this, and that one has a
measurable memory footprint improvement, so I would say we
should take it.
^ permalink raw reply
* Re: [PATCH] Let .git/config specify the url for submodules
From: Junio C Hamano @ 2007-06-02 9:15 UTC (permalink / raw)
To: Lars Hjemli; +Cc: skimo, Linus Torvalds, git
In-Reply-To: <8c5c35580706020139k3beae8bbj3f51eee0ff5fd30c@mail.gmail.com>
"Lars Hjemli" <hjemli@gmail.com> writes:
> But why would we want to design .gitmodules in a way that makes it
> hard to do the mapping from path to url?
Perhaps because "path" is not the "identity" of the subproject, but
the (logical) subproject name is?
^ permalink raw reply
* [PATCH] Add option -L to git-tag.
From: Matthijs Melchior @ 2007-06-02 8:37 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, Matthijs Melchior
This will list the selected tags and include annotations, if any.
Signed-off-by: Matthijs Melchior <mmelchior@xs4all.nl>
---
This patch has been created to allow me to easily see the annotations with tags.
I have not found any other way to do this...
Some remarks on the new bit of code:
- Sorting the tag names resulting from git-rev-parse is not nessecary since
the list of tags is already deliverd in sorted order.
- Using git-cat-file -t on every tag is expensive, but there is no alternative
-Matthijs
Documentation/git-tag.txt | 5 ++++-
git-tag.sh | 24 +++++++++++++++++-------
2 files changed, 21 insertions(+), 8 deletions(-)
diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
index 4e3e027..441f361 100644
--- a/Documentation/git-tag.txt
+++ b/Documentation/git-tag.txt
@@ -11,7 +11,7 @@ SYNOPSIS
[verse]
'git-tag' [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] <name> [<head>]
'git-tag' -d <name>...
-'git-tag' -l [<pattern>]
+'git-tag' [-l | -L] [<pattern>]
'git-tag' -v <name>
DESCRIPTION
@@ -41,6 +41,9 @@ GnuPG key for signing.
`-l <pattern>` lists tags that match the given pattern (or all
if no pattern is given).
+`-L <pattern>` lists tags, including their annotations, that match
+the given pattern (or all if no pattern is given).
+
OPTIONS
-------
-a::
diff --git a/git-tag.sh b/git-tag.sh
index 6f0b7a7..45c4253 100755
--- a/git-tag.sh
+++ b/git-tag.sh
@@ -1,7 +1,7 @@
#!/bin/sh
# Copyright (c) 2005 Linus Torvalds
-USAGE='-l [<pattern>] | [-a | -s | -u <key-id>] [-f | -d | -v] [-m <msg>] <tagname> [<head>]'
+USAGE='[-l | -L] [<pattern>] | [-a | -s | -u <key-id>] [-f | -d | -v] [-m <msg>] <tagname> [<head>]'
SUBDIRECTORY_OK='Yes'
. git-sh-setup
@@ -26,13 +26,23 @@ do
-f)
force=1
;;
- -l)
- case "$#" in
- 1)
- set x . ;;
- esac
+ -l|-L)
+ TAGSONLY=true
+ [ "$1" = -L ] && TAGSONLY=false
+ [ "$#" = 1 ] && set x .
shift
- git rev-parse --symbolic --tags | sort | grep "$@"
+ git rev-parse --symbolic --tags | grep "$@" |
+ while read TAG
+ do
+ echo "$TAG"
+ $TAGSONLY && continue
+ OBJTYPE=$(git cat-file -t "$TAG")
+ case $OBJTYPE in
+ tag) git cat-file $OBJTYPE "$TAG" |
+ sed '1,/^$/d;/^-----BEGIN PGP SIGNATURE-----$/Q;s/^/ /'
+ ;;
+ esac
+ done
exit $?
;;
-m)
--
1.5.2
^ permalink raw reply related
* Re: [PATCH] Let .git/config specify the url for submodules
From: Lars Hjemli @ 2007-06-02 8:39 UTC (permalink / raw)
To: skimo; +Cc: Junio C Hamano, Linus Torvalds, git
In-Reply-To: <20070602074410.GA955MdfPADPa@greensroom.kotnet.org>
On 6/2/07, Sven Verdoolaege <skimo@kotnet.org> wrote:
> On Sat, Jun 02, 2007 at 09:13:55AM +0200, Lars Hjemli wrote:
> > Then Sven suggested to create a submodule section for the url, which would
> > allow
> >
> > $ name=$(GIT_CONFIG=.gitmodules git-config path."$path".submodule)
> > $ url=$(GIT_CONFIG=.gitmodules git-config submodule."$name".url)
> >
> >
> > But I don't see an easy way to do the mapping from path to url/submodule
> > with:
> >
> > [submodule "xyzzylib"]
> > path=lib
> > url=git://xyzzy/lib-1.2.3
> >
> > Suggestions?
>
> I'm not a shell programmer,
Me neither ;-)
>but it could look something like this
>
> $ name=$(git config --get-regexp 'submodule\..*\.path' | while read module modulepath; do if test "$modulepath" = "$path"; then echo $module | sed -e 's/^submodule.//' -e 's/.path//'; fi; done)
>
Ahh, --get-regexp, thanks.
Then this actually works:
name=$(GIT_CONFIG=.gitmodules git-config --get-regexp
'submodule\..*\.path' 'lib' | sed -e 's/^submodule\.\(.*\)\.path
lib$/\1/')
But why would we want to design .gitmodules in a way that makes it
hard to do the mapping from path to url?
--
larsh
^ permalink raw reply
* Re: [PATCH] Let .git/config specify the url for submodules
From: Sven Verdoolaege @ 2007-06-02 7:49 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Lars Hjemli, Junio C Hamano, git
In-Reply-To: <alpine.LFD.0.98.0706010919360.3957@woody.linux-foundation.org>
On Fri, Jun 01, 2007 at 09:29:58AM -0700, Linus Torvalds wrote:
> [module "infrastructure"]
> submodule = lib
> submodule = build
>
> [submodule "lib"]
> url = git://xyzzy/lib-1.2.3
>
> [submodule "build"]
> url = git://xyzzy/build-0.61
>
>
> IOW, in the above case, we have *three* modules:
>
> - module "infrastructure", that is the union of submodules/paths "lib"
> and "build"
> - module "lib" (== submodule/path "lib")
> - module "build" (== submodule/path "build")
If there are three modules, then why is one in the "module" section
and the other two in the "submodule" section?
Why not allow a module to both contain smaller modules and be contained
in a bigger module?
skimo
^ permalink raw reply
* Re: [PATCH] Let .git/config specify the url for submodules
From: Sven Verdoolaege @ 2007-06-02 7:44 UTC (permalink / raw)
To: Lars Hjemli; +Cc: Junio C Hamano, Linus Torvalds, git
In-Reply-To: <8c5c35580706020013g2a4039fcsdf8974da8cd4c2c2@mail.gmail.com>
On Sat, Jun 02, 2007 at 09:13:55AM +0200, Lars Hjemli wrote:
> Then Sven suggested to create a submodule section for the url, which would
> allow
>
> $ name=$(GIT_CONFIG=.gitmodules git-config path."$path".submodule)
> $ url=$(GIT_CONFIG=.gitmodules git-config submodule."$name".url)
>
>
> But I don't see an easy way to do the mapping from path to url/submodule
> with:
>
> [submodule "xyzzylib"]
> path=lib
> url=git://xyzzy/lib-1.2.3
>
> Suggestions?
I'm not a shell programmer, but it could look something like this
$ name=$(git config --get-regexp 'submodule\..*\.path' | while read module modulepath; do if test "$modulepath" = "$path"; then echo $module | sed -e 's/^submodule.//' -e 's/.path//'; fi; done)
skimo
^ permalink raw reply
* Re: [PATCH] Let .git/config specify the url for submodules
From: Lars Hjemli @ 2007-06-02 7:13 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Linus Torvalds, skimo, git
In-Reply-To: <7vfy5bzby1.fsf@assigned-by-dhcp.cox.net>
On 6/1/07, Junio C Hamano <junkio@cox.net> wrote:
> Linus Torvalds <torvalds@linux-foundation.org> writes:
>
> > On Fri, 1 Jun 2007, Lars Hjemli wrote:
> > ...
> > Ack. I think the natural thing for a lot of cases is the trivial "module
> > name == path" case, so having to have
> >
> > [path "kernel"]
> > module = kernel
> >
> > for that case just sounds unnecessary.
> >
> > That said, I wonder if it wouldn't be more natural to do things the other
> > way around, because quite often a "module" (under CVS conventions) is a
> > *set* of directories, so with that in mind, it might be better to have the
> > mapping be something like this:
> >
> > [module "infrastructure"]
> > submodule = lib
> > submodule = build
> >
> > [submodule "lib"]
> > url = git://xyzzy/lib-1.2.3
> >
> > [submodule "build"]
> > url = git://xyzzy/build-0.61
> >
> > and make the rule be:
> > - submodules are named by their paths (ie "path == submodule")
> > - a module is a set of such submodules/paths
> > - if no "module" is defined, the default is to just use the
> > path/submodule name
>
> I take that if you do want to name a submodule differently from
> its (currently in-tree) path, you would do something like...
>
> [submodule "xyzzylib"]
> path = lib
> url = git://xyzzy/lib-1.2.3
>
The reason I wanted to use
[path "lib"]
submodule=xyzzylib
url=git://xyzzy/lib-1.2.3
is that the git-submodule command always starts out with the submodule
path, trying to map that to an url or a submodule name. My proposal
allows
$ name=$(GIT_CONFIG=.gitmodules git-config path."$path".submodule)
$ url=$(GIT_CONFIG=.gitmodules git-config path."$path".url)
Then Sven suggested to create a submodule section for the url, which would allow
$ name=$(GIT_CONFIG=.gitmodules git-config path."$path".submodule)
$ url=$(GIT_CONFIG=.gitmodules git-config submodule."$name".url)
But I don't see an easy way to do the mapping from path to url/submodule with:
[submodule "xyzzylib"]
path=lib
url=git://xyzzy/lib-1.2.3
Suggestions?
--
larsh
^ permalink raw reply
* git-svn adding too many blank lines during git-cherry-pick, and git-cherry getting confused
From: Robin H. Johnson @ 2007-06-02 4:50 UTC (permalink / raw)
To: Git Mailing List
[-- Attachment #1: Type: text/plain, Size: 1620 bytes --]
Hi,
Bit of weirdness I ran into.
I have a SVN tree, with a branch that gets some backported fixe (they
usually apply cleanly).
I commit the fix to the trunk + git-svn dcommit, and then switch to the
other branch, and git-cherry-pick the fix.
For git-svn commits, the log has:
On the trunk side, there is a two blank line before git-svn-id.
On the branch side, there are three blank lines before git-svn-id.
If I cherry-pick from that branch to a third branch, I get 4 blank
lines.
For regular SVN commits, the log has:
Only a single blank line before git-svn-id.
I think the source of the problem is that git-svn-id is being removed
when cherry-picking, but NOT the leading blank line.
This all leads to the hashes of the commits diverging badly, and then
git-cherry gets very confused when asked to compare the trunk vs. the
branches.
How do we solve it?
This is only on a conceptual level here, looking at the present state of
git-svn, I'm not sure how best to solve it.
git-svn fetch:
1. Get commit message from SVN.
2. Trim ALL trailing blank lines (and existing git-svn-id lines).
3. If the last line was header-style (Signed-off-by, CC, etc)
3.1. if it was, do not add a blank line.
3.2. If not, add a single blank line.
4. Insert git-svn-id header.
git-svn dcommit:
1. Get commit message (git cat-file commit ....)
2. Remove the git-svn-id line.
3. Remove all trailing blank lines.
4. Commit.
--
Robin Hugh Johnson
Gentoo Linux Developer & Council Member
E-Mail : robbat2@gentoo.org
GnuPG FP : 11AC BA4F 4778 E3F6 E4ED F38E B27B 944E 3488 4E85
[-- Attachment #2: Type: application/pgp-signature, Size: 321 bytes --]
^ permalink raw reply
* Improved git-gui blame viewer
From: Shawn O. Pearce @ 2007-06-02 4:17 UTC (permalink / raw)
To: git; +Cc: Linus Torvalds
A long time ago Linus Torvalds <torvalds@linux-foundation.org> wrote:
>
> On Sun, 18 Mar 2007, Shawn O. Pearce wrote:
> > Linus Torvalds <torvalds@linux-foundation.org> wrote:
> > >
> > > Of course, the git gui blame colorization is clearly done by somebody who
> > > is still actively popping LSD with both fists and didn't realize that the
> > > 60's are long done, but that's another issue.
> >
> > git-gui is open source. I'd be happy to take a patch. Or,
> > since that is horribly messy Tcl/Tk code, just a better color
> > suggestion. :-)
>
> I would suggest:
>
> - some special color for "currently selected" (which defaults to being
> the first one coming out of the blame thing, of course).
>
> I'd suggest "black text on pale green background", but that may be just
> me.
>
> - some *stable* graduated color for the rest. I don't think it
> necessarily needs to be "older" vs "newer", and in fact I'd suggest
> just two slightly different shades of gray for the background - just
> pick alternating shades for each blame entry that comes in (and leave
> un-blamed lines white).
I finally got the git-gui code to the point where cleaning up the
user interface was possible without sending myself to the nut house.
I tried out Linus' suggestions for coloring, and I like them. Enough
that they are now sitting in my `pu` branch on repo.or.cz/git-gui.git.
There's also a whole slew of other improvements to the blame viewer,
like being able to dig through history by clicking on commit ids,
and tooltips when you mouse over a region of the file.
Behavior on Windows is actually quite good; its less so on Mac
OS X. I'm fighting Tk there a little bit more than I should be.
Untested on Linux, so I'd love to hear some feedback on it.
git://repo.or.cz/git-gui.git pu
http://repo.or.cz/r/git-gui.git pu
--
Shawn.
^ permalink raw reply
* Re: [PATCH] Unify write_index_file functions
From: Nicolas Pitre @ 2007-06-02 2:04 UTC (permalink / raw)
To: Geert Bosch; +Cc: Git List, Junio C Hamano
In-Reply-To: <20070602014836.0D5644DF122@geert-boschs-computer.local>
On Fri, 1 Jun 2007, Geert Bosch wrote:
> This patch unifies the write_index_file functions in
> builtin-pack-objects.c and index-pack.c. As the name
> "index" is overloaded in git, move in the direction of
> using "idx" and "pack idx" when refering to the pack index.
> There should be no change in functionality.
>
> Signed-off-by: Geert Bosch <bosch@gnat.com>
Acked-by: Nicolas Pitre <nico@cam.org>
> ---
> builtin-pack-objects.c | 218 +++++++++++-------------------------------------
> index-pack.c | 208 ++++++++-------------------------------------
> pack-write.c | 142 +++++++++++++++++++++++++++++++
> pack.h | 14 +++
> 4 files changed, 243 insertions(+), 339 deletions(-)
>
> Now with corrected commit message.
>
> -Geert
>
> diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c
> index e52332d..a247238 100644
> --- a/builtin-pack-objects.c
> +++ b/builtin-pack-objects.c
> @@ -23,10 +23,9 @@ git-pack-objects [{ -q | --progress | --all-progress }] [--max-pack-size=N] \n\
> [--stdout | base-name] [<ref-list | <object-list]";
>
> struct object_entry {
> - unsigned char sha1[20];
> - uint32_t crc32; /* crc of raw pack data for this object */
> - off_t offset; /* offset into the final pack file */
> + struct pack_idx_entry idx;
> unsigned long size; /* uncompressed size */
> +
> unsigned int hash; /* name hint hash */
> unsigned int depth; /* delta depth */
> struct packed_git *in_pack; /* already in pack */
> @@ -65,7 +64,6 @@ static int allow_ofs_delta;
> static const char *pack_tmp_name, *idx_tmp_name;
> static char tmpname[PATH_MAX];
> static const char *base_name;
> -static unsigned char pack_file_sha1[20];
> static int progress = 1;
> static int window = 10;
> static uint32_t pack_size_limit;
> @@ -241,11 +239,11 @@ static void *delta_against(void *buf, unsigned long size, struct object_entry *e
> {
> unsigned long othersize, delta_size;
> enum object_type type;
> - void *otherbuf = read_sha1_file(entry->delta->sha1, &type, &othersize);
> + void *otherbuf = read_sha1_file(entry->delta->idx.sha1, &type, &othersize);
> void *delta_buf;
>
> if (!otherbuf)
> - die("unable to read %s", sha1_to_hex(entry->delta->sha1));
> + die("unable to read %s", sha1_to_hex(entry->delta->idx.sha1));
> delta_buf = diff_delta(otherbuf, othersize,
> buf, size, &delta_size, 0);
> if (!delta_buf || delta_size != entry->delta_size)
> @@ -374,11 +372,11 @@ static unsigned long write_object(struct sha1file *f,
> /* yes if unlimited packfile */
> !pack_size_limit ? 1 :
> /* no if base written to previous pack */
> - entry->delta->offset == (off_t)-1 ? 0 :
> + entry->delta->idx.offset == (off_t)-1 ? 0 :
> /* otherwise double-check written to this
> * pack, like we do below
> */
> - entry->delta->offset ? 1 : 0;
> + entry->delta->idx.offset ? 1 : 0;
>
> if (!pack_to_stdout)
> crc32_begin(f);
> @@ -405,16 +403,16 @@ static unsigned long write_object(struct sha1file *f,
> z_stream stream;
> unsigned long maxsize;
> void *out;
> - buf = read_sha1_file(entry->sha1, &type, &size);
> + buf = read_sha1_file(entry->idx.sha1, &type, &size);
> if (!buf)
> - die("unable to read %s", sha1_to_hex(entry->sha1));
> + die("unable to read %s", sha1_to_hex(entry->idx.sha1));
> if (size != entry->size)
> die("object %s size inconsistency (%lu vs %lu)",
> - sha1_to_hex(entry->sha1), size, entry->size);
> + sha1_to_hex(entry->idx.sha1), size, entry->size);
> if (usable_delta) {
> buf = delta_against(buf, size, entry);
> size = entry->delta_size;
> - obj_type = (allow_ofs_delta && entry->delta->offset) ?
> + obj_type = (allow_ofs_delta && entry->delta->idx.offset) ?
> OBJ_OFS_DELTA : OBJ_REF_DELTA;
> } else {
> /*
> @@ -451,7 +449,7 @@ static unsigned long write_object(struct sha1file *f,
> * encoding of the relative offset for the delta
> * base from this object's position in the pack.
> */
> - off_t ofs = entry->offset - entry->delta->offset;
> + off_t ofs = entry->idx.offset - entry->delta->idx.offset;
> unsigned pos = sizeof(dheader) - 1;
> dheader[pos] = ofs & 127;
> while (ofs >>= 7)
> @@ -475,7 +473,7 @@ static unsigned long write_object(struct sha1file *f,
> return 0;
> }
> sha1write(f, header, hdrlen);
> - sha1write(f, entry->delta->sha1, 20);
> + sha1write(f, entry->delta->idx.sha1, 20);
> hdrlen += 20;
> } else {
> if (limit && hdrlen + datalen + 20 >= limit) {
> @@ -496,7 +494,7 @@ static unsigned long write_object(struct sha1file *f,
> off_t offset;
>
> if (entry->delta) {
> - obj_type = (allow_ofs_delta && entry->delta->offset) ?
> + obj_type = (allow_ofs_delta && entry->delta->idx.offset) ?
> OBJ_OFS_DELTA : OBJ_REF_DELTA;
> reused_delta++;
> }
> @@ -506,11 +504,11 @@ static unsigned long write_object(struct sha1file *f,
> datalen = revidx[1].offset - offset;
> if (!pack_to_stdout && p->index_version > 1 &&
> check_pack_crc(p, &w_curs, offset, datalen, revidx->nr))
> - die("bad packed object CRC for %s", sha1_to_hex(entry->sha1));
> + die("bad packed object CRC for %s", sha1_to_hex(entry->idx.sha1));
> offset += entry->in_pack_header_size;
> datalen -= entry->in_pack_header_size;
> if (obj_type == OBJ_OFS_DELTA) {
> - off_t ofs = entry->offset - entry->delta->offset;
> + off_t ofs = entry->idx.offset - entry->delta->idx.offset;
> unsigned pos = sizeof(dheader) - 1;
> dheader[pos] = ofs & 127;
> while (ofs >>= 7)
> @@ -524,7 +522,7 @@ static unsigned long write_object(struct sha1file *f,
> if (limit && hdrlen + 20 + datalen + 20 >= limit)
> return 0;
> sha1write(f, header, hdrlen);
> - sha1write(f, entry->delta->sha1, 20);
> + sha1write(f, entry->delta->idx.sha1, 20);
> hdrlen += 20;
> } else {
> if (limit && hdrlen + datalen + 20 >= limit)
> @@ -534,7 +532,7 @@ static unsigned long write_object(struct sha1file *f,
>
> if (!pack_to_stdout && p->index_version == 1 &&
> check_pack_inflate(p, &w_curs, offset, datalen, entry->size))
> - die("corrupt packed object for %s", sha1_to_hex(entry->sha1));
> + die("corrupt packed object for %s", sha1_to_hex(entry->idx.sha1));
> copy_pack_data(f, p, &w_curs, offset, datalen);
> unuse_pack(&w_curs);
> reused++;
> @@ -543,7 +541,7 @@ static unsigned long write_object(struct sha1file *f,
> written_delta++;
> written++;
> if (!pack_to_stdout)
> - entry->crc32 = crc32_end(f);
> + entry->idx.crc32 = crc32_end(f);
> return hdrlen + datalen;
> }
>
> @@ -554,7 +552,7 @@ static off_t write_one(struct sha1file *f,
> unsigned long size;
>
> /* offset is non zero if object is written already. */
> - if (e->offset || e->preferred_base)
> + if (e->idx.offset || e->preferred_base)
> return offset;
>
> /* if we are deltified, write out base object first. */
> @@ -564,10 +562,10 @@ static off_t write_one(struct sha1file *f,
> return 0;
> }
>
> - e->offset = offset;
> + e->idx.offset = offset;
> size = write_object(f, e, offset);
> if (!size) {
> - e->offset = 0;
> + e->idx.offset = 0;
> return 0;
> }
> written_list[nr_written++] = e;
> @@ -584,8 +582,7 @@ static int open_object_dir_tmp(const char *path)
> return mkstemp(tmpname);
> }
>
> -/* forward declarations for write_pack_file */
> -static void write_index_file(off_t last_obj_offset, unsigned char *sha1);
> +/* forward declaration for write_pack_file */
> static int adjust_perm(const char *path, mode_t mode);
>
> static void write_pack_file(void)
> @@ -602,6 +599,8 @@ static void write_pack_file(void)
> written_list = xmalloc(nr_objects * sizeof(struct object_entry *));
>
> do {
> + unsigned char sha1[20];
> +
> if (pack_to_stdout) {
> f = sha1fd(1, "<stdout>");
> } else {
> @@ -633,23 +632,23 @@ static void write_pack_file(void)
> * If so, rewrite it like in fast-import
> */
> if (pack_to_stdout || nr_written == nr_remaining) {
> - sha1close(f, pack_file_sha1, 1);
> + sha1close(f, sha1, 1);
> } else {
> - sha1close(f, pack_file_sha1, 0);
> - fixup_pack_header_footer(f->fd, pack_file_sha1, pack_tmp_name, nr_written);
> + sha1close(f, sha1, 0);
> + fixup_pack_header_footer(f->fd, sha1, pack_tmp_name, nr_written);
> close(f->fd);
> }
>
> if (!pack_to_stdout) {
> - unsigned char object_list_sha1[20];
> mode_t mode = umask(0);
>
> umask(mode);
> mode = 0444 & ~mode;
>
> - write_index_file(last_obj_offset, object_list_sha1);
> + idx_tmp_name = write_idx_file(NULL,
> + (struct pack_idx_entry **) written_list, nr_written, sha1);
> snprintf(tmpname, sizeof(tmpname), "%s-%s.pack",
> - base_name, sha1_to_hex(object_list_sha1));
> + base_name, sha1_to_hex(sha1));
> if (adjust_perm(pack_tmp_name, mode))
> die("unable to make temporary pack file readable: %s",
> strerror(errno));
> @@ -657,19 +656,19 @@ static void write_pack_file(void)
> die("unable to rename temporary pack file: %s",
> strerror(errno));
> snprintf(tmpname, sizeof(tmpname), "%s-%s.idx",
> - base_name, sha1_to_hex(object_list_sha1));
> + base_name, sha1_to_hex(sha1));
> if (adjust_perm(idx_tmp_name, mode))
> die("unable to make temporary index file readable: %s",
> strerror(errno));
> if (rename(idx_tmp_name, tmpname))
> die("unable to rename temporary index file: %s",
> strerror(errno));
> - puts(sha1_to_hex(object_list_sha1));
> + puts(sha1_to_hex(sha1));
> }
>
> /* mark written objects as written to previous pack */
> for (j = 0; j < nr_written; j++) {
> - written_list[j]->offset = (off_t)-1;
> + written_list[j]->idx.offset = (off_t)-1;
> }
> nr_remaining -= nr_written;
> } while (nr_remaining && i < nr_objects);
> @@ -687,129 +686,12 @@ static void write_pack_file(void)
> */
> for (j = 0; i < nr_objects; i++) {
> struct object_entry *e = objects + i;
> - j += !e->offset && !e->preferred_base;
> + j += !e->idx.offset && !e->preferred_base;
> }
> if (j)
> die("wrote %u objects as expected but %u unwritten", written, j);
> }
>
> -static int sha1_sort(const void *_a, const void *_b)
> -{
> - const struct object_entry *a = *(struct object_entry **)_a;
> - const struct object_entry *b = *(struct object_entry **)_b;
> - return hashcmp(a->sha1, b->sha1);
> -}
> -
> -static uint32_t index_default_version = 1;
> -static uint32_t index_off32_limit = 0x7fffffff;
> -
> -static void write_index_file(off_t last_obj_offset, unsigned char *sha1)
> -{
> - struct sha1file *f;
> - struct object_entry **sorted_by_sha, **list, **last;
> - uint32_t array[256];
> - uint32_t i, index_version;
> - SHA_CTX ctx;
> -
> - int fd = open_object_dir_tmp("tmp_idx_XXXXXX");
> - if (fd < 0)
> - die("unable to create %s: %s\n", tmpname, strerror(errno));
> - idx_tmp_name = xstrdup(tmpname);
> - f = sha1fd(fd, idx_tmp_name);
> -
> - if (nr_written) {
> - sorted_by_sha = written_list;
> - qsort(sorted_by_sha, nr_written, sizeof(*sorted_by_sha), sha1_sort);
> - list = sorted_by_sha;
> - last = sorted_by_sha + nr_written;
> - } else
> - sorted_by_sha = list = last = NULL;
> -
> - /* if last object's offset is >= 2^31 we should use index V2 */
> - index_version = (last_obj_offset >> 31) ? 2 : index_default_version;
> -
> - /* index versions 2 and above need a header */
> - if (index_version >= 2) {
> - struct pack_idx_header hdr;
> - hdr.idx_signature = htonl(PACK_IDX_SIGNATURE);
> - hdr.idx_version = htonl(index_version);
> - sha1write(f, &hdr, sizeof(hdr));
> - }
> -
> - /*
> - * Write the first-level table (the list is sorted,
> - * but we use a 256-entry lookup to be able to avoid
> - * having to do eight extra binary search iterations).
> - */
> - for (i = 0; i < 256; i++) {
> - struct object_entry **next = list;
> - while (next < last) {
> - struct object_entry *entry = *next;
> - if (entry->sha1[0] != i)
> - break;
> - next++;
> - }
> - array[i] = htonl(next - sorted_by_sha);
> - list = next;
> - }
> - sha1write(f, array, 256 * 4);
> -
> - /* Compute the SHA1 hash of sorted object names. */
> - SHA1_Init(&ctx);
> -
> - /* Write the actual SHA1 entries. */
> - list = sorted_by_sha;
> - for (i = 0; i < nr_written; i++) {
> - struct object_entry *entry = *list++;
> - if (index_version < 2) {
> - uint32_t offset = htonl(entry->offset);
> - sha1write(f, &offset, 4);
> - }
> - sha1write(f, entry->sha1, 20);
> - SHA1_Update(&ctx, entry->sha1, 20);
> - }
> -
> - if (index_version >= 2) {
> - unsigned int nr_large_offset = 0;
> -
> - /* write the crc32 table */
> - list = sorted_by_sha;
> - for (i = 0; i < nr_written; i++) {
> - struct object_entry *entry = *list++;
> - uint32_t crc32_val = htonl(entry->crc32);
> - sha1write(f, &crc32_val, 4);
> - }
> -
> - /* write the 32-bit offset table */
> - list = sorted_by_sha;
> - for (i = 0; i < nr_written; i++) {
> - struct object_entry *entry = *list++;
> - uint32_t offset = (entry->offset <= index_off32_limit) ?
> - entry->offset : (0x80000000 | nr_large_offset++);
> - offset = htonl(offset);
> - sha1write(f, &offset, 4);
> - }
> -
> - /* write the large offset table */
> - list = sorted_by_sha;
> - while (nr_large_offset) {
> - struct object_entry *entry = *list++;
> - uint64_t offset = entry->offset;
> - if (offset > index_off32_limit) {
> - uint32_t split[2];
> - split[0] = htonl(offset >> 32);
> - split[1] = htonl(offset & 0xffffffff);
> - sha1write(f, split, 8);
> - nr_large_offset--;
> - }
> - }
> - }
> -
> - sha1write(f, pack_file_sha1, 20);
> - sha1close(f, NULL, 1);
> - SHA1_Final(sha1, &ctx);
> -}
> -
> static int locate_object_entry_hash(const unsigned char *sha1)
> {
> int i;
> @@ -817,7 +699,7 @@ static int locate_object_entry_hash(const unsigned char *sha1)
> memcpy(&ui, sha1, sizeof(unsigned int));
> i = ui % object_ix_hashsz;
> while (0 < object_ix[i]) {
> - if (!hashcmp(sha1, objects[object_ix[i] - 1].sha1))
> + if (!hashcmp(sha1, objects[object_ix[i] - 1].idx.sha1))
> return i;
> if (++i == object_ix_hashsz)
> i = 0;
> @@ -849,7 +731,7 @@ static void rehash_objects(void)
> object_ix = xrealloc(object_ix, sizeof(int) * object_ix_hashsz);
> memset(object_ix, 0, sizeof(int) * object_ix_hashsz);
> for (i = 0, oe = objects; i < nr_objects; i++, oe++) {
> - int ix = locate_object_entry_hash(oe->sha1);
> + int ix = locate_object_entry_hash(oe->idx.sha1);
> if (0 <= ix)
> continue;
> ix = -1 - ix;
> @@ -943,7 +825,7 @@ static int add_object_entry(const unsigned char *sha1, enum object_type type,
>
> entry = objects + nr_objects++;
> memset(entry, 0, sizeof(*entry));
> - hashcpy(entry->sha1, sha1);
> + hashcpy(entry->idx.sha1, sha1);
> entry->hash = hash;
> if (type)
> entry->type = type;
> @@ -1263,13 +1145,13 @@ static void check_object(struct object_entry *entry)
> ofs += 1;
> if (!ofs || MSB(ofs, 7))
> die("delta base offset overflow in pack for %s",
> - sha1_to_hex(entry->sha1));
> + sha1_to_hex(entry->idx.sha1));
> c = buf[used_0++];
> ofs = (ofs << 7) + (c & 127);
> }
> if (ofs >= entry->in_pack_offset)
> die("delta base offset out of bound for %s",
> - sha1_to_hex(entry->sha1));
> + sha1_to_hex(entry->idx.sha1));
> ofs = entry->in_pack_offset - ofs;
> if (!no_reuse_delta && !entry->preferred_base)
> base_ref = find_packed_object_name(p, ofs);
> @@ -1316,10 +1198,10 @@ static void check_object(struct object_entry *entry)
> unuse_pack(&w_curs);
> }
>
> - entry->type = sha1_object_info(entry->sha1, &entry->size);
> + entry->type = sha1_object_info(entry->idx.sha1, &entry->size);
> if (entry->type < 0)
> die("unable to get type of object %s",
> - sha1_to_hex(entry->sha1));
> + sha1_to_hex(entry->idx.sha1));
> }
>
> static int pack_offset_sort(const void *_a, const void *_b)
> @@ -1329,7 +1211,7 @@ static int pack_offset_sort(const void *_a, const void *_b)
>
> /* avoid filesystem trashing with loose objects */
> if (!a->in_pack && !b->in_pack)
> - return hashcmp(a->sha1, b->sha1);
> + return hashcmp(a->idx.sha1, b->idx.sha1);
>
> if (a->in_pack < b->in_pack)
> return -1;
> @@ -1441,16 +1323,16 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
>
> /* Load data if not already done */
> if (!trg->data) {
> - trg->data = read_sha1_file(trg_entry->sha1, &type, &sz);
> + trg->data = read_sha1_file(trg_entry->idx.sha1, &type, &sz);
> if (sz != trg_size)
> die("object %s inconsistent object length (%lu vs %lu)",
> - sha1_to_hex(trg_entry->sha1), sz, trg_size);
> + sha1_to_hex(trg_entry->idx.sha1), sz, trg_size);
> }
> if (!src->data) {
> - src->data = read_sha1_file(src_entry->sha1, &type, &sz);
> + src->data = read_sha1_file(src_entry->idx.sha1, &type, &sz);
> if (sz != src_size)
> die("object %s inconsistent object length (%lu vs %lu)",
> - sha1_to_hex(src_entry->sha1), sz, src_size);
> + sha1_to_hex(src_entry->idx.sha1), sz, src_size);
> }
> if (!src->index) {
> src->index = create_delta_index(src->data, src_size);
> @@ -1825,12 +1707,12 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
> }
> if (!prefixcmp(arg, "--index-version=")) {
> char *c;
> - index_default_version = strtoul(arg + 16, &c, 10);
> - if (index_default_version > 2)
> + pack_idx_default_version = strtoul(arg + 16, &c, 10);
> + if (pack_idx_default_version > 2)
> die("bad %s", arg);
> if (*c == ',')
> - index_off32_limit = strtoul(c+1, &c, 0);
> - if (*c || index_off32_limit & 0x80000000)
> + pack_idx_off32_limit = strtoul(c+1, &c, 0);
> + if (*c || pack_idx_off32_limit & 0x80000000)
> die("bad %s", arg);
> continue;
> }
> diff --git a/index-pack.c b/index-pack.c
> index 58c4a9c..82c8da3 100644
> --- a/index-pack.c
> +++ b/index-pack.c
> @@ -13,13 +13,11 @@ static const char index_pack_usage[] =
>
> struct object_entry
> {
> - off_t offset;
> + struct pack_idx_entry idx;
> unsigned long size;
> unsigned int hdr_size;
> - uint32_t crc32;
> enum object_type type;
> enum object_type real_type;
> - unsigned char sha1[20];
> };
>
> union delta_base {
> @@ -197,7 +195,7 @@ static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_
> unsigned shift;
> void *data;
>
> - obj->offset = consumed_bytes;
> + obj->idx.offset = consumed_bytes;
> input_crc32 = crc32(0, Z_NULL, 0);
>
> p = fill(1);
> @@ -229,15 +227,15 @@ static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_
> while (c & 128) {
> base_offset += 1;
> if (!base_offset || MSB(base_offset, 7))
> - bad_object(obj->offset, "offset value overflow for delta base object");
> + bad_object(obj->idx.offset, "offset value overflow for delta base object");
> p = fill(1);
> c = *p;
> use(1);
> base_offset = (base_offset << 7) + (c & 127);
> }
> - delta_base->offset = obj->offset - base_offset;
> - if (delta_base->offset >= obj->offset)
> - bad_object(obj->offset, "delta base offset is out of bound");
> + delta_base->offset = obj->idx.offset - base_offset;
> + if (delta_base->offset >= obj->idx.offset)
> + bad_object(obj->idx.offset, "delta base offset is out of bound");
> break;
> case OBJ_COMMIT:
> case OBJ_TREE:
> @@ -245,19 +243,19 @@ static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_
> case OBJ_TAG:
> break;
> default:
> - bad_object(obj->offset, "unknown object type %d", obj->type);
> + bad_object(obj->idx.offset, "unknown object type %d", obj->type);
> }
> - obj->hdr_size = consumed_bytes - obj->offset;
> + obj->hdr_size = consumed_bytes - obj->idx.offset;
>
> - data = unpack_entry_data(obj->offset, obj->size);
> - obj->crc32 = input_crc32;
> + data = unpack_entry_data(obj->idx.offset, obj->size);
> + obj->idx.crc32 = input_crc32;
> return data;
> }
>
> static void *get_data_from_pack(struct object_entry *obj)
> {
> - unsigned long from = obj[0].offset + obj[0].hdr_size;
> - unsigned long len = obj[1].offset - from;
> + unsigned long from = obj[0].idx.offset + obj[0].hdr_size;
> + unsigned long len = obj[1].idx.offset - from;
> unsigned long rdy = 0;
> unsigned char *src, *data;
> z_stream stream;
> @@ -360,11 +358,11 @@ static void resolve_delta(struct object_entry *delta_obj, void *base_data,
> &result_size);
> free(delta_data);
> if (!result)
> - bad_object(delta_obj->offset, "failed to apply delta");
> - sha1_object(result, result_size, type, delta_obj->sha1);
> + bad_object(delta_obj->idx.offset, "failed to apply delta");
> + sha1_object(result, result_size, type, delta_obj->idx.sha1);
> nr_resolved_deltas++;
>
> - hashcpy(delta_base.sha1, delta_obj->sha1);
> + hashcpy(delta_base.sha1, delta_obj->idx.sha1);
> if (!find_delta_children(&delta_base, &first, &last)) {
> for (j = first; j <= last; j++) {
> struct object_entry *child = objects + deltas[j].obj_no;
> @@ -374,7 +372,7 @@ static void resolve_delta(struct object_entry *delta_obj, void *base_data,
> }
>
> memset(&delta_base, 0, sizeof(delta_base));
> - delta_base.offset = delta_obj->offset;
> + delta_base.offset = delta_obj->idx.offset;
> if (!find_delta_children(&delta_base, &first, &last)) {
> for (j = first; j <= last; j++) {
> struct object_entry *child = objects + deltas[j].obj_no;
> @@ -418,12 +416,12 @@ static void parse_pack_objects(unsigned char *sha1)
> delta->obj_no = i;
> delta++;
> } else
> - sha1_object(data, obj->size, obj->type, obj->sha1);
> + sha1_object(data, obj->size, obj->type, obj->idx.sha1);
> free(data);
> if (verbose)
> display_progress(&progress, i+1);
> }
> - objects[i].offset = consumed_bytes;
> + objects[i].idx.offset = consumed_bytes;
> if (verbose)
> stop_progress(&progress);
>
> @@ -465,10 +463,10 @@ static void parse_pack_objects(unsigned char *sha1)
>
> if (obj->type == OBJ_REF_DELTA || obj->type == OBJ_OFS_DELTA)
> continue;
> - hashcpy(base.sha1, obj->sha1);
> + hashcpy(base.sha1, obj->idx.sha1);
> ref = !find_delta_children(&base, &ref_first, &ref_last);
> memset(&base, 0, sizeof(base));
> - base.offset = obj->offset;
> + base.offset = obj->idx.offset;
> ofs = !find_delta_children(&base, &ofs_first, &ofs_last);
> if (!ref && !ofs)
> continue;
> @@ -535,11 +533,11 @@ static void append_obj_to_pack(const unsigned char *sha1, void *buf,
> }
> header[n++] = c;
> write_or_die(output_fd, header, n);
> - obj[0].crc32 = crc32(0, Z_NULL, 0);
> - obj[0].crc32 = crc32(obj[0].crc32, header, n);
> - obj[1].offset = obj[0].offset + n;
> - obj[1].offset += write_compressed(output_fd, buf, size, &obj[0].crc32);
> - hashcpy(obj->sha1, sha1);
> + obj[0].idx.crc32 = crc32(0, Z_NULL, 0);
> + obj[0].idx.crc32 = crc32(obj[0].idx.crc32, header, n);
> + obj[1].idx.offset = obj[0].idx.offset + n;
> + obj[1].idx.offset += write_compressed(output_fd, buf, size, &obj[0].idx.crc32);
> + hashcpy(obj->idx.sha1, sha1);
> }
>
> static int delta_pos_compare(const void *_a, const void *_b)
> @@ -602,145 +600,6 @@ static void fix_unresolved_deltas(int nr_unresolved)
> free(sorted_by_pos);
> }
>
> -static uint32_t index_default_version = 1;
> -static uint32_t index_off32_limit = 0x7fffffff;
> -
> -static int sha1_compare(const void *_a, const void *_b)
> -{
> - struct object_entry *a = *(struct object_entry **)_a;
> - struct object_entry *b = *(struct object_entry **)_b;
> - return hashcmp(a->sha1, b->sha1);
> -}
> -
> -/*
> - * On entry *sha1 contains the pack content SHA1 hash, on exit it is
> - * the SHA1 hash of sorted object names.
> - */
> -static const char *write_index_file(const char *index_name, unsigned char *sha1)
> -{
> - struct sha1file *f;
> - struct object_entry **sorted_by_sha, **list, **last;
> - uint32_t array[256];
> - int i, fd;
> - SHA_CTX ctx;
> - uint32_t index_version;
> -
> - if (nr_objects) {
> - sorted_by_sha =
> - xcalloc(nr_objects, sizeof(struct object_entry *));
> - list = sorted_by_sha;
> - last = sorted_by_sha + nr_objects;
> - for (i = 0; i < nr_objects; ++i)
> - sorted_by_sha[i] = &objects[i];
> - qsort(sorted_by_sha, nr_objects, sizeof(sorted_by_sha[0]),
> - sha1_compare);
> - }
> - else
> - sorted_by_sha = list = last = NULL;
> -
> - if (!index_name) {
> - static char tmpfile[PATH_MAX];
> - snprintf(tmpfile, sizeof(tmpfile),
> - "%s/tmp_idx_XXXXXX", get_object_directory());
> - fd = mkstemp(tmpfile);
> - index_name = xstrdup(tmpfile);
> - } else {
> - unlink(index_name);
> - fd = open(index_name, O_CREAT|O_EXCL|O_WRONLY, 0600);
> - }
> - if (fd < 0)
> - die("unable to create %s: %s", index_name, strerror(errno));
> - f = sha1fd(fd, index_name);
> -
> - /* if last object's offset is >= 2^31 we should use index V2 */
> - index_version = (objects[nr_objects-1].offset >> 31) ? 2 : index_default_version;
> -
> - /* index versions 2 and above need a header */
> - if (index_version >= 2) {
> - struct pack_idx_header hdr;
> - hdr.idx_signature = htonl(PACK_IDX_SIGNATURE);
> - hdr.idx_version = htonl(index_version);
> - sha1write(f, &hdr, sizeof(hdr));
> - }
> -
> - /*
> - * Write the first-level table (the list is sorted,
> - * but we use a 256-entry lookup to be able to avoid
> - * having to do eight extra binary search iterations).
> - */
> - for (i = 0; i < 256; i++) {
> - struct object_entry **next = list;
> - while (next < last) {
> - struct object_entry *obj = *next;
> - if (obj->sha1[0] != i)
> - break;
> - next++;
> - }
> - array[i] = htonl(next - sorted_by_sha);
> - list = next;
> - }
> - sha1write(f, array, 256 * 4);
> -
> - /* compute the SHA1 hash of sorted object names. */
> - SHA1_Init(&ctx);
> -
> - /*
> - * Write the actual SHA1 entries..
> - */
> - list = sorted_by_sha;
> - for (i = 0; i < nr_objects; i++) {
> - struct object_entry *obj = *list++;
> - if (index_version < 2) {
> - uint32_t offset = htonl(obj->offset);
> - sha1write(f, &offset, 4);
> - }
> - sha1write(f, obj->sha1, 20);
> - SHA1_Update(&ctx, obj->sha1, 20);
> - }
> -
> - if (index_version >= 2) {
> - unsigned int nr_large_offset = 0;
> -
> - /* write the crc32 table */
> - list = sorted_by_sha;
> - for (i = 0; i < nr_objects; i++) {
> - struct object_entry *obj = *list++;
> - uint32_t crc32_val = htonl(obj->crc32);
> - sha1write(f, &crc32_val, 4);
> - }
> -
> - /* write the 32-bit offset table */
> - list = sorted_by_sha;
> - for (i = 0; i < nr_objects; i++) {
> - struct object_entry *obj = *list++;
> - uint32_t offset = (obj->offset <= index_off32_limit) ?
> - obj->offset : (0x80000000 | nr_large_offset++);
> - offset = htonl(offset);
> - sha1write(f, &offset, 4);
> - }
> -
> - /* write the large offset table */
> - list = sorted_by_sha;
> - while (nr_large_offset) {
> - struct object_entry *obj = *list++;
> - uint64_t offset = obj->offset;
> - if (offset > index_off32_limit) {
> - uint32_t split[2];
> - split[0] = htonl(offset >> 32);
> - split[1] = htonl(offset & 0xffffffff);
> - sha1write(f, split, 8);
> - nr_large_offset--;
> - }
> - }
> - }
> -
> - sha1write(f, sha1, 20);
> - sha1close(f, NULL, 1);
> - free(sorted_by_sha);
> - SHA1_Final(sha1, &ctx);
> - return index_name;
> -}
> -
> static void final(const char *final_pack_name, const char *curr_pack_name,
> const char *final_index_name, const char *curr_index_name,
> const char *keep_name, const char *keep_msg,
> @@ -830,6 +689,7 @@ int main(int argc, char **argv)
> const char *curr_index, *index_name = NULL;
> const char *keep_name = NULL, *keep_msg = NULL;
> char *index_name_buf = NULL, *keep_name_buf = NULL;
> + struct pack_idx_entry **idx_objects;
> unsigned char sha1[20];
>
> for (i = 1; i < argc; i++) {
> @@ -865,12 +725,12 @@ int main(int argc, char **argv)
> index_name = argv[++i];
> } else if (!prefixcmp(arg, "--index-version=")) {
> char *c;
> - index_default_version = strtoul(arg + 16, &c, 10);
> - if (index_default_version > 2)
> + pack_idx_default_version = strtoul(arg + 16, &c, 10);
> + if (pack_idx_default_version > 2)
> die("bad %s", arg);
> if (*c == ',')
> - index_off32_limit = strtoul(c+1, &c, 0);
> - if (*c || index_off32_limit & 0x80000000)
> + pack_idx_off32_limit = strtoul(c+1, &c, 0);
> + if (*c || pack_idx_off32_limit & 0x80000000)
> die("bad %s", arg);
> } else
> usage(index_pack_usage);
> @@ -940,7 +800,13 @@ int main(int argc, char **argv)
> nr_deltas - nr_resolved_deltas);
> }
> free(deltas);
> - curr_index = write_index_file(index_name, sha1);
> +
> + idx_objects = xmalloc((nr_objects) * sizeof(struct pack_idx_entry *));
> + for (i = 0; i < nr_objects; i++)
> + idx_objects[i] = &objects[i].idx;
> + curr_index = write_idx_file(index_name, idx_objects, nr_objects, sha1);
> + free(idx_objects);
> +
> final(pack_name, curr_pack,
> index_name, curr_index,
> keep_name, keep_msg,
> diff --git a/pack-write.c b/pack-write.c
> index ae2e481..1cf5f7c 100644
> --- a/pack-write.c
> +++ b/pack-write.c
> @@ -1,5 +1,147 @@
> #include "cache.h"
> #include "pack.h"
> +#include "csum-file.h"
> +
> +uint32_t pack_idx_default_version = 1;
> +uint32_t pack_idx_off32_limit = 0x7fffffff;
> +
> +static int sha1_compare(const void *_a, const void *_b)
> +{
> + struct pack_idx_entry *a = *(struct pack_idx_entry **)_a;
> + struct pack_idx_entry *b = *(struct pack_idx_entry **)_b;
> + return hashcmp(a->sha1, b->sha1);
> +}
> +
> +/*
> + * On entry *sha1 contains the pack content SHA1 hash, on exit it is
> + * the SHA1 hash of sorted object names. The objects array passed in
> + * will be sorted by SHA1 on exit.
> + */
> +const char *write_idx_file(const char *index_name, struct pack_idx_entry **objects, int nr_objects, unsigned char *sha1)
> +{
> + struct sha1file *f;
> + struct pack_idx_entry **sorted_by_sha, **list, **last;
> + off_t last_obj_offset = 0;
> + uint32_t array[256];
> + int i, fd;
> + SHA_CTX ctx;
> + uint32_t index_version;
> +
> + if (nr_objects) {
> + sorted_by_sha = objects;
> + list = sorted_by_sha;
> + last = sorted_by_sha + nr_objects;
> + for (i = 0; i < nr_objects; ++i) {
> + if (objects[i]->offset > last_obj_offset)
> + last_obj_offset = objects[i]->offset;
> + }
> + qsort(sorted_by_sha, nr_objects, sizeof(sorted_by_sha[0]),
> + sha1_compare);
> + }
> + else
> + sorted_by_sha = list = last = NULL;
> +
> + if (!index_name) {
> + static char tmpfile[PATH_MAX];
> + snprintf(tmpfile, sizeof(tmpfile),
> + "%s/tmp_idx_XXXXXX", get_object_directory());
> + fd = mkstemp(tmpfile);
> + index_name = xstrdup(tmpfile);
> + } else {
> + unlink(index_name);
> + fd = open(index_name, O_CREAT|O_EXCL|O_WRONLY, 0600);
> + }
> + if (fd < 0)
> + die("unable to create %s: %s", index_name, strerror(errno));
> + f = sha1fd(fd, index_name);
> +
> + /* if last object's offset is >= 2^31 we should use index V2 */
> + index_version = (last_obj_offset >> 31) ? 2 : pack_idx_default_version;
> +
> + /* index versions 2 and above need a header */
> + if (index_version >= 2) {
> + struct pack_idx_header hdr;
> + hdr.idx_signature = htonl(PACK_IDX_SIGNATURE);
> + hdr.idx_version = htonl(index_version);
> + sha1write(f, &hdr, sizeof(hdr));
> + }
> +
> + /*
> + * Write the first-level table (the list is sorted,
> + * but we use a 256-entry lookup to be able to avoid
> + * having to do eight extra binary search iterations).
> + */
> + for (i = 0; i < 256; i++) {
> + struct pack_idx_entry **next = list;
> + while (next < last) {
> + struct pack_idx_entry *obj = *next;
> + if (obj->sha1[0] != i)
> + break;
> + next++;
> + }
> + array[i] = htonl(next - sorted_by_sha);
> + list = next;
> + }
> + sha1write(f, array, 256 * 4);
> +
> + /* compute the SHA1 hash of sorted object names. */
> + SHA1_Init(&ctx);
> +
> + /*
> + * Write the actual SHA1 entries..
> + */
> + list = sorted_by_sha;
> + for (i = 0; i < nr_objects; i++) {
> + struct pack_idx_entry *obj = *list++;
> + if (index_version < 2) {
> + uint32_t offset = htonl(obj->offset);
> + sha1write(f, &offset, 4);
> + }
> + sha1write(f, obj->sha1, 20);
> + SHA1_Update(&ctx, obj->sha1, 20);
> + }
> +
> + if (index_version >= 2) {
> + unsigned int nr_large_offset = 0;
> +
> + /* write the crc32 table */
> + list = sorted_by_sha;
> + for (i = 0; i < nr_objects; i++) {
> + struct pack_idx_entry *obj = *list++;
> + uint32_t crc32_val = htonl(obj->crc32);
> + sha1write(f, &crc32_val, 4);
> + }
> +
> + /* write the 32-bit offset table */
> + list = sorted_by_sha;
> + for (i = 0; i < nr_objects; i++) {
> + struct pack_idx_entry *obj = *list++;
> + uint32_t offset = (obj->offset <= pack_idx_off32_limit) ?
> + obj->offset : (0x80000000 | nr_large_offset++);
> + offset = htonl(offset);
> + sha1write(f, &offset, 4);
> + }
> +
> + /* write the large offset table */
> + list = sorted_by_sha;
> + while (nr_large_offset) {
> + struct pack_idx_entry *obj = *list++;
> + uint64_t offset = obj->offset;
> + if (offset > pack_idx_off32_limit) {
> + uint32_t split[2];
> + split[0] = htonl(offset >> 32);
> + split[1] = htonl(offset & 0xffffffff);
> + sha1write(f, split, 8);
> + nr_large_offset--;
> + }
> + }
> + }
> +
> + sha1write(f, sha1, 20);
> + sha1close(f, NULL, 1);
> + SHA1_Final(sha1, &ctx);
> + return index_name;
> +}
>
> void fixup_pack_header_footer(int pack_fd,
> unsigned char *pack_file_sha1,
> diff --git a/pack.h b/pack.h
> index d667fb8..f357c9f 100644
> --- a/pack.h
> +++ b/pack.h
> @@ -34,6 +34,10 @@ struct pack_header {
> */
> #define PACK_IDX_SIGNATURE 0xff744f63 /* "\377tOc" */
>
> +/* These may be overridden by command-line parameters */
> +extern uint32_t pack_idx_default_version;
> +extern uint32_t pack_idx_off32_limit;
> +
> /*
> * Packed object index header
> */
> @@ -42,6 +46,16 @@ struct pack_idx_header {
> uint32_t idx_version;
> };
>
> +/*
> + * Common part of object structure used for write_idx_file
> + */
> +struct pack_idx_entry {
> + unsigned char sha1[20];
> + uint32_t crc32;
> + off_t offset;
> +};
> +
> +extern const char *write_idx_file(const char *index_name, struct pack_idx_entry **objects, int nr_objects, unsigned char *sha1);
>
> extern int verify_pack(struct packed_git *, int);
> extern void fixup_pack_header_footer(int, unsigned char *, const char *, uint32_t);
> --
> 1.5.1
>
> -
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
Nicolas
^ permalink raw reply
* [PATCH] Show html help with git-help --html
From: Nguyễn Thái Ngọc Duy @ 2007-06-02 1:53 UTC (permalink / raw)
To: git
This patch was inspired by ClearCase command 'ct man' which
opens an html help file on Windows. I at first attempted to
implement it for MinGW port only but found it so useful that I
wanted to have it even in Linux.
A new option '--help' is added to git. When git-help is called
with --help, it will try to open html files located at
$(sharedir)/html using xdg-open. HTML files are not installed
by default so users have to install them manually or have their
distributors to do that.
There are two new config options introduced in this patch. The
first is core.help. It has one of three values: html, auto or
man. 'html' has the same effect as git-help --html. 'auto'
will in addition fall back to man pages if possible. 'man'
is 'I hate html, give me my man pages'. The second option is
core.htmlprogram, used to specify the program you want to
open html files instead of xdg-open.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
Documentation/config.txt | 12 ++++++++++
Documentation/git.txt | 5 +++-
Makefile | 5 +++-
cache.h | 2 +
config.c | 17 ++++++++++++++
environment.c | 2 +
git.c | 2 +-
help.c | 53 ++++++++++++++++++++++++++++++++++++++++++++-
8 files changed, 93 insertions(+), 5 deletions(-)
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 3d8f03d..2ec8545 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -261,6 +261,18 @@ core.excludeFile::
'.git/info/exclude', git looks into this file for patterns
of files which are not meant to be tracked.
+core.help::
+ If 'html', it is equivalent to 'git-help' with option --html.
+ If 'auto', it tries to open html files first. If that attempt fails
+ (the html program does not exist or the program return non-zero
+ value), then it will fall back to man pages. If 'man', always use
+ man pages as usual.
+
+core.htmlprogram::
+ Specify the program used to open html help files when 'git-help'
+ is called with option --html or core.help is other than 'man'.
+ By default, xdg-open will be used.
+
alias.*::
Command aliases for the gitlink:git[1] command wrapper - e.g.
after defining "alias.last = cat-file commit HEAD", the invocation
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 98860af..589ebea 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -10,7 +10,7 @@ SYNOPSIS
--------
[verse]
'git' [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate]
- [--bare] [--git-dir=GIT_DIR] [--help] COMMAND [ARGS]
+ [--bare] [--git-dir=GIT_DIR] [--help [--html]] COMMAND [ARGS]
DESCRIPTION
-----------
@@ -87,6 +87,9 @@ OPTIONS
commands. If a git command is named this option will bring up
the man-page for that command. If the option '--all' or '-a' is
given then all available commands are printed.
+ If option '--html' is given, try opening html files instead of
+ using 'man'. The default program to open html files is xdg-open.
+ See 'git-config' to know how to change html program.
--exec-path::
Path to wherever your core git programs are installed.
diff --git a/Makefile b/Makefile
index cac0a4a..43e0d15 100644
--- a/Makefile
+++ b/Makefile
@@ -145,6 +145,7 @@ prefix = $(HOME)
bindir = $(prefix)/bin
gitexecdir = $(bindir)
sharedir = $(prefix)/share/
+htmldir = $(sharedir)/html/
template_dir = $(sharedir)/git-core/templates/
ifeq ($(prefix),/usr)
sysconfdir = /etc
@@ -693,6 +694,7 @@ ETC_GITCONFIG_SQ = $(subst ','\'',$(ETC_GITCONFIG))
DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
bindir_SQ = $(subst ','\'',$(bindir))
gitexecdir_SQ = $(subst ','\'',$(gitexecdir))
+htmldir_SQ = $(subst ','\'',$(htmldir))
template_dir_SQ = $(subst ','\'',$(template_dir))
prefix_SQ = $(subst ','\'',$(prefix))
@@ -741,7 +743,8 @@ git$X: git.c common-cmds.h $(BUILTIN_OBJS) $(GITLIBS) GIT-CFLAGS
$(ALL_CFLAGS) -o $@ $(filter %.c,$^) \
$(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)
-help.o: common-cmds.h
+help.o: help.c common-cmds.h
+ $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DHTML_DIR='"$(htmldir_SQ)"' $<
git-merge-subtree$X: git-merge-recursive$X
$(QUIET_BUILT_IN)rm -f $@ && ln git-merge-recursive$X $@
diff --git a/cache.h b/cache.h
index 0da7070..7a438ed 100644
--- a/cache.h
+++ b/cache.h
@@ -288,6 +288,8 @@ extern size_t packed_git_window_size;
extern size_t packed_git_limit;
extern size_t delta_base_cache_limit;
extern int auto_crlf;
+extern int show_html_help;
+extern const char *html_help_program;
#define GIT_REPO_VERSION 0
extern int repository_format_version;
diff --git a/config.c b/config.c
index 0614c2b..d216ab7 100644
--- a/config.c
+++ b/config.c
@@ -382,6 +382,23 @@ int git_default_config(const char *var, const char *value)
return 0;
}
+ if (!strcmp(var, "core.help")) {
+ if (!strcmp(value, "auto"))
+ show_html_help = 2;
+ else if (!strcmp(value, "html"))
+ show_html_help = 1;
+ else if (!strcmp(value, "man"))
+ show_html_help = 0;
+ else
+ return 1;
+ return 0;
+ }
+
+ if (!strcmp(var, "core.htmlprogram")) {
+ html_help_program = xstrdup(value);
+ return 0;
+ }
+
/* Add other config variables here and to Documentation/config.txt. */
return 0;
}
diff --git a/environment.c b/environment.c
index 9d3e5eb..e905972 100644
--- a/environment.c
+++ b/environment.c
@@ -32,6 +32,8 @@ size_t delta_base_cache_limit = 16 * 1024 * 1024;
int pager_in_use;
int pager_use_color = 1;
int auto_crlf = 0; /* 1: both ways, -1: only when adding git objects */
+int show_html_help = 0;
+const char *html_help_program = NULL;
static const char *git_dir;
static char *git_object_dir, *git_index_file, *git_refs_dir, *git_graft_file;
diff --git a/git.c b/git.c
index 29b55a1..c3c0fe8 100644
--- a/git.c
+++ b/git.c
@@ -4,7 +4,7 @@
#include "quote.h"
const char git_usage_string[] =
- "git [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate] [--bare] [--git-dir=GIT_DIR] [--help] COMMAND [ARGS]";
+ "git [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate] [--bare] [--git-dir=GIT_DIR] [--help [--html]] COMMAND [ARGS]";
static void prepend_to_path(const char *dir, int len)
{
diff --git a/help.c b/help.c
index 6a9af4d..e3e705b 100644
--- a/help.c
+++ b/help.c
@@ -9,6 +9,10 @@
#include "common-cmds.h"
#include <sys/ioctl.h>
+#ifndef HTML_DIR
+#define HTML_DIR "/usr/share/html/"
+#endif
+
/* most GUI terminals set COLUMNS (although some don't export it) */
static int term_columns(void)
{
@@ -183,6 +187,36 @@ static void show_man_page(const char *git_cmd)
execlp("man", "man", page, NULL);
}
+static void show_html_page(const char *git_cmd)
+{
+ const char *html_dir;
+ int i,len,ret;
+ char *p;
+
+ html_dir = HTML_DIR;
+ if (!html_help_program)
+ html_help_program = "xdg-open";
+
+ /* html_help_program space html_dir git- git_cmd .html */
+ len = strlen(html_help_program) + 1 + strlen(html_dir) + 4 + strlen(git_cmd) + 5;
+ p = xmalloc(len + 1);
+
+ strcpy(p, html_help_program);
+ strcat(p," ");
+ strcat(p,html_dir);
+ if (prefixcmp(git_cmd, "git"))
+ strcat(p,"git-");
+ strcat(p,git_cmd);
+ strcat(p,".html");
+
+ ret = system(p);
+
+ /* fallback to man pages */
+ if (show_html_help > 1 && (ret == -1 || ret > 0))
+ show_man_page(git_cmd);
+ exit(0);
+}
+
void help_unknown_cmd(const char *cmd)
{
printf("git: '%s' is not a git-command\n\n", cmd);
@@ -214,8 +248,23 @@ int cmd_help(int argc, const char **argv, const char *prefix)
exit(1);
}
- else
- show_man_page(help_cmd);
+ else {
+ git_config(git_default_config);
+ if (!strcmp(help_cmd, "--html")) {
+ help_cmd = argc > 2 ? argv[2] : NULL;
+ if (!help_cmd) {
+ printf("usage: %s\n\n", git_usage_string);
+ list_common_cmds_help();
+ exit(1);
+ }
+ show_html_help = 1;
+ }
+
+ if (show_html_help)
+ show_html_page(help_cmd);
+ else
+ show_man_page(help_cmd);
+ }
return 0;
}
--
1.5.2
^ permalink raw reply related
* [PATCH] Unify write_index_file functions
From: Geert Bosch @ 2007-06-01 19:18 UTC (permalink / raw)
To: Nicolas Pitre; +Cc: Git List, Junio C Hamano
In-Reply-To: <alpine.LFD.0.99.0706012126260.12885@xanadu.home>
This patch unifies the write_index_file functions in
builtin-pack-objects.c and index-pack.c. As the name
"index" is overloaded in git, move in the direction of
using "idx" and "pack idx" when refering to the pack index.
There should be no change in functionality.
Signed-off-by: Geert Bosch <bosch@gnat.com>
---
builtin-pack-objects.c | 218 +++++++++++-------------------------------------
index-pack.c | 208 ++++++++-------------------------------------
pack-write.c | 142 +++++++++++++++++++++++++++++++
pack.h | 14 +++
4 files changed, 243 insertions(+), 339 deletions(-)
Now with corrected commit message.
-Geert
diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c
index e52332d..a247238 100644
--- a/builtin-pack-objects.c
+++ b/builtin-pack-objects.c
@@ -23,10 +23,9 @@ git-pack-objects [{ -q | --progress | --all-progress }] [--max-pack-size=N] \n\
[--stdout | base-name] [<ref-list | <object-list]";
struct object_entry {
- unsigned char sha1[20];
- uint32_t crc32; /* crc of raw pack data for this object */
- off_t offset; /* offset into the final pack file */
+ struct pack_idx_entry idx;
unsigned long size; /* uncompressed size */
+
unsigned int hash; /* name hint hash */
unsigned int depth; /* delta depth */
struct packed_git *in_pack; /* already in pack */
@@ -65,7 +64,6 @@ static int allow_ofs_delta;
static const char *pack_tmp_name, *idx_tmp_name;
static char tmpname[PATH_MAX];
static const char *base_name;
-static unsigned char pack_file_sha1[20];
static int progress = 1;
static int window = 10;
static uint32_t pack_size_limit;
@@ -241,11 +239,11 @@ static void *delta_against(void *buf, unsigned long size, struct object_entry *e
{
unsigned long othersize, delta_size;
enum object_type type;
- void *otherbuf = read_sha1_file(entry->delta->sha1, &type, &othersize);
+ void *otherbuf = read_sha1_file(entry->delta->idx.sha1, &type, &othersize);
void *delta_buf;
if (!otherbuf)
- die("unable to read %s", sha1_to_hex(entry->delta->sha1));
+ die("unable to read %s", sha1_to_hex(entry->delta->idx.sha1));
delta_buf = diff_delta(otherbuf, othersize,
buf, size, &delta_size, 0);
if (!delta_buf || delta_size != entry->delta_size)
@@ -374,11 +372,11 @@ static unsigned long write_object(struct sha1file *f,
/* yes if unlimited packfile */
!pack_size_limit ? 1 :
/* no if base written to previous pack */
- entry->delta->offset == (off_t)-1 ? 0 :
+ entry->delta->idx.offset == (off_t)-1 ? 0 :
/* otherwise double-check written to this
* pack, like we do below
*/
- entry->delta->offset ? 1 : 0;
+ entry->delta->idx.offset ? 1 : 0;
if (!pack_to_stdout)
crc32_begin(f);
@@ -405,16 +403,16 @@ static unsigned long write_object(struct sha1file *f,
z_stream stream;
unsigned long maxsize;
void *out;
- buf = read_sha1_file(entry->sha1, &type, &size);
+ buf = read_sha1_file(entry->idx.sha1, &type, &size);
if (!buf)
- die("unable to read %s", sha1_to_hex(entry->sha1));
+ die("unable to read %s", sha1_to_hex(entry->idx.sha1));
if (size != entry->size)
die("object %s size inconsistency (%lu vs %lu)",
- sha1_to_hex(entry->sha1), size, entry->size);
+ sha1_to_hex(entry->idx.sha1), size, entry->size);
if (usable_delta) {
buf = delta_against(buf, size, entry);
size = entry->delta_size;
- obj_type = (allow_ofs_delta && entry->delta->offset) ?
+ obj_type = (allow_ofs_delta && entry->delta->idx.offset) ?
OBJ_OFS_DELTA : OBJ_REF_DELTA;
} else {
/*
@@ -451,7 +449,7 @@ static unsigned long write_object(struct sha1file *f,
* encoding of the relative offset for the delta
* base from this object's position in the pack.
*/
- off_t ofs = entry->offset - entry->delta->offset;
+ off_t ofs = entry->idx.offset - entry->delta->idx.offset;
unsigned pos = sizeof(dheader) - 1;
dheader[pos] = ofs & 127;
while (ofs >>= 7)
@@ -475,7 +473,7 @@ static unsigned long write_object(struct sha1file *f,
return 0;
}
sha1write(f, header, hdrlen);
- sha1write(f, entry->delta->sha1, 20);
+ sha1write(f, entry->delta->idx.sha1, 20);
hdrlen += 20;
} else {
if (limit && hdrlen + datalen + 20 >= limit) {
@@ -496,7 +494,7 @@ static unsigned long write_object(struct sha1file *f,
off_t offset;
if (entry->delta) {
- obj_type = (allow_ofs_delta && entry->delta->offset) ?
+ obj_type = (allow_ofs_delta && entry->delta->idx.offset) ?
OBJ_OFS_DELTA : OBJ_REF_DELTA;
reused_delta++;
}
@@ -506,11 +504,11 @@ static unsigned long write_object(struct sha1file *f,
datalen = revidx[1].offset - offset;
if (!pack_to_stdout && p->index_version > 1 &&
check_pack_crc(p, &w_curs, offset, datalen, revidx->nr))
- die("bad packed object CRC for %s", sha1_to_hex(entry->sha1));
+ die("bad packed object CRC for %s", sha1_to_hex(entry->idx.sha1));
offset += entry->in_pack_header_size;
datalen -= entry->in_pack_header_size;
if (obj_type == OBJ_OFS_DELTA) {
- off_t ofs = entry->offset - entry->delta->offset;
+ off_t ofs = entry->idx.offset - entry->delta->idx.offset;
unsigned pos = sizeof(dheader) - 1;
dheader[pos] = ofs & 127;
while (ofs >>= 7)
@@ -524,7 +522,7 @@ static unsigned long write_object(struct sha1file *f,
if (limit && hdrlen + 20 + datalen + 20 >= limit)
return 0;
sha1write(f, header, hdrlen);
- sha1write(f, entry->delta->sha1, 20);
+ sha1write(f, entry->delta->idx.sha1, 20);
hdrlen += 20;
} else {
if (limit && hdrlen + datalen + 20 >= limit)
@@ -534,7 +532,7 @@ static unsigned long write_object(struct sha1file *f,
if (!pack_to_stdout && p->index_version == 1 &&
check_pack_inflate(p, &w_curs, offset, datalen, entry->size))
- die("corrupt packed object for %s", sha1_to_hex(entry->sha1));
+ die("corrupt packed object for %s", sha1_to_hex(entry->idx.sha1));
copy_pack_data(f, p, &w_curs, offset, datalen);
unuse_pack(&w_curs);
reused++;
@@ -543,7 +541,7 @@ static unsigned long write_object(struct sha1file *f,
written_delta++;
written++;
if (!pack_to_stdout)
- entry->crc32 = crc32_end(f);
+ entry->idx.crc32 = crc32_end(f);
return hdrlen + datalen;
}
@@ -554,7 +552,7 @@ static off_t write_one(struct sha1file *f,
unsigned long size;
/* offset is non zero if object is written already. */
- if (e->offset || e->preferred_base)
+ if (e->idx.offset || e->preferred_base)
return offset;
/* if we are deltified, write out base object first. */
@@ -564,10 +562,10 @@ static off_t write_one(struct sha1file *f,
return 0;
}
- e->offset = offset;
+ e->idx.offset = offset;
size = write_object(f, e, offset);
if (!size) {
- e->offset = 0;
+ e->idx.offset = 0;
return 0;
}
written_list[nr_written++] = e;
@@ -584,8 +582,7 @@ static int open_object_dir_tmp(const char *path)
return mkstemp(tmpname);
}
-/* forward declarations for write_pack_file */
-static void write_index_file(off_t last_obj_offset, unsigned char *sha1);
+/* forward declaration for write_pack_file */
static int adjust_perm(const char *path, mode_t mode);
static void write_pack_file(void)
@@ -602,6 +599,8 @@ static void write_pack_file(void)
written_list = xmalloc(nr_objects * sizeof(struct object_entry *));
do {
+ unsigned char sha1[20];
+
if (pack_to_stdout) {
f = sha1fd(1, "<stdout>");
} else {
@@ -633,23 +632,23 @@ static void write_pack_file(void)
* If so, rewrite it like in fast-import
*/
if (pack_to_stdout || nr_written == nr_remaining) {
- sha1close(f, pack_file_sha1, 1);
+ sha1close(f, sha1, 1);
} else {
- sha1close(f, pack_file_sha1, 0);
- fixup_pack_header_footer(f->fd, pack_file_sha1, pack_tmp_name, nr_written);
+ sha1close(f, sha1, 0);
+ fixup_pack_header_footer(f->fd, sha1, pack_tmp_name, nr_written);
close(f->fd);
}
if (!pack_to_stdout) {
- unsigned char object_list_sha1[20];
mode_t mode = umask(0);
umask(mode);
mode = 0444 & ~mode;
- write_index_file(last_obj_offset, object_list_sha1);
+ idx_tmp_name = write_idx_file(NULL,
+ (struct pack_idx_entry **) written_list, nr_written, sha1);
snprintf(tmpname, sizeof(tmpname), "%s-%s.pack",
- base_name, sha1_to_hex(object_list_sha1));
+ base_name, sha1_to_hex(sha1));
if (adjust_perm(pack_tmp_name, mode))
die("unable to make temporary pack file readable: %s",
strerror(errno));
@@ -657,19 +656,19 @@ static void write_pack_file(void)
die("unable to rename temporary pack file: %s",
strerror(errno));
snprintf(tmpname, sizeof(tmpname), "%s-%s.idx",
- base_name, sha1_to_hex(object_list_sha1));
+ base_name, sha1_to_hex(sha1));
if (adjust_perm(idx_tmp_name, mode))
die("unable to make temporary index file readable: %s",
strerror(errno));
if (rename(idx_tmp_name, tmpname))
die("unable to rename temporary index file: %s",
strerror(errno));
- puts(sha1_to_hex(object_list_sha1));
+ puts(sha1_to_hex(sha1));
}
/* mark written objects as written to previous pack */
for (j = 0; j < nr_written; j++) {
- written_list[j]->offset = (off_t)-1;
+ written_list[j]->idx.offset = (off_t)-1;
}
nr_remaining -= nr_written;
} while (nr_remaining && i < nr_objects);
@@ -687,129 +686,12 @@ static void write_pack_file(void)
*/
for (j = 0; i < nr_objects; i++) {
struct object_entry *e = objects + i;
- j += !e->offset && !e->preferred_base;
+ j += !e->idx.offset && !e->preferred_base;
}
if (j)
die("wrote %u objects as expected but %u unwritten", written, j);
}
-static int sha1_sort(const void *_a, const void *_b)
-{
- const struct object_entry *a = *(struct object_entry **)_a;
- const struct object_entry *b = *(struct object_entry **)_b;
- return hashcmp(a->sha1, b->sha1);
-}
-
-static uint32_t index_default_version = 1;
-static uint32_t index_off32_limit = 0x7fffffff;
-
-static void write_index_file(off_t last_obj_offset, unsigned char *sha1)
-{
- struct sha1file *f;
- struct object_entry **sorted_by_sha, **list, **last;
- uint32_t array[256];
- uint32_t i, index_version;
- SHA_CTX ctx;
-
- int fd = open_object_dir_tmp("tmp_idx_XXXXXX");
- if (fd < 0)
- die("unable to create %s: %s\n", tmpname, strerror(errno));
- idx_tmp_name = xstrdup(tmpname);
- f = sha1fd(fd, idx_tmp_name);
-
- if (nr_written) {
- sorted_by_sha = written_list;
- qsort(sorted_by_sha, nr_written, sizeof(*sorted_by_sha), sha1_sort);
- list = sorted_by_sha;
- last = sorted_by_sha + nr_written;
- } else
- sorted_by_sha = list = last = NULL;
-
- /* if last object's offset is >= 2^31 we should use index V2 */
- index_version = (last_obj_offset >> 31) ? 2 : index_default_version;
-
- /* index versions 2 and above need a header */
- if (index_version >= 2) {
- struct pack_idx_header hdr;
- hdr.idx_signature = htonl(PACK_IDX_SIGNATURE);
- hdr.idx_version = htonl(index_version);
- sha1write(f, &hdr, sizeof(hdr));
- }
-
- /*
- * Write the first-level table (the list is sorted,
- * but we use a 256-entry lookup to be able to avoid
- * having to do eight extra binary search iterations).
- */
- for (i = 0; i < 256; i++) {
- struct object_entry **next = list;
- while (next < last) {
- struct object_entry *entry = *next;
- if (entry->sha1[0] != i)
- break;
- next++;
- }
- array[i] = htonl(next - sorted_by_sha);
- list = next;
- }
- sha1write(f, array, 256 * 4);
-
- /* Compute the SHA1 hash of sorted object names. */
- SHA1_Init(&ctx);
-
- /* Write the actual SHA1 entries. */
- list = sorted_by_sha;
- for (i = 0; i < nr_written; i++) {
- struct object_entry *entry = *list++;
- if (index_version < 2) {
- uint32_t offset = htonl(entry->offset);
- sha1write(f, &offset, 4);
- }
- sha1write(f, entry->sha1, 20);
- SHA1_Update(&ctx, entry->sha1, 20);
- }
-
- if (index_version >= 2) {
- unsigned int nr_large_offset = 0;
-
- /* write the crc32 table */
- list = sorted_by_sha;
- for (i = 0; i < nr_written; i++) {
- struct object_entry *entry = *list++;
- uint32_t crc32_val = htonl(entry->crc32);
- sha1write(f, &crc32_val, 4);
- }
-
- /* write the 32-bit offset table */
- list = sorted_by_sha;
- for (i = 0; i < nr_written; i++) {
- struct object_entry *entry = *list++;
- uint32_t offset = (entry->offset <= index_off32_limit) ?
- entry->offset : (0x80000000 | nr_large_offset++);
- offset = htonl(offset);
- sha1write(f, &offset, 4);
- }
-
- /* write the large offset table */
- list = sorted_by_sha;
- while (nr_large_offset) {
- struct object_entry *entry = *list++;
- uint64_t offset = entry->offset;
- if (offset > index_off32_limit) {
- uint32_t split[2];
- split[0] = htonl(offset >> 32);
- split[1] = htonl(offset & 0xffffffff);
- sha1write(f, split, 8);
- nr_large_offset--;
- }
- }
- }
-
- sha1write(f, pack_file_sha1, 20);
- sha1close(f, NULL, 1);
- SHA1_Final(sha1, &ctx);
-}
-
static int locate_object_entry_hash(const unsigned char *sha1)
{
int i;
@@ -817,7 +699,7 @@ static int locate_object_entry_hash(const unsigned char *sha1)
memcpy(&ui, sha1, sizeof(unsigned int));
i = ui % object_ix_hashsz;
while (0 < object_ix[i]) {
- if (!hashcmp(sha1, objects[object_ix[i] - 1].sha1))
+ if (!hashcmp(sha1, objects[object_ix[i] - 1].idx.sha1))
return i;
if (++i == object_ix_hashsz)
i = 0;
@@ -849,7 +731,7 @@ static void rehash_objects(void)
object_ix = xrealloc(object_ix, sizeof(int) * object_ix_hashsz);
memset(object_ix, 0, sizeof(int) * object_ix_hashsz);
for (i = 0, oe = objects; i < nr_objects; i++, oe++) {
- int ix = locate_object_entry_hash(oe->sha1);
+ int ix = locate_object_entry_hash(oe->idx.sha1);
if (0 <= ix)
continue;
ix = -1 - ix;
@@ -943,7 +825,7 @@ static int add_object_entry(const unsigned char *sha1, enum object_type type,
entry = objects + nr_objects++;
memset(entry, 0, sizeof(*entry));
- hashcpy(entry->sha1, sha1);
+ hashcpy(entry->idx.sha1, sha1);
entry->hash = hash;
if (type)
entry->type = type;
@@ -1263,13 +1145,13 @@ static void check_object(struct object_entry *entry)
ofs += 1;
if (!ofs || MSB(ofs, 7))
die("delta base offset overflow in pack for %s",
- sha1_to_hex(entry->sha1));
+ sha1_to_hex(entry->idx.sha1));
c = buf[used_0++];
ofs = (ofs << 7) + (c & 127);
}
if (ofs >= entry->in_pack_offset)
die("delta base offset out of bound for %s",
- sha1_to_hex(entry->sha1));
+ sha1_to_hex(entry->idx.sha1));
ofs = entry->in_pack_offset - ofs;
if (!no_reuse_delta && !entry->preferred_base)
base_ref = find_packed_object_name(p, ofs);
@@ -1316,10 +1198,10 @@ static void check_object(struct object_entry *entry)
unuse_pack(&w_curs);
}
- entry->type = sha1_object_info(entry->sha1, &entry->size);
+ entry->type = sha1_object_info(entry->idx.sha1, &entry->size);
if (entry->type < 0)
die("unable to get type of object %s",
- sha1_to_hex(entry->sha1));
+ sha1_to_hex(entry->idx.sha1));
}
static int pack_offset_sort(const void *_a, const void *_b)
@@ -1329,7 +1211,7 @@ static int pack_offset_sort(const void *_a, const void *_b)
/* avoid filesystem trashing with loose objects */
if (!a->in_pack && !b->in_pack)
- return hashcmp(a->sha1, b->sha1);
+ return hashcmp(a->idx.sha1, b->idx.sha1);
if (a->in_pack < b->in_pack)
return -1;
@@ -1441,16 +1323,16 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
/* Load data if not already done */
if (!trg->data) {
- trg->data = read_sha1_file(trg_entry->sha1, &type, &sz);
+ trg->data = read_sha1_file(trg_entry->idx.sha1, &type, &sz);
if (sz != trg_size)
die("object %s inconsistent object length (%lu vs %lu)",
- sha1_to_hex(trg_entry->sha1), sz, trg_size);
+ sha1_to_hex(trg_entry->idx.sha1), sz, trg_size);
}
if (!src->data) {
- src->data = read_sha1_file(src_entry->sha1, &type, &sz);
+ src->data = read_sha1_file(src_entry->idx.sha1, &type, &sz);
if (sz != src_size)
die("object %s inconsistent object length (%lu vs %lu)",
- sha1_to_hex(src_entry->sha1), sz, src_size);
+ sha1_to_hex(src_entry->idx.sha1), sz, src_size);
}
if (!src->index) {
src->index = create_delta_index(src->data, src_size);
@@ -1825,12 +1707,12 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
}
if (!prefixcmp(arg, "--index-version=")) {
char *c;
- index_default_version = strtoul(arg + 16, &c, 10);
- if (index_default_version > 2)
+ pack_idx_default_version = strtoul(arg + 16, &c, 10);
+ if (pack_idx_default_version > 2)
die("bad %s", arg);
if (*c == ',')
- index_off32_limit = strtoul(c+1, &c, 0);
- if (*c || index_off32_limit & 0x80000000)
+ pack_idx_off32_limit = strtoul(c+1, &c, 0);
+ if (*c || pack_idx_off32_limit & 0x80000000)
die("bad %s", arg);
continue;
}
diff --git a/index-pack.c b/index-pack.c
index 58c4a9c..82c8da3 100644
--- a/index-pack.c
+++ b/index-pack.c
@@ -13,13 +13,11 @@ static const char index_pack_usage[] =
struct object_entry
{
- off_t offset;
+ struct pack_idx_entry idx;
unsigned long size;
unsigned int hdr_size;
- uint32_t crc32;
enum object_type type;
enum object_type real_type;
- unsigned char sha1[20];
};
union delta_base {
@@ -197,7 +195,7 @@ static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_
unsigned shift;
void *data;
- obj->offset = consumed_bytes;
+ obj->idx.offset = consumed_bytes;
input_crc32 = crc32(0, Z_NULL, 0);
p = fill(1);
@@ -229,15 +227,15 @@ static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_
while (c & 128) {
base_offset += 1;
if (!base_offset || MSB(base_offset, 7))
- bad_object(obj->offset, "offset value overflow for delta base object");
+ bad_object(obj->idx.offset, "offset value overflow for delta base object");
p = fill(1);
c = *p;
use(1);
base_offset = (base_offset << 7) + (c & 127);
}
- delta_base->offset = obj->offset - base_offset;
- if (delta_base->offset >= obj->offset)
- bad_object(obj->offset, "delta base offset is out of bound");
+ delta_base->offset = obj->idx.offset - base_offset;
+ if (delta_base->offset >= obj->idx.offset)
+ bad_object(obj->idx.offset, "delta base offset is out of bound");
break;
case OBJ_COMMIT:
case OBJ_TREE:
@@ -245,19 +243,19 @@ static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_
case OBJ_TAG:
break;
default:
- bad_object(obj->offset, "unknown object type %d", obj->type);
+ bad_object(obj->idx.offset, "unknown object type %d", obj->type);
}
- obj->hdr_size = consumed_bytes - obj->offset;
+ obj->hdr_size = consumed_bytes - obj->idx.offset;
- data = unpack_entry_data(obj->offset, obj->size);
- obj->crc32 = input_crc32;
+ data = unpack_entry_data(obj->idx.offset, obj->size);
+ obj->idx.crc32 = input_crc32;
return data;
}
static void *get_data_from_pack(struct object_entry *obj)
{
- unsigned long from = obj[0].offset + obj[0].hdr_size;
- unsigned long len = obj[1].offset - from;
+ unsigned long from = obj[0].idx.offset + obj[0].hdr_size;
+ unsigned long len = obj[1].idx.offset - from;
unsigned long rdy = 0;
unsigned char *src, *data;
z_stream stream;
@@ -360,11 +358,11 @@ static void resolve_delta(struct object_entry *delta_obj, void *base_data,
&result_size);
free(delta_data);
if (!result)
- bad_object(delta_obj->offset, "failed to apply delta");
- sha1_object(result, result_size, type, delta_obj->sha1);
+ bad_object(delta_obj->idx.offset, "failed to apply delta");
+ sha1_object(result, result_size, type, delta_obj->idx.sha1);
nr_resolved_deltas++;
- hashcpy(delta_base.sha1, delta_obj->sha1);
+ hashcpy(delta_base.sha1, delta_obj->idx.sha1);
if (!find_delta_children(&delta_base, &first, &last)) {
for (j = first; j <= last; j++) {
struct object_entry *child = objects + deltas[j].obj_no;
@@ -374,7 +372,7 @@ static void resolve_delta(struct object_entry *delta_obj, void *base_data,
}
memset(&delta_base, 0, sizeof(delta_base));
- delta_base.offset = delta_obj->offset;
+ delta_base.offset = delta_obj->idx.offset;
if (!find_delta_children(&delta_base, &first, &last)) {
for (j = first; j <= last; j++) {
struct object_entry *child = objects + deltas[j].obj_no;
@@ -418,12 +416,12 @@ static void parse_pack_objects(unsigned char *sha1)
delta->obj_no = i;
delta++;
} else
- sha1_object(data, obj->size, obj->type, obj->sha1);
+ sha1_object(data, obj->size, obj->type, obj->idx.sha1);
free(data);
if (verbose)
display_progress(&progress, i+1);
}
- objects[i].offset = consumed_bytes;
+ objects[i].idx.offset = consumed_bytes;
if (verbose)
stop_progress(&progress);
@@ -465,10 +463,10 @@ static void parse_pack_objects(unsigned char *sha1)
if (obj->type == OBJ_REF_DELTA || obj->type == OBJ_OFS_DELTA)
continue;
- hashcpy(base.sha1, obj->sha1);
+ hashcpy(base.sha1, obj->idx.sha1);
ref = !find_delta_children(&base, &ref_first, &ref_last);
memset(&base, 0, sizeof(base));
- base.offset = obj->offset;
+ base.offset = obj->idx.offset;
ofs = !find_delta_children(&base, &ofs_first, &ofs_last);
if (!ref && !ofs)
continue;
@@ -535,11 +533,11 @@ static void append_obj_to_pack(const unsigned char *sha1, void *buf,
}
header[n++] = c;
write_or_die(output_fd, header, n);
- obj[0].crc32 = crc32(0, Z_NULL, 0);
- obj[0].crc32 = crc32(obj[0].crc32, header, n);
- obj[1].offset = obj[0].offset + n;
- obj[1].offset += write_compressed(output_fd, buf, size, &obj[0].crc32);
- hashcpy(obj->sha1, sha1);
+ obj[0].idx.crc32 = crc32(0, Z_NULL, 0);
+ obj[0].idx.crc32 = crc32(obj[0].idx.crc32, header, n);
+ obj[1].idx.offset = obj[0].idx.offset + n;
+ obj[1].idx.offset += write_compressed(output_fd, buf, size, &obj[0].idx.crc32);
+ hashcpy(obj->idx.sha1, sha1);
}
static int delta_pos_compare(const void *_a, const void *_b)
@@ -602,145 +600,6 @@ static void fix_unresolved_deltas(int nr_unresolved)
free(sorted_by_pos);
}
-static uint32_t index_default_version = 1;
-static uint32_t index_off32_limit = 0x7fffffff;
-
-static int sha1_compare(const void *_a, const void *_b)
-{
- struct object_entry *a = *(struct object_entry **)_a;
- struct object_entry *b = *(struct object_entry **)_b;
- return hashcmp(a->sha1, b->sha1);
-}
-
-/*
- * On entry *sha1 contains the pack content SHA1 hash, on exit it is
- * the SHA1 hash of sorted object names.
- */
-static const char *write_index_file(const char *index_name, unsigned char *sha1)
-{
- struct sha1file *f;
- struct object_entry **sorted_by_sha, **list, **last;
- uint32_t array[256];
- int i, fd;
- SHA_CTX ctx;
- uint32_t index_version;
-
- if (nr_objects) {
- sorted_by_sha =
- xcalloc(nr_objects, sizeof(struct object_entry *));
- list = sorted_by_sha;
- last = sorted_by_sha + nr_objects;
- for (i = 0; i < nr_objects; ++i)
- sorted_by_sha[i] = &objects[i];
- qsort(sorted_by_sha, nr_objects, sizeof(sorted_by_sha[0]),
- sha1_compare);
- }
- else
- sorted_by_sha = list = last = NULL;
-
- if (!index_name) {
- static char tmpfile[PATH_MAX];
- snprintf(tmpfile, sizeof(tmpfile),
- "%s/tmp_idx_XXXXXX", get_object_directory());
- fd = mkstemp(tmpfile);
- index_name = xstrdup(tmpfile);
- } else {
- unlink(index_name);
- fd = open(index_name, O_CREAT|O_EXCL|O_WRONLY, 0600);
- }
- if (fd < 0)
- die("unable to create %s: %s", index_name, strerror(errno));
- f = sha1fd(fd, index_name);
-
- /* if last object's offset is >= 2^31 we should use index V2 */
- index_version = (objects[nr_objects-1].offset >> 31) ? 2 : index_default_version;
-
- /* index versions 2 and above need a header */
- if (index_version >= 2) {
- struct pack_idx_header hdr;
- hdr.idx_signature = htonl(PACK_IDX_SIGNATURE);
- hdr.idx_version = htonl(index_version);
- sha1write(f, &hdr, sizeof(hdr));
- }
-
- /*
- * Write the first-level table (the list is sorted,
- * but we use a 256-entry lookup to be able to avoid
- * having to do eight extra binary search iterations).
- */
- for (i = 0; i < 256; i++) {
- struct object_entry **next = list;
- while (next < last) {
- struct object_entry *obj = *next;
- if (obj->sha1[0] != i)
- break;
- next++;
- }
- array[i] = htonl(next - sorted_by_sha);
- list = next;
- }
- sha1write(f, array, 256 * 4);
-
- /* compute the SHA1 hash of sorted object names. */
- SHA1_Init(&ctx);
-
- /*
- * Write the actual SHA1 entries..
- */
- list = sorted_by_sha;
- for (i = 0; i < nr_objects; i++) {
- struct object_entry *obj = *list++;
- if (index_version < 2) {
- uint32_t offset = htonl(obj->offset);
- sha1write(f, &offset, 4);
- }
- sha1write(f, obj->sha1, 20);
- SHA1_Update(&ctx, obj->sha1, 20);
- }
-
- if (index_version >= 2) {
- unsigned int nr_large_offset = 0;
-
- /* write the crc32 table */
- list = sorted_by_sha;
- for (i = 0; i < nr_objects; i++) {
- struct object_entry *obj = *list++;
- uint32_t crc32_val = htonl(obj->crc32);
- sha1write(f, &crc32_val, 4);
- }
-
- /* write the 32-bit offset table */
- list = sorted_by_sha;
- for (i = 0; i < nr_objects; i++) {
- struct object_entry *obj = *list++;
- uint32_t offset = (obj->offset <= index_off32_limit) ?
- obj->offset : (0x80000000 | nr_large_offset++);
- offset = htonl(offset);
- sha1write(f, &offset, 4);
- }
-
- /* write the large offset table */
- list = sorted_by_sha;
- while (nr_large_offset) {
- struct object_entry *obj = *list++;
- uint64_t offset = obj->offset;
- if (offset > index_off32_limit) {
- uint32_t split[2];
- split[0] = htonl(offset >> 32);
- split[1] = htonl(offset & 0xffffffff);
- sha1write(f, split, 8);
- nr_large_offset--;
- }
- }
- }
-
- sha1write(f, sha1, 20);
- sha1close(f, NULL, 1);
- free(sorted_by_sha);
- SHA1_Final(sha1, &ctx);
- return index_name;
-}
-
static void final(const char *final_pack_name, const char *curr_pack_name,
const char *final_index_name, const char *curr_index_name,
const char *keep_name, const char *keep_msg,
@@ -830,6 +689,7 @@ int main(int argc, char **argv)
const char *curr_index, *index_name = NULL;
const char *keep_name = NULL, *keep_msg = NULL;
char *index_name_buf = NULL, *keep_name_buf = NULL;
+ struct pack_idx_entry **idx_objects;
unsigned char sha1[20];
for (i = 1; i < argc; i++) {
@@ -865,12 +725,12 @@ int main(int argc, char **argv)
index_name = argv[++i];
} else if (!prefixcmp(arg, "--index-version=")) {
char *c;
- index_default_version = strtoul(arg + 16, &c, 10);
- if (index_default_version > 2)
+ pack_idx_default_version = strtoul(arg + 16, &c, 10);
+ if (pack_idx_default_version > 2)
die("bad %s", arg);
if (*c == ',')
- index_off32_limit = strtoul(c+1, &c, 0);
- if (*c || index_off32_limit & 0x80000000)
+ pack_idx_off32_limit = strtoul(c+1, &c, 0);
+ if (*c || pack_idx_off32_limit & 0x80000000)
die("bad %s", arg);
} else
usage(index_pack_usage);
@@ -940,7 +800,13 @@ int main(int argc, char **argv)
nr_deltas - nr_resolved_deltas);
}
free(deltas);
- curr_index = write_index_file(index_name, sha1);
+
+ idx_objects = xmalloc((nr_objects) * sizeof(struct pack_idx_entry *));
+ for (i = 0; i < nr_objects; i++)
+ idx_objects[i] = &objects[i].idx;
+ curr_index = write_idx_file(index_name, idx_objects, nr_objects, sha1);
+ free(idx_objects);
+
final(pack_name, curr_pack,
index_name, curr_index,
keep_name, keep_msg,
diff --git a/pack-write.c b/pack-write.c
index ae2e481..1cf5f7c 100644
--- a/pack-write.c
+++ b/pack-write.c
@@ -1,5 +1,147 @@
#include "cache.h"
#include "pack.h"
+#include "csum-file.h"
+
+uint32_t pack_idx_default_version = 1;
+uint32_t pack_idx_off32_limit = 0x7fffffff;
+
+static int sha1_compare(const void *_a, const void *_b)
+{
+ struct pack_idx_entry *a = *(struct pack_idx_entry **)_a;
+ struct pack_idx_entry *b = *(struct pack_idx_entry **)_b;
+ return hashcmp(a->sha1, b->sha1);
+}
+
+/*
+ * On entry *sha1 contains the pack content SHA1 hash, on exit it is
+ * the SHA1 hash of sorted object names. The objects array passed in
+ * will be sorted by SHA1 on exit.
+ */
+const char *write_idx_file(const char *index_name, struct pack_idx_entry **objects, int nr_objects, unsigned char *sha1)
+{
+ struct sha1file *f;
+ struct pack_idx_entry **sorted_by_sha, **list, **last;
+ off_t last_obj_offset = 0;
+ uint32_t array[256];
+ int i, fd;
+ SHA_CTX ctx;
+ uint32_t index_version;
+
+ if (nr_objects) {
+ sorted_by_sha = objects;
+ list = sorted_by_sha;
+ last = sorted_by_sha + nr_objects;
+ for (i = 0; i < nr_objects; ++i) {
+ if (objects[i]->offset > last_obj_offset)
+ last_obj_offset = objects[i]->offset;
+ }
+ qsort(sorted_by_sha, nr_objects, sizeof(sorted_by_sha[0]),
+ sha1_compare);
+ }
+ else
+ sorted_by_sha = list = last = NULL;
+
+ if (!index_name) {
+ static char tmpfile[PATH_MAX];
+ snprintf(tmpfile, sizeof(tmpfile),
+ "%s/tmp_idx_XXXXXX", get_object_directory());
+ fd = mkstemp(tmpfile);
+ index_name = xstrdup(tmpfile);
+ } else {
+ unlink(index_name);
+ fd = open(index_name, O_CREAT|O_EXCL|O_WRONLY, 0600);
+ }
+ if (fd < 0)
+ die("unable to create %s: %s", index_name, strerror(errno));
+ f = sha1fd(fd, index_name);
+
+ /* if last object's offset is >= 2^31 we should use index V2 */
+ index_version = (last_obj_offset >> 31) ? 2 : pack_idx_default_version;
+
+ /* index versions 2 and above need a header */
+ if (index_version >= 2) {
+ struct pack_idx_header hdr;
+ hdr.idx_signature = htonl(PACK_IDX_SIGNATURE);
+ hdr.idx_version = htonl(index_version);
+ sha1write(f, &hdr, sizeof(hdr));
+ }
+
+ /*
+ * Write the first-level table (the list is sorted,
+ * but we use a 256-entry lookup to be able to avoid
+ * having to do eight extra binary search iterations).
+ */
+ for (i = 0; i < 256; i++) {
+ struct pack_idx_entry **next = list;
+ while (next < last) {
+ struct pack_idx_entry *obj = *next;
+ if (obj->sha1[0] != i)
+ break;
+ next++;
+ }
+ array[i] = htonl(next - sorted_by_sha);
+ list = next;
+ }
+ sha1write(f, array, 256 * 4);
+
+ /* compute the SHA1 hash of sorted object names. */
+ SHA1_Init(&ctx);
+
+ /*
+ * Write the actual SHA1 entries..
+ */
+ list = sorted_by_sha;
+ for (i = 0; i < nr_objects; i++) {
+ struct pack_idx_entry *obj = *list++;
+ if (index_version < 2) {
+ uint32_t offset = htonl(obj->offset);
+ sha1write(f, &offset, 4);
+ }
+ sha1write(f, obj->sha1, 20);
+ SHA1_Update(&ctx, obj->sha1, 20);
+ }
+
+ if (index_version >= 2) {
+ unsigned int nr_large_offset = 0;
+
+ /* write the crc32 table */
+ list = sorted_by_sha;
+ for (i = 0; i < nr_objects; i++) {
+ struct pack_idx_entry *obj = *list++;
+ uint32_t crc32_val = htonl(obj->crc32);
+ sha1write(f, &crc32_val, 4);
+ }
+
+ /* write the 32-bit offset table */
+ list = sorted_by_sha;
+ for (i = 0; i < nr_objects; i++) {
+ struct pack_idx_entry *obj = *list++;
+ uint32_t offset = (obj->offset <= pack_idx_off32_limit) ?
+ obj->offset : (0x80000000 | nr_large_offset++);
+ offset = htonl(offset);
+ sha1write(f, &offset, 4);
+ }
+
+ /* write the large offset table */
+ list = sorted_by_sha;
+ while (nr_large_offset) {
+ struct pack_idx_entry *obj = *list++;
+ uint64_t offset = obj->offset;
+ if (offset > pack_idx_off32_limit) {
+ uint32_t split[2];
+ split[0] = htonl(offset >> 32);
+ split[1] = htonl(offset & 0xffffffff);
+ sha1write(f, split, 8);
+ nr_large_offset--;
+ }
+ }
+ }
+
+ sha1write(f, sha1, 20);
+ sha1close(f, NULL, 1);
+ SHA1_Final(sha1, &ctx);
+ return index_name;
+}
void fixup_pack_header_footer(int pack_fd,
unsigned char *pack_file_sha1,
diff --git a/pack.h b/pack.h
index d667fb8..f357c9f 100644
--- a/pack.h
+++ b/pack.h
@@ -34,6 +34,10 @@ struct pack_header {
*/
#define PACK_IDX_SIGNATURE 0xff744f63 /* "\377tOc" */
+/* These may be overridden by command-line parameters */
+extern uint32_t pack_idx_default_version;
+extern uint32_t pack_idx_off32_limit;
+
/*
* Packed object index header
*/
@@ -42,6 +46,16 @@ struct pack_idx_header {
uint32_t idx_version;
};
+/*
+ * Common part of object structure used for write_idx_file
+ */
+struct pack_idx_entry {
+ unsigned char sha1[20];
+ uint32_t crc32;
+ off_t offset;
+};
+
+extern const char *write_idx_file(const char *index_name, struct pack_idx_entry **objects, int nr_objects, unsigned char *sha1);
extern int verify_pack(struct packed_git *, int);
extern void fixup_pack_header_footer(int, unsigned char *, const char *, uint32_t);
--
1.5.1
^ permalink raw reply related
* [PATCH] Unify write_index_file functions
From: Geert Bosch @ 2007-06-01 19:18 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Nicolas Pitre, Dana How, Git List
In-Reply-To: <7vy7j3xwg5.fsf@assigned-by-dhcp.cox.net>
This patch creates a new pack-idx.c file containing a unified version of
the write_index_file functions in builtin-pack-objects.c and index-pack.c.
As the name "index" is overloaded in git, move in the direction
of using "idx" and "pack idx" when refering to the pack index.
There should be no change in functionality.
Signed-off-by: Geert Bosch <bosch@gnat.com>
---
builtin-pack-objects.c | 218 +++++++++++-------------------------------------
index-pack.c | 208 ++++++++-------------------------------------
pack-write.c | 142 +++++++++++++++++++++++++++++++
pack.h | 14 +++
4 files changed, 243 insertions(+), 339 deletions(-)
On Jun 1, 2007, at 16:15, Junio C Hamano wrote:
>Why? off_t offset used to be 8-byte aligned but now it is not...
[snip]
>Ah, you wanted to match the shape of the early part of two
>structures. Sounds error prone for people who would want to
>maintain both programs in the future.
Indeed, and I didn't catch that there was a special order
for efficiency.
>Why not make the private "struct object_entry" in each users
>have an embedded structure at the beginning like this:
I thought about that, but wanted to have a change as small
as possible. This version incorporates the suggestion.
On Jun 1, 2007, at 16:16, Dana How wrote:
>Good stuff. 3 minor issues:
>(1) Shawn named the new file containing common pack-writing
>functions "pack-write.c"; in that spirit should your new file
>be "idx-write.c" ?
Added this to pack-write.c as suggested by Nicolas.
>(2) write_idx_file has a sha1 argument with different in & out
>meanings, requiring copies at some call sites. Should this be 2
>separate args?
Again, I wanted to keep the change as small as possible. Also, one
extra copy of a SHA1 per generated index is just not worth bothering
about. As noted by Nicolas, the file-global static variable should
just be removed altogether.
>(3) 2 files now have definitions of "struct object_entry" with no
>indications >that the first 4 fields should be the same as
>"struct idx_object_entry". Please add at least some comments
>to the former (this is the only thing I care strongly about here).
>Better would be putting an idx_object_entry as the first field in
>the object_entry's, but that would result in a lot of trivial
>changes and could be done later.
That was the reason I avoided that change initially, but it's included
in this version.
On Jun 1, 2007, at 16:54, Nicolas Pitre wrote:
>I intended to do exactly that (I even mentioned it in 81a216a5d6) but
>I'm glad you beat me to it.
I'd like all code that knows about the index file format to
be more centralized, but was holding off until after your index V2
changes.
>A few comments.
>
>Please use pack-write.c rather than a new file. This pack-write.c
>was created exactly to gather common pack writing tasks.
OK, as done in this patch.
>Please also consider removing the pack index writing code from
>fast-import.c as well.
Well, that would be a follow-up patch. I'd like to keep each change
as small as possible.
[about changing field ordering]
>Don't do this. The crc32 field was carefully placed so the offset
>field is 64-bit aligned with no need for any padding.
OK, missed that.
>In fact, those 3 fields should probably be defined in a structure of
>their own rather than hoping that no one will fail to change the
>ordering in all places.
Sure.
This version should have addressed all noted issues.
-Geert
diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c
index e52332d..a247238 100644
--- a/builtin-pack-objects.c
+++ b/builtin-pack-objects.c
@@ -23,10 +23,9 @@ git-pack-objects [{ -q | --progress | --all-progress }] [--max-pack-size=N] \n\
[--stdout | base-name] [<ref-list | <object-list]";
struct object_entry {
- unsigned char sha1[20];
- uint32_t crc32; /* crc of raw pack data for this object */
- off_t offset; /* offset into the final pack file */
+ struct pack_idx_entry idx;
unsigned long size; /* uncompressed size */
+
unsigned int hash; /* name hint hash */
unsigned int depth; /* delta depth */
struct packed_git *in_pack; /* already in pack */
@@ -65,7 +64,6 @@ static int allow_ofs_delta;
static const char *pack_tmp_name, *idx_tmp_name;
static char tmpname[PATH_MAX];
static const char *base_name;
-static unsigned char pack_file_sha1[20];
static int progress = 1;
static int window = 10;
static uint32_t pack_size_limit;
@@ -241,11 +239,11 @@ static void *delta_against(void *buf, unsigned long size, struct object_entry *e
{
unsigned long othersize, delta_size;
enum object_type type;
- void *otherbuf = read_sha1_file(entry->delta->sha1, &type, &othersize);
+ void *otherbuf = read_sha1_file(entry->delta->idx.sha1, &type, &othersize);
void *delta_buf;
if (!otherbuf)
- die("unable to read %s", sha1_to_hex(entry->delta->sha1));
+ die("unable to read %s", sha1_to_hex(entry->delta->idx.sha1));
delta_buf = diff_delta(otherbuf, othersize,
buf, size, &delta_size, 0);
if (!delta_buf || delta_size != entry->delta_size)
@@ -374,11 +372,11 @@ static unsigned long write_object(struct sha1file *f,
/* yes if unlimited packfile */
!pack_size_limit ? 1 :
/* no if base written to previous pack */
- entry->delta->offset == (off_t)-1 ? 0 :
+ entry->delta->idx.offset == (off_t)-1 ? 0 :
/* otherwise double-check written to this
* pack, like we do below
*/
- entry->delta->offset ? 1 : 0;
+ entry->delta->idx.offset ? 1 : 0;
if (!pack_to_stdout)
crc32_begin(f);
@@ -405,16 +403,16 @@ static unsigned long write_object(struct sha1file *f,
z_stream stream;
unsigned long maxsize;
void *out;
- buf = read_sha1_file(entry->sha1, &type, &size);
+ buf = read_sha1_file(entry->idx.sha1, &type, &size);
if (!buf)
- die("unable to read %s", sha1_to_hex(entry->sha1));
+ die("unable to read %s", sha1_to_hex(entry->idx.sha1));
if (size != entry->size)
die("object %s size inconsistency (%lu vs %lu)",
- sha1_to_hex(entry->sha1), size, entry->size);
+ sha1_to_hex(entry->idx.sha1), size, entry->size);
if (usable_delta) {
buf = delta_against(buf, size, entry);
size = entry->delta_size;
- obj_type = (allow_ofs_delta && entry->delta->offset) ?
+ obj_type = (allow_ofs_delta && entry->delta->idx.offset) ?
OBJ_OFS_DELTA : OBJ_REF_DELTA;
} else {
/*
@@ -451,7 +449,7 @@ static unsigned long write_object(struct sha1file *f,
* encoding of the relative offset for the delta
* base from this object's position in the pack.
*/
- off_t ofs = entry->offset - entry->delta->offset;
+ off_t ofs = entry->idx.offset - entry->delta->idx.offset;
unsigned pos = sizeof(dheader) - 1;
dheader[pos] = ofs & 127;
while (ofs >>= 7)
@@ -475,7 +473,7 @@ static unsigned long write_object(struct sha1file *f,
return 0;
}
sha1write(f, header, hdrlen);
- sha1write(f, entry->delta->sha1, 20);
+ sha1write(f, entry->delta->idx.sha1, 20);
hdrlen += 20;
} else {
if (limit && hdrlen + datalen + 20 >= limit) {
@@ -496,7 +494,7 @@ static unsigned long write_object(struct sha1file *f,
off_t offset;
if (entry->delta) {
- obj_type = (allow_ofs_delta && entry->delta->offset) ?
+ obj_type = (allow_ofs_delta && entry->delta->idx.offset) ?
OBJ_OFS_DELTA : OBJ_REF_DELTA;
reused_delta++;
}
@@ -506,11 +504,11 @@ static unsigned long write_object(struct sha1file *f,
datalen = revidx[1].offset - offset;
if (!pack_to_stdout && p->index_version > 1 &&
check_pack_crc(p, &w_curs, offset, datalen, revidx->nr))
- die("bad packed object CRC for %s", sha1_to_hex(entry->sha1));
+ die("bad packed object CRC for %s", sha1_to_hex(entry->idx.sha1));
offset += entry->in_pack_header_size;
datalen -= entry->in_pack_header_size;
if (obj_type == OBJ_OFS_DELTA) {
- off_t ofs = entry->offset - entry->delta->offset;
+ off_t ofs = entry->idx.offset - entry->delta->idx.offset;
unsigned pos = sizeof(dheader) - 1;
dheader[pos] = ofs & 127;
while (ofs >>= 7)
@@ -524,7 +522,7 @@ static unsigned long write_object(struct sha1file *f,
if (limit && hdrlen + 20 + datalen + 20 >= limit)
return 0;
sha1write(f, header, hdrlen);
- sha1write(f, entry->delta->sha1, 20);
+ sha1write(f, entry->delta->idx.sha1, 20);
hdrlen += 20;
} else {
if (limit && hdrlen + datalen + 20 >= limit)
@@ -534,7 +532,7 @@ static unsigned long write_object(struct sha1file *f,
if (!pack_to_stdout && p->index_version == 1 &&
check_pack_inflate(p, &w_curs, offset, datalen, entry->size))
- die("corrupt packed object for %s", sha1_to_hex(entry->sha1));
+ die("corrupt packed object for %s", sha1_to_hex(entry->idx.sha1));
copy_pack_data(f, p, &w_curs, offset, datalen);
unuse_pack(&w_curs);
reused++;
@@ -543,7 +541,7 @@ static unsigned long write_object(struct sha1file *f,
written_delta++;
written++;
if (!pack_to_stdout)
- entry->crc32 = crc32_end(f);
+ entry->idx.crc32 = crc32_end(f);
return hdrlen + datalen;
}
@@ -554,7 +552,7 @@ static off_t write_one(struct sha1file *f,
unsigned long size;
/* offset is non zero if object is written already. */
- if (e->offset || e->preferred_base)
+ if (e->idx.offset || e->preferred_base)
return offset;
/* if we are deltified, write out base object first. */
@@ -564,10 +562,10 @@ static off_t write_one(struct sha1file *f,
return 0;
}
- e->offset = offset;
+ e->idx.offset = offset;
size = write_object(f, e, offset);
if (!size) {
- e->offset = 0;
+ e->idx.offset = 0;
return 0;
}
written_list[nr_written++] = e;
@@ -584,8 +582,7 @@ static int open_object_dir_tmp(const char *path)
return mkstemp(tmpname);
}
-/* forward declarations for write_pack_file */
-static void write_index_file(off_t last_obj_offset, unsigned char *sha1);
+/* forward declaration for write_pack_file */
static int adjust_perm(const char *path, mode_t mode);
static void write_pack_file(void)
@@ -602,6 +599,8 @@ static void write_pack_file(void)
written_list = xmalloc(nr_objects * sizeof(struct object_entry *));
do {
+ unsigned char sha1[20];
+
if (pack_to_stdout) {
f = sha1fd(1, "<stdout>");
} else {
@@ -633,23 +632,23 @@ static void write_pack_file(void)
* If so, rewrite it like in fast-import
*/
if (pack_to_stdout || nr_written == nr_remaining) {
- sha1close(f, pack_file_sha1, 1);
+ sha1close(f, sha1, 1);
} else {
- sha1close(f, pack_file_sha1, 0);
- fixup_pack_header_footer(f->fd, pack_file_sha1, pack_tmp_name, nr_written);
+ sha1close(f, sha1, 0);
+ fixup_pack_header_footer(f->fd, sha1, pack_tmp_name, nr_written);
close(f->fd);
}
if (!pack_to_stdout) {
- unsigned char object_list_sha1[20];
mode_t mode = umask(0);
umask(mode);
mode = 0444 & ~mode;
- write_index_file(last_obj_offset, object_list_sha1);
+ idx_tmp_name = write_idx_file(NULL,
+ (struct pack_idx_entry **) written_list, nr_written, sha1);
snprintf(tmpname, sizeof(tmpname), "%s-%s.pack",
- base_name, sha1_to_hex(object_list_sha1));
+ base_name, sha1_to_hex(sha1));
if (adjust_perm(pack_tmp_name, mode))
die("unable to make temporary pack file readable: %s",
strerror(errno));
@@ -657,19 +656,19 @@ static void write_pack_file(void)
die("unable to rename temporary pack file: %s",
strerror(errno));
snprintf(tmpname, sizeof(tmpname), "%s-%s.idx",
- base_name, sha1_to_hex(object_list_sha1));
+ base_name, sha1_to_hex(sha1));
if (adjust_perm(idx_tmp_name, mode))
die("unable to make temporary index file readable: %s",
strerror(errno));
if (rename(idx_tmp_name, tmpname))
die("unable to rename temporary index file: %s",
strerror(errno));
- puts(sha1_to_hex(object_list_sha1));
+ puts(sha1_to_hex(sha1));
}
/* mark written objects as written to previous pack */
for (j = 0; j < nr_written; j++) {
- written_list[j]->offset = (off_t)-1;
+ written_list[j]->idx.offset = (off_t)-1;
}
nr_remaining -= nr_written;
} while (nr_remaining && i < nr_objects);
@@ -687,129 +686,12 @@ static void write_pack_file(void)
*/
for (j = 0; i < nr_objects; i++) {
struct object_entry *e = objects + i;
- j += !e->offset && !e->preferred_base;
+ j += !e->idx.offset && !e->preferred_base;
}
if (j)
die("wrote %u objects as expected but %u unwritten", written, j);
}
-static int sha1_sort(const void *_a, const void *_b)
-{
- const struct object_entry *a = *(struct object_entry **)_a;
- const struct object_entry *b = *(struct object_entry **)_b;
- return hashcmp(a->sha1, b->sha1);
-}
-
-static uint32_t index_default_version = 1;
-static uint32_t index_off32_limit = 0x7fffffff;
-
-static void write_index_file(off_t last_obj_offset, unsigned char *sha1)
-{
- struct sha1file *f;
- struct object_entry **sorted_by_sha, **list, **last;
- uint32_t array[256];
- uint32_t i, index_version;
- SHA_CTX ctx;
-
- int fd = open_object_dir_tmp("tmp_idx_XXXXXX");
- if (fd < 0)
- die("unable to create %s: %s\n", tmpname, strerror(errno));
- idx_tmp_name = xstrdup(tmpname);
- f = sha1fd(fd, idx_tmp_name);
-
- if (nr_written) {
- sorted_by_sha = written_list;
- qsort(sorted_by_sha, nr_written, sizeof(*sorted_by_sha), sha1_sort);
- list = sorted_by_sha;
- last = sorted_by_sha + nr_written;
- } else
- sorted_by_sha = list = last = NULL;
-
- /* if last object's offset is >= 2^31 we should use index V2 */
- index_version = (last_obj_offset >> 31) ? 2 : index_default_version;
-
- /* index versions 2 and above need a header */
- if (index_version >= 2) {
- struct pack_idx_header hdr;
- hdr.idx_signature = htonl(PACK_IDX_SIGNATURE);
- hdr.idx_version = htonl(index_version);
- sha1write(f, &hdr, sizeof(hdr));
- }
-
- /*
- * Write the first-level table (the list is sorted,
- * but we use a 256-entry lookup to be able to avoid
- * having to do eight extra binary search iterations).
- */
- for (i = 0; i < 256; i++) {
- struct object_entry **next = list;
- while (next < last) {
- struct object_entry *entry = *next;
- if (entry->sha1[0] != i)
- break;
- next++;
- }
- array[i] = htonl(next - sorted_by_sha);
- list = next;
- }
- sha1write(f, array, 256 * 4);
-
- /* Compute the SHA1 hash of sorted object names. */
- SHA1_Init(&ctx);
-
- /* Write the actual SHA1 entries. */
- list = sorted_by_sha;
- for (i = 0; i < nr_written; i++) {
- struct object_entry *entry = *list++;
- if (index_version < 2) {
- uint32_t offset = htonl(entry->offset);
- sha1write(f, &offset, 4);
- }
- sha1write(f, entry->sha1, 20);
- SHA1_Update(&ctx, entry->sha1, 20);
- }
-
- if (index_version >= 2) {
- unsigned int nr_large_offset = 0;
-
- /* write the crc32 table */
- list = sorted_by_sha;
- for (i = 0; i < nr_written; i++) {
- struct object_entry *entry = *list++;
- uint32_t crc32_val = htonl(entry->crc32);
- sha1write(f, &crc32_val, 4);
- }
-
- /* write the 32-bit offset table */
- list = sorted_by_sha;
- for (i = 0; i < nr_written; i++) {
- struct object_entry *entry = *list++;
- uint32_t offset = (entry->offset <= index_off32_limit) ?
- entry->offset : (0x80000000 | nr_large_offset++);
- offset = htonl(offset);
- sha1write(f, &offset, 4);
- }
-
- /* write the large offset table */
- list = sorted_by_sha;
- while (nr_large_offset) {
- struct object_entry *entry = *list++;
- uint64_t offset = entry->offset;
- if (offset > index_off32_limit) {
- uint32_t split[2];
- split[0] = htonl(offset >> 32);
- split[1] = htonl(offset & 0xffffffff);
- sha1write(f, split, 8);
- nr_large_offset--;
- }
- }
- }
-
- sha1write(f, pack_file_sha1, 20);
- sha1close(f, NULL, 1);
- SHA1_Final(sha1, &ctx);
-}
-
static int locate_object_entry_hash(const unsigned char *sha1)
{
int i;
@@ -817,7 +699,7 @@ static int locate_object_entry_hash(const unsigned char *sha1)
memcpy(&ui, sha1, sizeof(unsigned int));
i = ui % object_ix_hashsz;
while (0 < object_ix[i]) {
- if (!hashcmp(sha1, objects[object_ix[i] - 1].sha1))
+ if (!hashcmp(sha1, objects[object_ix[i] - 1].idx.sha1))
return i;
if (++i == object_ix_hashsz)
i = 0;
@@ -849,7 +731,7 @@ static void rehash_objects(void)
object_ix = xrealloc(object_ix, sizeof(int) * object_ix_hashsz);
memset(object_ix, 0, sizeof(int) * object_ix_hashsz);
for (i = 0, oe = objects; i < nr_objects; i++, oe++) {
- int ix = locate_object_entry_hash(oe->sha1);
+ int ix = locate_object_entry_hash(oe->idx.sha1);
if (0 <= ix)
continue;
ix = -1 - ix;
@@ -943,7 +825,7 @@ static int add_object_entry(const unsigned char *sha1, enum object_type type,
entry = objects + nr_objects++;
memset(entry, 0, sizeof(*entry));
- hashcpy(entry->sha1, sha1);
+ hashcpy(entry->idx.sha1, sha1);
entry->hash = hash;
if (type)
entry->type = type;
@@ -1263,13 +1145,13 @@ static void check_object(struct object_entry *entry)
ofs += 1;
if (!ofs || MSB(ofs, 7))
die("delta base offset overflow in pack for %s",
- sha1_to_hex(entry->sha1));
+ sha1_to_hex(entry->idx.sha1));
c = buf[used_0++];
ofs = (ofs << 7) + (c & 127);
}
if (ofs >= entry->in_pack_offset)
die("delta base offset out of bound for %s",
- sha1_to_hex(entry->sha1));
+ sha1_to_hex(entry->idx.sha1));
ofs = entry->in_pack_offset - ofs;
if (!no_reuse_delta && !entry->preferred_base)
base_ref = find_packed_object_name(p, ofs);
@@ -1316,10 +1198,10 @@ static void check_object(struct object_entry *entry)
unuse_pack(&w_curs);
}
- entry->type = sha1_object_info(entry->sha1, &entry->size);
+ entry->type = sha1_object_info(entry->idx.sha1, &entry->size);
if (entry->type < 0)
die("unable to get type of object %s",
- sha1_to_hex(entry->sha1));
+ sha1_to_hex(entry->idx.sha1));
}
static int pack_offset_sort(const void *_a, const void *_b)
@@ -1329,7 +1211,7 @@ static int pack_offset_sort(const void *_a, const void *_b)
/* avoid filesystem trashing with loose objects */
if (!a->in_pack && !b->in_pack)
- return hashcmp(a->sha1, b->sha1);
+ return hashcmp(a->idx.sha1, b->idx.sha1);
if (a->in_pack < b->in_pack)
return -1;
@@ -1441,16 +1323,16 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
/* Load data if not already done */
if (!trg->data) {
- trg->data = read_sha1_file(trg_entry->sha1, &type, &sz);
+ trg->data = read_sha1_file(trg_entry->idx.sha1, &type, &sz);
if (sz != trg_size)
die("object %s inconsistent object length (%lu vs %lu)",
- sha1_to_hex(trg_entry->sha1), sz, trg_size);
+ sha1_to_hex(trg_entry->idx.sha1), sz, trg_size);
}
if (!src->data) {
- src->data = read_sha1_file(src_entry->sha1, &type, &sz);
+ src->data = read_sha1_file(src_entry->idx.sha1, &type, &sz);
if (sz != src_size)
die("object %s inconsistent object length (%lu vs %lu)",
- sha1_to_hex(src_entry->sha1), sz, src_size);
+ sha1_to_hex(src_entry->idx.sha1), sz, src_size);
}
if (!src->index) {
src->index = create_delta_index(src->data, src_size);
@@ -1825,12 +1707,12 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
}
if (!prefixcmp(arg, "--index-version=")) {
char *c;
- index_default_version = strtoul(arg + 16, &c, 10);
- if (index_default_version > 2)
+ pack_idx_default_version = strtoul(arg + 16, &c, 10);
+ if (pack_idx_default_version > 2)
die("bad %s", arg);
if (*c == ',')
- index_off32_limit = strtoul(c+1, &c, 0);
- if (*c || index_off32_limit & 0x80000000)
+ pack_idx_off32_limit = strtoul(c+1, &c, 0);
+ if (*c || pack_idx_off32_limit & 0x80000000)
die("bad %s", arg);
continue;
}
diff --git a/index-pack.c b/index-pack.c
index 58c4a9c..82c8da3 100644
--- a/index-pack.c
+++ b/index-pack.c
@@ -13,13 +13,11 @@ static const char index_pack_usage[] =
struct object_entry
{
- off_t offset;
+ struct pack_idx_entry idx;
unsigned long size;
unsigned int hdr_size;
- uint32_t crc32;
enum object_type type;
enum object_type real_type;
- unsigned char sha1[20];
};
union delta_base {
@@ -197,7 +195,7 @@ static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_
unsigned shift;
void *data;
- obj->offset = consumed_bytes;
+ obj->idx.offset = consumed_bytes;
input_crc32 = crc32(0, Z_NULL, 0);
p = fill(1);
@@ -229,15 +227,15 @@ static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_
while (c & 128) {
base_offset += 1;
if (!base_offset || MSB(base_offset, 7))
- bad_object(obj->offset, "offset value overflow for delta base object");
+ bad_object(obj->idx.offset, "offset value overflow for delta base object");
p = fill(1);
c = *p;
use(1);
base_offset = (base_offset << 7) + (c & 127);
}
- delta_base->offset = obj->offset - base_offset;
- if (delta_base->offset >= obj->offset)
- bad_object(obj->offset, "delta base offset is out of bound");
+ delta_base->offset = obj->idx.offset - base_offset;
+ if (delta_base->offset >= obj->idx.offset)
+ bad_object(obj->idx.offset, "delta base offset is out of bound");
break;
case OBJ_COMMIT:
case OBJ_TREE:
@@ -245,19 +243,19 @@ static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_
case OBJ_TAG:
break;
default:
- bad_object(obj->offset, "unknown object type %d", obj->type);
+ bad_object(obj->idx.offset, "unknown object type %d", obj->type);
}
- obj->hdr_size = consumed_bytes - obj->offset;
+ obj->hdr_size = consumed_bytes - obj->idx.offset;
- data = unpack_entry_data(obj->offset, obj->size);
- obj->crc32 = input_crc32;
+ data = unpack_entry_data(obj->idx.offset, obj->size);
+ obj->idx.crc32 = input_crc32;
return data;
}
static void *get_data_from_pack(struct object_entry *obj)
{
- unsigned long from = obj[0].offset + obj[0].hdr_size;
- unsigned long len = obj[1].offset - from;
+ unsigned long from = obj[0].idx.offset + obj[0].hdr_size;
+ unsigned long len = obj[1].idx.offset - from;
unsigned long rdy = 0;
unsigned char *src, *data;
z_stream stream;
@@ -360,11 +358,11 @@ static void resolve_delta(struct object_entry *delta_obj, void *base_data,
&result_size);
free(delta_data);
if (!result)
- bad_object(delta_obj->offset, "failed to apply delta");
- sha1_object(result, result_size, type, delta_obj->sha1);
+ bad_object(delta_obj->idx.offset, "failed to apply delta");
+ sha1_object(result, result_size, type, delta_obj->idx.sha1);
nr_resolved_deltas++;
- hashcpy(delta_base.sha1, delta_obj->sha1);
+ hashcpy(delta_base.sha1, delta_obj->idx.sha1);
if (!find_delta_children(&delta_base, &first, &last)) {
for (j = first; j <= last; j++) {
struct object_entry *child = objects + deltas[j].obj_no;
@@ -374,7 +372,7 @@ static void resolve_delta(struct object_entry *delta_obj, void *base_data,
}
memset(&delta_base, 0, sizeof(delta_base));
- delta_base.offset = delta_obj->offset;
+ delta_base.offset = delta_obj->idx.offset;
if (!find_delta_children(&delta_base, &first, &last)) {
for (j = first; j <= last; j++) {
struct object_entry *child = objects + deltas[j].obj_no;
@@ -418,12 +416,12 @@ static void parse_pack_objects(unsigned char *sha1)
delta->obj_no = i;
delta++;
} else
- sha1_object(data, obj->size, obj->type, obj->sha1);
+ sha1_object(data, obj->size, obj->type, obj->idx.sha1);
free(data);
if (verbose)
display_progress(&progress, i+1);
}
- objects[i].offset = consumed_bytes;
+ objects[i].idx.offset = consumed_bytes;
if (verbose)
stop_progress(&progress);
@@ -465,10 +463,10 @@ static void parse_pack_objects(unsigned char *sha1)
if (obj->type == OBJ_REF_DELTA || obj->type == OBJ_OFS_DELTA)
continue;
- hashcpy(base.sha1, obj->sha1);
+ hashcpy(base.sha1, obj->idx.sha1);
ref = !find_delta_children(&base, &ref_first, &ref_last);
memset(&base, 0, sizeof(base));
- base.offset = obj->offset;
+ base.offset = obj->idx.offset;
ofs = !find_delta_children(&base, &ofs_first, &ofs_last);
if (!ref && !ofs)
continue;
@@ -535,11 +533,11 @@ static void append_obj_to_pack(const unsigned char *sha1, void *buf,
}
header[n++] = c;
write_or_die(output_fd, header, n);
- obj[0].crc32 = crc32(0, Z_NULL, 0);
- obj[0].crc32 = crc32(obj[0].crc32, header, n);
- obj[1].offset = obj[0].offset + n;
- obj[1].offset += write_compressed(output_fd, buf, size, &obj[0].crc32);
- hashcpy(obj->sha1, sha1);
+ obj[0].idx.crc32 = crc32(0, Z_NULL, 0);
+ obj[0].idx.crc32 = crc32(obj[0].idx.crc32, header, n);
+ obj[1].idx.offset = obj[0].idx.offset + n;
+ obj[1].idx.offset += write_compressed(output_fd, buf, size, &obj[0].idx.crc32);
+ hashcpy(obj->idx.sha1, sha1);
}
static int delta_pos_compare(const void *_a, const void *_b)
@@ -602,145 +600,6 @@ static void fix_unresolved_deltas(int nr_unresolved)
free(sorted_by_pos);
}
-static uint32_t index_default_version = 1;
-static uint32_t index_off32_limit = 0x7fffffff;
-
-static int sha1_compare(const void *_a, const void *_b)
-{
- struct object_entry *a = *(struct object_entry **)_a;
- struct object_entry *b = *(struct object_entry **)_b;
- return hashcmp(a->sha1, b->sha1);
-}
-
-/*
- * On entry *sha1 contains the pack content SHA1 hash, on exit it is
- * the SHA1 hash of sorted object names.
- */
-static const char *write_index_file(const char *index_name, unsigned char *sha1)
-{
- struct sha1file *f;
- struct object_entry **sorted_by_sha, **list, **last;
- uint32_t array[256];
- int i, fd;
- SHA_CTX ctx;
- uint32_t index_version;
-
- if (nr_objects) {
- sorted_by_sha =
- xcalloc(nr_objects, sizeof(struct object_entry *));
- list = sorted_by_sha;
- last = sorted_by_sha + nr_objects;
- for (i = 0; i < nr_objects; ++i)
- sorted_by_sha[i] = &objects[i];
- qsort(sorted_by_sha, nr_objects, sizeof(sorted_by_sha[0]),
- sha1_compare);
- }
- else
- sorted_by_sha = list = last = NULL;
-
- if (!index_name) {
- static char tmpfile[PATH_MAX];
- snprintf(tmpfile, sizeof(tmpfile),
- "%s/tmp_idx_XXXXXX", get_object_directory());
- fd = mkstemp(tmpfile);
- index_name = xstrdup(tmpfile);
- } else {
- unlink(index_name);
- fd = open(index_name, O_CREAT|O_EXCL|O_WRONLY, 0600);
- }
- if (fd < 0)
- die("unable to create %s: %s", index_name, strerror(errno));
- f = sha1fd(fd, index_name);
-
- /* if last object's offset is >= 2^31 we should use index V2 */
- index_version = (objects[nr_objects-1].offset >> 31) ? 2 : index_default_version;
-
- /* index versions 2 and above need a header */
- if (index_version >= 2) {
- struct pack_idx_header hdr;
- hdr.idx_signature = htonl(PACK_IDX_SIGNATURE);
- hdr.idx_version = htonl(index_version);
- sha1write(f, &hdr, sizeof(hdr));
- }
-
- /*
- * Write the first-level table (the list is sorted,
- * but we use a 256-entry lookup to be able to avoid
- * having to do eight extra binary search iterations).
- */
- for (i = 0; i < 256; i++) {
- struct object_entry **next = list;
- while (next < last) {
- struct object_entry *obj = *next;
- if (obj->sha1[0] != i)
- break;
- next++;
- }
- array[i] = htonl(next - sorted_by_sha);
- list = next;
- }
- sha1write(f, array, 256 * 4);
-
- /* compute the SHA1 hash of sorted object names. */
- SHA1_Init(&ctx);
-
- /*
- * Write the actual SHA1 entries..
- */
- list = sorted_by_sha;
- for (i = 0; i < nr_objects; i++) {
- struct object_entry *obj = *list++;
- if (index_version < 2) {
- uint32_t offset = htonl(obj->offset);
- sha1write(f, &offset, 4);
- }
- sha1write(f, obj->sha1, 20);
- SHA1_Update(&ctx, obj->sha1, 20);
- }
-
- if (index_version >= 2) {
- unsigned int nr_large_offset = 0;
-
- /* write the crc32 table */
- list = sorted_by_sha;
- for (i = 0; i < nr_objects; i++) {
- struct object_entry *obj = *list++;
- uint32_t crc32_val = htonl(obj->crc32);
- sha1write(f, &crc32_val, 4);
- }
-
- /* write the 32-bit offset table */
- list = sorted_by_sha;
- for (i = 0; i < nr_objects; i++) {
- struct object_entry *obj = *list++;
- uint32_t offset = (obj->offset <= index_off32_limit) ?
- obj->offset : (0x80000000 | nr_large_offset++);
- offset = htonl(offset);
- sha1write(f, &offset, 4);
- }
-
- /* write the large offset table */
- list = sorted_by_sha;
- while (nr_large_offset) {
- struct object_entry *obj = *list++;
- uint64_t offset = obj->offset;
- if (offset > index_off32_limit) {
- uint32_t split[2];
- split[0] = htonl(offset >> 32);
- split[1] = htonl(offset & 0xffffffff);
- sha1write(f, split, 8);
- nr_large_offset--;
- }
- }
- }
-
- sha1write(f, sha1, 20);
- sha1close(f, NULL, 1);
- free(sorted_by_sha);
- SHA1_Final(sha1, &ctx);
- return index_name;
-}
-
static void final(const char *final_pack_name, const char *curr_pack_name,
const char *final_index_name, const char *curr_index_name,
const char *keep_name, const char *keep_msg,
@@ -830,6 +689,7 @@ int main(int argc, char **argv)
const char *curr_index, *index_name = NULL;
const char *keep_name = NULL, *keep_msg = NULL;
char *index_name_buf = NULL, *keep_name_buf = NULL;
+ struct pack_idx_entry **idx_objects;
unsigned char sha1[20];
for (i = 1; i < argc; i++) {
@@ -865,12 +725,12 @@ int main(int argc, char **argv)
index_name = argv[++i];
} else if (!prefixcmp(arg, "--index-version=")) {
char *c;
- index_default_version = strtoul(arg + 16, &c, 10);
- if (index_default_version > 2)
+ pack_idx_default_version = strtoul(arg + 16, &c, 10);
+ if (pack_idx_default_version > 2)
die("bad %s", arg);
if (*c == ',')
- index_off32_limit = strtoul(c+1, &c, 0);
- if (*c || index_off32_limit & 0x80000000)
+ pack_idx_off32_limit = strtoul(c+1, &c, 0);
+ if (*c || pack_idx_off32_limit & 0x80000000)
die("bad %s", arg);
} else
usage(index_pack_usage);
@@ -940,7 +800,13 @@ int main(int argc, char **argv)
nr_deltas - nr_resolved_deltas);
}
free(deltas);
- curr_index = write_index_file(index_name, sha1);
+
+ idx_objects = xmalloc((nr_objects) * sizeof(struct pack_idx_entry *));
+ for (i = 0; i < nr_objects; i++)
+ idx_objects[i] = &objects[i].idx;
+ curr_index = write_idx_file(index_name, idx_objects, nr_objects, sha1);
+ free(idx_objects);
+
final(pack_name, curr_pack,
index_name, curr_index,
keep_name, keep_msg,
diff --git a/pack-write.c b/pack-write.c
index ae2e481..1cf5f7c 100644
--- a/pack-write.c
+++ b/pack-write.c
@@ -1,5 +1,147 @@
#include "cache.h"
#include "pack.h"
+#include "csum-file.h"
+
+uint32_t pack_idx_default_version = 1;
+uint32_t pack_idx_off32_limit = 0x7fffffff;
+
+static int sha1_compare(const void *_a, const void *_b)
+{
+ struct pack_idx_entry *a = *(struct pack_idx_entry **)_a;
+ struct pack_idx_entry *b = *(struct pack_idx_entry **)_b;
+ return hashcmp(a->sha1, b->sha1);
+}
+
+/*
+ * On entry *sha1 contains the pack content SHA1 hash, on exit it is
+ * the SHA1 hash of sorted object names. The objects array passed in
+ * will be sorted by SHA1 on exit.
+ */
+const char *write_idx_file(const char *index_name, struct pack_idx_entry **objects, int nr_objects, unsigned char *sha1)
+{
+ struct sha1file *f;
+ struct pack_idx_entry **sorted_by_sha, **list, **last;
+ off_t last_obj_offset = 0;
+ uint32_t array[256];
+ int i, fd;
+ SHA_CTX ctx;
+ uint32_t index_version;
+
+ if (nr_objects) {
+ sorted_by_sha = objects;
+ list = sorted_by_sha;
+ last = sorted_by_sha + nr_objects;
+ for (i = 0; i < nr_objects; ++i) {
+ if (objects[i]->offset > last_obj_offset)
+ last_obj_offset = objects[i]->offset;
+ }
+ qsort(sorted_by_sha, nr_objects, sizeof(sorted_by_sha[0]),
+ sha1_compare);
+ }
+ else
+ sorted_by_sha = list = last = NULL;
+
+ if (!index_name) {
+ static char tmpfile[PATH_MAX];
+ snprintf(tmpfile, sizeof(tmpfile),
+ "%s/tmp_idx_XXXXXX", get_object_directory());
+ fd = mkstemp(tmpfile);
+ index_name = xstrdup(tmpfile);
+ } else {
+ unlink(index_name);
+ fd = open(index_name, O_CREAT|O_EXCL|O_WRONLY, 0600);
+ }
+ if (fd < 0)
+ die("unable to create %s: %s", index_name, strerror(errno));
+ f = sha1fd(fd, index_name);
+
+ /* if last object's offset is >= 2^31 we should use index V2 */
+ index_version = (last_obj_offset >> 31) ? 2 : pack_idx_default_version;
+
+ /* index versions 2 and above need a header */
+ if (index_version >= 2) {
+ struct pack_idx_header hdr;
+ hdr.idx_signature = htonl(PACK_IDX_SIGNATURE);
+ hdr.idx_version = htonl(index_version);
+ sha1write(f, &hdr, sizeof(hdr));
+ }
+
+ /*
+ * Write the first-level table (the list is sorted,
+ * but we use a 256-entry lookup to be able to avoid
+ * having to do eight extra binary search iterations).
+ */
+ for (i = 0; i < 256; i++) {
+ struct pack_idx_entry **next = list;
+ while (next < last) {
+ struct pack_idx_entry *obj = *next;
+ if (obj->sha1[0] != i)
+ break;
+ next++;
+ }
+ array[i] = htonl(next - sorted_by_sha);
+ list = next;
+ }
+ sha1write(f, array, 256 * 4);
+
+ /* compute the SHA1 hash of sorted object names. */
+ SHA1_Init(&ctx);
+
+ /*
+ * Write the actual SHA1 entries..
+ */
+ list = sorted_by_sha;
+ for (i = 0; i < nr_objects; i++) {
+ struct pack_idx_entry *obj = *list++;
+ if (index_version < 2) {
+ uint32_t offset = htonl(obj->offset);
+ sha1write(f, &offset, 4);
+ }
+ sha1write(f, obj->sha1, 20);
+ SHA1_Update(&ctx, obj->sha1, 20);
+ }
+
+ if (index_version >= 2) {
+ unsigned int nr_large_offset = 0;
+
+ /* write the crc32 table */
+ list = sorted_by_sha;
+ for (i = 0; i < nr_objects; i++) {
+ struct pack_idx_entry *obj = *list++;
+ uint32_t crc32_val = htonl(obj->crc32);
+ sha1write(f, &crc32_val, 4);
+ }
+
+ /* write the 32-bit offset table */
+ list = sorted_by_sha;
+ for (i = 0; i < nr_objects; i++) {
+ struct pack_idx_entry *obj = *list++;
+ uint32_t offset = (obj->offset <= pack_idx_off32_limit) ?
+ obj->offset : (0x80000000 | nr_large_offset++);
+ offset = htonl(offset);
+ sha1write(f, &offset, 4);
+ }
+
+ /* write the large offset table */
+ list = sorted_by_sha;
+ while (nr_large_offset) {
+ struct pack_idx_entry *obj = *list++;
+ uint64_t offset = obj->offset;
+ if (offset > pack_idx_off32_limit) {
+ uint32_t split[2];
+ split[0] = htonl(offset >> 32);
+ split[1] = htonl(offset & 0xffffffff);
+ sha1write(f, split, 8);
+ nr_large_offset--;
+ }
+ }
+ }
+
+ sha1write(f, sha1, 20);
+ sha1close(f, NULL, 1);
+ SHA1_Final(sha1, &ctx);
+ return index_name;
+}
void fixup_pack_header_footer(int pack_fd,
unsigned char *pack_file_sha1,
diff --git a/pack.h b/pack.h
index d667fb8..f357c9f 100644
--- a/pack.h
+++ b/pack.h
@@ -34,6 +34,10 @@ struct pack_header {
*/
#define PACK_IDX_SIGNATURE 0xff744f63 /* "\377tOc" */
+/* These may be overridden by command-line parameters */
+extern uint32_t pack_idx_default_version;
+extern uint32_t pack_idx_off32_limit;
+
/*
* Packed object index header
*/
@@ -42,6 +46,16 @@ struct pack_idx_header {
uint32_t idx_version;
};
+/*
+ * Common part of object structure used for write_idx_file
+ */
+struct pack_idx_entry {
+ unsigned char sha1[20];
+ uint32_t crc32;
+ off_t offset;
+};
+
+extern const char *write_idx_file(const char *index_name, struct pack_idx_entry **objects, int nr_objects, unsigned char *sha1);
extern int verify_pack(struct packed_git *, int);
extern void fixup_pack_header_footer(int, unsigned char *, const char *, uint32_t);
--
1.5.1
^ permalink raw reply related
* Re: [mingw port] git plumbing piping with CR/NL
From: Johannes Schindelin @ 2007-06-02 1:31 UTC (permalink / raw)
To: Nguyen Thai Ngoc Duy; +Cc: Alex Riesen, Git Mailing List, Johannes Sixt
In-Reply-To: <fcaeb9bf0706011656p2145afe0k8be9797d250566df@mail.gmail.com>
Hi,
On Fri, 1 Jun 2007, Nguyen Thai Ngoc Duy wrote:
> On 6/1/07, Alex Riesen <raa.lkml@gmail.com> wrote:
>
> > Why does your grep _alters_ the input, instead of filtering it, btw?
>
> I have no idea. It's grep from MKS Toolkit FYI.
Your subject says "[mingw port]". You should have mentioned that you use a
mixed setup, as the mingw port still depends on msys for the scripts.
Ciao,
Dscho
^ permalink raw reply
* Re: [mingw port] git plumbing piping with CR/NL
From: Sam Vilain @ 2007-06-02 1:31 UTC (permalink / raw)
To: Alex Riesen; +Cc: Nguyen Thai Ngoc Duy, Git Mailing List, Johannes Sixt
In-Reply-To: <20070601231816.GC6360@steel.home>
Alex Riesen wrote:
> > Apparently git should ignore \r at the end of the path. ...
> Why should it? \r is a valid character in filenames almost everywhere
> (except for the some proprietary OSes, as usual).
>
So is \n!
Sam.
^ permalink raw reply
* [PATCH] Add basic test-script for git-submodule
From: Lars Hjemli @ 2007-06-02 1:27 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Johannes Sixt, Johannes Schindelin, git
In-Reply-To: <7vmyzjzc76.fsf@assigned-by-dhcp.cox.net>
This test tries to verify basic sanity of git-submodule, i.e. that it is
able to clone and update a submodule repository, that its status output is
sane, and that it barfs when the submodule path is occupied during init.
Signed-off-by: Lars Hjemli <hjemli@gmail.com>
---
On 6/1/07, Junio C Hamano <junkio@cox.net> wrote:
> "Lars Hjemli" <hjemli@gmail.com> writes:
> > +test_expect_success 'the --cached sha1 should be rev1' '
> > + git-submodule --cached status | grep "^\+$rev1"
> > +'
>
> What's the purpose of that solitary backslash?
That's just a sign of me being sloppy, expecting the behaviour of 'grep -E' without
bothering to study the man-page. Sorry.
t/t7400-submodule-basic.sh | 143 ++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 143 insertions(+), 0 deletions(-)
create mode 100755 t/t7400-submodule-basic.sh
diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
new file mode 100755
index 0000000..6274729
--- /dev/null
+++ b/t/t7400-submodule-basic.sh
@@ -0,0 +1,143 @@
+#!/bin/sh
+#
+# Copyright (c) 2007 Lars Hjemli
+#
+
+test_description='Basic porcelain support for submodules
+
+This test tries to verify basic sanity of the init, update and status
+subcommands of git-submodule.
+'
+
+. ./test-lib.sh
+
+#
+# Test setup:
+# -create a repository in directory lib
+# -add a couple of files
+# -add directory lib to 'superproject', this creates a DIRLINK entry
+# -add a couple of regular files to enable testing of submodule filtering
+# -mv lib subrepo
+# -add an entry to .gitmodules for path 'lib'
+#
+test_expect_success 'Prepare submodule testing' '
+ mkdir lib &&
+ cd lib &&
+ git-init &&
+ echo a >a &&
+ git-add a &&
+ git-commit -m "submodule commit 1" &&
+ git-tag -a -m "rev-1" rev-1 &&
+ rev1=$(git-rev-parse HEAD) &&
+ if test -z "$rev1"
+ then
+ echo "[OOPS] submodule git-rev-parse returned nothing"
+ false
+ fi &&
+ cd .. &&
+ echo a >a &&
+ echo z >z &&
+ git-add a lib z &&
+ git-commit -m "super commit 1" &&
+ mv lib .subrepo &&
+ GIT_CONFIG=.gitmodules git-config module.lib.url ./.subrepo
+'
+
+test_expect_success 'status should only print one line' '
+ lines=$(git-submodule status | wc -l) &&
+ test $lines = 1
+'
+
+test_expect_success 'status should initially be "missing"' '
+ git-submodule status | grep "^-$rev1"
+'
+
+test_expect_success 'init should fail when path is used by a file' '
+ echo "hello" >lib &&
+ if git-submodule init
+ then
+ echo "[OOPS] init should have failed"
+ false
+ elif test -f lib && test "$(cat lib)" != "hello"
+ then
+ echo "[OOPS] init failed but lib file was molested"
+ false
+ else
+ rm lib
+ fi
+'
+
+test_expect_success 'init should fail when path is used by a nonempty directory' '
+ mkdir lib &&
+ echo "hello" >lib/a &&
+ if git-submodule init
+ then
+ echo "[OOPS] init should have failed"
+ false
+ elif test "$(cat lib/a)" != "hello"
+ then
+ echo "[OOPS] init failed but lib/a was molested"
+ false
+ else
+ rm lib/a
+ fi
+'
+
+test_expect_success 'init should work when path is an empty dir' '
+ rm -rf lib &&
+ mkdir lib &&
+ git-submodule init &&
+ head=$(cd lib && git-rev-parse HEAD) &&
+ if test -z "$head"
+ then
+ echo "[OOPS] Failed to obtain submodule head"
+ false
+ elif test "$head" != "$rev1"
+ then
+ echo "[OOPS] Submodule head is $head but should have been $rev1"
+ false
+ fi
+'
+
+test_expect_success 'status should be "up-to-date" after init' '
+ git-submodule status | grep "^ $rev1"
+'
+
+test_expect_success 'status should be "modified" after submodule commit' '
+ cd lib &&
+ echo b >b &&
+ git-add b &&
+ git-commit -m "submodule commit 2" &&
+ rev2=$(git-rev-parse HEAD) &&
+ cd .. &&
+ if test -z "$rev2"
+ then
+ echo "[OOPS] submodule git-rev-parse returned nothing"
+ false
+ fi &&
+ git-submodule status | grep "^+$rev2"
+'
+
+test_expect_success 'the --cached sha1 should be rev1' '
+ git-submodule --cached status | grep "^+$rev1"
+'
+
+test_expect_success 'update should checkout rev1' '
+ git-submodule update &&
+ head=$(cd lib && git-rev-parse HEAD) &&
+ if test -z "$head"
+ then
+ echo "[OOPS] submodule git-rev-parse returned nothing"
+ false
+ elif test "$head" != "$rev1"
+ then
+ echo "[OOPS] init did not checkout correct head"
+ false
+ fi
+'
+
+test_expect_success 'status should be "up-to-date" after update' '
+ git-submodule status | grep "^ $rev1"
+'
+
+test_done
--
1.5.2.839.ga3b1-dirty
^ permalink raw reply related
* [PATCH] Create a new manpage for the gitignore format, and reference it elsewhere
From: Josh Triplett @ 2007-06-02 1:01 UTC (permalink / raw)
To: git; +Cc: 427078, Frank Lichtenheld, Junio C Hamano
[-- Attachment #1: Type: text/plain, Size: 14580 bytes --]
Only git-ls-files(1) describes the gitignore format in detail, and it does so
with reference to git-ls-files options. Most users don't use the plumbing
command git-ls-files directly, and shouldn't have to look in its manpage for
information on the gitignore format.
Create a new manpage gitignore(5) (Documentation/gitignore.txt), and factor
out the gitignore documentation into that file, changing it to refer to
.gitignore and $GIT_DIR/info/exclude as used by porcelain commands. Reference
gitignore(5) from other relevant manpages and documentation. Remove
now-redundant information on exclude patterns from git-ls-files(1), leaving
only information on how git-ls-files options specify exclude patterns and what
precedence they have.
Signed-off-by: Josh Triplett <josh@freedesktop.org>
---
New version; fixes issues pointed out by Junio C Hamano and Frank Lichtenheld.
Documentation/Makefile | 2 +-
Documentation/config.txt | 3 +-
Documentation/git-ls-files.txt | 99 +++++-----------------------------
Documentation/git-read-tree.txt | 3 +-
Documentation/git-status.txt | 8 +--
Documentation/gitignore.txt | 102 +++++++++++++++++++++++++++++++++++
Documentation/repository-layout.txt | 3 +-
Documentation/user-manual.txt | 12 ++--
8 files changed, 131 insertions(+), 101 deletions(-)
create mode 100644 Documentation/gitignore.txt
diff --git a/Documentation/Makefile b/Documentation/Makefile
index 3f92783..ef4425c 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -2,7 +2,7 @@ MAN1_TXT= \
$(filter-out $(addsuffix .txt, $(ARTICLES) $(SP_ARTICLES)), \
$(wildcard git-*.txt)) \
gitk.txt
-MAN5_TXT=gitattributes.txt
+MAN5_TXT=gitattributes.txt gitignore.txt
MAN7_TXT=git.txt
DOC_HTML=$(patsubst %.txt,%.html,$(MAN1_TXT) $(MAN5_TXT) $(MAN7_TXT))
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 3d8f03d..bb4d6e0 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -259,7 +259,8 @@ Common unit suffixes of 'k', 'm', or 'g' are supported.
core.excludeFile::
In addition to '.gitignore' (per-directory) and
'.git/info/exclude', git looks into this file for patterns
- of files which are not meant to be tracked.
+ of files which are not meant to be tracked. See
+ gitlink:gitignore[5].
alias.*::
Command aliases for the gitlink:git[1] command wrapper - e.g.
diff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt
index 43e0d22..a78a9ff 100644
--- a/Documentation/git-ls-files.txt
+++ b/Documentation/git-ls-files.txt
@@ -139,46 +139,24 @@ Exclude Patterns
'git-ls-files' can use a list of "exclude patterns" when
traversing the directory tree and finding files to show when the
-flags --others or --ignored are specified.
+flags --others or --ignored are specified. gitlink:gitignore[5]
+specifies the format of exclude patterns.
-These exclude patterns come from these places:
+These exclude patterns come from these places, in order:
- 1. command line flag --exclude=<pattern> specifies a single
- pattern.
+ 1. The command line flag --exclude=<pattern> specifies a
+ single pattern. Patterns are ordered in the same order
+ they appear in the command line.
- 2. command line flag --exclude-from=<file> specifies a list of
- patterns stored in a file.
+ 2. The command line flag --exclude-from=<file> specifies a
+ file containing a list of patterns. Patterns are ordered
+ in the same order they appear in the file.
3. command line flag --exclude-per-directory=<name> specifies
a name of the file in each directory 'git-ls-files'
- examines, and if exists, its contents are used as an
- additional list of patterns.
-
-An exclude pattern file used by (2) and (3) contains one pattern
-per line. A line that starts with a '#' can be used as comment
-for readability.
-
-There are three lists of patterns that are in effect at a given
-time. They are built and ordered in the following way:
-
- * --exclude=<pattern> from the command line; patterns are
- ordered in the same order as they appear on the command line.
-
- * lines read from --exclude-from=<file>; patterns are ordered
- in the same order as they appear in the file.
-
- * When --exclude-per-directory=<name> is specified, upon
- entering a directory that has such a file, its contents are
- appended at the end of the current "list of patterns". They
- are popped off when leaving the directory.
-
-Each pattern in the pattern list specifies "a match pattern" and
-optionally the fate; either a file that matches the pattern is
-considered excluded or included. A filename is matched against
-the patterns in the three lists; the --exclude-from list is
-checked first, then the --exclude-per-directory list, and then
-finally the --exclude list. The last match determines its fate.
-If there is no match in the three lists, the fate is "included".
+ examines, normally `.gitignore`. Files in deeper
+ directories take precedence. Patterns are ordered in the
+ same order they appear in the files.
A pattern specified on the command line with --exclude or read
from the file specified with --exclude-from is relative to the
@@ -186,58 +164,9 @@ top of the directory tree. A pattern read from a file specified
by --exclude-per-directory is relative to the directory that the
pattern file appears in.
-An exclude pattern is of the following format:
-
- - an optional prefix '!' which means that the fate this pattern
- specifies is "include", not the usual "exclude"; the
- remainder of the pattern string is interpreted according to
- the following rules.
-
- - if it does not contain a slash '/', it is a shell glob
- pattern and used to match against the filename without
- leading directories.
-
- - otherwise, it is a shell glob pattern, suitable for
- consumption by fnmatch(3) with FNM_PATHNAME flag. I.e. a
- slash in the pattern must match a slash in the pathname.
- "Documentation/\*.html" matches "Documentation/git.html" but
- not "ppc/ppc.html". As a natural exception, "/*.c" matches
- "cat-file.c" but not "mozilla-sha1/sha1.c".
-
-An example:
-
---------------------------------------------------------------
- $ cat .git/info/exclude
- # ignore objects and archives, anywhere in the tree.
- *.[oa]
- $ cat Documentation/.gitignore
- # ignore generated html files,
- *.html
- # except foo.html which is maintained by hand
- !foo.html
- $ git-ls-files --ignored \
- --exclude='Documentation/*.[0-9]' \
- --exclude-from=.git/info/exclude \
- --exclude-per-directory=.gitignore
---------------------------------------------------------------
-
-Another example:
-
---------------------------------------------------------------
- $ cat .gitignore
- vmlinux*
- $ ls arch/foo/kernel/vm*
- arch/foo/kernel/vmlinux.lds.S
- $ echo '!/vmlinux*' >arch/foo/kernel/.gitignore
---------------------------------------------------------------
-
-The second .gitignore keeps `arch/foo/kernel/vmlinux.lds.S` file
-from getting ignored.
-
-
See Also
--------
-gitlink:git-read-tree[1]
+gitlink:git-read-tree[1], gitlink:gitignore[5]
Author
@@ -246,7 +175,7 @@ Written by Linus Torvalds <torvalds@osdl.org>
Documentation
--------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
+Documentation by David Greaves, Junio C Hamano, Josh Triplett, and the git-list <git@vger.kernel.org>.
GIT
---
diff --git a/Documentation/git-read-tree.txt b/Documentation/git-read-tree.txt
index 019c8be..acb5744 100644
--- a/Documentation/git-read-tree.txt
+++ b/Documentation/git-read-tree.txt
@@ -341,7 +341,8 @@ have finished your work-in-progress), attempt the merge again.
See Also
--------
-gitlink:git-write-tree[1]; gitlink:git-ls-files[1]
+gitlink:git-write-tree[1]; gitlink:git-ls-files[1];
+gitlink:gitignore[5]
Author
diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt
index d701538..1fd1af1 100644
--- a/Documentation/git-status.txt
+++ b/Documentation/git-status.txt
@@ -42,11 +42,9 @@ mean the same thing and the latter is kept for backward
compatibility) and `color.status.<slot>` configuration variables
to colorize its output.
-As for gitlink:git-add[1], the configuration variable
-'core.excludesfile' can indicate a path to a file containing patterns
-of file names to exclude, in addition to patterns given in
-'info/exclude' and '.gitignore'.
-
+See Also
+--------
+gitlink:gitignore[5]
Author
------
diff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt
new file mode 100644
index 0000000..c774ff0
--- /dev/null
+++ b/Documentation/gitignore.txt
@@ -0,0 +1,102 @@
+gitignore(5)
+============
+
+NAME
+----
+gitignore - Specifies intentionally untracked files to ignore
+
+SYNOPSIS
+--------
+$GIT_DIR/info/exclude, .gitignore
+
+DESCRIPTION
+-----------
+
+A `gitignore` file specifies intentionally untracked files that
+git should ignore. Each line in a `gitignore` file specifies a
+pattern.
+
+When deciding whether to ignore a path, git normally checks
+`gitignore` patterns from multiple sources, with the following
+order of precedence:
+
+ * Patterns read from the file specified by the configuration
+ variable 'core.excludesfile'.
+
+ * Patterns read from `$GIT_DIR/info/exclude`.
+
+ * Patterns read from a `.gitignore` file in the same directory
+ as the path, or in any parent directory, ordered from the
+ deepest such file to a file in the root of the repository.
+ These patterns match relative to the location of the
+ `.gitignore` file. A project normally includes such
+ `.gitignore` files in its repository, containing patterns for
+ files generated as part of the project build.
+
+The underlying git plumbing tools, such as
+gitlink:git-ls-files[1] and gitlink:git-read-tree[1], read
+`gitignore` patterns specified by command-line options, or from
+files specified by command-line options. Higher-level git
+tools, such as gitlink:git-status[1] and gitlink:git-add[1],
+use patterns from the sources specified above.
+
+Patterns have the following format:
+
+ - A blank line matches no files, so it can serve as a separator
+ for readability.
+
+ - A line starting with # serves as a comment.
+
+ - An optional prefix '!' which negates the pattern; any
+ matching file excluded by a previous pattern will become
+ included again.
+
+ - If the pattern does not contain a slash '/', git treats it as
+ a shell glob pattern and checks for a match against the
+ pathname without leading directories.
+
+ - Otherwise, git treats the pattern as a shell glob suitable
+ for consumption by fnmatch(3) with the FNM_PATHNAME flag: any
+ slash in the pattern must match a slash in the pathname. For
+ example, "Documentation/\*.html" matches
+ "Documentation/git.html" but not "ppc/ppc.html". A leading
+ slash matches the beginning of the pathname; for example,
+ "/*.c" matches "cat-file.c" but not "mozilla-sha1/sha1.c".
+
+An example:
+
+--------------------------------------------------------------
+ $ cat .git/info/exclude
+ # ignore objects and archives, anywhere in the tree.
+ *.[oa]
+ $ cat Documentation/.gitignore
+ # ignore generated html files,
+ *.html
+ # except foo.html which is maintained by hand
+ !foo.html
+ $ git-ls-files --ignored \
+ --exclude='Documentation/*.[0-9]' \
+ --exclude-from=.git/info/exclude \
+ --exclude-per-directory=.gitignore
+--------------------------------------------------------------
+
+Another example:
+
+--------------------------------------------------------------
+ $ cat .gitignore
+ vmlinux*
+ $ ls arch/foo/kernel/vm*
+ arch/foo/kernel/vmlinux.lds.S
+ $ echo '!/vmlinux*' >arch/foo/kernel/.gitignore
+--------------------------------------------------------------
+
+The second .gitignore prevents git from ignoring
+`arch/foo/kernel/vmlinux.lds.S`.
+
+Documentation
+-------------
+Documentation by David Greaves, Junio C Hamano, Josh Triplett, and the git-list <git@vger.kernel.org>.
+
+GIT
+---
+Part of the gitlink:git[7] suite
diff --git a/Documentation/repository-layout.txt b/Documentation/repository-layout.txt
index 0459bd9..15221b5 100644
--- a/Documentation/repository-layout.txt
+++ b/Documentation/repository-layout.txt
@@ -155,8 +155,7 @@ info/exclude::
exclude pattern list. `.gitignore` is the per-directory
ignore file. `git status`, `git add`, `git rm` and `git
clean` look at it but the core git commands do not look
- at it. See also: gitlink:git-ls-files[1] `--exclude-from`
- and `--exclude-per-directory`.
+ at it. See also: gitlink:gitignore[5].
remotes::
Stores shorthands to be used to give URL and default
diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt
index 4fabb8e..7eaafa8 100644
--- a/Documentation/user-manual.txt
+++ b/Documentation/user-manual.txt
@@ -1103,12 +1103,12 @@ showing up in the output of "`git status`", etc.
Git therefore provides "exclude patterns" for telling git which files to
actively ignore. Exclude patterns are thoroughly explained in the
-"Exclude Patterns" section of the gitlink:git-ls-files[1] manual page,
-but the heart of the concept is simply a list of files which git should
-ignore. Entries in the list may contain globs to specify multiple files,
-or may be prefixed by "`!`" to explicitly include (un-ignore) a previously
-excluded (ignored) file (i.e. later exclude patterns override earlier ones).
-The following example should illustrate such patterns:
+gitlink:gitignore[5] manual page, but the heart of the concept is simply
+a list of files which git should ignore. Entries in the list may contain
+globs to specify multiple files, or may be prefixed by "`!`" to
+explicitly include (un-ignore) a previously excluded (ignored) file
+(i.e. later exclude patterns override earlier ones). The following
+example should illustrate such patterns:
-------------------------------------------------
# Lines starting with '#' are considered comments.
--
1.5.2
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 252 bytes --]
^ permalink raw reply related
* Re: [PATCH] Create a new manpage for the gitignore format, and reference it elsewhere
From: Josh Triplett @ 2007-06-02 0:52 UTC (permalink / raw)
To: Frank Lichtenheld; +Cc: git, 427078
In-Reply-To: <20070601234710.GW3242@planck.djpig.de>
[-- Attachment #1: Type: text/plain, Size: 2947 bytes --]
Frank Lichtenheld wrote:
> On Fri, Jun 01, 2007 at 03:20:52PM -0700, Josh Triplett wrote:
>> Signed-off-by: Josh Triplett <josh@freedesktop.org>
>> Signed-off-by: Josh Triplett <josh@freedesktop.org>
>
> :) (Wanted to make some funny remark, but its too late here to be funny
> in a foreign language...)
Argh. git-commit -s --amend signed a second time. Sorry I missed this.
>> Documentation
>> --------------
>> -Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
>> +Documentation by David Greaves, Junio C Hamano, Josh Triplett, and the git-list <git@vger.kernel.org>.
>
> No offence, but adding your name here for removing content? ;)
I intentionally avoided adding my name to the pages in which I only removed
content, or only added a reference to gitignore(5). In the case of
git-ls-files, I rewrote some of the material. However, I don't care that
strongly about the credit.
>> +Some git plumbing tools, such as git-ls-files(1) and
>> +git-read-tree(1), read `gitignore` patterns specified by
>> +command-line options, or from files specified by command-line
>> +options.
>
> Missing gitlink:
Ah, good point.
> Also I don't like the paragraph. It should probably mention that
> these programs actually implement the behaviour described, that
> they aren't hardcoded to the mentioned filenames and that
> all git porcelain just happens to call them with them.
That seems like an implementation detail, only relevant to users of
git-ls-files and git-read-tree.
>> +Patterns have the following format:
>> +
>> + - A blank line matches no files, so it can serve as a separator
>> + for readability.
>> +
>> + - A line starting with #
>
> Is here missing something?
Oops. Yes, this should have said:
- A line starting with # serves as a comment.
>> + - Otherwise, git treats the pattern as a shell glob suitable
>> + for consumption by fnmatch(3) with the FNM_PATHNAME flag: any
>> + slash in the pattern must match a slash in the pathname. For
>> + example, "Documentation/\*.html" matches
>> + "Documentation/git.html" but not "ppc/ppc.html". A leading
>> + slash matches the beginning of the pathname; for example,
>> + "/*.c" matches "cat-file.c" but not "mozilla-sha1/sha1.c".
>
> I realise this is copy&paste but shouldn't that read:
> "Documentation/\*.html" matches "Documentation/git.html"
> but not "Documentation/ppc/ppc.html"
> ?
I don't know. Neither file seems to exist in current Git.
>> +Documentation
>> +-------------
>> +Documentation by Josh Triplett.
>
> No offence again, but given the amount of copy&paste, maybe the names from
> git-ls-files should also be added here.
Entirely correct; I don't know why I missed that, as I had intended to copy those
names. My apologies.
Expect an updated patch shortly, to fix the issues you pointed out.
- Josh Triplett
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 252 bytes --]
^ 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