mirror of
https://github.com/git/git
synced 2024-08-24 18:26:02 +00:00
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:
commit
d7b6c3c0f5
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -125,6 +125,7 @@ git-verify-tag
|
|||
git-whatchanged
|
||||
git-write-tree
|
||||
git-core-*/?*
|
||||
gitweb/gitweb.cgi
|
||||
test-date
|
||||
test-delta
|
||||
test-dump-cache-tree
|
||||
|
@ -140,7 +141,7 @@ config.mak
|
|||
autom4te.cache
|
||||
config.log
|
||||
config.status
|
||||
config.mak.in
|
||||
config.mak.autogen
|
||||
config.mak.append
|
||||
configure
|
||||
git-blame
|
||||
|
|
|
@ -83,9 +83,12 @@ core.repositoryFormatVersion::
|
|||
version.
|
||||
|
||||
core.sharedRepository::
|
||||
If true, the repository is made shareable between several users
|
||||
in a group (making sure all the files and objects are group-writable).
|
||||
See gitlink:git-init-db[1]. False by default.
|
||||
When 'group' (or 'true'), the repository is made shareable between
|
||||
several users in a group (making sure all the files and objects are
|
||||
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::
|
||||
If true, git will warn you if the ref name you passed it is ambiguous
|
||||
|
|
|
@ -36,6 +36,9 @@
|
|||
Turn off colored diff, even when the configuration file
|
||||
gives the default to color output.
|
||||
|
||||
--color-words::
|
||||
Show colored word diff, i.e. color words which have changed.
|
||||
|
||||
--no-renames::
|
||||
Turn off rename detection, even when the configuration
|
||||
file gives the default to do so.
|
||||
|
|
|
@ -11,7 +11,7 @@ SYNOPSIS
|
|||
[verse]
|
||||
'git-grep' [--cached]
|
||||
[-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]
|
||||
[-n] [-l | --files-with-matches] [-L | --files-without-match]
|
||||
[-c | --count]
|
||||
|
@ -47,6 +47,12 @@ OPTIONS
|
|||
-v | --invert-match::
|
||||
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::
|
||||
Use POSIX extended/basic regexp for patterns. Default
|
||||
is to use basic regexp.
|
||||
|
|
|
@ -8,17 +8,47 @@ git-init-db - Creates an empty git repository
|
|||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-init-db' [--template=<template_directory>] [--shared]
|
||||
'git-init-db' [--template=<template_directory>] [--shared[=<permissions>]]
|
||||
|
||||
|
||||
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
|
||||
|
@ -29,12 +59,6 @@ template files.
|
|||
An initial `HEAD` file that references the HEAD of the master branch
|
||||
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
|
||||
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 -
|
||||
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
|
||||
things that are already there. The primary reason for rerunning `git-init-db`
|
||||
is to pick up newly added templates.
|
||||
|
|
|
@ -8,7 +8,7 @@ git-status - Show working tree status
|
|||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-status'
|
||||
'git-status' <options>...
|
||||
|
||||
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
|
||||
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
|
||||
------
|
||||
|
|
|
@ -633,6 +633,9 @@ git Diffs
|
|||
|
||||
other
|
||||
~~~~~
|
||||
'GIT_PAGER'::
|
||||
This environment variable overrides `$PAGER`.
|
||||
|
||||
'GIT_TRACE'::
|
||||
If this variable is set git will print `trace:` messages on
|
||||
stderr telling about alias expansion, built-in command
|
||||
|
|
256
Documentation/howto/setup-git-server-over-http.txt
Normal file
256
Documentation/howto/setup-git-server-over-http.txt
Normal 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>
|
|
@ -244,6 +244,7 @@ $ git ls-files --stage
|
|||
$ git cat-file -t 513feba2
|
||||
blob
|
||||
$ git cat-file blob 513feba2
|
||||
hello world!
|
||||
hello world, again
|
||||
------------------------------------------------
|
||||
|
||||
|
|
|
@ -3,9 +3,17 @@
|
|||
GVF=GIT-VERSION-FILE
|
||||
DEF_VER=v1.4.2.GIT
|
||||
|
||||
LF='
|
||||
'
|
||||
|
||||
# First try git-describe, then see if there is a version file
|
||||
# (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');
|
||||
elif test -f version
|
||||
then
|
||||
|
|
2
INSTALL
2
INSTALL
|
@ -16,7 +16,7 @@ install" would not work.
|
|||
Alternatively you can use autoconf generated ./configure script to
|
||||
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
|
||||
$ make all doc ;# as yourself
|
||||
# make install install-doc ;# as root
|
||||
|
|
125
Makefile
125
Makefile
|
@ -22,7 +22,7 @@ all:
|
|||
# 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.
|
||||
# some C compilers supported these specifiers prior to C99 as an extension.
|
||||
#
|
||||
# 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
|
||||
# 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
|
||||
|
||||
CC = gcc
|
||||
|
@ -183,32 +193,23 @@ SIMPLE_PROGRAMS = \
|
|||
|
||||
# ... and all the rest that could be moved out of bindir to gitexecdir
|
||||
PROGRAMS = \
|
||||
git-checkout-index$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-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-send-pack$X git-shell$X \
|
||||
git-show-index$X git-ssh-fetch$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-symbolic-ref$X \
|
||||
git-name-rev$X git-pack-redundant$X git-var$X \
|
||||
git-pack-redundant$X git-var$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 \
|
||||
git-count-objects$X git-diff$X git-push$X git-mailsplit$X \
|
||||
git-grep$X git-add$X git-rm$X git-rev-list$X git-stripspace$X \
|
||||
git-check-ref-format$X git-rev-parse$X git-mailinfo$X \
|
||||
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
|
||||
BUILT_INS = \
|
||||
git-format-patch$X git-show$X git-whatchanged$X \
|
||||
git-get-tar-commit-id$X \
|
||||
$(patsubst builtin-%.o,git-%$X,$(BUILTIN_OBJS))
|
||||
|
||||
# what 'all' will build and 'install' will install, in gitexecdir
|
||||
ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)
|
||||
|
@ -237,7 +238,7 @@ LIB_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 \
|
||||
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.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 \
|
||||
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 \
|
||||
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-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o \
|
||||
builtin-grep.o builtin-add.o builtin-rev-list.o builtin-check-ref-format.o \
|
||||
builtin-rm.o builtin-init-db.o builtin-rev-parse.o \
|
||||
builtin-tar-tree.o builtin-upload-tar.o builtin-update-index.o \
|
||||
builtin-ls-files.o builtin-ls-tree.o builtin-write-tree.o \
|
||||
builtin-read-tree.o builtin-commit-tree.o builtin-mailinfo.o \
|
||||
builtin-apply.o builtin-show-branch.o builtin-diff-files.o \
|
||||
builtin-diff-index.o builtin-diff-stages.o builtin-diff-tree.o \
|
||||
builtin-cat-file.o builtin-mailsplit.o builtin-stripspace.o \
|
||||
builtin-update-ref.o builtin-fmt-merge-msg.o builtin-prune.o \
|
||||
builtin-mv.o builtin-prune-packed.o builtin-repo-config.o
|
||||
builtin-add.o \
|
||||
builtin-apply.o \
|
||||
builtin-cat-file.o \
|
||||
builtin-checkout-index.o \
|
||||
builtin-check-ref-format.o \
|
||||
builtin-commit-tree.o \
|
||||
builtin-count-objects.o \
|
||||
builtin-diff.o \
|
||||
builtin-diff-files.o \
|
||||
builtin-diff-index.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)
|
||||
EXTLIBS = -lz
|
||||
|
@ -306,7 +337,6 @@ ifeq ($(uname_S),SunOS)
|
|||
NEEDS_NSL = YesPlease
|
||||
SHELL_PATH = /bin/bash
|
||||
NO_STRCASESTR = YesPlease
|
||||
NO_STRLCPY = YesPlease
|
||||
ifeq ($(uname_R),5.8)
|
||||
NEEDS_LIBICONV = YesPlease
|
||||
NO_UNSETENV = YesPlease
|
||||
|
@ -548,7 +578,7 @@ export prefix TAR INSTALL DESTDIR SHELL_PATH template_dir
|
|||
|
||||
### Build rules
|
||||
|
||||
all: $(ALL_PROGRAMS) $(BUILT_INS) git$X gitk
|
||||
all: $(ALL_PROGRAMS) $(BUILT_INS) git$X gitk gitweb/gitweb.cgi
|
||||
|
||||
all: perl/Makefile
|
||||
$(MAKE) -C perl
|
||||
|
@ -562,7 +592,7 @@ git$X: git.c common-cmds.h $(BUILTIN_OBJS) $(GITLIBS) GIT-CFLAGS
|
|||
$(ALL_CFLAGS) -o $@ $(filter %.c,$^) \
|
||||
$(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)
|
||||
|
||||
builtin-help.o: common-cmds.h
|
||||
help.o: common-cmds.h
|
||||
|
||||
$(BUILT_INS): git$X
|
||||
rm -f $@ && ln git$X $@
|
||||
|
@ -616,6 +646,23 @@ git-status: git-commit
|
|||
cp $< $@+
|
||||
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
|
||||
rm -f $@ $@+
|
||||
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_CSS@@/r gitweb/gitweb.css' \
|
||||
-e '/@@GITWEB_CSS@@/d' \
|
||||
$@.sh | sed "s|/usr/bin/git|$(bindir)/git|" > $@+
|
||||
$@.sh > $@+
|
||||
chmod +x $@+
|
||||
mv $@+ $@
|
||||
|
||||
configure: configure.ac
|
||||
rm -f $@ $<+
|
||||
sed -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
|
||||
$< > $<+
|
||||
autoconf -o $@ $<+
|
||||
rm -f $<+
|
||||
|
||||
# These can record GIT_VERSION
|
||||
git$X git.spec \
|
||||
$(patsubst %.sh,%,$(SCRIPT_SH)) \
|
||||
|
@ -832,10 +886,11 @@ clean:
|
|||
rm -f $(ALL_PROGRAMS) $(BUILT_INS) git$X
|
||||
rm -f *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags
|
||||
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 -f $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz
|
||||
rm -f $(htmldocs).tar.gz $(manpages).tar.gz
|
||||
rm -f gitweb/gitweb.cgi
|
||||
$(MAKE) -C Documentation/ clean
|
||||
[ ! -f perl/Makefile ] || $(MAKE) -C perl/ clean || $(MAKE) -C perl/ clean
|
||||
rm -f perl/ppport.h perl/Makefile.old
|
||||
|
|
5
blame.c
5
blame.c
|
@ -351,10 +351,7 @@ static int fill_util_info(struct commit *commit)
|
|||
assert(util);
|
||||
assert(util->pathname);
|
||||
|
||||
if (get_blob_sha1(commit->tree, util->pathname, util->sha1))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
return !!get_blob_sha1(commit->tree, util->pathname, util->sha1);
|
||||
}
|
||||
|
||||
static void alloc_line_map(struct commit *commit)
|
||||
|
|
|
@ -93,9 +93,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
|
|||
|
||||
git_config(git_default_config);
|
||||
|
||||
newfd = hold_lock_file_for_update(&lock_file, get_index_file());
|
||||
if (newfd < 0)
|
||||
die("unable to create new index file");
|
||||
newfd = hold_lock_file_for_update(&lock_file, get_index_file(), 1);
|
||||
|
||||
if (read_cache() < 0)
|
||||
die("index file corrupt");
|
||||
|
|
248
builtin-apply.c
248
builtin-apply.c
|
@ -37,6 +37,7 @@ static int numstat = 0;
|
|||
static int summary = 0;
|
||||
static int check = 0;
|
||||
static int apply = 1;
|
||||
static int apply_in_reverse = 0;
|
||||
static int no_add = 0;
|
||||
static int show_index_info = 0;
|
||||
static int line_termination = '\n';
|
||||
|
@ -108,6 +109,13 @@ static int max_change, max_len;
|
|||
*/
|
||||
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 {
|
||||
unsigned long leading, trailing;
|
||||
unsigned long oldpos, oldlines;
|
||||
|
@ -117,12 +125,19 @@ struct fragment {
|
|||
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 {
|
||||
char *new_name, *old_name, *def_name;
|
||||
unsigned int old_mode, new_mode;
|
||||
int is_rename, is_copy, is_new, is_delete, is_binary, is_reverse;
|
||||
#define BINARY_DELTA_DEFLATED 1
|
||||
#define BINARY_LITERAL_DEFLATED 2
|
||||
int is_rename, is_copy, is_new, is_delete, is_binary;
|
||||
unsigned long deflate_origlen;
|
||||
int lines_added, lines_deleted;
|
||||
int score;
|
||||
|
@ -978,43 +993,70 @@ static inline int metadata_changes(struct patch *patch)
|
|||
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
|
||||
* that says the patch method (currently, either "deflated
|
||||
* literal" or "deflated delta") and the length of data before
|
||||
* deflating; a sequence of 'length-byte' followed by base-85
|
||||
* encoded data follows.
|
||||
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 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,
|
||||
* and we would limit the patch line to 66 characters,
|
||||
* so one line can fit up to 13 groups that would decode
|
||||
* to 52 bytes max. The length byte 'A'-'Z' corresponds
|
||||
* 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;
|
||||
struct fragment *fragment;
|
||||
unsigned long size = *sz_p;
|
||||
char *buffer = *buf_p;
|
||||
int patch_method;
|
||||
unsigned long origlen;
|
||||
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);
|
||||
used = llen;
|
||||
linenr++;
|
||||
|
||||
*status_p = 0;
|
||||
|
||||
if (!strncmp(buffer, "delta ", 6)) {
|
||||
patch->is_binary = BINARY_DELTA_DEFLATED;
|
||||
patch->deflate_origlen = strtoul(buffer + 6, NULL, 10);
|
||||
patch_method = BINARY_DELTA_DEFLATED;
|
||||
origlen = strtoul(buffer + 6, NULL, 10);
|
||||
}
|
||||
else if (!strncmp(buffer, "literal ", 8)) {
|
||||
patch->is_binary = BINARY_LITERAL_DEFLATED;
|
||||
patch->deflate_origlen = strtoul(buffer + 8, NULL, 10);
|
||||
patch_method = BINARY_LITERAL_DEFLATED;
|
||||
origlen = strtoul(buffer + 8, NULL, 10);
|
||||
}
|
||||
else
|
||||
return error("unrecognized binary patch at line %d: %.*s",
|
||||
linenr-1, llen-1, buffer);
|
||||
return NULL;
|
||||
|
||||
linenr++;
|
||||
buffer += llen;
|
||||
while (1) {
|
||||
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 ||
|
||||
byte_length <= max_byte_length - 4)
|
||||
goto corrupt;
|
||||
newsize = fragment->size + byte_length;
|
||||
newsize = hunk_size + byte_length;
|
||||
data = xrealloc(data, newsize);
|
||||
if (decode_85(data + fragment->size,
|
||||
buffer + 1,
|
||||
byte_length))
|
||||
if (decode_85(data + hunk_size, buffer + 1, byte_length))
|
||||
goto corrupt;
|
||||
fragment->size = newsize;
|
||||
hunk_size = newsize;
|
||||
buffer += 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:
|
||||
return error("corrupt binary patch at line %d: %.*s",
|
||||
linenr-1, llen-1, buffer);
|
||||
if (data)
|
||||
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)
|
||||
|
@ -1143,7 +1243,6 @@ static void reverse_patches(struct patch *p)
|
|||
swap(frag->newpos, frag->oldpos);
|
||||
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;
|
||||
}
|
||||
|
||||
static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag,
|
||||
int reverse, int inaccurate_eof)
|
||||
static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, int inaccurate_eof)
|
||||
{
|
||||
int match_beginning, match_end;
|
||||
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] == '\\')
|
||||
plen--;
|
||||
first = *patch;
|
||||
if (reverse) {
|
||||
if (apply_in_reverse) {
|
||||
if (first == '-')
|
||||
first = '+';
|
||||
else if (first == '+')
|
||||
|
@ -1506,28 +1604,6 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag,
|
|||
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)
|
||||
{
|
||||
unsigned long dst_size;
|
||||
|
@ -1535,30 +1611,29 @@ static int apply_binary_fragment(struct buffer_desc *desc, struct patch *patch)
|
|||
void *data;
|
||||
void *result;
|
||||
|
||||
/* Binary patch is irreversible */
|
||||
if (patch->is_reverse)
|
||||
return error("cannot reverse-apply a binary patch to '%s'",
|
||||
patch->new_name
|
||||
? patch->new_name : patch->old_name);
|
||||
|
||||
data = inflate_it(fragment->patch, fragment->size,
|
||||
patch->deflate_origlen);
|
||||
if (!data)
|
||||
return error("corrupt patch data");
|
||||
switch (patch->is_binary) {
|
||||
/* Binary patch is irreversible without the optional second hunk */
|
||||
if (apply_in_reverse) {
|
||||
if (!fragment->next)
|
||||
return error("cannot reverse-apply a binary patch "
|
||||
"without the reverse hunk to '%s'",
|
||||
patch->new_name
|
||||
? patch->new_name : patch->old_name);
|
||||
fragment = fragment;
|
||||
}
|
||||
data = (void*) fragment->patch;
|
||||
switch (fragment->binary_patch_method) {
|
||||
case BINARY_DELTA_DEFLATED:
|
||||
result = patch_delta(desc->buffer, desc->size,
|
||||
data,
|
||||
patch->deflate_origlen,
|
||||
fragment->size,
|
||||
&dst_size);
|
||||
free(desc->buffer);
|
||||
desc->buffer = result;
|
||||
free(data);
|
||||
break;
|
||||
case BINARY_LITERAL_DEFLATED:
|
||||
free(desc->buffer);
|
||||
desc->buffer = data;
|
||||
dst_size = patch->deflate_origlen;
|
||||
dst_size = fragment->size;
|
||||
break;
|
||||
}
|
||||
if (!desc->buffer)
|
||||
|
@ -1657,8 +1732,7 @@ static int apply_fragments(struct buffer_desc *desc, struct patch *patch)
|
|||
return apply_binary(desc, patch);
|
||||
|
||||
while (frag) {
|
||||
if (apply_one_fragment(desc, frag, patch->is_reverse,
|
||||
patch->inaccurate_eof) < 0)
|
||||
if (apply_one_fragment(desc, frag, patch->inaccurate_eof) < 0)
|
||||
return error("patch failed: %s:%ld",
|
||||
name, frag->oldpos);
|
||||
frag = frag->next;
|
||||
|
@ -1698,6 +1772,12 @@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *
|
|||
desc.buffer = buf;
|
||||
if (apply_fragments(&desc, patch) < 0)
|
||||
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->resultsize = desc.size;
|
||||
|
||||
|
@ -2040,6 +2120,9 @@ static int try_create_file(const char *path, unsigned int mode, const char *buf,
|
|||
int fd;
|
||||
|
||||
if (S_ISLNK(mode))
|
||||
/* Although buf:size is counted string, it also is NUL
|
||||
* terminated.
|
||||
*/
|
||||
return symlink(buf, path);
|
||||
fd = open(path, O_CREAT | O_EXCL | O_WRONLY, (mode & 0100) ? 0777 : 0666);
|
||||
if (fd < 0)
|
||||
|
@ -2185,8 +2268,7 @@ static int use_patch(struct patch *p)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int apply_patch(int fd, const char *filename,
|
||||
int reverse, int inaccurate_eof)
|
||||
static int apply_patch(int fd, const char *filename, int inaccurate_eof)
|
||||
{
|
||||
unsigned long offset, 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);
|
||||
if (nr < 0)
|
||||
break;
|
||||
if (reverse)
|
||||
if (apply_in_reverse)
|
||||
reverse_patches(patch);
|
||||
if (use_patch(patch)) {
|
||||
patch_stats(patch);
|
||||
|
@ -2225,12 +2307,9 @@ static int apply_patch(int fd, const char *filename,
|
|||
apply = 0;
|
||||
|
||||
write_index = check_index && apply;
|
||||
if (write_index && newfd < 0) {
|
||||
if (write_index && newfd < 0)
|
||||
newfd = hold_lock_file_for_update(&lock_file,
|
||||
get_index_file());
|
||||
if (newfd < 0)
|
||||
die("unable to create new index file");
|
||||
}
|
||||
get_index_file(), 1);
|
||||
if (check_index) {
|
||||
if (read_cache() < 0)
|
||||
die("unable to read index file");
|
||||
|
@ -2272,7 +2351,6 @@ int cmd_apply(int argc, const char **argv, const char *prefix)
|
|||
{
|
||||
int i;
|
||||
int read_stdin = 1;
|
||||
int reverse = 0;
|
||||
int inaccurate_eof = 0;
|
||||
|
||||
const char *whitespace_option = NULL;
|
||||
|
@ -2283,7 +2361,7 @@ int cmd_apply(int argc, const char **argv, const char *prefix)
|
|||
int fd;
|
||||
|
||||
if (!strcmp(arg, "-")) {
|
||||
apply_patch(0, "<stdin>", reverse, inaccurate_eof);
|
||||
apply_patch(0, "<stdin>", inaccurate_eof);
|
||||
read_stdin = 0;
|
||||
continue;
|
||||
}
|
||||
|
@ -2361,7 +2439,7 @@ int cmd_apply(int argc, const char **argv, const char *prefix)
|
|||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "-R") || !strcmp(arg, "--reverse")) {
|
||||
reverse = 1;
|
||||
apply_in_reverse = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--inaccurate-eof")) {
|
||||
|
@ -2384,12 +2462,12 @@ int cmd_apply(int argc, const char **argv, const char *prefix)
|
|||
usage(apply_usage);
|
||||
read_stdin = 0;
|
||||
set_default_whitespace_mode(whitespace_option);
|
||||
apply_patch(fd, arg, reverse, inaccurate_eof);
|
||||
apply_patch(fd, arg, inaccurate_eof);
|
||||
close(fd);
|
||||
}
|
||||
set_default_whitespace_mode(whitespace_option);
|
||||
if (read_stdin)
|
||||
apply_patch(0, "<stdin>", reverse, inaccurate_eof);
|
||||
apply_patch(0, "<stdin>", inaccurate_eof);
|
||||
if (whitespace_error) {
|
||||
if (squelch_whitespace_errors &&
|
||||
squelch_whitespace_errors < whitespace_error) {
|
||||
|
|
|
@ -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. */
|
||||
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)
|
||||
flush_buffer(cp, endp - cp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
if (!buf)
|
||||
die("Cannot read object %s", argv[2]);
|
||||
if (!strcmp(type, tag_type))
|
||||
return pprint_tag(sha1, buf, size);
|
||||
if (!strcmp(type, tag_type)) {
|
||||
pprint_tag(sha1, buf, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* otherwise just spit out the data */
|
||||
break;
|
||||
|
|
|
@ -42,8 +42,6 @@
|
|||
#include "cache-tree.h"
|
||||
|
||||
#define CHECKOUT_ALL 4
|
||||
static const char *prefix;
|
||||
static int prefix_length;
|
||||
static int line_termination = '\n';
|
||||
static int checkout_stage; /* default to checkout stage0 */
|
||||
static int to_tempfile;
|
||||
|
@ -51,7 +49,7 @@ static char topath[4][MAXPATHLEN+1];
|
|||
|
||||
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;
|
||||
|
||||
|
@ -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 pos = cache_name_pos(name, namelen);
|
||||
|
@ -106,7 +104,7 @@ static int checkout_file(const char *name)
|
|||
|
||||
if (did_checkout) {
|
||||
if (to_tempfile)
|
||||
write_tempfile_record(name);
|
||||
write_tempfile_record(name, prefix_length);
|
||||
return errs > 0 ? -1 : 0;
|
||||
}
|
||||
|
||||
|
@ -124,7 +122,7 @@ static int checkout_file(const char *name)
|
|||
return -1;
|
||||
}
|
||||
|
||||
static int checkout_all(void)
|
||||
static void checkout_all(const char *prefix, int prefix_length)
|
||||
{
|
||||
int i, errs = 0;
|
||||
struct cache_entry* last_ce = NULL;
|
||||
|
@ -141,7 +139,7 @@ static int checkout_all(void)
|
|||
if (last_ce && to_tempfile) {
|
||||
if (ce_namelen(last_ce) != 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,
|
||||
to_tempfile ? topath[ce_stage(ce)] : NULL) < 0)
|
||||
|
@ -149,13 +147,12 @@ static int checkout_all(void)
|
|||
last_ce = ce;
|
||||
}
|
||||
if (last_ce && to_tempfile)
|
||||
write_tempfile_record(last_ce->name);
|
||||
write_tempfile_record(last_ce->name, prefix_length);
|
||||
if (errs)
|
||||
/* we have already done our error reporting.
|
||||
* exit with the same code as die().
|
||||
*/
|
||||
exit(128);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char checkout_cache_usage[] =
|
||||
|
@ -163,16 +160,16 @@ static const char checkout_cache_usage[] =
|
|||
|
||||
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 newfd = -1;
|
||||
int all = 0;
|
||||
int read_from_stdin = 0;
|
||||
int prefix_length;
|
||||
|
||||
state.base_dir = "";
|
||||
prefix = setup_git_directory();
|
||||
git_config(git_default_config);
|
||||
state.base_dir = "";
|
||||
prefix_length = prefix ? strlen(prefix) : 0;
|
||||
|
||||
if (read_cache() < 0) {
|
||||
|
@ -206,7 +203,7 @@ int main(int argc, char **argv)
|
|||
state.refresh_cache = 1;
|
||||
if (newfd < 0)
|
||||
newfd = hold_lock_file_for_update
|
||||
(&lock_file, get_index_file());
|
||||
(&lock_file, get_index_file(), 1);
|
||||
if (newfd < 0)
|
||||
die("cannot open index.lock file.");
|
||||
continue;
|
||||
|
@ -270,7 +267,7 @@ int main(int argc, char **argv)
|
|||
if (read_from_stdin)
|
||||
die("git-checkout-index: don't mix '--stdin' and explicit filenames");
|
||||
p = prefix_path(prefix, prefix_length, arg);
|
||||
checkout_file(p);
|
||||
checkout_file(p, prefix_length);
|
||||
if (p < arg || p > arg + strlen(arg))
|
||||
free((char*)p);
|
||||
}
|
||||
|
@ -292,7 +289,7 @@ int main(int argc, char **argv)
|
|||
else
|
||||
path_name = buf.buf;
|
||||
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))
|
||||
free((char *)p);
|
||||
if (path_name != buf.buf)
|
||||
|
@ -301,7 +298,7 @@ int main(int argc, char **argv)
|
|||
}
|
||||
|
||||
if (all)
|
||||
checkout_all();
|
||||
checkout_all(prefix, prefix_length);
|
||||
|
||||
if (0 <= newfd &&
|
||||
(write_cache(newfd, active_cache, active_nr) ||
|
|
@ -47,12 +47,5 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
|
|||
if (rev.pending.nr ||
|
||||
rev.min_age != -1 || rev.max_age != -1)
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -56,13 +56,6 @@ static int builtin_diff_files(struct rev_info *revs,
|
|||
if (revs->max_count < 0 &&
|
||||
(revs->diffopt.output_format & DIFF_FORMAT_PATCH))
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -253,7 +246,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
|
|||
argc = setup_revisions(argc, argv, &rev, NULL);
|
||||
if (!rev.diffopt.output_format) {
|
||||
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
|
||||
|
@ -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,
|
||||
* and ent[2] == B. Show diff between the base and B.
|
||||
*/
|
||||
ent[1] = ent[2];
|
||||
return builtin_diff_tree(&rev, argc, argv, ent);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -123,6 +123,7 @@ struct grep_opt {
|
|||
struct grep_pat *pattern_list;
|
||||
struct grep_pat **pattern_tail;
|
||||
struct grep_expr *pattern_expression;
|
||||
int prefix_length;
|
||||
regex_t regexp;
|
||||
unsigned linenum:1;
|
||||
unsigned invert:1;
|
||||
|
@ -136,6 +137,7 @@ struct grep_opt {
|
|||
#define GREP_BINARY_TEXT 2
|
||||
unsigned binary:2;
|
||||
unsigned extended:1;
|
||||
unsigned relative:1;
|
||||
int regflags;
|
||||
unsigned pre_context;
|
||||
unsigned post_context;
|
||||
|
@ -388,9 +390,7 @@ static int buffer_is_binary(const char *ptr, unsigned long size)
|
|||
{
|
||||
if (FIRST_FEW_BYTES < size)
|
||||
size = FIRST_FEW_BYTES;
|
||||
if (memchr(ptr, 0, size))
|
||||
return 1;
|
||||
return 0;
|
||||
return !!memchr(ptr, 0, size);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
char *data;
|
||||
char type[20];
|
||||
char *to_free = NULL;
|
||||
int hit;
|
||||
|
||||
data = read_sha1_file(sha1, type, &size);
|
||||
if (!data) {
|
||||
error("'%s': unable to read %s", name, sha1_to_hex(sha1));
|
||||
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);
|
||||
free(data);
|
||||
free(to_free);
|
||||
return hit;
|
||||
}
|
||||
|
||||
|
@ -674,6 +695,8 @@ static int grep_file(struct grep_opt *opt, const char *filename)
|
|||
return 0;
|
||||
}
|
||||
close(i);
|
||||
if (opt->relative && opt->prefix_length)
|
||||
filename += opt->prefix_length;
|
||||
i = grep_buffer(opt, filename, data, st.st_size);
|
||||
free(data);
|
||||
return i;
|
||||
|
@ -720,7 +743,7 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)
|
|||
char *argptr = randarg;
|
||||
struct grep_pat *p;
|
||||
|
||||
if (opt->extended)
|
||||
if (opt->extended || (opt->relative && opt->prefix_length))
|
||||
return -1;
|
||||
len = nr = 0;
|
||||
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))
|
||||
continue;
|
||||
if (cached)
|
||||
hit |= grep_sha1(opt, ce->sha1, ce->name);
|
||||
hit |= grep_sha1(opt, ce->sha1, ce->name, 0);
|
||||
else
|
||||
hit |= grep_file(opt, ce->name);
|
||||
}
|
||||
|
@ -860,11 +883,12 @@ static int grep_tree(struct grep_opt *opt, const char **paths,
|
|||
int hit = 0;
|
||||
struct name_entry entry;
|
||||
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]) {
|
||||
int offset = sprintf(path_buf, "%s:", tree_name);
|
||||
down = path_buf + offset;
|
||||
if (tn_len) {
|
||||
tn_len = sprintf(path_buf, "%s:", tree_name);
|
||||
down = path_buf + tn_len;
|
||||
strcat(down, base);
|
||||
}
|
||||
else {
|
||||
|
@ -886,7 +910,7 @@ static int grep_tree(struct grep_opt *opt, const char **paths,
|
|||
if (!pathspec_matches(paths, down))
|
||||
;
|
||||
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)) {
|
||||
char type[20];
|
||||
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)
|
||||
{
|
||||
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) {
|
||||
struct tree_desc tree;
|
||||
void *data;
|
||||
|
@ -945,6 +969,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
|
|||
int i;
|
||||
|
||||
memset(&opt, 0, sizeof(opt));
|
||||
opt.prefix_length = (prefix && *prefix) ? strlen(prefix) : 0;
|
||||
opt.relative = 1;
|
||||
opt.pattern_tail = &opt.pattern_list;
|
||||
opt.regflags = REG_NEWLINE;
|
||||
|
||||
|
@ -1118,6 +1144,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
|
|||
}
|
||||
die(emsg_missing_argument, arg);
|
||||
}
|
||||
if (!strcmp("--full-name", arg)) {
|
||||
opt.relative = 0;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp("--", arg)) {
|
||||
/* later processing wants to have this at argv[1] */
|
||||
argv--;
|
||||
|
@ -1176,8 +1206,15 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
|
|||
verify_filename(prefix, argv[j]);
|
||||
}
|
||||
|
||||
if (i < argc)
|
||||
if (i < argc) {
|
||||
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) {
|
||||
paths = xcalloc(2, sizeof(const char *));
|
||||
paths[0] = prefix;
|
||||
|
|
|
@ -48,7 +48,8 @@ static const char *add_slash(const char *path)
|
|||
if (path[len - 1] != '/') {
|
||||
char *with_slash = xmalloc(len + 2);
|
||||
memcpy(with_slash, path, len);
|
||||
strcat(with_slash + len, "/");
|
||||
with_slash[len++] = '/';
|
||||
with_slash[len] = 0;
|
||||
return with_slash;
|
||||
}
|
||||
return path;
|
||||
|
@ -71,10 +72,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
|
|||
|
||||
git_config(git_default_config);
|
||||
|
||||
newfd = hold_lock_file_for_update(&lock_file, get_index_file());
|
||||
if (newfd < 0)
|
||||
die("unable to create new index file");
|
||||
|
||||
newfd = hold_lock_file_for_update(&lock_file, get_index_file(), 1);
|
||||
if (read_cache() < 0)
|
||||
die("index file corrupt");
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <stdlib.h>
|
||||
#include "builtin.h"
|
||||
#include "cache.h"
|
||||
#include "commit.h"
|
||||
#include "tag.h"
|
||||
|
@ -126,12 +127,11 @@ static const char* get_rev_name(struct object *o)
|
|||
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 };
|
||||
int as_is = 0, all = 0, transform_stdin = 0;
|
||||
|
||||
setup_git_directory();
|
||||
git_config(git_default_config);
|
||||
|
||||
if (argc < 2)
|
|
@ -1,3 +1,4 @@
|
|||
#include "builtin.h"
|
||||
#include "cache.h"
|
||||
#include "object.h"
|
||||
#include "blob.h"
|
||||
|
@ -269,6 +270,22 @@ static unsigned long write_object(struct sha1file *f,
|
|||
* 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) {
|
||||
buf = read_sha1_file(entry->sha1, type, &size);
|
||||
if (!buf)
|
||||
|
@ -1226,7 +1243,7 @@ static int git_pack_config(const char *k, const char *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;
|
||||
char line[40 + 1 + PATH_MAX + 2];
|
||||
|
@ -1235,7 +1252,6 @@ int main(int argc, char **argv)
|
|||
int num_preferred_base = 0;
|
||||
int i;
|
||||
|
||||
setup_git_directory();
|
||||
git_config(git_pack_config);
|
||||
|
||||
progress = isatty(2);
|
|
@ -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 */
|
||||
ref += 5;
|
||||
|
||||
if (strncmp(ref, "tags/", 5))
|
||||
return 0;
|
||||
|
||||
add_refspec(strdup(ref));
|
||||
if (!strncmp(ref, "tags/", 5))
|
||||
add_refspec(strdup(ref));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -52,9 +52,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
|
|||
|
||||
git_config(git_default_config);
|
||||
|
||||
newfd = hold_lock_file_for_update(&lock_file, get_index_file());
|
||||
if (newfd < 0)
|
||||
die("unable to create new index file");
|
||||
newfd = hold_lock_file_for_update(&lock_file, get_index_file(), 1);
|
||||
|
||||
if (read_cache() < 0)
|
||||
die("index file corrupt");
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include "builtin.h"
|
||||
#include "cache.h"
|
||||
|
||||
static const char git_symbolic_ref_usage[] =
|
||||
|
@ -17,9 +18,8 @@ static void check_symref(const char *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);
|
||||
switch (argc) {
|
||||
case 2:
|
|
@ -1,3 +1,4 @@
|
|||
#include "builtin.h"
|
||||
#include "cache.h"
|
||||
#include "object.h"
|
||||
#include "delta.h"
|
||||
|
@ -112,7 +113,7 @@ static void write_object(void *buf, unsigned long size, const char *type)
|
|||
}
|
||||
|
||||
static int resolve_delta(const char *type,
|
||||
void *base, unsigned long base_size,
|
||||
void *base, unsigned long base_size,
|
||||
void *delta, unsigned long delta_size)
|
||||
{
|
||||
void *result;
|
||||
|
@ -260,12 +261,12 @@ static void unpack_all(void)
|
|||
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;
|
||||
unsigned char sha1[20];
|
||||
|
||||
setup_git_directory();
|
||||
git_config(git_default_config);
|
||||
|
||||
quiet = !isatty(2);
|
||||
|
|
@ -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() */
|
||||
lock_file = xcalloc(1, sizeof(struct lock_file));
|
||||
|
||||
newfd = hold_lock_file_for_update(lock_file, get_index_file());
|
||||
if (newfd < 0)
|
||||
die("unable to create new cachefile");
|
||||
newfd = hold_lock_file_for_update(lock_file, get_index_file(), 1);
|
||||
|
||||
entries = read_cache();
|
||||
if (entries < 0)
|
||||
|
|
79
builtin-verify-pack.c
Normal file
79
builtin-verify-pack.c
Normal 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;
|
||||
}
|
|
@ -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() */
|
||||
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();
|
||||
if (entries < 0)
|
||||
|
|
98
builtin.h
98
builtin.h
|
@ -8,57 +8,57 @@ extern const char git_version_string[];
|
|||
extern const char git_usage_string[];
|
||||
|
||||
extern void help_unknown_cmd(const char *cmd);
|
||||
|
||||
extern int cmd_help(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_version(int argc, const char **argv, const char *prefix);
|
||||
|
||||
extern int cmd_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 mailinfo(FILE *in, FILE *out, int ks, const char *encoding, const char *msg, const char *patch);
|
||||
extern int split_mbox(const char **mbox, const char *dir, int allow_bare, int nr_prec, int skip);
|
||||
extern void stripspace(FILE *in, FILE *out);
|
||||
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 split_mbox(const char **mbox, const char *dir, int allow_bare, int nr_prec, int skip);
|
||||
|
||||
extern int cmd_add(int argc, const char **argv, const char *prefix);
|
||||
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 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 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
|
||||
|
|
4
cache.h
4
cache.h
|
@ -178,7 +178,7 @@ struct lock_file {
|
|||
struct lock_file *next;
|
||||
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 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_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_index(const unsigned char *sha1);
|
||||
|
|
|
@ -7,13 +7,6 @@
|
|||
#include "xdiff-interface.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)
|
||||
{
|
||||
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++) {
|
||||
int len;
|
||||
const char *path;
|
||||
if (uninteresting(q->queue[i]))
|
||||
if (diff_unmodified_pair(q->queue[i]))
|
||||
continue;
|
||||
path = q->queue[i]->two->path;
|
||||
len = strlen(path);
|
||||
|
@ -57,7 +50,7 @@ static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr,
|
|||
const char *path;
|
||||
int len;
|
||||
|
||||
if (uninteresting(q->queue[i]))
|
||||
if (diff_unmodified_pair(q->queue[i]))
|
||||
continue;
|
||||
path = q->queue[i]->two->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);
|
||||
}
|
||||
|
||||
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);
|
||||
int i;
|
||||
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)
|
||||
return; /* result deleted */
|
||||
|
@ -522,12 +521,13 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent)
|
|||
rlines = hunk_end - lno;
|
||||
if (cnt < hunk_end)
|
||||
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++)
|
||||
show_parent_lno(sline, lno, hunk_end, i);
|
||||
printf(" +%lu,%lu ", lno+1, rlines);
|
||||
for (i = 0; i <= num_parent; i++) putchar(combine_marker);
|
||||
putchar('\n');
|
||||
printf("%s\n", c_reset);
|
||||
while (lno < hunk_end) {
|
||||
struct lline *ll;
|
||||
int j;
|
||||
|
@ -535,18 +535,23 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent)
|
|||
sl = &sline[lno++];
|
||||
ll = sl->lost_head;
|
||||
while (ll) {
|
||||
fputs(c_old, stdout);
|
||||
for (j = 0; j < num_parent; j++) {
|
||||
if (ll->parent_map & (1UL<<j))
|
||||
putchar('-');
|
||||
else
|
||||
putchar(' ');
|
||||
}
|
||||
puts(ll->line);
|
||||
printf("%s%s\n", ll->line, c_reset);
|
||||
ll = ll->next;
|
||||
}
|
||||
if (cnt < lno)
|
||||
break;
|
||||
p_mask = 1;
|
||||
if (!(sl->flag & (mark-1)))
|
||||
fputs(c_plain, stdout);
|
||||
else
|
||||
fputs(c_new, stdout);
|
||||
for (j = 0; j < num_parent; j++) {
|
||||
if (p_mask & sl->flag)
|
||||
putchar('+');
|
||||
|
@ -554,7 +559,7 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent)
|
|||
putchar(' ');
|
||||
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];
|
||||
}
|
||||
|
||||
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))
|
||||
quote_c_style(path, NULL, stdout, 0);
|
||||
else
|
||||
printf("%s", path);
|
||||
putchar('\n');
|
||||
printf("%s\n", c_reset);
|
||||
}
|
||||
|
||||
static int show_patch_diff(struct combine_diff_path *elem, int num_parent,
|
||||
int dense, struct rev_info *rev)
|
||||
static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
|
||||
int dense, struct rev_info *rev)
|
||||
{
|
||||
struct diff_options *opt = &rev->diffopt;
|
||||
unsigned long result_size, cnt, lno;
|
||||
char *result, *cp;
|
||||
struct sline *sline; /* survived lines */
|
||||
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 abbrev = opt->full_index ? 40 : DEFAULT_ABBREV;
|
||||
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) {
|
||||
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)
|
||||
show_log(rev, opt->msg_sep);
|
||||
dump_quoted_path(dense ? "diff --cc " : "diff --combined ", elem->path);
|
||||
printf("index ");
|
||||
dump_quoted_path(dense ? "diff --cc " : "diff --combined ",
|
||||
elem->path, c_meta, c_reset);
|
||||
printf("%sindex ", c_meta);
|
||||
for (i = 0; i < num_parent; i++) {
|
||||
abb = find_unique_abbrev(elem->parent[i].sha1,
|
||||
abbrev);
|
||||
printf("%s%s", i ? "," : "", abb);
|
||||
}
|
||||
abb = find_unique_abbrev(elem->sha1, abbrev);
|
||||
printf("..%s\n", abb);
|
||||
printf("..%s%s\n", abb, c_reset);
|
||||
|
||||
if (mode_differs) {
|
||||
int added = !!elem->mode;
|
||||
|
@ -719,10 +729,11 @@ static int show_patch_diff(struct combine_diff_path *elem, int num_parent,
|
|||
DIFF_STATUS_ADDED)
|
||||
added = 0;
|
||||
if (added)
|
||||
printf("new file mode %06o", elem->mode);
|
||||
printf("%snew file mode %06o",
|
||||
c_meta, elem->mode);
|
||||
else {
|
||||
if (!elem->mode)
|
||||
printf("deleted file ");
|
||||
printf("%sdeleted file ", c_meta);
|
||||
printf("mode ");
|
||||
for (i = 0; i < num_parent; 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)
|
||||
printf("..%06o", elem->mode);
|
||||
}
|
||||
putchar('\n');
|
||||
printf("%s\n", c_reset);
|
||||
}
|
||||
dump_quoted_path("--- a/", elem->path);
|
||||
dump_quoted_path("+++ b/", elem->path);
|
||||
dump_sline(sline, cnt, num_parent);
|
||||
dump_quoted_path("--- a/", elem->path, c_meta, c_reset);
|
||||
dump_quoted_path("+++ b/", elem->path, c_meta, c_reset);
|
||||
dump_sline(sline, cnt, num_parent, opt->color_diff);
|
||||
}
|
||||
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);
|
||||
return shown_header;
|
||||
}
|
||||
|
||||
#define COLONS "::::::::::::::::::::::::::::::::"
|
||||
|
@ -819,11 +829,10 @@ void show_combined_diff(struct combine_diff_path *p,
|
|||
return;
|
||||
if (opt->output_format & (DIFF_FORMAT_RAW |
|
||||
DIFF_FORMAT_NAME |
|
||||
DIFF_FORMAT_NAME_STATUS)) {
|
||||
DIFF_FORMAT_NAME_STATUS))
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void diff_tree_combined(const unsigned char *sha1,
|
||||
|
|
|
@ -22,3 +22,19 @@ VPATH = @srcdir@
|
|||
export exec_prefix mandir
|
||||
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@
|
||||
|
||||
|
|
242
configure.ac
242
configure.ac
|
@ -2,7 +2,7 @@
|
|||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
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])
|
||||
|
||||
|
@ -19,6 +19,77 @@ echo "# ${config_append}. Generated by configure." > "${config_append}"
|
|||
# Append LINE to file ${config_append}
|
||||
AC_DEFUN([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.
|
||||
|
@ -30,6 +101,16 @@ AC_CHECK_TOOL(AR, ar, :)
|
|||
AC_CHECK_PROGS(TAR, [gtar tar])
|
||||
#
|
||||
# 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.
|
||||
|
@ -37,32 +118,43 @@ AC_MSG_NOTICE([CHECKS for libraries])
|
|||
#
|
||||
# Define NO_OPENSSL environment variable if you do not have OpenSSL.
|
||||
# Define NEEDS_SSL_WITH_CRYPTO if you need -lcrypto with -lssl (Darwin).
|
||||
AC_CHECK_LIB([ssl], [SHA1_Init],[],
|
||||
[AC_CHECK_LIB([crypto], [SHA1_INIT],
|
||||
[GIT_CONF_APPEND_LINE(NEEDS_SSL_WITH_CRYPTO=YesPlease)],
|
||||
[GIT_CONF_APPEND_LINE(NO_OPENSSL=YesPlease)])])
|
||||
AC_CHECK_LIB([crypto], [SHA1_Init],
|
||||
[NEEDS_SSL_WITH_CRYPTO=],
|
||||
[AC_CHECK_LIB([ssl], [SHA1_Init],
|
||||
[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
|
||||
# git-http-push are not built, and you cannot use http:// and https://
|
||||
# transports.
|
||||
AC_CHECK_LIB([curl], [curl_global_init],[],
|
||||
[GIT_CONF_APPEND_LINE(NO_CURL=YesPlease)])
|
||||
AC_CHECK_LIB([curl], [curl_global_init],
|
||||
[NO_CURL=],
|
||||
[NO_CURL=YesPlease])
|
||||
AC_SUBST(NO_CURL)
|
||||
#
|
||||
# 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.
|
||||
AC_CHECK_LIB([expat], [XML_ParserCreate],[],
|
||||
[GIT_CONF_APPEND_LINE(NO_EXPAT=YesPlease)])
|
||||
AC_CHECK_LIB([expat], [XML_ParserCreate],
|
||||
[NO_EXPAT=],
|
||||
[NO_EXPAT=YesPlease])
|
||||
AC_SUBST(NO_EXPAT)
|
||||
#
|
||||
# Define NEEDS_LIBICONV if linking with libc is not enough (Darwin).
|
||||
AC_CHECK_LIB([c], [iconv],[],
|
||||
[AC_CHECK_LIB([iconv],[iconv],
|
||||
[GIT_CONF_APPEND_LINE(NEEDS_LIBICONV=YesPlease)],[])])
|
||||
AC_CHECK_LIB([c], [iconv],
|
||||
[NEEDS_LIBICONV=],
|
||||
[NEEDS_LIBICONV=YesPlease])
|
||||
AC_SUBST(NEEDS_LIBICONV)
|
||||
#
|
||||
# Define NEEDS_SOCKET if linking with libc is not enough (SunOS,
|
||||
# Patrick Mauritz).
|
||||
AC_CHECK_LIB([c], [socket],[],
|
||||
[AC_CHECK_LIB([socket],[socket],
|
||||
[GIT_CONF_APPEND_LINE(NEEDS_SOCKET=YesPlease)],[])])
|
||||
AC_CHECK_LIB([c], [socket],
|
||||
[NEEDS_SOCKET=],
|
||||
[NEEDS_SOCKET=YesPlease])
|
||||
AC_SUBST(NEEDS_SOCKET)
|
||||
test -n "$NEEDS_SOCKET" && LIBS="$LIBS -lsocket"
|
||||
|
||||
|
||||
## Checks for header files.
|
||||
|
@ -72,21 +164,65 @@ AC_CHECK_LIB([c], [socket],[],
|
|||
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.
|
||||
AC_CHECK_MEMBER(struct dirent.d_ino,[],
|
||||
[GIT_CONF_APPEND_LINE(NO_D_INO_IN_DIRENT=YesPlease)],
|
||||
AC_CHECK_MEMBER(struct dirent.d_ino,
|
||||
[NO_D_INO_IN_DIRENT=],
|
||||
[NO_D_INO_IN_DIRENT=YesPlease],
|
||||
[#include <dirent.h>])
|
||||
AC_SUBST(NO_D_INO_IN_DIRENT)
|
||||
#
|
||||
# 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).
|
||||
AC_CHECK_MEMBER(struct dirent.d_type,[],
|
||||
[GIT_CONF_APPEND_LINE(NO_D_TYPE_IN_DIRENT=YesPlease)],
|
||||
AC_CHECK_MEMBER(struct dirent.d_type,
|
||||
[NO_D_TYPE_IN_DIRENT=],
|
||||
[NO_D_TYPE_IN_DIRENT=YesPlease],
|
||||
[#include <dirent.h>])
|
||||
AC_SUBST(NO_D_TYPE_IN_DIRENT)
|
||||
#
|
||||
# Define NO_SOCKADDR_STORAGE if your platform does not have struct
|
||||
# sockaddr_storage.
|
||||
AC_CHECK_TYPE(struct sockaddr_storage,[],
|
||||
[GIT_CONF_APPEND_LINE(NO_SOCKADDR_STORAGE=YesPlease)],
|
||||
[#include <netinet/in.h>])
|
||||
AC_CHECK_TYPE(struct sockaddr_storage,
|
||||
[NO_SOCKADDR_STORAGE=],
|
||||
[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.
|
||||
|
@ -94,21 +230,25 @@ AC_CHECK_TYPE(struct sockaddr_storage,[],
|
|||
AC_MSG_NOTICE([CHECKS for library functions])
|
||||
#
|
||||
# Define NO_STRCASESTR if you don't have strcasestr.
|
||||
AC_CHECK_FUNC(strcasestr,[],
|
||||
[GIT_CONF_APPEND_LINE(NO_STRCASESTR=YesPlease)])
|
||||
AC_CHECK_FUNC(strcasestr,
|
||||
[NO_STRCASESTR=],
|
||||
[NO_STRCASESTR=YesPlease])
|
||||
AC_SUBST(NO_STRCASESTR)
|
||||
#
|
||||
# Define NO_STRLCPY if you don't have strlcpy.
|
||||
AC_CHECK_FUNC(strlcpy,[],
|
||||
[GIT_CONF_APPEND_LINE(NO_STRLCPY=YesPlease)])
|
||||
AC_CHECK_FUNC(strlcpy,
|
||||
[NO_STRLCPY=],
|
||||
[NO_STRLCPY=YesPlease])
|
||||
AC_SUBST(NO_STRLCPY)
|
||||
#
|
||||
# Define NO_SETENV if you don't have setenv in the C library.
|
||||
AC_CHECK_FUNC(setenv,[],
|
||||
[GIT_CONF_APPEND_LINE(NO_SETENV=YesPlease)])
|
||||
AC_CHECK_FUNC(setenv,
|
||||
[NO_SETENV=],
|
||||
[NO_SETENV=YesPlease])
|
||||
AC_SUBST(NO_SETENV)
|
||||
#
|
||||
# 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.
|
||||
|
||||
|
||||
|
@ -125,9 +265,11 @@ AC_CHECK_FUNC(setenv,[],
|
|||
# a missing newline at the end of the file.
|
||||
|
||||
|
||||
## Site configuration
|
||||
## Site configuration (override autodetection)
|
||||
## --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
|
||||
# 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.
|
||||
# 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
|
||||
# git-http-push are not built, and you cannot use http:// and https://
|
||||
# transports.
|
||||
#
|
||||
# Define CURLDIR=/foo/bar if your curl header and library files are in
|
||||
# /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
|
||||
# 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_PYTHON if you want to loose all benefits of the recursive merge.
|
||||
#
|
||||
|
||||
## --enable-FEATURE[=ARG] and --disable-FEATURE
|
||||
#
|
||||
# Define COLLISION_CHECK below if you believe that SHA1's
|
||||
# 1461501637330902918203684832716283019655932542976 hashes do not give you
|
||||
# sufficient guarantee that no collisions between objects will ever happen.
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#define _XOPEN_SOURCE 500 /* glibc2 and AIX 5.3L need this */
|
||||
#define _XOPEN_SOURCE_EXTENDED 1 /* AIX 5.3L needs this */
|
||||
#define _GNU_SOURCE
|
||||
#include <time.h>
|
||||
#include "cache.h"
|
||||
#include "blob.h"
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "cache.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;
|
||||
|
||||
|
@ -21,7 +21,7 @@ static int sha1flush(struct sha1file *f, unsigned int count)
|
|||
count -= ret;
|
||||
if (count)
|
||||
continue;
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
if (!ret)
|
||||
die("sha1 file '%s' write error. Out of diskspace", f->name);
|
||||
|
|
201
diff.c
201
diff.c
|
@ -358,12 +358,152 @@ static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one)
|
|||
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 xdiff_emit_state xm;
|
||||
int nparents, color_diff;
|
||||
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)
|
||||
{
|
||||
if (diff_use_color)
|
||||
|
@ -398,12 +538,31 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
|
|||
else {
|
||||
int nparents = ecbdata->nparents;
|
||||
int color = DIFF_PLAIN;
|
||||
for (i = 0; i < nparents && len; i++) {
|
||||
if (line[i] == '-')
|
||||
color = DIFF_FILE_OLD;
|
||||
else if (line[i] == '+')
|
||||
color = DIFF_FILE_NEW;
|
||||
}
|
||||
if (ecbdata->diff_words && nparents != 1)
|
||||
/* fall back to normal diff */
|
||||
free_diff_words_data(ecbdata);
|
||||
if (ecbdata->diff_words) {
|
||||
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);
|
||||
}
|
||||
if (len > 0 && line[len-1] == '\n')
|
||||
|
@ -745,9 +904,7 @@ static int mmfile_is_binary(mmfile_t *mf)
|
|||
long sz = mf->size;
|
||||
if (FIRST_FEW_BYTES < sz)
|
||||
sz = FIRST_FEW_BYTES;
|
||||
if (memchr(mf->ptr, 0, sz))
|
||||
return 1;
|
||||
return 0;
|
||||
return !!memchr(mf->ptr, 0, sz);
|
||||
}
|
||||
|
||||
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.priv = &ecbdata;
|
||||
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);
|
||||
if (o->color_diff_words)
|
||||
free_diff_words_data(&ecbdata);
|
||||
}
|
||||
|
||||
free_ab_and_return:
|
||||
|
@ -1515,10 +1677,21 @@ void diff_setup(struct diff_options *options)
|
|||
|
||||
int diff_setup_done(struct diff_options *options)
|
||||
{
|
||||
if ((options->find_copies_harder &&
|
||||
options->detect_rename != DIFF_DETECT_COPY) ||
|
||||
(0 <= options->rename_limit && !options->detect_rename))
|
||||
return -1;
|
||||
int count = 0;
|
||||
|
||||
if (options->output_format & DIFF_FORMAT_NAME)
|
||||
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 |
|
||||
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;
|
||||
else if (!strcmp(arg, "-b") || !strcmp(arg, "--ignore-space-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"))
|
||||
options->detect_rename = 0;
|
||||
else
|
||||
|
|
3
diff.h
3
diff.h
|
@ -46,7 +46,8 @@ struct diff_options {
|
|||
full_index:1,
|
||||
silent_on_remove:1,
|
||||
find_copies_harder:1,
|
||||
color_diff:1;
|
||||
color_diff:1,
|
||||
color_diff_words:1;
|
||||
int context;
|
||||
int break_opt;
|
||||
int detect_rename;
|
||||
|
|
|
@ -366,13 +366,13 @@ static void add_sha1_list(unsigned char *sha1, unsigned long ino)
|
|||
sha1_list.nr = ++nr;
|
||||
}
|
||||
|
||||
static int fsck_dir(int i, char *path)
|
||||
static void fsck_dir(int i, char *path)
|
||||
{
|
||||
DIR *dir = opendir(path);
|
||||
struct dirent *de;
|
||||
|
||||
if (!dir)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
while ((de = readdir(dir)) != NULL) {
|
||||
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);
|
||||
}
|
||||
closedir(dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int default_refs = 0;
|
||||
|
|
28
git-am.sh
28
git-am.sh
|
@ -45,6 +45,12 @@ go_next () {
|
|||
this=$next
|
||||
}
|
||||
|
||||
cannot_fallback () {
|
||||
echo "$1"
|
||||
echo "Cannot fall back to three-way merge."
|
||||
exit 1
|
||||
}
|
||||
|
||||
fall_back_3way () {
|
||||
O_OBJECT=`cd "$GIT_OBJECT_DIRECTORY" && pwd`
|
||||
|
||||
|
@ -52,19 +58,23 @@ fall_back_3way () {
|
|||
mkdir "$dotest/patch-merge-tmp-dir"
|
||||
|
||||
# First see if the patch records the index info that we can use.
|
||||
if git-apply -z --index-info "$dotest/patch" \
|
||||
>"$dotest/patch-merge-index-info" 2>/dev/null &&
|
||||
GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \
|
||||
git-update-index -z --index-info <"$dotest/patch-merge-index-info" &&
|
||||
GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \
|
||||
git-write-tree >"$dotest/patch-merge-base+" &&
|
||||
# index has the base tree now.
|
||||
GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \
|
||||
git-apply -z --index-info "$dotest/patch" \
|
||||
>"$dotest/patch-merge-index-info" &&
|
||||
GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \
|
||||
git-update-index -z --index-info <"$dotest/patch-merge-index-info" &&
|
||||
GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \
|
||||
git-write-tree >"$dotest/patch-merge-base+" ||
|
||||
cannot_fallback "Patch does not record usable index information."
|
||||
|
||||
echo Using index info to reconstruct a base tree...
|
||||
if GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \
|
||||
git-apply $binary --cached <"$dotest/patch"
|
||||
then
|
||||
echo Using index info to reconstruct a base tree...
|
||||
mv "$dotest/patch-merge-base+" "$dotest/patch-merge-base"
|
||||
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
|
||||
|
||||
test -f "$dotest/patch-merge-index" &&
|
||||
|
|
|
@ -91,6 +91,9 @@ static inline void *xmalloc(size_t size)
|
|||
ret = malloc(1);
|
||||
if (!ret)
|
||||
die("Out of memory, malloc failed");
|
||||
#ifdef XMALLOC_POISON
|
||||
memset(ret, 0xA5, size);
|
||||
#endif
|
||||
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 */
|
||||
#undef isspace
|
||||
#undef isdigit
|
||||
|
|
|
@ -35,17 +35,12 @@ case "$1" in
|
|||
exit
|
||||
esac
|
||||
|
||||
# Make sure we are in a valid repository of a vintage we understand.
|
||||
if [ -z "$SUBDIRECTORY_OK" ]
|
||||
then
|
||||
: ${GIT_DIR=.git}
|
||||
: ${GIT_OBJECT_DIRECTORY="$GIT_DIR/objects"}
|
||||
|
||||
# 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
|
||||
GIT_DIR=$(GIT_DIR="$GIT_DIR" git-rev-parse --git-dir) || exit
|
||||
else
|
||||
GIT_DIR=$(git-rev-parse --git-dir) || exit
|
||||
fi
|
||||
: ${GIT_OBJECT_DIRECTORY="$GIT_DIR/objects"}
|
||||
|
|
75
git-svn.perl
75
git-svn.perl
|
@ -31,6 +31,7 @@
|
|||
use File::Path qw/mkpath/;
|
||||
use Getopt::Long qw/:config gnu_getopt no_ignore_case auto_abbrev pass_through/;
|
||||
use File::Spec qw//;
|
||||
use File::Copy qw/copy/;
|
||||
use POSIX qw/strftime/;
|
||||
use IPC::Open3;
|
||||
use Memoize;
|
||||
|
@ -77,9 +78,6 @@
|
|||
'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 = (
|
||||
fetch => [ \&fetch, "Download new revisions from SVN",
|
||||
{ '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) {
|
||||
while (1) {
|
||||
$SVN = libsvn_connect($url);
|
||||
last if (defined $SVN &&
|
||||
defined eval { $SVN->get_latest_revnum });
|
||||
my $n = shift @paths || last;
|
||||
$url .= "/$n";
|
||||
}
|
||||
my $tmp = libsvn_connect($full_url);
|
||||
my $url = $tmp->get_repos_root;
|
||||
$full_url =~ s#^\Q$url\E/*##;
|
||||
push @repo_path_split_cache, qr/^(\Q$url\E)/;
|
||||
return ($url, $full_url);
|
||||
} 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)) {
|
||||
my $n = shift @paths || last;
|
||||
$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 {
|
||||
|
@ -1760,43 +1755,6 @@ sub svn_info {
|
|||
|
||||
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 {
|
||||
my ($z_cmd, $cmd, $no_text_base) = @_;
|
||||
|
||||
|
@ -1824,9 +1782,11 @@ sub do_update_index {
|
|||
'text-base',"$f.svn-base");
|
||||
$tb =~ s#^/##;
|
||||
}
|
||||
my @s = stat($x);
|
||||
unlink $x or croak $!;
|
||||
eol_cp($tb, $x);
|
||||
copy($tb, $x);
|
||||
chmod(($mode &~ umask), $x) or croak $!;
|
||||
utime $s[8], $s[9], $x;
|
||||
}
|
||||
print $ui $x,"\0";
|
||||
}
|
||||
|
@ -2617,7 +2577,9 @@ sub libsvn_connect {
|
|||
sub libsvn_get_file {
|
||||
my ($gui, $f, $rev) = @_;
|
||||
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 $pool = SVN::Pool->new;
|
||||
|
@ -2664,6 +2626,7 @@ sub libsvn_log_entry {
|
|||
if (defined $_authors && ! defined $users{$author}) {
|
||||
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",
|
||||
author => $author, msg => $msg."\n", parents => $parents || [] }
|
||||
}
|
||||
|
|
88
git.c
88
git.c
|
@ -213,8 +213,8 @@ static int handle_alias(int *argcp, const char ***argv)
|
|||
|
||||
const char git_version_string[] = GIT_VERSION;
|
||||
|
||||
#define NEEDS_PREFIX 1
|
||||
#define USE_PAGER 2
|
||||
#define RUN_SETUP (1<<0)
|
||||
#define USE_PAGER (1<<1)
|
||||
|
||||
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 option;
|
||||
} commands[] = {
|
||||
{ "version", cmd_version },
|
||||
{ "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 },
|
||||
{ "add", cmd_add, RUN_SETUP },
|
||||
{ "apply", cmd_apply },
|
||||
{ "show-branch", cmd_show_branch, NEEDS_PREFIX },
|
||||
{ "diff-files", cmd_diff_files, NEEDS_PREFIX },
|
||||
{ "diff-index", cmd_diff_index, NEEDS_PREFIX },
|
||||
{ "diff-stages", cmd_diff_stages, NEEDS_PREFIX },
|
||||
{ "diff-tree", cmd_diff_tree, NEEDS_PREFIX },
|
||||
{ "cat-file", cmd_cat_file, NEEDS_PREFIX },
|
||||
{ "rev-parse", cmd_rev_parse, NEEDS_PREFIX },
|
||||
{ "write-tree", cmd_write_tree, NEEDS_PREFIX },
|
||||
{ "mailsplit", cmd_mailsplit },
|
||||
{ "cat-file", cmd_cat_file, RUN_SETUP },
|
||||
{ "checkout-index", cmd_checkout_index, RUN_SETUP },
|
||||
{ "check-ref-format", cmd_check_ref_format },
|
||||
{ "commit-tree", cmd_commit_tree, RUN_SETUP },
|
||||
{ "count-objects", cmd_count_objects },
|
||||
{ "diff", cmd_diff, RUN_SETUP },
|
||||
{ "diff-files", cmd_diff_files, RUN_SETUP },
|
||||
{ "diff-index", cmd_diff_index, RUN_SETUP },
|
||||
{ "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 },
|
||||
{ "stripspace", cmd_stripspace },
|
||||
{ "update-index", cmd_update_index, NEEDS_PREFIX },
|
||||
{ "update-ref", cmd_update_ref, NEEDS_PREFIX },
|
||||
{ "fmt-merge-msg", cmd_fmt_merge_msg, NEEDS_PREFIX },
|
||||
{ "prune", cmd_prune, NEEDS_PREFIX },
|
||||
{ "mv", cmd_mv, NEEDS_PREFIX },
|
||||
{ "prune-packed", cmd_prune_packed, NEEDS_PREFIX },
|
||||
{ "mailsplit", cmd_mailsplit },
|
||||
{ "mv", cmd_mv, RUN_SETUP },
|
||||
{ "name-rev", cmd_name_rev, RUN_SETUP },
|
||||
{ "pack-objects", cmd_pack_objects, RUN_SETUP },
|
||||
{ "prune", cmd_prune, RUN_SETUP },
|
||||
{ "prune-packed", cmd_prune_packed, RUN_SETUP },
|
||||
{ "push", cmd_push, RUN_SETUP },
|
||||
{ "read-tree", cmd_read_tree, RUN_SETUP },
|
||||
{ "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;
|
||||
|
||||
|
@ -281,7 +287,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
|
|||
continue;
|
||||
|
||||
prefix = NULL;
|
||||
if (p->option & NEEDS_PREFIX)
|
||||
if (p->option & RUN_SETUP)
|
||||
prefix = setup_git_directory();
|
||||
if (p->option & USE_PAGER)
|
||||
setup_pager();
|
||||
|
|
147
gitk
147
gitk
|
@ -312,7 +312,7 @@ proc getcommit {id} {
|
|||
|
||||
proc readrefs {} {
|
||||
global tagids idtags headids idheads tagcontents
|
||||
global otherrefids idotherrefs
|
||||
global otherrefids idotherrefs mainhead
|
||||
|
||||
foreach v {tagids idtags headids idheads otherrefids idotherrefs} {
|
||||
catch {unset $v}
|
||||
|
@ -358,6 +358,13 @@ proc readrefs {} {
|
|||
}
|
||||
}
|
||||
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} {
|
||||
|
@ -386,6 +393,7 @@ proc makewindow {} {
|
|||
global rowctxmenu mergemax wrapcomment
|
||||
global highlight_files gdttype
|
||||
global searchstring sstring
|
||||
global bgcolor fgcolor bglist fglist diffcolors
|
||||
|
||||
menu .bar
|
||||
.bar add cascade -label "File" -menu .bar.file
|
||||
|
@ -446,18 +454,19 @@ proc makewindow {} {
|
|||
.ctop add .ctop.top
|
||||
set canv .ctop.top.clist.canv
|
||||
canvas $canv -height $geometry(canvh) -width $geometry(canv1) \
|
||||
-bg white -bd 0 \
|
||||
-background $bgcolor -bd 0 \
|
||||
-yscrollincr $linespc -yscrollcommand "scrollcanv $cscroll"
|
||||
.ctop.top.clist add $canv
|
||||
set canv2 .ctop.top.clist.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
|
||||
set canv3 .ctop.top.clist.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
|
||||
bind .ctop.top.clist <Configure> {resizeclistpanes %W %w}
|
||||
lappend bglist $canv $canv2 $canv3
|
||||
|
||||
set sha1entry .ctop.top.bar.sha1
|
||||
set entries $sha1entry
|
||||
|
@ -563,19 +572,22 @@ proc makewindow {} {
|
|||
trace add variable searchstring write incrsearch
|
||||
pack $sstring -side left -expand 1 -fill x
|
||||
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) \
|
||||
-yscrollcommand scrolltext -wrap none
|
||||
scrollbar .ctop.cdet.left.sb -command "$ctext yview"
|
||||
pack .ctop.cdet.left.sb -side right -fill y
|
||||
pack $ctext -side left -fill both -expand 1
|
||||
.ctop.cdet add .ctop.cdet.left
|
||||
lappend bglist $ctext
|
||||
lappend fglist $ctext
|
||||
|
||||
$ctext tag conf comment -wrap $wrapcomment
|
||||
$ctext tag conf filesep -font [concat $textfont bold] -back "#aaaaaa"
|
||||
$ctext tag conf hunksep -fore blue
|
||||
$ctext tag conf d0 -fore red
|
||||
$ctext tag conf d1 -fore "#00a000"
|
||||
$ctext tag conf hunksep -fore [lindex $diffcolors 2]
|
||||
$ctext tag conf d0 -fore [lindex $diffcolors 0]
|
||||
$ctext tag conf d1 -fore [lindex $diffcolors 1]
|
||||
$ctext tag conf m0 -fore red
|
||||
$ctext tag conf m1 -fore blue
|
||||
$ctext tag conf m2 -fore green
|
||||
|
@ -608,11 +620,15 @@ proc makewindow {} {
|
|||
pack .ctop.cdet.right.mode -side top -fill x
|
||||
set cflist .ctop.cdet.right.cfiles
|
||||
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}]] \
|
||||
-yscrollcommand ".ctop.cdet.right.sb set" \
|
||||
-cursor [. cget -cursor] \
|
||||
-spacing1 1 -spacing3 1
|
||||
lappend bglist $cflist
|
||||
lappend fglist $cflist
|
||||
scrollbar .ctop.cdet.right.sb -command "$cflist yview"
|
||||
pack .ctop.cdet.right.sb -side right -fill y
|
||||
pack $cflist -side left -fill both -expand 1
|
||||
|
@ -747,6 +763,7 @@ proc savestuff {w} {
|
|||
global maxwidth showneartags
|
||||
global viewname viewfiles viewargs viewperm nextviewnum
|
||||
global cmitmode wrapcomment
|
||||
global colors bgcolor fgcolor diffcolors
|
||||
|
||||
if {$stuffsaved} return
|
||||
if {![winfo viewable .]} return
|
||||
|
@ -761,6 +778,10 @@ proc savestuff {w} {
|
|||
puts $f [list set cmitmode $cmitmode]
|
||||
puts $f [list set wrapcomment $wrapcomment]
|
||||
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(height) [winfo height .ctop]"
|
||||
puts $f "set geometry(canv1) [expr {[winfo width $canv]-2}]"
|
||||
|
@ -2870,11 +2891,11 @@ proc drawlines {id} {
|
|||
}
|
||||
|
||||
proc drawcmittext {id row col rmx} {
|
||||
global linespc canv canv2 canv3 canvy0
|
||||
global linespc canv canv2 canv3 canvy0 fgcolor
|
||||
global commitlisted commitinfo rowidlist
|
||||
global rowtextx idpos idtags idheads idotherrefs
|
||||
global linehtag linentag linedtag
|
||||
global mainfont canvxmax boldrows boldnamerows
|
||||
global mainfont canvxmax boldrows boldnamerows fgcolor
|
||||
|
||||
set ofill [expr {[lindex $commitlisted $row]? "blue": "white"}]
|
||||
set x [xc $row $col]
|
||||
|
@ -2882,7 +2903,7 @@ proc drawcmittext {id row col rmx} {
|
|||
set orad [expr {$linespc / 3}]
|
||||
set t [$canv create oval [expr {$x - $orad}] [expr {$y - $orad}] \
|
||||
[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 bind $t <1> {selcanvline {} %x %y}
|
||||
set xt [xc $row [llength [lindex $rowidlist $row]]]
|
||||
|
@ -2910,13 +2931,13 @@ proc drawcmittext {id row col rmx} {
|
|||
lappend nfont bold
|
||||
}
|
||||
}
|
||||
set linehtag($row) [$canv create text $xt $y -anchor w \
|
||||
-text $headline -font $font]
|
||||
set linehtag($row) [$canv create text $xt $y -anchor w -fill $fgcolor \
|
||||
-text $headline -font $font -tags text]
|
||||
$canv bind $linehtag($row) <Button-3> "rowmenu %X %Y $id"
|
||||
set linentag($row) [$canv2 create text 3 $y -anchor w \
|
||||
-text $name -font $nfont]
|
||||
set linedtag($row) [$canv3 create text 3 $y -anchor w \
|
||||
-text $date -font $mainfont]
|
||||
set linentag($row) [$canv2 create text 3 $y -anchor w -fill $fgcolor \
|
||||
-text $name -font $nfont -tags text]
|
||||
set linedtag($row) [$canv3 create text 3 $y -anchor w -fill $fgcolor \
|
||||
-text $date -font $mainfont -tags text]
|
||||
set xr [expr {$xt + [font measure $mainfont $headline]}]
|
||||
if {$xr > $canvxmax} {
|
||||
set canvxmax $xr
|
||||
|
@ -3136,9 +3157,9 @@ proc bindline {t id} {
|
|||
}
|
||||
|
||||
proc drawtags {id x xt y1} {
|
||||
global idtags idheads idotherrefs
|
||||
global idtags idheads idotherrefs mainhead
|
||||
global linespc lthickness
|
||||
global canv mainfont commitrow rowtextx curview
|
||||
global canv mainfont commitrow rowtextx curview fgcolor bgcolor
|
||||
|
||||
set marks {}
|
||||
set ntags 0
|
||||
|
@ -3163,8 +3184,14 @@ proc drawtags {id x xt y1} {
|
|||
set yb [expr {$yt + $linespc - 1}]
|
||||
set xvals {}
|
||||
set wvals {}
|
||||
set i -1
|
||||
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 wvals $wid
|
||||
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 {
|
||||
set xl [expr {$x + $delta}]
|
||||
set xr [expr {$x + $delta + $wid + $lthickness}]
|
||||
set font $mainfont
|
||||
if {[incr ntags -1] >= 0} {
|
||||
# draw a tag
|
||||
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
|
||||
if {[incr nheads -1] >= 0} {
|
||||
set col green
|
||||
if {$tag eq $mainhead} {
|
||||
lappend font bold
|
||||
}
|
||||
} else {
|
||||
set col "#ddddff"
|
||||
}
|
||||
|
@ -3201,8 +3232,8 @@ proc drawtags {id x xt y1} {
|
|||
-width 0 -fill "#ffddaa" -tags tag.$id
|
||||
}
|
||||
}
|
||||
set t [$canv create text $xl $y1 -anchor w -text $tag \
|
||||
-font $mainfont -tags tag.$id]
|
||||
set t [$canv create text $xl $y1 -anchor w -text $tag -fill $fgcolor \
|
||||
-font $font -tags [list tag.$id text]]
|
||||
if {$ntags >= 0} {
|
||||
$canv bind $t <1> [list showtag $tag 1]
|
||||
}
|
||||
|
@ -3223,10 +3254,11 @@ proc xcoord {i level ln} {
|
|||
}
|
||||
|
||||
proc show_status {msg} {
|
||||
global canv mainfont
|
||||
global canv mainfont fgcolor
|
||||
|
||||
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 {} {
|
||||
|
@ -4574,7 +4606,8 @@ proc linehover {} {
|
|||
set t [$canv create rectangle $x0 $y0 $x1 $y1 \
|
||||
-fill \#ffff80 -outline black -width 1 -tags hover]
|
||||
$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
|
||||
}
|
||||
|
||||
|
@ -5242,6 +5275,7 @@ proc doquit {} {
|
|||
proc doprefs {} {
|
||||
global maxwidth maxgraphpct diffopts
|
||||
global oldprefs prefstop showneartags
|
||||
global bgcolor fgcolor ctext diffcolors
|
||||
|
||||
set top .gitkprefs
|
||||
set prefstop $top
|
||||
|
@ -5265,6 +5299,7 @@ proc doprefs {} {
|
|||
-font optionfont
|
||||
spinbox $top.maxpct -from 1 -to 100 -width 4 -textvariable maxgraphpct
|
||||
grid x $top.maxpctl $top.maxpct -sticky w
|
||||
|
||||
label $top.ddisp -text "Diff display options"
|
||||
grid $top.ddisp - -sticky w -pady 10
|
||||
label $top.diffoptl -text "Options for diff program" \
|
||||
|
@ -5276,6 +5311,34 @@ proc doprefs {} {
|
|||
checkbutton $top.ntag.b -variable showneartags
|
||||
pack $top.ntag.b $top.ntag.l -side left
|
||||
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
|
||||
button $top.buts.ok -text "OK" -command prefsok
|
||||
button $top.buts.can -text "Cancel" -command prefscan
|
||||
|
@ -5285,6 +5348,35 @@ proc doprefs {} {
|
|||
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 {} {
|
||||
global maxwidth maxgraphpct diffopts
|
||||
global oldprefs prefstop showneartags
|
||||
|
@ -5620,6 +5712,9 @@ set wrapcomment "none"
|
|||
set showneartags 1
|
||||
|
||||
set colors {green red blue magenta darkgrey brown orange}
|
||||
set bgcolor white
|
||||
set fgcolor black
|
||||
set diffcolors {red "#00a000" blue}
|
||||
|
||||
catch {source ~/.gitk}
|
||||
|
||||
|
|
|
@ -5,5 +5,33 @@ The one working on:
|
|||
|
||||
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>
|
||||
|
||||
Any comment/question/concern to:
|
||||
Git mailing list <git@vger.kernel.org>
|
||||
|
||||
|
|
BIN
gitweb/git-logo.png
Normal file
BIN
gitweb/git-logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 208 B |
|
@ -117,9 +117,14 @@ div.list_head {
|
|||
|
||||
a.list {
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
table.tags a.list {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
a.list:hover {
|
||||
text-decoration: underline;
|
||||
color: #880000;
|
||||
|
@ -171,6 +176,10 @@ tr.dark {
|
|||
background-color: #f6f6f0;
|
||||
}
|
||||
|
||||
tr.dark2 {
|
||||
background-color: #f6f6f0;
|
||||
}
|
||||
|
||||
tr.dark:hover {
|
||||
background-color: #edece6;
|
||||
}
|
||||
|
@ -181,12 +190,16 @@ td {
|
|||
vertical-align: top;
|
||||
}
|
||||
|
||||
td.link {
|
||||
td.link, td.selflink {
|
||||
padding: 2px 5px;
|
||||
font-family: sans-serif;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
td.selflink {
|
||||
padding-right: 0px;
|
||||
}
|
||||
|
||||
td.sha1 {
|
||||
font-family: monospace;
|
||||
}
|
||||
|
@ -196,6 +209,10 @@ td.error {
|
|||
background-color: yellow;
|
||||
}
|
||||
|
||||
td.current_head {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
table.diff_tree span.file_status.new {
|
||||
color: #008000;
|
||||
}
|
||||
|
@ -209,6 +226,10 @@ table.diff_tree span.file_status.mode_chnge {
|
|||
color: #777777;
|
||||
}
|
||||
|
||||
table.diff_tree span.file_status.copied {
|
||||
color: #70a070;
|
||||
}
|
||||
|
||||
/* age2: 60*60*24*2 <= age */
|
||||
table.project_list td.age2, table.blame td.age2 {
|
||||
font-style: italic;
|
||||
|
@ -309,15 +330,30 @@ a.rss_logo:hover {
|
|||
background-color: #ee5500;
|
||||
}
|
||||
|
||||
span.tag {
|
||||
span.refs span {
|
||||
padding: 0px 4px;
|
||||
font-size: 10px;
|
||||
font-weight: normal;
|
||||
background-color: #ffffaa;
|
||||
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;
|
||||
}
|
||||
|
||||
span.refs span.head {
|
||||
background-color: #aaffaa;
|
||||
border-color: #ccffcc #00cc33 #00cc33 #ccffcc;
|
||||
}
|
||||
|
||||
span.atnight {
|
||||
color: #cc0000;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -140,7 +140,7 @@ static void list_commands(const char *exec_path, const char *pattern)
|
|||
continue;
|
||||
|
||||
entlen = strlen(de->d_name);
|
||||
if (4 < entlen && !strcmp(de->d_name + entlen - 4, ".exe"))
|
||||
if (has_extension(de->d_name, ".exe"))
|
||||
entlen -= 4;
|
||||
|
||||
if (longest < entlen)
|
|
@ -870,7 +870,7 @@ static void process_ls_pack(struct remote_ls_ctx *ls)
|
|||
|
||||
if (strlen(ls->dentry_name) == 63 &&
|
||||
!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);
|
||||
setup_index(ls->repo, sha1);
|
||||
}
|
||||
|
|
48
http-push.c
48
http-push.c
|
@ -530,7 +530,7 @@ static void start_put(struct transfer_request *request)
|
|||
request->dest = xmalloc(strlen(request->url) + 14);
|
||||
sprintf(request->dest, "Destination: %s", request->url);
|
||||
posn += 38;
|
||||
*(posn++) = '.';
|
||||
*(posn++) = '_';
|
||||
strcpy(posn, request->lock->token);
|
||||
|
||||
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)
|
||||
{
|
||||
int pipe_fd[2];
|
||||
pid_t merge_base_pid;
|
||||
char line[PATH_MAX + 20];
|
||||
unsigned char merge_sha1[20];
|
||||
int verified = 0;
|
||||
struct commit *head = lookup_commit(head_sha1);
|
||||
struct commit *branch = lookup_commit(branch_sha1);
|
||||
struct commit_list *merge_bases = get_merge_bases(head, branch, 1);
|
||||
|
||||
if (pipe(pipe_fd) < 0)
|
||||
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;
|
||||
return (merge_bases && !merge_bases->next && merge_bases->item == branch);
|
||||
}
|
||||
|
||||
static int delete_remote_branch(char *pattern, int force)
|
||||
|
|
|
@ -447,7 +447,7 @@ int main(int argc, char **argv)
|
|||
usage(index_pack_usage);
|
||||
if (!index_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'",
|
||||
pack_name);
|
||||
index_name_buf = xmalloc(len);
|
||||
|
|
|
@ -43,8 +43,8 @@ static int setup_indices(void)
|
|||
return -1;
|
||||
while ((de = readdir(dir)) != NULL) {
|
||||
int namelen = strlen(de->d_name);
|
||||
if (namelen != 50 ||
|
||||
strcmp(de->d_name + namelen - 5, ".pack"))
|
||||
if (namelen != 50 ||
|
||||
!has_extension(de->d_name, ".pack"))
|
||||
continue;
|
||||
get_sha1_hex(de->d_name + 5, sha1);
|
||||
setup_index(sha1);
|
||||
|
|
10
lockfile.c
10
lockfile.c
|
@ -22,7 +22,7 @@ static void remove_lock_file_on_signal(int 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;
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
char result_file[PATH_MAX];
|
||||
|
|
4
pager.c
4
pager.c
|
@ -15,10 +15,12 @@ void setup_pager(void)
|
|||
{
|
||||
pid_t pid;
|
||||
int fd[2];
|
||||
const char *pager = getenv("PAGER");
|
||||
const char *pager = getenv("GIT_PAGER");
|
||||
|
||||
if (!isatty(1))
|
||||
return;
|
||||
if (!pager)
|
||||
pager = getenv("PAGER");
|
||||
if (!pager)
|
||||
pager = "less";
|
||||
else if (!*pager || !strcmp(pager, "cat"))
|
||||
|
|
85
read-cache.c
85
read-cache.c
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
#include "cache.h"
|
||||
#include "cache-tree.h"
|
||||
#include <time.h>
|
||||
|
||||
/* Index extensions.
|
||||
*
|
||||
|
@ -840,6 +841,18 @@ int read_cache_from(const char *path)
|
|||
static unsigned char write_buffer[WRITE_BUFFER_SIZE];
|
||||
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)
|
||||
{
|
||||
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);
|
||||
buffered += partial;
|
||||
if (buffered == WRITE_BUFFER_SIZE) {
|
||||
SHA1_Update(context, write_buffer, WRITE_BUFFER_SIZE);
|
||||
if (write(fd, write_buffer, WRITE_BUFFER_SIZE) != WRITE_BUFFER_SIZE)
|
||||
write_buffer_len = buffered;
|
||||
if (ce_write_flush(context, fd))
|
||||
return -1;
|
||||
buffered = 0;
|
||||
}
|
||||
|
@ -867,10 +880,8 @@ static int write_index_ext_header(SHA_CTX *context, int fd,
|
|||
{
|
||||
ext = htonl(ext);
|
||||
sz = htonl(sz);
|
||||
if ((ce_write(context, fd, &ext, 4) < 0) ||
|
||||
(ce_write(context, fd, &sz, 4) < 0))
|
||||
return -1;
|
||||
return 0;
|
||||
return ((ce_write(context, fd, &ext, 4) < 0) ||
|
||||
(ce_write(context, fd, &sz, 4) < 0)) ? -1 : 0;
|
||||
}
|
||||
|
||||
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 */
|
||||
SHA1_Final(write_buffer + left, context);
|
||||
left += 20;
|
||||
if (write(fd, write_buffer, left) != left)
|
||||
return -1;
|
||||
return 0;
|
||||
return (write(fd, write_buffer, left) != left) ? -1 : 0;
|
||||
}
|
||||
|
||||
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
|
||||
* $ 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
|
||||
* as index, and if we were to smudge it by resetting its
|
||||
* 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;
|
||||
struct cache_header hdr;
|
||||
int i, removed;
|
||||
int i, removed, recent;
|
||||
struct stat st;
|
||||
time_t now;
|
||||
|
||||
for (i = removed = 0; i < entries; i++)
|
||||
if (!cache[i]->ce_mode)
|
||||
|
@ -983,5 +994,57 @@ int write_cache(int newfd, struct cache_entry **cache, int entries)
|
|||
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);
|
||||
}
|
||||
|
|
10
refs.c
10
refs.c
|
@ -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);
|
||||
if (namelen > 255)
|
||||
continue;
|
||||
if (namelen>5 && !strcmp(de->d_name+namelen-5,".lock"))
|
||||
if (has_extension(de->d_name, ".lock"))
|
||||
continue;
|
||||
memcpy(path + baselen, de->d_name, namelen+1);
|
||||
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))
|
||||
die("unable to create directory for %s", lock->ref_file);
|
||||
lock->lock_fd = hold_lock_file_for_update(lock->lk, lock->ref_file);
|
||||
if (lock->lock_fd < 0) {
|
||||
error("Couldn't open lock file %s: %s",
|
||||
lock->lk->filename, strerror(errno));
|
||||
unlock_ref(lock);
|
||||
return NULL;
|
||||
}
|
||||
lock->lock_fd = hold_lock_file_for_update(lock->lk, lock->ref_file, 1);
|
||||
|
||||
return old_sha1 ? verify_lock(lock, old_sha1, mustexist) : lock;
|
||||
}
|
||||
|
|
|
@ -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.abbrev = revs->abbrev;
|
||||
diff_setup_done(&revs->diffopt);
|
||||
if (diff_setup_done(&revs->diffopt) < 0)
|
||||
die("diff_setup_done failed");
|
||||
|
||||
return left;
|
||||
}
|
||||
|
|
|
@ -111,7 +111,7 @@ static void rev_list(int fd, struct ref *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;
|
||||
|
||||
|
@ -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 end up waiting for the other end instead
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void unmark_and_free(struct commit_list *list, unsigned int mark)
|
||||
|
|
37
sha1_file.c
37
sha1_file.c
|
@ -608,7 +608,7 @@ static void prepare_packed_git_one(char *objdir, int local)
|
|||
int namelen = strlen(de->d_name);
|
||||
struct packed_git *p;
|
||||
|
||||
if (strcmp(de->d_name + namelen - 4, ".idx"))
|
||||
if (!has_extension(de->d_name, ".idx"))
|
||||
continue;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
static void *map_sha1_file_internal(const unsigned char *sha1,
|
||||
unsigned long *size)
|
||||
void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
|
||||
{
|
||||
struct stat st;
|
||||
void *map;
|
||||
|
@ -702,10 +701,26 @@ static void *map_sha1_file_internal(const unsigned char *sha1,
|
|||
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)
|
||||
{
|
||||
unsigned char c;
|
||||
unsigned int word, bits;
|
||||
unsigned int bits;
|
||||
unsigned long size;
|
||||
static const char *typename[8] = {
|
||||
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->avail_out = bufsiz;
|
||||
|
||||
/*
|
||||
* 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)) {
|
||||
if (legacy_loose_object(map)) {
|
||||
inflateInit(stream);
|
||||
return inflate(stream, 0);
|
||||
}
|
||||
|
@ -1264,7 +1273,7 @@ int sha1_object_info(const unsigned char *sha1, char *type, unsigned long *sizep
|
|||
z_stream stream;
|
||||
char hdr[128];
|
||||
|
||||
map = map_sha1_file_internal(sha1, &mapsize);
|
||||
map = map_sha1_file(sha1, &mapsize);
|
||||
if (!map) {
|
||||
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))
|
||||
return read_packed_sha1(sha1, type, size);
|
||||
map = map_sha1_file_internal(sha1, &mapsize);
|
||||
map = map_sha1_file(sha1, &mapsize);
|
||||
if (map) {
|
||||
buf = unpack_sha1_file(map, mapsize, type, size);
|
||||
munmap(map, mapsize);
|
||||
|
@ -1647,7 +1656,7 @@ int write_sha1_to_fd(int fd, const unsigned char *sha1)
|
|||
{
|
||||
int retval;
|
||||
unsigned long objsize;
|
||||
void *buf = map_sha1_file_internal(sha1, &objsize);
|
||||
void *buf = map_sha1_file(sha1, &objsize);
|
||||
|
||||
if (buf) {
|
||||
retval = write_buffer(fd, buf, objsize);
|
||||
|
|
|
@ -199,7 +199,7 @@ const char *find_unique_abbrev(const unsigned char *sha1, int len)
|
|||
|
||||
is_null = !memcmp(sha1, null_sha1, 20);
|
||||
memcpy(hex, sha1_to_hex(sha1), 40);
|
||||
if (len == 40)
|
||||
if (len == 40 || !len)
|
||||
return hex;
|
||||
while (len < 40) {
|
||||
unsigned char sha1_ret[20];
|
||||
|
|
|
@ -88,7 +88,7 @@ test_expect_success setup '
|
|||
+*+ [initial] Initial
|
||||
EOF
|
||||
|
||||
V=`git version | sed -e 's/^git version //'`
|
||||
V=`git version | sed -e 's/^git version //' -e 's/\./\\./g'`
|
||||
while read cmd
|
||||
do
|
||||
case "$cmd" in
|
||||
|
@ -103,7 +103,9 @@ do
|
|||
test_expect_success "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 "\$"
|
||||
} >"$actual" &&
|
||||
if test -f "$expect"
|
||||
|
|
49
t/t4115-apply-symlink.sh
Executable file
49
t/t4115-apply-symlink.sh
Executable 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
46
t/t4116-apply-reverse.sh
Executable 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
|
|
@ -3,7 +3,7 @@
|
|||
# Copyright (c) 2006 Junio C Hamano
|
||||
#
|
||||
|
||||
test_description='git grep -w
|
||||
test_description='git grep various.
|
||||
'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
@ -19,7 +19,9 @@ test_expect_success setup '
|
|||
echo x x xx x >x &&
|
||||
echo y yy >y &&
|
||||
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
|
||||
'
|
||||
|
||||
|
@ -80,6 +82,31 @@ do
|
|||
diff expected actual
|
||||
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
|
||||
|
||||
test_done
|
||||
|
|
|
@ -11,4 +11,8 @@
|
|||
# This example catches duplicate Signed-off-by lines.
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
|
12
tree-diff.c
12
tree-diff.c
|
@ -15,7 +15,8 @@ static char *malloc_base(const char *base, const char *path, int pathlen)
|
|||
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)
|
||||
{
|
||||
|
@ -131,7 +132,8 @@ static void show_tree(struct diff_options *opt, const char *prefix, struct tree_
|
|||
}
|
||||
|
||||
/* 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;
|
||||
const char *path;
|
||||
|
@ -152,11 +154,9 @@ static int show_entry(struct diff_options *opt, const char *prefix, struct tree_
|
|||
|
||||
free(tree);
|
||||
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)
|
||||
|
|
3
tree.c
3
tree.c
|
@ -144,7 +144,7 @@ struct tree *lookup_tree(const unsigned char *sha1)
|
|||
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;
|
||||
struct object_refs *refs;
|
||||
|
@ -174,7 +174,6 @@ static int track_tree_refs(struct tree *item)
|
|||
refs->ref[i++] = obj;
|
||||
}
|
||||
set_object_refs(&item->object, refs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size)
|
||||
|
|
799
unpack-trees.c
Normal file
799
unpack-trees.c
Normal 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
35
unpack-trees.h
Normal 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
|
108
upload-pack.c
108
upload-pack.c
|
@ -14,12 +14,10 @@ static const char upload_pack_usage[] = "git-upload-pack [--strict] [--timeout=n
|
|||
#define THEY_HAVE (1U << 0)
|
||||
#define OUR_REF (1U << 1)
|
||||
#define WANTED (1U << 2)
|
||||
#define MAX_HAS 256
|
||||
#define MAX_NEEDS 256
|
||||
static int nr_has = 0, nr_needs = 0, multi_ack = 0, nr_our_refs = 0;
|
||||
static int multi_ack = 0, nr_our_refs = 0;
|
||||
static int use_thin_pack = 0;
|
||||
static unsigned char has_sha1[MAX_HAS][20];
|
||||
static unsigned char needs_sha1[MAX_NEEDS][20];
|
||||
static struct object_array have_obj;
|
||||
static struct object_array want_obj;
|
||||
static unsigned int timeout = 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];
|
||||
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 abort_msg[] = "aborting due to possible repository "
|
||||
"corruption on the remote side.";
|
||||
|
@ -107,7 +105,7 @@ static void create_pack_file(void)
|
|||
use_thin_pack = 0; /* no point doing it */
|
||||
}
|
||||
else
|
||||
args = nr_has + nr_needs + 5;
|
||||
args = have_obj.nr + want_obj.nr + 5;
|
||||
p = xmalloc(args * sizeof(char *));
|
||||
argv = (const char **) p;
|
||||
buf = xmalloc(args * 45);
|
||||
|
@ -118,20 +116,22 @@ static void create_pack_file(void)
|
|||
close(lp_pipe[1]);
|
||||
*p++ = "rev-list";
|
||||
*p++ = use_thin_pack ? "--objects-edge" : "--objects";
|
||||
if (create_full_pack || MAX_NEEDS <= nr_needs)
|
||||
if (create_full_pack)
|
||||
*p++ = "--all";
|
||||
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;
|
||||
memcpy(buf, sha1_to_hex(needs_sha1[i]), 41);
|
||||
memcpy(buf, sha1_to_hex(o->sha1), 41);
|
||||
buf += 41;
|
||||
}
|
||||
}
|
||||
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;
|
||||
*buf++ = '^';
|
||||
memcpy(buf, sha1_to_hex(has_sha1[i]), 41);
|
||||
memcpy(buf, sha1_to_hex(o->sha1), 41);
|
||||
buf += 41;
|
||||
}
|
||||
*p++ = NULL;
|
||||
|
@ -322,28 +322,29 @@ static void create_pack_file(void)
|
|||
|
||||
static int got_sha1(char *hex, unsigned char *sha1)
|
||||
{
|
||||
struct object *o;
|
||||
|
||||
if (get_sha1_hex(hex, sha1))
|
||||
die("git-upload-pack: expected SHA1 object, got '%s'", hex);
|
||||
if (!has_sha1_file(sha1))
|
||||
return 0;
|
||||
if (nr_has < MAX_HAS) {
|
||||
struct object *o = lookup_object(sha1);
|
||||
if (!(o && o->parsed))
|
||||
o = parse_object(sha1);
|
||||
if (!o)
|
||||
die("oops (%s)", sha1_to_hex(sha1));
|
||||
if (o->type == OBJ_COMMIT) {
|
||||
struct commit_list *parents;
|
||||
if (o->flags & THEY_HAVE)
|
||||
return 0;
|
||||
o->flags |= THEY_HAVE;
|
||||
for (parents = ((struct commit*)o)->parents;
|
||||
parents;
|
||||
parents = parents->next)
|
||||
parents->item->object.flags |= THEY_HAVE;
|
||||
}
|
||||
memcpy(has_sha1[nr_has++], sha1, 20);
|
||||
|
||||
o = lookup_object(sha1);
|
||||
if (!(o && o->parsed))
|
||||
o = parse_object(sha1);
|
||||
if (!o)
|
||||
die("oops (%s)", sha1_to_hex(sha1));
|
||||
if (o->type == OBJ_COMMIT) {
|
||||
struct commit_list *parents;
|
||||
if (o->flags & THEY_HAVE)
|
||||
return 0;
|
||||
o->flags |= THEY_HAVE;
|
||||
for (parents = ((struct commit*)o)->parents;
|
||||
parents;
|
||||
parents = parents->next)
|
||||
parents->item->object.flags |= THEY_HAVE;
|
||||
}
|
||||
add_object_array(o, NULL, &have_obj);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -361,26 +362,24 @@ static int get_common_commits(void)
|
|||
reset_timeout();
|
||||
|
||||
if (!len) {
|
||||
if (nr_has == 0 || multi_ack)
|
||||
if (have_obj.nr == 0 || multi_ack)
|
||||
packet_write(1, "NAK\n");
|
||||
continue;
|
||||
}
|
||||
len = strip(line, len);
|
||||
if (!strncmp(line, "have ", 5)) {
|
||||
if (got_sha1(line+5, sha1) &&
|
||||
(multi_ack || nr_has == 1)) {
|
||||
if (nr_has >= MAX_HAS)
|
||||
multi_ack = 0;
|
||||
(multi_ack || have_obj.nr == 1)) {
|
||||
packet_write(1, "ACK %s%s\n",
|
||||
sha1_to_hex(sha1),
|
||||
multi_ack ? " continue" : "");
|
||||
sha1_to_hex(sha1),
|
||||
multi_ack ? " continue" : "");
|
||||
if (multi_ack)
|
||||
memcpy(last_sha1, sha1, 20);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(line, "done")) {
|
||||
if (nr_has > 0) {
|
||||
if (have_obj.nr > 0) {
|
||||
if (multi_ack)
|
||||
packet_write(1, "ACK %s\n",
|
||||
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];
|
||||
int len, needs;
|
||||
int len;
|
||||
|
||||
needs = 0;
|
||||
for (;;) {
|
||||
struct object *o;
|
||||
unsigned char dummy[20], *sha1_buf;
|
||||
unsigned char sha1_buf[20];
|
||||
len = packet_read_line(0, line, sizeof(line));
|
||||
reset_timeout();
|
||||
if (!len)
|
||||
return needs;
|
||||
return;
|
||||
|
||||
sha1_buf = dummy;
|
||||
if (needs == MAX_NEEDS) {
|
||||
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))
|
||||
if (strncmp("want ", line, 5) ||
|
||||
get_sha1_hex(line+5, sha1_buf))
|
||||
die("git-upload-pack: protocol error, "
|
||||
"expected to get sha, not '%s'", line);
|
||||
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);
|
||||
if (!(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;
|
||||
}
|
||||
|
||||
static int upload_pack(void)
|
||||
static void upload_pack(void)
|
||||
{
|
||||
reset_timeout();
|
||||
head_ref(send_ref);
|
||||
for_each_ref(send_ref);
|
||||
packet_flush(1);
|
||||
nr_needs = receive_needs();
|
||||
if (!nr_needs)
|
||||
return 0;
|
||||
get_common_commits();
|
||||
create_pack_file();
|
||||
return 0;
|
||||
receive_needs();
|
||||
if (want_obj.nr) {
|
||||
get_common_commits();
|
||||
create_pack_file();
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
|
|
|
@ -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;
|
||||
}
|
Loading…
Reference in a new issue