Merge branch 'da/rev-parse-verify-quiet'
authorJunio C Hamano <gitster@pobox.com>
Mon, 29 Sep 2014 19:36:10 +0000 (12:36 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 29 Sep 2014 19:36:10 +0000 (12:36 -0700)
"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.

* da/rev-parse-verify-quiet:
stash: prefer --quiet over shell redirection of the standard error stream
refs: make rev-parse --quiet actually quiet
t1503: use test_must_be_empty
Documentation: a note about stdout for git rev-parse --verify --quiet

117 files changed:
Documentation/RelNotes/2.1.1.txt [new file with mode: 0644]
Documentation/RelNotes/2.2.0.txt
Documentation/git-credential-cache--daemon.txt
Documentation/git-fast-export.txt
Documentation/git-rebase.txt
Documentation/git-rev-list.txt
Documentation/git-send-pack.txt
Documentation/git-update-index.txt
Documentation/git.txt
Documentation/pretty-formats.txt
Documentation/rev-list-options.txt
Documentation/technical/api-allocation-growing.txt
Documentation/technical/api-strbuf.txt
Makefile
attr.c
builtin/apply.c
builtin/blame.c
builtin/branch.c
builtin/clone.c
builtin/commit.c
builtin/config.c
builtin/fast-export.c
builtin/for-each-ref.c
builtin/fsck.c
builtin/hash-object.c
builtin/index-pack.c
builtin/log.c
builtin/ls-files.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/repack.c
builtin/rm.c
builtin/send-pack.c
builtin/show-branch.c
builtin/unpack-objects.c
cache.h
column.c
commit-slab.h
commit.c
commit.h
config.c
connect.c
contrib/completion/git-completion.bash
contrib/svn-fe/Makefile
credential-cache--daemon.c
date.c
fast-import.c
fsck.c
fsck.h
git-bisect.sh
git-compat-util.h
git-stash.sh
git.c
graph.c
help.c
http-walker.c
ident.c
imap-send.c
khash.h
line-log.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
parse-options.c
po/TEAMS
po/de.po
pretty.c
reachable.c
read-cache.c
reflog-walk.c
reflog-walk.h
refs.c
refs.h
remote-curl.c
rerere.h
revision.c
server-info.c
sh-i18n--envsubst.c
shallow.c
strbuf.c
strbuf.h
string-list.c
t/t0026-eol-config.sh
t/t0027-auto-crlf.sh
t/t1303-wacky-config.sh
t/t1450-fsck.sh
t/t1502-rev-parse-parseopt.sh
t/t3201-branch-contains.sh
t/t3210-pack-refs.sh
t/t4205-log-pretty-formats.sh
t/t4212-log-corrupt.sh
t/t5302-pack-index.sh
t/t5304-prune.sh
t/t5401-update-hooks.sh
t/t5408-send-pack-stdin.sh [new file with mode: 0755]
t/t5541-http-push-smart.sh
t/t6038-merge-text-auto.sh
t/t9300-fast-import.sh
t/t9351-fast-export-anonymize.sh [new file with mode: 0755]
t/test-lib.sh
templates/hooks--pre-push.sample
test-date.c
trace.c
utf8.c
walker.c
write_or_die.c
diff --git a/Documentation/RelNotes/2.1.1.txt b/Documentation/RelNotes/2.1.1.txt
new file mode 100644 (file)
index 0000000..830fc3c
--- /dev/null
@@ -0,0 +1,44 @@
+Git v2.1.1 Release Notes
+========================
+
+ * Git 2.0 had a regression where "git fetch" into a shallowly
+   cloned repository from a repository with bitmap object index
+   enabled did not work correctly.  This has been corrected.
+
+ * Git 2.0 had a regression which broke (rarely used) "git diff-tree
+   -t".  This has been corrected.
+
+ * "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.  Now it means "nothing shown
+   for the log message part".
+
+ * "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), but they
+   didn't work that way.  Now it does.
+
+ * 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 did not work correctly.
+
+ * "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.
+
+ * "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, fast-import could have overflown
+   an on-stack buffer.
+
+ * After "pack-refs --prune" packed refs at the top-level, it failed
+   to prune them.
+
+ * "git gc --auto" triggered from "git fetch --quiet" was not quiet.
index 22b73618fc55a475b3e4c21cc0b62170f3e0b4cf..a5e3ce8f5de41ff7eb1e17686be80bf7f9c11775 100644 (file)
@@ -23,6 +23,28 @@ UI, Workflows & Features
    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").
+
+
 Performance, Internal Implementation, etc.
 
  * The API to manipulate the "refs" is currently undergoing a revamp
@@ -65,6 +87,24 @@ Performance, Internal Implementation, etc.
    "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.
 
@@ -79,7 +119,6 @@ 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.
-   (merge b9c7d6e jk/pretty-empty-format later to maint).
 
  * Implementations of "tar" that do not understand an extended pax
    header would extract the contents of it in a regular file; make
@@ -89,44 +128,65 @@ notes for details).
  * "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).
-   (merge a789ca7 jk/command-line-config-empty-string later to maint).
 
  * 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.
-   (merge 477a08a jc/apply-ws-prefix later to maint).
 
  * "git bundle create" with date-range specification were meant to
    exclude tags outside the range, but it didn't.
-   (merge 2c8544a lf/bundle-exclusion later to maint).
 
  * "git add x" where x that used to be a directory has become a
    symbolic link to a directory misbehaved.
-   (merge ccad42d rs/refresh-beyond-symlink later to maint).
 
  * The prompt script checked $GIT_DIR/ref/stash file to see if there
    is a stash, which was a no-no.
-   (merge 0fa7f01 jk/prompt-stash-could-be-packed later to maint).
 
  * Pack-protocol documentation had a minor typo.
-   (merge 5d146f7 sp/pack-protocol-doc-on-shallow later to maint).
 
  * "git checkout -m" did not switch to another branch while carrying
    the local changes forward when a path was deleted from the index.
-   (merge 6a143aa jn/unpack-trees-checkout-m-carry-deletion later to maint).
 
  * With sufficiently long refnames, "git fast-import" could have
    overflown an on-stack buffer.
-   (merge c252785 jk/fast-import-fixes later to maint).
 
  * After "pack-refs --prune" packed refs at the top-level, it failed
    to prune them.
-   (merge afd11d3 jk/prune-top-level-refs-after-packing later to maint).
 
  * Progress output from "git gc --auto" was visible in "git fetch -q".
-   (merge 6fceed3 nd/fetch-pass-quiet-to-gc-child-process later to maint).
 
  * We used to pass -1000 to poll(2), expecting it to also mean "no
    timeout", which should be spelled as -1.
-   (merge 6c71f8b et/spell-poll-infinite-with-minus-one-only later to maint).
+
+ * "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).
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 f14100a16022306d280221b3cb1ae88f8c5498ce..4138554912165478d182d5720d4d7b4c4ab78c05 100644 (file)
@@ -9,7 +9,7 @@ SYNOPSIS
 --------
 [verse]
 'git rebase' [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>]
-       [<upstream>] [<branch>]
+       [<upstream> [<branch>]]
 'git rebase' [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>]
        --root [<branch>]
 'git rebase' --continue | --skip | --abort | --edit-todo
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 dc3a568baa9c85e10bb6b53707cee9447363d0f2..2a0de42a75d482a4bbafefd19991dad25b3e67f9 100644 (file)
@@ -35,6 +35,16 @@ OPTIONS
        Instead of explicitly specifying which refs to update,
        update all heads that locally exist.
 
+--stdin::
+       Take the list of refs from stdin, one per line. If there
+       are refs specified on the command line in addition to this
+       option, then the refs from stdin are processed after those
+       on the command line.
++
+If '--stateless-rpc' is specified together with this option then
+the list of refs must be in packet format (pkt-line). Each ref must
+be in a separate packet, and the list must end with a flush packet.
+
 --dry-run::
        Do everything except actually send the updates.
 
@@ -77,7 +87,8 @@ this flag.
 Without '--all' and without any '<ref>', the heads that exist
 both on the local side and on the remote side are updated.
 
-When one or more '<ref>' are specified explicitly, it can be either a
+When one or more '<ref>' are specified explicitly (whether on the
+command line or via `--stdin`), it can be either a
 single pattern, or a pair of such pattern separated by a colon
 ":" (this means that a ref name cannot have a colon in it).  A
 single pattern '<name>' is just a shorthand for '<name>:<name>'.
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 26de4dd54804ed6d14f9e568547154996b919bd4..8b2c5424c4243f3d9cb791dcc47f3989006b688d 100644 (file)
@@ -43,9 +43,10 @@ unreleased) version of Git, that is available from the 'master'
 branch of the `git.git` repository.
 Documentation for older releases are available here:
 
-* link:v2.1.0/git.html[documentation for release 2.1]
+* link:v2.1.1/git.html[documentation for release 2.1.1]
 
 * release notes for
+  link:RelNotes/2.1.1.txt[2.1.1],
   link:RelNotes/2.1.0.txt[2.1].
 
 * link:v2.0.4/git.html[documentation for release 2.0.4]
index eac79096d3d9cb544c9e213d285b5a3158367246..eecc39dec99b3cab3da3e36440653ea46ac762b9 100644 (file)
@@ -115,7 +115,8 @@ 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])
@@ -126,8 +127,10 @@ The placeholders are:
 - '%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 430302c2f4ee8c3881d663b1f395234fd8cad0a3..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
index e0f15a3df3ae441d33b9d0a0ddadc729ec4773b3..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.
@@ -1348,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
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 f204cca5d2df50d8ecb01944927fb756ac387b5e..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)
index ca4ba6ff15b91d9cbb6b2ce3783fa3e69d0f3ff1..3838be2b0274fbd72b200c2bf294e4d2842a020c 100644 (file)
@@ -2580,6 +2580,9 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
        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;
index ced422b627fc05c462f6be8b6c20ee0ba9ff2628..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, "");
@@ -656,6 +647,20 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru
 
                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 dd4092b0509eb9f284118c001d8451a633f9ef7c..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;
index 41f481bd030ba96f8883e64517eda95931344545..b0fe7847d3cbebd2cef28611171924bf7440c467 100644 (file)
@@ -545,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));
@@ -625,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)
@@ -1819,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);
index aba71355f864202932e02bddb804d2fa3c0783d8..37305e93e937ade83072501df6b5d07033ee89d3 100644 (file)
@@ -611,7 +611,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
                check_argc(argc, 2, 2);
                value = normalize_value(argv[0], argv[1]);
                return git_config_set_multivar_in_file(given_config_source.file,
-                                                      argv[0], value, "^$", 0);
+                                                      argv[0], value,
+                                                      CONFIG_REGEX_NONE, 0);
        }
        else if (actions == ACTION_REPLACE_ALL) {
                check_write();
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 d42a27da89d8d5693c6335cf4e2123d41c030580..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) {
@@ -388,7 +388,8 @@ static void fsck_sha1_list(void)
                unsigned char *sha1 = entry->sha1;
 
                sha1_list.entry[i] = NULL;
-               fsck_sha1(sha1);
+               if (fsck_sha1(sha1))
+                       errors_found |= ERROR_OBJECT;
                free(entry);
        }
        sha1_list.nr = 0;
@@ -488,6 +489,7 @@ static int fsck_handle_ref(const char *refname, const unsigned char *sha1, int f
        obj = parse_object(sha1);
        if (!obj) {
                error("%s: invalid sha1 pointer %s", refname, sha1_to_hex(sha1));
+               errors_found |= ERROR_REACHABLE;
                /* We'll continue with the rest despite the error.. */
                return 0;
        }
@@ -504,7 +506,7 @@ static void get_default_heads(void)
 {
        if (head_points_at && !is_null_sha1(head_sha1))
                fsck_handle_ref("HEAD", head_sha1, 0, NULL);
-       for_each_ref(fsck_handle_ref, NULL);
+       for_each_rawref(fsck_handle_ref, NULL);
        if (include_reflogs)
                for_each_reflog(fsck_handle_reflog, NULL);
 
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 5568a5bc3b69be79f0d5fa09c694fd976c8319cc..792c66ca5932638e11f2587f928a6b98c08e7854 100644 (file)
@@ -112,6 +112,10 @@ static pthread_mutex_t deepest_delta_mutex;
 #define deepest_delta_lock()   lock_mutex(&deepest_delta_mutex)
 #define deepest_delta_unlock() unlock_mutex(&deepest_delta_mutex)
 
+static pthread_mutex_t type_cas_mutex;
+#define type_cas_lock()                lock_mutex(&type_cas_mutex)
+#define type_cas_unlock()      unlock_mutex(&type_cas_mutex)
+
 static pthread_key_t key;
 
 static inline void lock_mutex(pthread_mutex_t *mutex)
@@ -135,6 +139,7 @@ static void init_thread(void)
        init_recursive_mutex(&read_mutex);
        pthread_mutex_init(&counter_mutex, NULL);
        pthread_mutex_init(&work_mutex, NULL);
+       pthread_mutex_init(&type_cas_mutex, NULL);
        if (show_stat)
                pthread_mutex_init(&deepest_delta_mutex, NULL);
        pthread_key_create(&key, NULL);
@@ -157,6 +162,7 @@ static void cleanup_thread(void)
        pthread_mutex_destroy(&read_mutex);
        pthread_mutex_destroy(&counter_mutex);
        pthread_mutex_destroy(&work_mutex);
+       pthread_mutex_destroy(&type_cas_mutex);
        if (show_stat)
                pthread_mutex_destroy(&deepest_delta_mutex);
        for (i = 0; i < nr_threads; i++)
@@ -773,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));
@@ -862,7 +869,6 @@ static void resolve_delta(struct object_entry *delta_obj,
 {
        void *base_data, *delta_data;
 
-       delta_obj->real_type = base->obj->real_type;
        if (show_stat) {
                delta_obj->delta_depth = base->obj->delta_depth + 1;
                deepest_delta_lock();
@@ -888,6 +894,26 @@ static void resolve_delta(struct object_entry *delta_obj,
        counter_unlock();
 }
 
+/*
+ * Standard boolean compare-and-swap: atomically check whether "*type" is
+ * "want"; if so, swap in "set" and return true. Otherwise, leave it untouched
+ * and return false.
+ */
+static int compare_and_swap_type(enum object_type *type,
+                                enum object_type want,
+                                enum object_type set)
+{
+       enum object_type old;
+
+       type_cas_lock();
+       old = *type;
+       if (old == want)
+               *type = set;
+       type_cas_unlock();
+
+       return old == want;
+}
+
 static struct base_data *find_unresolved_deltas_1(struct base_data *base,
                                                  struct base_data *prev_base)
 {
@@ -915,7 +941,10 @@ static struct base_data *find_unresolved_deltas_1(struct base_data *base,
                struct object_entry *child = objects + deltas[base->ref_first].obj_no;
                struct base_data *result = alloc_base_data();
 
-               assert(child->real_type == OBJ_REF_DELTA);
+               if (!compare_and_swap_type(&child->real_type, OBJ_REF_DELTA,
+                                          base->obj->real_type))
+                       die("BUG: child->real_type != OBJ_REF_DELTA");
+
                resolve_delta(child, base, result);
                if (base->ref_first == base->ref_last && base->ofs_last == -1)
                        free_base_data(base);
@@ -929,6 +958,7 @@ static struct base_data *find_unresolved_deltas_1(struct base_data *base,
                struct base_data *result = alloc_base_data();
 
                assert(child->real_type == OBJ_OFS_DELTA);
+               child->real_type = base->obj->real_type;
                resolve_delta(child, base, result);
                if (base->ofs_first == base->ofs_last)
                        free_base_data(base);
@@ -1140,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 e4d812208d8844b9155739acfd59ef840f24a4ae..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;
@@ -1440,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 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 9da9e30d9be46a5ed2de06e8545fe61537ba3676..dff043dac33ea88a8c5a05ea5ac3da71ca00c0d3 100644 (file)
@@ -556,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";
@@ -1143,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 bf784cb94361f8db5ea17906d0199284a04be99a..8883baa903e92093cabcc3dbaac7ccec3eecd64a 100644 (file)
@@ -184,10 +184,10 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
 
                                modes[i] = WORKING_DIRECTORY;
                                n = argc + last - first;
-                               source = xrealloc(source, n * sizeof(char *));
-                               destination = xrealloc(destination, n * sizeof(char *));
-                               modes = xrealloc(modes, n * sizeof(enum update_mode));
-                               submodule_gitfile = xrealloc(submodule_gitfile, n * sizeof(char *));
+                               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);
index c25a4125103b5bb1c8571864a974105decc1a181..67d0bb14f8f18003d6a073b0c264f5b46ca12685 100644 (file)
@@ -210,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 afb8d9926496de2bed8bcab793dd79562e575e18..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>";
 
@@ -287,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;
@@ -298,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);
 }
 
index fc088dbe6aec8b7a8fd23c924d8bc10c426b78ec..2aae05d36486bd31666853c545c37f1280ee11c9 100644 (file)
@@ -377,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;
@@ -387,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 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 f420b74665bcf1746e94b4cc5eb66ded0a2235ff..4b1bc0fef72c9764a4e4a43bb30f2c820d1aec34 100644 (file)
@@ -110,6 +110,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
        int flags;
        unsigned int reject_reasons;
        int progress = -1;
+       int from_stdin = 0;
        struct push_cas_option cas = {0};
 
        argv++;
@@ -169,6 +170,10 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
                                args.stateless_rpc = 1;
                                continue;
                        }
+                       if (!strcmp(arg, "--stdin")) {
+                               from_stdin = 1;
+                               continue;
+                       }
                        if (!strcmp(arg, "--helper-status")) {
                                helper_status = 1;
                                continue;
@@ -201,6 +206,28 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
        }
        if (!dest)
                usage(send_pack_usage);
+
+       if (from_stdin) {
+               struct argv_array all_refspecs = ARGV_ARRAY_INIT;
+
+               for (i = 0; i < nr_refspecs; i++)
+                       argv_array_push(&all_refspecs, refspecs[i]);
+
+               if (args.stateless_rpc) {
+                       const char *buf;
+                       while ((buf = packet_read_line(0, NULL)))
+                               argv_array_push(&all_refspecs, buf);
+               } else {
+                       struct strbuf line = STRBUF_INIT;
+                       while (strbuf_getline(&line, stdin, '\n') != EOF)
+                               argv_array_push(&all_refspecs, line.buf);
+                       strbuf_release(&line);
+               }
+
+               refspecs = all_refspecs.argv;
+               nr_refspecs = all_refspecs.argc;
+       }
+
        /*
         * --all and --mirror are incompatible; neither makes sense
         * with any refspecs.
index 46498e111354bf0d86bb04f5207812e7f54259d8..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;
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;
 }
 
diff --git a/cache.h b/cache.h
index dfa1a5696d448b407644276df58fb24e25c57113..8206039cfe9545b4f6eb6757dfd62bf468b3be52 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -482,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)
 
@@ -1039,6 +1039,7 @@ enum date_mode {
        DATE_SHORT,
        DATE_LOCAL,
        DATE_ISO8601,
+       DATE_ISO8601_STRICT,
        DATE_RFC2822,
        DATE_RAW
 };
@@ -1046,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);
@@ -1284,6 +1285,8 @@ extern int update_server_info(int);
 #define CONFIG_INVALID_PATTERN 6
 #define CONFIG_GENERIC_ERROR 7
 
+#define CONFIG_REGEX_NONE ((void *)1)
+
 struct git_config_source {
        unsigned int use_stdin:1;
        const char *file;
@@ -1427,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 76b615db5f2a4ff7567a7d1d9d6514f838f15321..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);
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 a401ddfbc4e5c2e5e4a9d7aeedebc34e6103c9fa..bc68ccbe691a28ed9b22fa935c78d2e9640347ea 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -326,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);
 
@@ -359,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 83c913ad0928aba882a86f361170cd256adbd445..a677eb6c599ddb39f1b4bb7ac44a59bc167fb3a7 100644 (file)
--- a/config.c
+++ b/config.c
@@ -136,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;
 
        /*
@@ -147,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;
 }
@@ -1611,10 +1607,15 @@ static struct {
 
 static int matches(const char *key, const char *value)
 {
-       return !strcmp(key, store.key) &&
-               (store.value_regex == NULL ||
-                (store.do_not_match ^
-                 !regexec(store.value_regex, value, 0, NULL, 0)));
+       if (strcmp(key, store.key))
+               return 0; /* not ours */
+       if (!store.value_regex)
+               return 1; /* always matches */
+       if (store.value_regex == CONFIG_REGEX_NONE)
+               return 0; /* never matches */
+
+       return store.do_not_match ^
+               (value && !regexec(store.value_regex, value, 0, NULL, 0));
 }
 
 static int store_aux(const char *key, const char *value, void *cb)
@@ -1876,6 +1877,8 @@ int git_config_parse_key(const char *key, char **store_key, int *baselen_)
 /*
  * If value==NULL, unset in (remove from) config,
  * if value_regex!=NULL, disregard key/value pairs where value does not match.
+ * if value_regex==CONFIG_REGEX_NONE, do not match any existing values
+ *     (only add a new one)
  * if multi_replace==0, nothing, or only one matching key/value is replaced,
  *     else all matching key/values (regardless how many) are removed,
  *     before the new pair is written.
@@ -1959,6 +1962,8 @@ int git_config_set_multivar_in_file(const char *config_filename,
 
                if (value_regex == NULL)
                        store.value_regex = NULL;
+               else if (value_regex == CONFIG_REGEX_NONE)
+                       store.value_regex = CONFIG_REGEX_NONE;
                else {
                        if (value_regex[0] == '!') {
                                store.do_not_match = 1;
@@ -1990,7 +1995,8 @@ int git_config_set_multivar_in_file(const char *config_filename,
                if (git_config_from_file(store_aux, config_filename, NULL)) {
                        error("invalid config file %s", config_filename);
                        free(store.key);
-                       if (store.value_regex != NULL) {
+                       if (store.value_regex != NULL &&
+                           store.value_regex != CONFIG_REGEX_NONE) {
                                regfree(store.value_regex);
                                free(store.value_regex);
                        }
@@ -1999,7 +2005,8 @@ int git_config_set_multivar_in_file(const char *config_filename,
                }
 
                free(store.key);
-               if (store.value_regex != NULL) {
+               if (store.value_regex != NULL &&
+                   store.value_regex != CONFIG_REGEX_NONE) {
                        regfree(store.value_regex);
                        free(store.value_regex);
                }
index 87b52026326e8c0f0296e80d64c784888f719a8e..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);
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 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 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;
 }
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);
 }
 
 /*
index c071253c90807b6fa98771e9fd046fed12bb7b4b..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;
 }
 
@@ -1422,7 +1422,7 @@ static void mktree(struct tree_content *t, int v, struct strbuf *b)
 
 static void store_tree(struct tree_entry *root)
 {
-       struct tree_content *t = root->tree;
+       struct tree_content *t;
        unsigned int i, j, del;
        struct last_object lo = { STRBUF_INIT, 0, 0, /* no_swap */ 1 };
        struct object_entry *le = NULL;
@@ -1430,6 +1430,10 @@ static void store_tree(struct tree_entry *root)
        if (!is_null_sha1(root->versions[1].sha1))
                return;
 
+       if (!root->tree)
+               load_tree(root);
+       t = root->tree;
+
        for (i = 0; i < t->entry_count; i++) {
                if (t->entries[i]->tree)
                        store_tree(t->entries[i]);
@@ -1996,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;
@@ -2014,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;
 }
 
@@ -2026,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 == '<')
@@ -2045,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(
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 4e7e3f8726a26a1f7dfbb889fe3531d01d4419b9..0c4e663928cb8fb03c73a6d3de6a506c7d98fc9a 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
 
@@ -626,6 +627,8 @@ 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)
 {
        if (len > (size_t) len)
index 7ece0f1420e019b517088abdd828ff73c6b13ec0..d4cf818be9488f1b94fdf4766a8f73db6bfd1029 100755 (executable)
@@ -394,7 +394,7 @@ parse_flags_and_rev()
 
        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 --verify --quiet "$REV^2") &&
diff --git a/git.c b/git.c
index 210f1ae9d04dda4d16f9f072ef710bf630f6d52e..4076b014aba6c488e51a9bae8e5cd4b26e4e2476 100644 (file)
--- a/git.c
+++ b/git.c
@@ -14,7 +14,7 @@ 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.");
 
@@ -282,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);
 
diff --git a/graph.c b/graph.c
index 640433166b39c515746d698566839326d9ce7bbe..23fff73e18771c4163a93ac6b16d7b2021419e90 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);
@@ -1169,8 +1163,7 @@ static void graph_padding_line(struct git_graph *graph, struct strbuf *sb)
                                strbuf_addch(sb, ' ');
                        else {
                                int num_spaces = ((graph->num_parents - 2) * 2);
-                               for (j = 0; j < num_spaces; j++)
-                                       strbuf_addch(sb, ' ');
+                               strbuf_addchars(sb, ' ', num_spaces);
                        }
                } else {
                        strbuf_write_column(sb, col, '|');
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 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/ident.c b/ident.c
index 77bc882e59c887e948a1fba4d99805f5dedfa7f7..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
@@ -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 f33e56dba1e06cd61448069e3d300e3650477320..70bcc7a4e533bb04e8c515e8831a75ec93d2d066 100644 (file)
@@ -919,7 +919,7 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc, char *f
 
        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;
 
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 bcee7c596696eb1da109b3ff375e09453045a60f..cff7ac1dbd8942f3013e6fa91d30d2ea33495854 100644 (file)
@@ -174,14 +174,16 @@ 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;
        const struct name_decoration *decoration;
        const char *color_commit =
                diff_get_color(use_color, DIFF_COMMIT);
@@ -191,7 +193,6 @@ void format_decorations(struct strbuf *sb,
        decoration = get_name_decoration(&commit->object);
        if (!decoration)
                return;
-       prefix = " (";
        while (decoration) {
                strbuf_addstr(sb, color_commit);
                strbuf_addstr(sb, prefix);
@@ -200,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 8ab944c44cf1afd516505fe9bb80dbc06708d1af..22315c370aaef56222ba96e6aef7fe33bb17cd9e 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);
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;
 }
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) ||
index 461cc14354c79da2baa0b1aa8bad0fc61812846b..a33a38e7d058823cc462e66288e6e940b5af81e5 100644 (file)
--- a/po/TEAMS
+++ b/po/TEAMS
@@ -17,6 +17,7 @@ Members:      Thomas Rast <tr@thomasrast.ch>
                Christian Stimming <stimming@tuhh.de>
                Phillip Szelat <phillip.szelat@gmail.com>
                Matthias Rüster <matthias.ruester@gmail.com>
+               Magnus Görlitz <magnus.goerlitz@googlemail.com>
 
 Language:      fr (French)
 Repository:    https://github.com/jnavila/git
index e5d2b25f448b5b9847e9bcda5285198afa40930d..c807967cfcc4da737e8f142dab262534fb240734 100644 (file)
--- a/po/de.po
+++ b/po/de.po
@@ -29,7 +29,7 @@ msgid ""
 "'git commit -a'."
 msgstr ""
 "Korrigieren Sie dies im Arbeitsverzeichnis, und benutzen Sie\n"
-"dann 'git add/rm <Datei>' um die Auflösung entsprechend zu markieren\n"
+"dann 'git add/rm <Datei>', um die Auflösung entsprechend zu markieren\n"
 "und zu committen, oder benutzen Sie 'git commit -a'."
 
 #: archive.c:10
@@ -619,7 +619,7 @@ msgstr "Fehler beim Erstellen des Pfades '%s'%s"
 #: merge-recursive.c:703
 #, c-format
 msgid "Removing %s to make room for subdirectory\n"
-msgstr "Entferne %s um Platz für Unterverzeichnis zu schaffen\n"
+msgstr "Entferne %s, um Platz für Unterverzeichnis zu schaffen\n"
 
 #: merge-recursive.c:717 merge-recursive.c:738
 msgid ": perhaps a D/F conflict?"
@@ -1037,7 +1037,7 @@ msgstr[1] "Ihr Branch ist vor '%s' um %d Commits.\n"
 
 #: remote.c:1960
 msgid "  (use \"git push\" to publish your local commits)\n"
-msgstr "  (benutzen Sie \"git push\" um lokale Commits zu publizieren)\n"
+msgstr "  (benutzen Sie \"git push\", um lokale Commits zu publizieren)\n"
 
 #: remote.c:1963
 #, c-format
@@ -1052,7 +1052,7 @@ msgstr[1] ""
 #: remote.c:1971
 msgid "  (use \"git pull\" to update your local branch)\n"
 msgstr ""
-"  (benutzen Sie \"git pull\" um Ihren lokalen Branch zu aktualisieren)\n"
+"  (benutzen Sie \"git pull\", um Ihren lokalen Branch zu aktualisieren)\n"
 
 #: remote.c:1974
 #, c-format
@@ -1072,7 +1072,7 @@ msgstr[1] ""
 #: remote.c:1984
 msgid "  (use \"git pull\" to merge the remote branch into yours)\n"
 msgstr ""
-"  (benutzen Sie \"git pull\" um Ihren Branch mit dem Remote-Branch "
+"  (benutzen Sie \"git pull\", um Ihren Branch mit dem Remote-Branch "
 "zusammenzuführen)\n"
 
 #: run-command.c:80
@@ -1136,7 +1136,7 @@ msgstr "Ihre lokalen Ã„nderungen würden von \"revert\" Ã¼berschrieben werden."
 #: sequencer.c:233
 msgid "Commit your changes or stash them to proceed."
 msgstr ""
-"Tragen Sie Ihre Ã„nderungen ein oder benutzen Sie \"stash\" um fortzufahren."
+"Tragen Sie Ihre Ã„nderungen ein oder benutzen Sie \"stash\", um fortzufahren."
 
 #: sequencer.c:250
 msgid "Failed to lock HEAD during fast_forward_to"
@@ -1488,18 +1488,18 @@ msgstr ""
 #: wt-status.c:183
 msgid "  (use \"git add <file>...\" to mark resolution)"
 msgstr ""
-"  (benutzen Sie \"git add/rm <Datei>...\" um die Auflösung zu markieren)"
+"  (benutzen Sie \"git add/rm <Datei>...\", um die Auflösung zu markieren)"
 
 #: wt-status.c:185 wt-status.c:189
 msgid "  (use \"git add/rm <file>...\" as appropriate to mark resolution)"
 msgstr ""
-"  (benutzen Sie \"git add/rm <Datei>...\" um die Auflösung entsprechend zu "
+"  (benutzen Sie \"git add/rm <Datei>...\", um die Auflösung entsprechend zu "
 "markieren)"
 
 #: wt-status.c:187
 msgid "  (use \"git rm <file>...\" to mark resolution)"
 msgstr ""
-"  (benutzen Sie \"git add/rm <Datei>...\" um die Auflösung zu markieren)"
+"  (benutzen Sie \"git add/rm <Datei>...\", um die Auflösung zu markieren)"
 
 #: wt-status.c:198
 msgid "Changes to be committed:"
@@ -1512,20 +1512,20 @@ msgstr "Änderungen, die nicht zum Commit vorgemerkt sind:"
 #: wt-status.c:220
 msgid "  (use \"git add <file>...\" to update what will be committed)"
 msgstr ""
-"  (benutzen Sie \"git add <Datei>...\" um die Ã„nderungen zum Commit "
+"  (benutzen Sie \"git add <Datei>...\", um die Ã„nderungen zum Commit "
 "vorzumerken)"
 
 #: wt-status.c:222
 msgid "  (use \"git add/rm <file>...\" to update what will be committed)"
 msgstr ""
-"  (benutzen Sie \"git add/rm <Datei>...\" um die Ã„nderungen zum Commit "
+"  (benutzen Sie \"git add/rm <Datei>...\", um die Ã„nderungen zum Commit "
 "vorzumerken)"
 
 #: wt-status.c:223
 msgid ""
 "  (use \"git checkout -- <file>...\" to discard changes in working directory)"
 msgstr ""
-"  (benutzen Sie \"git checkout -- <Datei>...\" um die Ã„nderungen im "
+"  (benutzen Sie \"git checkout -- <Datei>...\", um die Ã„nderungen im "
 "Arbeitsverzeichnis zu verwerfen)"
 
 #: wt-status.c:225
@@ -1538,7 +1538,7 @@ msgstr ""
 #, c-format
 msgid "  (use \"git %s <file>...\" to include in what will be committed)"
 msgstr ""
-"  (benutzen Sie \"git %s <Datei>...\" um die Ã„nderungen zum Commit "
+"  (benutzen Sie \"git %s <Datei>...\", um die Ã„nderungen zum Commit "
 "vorzumerken)"
 
 #: wt-status.c:252
@@ -1653,7 +1653,7 @@ msgstr "Alle Konflikte sind behoben, aber Sie sind immer noch beim Merge."
 
 #: wt-status.c:945
 msgid "  (use \"git commit\" to conclude merge)"
-msgstr "  (benutzen Sie \"git commit\" um den Merge abzuschließen)"
+msgstr "  (benutzen Sie \"git commit\", um den Merge abzuschließen)"
 
 #: wt-status.c:955
 msgid "You are in the middle of an am session."
@@ -1670,12 +1670,12 @@ msgstr ""
 
 #: wt-status.c:964
 msgid "  (use \"git am --skip\" to skip this patch)"
-msgstr "  (benutzen Sie \"git am --skip\" um diesen Patch auszulassen)"
+msgstr "  (benutzen Sie \"git am --skip\", um diesen Patch auszulassen)"
 
 #: wt-status.c:966
 msgid "  (use \"git am --abort\" to restore the original branch)"
 msgstr ""
-"  (benutzen Sie \"git am --abort\" um den ursprünglichen Branch "
+"  (benutzen Sie \"git am --abort\", um den ursprünglichen Branch "
 "wiederherzustellen)"
 
 #: wt-status.c:1026 wt-status.c:1043
@@ -1695,12 +1695,12 @@ msgstr ""
 
 #: wt-status.c:1036
 msgid "  (use \"git rebase --skip\" to skip this patch)"
-msgstr "  (benutzen Sie \"git rebase --skip\" um diesen Patch auszulassen)"
+msgstr "  (benutzen Sie \"git rebase --skip\", um diesen Patch auszulassen)"
 
 #: wt-status.c:1038
 msgid "  (use \"git rebase --abort\" to check out the original branch)"
 msgstr ""
-"  (benutzen Sie \"git rebase --abort\" um den ursprünglichen Branch "
+"  (benutzen Sie \"git rebase --abort\", um den ursprünglichen Branch "
 "auszuchecken)"
 
 #: wt-status.c:1051
@@ -1739,7 +1739,7 @@ msgstr "Sie editieren gerade einen Commit während eines Rebase."
 #: wt-status.c:1075
 msgid "  (use \"git commit --amend\" to amend the current commit)"
 msgstr ""
-"  (benutzen Sie \"git commit --amend\" um den aktuellen Commit nachzubessern)"
+"  (benutzen Sie \"git commit --amend\", um den aktuellen Commit nachzubessern)"
 
 #: wt-status.c:1077
 msgid ""
@@ -1767,7 +1767,7 @@ msgstr ""
 #: wt-status.c:1097
 msgid "  (use \"git cherry-pick --abort\" to cancel the cherry-pick operation)"
 msgstr ""
-"  (benutzen Sie \"git cherry-pick --abort\" um die Cherry-Pick-Operation "
+"  (benutzen Sie \"git cherry-pick --abort\", um die Cherry-Pick-Operation "
 "abzubrechen)"
 
 #: wt-status.c:1106
@@ -1788,7 +1788,7 @@ msgstr "  (alle Konflikte behoben: führen Sie \"git revert --continue\" aus)"
 #: wt-status.c:1116
 msgid "  (use \"git revert --abort\" to cancel the revert operation)"
 msgstr ""
-"  (benutzen Sie \"git revert --abort\" um die Revert-Operation abzubrechen)"
+"  (benutzen Sie \"git revert --abort\", um die Revert-Operation abzubrechen)"
 
 #: wt-status.c:1127
 #, c-format
@@ -1802,7 +1802,7 @@ msgstr "Sie sind gerade bei einer binären Suche."
 #: wt-status.c:1134
 msgid "  (use \"git bisect reset\" to get back to the original branch)"
 msgstr ""
-"  (benutzen Sie \"git bisect reset\" um zum ursprünglichen Branch "
+"  (benutzen Sie \"git bisect reset\", um zum ursprünglichen Branch "
 "zurückzukehren)"
 
 #: wt-status.c:1309
@@ -1855,7 +1855,7 @@ msgstr "Unbeobachtete Dateien nicht aufgelistet%s"
 
 #: wt-status.c:1373
 msgid " (use -u option to show untracked files)"
-msgstr " (benutzen Sie die Option -u um unbeobachteten Dateien anzuzeigen)"
+msgstr " (benutzen Sie die Option -u, um unbeobachteten Dateien anzuzeigen)"
 
 #: wt-status.c:1379
 msgid "No changes"
@@ -2235,7 +2235,7 @@ msgstr[1] ""
 #: builtin/apply.c:2818
 #, c-format
 msgid "Context reduced to (%ld/%ld) to apply fragment at %d"
-msgstr "Kontext reduziert zu (%ld/%ld) um Patch-Bereich bei %d anzuwenden"
+msgstr "Kontext reduziert zu (%ld/%ld), um Patch-Bereich bei %d anzuwenden"
 
 #: builtin/apply.c:2824
 #, c-format
@@ -2691,7 +2691,7 @@ msgstr "Unterdrückt den Namen des Autors und den Zeitstempel (Standard: aus)"
 
 #: builtin/blame.c:2514
 msgid "Show author email instead of name (Default: off)"
-msgstr "Zeigt anstatt des Namens die Email-Adresse des Autors (Standard: aus)"
+msgstr "Zeigt anstatt des Namens die E-Mail-Adresse des Autors (Standard: aus)"
 
 #: builtin/blame.c:2515
 msgid "Ignore whitespace differences"
@@ -3085,7 +3085,7 @@ msgstr "zu viele Branches für eine Umbenennen-Operation angegeben"
 
 #: builtin/branch.c:952
 msgid "too many branches to set new upstream"
-msgstr "zu viele Branches angegeben um Upstream-Branch zu setzen"
+msgstr "zu viele Branches angegeben, um Upstream-Branch zu setzen"
 
 #: builtin/branch.c:956
 #, c-format
@@ -3108,7 +3108,7 @@ msgstr "Branch '%s' existiert nicht"
 #: builtin/branch.c:975
 msgid "too many branches to unset upstream"
 msgstr ""
-"zu viele Branches angegeben um Konfiguration zu Upstream-Branch zu entfernen"
+"zu viele Branches angegeben, um Konfiguration zu Upstream-Branch zu entfernen"
 
 #: builtin/branch.c:979
 msgid "could not unset upstream of HEAD when it does not point to any branch."
@@ -5071,7 +5071,7 @@ msgstr "gibt für jeden Commit das gesamte Verzeichnis aus"
 
 #: builtin/fast-export.c:718
 msgid "Use the done feature to terminate the stream"
-msgstr "Benutzt die \"done\"-Funktion um den Strom abzuschließen"
+msgstr "Benutzt die \"done\"-Funktion, um den Strom abzuschließen"
 
 #: builtin/fast-export.c:719
 msgid "Skip output of blob data"
@@ -5268,7 +5268,7 @@ msgid ""
 " 'git remote prune %s' to remove any old, conflicting branches"
 msgstr ""
 "Einige lokale Referenzen konnten nicht aktualisiert werden; versuchen Sie\n"
-"'git remote prune %s' um jeden Ã¤lteren, widersprüchlichen Branch zu löschen."
+"'git remote prune %s', um jeden Ã¤lteren, widersprüchlichen Branch zu löschen."
 
 #: builtin/fetch.c:759
 #, c-format
@@ -6535,7 +6535,7 @@ msgstr "zeigt Patchformat anstatt des Standards (Patch + Zusammenfassung)"
 
 #: builtin/log.c:1217
 msgid "Messaging"
-msgstr "Email-Einstellungen"
+msgstr "E-Mail-Einstellungen"
 
 #: builtin/log.c:1218
 msgid "header"
@@ -6543,11 +6543,11 @@ msgstr "Header"
 
 #: builtin/log.c:1219
 msgid "add email header"
-msgstr "fügt Email-Header hinzu"
+msgstr "fügt E-Mail-Header hinzu"
 
 #: builtin/log.c:1220 builtin/log.c:1222
 msgid "email"
-msgstr "Email"
+msgstr "E-Mail"
 
 #: builtin/log.c:1220
 msgid "add To: header"
@@ -6573,7 +6573,7 @@ msgstr "message-id"
 
 #: builtin/log.c:1228
 msgid "make first mail a reply to <message-id>"
-msgstr "macht aus erster Email eine Antwort zu <message-id>"
+msgstr "macht aus erster E-Mail eine Antwort zu <message-id>"
 
 #: builtin/log.c:1229 builtin/log.c:1232
 msgid "boundary"
@@ -6978,7 +6978,7 @@ msgstr "konnte nicht von '%s' lesen"
 #, c-format
 msgid "Not committing merge; use 'git commit' to complete the merge.\n"
 msgstr ""
-"Merge wurde nicht committet; benutzen Sie 'git commit' um den Merge "
+"Merge wurde nicht committet; benutzen Sie 'git commit', um den Merge "
 "abzuschließen.\n"
 
 #: builtin/merge.c:809
@@ -6990,7 +6990,7 @@ msgid ""
 "Lines starting with '%c' will be ignored, and an empty message aborts\n"
 "the commit.\n"
 msgstr ""
-"Bitte geben Sie eine Commit-Beschreibung ein um zu erklären, warum dieser\n"
+"Bitte geben Sie eine Commit-Beschreibung ein, um zu erklären, warum dieser\n"
 "Merge erforderlich ist, insbesondere wenn es einen aktualisierten\n"
 "Upstream-Branch mit einem Thema-Branch zusammenführt.\n"
 "\n"
@@ -7156,7 +7156,7 @@ msgstr "Merge mit Strategie %s fehlgeschlagen.\n"
 #: builtin/merge.c:1539
 #, c-format
 msgid "Using the %s to prepare resolving by hand.\n"
-msgstr "Benutzen Sie \"%s\" um die Auflösung per Hand vorzubereiten.\n"
+msgstr "Benutzen Sie \"%s\", um die Auflösung per Hand vorzubereiten.\n"
 
 #: builtin/merge.c:1551
 #, c-format
@@ -7299,7 +7299,7 @@ msgid "Please, stage your changes to .gitmodules or stash them to proceed"
 msgstr ""
 "Bitte merken Sie Ihre Ã„nderungen in .gitmodules zum Commit vor oder "
 "benutzen\n"
-"Sie \"stash\" um fortzufahren."
+"Sie \"stash\", um fortzufahren."
 
 #: builtin/mv.c:156
 #, c-format
@@ -7368,7 +7368,7 @@ msgstr "zeigt nur Namen an (keine SHA-1)"
 
 #: builtin/name-rev.c:310
 msgid "only use tags to name the commits"
-msgstr "verwendet nur Tags um die Commits zu benennen"
+msgstr "verwendet nur Tags, um die Commits zu benennen"
 
 #: builtin/name-rev.c:312
 msgid "only use refs matching <pattern>"
@@ -7621,7 +7621,7 @@ msgid ""
 "existing notes"
 msgstr ""
 "Konnte Notizen nicht hinzufügen. Existierende Notizen für Objekt %s "
-"gefunden. Verwenden Sie '-f' um die existierenden Notizen zu Ã¼berschreiben."
+"gefunden. Verwenden Sie '-f', um die existierenden Notizen zu Ã¼berschreiben."
 
 #: builtin/notes.c:460 builtin/notes.c:537
 #, c-format
@@ -7649,7 +7649,7 @@ msgid ""
 "existing notes"
 msgstr ""
 "Kann Notizen nicht kopieren. Existierende Notizen für Objekt %s gefunden. "
-"Verwenden Sie '-f' um die existierenden Notizen zu Ã¼berschreiben."
+"Verwenden Sie '-f', um die existierenden Notizen zu Ã¼berschreiben."
 
 #: builtin/notes.c:543
 #, c-format
@@ -9359,7 +9359,7 @@ msgid ""
 "(use -f to force removal)"
 msgstr ""
 "\n"
-"(benutzen Sie -f um die Löschung zu erzwingen)"
+"(benutzen Sie -f, um die Löschung zu erzwingen)"
 
 #: builtin/rm.c:240
 msgid "the following file has changes staged in the index:"
@@ -9373,7 +9373,7 @@ msgid ""
 "(use --cached to keep the file, or -f to force removal)"
 msgstr ""
 "\n"
-"(benutzen Sie --cached um die Datei zu behalten, oder -f um die Entfernung "
+"(benutzen Sie --cached, um die Datei zu behalten, oder -f, um die Entfernung "
 "zu erzwingen)"
 
 #: builtin/rm.c:252
@@ -9431,7 +9431,7 @@ msgstr "Unterdrückt Commit-Beschreibungen, liefert nur Anzahl der Commits"
 
 #: builtin/shortlog.c:234
 msgid "Show the email address of each author"
-msgstr "Zeigt die Email-Adresse von jedem Autor"
+msgstr "Zeigt die E-Mail-Adresse von jedem Autor"
 
 #: builtin/shortlog.c:235
 msgid "w[,i1[,i2]]"
@@ -9751,7 +9751,7 @@ msgstr "annotiertes und GPG-signiertes Tag"
 
 #: builtin/tag.c:605
 msgid "use another key to sign the tag"
-msgstr "verwendet einen anderen Schlüssel um das Tag zu signieren"
+msgstr "verwendet einen anderen Schlüssel, um das Tag zu signieren"
 
 #: builtin/tag.c:606
 msgid "replace the tag if exists"
@@ -10046,7 +10046,7 @@ msgid ""
 msgstr ""
 "'git help -a' und 'git help -g' listet verfügbare Unterkommandos und\n"
 "einige Anleitungen zu Git-Konzepten auf. Benutzen Sie 'git help <Kommando>'\n"
-"oder 'git help <Konzept>' um mehr Ã¼ber ein spezifisches Kommando oder\n"
+"oder 'git help <Konzept>', um mehr Ã¼ber ein spezifisches Kommando oder\n"
 "Konzept zu erfahren."
 
 #: parse-options.h:143
@@ -10200,7 +10200,7 @@ msgstr ""
 #: git-am.sh:141
 msgid "Using index info to reconstruct a base tree..."
 msgstr ""
-"Verwende Informationen aus der Staging-Area um einen Basisverzeichnis "
+"Verwende Informationen aus der Staging-Area, um einen Basisverzeichnis "
 "nachzustellen"
 
 #: git-am.sh:156
@@ -10257,7 +10257,7 @@ msgid ""
 "Use \"git am --abort\" to remove it."
 msgstr ""
 "Stray $dotest Verzeichnis gefunden.\n"
-"Benutzen Sie \"git am --abort\" um es zu entfernen."
+"Benutzen Sie \"git am --abort\", um es zu entfernen."
 
 #: git-am.sh:535
 msgid "Resolve operation not in progress, we are not resuming."
@@ -10284,7 +10284,7 @@ msgstr ""
 
 #: git-am.sh:732
 msgid "Patch does not have a valid e-mail address."
-msgstr "Patch enthält keine gültige Email-Adresse."
+msgstr "Patch enthält keine gültige E-Mail-Adresse."
 
 #: git-am.sh:779
 msgid "cannot be interactive without stdin connected to a terminal."
@@ -10515,7 +10515,7 @@ msgid ""
 msgstr ""
 "\"pull\" ist nicht möglich, weil Sie nicht zusammengeführte Dateien haben.\n"
 "Bitte korrigieren Sie dies im Arbeitsverzeichnis und benutzen Sie dann \n"
-"'git add/rm <Datei>' um die Auflösung entsprechend zu markieren, oder\n"
+"'git add/rm <Datei>', um die Auflösung entsprechend zu markieren, oder\n"
 "benutzen Sie 'git commit -a'."
 
 #: git-pull.sh:25
@@ -11014,7 +11014,7 @@ msgid ""
 "discard them"
 msgstr ""
 "Arbeitsverzeichnis von Submodul in '$displaypath' enthält lokale Ã„nderungen; "
-"verwenden Sie '-f' um diese zu verwerfen"
+"verwenden Sie '-f', um diese zu verwerfen"
 
 #: git-submodule.sh:701
 #, sh-format
index 44b9f643725c68325a9caf92dff819e22e38e3ad..5fd9de6ce11da25b8ddf8ece9f718023394624e6 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -554,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)
@@ -624,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;
@@ -738,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:
@@ -1197,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 */
@@ -1395,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);
        }
@@ -1672,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 654a8c58d689daf43f2ba4c40e4fe54d31c7826a..6f6835bf27481299a0374bc1c7746bad750cdd12 100644 (file)
@@ -229,6 +229,9 @@ void mark_reachable_objects(struct rev_info *revs, int mark_reflog,
        /* Add all external refs */
        for_each_ref(add_one_ref, revs);
 
+       /* detached HEAD is not included in the list above */
+       head_ref(add_one_ref, revs);
+
        /* Add all reflog info */
        if (mark_reflog)
                for_each_reflog(add_one_reflog, revs);
index b5917e0c0743af3c831f9571e19e269e8a1f6014..2fc1182f2267b3e9aed799eaf7df234cd36fefb9 100644 (file)
@@ -1465,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)
 {
@@ -1526,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);
@@ -2172,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 9e405f9e41ae52c413d4feb29521e30948a81ca8..ffd45e92922ec52dccccfaecf1ceaf29f9231337 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -784,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);
 }
 
 /*
@@ -823,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;
 }
 
@@ -2190,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));
 }
 
 /*
@@ -2216,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;
@@ -2258,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;
diff --git a/refs.h b/refs.h
index 0ca60599b1a321b2805df669a4f50a1c8e58cb19..2328f06e77d34d76a1f4affedcca2c51ff9e0093 100644 (file)
--- a/refs.h
+++ b/refs.h
@@ -109,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
index 017ddd9284d77e65f0d005649adbcc8a38e3a538..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;
@@ -862,6 +862,7 @@ static int push_git(struct discovery *heads, int nr_spec, char **specs)
        int i, err;
        struct argv_array args;
        struct string_list_item *cas_option;
+       struct strbuf preamble = STRBUF_INIT;
 
        argv_array_init(&args);
        argv_array_pushl(&args, "send-pack", "--stateless-rpc", "--helper-status",
@@ -879,17 +880,22 @@ static int push_git(struct discovery *heads, int nr_spec, char **specs)
        for_each_string_list_item(cas_option, &cas_options)
                argv_array_push(&args, cas_option->string);
        argv_array_push(&args, url.buf);
+
+       argv_array_push(&args, "--stdin");
        for (i = 0; i < nr_spec; i++)
-               argv_array_push(&args, specs[i]);
+               packet_buf_write(&preamble, "%s\n", specs[i]);
+       packet_buf_flush(&preamble);
 
        memset(&rpc, 0, sizeof(rpc));
        rpc.service_name = "git-receive-pack",
        rpc.argv = args.argv;
+       rpc.stdin_preamble = &preamble;
 
        err = rpc_service(&rpc, heads);
        if (rpc.result.len)
                write_or_die(1, rpc.result.buf, rpc.result.len);
        strbuf_release(&rpc.result);
+       strbuf_release(&preamble);
        argv_array_clear(&args);
        return err;
 }
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 0d3e4171ef73f0cfb58a4f396e17717f3b0bb5a3..e498b7c3394dda23cef3719ebf1f25877d613d4e 100644 (file)
@@ -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 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 */
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 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 4d3144308feaf3fdc541b582ed589962c6c459c1..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;
index 7bdc1da50732bacad3ba33526ba10ee8f7e200a4..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);
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 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 3a2c81968cf7d539410358de1c8af6cf1d2500c9..3b92083e19d09bad951519201f9605a17b168c1a 100755 (executable)
@@ -111,4 +111,24 @@ test_expect_success 'unset many entries' '
        test_must_fail git config section.key
 '
 
+test_expect_success '--add appends new value after existing empty value' '
+       cat >expect <<-\EOF &&
+
+
+       fool
+       roll
+       EOF
+       cp .git/config .git/config.old &&
+       test_when_finished "mv .git/config.old .git/config" &&
+       cat >.git/config <<-\EOF &&
+       [foo]
+               baz
+               baz =
+               baz = fool
+       EOF
+       git config --add foo.baz roll &&
+       git config --get-all foo.baz >output &&
+       test_cmp expect output
+'
+
 test_done
index 8c739c96135fe942d7e76236eb34429be93937a8..019fddd4e81ed7b2103f916a634f3e85e7291017 100755 (executable)
@@ -69,7 +69,7 @@ test_expect_success 'object with bad sha1' '
        git update-ref refs/heads/bogus $cmt &&
        test_when_finished "git update-ref -d refs/heads/bogus" &&
 
-       test_might_fail git fsck 2>out &&
+       test_must_fail git fsck 2>out &&
        cat out &&
        grep "$sha.*corrupt" out
 '
@@ -101,7 +101,7 @@ test_expect_success 'email with embedded > is not okay' '
        test_when_finished "remove_object $new" &&
        git update-ref refs/heads/bogus "$new" &&
        test_when_finished "git update-ref -d refs/heads/bogus" &&
-       git fsck 2>out &&
+       test_must_fail git fsck 2>out &&
        cat out &&
        grep "error in commit $new" out
 '
@@ -113,7 +113,7 @@ test_expect_success 'missing < email delimiter is reported nicely' '
        test_when_finished "remove_object $new" &&
        git update-ref refs/heads/bogus "$new" &&
        test_when_finished "git update-ref -d refs/heads/bogus" &&
-       git fsck 2>out &&
+       test_must_fail git fsck 2>out &&
        cat out &&
        grep "error in commit $new.* - bad name" out
 '
@@ -125,7 +125,7 @@ test_expect_success 'missing email is reported nicely' '
        test_when_finished "remove_object $new" &&
        git update-ref refs/heads/bogus "$new" &&
        test_when_finished "git update-ref -d refs/heads/bogus" &&
-       git fsck 2>out &&
+       test_must_fail git fsck 2>out &&
        cat out &&
        grep "error in commit $new.* - missing email" out
 '
@@ -137,7 +137,7 @@ test_expect_success '> in name is reported' '
        test_when_finished "remove_object $new" &&
        git update-ref refs/heads/bogus "$new" &&
        test_when_finished "git update-ref -d refs/heads/bogus" &&
-       git fsck 2>out &&
+       test_must_fail git fsck 2>out &&
        cat out &&
        grep "error in commit $new" out
 '
@@ -151,11 +151,31 @@ test_expect_success 'integer overflow in timestamps is reported' '
        test_when_finished "remove_object $new" &&
        git update-ref refs/heads/bogus "$new" &&
        test_when_finished "git update-ref -d refs/heads/bogus" &&
-       git fsck 2>out &&
+       test_must_fail git fsck 2>out &&
        cat out &&
        grep "error in commit $new.*integer overflow" out
 '
 
+test_expect_success 'malformatted tree object' '
+       test_when_finished "git update-ref -d refs/tags/wrong" &&
+       test_when_finished "remove_object \$T" &&
+       T=$(
+               GIT_INDEX_FILE=test-index &&
+               export GIT_INDEX_FILE &&
+               rm -f test-index &&
+               >x &&
+               git add x &&
+               T=$(git write-tree) &&
+               (
+                       git cat-file tree $T &&
+                       git cat-file tree $T
+               ) |
+               git hash-object -w -t tree --stdin
+       ) &&
+       test_must_fail git fsck 2>out &&
+       grep "error in tree .*contains duplicate file entries" out
+'
+
 test_expect_success 'tag pointing to nonexistent' '
        cat >invalid-tag <<-\EOF &&
        object ffffffffffffffffffffffffffffffffffffffff
@@ -194,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
@@ -282,4 +340,60 @@ test_expect_success 'fsck notices ".git" in trees' '
        )
 '
 
+# create a static test repo which is broken by omitting
+# one particular object ($1, which is looked up via rev-parse
+# in the new repository).
+create_repo_missing () {
+       rm -rf missing &&
+       git init missing &&
+       (
+               cd missing &&
+               git commit -m one --allow-empty &&
+               mkdir subdir &&
+               echo content >subdir/file &&
+               git add subdir/file &&
+               git commit -m two &&
+               unrelated=$(echo unrelated | git hash-object --stdin -w) &&
+               git tag -m foo tag $unrelated &&
+               sha1=$(git rev-parse --verify "$1") &&
+               path=$(echo $sha1 | sed 's|..|&/|') &&
+               rm .git/objects/$path
+       )
+}
+
+test_expect_success 'fsck notices missing blob' '
+       create_repo_missing HEAD:subdir/file &&
+       test_must_fail git -C missing fsck
+'
+
+test_expect_success 'fsck notices missing subtree' '
+       create_repo_missing HEAD:subdir &&
+       test_must_fail git -C missing fsck
+'
+
+test_expect_success 'fsck notices missing root tree' '
+       create_repo_missing HEAD^{tree} &&
+       test_must_fail git -C missing fsck
+'
+
+test_expect_success 'fsck notices missing parent' '
+       create_repo_missing HEAD^ &&
+       test_must_fail git -C missing fsck
+'
+
+test_expect_success 'fsck notices missing tagged object' '
+       create_repo_missing tag^{blob} &&
+       test_must_fail git -C missing fsck
+'
+
+test_expect_success 'fsck notices ref pointing to missing commit' '
+       create_repo_missing HEAD &&
+       test_must_fail git -C missing fsck
+'
+
+test_expect_success 'fsck notices ref pointing to missing tag' '
+       create_repo_missing tag &&
+       test_must_fail git -C missing fsck
+'
+
 test_done
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 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 de0cc4a0fd5fe37bb36a3268182d95de3589f4b4..7398605e7b894259548f257aaf3e92d9481534eb 100755 (executable)
@@ -438,6 +438,14 @@ test_expect_success 'strbuf_utf8_replace() not producing NUL' '
        ! 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) &&
@@ -457,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 58b792bf20a1cd64435fca0b3d24b2417303f819..67bd8ec020e7919a37c581d3ea7c6c12e70f4276 100755 (executable)
@@ -14,7 +14,7 @@ test_expect_success 'setup' '
 '
 
 test_expect_success 'fsck notices broken commit' '
-       git fsck 2>actual &&
+       test_must_fail git fsck 2>actual &&
        test_i18ngrep invalid.author actual
 '
 
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 377d3d3899737fec47f34f0db28ac876eb146af8..01c6a3fc1dc3ef028cfdaad749e9e68955f00226 100755 (executable)
@@ -104,6 +104,28 @@ test_expect_success 'prune: prune unreachable heads' '
 
 '
 
+test_expect_success 'prune: do not prune detached HEAD with no reflog' '
+
+       git checkout --detach --quiet &&
+       git commit --allow-empty -m "detached commit" &&
+       # verify that there is no reflogs
+       # (should be removed and disabled by previous test)
+       test ! -e .git/logs &&
+       git prune -n >prune_actual &&
+       : >prune_expected &&
+       test_cmp prune_actual prune_expected
+
+'
+
+test_expect_success 'prune: prune former HEAD after checking out branch' '
+
+       head_sha1=$(git rev-parse HEAD) &&
+       git checkout --quiet master &&
+       git prune -v >prune_actual &&
+       grep "$head_sha1" prune_actual
+
+'
+
 test_expect_success 'prune: do not prune heads listed as an argument' '
 
        : > file2 &&
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
diff --git a/t/t5408-send-pack-stdin.sh b/t/t5408-send-pack-stdin.sh
new file mode 100755 (executable)
index 0000000..e8737df
--- /dev/null
@@ -0,0 +1,92 @@
+#!/bin/sh
+
+test_description='send-pack --stdin tests'
+. ./test-lib.sh
+
+create_ref () {
+       tree=$(git write-tree) &&
+       test_tick &&
+       commit=$(echo "$1" | git commit-tree $tree) &&
+       git update-ref "$1" $commit
+}
+
+clear_remote () {
+       rm -rf remote.git &&
+       git init --bare remote.git
+}
+
+verify_push () {
+       git rev-parse "$1" >expect &&
+       git --git-dir=remote.git rev-parse "${2:-$1}" >actual &&
+       test_cmp expect actual
+}
+
+test_expect_success 'setup refs' '
+       cat >refs <<-\EOF &&
+       refs/heads/A
+       refs/heads/C
+       refs/tags/D
+       refs/heads/B
+       refs/tags/E
+       EOF
+       for i in $(cat refs); do
+               create_ref $i || return 1
+       done
+'
+
+# sanity check our setup
+test_expect_success 'refs on cmdline' '
+       clear_remote &&
+       git send-pack remote.git $(cat refs) &&
+       for i in $(cat refs); do
+               verify_push $i || return 1
+       done
+'
+
+test_expect_success 'refs over stdin' '
+       clear_remote &&
+       git send-pack remote.git --stdin <refs &&
+       for i in $(cat refs); do
+               verify_push $i || return 1
+       done
+'
+
+test_expect_success 'stdin lines are full refspecs' '
+       clear_remote &&
+       echo "A:other" >input &&
+       git send-pack remote.git --stdin <input &&
+       verify_push refs/heads/A refs/heads/other
+'
+
+test_expect_success 'stdin mixed with cmdline' '
+       clear_remote &&
+       echo A >input &&
+       git send-pack remote.git --stdin B <input &&
+       verify_push A &&
+       verify_push B
+'
+
+test_expect_success 'cmdline refs written in order' '
+       clear_remote &&
+       test_must_fail git send-pack remote.git A:foo B:foo &&
+       verify_push A foo
+'
+
+test_expect_success '--stdin refs come after cmdline' '
+       clear_remote &&
+       echo A:foo >input &&
+       test_must_fail git send-pack remote.git --stdin B:foo <input &&
+       verify_push B foo
+'
+
+test_expect_success 'refspecs and --mirror do not mix (cmdline)' '
+       clear_remote &&
+       test_must_fail git send-pack remote.git --mirror $(cat refs)
+'
+
+test_expect_success 'refspecs and --mirror do not mix (stdin)' '
+       clear_remote &&
+       test_must_fail git send-pack remote.git --mirror --stdin <refs
+'
+
+test_done
index 73af16f481836d3cbfa8a2f82c260d10a3a43c09..db1998873cee18a74d98d13963ad640bc1f8abbe 100755 (executable)
@@ -323,5 +323,20 @@ test_expect_success 'push into half-auth-complete requires password' '
        test_cmp expect actual
 '
 
+run_with_limited_cmdline () {
+       (ulimit -s 128 && "$@")
+}
+
+test_lazy_prereq CMDLINE_LIMIT 'run_with_limited_cmdline true'
+
+test_expect_success CMDLINE_LIMIT 'push 2000 tags over http' '
+       sha1=$(git rev-parse HEAD) &&
+       test_seq 2000 |
+         sort |
+         sed "s|.*|$sha1 refs/tags/really-long-tag-name-&|" \
+         >.git/packed-refs &&
+       run_with_limited_cmdline git push --mirror
+'
+
 stop_httpd
 test_done
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 99f51614ad9ec3de8abf272d6fc6a778707a2292..8a054494bd6c261575ab73e4f7eb72f33ba2967e 100755 (executable)
@@ -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'
@@ -3017,4 +3017,108 @@ test_expect_success 'T: empty reset doesnt delete branch' '
        git rev-parse --verify refs/heads/not-to-delete
 '
 
+###
+### series U (filedelete)
+###
+
+cat >input <<INPUT_END
+commit refs/heads/U
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data <<COMMIT
+test setup
+COMMIT
+M 100644 inline hello.c
+data <<BLOB
+blob 1
+BLOB
+M 100644 inline good/night.txt
+data <<BLOB
+sleep well
+BLOB
+M 100644 inline good/bye.txt
+data <<BLOB
+au revoir
+BLOB
+
+INPUT_END
+
+test_expect_success 'U: initialize for U tests' '
+       git fast-import <input
+'
+
+cat >input <<INPUT_END
+commit refs/heads/U
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data <<COMMIT
+delete good/night.txt
+COMMIT
+from refs/heads/U^0
+D good/night.txt
+
+INPUT_END
+
+test_expect_success 'U: filedelete file succeeds' '
+       git fast-import <input
+'
+
+cat >expect <<EOF
+:100644 000000 2907ebb4bf85d91bf0716bb3bd8a68ef48d6da76 0000000000000000000000000000000000000000 D     good/night.txt
+EOF
+
+git diff-tree -M -r U^1 U >actual
+
+test_expect_success 'U: validate file delete result' '
+       compare_diff_raw expect actual
+'
+
+cat >input <<INPUT_END
+commit refs/heads/U
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data <<COMMIT
+delete good dir
+COMMIT
+from refs/heads/U^0
+D good
+
+INPUT_END
+
+test_expect_success 'U: filedelete directory succeeds' '
+       git fast-import <input
+'
+
+cat >expect <<EOF
+:100644 000000 69cb75792f55123d8389c156b0b41c2ff00ed507 0000000000000000000000000000000000000000 D     good/bye.txt
+EOF
+
+git diff-tree -M -r U^1 U >actual
+
+test_expect_success 'U: validate directory delete result' '
+       compare_diff_raw expect actual
+'
+
+cat >input <<INPUT_END
+commit refs/heads/U
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data <<COMMIT
+must succeed
+COMMIT
+from refs/heads/U^0
+D ""
+
+INPUT_END
+
+test_expect_success 'U: filedelete root succeeds' '
+    git fast-import <input
+'
+
+cat >expect <<EOF
+:100644 000000 c18147dc648481eeb65dc5e66628429a64843327 0000000000000000000000000000000000000000 D     hello.c
+EOF
+
+git diff-tree -M -r U^1 U >actual
+
+test_expect_success 'U: validate root delete result' '
+       compare_diff_raw expect actual
+'
+
 test_done
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 2b525a8e1d19cd11fea0ba06372111306ce7bf41..82095e34eeb7ce9932abe1a5e97b1c2eb0888033 100644 (file)
@@ -870,6 +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 NATIVE_CRLF
        test_set_prereq SED_STRIPS_CR
        test_set_prereq GREP_STRIPS_CR
        GIT_TEST_CMP=mingw_test_cmp
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
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)
diff --git a/trace.c b/trace.c
index 54aaee58183f880365caa1986824054a4533797e..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);
 }
diff --git a/utf8.c b/utf8.c
index 401a6a509e8b4221a539cec6ad67721fc620d64e..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)
 {
index f8d370913a8dcfb87d62ab994b4823dc84157f8b..18a67d33cb55b799f7784e52ceac214cf76e5d3e 100644 (file)
--- a/walker.c
+++ b/walker.c
@@ -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;
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) {