diff options
84 files changed, 1486 insertions, 479 deletions
diff --git a/Documentation/config.txt b/Documentation/config.txt index 465eb13e7..ce722a2db 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -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 @@ -116,6 +119,10 @@ apply.whitespace:: Tells `git-apply` how to handle whitespaces, in the same way as the '--whitespace' option. See gitlink:git-apply[1]. +pager.color:: + A boolean to enable/disable colored output when the pager is in + use (default is true). + diff.color:: When true (or `always`), always use colors in patch. When false (or `never`), never. When set to `auto`, use @@ -219,14 +226,14 @@ showbranch.default:: See gitlink:git-show-branch[1]. tar.umask:: - By default, git-link:git-tar-tree[1] sets file and directories modes + By default, gitlink:git-tar-tree[1] sets file and directories modes to 0666 or 0777. While this is both useful and acceptable for projects such as the Linux Kernel, it might be excessive for other projects. With this variable, it becomes possible to tell - git-link:git-tar-tree[1] to apply a specific umask to the modes above. + gitlink:git-tar-tree[1] to apply a specific umask to the modes above. The special value "user" indicates that the user's current umask will be used. This should be enough for most projects, as it will lead to - the same permissions as git-link:git-checkout[1] would use. The default + the same permissions as gitlink:git-checkout[1] would use. The default value remains 0, which means world read-write. user.email:: diff --git a/Documentation/git-cvsimport.txt b/Documentation/git-cvsimport.txt index b0c6d7c30..d21d66bfe 100644 --- a/Documentation/git-cvsimport.txt +++ b/Documentation/git-cvsimport.txt @@ -116,7 +116,7 @@ file each time git-cvsimport is run. + It is not recommended to use this feature if you intend to export changes back to CVS again later with -git-link[1]::git-cvsexportcommit. +gitlink:git-cvsexportcommit[1]. OUTPUT ------ diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt index 62a8e7f22..dc7683383 100644 --- a/Documentation/git-grep.txt +++ b/Documentation/git-grep.txt @@ -16,7 +16,7 @@ SYNOPSIS [-n] [-l | --files-with-matches] [-L | --files-without-match] [-c | --count] [-A <post-context>] [-B <pre-context>] [-C <context>] - [-f <file>] [-e] <pattern> + [-f <file>] [-e] <pattern> [--and|--or|--not|(|)|-e <pattern>...] [<tree>...] [--] [<path>...] @@ -74,16 +74,30 @@ OPTIONS -e:: The next parameter is the pattern. This option has to be used for patterns starting with - and should be used in - scripts passing user input to grep. + scripts passing user input to grep. Multiple patterns are + combined by 'or'. + +--and | --or | --not | ( | ):: + Specify how multiple patterns are combined using boolean + expressions. `--or` is the default operator. `--and` has + higher precedence than `--or`. `-e` has to be used for all + patterns. `<tree>...`:: Search blobs in the trees for specified patterns. -`--`:: +\--:: Signals the end of options; the rest of the parameters are <path> limiters. +Example +------- + +git grep -e \'#define\' --and \( -e MAX_PATH -e PATH_MAX \):: + Looks for a line that has `#define` and either `MAX_PATH` or + `PATH_MAX`. + Author ------ Originally written by Linus Torvalds <torvalds@osdl.org>, later diff --git a/Documentation/git-init-db.txt b/Documentation/git-init-db.txt index 0a4fc14b9..63cd5dab3 100644 --- a/Documentation/git-init-db.txt +++ b/Documentation/git-init-db.txt @@ -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. +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. diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt index 56afd64f4..d4ae99fa5 100644 --- a/Documentation/git-push.txt +++ b/Documentation/git-push.txt @@ -8,7 +8,7 @@ git-push - Update remote refs along with associated objects SYNOPSIS -------- -'git-push' [--all] [--tags] [--force] <repository> <refspec>... +'git-push' [--all] [--tags] [-f | --force] <repository> <refspec>... DESCRIPTION ----------- diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt index f60eacd93..dd9fff16d 100644 --- a/Documentation/git-rev-list.txt +++ b/Documentation/git-rev-list.txt @@ -22,6 +22,7 @@ SYNOPSIS [ [\--objects | \--objects-edge] [ \--unpacked ] ] [ \--pretty | \--header ] [ \--bisect ] + [ \--merge ] <commit>... [ \-- <paths>... ] DESCRIPTION @@ -123,6 +124,10 @@ OPTIONS topological order (i.e. descendant commits are shown before their parents). +--merge:: + After a failed merge, show refs that touch files having a + conflict and don't exist on all heads to merge. + Author ------ Written by Linus Torvalds <torvalds@osdl.org> diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt index e446f4812..ce7857e5a 100644 --- a/Documentation/git-status.txt +++ b/Documentation/git-status.txt @@ -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 ------ diff --git a/Documentation/git.txt b/Documentation/git.txt index 7310a2b8b..bcf187a11 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -397,6 +397,9 @@ gitlink:git-quiltimport[1]:: gitlink:git-relink[1]:: Hardlink common objects in local repositories. +gitlink:git-svn[1]:: + Bidirectional operation between a single Subversion branch and git. + gitlink:git-svnimport[1]:: Import a SVN repository into git. @@ -442,6 +445,9 @@ gitlink:git-get-tar-commit-id[1]:: gitlink:git-imap-send[1]:: Dump a mailbox from stdin into an imap folder. +gitlink:git-instaweb[1]:: + Instantly browse your working repository in gitweb. + gitlink:git-mailinfo[1]:: Extracts patch and authorship information from a single e-mail message, optionally transliterating the commit diff --git a/Documentation/howto/setup-git-server-over-http.txt b/Documentation/howto/setup-git-server-over-http.txt new file mode 100644 index 000000000..ba191569a --- /dev/null +++ b/Documentation/howto/setup-git-server-over-http.txt @@ -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> diff --git a/Documentation/tutorial-2.txt b/Documentation/tutorial-2.txt index 894ca5e06..2f4fe1217 100644 --- a/Documentation/tutorial-2.txt +++ b/Documentation/tutorial-2.txt @@ -244,6 +244,7 @@ $ git ls-files --stage $ git cat-file -t 513feba2 blob $ git cat-file blob 513feba2 +hello world! hello world, again ------------------------------------------------ diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 5d25b7e12..14923c973 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,11 +1,19 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v1.4.GIT +DEF_VER=v1.4.2.GIT + +LF=' +' # First try git-describe, then see if there is a version file # (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 @@ -24,6 +24,11 @@ all: # 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). # +# Define NO_C99_FORMAT if your formatted IO functions (printf/scanf et.al.) +# do not support the 'size specifiers' introduced by C99, namely ll, hh, +# j, z, t. (representing long long int, char, intmax_t, size_t, ptrdiff_t). +# some c compilers supported these specifiers prior to C99 as an extension. +# # Define NO_STRCASESTR if you don't have strcasestr. # # Define NO_STRLCPY if you don't have strlcpy. @@ -173,14 +178,14 @@ PROGRAMS = \ git-hash-object$X git-index-pack$X git-local-fetch$X \ git-merge-base$X \ git-merge-index$X git-mktag$X git-mktree$X git-pack-objects$X git-patch-id$X \ - git-peek-remote$X git-prune-packed$X git-receive-pack$X \ + git-peek-remote$X git-receive-pack$X \ git-send-pack$X git-shell$X \ git-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-upload-pack$X git-verify-pack$X \ git-symbolic-ref$X \ - git-name-rev$X git-pack-redundant$X git-repo-config$X git-var$X \ + git-name-rev$X git-pack-redundant$X git-var$X \ git-describe$X git-merge-tree$X git-blame$X git-imap-send$X \ git-merge-recur$X @@ -193,7 +198,8 @@ BUILT_INS = git-log$X git-whatchanged$X git-show$X git-update-ref$X \ git-read-tree$X git-commit-tree$X git-write-tree$X \ git-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-fmt-merge-msg$X git-prune$X git-mv$X git-prune-packed$X \ + git-repo-config$X # what 'all' will build and 'install' will install, in gitexecdir ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS) @@ -250,7 +256,7 @@ BUILTIN_OBJS = \ builtin-diff-index.o builtin-diff-stages.o builtin-diff-tree.o \ builtin-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-mv.o builtin-prune-packed.o builtin-repo-config.o GITLIBS = $(LIB_FILE) $(XDIFF_LIB) LIBS = $(GITLIBS) -lz @@ -309,9 +315,9 @@ ifeq ($(uname_O),Cygwin) NO_D_TYPE_IN_DIRENT = YesPlease NO_D_INO_IN_DIRENT = YesPlease NO_STRCASESTR = YesPlease - NO_STRLCPY = YesPlease NO_SYMLINK_HEAD = YesPlease NEEDS_LIBICONV = YesPlease + NO_C99_FORMAT = YesPlease # There are conflicting reports about this. # On some boxes NO_MMAP is needed, and not so elsewhere. # Try uncommenting this if you see things break -- YMMV. @@ -433,6 +439,9 @@ endif ifdef NO_D_INO_IN_DIRENT ALL_CFLAGS += -DNO_D_INO_IN_DIRENT endif +ifdef NO_C99_FORMAT + ALL_CFLAGS += -DNO_C99_FORMAT +endif ifdef NO_SYMLINK_HEAD ALL_CFLAGS += -DNO_SYMLINK_HEAD endif @@ -718,7 +727,7 @@ install: all $(INSTALL) -d -m755 '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL) git$X gitk '$(DESTDIR_SQ)$(bindir_SQ)' - $(MAKE) -C templates install + $(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install $(INSTALL) -d -m755 '$(DESTDIR_SQ)$(GIT_PYTHON_DIR_SQ)' $(INSTALL) $(PYMODULES) '$(DESTDIR_SQ)$(GIT_PYTHON_DIR_SQ)' if test 'z$(bindir_SQ)' != 'z$(gitexecdir_SQ)'; \ @@ -39,8 +39,21 @@ DEFINE_ALLOCATOR(tree) DEFINE_ALLOCATOR(commit) DEFINE_ALLOCATOR(tag) +#ifdef NO_C99_FORMAT +#define SZ_FMT "%u" +#else +#define SZ_FMT "%zu" +#endif + +static void report(const char* name, unsigned int count, size_t size) +{ + fprintf(stderr, "%10s: %8u (" SZ_FMT " kB)\n", name, count, size); +} + +#undef SZ_FMT + #define REPORT(name) \ - fprintf(stderr, "%10s: %8u (%zu kB)\n", #name, name##_allocs, name##_allocs*sizeof(struct name) >> 10) + report(#name, name##_allocs, name##_allocs*sizeof(struct name) >> 10) void alloc_report(void) { @@ -20,7 +20,7 @@ #define DEBUG 0 -static const char blame_usage[] = "[-c] [-l] [-t] [-S <revs-file>] [--] file [commit]\n" +static const char blame_usage[] = "git-blame [-c] [-l] [-t] [-S <revs-file>] [--] file [commit]\n" " -c, --compatibility Use the same output mode as git-annotate (Default: off)\n" " -l, --long Show long commit SHA1 (Default: off)\n" " -t, --time Show raw timestamp (Default: off)\n" diff --git a/builtin-add.c b/builtin-add.c index f548b8007..0cb9c8120 100644 --- a/builtin-add.c +++ b/builtin-add.c @@ -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"); @@ -117,7 +115,7 @@ int cmd_add(int argc, const char **argv, const char *prefix) verbose = 1; continue; } - die(builtin_add_usage); + usage(builtin_add_usage); } pathspec = get_pathspec(prefix, argv + i); diff --git a/builtin-apply.c b/builtin-apply.c index f8c6763c7..9cf477c70 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -1698,6 +1698,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 +2046,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) @@ -2225,12 +2234,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"); diff --git a/builtin-check-ref-format.c b/builtin-check-ref-format.c index 701de439a..fe04be77a 100644 --- a/builtin-check-ref-format.c +++ b/builtin-check-ref-format.c @@ -9,6 +9,6 @@ int cmd_check_ref_format(int argc, const char **argv, const char *prefix) { if (argc != 2) - usage("git check-ref-format refname"); + usage("git-check-ref-format refname"); return !!check_ref_format(argv[1]); } diff --git a/builtin-diff.c b/builtin-diff.c index 48d2fd03b..a090e298a 100644 --- a/builtin-diff.c +++ b/builtin-diff.c @@ -23,7 +23,7 @@ struct blobinfo { }; static const char builtin_diff_usage[] = -"diff <options> <rev>{0,2} -- <path>*"; +"git-diff <options> <rev>{0,2} -- <path>*"; static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv) @@ -125,9 +125,6 @@ static int builtin_diff_blobs(struct rev_info *revs, int argc, const char **argv, struct blobinfo *blob) { - /* Blobs: the arguments are reversed when setup_revisions() - * picked them up. - */ unsigned mode = canon_mode(S_IFREG | 0644); if (argc > 1) @@ -135,8 +132,8 @@ static int builtin_diff_blobs(struct rev_info *revs, stuff_change(&revs->diffopt, mode, mode, - blob[1].sha1, blob[0].sha1, - blob[0].name, blob[0].name); + blob[0].sha1, blob[1].sha1, + blob[0].name, blob[1].name); diffcore_std(&revs->diffopt); diff_flush(&revs->diffopt); return 0; @@ -256,7 +253,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 @@ -351,6 +349,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix) * A and B. We have ent[0] == merge-base, ent[1] == A, * and ent[2] == B. Show diff between the base and B. */ + ent[1] = ent[2]; return builtin_diff_tree(&rev, argc, argv, ent); } else diff --git a/builtin-fmt-merge-msg.c b/builtin-fmt-merge-msg.c index c84224ee8..485ede7ca 100644 --- a/builtin-fmt-merge-msg.c +++ b/builtin-fmt-merge-msg.c @@ -1,3 +1,4 @@ +#include "builtin.h" #include "cache.h" #include "commit.h" #include "diff.h" @@ -242,7 +243,7 @@ static void shortlog(const char *name, unsigned char *sha1, free_list(&subjects); } -int cmd_fmt_merge_msg(int argc, char **argv, const char *prefix) +int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix) { int limit = 20, i = 0; char line[1024]; diff --git a/builtin-grep.c b/builtin-grep.c index 69b7c4862..93b7e07b3 100644 --- a/builtin-grep.c +++ b/builtin-grep.c @@ -410,8 +410,10 @@ static int fixmatch(const char *pattern, char *line, regmatch_t *match) static int match_one_pattern(struct grep_opt *opt, struct grep_pat *p, char *bol, char *eol) { int hit = 0; + int at_true_bol = 1; regmatch_t pmatch[10]; + again: if (!opt->fixed) { regex_t *exp = &p->regexp; hit = !regexec(exp, bol, ARRAY_SIZE(pmatch), @@ -422,22 +424,35 @@ static int match_one_pattern(struct grep_opt *opt, struct grep_pat *p, char *bol } if (hit && opt->word_regexp) { - /* Match beginning must be either - * beginning of the line, or at word - * boundary (i.e. the last char must - * not be alnum or underscore). - */ if ((pmatch[0].rm_so < 0) || (eol - bol) <= pmatch[0].rm_so || (pmatch[0].rm_eo < 0) || (eol - bol) < pmatch[0].rm_eo) die("regexp returned nonsense"); - if (pmatch[0].rm_so != 0 && - word_char(bol[pmatch[0].rm_so-1])) - hit = 0; - if (pmatch[0].rm_eo != (eol-bol) && - word_char(bol[pmatch[0].rm_eo])) + + /* Match beginning must be either beginning of the + * line, or at word boundary (i.e. the last char must + * not be a word char). Similarly, match end must be + * either end of the line, or at word boundary + * (i.e. the next char must not be a word char). + */ + if ( ((pmatch[0].rm_so == 0 && at_true_bol) || + !word_char(bol[pmatch[0].rm_so-1])) && + ((pmatch[0].rm_eo == (eol-bol)) || + !word_char(bol[pmatch[0].rm_eo])) ) + ; + else hit = 0; + + if (!hit && pmatch[0].rm_so + bol + 1 < eol) { + /* There could be more than one match on the + * line, and the first match might not be + * strict word match. But later ones could be! + */ + bol = pmatch[0].rm_so + bol + 1; + at_true_bol = 0; + goto again; + } } return hit; } diff --git a/builtin-help.c b/builtin-help.c index bb0b03f1a..6484cb9df 100644 --- a/builtin-help.c +++ b/builtin-help.c @@ -9,8 +9,6 @@ #include "exec_cmd.h" #include "common-cmds.h" -static const char git_usage[] = - "Usage: git [--version] [--exec-path[=GIT_EXEC_PATH]] [--help] COMMAND [ ARGS ]"; /* most GUI terminals set COLUMNS (although some don't export it) */ static int term_columns(void) @@ -142,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) @@ -178,31 +176,6 @@ static void list_common_cmds_help(void) puts("(use 'git help -a' to get a list of all installed git commands)"); } -void cmd_usage(int show_all, const char *exec_path, const char *fmt, ...) -{ - if (fmt) { - va_list ap; - - va_start(ap, fmt); - printf("git: "); - vprintf(fmt, ap); - va_end(ap); - putchar('\n'); - } - else - puts(git_usage); - - if (exec_path) { - putchar('\n'); - if (show_all) - list_commands(exec_path, "git-*"); - else - list_common_cmds_help(); - } - - exit(1); -} - static void show_man_page(const char *git_cmd) { const char *page; @@ -221,6 +194,13 @@ static void show_man_page(const char *git_cmd) execlp("man", "man", page, NULL); } +void help_unknown_cmd(const char *cmd) +{ + printf("git: '%s' is not a git-command\n\n", cmd); + list_common_cmds_help(); + exit(1); +} + int cmd_version(int argc, const char **argv, const char *prefix) { printf("git version %s\n", git_version_string); @@ -230,12 +210,24 @@ int cmd_version(int argc, const char **argv, const char *prefix) int cmd_help(int argc, const char **argv, const char *prefix) { const char *help_cmd = argc > 1 ? argv[1] : NULL; - if (!help_cmd) - cmd_usage(0, git_exec_path(), NULL); - else if (!strcmp(help_cmd, "--all") || !strcmp(help_cmd, "-a")) - cmd_usage(1, git_exec_path(), NULL); + const char *exec_path = git_exec_path(); + + if (!help_cmd) { + printf("usage: %s\n\n", git_usage_string); + list_common_cmds_help(); + exit(1); + } + + else if (!strcmp(help_cmd, "--all") || !strcmp(help_cmd, "-a")) { + printf("usage: %s\n\n", git_usage_string); + if(exec_path) + list_commands(exec_path, "git-*"); + exit(1); + } + else show_man_page(help_cmd); + return 0; } diff --git a/builtin-init-db.c b/builtin-init-db.c index 52473edf5..5085018e4 100644 --- a/builtin-init-db.c +++ b/builtin-init-db.c @@ -267,7 +267,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix) else if (!strncmp(arg, "--shared=", 9)) shared_repository = git_config_perm("arg", arg+9); else - die(init_db_usage); + usage(init_db_usage); } /* diff --git a/builtin-log.c b/builtin-log.c index 82c69d1d0..691cf3aef 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -34,7 +34,6 @@ static int cmd_log_walk(struct rev_info *rev) struct commit *commit; prepare_revision_walk(rev); - setup_pager(); while ((commit = get_revision(rev)) != NULL) { log_tree_commit(rev, commit); free(commit->buffer); @@ -258,6 +257,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) char message_id[1024]; char ref_message_id[1024]; + setup_ident(); git_config(git_format_config); init_revisions(&rev, prefix); rev.commit_format = CMIT_FMT_EMAIL; @@ -307,7 +307,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) !strcmp(argv[i], "-s")) { const char *committer; const char *endpos; - setup_ident(); committer = git_committer_info(1); endpos = strchr(committer, '>'); if (!endpos) diff --git a/builtin-ls-files.c b/builtin-ls-files.c index 79ffe8f42..11386c432 100644 --- a/builtin-ls-files.c +++ b/builtin-ls-files.c @@ -24,7 +24,6 @@ static int show_valid_bit = 0; static int line_terminator = '\n'; static int prefix_len = 0, prefix_offset = 0; -static const char *prefix = NULL; static const char **pathspec = NULL; static int error_unmatch = 0; static char *ps_matched = NULL; @@ -207,7 +206,7 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce) } } -static void show_files(struct dir_struct *dir) +static void show_files(struct dir_struct *dir, const char *prefix) { int i; @@ -253,7 +252,7 @@ static void show_files(struct dir_struct *dir) /* * Prune the index to only contain stuff starting with "prefix" */ -static void prune_cache(void) +static void prune_cache(const char *prefix) { int pos = cache_name_pos(prefix, prefix_len); unsigned int first, last; @@ -276,7 +275,7 @@ static void prune_cache(void) active_nr = last; } -static void verify_pathspec(void) +static const char *verify_pathspec(const char *prefix) { const char **p, *n, *prev; char *real_prefix; @@ -313,7 +312,7 @@ static void verify_pathspec(void) memcpy(real_prefix, prev, max); real_prefix[max] = 0; } - prefix = real_prefix; + return real_prefix; } static const char ls_files_usage[] = @@ -453,7 +452,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix) /* Verify that the pathspec matches the prefix */ if (pathspec) - verify_pathspec(); + prefix = verify_pathspec(prefix); /* Treat unmatching pathspec elements as errors */ if (pathspec && error_unmatch) { @@ -476,8 +475,8 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix) read_cache(); if (prefix) - prune_cache(); - show_files(&dir); + prune_cache(prefix); + show_files(&dir, prefix); if (ps_matched) { /* We need to make sure all pathspec matched otherwise diff --git a/builtin-mv.c b/builtin-mv.c index 62ae937cb..a731f8d9c 100644 --- a/builtin-mv.c +++ b/builtin-mv.c @@ -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"); @@ -99,7 +97,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix) ignore_errors = 1; continue; } - die(builtin_mv_usage); + usage(builtin_mv_usage); } count = argc - i - 1; if (count < 1) diff --git a/prune-packed.c b/builtin-prune-packed.c index d24b09711..d3dd94d9e 100644 --- a/prune-packed.c +++ b/builtin-prune-packed.c @@ -1,3 +1,4 @@ +#include "builtin.h" #include "cache.h" static const char prune_packed_usage[] = @@ -54,12 +55,10 @@ static void prune_packed_objects(void) } } -int main(int argc, char **argv) +int cmd_prune_packed(int argc, const char **argv, const char *prefix) { int i; - setup_git_directory(); - for (i = 1; i < argc; i++) { const char *arg = argv[i]; diff --git a/builtin-prune.c b/builtin-prune.c index 6a86eb52a..89ec7f142 100644 --- a/builtin-prune.c +++ b/builtin-prune.c @@ -10,7 +10,7 @@ #include "builtin.h" #include "cache-tree.h" -static const char prune_usage[] = "git prune [-n]"; +static const char prune_usage[] = "git-prune [-n]"; static int show_only = 0; static struct rev_info revs; diff --git a/builtin-push.c b/builtin-push.c index a82417106..53bc378f7 100644 --- a/builtin-push.c +++ b/builtin-push.c @@ -8,7 +8,7 @@ #define MAX_URI (16) -static const char push_usage[] = "git push [--all] [--tags] [--force] <repository> [<refspec>...]"; +static const char push_usage[] = "git-push [--all] [--tags] [-f | --force] <repository> [<refspec>...]"; static int all = 0, tags = 0, force = 0, thin = 1; static const char *execute = NULL; @@ -291,7 +291,7 @@ int cmd_push(int argc, const char **argv, const char *prefix) tags = 1; continue; } - if (!strcmp(arg, "--force")) { + if (!strcmp(arg, "--force") || !strcmp(arg, "-f")) { force = 1; continue; } diff --git a/builtin-read-tree.c b/builtin-read-tree.c index 8869cedea..8da8acbb0 100644 --- a/builtin-read-tree.c +++ b/builtin-read-tree.c @@ -88,7 +88,7 @@ static const char read_tree_usage[] = "git-read-tree (<sha> | [[-m [--aggressive static struct lock_file lock_file; -int cmd_read_tree(int argc, const char **argv, const char *prefix) +int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) { int i, newfd, stage = 0; unsigned char sha1[20]; @@ -100,9 +100,7 @@ int cmd_read_tree(int argc, const char **argv, const char *prefix) setup_git_directory(); 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); git_config(git_default_config); diff --git a/repo-config.c b/builtin-repo-config.c index 743f02b7d..c821e2271 100644 --- a/repo-config.c +++ b/builtin-repo-config.c @@ -1,3 +1,4 @@ +#include "builtin.h" #include "cache.h" #include <regex.h> @@ -128,7 +129,7 @@ free_strings: return ret; } -int main(int argc, const char **argv) +int cmd_repo_config(int argc, const char **argv, const char *prefix) { int nongit = 0; setup_git_directory_gently(&nongit); diff --git a/builtin-rm.c b/builtin-rm.c index 92d205a71..593d86744 100644 --- a/builtin-rm.c +++ b/builtin-rm.c @@ -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"); @@ -80,7 +78,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix) force = 1; continue; } - die(builtin_rm_usage); + usage(builtin_rm_usage); } if (argc <= i) usage(builtin_rm_usage); @@ -115,7 +113,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix) printf("rm '%s'\n", path); if (remove_file_from_cache(path)) - die("git rm: unable to remove %s", path); + die("git-rm: unable to remove %s", path); cache_tree_invalidate_path(active_cache_tree, path); } @@ -139,7 +137,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix) continue; } if (!removed) - die("git rm: %s: %s", path, strerror(errno)); + die("git-rm: %s: %s", path, strerror(errno)); } } diff --git a/builtin-tar-tree.c b/builtin-tar-tree.c index 7c48db9ec..215892b69 100644 --- a/builtin-tar-tree.c +++ b/builtin-tar-tree.c @@ -314,6 +314,7 @@ static int generate_tar(int argc, const char **argv, const char *prefix) struct commit *commit; struct tree_desc tree; struct strbuf current_path; + void *buffer; current_path.buf = xmalloc(PATH_MAX); current_path.alloc = PATH_MAX; @@ -341,8 +342,8 @@ static int generate_tar(int argc, const char **argv, const char *prefix) } else archive_time = time(NULL); - tree.buf = read_object_with_reference(sha1, tree_type, &tree.size, - tree_sha1); + tree.buf = buffer = read_object_with_reference(sha1, tree_type, + &tree.size, tree_sha1); if (!tree.buf) die("not a reference to a tag, commit or tree object: %s", sha1_to_hex(sha1)); @@ -351,6 +352,7 @@ static int generate_tar(int argc, const char **argv, const char *prefix) write_entry(tree_sha1, ¤t_path, 040777, NULL, 0); traverse_tree(&tree, ¤t_path); write_trailer(); + free(buffer); free(current_path.buf); return 0; } diff --git a/builtin-update-index.c b/builtin-update-index.c index 24dca47d8..d2556f376 100644 --- a/builtin-update-index.c +++ b/builtin-update-index.c @@ -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) diff --git a/builtin-write-tree.c b/builtin-write-tree.c index 0289f5993..ca06149f1 100644 --- a/builtin-write-tree.c +++ b/builtin-write-tree.c @@ -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) @@ -73,7 +73,7 @@ int cmd_write_tree(int argc, const char **argv, const char *unused_prefix) else if (!strncmp(arg, "--prefix=", 9)) prefix = arg + 9; else - die(write_tree_usage); + usage(write_tree_usage); argc--; argv++; } @@ -2,18 +2,12 @@ #define BUILTIN_H #include <stdio.h> - -#ifndef PATH_MAX -# define PATH_MAX 4096 -#endif +#include <limits.h> extern const char git_version_string[]; +extern const char git_usage_string[]; -void cmd_usage(int show_all, const char *exec_path, const char *fmt, ...) -#ifdef __GNUC__ - __attribute__((__format__(__printf__, 3, 4), __noreturn__)) -#endif - ; +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); @@ -26,6 +20,7 @@ extern int cmd_format_patch(int argc, const char **argv, const char *prefix); extern int cmd_count_objects(int argc, const char **argv, const char *prefix); extern int cmd_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); @@ -53,6 +48,7 @@ extern int cmd_update_index(int argc, const char **argv, const char *prefix); extern int cmd_update_ref(int argc, const char **argv, const char *prefix); extern int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix); extern int cmd_mv(int argc, const char **argv, const char *prefix); +extern int cmd_repo_config(int argc, const char **argv, const char *prefix); extern int cmd_write_tree(int argc, const char **argv, const char *prefix); extern int write_tree(unsigned char *sha1, int missing_ok, const char *prefix); @@ -176,7 +176,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 *); @@ -387,6 +387,7 @@ extern int receive_keep_pack(int fd[2], const char *me, int quiet, int); /* pager.c */ extern void setup_pager(void); extern int pager_in_use; +extern int pager_use_color; /* base85 */ int decode_85(char *dst, char *line, int linelen); diff --git a/checkout-index.c b/checkout-index.c index 61152f34b..dfb1c4441 100644 --- a/checkout-index.c +++ b/checkout-index.c @@ -206,7 +206,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; diff --git a/combine-diff.c b/combine-diff.c index 919112bba..ba8baca0a 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -497,11 +497,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 +528,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 +542,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 +566,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,14 +598,15 @@ 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, @@ -699,18 +712,22 @@ static int show_patch_diff(struct combine_diff_path *elem, int num_parent, if (show_hunks || mode_differs || working_tree_file) { 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 +736,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 +749,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); @@ -309,6 +309,11 @@ int git_default_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "pager.color")) { + pager_use_color = git_config_bool(var,value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/configure.ac b/configure.ac index c1f7751e6..a9c88c6a4 100644 --- a/configure.ac +++ b/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], [1.4.2], [git@vger.kernel.org]) AC_CONFIG_SRCDIR([git.c]) diff --git a/convert-objects.c b/convert-objects.c index ebea8e472..168771ed8 100644 --- a/convert-objects.c +++ b/convert-objects.c @@ -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" @@ -175,7 +175,7 @@ int git_diff_ui_config(const char *var, const char *value) diff_use_color_default = 1; /* bool */ else if (!strcasecmp(value, "auto")) { diff_use_color_default = 0; - if (isatty(1) || pager_in_use) { + if (isatty(1) || (pager_in_use && pager_use_color)) { char *term = getenv("TERM"); if (term && strcmp(term, "dumb")) diff_use_color_default = 1; @@ -1515,10 +1515,8 @@ 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; + if (options->find_copies_harder) + options->detect_rename = DIFF_DETECT_COPY; if (options->output_format & (DIFF_FORMAT_NAME | DIFF_FORMAT_NAME_STATUS | @@ -1786,13 +1784,9 @@ struct diff_filepair *diff_queue(struct diff_queue_struct *queue, struct diff_filespec *one, struct diff_filespec *two) { - struct diff_filepair *dp = xmalloc(sizeof(*dp)); + struct diff_filepair *dp = xcalloc(1, sizeof(*dp)); dp->one = one; dp->two = two; - dp->score = 0; - dp->status = 0; - dp->source_stays = 0; - dp->broken_pair = 0; if (queue) diff_q(queue, dp); return dp; diff --git a/diffcore-rename.c b/diffcore-rename.c index 1de8d3250..0ec488a90 100644 --- a/diffcore-rename.c +++ b/diffcore-rename.c @@ -205,6 +205,7 @@ static void record_rename_pair(int dst_index, int src_index, int score) fill_filespec(two, dst->sha1, dst->mode); dp = diff_queue(NULL, one, two); + dp->renamed_pair = 1; if (!strcmp(src->path, dst->path)) dp->score = rename_src[src_index].score; else diff --git a/diffcore.h b/diffcore.h index 73c7842cc..2249bc2c0 100644 --- a/diffcore.h +++ b/diffcore.h @@ -53,11 +53,12 @@ struct diff_filepair { char status; /* M C R N D U (see Documentation/diff-format.txt) */ unsigned source_stays : 1; /* all of R/C are copies */ unsigned broken_pair : 1; + unsigned renamed_pair : 1; }; #define DIFF_PAIR_UNMERGED(p) \ (!DIFF_FILE_VALID((p)->one) && !DIFF_FILE_VALID((p)->two)) -#define DIFF_PAIR_RENAME(p) (strcmp((p)->one->path, (p)->two->path)) +#define DIFF_PAIR_RENAME(p) ((p)->renamed_pair) #define DIFF_PAIR_BROKEN(p) \ ( (!DIFF_FILE_VALID((p)->one) != !DIFF_FILE_VALID((p)->two)) && \ diff --git a/environment.c b/environment.c index 42f39d657..87162b257 100644 --- a/environment.c +++ b/environment.c @@ -23,6 +23,7 @@ int shared_repository = PERM_UMASK; const char *apply_default_whitespace = NULL; int zlib_compression_level = Z_DEFAULT_COMPRESSION; int pager_in_use; +int pager_use_color = 1; static char *git_dir, *git_object_dir, *git_index_file, *git_refs_dir, *git_graft_file; diff --git a/fetch-clone.c b/fetch-clone.c index 81d137129..5e84c4620 100644 --- a/fetch-clone.c +++ b/fetch-clone.c @@ -129,10 +129,12 @@ static pid_t setup_sideband(int sideband, const char *me, int fd[2], int xd[2]) len--; switch (buf[0] & 0xFF) { case 3: + safe_write(2, "remote: ", 8); safe_write(2, buf+1, len); - fprintf(stderr, "\n"); + safe_write(2, "\n", 1); exit(1); case 2: + safe_write(2, "remote: ", 8); safe_write(2, buf+1, len); continue; case 1: @@ -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" && diff --git a/git-annotate.perl b/git-annotate.perl index 6db2f4824..215ed26f3 100755 --- a/git-annotate.perl +++ b/git-annotate.perl @@ -147,7 +147,7 @@ sub init_claim { sub handle_rev { - my $i = 0; + my $revseen = 0; my %seen; while (my $rev = shift @revqueue) { next if $seen{$rev}++; @@ -247,22 +247,129 @@ sub git_find_parent { return $parent; } +sub git_find_all_parents { + my ($rev) = @_; + + my $revparent = open_pipe("git-rev-list","--remove-empty", "--parents","--max-count=1","$rev") + or die "Failed to open git-rev-list to find a single parent: $!"; + + my $parentline = <$revparent>; + chomp $parentline; + my ($origrev, @parents) = split m/\s+/, $parentline; + + close($revparent); + + return @parents; +} + +sub git_merge_base { + my ($rev1, $rev2) = @_; + + my $mb = open_pipe("git-merge-base", $rev1, $rev2) + or die "Failed to open git-merge-base: $!"; + + my $base = <$mb>; + chomp $base; + + close($mb); + + return $base; +} + +# Construct a set of pseudo parents that are in the same order, +# and the same quantity as the real parents, +# but whose SHA1s are as similar to the logical parents +# as possible. +sub get_pseudo_parents { + my ($all, $fake) = @_; + + my @all = @$all; + my @fake = @$fake; + + my @pseudo; + + my %fake = map {$_ => 1} @fake; + my %seenfake; + + my $fakeidx = 0; + foreach my $p (@all) { + if (exists $fake{$p}) { + if ($fake[$fakeidx] ne $p) { + die sprintf("parent mismatch: %s != %s\nall:%s\nfake:%s\n", + $fake[$fakeidx], $p, + join(", ", @all), + join(", ", @fake), + ); + } + + push @pseudo, $p; + $fakeidx++; + $seenfake{$p}++; + + } else { + my $base = git_merge_base($fake[$fakeidx], $p); + if ($base ne $fake[$fakeidx]) { + die sprintf("Result of merge-base doesn't match fake: %s,%s != %s\n", + $fake[$fakeidx], $p, $base); + } + + # The details of how we parse the diffs + # mean that we cannot have a duplicate + # revision in the list, so if we've already + # seen the revision we would normally add, just use + # the actual revision. + if ($seenfake{$base}) { + push @pseudo, $p; + } else { + push @pseudo, $base; + $seenfake{$base}++; + } + } + } + + return @pseudo; +} + # Get a diff between the current revision and a parent. # Record the commit information that results. sub git_diff_parse { my ($parents, $rev, %revinfo) = @_; + my @pseudo_parents; + my @command = ("git-diff-tree"); + my $revision_spec; + + if (scalar @$parents == 1) { + + $revision_spec = join("..", $parents->[0], $rev); + @pseudo_parents = @$parents; + } else { + my @all_parents = git_find_all_parents($rev); + + if (@all_parents != @$parents) { + @pseudo_parents = get_pseudo_parents(\@all_parents, $parents); + } else { + @pseudo_parents = @$parents; + } + + $revision_spec = $rev; + push @command, "-c"; + } + my @filenames = ( $revs{$rev}{'filename'} ); + foreach my $parent (@$parents) { push @filenames, $revs{$parent}{'filename'}; } - my $diff = open_pipe("git-diff-tree","-M","-p","-c",$rev,"--", - @filenames ) + push @command, "-p", "-M", $revision_spec, "--", @filenames; + + + my $diff = open_pipe( @command ) or die "Failed to call git-diff for annotation: $!"; - _git_diff_parse($diff, $parents, $rev, %revinfo); + _git_diff_parse($diff, \@pseudo_parents, $rev, %revinfo); close($diff); } @@ -283,6 +390,7 @@ sub _git_diff_parse { $diff_header_regexp .= "@" x @$parents; $diff_header_regexp .= ' -\d+,\d+' x @$parents; $diff_header_regexp .= ' \+(\d+),\d+'; + $diff_header_regexp .= " " . ("@" x @$parents); my %claim_regexps; my $allparentplus = '^' . '\\+' x @$parents . '(.*)$'; @@ -311,13 +419,13 @@ sub _git_diff_parse { DIFF: while(<$diff>) { chomp; + #printf("%d:%s:\n", $gotheader, $_); if (m/$diff_header_regexp/) { $remstart = $1 - 1; # (0-based arrays) $gotheader = 1; - printf("Copying from %d to %d\n", $ri, $remstart); foreach my $parent (@$parents) { for (my $i = $ri; $i < $remstart; $i++) { $plines{$parent}[$pi{$parent}++] = $slines->[$i]; @@ -392,10 +500,17 @@ sub _git_diff_parse { printf("parent %s is on line %d\n", $parent, $pi{$parent}); } + my @context; + for (my $i = -2; $i < 2; $i++) { + push @context, get_line($slines, $ri + $i); + } + my $context = join("\n", @context); + + my $justline = substr($_, scalar @$parents); die sprintf("Line %d, does not match:\n|%s|\n|%s|\n%s\n", $ri, - substr($_,scalar @$parents), - get_line($slines,$ri), $rev); + $justline, + $context); } foreach my $parent (@$parents) { $plines{$parent}[$pi{$parent}++] = $slines->[$ri]; diff --git a/git-checkout.sh b/git-checkout.sh index 5613bfc40..580a9e8a2 100755 --- a/git-checkout.sh +++ b/git-checkout.sh @@ -67,6 +67,10 @@ while [ "$#" != "0" ]; do set x "$arg" "$@" shift fi + case "$1" in + --) + shift ;; + esac break ;; esac diff --git a/git-clone.sh b/git-clone.sh index a92b22a13..7060bdab0 100755 --- a/git-clone.sh +++ b/git-clone.sh @@ -205,7 +205,7 @@ dir="$2" [ -e "$dir" ] && echo "$dir already exists." && usage mkdir -p "$dir" && D=$(cd "$dir" && pwd) && -trap 'err=$?; cd ..; rm -r "$D"; exit $err' 0 +trap 'err=$?; cd ..; rm -rf "$D"; exit $err' 0 case "$bare" in yes) GIT_DIR="$D" ;; @@ -298,7 +298,7 @@ yes,yes) fi git-ls-remote "$repo" >"$GIT_DIR/CLONE_HEAD" || exit 1 ;; - http://*) + https://*|http://*) if test -z "@@NO_CURL@@" then clone_dumb_http "$repo" "$D" @@ -324,7 +324,8 @@ test -d "$GIT_DIR/refs/reference-tmp" && rm -fr "$GIT_DIR/refs/reference-tmp" if test -f "$GIT_DIR/CLONE_HEAD" then # Read git-fetch-pack -k output and store the remote branches. - @@PERL@@ -e "$copy_refs" "$GIT_DIR" "$use_separate_remote" "$origin" + @@PERL@@ -e "$copy_refs" "$GIT_DIR" "$use_separate_remote" "$origin" || + exit fi cd "$D" || exit diff --git a/git-compat-util.h b/git-compat-util.h index 93f558056..b2e18954c 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -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 diff --git a/git-push.sh b/git-push.sh deleted file mode 100755 index 21775fc21..000000000 --- a/git-push.sh +++ /dev/null @@ -1,87 +0,0 @@ -#!/bin/sh - -USAGE='[--all] [--tags] [--force] <repository> [<refspec>...]' -. git-sh-setup - -# Parse out parameters and then stop at remote, so that we can -# translate it using .git/branches information -has_all= -has_force= -has_exec= -has_thin=--thin -remote= -do_tags= - -while case "$#" in 0) break ;; esac -do - case "$1" in - --all) - has_all=--all ;; - --tags) - do_tags=yes ;; - --force) - has_force=--force ;; - --exec=*) - has_exec="$1" ;; - --thin) - ;; # noop - --no-thin) - has_thin= ;; - -*) - usage ;; - *) - set x "$@" - shift - break ;; - esac - shift -done -case "$#" in -0) - echo "Where would you want to push today?" - usage ;; -esac - -. git-parse-remote -remote=$(get_remote_url "$@") - -case "$has_all" in ---all) - set x ;; -'') - case "$do_tags,$#" in - yes,1) - set x $(cd "$GIT_DIR/refs" && find tags -type f -print) ;; - yes,*) - set x $(cd "$GIT_DIR/refs" && find tags -type f -print) \ - $(get_remote_refs_for_push "$@") ;; - ,*) - set x $(get_remote_refs_for_push "$@") ;; - esac -esac - -shift ;# away the initial 'x' - -# $# is now 0 if there was no explicit refspec on the command line -# and there was no default refspec to push from remotes/ file. -# we will let git-send-pack to do its "matching refs" thing. - -case "$remote" in -git://*) - die "Cannot use READ-ONLY transport to push to $remote" ;; -rsync://*) - die "Pushing with rsync transport is deprecated" ;; -esac - -set x "$remote" "$@"; shift -test "$has_all" && set x "$has_all" "$@" && shift -test "$has_force" && set x "$has_force" "$@" && shift -test "$has_exec" && set x "$has_exec" "$@" && shift -test "$has_thin" && set x "$has_thin" "$@" && shift - -case "$remote" in -http://* | https://*) - exec git-http-push "$@";; -*) - exec git-send-pack "$@";; -esac diff --git a/git-rebase.sh b/git-rebase.sh index cb1a9ce12..20f74d416 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -277,14 +277,11 @@ onto=$(git-rev-parse --verify "${onto_name}^0") || exit # Check if we are already based on $onto, but this should be # done only when upstream and onto are the same. -if test "$upstream" = "$onto" +mb=$(git-merge-base "$onto" "$branch") +if test "$upstream" = "$onto" && test "$mb" = "$onto" then - mb=$(git-merge-base "$onto" "$branch") - if test "$mb" = "$onto" - then - echo >&2 "Current branch $branch_name is up to date." - exit 0 - fi + echo >&2 "Current branch $branch_name is up to date." + exit 0 fi # Rewind the head to "$onto"; this saves our current head in ORIG_HEAD. @@ -292,9 +289,9 @@ git-reset --hard "$onto" # If the $onto is a proper descendant of the tip of the branch, then # we just fast forwarded. -if test "$mb" = "$onto" +if test "$mb" = "$branch" then - echo >&2 "Fast-forwarded $branch to $newbase." + echo >&2 "Fast-forwarded $branch_name to $onto_name." exit 0 fi diff --git a/git-sh-setup.sh b/git-sh-setup.sh index d15747f1e..42f9b1c12 100755 --- a/git-sh-setup.sh +++ b/git-sh-setup.sh @@ -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"} diff --git a/git-svn.perl b/git-svn.perl index 6453771f9..0d58bb9b3 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -31,6 +31,7 @@ use File::Basename qw/dirname basename/; 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 @@ my %cmt_opts = ( 'edit|e' => \$_edit, '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 || [] } } @@ -15,6 +15,9 @@ #include "builtin.h" +const char git_usage_string[] = + "git [--version] [--exec-path[=GIT_EXEC_PATH]] [--help] COMMAND [ ARGS ]"; + static void prepend_to_path(const char *dir, int len) { const char *old_path = getenv("PATH"); @@ -78,7 +81,7 @@ static int handle_options(const char*** argv, int* argc) setenv("GIT_DIR", getcwd(git_dir, 1024), 1); } else { fprintf(stderr, "Unknown option: %s\n", cmd); - cmd_usage(0, NULL, NULL); + usage(git_usage_string); } (*argv)++; @@ -211,6 +214,7 @@ static int handle_alias(int *argcp, const char ***argv) const char git_version_string[] = GIT_VERSION; #define NEEDS_PREFIX 1 +#define USE_PAGER 2 static void handle_internal_command(int argc, const char **argv, char **envp) { @@ -218,14 +222,14 @@ static void handle_internal_command(int argc, const char **argv, char **envp) static struct cmd_struct { const char *cmd; int (*fn)(int, const char **, const char *); - int prefix; + int option; } commands[] = { { "version", cmd_version }, { "help", cmd_help }, - { "log", cmd_log, NEEDS_PREFIX }, - { "whatchanged", cmd_whatchanged, NEEDS_PREFIX }, - { "show", cmd_show, NEEDS_PREFIX }, - { "push", cmd_push }, + { "log", cmd_log, NEEDS_PREFIX | USE_PAGER }, + { "whatchanged", cmd_whatchanged, NEEDS_PREFIX | USE_PAGER }, + { "show", cmd_show, NEEDS_PREFIX | USE_PAGER }, + { "push", cmd_push, NEEDS_PREFIX }, { "format-patch", cmd_format_patch, NEEDS_PREFIX }, { "count-objects", cmd_count_objects }, { "diff", cmd_diff, NEEDS_PREFIX }, @@ -259,6 +263,8 @@ static void handle_internal_command(int argc, const char **argv, char **envp) { "fmt-merge-msg", cmd_fmt_merge_msg, NEEDS_PREFIX }, { "prune", cmd_prune, NEEDS_PREFIX }, { "mv", cmd_mv, NEEDS_PREFIX }, + { "prune-packed", cmd_prune_packed, NEEDS_PREFIX }, + { "repo-config", cmd_repo_config }, }; int i; @@ -275,8 +281,10 @@ static void handle_internal_command(int argc, const char **argv, char **envp) continue; prefix = NULL; - if (p->prefix) + if (p->option & NEEDS_PREFIX) prefix = setup_git_directory(); + if (p->option & USE_PAGER) + setup_pager(); if (getenv("GIT_TRACE")) { int i; fprintf(stderr, "trace: built-in: git"); @@ -372,7 +380,7 @@ int main(int argc, const char **argv, char **envp) } if (errno == ENOENT) - cmd_usage(0, exec_path, "'%s' is not a git-command", cmd); + help_unknown_cmd(cmd); fprintf(stderr, "Failed to run command '%s': %s\n", cmd, strerror(errno)); @@ -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 } @@ -4901,7 +4934,7 @@ proc domktag {} { proc redrawtags {id} { global canv linehtag commitrow idpos selectedline curview - global mainfont + global mainfont canvxmax if {![info exists commitrow($curview,$id)]} return drawcmitrow $commitrow($curview,$id) @@ -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} diff --git a/hash-object.c b/hash-object.c index 43bd93bff..5f89e64c1 100644 --- a/hash-object.c +++ b/hash-object.c @@ -46,7 +46,7 @@ int main(int argc, char **argv) if (!no_more_flags && argv[i][0] == '-') { if (!strcmp(argv[i], "-t")) { if (argc <= ++i) - die(hash_object_usage); + usage(hash_object_usage); type = argv[i]; } else if (!strcmp(argv[i], "-w")) { @@ -66,8 +66,8 @@ int main(int argc, char **argv) hash_stdin(type, write_object); } else - die(hash_object_usage); - } + usage(hash_object_usage); + } else { const char *arg = argv[i]; if (0 <= prefix_length) diff --git a/http-fetch.c b/http-fetch.c index 1aad39b4d..de5fc44e6 100644 --- a/http-fetch.c +++ b/http-fetch.c @@ -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); } @@ -1226,6 +1226,7 @@ int main(int argc, const char **argv) int arg = 1; int rc = 0; + setup_ident(); setup_git_directory(); git_config(git_default_config); diff --git a/http-push.c b/http-push.c index 4021e7d92..d45733ef6 100644 --- a/http-push.c +++ b/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(); diff --git a/index-pack.c b/index-pack.c index b39953dc6..b20659c25 100644 --- a/index-pack.c +++ b/index-pack.c @@ -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); diff --git a/local-fetch.c b/local-fetch.c index b216bdd55..7d01845d3 100644 --- a/local-fetch.c +++ b/local-fetch.c @@ -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); @@ -210,6 +210,7 @@ int main(int argc, const char **argv) char **commit_id; int arg = 1; + setup_ident(); setup_git_directory(); git_config(git_default_config); diff --git a/lockfile.c b/lockfile.c index 2346e0e9e..2a2fea3cb 100644 --- a/lockfile.c +++ b/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]; diff --git a/log-tree.c b/log-tree.c index b67b8dd17..05ede0c17 100644 --- a/log-tree.c +++ b/log-tree.c @@ -59,7 +59,7 @@ void show_log(struct rev_info *opt, const char *sep) fputs(diff_unique_abbrev(commit->object.sha1, abbrev_commit), stdout); if (opt->parents) show_parents(commit, abbrev_commit); - putchar('\n'); + putchar(opt->diffopt.line_termination); return; } diff --git a/merge-recursive.c b/merge-recursive.c index 454e29357..048cca1d1 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -125,9 +125,7 @@ static int flush_cache(void) { /* flush temporary index */ struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); - int fd = hold_lock_file_for_update(lock, current_index_file); - if (fd < 0) - die("could not lock %s", lock->filename); + int fd = hold_lock_file_for_update(lock, current_index_file, 1); if (write_cache(fd, active_cache, active_nr) || close(fd) || commit_lock_file(lock)) die ("unable to write %s", current_index_file); @@ -2,10 +2,11 @@ #include "tag.h" /* - * A signature file has a very simple fixed format: three lines - * of "object <sha1>" + "type <typename>" + "tag <tagname>", - * followed by some free-form signature that git itself doesn't - * care about, but that can be verified with gpg or similar. + * A signature file has a very simple fixed format: four lines + * of "object <sha1>" + "type <typename>" + "tag <tagname>" + + * "tagger <committer>", followed by a blank line, a free-form tag + * message and a signature block that git itself doesn't care about, + * but that can be verified with gpg or similar. * * The first three lines are guaranteed to be at least 63 bytes: * "object <sha1>\n" is 48 bytes, "type tag\n" at 9 bytes is the @@ -38,6 +39,12 @@ static int verify_object(unsigned char *sha1, const char *expected_type) return ret; } +#ifdef NO_C99_FORMAT +#define PD_FMT "%d" +#else +#define PD_FMT "%td" +#endif + static int verify_tag(char *buffer, unsigned long size) { int typelen; @@ -46,45 +53,42 @@ static int verify_tag(char *buffer, unsigned long size) const char *object, *type_line, *tag_line, *tagger_line; if (size < 64) - return error("wanna fool me ? you obviously got the size wrong !\n"); + return error("wanna fool me ? you obviously got the size wrong !"); buffer[size] = 0; /* Verify object line */ object = buffer; if (memcmp(object, "object ", 7)) - return error("char%d: does not start with \"object \"\n", 0); + return error("char%d: does not start with \"object \"", 0); if (get_sha1_hex(object + 7, sha1)) - return error("char%d: could not get SHA1 hash\n", 7); + return error("char%d: could not get SHA1 hash", 7); /* Verify type line */ type_line = object + 48; if (memcmp(type_line - 1, "\ntype ", 6)) - return error("char%d: could not find \"\\ntype \"\n", 47); + return error("char%d: could not find \"\\ntype \"", 47); /* Verify tag-line */ tag_line = strchr(type_line, '\n'); if (!tag_line) - return error("char%td: could not find next \"\\n\"\n", type_line - buffer); + return error("char" PD_FMT ": could not find next \"\\n\"", type_line - buffer); tag_line++; if (memcmp(tag_line, "tag ", 4) || tag_line[4] == '\n') - return error("char%td: no \"tag \" found\n", tag_line - buffer); + return error("char" PD_FMT ": no \"tag \" found", tag_line - buffer); /* Get the actual type */ typelen = tag_line - type_line - strlen("type \n"); if (typelen >= sizeof(type)) - return error("char%td: type too long\n", type_line+5 - buffer); + return error("char" PD_FMT ": type too long", type_line+5 - buffer); memcpy(type, type_line+5, typelen); type[typelen] = 0; /* Verify that the object matches */ - if (get_sha1_hex(object + 7, sha1)) - return error("char%d: could not get SHA1 hash but this is really odd since i got it before !\n", 7); - if (verify_object(sha1, type)) - return error("char%d: could not verify object %s\n", 7, sha1); + return error("char%d: could not verify object %s", 7, sha1_to_hex(sha1)); /* Verify the tag-name: we don't allow control characters or spaces in it */ tag_line += 4; @@ -94,19 +98,24 @@ static int verify_tag(char *buffer, unsigned long size) break; if (c > ' ') continue; - return error("char%td: could not verify tag name\n", tag_line - buffer); + return error("char" PD_FMT ": could not verify tag name", tag_line - buffer); } /* Verify the tagger line */ tagger_line = tag_line; if (memcmp(tagger_line, "tagger", 6) || (tagger_line[6] == '\n')) - return error("char%td: could not find \"tagger\"\n", tagger_line - buffer); + return error("char" PD_FMT ": could not find \"tagger\"", tagger_line - buffer); + + /* TODO: check for committer info + blank line? */ + /* Also, the minimum length is probably + "tagger .", or 63+8=71 */ /* The actual stuff afterwards we don't care about.. */ return 0; } +#undef PD_FMT + int main(int argc, char **argv) { unsigned long size = 4096; @@ -114,7 +123,7 @@ int main(int argc, char **argv) unsigned char result_sha1[20]; if (argc != 1) - usage("cat <signaturefile> | git-mktag"); + usage("git-mktag < signaturefile"); setup_git_directory(); @@ -71,7 +71,7 @@ static void write_tree(unsigned char *sha1) write_sha1_file(buffer, offset, tree_type, sha1); } -static const char mktree_usage[] = "mktree [-z]"; +static const char mktree_usage[] = "git-mktree [-z]"; int main(int ac, char **av) { diff --git a/read-cache.c b/read-cache.c index fc2af2cb0..c575edac4 100644 --- a/read-cache.c +++ b/read-cache.c @@ -61,7 +61,7 @@ static int ce_compare_data(struct cache_entry *ce, struct stat *st) unsigned char sha1[20]; if (!index_fd(sha1, fd, st, 0, NULL)) match = memcmp(sha1, ce->sha1, 20); - close(fd); + /* index_fd() closed the file descriptor already */ } return match; } @@ -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; } diff --git a/revision.c b/revision.c index a58257ad8..5a91d06b9 100644 --- a/revision.c +++ b/revision.c @@ -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; } @@ -184,7 +184,7 @@ const char *setup_git_directory_gently(int *nongit_ok) } return NULL; bad_dir_environ: - if (!nongit_ok) { + if (nongit_ok) { *nongit_ok = 1; return NULL; } diff --git a/sha1_file.c b/sha1_file.c index 43bc2ea0c..3db956dd5 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -590,7 +590,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? */ diff --git a/sha1_name.c b/sha1_name.c index 5fe8e5d4b..c5a05faeb 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -193,7 +193,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]; diff --git a/ssh-fetch.c b/ssh-fetch.c index 6e16568f8..c7d8fa80e 100644 --- a/ssh-fetch.c +++ b/ssh-fetch.c @@ -132,6 +132,7 @@ int main(int argc, char **argv) prog = getenv("GIT_SSH_PUSH"); if (!prog) prog = "git-ssh-upload"; + setup_ident(); setup_git_directory(); git_config(git_default_config); diff --git a/t/annotate-tests.sh b/t/annotate-tests.sh index b6a2edd88..8baf2fef6 100644 --- a/t/annotate-tests.sh +++ b/t/annotate-tests.sh @@ -4,7 +4,8 @@ check_count () { head= case "$1" in -h) head="$2"; shift; shift ;; esac - $PROG file $head | perl -e ' + $PROG file $head >.result || return 1 + cat .result | perl -e ' my %expect = (@ARGV); my %count = (); while (<STDIN>) { diff --git a/t/t1003-read-tree-prefix.sh b/t/t1003-read-tree-prefix.sh new file mode 100755 index 000000000..48ab117d7 --- /dev/null +++ b/t/t1003-read-tree-prefix.sh @@ -0,0 +1,27 @@ +#!/bin/sh +# +# Copyright (c) 2006 Junio C Hamano +# + +test_description='git-read-tree --prefix test. +' + +. ./test-lib.sh + +test_expect_success setup ' + echo hello >one && + git-update-index --add one && + tree=`git-write-tree` && + echo tree is $tree +' + +echo 'one +two/one' >expect + +test_expect_success 'read-tree --prefix' ' + git-read-tree --prefix=two/ $tree && + git-ls-files >actual && + cmp expect actual +' + +test_done diff --git a/t/t1020-subdirectory.sh b/t/t1020-subdirectory.sh new file mode 100755 index 000000000..4409b87f8 --- /dev/null +++ b/t/t1020-subdirectory.sh @@ -0,0 +1,109 @@ +#!/bin/sh +# +# Copyright (c) 2006 Junio C Hamano +# + +test_description='Try various core-level commands in subdirectory. +' + +. ./test-lib.sh + +test_expect_success setup ' + long="a b c d e f g h i j k l m n o p q r s t u v w x y z" && + for c in $long; do echo $c; done >one && + mkdir dir && + for c in x y z $long a b c; do echo $c; done >dir/two && + cp one original.one && + cp dir/two original.two +' +HERE=`pwd` +LF=' +' + +test_expect_success 'update-index and ls-files' ' + cd $HERE && + git-update-index --add one && + case "`git-ls-files`" in + one) echo ok one ;; + *) echo bad one; exit 1 ;; + esac && + cd dir && + git-update-index --add two && + case "`git-ls-files`" in + two) echo ok two ;; + *) echo bad two; exit 1 ;; + esac && + cd .. && + case "`git-ls-files`" in + dir/two"$LF"one) echo ok both ;; + *) echo bad; exit 1 ;; + esac +' + +test_expect_success 'cat-file' ' + cd $HERE && + two=`git-ls-files -s dir/two` && + two=`expr "$two" : "[0-7]* \\([0-9a-f]*\\)"` && + echo "$two" && + git-cat-file -p "$two" >actual && + cmp dir/two actual && + cd dir && + git-cat-file -p "$two" >actual && + cmp two actual +' +rm -f actual dir/actual + +test_expect_success 'diff-files' ' + cd $HERE && + echo a >>one && + echo d >>dir/two && + case "`git-diff-files --name-only`" in + dir/two"$LF"one) echo ok top ;; + *) echo bad top; exit 1 ;; + esac && + # diff should not omit leading paths + cd dir && + case "`git-diff-files --name-only`" in + dir/two"$LF"one) echo ok subdir ;; + *) echo bad subdir; exit 1 ;; + esac && + case "`git-diff-files --name-only .`" in + dir/two) echo ok subdir limited ;; + *) echo bad subdir limited; exit 1 ;; + esac +' + +test_expect_success 'write-tree' ' + cd $HERE && + top=`git-write-tree` && + echo $top && + cd dir && + sub=`git-write-tree` && + echo $sub && + test "z$top" = "z$sub" +' + +test_expect_success 'checkout-index' ' + cd $HERE && + git-checkout-index -f -u one && + cmp one original.one && + cd dir && + git-checkout-index -f -u two && + cmp two ../original.two +' + +test_expect_success 'read-tree' ' + cd $HERE && + rm -f one dir/two && + tree=`git-write-tree` && + git-read-tree --reset -u "$tree" && + cmp one original.one && + cmp dir/two original.two && + cd dir && + rm -f two && + git-read-tree --reset -u "$tree" && + cmp two ../original.two && + cmp ../one ../original.one +' + +test_done diff --git a/t/t3800-mktag.sh b/t/t3800-mktag.sh new file mode 100755 index 000000000..5b23b7769 --- /dev/null +++ b/t/t3800-mktag.sh @@ -0,0 +1,227 @@ +#!/bin/sh +# +# + +test_description='git-mktag: tag object verify test' + +. ./test-lib.sh + +########################################################### +# check the tag.sig file, expecting verify_tag() to fail, +# and checking that the error message matches the pattern +# given in the expect.pat file. + +check_verify_failure () { + test_expect_success \ + "$1" \ + 'git-mktag <tag.sig 2>message || + egrep -q -f expect.pat message' +} + +########################################################### +# first create a commit, so we have a valid object/type +# for the tag. +echo Hello >A +git-update-index --add A +git-commit -m "Initial commit" +head=$(git-rev-parse --verify HEAD) + +############################################################ +# 1. length check + +cat >tag.sig <<EOF +too short for a tag +EOF + +cat >expect.pat <<EOF +^error: .*size wrong.*$ +EOF + +check_verify_failure 'Tag object length check' + +############################################################ +# 2. object line label check + +cat >tag.sig <<EOF +xxxxxx 139e9b33986b1c2670fff52c5067603117b3e895 +type tag +tag mytag +EOF + +cat >expect.pat <<EOF +^error: char0: .*"object "$ +EOF + +check_verify_failure '"object" line label check' + +############################################################ +# 3. object line SHA1 check + +cat >tag.sig <<EOF +object zz9e9b33986b1c2670fff52c5067603117b3e895 +type tag +tag mytag +EOF + +cat >expect.pat <<EOF +^error: char7: .*SHA1 hash$ +EOF + +check_verify_failure '"object" line SHA1 check' + +############################################################ +# 4. type line label check + +cat >tag.sig <<EOF +object 779e9b33986b1c2670fff52c5067603117b3e895 +xxxx tag +tag mytag +EOF + +cat >expect.pat <<EOF +^error: char47: .*"[\]ntype "$ +EOF + +check_verify_failure '"type" line label check' + +############################################################ +# 5. type line eol check + +echo "object 779e9b33986b1c2670fff52c5067603117b3e895" >tag.sig +echo -n "type tagsssssssssssssssssssssssssssssss" >>tag.sig + +cat >expect.pat <<EOF +^error: char48: .*"[\]n"$ +EOF + +check_verify_failure '"type" line eol check' + +############################################################ +# 6. tag line label check #1 + +cat >tag.sig <<EOF +object 779e9b33986b1c2670fff52c5067603117b3e895 +type tag +xxx mytag +EOF + +cat >expect.pat <<EOF +^error: char57: no "tag " found$ +EOF + +check_verify_failure '"tag" line label check #1' + +############################################################ +# 7. tag line label check #2 + +cat >tag.sig <<EOF +object 779e9b33986b1c2670fff52c5067603117b3e895 +type taggggggggggggggggggggggggggggggg +tag +EOF + +cat >expect.pat <<EOF +^error: char87: no "tag " found$ +EOF + +check_verify_failure '"tag" line label check #2' + +############################################################ +# 8. type line type-name length check + +cat >tag.sig <<EOF +object 779e9b33986b1c2670fff52c5067603117b3e895 +type taggggggggggggggggggggggggggggggg +tag mytag +EOF + +cat >expect.pat <<EOF +^error: char53: type too long$ +EOF + +check_verify_failure '"type" line type-name length check' + +############################################################ +# 9. verify object (SHA1/type) check + +cat >tag.sig <<EOF +object 779e9b33986b1c2670fff52c5067603117b3e895 +type tagggg +tag mytag +EOF + +cat >expect.pat <<EOF +^error: char7: could not verify object.*$ +EOF + +check_verify_failure 'verify object (SHA1/type) check' + +############################################################ +# 10. verify tag-name check + +cat >tag.sig <<EOF +object $head +type commit +tag my tag +EOF + +cat >expect.pat <<EOF +^error: char67: could not verify tag name$ +EOF + +check_verify_failure 'verify tag-name check' + +############################################################ +# 11. tagger line lable check #1 + +cat >tag.sig <<EOF +object $head +type commit +tag mytag +EOF + +cat >expect.pat <<EOF +^error: char70: could not find "tagger"$ +EOF + +check_verify_failure '"tagger" line label check #1' + +############################################################ +# 12. tagger line lable check #2 + +cat >tag.sig <<EOF +object $head +type commit +tag mytag +tagger +EOF + +cat >expect.pat <<EOF +^error: char70: could not find "tagger"$ +EOF + +check_verify_failure '"tagger" line label check #2' + +############################################################ +# 13. create valid tag + +cat >tag.sig <<EOF +object $head +type commit +tag mytag +tagger another@example.com +EOF + +test_expect_success \ + 'create valid tag' \ + 'git-mktag <tag.sig >.git/refs/tags/mytag 2>message' + +############################################################ +# 14. check mytag + +test_expect_success \ + 'check mytag' \ + 'git-tag -l | grep mytag' + + +test_done diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh index b24c829f0..71c454356 100755 --- a/t/t4013-diff-various.sh +++ b/t/t4013-diff-various.sh @@ -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" diff --git a/t/t4115-apply-symlink.sh b/t/t4115-apply-symlink.sh new file mode 100755 index 000000000..d5f2cfb18 --- /dev/null +++ b/t/t4115-apply-symlink.sh @@ -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 diff --git a/t/t7002-grep.sh b/t/t7002-grep.sh new file mode 100755 index 000000000..00a7d762c --- /dev/null +++ b/t/t7002-grep.sh @@ -0,0 +1,85 @@ +#!/bin/sh +# +# Copyright (c) 2006 Junio C Hamano +# + +test_description='git grep -w +' + +. ./test-lib.sh + +test_expect_success setup ' + { + echo foo mmap bar + echo foo_mmap bar + echo foo_mmap bar mmap + echo foo mmap bar_mmap + echo foo_mmap bar mmap baz + } >file && + echo x x xx x >x && + echo y yy >y && + echo zzz > z && + git add file x y z && + git commit -m initial +' + +for H in HEAD '' +do + case "$H" in + HEAD) HC='HEAD:' L='HEAD' ;; + '') HC= L='in working tree' ;; + esac + + test_expect_success "grep -w $L" ' + { + echo ${HC}file:1:foo mmap bar + echo ${HC}file:3:foo_mmap bar mmap + echo ${HC}file:4:foo mmap bar_mmap + echo ${HC}file:5:foo_mmap bar mmap baz + } >expected && + git grep -n -w -e mmap $H >actual && + diff expected actual + ' + + test_expect_success "grep -w $L (x)" ' + { + echo ${HC}x:1:x x xx x + } >expected && + git grep -n -w -e "x xx* x" $H >actual && + diff expected actual + ' + + test_expect_success "grep -w $L (y-1)" ' + { + echo ${HC}y:1:y yy + } >expected && + git grep -n -w -e "^y" $H >actual && + diff expected actual + ' + + test_expect_success "grep -w $L (y-2)" ' + : >expected && + if git grep -n -w -e "^y y" $H >actual + then + echo should not have matched + cat actual + false + else + diff expected actual + fi + ' + + test_expect_success "grep -w $L (z)" ' + : >expected && + if git grep -n -w -e "^z" $H >actual + then + echo should not have matched + cat actual + false + else + diff expected actual + fi + ' +done + +test_done diff --git a/t/t9100-git-svn-basic.sh b/t/t9100-git-svn-basic.sh index bf1d6381d..34a3ccd31 100755 --- a/t/t9100-git-svn-basic.sh +++ b/t/t9100-git-svn-basic.sh @@ -170,7 +170,7 @@ then test -L $SVN_TREE/exec-2.sh" name='modify a symlink to become a file' - git help > help || true + echo git help > help || true rm exec-2.sh cp help exec-2.sh git update-index exec-2.sh @@ -217,10 +217,10 @@ name='check imported tree checksums expected tree checksums' rm -f expected if test "$have_utf8" = t then - echo tree f735671b89a7eb30cab1d8597de35bd4271ab813 > expected + echo tree bf522353586b1b883488f2bc73dab0d9f774b9a9 > expected fi cat >> expected <<\EOF -tree 4b9af72bb861eaed053854ec502cf7df72618f0f +tree 83654bb36f019ae4fe77a0171f81075972087624 tree 031b8d557afc6fea52894eaebb45bec52f1ba6d1 tree 0b094cbff17168f24c302e297f55bfac65eb8bd3 tree d667270a1f7b109f5eb3aaea21ede14b56bfdd6e @@ -231,4 +231,3 @@ EOF test_expect_success "$name" "diff -u a expected" test_done - diff --git a/templates/Makefile b/templates/Makefile index 8f7f4fec3..9e1ae1a4e 100644 --- a/templates/Makefile +++ b/templates/Makefile @@ -6,11 +6,9 @@ prefix ?= $(HOME) template_dir ?= $(prefix)/share/git-core/templates/ # DESTDIR= -# Shell quote; -# Result of this needs to be placed inside '' -shq = $(subst ','\'',$(1)) -# This has surrounding '' -shellquote = '$(call shq,$(1))' +# Shell quote (do not use $(call) to accomodate ancient setups); +DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) +template_dir_SQ = $(subst ','\'',$(template_dir)) all: boilerplates.made custom @@ -43,6 +41,6 @@ clean: rm -rf blt boilerplates.made install: all - $(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(template_dir)) + $(INSTALL) -d -m755 '$(DESTDIR_SQ)$(template_dir_SQ)' (cd blt && $(TAR) cf - .) | \ - (cd $(call shellquote,$(DESTDIR)$(template_dir)) && $(TAR) xf -) + (cd '$(DESTDIR_SQ)$(template_dir_SQ)' && $(TAR) xf -) diff --git a/verify-pack.c b/verify-pack.c index c99db9dd7..357970da3 100644 --- a/verify-pack.c +++ b/verify-pack.c @@ -1,43 +1,60 @@ #include "cache.h" #include "pack.h" -static int verify_one_pack(char *arg, int verbose) +static int verify_one_pack(const char *path, int verbose) { - int len = strlen(arg); - 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? */ + 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; - if ((g = add_packed_git(arg, len, 1))) - break; - return error("packfile %s not found.", arg); } - return verify_pack(g, verbose); + + /* + * add_packed_git() uses our buffer (containing "foo.idx") to + * build the pack filename ("foo.pack"). Make sure it fits. + */ + if (len + 1 >= PATH_MAX) { + arg[len - 4] = '\0'; + return error("name too long: %s.pack", arg); + } + + pack = add_packed_git(arg, len, 1); + if (!pack) + return error("packfile %s not found.", arg); + + err = verify_pack(pack, verbose); + free(pack); + + return err; } static const char verify_pack_usage[] = "git-verify-pack [-v] <pack>..."; int main(int ac, char **av) { - int errs = 0; + int err = 0; int verbose = 0; int no_more_options = 0; + int nothing_done = 1; while (1 < ac) { - char path[PATH_MAX]; - if (!no_more_options && av[1][0] == '-') { if (!strcmp("-v", av[1])) verbose = 1; @@ -47,11 +64,15 @@ int main(int ac, char **av) usage(verify_pack_usage); } else { - strcpy(path, av[1]); - if (verify_one_pack(path, verbose)) - errs++; + if (verify_one_pack(av[1], verbose)) + err = 1; + nothing_done = 0; } ac--; av++; } - return !!errs; + + if (nothing_done) + usage(verify_pack_usage); + + return err; } |