Merge branch 'js/c-merge-recursive'
authorJunio C Hamano <junkio@cox.net>
Mon, 28 Aug 2006 03:18:58 +0000 (20:18 -0700)
committerJunio C Hamano <junkio@cox.net>
Mon, 28 Aug 2006 03:33:46 +0000 (20:33 -0700)
* js/c-merge-recursive: (21 commits)
  discard_cache(): discard index, even if no file was mmap()ed
  merge-recur: do not die unnecessarily
  merge-recur: try to merge older merge bases first
  merge-recur: if there is no common ancestor, fake empty one
  merge-recur: do not setenv("GIT_INDEX_FILE")
  merge-recur: do not call git-write-tree
  merge-recursive: fix rename handling
  .gitignore: git-merge-recur is a built file.
  merge-recur: virtual commits shall never be parsed
  merge-recur: use the unpack_trees() interface instead of exec()ing read-tree
  merge-recur: fix thinko in unique_path()
  Makefile: git-merge-recur depends on xdiff libraries.
  merge-recur: Explain why sha_eq() and struct stage_data cannot go
  merge-recur: Cleanup last mixedCase variables...
  merge-recur: Fix compiler warning with -pedantic
  merge-recur: Remove dead code
  merge-recur: Get rid of debug code
  merge-recur: Convert variable names to lower_case
  Cumulative update of merge-recursive in C
  recur vs recursive: help testing without touching too many stuff.
  ...

This is an evil merge that removes TEST script from the toplevel.

127 files changed:
.gitignore
Documentation/diff-options.txt
Documentation/git-apply.txt
Documentation/git-blame.txt
Documentation/git-daemon.txt
Documentation/git-grep.txt
Documentation/git-ls-remote.txt
Documentation/git-svn.txt
Documentation/git-update-index.txt
Documentation/git-zip-tree.txt [new file with mode: 0644]
Documentation/git.txt
Documentation/gitk.txt
Documentation/technical/racy-git.txt [new file with mode: 0644]
INSTALL
Makefile
TEST [deleted file]
blame.c
builtin-apply.c
builtin-cat-file.c
builtin-checkout-index.c [moved from checkout-index.c with 92% similarity]
builtin-commit-tree.c
builtin-count-objects.c [moved from builtin-count.c with 100% similarity]
builtin-diff-files.c
builtin-diff-stages.c
builtin-diff.c
builtin-fmt-merge-msg.c
builtin-grep.c
builtin-log.c
builtin-ls-files.c
builtin-ls-tree.c
builtin-mailinfo.c
builtin-mv.c
builtin-name-rev.c [moved from name-rev.c with 98% similarity]
builtin-pack-objects.c [moved from pack-objects.c with 96% similarity]
builtin-prune.c
builtin-push.c
builtin-read-tree.c
builtin-repo-config.c
builtin-rev-list.c
builtin-rev-parse.c
builtin-show-branch.c
builtin-symbolic-ref.c [moved from symbolic-ref.c with 88% similarity]
builtin-tar-tree.c
builtin-unpack-objects.c [moved from unpack-objects.c with 95% similarity]
builtin-update-index.c
builtin-update-ref.c
builtin-verify-pack.c [moved from verify-pack.c with 83% similarity]
builtin-write-tree.c
builtin-zip-tree.c [new file with mode: 0644]
builtin.h
cache-tree.c
cache.h
check-racy.c [new file with mode: 0644]
combine-diff.c
commit.c
config.mak.in
configure.ac
connect.c
contrib/emacs/vc-git.el
contrib/gitview/gitview.txt
convert-objects.c
csum-file.c
daemon.c
date.c
describe.c
diff-delta.c
diff-lib.c
diff.c
diff.h
diffcore-break.c
diffcore-rename.c
dir.c
dump-cache-tree.c
entry.c
environment.c
exec_cmd.c
fetch-clone.c
fetch-pack.c
fetch.c
fsck-objects.c
git-cherry.sh
git-compat-util.h
git-reset.sh
git-send-email.perl
git-svn.perl
git.c
gitweb/README
gitweb/git-logo.png [new file with mode: 0644]
gitweb/gitweb.css
gitweb/gitweb.perl [moved from gitweb/gitweb.cgi with 51% similarity]
help.c [moved from builtin-help.c with 99% similarity]
http-fetch.c
http-push.c
index-pack.c
local-fetch.c
log-tree.c
merge-base.c
merge-index.c
merge-tree.c
mktree.c
object.c
pack-check.c
pack-redundant.c
pager.c
patch-id.c
read-cache.c
receive-pack.c
refs.c
revision.c
run-command.c
send-pack.c
sha1_file.c
sha1_name.c
ssh-fetch.c
ssh-upload.c
t/t4116-apply-reverse.sh [new file with mode: 0755]
t/t4117-apply-reject.sh [new file with mode: 0755]
t/t7001-mv.sh
t/t7002-grep.sh
templates/hooks--commit-msg
tree-diff.c
tree-walk.c
tree.c
unpack-trees.c
upload-pack.c
write_or_die.c [new file with mode: 0644]
xdiff-interface.c

index 2299e36..3da0e5e 100644 (file)
@@ -126,6 +126,7 @@ git-verify-tag
 git-whatchanged
 git-write-tree
 git-core-*/?*
+gitweb/gitweb.cgi
 test-date
 test-delta
 test-dump-cache-tree
@@ -141,7 +142,7 @@ config.mak
 autom4te.cache
 config.log
 config.status
-config.mak.in
 config.mak.autogen
+config.mak.append
 configure
 git-blame
index 47ba9a4..b5d9763 100644 (file)
@@ -36,6 +36,9 @@
        Turn off colored diff, even when the configuration file
        gives the default to color output.
 
+--color-words::
+       Show colored word diff, i.e. color words which have changed.
+
 --no-renames::
        Turn off rename detection, even when the configuration
        file gives the default to do so.
index 2ff7494..c76cfff 100644 (file)
@@ -10,9 +10,10 @@ SYNOPSIS
 --------
 [verse]
 'git-apply' [--stat] [--numstat] [--summary] [--check] [--index] [--apply]
-         [--no-add] [--index-info] [--allow-binary-replacement] [-z] [-pNUM]
-         [-CNUM] [--whitespace=<nowarn|warn|error|error-all|strip>]
-         [<patch>...]
+         [--no-add] [--index-info] [--allow-binary-replacement | --binary]
+         [-R | --reverse] [--reject] [-z] [-pNUM] [-CNUM] [--inaccurate-eof]
+         [--whitespace=<nowarn|warn|error|error-all|strip>] [--exclude=PATH]
+         [--cached] [--verbose] [<patch>...]
 
 DESCRIPTION
 -----------
@@ -55,6 +56,11 @@ OPTIONS
        up-to-date, it is flagged as an error.  This flag also
        causes the index file to be updated.
 
+--cached::
+       Apply a patch without touching the working tree. Instead, take the
+       cached data, apply the patch, and store the result in the index,
+       without using the working tree. This implies '--index'.
+
 --index-info::
        Newer git-diff output has embedded 'index information'
        for each blob to help identify the original version that
@@ -62,6 +68,16 @@ OPTIONS
        the original version of the blob is available locally,
        outputs information about them to the standard output.
 
+-R, --reverse::
+       Apply the patch in reverse.
+
+--reject::
+       For atomicity, gitlink:git-apply[1] by default fails the whole patch and
+       does not touch the working tree when some of the hunks
+       do not apply.  This option makes it apply
+       the parts of the patch that are applicable, and leave the
+       rejected hunks in corresponding *.rej files.
+
 -z::
        When showing the index information, do not munge paths,
        but use NUL terminated machine readable format.  Without
@@ -80,8 +96,8 @@ OPTIONS
        ever ignored.
 
 --apply::
-       If you use any of the options marked ``Turns off
-       "apply"'' above, git-apply reads and outputs the
+       If you use any of the options marked "Turns off
+       'apply'" above, gitlink:git-apply[1] reads and outputs the
        information you asked without actually applying the
        patch.  Give this flag after those flags to also apply
        the patch.
@@ -93,7 +109,7 @@ OPTIONS
        the result with this option, which would apply the
        deletion part but not addition part.
 
---allow-binary-replacement::
+--allow-binary-replacement, --binary::
        When applying a patch, which is a git-enhanced patch
        that was prepared to record the pre- and post-image object
        name in full, and the path being patched exactly matches
@@ -104,13 +120,18 @@ OPTIONS
        result.  This allows binary files to be patched in a
        very limited way.
 
+--exclude=<path-pattern>::
+       Don't apply changes to files matching the given path pattern. This can
+       be useful when importing patchsets, where you want to exclude certain
+       files or directories.
+
 --whitespace=<option>::
        When applying a patch, detect a new or modified line
        that ends with trailing whitespaces (this includes a
        line that solely consists of whitespaces).  By default,
        the command outputs warning messages and applies the
        patch.
-       When `git-apply` is used for statistics and not applying a
+       When gitlink:git-apply[1] is used for statistics and not applying a
        patch, it defaults to `nowarn`.
        You can use different `<option>` to control this
        behavior:
@@ -124,6 +145,17 @@ OPTIONS
 * `strip` outputs warnings for a few such errors, strips out the
   trailing whitespaces and applies the patch.
 
+--inacurate-eof::
+       Under certain circumstances, some versions of diff do not correctly
+       detect a missing new-line at the end of the file. As a result, patches
+       created by such diff programs do not record incomplete lines
+       correctly. This option adds support for applying such patches by
+       working around this bug.
+
+--verbose::
+       Report progress to stderr. By default, only a message about the
+       current patch being applied will be printed. This option will cause
+       additional information to be reported.
 
 Configuration
 -------------
index bfed945..e1f8944 100644 (file)
@@ -3,21 +3,38 @@ git-blame(1)
 
 NAME
 ----
-git-blame - Blame file lines on commits
+git-blame - Show what revision and author last modified each line of a file
 
 SYNOPSIS
 --------
-git-blame file [options] file [revision]
+'git-blame' [-c] [-l] [-t] [-S <revs-file>] [--] <file> [<rev>]
 
 DESCRIPTION
 -----------
-Annotates each line in the given file with information from the commit
-which introduced the line. Start annotation from the given revision.
+
+Annotates each line in the given file with information from the revision which
+last modified the line. Optionally, start annotating from the given revision.
+
+This report doesn't tell you anything about lines which have been deleted or
+replaced; you need to use a tool such as gitlink:git-diff[1] or the "pickaxe"
+interface briefly mentioned in the following paragraph.
+
+Apart from supporting file annotation, git also supports searching the
+development history for when a code snippet occured in a change. This makes it
+possible to track when a code snippet was added to a file, moved or copied
+between files, and eventually deleted or replaced. It works by searching for
+a text string in the diff. A small example:
+
+-----------------------------------------------------------------------------
+$ git log --pretty=oneline -S'blame_usage'
+5040f17eba15504bad66b14a645bddd9b015ebb7 blame -S <ancestry-file>
+ea4c7f9bf69e781dd0cd88d2bccb2bf5cc15c9a7 git-blame: Make the output
+-----------------------------------------------------------------------------
 
 OPTIONS
 -------
 -c, --compatibility::
-       Use the same output mode as git-annotate (Default: off).
+       Use the same output mode as gitlink:git-annotate[1] (Default: off).
 
 -l, --long::
        Show long rev (Default: off).
@@ -26,7 +43,7 @@ OPTIONS
        Show raw timestamp (Default: off).
 
 -S, --rev-file <revs-file>::
-       Use revs from revs-file instead of calling git-rev-list.
+       Use revs from revs-file instead of calling gitlink:git-rev-list[1].
 
 -h, --help::
        Show help message.
index 0f7d274..17619a3 100644 (file)
@@ -11,7 +11,8 @@ SYNOPSIS
 'git-daemon' [--verbose] [--syslog] [--inetd | --port=n] [--export-all]
              [--timeout=n] [--init-timeout=n] [--strict-paths]
              [--base-path=path] [--user-path | --user-path=path]
-            [--reuseaddr] [--detach] [--pid-file=file] [directory...]
+            [--reuseaddr] [--detach] [--pid-file=file]
+            [--user=user [--group=group]] [directory...]
 
 DESCRIPTION
 -----------
@@ -93,6 +94,17 @@ OPTIONS
 --pid-file=file::
        Save the process id in 'file'.
 
+--user=user, --group=group::
+       Change daemon's uid and gid before entering the service loop.
+       When only `--user` is given without `--group`, the
+       primary group ID for the user is used.  The values of
+       the option are given to `getpwnam(3)` and `getgrnam(3)`
+       and numeric IDs are not supported.
++
+Giving these options is an error when used with `--inetd`; use
+the facility of inet daemon to achieve the same before spawning
+`git-daemon` if needed.
+
 <directory>::
        A directory to add to the whitelist of allowed directories. Unless
        --strict-paths is specified this will also include subdirectories
index dc76833..7545dd9 100644 (file)
@@ -11,7 +11,7 @@ SYNOPSIS
 [verse]
 'git-grep' [--cached]
           [-a | --text] [-I] [-i | --ignore-case] [-w | --word-regexp]
-          [-v | --invert-match]
+          [-v | --invert-match] [--full-name]
           [-E | --extended-regexp] [-G | --basic-regexp] [-F | --fixed-strings]
           [-n] [-l | --files-with-matches] [-L | --files-without-match]
           [-c | --count]
@@ -47,6 +47,12 @@ OPTIONS
 -v | --invert-match::
        Select non-matching lines.
 
+--full-name::
+       When run from a subdirectory, the command usually
+       outputs paths relative to the current directory.  This
+       option forces paths to be output relative to the project
+       top directory.
+
 -E | --extended-regexp | -G | --basic-regexp::
        Use POSIX extended/basic regexp for patterns.  Default
        is to use basic regexp.
index ae4c1a2..c8a4c5a 100644 (file)
@@ -3,16 +3,19 @@ git-ls-remote(1)
 
 NAME
 ----
-git-ls-remote - Look at references other repository has
+git-ls-remote - List references in a remote repository
 
 
 SYNOPSIS
 --------
-'git-ls-remote' [--heads] [--tags] <repository> <refs>...
+[verse]
+'git-ls-remote' [--heads] [--tags]  [-u <exec> | --upload-pack <exec>]
+             <repository> <refs>...
 
 DESCRIPTION
 -----------
-Displays the references other repository has.
+Displays references available in a remote repository along with the associated
+commit IDs.
 
 
 OPTIONS
@@ -23,9 +26,16 @@ OPTIONS
        both, references stored in refs/heads and refs/tags are
        displayed.
 
+-u <exec>, --upload-pack=<exec>::
+       Specify the full path of gitlink:git-upload-pack[1] on the remote
+       host. This allows listing references from repositories accessed via
+       SSH and where the SSH deamon does not use the PATH configured by the
+       user. Also see the '--exec' option for gitlink:git-peek-remote[1].
+
 <repository>::
        Location of the repository.  The shorthand defined in
-       $GIT_DIR/branches/ can be used.
+       $GIT_DIR/branches/ can be used. Use "." (dot) to list references in
+       the local repository.
 
 <refs>...::
        When unspecified, all references, after filtering done
index 7d86809..b7b63f7 100644 (file)
@@ -12,10 +12,8 @@ SYNOPSIS
 DESCRIPTION
 -----------
 git-svn is a simple conduit for changesets between a single Subversion
-branch and git.
-
-git-svn is not to be confused with git-svnimport.  The were designed
-with very different goals in mind.
+branch and git. It is not to be confused with gitlink:git-svnimport[1].
+They were designed with very different goals in mind.
 
 git-svn is designed for an individual developer who wants a
 bidirectional flow of changesets between a single branch in Subversion
@@ -34,26 +32,38 @@ git-svnimport is designed for.
 
 COMMANDS
 --------
-init::
+--
+
+'init'::
        Creates an empty git repository with additional metadata
        directories for git-svn.  The Subversion URL must be specified
        as a command-line argument.
 
-fetch::
-       Fetch unfetched revisions from the Subversion URL we are
-       tracking.  refs/remotes/git-svn will be updated to the
-       latest revision.
+'fetch'::
+
+Fetch unfetched revisions from the Subversion URL we are
+tracking.  refs/remotes/git-svn will be updated to the
+latest revision.
+
+Note: You should never attempt to modify the remotes/git-svn
+branch outside of git-svn.  Instead, create a branch from
+remotes/git-svn and work on that branch.  Use the 'commit'
+command (see below) to write git commits back to
+remotes/git-svn.
 
-       Note: You should never attempt to modify the remotes/git-svn
-       branch outside of git-svn.  Instead, create a branch from
-       remotes/git-svn and work on that branch.  Use the 'commit'
-       command (see below) to write git commits back to
-       remotes/git-svn.
+See '<<fetch-args,Additional Fetch Arguments>>' if you are interested in
+manually joining branches on commit.
 
-       See 'Additional Fetch Arguments' if you are interested in
-       manually joining branches on commit.
+'dcommit'::
+       Commit all diffs from the current HEAD directly to the SVN
+       repository, and then rebase or reset (depending on whether or
+       not there is a diff between SVN and HEAD).  It is recommended
+       that you run git-svn fetch and rebase (not pull) your commits
+       against the latest changes in the SVN repository.
+       This is advantageous over 'commit' (below) because it produces
+       cleaner, more linear history.
 
-commit::
+'commit'::
        Commit specified commit or tree objects to SVN.  This relies on
        your imported fetch data being up-to-date.  This makes
        absolutely no attempts to do patching when committing to SVN, it
@@ -61,9 +71,9 @@ commit::
        commit.  All merging is assumed to have taken place
        independently of git-svn functions.
 
-rebuild::
+'rebuild'::
        Not a part of daily usage, but this is a useful command if
-       you've just cloned a repository (using git-clone) that was
+       you've just cloned a repository (using gitlink:git-clone[1]) that was
        tracked with git-svn.  Unfortunately, git-clone does not clone
        git-svn metadata and the svn working tree that git-svn uses for
        its operations.  This rebuilds the metadata so git-svn can
@@ -71,130 +81,170 @@ rebuild::
        specified at the command-line if the directory/repository you're
        tracking has moved or changed protocols.
 
-show-ignore::
+'show-ignore'::
        Recursively finds and lists the svn:ignore property on
        directories.  The output is suitable for appending to
        the $GIT_DIR/info/exclude file.
 
+--
+
 OPTIONS
 -------
+--
+
 -r <ARG>::
 --revision <ARG>::
-       Only used with the 'fetch' command.
 
-       Takes any valid -r<argument> svn would accept and passes it
-       directly to svn. -r<ARG1>:<ARG2> ranges and "{" DATE "}" syntax
-       is also supported.  This is passed directly to svn, see svn
-       documentation for more details.
+Only used with the 'fetch' command.
+
+Takes any valid -r<argument> svn would accept and passes it
+directly to svn. -r<ARG1>:<ARG2> ranges and "{" DATE "}" syntax
+is also supported.  This is passed directly to svn, see svn
+documentation for more details.
 
-       This can allow you to make partial mirrors when running fetch.
+This can allow you to make partial mirrors when running fetch.
 
 -::
 --stdin::
-       Only used with the 'commit' command.
 
-       Read a list of commits from stdin and commit them in reverse
-       order.  Only the leading sha1 is read from each line, so
-       git-rev-list --pretty=oneline output can be used.
+Only used with the 'commit' command.
+
+Read a list of commits from stdin and commit them in reverse
+order.  Only the leading sha1 is read from each line, so
+git-rev-list --pretty=oneline output can be used.
 
 --rmdir::
-       Only used with the 'commit' command.
 
-       Remove directories from the SVN tree if there are no files left
-       behind.  SVN can version empty directories, and they are not
-       removed by default if there are no files left in them.  git
-       cannot version empty directories.  Enabling this flag will make
-       the commit to SVN act like git.
+Only used with the 'commit' command.
+
+Remove directories from the SVN tree if there are no files left
+behind.  SVN can version empty directories, and they are not
+removed by default if there are no files left in them.  git
+cannot version empty directories.  Enabling this flag will make
+the commit to SVN act like git.
 
-       repo-config key: svn.rmdir
+repo-config key: svn.rmdir
 
 -e::
 --edit::
-       Only used with the 'commit' command.
 
-       Edit the commit message before committing to SVN.  This is off by
-       default for objects that are commits, and forced on when committing
-       tree objects.
+Only used with the 'commit' command.
 
-       repo-config key: svn.edit
+Edit the commit message before committing to SVN.  This is off by
+default for objects that are commits, and forced on when committing
+tree objects.
+
+repo-config key: svn.edit
 
 -l<num>::
 --find-copies-harder::
-       Both of these are only used with the 'commit' command.
 
-       They are both passed directly to git-diff-tree see
-       git-diff-tree(1) for more information.
+Both of these are only used with the 'commit' command.
+
+They are both passed directly to git-diff-tree see
+gitlink:git-diff-tree[1] for more information.
 
-       repo-config key: svn.l
-       repo-config key: svn.findcopiesharder
+[verse]
+repo-config key: svn.l
+repo-config key: svn.findcopiesharder
 
 -A<filename>::
 --authors-file=<filename>::
 
-       Syntax is compatible with the files used by git-svnimport and
-       git-cvsimport:
+Syntax is compatible with the files used by git-svnimport and
+git-cvsimport:
 
 ------------------------------------------------------------------------
-loginname = Joe User <user@example.com>
+       loginname = Joe User <user@example.com>
 ------------------------------------------------------------------------
 
-       If this option is specified and git-svn encounters an SVN
-       committer name that does not exist in the authors-file, git-svn
-       will abort operation. The user will then have to add the
-       appropriate entry.  Re-running the previous git-svn command
-       after the authors-file is modified should continue operation.
+If this option is specified and git-svn encounters an SVN
+committer name that does not exist in the authors-file, git-svn
+will abort operation. The user will then have to add the
+appropriate entry.  Re-running the previous git-svn command
+after the authors-file is modified should continue operation.
+
+repo-config key: svn.authors-file
+
+-m::
+--merge::
+-s<strategy>::
+--strategy=<strategy>::
+
+These are only used with the 'dcommit' command.
 
-       repo-config key: svn.authors-file
+Passed directly to git-rebase when using 'dcommit' if a
+'git-reset' cannot be used (see dcommit).
+
+-n::
+--dry-run::
+
+This is only used with the 'dcommit' command.
+
+Print out the series of git arguments that would show
+which diffs would be committed to SVN.
+
+--
 
 ADVANCED OPTIONS
 ----------------
+--
+
 -b<refname>::
 --branch <refname>::
-       Used with 'fetch' or 'commit'.
+Used with 'fetch' or 'commit'.
 
-       This can be used to join arbitrary git branches to remotes/git-svn
-       on new commits where the tree object is equivalent.
+This can be used to join arbitrary git branches to remotes/git-svn
+on new commits where the tree object is equivalent.
 
-       When used with different GIT_SVN_ID values, tags and branches in
-       SVN can be tracked this way, as can some merges where the heads
-       end up having completely equivalent content.  This can even be
-       used to track branches across multiple SVN _repositories_.
+When used with different GIT_SVN_ID values, tags and branches in
+SVN can be tracked this way, as can some merges where the heads
+end up having completely equivalent content.  This can even be
+used to track branches across multiple SVN _repositories_.
 
-       This option may be specified multiple times, once for each
-       branch.
+This option may be specified multiple times, once for each
+branch.
 
-       repo-config key: svn.branch
+repo-config key: svn.branch
 
 -i<GIT_SVN_ID>::
 --id <GIT_SVN_ID>::
-       This sets GIT_SVN_ID (instead of using the environment).  See
-       the section on "Tracking Multiple Repositories or Branches" for
-       more information on using GIT_SVN_ID.
+
+This sets GIT_SVN_ID (instead of using the environment).  See the
+section on
+'<<tracking-multiple-repos,Tracking Multiple Repositories or Branches>>'
+for more information on using GIT_SVN_ID.
+
+--
 
 COMPATIBILITY OPTIONS
 ---------------------
+--
+
 --upgrade::
-       Only used with the 'rebuild' command.
+Only used with the 'rebuild' command.
 
-       Run this if you used an old version of git-svn that used
-       "git-svn-HEAD" instead of "remotes/git-svn" as the branch
-       for tracking the remote.
+Run this if you used an old version of git-svn that used
+"git-svn-HEAD" instead of "remotes/git-svn" as the branch
+for tracking the remote.
 
 --no-ignore-externals::
-       Only used with the 'fetch' and 'rebuild' command.
+Only used with the 'fetch' and 'rebuild' command.
+
+By default, git-svn passes --ignore-externals to svn to avoid
+fetching svn:external trees into git.  Pass this flag to enable
+externals tracking directly via git.
 
-       By default, git-svn passes --ignore-externals to svn to avoid
-       fetching svn:external trees into git.  Pass this flag to enable
-       externals tracking directly via git.
+Versions of svn that do not support --ignore-externals are
+automatically detected and this flag will be automatically
+enabled for them.
 
-       Versions of svn that do not support --ignore-externals are
-       automatically detected and this flag will be automatically
-       enabled for them.
+Otherwise, do not enable this flag unless you know what you're
+doing.
 
-       Otherwise, do not enable this flag unless you know what you're
-       doing.
+repo-config key: svn.noignoreexternals
 
-       repo-config key: svn.noignoreexternals
+--
 
 Basic Examples
 ~~~~~~~~~~~~~~
@@ -212,12 +262,26 @@ Tracking and contributing to an Subversion managed-project:
        git-svn commit <tree-ish> [<tree-ish_2> ...]
 # Commit all the git commits from my-branch that don't exist in SVN:
        git-svn commit remotes/git-svn..my-branch
-# Something is committed to SVN, pull the latest into your branch:
-       git-svn fetch && git pull . remotes/git-svn
+# Something is committed to SVN, rebase the latest into your branch:
+       git-svn fetch && git rebase remotes/git-svn
 # Append svn:ignore settings to the default git exclude file:
        git-svn show-ignore >> .git/info/exclude
 ------------------------------------------------------------------------
 
+REBASE VS. PULL
+---------------
+
+Originally, git-svn recommended that the remotes/git-svn branch be
+pulled from.  This is because the author favored 'git-svn commit B'
+to commit a single head rather than the 'git-svn commit A..B' notation
+to commit multiple commits.
+
+If you use 'git-svn commit A..B' to commit several diffs and you do not
+have the latest remotes/git-svn merged into my-branch, you should use
+'git rebase' to update your work branch instead of 'git pull'.  'pull'
+can cause non-linear history to be flattened when committing into SVN,
+which can lead to merge commits reversing previous commits in SVN.
+
 DESIGN PHILOSOPHY
 -----------------
 Merge tracking in Subversion is lacking and doing branched development
@@ -226,6 +290,7 @@ any automated merge/branch tracking on the Subversion side and leaves it
 entirely up to the user on the git side.  It's simply not worth it to do
 a useful translation when the original signal is weak.
 
+[[tracking-multiple-repos]]
 TRACKING MULTIPLE REPOSITORIES OR BRANCHES
 ------------------------------------------
 This is for advanced users, most users should ignore this section.
@@ -241,6 +306,7 @@ invocation.  The interface branch will be remotes/$GIT_SVN_ID, instead of
 remotes/git-svn.  Any remotes/$GIT_SVN_ID branch should never be modified
 by the user outside of git-svn commands.
 
+[[fetch-args]]
 ADDITIONAL FETCH ARGUMENTS
 --------------------------
 This is for advanced users, most users should ignore this section.
@@ -251,11 +317,15 @@ optionally be specified in the form of sha1 hex sums at the
 command-line.  Unfetched SVN revisions may also be tied to particular
 git commits with the following syntax:
 
+------------------------------------------------
        svn_revision_number=git_commit_sha1
+------------------------------------------------
 
-This allows you to tie unfetched SVN revision 375 to your current HEAD::
+This allows you to tie unfetched SVN revision 375 to your current HEAD:
 
-       `git-svn fetch 375=$(git-rev-parse HEAD)`
+------------------------------------------------
+       git-svn fetch 375=$(git-rev-parse HEAD)
+------------------------------------------------
 
 Advanced Example: Tracking a Reorganized Repository
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -310,6 +380,10 @@ the possible corner cases (git doesn't do it, either).  Renamed and
 copied files are fully supported if they're similar enough for git to
 detect them.
 
+SEE ALSO
+--------
+gitlink:git-rebase[1]
+
 Author
 ------
 Written by Eric Wong <normalperson@yhbt.net>.
index 3ae6e74..41bb7e1 100644 (file)
@@ -15,7 +15,7 @@ SYNOPSIS
             [--cacheinfo <mode> <object> <file>]\*
             [--chmod=(+|-)x]
             [--assume-unchanged | --no-assume-unchanged]
-            [--really-refresh] [--unresolve] [--again]
+            [--really-refresh] [--unresolve] [--again | -g]
             [--info-only] [--index-info]
             [-z] [--stdin]
             [--verbose]
@@ -80,7 +80,7 @@ OPTIONS
        filesystem that has very slow lstat(2) system call
        (e.g. cifs).
 
---again::
+--again, -g::
        Runs `git-update-index` itself on the paths whose index
        entries are different from those from the `HEAD` commit.
 
diff --git a/Documentation/git-zip-tree.txt b/Documentation/git-zip-tree.txt
new file mode 100644 (file)
index 0000000..2e9d981
--- /dev/null
@@ -0,0 +1,67 @@
+git-zip-tree(1)
+===============
+
+NAME
+----
+git-zip-tree - Creates a ZIP archive of the files in the named tree
+
+
+SYNOPSIS
+--------
+'git-zip-tree' [-0|...|-9] <tree-ish> [ <base> ]
+
+DESCRIPTION
+-----------
+Creates a ZIP archive containing the tree structure for the named tree.
+When <base> is specified it is added as a leading path to the files in the
+generated ZIP archive.
+
+git-zip-tree behaves differently when given a tree ID versus when given
+a commit ID or tag ID.  In the first case the current time is used as
+modification time of each file in the archive.  In the latter case the
+commit time as recorded in the referenced commit object is used instead.
+Additionally the commit ID is stored as an archive comment.
+
+Currently git-zip-tree can handle only files and directories, symbolic
+links are not supported.
+
+OPTIONS
+-------
+
+-0::
+       Store the files instead of deflating them.
+
+-9::
+       Highest and slowest compression level.  You can specify any
+       number from 1 to 9 to adjust compression speed and ratio.
+
+<tree-ish>::
+       The tree or commit to produce ZIP archive for.  If it is
+       the object name of a commit object.
+
+<base>::
+       Leading path to the files in the resulting ZIP archive.
+
+EXAMPLES
+--------
+git zip-tree v1.4.0 git-1.4.0 >git-1.4.0.zip::
+
+       Create a ZIP file for v1.4.0 release.
+
+git zip-tree HEAD:Documentation/ git-docs >docs.zip::
+
+       Put everything in the current head's Documentation/ directory
+       into 'docs.zip', with the prefix 'git-docs/'.
+
+Author
+------
+Written by Rene Scharfe.
+
+Documentation
+--------------
+Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
+
+GIT
+---
+Part of the gitlink:git[7] suite
+
index bcf187a..a9c87e3 100644 (file)
@@ -8,8 +8,9 @@ git - the stupid content tracker
 
 SYNOPSIS
 --------
+[verse]
 'git' [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate]
-       [--bare] [--git-dir=GIT_DIR] [--help] COMMAND [ARGS]
+    [--bare] [--git-dir=GIT_DIR] [--help] COMMAND [ARGS]
 
 DESCRIPTION
 -----------
@@ -633,6 +634,9 @@ git Diffs
 
 other
 ~~~~~
+'GIT_PAGER'::
+       This environment variable overrides `$PAGER`.
+
 'GIT_TRACE'::
        If this variable is set git will print `trace:` messages on
        stderr telling about alias expansion, built-in command
index cb482bf..23be005 100644 (file)
@@ -3,26 +3,52 @@ gitk(1)
 
 NAME
 ----
-gitk - Some git command not yet documented.
-
+gitk - git repository browser
 
 SYNOPSIS
 --------
-'gitk' [ --option ] <args>...
+'gitk' [<option>...] [<revs>] [--] [<path>...]
 
 DESCRIPTION
 -----------
-Does something not yet documented.
+Displays changes in a repository or a selected set of commits. This includes
+visualizing the commit graph, showing information related to each commit, and
+the files in the trees of each revision.
 
+Historically, gitk was the first repository browser. It's written in tcl/tk
+and started off in a separate repository but was later merged into the main
+git repository.
 
 OPTIONS
 -------
---option::
-       Some option not yet documented.
+To control which revisions to shown, the command takes options applicable to
+the gitlink:git-rev-list[1] command. This manual page describes only the most
+frequently used options.
+
+-n <number>, --max-count=<number>::
+
+       Limits the number of commits to show.
+
+--since=<date>::
+
+       Show commits more recent than a specific date.
+
+--until=<date>::
+
+       Show commits older than a specific date.
 
-<args>...::
-       Some argument not yet documented.
+<revs>::
 
+       Limit the revisions to show. This can be either a single revision
+       meaning show from the given revision and back, or it can be a range in
+       the form "'<from>'..'<to>'" to show all revisions between '<from>' and
+       back to '<to>'. Note, more advanced revision selection can be applied.
+
+<path>::
+
+       Limit commits to the ones touching files in the given paths. Note, to
+       avoid ambiguity wrt. revision names use "--" to separate the paths
+       from any preceeding options.
 
 Examples
 --------
@@ -37,13 +63,27 @@ gitk --since="2 weeks ago" \-- gitk::
        The "--" is necessary to avoid confusion with the *branch* named
        'gitk'
 
+See Also
+--------
+'qgit(1)'::
+       A repository browser written in C++ using Qt.
+
+'gitview(1)'::
+       A repository browser written in Python using Gtk. It's based on
+       'bzrk(1)' and distributed in the contrib area of the git repository.
+
+'tig(1)'::
+       A minimal repository browser and git tool output highlighter written
+       in C using Ncurses.
+
 Author
 ------
-Written by Paul Mackerras <paulus@samba.org>
+Written by Paul Mackerras <paulus@samba.org>.
 
 Documentation
 --------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
+Documentation by Junio C Hamano, Jonas Fonseca, and the git-list
+<git@vger.kernel.org>.
 
 GIT
 ---
diff --git a/Documentation/technical/racy-git.txt b/Documentation/technical/racy-git.txt
new file mode 100644 (file)
index 0000000..7597d04
--- /dev/null
@@ -0,0 +1,193 @@
+Use of index and Racy git problem
+=================================
+
+Background
+----------
+
+The index is one of the most important data structure in git.
+It represents a virtual working tree state by recording list of
+paths and their object names and serves as a staging area to
+write out the next tree object to be committed.  The state is
+"virtual" in the sense that it does not necessarily have to, and
+often does not, match the files in the working tree.
+
+There are cases git needs to examine the differences between the
+virtual working tree state in the index and the files in the
+working tree.  The most obvious case is when the user asks `git
+diff` (or its low level implementation, `git diff-files`) or
+`git-ls-files --modified`.  In addition, git internally checks
+if the files in the working tree is different from what are
+recorded in the index to avoid stomping on local changes in them
+during patch application, switching branches, and merging.
+
+In order to speed up this comparison between the files in the
+working tree and the index entries, the index entries record the
+information obtained from the filesystem via `lstat(2)` system
+call when they were last updated.  When checking if they differ,
+git first runs `lstat(2)` on the files and compare the result
+with this information (this is what was originally done by the
+`ce_match_stat()` function, which the current code does in
+`ce_match_stat_basic()` function).  If some of these "cached
+stat information" fields do not match, git can tell that the
+files are modified without even looking at their contents.
+
+Note: not all members in `struct stat` obtained via `lstat(2)`
+are used for this comparison.  For example, `st_atime` obviously
+is not useful.  Currently, git compares the file type (regular
+files vs symbolic links) and executable bits (only for regular
+files) from `st_mode` member, `st_mtime` and `st_ctime`
+timestamps, `st_uid`, `st_gid`, `st_ino`, and `st_size` members.
+With a `USE_STDEV` compile-time option, `st_dev` is also
+compared, but this is not enabled by default because this member
+is not stable on network filesystems.  With `USE_NSEC`
+compile-time option, `st_mtim.tv_nsec` and `st_ctim.tv_nsec`
+members are also compared, but this is not enabled by default
+because the value of this member becomes meaningless once the
+inode is evicted from the inode cache on filesystems that do not
+store it on disk.
+
+
+Racy git
+--------
+
+There is one slight problem with the optimization based on the
+cached stat information.  Consider this sequence:
+
+  $ git update-index 'foo'
+  : modify 'foo' in-place without changing its size
+
+The first `update-index` computes the object name of the
+contents of file `foo` and updates the index entry for `foo`
+along with the `struct stat` information.  If the modification
+that follows it happens very fast so that the file's `st_mtime`
+timestamp does not change, after this sequence, the cached stat
+information the index entry records still exactly match what you
+can obtain from the filesystem, but the file `foo` is modified.
+This way, git can incorrectly think files in the working tree
+are unmodified even though they actually are.  This is called
+the "racy git" problem (discovered by Pasky), and the entries
+that appear clean when they may not be because of this problem
+are called "racily clean".
+
+To avoid this problem, git does two things:
+
+. When the cached stat information says the file has not been
+  modified, and the `st_mtime` is the same as (or newer than)
+  the timestamp of the index file itself (which is the time `git
+  update-index foo` finished running in the above example), it
+  also compares the contents with the object registered in the
+  index entry to make sure they match.
+
+. When the index file is updated that contains racily clean
+  entries, cached `st_size` information is truncated to zero
+  before writing a new version of the index file.
+
+Because the index file itself is written after collecting all
+the stat information from updated paths, `st_mtime` timestamp of
+it is usually the same as or newer than any of the paths the
+index contains.  And no matter how quick the modification that
+follows `git update-index foo` finishes, the resulting
+`st_mtime` timestamp on `foo` cannot get the timestamp earlier
+than the index file.  Therefore, index entries that can be
+racily clean are limited to the ones that have the same
+timestamp as the index file itself.
+
+The callers that want to check if an index entry matches the
+corresponding file in the working tree continue to call
+`ce_match_stat()`, but with this change, `ce_match_stat()` uses
+`ce_modified_check_fs()` to see if racily clean ones are
+actually clean after comparing the cached stat information using
+`ce_match_stat_basic()`.
+
+The problem the latter solves is this sequence:
+
+  $ git update-index 'foo'
+  : modify 'foo' in-place without changing its size
+  : wait for enough time
+  $ git update-index 'bar'
+
+Without the latter, the timestamp of the index file gets a newer
+value, and falsely clean entry `foo` would not be caught by the
+timestamp comparison check done with the former logic anymore.
+The latter makes sure that the cached stat information for `foo`
+would never match with the file in the working tree, so later
+checks by `ce_match_stat_basic()` would report the index entry
+does not match the file and git does not have to fall back on more
+expensive `ce_modified_check_fs()`.
+
+
+Runtime penalty
+---------------
+
+The runtime penalty of falling back to `ce_modified_check_fs()`
+from `ce_match_stat()` can be very expensive when there are many
+racily clean entries.  An obvious way to artificially create
+this situation is to give the same timestamp to all the files in
+the working tree in a large project, run `git update-index` on
+them, and give the same timestamp to the index file:
+
+  $ date >.datestamp
+  $ git ls-files | xargs touch -r .datestamp
+  $ git ls-files | git update-index --stdin
+  $ touch -r .datestamp .git/index
+
+This will make all index entries racily clean.  The linux-2.6
+project, for example, there are over 20,000 files in the working
+tree.  On my Athron 64X2 3800+, after the above:
+
+  $ /usr/bin/time git diff-files
+  1.68user 0.54system 0:02.22elapsed 100%CPU (0avgtext+0avgdata 0maxresident)k
+  0inputs+0outputs (0major+67111minor)pagefaults 0swaps
+  $ git update-index MAINTAINERS
+  $ /usr/bin/time git diff-files
+  0.02user 0.12system 0:00.14elapsed 100%CPU (0avgtext+0avgdata 0maxresident)k
+  0inputs+0outputs (0major+935minor)pagefaults 0swaps
+
+Running `git update-index` in the middle checked the racily
+clean entries, and left the cached `st_mtime` for all the paths
+intact because they were actually clean (so this step took about
+the same amount of time as the first `git diff-files`).  After
+that, they are not racily clean anymore but are truly clean, so
+the second invocation of `git diff-files` fully took advantage
+of the cached stat information.
+
+
+Avoiding runtime penalty
+------------------------
+
+In order to avoid the above runtime penalty, the recent "master"
+branch (post 1.4.2) has a code that makes sure the index file
+gets timestamp newer than the youngest files in the index when
+there are many young files with the same timestamp as the
+resulting index file would otherwise would have by waiting
+before finishing writing the index file out.
+
+I suspect that in practice the situation where many paths in the
+index are all racily clean is quite rare.  The only code paths
+that can record recent timestamp for large number of paths I
+know of are:
+
+. Initial `git add .` of a large project.
+
+. `git checkout` of a large project from an empty index into an
+  unpopulated working tree.
+
+Note: switching branches with `git checkout` keeps the cached
+stat information of existing working tree files that are the
+same between the current branch and the new branch, which are
+all older than the resulting index file, and they will not
+become racily clean.  Only the files that are actually checked
+out can become racily clean.
+
+In a large project where raciness avoidance cost really matters,
+however, the initial computation of all object names in the
+index takes more than one second, and the index file is written
+out after all that happens.  Therefore the timestamp of the
+index file will be more than one seconds later than the the
+youngest file in the working tree.  This means that in these
+cases there actually will not be any racily clean entry in
+the resulting index.
+
+So in summary I think we should not worry about avoiding the
+runtime penalty and get rid of the "wait before finishing
+writing" code out.
diff --git a/INSTALL b/INSTALL
index ba9778c..fa9bf74 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -16,7 +16,7 @@ install" would not work.
 Alternatively you can use autoconf generated ./configure script to
 set up install paths (via config.mak.autogen), so you can write instead
 
-       $ autoconf ;# as yourself if ./configure doesn't exist yet
+       $ make configure ;# as yourself
        $ ./configure --prefix=/usr ;# as yourself
        $ make all doc ;# as yourself
        # make install install-doc ;# as root
index 1c327c1..a608476 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -27,7 +27,7 @@ all:
 # Define NO_C99_FORMAT if your formatted IO functions (printf/scanf et.al.)
 # do not support the 'size specifiers' introduced by C99, namely ll, hh,
 # j, z, t. (representing long long int, char, intmax_t, size_t, ptrdiff_t).
-# some c compilers supported these specifiers prior to C99 as an extension.
+# some C compilers supported these specifiers prior to C99 as an extension.
 #
 # Define NO_STRCASESTR if you don't have strcasestr.
 #
@@ -121,6 +121,17 @@ template_dir = $(prefix)/share/git-core/templates/
 GIT_PYTHON_DIR = $(prefix)/share/git-core/python
 # DESTDIR=
 
+# default configuration for gitweb
+GITWEB_CONFIG = gitweb_config.perl
+GITWEB_HOME_LINK_STR = projects
+GITWEB_SITENAME =
+GITWEB_PROJECTROOT = /pub/git
+GITWEB_BASE_URL =
+GITWEB_LIST =
+GITWEB_HOMETEXT = indextext.html
+GITWEB_CSS = gitweb.css
+GITWEB_LOGO = git-logo.png
+
 export prefix bindir gitexecdir template_dir GIT_PYTHON_DIR
 
 CC = gcc
@@ -173,33 +184,28 @@ SIMPLE_PROGRAMS = \
 
 # ... and all the rest that could be moved out of bindir to gitexecdir
 PROGRAMS = \
-       git-checkout-index$X \
        git-convert-objects$X git-fetch-pack$X git-fsck-objects$X \
        git-hash-object$X git-index-pack$X git-local-fetch$X \
        git-merge-base$X \
-       git-merge-index$X git-mktag$X git-mktree$X git-pack-objects$X git-patch-id$X \
+       git-merge-index$X git-mktag$X git-mktree$X git-patch-id$X \
        git-peek-remote$X git-receive-pack$X \
        git-send-pack$X git-shell$X \
        git-show-index$X git-ssh-fetch$X \
        git-ssh-upload$X git-unpack-file$X \
-       git-unpack-objects$X git-update-server-info$X \
+       git-update-server-info$X \
        git-upload-pack$X git-verify-pack$X \
-       git-symbolic-ref$X \
-       git-name-rev$X git-pack-redundant$X git-var$X \
+       git-pack-redundant$X git-var$X \
        git-describe$X git-merge-tree$X git-blame$X git-imap-send$X \
-       git-merge-recur$X
-
-BUILT_INS = git-log$X git-whatchanged$X git-show$X git-update-ref$X \
-       git-count-objects$X git-diff$X git-push$X git-mailsplit$X \
-       git-grep$X git-add$X git-rm$X git-rev-list$X git-stripspace$X \
-       git-check-ref-format$X git-rev-parse$X git-mailinfo$X \
-       git-init-db$X git-tar-tree$X git-upload-tar$X git-format-patch$X \
-       git-ls-files$X git-ls-tree$X git-get-tar-commit-id$X \
-       git-read-tree$X git-commit-tree$X git-write-tree$X \
-       git-apply$X git-show-branch$X git-diff-files$X git-update-index$X \
-       git-diff-index$X git-diff-stages$X git-diff-tree$X git-cat-file$X \
-       git-fmt-merge-msg$X git-prune$X git-mv$X git-prune-packed$X \
-       git-repo-config$X
+       git-merge-recur$X \
+       $(EXTRA_PROGRAMS)
+
+# Empty...
+EXTRA_PROGRAMS =
+
+BUILT_INS = \
+       git-format-patch$X git-show$X git-whatchanged$X \
+       git-get-tar-commit-id$X \
+       $(patsubst builtin-%.o,git-%$X,$(BUILTIN_OBJS))
 
 # what 'all' will build and 'install' will install, in gitexecdir
 ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)
@@ -228,7 +234,7 @@ LIB_H = \
        blob.h cache.h commit.h csum-file.h delta.h \
        diff.h object.h pack.h pkt-line.h quote.h refs.h \
        run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \
-       tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h
+       tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h
 
 DIFF_OBJS = \
        diff.o diff-lib.o diffcore-break.o diffcore-order.o \
@@ -243,20 +249,52 @@ LIB_OBJS = \
        server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
        tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
        fetch-clone.o revision.o pager.o tree-walk.o xdiff-interface.o \
-       alloc.o merge-file.o path-list.o unpack-trees.o $(DIFF_OBJS)
+       write_or_die.o \
+       alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS)
 
 BUILTIN_OBJS = \
-       builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o \
-       builtin-grep.o builtin-add.o builtin-rev-list.o builtin-check-ref-format.o \
-       builtin-rm.o builtin-init-db.o builtin-rev-parse.o \
-       builtin-tar-tree.o builtin-upload-tar.o builtin-update-index.o \
-       builtin-ls-files.o builtin-ls-tree.o builtin-write-tree.o \
-       builtin-read-tree.o builtin-commit-tree.o builtin-mailinfo.o \
-       builtin-apply.o builtin-show-branch.o builtin-diff-files.o \
-       builtin-diff-index.o builtin-diff-stages.o builtin-diff-tree.o \
-       builtin-cat-file.o builtin-mailsplit.o builtin-stripspace.o \
-       builtin-update-ref.o builtin-fmt-merge-msg.o builtin-prune.o \
-       builtin-mv.o builtin-prune-packed.o builtin-repo-config.o
+       builtin-add.o \
+       builtin-apply.o \
+       builtin-cat-file.o \
+       builtin-checkout-index.o \
+       builtin-check-ref-format.o \
+       builtin-commit-tree.o \
+       builtin-count-objects.o \
+       builtin-diff.o \
+       builtin-diff-files.o \
+       builtin-diff-index.o \
+       builtin-diff-stages.o \
+       builtin-diff-tree.o \
+       builtin-fmt-merge-msg.o \
+       builtin-grep.o \
+       builtin-init-db.o \
+       builtin-log.o \
+       builtin-ls-files.o \
+       builtin-ls-tree.o \
+       builtin-mailinfo.o \
+       builtin-mailsplit.o \
+       builtin-mv.o \
+       builtin-name-rev.o \
+       builtin-pack-objects.o \
+       builtin-prune.o \
+       builtin-prune-packed.o \
+       builtin-push.o \
+       builtin-read-tree.o \
+       builtin-repo-config.o \
+       builtin-rev-list.o \
+       builtin-rev-parse.o \
+       builtin-rm.o \
+       builtin-show-branch.o \
+       builtin-stripspace.o \
+       builtin-symbolic-ref.o \
+       builtin-tar-tree.o \
+       builtin-unpack-objects.o \
+       builtin-update-index.o \
+       builtin-update-ref.o \
+       builtin-upload-tar.o \
+       builtin-verify-pack.o \
+       builtin-write-tree.o \
+       builtin-zip-tree.o
 
 GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
 LIBS = $(GITLIBS) -lz
@@ -297,15 +335,16 @@ ifeq ($(uname_S),SunOS)
        NEEDS_NSL = YesPlease
        SHELL_PATH = /bin/bash
        NO_STRCASESTR = YesPlease
-       NO_STRLCPY = YesPlease
        ifeq ($(uname_R),5.8)
                NEEDS_LIBICONV = YesPlease
                NO_UNSETENV = YesPlease
                NO_SETENV = YesPlease
+               NO_C99_FORMAT = YesPlease
        endif
        ifeq ($(uname_R),5.9)
                NO_UNSETENV = YesPlease
                NO_SETENV = YesPlease
+               NO_C99_FORMAT = YesPlease
        endif
        INSTALL = ginstall
        TAR = gtar
@@ -524,7 +563,7 @@ LIB_OBJS += $(COMPAT_OBJS)
 export prefix TAR INSTALL DESTDIR SHELL_PATH template_dir
 ### Build rules
 
-all: $(ALL_PROGRAMS) $(BUILT_INS) git$X gitk
+all: $(ALL_PROGRAMS) $(BUILT_INS) git$X gitk gitweb/gitweb.cgi
 
 all:
        $(MAKE) -C templates
@@ -537,7 +576,7 @@ git$X: git.c common-cmds.h $(BUILTIN_OBJS) $(GITLIBS) GIT-CFLAGS
                $(ALL_CFLAGS) -o $@ $(filter %.c,$^) \
                $(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)
 
-builtin-help.o: common-cmds.h
+help.o: common-cmds.h
 
 $(BUILT_INS): git$X
        rm -f $@ && ln git$X $@
@@ -582,6 +621,24 @@ git-status: git-commit
        cp $< $@+
        mv $@+ $@
 
+gitweb/gitweb.cgi: gitweb/gitweb.perl
+       rm -f $@ $@+
+       sed -e '1s|#!.*perl|#!$(PERL_PATH_SQ)|' \
+           -e 's|++GIT_VERSION++|$(GIT_VERSION)|g' \
+           -e 's|++GIT_BINDIR++|$(bindir)|g' \
+           -e 's|++GITWEB_CONFIG++|$(GITWEB_CONFIG)|g' \
+           -e 's|++GITWEB_HOME_LINK_STR++|$(GITWEB_HOME_LINK_STR)|g' \
+           -e 's|++GITWEB_SITENAME++|$(GITWEB_SITENAME)|g' \
+           -e 's|++GITWEB_PROJECTROOT++|$(GITWEB_PROJECTROOT)|g' \
+           -e 's|++GITWEB_BASE_URL++|$(GITWEB_BASE_URL)|g' \
+           -e 's|++GITWEB_LIST++|$(GITWEB_LIST)|g' \
+           -e 's|++GITWEB_HOMETEXT++|$(GITWEB_HOMETEXT)|g' \
+           -e 's|++GITWEB_CSS++|$(GITWEB_CSS)|g' \
+           -e 's|++GITWEB_LOGO++|$(GITWEB_LOGO)|g' \
+           $< >$@+
+       chmod +x $@+
+       mv $@+ $@
+
 git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css
        rm -f $@ $@+
        sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
@@ -592,10 +649,17 @@ git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css
            -e '/@@GITWEB_CGI@@/d' \
            -e '/@@GITWEB_CSS@@/r gitweb/gitweb.css' \
            -e '/@@GITWEB_CSS@@/d' \
-           $@.sh | sed "s|/usr/bin/git|$(bindir)/git|" > $@+
+           $@.sh > $@+
        chmod +x $@+
        mv $@+ $@
 
+configure: configure.ac
+       rm -f $@ $<+
+       sed -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
+           $< > $<+
+       autoconf -o $@ $<+
+       rm -f $<+
+
 # These can record GIT_VERSION
 git$X git.spec \
        $(patsubst %.sh,%,$(SCRIPT_SH)) \
@@ -792,10 +856,11 @@ clean:
        rm -f $(ALL_PROGRAMS) $(BUILT_INS) git$X
        rm -f *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags
        rm -rf autom4te.cache
-       rm -f config.log config.mak.autogen configure config.status config.cache
+       rm -f configure config.log config.mak.autogen config.mak.append config.status config.cache
        rm -rf $(GIT_TARNAME) .doc-tmp-dir
        rm -f $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz
        rm -f $(htmldocs).tar.gz $(manpages).tar.gz
+       rm -f gitweb/gitweb.cgi
        $(MAKE) -C Documentation/ clean
        $(MAKE) -C templates clean
        $(MAKE) -C t/ clean
diff --git a/TEST b/TEST
deleted file mode 100755 (executable)
index 7286e2a..0000000
--- a/TEST
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/bin/sh -x
-
-cd t || exit
-GIT_USE_RECUR_FOR_RECURSIVE=LetsTryIt
-export GIT_USE_RECUR_FOR_RECURSIVE
-
-./t3400-rebase.sh              "$@" &&
-./t6020-merge-df.sh            "$@" &&
-./t3401-rebase-partial.sh      "$@" &&
-./t6021-merge-criss-cross.sh   "$@" &&
-./t3402-rebase-merge.sh        "$@" &&
-./t6022-merge-rename.sh        "$@" &&
-./t6010-merge-base.sh          "$@" &&
-:
diff --git a/blame.c b/blame.c
index 7099b53..8968046 100644 (file)
--- a/blame.c
+++ b/blame.c
@@ -56,9 +56,9 @@ struct patch {
 static void get_blob(struct commit *commit);
 
 /* Only used for statistics */
-static int num_get_patch = 0;
-static int num_commits = 0;
-static int patch_time = 0;
+static int num_get_patch;
+static int num_commits;
+static int patch_time;
 
 struct blame_diff_state {
        struct xdiff_emit_state xm;
@@ -165,7 +165,7 @@ static int get_blob_sha1(struct tree *t, const char *pathname,
        blame_file = pathname;
        pathspec[0] = pathname;
        pathspec[1] = NULL;
-       memset(blob_sha1, 0, sizeof(blob_sha1));
+       hashclr(blob_sha1);
        read_tree_recursive(t, "", 0, 0, pathspec, get_blob_sha1_internal);
 
        for (i = 0; i < 20; i++) {
@@ -176,7 +176,7 @@ static int get_blob_sha1(struct tree *t, const char *pathname,
        if (i == 20)
                return -1;
 
-       memcpy(sha1, blob_sha1, 20);
+       hashcpy(sha1, blob_sha1);
        return 0;
 }
 
@@ -191,7 +191,7 @@ static int get_blob_sha1_internal(const unsigned char *sha1, const char *base,
            strcmp(blame_file + baselen, pathname))
                return -1;
 
-       memcpy(blob_sha1, sha1, 20);
+       hashcpy(blob_sha1, sha1);
        return -1;
 }
 
@@ -351,10 +351,7 @@ static int fill_util_info(struct commit *commit)
        assert(util);
        assert(util->pathname);
 
-       if (get_blob_sha1(commit->tree, util->pathname, util->sha1))
-               return 1;
-       else
-               return 0;
+       return !!get_blob_sha1(commit->tree, util->pathname, util->sha1);
 }
 
 static void alloc_line_map(struct commit *commit)
index 9cf477c..b47ccac 100644 (file)
@@ -28,21 +28,24 @@ static int prefix_length = -1;
 static int newfd = -1;
 
 static int p_value = 1;
-static int allow_binary_replacement = 0;
-static int check_index = 0;
-static int write_index = 0;
-static int cached = 0;
-static int diffstat = 0;
-static int numstat = 0;
-static int summary = 0;
-static int check = 0;
+static int allow_binary_replacement;
+static int check_index;
+static int write_index;
+static int cached;
+static int diffstat;
+static int numstat;
+static int summary;
+static int check;
 static int apply = 1;
-static int no_add = 0;
-static int show_index_info = 0;
+static int apply_in_reverse;
+static int apply_with_reject;
+static int apply_verbosely;
+static int no_add;
+static int show_index_info;
 static int line_termination = '\n';
 static unsigned long p_context = -1;
 static const char apply_usage[] =
-"git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--cached] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [-z] [-pNUM] [-CNUM] [--whitespace=<nowarn|warn|error|error-all|strip>] <patch>...";
+"git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--cached] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [--reverse] [--reject] [--verbose] [-z] [-pNUM] [-CNUM] [--whitespace=<nowarn|warn|error|error-all|strip>] <patch>...";
 
 static enum whitespace_eol {
        nowarn_whitespace,
@@ -50,10 +53,10 @@ static enum whitespace_eol {
        error_on_whitespace,
        strip_whitespace,
 } new_whitespace = warn_on_whitespace;
-static int whitespace_error = 0;
+static int whitespace_error;
 static int squelch_whitespace_errors = 5;
-static int applied_after_stripping = 0;
-static const char *patch_input_file = NULL;
+static int applied_after_stripping;
+static const char *patch_input_file;
 
 static void parse_whitespace_option(const char *option)
 {
@@ -108,21 +111,37 @@ static int max_change, max_len;
  */
 static int linenr = 1;
 
+/*
+ * This represents one "hunk" from a patch, starting with
+ * "@@ -oldpos,oldlines +newpos,newlines @@" marker.  The
+ * patch text is pointed at by patch, and its byte length
+ * is stored in size.  leading and trailing are the number
+ * of context lines.
+ */
 struct fragment {
        unsigned long leading, trailing;
        unsigned long oldpos, oldlines;
        unsigned long newpos, newlines;
        const char *patch;
        int size;
+       int rejected;
        struct fragment *next;
 };
 
+/*
+ * When dealing with a binary patch, we reuse "leading" field
+ * to store the type of the binary hunk, either deflated "delta"
+ * or deflated "literal".
+ */
+#define binary_patch_method leading
+#define BINARY_DELTA_DEFLATED  1
+#define BINARY_LITERAL_DEFLATED 2
+
 struct patch {
        char *new_name, *old_name, *def_name;
        unsigned int old_mode, new_mode;
-       int is_rename, is_copy, is_new, is_delete, is_binary, is_reverse;
-#define BINARY_DELTA_DEFLATED 1
-#define BINARY_LITERAL_DEFLATED 2
+       int is_rename, is_copy, is_new, is_delete, is_binary;
+       int rejected;
        unsigned long deflate_origlen;
        int lines_added, lines_deleted;
        int score;
@@ -135,6 +154,24 @@ struct patch {
        struct patch *next;
 };
 
+static void say_patch_name(FILE *output, const char *pre, struct patch *patch, const char *post)
+{
+       fputs(pre, output);
+       if (patch->old_name && patch->new_name &&
+           strcmp(patch->old_name, patch->new_name)) {
+               write_name_quoted(NULL, 0, patch->old_name, 1, output);
+               fputs(" => ", output);
+               write_name_quoted(NULL, 0, patch->new_name, 1, output);
+       }
+       else {
+               const char *n = patch->new_name;
+               if (!n)
+                       n = patch->old_name;
+               write_name_quoted(NULL, 0, n, 1, output);
+       }
+       fputs(post, output);
+}
+
 #define CHUNKSIZE (8192)
 #define SLOP (16)
 
@@ -591,9 +628,7 @@ static char *git_header_name(char *line, int llen)
         * form.
         */
        for (len = 0 ; ; len++) {
-               char c = name[len];
-
-               switch (c) {
+               switch (name[len]) {
                default:
                        continue;
                case '\n':
@@ -978,51 +1013,82 @@ static inline int metadata_changes(struct patch *patch)
                 patch->old_mode != patch->new_mode);
 }
 
-static int parse_binary(char *buffer, unsigned long size, struct patch *patch)
+static char *inflate_it(const void *data, unsigned long size,
+                       unsigned long inflated_size)
 {
-       /* We have read "GIT binary patch\n"; what follows is a line
-        * that says the patch method (currently, either "deflated
-        * literal" or "deflated delta") and the length of data before
-        * deflating; a sequence of 'length-byte' followed by base-85
-        * encoded data follows.
+       z_stream stream;
+       void *out;
+       int st;
+
+       memset(&stream, 0, sizeof(stream));
+
+       stream.next_in = (unsigned char *)data;
+       stream.avail_in = size;
+       stream.next_out = out = xmalloc(inflated_size);
+       stream.avail_out = inflated_size;
+       inflateInit(&stream);
+       st = inflate(&stream, Z_FINISH);
+       if ((st != Z_STREAM_END) || stream.total_out != inflated_size) {
+               free(out);
+               return NULL;
+       }
+       return out;
+}
+
+static struct fragment *parse_binary_hunk(char **buf_p,
+                                         unsigned long *sz_p,
+                                         int *status_p,
+                                         int *used_p)
+{
+       /* Expect a line that begins with binary patch method ("literal"
+        * or "delta"), followed by the length of data before deflating.
+        * a sequence of 'length-byte' followed by base-85 encoded data
+        * should follow, terminated by a newline.
         *
         * Each 5-byte sequence of base-85 encodes up to 4 bytes,
         * and we would limit the patch line to 66 characters,
         * so one line can fit up to 13 groups that would decode
         * to 52 bytes max.  The length byte 'A'-'Z' corresponds
         * to 1-26 bytes, and 'a'-'z' corresponds to 27-52 bytes.
-        * The end of binary is signaled with an empty line.
         */
        int llen, used;
-       struct fragment *fragment;
+       unsigned long size = *sz_p;
+       char *buffer = *buf_p;
+       int patch_method;
+       unsigned long origlen;
        char *data = NULL;
+       int hunk_size = 0;
+       struct fragment *frag;
 
-       patch->fragments = fragment = xcalloc(1, sizeof(*fragment));
-
-       /* Grab the type of patch */
        llen = linelen(buffer, size);
        used = llen;
-       linenr++;
+
+       *status_p = 0;
 
        if (!strncmp(buffer, "delta ", 6)) {
-               patch->is_binary = BINARY_DELTA_DEFLATED;
-               patch->deflate_origlen = strtoul(buffer + 6, NULL, 10);
+               patch_method = BINARY_DELTA_DEFLATED;
+               origlen = strtoul(buffer + 6, NULL, 10);
        }
        else if (!strncmp(buffer, "literal ", 8)) {
-               patch->is_binary = BINARY_LITERAL_DEFLATED;
-               patch->deflate_origlen = strtoul(buffer + 8, NULL, 10);
+               patch_method = BINARY_LITERAL_DEFLATED;
+               origlen = strtoul(buffer + 8, NULL, 10);
        }
        else
-               return error("unrecognized binary patch at line %d: %.*s",
-                            linenr-1, llen-1, buffer);
+               return NULL;
+
+       linenr++;
        buffer += llen;
        while (1) {
                int byte_length, max_byte_length, newsize;
                llen = linelen(buffer, size);
                used += llen;
                linenr++;
-               if (llen == 1)
+               if (llen == 1) {
+                       /* consume the blank line */
+                       buffer++;
+                       size--;
                        break;
+               }
                /* Minimum line is "A00000\n" which is 7-byte long,
                 * and the line length must be multiple of 5 plus 2.
                 */
@@ -1043,21 +1109,79 @@ static int parse_binary(char *buffer, unsigned long size, struct patch *patch)
                if (max_byte_length < byte_length ||
                    byte_length <= max_byte_length - 4)
                        goto corrupt;
-               newsize = fragment->size + byte_length;
+               newsize = hunk_size + byte_length;
                data = xrealloc(data, newsize);
-               if (decode_85(data + fragment->size,
-                             buffer + 1,
-                             byte_length))
+               if (decode_85(data + hunk_size, buffer + 1, byte_length))
                        goto corrupt;
-               fragment->size = newsize;
+               hunk_size = newsize;
                buffer += llen;
                size -= llen;
        }
-       fragment->patch = data;
-       return used;
+
+       frag = xcalloc(1, sizeof(*frag));
+       frag->patch = inflate_it(data, hunk_size, origlen);
+       if (!frag->patch)
+               goto corrupt;
+       free(data);
+       frag->size = origlen;
+       *buf_p = buffer;
+       *sz_p = size;
+       *used_p = used;
+       frag->binary_patch_method = patch_method;
+       return frag;
+
  corrupt:
-       return error("corrupt binary patch at line %d: %.*s",
-                    linenr-1, llen-1, buffer);
+       if (data)
+               free(data);
+       *status_p = -1;
+       error("corrupt binary patch at line %d: %.*s",
+             linenr-1, llen-1, buffer);
+       return NULL;
+}
+
+static int parse_binary(char *buffer, unsigned long size, struct patch *patch)
+{
+       /* We have read "GIT binary patch\n"; what follows is a line
+        * that says the patch method (currently, either "literal" or
+        * "delta") and the length of data before deflating; a
+        * sequence of 'length-byte' followed by base-85 encoded data
+        * follows.
+        *
+        * When a binary patch is reversible, there is another binary
+        * hunk in the same format, starting with patch method (either
+        * "literal" or "delta") with the length of data, and a sequence
+        * of length-byte + base-85 encoded data, terminated with another
+        * empty line.  This data, when applied to the postimage, produces
+        * the preimage.
+        */
+       struct fragment *forward;
+       struct fragment *reverse;
+       int status;
+       int used, used_1;
+
+       forward = parse_binary_hunk(&buffer, &size, &status, &used);
+       if (!forward && !status)
+               /* there has to be one hunk (forward hunk) */
+               return error("unrecognized binary patch at line %d", linenr-1);
+       if (status)
+               /* otherwise we already gave an error message */
+               return status;
+
+       reverse = parse_binary_hunk(&buffer, &size, &status, &used_1);
+       if (reverse)
+               used += used_1;
+       else if (status) {
+               /* not having reverse hunk is not an error, but having
+                * a corrupt reverse hunk is.
+                */
+               free((void*) forward->patch);
+               free(forward);
+               return status;
+       }
+       forward->next = reverse;
+       patch->fragments = forward;
+       patch->is_binary = 1;
+       return used;
 }
 
 static int parse_chunk(char *buffer, unsigned long size, struct patch *patch)
@@ -1143,7 +1267,6 @@ static void reverse_patches(struct patch *p)
                        swap(frag->newpos, frag->oldpos);
                        swap(frag->newlines, frag->oldlines);
                }
-               p->is_reverse = !p->is_reverse;
        }
 }
 
@@ -1363,8 +1486,7 @@ static int apply_line(char *output, const char *patch, int plen)
        return plen;
 }
 
-static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag,
-       int reverse, int inaccurate_eof)
+static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, int inaccurate_eof)
 {
        int match_beginning, match_end;
        char *buf = desc->buffer;
@@ -1396,7 +1518,7 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag,
                if (len < size && patch[len] == '\\')
                        plen--;
                first = *patch;
-               if (reverse) {
+               if (apply_in_reverse) {
                        if (first == '-')
                                first = '+';
                        else if (first == '+')
@@ -1446,7 +1568,8 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag,
        lines = 0;
        pos = frag->newpos;
        for (;;) {
-               offset = find_offset(buf, desc->size, oldlines, oldsize, pos, &lines);
+               offset = find_offset(buf, desc->size,
+                                    oldlines, oldsize, pos, &lines);
                if (match_end && offset + oldsize != desc->size)
                        offset = -1;
                if (match_beginning && offset)
@@ -1459,8 +1582,10 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag,
                        /* Warn if it was necessary to reduce the number
                         * of context lines.
                         */
-                       if ((leading != frag->leading) || (trailing != frag->trailing))
-                               fprintf(stderr, "Context reduced to (%ld/%ld) to apply fragment at %d\n",
+                       if ((leading != frag->leading) ||
+                           (trailing != frag->trailing))
+                               fprintf(stderr, "Context reduced to (%ld/%ld)"
+                                       " to apply fragment at %d\n",
                                        leading, trailing, pos + lines);
 
                        if (size > alloc) {
@@ -1470,7 +1595,9 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag,
                                desc->buffer = buf;
                        }
                        desc->size = size;
-                       memmove(buf + offset + newsize, buf + offset + oldsize, size - offset - newsize);
+                       memmove(buf + offset + newsize,
+                               buf + offset + oldsize,
+                               size - offset - newsize);
                        memcpy(buf + offset, newlines, newsize);
                        offset = 0;
 
@@ -1506,28 +1633,6 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag,
        return offset;
 }
 
-static char *inflate_it(const void *data, unsigned long size,
-                       unsigned long inflated_size)
-{
-       z_stream stream;
-       void *out;
-       int st;
-
-       memset(&stream, 0, sizeof(stream));
-
-       stream.next_in = (unsigned char *)data;
-       stream.avail_in = size;
-       stream.next_out = out = xmalloc(inflated_size);
-       stream.avail_out = inflated_size;
-       inflateInit(&stream);
-       st = inflate(&stream, Z_FINISH);
-       if ((st != Z_STREAM_END) || stream.total_out != inflated_size) {
-               free(out);
-               return NULL;
-       }
-       return out;
-}
-
 static int apply_binary_fragment(struct buffer_desc *desc, struct patch *patch)
 {
        unsigned long dst_size;
@@ -1535,30 +1640,29 @@ static int apply_binary_fragment(struct buffer_desc *desc, struct patch *patch)
        void *data;
        void *result;
 
-       /* Binary patch is irreversible */
-       if (patch->is_reverse)
-               return error("cannot reverse-apply a binary patch to '%s'",
-                            patch->new_name
-                            ? patch->new_name : patch->old_name);
-
-       data = inflate_it(fragment->patch, fragment->size,
-                         patch->deflate_origlen);
-       if (!data)
-               return error("corrupt patch data");
-       switch (patch->is_binary) {
+       /* Binary patch is irreversible without the optional second hunk */
+       if (apply_in_reverse) {
+               if (!fragment->next)
+                       return error("cannot reverse-apply a binary patch "
+                                    "without the reverse hunk to '%s'",
+                                    patch->new_name
+                                    ? patch->new_name : patch->old_name);
+               fragment = fragment->next;
+       }
+       data = (void*) fragment->patch;
+       switch (fragment->binary_patch_method) {
        case BINARY_DELTA_DEFLATED:
                result = patch_delta(desc->buffer, desc->size,
                                     data,
-                                    patch->deflate_origlen,
+                                    fragment->size,
                                     &dst_size);
                free(desc->buffer);
                desc->buffer = result;
-               free(data);
                break;
        case BINARY_LITERAL_DEFLATED:
                free(desc->buffer);
                desc->buffer = data;
-               dst_size = patch->deflate_origlen;
+               dst_size = fragment->size;
                break;
        }
        if (!desc->buffer)
@@ -1609,7 +1713,7 @@ static int apply_binary(struct buffer_desc *desc, struct patch *patch)
        }
 
        get_sha1_hex(patch->new_sha1_prefix, sha1);
-       if (!memcmp(sha1, null_sha1, 20)) {
+       if (is_null_sha1(sha1)) {
                free(desc->buffer);
                desc->alloc = desc->size = 0;
                desc->buffer = NULL;
@@ -1642,7 +1746,7 @@ static int apply_binary(struct buffer_desc *desc, struct patch *patch)
                write_sha1_file_prepare(desc->buffer, desc->size, blob_type,
                                        sha1, hdr, &hdrlen);
                if (strcmp(sha1_to_hex(sha1), patch->new_sha1_prefix))
-                       return error("binary patch to '%s' creates incorrect result", name);
+                       return error("binary patch to '%s' creates incorrect result (expecting %s, got %s)", name, patch->new_sha1_prefix, sha1_to_hex(sha1));
        }
 
        return 0;
@@ -1657,10 +1761,12 @@ static int apply_fragments(struct buffer_desc *desc, struct patch *patch)
                return apply_binary(desc, patch);
 
        while (frag) {
-               if (apply_one_fragment(desc, frag, patch->is_reverse,
-                                       patch->inaccurate_eof) < 0)
-                       return error("patch failed: %s:%ld",
-                                    name, frag->oldpos);
+               if (apply_one_fragment(desc, frag, patch->inaccurate_eof)) {
+                       error("patch failed: %s:%ld", name, frag->oldpos);
+                       if (!apply_with_reject)
+                               return -1;
+                       frag->rejected = 1;
+               }
                frag = frag->next;
        }
        return 0;
@@ -1696,8 +1802,9 @@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *
        desc.size = size;
        desc.alloc = alloc;
        desc.buffer = buf;
+
        if (apply_fragments(&desc, patch) < 0)
-               return -1;
+               return -1; /* note with --reject this succeeds. */
 
        /* NUL terminate the result */
        if (desc.alloc <= desc.size)
@@ -1722,6 +1829,7 @@ static int check_patch(struct patch *patch, struct patch *prev_patch)
        struct cache_entry *ce = NULL;
        int ok_if_exists;
 
+       patch->rejected = 1; /* we will drop this after we succeed */
        if (old_name) {
                int changed = 0;
                int stat_ret = 0;
@@ -1827,24 +1935,23 @@ static int check_patch(struct patch *patch, struct patch *prev_patch)
 
        if (apply_data(patch, &st, ce) < 0)
                return error("%s: patch does not apply", name);
+       patch->rejected = 0;
        return 0;
 }
 
 static int check_patch_list(struct patch *patch)
 {
        struct patch *prev_patch = NULL;
-       int error = 0;
+       int err = 0;
 
        for (prev_patch = NULL; patch ; patch = patch->next) {
-               error |= check_patch(patch, prev_patch);
+               if (apply_verbosely)
+                       say_patch_name(stderr,
+                                      "Checking patch ", patch, "...\n");
+               err |= check_patch(patch, prev_patch);
                prev_patch = patch;
        }
-       return error;
-}
-
-static inline int is_null_sha1(const unsigned char *sha1)
-{
-       return !memcmp(sha1, null_sha1, 20);
+       return err;
 }
 
 static void show_index_list(struct patch *list)
@@ -2150,23 +2257,99 @@ static void write_out_one_result(struct patch *patch, int phase)
        if (phase == 0)
                remove_file(patch);
        if (phase == 1)
-       create_file(patch);
+               create_file(patch);
+}
+
+static int write_out_one_reject(struct patch *patch)
+{
+       FILE *rej;
+       char namebuf[PATH_MAX];
+       struct fragment *frag;
+       int cnt = 0;
+
+       for (cnt = 0, frag = patch->fragments; frag; frag = frag->next) {
+               if (!frag->rejected)
+                       continue;
+               cnt++;
+       }
+
+       if (!cnt) {
+               if (apply_verbosely)
+                       say_patch_name(stderr,
+                                      "Applied patch ", patch, " cleanly.\n");
+               return 0;
+       }
+
+       /* This should not happen, because a removal patch that leaves
+        * contents are marked "rejected" at the patch level.
+        */
+       if (!patch->new_name)
+               die("internal error");
+
+       /* Say this even without --verbose */
+       say_patch_name(stderr, "Applying patch ", patch, " with");
+       fprintf(stderr, " %d rejects...\n", cnt);
+
+       cnt = strlen(patch->new_name);
+       if (ARRAY_SIZE(namebuf) <= cnt + 5) {
+               cnt = ARRAY_SIZE(namebuf) - 5;
+               fprintf(stderr,
+                       "warning: truncating .rej filename to %.*s.rej",
+                       cnt - 1, patch->new_name);
+       }
+       memcpy(namebuf, patch->new_name, cnt);
+       memcpy(namebuf + cnt, ".rej", 5);
+
+       rej = fopen(namebuf, "w");
+       if (!rej)
+               return error("cannot open %s: %s", namebuf, strerror(errno));
+
+       /* Normal git tools never deal with .rej, so do not pretend
+        * this is a git patch by saying --git nor give extended
+        * headers.  While at it, maybe please "kompare" that wants
+        * the trailing TAB and some garbage at the end of line ;-).
+        */
+       fprintf(rej, "diff a/%s b/%s\t(rejected hunks)\n",
+               patch->new_name, patch->new_name);
+       for (cnt = 1, frag = patch->fragments;
+            frag;
+            cnt++, frag = frag->next) {
+               if (!frag->rejected) {
+                       fprintf(stderr, "Hunk #%d applied cleanly.\n", cnt);
+                       continue;
+               }
+               fprintf(stderr, "Rejected hunk #%d.\n", cnt);
+               fprintf(rej, "%.*s", frag->size, frag->patch);
+               if (frag->patch[frag->size-1] != '\n')
+                       fputc('\n', rej);
+       }
+       fclose(rej);
+       return -1;
 }
 
-static void write_out_results(struct patch *list, int skipped_patch)
+static int write_out_results(struct patch *list, int skipped_patch)
 {
        int phase;
+       int errs = 0;
+       struct patch *l;
 
        if (!list && !skipped_patch)
-               die("No changes");
+               return error("No changes");
 
        for (phase = 0; phase < 2; phase++) {
-               struct patch *l = list;
+               l = list;
                while (l) {
-                       write_out_one_result(l, phase);
+                       if (l->rejected)
+                               errs = 1;
+                       else {
+                               write_out_one_result(l, phase);
+                               if (phase == 1 && write_out_one_reject(l))
+                                       errs = 1;
+                       }
                        l = l->next;
                }
        }
+       return errs;
 }
 
 static struct lock_file lock_file;
@@ -2194,8 +2377,7 @@ static int use_patch(struct patch *p)
        return 1;
 }
 
-static int apply_patch(int fd, const char *filename,
-               int reverse, int inaccurate_eof)
+static int apply_patch(int fd, const char *filename, int inaccurate_eof)
 {
        unsigned long offset, size;
        char *buffer = read_patch_file(fd, &size);
@@ -2215,7 +2397,7 @@ static int apply_patch(int fd, const char *filename,
                nr = parse_chunk(buffer + offset, size, patch);
                if (nr < 0)
                        break;
-               if (reverse)
+               if (apply_in_reverse)
                        reverse_patches(patch);
                if (use_patch(patch)) {
                        patch_stats(patch);
@@ -2242,11 +2424,13 @@ static int apply_patch(int fd, const char *filename,
                        die("unable to read index file");
        }
 
-       if ((check || apply) && check_patch_list(list) < 0)
+       if ((check || apply) &&
+           check_patch_list(list) < 0 &&
+           !apply_with_reject)
                exit(1);
 
-       if (apply)
-               write_out_results(list, skipped_patch);
+       if (apply && write_out_results(list, skipped_patch))
+               exit(1);
 
        if (show_index_info)
                show_index_list(list);
@@ -2278,8 +2462,8 @@ int cmd_apply(int argc, const char **argv, const char *prefix)
 {
        int i;
        int read_stdin = 1;
-       int reverse = 0;
        int inaccurate_eof = 0;
+       int errs = 0;
 
        const char *whitespace_option = NULL;
 
@@ -2289,7 +2473,7 @@ int cmd_apply(int argc, const char **argv, const char *prefix)
                int fd;
 
                if (!strcmp(arg, "-")) {
-                       apply_patch(0, "<stdin>", reverse, inaccurate_eof);
+                       errs |= apply_patch(0, "<stdin>", inaccurate_eof);
                        read_stdin = 0;
                        continue;
                }
@@ -2367,7 +2551,15 @@ int cmd_apply(int argc, const char **argv, const char *prefix)
                        continue;
                }
                if (!strcmp(arg, "-R") || !strcmp(arg, "--reverse")) {
-                       reverse = 1;
+                       apply_in_reverse = 1;
+                       continue;
+               }
+               if (!strcmp(arg, "--reject")) {
+                       apply = apply_with_reject = apply_verbosely = 1;
+                       continue;
+               }
+               if (!strcmp(arg, "--verbose")) {
+                       apply_verbosely = 1;
                        continue;
                }
                if (!strcmp(arg, "--inaccurate-eof")) {
@@ -2390,18 +2582,19 @@ int cmd_apply(int argc, const char **argv, const char *prefix)
                        usage(apply_usage);
                read_stdin = 0;
                set_default_whitespace_mode(whitespace_option);
-               apply_patch(fd, arg, reverse, inaccurate_eof);
+               errs |= apply_patch(fd, arg, inaccurate_eof);
                close(fd);
        }
        set_default_whitespace_mode(whitespace_option);
        if (read_stdin)
-               apply_patch(0, "<stdin>", reverse, inaccurate_eof);
+               errs |= apply_patch(0, "<stdin>", inaccurate_eof);
        if (whitespace_error) {
                if (squelch_whitespace_errors &&
                    squelch_whitespace_errors < whitespace_error) {
                        int squelched =
                                whitespace_error - squelch_whitespace_errors;
-                       fprintf(stderr, "warning: squelched %d whitespace error%s\n",
+                       fprintf(stderr, "warning: squelched %d "
+                               "whitespace error%s\n",
                                squelched,
                                squelched == 1 ? "" : "s");
                }
@@ -2429,5 +2622,5 @@ int cmd_apply(int argc, const char **argv, const char *prefix)
                        die("Unable to write new index file");
        }
 
-       return 0;
+       return !!errs;
 }
index 814fb07..6c16bfa 100644 (file)
@@ -9,24 +9,7 @@
 #include "tree.h"
 #include "builtin.h"
 
-static void flush_buffer(const char *buf, unsigned long size)
-{
-       while (size > 0) {
-               long ret = xwrite(1, buf, size);
-               if (ret < 0) {
-                       /* Ignore epipe */
-                       if (errno == EPIPE)
-                               break;
-                       die("git-cat-file: %s", strerror(errno));
-               } else if (!ret) {
-                       die("git-cat-file: disk full?");
-               }
-               size -= ret;
-               buf += ret;
-       }
-}
-
-static int pprint_tag(const unsigned char *sha1, const char *buf, unsigned long size)
+static void pprint_tag(const unsigned char *sha1, const char *buf, unsigned long size)
 {
        /* the parser in tag.c is useless here. */
        const char *endp = buf + size;
@@ -42,7 +25,7 @@ static int pprint_tag(const unsigned char *sha1, const char *buf, unsigned long
                        /* Found the tagger line.  Copy out the contents
                         * of the buffer so far.
                         */
-                       flush_buffer(buf, cp - buf);
+                       write_or_die(1, buf, cp - buf);
 
                        /*
                         * Do something intelligent, like pretty-printing
@@ -61,18 +44,18 @@ static int pprint_tag(const unsigned char *sha1, const char *buf, unsigned long
                                                sp++;
                                        if (sp == cp) {
                                                /* give up */
-                                               flush_buffer(tagger,
+                                               write_or_die(1, tagger,
                                                             cp - tagger);
                                                break;
                                        }
                                        while (sp < cp &&
                                               !('0' <= *sp && *sp <= '9'))
                                                sp++;
-                                       flush_buffer(tagger, sp - tagger);
+                                       write_or_die(1, tagger, sp - tagger);
                                        date = strtoul(sp, &ep, 10);
                                        tz = strtol(ep, NULL, 10);
-                                       sp = show_date(date, tz);
-                                       flush_buffer(sp, strlen(sp));
+                                       sp = show_date(date, tz, 0);
+                                       write_or_die(1, sp, strlen(sp));
                                        xwrite(1, "\n", 1);
                                        break;
                                }
@@ -90,8 +73,7 @@ static int pprint_tag(const unsigned char *sha1, const char *buf, unsigned long
         * remainder as is.
         */
        if (cp < endp)
-               flush_buffer(cp, endp - cp);
-       return 0;
+               write_or_die(1, cp, endp - cp);
 }
 
 int cmd_cat_file(int argc, const char **argv, const char *prefix)
@@ -145,8 +127,10 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
                buf = read_sha1_file(sha1, type, &size);
                if (!buf)
                        die("Cannot read object %s", argv[2]);
-               if (!strcmp(type, tag_type))
-                       return pprint_tag(sha1, buf, size);
+               if (!strcmp(type, tag_type)) {
+                       pprint_tag(sha1, buf, size);
+                       return 0;
+               }
 
                /* otherwise just spit out the data */
                break;
@@ -161,6 +145,6 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
        if (!buf)
                die("git-cat-file %s: bad file", argv[2]);
 
-       flush_buffer(buf, size);
+       write_or_die(1, buf, size);
        return 0;
 }
similarity index 92%
rename from checkout-index.c
rename to builtin-checkout-index.c
index dfb1c44..b097c88 100644 (file)
 #include "cache-tree.h"
 
 #define CHECKOUT_ALL 4
-static const char *prefix;
-static int prefix_length;
 static int line_termination = '\n';
 static int checkout_stage; /* default to checkout stage0 */
 static int to_tempfile;
-static char topath[4][MAXPATHLEN+1];
+static char topath[4][PATH_MAX + 1];
 
 static struct checkout state;
 
-static void write_tempfile_record (const char *name)
+static void write_tempfile_record(const char *name, int prefix_length)
 {
        int i;
 
@@ -77,7 +75,7 @@ static void write_tempfile_record (const char *name)
        }
 }
 
-static int checkout_file(const char *name)
+static int checkout_file(const char *name, int prefix_length)
 {
        int namelen = strlen(name);
        int pos = cache_name_pos(name, namelen);
@@ -106,7 +104,7 @@ static int checkout_file(const char *name)
 
        if (did_checkout) {
                if (to_tempfile)
-                       write_tempfile_record(name);
+                       write_tempfile_record(name, prefix_length);
                return errs > 0 ? -1 : 0;
        }
 
@@ -124,7 +122,7 @@ static int checkout_file(const char *name)
        return -1;
 }
 
-static int checkout_all(void)
+static void checkout_all(const char *prefix, int prefix_length)
 {
        int i, errs = 0;
        struct cache_entry* last_ce = NULL;
@@ -141,7 +139,7 @@ static int checkout_all(void)
                if (last_ce && to_tempfile) {
                        if (ce_namelen(last_ce) != ce_namelen(ce)
                            || memcmp(last_ce->name, ce->name, ce_namelen(ce)))
-                               write_tempfile_record(last_ce->name);
+                               write_tempfile_record(last_ce->name, prefix_length);
                }
                if (checkout_entry(ce, &state,
                    to_tempfile ? topath[ce_stage(ce)] : NULL) < 0)
@@ -149,13 +147,12 @@ static int checkout_all(void)
                last_ce = ce;
        }
        if (last_ce && to_tempfile)
-               write_tempfile_record(last_ce->name);
+               write_tempfile_record(last_ce->name, prefix_length);
        if (errs)
                /* we have already done our error reporting.
                 * exit with the same code as die().
                 */
                exit(128);
-       return 0;
 }
 
 static const char checkout_cache_usage[] =
@@ -163,16 +160,16 @@ static const char checkout_cache_usage[] =
 
 static struct lock_file lock_file;
 
-int main(int argc, char **argv)
+int cmd_checkout_index(int argc, const char **argv, const char *prefix)
 {
        int i;
        int newfd = -1;
        int all = 0;
        int read_from_stdin = 0;
+       int prefix_length;
 
-       state.base_dir = "";
-       prefix = setup_git_directory();
        git_config(git_default_config);
+       state.base_dir = "";
        prefix_length = prefix ? strlen(prefix) : 0;
 
        if (read_cache() < 0) {
@@ -270,7 +267,7 @@ int main(int argc, char **argv)
                if (read_from_stdin)
                        die("git-checkout-index: don't mix '--stdin' and explicit filenames");
                p = prefix_path(prefix, prefix_length, arg);
-               checkout_file(p);
+               checkout_file(p, prefix_length);
                if (p < arg || p > arg + strlen(arg))
                        free((char*)p);
        }
@@ -292,7 +289,7 @@ int main(int argc, char **argv)
                        else
                                path_name = buf.buf;
                        p = prefix_path(prefix, prefix_length, path_name);
-                       checkout_file(p);
+                       checkout_file(p, prefix_length);
                        if (p < path_name || p > path_name + strlen(path_name))
                                free((char *)p);
                        if (path_name != buf.buf)
@@ -301,7 +298,7 @@ int main(int argc, char **argv)
        }
 
        if (all)
-               checkout_all();
+               checkout_all(prefix, prefix_length);
 
        if (0 <= newfd &&
            (write_cache(newfd, active_cache, active_nr) ||
index 9c98796..e2e690a 100644 (file)
@@ -69,7 +69,7 @@ static int new_parent(int idx)
        int i;
        unsigned char *sha1 = parent_sha1[idx];
        for (i = 0; i < idx; i++) {
-               if (!memcmp(parent_sha1[i], sha1, 20)) {
+               if (!hashcmp(parent_sha1[i], sha1)) {
                        error("duplicate parent %s ignored", sha1_to_hex(sha1));
                        return 0;
                }
similarity index 100%
rename from builtin-count.c
rename to builtin-count-objects.c
index ac13db7..5d4a5c5 100644 (file)
@@ -47,12 +47,5 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
        if (rev.pending.nr ||
            rev.min_age != -1 || rev.max_age != -1)
                usage(diff_files_usage);
-       /*
-        * Backward compatibility wart - "diff-files -s" used to
-        * defeat the common diff option "-s" which asked for
-        * DIFF_FORMAT_NO_OUTPUT.
-        */
-       if (rev.diffopt.output_format == DIFF_FORMAT_NO_OUTPUT)
-               rev.diffopt.output_format = DIFF_FORMAT_RAW;
        return run_diff_files(&rev, silent);
 }
index 5960e08..70bb898 100644 (file)
@@ -46,7 +46,7 @@ static void diff_stages(int stage1, int stage2, const char **pathspec)
                else if (!two)
                        diff_addremove(&diff_options, '-', ntohl(one->ce_mode),
                                       one->sha1, name, NULL);
-               else if (memcmp(one->sha1, two->sha1, 20) ||
+               else if (hashcmp(one->sha1, two->sha1) ||
                         (one->ce_mode != two->ce_mode) ||
                         diff_options.find_copies_harder)
                        diff_change(&diff_options,
index a090e29..a659020 100644 (file)
@@ -56,13 +56,6 @@ static int builtin_diff_files(struct rev_info *revs,
        if (revs->max_count < 0 &&
            (revs->diffopt.output_format & DIFF_FORMAT_PATCH))
                revs->combine_merges = revs->dense_combined_merges = 1;
-       /*
-        * Backward compatibility wart - "diff-files -s" used to
-        * defeat the common diff option "-s" which asked for
-        * DIFF_FORMAT_NO_OUTPUT.
-        */
-       if (revs->diffopt.output_format == DIFF_FORMAT_NO_OUTPUT)
-               revs->diffopt.output_format = DIFF_FORMAT_RAW;
        return run_diff_files(revs, silent);
 }
 
@@ -75,9 +68,8 @@ static void stuff_change(struct diff_options *opt,
 {
        struct diff_filespec *one, *two;
 
-       if (memcmp(null_sha1, old_sha1, 20) &&
-           memcmp(null_sha1, new_sha1, 20) &&
-           !memcmp(old_sha1, new_sha1, 20))
+       if (!is_null_sha1(old_sha1) && !is_null_sha1(new_sha1) &&
+           !hashcmp(old_sha1, new_sha1))
                return;
 
        if (opt->reverse_diff) {
@@ -200,7 +192,7 @@ static int builtin_diff_combined(struct rev_info *revs,
        parent = xmalloc(ents * sizeof(*parent));
        /* Again, the revs are all reverse */
        for (i = 0; i < ents; i++)
-               memcpy(parent + i, ent[ents - 1 - i].item->sha1, 20);
+               hashcpy((unsigned char*)parent + i, ent[ents - 1 - i].item->sha1);
        diff_tree_combined(parent[0], parent + 1, ents - 1,
                           revs->dense_combined_merges, revs);
        return 0;
@@ -298,7 +290,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
                if (obj->type == OBJ_BLOB) {
                        if (2 <= blobs)
                                die("more than two blobs given: '%s'", name);
-                       memcpy(blob[blobs].sha1, obj->sha1, 20);
+                       hashcpy(blob[blobs].sha1, obj->sha1);
                        blob[blobs].name = name;
                        blobs++;
                        continue;
index 485ede7..a5ed8db 100644 (file)
@@ -8,7 +8,7 @@
 static const char *fmt_merge_msg_usage =
        "git-fmt-merge-msg [--summary] [--no-summary] [--file <file>]";
 
-static int merge_summary = 0;
+static int merge_summary;
 
 static int fmt_merge_msg_config(const char *key, const char *value)
 {
@@ -27,8 +27,8 @@ static void append_to_list(struct list *list, char *value, void *payload)
 {
        if (list->nr == list->alloc) {
                list->alloc += 32;
-               list->list = realloc(list->list, sizeof(char *) * list->alloc);
-               list->payload = realloc(list->payload,
+               list->list = xrealloc(list->list, sizeof(char *) * list->alloc);
+               list->payload = xrealloc(list->payload,
                                sizeof(char *) * list->alloc);
        }
        list->payload[list->nr] = payload;
index 93b7e07..8213ce2 100644 (file)
@@ -123,6 +123,7 @@ struct grep_opt {
        struct grep_pat *pattern_list;
        struct grep_pat **pattern_tail;
        struct grep_expr *pattern_expression;
+       int prefix_length;
        regex_t regexp;
        unsigned linenum:1;
        unsigned invert:1;
@@ -136,6 +137,7 @@ struct grep_opt {
 #define GREP_BINARY_TEXT       2
        unsigned binary:2;
        unsigned extended:1;
+       unsigned relative:1;
        int regflags;
        unsigned pre_context;
        unsigned post_context;
@@ -173,61 +175,12 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)
        }
 }
 
-#if DEBUG
-static inline void indent(int in)
-{
-       int i;
-       for (i = 0; i < in; i++) putchar(' ');
-}
-
-static void dump_pattern_exp(struct grep_expr *x, int in)
-{
-       switch (x->node) {
-       case GREP_NODE_ATOM:
-               indent(in);
-               puts(x->u.atom->pattern);
-               break;
-       case GREP_NODE_NOT:
-               indent(in);
-               puts("--not");
-               dump_pattern_exp(x->u.unary, in+1);
-               break;
-       case GREP_NODE_AND:
-               dump_pattern_exp(x->u.binary.left, in+1);
-               indent(in);
-               puts("--and");
-               dump_pattern_exp(x->u.binary.right, in+1);
-               break;
-       case GREP_NODE_OR:
-               dump_pattern_exp(x->u.binary.left, in+1);
-               indent(in);
-               puts("--or");
-               dump_pattern_exp(x->u.binary.right, in+1);
-               break;
-       }
-}
-
-static void looking_at(const char *msg, struct grep_pat **list)
-{
-       struct grep_pat *p = *list;
-       fprintf(stderr, "%s: looking at ", msg);
-       if (!p)
-               fprintf(stderr, "empty\n");
-       else
-               fprintf(stderr, "<%s>\n", p->pattern);
-}
-#else
-#define looking_at(a,b) do {} while(0)
-#endif
-
 static struct grep_expr *compile_pattern_expr(struct grep_pat **);
 static struct grep_expr *compile_pattern_atom(struct grep_pat **list)
 {
        struct grep_pat *p;
        struct grep_expr *x;
 
-       looking_at("atom", list);
-
        p = *list;
        switch (p->token) {
        case GREP_PATTERN: /* atom */
@@ -255,8 +208,6 @@ static struct grep_expr *compile_pattern_not(struct grep_pat **list)
        struct grep_pat *p;
        struct grep_expr *x;
 
-       looking_at("not", list);
-
        p = *list;
        switch (p->token) {
        case GREP_NOT:
@@ -279,8 +230,6 @@ static struct grep_expr *compile_pattern_and(struct grep_pat **list)
        struct grep_pat *p;
        struct grep_expr *x, *y, *z;
 
-       looking_at("and", list);
-
        x = compile_pattern_not(list);
        p = *list;
        if (p && p->token == GREP_AND) {
@@ -304,8 +253,6 @@ static struct grep_expr *compile_pattern_or(struct grep_pat **list)
        struct grep_pat *p;
        struct grep_expr *x, *y, *z;
 
-       looking_at("or", list);
-
        x = compile_pattern_and(list);
        p = *list;
        if (x && p && p->token != GREP_CLOSE_PAREN) {
@@ -323,8 +270,6 @@ static struct grep_expr *compile_pattern_or(struct grep_pat **list)
 
 static struct grep_expr *compile_pattern_expr(struct grep_pat **list)
 {
-       looking_at("expr", list);
-
        return compile_pattern_or(list);
 }
 
@@ -348,9 +293,6 @@ static void compile_patterns(struct grep_opt *opt)
         */
        p = opt->pattern_list;
        opt->pattern_expression = compile_pattern_expr(&p);
-#if DEBUG
-       dump_pattern_exp(opt->pattern_expression, 0);
-#endif
        if (p)
                die("incomplete pattern expression: %s", p->pattern);
 }
@@ -388,9 +330,7 @@ static int buffer_is_binary(const char *ptr, unsigned long size)
 {
        if (FIRST_FEW_BYTES < size)
                size = FIRST_FEW_BYTES;
-       if (memchr(ptr, 0, size))
-               return 1;
-       return 0;
+       return !!memchr(ptr, 0, size);
 }
 
 static int fixmatch(const char *pattern, char *line, regmatch_t *match)
@@ -632,19 +572,40 @@ static int grep_buffer(struct grep_opt *opt, const char *name,
        return !!last_hit;
 }
 
-static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1, const char *name)
+static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1, const char *name, int tree_name_len)
 {
        unsigned long size;
        char *data;
        char type[20];
+       char *to_free = NULL;
        int hit;
+
        data = read_sha1_file(sha1, type, &size);
        if (!data) {
                error("'%s': unable to read %s", name, sha1_to_hex(sha1));
                return 0;
        }
+       if (opt->relative && opt->prefix_length) {
+               static char name_buf[PATH_MAX];
+               char *cp;
+               int name_len = strlen(name) - opt->prefix_length + 1;
+
+               if (!tree_name_len)
+                       name += opt->prefix_length;
+               else {
+                       if (ARRAY_SIZE(name_buf) <= name_len)
+                               cp = to_free = xmalloc(name_len);
+                       else
+                               cp = name_buf;
+                       memcpy(cp, name, tree_name_len);
+                       strcpy(cp + tree_name_len,
+                              name + tree_name_len + opt->prefix_length);
+                       name = cp;
+               }
+       }
        hit = grep_buffer(opt, name, data, size);
        free(data);
+       free(to_free);
        return hit;
 }
 
@@ -674,6 +635,8 @@ static int grep_file(struct grep_opt *opt, const char *filename)
                return 0;
        }
        close(i);
+       if (opt->relative && opt->prefix_length)
+               filename += opt->prefix_length;
        i = grep_buffer(opt, filename, data, st.st_size);
        free(data);
        return i;
@@ -720,7 +683,7 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)
        char *argptr = randarg;
        struct grep_pat *p;
 
-       if (opt->extended)
+       if (opt->extended || (opt->relative && opt->prefix_length))
                return -1;
        len = nr = 0;
        push_arg("grep");
@@ -845,7 +808,7 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached)
                if (!pathspec_matches(paths, ce->name))
                        continue;
                if (cached)
-                       hit |= grep_sha1(opt, ce->sha1, ce->name);
+                       hit |= grep_sha1(opt, ce->sha1, ce->name, 0);
                else
                        hit |= grep_file(opt, ce->name);
        }
@@ -860,11 +823,12 @@ static int grep_tree(struct grep_opt *opt, const char **paths,
        int hit = 0;
        struct name_entry entry;
        char *down;
-       char *path_buf = xmalloc(PATH_MAX + strlen(tree_name) + 100);
+       int tn_len = strlen(tree_name);
+       char *path_buf = xmalloc(PATH_MAX + tn_len + 100);
 
-       if (tree_name[0]) {
-               int offset = sprintf(path_buf, "%s:", tree_name);
-               down = path_buf + offset;
+       if (tn_len) {
+               tn_len = sprintf(path_buf, "%s:", tree_name);
+               down = path_buf + tn_len;
                strcat(down, base);
        }
        else {
@@ -886,7 +850,7 @@ static int grep_tree(struct grep_opt *opt, const char **paths,
                if (!pathspec_matches(paths, down))
                        ;
                else if (S_ISREG(entry.mode))
-                       hit |= grep_sha1(opt, entry.sha1, path_buf);
+                       hit |= grep_sha1(opt, entry.sha1, path_buf, tn_len);
                else if (S_ISDIR(entry.mode)) {
                        char type[20];
                        struct tree_desc sub;
@@ -907,7 +871,7 @@ static int grep_object(struct grep_opt *opt, const char **paths,
                       struct object *obj, const char *name)
 {
        if (obj->type == OBJ_BLOB)
-               return grep_sha1(opt, obj->sha1, name);
+               return grep_sha1(opt, obj->sha1, name, 0);
        if (obj->type == OBJ_COMMIT || obj->type == OBJ_TREE) {
                struct tree_desc tree;
                void *data;
@@ -945,6 +909,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
        int i;
 
        memset(&opt, 0, sizeof(opt));
+       opt.prefix_length = (prefix && *prefix) ? strlen(prefix) : 0;
+       opt.relative = 1;
        opt.pattern_tail = &opt.pattern_list;
        opt.regflags = REG_NEWLINE;
 
@@ -1118,6 +1084,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                        }
                        die(emsg_missing_argument, arg);
                }
+               if (!strcmp("--full-name", arg)) {
+                       opt.relative = 0;
+                       continue;
+               }
                if (!strcmp("--", arg)) {
                        /* later processing wants to have this at argv[1] */
                        argv--;
@@ -1176,8 +1146,15 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                        verify_filename(prefix, argv[j]);
        }
 
-       if (i < argc)
+       if (i < argc) {
                paths = get_pathspec(prefix, argv + i);
+               if (opt.prefix_length && opt.relative) {
+                       /* Make sure we do not get outside of paths */
+                       for (i = 0; paths[i]; i++)
+                               if (strncmp(prefix, paths[i], opt.prefix_length))
+                                       die("git-grep: cannot generate relative filenames containing '..'");
+               }
+       }
        else if (prefix) {
                paths = xcalloc(2, sizeof(const char *));
                paths[0] = prefix;
index 691cf3a..fbc58bb 100644 (file)
@@ -101,7 +101,7 @@ static int git_format_config(const char *var, const char *value)
        if (!strcmp(var, "format.headers")) {
                int len = strlen(value);
                extra_headers_size += len + 1;
-               extra_headers = realloc(extra_headers, extra_headers_size);
+               extra_headers = xrealloc(extra_headers, extra_headers_size);
                extra_headers[extra_headers_size - len - 1] = 0;
                strcat(extra_headers, value);
                return 0;
@@ -381,7 +381,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                        continue;
 
                nr++;
-               list = realloc(list, nr * sizeof(list[0]));
+               list = xrealloc(list, nr * sizeof(list[0]));
                list[nr - 1] = commit;
        }
        total = nr;
index 11386c4..ad8c41e 100644 (file)
 #include "dir.h"
 #include "builtin.h"
 
-static int abbrev = 0;
-static int show_deleted = 0;
-static int show_cached = 0;
-static int show_others = 0;
-static int show_stage = 0;
-static int show_unmerged = 0;
-static int show_modified = 0;
-static int show_killed = 0;
-static int show_valid_bit = 0;
+static int abbrev;
+static int show_deleted;
+static int show_cached;
+static int show_others;
+static int show_stage;
+static int show_unmerged;
+static int show_modified;
+static int show_killed;
+static int show_valid_bit;
 static int line_terminator = '\n';
 
-static int prefix_len = 0, prefix_offset = 0;
-static const char **pathspec = NULL;
-static int error_unmatch = 0;
-static char *ps_matched = NULL;
+static int prefix_len;
+static int prefix_offset;
+static const char **pathspec;
+static int error_unmatch;
+static char *ps_matched;
 
 static const char *tag_cached = "";
 static const char *tag_unmerged = "";
index 261147f..201defd 100644 (file)
@@ -14,10 +14,10 @@ static int line_termination = '\n';
 #define LS_TREE_ONLY 2
 #define LS_SHOW_TREES 4
 #define LS_NAME_ONLY 8
-static int abbrev = 0;
-static int ls_options = 0;
+static int abbrev;
+static int ls_options;
 static const char **pathspec;
-static int chomp_prefix = 0;
+static int chomp_prefix;
 static const char *ls_tree_prefix;
 
 static const char ls_tree_usage[] =
index 24a4fc6..0c65f93 100644 (file)
@@ -16,8 +16,8 @@
 
 static FILE *cmitmsg, *patchfile, *fin, *fout;
 
-static int keep_subject = 0;
-static const char *metainfo_charset = NULL;
+static int keep_subject;
+static const char *metainfo_charset;
 static char line[1000];
 static char date[1000];
 static char name[1000];
@@ -31,7 +31,7 @@ static char charset[256];
 
 static char multipart_boundary[1000];
 static int multipart_boundary_len;
-static int patch_lines = 0;
+static int patch_lines;
 
 static char *sanity_check(char *name, char *email)
 {
index a731f8d..4d21d88 100644 (file)
@@ -17,12 +17,19 @@ static const char builtin_mv_usage[] =
 static const char **copy_pathspec(const char *prefix, const char **pathspec,
                                  int count, int base_name)
 {
+       int i;
        const char **result = xmalloc((count + 1) * sizeof(const char *));
        memcpy(result, pathspec, count * sizeof(const char *));
        result[count] = NULL;
-       if (base_name) {
-               int i;
-               for (i = 0; i < count; i++) {
+       for (i = 0; i < count; i++) {
+               int length = strlen(result[i]);
+               if (length > 0 && result[i][length - 1] == '/') {
+                       char *without_slash = xmalloc(length);
+                       memcpy(without_slash, result[i], length - 1);
+                       without_slash[length - 1] = '\0';
+                       result[i] = without_slash;
+               }
+               if (base_name) {
                        const char *last_slash = strrchr(result[i], '/');
                        if (last_slash)
                                result[i] = last_slash + 1;
@@ -107,7 +114,10 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
        modes = xcalloc(count, sizeof(enum update_mode));
        dest_path = copy_pathspec(prefix, argv + argc - 1, 1, 0);
 
-       if (!lstat(dest_path[0], &st) &&
+       if (dest_path[0][0] == '\0')
+               /* special case: "." was normalized to "" */
+               destination = copy_pathspec(dest_path[0], argv + i, count, 1);
+       else if (!lstat(dest_path[0], &st) &&
                        S_ISDIR(st.st_mode)) {
                dest_path[0] = add_slash(dest_path[0]);
                destination = copy_pathspec(dest_path[0], argv + i, count, 1);
@@ -119,72 +129,71 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
 
        /* Checking */
        for (i = 0; i < count; i++) {
+               const char *src = source[i], *dst = destination[i];
+               int length, src_is_dir;
                const char *bad = NULL;
 
                if (show_only)
-                       printf("Checking rename of '%s' to '%s'\n",
-                               source[i], destination[i]);
+                       printf("Checking rename of '%s' to '%s'\n", src, dst);
 
-               if (lstat(source[i], &st) < 0)
+               length = strlen(src);
+               if (lstat(src, &st) < 0)
                        bad = "bad source";
-
-               if (S_ISDIR(st.st_mode)) {
-                       const char *dir = source[i], *dest_dir = destination[i];
-                       int first, last, len = strlen(dir);
-
-                       if (lstat(dest_dir, &st) == 0) {
-                               bad = "cannot move directory over file";
-                               goto next;
-                       }
+               else if (!strncmp(src, dst, length) &&
+                               (dst[length] == 0 || dst[length] == '/')) {
+                       bad = "can not move directory into itself";
+               } else if ((src_is_dir = S_ISDIR(st.st_mode))
+                               && lstat(dst, &st) == 0)
+                       bad = "cannot move directory over file";
+               else if (src_is_dir) {
+                       int first, last;
 
                        modes[i] = WORKING_DIRECTORY;
 
-                       first = cache_name_pos(source[i], len);
+                       first = cache_name_pos(src, length);
                        if (first >= 0)
-                               die ("Huh? %s/ is in index?", dir);
+                               die ("Huh? %s/ is in index?", src);
 
                        first = -1 - first;
                        for (last = first; last < active_nr; last++) {
                                const char *path = active_cache[last]->name;
-                               if (strncmp(path, dir, len) || path[len] != '/')
+                               if (strncmp(path, src, length)
+                                               || path[length] != '/')
                                        break;
                        }
 
                        if (last - first < 1)
                                bad = "source directory is empty";
-                       else if (!bad) {
-                               int j, dst_len = strlen(dest_dir);
+                       else {
+                               int j, dst_len;
 
                                if (last - first > 0) {
-                                       source = realloc(source,
+                                       source = xrealloc(source,
                                                        (count + last - first)
                                                        * sizeof(char *));
-                                       destination = realloc(destination,
+                                       destination = xrealloc(destination,
                                                        (count + last - first)
                                                        * sizeof(char *));
-                                       modes = realloc(modes,
+                                       modes = xrealloc(modes,
                                                        (count + last - first)
                                                        * sizeof(enum update_mode));
                                }
 
-                               dest_dir = add_slash(dest_dir);
+                               dst = add_slash(dst);
+                               dst_len = strlen(dst) - 1;
 
                                for (j = 0; j < last - first; j++) {
                                        const char *path =
                                                active_cache[first + j]->name;
                                        source[count + j] = path;
                                        destination[count + j] =
-                                               prefix_path(dest_dir, dst_len,
-                                                       path + len);
+                                               prefix_path(dst, dst_len,
+                                                       path + length);
                                        modes[count + j] = INDEX;
                                }
                                count += last - first;
                        }
-
-                       goto next;
-               }
-
-               if (!bad && lstat(destination[i], &st) == 0) {
+               } else if (lstat(dst, &st) == 0) {
                        bad = "destination exists";
                        if (force) {
                                /*
@@ -196,28 +205,17 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
                                                        " will overwrite!\n",
                                                        bad);
                                        bad = NULL;
-                                       path_list_insert(destination[i],
-                                                       &overwritten);
+                                       path_list_insert(dst, &overwritten);
                                } else
                                        bad = "Cannot overwrite";
                        }
-               }
-
-               if (!bad &&
-                   !strncmp(destination[i], source[i], strlen(source[i])))
-                       bad = "can not move directory into itself";
-
-               if (!bad && cache_name_pos(source[i], strlen(source[i])) < 0)
+               } else if (cache_name_pos(src, length) < 0)
                        bad = "not under version control";
+               else if (path_list_has_path(&src_for_dst, dst))
+                       bad = "multiple sources for the same target";
+               else
+                       path_list_insert(dst, &src_for_dst);
 
-               if (!bad) {
-                       if (path_list_has_path(&src_for_dst, destination[i]))
-                               bad = "multiple sources for the same target";
-                       else
-                               path_list_insert(destination[i], &src_for_dst);
-               }
-
-next:
                if (bad) {
                        if (ignore_errors) {
                                if (--count > 0) {
@@ -229,33 +227,32 @@ next:
                                }
                        } else
                                die ("%s, source=%s, destination=%s",
-                                    bad, source[i], destination[i]);
+                                    bad, src, dst);
                }
        }
 
        for (i = 0; i < count; i++) {
+               const char *src = source[i], *dst = destination[i];
+               enum update_mode mode = modes[i];
                if (show_only || verbose)
-                       printf("Renaming %s to %s\n",
-                              source[i], destination[i]);
-               if (!show_only && modes[i] != INDEX &&
-                   rename(source[i], destination[i]) < 0 &&
-                   !ignore_errors)
-                       die ("renaming %s failed: %s",
-                            source[i], strerror(errno));
-
-               if (modes[i] == WORKING_DIRECTORY)
+                       printf("Renaming %s to %s\n", src, dst);
+               if (!show_only && mode != INDEX &&
+                               rename(src, dst) < 0 && !ignore_errors)
+                       die ("renaming %s failed: %s", src, strerror(errno));
+
+               if (mode == WORKING_DIRECTORY)
                        continue;
 
-               if (cache_name_pos(source[i], strlen(source[i])) >= 0) {
-                       path_list_insert(source[i], &deleted);
+               if (cache_name_pos(src, strlen(src)) >= 0) {
+                       path_list_insert(src, &deleted);
 
                        /* destination can be a directory with 1 file inside */
-                       if (path_list_has_path(&overwritten, destination[i]))
-                               path_list_insert(destination[i], &changed);
+                       if (path_list_has_path(&overwritten, dst))
+                               path_list_insert(dst, &changed);
                        else
-                               path_list_insert(destination[i], &added);
+                               path_list_insert(dst, &added);
                } else
-                       path_list_insert(destination[i], &added);
+                       path_list_insert(dst, &added);
        }
 
         if (show_only) {
@@ -265,10 +262,10 @@ next:
        } else {
                for (i = 0; i < changed.nr; i++) {
                        const char *path = changed.items[i].path;
-                       int i = cache_name_pos(path, strlen(path));
-                       struct cache_entry *ce = active_cache[i];
+                       int j = cache_name_pos(path, strlen(path));
+                       struct cache_entry *ce = active_cache[j];
 
-                       if (i < 0)
+                       if (j < 0)
                                die ("Huh? Cache entry for %s unknown?", path);
                        refresh_cache_entry(ce, 0);
                }
similarity index 98%
rename from name-rev.c
rename to builtin-name-rev.c
index f92f14e..d44e782 100644 (file)
@@ -1,4 +1,5 @@
 #include <stdlib.h>
+#include "builtin.h"
 #include "cache.h"
 #include "commit.h"
 #include "tag.h"
@@ -74,7 +75,7 @@ copy_data:
        }
 }
 
-static int tags_only = 0;
+static int tags_only;
 
 static int name_ref(const char *path, const unsigned char *sha1)
 {
@@ -126,12 +127,11 @@ static const char* get_rev_name(struct object *o)
        return buffer;
 }
 
-int main(int argc, char **argv)
+int cmd_name_rev(int argc, const char **argv, const char *prefix)
 {
        struct object_array revs = { 0, 0, NULL };
        int as_is = 0, all = 0, transform_stdin = 0;
 
-       setup_git_directory();
        git_config(git_default_config);
 
        if (argc < 2)
similarity index 96%
rename from pack-objects.c
rename to builtin-pack-objects.c
index 861c7f0..46f524d 100644 (file)
@@ -1,3 +1,4 @@
+#include "builtin.h"
 #include "cache.h"
 #include "object.h"
 #include "blob.h"
@@ -52,17 +53,17 @@ struct object_entry {
  */
 
 static unsigned char object_list_sha1[20];
-static int non_empty = 0;
-static int no_reuse_delta = 0;
-static int local = 0;
-static int incremental = 0;
+static int non_empty;
+static int no_reuse_delta;
+static int local;
+static int incremental;
 static struct object_entry **sorted_by_sha, **sorted_by_type;
-static struct object_entry *objects = NULL;
-static int nr_objects = 0, nr_alloc = 0, nr_result = 0;
+static struct object_entry *objects;
+static int nr_objects, nr_alloc, nr_result;
 static const char *base_name;
 static unsigned char pack_file_sha1[20];
 static int progress = 1;
-static volatile sig_atomic_t progress_update = 0;
+static volatile sig_atomic_t progress_update;
 static int window = 10;
 
 /*
@@ -71,8 +72,8 @@ static int window = 10;
  * sorted_by_sha is also possible but this was easier to code and faster.
  * This hashtable is built after all the objects are seen.
  */
-static int *object_ix = NULL;
-static int object_ix_hashsz = 0;
+static int *object_ix;
+static int object_ix_hashsz;
 
 /*
  * Pack index for existing packs give us easy access to the offsets into
@@ -89,15 +90,15 @@ struct pack_revindex {
        struct packed_git *p;
        unsigned long *revindex;
 } *pack_revindex = NULL;
-static int pack_revindex_hashsz = 0;
+static int pack_revindex_hashsz;
 
 /*
  * stats
  */
-static int written = 0;
-static int written_delta = 0;
-static int reused = 0;
-static int reused_delta = 0;
+static int written;
+static int written_delta;
+static int reused;
+static int reused_delta;
 
 static int pack_revindex_ix(struct packed_git *p)
 {
@@ -269,6 +270,22 @@ static unsigned long write_object(struct sha1file *f,
                                 * and we do not need to deltify it.
                                 */
 
+       if (!entry->in_pack && !entry->delta) {
+               unsigned char *map;
+               unsigned long mapsize;
+               map = map_sha1_file(entry->sha1, &mapsize);
+               if (map && !legacy_loose_object(map)) {
+                       /* We can copy straight into the pack file */
+                       sha1write(f, map, mapsize);
+                       munmap(map, mapsize);
+                       written++;
+                       reused++;
+                       return mapsize;
+               }
+               if (map)
+                       munmap(map, mapsize);
+       }
+
        if (! to_reuse) {
                buf = read_sha1_file(entry->sha1, type, &size);
                if (!buf)
@@ -424,7 +441,7 @@ static int locate_object_entry_hash(const unsigned char *sha1)
        memcpy(&ui, sha1, sizeof(unsigned int));
        i = ui % object_ix_hashsz;
        while (0 < object_ix[i]) {
-               if (!memcmp(sha1, objects[object_ix[i]-1].sha1, 20))
+               if (!hashcmp(sha1, objects[object_ix[i] - 1].sha1))
                        return i;
                if (++i == object_ix_hashsz)
                        i = 0;
@@ -517,7 +534,7 @@ static int add_object_entry(const unsigned char *sha1, unsigned hash, int exclud
        entry = objects + idx;
        nr_objects = idx + 1;
        memset(entry, 0, sizeof(*entry));
-       memcpy(entry->sha1, sha1, 20);
+       hashcpy(entry->sha1, sha1);
        entry->hash = hash;
 
        if (object_ix_hashsz * 3 <= nr_objects * 4)
@@ -590,7 +607,7 @@ static struct pbase_tree_cache *pbase_tree_get(const unsigned char *sha1)
         */
        for (neigh = 0; neigh < 8; neigh++) {
                ent = pbase_tree_cache[my_ix];
-               if (ent && !memcmp(ent->sha1, sha1, 20)) {
+               if (ent && !hashcmp(ent->sha1, sha1)) {
                        ent->ref++;
                        return ent;
                }
@@ -632,7 +649,7 @@ static struct pbase_tree_cache *pbase_tree_get(const unsigned char *sha1)
                free(ent->tree_data);
                nent = ent;
        }
-       memcpy(nent->sha1, sha1, 20);
+       hashcpy(nent->sha1, sha1);
        nent->tree_data = data;
        nent->tree_size = size;
        nent->ref = 1;
@@ -772,7 +789,7 @@ static void add_preferred_base(unsigned char *sha1)
                return;
 
        for (it = pbase_tree; it; it = it->next) {
-               if (!memcmp(it->pcache.sha1, tree_sha1, 20)) {
+               if (!hashcmp(it->pcache.sha1, tree_sha1)) {
                        free(data);
                        return;
                }
@@ -782,7 +799,7 @@ static void add_preferred_base(unsigned char *sha1)
        it->next = pbase_tree;
        pbase_tree = it;
 
-       memcpy(it->pcache.sha1, tree_sha1, 20);
+       hashcpy(it->pcache.sha1, tree_sha1);
        it->pcache.tree_data = data;
        it->pcache.tree_size = size;
 }
@@ -914,7 +931,7 @@ static struct object_entry **create_sorted_list(entry_sort_t sort)
 
 static int sha1_sort(const struct object_entry *a, const struct object_entry *b)
 {
-       return memcmp(a->sha1, b->sha1, 20);
+       return hashcmp(a->sha1, b->sha1);
 }
 
 static struct object_entry **create_final_object_list(void)
@@ -1226,7 +1243,7 @@ static int git_pack_config(const char *k, const char *v)
        return git_default_config(k, v);
 }
 
-int main(int argc, char **argv)
+int cmd_pack_objects(int argc, const char **argv, const char *prefix)
 {
        SHA_CTX ctx;
        char line[40 + 1 + PATH_MAX + 2];
@@ -1235,7 +1252,6 @@ int main(int argc, char **argv)
        int num_preferred_base = 0;
        int i;
 
-       setup_git_directory();
        git_config(git_pack_config);
 
        progress = isatty(2);
index 89ec7f1..fc885ce 100644 (file)
@@ -11,7 +11,7 @@
 #include "cache-tree.h"
 
 static const char prune_usage[] = "git-prune [-n]";
-static int show_only = 0;
+static int show_only;
 static struct rev_info revs;
 
 static int prune_object(char *path, const char *filename, const unsigned char *sha1)
index 53bc378..ada8338 100644 (file)
 
 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;
+static int all, tags, force, thin = 1;
+static const char *execute;
 
 #define BUF_SIZE (2084)
 static char buffer[BUF_SIZE];
 
-static const char **refspec = NULL;
-static int refspec_nr = 0;
+static const char **refspec;
+static int refspec_nr;
 
 static void add_refspec(const char *ref)
 {
@@ -32,10 +32,8 @@ static int expand_one_ref(const char *ref, const unsigned char *sha1)
        /* Ignore the "refs/" at the beginning of the refname */
        ref += 5;
 
-       if (strncmp(ref, "tags/", 5))
-               return 0;
-
-       add_refspec(strdup(ref));
+       if (!strncmp(ref, "tags/", 5))
+               add_refspec(strdup(ref));
        return 0;
 }
 
@@ -234,7 +232,7 @@ static int do_push(const char *repo)
        common_argc = argc;
 
        for (i = 0; i < n; i++) {
-               int error;
+               int err;
                int dest_argc = common_argc;
                int dest_refspec_nr = refspec_nr;
                const char **dest_refspec = refspec;
@@ -250,10 +248,10 @@ static int do_push(const char *repo)
                while (dest_refspec_nr--)
                        argv[dest_argc++] = *dest_refspec++;
                argv[dest_argc] = NULL;
-               error = run_command_v(argc, argv);
-               if (!error)
+               err = run_command_v(argc, argv);
+               if (!err)
                        continue;
-               switch (error) {
+               switch (err) {
                case -ERR_RUN_COMMAND_FORK:
                        die("unable to fork for %s", sender);
                case -ERR_RUN_COMMAND_EXEC:
@@ -264,7 +262,7 @@ static int do_push(const char *repo)
                case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
                        die("%s died with strange error", sender);
                default:
-                       return -error;
+                       return -err;
                }
        }
        return 0;
index 8da8acb..c1867d2 100644 (file)
@@ -12,7 +12,7 @@
 #include "unpack-trees.h"
 #include "builtin.h"
 
-static struct object_list *trees = NULL;
+static struct object_list *trees;
 
 static int list_tree(unsigned char *sha1)
 {
@@ -53,7 +53,7 @@ static void prime_cache_tree_rec(struct cache_tree *it, struct tree *tree)
        struct name_entry entry;
        int cnt;
 
-       memcpy(it->sha1, tree->object.sha1, 20);
+       hashcpy(it->sha1, tree->object.sha1);
        desc.buf = tree->buffer;
        desc.size = tree->size;
        cnt = 0;
index c821e22..c416480 100644 (file)
@@ -5,14 +5,14 @@
 static const char git_config_set_usage[] =
 "git-repo-config [ --bool | --int ] [--get | --get-all | --get-regexp | --replace-all | --unset | --unset-all] name [value [value_regex]] | --list";
 
-static char* key = NULL;
-static regex_t* key_regexp = NULL;
-static regex_t* regexp = NULL;
-static int show_keys = 0;
-static int use_key_regexp = 0;
-static int do_all = 0;
-static int do_not_match = 0;
-static int seen = 0;
+static char *key;
+static regex_t *key_regexp;
+static regex_t *regexp;
+static int show_keys;
+static int use_key_regexp;
+static int do_all;
+static int do_not_match;
+static int seen;
 static enum { T_RAW, T_INT, T_BOOL } type = T_RAW;
 
 static int show_all_config(const char *key_, const char *value_)
index 0dee173..bc48a3e 100644 (file)
@@ -39,9 +39,9 @@ static const char rev_list_usage[] =
 
 static struct rev_info revs;
 
-static int bisect_list = 0;
-static int show_timestamp = 0;
-static int hdr_termination = 0;
+static int bisect_list;
+static int show_timestamp;
+static int hdr_termination;
 static const char *header_prefix;
 
 static void show_commit(struct commit *commit)
index aca4a36..fd3ccc8 100644 (file)
 #define DO_NONFLAGS    8
 static int filter = ~0;
 
-static const char *def = NULL;
+static const char *def;
 
 #define NORMAL 0
 #define REVERSED 1
 static int show_type = NORMAL;
-static int symbolic = 0;
-static int abbrev = 0;
-static int output_sq = 0;
+static int symbolic;
+static int abbrev;
+static int output_sq;
 
-static int revs_count = 0;
+static int revs_count;
 
 /*
  * Some arguments are relevant "revision" arguments,
index 2a1b848..18786f8 100644 (file)
@@ -8,9 +8,9 @@
 static const char show_branch_usage[] =
 "git-show-branch [--sparse] [--current] [--all] [--heads] [--tags] [--topo-order] [--more=count | --list | --independent | --merge-base ] [--topics] [<refs>...]";
 
-static int default_num = 0;
-static int default_alloc = 0;
-static const char **default_arg = NULL;
+static int default_num;
+static int default_alloc;
+static const char **default_arg;
 
 #define UNINTERESTING  01
 
@@ -378,7 +378,7 @@ static int append_head_ref(const char *refname, const unsigned char *sha1)
        /* If both heads/foo and tags/foo exists, get_sha1 would
         * get confused.
         */
-       if (get_sha1(refname + ofs, tmp) || memcmp(tmp, sha1, 20))
+       if (get_sha1(refname + ofs, tmp) || hashcmp(tmp, sha1))
                ofs = 5;
        return append_ref(refname + ofs, sha1);
 }
@@ -442,7 +442,7 @@ static int rev_is_head(char *head_path, int headlen, char *name,
 {
        int namelen;
        if ((!head_path[0]) ||
-           (head_sha1 && sha1 && memcmp(head_sha1, sha1, 20)))
+           (head_sha1 && sha1 && hashcmp(head_sha1, sha1)))
                return 0;
        namelen = strlen(name);
        if ((headlen < namelen) ||
similarity index 88%
rename from symbolic-ref.c
rename to builtin-symbolic-ref.c
index 193c87c..b4ec6f2 100644 (file)
@@ -1,3 +1,4 @@
+#include "builtin.h"
 #include "cache.h"
 
 static const char git_symbolic_ref_usage[] =
@@ -17,9 +18,8 @@ static void check_symref(const char *HEAD)
                die("No such ref: %s", HEAD);
 }
 
-int main(int argc, const char **argv)
+int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
 {
-       setup_git_directory();
        git_config(git_default_config);
        switch (argc) {
        case 2:
index 215892b..61a4135 100644 (file)
@@ -14,7 +14,7 @@
 #define BLOCKSIZE      (RECORDSIZE * 20)
 
 static const char tar_tree_usage[] =
-"git-tar-tree [--remote=<repo>] <ent> [basedir]";
+"git-tar-tree [--remote=<repo>] <tree-ish> [basedir]";
 
 static char block[BLOCKSIZE];
 static unsigned long offset;
@@ -22,30 +22,11 @@ static unsigned long offset;
 static time_t archive_time;
 static int tar_umask;
 
-/* tries hard to write, either succeeds or dies in the attempt */
-static void reliable_write(const void *data, unsigned long size)
-{
-       const char *buf = data;
-
-       while (size > 0) {
-               long ret = xwrite(1, buf, size);
-               if (ret < 0) {
-                       if (errno == EPIPE)
-                               exit(0);
-                       die("git-tar-tree: %s", strerror(errno));
-               } else if (!ret) {
-                       die("git-tar-tree: disk full?");
-               }
-               size -= ret;
-               buf += ret;
-       }
-}
-
 /* writes out the whole block, but only if it is full */
 static void write_if_needed(void)
 {
        if (offset == BLOCKSIZE) {
-               reliable_write(block, BLOCKSIZE);
+               write_or_die(1, block, BLOCKSIZE);
                offset = 0;
        }
 }
@@ -70,7 +51,7 @@ static void write_blocked(const void *data, unsigned long size)
                write_if_needed();
        }
        while (size >= BLOCKSIZE) {
-               reliable_write(buf, BLOCKSIZE);
+               write_or_die(1, buf, BLOCKSIZE);
                size -= BLOCKSIZE;
                buf += BLOCKSIZE;
        }
@@ -94,10 +75,10 @@ static void write_trailer(void)
 {
        int tail = BLOCKSIZE - offset;
        memset(block + offset, 0, tail);
-       reliable_write(block, BLOCKSIZE);
+       write_or_die(1, block, BLOCKSIZE);
        if (tail < 2 * RECORDSIZE) {
                memset(block, 0, offset);
-               reliable_write(block, BLOCKSIZE);
+               write_or_die(1, block, BLOCKSIZE);
        }
 }
 
@@ -294,7 +275,7 @@ static void traverse_tree(struct tree_desc *tree, struct strbuf *path)
        }
 }
 
-int git_tar_config(const char *var, const char *value)
+static int git_tar_config(const char *var, const char *value)
 {
        if (!strcmp(var, "tar.umask")) {
                if (!strcmp(value, "user")) {
similarity index 95%
rename from unpack-objects.c
rename to builtin-unpack-objects.c
index 48c1ee7..ca0ebc2 100644 (file)
@@ -1,3 +1,4 @@
+#include "builtin.h"
 #include "cache.h"
 #include "object.h"
 #include "delta.h"
@@ -94,7 +95,7 @@ static void add_delta_to_list(unsigned char *base_sha1, void *delta, unsigned lo
 {
        struct delta_info *info = xmalloc(sizeof(*info));
 
-       memcpy(info->base_sha1, base_sha1, 20);
+       hashcpy(info->base_sha1, base_sha1);
        info->size = size;
        info->delta = delta;
        info->next = delta_list;
@@ -112,7 +113,7 @@ static void write_object(void *buf, unsigned long size, const char *type)
 }
 
 static int resolve_delta(const char *type,
-       void *base, unsigned long base_size, 
+       void *base, unsigned long base_size,
        void *delta, unsigned long delta_size)
 {
        void *result;
@@ -135,7 +136,7 @@ static void added_object(unsigned char *sha1, const char *type, void *data, unsi
        struct delta_info *info;
 
        while ((info = *p) != NULL) {
-               if (!memcmp(info->base_sha1, sha1, 20)) {
+               if (!hashcmp(info->base_sha1, sha1)) {
                        *p = info->next;
                        p = &delta_list;
                        resolve_delta(type, data, size, info->delta, info->size);
@@ -172,7 +173,7 @@ static int unpack_delta_entry(unsigned long delta_size)
        unsigned char base_sha1[20];
        int result;
 
-       memcpy(base_sha1, fill(20), 20);
+       hashcpy(base_sha1, fill(20));
        use(20);
 
        delta_data = get_data(delta_size);
@@ -260,12 +261,12 @@ static void unpack_all(void)
                die("unresolved deltas left after unpacking");
 }
 
-int main(int argc, char **argv)
+int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
 {
        int i;
        unsigned char sha1[20];
 
-       setup_git_directory();
+       git_config(git_default_config);
 
        quiet = !isatty(2);
 
@@ -291,7 +292,7 @@ int main(int argc, char **argv)
        unpack_all();
        SHA1_Update(&ctx, buffer, offset);
        SHA1_Final(sha1, &ctx);
-       if (memcmp(fill(20), sha1, 20))
+       if (hashcmp(fill(20), sha1))
                die("final sha1 did not match");
        use(20);
 
index d2556f3..0620e77 100644 (file)
@@ -23,7 +23,7 @@ static int allow_replace;
 static int info_only;
 static int force_remove;
 static int verbose;
-static int mark_valid_only = 0;
+static int mark_valid_only;
 #define MARK_VALID 1
 #define UNMARK_VALID 2
 
@@ -142,7 +142,7 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,
        size = cache_entry_size(len);
        ce = xcalloc(1, size);
 
-       memcpy(ce->sha1, sha1, 20);
+       hashcpy(ce->sha1, sha1);
        memcpy(ce->name, path, len);
        ce->ce_flags = create_ce_flags(len, stage);
        ce->ce_mode = create_ce_mode(mode);
@@ -306,7 +306,7 @@ static void read_index_info(int line_termination)
 }
 
 static const char update_index_usage[] =
-"git-update-index [-q] [--add] [--replace] [--remove] [--unmerged] [--refresh] [--really-refresh] [--cacheinfo] [--chmod=(+|-)x] [--assume-unchanged] [--info-only] [--force-remove] [--stdin] [--index-info] [--unresolve] [--again] [--ignore-missing] [-z] [--verbose] [--] <file>...";
+"git-update-index [-q] [--add] [--replace] [--remove] [--unmerged] [--refresh] [--really-refresh] [--cacheinfo] [--chmod=(+|-)x] [--assume-unchanged] [--info-only] [--force-remove] [--stdin] [--index-info] [--unresolve] [--again | -g] [--ignore-missing] [-z] [--verbose] [--] <file>...";
 
 static unsigned char head_sha1[20];
 static unsigned char merge_head_sha1[20];
@@ -333,7 +333,7 @@ static struct cache_entry *read_one_ent(const char *which,
        size = cache_entry_size(namelen);
        ce = xcalloc(1, size);
 
-       memcpy(ce->sha1, sha1, 20);
+       hashcpy(ce->sha1, sha1);
        memcpy(ce->name, path, namelen);
        ce->ce_flags = create_ce_flags(namelen, stage);
        ce->ce_mode = create_ce_mode(mode);
@@ -378,7 +378,7 @@ static int unresolve_one(const char *path)
                ret = -1;
                goto free_return;
        }
-       if (!memcmp(ce_2->sha1, ce_3->sha1, 20) &&
+       if (!hashcmp(ce_2->sha1, ce_3->sha1) &&
            ce_2->ce_mode == ce_3->ce_mode) {
                fprintf(stderr, "%s: identical in both, skipping.\n",
                        path);
@@ -460,7 +460,7 @@ static int do_reupdate(int ac, const char **av,
                        old = read_one_ent(NULL, head_sha1,
                                           ce->name, ce_namelen(ce), 0);
                if (old && ce->ce_mode == old->ce_mode &&
-                   !memcmp(ce->sha1, old->sha1, 20)) {
+                   !hashcmp(ce->sha1, old->sha1)) {
                        free(old);
                        continue; /* unchanged */
                }
@@ -595,7 +595,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
                                        active_cache_changed = 0;
                                goto finish;
                        }
-                       if (!strcmp(path, "--again")) {
+                       if (!strcmp(path, "--again") || !strcmp(path, "-g")) {
                                has_errors = do_reupdate(argc - i, argv + i,
                                                         prefix, prefix_length);
                                if (has_errors)
index 5bd7182..90a3da5 100644 (file)
@@ -44,7 +44,7 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
 
        if (get_sha1(value, sha1))
                die("%s: not a valid SHA1", value);
-       memset(oldsha1, 0, 20);
+       hashclr(oldsha1);
        if (oldval && get_sha1(oldval, oldsha1))
                die("%s: not a valid old SHA1", oldval);
 
similarity index 83%
rename from verify-pack.c
rename to builtin-verify-pack.c
index 357970d..7d39d9b 100644 (file)
@@ -1,3 +1,4 @@
+#include "builtin.h"
 #include "cache.h"
 #include "pack.h"
 
@@ -47,28 +48,28 @@ static int verify_one_pack(const char *path, int verbose)
 
 static const char verify_pack_usage[] = "git-verify-pack [-v] <pack>...";
 
-int main(int ac, char **av)
+int cmd_verify_pack(int argc, const char **argv, const char *prefix)
 {
        int err = 0;
        int verbose = 0;
        int no_more_options = 0;
        int nothing_done = 1;
 
-       while (1 < ac) {
-               if (!no_more_options && av[1][0] == '-') {
-                       if (!strcmp("-v", av[1]))
+       while (1 < argc) {
+               if (!no_more_options && argv[1][0] == '-') {
+                       if (!strcmp("-v", argv[1]))
                                verbose = 1;
-                       else if (!strcmp("--", av[1]))
+                       else if (!strcmp("--", argv[1]))
                                no_more_options = 1;
                        else
                                usage(verify_pack_usage);
                }
                else {
-                       if (verify_one_pack(av[1], verbose))
+                       if (verify_one_pack(argv[1], verbose))
                                err = 1;
                        nothing_done = 0;
                }
-               ac--; av++;
+               argc--; argv++;
        }
 
        if (nothing_done)
index ca06149..50670dc 100644 (file)
@@ -50,10 +50,10 @@ int write_tree(unsigned char *sha1, int missing_ok, const char *prefix)
        if (prefix) {
                struct cache_tree *subtree =
                        cache_tree_find(active_cache_tree, prefix);
-               memcpy(sha1, subtree->sha1, 20);
+               hashcpy(sha1, subtree->sha1);
        }
        else
-               memcpy(sha1, active_cache_tree->sha1, 20);
+               hashcpy(sha1, active_cache_tree->sha1);
 
        rollback_lock_file(lock_file);
 
diff --git a/builtin-zip-tree.c b/builtin-zip-tree.c
new file mode 100644 (file)
index 0000000..a5b834d
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 2006 Rene Scharfe
+ */
+#include <time.h>
+#include "cache.h"
+#include "commit.h"
+#include "blob.h"
+#include "tree.h"
+#include "quote.h"
+#include "builtin.h"
+
+static const char zip_tree_usage[] =
+"git-zip-tree [-0|...|-9] <tree-ish> [ <base> ]";
+
+static int zip_date;
+static int zip_time;
+
+static unsigned char *zip_dir;
+static unsigned int zip_dir_size;
+
+static unsigned int zip_offset;
+static unsigned int zip_dir_offset;
+static unsigned int zip_dir_entries;
+
+#define ZIP_DIRECTORY_MIN_SIZE (1024 * 1024)
+
+struct zip_local_header {
+       unsigned char magic[4];
+       unsigned char version[2];
+       unsigned char flags[2];
+       unsigned char compression_method[2];
+       unsigned char mtime[2];
+       unsigned char mdate[2];
+       unsigned char crc32[4];
+       unsigned char compressed_size[4];
+       unsigned char size[4];
+       unsigned char filename_length[2];
+       unsigned char extra_length[2];
+};
+
+struct zip_dir_header {
+       unsigned char magic[4];
+       unsigned char creator_version[2];
+       unsigned char version[2];
+       unsigned char flags[2];
+       unsigned char compression_method[2];
+       unsigned char mtime[2];
+       unsigned char mdate[2];
+       unsigned char crc32[4];
+       unsigned char compressed_size[4];
+       unsigned char size[4];
+       unsigned char filename_length[2];
+       unsigned char extra_length[2];
+       unsigned char comment_length[2];
+       unsigned char disk[2];
+       unsigned char attr1[2];
+       unsigned char attr2[4];
+       unsigned char offset[4];
+};
+
+struct zip_dir_trailer {
+       unsigned char magic[4];
+       unsigned char disk[2];
+       unsigned char directory_start_disk[2];
+       unsigned char entries_on_this_disk[2];
+       unsigned char entries[2];
+       unsigned char size[4];
+       unsigned char offset[4];
+       unsigned char comment_length[2];
+};
+
+static void copy_le16(unsigned char *dest, unsigned int n)
+{
+       dest[0] = 0xff & n;
+       dest[1] = 0xff & (n >> 010);
+}
+
+static void copy_le32(unsigned char *dest, unsigned int n)
+{
+       dest[0] = 0xff & n;
+       dest[1] = 0xff & (n >> 010);
+       dest[2] = 0xff & (n >> 020);
+       dest[3] = 0xff & (n >> 030);
+}
+
+static void *zlib_deflate(void *data, unsigned long size,
+                          unsigned long *compressed_size)
+{
+       z_stream stream;
+       unsigned long maxsize;
+       void *buffer;
+       int result;
+
+       memset(&stream, 0, sizeof(stream));
+       deflateInit(&stream, zlib_compression_level);
+       maxsize = deflateBound(&stream, size);
+       buffer = xmalloc(maxsize);
+
+       stream.next_in = data;
+       stream.avail_in = size;
+       stream.next_out = buffer;
+       stream.avail_out = maxsize;
+
+       do {
+               result = deflate(&stream, Z_FINISH);
+       } while (result == Z_OK);
+
+       if (result != Z_STREAM_END) {
+               free(buffer);
+               return NULL;
+       }
+
+       deflateEnd(&stream);
+       *compressed_size = stream.total_out;
+
+       return buffer;
+}
+
+static char *construct_path(const char *base, int baselen,
+                            const char *filename, int isdir, int *pathlen)
+{
+       int filenamelen = strlen(filename);
+       int len = baselen + filenamelen;
+       char *path, *p;
+
+       if (isdir)
+               len++;
+       p = path = xmalloc(len + 1);
+
+       memcpy(p, base, baselen);
+       p += baselen;
+       memcpy(p, filename, filenamelen);
+       p += filenamelen;
+       if (isdir)
+               *p++ = '/';
+       *p = '\0';
+
+       *pathlen = len;
+
+       return path;
+}
+
+static int write_zip_entry(const unsigned char *sha1,
+                           const char *base, int baselen,
+                           const char *filename, unsigned mode, int stage)
+{
+       struct zip_local_header header;
+       struct zip_dir_header dirent;
+       unsigned long compressed_size;
+       unsigned long uncompressed_size;
+       unsigned long crc;
+       unsigned long direntsize;
+       unsigned long size;
+       int method;
+       int result = -1;
+       int pathlen;
+       unsigned char *out;
+       char *path;
+       char type[20];
+       void *buffer = NULL;
+       void *deflated = NULL;
+
+       crc = crc32(0, Z_NULL, 0);
+
+       path = construct_path(base, baselen, filename, S_ISDIR(mode), &pathlen);
+       if (pathlen > 0xffff) {
+               error("path too long (%d chars, SHA1: %s): %s", pathlen,
+                     sha1_to_hex(sha1), path);
+               goto out;
+       }
+
+       if (S_ISDIR(mode)) {
+               method = 0;
+               result = READ_TREE_RECURSIVE;
+               out = NULL;
+               uncompressed_size = 0;
+               compressed_size = 0;
+       } else if (S_ISREG(mode)) {
+               method = zlib_compression_level == 0 ? 0 : 8;
+               result = 0;
+               buffer = read_sha1_file(sha1, type, &size);
+               if (!buffer)
+                       die("cannot read %s", sha1_to_hex(sha1));
+               crc = crc32(crc, buffer, size);
+               out = buffer;
+               uncompressed_size = size;
+               compressed_size = size;
+       } else {
+               error("unsupported file mode: 0%o (SHA1: %s)", mode,
+                     sha1_to_hex(sha1));
+               goto out;
+       }
+
+       if (method == 8) {
+               deflated = zlib_deflate(buffer, size, &compressed_size);
+               if (deflated && compressed_size - 6 < size) {
+                       /* ZLIB --> raw compressed data (see RFC 1950) */
+                       /* CMF and FLG ... */
+                       out = (unsigned char *)deflated + 2;
+                       compressed_size -= 6;   /* ... and ADLER32 */
+               } else {
+                       method = 0;
+                       compressed_size = size;
+               }
+       }
+
+       /* make sure we have enough free space in the dictionary */
+       direntsize = sizeof(struct zip_dir_header) + pathlen;
+       while (zip_dir_size < zip_dir_offset + direntsize) {
+               zip_dir_size += ZIP_DIRECTORY_MIN_SIZE;
+               zip_dir = xrealloc(zip_dir, zip_dir_size);
+       }
+
+       copy_le32(dirent.magic, 0x02014b50);
+       copy_le16(dirent.creator_version, 0);
+       copy_le16(dirent.version, 20);
+       copy_le16(dirent.flags, 0);
+       copy_le16(dirent.compression_method, method);
+       copy_le16(dirent.mtime, zip_time);
+       copy_le16(dirent.mdate, zip_date);
+       copy_le32(dirent.crc32, crc);
+       copy_le32(dirent.compressed_size, compressed_size);
+       copy_le32(dirent.size, uncompressed_size);
+       copy_le16(dirent.filename_length, pathlen);
+       copy_le16(dirent.extra_length, 0);
+       copy_le16(dirent.comment_length, 0);
+       copy_le16(dirent.disk, 0);
+       copy_le16(dirent.attr1, 0);
+       copy_le32(dirent.attr2, 0);
+       copy_le32(dirent.offset, zip_offset);
+       memcpy(zip_dir + zip_dir_offset, &dirent, sizeof(struct zip_dir_header));
+       zip_dir_offset += sizeof(struct zip_dir_header);
+       memcpy(zip_dir + zip_dir_offset, path, pathlen);
+       zip_dir_offset += pathlen;
+       zip_dir_entries++;
+
+       copy_le32(header.magic, 0x04034b50);
+       copy_le16(header.version, 20);
+       copy_le16(header.flags, 0);
+       copy_le16(header.compression_method, method);
+       copy_le16(header.mtime, zip_time);
+       copy_le16(header.mdate, zip_date);
+       copy_le32(header.crc32, crc);
+       copy_le32(header.compressed_size, compressed_size);
+       copy_le32(header.size, uncompressed_size);
+       copy_le16(header.filename_length, pathlen);
+       copy_le16(header.extra_length, 0);
+       write_or_die(1, &header, sizeof(struct zip_local_header));
+       zip_offset += sizeof(struct zip_local_header);
+       write_or_die(1, path, pathlen);
+       zip_offset += pathlen;
+       if (compressed_size > 0) {
+               write_or_die(1, out, compressed_size);
+               zip_offset += compressed_size;
+       }
+
+out:
+       free(buffer);
+       free(deflated);
+       free(path);
+
+       return result;
+}
+
+static void write_zip_trailer(const unsigned char *sha1)
+{
+       struct zip_dir_trailer trailer;
+
+       copy_le32(trailer.magic, 0x06054b50);
+       copy_le16(trailer.disk, 0);
+       copy_le16(trailer.directory_start_disk, 0);
+       copy_le16(trailer.entries_on_this_disk, zip_dir_entries);
+       copy_le16(trailer.entries, zip_dir_entries);
+       copy_le32(trailer.size, zip_dir_offset);
+       copy_le32(trailer.offset, zip_offset);
+       copy_le16(trailer.comment_length, sha1 ? 40 : 0);
+
+       write_or_die(1, zip_dir, zip_dir_offset);
+       write_or_die(1, &trailer, sizeof(struct zip_dir_trailer));
+       if (sha1)
+               write_or_die(1, sha1_to_hex(sha1), 40);
+}
+
+static void dos_time(time_t *time, int *dos_date, int *dos_time)
+{
+       struct tm *t = localtime(time);
+
+       *dos_date = t->tm_mday + (t->tm_mon + 1) * 32 +
+                   (t->tm_year + 1900 - 1980) * 512;
+       *dos_time = t->tm_sec / 2 + t->tm_min * 32 + t->tm_hour * 2048;
+}
+
+int cmd_zip_tree(int argc, const char **argv, const char *prefix)
+{
+       unsigned char sha1[20];
+       struct tree *tree;
+       struct commit *commit;
+       time_t archive_time;
+       char *base;
+       int baselen;
+
+       git_config(git_default_config);
+
+       if (argc > 1 && argv[1][0] == '-') {
+               if (isdigit(argv[1][1]) && argv[1][2] == '\0') {
+                       zlib_compression_level = argv[1][1] - '0';
+                       argc--;
+                       argv++;
+               }
+       }
+
+       switch (argc) {
+       case 3:
+               base = strdup(argv[2]);
+               baselen = strlen(base);
+               break;
+       case 2:
+               base = strdup("");
+               baselen = 0;
+               break;
+       default:
+               usage(zip_tree_usage);
+       }
+
+       if (get_sha1(argv[1], sha1))
+               die("Not a valid object name %s", argv[1]);
+
+       commit = lookup_commit_reference_gently(sha1, 1);
+       archive_time = commit ? commit->date : time(NULL);
+       dos_time(&archive_time, &zip_date, &zip_time);
+
+       zip_dir = xmalloc(ZIP_DIRECTORY_MIN_SIZE);
+       zip_dir_size = ZIP_DIRECTORY_MIN_SIZE;
+
+       tree = parse_tree_indirect(sha1);
+       if (!tree)
+               die("not a tree object");
+
+       if (baselen > 0) {
+               write_zip_entry(tree->object.sha1, "", 0, base, 040777, 0);
+               base = xrealloc(base, baselen + 1);
+               base[baselen] = '/';
+               baselen++;
+               base[baselen] = '\0';
+       }
+       read_tree_recursive(tree, base, baselen, 0, NULL, write_zip_entry);
+       write_zip_trailer(commit ? commit->object.sha1 : NULL);
+
+       free(zip_dir);
+       free(base);
+
+       return 0;
+}
index 26ebcaf..25431d7 100644 (file)
--- a/builtin.h
+++ b/builtin.h
@@ -8,57 +8,58 @@ extern const char git_version_string[];
 extern const char git_usage_string[];
 
 extern void help_unknown_cmd(const char *cmd);
+extern int mailinfo(FILE *in, FILE *out, int ks, const char *encoding, const char *msg, const char *patch);
+extern int split_mbox(const char **mbox, const char *dir, int allow_bare, int nr_prec, int skip);
+extern void stripspace(FILE *in, FILE *out);
+extern int write_tree(unsigned char *sha1, int missing_ok, const char *prefix);
 
-extern int cmd_help(int argc, const char **argv, const char *prefix);
-extern int cmd_version(int argc, const char **argv, const char *prefix);
-
-extern int cmd_whatchanged(int argc, const char **argv, const char *prefix);
-extern int cmd_show(int argc, const char **argv, const char *prefix);
-extern int cmd_log(int argc, const char **argv, const char *prefix);
-extern int cmd_diff(int argc, const char **argv, const char *prefix);
-extern int cmd_format_patch(int argc, const char **argv, const char *prefix);
-extern int cmd_count_objects(int argc, const char **argv, const char *prefix);
-
-extern int cmd_prune(int argc, const char **argv, const char *prefix);
-extern int cmd_prune_packed(int argc, const char **argv, const char *prefix);
-
-extern int cmd_push(int argc, const char **argv, const char *prefix);
-extern int cmd_grep(int argc, const char **argv, const char *prefix);
-extern int cmd_rm(int argc, const char **argv, const char *prefix);
 extern int cmd_add(int argc, const char **argv, const char *prefix);
-extern int cmd_rev_list(int argc, const char **argv, const char *prefix);
+extern int cmd_apply(int argc, const char **argv, const char *prefix);
+extern int cmd_cat_file(int argc, const char **argv, const char *prefix);
+extern int cmd_checkout_index(int argc, const char **argv, const char *prefix);
 extern int cmd_check_ref_format(int argc, const char **argv, const char *prefix);
-extern int cmd_init_db(int argc, const char **argv, const char *prefix);
-extern int cmd_tar_tree(int argc, const char **argv, const char *prefix);
-extern int cmd_upload_tar(int argc, const char **argv, const char *prefix);
-extern int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix);
-extern int cmd_ls_files(int argc, const char **argv, const char *prefix);
-extern int cmd_ls_tree(int argc, const char **argv, const char *prefix);
-extern int cmd_read_tree(int argc, const char **argv, const char *prefix);
 extern int cmd_commit_tree(int argc, const char **argv, const char *prefix);
-extern int cmd_apply(int argc, const char **argv, const char *prefix);
-extern int cmd_show_branch(int argc, const char **argv, const char *prefix);
+extern int cmd_count_objects(int argc, const char **argv, const char *prefix);
 extern int cmd_diff_files(int argc, const char **argv, const char *prefix);
 extern int cmd_diff_index(int argc, const char **argv, const char *prefix);
+extern int cmd_diff(int argc, const char **argv, const char *prefix);
 extern int cmd_diff_stages(int argc, const char **argv, const char *prefix);
 extern int cmd_diff_tree(int argc, const char **argv, const char *prefix);
-extern int cmd_cat_file(int argc, const char **argv, const char *prefix);
-extern int cmd_rev_parse(int argc, const char **argv, const char *prefix);
-extern int cmd_update_index(int argc, const char **argv, const char *prefix);
-extern int cmd_update_ref(int argc, const char **argv, const char *prefix);
 extern int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix);
+extern int cmd_format_patch(int argc, const char **argv, const char *prefix);
+extern int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix);
+extern int cmd_grep(int argc, const char **argv, const char *prefix);
+extern int cmd_help(int argc, const char **argv, const char *prefix);
+extern int cmd_init_db(int argc, const char **argv, const char *prefix);
+extern int cmd_log(int argc, const char **argv, const char *prefix);
+extern int cmd_ls_files(int argc, const char **argv, const char *prefix);
+extern int cmd_ls_tree(int argc, const char **argv, const char *prefix);
+extern int cmd_mailinfo(int argc, const char **argv, const char *prefix);
+extern int cmd_mailsplit(int argc, const char **argv, const char *prefix);
 extern int cmd_mv(int argc, const char **argv, const char *prefix);
+extern int cmd_name_rev(int argc, const char **argv, const char *prefix);
+extern int cmd_pack_objects(int argc, const char **argv, const char *prefix);
+extern int cmd_prune(int argc, const char **argv, const char *prefix);
+extern int cmd_prune_packed(int argc, const char **argv, const char *prefix);
+extern int cmd_push(int argc, const char **argv, const char *prefix);
+extern int cmd_read_tree(int argc, const char **argv, const char *prefix);
 extern int cmd_repo_config(int argc, const char **argv, const char *prefix);
-
+extern int cmd_rev_list(int argc, const char **argv, const char *prefix);
+extern int cmd_rev_parse(int argc, const char **argv, const char *prefix);
+extern int cmd_rm(int argc, const char **argv, const char *prefix);
+extern int cmd_show_branch(int argc, const char **argv, const char *prefix);
+extern int cmd_show(int argc, const char **argv, const char *prefix);
+extern int cmd_stripspace(int argc, const char **argv, const char *prefix);
+extern int cmd_symbolic_ref(int argc, const char **argv, const char *prefix);
+extern int cmd_tar_tree(int argc, const char **argv, const char *prefix);
+extern int cmd_zip_tree(int argc, const char **argv, const char *prefix);
+extern int cmd_unpack_objects(int argc, const char **argv, const char *prefix);
+extern int cmd_update_index(int argc, const char **argv, const char *prefix);
+extern int cmd_update_ref(int argc, const char **argv, const char *prefix);
+extern int cmd_upload_tar(int argc, const char **argv, const char *prefix);
+extern int cmd_version(int argc, const char **argv, const char *prefix);
+extern int cmd_whatchanged(int argc, const char **argv, const char *prefix);
 extern int cmd_write_tree(int argc, const char **argv, const char *prefix);
-extern int write_tree(unsigned char *sha1, int missing_ok, const char *prefix);
+extern int cmd_verify_pack(int argc, const char **argv, const char *prefix);
 
-extern int cmd_mailsplit(int argc, const char **argv, const char *prefix);
-extern int split_mbox(const char **mbox, const char *dir, int allow_bare, int nr_prec, int skip);
-
-extern int cmd_mailinfo(int argc, const char **argv, const char *prefix);
-extern int mailinfo(FILE *in, FILE *out, int ks, const char *encoding, const char *msg, const char *patch);
-
-extern int cmd_stripspace(int argc, const char **argv, const char *prefix);
-extern void stripspace(FILE *in, FILE *out);
 #endif
index d9f7e1e..323c68a 100644 (file)
@@ -335,7 +335,7 @@ static int update_one(struct cache_tree *it,
                offset += sprintf(buffer + offset,
                                  "%o %.*s", mode, entlen, path + baselen);
                buffer[offset++] = 0;
-               memcpy(buffer + offset, sha1, 20);
+               hashcpy((unsigned char*)buffer + offset, sha1);
                offset += 20;
 
 #if DEBUG
@@ -412,7 +412,7 @@ static void *write_one(struct cache_tree *it,
 #endif
 
        if (0 <= it->entry_count) {
-               memcpy(buffer + *offset, it->sha1, 20);
+               hashcpy((unsigned char*)buffer + *offset, it->sha1);
                *offset += 20;
        }
        for (i = 0; i < it->subtree_nr; i++) {
@@ -478,7 +478,7 @@ static struct cache_tree *read_one(const char **buffer, unsigned long *size_p)
        if (0 <= it->entry_count) {
                if (size < 20)
                        goto free_return;
-               memcpy(it->sha1, buf, 20);
+               hashcpy(it->sha1, (unsigned char*)buf);
                buf += 20;
                size -= 20;
        }
diff --git a/cache.h b/cache.h
index 9f90df4..03d9dd0 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -123,7 +123,7 @@ extern int cache_errno;
 #define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
 #define GRAFT_ENVIRONMENT "GIT_GRAFT_FILE"
 
-extern char *get_git_dir(void);
+extern const char *get_git_dir(void);
 extern char *get_object_directory(void);
 extern char *get_refs_directory(void);
 extern char *get_index_file(void);
@@ -211,6 +211,22 @@ extern char *sha1_pack_name(const unsigned char *sha1);
 extern char *sha1_pack_index_name(const unsigned char *sha1);
 extern const char *find_unique_abbrev(const unsigned char *sha1, int);
 extern const unsigned char null_sha1[20];
+static inline int is_null_sha1(const unsigned char *sha1)
+{
+       return !memcmp(sha1, null_sha1, 20);
+}
+static inline int hashcmp(const unsigned char *sha1, const unsigned char *sha2)
+{
+       return memcmp(sha1, sha2, 20);
+}
+static inline void hashcpy(unsigned char *sha_dst, const unsigned char *sha_src)
+{
+       memcpy(sha_dst, sha_src, 20);
+}
+static inline void hashclr(unsigned char *hash)
+{
+       memset(hash, 0, 20);
+}
 
 int git_mkstemp(char *path, size_t n, const char *template);
 
@@ -245,6 +261,8 @@ extern int move_temp_to_file(const char *tmpfile, char *filename);
 
 extern int has_sha1_pack(const unsigned char *sha1);
 extern int has_sha1_file(const unsigned char *sha1);
+extern void *map_sha1_file(const unsigned char *sha1, unsigned long *);
+extern int legacy_loose_object(unsigned char *);
 
 extern int has_pack_file(const unsigned char *sha1);
 extern int has_pack_index(const unsigned char *sha1);
@@ -269,7 +287,7 @@ extern void *read_object_with_reference(const unsigned char *sha1,
                                        unsigned long *size,
                                        unsigned char *sha1_ret);
 
-const char *show_date(unsigned long time, int timezone);
+const char *show_date(unsigned long time, int timezone, int relative);
 const char *show_rfc2822_date(unsigned long time, int timezone);
 int parse_date(const char *date, char *buf, int bufsize);
 void datestamp(char *buf, int bufsize);
@@ -379,6 +397,7 @@ extern char git_default_name[MAX_GITNAME];
 extern char git_commit_encoding[MAX_ENCODING_LENGTH];
 
 extern int copy_fd(int ifd, int ofd);
+extern void write_or_die(int fd, const void *buf, size_t count);
 
 /* Finish off pack transfer receiving end */
 extern int receive_unpack_pack(int fd[2], const char *me, int quiet, int);
diff --git a/check-racy.c b/check-racy.c
new file mode 100644 (file)
index 0000000..d6a08b4
--- /dev/null
@@ -0,0 +1,28 @@
+#include "cache.h"
+
+int main(int ac, char **av)
+{
+       int i;
+       int dirty, clean, racy;
+
+       dirty = clean = racy = 0;
+       read_cache();
+       for (i = 0; i < active_nr; i++) {
+               struct cache_entry *ce = active_cache[i];
+               struct stat st;
+
+               if (lstat(ce->name, &st)) {
+                       error("lstat(%s): %s", ce->name, strerror(errno));
+                       continue;
+               }
+
+               if (ce_match_stat(ce, &st, 0))
+                       dirty++;
+               else if (ce_match_stat(ce, &st, 2))
+                       racy++;
+               else
+                       clean++;
+       }
+       printf("dirty %d, clean %d, racy %d\n", dirty, clean, racy);
+       return 0;
+}
index ba8baca..46d9121 100644 (file)
@@ -7,13 +7,6 @@
 #include "xdiff-interface.h"
 #include "log-tree.h"
 
-static int uninteresting(struct diff_filepair *p)
-{
-       if (diff_unmodified_pair(p))
-               return 1;
-       return 0;
-}
-
 static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr, int n, int num_parent)
 {
        struct diff_queue_struct *q = &diff_queued_diff;
@@ -25,7 +18,7 @@ static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr,
                for (i = 0; i < q->nr; i++) {
                        int len;
                        const char *path;
-                       if (uninteresting(q->queue[i]))
+                       if (diff_unmodified_pair(q->queue[i]))
                                continue;
                        path = q->queue[i]->two->path;
                        len = strlen(path);
@@ -38,9 +31,9 @@ static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr,
                        memset(p->parent, 0,
                               sizeof(p->parent[0]) * num_parent);
 
-                       memcpy(p->sha1, q->queue[i]->two->sha1, 20);
+                       hashcpy(p->sha1, q->queue[i]->two->sha1);
                        p->mode = q->queue[i]->two->mode;
-                       memcpy(p->parent[n].sha1, q->queue[i]->one->sha1, 20);
+                       hashcpy(p->parent[n].sha1, q->queue[i]->one->sha1);
                        p->parent[n].mode = q->queue[i]->one->mode;
                        p->parent[n].status = q->queue[i]->status;
                        *tail = p;
@@ -57,14 +50,13 @@ static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr,
                        const char *path;
                        int len;
 
-                       if (uninteresting(q->queue[i]))
+                       if (diff_unmodified_pair(q->queue[i]))
                                continue;
                        path = q->queue[i]->two->path;
                        len = strlen(path);
                        if (len == p->len && !memcmp(path, p->path, len)) {
                                found = 1;
-                               memcpy(p->parent[n].sha1,
-                                      q->queue[i]->one->sha1, 20);
+                               hashcpy(p->parent[n].sha1, q->queue[i]->one->sha1);
                                p->parent[n].mode = q->queue[i]->one->mode;
                                p->parent[n].status = q->queue[i]->status;
                                break;
@@ -101,7 +93,7 @@ static char *grab_blob(const unsigned char *sha1, unsigned long *size)
 {
        char *blob;
        char type[20];
-       if (!memcmp(sha1, null_sha1, 20)) {
+       if (is_null_sha1(sha1)) {
                /* deleted blob */
                *size = 0;
                return xcalloc(1, 1);
@@ -609,16 +601,16 @@ static void dump_quoted_path(const char *prefix, const char *path,
        printf("%s\n", c_reset);
 }
 
-static int show_patch_diff(struct combine_diff_path *elem, int num_parent,
-                          int dense, struct rev_info *rev)
+static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
+                           int dense, struct rev_info *rev)
 {
        struct diff_options *opt = &rev->diffopt;
        unsigned long result_size, cnt, lno;
        char *result, *cp;
        struct sline *sline; /* survived lines */
        int mode_differs = 0;
-       int i, show_hunks, shown_header = 0;
-       int working_tree_file = !memcmp(elem->sha1, null_sha1, 20);
+       int i, show_hunks;
+       int working_tree_file = is_null_sha1(elem->sha1);
        int abbrev = opt->full_index ? 40 : DEFAULT_ABBREV;
        mmfile_t result_file;
 
@@ -695,8 +687,8 @@ static int show_patch_diff(struct combine_diff_path *elem, int num_parent,
        for (i = 0; i < num_parent; i++) {
                int j;
                for (j = 0; j < i; j++) {
-                       if (!memcmp(elem->parent[i].sha1,
-                                   elem->parent[j].sha1, 20)) {
+                       if (!hashcmp(elem->parent[i].sha1,
+                                    elem->parent[j].sha1)) {
                                reuse_combine_diff(sline, cnt, i, j);
                                break;
                        }
@@ -769,7 +761,6 @@ static int show_patch_diff(struct combine_diff_path *elem, int num_parent,
        }
        free(sline[0].p_lno);
        free(sline);
-       return shown_header;
 }
 
 #define COLONS "::::::::::::::::::::::::::::::::"
@@ -837,11 +828,10 @@ void show_combined_diff(struct combine_diff_path *p,
                return;
        if (opt->output_format & (DIFF_FORMAT_RAW |
                                  DIFF_FORMAT_NAME |
-                                 DIFF_FORMAT_NAME_STATUS)) {
+                                 DIFF_FORMAT_NAME_STATUS))
                show_raw_diff(p, num_parent, rev);
-       } else if (opt->output_format & DIFF_FORMAT_PATCH) {
+       else if (opt->output_format & DIFF_FORMAT_PATCH)
                show_patch_diff(p, num_parent, dense, rev);
-       }
 }
 
 void diff_tree_combined(const unsigned char *sha1,
@@ -936,6 +926,7 @@ void diff_tree_combined_merge(const unsigned char *sha1,
        for (parents = commit->parents, num_parent = 0;
             parents;
             parents = parents->next, num_parent++)
-               memcpy(parent + num_parent, parents->item->object.sha1, 20);
+               hashcpy((unsigned char*)(parent + num_parent),
+                       parents->item->object.sha1);
        diff_tree_combined(sha1, parent, num_parent, dense, rev);
 }
index 77f0ca1..c3ff9b4 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -7,15 +7,15 @@ int save_commit_buffer = 1;
 struct sort_node
 {
        /*
-         * the number of children of the associated commit
-         * that also occur in the list being sorted.
-         */
+        * the number of children of the associated commit
+        * that also occur in the list being sorted.
+        */
        unsigned int indegree;
 
        /*
-         * reference to original list item that we will re-use
-         * on output.
-         */
+        * reference to original list item that we will re-use
+        * on output.
+        */
        struct commit_list * list_item;
 
 };
@@ -123,7 +123,7 @@ static int commit_graft_pos(const unsigned char *sha1)
        while (lo < hi) {
                int mi = (lo + hi) / 2;
                struct commit_graft *graft = commit_graft[mi];
-               int cmp = memcmp(sha1, graft->sha1, 20);
+               int cmp = hashcmp(sha1, graft->sha1);
                if (!cmp)
                        return mi;
                if (cmp < 0)
@@ -507,14 +507,14 @@ static int add_user_info(const char *what, enum cmit_fmt fmt, char *buf, const c
        }
        switch (fmt) {
        case CMIT_FMT_MEDIUM:
-               ret += sprintf(buf + ret, "Date:   %s\n", show_date(time, tz));
+               ret += sprintf(buf + ret, "Date:   %s\n", show_date(time, tz, 0));
                break;
        case CMIT_FMT_EMAIL:
                ret += sprintf(buf + ret, "Date: %s\n",
                               show_rfc2822_date(time, tz));
                break;
        case CMIT_FMT_FULLER:
-               ret += sprintf(buf + ret, "%sDate: %s\n", what, show_date(time, tz));
+               ret += sprintf(buf + ret, "%sDate: %s\n", what, show_date(time, tz, 0));
                break;
        default:
                /* notin' */
@@ -727,10 +727,10 @@ struct commit *pop_commit(struct commit_list **stack)
 
 int count_parents(struct commit * commit)
 {
-        int count = 0;
+        int count;
         struct commit_list * parents = commit->parents;
-        for (count=0;parents; parents=parents->next,count++)
-          ;
+        for (count = 0; parents; parents = parents->next,count++)
+               ;
         return count;
 }
 
index 04f508a..369e611 100644 (file)
@@ -22,3 +22,19 @@ VPATH = @srcdir@
 export exec_prefix mandir
 export srcdir VPATH
 
+NO_PYTHON=@NO_PYTHON@
+NEEDS_SSL_WITH_CRYPTO=@NEEDS_SSL_WITH_CRYPTO@
+NO_OPENSSL=@NO_OPENSSL@
+NO_CURL=@NO_CURL@
+NO_EXPAT=@NO_EXPAT@
+NEEDS_LIBICONV=@NEEDS_LIBICONV@
+NEEDS_SOCKET=@NEEDS_SOCKET@
+NO_D_INO_IN_DIRENT=@NO_D_INO_IN_DIRENT@
+NO_D_TYPE_IN_DIRENT=@NO_D_TYPE_IN_DIRENT@
+NO_SOCKADDR_STORAGE=@NO_SOCKADDR_STORAGE@
+NO_IPV6=@NO_IPV6@
+NO_C99_FORMAT=@NO_C99_FORMAT@
+NO_STRCASESTR=@NO_STRCASESTR@
+NO_STRLCPY=@NO_STRLCPY@
+NO_SETENV=@NO_SETENV@
+
index a9c88c6..36f9cd9 100644 (file)
@@ -2,7 +2,7 @@
 # Process this file with autoconf to produce a configure script.
 
 AC_PREREQ(2.59)
-AC_INIT([git], [1.4.2], [git@vger.kernel.org])
+AC_INIT([git], [@@GIT_VERSION@@], [git@vger.kernel.org])
 
 AC_CONFIG_SRCDIR([git.c])
 
@@ -19,6 +19,77 @@ echo "# ${config_append}.  Generated by configure." > "${config_append}"
 # Append LINE to file ${config_append}
 AC_DEFUN([GIT_CONF_APPEND_LINE],
 [echo "$1" >> "${config_append}"])# GIT_CONF_APPEND_LINE
+#
+# GIT_ARG_SET_PATH(PROGRAM)
+# -------------------------
+# Provide --with-PROGRAM=PATH option to set PATH to PROGRAM
+AC_DEFUN([GIT_ARG_SET_PATH],
+[AC_ARG_WITH([$1],
+ [AS_HELP_STRING([--with-$1=PATH],
+                 [provide PATH to $1])],
+ [GIT_CONF_APPEND_PATH($1)],[])
+])# GIT_ARG_SET_PATH
+#
+# GIT_CONF_APPEND_PATH(PROGRAM)
+# ------------------------------
+# Parse --with-PROGRAM=PATH option to set PROGRAM_PATH=PATH
+# Used by GIT_ARG_SET_PATH(PROGRAM)
+AC_DEFUN([GIT_CONF_APPEND_PATH],
+[PROGRAM=m4_toupper($1); \
+if test "$withval" = "no"; then \
+       AC_MSG_ERROR([You cannot use git without $1]); \
+else \
+       if test "$withval" = "yes"; then \
+               AC_MSG_WARN([You should provide path for --with-$1=PATH]); \
+       else \
+               GIT_CONF_APPEND_LINE(${PROGRAM}_PATH=$withval); \
+       fi; \
+fi; \
+]) # GIT_CONF_APPEND_PATH
+#
+# GIT_PARSE_WITH(PACKAGE)
+# -----------------------
+# For use in AC_ARG_WITH action-if-found, for packages default ON.
+# * Set NO_PACKAGE=YesPlease for --without-PACKAGE
+# * Set PACKAGEDIR=PATH for --with-PACKAGE=PATH
+# * Unset NO_PACKAGE for --with-PACKAGE without ARG
+AC_DEFUN([GIT_PARSE_WITH],
+[PACKAGE=m4_toupper($1); \
+if test "$withval" = "no"; then \
+       m4_toupper(NO_$1)=YesPlease; \
+elif test "$withval" = "yes"; then \
+       m4_toupper(NO_$1)=; \
+else \
+       m4_toupper(NO_$1)=; \
+       GIT_CONF_APPEND_LINE(${PACKAGE}DIR=$withval); \
+fi \
+])# GIT_PARSE_WITH
+
+
+## Site configuration related to programs (before tests)
+## --with-PACKAGE[=ARG] and --without-PACKAGE
+#
+# Define SHELL_PATH to provide path to shell.
+GIT_ARG_SET_PATH(shell)
+#
+# Define PERL_PATH to provide path to Perl.
+GIT_ARG_SET_PATH(perl)
+#
+# Define NO_PYTHON if you want to lose all benefits of the recursive merge.
+# Define PYTHON_PATH to provide path to Python.
+AC_ARG_WITH(python,[AS_HELP_STRING([--with-python=PATH], [provide PATH to python])
+AS_HELP_STRING([--without-python], [don't use python scripts])],
+ [if test "$withval" = "no"; then \
+    NO_PYTHON=YesPlease; \
+  elif test "$withval" = "yes"; then \
+    NO_PYTHON=; \
+  else \
+    NO_PYTHON=; \
+    PYTHON_PATH=$withval; \
+  fi; \
+ ])
+AC_SUBST(NO_PYTHON)
+AC_SUBST(PYTHON_PATH)
 
 
 ## Checks for programs.
@@ -30,6 +101,16 @@ AC_CHECK_TOOL(AR, ar, :)
 AC_CHECK_PROGS(TAR, [gtar tar])
 #
 # Define NO_PYTHON if you want to lose all benefits of the recursive merge.
+# Define PYTHON_PATH to provide path to Python.
+if test -z "$NO_PYTHON"; then
+       if test -z "$PYTHON_PATH"; then
+               AC_PATH_PROGS(PYTHON_PATH, [python python2.4 python2.3 python2])
+       fi
+       if test -n "$PYTHON_PATH"; then
+               GIT_CONF_APPEND_LINE([PYTHON_PATH=@PYTHON_PATH@])
+               NO_PYTHON=""
+       fi
+fi
 
 
 ## Checks for libraries.
@@ -37,32 +118,43 @@ AC_MSG_NOTICE([CHECKS for libraries])
 #
 # Define NO_OPENSSL environment variable if you do not have OpenSSL.
 # Define NEEDS_SSL_WITH_CRYPTO if you need -lcrypto with -lssl (Darwin).
-AC_CHECK_LIB([ssl], [SHA1_Init],[],
-[AC_CHECK_LIB([crypto], [SHA1_INIT],
- [GIT_CONF_APPEND_LINE(NEEDS_SSL_WITH_CRYPTO=YesPlease)],
- [GIT_CONF_APPEND_LINE(NO_OPENSSL=YesPlease)])])
+AC_CHECK_LIB([crypto], [SHA1_Init],
+[NEEDS_SSL_WITH_CRYPTO=],
+[AC_CHECK_LIB([ssl], [SHA1_Init],
+ [NEEDS_SSL_WITH_CRYPTO=YesPlease
+  NEEDS_SSL_WITH_CRYPTO=],
+ [NO_OPENSSL=YesPlease])])
+AC_SUBST(NEEDS_SSL_WITH_CRYPTO)
+AC_SUBST(NO_OPENSSL)
 #
 # Define NO_CURL if you do not have curl installed.  git-http-pull and
 # git-http-push are not built, and you cannot use http:// and https://
 # transports.
-AC_CHECK_LIB([curl], [curl_global_init],[],
-[GIT_CONF_APPEND_LINE(NO_CURL=YesPlease)])
+AC_CHECK_LIB([curl], [curl_global_init],
+[NO_CURL=],
+[NO_CURL=YesPlease])
+AC_SUBST(NO_CURL)
 #
 # Define NO_EXPAT if you do not have expat installed.  git-http-push is
 # not built, and you cannot push using http:// and https:// transports.
-AC_CHECK_LIB([expat], [XML_ParserCreate],[],
-[GIT_CONF_APPEND_LINE(NO_EXPAT=YesPlease)])
+AC_CHECK_LIB([expat], [XML_ParserCreate],
+[NO_EXPAT=],
+[NO_EXPAT=YesPlease])
+AC_SUBST(NO_EXPAT)
 #
 # Define NEEDS_LIBICONV if linking with libc is not enough (Darwin).
-AC_CHECK_LIB([c], [iconv],[],
-[AC_CHECK_LIB([iconv],[iconv],
- [GIT_CONF_APPEND_LINE(NEEDS_LIBICONV=YesPlease)],[])])
+AC_CHECK_LIB([c], [iconv],
+[NEEDS_LIBICONV=],
+[NEEDS_LIBICONV=YesPlease])
+AC_SUBST(NEEDS_LIBICONV)
 #
 # Define NEEDS_SOCKET if linking with libc is not enough (SunOS,
 # Patrick Mauritz).
-AC_CHECK_LIB([c], [socket],[],
-[AC_CHECK_LIB([socket],[socket],
- [GIT_CONF_APPEND_LINE(NEEDS_SOCKET=YesPlease)],[])])
+AC_CHECK_LIB([c], [socket],
+[NEEDS_SOCKET=],
+[NEEDS_SOCKET=YesPlease])
+AC_SUBST(NEEDS_SOCKET)
+test -n "$NEEDS_SOCKET" && LIBS="$LIBS -lsocket"
 
 
 ## Checks for header files.
@@ -72,21 +164,65 @@ AC_CHECK_LIB([c], [socket],[],
 AC_MSG_NOTICE([CHECKS for typedefs, structures, and compiler characteristics])
 #
 # Define NO_D_INO_IN_DIRENT if you don't have d_ino in your struct dirent.
-AC_CHECK_MEMBER(struct dirent.d_ino,[],
-[GIT_CONF_APPEND_LINE(NO_D_INO_IN_DIRENT=YesPlease)],
+AC_CHECK_MEMBER(struct dirent.d_ino,
+[NO_D_INO_IN_DIRENT=],
+[NO_D_INO_IN_DIRENT=YesPlease],
 [#include <dirent.h>])
+AC_SUBST(NO_D_INO_IN_DIRENT)
 #
 # Define NO_D_TYPE_IN_DIRENT if your platform defines DT_UNKNOWN but lacks
 # d_type in struct dirent (latest Cygwin -- will be fixed soonish).
-AC_CHECK_MEMBER(struct dirent.d_type,[],
-[GIT_CONF_APPEND_LINE(NO_D_TYPE_IN_DIRENT=YesPlease)],
+AC_CHECK_MEMBER(struct dirent.d_type,
+[NO_D_TYPE_IN_DIRENT=],
+[NO_D_TYPE_IN_DIRENT=YesPlease],
 [#include <dirent.h>])
+AC_SUBST(NO_D_TYPE_IN_DIRENT)
 #
 # Define NO_SOCKADDR_STORAGE if your platform does not have struct
 # sockaddr_storage.
-AC_CHECK_TYPE(struct sockaddr_storage,[],
-[GIT_CONF_APPEND_LINE(NO_SOCKADDR_STORAGE=YesPlease)],
-[#include <netinet/in.h>])
+AC_CHECK_TYPE(struct sockaddr_storage,
+[NO_SOCKADDR_STORAGE=],
+[NO_SOCKADDR_STORAGE=YesPlease],[
+#include <sys/types.h>
+#include <sys/socket.h>
+])
+AC_SUBST(NO_SOCKADDR_STORAGE)
+#
+# Define NO_IPV6 if you lack IPv6 support and getaddrinfo().
+AC_CHECK_TYPE([struct addrinfo],[
+ AC_CHECK_FUNC([getaddrinfo],
+  [NO_IPV6=],
+  [NO_IPV6=YesPlease])
+],[NO_IPV6=YesPlease],[
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+])
+AC_SUBST(NO_IPV6)
+#
+# Define NO_C99_FORMAT if your formatted IO functions (printf/scanf et.al.)
+# do not support the 'size specifiers' introduced by C99, namely ll, hh,
+# j, z, t. (representing long long int, char, intmax_t, size_t, ptrdiff_t).
+# some C compilers supported these specifiers prior to C99 as an extension.
+AC_CACHE_CHECK(whether formatted IO functions support C99 size specifiers,
+ ac_cv_c_c99_format,
+[# Actually git uses only %z (%zu) in alloc.c, and %t (%td) in mktag.c
+AC_RUN_IFELSE(
+       [AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT],
+               [[char buf[64];
+               if (sprintf(buf, "%lld%hhd%jd%zd%td", (long long int)1, (char)2, (intmax_t)3, (size_t)4, (ptrdiff_t)5) != 5)
+                 exit(1);
+               else if (strcmp(buf, "12345"))
+                 exit(2);]])],
+       [ac_cv_c_c99_format=yes],
+       [ac_cv_c_c99_format=no])
+])
+if test $ac_cv_c_c99_format = no; then
+       NO_C99_FORMAT=YesPlease
+else
+       NO_C99_FORMAT=
+fi
+AC_SUBST(NO_C99_FORMAT)
 
 
 ## Checks for library functions.
@@ -94,21 +230,25 @@ AC_CHECK_TYPE(struct sockaddr_storage,[],
 AC_MSG_NOTICE([CHECKS for library functions])
 #
 # Define NO_STRCASESTR if you don't have strcasestr.
-AC_CHECK_FUNC(strcasestr,[],
-[GIT_CONF_APPEND_LINE(NO_STRCASESTR=YesPlease)])
+AC_CHECK_FUNC(strcasestr,
+[NO_STRCASESTR=],
+[NO_STRCASESTR=YesPlease])
+AC_SUBST(NO_STRCASESTR)
 #
 # Define NO_STRLCPY if you don't have strlcpy.
-AC_CHECK_FUNC(strlcpy,[],
-[GIT_CONF_APPEND_LINE(NO_STRLCPY=YesPlease)])
+AC_CHECK_FUNC(strlcpy,
+[NO_STRLCPY=],
+[NO_STRLCPY=YesPlease])
+AC_SUBST(NO_STRLCPY)
 #
 # Define NO_SETENV if you don't have setenv in the C library.
-AC_CHECK_FUNC(setenv,[],
-[GIT_CONF_APPEND_LINE(NO_SETENV=YesPlease)])
+AC_CHECK_FUNC(setenv,
+[NO_SETENV=],
+[NO_SETENV=YesPlease])
+AC_SUBST(NO_SETENV)
 #
 # Define NO_MMAP if you want to avoid mmap.
 #
-# Define NO_IPV6 if you lack IPv6 support and getaddrinfo().
-#
 # Define NO_ICONV if your libc does not properly support iconv.
 
 
@@ -125,9 +265,11 @@ AC_CHECK_FUNC(setenv,[],
 # a missing newline at the end of the file.
 
 
-## Site configuration
+## Site configuration (override autodetection)
 ## --with-PACKAGE[=ARG] and --without-PACKAGE
-# Define NO_SVN_TESTS if you want to skip time-consuming SVN interopability
+AC_MSG_NOTICE([CHECKS for site configuration])
+#
+# Define NO_SVN_TESTS if you want to skip time-consuming SVN interoperability
 # tests.  These tests take up a significant amount of the total test time
 # but are not needed unless you plan to talk to SVN repos.
 #
@@ -145,21 +287,51 @@ AC_CHECK_FUNC(setenv,[],
 # Define NO_OPENSSL environment variable if you do not have OpenSSL.
 # This also implies MOZILLA_SHA1.
 #
+# Define OPENSSLDIR=/foo/bar if your openssl header and library files are in
+# /foo/bar/include and /foo/bar/lib directories.
+AC_ARG_WITH(openssl,
+AS_HELP_STRING([--with-openssl],[use OpenSSL library (default is YES)])
+AS_HELP_STRING([],              [ARG can be prefix for openssl library and headers]),\
+GIT_PARSE_WITH(openssl))
+#
 # Define NO_CURL if you do not have curl installed.  git-http-pull and
 # git-http-push are not built, and you cannot use http:// and https://
 # transports.
 #
 # Define CURLDIR=/foo/bar if your curl header and library files are in
 # /foo/bar/include and /foo/bar/lib directories.
+AC_ARG_WITH(curl,
+AS_HELP_STRING([--with-curl],[support http(s):// transports (default is YES)])
+AS_HELP_STRING([],           [ARG can be also prefix for curl library and headers]),
+GIT_PARSE_WITH(curl))
 #
 # Define NO_EXPAT if you do not have expat installed.  git-http-push is
 # not built, and you cannot push using http:// and https:// transports.
 #
-# Define NO_MMAP if you want to avoid mmap.
+# Define EXPATDIR=/foo/bar if your expat header and library files are in
+# /foo/bar/include and /foo/bar/lib directories.
+AC_ARG_WITH(expat,
+AS_HELP_STRING([--with-expat],
+[support git-push using http:// and https:// transports via WebDAV (default is YES)])
+AS_HELP_STRING([],            [ARG can be also prefix for expat library and headers]),
+GIT_PARSE_WITH(expat))
+#
+# Define NO_FINK if you are building on Darwin/Mac OS X, have Fink
+# installed in /sw, but don't want GIT to link against any libraries
+# installed there.  If defined you may specify your own (or Fink's)
+# include directories and library directories by defining CFLAGS
+# and LDFLAGS appropriately.
 #
-# Define NO_PYTHON if you want to loose all benefits of the recursive merge.
+# Define NO_DARWIN_PORTS if you are building on Darwin/Mac OS X,
+# have DarwinPorts installed in /opt/local, but don't want GIT to
+# link against any libraries installed there.  If defined you may
+# specify your own (or DarwinPort's) include directories and
+# library directories by defining CFLAGS and LDFLAGS appropriately.
 #
+# Define NO_MMAP if you want to avoid mmap.
+
 ## --enable-FEATURE[=ARG] and --disable-FEATURE
+#
 # Define COLLISION_CHECK below if you believe that SHA1's
 # 1461501637330902918203684832716283019655932542976 hashes do not give you
 # sufficient guarantee that no collisions between objects will ever happen.
index 4422a0d..e501ccc 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -10,7 +10,7 @@
 #include <netdb.h>
 #include <signal.h>
 
-static char *server_capabilities = NULL;
+static char *server_capabilities;
 
 static int check_ref(const char *name, int len, unsigned int flags)
 {
@@ -77,7 +77,7 @@ struct ref **get_remote_heads(int in, struct ref **list,
                if (nr_match && !path_match(name, nr_match, match))
                        continue;
                ref = xcalloc(1, sizeof(*ref) + len - 40);
-               memcpy(ref->old_sha1, old_sha1, 20);
+               hashcpy(ref->old_sha1, old_sha1);
                memcpy(ref->name, buffer + 41, len - 40);
                *list = ref;
                list = &ref->next;
@@ -208,7 +208,7 @@ static struct ref *try_explicit_object_name(const char *name)
        len = strlen(name) + 1;
        ref = xcalloc(1, sizeof(*ref) + len);
        memcpy(ref->name, name, len);
-       memcpy(ref->new_sha1, sha1, 20);
+       hashcpy(ref->new_sha1, sha1);
        return ref;
 }
 
@@ -318,7 +318,7 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
                        int len = strlen(src->name) + 1;
                        dst_peer = xcalloc(1, sizeof(*dst_peer) + len);
                        memcpy(dst_peer->name, src->name, len);
-                       memcpy(dst_peer->new_sha1, src->new_sha1, 20);
+                       hashcpy(dst_peer->new_sha1, src->new_sha1);
                        link_dst_tail(dst_peer, dst_tail);
                }
                dst_peer->peer_ref = src;
@@ -493,8 +493,8 @@ static void git_tcp_connect(int fd[2], char *host)
 }
 
 
-static char *git_proxy_command = NULL;
-static const char *rhost_name = NULL;
+static char *git_proxy_command;
+static const char *rhost_name;
 static int rhost_len;
 
 static int git_proxy_command_options(const char *var, const char *value)
@@ -737,14 +737,9 @@ int git_connect(int fd[2], char *url, const char *prog)
 
 int finish_connect(pid_t pid)
 {
-       int ret;
-
-       for (;;) {
-               ret = waitpid(pid, NULL, 0);
-               if (!ret)
-                       break;
+       while (waitpid(pid, NULL, 0) < 0) {
                if (errno != EINTR)
-                       break;
+                       return -1;
        }
-       return ret;
+       return 0;
 }
index 3f6ed69..4a8f790 100644 (file)
@@ -54,7 +54,7 @@
     (let* ((dir (file-name-directory file))
            (name (file-relative-name file dir)))
       (when dir (cd dir))
-      (and (eq 0 (call-process "git" nil '(t nil) nil "ls-files" "-c" "-z" "--" name))
+      (and (ignore-errors (eq 0 (call-process "git" nil '(t nil) nil "ls-files" "-c" "-z" "--" name)))
            (let ((str (buffer-string)))
              (and (> (length str) (length name))
                   (string= (substring str 0 (1+ (length name))) (concat name "\0"))))))))
index 6924df2..77c29de 100644 (file)
@@ -7,40 +7,50 @@ gitview - A GTK based repository browser for git
 
 SYNOPSIS
 --------
-'gitview'  [options] [args]
+'gitview' [options] [args]
 
 DESCRIPTION
 ---------
 
-Dependencies
+Dependencies:
 
 * Python 2.4
 * PyGTK 2.8 or later
 * PyCairo 1.0 or later
 
 OPTIONS
-------
-       --without-diff
-               If the user doesn't want to list the commit diffs in the main window. This may speed up the repository browsing.
-
-       <args>
-               All the valid option for git-rev-list(1)
-       Key Bindings:
-       F4:
-               To maximize the window
-       F5:
-               To reread references.
-       F11:
-               Full screen
-       F12:
-               Leave full screen
+-------
+--without-diff::
+
+       If the user doesn't want to list the commit diffs in the main window.
+       This may speed up the repository browsing.
+
+<args>::
+
+       All the valid option for gitlink:git-rev-list[1].
+
+Key Bindings
+------------
+F4::
+       To maximize the window
+
+F5::
+       To reread references.
+
+F11::
+       Full screen
+
+F12::
+       Leave full screen
 
 EXAMPLES
-------
-       gitview v2.6.12.. include/scsi drivers/scsi
-         Show as the changes since version v2.6.12 that changed any file in the include/scsi
-         or drivers/scsi subdirectories
+--------
+
+gitview v2.6.12.. include/scsi drivers/scsi::
+
+       Show as the changes since version v2.6.12 that changed any file in the
+       include/scsi or drivers/scsi subdirectories
 
-       gitview --since=2.weeks.ago
-         Show the changes during the last two weeks
+gitview --since=2.weeks.ago::
 
+       Show the changes during the last two weeks
index 168771e..631678b 100644 (file)
@@ -23,7 +23,7 @@ static struct entry * convert_entry(unsigned char *sha1);
 static struct entry *insert_new(unsigned char *sha1, int pos)
 {
        struct entry *new = xcalloc(1, sizeof(struct entry));
-       memcpy(new->old_sha1, sha1, 20);
+       hashcpy(new->old_sha1, sha1);
        memmove(convert + pos + 1, convert + pos, (nr_convert - pos) * sizeof(struct entry *));
        convert[pos] = new;
        nr_convert++;
@@ -39,7 +39,7 @@ static struct entry *lookup_entry(unsigned char *sha1)
        while (low < high) {
                int next = (low + high) / 2;
                struct entry *n = convert[next];
-               int cmp = memcmp(sha1, n->old_sha1, 20);
+               int cmp = hashcmp(sha1, n->old_sha1);
                if (!cmp)
                        return n;
                if (cmp < 0) {
@@ -54,7 +54,7 @@ static struct entry *lookup_entry(unsigned char *sha1)
 static void convert_binary_sha1(void *buffer)
 {
        struct entry *entry = convert_entry(buffer);
-       memcpy(buffer, entry->new_sha1, 20);
+       hashcpy(buffer, entry->new_sha1);
 }
 
 static void convert_ascii_sha1(void *buffer)
@@ -104,7 +104,7 @@ static int write_subdirectory(void *buffer, unsigned long size, const char *base
                if (!slash) {
                        newlen += sprintf(new + newlen, "%o %s", mode, path);
                        new[newlen++] = '\0';
-                       memcpy(new + newlen, (char *) buffer + len - 20, 20);
+                       hashcpy((unsigned char*)new + newlen, (unsigned char *) buffer + len - 20);
                        newlen += 20;
 
                        used += len;
index 6a7b40f..b7174c6 100644 (file)
@@ -10,7 +10,7 @@
 #include "cache.h"
 #include "csum-file.h"
 
-static int sha1flush(struct sha1file *f, unsigned int count)
+static void sha1flush(struct sha1file *f, unsigned int count)
 {
        void *buf = f->buffer;
 
@@ -21,7 +21,7 @@ static int sha1flush(struct sha1file *f, unsigned int count)
                        count -= ret;
                        if (count)
                                continue;
-                       return 0;
+                       return;
                }
                if (!ret)
                        die("sha1 file '%s' write error. Out of diskspace", f->name);
@@ -38,7 +38,7 @@ int sha1close(struct sha1file *f, unsigned char *result, int update)
        }
        SHA1_Final(f->buffer, &f->ctx);
        if (result)
-               memcpy(result, f->buffer, 20);
+               hashcpy(result, f->buffer);
        if (update)
                sha1flush(f, 20);
        if (close(f->fd))
index 810837f..66ec830 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -7,6 +7,8 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <syslog.h>
+#include <pwd.h>
+#include <grp.h>
 #include "pkt-line.h"
 #include "cache.h"
 #include "exec_cmd.h"
@@ -19,27 +21,28 @@ static const char daemon_usage[] =
 "git-daemon [--verbose] [--syslog] [--inetd | --port=n] [--export-all]\n"
 "           [--timeout=n] [--init-timeout=n] [--strict-paths]\n"
 "           [--base-path=path] [--user-path | --user-path=path]\n"
-"           [--reuseaddr] [--detach] [--pid-file=file] [directory...]";
+"           [--reuseaddr] [--detach] [--pid-file=file]\n"
+"           [--user=user [[--group=group]] [directory...]";
 
 /* List of acceptable pathname prefixes */
-static char **ok_paths = NULL;
-static int strict_paths = 0;
+static char **ok_paths;
+static int strict_paths;
 
 /* If this is set, git-daemon-export-ok is not required */
-static int export_all_trees = 0;
+static int export_all_trees;
 
 /* Take all paths relative to this one if non-NULL */
-static char *base_path = NULL;
+static char *base_path;
 
 /* If defined, ~user notation is allowed and the string is inserted
  * after ~user/.  E.g. a request to git://host/~alice/frotz would
  * go to /home/alice/pub_git/frotz with --user-path=pub_git.
  */
-static const char *user_path = NULL;
+static const char *user_path;
 
 /* Timeout, and initial timeout */
-static unsigned int timeout = 0;
-static unsigned int init_timeout = 0;
+static unsigned int timeout;
+static unsigned int init_timeout;
 
 static void logreport(int priority, const char *err, va_list params)
 {
@@ -333,12 +336,12 @@ static int execute(struct sockaddr *addr)
 static int max_connections = 25;
 
 /* These are updated by the signal handler */
-static volatile unsigned int children_reaped = 0;
+static volatile unsigned int children_reaped;
 static pid_t dead_child[MAX_CHILDREN];
 
 /* These are updated by the main loop */
-static unsigned int children_spawned = 0;
-static unsigned int children_deleted = 0;
+static unsigned int children_spawned;
+static unsigned int children_deleted;
 
 static struct child {
        pid_t pid;
@@ -526,7 +529,6 @@ static int socksetup(int port, int **socklist_p)
 
        for (ai = ai0; ai; ai = ai->ai_next) {
                int sockfd;
-               int *newlist;
 
                sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
                if (sockfd < 0)
@@ -560,11 +562,7 @@ static int socksetup(int port, int **socklist_p)
                        continue;       /* not fatal */
                }
 
-               newlist = realloc(socklist, sizeof(int) * (socknum + 1));
-               if (!newlist)
-                       die("memory allocation failed: %s", strerror(errno));
-
-               socklist = newlist;
+               socklist = xrealloc(socklist, sizeof(int) * (socknum + 1));
                socklist[socknum++] = sockfd;
 
                if (maxfd < sockfd)
@@ -701,7 +699,7 @@ static void store_pid(const char *path)
        fclose(f);
 }
 
-static int serve(int port)
+static int serve(int port, struct passwd *pass, gid_t gid)
 {
        int socknum, *socklist;
 
@@ -709,6 +707,11 @@ static int serve(int port)
        if (socknum == 0)
                die("unable to allocate any listen sockets on port %u", port);
 
+       if (pass && gid &&
+           (initgroups(pass->pw_name, gid) || setgid (gid) ||
+            setuid(pass->pw_uid)))
+               die("cannot drop privileges");
+
        return service_loop(socknum, socklist);
 }
 
@@ -716,8 +719,11 @@ int main(int argc, char **argv)
 {
        int port = DEFAULT_GIT_PORT;
        int inetd_mode = 0;
-       const char *pid_file = NULL;
+       const char *pid_file = NULL, *user_name = NULL, *group_name = NULL;
        int detach = 0;
+       struct passwd *pass = NULL;
+       struct group *group;
+       gid_t gid = 0;
        int i;
 
        /* Without this we cannot rely on waitpid() to tell
@@ -791,6 +797,14 @@ int main(int argc, char **argv)
                        log_syslog = 1;
                        continue;
                }
+               if (!strncmp(arg, "--user=", 7)) {
+                       user_name = arg + 7;
+                       continue;
+               }
+               if (!strncmp(arg, "--group=", 8)) {
+                       group_name = arg + 8;
+                       continue;
+               }
                if (!strcmp(arg, "--")) {
                        ok_paths = &argv[i+1];
                        break;
@@ -802,6 +816,28 @@ int main(int argc, char **argv)
                usage(daemon_usage);
        }
 
+       if (inetd_mode && (group_name || user_name))
+               die("--user and --group are incompatible with --inetd");
+
+       if (group_name && !user_name)
+               die("--group supplied without --user");
+
+       if (user_name) {
+               pass = getpwnam(user_name);
+               if (!pass)
+                       die("user not found - %s", user_name);
+
+               if (!group_name)
+                       gid = pass->pw_gid;
+               else {
+                       group = getgrnam(group_name);
+                       if (!group)
+                               die("group not found - %s", group_name);
+
+                       gid = group->gr_gid;
+               }
+       }
+
        if (log_syslog) {
                openlog("git-daemon", 0, LOG_DAEMON);
                set_die_routine(daemon_die);
@@ -831,5 +867,5 @@ int main(int argc, char **argv)
        if (pid_file)
                store_pid(pid_file);
 
-       return serve(port);
+       return serve(port, pass, gid);
 }
diff --git a/date.c b/date.c
index 66be23a..e387dcd 100644 (file)
--- a/date.c
+++ b/date.c
@@ -37,6 +37,16 @@ static const char *weekday_names[] = {
        "Sundays", "Mondays", "Tuesdays", "Wednesdays", "Thursdays", "Fridays", "Saturdays"
 };
 
+static time_t gm_time_t(unsigned long time, int tz)
+{
+       int minutes;
+
+       minutes = tz < 0 ? -tz : tz;
+       minutes = (minutes / 100)*60 + (minutes % 100);
+       minutes = tz < 0 ? -minutes : minutes;
+       return time + minutes * 60;
+}
+
 /*
  * The "tz" thing is passed in as this strange "decimal parse of tz"
  * thing, which means that tz -0100 is passed in as the integer -100,
@@ -44,21 +54,58 @@ static const char *weekday_names[] = {
  */
 static struct tm *time_to_tm(unsigned long time, int tz)
 {
-       time_t t;
-       int minutes;
-
-       minutes = tz < 0 ? -tz : tz;
-       minutes = (minutes / 100)*60 + (minutes % 100);
-       minutes = tz < 0 ? -minutes : minutes;
-       t = time + minutes * 60;
+       time_t t = gm_time_t(time, tz);
        return gmtime(&t);
 }
 
-const char *show_date(unsigned long time, int tz)
+const char *show_date(unsigned long time, int tz, int relative)
 {
        struct tm *tm;
        static char timebuf[200];
 
+       if (relative) {
+               unsigned long diff;
+               time_t t = gm_time_t(time, tz);
+               struct timeval now;
+               gettimeofday(&now, NULL);
+               if (now.tv_sec < t)
+                       return "in the future";
+               diff = now.tv_sec - t;
+               if (diff < 90) {
+                       snprintf(timebuf, sizeof(timebuf), "%lu seconds ago", diff);
+                       return timebuf;
+               }
+               /* Turn it into minutes */
+               diff = (diff + 30) / 60;
+               if (diff < 90) {
+                       snprintf(timebuf, sizeof(timebuf), "%lu minutes ago", diff);
+                       return timebuf;
+               }
+               /* Turn it into hours */
+               diff = (diff + 30) / 60;
+               if (diff < 36) {
+                       snprintf(timebuf, sizeof(timebuf), "%lu hours ago", diff);
+                       return timebuf;
+               }
+               /* We deal with number of days from here on */
+               diff = (diff + 12) / 24;
+               if (diff < 14) {
+                       snprintf(timebuf, sizeof(timebuf), "%lu days ago", diff);
+                       return timebuf;
+               }
+               /* Say weeks for the past 10 weeks or so */
+               if (diff < 70) {
+                       snprintf(timebuf, sizeof(timebuf), "%lu weeks ago", (diff + 3) / 7);
+                       return timebuf;
+               }
+               /* Say months for the past 12 months or so */
+               if (diff < 360) {
+                       snprintf(timebuf, sizeof(timebuf), "%lu months ago", (diff + 15) / 30);
+                       return timebuf;
+               }
+               /* Else fall back on absolute format.. */
+       }
+
        tm = time_to_tm(time, tz);
        if (!tm)
                return NULL;
@@ -584,10 +631,10 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, int *num)
        const struct typelen *tl;
        const struct special *s;
        const char *end = date;
-       int n = 1, i;
+       int i;
 
-       while (isalpha(*++end))
-               n++;
+       while (isalpha(*++end));
+               ;
 
        for (i = 0; i < 12; i++) {
                int match = match_string(date, month_names[i]);
index 324ca89..5dd8b2e 100644 (file)
@@ -8,12 +8,12 @@
 static const char describe_usage[] =
 "git-describe [--all] [--tags] [--abbrev=<n>] <committish>*";
 
-static int all = 0;    /* Default to annotated tags only */
-static int tags = 0;   /* But allow any tags if --tags is specified */
+static int all;        /* Default to annotated tags only */
+static int tags;       /* But allow any tags if --tags is specified */
 
 static int abbrev = DEFAULT_ABBREV;
 
-static int names = 0, allocs = 0;
+static int names, allocs;
 static struct commit_name {
        const struct commit *commit;
        int prio; /* annotated tag = 2, tag = 1, head = 0 */
@@ -42,7 +42,7 @@ static void add_to_known_names(const char *path,
        struct commit_name *name = xmalloc(sizeof(struct commit_name) + len);
 
        name->commit = commit;
-       name->prio = prio; 
+       name->prio = prio;
        memcpy(name->path, path, len);
        idx = names;
        if (idx >= allocs) {
@@ -154,7 +154,7 @@ int main(int argc, char **argv)
                        tags = 1;
                else if (!strncmp(arg, "--abbrev=", 9)) {
                        abbrev = strtoul(arg + 9, NULL, 10);
-                       if (abbrev < MINIMUM_ABBREV || 40 <= abbrev)
+                       if (abbrev < MINIMUM_ABBREV || 40 < abbrev)
                                abbrev = DEFAULT_ABBREV;
                }
                else
index 7da9205..fa16d06 100644 (file)
@@ -152,7 +152,7 @@ struct delta_index * create_delta_index(const void *buf, unsigned long bufsize)
           initialization in create_delta(). */
        entries = (bufsize - 1)  / RABIN_WINDOW;
        hsize = entries / 4;
-       for (i = 4; (1 << i) < hsize && i < 31; i++);
+       for (i = 4; (1u << i) < hsize && i < 31; i++);
        hsize = 1 << i;
        hmask = hsize - 1;
 
@@ -392,7 +392,7 @@ create_delta(const struct delta_index *index,
                                outsize = max_size + MAX_OP_SIZE + 1;
                        if (max_size && outpos > max_size)
                                break;
-                       out = realloc(out, outsize);
+                       out = xrealloc(out, outsize);
                        if (!out) {
                                free(tmp);
                                return NULL;
index 116b5a9..9edfa92 100644 (file)
@@ -48,7 +48,7 @@ int run_diff_files(struct rev_info *revs, int silent_on_removed)
                        memcpy(dpath->path, ce->name, path_len);
                        dpath->path[path_len] = '\0';
                        dpath->mode = 0;
-                       memset(dpath->sha1, 0, 20);
+                       hashclr(dpath->sha1);
                        memset(&(dpath->parent[0]), 0,
                                        sizeof(struct combine_diff_parent)*5);
 
@@ -66,8 +66,7 @@ int run_diff_files(struct rev_info *revs, int silent_on_removed)
                                if (2 <= stage) {
                                        int mode = ntohl(nce->ce_mode);
                                        num_compare_stages++;
-                                       memcpy(dpath->parent[stage-2].sha1,
-                                              nce->sha1, 20);
+                                       hashcpy(dpath->parent[stage-2].sha1, nce->sha1);
                                        dpath->parent[stage-2].mode =
                                                canon_mode(mode);
                                        dpath->parent[stage-2].status =
@@ -215,7 +214,7 @@ static int show_modified(struct rev_info *revs,
        }
 
        oldmode = old->ce_mode;
-       if (mode == oldmode && !memcmp(sha1, old->sha1, 20) &&
+       if (mode == oldmode && !hashcmp(sha1, old->sha1) &&
            !revs->diffopt.find_copies_harder)
                return 0;
 
diff --git a/diff.c b/diff.c
index b3b1781..70699fd 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -13,9 +13,9 @@
 
 static int use_size_cache;
 
-static int diff_detect_rename_default = 0;
+static int diff_detect_rename_default;
 static int diff_rename_limit_default = -1;
-static int diff_use_color_default = 0;
+static int diff_use_color_default;
 
 /* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */
 static char diff_colors[][24] = {
@@ -358,12 +358,152 @@ static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one)
        return 0;
 }
 
+struct diff_words_buffer {
+       mmfile_t text;
+       long alloc;
+       long current; /* output pointer */
+       int suppressed_newline;
+};
+
+static void diff_words_append(char *line, unsigned long len,
+               struct diff_words_buffer *buffer)
+{
+       if (buffer->text.size + len > buffer->alloc) {
+               buffer->alloc = (buffer->text.size + len) * 3 / 2;
+               buffer->text.ptr = xrealloc(buffer->text.ptr, buffer->alloc);
+       }
+       line++;
+       len--;
+       memcpy(buffer->text.ptr + buffer->text.size, line, len);
+       buffer->text.size += len;
+}
+
+struct diff_words_data {
+       struct xdiff_emit_state xm;
+       struct diff_words_buffer minus, plus;
+};
+
+static void print_word(struct diff_words_buffer *buffer, int len, int color,
+               int suppress_newline)
+{
+       const char *ptr;
+       int eol = 0;
+
+       if (len == 0)
+               return;
+
+       ptr  = buffer->text.ptr + buffer->current;
+       buffer->current += len;
+
+       if (ptr[len - 1] == '\n') {
+               eol = 1;
+               len--;
+       }
+
+       fputs(diff_get_color(1, color), stdout);
+       fwrite(ptr, len, 1, stdout);
+       fputs(diff_get_color(1, DIFF_RESET), stdout);
+
+       if (eol) {
+               if (suppress_newline)
+                       buffer->suppressed_newline = 1;
+               else
+                       putchar('\n');
+       }
+}
+
+static void fn_out_diff_words_aux(void *priv, char *line, unsigned long len)
+{
+       struct diff_words_data *diff_words = priv;
+
+       if (diff_words->minus.suppressed_newline) {
+               if (line[0] != '+')
+                       putchar('\n');
+               diff_words->minus.suppressed_newline = 0;
+       }
+
+       len--;
+       switch (line[0]) {
+               case '-':
+                       print_word(&diff_words->minus, len, DIFF_FILE_OLD, 1);
+                       break;
+               case '+':
+                       print_word(&diff_words->plus, len, DIFF_FILE_NEW, 0);
+                       break;
+               case ' ':
+                       print_word(&diff_words->plus, len, DIFF_PLAIN, 0);
+                       diff_words->minus.current += len;
+                       break;
+       }
+}
+
+/* this executes the word diff on the accumulated buffers */
+static void diff_words_show(struct diff_words_data *diff_words)
+{
+       xpparam_t xpp;
+       xdemitconf_t xecfg;
+       xdemitcb_t ecb;
+       mmfile_t minus, plus;
+       int i;
+
+       minus.size = diff_words->minus.text.size;
+       minus.ptr = xmalloc(minus.size);
+       memcpy(minus.ptr, diff_words->minus.text.ptr, minus.size);
+       for (i = 0; i < minus.size; i++)
+               if (isspace(minus.ptr[i]))
+                       minus.ptr[i] = '\n';
+       diff_words->minus.current = 0;
+
+       plus.size = diff_words->plus.text.size;
+       plus.ptr = xmalloc(plus.size);
+       memcpy(plus.ptr, diff_words->plus.text.ptr, plus.size);
+       for (i = 0; i < plus.size; i++)
+               if (isspace(plus.ptr[i]))
+                       plus.ptr[i] = '\n';
+       diff_words->plus.current = 0;
+
+       xpp.flags = XDF_NEED_MINIMAL;
+       xecfg.ctxlen = diff_words->minus.alloc + diff_words->plus.alloc;
+       xecfg.flags = 0;
+       ecb.outf = xdiff_outf;
+       ecb.priv = diff_words;
+       diff_words->xm.consume = fn_out_diff_words_aux;
+       xdl_diff(&minus, &plus, &xpp, &xecfg, &ecb);
+
+       free(minus.ptr);
+       free(plus.ptr);
+       diff_words->minus.text.size = diff_words->plus.text.size = 0;
+
+       if (diff_words->minus.suppressed_newline) {
+               putchar('\n');
+               diff_words->minus.suppressed_newline = 0;
+       }
+}
+
 struct emit_callback {
        struct xdiff_emit_state xm;
        int nparents, color_diff;
        const char **label_path;
+       struct diff_words_data *diff_words;
 };
 
+static void free_diff_words_data(struct emit_callback *ecbdata)
+{
+       if (ecbdata->diff_words) {
+               /* flush buffers */
+               if (ecbdata->diff_words->minus.text.size ||
+                               ecbdata->diff_words->plus.text.size)
+                       diff_words_show(ecbdata->diff_words);
+
+               if (ecbdata->diff_words->minus.text.ptr)
+                       free (ecbdata->diff_words->minus.text.ptr);
+               if (ecbdata->diff_words->plus.text.ptr)
+                       free (ecbdata->diff_words->plus.text.ptr);
+               free(ecbdata->diff_words);
+               ecbdata->diff_words = NULL;
+       }
+}
+
 const char *diff_get_color(int diff_use_color, enum color_diff ix)
 {
        if (diff_use_color)
@@ -398,12 +538,31 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
        else {
                int nparents = ecbdata->nparents;
                int color = DIFF_PLAIN;
-               for (i = 0; i < nparents && len; i++) {
-                       if (line[i] == '-')
-                               color = DIFF_FILE_OLD;
-                       else if (line[i] == '+')
-                               color = DIFF_FILE_NEW;
-               }
+               if (ecbdata->diff_words && nparents != 1)
+                       /* fall back to normal diff */
+                       free_diff_words_data(ecbdata);
+               if (ecbdata->diff_words) {
+                       if (line[0] == '-') {
+                               diff_words_append(line, len,
+                                               &ecbdata->diff_words->minus);
+                               return;
+                       } else if (line[0] == '+') {
+                               diff_words_append(line, len,
+                                               &ecbdata->diff_words->plus);
+                               return;
+                       }
+                       if (ecbdata->diff_words->minus.text.size ||
+                                       ecbdata->diff_words->plus.text.size)
+                               diff_words_show(ecbdata->diff_words);
+                       line++;
+                       len--;
+               } else
+                       for (i = 0; i < nparents && len; i++) {
+                               if (line[i] == '-')
+                                       color = DIFF_FILE_OLD;
+                               else if (line[i] == '+')
+                                       color = DIFF_FILE_NEW;
+                       }
                set = diff_get_color(ecbdata->color_diff, color);
        }
        if (len > 0 && line[len-1] == '\n')
@@ -679,7 +838,7 @@ static unsigned char *deflate_it(char *data,
        return deflated;
 }
 
-static void emit_binary_diff(mmfile_t *one, mmfile_t *two)
+static void emit_binary_diff_body(mmfile_t *one, mmfile_t *two)
 {
        void *cp;
        void *delta;
@@ -690,7 +849,6 @@ static void emit_binary_diff(mmfile_t *one, mmfile_t *two)
        unsigned long deflate_size;
        unsigned long data_size;
 
-       printf("GIT binary patch\n");
        /* We could do deflated delta, or we could do just deflated two,
         * whichever is smaller.
         */
@@ -739,15 +897,20 @@ static void emit_binary_diff(mmfile_t *one, mmfile_t *two)
        free(data);
 }
 
+static void emit_binary_diff(mmfile_t *one, mmfile_t *two)
+{
+       printf("GIT binary patch\n");
+       emit_binary_diff_body(one, two);
+       emit_binary_diff_body(two, one);
+}
+
 #define FIRST_FEW_BYTES 8000
 static int mmfile_is_binary(mmfile_t *mf)
 {
        long sz = mf->size;
        if (FIRST_FEW_BYTES < sz)
                sz = FIRST_FEW_BYTES;
-       if (memchr(mf->ptr, 0, sz))
-               return 1;
-       return 0;
+       return !!memchr(mf->ptr, 0, sz);
 }
 
 static void builtin_diff(const char *name_a,
@@ -836,7 +999,12 @@ static void builtin_diff(const char *name_a,
                ecb.outf = xdiff_outf;
                ecb.priv = &ecbdata;
                ecbdata.xm.consume = fn_out_consume;
+               if (o->color_diff_words)
+                       ecbdata.diff_words =
+                               xcalloc(1, sizeof(struct diff_words_data));
                xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
+               if (o->color_diff_words)
+                       free_diff_words_data(&ecbdata);
        }
 
  free_ab_and_return:
@@ -939,8 +1107,8 @@ void fill_filespec(struct diff_filespec *spec, const unsigned char *sha1,
 {
        if (mode) {
                spec->mode = canon_mode(mode);
-               memcpy(spec->sha1, sha1, 20);
-               spec->sha1_valid = !!memcmp(sha1, null_sha1, 20);
+               hashcpy(spec->sha1, sha1);
+               spec->sha1_valid = !is_null_sha1(sha1);
        }
 }
 
@@ -978,7 +1146,7 @@ static int work_tree_matches(const char *name, const unsigned char *sha1)
        if ((lstat(name, &st) < 0) ||
            !S_ISREG(st.st_mode) || /* careful! */
            ce_match_stat(ce, &st, 0) ||
-           memcmp(sha1, ce->sha1, 20))
+           hashcmp(sha1, ce->sha1))
                return 0;
        /* we return 1 only when we can stat, it is a regular file,
         * stat information matches, and sha1 recorded in the cache
@@ -1006,7 +1174,7 @@ static struct sha1_size_cache *locate_size_cache(unsigned char *sha1,
        while (last > first) {
                int cmp, next = (last + first) >> 1;
                e = sha1_size_cache[next];
-               cmp = memcmp(e->sha1, sha1, 20);
+               cmp = hashcmp(e->sha1, sha1);
                if (!cmp)
                        return e;
                if (cmp < 0) {
@@ -1032,7 +1200,7 @@ static struct sha1_size_cache *locate_size_cache(unsigned char *sha1,
                        sizeof(*sha1_size_cache));
        e = xmalloc(sizeof(struct sha1_size_cache));
        sha1_size_cache[first] = e;
-       memcpy(e->sha1, sha1, 20);
+       hashcpy(e->sha1, sha1);
        e->size = size;
        return e;
 }
@@ -1354,7 +1522,7 @@ static void diff_fill_sha1_info(struct diff_filespec *one)
                }
        }
        else
-               memset(one->sha1, 0, 20);
+               hashclr(one->sha1);
 }
 
 static void run_diff(struct diff_filepair *p, struct diff_options *o)
@@ -1417,7 +1585,7 @@ static void run_diff(struct diff_filepair *p, struct diff_options *o)
                ;
        }
 
-       if (memcmp(one->sha1, two->sha1, 20)) {
+       if (hashcmp(one->sha1, two->sha1)) {
                int abbrev = o->full_index ? 40 : DEFAULT_ABBREV;
 
                len += snprintf(msg + len, sizeof(msg) - len,
@@ -1515,6 +1683,19 @@ void diff_setup(struct diff_options *options)
 
 int diff_setup_done(struct diff_options *options)
 {
+       int count = 0;
+
+       if (options->output_format & DIFF_FORMAT_NAME)
+               count++;
+       if (options->output_format & DIFF_FORMAT_NAME_STATUS)
+               count++;
+       if (options->output_format & DIFF_FORMAT_CHECKDIFF)
+               count++;
+       if (options->output_format & DIFF_FORMAT_NO_OUTPUT)
+               count++;
+       if (count > 1)
+               die("--name-only, --name-status, --check and -s are mutually exclusive");
+
        if (options->find_copies_harder)
                options->detect_rename = DIFF_DETECT_COPY;
 
@@ -1697,6 +1878,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
                options->xdl_opts |= XDF_IGNORE_WHITESPACE;
        else if (!strcmp(arg, "-b") || !strcmp(arg, "--ignore-space-change"))
                options->xdl_opts |= XDF_IGNORE_WHITESPACE_CHANGE;
+       else if (!strcmp(arg, "--color-words"))
+               options->color_diff = options->color_diff_words = 1;
        else if (!strcmp(arg, "--no-renames"))
                options->detect_rename = 0;
        else
@@ -1921,7 +2104,7 @@ int diff_unmodified_pair(struct diff_filepair *p)
         * dealing with a change.
         */
        if (one->sha1_valid && two->sha1_valid &&
-           !memcmp(one->sha1, two->sha1, sizeof(one->sha1)))
+           !hashcmp(one->sha1, two->sha1))
                return 1; /* no change */
        if (!one->sha1_valid && !two->sha1_valid)
                return 1; /* both look at the same file on the filesystem. */
@@ -2060,7 +2243,7 @@ static void diff_resolve_rename_copy(void)
                        if (!p->status)
                                p->status = DIFF_STATUS_RENAMED;
                }
-               else if (memcmp(p->one->sha1, p->two->sha1, 20) ||
+               else if (hashcmp(p->one->sha1, p->two->sha1) ||
                         p->one->mode != p->two->mode)
                        p->status = DIFF_STATUS_MODIFIED;
                else {
diff --git a/diff.h b/diff.h
index 2cced53..b007240 100644 (file)
--- a/diff.h
+++ b/diff.h
@@ -46,7 +46,8 @@ struct diff_options {
                 full_index:1,
                 silent_on_remove:1,
                 find_copies_harder:1,
-                color_diff:1;
+                color_diff:1,
+                color_diff_words:1;
        int context;
        int break_opt;
        int detect_rename;
index ed0e14c..acb18db 100644 (file)
@@ -56,7 +56,7 @@ static int should_break(struct diff_filespec *src,
                return 0; /* leave symlink rename alone */
 
        if (src->sha1_valid && dst->sha1_valid &&
-           !memcmp(src->sha1, dst->sha1, 20))
+           !hashcmp(src->sha1, dst->sha1))
                return 0; /* they are the same */
 
        if (diff_populate_filespec(src, 0) || diff_populate_filespec(dst, 0))
index 0ec488a..ef23901 100644 (file)
@@ -101,7 +101,7 @@ static int is_exact_match(struct diff_filespec *src,
                          int contents_too)
 {
        if (src->sha1_valid && dst->sha1_valid &&
-           !memcmp(src->sha1, dst->sha1, 20))
+           !hashcmp(src->sha1, dst->sha1))
                return 1;
        if (!contents_too)
                return 0;
diff --git a/dir.c b/dir.c
index 092d077..d53d48f 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -101,8 +101,8 @@ void add_exclude(const char *string, const char *base,
        x->baselen = baselen;
        if (which->nr == which->alloc) {
                which->alloc = alloc_nr(which->alloc);
-               which->excludes = realloc(which->excludes,
-                                         which->alloc * sizeof(x));
+               which->excludes = xrealloc(which->excludes,
+                                          which->alloc * sizeof(x));
        }
        which->excludes[which->nr++] = x;
 }
@@ -293,7 +293,7 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
        if (fdir) {
                int exclude_stk;
                struct dirent *de;
-               char fullname[MAXPATHLEN + 1];
+               char fullname[PATH_MAX + 1];
                memcpy(fullname, base, baselen);
 
                exclude_stk = push_exclude_per_directory(dir, base, baselen);
index 1ccaf51..1f73f1e 100644 (file)
@@ -33,7 +33,7 @@ static int dump_cache_tree(struct cache_tree *it,
        }
        else {
                dump_one(it, pfx, "");
-               if (memcmp(it->sha1, ref->sha1, 20) ||
+               if (hashcmp(it->sha1, ref->sha1) ||
                    ref->entry_count != it->entry_count ||
                    ref->subtree_nr != it->subtree_nr) {
                        dump_one(ref, pfx, "#(ref) ");
diff --git a/entry.c b/entry.c
index 793724f..b2ea0ef 100644 (file)
--- a/entry.c
+++ b/entry.c
@@ -135,7 +135,7 @@ static int write_entry(struct cache_entry *ce, char *path, struct checkout *stat
 
 int checkout_entry(struct cache_entry *ce, struct checkout *state, char *topath)
 {
-       static char path[MAXPATHLEN+1];
+       static char path[PATH_MAX + 1];
        struct stat st;
        int len = state->base_dir_len;
 
@@ -172,5 +172,3 @@ int checkout_entry(struct cache_entry *ce, struct checkout *state, char *topath)
        create_directories(path, state);
        return write_entry(ce, path, state, 0);
 }
-
-
index 87162b2..5fae9ac 100644 (file)
@@ -13,20 +13,21 @@ char git_default_email[MAX_GITNAME];
 char git_default_name[MAX_GITNAME];
 int use_legacy_headers = 1;
 int trust_executable_bit = 1;
-int assume_unchanged = 0;
-int prefer_symlink_refs = 0;
-int log_all_ref_updates = 0;
+int assume_unchanged;
+int prefer_symlink_refs;
+int log_all_ref_updates;
 int warn_ambiguous_refs = 1;
-int repository_format_version = 0;
+int repository_format_version;
 char git_commit_encoding[MAX_ENCODING_LENGTH] = "utf-8";
 int shared_repository = PERM_UMASK;
-const char *apply_default_whitespace = NULL;
+const char *apply_default_whitespace;
 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;
+static const char *git_dir;
+static char *git_object_dir, *git_index_file, *git_refs_dir, *git_graft_file;
+
 static void setup_git_env(void)
 {
        git_dir = getenv(GIT_DIR_ENVIRONMENT);
@@ -49,7 +50,7 @@ static void setup_git_env(void)
                git_graft_file = strdup(git_path("info/grafts"));
 }
 
-char *get_git_dir(void)
+const char *get_git_dir(void)
 {
        if (!git_dir)
                setup_git_env();
index 62f51fc..e30936d 100644 (file)
@@ -5,7 +5,7 @@
 
 extern char **environ;
 static const char *builtin_exec_path = GIT_EXEC_PATH;
-static const char *current_exec_path = NULL;
+static const char *current_exec_path;
 
 void git_set_exec_path(const char *exec_path)
 {
index 5e84c46..c5cf477 100644 (file)
@@ -44,9 +44,8 @@ static int finish_pack(const char *pack_tmp_name, const char *me)
 
        for (;;) {
                int status, code;
-               int retval = waitpid(pid, &status, 0);
 
-               if (retval < 0) {
+               if (waitpid(pid, &status, 0) < 0) {
                        if (errno == EINTR)
                                continue;
                        error("waitpid failed (%s)", strerror(errno));
index b7824db..377fede 100644 (file)
@@ -24,8 +24,8 @@ static const char *exec = "git-upload-pack";
  */
 #define MAX_IN_VAIN 256
 
-static struct commit_list *rev_list = NULL;
-static int non_common_revs = 0, multi_ack = 0, use_thin_pack = 0, use_sideband;
+static struct commit_list *rev_list;
+static int non_common_revs, multi_ack, use_thin_pack, use_sideband;
 
 static void rev_list_push(struct commit *commit, int mark)
 {
@@ -250,7 +250,7 @@ done:
        return retval;
 }
 
-static struct commit_list *complete = NULL;
+static struct commit_list *complete;
 
 static int mark_complete(const char *path, const unsigned char *sha1)
 {
@@ -404,7 +404,7 @@ static int everything_local(struct ref **refs, int nr_match, char **match)
                        continue;
                }
 
-               memcpy(ref->new_sha1, local, 20);
+               hashcpy(ref->new_sha1, local);
                if (!verbose)
                        continue;
                fprintf(stderr,
diff --git a/fetch.c b/fetch.c
index aeb6bf2..ef60b04 100644 (file)
--- a/fetch.c
+++ b/fetch.c
@@ -84,7 +84,7 @@ static int process_commit(struct commit *commit)
        if (commit->object.flags & COMPLETE)
                return 0;
 
-       memcpy(current_commit_sha1, commit->object.sha1, 20);
+       hashcpy(current_commit_sha1, commit->object.sha1);
 
        pull_say("walk %s\n", sha1_to_hex(commit->object.sha1));
 
index e167f41..ae0ec8d 100644 (file)
 #define REACHABLE 0x0001
 #define SEEN      0x0002
 
-static int show_root = 0;
-static int show_tags = 0;
-static int show_unreachable = 0;
-static int check_full = 0;
-static int check_strict = 0;
-static int keep_cache_objects = 0;
+static int show_root;
+static int show_tags;
+static int show_unreachable;
+static int check_full;
+static int check_strict;
+static int keep_cache_objects;
 static unsigned char head_sha1[20];
 
 #ifdef NO_D_INO_IN_DIRENT
@@ -356,7 +356,7 @@ static void add_sha1_list(unsigned char *sha1, unsigned long ino)
        int nr;
 
        entry->ino = ino;
-       memcpy(entry->sha1, sha1, 20);
+       hashcpy(entry->sha1, sha1);
        nr = sha1_list.nr;
        if (nr == MAX_SHA1_ENTRIES) {
                fsck_sha1_list();
@@ -366,13 +366,13 @@ static void add_sha1_list(unsigned char *sha1, unsigned long ino)
        sha1_list.nr = ++nr;
 }
 
-static int fsck_dir(int i, char *path)
+static void fsck_dir(int i, char *path)
 {
        DIR *dir = opendir(path);
        struct dirent *de;
 
        if (!dir)
-               return 0;
+               return;
 
        while ((de = readdir(dir)) != NULL) {
                char name[100];
@@ -398,10 +398,9 @@ static int fsck_dir(int i, char *path)
                fprintf(stderr, "bad sha1 file: %s/%s\n", path, de->d_name);
        }
        closedir(dir);
-       return 0;
 }
 
-static int default_refs = 0;
+static int default_refs;
 
 static int fsck_handle_ref(const char *refname, const unsigned char *sha1)
 {
@@ -453,7 +452,7 @@ static int fsck_head_link(void)
        if (strncmp(git_refs_heads_master + pfxlen, "refs/heads/", 11))
                return error("HEAD points to something strange (%s)",
                             git_refs_heads_master + pfxlen);
-       if (!memcmp(null_sha1, sha1, 20))
+       if (is_null_sha1(sha1))
                return error("HEAD: not a valid git pointer");
        return 0;
 }
index f0e8831..8832573 100755 (executable)
@@ -51,9 +51,6 @@ patch=$tmp-patch
 mkdir $patch
 trap "rm -rf $tmp-*" 0 1 2 3 15
 
-_x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
-_x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
-
 for c in $inup
 do
        git-diff-tree -p $c
index b2e1895..91f2b0d 100644 (file)
@@ -172,7 +172,4 @@ static inline int sane_case(int x, int high)
        return x;
 }
 
-#ifndef MAXPATHLEN
-#define MAXPATHLEN 256
-#endif
 #endif
index 36fc8ce..3133b5b 100755 (executable)
@@ -3,9 +3,6 @@
 USAGE='[--mixed | --soft | --hard]  [<commit-ish>]'
 . git-sh-setup
 
-tmp=${GIT_DIR}/reset.$$
-trap 'rm -f $tmp-*' 0 1 2 3 15
-
 update=
 reset_type=--mixed
 case "$1" in
index a83c7e9..746c525 100755 (executable)
@@ -510,7 +510,7 @@ foreach my $t (@files) {
                                        if ($2 eq $from) {
                                                next if ($suppress_from);
                                        }
-                                       else {
+                                       elsif ($1 eq 'From') {
                                                $author_not_sender = $2;
                                        }
                                        printf("(mbox) Adding cc: %s from line '%s'\n",
index 0d58bb9..0290850 100755 (executable)
@@ -51,7 +51,8 @@ my ($_revision,$_stdin,$_no_ignore_ext,$_no_stop_copy,$_help,$_rmdir,$_edit,
        $_message, $_file, $_follow_parent, $_no_metadata,
        $_template, $_shared, $_no_default_regex, $_no_graft_copy,
        $_limit, $_verbose, $_incremental, $_oneline, $_l_fmt, $_show_commit,
-       $_version, $_upgrade, $_authors, $_branch_all_refs, @_opt_m);
+       $_version, $_upgrade, $_authors, $_branch_all_refs, @_opt_m,
+       $_merge, $_strategy, $_dry_run);
 my (@_branch_from, %tree_map, %users, %rusers, %equiv);
 my ($_svn_co_url_revs, $_svn_pg_peg_revs);
 my @repo_path_split_cache;
@@ -118,6 +119,11 @@ my %cmd = (
                        { 'message|m=s' => \$_message,
                          'file|F=s' => \$_file,
                        %cmt_opts } ],
+       dcommit => [ \&dcommit, 'Commit several diffs to merge with upstream',
+                       { 'merge|m|M' => \$_merge,
+                         'strategy|s=s' => \$_strategy,
+                         'dry-run|n' => \$_dry_run,
+                       %cmt_opts } ],
 );
 
 my $cmd;
@@ -500,6 +506,8 @@ sub commit_lib {
        my @lock = $SVN::Core::VERSION ge '1.2.0' ? (undef, 0) : ();
        my $commit_msg = "$GIT_SVN_DIR/.svn-commit.tmp.$$";
 
+       my $repo;
+       ($repo, $SVN_PATH) = repo_path_split($SVN_URL);
        set_svn_commit_env();
        foreach my $c (@revs) {
                my $log_msg = get_commit_message($c, $commit_msg);
@@ -508,6 +516,8 @@ sub commit_lib {
                # can't track down... (it's probably in the SVN code)
                defined(my $pid = open my $fh, '-|') or croak $!;
                if (!$pid) {
+                       $SVN_LOG = libsvn_connect($repo);
+                       $SVN = libsvn_connect($repo);
                        my $ed = SVN::Git::Editor->new(
                                        {       r => $r_last,
                                                ra => $SVN,
@@ -557,6 +567,33 @@ sub commit_lib {
        unlink $commit_msg;
 }
 
+sub dcommit {
+       my $gs = "refs/remotes/$GIT_SVN";
+       chomp(my @refs = safe_qx(qw/git-rev-list --no-merges/, "$gs..HEAD"));
+       foreach my $d (reverse @refs) {
+               if ($_dry_run) {
+                       print "diff-tree $d~1 $d\n";
+               } else {
+                       commit_diff("$d~1", $d);
+               }
+       }
+       return if $_dry_run;
+       fetch();
+       my @diff = safe_qx(qw/git-diff-tree HEAD/, $gs);
+       my @finish;
+       if (@diff) {
+               @finish = qw/rebase/;
+               push @finish, qw/--merge/ if $_merge;
+               push @finish, "--strategy=$_strategy" if $_strategy;
+               print STDERR "W: HEAD and $gs differ, using @finish:\n", @diff;
+       } else {
+               print "No changes between current HEAD and $gs\n",
+                     "Hard resetting to the latest $gs\n";
+               @finish = qw/reset --hard/;
+       }
+       sys('git', @finish, $gs);
+}
+
 sub show_ignore {
        $SVN_URL ||= file_to_s("$GIT_SVN_DIR/info/url");
        $_use_lib ? show_ignore_lib() : show_ignore_cmd();
@@ -782,6 +819,7 @@ sub commit_diff {
        } else {
                $ed->close_edit;
        }
+       $_message = $_file = undef;
 }
 
 ########################### utility functions #########################
diff --git a/git.c b/git.c
index 18ba14a..bd07289 100644 (file)
--- a/git.c
+++ b/git.c
@@ -92,7 +92,7 @@ static int handle_options(const char*** argv, int* argc)
 }
 
 static const char *alias_command;
-static char *alias_string = NULL;
+static char *alias_string;
 
 static int git_alias_config(const char *var, const char *value)
 {
@@ -120,7 +120,7 @@ static int split_cmdline(char *cmdline, const char ***argv)
                                ; /* skip */
                        if (count >= size) {
                                size += 16;
-                               *argv = realloc(*argv, sizeof(char*) * size);
+                               *argv = xrealloc(*argv, sizeof(char*) * size);
                        }
                        (*argv)[count++] = cmdline + dst;
                } else if(!quoted && (c == '\'' || c == '"')) {
@@ -191,8 +191,8 @@ static int handle_alias(int *argcp, const char ***argv)
                        fflush(stderr);
                }
 
-               new_argv = realloc(new_argv, sizeof(char*) *
-                                  (count + *argcp + 1));
+               new_argv = xrealloc(new_argv, sizeof(char*) *
+                                   (count + *argcp + 1));
                /* insert after command name */
                memcpy(new_argv + count, *argv + 1, sizeof(char*) * *argcp);
                new_argv[count+*argcp] = NULL;
@@ -213,8 +213,8 @@ static int handle_alias(int *argcp, const char ***argv)
 
 const char git_version_string[] = GIT_VERSION;
 
-#define NEEDS_PREFIX 1
-#define USE_PAGER 2
+#define RUN_SETUP      (1<<0)
+#define USE_PAGER      (1<<1)
 
 static void handle_internal_command(int argc, const char **argv, char **envp)
 {
@@ -224,47 +224,54 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
                int (*fn)(int, const char **, const char *);
                int option;
        } commands[] = {
-               { "version", cmd_version },
-               { "help", cmd_help },
-               { "log", cmd_log, NEEDS_PREFIX | USE_PAGER },
-               { "whatchanged", cmd_whatchanged, NEEDS_PREFIX | USE_PAGER },
-               { "show", cmd_show, NEEDS_PREFIX | USE_PAGER },
-               { "push", cmd_push, NEEDS_PREFIX },
-               { "format-patch", cmd_format_patch, NEEDS_PREFIX },
+               { "add", cmd_add, RUN_SETUP },
+               { "apply", cmd_apply },
+               { "cat-file", cmd_cat_file, RUN_SETUP },
+               { "checkout-index", cmd_checkout_index, RUN_SETUP },
+               { "check-ref-format", cmd_check_ref_format },
+               { "commit-tree", cmd_commit_tree, RUN_SETUP },
                { "count-objects", cmd_count_objects },
-               { "diff", cmd_diff, NEEDS_PREFIX },
-               { "grep", cmd_grep, NEEDS_PREFIX },
-               { "rm", cmd_rm, NEEDS_PREFIX },
-               { "add", cmd_add, NEEDS_PREFIX },
-               { "rev-list", cmd_rev_list, NEEDS_PREFIX },
-               { "init-db", cmd_init_db },
+               { "diff", cmd_diff, RUN_SETUP },
+               { "diff-files", cmd_diff_files, RUN_SETUP },
+               { "diff-index", cmd_diff_index, RUN_SETUP },
+               { "diff-stages", cmd_diff_stages, RUN_SETUP },
+               { "diff-tree", cmd_diff_tree, RUN_SETUP },
+               { "fmt-merge-msg", cmd_fmt_merge_msg, RUN_SETUP },
+               { "format-patch", cmd_format_patch, RUN_SETUP },
                { "get-tar-commit-id", cmd_get_tar_commit_id },
-               { "upload-tar", cmd_upload_tar },
-               { "check-ref-format", cmd_check_ref_format },
-               { "ls-files", cmd_ls_files, NEEDS_PREFIX },
-               { "ls-tree", cmd_ls_tree, NEEDS_PREFIX },
-               { "tar-tree", cmd_tar_tree, NEEDS_PREFIX },
-               { "read-tree", cmd_read_tree, NEEDS_PREFIX },
-               { "commit-tree", cmd_commit_tree, NEEDS_PREFIX },
-               { "apply", cmd_apply },
-               { "show-branch", cmd_show_branch, NEEDS_PREFIX },
-               { "diff-files", cmd_diff_files, NEEDS_PREFIX },
-               { "diff-index", cmd_diff_index, NEEDS_PREFIX },
-               { "diff-stages", cmd_diff_stages, NEEDS_PREFIX },
-               { "diff-tree", cmd_diff_tree, NEEDS_PREFIX },
-               { "cat-file", cmd_cat_file, NEEDS_PREFIX },
-               { "rev-parse", cmd_rev_parse, NEEDS_PREFIX },
-               { "write-tree", cmd_write_tree, NEEDS_PREFIX },
-               { "mailsplit", cmd_mailsplit },
+               { "grep", cmd_grep, RUN_SETUP },
+               { "help", cmd_help },
+               { "init-db", cmd_init_db },
+               { "log", cmd_log, RUN_SETUP | USE_PAGER },
+               { "ls-files", cmd_ls_files, RUN_SETUP },
+               { "ls-tree", cmd_ls_tree, RUN_SETUP },
                { "mailinfo", cmd_mailinfo },
-               { "stripspace", cmd_stripspace },
-               { "update-index", cmd_update_index, NEEDS_PREFIX },
-               { "update-ref", cmd_update_ref, NEEDS_PREFIX },
-               { "fmt-merge-msg", cmd_fmt_merge_msg, NEEDS_PREFIX },
-               { "prune", cmd_prune, NEEDS_PREFIX },
-               { "mv", cmd_mv, NEEDS_PREFIX },
-               { "prune-packed", cmd_prune_packed, NEEDS_PREFIX },
+               { "mailsplit", cmd_mailsplit },
+               { "mv", cmd_mv, RUN_SETUP },
+               { "name-rev", cmd_name_rev, RUN_SETUP },
+               { "pack-objects", cmd_pack_objects, RUN_SETUP },
+               { "prune", cmd_prune, RUN_SETUP },
+               { "prune-packed", cmd_prune_packed, RUN_SETUP },
+               { "push", cmd_push, RUN_SETUP },
+               { "read-tree", cmd_read_tree, RUN_SETUP },
                { "repo-config", cmd_repo_config },
+               { "rev-list", cmd_rev_list, RUN_SETUP },
+               { "rev-parse", cmd_rev_parse, RUN_SETUP },
+               { "rm", cmd_rm, RUN_SETUP },
+               { "show-branch", cmd_show_branch, RUN_SETUP },
+               { "show", cmd_show, RUN_SETUP | USE_PAGER },
+               { "stripspace", cmd_stripspace },
+               { "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
+               { "tar-tree", cmd_tar_tree, RUN_SETUP },
+               { "zip-tree", cmd_zip_tree, RUN_SETUP },
+               { "unpack-objects", cmd_unpack_objects, RUN_SETUP },
+               { "update-index", cmd_update_index, RUN_SETUP },
+               { "update-ref", cmd_update_ref, RUN_SETUP },
+               { "upload-tar", cmd_upload_tar },
+               { "version", cmd_version },
+               { "whatchanged", cmd_whatchanged, RUN_SETUP | USE_PAGER },
+               { "write-tree", cmd_write_tree, RUN_SETUP },
+               { "verify-pack", cmd_verify_pack },
        };
        int i;
 
@@ -281,16 +288,16 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
                        continue;
 
                prefix = NULL;
-               if (p->option & NEEDS_PREFIX)
+               if (p->option & RUN_SETUP)
                        prefix = setup_git_directory();
                if (p->option & USE_PAGER)
                        setup_pager();
                if (getenv("GIT_TRACE")) {
-                       int i;
+                       int j;
                        fprintf(stderr, "trace: built-in: git");
-                       for (i = 0; i < argc; ++i) {
+                       for (j = 0; j < argc; ++j) {
                                fputc(' ', stderr);
-                               sq_quote_print(stderr, argv[i]);
+                               sq_quote_print(stderr, argv[j]);
                        }
                        putc('\n', stderr);
                        fflush(stderr);
index 8d67276..27c6dac 100644 (file)
@@ -5,5 +5,33 @@ The one working on:
 
 From the git version 1.4.0 gitweb is bundled with git.
 
-Any comment/question/concern to:
+
+How to configure gitweb for your local system:
+
+You can specify the following configuration variables when building GIT:
+ * GITWEB_SITENAME
+   Shown in the title of all generated pages, defaults to the servers name.
+ * GITWEB_PROJECTROOT
+   The root directory for all projects shown by gitweb.
+ * GITWEB_LIST
+   points to a directory to scan for projects (defaults to project root)
+   or to a file for explicit listing of projects.
+ * GITWEB_HOMETEXT
+   points to an .html file which is included on the gitweb project
+   overview page.
+ * GITWEB_CSS
+   Points to the location where you put gitweb.css on your web server.
+ * GITWEB_LOGO
+   Points to the location where you put git-logo.png on your web server.
+ * GITWEB_CONFIG
+   This file will be loaded using 'require'.  If the environment
+   $GITWEB_CONFIG is set when gitweb.cgi is executed the file in the
+   environment variable will be loaded instead of the file
+   specified when gitweb.cgi was created.
+
+Originally written by:
   Kay Sievers <kay.sievers@vrfy.org>
+
+Any comment/question/concern to:
+  Git mailing list <git@vger.kernel.org>
+
diff --git a/gitweb/git-logo.png b/gitweb/git-logo.png
new file mode 100644 (file)
index 0000000..16ae8d5
Binary files /dev/null and b/gitweb/git-logo.png differ
index fffdb13..9013895 100644 (file)
@@ -117,9 +117,14 @@ div.list_head {
 
 a.list {
        text-decoration: none;
+       font-weight: bold;
        color: #000000;
 }
 
+table.tags a.list {
+       font-weight: normal;
+}
+
 a.list:hover {
        text-decoration: underline;
        color: #880000;
@@ -171,6 +176,10 @@ tr.dark {
        background-color: #f6f6f0;
 }
 
+tr.dark2 {
+       background-color: #f6f6f0;
+}
+
 tr.dark:hover {
        background-color: #edece6;
 }
@@ -181,12 +190,16 @@ td {
        vertical-align: top;
 }
 
-td.link {
+td.link, td.selflink {
        padding: 2px 5px;
        font-family: sans-serif;
        font-size: 10px;
 }
 
+td.selflink {
+       padding-right: 0px;
+}
+
 td.sha1 {
        font-family: monospace;
 }
@@ -196,6 +209,10 @@ td.error {
        background-color: yellow;
 }
 
+td.current_head {
+       text-decoration: underline;
+}
+
 table.diff_tree span.file_status.new {
        color: #008000;
 }
@@ -209,6 +226,10 @@ table.diff_tree span.file_status.mode_chnge {
        color: #777777;
 }
 
+table.diff_tree span.file_status.copied {
+  color: #70a070;
+}
+
 /* age2: 60*60*24*2 <= age */
 table.project_list td.age2, table.blame td.age2 {
        font-style: italic;
@@ -309,15 +330,30 @@ a.rss_logo:hover {
        background-color: #ee5500;
 }
 
-span.tag {
+span.refs span {
        padding: 0px 4px;
        font-size: 10px;
        font-weight: normal;
-       background-color: #ffffaa;
        border: 1px solid;
+       background-color: #ffaaff;
+       border-color: #ffccff #ff00ee #ff00ee #ffccff;
+}
+
+span.refs span.ref {
+       background-color: #aaaaff;
+       border-color: #ccccff #0033cc #0033cc #ccccff;
+}
+
+span.refs span.tag {
+       background-color: #ffffaa;
        border-color: #ffffcc #ffee00 #ffee00 #ffffcc;
 }
 
+span.refs span.head {
+       background-color: #aaffaa;
+       border-color: #ccffcc #00cc33 #00cc33 #ccffcc;
+}
+
 span.atnight {
        color: #cc0000;
 }
similarity index 51%
rename from gitweb/gitweb.cgi
rename to gitweb/gitweb.perl
index e5fca63..966c54a 100755 (executable)
@@ -14,47 +14,49 @@ use CGI::Util qw(unescape);
 use CGI::Carp qw(fatalsToBrowser);
 use Encode;
 use Fcntl ':mode';
+use File::Find qw();
 binmode STDOUT, ':utf8';
 
 our $cgi = new CGI;
-our $version = "267";
+our $version = "++GIT_VERSION++";
 our $my_url = $cgi->url();
 our $my_uri = $cgi->url(-absolute => 1);
-our $rss_link = "";
 
 # core git executable to use
 # this can just be "git" if your webserver has a sensible PATH
-our $GIT = "/usr/bin/git";
+our $GIT = "++GIT_BINDIR++/git";
 
 # absolute fs-path which will be prepended to the project path
 #our $projectroot = "/pub/scm";
-our $projectroot = "/home/kay/public_html/pub/scm";
-
-# version of the core git binary
-our $git_version = qx($GIT --version) =~ m/git version (.*)$/ ? $1 : "unknown";
+our $projectroot = "++GITWEB_PROJECTROOT++";
 
 # location for temporary files needed for diffs
 our $git_temp = "/tmp/gitweb";
-if (! -d $git_temp) {
-    mkdir($git_temp, 0700) || die_error("Couldn't mkdir $git_temp");
-}
 
 # target of the home link on top of all pages
 our $home_link = $my_uri;
 
+# string of the home link on top of all pages
+our $home_link_str = "++GITWEB_HOME_LINK_STR++";
+
 # name of your site or organization to appear in page titles
 # replace this with something more descriptive for clearer bookmarks
-our $site_name = $ENV{'SERVER_NAME'} || "Untitled";
+our $site_name = "++GITWEB_SITENAME++" || $ENV{'SERVER_NAME'} || "Untitled";
 
 # html text to include at home page
-our $home_text = "indextext.html";
+our $home_text = "++GITWEB_HOMETEXT++";
 
 # URI of d