Merge branch 'ts/daemon'
authorJunio C Hamano <junkio@cox.net>
Mon, 28 Aug 2006 00:51:42 +0000 (17:51 -0700)
committerJunio C Hamano <junkio@cox.net>
Mon, 28 Aug 2006 00:51:42 +0000 (17:51 -0700)
* ts/daemon:
Added support for dropping privileges to git-daemon.

74 files changed:
Documentation/git-apply.txt
Documentation/git-blame.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
Makefile
blame.c
builtin-apply.c
builtin-cat-file.c
builtin-checkout-index.c
builtin-diff.c
builtin-fmt-merge-msg.c
builtin-grep.c
builtin-log.c
builtin-mv.c
builtin-pack-objects.c
builtin-push.c
builtin-read-tree.c
builtin-tar-tree.c
builtin-unpack-objects.c
builtin-update-index.c
builtin-update-ref.c
builtin-write-tree.c
builtin-zip-tree.c [new file with mode: 0644]
builtin.h
cache-tree.c
cache.h
combine-diff.c
commit.c
connect.c
contrib/gitview/gitview.txt
convert-objects.c
csum-file.c
daemon.c
date.c
describe.c
diff-delta.c
diff-lib.c
diff.c
dir.c
entry.c
environment.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/gitweb.perl
http-fetch.c
http-push.c
index-pack.c
mktree.c
object.c
patch-id.c
receive-pack.c
refs.c
revision.c
send-pack.c
sha1_file.c
sha1_name.c
t/t4116-apply-reverse.sh
t/t4117-apply-reject.sh [new file with mode: 0755]
tree-walk.c
tree.c
unpack-trees.c
upload-pack.c
xdiff-interface.c
index 2ff74949a73aa8670750105a7d292206877477c7..c76cfffdc6cd9982aa02e34b2b09fc22897e7402 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 bfed945914c5de74d6f46e51ee8fbe459e4d8420..e1f89444a95618a1e520940a79389c854cf9d576 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 ae4c1a250e835bd39ee291088ba74c3c57604ac9..c8a4c5a4d9d2bead8686f1b582e985531a7f3591 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 7d868098448c7cc6712988c7bb1df541aedf6824..b7b63f7136a01d6f3383346c292e5c8aceb8ced4 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 3ae6e74573d1b5f651f8dabc6c9569b05e049b10..41bb7e12e3d89e4876a60ea7733cffcaf09cd6ed 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 3de5fa9c82de4d49a041480ce6681f69a97f167c..a9c87e38dae69b0799328917727867342eb5d22c 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
 -----------
index cb482bf98ef9e2509ab2d2e1665933687538a574..23be0050b0023cbfecc5fa271b97a7d9855a73b0 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
 ---
index b15b420ea218b23a53548577bdc874f8484a6d78..d9741f917f0dab4d9a7e98764fdb04d8f3443cb4 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -292,7 +292,8 @@ BUILTIN_OBJS = \
        builtin-update-ref.o \
        builtin-upload-tar.o \
        builtin-verify-pack.o \
-       builtin-write-tree.o
+       builtin-write-tree.o \
+       builtin-zip-tree.o
 
 GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
 LIBS = $(GITLIBS) -lz
diff --git a/blame.c b/blame.c
index c253b9ca45cf7d860052ddae95bc1ed34974ffb8..8968046b0045633e6046c3126978819e9910a5f2 100644 (file)
--- a/blame.c
+++ b/blame.c
@@ -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;
 }
 
index 4f0eef0ac3c2d20475b0b50e81f4d51cd4f95396..b47ccacc2e0618476ca4816e111a97b2c46f0f4f 100644 (file)
@@ -38,12 +38,14 @@ static int summary;
 static int check;
 static int apply = 1;
 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,
@@ -122,6 +124,7 @@ struct fragment {
        unsigned long newpos, newlines;
        const char *patch;
        int size;
+       int rejected;
        struct fragment *next;
 };
 
@@ -138,6 +141,7 @@ 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;
+       int rejected;
        unsigned long deflate_origlen;
        int lines_added, lines_deleted;
        int score;
@@ -150,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)
 
@@ -606,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':
@@ -1063,8 +1083,12 @@ static struct fragment *parse_binary_hunk(char **buf_p,
                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.
                 */
@@ -1544,7 +1568,8 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
        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)
@@ -1557,8 +1582,10 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
                        /* 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) {
@@ -1568,7 +1595,9 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
                                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;
 
@@ -1618,7 +1647,7 @@ static int apply_binary_fragment(struct buffer_desc *desc, struct patch *patch)
                                     "without the reverse hunk to '%s'",
                                     patch->new_name
                                     ? patch->new_name : patch->old_name);
-               fragment = fragment;
+               fragment = fragment->next;
        }
        data = (void*) fragment->patch;
        switch (fragment->binary_patch_method) {
@@ -1717,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;
@@ -1732,9 +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->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;
@@ -1770,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)
@@ -1796,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;
@@ -1901,19 +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;
+       return err;
 }
 
 static void show_index_list(struct patch *list)
@@ -2219,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 void write_out_results(struct patch *list, int skipped_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 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;
@@ -2310,11 +2424,13 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof)
                        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);
@@ -2347,6 +2463,7 @@ int cmd_apply(int argc, const char **argv, const char *prefix)
        int i;
        int read_stdin = 1;
        int inaccurate_eof = 0;
+       int errs = 0;
 
        const char *whitespace_option = NULL;
 
@@ -2356,7 +2473,7 @@ int cmd_apply(int argc, const char **argv, const char *prefix)
                int fd;
 
                if (!strcmp(arg, "-")) {
-                       apply_patch(0, "<stdin>", inaccurate_eof);
+                       errs |= apply_patch(0, "<stdin>", inaccurate_eof);
                        read_stdin = 0;
                        continue;
                }
@@ -2437,6 +2554,14 @@ int cmd_apply(int argc, const char **argv, const char *prefix)
                        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")) {
                        inaccurate_eof = 1;
                        continue;
@@ -2457,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, inaccurate_eof);
+               errs |= apply_patch(fd, arg, inaccurate_eof);
                close(fd);
        }
        set_default_whitespace_mode(whitespace_option);
        if (read_stdin)
-               apply_patch(0, "<stdin>", 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");
                }
@@ -2496,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 7a6fa56e93034f0553e5a119180b3841cc773cb4..6c16bfa1ae4ae6207a74a8caa95564c649c4b0dd 100644 (file)
@@ -54,7 +54,7 @@ static void pprint_tag(const unsigned char *sha1, const char *buf, unsigned long
                                        write_or_die(1, tagger, sp - tagger);
                                        date = strtoul(sp, &ep, 10);
                                        tz = strtol(ep, NULL, 10);
-                                       sp = show_date(date, tz);
+                                       sp = show_date(date, tz, 0);
                                        write_or_die(1, sp, strlen(sp));
                                        xwrite(1, "\n", 1);
                                        break;
index 6b55f931cbd8b79a01057b55eb41a043a4db5e3b..b097c888a0da044d6dc78c9747eb18e45b46709d 100644 (file)
@@ -45,7 +45,7 @@
 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;
 
index 874f773421620642425e67f650de2a34396f1c0f..a6590205e8f746304f3d06d3e328a05bf2bf954e 100644 (file)
@@ -192,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;
@@ -290,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 28b5dfd054ea8277379d6913b1f1c4cde225e70d..a5ed8dbbac2a1320e7cf61e16eeccdf5c5cee915 100644 (file)
@@ -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 0bd517b2649af37d9980f85e784f9a00c3263922..8213ce240232a1dc8a0a498972323a33e8fcb7a0 100644 (file)
@@ -293,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);
 }
index 691cf3aef785950132c6be65f8aab39d4b12207e..fbc58bbcab1a992efb6ee359171d7ed6f0c52ab9 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 ff882bec474c59c9cb4bb49d723cf81febb204ad..4d21d88412cac52cbd5d127de439abc3e172b352 100644 (file)
@@ -168,13 +168,13 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
                                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));
                                }
@@ -262,10 +262,10 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
        } 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);
                }
index f19f0d60460a721dafcd232d4896231f765a979f..46f524dfc32a5eaea06df6e3502c83710a1c09bb 100644 (file)
@@ -534,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)
@@ -649,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;
@@ -799,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;
 }
index 2b5e6fa9ed18c20cda264dbaf9df9d3cbac93c0e..ada8338cc1d0fbf389cd346b5134595afaaa2e66 100644 (file)
@@ -232,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;
@@ -248,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:
@@ -262,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 53087faf7a63e6268ffff5239142a00c120dcf8f..c1867d2a0052ad797481f3d5f9aa544952ff251b 100644 (file)
@@ -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 e0bcb0a1e146c3f85fa98463a0d4bb5913a3f2b2..61a413590d74d0fb167d715aa754df1a8794c085 100644 (file)
@@ -275,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")) {
index f0ae5c987af79bc5254df7cd3587ed1852e63209..ca0ebc258563f2ea2aec94eed2de31799f3f16cc 100644 (file)
@@ -95,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;
@@ -173,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);
index 5dd91af180df0f832ecc747050ad5306efe9c8b6..0620e779b04146a01f9e06cbbcd535b106034bd6 100644 (file)
@@ -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);
@@ -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 5bd71825fdc48392952faf170efe98c072c7e482..90a3da53ad003a82781e6d4acfc7815c8f15f24f 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);
 
index ca06149f186449407c6536fcc3caa37cd4101ce3..50670dc7bf46c74e95b2e204d05afc077350a19f 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 ade58c4a1f06b161f00caa015192fa89c137d273..25431d70816634cec4ca6c54dc670ac536246277 100644 (file)
--- a/builtin.h
+++ b/builtin.h
@@ -52,6 +52,7 @@ 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);
index d9f7e1e3dd598d34e08d6370544b562daf4640d2..323c68a6709f30312e0dfb0fd60fcd7e69cd710b 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 08d6a91279c87ad1e4d7ce1be1ac927b52a6113e..ccb83a1fd5ccf9fe38e154b93b436e0021a91be6 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);
@@ -218,6 +218,14 @@ 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);
 
@@ -278,7 +286,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);
index 0682acd50d618e4ba8319372c46c72b3e479b8e6..46d9121baf2ebb024f6b19993a9b75fa3b67951a 100644 (file)
@@ -31,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;
@@ -56,8 +56,7 @@ static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr,
                        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;
@@ -927,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 00bc3de22eb670c07e78087d96d9a3cff1d0fd67..c3ff9b4175c00a600ae25f9dc90eb521d7053719 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -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' */
index 7a6a73f2a333d067c5a5442004f76ebbb9aaed17..e501ccce259e7ac1a4e92fecc713950e82d3b71a 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -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;
index 6924df286e0a85bd49ef69e29781658ba8a17339..77c29de305fabc518edf060b0e6634d9c5c9f71e 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 4e7ff7517f40f5dd5c23cd3fd6a42d3cb621aec1..631678b08a7cb83b0349f1a683d3cd7fb797fb7a 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++;
@@ -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 e2278897d08b750f383ae5bb2ac7e738a99a7ae5..b7174c6c056c5a8f2a800ecbcb3cdf304c0bfc3f 100644 (file)
@@ -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 dd3915a07ab63621a55f7c9404659c1039d336cd..66ec830b7cab775e16c3fe06539e698edd6b7aff 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -529,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)
@@ -563,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)
diff --git a/date.c b/date.c
index 66be23ab21ef855ecbadeceae1dea2972efd4c2f..e387dcd3976d8e12afdce5d7600ca0022f4ca835 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 2b9301fc1205795e30dfd7a7493cb03cdebdb437..5dd8b2e3977a2ff724ca208621f76a898cff0389 100644 (file)
@@ -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 7da9205a5da6a4f016bc6b556bee01895cdcc19d..fa16d06c8d1e85a458428c673cb2f589857f5424 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 3e4b3b96b71925974eee5f1f691158c314722011..9edfa9262622c64edecfaf7b4f72a79873b8882a 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 =
diff --git a/diff.c b/diff.c
index da7cca1952e7e245730bd81419e1b23ce57ef173..70699fd8c48754215934a8ed45db336b9db68918 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -838,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;
@@ -849,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.
         */
@@ -898,6 +897,13 @@ 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)
 {
@@ -1101,7 +1107,7 @@ void fill_filespec(struct diff_filespec *spec, const unsigned char *sha1,
 {
        if (mode) {
                spec->mode = canon_mode(mode);
-               memcpy(spec->sha1, sha1, 20);
+               hashcpy(spec->sha1, sha1);
                spec->sha1_valid = !is_null_sha1(sha1);
        }
 }
@@ -1194,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;
 }
@@ -1516,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)
diff --git a/dir.c b/dir.c
index 092d07736c60d4c6d86201ebeb841498c3be92a0..d53d48f70c7f07a3fe5e6851467fc566b341aeb9 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);
diff --git a/entry.c b/entry.c
index 793724fd52063157545f523f6d88953b96385c2c..b2ea0efa82e1a0511fe5aa798618c23827b59bab 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 e6bd0033b4666f52dc756b6e2b0d5a1745b0c6b9..5fae9ac3056dd00beba3b9a13be99f7bb39d584e 100644 (file)
@@ -25,8 +25,9 @@ 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 e18c1489a1ab8620cade351ec502828b10a41ac4..377feded1ccafdece86499d1917d297145fd28ac 100644 (file)
@@ -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 aeb6bf2639cc75b6f738348bcc267179a8a0da65..ef60b045eaa0a55ba65499187a3aac082ffb6af2 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 31e00d84b30f95c713b3dc6a654b4ef8459c6729..ae0ec8d039cfce698daa8a9f44c7f49b932373c8 100644 (file)
@@ -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();
index f0e8831fa49ae46eb7ad664b6ad489e3974c9f91..8832573fee9d3b8d4be92786ae5116ee6e5405bb 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 b2e18954c03ff502053cb74d142faab7d2a8dacb..91f2b0d3f0cf9d8539e7e09adc057dc337caae21 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 36fc8ce25b39682ba256a8d39bf9a393907ef43d..3133b5bd25ca7ad3c2a5451ee9c2e0f4514cd980 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 a83c7e90948fc3fe1b1ac82335704d66d060edab..746c525079317491e35827f331922e17e5fbd089 100755 (executable)
@@ -510,7 +510,7 @@ sub send_message
                                        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 0d58bb9b37944728baa7d8af17d714f6ee8b4509..0290850b6639b4865d0941089d00a8c2ac5de366 100755 (executable)
@@ -51,7 +51,8 @@
        $_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;
                        { '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 930998bbe542cbaa92b3f16a6b0dc0d6ad43b874..bd07289d71a75ad0280bae21c64c4c4be86f80d2 100644 (file)
--- a/git.c
+++ b/git.c
@@ -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;
@@ -263,6 +263,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
                { "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 },
@@ -292,11 +293,11 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
                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 04282fa5e381c1dc156085281e8517fb69be6192..966c54a63cacf20d2a71241f738df0378e46f569 100755 (executable)
@@ -1882,7 +1882,7 @@ sub git_blame {
                chomp $line;
                $line_class_num = ($line_class_num + 1) % $line_class_len;
 
-               if ($line =~ m/^([0-9a-fA-F]{40})\t\(\s*([^\t]+)\t(\d+) \+\d\d\d\d\t(\d+)\)(.*)$/) {
+               if ($line =~ m/^([0-9a-fA-F]{40})\t\(\s*([^\t]+)\t(\d+) [+-]\d\d\d\d\t(\d+)\)(.*)$/) {
                        $long_rev = $1;
                        $author   = $2;
                        $time     = $3;
index d1f74b443be23e8cd7f10128713217acfab5254b..7619b338feb92a431268fc5a3963415af1b53e99 100644 (file)
@@ -393,7 +393,7 @@ void prefetch(unsigned char *sha1)
        char *filename = sha1_file_name(sha1);
 
        newreq = xmalloc(sizeof(*newreq));
-       memcpy(newreq->sha1, sha1, 20);
+       hashcpy(newreq->sha1, sha1);
        newreq->repo = alt;
        newreq->url = NULL;
        newreq->local = -1;
index 48497797f1650a2ed3f24010a85123993b14d8aa..04cb238e965efdff564a9b57ce1253b274268c46 100644 (file)
@@ -1700,7 +1700,7 @@ static int locking_available(void)
        return lock_flags;
 }
 
-struct object_list **add_one_object(struct object *obj, struct object_list **p)
+static struct object_list **add_one_object(struct object *obj, struct object_list **p)
 {
        struct object_list *entry = xmalloc(sizeof(struct object_list));
        entry->item = obj;
@@ -1874,7 +1874,7 @@ static int one_local_ref(const char *refname, const unsigned char *sha1)
        struct ref *ref;
        int len = strlen(refname) + 1;
        ref = xcalloc(1, sizeof(*ref) + len);
-       memcpy(ref->new_sha1, sha1, 20);
+       hashcpy(ref->new_sha1, sha1);
        memcpy(ref->name, refname, len);
        *local_tail = ref;
        local_tail = &ref->next;
@@ -1909,7 +1909,7 @@ static void one_remote_ref(char *refname)
        }
 
        ref = xcalloc(1, sizeof(*ref) + len);
-       memcpy(ref->old_sha1, remote_sha1, 20);
+       hashcpy(ref->old_sha1, remote_sha1);
        memcpy(ref->name, refname, len);
        *remote_tail = ref;
        remote_tail = &ref->next;
@@ -2164,7 +2164,7 @@ static void fetch_symref(const char *path, char **symref, unsigned char *sha1)
        if (*symref != NULL)
                free(*symref);
        *symref = NULL;
-       memset(sha1, 0, 20);
+       hashclr(sha1);
 
        if (buffer.posn == 0)
                return;
@@ -2445,7 +2445,7 @@ int main(int argc, char **argv)
                                continue;
                        }
                }
-               memcpy(ref->new_sha1, ref->peer_ref->new_sha1, 20);
+               hashcpy(ref->new_sha1, ref->peer_ref->new_sha1);
                if (is_zero_sha1(ref->new_sha1)) {
                        error("cannot happen anymore");
                        rc = -3;
index 96ea6874634959c18263779a01f8385ee9ffde1e..80bc6cb45b1a91c31dbdf18b48399b7a7a6b2737 100644 (file)
@@ -161,7 +161,7 @@ static void *unpack_raw_entry(unsigned long offset,
        case OBJ_DELTA:
                if (pos + 20 >= pack_limit)
                        bad_object(offset, "object extends past end of pack");
-               memcpy(delta_base, pack_base + pos, 20);
+               hashcpy(delta_base, pack_base + pos);
                pos += 20;
                /* fallthru */
        case OBJ_COMMIT:
@@ -304,7 +304,7 @@ static void parse_pack_objects(void)
                if (obj->type == OBJ_DELTA) {
                        struct delta_entry *delta = &deltas[nr_deltas++];
                        delta->obj = obj;
-                       memcpy(delta->base_sha1, base_sha1, 20);
+                       hashcpy(delta->base_sha1, base_sha1);
                } else
                        sha1_object(data, data_size, obj->type, obj->sha1);
                free(data);
index 93241385e4aee76fc42db5849365740c474b9bdd..56205d1e0053cdcb7236bde199817a5529d3f433 100644 (file)
--- a/mktree.c
+++ b/mktree.c
@@ -30,7 +30,7 @@ static void append_to_tree(unsigned mode, unsigned char *sha1, char *path)
        ent = entries[used++] = xmalloc(sizeof(**entries) + len + 1);
        ent->mode = mode;
        ent->len = len;
-       memcpy(ent->sha1, sha1, 20);
+       hashcpy(ent->sha1, sha1);
        memcpy(ent->name, path, len+1);
 }
 
@@ -64,7 +64,7 @@ static void write_tree(unsigned char *sha1)
                offset += sprintf(buffer + offset, "%o ", ent->mode);
                offset += sprintf(buffer + offset, "%s", ent->name);
                buffer[offset++] = 0;
-               memcpy(buffer + offset, ent->sha1, 20);
+               hashcpy((unsigned char*)buffer + offset, ent->sha1);
                offset += 20;
        }
        write_sha1_file(buffer, offset, tree_type, sha1);
index fdcfff7c86057bf8e5a7285518f186c67a1715bb..60bf16b902033d9f256282201ca7aeca74855d7e 100644 (file)
--- a/object.c
+++ b/object.c
@@ -91,7 +91,7 @@ void created_object(const unsigned char *sha1, struct object *obj)
        obj->used = 0;
        obj->type = OBJ_NONE;
        obj->flags = 0;
-       memcpy(obj->sha1, sha1, 20);
+       hashcpy(obj->sha1, sha1);
 
        if (obj_hash_size - 1 <= nr_objs * 2)
                grow_object_hash();
index 3b4c80f764bd11a740a7cce60f2e8c062706e897..086d2d9c68835c6a7434932f6e3b430e0906578d 100644 (file)
@@ -47,7 +47,7 @@ static void generate_id_list(void)
 
                if (!get_sha1_hex(p, n)) {
                        flush_current_id(patchlen, sha1, &ctx);
-                       memcpy(sha1, n, 20);
+                       hashcpy(sha1, n);
                        patchlen = 0;
                        continue;
                }
index 81e91909b8ac88423c550a6489285b003378c5f0..201531626c2a60dffd1720ab4d00d7023bcbc78e 100644 (file)
@@ -247,8 +247,8 @@ static void read_head_info(void)
                                report_status = 1;
                }
                cmd = xmalloc(sizeof(struct command) + len - 80);
-               memcpy(cmd->old_sha1, old_sha1, 20);
-               memcpy(cmd->new_sha1, new_sha1, 20);
+               hashcpy(cmd->old_sha1, old_sha1);
+               hashcpy(cmd->new_sha1, new_sha1);
                memcpy(cmd->ref_name, line + 82, len - 81);
                cmd->error_string = "n/a (unpacker error)";
                cmd->next = NULL;
diff --git a/refs.c b/refs.c
index 17cd0cef3c9819d70083554f99d8f09391171db1..e70ef0ae0fe58671a35b71a55fbf81425ee84581 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -29,7 +29,7 @@ const char *resolve_ref(const char *path, unsigned char *sha1, int reading)
                if (lstat(path, &st) < 0) {
                        if (reading || errno != ENOENT)
                                return NULL;
-                       memset(sha1, 0, 20);
+                       hashclr(sha1);
                        return path;
                }
 
index 5a91d06b980d710e30a80c353a636ca1ca6b9a55..1d89d72738ff917d29373d50c2c2cc9bbd10b2c0 100644 (file)
@@ -496,7 +496,7 @@ static int add_parents_only(struct rev_info *revs, const char *arg, int flags)
                it = get_reference(revs, arg, sha1, 0);
                if (it->type != OBJ_TAG)
                        break;
-               memcpy(sha1, ((struct tag*)it)->tagged->sha1, 20);
+               hashcpy(sha1, ((struct tag*)it)->tagged->sha1);
        }
        if (it->type != OBJ_COMMIT)
                return 0;
index f7c0cfc6f67ba4d325ac6fc9f6c74fad78d1208e..fd79a61923ddc20af216ccd252e40bf38a70eccb 100644 (file)
@@ -185,7 +185,7 @@ static int one_local_ref(const char *refname, const unsigned char *sha1)
        struct ref *ref;
        int len = strlen(refname) + 1;
        ref = xcalloc(1, sizeof(*ref) + len);
-       memcpy(ref->new_sha1, sha1, 20);
+       hashcpy(ref->new_sha1, sha1);
        memcpy(ref->name, refname, len);
        *local_tail = ref;
        local_tail = &ref->next;
@@ -310,7 +310,7 @@ static int send_pack(int in, int out, int nr_refspec, char **refspec)
                                continue;
                        }
                }
-               memcpy(ref->new_sha1, ref->peer_ref->new_sha1, 20);
+               hashcpy(ref->new_sha1, ref->peer_ref->new_sha1);
                if (is_zero_sha1(ref->new_sha1)) {
                        error("cannot happen anymore");
                        ret = -3;
index 066cff1fa6e8dd1485876984becdecd7bb4987b6..46272b591645e444396ae683673620594f336a7c 100644 (file)
@@ -540,7 +540,7 @@ struct packed_git *add_packed_git(char *path, int path_len, int local)
        p->pack_use_cnt = 0;
        p->pack_local = local;
        if ((path_len > 44) && !get_sha1_hex(path + path_len - 44, sha1))
-               memcpy(p->sha1, sha1, 20);
+               hashcpy(p->sha1, sha1);
        return p;
 }
 
@@ -571,7 +571,7 @@ struct packed_git *parse_pack_index_file(const unsigned char *sha1, char *idx_pa
        p->pack_base = NULL;
        p->pack_last_used = 0;
        p->pack_use_cnt = 0;
-       memcpy(p->sha1, sha1, 20);
+       hashcpy(p->sha1, sha1);
        return p;
 }
 
@@ -917,23 +917,19 @@ static unsigned long unpack_object_header(struct packed_git *p, unsigned long of
        enum object_type *type, unsigned long *sizep)
 {
        unsigned shift;
-       unsigned char *pack, c;
+       unsigned char c;
        unsigned long size;
 
        if (offset >= p->pack_size)
                die("object offset outside of pack file");
-
-       pack =  (unsigned char *) p->pack_base + offset;
-       c = *pack++;
-       offset++;
+       c = *((unsigned char *)p->pack_base + offset++);
        *type = (c >> 4) & 7;
        size = c & 15;
        shift = 4;
        while (c & 0x80) {
                if (offset >= p->pack_size)
                        die("object offset outside of pack file");
-               c = *pack++;
-               offset++;
+               c = *((unsigned char *)p->pack_base + offset++);
                size += (c & 0x7f) << shift;
                shift += 7;
        }
@@ -953,7 +949,7 @@ int check_reuse_pack_delta(struct packed_git *p, unsigned long offset,
        ptr = unpack_object_header(p, ptr, kindp, sizep);
        if (*kindp != OBJ_DELTA)
                goto done;
-       memcpy(base, (unsigned char *) p->pack_base + ptr, 20);
+       hashcpy(base, (unsigned char *) p->pack_base + ptr);
        status = 0;
  done:
        unuse_packed_git(p);
@@ -981,7 +977,7 @@ void packed_object_info_detail(struct pack_entry *e,
                if (p->pack_size <= offset + 20)
                        die("pack file %s records an incomplete delta base",
                            p->pack_name);
-               memcpy(base_sha1, pack, 20);
+               hashcpy(base_sha1, pack);
                do {
                        struct pack_entry base_ent;
                        unsigned long junk;
@@ -996,16 +992,10 @@ void packed_object_info_detail(struct pack_entry *e,
        }
        switch (kind) {
        case OBJ_COMMIT:
-               strcpy(type, commit_type);
-               break;
        case OBJ_TREE:
-               strcpy(type, tree_type);
-               break;
        case OBJ_BLOB:
-               strcpy(type, blob_type);
-               break;
        case OBJ_TAG:
-               strcpy(type, tag_type);
+               strcpy(type, type_names[kind]);
                break;
        default:
                die("corrupted pack file %s containing object of kind %d",
@@ -1036,16 +1026,10 @@ static int packed_object_info(struct pack_entry *entry,
                unuse_packed_git(p);
                return retval;
        case OBJ_COMMIT:
-               strcpy(type, commit_type);
-               break;
        case OBJ_TREE:
-               strcpy(type, tree_type);
-               break;
        case OBJ_BLOB:
-               strcpy(type, blob_type);
-               break;
        case OBJ_TAG:
-               strcpy(type, tag_type);
+               strcpy(type, type_names[kind]);
                break;
        default:
                die("corrupted pack file %s containing object of kind %d",
@@ -1057,23 +1041,49 @@ static int packed_object_info(struct pack_entry *entry,
        return 0;
 }
 
-static void *unpack_delta_entry(unsigned char *base_sha1,
+static void *unpack_compressed_entry(struct packed_git *p,
+                                   unsigned long offset,
+                                   unsigned long size)
+{
+       int st;
+       z_stream stream;
+       unsigned char *buffer;
+
+       buffer = xmalloc(size + 1);
+       buffer[size] = 0;
+       memset(&stream, 0, sizeof(stream));
+       stream.next_in = (unsigned char*)p->pack_base + offset;
+       stream.avail_in = p->pack_size - offset;
+       stream.next_out = buffer;
+       stream.avail_out = size;
+
+       inflateInit(&stream);
+       st = inflate(&stream, Z_FINISH);
+       inflateEnd(&stream);
+       if ((st != Z_STREAM_END) || stream.total_out != size) {
+               free(buffer);
+               return NULL;
+       }
+
+       return buffer;
+}
+
+static void *unpack_delta_entry(struct packed_git *p,
+                               unsigned long offset,
                                unsigned long delta_size,
-                               unsigned long left,
                                char *type,
-                               unsigned long *sizep,
-                               struct packed_git *p)
+                               unsigned long *sizep)
 {
        struct pack_entry base_ent;
-       void *data, *delta_data, *result, *base;
-       unsigned long data_size, result_size, base_size;
-       z_stream stream;
-       int st;
+       void *delta_data, *result, *base;
+       unsigned long result_size, base_size;
+       unsigned char* base_sha1;
 
-       if (left < 20)
+       if ((offset + 20) >= p->pack_size)
                die("truncated pack file");
 
        /* The base entry _must_ be in the same pack */
+       base_sha1 = (unsigned char*)p->pack_base + offset;
        if (!find_pack_entry_one(base_sha1, &base_ent, p))
                die("failed to find delta-pack base object %s",
                    sha1_to_hex(base_sha1));
@@ -1082,23 +1092,7 @@ static void *unpack_delta_entry(unsigned char *base_sha1,
                die("failed to read delta-pack base object %s",
                    sha1_to_hex(base_sha1));
 
-       data = base_sha1 + 20;
-       data_size = left - 20;
-       delta_data = xmalloc(delta_size);
-
-       memset(&stream, 0, sizeof(stream));
-
-       stream.next_in = data;
-       stream.avail_in = data_size;
-       stream.next_out = delta_data;
-       stream.avail_out = delta_size;
-
-       inflateInit(&stream);
-       st = inflate(&stream, Z_FINISH);
-       inflateEnd(&stream);
-       if ((st != Z_STREAM_END) || stream.total_out != delta_size)
-               die("delta data unpack failed");
-
+       delta_data = unpack_compressed_entry(p, offset + 20, delta_size);
        result = patch_delta(base, base_size,
                             delta_data, delta_size,
                             &result_size);
@@ -1110,33 +1104,6 @@ static void *unpack_delta_entry(unsigned char *base_sha1,
        return result;
 }
 
-static void *unpack_non_delta_entry(unsigned char *data,
-                                   unsigned long size,
-                                   unsigned long left)
-{
-       int st;
-       z_stream stream;
-       unsigned char *buffer;
-
-       buffer = xmalloc(size + 1);
-       buffer[size] = 0;
-       memset(&stream, 0, sizeof(stream));
-       stream.next_in = data;
-       stream.avail_in = left;
-       stream.next_out = buffer;
-       stream.avail_out = size;
-
-       inflateInit(&stream);
-       st = inflate(&stream, Z_FINISH);
-       inflateEnd(&stream);
-       if ((st != Z_STREAM_END) || stream.total_out != size) {
-               free(buffer);
-               return NULL;
-       }
-
-       return buffer;
-}
-
 static void *unpack_entry(struct pack_entry *entry,
                          char *type, unsigned long *sizep)
 {
@@ -1157,36 +1124,23 @@ void *unpack_entry_gently(struct pack_entry *entry,
                          char *type, unsigned long *sizep)
 {
        struct packed_git *p = entry->p;
-       unsigned long offset, size, left;
-       unsigned char *pack;
+       unsigned long offset, size;
        enum object_type kind;
-       void *retval;
 
        offset = unpack_object_header(p, entry->offset, &kind, &size);
-       pack = (unsigned char *) p->pack_base + offset;
-       left = p->pack_size - offset;
        switch (kind) {
        case OBJ_DELTA:
-               retval = unpack_delta_entry(pack, size, left, type, sizep, p);
-               return retval;
+               return unpack_delta_entry(p, offset, size, type, sizep);
        case OBJ_COMMIT:
-               strcpy(type, commit_type);
-               break;
        case OBJ_TREE:
-               strcpy(type, tree_type);
-               break;
        case OBJ_BLOB:
-               strcpy(type, blob_type);
-               break;
        case OBJ_TAG:
-               strcpy(type, tag_type);
-               break;
+               strcpy(type, type_names[kind]);
+               *sizep = size;
+               return unpack_compressed_entry(p, offset, size);
        default:
                return NULL;
        }
-       *sizep = size;
-       retval = unpack_non_delta_entry(pack, size, left);
-       return retval;
 }
 
 int num_packed_objects(const struct packed_git *p)
@@ -1201,7 +1155,7 @@ int nth_packed_object_sha1(const struct packed_git *p, int n,
        void *index = p->index_base + 256;
        if (n < 0 || num_packed_objects(p) <= n)
                return -1;
-       memcpy(sha1, (char *) index + (24 * n) + 4, 20);
+       hashcpy(sha1, (unsigned char *) index + (24 * n) + 4);
        return 0;
 }
 
@@ -1218,7 +1172,7 @@ int find_pack_entry_one(const unsigned char *sha1,
                int cmp = hashcmp((unsigned char *)index + (24 * mi) + 4, sha1);
                if (!cmp) {
                        e->offset = ntohl(*((unsigned int *) ((char *) index + (24 * mi))));
-                       memcpy(e->sha1, sha1, 20);
+                       hashcpy(e->sha1, sha1);
                        e->p = p;
                        return 1;
                }
@@ -1331,7 +1285,7 @@ void *read_object_with_reference(const unsigned char *sha1,
        unsigned long isize;
        unsigned char actual_sha1[20];
 
-       memcpy(actual_sha1, sha1, 20);
+       hashcpy(actual_sha1, sha1);
        while (1) {
                int ref_length = -1;
                const char *ref_type = NULL;
@@ -1342,7 +1296,7 @@ void *read_object_with_reference(const unsigned char *sha1,
                if (!strcmp(type, required_type)) {
                        *size = isize;
                        if (actual_sha1_return)
-                               memcpy(actual_sha1_return, actual_sha1, 20);
+                               hashcpy(actual_sha1_return, actual_sha1);
                        return buffer;
                }
                /* Handle references */
@@ -1537,7 +1491,7 @@ int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned cha
         */
        filename = write_sha1_file_prepare(buf, len, type, sha1, hdr, &hdrlen);
        if (returnsha1)
-               memcpy(returnsha1, sha1, 20);
+               hashcpy(returnsha1, sha1);
        if (has_sha1_file(sha1))
                return 0;
        fd = open(filename, O_RDONLY);
@@ -1786,7 +1740,7 @@ int read_pipe(int fd, char** return_buf, unsigned long* return_size)
                        off += iret;
                        if (off == size) {
                                size *= 2;
-                               buf = realloc(buf, size);
+                               buf = xrealloc(buf, size);
                        }
                }
        } while (iret > 0);
index e9eb6ce882ea92523c9a871c7581457af2dc78c5..3f6b77ccfadab14453a76b6654b50b186c9f5b25 100644 (file)
@@ -103,7 +103,7 @@ static int find_short_packed_object(int len, const unsigned char *match, unsigne
                                    !match_sha(len, match, next)) {
                                        /* unique within this pack */
                                        if (!found) {
-                                               memcpy(found_sha1, now, 20);
+                                               hashcpy(found_sha1, now);
                                                found++;
                                        }
                                        else if (hashcmp(found_sha1, now)) {
@@ -120,7 +120,7 @@ static int find_short_packed_object(int len, const unsigned char *match, unsigne
                }
        }
        if (found == 1)
-               memcpy(sha1, found_sha1, 20);
+               hashcpy(sha1, found_sha1);
        return found;
 }
 
@@ -140,13 +140,13 @@ static int find_unique_short_object(int len, char *canonical,
        if (1 < has_unpacked || 1 < has_packed)
                return SHORT_NAME_AMBIGUOUS;
        if (has_unpacked != has_packed) {
-               memcpy(sha1, (has_packed ? packed_sha1 : unpacked_sha1), 20);
+               hashcpy(sha1, (has_packed ? packed_sha1 : unpacked_sha1));
                return 0;
        }
        /* Both have unique ones -- do they match? */
        if (hashcmp(packed_sha1, unpacked_sha1))
                return SHORT_NAME_AMBIGUOUS;
-       memcpy(sha1, packed_sha1, 20);
+       hashcpy(sha1, packed_sha1);
        return 0;
 }
 
@@ -159,7 +159,7 @@ static int get_short_sha1(const char *name, int len, unsigned char *sha1,
 
        if (len < MINIMUM_ABBREV)
                return -1;
-       memset(res, 0, 20);
+       hashclr(res);
        memset(canonical, 'x', 40);
        for (i = 0; i < len ;i++) {
                unsigned char c = name[i];
@@ -320,13 +320,13 @@ static int get_parent(const char *name, int len,
        if (parse_commit(commit))
                return -1;
        if (!idx) {
-               memcpy(result, commit->object.sha1, 20);
+               hashcpy(result, commit->object.sha1);
                return 0;
        }
        p = commit->parents;
        while (p) {
                if (!--idx) {
-                       memcpy(result, p->item->object.sha1, 20);
+                       hashcpy(result, p->item->object.sha1);
                        return 0;
                }
                p = p->next;
@@ -347,9 +347,9 @@ static int get_nth_ancestor(const char *name, int len,
 
                if (!commit || parse_commit(commit) || !commit->parents)
                        return -1;
-               memcpy(sha1, commit->parents->item->object.sha1, 20);
+               hashcpy(sha1, commit->parents->item->object.sha1);
        }
-       memcpy(result, sha1, 20);
+       hashcpy(result, sha1);
        return 0;
 }
 
@@ -401,7 +401,7 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
                o = deref_tag(o, name, sp - name - 2);
                if (!o || (!o->parsed && !parse_object(o->sha1)))
                        return -1;
-               memcpy(sha1, o->sha1, 20);
+               hashcpy(sha1, o->sha1);
        }
        else {
                /* At this point, the syntax look correct, so
@@ -413,7 +413,7 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
                        if (!o || (!o->parsed && !parse_object(o->sha1)))
                                return -1;
                        if (o->type == expected_type) {
-                               memcpy(sha1, o->sha1, 20);
+                               hashcpy(sha1, o->sha1);
                                return 0;
                        }
                        if (o->type == OBJ_TAG)
@@ -520,7 +520,7 @@ int get_sha1(const char *name, unsigned char *sha1)
                            memcmp(ce->name, cp, namelen))
                                break;
                        if (ce_stage(ce) == stage) {
-                               memcpy(sha1, ce->sha1, 20);
+                               hashcpy(sha1, ce->sha1);
                                return 0;
                        }
                        pos++;
index 69aebe600573fa0e014e97001f40836d3a18b82b..74f5c2a5755c8d29045498031c0bc3721a00b9c7 100755 (executable)
@@ -22,25 +22,64 @@ test_expect_success setup '
        tr "[mon]" '\''[\0\1\2]'\'' <file1 >file2 &&
 
        git commit -a -m second &&
+       git tag second &&
 
-       git diff --binary -R initial >patch
+       git diff --binary initial second >patch
 
 '
 
 test_expect_success 'apply in forward' '
 
+       T0=`git rev-parse "second^{tree}"` &&
+       git reset --hard initial &&
        git apply --index --binary patch &&
-       git diff initial >diff &&
-       diff -u /dev/null diff
-
+       T1=`git write-tree` &&
+       test "$T0" = "$T1"
 '
 
 test_expect_success 'apply in reverse' '
 
+       git reset --hard second &&
        git apply --reverse --binary --index patch &&
        git diff >diff &&
        diff -u /dev/null diff
 
 '
 
+test_expect_success 'setup separate repository lacking postimage' '
+
+       git tar-tree initial initial | tar xf - &&
+       (
+               cd initial && git init-db && git add .
+       ) &&
+
+       git tar-tree second second | tar xf - &&
+       (
+               cd second && git init-db && git add .
+       )
+
+'
+
+test_expect_success 'apply in forward without postimage' '
+
+       T0=`git rev-parse "second^{tree}"` &&
+       (
+               cd initial &&
+               git apply --index --binary ../patch &&
+               T1=`git write-tree` &&
+               test "$T0" = "$T1"
+       )
+'
+
+test_expect_success 'apply in reverse without postimage' '
+
+       T0=`git rev-parse "initial^{tree}"` &&
+       (
+               cd second &&
+               git apply --index --binary --reverse ../patch &&
+               T1=`git write-tree` &&
+               test "$T0" = "$T1"
+       )
+'
+
 test_done
diff --git a/t/t4117-apply-reject.sh b/t/t4117-apply-reject.sh
new file mode 100755 (executable)
index 0000000..b4de075
--- /dev/null
@@ -0,0 +1,157 @@
+#!/bin/sh
+#
+# Copyright (c) 2005 Junio C Hamano
+#
+
+test_description='git-apply with rejects
+
+'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+       for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
+       do
+               echo $i
+       done >file1 &&
+       cat file1 >saved.file1 &&
+       git update-index --add file1 &&
+       git commit -m initial &&
+
+       for i in 1 2 A B 4 5 6 7 8 9 10 11 12 C 13 14 15 16 17 18 19 20 D 21
+       do
+               echo $i
+       done >file1 &&
+       git diff >patch.1 &&
+       cat file1 >clean &&
+
+       for i in 1 E 2 3 4 5 6 7 8 9 10 11 12 C 13 14 15 16 17 18 19 20 F 21
+       do
+               echo $i
+       done >expected &&
+
+       mv file1 file2 &&
+       git update-index --add --remove file1 file2 &&
+       git diff -M HEAD >patch.2 &&
+
+       rm -f file1 file2 &&
+       mv saved.file1 file1 &&
+       git update-index --add --remove file1 file2 &&
+
+       for i in 1 E 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 F 21
+       do
+               echo $i
+       done >file1 &&
+
+       cat file1 >saved.file1
+'
+
+test_expect_success 'apply without --reject should fail' '
+
+       if git apply patch.1
+       then
+               echo "Eh? Why?"
+               exit 1
+       fi
+
+       diff -u file1 saved.file1
+'
+
+test_expect_success 'apply without --reject should fail' '
+
+       if git apply --verbose patch.1
+       then
+               echo "Eh? Why?"
+               exit 1
+       fi
+
+       diff -u file1 saved.file1
+'
+
+test_expect_success 'apply with --reject should fail but update the file' '
+
+       cat saved.file1 >file1 &&
+       rm -f file1.rej file2.rej &&
+
+       if git apply --reject patch.1
+       then
+               echo "succeeds with --reject?"
+               exit 1
+       fi
+
+       diff -u file1 expected &&
+
+       cat file1.rej &&
+
+       if test -f file2.rej
+       then
+               echo "file2 should not have been touched"
+               exit 1
+       fi
+'
+
+test_expect_success 'apply with --reject should fail but update the file' '
+
+       cat saved.file1 >file1 &&
+       rm -f file1.rej file2.rej file2 &&
+
+       if git apply --reject patch.2 >rejects
+       then
+               echo "succeeds with --reject?"
+               exit 1
+       fi
+
+       test -f file1 && {
+               echo "file1 still exists?"
+               exit 1
+       }
+       diff -u file2 expected &&
+
+       cat file2.rej &&
+
+       if test -f file1.rej
+       then
+               echo "file2 should not have been touched"
+               exit 1
+       fi
+
+'
+
+test_expect_success 'the same test with --verbose' '
+
+       cat saved.file1 >file1 &&
+       rm -f file1.rej file2.rej file2 &&
+
+       if git apply --reject --verbose patch.2 >rejects
+       then
+               echo "succeeds with --reject?"
+               exit 1
+       fi
+
+       test -f file1 && {
+               echo "file1 still exists?"
+               exit 1
+       }
+       diff -u file2 expected &&
+
+       cat file2.rej &&
+
+       if test -f file1.rej
+       then
+               echo "file2 should not have been touched"
+               exit 1
+       fi
+
+'
+
+test_expect_success 'apply cleanly with --verbose' '
+
+       git cat-file -p HEAD:file1 >file1 &&
+       rm -f file?.rej file2 &&
+
+       git apply --verbose patch.1 &&
+
+       diff -u file1 clean
+'
+
+test_done
index 3f83e98f3a443e4537f53abf32bcca1389c5d9d8..14cc5aea6c4eefbf4b0fa9c72ccb70ec550b44b4 100644 (file)
@@ -179,7 +179,7 @@ static int find_tree_entry(struct tree_desc *t, const char *name, unsigned char
                if (cmp < 0)
                        break;
                if (entrylen == namelen) {
-                       memcpy(result, sha1, 20);
+                       hashcpy(result, sha1);
                        return 0;
                }
                if (name[entrylen] != '/')
@@ -187,7 +187,7 @@ static int find_tree_entry(struct tree_desc *t, const char *name, unsigned char
                if (!S_ISDIR(*mode))
                        break;
                if (++entrylen == namelen) {
-                       memcpy(result, sha1, 20);
+                       hashcpy(result, sha1);
                        return 0;
                }
                return get_tree_entry(sha1, name + entrylen, result, mode);
diff --git a/tree.c b/tree.c
index ef456be9dd0faee46435a3c3b126a36c2be58051..ea386e506659c65224cfe55bdc4f8d086171637a 100644 (file)
--- a/tree.c
+++ b/tree.c
@@ -25,7 +25,7 @@ static int read_one_entry(const unsigned char *sha1, const char *base, int basel
        ce->ce_flags = create_ce_flags(baselen + len, stage);
        memcpy(ce->name, base, baselen);
        memcpy(ce->name + baselen, pathname, len+1);
-       memcpy(ce->sha1, sha1, 20);
+       hashcpy(ce->sha1, sha1);
        return add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
 }
 
index 467d9940f5a2e9cd8a880e4c8f0f1d2a8a5f7aa1..3ac0289b3a3309fca9ade4e271dbd8b0d2f148ea 100644 (file)
@@ -200,7 +200,7 @@ static int unpack_trees_rec(struct tree_entry_list **posns, int len,
 
                        any_files = 1;
 
-                       memcpy(ce->sha1, posns[i]->sha1, 20);
+                       hashcpy(ce->sha1, posns[i]->sha1);
                        src[i + o->merge] = ce;
                        subposns[i] = df_conflict_list;
                        posns[i] = posns[i]->next;
index fcf279843ad23b0605f3c2bc558e8d04a903554b..51ce936b060d34a2f759dba4f7aeeecf47a59a4b 100644 (file)
@@ -374,7 +374,7 @@ static int get_common_commits(void)
                                             sha1_to_hex(sha1),
                                             multi_ack ?  " continue" : "");
                                if (multi_ack)
-                                       memcpy(last_sha1, sha1, 20);
+                                       hashcpy(last_sha1, sha1);
                        }
                        continue;
                }
index 6a82da73b6d3b6b8cca23c3183cddc36c5cafb4b..08602f522183dc43787616f37cba9b8af4e3dade 100644 (file)
@@ -69,9 +69,9 @@ int xdiff_outf(void *priv_, mmbuffer_t *mb, int nbuf)
        for (i = 0; i < nbuf; i++) {
                if (mb[i].ptr[mb[i].size-1] != '\n') {
                        /* Incomplete line */
-                       priv->remainder = realloc(priv->remainder,
-                                                 priv->remainder_size +
-                                                 mb[i].size);
+                       priv->remainder = xrealloc(priv->remainder,
+                                                  priv->remainder_size +
+                                                  mb[i].size);
                        memcpy(priv->remainder + priv->remainder_size,
                               mb[i].ptr, mb[i].size);
                        priv->remainder_size += mb[i].size;
@@ -83,9 +83,9 @@ int xdiff_outf(void *priv_, mmbuffer_t *mb, int nbuf)
                        consume_one(priv, mb[i].ptr, mb[i].size);
                        continue;
                }
-               priv->remainder = realloc(priv->remainder,
-                                         priv->remainder_size +
-                                         mb[i].size);
+               priv->remainder = xrealloc(priv->remainder,
+                                          priv->remainder_size +
+                                          mb[i].size);
                memcpy(priv->remainder + priv->remainder_size,
                       mb[i].ptr, mb[i].size);
                consume_one(priv, priv->remainder,