Merge branch 'master' into js/c-merge-recursive

Adjust to hold_lock_file_for_update() change on the master.
This commit is contained in:
Junio C Hamano 2006-08-12 18:34:36 -07:00
commit eed94a570e
84 changed files with 1487 additions and 480 deletions

View File

@ -83,9 +83,12 @@ core.repositoryFormatVersion::
version. version.
core.sharedRepository:: core.sharedRepository::
If true, the repository is made shareable between several users When 'group' (or 'true'), the repository is made shareable between
in a group (making sure all the files and objects are group-writable). several users in a group (making sure all the files and objects are
See gitlink:git-init-db[1]. False by default. group-writable). When 'all' (or 'world' or 'everybody'), the
repository will be readable by all users, additionally to being
group-shareable. When 'umask' (or 'false'), git will use permissions
reported by umask(2). See gitlink:git-init-db[1]. False by default.
core.warnAmbiguousRefs:: core.warnAmbiguousRefs::
If true, git will warn you if the ref name you passed it is ambiguous If true, git will warn you if the ref name you passed it is ambiguous
@ -116,6 +119,10 @@ apply.whitespace::
Tells `git-apply` how to handle whitespaces, in the same way Tells `git-apply` how to handle whitespaces, in the same way
as the '--whitespace' option. See gitlink:git-apply[1]. as the '--whitespace' option. See gitlink:git-apply[1].
pager.color::
A boolean to enable/disable colored output when the pager is in
use (default is true).
diff.color:: diff.color::
When true (or `always`), always use colors in patch. When true (or `always`), always use colors in patch.
When false (or `never`), never. When set to `auto`, use When false (or `never`), never. When set to `auto`, use
@ -219,14 +226,14 @@ showbranch.default::
See gitlink:git-show-branch[1]. See gitlink:git-show-branch[1].
tar.umask:: tar.umask::
By default, git-link:git-tar-tree[1] sets file and directories modes By default, gitlink:git-tar-tree[1] sets file and directories modes
to 0666 or 0777. While this is both useful and acceptable for projects to 0666 or 0777. While this is both useful and acceptable for projects
such as the Linux Kernel, it might be excessive for other projects. such as the Linux Kernel, it might be excessive for other projects.
With this variable, it becomes possible to tell With this variable, it becomes possible to tell
git-link:git-tar-tree[1] to apply a specific umask to the modes above. gitlink:git-tar-tree[1] to apply a specific umask to the modes above.
The special value "user" indicates that the user's current umask will The special value "user" indicates that the user's current umask will
be used. This should be enough for most projects, as it will lead to be used. This should be enough for most projects, as it will lead to
the same permissions as git-link:git-checkout[1] would use. The default the same permissions as gitlink:git-checkout[1] would use. The default
value remains 0, which means world read-write. value remains 0, which means world read-write.
user.email:: user.email::

View File

@ -116,7 +116,7 @@ file each time git-cvsimport is run.
+ +
It is not recommended to use this feature if you intend to It is not recommended to use this feature if you intend to
export changes back to CVS again later with export changes back to CVS again later with
git-link[1]::git-cvsexportcommit. gitlink:git-cvsexportcommit[1].
OUTPUT OUTPUT
------ ------

View File

@ -16,7 +16,7 @@ SYNOPSIS
[-n] [-l | --files-with-matches] [-L | --files-without-match] [-n] [-l | --files-with-matches] [-L | --files-without-match]
[-c | --count] [-c | --count]
[-A <post-context>] [-B <pre-context>] [-C <context>] [-A <post-context>] [-B <pre-context>] [-C <context>]
[-f <file>] [-e] <pattern> [-f <file>] [-e] <pattern> [--and|--or|--not|(|)|-e <pattern>...]
[<tree>...] [<tree>...]
[--] [<path>...] [--] [<path>...]
@ -74,16 +74,30 @@ OPTIONS
-e:: -e::
The next parameter is the pattern. This option has to be The next parameter is the pattern. This option has to be
used for patterns starting with - and should be used in used for patterns starting with - and should be used in
scripts passing user input to grep. scripts passing user input to grep. Multiple patterns are
combined by 'or'.
--and | --or | --not | ( | )::
Specify how multiple patterns are combined using boolean
expressions. `--or` is the default operator. `--and` has
higher precedence than `--or`. `-e` has to be used for all
patterns.
`<tree>...`:: `<tree>...`::
Search blobs in the trees for specified patterns. Search blobs in the trees for specified patterns.
`--`:: \--::
Signals the end of options; the rest of the parameters Signals the end of options; the rest of the parameters
are <path> limiters. are <path> limiters.
Example
-------
git grep -e \'#define\' --and \( -e MAX_PATH -e PATH_MAX \)::
Looks for a line that has `#define` and either `MAX_PATH` or
`PATH_MAX`.
Author Author
------ ------
Originally written by Linus Torvalds <torvalds@osdl.org>, later Originally written by Linus Torvalds <torvalds@osdl.org>, later

View File

@ -8,17 +8,47 @@ git-init-db - Creates an empty git repository
SYNOPSIS SYNOPSIS
-------- --------
'git-init-db' [--template=<template_directory>] [--shared] 'git-init-db' [--template=<template_directory>] [--shared[=<permissions>]]
OPTIONS OPTIONS
------- -------
--template=<template_directory>::
Provide the directory from which templates will be used.
The default template directory is `/usr/share/git-core/templates`.
--shared:: --
Specify that the git repository is to be shared amongst several users.
--template=<template_directory>::
Provide the directory from which templates will be used. The default template
directory is `/usr/share/git-core/templates`.
When specified, `<template_directory>` is used as the source of the template
files rather than the default. The template files include some directory
structure, some suggested "exclude patterns", and copies of non-executing
"hook" files. The suggested patterns and hook files are all modifiable and
extensible.
--shared[={false|true|umask|group|all|world|everybody}]::
Specify that the git repository is to be shared amongst several users. This
allows users belonging to the same group to push into that
repository. When specified, the config variable "core.sharedRepository" is
set so that files and directories under `$GIT_DIR` are created with the
requested permissions. When not specified, git will use permissions reported
by umask(2).
The option can have the following values, defaulting to 'group' if no value
is given:
- 'umask' (or 'false'): Use permissions reported by umask(2). The default,
when `--shared` is not specified.
- 'group' (or 'true'): Make the repository group-writable, (and g+sx, since
the git group may be not the primary group of all users).
- 'all' (or 'world' or 'everybody'): Same as 'group', but make the repository
readable by all users.
--
DESCRIPTION DESCRIPTION
@ -29,12 +59,6 @@ template files.
An initial `HEAD` file that references the HEAD of the master branch An initial `HEAD` file that references the HEAD of the master branch
is also created. is also created.
If `--template=<template_directory>` is specified, `<template_directory>`
is used as the source of the template files rather than the default.
The template files include some directory structure, some suggested
"exclude patterns", and copies of non-executing "hook" files. The
suggested patterns and hook files are all modifiable and extensible.
If the `$GIT_DIR` environment variable is set then it specifies a path If the `$GIT_DIR` environment variable is set then it specifies a path
to use instead of `./.git` for the base of the repository. to use instead of `./.git` for the base of the repository.
@ -42,11 +66,6 @@ If the object storage directory is specified via the `$GIT_OBJECT_DIRECTORY`
environment variable then the sha1 directories are created underneath - environment variable then the sha1 directories are created underneath -
otherwise the default `$GIT_DIR/objects` directory is used. otherwise the default `$GIT_DIR/objects` directory is used.
A shared repository allows users belonging to the same group to push into that
repository. When specifying `--shared` the config variable "core.sharedRepository"
is set to 'true' so that directories under `$GIT_DIR` are made group writable
(and g+sx, since the git group may be not the primary group of all users).
Running `git-init-db` in an existing repository is safe. It will not overwrite Running `git-init-db` in an existing repository is safe. It will not overwrite
things that are already there. The primary reason for rerunning `git-init-db` things that are already there. The primary reason for rerunning `git-init-db`
is to pick up newly added templates. is to pick up newly added templates.

View File

@ -8,7 +8,7 @@ git-push - Update remote refs along with associated objects
SYNOPSIS SYNOPSIS
-------- --------
'git-push' [--all] [--tags] [--force] <repository> <refspec>... 'git-push' [--all] [--tags] [-f | --force] <repository> <refspec>...
DESCRIPTION DESCRIPTION
----------- -----------

View File

@ -22,6 +22,7 @@ SYNOPSIS
[ [\--objects | \--objects-edge] [ \--unpacked ] ] [ [\--objects | \--objects-edge] [ \--unpacked ] ]
[ \--pretty | \--header ] [ \--pretty | \--header ]
[ \--bisect ] [ \--bisect ]
[ \--merge ]
<commit>... [ \-- <paths>... ] <commit>... [ \-- <paths>... ]
DESCRIPTION DESCRIPTION
@ -123,6 +124,10 @@ OPTIONS
topological order (i.e. descendant commits are shown topological order (i.e. descendant commits are shown
before their parents). before their parents).
--merge::
After a failed merge, show refs that touch files having a
conflict and don't exist on all heads to merge.
Author Author
------ ------
Written by Linus Torvalds <torvalds@osdl.org> Written by Linus Torvalds <torvalds@osdl.org>

View File

@ -8,7 +8,7 @@ git-status - Show working tree status
SYNOPSIS SYNOPSIS
-------- --------
'git-status' 'git-status' <options>...
DESCRIPTION DESCRIPTION
----------- -----------
@ -23,6 +23,10 @@ If there is no path that is different between the index file and
the current HEAD commit, the command exits with non-zero the current HEAD commit, the command exits with non-zero
status. status.
The command takes the same set of options as `git-commit`; it
shows what would be committed if the same options are given to
`git-commit`.
OUTPUT OUTPUT
------ ------

View File

@ -397,6 +397,9 @@ gitlink:git-quiltimport[1]::
gitlink:git-relink[1]:: gitlink:git-relink[1]::
Hardlink common objects in local repositories. Hardlink common objects in local repositories.
gitlink:git-svn[1]::
Bidirectional operation between a single Subversion branch and git.
gitlink:git-svnimport[1]:: gitlink:git-svnimport[1]::
Import a SVN repository into git. Import a SVN repository into git.
@ -442,6 +445,9 @@ gitlink:git-get-tar-commit-id[1]::
gitlink:git-imap-send[1]:: gitlink:git-imap-send[1]::
Dump a mailbox from stdin into an imap folder. Dump a mailbox from stdin into an imap folder.
gitlink:git-instaweb[1]::
Instantly browse your working repository in gitweb.
gitlink:git-mailinfo[1]:: gitlink:git-mailinfo[1]::
Extracts patch and authorship information from a single Extracts patch and authorship information from a single
e-mail message, optionally transliterating the commit e-mail message, optionally transliterating the commit

View File

@ -0,0 +1,256 @@
From: Rutger Nijlunsing <rutger@nospam.com>
Subject: Setting up a git repository which can be pushed into and pulled from over HTTP.
Date: Thu, 10 Aug 2006 22:00:26 +0200
Since Apache is one of those packages people like to compile
themselves while others prefer the bureaucrat's dream Debian, it is
impossible to give guidelines which will work for everyone. Just send
some feedback to the mailing list at git@vger.kernel.org to get this
document tailored to your favorite distro.
What's needed:
- Have an Apache web-server
On Debian:
$ apt-get install apache2
To get apache2 by default started,
edit /etc/default/apache2 and set NO_START=0
- can edit the configuration of it.
This could be found under /etc/httpd, or refer to your Apache documentation.
On Debian: this means being able to edit files under /etc/apache2
- can restart it.
'apachectl --graceful' might do. If it doesn't, just stop and
restart apache. Be warning that active connections to your server
might be aborted by this.
On Debian:
$ /etc/init.d/apache2 restart
or
$ /etc/init.d/apache2 force-reload
(which seems to do the same)
This adds symlinks from the /etc/apache2/mods-enabled to
/etc/apache2/mods-available.
- have permissions to chown a directory
- have git installed at the server _and_ client
In effect, this probably means you're going to be root.
Step 1: setup a bare GIT repository
-----------------------------------
At the time of writing, git-http-push cannot remotely create a GIT
repository. So we have to do that at the server side with git. Another
option would be to generate an empty repository at the client and copy
it to the server with WebDAV. But then you're probably the first to
try that out :)
Create the directory under the DocumentRoot of the directories served
by Apache. As an example we take /usr/local/apache2, but try "grep
DocumentRoot /where/ever/httpd.conf" to find your root:
$ cd /usr/local/apache/htdocs
$ mkdir my-new-repo.git
On Debian:
$ cd /var/www
$ mkdir my-new-repo.git
Initialize a bare repository
$ cd my-new-repo.git
$ git --bare init-db
Change the ownership to your web-server's credentials. Use "grep ^User
httpd.conf" and "grep ^Group httpd.conf" to find out:
$ chown -R www.www .
On Debian:
$ chown -R www-data.www-data .
If you do not know which user Apache runs as, you can alternatively do
a "chmod -R a+w .", inspect the files which are created later on, and
set the permissions appropriately.
Restart apache2, and check whether http://server/my-new-repo.git gives
a directory listing. If not, check whether apache started up
successfully.
Step 2: enable DAV on this repository
-------------------------------------
First make sure the dav_module is loaded. For this, insert in httpd.conf:
LoadModule dav_module libexec/httpd/libdav.so
AddModule mod_dav.c
Also make sure that this line exists which is the file used for
locking DAV operations:
DAVLockDB "/usr/local/apache2/temp/DAV.lock"
On Debian these steps can be performed with:
Enable the dav and dav_fs modules of apache:
$ a2enmod dav_fs
(just to be sure. dav_fs might be unneeded, I don't know)
$ a2enmod dav
The DAV lock is located in /etc/apache2/mods-available/dav_fs.conf:
DAVLockDB /var/lock/apache2/DAVLock
Of course, it can point somewhere else, but the string is actually just a
prefix in some Apache configurations, and therefore the _directory_ has to
be writable by the user Apache runs as.
Then, add something like this to your httpd.conf
<Location /my-new-repo.git>
DAV on
AuthType Basic
AuthName "Git"
AuthUserFile /usr/local/apache2/conf/passwd.git
Require valid-user
</Location>
On Debian:
Create (or add to) /etc/apache2/conf.d/git.conf :
<Location /my-new-repo.git>
DAV on
AuthType Basic
AuthName "Git"
AuthUserFile /etc/apache2/passwd.git
Require valid-user
</Location>
Debian automatically reads all files under /etc/apach2/conf.d.
The password file can be somewhere else, but it has to be readable by
Apache and preferably not readable by the world.
Create this file by
$ htpasswd -c /usr/local/apache2/conf/passwd.git <user>
On Debian:
$ htpasswd -c /etc/apache2/passwd.git <user>
You will be asked a password, and the file is created. Subsequent calls
to htpasswd should omit the '-c' option, since you want to append to the
existing file.
You need to restart Apache.
Now go to http://<username>@<servername>/my-new-repo.git in your
browser to check whether it asks for a password and accepts the right
password.
On Debian:
To test the WebDAV part, do:
$ apt-get install litmus
$ litmus http://<servername>/my-new-repo.git <username> <password>
Most tests should pass.
A command line tool to test WebDAV is cadaver.
If you're into Windows, from XP onwards Internet Explorer supports
WebDAV. For this, do Internet Explorer -> Open Location ->
http://<servername>/my-new-repo.git [x] Open as webfolder -> login .
Step 3: setup the client
------------------------
Make sure that you have HTTP support, i.e. your git was built with curl.
The easiest way to check is to look for the executable 'git-http-push'.
Then, add the following to your $HOME/.netrc (you can do without, but will be
asked to input your password a _lot_ of times):
machine <servername>
login <username>
password <password>
...and set permissions:
chmod 600 ~/.netrc
If you want to access the web-server by its IP, you have to type that in,
instead of the server name.
To check whether all is OK, do:
curl --netrc --location -v http://<username>@<servername>/my-new-repo.git/
...this should give a directory listing in HTML of /var/www/my-new-repo.git .
Now, add the remote in your existing repository which contains the project
you want to export:
$ git-repo-config remote.upload.url \
http://<username>@<servername>/my-new-repo.git/
It is important to put the last '/'; Without it, the server will send
a redirect which git-http-push does not (yet) understand, and git-http-push
will repeat the request infinitely.
Step 4: make the initial push
-----------------------------
From your client repository, do
$ git push upload master
This pushes branch 'master' (which is assumed to be the branch you
want to export) to repository called 'upload', which we previously
defined with git-repo-config.
Troubleshooting:
----------------
If git-http-push says
Error: no DAV locking support on remote repo http://...
then it means the web-server did not accept your authentication. Make sure
that the user name and password matches in httpd.conf, .netrc and the URL
you are uploading to.
If git-http-push shows you an error (22/502) when trying to MOVE a blob,
it means that your web-server somehow does not recognize its name in the
request; This can happen when you start Apache, but then disable the
network interface. A simple restart of Apache helps.
Errors like (22/502) are of format (curl error code/http error
code). So (22/404) means something like 'not found' at the server.
Reading /usr/local/apache2/logs/error_log is often helpful.
On Debian: Read /var/log/apache2/error.log instead.
Debian References: http://www.debian-administration.org/articles/285
Authors
Johannes Schindelin <Johannes.Schindelin@gmx.de>
Rutger Nijlunsing <git@wingding.demon.nl>

View File

@ -244,6 +244,7 @@ $ git ls-files --stage
$ git cat-file -t 513feba2 $ git cat-file -t 513feba2
blob blob
$ git cat-file blob 513feba2 $ git cat-file blob 513feba2
hello world!
hello world, again hello world, again
------------------------------------------------ ------------------------------------------------

View File

@ -1,11 +1,19 @@
#!/bin/sh #!/bin/sh
GVF=GIT-VERSION-FILE GVF=GIT-VERSION-FILE
DEF_VER=v1.4.GIT DEF_VER=v1.4.2.GIT
LF='
'
# First try git-describe, then see if there is a version file # First try git-describe, then see if there is a version file
# (included in release tarballs), then default # (included in release tarballs), then default
if VN=$(git describe --abbrev=4 HEAD 2>/dev/null); then if VN=$(git describe --abbrev=4 HEAD 2>/dev/null) &&
case "$VN" in
*$LF*) (exit 1) ;;
v[0-9]*) : happy ;;
esac
then
VN=$(echo "$VN" | sed -e 's/-/./g'); VN=$(echo "$VN" | sed -e 's/-/./g');
elif test -f version elif test -f version
then then

View File

@ -24,6 +24,11 @@ all:
# Define NO_D_TYPE_IN_DIRENT if your platform defines DT_UNKNOWN but lacks # Define NO_D_TYPE_IN_DIRENT if your platform defines DT_UNKNOWN but lacks
# d_type in struct dirent (latest Cygwin -- will be fixed soonish). # d_type in struct dirent (latest Cygwin -- will be fixed soonish).
# #
# Define NO_C99_FORMAT if your formatted IO functions (printf/scanf et.al.)
# do not support the 'size specifiers' introduced by C99, namely ll, hh,
# j, z, t. (representing long long int, char, intmax_t, size_t, ptrdiff_t).
# some c compilers supported these specifiers prior to C99 as an extension.
#
# Define NO_STRCASESTR if you don't have strcasestr. # Define NO_STRCASESTR if you don't have strcasestr.
# #
# Define NO_STRLCPY if you don't have strlcpy. # Define NO_STRLCPY if you don't have strlcpy.
@ -173,14 +178,14 @@ PROGRAMS = \
git-hash-object$X git-index-pack$X git-local-fetch$X \ git-hash-object$X git-index-pack$X git-local-fetch$X \
git-merge-base$X \ git-merge-base$X \
git-merge-index$X git-mktag$X git-mktree$X git-pack-objects$X git-patch-id$X \ git-merge-index$X git-mktag$X git-mktree$X git-pack-objects$X git-patch-id$X \
git-peek-remote$X git-prune-packed$X git-receive-pack$X \ git-peek-remote$X git-receive-pack$X \
git-send-pack$X git-shell$X \ git-send-pack$X git-shell$X \
git-show-index$X git-ssh-fetch$X \ git-show-index$X git-ssh-fetch$X \
git-ssh-upload$X git-unpack-file$X \ git-ssh-upload$X git-unpack-file$X \
git-unpack-objects$X git-update-server-info$X \ git-unpack-objects$X git-update-server-info$X \
git-upload-pack$X git-verify-pack$X \ git-upload-pack$X git-verify-pack$X \
git-symbolic-ref$X \ git-symbolic-ref$X \
git-name-rev$X git-pack-redundant$X git-repo-config$X git-var$X \ git-name-rev$X git-pack-redundant$X git-var$X \
git-describe$X git-merge-tree$X git-blame$X git-imap-send$X \ git-describe$X git-merge-tree$X git-blame$X git-imap-send$X \
git-merge-recur$X git-merge-recur$X
@ -193,7 +198,8 @@ BUILT_INS = git-log$X git-whatchanged$X git-show$X git-update-ref$X \
git-read-tree$X git-commit-tree$X git-write-tree$X \ git-read-tree$X git-commit-tree$X git-write-tree$X \
git-apply$X git-show-branch$X git-diff-files$X git-update-index$X \ git-apply$X git-show-branch$X git-diff-files$X git-update-index$X \
git-diff-index$X git-diff-stages$X git-diff-tree$X git-cat-file$X \ git-diff-index$X git-diff-stages$X git-diff-tree$X git-cat-file$X \
git-fmt-merge-msg$X git-prune$X git-mv$X git-fmt-merge-msg$X git-prune$X git-mv$X git-prune-packed$X \
git-repo-config$X
# what 'all' will build and 'install' will install, in gitexecdir # what 'all' will build and 'install' will install, in gitexecdir
ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS) ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)
@ -250,7 +256,7 @@ BUILTIN_OBJS = \
builtin-diff-index.o builtin-diff-stages.o builtin-diff-tree.o \ builtin-diff-index.o builtin-diff-stages.o builtin-diff-tree.o \
builtin-cat-file.o builtin-mailsplit.o builtin-stripspace.o \ builtin-cat-file.o builtin-mailsplit.o builtin-stripspace.o \
builtin-update-ref.o builtin-fmt-merge-msg.o builtin-prune.o \ builtin-update-ref.o builtin-fmt-merge-msg.o builtin-prune.o \
builtin-mv.o builtin-mv.o builtin-prune-packed.o builtin-repo-config.o
GITLIBS = $(LIB_FILE) $(XDIFF_LIB) GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
LIBS = $(GITLIBS) -lz LIBS = $(GITLIBS) -lz
@ -309,9 +315,9 @@ ifeq ($(uname_O),Cygwin)
NO_D_TYPE_IN_DIRENT = YesPlease NO_D_TYPE_IN_DIRENT = YesPlease
NO_D_INO_IN_DIRENT = YesPlease NO_D_INO_IN_DIRENT = YesPlease
NO_STRCASESTR = YesPlease NO_STRCASESTR = YesPlease
NO_STRLCPY = YesPlease
NO_SYMLINK_HEAD = YesPlease NO_SYMLINK_HEAD = YesPlease
NEEDS_LIBICONV = YesPlease NEEDS_LIBICONV = YesPlease
NO_C99_FORMAT = YesPlease
# There are conflicting reports about this. # There are conflicting reports about this.
# On some boxes NO_MMAP is needed, and not so elsewhere. # On some boxes NO_MMAP is needed, and not so elsewhere.
# Try uncommenting this if you see things break -- YMMV. # Try uncommenting this if you see things break -- YMMV.
@ -433,6 +439,9 @@ endif
ifdef NO_D_INO_IN_DIRENT ifdef NO_D_INO_IN_DIRENT
ALL_CFLAGS += -DNO_D_INO_IN_DIRENT ALL_CFLAGS += -DNO_D_INO_IN_DIRENT
endif endif
ifdef NO_C99_FORMAT
ALL_CFLAGS += -DNO_C99_FORMAT
endif
ifdef NO_SYMLINK_HEAD ifdef NO_SYMLINK_HEAD
ALL_CFLAGS += -DNO_SYMLINK_HEAD ALL_CFLAGS += -DNO_SYMLINK_HEAD
endif endif
@ -718,7 +727,7 @@ install: all
$(INSTALL) -d -m755 '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL) -d -m755 '$(DESTDIR_SQ)$(gitexecdir_SQ)'
$(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
$(INSTALL) git$X gitk '$(DESTDIR_SQ)$(bindir_SQ)' $(INSTALL) git$X gitk '$(DESTDIR_SQ)$(bindir_SQ)'
$(MAKE) -C templates install $(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install
$(INSTALL) -d -m755 '$(DESTDIR_SQ)$(GIT_PYTHON_DIR_SQ)' $(INSTALL) -d -m755 '$(DESTDIR_SQ)$(GIT_PYTHON_DIR_SQ)'
$(INSTALL) $(PYMODULES) '$(DESTDIR_SQ)$(GIT_PYTHON_DIR_SQ)' $(INSTALL) $(PYMODULES) '$(DESTDIR_SQ)$(GIT_PYTHON_DIR_SQ)'
if test 'z$(bindir_SQ)' != 'z$(gitexecdir_SQ)'; \ if test 'z$(bindir_SQ)' != 'z$(gitexecdir_SQ)'; \

15
alloc.c
View File

@ -39,8 +39,21 @@ DEFINE_ALLOCATOR(tree)
DEFINE_ALLOCATOR(commit) DEFINE_ALLOCATOR(commit)
DEFINE_ALLOCATOR(tag) DEFINE_ALLOCATOR(tag)
#ifdef NO_C99_FORMAT
#define SZ_FMT "%u"
#else
#define SZ_FMT "%zu"
#endif
static void report(const char* name, unsigned int count, size_t size)
{
fprintf(stderr, "%10s: %8u (" SZ_FMT " kB)\n", name, count, size);
}
#undef SZ_FMT
#define REPORT(name) \ #define REPORT(name) \
fprintf(stderr, "%10s: %8u (%zu kB)\n", #name, name##_allocs, name##_allocs*sizeof(struct name) >> 10) report(#name, name##_allocs, name##_allocs*sizeof(struct name) >> 10)
void alloc_report(void) void alloc_report(void)
{ {

View File

@ -20,7 +20,7 @@
#define DEBUG 0 #define DEBUG 0
static const char blame_usage[] = "[-c] [-l] [-t] [-S <revs-file>] [--] file [commit]\n" static const char blame_usage[] = "git-blame [-c] [-l] [-t] [-S <revs-file>] [--] file [commit]\n"
" -c, --compatibility Use the same output mode as git-annotate (Default: off)\n" " -c, --compatibility Use the same output mode as git-annotate (Default: off)\n"
" -l, --long Show long commit SHA1 (Default: off)\n" " -l, --long Show long commit SHA1 (Default: off)\n"
" -t, --time Show raw timestamp (Default: off)\n" " -t, --time Show raw timestamp (Default: off)\n"

View File

@ -93,9 +93,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
git_config(git_default_config); git_config(git_default_config);
newfd = hold_lock_file_for_update(&lock_file, get_index_file()); newfd = hold_lock_file_for_update(&lock_file, get_index_file(), 1);
if (newfd < 0)
die("unable to create new index file");
if (read_cache() < 0) if (read_cache() < 0)
die("index file corrupt"); die("index file corrupt");
@ -117,7 +115,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
verbose = 1; verbose = 1;
continue; continue;
} }
die(builtin_add_usage); usage(builtin_add_usage);
} }
pathspec = get_pathspec(prefix, argv + i); pathspec = get_pathspec(prefix, argv + i);

View File

@ -1698,6 +1698,12 @@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *
desc.buffer = buf; desc.buffer = buf;
if (apply_fragments(&desc, patch) < 0) if (apply_fragments(&desc, patch) < 0)
return -1; return -1;
/* NUL terminate the result */
if (desc.alloc <= desc.size)
desc.buffer = xrealloc(desc.buffer, desc.size + 1);
desc.buffer[desc.size] = 0;
patch->result = desc.buffer; patch->result = desc.buffer;
patch->resultsize = desc.size; patch->resultsize = desc.size;
@ -2040,6 +2046,9 @@ static int try_create_file(const char *path, unsigned int mode, const char *buf,
int fd; int fd;
if (S_ISLNK(mode)) if (S_ISLNK(mode))
/* Although buf:size is counted string, it also is NUL
* terminated.
*/
return symlink(buf, path); return symlink(buf, path);
fd = open(path, O_CREAT | O_EXCL | O_WRONLY, (mode & 0100) ? 0777 : 0666); fd = open(path, O_CREAT | O_EXCL | O_WRONLY, (mode & 0100) ? 0777 : 0666);
if (fd < 0) if (fd < 0)
@ -2225,12 +2234,9 @@ static int apply_patch(int fd, const char *filename,
apply = 0; apply = 0;
write_index = check_index && apply; write_index = check_index && apply;
if (write_index && newfd < 0) { if (write_index && newfd < 0)
newfd = hold_lock_file_for_update(&lock_file, newfd = hold_lock_file_for_update(&lock_file,
get_index_file()); get_index_file(), 1);
if (newfd < 0)
die("unable to create new index file");
}
if (check_index) { if (check_index) {
if (read_cache() < 0) if (read_cache() < 0)
die("unable to read index file"); die("unable to read index file");

View File

@ -9,6 +9,6 @@
int cmd_check_ref_format(int argc, const char **argv, const char *prefix) int cmd_check_ref_format(int argc, const char **argv, const char *prefix)
{ {
if (argc != 2) if (argc != 2)
usage("git check-ref-format refname"); usage("git-check-ref-format refname");
return !!check_ref_format(argv[1]); return !!check_ref_format(argv[1]);
} }

View File

@ -23,7 +23,7 @@ struct blobinfo {
}; };
static const char builtin_diff_usage[] = static const char builtin_diff_usage[] =
"diff <options> <rev>{0,2} -- <path>*"; "git-diff <options> <rev>{0,2} -- <path>*";
static int builtin_diff_files(struct rev_info *revs, static int builtin_diff_files(struct rev_info *revs,
int argc, const char **argv) int argc, const char **argv)
@ -125,9 +125,6 @@ static int builtin_diff_blobs(struct rev_info *revs,
int argc, const char **argv, int argc, const char **argv,
struct blobinfo *blob) struct blobinfo *blob)
{ {
/* Blobs: the arguments are reversed when setup_revisions()
* picked them up.
*/
unsigned mode = canon_mode(S_IFREG | 0644); unsigned mode = canon_mode(S_IFREG | 0644);
if (argc > 1) if (argc > 1)
@ -135,8 +132,8 @@ static int builtin_diff_blobs(struct rev_info *revs,
stuff_change(&revs->diffopt, stuff_change(&revs->diffopt,
mode, mode, mode, mode,
blob[1].sha1, blob[0].sha1, blob[0].sha1, blob[1].sha1,
blob[0].name, blob[0].name); blob[0].name, blob[1].name);
diffcore_std(&revs->diffopt); diffcore_std(&revs->diffopt);
diff_flush(&revs->diffopt); diff_flush(&revs->diffopt);
return 0; return 0;
@ -256,7 +253,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
argc = setup_revisions(argc, argv, &rev, NULL); argc = setup_revisions(argc, argv, &rev, NULL);
if (!rev.diffopt.output_format) { if (!rev.diffopt.output_format) {
rev.diffopt.output_format = DIFF_FORMAT_PATCH; rev.diffopt.output_format = DIFF_FORMAT_PATCH;
diff_setup_done(&rev.diffopt); if (diff_setup_done(&rev.diffopt) < 0)
die("diff_setup_done failed");
} }
/* Do we have --cached and not have a pending object, then /* Do we have --cached and not have a pending object, then
@ -351,6 +349,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
* A and B. We have ent[0] == merge-base, ent[1] == A, * A and B. We have ent[0] == merge-base, ent[1] == A,
* and ent[2] == B. Show diff between the base and B. * and ent[2] == B. Show diff between the base and B.
*/ */
ent[1] = ent[2];
return builtin_diff_tree(&rev, argc, argv, ent); return builtin_diff_tree(&rev, argc, argv, ent);
} }
else else

View File

@ -1,3 +1,4 @@
#include "builtin.h"
#include "cache.h" #include "cache.h"
#include "commit.h" #include "commit.h"
#include "diff.h" #include "diff.h"
@ -242,7 +243,7 @@ static void shortlog(const char *name, unsigned char *sha1,
free_list(&subjects); free_list(&subjects);
} }
int cmd_fmt_merge_msg(int argc, char **argv, const char *prefix) int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
{ {
int limit = 20, i = 0; int limit = 20, i = 0;
char line[1024]; char line[1024];

View File

@ -410,8 +410,10 @@ static int fixmatch(const char *pattern, char *line, regmatch_t *match)
static int match_one_pattern(struct grep_opt *opt, struct grep_pat *p, char *bol, char *eol) static int match_one_pattern(struct grep_opt *opt, struct grep_pat *p, char *bol, char *eol)
{ {
int hit = 0; int hit = 0;
int at_true_bol = 1;
regmatch_t pmatch[10]; regmatch_t pmatch[10];
again:
if (!opt->fixed) { if (!opt->fixed) {
regex_t *exp = &p->regexp; regex_t *exp = &p->regexp;
hit = !regexec(exp, bol, ARRAY_SIZE(pmatch), hit = !regexec(exp, bol, ARRAY_SIZE(pmatch),
@ -422,22 +424,35 @@ static int match_one_pattern(struct grep_opt *opt, struct grep_pat *p, char *bol
} }
if (hit && opt->word_regexp) { if (hit && opt->word_regexp) {
/* Match beginning must be either
* beginning of the line, or at word
* boundary (i.e. the last char must
* not be alnum or underscore).
*/
if ((pmatch[0].rm_so < 0) || if ((pmatch[0].rm_so < 0) ||
(eol - bol) <= pmatch[0].rm_so || (eol - bol) <= pmatch[0].rm_so ||
(pmatch[0].rm_eo < 0) || (pmatch[0].rm_eo < 0) ||
(eol - bol) < pmatch[0].rm_eo) (eol - bol) < pmatch[0].rm_eo)
die("regexp returned nonsense"); die("regexp returned nonsense");
if (pmatch[0].rm_so != 0 &&
word_char(bol[pmatch[0].rm_so-1])) /* Match beginning must be either beginning of the
hit = 0; * line, or at word boundary (i.e. the last char must
if (pmatch[0].rm_eo != (eol-bol) && * not be a word char). Similarly, match end must be
word_char(bol[pmatch[0].rm_eo])) * either end of the line, or at word boundary
* (i.e. the next char must not be a word char).
*/
if ( ((pmatch[0].rm_so == 0 && at_true_bol) ||
!word_char(bol[pmatch[0].rm_so-1])) &&
((pmatch[0].rm_eo == (eol-bol)) ||
!word_char(bol[pmatch[0].rm_eo])) )
;
else
hit = 0; hit = 0;
if (!hit && pmatch[0].rm_so + bol + 1 < eol) {
/* There could be more than one match on the
* line, and the first match might not be
* strict word match. But later ones could be!
*/
bol = pmatch[0].rm_so + bol + 1;
at_true_bol = 0;
goto again;
}
} }
return hit; return hit;
} }

View File

@ -9,8 +9,6 @@
#include "exec_cmd.h" #include "exec_cmd.h"
#include "common-cmds.h" #include "common-cmds.h"
static const char git_usage[] =
"Usage: git [--version] [--exec-path[=GIT_EXEC_PATH]] [--help] COMMAND [ ARGS ]";
/* most GUI terminals set COLUMNS (although some don't export it) */ /* most GUI terminals set COLUMNS (although some don't export it) */
static int term_columns(void) static int term_columns(void)
@ -142,7 +140,7 @@ static void list_commands(const char *exec_path, const char *pattern)
continue; continue;
entlen = strlen(de->d_name); entlen = strlen(de->d_name);
if (4 < entlen && !strcmp(de->d_name + entlen - 4, ".exe")) if (has_extension(de->d_name, ".exe"))
entlen -= 4; entlen -= 4;
if (longest < entlen) if (longest < entlen)
@ -178,31 +176,6 @@ static void list_common_cmds_help(void)
puts("(use 'git help -a' to get a list of all installed git commands)"); puts("(use 'git help -a' to get a list of all installed git commands)");
} }
void cmd_usage(int show_all, const char *exec_path, const char *fmt, ...)
{
if (fmt) {
va_list ap;
va_start(ap, fmt);
printf("git: ");
vprintf(fmt, ap);
va_end(ap);
putchar('\n');
}
else
puts(git_usage);
if (exec_path) {
putchar('\n');
if (show_all)
list_commands(exec_path, "git-*");
else
list_common_cmds_help();
}
exit(1);
}
static void show_man_page(const char *git_cmd) static void show_man_page(const char *git_cmd)
{ {
const char *page; const char *page;
@ -221,6 +194,13 @@ static void show_man_page(const char *git_cmd)
execlp("man", "man", page, NULL); execlp("man", "man", page, NULL);
} }
void help_unknown_cmd(const char *cmd)
{
printf("git: '%s' is not a git-command\n\n", cmd);
list_common_cmds_help();
exit(1);
}
int cmd_version(int argc, const char **argv, const char *prefix) int cmd_version(int argc, const char **argv, const char *prefix)
{ {
printf("git version %s\n", git_version_string); printf("git version %s\n", git_version_string);
@ -230,12 +210,24 @@ int cmd_version(int argc, const char **argv, const char *prefix)
int cmd_help(int argc, const char **argv, const char *prefix) int cmd_help(int argc, const char **argv, const char *prefix)
{ {
const char *help_cmd = argc > 1 ? argv[1] : NULL; const char *help_cmd = argc > 1 ? argv[1] : NULL;
if (!help_cmd) const char *exec_path = git_exec_path();
cmd_usage(0, git_exec_path(), NULL);
else if (!strcmp(help_cmd, "--all") || !strcmp(help_cmd, "-a")) if (!help_cmd) {
cmd_usage(1, git_exec_path(), NULL); printf("usage: %s\n\n", git_usage_string);
list_common_cmds_help();
exit(1);
}
else if (!strcmp(help_cmd, "--all") || !strcmp(help_cmd, "-a")) {
printf("usage: %s\n\n", git_usage_string);
if(exec_path)
list_commands(exec_path, "git-*");
exit(1);
}
else else
show_man_page(help_cmd); show_man_page(help_cmd);
return 0; return 0;
} }

View File

@ -267,7 +267,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
else if (!strncmp(arg, "--shared=", 9)) else if (!strncmp(arg, "--shared=", 9))
shared_repository = git_config_perm("arg", arg+9); shared_repository = git_config_perm("arg", arg+9);
else else
die(init_db_usage); usage(init_db_usage);
} }
/* /*

View File

@ -34,7 +34,6 @@ static int cmd_log_walk(struct rev_info *rev)
struct commit *commit; struct commit *commit;
prepare_revision_walk(rev); prepare_revision_walk(rev);
setup_pager();
while ((commit = get_revision(rev)) != NULL) { while ((commit = get_revision(rev)) != NULL) {
log_tree_commit(rev, commit); log_tree_commit(rev, commit);
free(commit->buffer); free(commit->buffer);
@ -258,6 +257,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
char message_id[1024]; char message_id[1024];
char ref_message_id[1024]; char ref_message_id[1024];
setup_ident();
git_config(git_format_config); git_config(git_format_config);
init_revisions(&rev, prefix); init_revisions(&rev, prefix);
rev.commit_format = CMIT_FMT_EMAIL; rev.commit_format = CMIT_FMT_EMAIL;
@ -307,7 +307,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
!strcmp(argv[i], "-s")) { !strcmp(argv[i], "-s")) {
const char *committer; const char *committer;
const char *endpos; const char *endpos;
setup_ident();
committer = git_committer_info(1); committer = git_committer_info(1);
endpos = strchr(committer, '>'); endpos = strchr(committer, '>');
if (!endpos) if (!endpos)

View File

@ -24,7 +24,6 @@ static int show_valid_bit = 0;
static int line_terminator = '\n'; static int line_terminator = '\n';
static int prefix_len = 0, prefix_offset = 0; static int prefix_len = 0, prefix_offset = 0;
static const char *prefix = NULL;
static const char **pathspec = NULL; static const char **pathspec = NULL;
static int error_unmatch = 0; static int error_unmatch = 0;
static char *ps_matched = NULL; static char *ps_matched = NULL;
@ -207,7 +206,7 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce)
} }
} }
static void show_files(struct dir_struct *dir) static void show_files(struct dir_struct *dir, const char *prefix)
{ {
int i; int i;
@ -253,7 +252,7 @@ static void show_files(struct dir_struct *dir)
/* /*
* Prune the index to only contain stuff starting with "prefix" * Prune the index to only contain stuff starting with "prefix"
*/ */
static void prune_cache(void) static void prune_cache(const char *prefix)
{ {
int pos = cache_name_pos(prefix, prefix_len); int pos = cache_name_pos(prefix, prefix_len);
unsigned int first, last; unsigned int first, last;
@ -276,7 +275,7 @@ static void prune_cache(void)
active_nr = last; active_nr = last;
} }
static void verify_pathspec(void) static const char *verify_pathspec(const char *prefix)
{ {
const char **p, *n, *prev; const char **p, *n, *prev;
char *real_prefix; char *real_prefix;
@ -313,7 +312,7 @@ static void verify_pathspec(void)
memcpy(real_prefix, prev, max); memcpy(real_prefix, prev, max);
real_prefix[max] = 0; real_prefix[max] = 0;
} }
prefix = real_prefix; return real_prefix;
} }
static const char ls_files_usage[] = static const char ls_files_usage[] =
@ -453,7 +452,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
/* Verify that the pathspec matches the prefix */ /* Verify that the pathspec matches the prefix */
if (pathspec) if (pathspec)
verify_pathspec(); prefix = verify_pathspec(prefix);
/* Treat unmatching pathspec elements as errors */ /* Treat unmatching pathspec elements as errors */
if (pathspec && error_unmatch) { if (pathspec && error_unmatch) {
@ -476,8 +475,8 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
read_cache(); read_cache();
if (prefix) if (prefix)
prune_cache(); prune_cache(prefix);
show_files(&dir); show_files(&dir, prefix);
if (ps_matched) { if (ps_matched) {
/* We need to make sure all pathspec matched otherwise /* We need to make sure all pathspec matched otherwise

View File

@ -48,7 +48,8 @@ static const char *add_slash(const char *path)
if (path[len - 1] != '/') { if (path[len - 1] != '/') {
char *with_slash = xmalloc(len + 2); char *with_slash = xmalloc(len + 2);
memcpy(with_slash, path, len); memcpy(with_slash, path, len);
strcat(with_slash + len, "/"); with_slash[len++] = '/';
with_slash[len] = 0;
return with_slash; return with_slash;
} }
return path; return path;
@ -71,10 +72,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
git_config(git_default_config); git_config(git_default_config);
newfd = hold_lock_file_for_update(&lock_file, get_index_file()); newfd = hold_lock_file_for_update(&lock_file, get_index_file(), 1);
if (newfd < 0)
die("unable to create new index file");
if (read_cache() < 0) if (read_cache() < 0)
die("index file corrupt"); die("index file corrupt");
@ -99,7 +97,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
ignore_errors = 1; ignore_errors = 1;
continue; continue;
} }
die(builtin_mv_usage); usage(builtin_mv_usage);
} }
count = argc - i - 1; count = argc - i - 1;
if (count < 1) if (count < 1)

View File

@ -1,3 +1,4 @@
#include "builtin.h"
#include "cache.h" #include "cache.h"
static const char prune_packed_usage[] = static const char prune_packed_usage[] =
@ -54,12 +55,10 @@ static void prune_packed_objects(void)
} }
} }
int main(int argc, char **argv) int cmd_prune_packed(int argc, const char **argv, const char *prefix)
{ {
int i; int i;
setup_git_directory();
for (i = 1; i < argc; i++) { for (i = 1; i < argc; i++) {
const char *arg = argv[i]; const char *arg = argv[i];

View File

@ -10,7 +10,7 @@
#include "builtin.h" #include "builtin.h"
#include "cache-tree.h" #include "cache-tree.h"
static const char prune_usage[] = "git prune [-n]"; static const char prune_usage[] = "git-prune [-n]";
static int show_only = 0; static int show_only = 0;
static struct rev_info revs; static struct rev_info revs;

View File

@ -8,7 +8,7 @@
#define MAX_URI (16) #define MAX_URI (16)
static const char push_usage[] = "git push [--all] [--tags] [--force] <repository> [<refspec>...]"; static const char push_usage[] = "git-push [--all] [--tags] [-f | --force] <repository> [<refspec>...]";
static int all = 0, tags = 0, force = 0, thin = 1; static int all = 0, tags = 0, force = 0, thin = 1;
static const char *execute = NULL; static const char *execute = NULL;
@ -291,7 +291,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
tags = 1; tags = 1;
continue; continue;
} }
if (!strcmp(arg, "--force")) { if (!strcmp(arg, "--force") || !strcmp(arg, "-f")) {
force = 1; force = 1;
continue; continue;
} }

View File

@ -88,7 +88,7 @@ static const char read_tree_usage[] = "git-read-tree (<sha> | [[-m [--aggressive
static struct lock_file lock_file; static struct lock_file lock_file;
int cmd_read_tree(int argc, const char **argv, const char *prefix) int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
{ {
int i, newfd, stage = 0; int i, newfd, stage = 0;
unsigned char sha1[20]; unsigned char sha1[20];
@ -100,9 +100,7 @@ int cmd_read_tree(int argc, const char **argv, const char *prefix)
setup_git_directory(); setup_git_directory();
git_config(git_default_config); git_config(git_default_config);
newfd = hold_lock_file_for_update(&lock_file, get_index_file()); newfd = hold_lock_file_for_update(&lock_file, get_index_file(), 1);
if (newfd < 0)
die("unable to create new index file");
git_config(git_default_config); git_config(git_default_config);

View File

@ -1,3 +1,4 @@
#include "builtin.h"
#include "cache.h" #include "cache.h"
#include <regex.h> #include <regex.h>
@ -128,7 +129,7 @@ free_strings:
return ret; return ret;
} }
int main(int argc, const char **argv) int cmd_repo_config(int argc, const char **argv, const char *prefix)
{ {
int nongit = 0; int nongit = 0;
setup_git_directory_gently(&nongit); setup_git_directory_gently(&nongit);

View File

@ -52,9 +52,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
git_config(git_default_config); git_config(git_default_config);
newfd = hold_lock_file_for_update(&lock_file, get_index_file()); newfd = hold_lock_file_for_update(&lock_file, get_index_file(), 1);
if (newfd < 0)
die("unable to create new index file");
if (read_cache() < 0) if (read_cache() < 0)
die("index file corrupt"); die("index file corrupt");
@ -80,7 +78,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
force = 1; force = 1;
continue; continue;
} }
die(builtin_rm_usage); usage(builtin_rm_usage);
} }
if (argc <= i) if (argc <= i)
usage(builtin_rm_usage); usage(builtin_rm_usage);
@ -115,7 +113,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
printf("rm '%s'\n", path); printf("rm '%s'\n", path);
if (remove_file_from_cache(path)) if (remove_file_from_cache(path))
die("git rm: unable to remove %s", path); die("git-rm: unable to remove %s", path);
cache_tree_invalidate_path(active_cache_tree, path); cache_tree_invalidate_path(active_cache_tree, path);
} }
@ -139,7 +137,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
continue; continue;
} }
if (!removed) if (!removed)
die("git rm: %s: %s", path, strerror(errno)); die("git-rm: %s: %s", path, strerror(errno));
} }
} }

View File

@ -314,6 +314,7 @@ static int generate_tar(int argc, const char **argv, const char *prefix)
struct commit *commit; struct commit *commit;
struct tree_desc tree; struct tree_desc tree;
struct strbuf current_path; struct strbuf current_path;
void *buffer;
current_path.buf = xmalloc(PATH_MAX); current_path.buf = xmalloc(PATH_MAX);
current_path.alloc = PATH_MAX; current_path.alloc = PATH_MAX;
@ -341,8 +342,8 @@ static int generate_tar(int argc, const char **argv, const char *prefix)
} else } else
archive_time = time(NULL); archive_time = time(NULL);
tree.buf = read_object_with_reference(sha1, tree_type, &tree.size, tree.buf = buffer = read_object_with_reference(sha1, tree_type,
tree_sha1); &tree.size, tree_sha1);
if (!tree.buf) if (!tree.buf)
die("not a reference to a tag, commit or tree object: %s", die("not a reference to a tag, commit or tree object: %s",
sha1_to_hex(sha1)); sha1_to_hex(sha1));
@ -351,6 +352,7 @@ static int generate_tar(int argc, const char **argv, const char *prefix)
write_entry(tree_sha1, &current_path, 040777, NULL, 0); write_entry(tree_sha1, &current_path, 040777, NULL, 0);
traverse_tree(&tree, &current_path); traverse_tree(&tree, &current_path);
write_trailer(); write_trailer();
free(buffer);
free(current_path.buf); free(current_path.buf);
return 0; return 0;
} }

View File

@ -491,9 +491,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
/* We can't free this memory, it becomes part of a linked list parsed atexit() */ /* We can't free this memory, it becomes part of a linked list parsed atexit() */
lock_file = xcalloc(1, sizeof(struct lock_file)); lock_file = xcalloc(1, sizeof(struct lock_file));
newfd = hold_lock_file_for_update(lock_file, get_index_file()); newfd = hold_lock_file_for_update(lock_file, get_index_file(), 1);
if (newfd < 0)
die("unable to create new cachefile");
entries = read_cache(); entries = read_cache();
if (entries < 0) if (entries < 0)

View File

@ -18,7 +18,7 @@ int write_tree(unsigned char *sha1, int missing_ok, const char *prefix)
/* We can't free this memory, it becomes part of a linked list parsed atexit() */ /* We can't free this memory, it becomes part of a linked list parsed atexit() */
struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file)); struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
newfd = hold_lock_file_for_update(lock_file, get_index_file()); newfd = hold_lock_file_for_update(lock_file, get_index_file(), 0);
entries = read_cache(); entries = read_cache();
if (entries < 0) if (entries < 0)
@ -73,7 +73,7 @@ int cmd_write_tree(int argc, const char **argv, const char *unused_prefix)
else if (!strncmp(arg, "--prefix=", 9)) else if (!strncmp(arg, "--prefix=", 9))
prefix = arg + 9; prefix = arg + 9;
else else
die(write_tree_usage); usage(write_tree_usage);
argc--; argv++; argc--; argv++;
} }

View File

@ -2,18 +2,12 @@
#define BUILTIN_H #define BUILTIN_H
#include <stdio.h> #include <stdio.h>
#include <limits.h>
#ifndef PATH_MAX
# define PATH_MAX 4096
#endif
extern const char git_version_string[]; extern const char git_version_string[];
extern const char git_usage_string[];
void cmd_usage(int show_all, const char *exec_path, const char *fmt, ...) extern void help_unknown_cmd(const char *cmd);
#ifdef __GNUC__
__attribute__((__format__(__printf__, 3, 4), __noreturn__))
#endif
;
extern int cmd_help(int argc, const char **argv, const char *prefix); extern int cmd_help(int argc, const char **argv, const char *prefix);
extern int cmd_version(int argc, const char **argv, const char *prefix); extern int cmd_version(int argc, const char **argv, const char *prefix);
@ -26,6 +20,7 @@ extern int cmd_format_patch(int argc, const char **argv, const char *prefix);
extern int cmd_count_objects(int argc, const char **argv, const char *prefix); extern int cmd_count_objects(int argc, const char **argv, const char *prefix);
extern int cmd_prune(int argc, const char **argv, const char *prefix); extern int cmd_prune(int argc, const char **argv, const char *prefix);
extern int cmd_prune_packed(int argc, const char **argv, const char *prefix);
extern int cmd_push(int argc, const char **argv, const char *prefix); extern int cmd_push(int argc, const char **argv, const char *prefix);
extern int cmd_grep(int argc, const char **argv, const char *prefix); extern int cmd_grep(int argc, const char **argv, const char *prefix);
@ -53,6 +48,7 @@ extern int cmd_update_index(int argc, const char **argv, const char *prefix);
extern int cmd_update_ref(int argc, const char **argv, const char *prefix); extern int cmd_update_ref(int argc, const char **argv, const char *prefix);
extern int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix); extern int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix);
extern int cmd_mv(int argc, const char **argv, const char *prefix); extern int cmd_mv(int argc, const char **argv, const char *prefix);
extern int cmd_repo_config(int argc, const char **argv, const char *prefix);
extern int cmd_write_tree(int argc, const char **argv, const char *prefix); extern int cmd_write_tree(int argc, const char **argv, const char *prefix);
extern int write_tree(unsigned char *sha1, int missing_ok, const char *prefix); extern int write_tree(unsigned char *sha1, int missing_ok, const char *prefix);

View File

@ -176,7 +176,7 @@ struct lock_file {
struct lock_file *next; struct lock_file *next;
char filename[PATH_MAX]; char filename[PATH_MAX];
}; };
extern int hold_lock_file_for_update(struct lock_file *, const char *path); extern int hold_lock_file_for_update(struct lock_file *, const char *path, int);
extern int commit_lock_file(struct lock_file *); extern int commit_lock_file(struct lock_file *);
extern void rollback_lock_file(struct lock_file *); extern void rollback_lock_file(struct lock_file *);
@ -387,6 +387,7 @@ extern int receive_keep_pack(int fd[2], const char *me, int quiet, int);
/* pager.c */ /* pager.c */
extern void setup_pager(void); extern void setup_pager(void);
extern int pager_in_use; extern int pager_in_use;
extern int pager_use_color;
/* base85 */ /* base85 */
int decode_85(char *dst, char *line, int linelen); int decode_85(char *dst, char *line, int linelen);

View File

@ -206,7 +206,7 @@ int main(int argc, char **argv)
state.refresh_cache = 1; state.refresh_cache = 1;
if (newfd < 0) if (newfd < 0)
newfd = hold_lock_file_for_update newfd = hold_lock_file_for_update
(&lock_file, get_index_file()); (&lock_file, get_index_file(), 1);
if (newfd < 0) if (newfd < 0)
die("cannot open index.lock file."); die("cannot open index.lock file.");
continue; continue;

View File

@ -497,11 +497,17 @@ static void show_parent_lno(struct sline *sline, unsigned long l0, unsigned long
printf(" -%lu,%lu", l0, l1-l0); printf(" -%lu,%lu", l0, l1-l0);
} }
static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent) static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent,
int use_color)
{ {
unsigned long mark = (1UL<<num_parent); unsigned long mark = (1UL<<num_parent);
int i; int i;
unsigned long lno = 0; unsigned long lno = 0;
const char *c_frag = diff_get_color(use_color, DIFF_FRAGINFO);
const char *c_new = diff_get_color(use_color, DIFF_FILE_NEW);
const char *c_old = diff_get_color(use_color, DIFF_FILE_OLD);
const char *c_plain = diff_get_color(use_color, DIFF_PLAIN);
const char *c_reset = diff_get_color(use_color, DIFF_RESET);
if (!cnt) if (!cnt)
return; /* result deleted */ return; /* result deleted */
@ -522,12 +528,13 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent)
rlines = hunk_end - lno; rlines = hunk_end - lno;
if (cnt < hunk_end) if (cnt < hunk_end)
rlines--; /* pointing at the last delete hunk */ rlines--; /* pointing at the last delete hunk */
fputs(c_frag, stdout);
for (i = 0; i <= num_parent; i++) putchar(combine_marker); for (i = 0; i <= num_parent; i++) putchar(combine_marker);
for (i = 0; i < num_parent; i++) for (i = 0; i < num_parent; i++)
show_parent_lno(sline, lno, hunk_end, i); show_parent_lno(sline, lno, hunk_end, i);
printf(" +%lu,%lu ", lno+1, rlines); printf(" +%lu,%lu ", lno+1, rlines);
for (i = 0; i <= num_parent; i++) putchar(combine_marker); for (i = 0; i <= num_parent; i++) putchar(combine_marker);
putchar('\n'); printf("%s\n", c_reset);
while (lno < hunk_end) { while (lno < hunk_end) {
struct lline *ll; struct lline *ll;
int j; int j;
@ -535,18 +542,23 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent)
sl = &sline[lno++]; sl = &sline[lno++];
ll = sl->lost_head; ll = sl->lost_head;
while (ll) { while (ll) {
fputs(c_old, stdout);
for (j = 0; j < num_parent; j++) { for (j = 0; j < num_parent; j++) {
if (ll->parent_map & (1UL<<j)) if (ll->parent_map & (1UL<<j))
putchar('-'); putchar('-');
else else
putchar(' '); putchar(' ');
} }
puts(ll->line); printf("%s%s\n", ll->line, c_reset);
ll = ll->next; ll = ll->next;
} }
if (cnt < lno) if (cnt < lno)
break; break;
p_mask = 1; p_mask = 1;
if (!(sl->flag & (mark-1)))
fputs(c_plain, stdout);
else
fputs(c_new, stdout);
for (j = 0; j < num_parent; j++) { for (j = 0; j < num_parent; j++) {
if (p_mask & sl->flag) if (p_mask & sl->flag)
putchar('+'); putchar('+');
@ -554,7 +566,7 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent)
putchar(' '); putchar(' ');
p_mask <<= 1; p_mask <<= 1;
} }
printf("%.*s\n", sl->len, sl->bol); printf("%.*s%s\n", sl->len, sl->bol, c_reset);
} }
} }
} }
@ -586,14 +598,15 @@ static void reuse_combine_diff(struct sline *sline, unsigned long cnt,
sline->p_lno[i] = sline->p_lno[j]; sline->p_lno[i] = sline->p_lno[j];
} }
static void dump_quoted_path(const char *prefix, const char *path) static void dump_quoted_path(const char *prefix, const char *path,
const char *c_meta, const char *c_reset)
{ {
fputs(prefix, stdout); printf("%s%s", c_meta, prefix);
if (quote_c_style(path, NULL, NULL, 0)) if (quote_c_style(path, NULL, NULL, 0))
quote_c_style(path, NULL, stdout, 0); quote_c_style(path, NULL, stdout, 0);
else else
printf("%s", path); printf("%s", path);
putchar('\n'); printf("%s\n", c_reset);
} }
static int show_patch_diff(struct combine_diff_path *elem, int num_parent, static int show_patch_diff(struct combine_diff_path *elem, int num_parent,
@ -699,18 +712,22 @@ static int show_patch_diff(struct combine_diff_path *elem, int num_parent,
if (show_hunks || mode_differs || working_tree_file) { if (show_hunks || mode_differs || working_tree_file) {
const char *abb; const char *abb;
int use_color = opt->color_diff;
const char *c_meta = diff_get_color(use_color, DIFF_METAINFO);
const char *c_reset = diff_get_color(use_color, DIFF_RESET);
if (rev->loginfo) if (rev->loginfo)
show_log(rev, opt->msg_sep); show_log(rev, opt->msg_sep);
dump_quoted_path(dense ? "diff --cc " : "diff --combined ", elem->path); dump_quoted_path(dense ? "diff --cc " : "diff --combined ",
printf("index "); elem->path, c_meta, c_reset);
printf("%sindex ", c_meta);
for (i = 0; i < num_parent; i++) { for (i = 0; i < num_parent; i++) {
abb = find_unique_abbrev(elem->parent[i].sha1, abb = find_unique_abbrev(elem->parent[i].sha1,
abbrev); abbrev);
printf("%s%s", i ? "," : "", abb); printf("%s%s", i ? "," : "", abb);
} }
abb = find_unique_abbrev(elem->sha1, abbrev); abb = find_unique_abbrev(elem->sha1, abbrev);
printf("..%s\n", abb); printf("..%s%s\n", abb, c_reset);
if (mode_differs) { if (mode_differs) {
int added = !!elem->mode; int added = !!elem->mode;
@ -719,10 +736,11 @@ static int show_patch_diff(struct combine_diff_path *elem, int num_parent,
DIFF_STATUS_ADDED) DIFF_STATUS_ADDED)
added = 0; added = 0;
if (added) if (added)
printf("new file mode %06o", elem->mode); printf("%snew file mode %06o",
c_meta, elem->mode);
else { else {
if (!elem->mode) if (!elem->mode)
printf("deleted file "); printf("%sdeleted file ", c_meta);
printf("mode "); printf("mode ");
for (i = 0; i < num_parent; i++) { for (i = 0; i < num_parent; i++) {
printf("%s%06o", i ? "," : "", printf("%s%06o", i ? "," : "",
@ -731,11 +749,11 @@ static int show_patch_diff(struct combine_diff_path *elem, int num_parent,
if (elem->mode) if (elem->mode)
printf("..%06o", elem->mode); printf("..%06o", elem->mode);
} }
putchar('\n'); printf("%s\n", c_reset);
} }
dump_quoted_path("--- a/", elem->path); dump_quoted_path("--- a/", elem->path, c_meta, c_reset);
dump_quoted_path("+++ b/", elem->path); dump_quoted_path("+++ b/", elem->path, c_meta, c_reset);
dump_sline(sline, cnt, num_parent); dump_sline(sline, cnt, num_parent, opt->color_diff);
} }
free(result); free(result);

View File

@ -309,6 +309,11 @@ int git_default_config(const char *var, const char *value)
return 0; return 0;
} }
if (!strcmp(var, "pager.color")) {
pager_use_color = git_config_bool(var,value);
return 0;
}
/* Add other config variables here and to Documentation/config.txt. */ /* Add other config variables here and to Documentation/config.txt. */
return 0; return 0;
} }

View File

@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script. # Process this file with autoconf to produce a configure script.
AC_PREREQ(2.59) AC_PREREQ(2.59)
AC_INIT([git], [1.4.1], [git@vger.kernel.org]) AC_INIT([git], [1.4.2], [git@vger.kernel.org])
AC_CONFIG_SRCDIR([git.c]) AC_CONFIG_SRCDIR([git.c])

View File

@ -1,5 +1,6 @@
#define _XOPEN_SOURCE 500 /* glibc2 and AIX 5.3L need this */ #define _XOPEN_SOURCE 500 /* glibc2 and AIX 5.3L need this */
#define _XOPEN_SOURCE_EXTENDED 1 /* AIX 5.3L needs this */ #define _XOPEN_SOURCE_EXTENDED 1 /* AIX 5.3L needs this */
#define _GNU_SOURCE
#include <time.h> #include <time.h>
#include "cache.h" #include "cache.h"
#include "blob.h" #include "blob.h"

14
diff.c
View File

@ -175,7 +175,7 @@ int git_diff_ui_config(const char *var, const char *value)
diff_use_color_default = 1; /* bool */ diff_use_color_default = 1; /* bool */
else if (!strcasecmp(value, "auto")) { else if (!strcasecmp(value, "auto")) {
diff_use_color_default = 0; diff_use_color_default = 0;
if (isatty(1) || pager_in_use) { if (isatty(1) || (pager_in_use && pager_use_color)) {
char *term = getenv("TERM"); char *term = getenv("TERM");
if (term && strcmp(term, "dumb")) if (term && strcmp(term, "dumb"))
diff_use_color_default = 1; diff_use_color_default = 1;
@ -1515,10 +1515,8 @@ void diff_setup(struct diff_options *options)
int diff_setup_done(struct diff_options *options) int diff_setup_done(struct diff_options *options)
{ {
if ((options->find_copies_harder && if (options->find_copies_harder)
options->detect_rename != DIFF_DETECT_COPY) || options->detect_rename = DIFF_DETECT_COPY;
(0 <= options->rename_limit && !options->detect_rename))
return -1;
if (options->output_format & (DIFF_FORMAT_NAME | if (options->output_format & (DIFF_FORMAT_NAME |
DIFF_FORMAT_NAME_STATUS | DIFF_FORMAT_NAME_STATUS |
@ -1786,13 +1784,9 @@ struct diff_filepair *diff_queue(struct diff_queue_struct *queue,
struct diff_filespec *one, struct diff_filespec *one,
struct diff_filespec *two) struct diff_filespec *two)
{ {
struct diff_filepair *dp = xmalloc(sizeof(*dp)); struct diff_filepair *dp = xcalloc(1, sizeof(*dp));
dp->one = one; dp->one = one;
dp->two = two; dp->two = two;
dp->score = 0;
dp->status = 0;
dp->source_stays = 0;
dp->broken_pair = 0;
if (queue) if (queue)
diff_q(queue, dp); diff_q(queue, dp);
return dp; return dp;

View File

@ -205,6 +205,7 @@ static void record_rename_pair(int dst_index, int src_index, int score)
fill_filespec(two, dst->sha1, dst->mode); fill_filespec(two, dst->sha1, dst->mode);
dp = diff_queue(NULL, one, two); dp = diff_queue(NULL, one, two);
dp->renamed_pair = 1;
if (!strcmp(src->path, dst->path)) if (!strcmp(src->path, dst->path))
dp->score = rename_src[src_index].score; dp->score = rename_src[src_index].score;
else else

View File

@ -53,11 +53,12 @@ struct diff_filepair {
char status; /* M C R N D U (see Documentation/diff-format.txt) */ char status; /* M C R N D U (see Documentation/diff-format.txt) */
unsigned source_stays : 1; /* all of R/C are copies */ unsigned source_stays : 1; /* all of R/C are copies */
unsigned broken_pair : 1; unsigned broken_pair : 1;
unsigned renamed_pair : 1;
}; };
#define DIFF_PAIR_UNMERGED(p) \ #define DIFF_PAIR_UNMERGED(p) \
(!DIFF_FILE_VALID((p)->one) && !DIFF_FILE_VALID((p)->two)) (!DIFF_FILE_VALID((p)->one) && !DIFF_FILE_VALID((p)->two))
#define DIFF_PAIR_RENAME(p) (strcmp((p)->one->path, (p)->two->path)) #define DIFF_PAIR_RENAME(p) ((p)->renamed_pair)
#define DIFF_PAIR_BROKEN(p) \ #define DIFF_PAIR_BROKEN(p) \
( (!DIFF_FILE_VALID((p)->one) != !DIFF_FILE_VALID((p)->two)) && \ ( (!DIFF_FILE_VALID((p)->one) != !DIFF_FILE_VALID((p)->two)) && \

View File

@ -23,6 +23,7 @@ int shared_repository = PERM_UMASK;
const char *apply_default_whitespace = NULL; const char *apply_default_whitespace = NULL;
int zlib_compression_level = Z_DEFAULT_COMPRESSION; int zlib_compression_level = Z_DEFAULT_COMPRESSION;
int pager_in_use; int pager_in_use;
int pager_use_color = 1;
static char *git_dir, *git_object_dir, *git_index_file, *git_refs_dir, static char *git_dir, *git_object_dir, *git_index_file, *git_refs_dir,
*git_graft_file; *git_graft_file;

View File

@ -129,10 +129,12 @@ static pid_t setup_sideband(int sideband, const char *me, int fd[2], int xd[2])
len--; len--;
switch (buf[0] & 0xFF) { switch (buf[0] & 0xFF) {
case 3: case 3:
safe_write(2, "remote: ", 8);
safe_write(2, buf+1, len); safe_write(2, buf+1, len);
fprintf(stderr, "\n"); safe_write(2, "\n", 1);
exit(1); exit(1);
case 2: case 2:
safe_write(2, "remote: ", 8);
safe_write(2, buf+1, len); safe_write(2, buf+1, len);
continue; continue;
case 1: case 1:

View File

@ -45,6 +45,12 @@ go_next () {
this=$next this=$next
} }
cannot_fallback () {
echo "$1"
echo "Cannot fall back to three-way merge."
exit 1
}
fall_back_3way () { fall_back_3way () {
O_OBJECT=`cd "$GIT_OBJECT_DIRECTORY" && pwd` O_OBJECT=`cd "$GIT_OBJECT_DIRECTORY" && pwd`
@ -52,19 +58,23 @@ fall_back_3way () {
mkdir "$dotest/patch-merge-tmp-dir" mkdir "$dotest/patch-merge-tmp-dir"
# First see if the patch records the index info that we can use. # First see if the patch records the index info that we can use.
if git-apply -z --index-info "$dotest/patch" \ git-apply -z --index-info "$dotest/patch" \
>"$dotest/patch-merge-index-info" 2>/dev/null && >"$dotest/patch-merge-index-info" &&
GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \ GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \
git-update-index -z --index-info <"$dotest/patch-merge-index-info" && git-update-index -z --index-info <"$dotest/patch-merge-index-info" &&
GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \ GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \
git-write-tree >"$dotest/patch-merge-base+" && git-write-tree >"$dotest/patch-merge-base+" ||
# index has the base tree now. cannot_fallback "Patch does not record usable index information."
GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \
echo Using index info to reconstruct a base tree...
if GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \
git-apply $binary --cached <"$dotest/patch" git-apply $binary --cached <"$dotest/patch"
then then
echo Using index info to reconstruct a base tree...
mv "$dotest/patch-merge-base+" "$dotest/patch-merge-base" mv "$dotest/patch-merge-base+" "$dotest/patch-merge-base"
mv "$dotest/patch-merge-tmp-index" "$dotest/patch-merge-index" mv "$dotest/patch-merge-tmp-index" "$dotest/patch-merge-index"
else
cannot_fallback "Did you hand edit your patch?
It does not apply to blobs recorded in its index."
fi fi
test -f "$dotest/patch-merge-index" && test -f "$dotest/patch-merge-index" &&

View File

@ -147,7 +147,7 @@ sub init_claim {
sub handle_rev { sub handle_rev {
my $i = 0; my $revseen = 0;
my %seen; my %seen;
while (my $rev = shift @revqueue) { while (my $rev = shift @revqueue) {
next if $seen{$rev}++; next if $seen{$rev}++;
@ -247,22 +247,129 @@ sub git_find_parent {
return $parent; return $parent;
} }
sub git_find_all_parents {
my ($rev) = @_;
my $revparent = open_pipe("git-rev-list","--remove-empty", "--parents","--max-count=1","$rev")
or die "Failed to open git-rev-list to find a single parent: $!";
my $parentline = <$revparent>;
chomp $parentline;
my ($origrev, @parents) = split m/\s+/, $parentline;
close($revparent);
return @parents;
}
sub git_merge_base {
my ($rev1, $rev2) = @_;
my $mb = open_pipe("git-merge-base", $rev1, $rev2)
or die "Failed to open git-merge-base: $!";
my $base = <$mb>;
chomp $base;
close($mb);
return $base;
}
# Construct a set of pseudo parents that are in the same order,
# and the same quantity as the real parents,
# but whose SHA1s are as similar to the logical parents
# as possible.
sub get_pseudo_parents {
my ($all, $fake) = @_;
my @all = @$all;
my @fake = @$fake;
my @pseudo;
my %fake = map {$_ => 1} @fake;
my %seenfake;
my $fakeidx = 0;
foreach my $p (@all) {
if (exists $fake{$p}) {
if ($fake[$fakeidx] ne $p) {
die sprintf("parent mismatch: %s != %s\nall:%s\nfake:%s\n",
$fake[$fakeidx], $p,
join(", ", @all),
join(", ", @fake),
);
}
push @pseudo, $p;
$fakeidx++;
$seenfake{$p}++;
} else {
my $base = git_merge_base($fake[$fakeidx], $p);
if ($base ne $fake[$fakeidx]) {
die sprintf("Result of merge-base doesn't match fake: %s,%s != %s\n",
$fake[$fakeidx], $p, $base);
}
# The details of how we parse the diffs
# mean that we cannot have a duplicate
# revision in the list, so if we've already
# seen the revision we would normally add, just use
# the actual revision.
if ($seenfake{$base}) {
push @pseudo, $p;
} else {
push @pseudo, $base;
$seenfake{$base}++;
}
}
}
return @pseudo;
}
# Get a diff between the current revision and a parent. # Get a diff between the current revision and a parent.
# Record the commit information that results. # Record the commit information that results.
sub git_diff_parse { sub git_diff_parse {
my ($parents, $rev, %revinfo) = @_; my ($parents, $rev, %revinfo) = @_;
my @pseudo_parents;
my @command = ("git-diff-tree");
my $revision_spec;
if (scalar @$parents == 1) {
$revision_spec = join("..", $parents->[0], $rev);
@pseudo_parents = @$parents;
} else {
my @all_parents = git_find_all_parents($rev);
if (@all_parents != @$parents) {
@pseudo_parents = get_pseudo_parents(\@all_parents, $parents);
} else {
@pseudo_parents = @$parents;
}
$revision_spec = $rev;
push @command, "-c";
}
my @filenames = ( $revs{$rev}{'filename'} ); my @filenames = ( $revs{$rev}{'filename'} );
foreach my $parent (@$parents) { foreach my $parent (@$parents) {
push @filenames, $revs{$parent}{'filename'}; push @filenames, $revs{$parent}{'filename'};
} }
my $diff = open_pipe("git-diff-tree","-M","-p","-c",$rev,"--", push @command, "-p", "-M", $revision_spec, "--", @filenames;
@filenames )
my $diff = open_pipe( @command )
or die "Failed to call git-diff for annotation: $!"; or die "Failed to call git-diff for annotation: $!";
_git_diff_parse($diff, $parents, $rev, %revinfo); _git_diff_parse($diff, \@pseudo_parents, $rev, %revinfo);
close($diff); close($diff);
} }
@ -283,6 +390,7 @@ sub _git_diff_parse {
$diff_header_regexp .= "@" x @$parents; $diff_header_regexp .= "@" x @$parents;
$diff_header_regexp .= ' -\d+,\d+' x @$parents; $diff_header_regexp .= ' -\d+,\d+' x @$parents;
$diff_header_regexp .= ' \+(\d+),\d+'; $diff_header_regexp .= ' \+(\d+),\d+';
$diff_header_regexp .= " " . ("@" x @$parents);
my %claim_regexps; my %claim_regexps;
my $allparentplus = '^' . '\\+' x @$parents . '(.*)$'; my $allparentplus = '^' . '\\+' x @$parents . '(.*)$';
@ -311,13 +419,13 @@ sub _git_diff_parse {
DIFF: DIFF:
while(<$diff>) { while(<$diff>) {
chomp; chomp;
#printf("%d:%s:\n", $gotheader, $_);
if (m/$diff_header_regexp/) { if (m/$diff_header_regexp/) {
$remstart = $1 - 1; $remstart = $1 - 1;
# (0-based arrays) # (0-based arrays)
$gotheader = 1; $gotheader = 1;
printf("Copying from %d to %d\n", $ri, $remstart);
foreach my $parent (@$parents) { foreach my $parent (@$parents) {
for (my $i = $ri; $i < $remstart; $i++) { for (my $i = $ri; $i < $remstart; $i++) {
$plines{$parent}[$pi{$parent}++] = $slines->[$i]; $plines{$parent}[$pi{$parent}++] = $slines->[$i];
@ -392,10 +500,17 @@ sub _git_diff_parse {
printf("parent %s is on line %d\n", $parent, $pi{$parent}); printf("parent %s is on line %d\n", $parent, $pi{$parent});
} }
my @context;
for (my $i = -2; $i < 2; $i++) {
push @context, get_line($slines, $ri + $i);
}
my $context = join("\n", @context);
my $justline = substr($_, scalar @$parents);
die sprintf("Line %d, does not match:\n|%s|\n|%s|\n%s\n", die sprintf("Line %d, does not match:\n|%s|\n|%s|\n%s\n",
$ri, $ri,
substr($_,scalar @$parents), $justline,
get_line($slines,$ri), $rev); $context);
} }
foreach my $parent (@$parents) { foreach my $parent (@$parents) {
$plines{$parent}[$pi{$parent}++] = $slines->[$ri]; $plines{$parent}[$pi{$parent}++] = $slines->[$ri];

View File

@ -67,6 +67,10 @@ while [ "$#" != "0" ]; do
set x "$arg" "$@" set x "$arg" "$@"
shift shift
fi fi
case "$1" in
--)
shift ;;
esac
break break
;; ;;
esac esac

View File

@ -205,7 +205,7 @@ dir="$2"
[ -e "$dir" ] && echo "$dir already exists." && usage [ -e "$dir" ] && echo "$dir already exists." && usage
mkdir -p "$dir" && mkdir -p "$dir" &&
D=$(cd "$dir" && pwd) && D=$(cd "$dir" && pwd) &&
trap 'err=$?; cd ..; rm -r "$D"; exit $err' 0 trap 'err=$?; cd ..; rm -rf "$D"; exit $err' 0
case "$bare" in case "$bare" in
yes) yes)
GIT_DIR="$D" ;; GIT_DIR="$D" ;;
@ -298,7 +298,7 @@ yes,yes)
fi fi
git-ls-remote "$repo" >"$GIT_DIR/CLONE_HEAD" || exit 1 git-ls-remote "$repo" >"$GIT_DIR/CLONE_HEAD" || exit 1
;; ;;
http://*) https://*|http://*)
if test -z "@@NO_CURL@@" if test -z "@@NO_CURL@@"
then then
clone_dumb_http "$repo" "$D" clone_dumb_http "$repo" "$D"
@ -324,7 +324,8 @@ test -d "$GIT_DIR/refs/reference-tmp" && rm -fr "$GIT_DIR/refs/reference-tmp"
if test -f "$GIT_DIR/CLONE_HEAD" if test -f "$GIT_DIR/CLONE_HEAD"
then then
# Read git-fetch-pack -k output and store the remote branches. # Read git-fetch-pack -k output and store the remote branches.
@@PERL@@ -e "$copy_refs" "$GIT_DIR" "$use_separate_remote" "$origin" @@PERL@@ -e "$copy_refs" "$GIT_DIR" "$use_separate_remote" "$origin" ||
exit
fi fi
cd "$D" || exit cd "$D" || exit

View File

@ -91,6 +91,9 @@ static inline void *xmalloc(size_t size)
ret = malloc(1); ret = malloc(1);
if (!ret) if (!ret)
die("Out of memory, malloc failed"); die("Out of memory, malloc failed");
#ifdef XMALLOC_POISON
memset(ret, 0xA5, size);
#endif
return ret; return ret;
} }
@ -136,6 +139,13 @@ static inline ssize_t xwrite(int fd, const void *buf, size_t len)
} }
} }
static inline int has_extension(const char *filename, const char *ext)
{
size_t len = strlen(filename);
size_t extlen = strlen(ext);
return len > extlen && !memcmp(filename + len - extlen, ext, extlen);
}
/* Sane ctype - no locale, and works with signed chars */ /* Sane ctype - no locale, and works with signed chars */
#undef isspace #undef isspace
#undef isdigit #undef isdigit

View File

@ -1,87 +0,0 @@
#!/bin/sh
USAGE='[--all] [--tags] [--force] <repository> [<refspec>...]'
. git-sh-setup
# Parse out parameters and then stop at remote, so that we can
# translate it using .git/branches information
has_all=
has_force=
has_exec=
has_thin=--thin
remote=
do_tags=
while case "$#" in 0) break ;; esac
do
case "$1" in
--all)
has_all=--all ;;
--tags)
do_tags=yes ;;
--force)
has_force=--force ;;
--exec=*)
has_exec="$1" ;;
--thin)
;; # noop
--no-thin)
has_thin= ;;
-*)
usage ;;
*)
set x "$@"
shift
break ;;
esac
shift
done
case "$#" in
0)
echo "Where would you want to push today?"
usage ;;
esac
. git-parse-remote
remote=$(get_remote_url "$@")
case "$has_all" in
--all)
set x ;;
'')
case "$do_tags,$#" in
yes,1)
set x $(cd "$GIT_DIR/refs" && find tags -type f -print) ;;
yes,*)
set x $(cd "$GIT_DIR/refs" && find tags -type f -print) \
$(get_remote_refs_for_push "$@") ;;
,*)
set x $(get_remote_refs_for_push "$@") ;;
esac
esac
shift ;# away the initial 'x'
# $# is now 0 if there was no explicit refspec on the command line
# and there was no default refspec to push from remotes/ file.
# we will let git-send-pack to do its "matching refs" thing.
case "$remote" in
git://*)
die "Cannot use READ-ONLY transport to push to $remote" ;;
rsync://*)
die "Pushing with rsync transport is deprecated" ;;
esac
set x "$remote" "$@"; shift
test "$has_all" && set x "$has_all" "$@" && shift
test "$has_force" && set x "$has_force" "$@" && shift
test "$has_exec" && set x "$has_exec" "$@" && shift
test "$has_thin" && set x "$has_thin" "$@" && shift
case "$remote" in
http://* | https://*)
exec git-http-push "$@";;
*)
exec git-send-pack "$@";;
esac

View File

@ -277,14 +277,11 @@ onto=$(git-rev-parse --verify "${onto_name}^0") || exit
# Check if we are already based on $onto, but this should be # Check if we are already based on $onto, but this should be
# done only when upstream and onto are the same. # done only when upstream and onto are the same.
if test "$upstream" = "$onto" mb=$(git-merge-base "$onto" "$branch")
if test "$upstream" = "$onto" && test "$mb" = "$onto"
then then
mb=$(git-merge-base "$onto" "$branch") echo >&2 "Current branch $branch_name is up to date."
if test "$mb" = "$onto" exit 0
then
echo >&2 "Current branch $branch_name is up to date."
exit 0
fi
fi fi
# Rewind the head to "$onto"; this saves our current head in ORIG_HEAD. # Rewind the head to "$onto"; this saves our current head in ORIG_HEAD.
@ -292,9 +289,9 @@ git-reset --hard "$onto"
# If the $onto is a proper descendant of the tip of the branch, then # If the $onto is a proper descendant of the tip of the branch, then
# we just fast forwarded. # we just fast forwarded.
if test "$mb" = "$onto" if test "$mb" = "$branch"
then then
echo >&2 "Fast-forwarded $branch to $newbase." echo >&2 "Fast-forwarded $branch_name to $onto_name."
exit 0 exit 0
fi fi

View File

@ -35,17 +35,12 @@ case "$1" in
exit exit
esac esac
# Make sure we are in a valid repository of a vintage we understand.
if [ -z "$SUBDIRECTORY_OK" ] if [ -z "$SUBDIRECTORY_OK" ]
then then
: ${GIT_DIR=.git} : ${GIT_DIR=.git}
: ${GIT_OBJECT_DIRECTORY="$GIT_DIR/objects"} GIT_DIR=$(GIT_DIR="$GIT_DIR" git-rev-parse --git-dir) || exit
# Make sure we are in a valid repository of a vintage we understand.
GIT_DIR="$GIT_DIR" git repo-config --get core.nosuch >/dev/null
if test $? = 128
then
exit
fi
else else
GIT_DIR=$(git-rev-parse --git-dir) || exit GIT_DIR=$(git-rev-parse --git-dir) || exit
fi fi
: ${GIT_OBJECT_DIRECTORY="$GIT_DIR/objects"}

View File

@ -31,6 +31,7 @@ use File::Basename qw/dirname basename/;
use File::Path qw/mkpath/; use File::Path qw/mkpath/;
use Getopt::Long qw/:config gnu_getopt no_ignore_case auto_abbrev pass_through/; use Getopt::Long qw/:config gnu_getopt no_ignore_case auto_abbrev pass_through/;
use File::Spec qw//; use File::Spec qw//;
use File::Copy qw/copy/;
use POSIX qw/strftime/; use POSIX qw/strftime/;
use IPC::Open3; use IPC::Open3;
use Memoize; use Memoize;
@ -77,9 +78,6 @@ my %cmt_opts = ( 'edit|e' => \$_edit,
'copy-similarity|C=i'=> \$_cp_similarity 'copy-similarity|C=i'=> \$_cp_similarity
); );
# yes, 'native' sets "\n". Patches to fix this for non-*nix systems welcome:
my %EOL = ( CR => "\015", LF => "\012", CRLF => "\015\012", native => "\012" );
my %cmd = ( my %cmd = (
fetch => [ \&fetch, "Download new revisions from SVN", fetch => [ \&fetch, "Download new revisions from SVN",
{ 'revision|r=s' => \$_revision, %fc_opts } ], { 'revision|r=s' => \$_revision, %fc_opts } ],
@ -1160,27 +1158,24 @@ sub repo_path_split {
} }
} }
my ($url, $path) = ($full_url =~ m!^([a-z\+]+://[^/]*)(.*)$!i);
$path =~ s#^/+##;
my @paths = split(m#/+#, $path);
if ($_use_lib) { if ($_use_lib) {
while (1) { my $tmp = libsvn_connect($full_url);
$SVN = libsvn_connect($url); my $url = $tmp->get_repos_root;
last if (defined $SVN && $full_url =~ s#^\Q$url\E/*##;
defined eval { $SVN->get_latest_revnum }); push @repo_path_split_cache, qr/^(\Q$url\E)/;
my $n = shift @paths || last; return ($url, $full_url);
$url .= "/$n";
}
} else { } else {
my ($url, $path) = ($full_url =~ m!^([a-z\+]+://[^/]*)(.*)$!i);
$path =~ s#^/+##;
my @paths = split(m#/+#, $path);
while (quiet_run(qw/svn ls --non-interactive/, $url)) { while (quiet_run(qw/svn ls --non-interactive/, $url)) {
my $n = shift @paths || last; my $n = shift @paths || last;
$url .= "/$n"; $url .= "/$n";
} }
push @repo_path_split_cache, qr/^(\Q$url\E)/;
$path = join('/',@paths);
return ($url, $path);
} }
push @repo_path_split_cache, qr/^(\Q$url\E)/;
$path = join('/',@paths);
return ($url, $path);
} }
sub setup_git_svn { sub setup_git_svn {
@ -1760,43 +1755,6 @@ sub svn_info {
sub sys { system(@_) == 0 or croak $? } sub sys { system(@_) == 0 or croak $? }
sub eol_cp {
my ($from, $to) = @_;
my $es = svn_propget_base('svn:eol-style', $to);
open my $rfd, '<', $from or croak $!;
binmode $rfd or croak $!;
open my $wfd, '>', $to or croak $!;
binmode $wfd or croak $!;
eol_cp_fd($rfd, $wfd, $es);
close $rfd or croak $!;
close $wfd or croak $!;
}
sub eol_cp_fd {
my ($rfd, $wfd, $es) = @_;
my $eol = defined $es ? $EOL{$es} : undef;
my $buf;
use bytes;
while (1) {
my ($r, $w, $t);
defined($r = sysread($rfd, $buf, 4096)) or croak $!;
return unless $r;
if ($eol) {
if ($buf =~ /\015$/) {
my $c;
defined($r = sysread($rfd,$c,1)) or croak $!;
$buf .= $c if $r > 0;
}
$buf =~ s/(?:\015\012|\015|\012)/$eol/gs;
$r = length($buf);
}
for ($w = 0; $w < $r; $w += $t) {
$t = syswrite($wfd, $buf, $r - $w, $w) or croak $!;
}
}
no bytes;
}
sub do_update_index { sub do_update_index {
my ($z_cmd, $cmd, $no_text_base) = @_; my ($z_cmd, $cmd, $no_text_base) = @_;
@ -1824,9 +1782,11 @@ sub do_update_index {
'text-base',"$f.svn-base"); 'text-base',"$f.svn-base");
$tb =~ s#^/##; $tb =~ s#^/##;
} }
my @s = stat($x);
unlink $x or croak $!; unlink $x or croak $!;
eol_cp($tb, $x); copy($tb, $x);
chmod(($mode &~ umask), $x) or croak $!; chmod(($mode &~ umask), $x) or croak $!;
utime $s[8], $s[9], $x;
} }
print $ui $x,"\0"; print $ui $x,"\0";
} }
@ -2617,7 +2577,9 @@ sub libsvn_connect {
sub libsvn_get_file { sub libsvn_get_file {
my ($gui, $f, $rev) = @_; my ($gui, $f, $rev) = @_;
my $p = $f; my $p = $f;
return unless ($p =~ s#^\Q$SVN_PATH\E/##); if (length $SVN_PATH > 0) {
return unless ($p =~ s#^\Q$SVN_PATH\E/##);
}
my ($hash, $pid, $in, $out); my ($hash, $pid, $in, $out);
my $pool = SVN::Pool->new; my $pool = SVN::Pool->new;
@ -2664,6 +2626,7 @@ sub libsvn_log_entry {
if (defined $_authors && ! defined $users{$author}) { if (defined $_authors && ! defined $users{$author}) {
die "Author: $author not defined in $_authors file\n"; die "Author: $author not defined in $_authors file\n";
} }
$msg = '' if ($rev == 0 && !defined $msg);
return { revision => $rev, date => "+0000 $Y-$m-$d $H:$M:$S", return { revision => $rev, date => "+0000 $Y-$m-$d $H:$M:$S",
author => $author, msg => $msg."\n", parents => $parents || [] } author => $author, msg => $msg."\n", parents => $parents || [] }
} }

24
git.c
View File

@ -15,6 +15,9 @@
#include "builtin.h" #include "builtin.h"
const char git_usage_string[] =
"git [--version] [--exec-path[=GIT_EXEC_PATH]] [--help] COMMAND [ ARGS ]";
static void prepend_to_path(const char *dir, int len) static void prepend_to_path(const char *dir, int len)
{ {
const char *old_path = getenv("PATH"); const char *old_path = getenv("PATH");
@ -78,7 +81,7 @@ static int handle_options(const char*** argv, int* argc)
setenv("GIT_DIR", getcwd(git_dir, 1024), 1); setenv("GIT_DIR", getcwd(git_dir, 1024), 1);
} else { } else {
fprintf(stderr, "Unknown option: %s\n", cmd); fprintf(stderr, "Unknown option: %s\n", cmd);
cmd_usage(0, NULL, NULL); usage(git_usage_string);
} }
(*argv)++; (*argv)++;
@ -211,6 +214,7 @@ static int handle_alias(int *argcp, const char ***argv)
const char git_version_string[] = GIT_VERSION; const char git_version_string[] = GIT_VERSION;
#define NEEDS_PREFIX 1 #define NEEDS_PREFIX 1
#define USE_PAGER 2
static void handle_internal_command(int argc, const char **argv, char **envp) static void handle_internal_command(int argc, const char **argv, char **envp)
{ {
@ -218,14 +222,14 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
static struct cmd_struct { static struct cmd_struct {
const char *cmd; const char *cmd;
int (*fn)(int, const char **, const char *); int (*fn)(int, const char **, const char *);
int prefix; int option;
} commands[] = { } commands[] = {
{ "version", cmd_version }, { "version", cmd_version },
{ "help", cmd_help }, { "help", cmd_help },
{ "log", cmd_log, NEEDS_PREFIX }, { "log", cmd_log, NEEDS_PREFIX | USE_PAGER },
{ "whatchanged", cmd_whatchanged, NEEDS_PREFIX }, { "whatchanged", cmd_whatchanged, NEEDS_PREFIX | USE_PAGER },
{ "show", cmd_show, NEEDS_PREFIX }, { "show", cmd_show, NEEDS_PREFIX | USE_PAGER },
{ "push", cmd_push }, { "push", cmd_push, NEEDS_PREFIX },
{ "format-patch", cmd_format_patch, NEEDS_PREFIX }, { "format-patch", cmd_format_patch, NEEDS_PREFIX },
{ "count-objects", cmd_count_objects }, { "count-objects", cmd_count_objects },
{ "diff", cmd_diff, NEEDS_PREFIX }, { "diff", cmd_diff, NEEDS_PREFIX },
@ -259,6 +263,8 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
{ "fmt-merge-msg", cmd_fmt_merge_msg, NEEDS_PREFIX }, { "fmt-merge-msg", cmd_fmt_merge_msg, NEEDS_PREFIX },
{ "prune", cmd_prune, NEEDS_PREFIX }, { "prune", cmd_prune, NEEDS_PREFIX },
{ "mv", cmd_mv, NEEDS_PREFIX }, { "mv", cmd_mv, NEEDS_PREFIX },
{ "prune-packed", cmd_prune_packed, NEEDS_PREFIX },
{ "repo-config", cmd_repo_config },
}; };
int i; int i;
@ -275,8 +281,10 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
continue; continue;
prefix = NULL; prefix = NULL;
if (p->prefix) if (p->option & NEEDS_PREFIX)
prefix = setup_git_directory(); prefix = setup_git_directory();
if (p->option & USE_PAGER)
setup_pager();
if (getenv("GIT_TRACE")) { if (getenv("GIT_TRACE")) {
int i; int i;
fprintf(stderr, "trace: built-in: git"); fprintf(stderr, "trace: built-in: git");
@ -372,7 +380,7 @@ int main(int argc, const char **argv, char **envp)
} }
if (errno == ENOENT) if (errno == ENOENT)
cmd_usage(0, exec_path, "'%s' is not a git-command", cmd); help_unknown_cmd(cmd);
fprintf(stderr, "Failed to run command '%s': %s\n", fprintf(stderr, "Failed to run command '%s': %s\n",
cmd, strerror(errno)); cmd, strerror(errno));

149
gitk
View File

@ -312,7 +312,7 @@ proc getcommit {id} {
proc readrefs {} { proc readrefs {} {
global tagids idtags headids idheads tagcontents global tagids idtags headids idheads tagcontents
global otherrefids idotherrefs global otherrefids idotherrefs mainhead
foreach v {tagids idtags headids idheads otherrefids idotherrefs} { foreach v {tagids idtags headids idheads otherrefids idotherrefs} {
catch {unset $v} catch {unset $v}
@ -358,6 +358,13 @@ proc readrefs {} {
} }
} }
close $refd close $refd
set mainhead {}
catch {
set thehead [exec git symbolic-ref HEAD]
if {[string match "refs/heads/*" $thehead]} {
set mainhead [string range $thehead 11 end]
}
}
} }
proc show_error {w top msg} { proc show_error {w top msg} {
@ -386,6 +393,7 @@ proc makewindow {} {
global rowctxmenu mergemax wrapcomment global rowctxmenu mergemax wrapcomment
global highlight_files gdttype global highlight_files gdttype
global searchstring sstring global searchstring sstring
global bgcolor fgcolor bglist fglist diffcolors
menu .bar menu .bar
.bar add cascade -label "File" -menu .bar.file .bar add cascade -label "File" -menu .bar.file
@ -446,18 +454,19 @@ proc makewindow {} {
.ctop add .ctop.top .ctop add .ctop.top
set canv .ctop.top.clist.canv set canv .ctop.top.clist.canv
canvas $canv -height $geometry(canvh) -width $geometry(canv1) \ canvas $canv -height $geometry(canvh) -width $geometry(canv1) \
-bg white -bd 0 \ -background $bgcolor -bd 0 \
-yscrollincr $linespc -yscrollcommand "scrollcanv $cscroll" -yscrollincr $linespc -yscrollcommand "scrollcanv $cscroll"
.ctop.top.clist add $canv .ctop.top.clist add $canv
set canv2 .ctop.top.clist.canv2 set canv2 .ctop.top.clist.canv2
canvas $canv2 -height $geometry(canvh) -width $geometry(canv2) \ canvas $canv2 -height $geometry(canvh) -width $geometry(canv2) \
-bg white -bd 0 -yscrollincr $linespc -background $bgcolor -bd 0 -yscrollincr $linespc
.ctop.top.clist add $canv2 .ctop.top.clist add $canv2
set canv3 .ctop.top.clist.canv3 set canv3 .ctop.top.clist.canv3
canvas $canv3 -height $geometry(canvh) -width $geometry(canv3) \ canvas $canv3 -height $geometry(canvh) -width $geometry(canv3) \
-bg white -bd 0 -yscrollincr $linespc -background $bgcolor -bd 0 -yscrollincr $linespc
.ctop.top.clist add $canv3 .ctop.top.clist add $canv3
bind .ctop.top.clist <Configure> {resizeclistpanes %W %w} bind .ctop.top.clist <Configure> {resizeclistpanes %W %w}
lappend bglist $canv $canv2 $canv3
set sha1entry .ctop.top.bar.sha1 set sha1entry .ctop.top.bar.sha1
set entries $sha1entry set entries $sha1entry
@ -563,19 +572,22 @@ proc makewindow {} {
trace add variable searchstring write incrsearch trace add variable searchstring write incrsearch
pack $sstring -side left -expand 1 -fill x pack $sstring -side left -expand 1 -fill x
set ctext .ctop.cdet.left.ctext set ctext .ctop.cdet.left.ctext
text $ctext -bg white -state disabled -font $textfont \ text $ctext -background $bgcolor -foreground $fgcolor \
-state disabled -font $textfont \
-width $geometry(ctextw) -height $geometry(ctexth) \ -width $geometry(ctextw) -height $geometry(ctexth) \
-yscrollcommand scrolltext -wrap none -yscrollcommand scrolltext -wrap none
scrollbar .ctop.cdet.left.sb -command "$ctext yview" scrollbar .ctop.cdet.left.sb -command "$ctext yview"
pack .ctop.cdet.left.sb -side right -fill y pack .ctop.cdet.left.sb -side right -fill y
pack $ctext -side left -fill both -expand 1 pack $ctext -side left -fill both -expand 1
.ctop.cdet add .ctop.cdet.left .ctop.cdet add .ctop.cdet.left
lappend bglist $ctext
lappend fglist $ctext
$ctext tag conf comment -wrap $wrapcomment $ctext tag conf comment -wrap $wrapcomment
$ctext tag conf filesep -font [concat $textfont bold] -back "#aaaaaa" $ctext tag conf filesep -font [concat $textfont bold] -back "#aaaaaa"
$ctext tag conf hunksep -fore blue $ctext tag conf hunksep -fore [lindex $diffcolors 2]
$ctext tag conf d0 -fore red $ctext tag conf d0 -fore [lindex $diffcolors 0]
$ctext tag conf d1 -fore "#00a000" $ctext tag conf d1 -fore [lindex $diffcolors 1]
$ctext tag conf m0 -fore red $ctext tag conf m0 -fore red
$ctext tag conf m1 -fore blue $ctext tag conf m1 -fore blue
$ctext tag conf m2 -fore green $ctext tag conf m2 -fore green
@ -608,11 +620,15 @@ proc makewindow {} {
pack .ctop.cdet.right.mode -side top -fill x pack .ctop.cdet.right.mode -side top -fill x
set cflist .ctop.cdet.right.cfiles set cflist .ctop.cdet.right.cfiles
set indent [font measure $mainfont "nn"] set indent [font measure $mainfont "nn"]
text $cflist -width $geometry(cflistw) -background white -font $mainfont \ text $cflist -width $geometry(cflistw) \
-background $bgcolor -foreground $fgcolor \
-font $mainfont \
-tabs [list $indent [expr {2 * $indent}]] \ -tabs [list $indent [expr {2 * $indent}]] \
-yscrollcommand ".ctop.cdet.right.sb set" \ -yscrollcommand ".ctop.cdet.right.sb set" \
-cursor [. cget -cursor] \ -cursor [. cget -cursor] \
-spacing1 1 -spacing3 1 -spacing1 1 -spacing3 1
lappend bglist $cflist
lappend fglist $cflist
scrollbar .ctop.cdet.right.sb -command "$cflist yview" scrollbar .ctop.cdet.right.sb -command "$cflist yview"
pack .ctop.cdet.right.sb -side right -fill y pack .ctop.cdet.right.sb -side right -fill y
pack $cflist -side left -fill both -expand 1 pack $cflist -side left -fill both -expand 1
@ -747,6 +763,7 @@ proc savestuff {w} {
global maxwidth showneartags global maxwidth showneartags
global viewname viewfiles viewargs viewperm nextviewnum global viewname viewfiles viewargs viewperm nextviewnum
global cmitmode wrapcomment global cmitmode wrapcomment
global colors bgcolor fgcolor diffcolors
if {$stuffsaved} return if {$stuffsaved} return
if {![winfo viewable .]} return if {![winfo viewable .]} return
@ -761,6 +778,10 @@ proc savestuff {w} {
puts $f [list set cmitmode $cmitmode] puts $f [list set cmitmode $cmitmode]
puts $f [list set wrapcomment $wrapcomment] puts $f [list set wrapcomment $wrapcomment]
puts $f [list set showneartags $showneartags] puts $f [list set showneartags $showneartags]
puts $f [list set bgcolor $bgcolor]
puts $f [list set fgcolor $fgcolor]
puts $f [list set colors $colors]
puts $f [list set diffcolors $diffcolors]
puts $f "set geometry(width) [winfo width .ctop]" puts $f "set geometry(width) [winfo width .ctop]"
puts $f "set geometry(height) [winfo height .ctop]" puts $f "set geometry(height) [winfo height .ctop]"
puts $f "set geometry(canv1) [expr {[winfo width $canv]-2}]" puts $f "set geometry(canv1) [expr {[winfo width $canv]-2}]"
@ -2870,11 +2891,11 @@ proc drawlines {id} {
} }
proc drawcmittext {id row col rmx} { proc drawcmittext {id row col rmx} {
global linespc canv canv2 canv3 canvy0 global linespc canv canv2 canv3 canvy0 fgcolor
global commitlisted commitinfo rowidlist global commitlisted commitinfo rowidlist
global rowtextx idpos idtags idheads idotherrefs global rowtextx idpos idtags idheads idotherrefs
global linehtag linentag linedtag global linehtag linentag linedtag
global mainfont canvxmax boldrows boldnamerows global mainfont canvxmax boldrows boldnamerows fgcolor
set ofill [expr {[lindex $commitlisted $row]? "blue": "white"}] set ofill [expr {[lindex $commitlisted $row]? "blue": "white"}]
set x [xc $row $col] set x [xc $row $col]
@ -2882,7 +2903,7 @@ proc drawcmittext {id row col rmx} {
set orad [expr {$linespc / 3}] set orad [expr {$linespc / 3}]
set t [$canv create oval [expr {$x - $orad}] [expr {$y - $orad}] \ set t [$canv create oval [expr {$x - $orad}] [expr {$y - $orad}] \
[expr {$x + $orad - 1}] [expr {$y + $orad - 1}] \ [expr {$x + $orad - 1}] [expr {$y + $orad - 1}] \
-fill $ofill -outline black -width 1] -fill $ofill -outline $fgcolor -width 1 -tags circle]
$canv raise $t $canv raise $t
$canv bind $t <1> {selcanvline {} %x %y} $canv bind $t <1> {selcanvline {} %x %y}
set xt [xc $row [llength [lindex $rowidlist $row]]] set xt [xc $row [llength [lindex $rowidlist $row]]]
@ -2910,13 +2931,13 @@ proc drawcmittext {id row col rmx} {
lappend nfont bold lappend nfont bold
} }
} }
set linehtag($row) [$canv create text $xt $y -anchor w \ set linehtag($row) [$canv create text $xt $y -anchor w -fill $fgcolor \
-text $headline -font $font] -text $headline -font $font -tags text]
$canv bind $linehtag($row) <Button-3> "rowmenu %X %Y $id" $canv bind $linehtag($row) <Button-3> "rowmenu %X %Y $id"
set linentag($row) [$canv2 create text 3 $y -anchor w \ set linentag($row) [$canv2 create text 3 $y -anchor w -fill $fgcolor \
-text $name -font $nfont] -text $name -font $nfont -tags text]
set linedtag($row) [$canv3 create text 3 $y -anchor w \ set linedtag($row) [$canv3 create text 3 $y -anchor w -fill $fgcolor \
-text $date -font $mainfont] -text $date -font $mainfont -tags text]
set xr [expr {$xt + [font measure $mainfont $headline]}] set xr [expr {$xt + [font measure $mainfont $headline]}]
if {$xr > $canvxmax} { if {$xr > $canvxmax} {
set canvxmax $xr set canvxmax $xr
@ -3136,9 +3157,9 @@ proc bindline {t id} {
} }
proc drawtags {id x xt y1} { proc drawtags {id x xt y1} {
global idtags idheads idotherrefs global idtags idheads idotherrefs mainhead
global linespc lthickness global linespc lthickness
global canv mainfont commitrow rowtextx curview global canv mainfont commitrow rowtextx curview fgcolor bgcolor
set marks {} set marks {}
set ntags 0 set ntags 0
@ -3163,8 +3184,14 @@ proc drawtags {id x xt y1} {
set yb [expr {$yt + $linespc - 1}] set yb [expr {$yt + $linespc - 1}]
set xvals {} set xvals {}
set wvals {} set wvals {}
set i -1
foreach tag $marks { foreach tag $marks {
set wid [font measure $mainfont $tag] incr i
if {$i >= $ntags && $i < $ntags + $nheads && $tag eq $mainhead} {
set wid [font measure [concat $mainfont bold] $tag]
} else {
set wid [font measure $mainfont $tag]
}
lappend xvals $xt lappend xvals $xt
lappend wvals $wid lappend wvals $wid
set xt [expr {$xt + $delta + $wid + $lthickness + $linespc}] set xt [expr {$xt + $delta + $wid + $lthickness + $linespc}]
@ -3175,6 +3202,7 @@ proc drawtags {id x xt y1} {
foreach tag $marks x $xvals wid $wvals { foreach tag $marks x $xvals wid $wvals {
set xl [expr {$x + $delta}] set xl [expr {$x + $delta}]
set xr [expr {$x + $delta + $wid + $lthickness}] set xr [expr {$x + $delta + $wid + $lthickness}]
set font $mainfont
if {[incr ntags -1] >= 0} { if {[incr ntags -1] >= 0} {
# draw a tag # draw a tag
set t [$canv create polygon $x [expr {$yt + $delta}] $xl $yt \ set t [$canv create polygon $x [expr {$yt + $delta}] $xl $yt \
@ -3186,6 +3214,9 @@ proc drawtags {id x xt y1} {
# draw a head or other ref # draw a head or other ref
if {[incr nheads -1] >= 0} { if {[incr nheads -1] >= 0} {
set col green set col green
if {$tag eq $mainhead} {
lappend font bold
}
} else { } else {
set col "#ddddff" set col "#ddddff"
} }
@ -3201,8 +3232,8 @@ proc drawtags {id x xt y1} {
-width 0 -fill "#ffddaa" -tags tag.$id -width 0 -fill "#ffddaa" -tags tag.$id
} }
} }
set t [$canv create text $xl $y1 -anchor w -text $tag \ set t [$canv create text $xl $y1 -anchor w -text $tag -fill $fgcolor \
-font $mainfont -tags tag.$id] -font $font -tags [list tag.$id text]]
if {$ntags >= 0} { if {$ntags >= 0} {
$canv bind $t <1> [list showtag $tag 1] $canv bind $t <1> [list showtag $tag 1]
} }
@ -3223,10 +3254,11 @@ proc xcoord {i level ln} {
} }
proc show_status {msg} { proc show_status {msg} {
global canv mainfont global canv mainfont fgcolor
clear_display clear_display
$canv create text 3 3 -anchor nw -text $msg -font $mainfont -tags textitems $canv create text 3 3 -anchor nw -text $msg -font $mainfont \
-tags text -fill $fgcolor
} }
proc finishcommits {} { proc finishcommits {} {
@ -4574,7 +4606,8 @@ proc linehover {} {
set t [$canv create rectangle $x0 $y0 $x1 $y1 \ set t [$canv create rectangle $x0 $y0 $x1 $y1 \
-fill \#ffff80 -outline black -width 1 -tags hover] -fill \#ffff80 -outline black -width 1 -tags hover]
$canv raise $t $canv raise $t
set t [$canv create text $x $y -anchor nw -text $text -tags hover -font $mainfont] set t [$canv create text $x $y -anchor nw -text $text -tags hover \
-font $mainfont]
$canv raise $t $canv raise $t
} }
@ -4901,7 +4934,7 @@ proc domktag {} {
proc redrawtags {id} { proc redrawtags {id} {
global canv linehtag commitrow idpos selectedline curview global canv linehtag commitrow idpos selectedline curview
global mainfont global mainfont canvxmax
if {![info exists commitrow($curview,$id)]} return if {![info exists commitrow($curview,$id)]} return
drawcmitrow $commitrow($curview,$id) drawcmitrow $commitrow($curview,$id)
@ -5242,6 +5275,7 @@ proc doquit {} {
proc doprefs {} { proc doprefs {} {
global maxwidth maxgraphpct diffopts global maxwidth maxgraphpct diffopts
global oldprefs prefstop showneartags global oldprefs prefstop showneartags
global bgcolor fgcolor ctext diffcolors
set top .gitkprefs set top .gitkprefs
set prefstop $top set prefstop $top
@ -5265,6 +5299,7 @@ proc doprefs {} {
-font optionfont -font optionfont
spinbox $top.maxpct -from 1 -to 100 -width 4 -textvariable maxgraphpct spinbox $top.maxpct -from 1 -to 100 -width 4 -textvariable maxgraphpct
grid x $top.maxpctl $top.maxpct -sticky w grid x $top.maxpctl $top.maxpct -sticky w
label $top.ddisp -text "Diff display options" label $top.ddisp -text "Diff display options"
grid $top.ddisp - -sticky w -pady 10 grid $top.ddisp - -sticky w -pady 10
label $top.diffoptl -text "Options for diff program" \ label $top.diffoptl -text "Options for diff program" \
@ -5276,6 +5311,34 @@ proc doprefs {} {
checkbutton $top.ntag.b -variable showneartags checkbutton $top.ntag.b -variable showneartags
pack $top.ntag.b $top.ntag.l -side left pack $top.ntag.b $top.ntag.l -side left
grid x $top.ntag -sticky w grid x $top.ntag -sticky w
label $top.cdisp -text "Colors: press to choose"
grid $top.cdisp - -sticky w -pady 10
label $top.bg -padx 40 -relief sunk -background $bgcolor
button $top.bgbut -text "Background" -font optionfont \
-command [list choosecolor bgcolor 0 $top.bg background setbg]
grid x $top.bgbut $top.bg -sticky w
label $top.fg -padx 40 -relief sunk -background $fgcolor
button $top.fgbut -text "Foreground" -font optionfont \
-command [list choosecolor fgcolor 0 $top.fg foreground setfg]
grid x $top.fgbut $top.fg -sticky w
label $top.diffold -padx 40 -relief sunk -background [lindex $diffcolors 0]
button $top.diffoldbut -text "Diff: old lines" -font optionfont \
-command [list choosecolor diffcolors 0 $top.diffold "diff old lines" \
[list $ctext tag conf d0 -foreground]]
grid x $top.diffoldbut $top.diffold -sticky w
label $top.diffnew -padx 40 -relief sunk -background [lindex $diffcolors 1]
button $top.diffnewbut -text "Diff: new lines" -font optionfont \
-command [list choosecolor diffcolors 1 $top.diffnew "diff new lines" \
[list $ctext tag conf d1 -foreground]]
grid x $top.diffnewbut $top.diffnew -sticky w
label $top.hunksep -padx 40 -relief sunk -background [lindex $diffcolors 2]
button $top.hunksepbut -text "Diff: hunk header" -font optionfont \
-command [list choosecolor diffcolors 2 $top.hunksep \
"diff hunk header" \
[list $ctext tag conf hunksep -foreground]]
grid x $top.hunksepbut $top.hunksep -sticky w
frame $top.buts frame $top.buts
button $top.buts.ok -text "OK" -command prefsok button $top.buts.ok -text "OK" -command prefsok
button $top.buts.can -text "Cancel" -command prefscan button $top.buts.can -text "Cancel" -command prefscan
@ -5285,6 +5348,35 @@ proc doprefs {} {
grid $top.buts - - -pady 10 -sticky ew grid $top.buts - - -pady 10 -sticky ew
} }
proc choosecolor {v vi w x cmd} {
global $v
set c [tk_chooseColor -initialcolor [lindex [set $v] $vi] \
-title "Gitk: choose color for $x"]
if {$c eq {}} return
$w conf -background $c
lset $v $vi $c
eval $cmd $c
}
proc setbg {c} {
global bglist
foreach w $bglist {
$w conf -background $c
}
}
proc setfg {c} {
global fglist canv
foreach w $fglist {
$w conf -foreground $c
}
allcanvs itemconf text -fill $c
$canv itemconf circle -outline $c
}
proc prefscan {} { proc prefscan {} {
global maxwidth maxgraphpct diffopts global maxwidth maxgraphpct diffopts
global oldprefs prefstop showneartags global oldprefs prefstop showneartags
@ -5620,6 +5712,9 @@ set wrapcomment "none"
set showneartags 1 set showneartags 1
set colors {green red blue magenta darkgrey brown orange} set colors {green red blue magenta darkgrey brown orange}
set bgcolor white
set fgcolor black
set diffcolors {red "#00a000" blue}
catch {source ~/.gitk} catch {source ~/.gitk}

View File

@ -46,7 +46,7 @@ int main(int argc, char **argv)
if (!no_more_flags && argv[i][0] == '-') { if (!no_more_flags && argv[i][0] == '-') {
if (!strcmp(argv[i], "-t")) { if (!strcmp(argv[i], "-t")) {
if (argc <= ++i) if (argc <= ++i)
die(hash_object_usage); usage(hash_object_usage);
type = argv[i]; type = argv[i];
} }
else if (!strcmp(argv[i], "-w")) { else if (!strcmp(argv[i], "-w")) {
@ -66,8 +66,8 @@ int main(int argc, char **argv)
hash_stdin(type, write_object); hash_stdin(type, write_object);
} }
else else
die(hash_object_usage); usage(hash_object_usage);
} }
else { else {
const char *arg = argv[i]; const char *arg = argv[i];
if (0 <= prefix_length) if (0 <= prefix_length)

View File

@ -870,7 +870,7 @@ static void process_ls_pack(struct remote_ls_ctx *ls)
if (strlen(ls->dentry_name) == 63 && if (strlen(ls->dentry_name) == 63 &&
!strncmp(ls->dentry_name, "objects/pack/pack-", 18) && !strncmp(ls->dentry_name, "objects/pack/pack-", 18) &&
!strncmp(ls->dentry_name+58, ".pack", 5)) { has_extension(ls->dentry_name, ".pack")) {
get_sha1_hex(ls->dentry_name + 18, sha1); get_sha1_hex(ls->dentry_name + 18, sha1);
setup_index(ls->repo, sha1); setup_index(ls->repo, sha1);
} }
@ -1226,6 +1226,7 @@ int main(int argc, const char **argv)
int arg = 1; int arg = 1;
int rc = 0; int rc = 0;
setup_ident();
setup_git_directory(); setup_git_directory();
git_config(git_default_config); git_config(git_default_config);

View File

@ -530,7 +530,7 @@ static void start_put(struct transfer_request *request)
request->dest = xmalloc(strlen(request->url) + 14); request->dest = xmalloc(strlen(request->url) + 14);
sprintf(request->dest, "Destination: %s", request->url); sprintf(request->dest, "Destination: %s", request->url);
posn += 38; posn += 38;
*(posn++) = '.'; *(posn++) = '_';
strcpy(posn, request->lock->token); strcpy(posn, request->lock->token);
slot = get_active_slot(); slot = get_active_slot();

View File

@ -447,7 +447,7 @@ int main(int argc, char **argv)
usage(index_pack_usage); usage(index_pack_usage);
if (!index_name) { if (!index_name) {
int len = strlen(pack_name); int len = strlen(pack_name);
if (len < 5 || strcmp(pack_name + len - 5, ".pack")) if (!has_extension(pack_name, ".pack"))
die("packfile name '%s' does not end with '.pack'", die("packfile name '%s' does not end with '.pack'",
pack_name); pack_name);
index_name_buf = xmalloc(len); index_name_buf = xmalloc(len);

View File

@ -43,8 +43,8 @@ static int setup_indices(void)
return -1; return -1;
while ((de = readdir(dir)) != NULL) { while ((de = readdir(dir)) != NULL) {
int namelen = strlen(de->d_name); int namelen = strlen(de->d_name);
if (namelen != 50 || if (namelen != 50 ||
strcmp(de->d_name + namelen - 5, ".pack")) !has_extension(de->d_name, ".pack"))
continue; continue;
get_sha1_hex(de->d_name + 5, sha1); get_sha1_hex(de->d_name + 5, sha1);
setup_index(sha1); setup_index(sha1);
@ -210,6 +210,7 @@ int main(int argc, const char **argv)
char **commit_id; char **commit_id;
int arg = 1; int arg = 1;
setup_ident();
setup_git_directory(); setup_git_directory();
git_config(git_default_config); git_config(git_default_config);

View File

@ -22,7 +22,7 @@ static void remove_lock_file_on_signal(int signo)
raise(signo); raise(signo);
} }
int hold_lock_file_for_update(struct lock_file *lk, const char *path) static int lock_file(struct lock_file *lk, const char *path)
{ {
int fd; int fd;
sprintf(lk->filename, "%s.lock", path); sprintf(lk->filename, "%s.lock", path);
@ -41,6 +41,14 @@ int hold_lock_file_for_update(struct lock_file *lk, const char *path)
return fd; return fd;
} }
int hold_lock_file_for_update(struct lock_file *lk, const char *path, int die_on_error)
{
int fd = lock_file(lk, path);
if (fd < 0 && die_on_error)
die("unable to create '%s': %s", path, strerror(errno));
return fd;
}
int commit_lock_file(struct lock_file *lk) int commit_lock_file(struct lock_file *lk)
{ {
char result_file[PATH_MAX]; char result_file[PATH_MAX];

View File

@ -59,7 +59,7 @@ void show_log(struct rev_info *opt, const char *sep)
fputs(diff_unique_abbrev(commit->object.sha1, abbrev_commit), stdout); fputs(diff_unique_abbrev(commit->object.sha1, abbrev_commit), stdout);
if (opt->parents) if (opt->parents)
show_parents(commit, abbrev_commit); show_parents(commit, abbrev_commit);
putchar('\n'); putchar(opt->diffopt.line_termination);
return; return;
} }

View File

@ -125,9 +125,7 @@ static int flush_cache(void)
{ {
/* flush temporary index */ /* flush temporary index */
struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
int fd = hold_lock_file_for_update(lock, current_index_file); int fd = hold_lock_file_for_update(lock, current_index_file, 1);
if (fd < 0)
die("could not lock %s", lock->filename);
if (write_cache(fd, active_cache, active_nr) || if (write_cache(fd, active_cache, active_nr) ||
close(fd) || commit_lock_file(lock)) close(fd) || commit_lock_file(lock))
die ("unable to write %s", current_index_file); die ("unable to write %s", current_index_file);

45
mktag.c
View File

@ -2,10 +2,11 @@
#include "tag.h" #include "tag.h"
/* /*
* A signature file has a very simple fixed format: three lines * A signature file has a very simple fixed format: four lines
* of "object <sha1>" + "type <typename>" + "tag <tagname>", * of "object <sha1>" + "type <typename>" + "tag <tagname>" +
* followed by some free-form signature that git itself doesn't * "tagger <committer>", followed by a blank line, a free-form tag
* care about, but that can be verified with gpg or similar. * message and a signature block that git itself doesn't care about,
* but that can be verified with gpg or similar.
* *
* The first three lines are guaranteed to be at least 63 bytes: * The first three lines are guaranteed to be at least 63 bytes:
* "object <sha1>\n" is 48 bytes, "type tag\n" at 9 bytes is the * "object <sha1>\n" is 48 bytes, "type tag\n" at 9 bytes is the
@ -38,6 +39,12 @@ static int verify_object(unsigned char *sha1, const char *expected_type)
return ret; return ret;
} }
#ifdef NO_C99_FORMAT
#define PD_FMT "%d"
#else
#define PD_FMT "%td"
#endif
static int verify_tag(char *buffer, unsigned long size) static int verify_tag(char *buffer, unsigned long size)
{ {
int typelen; int typelen;
@ -46,45 +53,42 @@ static int verify_tag(char *buffer, unsigned long size)
const char *object, *type_line, *tag_line, *tagger_line; const char *object, *type_line, *tag_line, *tagger_line;
if (size < 64) if (size < 64)
return error("wanna fool me ? you obviously got the size wrong !\n"); return error("wanna fool me ? you obviously got the size wrong !");
buffer[size] = 0; buffer[size] = 0;
/* Verify object line */ /* Verify object line */
object = buffer; object = buffer;
if (memcmp(object, "object ", 7)) if (memcmp(object, "object ", 7))
return error("char%d: does not start with \"object \"\n", 0); return error("char%d: does not start with \"object \"", 0);
if (get_sha1_hex(object + 7, sha1)) if (get_sha1_hex(object + 7, sha1))
return error("char%d: could not get SHA1 hash\n", 7); return error("char%d: could not get SHA1 hash", 7);
/* Verify type line */ /* Verify type line */
type_line = object + 48; type_line = object + 48;
if (memcmp(type_line - 1, "\ntype ", 6)) if (memcmp(type_line - 1, "\ntype ", 6))
return error("char%d: could not find \"\\ntype \"\n", 47); return error("char%d: could not find \"\\ntype \"", 47);
/* Verify tag-line */ /* Verify tag-line */
tag_line = strchr(type_line, '\n'); tag_line = strchr(type_line, '\n');
if (!tag_line) if (!tag_line)
return error("char%td: could not find next \"\\n\"\n", type_line - buffer); return error("char" PD_FMT ": could not find next \"\\n\"", type_line - buffer);
tag_line++; tag_line++;
if (memcmp(tag_line, "tag ", 4) || tag_line[4] == '\n') if (memcmp(tag_line, "tag ", 4) || tag_line[4] == '\n')
return error("char%td: no \"tag \" found\n", tag_line - buffer); return error("char" PD_FMT ": no \"tag \" found", tag_line - buffer);
/* Get the actual type */ /* Get the actual type */
typelen = tag_line - type_line - strlen("type \n"); typelen = tag_line - type_line - strlen("type \n");
if (typelen >= sizeof(type)) if (typelen >= sizeof(type))
return error("char%td: type too long\n", type_line+5 - buffer); return error("char" PD_FMT ": type too long", type_line+5 - buffer);
memcpy(type, type_line+5, typelen); memcpy(type, type_line+5, typelen);
type[typelen] = 0; type[typelen] = 0;
/* Verify that the object matches */ /* Verify that the object matches */
if (get_sha1_hex(object + 7, sha1))
return error("char%d: could not get SHA1 hash but this is really odd since i got it before !\n", 7);
if (verify_object(sha1, type)) if (verify_object(sha1, type))
return error("char%d: could not verify object %s\n", 7, sha1); return error("char%d: could not verify object %s", 7, sha1_to_hex(sha1));
/* Verify the tag-name: we don't allow control characters or spaces in it */ /* Verify the tag-name: we don't allow control characters or spaces in it */
tag_line += 4; tag_line += 4;
@ -94,19 +98,24 @@ static int verify_tag(char *buffer, unsigned long size)
break; break;
if (c > ' ') if (c > ' ')
continue; continue;
return error("char%td: could not verify tag name\n", tag_line - buffer); return error("char" PD_FMT ": could not verify tag name", tag_line - buffer);
} }
/* Verify the tagger line */ /* Verify the tagger line */
tagger_line = tag_line; tagger_line = tag_line;
if (memcmp(tagger_line, "tagger", 6) || (tagger_line[6] == '\n')) if (memcmp(tagger_line, "tagger", 6) || (tagger_line[6] == '\n'))
return error("char%td: could not find \"tagger\"\n", tagger_line - buffer); return error("char" PD_FMT ": could not find \"tagger\"", tagger_line - buffer);
/* TODO: check for committer info + blank line? */
/* Also, the minimum length is probably + "tagger .", or 63+8=71 */
/* The actual stuff afterwards we don't care about.. */ /* The actual stuff afterwards we don't care about.. */
return 0; return 0;
} }
#undef PD_FMT
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
unsigned long size = 4096; unsigned long size = 4096;
@ -114,7 +123,7 @@ int main(int argc, char **argv)
unsigned char result_sha1[20]; unsigned char result_sha1[20];
if (argc != 1) if (argc != 1)
usage("cat <signaturefile> | git-mktag"); usage("git-mktag < signaturefile");
setup_git_directory(); setup_git_directory();

View File

@ -71,7 +71,7 @@ static void write_tree(unsigned char *sha1)
write_sha1_file(buffer, offset, tree_type, sha1); write_sha1_file(buffer, offset, tree_type, sha1);
} }
static const char mktree_usage[] = "mktree [-z]"; static const char mktree_usage[] = "git-mktree [-z]";
int main(int ac, char **av) int main(int ac, char **av)
{ {

View File

@ -61,7 +61,7 @@ static int ce_compare_data(struct cache_entry *ce, struct stat *st)
unsigned char sha1[20]; unsigned char sha1[20];
if (!index_fd(sha1, fd, st, 0, NULL)) if (!index_fd(sha1, fd, st, 0, NULL))
match = memcmp(sha1, ce->sha1, 20); match = memcmp(sha1, ce->sha1, 20);
close(fd); /* index_fd() closed the file descriptor already */
} }
return match; return match;
} }

10
refs.c
View File

@ -147,7 +147,7 @@ static int do_for_each_ref(const char *base, int (*fn)(const char *path, const u
namelen = strlen(de->d_name); namelen = strlen(de->d_name);
if (namelen > 255) if (namelen > 255)
continue; continue;
if (namelen>5 && !strcmp(de->d_name+namelen-5,".lock")) if (has_extension(de->d_name, ".lock"))
continue; continue;
memcpy(path + baselen, de->d_name, namelen+1); memcpy(path + baselen, de->d_name, namelen+1);
if (stat(git_path("%s", path), &st) < 0) if (stat(git_path("%s", path), &st) < 0)
@ -319,13 +319,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *path,
if (safe_create_leading_directories(lock->ref_file)) if (safe_create_leading_directories(lock->ref_file))
die("unable to create directory for %s", lock->ref_file); die("unable to create directory for %s", lock->ref_file);
lock->lock_fd = hold_lock_file_for_update(lock->lk, lock->ref_file); lock->lock_fd = hold_lock_file_for_update(lock->lk, lock->ref_file, 1);
if (lock->lock_fd < 0) {
error("Couldn't open lock file %s: %s",
lock->lk->filename, strerror(errno));
unlock_ref(lock);
return NULL;
}
return old_sha1 ? verify_lock(lock, old_sha1, mustexist) : lock; return old_sha1 ? verify_lock(lock, old_sha1, mustexist) : lock;
} }

View File

@ -936,7 +936,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
revs->diffopt.output_format = DIFF_FORMAT_PATCH; revs->diffopt.output_format = DIFF_FORMAT_PATCH;
} }
revs->diffopt.abbrev = revs->abbrev; revs->diffopt.abbrev = revs->abbrev;
diff_setup_done(&revs->diffopt); if (diff_setup_done(&revs->diffopt) < 0)
die("diff_setup_done failed");
return left; return left;
} }

View File

@ -184,7 +184,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
} }
return NULL; return NULL;
bad_dir_environ: bad_dir_environ:
if (!nongit_ok) { if (nongit_ok) {
*nongit_ok = 1; *nongit_ok = 1;
return NULL; return NULL;
} }

View File

@ -590,7 +590,7 @@ static void prepare_packed_git_one(char *objdir, int local)
int namelen = strlen(de->d_name); int namelen = strlen(de->d_name);
struct packed_git *p; struct packed_git *p;
if (strcmp(de->d_name + namelen - 4, ".idx")) if (!has_extension(de->d_name, ".idx"))
continue; continue;
/* we have .idx. Is it a file we can map? */ /* we have .idx. Is it a file we can map? */

View File

@ -193,7 +193,7 @@ const char *find_unique_abbrev(const unsigned char *sha1, int len)
is_null = !memcmp(sha1, null_sha1, 20); is_null = !memcmp(sha1, null_sha1, 20);
memcpy(hex, sha1_to_hex(sha1), 40); memcpy(hex, sha1_to_hex(sha1), 40);
if (len == 40) if (len == 40 || !len)
return hex; return hex;
while (len < 40) { while (len < 40) {
unsigned char sha1_ret[20]; unsigned char sha1_ret[20];

View File

@ -132,6 +132,7 @@ int main(int argc, char **argv)
prog = getenv("GIT_SSH_PUSH"); prog = getenv("GIT_SSH_PUSH");
if (!prog) prog = "git-ssh-upload"; if (!prog) prog = "git-ssh-upload";
setup_ident();
setup_git_directory(); setup_git_directory();
git_config(git_default_config); git_config(git_default_config);

View File

@ -4,7 +4,8 @@
check_count () { check_count () {
head= head=
case "$1" in -h) head="$2"; shift; shift ;; esac case "$1" in -h) head="$2"; shift; shift ;; esac
$PROG file $head | perl -e ' $PROG file $head >.result || return 1
cat .result | perl -e '
my %expect = (@ARGV); my %expect = (@ARGV);
my %count = (); my %count = ();
while (<STDIN>) { while (<STDIN>) {

27
t/t1003-read-tree-prefix.sh Executable file
View File

@ -0,0 +1,27 @@
#!/bin/sh
#
# Copyright (c) 2006 Junio C Hamano
#
test_description='git-read-tree --prefix test.
'
. ./test-lib.sh
test_expect_success setup '
echo hello >one &&
git-update-index --add one &&
tree=`git-write-tree` &&
echo tree is $tree
'
echo 'one
two/one' >expect
test_expect_success 'read-tree --prefix' '
git-read-tree --prefix=two/ $tree &&
git-ls-files >actual &&
cmp expect actual
'
test_done

109
t/t1020-subdirectory.sh Executable file
View File

@ -0,0 +1,109 @@
#!/bin/sh
#
# Copyright (c) 2006 Junio C Hamano
#
test_description='Try various core-level commands in subdirectory.
'
. ./test-lib.sh
test_expect_success setup '
long="a b c d e f g h i j k l m n o p q r s t u v w x y z" &&
for c in $long; do echo $c; done >one &&
mkdir dir &&
for c in x y z $long a b c; do echo $c; done >dir/two &&
cp one original.one &&
cp dir/two original.two
'
HERE=`pwd`
LF='
'
test_expect_success 'update-index and ls-files' '
cd $HERE &&
git-update-index --add one &&
case "`git-ls-files`" in
one) echo ok one ;;
*) echo bad one; exit 1 ;;
esac &&
cd dir &&
git-update-index --add two &&
case "`git-ls-files`" in
two) echo ok two ;;
*) echo bad two; exit 1 ;;
esac &&
cd .. &&
case "`git-ls-files`" in
dir/two"$LF"one) echo ok both ;;
*) echo bad; exit 1 ;;
esac
'
test_expect_success 'cat-file' '
cd $HERE &&
two=`git-ls-files -s dir/two` &&
two=`expr "$two" : "[0-7]* \\([0-9a-f]*\\)"` &&
echo "$two" &&
git-cat-file -p "$two" >actual &&
cmp dir/two actual &&
cd dir &&
git-cat-file -p "$two" >actual &&
cmp two actual
'
rm -f actual dir/actual
test_expect_success 'diff-files' '
cd $HERE &&
echo a >>one &&
echo d >>dir/two &&
case "`git-diff-files --name-only`" in
dir/two"$LF"one) echo ok top ;;
*) echo bad top; exit 1 ;;
esac &&
# diff should not omit leading paths
cd dir &&
case "`git-diff-files --name-only`" in
dir/two"$LF"one) echo ok subdir ;;
*) echo bad subdir; exit 1 ;;
esac &&
case "`git-diff-files --name-only .`" in
dir/two) echo ok subdir limited ;;
*) echo bad subdir limited; exit 1 ;;
esac
'
test_expect_success 'write-tree' '
cd $HERE &&
top=`git-write-tree` &&
echo $top &&
cd dir &&
sub=`git-write-tree` &&
echo $sub &&
test "z$top" = "z$sub"
'
test_expect_success 'checkout-index' '
cd $HERE &&
git-checkout-index -f -u one &&
cmp one original.one &&
cd dir &&
git-checkout-index -f -u two &&
cmp two ../original.two
'
test_expect_success 'read-tree' '
cd $HERE &&
rm -f one dir/two &&
tree=`git-write-tree` &&
git-read-tree --reset -u "$tree" &&
cmp one original.one &&
cmp dir/two original.two &&
cd dir &&
rm -f two &&
git-read-tree --reset -u "$tree" &&
cmp two ../original.two &&
cmp ../one ../original.one
'
test_done

227
t/t3800-mktag.sh Executable file
View File

@ -0,0 +1,227 @@
#!/bin/sh
#
#
test_description='git-mktag: tag object verify test'
. ./test-lib.sh
###########################################################
# check the tag.sig file, expecting verify_tag() to fail,
# and checking that the error message matches the pattern
# given in the expect.pat file.
check_verify_failure () {
test_expect_success \
"$1" \
'git-mktag <tag.sig 2>message ||
egrep -q -f expect.pat message'
}
###########################################################
# first create a commit, so we have a valid object/type
# for the tag.
echo Hello >A
git-update-index --add A
git-commit -m "Initial commit"
head=$(git-rev-parse --verify HEAD)
############################################################
# 1. length check
cat >tag.sig <<EOF
too short for a tag
EOF
cat >expect.pat <<EOF
^error: .*size wrong.*$
EOF
check_verify_failure 'Tag object length check'
############################################################
# 2. object line label check
cat >tag.sig <<EOF
xxxxxx 139e9b33986b1c2670fff52c5067603117b3e895
type tag
tag mytag
EOF
cat >expect.pat <<EOF
^error: char0: .*"object "$
EOF
check_verify_failure '"object" line label check'
############################################################
# 3. object line SHA1 check
cat >tag.sig <<EOF
object zz9e9b33986b1c2670fff52c5067603117b3e895
type tag
tag mytag
EOF
cat >expect.pat <<EOF
^error: char7: .*SHA1 hash$
EOF
check_verify_failure '"object" line SHA1 check'
############################################################
# 4. type line label check
cat >tag.sig <<EOF
object 779e9b33986b1c2670fff52c5067603117b3e895
xxxx tag
tag mytag
EOF
cat >expect.pat <<EOF
^error: char47: .*"[\]ntype "$
EOF
check_verify_failure '"type" line label check'
############################################################
# 5. type line eol check
echo "object 779e9b33986b1c2670fff52c5067603117b3e895" >tag.sig
echo -n "type tagsssssssssssssssssssssssssssssss" >>tag.sig
cat >expect.pat <<EOF
^error: char48: .*"[\]n"$
EOF
check_verify_failure '"type" line eol check'
############################################################
# 6. tag line label check #1
cat >tag.sig <<EOF
object 779e9b33986b1c2670fff52c5067603117b3e895
type tag
xxx mytag
EOF
cat >expect.pat <<EOF
^error: char57: no "tag " found$
EOF
check_verify_failure '"tag" line label check #1'
############################################################
# 7. tag line label check #2
cat >tag.sig <<EOF
object 779e9b33986b1c2670fff52c5067603117b3e895
type taggggggggggggggggggggggggggggggg
tag
EOF
cat >expect.pat <<EOF
^error: char87: no "tag " found$
EOF
check_verify_failure '"tag" line label check #2'
############################################################
# 8. type line type-name length check
cat >tag.sig <<EOF
object 779e9b33986b1c2670fff52c5067603117b3e895
type taggggggggggggggggggggggggggggggg
tag mytag
EOF
cat >expect.pat <<EOF
^error: char53: type too long$
EOF
check_verify_failure '"type" line type-name length check'
############################################################
# 9. verify object (SHA1/type) check
cat >tag.sig <<EOF
object 779e9b33986b1c2670fff52c5067603117b3e895
type tagggg
tag mytag
EOF
cat >expect.pat <<EOF
^error: char7: could not verify object.*$
EOF
check_verify_failure 'verify object (SHA1/type) check'
############################################################
# 10. verify tag-name check
cat >tag.sig <<EOF
object $head
type commit
tag my tag
EOF
cat >expect.pat <<EOF
^error: char67: could not verify tag name$
EOF
check_verify_failure 'verify tag-name check'
############################################################
# 11. tagger line lable check #1
cat >tag.sig <<EOF
object $head
type commit
tag mytag
EOF
cat >expect.pat <<EOF
^error: char70: could not find "tagger"$
EOF
check_verify_failure '"tagger" line label check #1'
############################################################
# 12. tagger line lable check #2
cat >tag.sig <<EOF
object $head
type commit
tag mytag
tagger
EOF
cat >expect.pat <<EOF
^error: char70: could not find "tagger"$
EOF
check_verify_failure '"tagger" line label check #2'
############################################################
# 13. create valid tag
cat >tag.sig <<EOF
object $head
type commit
tag mytag
tagger another@example.com
EOF
test_expect_success \
'create valid tag' \
'git-mktag <tag.sig >.git/refs/tags/mytag 2>message'
############################################################
# 14. check mytag
test_expect_success \
'check mytag' \
'git-tag -l | grep mytag'
test_done

View File

@ -88,7 +88,7 @@ test_expect_success setup '
+*+ [initial] Initial +*+ [initial] Initial
EOF EOF
V=`git version | sed -e 's/^git version //'` V=`git version | sed -e 's/^git version //' -e 's/\./\\./g'`
while read cmd while read cmd
do do
case "$cmd" in case "$cmd" in
@ -103,7 +103,9 @@ do
test_expect_success "git $cmd" ' test_expect_success "git $cmd" '
{ {
echo "\$ git $cmd" echo "\$ git $cmd"
git $cmd | sed -e "s/$V/g-i-t--v-e-r-s-i-o-n/" git $cmd |
sed -e "s/^\\(-*\\)$V\\(-*\\)\$/\\1g-i-t--v-e-r-s-i-o-n\2/" \
-e "s/^\\( *boundary=\"-*\\)$V\\(-*\\)\"\$/\\1g-i-t--v-e-r-s-i-o-n\2\"/"
echo "\$" echo "\$"
} >"$actual" && } >"$actual" &&
if test -f "$expect" if test -f "$expect"

49
t/t4115-apply-symlink.sh Executable file
View File

@ -0,0 +1,49 @@
#!/bin/sh
#
# Copyright (c) 2005 Junio C Hamano
#
test_description='git-apply symlinks and partial files
'
. ./test-lib.sh
test_expect_success setup '
ln -s path1/path2/path3/path4/path5 link1 &&
git add link? &&
git commit -m initial &&
git branch side &&
rm -f link? &&
ln -s htap6 link1 &&
git update-index link? &&
git commit -m second &&
git diff-tree -p HEAD^ HEAD >patch &&
git apply --stat --summary patch
'
test_expect_success 'apply symlink patch' '
git checkout side &&
git apply patch &&
git diff-files -p >patched &&
diff -u patch patched
'
test_expect_success 'apply --index symlink patch' '
git checkout -f side &&
git apply --index patch &&
git diff-index --cached -p HEAD >patched &&
diff -u patch patched
'
test_done

85
t/t7002-grep.sh Executable file
View File

@ -0,0 +1,85 @@
#!/bin/sh
#
# Copyright (c) 2006 Junio C Hamano
#
test_description='git grep -w
'
. ./test-lib.sh
test_expect_success setup '
{
echo foo mmap bar
echo foo_mmap bar
echo foo_mmap bar mmap
echo foo mmap bar_mmap
echo foo_mmap bar mmap baz
} >file &&
echo x x xx x >x &&
echo y yy >y &&
echo zzz > z &&
git add file x y z &&
git commit -m initial
'
for H in HEAD ''
do
case "$H" in
HEAD) HC='HEAD:' L='HEAD' ;;
'') HC= L='in working tree' ;;
esac
test_expect_success "grep -w $L" '
{
echo ${HC}file:1:foo mmap bar
echo ${HC}file:3:foo_mmap bar mmap
echo ${HC}file:4:foo mmap bar_mmap
echo ${HC}file:5:foo_mmap bar mmap baz
} >expected &&
git grep -n -w -e mmap $H >actual &&
diff expected actual
'
test_expect_success "grep -w $L (x)" '
{
echo ${HC}x:1:x x xx x
} >expected &&
git grep -n -w -e "x xx* x" $H >actual &&
diff expected actual
'
test_expect_success "grep -w $L (y-1)" '
{
echo ${HC}y:1:y yy
} >expected &&
git grep -n -w -e "^y" $H >actual &&
diff expected actual
'
test_expect_success "grep -w $L (y-2)" '
: >expected &&
if git grep -n -w -e "^y y" $H >actual
then
echo should not have matched
cat actual
false
else
diff expected actual
fi
'
test_expect_success "grep -w $L (z)" '
: >expected &&
if git grep -n -w -e "^z" $H >actual
then
echo should not have matched
cat actual
false
else
diff expected actual
fi
'
done
test_done

View File

@ -170,7 +170,7 @@ then
test -L $SVN_TREE/exec-2.sh" test -L $SVN_TREE/exec-2.sh"
name='modify a symlink to become a file' name='modify a symlink to become a file'
git help > help || true echo git help > help || true
rm exec-2.sh rm exec-2.sh
cp help exec-2.sh cp help exec-2.sh
git update-index exec-2.sh git update-index exec-2.sh
@ -217,10 +217,10 @@ name='check imported tree checksums expected tree checksums'
rm -f expected rm -f expected
if test "$have_utf8" = t if test "$have_utf8" = t
then then
echo tree f735671b89a7eb30cab1d8597de35bd4271ab813 > expected echo tree bf522353586b1b883488f2bc73dab0d9f774b9a9 > expected
fi fi
cat >> expected <<\EOF cat >> expected <<\EOF
tree 4b9af72bb861eaed053854ec502cf7df72618f0f tree 83654bb36f019ae4fe77a0171f81075972087624
tree 031b8d557afc6fea52894eaebb45bec52f1ba6d1 tree 031b8d557afc6fea52894eaebb45bec52f1ba6d1
tree 0b094cbff17168f24c302e297f55bfac65eb8bd3 tree 0b094cbff17168f24c302e297f55bfac65eb8bd3
tree d667270a1f7b109f5eb3aaea21ede14b56bfdd6e tree d667270a1f7b109f5eb3aaea21ede14b56bfdd6e
@ -231,4 +231,3 @@ EOF
test_expect_success "$name" "diff -u a expected" test_expect_success "$name" "diff -u a expected"
test_done test_done

View File

@ -6,11 +6,9 @@ prefix ?= $(HOME)
template_dir ?= $(prefix)/share/git-core/templates/ template_dir ?= $(prefix)/share/git-core/templates/
# DESTDIR= # DESTDIR=
# Shell quote; # Shell quote (do not use $(call) to accomodate ancient setups);
# Result of this needs to be placed inside '' DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
shq = $(subst ','\'',$(1)) template_dir_SQ = $(subst ','\'',$(template_dir))
# This has surrounding ''
shellquote = '$(call shq,$(1))'
all: boilerplates.made custom all: boilerplates.made custom
@ -43,6 +41,6 @@ clean:
rm -rf blt boilerplates.made rm -rf blt boilerplates.made
install: all install: all
$(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(template_dir)) $(INSTALL) -d -m755 '$(DESTDIR_SQ)$(template_dir_SQ)'
(cd blt && $(TAR) cf - .) | \ (cd blt && $(TAR) cf - .) | \
(cd $(call shellquote,$(DESTDIR)$(template_dir)) && $(TAR) xf -) (cd '$(DESTDIR_SQ)$(template_dir_SQ)' && $(TAR) xf -)

View File

@ -1,43 +1,60 @@
#include "cache.h" #include "cache.h"
#include "pack.h" #include "pack.h"
static int verify_one_pack(char *arg, int verbose) static int verify_one_pack(const char *path, int verbose)
{ {
int len = strlen(arg); char arg[PATH_MAX];
struct packed_git *g; int len;
struct packed_git *pack;
while (1) { int err;
/* Should name foo.idx, but foo.pack may be named;
* convert it to foo.idx len = strlcpy(arg, path, PATH_MAX);
*/ if (len >= PATH_MAX)
if (!strcmp(arg + len - 5, ".pack")) { return error("name too long: %s", path);
strcpy(arg + len - 5, ".idx");
len--; /*
} * In addition to "foo.idx" we accept "foo.pack" and "foo";
/* Should name foo.idx now */ * normalize these forms to "foo.idx" for add_packed_git().
if ((g = add_packed_git(arg, len, 1))) */
break; if (has_extension(arg, ".pack")) {
/* No? did you name just foo? */ strcpy(arg + len - 5, ".idx");
len--;
} else if (!has_extension(arg, ".idx")) {
if (len + 4 >= PATH_MAX)
return error("name too long: %s.idx", arg);
strcpy(arg + len, ".idx"); strcpy(arg + len, ".idx");
len += 4; len += 4;
if ((g = add_packed_git(arg, len, 1)))
break;
return error("packfile %s not found.", arg);
} }
return verify_pack(g, verbose);
/*
* add_packed_git() uses our buffer (containing "foo.idx") to
* build the pack filename ("foo.pack"). Make sure it fits.
*/
if (len + 1 >= PATH_MAX) {
arg[len - 4] = '\0';
return error("name too long: %s.pack", arg);
}
pack = add_packed_git(arg, len, 1);
if (!pack)
return error("packfile %s not found.", arg);
err = verify_pack(pack, verbose);
free(pack);
return err;
} }
static const char verify_pack_usage[] = "git-verify-pack [-v] <pack>..."; static const char verify_pack_usage[] = "git-verify-pack [-v] <pack>...";
int main(int ac, char **av) int main(int ac, char **av)
{ {
int errs = 0; int err = 0;
int verbose = 0; int verbose = 0;
int no_more_options = 0; int no_more_options = 0;
int nothing_done = 1;
while (1 < ac) { while (1 < ac) {
char path[PATH_MAX];
if (!no_more_options && av[1][0] == '-') { if (!no_more_options && av[1][0] == '-') {
if (!strcmp("-v", av[1])) if (!strcmp("-v", av[1]))
verbose = 1; verbose = 1;
@ -47,11 +64,15 @@ int main(int ac, char **av)
usage(verify_pack_usage); usage(verify_pack_usage);
} }
else { else {
strcpy(path, av[1]); if (verify_one_pack(av[1], verbose))
if (verify_one_pack(path, verbose)) err = 1;
errs++; nothing_done = 0;
} }
ac--; av++; ac--; av++;
} }
return !!errs;
if (nothing_done)
usage(verify_pack_usage);
return err;
} }