Merge branch 'master' into pb/gitpm

* master: (166 commits)
  git-apply --binary: clean up and prepare for --reverse
  Fix detection of ipv6 on Solaris
  Look for sockaddr_storage in sys/socket.h
  Solaris has strlcpy() at least since version 8
  git-apply --reverse: simplify reverse option.
  t4116 apply --reverse test
  Make sha1flush void and remove conditional return.
  Make upload_pack void and remove conditional return.
  Make track_tree_refs void.
  Make pack_objects void.
  Make fsck_dir void.
  Make checkout_all void.
  Make show_entry void
  Make pprint_tag void and cleans up call in cmd_cat_file.
  Remove combine-diff.c::uninteresting()
  read-cache.c cleanup
  http-push.c cleanup
  diff.c cleanup
  builtin-push.c cleanup
  builtin-grep.c cleanup
  ...
This commit is contained in:
Junio C Hamano 2006-08-15 03:13:34 -07:00
commit d7b6c3c0f5
76 changed files with 4329 additions and 3104 deletions

3
.gitignore vendored
View File

@ -125,6 +125,7 @@ git-verify-tag
git-whatchanged git-whatchanged
git-write-tree git-write-tree
git-core-*/?* git-core-*/?*
gitweb/gitweb.cgi
test-date test-date
test-delta test-delta
test-dump-cache-tree test-dump-cache-tree
@ -140,7 +141,7 @@ config.mak
autom4te.cache autom4te.cache
config.log config.log
config.status config.status
config.mak.in
config.mak.autogen config.mak.autogen
config.mak.append
configure configure
git-blame git-blame

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

View File

@ -36,6 +36,9 @@
Turn off colored diff, even when the configuration file Turn off colored diff, even when the configuration file
gives the default to color output. gives the default to color output.
--color-words::
Show colored word diff, i.e. color words which have changed.
--no-renames:: --no-renames::
Turn off rename detection, even when the configuration Turn off rename detection, even when the configuration
file gives the default to do so. file gives the default to do so.

View File

@ -11,7 +11,7 @@ SYNOPSIS
[verse] [verse]
'git-grep' [--cached] 'git-grep' [--cached]
[-a | --text] [-I] [-i | --ignore-case] [-w | --word-regexp] [-a | --text] [-I] [-i | --ignore-case] [-w | --word-regexp]
[-v | --invert-match] [-v | --invert-match] [--full-name]
[-E | --extended-regexp] [-G | --basic-regexp] [-F | --fixed-strings] [-E | --extended-regexp] [-G | --basic-regexp] [-F | --fixed-strings]
[-n] [-l | --files-with-matches] [-L | --files-without-match] [-n] [-l | --files-with-matches] [-L | --files-without-match]
[-c | --count] [-c | --count]
@ -47,6 +47,12 @@ OPTIONS
-v | --invert-match:: -v | --invert-match::
Select non-matching lines. Select non-matching lines.
--full-name::
When run from a subdirectory, the command usually
outputs paths relative to the current directory. This
option forces paths to be output relative to the project
top directory.
-E | --extended-regexp | -G | --basic-regexp:: -E | --extended-regexp | -G | --basic-regexp::
Use POSIX extended/basic regexp for patterns. Default Use POSIX extended/basic regexp for patterns. Default
is to use basic regexp. is to use basic regexp.

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-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

@ -633,6 +633,9 @@ git Diffs
other other
~~~~~ ~~~~~
'GIT_PAGER'::
This environment variable overrides `$PAGER`.
'GIT_TRACE':: 'GIT_TRACE'::
If this variable is set git will print `trace:` messages on If this variable is set git will print `trace:` messages on
stderr telling about alias expansion, built-in command stderr telling about alias expansion, built-in command

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

@ -3,9 +3,17 @@
GVF=GIT-VERSION-FILE GVF=GIT-VERSION-FILE
DEF_VER=v1.4.2.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

@ -16,7 +16,7 @@ install" would not work.
Alternatively you can use autoconf generated ./configure script to Alternatively you can use autoconf generated ./configure script to
set up install paths (via config.mak.autogen), so you can write instead set up install paths (via config.mak.autogen), so you can write instead
$ autoconf ;# as yourself if ./configure doesn't exist yet $ make configure ;# as yourself
$ ./configure --prefix=/usr ;# as yourself $ ./configure --prefix=/usr ;# as yourself
$ make all doc ;# as yourself $ make all doc ;# as yourself
# make install install-doc ;# as root # make install install-doc ;# as root

125
Makefile
View File

@ -22,7 +22,7 @@ all:
# Define NO_C99_FORMAT if your formatted IO functions (printf/scanf et.al.) # 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, # 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). # 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. # 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.
# #
@ -126,6 +126,16 @@ template_dir = $(prefix)/share/git-core/templates/
GIT_PYTHON_DIR = $(prefix)/share/git-core/python GIT_PYTHON_DIR = $(prefix)/share/git-core/python
# DESTDIR= # DESTDIR=
# default configuration for gitweb
GITWEB_CONFIG = gitweb_config.perl
GITWEB_HOME_LINK_STR = projects
GITWEB_SITENAME =
GITWEB_PROJECTROOT = /pub/git
GITWEB_LIST =
GITWEB_HOMETEXT = indextext.html
GITWEB_CSS = gitweb.css
GITWEB_LOGO = git-logo.png
export prefix bindir gitexecdir template_dir GIT_PYTHON_DIR export prefix bindir gitexecdir template_dir GIT_PYTHON_DIR
CC = gcc CC = gcc
@ -183,32 +193,23 @@ SIMPLE_PROGRAMS = \
# ... and all the rest that could be moved out of bindir to gitexecdir # ... and all the rest that could be moved out of bindir to gitexecdir
PROGRAMS = \ PROGRAMS = \
git-checkout-index$X \
git-convert-objects$X git-fetch-pack$X git-fsck-objects$X \ git-convert-objects$X git-fetch-pack$X git-fsck-objects$X \
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-patch-id$X \
git-peek-remote$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-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-pack-redundant$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
BUILT_INS = git-log$X git-whatchanged$X git-show$X git-update-ref$X \ BUILT_INS = \
git-count-objects$X git-diff$X git-push$X git-mailsplit$X \ git-format-patch$X git-show$X git-whatchanged$X \
git-grep$X git-add$X git-rm$X git-rev-list$X git-stripspace$X \ git-get-tar-commit-id$X \
git-check-ref-format$X git-rev-parse$X git-mailinfo$X \ $(patsubst builtin-%.o,git-%$X,$(BUILTIN_OBJS))
git-init-db$X git-tar-tree$X git-upload-tar$X git-format-patch$X \
git-ls-files$X git-ls-tree$X git-get-tar-commit-id$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-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-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)
@ -237,7 +238,7 @@ LIB_H = \
blob.h cache.h commit.h csum-file.h delta.h \ blob.h cache.h commit.h csum-file.h delta.h \
diff.h object.h pack.h pkt-line.h quote.h refs.h \ diff.h object.h pack.h pkt-line.h quote.h refs.h \
run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \ run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \
tree-walk.h log-tree.h dir.h path-list.h tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h
DIFF_OBJS = \ DIFF_OBJS = \
diff.o diff-lib.o diffcore-break.o diffcore-order.o \ diff.o diff-lib.o diffcore-break.o diffcore-order.o \
@ -252,20 +253,50 @@ LIB_OBJS = \
server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \ server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
tag.o tree.o usage.o config.o environment.o ctype.o copy.o \ tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
fetch-clone.o revision.o pager.o tree-walk.o xdiff-interface.o \ fetch-clone.o revision.o pager.o tree-walk.o xdiff-interface.o \
alloc.o merge-file.o path-list.o $(DIFF_OBJS) alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS)
BUILTIN_OBJS = \ BUILTIN_OBJS = \
builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o \ builtin-add.o \
builtin-grep.o builtin-add.o builtin-rev-list.o builtin-check-ref-format.o \ builtin-apply.o \
builtin-rm.o builtin-init-db.o builtin-rev-parse.o \ builtin-cat-file.o \
builtin-tar-tree.o builtin-upload-tar.o builtin-update-index.o \ builtin-checkout-index.o \
builtin-ls-files.o builtin-ls-tree.o builtin-write-tree.o \ builtin-check-ref-format.o \
builtin-read-tree.o builtin-commit-tree.o builtin-mailinfo.o \ builtin-commit-tree.o \
builtin-apply.o builtin-show-branch.o builtin-diff-files.o \ builtin-count-objects.o \
builtin-diff-index.o builtin-diff-stages.o builtin-diff-tree.o \ builtin-diff.o \
builtin-cat-file.o builtin-mailsplit.o builtin-stripspace.o \ builtin-diff-files.o \
builtin-update-ref.o builtin-fmt-merge-msg.o builtin-prune.o \ builtin-diff-index.o \
builtin-mv.o builtin-prune-packed.o builtin-repo-config.o builtin-diff-stages.o \
builtin-diff-tree.o \
builtin-fmt-merge-msg.o \
builtin-grep.o \
builtin-init-db.o \
builtin-log.o \
builtin-ls-files.o \
builtin-ls-tree.o \
builtin-mailinfo.o \
builtin-mailsplit.o \
builtin-mv.o \
builtin-name-rev.o \
builtin-pack-objects.o \
builtin-prune.o \
builtin-prune-packed.o \
builtin-push.o \
builtin-read-tree.o \
builtin-repo-config.o \
builtin-rev-list.o \
builtin-rev-parse.o \
builtin-rm.o \
builtin-show-branch.o \
builtin-stripspace.o \
builtin-symbolic-ref.o \
builtin-tar-tree.o \
builtin-unpack-objects.o \
builtin-update-index.o \
builtin-update-ref.o \
builtin-upload-tar.o \
builtin-verify-pack.o \
builtin-write-tree.o
GITLIBS = $(LIB_FILE) $(XDIFF_LIB) GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
EXTLIBS = -lz EXTLIBS = -lz
@ -306,7 +337,6 @@ ifeq ($(uname_S),SunOS)
NEEDS_NSL = YesPlease NEEDS_NSL = YesPlease
SHELL_PATH = /bin/bash SHELL_PATH = /bin/bash
NO_STRCASESTR = YesPlease NO_STRCASESTR = YesPlease
NO_STRLCPY = YesPlease
ifeq ($(uname_R),5.8) ifeq ($(uname_R),5.8)
NEEDS_LIBICONV = YesPlease NEEDS_LIBICONV = YesPlease
NO_UNSETENV = YesPlease NO_UNSETENV = YesPlease
@ -548,7 +578,7 @@ export prefix TAR INSTALL DESTDIR SHELL_PATH template_dir
### Build rules ### Build rules
all: $(ALL_PROGRAMS) $(BUILT_INS) git$X gitk all: $(ALL_PROGRAMS) $(BUILT_INS) git$X gitk gitweb/gitweb.cgi
all: perl/Makefile all: perl/Makefile
$(MAKE) -C perl $(MAKE) -C perl
@ -562,7 +592,7 @@ git$X: git.c common-cmds.h $(BUILTIN_OBJS) $(GITLIBS) GIT-CFLAGS
$(ALL_CFLAGS) -o $@ $(filter %.c,$^) \ $(ALL_CFLAGS) -o $@ $(filter %.c,$^) \
$(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS) $(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)
builtin-help.o: common-cmds.h help.o: common-cmds.h
$(BUILT_INS): git$X $(BUILT_INS): git$X
rm -f $@ && ln git$X $@ rm -f $@ && ln git$X $@
@ -616,6 +646,23 @@ git-status: git-commit
cp $< $@+ cp $< $@+
mv $@+ $@ mv $@+ $@
gitweb/gitweb.cgi: gitweb/gitweb.perl
rm -f $@ $@+
sed -e '1s|#!.*perl|#!$(PERL_PATH_SQ)|' \
-e 's|++GIT_VERSION++|$(GIT_VERSION)|g' \
-e 's|++GIT_BINDIR++|$(bindir)|g' \
-e 's|++GITWEB_CONFIG++|$(GITWEB_CONFIG)|g' \
-e 's|++GITWEB_HOME_LINK_STR++|$(GITWEB_HOME_LINK_STR)|g' \
-e 's|++GITWEB_SITENAME++|$(GITWEB_SITENAME)|g' \
-e 's|++GITWEB_PROJECTROOT++|$(GITWEB_PROJECTROOT)|g' \
-e 's|++GITWEB_LIST++|$(GITWEB_LIST)|g' \
-e 's|++GITWEB_HOMETEXT++|$(GITWEB_HOMETEXT)|g' \
-e 's|++GITWEB_CSS++|$(GITWEB_CSS)|g' \
-e 's|++GITWEB_LOGO++|$(GITWEB_LOGO)|g' \
$< >$@+
chmod +x $@+
mv $@+ $@
git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css
rm -f $@ $@+ rm -f $@ $@+
sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
@ -626,10 +673,17 @@ git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css
-e '/@@GITWEB_CGI@@/d' \ -e '/@@GITWEB_CGI@@/d' \
-e '/@@GITWEB_CSS@@/r gitweb/gitweb.css' \ -e '/@@GITWEB_CSS@@/r gitweb/gitweb.css' \
-e '/@@GITWEB_CSS@@/d' \ -e '/@@GITWEB_CSS@@/d' \
$@.sh | sed "s|/usr/bin/git|$(bindir)/git|" > $@+ $@.sh > $@+
chmod +x $@+ chmod +x $@+
mv $@+ $@ mv $@+ $@
configure: configure.ac
rm -f $@ $<+
sed -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
$< > $<+
autoconf -o $@ $<+
rm -f $<+
# These can record GIT_VERSION # These can record GIT_VERSION
git$X git.spec \ git$X git.spec \
$(patsubst %.sh,%,$(SCRIPT_SH)) \ $(patsubst %.sh,%,$(SCRIPT_SH)) \
@ -832,10 +886,11 @@ clean:
rm -f $(ALL_PROGRAMS) $(BUILT_INS) git$X rm -f $(ALL_PROGRAMS) $(BUILT_INS) git$X
rm -f *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags rm -f *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags
rm -rf autom4te.cache rm -rf autom4te.cache
rm -f config.log config.mak.autogen configure config.status config.cache rm -f configure config.log config.mak.autogen config.mak.append config.status config.cache
rm -rf $(GIT_TARNAME) .doc-tmp-dir rm -rf $(GIT_TARNAME) .doc-tmp-dir
rm -f $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz rm -f $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz
rm -f $(htmldocs).tar.gz $(manpages).tar.gz rm -f $(htmldocs).tar.gz $(manpages).tar.gz
rm -f gitweb/gitweb.cgi
$(MAKE) -C Documentation/ clean $(MAKE) -C Documentation/ clean
[ ! -f perl/Makefile ] || $(MAKE) -C perl/ clean || $(MAKE) -C perl/ clean [ ! -f perl/Makefile ] || $(MAKE) -C perl/ clean || $(MAKE) -C perl/ clean
rm -f perl/ppport.h perl/Makefile.old rm -f perl/ppport.h perl/Makefile.old

View File

@ -351,10 +351,7 @@ static int fill_util_info(struct commit *commit)
assert(util); assert(util);
assert(util->pathname); assert(util->pathname);
if (get_blob_sha1(commit->tree, util->pathname, util->sha1)) return !!get_blob_sha1(commit->tree, util->pathname, util->sha1);
return 1;
else
return 0;
} }
static void alloc_line_map(struct commit *commit) static void alloc_line_map(struct commit *commit)

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");

View File

@ -37,6 +37,7 @@ static int numstat = 0;
static int summary = 0; static int summary = 0;
static int check = 0; static int check = 0;
static int apply = 1; static int apply = 1;
static int apply_in_reverse = 0;
static int no_add = 0; static int no_add = 0;
static int show_index_info = 0; static int show_index_info = 0;
static int line_termination = '\n'; static int line_termination = '\n';
@ -108,6 +109,13 @@ static int max_change, max_len;
*/ */
static int linenr = 1; static int linenr = 1;
/*
* This represents one "hunk" from a patch, starting with
* "@@ -oldpos,oldlines +newpos,newlines @@" marker. The
* patch text is pointed at by patch, and its byte length
* is stored in size. leading and trailing are the number
* of context lines.
*/
struct fragment { struct fragment {
unsigned long leading, trailing; unsigned long leading, trailing;
unsigned long oldpos, oldlines; unsigned long oldpos, oldlines;
@ -117,12 +125,19 @@ struct fragment {
struct fragment *next; struct fragment *next;
}; };
/*
* When dealing with a binary patch, we reuse "leading" field
* to store the type of the binary hunk, either deflated "delta"
* or deflated "literal".
*/
#define binary_patch_method leading
#define BINARY_DELTA_DEFLATED 1
#define BINARY_LITERAL_DEFLATED 2
struct patch { struct patch {
char *new_name, *old_name, *def_name; char *new_name, *old_name, *def_name;
unsigned int old_mode, new_mode; unsigned int old_mode, new_mode;
int is_rename, is_copy, is_new, is_delete, is_binary, is_reverse; int is_rename, is_copy, is_new, is_delete, is_binary;
#define BINARY_DELTA_DEFLATED 1
#define BINARY_LITERAL_DEFLATED 2
unsigned long deflate_origlen; unsigned long deflate_origlen;
int lines_added, lines_deleted; int lines_added, lines_deleted;
int score; int score;
@ -978,43 +993,70 @@ static inline int metadata_changes(struct patch *patch)
patch->old_mode != patch->new_mode); patch->old_mode != patch->new_mode);
} }
static int parse_binary(char *buffer, unsigned long size, struct patch *patch) static char *inflate_it(const void *data, unsigned long size,
unsigned long inflated_size)
{ {
/* We have read "GIT binary patch\n"; what follows is a line z_stream stream;
* that says the patch method (currently, either "deflated void *out;
* literal" or "deflated delta") and the length of data before int st;
* deflating; a sequence of 'length-byte' followed by base-85
* encoded data follows. memset(&stream, 0, sizeof(stream));
stream.next_in = (unsigned char *)data;
stream.avail_in = size;
stream.next_out = out = xmalloc(inflated_size);
stream.avail_out = inflated_size;
inflateInit(&stream);
st = inflate(&stream, Z_FINISH);
if ((st != Z_STREAM_END) || stream.total_out != inflated_size) {
free(out);
return NULL;
}
return out;
}
static struct fragment *parse_binary_hunk(char **buf_p,
unsigned long *sz_p,
int *status_p,
int *used_p)
{
/* Expect a line that begins with binary patch method ("literal"
* or "delta"), followed by the length of data before deflating.
* a sequence of 'length-byte' followed by base-85 encoded data
* should follow, terminated by a newline.
* *
* Each 5-byte sequence of base-85 encodes up to 4 bytes, * Each 5-byte sequence of base-85 encodes up to 4 bytes,
* and we would limit the patch line to 66 characters, * and we would limit the patch line to 66 characters,
* so one line can fit up to 13 groups that would decode * so one line can fit up to 13 groups that would decode
* to 52 bytes max. The length byte 'A'-'Z' corresponds * to 52 bytes max. The length byte 'A'-'Z' corresponds
* to 1-26 bytes, and 'a'-'z' corresponds to 27-52 bytes. * to 1-26 bytes, and 'a'-'z' corresponds to 27-52 bytes.
* The end of binary is signaled with an empty line.
*/ */
int llen, used; int llen, used;
struct fragment *fragment; unsigned long size = *sz_p;
char *buffer = *buf_p;
int patch_method;
unsigned long origlen;
char *data = NULL; char *data = NULL;
int hunk_size = 0;
struct fragment *frag;
patch->fragments = fragment = xcalloc(1, sizeof(*fragment));
/* Grab the type of patch */
llen = linelen(buffer, size); llen = linelen(buffer, size);
used = llen; used = llen;
linenr++;
*status_p = 0;
if (!strncmp(buffer, "delta ", 6)) { if (!strncmp(buffer, "delta ", 6)) {
patch->is_binary = BINARY_DELTA_DEFLATED; patch_method = BINARY_DELTA_DEFLATED;
patch->deflate_origlen = strtoul(buffer + 6, NULL, 10); origlen = strtoul(buffer + 6, NULL, 10);
} }
else if (!strncmp(buffer, "literal ", 8)) { else if (!strncmp(buffer, "literal ", 8)) {
patch->is_binary = BINARY_LITERAL_DEFLATED; patch_method = BINARY_LITERAL_DEFLATED;
patch->deflate_origlen = strtoul(buffer + 8, NULL, 10); origlen = strtoul(buffer + 8, NULL, 10);
} }
else else
return error("unrecognized binary patch at line %d: %.*s", return NULL;
linenr-1, llen-1, buffer);
linenr++;
buffer += llen; buffer += llen;
while (1) { while (1) {
int byte_length, max_byte_length, newsize; int byte_length, max_byte_length, newsize;
@ -1043,21 +1085,79 @@ static int parse_binary(char *buffer, unsigned long size, struct patch *patch)
if (max_byte_length < byte_length || if (max_byte_length < byte_length ||
byte_length <= max_byte_length - 4) byte_length <= max_byte_length - 4)
goto corrupt; goto corrupt;
newsize = fragment->size + byte_length; newsize = hunk_size + byte_length;
data = xrealloc(data, newsize); data = xrealloc(data, newsize);
if (decode_85(data + fragment->size, if (decode_85(data + hunk_size, buffer + 1, byte_length))
buffer + 1,
byte_length))
goto corrupt; goto corrupt;
fragment->size = newsize; hunk_size = newsize;
buffer += llen; buffer += llen;
size -= llen; size -= llen;
} }
fragment->patch = data;
return used; frag = xcalloc(1, sizeof(*frag));
frag->patch = inflate_it(data, hunk_size, origlen);
if (!frag->patch)
goto corrupt;
free(data);
frag->size = origlen;
*buf_p = buffer;
*sz_p = size;
*used_p = used;
frag->binary_patch_method = patch_method;
return frag;
corrupt: corrupt:
return error("corrupt binary patch at line %d: %.*s", if (data)
linenr-1, llen-1, buffer); free(data);
*status_p = -1;
error("corrupt binary patch at line %d: %.*s",
linenr-1, llen-1, buffer);
return NULL;
}
static int parse_binary(char *buffer, unsigned long size, struct patch *patch)
{
/* We have read "GIT binary patch\n"; what follows is a line
* that says the patch method (currently, either "literal" or
* "delta") and the length of data before deflating; a
* sequence of 'length-byte' followed by base-85 encoded data
* follows.
*
* When a binary patch is reversible, there is another binary
* hunk in the same format, starting with patch method (either
* "literal" or "delta") with the length of data, and a sequence
* of length-byte + base-85 encoded data, terminated with another
* empty line. This data, when applied to the postimage, produces
* the preimage.
*/
struct fragment *forward;
struct fragment *reverse;
int status;
int used, used_1;
forward = parse_binary_hunk(&buffer, &size, &status, &used);
if (!forward && !status)
/* there has to be one hunk (forward hunk) */
return error("unrecognized binary patch at line %d", linenr-1);
if (status)
/* otherwise we already gave an error message */
return status;
reverse = parse_binary_hunk(&buffer, &size, &status, &used_1);
if (reverse)
used += used_1;
else if (status) {
/* not having reverse hunk is not an error, but having
* a corrupt reverse hunk is.
*/
free((void*) forward->patch);
free(forward);
return status;
}
forward->next = reverse;
patch->fragments = forward;
patch->is_binary = 1;
return used;
} }
static int parse_chunk(char *buffer, unsigned long size, struct patch *patch) static int parse_chunk(char *buffer, unsigned long size, struct patch *patch)
@ -1143,7 +1243,6 @@ static void reverse_patches(struct patch *p)
swap(frag->newpos, frag->oldpos); swap(frag->newpos, frag->oldpos);
swap(frag->newlines, frag->oldlines); swap(frag->newlines, frag->oldlines);
} }
p->is_reverse = !p->is_reverse;
} }
} }
@ -1363,8 +1462,7 @@ static int apply_line(char *output, const char *patch, int plen)
return plen; return plen;
} }
static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, int inaccurate_eof)
int reverse, int inaccurate_eof)
{ {
int match_beginning, match_end; int match_beginning, match_end;
char *buf = desc->buffer; char *buf = desc->buffer;
@ -1396,7 +1494,7 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag,
if (len < size && patch[len] == '\\') if (len < size && patch[len] == '\\')
plen--; plen--;
first = *patch; first = *patch;
if (reverse) { if (apply_in_reverse) {
if (first == '-') if (first == '-')
first = '+'; first = '+';
else if (first == '+') else if (first == '+')
@ -1506,28 +1604,6 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag,
return offset; return offset;
} }
static char *inflate_it(const void *data, unsigned long size,
unsigned long inflated_size)
{
z_stream stream;
void *out;
int st;
memset(&stream, 0, sizeof(stream));
stream.next_in = (unsigned char *)data;
stream.avail_in = size;
stream.next_out = out = xmalloc(inflated_size);
stream.avail_out = inflated_size;
inflateInit(&stream);
st = inflate(&stream, Z_FINISH);
if ((st != Z_STREAM_END) || stream.total_out != inflated_size) {
free(out);
return NULL;
}
return out;
}
static int apply_binary_fragment(struct buffer_desc *desc, struct patch *patch) static int apply_binary_fragment(struct buffer_desc *desc, struct patch *patch)
{ {
unsigned long dst_size; unsigned long dst_size;
@ -1535,30 +1611,29 @@ static int apply_binary_fragment(struct buffer_desc *desc, struct patch *patch)
void *data; void *data;
void *result; void *result;
/* Binary patch is irreversible */ /* Binary patch is irreversible without the optional second hunk */
if (patch->is_reverse) if (apply_in_reverse) {
return error("cannot reverse-apply a binary patch to '%s'", if (!fragment->next)
patch->new_name return error("cannot reverse-apply a binary patch "
? patch->new_name : patch->old_name); "without the reverse hunk to '%s'",
patch->new_name
data = inflate_it(fragment->patch, fragment->size, ? patch->new_name : patch->old_name);
patch->deflate_origlen); fragment = fragment;
if (!data) }
return error("corrupt patch data"); data = (void*) fragment->patch;
switch (patch->is_binary) { switch (fragment->binary_patch_method) {
case BINARY_DELTA_DEFLATED: case BINARY_DELTA_DEFLATED:
result = patch_delta(desc->buffer, desc->size, result = patch_delta(desc->buffer, desc->size,
data, data,
patch->deflate_origlen, fragment->size,
&dst_size); &dst_size);
free(desc->buffer); free(desc->buffer);
desc->buffer = result; desc->buffer = result;
free(data);
break; break;
case BINARY_LITERAL_DEFLATED: case BINARY_LITERAL_DEFLATED:
free(desc->buffer); free(desc->buffer);
desc->buffer = data; desc->buffer = data;
dst_size = patch->deflate_origlen; dst_size = fragment->size;
break; break;
} }
if (!desc->buffer) if (!desc->buffer)
@ -1657,8 +1732,7 @@ static int apply_fragments(struct buffer_desc *desc, struct patch *patch)
return apply_binary(desc, patch); return apply_binary(desc, patch);
while (frag) { while (frag) {
if (apply_one_fragment(desc, frag, patch->is_reverse, if (apply_one_fragment(desc, frag, patch->inaccurate_eof) < 0)
patch->inaccurate_eof) < 0)
return error("patch failed: %s:%ld", return error("patch failed: %s:%ld",
name, frag->oldpos); name, frag->oldpos);
frag = frag->next; frag = frag->next;
@ -1698,6 +1772,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 +2120,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)
@ -2185,8 +2268,7 @@ static int use_patch(struct patch *p)
return 1; return 1;
} }
static int apply_patch(int fd, const char *filename, static int apply_patch(int fd, const char *filename, int inaccurate_eof)
int reverse, int inaccurate_eof)
{ {
unsigned long offset, size; unsigned long offset, size;
char *buffer = read_patch_file(fd, &size); char *buffer = read_patch_file(fd, &size);
@ -2206,7 +2288,7 @@ static int apply_patch(int fd, const char *filename,
nr = parse_chunk(buffer + offset, size, patch); nr = parse_chunk(buffer + offset, size, patch);
if (nr < 0) if (nr < 0)
break; break;
if (reverse) if (apply_in_reverse)
reverse_patches(patch); reverse_patches(patch);
if (use_patch(patch)) { if (use_patch(patch)) {
patch_stats(patch); patch_stats(patch);
@ -2225,12 +2307,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");
@ -2272,7 +2351,6 @@ int cmd_apply(int argc, const char **argv, const char *prefix)
{ {
int i; int i;
int read_stdin = 1; int read_stdin = 1;
int reverse = 0;
int inaccurate_eof = 0; int inaccurate_eof = 0;
const char *whitespace_option = NULL; const char *whitespace_option = NULL;
@ -2283,7 +2361,7 @@ int cmd_apply(int argc, const char **argv, const char *prefix)
int fd; int fd;
if (!strcmp(arg, "-")) { if (!strcmp(arg, "-")) {
apply_patch(0, "<stdin>", reverse, inaccurate_eof); apply_patch(0, "<stdin>", inaccurate_eof);
read_stdin = 0; read_stdin = 0;
continue; continue;
} }
@ -2361,7 +2439,7 @@ int cmd_apply(int argc, const char **argv, const char *prefix)
continue; continue;
} }
if (!strcmp(arg, "-R") || !strcmp(arg, "--reverse")) { if (!strcmp(arg, "-R") || !strcmp(arg, "--reverse")) {
reverse = 1; apply_in_reverse = 1;
continue; continue;
} }
if (!strcmp(arg, "--inaccurate-eof")) { if (!strcmp(arg, "--inaccurate-eof")) {
@ -2384,12 +2462,12 @@ int cmd_apply(int argc, const char **argv, const char *prefix)
usage(apply_usage); usage(apply_usage);
read_stdin = 0; read_stdin = 0;
set_default_whitespace_mode(whitespace_option); set_default_whitespace_mode(whitespace_option);
apply_patch(fd, arg, reverse, inaccurate_eof); apply_patch(fd, arg, inaccurate_eof);
close(fd); close(fd);
} }
set_default_whitespace_mode(whitespace_option); set_default_whitespace_mode(whitespace_option);
if (read_stdin) if (read_stdin)
apply_patch(0, "<stdin>", reverse, inaccurate_eof); apply_patch(0, "<stdin>", inaccurate_eof);
if (whitespace_error) { if (whitespace_error) {
if (squelch_whitespace_errors && if (squelch_whitespace_errors &&
squelch_whitespace_errors < whitespace_error) { squelch_whitespace_errors < whitespace_error) {

View File

@ -26,7 +26,7 @@ static void flush_buffer(const char *buf, unsigned long size)
} }
} }
static int pprint_tag(const unsigned char *sha1, const char *buf, unsigned long size) static void pprint_tag(const unsigned char *sha1, const char *buf, unsigned long size)
{ {
/* the parser in tag.c is useless here. */ /* the parser in tag.c is useless here. */
const char *endp = buf + size; const char *endp = buf + size;
@ -91,7 +91,6 @@ static int pprint_tag(const unsigned char *sha1, const char *buf, unsigned long
*/ */
if (cp < endp) if (cp < endp)
flush_buffer(cp, endp - cp); flush_buffer(cp, endp - cp);
return 0;
} }
int cmd_cat_file(int argc, const char **argv, const char *prefix) int cmd_cat_file(int argc, const char **argv, const char *prefix)
@ -145,8 +144,10 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
buf = read_sha1_file(sha1, type, &size); buf = read_sha1_file(sha1, type, &size);
if (!buf) if (!buf)
die("Cannot read object %s", argv[2]); die("Cannot read object %s", argv[2]);
if (!strcmp(type, tag_type)) if (!strcmp(type, tag_type)) {
return pprint_tag(sha1, buf, size); pprint_tag(sha1, buf, size);
return 0;
}
/* otherwise just spit out the data */ /* otherwise just spit out the data */
break; break;

View File

@ -42,8 +42,6 @@
#include "cache-tree.h" #include "cache-tree.h"
#define CHECKOUT_ALL 4 #define CHECKOUT_ALL 4
static const char *prefix;
static int prefix_length;
static int line_termination = '\n'; static int line_termination = '\n';
static int checkout_stage; /* default to checkout stage0 */ static int checkout_stage; /* default to checkout stage0 */
static int to_tempfile; static int to_tempfile;
@ -51,7 +49,7 @@ static char topath[4][MAXPATHLEN+1];
static struct checkout state; static struct checkout state;
static void write_tempfile_record (const char *name) static void write_tempfile_record(const char *name, int prefix_length)
{ {
int i; int i;
@ -77,7 +75,7 @@ static void write_tempfile_record (const char *name)
} }
} }
static int checkout_file(const char *name) static int checkout_file(const char *name, int prefix_length)
{ {
int namelen = strlen(name); int namelen = strlen(name);
int pos = cache_name_pos(name, namelen); int pos = cache_name_pos(name, namelen);
@ -106,7 +104,7 @@ static int checkout_file(const char *name)
if (did_checkout) { if (did_checkout) {
if (to_tempfile) if (to_tempfile)
write_tempfile_record(name); write_tempfile_record(name, prefix_length);
return errs > 0 ? -1 : 0; return errs > 0 ? -1 : 0;
} }
@ -124,7 +122,7 @@ static int checkout_file(const char *name)
return -1; return -1;
} }
static int checkout_all(void) static void checkout_all(const char *prefix, int prefix_length)
{ {
int i, errs = 0; int i, errs = 0;
struct cache_entry* last_ce = NULL; struct cache_entry* last_ce = NULL;
@ -141,7 +139,7 @@ static int checkout_all(void)
if (last_ce && to_tempfile) { if (last_ce && to_tempfile) {
if (ce_namelen(last_ce) != ce_namelen(ce) if (ce_namelen(last_ce) != ce_namelen(ce)
|| memcmp(last_ce->name, ce->name, ce_namelen(ce))) || memcmp(last_ce->name, ce->name, ce_namelen(ce)))
write_tempfile_record(last_ce->name); write_tempfile_record(last_ce->name, prefix_length);
} }
if (checkout_entry(ce, &state, if (checkout_entry(ce, &state,
to_tempfile ? topath[ce_stage(ce)] : NULL) < 0) to_tempfile ? topath[ce_stage(ce)] : NULL) < 0)
@ -149,13 +147,12 @@ static int checkout_all(void)
last_ce = ce; last_ce = ce;
} }
if (last_ce && to_tempfile) if (last_ce && to_tempfile)
write_tempfile_record(last_ce->name); write_tempfile_record(last_ce->name, prefix_length);
if (errs) if (errs)
/* we have already done our error reporting. /* we have already done our error reporting.
* exit with the same code as die(). * exit with the same code as die().
*/ */
exit(128); exit(128);
return 0;
} }
static const char checkout_cache_usage[] = static const char checkout_cache_usage[] =
@ -163,16 +160,16 @@ static const char checkout_cache_usage[] =
static struct lock_file lock_file; static struct lock_file lock_file;
int main(int argc, char **argv) int cmd_checkout_index(int argc, const char **argv, const char *prefix)
{ {
int i; int i;
int newfd = -1; int newfd = -1;
int all = 0; int all = 0;
int read_from_stdin = 0; int read_from_stdin = 0;
int prefix_length;
state.base_dir = "";
prefix = setup_git_directory();
git_config(git_default_config); git_config(git_default_config);
state.base_dir = "";
prefix_length = prefix ? strlen(prefix) : 0; prefix_length = prefix ? strlen(prefix) : 0;
if (read_cache() < 0) { if (read_cache() < 0) {
@ -206,7 +203,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;
@ -270,7 +267,7 @@ int main(int argc, char **argv)
if (read_from_stdin) if (read_from_stdin)
die("git-checkout-index: don't mix '--stdin' and explicit filenames"); die("git-checkout-index: don't mix '--stdin' and explicit filenames");
p = prefix_path(prefix, prefix_length, arg); p = prefix_path(prefix, prefix_length, arg);
checkout_file(p); checkout_file(p, prefix_length);
if (p < arg || p > arg + strlen(arg)) if (p < arg || p > arg + strlen(arg))
free((char*)p); free((char*)p);
} }
@ -292,7 +289,7 @@ int main(int argc, char **argv)
else else
path_name = buf.buf; path_name = buf.buf;
p = prefix_path(prefix, prefix_length, path_name); p = prefix_path(prefix, prefix_length, path_name);
checkout_file(p); checkout_file(p, prefix_length);
if (p < path_name || p > path_name + strlen(path_name)) if (p < path_name || p > path_name + strlen(path_name))
free((char *)p); free((char *)p);
if (path_name != buf.buf) if (path_name != buf.buf)
@ -301,7 +298,7 @@ int main(int argc, char **argv)
} }
if (all) if (all)
checkout_all(); checkout_all(prefix, prefix_length);
if (0 <= newfd && if (0 <= newfd &&
(write_cache(newfd, active_cache, active_nr) || (write_cache(newfd, active_cache, active_nr) ||

View File

@ -47,12 +47,5 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
if (rev.pending.nr || if (rev.pending.nr ||
rev.min_age != -1 || rev.max_age != -1) rev.min_age != -1 || rev.max_age != -1)
usage(diff_files_usage); usage(diff_files_usage);
/*
* Backward compatibility wart - "diff-files -s" used to
* defeat the common diff option "-s" which asked for
* DIFF_FORMAT_NO_OUTPUT.
*/
if (rev.diffopt.output_format == DIFF_FORMAT_NO_OUTPUT)
rev.diffopt.output_format = DIFF_FORMAT_RAW;
return run_diff_files(&rev, silent); return run_diff_files(&rev, silent);
} }

View File

@ -56,13 +56,6 @@ static int builtin_diff_files(struct rev_info *revs,
if (revs->max_count < 0 && if (revs->max_count < 0 &&
(revs->diffopt.output_format & DIFF_FORMAT_PATCH)) (revs->diffopt.output_format & DIFF_FORMAT_PATCH))
revs->combine_merges = revs->dense_combined_merges = 1; revs->combine_merges = revs->dense_combined_merges = 1;
/*
* Backward compatibility wart - "diff-files -s" used to
* defeat the common diff option "-s" which asked for
* DIFF_FORMAT_NO_OUTPUT.
*/
if (revs->diffopt.output_format == DIFF_FORMAT_NO_OUTPUT)
revs->diffopt.output_format = DIFF_FORMAT_RAW;
return run_diff_files(revs, silent); return run_diff_files(revs, silent);
} }
@ -253,7 +246,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
@ -348,6 +342,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

@ -123,6 +123,7 @@ struct grep_opt {
struct grep_pat *pattern_list; struct grep_pat *pattern_list;
struct grep_pat **pattern_tail; struct grep_pat **pattern_tail;
struct grep_expr *pattern_expression; struct grep_expr *pattern_expression;
int prefix_length;
regex_t regexp; regex_t regexp;
unsigned linenum:1; unsigned linenum:1;
unsigned invert:1; unsigned invert:1;
@ -136,6 +137,7 @@ struct grep_opt {
#define GREP_BINARY_TEXT 2 #define GREP_BINARY_TEXT 2
unsigned binary:2; unsigned binary:2;
unsigned extended:1; unsigned extended:1;
unsigned relative:1;
int regflags; int regflags;
unsigned pre_context; unsigned pre_context;
unsigned post_context; unsigned post_context;
@ -388,9 +390,7 @@ static int buffer_is_binary(const char *ptr, unsigned long size)
{ {
if (FIRST_FEW_BYTES < size) if (FIRST_FEW_BYTES < size)
size = FIRST_FEW_BYTES; size = FIRST_FEW_BYTES;
if (memchr(ptr, 0, size)) return !!memchr(ptr, 0, size);
return 1;
return 0;
} }
static int fixmatch(const char *pattern, char *line, regmatch_t *match) static int fixmatch(const char *pattern, char *line, regmatch_t *match)
@ -632,19 +632,40 @@ static int grep_buffer(struct grep_opt *opt, const char *name,
return !!last_hit; return !!last_hit;
} }
static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1, const char *name) static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1, const char *name, int tree_name_len)
{ {
unsigned long size; unsigned long size;
char *data; char *data;
char type[20]; char type[20];
char *to_free = NULL;
int hit; int hit;
data = read_sha1_file(sha1, type, &size); data = read_sha1_file(sha1, type, &size);
if (!data) { if (!data) {
error("'%s': unable to read %s", name, sha1_to_hex(sha1)); error("'%s': unable to read %s", name, sha1_to_hex(sha1));
return 0; return 0;
} }
if (opt->relative && opt->prefix_length) {
static char name_buf[PATH_MAX];
char *cp;
int name_len = strlen(name) - opt->prefix_length + 1;
if (!tree_name_len)
name += opt->prefix_length;
else {
if (ARRAY_SIZE(name_buf) <= name_len)
cp = to_free = xmalloc(name_len);
else
cp = name_buf;
memcpy(cp, name, tree_name_len);
strcpy(cp + tree_name_len,
name + tree_name_len + opt->prefix_length);
name = cp;
}
}
hit = grep_buffer(opt, name, data, size); hit = grep_buffer(opt, name, data, size);
free(data); free(data);
free(to_free);
return hit; return hit;
} }
@ -674,6 +695,8 @@ static int grep_file(struct grep_opt *opt, const char *filename)
return 0; return 0;
} }
close(i); close(i);
if (opt->relative && opt->prefix_length)
filename += opt->prefix_length;
i = grep_buffer(opt, filename, data, st.st_size); i = grep_buffer(opt, filename, data, st.st_size);
free(data); free(data);
return i; return i;
@ -720,7 +743,7 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)
char *argptr = randarg; char *argptr = randarg;
struct grep_pat *p; struct grep_pat *p;
if (opt->extended) if (opt->extended || (opt->relative && opt->prefix_length))
return -1; return -1;
len = nr = 0; len = nr = 0;
push_arg("grep"); push_arg("grep");
@ -845,7 +868,7 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached)
if (!pathspec_matches(paths, ce->name)) if (!pathspec_matches(paths, ce->name))
continue; continue;
if (cached) if (cached)
hit |= grep_sha1(opt, ce->sha1, ce->name); hit |= grep_sha1(opt, ce->sha1, ce->name, 0);
else else
hit |= grep_file(opt, ce->name); hit |= grep_file(opt, ce->name);
} }
@ -860,11 +883,12 @@ static int grep_tree(struct grep_opt *opt, const char **paths,
int hit = 0; int hit = 0;
struct name_entry entry; struct name_entry entry;
char *down; char *down;
char *path_buf = xmalloc(PATH_MAX + strlen(tree_name) + 100); int tn_len = strlen(tree_name);
char *path_buf = xmalloc(PATH_MAX + tn_len + 100);
if (tree_name[0]) { if (tn_len) {
int offset = sprintf(path_buf, "%s:", tree_name); tn_len = sprintf(path_buf, "%s:", tree_name);
down = path_buf + offset; down = path_buf + tn_len;
strcat(down, base); strcat(down, base);
} }
else { else {
@ -886,7 +910,7 @@ static int grep_tree(struct grep_opt *opt, const char **paths,
if (!pathspec_matches(paths, down)) if (!pathspec_matches(paths, down))
; ;
else if (S_ISREG(entry.mode)) else if (S_ISREG(entry.mode))
hit |= grep_sha1(opt, entry.sha1, path_buf); hit |= grep_sha1(opt, entry.sha1, path_buf, tn_len);
else if (S_ISDIR(entry.mode)) { else if (S_ISDIR(entry.mode)) {
char type[20]; char type[20];
struct tree_desc sub; struct tree_desc sub;
@ -907,7 +931,7 @@ static int grep_object(struct grep_opt *opt, const char **paths,
struct object *obj, const char *name) struct object *obj, const char *name)
{ {
if (obj->type == OBJ_BLOB) if (obj->type == OBJ_BLOB)
return grep_sha1(opt, obj->sha1, name); return grep_sha1(opt, obj->sha1, name, 0);
if (obj->type == OBJ_COMMIT || obj->type == OBJ_TREE) { if (obj->type == OBJ_COMMIT || obj->type == OBJ_TREE) {
struct tree_desc tree; struct tree_desc tree;
void *data; void *data;
@ -945,6 +969,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
int i; int i;
memset(&opt, 0, sizeof(opt)); memset(&opt, 0, sizeof(opt));
opt.prefix_length = (prefix && *prefix) ? strlen(prefix) : 0;
opt.relative = 1;
opt.pattern_tail = &opt.pattern_list; opt.pattern_tail = &opt.pattern_list;
opt.regflags = REG_NEWLINE; opt.regflags = REG_NEWLINE;
@ -1118,6 +1144,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
} }
die(emsg_missing_argument, arg); die(emsg_missing_argument, arg);
} }
if (!strcmp("--full-name", arg)) {
opt.relative = 0;
continue;
}
if (!strcmp("--", arg)) { if (!strcmp("--", arg)) {
/* later processing wants to have this at argv[1] */ /* later processing wants to have this at argv[1] */
argv--; argv--;
@ -1176,8 +1206,15 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
verify_filename(prefix, argv[j]); verify_filename(prefix, argv[j]);
} }
if (i < argc) if (i < argc) {
paths = get_pathspec(prefix, argv + i); paths = get_pathspec(prefix, argv + i);
if (opt.prefix_length && opt.relative) {
/* Make sure we do not get outside of paths */
for (i = 0; paths[i]; i++)
if (strncmp(prefix, paths[i], opt.prefix_length))
die("git-grep: cannot generate relative filenames containing '..'");
}
}
else if (prefix) { else if (prefix) {
paths = xcalloc(2, sizeof(const char *)); paths = xcalloc(2, sizeof(const char *));
paths[0] = prefix; paths[0] = prefix;

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");

View File

@ -1,4 +1,5 @@
#include <stdlib.h> #include <stdlib.h>
#include "builtin.h"
#include "cache.h" #include "cache.h"
#include "commit.h" #include "commit.h"
#include "tag.h" #include "tag.h"
@ -126,12 +127,11 @@ static const char* get_rev_name(struct object *o)
return buffer; return buffer;
} }
int main(int argc, char **argv) int cmd_name_rev(int argc, const char **argv, const char *prefix)
{ {
struct object_array revs = { 0, 0, NULL }; struct object_array revs = { 0, 0, NULL };
int as_is = 0, all = 0, transform_stdin = 0; int as_is = 0, all = 0, transform_stdin = 0;
setup_git_directory();
git_config(git_default_config); git_config(git_default_config);
if (argc < 2) if (argc < 2)

View File

@ -1,3 +1,4 @@
#include "builtin.h"
#include "cache.h" #include "cache.h"
#include "object.h" #include "object.h"
#include "blob.h" #include "blob.h"
@ -269,6 +270,22 @@ static unsigned long write_object(struct sha1file *f,
* and we do not need to deltify it. * and we do not need to deltify it.
*/ */
if (!entry->in_pack && !entry->delta) {
unsigned char *map;
unsigned long mapsize;
map = map_sha1_file(entry->sha1, &mapsize);
if (map && !legacy_loose_object(map)) {
/* We can copy straight into the pack file */
sha1write(f, map, mapsize);
munmap(map, mapsize);
written++;
reused++;
return mapsize;
}
if (map)
munmap(map, mapsize);
}
if (! to_reuse) { if (! to_reuse) {
buf = read_sha1_file(entry->sha1, type, &size); buf = read_sha1_file(entry->sha1, type, &size);
if (!buf) if (!buf)
@ -1226,7 +1243,7 @@ static int git_pack_config(const char *k, const char *v)
return git_default_config(k, v); return git_default_config(k, v);
} }
int main(int argc, char **argv) int cmd_pack_objects(int argc, const char **argv, const char *prefix)
{ {
SHA_CTX ctx; SHA_CTX ctx;
char line[40 + 1 + PATH_MAX + 2]; char line[40 + 1 + PATH_MAX + 2];
@ -1235,7 +1252,6 @@ int main(int argc, char **argv)
int num_preferred_base = 0; int num_preferred_base = 0;
int i; int i;
setup_git_directory();
git_config(git_pack_config); git_config(git_pack_config);
progress = isatty(2); progress = isatty(2);

View File

@ -32,10 +32,8 @@ static int expand_one_ref(const char *ref, const unsigned char *sha1)
/* Ignore the "refs/" at the beginning of the refname */ /* Ignore the "refs/" at the beginning of the refname */
ref += 5; ref += 5;
if (strncmp(ref, "tags/", 5)) if (!strncmp(ref, "tags/", 5))
return 0; add_refspec(strdup(ref));
add_refspec(strdup(ref));
return 0; return 0;
} }

File diff suppressed because it is too large Load Diff

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");

View File

@ -1,3 +1,4 @@
#include "builtin.h"
#include "cache.h" #include "cache.h"
static const char git_symbolic_ref_usage[] = static const char git_symbolic_ref_usage[] =
@ -17,9 +18,8 @@ static void check_symref(const char *HEAD)
die("No such ref: %s", HEAD); die("No such ref: %s", HEAD);
} }
int main(int argc, const char **argv) int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
{ {
setup_git_directory();
git_config(git_default_config); git_config(git_default_config);
switch (argc) { switch (argc) {
case 2: case 2:

View File

@ -1,3 +1,4 @@
#include "builtin.h"
#include "cache.h" #include "cache.h"
#include "object.h" #include "object.h"
#include "delta.h" #include "delta.h"
@ -260,12 +261,12 @@ static void unpack_all(void)
die("unresolved deltas left after unpacking"); die("unresolved deltas left after unpacking");
} }
int main(int argc, char **argv) int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
{ {
int i; int i;
unsigned char sha1[20]; unsigned char sha1[20];
setup_git_directory(); git_config(git_default_config);
quiet = !isatty(2); quiet = !isatty(2);

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)

79
builtin-verify-pack.c Normal file
View File

@ -0,0 +1,79 @@
#include "builtin.h"
#include "cache.h"
#include "pack.h"
static int verify_one_pack(const char *path, int verbose)
{
char arg[PATH_MAX];
int len;
struct packed_git *pack;
int err;
len = strlcpy(arg, path, PATH_MAX);
if (len >= PATH_MAX)
return error("name too long: %s", path);
/*
* In addition to "foo.idx" we accept "foo.pack" and "foo";
* normalize these forms to "foo.idx" for add_packed_git().
*/
if (has_extension(arg, ".pack")) {
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");
len += 4;
}
/*
* 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>...";
int cmd_verify_pack(int argc, const char **argv, const char *prefix)
{
int err = 0;
int verbose = 0;
int no_more_options = 0;
int nothing_done = 1;
while (1 < argc) {
if (!no_more_options && argv[1][0] == '-') {
if (!strcmp("-v", argv[1]))
verbose = 1;
else if (!strcmp("--", argv[1]))
no_more_options = 1;
else
usage(verify_pack_usage);
}
else {
if (verify_one_pack(argv[1], verbose))
err = 1;
nothing_done = 0;
}
argc--; argv++;
}
if (nothing_done)
usage(verify_pack_usage);
return err;
}

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)

View File

@ -8,57 +8,57 @@ extern const char git_version_string[];
extern const char git_usage_string[]; extern const char git_usage_string[];
extern void help_unknown_cmd(const char *cmd); extern void help_unknown_cmd(const char *cmd);
extern int mailinfo(FILE *in, FILE *out, int ks, const char *encoding, const char *msg, const char *patch);
extern int cmd_help(int argc, const char **argv, const char *prefix); extern int split_mbox(const char **mbox, const char *dir, int allow_bare, int nr_prec, int skip);
extern int cmd_version(int argc, const char **argv, const char *prefix); extern void stripspace(FILE *in, FILE *out);
extern int cmd_whatchanged(int argc, const char **argv, const char *prefix);
extern int cmd_show(int argc, const char **argv, const char *prefix);
extern int cmd_log(int argc, const char **argv, const char *prefix);
extern int cmd_diff(int argc, const char **argv, const char *prefix);
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_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_grep(int argc, const char **argv, const char *prefix);
extern int cmd_rm(int argc, const char **argv, const char *prefix);
extern int cmd_add(int argc, const char **argv, const char *prefix);
extern int cmd_rev_list(int argc, const char **argv, const char *prefix);
extern int cmd_check_ref_format(int argc, const char **argv, const char *prefix);
extern int cmd_init_db(int argc, const char **argv, const char *prefix);
extern int cmd_tar_tree(int argc, const char **argv, const char *prefix);
extern int cmd_upload_tar(int argc, const char **argv, const char *prefix);
extern int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix);
extern int cmd_ls_files(int argc, const char **argv, const char *prefix);
extern int cmd_ls_tree(int argc, const char **argv, const char *prefix);
extern int cmd_read_tree(int argc, const char **argv, const char *prefix);
extern int cmd_commit_tree(int argc, const char **argv, const char *prefix);
extern int cmd_apply(int argc, const char **argv, const char *prefix);
extern int cmd_show_branch(int argc, const char **argv, const char *prefix);
extern int cmd_diff_files(int argc, const char **argv, const char *prefix);
extern int cmd_diff_index(int argc, const char **argv, const char *prefix);
extern int cmd_diff_stages(int argc, const char **argv, const char *prefix);
extern int cmd_diff_tree(int argc, const char **argv, const char *prefix);
extern int cmd_cat_file(int argc, const char **argv, const char *prefix);
extern int cmd_rev_parse(int argc, const char **argv, const char *prefix);
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_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_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 write_tree(unsigned char *sha1, int missing_ok, const char *prefix); extern int write_tree(unsigned char *sha1, int missing_ok, const char *prefix);
extern int cmd_mailsplit(int argc, const char **argv, const char *prefix); extern int cmd_add(int argc, const char **argv, const char *prefix);
extern int split_mbox(const char **mbox, const char *dir, int allow_bare, int nr_prec, int skip); extern int cmd_apply(int argc, const char **argv, const char *prefix);
extern int cmd_cat_file(int argc, const char **argv, const char *prefix);
extern int cmd_checkout_index(int argc, const char **argv, const char *prefix);
extern int cmd_check_ref_format(int argc, const char **argv, const char *prefix);
extern int cmd_commit_tree(int argc, const char **argv, const char *prefix);
extern int cmd_count_objects(int argc, const char **argv, const char *prefix);
extern int cmd_diff_files(int argc, const char **argv, const char *prefix);
extern int cmd_diff_index(int argc, const char **argv, const char *prefix);
extern int cmd_diff(int argc, const char **argv, const char *prefix);
extern int cmd_diff_stages(int argc, const char **argv, const char *prefix);
extern int cmd_diff_tree(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_format_patch(int argc, const char **argv, const char *prefix);
extern int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix);
extern int cmd_grep(int argc, const char **argv, const char *prefix);
extern int cmd_help(int argc, const char **argv, const char *prefix);
extern int cmd_init_db(int argc, const char **argv, const char *prefix);
extern int cmd_log(int argc, const char **argv, const char *prefix);
extern int cmd_ls_files(int argc, const char **argv, const char *prefix);
extern int cmd_ls_tree(int argc, const char **argv, const char *prefix);
extern int cmd_mailinfo(int argc, const char **argv, const char *prefix); extern int cmd_mailinfo(int argc, const char **argv, const char *prefix);
extern int mailinfo(FILE *in, FILE *out, int ks, const char *encoding, const char *msg, const char *patch); extern int cmd_mailsplit(int argc, const char **argv, const char *prefix);
extern int cmd_mv(int argc, const char **argv, const char *prefix);
extern int cmd_name_rev(int argc, const char **argv, const char *prefix);
extern int cmd_pack_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_packed(int argc, const char **argv, const char *prefix);
extern int cmd_push(int argc, const char **argv, const char *prefix);
extern int cmd_read_tree(int argc, const char **argv, const char *prefix);
extern int cmd_repo_config(int argc, const char **argv, const char *prefix);
extern int cmd_rev_list(int argc, const char **argv, const char *prefix);
extern int cmd_rev_parse(int argc, const char **argv, const char *prefix);
extern int cmd_rm(int argc, const char **argv, const char *prefix);
extern int cmd_show_branch(int argc, const char **argv, const char *prefix);
extern int cmd_show(int argc, const char **argv, const char *prefix);
extern int cmd_stripspace(int argc, const char **argv, const char *prefix); extern int cmd_stripspace(int argc, const char **argv, const char *prefix);
extern void stripspace(FILE *in, FILE *out); extern int cmd_symbolic_ref(int argc, const char **argv, const char *prefix);
extern int cmd_tar_tree(int argc, const char **argv, const char *prefix);
extern int cmd_unpack_objects(int argc, const char **argv, const char *prefix);
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_upload_tar(int argc, const char **argv, const char *prefix);
extern int cmd_version(int argc, const char **argv, const char *prefix);
extern int cmd_whatchanged(int argc, const char **argv, const char *prefix);
extern int cmd_write_tree(int argc, const char **argv, const char *prefix);
extern int cmd_verify_pack(int argc, const char **argv, const char *prefix);
#endif #endif

View File

@ -178,7 +178,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 *);
@ -247,6 +247,8 @@ extern int move_temp_to_file(const char *tmpfile, char *filename);
extern int has_sha1_pack(const unsigned char *sha1); extern int has_sha1_pack(const unsigned char *sha1);
extern int has_sha1_file(const unsigned char *sha1); extern int has_sha1_file(const unsigned char *sha1);
extern void *map_sha1_file(const unsigned char *sha1, unsigned long *);
extern int legacy_loose_object(unsigned char *);
extern int has_pack_file(const unsigned char *sha1); extern int has_pack_file(const unsigned char *sha1);
extern int has_pack_index(const unsigned char *sha1); extern int has_pack_index(const unsigned char *sha1);

View File

@ -7,13 +7,6 @@
#include "xdiff-interface.h" #include "xdiff-interface.h"
#include "log-tree.h" #include "log-tree.h"
static int uninteresting(struct diff_filepair *p)
{
if (diff_unmodified_pair(p))
return 1;
return 0;
}
static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr, int n, int num_parent) static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr, int n, int num_parent)
{ {
struct diff_queue_struct *q = &diff_queued_diff; struct diff_queue_struct *q = &diff_queued_diff;
@ -25,7 +18,7 @@ static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr,
for (i = 0; i < q->nr; i++) { for (i = 0; i < q->nr; i++) {
int len; int len;
const char *path; const char *path;
if (uninteresting(q->queue[i])) if (diff_unmodified_pair(q->queue[i]))
continue; continue;
path = q->queue[i]->two->path; path = q->queue[i]->two->path;
len = strlen(path); len = strlen(path);
@ -57,7 +50,7 @@ static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr,
const char *path; const char *path;
int len; int len;
if (uninteresting(q->queue[i])) if (diff_unmodified_pair(q->queue[i]))
continue; continue;
path = q->queue[i]->two->path; path = q->queue[i]->two->path;
len = strlen(path); len = strlen(path);
@ -497,11 +490,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 +521,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 +535,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 +559,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,25 +591,26 @@ 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 void show_patch_diff(struct combine_diff_path *elem, int num_parent,
int dense, struct rev_info *rev) int dense, struct rev_info *rev)
{ {
struct diff_options *opt = &rev->diffopt; struct diff_options *opt = &rev->diffopt;
unsigned long result_size, cnt, lno; unsigned long result_size, cnt, lno;
char *result, *cp; char *result, *cp;
struct sline *sline; /* survived lines */ struct sline *sline; /* survived lines */
int mode_differs = 0; int mode_differs = 0;
int i, show_hunks, shown_header = 0; int i, show_hunks;
int working_tree_file = !memcmp(elem->sha1, null_sha1, 20); int working_tree_file = !memcmp(elem->sha1, null_sha1, 20);
int abbrev = opt->full_index ? 40 : DEFAULT_ABBREV; int abbrev = opt->full_index ? 40 : DEFAULT_ABBREV;
mmfile_t result_file; mmfile_t result_file;
@ -699,18 +705,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 +729,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 +742,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);
@ -751,7 +762,6 @@ static int show_patch_diff(struct combine_diff_path *elem, int num_parent,
} }
free(sline[0].p_lno); free(sline[0].p_lno);
free(sline); free(sline);
return shown_header;
} }
#define COLONS "::::::::::::::::::::::::::::::::" #define COLONS "::::::::::::::::::::::::::::::::"
@ -819,11 +829,10 @@ void show_combined_diff(struct combine_diff_path *p,
return; return;
if (opt->output_format & (DIFF_FORMAT_RAW | if (opt->output_format & (DIFF_FORMAT_RAW |
DIFF_FORMAT_NAME | DIFF_FORMAT_NAME |
DIFF_FORMAT_NAME_STATUS)) { DIFF_FORMAT_NAME_STATUS))
show_raw_diff(p, num_parent, rev); show_raw_diff(p, num_parent, rev);
} else if (opt->output_format & DIFF_FORMAT_PATCH) { else if (opt->output_format & DIFF_FORMAT_PATCH)
show_patch_diff(p, num_parent, dense, rev); show_patch_diff(p, num_parent, dense, rev);
}
} }
void diff_tree_combined(const unsigned char *sha1, void diff_tree_combined(const unsigned char *sha1,

View File

@ -22,3 +22,19 @@ VPATH = @srcdir@
export exec_prefix mandir export exec_prefix mandir
export srcdir VPATH export srcdir VPATH
NO_PYTHON=@NO_PYTHON@
NEEDS_SSL_WITH_CRYPTO=@NEEDS_SSL_WITH_CRYPTO@
NO_OPENSSL=@NO_OPENSSL@
NO_CURL=@NO_CURL@
NO_EXPAT=@NO_EXPAT@
NEEDS_LIBICONV=@NEEDS_LIBICONV@
NEEDS_SOCKET=@NEEDS_SOCKET@
NO_D_INO_IN_DIRENT=@NO_D_INO_IN_DIRENT@
NO_D_TYPE_IN_DIRENT=@NO_D_TYPE_IN_DIRENT@
NO_SOCKADDR_STORAGE=@NO_SOCKADDR_STORAGE@
NO_IPV6=@NO_IPV6@
NO_C99_FORMAT=@NO_C99_FORMAT@
NO_STRCASESTR=@NO_STRCASESTR@
NO_STRLCPY=@NO_STRLCPY@
NO_SETENV=@NO_SETENV@

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], [@@GIT_VERSION@@], [git@vger.kernel.org])
AC_CONFIG_SRCDIR([git.c]) AC_CONFIG_SRCDIR([git.c])
@ -19,6 +19,77 @@ echo "# ${config_append}. Generated by configure." > "${config_append}"
# Append LINE to file ${config_append} # Append LINE to file ${config_append}
AC_DEFUN([GIT_CONF_APPEND_LINE], AC_DEFUN([GIT_CONF_APPEND_LINE],
[echo "$1" >> "${config_append}"])# GIT_CONF_APPEND_LINE [echo "$1" >> "${config_append}"])# GIT_CONF_APPEND_LINE
#
# GIT_ARG_SET_PATH(PROGRAM)
# -------------------------
# Provide --with-PROGRAM=PATH option to set PATH to PROGRAM
AC_DEFUN([GIT_ARG_SET_PATH],
[AC_ARG_WITH([$1],
[AS_HELP_STRING([--with-$1=PATH],
[provide PATH to $1])],
[GIT_CONF_APPEND_PATH($1)],[])
])# GIT_ARG_SET_PATH
#
# GIT_CONF_APPEND_PATH(PROGRAM)
# ------------------------------
# Parse --with-PROGRAM=PATH option to set PROGRAM_PATH=PATH
# Used by GIT_ARG_SET_PATH(PROGRAM)
AC_DEFUN([GIT_CONF_APPEND_PATH],
[PROGRAM=m4_toupper($1); \
if test "$withval" = "no"; then \
AC_MSG_ERROR([You cannot use git without $1]); \
else \
if test "$withval" = "yes"; then \
AC_MSG_WARN([You should provide path for --with-$1=PATH]); \
else \
GIT_CONF_APPEND_LINE(${PROGRAM}_PATH=$withval); \
fi; \
fi; \
]) # GIT_CONF_APPEND_PATH
#
# GIT_PARSE_WITH(PACKAGE)
# -----------------------
# For use in AC_ARG_WITH action-if-found, for packages default ON.
# * Set NO_PACKAGE=YesPlease for --without-PACKAGE
# * Set PACKAGEDIR=PATH for --with-PACKAGE=PATH
# * Unset NO_PACKAGE for --with-PACKAGE without ARG
AC_DEFUN([GIT_PARSE_WITH],
[PACKAGE=m4_toupper($1); \
if test "$withval" = "no"; then \
m4_toupper(NO_$1)=YesPlease; \
elif test "$withval" = "yes"; then \
m4_toupper(NO_$1)=; \
else \
m4_toupper(NO_$1)=; \
GIT_CONF_APPEND_LINE(${PACKAGE}DIR=$withval); \
fi \
])# GIT_PARSE_WITH
## Site configuration related to programs (before tests)
## --with-PACKAGE[=ARG] and --without-PACKAGE
#
# Define SHELL_PATH to provide path to shell.
GIT_ARG_SET_PATH(shell)
#
# Define PERL_PATH to provide path to Perl.
GIT_ARG_SET_PATH(perl)
#
# Define NO_PYTHON if you want to lose all benefits of the recursive merge.
# Define PYTHON_PATH to provide path to Python.
AC_ARG_WITH(python,[AS_HELP_STRING([--with-python=PATH], [provide PATH to python])
AS_HELP_STRING([--without-python], [don't use python scripts])],
[if test "$withval" = "no"; then \
NO_PYTHON=YesPlease; \
elif test "$withval" = "yes"; then \
NO_PYTHON=; \
else \
NO_PYTHON=; \
PYTHON_PATH=$withval; \
fi; \
])
AC_SUBST(NO_PYTHON)
AC_SUBST(PYTHON_PATH)
## Checks for programs. ## Checks for programs.
@ -30,6 +101,16 @@ AC_CHECK_TOOL(AR, ar, :)
AC_CHECK_PROGS(TAR, [gtar tar]) AC_CHECK_PROGS(TAR, [gtar tar])
# #
# Define NO_PYTHON if you want to lose all benefits of the recursive merge. # Define NO_PYTHON if you want to lose all benefits of the recursive merge.
# Define PYTHON_PATH to provide path to Python.
if test -z "$NO_PYTHON"; then
if test -z "$PYTHON_PATH"; then
AC_PATH_PROGS(PYTHON_PATH, [python python2.4 python2.3 python2])
fi
if test -n "$PYTHON_PATH"; then
GIT_CONF_APPEND_LINE([PYTHON_PATH=@PYTHON_PATH@])
NO_PYTHON=""
fi
fi
## Checks for libraries. ## Checks for libraries.
@ -37,32 +118,43 @@ AC_MSG_NOTICE([CHECKS for libraries])
# #
# Define NO_OPENSSL environment variable if you do not have OpenSSL. # Define NO_OPENSSL environment variable if you do not have OpenSSL.
# Define NEEDS_SSL_WITH_CRYPTO if you need -lcrypto with -lssl (Darwin). # Define NEEDS_SSL_WITH_CRYPTO if you need -lcrypto with -lssl (Darwin).
AC_CHECK_LIB([ssl], [SHA1_Init],[], AC_CHECK_LIB([crypto], [SHA1_Init],
[AC_CHECK_LIB([crypto], [SHA1_INIT], [NEEDS_SSL_WITH_CRYPTO=],
[GIT_CONF_APPEND_LINE(NEEDS_SSL_WITH_CRYPTO=YesPlease)], [AC_CHECK_LIB([ssl], [SHA1_Init],
[GIT_CONF_APPEND_LINE(NO_OPENSSL=YesPlease)])]) [NEEDS_SSL_WITH_CRYPTO=YesPlease
NEEDS_SSL_WITH_CRYPTO=],
[NO_OPENSSL=YesPlease])])
AC_SUBST(NEEDS_SSL_WITH_CRYPTO)
AC_SUBST(NO_OPENSSL)
# #
# Define NO_CURL if you do not have curl installed. git-http-pull and # Define NO_CURL if you do not have curl installed. git-http-pull and
# git-http-push are not built, and you cannot use http:// and https:// # git-http-push are not built, and you cannot use http:// and https://
# transports. # transports.
AC_CHECK_LIB([curl], [curl_global_init],[], AC_CHECK_LIB([curl], [curl_global_init],
[GIT_CONF_APPEND_LINE(NO_CURL=YesPlease)]) [NO_CURL=],
[NO_CURL=YesPlease])
AC_SUBST(NO_CURL)
# #
# Define NO_EXPAT if you do not have expat installed. git-http-push is # Define NO_EXPAT if you do not have expat installed. git-http-push is
# not built, and you cannot push using http:// and https:// transports. # not built, and you cannot push using http:// and https:// transports.
AC_CHECK_LIB([expat], [XML_ParserCreate],[], AC_CHECK_LIB([expat], [XML_ParserCreate],
[GIT_CONF_APPEND_LINE(NO_EXPAT=YesPlease)]) [NO_EXPAT=],
[NO_EXPAT=YesPlease])
AC_SUBST(NO_EXPAT)
# #
# Define NEEDS_LIBICONV if linking with libc is not enough (Darwin). # Define NEEDS_LIBICONV if linking with libc is not enough (Darwin).
AC_CHECK_LIB([c], [iconv],[], AC_CHECK_LIB([c], [iconv],
[AC_CHECK_LIB([iconv],[iconv], [NEEDS_LIBICONV=],
[GIT_CONF_APPEND_LINE(NEEDS_LIBICONV=YesPlease)],[])]) [NEEDS_LIBICONV=YesPlease])
AC_SUBST(NEEDS_LIBICONV)
# #
# Define NEEDS_SOCKET if linking with libc is not enough (SunOS, # Define NEEDS_SOCKET if linking with libc is not enough (SunOS,
# Patrick Mauritz). # Patrick Mauritz).
AC_CHECK_LIB([c], [socket],[], AC_CHECK_LIB([c], [socket],
[AC_CHECK_LIB([socket],[socket], [NEEDS_SOCKET=],
[GIT_CONF_APPEND_LINE(NEEDS_SOCKET=YesPlease)],[])]) [NEEDS_SOCKET=YesPlease])
AC_SUBST(NEEDS_SOCKET)
test -n "$NEEDS_SOCKET" && LIBS="$LIBS -lsocket"
## Checks for header files. ## Checks for header files.
@ -72,21 +164,65 @@ AC_CHECK_LIB([c], [socket],[],
AC_MSG_NOTICE([CHECKS for typedefs, structures, and compiler characteristics]) AC_MSG_NOTICE([CHECKS for typedefs, structures, and compiler characteristics])
# #
# Define NO_D_INO_IN_DIRENT if you don't have d_ino in your struct dirent. # Define NO_D_INO_IN_DIRENT if you don't have d_ino in your struct dirent.
AC_CHECK_MEMBER(struct dirent.d_ino,[], AC_CHECK_MEMBER(struct dirent.d_ino,
[GIT_CONF_APPEND_LINE(NO_D_INO_IN_DIRENT=YesPlease)], [NO_D_INO_IN_DIRENT=],
[NO_D_INO_IN_DIRENT=YesPlease],
[#include <dirent.h>]) [#include <dirent.h>])
AC_SUBST(NO_D_INO_IN_DIRENT)
# #
# 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).
AC_CHECK_MEMBER(struct dirent.d_type,[], AC_CHECK_MEMBER(struct dirent.d_type,
[GIT_CONF_APPEND_LINE(NO_D_TYPE_IN_DIRENT=YesPlease)], [NO_D_TYPE_IN_DIRENT=],
[NO_D_TYPE_IN_DIRENT=YesPlease],
[#include <dirent.h>]) [#include <dirent.h>])
AC_SUBST(NO_D_TYPE_IN_DIRENT)
# #
# Define NO_SOCKADDR_STORAGE if your platform does not have struct # Define NO_SOCKADDR_STORAGE if your platform does not have struct
# sockaddr_storage. # sockaddr_storage.
AC_CHECK_TYPE(struct sockaddr_storage,[], AC_CHECK_TYPE(struct sockaddr_storage,
[GIT_CONF_APPEND_LINE(NO_SOCKADDR_STORAGE=YesPlease)], [NO_SOCKADDR_STORAGE=],
[#include <netinet/in.h>]) [NO_SOCKADDR_STORAGE=YesPlease],[
#include <sys/types.h>
#include <sys/socket.h>
])
AC_SUBST(NO_SOCKADDR_STORAGE)
#
# Define NO_IPV6 if you lack IPv6 support and getaddrinfo().
AC_CHECK_TYPE([struct addrinfo],[
AC_CHECK_FUNC([getaddrinfo],
[NO_IPV6=],
[NO_IPV6=YesPlease])
],[NO_IPV6=YesPlease],[
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
])
AC_SUBST(NO_IPV6)
#
# 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.
AC_CACHE_CHECK(whether formatted IO functions support C99 size specifiers,
ac_cv_c_c99_format,
[# Actually git uses only %z (%zu) in alloc.c, and %t (%td) in mktag.c
AC_RUN_IFELSE(
[AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT],
[[char buf[64];
if (sprintf(buf, "%lld%hhd%jd%zd%td", (long long int)1, (char)2, (intmax_t)3, (size_t)4, (ptrdiff_t)5) != 5)
exit(1);
else if (strcmp(buf, "12345"))
exit(2);]])],
[ac_cv_c_c99_format=yes],
[ac_cv_c_c99_format=no])
])
if test $ac_cv_c_c99_format = no; then
NO_C99_FORMAT=YesPlease
else
NO_C99_FORMAT=
fi
AC_SUBST(NO_C99_FORMAT)
## Checks for library functions. ## Checks for library functions.
@ -94,21 +230,25 @@ AC_CHECK_TYPE(struct sockaddr_storage,[],
AC_MSG_NOTICE([CHECKS for library functions]) AC_MSG_NOTICE([CHECKS for library functions])
# #
# Define NO_STRCASESTR if you don't have strcasestr. # Define NO_STRCASESTR if you don't have strcasestr.
AC_CHECK_FUNC(strcasestr,[], AC_CHECK_FUNC(strcasestr,
[GIT_CONF_APPEND_LINE(NO_STRCASESTR=YesPlease)]) [NO_STRCASESTR=],
[NO_STRCASESTR=YesPlease])
AC_SUBST(NO_STRCASESTR)
# #
# Define NO_STRLCPY if you don't have strlcpy. # Define NO_STRLCPY if you don't have strlcpy.
AC_CHECK_FUNC(strlcpy,[], AC_CHECK_FUNC(strlcpy,
[GIT_CONF_APPEND_LINE(NO_STRLCPY=YesPlease)]) [NO_STRLCPY=],
[NO_STRLCPY=YesPlease])
AC_SUBST(NO_STRLCPY)
# #
# Define NO_SETENV if you don't have setenv in the C library. # Define NO_SETENV if you don't have setenv in the C library.
AC_CHECK_FUNC(setenv,[], AC_CHECK_FUNC(setenv,
[GIT_CONF_APPEND_LINE(NO_SETENV=YesPlease)]) [NO_SETENV=],
[NO_SETENV=YesPlease])
AC_SUBST(NO_SETENV)
# #
# Define NO_MMAP if you want to avoid mmap. # Define NO_MMAP if you want to avoid mmap.
# #
# Define NO_IPV6 if you lack IPv6 support and getaddrinfo().
#
# Define NO_ICONV if your libc does not properly support iconv. # Define NO_ICONV if your libc does not properly support iconv.
@ -125,9 +265,11 @@ AC_CHECK_FUNC(setenv,[],
# a missing newline at the end of the file. # a missing newline at the end of the file.
## Site configuration ## Site configuration (override autodetection)
## --with-PACKAGE[=ARG] and --without-PACKAGE ## --with-PACKAGE[=ARG] and --without-PACKAGE
# Define NO_SVN_TESTS if you want to skip time-consuming SVN interopability AC_MSG_NOTICE([CHECKS for site configuration])
#
# Define NO_SVN_TESTS if you want to skip time-consuming SVN interoperability
# tests. These tests take up a significant amount of the total test time # tests. These tests take up a significant amount of the total test time
# but are not needed unless you plan to talk to SVN repos. # but are not needed unless you plan to talk to SVN repos.
# #
@ -145,21 +287,51 @@ AC_CHECK_FUNC(setenv,[],
# Define NO_OPENSSL environment variable if you do not have OpenSSL. # Define NO_OPENSSL environment variable if you do not have OpenSSL.
# This also implies MOZILLA_SHA1. # This also implies MOZILLA_SHA1.
# #
# Define OPENSSLDIR=/foo/bar if your openssl header and library files are in
# /foo/bar/include and /foo/bar/lib directories.
AC_ARG_WITH(openssl,
AS_HELP_STRING([--with-openssl],[use OpenSSL library (default is YES)])
AS_HELP_STRING([], [ARG can be prefix for openssl library and headers]),\
GIT_PARSE_WITH(openssl))
#
# Define NO_CURL if you do not have curl installed. git-http-pull and # Define NO_CURL if you do not have curl installed. git-http-pull and
# git-http-push are not built, and you cannot use http:// and https:// # git-http-push are not built, and you cannot use http:// and https://
# transports. # transports.
# #
# Define CURLDIR=/foo/bar if your curl header and library files are in # Define CURLDIR=/foo/bar if your curl header and library files are in
# /foo/bar/include and /foo/bar/lib directories. # /foo/bar/include and /foo/bar/lib directories.
AC_ARG_WITH(curl,
AS_HELP_STRING([--with-curl],[support http(s):// transports (default is YES)])
AS_HELP_STRING([], [ARG can be also prefix for curl library and headers]),
GIT_PARSE_WITH(curl))
# #
# Define NO_EXPAT if you do not have expat installed. git-http-push is # Define NO_EXPAT if you do not have expat installed. git-http-push is
# not built, and you cannot push using http:// and https:// transports. # not built, and you cannot push using http:// and https:// transports.
# #
# Define EXPATDIR=/foo/bar if your expat header and library files are in
# /foo/bar/include and /foo/bar/lib directories.
AC_ARG_WITH(expat,
AS_HELP_STRING([--with-expat],
[support git-push using http:// and https:// transports via WebDAV (default is YES)])
AS_HELP_STRING([], [ARG can be also prefix for expat library and headers]),
GIT_PARSE_WITH(expat))
#
# Define NO_FINK if you are building on Darwin/Mac OS X, have Fink
# installed in /sw, but don't want GIT to link against any libraries
# installed there. If defined you may specify your own (or Fink's)
# include directories and library directories by defining CFLAGS
# and LDFLAGS appropriately.
#
# Define NO_DARWIN_PORTS if you are building on Darwin/Mac OS X,
# have DarwinPorts installed in /opt/local, but don't want GIT to
# link against any libraries installed there. If defined you may
# specify your own (or DarwinPort's) include directories and
# library directories by defining CFLAGS and LDFLAGS appropriately.
#
# Define NO_MMAP if you want to avoid mmap. # Define NO_MMAP if you want to avoid mmap.
#
# Define NO_PYTHON if you want to loose all benefits of the recursive merge.
#
## --enable-FEATURE[=ARG] and --disable-FEATURE ## --enable-FEATURE[=ARG] and --disable-FEATURE
#
# Define COLLISION_CHECK below if you believe that SHA1's # Define COLLISION_CHECK below if you believe that SHA1's
# 1461501637330902918203684832716283019655932542976 hashes do not give you # 1461501637330902918203684832716283019655932542976 hashes do not give you
# sufficient guarantee that no collisions between objects will ever happen. # sufficient guarantee that no collisions between objects will ever happen.

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"

View File

@ -10,7 +10,7 @@
#include "cache.h" #include "cache.h"
#include "csum-file.h" #include "csum-file.h"
static int sha1flush(struct sha1file *f, unsigned int count) static void sha1flush(struct sha1file *f, unsigned int count)
{ {
void *buf = f->buffer; void *buf = f->buffer;
@ -21,7 +21,7 @@ static int sha1flush(struct sha1file *f, unsigned int count)
count -= ret; count -= ret;
if (count) if (count)
continue; continue;
return 0; return;
} }
if (!ret) if (!ret)
die("sha1 file '%s' write error. Out of diskspace", f->name); die("sha1 file '%s' write error. Out of diskspace", f->name);

201
diff.c
View File

@ -358,12 +358,152 @@ static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one)
return 0; return 0;
} }
struct diff_words_buffer {
mmfile_t text;
long alloc;
long current; /* output pointer */
int suppressed_newline;
};
static void diff_words_append(char *line, unsigned long len,
struct diff_words_buffer *buffer)
{
if (buffer->text.size + len > buffer->alloc) {
buffer->alloc = (buffer->text.size + len) * 3 / 2;
buffer->text.ptr = xrealloc(buffer->text.ptr, buffer->alloc);
}
line++;
len--;
memcpy(buffer->text.ptr + buffer->text.size, line, len);
buffer->text.size += len;
}
struct diff_words_data {
struct xdiff_emit_state xm;
struct diff_words_buffer minus, plus;
};
static void print_word(struct diff_words_buffer *buffer, int len, int color,
int suppress_newline)
{
const char *ptr;
int eol = 0;
if (len == 0)
return;
ptr = buffer->text.ptr + buffer->current;
buffer->current += len;
if (ptr[len - 1] == '\n') {
eol = 1;
len--;
}
fputs(diff_get_color(1, color), stdout);
fwrite(ptr, len, 1, stdout);
fputs(diff_get_color(1, DIFF_RESET), stdout);
if (eol) {
if (suppress_newline)
buffer->suppressed_newline = 1;
else
putchar('\n');
}
}
static void fn_out_diff_words_aux(void *priv, char *line, unsigned long len)
{
struct diff_words_data *diff_words = priv;
if (diff_words->minus.suppressed_newline) {
if (line[0] != '+')
putchar('\n');
diff_words->minus.suppressed_newline = 0;
}
len--;
switch (line[0]) {
case '-':
print_word(&diff_words->minus, len, DIFF_FILE_OLD, 1);
break;
case '+':
print_word(&diff_words->plus, len, DIFF_FILE_NEW, 0);
break;
case ' ':
print_word(&diff_words->plus, len, DIFF_PLAIN, 0);
diff_words->minus.current += len;
break;
}
}
/* this executes the word diff on the accumulated buffers */
static void diff_words_show(struct diff_words_data *diff_words)
{
xpparam_t xpp;
xdemitconf_t xecfg;
xdemitcb_t ecb;
mmfile_t minus, plus;
int i;
minus.size = diff_words->minus.text.size;
minus.ptr = xmalloc(minus.size);
memcpy(minus.ptr, diff_words->minus.text.ptr, minus.size);
for (i = 0; i < minus.size; i++)
if (isspace(minus.ptr[i]))
minus.ptr[i] = '\n';
diff_words->minus.current = 0;
plus.size = diff_words->plus.text.size;
plus.ptr = xmalloc(plus.size);
memcpy(plus.ptr, diff_words->plus.text.ptr, plus.size);
for (i = 0; i < plus.size; i++)
if (isspace(plus.ptr[i]))
plus.ptr[i] = '\n';
diff_words->plus.current = 0;
xpp.flags = XDF_NEED_MINIMAL;
xecfg.ctxlen = diff_words->minus.alloc + diff_words->plus.alloc;
xecfg.flags = 0;
ecb.outf = xdiff_outf;
ecb.priv = diff_words;
diff_words->xm.consume = fn_out_diff_words_aux;
xdl_diff(&minus, &plus, &xpp, &xecfg, &ecb);
free(minus.ptr);
free(plus.ptr);
diff_words->minus.text.size = diff_words->plus.text.size = 0;
if (diff_words->minus.suppressed_newline) {
putchar('\n');
diff_words->minus.suppressed_newline = 0;
}
}
struct emit_callback { struct emit_callback {
struct xdiff_emit_state xm; struct xdiff_emit_state xm;
int nparents, color_diff; int nparents, color_diff;
const char **label_path; const char **label_path;
struct diff_words_data *diff_words;
}; };
static void free_diff_words_data(struct emit_callback *ecbdata)
{
if (ecbdata->diff_words) {
/* flush buffers */
if (ecbdata->diff_words->minus.text.size ||
ecbdata->diff_words->plus.text.size)
diff_words_show(ecbdata->diff_words);
if (ecbdata->diff_words->minus.text.ptr)
free (ecbdata->diff_words->minus.text.ptr);
if (ecbdata->diff_words->plus.text.ptr)
free (ecbdata->diff_words->plus.text.ptr);
free(ecbdata->diff_words);
ecbdata->diff_words = NULL;
}
}
const char *diff_get_color(int diff_use_color, enum color_diff ix) const char *diff_get_color(int diff_use_color, enum color_diff ix)
{ {
if (diff_use_color) if (diff_use_color)
@ -398,12 +538,31 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
else { else {
int nparents = ecbdata->nparents; int nparents = ecbdata->nparents;
int color = DIFF_PLAIN; int color = DIFF_PLAIN;
for (i = 0; i < nparents && len; i++) { if (ecbdata->diff_words && nparents != 1)
if (line[i] == '-') /* fall back to normal diff */
color = DIFF_FILE_OLD; free_diff_words_data(ecbdata);
else if (line[i] == '+') if (ecbdata->diff_words) {
color = DIFF_FILE_NEW; if (line[0] == '-') {
} diff_words_append(line, len,
&ecbdata->diff_words->minus);
return;
} else if (line[0] == '+') {
diff_words_append(line, len,
&ecbdata->diff_words->plus);
return;
}
if (ecbdata->diff_words->minus.text.size ||
ecbdata->diff_words->plus.text.size)
diff_words_show(ecbdata->diff_words);
line++;
len--;
} else
for (i = 0; i < nparents && len; i++) {
if (line[i] == '-')
color = DIFF_FILE_OLD;
else if (line[i] == '+')
color = DIFF_FILE_NEW;
}
set = diff_get_color(ecbdata->color_diff, color); set = diff_get_color(ecbdata->color_diff, color);
} }
if (len > 0 && line[len-1] == '\n') if (len > 0 && line[len-1] == '\n')
@ -745,9 +904,7 @@ static int mmfile_is_binary(mmfile_t *mf)
long sz = mf->size; long sz = mf->size;
if (FIRST_FEW_BYTES < sz) if (FIRST_FEW_BYTES < sz)
sz = FIRST_FEW_BYTES; sz = FIRST_FEW_BYTES;
if (memchr(mf->ptr, 0, sz)) return !!memchr(mf->ptr, 0, sz);
return 1;
return 0;
} }
static void builtin_diff(const char *name_a, static void builtin_diff(const char *name_a,
@ -836,7 +993,12 @@ static void builtin_diff(const char *name_a,
ecb.outf = xdiff_outf; ecb.outf = xdiff_outf;
ecb.priv = &ecbdata; ecb.priv = &ecbdata;
ecbdata.xm.consume = fn_out_consume; ecbdata.xm.consume = fn_out_consume;
if (o->color_diff_words)
ecbdata.diff_words =
xcalloc(1, sizeof(struct diff_words_data));
xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb); xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
if (o->color_diff_words)
free_diff_words_data(&ecbdata);
} }
free_ab_and_return: free_ab_and_return:
@ -1515,10 +1677,21 @@ 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 && int count = 0;
options->detect_rename != DIFF_DETECT_COPY) ||
(0 <= options->rename_limit && !options->detect_rename)) if (options->output_format & DIFF_FORMAT_NAME)
return -1; count++;
if (options->output_format & DIFF_FORMAT_NAME_STATUS)
count++;
if (options->output_format & DIFF_FORMAT_CHECKDIFF)
count++;
if (options->output_format & DIFF_FORMAT_NO_OUTPUT)
count++;
if (count > 1)
die("--name-only, --name-status, --check and -s are mutually exclusive");
if (options->find_copies_harder)
options->detect_rename = DIFF_DETECT_COPY;
if (options->output_format & (DIFF_FORMAT_NAME | if (options->output_format & (DIFF_FORMAT_NAME |
DIFF_FORMAT_NAME_STATUS | DIFF_FORMAT_NAME_STATUS |
@ -1699,6 +1872,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
options->xdl_opts |= XDF_IGNORE_WHITESPACE; options->xdl_opts |= XDF_IGNORE_WHITESPACE;
else if (!strcmp(arg, "-b") || !strcmp(arg, "--ignore-space-change")) else if (!strcmp(arg, "-b") || !strcmp(arg, "--ignore-space-change"))
options->xdl_opts |= XDF_IGNORE_WHITESPACE_CHANGE; options->xdl_opts |= XDF_IGNORE_WHITESPACE_CHANGE;
else if (!strcmp(arg, "--color-words"))
options->color_diff = options->color_diff_words = 1;
else if (!strcmp(arg, "--no-renames")) else if (!strcmp(arg, "--no-renames"))
options->detect_rename = 0; options->detect_rename = 0;
else else

3
diff.h
View File

@ -46,7 +46,8 @@ struct diff_options {
full_index:1, full_index:1,
silent_on_remove:1, silent_on_remove:1,
find_copies_harder:1, find_copies_harder:1,
color_diff:1; color_diff:1,
color_diff_words:1;
int context; int context;
int break_opt; int break_opt;
int detect_rename; int detect_rename;

View File

@ -366,13 +366,13 @@ static void add_sha1_list(unsigned char *sha1, unsigned long ino)
sha1_list.nr = ++nr; sha1_list.nr = ++nr;
} }
static int fsck_dir(int i, char *path) static void fsck_dir(int i, char *path)
{ {
DIR *dir = opendir(path); DIR *dir = opendir(path);
struct dirent *de; struct dirent *de;
if (!dir) if (!dir)
return 0; return;
while ((de = readdir(dir)) != NULL) { while ((de = readdir(dir)) != NULL) {
char name[100]; char name[100];
@ -398,7 +398,6 @@ static int fsck_dir(int i, char *path)
fprintf(stderr, "bad sha1 file: %s/%s\n", path, de->d_name); fprintf(stderr, "bad sha1 file: %s/%s\n", path, de->d_name);
} }
closedir(dir); closedir(dir);
return 0;
} }
static int default_refs = 0; static int default_refs = 0;

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

@ -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

@ -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 || [] }
} }

88
git.c
View File

@ -213,8 +213,8 @@ 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 RUN_SETUP (1<<0)
#define USE_PAGER 2 #define USE_PAGER (1<<1)
static void handle_internal_command(int argc, const char **argv, char **envp) static void handle_internal_command(int argc, const char **argv, char **envp)
{ {
@ -224,47 +224,53 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
int (*fn)(int, const char **, const char *); int (*fn)(int, const char **, const char *);
int option; int option;
} commands[] = { } commands[] = {
{ "version", cmd_version }, { "add", cmd_add, RUN_SETUP },
{ "help", cmd_help },
{ "log", cmd_log, NEEDS_PREFIX | USE_PAGER },
{ "whatchanged", cmd_whatchanged, NEEDS_PREFIX | USE_PAGER },
{ "show", cmd_show, NEEDS_PREFIX | USE_PAGER },
{ "push", cmd_push },
{ "format-patch", cmd_format_patch, NEEDS_PREFIX },
{ "count-objects", cmd_count_objects },
{ "diff", cmd_diff, NEEDS_PREFIX },
{ "grep", cmd_grep, NEEDS_PREFIX },
{ "rm", cmd_rm, NEEDS_PREFIX },
{ "add", cmd_add, NEEDS_PREFIX },
{ "rev-list", cmd_rev_list, NEEDS_PREFIX },
{ "init-db", cmd_init_db },
{ "get-tar-commit-id", cmd_get_tar_commit_id },
{ "upload-tar", cmd_upload_tar },
{ "check-ref-format", cmd_check_ref_format },
{ "ls-files", cmd_ls_files, NEEDS_PREFIX },
{ "ls-tree", cmd_ls_tree, NEEDS_PREFIX },
{ "tar-tree", cmd_tar_tree, NEEDS_PREFIX },
{ "read-tree", cmd_read_tree, NEEDS_PREFIX },
{ "commit-tree", cmd_commit_tree, NEEDS_PREFIX },
{ "apply", cmd_apply }, { "apply", cmd_apply },
{ "show-branch", cmd_show_branch, NEEDS_PREFIX }, { "cat-file", cmd_cat_file, RUN_SETUP },
{ "diff-files", cmd_diff_files, NEEDS_PREFIX }, { "checkout-index", cmd_checkout_index, RUN_SETUP },
{ "diff-index", cmd_diff_index, NEEDS_PREFIX }, { "check-ref-format", cmd_check_ref_format },
{ "diff-stages", cmd_diff_stages, NEEDS_PREFIX }, { "commit-tree", cmd_commit_tree, RUN_SETUP },
{ "diff-tree", cmd_diff_tree, NEEDS_PREFIX }, { "count-objects", cmd_count_objects },
{ "cat-file", cmd_cat_file, NEEDS_PREFIX }, { "diff", cmd_diff, RUN_SETUP },
{ "rev-parse", cmd_rev_parse, NEEDS_PREFIX }, { "diff-files", cmd_diff_files, RUN_SETUP },
{ "write-tree", cmd_write_tree, NEEDS_PREFIX }, { "diff-index", cmd_diff_index, RUN_SETUP },
{ "mailsplit", cmd_mailsplit }, { "diff-stages", cmd_diff_stages, RUN_SETUP },
{ "diff-tree", cmd_diff_tree, RUN_SETUP },
{ "fmt-merge-msg", cmd_fmt_merge_msg, RUN_SETUP },
{ "format-patch", cmd_format_patch, RUN_SETUP },
{ "get-tar-commit-id", cmd_get_tar_commit_id },
{ "grep", cmd_grep, RUN_SETUP },
{ "help", cmd_help },
{ "init-db", cmd_init_db },
{ "log", cmd_log, RUN_SETUP | USE_PAGER },
{ "ls-files", cmd_ls_files, RUN_SETUP },
{ "ls-tree", cmd_ls_tree, RUN_SETUP },
{ "mailinfo", cmd_mailinfo }, { "mailinfo", cmd_mailinfo },
{ "stripspace", cmd_stripspace }, { "mailsplit", cmd_mailsplit },
{ "update-index", cmd_update_index, NEEDS_PREFIX }, { "mv", cmd_mv, RUN_SETUP },
{ "update-ref", cmd_update_ref, NEEDS_PREFIX }, { "name-rev", cmd_name_rev, RUN_SETUP },
{ "fmt-merge-msg", cmd_fmt_merge_msg, NEEDS_PREFIX }, { "pack-objects", cmd_pack_objects, RUN_SETUP },
{ "prune", cmd_prune, NEEDS_PREFIX }, { "prune", cmd_prune, RUN_SETUP },
{ "mv", cmd_mv, NEEDS_PREFIX }, { "prune-packed", cmd_prune_packed, RUN_SETUP },
{ "prune-packed", cmd_prune_packed, NEEDS_PREFIX }, { "push", cmd_push, RUN_SETUP },
{ "read-tree", cmd_read_tree, RUN_SETUP },
{ "repo-config", cmd_repo_config }, { "repo-config", cmd_repo_config },
{ "rev-list", cmd_rev_list, RUN_SETUP },
{ "rev-parse", cmd_rev_parse, RUN_SETUP },
{ "rm", cmd_rm, RUN_SETUP },
{ "show-branch", cmd_show_branch, RUN_SETUP },
{ "show", cmd_show, RUN_SETUP | USE_PAGER },
{ "stripspace", cmd_stripspace },
{ "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
{ "tar-tree", cmd_tar_tree, RUN_SETUP },
{ "unpack-objects", cmd_unpack_objects, RUN_SETUP },
{ "update-index", cmd_update_index, RUN_SETUP },
{ "update-ref", cmd_update_ref, RUN_SETUP },
{ "upload-tar", cmd_upload_tar },
{ "version", cmd_version },
{ "whatchanged", cmd_whatchanged, RUN_SETUP | USE_PAGER },
{ "write-tree", cmd_write_tree, RUN_SETUP },
{ "verify-pack", cmd_verify_pack },
}; };
int i; int i;
@ -281,7 +287,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
continue; continue;
prefix = NULL; prefix = NULL;
if (p->option & NEEDS_PREFIX) if (p->option & RUN_SETUP)
prefix = setup_git_directory(); prefix = setup_git_directory();
if (p->option & USE_PAGER) if (p->option & USE_PAGER)
setup_pager(); setup_pager();

147
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
} }
@ -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

@ -5,5 +5,33 @@ The one working on:
From the git version 1.4.0 gitweb is bundled with git. From the git version 1.4.0 gitweb is bundled with git.
Any comment/question/concern to:
How to configure gitweb for your local system:
You can specify the following configuration variables when building GIT:
* GITWEB_SITENAME
Shown in the title of all generated pages, defaults to the servers name.
* GITWEB_PROJECTROOT
The root directory for all projects shown by gitweb.
* GITWEB_LIST
points to a directory to scan for projects (defaults to project root)
or to a file for explicit listing of projects.
* GITWEB_HOMETEXT
points to an .html file which is included on the gitweb project
overview page.
* GITWEB_CSS
Points to the location where you put gitweb.css on your web server.
* GITWEB_LOGO
Points to the location where you put git-logo.png on your web server.
* GITWEB_CONFIG
This file will be loaded using 'require'. If the environment
$GITWEB_CONFIG is set when gitweb.cgi is executed the file in the
environment variable will be loaded instead of the file
specified when gitweb.cgi was created.
Originally written by:
Kay Sievers <kay.sievers@vrfy.org> Kay Sievers <kay.sievers@vrfy.org>
Any comment/question/concern to:
Git mailing list <git@vger.kernel.org>

BIN
gitweb/git-logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 B

View File

@ -117,9 +117,14 @@ div.list_head {
a.list { a.list {
text-decoration: none; text-decoration: none;
font-weight: bold;
color: #000000; color: #000000;
} }
table.tags a.list {
font-weight: normal;
}
a.list:hover { a.list:hover {
text-decoration: underline; text-decoration: underline;
color: #880000; color: #880000;
@ -171,6 +176,10 @@ tr.dark {
background-color: #f6f6f0; background-color: #f6f6f0;
} }
tr.dark2 {
background-color: #f6f6f0;
}
tr.dark:hover { tr.dark:hover {
background-color: #edece6; background-color: #edece6;
} }
@ -181,12 +190,16 @@ td {
vertical-align: top; vertical-align: top;
} }
td.link { td.link, td.selflink {
padding: 2px 5px; padding: 2px 5px;
font-family: sans-serif; font-family: sans-serif;
font-size: 10px; font-size: 10px;
} }
td.selflink {
padding-right: 0px;
}
td.sha1 { td.sha1 {
font-family: monospace; font-family: monospace;
} }
@ -196,6 +209,10 @@ td.error {
background-color: yellow; background-color: yellow;
} }
td.current_head {
text-decoration: underline;
}
table.diff_tree span.file_status.new { table.diff_tree span.file_status.new {
color: #008000; color: #008000;
} }
@ -209,6 +226,10 @@ table.diff_tree span.file_status.mode_chnge {
color: #777777; color: #777777;
} }
table.diff_tree span.file_status.copied {
color: #70a070;
}
/* age2: 60*60*24*2 <= age */ /* age2: 60*60*24*2 <= age */
table.project_list td.age2, table.blame td.age2 { table.project_list td.age2, table.blame td.age2 {
font-style: italic; font-style: italic;
@ -309,15 +330,30 @@ a.rss_logo:hover {
background-color: #ee5500; background-color: #ee5500;
} }
span.tag { span.refs span {
padding: 0px 4px; padding: 0px 4px;
font-size: 10px; font-size: 10px;
font-weight: normal; font-weight: normal;
background-color: #ffffaa;
border: 1px solid; border: 1px solid;
background-color: #ffaaff;
border-color: #ffccff #ff00ee #ff00ee #ffccff;
}
span.refs span.ref {
background-color: #aaaaff;
border-color: #ccccff #0033cc #0033cc #ccccff;
}
span.refs span.tag {
background-color: #ffffaa;
border-color: #ffffcc #ffee00 #ffee00 #ffffcc; border-color: #ffffcc #ffee00 #ffee00 #ffffcc;
} }
span.refs span.head {
background-color: #aaffaa;
border-color: #ccffcc #00cc33 #00cc33 #ccffcc;
}
span.atnight { span.atnight {
color: #cc0000; color: #cc0000;
} }

File diff suppressed because it is too large Load Diff

View File

@ -140,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)

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);
} }

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();
@ -2182,49 +2182,11 @@ static void fetch_symref(const char *path, char **symref, unsigned char *sha1)
static int verify_merge_base(unsigned char *head_sha1, unsigned char *branch_sha1) static int verify_merge_base(unsigned char *head_sha1, unsigned char *branch_sha1)
{ {
int pipe_fd[2]; struct commit *head = lookup_commit(head_sha1);
pid_t merge_base_pid; struct commit *branch = lookup_commit(branch_sha1);
char line[PATH_MAX + 20]; struct commit_list *merge_bases = get_merge_bases(head, branch, 1);
unsigned char merge_sha1[20];
int verified = 0;
if (pipe(pipe_fd) < 0) return (merge_bases && !merge_bases->next && merge_bases->item == branch);
die("Verify merge base: pipe failed");
merge_base_pid = fork();
if (!merge_base_pid) {
static const char *args[] = {
"merge-base",
"-a",
NULL,
NULL,
NULL
};
args[2] = strdup(sha1_to_hex(head_sha1));
args[3] = sha1_to_hex(branch_sha1);
dup2(pipe_fd[1], 1);
close(pipe_fd[0]);
close(pipe_fd[1]);
execv_git_cmd(args);
die("merge-base setup failed");
}
if (merge_base_pid < 0)
die("merge-base fork failed");
dup2(pipe_fd[0], 0);
close(pipe_fd[0]);
close(pipe_fd[1]);
while (fgets(line, sizeof(line), stdin) != NULL) {
if (get_sha1_hex(line, merge_sha1))
die("expected sha1, got garbage:\n %s", line);
if (!memcmp(branch_sha1, merge_sha1, 20)) {
verified = 1;
break;
}
}
return verified;
} }
static int delete_remote_branch(char *pattern, int force) static int delete_remote_branch(char *pattern, int force)

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

@ -44,7 +44,7 @@ static int setup_indices(void)
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);

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

@ -15,10 +15,12 @@ void setup_pager(void)
{ {
pid_t pid; pid_t pid;
int fd[2]; int fd[2];
const char *pager = getenv("PAGER"); const char *pager = getenv("GIT_PAGER");
if (!isatty(1)) if (!isatty(1))
return; return;
if (!pager)
pager = getenv("PAGER");
if (!pager) if (!pager)
pager = "less"; pager = "less";
else if (!*pager || !strcmp(pager, "cat")) else if (!*pager || !strcmp(pager, "cat"))

View File

@ -5,6 +5,7 @@
*/ */
#include "cache.h" #include "cache.h"
#include "cache-tree.h" #include "cache-tree.h"
#include <time.h>
/* Index extensions. /* Index extensions.
* *
@ -840,6 +841,18 @@ unmap:
static unsigned char write_buffer[WRITE_BUFFER_SIZE]; static unsigned char write_buffer[WRITE_BUFFER_SIZE];
static unsigned long write_buffer_len; static unsigned long write_buffer_len;
static int ce_write_flush(SHA_CTX *context, int fd)
{
unsigned int buffered = write_buffer_len;
if (buffered) {
SHA1_Update(context, write_buffer, buffered);
if (write(fd, write_buffer, buffered) != buffered)
return -1;
write_buffer_len = 0;
}
return 0;
}
static int ce_write(SHA_CTX *context, int fd, void *data, unsigned int len) static int ce_write(SHA_CTX *context, int fd, void *data, unsigned int len)
{ {
while (len) { while (len) {
@ -850,8 +863,8 @@ static int ce_write(SHA_CTX *context, int fd, void *data, unsigned int len)
memcpy(write_buffer + buffered, data, partial); memcpy(write_buffer + buffered, data, partial);
buffered += partial; buffered += partial;
if (buffered == WRITE_BUFFER_SIZE) { if (buffered == WRITE_BUFFER_SIZE) {
SHA1_Update(context, write_buffer, WRITE_BUFFER_SIZE); write_buffer_len = buffered;
if (write(fd, write_buffer, WRITE_BUFFER_SIZE) != WRITE_BUFFER_SIZE) if (ce_write_flush(context, fd))
return -1; return -1;
buffered = 0; buffered = 0;
} }
@ -867,10 +880,8 @@ static int write_index_ext_header(SHA_CTX *context, int fd,
{ {
ext = htonl(ext); ext = htonl(ext);
sz = htonl(sz); sz = htonl(sz);
if ((ce_write(context, fd, &ext, 4) < 0) || return ((ce_write(context, fd, &ext, 4) < 0) ||
(ce_write(context, fd, &sz, 4) < 0)) (ce_write(context, fd, &sz, 4) < 0)) ? -1 : 0;
return -1;
return 0;
} }
static int ce_flush(SHA_CTX *context, int fd) static int ce_flush(SHA_CTX *context, int fd)
@ -892,9 +903,7 @@ static int ce_flush(SHA_CTX *context, int fd)
/* Append the SHA1 signature at the end */ /* Append the SHA1 signature at the end */
SHA1_Final(write_buffer + left, context); SHA1_Final(write_buffer + left, context);
left += 20; left += 20;
if (write(fd, write_buffer, left) != left) return (write(fd, write_buffer, left) != left) ? -1 : 0;
return -1;
return 0;
} }
static void ce_smudge_racily_clean_entry(struct cache_entry *ce) static void ce_smudge_racily_clean_entry(struct cache_entry *ce)
@ -923,7 +932,7 @@ static void ce_smudge_racily_clean_entry(struct cache_entry *ce)
* $ echo filfre >nitfol * $ echo filfre >nitfol
* $ git-update-index --add nitfol * $ git-update-index --add nitfol
* *
* but it does not. Whe the second update-index runs, * but it does not. When the second update-index runs,
* it notices that the entry "frotz" has the same timestamp * it notices that the entry "frotz" has the same timestamp
* as index, and if we were to smudge it by resetting its * as index, and if we were to smudge it by resetting its
* size to zero here, then the object name recorded * size to zero here, then the object name recorded
@ -945,7 +954,9 @@ int write_cache(int newfd, struct cache_entry **cache, int entries)
{ {
SHA_CTX c; SHA_CTX c;
struct cache_header hdr; struct cache_header hdr;
int i, removed; int i, removed, recent;
struct stat st;
time_t now;
for (i = removed = 0; i < entries; i++) for (i = removed = 0; i < entries; i++)
if (!cache[i]->ce_mode) if (!cache[i]->ce_mode)
@ -983,5 +994,57 @@ int write_cache(int newfd, struct cache_entry **cache, int entries)
return -1; return -1;
} }
} }
/*
* To prevent later ce_match_stat() from always falling into
* check_fs(), if we have too many entries that can trigger
* racily clean check, we are better off delaying the return.
* We arbitrarily say if more than 20 paths or 25% of total
* paths are very new, we delay the return until the index
* file gets a new timestamp.
*
* NOTE! NOTE! NOTE!
*
* This assumes that nobody is touching the working tree while
* we are updating the index.
*/
/* Make sure that the new index file has st_mtime
* that is current enough -- ce_write() batches the data
* so it might not have written anything yet.
*/
ce_write_flush(&c, newfd);
now = fstat(newfd, &st) ? 0 : st.st_mtime;
if (now) {
recent = 0;
for (i = 0; i < entries; i++) {
struct cache_entry *ce = cache[i];
time_t entry_time = (time_t) ntohl(ce->ce_mtime.sec);
if (!ce->ce_mode)
continue;
if (now && now <= entry_time)
recent++;
}
if (20 < recent && entries <= recent * 4) {
#if 0
fprintf(stderr, "entries %d\n", entries);
fprintf(stderr, "recent %d\n", recent);
fprintf(stderr, "now %lu\n", now);
#endif
while (!fstat(newfd, &st) && st.st_mtime <= now) {
struct timespec rq, rm;
off_t where = lseek(newfd, 0, SEEK_CUR);
rq.tv_sec = 0;
rq.tv_nsec = 250000000;
nanosleep(&rq, &rm);
if ((where == (off_t) -1) ||
(write(newfd, "", 1) != 1) ||
(lseek(newfd, -1, SEEK_CUR) != where) ||
ftruncate(newfd, where))
break;
}
}
}
return ce_flush(&c, newfd); return ce_flush(&c, newfd);
} }

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

@ -111,7 +111,7 @@ static void rev_list(int fd, struct ref *refs)
exec_rev_list(refs); exec_rev_list(refs);
} }
static int pack_objects(int fd, struct ref *refs) static void pack_objects(int fd, struct ref *refs)
{ {
pid_t rev_list_pid; pid_t rev_list_pid;
@ -126,7 +126,6 @@ static int pack_objects(int fd, struct ref *refs)
* We don't wait for the rev-list pipeline in the parent: * We don't wait for the rev-list pipeline in the parent:
* we end up waiting for the other end instead * we end up waiting for the other end instead
*/ */
return 0;
} }
static void unmark_and_free(struct commit_list *list, unsigned int mark) static void unmark_and_free(struct commit_list *list, unsigned int mark)

View File

@ -608,7 +608,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? */
@ -664,8 +664,7 @@ int check_sha1_signature(const unsigned char *sha1, void *map, unsigned long siz
return memcmp(sha1, real_sha1, 20) ? -1 : 0; return memcmp(sha1, real_sha1, 20) ? -1 : 0;
} }
static void *map_sha1_file_internal(const unsigned char *sha1, void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
unsigned long *size)
{ {
struct stat st; struct stat st;
void *map; void *map;
@ -702,10 +701,26 @@ static void *map_sha1_file_internal(const unsigned char *sha1,
return map; return map;
} }
int legacy_loose_object(unsigned char *map)
{
unsigned int word;
/*
* Is it a zlib-compressed buffer? If so, the first byte
* must be 0x78 (15-bit window size, deflated), and the
* first 16-bit word is evenly divisible by 31
*/
word = (map[0] << 8) + map[1];
if (map[0] == 0x78 && !(word % 31))
return 1;
else
return 0;
}
static int unpack_sha1_header(z_stream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz) static int unpack_sha1_header(z_stream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz)
{ {
unsigned char c; unsigned char c;
unsigned int word, bits; unsigned int bits;
unsigned long size; unsigned long size;
static const char *typename[8] = { static const char *typename[8] = {
NULL, /* OBJ_EXT */ NULL, /* OBJ_EXT */
@ -721,13 +736,7 @@ static int unpack_sha1_header(z_stream *stream, unsigned char *map, unsigned lon
stream->next_out = buffer; stream->next_out = buffer;
stream->avail_out = bufsiz; stream->avail_out = bufsiz;
/* if (legacy_loose_object(map)) {
* Is it a zlib-compressed buffer? If so, the first byte
* must be 0x78 (15-bit window size, deflated), and the
* first 16-bit word is evenly divisible by 31
*/
word = (map[0] << 8) + map[1];
if (map[0] == 0x78 && !(word % 31)) {
inflateInit(stream); inflateInit(stream);
return inflate(stream, 0); return inflate(stream, 0);
} }
@ -1264,7 +1273,7 @@ int sha1_object_info(const unsigned char *sha1, char *type, unsigned long *sizep
z_stream stream; z_stream stream;
char hdr[128]; char hdr[128];
map = map_sha1_file_internal(sha1, &mapsize); map = map_sha1_file(sha1, &mapsize);
if (!map) { if (!map) {
struct pack_entry e; struct pack_entry e;
@ -1309,7 +1318,7 @@ void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size
if (find_pack_entry(sha1, &e)) if (find_pack_entry(sha1, &e))
return read_packed_sha1(sha1, type, size); return read_packed_sha1(sha1, type, size);
map = map_sha1_file_internal(sha1, &mapsize); map = map_sha1_file(sha1, &mapsize);
if (map) { if (map) {
buf = unpack_sha1_file(map, mapsize, type, size); buf = unpack_sha1_file(map, mapsize, type, size);
munmap(map, mapsize); munmap(map, mapsize);
@ -1647,7 +1656,7 @@ int write_sha1_to_fd(int fd, const unsigned char *sha1)
{ {
int retval; int retval;
unsigned long objsize; unsigned long objsize;
void *buf = map_sha1_file_internal(sha1, &objsize); void *buf = map_sha1_file(sha1, &objsize);
if (buf) { if (buf) {
retval = write_buffer(fd, buf, objsize); retval = write_buffer(fd, buf, objsize);

View File

@ -199,7 +199,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

@ -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

46
t/t4116-apply-reverse.sh Executable file
View File

@ -0,0 +1,46 @@
#!/bin/sh
#
# Copyright (c) 2005 Junio C Hamano
#
test_description='git-apply in reverse
'
. ./test-lib.sh
test_expect_success setup '
for i in a b c d e f g h i j k l m n; do echo $i; done >file1 &&
tr "[ijk]" '\''[\0\1\2]'\'' <file1 >file2 &&
git add file1 file2 &&
git commit -m initial &&
git tag initial &&
for i in a b c g h i J K L m o n p q; do echo $i; done >file1 &&
tr "[mon]" '\''[\0\1\2]'\'' <file1 >file2 &&
git commit -a -m second &&
git diff --binary -R initial >patch
'
test_expect_success 'apply in forward' '
git apply --index --binary patch &&
git diff initial >diff &&
diff -u /dev/null diff
'
test_expect_success 'apply in reverse' '
git apply --reverse --binary --index patch &&
git diff >diff &&
diff -u /dev/null diff
'
test_done

View File

@ -3,7 +3,7 @@
# Copyright (c) 2006 Junio C Hamano # Copyright (c) 2006 Junio C Hamano
# #
test_description='git grep -w test_description='git grep various.
' '
. ./test-lib.sh . ./test-lib.sh
@ -19,7 +19,9 @@ test_expect_success setup '
echo x x xx x >x && echo x x xx x >x &&
echo y yy >y && echo y yy >y &&
echo zzz > z && echo zzz > z &&
git add file x y z && mkdir t &&
echo test >t/t &&
git add file x y z t/t &&
git commit -m initial git commit -m initial
' '
@ -80,6 +82,31 @@ do
diff expected actual diff expected actual
fi fi
' '
test_expect_success "grep $L (t-1)" '
echo "${HC}t/t:1:test" >expected &&
git grep -n -e test $H >actual &&
diff expected actual
'
test_expect_success "grep $L (t-2)" '
echo "${HC}t:1:test" >expected &&
(
cd t &&
git grep -n -e test $H
) >actual &&
diff expected actual
'
test_expect_success "grep $L (t-3)" '
echo "${HC}t/t:1:test" >expected &&
(
cd t &&
git grep --full-name -n -e test $H
) >actual &&
diff expected actual
'
done done
test_done test_done

View File

@ -11,4 +11,8 @@
# This example catches duplicate Signed-off-by lines. # This example catches duplicate Signed-off-by lines.
test "" = "$(grep '^Signed-off-by: ' "$1" | test "" = "$(grep '^Signed-off-by: ' "$1" |
sort | uniq -c | sed -e '/^[ ]*1 /d')" sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
echo >&2 Duplicate Signed-off-by lines.
exit 1
}

View File

@ -15,7 +15,8 @@ static char *malloc_base(const char *base, const char *path, int pathlen)
return newbase; return newbase;
} }
static int show_entry(struct diff_options *opt, const char *prefix, struct tree_desc *desc, const char *base); static void show_entry(struct diff_options *opt, const char *prefix, struct tree_desc *desc,
const char *base);
static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const char *base, struct diff_options *opt) static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const char *base, struct diff_options *opt)
{ {
@ -131,7 +132,8 @@ static void show_tree(struct diff_options *opt, const char *prefix, struct tree_
} }
/* A file entry went away or appeared */ /* A file entry went away or appeared */
static int show_entry(struct diff_options *opt, const char *prefix, struct tree_desc *desc, const char *base) static void show_entry(struct diff_options *opt, const char *prefix, struct tree_desc *desc,
const char *base)
{ {
unsigned mode; unsigned mode;
const char *path; const char *path;
@ -152,11 +154,9 @@ static int show_entry(struct diff_options *opt, const char *prefix, struct tree_
free(tree); free(tree);
free(newbase); free(newbase);
return 0; } else {
opt->add_remove(opt, prefix[0], mode, sha1, base, path);
} }
opt->add_remove(opt, prefix[0], mode, sha1, base, path);
return 0;
} }
int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, struct diff_options *opt) int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, struct diff_options *opt)

3
tree.c
View File

@ -144,7 +144,7 @@ struct tree *lookup_tree(const unsigned char *sha1)
return (struct tree *) obj; return (struct tree *) obj;
} }
static int track_tree_refs(struct tree *item) static void track_tree_refs(struct tree *item)
{ {
int n_refs = 0, i; int n_refs = 0, i;
struct object_refs *refs; struct object_refs *refs;
@ -174,7 +174,6 @@ static int track_tree_refs(struct tree *item)
refs->ref[i++] = obj; refs->ref[i++] = obj;
} }
set_object_refs(&item->object, refs); set_object_refs(&item->object, refs);
return 0;
} }
int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size) int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size)

799
unpack-trees.c Normal file
View File

@ -0,0 +1,799 @@
#include <signal.h>
#include <sys/time.h>
#include "cache.h"
#include "tree.h"
#include "tree-walk.h"
#include "cache-tree.h"
#include "unpack-trees.h"
#define DBRT_DEBUG 1
struct tree_entry_list {
struct tree_entry_list *next;
unsigned directory : 1;
unsigned executable : 1;
unsigned symlink : 1;
unsigned int mode;
const char *name;
const unsigned char *sha1;
};
static struct tree_entry_list *create_tree_entry_list(struct tree *tree)
{
struct tree_desc desc;
struct name_entry one;
struct tree_entry_list *ret = NULL;
struct tree_entry_list **list_p = &ret;
if (!tree->object.parsed)
parse_tree(tree);
desc.buf = tree->buffer;
desc.size = tree->size;
while (tree_entry(&desc, &one)) {
struct tree_entry_list *entry;
entry = xmalloc(sizeof(struct tree_entry_list));
entry->name = one.path;
entry->sha1 = one.sha1;
entry->mode = one.mode;
entry->directory = S_ISDIR(one.mode) != 0;
entry->executable = (one.mode & S_IXUSR) != 0;
entry->symlink = S_ISLNK(one.mode) != 0;
entry->next = NULL;
*list_p = entry;
list_p = &entry->next;
}
return ret;
}
static int entcmp(const char *name1, int dir1, const char *name2, int dir2)
{
int len1 = strlen(name1);
int len2 = strlen(name2);
int len = len1 < len2 ? len1 : len2;
int ret = memcmp(name1, name2, len);
unsigned char c1, c2;
if (ret)
return ret;
c1 = name1[len];
c2 = name2[len];
if (!c1 && dir1)
c1 = '/';
if (!c2 && dir2)
c2 = '/';
ret = (c1 < c2) ? -1 : (c1 > c2) ? 1 : 0;
if (c1 && c2 && !ret)
ret = len1 - len2;
return ret;
}
static int unpack_trees_rec(struct tree_entry_list **posns, int len,
const char *base, struct unpack_trees_options *o,
int *indpos,
struct tree_entry_list *df_conflict_list)
{
int baselen = strlen(base);
int src_size = len + 1;
do {
int i;
const char *first;
int firstdir = 0;
int pathlen;
unsigned ce_size;
struct tree_entry_list **subposns;
struct cache_entry **src;
int any_files = 0;
int any_dirs = 0;
char *cache_name;
int ce_stage;
/* Find the first name in the input. */
first = NULL;
cache_name = NULL;
/* Check the cache */
if (o->merge && *indpos < active_nr) {
/* This is a bit tricky: */
/* If the index has a subdirectory (with
* contents) as the first name, it'll get a
* filename like "foo/bar". But that's after
* "foo", so the entry in trees will get
* handled first, at which point we'll go into
* "foo", and deal with "bar" from the index,
* because the base will be "foo/". The only
* way we can actually have "foo/bar" first of
* all the things is if the trees don't
* contain "foo" at all, in which case we'll
* handle "foo/bar" without going into the
* directory, but that's fine (and will return
* an error anyway, with the added unknown
* file case.
*/
cache_name = active_cache[*indpos]->name;
if (strlen(cache_name) > baselen &&
!memcmp(cache_name, base, baselen)) {
cache_name += baselen;
first = cache_name;
} else {
cache_name = NULL;
}
}
#if DBRT_DEBUG > 1
if (first)
printf("index %s\n", first);
#endif
for (i = 0; i < len; i++) {
if (!posns[i] || posns[i] == df_conflict_list)
continue;
#if DBRT_DEBUG > 1
printf("%d %s\n", i + 1, posns[i]->name);
#endif
if (!first || entcmp(first, firstdir,
posns[i]->name,
posns[i]->directory) > 0) {
first = posns[i]->name;
firstdir = posns[i]->directory;
}
}
/* No name means we're done */
if (!first)
return 0;
pathlen = strlen(first);
ce_size = cache_entry_size(baselen + pathlen);
src = xcalloc(src_size, sizeof(struct cache_entry *));
subposns = xcalloc(len, sizeof(struct tree_list_entry *));
if (cache_name && !strcmp(cache_name, first)) {
any_files = 1;
src[0] = active_cache[*indpos];
remove_cache_entry_at(*indpos);
}
for (i = 0; i < len; i++) {
struct cache_entry *ce;
if (!posns[i] ||
(posns[i] != df_conflict_list &&
strcmp(first, posns[i]->name))) {
continue;
}
if (posns[i] == df_conflict_list) {
src[i + o->merge] = o->df_conflict_entry;
continue;
}
if (posns[i]->directory) {
struct tree *tree = lookup_tree(posns[i]->sha1);
any_dirs = 1;
parse_tree(tree);
subposns[i] = create_tree_entry_list(tree);
posns[i] = posns[i]->next;
src[i + o->merge] = o->df_conflict_entry;
continue;
}
if (!o->merge)
ce_stage = 0;
else if (i + 1 < o->head_idx)
ce_stage = 1;
else if (i + 1 > o->head_idx)
ce_stage = 3;
else
ce_stage = 2;
ce = xcalloc(1, ce_size);
ce->ce_mode = create_ce_mode(posns[i]->mode);
ce->ce_flags = create_ce_flags(baselen + pathlen,
ce_stage);
memcpy(ce->name, base, baselen);
memcpy(ce->name + baselen, first, pathlen + 1);
any_files = 1;
memcpy(ce->sha1, posns[i]->sha1, 20);
src[i + o->merge] = ce;
subposns[i] = df_conflict_list;
posns[i] = posns[i]->next;
}
if (any_files) {
if (o->merge) {
int ret;
#if DBRT_DEBUG > 1
printf("%s:\n", first);
for (i = 0; i < src_size; i++) {
printf(" %d ", i);
if (src[i])
printf("%s\n", sha1_to_hex(src[i]->sha1));
else
printf("\n");
}
#endif
ret = o->fn(src, o);
#if DBRT_DEBUG > 1
printf("Added %d entries\n", ret);
#endif
*indpos += ret;
} else {
for (i = 0; i < src_size; i++) {
if (src[i]) {
add_cache_entry(src[i], ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
}
}
}
}
if (any_dirs) {
char *newbase = xmalloc(baselen + 2 + pathlen);
memcpy(newbase, base, baselen);
memcpy(newbase + baselen, first, pathlen);
newbase[baselen + pathlen] = '/';
newbase[baselen + pathlen + 1] = '\0';
if (unpack_trees_rec(subposns, len, newbase, o,
indpos, df_conflict_list))
return -1;
free(newbase);
}
free(subposns);
free(src);
} while (1);
}
/* Unlink the last component and attempt to remove leading
* directories, in case this unlink is the removal of the
* last entry in the directory -- empty directories are removed.
*/
static void unlink_entry(char *name)
{
char *cp, *prev;
if (unlink(name))
return;
prev = NULL;
while (1) {
int status;
cp = strrchr(name, '/');
if (prev)
*prev = '/';
if (!cp)
break;
*cp = 0;
status = rmdir(name);
if (status) {
*cp = '/';
break;
}
prev = cp;
}
}
static volatile int progress_update = 0;
static void progress_interval(int signum)
{
progress_update = 1;
}
static void setup_progress_signal(void)
{
struct sigaction sa;
struct itimerval v;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = progress_interval;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
sigaction(SIGALRM, &sa, NULL);
v.it_interval.tv_sec = 1;
v.it_interval.tv_usec = 0;
v.it_value = v.it_interval;
setitimer(ITIMER_REAL, &v, NULL);
}
static struct checkout state;
static void check_updates(struct cache_entry **src, int nr,
struct unpack_trees_options *o)
{
unsigned short mask = htons(CE_UPDATE);
unsigned last_percent = 200, cnt = 0, total = 0;
if (o->update && o->verbose_update) {
for (total = cnt = 0; cnt < nr; cnt++) {
struct cache_entry *ce = src[cnt];
if (!ce->ce_mode || ce->ce_flags & mask)
total++;
}
/* Don't bother doing this for very small updates */
if (total < 250)
total = 0;
if (total) {
fprintf(stderr, "Checking files out...\n");
setup_progress_signal();
progress_update = 1;
}
cnt = 0;
}
while (nr--) {
struct cache_entry *ce = *src++;
if (total) {
if (!ce->ce_mode || ce->ce_flags & mask) {
unsigned percent;
cnt++;
percent = (cnt * 100) / total;
if (percent != last_percent ||
progress_update) {
fprintf(stderr, "%4u%% (%u/%u) done\r",
percent, cnt, total);
last_percent = percent;
progress_update = 0;
}
}
}
if (!ce->ce_mode) {
if (o->update)
unlink_entry(ce->name);
continue;
}
if (ce->ce_flags & mask) {
ce->ce_flags &= ~mask;
if (o->update)
checkout_entry(ce, &state, NULL);
}
}
if (total) {
signal(SIGALRM, SIG_IGN);
fputc('\n', stderr);
}
}
int unpack_trees(struct object_list *trees, struct unpack_trees_options *o)
{
int indpos = 0;
unsigned len = object_list_length(trees);
struct tree_entry_list **posns;
int i;
struct object_list *posn = trees;
struct tree_entry_list df_conflict_list;
struct cache_entry df_conflict_entry;
memset(&df_conflict_list, 0, sizeof(df_conflict_list));
df_conflict_list.next = &df_conflict_list;
memset(&state, 0, sizeof(state));
state.base_dir = "";
state.force = 1;
state.quiet = 1;
state.refresh_cache = 1;
o->merge_size = len;
memset(&df_conflict_entry, 0, sizeof(df_conflict_entry));
o->df_conflict_entry = &df_conflict_entry;
if (len) {
posns = xmalloc(len * sizeof(struct tree_entry_list *));
for (i = 0; i < len; i++) {
posns[i] = create_tree_entry_list((struct tree *) posn->item);
posn = posn->next;
}
if (unpack_trees_rec(posns, len, o->prefix ? o->prefix : "",
o, &indpos, &df_conflict_list))
return -1;
}
if (o->trivial_merges_only && o->nontrivial_merge)
die("Merge requires file-level merging");
check_updates(active_cache, active_nr, o);
return 0;
}
/* Here come the merge functions */
static void reject_merge(struct cache_entry *ce)
{
die("Entry '%s' would be overwritten by merge. Cannot merge.",
ce->name);
}
static int same(struct cache_entry *a, struct cache_entry *b)
{
if (!!a != !!b)
return 0;
if (!a && !b)
return 1;
return a->ce_mode == b->ce_mode &&
!memcmp(a->sha1, b->sha1, 20);
}
/*
* When a CE gets turned into an unmerged entry, we
* want it to be up-to-date
*/
static void verify_uptodate(struct cache_entry *ce,
struct unpack_trees_options *o)
{
struct stat st;
if (o->index_only || o->reset)
return;
if (!lstat(ce->name, &st)) {
unsigned changed = ce_match_stat(ce, &st, 1);
if (!changed)
return;
errno = 0;
}
if (o->reset) {
ce->ce_flags |= htons(CE_UPDATE);
return;
}
if (errno == ENOENT)
return;
die("Entry '%s' not uptodate. Cannot merge.", ce->name);
}
static void invalidate_ce_path(struct cache_entry *ce)
{
if (ce)
cache_tree_invalidate_path(active_cache_tree, ce->name);
}
/*
* We do not want to remove or overwrite a working tree file that
* is not tracked.
*/
static void verify_absent(const char *path, const char *action,
struct unpack_trees_options *o)
{
struct stat st;
if (o->index_only || o->reset || !o->update)
return;
if (!lstat(path, &st))
die("Untracked working tree file '%s' "
"would be %s by merge.", path, action);
}
static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
struct unpack_trees_options *o)
{
merge->ce_flags |= htons(CE_UPDATE);
if (old) {
/*
* See if we can re-use the old CE directly?
* That way we get the uptodate stat info.
*
* This also removes the UPDATE flag on
* a match.
*/
if (same(old, merge)) {
*merge = *old;
} else {
verify_uptodate(old, o);
invalidate_ce_path(old);
}
}
else {
verify_absent(merge->name, "overwritten", o);
invalidate_ce_path(merge);
}
merge->ce_flags &= ~htons(CE_STAGEMASK);
add_cache_entry(merge, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
return 1;
}
static int deleted_entry(struct cache_entry *ce, struct cache_entry *old,
struct unpack_trees_options *o)
{
if (old)
verify_uptodate(old, o);
else
verify_absent(ce->name, "removed", o);
ce->ce_mode = 0;
add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
invalidate_ce_path(ce);
return 1;
}
static int keep_entry(struct cache_entry *ce)
{
add_cache_entry(ce, ADD_CACHE_OK_TO_ADD);
return 1;
}
#if DBRT_DEBUG
static void show_stage_entry(FILE *o,
const char *label, const struct cache_entry *ce)
{
if (!ce)
fprintf(o, "%s (missing)\n", label);
else
fprintf(o, "%s%06o %s %d\t%s\n",
label,
ntohl(ce->ce_mode),
sha1_to_hex(ce->sha1),
ce_stage(ce),
ce->name);
}
#endif
int threeway_merge(struct cache_entry **stages,
struct unpack_trees_options *o)
{
struct cache_entry *index;
struct cache_entry *head;
struct cache_entry *remote = stages[o->head_idx + 1];
int count;
int head_match = 0;
int remote_match = 0;
const char *path = NULL;
int df_conflict_head = 0;
int df_conflict_remote = 0;
int any_anc_missing = 0;
int no_anc_exists = 1;
int i;
for (i = 1; i < o->head_idx; i++) {
if (!stages[i])
any_anc_missing = 1;
else {
if (!path)
path = stages[i]->name;
no_anc_exists = 0;
}
}
index = stages[0];
head = stages[o->head_idx];
if (head == o->df_conflict_entry) {
df_conflict_head = 1;
head = NULL;
}
if (remote == o->df_conflict_entry) {
df_conflict_remote = 1;
remote = NULL;
}
if (!path && index)
path = index->name;
if (!path && head)
path = head->name;
if (!path && remote)
path = remote->name;
/* First, if there's a #16 situation, note that to prevent #13
* and #14.
*/
if (!same(remote, head)) {
for (i = 1; i < o->head_idx; i++) {
if (same(stages[i], head)) {
head_match = i;
}
if (same(stages[i], remote)) {
remote_match = i;
}
}
}
/* We start with cases where the index is allowed to match
* something other than the head: #14(ALT) and #2ALT, where it
* is permitted to match the result instead.
*/
/* #14, #14ALT, #2ALT */
if (remote && !df_conflict_head && head_match && !remote_match) {
if (index && !same(index, remote) && !same(index, head))
reject_merge(index);
return merged_entry(remote, index, o);
}
/*
* If we have an entry in the index cache, then we want to
* make sure that it matches head.
*/
if (index && !same(index, head)) {
reject_merge(index);
}
if (head) {
/* #5ALT, #15 */
if (same(head, remote))
return merged_entry(head, index, o);
/* #13, #3ALT */
if (!df_conflict_remote && remote_match && !head_match)
return merged_entry(head, index, o);
}
/* #1 */
if (!head && !remote && any_anc_missing)
return 0;
/* Under the new "aggressive" rule, we resolve mostly trivial
* cases that we historically had git-merge-one-file resolve.
*/
if (o->aggressive) {
int head_deleted = !head && !df_conflict_head;
int remote_deleted = !remote && !df_conflict_remote;
/*
* Deleted in both.
* Deleted in one and unchanged in the other.
*/
if ((head_deleted && remote_deleted) ||
(head_deleted && remote && remote_match) ||
(remote_deleted && head && head_match)) {
if (index)
return deleted_entry(index, index, o);
else if (path)
verify_absent(path, "removed", o);
return 0;
}
/*
* Added in both, identically.
*/
if (no_anc_exists && head && remote && same(head, remote))
return merged_entry(head, index, o);
}
/* Below are "no merge" cases, which require that the index be
* up-to-date to avoid the files getting overwritten with
* conflict resolution files.
*/
if (index) {
verify_uptodate(index, o);
}
else if (path)
verify_absent(path, "overwritten", o);
o->nontrivial_merge = 1;
/* #2, #3, #4, #6, #7, #9, #11. */
count = 0;
if (!head_match || !remote_match) {
for (i = 1; i < o->head_idx; i++) {
if (stages[i]) {
keep_entry(stages[i]);
count++;
break;
}
}
}
#if DBRT_DEBUG
else {
fprintf(stderr, "read-tree: warning #16 detected\n");
show_stage_entry(stderr, "head ", stages[head_match]);
show_stage_entry(stderr, "remote ", stages[remote_match]);
}
#endif
if (head) { count += keep_entry(head); }
if (remote) { count += keep_entry(remote); }
return count;
}
/*
* Two-way merge.
*
* The rule is to "carry forward" what is in the index without losing
* information across a "fast forward", favoring a successful merge
* over a merge failure when it makes sense. For details of the
* "carry forward" rule, please see <Documentation/git-read-tree.txt>.
*
*/
int twoway_merge(struct cache_entry **src,
struct unpack_trees_options *o)
{
struct cache_entry *current = src[0];
struct cache_entry *oldtree = src[1], *newtree = src[2];
if (o->merge_size != 2)
return error("Cannot do a twoway merge of %d trees",
o->merge_size);
if (current) {
if ((!oldtree && !newtree) || /* 4 and 5 */
(!oldtree && newtree &&
same(current, newtree)) || /* 6 and 7 */
(oldtree && newtree &&
same(oldtree, newtree)) || /* 14 and 15 */
(oldtree && newtree &&
!same(oldtree, newtree) && /* 18 and 19*/
same(current, newtree))) {
return keep_entry(current);
}
else if (oldtree && !newtree && same(current, oldtree)) {
/* 10 or 11 */
return deleted_entry(oldtree, current, o);
}
else if (oldtree && newtree &&
same(current, oldtree) && !same(current, newtree)) {
/* 20 or 21 */
return merged_entry(newtree, current, o);
}
else {
/* all other failures */
if (oldtree)
reject_merge(oldtree);
if (current)
reject_merge(current);
if (newtree)
reject_merge(newtree);
return -1;
}
}
else if (newtree)
return merged_entry(newtree, current, o);
else
return deleted_entry(oldtree, current, o);
}
/*
* Bind merge.
*
* Keep the index entries at stage0, collapse stage1 but make sure
* stage0 does not have anything there.
*/
int bind_merge(struct cache_entry **src,
struct unpack_trees_options *o)
{
struct cache_entry *old = src[0];
struct cache_entry *a = src[1];
if (o->merge_size != 1)
return error("Cannot do a bind merge of %d trees\n",
o->merge_size);
if (a && old)
die("Entry '%s' overlaps. Cannot bind.", a->name);
if (!a)
return keep_entry(old);
else
return merged_entry(a, NULL, o);
}
/*
* One-way merge.
*
* The rule is:
* - take the stat information from stage0, take the data from stage1
*/
int oneway_merge(struct cache_entry **src,
struct unpack_trees_options *o)
{
struct cache_entry *old = src[0];
struct cache_entry *a = src[1];
if (o->merge_size != 1)
return error("Cannot do a oneway merge of %d trees",
o->merge_size);
if (!a)
return deleted_entry(old, old, o);
if (old && same(old, a)) {
if (o->reset) {
struct stat st;
if (lstat(old->name, &st) ||
ce_match_stat(old, &st, 1))
old->ce_flags |= htons(CE_UPDATE);
}
return keep_entry(old);
}
return merged_entry(a, old, o);
}

35
unpack-trees.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef UNPACK_TREES_H
#define UNPACK_TREES_H
struct unpack_trees_options;
typedef int (*merge_fn_t)(struct cache_entry **src,
struct unpack_trees_options *options);
struct unpack_trees_options {
int reset;
int merge;
int update;
int index_only;
int nontrivial_merge;
int trivial_merges_only;
int verbose_update;
int aggressive;
const char *prefix;
merge_fn_t fn;
int head_idx;
int merge_size;
struct cache_entry *df_conflict_entry;
};
extern int unpack_trees(struct object_list *trees,
struct unpack_trees_options *options);
int threeway_merge(struct cache_entry **stages, struct unpack_trees_options *o);
int twoway_merge(struct cache_entry **src, struct unpack_trees_options *o);
int bind_merge(struct cache_entry **src, struct unpack_trees_options *o);
int oneway_merge(struct cache_entry **src, struct unpack_trees_options *o);
#endif

View File

@ -14,12 +14,10 @@ static const char upload_pack_usage[] = "git-upload-pack [--strict] [--timeout=n
#define THEY_HAVE (1U << 0) #define THEY_HAVE (1U << 0)
#define OUR_REF (1U << 1) #define OUR_REF (1U << 1)
#define WANTED (1U << 2) #define WANTED (1U << 2)
#define MAX_HAS 256 static int multi_ack = 0, nr_our_refs = 0;
#define MAX_NEEDS 256
static int nr_has = 0, nr_needs = 0, multi_ack = 0, nr_our_refs = 0;
static int use_thin_pack = 0; static int use_thin_pack = 0;
static unsigned char has_sha1[MAX_HAS][20]; static struct object_array have_obj;
static unsigned char needs_sha1[MAX_NEEDS][20]; static struct object_array want_obj;
static unsigned int timeout = 0; static unsigned int timeout = 0;
static int use_sideband = 0; static int use_sideband = 0;
@ -83,7 +81,7 @@ static void create_pack_file(void)
*/ */
int lp_pipe[2], pu_pipe[2], pe_pipe[2]; int lp_pipe[2], pu_pipe[2], pe_pipe[2];
pid_t pid_rev_list, pid_pack_objects; pid_t pid_rev_list, pid_pack_objects;
int create_full_pack = (nr_our_refs == nr_needs && !nr_has); int create_full_pack = (nr_our_refs == want_obj.nr && !have_obj.nr);
char data[8193], progress[128]; char data[8193], progress[128];
char abort_msg[] = "aborting due to possible repository " char abort_msg[] = "aborting due to possible repository "
"corruption on the remote side."; "corruption on the remote side.";
@ -107,7 +105,7 @@ static void create_pack_file(void)
use_thin_pack = 0; /* no point doing it */ use_thin_pack = 0; /* no point doing it */
} }
else else
args = nr_has + nr_needs + 5; args = have_obj.nr + want_obj.nr + 5;
p = xmalloc(args * sizeof(char *)); p = xmalloc(args * sizeof(char *));
argv = (const char **) p; argv = (const char **) p;
buf = xmalloc(args * 45); buf = xmalloc(args * 45);
@ -118,20 +116,22 @@ static void create_pack_file(void)
close(lp_pipe[1]); close(lp_pipe[1]);
*p++ = "rev-list"; *p++ = "rev-list";
*p++ = use_thin_pack ? "--objects-edge" : "--objects"; *p++ = use_thin_pack ? "--objects-edge" : "--objects";
if (create_full_pack || MAX_NEEDS <= nr_needs) if (create_full_pack)
*p++ = "--all"; *p++ = "--all";
else { else {
for (i = 0; i < nr_needs; i++) { for (i = 0; i < want_obj.nr; i++) {
struct object *o = want_obj.objects[i].item;
*p++ = buf; *p++ = buf;
memcpy(buf, sha1_to_hex(needs_sha1[i]), 41); memcpy(buf, sha1_to_hex(o->sha1), 41);
buf += 41; buf += 41;
} }
} }
if (!create_full_pack) if (!create_full_pack)
for (i = 0; i < nr_has; i++) { for (i = 0; i < have_obj.nr; i++) {
struct object *o = have_obj.objects[i].item;
*p++ = buf; *p++ = buf;
*buf++ = '^'; *buf++ = '^';
memcpy(buf, sha1_to_hex(has_sha1[i]), 41); memcpy(buf, sha1_to_hex(o->sha1), 41);
buf += 41; buf += 41;
} }
*p++ = NULL; *p++ = NULL;
@ -322,28 +322,29 @@ static void create_pack_file(void)
static int got_sha1(char *hex, unsigned char *sha1) static int got_sha1(char *hex, unsigned char *sha1)
{ {
struct object *o;
if (get_sha1_hex(hex, sha1)) if (get_sha1_hex(hex, sha1))
die("git-upload-pack: expected SHA1 object, got '%s'", hex); die("git-upload-pack: expected SHA1 object, got '%s'", hex);
if (!has_sha1_file(sha1)) if (!has_sha1_file(sha1))
return 0; return 0;
if (nr_has < MAX_HAS) {
struct object *o = lookup_object(sha1); o = lookup_object(sha1);
if (!(o && o->parsed)) if (!(o && o->parsed))
o = parse_object(sha1); o = parse_object(sha1);
if (!o) if (!o)
die("oops (%s)", sha1_to_hex(sha1)); die("oops (%s)", sha1_to_hex(sha1));
if (o->type == OBJ_COMMIT) { if (o->type == OBJ_COMMIT) {
struct commit_list *parents; struct commit_list *parents;
if (o->flags & THEY_HAVE) if (o->flags & THEY_HAVE)
return 0; return 0;
o->flags |= THEY_HAVE; o->flags |= THEY_HAVE;
for (parents = ((struct commit*)o)->parents; for (parents = ((struct commit*)o)->parents;
parents; parents;
parents = parents->next) parents = parents->next)
parents->item->object.flags |= THEY_HAVE; parents->item->object.flags |= THEY_HAVE;
}
memcpy(has_sha1[nr_has++], sha1, 20);
} }
add_object_array(o, NULL, &have_obj);
return 1; return 1;
} }
@ -361,26 +362,24 @@ static int get_common_commits(void)
reset_timeout(); reset_timeout();
if (!len) { if (!len) {
if (nr_has == 0 || multi_ack) if (have_obj.nr == 0 || multi_ack)
packet_write(1, "NAK\n"); packet_write(1, "NAK\n");
continue; continue;
} }
len = strip(line, len); len = strip(line, len);
if (!strncmp(line, "have ", 5)) { if (!strncmp(line, "have ", 5)) {
if (got_sha1(line+5, sha1) && if (got_sha1(line+5, sha1) &&
(multi_ack || nr_has == 1)) { (multi_ack || have_obj.nr == 1)) {
if (nr_has >= MAX_HAS)
multi_ack = 0;
packet_write(1, "ACK %s%s\n", packet_write(1, "ACK %s%s\n",
sha1_to_hex(sha1), sha1_to_hex(sha1),
multi_ack ? " continue" : ""); multi_ack ? " continue" : "");
if (multi_ack) if (multi_ack)
memcpy(last_sha1, sha1, 20); memcpy(last_sha1, sha1, 20);
} }
continue; continue;
} }
if (!strcmp(line, "done")) { if (!strcmp(line, "done")) {
if (nr_has > 0) { if (have_obj.nr > 0) {
if (multi_ack) if (multi_ack)
packet_write(1, "ACK %s\n", packet_write(1, "ACK %s\n",
sha1_to_hex(last_sha1)); sha1_to_hex(last_sha1));
@ -393,31 +392,21 @@ static int get_common_commits(void)
} }
} }
static int receive_needs(void) static void receive_needs(void)
{ {
static char line[1000]; static char line[1000];
int len, needs; int len;
needs = 0;
for (;;) { for (;;) {
struct object *o; struct object *o;
unsigned char dummy[20], *sha1_buf; unsigned char sha1_buf[20];
len = packet_read_line(0, line, sizeof(line)); len = packet_read_line(0, line, sizeof(line));
reset_timeout(); reset_timeout();
if (!len) if (!len)
return needs; return;
sha1_buf = dummy; if (strncmp("want ", line, 5) ||
if (needs == MAX_NEEDS) { get_sha1_hex(line+5, sha1_buf))
fprintf(stderr,
"warning: supporting only a max of %d requests. "
"sending everything instead.\n",
MAX_NEEDS);
}
else if (needs < MAX_NEEDS)
sha1_buf = needs_sha1[needs];
if (strncmp("want ", line, 5) || get_sha1_hex(line+5, sha1_buf))
die("git-upload-pack: protocol error, " die("git-upload-pack: protocol error, "
"expected to get sha, not '%s'", line); "expected to get sha, not '%s'", line);
if (strstr(line+45, "multi_ack")) if (strstr(line+45, "multi_ack"))
@ -440,7 +429,7 @@ static int receive_needs(void)
die("git-upload-pack: not our ref %s", line+5); die("git-upload-pack: not our ref %s", line+5);
if (!(o->flags & WANTED)) { if (!(o->flags & WANTED)) {
o->flags |= WANTED; o->flags |= WANTED;
needs++; add_object_array(o, NULL, &want_obj);
} }
} }
} }
@ -470,18 +459,17 @@ static int send_ref(const char *refname, const unsigned char *sha1)
return 0; return 0;
} }
static int upload_pack(void) static void upload_pack(void)
{ {
reset_timeout(); reset_timeout();
head_ref(send_ref); head_ref(send_ref);
for_each_ref(send_ref); for_each_ref(send_ref);
packet_flush(1); packet_flush(1);
nr_needs = receive_needs(); receive_needs();
if (!nr_needs) if (want_obj.nr) {
return 0; get_common_commits();
get_common_commits(); create_pack_file();
create_pack_file(); }
return 0;
} }
int main(int argc, char **argv) int main(int argc, char **argv)

View File

@ -1,57 +0,0 @@
#include "cache.h"
#include "pack.h"
static int verify_one_pack(char *arg, int verbose)
{
int len = strlen(arg);
struct packed_git *g;
while (1) {
/* Should name foo.idx, but foo.pack may be named;
* convert it to foo.idx
*/
if (!strcmp(arg + len - 5, ".pack")) {
strcpy(arg + len - 5, ".idx");
len--;
}
/* Should name foo.idx now */
if ((g = add_packed_git(arg, len, 1)))
break;
/* No? did you name just foo? */
strcpy(arg + len, ".idx");
len += 4;
if ((g = add_packed_git(arg, len, 1)))
break;
return error("packfile %s not found.", arg);
}
return verify_pack(g, verbose);
}
static const char verify_pack_usage[] = "git-verify-pack [-v] <pack>...";
int main(int ac, char **av)
{
int errs = 0;
int verbose = 0;
int no_more_options = 0;
while (1 < ac) {
char path[PATH_MAX];
if (!no_more_options && av[1][0] == '-') {
if (!strcmp("-v", av[1]))
verbose = 1;
else if (!strcmp("--", av[1]))
no_more_options = 1;
else
usage(verify_pack_usage);
}
else {
strcpy(path, av[1]);
if (verify_one_pack(path, verbose))
errs++;
}
ac--; av++;
}
return !!errs;
}