]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Sync with 2.1.2
authorJunio C Hamano <gitster@pobox.com>
Tue, 30 Sep 2014 05:17:57 +0000 (22:17 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 30 Sep 2014 05:17:57 +0000 (22:17 -0700)
* maint:
  Git 2.1.2

217 files changed:
.gitignore
Documentation/RelNotes/2.2.0.txt [new file with mode: 0644]
Documentation/config.txt
Documentation/git-credential-cache--daemon.txt
Documentation/git-fast-export.txt
Documentation/git-imap-send.txt
Documentation/git-init.txt
Documentation/git-rev-list.txt
Documentation/git-rev-parse.txt
Documentation/git-svn.txt
Documentation/git-update-index.txt
Documentation/gitattributes.txt
Documentation/pretty-formats.txt
Documentation/rev-list-options.txt
Documentation/technical/api-allocation-growing.txt
Documentation/technical/api-config.txt
Documentation/technical/api-run-command.txt
Documentation/technical/api-strbuf.txt
GIT-VERSION-GEN
Makefile
RelNotes
abspath.c
advice.c
alias.c
archive-tar.c
archive.c
attr.c
bisect.c
branch.c
builtin/add.c
builtin/apply.c
builtin/blame.c
builtin/branch.c
builtin/checkout.c
builtin/clean.c
builtin/clone.c
builtin/commit.c
builtin/config.c
builtin/fast-export.c
builtin/for-each-ref.c
builtin/fsck.c
builtin/gc.c
builtin/hash-object.c
builtin/help.c
builtin/index-pack.c
builtin/init-db.c
builtin/log.c
builtin/ls-files.c
builtin/mailinfo.c
builtin/mailsplit.c
builtin/merge-tree.c
builtin/merge.c
builtin/mv.c
builtin/notes.c
builtin/pack-objects.c
builtin/prune-packed.c
builtin/receive-pack.c
builtin/remote-ext.c
builtin/repack.c
builtin/replace.c
builtin/rev-parse.c
builtin/rm.c
builtin/show-branch.c
builtin/tag.c
builtin/unpack-objects.c
builtin/update-ref.c
builtin/verify-pack.c
bundle.c
cache-tree.c
cache-tree.h
cache.h
column.c
commit-slab.h
commit.c
commit.h
compat/mingw.h
config.c
config.mak.uname
configure.ac
connect.c
connected.c
contrib/completion/git-completion.bash
contrib/subtree/Makefile
contrib/svn-fe/Makefile
convert.c
credential-cache--daemon.c
credential-cache.c
credential.c
daemon.c
date.c
diff.c
diffcore-rename.c
diffcore.h
dir.c
editor.c
exec_cmd.c
fast-import.c
fetch-pack.c
fsck.c
fsck.h
git-bisect.sh
git-compat-util.h
git-pull.sh
git-stash.sh
git-svn.perl
git.c
gpg-interface.c
graph.c
help.c
http-backend.c
http-walker.c
http.c
ident.c
imap-send.c
khash.h
line-log.c
ll-merge.c
lockfile.c
log-tree.c
log-tree.h
merge-recursive.c
object.c
object.h
pack-bitmap-write.c
pack-bitmap.c
pack-objects.c
pack-write.c
pager.c
parse-options.c
path.c
pretty.c
prompt.c
read-cache.c
reflog-walk.c
reflog-walk.h
refs.c
refs.h
remote-curl.c
remote-testsvn.c
remote.c
remote.h
rerere.c
rerere.h
revision.c
run-command.c
run-command.h
send-pack.c
sequencer.c
server-info.c
setup.c
sh-i18n--envsubst.c
sha1_file.c
sha1_name.c
shallow.c
strbuf.c
strbuf.h
string-list.c
submodule.c
t/t0005-signals.sh
t/t0008-ignores.sh
t/t0026-eol-config.sh
t/t0027-auto-crlf.sh
t/t0081-line-buffer.sh
t/t0090-cache-tree.sh
t/t1020-subdirectory.sh
t/t1050-large.sh
t/t1300-repo-config.sh
t/t1308-config-set.sh [new file with mode: 0755]
t/t1402-check-ref-format.sh
t/t1450-fsck.sh
t/t1502-rev-parse-parseopt.sh
t/t1503-rev-parse-verify.sh
t/t3201-branch-contains.sh
t/t3210-pack-refs.sh
t/t3302-notes-index-expensive.sh
t/t3419-rebase-patch-id.sh
t/t3901-i18n-patch.sh
t/t3903-stash.sh
t/t4055-diff-context.sh
t/t4201-shortlog.sh
t/t4205-log-pretty-formats.sh
t/t4210-log-i18n.sh
t/t5004-archive-corner-cases.sh
t/t5100-mailinfo.sh
t/t5100/embed-from.expect [new file with mode: 0644]
t/t5100/embed-from.in [new file with mode: 0644]
t/t5100/quoted-from.expect [new file with mode: 0644]
t/t5100/quoted-from.in [new file with mode: 0644]
t/t5302-pack-index.sh
t/t5401-update-hooks.sh
t/t5601-clone.sh
t/t6031-merge-recursive.sh
t/t6038-merge-text-auto.sh
t/t8005-blame-i18n.sh
t/t9119-git-svn-info.sh
t/t9300-fast-import.sh
t/t9351-fast-export-anonymize.sh [new file with mode: 0755]
t/t9809-git-p4-client-view.sh
t/t9812-git-p4-wildcards.sh
t/t9815-git-p4-submit-fail.sh
t/test-lib.sh
templates/hooks--pre-push.sample
test-config.c [new file with mode: 0644]
test-date.c
test-dump-cache-tree.c
test-run-command.c
test-subprocess.c
trace.c
transport-helper.c
transport.c
unix-socket.c
upload-pack.c
utf8.c
walker.c
wrapper.c
write_or_die.c
wt-status.c

index 81e12c0621d42b495ab540391e1cd8ece18587b7..5bfb234591a63446d9fccf7665e442f02d1c76b5 100644 (file)
 /gitweb/static/gitweb.min.*
 /test-chmtime
 /test-ctype
+/test-config
 /test-date
 /test-delta
 /test-dump-cache-tree
diff --git a/Documentation/RelNotes/2.2.0.txt b/Documentation/RelNotes/2.2.0.txt
new file mode 100644 (file)
index 0000000..438f92e
--- /dev/null
@@ -0,0 +1,204 @@
+Git v2.2 Release Notes
+======================
+
+Updates since v2.1
+------------------
+
+Ports
+
+ * Building on older MacOS X systems automatically sets
+   the necessary NO_APPLE_COMMON_CRYPTO build-time option.
+
+
+UI, Workflows & Features
+
+ * "git config --edit --global" starts from a skeletal per-user
+   configuration file contents, instead of a total blank, when the
+   user does not already have any.  This immediately reduces the
+   need for a later "Have you forgotten setting core.user?" and we
+   can add more to the template as we gain more experience.
+
+ * "git stash list -p" used to be almost always a no-op because each
+   stash entry is represented as a merge commit.  It learned to show
+   the difference between the base commit version and the working tree
+   version, which is in line with what "git show" gives.
+
+ * Sometimes users want to report a bug they experience on their
+   repository, but they are not at liberty to share the contents of
+   the repository.  "fast-export" was taught an "--anonymize" option
+   to replace blob contents, names of people and paths and log
+   messages with bland and simple strings to help them.
+
+ * "log --date=iso" uses a slight variant of ISO 8601 format that is
+   made more human readable.  A new "--date=iso-strict" option gives
+   datetime output that is more strictly conformant.
+
+ * A broken reimplementation of Git could write an invalid index that
+   records both stage #0 and higher stage entries for the same path.
+   We now notice and reject such an index, as there is no sensible
+   fallback (we do not know if the broken tool wanted to resolve and
+   forgot to remove higher stage entries, or if it wanted to unresolve
+   and forgot to remove the stage#0 entry).
+
+ * The "pre-receive" and "post-receive" hooks are no longer required
+   to consume their input fully (not following this requirement used
+   to result in intermittent errors in "git push").
+
+ * The pretty-format specifier "%d", which expanded to " (tagname)"
+   for a tagged commit, gained a cousin "%D" that just gives the
+   "tagname" without frills.
+
+Performance, Internal Implementation, etc.
+
+ * The API to manipulate the "refs" is currently undergoing a revamp
+   to make it more transactional, with the eventual goal to allow
+   all-or-none atomic updates and migrating the storage to something
+   other than the traditional filesystem based one (e.g. databases).
+
+ * We no longer attempt to keep track of individual dependencies to
+   the header files in the build procedure, relying on automated
+   dependency generation support from modern compilers.
+
+ * In tests, we have been using NOT_{MINGW,CYGWIN} test prerequisites
+   long before negated prerequisites e.g. !MINGW were invented.
+   The former has been converted to the latter to avoid confusion.
+
+ * Looking up remotes configuration in a repository with very many
+   remotes defined has been optimized.
+
+ * There are cases where you lock and open to write a file, close it
+   to show the updated contents to external processes, and then have
+   to update the file again while still holding the lock, but the
+   lockfile API lacked support for such an access pattern.
+
+ * The API to allocate the structure to keep track of commit
+   decoration has been updated to make it less cumbersome to use.
+
+ * An in-core caching layer to let us avoid reading the same
+   configuration files number of times has been added.  A few commands
+   have been converted to use this subsystem.
+
+ * Various code paths have been cleaned up and simplified by using
+   "strbuf", "starts_with()", and "skip_prefix()" APIs more.
+
+ * A few codepaths that died when large blobs that would not fit in
+   core are involved in their operation have been taught to punt
+   instead, by e.g. marking too large a blob as not to be diffed.
+
+ * A few more code paths in "commit" and "checkout" have been taught
+   to repopulate the cache-tree in the index, to help speed up later
+   "write-tree" (used in "commit") and "diff-index --cached" (used in
+   "status").
+
+ * A common programming mistake to assign the same short option name
+   to two separate options is detected by parse_options() API to help
+   developers.
+
+ * The code path to write out the packed-refs file has been optimized,
+   which especially matters in a repository with a large number of
+   refs.
+
+ * The check to see if a ref $F can be created by making sure no
+   existing ref has $F/ as its prefix has been optimized, which
+   especially matters in a repository with a large number of existing
+   refs.
+
+ * "git fsck" was taught to check contents of tag objects a bit more.
+
+ * "git hash-object" was taught a "--literally" option to help
+   debugging.
+
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v2.1
+----------------
+
+Unless otherwise noted, all the fixes since v2.1 in the maintenance
+track are contained in this release (see the maintenance releases'
+notes for details).
+
+ * "git log --pretty/format=" with an empty format string did not
+   mean the more obvious "No output whatsoever" but "Use default
+   format", which was counterintuitive.
+
+ * Implementations of "tar" that do not understand an extended pax
+   header would extract the contents of it in a regular file; make
+   sure the permission bits of this file follows the same tar.umask
+   configuration setting.
+
+ * "git -c section.var command" and "git -c section.var= command"
+   should pass the configuration differently (the former should be a
+   boolean true, the latter should be an empty string).
+
+ * Applying a patch not generated by Git in a subdirectory used to
+   check the whitespace breakage using the attributes for incorrect
+   paths. Also whitespace checks were performed even for paths
+   excluded via "git apply --exclude=<path>" mechanism.
+
+ * "git bundle create" with date-range specification were meant to
+   exclude tags outside the range, but it didn't.
+
+ * "git add x" where x that used to be a directory has become a
+   symbolic link to a directory misbehaved.
+
+ * The prompt script checked $GIT_DIR/ref/stash file to see if there
+   is a stash, which was a no-no.
+
+ * Pack-protocol documentation had a minor typo.
+
+ * "git checkout -m" did not switch to another branch while carrying
+   the local changes forward when a path was deleted from the index.
+
+ * With sufficiently long refnames, "git fast-import" could have
+   overflown an on-stack buffer.
+
+ * After "pack-refs --prune" packed refs at the top-level, it failed
+   to prune them.
+
+ * Progress output from "git gc --auto" was visible in "git fetch -q".
+
+ * We used to pass -1000 to poll(2), expecting it to also mean "no
+   timeout", which should be spelled as -1.
+
+ * "git rebase" documentation was unclear that it is required to
+   specify on what <upstream> the rebase is to be done when telling it
+   to first check out <branch>.
+   (merge 95c6826 so/rebase-doc later to maint).
+
+ * "git push" over HTTP transport had an artificial limit on number of
+   refs that can be pushed imposed by the command line length.
+   (merge 26be19b jk/send-pack-many-refspecs later to maint).
+
+ * When receiving an invalid pack stream that records the same object
+   twice, multiple threads got confused due to a race.
+   (merge ab791dd jk/index-pack-threading-races later to maint).
+
+ * An attempt to remove the entire tree in the "git fast-import" input
+   stream caused it to misbehave.
+   (merge 2668d69 mb/fast-import-delete-root later to maint).
+
+ * Reachability check (used in "git prune" and friends) did not add a
+   detached HEAD as a starting point to traverse objects still in use.
+   (merge c40fdd0 mk/reachable-protect-detached-head later to maint).
+
+ * "git config --add section.var val" used to lose existing
+   section.var whose value was an empty string.
+   (merge c1063be ta/config-add-to-empty-or-true-fix later to maint).
+
+ * "git fsck" failed to report that it found corrupt objects via its
+   exit status in some cases.
+   (merge 30d1038 jk/fsck-exit-code-fix later to maint).
+
+ * Use of "--verbose" option used to break "git branch --merged".
+   (merge 12994dd jk/maint-branch-verbose-merged later to maint).
+
+ * Some MUAs mangled a line in a message that begins with "From " to
+   ">From " when writing to a mailbox file and feeding such an input
+   to "git am" used to lose such a line.
+   (merge 85de86a jk/mbox-from-line later to maint).
+
+ * "rev-parse --verify --quiet $name" is meant to quietly exit with a
+   non-zero status when $name is not a valid object name, but still
+   gave error messages in some cases.
index c55c22ab7be94e798164a48622aca21dd4daa44f..3b5b24aeb7f16c03e06bd6f38fd89e9080011ce7 100644 (file)
@@ -499,7 +499,8 @@ core.bigFileThreshold::
        Files larger than this size are stored deflated, without
        attempting delta compression.  Storing large files without
        delta compression avoids excessive memory usage, at the
-       slight expense of increased disk usage.
+       slight expense of increased disk usage. Additionally files
+       larger than this size are always treated as binary.
 +
 Default is 512 MiB on all platforms.  This should be reasonable
 for most projects as source code and other text files can still
index d15db42d43b9e94628246a30e7c12df41b45b935..7051c6bdf8f542b8fb8c3c4a5a24471355111922 100644 (file)
@@ -8,7 +8,7 @@ git-credential-cache--daemon - Temporarily store user credentials in memory
 SYNOPSIS
 --------
 [verse]
-git credential-cache--daemon <socket>
+git credential-cache--daemon [--debug] <socket>
 
 DESCRIPTION
 -----------
@@ -21,6 +21,10 @@ for `git-credential-cache` clients. Clients may store and retrieve
 credentials. Each credential is held for a timeout specified by the
 client; once no credentials are held, the daemon exits.
 
+If the `--debug` option is specified, the daemon does not close its
+stderr stream, and may output extra diagnostics to it even after it has
+begun listening for clients.
+
 GIT
 ---
 Part of the linkgit:git[1] suite
index 221506b04ba55fac2151d8ac95da7df57eb9d411..dbe9a46833f2b18bb06c0b60db76930befb88d43 100644 (file)
@@ -105,6 +105,11 @@ marks the same across runs.
        in the commit (as opposed to just listing the files which are
        different from the commit's first parent).
 
+--anonymize::
+       Anonymize the contents of the repository while still retaining
+       the shape of the history and stored tree.  See the section on
+       `ANONYMIZING` below.
+
 --refspec::
        Apply the specified refspec to each ref exported. Multiple of them can
        be specified.
@@ -141,6 +146,62 @@ referenced by that revision range contains the string
 'refs/heads/master'.
 
 
+ANONYMIZING
+-----------
+
+If the `--anonymize` option is given, git will attempt to remove all
+identifying information from the repository while still retaining enough
+of the original tree and history patterns to reproduce some bugs. The
+goal is that a git bug which is found on a private repository will
+persist in the anonymized repository, and the latter can be shared with
+git developers to help solve the bug.
+
+With this option, git will replace all refnames, paths, blob contents,
+commit and tag messages, names, and email addresses in the output with
+anonymized data.  Two instances of the same string will be replaced
+equivalently (e.g., two commits with the same author will have the same
+anonymized author in the output, but bear no resemblance to the original
+author string). The relationship between commits, branches, and tags is
+retained, as well as the commit timestamps (but the commit messages and
+refnames bear no resemblance to the originals). The relative makeup of
+the tree is retained (e.g., if you have a root tree with 10 files and 3
+trees, so will the output), but their names and the contents of the
+files will be replaced.
+
+If you think you have found a git bug, you can start by exporting an
+anonymized stream of the whole repository:
+
+---------------------------------------------------
+$ git fast-export --anonymize --all >anon-stream
+---------------------------------------------------
+
+Then confirm that the bug persists in a repository created from that
+stream (many bugs will not, as they really do depend on the exact
+repository contents):
+
+---------------------------------------------------
+$ git init anon-repo
+$ cd anon-repo
+$ git fast-import <../anon-stream
+$ ... test your bug ...
+---------------------------------------------------
+
+If the anonymized repository shows the bug, it may be worth sharing
+`anon-stream` along with a regular bug report. Note that the anonymized
+stream compresses very well, so gzipping it is encouraged. If you want
+to examine the stream to see that it does not contain any private data,
+you can peruse it directly before sending. You may also want to try:
+
+---------------------------------------------------
+$ perl -pe 's/\d+/X/g' <anon-stream | sort -u | less
+---------------------------------------------------
+
+which shows all of the unique lines (with numbers converted to "X", to
+collapse "User 0", "User 1", etc into "User X"). This produces a much
+smaller output, and it is usually easy to quickly confirm that there is
+no private data in the stream.
+
+
 Limitations
 -----------
 
index 875d2831a541170402849e2c8598fabafa42a0df..7d991d919ccf3378fdc924418aede45f8cb38632 100644 (file)
@@ -38,18 +38,17 @@ Variables
 imap.folder::
        The folder to drop the mails into, which is typically the Drafts
        folder. For example: "INBOX.Drafts", "INBOX/Drafts" or
-       "[Gmail]/Drafts". Required to use imap-send.
+       "[Gmail]/Drafts". Required.
 
 imap.tunnel::
        Command used to setup a tunnel to the IMAP server through which
        commands will be piped instead of using a direct network connection
-       to the server. Required when imap.host is not set to use imap-send.
+       to the server. Required when imap.host is not set.
 
 imap.host::
        A URL identifying the server. Use a `imap://` prefix for non-secure
        connections and a `imaps://` prefix for secure connections.
-       Ignored when imap.tunnel is set, but required to use imap-send
-       otherwise.
+       Ignored when imap.tunnel is set, but required otherwise.
 
 imap.user::
        The username to use when logging in to the server.
@@ -76,7 +75,8 @@ imap.preformattedHTML::
 
 imap.authMethod::
        Specify authenticate method for authentication with IMAP server.
-       Current supported method is 'CRAM-MD5' only.
+       Current supported method is 'CRAM-MD5' only. If this is not set
+       then 'git imap-send' uses the basic IMAP plaintext LOGIN command.
 
 Examples
 ~~~~~~~~
index afd721e3a94e377372431254d6c0f3e79a61c099..369f889bb4d5f9f5066552cef74525649477ca9c 100644 (file)
@@ -43,7 +43,7 @@ OPTIONS
 -q::
 --quiet::
 
-Only print error and warning messages, all other output will be suppressed.
+Only print error and warning messages; all other output will be suppressed.
 
 --bare::
 
@@ -57,12 +57,12 @@ DIRECTORY" section below.)
 
 --separate-git-dir=<git dir>::
 
-Instead of initializing the repository where it is supposed to be,
-place a filesytem-agnostic Git symbolic link there, pointing to the
-specified path, and initialize a Git repository at the path. The
-result is Git repository can be separated from working tree. If this
-is reinitialization, the repository will be moved to the specified
-path.
+Instead of initializing the repository as a directory to either `$GIT_DIR` or
+`./.git/`, create a text file there containing the path to the actual
+repository.  This file acts as filesystem-agnostic Git symbolic link to the
+repository.
++
+If this is reinitialization, the repository will be moved to the specified path.
 
 --shared[=(false|true|umask|group|all|world|everybody|0xxx)]::
 
@@ -72,60 +72,65 @@ repository.  When specified, the config variable "core.sharedRepository" is
 set so that files and directories under `$GIT_DIR` are created with the
 requested permissions.  When not specified, Git will use permissions reported
 by umask(2).
-
++
 The option can have the following values, defaulting to 'group' if no value
 is given:
++
+--
+'umask' (or 'false')::
 
- - 'umask' (or 'false'): Use permissions reported by umask(2). The default,
-   when `--shared` is not specified.
+Use permissions reported by umask(2). The default, when `--shared` is not
+specified.
 
- - 'group' (or 'true'): Make the repository group-writable, (and g+sx, since
-   the git group may be not the primary group of all users).
-   This is used to loosen the permissions of an otherwise safe umask(2) value.
-   Note that the umask still applies to the other permission bits (e.g. if
-   umask is '0022', using 'group' will not remove read privileges from other
-   (non-group) users). See '0xxx' for how to exactly specify the repository
-   permissions.
+'group' (or 'true')::
 
- - 'all' (or 'world' or 'everybody'): Same as 'group', but make the repository
-   readable by all users.
+Make the repository group-writable, (and g+sx, since the git group may be not
+the primary group of all users). This is used to loosen the permissions of an
+otherwise safe umask(2) value. Note that the umask still applies to the other
+permission bits (e.g. if umask is '0022', using 'group' will not remove read
+privileges from other (non-group) users). See '0xxx' for how to exactly specify
+the repository permissions.
 
- - '0xxx': '0xxx' is an octal number and each file will have mode '0xxx'.
-   '0xxx' will override users' umask(2) value (and not only loosen permissions
-   as 'group' and 'all' does). '0640' will create a repository which is
-   group-readable, but not group-writable or accessible to others. '0660' will
-   create a repo that is readable and writable to the current user and group,
-   but inaccessible to others.
+'all' (or 'world' or 'everybody')::
 
-By default, the configuration flag receive.denyNonFastForwards is enabled
+Same as 'group', but make the repository readable by all users.
+
+'0xxx'::
+
+'0xxx' is an octal number and each file will have mode '0xxx'. '0xxx' will
+override users' umask(2) value (and not only loosen permissions as 'group' and
+'all' does). '0640' will create a repository which is group-readable, but not
+group-writable or accessible to others. '0660' will create a repo that is
+readable and writable to the current user and group, but inaccessible to others.
+--
+
+By default, the configuration flag `receive.denyNonFastForwards` is enabled
 in shared repositories, so that you cannot force a non fast-forwarding push
 into it.
 
-If you name a (possibly non-existent) directory at the end of the command
-line, the command is run inside the directory (possibly after creating it).
+If you provide a 'directory', the command is run inside it. If this directory
+does not exist, it will be created.
 
 --
 
-
 TEMPLATE DIRECTORY
 ------------------
 
 The template directory contains files and directories that will be copied to
 the `$GIT_DIR` after it is created.
 
-The template directory used will (in order):
+The template directory will be one of the following (in order):
 
- - The argument given with the `--template` option.
+ - the argument given with the `--template` option;
 
- - The contents of the `$GIT_TEMPLATE_DIR` environment variable.
+ - the contents of the `$GIT_TEMPLATE_DIR` environment variable;
 
- - The `init.templatedir` configuration variable.
+ - the `init.templatedir` configuration variable; or
 
- - The default template directory: `/usr/share/git-core/templates`.
+ - the default template directory: `/usr/share/git-core/templates`.
 
-The default template directory includes some directory structure, some
-suggested "exclude patterns", and copies of sample "hook" files.
-The suggested patterns and hook files are all modifiable and extensible.
+The default template directory includes some directory structure, suggested
+"exclude patterns" (see linkgit:gitignore[5]), and sample hook files (see linkgit:githooks[5]).
 
 EXAMPLES
 --------
@@ -136,10 +141,12 @@ Start a new Git repository for an existing code base::
 $ cd /path/to/my/codebase
 $ git init      <1>
 $ git add .     <2>
+$ git commit    <3>
 ----------------
 +
-<1> prepare /path/to/my/codebase/.git directory
-<2> add all existing file to the index
+<1> Create a /path/to/my/codebase/.git directory.
+<2> Add all existing files to the index.
+<3> Record the pristine state as the first commit in the history.
 
 GIT
 ---
index 7a1585def0ce0c0ca78a2735f619f0e8bdf3506c..fd7f8b5bc1840bc93273dd7b076d86499626912a 100644 (file)
@@ -45,7 +45,7 @@ SYNOPSIS
             [ \--regexp-ignore-case | -i ]
             [ \--extended-regexp | -E ]
             [ \--fixed-strings | -F ]
-            [ \--date=(local|relative|default|iso|rfc|short) ]
+            [ \--date=(local|relative|default|iso|iso-strict|rfc|short) ]
             [ [\--objects | \--objects-edge] [ \--unpacked ] ]
             [ \--pretty | \--header ]
             [ \--bisect ]
index 0b84769bd91b5894a246ff3d499dca1ffba339ac..fa4a8c3afcb93a5fc72e9d0a5dc798d773e0bb9e 100644 (file)
@@ -114,6 +114,7 @@ can be used.
        Only meaningful in `--verify` mode. Do not output an error
        message if the first argument is not a valid object name;
        instead exit with non-zero status silently.
+       SHA-1s for valid object names are printed to stdout on success.
 
 --sq::
        Usually the output is made one line per flag and
index 44c970ce18143e2a45c9f5364535e26508b50317..ef8ef1c545bbc14366ec71d904ad77b2a74802ff 100644 (file)
@@ -386,11 +386,13 @@ Any other arguments are passed directly to 'git log'
        tree-ish to specify which branch should be searched).  When given a
        tree-ish, returns the corresponding SVN revision number.
 +
+-B;;
 --before;;
        Don't require an exact match if given an SVN revision, instead find
        the commit corresponding to the state of the SVN repository (on the
        current branch) at the specified revision.
 +
+-A;;
 --after;;
        Don't require an exact match if given an SVN revision; if there is
        not an exact match return the closest match searching forward in the
@@ -608,21 +610,6 @@ config key: svn.authorsfile
        Make 'git svn' less verbose. Specify a second time to make it
        even less verbose.
 
---repack[=<n>]::
---repack-flags=<flags>::
-       These should help keep disk usage sane for large fetches with
-       many revisions.
-+
---repack takes an optional argument for the number of revisions
-to fetch before repacking.  This defaults to repacking every
-1000 commits fetched if no argument is specified.
-+
---repack-flags are passed directly to 'git repack'.
-+
-[verse]
-config key: svn.repack
-config key: svn.repackflags
-
 -m::
 --merge::
 -s<strategy>::
index dfc09d93d85f5ca598447e98327518082c8e1a16..82eca6fdf6149a270bf85937f91f3e9cc453052d 100644 (file)
@@ -202,7 +202,7 @@ merging.
 To pretend you have a file with mode and sha1 at path, say:
 
 ----------------
-$ git update-index --cacheinfo mode sha1 path
+$ git update-index --cacheinfo <mode>,<sha1>,<path>
 ----------------
 
 '--info-only' is used to register files without placing them in the object
index 643c1ba9290ff10813eab57b95f7c26d8c43c7e2..9b45bda7485c7e4742b13cdf19272968592b640a 100644 (file)
@@ -440,8 +440,8 @@ Unspecified::
 
        A path to which the `diff` attribute is unspecified
        first gets its contents inspected, and if it looks like
-       text, it is treated as text.  Otherwise it would
-       generate `Binary files differ`.
+       text and is smaller than core.bigFileThreshold, it is treated
+       as text. Otherwise it would generate `Binary files differ`.
 
 String::
 
index 85d63532a3e165110717ca2602e9dd806f10bd9f..eecc39dec99b3cab3da3e36440653ea46ac762b9 100644 (file)
@@ -115,19 +115,22 @@ The placeholders are:
 - '%aD': author date, RFC2822 style
 - '%ar': author date, relative
 - '%at': author date, UNIX timestamp
-- '%ai': author date, ISO 8601 format
+- '%ai': author date, ISO 8601-like format
+- '%aI': author date, strict ISO 8601 format
 - '%cn': committer name
 - '%cN': committer name (respecting .mailmap, see
   linkgit:git-shortlog[1] or linkgit:git-blame[1])
 - '%ce': committer email
 - '%cE': committer email (respecting .mailmap, see
   linkgit:git-shortlog[1] or linkgit:git-blame[1])
-- '%cd': committer date
+- '%cd': committer date (format respects --date= option)
 - '%cD': committer date, RFC2822 style
 - '%cr': committer date, relative
 - '%ct': committer date, UNIX timestamp
-- '%ci': committer date, ISO 8601 format
+- '%ci': committer date, ISO 8601-like format
+- '%cI': committer date, strict ISO 8601 format
 - '%d': ref names, like the --decorate option of linkgit:git-log[1]
+- '%D': ref names without the " (", ")" wrapping.
 - '%e': encoding
 - '%s': subject
 - '%f': sanitized subject line, suitable for a filename
@@ -182,8 +185,9 @@ The placeholders are:
 NOTE: Some placeholders may depend on other options given to the
 revision traversal engine. For example, the `%g*` reflog options will
 insert an empty string unless we are traversing reflog entries (e.g., by
-`git log -g`). The `%d` placeholder will use the "short" decoration
-format if `--decorate` was not already provided on the command line.
+`git log -g`). The `%d` and `%D` placeholders will use the "short"
+decoration format if `--decorate` was not already provided on the command
+line.
 
 If you add a `+` (plus sign) after '%' of a placeholder, a line-feed
 is inserted immediately before the expansion if and only if the
index deb8cca9173ccbaf8c15ade3f8b3312fb6bdcbad..5d311b8d46712ab0efb863d3ecd009386476a092 100644 (file)
@@ -677,7 +677,7 @@ include::pretty-options.txt[]
 --relative-date::
        Synonym for `--date=relative`.
 
---date=(relative|local|default|iso|rfc|short|raw)::
+--date=(relative|local|default|iso|iso-strict|rfc|short|raw)::
        Only takes effect for dates shown in human-readable format, such
        as when using `--pretty`. `log.date` config variable sets a default
        value for the log command's `--date` option.
@@ -687,7 +687,16 @@ e.g. ``2 hours ago''.
 +
 `--date=local` shows timestamps in user's local time zone.
 +
-`--date=iso` (or `--date=iso8601`) shows timestamps in ISO 8601 format.
+`--date=iso` (or `--date=iso8601`) shows timestamps in a ISO 8601-like format.
+The differences to the strict ISO 8601 format are:
+
+       - a space instead of the `T` date/time delimiter
+       - a space between time and time zone
+       - no colon between hours and minutes of the time zone
+
++
+`--date=iso-strict` (or `--date=iso8601-strict`) shows timestamps in strict
+ISO 8601 format.
 +
 `--date=rfc` (or `--date=rfc2822`) shows timestamps in RFC 2822
 format, often found in email messages.
index 542946b1ba701069837b702cbd8fe8079cecf56d..5a59b548448f3744a24ff9a58181b105f9cb1934 100644 (file)
@@ -34,3 +34,6 @@ item[nr++] = value you like;
 ------------
 
 You are responsible for updating the `nr` variable.
+
+If you need to specify the number of elements to allocate explicitly
+then use the macro `REALLOC_ARRAY(item, alloc)` instead of `ALLOC_GROW`.
index edd5018e158362fb3ad91c6d797d591eefb46678..0d8b99b368aea13a322382314d88229acda0b1db 100644 (file)
@@ -77,6 +77,99 @@ To read a specific file in git-config format, use
 `git_config_from_file`. This takes the same callback and data parameters
 as `git_config`.
 
+Querying For Specific Variables
+-------------------------------
+
+For programs wanting to query for specific variables in a non-callback
+manner, the config API provides two functions `git_config_get_value`
+and `git_config_get_value_multi`. They both read values from an internal
+cache generated previously from reading the config files.
+
+`int git_config_get_value(const char *key, const char **value)`::
+
+       Finds the highest-priority value for the configuration variable `key`,
+       stores the pointer to it in `value` and returns 0. When the
+       configuration variable `key` is not found, returns 1 without touching
+       `value`. The caller should not free or modify `value`, as it is owned
+       by the cache.
+
+`const struct string_list *git_config_get_value_multi(const char *key)`::
+
+       Finds and returns the value list, sorted in order of increasing priority
+       for the configuration variable `key`. When the configuration variable
+       `key` is not found, returns NULL. The caller should not free or modify
+       the returned pointer, as it is owned by the cache.
+
+`void git_config_clear(void)`::
+
+       Resets and invalidates the config cache.
+
+The config API also provides type specific API functions which do conversion
+as well as retrieval for the queried variable, including:
+
+`int git_config_get_int(const char *key, int *dest)`::
+
+       Finds and parses the value to an integer for the configuration variable
+       `key`. Dies on error; otherwise, stores the value of the parsed integer in
+       `dest` and returns 0. When the configuration variable `key` is not found,
+       returns 1 without touching `dest`.
+
+`int git_config_get_ulong(const char *key, unsigned long *dest)`::
+
+       Similar to `git_config_get_int` but for unsigned longs.
+
+`int git_config_get_bool(const char *key, int *dest)`::
+
+       Finds and parses the value into a boolean value, for the configuration
+       variable `key` respecting keywords like "true" and "false". Integer
+       values are converted into true/false values (when they are non-zero or
+       zero, respectively). Other values cause a die(). If parsing is successful,
+       stores the value of the parsed result in `dest` and returns 0. When the
+       configuration variable `key` is not found, returns 1 without touching
+       `dest`.
+
+`int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest)`::
+
+       Similar to `git_config_get_bool`, except that integers are copied as-is,
+       and `is_bool` flag is unset.
+
+`int git_config_get_maybe_bool(const char *key, int *dest)`::
+
+       Similar to `git_config_get_bool`, except that it returns -1 on error
+       rather than dying.
+
+`int git_config_get_string_const(const char *key, const char **dest)`::
+
+       Allocates and copies the retrieved string into the `dest` parameter for
+       the configuration variable `key`; if NULL string is given, prints an
+       error message and returns -1. When the configuration variable `key` is
+       not found, returns 1 without touching `dest`.
+
+`int git_config_get_string(const char *key, char **dest)`::
+
+       Similar to `git_config_get_string_const`, except that retrieved value
+       copied into the `dest` parameter is a mutable string.
+
+`int git_config_get_pathname(const char *key, const char **dest)`::
+
+       Similar to `git_config_get_string`, but expands `~` or `~user` into
+       the user's home directory when found at the beginning of the path.
+
+`git_die_config(const char *key, const char *err, ...)`::
+
+       First prints the error message specified by the caller in `err` and then
+       dies printing the line number and the file name of the highest priority
+       value for the configuration variable `key`.
+
+`void git_die_config_linenr(const char *key, const char *filename, int linenr)`::
+
+       Helper function which formats the die error message according to the
+       parameters entered. Used by `git_die_config()`. It can be used by callers
+       handling `git_config_get_value_multi()` to print the correct error message
+       for the desired value.
+
+See test-config.c for usage examples.
+
 Value Parsing Helpers
 ---------------------
 
@@ -134,6 +227,68 @@ int read_file_with_include(const char *file, config_fn_t fn, void *data)
 `git_config` respects includes automatically. The lower-level
 `git_config_from_file` does not.
 
+Custom Configsets
+-----------------
+
+A `config_set` can be used to construct an in-memory cache for
+config-like files that the caller specifies (i.e., files like `.gitmodules`,
+`~/.gitconfig` etc.). For example,
+
+---------------------------------------
+struct config_set gm_config;
+git_configset_init(&gm_config);
+int b;
+/* we add config files to the config_set */
+git_configset_add_file(&gm_config, ".gitmodules");
+git_configset_add_file(&gm_config, ".gitmodules_alt");
+
+if (!git_configset_get_bool(gm_config, "submodule.frotz.ignore", &b)) {
+       /* hack hack hack */
+}
+
+/* when we are done with the configset */
+git_configset_clear(&gm_config);
+----------------------------------------
+
+Configset API provides functions for the above mentioned work flow, including:
+
+`void git_configset_init(struct config_set *cs)`::
+
+       Initializes the config_set `cs`.
+
+`int git_configset_add_file(struct config_set *cs, const char *filename)`::
+
+       Parses the file and adds the variable-value pairs to the `config_set`,
+       dies if there is an error in parsing the file. Returns 0 on success, or
+       -1 if the file does not exist or is inaccessible. The user has to decide
+       if he wants to free the incomplete configset or continue using it when
+       the function returns -1.
+
+`int git_configset_get_value(struct config_set *cs, const char *key, const char **value)`::
+
+       Finds the highest-priority value for the configuration variable `key`
+       and config set `cs`, stores the pointer to it in `value` and returns 0.
+       When the configuration variable `key` is not found, returns 1 without
+       touching `value`. The caller should not free or modify `value`, as it
+       is owned by the cache.
+
+`const struct string_list *git_configset_get_value_multi(struct config_set *cs, const char *key)`::
+
+       Finds and returns the value list, sorted in order of increasing priority
+       for the configuration variable `key` and config set `cs`. When the
+       configuration variable `key` is not found, returns NULL. The caller
+       should not free or modify the returned pointer, as it is owned by the cache.
+
+`void git_configset_clear(struct config_set *cs)`::
+
+       Clears `config_set` structure, removes all saved variable-value pairs.
+
+In addition to above functions, the `config_set` API provides type specific
+functions in the vein of `git_config_get_int` and family but with an extra
+parameter, pointer to struct `config_set`.
+They all behave similarly to the `git_config_get*()` family described in
+"Querying For Specific Variables" above.
+
 Writing Config Files
 --------------------
 
index 69510ae57afcedbe13334160c6a26c52c42e8d54..842b8389eb867b6db654cf7fe29e8f10b92b259e 100644 (file)
@@ -13,6 +13,10 @@ produces in the caller in order to process it.
 Functions
 ---------
 
+`child_process_init`
+
+       Initialize a struct child_process variable.
+
 `start_command`::
 
        Start a sub-process. Takes a pointer to a `struct child_process`
@@ -96,8 +100,8 @@ command to run in a sub-process.
 
 The caller:
 
-1. allocates and clears (memset(&chld, 0, sizeof(chld));) a
-   struct child_process variable;
+1. allocates and clears (using child_process_init() or
+   CHILD_PROCESS_INIT) a struct child_process variable;
 2. initializes the members;
 3. calls start_command();
 4. processes the data;
index f9c06a7573e9294a967d641cdfc2723b86c1c864..cca6543234a5dd15e415b9e640f518097c1ec4fd 100644 (file)
@@ -160,6 +160,10 @@ then they will free() it.
 
        Add a single character to the buffer.
 
+`strbuf_addchars`::
+
+       Add a character the specified number of times to the buffer.
+
 `strbuf_insert`::
 
        Insert data to the given position of the buffer. The remaining contents
@@ -307,6 +311,16 @@ same behaviour as well.
        use it unless you need the correct position in the file
        descriptor.
 
+`strbuf_getcwd`::
+
+       Set the buffer to the path of the current working directory.
+
+`strbuf_add_absolute_path`
+
+       Add a path to a buffer, converting a relative path to an
+       absolute one in the process.  Symbolic links are not
+       resolved.
+
 `stripspace`::
 
        Strip whitespace from a buffer. The second parameter controls if
index 14b866e9b318178b7a820a5a383c2fe01672f11c..153d55d2b99e1340f92140eb231cd919d3af80c8 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v2.1.2
+DEF_VER=v2.1.0.GIT
 
 LF='
 '
index 9f984a9e5561d6b67b453124a311963ae8845f6d..f34a2d4cb82a907c2a1a9a8d760cfd3a1788f6e3 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -14,11 +14,11 @@ all::
 # Define INLINE to a suitable substitute (such as '__inline' or '') if git
 # fails to compile with errors about undefined inline functions or similar.
 #
-# Define SNPRINTF_RETURNS_BOGUS if your are on a system which snprintf()
+# Define SNPRINTF_RETURNS_BOGUS if you are on a system which snprintf()
 # or vsnprintf() return -1 instead of number of characters which would
 # have been written to the final string if enough space had been available.
 #
-# Define FREAD_READS_DIRECTORIES if your are on a system which succeeds
+# Define FREAD_READS_DIRECTORIES if you are on a system which succeeds
 # when attempting to read from an fopen'ed directory.
 #
 # Define NO_OPENSSL environment variable if you do not have OpenSSL.
@@ -317,9 +317,6 @@ all::
 # dependency rules.  The default is "auto", which means to use computed header
 # dependencies if your compiler is detected to support it.
 #
-# Define CHECK_HEADER_DEPENDENCIES to check for problems in the hard-coded
-# dependency rules.
-#
 # Define NATIVE_CRLF if your platform uses CRLF for line endings.
 #
 # Define XDL_FAST_HASH to use an alternative line-hashing method in
@@ -432,7 +429,6 @@ XDIFF_OBJS =
 VCSSVN_OBJS =
 GENERATED_H =
 EXTRA_CPPFLAGS =
-LIB_H =
 LIB_OBJS =
 PROGRAM_OBJS =
 PROGRAMS =
@@ -551,6 +547,7 @@ PROGRAMS += $(patsubst %.o,git-%$X,$(PROGRAM_OBJS))
 
 TEST_PROGRAMS_NEED_X += test-chmtime
 TEST_PROGRAMS_NEED_X += test-ctype
+TEST_PROGRAMS_NEED_X += test-config
 TEST_PROGRAMS_NEED_X += test-date
 TEST_PROGRAMS_NEED_X += test-delta
 TEST_PROGRAMS_NEED_X += test-dump-cache-tree
@@ -631,131 +628,11 @@ VCSSVN_LIB = vcs-svn/lib.a
 
 GENERATED_H += common-cmds.h
 
-LIB_H += advice.h
-LIB_H += archive.h
-LIB_H += argv-array.h
-LIB_H += attr.h
-LIB_H += bisect.h
-LIB_H += blob.h
-LIB_H += branch.h
-LIB_H += builtin.h
-LIB_H += bulk-checkin.h
-LIB_H += bundle.h
-LIB_H += cache-tree.h
-LIB_H += cache.h
-LIB_H += color.h
-LIB_H += column.h
-LIB_H += commit.h
-LIB_H += compat/bswap.h
-LIB_H += compat/mingw.h
-LIB_H += compat/obstack.h
-LIB_H += compat/poll/poll.h
-LIB_H += compat/precompose_utf8.h
-LIB_H += compat/terminal.h
-LIB_H += compat/win32/dirent.h
-LIB_H += compat/win32/pthread.h
-LIB_H += compat/win32/syslog.h
-LIB_H += connected.h
-LIB_H += convert.h
-LIB_H += credential.h
-LIB_H += csum-file.h
-LIB_H += decorate.h
-LIB_H += delta.h
-LIB_H += diff.h
-LIB_H += diffcore.h
-LIB_H += dir.h
-LIB_H += exec_cmd.h
-LIB_H += ewah/ewok.h
-LIB_H += ewah/ewok_rlw.h
-LIB_H += fetch-pack.h
-LIB_H += fmt-merge-msg.h
-LIB_H += fsck.h
-LIB_H += gettext.h
-LIB_H += git-compat-util.h
-LIB_H += gpg-interface.h
-LIB_H += graph.h
-LIB_H += grep.h
-LIB_H += hashmap.h
-LIB_H += help.h
-LIB_H += http.h
-LIB_H += kwset.h
-LIB_H += levenshtein.h
-LIB_H += line-log.h
-LIB_H += line-range.h
-LIB_H += list-objects.h
-LIB_H += ll-merge.h
-LIB_H += log-tree.h
-LIB_H += mailmap.h
-LIB_H += merge-blobs.h
-LIB_H += merge-recursive.h
-LIB_H += mergesort.h
-LIB_H += notes-cache.h
-LIB_H += notes-merge.h
-LIB_H += notes-utils.h
-LIB_H += notes.h
-LIB_H += object.h
-LIB_H += pack-objects.h
-LIB_H += pack-revindex.h
-LIB_H += pack.h
-LIB_H += pack-bitmap.h
-LIB_H += parse-options.h
-LIB_H += patch-ids.h
-LIB_H += pathspec.h
-LIB_H += pkt-line.h
-LIB_H += prio-queue.h
-LIB_H += progress.h
-LIB_H += prompt.h
-LIB_H += quote.h
-LIB_H += reachable.h
-LIB_H += reflog-walk.h
-LIB_H += refs.h
-LIB_H += remote.h
-LIB_H += rerere.h
-LIB_H += resolve-undo.h
-LIB_H += revision.h
-LIB_H += run-command.h
-LIB_H += send-pack.h
-LIB_H += sequencer.h
-LIB_H += sha1-array.h
-LIB_H += sha1-lookup.h
-LIB_H += shortlog.h
-LIB_H += sideband.h
-LIB_H += sigchain.h
-LIB_H += strbuf.h
-LIB_H += streaming.h
-LIB_H += string-list.h
-LIB_H += submodule.h
-LIB_H += tag.h
-LIB_H += tar.h
-LIB_H += thread-utils.h
-LIB_H += transport.h
-LIB_H += tree-walk.h
-LIB_H += tree.h
-LIB_H += unpack-trees.h
-LIB_H += unicode_width.h
-LIB_H += url.h
-LIB_H += urlmatch.h
-LIB_H += userdiff.h
-LIB_H += utf8.h
-LIB_H += varint.h
-LIB_H += vcs-svn/fast_export.h
-LIB_H += vcs-svn/line_buffer.h
-LIB_H += vcs-svn/repo_tree.h
-LIB_H += vcs-svn/sliding_window.h
-LIB_H += vcs-svn/svndiff.h
-LIB_H += vcs-svn/svndump.h
-LIB_H += walker.h
-LIB_H += wildmatch.h
-LIB_H += wt-status.h
-LIB_H += xdiff-interface.h
-LIB_H += xdiff/xdiff.h
-LIB_H += xdiff/xdiffi.h
-LIB_H += xdiff/xemit.h
-LIB_H += xdiff/xinclude.h
-LIB_H += xdiff/xmacros.h
-LIB_H += xdiff/xprepare.h
-LIB_H += xdiff/xtypes.h
-LIB_H += xdiff/xutils.h
+LIB_H = $(shell $(FIND) . \
+       -name .git -prune -o \
+       -name t -prune -o \
+       -name Documentation -prune -o \
+       -name '*.h' -print)
 
 LIB_OBJS += abspath.o
 LIB_OBJS += advice.o
@@ -1025,11 +902,6 @@ sysconfdir = etc
 endif
 endif
 
-ifdef CHECK_HEADER_DEPENDENCIES
-COMPUTE_HEADER_DEPENDENCIES = no
-USE_COMPUTED_HEADER_DEPENDENCIES =
-endif
-
 ifndef COMPUTE_HEADER_DEPENDENCIES
 COMPUTE_HEADER_DEPENDENCIES = auto
 endif
@@ -1381,7 +1253,6 @@ ifdef NO_INET_PTON
 endif
 ifndef NO_UNIX_SOCKETS
        LIB_OBJS += unix-socket.o
-       LIB_H += unix-socket.h
        PROGRAM_OBJS += credential-cache.o
        PROGRAM_OBJS += credential-cache--daemon.o
 endif
@@ -1405,12 +1276,10 @@ endif
 ifdef BLK_SHA1
        SHA1_HEADER = "block-sha1/sha1.h"
        LIB_OBJS += block-sha1/sha1.o
-       LIB_H += block-sha1/sha1.h
 else
 ifdef PPC_SHA1
        SHA1_HEADER = "ppc/sha1.h"
        LIB_OBJS += ppc/sha1.o ppc/sha1ppc.o
-       LIB_H += ppc/sha1.h
 else
 ifdef APPLE_COMMON_CRYPTO
        COMPAT_CFLAGS += -DCOMMON_DIGEST_FOR_OPENSSL
@@ -1479,6 +1348,9 @@ ifdef NO_REGEX
        COMPAT_CFLAGS += -Icompat/regex
        COMPAT_OBJS += compat/regex/regex.o
 endif
+ifdef NATIVE_CRLF
+       BASIC_CFLAGS += -DNATIVE_CRLF
+endif
 
 ifdef USE_NED_ALLOCATOR
        COMPAT_CFLAGS += -Icompat/nedmalloc
@@ -1937,29 +1809,13 @@ $(dep_dirs):
 missing_dep_dirs := $(filter-out $(wildcard $(dep_dirs)),$(dep_dirs))
 dep_file = $(dir $@).depend/$(notdir $@).d
 dep_args = -MF $(dep_file) -MQ $@ -MMD -MP
-ifdef CHECK_HEADER_DEPENDENCIES
-$(error cannot compute header dependencies outside a normal build. \
-Please unset CHECK_HEADER_DEPENDENCIES and try again)
-endif
 endif
 
 ifneq ($(COMPUTE_HEADER_DEPENDENCIES),yes)
-ifndef CHECK_HEADER_DEPENDENCIES
 dep_dirs =
 missing_dep_dirs =
 dep_args =
 endif
-endif
-
-ifdef CHECK_HEADER_DEPENDENCIES
-ifndef PRINT_HEADER_DEPENDENCIES
-missing_deps = $(filter-out $(notdir $^), \
-       $(notdir $(shell $(MAKE) -s $@ \
-               CHECK_HEADER_DEPENDENCIES=YesPlease \
-               USE_COMPUTED_HEADER_DEPENDENCIES=YesPlease \
-               PRINT_HEADER_DEPENDENCIES=YesPlease)))
-endif
-endif
 
 ASM_SRC := $(wildcard $(OBJECTS:o=S))
 ASM_OBJ := $(ASM_SRC:S=o)
@@ -1967,45 +1823,10 @@ C_OBJ := $(filter-out $(ASM_OBJ),$(OBJECTS))
 
 .SUFFIXES:
 
-ifdef PRINT_HEADER_DEPENDENCIES
-$(C_OBJ): %.o: %.c FORCE
-       echo $^
-$(ASM_OBJ): %.o: %.S FORCE
-       echo $^
-
-ifndef CHECK_HEADER_DEPENDENCIES
-$(error cannot print header dependencies during a normal build. \
-Please set CHECK_HEADER_DEPENDENCIES and try again)
-endif
-endif
-
-ifndef PRINT_HEADER_DEPENDENCIES
-ifdef CHECK_HEADER_DEPENDENCIES
-$(C_OBJ): %.o: %.c $(dep_files) FORCE
-       @set -e; echo CHECK $@; \
-       missing_deps="$(missing_deps)"; \
-       if test "$$missing_deps"; \
-       then \
-               echo missing dependencies: $$missing_deps; \
-               false; \
-       fi
-$(ASM_OBJ): %.o: %.S $(dep_files) FORCE
-       @set -e; echo CHECK $@; \
-       missing_deps="$(missing_deps)"; \
-       if test "$$missing_deps"; \
-       then \
-               echo missing dependencies: $$missing_deps; \
-               false; \
-       fi
-endif
-endif
-
-ifndef CHECK_HEADER_DEPENDENCIES
 $(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
        $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
 $(ASM_OBJ): %.o: %.S GIT-CFLAGS $(missing_dep_dirs)
        $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
-endif
 
 %.s: %.c GIT-CFLAGS FORCE
        $(QUIET_CC)$(CC) -o $@ -S $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
@@ -2132,9 +1953,9 @@ XGETTEXT_FLAGS_C = $(XGETTEXT_FLAGS) --language=C \
 XGETTEXT_FLAGS_SH = $(XGETTEXT_FLAGS) --language=Shell \
        --keyword=gettextln --keyword=eval_gettextln
 XGETTEXT_FLAGS_PERL = $(XGETTEXT_FLAGS) --keyword=__ --language=Perl
-LOCALIZED_C := $(C_OBJ:o=c) $(LIB_H) $(GENERATED_H)
-LOCALIZED_SH := $(SCRIPT_SH)
-LOCALIZED_PERL := $(SCRIPT_PERL)
+LOCALIZED_C = $(C_OBJ:o=c) $(LIB_H) $(GENERATED_H)
+LOCALIZED_SH = $(SCRIPT_SH)
+LOCALIZED_PERL = $(SCRIPT_PERL)
 
 ifdef XGETTEXT_INCLUDE_TESTS
 LOCALIZED_C += t/t0200/test.c
@@ -2142,7 +1963,7 @@ LOCALIZED_SH += t/t0200/test.sh
 LOCALIZED_PERL += t/t0200/test.perl
 endif
 
-po/git.pot: $(LOCALIZED_C)
+po/git.pot: $(GENERATED_H) FORCE
        $(QUIET_XGETTEXT)$(XGETTEXT) -o$@+ $(XGETTEXT_FLAGS_C) $(LOCALIZED_C)
        $(QUIET_XGETTEXT)$(XGETTEXT) -o$@+ --join-existing $(XGETTEXT_FLAGS_SH) \
                $(LOCALIZED_SH)
index f2706be6c1253c8e902badc8d01f58381e0c05b6..c473b35ad95f0fc1ff05c19493ded96ca6a48f55 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.1.2.txt
\ No newline at end of file
+Documentation/RelNotes/2.2.0.txt
\ No newline at end of file
index ca33558a91c5259a793fc56b571fa683e16b134f..5edb4e78162ca6646ef42ad2c8abc36872cd75a5 100644 (file)
--- a/abspath.c
+++ b/abspath.c
@@ -33,7 +33,7 @@ int is_directory(const char *path)
  */
 static const char *real_path_internal(const char *path, int die_on_error)
 {
-       static char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1];
+       static struct strbuf sb = STRBUF_INIT;
        char *retval = NULL;
 
        /*
@@ -41,16 +41,14 @@ static const char *real_path_internal(const char *path, int die_on_error)
         * here so that we can chdir() back to it at the end of the
         * function:
         */
-       char cwd[1024] = "";
-
-       int buf_index = 1;
+       struct strbuf cwd = STRBUF_INIT;
 
        int depth = MAXDEPTH;
        char *last_elem = NULL;
        struct stat st;
 
        /* We've already done it */
-       if (path == buf || path == next_buf)
+       if (path == sb.buf)
                return path;
 
        if (!*path) {
@@ -60,41 +58,38 @@ static const char *real_path_internal(const char *path, int die_on_error)
                        goto error_out;
        }
 
-       if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX) {
-               if (die_on_error)
-                       die("Too long path: %.*s", 60, path);
-               else
-                       goto error_out;
-       }
+       strbuf_reset(&sb);
+       strbuf_addstr(&sb, path);
 
        while (depth--) {
-               if (!is_directory(buf)) {
-                       char *last_slash = find_last_dir_sep(buf);
+               if (!is_directory(sb.buf)) {
+                       char *last_slash = find_last_dir_sep(sb.buf);
                        if (last_slash) {
                                last_elem = xstrdup(last_slash + 1);
-                               last_slash[1] = '\0';
+                               strbuf_setlen(&sb, last_slash - sb.buf + 1);
                        } else {
-                               last_elem = xstrdup(buf);
-                               *buf = '\0';
+                               last_elem = xmemdupz(sb.buf, sb.len);
+                               strbuf_reset(&sb);
                        }
                }
 
-               if (*buf) {
-                       if (!*cwd && !getcwd(cwd, sizeof(cwd))) {
+               if (sb.len) {
+                       if (!cwd.len && strbuf_getcwd(&cwd)) {
                                if (die_on_error)
                                        die_errno("Could not get current working directory");
                                else
                                        goto error_out;
                        }
 
-                       if (chdir(buf)) {
+                       if (chdir(sb.buf)) {
                                if (die_on_error)
-                                       die_errno("Could not switch to '%s'", buf);
+                                       die_errno("Could not switch to '%s'",
+                                                 sb.buf);
                                else
                                        goto error_out;
                        }
                }
-               if (!getcwd(buf, PATH_MAX)) {
+               if (strbuf_getcwd(&sb)) {
                        if (die_on_error)
                                die_errno("Could not get current working directory");
                        else
@@ -102,48 +97,35 @@ static const char *real_path_internal(const char *path, int die_on_error)
                }
 
                if (last_elem) {
-                       size_t len = strlen(buf);
-                       if (len + strlen(last_elem) + 2 > PATH_MAX) {
-                               if (die_on_error)
-                                       die("Too long path name: '%s/%s'",
-                                           buf, last_elem);
-                               else
-                                       goto error_out;
-                       }
-                       if (len && !is_dir_sep(buf[len - 1]))
-                               buf[len++] = '/';
-                       strcpy(buf + len, last_elem);
+                       if (sb.len && !is_dir_sep(sb.buf[sb.len - 1]))
+                               strbuf_addch(&sb, '/');
+                       strbuf_addstr(&sb, last_elem);
                        free(last_elem);
                        last_elem = NULL;
                }
 
-               if (!lstat(buf, &st) && S_ISLNK(st.st_mode)) {
-                       ssize_t len = readlink(buf, next_buf, PATH_MAX);
+               if (!lstat(sb.buf, &st) && S_ISLNK(st.st_mode)) {
+                       struct strbuf next_sb = STRBUF_INIT;
+                       ssize_t len = strbuf_readlink(&next_sb, sb.buf, 0);
                        if (len < 0) {
                                if (die_on_error)
-                                       die_errno("Invalid symlink '%s'", buf);
-                               else
-                                       goto error_out;
-                       }
-                       if (PATH_MAX <= len) {
-                               if (die_on_error)
-                                       die("symbolic link too long: %s", buf);
+                                       die_errno("Invalid symlink '%s'",
+                                                 sb.buf);
                                else
                                        goto error_out;
                        }
-                       next_buf[len] = '\0';
-                       buf = next_buf;
-                       buf_index = 1 - buf_index;
-                       next_buf = bufs[buf_index];
+                       strbuf_swap(&sb, &next_sb);
+                       strbuf_release(&next_sb);
                } else
                        break;
        }
 
-       retval = buf;
+       retval = sb.buf;
 error_out:
        free(last_elem);
-       if (*cwd && chdir(cwd))
-               die_errno("Could not change back to '%s'", cwd);
+       if (cwd.len && chdir(cwd.buf))
+               die_errno("Could not change back to '%s'", cwd.buf);
+       strbuf_release(&cwd);
 
        return retval;
 }
@@ -158,54 +140,16 @@ const char *real_path_if_valid(const char *path)
        return real_path_internal(path, 0);
 }
 
-static const char *get_pwd_cwd(void)
-{
-       static char cwd[PATH_MAX + 1];
-       char *pwd;
-       struct stat cwd_stat, pwd_stat;
-       if (getcwd(cwd, PATH_MAX) == NULL)
-               return NULL;
-       pwd = getenv("PWD");
-       if (pwd && strcmp(pwd, cwd)) {
-               stat(cwd, &cwd_stat);
-               if ((cwd_stat.st_dev || cwd_stat.st_ino) &&
-                   !stat(pwd, &pwd_stat) &&
-                   pwd_stat.st_dev == cwd_stat.st_dev &&
-                   pwd_stat.st_ino == cwd_stat.st_ino) {
-                       strlcpy(cwd, pwd, PATH_MAX);
-               }
-       }
-       return cwd;
-}
-
 /*
  * Use this to get an absolute path from a relative one. If you want
  * to resolve links, you should use real_path.
- *
- * If the path is already absolute, then return path. As the user is
- * never meant to free the return value, we're safe.
  */
 const char *absolute_path(const char *path)
 {
-       static char buf[PATH_MAX + 1];
-
-       if (!*path) {
-               die("The empty string is not a valid path");
-       } else if (is_absolute_path(path)) {
-               if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
-                       die("Too long path: %.*s", 60, path);
-       } else {
-               size_t len;
-               const char *fmt;
-               const char *cwd = get_pwd_cwd();
-               if (!cwd)
-                       die_errno("Cannot determine the current working directory");
-               len = strlen(cwd);
-               fmt = (len > 0 && is_dir_sep(cwd[len - 1])) ? "%s%s" : "%s/%s";
-               if (snprintf(buf, PATH_MAX, fmt, cwd, path) >= PATH_MAX)
-                       die("Too long path: %.*s", 60, path);
-       }
-       return buf;
+       static struct strbuf sb = STRBUF_INIT;
+       strbuf_reset(&sb);
+       strbuf_add_absolute_path(&sb, path);
+       return sb.buf;
 }
 
 /*
index 9b420331926c6bf1aa371f973d6a96886f419b06..3b8bf3c6da6afdd5ef4cfcc77131690ccbbf3757 100644 (file)
--- a/advice.c
+++ b/advice.c
@@ -86,8 +86,7 @@ int error_resolve_conflict(const char *me)
                 * other commands doing a merge do.
                 */
                advise(_("Fix them up in the work tree, and then use 'git add/rm <file>'\n"
-                        "as appropriate to mark resolution and make a commit, or use\n"
-                        "'git commit -a'."));
+                        "as appropriate to mark resolution and make a commit."));
        return -1;
 }
 
diff --git a/alias.c b/alias.c
index 758c8671494ad003a6e7e33f8a14b5450311bf54..6aa164a362427ffa5dc8616bcb01aec3f15b462b 100644 (file)
--- a/alias.c
+++ b/alias.c
@@ -1,26 +1,13 @@
 #include "cache.h"
 
-static const char *alias_key;
-static char *alias_val;
-
-static int alias_lookup_cb(const char *k, const char *v, void *cb)
-{
-       const char *name;
-       if (skip_prefix(k, "alias.", &name) && !strcmp(name, alias_key)) {
-               if (!v)
-                       return config_error_nonbool(k);
-               alias_val = xstrdup(v);
-               return 0;
-       }
-       return 0;
-}
-
 char *alias_lookup(const char *alias)
 {
-       alias_key = alias;
-       alias_val = NULL;
-       git_config(alias_lookup_cb, NULL);
-       return alias_val;
+       char *v = NULL;
+       struct strbuf key = STRBUF_INIT;
+       strbuf_addf(&key, "alias.%s", alias);
+       git_config_get_string(key.buf, &v);
+       strbuf_release(&key);
+       return v;
 }
 
 #define SPLIT_CMDLINE_BAD_ENDING 1
index 719b6298e6abf9c9e9e8009ec49dfc76d0d9e49b..df2f4c8a643796ee96a31185f2a49fa7e00ca991 100644 (file)
@@ -192,7 +192,7 @@ static int write_extended_header(struct archiver_args *args,
        unsigned int mode;
        memset(&header, 0, sizeof(header));
        *header.typeflag = TYPEFLAG_EXT_HEADER;
-       mode = 0100666;
+       mode = 0100666 & ~tar_umask;
        sprintf(header.name, "%s.paxheader", sha1_to_hex(sha1));
        prepare_header(args, &header, mode, size);
        write_blocked(&header, sizeof(header));
@@ -300,7 +300,7 @@ static int write_global_extended_header(struct archiver_args *args)
        strbuf_append_ext_header(&ext_header, "comment", sha1_to_hex(sha1), 40);
        memset(&header, 0, sizeof(header));
        *header.typeflag = TYPEFLAG_GLOBAL_HEADER;
-       mode = 0100666;
+       mode = 0100666 & ~tar_umask;
        strcpy(header.name, "pax_global_header");
        prepare_header(args, &header, mode, ext_header.len);
        write_blocked(&header, sizeof(header));
@@ -395,7 +395,7 @@ static int write_tar_filter_archive(const struct archiver *ar,
                                    struct archiver_args *args)
 {
        struct strbuf cmd = STRBUF_INIT;
-       struct child_process filter;
+       struct child_process filter = CHILD_PROCESS_INIT;
        const char *argv[2];
        int r;
 
@@ -406,7 +406,6 @@ static int write_tar_filter_archive(const struct archiver *ar,
        if (args->compression_level >= 0)
                strbuf_addf(&cmd, " -%d", args->compression_level);
 
-       memset(&filter, 0, sizeof(filter));
        argv[0] = cmd.buf;
        argv[1] = NULL;
        filter.argv = argv;
index 3fc0fb2928f1007ec5d8763d9d3a9b88152059ad..952a659bcb59ea8b476d6677f2a04d717c6c7dd2 100644 (file)
--- a/archive.c
+++ b/archive.c
@@ -402,14 +402,6 @@ static int parse_archive_args(int argc, const char **argv,
        return argc;
 }
 
-static int git_default_archive_config(const char *var, const char *value,
-                                     void *cb)
-{
-       if (!strcmp(var, "uploadarchive.allowunreachable"))
-               remote_allow_unreachable = git_config_bool(var, value);
-       return git_default_config(var, value, cb);
-}
-
 int write_archive(int argc, const char **argv, const char *prefix,
                  int setup_prefix, const char *name_hint, int remote)
 {
@@ -420,7 +412,9 @@ int write_archive(int argc, const char **argv, const char *prefix,
        if (setup_prefix && prefix == NULL)
                prefix = setup_git_directory_gently(&nongit);
 
-       git_config(git_default_archive_config, NULL);
+       git_config_get_bool("uploadarchive.allowunreachable", &remote_allow_unreachable);
+       git_config(git_default_config, NULL);
+
        init_tar_archiver();
        init_zip_archiver();
 
diff --git a/attr.c b/attr.c
index 734222dc45c588736f963dea7907258e76024415..cd5469770a6f7841ae327e6ba7141dd99d9cacc1 100644 (file)
--- a/attr.c
+++ b/attr.c
@@ -97,8 +97,7 @@ static struct git_attr *git_attr_internal(const char *name, int len)
        a->attr_nr = attr_nr++;
        git_attr_hash[pos] = a;
 
-       check_all_attr = xrealloc(check_all_attr,
-                                 sizeof(*check_all_attr) * attr_nr);
+       REALLOC_ARRAY(check_all_attr, attr_nr);
        check_all_attr[a->attr_nr].attr = a;
        check_all_attr[a->attr_nr].value = ATTR__UNKNOWN;
        return a;
index d6e851d783c3541eb21edd47170ce7a32e082e61..df09cbc8cabe9dcb87a0023445babcf14c3d7691 100644 (file)
--- a/bisect.c
+++ b/bisect.c
@@ -215,11 +215,12 @@ static struct commit_list *best_bisection_sorted(struct commit_list *list, int n
        }
        qsort(array, cnt, sizeof(*array), compare_commit_dist);
        for (p = list, i = 0; i < cnt; i++) {
-               struct name_decoration *r = xmalloc(sizeof(*r) + 100);
+               char buf[100]; /* enough for dist=%d */
                struct object *obj = &(array[i].commit->object);
 
-               sprintf(r->name, "dist=%d", array[i].distance);
-               r->next = add_decoration(&name_decoration, obj, r);
+               snprintf(buf, sizeof(buf), "dist=%d", array[i].distance);
+               add_name_decoration(DECORATION_NONE, buf, obj);
+
                p->item = array[i].commit;
                p = p->next;
        }
index 46e8aa86df1811ff19899869a33ecb48cacb107f..9a2228ebb46df721741db2249ab25cce5dfb4282 100644 (file)
--- a/branch.c
+++ b/branch.c
@@ -140,33 +140,17 @@ static int setup_tracking(const char *new_ref, const char *orig_ref,
        return 0;
 }
 
-struct branch_desc_cb {
-       const char *config_name;
-       const char *value;
-};
-
-static int read_branch_desc_cb(const char *var, const char *value, void *cb)
-{
-       struct branch_desc_cb *desc = cb;
-       if (strcmp(desc->config_name, var))
-               return 0;
-       free((char *)desc->value);
-       return git_config_string(&desc->value, var, value);
-}
-
 int read_branch_desc(struct strbuf *buf, const char *branch_name)
 {
-       struct branch_desc_cb cb;
+       char *v = NULL;
        struct strbuf name = STRBUF_INIT;
        strbuf_addf(&name, "branch.%s.description", branch_name);
-       cb.config_name = name.buf;
-       cb.value = NULL;
-       if (git_config(read_branch_desc_cb, &cb) < 0) {
+       if (git_config_get_string(name.buf, &v)) {
                strbuf_release(&name);
                return -1;
        }
-       if (cb.value)
-               strbuf_addstr(buf, cb.value);
+       strbuf_addstr(buf, v);
+       free(v);
        strbuf_release(&name);
        return 0;
 }
@@ -226,7 +210,6 @@ void create_branch(const char *head,
                   int force, int reflog, int clobber_head,
                   int quiet, enum branch_track track)
 {
-       struct ref_lock *lock = NULL;
        struct commit *commit;
        unsigned char sha1[20];
        char *real_ref, msg[PATH_MAX + 20];
@@ -285,15 +268,6 @@ void create_branch(const char *head,
                die(_("Not a valid branch point: '%s'."), start_name);
        hashcpy(sha1, commit->object.sha1);
 
-       if (!dont_change_ref) {
-               lock = lock_any_ref_for_update(ref.buf, NULL, 0, NULL);
-               if (!lock)
-                       die_errno(_("Failed to lock ref for update"));
-       }
-
-       if (reflog)
-               log_all_ref_updates = 1;
-
        if (forcing)
                snprintf(msg, sizeof msg, "branch: Reset to %s",
                         start_name);
@@ -301,13 +275,26 @@ void create_branch(const char *head,
                snprintf(msg, sizeof msg, "branch: Created from %s",
                         start_name);
 
+       if (reflog)
+               log_all_ref_updates = 1;
+
+       if (!dont_change_ref) {
+               struct ref_transaction *transaction;
+               struct strbuf err = STRBUF_INIT;
+
+               transaction = ref_transaction_begin(&err);
+               if (!transaction ||
+                   ref_transaction_update(transaction, ref.buf, sha1,
+                                          null_sha1, 0, !forcing, &err) ||
+                   ref_transaction_commit(transaction, msg, &err))
+                       die("%s", err.buf);
+               ref_transaction_free(transaction);
+               strbuf_release(&err);
+       }
+
        if (real_ref && track)
                setup_tracking(ref.buf + 11, real_ref, track, quiet);
 
-       if (!dont_change_ref)
-               if (write_ref_sha1(lock, sha1, msg) < 0)
-                       die_errno(_("Failed to write ref"));
-
        strbuf_release(&ref);
        free(real_ref);
 }
index 4baf3a563510b10e592ff06ae62df2f405413f6c..352b85e8db19e1b4fa05ca37804f0c625e582912 100644 (file)
@@ -180,7 +180,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
        char *file = git_pathdup("ADD_EDIT.patch");
        const char *apply_argv[] = { "apply", "--recount", "--cached",
                NULL, NULL };
-       struct child_process child;
+       struct child_process child = CHILD_PROCESS_INIT;
        struct rev_info rev;
        int out;
        struct stat st;
@@ -214,7 +214,6 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
        if (!st.st_size)
                die(_("Empty patch. Aborted."));
 
-       memset(&child, 0, sizeof(child));
        child.git_cmd = 1;
        child.argv = apply_argv;
        if (run_command(&child))
index 6b7c764918cff18957f67a2e345c0610e459859d..8714a887203acd84ad08f3e0917fc72b2c7a3138 100644 (file)
@@ -2626,7 +2626,7 @@ static void update_image(struct image *img,
                 * NOTE: this knows that we never call remove_first_line()
                 * on anything other than pre/post image.
                 */
-               img->line = xrealloc(img->line, nr * sizeof(*img->line));
+               REALLOC_ARRAY(img->line, nr);
                img->line_allocated = img->line;
        }
        if (preimage_limit != postimage->nr)
@@ -4274,13 +4274,11 @@ static int apply_patch(int fd, const char *filename, int options)
        return 0;
 }
 
-static int git_apply_config(const char *var, const char *value, void *cb)
+static void git_apply_config(void)
 {
-       if (!strcmp(var, "apply.whitespace"))
-               return git_config_string(&apply_default_whitespace, var, value);
-       else if (!strcmp(var, "apply.ignorewhitespace"))
-               return git_config_string(&apply_default_ignorewhitespace, var, value);
-       return git_default_config(var, value, cb);
+       git_config_get_string_const("apply.whitespace", &apply_default_whitespace);
+       git_config_get_string_const("apply.ignorewhitespace", &apply_default_ignorewhitespace);
+       git_config(git_default_config, NULL);
 }
 
 static int option_parse_exclude(const struct option *opt,
@@ -4428,7 +4426,7 @@ int cmd_apply(int argc, const char **argv, const char *prefix_)
 
        prefix = prefix_;
        prefix_length = prefix ? strlen(prefix) : 0;
-       git_config(git_apply_config, NULL);
+       git_apply_config();
        if (apply_default_whitespace)
                parse_whitespace_option(apply_default_whitespace);
        if (apply_default_ignorewhitespace)
index 17d30d00aa3f6c4d0f62cae6603f9003dd2f2395..3838be2b0274fbd72b200c2bf294e4d2842a020c 100644 (file)
@@ -2580,6 +2580,9 @@ parse_done:
        case DATE_RFC2822:
                blame_date_width = sizeof("Thu, 19 Oct 2006 16:00:04 -0700");
                break;
+       case DATE_ISO8601_STRICT:
+               blame_date_width = sizeof("2006-10-19T16:00:04-07:00");
+               break;
        case DATE_ISO8601:
                blame_date_width = sizeof("2006-10-19 16:00:04 -0700");
                break;
@@ -2700,7 +2703,7 @@ parse_done:
         * uninteresting.
         */
        if (prepare_revision_walk(&revs))
-               die("revision walk setup failed");
+               die(_("revision walk setup failed"));
 
        if (is_null_sha1(sb.final->object.sha1)) {
                o = sb.final->util;
index 0591b22a483619ac9a7d889a49e45ffa9d68ab72..9e4666f0c53164113ac211eee674ba838fb7ae72 100644 (file)
@@ -280,6 +280,7 @@ struct ref_item {
        char *dest;
        unsigned int kind, width;
        struct commit *commit;
+       int ignore;
 };
 
 struct ref_list {
@@ -385,6 +386,7 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags,
        newitem->commit = commit;
        newitem->width = utf8_strwidth(refname);
        newitem->dest = resolve_symref(orig_refname, prefix);
+       newitem->ignore = 0;
        /* adjust for "remotes/" */
        if (newitem->kind == REF_REMOTE_BRANCH &&
            ref_list->kinds != REF_REMOTE_BRANCH)
@@ -484,17 +486,6 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
        free(ref);
 }
 
-static int matches_merge_filter(struct commit *commit)
-{
-       int is_merged;
-
-       if (merge_filter == NO_FILTER)
-               return 1;
-
-       is_merged = !!(commit->object.flags & UNINTERESTING);
-       return (is_merged == (merge_filter == SHOW_MERGED));
-}
-
 static void add_verbose_info(struct strbuf *out, struct ref_item *item,
                             int verbose, int abbrev)
 {
@@ -522,10 +513,9 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
 {
        char c;
        int color;
-       struct commit *commit = item->commit;
        struct strbuf out = STRBUF_INIT, name = STRBUF_INIT;
 
-       if (!matches_merge_filter(commit))
+       if (item->ignore)
                return;
 
        switch (item->kind) {
@@ -575,7 +565,7 @@ static int calc_maxwidth(struct ref_list *refs)
 {
        int i, w = 0;
        for (i = 0; i < refs->index; i++) {
-               if (!matches_merge_filter(refs->list[i].commit))
+               if (refs->list[i].ignore)
                        continue;
                if (refs->list[i].width > w)
                        w = refs->list[i].width;
@@ -618,6 +608,7 @@ static void show_detached(struct ref_list *ref_list)
                item.kind = REF_LOCAL_BRANCH;
                item.dest = NULL;
                item.commit = head_commit;
+               item.ignore = 0;
                if (item.width > ref_list->maxwidth)
                        ref_list->maxwidth = item.width;
                print_ref_item(&item, ref_list->maxwidth, ref_list->verbose, ref_list->abbrev, 1, "");
@@ -653,7 +644,23 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru
                add_pending_object(&ref_list.revs,
                                   (struct object *) filter, "");
                ref_list.revs.limited = 1;
-               prepare_revision_walk(&ref_list.revs);
+
+               if (prepare_revision_walk(&ref_list.revs))
+                       die(_("revision walk setup failed"));
+
+               for (i = 0; i < ref_list.index; i++) {
+                       struct ref_item *item = &ref_list.list[i];
+                       struct commit *commit = item->commit;
+                       int is_merged = !!(commit->object.flags & UNINTERESTING);
+                       item->ignore = is_merged != (merge_filter == SHOW_MERGED);
+               }
+
+               for (i = 0; i < ref_list.index; i++) {
+                       struct ref_item *item = &ref_list.list[i];
+                       clear_commit_marks(item->commit, ALL_REV_FLAGS);
+               }
+               clear_commit_marks(filter, ALL_REV_FLAGS);
+
                if (verbose)
                        ref_list.maxwidth = calc_maxwidth(&ref_list);
        }
index f71e74531d2a7d195ff2987f6dca3c69c636aa7c..8afdf2b5c4bfbd53e7315afe9d8ae3d88f93dd57 100644 (file)
@@ -552,6 +552,12 @@ static int merge_working_tree(const struct checkout_opts *opts,
                }
        }
 
+       if (!active_cache_tree)
+               active_cache_tree = cache_tree();
+
+       if (!cache_tree_fully_valid(active_cache_tree))
+               cache_tree_update(&the_index, WRITE_TREE_SILENT | WRITE_TREE_REPAIR);
+
        if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
                die(_("unable to write new index file"));
 
index 1032563e5fae880df9256c9eafaa96d60462ecd2..3beeea6ec0fdc3883f2456caf46f3e1c4dadc682 100644 (file)
@@ -67,7 +67,7 @@ struct menu_item {
        char hotkey;
        const char *title;
        int selected;
-       int (*fn)();
+       int (*fn)(void);
 };
 
 enum menu_stuff_type {
index bbd169ceb49b2e09197e469aeb572e9aa54d4b85..3927edfb6ede269929dc704cbb928a7516a8a0a7 100644 (file)
@@ -685,9 +685,10 @@ static void write_config(struct string_list *config)
        }
 }
 
-static void write_refspec_config(const char* src_ref_prefix,
-               const struct ref* our_head_points_at,
-               const struct ref* remote_head_points_at, struct strbuf* branch_top)
+static void write_refspec_config(const char *src_ref_prefix,
+               const struct ref *our_head_points_at,
+               const struct ref *remote_head_points_at,
+               struct strbuf *branch_top)
 {
        struct strbuf key = STRBUF_INIT;
        struct strbuf value = STRBUF_INIT;
@@ -1004,5 +1005,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        strbuf_release(&key);
        strbuf_release(&value);
        junk_mode = JUNK_LEAVE_ALL;
+
+       free(refspec);
        return err;
 }
index 5ed60364ce5eb1f458e1f5155d76abd7341d24ea..b0fe7847d3cbebd2cef28611171924bf7440c467 100644 (file)
@@ -42,7 +42,20 @@ static const char * const builtin_status_usage[] = {
        NULL
 };
 
-static const char implicit_ident_advice[] =
+static const char implicit_ident_advice_noconfig[] =
+N_("Your name and email address were configured automatically based\n"
+"on your username and hostname. Please check that they are accurate.\n"
+"You can suppress this message by setting them explicitly. Run the\n"
+"following command and follow the instructions in your editor to edit\n"
+"your configuration file:\n"
+"\n"
+"    git config --global --edit\n"
+"\n"
+"After doing this, you may fix the identity used for this commit with:\n"
+"\n"
+"    git commit --amend --reset-author\n");
+
+static const char implicit_ident_advice_config[] =
 N_("Your name and email address were configured automatically based\n"
 "on your username and hostname. Please check that they are accurate.\n"
 "You can suppress this message by setting them explicitly:\n"
@@ -340,6 +353,13 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,
 
                discard_cache();
                read_cache_from(index_lock.filename);
+               if (update_main_cache_tree(WRITE_TREE_SILENT) == 0) {
+                       if (reopen_lock_file(&index_lock) < 0)
+                               die(_("unable to write index file"));
+                       if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))
+                               die(_("unable to update temporary index"));
+               } else
+                       warning(_("Failed to update main cache tree"));
 
                commit_style = COMMIT_NORMAL;
                return index_lock.filename;
@@ -380,8 +400,12 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,
        if (!only && !pathspec.nr) {
                hold_locked_index(&index_lock, 1);
                refresh_cache_or_die(refresh_flags);
-               if (active_cache_changed) {
+               if (active_cache_changed
+                   || !cache_tree_fully_valid(active_cache_tree)) {
                        update_main_cache_tree(WRITE_TREE_SILENT);
+                       active_cache_changed = 1;
+               }
+               if (active_cache_changed) {
                        if (write_locked_index(&the_index, &index_lock,
                                               COMMIT_LOCK))
                                die(_("unable to write new_index file"));
@@ -431,6 +455,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,
        hold_locked_index(&index_lock, 1);
        add_remove_files(&partial);
        refresh_cache(REFRESH_QUIET);
+       update_main_cache_tree(WRITE_TREE_SILENT);
        if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))
                die(_("unable to write new_index file"));
 
@@ -520,77 +545,80 @@ static int sane_ident_split(struct ident_split *person)
        return 1;
 }
 
-static int parse_force_date(const char *in, char *out, int len)
+static int parse_force_date(const char *in, struct strbuf *out)
 {
-       if (len < 1)
-               return -1;
-       *out++ = '@';
-       len--;
+       strbuf_addch(out, '@');
 
-       if (parse_date(in, out, len) < 0) {
+       if (parse_date(in, out) < 0) {
                int errors = 0;
                unsigned long t = approxidate_careful(in, &errors);
                if (errors)
                        return -1;
-               snprintf(out, len, "%lu", t);
+               strbuf_addf(out, "%lu", t);
        }
 
        return 0;
 }
 
+static void set_ident_var(char **buf, char *val)
+{
+       free(*buf);
+       *buf = val;
+}
+
+static char *envdup(const char *var)
+{
+       const char *val = getenv(var);
+       return val ? xstrdup(val) : NULL;
+}
+
 static void determine_author_info(struct strbuf *author_ident)
 {
        char *name, *email, *date;
        struct ident_split author;
-       char date_buf[64];
 
-       name = getenv("GIT_AUTHOR_NAME");
-       email = getenv("GIT_AUTHOR_EMAIL");
-       date = getenv("GIT_AUTHOR_DATE");
+       name = envdup("GIT_AUTHOR_NAME");
+       email = envdup("GIT_AUTHOR_EMAIL");
+       date = envdup("GIT_AUTHOR_DATE");
 
        if (author_message) {
-               const char *a, *lb, *rb, *eol;
+               struct ident_split ident;
                size_t len;
+               const char *a;
 
-               a = strstr(author_message_buffer, "\nauthor ");
+               a = find_commit_header(author_message_buffer, "author", &len);
                if (!a)
-                       die(_("invalid commit: %s"), author_message);
-
-               lb = strchrnul(a + strlen("\nauthor "), '<');
-               rb = strchrnul(lb, '>');
-               eol = strchrnul(rb, '\n');
-               if (!*lb || !*rb || !*eol)
-                       die(_("invalid commit: %s"), author_message);
-
-               if (lb == a + strlen("\nauthor "))
-                       /* \nauthor <foo@example.com> */
-                       name = xcalloc(1, 1);
-               else
-                       name = xmemdupz(a + strlen("\nauthor "),
-                                       (lb - strlen(" ") -
-                                        (a + strlen("\nauthor "))));
-               email = xmemdupz(lb + strlen("<"), rb - (lb + strlen("<")));
-               len = eol - (rb + strlen("> "));
-               date = xmalloc(len + 2);
-               *date = '@';
-               memcpy(date + 1, rb + strlen("> "), len);
-               date[len + 1] = '\0';
+                       die(_("commit '%s' lacks author header"), author_message);
+               if (split_ident_line(&ident, a, len) < 0)
+                       die(_("commit '%s' has malformed author line"), author_message);
+
+               set_ident_var(&name, xmemdupz(ident.name_begin, ident.name_end - ident.name_begin));
+               set_ident_var(&email, xmemdupz(ident.mail_begin, ident.mail_end - ident.mail_begin));
+
+               if (ident.date_begin) {
+                       struct strbuf date_buf = STRBUF_INIT;
+                       strbuf_addch(&date_buf, '@');
+                       strbuf_add(&date_buf, ident.date_begin, ident.date_end - ident.date_begin);
+                       strbuf_addch(&date_buf, ' ');
+                       strbuf_add(&date_buf, ident.tz_begin, ident.tz_end - ident.tz_begin);
+                       set_ident_var(&date, strbuf_detach(&date_buf, NULL));
+               }
        }
 
        if (force_author) {
-               const char *lb = strstr(force_author, " <");
-               const char *rb = strchr(force_author, '>');
+               struct ident_split ident;
 
-               if (!lb || !rb)
+               if (split_ident_line(&ident, force_author, strlen(force_author)) < 0)
                        die(_("malformed --author parameter"));
-               name = xstrndup(force_author, lb - force_author);
-               email = xstrndup(lb + 2, rb - (lb + 2));
+               set_ident_var(&name, xmemdupz(ident.name_begin, ident.name_end - ident.name_begin));
+               set_ident_var(&email, xmemdupz(ident.mail_begin, ident.mail_end - ident.mail_begin));
        }
 
        if (force_date) {
-               if (parse_force_date(force_date, date_buf, sizeof(date_buf)))
+               struct strbuf date_buf = STRBUF_INIT;
+               if (parse_force_date(force_date, &date_buf))
                        die(_("invalid date format: %s"), force_date);
-               date = date_buf;
+               set_ident_var(&date, strbuf_detach(&date_buf, NULL));
        }
 
        strbuf_addstr(author_ident, fmt_ident(name, email, date, IDENT_STRICT));
@@ -600,6 +628,10 @@ static void determine_author_info(struct strbuf *author_ident)
                export_one("GIT_AUTHOR_EMAIL", author.mail_begin, author.mail_end, 0);
                export_one("GIT_AUTHOR_DATE", author.date_begin, author.tz_end, '@');
        }
+
+       free(name);
+       free(email);
+       free(date);
 }
 
 static void split_ident_or_die(struct ident_split *id, const struct strbuf *buf)
@@ -1048,7 +1080,8 @@ static const char *find_author_by_nickname(const char *name)
        revs.mailmap = &mailmap;
        read_mailmap(revs.mailmap, NULL);
 
-       prepare_revision_walk(&revs);
+       if (prepare_revision_walk(&revs))
+               die(_("revision walk setup failed"));
        commit = get_revision(&revs);
        if (commit) {
                struct pretty_print_context ctx = {0};
@@ -1402,6 +1435,24 @@ int cmd_status(int argc, const char **argv, const char *prefix)
        return 0;
 }
 
+static const char *implicit_ident_advice(void)
+{
+       char *user_config = NULL;
+       char *xdg_config = NULL;
+       int config_exists;
+
+       home_config_paths(&user_config, &xdg_config, "config");
+       config_exists = file_exists(user_config) || file_exists(xdg_config);
+       free(user_config);
+       free(xdg_config);
+
+       if (config_exists)
+               return _(implicit_ident_advice_config);
+       else
+               return _(implicit_ident_advice_noconfig);
+
+}
+
 static void print_summary(const char *prefix, const unsigned char *sha1,
                          int initial_commit)
 {
@@ -1440,7 +1491,7 @@ static void print_summary(const char *prefix, const unsigned char *sha1,
                strbuf_addbuf_percentquote(&format, &committer_ident);
                if (advice_implicit_identity) {
                        strbuf_addch(&format, '\n');
-                       strbuf_addstr(&format, _(implicit_ident_advice));
+                       strbuf_addstr(&format, implicit_ident_advice());
                }
        }
        strbuf_release(&author_ident);
@@ -1508,7 +1559,7 @@ static int run_rewrite_hook(const unsigned char *oldsha1,
 {
        /* oldsha1 SP newsha1 LF NUL */
        static char buf[2*40 + 3];
-       struct child_process proc;
+       struct child_process proc = CHILD_PROCESS_INIT;
        const char *argv[3];
        int code;
        size_t n;
@@ -1520,7 +1571,6 @@ static int run_rewrite_hook(const unsigned char *oldsha1,
        argv[1] = "amend";
        argv[2] = NULL;
 
-       memset(&proc, 0, sizeof(proc));
        proc.argv = argv;
        proc.in = -1;
        proc.stdout_to_stderr = 1;
@@ -1620,11 +1670,12 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
        const char *index_file, *reflog_msg;
        char *nl;
        unsigned char sha1[20];
-       struct ref_lock *ref_lock;
        struct commit_list *parents = NULL, **pptr = &parents;
        struct stat statbuf;
        struct commit *current_head = NULL;
        struct commit_extra_header *extra = NULL;
+       struct ref_transaction *transaction;
+       struct strbuf err = STRBUF_INIT;
 
        if (argc == 2 && !strcmp(argv[1], "-h"))
                usage_with_options(builtin_commit_usage, builtin_commit_options);
@@ -1746,16 +1797,6 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
        strbuf_release(&author_ident);
        free_commit_extra_headers(extra);
 
-       ref_lock = lock_any_ref_for_update("HEAD",
-                                          !current_head
-                                          ? NULL
-                                          : current_head->object.sha1,
-                                          0, NULL);
-       if (!ref_lock) {
-               rollback_index_files();
-               die(_("cannot lock HEAD ref"));
-       }
-
        nl = strchr(sb.buf, '\n');
        if (nl)
                strbuf_setlen(&sb, nl + 1 - sb.buf);
@@ -1764,10 +1805,17 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
        strbuf_insert(&sb, 0, reflog_msg, strlen(reflog_msg));
        strbuf_insert(&sb, strlen(reflog_msg), ": ", 2);
 
-       if (write_ref_sha1(ref_lock, sha1, sb.buf) < 0) {
+       transaction = ref_transaction_begin(&err);
+       if (!transaction ||
+           ref_transaction_update(transaction, "HEAD", sha1,
+                                  current_head
+                                  ? current_head->object.sha1 : NULL,
+                                  0, !!current_head, &err) ||
+           ref_transaction_commit(transaction, sb.buf, &err)) {
                rollback_index_files();
-               die(_("cannot update HEAD ref"));
+               die("%s", err.buf);
        }
+       ref_transaction_free(transaction);
 
        unlink(git_path("CHERRY_PICK_HEAD"));
        unlink(git_path("REVERT_HEAD"));
@@ -1778,7 +1826,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
 
        if (commit_index_files())
                die (_("Repository has been updated, but unable to write\n"
-                    "new_index file. Check that disk is not full or quota is\n"
+                    "new_index file. Check that disk is not full and quota is\n"
                     "not exceeded, and then \"git reset HEAD\" to recover."));
 
        rerere(0);
@@ -1796,5 +1844,6 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
        if (!quiet)
                print_summary(prefix, sha1, !current_head);
 
+       strbuf_release(&err);
        return 0;
 }
index 7bba5163834c87272a85ba324821beb1c9bca2c1..37305e93e937ade83072501df6b5d07033ee89d3 100644 (file)
@@ -445,6 +445,20 @@ static int get_urlmatch(const char *var, const char *url)
        return 0;
 }
 
+static char *default_user_config(void)
+{
+       struct strbuf buf = STRBUF_INIT;
+       strbuf_addf(&buf,
+                   _("# This is Git's per-user configuration file.\n"
+                     "[core]\n"
+                     "# Please adapt and uncomment the following lines:\n"
+                     "#        user = %s\n"
+                     "#        email = %s\n"),
+                   ident_default_name(),
+                   ident_default_email());
+       return strbuf_detach(&buf, NULL);
+}
+
 int cmd_config(int argc, const char **argv, const char *prefix)
 {
        int nongit = !startup_info->have_repository;
@@ -551,6 +565,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
                }
        }
        else if (actions == ACTION_EDIT) {
+               const char *config_file = given_config_source.file ?
+                       given_config_source.file : git_path("config");
                check_argc(argc, 0, 0);
                if (!given_config_source.file && nongit)
                        die("not in a git directory");
@@ -559,9 +575,18 @@ int cmd_config(int argc, const char **argv, const char *prefix)
                if (given_config_source.blob)
                        die("editing blobs is not supported");
                git_config(git_default_config, NULL);
-               launch_editor(given_config_source.file ?
-                             given_config_source.file : git_path("config"),
-                             NULL, NULL);
+               if (use_global_config) {
+                       int fd = open(config_file, O_CREAT | O_EXCL | O_WRONLY, 0666);
+                       if (fd) {
+                               char *content = default_user_config();
+                               write_str_in_full(fd, content);
+                               free(content);
+                               close(fd);
+                       }
+                       else if (errno != EEXIST)
+                               die_errno(_("cannot create configuration file %s"), config_file);
+               }
+               launch_editor(config_file, NULL, NULL);
        }
        else if (actions == ACTION_SET) {
                int ret;
index 92b4624a4b93ff50c661e44242d508aed31877eb..b8182c241dad4fd7221432cb5b40674f76789be4 100644 (file)
@@ -18,6 +18,7 @@
 #include "parse-options.h"
 #include "quote.h"
 #include "remote.h"
+#include "blob.h"
 
 static const char *fast_export_usage[] = {
        N_("git fast-export [rev-list-opts]"),
@@ -34,6 +35,7 @@ static int full_tree;
 static struct string_list extra_refs = STRING_LIST_INIT_NODUP;
 static struct refspec *refspecs;
 static int refspecs_nr;
+static int anonymize;
 
 static int parse_opt_signed_tag_mode(const struct option *opt,
                                     const char *arg, int unset)
@@ -81,6 +83,76 @@ static int has_unshown_parent(struct commit *commit)
        return 0;
 }
 
+struct anonymized_entry {
+       struct hashmap_entry hash;
+       const char *orig;
+       size_t orig_len;
+       const char *anon;
+       size_t anon_len;
+};
+
+static int anonymized_entry_cmp(const void *va, const void *vb,
+                               const void *data)
+{
+       const struct anonymized_entry *a = va, *b = vb;
+       return a->orig_len != b->orig_len ||
+               memcmp(a->orig, b->orig, a->orig_len);
+}
+
+/*
+ * Basically keep a cache of X->Y so that we can repeatedly replace
+ * the same anonymized string with another. The actual generation
+ * is farmed out to the generate function.
+ */
+static const void *anonymize_mem(struct hashmap *map,
+                                void *(*generate)(const void *, size_t *),
+                                const void *orig, size_t *len)
+{
+       struct anonymized_entry key, *ret;
+
+       if (!map->cmpfn)
+               hashmap_init(map, anonymized_entry_cmp, 0);
+
+       hashmap_entry_init(&key, memhash(orig, *len));
+       key.orig = orig;
+       key.orig_len = *len;
+       ret = hashmap_get(map, &key, NULL);
+
+       if (!ret) {
+               ret = xmalloc(sizeof(*ret));
+               hashmap_entry_init(&ret->hash, key.hash.hash);
+               ret->orig = xstrdup(orig);
+               ret->orig_len = *len;
+               ret->anon = generate(orig, len);
+               ret->anon_len = *len;
+               hashmap_put(map, ret);
+       }
+
+       *len = ret->anon_len;
+       return ret->anon;
+}
+
+/*
+ * We anonymize each component of a path individually,
+ * so that paths a/b and a/c will share a common root.
+ * The paths are cached via anonymize_mem so that repeated
+ * lookups for "a" will yield the same value.
+ */
+static void anonymize_path(struct strbuf *out, const char *path,
+                          struct hashmap *map,
+                          void *(*generate)(const void *, size_t *))
+{
+       while (*path) {
+               const char *end_of_component = strchrnul(path, '/');
+               size_t len = end_of_component - path;
+               const char *c = anonymize_mem(map, generate, path, &len);
+               strbuf_add(out, c, len);
+               path = end_of_component;
+               if (*path)
+                       strbuf_addch(out, *path++);
+       }
+}
+
 /* Since intptr_t is C99, we do not use it here */
 static inline uint32_t *mark_to_ptr(uint32_t mark)
 {
@@ -119,6 +191,26 @@ static void show_progress(void)
                printf("progress %d objects\n", counter);
 }
 
+/*
+ * Ideally we would want some transformation of the blob data here
+ * that is unreversible, but would still be the same size and have
+ * the same data relationship to other blobs (so that we get the same
+ * delta and packing behavior as the original). But the first and last
+ * requirements there are probably mutually exclusive, so let's take
+ * the easy way out for now, and just generate arbitrary content.
+ *
+ * There's no need to cache this result with anonymize_mem, since
+ * we already handle blob content caching with marks.
+ */
+static char *anonymize_blob(unsigned long *size)
+{
+       static int counter;
+       struct strbuf out = STRBUF_INIT;
+       strbuf_addf(&out, "anonymous blob %d", counter++);
+       *size = out.len;
+       return strbuf_detach(&out, NULL);
+}
+
 static void export_blob(const unsigned char *sha1)
 {
        unsigned long size;
@@ -137,12 +229,19 @@ static void export_blob(const unsigned char *sha1)
        if (object && object->flags & SHOWN)
                return;
 
-       buf = read_sha1_file(sha1, &type, &size);
-       if (!buf)
-               die ("Could not read blob %s", sha1_to_hex(sha1));
-       if (check_sha1_signature(sha1, buf, size, typename(type)) < 0)
-               die("sha1 mismatch in blob %s", sha1_to_hex(sha1));
-       object = parse_object_buffer(sha1, type, size, buf, &eaten);
+       if (anonymize) {
+               buf = anonymize_blob(&size);
+               object = (struct object *)lookup_blob(sha1);
+               eaten = 0;
+       } else {
+               buf = read_sha1_file(sha1, &type, &size);
+               if (!buf)
+                       die ("Could not read blob %s", sha1_to_hex(sha1));
+               if (check_sha1_signature(sha1, buf, size, typename(type)) < 0)
+                       die("sha1 mismatch in blob %s", sha1_to_hex(sha1));
+               object = parse_object_buffer(sha1, type, size, buf, &eaten);
+       }
+
        if (!object)
                die("Could not read blob %s", sha1_to_hex(sha1));
 
@@ -190,7 +289,7 @@ static int depth_first(const void *a_, const void *b_)
        return (a->status == 'R') - (b->status == 'R');
 }
 
-static void print_path(const char *path)
+static void print_path_1(const char *path)
 {
        int need_quote = quote_c_style(path, NULL, NULL, 0);
        if (need_quote)
@@ -201,6 +300,43 @@ static void print_path(const char *path)
                printf("%s", path);
 }
 
+static void *anonymize_path_component(const void *path, size_t *len)
+{
+       static int counter;
+       struct strbuf out = STRBUF_INIT;
+       strbuf_addf(&out, "path%d", counter++);
+       return strbuf_detach(&out, len);
+}
+
+static void print_path(const char *path)
+{
+       if (!anonymize)
+               print_path_1(path);
+       else {
+               static struct hashmap paths;
+               static struct strbuf anon = STRBUF_INIT;
+
+               anonymize_path(&anon, path, &paths, anonymize_path_component);
+               print_path_1(anon.buf);
+               strbuf_reset(&anon);
+       }
+}
+
+static void *generate_fake_sha1(const void *old, size_t *len)
+{
+       static uint32_t counter = 1; /* avoid null sha1 */
+       unsigned char *out = xcalloc(20, 1);
+       put_be32(out + 16, counter++);
+       return out;
+}
+
+static const unsigned char *anonymize_sha1(const unsigned char *sha1)
+{
+       static struct hashmap sha1s;
+       size_t len = 20;
+       return anonymize_mem(&sha1s, generate_fake_sha1, sha1, &len);
+}
+
 static void show_filemodify(struct diff_queue_struct *q,
                            struct diff_options *options, void *data)
 {
@@ -245,7 +381,9 @@ static void show_filemodify(struct diff_queue_struct *q,
                         */
                        if (no_data || S_ISGITLINK(spec->mode))
                                printf("M %06o %s ", spec->mode,
-                                      sha1_to_hex(spec->sha1));
+                                      sha1_to_hex(anonymize ?
+                                                  anonymize_sha1(spec->sha1) :
+                                                  spec->sha1));
                        else {
                                struct object *object = lookup_object(spec->sha1);
                                printf("M %06o :%d ", spec->mode,
@@ -279,6 +417,114 @@ static const char *find_encoding(const char *begin, const char *end)
        return bol;
 }
 
+static void *anonymize_ref_component(const void *old, size_t *len)
+{
+       static int counter;
+       struct strbuf out = STRBUF_INIT;
+       strbuf_addf(&out, "ref%d", counter++);
+       return strbuf_detach(&out, len);
+}
+
+static const char *anonymize_refname(const char *refname)
+{
+       /*
+        * If any of these prefixes is found, we will leave it intact
+        * so that tags remain tags and so forth.
+        */
+       static const char *prefixes[] = {
+               "refs/heads/",
+               "refs/tags/",
+               "refs/remotes/",
+               "refs/"
+       };
+       static struct hashmap refs;
+       static struct strbuf anon = STRBUF_INIT;
+       int i;
+
+       /*
+        * We also leave "master" as a special case, since it does not reveal
+        * anything interesting.
+        */
+       if (!strcmp(refname, "refs/heads/master"))
+               return refname;
+
+       strbuf_reset(&anon);
+       for (i = 0; i < ARRAY_SIZE(prefixes); i++) {
+               if (skip_prefix(refname, prefixes[i], &refname)) {
+                       strbuf_addstr(&anon, prefixes[i]);
+                       break;
+               }
+       }
+
+       anonymize_path(&anon, refname, &refs, anonymize_ref_component);
+       return anon.buf;
+}
+
+/*
+ * We do not even bother to cache commit messages, as they are unlikely
+ * to be repeated verbatim, and it is not that interesting when they are.
+ */
+static char *anonymize_commit_message(const char *old)
+{
+       static int counter;
+       return xstrfmt("subject %d\n\nbody\n", counter++);
+}
+
+static struct hashmap idents;
+static void *anonymize_ident(const void *old, size_t *len)
+{
+       static int counter;
+       struct strbuf out = STRBUF_INIT;
+       strbuf_addf(&out, "User %d <user%d@example.com>", counter, counter);
+       counter++;
+       return strbuf_detach(&out, len);
+}
+
+/*
+ * Our strategy here is to anonymize the names and email addresses,
+ * but keep timestamps intact, as they influence things like traversal
+ * order (and by themselves should not be too revealing).
+ */
+static void anonymize_ident_line(const char **beg, const char **end)
+{
+       static struct strbuf buffers[] = { STRBUF_INIT, STRBUF_INIT };
+       static unsigned which_buffer;
+
+       struct strbuf *out;
+       struct ident_split split;
+       const char *end_of_header;
+
+       out = &buffers[which_buffer++];
+       which_buffer %= ARRAY_SIZE(buffers);
+       strbuf_reset(out);
+
+       /* skip "committer", "author", "tagger", etc */
+       end_of_header = strchr(*beg, ' ');
+       if (!end_of_header)
+               die("BUG: malformed line fed to anonymize_ident_line: %.*s",
+                   (int)(*end - *beg), *beg);
+       end_of_header++;
+       strbuf_add(out, *beg, end_of_header - *beg);
+
+       if (!split_ident_line(&split, end_of_header, *end - end_of_header) &&
+           split.date_begin) {
+               const char *ident;
+               size_t len;
+
+               len = split.mail_end - split.name_begin;
+               ident = anonymize_mem(&idents, anonymize_ident,
+                                     split.name_begin, &len);
+               strbuf_add(out, ident, len);
+               strbuf_addch(out, ' ');
+               strbuf_add(out, split.date_begin, split.tz_end - split.date_begin);
+       } else {
+               strbuf_addstr(out, "Malformed Ident <malformed@example.com> 0 -0000");
+       }
+
+       *beg = out->buf;
+       *end = out->buf + out->len;
+}
+
 static void handle_commit(struct commit *commit, struct rev_info *rev)
 {
        int saved_output_format = rev->diffopt.output_format;
@@ -287,6 +533,7 @@ static void handle_commit(struct commit *commit, struct rev_info *rev)
        const char *encoding, *message;
        char *reencoded = NULL;
        struct commit_list *p;
+       const char *refname;
        int i;
 
        rev->diffopt.output_format = DIFF_FORMAT_CALLBACK;
@@ -326,13 +573,22 @@ static void handle_commit(struct commit *commit, struct rev_info *rev)
                if (!S_ISGITLINK(diff_queued_diff.queue[i]->two->mode))
                        export_blob(diff_queued_diff.queue[i]->two->sha1);
 
+       refname = commit->util;
+       if (anonymize) {
+               refname = anonymize_refname(refname);
+               anonymize_ident_line(&committer, &committer_end);
+               anonymize_ident_line(&author, &author_end);
+       }
+
        mark_next_object(&commit->object);
-       if (!is_encoding_utf8(encoding))
+       if (anonymize)
+               reencoded = anonymize_commit_message(message);
+       else if (!is_encoding_utf8(encoding))
                reencoded = reencode_string(message, "UTF-8", encoding);
        if (!commit->parents)
-               printf("reset %s\n", (const char*)commit->util);
+               printf("reset %s\n", refname);
        printf("commit %s\nmark :%"PRIu32"\n%.*s\n%.*s\ndata %u\n%s",
-              (const char *)commit->util, last_idnum,
+              refname, last_idnum,
               (int)(author_end - author), author,
               (int)(committer_end - committer), committer,
               (unsigned)(reencoded
@@ -363,6 +619,14 @@ static void handle_commit(struct commit *commit, struct rev_info *rev)
        show_progress();
 }
 
+static void *anonymize_tag(const void *old, size_t *len)
+{
+       static int counter;
+       struct strbuf out = STRBUF_INIT;
+       strbuf_addf(&out, "tag message %d", counter++);
+       return strbuf_detach(&out, len);
+}
+
 static void handle_tail(struct object_array *commits, struct rev_info *revs)
 {
        struct commit *commit;
@@ -419,6 +683,17 @@ static void handle_tag(const char *name, struct tag *tag)
        } else {
                tagger++;
                tagger_end = strchrnul(tagger, '\n');
+               if (anonymize)
+                       anonymize_ident_line(&tagger, &tagger_end);
+       }
+
+       if (anonymize) {
+               name = anonymize_refname(name);
+               if (message) {
+                       static struct hashmap tags;
+                       message = anonymize_mem(&tags, anonymize_tag,
+                                               message, &message_size);
+               }
        }
 
        /* handle signed tags */
@@ -584,6 +859,8 @@ static void handle_tags_and_duplicates(void)
                        handle_tag(name, (struct tag *)object);
                        break;
                case OBJ_COMMIT:
+                       if (anonymize)
+                               name = anonymize_refname(name);
                        /* create refs pointing to already seen commits */
                        commit = (struct commit *)object;
                        printf("reset %s\nfrom :%d\n\n", name,
@@ -719,6 +996,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
                OPT_BOOL(0, "no-data", &no_data, N_("Skip output of blob data")),
                OPT_STRING_LIST(0, "refspec", &refspecs_list, N_("refspec"),
                             N_("Apply refspec to exported refs")),
+               OPT_BOOL(0, "anonymize", &anonymize, N_("anonymize output")),
                OPT_END()
        };
 
index 47bd624696d5e94295dda8846f00dcbb80a6ca5a..fda0f047125f16f080288c1cda76b0e337784a54 100644 (file)
@@ -138,10 +138,8 @@ static int parse_atom(const char *atom, const char *ep)
        /* Add it in, including the deref prefix */
        at = used_atom_cnt;
        used_atom_cnt++;
-       used_atom = xrealloc(used_atom,
-                            (sizeof *used_atom) * used_atom_cnt);
-       used_atom_type = xrealloc(used_atom_type,
-                                 (sizeof(*used_atom_type) * used_atom_cnt));
+       REALLOC_ARRAY(used_atom, used_atom_cnt);
+       REALLOC_ARRAY(used_atom_type, used_atom_cnt);
        used_atom[at] = xmemdupz(atom, ep - atom);
        used_atom_type[at] = valid_atom[i].cmp_type;
        if (*atom == '*')
@@ -633,7 +631,7 @@ static void populate_value(struct refinfo *ref)
        unsigned long size;
        const unsigned char *tagged;
 
-       ref->value = xcalloc(sizeof(struct atom_value), used_atom_cnt);
+       ref->value = xcalloc(used_atom_cnt, sizeof(struct atom_value));
 
        if (need_symref && (ref->flag & REF_ISSYMREF) && !ref->symref) {
                unsigned char unused1[20];
@@ -870,8 +868,7 @@ static int grab_single_ref(const char *refname, const unsigned char *sha1, int f
        ref->flag = flag;
 
        cnt = cb->grab_cnt;
-       cb->grab_array = xrealloc(cb->grab_array,
-                                 sizeof(*cb->grab_array) * (cnt + 1));
+       REALLOC_ARRAY(cb->grab_array, cnt + 1);
        cb->grab_array[cnt++] = ref;
        cb->grab_cnt = cnt;
        return 0;
index 0928a98a71ca2b764d4fbb59976f1c4bdc421dde..e9ba576c1fe85cab505eb13fc20ae68dcfc19ff3 100644 (file)
@@ -298,7 +298,7 @@ static int fsck_obj(struct object *obj)
 
        if (fsck_walk(obj, mark_used, NULL))
                objerror(obj, "broken links");
-       if (fsck_object(obj, check_strict, fsck_error_func))
+       if (fsck_object(obj, NULL, 0, check_strict, fsck_error_func))
                return -1;
 
        if (obj->type == OBJ_TREE) {
index 8d219d8c42cb4dfb64468f9b4d82648bff646685..ced1456e1e3b71af05e382fcd505cc269391bb88 100644 (file)
@@ -55,44 +55,33 @@ static void remove_pidfile_on_signal(int signo)
        raise(signo);
 }
 
-static int gc_config(const char *var, const char *value, void *cb)
+static void gc_config(void)
 {
-       if (!strcmp(var, "gc.packrefs")) {
+       const char *value;
+
+       if (!git_config_get_value("gc.packrefs", &value)) {
                if (value && !strcmp(value, "notbare"))
                        pack_refs = -1;
                else
-                       pack_refs = git_config_bool(var, value);
-               return 0;
-       }
-       if (!strcmp(var, "gc.aggressivewindow")) {
-               aggressive_window = git_config_int(var, value);
-               return 0;
-       }
-       if (!strcmp(var, "gc.aggressivedepth")) {
-               aggressive_depth = git_config_int(var, value);
-               return 0;
-       }
-       if (!strcmp(var, "gc.auto")) {
-               gc_auto_threshold = git_config_int(var, value);
-               return 0;
-       }
-       if (!strcmp(var, "gc.autopacklimit")) {
-               gc_auto_pack_limit = git_config_int(var, value);
-               return 0;
+                       pack_refs = git_config_bool("gc.packrefs", value);
        }
-       if (!strcmp(var, "gc.autodetach")) {
-               detach_auto = git_config_bool(var, value);
-               return 0;
-       }
-       if (!strcmp(var, "gc.pruneexpire")) {
-               if (value && strcmp(value, "now")) {
+
+       git_config_get_int("gc.aggressivewindow", &aggressive_window);
+       git_config_get_int("gc.aggressivedepth", &aggressive_depth);
+       git_config_get_int("gc.auto", &gc_auto_threshold);
+       git_config_get_int("gc.autopacklimit", &gc_auto_pack_limit);
+       git_config_get_bool("gc.autodetach", &detach_auto);
+
+       if (!git_config_get_string_const("gc.pruneexpire", &prune_expire)) {
+               if (strcmp(prune_expire, "now")) {
                        unsigned long now = approxidate("now");
-                       if (approxidate(value) >= now)
-                               return error(_("Invalid %s: '%s'"), var, value);
+                       if (approxidate(prune_expire) >= now) {
+                               git_die_config("gc.pruneexpire", _("Invalid gc.pruneexpire: '%s'"),
+                                               prune_expire);
+                       }
                }
-               return git_config_string(&prune_expire, var, value);
        }
-       return git_default_config(var, value, cb);
+       git_config(git_default_config, NULL);
 }
 
 static int too_many_loose_objects(void)
@@ -301,7 +290,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
        argv_array_pushl(&prune, "prune", "--expire", NULL );
        argv_array_pushl(&rerere, "rerere", "gc", NULL);
 
-       git_config(gc_config, NULL);
+       gc_config();
 
        if (pack_refs < 0)
                pack_refs = !is_bare_repository();
index d7fcf4c13c7e0f0855fba51c6b58d2b06c99984e..61583633182da359556fc65795a8eb740167675c 100644 (file)
 #include "parse-options.h"
 #include "exec_cmd.h"
 
-static void hash_fd(int fd, const char *type, int write_object, const char *path)
+/*
+ * This is to create corrupt objects for debugging and as such it
+ * needs to bypass the data conversion performed by, and the type
+ * limitation imposed by, index_fd() and its callees.
+ */
+static int hash_literally(unsigned char *sha1, int fd, const char *type, unsigned flags)
+{
+       struct strbuf buf = STRBUF_INIT;
+       int ret;
+
+       if (strbuf_read(&buf, fd, 4096) < 0)
+               ret = -1;
+       else if (flags & HASH_WRITE_OBJECT)
+               ret = write_sha1_file(buf.buf, buf.len, type, sha1);
+       else
+               ret = hash_sha1_file(buf.buf, buf.len, type, sha1);
+       strbuf_release(&buf);
+       return ret;
+}
+
+static void hash_fd(int fd, const char *type, const char *path, unsigned flags,
+                   int literally)
 {
        struct stat st;
        unsigned char sha1[20];
-       unsigned flags = (HASH_FORMAT_CHECK |
-                         (write_object ? HASH_WRITE_OBJECT : 0));
 
        if (fstat(fd, &st) < 0 ||
-           index_fd(sha1, fd, &st, type_from_string(type), path, flags))
-               die(write_object
+           (literally
+            ? hash_literally(sha1, fd, type, flags)
+            : index_fd(sha1, fd, &st, type_from_string(type), path, flags)))
+               die((flags & HASH_WRITE_OBJECT)
                    ? "Unable to add %s to database"
                    : "Unable to hash %s", path);
        printf("%s\n", sha1_to_hex(sha1));
        maybe_flush_or_die(stdout, "hash to stdout");
 }
 
-static void hash_object(const char *path, const char *type, int write_object,
-                       const char *vpath)
+static void hash_object(const char *path, const char *type, const char *vpath,
+                       unsigned flags, int literally)
 {
        int fd;
        fd = open(path, O_RDONLY);
        if (fd < 0)
                die_errno("Cannot open '%s'", path);
-       hash_fd(fd, type, write_object, vpath);
+       hash_fd(fd, type, vpath, flags, literally);
 }
 
-static int no_filters;
-
-static void hash_stdin_paths(const char *type, int write_objects)
+static void hash_stdin_paths(const char *type, int no_filters, unsigned flags,
+                            int literally)
 {
        struct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT;
 
@@ -49,47 +69,46 @@ static void hash_stdin_paths(const char *type, int write_objects)
                                die("line is badly quoted");
                        strbuf_swap(&buf, &nbuf);
                }
-               hash_object(buf.buf, type, write_objects,
-                   no_filters ? NULL : buf.buf);
+               hash_object(buf.buf, type, no_filters ? NULL : buf.buf, flags,
+                           literally);
        }
        strbuf_release(&buf);
        strbuf_release(&nbuf);
 }
 
-static const char * const hash_object_usage[] = {
-       N_("git hash-object [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin] [--] <file>..."),
-       N_("git hash-object  --stdin-paths < <list-of-paths>"),
-       NULL
-};
-
-static const char *type;
-static int write_object;
-static int hashstdin;
-static int stdin_paths;
-static const char *vpath;
-
-static const struct option hash_object_options[] = {
-       OPT_STRING('t', NULL, &type, N_("type"), N_("object type")),
-       OPT_BOOL('w', NULL, &write_object, N_("write the object into the object database")),
-       OPT_COUNTUP( 0 , "stdin", &hashstdin, N_("read the object from stdin")),
-       OPT_BOOL( 0 , "stdin-paths", &stdin_paths, N_("read file names from stdin")),
-       OPT_BOOL( 0 , "no-filters", &no_filters, N_("store file as is without filters")),
-       OPT_STRING( 0 , "path", &vpath, N_("file"), N_("process file as it were from this path")),
-       OPT_END()
-};
-
 int cmd_hash_object(int argc, const char **argv, const char *prefix)
 {
+       static const char * const hash_object_usage[] = {
+               N_("git hash-object [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin] [--] <file>..."),
+               N_("git hash-object  --stdin-paths < <list-of-paths>"),
+               NULL
+       };
+       const char *type = blob_type;
+       int hashstdin = 0;
+       int stdin_paths = 0;
+       int no_filters = 0;
+       int literally = 0;
+       unsigned flags = HASH_FORMAT_CHECK;
+       const char *vpath = NULL;
+       const struct option hash_object_options[] = {
+               OPT_STRING('t', NULL, &type, N_("type"), N_("object type")),
+               OPT_BIT('w', NULL, &flags, N_("write the object into the object database"),
+                       HASH_WRITE_OBJECT),
+               OPT_COUNTUP( 0 , "stdin", &hashstdin, N_("read the object from stdin")),
+               OPT_BOOL( 0 , "stdin-paths", &stdin_paths, N_("read file names from stdin")),
+               OPT_BOOL( 0 , "no-filters", &no_filters, N_("store file as is without filters")),
+               OPT_BOOL( 0, "literally", &literally, N_("just hash any random garbage to create corrupt objects for debugging Git")),
+               OPT_STRING( 0 , "path", &vpath, N_("file"), N_("process file as it were from this path")),
+               OPT_END()
+       };
        int i;
        int prefix_length = -1;
        const char *errstr = NULL;
 
-       type = blob_type;
-
        argc = parse_options(argc, argv, NULL, hash_object_options,
                             hash_object_usage, 0);
 
-       if (write_object) {
+       if (flags & HASH_WRITE_OBJECT) {
                prefix = setup_git_directory();
                prefix_length = prefix ? strlen(prefix) : 0;
                if (vpath && prefix)
@@ -119,19 +138,19 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix)
        }
 
        if (hashstdin)
-               hash_fd(0, type, write_object, vpath);
+               hash_fd(0, type, vpath, flags, literally);
 
        for (i = 0 ; i < argc; i++) {
                const char *arg = argv[i];
 
                if (0 <= prefix_length)
                        arg = prefix_filename(prefix, prefix_length, arg);
-               hash_object(arg, type, write_object,
-                           no_filters ? NULL : vpath ? vpath : arg);
+               hash_object(arg, type, no_filters ? NULL : vpath ? vpath : arg,
+                           flags, literally);
        }
 
        if (stdin_paths)
-               hash_stdin_paths(type, write_object);
+               hash_stdin_paths(type, no_filters, flags, literally);
 
        return 0;
 }
index 1fdefeb6867cdd37beaf41c5fa9e113576b19f17..8343b4027d458d77a720f79d64c9a4c116208f84 100644 (file)
@@ -79,12 +79,11 @@ static const char *get_man_viewer_info(const char *name)
 static int check_emacsclient_version(void)
 {
        struct strbuf buffer = STRBUF_INIT;
-       struct child_process ec_process;
+       struct child_process ec_process = CHILD_PROCESS_INIT;
        const char *argv_ec[] = { "emacsclient", "--version", NULL };
        int version;
 
        /* emacsclient prints its version number on stderr */
-       memset(&ec_process, 0, sizeof(ec_process));
        ec_process.argv = argv_ec;
        ec_process.err = -1;
        ec_process.stdout_to_stderr = 1;
index eebf1a8fc21fd551f3917ad23ab5a45dff302f23..792c66ca5932638e11f2587f928a6b98c08e7854 100644 (file)
@@ -779,7 +779,8 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
                        if (!obj)
                                die(_("invalid %s"), typename(type));
                        if (do_fsck_object &&
-                           fsck_object(obj, 1, fsck_error_function))
+                           fsck_object(obj, buf, size, 1,
+                                   fsck_error_function))
                                die(_("Error in object"));
                        if (fsck_walk(obj, mark_link, NULL))
                                die(_("Not all child objects of %s are reachable"), sha1_to_hex(obj->sha1));
@@ -1169,9 +1170,7 @@ static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned cha
                int nr_objects_initial = nr_objects;
                if (nr_unresolved <= 0)
                        die(_("confusion beyond insanity"));
-               objects = xrealloc(objects,
-                                  (nr_objects + nr_unresolved + 1)
-                                  * sizeof(*objects));
+               REALLOC_ARRAY(objects, nr_objects + nr_unresolved + 1);
                memset(objects + nr_objects + 1, 0,
                       nr_unresolved * sizeof(*objects));
                f = sha1fd(output_fd, curr_pack);
index 56f85e239ae0d2607c38e3c46013007ba9e71b12..587a5055ed677c3541c85101d944ffb0a19b1962 100644 (file)
@@ -330,12 +330,12 @@ int set_git_dir_init(const char *git_dir, const char *real_git_dir,
                 * moving the target repo later on in separate_git_dir()
                 */
                git_link = xstrdup(real_path(git_dir));
+               set_git_dir(real_path(real_git_dir));
        }
        else {
-               real_git_dir = real_path(git_dir);
+               set_git_dir(real_path(git_dir));
                git_link = NULL;
        }
-       set_git_dir(real_path(real_git_dir));
        return 0;
 }
 
@@ -426,8 +426,9 @@ int init_db(const char *template_dir, unsigned int flags)
 
 static int guess_repository_type(const char *git_dir)
 {
-       char cwd[PATH_MAX];
        const char *slash;
+       char *cwd;
+       int cwd_is_git_dir;
 
        /*
         * "GIT_DIR=. git init" is always bare.
@@ -435,9 +436,10 @@ static int guess_repository_type(const char *git_dir)
         */
        if (!strcmp(".", git_dir))
                return 1;
-       if (!getcwd(cwd, sizeof(cwd)))
-               die_errno(_("cannot tell cwd"));
-       if (!strcmp(git_dir, cwd))
+       cwd = xgetcwd();
+       cwd_is_git_dir = !strcmp(git_dir, cwd);
+       free(cwd);
+       if (cwd_is_git_dir)
                return 1;
        /*
         * "GIT_DIR=.git or GIT_DIR=something/.git is usually not.
@@ -535,10 +537,9 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
                usage(init_db_usage[0]);
        }
        if (is_bare_repository_cfg == 1) {
-               static char git_dir[PATH_MAX+1];
-
-               setenv(GIT_DIR_ENVIRONMENT,
-                       getcwd(git_dir, sizeof(git_dir)), argc > 0);
+               char *cwd = xgetcwd();
+               setenv(GIT_DIR_ENVIRONMENT, cwd, argc > 0);
+               free(cwd);
        }
 
        if (init_shared_repository != -1)
@@ -572,13 +573,10 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
                        git_work_tree_cfg = xstrdup(real_path(rel));
                        free(rel);
                }
-               if (!git_work_tree_cfg) {
-                       git_work_tree_cfg = xcalloc(PATH_MAX, 1);
-                       if (!getcwd(git_work_tree_cfg, PATH_MAX))
-                               die_errno (_("Cannot access current working directory"));
-               }
+               if (!git_work_tree_cfg)
+                       git_work_tree_cfg = xgetcwd();
                if (work_tree)
-                       set_git_work_tree(real_path(work_tree));
+                       set_git_work_tree(work_tree);
                else
                        set_git_work_tree(git_work_tree_cfg);
                if (access(get_git_work_tree(), X_OK))
@@ -587,7 +585,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
        }
        else {
                if (work_tree)
-                       set_git_work_tree(real_path(work_tree));
+                       set_git_work_tree(work_tree);
        }
 
        set_git_dir_init(git_dir, real_git_dir, 1);
index 4389722b4b1edffce8cd2a63dae52277e022ac99..2fb34c7de96a4236327d46bf1392d54fa882c17f 100644 (file)
@@ -78,7 +78,7 @@ static int decorate_callback(const struct option *opt, const char *arg, int unse
                decoration_style = DECORATE_SHORT_REFS;
 
        if (decoration_style < 0)
-               die("invalid --decorate option: %s", arg);
+               die(_("invalid --decorate option: %s"), arg);
 
        decoration_given = 1;
 
@@ -130,7 +130,7 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
                { OPTION_CALLBACK, 0, "decorate", NULL, NULL, N_("decorate options"),
                  PARSE_OPT_OPTARG, decorate_callback},
                OPT_CALLBACK('L', NULL, &line_cb, "n,m:file",
-                            "Process line range n,m in file, counting from 1",
+                            N_("Process line range n,m in file, counting from 1"),
                             log_line_range_callback),
                OPT_END()
        };
@@ -150,7 +150,7 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
 
        /* Any arguments at this point are not recognized */
        if (argc > 1)
-               die("unrecognized argument: %s", argv[1]);
+               die(_("unrecognized argument: %s"), argv[1]);
 
        memset(&w, 0, sizeof(w));
        userformat_find_requirements(NULL, &w);
@@ -447,13 +447,13 @@ static int show_blob_object(const unsigned char *sha1, struct rev_info *rev, con
                return stream_blob_to_fd(1, sha1, NULL, 0);
 
        if (get_sha1_with_context(obj_name, 0, sha1c, &obj_context))
-               die("Not a valid object name %s", obj_name);
+               die(_("Not a valid object name %s"), obj_name);
        if (!obj_context.path[0] ||
            !textconv_object(obj_context.path, obj_context.mode, sha1c, 1, &buf, &size))
                return stream_blob_to_fd(1, sha1, NULL, 0);
 
        if (!buf)
-               die("git show %s: bad file", obj_name);
+               die(_("git show %s: bad file"), obj_name);
 
        write_or_die(1, buf, size);
        return 0;
@@ -864,6 +864,7 @@ static void add_branch_description(struct strbuf *buf, const char *branch_name)
                strbuf_addbuf(buf, &desc);
                strbuf_addch(buf, '\n');
        }
+       strbuf_release(&desc);
 }
 
 static char *find_branch_name(struct rev_info *rev)
@@ -1439,7 +1440,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                        continue;
 
                nr++;
-               list = xrealloc(list, nr * sizeof(list[0]));
+               REALLOC_ARRAY(list, nr);
                list[nr - 1] = commit;
        }
        if (nr == 0)
index 47c38808a26a4602f8bd2c7d87f67770a625c679..99cee20fb07ce7ed03da230bfa031c277f584fc1 100644 (file)
@@ -474,7 +474,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
                OPT_BOOL('k', "killed", &show_killed,
                        N_("show files on the filesystem that need to be removed")),
                OPT_BIT(0, "directory", &dir.flags,
-                       N_("show 'other' directories' name only"),
+                       N_("show 'other' directories' names only"),
                        DIR_SHOW_OTHER_DIRECTORIES),
                OPT_NEGBIT(0, "empty-directory", &dir.flags,
                        N_("don't show empty directories"),
index cf11c8d6071dd791508d3bd5f46d30550765a90f..6a14d2985d12394d343cb91290111d6a8c0a5d06 100644 (file)
@@ -288,6 +288,22 @@ static inline int cmp_header(const struct strbuf *line, const char *hdr)
                        line->buf[len] == ':' && isspace(line->buf[len + 1]);
 }
 
+static int is_format_patch_separator(const char *line, int len)
+{
+       static const char SAMPLE[] =
+               "From e6807f3efca28b30decfecb1732a56c7db1137ee Mon Sep 17 00:00:00 2001\n";
+       const char *cp;
+
+       if (len != strlen(SAMPLE))
+               return 0;
+       if (!skip_prefix(line, "From ", &cp))
+               return 0;
+       if (strspn(cp, "0123456789abcdef") != 40)
+               return 0;
+       cp += 40;
+       return !memcmp(SAMPLE + (cp - line), cp, strlen(SAMPLE) - (cp - line));
+}
+
 static int check_header(const struct strbuf *line,
                                struct strbuf *hdr_data[], int overwrite)
 {
@@ -329,7 +345,7 @@ static int check_header(const struct strbuf *line,
 
        /* for inbody stuff */
        if (starts_with(line->buf, ">From") && isspace(line->buf[5])) {
-               ret = 1; /* Should this return 0? */
+               ret = is_format_patch_separator(line->buf + 1, line->len - 1);
                goto check_header_out;
        }
        if (starts_with(line->buf, "[PATCH]") && isspace(line->buf[7])) {
index 06296d4bdf607431bfcb38f0bc6720f555d6917a..763cda098cf1e2ac2ccbae45d3602f8bb1093be0 100644 (file)
@@ -53,14 +53,16 @@ static int keep_cr;
  */
 static int split_one(FILE *mbox, const char *name, int allow_bare)
 {
-       FILE *output = NULL;
+       FILE *output;
        int fd;
        int status = 0;
        int is_bare = !is_from_line(buf.buf, buf.len);
 
-       if (is_bare && !allow_bare)
-               goto corrupt;
-
+       if (is_bare && !allow_bare) {
+               unlink(name);
+               fprintf(stderr, "corrupt mailbox\n");
+               exit(1);
+       }
        fd = open(name, O_WRONLY | O_CREAT | O_EXCL, 0666);
        if (fd < 0)
                die_errno("cannot open output file '%s'", name);
@@ -91,13 +93,6 @@ static int split_one(FILE *mbox, const char *name, int allow_bare)
        }
        fclose(output);
        return status;
-
- corrupt:
-       if (output)
-               fclose(output);
-       unlink(name);
-       fprintf(stderr, "corrupt mailbox\n");
-       exit(1);
 }
 
 static int populate_maildir_list(struct string_list *list, const char *path)
index 61cbde4094bf27ea9dfaba158233ba7f4613f2ee..f9ab48597e58ed97fc208b58c17b8becb105e095 100644 (file)
@@ -25,7 +25,7 @@ static void add_merge_entry(struct merge_list *entry)
        merge_result_end = &entry->next;
 }
 
-static void merge_trees_recursive(struct tree_desc t[3], const char *base, int df_conflict);
+static void merge_trees(struct tree_desc t[3], const char *base);
 
 static const char *explanation(struct merge_list *entry)
 {
@@ -195,8 +195,8 @@ static void resolve(const struct traverse_info *info, struct name_entry *ours, s
        add_merge_entry(final);
 }
 
-static void unresolved_directory(const struct traverse_info *info, struct name_entry n[3],
-                                int df_conflict)
+static void unresolved_directory(const struct traverse_info *info,
+                                struct name_entry n[3])
 {
        char *newbase;
        struct name_entry *p;
@@ -218,7 +218,7 @@ static void unresolved_directory(const struct traverse_info *info, struct name_e
        buf2 = fill_tree_descriptor(t+2, ENTRY_SHA1(n + 2));
 #undef ENTRY_SHA1
 
-       merge_trees_recursive(t, newbase, df_conflict);
+       merge_trees(t, newbase);
 
        free(buf0);
        free(buf1);
@@ -259,7 +259,7 @@ static void unresolved(const struct traverse_info *info, struct name_entry n[3])
                        dirmask |= (1 << i);
        }
 
-       unresolved_directory(info, n, dirmask && (dirmask != mask));
+       unresolved_directory(info, n);
 
        if (dirmask == mask)
                return;
@@ -335,21 +335,15 @@ static int threeway_callback(int n, unsigned long mask, unsigned long dirmask, s
        return mask;
 }
 
-static void merge_trees_recursive(struct tree_desc t[3], const char *base, int df_conflict)
+static void merge_trees(struct tree_desc t[3], const char *base)
 {
        struct traverse_info info;
 
        setup_traverse_info(&info, base);
-       info.data = &df_conflict;
        info.fn = threeway_callback;
        traverse_trees(3, t, &info);
 }
 
-static void merge_trees(struct tree_desc t[3], const char *base)
-{
-       merge_trees_recursive(t, base, 0);
-}
-
 static void *get_tree_descriptor(struct tree_desc *desc, const char *rev)
 {
        unsigned char sha1[20];
index ce82eb297db3d03394f4e73a9b07574661db7090..dff043dac33ea88a8c5a05ea5ac3da71ca00c0d3 100644 (file)
@@ -237,11 +237,10 @@ static void drop_save(void)
 static int save_state(unsigned char *stash)
 {
        int len;
-       struct child_process cp;
+       struct child_process cp = CHILD_PROCESS_INIT;
        struct strbuf buffer = STRBUF_INIT;
        const char *argv[] = {"stash", "create", NULL};
 
-       memset(&cp, 0, sizeof(cp));
        cp.argv = argv;
        cp.out = -1;
        cp.git_cmd = 1;
@@ -557,7 +556,7 @@ static void parse_branch_merge_options(char *bmo)
        if (argc < 0)
                die(_("Bad branch.%s.mergeoptions string: %s"), branch,
                    split_cmdline_strerror(argc));
-       argv = xrealloc(argv, sizeof(*argv) * (argc + 2));
+       REALLOC_ARRAY(argv, argc + 2);
        memmove(argv + 1, argv, sizeof(*argv) * (argc + 1));
        argc++;
        argv[0] = "branch.*.mergeoptions";
@@ -1144,14 +1143,14 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                 */
                if (advice_resolve_conflict)
                        die(_("You have not concluded your merge (MERGE_HEAD exists).\n"
-                                 "Please, commit your changes before you can merge."));
+                                 "Please, commit your changes before you merge."));
                else
                        die(_("You have not concluded your merge (MERGE_HEAD exists)."));
        }
        if (file_exists(git_path("CHERRY_PICK_HEAD"))) {
                if (advice_resolve_conflict)
                        die(_("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
-                           "Please, commit your changes before you can merge."));
+                           "Please, commit your changes before you merge."));
                else
                        die(_("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."));
        }
index 6ffe540c202f69a41fcf40d443f73073d3ba08bd..8883baa903e92093cabcc3dbaac7ccec3eecd64a 100644 (file)
@@ -61,6 +61,46 @@ static const char *add_slash(const char *path)
 static struct lock_file lock_file;
 #define SUBMODULE_WITH_GITDIR ((const char *)1)
 
+static void prepare_move_submodule(const char *src, int first,
+                                  const char **submodule_gitfile)
+{
+       struct strbuf submodule_dotgit = STRBUF_INIT;
+       if (!S_ISGITLINK(active_cache[first]->ce_mode))
+               die(_("Directory %s is in index and no submodule?"), src);
+       if (!is_staging_gitmodules_ok())
+               die(_("Please stage your changes to .gitmodules or stash them to proceed"));
+       strbuf_addf(&submodule_dotgit, "%s/.git", src);
+       *submodule_gitfile = read_gitfile(submodule_dotgit.buf);
+       if (*submodule_gitfile)
+               *submodule_gitfile = xstrdup(*submodule_gitfile);
+       else
+               *submodule_gitfile = SUBMODULE_WITH_GITDIR;
+       strbuf_release(&submodule_dotgit);
+}
+
+static int index_range_of_same_dir(const char *src, int length,
+                                  int *first_p, int *last_p)
+{
+       const char *src_w_slash = add_slash(src);
+       int first, last, len_w_slash = length + 1;
+
+       first = cache_name_pos(src_w_slash, len_w_slash);
+       if (first >= 0)
+               die(_("%.*s is in index"), len_w_slash, src_w_slash);
+
+       first = -1 - first;
+       for (last = first; last < active_nr; last++) {
+               const char *path = active_cache[last]->name;
+               if (strncmp(path, src_w_slash, len_w_slash))
+                       break;
+       }
+       if (src_w_slash != src)
+               free((char *)src_w_slash);
+       *first_p = first;
+       *last_p = last;
+       return last - first;
+}
+
 int cmd_mv(int argc, const char **argv, const char *prefix)
 {
        int i, gitmodules_modified = 0;
@@ -108,7 +148,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
                destination = internal_copy_pathspec(dest_path[0], argv, argc, DUP_BASENAME);
        } else {
                if (argc != 1)
-                       die("destination '%s' is not a directory", dest_path[0]);
+                       die(_("destination '%s' is not a directory"), dest_path[0]);
                destination = dest_path;
        }
 
@@ -131,75 +171,36 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
                                && lstat(dst, &st) == 0)
                        bad = _("cannot move directory over file");
                else if (src_is_dir) {
-                       int first = cache_name_pos(src, length);
-                       if (first >= 0) {
-                               struct strbuf submodule_dotgit = STRBUF_INIT;
-                               if (!S_ISGITLINK(active_cache[first]->ce_mode))
-                                       die (_("Huh? Directory %s is in index and no submodule?"), src);
-                               if (!is_staging_gitmodules_ok())
-                                       die (_("Please, stage your changes to .gitmodules or stash them to proceed"));
-                               strbuf_addf(&submodule_dotgit, "%s/.git", src);
-                               submodule_gitfile[i] = read_gitfile(submodule_dotgit.buf);
-                               if (submodule_gitfile[i])
-                                       submodule_gitfile[i] = xstrdup(submodule_gitfile[i]);
-                               else
-                                       submodule_gitfile[i] = SUBMODULE_WITH_GITDIR;
-                               strbuf_release(&submodule_dotgit);
-                       } else {
-                               const char *src_w_slash = add_slash(src);
-                               int last, len_w_slash = length + 1;
+                       int first = cache_name_pos(src, length), last;
 
-                               modes[i] = WORKING_DIRECTORY;
+                       if (first >= 0)
+                               prepare_move_submodule(src, first,
+                                                      submodule_gitfile + i);
+                       else if (index_range_of_same_dir(src, length,
+                                                        &first, &last) < 1)
+                               bad = _("source directory is empty");
+                       else { /* last - first >= 1 */
+                               int j, dst_len, n;
 
-                               first = cache_name_pos(src_w_slash, len_w_slash);
-                               if (first >= 0)
-                                       die (_("Huh? %.*s is in index?"),
-                                                       len_w_slash, src_w_slash);
-
-                               first = -1 - first;
-                               for (last = first; last < active_nr; last++) {
-                                       const char *path = active_cache[last]->name;
-                                       if (strncmp(path, src_w_slash, len_w_slash))
-                                               break;
-                               }
-                               if (src_w_slash != src)
-                                       free((char *)src_w_slash);
-
-                               if (last - first < 1)
-                                       bad = _("source directory is empty");
-                               else {
-                                       int j, dst_len;
-
-                                       if (last - first > 0) {
-                                               source = xrealloc(source,
-                                                               (argc + last - first)
-                                                               * sizeof(char *));
-                                               destination = xrealloc(destination,
-                                                               (argc + last - first)
-                                                               * sizeof(char *));
-                                               modes = xrealloc(modes,
-                                                               (argc + last - first)
-                                                               * sizeof(enum update_mode));
-                                               submodule_gitfile = xrealloc(submodule_gitfile,
-                                                               (argc + last - first)
-                                                               * sizeof(char *));
-                                       }
+                               modes[i] = WORKING_DIRECTORY;
+                               n = argc + last - first;
+                               REALLOC_ARRAY(source, n);
+                               REALLOC_ARRAY(destination, n);
+                               REALLOC_ARRAY(modes, n);
+                               REALLOC_ARRAY(submodule_gitfile, n);
 
-                                       dst = add_slash(dst);
-                                       dst_len = strlen(dst);
+                               dst = add_slash(dst);
+                               dst_len = strlen(dst);
 
-                                       for (j = 0; j < last - first; j++) {
-                                               const char *path =
-                                                       active_cache[first + j]->name;
-                                               source[argc + j] = path;
-                                               destination[argc + j] =
-                                                       prefix_path(dst, dst_len,
-                                                               path + length + 1);
-                                               modes[argc + j] = INDEX;
-                                               submodule_gitfile[argc + j] = NULL;
-                                       }
-                                       argc += last - first;
+                               for (j = 0; j < last - first; j++) {
+                                       const char *path = active_cache[first + j]->name;
+                                       source[argc + j] = path;
+                                       destination[argc + j] =
+                                               prefix_path(dst, dst_len, path + length + 1);
+                                       modes[argc + j] = INDEX;
+                                       submodule_gitfile[argc + j] = NULL;
                                }
+                               argc += last - first;
                        }
                } else if (cache_name_pos(src, length) < 0)
                        bad = _("not under version control");
@@ -225,24 +226,22 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
                else
                        string_list_insert(&src_for_dst, dst);
 
-               if (bad) {
-                       if (ignore_errors) {
-                               if (--argc > 0) {
-                                       memmove(source + i, source + i + 1,
-                                               (argc - i) * sizeof(char *));
-                                       memmove(destination + i,
-                                               destination + i + 1,
-                                               (argc - i) * sizeof(char *));
-                                       memmove(modes + i, modes + i + 1,
-                                               (argc - i) * sizeof(enum update_mode));
-                                       memmove(submodule_gitfile + i,
-                                               submodule_gitfile + i + 1,
-                                               (argc - i) * sizeof(char *));
-                                       i--;
-                               }
-                       } else
-                               die (_("%s, source=%s, destination=%s"),
-                                    bad, src, dst);
+               if (!bad)
+                       continue;
+               if (!ignore_errors)
+                       die(_("%s, source=%s, destination=%s"),
+                            bad, src, dst);
+               if (--argc > 0) {
+                       int n = argc - i;
+                       memmove(source + i, source + i + 1,
+                               n * sizeof(char *));
+                       memmove(destination + i, destination + i + 1,
+                               n * sizeof(char *));
+                       memmove(modes + i, modes + i + 1,
+                               n * sizeof(enum update_mode));
+                       memmove(submodule_gitfile + i, submodule_gitfile + i + 1,
+                               n * sizeof(char *));
+                       i--;
                }
        }
 
@@ -254,7 +253,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
                        printf(_("Renaming %s to %s\n"), src, dst);
                if (!show_only && mode != INDEX) {
                        if (rename(src, dst) < 0 && !ignore_errors)
-                               die_errno (_("renaming '%s' failed"), src);
+                               die_errno(_("renaming '%s' failed"), src);
                        if (submodule_gitfile[i]) {
                                if (submodule_gitfile[i] != SUBMODULE_WITH_GITDIR)
                                        connect_work_tree_and_git_dir(dst, submodule_gitfile[i]);
@@ -275,10 +274,9 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
        if (gitmodules_modified)
                stage_updated_gitmodules();
 
-       if (active_cache_changed) {
-               if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
-                       die(_("Unable to write new index file"));
-       }
+       if (active_cache_changed &&
+           write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
+               die(_("Unable to write new index file"));
 
        return 0;
 }
index 820c34135cab439e2168dd08947bd79d7ed7ae71..67d0bb14f8f18003d6a073b0c264f5b46ca12685 100644 (file)
@@ -122,12 +122,11 @@ static void write_commented_object(int fd, const unsigned char *object)
 {
        const char *show_args[5] =
                {"show", "--stat", "--no-notes", sha1_to_hex(object), NULL};
-       struct child_process show;
+       struct child_process show = CHILD_PROCESS_INIT;
        struct strbuf buf = STRBUF_INIT;
        struct strbuf cbuf = STRBUF_INIT;
 
        /* Invoke "git show --stat --no-notes $object" */
-       memset(&show, 0, sizeof(show));
        show.argv = show_args;
        show.no_stdin = 1;
        show.out = -1;
@@ -211,7 +210,7 @@ static void create_note(const unsigned char *object, struct msg_arg *msg,
                if (write_sha1_file(msg->buf.buf, msg->buf.len, blob_type, result)) {
                        error(_("unable to write note object"));
                        if (path)
-                               error(_("The note contents has been left in %s"),
+                               error(_("The note contents have been left in %s"),
                                      path);
                        exit(128);
                }
index b59f5d895e38bdb96d19b5fc5061669facdf22cc..d39193453a6bf868f8b62dac18201b0b4b7bccbd 100644 (file)
@@ -89,8 +89,7 @@ static void index_commit_for_bitmap(struct commit *commit)
 {
        if (indexed_commits_nr >= indexed_commits_alloc) {
                indexed_commits_alloc = (indexed_commits_alloc + 32) * 2;
-               indexed_commits = xrealloc(indexed_commits,
-                       indexed_commits_alloc * sizeof(struct commit *));
+               REALLOC_ARRAY(indexed_commits, indexed_commits_alloc);
        }
 
        indexed_commits[indexed_commits_nr++] = commit;
index 6879468c46a7baca69e5e28b0c6e38ff7099a6ff..d430731d701d7a06e1da0d8273c03453b85dcf96 100644 (file)
@@ -68,6 +68,7 @@ void prune_packed_objects(int opts)
                rmdir(pathname.buf);
        }
        stop_progress(&progress);
+       strbuf_release(&pathname);
 }
 
 int cmd_prune_packed(int argc, const char **argv, const char *prefix)
index f93ac454b4133f5c1e7cb1675a618b4c0b3174cd..daf0600ca30eb3969e0583cc1096e6f33291d4aa 100644 (file)
@@ -15,6 +15,7 @@
 #include "connected.h"
 #include "argv-array.h"
 #include "version.h"
+#include "sigchain.h"
 
 static const char receive_pack_usage[] = "git receive-pack <git-dir>";
 
@@ -255,7 +256,7 @@ static int copy_to_sideband(int in, int out, void *arg)
 typedef int (*feed_fn)(void *, const char **, size_t *);
 static int run_and_feed_hook(const char *hook_name, feed_fn feed, void *feed_state)
 {
-       struct child_process proc;
+       struct child_process proc = CHILD_PROCESS_INIT;
        struct async muxer;
        const char *argv[2];
        int code;
@@ -266,7 +267,6 @@ static int run_and_feed_hook(const char *hook_name, feed_fn feed, void *feed_sta
 
        argv[1] = NULL;
 
-       memset(&proc, 0, sizeof(proc));
        proc.argv = argv;
        proc.in = -1;
        proc.stdout_to_stderr = 1;
@@ -288,6 +288,8 @@ static int run_and_feed_hook(const char *hook_name, feed_fn feed, void *feed_sta
                return code;
        }
 
+       sigchain_push(SIGPIPE, SIG_IGN);
+
        while (1) {
                const char *buf;
                size_t n;
@@ -299,6 +301,9 @@ static int run_and_feed_hook(const char *hook_name, feed_fn feed, void *feed_sta
        close(proc.in);
        if (use_sideband)
                finish_async(&muxer);
+
+       sigchain_pop(SIGPIPE);
+
        return finish_command(&proc);
 }
 
@@ -350,7 +355,7 @@ static int run_receive_hook(struct command *commands, const char *hook_name,
 static int run_update_hook(struct command *cmd)
 {
        const char *argv[5];
-       struct child_process proc;
+       struct child_process proc = CHILD_PROCESS_INIT;
        int code;
 
        argv[0] = find_hook("update");
@@ -362,7 +367,6 @@ static int run_update_hook(struct command *cmd)
        argv[3] = sha1_to_hex(cmd->new_sha1);
        argv[4] = NULL;
 
-       memset(&proc, 0, sizeof(proc));
        proc.no_stdin = 1;
        proc.stdout_to_stderr = 1;
        proc.err = use_sideband ? -1 : 0;
@@ -475,7 +479,6 @@ static const char *update(struct command *cmd, struct shallow_info *si)
        const char *namespaced_name;
        unsigned char *old_sha1 = cmd->old_sha1;
        unsigned char *new_sha1 = cmd->new_sha1;
-       struct ref_lock *lock;
 
        /* only refs/... are allowed */
        if (!starts_with(name, "refs/") || check_refname_format(name + 5, 0)) {
@@ -576,19 +579,27 @@ static const char *update(struct command *cmd, struct shallow_info *si)
                return NULL; /* good */
        }
        else {
+               struct strbuf err = STRBUF_INIT;
+               struct ref_transaction *transaction;
+
                if (shallow_update && si->shallow_ref[cmd->index] &&
                    update_shallow_ref(cmd, si))
                        return "shallow error";
 
-               lock = lock_any_ref_for_update(namespaced_name, old_sha1,
-                                              0, NULL);
-               if (!lock) {
-                       rp_error("failed to lock %s", name);
-                       return "failed to lock";
-               }
-               if (write_ref_sha1(lock, new_sha1, "push")) {
-                       return "failed to write"; /* error() already called */
+               transaction = ref_transaction_begin(&err);
+               if (!transaction ||
+                   ref_transaction_update(transaction, namespaced_name,
+                                          new_sha1, old_sha1, 0, 1, &err) ||
+                   ref_transaction_commit(transaction, "push", &err)) {
+                       ref_transaction_free(transaction);
+
+                       rp_error("%s", err.buf);
+                       strbuf_release(&err);
+                       return "failed to update ref";
                }
+
+               ref_transaction_free(transaction);
+               strbuf_release(&err);
                return NULL; /* good */
        }
 }
@@ -598,7 +609,7 @@ static void run_update_post_hook(struct command *commands)
        struct command *cmd;
        int argc;
        const char **argv;
-       struct child_process proc;
+       struct child_process proc = CHILD_PROCESS_INIT;
        char *hook;
 
        hook = find_hook("post-update");
@@ -621,7 +632,6 @@ static void run_update_post_hook(struct command *commands)
        }
        argv[argc] = NULL;
 
-       memset(&proc, 0, sizeof(proc));
        proc.no_stdin = 1;
        proc.stdout_to_stderr = 1;
        proc.err = use_sideband ? -1 : 0;
@@ -911,7 +921,7 @@ static const char *unpack(int err_fd, struct shallow_info *si)
        const char *hdr_err;
        int status;
        char hdr_arg[38];
-       struct child_process child;
+       struct child_process child = CHILD_PROCESS_INIT;
        int fsck_objects = (receive_fsck_objects >= 0
                            ? receive_fsck_objects
                            : transfer_fsck_objects >= 0
@@ -933,7 +943,6 @@ static const char *unpack(int err_fd, struct shallow_info *si)
                argv_array_pushl(&av, "--shallow-file", alt_shallow_file, NULL);
        }
 
-       memset(&child, 0, sizeof(child));
        if (ntohl(hdr.hdr_entries) < unpack_limit) {
                argv_array_pushl(&av, "unpack-objects", hdr_arg, NULL);
                if (quiet)
index 692c834d9dd48615e42b67e3924c64e3397ad903..d699d28e98c7e76e3c0a4943b58a8c88acede988 100644 (file)
@@ -179,9 +179,8 @@ static void send_git_request(int stdin_fd, const char *serv, const char *repo,
 static int run_child(const char *arg, const char *service)
 {
        int r;
-       struct child_process child;
+       struct child_process child = CHILD_PROCESS_INIT;
 
-       memset(&child, 0, sizeof(child));
        child.in = -1;
        child.out = -1;
        child.err = 0;
index a77e743b94036b2d856e6b3f74999170e39b5f17..2aae05d36486bd31666853c545c37f1280ee11c9 100644 (file)
@@ -133,7 +133,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
                {".idx"},
                {".bitmap", 1},
        };
-       struct child_process cmd;
+       struct child_process cmd = CHILD_PROCESS_INIT;
        struct string_list_item *item;
        struct argv_array cmd_args = ARGV_ARRAY_INIT;
        struct string_list names = STRING_LIST_INIT_DUP;
@@ -250,7 +250,6 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 
        argv_array_push(&cmd_args, packtmp);
 
-       memset(&cmd, 0, sizeof(cmd));
        cmd.argv = cmd_args.argv;
        cmd.git_cmd = 1;
        cmd.out = -1;
@@ -378,6 +377,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
        /* End of pack replacement. */
 
        if (delete_redundant) {
+               int opts = 0;
                sort_string_list(&names);
                for_each_string_list_item(item, &existing_packs) {
                        char *sha1;
@@ -388,25 +388,13 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
                        if (!string_list_has_string(&names, sha1))
                                remove_redundant_pack(packdir, item->string);
                }
-               argv_array_push(&cmd_args, "prune-packed");
-               if (quiet)
-                       argv_array_push(&cmd_args, "--quiet");
-
-               memset(&cmd, 0, sizeof(cmd));
-               cmd.argv = cmd_args.argv;
-               cmd.git_cmd = 1;
-               run_command(&cmd);
-               argv_array_clear(&cmd_args);
+               if (!quiet && isatty(2))
+                       opts |= PRUNE_PACKED_VERBOSE;
+               prune_packed_objects(opts);
        }
 
-       if (!no_update_server_info) {
-               argv_array_push(&cmd_args, "update-server-info");
-               memset(&cmd, 0, sizeof(cmd));
-               cmd.argv = cmd_args.argv;
-               cmd.git_cmd = 1;
-               run_command(&cmd);
-               argv_array_clear(&cmd_args);
-       }
+       if (!no_update_server_info)
+               update_server_info(0);
        remove_temporary_files();
        string_list_clear(&names, 0);
        string_list_clear(&rollback, 0);
index 294b61b97e20ac9b5684bd6a180da37ebef43db9..8020db850092691f55df3815173a6eefce0ca6a0 100644 (file)
@@ -155,7 +155,8 @@ static int replace_object_sha1(const char *object_ref,
        unsigned char prev[20];
        enum object_type obj_type, repl_type;
        char ref[PATH_MAX];
-       struct ref_lock *lock;
+       struct ref_transaction *transaction;
+       struct strbuf err = STRBUF_INIT;
 
        obj_type = sha1_object_info(object, NULL);
        repl_type = sha1_object_info(repl, NULL);
@@ -168,12 +169,13 @@ static int replace_object_sha1(const char *object_ref,
 
        check_ref_valid(object, prev, ref, sizeof(ref), force);
 
-       lock = lock_any_ref_for_update(ref, prev, 0, NULL);
-       if (!lock)
-               die("%s: cannot lock the ref", ref);
-       if (write_ref_sha1(lock, repl, NULL) < 0)
-               die("%s: cannot update the ref", ref);
+       transaction = ref_transaction_begin(&err);
+       if (!transaction ||
+           ref_transaction_update(transaction, ref, repl, prev, 0, 1, &err) ||
+           ref_transaction_commit(transaction, NULL, &err))
+               die("%s", err.buf);
 
+       ref_transaction_free(transaction);
        return 0;
 }
 
@@ -197,7 +199,7 @@ static int replace_object(const char *object_ref, const char *replace_ref, int f
 static void export_object(const unsigned char *sha1, enum object_type type,
                          int raw, const char *filename)
 {
-       struct child_process cmd = { NULL };
+       struct child_process cmd = CHILD_PROCESS_INIT;
        int fd;
 
        fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
@@ -234,7 +236,7 @@ static void import_object(unsigned char *sha1, enum object_type type,
 
        if (!raw && type == OBJ_TREE) {
                const char *argv[] = { "mktree", NULL };
-               struct child_process cmd = { argv };
+               struct child_process cmd = CHILD_PROCESS_INIT;
                struct strbuf result = STRBUF_INIT;
 
                cmd.argv = argv;
index d85e08cc9cc22ee307470dbeb12fdd8d1eea655b..35d3c43ed656bf28b78501426f4502c0dff1e7b0 100644 (file)
@@ -508,7 +508,9 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
        int has_dashdash = 0;
        int output_prefix = 0;
        unsigned char sha1[20];
+       unsigned int flags = 0;
        const char *name = NULL;
+       struct object_context unused;
 
        if (argc > 1 && !strcmp("--parseopt", argv[1]))
                return cmd_parseopt(argc - 1, argv + 1, prefix);
@@ -596,6 +598,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
                        }
                        if (!strcmp(arg, "--quiet") || !strcmp(arg, "-q")) {
                                quiet = 1;
+                               flags |= GET_SHA1_QUIETLY;
                                continue;
                        }
                        if (!strcmp(arg, "--short") ||
@@ -736,7 +739,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
                        }
                        if (!strcmp(arg, "--git-dir")) {
                                const char *gitdir = getenv(GIT_DIR_ENVIRONMENT);
-                               static char cwd[PATH_MAX];
+                               char *cwd;
                                int len;
                                if (gitdir) {
                                        puts(gitdir);
@@ -746,10 +749,10 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
                                        puts(".git");
                                        continue;
                                }
-                               if (!getcwd(cwd, PATH_MAX))
-                                       die_errno("unable to get current working directory");
+                               cwd = xgetcwd();
                                len = strlen(cwd);
                                printf("%s%s.git\n", cwd, len && cwd[len-1] != '/' ? "/" : "");
+                               free(cwd);
                                continue;
                        }
                        if (!strcmp(arg, "--resolve-git-dir")) {
@@ -818,7 +821,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
                        name++;
                        type = REVERSED;
                }
-               if (!get_sha1(name, sha1)) {
+               if (!get_sha1_with_context(name, flags, sha1, &unused)) {
                        if (verify)
                                revs_count++;
                        else
index bc6490b8bca554c568973997568543e206ffdb3e..2b61d3bd41164286fcca3e5fe3c807387d946ff2 100644 (file)
@@ -65,7 +65,7 @@ static void error_removing_concrete_submodules(struct string_list *files, int *e
                          Q_("the following submodule (or one of its nested "
                             "submodules)\n"
                             "uses a .git directory:",
-                            "the following submodules (or one of its nested "
+                            "the following submodules (or one of their nested "
                             "submodules)\n"
                             "use a .git directory:", files->nr),
                          _("\n(use 'rm -rf' if you really want to remove "
index 298c95e3f8b03e7f89d7767407ca8cee3eecc591..199b081e9b805cceb1f2097f2d33966e5f8ff167 100644 (file)
@@ -563,7 +563,7 @@ static int git_show_branch_config(const char *var, const char *value, void *cb)
                        default_arg[default_num++] = "show-branch";
                } else if (default_alloc <= default_num + 1) {
                        default_alloc = default_alloc * 3 / 2 + 20;
-                       default_arg = xrealloc(default_arg, sizeof *default_arg * default_alloc);
+                       REALLOC_ARRAY(default_arg, default_alloc);
                }
                default_arg[default_num++] = xstrdup(value);
                default_arg[default_num] = NULL;
@@ -723,6 +723,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
                char nth_desc[256];
                char *ref;
                int base = 0;
+               unsigned int flags = 0;
 
                if (ac == 0) {
                        static const char *fake_av[2];
@@ -749,7 +750,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
                                /* Ah, that is a date spec... */
                                unsigned long at;
                                at = approxidate(reflog_base);
-                               read_ref_at(ref, at, -1, sha1, NULL,
+                               read_ref_at(ref, flags, at, -1, sha1, NULL,
                                            NULL, NULL, &base);
                        }
                }
@@ -760,7 +761,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
                        unsigned long timestamp;
                        int tz;
 
-                       if (read_ref_at(ref, 0, base+i, sha1, &logmsg,
+                       if (read_ref_at(ref, flags, 0, base+i, sha1, &logmsg,
                                        &timestamp, &tz, NULL)) {
                                reflog = i;
                                break;
index 19eb7478208d7e9c88ced92f2620572d2b234974..a81b9e4174c77fc10d9f0a37c547723505208c3c 100644 (file)
@@ -576,7 +576,6 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
        struct strbuf ref = STRBUF_INIT;
        unsigned char object[20], prev[20];
        const char *object_ref, *tag;
-       struct ref_lock *lock;
        struct create_tag_options opt;
        char *cleanup_arg = NULL;
        int annotate = 0, force = 0, lines = -1;
@@ -584,6 +583,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
        const char *msgfile = NULL, *keyid = NULL;
        struct msg_arg msg = { 0, STRBUF_INIT };
        struct commit_list *with_commit = NULL;
+       struct ref_transaction *transaction;
+       struct strbuf err = STRBUF_INIT;
        struct option options[] = {
                OPT_CMDMODE('l', "list", &cmdmode, N_("list tag names"), 'l'),
                { OPTION_INTEGER, 'n', NULL, &lines, N_("n"),
@@ -729,14 +730,17 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
        if (annotate)
                create_tag(object, tag, &buf, &opt, prev, object);
 
-       lock = lock_any_ref_for_update(ref.buf, prev, 0, NULL);
-       if (!lock)
-               die(_("%s: cannot lock the ref"), ref.buf);
-       if (write_ref_sha1(lock, object, NULL) < 0)
-               die(_("%s: cannot update the ref"), ref.buf);
+       transaction = ref_transaction_begin(&err);
+       if (!transaction ||
+           ref_transaction_update(transaction, ref.buf, object, prev,
+                                  0, 1, &err) ||
+           ref_transaction_commit(transaction, NULL, &err))
+               die("%s", err.buf);
+       ref_transaction_free(transaction);
        if (force && !is_null_sha1(prev) && hashcmp(prev, object))
                printf(_("Updated tag '%s' (was %s)\n"), tag, find_unique_abbrev(prev, DEFAULT_ABBREV));
 
+       strbuf_release(&err);
        strbuf_release(&buf);
        strbuf_release(&ref);
        return 0;
index 99cde45879401350355083f773a2ff2b78113d1a..855d94b90ba019ff19832ff49a76d6cc0077e956 100644 (file)
@@ -164,10 +164,10 @@ static unsigned nr_objects;
  * Called only from check_object() after it verified this object
  * is Ok.
  */
-static void write_cached_object(struct object *obj)
+static void write_cached_object(struct object *obj, struct obj_buffer *obj_buf)
 {
        unsigned char sha1[20];
-       struct obj_buffer *obj_buf = lookup_object_buffer(obj);
+
        if (write_sha1_file(obj_buf->buffer, obj_buf->size, typename(obj->type), sha1) < 0)
                die("failed to write object %s", sha1_to_hex(obj->sha1));
        obj->flags |= FLAG_WRITTEN;
@@ -180,6 +180,8 @@ static void write_cached_object(struct object *obj)
  */
 static int check_object(struct object *obj, int type, void *data)
 {
+       struct obj_buffer *obj_buf;
+
        if (!obj)
                return 1;
 
@@ -198,11 +200,15 @@ static int check_object(struct object *obj, int type, void *data)
                return 0;
        }
 
-       if (fsck_object(obj, 1, fsck_error_function))
+       obj_buf = lookup_object_buffer(obj);
+       if (!obj_buf)
+               die("Whoops! Cannot find object '%s'", sha1_to_hex(obj->sha1));
+       if (fsck_object(obj, obj_buf->buffer, obj_buf->size, 1,
+                       fsck_error_function))
                die("Error in object");
        if (fsck_walk(obj, check_object, NULL))
                die("Error on reachable objects of %s", sha1_to_hex(obj->sha1));
-       write_cached_object(obj);
+       write_cached_object(obj, obj_buf);
        return 0;
 }
 
index 3067b11310fb01e9e05a1988898566f211601e07..54a48c0cfaab57122fc7ce57c525638c2c95408c 100644 (file)
@@ -12,11 +12,8 @@ static const char * const git_update_ref_usage[] = {
        NULL
 };
 
-static struct ref_transaction *transaction;
-
 static char line_termination = '\n';
 static int update_flags;
-static struct strbuf err = STRBUF_INIT;
 
 /*
  * Parse one whitespace- or NUL-terminated, possibly C-quoted argument
@@ -177,8 +174,10 @@ static int parse_next_sha1(struct strbuf *input, const char **next,
  * depending on how line_termination is set.
  */
 
-static const char *parse_cmd_update(struct strbuf *input, const char *next)
+static const char *parse_cmd_update(struct ref_transaction *transaction,
+                                   struct strbuf *input, const char *next)
 {
+       struct strbuf err = STRBUF_INIT;
        char *refname;
        unsigned char new_sha1[20];
        unsigned char old_sha1[20];
@@ -204,12 +203,15 @@ static const char *parse_cmd_update(struct strbuf *input, const char *next)
 
        update_flags = 0;
        free(refname);
+       strbuf_release(&err);
 
        return next;
 }
 
-static const char *parse_cmd_create(struct strbuf *input, const char *next)
+static const char *parse_cmd_create(struct ref_transaction *transaction,
+                                   struct strbuf *input, const char *next)
 {
+       struct strbuf err = STRBUF_INIT;
        char *refname;
        unsigned char new_sha1[20];
 
@@ -226,16 +228,21 @@ static const char *parse_cmd_create(struct strbuf *input, const char *next)
        if (*next != line_termination)
                die("create %s: extra input: %s", refname, next);
 
-       ref_transaction_create(transaction, refname, new_sha1, update_flags);
+       if (ref_transaction_create(transaction, refname, new_sha1,
+                                  update_flags, &err))
+               die("%s", err.buf);
 
        update_flags = 0;
        free(refname);
+       strbuf_release(&err);
 
        return next;
 }
 
-static const char *parse_cmd_delete(struct strbuf *input, const char *next)
+static const char *parse_cmd_delete(struct ref_transaction *transaction,
+                                   struct strbuf *input, const char *next)
 {
+       struct strbuf err = STRBUF_INIT;
        char *refname;
        unsigned char old_sha1[20];
        int have_old;
@@ -256,17 +263,21 @@ static const char *parse_cmd_delete(struct strbuf *input, const char *next)
        if (*next != line_termination)
                die("delete %s: extra input: %s", refname, next);
 
-       ref_transaction_delete(transaction, refname, old_sha1,
-                              update_flags, have_old);
+       if (ref_transaction_delete(transaction, refname, old_sha1,
+                                  update_flags, have_old, &err))
+               die("%s", err.buf);
 
        update_flags = 0;
        free(refname);
+       strbuf_release(&err);
 
        return next;
 }
 
-static const char *parse_cmd_verify(struct strbuf *input, const char *next)
+static const char *parse_cmd_verify(struct ref_transaction *transaction,
+                                   struct strbuf *input, const char *next)
 {
+       struct strbuf err = STRBUF_INIT;
        char *refname;
        unsigned char new_sha1[20];
        unsigned char old_sha1[20];
@@ -294,6 +305,7 @@ static const char *parse_cmd_verify(struct strbuf *input, const char *next)
 
        update_flags = 0;
        free(refname);
+       strbuf_release(&err);
 
        return next;
 }
@@ -307,7 +319,7 @@ static const char *parse_cmd_option(struct strbuf *input, const char *next)
        return next + 8;
 }
 
-static void update_refs_stdin(void)
+static void update_refs_stdin(struct ref_transaction *transaction)
 {
        struct strbuf input = STRBUF_INIT;
        const char *next;
@@ -322,13 +334,13 @@ static void update_refs_stdin(void)
                else if (isspace(*next))
                        die("whitespace before command: %s", next);
                else if (starts_with(next, "update "))
-                       next = parse_cmd_update(&input, next + 7);
+                       next = parse_cmd_update(transaction, &input, next + 7);
                else if (starts_with(next, "create "))
-                       next = parse_cmd_create(&input, next + 7);
+                       next = parse_cmd_create(transaction, &input, next + 7);
                else if (starts_with(next, "delete "))
-                       next = parse_cmd_delete(&input, next + 7);
+                       next = parse_cmd_delete(transaction, &input, next + 7);
                else if (starts_with(next, "verify "))
-                       next = parse_cmd_verify(&input, next + 7);
+                       next = parse_cmd_verify(transaction, &input, next + 7);
                else if (starts_with(next, "option "))
                        next = parse_cmd_option(&input, next + 7);
                else
@@ -362,15 +374,21 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
                die("Refusing to perform update with empty message.");
 
        if (read_stdin) {
-               transaction = ref_transaction_begin();
+               struct strbuf err = STRBUF_INIT;
+               struct ref_transaction *transaction;
+
+               transaction = ref_transaction_begin(&err);
+               if (!transaction)
+                       die("%s", err.buf);
                if (delete || no_deref || argc > 0)
                        usage_with_options(git_update_ref_usage, options);
                if (end_null)
                        line_termination = '\0';
-               update_refs_stdin();
+               update_refs_stdin(transaction);
                if (ref_transaction_commit(transaction, msg, &err))
                        die("%s", err.buf);
                ref_transaction_free(transaction);
+               strbuf_release(&err);
                return 0;
        }
 
index 972579f33c4b0adfb2240ef90b22980dc042c70a..7747537beb72aba52377a13b9b3d61829f3a2fa8 100644 (file)
@@ -8,7 +8,7 @@
 
 static int verify_one_pack(const char *path, unsigned int flags)
 {
-       struct child_process index_pack;
+       struct child_process index_pack = CHILD_PROCESS_INIT;
        const char *argv[] = {"index-pack", NULL, NULL, NULL };
        struct strbuf arg = STRBUF_INIT;
        int verbose = flags & VERIFY_PACK_VERBOSE;
@@ -32,7 +32,6 @@ static int verify_one_pack(const char *path, unsigned int flags)
                strbuf_addstr(&arg, ".pack");
        argv[2] = arg.buf;
 
-       memset(&index_pack, 0, sizeof(index_pack));
        index_pack.argv = argv;
        index_pack.git_cmd = 1;
 
index b708906cdbd2a14d0e5bcd1e1288c78777cf6a5e..b2b89fe8628eb29b613754ee8e837fd56de185da 100644 (file)
--- a/bundle.c
+++ b/bundle.c
@@ -240,7 +240,7 @@ int create_bundle(struct bundle_header *header, const char *path,
        int i, ref_count = 0;
        struct strbuf buf = STRBUF_INIT;
        struct rev_info revs;
-       struct child_process rls;
+       struct child_process rls = CHILD_PROCESS_INIT;
        FILE *rls_fout;
 
        bundle_to_stdout = !strcmp(path, "-");
@@ -258,7 +258,6 @@ int create_bundle(struct bundle_header *header, const char *path,
        init_revisions(&revs, NULL);
 
        /* write prerequisites */
-       memset(&rls, 0, sizeof(rls));
        argv_array_pushl(&rls.args,
                         "rev-list", "--boundary", "--pretty=oneline",
                         NULL);
@@ -417,14 +416,13 @@ int unbundle(struct bundle_header *header, int bundle_fd, int flags)
 {
        const char *argv_index_pack[] = {"index-pack",
                                         "--fix-thin", "--stdin", NULL, NULL};
-       struct child_process ip;
+       struct child_process ip = CHILD_PROCESS_INIT;
 
        if (flags & BUNDLE_VERBOSE)
                argv_index_pack[3] = "-v";
 
        if (verify_bundle(header, 0))
                return -1;
-       memset(&ip, 0, sizeof(ip));
        ip.argv = argv_index_pack;
        ip.in = bundle_fd;
        ip.no_stdout = 1;
index c53f7de2b13acfc1b97c60b04552e57791377442..75a54fdc7232e5693b042aa06540d51a99f01551 100644 (file)
@@ -246,9 +246,12 @@ static int update_one(struct cache_tree *it,
        struct strbuf buffer;
        int missing_ok = flags & WRITE_TREE_MISSING_OK;
        int dryrun = flags & WRITE_TREE_DRY_RUN;
+       int repair = flags & WRITE_TREE_REPAIR;
        int to_invalidate = 0;
        int i;
 
+       assert(!(dryrun && repair));
+
        *skip_count = 0;
 
        if (0 <= it->entry_count && has_sha1_file(it->sha1))
@@ -320,6 +323,7 @@ static int update_one(struct cache_tree *it,
                int pathlen, entlen;
                const unsigned char *sha1;
                unsigned mode;
+               int expected_missing = 0;
 
                path = ce->name;
                pathlen = ce_namelen(ce);
@@ -336,8 +340,10 @@ static int update_one(struct cache_tree *it,
                        i += sub->count;
                        sha1 = sub->cache_tree->sha1;
                        mode = S_IFDIR;
-                       if (sub->cache_tree->entry_count < 0)
+                       if (sub->cache_tree->entry_count < 0) {
                                to_invalidate = 1;
+                               expected_missing = 1;
+                       }
                }
                else {
                        sha1 = ce->sha1;
@@ -347,6 +353,8 @@ static int update_one(struct cache_tree *it,
                }
                if (mode != S_IFGITLINK && !missing_ok && !has_sha1_file(sha1)) {
                        strbuf_release(&buffer);
+                       if (expected_missing)
+                               return -1;
                        return error("invalid object %06o %s for '%.*s'",
                                mode, sha1_to_hex(sha1), entlen+baselen, path);
                }
@@ -381,7 +389,14 @@ static int update_one(struct cache_tree *it,
 #endif
        }
 
-       if (dryrun)
+       if (repair) {
+               unsigned char sha1[20];
+               hash_sha1_file(buffer.buf, buffer.len, tree_type, sha1);
+               if (has_sha1_file(sha1))
+                       hashcpy(it->sha1, sha1);
+               else
+                       to_invalidate = 1;
+       } else if (dryrun)
                hash_sha1_file(buffer.buf, buffer.len, tree_type, it->sha1);
        else if (write_sha1_file(buffer.buf, buffer.len, tree_type, it->sha1)) {
                strbuf_release(&buffer);
index b47ccec7f626d7cda34ed17661c1dc3e4f035d6a..aa7b3e4a0a9d4bbb29574d71e23c05349be4c6fc 100644 (file)
@@ -39,6 +39,7 @@ int update_main_cache_tree(int);
 #define WRITE_TREE_IGNORE_CACHE_TREE 2
 #define WRITE_TREE_DRY_RUN 4
 #define WRITE_TREE_SILENT 8
+#define WRITE_TREE_REPAIR 16
 
 /* error return codes */
 #define WRITE_TREE_UNREADABLE_INDEX (-1)
diff --git a/cache.h b/cache.h
index dcf3a2afe9d782e4b2474d8834602f80610ba25f..8206039cfe9545b4f6eb6757dfd62bf468b3be52 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -8,6 +8,7 @@
 #include "gettext.h"
 #include "convert.h"
 #include "trace.h"
+#include "string-list.h"
 
 #include SHA1_HEADER
 #ifndef git_SHA_CTX
@@ -481,7 +482,7 @@ extern int daemonize(void);
                                alloc = (nr); \
                        else \
                                alloc = alloc_nr(alloc); \
-                       x = xrealloc((x), alloc * sizeof(*(x))); \
+                       REALLOC_ARRAY(x, alloc); \
                } \
        } while (0)
 
@@ -585,6 +586,7 @@ extern NORETURN void unable_to_lock_index_die(const char *path, int err);
 extern int hold_lock_file_for_update(struct lock_file *, const char *path, int);
 extern int hold_lock_file_for_append(struct lock_file *, const char *path, int);
 extern int commit_lock_file(struct lock_file *);
+extern int reopen_lock_file(struct lock_file *);
 extern void update_index_if_able(struct index_state *, struct lock_file *);
 
 extern int hold_locked_index(struct lock_file *, int);
@@ -1037,6 +1039,7 @@ enum date_mode {
        DATE_SHORT,
        DATE_LOCAL,
        DATE_ISO8601,
+       DATE_ISO8601_STRICT,
        DATE_RFC2822,
        DATE_RAW
 };
@@ -1044,10 +1047,10 @@ enum date_mode {
 const char *show_date(unsigned long time, int timezone, enum date_mode mode);
 void show_date_relative(unsigned long time, int tz, const struct timeval *now,
                        struct strbuf *timebuf);
-int parse_date(const char *date, char *buf, int bufsize);
+int parse_date(const char *date, struct strbuf *out);
 int parse_date_basic(const char *date, unsigned long *timestamp, int *offset);
 int parse_expiry_date(const char *date, unsigned long *timestamp);
-void datestamp(char *buf, int bufsize);
+void datestamp(struct strbuf *out);
 #define approxidate(s) approxidate_careful((s), NULL)
 unsigned long approxidate_careful(const char *, int *);
 unsigned long approxidate_relative(const char *date, const struct timeval *now);
@@ -1061,6 +1064,7 @@ extern const char *git_author_info(int);
 extern const char *git_committer_info(int);
 extern const char *fmt_ident(const char *name, const char *email, const char *date_str, int);
 extern const char *fmt_name(const char *name, const char *email);
+extern const char *ident_default_name(void);
 extern const char *ident_default_email(void);
 extern const char *git_editor(void);
 extern const char *git_pager(int stdout_is_tty);
@@ -1296,7 +1300,7 @@ extern int git_config_from_buf(config_fn_t fn, const char *name,
                               const char *buf, size_t len, void *data);
 extern void git_config_push_parameter(const char *text);
 extern int git_config_from_parameters(config_fn_t fn, void *data);
-extern int git_config(config_fn_t fn, void *);
+extern void git_config(config_fn_t fn, void *);
 extern int git_config_with_options(config_fn_t fn, void *,
                                   struct git_config_source *config_source,
                                   int respect_includes);
@@ -1353,6 +1357,69 @@ extern int parse_config_key(const char *var,
                            const char **subsection, int *subsection_len,
                            const char **key);
 
+struct config_set_element {
+       struct hashmap_entry ent;
+       char *key;
+       struct string_list value_list;
+};
+
+struct configset_list_item {
+       struct config_set_element *e;
+       int value_index;
+};
+
+/*
+ * the contents of the list are ordered according to their
+ * position in the config files and order of parsing the files.
+ * (i.e. key-value pair at the last position of .git/config will
+ * be at the last item of the list)
+ */
+struct configset_list {
+       struct configset_list_item *items;
+       unsigned int nr, alloc;
+};
+
+struct config_set {
+       struct hashmap config_hash;
+       int hash_initialized;
+       struct configset_list list;
+};
+
+extern void git_configset_init(struct config_set *cs);
+extern int git_configset_add_file(struct config_set *cs, const char *filename);
+extern int git_configset_get_value(struct config_set *cs, const char *key, const char **value);
+extern const struct string_list *git_configset_get_value_multi(struct config_set *cs, const char *key);
+extern void git_configset_clear(struct config_set *cs);
+extern int git_configset_get_string_const(struct config_set *cs, const char *key, const char **dest);
+extern int git_configset_get_string(struct config_set *cs, const char *key, char **dest);
+extern int git_configset_get_int(struct config_set *cs, const char *key, int *dest);
+extern int git_configset_get_ulong(struct config_set *cs, const char *key, unsigned long *dest);
+extern int git_configset_get_bool(struct config_set *cs, const char *key, int *dest);
+extern int git_configset_get_bool_or_int(struct config_set *cs, const char *key, int *is_bool, int *dest);
+extern int git_configset_get_maybe_bool(struct config_set *cs, const char *key, int *dest);
+extern int git_configset_get_pathname(struct config_set *cs, const char *key, const char **dest);
+
+extern int git_config_get_value(const char *key, const char **value);
+extern const struct string_list *git_config_get_value_multi(const char *key);
+extern void git_config_clear(void);
+extern void git_config_iter(config_fn_t fn, void *data);
+extern int git_config_get_string_const(const char *key, const char **dest);
+extern int git_config_get_string(const char *key, char **dest);
+extern int git_config_get_int(const char *key, int *dest);
+extern int git_config_get_ulong(const char *key, unsigned long *dest);
+extern int git_config_get_bool(const char *key, int *dest);
+extern int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest);
+extern int git_config_get_maybe_bool(const char *key, int *dest);
+extern int git_config_get_pathname(const char *key, const char **dest);
+
+struct key_value_info {
+       const char *filename;
+       int linenr;
+};
+
+extern NORETURN void git_die_config(const char *key, const char *err, ...) __attribute__((format(printf, 2, 3)));
+extern NORETURN void git_die_config_linenr(const char *key, const char *filename, int linenr);
+
 extern int committer_ident_sufficiently_given(void);
 extern int author_ident_sufficiently_given(void);
 
@@ -1363,6 +1430,8 @@ extern const char *git_mailmap_blob;
 
 /* IO helper functions */
 extern void maybe_flush_or_die(FILE *, const char *);
+__attribute__((format (printf, 2, 3)))
+extern void fprintf_or_die(FILE *, const char *fmt, ...);
 extern int copy_fd(int ifd, int ofd);
 extern int copy_file(const char *dst, const char *src, int mode);
 extern int copy_file_with_time(const char *dst, const char *src, int mode);
index ca878bcea7a42476a7c2b03e74897a2af87bec3f..8082a944fd6d07f69d323678380d635d9361b77c 100644 (file)
--- a/column.c
+++ b/column.c
@@ -81,8 +81,7 @@ static void compute_column_width(struct column_data *data)
  */
 static void shrink_columns(struct column_data *data)
 {
-       data->width = xrealloc(data->width,
-                              sizeof(*data->width) * data->cols);
+       REALLOC_ARRAY(data->width, data->cols);
        while (data->rows > 1) {
                int x, total_width, cols, rows;
                rows = data->rows;
@@ -91,8 +90,7 @@ static void shrink_columns(struct column_data *data)
                data->rows--;
                data->cols = DIV_ROUND_UP(data->list->nr, data->rows);
                if (data->cols != cols)
-                       data->width = xrealloc(data->width,
-                                              sizeof(*data->width) * data->cols);
+                       REALLOC_ARRAY(data->width, data->cols);
                compute_column_width(data);
 
                total_width = strlen(data->opts.indent);
@@ -367,7 +365,7 @@ int parseopt_column_callback(const struct option *opt,
 }
 
 static int fd_out = -1;
-static struct child_process column_process;
+static struct child_process column_process = CHILD_PROCESS_INIT;
 
 int run_column_filter(int colopts, const struct column_options *opts)
 {
index 375c9c751adbf165c757832667102b761e1358c3..f37ec3831f60cb9072d6cbf4f3d0126bc0681bf1 100644 (file)
@@ -90,8 +90,7 @@ static MAYBE_UNUSED elemtype *slabname## _at(struct slabname *s,      \
                                                                        \
        if (s->slab_count <= nth_slab) {                                \
                int i;                                                  \
-               s->slab = xrealloc(s->slab,                             \
-                                  (nth_slab + 1) * sizeof(*s->slab));  \
+               REALLOC_ARRAY(s->slab, nth_slab + 1);                   \
                stat_ ##slabname## realloc++;                           \
                for (i = s->slab_count; i <= nth_slab; i++)             \
                        s->slab[i] = NULL;                              \
index ae7f2b10f4e08a549614346c8262b10503cca953..9c4439fed61c3b26d493d0f0306b65a471da9b19 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -584,25 +584,19 @@ define_commit_slab(author_date_slab, unsigned long);
 static void record_author_date(struct author_date_slab *author_date,
                               struct commit *commit)
 {
-       const char *buf, *line_end, *ident_line;
        const char *buffer = get_commit_buffer(commit, NULL);
        struct ident_split ident;
+       const char *ident_line;
+       size_t ident_len;
        char *date_end;
        unsigned long date;
 
-       for (buf = buffer; buf; buf = line_end + 1) {
-               line_end = strchrnul(buf, '\n');
-               if (!skip_prefix(buf, "author ", &ident_line)) {
-                       if (!line_end[0] || line_end[1] == '\n')
-                               return; /* end of header */
-                       continue;
-               }
-               if (split_ident_line(&ident,
-                                    ident_line, line_end - ident_line) ||
-                   !ident.date_begin || !ident.date_end)
-                       goto fail_exit; /* malformed "author" line */
-               break;
-       }
+       ident_line = find_commit_header(buffer, "author", &ident_len);
+       if (!ident_line)
+               goto fail_exit; /* no author line */
+       if (split_ident_line(&ident, ident_line, ident_len) ||
+           !ident.date_begin || !ident.date_end)
+               goto fail_exit; /* malformed "author" line */
 
        date = strtoul(ident.date_begin, &date_end, 10);
        if (date_end != ident.date_end)
@@ -1256,7 +1250,7 @@ static void parse_gpg_output(struct signature_check *sigc)
        }
 }
 
-void check_commit_signature(const struct commitcommit, struct signature_check *sigc)
+void check_commit_signature(const struct commit *commit, struct signature_check *sigc)
 {
        struct strbuf payload = STRBUF_INIT;
        struct strbuf signature = STRBUF_INIT;
@@ -1660,3 +1654,25 @@ void print_commit_list(struct commit_list *list,
                printf(format, sha1_to_hex(list->item->object.sha1));
        }
 }
+
+const char *find_commit_header(const char *msg, const char *key, size_t *out_len)
+{
+       int key_len = strlen(key);
+       const char *line = msg;
+
+       while (line) {
+               const char *eol = strchrnul(line, '\n');
+
+               if (line == eol)
+                       return NULL;
+
+               if (eol - line > key_len &&
+                   !strncmp(line, key, key_len) &&
+                   line[key_len] == ' ') {
+                       *out_len = eol - line - key_len - 1;
+                       return line + key_len + 1;
+               }
+               line = *eol ? eol + 1 : NULL;
+       }
+       return NULL;
+}
index aa8c3ca50af42375caf954e309d76731b4a9295e..bc68ccbe691a28ed9b22fa935c78d2e9640347ea 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -26,13 +26,25 @@ extern int save_commit_buffer;
 extern const char *commit_type;
 
 /* While we can decorate any object with a name, it's only used for commits.. */
-extern struct decoration name_decoration;
 struct name_decoration {
        struct name_decoration *next;
        int type;
-       char name[1];
+       char name[FLEX_ARRAY];
 };
 
+enum decoration_type {
+       DECORATION_NONE = 0,
+       DECORATION_REF_LOCAL,
+       DECORATION_REF_REMOTE,
+       DECORATION_REF_TAG,
+       DECORATION_REF_STASH,
+       DECORATION_REF_HEAD,
+       DECORATION_GRAFTED,
+};
+
+void add_name_decoration(enum decoration_type type, const char *name, struct object *obj);
+const struct name_decoration *get_name_decoration(const struct object *obj);
+
 struct commit *lookup_commit(const unsigned char *sha1);
 struct commit *lookup_commit_reference(const unsigned char *sha1);
 struct commit *lookup_commit_reference_gently(const unsigned char *sha1,
@@ -314,6 +326,17 @@ extern struct commit_extra_header *read_commit_extra_headers(struct commit *, co
 
 extern void free_commit_extra_headers(struct commit_extra_header *extra);
 
+/*
+ * Search the commit object contents given by "msg" for the header "key".
+ * Returns a pointer to the start of the header contents, or NULL. The length
+ * of the header, up to the first newline, is returned via out_len.
+ *
+ * Note that some headers (like mergetag) may be multi-line. It is the caller's
+ * responsibility to parse further in this case!
+ */
+extern const char *find_commit_header(const char *msg, const char *key,
+                                     size_t *out_len);
+
 typedef void (*each_mergetag_fn)(struct commit *commit, struct commit_extra_header *extra,
                                 void *cb_data);
 
@@ -347,7 +370,7 @@ extern void print_commit_list(struct commit_list *list,
  * at all.  This may allocate memory for sig->gpg_output, sig->gpg_status,
  * sig->signer and sig->key.
  */
-extern void check_commit_signature(const struct commitcommit, struct signature_check *sigc);
+extern void check_commit_signature(const struct commit *commit, struct signature_check *sigc);
 
 int compare_commits_by_commit_date(const void *a_, const void *b_, void *unused);
 
index df0e3203abed06374a789be191ff130e3ba728b6..5e499cfb71a00ea81013c1ed21e9a5e9dc9e2544 100644 (file)
@@ -69,7 +69,6 @@ struct sigaction {
        sig_handler_t sa_handler;
        unsigned sa_flags;
 };
-#define sigemptyset(x) (void)0
 #define SA_RESTART 0
 
 struct itimerval {
@@ -116,6 +115,12 @@ static inline int fcntl(int fd, int cmd, ...)
 }
 /* bash cannot reliably detect negative return codes as failure */
 #define exit(code) exit((code) & 0xff)
+#define sigemptyset(x) (void)0
+static inline int sigaddset(sigset_t *set, int signum)
+{ return 0; }
+#define SIG_UNBLOCK 0
+static inline int sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
+{ return 0; }
 
 /*
  * simple adaptors
index 9e42d3832bbcce428705ef616d5b2008c47ec91a..a677eb6c599ddb39f1b4bb7ac44a59bc167fb3a7 100644 (file)
--- a/config.c
+++ b/config.c
@@ -9,6 +9,8 @@
 #include "exec_cmd.h"
 #include "strbuf.h"
 #include "quote.h"
+#include "hashmap.h"
+#include "string-list.h"
 
 struct config_source {
        struct config_source *prev;
@@ -37,6 +39,13 @@ static struct config_source *cf;
 
 static int zlib_compression_seen;
 
+/*
+ * Default config_set that contains key-value pairs from the usual set of config
+ * config files (i.e repo specific .git/config, user wide ~/.gitconfig, XDG
+ * config file and the global /etc/gitconfig)
+ */
+static struct config_set the_config_set;
+
 static int config_file_fgetc(struct config_source *conf)
 {
        return fgetc(conf->u.file);
@@ -127,7 +136,6 @@ static int handle_path_include(const char *path, struct config_include_data *inc
 int git_config_include(const char *var, const char *value, void *data)
 {
        struct config_include_data *inc = data;
-       const char *type;
        int ret;
 
        /*
@@ -138,10 +146,7 @@ int git_config_include(const char *var, const char *value, void *data)
        if (ret < 0)
                return ret;
 
-       if (!skip_prefix(var, "include.", &type))
-               return ret;
-
-       if (!strcmp(type, "path"))
+       if (!strcmp(var, "include.path"))
                ret = handle_path_include(value, inc);
        return ret;
 }
@@ -237,6 +242,7 @@ static int get_next_char(void)
                cf->linenr++;
        if (c == EOF) {
                cf->eof = 1;
+               cf->linenr++;
                c = '\n';
        }
        return c;
@@ -312,6 +318,7 @@ static int get_value(config_fn_t fn, void *data, struct strbuf *name)
 {
        int c;
        char *value;
+       int ret;
 
        /* Get the full name */
        for (;;) {
@@ -334,7 +341,15 @@ static int get_value(config_fn_t fn, void *data, struct strbuf *name)
                if (!value)
                        return -1;
        }
-       return fn(name->buf, value, data);
+       /*
+        * We already consumed the \n, but we need linenr to point to
+        * the line we just parsed during the call to fn to get
+        * accurate line number in error messages.
+        */
+       cf->linenr--;
+       ret = fn(name->buf, value, data);
+       cf->linenr++;
+       return ret;
 }
 
 static int get_extended_base_var(struct strbuf *name, int c)
@@ -450,9 +465,9 @@ static int git_parse_source(config_fn_t fn, void *data)
                        break;
        }
        if (cf->die_on_error)
-               die("bad config file line %d in %s", cf->linenr, cf->name);
+               die(_("bad config file line %d in %s"), cf->linenr, cf->name);
        else
-               return error("bad config file line %d in %s", cf->linenr, cf->name);
+               return error(_("bad config file line %d in %s"), cf->linenr, cf->name);
 }
 
 static int parse_unit_factor(const char *end, uintmax_t *val)
@@ -568,9 +583,9 @@ static void die_bad_number(const char *name, const char *value)
                value = "";
 
        if (cf && cf->name)
-               die("bad numeric config value '%s' for '%s' in %s: %s",
+               die(_("bad numeric config value '%s' for '%s' in %s: %s"),
                    value, name, cf->name, reason);
-       die("bad numeric config value '%s' for '%s': %s", value, name, reason);
+       die(_("bad numeric config value '%s' for '%s': %s"), value, name, reason);
 }
 
 int git_config_int(const char *name, const char *value)
@@ -655,7 +670,7 @@ int git_config_pathname(const char **dest, const char *var, const char *value)
                return config_error_nonbool(var);
        *dest = expand_user_path(value);
        if (!*dest)
-               die("Failed to expand user dir in: '%s'", value);
+               die(_("failed to expand user dir in: '%s'"), value);
        return 0;
 }
 
@@ -733,7 +748,7 @@ static int git_default_core_config(const char *var, const char *value)
                if (level == -1)
                        level = Z_DEFAULT_COMPRESSION;
                else if (level < 0 || level > Z_BEST_COMPRESSION)
-                       die("bad zlib compression level %d", level);
+                       die(_("bad zlib compression level %d"), level);
                zlib_compression_level = level;
                zlib_compression_seen = 1;
                return 0;
@@ -744,7 +759,7 @@ static int git_default_core_config(const char *var, const char *value)
                if (level == -1)
                        level = Z_DEFAULT_COMPRESSION;
                else if (level < 0 || level > Z_BEST_COMPRESSION)
-                       die("bad zlib compression level %d", level);
+                       die(_("bad zlib compression level %d"), level);
                core_compression_level = level;
                core_compression_seen = 1;
                if (!zlib_compression_seen)
@@ -866,7 +881,7 @@ static int git_default_core_config(const char *var, const char *value)
                else if (!strcmp(value, "link"))
                        object_creation_mode = OBJECT_CREATION_USES_HARDLINKS;
                else
-                       die("Invalid mode for object creation: %s", value);
+                       die(_("invalid mode for object creation: %s"), value);
                return 0;
        }
 
@@ -1166,7 +1181,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
 
        switch (git_config_from_parameters(fn, data)) {
        case -1: /* error */
-               die("unable to parse command-line config");
+               die(_("unable to parse command-line config"));
                break;
        case 0: /* found nothing */
                break;
@@ -1213,9 +1228,365 @@ int git_config_with_options(config_fn_t fn, void *data,
        return ret;
 }
 
-int git_config(config_fn_t fn, void *data)
+static void git_config_raw(config_fn_t fn, void *data)
+{
+       if (git_config_with_options(fn, data, NULL, 1) < 0)
+               /*
+                * git_config_with_options() normally returns only
+                * positive values, as most errors are fatal, and
+                * non-fatal potential errors are guarded by "if"
+                * statements that are entered only when no error is
+                * possible.
+                *
+                * If we ever encounter a non-fatal error, it means
+                * something went really wrong and we should stop
+                * immediately.
+                */
+               die(_("unknown error occured while reading the configuration files"));
+}
+
+static void configset_iter(struct config_set *cs, config_fn_t fn, void *data)
+{
+       int i, value_index;
+       struct string_list *values;
+       struct config_set_element *entry;
+       struct configset_list *list = &cs->list;
+       struct key_value_info *kv_info;
+
+       for (i = 0; i < list->nr; i++) {
+               entry = list->items[i].e;
+               value_index = list->items[i].value_index;
+               values = &entry->value_list;
+               if (fn(entry->key, values->items[value_index].string, data) < 0) {
+                       kv_info = values->items[value_index].util;
+                       git_die_config_linenr(entry->key, kv_info->filename, kv_info->linenr);
+               }
+       }
+}
+
+static void git_config_check_init(void);
+
+void git_config(config_fn_t fn, void *data)
+{
+       git_config_check_init();
+       configset_iter(&the_config_set, fn, data);
+}
+
+static struct config_set_element *configset_find_element(struct config_set *cs, const char *key)
+{
+       struct config_set_element k;
+       struct config_set_element *found_entry;
+       char *normalized_key;
+       int ret;
+       /*
+        * `key` may come from the user, so normalize it before using it
+        * for querying entries from the hashmap.
+        */
+       ret = git_config_parse_key(key, &normalized_key, NULL);
+
+       if (ret)
+               return NULL;
+
+       hashmap_entry_init(&k, strhash(normalized_key));
+       k.key = normalized_key;
+       found_entry = hashmap_get(&cs->config_hash, &k, NULL);
+       free(normalized_key);
+       return found_entry;
+}
+
+static int configset_add_value(struct config_set *cs, const char *key, const char *value)
+{
+       struct config_set_element *e;
+       struct string_list_item *si;
+       struct configset_list_item *l_item;
+       struct key_value_info *kv_info = xmalloc(sizeof(*kv_info));
+
+       e = configset_find_element(cs, key);
+       /*
+        * Since the keys are being fed by git_config*() callback mechanism, they
+        * are already normalized. So simply add them without any further munging.
+        */
+       if (!e) {
+               e = xmalloc(sizeof(*e));
+               hashmap_entry_init(e, strhash(key));
+               e->key = xstrdup(key);
+               string_list_init(&e->value_list, 1);
+               hashmap_add(&cs->config_hash, e);
+       }
+       si = string_list_append_nodup(&e->value_list, value ? xstrdup(value) : NULL);
+
+       ALLOC_GROW(cs->list.items, cs->list.nr + 1, cs->list.alloc);
+       l_item = &cs->list.items[cs->list.nr++];
+       l_item->e = e;
+       l_item->value_index = e->value_list.nr - 1;
+
+       if (cf) {
+               kv_info->filename = strintern(cf->name);
+               kv_info->linenr = cf->linenr;
+       } else {
+               /* for values read from `git_config_from_parameters()` */
+               kv_info->filename = NULL;
+               kv_info->linenr = -1;
+       }
+       si->util = kv_info;
+
+       return 0;
+}
+
+static int config_set_element_cmp(const struct config_set_element *e1,
+                                const struct config_set_element *e2, const void *unused)
+{
+       return strcmp(e1->key, e2->key);
+}
+
+void git_configset_init(struct config_set *cs)
+{
+       hashmap_init(&cs->config_hash, (hashmap_cmp_fn)config_set_element_cmp, 0);
+       cs->hash_initialized = 1;
+       cs->list.nr = 0;
+       cs->list.alloc = 0;
+       cs->list.items = NULL;
+}
+
+void git_configset_clear(struct config_set *cs)
+{
+       struct config_set_element *entry;
+       struct hashmap_iter iter;
+       if (!cs->hash_initialized)
+               return;
+
+       hashmap_iter_init(&cs->config_hash, &iter);
+       while ((entry = hashmap_iter_next(&iter))) {
+               free(entry->key);
+               string_list_clear(&entry->value_list, 1);
+       }
+       hashmap_free(&cs->config_hash, 1);
+       cs->hash_initialized = 0;
+       free(cs->list.items);
+       cs->list.nr = 0;
+       cs->list.alloc = 0;
+       cs->list.items = NULL;
+}
+
+static int config_set_callback(const char *key, const char *value, void *cb)
+{
+       struct config_set *cs = cb;
+       configset_add_value(cs, key, value);
+       return 0;
+}
+
+int git_configset_add_file(struct config_set *cs, const char *filename)
+{
+       return git_config_from_file(config_set_callback, filename, cs);
+}
+
+int git_configset_get_value(struct config_set *cs, const char *key, const char **value)
+{
+       const struct string_list *values = NULL;
+       /*
+        * Follows "last one wins" semantic, i.e., if there are multiple matches for the
+        * queried key in the files of the configset, the value returned will be the last
+        * value in the value list for that key.
+        */
+       values = git_configset_get_value_multi(cs, key);
+
+       if (!values)
+               return 1;
+       assert(values->nr > 0);
+       *value = values->items[values->nr - 1].string;
+       return 0;
+}
+
+const struct string_list *git_configset_get_value_multi(struct config_set *cs, const char *key)
+{
+       struct config_set_element *e = configset_find_element(cs, key);
+       return e ? &e->value_list : NULL;
+}
+
+int git_configset_get_string_const(struct config_set *cs, const char *key, const char **dest)
+{
+       const char *value;
+       if (!git_configset_get_value(cs, key, &value))
+               return git_config_string(dest, key, value);
+       else
+               return 1;
+}
+
+int git_configset_get_string(struct config_set *cs, const char *key, char **dest)
 {
-       return git_config_with_options(fn, data, NULL, 1);
+       return git_configset_get_string_const(cs, key, (const char **)dest);
+}
+
+int git_configset_get_int(struct config_set *cs, const char *key, int *dest)
+{
+       const char *value;
+       if (!git_configset_get_value(cs, key, &value)) {
+               *dest = git_config_int(key, value);
+               return 0;
+       } else
+               return 1;
+}
+
+int git_configset_get_ulong(struct config_set *cs, const char *key, unsigned long *dest)
+{
+       const char *value;
+       if (!git_configset_get_value(cs, key, &value)) {
+               *dest = git_config_ulong(key, value);
+               return 0;
+       } else
+               return 1;
+}
+
+int git_configset_get_bool(struct config_set *cs, const char *key, int *dest)
+{
+       const char *value;
+       if (!git_configset_get_value(cs, key, &value)) {
+               *dest = git_config_bool(key, value);
+               return 0;
+       } else
+               return 1;
+}
+
+int git_configset_get_bool_or_int(struct config_set *cs, const char *key,
+                               int *is_bool, int *dest)
+{
+       const char *value;
+       if (!git_configset_get_value(cs, key, &value)) {
+               *dest = git_config_bool_or_int(key, value, is_bool);
+               return 0;
+       } else
+               return 1;
+}
+
+int git_configset_get_maybe_bool(struct config_set *cs, const char *key, int *dest)
+{
+       const char *value;
+       if (!git_configset_get_value(cs, key, &value)) {
+               *dest = git_config_maybe_bool(key, value);
+               if (*dest == -1)
+                       return -1;
+               return 0;
+       } else
+               return 1;
+}
+
+int git_configset_get_pathname(struct config_set *cs, const char *key, const char **dest)
+{
+       const char *value;
+       if (!git_configset_get_value(cs, key, &value))
+               return git_config_pathname(dest, key, value);
+       else
+               return 1;
+}
+
+static void git_config_check_init(void)
+{
+       if (the_config_set.hash_initialized)
+               return;
+       git_configset_init(&the_config_set);
+       git_config_raw(config_set_callback, &the_config_set);
+}
+
+void git_config_clear(void)
+{
+       if (!the_config_set.hash_initialized)
+               return;
+       git_configset_clear(&the_config_set);
+}
+
+int git_config_get_value(const char *key, const char **value)
+{
+       git_config_check_init();
+       return git_configset_get_value(&the_config_set, key, value);
+}
+
+const struct string_list *git_config_get_value_multi(const char *key)
+{
+       git_config_check_init();
+       return git_configset_get_value_multi(&the_config_set, key);
+}
+
+int git_config_get_string_const(const char *key, const char **dest)
+{
+       int ret;
+       git_config_check_init();
+       ret = git_configset_get_string_const(&the_config_set, key, dest);
+       if (ret < 0)
+               git_die_config(key, NULL);
+       return ret;
+}
+
+int git_config_get_string(const char *key, char **dest)
+{
+       git_config_check_init();
+       return git_config_get_string_const(key, (const char **)dest);
+}
+
+int git_config_get_int(const char *key, int *dest)
+{
+       git_config_check_init();
+       return git_configset_get_int(&the_config_set, key, dest);
+}
+
+int git_config_get_ulong(const char *key, unsigned long *dest)
+{
+       git_config_check_init();
+       return git_configset_get_ulong(&the_config_set, key, dest);
+}
+
+int git_config_get_bool(const char *key, int *dest)
+{
+       git_config_check_init();
+       return git_configset_get_bool(&the_config_set, key, dest);
+}
+
+int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest)
+{
+       git_config_check_init();
+       return git_configset_get_bool_or_int(&the_config_set, key, is_bool, dest);
+}
+
+int git_config_get_maybe_bool(const char *key, int *dest)
+{
+       git_config_check_init();
+       return git_configset_get_maybe_bool(&the_config_set, key, dest);
+}
+
+int git_config_get_pathname(const char *key, const char **dest)
+{
+       int ret;
+       git_config_check_init();
+       ret = git_configset_get_pathname(&the_config_set, key, dest);
+       if (ret < 0)
+               git_die_config(key, NULL);
+       return ret;
+}
+
+NORETURN
+void git_die_config_linenr(const char *key, const char *filename, int linenr)
+{
+       if (!filename)
+               die(_("unable to parse '%s' from command-line config"), key);
+       else
+               die(_("bad config variable '%s' in file '%s' at line %d"),
+                   key, filename, linenr);
+}
+
+NORETURN __attribute__((format(printf, 2, 3)))
+void git_die_config(const char *key, const char *err, ...)
+{
+       const struct string_list *values;
+       struct key_value_info *kv_info;
+
+       if (err) {
+               va_list params;
+               va_start(params, err);
+               vreportf("error: ", err, params);
+               va_end(params);
+       }
+       values = git_config_get_value_multi(key);
+       kv_info = values->items[values->nr - 1].util;
+       git_die_config_linenr(key, kv_info->filename, kv_info->linenr);
 }
 
 /*
@@ -1256,7 +1627,7 @@ static int store_aux(const char *key, const char *value, void *cb)
        case KEY_SEEN:
                if (matches(key, value)) {
                        if (store.seen == 1 && store.multi_replace == 0) {
-                               warning("%s has multiple values", key);
+                               warning(_("%s has multiple values"), key);
                        }
 
                        ALLOC_GROW(store.offset, store.seen + 1,
@@ -1724,6 +2095,9 @@ int git_config_set_multivar_in_file(const char *config_filename,
        lock = NULL;
        ret = 0;
 
+       /* Invalidate the config cache */
+       git_config_clear();
+
 out_free:
        if (lock)
                rollback_lock_file(lock);
index 15ee15e98c2cb232e1e42315dc44f7efd87b4f1c..a2f380fd8dbb852ceeb4933b1b942e0e4803f44a 100644 (file)
@@ -89,8 +89,13 @@ ifeq ($(uname_S),Darwin)
        NEEDS_CRYPTO_WITH_SSL = YesPlease
        NEEDS_SSL_WITH_CRYPTO = YesPlease
        NEEDS_LIBICONV = YesPlease
+       # Note: $(uname_R) gives us the underlying Darwin version.
+       # - MacOS 10.0.* and MacOS 10.1.0 = Darwin 1.*
+       # - MacOS 10.x.* = Darwin (x+4).* for (1 <= x)
+       # i.e. "begins with [15678] and a dot" means "10.4.* or older".
        ifeq ($(shell expr "$(uname_R)" : '[15678]\.'),2)
                OLD_ICONV = UnfortunatelyYes
+               NO_APPLE_COMMON_CRYPTO = YesPlease
        endif
        ifeq ($(shell expr "$(uname_R)" : '[15]\.'),2)
                NO_STRLCPY = YesPlease
index 4b1ae7c3c9f5ff5080dc026a6eb835d579d29949..6af964797f7b0ee64deb34bdff40b2a17db067b6 100644 (file)
@@ -746,6 +746,14 @@ case $ac_cv_type_socklen_t in
 esac
 GIT_CONF_SUBST([SOCKLEN_T])
 
+#
+# Define NO_STRUCT_ITIMERVAL if you don't have struct itimerval.
+AC_CHECK_TYPES([struct itimerval],
+[NO_STRUCT_ITIMERVAL=],
+[NO_STRUCT_ITIMERVAL=UnfortunatelyYes],
+[#include <sys/time.h>])
+GIT_CONF_SUBST([NO_STRUCT_ITIMERVAL])
+#
 # Define NO_D_INO_IN_DIRENT if you don't have d_ino in your struct dirent.
 AC_CHECK_MEMBER(struct dirent.d_ino,
 [NO_D_INO_IN_DIRENT=],
@@ -903,6 +911,12 @@ AC_CHECK_LIB([iconv], [locale_charset],
                      [CHARSET_LIB=-lcharset])])
 GIT_CONF_SUBST([CHARSET_LIB])
 #
+# Define NO_SETITIMER if you don't have setitimer.
+GIT_CHECK_FUNC(setitimer,
+[NO_SETITIMER=],
+[NO_SETITIMER=YesPlease])
+GIT_CONF_SUBST([NO_SETITIMER])
+#
 # Define NO_STRCASESTR if you don't have strcasestr.
 GIT_CHECK_FUNC(strcasestr,
 [NO_STRCASESTR=],
index 5047402a1aade7a443f55999550ae4542189ef01..d47d0ec6040fdb8b07a689e299dac121bb468717 100644 (file)
--- a/connect.c
+++ b/connect.c
 static char *server_capabilities;
 static const char *parse_feature_value(const char *, const char *, int *);
 
-static int check_ref(const char *name, int len, unsigned int flags)
+static int check_ref(const char *name, unsigned int flags)
 {
        if (!flags)
                return 1;
 
-       if (len < 5 || memcmp(name, "refs/", 5))
+       if (!skip_prefix(name, "refs/", &name))
                return 0;
 
-       /* Skip the "refs/" part */
-       name += 5;
-       len -= 5;
-
        /* REF_NORMAL means that we don't want the magic fake tag refs */
        if ((flags & REF_NORMAL) && check_refname_format(name, 0))
                return 0;
 
        /* REF_HEADS means that we want regular branch heads */
-       if ((flags & REF_HEADS) && !memcmp(name, "heads/", 6))
+       if ((flags & REF_HEADS) && starts_with(name, "heads/"))
                return 1;
 
        /* REF_TAGS means that we want tags */
-       if ((flags & REF_TAGS) && !memcmp(name, "tags/", 5))
+       if ((flags & REF_TAGS) && starts_with(name, "tags/"))
                return 1;
 
        /* All type bits clear means that we are ok with anything */
@@ -43,7 +39,7 @@ static int check_ref(const char *name, int len, unsigned int flags)
 
 int check_ref_type(const struct ref *ref, int flags)
 {
-       return check_ref(ref->name, strlen(ref->name), flags);
+       return check_ref(ref->name, flags);
 }
 
 static void die_initial_contact(int got_at_least_one_head)
@@ -167,7 +163,7 @@ struct ref **get_remote_heads(int in, char *src_buf, size_t src_len,
                        continue;
                }
 
-               if (!check_ref(name, name_len, flags))
+               if (!check_ref(name, flags))
                        continue;
                ref = alloc_ref(buffer + 41);
                hashcpy(ref->old_sha1, old_sha1);
@@ -537,7 +533,8 @@ static struct child_process *git_proxy_connect(int fd[2], char *host)
 
        get_host_and_port(&host, &port);
 
-       proxy = xcalloc(1, sizeof(*proxy));
+       proxy = xmalloc(sizeof(*proxy));
+       child_process_init(proxy);
        argv_array_push(&proxy->args, git_proxy_command);
        argv_array_push(&proxy->args, host);
        argv_array_push(&proxy->args, port);
@@ -639,7 +636,7 @@ static enum protocol parse_connect_url(const char *url_orig, char **ret_host,
        return protocol;
 }
 
-static struct child_process no_fork;
+static struct child_process no_fork = CHILD_PROCESS_INIT;
 
 /*
  * This returns a dummy child_process if the transport protocol does not
@@ -694,7 +691,8 @@ struct child_process *git_connect(int fd[2], const char *url,
                             target_host, 0);
                free(target_host);
        } else {
-               conn = xcalloc(1, sizeof(*conn));
+               conn = xmalloc(sizeof(*conn));
+               child_process_init(conn);
 
                strbuf_addstr(&cmd, prog);
                strbuf_addch(&cmd, ' ');
index dae9c9972eb3485bd20494efd78d09f1189667cb..299c56090bc38b1572b0ac03ec48532f40de605f 100644 (file)
@@ -25,7 +25,7 @@ static int check_everything_connected_real(sha1_iterate_fn fn,
                                           struct transport *transport,
                                           const char *shallow_file)
 {
-       struct child_process rev_list;
+       struct child_process rev_list = CHILD_PROCESS_INIT;
        const char *argv[9];
        char commit[41];
        unsigned char sha1[20];
@@ -60,7 +60,6 @@ static int check_everything_connected_real(sha1_iterate_fn fn,
                argv[ac++] = "--quiet";
        argv[ac] = NULL;
 
-       memset(&rev_list, 0, sizeof(rev_list));
        rev_list.argv = argv;
        rev_list.git_cmd = 1;
        rev_list.in = -1;
index 06bf262087768d98450cb589eb8f8fcc51ed2f74..5ea5b82d2b6c54111c059a1c844c6e9f0b3d3a79 100644 (file)
@@ -1175,8 +1175,8 @@ __git_diff_common_options="--stat --numstat --shortstat --summary
                        --full-index --binary --abbrev --diff-filter=
                        --find-copies-harder
                        --text --ignore-space-at-eol --ignore-space-change
-                       --ignore-all-space --exit-code --quiet --ext-diff
-                       --no-ext-diff
+                       --ignore-all-space --ignore-blank-lines --exit-code
+                       --quiet --ext-diff --no-ext-diff
                        --no-prefix --src-prefix= --dst-prefix=
                        --inter-hunk-context=
                        --patience --histogram --minimal
index d9a0ce2c6337b906617306f466139b5f486a753d..c2bd703ee3aa0fd734c71dc50c01085455d33773 100644 (file)
@@ -1,3 +1,6 @@
+# The default target of this Makefile is...
+all::
+
 -include ../../config.mak.autogen
 -include ../../config.mak
 
@@ -34,7 +37,7 @@ GIT_SUBTREE_XML := git-subtree.xml
 GIT_SUBTREE_TXT := git-subtree.txt
 GIT_SUBTREE_HTML := git-subtree.html
 
-all: $(GIT_SUBTREE)
+all:: $(GIT_SUBTREE)
 
 $(GIT_SUBTREE): $(GIT_SUBTREE_SH)
        sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' $< >$@
index 360d8da41754edf251b5441fcb89176ca3d4cda8..e8651aaf4b53218b9a2726a4a03595e05defc3c8 100644 (file)
@@ -1,18 +1,58 @@
 all:: svn-fe$X
 
-CC = gcc
+CC = cc
 RM = rm -f
 MV = mv
 
 CFLAGS = -g -O2 -Wall
 LDFLAGS =
-ALL_CFLAGS = $(CFLAGS)
-ALL_LDFLAGS = $(LDFLAGS)
-EXTLIBS =
+EXTLIBS = -lz
+
+include ../../config.mak.uname
+-include ../../config.mak.autogen
+-include ../../config.mak
+
+ifeq ($(uname_S),Darwin)
+       ifndef NO_FINK
+               ifeq ($(shell test -d /sw/lib && echo y),y)
+                       CFLAGS += -I/sw/include
+                       LDFLAGS += -L/sw/lib
+               endif
+       endif
+       ifndef NO_DARWIN_PORTS
+               ifeq ($(shell test -d /opt/local/lib && echo y),y)
+                       CFLAGS += -I/opt/local/include
+                       LDFLAGS += -L/opt/local/lib
+               endif
+       endif
+endif
+
+ifndef NO_OPENSSL
+       EXTLIBS += -lssl
+       ifdef NEEDS_CRYPTO_WITH_SSL
+               EXTLIBS += -lcrypto
+       endif
+endif
+
+ifndef NO_PTHREADS
+       CFLAGS += $(PTHREADS_CFLAGS)
+       EXTLIBS += $(PTHREAD_LIBS)
+endif
+
+ifdef HAVE_CLOCK_GETTIME
+       CFLAGS += -DHAVE_CLOCK_GETTIME
+       EXTLIBS += -lrt
+endif
+
+ifdef NEEDS_LIBICONV
+       EXTLIBS += -liconv
+endif
 
 GIT_LIB = ../../libgit.a
 VCSSVN_LIB = ../../vcs-svn/lib.a
-LIBS = $(VCSSVN_LIB) $(GIT_LIB) $(EXTLIBS)
+XDIFF_LIB = ../../xdiff/lib.a
+
+LIBS = $(VCSSVN_LIB) $(GIT_LIB) $(XDIFF_LIB)
 
 QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
 QUIET_SUBDIR1 =
@@ -33,12 +73,11 @@ ifndef V
 endif
 endif
 
-svn-fe$X: svn-fe.o $(VCSSVN_LIB) $(GIT_LIB)
-       $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ svn-fe.o \
-               $(ALL_LDFLAGS) $(LIBS)
+svn-fe$X: svn-fe.o $(VCSSVN_LIB) $(XDIFF_LIB) $(GIT_LIB)
+       $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(EXTLIBS) -o $@ svn-fe.o $(LIBS)
 
 svn-fe.o: svn-fe.c ../../vcs-svn/svndump.h
-       $(QUIET_CC)$(CC) -I../../vcs-svn -o $*.o -c $(ALL_CFLAGS) $<
+       $(QUIET_CC)$(CC) $(CFLAGS) -I../../vcs-svn -o $*.o -c $<
 
 svn-fe.html: svn-fe.txt
        $(QUIET_SUBDIR0)../../Documentation $(QUIET_SUBDIR1) \
@@ -54,6 +93,9 @@ svn-fe.1: svn-fe.txt
 ../../vcs-svn/lib.a: FORCE
        $(QUIET_SUBDIR0)../.. $(QUIET_SUBDIR1) vcs-svn/lib.a
 
+../../xdiff/lib.a: FORCE
+       $(QUIET_SUBDIR0)../.. $(QUIET_SUBDIR1) xdiff/lib.a
+
 ../../libgit.a: FORCE
        $(QUIET_SUBDIR0)../.. $(QUIET_SUBDIR1) libgit.a
 
index cb5fbb45ea04cead65316ecf6b44730b17108122..aa7a139bcf7f3d33511e106545e6d8989a0ffe35 100644 (file)
--- a/convert.c
+++ b/convert.c
@@ -321,7 +321,7 @@ static int filter_buffer(int in, int out, void *data)
        /*
         * Spawn cmd and feed the buffer contents through its stdin.
         */
-       struct child_process child_process;
+       struct child_process child_process = CHILD_PROCESS_INIT;
        struct filter_params *params = (struct filter_params *)data;
        int write_err, status;
        const char *argv[] = { NULL, NULL };
@@ -344,7 +344,6 @@ static int filter_buffer(int in, int out, void *data)
 
        argv[0] = cmd.buf;
 
-       memset(&child_process, 0, sizeof(child_process));
        child_process.argv = argv;
        child_process.use_shell = 1;
        child_process.in = -1;
index 3b370ca5e529c74e17e0f39da5c689ebc4ccfc25..c2f00498f6a171ecde3dd91a5cbdb30d88827495 100644 (file)
@@ -2,6 +2,7 @@
 #include "credential.h"
 #include "unix-socket.h"
 #include "sigchain.h"
+#include "parse-options.h"
 
 static const char *socket_path;
 
@@ -201,7 +202,7 @@ static int serve_cache_loop(int fd)
        return 1;
 }
 
-static void serve_cache(const char *socket_path)
+static void serve_cache(const char *socket_path, int debug)
 {
        int fd;
 
@@ -211,6 +212,10 @@ static void serve_cache(const char *socket_path)
 
        printf("ok\n");
        fclose(stdout);
+       if (!debug) {
+               if (!freopen("/dev/null", "w", stderr))
+                       die_errno("unable to point stderr to /dev/null");
+       }
 
        while (serve_cache_loop(fd))
                ; /* nothing */
@@ -252,16 +257,28 @@ static void check_socket_directory(const char *path)
 
 int main(int argc, const char **argv)
 {
-       socket_path = argv[1];
+       static const char *usage[] = {
+               "git-credential-cache--daemon [opts] <socket_path>",
+               NULL
+       };
+       int debug = 0;
+       const struct option options[] = {
+               OPT_BOOL(0, "debug", &debug,
+                        N_("print debugging messages to stderr")),
+               OPT_END()
+       };
+
+       argc = parse_options(argc, argv, NULL, options, usage, 0);
+       socket_path = argv[0];
 
        if (!socket_path)
-               die("usage: git-credential-cache--daemon <socket_path>");
+               usage_with_options(usage, options);
        check_socket_directory(socket_path);
 
        atexit(cleanup_socket);
        sigchain_push_common(cleanup_socket_on_signal);
 
-       serve_cache(socket_path);
+       serve_cache(socket_path, debug);
 
        return 0;
 }
index 9a03792c7de109e957a1f01924c4f66ba87b5c87..8689a1519a5635a1d92e9e4106936b4159d2e106 100644 (file)
@@ -37,12 +37,11 @@ static int send_request(const char *socket, const struct strbuf *out)
 
 static void spawn_daemon(const char *socket)
 {
-       struct child_process daemon;
+       struct child_process daemon = CHILD_PROCESS_INIT;
        const char *argv[] = { NULL, NULL, NULL };
        char buf[128];
        int r;
 
-       memset(&daemon, 0, sizeof(daemon));
        argv[0] = "git-credential-cache--daemon";
        argv[1] = socket;
        daemon.argv = argv;
index 4d79d320f89e956aa9233a170120f05b2473ca59..1886ea50b3b3c2a213e34876de691fa3d0a83b6c 100644 (file)
@@ -205,11 +205,10 @@ static int run_credential_helper(struct credential *c,
                                 const char *cmd,
                                 int want_output)
 {
-       struct child_process helper;
+       struct child_process helper = CHILD_PROCESS_INIT;
        const char *argv[] = { NULL, NULL };
        FILE *fp;
 
-       memset(&helper, 0, sizeof(helper));
        argv[0] = cmd;
        helper.argv = argv;
        helper.use_shell = 1;
index e6b51ed9981f2e4084504a2a092a3f28fc7d4c8a..4dcfff9352c8d034bfaec4efa0c36df41e7813a7 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -230,23 +230,6 @@ struct daemon_service {
        int overridable;
 };
 
-static struct daemon_service *service_looking_at;
-static int service_enabled;
-
-static int git_daemon_config(const char *var, const char *value, void *cb)
-{
-       const char *service;
-
-       if (skip_prefix(var, "daemon.", &service) &&
-           !strcmp(service, service_looking_at->config_name)) {
-               service_enabled = git_config_bool(var, value);
-               return 0;
-       }
-
-       /* we are not interested in parsing any other configuration here */
-       return 0;
-}
-
 static int daemon_error(const char *dir, const char *msg)
 {
        if (!informative_errors)
@@ -259,7 +242,7 @@ static const char *access_hook;
 
 static int run_access_hook(struct daemon_service *service, const char *dir, const char *path)
 {
-       struct child_process child;
+       struct child_process child = CHILD_PROCESS_INIT;
        struct strbuf buf = STRBUF_INIT;
        const char *argv[8];
        const char **arg = argv;
@@ -277,7 +260,6 @@ static int run_access_hook(struct daemon_service *service, const char *dir, cons
        *arg = NULL;
 #undef STRARG
 
-       memset(&child, 0, sizeof(child));
        child.use_shell = 1;
        child.argv = argv;
        child.no_stdin = 1;
@@ -324,6 +306,7 @@ static int run_service(const char *dir, struct daemon_service *service)
 {
        const char *path;
        int enabled = service->enabled;
+       struct strbuf var = STRBUF_INIT;
 
        loginfo("Request %s for '%s'", service->name, dir);
 
@@ -354,11 +337,9 @@ static int run_service(const char *dir, struct daemon_service *service)
        }
 
        if (service->overridable) {
-               service_looking_at = service;
-               service_enabled = -1;
-               git_config(git_daemon_config, NULL);
-               if (0 <= service_enabled)
-                       enabled = service_enabled;
+               strbuf_addf(&var, "daemon.%s", service->config_name);
+               git_config_get_bool(var.buf, &enabled);
+               strbuf_release(&var);
        }
        if (!enabled) {
                logerror("'%s': service not enabled for '%s'",
@@ -406,9 +387,8 @@ static void copy_to_log(int fd)
 
 static int run_service_command(const char **argv)
 {
-       struct child_process cld;
+       struct child_process cld = CHILD_PROCESS_INIT;
 
-       memset(&cld, 0, sizeof(cld));
        cld.argv = argv;
        cld.git_cmd = 1;
        cld.err = -1;
@@ -733,7 +713,7 @@ static void check_dead_children(void)
 static char **cld_argv;
 static void handle(int incoming, struct sockaddr *addr, socklen_t addrlen)
 {
-       struct child_process cld = { NULL };
+       struct child_process cld = CHILD_PROCESS_INIT;
        char addrbuf[300] = "REMOTE_ADDR=", portbuf[300];
        char *env[] = { addrbuf, portbuf, NULL };
 
diff --git a/date.c b/date.c
index 782de95d90c6ac1a02ddfa0df81ca93ecdf910c4..59dfe579c6a0c65abe0a34052cdbf16643afbfb8 100644 (file)
--- a/date.c
+++ b/date.c
@@ -200,7 +200,16 @@ const char *show_date(unsigned long time, int tz, enum date_mode mode)
                                tm->tm_mday,
                                tm->tm_hour, tm->tm_min, tm->tm_sec,
                                tz);
-       else if (mode == DATE_RFC2822)
+       else if (mode == DATE_ISO8601_STRICT) {
+               char sign = (tz >= 0) ? '+' : '-';
+               tz = abs(tz);
+               strbuf_addf(&timebuf, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
+                               tm->tm_year + 1900,
+                               tm->tm_mon + 1,
+                               tm->tm_mday,
+                               tm->tm_hour, tm->tm_min, tm->tm_sec,
+                               sign, tz / 100, tz % 100);
+       } else if (mode == DATE_RFC2822)
                strbuf_addf(&timebuf, "%.3s, %d %.3s %d %02d:%02d:%02d %+05d",
                        weekday_names[tm->tm_wday], tm->tm_mday,
                        month_names[tm->tm_mon], tm->tm_year + 1900,
@@ -605,7 +614,7 @@ static int match_tz(const char *date, int *offp)
        return end - date;
 }
 
-static int date_string(unsigned long date, int offset, char *buf, int len)
+static void date_string(unsigned long date, int offset, struct strbuf *buf)
 {
        int sign = '+';
 
@@ -613,7 +622,7 @@ static int date_string(unsigned long date, int offset, char *buf, int len)
                offset = -offset;
                sign = '-';
        }
-       return snprintf(buf, len, "%lu %c%02d%02d", date, sign, offset / 60, offset % 60);
+       strbuf_addf(buf, "%lu %c%02d%02d", date, sign, offset / 60, offset % 60);
 }
 
 /*
@@ -735,13 +744,14 @@ int parse_expiry_date(const char *date, unsigned long *timestamp)
        return errors;
 }
 
-int parse_date(const char *date, char *result, int maxlen)
+int parse_date(const char *date, struct strbuf *result)
 {
        unsigned long timestamp;
        int offset;
        if (parse_date_basic(date, &timestamp, &offset))
                return -1;
-       return date_string(timestamp, offset, result, maxlen);
+       date_string(timestamp, offset, result);
+       return 0;
 }
 
 enum date_mode parse_date_format(const char *format)
@@ -751,6 +761,9 @@ enum date_mode parse_date_format(const char *format)
        else if (!strcmp(format, "iso8601") ||
                 !strcmp(format, "iso"))
                return DATE_ISO8601;
+       else if (!strcmp(format, "iso8601-strict") ||
+                !strcmp(format, "iso-strict"))
+               return DATE_ISO8601_STRICT;
        else if (!strcmp(format, "rfc2822") ||
                 !strcmp(format, "rfc"))
                return DATE_RFC2822;
@@ -766,7 +779,7 @@ enum date_mode parse_date_format(const char *format)
                die("unknown date format %s", format);
 }
 
-void datestamp(char *buf, int bufsize)
+void datestamp(struct strbuf *out)
 {
        time_t now;
        int offset;
@@ -776,7 +789,7 @@ void datestamp(char *buf, int bufsize)
        offset = tm_to_time_t(localtime(&now)) - now;
        offset /= 60;
 
-       date_string(now, offset, buf, bufsize);
+       date_string(now, offset, out);
 }
 
 /*
diff --git a/diff.c b/diff.c
index 867f034b8ffc052d28f28a86fd9f52a5aa5b2c82..d7a5c81bb8545584ce5fe652dc42f2ee8bc1e2fd 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -376,7 +376,7 @@ static unsigned long diff_filespec_size(struct diff_filespec *one)
 {
        if (!DIFF_FILE_VALID(one))
                return 0;
-       diff_populate_filespec(one, 1);
+       diff_populate_filespec(one, CHECK_SIZE_ONLY);
        return one->size;
 }
 
@@ -1910,11 +1910,11 @@ static void show_dirstat(struct diff_options *options)
                        diff_free_filespec_data(p->one);
                        diff_free_filespec_data(p->two);
                } else if (DIFF_FILE_VALID(p->one)) {
-                       diff_populate_filespec(p->one, 1);
+                       diff_populate_filespec(p->one, CHECK_SIZE_ONLY);
                        copied = added = 0;
                        diff_free_filespec_data(p->one);
                } else if (DIFF_FILE_VALID(p->two)) {
-                       diff_populate_filespec(p->two, 1);
+                       diff_populate_filespec(p->two, CHECK_SIZE_ONLY);
                        copied = 0;
                        added = p->two->size;
                        diff_free_filespec_data(p->two);
@@ -2188,8 +2188,8 @@ int diff_filespec_is_binary(struct diff_filespec *one)
                        one->is_binary = one->driver->binary;
                else {
                        if (!one->data && DIFF_FILE_VALID(one))
-                               diff_populate_filespec(one, 0);
-                       if (one->data)
+                               diff_populate_filespec(one, CHECK_BINARY);
+                       if (one->is_binary == -1 && one->data)
                                one->is_binary = buffer_is_binary(one->data,
                                                one->size);
                        if (one->is_binary == -1)
@@ -2324,6 +2324,19 @@ static void builtin_diff(const char *name_a,
        } else if (!DIFF_OPT_TST(o, TEXT) &&
            ( (!textconv_one && diff_filespec_is_binary(one)) ||
              (!textconv_two && diff_filespec_is_binary(two)) )) {
+               if (!one->data && !two->data &&
+                   S_ISREG(one->mode) && S_ISREG(two->mode) &&
+                   !DIFF_OPT_TST(o, BINARY)) {
+                       if (!hashcmp(one->sha1, two->sha1)) {
+                               if (must_show_header)
+                                       fprintf(o->file, "%s", header.buf);
+                               goto free_ab_and_return;
+                       }
+                       fprintf(o->file, "%s", header.buf);
+                       fprintf(o->file, "%sBinary files %s and %s differ\n",
+                               line_prefix, lbl[0], lbl[1]);
+                       goto free_ab_and_return;
+               }
                if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
                        die("unable to read files to diff");
                /* Quite common confusing case */
@@ -2668,8 +2681,9 @@ static int diff_populate_gitlink(struct diff_filespec *s, int size_only)
  * grab the data for the blob (or file) for our own in-core comparison.
  * diff_filespec has data and size fields for this purpose.
  */
-int diff_populate_filespec(struct diff_filespec *s, int size_only)
+int diff_populate_filespec(struct diff_filespec *s, unsigned int flags)
 {
+       int size_only = flags & CHECK_SIZE_ONLY;
        int err = 0;
        /*
         * demote FAIL to WARN to allow inspecting the situation
@@ -2724,6 +2738,11 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
                }
                if (size_only)
                        return 0;
+               if ((flags & CHECK_BINARY) &&
+                   s->size > big_file_threshold && s->is_binary == -1) {
+                       s->is_binary = 1;
+                       return 0;
+               }
                fd = open(s->path, O_RDONLY);
                if (fd < 0)
                        goto err_empty;
@@ -2745,16 +2764,21 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
        }
        else {
                enum object_type type;
-               if (size_only) {
+               if (size_only || (flags & CHECK_BINARY)) {
                        type = sha1_object_info(s->sha1, &s->size);
                        if (type < 0)
                                die("unable to read %s", sha1_to_hex(s->sha1));
-               } else {
-                       s->data = read_sha1_file(s->sha1, &type, &s->size);
-                       if (!s->data)
-                               die("unable to read %s", sha1_to_hex(s->sha1));
-                       s->should_free = 1;
+                       if (size_only)
+                               return 0;
+                       if (s->size > big_file_threshold && s->is_binary == -1) {
+                               s->is_binary = 1;
+                               return 0;
+                       }
                }
+               s->data = read_sha1_file(s->sha1, &type, &s->size);
+               if (!s->data)
+                       die("unable to read %s", sha1_to_hex(s->sha1));
+               s->should_free = 1;
        }
        return 0;
 }
@@ -4688,8 +4712,8 @@ static int diff_filespec_check_stat_unmatch(struct diff_filepair *p)
            !DIFF_FILE_VALID(p->two) ||
            (p->one->sha1_valid && p->two->sha1_valid) ||
            (p->one->mode != p->two->mode) ||
-           diff_populate_filespec(p->one, 1) ||
-           diff_populate_filespec(p->two, 1) ||
+           diff_populate_filespec(p->one, CHECK_SIZE_ONLY) ||
+           diff_populate_filespec(p->two, CHECK_SIZE_ONLY) ||
            (p->one->size != p->two->size) ||
            !diff_filespec_is_identical(p->one, p->two)) /* (2) */
                p->skip_stat_unmatch_result = 1;
@@ -4931,7 +4955,7 @@ static char *run_textconv(const char *pgm, struct diff_filespec *spec,
        struct diff_tempfile *temp;
        const char *argv[3];
        const char **arg = argv;
-       struct child_process child;
+       struct child_process child = CHILD_PROCESS_INIT;
        struct strbuf buf = STRBUF_INIT;
        int err = 0;
 
@@ -4940,7 +4964,6 @@ static char *run_textconv(const char *pgm, struct diff_filespec *spec,
        *arg++ = temp->name;
        *arg = NULL;
 
-       memset(&child, 0, sizeof(child));
        child.use_shell = 1;
        child.argv = argv;
        child.out = -1;
index 2e44a3745939bb75841730ba0cff78ea872df8d9..4e132f1fdb68ed3c930ca8224a5403c9b406cc3b 100644 (file)
@@ -147,9 +147,11 @@ static int estimate_similarity(struct diff_filespec *src,
         * is a possible size - we really should have a flag to
         * say whether the size is valid or not!)
         */
-       if (!src->cnt_data && diff_populate_filespec(src, 1))
+       if (!src->cnt_data &&
+           diff_populate_filespec(src, CHECK_SIZE_ONLY))
                return 0;
-       if (!dst->cnt_data && diff_populate_filespec(dst, 1))
+       if (!dst->cnt_data &&
+           diff_populate_filespec(dst, CHECK_SIZE_ONLY))
                return 0;
 
        max_size = ((src->size > dst->size) ? src->size : dst->size);
index c876dac71a585abb1e138444eb28258e3bf6d7e8..33ea2de348803b29a08a6713ae4cab1345f874d9 100644 (file)
@@ -55,7 +55,9 @@ extern void free_filespec(struct diff_filespec *);
 extern void fill_filespec(struct diff_filespec *, const unsigned char *,
                          int, unsigned short);
 
-extern int diff_populate_filespec(struct diff_filespec *, int);
+#define CHECK_SIZE_ONLY 1
+#define CHECK_BINARY    2
+extern int diff_populate_filespec(struct diff_filespec *, unsigned int);
 extern void diff_free_filespec_data(struct diff_filespec *);
 extern void diff_free_filespec_blob(struct diff_filespec *);
 extern int diff_filespec_is_binary(struct diff_filespec *);
diff --git a/dir.c b/dir.c
index fcb68729b1f559008e1797ff50f38acf81268d3d..bd274a73f1faaee40bce34024ef17bfd44fbcad7 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -1507,12 +1507,16 @@ int dir_inside_of(const char *subdir, const char *dir)
 
 int is_inside_dir(const char *dir)
 {
-       char cwd[PATH_MAX];
+       char *cwd;
+       int rc;
+
        if (!dir)
                return 0;
-       if (!getcwd(cwd, sizeof(cwd)))
-               die_errno("can't find the current directory");
-       return dir_inside_of(cwd, dir) >= 0;
+
+       cwd = xgetcwd();
+       rc = (dir_inside_of(cwd, dir) >= 0);
+       free(cwd);
+       return rc;
 }
 
 int is_empty_dir(const char *path)
index 0abbd8dc3a0ec91acd0c143b6d9b5ad41ac90417..01c644cddbe8e57e31cc711aa0ca3838cf23c64d 100644 (file)
--- a/editor.c
+++ b/editor.c
@@ -38,10 +38,9 @@ int launch_editor(const char *path, struct strbuf *buffer, const char *const *en
 
        if (strcmp(editor, ":")) {
                const char *args[] = { editor, real_path(path), NULL };
-               struct child_process p;
+               struct child_process p = CHILD_PROCESS_INIT;
                int ret, sig;
 
-               memset(&p, 0, sizeof(p));
                p.argv = args;
                p.env = env;
                p.use_shell = 1;
index 125fa6fabf503d29cb82b2ccbc92359abf95b0e8..698e7526c40749fd333367018c192537cf6b4562 100644 (file)
@@ -86,11 +86,7 @@ const char *git_exec_path(void)
 static void add_path(struct strbuf *out, const char *path)
 {
        if (path && *path) {
-               if (is_absolute_path(path))
-                       strbuf_addstr(out, path);
-               else
-                       strbuf_addstr(out, absolute_path(path));
-
+               strbuf_add_absolute_path(out, path);
                strbuf_addch(out, PATH_SEP);
        }
 }
index a40b4ea2d0447e5369efafa9943e1e46a28cc477..96b0f4236a2083044e4ae1dfa3b8180e3e586ba1 100644 (file)
@@ -878,7 +878,7 @@ static void start_packfile(void)
        pack_size = sizeof(hdr);
        object_count = 0;
 
-       all_packs = xrealloc(all_packs, sizeof(*all_packs) * (pack_id + 1));
+       REALLOC_ARRAY(all_packs, pack_id + 1);
        all_packs[pack_id] = p;
 }
 
@@ -1686,8 +1686,9 @@ found_entry:
 static int update_branch(struct branch *b)
 {
        static const char *msg = "fast-import";
-       struct ref_lock *lock;
+       struct ref_transaction *transaction;
        unsigned char old_sha1[20];
+       struct strbuf err = STRBUF_INIT;
 
        if (read_ref(b->name, old_sha1))
                hashclr(old_sha1);
@@ -1696,29 +1697,33 @@ static int update_branch(struct branch *b)
                        delete_ref(b->name, old_sha1, 0);
                return 0;
        }
-       lock = lock_any_ref_for_update(b->name, old_sha1, 0, NULL);
-       if (!lock)
-               return error("Unable to lock %s", b->name);
        if (!force_update && !is_null_sha1(old_sha1)) {
                struct commit *old_cmit, *new_cmit;
 
                old_cmit = lookup_commit_reference_gently(old_sha1, 0);
                new_cmit = lookup_commit_reference_gently(b->sha1, 0);
-               if (!old_cmit || !new_cmit) {
-                       unlock_ref(lock);
+               if (!old_cmit || !new_cmit)
                        return error("Branch %s is missing commits.", b->name);
-               }
 
                if (!in_merge_bases(old_cmit, new_cmit)) {
-                       unlock_ref(lock);
                        warning("Not updating %s"
                                " (new tip %s does not contain %s)",
                                b->name, sha1_to_hex(b->sha1), sha1_to_hex(old_sha1));
                        return -1;
                }
        }
-       if (write_ref_sha1(lock, b->sha1, msg) < 0)
-               return error("Unable to update %s", b->name);
+       transaction = ref_transaction_begin(&err);
+       if (!transaction ||
+           ref_transaction_update(transaction, b->name, b->sha1, old_sha1,
+                                  0, 1, &err) ||
+           ref_transaction_commit(transaction, msg, &err)) {
+               ref_transaction_free(transaction);
+               error("%s", err.buf);
+               strbuf_release(&err);
+               return -1;
+       }
+       ref_transaction_free(transaction);
+       strbuf_release(&err);
        return 0;
 }
 
@@ -1737,17 +1742,32 @@ static void dump_tags(void)
 {
        static const char *msg = "fast-import";
        struct tag *t;
-       struct ref_lock *lock;
        struct strbuf ref_name = STRBUF_INIT;
+       struct strbuf err = STRBUF_INIT;
+       struct ref_transaction *transaction;
 
+       transaction = ref_transaction_begin(&err);
+       if (!transaction) {
+               failure |= error("%s", err.buf);
+               goto cleanup;
+       }
        for (t = first_tag; t; t = t->next_tag) {
                strbuf_reset(&ref_name);
-               strbuf_addf(&ref_name, "tags/%s", t->name);
-               lock = lock_ref_sha1(ref_name.buf, NULL);
-               if (!lock || write_ref_sha1(lock, t->sha1, msg) < 0)
-                       failure |= error("Unable to update %s", ref_name.buf);
+               strbuf_addf(&ref_name, "refs/tags/%s", t->name);
+
+               if (ref_transaction_update(transaction, ref_name.buf, t->sha1,
+                                          NULL, 0, 0, &err)) {
+                       failure |= error("%s", err.buf);
+                       goto cleanup;
+               }
        }
+       if (ref_transaction_commit(transaction, msg, &err))
+               failure |= error("%s", err.buf);
+
+ cleanup:
+       ref_transaction_free(transaction);
        strbuf_release(&ref_name);
+       strbuf_release(&err);
 }
 
 static void dump_marks_helper(FILE *f,
@@ -1980,7 +2000,7 @@ static int parse_data(struct strbuf *sb, uintmax_t limit, uintmax_t *len_res)
        return 1;
 }
 
-static int validate_raw_date(const char *src, char *result, int maxlen)
+static int validate_raw_date(const char *src, struct strbuf *result)
 {
        const char *orig_src = src;
        char *endp;
@@ -1998,11 +2018,10 @@ static int validate_raw_date(const char *src, char *result, int maxlen)
                return -1;
 
        num = strtoul(src + 1, &endp, 10);
-       if (errno || endp == src + 1 || *endp || (endp - orig_src) >= maxlen ||
-           1400 < num)
+       if (errno || endp == src + 1 || *endp || 1400 < num)
                return -1;
 
-       strcpy(result, orig_src);
+       strbuf_addstr(result, orig_src);
        return 0;
 }
 
@@ -2010,7 +2029,7 @@ static char *parse_ident(const char *buf)
 {
        const char *ltgt;
        size_t name_len;
-       char *ident;
+       struct strbuf ident = STRBUF_INIT;
 
        /* ensure there is a space delimiter even if there is no name */
        if (*buf == '<')
@@ -2029,26 +2048,25 @@ static char *parse_ident(const char *buf)
                die("Missing space after > in ident string: %s", buf);
        ltgt++;
        name_len = ltgt - buf;
-       ident = xmalloc(name_len + 24);
-       strncpy(ident, buf, name_len);
+       strbuf_add(&ident, buf, name_len);
 
        switch (whenspec) {
        case WHENSPEC_RAW:
-               if (validate_raw_date(ltgt, ident + name_len, 24) < 0)
+               if (validate_raw_date(ltgt, &ident) < 0)
                        die("Invalid raw date \"%s\" in ident: %s", ltgt, buf);
                break;
        case WHENSPEC_RFC2822:
-               if (parse_date(ltgt, ident + name_len, 24) < 0)
+               if (parse_date(ltgt, &ident) < 0)
                        die("Invalid rfc2822 date \"%s\" in ident: %s", ltgt, buf);
                break;
        case WHENSPEC_NOW:
                if (strcmp("now", ltgt))
                        die("Date in ident must be 'now': %s", buf);
-               datestamp(ident + name_len, 24);
+               datestamp(&ident);
                break;
        }
 
-       return ident;
+       return strbuf_detach(&ident, NULL);
 }
 
 static void parse_and_store_blob(
@@ -3283,36 +3301,34 @@ static void parse_option(const char *option)
        die("This version of fast-import does not support option: %s", option);
 }
 
-static int git_pack_config(const char *k, const char *v, void *cb)
+static void git_pack_config(void)
 {
-       if (!strcmp(k, "pack.depth")) {
-               max_depth = git_config_int(k, v);
+       int indexversion_value;
+       unsigned long packsizelimit_value;
+
+       if (!git_config_get_ulong("pack.depth", &max_depth)) {
                if (max_depth > MAX_DEPTH)
                        max_depth = MAX_DEPTH;
-               return 0;
        }
-       if (!strcmp(k, "pack.compression")) {
-               int level = git_config_int(k, v);
-               if (level == -1)
-                       level = Z_DEFAULT_COMPRESSION;
-               else if (level < 0 || level > Z_BEST_COMPRESSION)
-                       die("bad pack compression level %d", level);
-               pack_compression_level = level;
+       if (!git_config_get_int("pack.compression", &pack_compression_level)) {
+               if (pack_compression_level == -1)
+                       pack_compression_level = Z_DEFAULT_COMPRESSION;
+               else if (pack_compression_level < 0 ||
+                        pack_compression_level > Z_BEST_COMPRESSION)
+                       git_die_config("pack.compression",
+                                       "bad pack compression level %d", pack_compression_level);
                pack_compression_seen = 1;
-               return 0;
        }
-       if (!strcmp(k, "pack.indexversion")) {
-               pack_idx_opts.version = git_config_int(k, v);
+       if (!git_config_get_int("pack.indexversion", &indexversion_value)) {
+               pack_idx_opts.version = indexversion_value;
                if (pack_idx_opts.version > 2)
-                       die("bad pack.indexversion=%"PRIu32,
-                           pack_idx_opts.version);
-               return 0;
+                       git_die_config("pack.indexversion",
+                                       "bad pack.indexversion=%"PRIu32, pack_idx_opts.version);
        }
-       if (!strcmp(k, "pack.packsizelimit")) {
-               max_packsize = git_config_ulong(k, v);
-               return 0;
-       }
-       return git_default_config(k, v, cb);
+       if (!git_config_get_ulong("pack.packsizelimit", &packsizelimit_value))
+               max_packsize = packsizelimit_value;
+
+       git_config(git_default_config, NULL);
 }
 
 static const char fast_import_usage[] =
@@ -3365,7 +3381,7 @@ int main(int argc, char **argv)
 
        setup_git_directory();
        reset_pack_idx_option(&pack_idx_opts);
-       git_config(git_pack_config, NULL);
+       git_pack_config();
        if (!pack_compression_seen && core_compression_seen)
                pack_compression_level = core_compression_level;
 
index b8a58fa7a542fe166ad71c9b17a4908c81d24a4f..7487aa730630e8b45874e3487db8e71c05e1968c 100644 (file)
@@ -666,7 +666,7 @@ static int get_pack(struct fetch_pack_args *args,
        char hdr_arg[256];
        const char **av, *cmd_name;
        int do_keep = args->keep_pack;
-       struct child_process cmd;
+       struct child_process cmd = CHILD_PROCESS_INIT;
        int ret;
 
        memset(&demux, 0, sizeof(demux));
@@ -685,7 +685,6 @@ static int get_pack(struct fetch_pack_args *args,
        else
                demux.out = xd[0];
 
-       memset(&cmd, 0, sizeof(cmd));
        cmd.argv = argv;
        av = argv;
        *hdr_arg = 0;
@@ -869,34 +868,15 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
        return ref;
 }
 
-static int fetch_pack_config(const char *var, const char *value, void *cb)
+static void fetch_pack_config(void)
 {
-       if (strcmp(var, "fetch.unpacklimit") == 0) {
-               fetch_unpack_limit = git_config_int(var, value);
-               return 0;
-       }
-
-       if (strcmp(var, "transfer.unpacklimit") == 0) {
-               transfer_unpack_limit = git_config_int(var, value);
-               return 0;
-       }
-
-       if (strcmp(var, "repack.usedeltabaseoffset") == 0) {
-               prefer_ofs_delta = git_config_bool(var, value);
-               return 0;
-       }
-
-       if (!strcmp(var, "fetch.fsckobjects")) {
-               fetch_fsck_objects = git_config_bool(var, value);
-               return 0;
-       }
-
-       if (!strcmp(var, "transfer.fsckobjects")) {
-               transfer_fsck_objects = git_config_bool(var, value);
-               return 0;
-       }
+       git_config_get_int("fetch.unpacklimit", &fetch_unpack_limit);
+       git_config_get_int("transfer.unpacklimit", &transfer_unpack_limit);
+       git_config_get_bool("repack.usedeltabaseoffset", &prefer_ofs_delta);
+       git_config_get_bool("fetch.fsckobjects", &fetch_fsck_objects);
+       git_config_get_bool("transfer.fsckobjects", &transfer_fsck_objects);
 
-       return git_default_config(var, value, cb);
+       git_config(git_default_config, NULL);
 }
 
 static void fetch_pack_setup(void)
@@ -904,7 +884,7 @@ static void fetch_pack_setup(void)
        static int did_setup;
        if (did_setup)
                return;
-       git_config(fetch_pack_config, NULL);
+       fetch_pack_config();
        if (0 <= transfer_unpack_limit)
                unpack_limit = transfer_unpack_limit;
        else if (0 <= fetch_unpack_limit)
diff --git a/fsck.c b/fsck.c
index 56156fff44a3556e2fa0b691ab103612a4678a3e..2fffa434a5763abb6d7895ee8c7582307766ee62 100644 (file)
--- a/fsck.c
+++ b/fsck.c
@@ -6,6 +6,7 @@
 #include "commit.h"
 #include "tag.h"
 #include "fsck.h"
+#include "refs.h"
 
 static int fsck_walk_tree(struct tree *tree, fsck_walk_func walk, void *data)
 {
@@ -237,6 +238,26 @@ static int fsck_tree(struct tree *item, int strict, fsck_error error_func)
        return retval;
 }
 
+static int require_end_of_header(const void *data, unsigned long size,
+       struct object *obj, fsck_error error_func)
+{
+       const char *buffer = (const char *)data;
+       unsigned long i;
+
+       for (i = 0; i < size; i++) {
+               switch (buffer[i]) {
+               case '\0':
+                       return error_func(obj, FSCK_ERROR,
+                               "unterminated header: NUL at offset %d", i);
+               case '\n':
+                       if (i + 1 < size && buffer[i + 1] == '\n')
+                               return 0;
+               }
+       }
+
+       return error_func(obj, FSCK_ERROR, "unterminated header");
+}
+
 static int fsck_ident(const char **ident, struct object *obj, fsck_error error_func)
 {
        char *end;
@@ -277,13 +298,16 @@ static int fsck_ident(const char **ident, struct object *obj, fsck_error error_f
 }
 
 static int fsck_commit_buffer(struct commit *commit, const char *buffer,
-                             fsck_error error_func)
+       unsigned long size, fsck_error error_func)
 {
        unsigned char tree_sha1[20], sha1[20];
        struct commit_graft *graft;
        unsigned parent_count, parent_line_count = 0;
        int err;
 
+       if (require_end_of_header(buffer, size, &commit->object, error_func))
+               return -1;
+
        if (!skip_prefix(buffer, "tree ", &buffer))
                return error_func(&commit->object, FSCK_ERROR, "invalid format - expected 'tree' line");
        if (get_sha1_hex(buffer, tree_sha1) || buffer[40] != '\n')
@@ -322,24 +346,111 @@ static int fsck_commit_buffer(struct commit *commit, const char *buffer,
        return 0;
 }
 
-static int fsck_commit(struct commit *commit, fsck_error error_func)
+static int fsck_commit(struct commit *commit, const char *data,
+       unsigned long size, fsck_error error_func)
 {
-       const char *buffer = get_commit_buffer(commit, NULL);
-       int ret = fsck_commit_buffer(commit, buffer, error_func);
-       unuse_commit_buffer(commit, buffer);
+       const char *buffer = data ?  data : get_commit_buffer(commit, &size);
+       int ret = fsck_commit_buffer(commit, buffer, size, error_func);
+       if (!data)
+               unuse_commit_buffer(commit, buffer);
        return ret;
 }
 
-static int fsck_tag(struct tag *tag, fsck_error error_func)
+static int fsck_tag_buffer(struct tag *tag, const char *data,
+       unsigned long size, fsck_error error_func)
+{
+       unsigned char sha1[20];
+       int ret = 0;
+       const char *buffer;
+       char *to_free = NULL, *eol;
+       struct strbuf sb = STRBUF_INIT;
+
+       if (data)
+               buffer = data;
+       else {
+               enum object_type type;
+
+               buffer = to_free =
+                       read_sha1_file(tag->object.sha1, &type, &size);
+               if (!buffer)
+                       return error_func(&tag->object, FSCK_ERROR,
+                               "cannot read tag object");
+
+               if (type != OBJ_TAG) {
+                       ret = error_func(&tag->object, FSCK_ERROR,
+                               "expected tag got %s",
+                           typename(type));
+                       goto done;
+               }
+       }
+
+       if (require_end_of_header(buffer, size, &tag->object, error_func))
+               goto done;
+
+       if (!skip_prefix(buffer, "object ", &buffer)) {
+               ret = error_func(&tag->object, FSCK_ERROR, "invalid format - expected 'object' line");
+               goto done;
+       }
+       if (get_sha1_hex(buffer, sha1) || buffer[40] != '\n') {
+               ret = error_func(&tag->object, FSCK_ERROR, "invalid 'object' line format - bad sha1");
+               goto done;
+       }
+       buffer += 41;
+
+       if (!skip_prefix(buffer, "type ", &buffer)) {
+               ret = error_func(&tag->object, FSCK_ERROR, "invalid format - expected 'type' line");
+               goto done;
+       }
+       eol = strchr(buffer, '\n');
+       if (!eol) {
+               ret = error_func(&tag->object, FSCK_ERROR, "invalid format - unexpected end after 'type' line");
+               goto done;
+       }
+       if (type_from_string_gently(buffer, eol - buffer, 1) < 0)
+               ret = error_func(&tag->object, FSCK_ERROR, "invalid 'type' value");
+       if (ret)
+               goto done;
+       buffer = eol + 1;
+
+       if (!skip_prefix(buffer, "tag ", &buffer)) {
+               ret = error_func(&tag->object, FSCK_ERROR, "invalid format - expected 'tag' line");
+               goto done;
+       }
+       eol = strchr(buffer, '\n');
+       if (!eol) {
+               ret = error_func(&tag->object, FSCK_ERROR, "invalid format - unexpected end after 'type' line");
+               goto done;
+       }
+       strbuf_addf(&sb, "refs/tags/%.*s", (int)(eol - buffer), buffer);
+       if (check_refname_format(sb.buf, 0))
+               error_func(&tag->object, FSCK_WARN, "invalid 'tag' name: %s", buffer);
+       buffer = eol + 1;
+
+       if (!skip_prefix(buffer, "tagger ", &buffer))
+               /* early tags do not contain 'tagger' lines; warn only */
+               error_func(&tag->object, FSCK_WARN, "invalid format - expected 'tagger' line");
+       else
+               ret = fsck_ident(&buffer, &tag->object, error_func);
+
+done:
+       strbuf_release(&sb);
+       free(to_free);
+       return ret;
+}
+
+static int fsck_tag(struct tag *tag, const char *data,
+       unsigned long size, fsck_error error_func)
 {
        struct object *tagged = tag->tagged;
 
        if (!tagged)
                return error_func(&tag->object, FSCK_ERROR, "could not load tagged object");
-       return 0;
+
+       return fsck_tag_buffer(tag, data, size, error_func);
 }
 
-int fsck_object(struct object *obj, int strict, fsck_error error_func)
+int fsck_object(struct object *obj, void *data, unsigned long size,
+       int strict, fsck_error error_func)
 {
        if (!obj)
                return error_func(obj, FSCK_ERROR, "no valid object to fsck");
@@ -349,9 +460,11 @@ int fsck_object(struct object *obj, int strict, fsck_error error_func)
        if (obj->type == OBJ_TREE)
                return fsck_tree((struct tree *) obj, strict, error_func);
        if (obj->type == OBJ_COMMIT)
-               return fsck_commit((struct commit *) obj, error_func);
+               return fsck_commit((struct commit *) obj, (const char *) data,
+                       size, error_func);
        if (obj->type == OBJ_TAG)
-               return fsck_tag((struct tag *) obj, error_func);
+               return fsck_tag((struct tag *) obj, (const char *) data,
+                       size, error_func);
 
        return error_func(obj, FSCK_ERROR, "unknown type '%d' (internal fsck error)",
                          obj->type);
diff --git a/fsck.h b/fsck.h
index 1e4f527318ea4b4d701a27e08d68f3551173f176..d1e6387a44e223b6d9438c7c35dc9efaa52f7d48 100644 (file)
--- a/fsck.h
+++ b/fsck.h
@@ -28,6 +28,8 @@ int fsck_error_function(struct object *obj, int type, const char *fmt, ...);
  *    0                everything OK
  */
 int fsck_walk(struct object *obj, fsck_walk_func walk, void *data);
-int fsck_object(struct object *obj, int strict, fsck_error error_func);
+/* If NULL is passed for data, we assume the object is local and read it. */
+int fsck_object(struct object *obj, void *data, unsigned long size,
+       int strict, fsck_error error_func);
 
 #endif
index 1e0d602f4b156929b74d10546cf5a5ba0f8518dd..6cda2b5a601c54d138ab3126a25c59371f6f7188 100755 (executable)
@@ -286,11 +286,11 @@ bisect_next_check() {
 
                if test -s "$GIT_DIR/BISECT_START"
                then
-                       gettextln "You need to give me at least one good and one bad revisions.
+                       gettextln "You need to give me at least one good and one bad revision.
 (You can use \"git bisect bad\" and \"git bisect good\" for that.)" >&2
                else
                        gettextln "You need to start by \"git bisect start\".
-You then need to give me at least one good and one bad revisions.
+You then need to give me at least one good and one bad revision.
 (You can use \"git bisect bad\" and \"git bisect good\" for that.)" >&2
                fi
                exit 1 ;;
index f587749b7cf6a74be376792eb0ad70b7e5e4f597..fb41118c0705c628bed093c4a915a58aa01a5a1a 100644 (file)
@@ -82,6 +82,7 @@
 #define _ALL_SOURCE 1
 #define _GNU_SOURCE 1
 #define _BSD_SOURCE 1
+#define _DEFAULT_SOURCE 1
 #define _NETBSD_SOURCE 1
 #define _SGI_SOURCE 1
 
@@ -191,7 +192,7 @@ extern int compat_mkdir_wo_trailing_slash(const char*, mode_t);
 struct itimerval {
        struct timeval it_interval;
        struct timeval it_value;
-}
+};
 #endif
 
 #ifdef NO_SETITIMER
@@ -264,19 +265,35 @@ extern char *gitbasename(char *);
 #endif
 
 #ifndef has_dos_drive_prefix
-#define has_dos_drive_prefix(path) 0
+static inline int git_has_dos_drive_prefix(const char *path)
+{
+       return 0;
+}
+#define has_dos_drive_prefix git_has_dos_drive_prefix
 #endif
 
-#ifndef offset_1st_component
-#define offset_1st_component(path) (is_dir_sep((path)[0]))
+#ifndef is_dir_sep
+static inline int git_is_dir_sep(int c)
+{
+       return c == '/';
+}
+#define is_dir_sep git_is_dir_sep
 #endif
 
-#ifndef is_dir_sep
-#define is_dir_sep(c) ((c) == '/')
+#ifndef offset_1st_component
+static inline int git_offset_1st_component(const char *path)
+{
+       return is_dir_sep(path[0]);
+}
+#define offset_1st_component git_offset_1st_component
 #endif
 
 #ifndef find_last_dir_sep
-#define find_last_dir_sep(path) strrchr(path, '/')
+static inline char *git_find_last_dir_sep(const char *path)
+{
+       return strrchr(path, '/');
+}
+#define find_last_dir_sep git_find_last_dir_sep
 #endif
 
 #if defined(__HP_cc) && (__HP_cc >= 61000)
@@ -593,6 +610,7 @@ extern try_to_free_t set_try_to_free_routine(try_to_free_t);
 extern char *xstrdup(const char *str);
 extern void *xmalloc(size_t size);
 extern void *xmallocz(size_t size);
+extern void *xmallocz_gently(size_t size);
 extern void *xmemdupz(const void *data, size_t len);
 extern char *xstrndup(const char *str, size_t len);
 extern void *xrealloc(void *ptr, size_t size);
@@ -607,6 +625,9 @@ extern int xmkstemp(char *template);
 extern int xmkstemp_mode(char *template, int mode);
 extern int odb_mkstemp(char *template, size_t limit, const char *pattern);
 extern int odb_pack_keep(char *name, size_t namesz, const unsigned char *sha1);
+extern char *xgetcwd(void);
+
+#define REALLOC_ARRAY(x, alloc) (x) = xrealloc((x), (alloc) * sizeof(*(x)))
 
 static inline size_t xsize_t(off_t len)
 {
index 18a394fcc4e704621c8b5e8bc92b7cbee2fd21fe..4d4fc77b05648c7d2d76ae932b7d68cdf411d364 100755 (executable)
@@ -20,7 +20,7 @@ die_conflict () {
     if [ $(git config --bool --get advice.resolveConflict || echo true) = "true" ]; then
        die "$(gettext "Pull is not possible because you have unmerged files.
 Please, fix them up in the work tree, and then use 'git add/rm <file>'
-as appropriate to mark resolution, or use 'git commit -a'.")"
+as appropriate to mark resolution and make a commit.")"
     else
        die "$(gettext "Pull is not possible because you have unmerged files.")"
     fi
index bcc757b3900b02595e5b432edcfd590e312b48ce..d4cf818be9488f1b94fdf4766a8f73db6bfd1029 100755 (executable)
@@ -50,7 +50,7 @@ clear_stash () {
        then
                die "$(gettext "git stash clear with parameters is unimplemented")"
        fi
-       if current=$(git rev-parse --verify $ref_stash 2>/dev/null)
+       if current=$(git rev-parse --verify --quiet $ref_stash)
        then
                git update-ref -d $ref_stash $current
        fi
@@ -292,12 +292,12 @@ save_stash () {
 }
 
 have_stash () {
-       git rev-parse --verify $ref_stash >/dev/null 2>&1
+       git rev-parse --verify --quiet $ref_stash >/dev/null
 }
 
 list_stash () {
        have_stash || return 0
-       git log --format="%gd: %gs" -g "$@" $ref_stash --
+       git log --format="%gd: %gs" -g --first-parent -m "$@" $ref_stash --
 }
 
 show_stash () {
@@ -392,12 +392,12 @@ parse_flags_and_rev()
                ;;
        esac
 
-       REV=$(git rev-parse --quiet --symbolic --verify "$1" 2>/dev/null) || {
+       REV=$(git rev-parse --symbolic --verify --quiet "$1") || {
                reference="$1"
-               die "$(eval_gettext "\$reference is not valid reference")"
+               die "$(eval_gettext "\$reference is not valid reference")"
        }
 
-       i_commit=$(git rev-parse --quiet --verify "$REV^2" 2>/dev/null) &&
+       i_commit=$(git rev-parse --verify --quiet "$REV^2") &&
        set -- $(git rev-parse "$REV" "$REV^1" "$REV:" "$REV^1:" "$REV^2:" 2>/dev/null) &&
        s=$1 &&
        w_commit=$1 &&
@@ -409,7 +409,7 @@ parse_flags_and_rev()
        test "$ref_stash" = "$(git rev-parse --symbolic-full-name "${REV%@*}")" &&
        IS_STASH_REF=t
 
-       u_commit=$(git rev-parse --quiet --verify "$REV^3" 2>/dev/null) &&
+       u_commit=$(git rev-parse --verify --quiet "$REV^3") &&
        u_tree=$(git rev-parse "$REV^3:" 2>/dev/null)
 }
 
@@ -531,7 +531,8 @@ drop_stash () {
                die "$(eval_gettext "\${REV}: Could not drop stash entry")"
 
        # clear_stash if we just dropped the last stash entry
-       git rev-parse --verify "$ref_stash@{0}" >/dev/null 2>&1 || clear_stash
+       git rev-parse --verify --quiet "$ref_stash@{0}" >/dev/null ||
+       clear_stash
 }
 
 apply_to_branch () {
index 0a323722a601b2cb900385e531d315558b6d3fe9..b6e2186cef0fcddc7c7b82378b07941d9f671a92 100755 (executable)
@@ -260,8 +260,8 @@ my %cmd = (
                        } ],
        'find-rev' => [ \&cmd_find_rev,
                        "Translate between SVN revision numbers and tree-ish",
-                       { 'before' => \$_before,
-                         'after' => \$_after } ],
+                       { 'B|before' => \$_before,
+                         'A|after' => \$_after } ],
        'rebase' => [ \&cmd_rebase, "Fetch and rebase your working directory",
                        { 'merge|m|M' => \$_merge,
                          'verbose|v' => \$_verbose,
@@ -306,13 +306,16 @@ sub readline {
 }
 package main;
 
-my $term = eval {
-       $ENV{"GIT_SVN_NOTTY"}
-               ? new Term::ReadLine 'git-svn', \*STDIN, \*STDOUT
-               : new Term::ReadLine 'git-svn';
-};
-if ($@) {
-       $term = new FakeTerm "$@: going non-interactive";
+my $term;
+sub term_init {
+       $term = eval {
+               $ENV{"GIT_SVN_NOTTY"}
+                       ? new Term::ReadLine 'git-svn', \*STDIN, \*STDOUT
+                       : new Term::ReadLine 'git-svn';
+       };
+       if ($@) {
+               $term = new FakeTerm "$@: going non-interactive";
+       }
 }
 
 my $cmd;
@@ -424,6 +427,7 @@ sub ask {
        my $default = $arg{default};
        my $resp;
        my $i = 0;
+       term_init() unless $term;
 
        if ( !( defined($term->IN)
             && defined( fileno($term->IN) )
@@ -1161,7 +1165,9 @@ sub cmd_branch {
        ::_req_svn();
 
        my $ctx = SVN::Client->new(
-               auth    => Git::SVN::Ra::_auth_providers(),
+               config => SVN::Core::config_get_config(
+                       $Git::SVN::Ra::config_dir
+               ),
                log_msg => sub {
                        ${ $_[0] } = defined $_message
                                ? $_message
@@ -1475,10 +1481,37 @@ sub cmd_commit_diff {
        }
 }
 
-
 sub cmd_info {
-       my $path = canonicalize_path(defined($_[0]) ? $_[0] : ".");
-       my $fullpath = canonicalize_path($cmd_dir_prefix . $path);
+       my $path_arg = defined($_[0]) ? $_[0] : '.';
+       my $path = $path_arg;
+       if (File::Spec->file_name_is_absolute($path)) {
+               $path = canonicalize_path($path);
+
+               my $toplevel = eval {
+                       my @cmd = qw/rev-parse --show-toplevel/;
+                       command_oneline(\@cmd, STDERR => 0);
+               };
+
+               # remove $toplevel from the absolute path:
+               my ($vol, $dirs, $file) = File::Spec->splitpath($path);
+               my (undef, $tdirs, $tfile) = File::Spec->splitpath($toplevel);
+               my @dirs = File::Spec->splitdir($dirs);
+               my @tdirs = File::Spec->splitdir($tdirs);
+               pop @dirs if $dirs[-1] eq '';
+               pop @tdirs if $tdirs[-1] eq '';
+               push @dirs, $file;
+               push @tdirs, $tfile;
+               while (@tdirs && @dirs && $tdirs[0] eq $dirs[0]) {
+                       shift @dirs;
+                       shift @tdirs;
+               }
+               $dirs = File::Spec->catdir(@dirs);
+               $path = File::Spec->catpath($vol, $dirs);
+
+               $path = canonicalize_path($path);
+       } else {
+               $path = canonicalize_path($cmd_dir_prefix . $path);
+       }
        if (exists $_[1]) {
                die "Too many arguments specified\n";
        }
@@ -1499,14 +1532,14 @@ sub cmd_info {
        # canonicalize_path() will return "" to make libsvn 1.5.x happy,
        $path = "." if $path eq "";
 
-       my $full_url = canonicalize_url( add_path_to_url( $url, $fullpath ) );
+       my $full_url = canonicalize_url( add_path_to_url( $url, $path ) );
 
        if ($_url) {
                print "$full_url\n";
                return;
        }
 
-       my $result = "Path: $path\n";
+       my $result = "Path: $path_arg\n";
        $result .= "Name: " . basename($path) . "\n" if $file_type ne "dir";
        $result .= "URL: $full_url\n";
 
@@ -1537,7 +1570,7 @@ sub cmd_info {
        }
 
        my ($lc_author, $lc_rev, $lc_date_utc);
-       my @args = Git::SVN::Log::git_svn_log_cmd($rev, $rev, "--", $fullpath);
+       my @args = Git::SVN::Log::git_svn_log_cmd($rev, $rev, "--", $path);
        my $log = command_output_pipe(@args);
        my $esc_color = qr/(?:\033\[(?:(?:\d+;)*\d*)?m)*/;
        while (<$log>) {
diff --git a/git.c b/git.c
index 9c495198317bf31ff40785a48bf0a44253548098..4cebf32126014938533b66cb57164c6602a1675c 100644 (file)
--- a/git.c
+++ b/git.c
@@ -14,13 +14,13 @@ const char git_usage_string[] =
        "           <command> [<args>]";
 
 const char git_more_info_string[] =
-       N_("'git help -a' and 'git help -g' lists available subcommands and some\n"
+       N_("'git help -a' and 'git help -g' list available subcommands and some\n"
           "concept guides. See 'git help <command>' or 'git help <concept>'\n"
           "to read about a specific subcommand or concept.");
 
 static struct startup_info git_startup_info;
 static int use_pager = -1;
-static char orig_cwd[PATH_MAX];
+static char *orig_cwd;
 static const char *env_names[] = {
        GIT_DIR_ENVIRONMENT,
        GIT_WORK_TREE_ENVIRONMENT,
@@ -36,8 +36,7 @@ static void save_env(void)
        if (saved_environment)
                return;
        saved_environment = 1;
-       if (!getcwd(orig_cwd, sizeof(orig_cwd)))
-               die_errno("cannot getcwd");
+       orig_cwd = xgetcwd();
        for (i = 0; i < ARRAY_SIZE(env_names); i++) {
                orig_env[i] = getenv(env_names[i]);
                if (orig_env[i])
@@ -48,8 +47,9 @@ static void save_env(void)
 static void restore_env(void)
 {
        int i;
-       if (*orig_cwd && chdir(orig_cwd))
+       if (orig_cwd && chdir(orig_cwd))
                die_errno("could not move to %s", orig_cwd);
+       free(orig_cwd);
        for (i = 0; i < ARRAY_SIZE(env_names); i++) {
                if (orig_env[i])
                        setenv(env_names[i], orig_env[i], 1);
@@ -161,9 +161,10 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
                        if (envchanged)
                                *envchanged = 1;
                } else if (!strcmp(cmd, "--bare")) {
-                       static char git_dir[PATH_MAX+1];
+                       char *cwd = xgetcwd();
                        is_bare_repository_cfg = 1;
-                       setenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir, sizeof(git_dir)), 0);
+                       setenv(GIT_DIR_ENVIRONMENT, cwd, 0);
+                       free(cwd);
                        setenv(GIT_IMPLICIT_WORK_TREE_ENVIRONMENT, "0", 1);
                        if (envchanged)
                                *envchanged = 1;
@@ -281,8 +282,7 @@ static int handle_alias(int *argcp, const char ***argv)
                                  "trace: alias expansion: %s =>",
                                  alias_command);
 
-               new_argv = xrealloc(new_argv, sizeof(char *) *
-                                   (count + *argcp));
+               REALLOC_ARRAY(new_argv, count + *argcp);
                /* insert after command name */
                memcpy(new_argv + count, *argv + 1, sizeof(char *) * *argcp);
 
@@ -592,6 +592,26 @@ static int run_argv(int *argcp, const char ***argv)
        return done_alias;
 }
 
+/*
+ * Many parts of Git have subprograms communicate via pipe, expect the
+ * upstream of a pipe to die with SIGPIPE when the downstream of a
+ * pipe does not need to read all that is written.  Some third-party
+ * programs that ignore or block SIGPIPE for their own reason forget
+ * to restore SIGPIPE handling to the default before spawning Git and
+ * break this carefully orchestrated machinery.
+ *
+ * Restore the way SIGPIPE is handled to default, which is what we
+ * expect.
+ */
+static void restore_sigpipe_to_default(void)
+{
+       sigset_t unblock;
+
+       sigemptyset(&unblock);
+       sigaddset(&unblock, SIGPIPE);
+       sigprocmask(SIG_UNBLOCK, &unblock, NULL);
+       signal(SIGPIPE, SIG_DFL);
+}
 
 int main(int argc, char **av)
 {
@@ -611,6 +631,8 @@ int main(int argc, char **av)
         */
        sanitize_stdfds();
 
+       restore_sigpipe_to_default();
+
        git_setup_gettext();
 
        trace_command_performance(argv);
index ff07012726ea28daa2551966d0555d2e8efa2375..1ef73fb7dfedd8cd5d3444433218ff177a63111b 100644 (file)
@@ -55,12 +55,11 @@ const char *get_signing_key(void)
  */
 int sign_buffer(struct strbuf *buffer, struct strbuf *signature, const char *signing_key)
 {
-       struct child_process gpg;
+       struct child_process gpg = CHILD_PROCESS_INIT;
        const char *args[4];
        ssize_t len;
        size_t i, j, bottom;
 
-       memset(&gpg, 0, sizeof(gpg));
        gpg.argv = args;
        gpg.in = -1;
        gpg.out = -1;
@@ -116,7 +115,7 @@ int verify_signed_buffer(const char *payload, size_t payload_size,
                         const char *signature, size_t signature_size,
                         struct strbuf *gpg_output, struct strbuf *gpg_status)
 {
-       struct child_process gpg;
+       struct child_process gpg = CHILD_PROCESS_INIT;
        const char *args_gpg[] = {NULL, "--status-fd=1", "--verify", "FILE", "-", NULL};
        char path[PATH_MAX];
        int fd, ret;
@@ -133,7 +132,6 @@ int verify_signed_buffer(const char *payload, size_t payload_size,
                             path, strerror(errno));
        close(fd);
 
-       memset(&gpg, 0, sizeof(gpg));
        gpg.argv = args_gpg;
        gpg.in = -1;
        gpg.out = -1;
diff --git a/graph.c b/graph.c
index 640433166b39c515746d698566839326d9ce7bbe..c25a09a8fdaf3e90bf7e029c78127146418ab023 100644 (file)
--- a/graph.c
+++ b/graph.c
@@ -267,16 +267,10 @@ static void graph_ensure_capacity(struct git_graph *graph, int num_columns)
                graph->column_capacity *= 2;
        } while (graph->column_capacity < num_columns);
 
-       graph->columns = xrealloc(graph->columns,
-                                 sizeof(struct column) *
-                                 graph->column_capacity);
-       graph->new_columns = xrealloc(graph->new_columns,
-                                     sizeof(struct column) *
-                                     graph->column_capacity);
-       graph->mapping = xrealloc(graph->mapping,
-                                 sizeof(int) * 2 * graph->column_capacity);
-       graph->new_mapping = xrealloc(graph->new_mapping,
-                                     sizeof(int) * 2 * graph->column_capacity);
+       REALLOC_ARRAY(graph->columns, graph->column_capacity);
+       REALLOC_ARRAY(graph->new_columns, graph->column_capacity);
+       REALLOC_ARRAY(graph->mapping, graph->column_capacity * 2);
+       REALLOC_ARRAY(graph->new_mapping, graph->column_capacity * 2);
 }
 
 /*
@@ -1145,7 +1139,7 @@ int graph_next_line(struct git_graph *graph, struct strbuf *sb)
 
 static void graph_padding_line(struct git_graph *graph, struct strbuf *sb)
 {
-       int i, j;
+       int i;
 
        if (graph->state != GRAPH_COMMIT) {
                graph_next_line(graph, sb);
@@ -1161,21 +1155,11 @@ static void graph_padding_line(struct git_graph *graph, struct strbuf *sb)
         */
        for (i = 0; i < graph->num_columns; i++) {
                struct column *col = &graph->columns[i];
-               struct commit *col_commit = col->commit;
-               if (col_commit == graph->commit) {
-                       strbuf_write_column(sb, col, '|');
-
-                       if (graph->num_parents < 3)
-                               strbuf_addch(sb, ' ');
-                       else {
-                               int num_spaces = ((graph->num_parents - 2) * 2);
-                               for (j = 0; j < num_spaces; j++)
-                                       strbuf_addch(sb, ' ');
-                       }
-               } else {
-                       strbuf_write_column(sb, col, '|');
+               strbuf_write_column(sb, col, '|');
+               if (col->commit == graph->commit && graph->num_parents > 2)
+                       strbuf_addchars(sb, ' ', (graph->num_parents - 2) * 2);
+               else
                        strbuf_addch(sb, ' ');
-               }
        }
 
        graph_pad_horizontally(graph, sb, graph->num_columns);
diff --git a/help.c b/help.c
index 7af65e205ecdf1a01dce009cbf0ada15de68c844..2072a873e2db784ca66c0f1736b12e523a96b7db 100644 (file)
--- a/help.c
+++ b/help.c
@@ -305,7 +305,7 @@ const char *help_unknown_cmd(const char *cmd)
        add_cmd_list(&main_cmds, &aliases);
        add_cmd_list(&main_cmds, &other_cmds);
        qsort(main_cmds.names, main_cmds.cnt,
-             sizeof(main_cmds.names), cmdname_compare);
+             sizeof(*main_cmds.names), cmdname_compare);
        uniq(&main_cmds);
 
        /* This abuses cmdname->len for levenshtein distance */
index 80790bbaef95a56ac737c7763e48035e3e0754ee..404e682593ecfca218d0aee0634f5c21356ef69c 100644 (file)
@@ -219,29 +219,22 @@ static void get_idx_file(char *name)
        send_local_file("application/x-git-packed-objects-toc", name);
 }
 
-static int http_config(const char *var, const char *value, void *cb)
+static void http_config(void)
 {
-       const char *p;
+       int i, value = 0;
+       struct strbuf var = STRBUF_INIT;
 
-       if (!strcmp(var, "http.getanyfile")) {
-               getanyfile = git_config_bool(var, value);
-               return 0;
-       }
+       git_config_get_bool("http.getanyfile", &getanyfile);
 
-       if (skip_prefix(var, "http.", &p)) {
-               int i;
-
-               for (i = 0; i < ARRAY_SIZE(rpc_service); i++) {
-                       struct rpc_service *svc = &rpc_service[i];
-                       if (!strcmp(p, svc->config_name)) {
-                               svc->enabled = git_config_bool(var, value);
-                               return 0;
-                       }
-               }
+       for (i = 0; i < ARRAY_SIZE(rpc_service); i++) {
+               struct rpc_service *svc = &rpc_service[i];
+               strbuf_addf(&var, "http.%s", svc->config_name);
+               if (!git_config_get_bool(var.buf, &value))
+                       svc->enabled = value;
+               strbuf_reset(&var);
        }
 
-       /* we are not interested in parsing any other configuration here */
-       return 0;
+       strbuf_release(&var);
 }
 
 static struct rpc_service *select_service(const char *name)
@@ -323,7 +316,7 @@ static void run_service(const char **argv)
        const char *host = getenv("REMOTE_ADDR");
        struct argv_array env = ARGV_ARRAY_INIT;
        int gzipped_request = 0;
-       struct child_process cld;
+       struct child_process cld = CHILD_PROCESS_INIT;
 
        if (encoding && !strcmp(encoding, "gzip"))
                gzipped_request = 1;
@@ -341,7 +334,6 @@ static void run_service(const char **argv)
                argv_array_pushf(&env, "GIT_COMMITTER_EMAIL=%s@http.%s",
                                 user, host);
 
-       memset(&cld, 0, sizeof(cld));
        cld.argv = argv;
        cld.env = env.argv;
        if (gzipped_request)
@@ -627,7 +619,7 @@ int main(int argc, char **argv)
            access("git-daemon-export-ok", F_OK) )
                not_found("Repository not exported: '%s'", dir);
 
-       git_config(http_config, NULL);
+       http_config();
        cmd->imp(cmd_arg);
        return 0;
 }
index dbddfaa1773265a2917d4715158f16845d7139e5..88da5468e77f5a543edb7583e2846f19eb509653 100644 (file)
@@ -230,7 +230,6 @@ static void process_alternates_response(void *callback_data)
                        int okay = 0;
                        int serverlen = 0;
                        struct alt_base *newalt;
-                       char *target = NULL;
                        if (data[i] == '/') {
                                /*
                                 * This counts
@@ -287,17 +286,15 @@ static void process_alternates_response(void *callback_data)
                        }
                        /* skip "objects\n" at end */
                        if (okay) {
-                               target = xmalloc(serverlen + posn - i - 6);
-                               memcpy(target, base, serverlen);
-                               memcpy(target + serverlen, data + i,
-                                      posn - i - 7);
-                               target[serverlen + posn - i - 7] = 0;
+                               struct strbuf target = STRBUF_INIT;
+                               strbuf_add(&target, base, serverlen);
+                               strbuf_add(&target, data + i, posn - i - 7);
                                if (walker->get_verbosely)
-                                       fprintf(stderr,
-                                               "Also look at %s\n", target);
+                                       fprintf(stderr, "Also look at %s\n",
+                                               target.buf);
                                newalt = xmalloc(sizeof(*newalt));
                                newalt->next = NULL;
-                               newalt->base = target;
+                               newalt->base = strbuf_detach(&target, NULL);
                                newalt->got_indices = 0;
                                newalt->packs = NULL;
 
diff --git a/http.c b/http.c
index c8cd50dd0c2b2213a86957cd4b24c03c0d85717d..0adcec4683f997044807a772713d476dd77cf105 100644 (file)
--- a/http.c
+++ b/http.c
@@ -300,6 +300,9 @@ static CURL *get_curl_handle(void)
 {
        CURL *result = curl_easy_init();
 
+       if (!result)
+               die("curl_easy_init failed");
+
        if (!curl_ssl_verify) {
                curl_easy_setopt(result, CURLOPT_SSL_VERIFYPEER, 0);
                curl_easy_setopt(result, CURLOPT_SSL_VERIFYHOST, 0);
@@ -399,7 +402,8 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
        git_config(urlmatch_config_entry, &config);
        free(normalized_url);
 
-       curl_global_init(CURL_GLOBAL_ALL);
+       if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK)
+               die("curl_global_init failed");
 
        http_proactive_auth = proactive_auth;
 
@@ -417,10 +421,8 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
        }
 
        curlm = curl_multi_init();
-       if (curlm == NULL) {
-               fprintf(stderr, "Error creating curl multi handle.\n");
-               exit(1);
-       }
+       if (!curlm)
+               die("curl_multi_init failed");
 #endif
 
        if (getenv("GIT_SSL_NO_VERIFY"))
@@ -1332,7 +1334,7 @@ int finish_http_pack_request(struct http_pack_request *preq)
        struct packed_git **lst;
        struct packed_git *p = preq->target;
        char *tmp_idx;
-       struct child_process ip;
+       struct child_process ip = CHILD_PROCESS_INIT;
        const char *ip_argv[8];
 
        close_pack_index(p);
@@ -1355,7 +1357,6 @@ int finish_http_pack_request(struct http_pack_request *preq)
        ip_argv[3] = preq->tmpfile;
        ip_argv[4] = NULL;
 
-       memset(&ip, 0, sizeof(ip));
        ip.argv = ip_argv;
        ip.git_cmd = 1;
        ip.no_stdin = 1;
diff --git a/ident.c b/ident.c
index 1d9b6e770d02d12f77b417e05aca5134eccf1c40..5ff1aadaaaa999df3bfecb07f84f259469b3a54d 100644 (file)
--- a/ident.c
+++ b/ident.c
@@ -9,7 +9,7 @@
 
 static struct strbuf git_default_name = STRBUF_INIT;
 static struct strbuf git_default_email = STRBUF_INIT;
-static char git_default_date[50];
+static struct strbuf git_default_date = STRBUF_INIT;
 
 #define IDENT_NAME_GIVEN 01
 #define IDENT_MAIL_GIVEN 02
@@ -102,7 +102,7 @@ static void copy_email(const struct passwd *pw, struct strbuf *email)
        add_domainname(email);
 }
 
-static const char *ident_default_name(void)
+const char *ident_default_name(void)
 {
        if (!git_default_name.len) {
                copy_gecos(xgetpwuid_self(), &git_default_name);
@@ -129,9 +129,9 @@ const char *ident_default_email(void)
 
 static const char *ident_default_date(void)
 {
-       if (!git_default_date[0])
-               datestamp(git_default_date, sizeof(git_default_date));
-       return git_default_date;
+       if (!git_default_date.len)
+               datestamp(&git_default_date);
+       return git_default_date.buf;
 }
 
 static int crud(unsigned char c)
@@ -292,7 +292,6 @@ const char *fmt_ident(const char *name, const char *email,
                      const char *date_str, int flag)
 {
        static struct strbuf ident = STRBUF_INIT;
-       char date[50];
        int strict = (flag & IDENT_STRICT);
        int want_date = !(flag & IDENT_NO_DATE);
        int want_name = !(flag & IDENT_NO_NAME);
@@ -320,15 +319,6 @@ const char *fmt_ident(const char *name, const char *email,
                die("unable to auto-detect email address (got '%s')", email);
        }
 
-       if (want_date) {
-               if (date_str && date_str[0]) {
-                       if (parse_date(date_str, date, sizeof(date)) < 0)
-                               die("invalid date format: %s", date_str);
-               }
-               else
-                       strcpy(date, ident_default_date());
-       }
-
        strbuf_reset(&ident);
        if (want_name) {
                strbuf_addstr_without_crud(&ident, name);
@@ -339,8 +329,14 @@ const char *fmt_ident(const char *name, const char *email,
                        strbuf_addch(&ident, '>');
        if (want_date) {
                strbuf_addch(&ident, ' ');
-               strbuf_addstr_without_crud(&ident, date);
+               if (date_str && date_str[0]) {
+                       if (parse_date(date_str, &ident) < 0)
+                               die("invalid date format: %s", date_str);
+               }
+               else
+                       strbuf_addstr(&ident, ident_default_date());
        }
+
        return ident.buf;
 }
 
index 524fbabc96f450f1faed196c1743d2f8d697b587..70bcc7a4e533bb04e8c515e8831a75ec93d2d066 100644 (file)
@@ -69,6 +69,7 @@ struct imap_server_conf {
        char *tunnel;
        char *host;
        int port;
+       char *folder;
        char *user;
        char *pass;
        int use_ssl;
@@ -82,6 +83,7 @@ static struct imap_server_conf server = {
        NULL,   /* tunnel */
        NULL,   /* host */
        0,      /* port */
+       NULL,   /* folder */
        NULL,   /* user */
        NULL,   /* pass */
        0,      /* use_ssl */
@@ -128,7 +130,6 @@ struct imap_cmd_cb {
        char *data;
        int dlen;
        int uid;
-       unsigned create:1, trycreate:1;
 };
 
 struct imap_cmd {
@@ -493,9 +494,9 @@ static int nfsnprintf(char *buf, int blen, const char *fmt, ...)
        return ret;
 }
 
-static struct imap_cmd *v_issue_imap_cmd(struct imap_store *ctx,
-                                        struct imap_cmd_cb *cb,
-                                        const char *fmt, va_list ap)
+static struct imap_cmd *issue_imap_cmd(struct imap_store *ctx,
+                                      struct imap_cmd_cb *cb,
+                                      const char *fmt, va_list ap)
 {
        struct imap *imap = ctx->imap;
        struct imap_cmd *cmd;
@@ -524,7 +525,7 @@ static struct imap_cmd *v_issue_imap_cmd(struct imap_store *ctx,
        if (Verbose) {
                if (imap->num_in_progress)
                        printf("(%d in progress) ", imap->num_in_progress);
-               if (memcmp(cmd->cmd, "LOGIN", 5))
+               if (!starts_with(cmd->cmd, "LOGIN"))
                        printf(">>> %s", buf);
                else
                        printf(">>> %d LOGIN <user> <pass>\n", cmd->tag);
@@ -558,20 +559,6 @@ static struct imap_cmd *v_issue_imap_cmd(struct imap_store *ctx,
        return cmd;
 }
 
-__attribute__((format (printf, 3, 4)))
-static struct imap_cmd *issue_imap_cmd(struct imap_store *ctx,
-                                      struct imap_cmd_cb *cb,
-                                      const char *fmt, ...)
-{
-       struct imap_cmd *ret;
-       va_list ap;
-
-       va_start(ap, fmt);
-       ret = v_issue_imap_cmd(ctx, cb, fmt, ap);
-       va_end(ap);
-       return ret;
-}
-
 __attribute__((format (printf, 3, 4)))
 static int imap_exec(struct imap_store *ctx, struct imap_cmd_cb *cb,
                     const char *fmt, ...)
@@ -580,7 +567,7 @@ static int imap_exec(struct imap_store *ctx, struct imap_cmd_cb *cb,
        struct imap_cmd *cmdp;
 
        va_start(ap, fmt);
-       cmdp = v_issue_imap_cmd(ctx, cb, fmt, ap);
+       cmdp = issue_imap_cmd(ctx, cb, fmt, ap);
        va_end(ap);
        if (!cmdp)
                return RESP_BAD;
@@ -596,7 +583,7 @@ static int imap_exec_m(struct imap_store *ctx, struct imap_cmd_cb *cb,
        struct imap_cmd *cmdp;
 
        va_start(ap, fmt);
-       cmdp = v_issue_imap_cmd(ctx, cb, fmt, ap);
+       cmdp = issue_imap_cmd(ctx, cb, fmt, ap);
        va_end(ap);
        if (!cmdp)
                return DRV_STORE_BAD;
@@ -714,8 +701,8 @@ static int parse_response_code(struct imap_store *ctx, struct imap_cmd_cb *cb,
 static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd)
 {
        struct imap *imap = ctx->imap;
-       struct imap_cmd *cmdp, **pcmdp, *ncmdp;
-       char *cmd, *arg, *arg1, *p;
+       struct imap_cmd *cmdp, **pcmdp;
+       char *cmd, *arg, *arg1;
        int n, resp, resp2, tag;
 
        for (;;) {
@@ -801,39 +788,17 @@ static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd)
                        if (!strcmp("OK", arg))
                                resp = DRV_OK;
                        else {
-                               if (!strcmp("NO", arg)) {
-                                       if (cmdp->cb.create && cmd && (cmdp->cb.trycreate || !memcmp(cmd, "[TRYCREATE]", 11))) { /* SELECT, APPEND or UID COPY */
-                                               p = strchr(cmdp->cmd, '"');
-                                               if (!issue_imap_cmd(ctx, NULL, "CREATE \"%.*s\"", (int)(strchr(p + 1, '"') - p + 1), p)) {
-                                                       resp = RESP_BAD;
-                                                       goto normal;
-                                               }
-                                               /* not waiting here violates the spec, but a server that does not
-                                                  grok this nonetheless violates it too. */
-                                               cmdp->cb.create = 0;
-                                               if (!(ncmdp = issue_imap_cmd(ctx, &cmdp->cb, "%s", cmdp->cmd))) {
-                                                       resp = RESP_BAD;
-                                                       goto normal;
-                                               }
-                                               free(cmdp->cmd);
-                                               free(cmdp);
-                                               if (!tcmd)
-                                                       return 0;       /* ignored */
-                                               if (cmdp == tcmd)
-                                                       tcmd = ncmdp;
-                                               continue;
-                                       }
+                               if (!strcmp("NO", arg))
                                        resp = RESP_NO;
-                               else /*if (!strcmp("BAD", arg))*/
+                               else /*if (!strcmp("BAD", arg))*/
                                        resp = RESP_BAD;
                                fprintf(stderr, "IMAP command '%s' returned response (%s) - %s\n",
-                                        memcmp(cmdp->cmd, "LOGIN", 5) ?
+                                       !starts_with(cmdp->cmd, "LOGIN") ?
                                                        cmdp->cmd : "LOGIN <user> <pass>",
                                                        arg, cmd ? cmd : "");
                        }
                        if ((resp2 = parse_response_code(ctx, &cmdp->cb, cmd)) > resp)
                                resp = resp2;
-               normal:
                        if (cmdp->cb.done)
                                cmdp->cb.done(ctx, cmdp, resp);
                        free(cmdp->cb.data);
@@ -944,7 +909,7 @@ static int auth_cram_md5(struct imap_store *ctx, struct imap_cmd *cmd, const cha
        return 0;
 }
 
-static struct imap_store *imap_open_store(struct imap_server_conf *srvc)
+static struct imap_store *imap_open_store(struct imap_server_conf *srvc, char *folder)
 {
        struct credential cred = CREDENTIAL_INIT;
        struct imap_store *ctx;
@@ -954,24 +919,23 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc)
 
        ctx = xcalloc(1, sizeof(*ctx));
 
-       ctx->imap = imap = xcalloc(sizeof(*imap), 1);
+       ctx->imap = imap = xcalloc(1, sizeof(*imap));
        imap->buf.sock.fd[0] = imap->buf.sock.fd[1] = -1;
        imap->in_progress_append = &imap->in_progress;
 
        /* open connection to IMAP server */
 
        if (srvc->tunnel) {
-               const char *argv[] = { srvc->tunnel, NULL };
-               struct child_process tunnel = {NULL};
+               struct child_process tunnel = CHILD_PROCESS_INIT;
 
                imap_info("Starting tunnel '%s'... ", srvc->tunnel);
 
-               tunnel.argv = argv;
+               argv_array_push(&tunnel.args, srvc->tunnel);
                tunnel.use_shell = 1;
                tunnel.in = -1;
                tunnel.out = -1;
                if (start_command(&tunnel))
-                       die("cannot start proxy %s", argv[0]);
+                       die("cannot start proxy %s", srvc->tunnel);
 
                imap->buf.sock.fd[0] = tunnel.out;
                imap->buf.sock.fd[1] = tunnel.in;
@@ -1156,6 +1120,25 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc)
                credential_approve(&cred);
        credential_clear(&cred);
 
+       /* check the target mailbox exists */
+       ctx->name = folder;
+       switch (imap_exec(ctx, NULL, "EXAMINE \"%s\"", ctx->name)) {
+       case RESP_OK:
+               /* ok */
+               break;
+       case RESP_BAD:
+               fprintf(stderr, "IMAP error: could not check mailbox\n");
+               goto out;
+       case RESP_NO:
+               if (imap_exec(ctx, NULL, "CREATE \"%s\"", ctx->name) == RESP_OK) {
+                       imap_info("Created missing mailbox\n");
+               } else {
+                       fprintf(stderr, "IMAP error: could not create missing mailbox\n");
+                       goto out;
+               }
+               break;
+       }
+
        ctx->prefix = "";
        return ctx;
 
@@ -1164,6 +1147,7 @@ bail:
                credential_reject(&cred);
        credential_clear(&cred);
 
+ out:
        imap_close_store(ctx);
        return NULL;
 }
@@ -1219,7 +1203,6 @@ static int imap_store_msg(struct imap_store *ctx, struct strbuf *msg)
 
        box = ctx->name;
        prefix = !strcmp(box, "INBOX") ? "" : ctx->prefix;
-       cb.create = 0;
        ret = imap_exec_m(ctx, &cb, "APPEND \"%s%s\" ", prefix, box);
        imap->caps = imap->rcaps;
        if (ret != DRV_OK)
@@ -1324,45 +1307,35 @@ static int split_msg(struct strbuf *all_msgs, struct strbuf *msg, int *ofs)
        return 1;
 }
 
-static char *imap_folder;
-
-static int git_imap_config(const char *key, const char *val, void *cb)
+static void git_imap_config(void)
 {
-       if (!skip_prefix(key, "imap.", &key))
-               return 0;
+       const char *val = NULL;
+
+       git_config_get_bool("imap.sslverify", &server.ssl_verify);
+       git_config_get_bool("imap.preformattedhtml", &server.use_html);
+       git_config_get_string("imap.folder", &server.folder);
 
-       /* check booleans first, and barf on others */
-       if (!strcmp("sslverify", key))
-               server.ssl_verify = git_config_bool(key, val);
-       else if (!strcmp("preformattedhtml", key))
-               server.use_html = git_config_bool(key, val);
-       else if (!val)
-               return config_error_nonbool(key);
-
-       if (!strcmp("folder", key)) {
-               imap_folder = xstrdup(val);
-       } else if (!strcmp("host", key)) {
-               if (starts_with(val, "imap:"))
-                       val += 5;
-               else if (starts_with(val, "imaps:")) {
-                       val += 6;
-                       server.use_ssl = 1;
+       if (!git_config_get_value("imap.host", &val)) {
+               if (!val) {
+                       git_die_config("imap.host", "Missing value for 'imap.host'");
+               } else {
+                       if (starts_with(val, "imap:"))
+                               val += 5;
+                       else if (starts_with(val, "imaps:")) {
+                               val += 6;
+                               server.use_ssl = 1;
+                       }
+                       if (starts_with(val, "//"))
+                               val += 2;
+                       server.host = xstrdup(val);
                }
-               if (starts_with(val, "//"))
-                       val += 2;
-               server.host = xstrdup(val);
-       } else if (!strcmp("user", key))
-               server.user = xstrdup(val);
-       else if (!strcmp("pass", key))
-               server.pass = xstrdup(val);
-       else if (!strcmp("port", key))
-               server.port = git_config_int(key, val);
-       else if (!strcmp("tunnel", key))
-               server.tunnel = xstrdup(val);
-       else if (!strcmp("authmethod", key))
-               server.auth_method = xstrdup(val);
+       }
 
-       return 0;
+       git_config_get_string("imap.user", &server.user);
+       git_config_get_string("imap.pass", &server.pass);
+       git_config_get_int("imap.port", &server.port);
+       git_config_get_string("imap.tunnel", &server.tunnel);
+       git_config_get_string("imap.authmethod", &server.auth_method);
 }
 
 int main(int argc, char **argv)
@@ -1383,12 +1356,12 @@ int main(int argc, char **argv)
                usage(imap_send_usage);
 
        setup_git_directory_gently(&nongit_ok);
-       git_config(git_imap_config, NULL);
+       git_imap_config();
 
        if (!server.port)
                server.port = server.use_ssl ? 993 : 143;
 
-       if (!imap_folder) {
+       if (!server.folder) {
                fprintf(stderr, "no imap store specified\n");
                return 1;
        }
@@ -1418,14 +1391,13 @@ int main(int argc, char **argv)
        }
 
        /* write it to the imap server */
-       ctx = imap_open_store(&server);
+       ctx = imap_open_store(&server, server.folder);
        if (!ctx) {
                fprintf(stderr, "failed to open store\n");
                return 1;
        }
 
        fprintf(stderr, "sending %d message%s\n", total, (total != 1) ? "s" : "");
-       ctx->name = imap_folder;
        while (1) {
                unsigned percent = n * 100 / total;
 
diff --git a/khash.h b/khash.h
index 06c79065490f152ceed2732ba1b93c309eb4d574..376475a5eaf80585311ab518d03c229a7a49a7ed 100644 (file)
--- a/khash.h
+++ b/khash.h
@@ -121,13 +121,9 @@ static const double __ac_HASH_UPPER = 0.77;
                                if (!new_flags) return -1;                                                              \
                                memset(new_flags, 0xaa, __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
                                if (h->n_buckets < new_n_buckets) {     /* expand */            \
-                                       khkey_t *new_keys = (khkey_t*)xrealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
-                                       if (!new_keys) return -1;                                                       \
-                                       h->keys = new_keys;                                                                     \
+                                       REALLOC_ARRAY(h->keys, new_n_buckets); \
                                        if (kh_is_map) {                                                                        \
-                                               khval_t *new_vals = (khval_t*)xrealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \
-                                               if (!new_vals) return -1;                                               \
-                                               h->vals = new_vals;                                                             \
+                                               REALLOC_ARRAY(h->vals, new_n_buckets); \
                                        }                                                                                                       \
                                } /* otherwise shrink */                                                                \
                        }                                                                                                                       \
@@ -160,8 +156,8 @@ static const double __ac_HASH_UPPER = 0.77;
                                }                                                                                                               \
                        }                                                                                                                       \
                        if (h->n_buckets > new_n_buckets) { /* shrink the hash table */ \
-                               h->keys = (khkey_t*)xrealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
-                               if (kh_is_map) h->vals = (khval_t*)xrealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \
+                               REALLOC_ARRAY(h->keys, new_n_buckets); \
+                               if (kh_is_map) REALLOC_ARRAY(h->vals, new_n_buckets); \
                        }                                                                                                                       \
                        free(h->flags); /* free the working space */                            \
                        h->flags = new_flags;                                                                           \
index 1008e722584c882ac86b936307ace701b9225aaf..038c58a395c6804e5f719d4d82a3d4edbd6d8901 100644 (file)
@@ -533,7 +533,7 @@ static void fill_line_ends(struct diff_filespec *spec, long *lines,
        }
 
        /* shrink the array to fit the elements */
-       ends = xrealloc(ends, cur * sizeof(*ends));
+       REALLOC_ARRAY(ends, cur);
        *lines = cur-1;
        *line_ends = ends;
 }
index fb61ea66a13eba3a8e91a05dbe1c37de98cec853..8ea03e536a56655ff48f4fa8a3050c0225d52f38 100644 (file)
@@ -225,11 +225,8 @@ static int read_merge_config(const char *var, const char *value, void *cb)
        const char *key, *name;
        int namelen;
 
-       if (!strcmp(var, "merge.default")) {
-               if (value)
-                       default_ll_merge = xstrdup(value);
-               return 0;
-       }
+       if (!strcmp(var, "merge.default"))
+               return git_config_string(&default_ll_merge, var, value);
 
        /*
         * We are not interested in anything but "merge.<name>.variable";
@@ -254,12 +251,8 @@ static int read_merge_config(const char *var, const char *value, void *cb)
                ll_user_merge_tail = &(fn->next);
        }
 
-       if (!strcmp("name", key)) {
-               if (!value)
-                       return error("%s: lacks value", var);
-               fn->description = xstrdup(value);
-               return 0;
-       }
+       if (!strcmp("name", key))
+               return git_config_string(&fn->description, var, value);
 
        if (!strcmp("driver", key)) {
                if (!value)
@@ -285,12 +278,8 @@ static int read_merge_config(const char *var, const char *value, void *cb)
                return 0;
        }
 
-       if (!strcmp("recursive", key)) {
-               if (!value)
-                       return error("%s: lacks value", var);
-               fn->recursive = xstrdup(value);
-               return 0;
-       }
+       if (!strcmp("recursive", key))
+               return git_config_string(&fn->recursive, var, value);
 
        return 0;
 }
index 2564a7f5447b904585f629f0d1233c8a59483a40..2a800cef33ed7fb1ba7d3499459eccd824ab33e4 100644 (file)
@@ -237,6 +237,16 @@ int close_lock_file(struct lock_file *lk)
        return close(fd);
 }
 
+int reopen_lock_file(struct lock_file *lk)
+{
+       if (0 <= lk->fd)
+               die(_("BUG: reopen a lockfile that is still open"));
+       if (!lk->filename[0])
+               die(_("BUG: reopen a lockfile that has been committed"));
+       lk->fd = open(lk->filename, O_WRONLY);
+       return lk->fd;
+}
+
 int commit_lock_file(struct lock_file *lk)
 {
        char result_file[PATH_MAX];
index 95e9b1da259ef33a1c5bc7f7d07e853ebc5dbcec..cff7ac1dbd8942f3013e6fa91d30d2ea33495854 100644 (file)
 #include "sequencer.h"
 #include "line-log.h"
 
-struct decoration name_decoration = { "object names" };
-
-enum decoration_type {
-       DECORATION_NONE = 0,
-       DECORATION_REF_LOCAL,
-       DECORATION_REF_REMOTE,
-       DECORATION_REF_TAG,
-       DECORATION_REF_STASH,
-       DECORATION_REF_HEAD,
-       DECORATION_GRAFTED,
-};
+static struct decoration name_decoration = { "object names" };
 
 static char decoration_colors[][COLOR_MAXLEN] = {
        GIT_COLOR_RESET,
@@ -84,15 +74,20 @@ int parse_decorate_color_config(const char *var, const int ofs, const char *valu
 #define decorate_get_color_opt(o, ix) \
        decorate_get_color((o)->use_color, ix)
 
-static void add_name_decoration(enum decoration_type type, const char *name, struct object *obj)
+void add_name_decoration(enum decoration_type type, const char *name, struct object *obj)
 {
        int nlen = strlen(name);
-       struct name_decoration *res = xmalloc(sizeof(struct name_decoration) + nlen);
+       struct name_decoration *res = xmalloc(sizeof(*res) + nlen + 1);
        memcpy(res->name, name, nlen + 1);
        res->type = type;
        res->next = add_decoration(&name_decoration, obj, res);
 }
 
+const struct name_decoration *get_name_decoration(const struct object *obj)
+{
+       return lookup_decoration(&name_decoration, obj);
+}
+
 static int add_ref_decoration(const char *refname, const unsigned char *sha1, int flags, void *cb_data)
 {
        struct object *obj;
@@ -179,24 +174,25 @@ static void show_children(struct rev_info *opt, struct commit *commit, int abbre
 }
 
 /*
- * The caller makes sure there is no funny color before
- * calling. format_decorations makes sure the same after return.
+ * The caller makes sure there is no funny color before calling.
+ * format_decorations_extended makes sure the same after return.
  */
-void format_decorations(struct strbuf *sb,
+void format_decorations_extended(struct strbuf *sb,
                        const struct commit *commit,
-                       int use_color)
+                       int use_color,
+                       const char *prefix,
+                       const char *separator,
+                       const char *suffix)
 {
-       const char *prefix;
-       struct name_decoration *decoration;
+       const struct name_decoration *decoration;
        const char *color_commit =
                diff_get_color(use_color, DIFF_COMMIT);
        const char *color_reset =
                decorate_get_color(use_color, DECORATION_NONE);
 
-       decoration = lookup_decoration(&name_decoration, &commit->object);
+       decoration = get_name_decoration(&commit->object);
        if (!decoration)
                return;
-       prefix = " (";
        while (decoration) {
                strbuf_addstr(sb, color_commit);
                strbuf_addstr(sb, prefix);
@@ -205,11 +201,11 @@ void format_decorations(struct strbuf *sb,
                        strbuf_addstr(sb, "tag: ");
                strbuf_addstr(sb, decoration->name);
                strbuf_addstr(sb, color_reset);
-               prefix = ", ";
+               prefix = separator;
                decoration = decoration->next;
        }
        strbuf_addstr(sb, color_commit);
-       strbuf_addch(sb, ')');
+       strbuf_addstr(sb, suffix);
        strbuf_addstr(sb, color_reset);
 }
 
index d6ecd4dc46b82147c5c7e00dcfa2e9088ab00d7c..b26160c4d64b041ed31826a61d4b898c8608c0a2 100644 (file)
@@ -13,7 +13,13 @@ int log_tree_diff_flush(struct rev_info *);
 int log_tree_commit(struct rev_info *, struct commit *);
 int log_tree_opt_parse(struct rev_info *, const char **, int);
 void show_log(struct rev_info *opt);
-void format_decorations(struct strbuf *sb, const struct commit *commit, int use_color);
+void format_decorations_extended(struct strbuf *sb, const struct commit *commit,
+                            int use_color,
+                            const char *prefix,
+                            const char *separator,
+                            const char *suffix);
+#define format_decorations(strbuf, commit, color) \
+                            format_decorations_extended((strbuf), (commit), (color), " (", ", ", ")")
 void show_decorations(struct rev_info *opt, struct commit *commit);
 void log_write_email_headers(struct rev_info *opt, struct commit *commit,
                             const char **subject_p,
index 1d332b8bbbf076b819e2052c84874fb0728dae02..8ad4be897d88c691d43c30afb698a1ae952b8596 100644 (file)
@@ -163,9 +163,7 @@ static void output(struct merge_options *o, int v, const char *fmt, ...)
        if (!show(o, v))
                return;
 
-       strbuf_grow(&o->obuf, o->call_depth * 2 + 2);
-       memset(o->obuf.buf + o->obuf.len, ' ', o->call_depth * 2);
-       strbuf_setlen(&o->obuf, o->obuf.len + o->call_depth * 2);
+       strbuf_addchars(&o->obuf, ' ', o->call_depth * 2);
 
        va_start(ap, fmt);
        strbuf_vaddf(&o->obuf, fmt, ap);
@@ -1557,7 +1555,7 @@ static int blob_unchanged(const unsigned char *o_sha,
         * unchanged since their sha1s have already been compared.
         */
        if (renormalize_buffer(path, o.buf, o.len, &o) |
-           renormalize_buffer(path, a.buf, o.len, &a))
+           renormalize_buffer(path, a.buf, a.len, &a))
                ret = (o.len == a.len && !memcmp(o.buf, a.buf, o.len));
 
 error_return:
@@ -1688,10 +1686,6 @@ static int merge_content(struct merge_options *o,
 static int process_entry(struct merge_options *o,
                         const char *path, struct stage_data *entry)
 {
-       /*
-       printf("processing entry, clean cache: %s\n", index_only ? "yes": "no");
-       print_index_entry("\tpath: ", entry);
-       */
        int clean_merge = 1;
        int normalize = o->renormalize;
        unsigned o_mode = entry->stages[1].mode;
@@ -2026,22 +2020,12 @@ int merge_recursive_generic(struct merge_options *o,
        return clean ? 0 : 1;
 }
 
-static int merge_recursive_config(const char *var, const char *value, void *cb)
+static void merge_recursive_config(struct merge_options *o)
 {
-       struct merge_options *o = cb;
-       if (!strcmp(var, "merge.verbosity")) {
-               o->verbosity = git_config_int(var, value);
-               return 0;
-       }
-       if (!strcmp(var, "diff.renamelimit")) {
-               o->diff_rename_limit = git_config_int(var, value);
-               return 0;
-       }
-       if (!strcmp(var, "merge.renamelimit")) {
-               o->merge_rename_limit = git_config_int(var, value);
-               return 0;
-       }
-       return git_xmerge_config(var, value, cb);
+       git_config_get_int("merge.verbosity", &o->verbosity);
+       git_config_get_int("diff.renamelimit", &o->diff_rename_limit);
+       git_config_get_int("merge.renamelimit", &o->merge_rename_limit);
+       git_config(git_xmerge_config, NULL);
 }
 
 void init_merge_options(struct merge_options *o)
@@ -2052,7 +2036,7 @@ void init_merge_options(struct merge_options *o)
        o->diff_rename_limit = -1;
        o->merge_rename_limit = -1;
        o->renormalize = 0;
-       git_config(merge_recursive_config, o);
+       merge_recursive_config(o);
        if (getenv("GIT_MERGE_VERBOSITY"))
                o->verbosity =
                        strtol(getenv("GIT_MERGE_VERBOSITY"), NULL, 10);
index a16b9f9e936d060ba190b6c7e82ff5f25795f490..ca9d790f4d2b0f30ff585df7a6f8edf515e40a20 100644 (file)
--- a/object.c
+++ b/object.c
@@ -33,13 +33,20 @@ const char *typename(unsigned int type)
        return object_type_strings[type];
 }
 
-int type_from_string(const char *str)
+int type_from_string_gently(const char *str, ssize_t len, int gentle)
 {
        int i;
 
+       if (len < 0)
+               len = strlen(str);
+
        for (i = 1; i < ARRAY_SIZE(object_type_strings); i++)
-               if (!strcmp(str, object_type_strings[i]))
+               if (!strncmp(str, object_type_strings[i], len))
                        return i;
+
+       if (gentle)
+               return -1;
+
        die("invalid object type \"%s\"", str);
 }
 
@@ -312,7 +319,7 @@ static void add_object_array_with_mode_context(struct object *obj, const char *n
 
        if (nr >= alloc) {
                alloc = (alloc + 32) * 2;
-               objects = xrealloc(objects, alloc * sizeof(*objects));
+               REALLOC_ARRAY(objects, alloc);
                array->alloc = alloc;
                array->objects = objects;
        }
index 5e8d8ee5485a5825c4dc0a0bba1911061723e161..e028ced74c6c50459376d778c8bb9bae1d2808c3 100644 (file)
--- a/object.h
+++ b/object.h
@@ -53,7 +53,8 @@ struct object {
 };
 
 extern const char *typename(unsigned int type);
-extern int type_from_string(const char *str);
+extern int type_from_string_gently(const char *str, ssize_t, int gentle);
+#define type_from_string(str) type_from_string_gently(str, -1, 0)
 
 /*
  * Return the current number of buckets in the object hashmap.
index 5f1791a59c5e9ecd553fb9109fa774d921f777c8..8029ae35619fbff7e9e595b20ea25c379c698016 100644 (file)
@@ -111,8 +111,7 @@ static inline void push_bitmapped_commit(struct commit *commit, struct ewah_bitm
 {
        if (writer.selected_nr >= writer.selected_alloc) {
                writer.selected_alloc = (writer.selected_alloc + 32) * 2;
-               writer.selected = xrealloc(writer.selected,
-                                          writer.selected_alloc * sizeof(struct bitmapped_commit));
+               REALLOC_ARRAY(writer.selected, writer.selected_alloc);
        }
 
        writer.selected[writer.selected_nr].commit = commit;
index 91e41015316e8d5c166cdee92c453ec23a483dab..a1f3c0d34f8958c08310aa9fc77e764885b76008 100644 (file)
@@ -400,10 +400,8 @@ static int ext_index_add_object(struct object *object, const char *name)
        if (hash_ret > 0) {
                if (eindex->count >= eindex->alloc) {
                        eindex->alloc = (eindex->alloc + 16) * 3 / 2;
-                       eindex->objects = xrealloc(eindex->objects,
-                               eindex->alloc * sizeof(struct object *));
-                       eindex->hashes = xrealloc(eindex->hashes,
-                               eindex->alloc * sizeof(uint32_t));
+                       REALLOC_ARRAY(eindex->objects, eindex->alloc);
+                       REALLOC_ARRAY(eindex->hashes, eindex->alloc);
                }
 
                bitmap_pos = eindex->count;
index 9992f3ecf249c32e5be31dc047bad46a4c4ac367..6398a8aa96f2f44c0b01cf168619f1d269bc6dbb 100644 (file)
@@ -92,8 +92,7 @@ struct object_entry *packlist_alloc(struct packing_data *pdata,
 
        if (pdata->nr_objects >= pdata->nr_alloc) {
                pdata->nr_alloc = (pdata->nr_alloc  + 1024) * 3 / 2;
-               pdata->objects = xrealloc(pdata->objects,
-                                         pdata->nr_alloc * sizeof(*new_entry));
+               REALLOC_ARRAY(pdata->objects, pdata->nr_alloc);
        }
 
        new_entry = pdata->objects + pdata->nr_objects++;
index 9ccf80419b06789aa3a1171869bd4179787e5eff..33293ce2a6b8ea51516e42d01001b15a3016ca27 100644 (file)
@@ -288,13 +288,12 @@ char *index_pack_lockfile(int ip_out)
         * case, we need it to remove the corresponding .keep file
         * later on.  If we don't get that then tough luck with it.
         */
-       if (read_in_full(ip_out, packname, 46) == 46 && packname[45] == '\n' &&
-           memcmp(packname, "keep\t", 5) == 0) {
-               char path[PATH_MAX];
+       if (read_in_full(ip_out, packname, 46) == 46 && packname[45] == '\n') {
+               const char *name;
                packname[45] = 0;
-               snprintf(path, sizeof(path), "%s/pack/pack-%s.keep",
-                        get_object_directory(), packname + 5);
-               return xstrdup(path);
+               if (skip_prefix(packname, "keep\t", &name))
+                       return xstrfmt("%s/pack/pack-%s.keep",
+                                      get_object_directory(), name);
        }
        return NULL;
 }
diff --git a/pager.c b/pager.c
index 8b5cbc56e4fd57a1b9d2cad3e668df4c508a7b17..b2b805af98552061a723f3b8e2ac3093d0b897f7 100644 (file)
--- a/pager.c
+++ b/pager.c
@@ -6,19 +6,13 @@
 #define DEFAULT_PAGER "less"
 #endif
 
-struct pager_config {
-       const char *cmd;
-       int want;
-       char *value;
-};
-
 /*
  * This is split up from the rest of git so that we can do
  * something different on Windows.
  */
 
 static const char *pager_argv[] = { NULL, NULL };
-static struct child_process pager_process;
+static struct child_process pager_process = CHILD_PROCESS_INIT;
 
 static void wait_for_pager(void)
 {
@@ -155,30 +149,22 @@ int decimal_width(int number)
        return width;
 }
 
-static int pager_command_config(const char *var, const char *value, void *data)
+/* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */
+int check_pager_config(const char *cmd)
 {
-       struct pager_config *c = data;
-       if (starts_with(var, "pager.") && !strcmp(var + 6, c->cmd)) {
-               int b = git_config_maybe_bool(var, value);
+       int want = -1;
+       struct strbuf key = STRBUF_INIT;
+       const char *value = NULL;
+       strbuf_addf(&key, "pager.%s", cmd);
+       if (!git_config_get_value(key.buf, &value)) {
+               int b = git_config_maybe_bool(key.buf, value);
                if (b >= 0)
-                       c->want = b;
+                       want = b;
                else {
-                       c->want = 1;
-                       c->value = xstrdup(value);
+                       want = 1;
+                       pager_program = xstrdup(value);
                }
        }
-       return 0;
-}
-
-/* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */
-int check_pager_config(const char *cmd)
-{
-       struct pager_config c;
-       c.cmd = cmd;
-       c.want = -1;
-       c.value = NULL;
-       git_config(pager_command_config, &c);
-       if (c.value)
-               pager_program = c.value;
-       return c.want;
+       strbuf_release(&key);
+       return want;
 }
index e7dafa80d55adb9b863c23f711389e5eaa6b2c5e..80106c06bcc68782baad6afa5954b829ab17ba8d 100644 (file)
@@ -14,8 +14,12 @@ static int parse_options_usage(struct parse_opt_ctx_t *ctx,
 
 int optbug(const struct option *opt, const char *reason)
 {
-       if (opt->long_name)
+       if (opt->long_name) {
+               if (opt->short_name)
+                       return error("BUG: switch '%c' (--%s) %s",
+                                    opt->short_name, opt->long_name, reason);
                return error("BUG: option '%s' %s", opt->long_name, reason);
+       }
        return error("BUG: switch '%c' %s", opt->short_name, reason);
 }
 
@@ -347,12 +351,20 @@ static void check_typos(const char *arg, const struct option *options)
 static void parse_options_check(const struct option *opts)
 {
        int err = 0;
+       char short_opts[128];
 
+       memset(short_opts, '\0', sizeof(short_opts));
        for (; opts->type != OPTION_END; opts++) {
                if ((opts->flags & PARSE_OPT_LASTARG_DEFAULT) &&
                    (opts->flags & PARSE_OPT_OPTARG))
                        err |= optbug(opts, "uses incompatible flags "
                                        "LASTARG_DEFAULT and OPTARG");
+               if (opts->short_name) {
+                       if (0x7F <= opts->short_name)
+                               err |= optbug(opts, "invalid short name");
+                       else if (short_opts[opts->short_name]++)
+                               err |= optbug(opts, "short name already used");
+               }
                if (opts->flags & PARSE_OPT_NODASH &&
                    ((opts->flags & PARSE_OPT_OPTARG) ||
                     !(opts->flags & PARSE_OPT_NOARG) ||
diff --git a/path.c b/path.c
index 3afcdb432a009b5e1c869123139192cf1a688292..f68df0cf888124592db6c771d78d94894ffbacd9 100644 (file)
--- a/path.c
+++ b/path.c
@@ -148,10 +148,12 @@ void home_config_paths(char **global, char **xdg, char *file)
                        *global = mkpathdup("%s/.gitconfig", home);
        }
 
-       if (!xdg_home)
-               *xdg = NULL;
-       else
-               *xdg = mkpathdup("%s/git/%s", xdg_home, file);
+       if (xdg) {
+               if (!xdg_home)
+                       *xdg = NULL;
+               else
+                       *xdg = mkpathdup("%s/git/%s", xdg_home, file);
+       }
 
        free(to_free);
 }
index 31fc76b2fde8297298a7d9ffd38ea7f00eede2fa..5fd9de6ce11da25b8ddf8ece9f718023394624e6 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -70,7 +70,9 @@ static int git_pretty_formats_config(const char *var, const char *value, void *c
 
        commit_format->name = xstrdup(name);
        commit_format->format = CMIT_FMT_USERFORMAT;
-       git_config_string(&fmt, var, value);
+       if (git_config_string(&fmt, var, value))
+               return -1;
+
        if (starts_with(fmt, "format:") || starts_with(fmt, "tformat:")) {
                commit_format->is_tformat = fmt[0] == 't';
                fmt = strchr(fmt, ':') + 1;
@@ -552,31 +554,11 @@ static void add_merge_info(const struct pretty_print_context *pp,
        strbuf_addch(sb, '\n');
 }
 
-static char *get_header(const struct commit *commit, const char *msg,
-                       const char *key)
+static char *get_header(const char *msg, const char *key)
 {
-       int key_len = strlen(key);
-       const char *line = msg;
-
-       while (line) {
-               const char *eol = strchrnul(line, '\n'), *next;
-
-               if (line == eol)
-                       return NULL;
-               if (!*eol) {
-                       warning("malformed commit (header is missing newline): %s",
-                               sha1_to_hex(commit->object.sha1));
-                       next = NULL;
-               } else
-                       next = eol + 1;
-               if (eol - line > key_len &&
-                   !strncmp(line, key, key_len) &&
-                   line[key_len] == ' ') {
-                       return xmemdupz(line + key_len + 1, eol - line - key_len - 1);
-               }
-               line = next;
-       }
-       return NULL;
+       size_t len;
+       const char *v = find_commit_header(msg, key, &len);
+       return v ? xmemdupz(v, len) : NULL;
 }
 
 static char *replace_encoding_header(char *buf, const char *encoding)
@@ -622,11 +604,10 @@ const char *logmsg_reencode(const struct commit *commit,
 
        if (!output_encoding || !*output_encoding) {
                if (commit_encoding)
-                       *commit_encoding =
-                               get_header(commit, msg, "encoding");
+                       *commit_encoding = get_header(msg, "encoding");
                return msg;
        }
-       encoding = get_header(commit, msg, "encoding");
+       encoding = get_header(msg, "encoding");
        if (commit_encoding)
                *commit_encoding = encoding;
        use_encoding = encoding ? encoding : utf8;
@@ -736,9 +717,12 @@ static size_t format_person_part(struct strbuf *sb, char part,
        case 'r':       /* date, relative */
                strbuf_addstr(sb, show_ident_date(&s, DATE_RELATIVE));
                return placeholder_len;
-       case 'i':       /* date, ISO 8601 */
+       case 'i':       /* date, ISO 8601-like */
                strbuf_addstr(sb, show_ident_date(&s, DATE_ISO8601));
                return placeholder_len;
+       case 'I':       /* date, ISO 8601 strict */
+               strbuf_addstr(sb, show_ident_date(&s, DATE_ISO8601_STRICT));
+               return placeholder_len;
        }
 
 skip:
@@ -1195,6 +1179,10 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
                load_ref_decorations(DECORATE_SHORT_REFS);
                format_decorations(sb, commit, c->auto_color);
                return 1;
+       case 'D':
+               load_ref_decorations(DECORATE_SHORT_REFS);
+               format_decorations_extended(sb, commit, c->auto_color, "", ", ", "");
+               return 1;
        case 'g':               /* reflog info */
                switch(placeholder[1]) {
                case 'd':       /* reflog selector */
@@ -1393,9 +1381,7 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
                 * convert it back to chars
                 */
                padding = padding - len + local_sb.len;
-               strbuf_grow(sb, padding);
-               strbuf_setlen(sb, sb_len + padding);
-               memset(sb->buf + sb_len, ' ', sb->len - sb_len);
+               strbuf_addchars(sb, ' ', padding);
                memcpy(sb->buf + sb_len + offset, local_sb.buf,
                       local_sb.len);
        }
@@ -1670,10 +1656,8 @@ void pp_remainder(struct pretty_print_context *pp,
                first = 0;
 
                strbuf_grow(sb, linelen + indent + 20);
-               if (indent) {
-                       memset(sb->buf + sb->len, ' ', indent);
-                       strbuf_setlen(sb, sb->len + indent);
-               }
+               if (indent)
+                       strbuf_addchars(sb, ' ', indent);
                strbuf_add(sb, line, linelen);
                strbuf_addch(sb, '\n');
        }
index d7bb17cb663c2f47ad59d34ecea17c6cc977e815..e5b4938efcf329eb4f25b6f90231c35abeacbbd3 100644 (file)
--- a/prompt.c
+++ b/prompt.c
@@ -6,7 +6,7 @@
 
 static char *do_askpass(const char *cmd, const char *prompt)
 {
-       struct child_process pass;
+       struct child_process pass = CHILD_PROCESS_INIT;
        const char *args[3];
        static struct strbuf buffer = STRBUF_INIT;
        int err = 0;
@@ -15,7 +15,6 @@ static char *do_askpass(const char *cmd, const char *prompt)
        args[1] = prompt;
        args[2] = NULL;
 
-       memset(&pass, 0, sizeof(pass));
        pass.argv = args;
        pass.out = -1;
 
index 6f0057fe66a59e1239703ee4458de200304f727a..2fc1182f2267b3e9aed799eaf7df234cd36fefb9 100644 (file)
@@ -1246,24 +1246,16 @@ static struct cache_entry *refresh_cache_entry(struct cache_entry *ce,
 
 #define INDEX_FORMAT_DEFAULT 3
 
-static int index_format_config(const char *var, const char *value, void *cb)
-{
-       unsigned int *version = cb;
-       if (!strcmp(var, "index.version")) {
-               *version = git_config_int(var, value);
-               return 0;
-       }
-       return 1;
-}
-
 static unsigned int get_index_format_default(void)
 {
        char *envversion = getenv("GIT_INDEX_VERSION");
        char *endp;
+       int value;
        unsigned int version = INDEX_FORMAT_DEFAULT;
 
        if (!envversion) {
-               git_config(index_format_config, &version);
+               if (!git_config_get_int("index.version", &value))
+                       version = value;
                if (version < INDEX_FORMAT_LB || INDEX_FORMAT_UB < version) {
                        warning(_("index.version set, but the value is invalid.\n"
                                  "Using version %i"), INDEX_FORMAT_DEFAULT);
@@ -1473,6 +1465,21 @@ static struct cache_entry *create_from_disk(struct ondisk_cache_entry *ondisk,
        return ce;
 }
 
+static void check_ce_order(struct cache_entry *ce, struct cache_entry *next_ce)
+{
+       int name_compare = strcmp(ce->name, next_ce->name);
+       if (0 < name_compare)
+               die("unordered stage entries in index");
+       if (!name_compare) {
+               if (!ce_stage(ce))
+                       die("multiple stage entries for merged file '%s'",
+                               ce->name);
+               if (ce_stage(ce) > ce_stage(next_ce))
+                       die("unordered stage entries for '%s'",
+                               ce->name);
+       }
+}
+
 /* remember to discard_cache() before reading a different cache! */
 int do_read_index(struct index_state *istate, const char *path, int must_exist)
 {
@@ -1534,6 +1541,9 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)
                ce = create_from_disk(disk_ce, &consumed, previous_name);
                set_index_entry(istate, i, ce);
 
+               if (i > 0)
+                       check_ce_order(istate->cache[i - 1], ce);
+
                src_offset += consumed;
        }
        strbuf_release(&previous_name_buf);
@@ -2180,7 +2190,6 @@ int read_index_unmerged(struct index_state *istate)
                if (add_index_entry(istate, new_ce, 0))
                        return error("%s: cannot drop to stage #0",
                                     new_ce->name);
-               i = index_name_pos(istate, new_ce->name, len);
        }
        return unmerged;
 }
index 9ce8b53ccc85abcf27d7aff8f86a350ef2cd36b2..0e5174b6059174d2bcdb15ab584b747205e782dd 100644 (file)
@@ -133,7 +133,7 @@ struct reflog_walk_info {
        struct commit_reflog *last_commit_reflog;
 };
 
-void init_reflog_walk(struct reflog_walk_info** info)
+void init_reflog_walk(struct reflog_walk_info **info)
 {
        *info = xcalloc(1, sizeof(struct reflog_walk_info));
 }
index 50265f51c56431025b665abf34ac29fdce3d302b..a9bd60e32d24bf61cbc2ea879b5bfd0e0e5c5c61 100644 (file)
@@ -5,7 +5,7 @@
 
 struct reflog_walk_info;
 
-extern void init_reflog_walk(struct reflog_walk_info** info);
+extern void init_reflog_walk(struct reflog_walk_info **info);
 extern int add_reflog_for_walk(struct reflog_walk_info *info,
                struct commit *commit, const char *name);
 extern void fake_reflog_parent(struct reflog_walk_info *info,
diff --git a/refs.c b/refs.c
index 82e5b1b14f7a6e7341dfcf8fbf61ae3982851e18..ffd45e92922ec52dccccfaecf1ceaf29f9231337 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -24,6 +24,11 @@ static unsigned char refname_disposition[256] = {
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 4, 4
 };
 
+/*
+ * Used as a flag to ref_transaction_delete when a loose ref is being
+ * pruned.
+ */
+#define REF_ISPRUNING  0x0100
 /*
  * Try to read one refname component from the front of refname.
  * Return the length of the component found, or -1 if the component is
@@ -779,37 +784,32 @@ static void prime_ref_dir(struct ref_dir *dir)
                        prime_ref_dir(get_ref_dir(entry));
        }
 }
-/*
- * Return true iff refname1 and refname2 conflict with each other.
- * Two reference names conflict if one of them exactly matches the
- * leading components of the other; e.g., "foo/bar" conflicts with
- * both "foo" and with "foo/bar/baz" but not with "foo/bar" or
- * "foo/barbados".
- */
-static int names_conflict(const char *refname1, const char *refname2)
+
+static int entry_matches(struct ref_entry *entry, const char *refname)
 {
-       for (; *refname1 && *refname1 == *refname2; refname1++, refname2++)
-               ;
-       return (*refname1 == '\0' && *refname2 == '/')
-               || (*refname1 == '/' && *refname2 == '\0');
+       return refname && !strcmp(entry->name, refname);
 }
 
-struct name_conflict_cb {
-       const char *refname;
-       const char *oldrefname;
-       const char *conflicting_refname;
+struct nonmatching_ref_data {
+       const char *skip;
+       struct ref_entry *found;
 };
 
-static int name_conflict_fn(struct ref_entry *entry, void *cb_data)
+static int nonmatching_ref_fn(struct ref_entry *entry, void *vdata)
 {
-       struct name_conflict_cb *data = (struct name_conflict_cb *)cb_data;
-       if (data->oldrefname && !strcmp(data->oldrefname, entry->name))
+       struct nonmatching_ref_data *data = vdata;
+
+       if (entry_matches(entry, data->skip))
                return 0;
-       if (names_conflict(data->refname, entry->name)) {
-               data->conflicting_refname = entry->name;
-               return 1;
-       }
-       return 0;
+
+       data->found = entry;
+       return 1;
+}
+
+static void report_refname_conflict(struct ref_entry *entry,
+                                   const char *refname)
+{
+       error("'%s' exists; cannot create '%s'", entry->name, refname);
 }
 
 /*
@@ -818,21 +818,84 @@ static int name_conflict_fn(struct ref_entry *entry, void *cb_data)
  * oldrefname is non-NULL, ignore potential conflicts with oldrefname
  * (e.g., because oldrefname is scheduled for deletion in the same
  * operation).
+ *
+ * Two reference names conflict if one of them exactly matches the
+ * leading components of the other; e.g., "foo/bar" conflicts with
+ * both "foo" and with "foo/bar/baz" but not with "foo/bar" or
+ * "foo/barbados".
  */
 static int is_refname_available(const char *refname, const char *oldrefname,
                                struct ref_dir *dir)
 {
-       struct name_conflict_cb data;
-       data.refname = refname;
-       data.oldrefname = oldrefname;
-       data.conflicting_refname = NULL;
+       const char *slash;
+       size_t len;
+       int pos;
+       char *dirname;
 
-       sort_ref_dir(dir);
-       if (do_for_each_entry_in_dir(dir, 0, name_conflict_fn, &data)) {
-               error("'%s' exists; cannot create '%s'",
-                     data.conflicting_refname, refname);
+       for (slash = strchr(refname, '/'); slash; slash = strchr(slash + 1, '/')) {
+               /*
+                * We are still at a leading dir of the refname; we are
+                * looking for a conflict with a leaf entry.
+                *
+                * If we find one, we still must make sure it is
+                * not "oldrefname".
+                */
+               pos = search_ref_dir(dir, refname, slash - refname);
+               if (pos >= 0) {
+                       struct ref_entry *entry = dir->entries[pos];
+                       if (entry_matches(entry, oldrefname))
+                               return 1;
+                       report_refname_conflict(entry, refname);
+                       return 0;
+               }
+
+
+               /*
+                * Otherwise, we can try to continue our search with
+                * the next component; if we come up empty, we know
+                * there is nothing under this whole prefix.
+                */
+               pos = search_ref_dir(dir, refname, slash + 1 - refname);
+               if (pos < 0)
+                       return 1;
+
+               dir = get_ref_dir(dir->entries[pos]);
+       }
+
+       /*
+        * We are at the leaf of our refname; we want to
+        * make sure there are no directories which match it.
+        */
+       len = strlen(refname);
+       dirname = xmallocz(len + 1);
+       sprintf(dirname, "%s/", refname);
+       pos = search_ref_dir(dir, dirname, len + 1);
+       free(dirname);
+
+       if (pos >= 0) {
+               /*
+                * We found a directory named "refname". It is a
+                * problem iff it contains any ref that is not
+                * "oldrefname".
+                */
+               struct ref_entry *entry = dir->entries[pos];
+               struct ref_dir *dir = get_ref_dir(entry);
+               struct nonmatching_ref_data data;
+
+               data.skip = oldrefname;
+               sort_ref_dir(dir);
+               if (!do_for_each_entry_in_dir(dir, 0, nonmatching_ref_fn, &data))
+                       return 1;
+
+               report_refname_conflict(data.found, refname);
                return 0;
        }
+
+       /*
+        * There is no point in searching for another leaf
+        * node which matches it; such an entry would be the
+        * ref we are looking for, not a conflict.
+        */
        return 1;
 }
 
@@ -2068,7 +2131,10 @@ int dwim_log(const char *str, int len, unsigned char *sha1, char **log)
        return logs_found;
 }
 
-/* This function should make sure errno is meaningful on error */
+/*
+ * Locks a "refs/" ref returning the lock on success and NULL on failure.
+ * On failure errno is set to something meaningful.
+ */
 static struct ref_lock *lock_ref_sha1_basic(const char *refname,
                                            const unsigned char *old_sha1,
                                            int flags, int *type_p)
@@ -2169,15 +2235,6 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
        return NULL;
 }
 
-struct ref_lock *lock_ref_sha1(const char *refname, const unsigned char *old_sha1)
-{
-       char refpath[PATH_MAX];
-       if (check_refname_format(refname, 0))
-               return NULL;
-       strcpy(refpath, mkpath("refs/%s", refname));
-       return lock_ref_sha1_basic(refpath, old_sha1, 0, NULL);
-}
-
 struct ref_lock *lock_any_ref_for_update(const char *refname,
                                         const unsigned char *old_sha1,
                                         int flags, int *type_p)
@@ -2191,25 +2248,12 @@ struct ref_lock *lock_any_ref_for_update(const char *refname,
  * Write an entry to the packed-refs file for the specified refname.
  * If peeled is non-NULL, write it as the entry's peeled value.
  */
-static void write_packed_entry(int fd, char *refname, unsigned char *sha1,
+static void write_packed_entry(FILE *fh, char *refname, unsigned char *sha1,
                               unsigned char *peeled)
 {
-       char line[PATH_MAX + 100];
-       int len;
-
-       len = snprintf(line, sizeof(line), "%s %s\n",
-                      sha1_to_hex(sha1), refname);
-       /* this should not happen but just being defensive */
-       if (len > sizeof(line))
-               die("too long a refname '%s'", refname);
-       write_or_die(fd, line, len);
-
-       if (peeled) {
-               if (snprintf(line, sizeof(line), "^%s\n",
-                            sha1_to_hex(peeled)) != PEELED_LINE_LENGTH)
-                       die("internal error");
-               write_or_die(fd, line, PEELED_LINE_LENGTH);
-       }
+       fprintf_or_die(fh, "%s %s\n", sha1_to_hex(sha1), refname);
+       if (peeled)
+               fprintf_or_die(fh, "^%s\n", sha1_to_hex(peeled));
 }
 
 /*
@@ -2217,13 +2261,12 @@ static void write_packed_entry(int fd, char *refname, unsigned char *sha1,
  */
 static int write_packed_entry_fn(struct ref_entry *entry, void *cb_data)
 {
-       int *fd = cb_data;
        enum peel_status peel_status = peel_entry(entry, 0);
 
        if (peel_status != PEEL_PEELED && peel_status != PEEL_NON_TAG)
                error("internal error: %s is not a valid packed reference!",
                      entry->name);
-       write_packed_entry(*fd, entry->name, entry->u.value.sha1,
+       write_packed_entry(cb_data, entry->name, entry->u.value.sha1,
                           peel_status == PEEL_PEELED ?
                           entry->u.value.peeled : NULL);
        return 0;
@@ -2259,15 +2302,22 @@ int commit_packed_refs(void)
                get_packed_ref_cache(&ref_cache);
        int error = 0;
        int save_errno = 0;
+       FILE *out;
 
        if (!packed_ref_cache->lock)
                die("internal error: packed-refs not locked");
-       write_or_die(packed_ref_cache->lock->fd,
-                    PACKED_REFS_HEADER, strlen(PACKED_REFS_HEADER));
 
+       out = fdopen(packed_ref_cache->lock->fd, "w");
+       if (!out)
+               die_errno("unable to fdopen packed-refs descriptor");
+
+       fprintf_or_die(out, "%s", PACKED_REFS_HEADER);
        do_for_each_entry_in_dir(get_packed_ref_dir(packed_ref_cache),
-                                0, write_packed_entry_fn,
-                                &packed_ref_cache->lock->fd);
+                                0, write_packed_entry_fn, out);
+       if (fclose(out))
+               die_errno("write error");
+       packed_ref_cache->lock->fd = -1;
+
        if (commit_lock_file(packed_ref_cache->lock)) {
                save_errno = errno;
                error = -1;
@@ -2387,14 +2437,25 @@ static void try_remove_empty_parents(char *name)
 /* make sure nobody touched the ref, and unlink */
 static void prune_ref(struct ref_to_prune *r)
 {
-       struct ref_lock *lock = lock_any_ref_for_update(r->name, r->sha1,
-                                                       0, NULL);
+       struct ref_transaction *transaction;
+       struct strbuf err = STRBUF_INIT;
 
-       if (lock) {
-               unlink_or_warn(git_path("%s", r->name));
-               unlock_ref(lock);
-               try_remove_empty_parents(r->name);
+       if (check_refname_format(r->name, 0))
+               return;
+
+       transaction = ref_transaction_begin(&err);
+       if (!transaction ||
+           ref_transaction_delete(transaction, r->name, r->sha1,
+                                  REF_ISPRUNING, 1, &err) ||
+           ref_transaction_commit(transaction, NULL, &err)) {
+               ref_transaction_free(transaction);
+               error("%s", err.buf);
+               strbuf_release(&err);
+               return;
        }
+       ref_transaction_free(transaction);
+       strbuf_release(&err);
+       try_remove_empty_parents(r->name);
 }
 
 static void prune_refs(struct ref_to_prune *r)
@@ -2537,11 +2598,6 @@ int repack_without_refs(const char **refnames, int n, struct strbuf *err)
        return ret;
 }
 
-static int repack_without_ref(const char *refname)
-{
-       return repack_without_refs(&refname, 1, NULL);
-}
-
 static int delete_ref_loose(struct ref_lock *lock, int flag)
 {
        if (!(flag & REF_ISPACKED) || flag & REF_ISSYMREF) {
@@ -2559,24 +2615,22 @@ static int delete_ref_loose(struct ref_lock *lock, int flag)
 
 int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
 {
-       struct ref_lock *lock;
-       int ret = 0, flag = 0;
-
-       lock = lock_ref_sha1_basic(refname, sha1, delopt, &flag);
-       if (!lock)
+       struct ref_transaction *transaction;
+       struct strbuf err = STRBUF_INIT;
+
+       transaction = ref_transaction_begin(&err);
+       if (!transaction ||
+           ref_transaction_delete(transaction, refname, sha1, delopt,
+                                  sha1 && !is_null_sha1(sha1), &err) ||
+           ref_transaction_commit(transaction, NULL, &err)) {
+               error("%s", err.buf);
+               ref_transaction_free(transaction);
+               strbuf_release(&err);
                return 1;
-       ret |= delete_ref_loose(lock, flag);
-
-       /* removing the loose one could have resurrected an earlier
-        * packed one.  Also, if it was not loose we need to repack
-        * without it.
-        */
-       ret |= repack_without_ref(lock->ref_name);
-
-       unlink_or_warn(git_path("logs/%s", lock->ref_name));
-       clear_loose_ref_cache(&ref_cache);
-       unlock_ref(lock);
-       return ret;
+       }
+       ref_transaction_free(transaction);
+       strbuf_release(&err);
+       return 0;
 }
 
 /*
@@ -3105,7 +3159,7 @@ static int read_ref_at_ent_oldest(unsigned char *osha1, unsigned char *nsha1,
        return 1;
 }
 
-int read_ref_at(const char *refname, unsigned long at_time, int cnt,
+int read_ref_at(const char *refname, unsigned int flags, unsigned long at_time, int cnt,
                unsigned char *sha1, char **msg,
                unsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt)
 {
@@ -3123,8 +3177,12 @@ int read_ref_at(const char *refname, unsigned long at_time, int cnt,
 
        for_each_reflog_ent_reverse(refname, read_ref_at_ent, &cb);
 
-       if (!cb.reccnt)
-               die("Log for %s is empty.", refname);
+       if (!cb.reccnt) {
+               if (flags & GET_SHA1_QUIETLY)
+                       exit(128);
+               else
+                       die("Log for %s is empty.", refname);
+       }
        if (cb.found_it)
                return 0;
 
@@ -3333,43 +3391,6 @@ int for_each_reflog(each_ref_fn fn, void *cb_data)
        return retval;
 }
 
-static struct ref_lock *update_ref_lock(const char *refname,
-                                       const unsigned char *oldval,
-                                       int flags, int *type_p,
-                                       enum action_on_err onerr)
-{
-       struct ref_lock *lock;
-       lock = lock_any_ref_for_update(refname, oldval, flags, type_p);
-       if (!lock) {
-               const char *str = "Cannot lock the ref '%s'.";
-               switch (onerr) {
-               case UPDATE_REFS_MSG_ON_ERR: error(str, refname); break;
-               case UPDATE_REFS_DIE_ON_ERR: die(str, refname); break;
-               case UPDATE_REFS_QUIET_ON_ERR: break;
-               }
-       }
-       return lock;
-}
-
-static int update_ref_write(const char *action, const char *refname,
-                           const unsigned char *sha1, struct ref_lock *lock,
-                           struct strbuf *err, enum action_on_err onerr)
-{
-       if (write_ref_sha1(lock, sha1, action) < 0) {
-               const char *str = "Cannot update the ref '%s'.";
-               if (err)
-                       strbuf_addf(err, str, refname);
-
-               switch (onerr) {
-               case UPDATE_REFS_MSG_ON_ERR: error(str, refname); break;
-               case UPDATE_REFS_DIE_ON_ERR: die(str, refname); break;
-               case UPDATE_REFS_QUIET_ON_ERR: break;
-               }
-               return 1;
-       }
-       return 0;
-}
-
 /**
  * Information needed for a single ref update.  Set new_sha1 to the
  * new value or to zero to delete the ref.  To check the old value
@@ -3386,6 +3407,21 @@ struct ref_update {
        const char refname[FLEX_ARRAY];
 };
 
+/*
+ * Transaction states.
+ * OPEN:   The transaction is in a valid state and can accept new updates.
+ *         An OPEN transaction can be committed.
+ * CLOSED: A closed transaction is no longer active and no other operations
+ *         than free can be used on it in this state.
+ *         A transaction can either become closed by successfully committing
+ *         an active transaction or if there is a failure while building
+ *         the transaction thus rendering it failed/inactive.
+ */
+enum ref_transaction_state {
+       REF_TRANSACTION_OPEN   = 0,
+       REF_TRANSACTION_CLOSED = 1
+};
+
 /*
  * Data structure for holding a reference transaction, which can
  * consist of checks and updates to multiple references, carried out
@@ -3395,9 +3431,10 @@ struct ref_transaction {
        struct ref_update **updates;
        size_t alloc;
        size_t nr;
+       enum ref_transaction_state state;
 };
 
-struct ref_transaction *ref_transaction_begin(void)
+struct ref_transaction *ref_transaction_begin(struct strbuf *err)
 {
        return xcalloc(1, sizeof(struct ref_transaction));
 }
@@ -3437,6 +3474,9 @@ int ref_transaction_update(struct ref_transaction *transaction,
 {
        struct ref_update *update;
 
+       if (transaction->state != REF_TRANSACTION_OPEN)
+               die("BUG: update called for transaction that is not open");
+
        if (have_old && !old_sha1)
                die("BUG: have_old is true but old_sha1 is NULL");
 
@@ -3449,44 +3489,84 @@ int ref_transaction_update(struct ref_transaction *transaction,
        return 0;
 }
 
-void ref_transaction_create(struct ref_transaction *transaction,
-                           const char *refname,
-                           const unsigned char *new_sha1,
-                           int flags)
+int ref_transaction_create(struct ref_transaction *transaction,
+                          const char *refname,
+                          const unsigned char *new_sha1,
+                          int flags,
+                          struct strbuf *err)
 {
-       struct ref_update *update = add_update(transaction, refname);
+       struct ref_update *update;
+
+       if (transaction->state != REF_TRANSACTION_OPEN)
+               die("BUG: create called for transaction that is not open");
+
+       if (!new_sha1 || is_null_sha1(new_sha1))
+               die("BUG: create ref with null new_sha1");
+
+       update = add_update(transaction, refname);
 
-       assert(!is_null_sha1(new_sha1));
        hashcpy(update->new_sha1, new_sha1);
        hashclr(update->old_sha1);
        update->flags = flags;
        update->have_old = 1;
+       return 0;
 }
 
-void ref_transaction_delete(struct ref_transaction *transaction,
-                           const char *refname,
-                           const unsigned char *old_sha1,
-                           int flags, int have_old)
+int ref_transaction_delete(struct ref_transaction *transaction,
+                          const char *refname,
+                          const unsigned char *old_sha1,
+                          int flags, int have_old,
+                          struct strbuf *err)
 {
-       struct ref_update *update = add_update(transaction, refname);
+       struct ref_update *update;
+
+       if (transaction->state != REF_TRANSACTION_OPEN)
+               die("BUG: delete called for transaction that is not open");
+
+       if (have_old && !old_sha1)
+               die("BUG: have_old is true but old_sha1 is NULL");
 
+       update = add_update(transaction, refname);
        update->flags = flags;
        update->have_old = have_old;
        if (have_old) {
                assert(!is_null_sha1(old_sha1));
                hashcpy(update->old_sha1, old_sha1);
        }
+       return 0;
 }
 
 int update_ref(const char *action, const char *refname,
               const unsigned char *sha1, const unsigned char *oldval,
               int flags, enum action_on_err onerr)
 {
-       struct ref_lock *lock;
-       lock = update_ref_lock(refname, oldval, flags, NULL, onerr);
-       if (!lock)
+       struct ref_transaction *t;
+       struct strbuf err = STRBUF_INIT;
+
+       t = ref_transaction_begin(&err);
+       if (!t ||
+           ref_transaction_update(t, refname, sha1, oldval, flags,
+                                  !!oldval, &err) ||
+           ref_transaction_commit(t, action, &err)) {
+               const char *str = "update_ref failed for ref '%s': %s";
+
+               ref_transaction_free(t);
+               switch (onerr) {
+               case UPDATE_REFS_MSG_ON_ERR:
+                       error(str, refname, err.buf);
+                       break;
+               case UPDATE_REFS_DIE_ON_ERR:
+                       die(str, refname, err.buf);
+                       break;
+               case UPDATE_REFS_QUIET_ON_ERR:
+                       break;
+               }
+               strbuf_release(&err);
                return 1;
-       return update_ref_write(action, refname, sha1, lock, NULL, onerr);
+       }
+       strbuf_release(&err);
+       ref_transaction_free(t);
+       return 0;
 }
 
 static int ref_update_compare(const void *r1, const void *r2)
@@ -3520,8 +3600,13 @@ int ref_transaction_commit(struct ref_transaction *transaction,
        int n = transaction->nr;
        struct ref_update **updates = transaction->updates;
 
-       if (!n)
+       if (transaction->state != REF_TRANSACTION_OPEN)
+               die("BUG: commit called for transaction that is not open");
+
+       if (!n) {
+               transaction->state = REF_TRANSACTION_CLOSED;
                return 0;
+       }
 
        /* Allocate work space */
        delnames = xmalloc(sizeof(*delnames) * n);
@@ -3536,12 +3621,12 @@ int ref_transaction_commit(struct ref_transaction *transaction,
        for (i = 0; i < n; i++) {
                struct ref_update *update = updates[i];
 
-               update->lock = update_ref_lock(update->refname,
-                                              (update->have_old ?
-                                               update->old_sha1 : NULL),
-                                              update->flags,
-                                              &update->type,
-                                              UPDATE_REFS_QUIET_ON_ERR);
+               update->lock = lock_any_ref_for_update(update->refname,
+                                                      (update->have_old ?
+                                                       update->old_sha1 :
+                                                       NULL),
+                                                      update->flags,
+                                                      &update->type);
                if (!update->lock) {
                        if (err)
                                strbuf_addf(err, "Cannot lock the ref '%s'.",
@@ -3556,14 +3641,15 @@ int ref_transaction_commit(struct ref_transaction *transaction,
                struct ref_update *update = updates[i];
 
                if (!is_null_sha1(update->new_sha1)) {
-                       ret = update_ref_write(msg,
-                                              update->refname,
-                                              update->new_sha1,
-                                              update->lock, err,
-                                              UPDATE_REFS_QUIET_ON_ERR);
-                       update->lock = NULL; /* freed by update_ref_write */
-                       if (ret)
+                       ret = write_ref_sha1(update->lock, update->new_sha1,
+                                            msg);
+                       update->lock = NULL; /* freed by write_ref_sha1 */
+                       if (ret) {
+                               if (err)
+                                       strbuf_addf(err, "Cannot update the ref '%s'.",
+                                                   update->refname);
                                goto cleanup;
+                       }
                }
        }
 
@@ -3572,8 +3658,9 @@ int ref_transaction_commit(struct ref_transaction *transaction,
                struct ref_update *update = updates[i];
 
                if (update->lock) {
-                       delnames[delnum++] = update->lock->ref_name;
                        ret |= delete_ref_loose(update->lock, update->type);
+                       if (!(update->flags & REF_ISPRUNING))
+                               delnames[delnum++] = update->lock->ref_name;
                }
        }
 
@@ -3583,6 +3670,8 @@ int ref_transaction_commit(struct ref_transaction *transaction,
        clear_loose_ref_cache(&ref_cache);
 
 cleanup:
+       transaction->state = REF_TRANSACTION_CLOSED;
+
        for (i = 0; i < n; i++)
                if (updates[i]->lock)
                        unlock_ref(updates[i]->lock);
diff --git a/refs.h b/refs.h
index ec46acdde7b67d3531a4c0e18d33901d2a4f307a..2328f06e77d34d76a1f4affedcca2c51ff9e0093 100644 (file)
--- a/refs.h
+++ b/refs.h
@@ -10,6 +10,38 @@ struct ref_lock {
        int force_write;
 };
 
+/*
+ * A ref_transaction represents a collection of ref updates
+ * that should succeed or fail together.
+ *
+ * Calling sequence
+ * ----------------
+ * - Allocate and initialize a `struct ref_transaction` by calling
+ *   `ref_transaction_begin()`.
+ *
+ * - List intended ref updates by calling functions like
+ *   `ref_transaction_update()` and `ref_transaction_create()`.
+ *
+ * - Call `ref_transaction_commit()` to execute the transaction.
+ *   If this succeeds, the ref updates will have taken place and
+ *   the transaction cannot be rolled back.
+ *
+ * - At any time call `ref_transaction_free()` to discard the
+ *   transaction and free associated resources.  In particular,
+ *   this rolls back the transaction if it has not been
+ *   successfully committed.
+ *
+ * Error handling
+ * --------------
+ *
+ * On error, transaction functions append a message about what
+ * went wrong to the 'err' argument.  The message mentions what
+ * ref was being updated (if any) when the error occurred so it
+ * can be passed to 'die' or 'error' as-is.
+ *
+ * The message is appended to err without first clearing err.
+ * err will not be '\n' terminated.
+ */
 struct ref_transaction;
 
 /*
@@ -77,7 +109,7 @@ static inline const char *has_glob_specials(const char *pattern)
 extern int for_each_rawref(each_ref_fn, void *);
 
 extern void warn_dangling_symref(FILE *fp, const char *msg_fmt, const char *refname);
-extern void warn_dangling_symrefs(FILE *fp, const char *msg_fmt, const struct string_listrefnames);
+extern void warn_dangling_symrefs(FILE *fp, const char *msg_fmt, const struct string_list *refnames);
 
 /*
  * Lock the packed-refs file for writing.  Flags is passed to
@@ -141,14 +173,17 @@ extern int is_branch(const char *refname);
 extern int peel_ref(const char *refname, unsigned char *sha1);
 
 /*
- * Locks a "refs/" ref returning the lock on success and NULL on failure.
- * On failure errno is set to something meaningful.
+ * Flags controlling lock_any_ref_for_update(), ref_transaction_update(),
+ * ref_transaction_create(), etc.
+ * REF_NODEREF: act on the ref directly, instead of dereferencing
+ *              symbolic references.
+ *
+ * Flags >= 0x100 are reserved for internal use.
  */
-extern struct ref_lock *lock_ref_sha1(const char *refname, const unsigned char *old_sha1);
-
-/** Locks any ref (for 'HEAD' type refs). */
 #define REF_NODEREF    0x01
-/* errno is set to something meaningful on failure */
+/*
+ * This function sets errno to something meaningful on failure.
+ */
 extern struct ref_lock *lock_any_ref_for_update(const char *refname,
                                                const unsigned char *old_sha1,
                                                int flags, int *type_p);
@@ -171,7 +206,8 @@ extern int write_ref_sha1(struct ref_lock *lock, const unsigned char *sha1, cons
 int log_ref_setup(const char *refname, char *logfile, int bufsize);
 
 /** Reads log for the value of ref during at_time. **/
-extern int read_ref_at(const char *refname, unsigned long at_time, int cnt,
+extern int read_ref_at(const char *refname, unsigned int flags,
+                      unsigned long at_time, int cnt,
                       unsigned char *sha1, char **msg,
                       unsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt);
 
@@ -232,7 +268,7 @@ enum action_on_err {
  * Begin a reference transaction.  The reference transaction must
  * be freed by calling ref_transaction_free().
  */
-struct ref_transaction *ref_transaction_begin(void);
+struct ref_transaction *ref_transaction_begin(struct strbuf *err);
 
 /*
  * The following functions add a reference check or update to a
@@ -250,7 +286,7 @@ struct ref_transaction *ref_transaction_begin(void);
  * it must not have existed beforehand.
  * Function returns 0 on success and non-zero on failure. A failure to update
  * means that the transaction as a whole has failed and will need to be
- * rolled back. On failure the err buffer will be updated.
+ * rolled back.
  */
 int ref_transaction_update(struct ref_transaction *transaction,
                           const char *refname,
@@ -264,28 +300,34 @@ int ref_transaction_update(struct ref_transaction *transaction,
  * that the reference should have after the update; it must not be the
  * null SHA-1.  It is verified that the reference does not exist
  * already.
+ * Function returns 0 on success and non-zero on failure. A failure to create
+ * means that the transaction as a whole has failed and will need to be
+ * rolled back.
  */
-void ref_transaction_create(struct ref_transaction *transaction,
-                           const char *refname,
-                           const unsigned char *new_sha1,
-                           int flags);
+int ref_transaction_create(struct ref_transaction *transaction,
+                          const char *refname,
+                          const unsigned char *new_sha1,
+                          int flags,
+                          struct strbuf *err);
 
 /*
  * Add a reference deletion to transaction.  If have_old is true, then
  * old_sha1 holds the value that the reference should have had before
  * the update (which must not be the null SHA-1).
+ * Function returns 0 on success and non-zero on failure. A failure to delete
+ * means that the transaction as a whole has failed and will need to be
+ * rolled back.
  */
-void ref_transaction_delete(struct ref_transaction *transaction,
-                           const char *refname,
-                           const unsigned char *old_sha1,
-                           int flags, int have_old);
+int ref_transaction_delete(struct ref_transaction *transaction,
+                          const char *refname,
+                          const unsigned char *old_sha1,
+                          int flags, int have_old,
+                          struct strbuf *err);
 
 /*
  * Commit all of the changes that have been queued in transaction, as
  * atomically as possible.  Return a nonzero value if there is a
  * problem.
- * If err is non-NULL we will add an error string to it to explain why
- * the transaction failed. The string does not end in newline.
  */
 int ref_transaction_commit(struct ref_transaction *transaction,
                           const char *msg, struct strbuf *err);
index 558b9fecdf5bca1deb2577a51b1e8473e3350911..cd626d15e59832e6fee74b2ca845a23a5fce77ee 100644 (file)
@@ -221,7 +221,7 @@ static int show_http_message(struct strbuf *type, struct strbuf *charset,
        return 0;
 }
 
-static struct discoverydiscover_refs(const char *service, int for_push)
+static struct discovery *discover_refs(const char *service, int for_push)
 {
        struct strbuf exp = STRBUF_INIT;
        struct strbuf type = STRBUF_INIT;
@@ -623,10 +623,9 @@ static int rpc_service(struct rpc_state *rpc, struct discovery *heads)
        const char *svc = rpc->service_name;
        struct strbuf buf = STRBUF_INIT;
        struct strbuf *preamble = rpc->stdin_preamble;
-       struct child_process client;
+       struct child_process client = CHILD_PROCESS_INIT;
        int err = 0;
 
-       memset(&client, 0, sizeof(client));
        client.in = -1;
        client.out = -1;
        client.git_cmd = 1;
index 686e07d317bf157461f0ce680958a466675c80bc..48bf6eb93b361a736d96e701749c16bae8d169a8 100644 (file)
@@ -175,7 +175,7 @@ static int cmd_import(const char *line)
        char *note_msg;
        unsigned char head_sha1[20];
        unsigned int startrev;
-       struct child_process svndump_proc;
+       struct child_process svndump_proc = CHILD_PROCESS_INIT;
        const char *command = "svnrdump";
 
        if (read_ref(private_ref, head_sha1))
@@ -200,7 +200,6 @@ static int cmd_import(const char *line)
                if(dumpin_fd < 0)
                        die_errno("Couldn't open svn dump file %s.", url);
        } else {
-               memset(&svndump_proc, 0, sizeof(struct child_process));
                svndump_proc.out = -1;
                argv_array_push(&svndump_proc.args, command);
                argv_array_push(&svndump_proc.args, "dump");
index 3d6c86a36f26406305d58505b10db3f747a2546c..ce785f8953bd8a51ef1c3ce57da5c8e7cce7cef5 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -42,6 +42,7 @@ struct rewrites {
 static struct remote **remotes;
 static int remotes_alloc;
 static int remotes_nr;
+static struct hashmap remotes_hash;
 
 static struct branch **branches;
 static int branches_alloc;
@@ -136,26 +137,51 @@ static void add_url_alias(struct remote *remote, const char *url)
        add_pushurl_alias(remote, url);
 }
 
+struct remotes_hash_key {
+       const char *str;
+       int len;
+};
+
+static int remotes_hash_cmp(const struct remote *a, const struct remote *b, const struct remotes_hash_key *key)
+{
+       if (key)
+               return strncmp(a->name, key->str, key->len) || a->name[key->len];
+       else
+               return strcmp(a->name, b->name);
+}
+
+static inline void init_remotes_hash(void)
+{
+       if (!remotes_hash.cmpfn)
+               hashmap_init(&remotes_hash, (hashmap_cmp_fn)remotes_hash_cmp, 0);
+}
+
 static struct remote *make_remote(const char *name, int len)
 {
-       struct remote *ret;
-       int i;
+       struct remote *ret, *replaced;
+       struct remotes_hash_key lookup;
+       struct hashmap_entry lookup_entry;
 
-       for (i = 0; i < remotes_nr; i++) {
-               if (len ? (!strncmp(name, remotes[i]->name, len) &&
-                          !remotes[i]->name[len]) :
-                   !strcmp(name, remotes[i]->name))
-                       return remotes[i];
-       }
+       if (!len)
+               len = strlen(name);
+
+       init_remotes_hash();
+       lookup.str = name;
+       lookup.len = len;
+       hashmap_entry_init(&lookup_entry, memhash(name, len));
+
+       if ((ret = hashmap_get(&remotes_hash, &lookup_entry, &lookup)) != NULL)
+               return ret;
 
        ret = xcalloc(1, sizeof(struct remote));
        ret->prune = -1;  /* unspecified */
        ALLOC_GROW(remotes, remotes_nr + 1, remotes_alloc);
        remotes[remotes_nr++] = ret;
-       if (len)
-               ret->name = xstrndup(name, len);
-       else
-               ret->name = xstrdup(name);
+       ret->name = xstrndup(name, len);
+
+       hashmap_entry_init(ret, lookup_entry.hash);
+       replaced = hashmap_put(&remotes_hash, ret);
+       assert(replaced == NULL);  /* no previous entry overwritten */
        return ret;
 }
 
@@ -717,13 +743,16 @@ struct remote *pushremote_get(const char *name)
 
 int remote_is_configured(const char *name)
 {
-       int i;
+       struct remotes_hash_key lookup;
+       struct hashmap_entry lookup_entry;
        read_config();
 
-       for (i = 0; i < remotes_nr; i++)
-               if (!strcmp(name, remotes[i]->name))
-                       return 1;
-       return 0;
+       init_remotes_hash();
+       lookup.str = name;
+       lookup.len = strlen(name);
+       hashmap_entry_init(&lookup_entry, memhash(name, lookup.len));
+
+       return hashmap_get(&remotes_hash, &lookup_entry, &lookup) != NULL;
 }
 
 int for_each_remote(each_remote_fn fn, void *priv)
@@ -833,21 +862,14 @@ static int match_name_with_pattern(const char *key, const char *name,
        ret = !strncmp(name, key, klen) && namelen >= klen + ksuffixlen &&
                !memcmp(name + namelen - ksuffixlen, kstar + 1, ksuffixlen);
        if (ret && value) {
+               struct strbuf sb = STRBUF_INIT;
                const char *vstar = strchr(value, '*');
-               size_t vlen;
-               size_t vsuffixlen;
                if (!vstar)
                        die("Value '%s' of pattern has no '*'", value);
-               vlen = vstar - value;
-               vsuffixlen = strlen(vstar + 1);
-               *result = xmalloc(vlen + vsuffixlen +
-                                 strlen(name) -
-                                 klen - ksuffixlen + 1);
-               strncpy(*result, value, vlen);
-               strncpy(*result + vlen,
-                       name + klen, namelen - klen - ksuffixlen);
-               strcpy(*result + vlen + namelen - klen - ksuffixlen,
-                      vstar + 1);
+               strbuf_add(&sb, value, vstar - value);
+               strbuf_add(&sb, name + klen, namelen - klen - ksuffixlen);
+               strbuf_addstr(&sb, vstar + 1);
+               *result = strbuf_detach(&sb, NULL);
        }
        return ret;
 }
@@ -1893,7 +1915,8 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
 
        init_revisions(&revs, NULL);
        setup_revisions(rev_argc, rev_argv, &revs, NULL);
-       prepare_revision_walk(&revs);
+       if (prepare_revision_walk(&revs))
+               die("revision walk setup failed");
 
        /* ... and count the commits on each side. */
        *num_ours = 0;
@@ -1920,7 +1943,7 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
 int format_tracking_info(struct branch *branch, struct strbuf *sb)
 {
        int ours, theirs;
-       const char *base;
+       char *base;
        int upstream_is_gone = 0;
 
        switch (stat_tracking_info(branch, &ours, &theirs)) {
@@ -1936,8 +1959,7 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
                break;
        }
 
-       base = branch->merge[0]->dst;
-       base = shorten_unambiguous_ref(base, 0);
+       base = shorten_unambiguous_ref(branch->merge[0]->dst, 0);
        if (upstream_is_gone) {
                strbuf_addf(sb,
                        _("Your branch is based on '%s', but the upstream is gone.\n"),
@@ -1983,6 +2005,7 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
                        strbuf_addf(sb,
                                _("  (use \"git pull\" to merge the remote branch into yours)\n"));
        }
+       free(base);
        return 1;
 }
 
index 917d383a80ddbfa377f10c3d1a4e132336065c2c..8b62efd2adcb74c7e46d3f918a25658d6f6ce16f 100644 (file)
--- a/remote.h
+++ b/remote.h
@@ -2,6 +2,7 @@
 #define REMOTE_H
 
 #include "parse-options.h"
+#include "hashmap.h"
 
 enum {
        REMOTE_CONFIG,
@@ -10,6 +11,8 @@ enum {
 };
 
 struct remote {
+       struct hashmap_entry ent;  /* must be first */
+
        const char *name;
        int origin;
 
index d84b495895bc6d42980c388ed03c560174604f92..20b18add42d2551a227eaac8125fe806006d2856 100644 (file)
--- a/rerere.c
+++ b/rerere.c
@@ -573,15 +573,11 @@ static int do_plain_rerere(struct string_list *rr, int fd)
        return write_rr(rr, fd);
 }
 
-static int git_rerere_config(const char *var, const char *value, void *cb)
+static void git_rerere_config(void)
 {
-       if (!strcmp(var, "rerere.enabled"))
-               rerere_enabled = git_config_bool(var, value);
-       else if (!strcmp(var, "rerere.autoupdate"))
-               rerere_autoupdate = git_config_bool(var, value);
-       else
-               return git_default_config(var, value, cb);
-       return 0;
+       git_config_get_bool("rerere.enabled", &rerere_enabled);
+       git_config_get_bool("rerere.autoupdate", &rerere_autoupdate);
+       git_config(git_default_config, NULL);
 }
 
 static int is_rerere_enabled(void)
@@ -606,7 +602,7 @@ int setup_rerere(struct string_list *merge_rr, int flags)
 {
        int fd;
 
-       git_config(git_rerere_config, NULL);
+       git_rerere_config();
        if (!is_rerere_enabled())
                return -1;
 
@@ -699,24 +695,6 @@ static void unlink_rr_item(const char *name)
        rmdir(git_path("rr-cache/%s", name));
 }
 
-struct rerere_gc_config_cb {
-       int cutoff_noresolve;
-       int cutoff_resolve;
-};
-
-static int git_rerere_gc_config(const char *var, const char *value, void *cb)
-{
-       struct rerere_gc_config_cb *cf = cb;
-
-       if (!strcmp(var, "gc.rerereresolved"))
-               cf->cutoff_resolve = git_config_int(var, value);
-       else if (!strcmp(var, "gc.rerereunresolved"))
-               cf->cutoff_noresolve = git_config_int(var, value);
-       else
-               return git_default_config(var, value, cb);
-       return 0;
-}
-
 void rerere_gc(struct string_list *rr)
 {
        struct string_list to_remove = STRING_LIST_INIT_DUP;
@@ -724,9 +702,12 @@ void rerere_gc(struct string_list *rr)
        struct dirent *e;
        int i, cutoff;
        time_t now = time(NULL), then;
-       struct rerere_gc_config_cb cf = { 15, 60 };
+       int cutoff_noresolve = 15;
+       int cutoff_resolve = 60;
 
-       git_config(git_rerere_gc_config, &cf);
+       git_config_get_int("gc.rerereresolved", &cutoff_resolve);
+       git_config_get_int("gc.rerereunresolved", &cutoff_noresolve);
+       git_config(git_default_config, NULL);
        dir = opendir(git_path("rr-cache"));
        if (!dir)
                die_errno("unable to open rr-cache directory");
@@ -736,12 +717,12 @@ void rerere_gc(struct string_list *rr)
 
                then = rerere_last_used_at(e->d_name);
                if (then) {
-                       cutoff = cf.cutoff_resolve;
+                       cutoff = cutoff_resolve;
                } else {
                        then = rerere_created_at(e->d_name);
                        if (!then)
                                continue;
-                       cutoff = cf.cutoff_noresolve;
+                       cutoff = cutoff_noresolve;
                }
                if (then < now - cutoff * 86400)
                        string_list_append(&to_remove, e->d_name);
index 4aa06c9a519aa289f177487b41e3f6c5b1213ef4..2956c2edf2f0f88bd9fb15682e31e3478df44a03 100644 (file)
--- a/rerere.h
+++ b/rerere.h
@@ -24,6 +24,6 @@ extern void rerere_clear(struct string_list *);
 extern void rerere_gc(struct string_list *);
 
 #define OPT_RERERE_AUTOUPDATE(v) OPT_UYN(0, "rerere-autoupdate", (v), \
-       "update the index with reused conflict resolution if possible")
+       N_("update the index with reused conflict resolution if possible"))
 
 #endif
index 615535c98453336323a437530132f27824b51ac2..e498b7c3394dda23cef3719ebf1f25877d613d4e 100644 (file)
@@ -473,7 +473,7 @@ static int rev_compare_tree(struct rev_info *revs,
                 * If we are simplifying by decoration, then the commit
                 * is worth showing if it has a tag pointing at it.
                 */
-               if (lookup_decoration(&name_decoration, &commit->object))
+               if (get_name_decoration(&commit->object))
                        return REV_TREE_DIFFERENT;
                /*
                 * A commit that is not pointed by a tag is uninteresting
@@ -1397,7 +1397,7 @@ static void prepare_show_merge(struct rev_info *revs)
                        continue;
                if (ce_path_match(ce, &revs->prune_data, NULL)) {
                        prune_num++;
-                       prune = xrealloc(prune, sizeof(*prune) * prune_num);
+                       REALLOC_ARRAY(prune, prune_num);
                        prune[prune_num-2] = ce->name;
                        prune[prune_num-1] = NULL;
                }
index 35a3ebf07b1792ac7b0ecef30781223591413093..761f0fde40c91a3cc910c092c5aa9ad56f2f0042 100644 (file)
@@ -8,6 +8,12 @@
 # define SHELL_PATH "/bin/sh"
 #endif
 
+void child_process_init(struct child_process *child)
+{
+       memset(child, 0, sizeof(*child));
+       argv_array_init(&child->args);
+}
+
 struct child_to_clean {
        pid_t pid;
        struct child_to_clean *next;
@@ -555,31 +561,21 @@ int run_command(struct child_process *cmd)
        return finish_command(cmd);
 }
 
-static void prepare_run_command_v_opt(struct child_process *cmd,
-                                     const char **argv,
-                                     int opt)
-{
-       memset(cmd, 0, sizeof(*cmd));
-       cmd->argv = argv;
-       cmd->no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0;
-       cmd->git_cmd = opt & RUN_GIT_CMD ? 1 : 0;
-       cmd->stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0;
-       cmd->silent_exec_failure = opt & RUN_SILENT_EXEC_FAILURE ? 1 : 0;
-       cmd->use_shell = opt & RUN_USING_SHELL ? 1 : 0;
-       cmd->clean_on_exit = opt & RUN_CLEAN_ON_EXIT ? 1 : 0;
-}
-
 int run_command_v_opt(const char **argv, int opt)
 {
-       struct child_process cmd;
-       prepare_run_command_v_opt(&cmd, argv, opt);
-       return run_command(&cmd);
+       return run_command_v_opt_cd_env(argv, opt, NULL, NULL);
 }
 
 int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const char *const *env)
 {
-       struct child_process cmd;
-       prepare_run_command_v_opt(&cmd, argv, opt);
+       struct child_process cmd = CHILD_PROCESS_INIT;
+       cmd.argv = argv;
+       cmd.no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0;
+       cmd.git_cmd = opt & RUN_GIT_CMD ? 1 : 0;
+       cmd.stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0;
+       cmd.silent_exec_failure = opt & RUN_SILENT_EXEC_FAILURE ? 1 : 0;
+       cmd.use_shell = opt & RUN_USING_SHELL ? 1 : 0;
+       cmd.clean_on_exit = opt & RUN_CLEAN_ON_EXIT ? 1 : 0;
        cmd.dir = dir;
        cmd.env = env;
        return run_command(&cmd);
@@ -763,14 +759,13 @@ char *find_hook(const char *name)
 
 int run_hook_ve(const char *const *env, const char *name, va_list args)
 {
-       struct child_process hook;
+       struct child_process hook = CHILD_PROCESS_INIT;
        const char *p;
 
        p = find_hook(name);
        if (!p)
                return 0;
 
-       memset(&hook, 0, sizeof(hook));
        argv_array_push(&hook.args, p);
        while ((p = va_arg(args, const char *)))
                argv_array_push(&hook.args, p);
index ea73de309bc65c3d00bb34ad84824ba72d85cbfe..1b135d1c960aa58e2fa4ad44ecc195835daac69a 100644 (file)
@@ -44,6 +44,9 @@ struct child_process {
        unsigned clean_on_exit:1;
 };
 
+#define CHILD_PROCESS_INIT { NULL, ARGV_ARRAY_INIT }
+void child_process_init(struct child_process *);
+
 int start_command(struct child_process *);
 int finish_command(struct child_process *);
 int run_command(struct child_process *);
index 6129b0fd8e8e1961ab4c74de4f421c41c7786b42..8b4cbf049c243b8cdc1add94ddf1bf50bcbd8df9 100644 (file)
@@ -47,7 +47,7 @@ static int pack_objects(int fd, struct ref *refs, struct sha1_array *extra, stru
                NULL,
                NULL,
        };
-       struct child_process po;
+       struct child_process po = CHILD_PROCESS_INIT;
        int i;
 
        i = 4;
@@ -59,7 +59,6 @@ static int pack_objects(int fd, struct ref *refs, struct sha1_array *extra, stru
                argv[i++] = "-q";
        if (args->progress)
                argv[i++] = "--progress";
-       memset(&po, 0, sizeof(po));
        po.argv = argv;
        po.in = -1;
        po.out = args->stateless_rpc ? -1 : fd;
index 3c060e054720b7b17f9a868cabb1a0ef62aa1b50..5e8a207474bc6971a0de4f9ff6160a5681ac7b6d 100644 (file)
@@ -237,23 +237,33 @@ static int error_dirty_index(struct replay_opts *opts)
 static int fast_forward_to(const unsigned char *to, const unsigned char *from,
                        int unborn, struct replay_opts *opts)
 {
-       struct ref_lock *ref_lock;
+       struct ref_transaction *transaction;
        struct strbuf sb = STRBUF_INIT;
-       int ret;
+       struct strbuf err = STRBUF_INIT;
 
        read_cache();
        if (checkout_fast_forward(from, to, 1))
                exit(128); /* the callee should have complained already */
-       ref_lock = lock_any_ref_for_update("HEAD", unborn ? null_sha1 : from,
-                                          0, NULL);
-       if (!ref_lock)
-               return error(_("Failed to lock HEAD during fast_forward_to"));
 
        strbuf_addf(&sb, "%s: fast-forward", action_name(opts));
-       ret = write_ref_sha1(ref_lock, to, sb.buf);
+
+       transaction = ref_transaction_begin(&err);
+       if (!transaction ||
+           ref_transaction_update(transaction, "HEAD",
+                                  to, unborn ? null_sha1 : from,
+                                  0, 1, &err) ||
+           ref_transaction_commit(transaction, sb.buf, &err)) {
+               ref_transaction_free(transaction);
+               error("%s", err.buf);
+               strbuf_release(&sb);
+               strbuf_release(&err);
+               return -1;
+       }
 
        strbuf_release(&sb);
-       return ret;
+       strbuf_release(&err);
+       ref_transaction_free(transaction);
+       return 0;
 }
 
 static int do_recursive_merge(struct commit *base, struct commit *next,
index 9ec744e9f2da294a21ac02b46f0ea0b35889ae54..31f4a749fbad73b9f7bc1f1ebf9b11fd743ab374 100644 (file)
@@ -4,45 +4,80 @@
 #include "commit.h"
 #include "tag.h"
 
-/* refs */
-static FILE *info_ref_fp;
+/*
+ * Create the file "path" by writing to a temporary file and renaming
+ * it into place. The contents of the file come from "generate", which
+ * should return non-zero if it encounters an error.
+ */
+static int update_info_file(char *path, int (*generate)(FILE *))
+{
+       char *tmp = mkpathdup("%s_XXXXXX", path);
+       int ret = -1;
+       int fd = -1;
+       FILE *fp = NULL;
+
+       safe_create_leading_directories(path);
+       fd = mkstemp(tmp);
+       if (fd < 0)
+               goto out;
+       fp = fdopen(fd, "w");
+       if (!fp)
+               goto out;
+       ret = generate(fp);
+       if (ret)
+               goto out;
+       if (fclose(fp))
+               goto out;
+       if (adjust_shared_perm(tmp) < 0)
+               goto out;
+       if (rename(tmp, path) < 0)
+               goto out;
+       ret = 0;
+
+out:
+       if (ret) {
+               error("unable to update %s: %s", path, strerror(errno));
+               if (fp)
+                       fclose(fp);
+               else if (fd >= 0)
+                       close(fd);
+               unlink(tmp);
+       }
+       free(tmp);
+       return ret;
+}
 
 static int add_info_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
 {
+       FILE *fp = cb_data;
        struct object *o = parse_object(sha1);
        if (!o)
                return -1;
 
-       fprintf(info_ref_fp, "%s        %s\n", sha1_to_hex(sha1), path);
+       if (fprintf(fp, "%s     %s\n", sha1_to_hex(sha1), path) < 0)
+               return -1;
+
        if (o->type == OBJ_TAG) {
                o = deref_tag(o, path, 0);
                if (o)
-                       fprintf(info_ref_fp, "%s        %s^{}\n",
-                               sha1_to_hex(o->sha1), path);
+                       if (fprintf(fp, "%s     %s^{}\n",
+                               sha1_to_hex(o->sha1), path) < 0)
+                               return -1;
        }
        return 0;
 }
 
+static int generate_info_refs(FILE *fp)
+{
+       return for_each_ref(add_info_ref, fp);
+}
+
 static int update_info_refs(int force)
 {
-       char *path0 = git_pathdup("info/refs");
-       int len = strlen(path0);
-       char *path1 = xmalloc(len + 2);
-
-       strcpy(path1, path0);
-       strcpy(path1 + len, "+");
-
-       safe_create_leading_directories(path0);
-       info_ref_fp = fopen(path1, "w");
-       if (!info_ref_fp)
-               return error("unable to update %s", path1);
-       for_each_ref(add_info_ref, NULL);
-       fclose(info_ref_fp);
-       adjust_shared_perm(path1);
-       rename(path1, path0);
-       free(path0);
-       free(path1);
-       return 0;
+       char *path = git_pathdup("info/refs");
+       int ret = update_info_file(path, generate_info_refs);
+       free(path);
+       return ret;
 }
 
 /* packs */
@@ -198,36 +233,36 @@ static void init_pack_info(const char *infofile, int force)
                info[i]->new_num = i;
 }
 
-static void write_pack_info_file(FILE *fp)
+static void free_pack_info(void)
 {
        int i;
        for (i = 0; i < num_pack; i++)
-               fprintf(fp, "P %s\n", info[i]->p->pack_name + objdirlen + 6);
-       fputc('\n', fp);
+               free(info[i]);
+       free(info);
 }
 
-static int update_info_packs(int force)
+static int write_pack_info_file(FILE *fp)
 {
-       char infofile[PATH_MAX];
-       char name[PATH_MAX];
-       int namelen;
-       FILE *fp;
+       int i;
+       for (i = 0; i < num_pack; i++) {
+               if (fprintf(fp, "P %s\n", info[i]->p->pack_name + objdirlen + 6) < 0)
+                       return -1;
+       }
+       if (fputc('\n', fp) == EOF)
+               return -1;
+       return 0;
+}
 
-       namelen = sprintf(infofile, "%s/info/packs", get_object_directory());
-       strcpy(name, infofile);
-       strcpy(name + namelen, "+");
+static int update_info_packs(int force)
+{
+       char *infofile = mkpathdup("%s/info/packs", get_object_directory());
+       int ret;
 
        init_pack_info(infofile, force);
-
-       safe_create_leading_directories(name);
-       fp = fopen(name, "w");
-       if (!fp)
-               return error("cannot open %s", name);
-       write_pack_info_file(fp);
-       fclose(fp);
-       adjust_shared_perm(name);
-       rename(name, infofile);
-       return 0;
+       ret = update_info_file(infofile, write_pack_info_file);
+       free_pack_info();
+       free(infofile);
+       return ret;
 }
 
 /* public */
diff --git a/setup.c b/setup.c
index 0a22f8bd1d631fe5f0afe1d84162ca4064a00e4f..979b13f0c6cd6bc3c265187e8ea79628bfe99f87 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -387,7 +387,7 @@ const char *read_gitfile(const char *path)
 }
 
 static const char *setup_explicit_git_dir(const char *gitdirenv,
-                                         char *cwd, int len,
+                                         struct strbuf *cwd,
                                          int *nongit_ok)
 {
        const char *work_tree_env = getenv(GIT_WORK_TREE_ENVIRONMENT);
@@ -434,16 +434,16 @@ static const char *setup_explicit_git_dir(const char *gitdirenv,
                if (is_absolute_path(git_work_tree_cfg))
                        set_git_work_tree(git_work_tree_cfg);
                else {
-                       char core_worktree[PATH_MAX];
+                       char *core_worktree;
                        if (chdir(gitdirenv))
                                die_errno("Could not chdir to '%s'", gitdirenv);
                        if (chdir(git_work_tree_cfg))
                                die_errno("Could not chdir to '%s'", git_work_tree_cfg);
-                       if (!getcwd(core_worktree, PATH_MAX))
-                               die_errno("Could not get directory '%s'", git_work_tree_cfg);
-                       if (chdir(cwd))
+                       core_worktree = xgetcwd();
+                       if (chdir(cwd->buf))
                                die_errno("Could not come back to cwd");
                        set_git_work_tree(core_worktree);
+                       free(core_worktree);
                }
        }
        else if (!git_env_bool(GIT_IMPLICIT_WORK_TREE_ENVIRONMENT, 1)) {
@@ -459,21 +459,20 @@ static const char *setup_explicit_git_dir(const char *gitdirenv,
        worktree = get_git_work_tree();
 
        /* both get_git_work_tree() and cwd are already normalized */
-       if (!strcmp(cwd, worktree)) { /* cwd == worktree */
+       if (!strcmp(cwd->buf, worktree)) { /* cwd == worktree */
                set_git_dir(gitdirenv);
                free(gitfile);
                return NULL;
        }
 
-       offset = dir_inside_of(cwd, worktree);
+       offset = dir_inside_of(cwd->buf, worktree);
        if (offset >= 0) {      /* cwd inside worktree? */
                set_git_dir(real_path(gitdirenv));
                if (chdir(worktree))
                        die_errno("Could not chdir to '%s'", worktree);
-               cwd[len++] = '/';
-               cwd[len] = '\0';
+               strbuf_addch(cwd, '/');
                free(gitfile);
-               return cwd + offset;
+               return cwd->buf + offset;
        }
 
        /* cwd outside worktree */
@@ -483,7 +482,7 @@ static const char *setup_explicit_git_dir(const char *gitdirenv,
 }
 
 static const char *setup_discovered_git_dir(const char *gitdir,
-                                           char *cwd, int offset, int len,
+                                           struct strbuf *cwd, int offset,
                                            int *nongit_ok)
 {
        if (check_repository_format_gently(gitdir, nongit_ok))
@@ -491,17 +490,17 @@ static const char *setup_discovered_git_dir(const char *gitdir,
 
        /* --work-tree is set without --git-dir; use discovered one */
        if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
-               if (offset != len && !is_absolute_path(gitdir))
+               if (offset != cwd->len && !is_absolute_path(gitdir))
                        gitdir = xstrdup(real_path(gitdir));
-               if (chdir(cwd))
+               if (chdir(cwd->buf))
                        die_errno("Could not come back to cwd");
-               return setup_explicit_git_dir(gitdir, cwd, len, nongit_ok);
+               return setup_explicit_git_dir(gitdir, cwd, nongit_ok);
        }
 
        /* #16.2, #17.2, #20.2, #21.2, #24, #25, #28, #29 (see t1510) */
        if (is_bare_repository_cfg > 0) {
-               set_git_dir(offset == len ? gitdir : real_path(gitdir));
-               if (chdir(cwd))
+               set_git_dir(offset == cwd->len ? gitdir : real_path(gitdir));
+               if (chdir(cwd->buf))
                        die_errno("Could not come back to cwd");
                return NULL;
        }
@@ -512,18 +511,18 @@ static const char *setup_discovered_git_dir(const char *gitdir,
                set_git_dir(gitdir);
        inside_git_dir = 0;
        inside_work_tree = 1;
-       if (offset == len)
+       if (offset == cwd->len)
                return NULL;
 
        /* Make "offset" point to past the '/', and add a '/' at the end */
        offset++;
-       cwd[len++] = '/';
-       cwd[len] = 0;
-       return cwd + offset;
+       strbuf_addch(cwd, '/');
+       return cwd->buf + offset;
 }
 
 /* #16.1, #17.1, #20.1, #21.1, #22.1 (see t1510) */
-static const char *setup_bare_git_dir(char *cwd, int offset, int len, int *nongit_ok)
+static const char *setup_bare_git_dir(struct strbuf *cwd, int offset,
+                                     int *nongit_ok)
 {
        int root_len;
 
@@ -536,20 +535,20 @@ static const char *setup_bare_git_dir(char *cwd, int offset, int len, int *nongi
        if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
                const char *gitdir;
 
-               gitdir = offset == len ? "." : xmemdupz(cwd, offset);
-               if (chdir(cwd))
+               gitdir = offset == cwd->len ? "." : xmemdupz(cwd->buf, offset);
+               if (chdir(cwd->buf))
                        die_errno("Could not come back to cwd");
-               return setup_explicit_git_dir(gitdir, cwd, len, nongit_ok);
+               return setup_explicit_git_dir(gitdir, cwd, nongit_ok);
        }
 
        inside_git_dir = 1;
        inside_work_tree = 0;
-       if (offset != len) {
-               if (chdir(cwd))
+       if (offset != cwd->len) {
+               if (chdir(cwd->buf))
                        die_errno("Cannot come back to cwd");
-               root_len = offset_1st_component(cwd);
-               cwd[offset > root_len ? offset : root_len] = '\0';
-               set_git_dir(cwd);
+               root_len = offset_1st_component(cwd->buf);
+               strbuf_setlen(cwd, offset > root_len ? offset : root_len);
+               set_git_dir(cwd->buf);
        }
        else
                set_git_dir(".");
@@ -617,13 +616,22 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
 {
        const char *env_ceiling_dirs = getenv(CEILING_DIRECTORIES_ENVIRONMENT);
        struct string_list ceiling_dirs = STRING_LIST_INIT_DUP;
-       static char cwd[PATH_MAX + 1];
+       static struct strbuf cwd = STRBUF_INIT;
        const char *gitdirenv, *ret;
        char *gitfile;
-       int len, offset, offset_parent, ceil_offset = -1;
+       int offset, offset_parent, ceil_offset = -1;
        dev_t current_device = 0;
        int one_filesystem = 1;
 
+       /*
+        * We may have read an incomplete configuration before
+        * setting-up the git directory. If so, clear the cache so
+        * that the next queries to the configuration reload complete
+        * configuration (including the per-repo config file that we
+        * ignored previously).
+        */
+       git_config_clear();
+
        /*
         * Let's assume that we are in a git repository.
         * If it turns out later that we are somewhere else, the value will be
@@ -632,9 +640,9 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
        if (nongit_ok)
                *nongit_ok = 0;
 
-       if (!getcwd(cwd, sizeof(cwd) - 1))
+       if (strbuf_getcwd(&cwd))
                die_errno("Unable to read current working directory");
-       offset = len = strlen(cwd);
+       offset = cwd.len;
 
        /*
         * If GIT_DIR is set explicitly, we're not going
@@ -643,7 +651,7 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
         */
        gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
        if (gitdirenv)
-               return setup_explicit_git_dir(gitdirenv, cwd, len, nongit_ok);
+               return setup_explicit_git_dir(gitdirenv, &cwd, nongit_ok);
 
        if (env_ceiling_dirs) {
                int empty_entry_found = 0;
@@ -651,11 +659,11 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
                string_list_split(&ceiling_dirs, env_ceiling_dirs, PATH_SEP, -1);
                filter_string_list(&ceiling_dirs, 0,
                                   canonicalize_ceiling_entry, &empty_entry_found);
-               ceil_offset = longest_ancestor_length(cwd, &ceiling_dirs);
+               ceil_offset = longest_ancestor_length(cwd.buf, &ceiling_dirs);
                string_list_clear(&ceiling_dirs, 0);
        }
 
-       if (ceil_offset < 0 && has_dos_drive_prefix(cwd))
+       if (ceil_offset < 0 && has_dos_drive_prefix(cwd.buf))
                ceil_offset = 1;
 
        /*
@@ -683,7 +691,7 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
 
                if (gitdirenv) {
                        ret = setup_discovered_git_dir(gitdirenv,
-                                                      cwd, offset, len,
+                                                      &cwd, offset,
                                                       nongit_ok);
                        free(gitfile);
                        return ret;
@@ -691,29 +699,31 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
                free(gitfile);
 
                if (is_git_directory("."))
-                       return setup_bare_git_dir(cwd, offset, len, nongit_ok);
+                       return setup_bare_git_dir(&cwd, offset, nongit_ok);
 
                offset_parent = offset;
-               while (--offset_parent > ceil_offset && cwd[offset_parent] != '/');
+               while (--offset_parent > ceil_offset && cwd.buf[offset_parent] != '/');
                if (offset_parent <= ceil_offset)
-                       return setup_nongit(cwd, nongit_ok);
+                       return setup_nongit(cwd.buf, nongit_ok);
                if (one_filesystem) {
-                       dev_t parent_device = get_device_or_die("..", cwd, offset);
+                       dev_t parent_device = get_device_or_die("..", cwd.buf,
+                                                               offset);
                        if (parent_device != current_device) {
                                if (nongit_ok) {
-                                       if (chdir(cwd))
+                                       if (chdir(cwd.buf))
                                                die_errno("Cannot come back to cwd");
                                        *nongit_ok = 1;
                                        return NULL;
                                }
-                               cwd[offset] = '\0';
+                               strbuf_setlen(&cwd, offset);
                                die("Not a git repository (or any parent up to mount point %s)\n"
-                               "Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).", cwd);
+                               "Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).",
+                                   cwd.buf);
                        }
                }
                if (chdir("..")) {
-                       cwd[offset] = '\0';
-                       die_errno("Cannot change to '%s/..'", cwd);
+                       strbuf_setlen(&cwd, offset);
+                       die_errno("Cannot change to '%s/..'", cwd.buf);
                }
                offset = offset_parent;
        }
index 6dd03a974ae9a5063c40cd50e0c6e7645afca971..2842a22d7fdda33d62d617d5ba9b826ad428c17e 100644 (file)
@@ -208,11 +208,8 @@ string_list_append (string_list_ty *slp, const char *s)
   /* Grow the list.  */
   if (slp->nitems >= slp->nitems_max)
     {
-      size_t nbytes;
-
       slp->nitems_max = slp->nitems_max * 2 + 4;
-      nbytes = slp->nitems_max * sizeof (slp->item[0]);
-      slp->item = (const char **) xrealloc (slp->item, nbytes);
+      REALLOC_ARRAY(slp->item, slp->nitems_max);
     }
 
   /* Add the string to the end of the list.  */
index 3f70b1d86aaa8e0648d8a3c6ebb6aca701ae7475..c08c0cbea805b38104504b9b51266949affb6991 100644 (file)
@@ -350,7 +350,7 @@ static void link_alt_odb_entries(const char *alt, int len, int sep,
                return;
        }
 
-       strbuf_addstr(&objdirbuf, absolute_path(get_object_directory()));
+       strbuf_add_absolute_path(&objdirbuf, get_object_directory());
        normalize_path_copy(objdirbuf.buf, objdirbuf.buf);
 
        alt_copy = xmemdupz(alt, len);
@@ -1923,7 +1923,9 @@ static void *unpack_compressed_entry(struct packed_git *p,
        git_zstream stream;
        unsigned char *buffer, *in;
 
-       buffer = xmallocz(size);
+       buffer = xmallocz_gently(size);
+       if (!buffer)
+               return NULL;
        memset(&stream, 0, sizeof(stream));
        stream.next_out = buffer;
        stream.avail_out = size + 1;
index 63ee66fedd617e2cacfae7a763f43ee600d15273..5b004f513b999b31b7968b22dde955c859704853 100644 (file)
@@ -432,7 +432,8 @@ static inline int upstream_mark(const char *string, int len)
 static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned lookup_flags);
 static int interpret_nth_prior_checkout(const char *name, int namelen, struct strbuf *buf);
 
-static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
+static int get_sha1_basic(const char *str, int len, unsigned char *sha1,
+                         unsigned int flags)
 {
        static const char *warn_msg = "refname '%.*s' is ambiguous.";
        static const char *object_name_msg = N_(
@@ -511,7 +512,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
        if (!refs_found)
                return -1;
 
-       if (warn_ambiguous_refs &&
+       if (warn_ambiguous_refs && !(flags & GET_SHA1_QUIETLY) &&
            (refs_found > 1 ||
             !get_short_sha1(str, len, tmp_sha1, GET_SHA1_QUIETLY)))
                warning(warn_msg, len, str);
@@ -545,7 +546,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
                                return -1;
                        }
                }
-               if (read_ref_at(real_ref, at_time, nth, sha1, NULL,
+               if (read_ref_at(real_ref, flags, at_time, nth, sha1, NULL,
                                &co_time, &co_tz, &co_cnt)) {
                        if (!len) {
                                if (starts_with(real_ref, "refs/heads/")) {
@@ -557,11 +558,16 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
                                        len = 4;
                                }
                        }
-                       if (at_time)
-                               warning("Log for '%.*s' only goes "
-                                       "back to %s.", len, str,
-                                       show_date(co_time, co_tz, DATE_RFC2822));
-                       else {
+                       if (at_time) {
+                               if (!(flags & GET_SHA1_QUIETLY)) {
+                                       warning("Log for '%.*s' only goes "
+                                               "back to %s.", len, str,
+                                               show_date(co_time, co_tz, DATE_RFC2822));
+                               }
+                       } else {
+                               if (flags & GET_SHA1_QUIETLY) {
+                                       exit(128);
+                               }
                                die("Log for '%.*s' only has %d entries.",
                                    len, str, co_cnt);
                        }
@@ -801,7 +807,7 @@ static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned l
        if (!ret)
                return 0;
 
-       ret = get_sha1_basic(name, len, sha1);
+       ret = get_sha1_basic(name, len, sha1, lookup_flags);
        if (!ret)
                return 0;
 
@@ -839,7 +845,7 @@ static int handle_one_ref(const char *path,
        }
        if (object->type != OBJ_COMMIT)
                return 0;
-       commit_list_insert_by_date((struct commit *)object, list);
+       commit_list_insert((struct commit *)object, list);
        return 0;
 }
 
@@ -1366,6 +1372,7 @@ static int get_sha1_with_context_1(const char *name,
                if (!only_to_die && namelen > 2 && name[1] == '/') {
                        struct commit_list *list = NULL;
                        for_each_ref(handle_one_ref, &list);
+                       commit_list_sort_by_date(&list);
                        return get_sha1_oneline(name + 2, sha1, list);
                }
                if (namelen < 3 ||
index de07709e3358947062984970e85005ded224baf9..57f4afa6b40585c663d0df78494ce2108611ce4b 100644 (file)
--- a/shallow.c
+++ b/shallow.c
@@ -392,8 +392,7 @@ static uint32_t *paint_alloc(struct paint_info *info)
        void *p;
        if (!info->slab_count || info->free + size > info->end) {
                info->slab_count++;
-               info->slab = xrealloc(info->slab,
-                                     info->slab_count * sizeof(*info->slab));
+               REALLOC_ARRAY(info->slab, info->slab_count);
                info->free = xmalloc(COMMIT_SLAB_SIZE);
                info->slab[info->slab_count - 1] = info->free;
                info->end = info->free + COMMIT_SLAB_SIZE;
index 33018d847f08424211c02cff8002680f5a2f02e9..0346e74a47d14ef13757cadfe2a0de778b5c4cc4 100644 (file)
--- a/strbuf.c
+++ b/strbuf.c
@@ -204,6 +204,13 @@ void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len)
        strbuf_setlen(sb, sb->len + len);
 }
 
+void strbuf_addchars(struct strbuf *sb, int c, size_t n)
+{
+       strbuf_grow(sb, n);
+       memset(sb->buf + sb->len, c, n);
+       strbuf_setlen(sb, sb->len + n);
+}
+
 void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
 {
        va_list ap;
@@ -406,6 +413,27 @@ int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint)
        return -1;
 }
 
+int strbuf_getcwd(struct strbuf *sb)
+{
+       size_t oldalloc = sb->alloc;
+       size_t guessed_len = 128;
+
+       for (;; guessed_len *= 2) {
+               strbuf_grow(sb, guessed_len);
+               if (getcwd(sb->buf, sb->alloc)) {
+                       strbuf_setlen(sb, strlen(sb->buf));
+                       return 0;
+               }
+               if (errno != ERANGE)
+                       break;
+       }
+       if (oldalloc == 0)
+               strbuf_release(sb);
+       else
+               strbuf_reset(sb);
+       return -1;
+}
+
 int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term)
 {
        int ch;
@@ -555,6 +583,31 @@ void strbuf_humanise_bytes(struct strbuf *buf, off_t bytes)
        }
 }
 
+void strbuf_add_absolute_path(struct strbuf *sb, const char *path)
+{
+       if (!*path)
+               die("The empty string is not a valid path");
+       if (!is_absolute_path(path)) {
+               struct stat cwd_stat, pwd_stat;
+               size_t orig_len = sb->len;
+               char *cwd = xgetcwd();
+               char *pwd = getenv("PWD");
+               if (pwd && strcmp(pwd, cwd) &&
+                   !stat(cwd, &cwd_stat) &&
+                   (cwd_stat.st_dev || cwd_stat.st_ino) &&
+                   !stat(pwd, &pwd_stat) &&
+                   pwd_stat.st_dev == cwd_stat.st_dev &&
+                   pwd_stat.st_ino == cwd_stat.st_ino)
+                       strbuf_addstr(sb, pwd);
+               else
+                       strbuf_addstr(sb, cwd);
+               if (sb->len > orig_len && !is_dir_sep(sb->buf[sb->len - 1]))
+                       strbuf_addch(sb, '/');
+               free(cwd);
+       }
+       strbuf_addstr(sb, path);
+}
+
 int printf_ln(const char *fmt, ...)
 {
        int ret;
index a7c0192e9ee392bd232b325692a9111b3e160e84..652b6c432b325aaed29d7d374994a2a95d11a7c8 100644 (file)
--- a/strbuf.h
+++ b/strbuf.h
@@ -138,6 +138,7 @@ static inline void strbuf_addbuf(struct strbuf *sb, const struct strbuf *sb2)
        strbuf_add(sb, sb2->buf, sb2->len);
 }
 extern void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len);
+extern void strbuf_addchars(struct strbuf *sb, int c, size_t n);
 
 typedef size_t (*expand_fn_t) (struct strbuf *sb, const char *placeholder, void *context);
 extern void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn, void *context);
@@ -174,6 +175,7 @@ extern size_t strbuf_fread(struct strbuf *, size_t, FILE *);
 extern ssize_t strbuf_read(struct strbuf *, int fd, size_t hint);
 extern int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint);
 extern int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint);
+extern int strbuf_getcwd(struct strbuf *sb);
 
 extern int strbuf_getwholeline(struct strbuf *, FILE *, int);
 extern int strbuf_getline(struct strbuf *, FILE *, int);
@@ -189,6 +191,8 @@ extern void strbuf_addstr_urlencode(struct strbuf *, const char *,
                                    int reserved);
 extern void strbuf_humanise_bytes(struct strbuf *buf, off_t bytes);
 
+extern void strbuf_add_absolute_path(struct strbuf *sb, const char *path);
+
 __attribute__((format (printf,1,2)))
 extern int printf_ln(const char *fmt, ...);
 __attribute__((format (printf,2,3)))
index db38b62b46fd15d849ed405f0b60cb7c72eaee40..c5aa0765e8e0a044e9e84e43280d5964f232ef63 100644 (file)
@@ -43,8 +43,7 @@ static int add_entry(int insert_at, struct string_list *list, const char *string
 
        if (list->nr + 1 >= list->alloc) {
                list->alloc += 32;
-               list->items = xrealloc(list->items, list->alloc
-                               * sizeof(struct string_list_item));
+               REALLOC_ARRAY(list->items, list->alloc);
        }
        if (index < list->nr)
                memmove(list->items + index + 1, list->items + index,
index c3a61e70f9f72eced2530d425717972881b947c8..0690dc50d07e9fd30242e41afe149476a34fc105 100644 (file)
@@ -433,13 +433,12 @@ static int submodule_needs_pushing(const char *path, const unsigned char sha1[20
                return 0;
 
        if (for_each_remote_ref_submodule(path, has_remote, NULL) > 0) {
-               struct child_process cp;
+               struct child_process cp = CHILD_PROCESS_INIT;
                const char *argv[] = {"rev-list", NULL, "--not", "--remotes", "-n", "1" , NULL};
                struct strbuf buf = STRBUF_INIT;
                int needs_pushing = 0;
 
                argv[1] = sha1_to_hex(sha1);
-               memset(&cp, 0, sizeof(cp));
                cp.argv = argv;
                cp.env = local_repo_env;
                cp.git_cmd = 1;
@@ -524,10 +523,9 @@ static int push_submodule(const char *path)
                return 1;
 
        if (for_each_remote_ref_submodule(path, has_remote, NULL) > 0) {
-               struct child_process cp;
+               struct child_process cp = CHILD_PROCESS_INIT;
                const char *argv[] = {"push", NULL};
 
-               memset(&cp, 0, sizeof(cp));
                cp.argv = argv;
                cp.env = local_repo_env;
                cp.git_cmd = 1;
@@ -569,12 +567,11 @@ static int is_submodule_commit_present(const char *path, unsigned char sha1[20])
        if (!add_submodule_odb(path) && lookup_commit_reference(sha1)) {
                /* Even if the submodule is checked out and the commit is
                 * present, make sure it is reachable from a ref. */
-               struct child_process cp;
+               struct child_process cp = CHILD_PROCESS_INIT;
                const char *argv[] = {"rev-list", "-n", "1", NULL, "--not", "--all", NULL};
                struct strbuf buf = STRBUF_INIT;
 
                argv[3] = sha1_to_hex(sha1);
-               memset(&cp, 0, sizeof(cp));
                cp.argv = argv;
                cp.env = local_repo_env;
                cp.git_cmd = 1;
@@ -695,7 +692,7 @@ int fetch_populated_submodules(const struct argv_array *options,
                               int quiet)
 {
        int i, result = 0;
-       struct child_process cp;
+       struct child_process cp = CHILD_PROCESS_INIT;
        struct argv_array argv = ARGV_ARRAY_INIT;
        struct string_list_item *name_for_path;
        const char *work_tree = get_git_work_tree();
@@ -711,7 +708,6 @@ int fetch_populated_submodules(const struct argv_array *options,
        argv_array_push(&argv, "--recurse-submodules-default");
        /* default value, "--submodule-prefix" and its value are added later */
 
-       memset(&cp, 0, sizeof(cp));
        cp.env = local_repo_env;
        cp.git_cmd = 1;
        cp.no_stdin = 1;
@@ -794,7 +790,7 @@ out:
 unsigned is_submodule_modified(const char *path, int ignore_untracked)
 {
        ssize_t len;
-       struct child_process cp;
+       struct child_process cp = CHILD_PROCESS_INIT;
        const char *argv[] = {
                "status",
                "--porcelain",
@@ -821,7 +817,6 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked)
        if (ignore_untracked)
                argv[2] = "-uno";
 
-       memset(&cp, 0, sizeof(cp));
        cp.argv = argv;
        cp.env = local_repo_env;
        cp.git_cmd = 1;
@@ -862,7 +857,7 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked)
 
 int submodule_uses_gitfile(const char *path)
 {
-       struct child_process cp;
+       struct child_process cp = CHILD_PROCESS_INIT;
        const char *argv[] = {
                "submodule",
                "foreach",
@@ -883,7 +878,6 @@ int submodule_uses_gitfile(const char *path)
        strbuf_release(&buf);
 
        /* Now test that all nested submodules use a gitfile too */
-       memset(&cp, 0, sizeof(cp));
        cp.argv = argv;
        cp.env = local_repo_env;
        cp.git_cmd = 1;
@@ -901,7 +895,7 @@ int ok_to_remove_submodule(const char *path)
 {
        struct stat st;
        ssize_t len;
-       struct child_process cp;
+       struct child_process cp = CHILD_PROCESS_INIT;
        const char *argv[] = {
                "status",
                "--porcelain",
@@ -918,7 +912,6 @@ int ok_to_remove_submodule(const char *path)
        if (!submodule_uses_gitfile(path))
                return 0;
 
-       memset(&cp, 0, sizeof(cp));
        cp.argv = argv;
        cp.env = local_repo_env;
        cp.git_cmd = 1;
index 981437b3a88b86ee1ddd26f842a0048b8dc2b57f..aeea50c6339ebd4a0d33ce03b7fad5948e69a8a8 100755 (executable)
@@ -27,4 +27,26 @@ test_expect_success !MINGW 'signals are propagated using shell convention' '
        test_expect_code 143 git sigterm
 '
 
+large_git () {
+       for i in $(test_seq 1 100)
+       do
+               git diff --cached --binary || return
+       done
+}
+
+test_expect_success 'create blob' '
+       test-genrandom foo 16384 >file &&
+       git add file
+'
+
+test_expect_success !MINGW 'a constipated git dies with SIGPIPE' '
+       OUT=$( ((large_git; echo $? 1>&3) | :) 3>&1 )
+       test "$OUT" -eq 141
+'
+
+test_expect_success !MINGW 'a constipated git dies with SIGPIPE even if parent ignores it' '
+       OUT=$( ((trap "" PIPE; large_git; echo $? 1>&3) | :) 3>&1 )
+       test "$OUT" -eq 141
+'
+
 test_done
index 39e55a13c885399150094f9a2774f85e0acd63a6..8dc6939b9049baa32aca1200e36378e6e2296e9d 100755 (executable)
@@ -806,7 +806,7 @@ test_expect_success !MINGW 'quoting allows trailing whitespace' '
        test_cmp err.expect err
 '
 
-test_expect_success NOT_MINGW,NOT_CYGWIN 'correct handling of backslashes' '
+test_expect_success !MINGW,!CYGWIN 'correct handling of backslashes' '
        rm -rf whitespace &&
        mkdir whitespace &&
        >"whitespace/trailing 1  " &&
index 4807b0f015d4b87aa762c0f7585d863a1dc34514..c5203e232c8b6e480e2c3a16dca78d625f364aac 100755 (executable)
@@ -80,4 +80,24 @@ test_expect_success 'autocrlf=true overrides unset eol' '
        test -z "$onediff" && test -z "$twodiff"
 '
 
+test_expect_success NATIVE_CRLF 'eol native is crlf' '
+
+       rm -rf native_eol && mkdir native_eol &&
+       (
+               cd native_eol &&
+               printf "*.txt text\n" >.gitattributes &&
+               printf "one\r\ntwo\r\nthree\r\n" >filedos.txt &&
+               printf "one\ntwo\nthree\n" >fileunix.txt &&
+               git init &&
+               git config core.autocrlf false &&
+               git config core.eol native &&
+               git add filedos.txt fileunix.txt &&
+               git commit -m "first" &&
+               rm file*.txt &&
+               git reset --hard HEAD &&
+               has_cr filedos.txt &&
+               has_cr fileunix.txt
+       )
+'
+
 test_done
index 72dd3e8bb4645a3c522e4c115c38a455dbe9c434..2a4a6c1226f7cf315510f8bd84b5d6fb8045ee5d 100755 (executable)
@@ -10,30 +10,26 @@ then
        test_done
 fi
 
-
-compare_files()
-{
-       od -c <"$1" >"$1".expect &&
-       od -c <"$2" >"$2".actual &&
+compare_files () {
+       tr '\015\000' QN <"$1" >"$1".expect &&
+       tr '\015\000' QN <"$2" >"$2".actual &&
        test_cmp "$1".expect "$2".actual &&
        rm "$1".expect "$2".actual
 }
 
-compare_ws_file()
-{
+compare_ws_file () {
        pfx=$1
        exp=$2.expect
        act=$pfx.actual.$3
-       od -c <"$2" >"$exp" &&
-       od -c <"$3" >"$act" &&
+       tr '\015\000' QN <"$2" >"$exp" &&
+       tr '\015\000' QN <"$3" >"$act" &&
        test_cmp $exp $act &&
        rm $exp $act
 }
 
-create_gitattributes()
-{
-       txtbin=$1
-       case "$txtbin" in
+create_gitattributes () {
+       attr=$1
+       case "$attr" in
                auto)
                echo "*.txt text=auto" >.gitattributes
                ;;
@@ -43,35 +39,43 @@ create_gitattributes()
                -text)
                echo "*.txt -text" >.gitattributes
                ;;
-               *)
+               crlf)
+               echo "*.txt eol=crlf" >.gitattributes
+               ;;
+               lf)
+               echo "*.txt eol=lf" >.gitattributes
+               ;;
+               "")
                echo >.gitattributes
                ;;
+               *)
+               echo >&2 invalid attribute: $attr
+               exit 1
+               ;;
        esac
 }
 
-create_file_in_repo()
-{
+create_file_in_repo () {
        crlf=$1
-       txtbin=$2
-       create_gitattributes "$txtbin" &&
+       attr=$2
+       create_gitattributes "$attr" &&
        for f in LF CRLF LF_mix_CR CRLF_mix_LF CRLF_nul
        do
-               pfx=crlf_${crlf}_attr_${txtbin}_$f.txt &&
+               pfx=crlf_${crlf}_attr_${attr}_$f.txt &&
                cp $f $pfx && git -c core.autocrlf=$crlf add $pfx
        done &&
        git commit -m "core.autocrlf $crlf"
 }
 
-check_files_in_repo()
-{
+check_files_in_repo () {
        crlf=$1
-       txtbin=$2
+       attr=$2
        lfname=$3
        crlfname=$4
        lfmixcrlf=$5
        lfmixcr=$6
        crlfnul=$7
-       pfx=crlf_${crlf}_attr_${txtbin}_ &&
+       pfx=crlf_${crlf}_attr_${attr}_ &&
        compare_files $lfname ${pfx}LF.txt &&
        compare_files $crlfname ${pfx}CRLF.txt &&
        compare_files $lfmixcrlf ${pfx}CRLF_mix_LF.txt &&
@@ -80,19 +84,18 @@ check_files_in_repo()
 }
 
 
-check_files_in_ws()
-{
+check_files_in_ws () {
        eol=$1
        crlf=$2
-       txtbin=$3
+       attr=$3
        lfname=$4
        crlfname=$5
        lfmixcrlf=$6
        lfmixcr=$7
        crlfnul=$8
-       create_gitattributes $txtbin &&
+       create_gitattributes $attr &&
        git config core.autocrlf $crlf &&
-       pfx=eol_${eol}_crlf_${crlf}_attr_${txtbin}_ &&
+       pfx=eol_${eol}_crlf_${crlf}_attr_${attr}_ &&
        src=crlf_false_attr__ &&
        for f in LF CRLF LF_mix_CR CRLF_mix_LF CRLF_nul
        do
@@ -104,42 +107,24 @@ check_files_in_ws()
                fi
        done
 
-
-       test_expect_success "checkout core.eol=$eol core.autocrlf=$crlf gitattributes=$txtbin file=LF" "
+       test_expect_success "checkout core.eol=$eol core.autocrlf=$crlf gitattributes=$attr file=LF" "
                compare_ws_file $pfx $lfname    ${src}LF.txt
        "
-       test_expect_success "checkout core.eol=$eol core.autocrlf=$crlf gitattributes=$txtbin file=CRLF" "
+       test_expect_success "checkout core.eol=$eol core.autocrlf=$crlf gitattributes=$attr file=CRLF" "
                compare_ws_file $pfx $crlfname  ${src}CRLF.txt
        "
-       test_expect_success "checkout core.eol=$eol core.autocrlf=$crlf gitattributes=$txtbin file=CRLF_mix_LF" "
+       test_expect_success "checkout core.eol=$eol core.autocrlf=$crlf gitattributes=$attr file=CRLF_mix_LF" "
                compare_ws_file $pfx $lfmixcrlf ${src}CRLF_mix_LF.txt
        "
-       test_expect_success "checkout core.eol=$eol core.autocrlf=$crlf gitattributes=$txtbin file=LF_mix_CR" "
+       test_expect_success "checkout core.eol=$eol core.autocrlf=$crlf gitattributes=$attr file=LF_mix_CR" "
                compare_ws_file $pfx $lfmixcr   ${src}LF_mix_CR.txt
        "
-       test_expect_success "checkout core.eol=$eol core.autocrlf=$crlf gitattributes=$txtbin file=CRLF_nul" "
+       test_expect_success "checkout core.eol=$eol core.autocrlf=$crlf gitattributes=$attr file=CRLF_nul" "
                compare_ws_file $pfx $crlfnul   ${src}CRLF_nul.txt
        "
 }
 
 #######
-(
-       type od >/dev/null &&
-       printf "line1Q\r\nline2\r\nline3" | q_to_nul >CRLF_nul &&
-       cat >expect <<-EOF &&
-       0000000 l i n e 1 \0 \r \n l i n e 2 \r \n l
-       0000020 i n e 3
-       0000024
-EOF
-       od -c CRLF_nul | sed -e "s/[    ][       ]*/ /g" -e "s/ *$//" >actual
-       test_cmp expect actual &&
-       rm expect actual
-) || {
-               skip_all="od not found or od -c not usable"
-               exit 0
-               test_done
-}
-
 test_expect_success 'setup master' '
        echo >.gitattributes &&
        git checkout -b master &&
@@ -150,9 +135,10 @@ test_expect_success 'setup master' '
        printf "line1\r\nline2\nline3"   >CRLF_mix_LF &&
        printf "line1\nline2\rline3"     >LF_mix_CR &&
        printf "line1\r\nline2\rline3"   >CRLF_mix_CR &&
+       printf "line1Q\r\nline2\r\nline3" | q_to_nul >CRLF_nul &&
        printf "line1Q\nline2\nline3" | q_to_nul >LF_nul
 '
-#  CRLF_nul had been created above
+
 
 test_expect_success 'create files' '
        create_file_in_repo false "" &&
@@ -201,7 +187,8 @@ test_expect_success 'commit -text' '
 ################################################################################
 # Check how files in the repo are changed when they are checked out
 # How to read the table below:
-# - check_files_in_ws will check multiple files, see below
+# - check_files_in_ws will check multiple files with a combination of settings
+#   and attributes (core.autocrlf=input is forbidden with core.eol=crlf)
 # - parameter $1 : core.eol               lf | crlf
 # - parameter $2 : core.autocrlf          false | true | input
 # - parameter $3 : text in .gitattributs  "" (empty) | auto | text | -text
@@ -211,55 +198,88 @@ test_expect_success 'commit -text' '
 # - parameter $7 : reference for a file with LF and CR in the repo (does somebody uses this ?)
 # - parameter $8 : reference for a file with CRLF and a NUL (should be handled as binary when auto)
 
-check_files_in_ws lf      false  ""       LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
-check_files_in_ws lf      true   ""       CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
-check_files_in_ws lf      input  ""       LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
-
-check_files_in_ws lf      false "auto"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
-check_files_in_ws lf      true  "auto"    CRLF  CRLF  CRLF         LF_mix_CR    CRLF_nul
-check_files_in_ws lf      input "auto"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
-
-check_files_in_ws lf      false "text"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
-check_files_in_ws lf      true  "text"    CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul
-check_files_in_ws lf      input "text"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
-
-check_files_in_ws lf      false "-text"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
-check_files_in_ws lf      true  "-text"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
-check_files_in_ws lf      input "-text"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
-
-###########
-#core.autocrlf=input is forbidden with core.eol=crlf
-check_files_in_ws crlf    false ""        LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
-check_files_in_ws crlf    true  ""        CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
-
-check_files_in_ws crlf    false "auto"    CRLF  CRLF  CRLF         LF_mix_CR    CRLF_nul
-check_files_in_ws crlf    true  "auto"    CRLF  CRLF  CRLF         LF_mix_CR    CRLF_nul
-
-check_files_in_ws crlf    false "text"    CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul
-check_files_in_ws crlf    true  "text"    CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul
-
-check_files_in_ws crlf    false "-text"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
-check_files_in_ws crlf    true  "-text"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
-
+#                                            What we have in the repo:
+#                                                                                                                               ----------------- EOL in repo ----------------
+#                                                                                                                               LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+#                   settings with checkout:
+#                   core.   core.   .gitattr
+#                    eol     acrlf
+#                                            ----------------------------------------------
+#                                            What we want to have in the working tree:
 if test_have_prereq MINGW
 then
-check_files_in_ws ""      false ""        LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
-check_files_in_ws ""      true  ""        CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
-check_files_in_ws ""      false "auto"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
-check_files_in_ws ""      true  "auto"    CRLF  CRLF  CRLF         LF_mix_CR    CRLF_nul
-check_files_in_ws ""      false "text"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
-check_files_in_ws ""      true  "text"    CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul
-check_files_in_ws ""      false "-text"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
-check_files_in_ws ""      true  "-text"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
-
-check_files_in_ws native  false ""        LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
-check_files_in_ws native  true  ""        CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
-check_files_in_ws native  false "auto"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
-check_files_in_ws native  true  "auto"    CRLF  CRLF  CRLF         LF_mix_CR    CRLF_nul
-check_files_in_ws native  false "text"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
-check_files_in_ws native  true  "text"    CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul
-check_files_in_ws native  false "-text"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
-check_files_in_ws native  true  "-text"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+MIX_CRLF_LF=CRLF
+MIX_LF_CR=CRLF_mix_CR
+NL=CRLF
+else
+MIX_CRLF_LF=CRLF_mix_LF
+MIX_LF_CR=LF_mix_CR
+NL=LF
 fi
+export CRLF_MIX_LF_CR MIX NL
+
+check_files_in_ws    lf      false  ""       LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws    lf      true   ""       CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws    lf      input  ""       LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws    lf      false "auto"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws    lf      true  "auto"    CRLF  CRLF  CRLF         LF_mix_CR    CRLF_nul
+check_files_in_ws    lf      input "auto"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws    lf      false "text"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws    lf      true  "text"    CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul
+check_files_in_ws    lf      input "text"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws    lf      false "-text"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws    lf      true  "-text"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws    lf      input "-text"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws    lf      false "lf"      LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws    lf      true  "lf"      LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws    lf      input "lf"      LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws    lf      false "crlf"    CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul
+check_files_in_ws    lf      true  "crlf"    CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul
+check_files_in_ws    lf      input "crlf"    CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul
+
+check_files_in_ws    crlf    false  ""       LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws    crlf    true   ""       CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws    crlf    false "auto"    CRLF  CRLF  CRLF         LF_mix_CR    CRLF_nul
+check_files_in_ws    crlf    true  "auto"    CRLF  CRLF  CRLF         LF_mix_CR    CRLF_nul
+check_files_in_ws    crlf    false "text"    CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul
+check_files_in_ws    crlf    true  "text"    CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul
+check_files_in_ws    crlf    false "-text"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws    crlf    true  "-text"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws    crlf    false "lf"      LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws    crlf    true  "lf"      LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws    crlf    false "crlf"    CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul
+check_files_in_ws    crlf    true  "crlf"    CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul
+
+check_files_in_ws    ""      false  ""       LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws    ""      true   ""       CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws    ""      input  ""       LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws    ""      false "auto"    $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    CRLF_nul
+check_files_in_ws    ""      true  "auto"    CRLF  CRLF  CRLF         LF_mix_CR    CRLF_nul
+check_files_in_ws    ""      input "auto"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws    ""      false "text"    $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   CRLF_nul
+check_files_in_ws    ""      true  "text"    CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul
+check_files_in_ws    ""      input "text"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws    ""      false "-text"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws    ""      true  "-text"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws    ""      input "-text"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws    ""      false "lf"      LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws    ""      true  "lf"      LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws    ""      input "lf"      LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws    ""      false "crlf"    CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul
+check_files_in_ws    ""      true  "crlf"    CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul
+check_files_in_ws    ""      input "crlf"    CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul
+
+check_files_in_ws    native  false  ""       LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws    native  true   ""       CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws    native  false "auto"    $NL   CRLF  $MIX_CRLF_LF LF_mix_CR    CRLF_nul
+check_files_in_ws    native  true  "auto"    CRLF  CRLF  CRLF         LF_mix_CR    CRLF_nul
+check_files_in_ws    native  false "text"    $NL   CRLF  $MIX_CRLF_LF $MIX_LF_CR   CRLF_nul
+check_files_in_ws    native  true  "text"    CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul
+check_files_in_ws    native  false "-text"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws    native  true  "-text"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws    native  false "lf"      LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws    native  true  "lf"      LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws    native  false "crlf"    CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul
+check_files_in_ws    native  true  "crlf"    CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul
 
 test_done
index 25dba008f3e4904cfe3100d9745a9b324622d779..ce92e6acad41712d6bc82b057858e7030c7ccde0 100755 (executable)
@@ -29,7 +29,7 @@ test_expect_success '0-length read, send along greeting' '
        test_cmp expect actual
 '
 
-test_expect_success NOT_MINGW 'read from file descriptor' '
+test_expect_success !MINGW 'read from file descriptor' '
        rm -f input &&
        echo hello >expect &&
        echo hello >input &&
index 6c33e28ee8df4d239dd6d1c1d98c324b01c70ed3..f9648a86426470785159b5132305a256c80b5ca4 100755 (executable)
@@ -8,7 +8,7 @@ cache-tree extension.
  . ./test-lib.sh
 
 cmp_cache_tree () {
-       test-dump-cache-tree >actual &&
+       test-dump-cache-tree | sed -e '/#(ref)/d' >actual &&
        sed "s/$_x40/SHA/" <actual >filtered &&
        test_cmp "$1" filtered
 }
@@ -16,15 +16,40 @@ cmp_cache_tree () {
 # We don't bother with actually checking the SHA1:
 # test-dump-cache-tree already verifies that all existing data is
 # correct.
-test_shallow_cache_tree () {
-       printf "SHA  (%d entries, 0 subtrees)\n" $(git ls-files|wc -l) >expect &&
+generate_expected_cache_tree_rec () {
+       dir="$1${1:+/}" &&
+       parent="$2" &&
+       # ls-files might have foo/bar, foo/bar/baz, and foo/bar/quux
+       # We want to count only foo because it's the only direct child
+       subtrees=$(git ls-files|grep /|cut -d / -f 1|uniq) &&
+       subtree_count=$(echo "$subtrees"|awk '$1 {++c} END {print c}') &&
+       entries=$(git ls-files|wc -l) &&
+       printf "SHA $dir (%d entries, %d subtrees)\n" "$entries" "$subtree_count" &&
+       for subtree in $subtrees
+       do
+               cd "$subtree"
+               generate_expected_cache_tree_rec "$dir$subtree" "$dir" || return 1
+               cd ..
+       done &&
+       dir=$parent
+}
+
+generate_expected_cache_tree () {
+       (
+               generate_expected_cache_tree_rec
+       )
+}
+
+test_cache_tree () {
+       generate_expected_cache_tree >expect &&
        cmp_cache_tree expect
 }
 
 test_invalid_cache_tree () {
-       echo "invalid                                   (0 subtrees)" >expect &&
-       printf "SHA #(ref)  (%d entries, 0 subtrees)\n" $(git ls-files|wc -l) >>expect &&
-       cmp_cache_tree expect
+       printf "invalid                                  %s ()\n" "" "$@" >expect &&
+       test-dump-cache-tree |
+       sed -n -e "s/[0-9]* subtrees//" -e '/#(ref)/d' -e '/^invalid /p' >actual &&
+       test_cmp expect actual
 }
 
 test_no_cache_tree () {
@@ -32,26 +57,59 @@ test_no_cache_tree () {
        cmp_cache_tree expect
 }
 
-test_expect_failure 'initial commit has cache-tree' '
+test_expect_success 'initial commit has cache-tree' '
        test_commit foo &&
-       test_shallow_cache_tree
+       test_cache_tree
 '
 
 test_expect_success 'read-tree HEAD establishes cache-tree' '
        git read-tree HEAD &&
-       test_shallow_cache_tree
+       test_cache_tree
 '
 
 test_expect_success 'git-add invalidates cache-tree' '
        test_when_finished "git reset --hard; git read-tree HEAD" &&
-       echo "I changed this file" > foo &&
+       echo "I changed this file" >foo &&
        git add foo &&
        test_invalid_cache_tree
 '
 
+test_expect_success 'git-add in subdir invalidates cache-tree' '
+       test_when_finished "git reset --hard; git read-tree HEAD" &&
+       mkdir dirx &&
+       echo "I changed this file" >dirx/foo &&
+       git add dirx/foo &&
+       test_invalid_cache_tree
+'
+
+cat >before <<\EOF
+SHA  (3 entries, 2 subtrees)
+SHA dir1/ (1 entries, 0 subtrees)
+SHA dir2/ (1 entries, 0 subtrees)
+EOF
+
+cat >expect <<\EOF
+invalid                                   (2 subtrees)
+invalid                                  dir1/ (0 subtrees)
+SHA dir2/ (1 entries, 0 subtrees)
+EOF
+
+test_expect_success 'git-add in subdir does not invalidate sibling cache-tree' '
+       git tag no-children &&
+       test_when_finished "git reset --hard no-children; git read-tree HEAD" &&
+       mkdir dir1 dir2 &&
+       test_commit dir1/a &&
+       test_commit dir2/b &&
+       echo "I changed this file" >dir1/a &&
+       cmp_cache_tree before &&
+       echo "I changed this file" >dir1/a &&
+       git add dir1/a &&
+       cmp_cache_tree expect
+'
+
 test_expect_success 'update-index invalidates cache-tree' '
        test_when_finished "git reset --hard; git read-tree HEAD" &&
-       echo "I changed this file" > foo &&
+       echo "I changed this file" >foo &&
        git update-index --add foo &&
        test_invalid_cache_tree
 '
@@ -59,7 +117,7 @@ test_expect_success 'update-index invalidates cache-tree' '
 test_expect_success 'write-tree establishes cache-tree' '
        test-scrap-cache-tree &&
        git write-tree &&
-       test_shallow_cache_tree
+       test_cache_tree
 '
 
 test_expect_success 'test-scrap-cache-tree works' '
@@ -70,24 +128,94 @@ test_expect_success 'test-scrap-cache-tree works' '
 
 test_expect_success 'second commit has cache-tree' '
        test_commit bar &&
-       test_shallow_cache_tree
+       test_cache_tree
+'
+
+test_expect_success 'commit --interactive gives cache-tree on partial commit' '
+       cat <<-\EOT >foo.c &&
+       int foo()
+       {
+               return 42;
+       }
+       int bar()
+       {
+               return 42;
+       }
+       EOT
+       git add foo.c &&
+       test_invalid_cache_tree &&
+       git commit -m "add a file" &&
+       test_cache_tree &&
+       cat <<-\EOT >foo.c &&
+       int foo()
+       {
+               return 43;
+       }
+       int bar()
+       {
+               return 44;
+       }
+       EOT
+       (echo p; echo 1; echo; echo s; echo n; echo y; echo q) |
+       git commit --interactive -m foo &&
+       test_cache_tree
+'
+
+test_expect_success 'commit in child dir has cache-tree' '
+       mkdir dir &&
+       >dir/child.t &&
+       git add dir/child.t &&
+       git commit -m dir/child.t &&
+       test_cache_tree
 '
 
 test_expect_success 'reset --hard gives cache-tree' '
        test-scrap-cache-tree &&
        git reset --hard &&
-       test_shallow_cache_tree
+       test_cache_tree
 '
 
 test_expect_success 'reset --hard without index gives cache-tree' '
        rm -f .git/index &&
        git reset --hard &&
-       test_shallow_cache_tree
+       test_cache_tree
 '
 
-test_expect_failure 'checkout gives cache-tree' '
+test_expect_success 'checkout gives cache-tree' '
+       git tag current &&
        git checkout HEAD^ &&
-       test_shallow_cache_tree
+       test_cache_tree
+'
+
+test_expect_success 'checkout -b gives cache-tree' '
+       git checkout current &&
+       git checkout -b prev HEAD^ &&
+       test_cache_tree
+'
+
+test_expect_success 'checkout -B gives cache-tree' '
+       git checkout current &&
+       git checkout -B prev HEAD^ &&
+       test_cache_tree
+'
+
+test_expect_success 'partial commit gives cache-tree' '
+       git checkout -b partial no-children &&
+       test_commit one &&
+       test_commit two &&
+       echo "some change" >one.t &&
+       git add one.t &&
+       echo "some other change" >two.t &&
+       git commit two.t -m partial &&
+       test_cache_tree
+'
+
+test_expect_success 'no phantom error when switching trees' '
+       mkdir newdir &&
+       >newdir/one &&
+       git add newdir/one &&
+       git checkout 2>errors &&
+       ! test -s errors
 '
 
 test_done
index 62c0d25af4ca1c8ef5d0d63b6e3ea329a6d75205..2edb4f2de5cc32d0f8847790d06a8de0c98d99c3 100755 (executable)
@@ -118,7 +118,7 @@ test_expect_success 'alias expansion' '
        )
 '
 
-test_expect_success NOT_MINGW '!alias expansion' '
+test_expect_success !MINGW '!alias expansion' '
        pwd >expect &&
        (
                git config alias.test-alias-directory !pwd &&
index aea493646e4400e733749768e48f2a3d1a470299..05a1e1d270d2f6254658607541f1b114299533e5 100755 (executable)
@@ -112,6 +112,20 @@ test_expect_success 'diff --raw' '
        git diff --raw HEAD^
 '
 
+test_expect_success 'diff --stat' '
+       git diff --stat HEAD^ HEAD
+'
+
+test_expect_success 'diff' '
+       git diff HEAD^ HEAD >actual &&
+       grep "Binary files.*differ" actual
+'
+
+test_expect_success 'diff --cached' '
+       git diff --cached HEAD^ >actual &&
+       grep "Binary files.*differ" actual
+'
+
 test_expect_success 'hash-object' '
        git hash-object large1
 '
@@ -163,4 +177,10 @@ test_expect_success 'zip achiving, deflate' '
        git archive --format=zip HEAD >/dev/null
 '
 
+test_expect_success 'fsck' '
+       test_must_fail git fsck 2>err &&
+       n=$(grep "error: attempting to allocate .* over limit" err | wc -l) &&
+       test "$n" -gt 1
+'
+
 test_done
index 46f6ae25714d55066159d96f4a496f60a10790da..938fc8bfd76c9889ebb2129642f878c9449acc9f 100755 (executable)
@@ -824,14 +824,14 @@ cat >expect <<\EOF
        trailingtilde = foo~
 EOF
 
-test_expect_success NOT_MINGW 'set --path' '
+test_expect_success !MINGW 'set --path' '
        rm -f .git/config &&
        git config --path path.home "~/" &&
        git config --path path.normal "/dev/null" &&
        git config --path path.trailingtilde "foo~" &&
        test_cmp expect .git/config'
 
-if test_have_prereq NOT_MINGW && test "${HOME+set}"
+if test_have_prereq !MINGW && test "${HOME+set}"
 then
        test_set_prereq HOMEVAR
 fi
@@ -854,7 +854,7 @@ cat >expect <<\EOF
 foo~
 EOF
 
-test_expect_success NOT_MINGW 'get --path copes with unset $HOME' '
+test_expect_success !MINGW 'get --path copes with unset $HOME' '
        (
                unset HOME;
                test_must_fail git config --get --path path.home \
diff --git a/t/t1308-config-set.sh b/t/t1308-config-set.sh
new file mode 100755 (executable)
index 0000000..ea0bce2
--- /dev/null
@@ -0,0 +1,221 @@
+#!/bin/sh
+
+test_description='Test git config-set API in different settings'
+
+. ./test-lib.sh
+
+# 'check_config get_* section.key value' verifies that the entry for
+# section.key is 'value'
+check_config () {
+       if test "$1" = expect_code
+       then
+               expect_code="$2" && shift && shift
+       else
+               expect_code=0
+       fi &&
+       op=$1 key=$2 && shift && shift &&
+       if test $# != 0
+       then
+               printf "%s\n" "$@"
+       fi >expect &&
+       test_expect_code $expect_code test-config "$op" "$key" >actual &&
+       test_cmp expect actual
+}
+
+test_expect_success 'setup default config' '
+       cat >.git/config <<\EOF
+       [case]
+               penguin = very blue
+               Movie = BadPhysics
+               UPPERCASE = true
+               MixedCase = true
+               my =
+               foo
+               baz = sam
+       [Cores]
+               WhatEver = Second
+               baz = bar
+       [cores]
+               baz = bat
+       [CORES]
+               baz = ball
+       [my "Foo bAr"]
+               hi = mixed-case
+       [my "FOO BAR"]
+               hi = upper-case
+       [my "foo bar"]
+               hi = lower-case
+       [case]
+               baz = bat
+               baz = hask
+       [lamb]
+               chop = 65
+               head = none
+       [goat]
+               legs = 4
+               head = true
+               skin = false
+               nose = 1
+               horns
+       EOF
+'
+
+test_expect_success 'get value for a simple key' '
+       check_config get_value case.penguin "very blue"
+'
+
+test_expect_success 'get value for a key with value as an empty string' '
+       check_config get_value case.my ""
+'
+
+test_expect_success 'get value for a key with value as NULL' '
+       check_config get_value case.foo "(NULL)"
+'
+
+test_expect_success 'upper case key' '
+       check_config get_value case.UPPERCASE "true" &&
+       check_config get_value case.uppercase "true"
+'
+
+test_expect_success 'mixed case key' '
+       check_config get_value case.MixedCase "true" &&
+       check_config get_value case.MIXEDCASE "true" &&
+       check_config get_value case.mixedcase "true"
+'
+
+test_expect_success 'key and value with mixed case' '
+       check_config get_value case.Movie "BadPhysics"
+'
+
+test_expect_success 'key with case sensitive subsection' '
+       check_config get_value "my.Foo bAr.hi" "mixed-case" &&
+       check_config get_value "my.FOO BAR.hi" "upper-case" &&
+       check_config get_value "my.foo bar.hi" "lower-case"
+'
+
+test_expect_success 'key with case insensitive section header' '
+       check_config get_value cores.baz "ball" &&
+       check_config get_value Cores.baz "ball" &&
+       check_config get_value CORES.baz "ball" &&
+       check_config get_value coreS.baz "ball"
+'
+
+test_expect_success 'key with case insensitive section header & variable' '
+       check_config get_value CORES.BAZ "ball" &&
+       check_config get_value cores.baz "ball" &&
+       check_config get_value cores.BaZ "ball" &&
+       check_config get_value cOreS.bAz "ball"
+'
+
+test_expect_success 'find value with misspelled key' '
+       check_config expect_code 1 get_value "my.fOo Bar.hi" "Value not found for \"my.fOo Bar.hi\""
+'
+
+test_expect_success 'find value with the highest priority' '
+       check_config get_value case.baz "hask"
+'
+
+test_expect_success 'find integer value for a key' '
+       check_config get_int lamb.chop 65
+'
+
+test_expect_success 'find string value for a key' '
+       check_config get_string case.baz hask &&
+       check_config expect_code 1 get_string case.ba "Value not found for \"case.ba\""
+'
+
+test_expect_success 'check line error when NULL string is queried' '
+       test_expect_code 128 test-config get_string case.foo 2>result &&
+       test_i18ngrep "fatal: .*case\.foo.*\.git/config.*line 7" result
+'
+
+test_expect_success 'find integer if value is non parse-able' '
+       check_config expect_code 128 get_int lamb.head
+'
+
+test_expect_success 'find bool value for the entered key' '
+       check_config get_bool goat.head 1 &&
+       check_config get_bool goat.skin 0 &&
+       check_config get_bool goat.nose 1 &&
+       check_config get_bool goat.horns 1 &&
+       check_config get_bool goat.legs 1
+'
+
+test_expect_success 'find multiple values' '
+       check_config get_value_multi case.baz sam bat hask
+'
+
+test_expect_success 'find value from a configset' '
+       cat >config2 <<-\EOF &&
+       [case]
+               baz = lama
+       [my]
+               new = silk
+       [case]
+               baz = ball
+       EOF
+       echo silk >expect &&
+       test-config configset_get_value my.new config2 .git/config >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'find value with highest priority from a configset' '
+       echo hask >expect &&
+       test-config configset_get_value case.baz config2 .git/config >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'find value_list for a key from a configset' '
+       cat >except <<-\EOF &&
+       sam
+       bat
+       hask
+       lama
+       ball
+       EOF
+       test-config configset_get_value case.baz config2 .git/config >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'proper error on non-existent files' '
+       echo "Error (-1) reading configuration file non-existent-file." >expect &&
+       test_expect_code 2 test-config configset_get_value foo.bar non-existent-file 2>actual &&
+       test_cmp expect actual
+'
+
+test_expect_success POSIXPERM,SANITY 'proper error on non-accessible files' '
+       chmod -r .git/config &&
+       test_when_finished "chmod +r .git/config" &&
+       echo "Error (-1) reading configuration file .git/config." >expect &&
+       test_expect_code 2 test-config configset_get_value foo.bar .git/config 2>actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'proper error on error in default config files' '
+       cp .git/config .git/config.old &&
+       test_when_finished "mv .git/config.old .git/config" &&
+       echo "[" >>.git/config &&
+       echo "fatal: bad config file line 35 in .git/config" >expect &&
+       test_expect_code 128 test-config get_value foo.bar 2>actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'proper error on error in custom config files' '
+       echo "[" >>syntax-error &&
+       echo "fatal: bad config file line 1 in syntax-error" >expect &&
+       test_expect_code 128 test-config configset_get_value foo.bar syntax-error 2>actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'check line errors for malformed values' '
+       mv .git/config .git/config.old &&
+       test_when_finished "mv .git/config.old .git/config" &&
+       cat >.git/config <<-\EOF &&
+       [alias]
+               br
+       EOF
+       test_expect_code 128 git br 2>result &&
+       test_i18ngrep "fatal: .*alias\.br.*\.git/config.*line 2" result
+'
+
+test_done
index 4bc7141226c802ca049a76e978b6196f9e9fd7ff..e5dc62e9efbf9c26bad93c7384f9fb9fa6a970e8 100755 (executable)
@@ -7,7 +7,7 @@ test_description='Test git check-ref-format'
 valid_ref() {
        prereq=
        case $1 in
-       [A-Z]*)
+       [A-Z!]*)
                prereq=$1
                shift
        esac
@@ -19,7 +19,7 @@ valid_ref() {
 invalid_ref() {
        prereq=
        case $1 in
-       [A-Z]*)
+       [A-Z!]*)
                prereq=$1
                shift
        esac
@@ -30,17 +30,17 @@ invalid_ref() {
 }
 
 invalid_ref ''
-invalid_ref NOT_MINGW '/'
-invalid_ref NOT_MINGW '/' --allow-onelevel
-invalid_ref NOT_MINGW '/' --normalize
-invalid_ref NOT_MINGW '/' '--allow-onelevel --normalize'
+invalid_ref !MINGW '/'
+invalid_ref !MINGW '/' --allow-onelevel
+invalid_ref !MINGW '/' --normalize
+invalid_ref !MINGW '/' '--allow-onelevel --normalize'
 valid_ref 'foo/bar/baz'
 valid_ref 'foo/bar/baz' --normalize
 invalid_ref 'refs///heads/foo'
 valid_ref 'refs///heads/foo' --normalize
 invalid_ref 'heads/foo/'
-invalid_ref NOT_MINGW '/heads/foo'
-valid_ref NOT_MINGW '/heads/foo' --normalize
+invalid_ref !MINGW '/heads/foo'
+valid_ref !MINGW '/heads/foo' --normalize
 invalid_ref '///heads/foo'
 valid_ref '///heads/foo' --normalize
 invalid_ref './foo'
@@ -120,14 +120,14 @@ invalid_ref "$ref" --refspec-pattern
 invalid_ref "$ref" '--refspec-pattern --allow-onelevel'
 
 ref='/foo'
-invalid_ref NOT_MINGW "$ref"
-invalid_ref NOT_MINGW "$ref" --allow-onelevel
-invalid_ref NOT_MINGW "$ref" --refspec-pattern
-invalid_ref NOT_MINGW "$ref" '--refspec-pattern --allow-onelevel'
-invalid_ref NOT_MINGW "$ref" --normalize
-valid_ref NOT_MINGW "$ref" '--allow-onelevel --normalize'
-invalid_ref NOT_MINGW "$ref" '--refspec-pattern --normalize'
-valid_ref NOT_MINGW "$ref" '--refspec-pattern --allow-onelevel --normalize'
+invalid_ref !MINGW "$ref"
+invalid_ref !MINGW "$ref" --allow-onelevel
+invalid_ref !MINGW "$ref" --refspec-pattern
+invalid_ref !MINGW "$ref" '--refspec-pattern --allow-onelevel'
+invalid_ref !MINGW "$ref" --normalize
+valid_ref !MINGW "$ref" '--allow-onelevel --normalize'
+invalid_ref !MINGW "$ref" '--refspec-pattern --normalize'
+valid_ref !MINGW "$ref" '--refspec-pattern --allow-onelevel --normalize'
 
 test_expect_success "check-ref-format --branch @{-1}" '
        T=$(git write-tree) &&
@@ -162,7 +162,7 @@ test_expect_success 'check-ref-format --branch from subdir' '
 valid_ref_normalized() {
        prereq=
        case $1 in
-       [A-Z]*)
+       [A-Z!]*)
                prereq=$1
                shift
        esac
@@ -174,7 +174,7 @@ valid_ref_normalized() {
 invalid_ref_normalized() {
        prereq=
        case $1 in
-       [A-Z]*)
+       [A-Z!]*)
                prereq=$1
                shift
        esac
@@ -185,10 +185,10 @@ invalid_ref_normalized() {
 
 valid_ref_normalized 'heads/foo' 'heads/foo'
 valid_ref_normalized 'refs///heads/foo' 'refs/heads/foo'
-valid_ref_normalized NOT_MINGW '/heads/foo' 'heads/foo'
+valid_ref_normalized !MINGW '/heads/foo' 'heads/foo'
 valid_ref_normalized '///heads/foo' 'heads/foo'
 invalid_ref_normalized 'foo'
-invalid_ref_normalized NOT_MINGW '/foo'
+invalid_ref_normalized !MINGW '/foo'
 invalid_ref_normalized 'heads/foo/../bar'
 invalid_ref_normalized 'heads/./foo'
 invalid_ref_normalized 'heads\foo'
index b52397afd3352b873c9c7fabb91eb850aaf0db3b..019fddd4e81ed7b2103f916a634f3e85e7291017 100755 (executable)
@@ -214,6 +214,44 @@ test_expect_success 'tag pointing to something else than its type' '
        test_must_fail git fsck --tags
 '
 
+test_expect_success 'tag with incorrect tag name & missing tagger' '
+       sha=$(git rev-parse HEAD) &&
+       cat >wrong-tag <<-EOF &&
+       object $sha
+       type commit
+       tag wrong name format
+
+       This is an invalid tag.
+       EOF
+
+       tag=$(git hash-object -t tag -w --stdin <wrong-tag) &&
+       test_when_finished "remove_object $tag" &&
+       echo $tag >.git/refs/tags/wrong &&
+       test_when_finished "git update-ref -d refs/tags/wrong" &&
+       git fsck --tags 2>out &&
+       grep "invalid .tag. name" out &&
+       grep "expected .tagger. line" out
+'
+
+test_expect_success 'tag with bad tagger' '
+       sha=$(git rev-parse HEAD) &&
+       cat >wrong-tag <<-EOF &&
+       object $sha
+       type commit
+       tag not-quite-wrong
+       tagger Bad Tagger Name
+
+       This is an invalid tag.
+       EOF
+
+       tag=$(git hash-object --literally -t tag -w --stdin <wrong-tag) &&
+       test_when_finished "remove_object $tag" &&
+       echo $tag >.git/refs/tags/wrong &&
+       test_when_finished "git update-ref -d refs/tags/wrong" &&
+       test_must_fail git fsck --tags 2>out &&
+       grep "error in tag .*: invalid author/committer" out
+'
+
 test_expect_success 'cleaned up' '
        git fsck >actual 2>&1 &&
        test_cmp empty actual
index 922423e7d01699b7f56e482c08355942a560671a..ebe7c3b87c34755399495a375b9f4b7e0a45b1c1 100755 (executable)
@@ -19,7 +19,7 @@ sed -e 's/^|//' >expect <<\END_EXPECT
 |    -d, --data[=...]      short and long option with an optional argument
 |
 |Argument hints
-|    -b <arg>              short option required argument
+|    -B <arg>              short option required argument
 |    --bar2 <arg>          long option required argument
 |    -e, --fuz <with-space>
 |                          short and long option required argument
@@ -51,7 +51,7 @@ sed -e 's/^|//' >optionspec <<\EOF
 |d,data?   short and long option with an optional argument
 |
 | Argument hints
-|b=arg     short option required argument
+|B=arg     short option required argument
 |bar2=arg  long option required argument
 |e,fuz=with-space  short and long option required argument
 |s?some    short option optional argument
index 813cc1b3e29ec840deb63ad9c3c1dffd2187cdc5..823fe1d79924b68950a59ffde902b16db29205b6 100755 (executable)
@@ -72,15 +72,42 @@ test_expect_success 'fails with any bad rev or many good revs' '
 
 test_expect_success 'fails silently when using -q' '
        test_must_fail git rev-parse --verify --quiet 2>error &&
-       test -z "$(cat error)" &&
+       test_must_be_empty error &&
        test_must_fail git rev-parse -q --verify foo 2>error &&
-       test -z "$(cat error)" &&
+       test_must_be_empty error &&
        test_must_fail git rev-parse --verify -q HEAD bar 2>error &&
-       test -z "$(cat error)" &&
+       test_must_be_empty error &&
        test_must_fail git rev-parse --quiet --verify baz HEAD 2>error &&
-       test -z "$(cat error)" &&
+       test_must_be_empty error &&
        test_must_fail git rev-parse -q --verify $HASH2 HEAD 2>error &&
-       test -z "$(cat error)"
+       test_must_be_empty error
+'
+
+test_expect_success 'fails silently when using -q with deleted reflogs' '
+       ref=$(git rev-parse HEAD) &&
+       : >.git/logs/refs/test &&
+       git update-ref -m "message for refs/test" refs/test "$ref" &&
+       git reflog delete --updateref --rewrite refs/test@{0} &&
+       test_must_fail git rev-parse -q --verify refs/test@{0} >error 2>&1 &&
+       test_must_be_empty error
+'
+
+test_expect_success 'fails silently when using -q with not enough reflogs' '
+       ref=$(git rev-parse HEAD) &&
+       : >.git/logs/refs/test2 &&
+       git update-ref -m "message for refs/test2" refs/test2 "$ref" &&
+       test_must_fail git rev-parse -q --verify refs/test2@{999} >error 2>&1 &&
+       test_must_be_empty error
+'
+
+test_expect_success 'succeeds silently with -q and reflogs that do not go far back enough in time' '
+       ref=$(git rev-parse HEAD) &&
+       : >.git/logs/refs/test3 &&
+       git update-ref -m "message for refs/test3" refs/test3 "$ref" &&
+       git rev-parse -q --verify refs/test3@{1.year.ago} >actual 2>error &&
+       test_must_be_empty error &&
+       echo "$ref" >expect &&
+       test_cmp expect actual
 '
 
 test_expect_success 'no stdout output on error' '
index 141b0611eac306616078a599a216c6050dc45389..912a6635a808cbb6ae78dec545441d363bdeb0d0 100755 (executable)
@@ -130,4 +130,33 @@ test_expect_success 'implicit --list conflicts with modification options' '
 
 '
 
+# We want to set up a case where the walk for the tracking info
+# of one branch crosses the tip of another branch (and make sure
+# that the latter walk does not mess up our flag to see if it was
+# merged).
+#
+# Here "topic" tracks "master" with one extra commit, and "zzz" points to the
+# same tip as master The name "zzz" must come alphabetically after "topic"
+# as we process them in that order.
+test_expect_success 'branch --merged with --verbose' '
+       git branch --track topic master &&
+       git branch zzz topic &&
+       git checkout topic &&
+       test_commit foo &&
+       git branch --merged topic >actual &&
+       cat >expect <<-\EOF &&
+         master
+       * topic
+         zzz
+       EOF
+       test_cmp expect actual &&
+       git branch --verbose --merged topic >actual &&
+       cat >expect <<-\EOF &&
+         master c77a0a9 second on master
+       * topic  2c939f4 [ahead 1] foo
+         zzz    c77a0a9 second on master
+       EOF
+       test_cmp expect actual
+'
+
 test_done
index 3a017bf437395526cf54403d4ea1db36a3cff0b3..aa9eb3a3e5ef0637615c6d958a29dbd9bbbf0895 100755 (executable)
@@ -11,7 +11,9 @@ semantic is still the same.
 '
 . ./test-lib.sh
 
-echo '[core] logallrefupdates = true' >>.git/config
+test_expect_success 'enable reflogs' '
+       git config core.logallrefupdates true
+'
 
 test_expect_success \
     'prepare a trivial repository' \
@@ -158,4 +160,31 @@ test_expect_success 'pack ref directly below refs/' '
        test_path_is_missing .git/refs/top
 '
 
+test_expect_success 'disable reflogs' '
+       git config core.logallrefupdates false &&
+       rm -rf .git/logs
+'
+
+test_expect_success 'create packed foo/bar/baz branch' '
+       git branch foo/bar/baz &&
+       git pack-refs --all --prune &&
+       test_path_is_missing .git/refs/heads/foo/bar/baz &&
+       test_path_is_missing .git/logs/refs/heads/foo/bar/baz
+'
+
+test_expect_success 'notice d/f conflict with existing directory' '
+       test_must_fail git branch foo &&
+       test_must_fail git branch foo/bar
+'
+
+test_expect_success 'existing directory reports concrete ref' '
+       test_must_fail git branch foo 2>stderr &&
+       grep refs/heads/foo/bar/baz stderr
+'
+
+test_expect_success 'notice d/f conflict with existing ref' '
+       test_must_fail git branch foo/bar/baz/extra &&
+       test_must_fail git branch foo/bar/baz/lots/of/extra/components
+'
+
 test_done
index 8d44e04354f05856465904700ff0374dae74ba59..7217c5e222baf0b99b934e36b9418c9d8e13ae9d 100755 (executable)
@@ -7,8 +7,6 @@ test_description='Test commit notes index (expensive!)'
 
 . ./test-lib.sh
 
-test -n "$GIT_NOTES_TIMING_TESTS" && test_set_prereq EXPENSIVE
-
 create_repo () {
        number_of_commits=$1
        nr=0
index 9292b499f39925b6832bccd826fb43a8818f155a..217dd79b2e4b5c02ee27f3b913c37c489ec585f2 100755 (executable)
@@ -4,8 +4,6 @@ test_description='git rebase - test patch id computation'
 
 . ./test-lib.sh
 
-test -n "$GIT_PATCHID_TIMING_TESTS" && test_set_prereq EXPENSIVE
-
 count () {
        i=0
        while test $i -lt $1
index 55c8a2f57677085fe1185cd2e3e6d9a2021fd744..a392f3d1d66757361ff9fc4e26f4125da5ab0a4f 100755 (executable)
@@ -54,7 +54,7 @@ test_expect_success setup '
        git add yours &&
        git commit -s -m "Second on side" &&
 
-       if test_have_prereq NOT_MINGW
+       if test_have_prereq !MINGW
        then
                # the second one on the side branch is ISO-8859-1
                git config i18n.commitencoding ISO8859-1 &&
@@ -122,7 +122,7 @@ test_expect_success 'rebase (U/L)' '
        check_encoding 2
 '
 
-test_expect_success NOT_MINGW 'rebase (L/L)' '
+test_expect_success !MINGW 'rebase (L/L)' '
        # In this test we want ISO-8859-1 encoded commits as the result
        git config i18n.commitencoding ISO8859-1 &&
        git config i18n.logoutputencoding ISO8859-1 &&
@@ -134,7 +134,7 @@ test_expect_success NOT_MINGW 'rebase (L/L)' '
        check_encoding 2 8859
 '
 
-test_expect_success NOT_MINGW 'rebase (L/U)' '
+test_expect_success !MINGW 'rebase (L/U)' '
        # This is pathological -- use UTF-8 as intermediate form
        # to get ISO-8859-1 results.
        git config i18n.commitencoding ISO8859-1 &&
@@ -162,7 +162,7 @@ test_expect_success 'cherry-pick(U/U)' '
        check_encoding 3
 '
 
-test_expect_success NOT_MINGW 'cherry-pick(L/L)' '
+test_expect_success !MINGW 'cherry-pick(L/L)' '
        # Both the commitencoding and logoutputencoding is set to ISO-8859-1
 
        git config i18n.commitencoding ISO8859-1 &&
@@ -192,7 +192,7 @@ test_expect_success 'cherry-pick(U/L)' '
        check_encoding 3
 '
 
-test_expect_success NOT_MINGW 'cherry-pick(L/U)' '
+test_expect_success !MINGW 'cherry-pick(L/U)' '
        # Again, the commitencoding is set to ISO-8859-1 but
        # logoutputencoding is set to UTF-8.
 
index 5b79b216e2e3bb837e58828a2e9a292cb2d7cc53..1e29962fad30edb263cd07b6586f1b1a962c88cf 100755 (executable)
@@ -685,4 +685,46 @@ test_expect_success 'handle stash specification with spaces' '
        grep pig file
 '
 
+test_expect_success 'setup stash with index and worktree changes' '
+       git stash clear &&
+       git reset --hard &&
+       echo index >file &&
+       git add file &&
+       echo working >file &&
+       git stash
+'
+
+test_expect_success 'stash list implies --first-parent -m' '
+       cat >expect <<-\EOF &&
+       stash@{0}: WIP on master: b27a2bc subdir
+
+       diff --git a/file b/file
+       index 257cc56..d26b33d 100644
+       --- a/file
+       +++ b/file
+       @@ -1 +1 @@
+       -foo
+       +working
+       EOF
+       git stash list -p >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'stash list --cc shows combined diff' '
+       cat >expect <<-\EOF &&
+       stash@{0}: WIP on master: b27a2bc subdir
+
+       diff --cc file
+       index 257cc56,9015a7a..d26b33d
+       --- a/file
+       +++ b/file
+       @@@ -1,1 -1,1 +1,1 @@@
+       - foo
+        -index
+       ++working
+       EOF
+       git stash list -p --cc >actual &&
+       test_cmp expect actual
+'
+
 test_done
index cd0454356a6ea26c630f76748dd2c4f73bed8526..741e0803c1ac0a418c98c7eee9cb449a7c60da06 100755 (executable)
@@ -79,7 +79,7 @@ test_expect_success 'non-integer config parsing' '
 test_expect_success 'negative integer config parsing' '
        git config diff.context -1 &&
        test_must_fail git diff 2>output &&
-       test_i18ngrep "bad config file" output
+       test_i18ngrep "bad config variable" output
 '
 
 test_expect_success '-U0 is valid, so is diff.context=0' '
index 565c020c45434bf151d7a142ebe1a1cca3299ab4..7600a3e3e8f4fab47abd68a29bb06defb6bbce02 100755 (executable)
@@ -93,7 +93,7 @@ test_expect_success 'output from user-defined format is re-wrapped' '
        test_cmp expect log.predictable
 '
 
-test_expect_success NOT_MINGW 'shortlog wrapping' '
+test_expect_success !MINGW 'shortlog wrapping' '
        cat >expect <<\EOF &&
 A U Thor (5):
       Test
@@ -114,7 +114,7 @@ EOF
        test_cmp expect out
 '
 
-test_expect_success NOT_MINGW 'shortlog from non-git directory' '
+test_expect_success !MINGW 'shortlog from non-git directory' '
        git log HEAD >log &&
        GIT_DIR=non-existing git shortlog -w <log >out &&
        test_cmp expect out
@@ -159,7 +159,7 @@ $DSCHO (2):
 
 EOF
 
-test_expect_success NOT_MINGW 'shortlog encoding' '
+test_expect_success !MINGW 'shortlog encoding' '
        git reset --hard "$commit" &&
        git config --unset i18n.commitencoding &&
        echo 2 > a1 &&
index 349c531989326eacfe1e1448bfed740d7fd4bd8e..7398605e7b894259548f257aaf3e92d9481534eb 100755 (executable)
@@ -431,6 +431,21 @@ EOF
        test_cmp expected actual
 '
 
+test_expect_success 'strbuf_utf8_replace() not producing NUL' '
+       git log --color --pretty="tformat:%<(10,trunc)%s%>>(10,ltrunc)%C(auto)%d" |
+               test_decode_color |
+               nul_to_q >actual &&
+       ! grep Q actual
+'
+
+# ISO strict date format
+test_expect_success 'ISO and ISO-strict date formats display the same values' '
+       git log --format=%ai%n%ci |
+       sed -e "s/ /T/; s/ //; s/..\$/:&/" >expected &&
+       git log --format=%aI%n%cI >actual &&
+       test_cmp expected actual
+'
+
 # get new digests (with no abbreviations)
 head1=$(git rev-parse --verify HEAD~0) &&
 head2=$(git rev-parse --verify HEAD~1) &&
@@ -450,4 +465,15 @@ EOF
        test_cmp expected actual1
 '
 
+test_expect_success 'clean log decoration' '
+       git log --no-walk --tags --pretty="%H %D" --decorate=full >actual &&
+       cat >expected <<EOF &&
+$head1 tag: refs/tags/tag2
+$head2 tag: refs/tags/message-one
+$old_head1 tag: refs/tags/message-two
+EOF
+       sort actual >actual1 &&
+       test_cmp expected actual1
+'
+
 test_done
index 9110404e55eaacd10a73d7d4b2bae7f288a031b1..e585fe6129b7af264427d8af46de21cb08efad7f 100755 (executable)
@@ -34,7 +34,7 @@ test_expect_success 'log --grep searches in log output encoding (utf8)' '
        test_cmp expect actual
 '
 
-test_expect_success NOT_MINGW 'log --grep searches in log output encoding (latin1)' '
+test_expect_success !MINGW 'log --grep searches in log output encoding (latin1)' '
        cat >expect <<-\EOF &&
        latin1
        utf8
@@ -43,7 +43,7 @@ test_expect_success NOT_MINGW 'log --grep searches in log output encoding (latin
        test_cmp expect actual
 '
 
-test_expect_success NOT_MINGW 'log --grep does not find non-reencoded values (utf8)' '
+test_expect_success !MINGW 'log --grep does not find non-reencoded values (utf8)' '
        >expect &&
        git log --encoding=utf8 --format=%s --grep=$latin1_e >actual &&
        test_cmp expect actual
index 305bcac6b765111106887d4d24d99657c0554b5b..83d20c4ba9640fff27777917da0342940c33e0e3 100755 (executable)
@@ -113,4 +113,9 @@ test_expect_success 'archive empty subtree by direct pathspec' '
        check_dir extract sub
 '
 
+test_expect_success 'archive applies umask even for pax headers' '
+       git archive --format=tar HEAD >archive.tar &&
+       ! grep 0666 archive.tar
+'
+
 test_done
index 3e64a7a65da86410dd0236975bef9bd0013a6405..9e1ad1ca21341d449fa3ab1b896a899e51272127 100755 (executable)
@@ -89,4 +89,22 @@ test_expect_success 'mailinfo on from header without name works' '
 
 '
 
+test_expect_success 'mailinfo finds headers after embedded From line' '
+       mkdir embed-from &&
+       git mailsplit -oembed-from "$TEST_DIRECTORY"/t5100/embed-from.in &&
+       test_cmp "$TEST_DIRECTORY"/t5100/embed-from.in embed-from/0001 &&
+       git mailinfo embed-from/msg embed-from/patch \
+         <embed-from/0001 >embed-from/out &&
+       test_cmp "$TEST_DIRECTORY"/t5100/embed-from.expect embed-from/out
+'
+
+test_expect_success 'mailinfo on message with quoted >From' '
+       mkdir quoted-from &&
+       git mailsplit -oquoted-from "$TEST_DIRECTORY"/t5100/quoted-from.in &&
+       test_cmp "$TEST_DIRECTORY"/t5100/quoted-from.in quoted-from/0001 &&
+       git mailinfo quoted-from/msg quoted-from/patch \
+         <quoted-from/0001 >quoted-from/out &&
+       test_cmp "$TEST_DIRECTORY"/t5100/quoted-from.expect quoted-from/msg
+'
+
 test_done
diff --git a/t/t5100/embed-from.expect b/t/t5100/embed-from.expect
new file mode 100644 (file)
index 0000000..06a3a38
--- /dev/null
@@ -0,0 +1,5 @@
+Author: Commit Author
+Email: commit@example.com
+Subject: patch subject
+Date: Sat, 13 Sep 2014 21:13:23 -0400 
+
diff --git a/t/t5100/embed-from.in b/t/t5100/embed-from.in
new file mode 100644 (file)
index 0000000..5f3f84e
--- /dev/null
@@ -0,0 +1,13 @@
+From 1234567890123456789012345678901234567890 Mon Sep 17 00:00:00 2001
+From: Email Author <email@example.com>
+Date: Sun, 25 May 2008 00:38:18 -0700
+Subject: [PATCH] email subject
+
+>From 1234567890123456789012345678901234567890 Mon Sep 17 00:00:00 2001
+From: Commit Author <commit@example.com>
+Date: Sat, 13 Sep 2014 21:13:23 -0400
+Subject: patch subject
+
+patch body
+---
+patch
diff --git a/t/t5100/quoted-from.expect b/t/t5100/quoted-from.expect
new file mode 100644 (file)
index 0000000..8c9d48c
--- /dev/null
@@ -0,0 +1,3 @@
+>From the depths of history, we are stuck with the
+flaky mbox format.
+
diff --git a/t/t5100/quoted-from.in b/t/t5100/quoted-from.in
new file mode 100644 (file)
index 0000000..847e1c4
--- /dev/null
@@ -0,0 +1,10 @@
+From 1234567890123456789012345678901234567890 Mon Sep 17 00:00:00 2001
+From: Author Name <somebody@example.com>
+Date: Sun, 25 May 2008 00:38:18 -0700
+Subject: [PATCH] testing quoted >From
+
+>From the depths of history, we are stuck with the
+flaky mbox format.
+
+---
+patch
index 4bbb718751738c3e913c25160d0fff52d8350bba..61bc8da56028625fa2525cc5b067d40367f2b1c6 100755 (executable)
@@ -243,4 +243,23 @@ test_expect_success 'running index-pack in the object store' '
     test -f .git/objects/pack/pack-${pack1}.idx
 '
 
+test_expect_success 'index-pack --strict warns upon missing tagger in tag' '
+    sha=$(git rev-parse HEAD) &&
+    cat >wrong-tag <<EOF &&
+object $sha
+type commit
+tag guten tag
+
+This is an invalid tag.
+EOF
+
+    tag=$(git hash-object -t tag -w --stdin <wrong-tag) &&
+    pack1=$(echo $tag $sha | git pack-objects tag-test) &&
+    echo remove tag object &&
+    thirtyeight=${tag#??} &&
+    rm -f .git/objects/${tag%$thirtyeight}/$thirtyeight &&
+    git index-pack --strict tag-test-${pack1}.pack 2>err &&
+    grep "^error:.* expected .tagger. line" err
+'
+
 test_done
index 17bcb0b04096eabb29c13a025fd2afe8d1e4623b..7f278d8ce932f34420c337571ec043ffb5e318e9 100755 (executable)
@@ -135,4 +135,17 @@ test_expect_success 'send-pack stderr contains hook messages' '
        test_cmp expect actual
 '
 
+test_expect_success 'pre-receive hook that forgets to read its input' '
+       write_script victim.git/hooks/pre-receive <<-\EOF &&
+       exit 0
+       EOF
+       rm -f victim.git/hooks/update victim.git/hooks/post-update &&
+
+       for v in $(test_seq 100 999)
+       do
+               git branch branch_$v master || return
+       done &&
+       git push ./victim.git "+refs/heads/*:refs/heads/*"
+'
+
 test_done
index 5e67035be800b5cbec5a99dd9e3e458a343440df..e4f10c0f68b94bfa719c3d208f622541506c86b3 100755 (executable)
@@ -318,7 +318,7 @@ test_expect_success 'clone myhost:src uses ssh' '
        expect_ssh myhost src
 '
 
-test_expect_success NOT_MINGW,NOT_CYGWIN 'clone local path foo:bar' '
+test_expect_success !MINGW,!CYGWIN 'clone local path foo:bar' '
        cp -R src "foo:bar" &&
        git clone "foo:bar" foobar &&
        expect_ssh none
@@ -339,7 +339,7 @@ test_clone_url () {
        expect_ssh "$2" "$3"
 }
 
-test_expect_success NOT_MINGW 'clone c:temp is ssl' '
+test_expect_success !MINGW 'clone c:temp is ssl' '
        test_clone_url c:temp c temp
 '
 
index a953f1b55cc26aae703d3c84f74df3265cc2ed57..6464a16a192f495c5aab5ec1af17d3e17acaded6 100755 (executable)
@@ -13,6 +13,7 @@ test_expect_success 'mode change in one branch: keep changed version' '
        git commit -m a &&
        git checkout -b b1 master &&
        test_chmod +x file1 &&
+       git add file1 &&
        git commit -m b1 &&
        git checkout a1 &&
        git merge-recursive master -- a1 b1 &&
index d9c2d386ddf8caff4b87fa457c23757f76c293c7..85c10b0940a896bb49aefee9a2885b1c39217bab 100755 (executable)
@@ -72,6 +72,10 @@ test_expect_success 'Merge after setting text=auto' '
        same line
        EOF
 
+       if test_have_prereq NATIVE_CRLF; then
+               append_cr <expected >expected.temp &&
+               mv expected.temp expected
+       fi &&
        git config merge.renormalize true &&
        git rm -fr . &&
        rm -f .gitattributes &&
@@ -86,6 +90,10 @@ test_expect_success 'Merge addition of text=auto' '
        same line
        EOF
 
+       if test_have_prereq NATIVE_CRLF; then
+               append_cr <expected >expected.temp &&
+               mv expected.temp expected
+       fi &&
        git config merge.renormalize true &&
        git rm -fr . &&
        rm -f .gitattributes &&
@@ -95,16 +103,19 @@ test_expect_success 'Merge addition of text=auto' '
 '
 
 test_expect_success 'Detect CRLF/LF conflict after setting text=auto' '
-       q_to_cr <<-\EOF >expected &&
-       <<<<<<<
-       first line
-       same line
-       =======
-       first lineQ
-       same lineQ
-       >>>>>>>
-       EOF
-
+       echo "<<<<<<<" >expected &&
+       if test_have_prereq NATIVE_CRLF; then
+               echo first line | append_cr >>expected &&
+               echo same line | append_cr >>expected &&
+               echo ======= | append_cr >>expected
+       else
+               echo first line >>expected &&
+               echo same line >>expected &&
+               echo ======= >>expected
+       fi &&
+       echo first line | append_cr >>expected &&
+       echo same line | append_cr >>expected &&
+       echo ">>>>>>>" >>expected &&
        git config merge.renormalize false &&
        rm -f .gitattributes &&
        git reset --hard a &&
@@ -114,16 +125,19 @@ test_expect_success 'Detect CRLF/LF conflict after setting text=auto' '
 '
 
 test_expect_success 'Detect LF/CRLF conflict from addition of text=auto' '
-       q_to_cr <<-\EOF >expected &&
-       <<<<<<<
-       first lineQ
-       same lineQ
-       =======
-       first line
-       same line
-       >>>>>>>
-       EOF
-
+       echo "<<<<<<<" >expected &&
+       echo first line | append_cr >>expected &&
+       echo same line | append_cr >>expected &&
+       if test_have_prereq NATIVE_CRLF; then
+               echo ======= | append_cr >>expected &&
+               echo first line | append_cr >>expected &&
+               echo same line | append_cr >>expected
+       else
+               echo ======= >>expected &&
+               echo first line >>expected &&
+               echo same line >>expected
+       fi &&
+       echo ">>>>>>>" >>expected &&
        git config merge.renormalize false &&
        rm -f .gitattributes &&
        git reset --hard b &&
index a6e73d063544a5856647d5cb9dc1260a0454f7ff..847d098c094566aafd8dd05fd3962e28f113360e 100755 (executable)
@@ -33,7 +33,7 @@ author $SJIS_NAME
 summary $SJIS_MSG
 EOF
 
-test_expect_success NOT_MINGW \
+test_expect_success !MINGW \
        'blame respects i18n.commitencoding' '
        git blame --incremental file | \
                egrep "^(author|summary) " > actual &&
@@ -49,7 +49,7 @@ author $EUC_JAPAN_NAME
 summary $EUC_JAPAN_MSG
 EOF
 
-test_expect_success NOT_MINGW \
+test_expect_success !MINGW \
        'blame respects i18n.logoutputencoding' '
        git config i18n.logoutputencoding eucJP &&
        git blame --incremental file | \
@@ -66,7 +66,7 @@ author $UTF8_NAME
 summary $UTF8_MSG
 EOF
 
-test_expect_success NOT_MINGW \
+test_expect_success !MINGW \
        'blame respects --encoding=UTF-8' '
        git blame --incremental --encoding=UTF-8 file | \
                egrep "^(author|summary) " > actual &&
@@ -82,7 +82,7 @@ author $UTF8_NAME
 summary $UTF8_MSG
 EOF
 
-test_expect_success NOT_MINGW \
+test_expect_success !MINGW \
        'blame respects --encoding=none' '
        git blame --incremental --encoding=none file | \
                egrep "^(author|summary) " > actual &&
index ff19695e776f803aef03a18e70067c89aa3be218..f16f3234a1acb9953ba33578b6cb689e2583ea80 100755 (executable)
@@ -74,6 +74,36 @@ test_expect_success 'info .' "
        test_cmp_info expected.info-dot actual.info-dot
        "
 
+test_expect_success 'info $(pwd)' '
+       (cd svnwc; svn info "$(pwd)") >expected.info-pwd &&
+       (cd gitwc; git svn info "$(pwd)") >actual.info-pwd &&
+       grep -v ^Path: <expected.info-pwd >expected.info-np &&
+       grep -v ^Path: <actual.info-pwd >actual.info-np &&
+       test_cmp_info expected.info-np actual.info-np &&
+       test "$(sed -ne \"/^Path:/ s!/svnwc!!\" <expected.info-pwd)" = \
+            "$(sed -ne \"/^Path:/ s!/gitwc!!\" <actual.info-pwd)"
+       '
+
+test_expect_success 'info $(pwd)/../___wc' '
+       (cd svnwc; svn info "$(pwd)/../svnwc") >expected.info-pwd &&
+       (cd gitwc; git svn info "$(pwd)/../gitwc") >actual.info-pwd &&
+       grep -v ^Path: <expected.info-pwd >expected.info-np &&
+       grep -v ^Path: <actual.info-pwd >actual.info-np &&
+       test_cmp_info expected.info-np actual.info-np &&
+       test "$(sed -ne \"/^Path:/ s!/svnwc!!\" <expected.info-pwd)" = \
+            "$(sed -ne \"/^Path:/ s!/gitwc!!\" <actual.info-pwd)"
+       '
+
+test_expect_success 'info $(pwd)/../___wc//file' '
+       (cd svnwc; svn info "$(pwd)/../svnwc//file") >expected.info-pwd &&
+       (cd gitwc; git svn info "$(pwd)/../gitwc//file") >actual.info-pwd &&
+       grep -v ^Path: <expected.info-pwd >expected.info-np &&
+       grep -v ^Path: <actual.info-pwd >actual.info-np &&
+       test_cmp_info expected.info-np actual.info-np &&
+       test "$(sed -ne \"/^Path:/ s!/svnwc!!\" <expected.info-pwd)" = \
+            "$(sed -ne \"/^Path:/ s!/gitwc!!\" <actual.info-pwd)"
+       '
+
 test_expect_success 'info --url .' '
        test "$(cd gitwc; git svn info --url .)" = "$quoted_svnrepo"
        '
index d400442a4a8891a6f20e1b764fa19488f803c9c4..8df0445a84f86d9097406478ee0b08be7eeda74b 100755 (executable)
@@ -2336,7 +2336,7 @@ test_expect_success 'R: cat-blob-fd must be a nonnegative integer' '
        test_must_fail git fast-import --cat-blob-fd=-1 </dev/null
 '
 
-test_expect_success NOT_MINGW 'R: print old blob' '
+test_expect_success !MINGW 'R: print old blob' '
        blob=$(echo "yes it can" | git hash-object -w --stdin) &&
        cat >expect <<-EOF &&
        ${blob} blob 11
@@ -2348,7 +2348,7 @@ test_expect_success NOT_MINGW 'R: print old blob' '
        test_cmp expect actual
 '
 
-test_expect_success NOT_MINGW 'R: in-stream cat-blob-fd not respected' '
+test_expect_success !MINGW 'R: in-stream cat-blob-fd not respected' '
        echo hello >greeting &&
        blob=$(git hash-object -w greeting) &&
        cat >expect <<-EOF &&
@@ -2369,7 +2369,7 @@ test_expect_success NOT_MINGW 'R: in-stream cat-blob-fd not respected' '
        test_cmp expect actual.1
 '
 
-test_expect_success NOT_MINGW 'R: print new blob' '
+test_expect_success !MINGW 'R: print new blob' '
        blob=$(echo "yep yep yep" | git hash-object --stdin) &&
        cat >expect <<-EOF &&
        ${blob} blob 12
@@ -2387,7 +2387,7 @@ test_expect_success NOT_MINGW 'R: print new blob' '
        test_cmp expect actual
 '
 
-test_expect_success NOT_MINGW 'R: print new blob by sha1' '
+test_expect_success !MINGW 'R: print new blob by sha1' '
        blob=$(echo "a new blob named by sha1" | git hash-object --stdin) &&
        cat >expect <<-EOF &&
        ${blob} blob 25
@@ -2687,7 +2687,7 @@ test_expect_success 'R: verify created pack' '
 test_expect_success \
        'R: verify written objects' \
        'git --git-dir=R/.git cat-file blob big-file:big1 >actual &&
-        test_cmp expect actual &&
+        test_cmp_bin expect actual &&
         a=$(git --git-dir=R/.git rev-parse big-file:big1) &&
         b=$(git --git-dir=R/.git rev-parse big-file:big2) &&
         test $a = $b'
@@ -2866,7 +2866,7 @@ test_expect_success 'S: notemodify with garbage after sha1 dataref must fail' '
 #
 # notemodify, mark in commit-ish
 #
-test_expect_success 'S: notemodify with garbarge after mark commit-ish must fail' '
+test_expect_success 'S: notemodify with garbage after mark commit-ish must fail' '
        test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
        commit refs/heads/Snotes
        committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
diff --git a/t/t9351-fast-export-anonymize.sh b/t/t9351-fast-export-anonymize.sh
new file mode 100755 (executable)
index 0000000..897dc50
--- /dev/null
@@ -0,0 +1,112 @@
+#!/bin/sh
+
+test_description='basic tests for fast-export --anonymize'
+. ./test-lib.sh
+
+test_expect_success 'setup simple repo' '
+       test_commit base &&
+       test_commit foo &&
+       git checkout -b other HEAD^ &&
+       mkdir subdir &&
+       test_commit subdir/bar &&
+       test_commit subdir/xyzzy &&
+       git tag -m "annotated tag" mytag
+'
+
+test_expect_success 'export anonymized stream' '
+       git fast-export --anonymize --all >stream
+'
+
+# this also covers commit messages
+test_expect_success 'stream omits path names' '
+       ! grep base stream &&
+       ! grep foo stream &&
+       ! grep subdir stream &&
+       ! grep bar stream &&
+       ! grep xyzzy stream
+'
+
+test_expect_success 'stream allows master as refname' '
+       grep master stream
+'
+
+test_expect_success 'stream omits other refnames' '
+       ! grep other stream &&
+       ! grep mytag stream
+'
+
+test_expect_success 'stream omits identities' '
+       ! grep "$GIT_COMMITTER_NAME" stream &&
+       ! grep "$GIT_COMMITTER_EMAIL" stream &&
+       ! grep "$GIT_AUTHOR_NAME" stream &&
+       ! grep "$GIT_AUTHOR_EMAIL" stream
+'
+
+test_expect_success 'stream omits tag message' '
+       ! grep "annotated tag" stream
+'
+
+# NOTE: we chdir to the new, anonymized repository
+# after this. All further tests should assume this.
+test_expect_success 'import stream to new repository' '
+       git init new &&
+       cd new &&
+       git fast-import <../stream
+'
+
+test_expect_success 'result has two branches' '
+       git for-each-ref --format="%(refname)" refs/heads >branches &&
+       test_line_count = 2 branches &&
+       other_branch=$(grep -v refs/heads/master branches)
+'
+
+test_expect_success 'repo has original shape and timestamps' '
+       shape () {
+               git log --format="%m %ct" --left-right --boundary "$@"
+       } &&
+       (cd .. && shape master...other) >expect &&
+       shape master...$other_branch >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'root tree has original shape' '
+       # the output entries are not necessarily in the same
+       # order, but we know at least that we will have one tree
+       # and one blob, so just check the sorted order
+       cat >expect <<-\EOF &&
+       blob
+       tree
+       EOF
+       git ls-tree $other_branch >root &&
+       cut -d" " -f2 <root | sort >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'paths in subdir ended up in one tree' '
+       cat >expect <<-\EOF &&
+       blob
+       blob
+       EOF
+       tree=$(grep tree root | cut -f2) &&
+       git ls-tree $other_branch:$tree >tree &&
+       cut -d" " -f2 <tree >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'tag points to branch tip' '
+       git rev-parse $other_branch >expect &&
+       git for-each-ref --format="%(*objectname)" | grep . >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'idents are shared' '
+       git log --all --format="%an <%ae>" >authors &&
+       sort -u authors >unique &&
+       test_line_count = 1 unique &&
+       git log --all --format="%cn <%ce>" >committers &&
+       sort -u committers >unique &&
+       test_line_count = 1 unique &&
+       ! test_cmp authors committers
+'
+
+test_done
index 23a827fa77d0a5d527cef29a15a205ee14d68e27..897b3c3034efcab3af88d8eddc4670e274361dd5 100755 (executable)
@@ -365,7 +365,7 @@ test_expect_success 'wildcard files submit back to p4, client-spec case' '
        (
                cd "$git" &&
                echo git-wild-hash >dir1/git-wild#hash &&
-               if test_have_prereq NOT_MINGW NOT_CYGWIN
+               if test_have_prereq !MINGW,!CYGWIN
                then
                        echo git-wild-star >dir1/git-wild\*star
                fi &&
@@ -379,7 +379,7 @@ test_expect_success 'wildcard files submit back to p4, client-spec case' '
        (
                cd "$cli" &&
                test_path_is_file dir1/git-wild#hash &&
-               if test_have_prereq NOT_MINGW NOT_CYGWIN
+               if test_have_prereq !MINGW,!CYGWIN
                then
                        test_path_is_file dir1/git-wild\*star
                fi &&
index c7472cbf54584c7610094677693114d41b422afe..0206771fbb91b734a626e628b21786805ebcfa22 100755 (executable)
@@ -14,7 +14,7 @@ test_expect_success 'add p4 files with wildcards in the names' '
                printf "file2\nhas\nsome\nrandom\ntext\n" >file2 &&
                p4 add file2 &&
                echo file-wild-hash >file-wild#hash &&
-               if test_have_prereq NOT_MINGW NOT_CYGWIN
+               if test_have_prereq !MINGW,!CYGWIN
                then
                        echo file-wild-star >file-wild\*star
                fi &&
@@ -31,7 +31,7 @@ test_expect_success 'wildcard files git p4 clone' '
        (
                cd "$git" &&
                test -f file-wild#hash &&
-               if test_have_prereq NOT_MINGW NOT_CYGWIN
+               if test_have_prereq !MINGW,!CYGWIN
                then
                        test -f file-wild\*star
                fi &&
@@ -46,7 +46,7 @@ test_expect_success 'wildcard files submit back to p4, add' '
        (
                cd "$git" &&
                echo git-wild-hash >git-wild#hash &&
-               if test_have_prereq NOT_MINGW NOT_CYGWIN
+               if test_have_prereq !MINGW,!CYGWIN
                then
                        echo git-wild-star >git-wild\*star
                fi &&
@@ -60,7 +60,7 @@ test_expect_success 'wildcard files submit back to p4, add' '
        (
                cd "$cli" &&
                test_path_is_file git-wild#hash &&
-               if test_have_prereq NOT_MINGW NOT_CYGWIN
+               if test_have_prereq !MINGW,!CYGWIN
                then
                        test_path_is_file git-wild\*star
                fi &&
@@ -75,7 +75,7 @@ test_expect_success 'wildcard files submit back to p4, modify' '
        (
                cd "$git" &&
                echo new-line >>git-wild#hash &&
-               if test_have_prereq NOT_MINGW NOT_CYGWIN
+               if test_have_prereq !MINGW,!CYGWIN
                then
                        echo new-line >>git-wild\*star
                fi &&
@@ -89,7 +89,7 @@ test_expect_success 'wildcard files submit back to p4, modify' '
        (
                cd "$cli" &&
                test_line_count = 2 git-wild#hash &&
-               if test_have_prereq NOT_MINGW NOT_CYGWIN
+               if test_have_prereq !MINGW,!CYGWIN
                then
                        test_line_count = 2 git-wild\*star
                fi &&
@@ -152,7 +152,7 @@ test_expect_success 'wildcard files submit back to p4, delete' '
        (
                cd "$cli" &&
                test_path_is_missing git-wild#hash &&
-               if test_have_prereq NOT_MINGW NOT_CYGWIN
+               if test_have_prereq !MINGW,!CYGWIN
                then
                        test_path_is_missing git-wild\*star
                fi &&
index 1243d96092ad5c6a66d66ee9debc399649ffa0a2..4cff6a760fc27b4f4f87c5f0387e34b3039e5518 100755 (executable)
@@ -417,7 +417,7 @@ test_expect_success 'cleanup chmod after submit cancel' '
                ! p4 fstat -T action text &&
                test_path_is_file text+x &&
                ! p4 fstat -T action text+x &&
-               if test_have_prereq NOT_CYGWIN
+               if test_have_prereq !CYGWIN
                then
                        stat --format=%A text | egrep ^-r-- &&
                        stat --format=%A text+x | egrep ^-r-x
index b1bc65bfb564ca85d35c42071f825360d1998392..82095e34eeb7ce9932abe1a5e97b1c2eb0888033 100644 (file)
@@ -870,7 +870,7 @@ case $(uname -s) in
        # backslashes in pathspec are converted to '/'
        # exec does not inherit the PID
        test_set_prereq MINGW
-       test_set_prereq NOT_CYGWIN
+       test_set_prereq NATIVE_CRLF
        test_set_prereq SED_STRIPS_CR
        test_set_prereq GREP_STRIPS_CR
        GIT_TEST_CMP=mingw_test_cmp
@@ -878,7 +878,6 @@ case $(uname -s) in
 *CYGWIN*)
        test_set_prereq POSIXPERM
        test_set_prereq EXECKEEPSPID
-       test_set_prereq NOT_MINGW
        test_set_prereq CYGWIN
        test_set_prereq SED_STRIPS_CR
        test_set_prereq GREP_STRIPS_CR
@@ -887,8 +886,6 @@ case $(uname -s) in
        test_set_prereq POSIXPERM
        test_set_prereq BSLASHPSPEC
        test_set_prereq EXECKEEPSPID
-       test_set_prereq NOT_MINGW
-       test_set_prereq NOT_CYGWIN
        ;;
 esac
 
index 1f3bcebfd76ae1b37e1542631a87e5a5e3e6b1eb..69e3c67b00f482449e77945eb114f58244078b1e 100755 (executable)
@@ -45,7 +45,7 @@ do
                commit=`git rev-list -n 1 --grep '^WIP' "$range"`
                if [ -n "$commit" ]
                then
-                       echo "Found WIP commit in $local_ref, not pushing"
+                       echo >&2 "Found WIP commit in $local_ref, not pushing"
                        exit 1
                fi
        fi
diff --git a/test-config.c b/test-config.c
new file mode 100644 (file)
index 0000000..6a77552
--- /dev/null
@@ -0,0 +1,152 @@
+#include "cache.h"
+#include "string-list.h"
+
+/*
+ * This program exposes the C API of the configuration mechanism
+ * as a set of simple commands in order to facilitate testing.
+ *
+ * Reads stdin and prints result of command to stdout:
+ *
+ * get_value -> prints the value with highest priority for the entered key
+ *
+ * get_value_multi -> prints all values for the entered key in increasing order
+ *                  of priority
+ *
+ * get_int -> print integer value for the entered key or die
+ *
+ * get_bool -> print bool value for the entered key or die
+ *
+ * get_string -> print string value for the entered key or die
+ *
+ * configset_get_value -> returns value with the highest priority for the entered key
+ *                     from a config_set constructed from files entered as arguments.
+ *
+ * configset_get_value_multi -> returns value_list for the entered key sorted in
+ *                             ascending order of priority from a config_set
+ *                             constructed from files entered as arguments.
+ *
+ * Examples:
+ *
+ * To print the value with highest priority for key "foo.bAr Baz.rock":
+ *     test-config get_value "foo.bAr Baz.rock"
+ *
+ */
+
+
+int main(int argc, char **argv)
+{
+       int i, val;
+       const char *v;
+       const struct string_list *strptr;
+       struct config_set cs;
+       git_configset_init(&cs);
+
+       if (argc < 2) {
+               fprintf(stderr, "Please, provide a command name on the command-line\n");
+               goto exit1;
+       } else if (argc == 3 && !strcmp(argv[1], "get_value")) {
+               if (!git_config_get_value(argv[2], &v)) {
+                       if (!v)
+                               printf("(NULL)\n");
+                       else
+                               printf("%s\n", v);
+                       goto exit0;
+               } else {
+                       printf("Value not found for \"%s\"\n", argv[2]);
+                       goto exit1;
+               }
+       } else if (argc == 3 && !strcmp(argv[1], "get_value_multi")) {
+               strptr = git_config_get_value_multi(argv[2]);
+               if (strptr) {
+                       for (i = 0; i < strptr->nr; i++) {
+                               v = strptr->items[i].string;
+                               if (!v)
+                                       printf("(NULL)\n");
+                               else
+                                       printf("%s\n", v);
+                       }
+                       goto exit0;
+               } else {
+                       printf("Value not found for \"%s\"\n", argv[2]);
+                       goto exit1;
+               }
+       } else if (argc == 3 && !strcmp(argv[1], "get_int")) {
+               if (!git_config_get_int(argv[2], &val)) {
+                       printf("%d\n", val);
+                       goto exit0;
+               } else {
+                       printf("Value not found for \"%s\"\n", argv[2]);
+                       goto exit1;
+               }
+       } else if (argc == 3 && !strcmp(argv[1], "get_bool")) {
+               if (!git_config_get_bool(argv[2], &val)) {
+                       printf("%d\n", val);
+                       goto exit0;
+               } else {
+                       printf("Value not found for \"%s\"\n", argv[2]);
+                       goto exit1;
+               }
+       } else if (argc == 3 && !strcmp(argv[1], "get_string")) {
+               if (!git_config_get_string_const(argv[2], &v)) {
+                       printf("%s\n", v);
+                       goto exit0;
+               } else {
+                       printf("Value not found for \"%s\"\n", argv[2]);
+                       goto exit1;
+               }
+       } else if (!strcmp(argv[1], "configset_get_value")) {
+               for (i = 3; i < argc; i++) {
+                       int err;
+                       if ((err = git_configset_add_file(&cs, argv[i]))) {
+                               fprintf(stderr, "Error (%d) reading configuration file %s.\n", err, argv[i]);
+                               goto exit2;
+                       }
+               }
+               if (!git_configset_get_value(&cs, argv[2], &v)) {
+                       if (!v)
+                               printf("(NULL)\n");
+                       else
+                               printf("%s\n", v);
+                       goto exit0;
+               } else {
+                       printf("Value not found for \"%s\"\n", argv[2]);
+                       goto exit1;
+               }
+       } else if (!strcmp(argv[1], "configset_get_value_multi")) {
+               for (i = 3; i < argc; i++) {
+                       int err;
+                       if ((err = git_configset_add_file(&cs, argv[i]))) {
+                               fprintf(stderr, "Error (%d) reading configuration file %s.\n", err, argv[i]);
+                               goto exit2;
+                       }
+               }
+               strptr = git_configset_get_value_multi(&cs, argv[2]);
+               if (strptr) {
+                       for (i = 0; i < strptr->nr; i++) {
+                               v = strptr->items[i].string;
+                               if (!v)
+                                       printf("(NULL)\n");
+                               else
+                                       printf("%s\n", v);
+                       }
+                       goto exit0;
+               } else {
+                       printf("Value not found for \"%s\"\n", argv[2]);
+                       goto exit1;
+               }
+       }
+
+       die("%s: Please check the syntax and the function name", argv[0]);
+
+exit0:
+       git_configset_clear(&cs);
+       return 0;
+
+exit1:
+       git_configset_clear(&cs);
+       return 1;
+
+exit2:
+       git_configset_clear(&cs);
+       return 2;
+}
index 10afaabbfaed9ee1b4a6a498a2110fb904d48645..94a6997a8f6aa40cd86859dbd3eb27704e46b034 100644 (file)
@@ -19,19 +19,21 @@ static void show_dates(char **argv, struct timeval *now)
 
 static void parse_dates(char **argv, struct timeval *now)
 {
+       struct strbuf result = STRBUF_INIT;
+
        for (; *argv; argv++) {
-               char result[100];
                unsigned long t;
                int tz;
 
-               result[0] = 0;
-               parse_date(*argv, result, sizeof(result));
-               if (sscanf(result, "%lu %d", &t, &tz) == 2)
+               strbuf_reset(&result);
+               parse_date(*argv, &result);
+               if (sscanf(result.buf, "%lu %d", &t, &tz) == 2)
                        printf("%s -> %s\n",
                               *argv, show_date(t, tz, DATE_ISO8601));
                else
                        printf("%s -> bad\n", *argv);
        }
+       strbuf_release(&result);
 }
 
 static void parse_approxidate(char **argv, struct timeval *now)
index 330ba4f4dd23e2cf21acbe8a7023eaca4ec09afe..54c0872fcb18edb4ca28a63fdfd4be3a17df388e 100644 (file)
@@ -26,16 +26,16 @@ static int dump_cache_tree(struct cache_tree *it,
                return 0;
 
        if (it->entry_count < 0) {
+               /* invalid */
                dump_one(it, pfx, "");
                dump_one(ref, pfx, "#(ref) ");
-               if (it->subtree_nr != ref->subtree_nr)
-                       errs = 1;
        }
        else {
                dump_one(it, pfx, "");
                if (hashcmp(it->sha1, ref->sha1) ||
                    ref->entry_count != it->entry_count ||
                    ref->subtree_nr != it->subtree_nr) {
+                       /* claims to be valid but is lying */
                        dump_one(ref, pfx, "#(ref) ");
                        errs = 1;
                }
index 37918e15f5ce06d0079ce09ae1a7be7b14533c48..89c7de2c600ce2781ce666324e703d555937740a 100644 (file)
@@ -15,9 +15,7 @@
 
 int main(int argc, char **argv)
 {
-       struct child_process proc;
-
-       memset(&proc, 0, sizeof(proc));
+       struct child_process proc = CHILD_PROCESS_INIT;
 
        if (argc < 3)
                return 1;
index 93525eb7be48eb11c242200827a7f6f0706ee241..56881a032471752ca16880d98ea1510e16d38eed 100644 (file)
@@ -3,7 +3,7 @@
 
 int main(int argc, char **argv)
 {
-       struct child_process cp;
+       struct child_process cp = CHILD_PROCESS_INIT;
        int nogit = 0;
 
        setup_git_directory_gently(&nogit);
@@ -13,7 +13,6 @@ int main(int argc, char **argv)
                setup_work_tree();
                argv++;
        }
-       memset(&cp, 0, sizeof(cp));
        cp.git_cmd = 1;
        cp.argv = (const char **)argv + 1;
        return run_command(&cp);
diff --git a/trace.c b/trace.c
index e583dc63bb8d7062f8b735e701978574e9fcbf25..b6f25a23fdf8b6eec64181b5d6b56909bbe4ae7b 100644 (file)
--- a/trace.c
+++ b/trace.c
@@ -216,7 +216,7 @@ void trace_argv_printf(const char **argv, const char *format, ...)
        va_end(ap);
 }
 
-void trace_strbuf(const char *key, const struct strbuf *data)
+void trace_strbuf(struct trace_key *key, const struct strbuf *data)
 {
        trace_strbuf_fl(NULL, 0, key, data);
 }
@@ -298,13 +298,12 @@ void trace_repo_setup(const char *prefix)
 {
        static struct trace_key key = TRACE_KEY_INIT(SETUP);
        const char *git_work_tree;
-       char cwd[PATH_MAX];
+       char *cwd;
 
        if (!trace_want(&key))
                return;
 
-       if (!getcwd(cwd, PATH_MAX))
-               die("Unable to get current working directory");
+       cwd = xgetcwd();
 
        if (!(git_work_tree = get_git_work_tree()))
                git_work_tree = "(null)";
@@ -316,6 +315,8 @@ void trace_repo_setup(const char *prefix)
        trace_printf_key(&key, "setup: worktree: %s\n", quote_crnl(git_work_tree));
        trace_printf_key(&key, "setup: cwd: %s\n", quote_crnl(cwd));
        trace_printf_key(&key, "setup: prefix: %s\n", quote_crnl(prefix));
+
+       free(cwd);
 }
 
 int trace_want(struct trace_key *key)
index 3d8fe7d801293a338f13dfd01ba352e84c658813..080a7a6ae23e6915c425a3e471fd641aabafba90 100644 (file)
@@ -118,7 +118,8 @@ static struct child_process *get_helper(struct transport *transport)
        if (data->helper)
                return data->helper;
 
-       helper = xcalloc(1, sizeof(*helper));
+       helper = xmalloc(sizeof(*helper));
+       child_process_init(helper);
        helper->in = -1;
        helper->out = -1;
        helper->err = 0;
@@ -395,7 +396,7 @@ static int get_importer(struct transport *transport, struct child_process *fasti
        struct child_process *helper = get_helper(transport);
        struct helper_data *data = transport->data;
        int cat_blob_fd, code;
-       memset(fastimport, 0, sizeof(*fastimport));
+       child_process_init(fastimport);
        fastimport->in = helper->out;
        argv_array_push(&fastimport->args, "fast-import");
        argv_array_push(&fastimport->args, debug ? "--stats" : "--quiet");
index 662421bb5e076177f0fc320330287d3da50303a5..7388bb87dae96514801bcd604b74d31f54955f9a 100644 (file)
@@ -201,7 +201,7 @@ static struct ref *get_refs_via_rsync(struct transport *transport, int for_push)
 {
        struct strbuf buf = STRBUF_INIT, temp_dir = STRBUF_INIT;
        struct ref dummy = {NULL}, *tail = &dummy;
-       struct child_process rsync;
+       struct child_process rsync = CHILD_PROCESS_INIT;
        const char *args[5];
        int temp_dir_len;
 
@@ -218,7 +218,6 @@ static struct ref *get_refs_via_rsync(struct transport *transport, int for_push)
        strbuf_addstr(&buf, rsync_url(transport->url));
        strbuf_addstr(&buf, "/refs");
 
-       memset(&rsync, 0, sizeof(rsync));
        rsync.argv = args;
        rsync.stdout_to_stderr = 1;
        args[0] = "rsync";
@@ -263,9 +262,8 @@ static struct ref *get_refs_via_rsync(struct transport *transport, int for_push)
 static int fetch_objs_via_rsync(struct transport *transport,
                                int nr_objs, struct ref **to_fetch)
 {
-       struct child_process rsync;
+       struct child_process rsync = CHILD_PROCESS_INIT;
 
-       memset(&rsync, 0, sizeof(rsync));
        rsync.stdout_to_stderr = 1;
        argv_array_push(&rsync.args, "rsync");
        argv_array_push(&rsync.args, (transport->verbose > 1) ? "-rv" : "-r");
@@ -327,7 +325,7 @@ static int rsync_transport_push(struct transport *transport,
 {
        struct strbuf buf = STRBUF_INIT, temp_dir = STRBUF_INIT;
        int result = 0, i;
-       struct child_process rsync;
+       struct child_process rsync = CHILD_PROCESS_INIT;
        const char *args[10];
 
        if (flags & TRANSPORT_PUSH_MIRROR)
@@ -338,7 +336,6 @@ static int rsync_transport_push(struct transport *transport,
        strbuf_addstr(&buf, rsync_url(transport->url));
        strbuf_addch(&buf, '/');
 
-       memset(&rsync, 0, sizeof(rsync));
        rsync.argv = args;
        rsync.stdout_to_stderr = 1;
        i = 0;
@@ -1056,7 +1053,7 @@ static int run_pre_push_hook(struct transport *transport,
 {
        int ret = 0, x;
        struct ref *r;
-       struct child_process proc;
+       struct child_process proc = CHILD_PROCESS_INIT;
        struct strbuf buf;
        const char *argv[4];
 
@@ -1067,7 +1064,6 @@ static int run_pre_push_hook(struct transport *transport,
        argv[2] = transport->url;
        argv[3] = NULL;
 
-       memset(&proc, 0, sizeof(proc));
        proc.argv = argv;
        proc.in = -1;
 
index 91bd6b89d4946bbd80a0b9e9e7d6af21d6a2f61a..19ed48be9902f321285bfbec3feaf8357fd5e9b9 100644 (file)
@@ -18,12 +18,12 @@ static int chdir_len(const char *orig, int len)
 }
 
 struct unix_sockaddr_context {
-       char orig_dir[PATH_MAX];
+       char *orig_dir;
 };
 
 static void unix_sockaddr_cleanup(struct unix_sockaddr_context *ctx)
 {
-       if (!ctx->orig_dir[0])
+       if (!ctx->orig_dir)
                return;
        /*
         * If we fail, we can't just return an error, since we have
@@ -32,6 +32,7 @@ static void unix_sockaddr_cleanup(struct unix_sockaddr_context *ctx)
         */
        if (chdir(ctx->orig_dir) < 0)
                die("unable to restore original working directory");
+       free(ctx->orig_dir);
 }
 
 static int unix_sockaddr_init(struct sockaddr_un *sa, const char *path,
@@ -39,10 +40,11 @@ static int unix_sockaddr_init(struct sockaddr_un *sa, const char *path,
 {
        int size = strlen(path) + 1;
 
-       ctx->orig_dir[0] = '\0';
+       ctx->orig_dir = NULL;
        if (size > sizeof(sa->sun_path)) {
                const char *slash = find_last_dir_sep(path);
                const char *dir;
+               struct strbuf cwd = STRBUF_INIT;
 
                if (!slash) {
                        errno = ENAMETOOLONG;
@@ -56,11 +58,9 @@ static int unix_sockaddr_init(struct sockaddr_un *sa, const char *path,
                        errno = ENAMETOOLONG;
                        return -1;
                }
-
-               if (!getcwd(ctx->orig_dir, sizeof(ctx->orig_dir))) {
-                       errno = ENAMETOOLONG;
+               if (strbuf_getcwd(&cwd))
                        return -1;
-               }
+               ctx->orig_dir = strbuf_detach(&cwd, NULL);
                if (chdir_len(dir, slash - dir) < 0)
                        return -1;
        }
index 433211a238cfee261e6e1f9e73d14df9178f004a..c789ec00507696b4e52b081b66cc0e7c8cba42f9 100644 (file)
@@ -80,7 +80,7 @@ static int write_one_shallow(const struct commit_graft *graft, void *cb_data)
 
 static void create_pack_file(void)
 {
-       struct child_process pack_objects;
+       struct child_process pack_objects = CHILD_PROCESS_INIT;
        char data[8193], progress[128];
        char abort_msg[] = "aborting due to possible repository "
                "corruption on the remote side.";
@@ -108,7 +108,6 @@ static void create_pack_file(void)
                argv[arg++] = "--include-tag";
        argv[arg++] = NULL;
 
-       memset(&pack_objects, 0, sizeof(pack_objects));
        pack_objects.in = -1;
        pack_objects.out = -1;
        pack_objects.err = -1;
@@ -450,7 +449,7 @@ static void check_non_tip(void)
        static const char *argv[] = {
                "rev-list", "--stdin", NULL,
        };
-       static struct child_process cmd;
+       static struct child_process cmd = CHILD_PROCESS_INIT;
        struct object *o;
        char namebuf[42]; /* ^ + SHA-1 + LF */
        int i;
diff --git a/utf8.c b/utf8.c
index b30790d043aa4b01da00686654dfb615a92e75b6..454177794929933a6ccc4d91e7d5c784f0f07bff 100644 (file)
--- a/utf8.c
+++ b/utf8.c
@@ -239,13 +239,6 @@ int is_utf8(const char *text)
        return 1;
 }
 
-static void strbuf_addchars(struct strbuf *sb, int c, size_t n)
-{
-       strbuf_grow(sb, n);
-       memset(sb->buf + sb->len, c, n);
-       strbuf_setlen(sb, sb->len + n);
-}
-
 static void strbuf_add_indented_text(struct strbuf *buf, const char *text,
                                     int indent, int indent2)
 {
@@ -382,6 +375,9 @@ void strbuf_utf8_replace(struct strbuf *sb_src, int pos, int width,
                        dst += n;
                }
 
+               if (src >= end)
+                       break;
+
                old = src;
                n = utf8_width((const char**)&src, NULL);
                if (!src)       /* broken utf-8, do nothing */
index 014826464e07c93374868c61673cfe308961dfb7..18a67d33cb55b799f7784e52ceac214cf76e5d3e 100644 (file)
--- a/walker.c
+++ b/walker.c
@@ -205,7 +205,7 @@ static int mark_complete(const char *path, const unsigned char *sha1, int flag,
        struct commit *commit = lookup_commit_reference_gently(sha1, 1);
        if (commit) {
                commit->object.flags |= COMPLETE;
-               commit_list_insert_by_date(commit, &complete);
+               commit_list_insert(commit, &complete);
        }
        return 0;
 }
@@ -228,8 +228,8 @@ int walker_targets_stdin(char ***target, const char ***write_ref)
 
                if (targets >= targets_alloc) {
                        targets_alloc = targets_alloc ? targets_alloc * 2 : 64;
-                       *target = xrealloc(*target, targets_alloc * sizeof(**target));
-                       *write_ref = xrealloc(*write_ref, targets_alloc * sizeof(**write_ref));
+                       REALLOC_ARRAY(*target, targets_alloc);
+                       REALLOC_ARRAY(*write_ref, targets_alloc);
                }
                (*target)[targets] = xstrdup(tg_one);
                (*write_ref)[targets] = rf_one ? xstrdup(rf_one) : NULL;
@@ -251,64 +251,76 @@ void walker_targets_free(int targets, char **target, const char **write_ref)
 int walker_fetch(struct walker *walker, int targets, char **target,
                 const char **write_ref, const char *write_ref_log_details)
 {
-       struct ref_lock **lock = xcalloc(targets, sizeof(struct ref_lock *));
+       struct strbuf refname = STRBUF_INIT;
+       struct strbuf err = STRBUF_INIT;
+       struct ref_transaction *transaction = NULL;
        unsigned char *sha1 = xmalloc(targets * 20);
-       const char *msg;
-       char *to_free = NULL;
-       int ret;
-       int i;
+       char *msg = NULL;
+       int i, ret = -1;
 
        save_commit_buffer = 0;
 
-       for (i = 0; i < targets; i++) {
-               if (!write_ref || !write_ref[i])
-                       continue;
-
-               lock[i] = lock_ref_sha1(write_ref[i], NULL);
-               if (!lock[i]) {
-                       error("Can't lock ref %s", write_ref[i]);
-                       goto unlock_and_fail;
+       if (write_ref) {
+               transaction = ref_transaction_begin(&err);
+               if (!transaction) {
+                       error("%s", err.buf);
+                       goto done;
                }
        }
 
-       if (!walker->get_recover)
+       if (!walker->get_recover) {
                for_each_ref(mark_complete, NULL);
+               commit_list_sort_by_date(&complete);
+       }
 
        for (i = 0; i < targets; i++) {
                if (interpret_target(walker, target[i], &sha1[20 * i])) {
                        error("Could not interpret response from server '%s' as something to pull", target[i]);
-                       goto unlock_and_fail;
+                       goto done;
                }
                if (process(walker, lookup_unknown_object(&sha1[20 * i])))
-                       goto unlock_and_fail;
+                       goto done;
        }
 
        if (loop(walker))
-               goto unlock_and_fail;
-
-       if (write_ref_log_details)
-               msg = to_free = xstrfmt("fetch from %s", write_ref_log_details);
-       else
-               msg = "fetch (unknown)";
+               goto done;
+       if (!write_ref) {
+               ret = 0;
+               goto done;
+       }
+       if (write_ref_log_details) {
+               msg = xstrfmt("fetch from %s", write_ref_log_details);
+       } else {
+               msg = NULL;
+       }
        for (i = 0; i < targets; i++) {
-               if (!write_ref || !write_ref[i])
+               if (!write_ref[i])
                        continue;
-               ret = write_ref_sha1(lock[i], &sha1[20 * i], msg);
-               lock[i] = NULL;
-               if (ret)
-                       goto unlock_and_fail;
+               strbuf_reset(&refname);
+               strbuf_addf(&refname, "refs/%s", write_ref[i]);
+               if (ref_transaction_update(transaction, refname.buf,
+                                          &sha1[20 * i], NULL, 0, 0,
+                                          &err)) {
+                       error("%s", err.buf);
+                       goto done;
+               }
+       }
+       if (ref_transaction_commit(transaction,
+                                  msg ? msg : "fetch (unknown)",
+                                  &err)) {
+               error("%s", err.buf);
+               goto done;
        }
-       free(to_free);
-
-       return 0;
 
-unlock_and_fail:
-       for (i = 0; i < targets; i++)
-               if (lock[i])
-                       unlock_ref(lock[i]);
-       free(to_free);
+       ret = 0;
 
-       return -1;
+done:
+       ref_transaction_free(transaction);
+       free(msg);
+       free(sha1);
+       strbuf_release(&err);
+       strbuf_release(&refname);
+       return ret;
 }
 
 void walker_free(struct walker *walker)
index bc1bfb86003cb4133cc4ce3ce6423ce780ed7c84..25074d71b6ce72066efc02abda74ddfb10f71d6c 100644 (file)
--- a/wrapper.c
+++ b/wrapper.c
@@ -9,16 +9,23 @@ static void do_nothing(size_t size)
 
 static void (*try_to_free_routine)(size_t size) = do_nothing;
 
-static void memory_limit_check(size_t size)
+static int memory_limit_check(size_t size, int gentle)
 {
        static int limit = -1;
        if (limit == -1) {
                const char *env = getenv("GIT_ALLOC_LIMIT");
                limit = env ? atoi(env) * 1024 : 0;
        }
-       if (limit && size > limit)
-               die("attempting to allocate %"PRIuMAX" over limit %d",
-                   (intmax_t)size, limit);
+       if (limit && size > limit) {
+               if (gentle) {
+                       error("attempting to allocate %"PRIuMAX" over limit %d",
+                             (intmax_t)size, limit);
+                       return -1;
+               } else
+                       die("attempting to allocate %"PRIuMAX" over limit %d",
+                           (intmax_t)size, limit);
+       }
+       return 0;
 }
 
 try_to_free_t set_try_to_free_routine(try_to_free_t routine)
@@ -42,11 +49,12 @@ char *xstrdup(const char *str)
        return ret;
 }
 
-void *xmalloc(size_t size)
+static void *do_xmalloc(size_t size, int gentle)
 {
        void *ret;
 
-       memory_limit_check(size);
+       if (memory_limit_check(size, gentle))
+               return NULL;
        ret = malloc(size);
        if (!ret && !size)
                ret = malloc(1);
@@ -55,9 +63,16 @@ void *xmalloc(size_t size)
                ret = malloc(size);
                if (!ret && !size)
                        ret = malloc(1);
-               if (!ret)
-                       die("Out of memory, malloc failed (tried to allocate %lu bytes)",
-                           (unsigned long)size);
+               if (!ret) {
+                       if (!gentle)
+                               die("Out of memory, malloc failed (tried to allocate %lu bytes)",
+                                   (unsigned long)size);
+                       else {
+                               error("Out of memory, malloc failed (tried to allocate %lu bytes)",
+                                     (unsigned long)size);
+                               return NULL;
+                       }
+               }
        }
 #ifdef XMALLOC_POISON
        memset(ret, 0xA5, size);
@@ -65,16 +80,37 @@ void *xmalloc(size_t size)
        return ret;
 }
 
-void *xmallocz(size_t size)
+void *xmalloc(size_t size)
+{
+       return do_xmalloc(size, 0);
+}
+
+static void *do_xmallocz(size_t size, int gentle)
 {
        void *ret;
-       if (unsigned_add_overflows(size, 1))
-               die("Data too large to fit into virtual memory space.");
-       ret = xmalloc(size + 1);
-       ((char*)ret)[size] = 0;
+       if (unsigned_add_overflows(size, 1)) {
+               if (gentle) {
+                       error("Data too large to fit into virtual memory space.");
+                       return NULL;
+               } else
+                       die("Data too large to fit into virtual memory space.");
+       }
+       ret = do_xmalloc(size + 1, gentle);
+       if (ret)
+               ((char*)ret)[size] = 0;
        return ret;
 }
 
+void *xmallocz(size_t size)
+{
+       return do_xmallocz(size, 0);
+}
+
+void *xmallocz_gently(size_t size)
+{
+       return do_xmallocz(size, 1);
+}
+
 /*
  * xmemdupz() allocates (len + 1) bytes of memory, duplicates "len" bytes of
  * "data" to the allocated memory, zero terminates the allocated memory,
@@ -96,7 +132,7 @@ void *xrealloc(void *ptr, size_t size)
 {
        void *ret;
 
-       memory_limit_check(size);
+       memory_limit_check(size, 0);
        ret = realloc(ptr, size);
        if (!ret && !size)
                ret = realloc(ptr, 1);
@@ -115,7 +151,7 @@ void *xcalloc(size_t nmemb, size_t size)
 {
        void *ret;
 
-       memory_limit_check(size * nmemb);
+       memory_limit_check(size * nmemb, 0);
        ret = calloc(nmemb, size);
        if (!ret && (!nmemb || !size))
                ret = calloc(1, 1);
@@ -493,3 +529,11 @@ struct passwd *xgetpwuid_self(void)
                    errno ? strerror(errno) : _("no such user"));
        return pw;
 }
+
+char *xgetcwd(void)
+{
+       struct strbuf sb = STRBUF_INIT;
+       if (strbuf_getcwd(&sb))
+               die_errno(_("unable to get current working directory"));
+       return strbuf_detach(&sb, NULL);
+}
index b50f99a9361926d2116c85e3e90a132fb9dab742..e7afe7a295e586d58313e82e87b22de347aef7a1 100644 (file)
@@ -49,6 +49,21 @@ void maybe_flush_or_die(FILE *f, const char *desc)
        }
 }
 
+void fprintf_or_die(FILE *f, const char *fmt, ...)
+{
+       va_list ap;
+       int ret;
+
+       va_start(ap, fmt);
+       ret = vfprintf(f, fmt, ap);
+       va_end(ap);
+
+       if (ret < 0) {
+               check_pipe(errno);
+               die_errno("write error");
+       }
+}
+
 void fsync_or_die(int fd, const char *msg)
 {
        if (fsync(fd) < 0) {
index 27da5296be253844e0f2bc8d5996faf343192828..1bf5d725453f726f6a6179f9706a50f3c8c9dbb5 100644 (file)
@@ -725,7 +725,7 @@ static void wt_status_print_changed(struct wt_status *s)
 
 static void wt_status_print_submodule_summary(struct wt_status *s, int uncommitted)
 {
-       struct child_process sm_summary;
+       struct child_process sm_summary = CHILD_PROCESS_INIT;
        struct argv_array env = ARGV_ARRAY_INIT;
        struct argv_array argv = ARGV_ARRAY_INIT;
        struct strbuf cmd_stdout = STRBUF_INIT;
@@ -744,7 +744,6 @@ static void wt_status_print_submodule_summary(struct wt_status *s, int uncommitt
        if (!uncommitted)
                argv_array_push(&argv, s->amend ? "HEAD^" : "HEAD");
 
-       memset(&sm_summary, 0, sizeof(sm_summary));
        sm_summary.argv = argv.argv;
        sm_summary.env = env.argv;
        sm_summary.git_cmd = 1;