Merge branch 'jk/push-config'
authorJunio C Hamano <gitster@pobox.com>
Mon, 23 Mar 2015 18:28:13 +0000 (11:28 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 23 Mar 2015 18:28:14 +0000 (11:28 -0700)
Restructure "git push" codepath to make it easier to add new
configuration bits and then add push.followTags configuration that
turns --follow-tags option on by default.

* jk/push-config:
push: allow --follow-tags to be set by config push.followTags
cmd_push: pass "flags" pointer to config callback
cmd_push: set "atomic" bit directly
git_push_config: drop cargo-culted wt_status pointer

188 files changed:
Documentation/CodingGuidelines
Documentation/RelNotes/2.3.1.txt [new file with mode: 0644]
Documentation/RelNotes/2.3.2.txt [new file with mode: 0644]
Documentation/RelNotes/2.3.3.txt [new file with mode: 0644]
Documentation/RelNotes/2.4.0.txt [new file with mode: 0644]
Documentation/blame-options.txt
Documentation/config.txt
Documentation/diff-config.txt
Documentation/diff-format.txt
Documentation/diff-options.txt
Documentation/fetch-options.txt
Documentation/git-add.txt
Documentation/git-am.txt
Documentation/git-apply.txt
Documentation/git-branch.txt
Documentation/git-check-ignore.txt
Documentation/git-checkout.txt
Documentation/git-clean.txt
Documentation/git-commit-tree.txt
Documentation/git-commit.txt
Documentation/git-config.txt
Documentation/git-cvsserver.txt
Documentation/git-fetch.txt
Documentation/git-format-patch.txt
Documentation/git-gc.txt
Documentation/git-imap-send.txt
Documentation/git-init.txt
Documentation/git-instaweb.txt
Documentation/git-log.txt
Documentation/git-merge.txt
Documentation/git-pull.txt
Documentation/git-push.txt
Documentation/git-rebase.txt
Documentation/git-receive-pack.txt
Documentation/git-reflog.txt
Documentation/git-remote.txt
Documentation/git-repack.txt
Documentation/git-rerere.txt
Documentation/git-send-email.txt
Documentation/git-status.txt
Documentation/git-submodule.txt
Documentation/git-tag.txt
Documentation/git.txt
Documentation/gitattributes.txt
Documentation/gitcredentials.txt
Documentation/gitignore.txt
Documentation/gitmodules.txt
Documentation/gitweb.conf.txt
Documentation/merge-config.txt
Documentation/rev-list-options.txt
Documentation/technical/api-error-handling.txt [new file with mode: 0644]
Documentation/technical/api-strbuf.txt [deleted file]
Documentation/user-manual.txt
GIT-VERSION-GEN
Makefile
RelNotes [changed from file to symlink]
archive-zip.c
attr.c
branch.c
builtin/apply.c
builtin/blame.c
builtin/branch.c
builtin/clean.c
builtin/commit.c
builtin/fetch.c
builtin/for-each-ref.c
builtin/grep.c
builtin/help.c
builtin/index-pack.c
builtin/merge-file.c
builtin/pack-objects.c
builtin/receive-pack.c
builtin/reflog.c
builtin/replace.c
builtin/tag.c
builtin/update-ref.c
bulk-checkin.c
bundle.c
cache.h
check-builtins.sh
config.c
config.mak.uname
configure.ac
connect.c
contrib/completion/git-completion.bash
contrib/credential/wincred/git-credential-wincred.c
ctype.c
daemon.c
diff-lib.c
diff.c
diffcore-rename.c
ewah/ewok.h
fast-import.c
gettext.c
gettext.h
git-add--interactive.perl
git-compat-util.h
git-instaweb.sh
git-rebase--interactive.sh
git-remote-testgit.sh
git-send-email.perl
git-submodule.sh
git-svn.perl
git.c
hex.c
http-push.c
http.c
imap-send.c
kwset.c
kwset.h
log-tree.c
pager.c
perl/Git.pm
perl/Git/SVN.pm
perl/Git/SVN/Editor.pm
perl/Git/SVN/Fetcher.pm
perl/Git/SVN/Ra.pm
pretty.c
read-cache.c
refs.c
refs.h
remote-curl.c
run-command.c
sequencer.c
sha1_file.c
sha1_name.c
strbuf.h
t/diff-lib.sh
t/diff-lib/COPYING [new file with mode: 0644]
t/diff-lib/README [new file with mode: 0644]
t/lib-gpg.sh
t/lib-gpg/keyring.gpg
t/lib-httpd.sh
t/lib-httpd/apache.conf
t/t0056-git-C.sh
t/t0061-run-command.sh
t/t1307-config-blob.sh
t/t1509-root-worktree.sh
t/t3203-branch-output.sh
t/t3404-rebase-interactive.sh
t/t3511-cherry-pick-x.sh
t/t4003-diff-rename-1.sh
t/t4005-diff-rename-2.sh
t/t4007-rename-3.sh
t/t4008-diff-break-rewrite.sh
t/t4009-diff-rename-4.sh
t/t4010-diff-pathspec.sh
t/t4013/diff.log_--decorate_--all
t/t4047-diff-dirstat.sh
t/t4058-diff-duplicates.sh [new file with mode: 0755]
t/t4122-apply-symlink-inside.sh
t/t4138-apply-ws-expansion.sh [new file with mode: 0755]
t/t4139-apply-escape.sh [new file with mode: 0755]
t/t4207-log-decoration-colors.sh
t/t5003-archive-zip.sh
t/t5304-prune.sh
t/t5500-fetch-pack.sh
t/t5516-fetch-push.sh
t/t5528-push-default.sh
t/t5541-http-push-smart.sh
t/t5550-http-fetch-dumb.sh
t/t5551-http-fetch-smart.sh
t/t5570-git-daemon.sh
t/t5601-clone.sh
t/t5801-remote-helpers.sh
t/t6023-merge-file.sh
t/t7004-tag.sh
t/t7400-submodule-basic.sh
t/t7508-status.sh
t/t7510-signed-commit.sh
t/t7516-commit-races.sh [new file with mode: 0755]
t/t9001-send-email.sh
t/t9300-fast-import.sh
t/t9902-completion.sh
t/test-lib-functions.sh
t/test-lib.sh
thread-utils.c
trailer.c
transport-helper.c
transport.c
upload-pack.c
userdiff.c
versioncmp.c
walker.c
wrapper.c
wt-status.c
wt-status.h
zlib.c
index 49089de5c0024202493867e545d3d6b87c98571d..376d5ec4f8dbbc0034416192fc13a1a527c7ca4b 100644 (file)
@@ -418,6 +418,29 @@ Error Messages
  - Say what the error is first ("cannot open %s", not "%s: cannot open")
 
 
+Externally Visible Names
+
+ - For configuration variable names, follow the existing convention:
+
+   . The section name indicates the affected subsystem.
+
+   . The subsection name, if any, indicates which of an unbounded set
+     of things to set the value for.
+
+   . The variable name describes the effect of tweaking this knob.
+
+   The section and variable names that consist of multiple words are
+   formed by concatenating the words without punctuations (e.g. `-`),
+   and are broken using bumpyCaps in documentation as a hint to the
+   reader.
+
+   When choosing the variable namespace, do not use variable name for
+   specifying possibly unbounded set of things, most notably anything
+   an end user can freely come up with (e.g. branch names).  Instead,
+   use subsection names or variable values, like the existing variable
+   branch.<name>.description does.
+
+
 Writing Documentation:
 
  Most (if not all) of the documentation pages are written in the
@@ -503,7 +526,7 @@ Writing Documentation:
  `backticks around word phrases`, do so.
    `--pretty=oneline`
    `git rev-list`
-   `remote.pushdefault`
+   `remote.pushDefault`
 
  Word phrases enclosed in `backtick characters` are rendered literally
  and will not be further expanded. The use of `backticks` to achieve the
diff --git a/Documentation/RelNotes/2.3.1.txt b/Documentation/RelNotes/2.3.1.txt
new file mode 100644 (file)
index 0000000..cf96186
--- /dev/null
@@ -0,0 +1,52 @@
+Git v2.3.1 Release Notes
+========================
+
+Fixes since v2.3
+----------------
+
+ * The interactive "show a list and let the user choose from it"
+   interface "add -i" used showed and prompted to the user even when
+   the candidate list was empty, against which the only "choice" the
+   user could have made was to choose nothing.
+
+ * "git apply --whitespace=fix" used to under-allocate the memory
+   when the fix resulted in a longer text than the original patch.
+
+ * "git log --help" used to show rev-list options that are irrelevant
+   to the "log" command.
+
+ * The error message from "git commit", when a non-existing author
+   name was given as value to the "--author=" parameter, has been
+   reworded to avoid misunderstanding.
+
+ * A broken pack .idx file in the receiving repository prevented the
+   dumb http transport from fetching a good copy of it from the other
+   side.
+
+ * The documentation incorrectly said that C(opy) and R(ename) are the
+   only ones that can be followed by the score number in the output in
+   the --raw format.
+
+ * Fix a misspelled conditional that is always true.
+
+ * Code to read branch name from various files in .git/ directory
+   would have misbehaved if the code to write them left an empty file.
+
+ * The "git push" documentation made the "--repo=<there>" option
+   easily misunderstood.
+
+ * After attempting and failing a password-less authentication
+   (e.g. kerberos), libcURL refuses to fall back to password based
+   Basic authentication without a bit of help/encouragement.
+
+ * Setting diff.submodule to 'log' made "git format-patch" produce
+   broken patches.
+
+ * "git rerere" (invoked internally from many mergy operations) did
+   not correctly signal errors when told to update the working tree
+   files and failed to do so for whatever reason.
+
+ * "git blame HEAD -- missing" failed to correctly say "HEAD" when it
+   tried to say "No such path 'missing' in HEAD".
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
diff --git a/Documentation/RelNotes/2.3.2.txt b/Documentation/RelNotes/2.3.2.txt
new file mode 100644 (file)
index 0000000..f4caf54
--- /dev/null
@@ -0,0 +1,79 @@
+Git v2.3.2 Release Notes
+========================
+
+Fixes since v2.3.1
+------------------
+
+ * "update-index --refresh" used to leak when an entry cannot be
+   refreshed for whatever reason.
+
+ * "git fast-import" used to crash when it could not close and
+   conclude the resulting packfile cleanly.
+
+ * "git blame" died, trying to free an uninitialized piece of memory.
+
+ * "git merge-file" did not work correctly in a subdirectory.
+
+ * "git submodule add" failed to squash "path/to/././submodule" to
+   "path/to/submodule".
+
+ * In v2.2.0, we broke "git prune" that runs in a repository that
+   borrows from an alternate object store.
+
+ * Certain older vintages of cURL give irregular output from
+   "curl-config --vernum", which confused our build system.
+
+ * An earlier workaround to squelch unhelpful deprecation warnings
+   from the complier on Mac OSX unnecessarily set minimum required
+   version of the OS, which the user might want to raise (or lower)
+   for other reasons.
+
+ * Longstanding configuration variable naming rules has been added to
+   the documentation.
+
+ * The credential helper for Windows (in contrib/) used to mishandle
+   a user name with an at-sign in it.
+
+ * Older GnuPG implementations may not correctly import the keyring
+   material we prepare for the tests to use.
+
+ * Clarify in the documentation that "remote.<nick>.pushURL" and
+   "remote.<nick>.URL" are there to name the same repository accessed
+   via different transports, not two separate repositories.
+
+ * The pack bitmap support did not build with older versions of GCC.
+
+ * Reading configuration from a blob object, when it ends with a lone
+   CR, use to confuse the configuration parser.
+
+ * We didn't format an integer that wouldn't fit in "int" but in
+   "uintmax_t" correctly.
+
+ * "git push --signed" gave an incorrectly worded error message when
+   the other side did not support the capability.
+
+ * "git fetch" over a remote-helper that cannot respond to "list"
+   command could not fetch from a symbolic reference e.g. HEAD.
+
+ * The insn sheet "git rebase -i" creates did not fully honor
+   core.abbrev settings.
+
+ * The tests that wanted to see that file becomes unreadable after
+   running "chmod a-r file", and the tests that wanted to make sure it
+   is not run as root, we used "can we write into the / directory?" as
+   a cheap substitute, but on some platforms that is not a good
+   heuristics.  The tests and their prerequisites have been updated to
+   check what they really require.
+
+ * The configuration variable 'mailinfo.scissors' was hard to
+   discover in the documentation.
+
+ * Correct a breakage to git-svn around v2.2 era that triggers
+   premature closing of FileHandle.
+
+ * Even though we officially haven't dropped Perl 5.8 support, the
+   Getopt::Long package that came with it does not support "--no-"
+   prefix to negate a boolean option; manually add support to help
+   people with older Getopt::Long package.
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
diff --git a/Documentation/RelNotes/2.3.3.txt b/Documentation/RelNotes/2.3.3.txt
new file mode 100644 (file)
index 0000000..5ef1264
--- /dev/null
@@ -0,0 +1,39 @@
+Git v2.3.3 Release Notes
+========================
+
+Fixes since v2.3.2
+------------------
+
+ * A corrupt input to "git diff -M" used cause us to segfault.
+
+ * The borrowed code in kwset API did not follow our usual convention
+   to use "unsigned char" to store values that range from 0-255.
+
+ * Description given by "grep -h" for its --exclude-standard option
+   was phrased poorly.
+
+ * Documentaton for "git remote add" mentioned "--tags" and
+   "--no-tags" and it was not clear that fetch from the remote in
+   the future will use the default behaviour when neither is given
+   to override it.
+
+ * "git diff --shortstat --dirstat=changes" showed a dirstat based on
+   lines that was never asked by the end user in addition to the
+   dirstat that the user asked for.
+
+ * The interaction between "git submodule update" and the
+   submodule.*.update configuration was not clearly documented.
+
+ * "git apply" was not very careful about reading from, removing,
+   updating and creating paths outside the working tree (under
+   --index/--cached) or the current directory (when used as a
+   replacement for GNU patch).
+
+ * "git daemon" looked up the hostname even when "%CH" and "%IP"
+   interpolations are not requested, which was unnecessary.
+
+ * The "interpolated-path" option of "git daemon" inserted any string
+   client declared on the "host=" capability request without checking.
+   Sanitize and limit %H and %CH to a saner and a valid DNS name.
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
diff --git a/Documentation/RelNotes/2.4.0.txt b/Documentation/RelNotes/2.4.0.txt
new file mode 100644 (file)
index 0000000..ca149da
--- /dev/null
@@ -0,0 +1,383 @@
+Git 2.4 Release Notes
+=====================
+
+Backward compatibility warning(s)
+---------------------------------
+
+Output from "git log --decorate" (and "%d" format specifier used in
+the userformat "--format=<string>" parameter "git log" family of
+command takes) used to list "HEAD" just like other tips of branch
+names, separated with a comma in between.  E.g.
+
+    $ git log --decorate -1 master
+    commit bdb0f6788fa5e3cacc4315e9ff318a27b2676ff4 (HEAD, master)
+    ...
+
+This release updates the output slightly when HEAD refers to the tip
+of a branch whose name is also shown in the output.  The above is
+shown as:
+
+    $ git log --decorate -1 master
+    commit bdb0f6788fa5e3cacc4315e9ff318a27b2676ff4 (HEAD -> master)
+    ...
+
+
+
+
+Updates since v2.3
+------------------
+
+Ports
+
+ * Our default I/O size (8 MiB) for large files was too large for some
+   platforms with smaller SSIZE_MAX, leading to read(2)/write(2)
+   failures.
+
+ * We did not check the curl library version before using
+   CURLOPT_PROXYAUTH feature that may not exist.
+
+ * We now detect number of CPUs on older BSD-derived systems.
+
+ * Portability fixes and workarounds for shell scripts have been added
+   to help BSD-derived systems.
+
+
+UI, Workflows & Features
+
+ * The command usage info strings given by "git cmd -h" and in
+   documentation have been tweaked for consistency.
+
+ * The "sync" subcommand of "git p4" now allows users to exclude
+   subdirectories like its "clone" subcommand does.
+
+ * "git log --invert-grep --grep=WIP" will show only commits that do
+   not have the string "WIP" in their messages.
+
+ * "git push" has been taught a "--atomic" option that makes push to
+   update more than one ref an "all-or-none" affair.
+
+ * Extending the "push to deploy" added in 2.3, the behaviour of "git
+   push" when updating the branch that is checked out can now be
+   tweaked by push-to-checkout hook.
+
+ * Using environment variable LANGUAGE and friends on the client side,
+   HTTP-based transports now send Accept-Language when making requests.
+
+ * "git send-email" used to accept a mistaken "y" (or "yes") as an
+   answer to "What encoding do you want to use [UTF-8]? " without
+   questioning.  Now it asks for confirmation when the answer looks
+   too short to be a valid encoding name.
+
+ * When "git apply --whitespace=fix" fixed whitespace errors in the
+   common context lines, the command reports that it did so.
+
+ * "git status" now allows the "-v" to be given twice to show the
+   differences that are left in the working tree not to be committed.
+
+ * "git cherry-pick" used to clean-up the log message even when it is
+   merely replaying an existing commit.  It now replays the message
+   verbatim unless you are editing the message of resulting commits.
+
+ * "git archive" can now be told to set the 'text' attribute in the
+   resulting zip archive.
+
+ * Output from "git log --decorate" mentions HEAD when it points at a
+   tip of an branch differently from a detached HEAD.
+
+   This is a potentially backward-incompatible change.
+
+ * "git branch" on a detached HEAD always said "(detached from xyz)",
+   even when "git status" would report "detached at xyz".  The HEAD is
+   actually at xyz and haven't been moved since it was detached in
+   such a case, but the user cannot read what the current value of
+   HEAD is when "detached from" is used.
+   (merge 4b06318 mg/detached-head-report later to maint).
+
+ * "git -C '' subcmd" refused to work in the current directory, unlike
+   "cd ''" which silently behaves as a no-op.
+   (merge 6a536e2 kn/git-cd-to-empty later to maint).
+
+ * The versionsort.prerelease configuration variable can be used to
+   specify that v1.0-pre1 comes before v1.0.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * Implementation of N_() macro has been updated slightly to help us
+   detect mistakes.
+
+ * Implementation of "reflog expire" has been restructured to fit the
+   reflogs better with the recently updated ref API.
+
+ * The transport-helper did not give transport options such as
+   verbosity, progress, cloning, etc. to import and export based
+   helpers, like it did for fetch and push based helpers, robbing them
+   the chance to honor the wish of the end-users better.
+
+ * The tests that wanted to see that file becomes unreadable after
+   running "chmod a-r file", and the tests that wanted to make sure it
+   is not run as root, we used "can we write into the / directory?" as
+   a cheap substitute, but on some platforms that is not a good
+   heuristics.  The tests and their prerequisites have been updated to
+   check what they really require.
+   (merge f400e51 jk/sanity later to maint).
+
+ * Various issues around "reflog expire", e.g. using --updateref when
+   expiring a reflog for a symbolic reference, have been corrected
+   and/or made saner.
+
+ * The strbuf API was explained between the API documentation and in
+   the header file.  Move missing bits to strbuf.h so that programmers
+   can check only one place for all necessary information.
+
+ * The error handling functions and conventions are now documented in
+   the API manual.
+
+ * Optimize attribute look-up, mostly useful in "git grep" on a
+   project that does not use many attributes, by avoiding it when we
+   (should) know that the attributes are not defined in the first
+   place.
+
+ * Typofix in comments.
+   (merge ef2956a ak/git-pm-typofix later to maint).
+
+ * Code clean-up.
+   (merge 0b868f0 sb/hex-object-name-is-at-most-41-bytes-long later to maint).
+   (merge 5d30851 dp/remove-duplicated-header-inclusion later to maint).
+
+ * Simplify the ref transaction API around how "the ref should be
+   pointing at this object" is specified.
+
+ * Code in "git daemon" to parse out and hold hostnames used in
+   request interpolation has been simplified.
+
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v2.3
+----------------
+
+Unless otherwise noted, all the fixes since v2.3 in the maintenance
+track are contained in this release (see the maintenance releases'
+notes for details).
+
+ * "git blame HEAD -- missing" failed to correctly say "HEAD" when it
+   tried to say "No such path 'missing' in HEAD".
+   (merge a46442f jk/blame-commit-label later to maint).
+
+ * "git rerere" (invoked internally from many mergy operations) did
+   not correctly signal errors when told to update the working tree
+   files and failed to do so for whatever reason.
+   (merge 89ea903 jn/rerere-fail-on-auto-update-failure later to maint).
+
+ * Setting diff.submodule to 'log' made "git format-patch" produce
+   broken patches.
+   (merge 339de50 dk/format-patch-ignore-diff-submodule later to maint).
+
+ * After attempting and failing a password-less authentication
+   (e.g. kerberos), libcURL refuses to fall back to password based
+   Basic authentication without a bit of help/encouragement.
+   (merge 4dbe664 bc/http-fallback-to-password-after-krb-fails later to maint).
+
+ * The "git push" documentation made the "--repo=<there>" option
+   easily misunderstood.
+   (merge 57b92a7 mg/push-repo-option-doc later to maint).
+
+ * Code to read branch name from various files in .git/ directory
+   would have misbehaved if the code to write them left an empty file.
+   (merge 66ec904 jk/status-read-branch-name-fix later to maint).
+
+ * A misspelled conditional that is always true has been fixed.
+   (merge 94ee8e2 jk/remote-curl-an-array-in-struct-cannot-be-null later to maint).
+
+ * The documentation incorrectly said that C(opy) and R(ename) are the
+   only ones that can be followed by the score number in the output in
+   the --raw format.
+   (merge ac1c2d9 jc/diff-format-doc later to maint).
+
+ * A broken pack .idx file in the receiving repository prevented the
+   dumb http transport from fetching a good copy of it from the other
+   side.
+   (merge 8b9c2dd jk/dumb-http-idx-fetch-fix later to maint).
+
+ * The error message from "git commit", when a non-existing author
+   name was given as value to the "--author=" parameter, has been
+   reworded to avoid misunderstanding.
+   (merge 1044b1f mg/commit-author-no-match-malformed-message later to maint).
+
+ * "git log --help" used to show rev-list options that are irrelevant
+   to the "log" command.
+   (merge 3cab02d jc/doc-log-rev-list-options later to maint).
+
+ * "git apply --whitespace=fix" used to under-allocate the memory when
+   the fix resulted in a longer text than the original patch.
+   (merge 407a792 jc/apply-ws-fix-expands later to maint).
+
+ * The interactive "show a list and let the user choose from it"
+   interface "add -i" used showed and prompted to the user even when
+   the candidate list was empty, against which the only "choice" the
+   user could have made was to choose nothing.
+   (merge a9c4641 ak/add-i-empty-candidates later to maint).
+
+ * The insn sheet "git rebase -i" creates did not fully honor
+   core.abbrev settings.
+   (merge edb72d5 ks/rebase-i-abbrev later to maint).
+
+ * "git fetch" over a remote-helper that cannot respond to "list"
+   command could not fetch from a symbolic reference e.g. HEAD.
+   (merge 33cae54 mh/deref-symref-over-helper-transport later to maint).
+
+ * "git push --signed" gave an incorrectly worded error message when
+   the other side did not support the capability.
+   (merge 45917f0 jc/push-cert later to maint).
+
+ * We didn't format an integer that wouldn't fit in "int" but in
+   "uintmax_t" correctly.
+   (merge d306f3d jk/decimal-width-for-uintmax later to maint).
+
+ * Reading configuration from a blob object, when it ends with a lone
+   CR, use to confuse the configuration parser.
+   (merge 1d0655c jk/config-no-ungetc-eof later to maint).
+
+ * The pack bitmap support did not build with older versions of GCC.
+   (merge bd4e882 jk/pack-bitmap later to maint).
+
+ * The documentation wasn't clear that "remote.<nick>.pushURL" and
+   "remote.<nick>.URL" are there to name the same repository accessed
+   via different transports, not two separate repositories.
+   (merge 697f652 jc/remote-set-url-doc later to maint).
+
+ * Older GnuPG implementations may not correctly import the keyring
+   material we prepare for the tests to use.
+   (merge 1f985d6 ch/new-gpg-drops-rfc-1991 later to maint).
+
+ * The credential helper for Windows (in contrib/) used to mishandle
+   a user name with an at-sign in it.
+   (merge 13d261e av/wincred-with-at-in-username-fix later to maint).
+
+ * Longstanding configuration variable naming rules has been added to
+   the documentation.
+   (merge 35840a3 jc/conf-var-doc later to maint).
+
+ * An earlier workaround to squelch unhelpful deprecation warnings
+   from the complier on Mac OSX unnecessarily set minimum required
+   version of the OS, which the user might want to raise (or lower)
+   for other reasons.
+   (merge 88c03eb es/squelch-openssl-warnings-on-macosx later to maint).
+
+ * Certain older vintages of cURL give irregular output from
+   "curl-config --vernum", which confused our build system.
+   (merge 3af6792 tc/curl-vernum-output-broken-in-7.11 later to maint).
+
+ * In v2.2.0, we broke "git prune" that runs in a repository that
+   borrows from an alternate object store.
+   (merge b0a4264 jk/prune-mtime later to maint).
+
+ * "git submodule add" failed to squash "path/to/././submodule" to
+   "path/to/submodule".
+   (merge 8196e72 ps/submodule-sanitize-path-upon-add later to maint).
+
+ * "git merge-file" did not work correctly in a subdirectory.
+   (merge 204a8ff ab/merge-file-prefix later to maint).
+
+ * "git blame" died, trying to free an uninitialized piece of memory.
+   (merge e600592 es/blame-commit-info-fix later to maint).
+
+ * "git fast-import" used to crash when it could not close and
+   conclude the resulting packfile cleanly.
+   (merge 5e915f3 jk/fast-import-die-nicely-fix later to maint).
+
+ * "update-index --refresh" used to leak when an entry cannot be
+   refreshed for whatever reason.
+   (merge bc1c2ca sb/plug-leak-in-make-cache-entry later to maint).
+
+ * The "interpolated-path" option of "git daemon" inserted any string
+   client declared on the "host=" capability request without checking.
+   Sanitize and limit %H and %CH to a saner and a valid DNS name.
+   (merge b485373 jk/daemon-interpolate later to maint).
+
+ * "git daemon" looked up the hostname even when "%CH" and "%IP"
+   interpolations are not requested, which was unnecessary.
+   (merge dc8edc8 rs/daemon-interpolate later to maint).
+
+ * Even though we officially haven't dropped Perl 5.8 support, the
+   Getopt::Long package that came with it does not support "--no-"
+   prefix to negate a boolean option; manually add support to help
+   people with older Getopt::Long package.
+   (merge f471494 km/send-email-getopt-long-workarounds later to maint).
+
+ * "git apply" was not very careful about reading from, removing,
+   updating and creating paths outside the working tree (under
+   --index/--cached) or the current directory (when used as a
+   replacement for GNU patch).
+   (merge e0d201b jc/apply-beyond-symlink later to maint).
+
+ * A breakage to git-svn around v2.2 era that triggers premature
+   closing of FileHandle has been corrected.
+   (merge e426311 ew/svn-maint-fixes later to maint).
+
+ * We did not parse username followed by literal IPv6 address in SSH
+   transport URLs, e.g. ssh://user@[2001:db8::1]:22/repo.git
+   correctly.
+   (merge 3f55cca tb/connect-ipv6-parse-fix later to maint).
+
+ * The configuration variable 'mailinfo.scissors' was hard to
+   discover in the documentation.
+   (merge afb5de7 mm/am-c-doc later to maint).
+
+ * The interaction between "git submodule update" and the
+   submodule.*.update configuration was not clearly documented.
+   (merge 5c31acf ms/submodule-update-config-doc later to maint).
+
+ * "git diff --shortstat --dirstat=changes" showed a dirstat based on
+   lines that was never asked by the end user in addition to the
+   dirstat that the user asked for.
+   (merge ab27389 mk/diff-shortstat-dirstat-fix later to maint).
+
+ * "git remote add" mentioned "--tags" and "--no-tags" and was not
+   clear that fetch from the remote in the future will use the default
+   behaviour when neither is given to override it.
+   (merge aaba0ab mg/doc-remote-tags-or-not later to maint).
+
+ * Description given by "grep -h" for its --exclude-standard option
+   was phrased poorly.
+   (merge 77fdb8a nd/grep-exclude-standard-help-fix later to maint).
+
+ * "git rebase -i" recently started to include the number of
+   commits in the insn sheet to be processed, but on a platform
+   that prepends leading whitespaces to "wc -l" output, the numbers
+   are shown with extra whitespaces that aren't necessary.
+   (merge 2185d3b es/rebase-i-count-todo later to maint).
+
+ * The borrowed code in kwset API did not follow our usual convention
+   to use "unsigned char" to store values that range from 0-255.
+   (merge 189c860 bw/kwset-use-unsigned later to maint).
+
+ * A corrupt input to "git diff -M" used to cause it to segfault.
+   (merge 4d6be03 jk/diffcore-rename-duplicate later to maint).
+
+ * Certain builds of GPG triggered false breakages in a test.
+   (merge 3f88c1b mg/verify-commit later to maint).
+
+ * "git imap-send" learned to optionally talk with an IMAP server via
+   libcURL; because there is no other option when Git is built with
+   NO_OPENSSL option, use that codepath by default under such
+   configuration.
+   (merge dcd01ea km/imap-send-libcurl-options later to maint).
+
+ * "git log --decorate" did not reset colors correctly around the
+   branch names.
+   (merge 5ee8758 jc/decorate-leaky-separator-color later to maint).
+
+ * Code cleanups and documentaiton updates.
+   (merge 2ce63e9 rs/simple-cleanups later to maint).
+   (merge 33baa69 rj/no-xopen-source-for-cygwin later to maint).
+   (merge 817d03e jc/diff-test-updates later to maint).
+   (merge eb32c66 ak/t5516-typofix later to maint).
+   (merge bcd57cb mr/doc-clean-f-f later to maint).
+   (merge 0d6accc mg/doc-status-color-slot later to maint).
+   (merge 53e53c7 sg/completion-remote later to maint).
+   (merge 8fa7975 ak/git-done-help-cleanup later to maint).
+   (merge 9a6f128 rs/deflate-init-cleanup later to maint).
+   (merge 6f75d45 rs/use-isxdigit later to maint).
index 0cebc4f6927211ffbc013de9368f03f480dba65d..b299b5902360bdd9f784e5b3acdae3b558a6565a 100644 (file)
@@ -4,7 +4,7 @@
 
 --root::
        Do not treat root commits as boundaries.  This can also be
-       controlled via the `blame.showroot` config option.
+       controlled via the `blame.showRoot` config option.
 
 --show-stats::
        Include additional statistics at the end of blame output.
index e01d21cda2811badd7395e68f6c29341c9355eda..2e5ceaf71974b1e5404de79103648da1829eaf42 100644 (file)
@@ -14,7 +14,8 @@ the fully qualified variable name of the variable itself is the last
 dot-separated segment and the section name is everything before the last
 dot. The variable names are case-insensitive, allow only alphanumeric
 characters and `-`, and must start with an alphabetic character.  Some
-variables may appear multiple times.
+variables may appear multiple times; we say then that the variable is
+multivalued.
 
 Syntax
 ~~~~~~
@@ -25,7 +26,7 @@ blank lines are ignored.
 
 The file consists of sections and variables.  A section begins with
 the name of the section in square brackets and continues until the next
-section begins.  Section names are not case sensitive.  Only alphanumeric
+section begins.  Section names are case-insensitive.  Only alphanumeric
 characters, `-` and `.` are allowed in section names.  Each variable
 must belong to some section, which means that there must be a section
 header before the first setting of a variable.
@@ -40,8 +41,8 @@ in the section header, like in the example below:
 --------
 
 Subsection names are case sensitive and can contain any characters except
-newline (doublequote `"` and backslash have to be escaped as `\"` and `\\`,
-respectively).  Section headers cannot span multiple
+newline (doublequote `"` and backslash can be included by escaping them
+as `\"` and `\\`, respectively).  Section headers cannot span multiple
 lines.  Variables may belong directly to a section or to a given subsection.
 You can have `[section]` if you have `[section "subsection"]`, but you
 don't need to.
@@ -53,38 +54,27 @@ restrictions as section names.
 
 All the other lines (and the remainder of the line after the section
 header) are recognized as setting variables, in the form
-'name = value'.  If there is no equal sign on the line, the entire line
-is taken as 'name' and the variable is recognized as boolean "true".
+'name = value' (or just 'name', which is a short-hand to say that
+the variable is the boolean "true").
 The variable names are case-insensitive, allow only alphanumeric characters
-and `-`, and must start with an alphabetic character.  There can be more
-than one value for a given variable; we say then that the variable is
-multivalued.
-
-Leading and trailing whitespace in a variable value is discarded.
-Internal whitespace within a variable value is retained verbatim.
+and `-`, and must start with an alphabetic character.
 
-The values following the equals sign in variable assign are all either
-a string, an integer, or a boolean.  Boolean values may be given as yes/no,
-1/0, true/false or on/off.  Case is not significant in boolean values, when
-converting value to the canonical form using '--bool' type specifier;
-'git config' will ensure that the output is "true" or "false".
+A line that defines a value can be continued to the next line by
+ending it with a `\`; the backquote and the end-of-line are
+stripped.  Leading whitespaces after 'name =', the remainder of the
+line after the first comment character '#' or ';', and trailing
+whitespaces of the line are discarded unless they are enclosed in
+double quotes.  Internal whitespaces within the value are retained
+verbatim.
 
-String values may be entirely or partially enclosed in double quotes.
-You need to enclose variable values in double quotes if you want to
-preserve leading or trailing whitespace, or if the variable value contains
-comment characters (i.e. it contains '#' or ';').
-Double quote `"` and backslash `\` characters in variable values must
-be escaped: use `\"` for `"` and `\\` for `\`.
+Inside double quotes, double quote `"` and backslash `\` characters
+must be escaped: use `\"` for `"` and `\\` for `\`.
 
 The following escape sequences (beside `\"` and `\\`) are recognized:
 `\n` for newline character (NL), `\t` for horizontal tabulation (HT, TAB)
 and `\b` for backspace (BS).  Other char escape sequences (including octal
 escape sequences) are invalid.
 
-Variable values ending in a `\` are continued on the next line in the
-customary UNIX fashion.
-
-Some variables may require a special value format.
 
 Includes
 ~~~~~~~~
@@ -126,6 +116,60 @@ Example
                path = foo ; expand "foo" relative to the current file
                path = ~/foo ; expand "foo" in your $HOME directory
 
+
+Values
+~~~~~~
+
+Values of many variables are treated as a simple string, but there
+are variables that take values of specific types and there are rules
+as to how to spell them.
+
+boolean::
+
+       When a variable is said to take a boolean value, many
+       synonyms are accepted for 'true' and 'false'; these are all
+       case-insensitive.
+
+       true;; Boolean true can be spelled as `yes`, `on`, `true`,
+               or `1`.  Also, a variable defined without `= <value>`
+               is taken as true.
+
+       false;; Boolean false can be spelled as `no`, `off`,
+               `false`, or `0`.
++
+When converting value to the canonical form using '--bool' type
+specifier; 'git config' will ensure that the output is "true" or
+"false" (spelled in lowercase).
+
+integer::
+       The value for many variables that specify various sizes can
+       be suffixed with `k`, `M`,... to mean "scale the number by
+       1024", "by 1024x1024", etc.
+
+color::
+       The value for a variables that takes a color is a list of
+       colors (at most two) and attributes (at most one), separated
+       by spaces.  The colors accepted are `normal`, `black`,
+       `red`, `green`, `yellow`, `blue`, `magenta`, `cyan` and
+       `white`; the attributes are `bold`, `dim`, `ul`, `blink` and
+       `reverse`.  The first color given is the foreground; the
+       second is the background.  The position of the attribute, if
+       any, doesn't matter. Attributes may be turned off specifically
+       by prefixing them with `no` (e.g., `noreverse`, `noul`, etc).
++
+Colors (foreground and background) may also be given as numbers between
+0 and 255; these use ANSI 256-color mode (but note that not all
+terminals may support this).  If your terminal supports it, you may also
+specify 24-bit RGB values as hex, like `#ff0ab3`.
++
+The attributes are meant to be reset at the beginning of each item
+in the colored output, so setting color.decorate.branch to `black`
+will paint that branch name in a plain `black`, even if the previous
+thing on the same output line (e.g. opening parenthesis before the
+list of branch names in `log --decorate` output) is set to be
+painted with `bold` or some other attribute.
+
+
 Variables
 ~~~~~~~~~
 
@@ -225,7 +269,7 @@ See linkgit:git-update-index[1].
 +
 The default is true (when core.filemode is not specified in the config file).
 
-core.ignorecase::
+core.ignoreCase::
        If true, this option enables various workarounds to enable
        Git to work better on filesystems that are not case sensitive,
        like FAT. For example, if a directory listing finds
@@ -234,12 +278,12 @@ core.ignorecase::
        "Makefile".
 +
 The default is false, except linkgit:git-clone[1] or linkgit:git-init[1]
-will probe and set core.ignorecase true if appropriate when the repository
+will probe and set core.ignoreCase true if appropriate when the repository
 is created.
 
-core.precomposeunicode::
+core.precomposeUnicode::
        This option is only used by Mac OS implementation of Git.
-       When core.precomposeunicode=true, Git reverts the unicode decomposition
+       When core.precomposeUnicode=true, Git reverts the unicode decomposition
        of filenames done by Mac OS. This is useful when sharing a repository
        between Mac OS and Linux or Windows.
        (Git for Windows 1.7.10 or higher is needed, or Git under cygwin 1.7).
@@ -264,13 +308,13 @@ core.trustctime::
        crawlers and some backup systems).
        See linkgit:git-update-index[1]. True by default.
 
-core.checkstat::
+core.checkStat::
        Determines which stat fields to match between the index
        and work tree. The user can set this to 'default' or
        'minimal'. Default (or explicitly 'default'), is to check
        all fields, including the sub-second part of mtime and ctime.
 
-core.quotepath::
+core.quotePath::
        The commands that output paths (e.g. 'ls-files',
        'diff'), when not given the `-z` option, will quote
        "unusual" characters in the pathname by enclosing the
@@ -474,9 +518,9 @@ core.compression::
        -1 is the zlib default. 0 means no compression,
        and 1..9 are various speed/size tradeoffs, 9 being slowest.
        If set, this provides a default to other compression variables,
-       such as 'core.loosecompression' and 'pack.compression'.
+       such as 'core.looseCompression' and 'pack.compression'.
 
-core.loosecompression::
+core.looseCompression::
        An integer -1..9, indicating the compression level for objects that
        are not in a pack file. -1 is the zlib default. 0 means no
        compression, and 1..9 are various speed/size tradeoffs, 9 being
@@ -537,7 +581,7 @@ be delta compressed, but larger binary media files won't be.
 +
 Common unit suffixes of 'k', 'm', or 'g' are supported.
 
-core.excludesfile::
+core.excludesFile::
        In addition to '.gitignore' (per-directory) and
        '.git/info/exclude', Git looks into this file for patterns
        of files which are not meant to be tracked.  "`~/`" is expanded
@@ -546,7 +590,7 @@ core.excludesfile::
        If $XDG_CONFIG_HOME is either not set or empty, $HOME/.config/git/ignore
        is used instead. See linkgit:gitignore[5].
 
-core.askpass::
+core.askPass::
        Some commands (e.g. svn and http interfaces) that interactively
        ask for a password can be told to use an external program given
        via the value of this variable. Can be overridden by the 'GIT_ASKPASS'
@@ -555,11 +599,11 @@ core.askpass::
        prompt. The external program shall be given a suitable prompt as
        command-line argument and write the password on its STDOUT.
 
-core.attributesfile::
+core.attributesFile::
        In addition to '.gitattributes' (per-directory) and
        '.git/info/attributes', Git looks into this file for attributes
        (see linkgit:gitattributes[5]). Path expansions are made the same
-       way as for `core.excludesfile`. Its default value is
+       way as for `core.excludesFile`. Its default value is
        $XDG_CONFIG_HOME/git/attributes. If $XDG_CONFIG_HOME is either not
        set or empty, $HOME/.config/git/attributes is used instead.
 
@@ -569,7 +613,7 @@ core.editor::
        variable when it is set, and the environment variable
        `GIT_EDITOR` is not set.  See linkgit:git-var[1].
 
-core.commentchar::
+core.commentChar::
        Commands such as `commit` and `tag` that lets you edit
        messages consider a line that begins with this character
        commented, and removes them after the editor returns
@@ -638,7 +682,7 @@ core.whitespace::
   is relevant for `indent-with-non-tab` and when Git fixes `tab-in-indent`
   errors. The default tab width is 8. Allowed values are 1 to 63.
 
-core.fsyncobjectfiles::
+core.fsyncObjectFiles::
        This boolean will enable 'fsync()' when writing object files.
 +
 This is a total waste of time and effort on a filesystem that orders
@@ -646,7 +690,7 @@ data writes properly, but can be useful for filesystems that do not use
 journalling (traditional UNIX filesystems) or that only journal metadata
 and not file contents (OS X's HFS+, or Linux ext3 with "data=writeback").
 
-core.preloadindex::
+core.preloadIndex::
        Enable parallel index preload for operations like 'git diff'
 +
 This can speed up operations like 'git diff' and 'git status' especially
@@ -683,14 +727,13 @@ core.abbrev::
        for abbreviated object names to stay unique for sufficiently long
        time.
 
-add.ignore-errors::
 add.ignoreErrors::
+add.ignore-errors (deprecated)::
        Tells 'git add' to continue adding files when some files cannot be
        added due to indexing errors. Equivalent to the '--ignore-errors'
-       option of linkgit:git-add[1].  Older versions of Git accept only
-       `add.ignore-errors`, which does not follow the usual naming
-       convention for configuration variables.  Newer versions of Git
-       honor `add.ignoreErrors` as well.
+       option of linkgit:git-add[1].  `add.ignore-errors` is deprecated,
+       as it does not follow the usual naming convention for configuration
+       variables.
 
 alias.*::
        Command aliases for the linkgit:git[1] command wrapper - e.g.
@@ -718,7 +761,7 @@ am.keepcr::
        by giving '--no-keep-cr' from the command line.
        See linkgit:git-am[1], linkgit:git-mailsplit[1].
 
-apply.ignorewhitespace::
+apply.ignoreWhitespace::
        When set to 'change', tells 'git apply' to ignore changes in
        whitespace, in the same way as the '--ignore-space-change'
        option.
@@ -730,7 +773,7 @@ apply.whitespace::
        Tells 'git apply' how to handle whitespaces, in the same way
        as the '--whitespace' option. See linkgit:git-apply[1].
 
-branch.autosetupmerge::
+branch.autoSetupMerge::
        Tells 'git branch' and 'git checkout' to set up new branches
        so that linkgit:git-pull[1] will appropriately merge from the
        starting point branch. Note that even if this option is not set,
@@ -742,7 +785,7 @@ branch.autosetupmerge::
        local branch or remote-tracking
        branch. This option defaults to true.
 
-branch.autosetuprebase::
+branch.autoSetupRebase::
        When a new branch is created with 'git branch' or 'git checkout'
        that tracks another branch, this variable tells Git to set
        up pull to rebase instead of merge (see "branch.<name>.rebase").
@@ -753,27 +796,27 @@ branch.autosetuprebase::
        remote-tracking branches.
        When `always`, rebase will be set to true for all tracking
        branches.
-       See "branch.autosetupmerge" for details on how to set up a
+       See "branch.autoSetupMerge" for details on how to set up a
        branch to track another branch.
        This option defaults to never.
 
 branch.<name>.remote::
        When on branch <name>, it tells 'git fetch' and 'git push'
        which remote to fetch from/push to.  The remote to push to
-       may be overridden with `remote.pushdefault` (for all branches).
+       may be overridden with `remote.pushDefault` (for all branches).
        The remote to push to, for the current branch, may be further
-       overridden by `branch.<name>.pushremote`.  If no remote is
+       overridden by `branch.<name>.pushRemote`.  If no remote is
        configured, or if you are not on any branch, it defaults to
-       `origin` for fetching and `remote.pushdefault` for pushing.
+       `origin` for fetching and `remote.pushDefault` for pushing.
        Additionally, `.` (a period) is the current local repository
        (a dot-repository), see `branch.<name>.merge`'s final note below.
 
-branch.<name>.pushremote::
+branch.<name>.pushRemote::
        When on branch <name>, it overrides `branch.<name>.remote` for
-       pushing.  It also overrides `remote.pushdefault` for pushing
+       pushing.  It also overrides `remote.pushDefault` for pushing
        from branch <name>.  When you pull from one place (e.g. your
        upstream) and push to another place (e.g. your own publishing
-       repository), you would want to set `remote.pushdefault` to
+       repository), you would want to set `remote.pushDefault` to
        specify the remote to push to for all branches, and use this
        option to override it for a specific branch.
 
@@ -795,7 +838,7 @@ branch.<name>.merge::
        branch.<name>.merge to the desired branch, and use the relative path
        setting `.` (a period) for branch.<name>.remote.
 
-branch.<name>.mergeoptions::
+branch.<name>.mergeOptions::
        Sets default options for merging into branch <name>. The syntax and
        supported options are the same as those of linkgit:git-merge[1], but
        option values containing whitespace characters are currently not
@@ -847,20 +890,6 @@ color.branch.<slot>::
        `remote` (a remote-tracking branch in refs/remotes/),
        `upstream` (upstream tracking branch), `plain` (other
        refs).
-+
-The value for these configuration variables is a list of colors (at most
-two) and attributes (at most one), separated by spaces.  The colors
-accepted are `normal`, `black`, `red`, `green`, `yellow`, `blue`,
-`magenta`, `cyan` and `white`; the attributes are `bold`, `dim`, `ul`,
-`blink` and `reverse`.  The first color given is the foreground; the
-second is the background.  The position of the attribute, if any,
-doesn't matter. Attributes may be turned off specifically by prefixing
-them with `no` (e.g., `noreverse`, `noul`, etc).
-+
-Colors (foreground and background) may also be given as numbers between
-0 and 255; these use ANSI 256-color mode (but note that not all
-terminals may support this).  If your terminal supports it, you may also
-specify 24-bit RGB values as hex, like `#ff0ab3`.
 
 color.diff::
        Whether to use ANSI escape sequences to add color to patches.
@@ -880,8 +909,7 @@ color.diff.<slot>::
        of `plain` (context text), `meta` (metainformation), `frag`
        (hunk header), 'func' (function in hunk header), `old` (removed lines),
        `new` (added lines), `commit` (commit headers), or `whitespace`
-       (highlighting whitespace errors). The values of these variables may be
-       specified as in color.branch.<slot>.
+       (highlighting whitespace errors).
 
 color.decorate.<slot>::
        Use customized color for 'git log --decorate' output.  `<slot>` is one
@@ -918,8 +946,6 @@ color.grep.<slot>::
        separators between fields on a line (`:`, `-`, and `=`)
        and between hunks (`--`)
 --
-+
-The values of these variables may be specified as in color.branch.<slot>.
 
 color.interactive::
        When set to `always`, always use colors for interactive prompts
@@ -932,14 +958,13 @@ color.interactive.<slot>::
        Use customized color for 'git add --interactive' and 'git clean
        --interactive' output. `<slot>` may be `prompt`, `header`, `help`
        or `error`, for four distinct types of normal output from
-       interactive commands.  The values of these variables may be
-       specified as in color.branch.<slot>.
+       interactive commands.
 
 color.pager::
        A boolean to enable/disable colored output when the pager is in
        use (default is true).
 
-color.showbranch::
+color.showBranch::
        A boolean to enable/disable color in the output of
        linkgit:git-show-branch[1]. May be set to `always`,
        `false` (or `never`) or `auto` (or `true`), in which case colors are used
@@ -957,10 +982,10 @@ color.status.<slot>::
        `added` or `updated` (files which are added but not committed),
        `changed` (files which are changed but not added in the index),
        `untracked` (files which are not tracked by Git),
-       `branch` (the current branch), or
+       `branch` (the current branch),
        `nobranch` (the color the 'no branch' warning is shown in, defaulting
-       to red). The values of these variables may be specified as in
-       color.branch.<slot>.
+       to red), or
+       `unmerged` (files which have unmerged changes).
 
 color.ui::
        This variable determines the default value for variables such
@@ -1039,7 +1064,7 @@ commit.cleanup::
        have to remove the help lines that begin with `#` in the commit log
        template yourself, if you do this).
 
-commit.gpgsign::
+commit.gpgSign::
 
        A boolean to specify whether all commits should be GPG signed.
        Use of this option when doing operations such as rebase can
@@ -1152,7 +1177,7 @@ format.cc::
        by mail.  See the --to and --cc options in
        linkgit:git-format-patch[1].
 
-format.subjectprefix::
+format.subjectPrefix::
        The default for format-patch is to output files with the '[PATCH]'
        subject prefix. Use this variable to change that prefix.
 
@@ -1162,7 +1187,7 @@ format.signature::
        Set this variable to the empty string ("") to suppress
        signature generation.
 
-format.signaturefile::
+format.signatureFile::
        Works just like format.signature except the contents of the
        file specified by this variable will be used as the signature.
 
@@ -1186,7 +1211,7 @@ format.thread::
        A true boolean value is the same as `shallow`, and a false
        value disables threading.
 
-format.signoff::
+format.signOff::
        A boolean value which lets you enable the `-s/--signoff` option of
        format-patch by default. *Note:* Adding the Signed-off-by: line to a
        patch should be a conscious act and means that you certify you have
@@ -1225,17 +1250,17 @@ gc.auto::
        light-weight garbage collection from time to time.  The
        default value is 6700.  Setting this to 0 disables it.
 
-gc.autopacklimit::
+gc.autoPackLimit::
        When there are more than this many packs that are not
        marked with `*.keep` file in the repository, `git gc
        --auto` consolidates them into one larger pack.  The
        default value is 50.  Setting this to 0 disables it.
 
-gc.autodetach::
+gc.autoDetach::
        Make `git gc --auto` return immediately and run in background
        if the system supports it. Default is true.
 
-gc.packrefs::
+gc.packRefs::
        Running `git pack-refs` in a repository renders it
        unclonable by Git versions prior to 1.5.1.2 over dumb
        transports such as HTTP.  This variable determines whether
@@ -1243,38 +1268,38 @@ gc.packrefs::
        to enable it within all non-bare repos or it can be set to a
        boolean value.  The default is `true`.
 
-gc.pruneexpire::
+gc.pruneExpire::
        When 'git gc' is run, it will call 'prune --expire 2.weeks.ago'.
        Override the grace period with this config variable.  The value
        "now" may be used to disable this  grace period and always prune
        unreachable objects immediately.
 
-gc.reflogexpire::
-gc.<pattern>.reflogexpire::
+gc.reflogExpire::
+gc.<pattern>.reflogExpire::
        'git reflog expire' removes reflog entries older than
        this time; defaults to 90 days.  With "<pattern>" (e.g.
        "refs/stash") in the middle the setting applies only to
        the refs that match the <pattern>.
 
-gc.reflogexpireunreachable::
-gc.<ref>.reflogexpireunreachable::
+gc.reflogExpireUnreachable::
+gc.<ref>.reflogExpireUnreachable::
        'git reflog expire' removes reflog entries older than
        this time and are not reachable from the current tip;
        defaults to 30 days.  With "<pattern>" (e.g. "refs/stash")
        in the middle, the setting applies only to the refs that
        match the <pattern>.
 
-gc.rerereresolved::
+gc.rerereResolved::
        Records of conflicted merge you resolved earlier are
        kept for this many days when 'git rerere gc' is run.
        The default is 60 days.  See linkgit:git-rerere[1].
 
-gc.rerereunresolved::
+gc.rerereUnresolved::
        Records of conflicted merge you have not resolved are
        kept for this many days when 'git rerere gc' is run.
        The default is 15 days.  See linkgit:git-rerere[1].
 
-gitcvs.commitmsgannotation::
+gitcvs.commitMsgAnnotation::
        Append this string to each commit message. Set to empty string
        to disable this feature. Defaults to "via git-CVS emulator".
 
@@ -1282,7 +1307,7 @@ gitcvs.enabled::
        Whether the CVS server interface is enabled for this repository.
        See linkgit:git-cvsserver[1].
 
-gitcvs.logfile::
+gitcvs.logFile::
        Path to a log file where the CVS server interface well... logs
        various stuff. See linkgit:git-cvsserver[1].
 
@@ -1294,10 +1319,10 @@ gitcvs.usecrlfattr::
        treat it as text. If they suppress text conversion, the file
        will be set with '-kb' mode, which suppresses any newline munging
        the client might otherwise do. If the attributes do not allow
-       the file type to be determined, then 'gitcvs.allbinary' is
+       the file type to be determined, then 'gitcvs.allBinary' is
        used. See linkgit:gitattributes[5].
 
-gitcvs.allbinary::
+gitcvs.allBinary::
        This is used if 'gitcvs.usecrlfattr' does not resolve
        the correct '-kb' mode to use. If true, all
        unresolved files are sent to the client in
@@ -1307,7 +1332,7 @@ gitcvs.allbinary::
        then the contents of the file are examined to decide if
        it is binary, similar to 'core.autocrlf'.
 
-gitcvs.dbname::
+gitcvs.dbName::
        Database used by git-cvsserver to cache revision information
        derived from the Git repository. The exact meaning depends on the
        used database driver, for SQLite (which is the default driver) this
@@ -1315,7 +1340,7 @@ gitcvs.dbname::
        linkgit:git-cvsserver[1] for details). May not contain semicolons (`;`).
        Default: '%Ggitcvs.%m.sqlite'
 
-gitcvs.dbdriver::
+gitcvs.dbDriver::
        Used Perl DBI driver. You can specify any available driver
        for this here, but it might not work. git-cvsserver is tested
        with 'DBD::SQLite', reported to work with 'DBD::Pg', and
@@ -1323,10 +1348,10 @@ gitcvs.dbdriver::
        May not contain double colons (`:`). Default: 'SQLite'.
        See linkgit:git-cvsserver[1].
 
-gitcvs.dbuser, gitcvs.dbpass::
-       Database user and password. Only useful if setting 'gitcvs.dbdriver',
+gitcvs.dbUser, gitcvs.dbPass::
+       Database user and password. Only useful if setting 'gitcvs.dbDriver',
        since SQLite has no concept of database users and/or passwords.
-       'gitcvs.dbuser' supports variable substitution (see
+       'gitcvs.dbUser' supports variable substitution (see
        linkgit:git-cvsserver[1] for details).
 
 gitcvs.dbTableNamePrefix::
@@ -1337,7 +1362,7 @@ gitcvs.dbTableNamePrefix::
        characters will be replaced with underscores.
 
 All gitcvs variables except for 'gitcvs.usecrlfattr' and
-'gitcvs.allbinary' can also be specified as
+'gitcvs.allBinary' can also be specified as
 'gitcvs.<access_method>.<varname>' (where 'access_method'
 is one of "ext" and "pserver") to make them apply only for the given
 access method.
@@ -1355,7 +1380,7 @@ gitweb.highlight::
 gitweb.patches::
 gitweb.pickaxe::
 gitweb.remote_heads::
-gitweb.showsizes::
+gitweb.showSizes::
 gitweb.snapshot::
        See linkgit:gitweb.conf[5] for description.
 
@@ -1384,15 +1409,15 @@ gpg.program::
        signed, and the program is expected to send the result to its
        standard output.
 
-gui.commitmsgwidth::
+gui.commitMsgWidth::
        Defines how wide the commit message window is in the
        linkgit:git-gui[1]. "75" is the default.
 
-gui.diffcontext::
+gui.diffContext::
        Specifies how many context lines should be used in calls to diff
        made by the linkgit:git-gui[1]. The default is "5".
 
-gui.displayuntracked::
+gui.displayUntracked::
        Determines if linkgit::git-gui[1] shows untracked files
        in the file list. The default is "true".
 
@@ -1404,16 +1429,16 @@ gui.encoding::
        If this option is not set, the tools default to the
        locale encoding.
 
-gui.matchtrackingbranch::
+gui.matchTrackingBranch::
        Determines if new branches created with linkgit:git-gui[1] should
        default to tracking remote branches with matching names or
        not. Default: "false".
 
-gui.newbranchtemplate::
+gui.newBranchTemplate::
        Is used as suggested name when creating new branches using the
        linkgit:git-gui[1].
 
-gui.pruneduringfetch::
+gui.pruneDuringFetch::
        "true" if linkgit:git-gui[1] should prune remote-tracking branches when
        performing a fetch. The default value is "false".
 
@@ -1421,17 +1446,17 @@ gui.trustmtime::
        Determines if linkgit:git-gui[1] should trust the file modification
        timestamp or not. By default the timestamps are not trusted.
 
-gui.spellingdictionary::
+gui.spellingDictionary::
        Specifies the dictionary used for spell checking commit messages in
        the linkgit:git-gui[1]. When set to "none" spell checking is turned
        off.
 
-gui.fastcopyblame::
+gui.fastCopyBlame::
        If true, 'git gui blame' uses `-C` instead of `-C -C` for original
        location detection. It makes blame significantly faster on huge
        repositories at the expense of less thorough copy detection.
 
-gui.copyblamethreshold::
+gui.copyBlameThreshold::
        Specifies the threshold to use in 'git gui blame' original location
        detection, measured in alphanumeric characters. See the
        linkgit:git-blame[1] manual for more information on copy detection.
@@ -1451,22 +1476,22 @@ guitool.<name>.cmd::
        'FILENAME', and the name of the current branch as 'CUR_BRANCH' (if
        the head is detached, 'CUR_BRANCH' is empty).
 
-guitool.<name>.needsfile::
+guitool.<name>.needsFile::
        Run the tool only if a diff is selected in the GUI. It guarantees
        that 'FILENAME' is not empty.
 
-guitool.<name>.noconsole::
+guitool.<name>.noConsole::
        Run the command silently, without creating a window to display its
        output.
 
-guitool.<name>.norescan::
+guitool.<name>.noRescan::
        Don't rescan the working directory for changes after the tool
        finishes execution.
 
 guitool.<name>.confirm::
        Show a confirmation dialog before actually running the tool.
 
-guitool.<name>.argprompt::
+guitool.<name>.argPrompt::
        Request a string argument from the user, and pass it to the tool
        through the 'ARGS' environment variable. Since requesting an
        argument implies confirmation, the 'confirm' option has no effect
@@ -1474,13 +1499,13 @@ guitool.<name>.argprompt::
        the dialog uses a built-in generic prompt; otherwise the exact
        value of the variable is used.
 
-guitool.<name>.revprompt::
+guitool.<name>.revPrompt::
        Request a single valid revision from the user, and set the
        'REVISION' environment variable. In other aspects this option
-       is similar to 'argprompt', and can be used together with it.
+       is similar to 'argPrompt', and can be used together with it.
 
-guitool.<name>.revunmerged::
-       Show only unmerged branches in the 'revprompt' subdialog.
+guitool.<name>.revUnmerged::
+       Show only unmerged branches in the 'revPrompt' subdialog.
        This is useful for tools similar to merge or rebase, but not
        for things like checkout or reset.
 
@@ -1490,7 +1515,7 @@ guitool.<name>.title::
 
 guitool.<name>.prompt::
        Specifies the general prompt string to display at the top of
-       the dialog, before subsections for 'argprompt' and 'revprompt'.
+       the dialog, before subsections for 'argPrompt' and 'revPrompt'.
        The default value includes the actual command.
 
 help.browser::
@@ -1502,7 +1527,7 @@ help.format::
        Values 'man', 'info', 'web' and 'html' are supported. 'man' is
        the default. 'web' and 'html' are the same.
 
-help.autocorrect::
+help.autoCorrect::
        Automatically correct and execute mistyped commands after
        waiting for the given number of deciseconds (0.1 sec). If more
        than one command can be deduced from the entered text, nothing
@@ -1511,7 +1536,7 @@ help.autocorrect::
        value is 0 - the command will be just shown but not executed.
        This is the default.
 
-help.htmlpath::
+help.htmlPath::
        Specify the path where the HTML documentation resides. File system paths
        and URLs are supported. HTML pages will be prefixed with this path when
        help is displayed in the 'web' format. This defaults to the documentation
@@ -1523,17 +1548,17 @@ http.proxy::
        `curl(1)`).  This can be overridden on a per-remote basis; see
        remote.<name>.proxy
 
-http.cookiefile::
+http.cookieFile::
        File containing previously stored cookie lines which should be used
        in the Git http session, if they match the server. The file format
        of the file to read cookies from should be plain HTTP headers or
        the Netscape/Mozilla cookie file format (see linkgit:curl[1]).
-       NOTE that the file specified with http.cookiefile is only used as
+       NOTE that the file specified with http.cookieFile is only used as
        input unless http.saveCookies is set.
 
-http.savecookies::
+http.saveCookies::
        If set, store cookies received during requests to the file specified by
-       http.cookiefile. Has no effect if http.cookiefile is unset.
+       http.cookieFile. Has no effect if http.cookieFile is unset.
 
 http.sslVerify::
        Whether to verify the SSL certificate when fetching or pushing
@@ -1604,7 +1629,7 @@ http.noEPSV::
        support EPSV mode. Can be overridden by the 'GIT_CURL_FTP_NO_EPSV'
        environment variable. Default is false (curl will use EPSV).
 
-http.useragent::
+http.userAgent::
        The HTTP USER_AGENT string presented to an HTTP server.  The default
        value represents the version of the client Git such as git/1.7.1.
        This option allows you to override this value to a more common value
@@ -1677,7 +1702,7 @@ index.version::
        Specify the version with which new index files should be
        initialized.  This does not affect existing repositories.
 
-init.templatedir::
+init.templateDir::
        Specify the directory from which templates will be copied.
        (See the "TEMPLATE DIRECTORY" section of linkgit:git-init[1].)
 
@@ -1693,7 +1718,7 @@ instaweb.local::
        If true the web server started by linkgit:git-instaweb[1] will
        be bound to the local IP (127.0.0.1).
 
-instaweb.modulepath::
+instaweb.modulePath::
        The default module path for linkgit:git-instaweb[1] to use
        instead of /usr/lib/apache2/modules.  Only used if httpd
        is Apache.
@@ -1702,7 +1727,7 @@ instaweb.port::
        The port number to bind the gitweb httpd to. See
        linkgit:git-instaweb[1].
 
-interactive.singlekey::
+interactive.singleKey::
        In interactive commands, allow the user to provide one-letter
        input with a single key (i.e., without hitting enter).
        Currently this is used by the `--patch` mode of
@@ -1730,7 +1755,7 @@ log.decorate::
        specified, the full ref name (including prefix) will be printed.
        This is the same as the log commands '--decorate' option.
 
-log.showroot::
+log.showRoot::
        If true, the initial commit will be shown as a big creation event.
        This is equivalent to a diff against an empty tree.
        Tools like linkgit:git-log[1] or linkgit:git-whatchanged[1], which
@@ -1740,6 +1765,13 @@ log.mailmap::
        If true, makes linkgit:git-log[1], linkgit:git-show[1], and
        linkgit:git-whatchanged[1] assume `--use-mailmap`.
 
+mailinfo.scissors::
+       If true, makes linkgit:git-mailinfo[1] (and therefore
+       linkgit:git-am[1]) act by default as if the --scissors option
+       was provided on the command-line. When active, this features
+       removes everything from the message body before a scissors
+       line (i.e. consisting mainly of ">8", "8<" and "-").
+
 mailmap.file::
        The location of an augmenting mailmap file. The default
        mailmap, located in the root of the repository, is loaded
@@ -1960,7 +1992,7 @@ pack.useBitmaps::
        true. You should not generally need to turn this off unless
        you are debugging pack bitmaps.
 
-pack.writebitmaps::
+pack.writeBitmaps (deprecated)::
        This is a deprecated synonym for `repack.writeBitmaps`.
 
 pack.writeBitmapHashCache::
@@ -2089,10 +2121,10 @@ rebase.stat::
        Whether to show a diffstat of what changed upstream since the last
        rebase. False by default.
 
-rebase.autosquash::
+rebase.autoSquash::
        If set to true enable '--autosquash' option by default.
 
-rebase.autostash::
+rebase.autoStash::
        When set to true, automatically create a temporary stash
        before the operation begins, and apply it after the operation
        ends.  This means that you can run rebase on a dirty worktree.
@@ -2100,7 +2132,7 @@ rebase.autostash::
        successful rebase might result in non-trivial conflicts.
        Defaults to false.
 
-receive.advertiseatomic::
+receive.advertiseAtomic::
        By default, git-receive-pack will advertise the atomic push
        capability to its clients. If you don't want to this capability
        to be advertised, set this variable to false.
@@ -2110,13 +2142,13 @@ receive.autogc::
        receiving data from git-push and updating refs.  You can stop
        it by setting this variable to false.
 
-receive.certnonceseed::
+receive.certNonceSeed::
        By setting this variable to a string, `git receive-pack`
        will accept a `git push --signed` and verifies it by using
        a "nonce" protected by HMAC using this string as a secret
        key.
 
-receive.certnonceslop::
+receive.certNonceSlop::
        When a `git push --signed` sent a push certificate with a
        "nonce" that was issued by a receive-pack serving the same
        repository within this many seconds, export the "nonce"
@@ -2180,7 +2212,7 @@ receive.denyNonFastForwards::
        even if that push is forced. This configuration variable is
        set when initializing a shared repository.
 
-receive.hiderefs::
+receive.hideRefs::
        String(s) `receive-pack` uses to decide which refs to omit
        from its initial advertisement.  Use more than one
        definitions to specify multiple prefix strings. A ref that
@@ -2189,18 +2221,18 @@ receive.hiderefs::
        push`, and an attempt to update or delete a hidden ref by
        `git push` is rejected.
 
-receive.updateserverinfo::
+receive.updateServerInfo::
        If set to true, git-receive-pack will run git-update-server-info
        after receiving data from git-push and updating refs.
 
-receive.shallowupdate::
+receive.shallowUpdate::
        If set to true, .git/shallow can be updated when new refs
        require new shallow roots. Otherwise those refs are rejected.
 
-remote.pushdefault::
+remote.pushDefault::
        The remote to push to by default.  Overrides
        `branch.<name>.remote` for all branches, and is overridden by
-       `branch.<name>.pushremote` for specific branches.
+       `branch.<name>.pushRemote` for specific branches.
 
 remote.<name>.url::
        The URL of a remote repository.  See linkgit:git-fetch[1] or
@@ -2244,7 +2276,7 @@ remote.<name>.uploadpack::
        The default program to execute on the remote side when fetching.  See
        option \--upload-pack of linkgit:git-fetch-pack[1].
 
-remote.<name>.tagopt::
+remote.<name>.tagOpt::
        Setting this value to \--no-tags disables automatic tag following when
        fetching from remote <name>. Setting it to \--tags will fetch every
        tag from remote <name>, even if they are not reachable from remote
@@ -2266,7 +2298,7 @@ remotes.<group>::
        The list of remotes which are fetched by "git remote update
        <group>".  See linkgit:git-remote[1].
 
-repack.usedeltabaseoffset::
+repack.useDeltaBaseOffset::
        By default, linkgit:git-repack[1] creates packs that use
        delta-base offset. If you need to share your repository with
        Git older than version 1.4.4, either directly or via a dumb
@@ -2289,7 +2321,7 @@ repack.writeBitmaps::
        space and extra time spent on the initial repack.  Defaults to
        false.
 
-rerere.autoupdate::
+rerere.autoUpdate::
        When set to true, `git-rerere` updates the index with the
        resulting contents after it cleanly resolves conflicts using
        previously recorded resolution.  Defaults to false.
@@ -2308,12 +2340,12 @@ sendemail.identity::
        values in the 'sendemail' section. The default identity is
        the value of 'sendemail.identity'.
 
-sendemail.smtpencryption::
+sendemail.smtpEncryption::
        See linkgit:git-send-email[1] for description.  Note that this
        setting is not subject to the 'identity' mechanism.
 
-sendemail.smtpssl::
-       Deprecated alias for 'sendemail.smtpencryption = ssl'.
+sendemail.smtpssl (deprecated)::
+       Deprecated alias for 'sendemail.smtpEncryption = ssl'.
 
 sendemail.smtpsslcertpath::
        Path to ca-certificates (either a directory or a single file).
@@ -2325,34 +2357,34 @@ sendemail.<identity>.*::
        identity is selected, through command-line or
        'sendemail.identity'.
 
-sendemail.aliasesfile::
-sendemail.aliasfiletype::
+sendemail.aliasesFile::
+sendemail.aliasFileType::
 sendemail.annotate::
 sendemail.bcc::
 sendemail.cc::
-sendemail.cccmd::
-sendemail.chainreplyto::
+sendemail.ccCmd::
+sendemail.chainReplyTo::
 sendemail.confirm::
-sendemail.envelopesender::
+sendemail.envelopeSender::
 sendemail.from::
-sendemail.multiedit::
+sendemail.multiEdit::
 sendemail.signedoffbycc::
-sendemail.smtppass::
+sendemail.smtpPass::
 sendemail.suppresscc::
-sendemail.suppressfrom::
+sendemail.suppressFrom::
 sendemail.to::
-sendemail.smtpdomain::
-sendemail.smtpserver::
-sendemail.smtpserverport::
-sendemail.smtpserveroption::
-sendemail.smtpuser::
+sendemail.smtpDomain::
+sendemail.smtpServer::
+sendemail.smtpServerPort::
+sendemail.smtpServerOption::
+sendemail.smtpUser::
 sendemail.thread::
-sendemail.transferencoding::
+sendemail.transferEncoding::
 sendemail.validate::
 sendemail.xmailer::
        See linkgit:git-send-email[1] for description.
 
-sendemail.signedoffcc::
+sendemail.signedoffcc (deprecated)::
        Deprecated alias for 'sendemail.signedoffbycc'.
 
 showbranch.default::
@@ -2399,7 +2431,7 @@ If this variable is not specified, it defaults to 'normal'.
 This variable can be overridden with the -u|--untracked-files option
 of linkgit:git-status[1] and linkgit:git-commit[1].
 
-status.submodulesummary::
+status.submoduleSummary::
        Defaults to false.
        If this is set to a non zero number or true (identical to -1 or an
        unlimited number), the submodule summary will be enabled and a
@@ -2417,12 +2449,16 @@ status.submodulesummary::
 
 submodule.<name>.path::
 submodule.<name>.url::
+       The path within this project and URL for a submodule. These
+       variables are initially populated by 'git submodule init'. See
+       linkgit:git-submodule[1] and linkgit:gitmodules[5] for
+       details.
+
 submodule.<name>.update::
-       The path within this project, URL, and the updating strategy
-       for a submodule.  These variables are initially populated
-       by 'git submodule init'; edit them to override the
-       URL and other values found in the `.gitmodules` file.  See
-       linkgit:git-submodule[1] and linkgit:gitmodules[5] for details.
+       The default update procedure for a submodule. This variable
+       is populated by `git submodule init` from the
+       linkgit:gitmodules[5] file. See description of 'update'
+       command in linkgit:git-submodule[1].
 
 submodule.<name>.branch::
        The remote branch name for a submodule, used by `git submodule
@@ -2470,9 +2506,9 @@ transfer.fsckObjects::
        not set, the value of this variable is used instead.
        Defaults to false.
 
-transfer.hiderefs::
-       This variable can be used to set both `receive.hiderefs`
-       and `uploadpack.hiderefs` at the same time to the same
+transfer.hideRefs::
+       This variable can be used to set both `receive.hideRefs`
+       and `uploadpack.hideRefs` at the same time to the same
        values.  See entries for these other variables.
 
 transfer.unpackLimit::
@@ -2487,7 +2523,7 @@ uploadarchive.allowUnreachable::
        linkgit:git-upload-archive[1] for more details. Defaults to
        `false`.
 
-uploadpack.hiderefs::
+uploadpack.hideRefs::
        String(s) `upload-pack` uses to decide which refs to omit
        from its initial advertisement.  Use more than one
        definitions to specify multiple prefix strings. A ref that
@@ -2497,12 +2533,12 @@ uploadpack.hiderefs::
        fetch` will fail.  See also `uploadpack.allowtipsha1inwant`.
 
 uploadpack.allowtipsha1inwant::
-       When `uploadpack.hiderefs` is in effect, allow `upload-pack`
+       When `uploadpack.hideRefs` is in effect, allow `upload-pack`
        to accept a fetch request that asks for an object at the tip
        of a hidden ref (by default, such a request is rejected).
-       see also `uploadpack.hiderefs`.
+       see also `uploadpack.hideRefs`.
 
-uploadpack.keepalive::
+uploadpack.keepAlive::
        When `upload-pack` has started `pack-objects`, there may be a
        quiet period while `pack-objects` prepares the pack. Normally
        it would output progress information, but if `--quiet` was used
@@ -2510,7 +2546,7 @@ uploadpack.keepalive::
        the pack data begins. Some clients and networks may consider
        the server to be hung and give up. Setting this option instructs
        `upload-pack` to send an empty keepalive packet every
-       `uploadpack.keepalive` seconds. Setting this option to 0
+       `uploadpack.keepAlive` seconds. Setting this option to 0
        disables keepalive packets entirely. The default is 5 seconds.
 
 url.<base>.insteadOf::
@@ -2547,13 +2583,25 @@ user.name::
        Can be overridden by the 'GIT_AUTHOR_NAME' and 'GIT_COMMITTER_NAME'
        environment variables.  See linkgit:git-commit-tree[1].
 
-user.signingkey::
+user.signingKey::
        If linkgit:git-tag[1] or linkgit:git-commit[1] is not selecting the
        key you want it to automatically when creating a signed tag or
        commit, you can override the default selection with this variable.
        This option is passed unchanged to gpg's --local-user parameter,
        so you may specify a key using any method that gpg supports.
 
+versionsort.prereleaseSuffix::
+       When version sort is used in linkgit:git-tag[1], prerelease
+       tags (e.g. "1.0-rc1") may appear after the main release
+       "1.0". By specifying the suffix "-rc" in this variable,
+       "1.0-rc1" will appear before "1.0".
++
+This variable can be specified multiple times, once per suffix. The
+order of suffixes in the config file determines the sorting order
+(e.g. if "-pre" appears before "-rc" in the config file then 1.0-preXX
+is sorted before 1.0-rcXX). The sorting order between different
+suffixes is undefined if they are in multiple config files.
+
 web.browser::
        Specify a web browser that may be used by some commands.
        Currently only linkgit:git-instaweb[1] and linkgit:git-help[1]
index b0017795208d971eb40001ff20bd2516c8d9a58e..6eaa45271c9ff2d1200e4299c3040d52952a2ec4 100644 (file)
@@ -1,4 +1,4 @@
-diff.autorefreshindex::
+diff.autoRefreshIndex::
        When using 'git diff' to compare with work tree
        files, do not consider stat-only change as changed.
        Instead, silently run `git update-index --refresh` to
@@ -75,11 +75,11 @@ diff.ignoreSubmodules::
        commands such as 'git diff-files'. 'git checkout' also honors
        this setting when reporting uncommitted changes. Setting it to
        'all' disables the submodule summary normally shown by 'git commit'
-       and 'git status' when 'status.submodulesummary' is set unless it is
+       and 'git status' when 'status.submoduleSummary' is set unless it is
        overridden by using the --ignore-submodules command-line option.
        The 'git submodule' commands are not affected by this setting.
 
-diff.mnemonicprefix::
+diff.mnemonicPrefix::
        If set, 'git diff' uses a prefix pair that is different from the
        standard "a/" and "b/" depending on what is being compared.  When
        this configuration is in effect, reverse diff output also swaps
@@ -98,7 +98,7 @@ diff.mnemonicprefix::
 diff.noprefix::
        If set, 'git diff' does not show any source or destination prefix.
 
-diff.orderfile::
+diff.orderFile::
        File indicating how to order files within a diff, using
        one shell glob pattern per line.
        Can be overridden by the '-O' option to linkgit:git-diff[1].
@@ -148,7 +148,7 @@ diff.<driver>.textconv::
        conversion is used to generate a human-readable diff.  See
        linkgit:gitattributes[5] for details.
 
-diff.<driver>.wordregex::
+diff.<driver>.wordRegex::
        The regular expression that the diff driver should use to
        split words in a line.  See linkgit:gitattributes[5] for
        details.
index 15c7e794f4adaccb8885683946a9f4e7e4dc92c2..85b08909ce25acc5f9deae9a3e0ade2bd679bc94 100644 (file)
@@ -66,7 +66,8 @@ be committed)
 
 Status letters C and R are always followed by a score (denoting the
 percentage of similarity between the source and target of the move or
-copy), and are the only ones to be so.
+copy).  Status letter M may be followed by a score (denoting the
+percentage of dissimilarity) for file rewrites.
 
 <sha1> is shown as all 0's if a file is new on the filesystem
 and it is out of sync with the index.
index 6cb083aae58018084c8da689bf2bfe5ccc136de5..ccd499867b64d0609df66196f833fff173dd60da 100644 (file)
@@ -432,8 +432,8 @@ endif::git-format-patch[]
 -O<orderfile>::
        Output the patch in the order specified in the
        <orderfile>, which has one shell glob pattern per line.
-       This overrides the `diff.orderfile` configuration variable
-       (see linkgit:git-config[1]).  To cancel `diff.orderfile`,
+       This overrides the `diff.orderFile` configuration variable
+       (see linkgit:git-config[1]).  To cancel `diff.orderFile`,
        use `-O/dev/null`.
 
 ifndef::git-format-patch[]
index b09a783ee313bf67cb07db03bb3127d252ab70c3..45583d8454b4cae9bdb2ddb904c077cf1d3a1223 100644 (file)
@@ -68,7 +68,7 @@ endif::git-pull[]
        By default, tags that point at objects that are downloaded
        from the remote repository are fetched and stored locally.
        This option disables this automatic tag following. The default
-       behavior for a remote may be specified with the remote.<name>.tagopt
+       behavior for a remote may be specified with the remote.<name>.tagOpt
        setting. See linkgit:git-config[1].
 
 ifndef::git-pull[]
index 1c74907dd4c9021f41d88cf9f766c4855c0d6f97..f2eb9076d73d830c19dc70bf2175e55a46ae1111 100644 (file)
@@ -173,7 +173,7 @@ for "git add --no-all <pathspec>...", i.e. ignored removed files.
 Configuration
 -------------
 
-The optional configuration variable `core.excludesfile` indicates a path to a
+The optional configuration variable `core.excludesFile` indicates a path to a
 file containing patterns of file names to exclude from git-add, similar to
 $GIT_DIR/info/exclude.  Patterns in the exclude file are used in addition to
 those in info/exclude.  See linkgit:gitignore[5].
@@ -317,7 +317,7 @@ After deciding the fate for all hunks, if there is any hunk
 that was chosen, the index is updated with the selected hunks.
 +
 You can omit having to type return here, by setting the configuration
-variable `interactive.singlekey` to `true`.
+variable `interactive.singleKey` to `true`.
 
 diff::
 
index f4eea28dc4d03e02f9af3eedba5d15743b8553f6..0d8ba48f792ae82237a56aa0dd2aca03f4e16020 100644 (file)
@@ -52,7 +52,8 @@ OPTIONS
 -c::
 --scissors::
        Remove everything in body before a scissors line (see
-       linkgit:git-mailinfo[1]).
+       linkgit:git-mailinfo[1]). Can be activated by default using
+       the `mailinfo.scissors` configuration variable.
 
 --no-scissors::
        Ignore scissors lines (see linkgit:git-mailinfo[1]).
index f605327946f1bc72a62a6129d7e783162853ad51..d9ed6a1a4ea6dc0068144eac4c5e0f5ef33a04cb 100644 (file)
@@ -16,7 +16,7 @@ SYNOPSIS
          [--ignore-space-change | --ignore-whitespace ]
          [--whitespace=(nowarn|warn|fix|error|error-all)]
          [--exclude=<path>] [--include=<path>] [--directory=<root>]
-         [--verbose] [<patch>...]
+         [--verbose] [--unsafe-paths] [<patch>...]
 
 DESCRIPTION
 -----------
@@ -229,10 +229,20 @@ For example, a patch that talks about updating `a/git-gui.sh` to `b/git-gui.sh`
 can be applied to the file in the working tree `modules/git-gui/git-gui.sh` by
 running `git apply --directory=modules/git-gui`.
 
+--unsafe-paths::
+       By default, a patch that affects outside the working area
+       (either a Git controlled working tree, or the current working
+       directory when "git apply" is used as a replacement of GNU
+       patch) is rejected as a mistake (or a mischief).
++
+When `git apply` is used as a "better GNU patch", the user can pass
+the `--unsafe-paths` option to override this safety check.  This option
+has no effect when `--index` or `--cached` is in use.
+
 Configuration
 -------------
 
-apply.ignorewhitespace::
+apply.ignoreWhitespace::
        Set to 'change' if you want changes in whitespace to be ignored by default.
        Set to one of: no, none, never, false if you want changes in
        whitespace to be significant.
index 311b33674eb2bda2c8e0bd5d2de4499a156b1719..359619b5527a8211c71eca029d0341b7fe6d548f 100644 (file)
@@ -51,7 +51,7 @@ When a local branch is started off a remote-tracking branch, Git sets up the
 branch (specifically the `branch.<name>.remote` and `branch.<name>.merge`
 configuration entries) so that 'git pull' will appropriately merge from
 the remote-tracking branch. This behavior may be changed via the global
-`branch.autosetupmerge` configuration flag. That setting can be
+`branch.autoSetupMerge` configuration flag. That setting can be
 overridden by using the `--track` and `--no-track` options, and
 changed later using `git branch --set-upstream-to`.
 
@@ -166,14 +166,14 @@ This option is only applicable in non-verbose mode.
        upstream when the new branch is checked out.
 +
 This behavior is the default when the start point is a remote-tracking branch.
-Set the branch.autosetupmerge configuration variable to `false` if you
+Set the branch.autoSetupMerge configuration variable to `false` if you
 want `git checkout` and `git branch` to always behave as if '--no-track'
 were given. Set it to `always` if you want this behavior when the
 start-point is either a local or remote-tracking branch.
 
 --no-track::
        Do not set up "upstream" configuration, even if the
-       branch.autosetupmerge configuration variable is true.
+       branch.autoSetupMerge configuration variable is true.
 
 --set-upstream::
        If specified branch does not exist yet or if `--force` has been
index 788a0115805214f4169c50279d94cd31e5f0becc..e35cd0489b6961a5322ea49eeb769bbfb883070e 100644 (file)
@@ -72,7 +72,7 @@ matching pattern, <source> is the pattern's source file, and <linenum>
 is the line number of the pattern within that source.  If the pattern
 contained a `!` prefix or `/` suffix, it will be preserved in the
 output.  <source> will be an absolute path when referring to the file
-configured by `core.excludesfile`, or relative to the repository root
+configured by `core.excludesFile`, or relative to the repository root
 when referring to `.git/info/exclude` or a per-directory exclude file.
 
 If `-z` is specified, the pathnames in the output are delimited by the
index 33ad2adf5ce86119e55f94fa1d29233e8caf4a67..d5041082e88349d7c814ae1c036b15841f47a6d0 100644 (file)
@@ -144,7 +144,7 @@ explicitly give a name with '-b' in such a case.
 
 --no-track::
        Do not set up "upstream" configuration, even if the
-       branch.autosetupmerge configuration variable is true.
+       branch.autoSetupMerge configuration variable is true.
 
 -l::
        Create the new branch's reflog; see linkgit:git-branch[1] for
@@ -210,7 +210,7 @@ the conflicted merge in the specified paths.
 --conflict=<style>::
        The same as --merge option above, but changes the way the
        conflicting hunks are presented, overriding the
-       merge.conflictstyle configuration variable.  Possible values are
+       merge.conflictStyle configuration variable.  Possible values are
        "merge" (default) and "diff3" (in addition to what is shown by
        "merge" style, shows the original contents).
 
index 94b6d19cf2a658a9258ee54b141b4eb9b1a6cae3..641681f61ad360fcfd5aa98f81a9e3d49c44c8a7 100644 (file)
@@ -34,8 +34,12 @@ OPTIONS
 -f::
 --force::
        If the Git configuration variable clean.requireForce is not set
-       to false, 'git clean' will refuse to run unless given -f, -n or
-       -i.
+       to false, 'git clean' will refuse to delete files or directories
+       unless given -f, -n or -i. Git will refuse to delete directories
+       with .git sub directory or file unless a second -f
+       is given. This affects also git submodules where the storage area
+       of the removed submodule under .git/modules/ is not removed until
+       -f is given twice.
 
 -i::
 --interactive::
index a469eab06683dece65f447a6c2691c30fe54b214..f5f2a8d326502714299cf85d9819bb065d5af390 100644 (file)
@@ -59,7 +59,7 @@ OPTIONS
        GPG-sign commit.
 
 --no-gpg-sign::
-       Countermand `commit.gpgsign` configuration variable that is
+       Countermand `commit.gpgSign` configuration variable that is
        set to force each and every commit to be signed.
 
 
index 1e74b75d383838b3828f3fee20750c399d77cba0..617e29b38b337a40d8aede609d9d979c1b3aac02 100644 (file)
@@ -284,6 +284,10 @@ configuration variable documented in linkgit:git-config[1].
        would be committed at the bottom of the commit message
        template.  Note that this diff output doesn't have its
        lines prefixed with '#'.
++
+If specified twice, show in addition the unified diff between
+what would be committed and the worktree files, i.e. the unstaged
+changes to tracked files.
 
 -q::
 --quiet::
@@ -310,7 +314,7 @@ configuration variable documented in linkgit:git-config[1].
        GPG-sign commit.
 
 --no-gpg-sign::
-       Countermand `commit.gpgsign` configuration variable that is
+       Countermand `commit.gpgSign` configuration variable that is
        set to force each and every commit to be signed.
 
 \--::
index 9dfa1a5ce265eacd64febc3775cb05525b58d7f0..02ec096faac77acace9b36d60e6b1889ac18e85e 100644 (file)
@@ -405,7 +405,7 @@ true
 % git config --bool --get-urlmatch http.sslverify https://weak.example.com
 false
 % git config --get-urlmatch http https://weak.example.com
-http.cookiefile /tmp/cookie.txt
+http.cookieFile /tmp/cookie.txt
 http.sslverify false
 ------------
 
index 4961f1abdaa8b54e9af2beae6233eaa6fd0dc9db..db4d7a917c5b375487df01816bac36ff30dff7c7 100644 (file)
@@ -154,7 +154,7 @@ with CVS_SERVER (and shouldn't) as 'git-shell' understands `cvs` to mean
    [gitcvs]
         enabled=1
         # optional for debugging
-        logfile=/path/to/logfile
+       logFile=/path/to/logfile
 
 ------
 Note: you need to ensure each user that is going to invoke 'git-cvsserver' has
@@ -254,14 +254,14 @@ Configuring database backend
 its documentation if changing these variables, especially
 about `DBI->connect()`.
 
-gitcvs.dbname::
+gitcvs.dbName::
        Database name. The exact meaning depends on the
        selected database driver, for SQLite this is a filename.
        Supports variable substitution (see below). May
        not contain semicolons (`;`).
        Default: '%Ggitcvs.%m.sqlite'
 
-gitcvs.dbdriver::
+gitcvs.dbDriver::
        Used DBI driver. You can specify any available driver
        for this here, but it might not work. cvsserver is tested
        with 'DBD::SQLite', reported to work with
@@ -271,12 +271,12 @@ gitcvs.dbdriver::
        Default: 'SQLite'
 
 gitcvs.dbuser::
-       Database user. Only useful if setting `dbdriver`, since
+       Database user. Only useful if setting `dbDriver`, since
        SQLite has no concept of database users. Supports variable
        substitution (see below).
 
-gitcvs.dbpass::
-       Database password.  Only useful if setting `dbdriver`, since
+gitcvs.dbPass::
+       Database password.  Only useful if setting `dbDriver`, since
        SQLite has no concept of database passwords.
 
 gitcvs.dbTableNamePrefix::
@@ -288,7 +288,7 @@ All variables can also be set per access method, see <<configaccessmethod,above>
 
 Variable substitution
 ^^^^^^^^^^^^^^^^^^^^^
-In `dbdriver` and `dbuser` you can use the following variables:
+In `dbDriver` and `dbUser` you can use the following variables:
 
 %G::
        Git directory name
@@ -413,16 +413,16 @@ about end-of-line conversion.
 
 Alternatively, if `gitcvs.usecrlfattr` config is not enabled
 or the attributes do not allow automatic detection for a filename, then
-the server uses the `gitcvs.allbinary` config for the default setting.
-If `gitcvs.allbinary` is set, then file not otherwise
+the server uses the `gitcvs.allBinary` config for the default setting.
+If `gitcvs.allBinary` is set, then file not otherwise
 specified will default to '-kb' mode. Otherwise the '-k' mode
-is left blank. But if `gitcvs.allbinary` is set to "guess", then
+is left blank. But if `gitcvs.allBinary` is set to "guess", then
 the correct '-k' mode will be guessed based on the contents of
 the file.
 
 For best consistency with 'cvs', it is probably best to override the
 defaults by setting `gitcvs.usecrlfattr` to true,
-and `gitcvs.allbinary` to "guess".
+and `gitcvs.allBinary` to "guess".
 
 Dependencies
 ------------
index 8deb61469d9cbd8786c27567851158c90c31aa8a..e62d9a0717f0d383535159c7d522bfb303855160 100644 (file)
@@ -26,7 +26,7 @@ By default, any tag that points into the histories being fetched is
 also fetched; the effect is to fetch tags that
 point at branches that you are interested in.  This default behavior
 can be changed by using the --tags or --no-tags options or by
-configuring remote.<name>.tagopt.  By using a refspec that fetches tags
+configuring remote.<name>.tagOpt.  By using a refspec that fetches tags
 explicitly, you can fetch tags that do not point into branches you
 are interested in as well.
 
index c0fd470da42991404c722f45ee7ac48cd774287b..bb3ea9372f873ee50c3c6fb4092cd95ebbba3312 100644 (file)
@@ -273,13 +273,13 @@ attachments, and sign off patches with configuration variables.
 ------------
 [format]
        headers = "Organization: git-foo\n"
-       subjectprefix = CHANGE
+       subjectPrefix = CHANGE
        suffix = .txt
        numbered = auto
        to = <email>
        cc = <email>
        attach [ = mime-boundary-string ]
-       signoff = true
+       signOff = true
        coverletter = auto
 ------------
 
index 273c4663c8736aa14678b35e3bf4a8de68b78faf..52234987f9993a0b9f6d3f50ce9b26e074f3b58d 100644 (file)
@@ -54,10 +54,10 @@ all loose objects are combined into a single pack using
 `git repack -d -l`.  Setting the value of `gc.auto` to 0
 disables automatic packing of loose objects.
 +
-If the number of packs exceeds the value of `gc.autopacklimit`,
+If the number of packs exceeds the value of `gc.autoPackLimit`,
 then existing packs (except those marked with a `.keep` file)
 are consolidated into a single pack by using the `-A` option of
-'git repack'. Setting `gc.autopacklimit` to 0 disables
+'git repack'. Setting `gc.autoPackLimit` to 0 disables
 automatic consolidation of packs.
 
 --prune=<date>::
@@ -101,18 +101,18 @@ branches:
 ------------
 [gc "refs/remotes/*"]
        reflogExpire = never
-       reflogexpireUnreachable = 3 days
+       reflogExpireUnreachable = 3 days
 ------------
 
-The optional configuration variable 'gc.rerereresolved' indicates
+The optional configuration variable 'gc.rerereResolved' indicates
 how long records of conflicted merge you resolved earlier are
 kept.  This defaults to 60 days.
 
-The optional configuration variable 'gc.rerereunresolved' indicates
+The optional configuration variable 'gc.rerereUnresolved' indicates
 how long records of conflicted merge you have not resolved are
 kept.  This defaults to 15 days.
 
-The optional configuration variable 'gc.packrefs' determines if
+The optional configuration variable 'gc.packRefs' determines if
 'git gc' runs 'git pack-refs'. This can be set to "notbare" to enable
 it within all non-bare repos or it can be set to a boolean value.
 This defaults to true.
index 77aacf130936435970a945e4d687d01c12b1a0f9..5d1e4c80cd5d479a43c39ffb12b66a7302e754e7 100644 (file)
@@ -44,7 +44,8 @@ OPTIONS
 
 --no-curl::
        Talk to the IMAP server using git's own IMAP routines instead of
-       using libcurl.
+       using libcurl.  Ignored if Git was built with the NO_OPENSSL option
+       set.
 
 
 CONFIGURATION
index 369f889bb4d5f9f5066552cef74525649477ca9c..8174d27efdc13b3f611b4aedda70086f39867d73 100644 (file)
@@ -125,7 +125,7 @@ The template directory will be one of the following (in order):
 
  - the contents of the `$GIT_TEMPLATE_DIR` environment variable;
 
- - the `init.templatedir` configuration variable; or
+ - the `init.templateDir` configuration variable; or
 
  - the default template directory: `/usr/share/git-core/templates`.
 
index f3eef510f2ba906f64e802a4ea9e1d671530aca4..cc75b2502288f74a6503b22d6a9abfdd799f97d3 100644 (file)
@@ -76,7 +76,7 @@ You may specify configuration in your .git/config
        httpd = apache2 -f
        port = 4321
        browser = konqueror
-       modulepath = /usr/lib/apache2/modules
+       modulePath = /usr/lib/apache2/modules
 
 -----------------------------------------------------------------------
 
index 1f7bc67d6cc8a842151fc2e4705ecc4e6fb8392e..18bc716a0c89e42d91973b510da1d61d33aad977 100644 (file)
@@ -184,7 +184,7 @@ log.date::
        `--date` option.)  Defaults to "default", which means to write
        dates like `Sat May 8 19:35:34 2010 -0500`.
 
-log.showroot::
+log.showRoot::
        If `false`, `git log` and related commands will not treat the
        initial commit as a big creation event.  Any root commits in
        `git log -p` output would be shown without a diff attached.
index cf2c374b710673e891f8337cb9bcc90d72be460a..1f94908e3c0a803c32eb2392ef4dc8158c6e1c53 100644 (file)
@@ -232,7 +232,7 @@ Barbie's remark on your side.  The only thing you can tell is that your
 side wants to say it is hard and you'd prefer to go shopping, while the
 other side wants to claim it is easy.
 
-An alternative style can be used by setting the "merge.conflictstyle"
+An alternative style can be used by setting the "merge.conflictStyle"
 configuration variable to "diff3".  In "diff3" style, the above conflict
 may look like this:
 
@@ -329,7 +329,7 @@ CONFIGURATION
 -------------
 include::merge-config.txt[]
 
-branch.<name>.mergeoptions::
+branch.<name>.mergeOptions::
        Sets default options for merging into branch <name>. The syntax and
        supported options are the same as those of 'git merge', but option
        values containing whitespace characters are currently not supported.
index 200eb22260069af7a9e2e248f0794a73e2cf4a9f..d3d236cd1f5e2db69b0b234a9be5b5066dd80d52 100644 (file)
@@ -117,7 +117,7 @@ locally created merge commits will not be flattened.
 +
 When false, merge the current branch into the upstream branch.
 +
-See `pull.rebase`, `branch.<name>.rebase` and `branch.autosetuprebase` in
+See `pull.rebase`, `branch.<name>.rebase` and `branch.autoSetupRebase` in
 linkgit:git-config[1] if you want to make `git pull` always use
 `--rebase` instead of merging.
 +
index caa187be06d813606fdddfb1f56bd59609898010..5171086181f86b995f89ddc68de94bd2359561a3 100644 (file)
@@ -222,22 +222,8 @@ origin +master` to force a push to the `master` branch). See the
 `<refspec>...` section above for details.
 
 --repo=<repository>::
-       This option is only relevant if no <repository> argument is
-       passed in the invocation. In this case, 'git push' derives the
-       remote name from the current branch: If it tracks a remote
-       branch, then that remote repository is pushed to. Otherwise,
-       the name "origin" is used. For this latter case, this option
-       can be used to override the name "origin". In other words,
-       the difference between these two commands
-+
---------------------------
-git push public         #1
-git push --repo=public  #2
---------------------------
-+
-is that #1 always pushes to "public" whereas #2 pushes to "public"
-only if the current branch does not track a remote branch. This is
-useful if you write an alias or script around 'git push'.
+       This option is equivalent to the <repository> argument. If both
+       are specified, the command-line argument takes precedence.
 
 -u::
 --set-upstream::
index 924827dc2ec79fc4df83a572dcef89425b844f81..d728030590edb673b4de28ecf7dc1665a525678b 100644 (file)
@@ -207,10 +207,10 @@ rebase.stat::
        Whether to show a diffstat of what changed upstream since the last
        rebase. False by default.
 
-rebase.autosquash::
+rebase.autoSquash::
        If set to true enable '--autosquash' option by default.
 
-rebase.autostash::
+rebase.autoStash::
        If set to true enable '--autostash' option by default.
 
 OPTIONS
@@ -414,7 +414,7 @@ squash/fixup series.
 This option is only valid when the '--interactive' option is used.
 +
 If the '--autosquash' option is enabled by default using the
-configuration variable `rebase.autosquash`, this option can be
+configuration variable `rebase.autoSquash`, this option can be
 used to override and disable this setting.
 
 --[no-]autostash::
index 9016960e27164a11d687ed16b34245667e271fe3..000ee8dba2ab3069e0459defe3df9d7140541a59 100644 (file)
@@ -100,7 +100,7 @@ the following environment variables:
        starting time is different by this many seconds from the
        current session.  Only meaningful when
        `GIT_PUSH_CERT_NONCE_STATUS` says `SLOP`.
-       Also read about `receive.certnonceslop` variable in
+       Also read about `receive.certNonceSlop` variable in
        linkgit:git-config[1].
 
 This hook is called before any refname is updated and before any
index 70791b9fd88b4c64260523a5fcadcb46ce504f8f..5e7908e4f705d858dca8483069fd3b89c8f7e31c 100644 (file)
@@ -17,85 +17,113 @@ The command takes various subcommands, and different options
 depending on the subcommand:
 
 [verse]
-'git reflog expire' [--dry-run] [--stale-fix] [--verbose]
-       [--expire=<time>] [--expire-unreachable=<time>] [--all] <refs>...
-'git reflog delete' ref@\{specifier\}...
 'git reflog' ['show'] [log-options] [<ref>]
+'git reflog expire' [--expire=<time>] [--expire-unreachable=<time>]
+       [--rewrite] [--updateref] [--stale-fix]
+       [--dry-run] [--verbose] [--all | <refs>...]
+'git reflog delete' [--rewrite] [--updateref]
+       [--dry-run] [--verbose] ref@\{specifier\}...
+
+Reference logs, or "reflogs", record when the tips of branches and
+other references were updated in the local repository. Reflogs are
+useful in various Git commands, to specify the old value of a
+reference. For example, `HEAD@{2}` means "where HEAD used to be two
+moves ago", `master@{one.week.ago}` means "where master used to point
+to one week ago in this local repository", and so on. See
+linkgit:gitrevisions[7] for more details.
+
+This command manages the information recorded in the reflogs.
+
+The "show" subcommand (which is also the default, in the absence of
+any subcommands) shows the log of the reference provided in the
+command-line (or `HEAD`, by default). The reflog covers all recent
+actions, and in addition the `HEAD` reflog records branch switching.
+`git reflog show` is an alias for `git log -g --abbrev-commit
+--pretty=oneline`; see linkgit:git-log[1] for more information.
+
+The "expire" subcommand prunes older reflog entries. Entries older
+than `expire` time, or entries older than `expire-unreachable` time
+and not reachable from the current tip, are removed from the reflog.
+This is typically not used directly by end users -- instead, see
+linkgit:git-gc[1].
+
+The "delete" subcommand deletes single entries from the reflog. Its
+argument must be an _exact_ entry (e.g. "`git reflog delete
+master@{2}`"). This subcommand is also typically not used directly by
+end users.
 
-Reflog is a mechanism to record when the tip of branches are
-updated.  This command is to manage the information recorded in it.
 
-The subcommand "expire" is used to prune older reflog entries.
-Entries older than `expire` time, or entries older than
-`expire-unreachable` time and not reachable from the current
-tip, are removed from the reflog.  This is typically not used
-directly by the end users -- instead, see linkgit:git-gc[1].
-
-The subcommand "show" (which is also the default, in the absence of any
-subcommands) will take all the normal log options, and show the log of
-the reference provided in the command-line (or `HEAD`, by default).
-The reflog will cover all recent actions (HEAD reflog records branch switching
-as well).  It is an alias for `git log -g --abbrev-commit --pretty=oneline`;
-see linkgit:git-log[1].
+OPTIONS
+-------
 
-The reflog is useful in various Git commands, to specify the old value
-of a reference. For example, `HEAD@{2}` means "where HEAD used to be
-two moves ago", `master@{one.week.ago}` means "where master used to
-point to one week ago", and so on. See linkgit:gitrevisions[7] for
-more details.
+Options for `show`
+~~~~~~~~~~~~~~~~~~
 
-To delete single entries from the reflog, use the subcommand "delete"
-and specify the _exact_ entry (e.g. "`git reflog delete master@{2}`").
+`git reflog show` accepts any of the options accepted by `git log`.
 
 
-OPTIONS
--------
+Options for `expire`
+~~~~~~~~~~~~~~~~~~~~
 
---stale-fix::
-       This revamps the logic -- the definition of "broken commit"
-       becomes: a commit that is not reachable from any of the refs and
-       there is a missing object among the commit, tree, or blob
-       objects reachable from it that is not reachable from any of the
-       refs.
-+
-This computation involves traversing all the reachable objects, i.e. it
-has the same cost as 'git prune'.  Fortunately, once this is run, we
-should not have to ever worry about missing objects, because the current
-prune and pack-objects know about reflogs and protect objects referred by
-them.
+--all::
+       Process the reflogs of all references.
 
 --expire=<time>::
-       Entries older than this time are pruned.  Without the
-       option it is taken from configuration `gc.reflogExpire`,
-       which in turn defaults to 90 days.  --expire=all prunes
-       entries regardless of their age; --expire=never turns off
-       pruning of reachable entries (but see --expire-unreachable).
+       Prune entries older than the specified time. If this option is
+       not specified, the expiration time is taken from the
+       configuration setting `gc.reflogExpire`, which in turn
+       defaults to 90 days. `--expire=all` prunes entries regardless
+       of their age; `--expire=never` turns off pruning of reachable
+       entries (but see `--expire-unreachable`).
 
 --expire-unreachable=<time>::
-       Entries older than this time and not reachable from
-       the current tip of the branch are pruned.  Without the
-       option it is taken from configuration
-       `gc.reflogExpireUnreachable`, which in turn defaults to
-       30 days.  --expire-unreachable=all prunes unreachable
-       entries regardless of their age; --expire-unreachable=never
+       Prune entries older than `<time>` that are not reachable from
+       the current tip of the branch. If this option is not
+       specified, the expiration time is taken from the configuration
+       setting `gc.reflogExpireUnreachable`, which in turn defaults
+       to 30 days. `--expire-unreachable=all` prunes unreachable
+       entries regardless of their age; `--expire-unreachable=never`
        turns off early pruning of unreachable entries (but see
-       --expire).
-
---all::
-       Instead of listing <refs> explicitly, prune all refs.
+       `--expire`).
 
 --updateref::
-       Update the ref with the sha1 of the top reflog entry (i.e.
-       <ref>@\{0\}) after expiring or deleting.
+       Update the reference to the value of the top reflog entry (i.e.
+       <ref>@\{0\}) if the previous top entry was pruned.  (This
+       option is ignored for symbolic references.)
 
 --rewrite::
-       While expiring or deleting, adjust each reflog entry to ensure
-       that the `old` sha1 field points to the `new` sha1 field of the
-       previous entry.
+       If a reflog entry's predecessor is pruned, adjust its "old"
+       SHA-1 to be equal to the "new" SHA-1 field of the entry that
+       now precedes it.
+
+--stale-fix::
+       Prune any reflog entries that point to "broken commits". A
+       broken commit is a commit that is not reachable from any of
+       the reference tips and that refers, directly or indirectly, to
+       a missing commit, tree, or blob object.
++
+This computation involves traversing all the reachable objects, i.e. it
+has the same cost as 'git prune'.  It is primarily intended to fix
+corruption caused by garbage collecting using older versions of Git,
+which didn't protect objects referred to by reflogs.
+
+-n::
+--dry-run::
+       Do not actually prune any entries; just show what would have
+       been pruned.
 
 --verbose::
        Print extra information on screen.
 
+
+Options for `delete`
+~~~~~~~~~~~~~~~~~~~~
+
+`git reflog delete` accepts options `--updateref`, `--rewrite`, `-n`,
+`--dry-run`, and `--verbose`, with the same meanings as when they are
+used with `expire`.
+
+
 GIT
 ---
 Part of the linkgit:git[1] suite
index cb103c8b6f8fe4fd89ad5e1a37b551f9f54d75c7..4c6d6de7b77c2f1a70e2335fed0e65e956f99c6f 100644 (file)
@@ -58,6 +58,9 @@ remote repository.
 With `--no-tags` option, `git fetch <name>` does not import tags from
 the remote repository.
 +
+By default, only tags on fetched branches are imported
+(see linkgit:git-fetch[1]).
++
 With `-t <branch>` option, instead of the default glob
 refspec for the remote to track all branches under
 the `refs/remotes/<name>/` namespace, a refspec to track only `<branch>`
@@ -130,17 +133,25 @@ branches, adds to that list.
 
 'set-url'::
 
-Changes URL remote points to. Sets first URL remote points to matching
+Changes URLs for the remote. Sets first URL for remote <name> that matches
 regex <oldurl> (first URL if no <oldurl> is given) to <newurl>. If
-<oldurl> doesn't match any URL, error occurs and nothing is changed.
+<oldurl> doesn't match any URL, an error occurs and nothing is changed.
 +
 With '--push', push URLs are manipulated instead of fetch URLs.
 +
-With '--add', instead of changing some URL, new URL is added.
+With '--add', instead of changing existing URLs, new URL is added.
++
+With '--delete', instead of changing existing URLs, all URLs matching
+regex <url> are deleted for remote <name>.  Trying to delete all
+non-push URLs is an error.
 +
-With '--delete', instead of changing some URL, all URLs matching
-regex <url> are deleted. Trying to delete all non-push URLs is an
-error.
+Note that the push URL and the fetch URL, even though they can
+be set differently, must still refer to the same place.  What you
+pushed to the push URL should be what you would see if you
+immediately fetched from the fetch URL.  If you are trying to
+fetch from one place (e.g. your upstream) and push to another (e.g.
+your publishing repository), use two separate remotes.
+
 
 'show'::
 
index 4786a780b5443e6c021e1ce49c3d0f1d96865aba..0e0bd363d6773bd2652287e12aff62bcf6ea09f4 100644 (file)
@@ -115,7 +115,7 @@ other objects in that pack they already have locally.
        Write a reachability bitmap index as part of the repack. This
        only makes sense when used with `-a` or `-A`, as the bitmaps
        must be able to refer to all reachable objects. This option
-       overrides the setting of `pack.writebitmaps`.
+       overrides the setting of `pack.writeBitmaps`.
 
 --pack-kept-objects::
        Include objects in `.keep` files when repacking.  Note that we
@@ -123,7 +123,7 @@ other objects in that pack they already have locally.
        This means that we may duplicate objects, but this makes the
        option safe to use when there are concurrent pushes or fetches.
        This option is generally only useful if you are writing bitmaps
-       with `-b` or `pack.writebitmaps`, as it ensures that the
+       with `-b` or `pack.writeBitmaps`, as it ensures that the
        bitmapped packfile has the necessary objects.
 
 Configuration
index a62227f84e88a5fae13af18e66aec6452693d354..9ee083c415a27dc499b75031d49df9e3f3856ec0 100644 (file)
@@ -69,7 +69,7 @@ Prune records of conflicted merges that
 occurred a long time ago.  By default, unresolved conflicts older
 than 15 days and resolved conflicts older than 60
 days are pruned.  These defaults are controlled via the
-`gc.rerereunresolved` and `gc.rerereresolved` configuration
+`gc.rerereUnresolved` and `gc.rerereResolved` configuration
 variables respectively.
 
 
index f248a8665e1f775edb6932af69b68b7081e1687c..804554609def705bee51e9be087623233c857935 100644 (file)
@@ -47,7 +47,7 @@ Composing
 --annotate::
        Review and edit each patch you're about to send. Default is the value
        of 'sendemail.annotate'. See the CONFIGURATION section for
-       'sendemail.multiedit'.
+       'sendemail.multiEdit'.
 
 --bcc=<address>::
        Specify a "Bcc:" value for each email. Default is the value of
@@ -73,7 +73,7 @@ and In-Reply-To headers will be used unless they are removed.
 +
 Missing From or In-Reply-To headers will be prompted for.
 +
-See the CONFIGURATION section for 'sendemail.multiedit'.
+See the CONFIGURATION section for 'sendemail.multiEdit'.
 
 --from=<address>::
        Specify the sender of the emails.  If not specified on the command line,
@@ -156,31 +156,31 @@ Sending
        subscribed to a list. In order to use the 'From' address, set the
        value to "auto". If you use the sendmail binary, you must have
        suitable privileges for the -f parameter.  Default is the value of the
-       'sendemail.envelopesender' configuration variable; if that is
+       'sendemail.envelopeSender' configuration variable; if that is
        unspecified, choosing the envelope sender is left to your MTA.
 
 --smtp-encryption=<encryption>::
        Specify the encryption to use, either 'ssl' or 'tls'.  Any other
        value reverts to plain SMTP.  Default is the value of
-       'sendemail.smtpencryption'.
+       'sendemail.smtpEncryption'.
 
 --smtp-domain=<FQDN>::
        Specifies the Fully Qualified Domain Name (FQDN) used in the
        HELO/EHLO command to the SMTP server.  Some servers require the
        FQDN to match your IP address.  If not set, git send-email attempts
        to determine your FQDN automatically.  Default is the value of
-       'sendemail.smtpdomain'.
+       'sendemail.smtpDomain'.
 
 --smtp-pass[=<password>]::
        Password for SMTP-AUTH. The argument is optional: If no
        argument is specified, then the empty string is used as
-       the password. Default is the value of 'sendemail.smtppass',
+       the password. Default is the value of 'sendemail.smtpPass',
        however '--smtp-pass' always overrides this value.
 +
 Furthermore, passwords need not be specified in configuration files
 or on the command line. If a username has been specified (with
-'--smtp-user' or a 'sendemail.smtpuser'), but no password has been
-specified (with '--smtp-pass' or 'sendemail.smtppass'), then
+'--smtp-user' or a 'sendemail.smtpUser'), but no password has been
+specified (with '--smtp-pass' or 'sendemail.smtpPass'), then
 a password is obtained using 'git-credential'.
 
 --smtp-server=<host>::
@@ -188,7 +188,7 @@ a password is obtained using 'git-credential'.
        `smtp.example.com` or a raw IP address).  Alternatively it can
        specify a full pathname of a sendmail-like program instead;
        the program must support the `-i` option.  Default value can
-       be specified by the 'sendemail.smtpserver' configuration
+       be specified by the 'sendemail.smtpServer' configuration
        option; the built-in default is `/usr/sbin/sendmail` or
        `/usr/lib/sendmail` if such program is available, or
        `localhost` otherwise.
@@ -199,11 +199,11 @@ a password is obtained using 'git-credential'.
        submission port 587, or the common SSL smtp port 465);
        symbolic port names (e.g. "submission" instead of 587)
        are also accepted. The port can also be set with the
-       'sendemail.smtpserverport' configuration variable.
+       'sendemail.smtpServerPort' configuration variable.
 
 --smtp-server-option=<option>::
        If set, specifies the outgoing SMTP server option to use.
-       Default value can be specified by the 'sendemail.smtpserveroption'
+       Default value can be specified by the 'sendemail.smtpServerOption'
        configuration option.
 +
 The --smtp-server-option option must be repeated for each option you want
@@ -225,8 +225,8 @@ must be used for each option.
        be the best choice on most platforms).
 
 --smtp-user=<user>::
-       Username for SMTP-AUTH. Default is the value of 'sendemail.smtpuser';
-       if a username is not specified (with '--smtp-user' or 'sendemail.smtpuser'),
+       Username for SMTP-AUTH. Default is the value of 'sendemail.smtpUser';
+       if a username is not specified (with '--smtp-user' or 'sendemail.smtpUser'),
        then authentication is not attempted.
 
 --smtp-debug=0|1::
@@ -247,14 +247,14 @@ Automating
        Specify a command to execute once per patch file which
        should generate patch file specific "Cc:" entries.
        Output of this command must be single email address per line.
-       Default is the value of 'sendemail.cccmd' configuration value.
+       Default is the value of 'sendemail.ccCmd' configuration value.
 
 --[no-]chain-reply-to::
        If this is set, each email will be sent as a reply to the previous
        email sent.  If disabled with "--no-chain-reply-to", all emails after
        the first will be sent as replies to the first email sent.  When using
        this, it is recommended that the first file given be an overview of the
-       entire patch series. Disabled by default, but the 'sendemail.chainreplyto'
+       entire patch series. Disabled by default, but the 'sendemail.chainReplyTo'
        configuration variable can be used to enable it.
 
 --identity=<identity>::
@@ -304,7 +304,7 @@ specified, as well as 'body' if --no-signed-off-cc is specified.
 
 --[no-]suppress-from::
        If this is set, do not add the From: address to the cc: list.
-       Default is the value of 'sendemail.suppressfrom' configuration
+       Default is the value of 'sendemail.suppressFrom' configuration
        value; if that is unspecified, default to --no-suppress-from.
 
 --[no-]thread::
@@ -377,15 +377,15 @@ default to '--validate'.
 CONFIGURATION
 -------------
 
-sendemail.aliasesfile::
+sendemail.aliasesFile::
        To avoid typing long email addresses, point this to one or more
-       email aliases files.  You must also supply 'sendemail.aliasfiletype'.
+       email aliases files.  You must also supply 'sendemail.aliasFileType'.
 
-sendemail.aliasfiletype::
-       Format of the file(s) specified in sendemail.aliasesfile. Must be
+sendemail.aliasFileType::
+       Format of the file(s) specified in sendemail.aliasesFile. Must be
        one of 'mutt', 'mailrc', 'pine', 'elm', or 'gnus'.
 
-sendemail.multiedit::
+sendemail.multiEdit::
        If true (default), a single editor instance will be spawned to edit
        files you have to edit (patches when '--annotate' is used, and the
        summary when '--compose' is used). If false, files will be edited one
@@ -404,10 +404,10 @@ To use 'git send-email' to send your patches through the GMail SMTP server,
 edit ~/.gitconfig to specify your account settings:
 
        [sendemail]
-               smtpencryption = tls
-               smtpserver = smtp.gmail.com
-               smtpuser = yourname@gmail.com
-               smtpserverport = 587
+               smtpEncryption = tls
+               smtpServer = smtp.gmail.com
+               smtpUser = yourname@gmail.com
+               smtpServerPort = 587
 
 Once your commits are ready to be sent to the mailing list, run the
 following commands:
index 4d8d530d3542801337f7970b669514af3131ac99..b3319f7c2adb666522d0461e14703940d25e1709 100644 (file)
@@ -77,7 +77,7 @@ configuration variable documented in linkgit:git-config[1].
        only changes to the commits stored in the superproject are shown (this was
        the behavior before 1.7.0). Using "all" hides all changes to submodules
        (and suppresses the output of submodule summaries when the config option
-       `status.submodulesummary` is set).
+       `status.submoduleSummary` is set).
 
 --ignored::
        Show ignored files as well.
@@ -207,7 +207,7 @@ If the config variable `status.relativePaths` is set to false, then all
 paths shown are relative to the repository root, not to the current
 directory.
 
-If `status.submodulesummary` is set to a non zero number or true (identical
+If `status.submoduleSummary` is set to a non zero number or true (identical
 to -1 or an unlimited number), the submodule summary will be enabled for
 the long format and a summary of commits for modified submodules will be
 shown (see --summary-limit option of linkgit:git-submodule[1]). Please note
index 8e6af65da0e0f234315c42391a8bab42fc39abb6..2c25916f8f7cd0a7ca69c3b980d85251a29b681b 100644 (file)
@@ -154,27 +154,51 @@ If `--force` is specified, the submodule's work tree will be removed even if
 it contains local modifications.
 
 update::
-       Update the registered submodules, i.e. clone missing submodules and
-       checkout the commit specified in the index of the containing repository.
-       This will make the submodules HEAD be detached unless `--rebase` or
-       `--merge` is specified or the key `submodule.$name.update` is set to
-       `rebase`, `merge` or `none`. `none` can be overridden by specifying
-       `--checkout`. Setting the key `submodule.$name.update` to `!command`
-       will cause `command` to be run. `command` can be any arbitrary shell
-       command that takes a single argument, namely the sha1 to update to.
 +
+--
+Update the registered submodules to match what the superproject
+expects by cloning missing submodules and updating the working tree of
+the submodules. The "updating" can be done in several ways depending
+on command line options and the value of `submodule.<name>.update`
+configuration variable. Supported update procedures are:
+
+       checkout;; the commit recorded in the superproject will be
+           checked out in the submodule on a detached HEAD. This is
+           done when `--checkout` option is given, or no option is
+           given, and `submodule.<name>.update` is unset, or if it is
+           set to 'checkout'.
++
+If `--force` is specified, the submodule will be checked out (using
+`git checkout --force` if appropriate), even if the commit specified
+in the index of the containing repository already matches the commit
+checked out in the submodule.
+
+       rebase;; the current branch of the submodule will be rebased
+           onto the commit recorded in the superproject. This is done
+           when `--rebase` option is given, or no option is given, and
+           `submodule.<name>.update` is set to 'rebase'.
+
+       merge;; the commit recorded in the superproject will be merged
+           into the current branch in the submodule. This is done
+           when `--merge` option is given, or no option is given, and
+           `submodule.<name>.update` is set to 'merge'.
+
+       custom command;; arbitrary shell command that takes a single
+           argument (the sha1 of the commit recorded in the
+           superproject) is executed. This is done when no option is
+           given, and `submodule.<name>.update` has the form of
+           '!command'.
+
+When no option is given and `submodule.<name>.update` is set to 'none',
+the submodule is not updated.
+
 If the submodule is not yet initialized, and you just want to use the
 setting as stored in .gitmodules, you can automatically initialize the
 submodule with the `--init` option.
-+
+
 If `--recursive` is specified, this command will recurse into the
 registered submodules, and update any nested submodules within.
-+
-If `--force` is specified, the submodule will be checked out (using
-`git checkout --force` if appropriate), even if the commit specified in the
-index of the containing repository already matches the commit checked out in
-the submodule.
-
+--
 summary::
        Show commit summary between the given commit (defaults to HEAD) and
        working tree/index. For a submodule in question, a series of commits
@@ -238,10 +262,12 @@ OPTIONS
        When running add, allow adding an otherwise ignored submodule path.
        When running deinit the submodule work trees will be removed even if
        they contain local changes.
-       When running update, throw away local changes in submodules when
-       switching to a different commit; and always run a checkout operation
-       in the submodule, even if the commit listed in the index of the
-       containing repository matches the commit checked out in the submodule.
+       When running update (only effective with the checkout procedure),
+       throw away local changes in submodules when switching to a
+       different commit; and always run a checkout operation in the
+       submodule, even if the commit listed in the index of the
+       containing repository matches the commit checked out in the
+       submodule.
 
 --cached::
        This option is only valid for status and summary commands.  These
@@ -302,7 +328,7 @@ the submodule itself.
        Checkout the commit recorded in the superproject on a detached HEAD
        in the submodule. This is the default behavior, the main use of
        this option is to override `submodule.$name.update` when set to
-       `merge`, `rebase` or `none`.
+       a value other than `checkout`.
        If the key `submodule.$name.update` is either not explicitly set or
        set to `checkout`, this option is implicit.
 
index e953ba4439f5995c797b4d7ad869847a5479d982..bfba4ef078a916dd81782441b922b2059436164d 100644 (file)
@@ -161,7 +161,7 @@ it in the repository configuration as follows:
 
 -------------------------------------
 [user]
-    signingkey = <gpg-key-id>
+    signingKey = <gpg-key-id>
 -------------------------------------
 
 
index eadbd05356398a3c85884efc6779bba0e923b311..c0022920c0c644bba2ff9059ccbeb175d55aec30 100644 (file)
@@ -43,9 +43,12 @@ 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.3.0/git.html[documentation for release 2.3]
+* link:v2.3.3/git.html[documentation for release 2.3.3]
 
 * release notes for
+  link:RelNotes/2.3.3.txt[2.3.3],
+  link:RelNotes/2.3.2.txt[2.3.2],
+  link:RelNotes/2.3.1.txt[2.3.1],
   link:RelNotes/2.3.0.txt[2.3].
 
 * link:v2.2.2/git.html[documentation for release 2.2.2]
@@ -916,7 +919,7 @@ for further details.
        If this environment variable is set, then Git commands which need to
        acquire passwords or passphrases (e.g. for HTTP or IMAP authentication)
        will call this program with a suitable prompt as command-line argument
-       and read the password from its STDOUT. See also the 'core.askpass'
+       and read the password from its STDOUT. See also the 'core.askPass'
        option in linkgit:git-config[1].
 
 'GIT_TERMINAL_PROMPT'::
index c892ffa5ce41cfce80d0575e1eb0c0b99bc1a09c..70899b302365f1f441422778d7683d277924279f 100644 (file)
@@ -80,7 +80,7 @@ Attributes which should be version-controlled and distributed to other
 repositories (i.e., attributes of interest to all users) should go into
 `.gitattributes` files. Attributes that should affect all repositories
 for a single user should be placed in a file specified by the
-`core.attributesfile` configuration option (see linkgit:git-config[1]).
+`core.attributesFile` configuration option (see linkgit:git-config[1]).
 Its default value is $XDG_CONFIG_HOME/git/attributes. If $XDG_CONFIG_HOME
 is either not set or empty, $HOME/.config/git/attributes is used instead.
 Attributes for all users on a system should be placed in the
index 47576be5dbcdfa855c6d5178a92b748c7d41002b..1c75be080368a5975b609cd8b902d224eabc9bd8 100644 (file)
@@ -32,7 +32,7 @@ strategies to ask the user for usernames and passwords:
    to the program on the command line, and the user's input is read
    from its standard output.
 
-2. Otherwise, if the `core.askpass` configuration variable is set, its
+2. Otherwise, if the `core.askPass` configuration variable is set, its
    value is used as above.
 
 3. Otherwise, if the `SSH_ASKPASS` environment variable is set, its
index 4fd04423e9342e05d34b4a72a4e1af802b8c10c8..473623d6318a859c9ed2cf600222ea6cb4a25d4c 100644 (file)
@@ -38,7 +38,7 @@ precedence, the last matching pattern decides the outcome):
  * Patterns read from `$GIT_DIR/info/exclude`.
 
  * Patterns read from the file specified by the configuration
-   variable 'core.excludesfile'.
+   variable 'core.excludesFile'.
 
 Which file to place a pattern in depends on how the pattern is meant to
 be used.
@@ -56,7 +56,7 @@ be used.
  * Patterns which a user wants Git to
    ignore in all situations (e.g., backup or temporary files generated by
    the user's editor of choice) generally go into a file specified by
-   `core.excludesfile` in the user's `~/.gitconfig`. Its default value is
+   `core.excludesFile` in the user's `~/.gitconfig`. Its default value is
    $XDG_CONFIG_HOME/git/ignore. If $XDG_CONFIG_HOME is either not set or
    empty, $HOME/.config/git/ignore is used instead.
 
index f6c0dfd0290a9b2174c645630998d2a62cdb9f5e..ac70eca321cd1747e2916646c691ac18cb4dbd97 100644 (file)
@@ -38,18 +38,15 @@ submodule.<name>.url::
 In addition, there are a number of optional keys:
 
 submodule.<name>.update::
-       Defines what to do when the submodule is updated by the superproject.
-       If 'checkout' (the default), the new commit specified in the
-       superproject will be checked out in the submodule on a detached HEAD.
-       If 'rebase', the current branch of the submodule will be rebased onto
-       the commit specified in the superproject. If 'merge', the commit
-       specified in the superproject will be merged into the current branch
-       in the submodule.
-       If 'none', the submodule with name `$name` will not be updated
-       by default.
-
-       This config option is overridden if 'git submodule update' is given
-       the '--merge', '--rebase' or '--checkout' options.
+       Defines the default update procedure for the named submodule,
+       i.e. how the submodule is updated by "git submodule update"
+       command in the superproject. This is only used by `git
+       submodule init` to initialize the configuration variable of
+       the same name. Allowed values here are 'checkout', 'rebase',
+       'merge' or 'none'. See description of 'update' command in
+       linkgit:git-submodule[1] for their meaning. Note that the
+       '!command' form is intentionally ignored here for security
+       reasons.
 
 submodule.<name>.branch::
        A remote branch name for tracking updates in the upstream submodule.
index ebe7a6c24cfef75441906a3e4de550b9fd296c0b..0506f07d74421e277c608f37951a063d66a5a5b3 100644 (file)
@@ -706,7 +706,7 @@ show-sizes::
        I/O.  Enabled by default.
 +
 This feature can be configured on a per-repository basis via
-repository's `gitweb.showsizes` configuration variable (boolean).
+repository's `gitweb.showSizes` configuration variable (boolean).
 
 patches::
        Enable and configure "patches" view, which displays list of commits in email
index d78d6d854e5fa0a2d4f030d821984f3e6827b9c1..8a0e52f8ee64564ba1dcac63fc91cdef075996a7 100644 (file)
@@ -1,4 +1,4 @@
-merge.conflictstyle::
+merge.conflictStyle::
        Specify the style in which conflicted hunks are written out to
        working tree files upon merge.  The default is "merge", which
        shows a `<<<<<<<` conflict marker, changes made by one side,
index 0f3d460d34a6285687792c22c66a24921f17baa7..4ed8587c846d78a03e154ec6a4716d78882840b5 100644 (file)
@@ -176,11 +176,6 @@ explicitly.
        Pretend as if all objects mentioned by reflogs are listed on the
        command line as `<commit>`.
 
---indexed-objects::
-       Pretend as if all trees and blobs used by the index are listed
-       on the command line.  Note that you probably want to use
-       `--objects`, too.
-
 --ignore-missing::
        Upon seeing an invalid object name in the input, pretend as if
        the bad input was not given.
@@ -648,6 +643,7 @@ Object Traversal
 
 These options are mostly targeted for packing of Git repositories.
 
+ifdef::git-rev-list[]
 --objects::
        Print the object IDs of any object referenced by the listed
        commits.  `--objects foo ^bar` thus means ``send me
@@ -666,9 +662,15 @@ These options are mostly targeted for packing of Git repositories.
        commits at the cost of increased time.  This is used instead of
        `--objects-edge` to build ``thin'' packs for shallow repositories.
 
+--indexed-objects::
+       Pretend as if all trees and blobs used by the index are listed
+       on the command line.  Note that you probably want to use
+       `--objects`, too.
+
 --unpacked::
        Only useful with `--objects`; print the object IDs that are not
        in packs.
+endif::git-rev-list[]
 
 --no-walk[=(sorted|unsorted)]::
        Only show the given commits, but do not traverse their ancestors.
diff --git a/Documentation/technical/api-error-handling.txt b/Documentation/technical/api-error-handling.txt
new file mode 100644 (file)
index 0000000..fc68db1
--- /dev/null
@@ -0,0 +1,75 @@
+Error reporting in git
+======================
+
+`die`, `usage`, `error`, and `warning` report errors of various
+kinds.
+
+- `die` is for fatal application errors.  It prints a message to
+  the user and exits with status 128.
+
+- `usage` is for errors in command line usage.  After printing its
+  message, it exits with status 129.  (See also `usage_with_options`
+  in the link:api-parse-options.html[parse-options API].)
+
+- `error` is for non-fatal library errors.  It prints a message
+  to the user and returns -1 for convenience in signaling the error
+  to the caller.
+
+- `warning` is for reporting situations that probably should not
+  occur but which the user (and Git) can continue to work around
+  without running into too many problems.  Like `error`, it
+  returns -1 after reporting the situation to the caller.
+
+Customizable error handlers
+---------------------------
+
+The default behavior of `die` and `error` is to write a message to
+stderr and then exit or return as appropriate.  This behavior can be
+overridden using `set_die_routine` and `set_error_routine`.  For
+example, "git daemon" uses set_die_routine to write the reason `die`
+was called to syslog before exiting.
+
+Library errors
+--------------
+
+Functions return a negative integer on error.  Details beyond that
+vary from function to function:
+
+- Some functions return -1 for all errors.  Others return a more
+  specific value depending on how the caller might want to react
+  to the error.
+
+- Some functions report the error to stderr with `error`,
+  while others leave that for the caller to do.
+
+- errno is not meaningful on return from most functions (except
+  for thin wrappers for system calls).
+
+Check the function's API documentation to be sure.
+
+Caller-handled errors
+---------------------
+
+An increasing number of functions take a parameter 'struct strbuf *err'.
+On error, such functions append a message about what went wrong to the
+'err' strbuf.  The message is meant to be complete enough to be passed
+to `die` or `error` as-is.  For example:
+
+       if (ref_transaction_commit(transaction, &err))
+               die("%s", err.buf);
+
+The 'err' parameter will be untouched if no error occured, so multiple
+function calls can be chained:
+
+       t = ref_transaction_begin(&err);
+       if (!t ||
+           ref_transaction_update(t, "HEAD", ..., &err) ||
+           ret_transaction_commit(t, &err))
+               die("%s", err.buf);
+
+The 'err' parameter must be a pointer to a valid strbuf.  To silence
+a message, pass a strbuf that is explicitly ignored:
+
+       if (thing_that_can_fail_in_an_ignorable_way(..., &err))
+               /* This failure is okay. */
+               strbuf_reset(&err);
diff --git a/Documentation/technical/api-strbuf.txt b/Documentation/technical/api-strbuf.txt
deleted file mode 100644 (file)
index cca6543..0000000
+++ /dev/null
@@ -1,351 +0,0 @@
-strbuf API
-==========
-
-strbuf's are meant to be used with all the usual C string and memory
-APIs. Given that the length of the buffer is known, it's often better to
-use the mem* functions than a str* one (memchr vs. strchr e.g.).
-Though, one has to be careful about the fact that str* functions often
-stop on NULs and that strbufs may have embedded NULs.
-
-A strbuf is NUL terminated for convenience, but no function in the
-strbuf API actually relies on the string being free of NULs.
-
-strbufs have some invariants that are very important to keep in mind:
-
-. The `buf` member is never NULL, so it can be used in any usual C
-string operations safely. strbuf's _have_ to be initialized either by
-`strbuf_init()` or by `= STRBUF_INIT` before the invariants, though.
-+
-Do *not* assume anything on what `buf` really is (e.g. if it is
-allocated memory or not), use `strbuf_detach()` to unwrap a memory
-buffer from its strbuf shell in a safe way. That is the sole supported
-way. This will give you a malloced buffer that you can later `free()`.
-+
-However, it is totally safe to modify anything in the string pointed by
-the `buf` member, between the indices `0` and `len-1` (inclusive).
-
-. The `buf` member is a byte array that has at least `len + 1` bytes
-  allocated. The extra byte is used to store a `'\0'`, allowing the
-  `buf` member to be a valid C-string. Every strbuf function ensure this
-  invariant is preserved.
-+
-NOTE: It is OK to "play" with the buffer directly if you work it this
-      way:
-+
-----
-strbuf_grow(sb, SOME_SIZE); <1>
-strbuf_setlen(sb, sb->len + SOME_OTHER_SIZE);
-----
-<1> Here, the memory array starting at `sb->buf`, and of length
-`strbuf_avail(sb)` is all yours, and you can be sure that
-`strbuf_avail(sb)` is at least `SOME_SIZE`.
-+
-NOTE: `SOME_OTHER_SIZE` must be smaller or equal to `strbuf_avail(sb)`.
-+
-Doing so is safe, though if it has to be done in many places, adding the
-missing API to the strbuf module is the way to go.
-+
-WARNING: Do _not_ assume that the area that is yours is of size `alloc
-- 1` even if it's true in the current implementation. Alloc is somehow a
-"private" member that should not be messed with. Use `strbuf_avail()`
-instead.
-
-Data structures
----------------
-
-* `struct strbuf`
-
-This is the string buffer structure. The `len` member can be used to
-determine the current length of the string, and `buf` member provides
-access to the string itself.
-
-Functions
----------
-
-* Life cycle
-
-`strbuf_init`::
-
-       Initialize the structure. The second parameter can be zero or a bigger
-       number to allocate memory, in case you want to prevent further reallocs.
-
-`strbuf_release`::
-
-       Release a string buffer and the memory it used. You should not use the
-       string buffer after using this function, unless you initialize it again.
-
-`strbuf_detach`::
-
-       Detach the string from the strbuf and returns it; you now own the
-       storage the string occupies and it is your responsibility from then on
-       to release it with `free(3)` when you are done with it.
-
-`strbuf_attach`::
-
-       Attach a string to a buffer. You should specify the string to attach,
-       the current length of the string and the amount of allocated memory.
-       The amount must be larger than the string length, because the string you
-       pass is supposed to be a NUL-terminated string.  This string _must_ be
-       malloc()ed, and after attaching, the pointer cannot be relied upon
-       anymore, and neither be free()d directly.
-
-`strbuf_swap`::
-
-       Swap the contents of two string buffers.
-
-* Related to the size of the buffer
-
-`strbuf_avail`::
-
-       Determine the amount of allocated but unused memory.
-
-`strbuf_grow`::
-
-       Ensure that at least this amount of unused memory is available after
-       `len`. This is used when you know a typical size for what you will add
-       and want to avoid repetitive automatic resizing of the underlying buffer.
-       This is never a needed operation, but can be critical for performance in
-       some cases.
-
-`strbuf_setlen`::
-
-       Set the length of the buffer to a given value. This function does *not*
-       allocate new memory, so you should not perform a `strbuf_setlen()` to a
-       length that is larger than `len + strbuf_avail()`. `strbuf_setlen()` is
-       just meant as a 'please fix invariants from this strbuf I just messed
-       with'.
-
-`strbuf_reset`::
-
-       Empty the buffer by setting the size of it to zero.
-
-* Related to the contents of the buffer
-
-`strbuf_trim`::
-
-       Strip whitespace from the beginning and end of a string.
-       Equivalent to performing `strbuf_rtrim()` followed by `strbuf_ltrim()`.
-
-`strbuf_rtrim`::
-
-       Strip whitespace from the end of a string.
-
-`strbuf_ltrim`::
-
-       Strip whitespace from the beginning of a string.
-
-`strbuf_reencode`::
-
-       Replace the contents of the strbuf with a reencoded form.  Returns -1
-       on error, 0 on success.
-
-`strbuf_tolower`::
-
-       Lowercase each character in the buffer using `tolower`.
-
-`strbuf_cmp`::
-
-       Compare two buffers. Returns an integer less than, equal to, or greater
-       than zero if the first buffer is found, respectively, to be less than,
-       to match, or be greater than the second buffer.
-
-* Adding data to the buffer
-
-NOTE: All of the functions in this section will grow the buffer as necessary.
-If they fail for some reason other than memory shortage and the buffer hadn't
-been allocated before (i.e. the `struct strbuf` was set to `STRBUF_INIT`),
-then they will free() it.
-
-`strbuf_addch`::
-
-       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
-       will be shifted, not overwritten.
-
-`strbuf_remove`::
-
-       Remove given amount of data from a given position of the buffer.
-
-`strbuf_splice`::
-
-       Remove the bytes between `pos..pos+len` and replace it with the given
-       data.
-
-`strbuf_add_commented_lines`::
-
-       Add a NUL-terminated string to the buffer. Each line will be prepended
-       by a comment character and a blank.
-
-`strbuf_add`::
-
-       Add data of given length to the buffer.
-
-`strbuf_addstr`::
-
-Add a NUL-terminated string to the buffer.
-+
-NOTE: This function will *always* be implemented as an inline or a macro
-that expands to:
-+
-----
-strbuf_add(..., s, strlen(s));
-----
-+
-Meaning that this is efficient to write things like:
-+
-----
-strbuf_addstr(sb, "immediate string");
-----
-
-`strbuf_addbuf`::
-
-       Copy the contents of another buffer at the end of the current one.
-
-`strbuf_adddup`::
-
-       Copy part of the buffer from a given position till a given length to the
-       end of the buffer.
-
-`strbuf_expand`::
-
-       This function can be used to expand a format string containing
-       placeholders. To that end, it parses the string and calls the specified
-       function for every percent sign found.
-+
-The callback function is given a pointer to the character after the `%`
-and a pointer to the struct strbuf.  It is expected to add the expanded
-version of the placeholder to the strbuf, e.g. to add a newline
-character if the letter `n` appears after a `%`.  The function returns
-the length of the placeholder recognized and `strbuf_expand()` skips
-over it.
-+
-The format `%%` is automatically expanded to a single `%` as a quoting
-mechanism; callers do not need to handle the `%` placeholder themselves,
-and the callback function will not be invoked for this placeholder.
-+
-All other characters (non-percent and not skipped ones) are copied
-verbatim to the strbuf.  If the callback returned zero, meaning that the
-placeholder is unknown, then the percent sign is copied, too.
-+
-In order to facilitate caching and to make it possible to give
-parameters to the callback, `strbuf_expand()` passes a context pointer,
-which can be used by the programmer of the callback as she sees fit.
-
-`strbuf_expand_dict_cb`::
-
-       Used as callback for `strbuf_expand()`, expects an array of
-       struct strbuf_expand_dict_entry as context, i.e. pairs of
-       placeholder and replacement string.  The array needs to be
-       terminated by an entry with placeholder set to NULL.
-
-`strbuf_addbuf_percentquote`::
-
-       Append the contents of one strbuf to another, quoting any
-       percent signs ("%") into double-percents ("%%") in the
-       destination. This is useful for literal data to be fed to either
-       strbuf_expand or to the *printf family of functions.
-
-`strbuf_humanise_bytes`::
-
-       Append the given byte size as a human-readable string (i.e. 12.23 KiB,
-       3.50 MiB).
-
-`strbuf_addf`::
-
-       Add a formatted string to the buffer.
-
-`strbuf_commented_addf`::
-
-       Add a formatted string prepended by a comment character and a
-       blank to the buffer.
-
-`strbuf_fread`::
-
-       Read a given size of data from a FILE* pointer to the buffer.
-+
-NOTE: The buffer is rewound if the read fails. If -1 is returned,
-`errno` must be consulted, like you would do for `read(3)`.
-`strbuf_read()`, `strbuf_read_file()` and `strbuf_getline()` has the
-same behaviour as well.
-
-`strbuf_read`::
-
-       Read the contents of a given file descriptor. The third argument can be
-       used to give a hint about the file size, to avoid reallocs.
-
-`strbuf_read_file`::
-
-       Read the contents of a file, specified by its path. The third argument
-       can be used to give a hint about the file size, to avoid reallocs.
-
-`strbuf_readlink`::
-
-       Read the target of a symbolic link, specified by its path.  The third
-       argument can be used to give a hint about the size, to avoid reallocs.
-
-`strbuf_getline`::
-
-       Read a line from a FILE *, overwriting the existing contents
-       of the strbuf. The second argument specifies the line
-       terminator character, typically `'\n'`.
-       Reading stops after the terminator or at EOF.  The terminator
-       is removed from the buffer before returning.  Returns 0 unless
-       there was nothing left before EOF, in which case it returns `EOF`.
-
-`strbuf_getwholeline`::
-
-       Like `strbuf_getline`, but keeps the trailing terminator (if
-       any) in the buffer.
-
-`strbuf_getwholeline_fd`::
-
-       Like `strbuf_getwholeline`, but operates on a file descriptor.
-       It reads one character at a time, so it is very slow.  Do not
-       use it unless you need the correct position in the file
-       descriptor.
-
-`strbuf_getcwd`::
-
-       Set the buffer to the path of the current working directory.
-
-`strbuf_add_absolute_path`
-
-       Add a path to a buffer, converting a relative path to an
-       absolute one in the process.  Symbolic links are not
-       resolved.
-
-`stripspace`::
-
-       Strip whitespace from a buffer. The second parameter controls if
-       comments are considered contents to be removed or not.
-
-`strbuf_split_buf`::
-`strbuf_split_str`::
-`strbuf_split_max`::
-`strbuf_split`::
-
-       Split a string or strbuf into a list of strbufs at a specified
-       terminator character.  The returned substrings include the
-       terminator characters.  Some of these functions take a `max`
-       parameter, which, if positive, limits the output to that
-       number of substrings.
-
-`strbuf_list_free`::
-
-       Free a list of strbufs (for example, the return values of the
-       `strbuf_split()` functions).
-
-`launch_editor`::
-
-       Launch the user preferred editor to edit a file and fill the buffer
-       with the file's contents upon the user completing their editing. The
-       third argument can be used to set the environment which the editor is
-       run in. If the buffer is NULL the editor is launched as usual but the
-       file's contents are not read into the buffer upon completion.
index 7330d880f373fcb067c1dec954ddd60cda370c5d..68978f53381baf1b179b70f22e97084893d5c227 100644 (file)
@@ -1200,7 +1200,7 @@ for other users who clone your repository.
 If you wish the exclude patterns to affect only certain repositories
 (instead of every repository for a given project), you may instead put
 them in a file in your repository named `.git/info/exclude`, or in any
-file specified by the `core.excludesfile` configuration variable.
+file specified by the `core.excludesFile` configuration variable.
 Some Git commands can also take exclude patterns directly on the
 command line.  See linkgit:gitignore[5] for the details.
 
index 780064ad7173fd5be40b3b5e419db5c3e53f96f2..734fa9b4347ac1f65ad35ada88098404d92fcb25 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v2.3.0
+DEF_VER=v2.3.3.GIT
 
 LF='
 '
index e8ce649ca1e2fb536e7de366205666388d8cfdf7..5f3987fe3bd945fb5a84c9f45a8de7da5581f79a 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -357,6 +357,8 @@ all::
 # and define it to "no" if you need to remove the parentheses () around the
 # constant.  The default is "auto", which means to use parentheses if your
 # compiler is detected to support it.
+#
+# Define HAVE_BSD_SYSCTL if your platform has a BSD-compatible sysctl function.
 
 GIT-VERSION-FILE: FORCE
        @$(SHELL_PATH) ./GIT-VERSION-GEN
@@ -1052,13 +1054,13 @@ else
        REMOTE_CURL_NAMES = $(REMOTE_CURL_PRIMARY) $(REMOTE_CURL_ALIASES)
        PROGRAM_OBJS += http-fetch.o
        PROGRAMS += $(REMOTE_CURL_NAMES)
-       curl_check := $(shell (echo 070908; curl-config --vernum) 2>/dev/null | sort -r | sed -ne 2p)
+       curl_check := $(shell (echo 070908; curl-config --vernum | sed -e '/^70[BC]/s/^/0/') 2>/dev/null | sort -r | sed -ne 2p)
        ifeq "$(curl_check)" "070908"
                ifndef NO_EXPAT
                        PROGRAM_OBJS += http-push.o
                endif
        endif
-       curl_check := $(shell (echo 072200; curl-config --vernum) 2>/dev/null | sort -r | sed -ne 2p)
+       curl_check := $(shell (echo 072200; curl-config --vernum | sed -e '/^70[BC]/s/^/0/') 2>/dev/null | sort -r | sed -ne 2p)
        ifeq "$(curl_check)" "072200"
                USE_CURL_FOR_IMAP_SEND = YesPlease
        endif
@@ -1431,6 +1433,10 @@ ifdef HAVE_CLOCK_MONOTONIC
        BASIC_CFLAGS += -DHAVE_CLOCK_MONOTONIC
 endif
 
+ifdef HAVE_BSD_SYSCTL
+       BASIC_CFLAGS += -DHAVE_BSD_SYSCTL
+endif
+
 ifeq ($(TCLTK_PATH),)
 NO_TCLTK = NoThanks
 endif
deleted file mode 100644 (file)
index 0fbbabb4f8ca4eb7ada7e6f559569d698adbf246..0000000000000000000000000000000000000000
--- a/RelNotes
+++ /dev/null
@@ -1,64 +0,0 @@
-Git ???? Release Notes
-======================
-
-Updates since v2.3
-------------------
-
-Ports
-
-
-UI, Workflows & Features
-
- * The command usage info strings given by "git cmd -h" and in
-   documentation have been tweaked for consistency.
-
- * The "sync" subcommand of "git p4" now allows users to exclude
-   subdirectories like its "clone" subcommand does.
-
- * "git log --invert-grep --grep=WIP" will show only commits that do
-   not have the string "WIP" in their messages.
-
- * "git push" has been taught a "--atomic" option that makes push to
-   update more than one ref an "all-or-none" affair.
-
- * Extending the "push to deploy" added in 2.3, the behaviour of "git
-   push" when updating the branch that is checked out can now be
-   tweaked by push-to-checkout hook.
-
-
-Performance, Internal Implementation, Development Support etc.
-
- * Implementation of N_() macro has been updated slightly to help us
-   detect mistakes.
-
- * Implementation of "reflog expire" has been restructured to fit the
-   reflogs better with the recently updated ref API.
-
-
-Also contains various documentation updates and code clean-ups.
-
-
-Fixes since v2.3
-----------------
-
-Unless otherwise noted, all the fixes since v2.3 in the maintenance
-track are contained in this release (see the maintenance releases'
-notes for details).
-
- * "git blame HEAD -- missing" failed to correctly say "HEAD" when it
-   tried to say "No such path 'missing' in HEAD".
-   (merge a46442f jk/blame-commit-label later to maint).
-
- * "git rerere" (invoked internally from many mergy operations) did
-   not correctly signal errors when told to update the working tree
-   files and failed to do so for whatever reason.
-   (merge 89ea903 jn/rerere-fail-on-auto-update-failure later to maint).
-
- * Setting diff.submodule to 'log' made "git format-patch" produce
-   broken patches.
-   (merge 339de50 dk/format-patch-ignore-diff-submodule later to maint).
-
- * After attempting and failing a password-less authentication
-   (e.g. kerberos), libcURL refuses to fall back to password based
-   Basic authentication without a bit of help/encouragement.
-   (merge 4dbe664 bc/http-fallback-to-password-after-krb-fails later to maint).
new file mode 120000 (symlink)
index 0000000000000000000000000000000000000000..1addbec92533510e6e368c607deb36e504bbc438
--- /dev/null
+++ b/RelNotes
@@ -0,0 +1 @@
+Documentation/RelNotes/2.4.0.txt
\ No newline at end of file
index 4bde019bce632703d4e336d6404693487cdbcdfb..ffb3535e93dca2135724d998657b80c2bc4d6f20 100644 (file)
@@ -5,6 +5,8 @@
 #include "archive.h"
 #include "streaming.h"
 #include "utf8.h"
+#include "userdiff.h"
+#include "xdiff-interface.h"
 
 static int zip_date;
 static int zip_time;
@@ -120,7 +122,6 @@ static void *zlib_deflate_raw(void *data, unsigned long size,
        void *buffer;
        int result;
 
-       memset(&stream, 0, sizeof(stream));
        git_deflate_init_raw(&stream, compression_level);
        maxsize = git_deflate_bound(&stream, size);
        buffer = xmalloc(maxsize);
@@ -189,6 +190,16 @@ static int has_only_ascii(const char *s)
        }
 }
 
+static int entry_is_binary(const char *path, const void *buffer, size_t size)
+{
+       struct userdiff_driver *driver = userdiff_find_by_path(path);
+       if (!driver)
+               driver = userdiff_find_by_name("default");
+       if (driver->binary != -1)
+               return driver->binary;
+       return buffer_is_binary(buffer, size);
+}
+
 #define STREAM_BUFFER_SIZE (1024 * 16)
 
 static int write_zip_entry(struct archiver_args *args,
@@ -210,6 +221,8 @@ static int write_zip_entry(struct archiver_args *args,
        struct git_istream *stream = NULL;
        unsigned long flags = 0;
        unsigned long size;
+       int is_binary = -1;
+       const char *path_without_prefix = path + args->baselen;
 
        crc = crc32(0, NULL, 0);
 
@@ -256,6 +269,8 @@ static int write_zip_entry(struct archiver_args *args,
                                return error("cannot read %s",
                                             sha1_to_hex(sha1));
                        crc = crc32(crc, buffer, size);
+                       is_binary = entry_is_binary(path_without_prefix,
+                                                   buffer, size);
                        out = buffer;
                }
                compressed_size = (method == 0) ? size : 0;
@@ -300,7 +315,6 @@ static int write_zip_entry(struct archiver_args *args,
        copy_le16(dirent.extra_length, ZIP_EXTRA_MTIME_SIZE);
        copy_le16(dirent.comment_length, 0);
        copy_le16(dirent.disk, 0);
-       copy_le16(dirent.attr1, 0);
        copy_le32(dirent.attr2, attr2);
        copy_le32(dirent.offset, zip_offset);
 
@@ -328,6 +342,9 @@ static int write_zip_entry(struct archiver_args *args,
                        if (readlen <= 0)
                                break;
                        crc = crc32(crc, buf, readlen);
+                       if (is_binary == -1)
+                               is_binary = entry_is_binary(path_without_prefix,
+                                                           buf, readlen);
                        write_or_die(1, buf, readlen);
                }
                close_istream(stream);
@@ -349,7 +366,6 @@ static int write_zip_entry(struct archiver_args *args,
                size_t out_len;
                unsigned char compressed[STREAM_BUFFER_SIZE * 2];
 
-               memset(&zstream, 0, sizeof(zstream));
                git_deflate_init_raw(&zstream, args->compression_level);
 
                compressed_size = 0;
@@ -361,6 +377,9 @@ static int write_zip_entry(struct archiver_args *args,
                        if (readlen <= 0)
                                break;
                        crc = crc32(crc, buf, readlen);
+                       if (is_binary == -1)
+                               is_binary = entry_is_binary(path_without_prefix,
+                                                           buf, readlen);
 
                        zstream.next_in = buf;
                        zstream.avail_in = readlen;
@@ -405,6 +424,8 @@ static int write_zip_entry(struct archiver_args *args,
        free(deflated);
        free(buffer);
 
+       copy_le16(dirent.attr1, !is_binary);
+
        memcpy(zip_dir + zip_dir_offset, &dirent, ZIP_DIR_HEADER_SIZE);
        zip_dir_offset += ZIP_DIR_HEADER_SIZE;
        memcpy(zip_dir + zip_dir_offset, path, pathlen);
diff --git a/attr.c b/attr.c
index cd5469770a6f7841ae327e6ba7141dd99d9cacc1..1f9eebd2ddb7fe8a561500c41f33a52d1fb4fdd1 100644 (file)
--- a/attr.c
+++ b/attr.c
@@ -32,9 +32,12 @@ struct git_attr {
        struct git_attr *next;
        unsigned h;
        int attr_nr;
+       int maybe_macro;
+       int maybe_real;
        char name[FLEX_ARRAY];
 };
 static int attr_nr;
+static int cannot_trust_maybe_real;
 
 static struct git_attr_check *check_all_attr;
 static struct git_attr *(git_attr_hash[HASHSIZE]);
@@ -95,6 +98,8 @@ static struct git_attr *git_attr_internal(const char *name, int len)
        a->h = hval;
        a->next = git_attr_hash[pos];
        a->attr_nr = attr_nr++;
+       a->maybe_macro = 0;
+       a->maybe_real = 0;
        git_attr_hash[pos] = a;
 
        REALLOC_ARRAY(check_all_attr, attr_nr);
@@ -244,9 +249,10 @@ static struct match_attr *parse_attr_line(const char *line, const char *src,
                      sizeof(*res) +
                      sizeof(struct attr_state) * num_attr +
                      (is_macro ? 0 : namelen + 1));
-       if (is_macro)
+       if (is_macro) {
                res->u.attr = git_attr_internal(name, namelen);
-       else {
+               res->u.attr->maybe_macro = 1;
+       } else {
                char *p = (char *)&(res->state[num_attr]);
                memcpy(p, name, namelen);
                res->u.pat.pattern = p;
@@ -266,6 +272,10 @@ static struct match_attr *parse_attr_line(const char *line, const char *src,
        /* Second pass to fill the attr_states */
        for (cp = states, i = 0; *cp; i++) {
                cp = parse_attr(src, lineno, cp, &(res->state[i]));
+               if (!is_macro)
+                       res->state[i].attr->maybe_real = 1;
+               if (res->state[i].attr->maybe_macro)
+                       cannot_trust_maybe_real = 1;
        }
 
        return res;
@@ -681,13 +691,14 @@ static int fill(const char *path, int pathlen, int basename_offset,
        return rem;
 }
 
-static int macroexpand_one(int attr_nr, int rem)
+static int macroexpand_one(int nr, int rem)
 {
        struct attr_stack *stk;
        struct match_attr *a = NULL;
        int i;
 
-       if (check_all_attr[attr_nr].value != ATTR__TRUE)
+       if (check_all_attr[nr].value != ATTR__TRUE ||
+           !check_all_attr[nr].attr->maybe_macro)
                return rem;
 
        for (stk = attr_stack; !a && stk; stk = stk->prev)
@@ -695,7 +706,7 @@ static int macroexpand_one(int attr_nr, int rem)
                        struct match_attr *ma = stk->attrs[i];
                        if (!ma->is_macro)
                                continue;
-                       if (ma->u.attr->attr_nr == attr_nr)
+                       if (ma->u.attr->attr_nr == nr)
                                a = ma;
                }
 
@@ -706,10 +717,13 @@ static int macroexpand_one(int attr_nr, int rem)
 }
 
 /*
- * Collect all attributes for path into the array pointed to by
- * check_all_attr.
+ * Collect attributes for path into the array pointed to by
+ * check_all_attr. If num is non-zero, only attributes in check[] are
+ * collected. Otherwise all attributes are collected.
  */
-static void collect_all_attrs(const char *path)
+static void collect_some_attrs(const char *path, int num,
+                              struct git_attr_check *check)
+
 {
        struct attr_stack *stk;
        int i, pathlen, rem, dirlen;
@@ -732,6 +746,19 @@ static void collect_all_attrs(const char *path)
        prepare_attr_stack(path, dirlen);
        for (i = 0; i < attr_nr; i++)
                check_all_attr[i].value = ATTR__UNKNOWN;
+       if (num && !cannot_trust_maybe_real) {
+               rem = 0;
+               for (i = 0; i < num; i++) {
+                       if (!check[i].attr->maybe_real) {
+                               struct git_attr_check *c;
+                               c = check_all_attr + check[i].attr->attr_nr;
+                               c->value = ATTR__UNSET;
+                               rem++;
+                       }
+               }
+               if (rem == num)
+                       return;
+       }
 
        rem = attr_nr;
        for (stk = attr_stack; 0 < rem && stk; stk = stk->prev)
@@ -742,7 +769,7 @@ int git_check_attr(const char *path, int num, struct git_attr_check *check)
 {
        int i;
 
-       collect_all_attrs(path);
+       collect_some_attrs(path, num, check);
 
        for (i = 0; i < num; i++) {
                const char *value = check_all_attr[check[i].attr->attr_nr].value;
@@ -758,7 +785,7 @@ int git_all_attrs(const char *path, int *num, struct git_attr_check **check)
 {
        int i, count, j;
 
-       collect_all_attrs(path);
+       collect_some_attrs(path, 0, NULL);
 
        /* Count the number of attributes that are set. */
        count = 0;
index 4bab55a9a85e187e2a3906312f1e771f4a214f45..b0024353f4409c8b54c4b569b8fb7c435b26cdae 100644 (file)
--- a/branch.c
+++ b/branch.c
@@ -284,8 +284,9 @@ void create_branch(const char *head,
 
                transaction = ref_transaction_begin(&err);
                if (!transaction ||
-                   ref_transaction_update(transaction, ref.buf, sha1,
-                                          null_sha1, 0, !forcing, msg, &err) ||
+                   ref_transaction_update(transaction, ref.buf,
+                                          sha1, forcing ? NULL : null_sha1,
+                                          0, msg, &err) ||
                    ref_transaction_commit(transaction, &err))
                        die("%s", err.buf);
                ref_transaction_free(transaction);
index 23bda9628795016353d6feaf2b9699e48837f62c..65b97eee69d4814bf80f87b1fd6857b8ed80cb90 100644 (file)
@@ -51,6 +51,7 @@ static int apply_verbosely;
 static int allow_overlap;
 static int no_add;
 static int threeway;
+static int unsafe_paths;
 static const char *fake_ancestor;
 static int line_termination = '\n';
 static unsigned int p_context = UINT_MAX;
@@ -1600,6 +1601,9 @@ static int parse_fragment(const char *line, unsigned long size,
                        if (!deleted && !added)
                                leading++;
                        trailing++;
+                       if (!apply_in_reverse &&
+                           ws_error_action == correct_ws_error)
+                               check_whitespace(line, len, patch->ws_rule);
                        break;
                case '-':
                        if (apply_in_reverse &&
@@ -2230,6 +2234,12 @@ static void update_pre_post_images(struct image *preimage,
                ctx++;
        }
 
+       if (postlen
+           ? postlen < new - postimage->buf
+           : postimage->len < new - postimage->buf)
+               die("BUG: caller miscounted postlen: asked %d, orig = %d, used = %d",
+                   (int)postlen, (int) postimage->len, (int)(new - postimage->buf));
+
        /* Fix the length of the whole thing */
        postimage->len = new - postimage->buf;
        postimage->nr -= reduced;
@@ -2385,10 +2395,27 @@ static int match_fragment(struct image *img,
 
        /*
         * The hunk does not apply byte-by-byte, but the hash says
-        * it might with whitespace fuzz. We haven't been asked to
+        * it might with whitespace fuzz. We weren't asked to
         * ignore whitespace, we were asked to correct whitespace
         * errors, so let's try matching after whitespace correction.
         *
+        * While checking the preimage against the target, whitespace
+        * errors in both fixed, we count how large the corresponding
+        * postimage needs to be.  The postimage prepared by
+        * apply_one_fragment() has whitespace errors fixed on added
+        * lines already, but the common lines were propagated as-is,
+        * which may become longer when their whitespace errors are
+        * fixed.
+        */
+
+       /* First count added lines in postimage */
+       postlen = 0;
+       for (i = 0; i < postimage->nr; i++) {
+               if (!(postimage->line[i].flag & LINE_COMMON))
+                       postlen += postimage->line[i].len;
+       }
+
+       /*
         * The preimage may extend beyond the end of the file,
         * but in this loop we will only handle the part of the
         * preimage that falls within the file.
@@ -2396,7 +2423,6 @@ static int match_fragment(struct image *img,
        strbuf_init(&fixed, preimage->len + 1);
        orig = preimage->buf;
        target = img->buf + try;
-       postlen = 0;
        for (i = 0; i < preimage_limit; i++) {
                size_t oldlen = preimage->line[i].len;
                size_t tgtlen = img->line[try_lno + i].len;
@@ -2424,7 +2450,10 @@ static int match_fragment(struct image *img,
                match = (tgtfix.len == fixed.len - fixstart &&
                         !memcmp(tgtfix.buf, fixed.buf + fixstart,
                                             fixed.len - fixstart));
-               postlen += tgtfix.len;
+
+               /* Add the length if this is common with the postimage */
+               if (preimage->line[i].flag & LINE_COMMON)
+                       postlen += tgtfix.len;
 
                strbuf_release(&tgtfix);
                if (!match)
@@ -3196,7 +3225,7 @@ static int load_patch_target(struct strbuf *buf,
                             const char *name,
                             unsigned expected_mode)
 {
-       if (cached) {
+       if (cached || check_index) {
                if (read_file_or_gitlink(ce, buf))
                        return error(_("read of %s failed"), name);
        } else if (name) {
@@ -3205,6 +3234,8 @@ static int load_patch_target(struct strbuf *buf,
                                return read_file_or_gitlink(ce, buf);
                        else
                                return SUBMODULE_PATCH_WITHOUT_INDEX;
+               } else if (has_symlink_leading_path(name, strlen(name))) {
+                       return error(_("reading from '%s' beyond a symbolic link"), name);
                } else {
                        if (read_old_data(st, name, buf))
                                return error(_("read of %s failed"), name);
@@ -3544,6 +3575,121 @@ static int check_to_create(const char *new_name, int ok_if_exists)
        return 0;
 }
 
+/*
+ * We need to keep track of how symlinks in the preimage are
+ * manipulated by the patches.  A patch to add a/b/c where a/b
+ * is a symlink should not be allowed to affect the directory
+ * the symlink points at, but if the same patch removes a/b,
+ * it is perfectly fine, as the patch removes a/b to make room
+ * to create a directory a/b so that a/b/c can be created.
+ */
+static struct string_list symlink_changes;
+#define SYMLINK_GOES_AWAY 01
+#define SYMLINK_IN_RESULT 02
+
+static uintptr_t register_symlink_changes(const char *path, uintptr_t what)
+{
+       struct string_list_item *ent;
+
+       ent = string_list_lookup(&symlink_changes, path);
+       if (!ent) {
+               ent = string_list_insert(&symlink_changes, path);
+               ent->util = (void *)0;
+       }
+       ent->util = (void *)(what | ((uintptr_t)ent->util));
+       return (uintptr_t)ent->util;
+}
+
+static uintptr_t check_symlink_changes(const char *path)
+{
+       struct string_list_item *ent;
+
+       ent = string_list_lookup(&symlink_changes, path);
+       if (!ent)
+               return 0;
+       return (uintptr_t)ent->util;
+}
+
+static void prepare_symlink_changes(struct patch *patch)
+{
+       for ( ; patch; patch = patch->next) {
+               if ((patch->old_name && S_ISLNK(patch->old_mode)) &&
+                   (patch->is_rename || patch->is_delete))
+                       /* the symlink at patch->old_name is removed */
+                       register_symlink_changes(patch->old_name, SYMLINK_GOES_AWAY);
+
+               if (patch->new_name && S_ISLNK(patch->new_mode))
+                       /* the symlink at patch->new_name is created or remains */
+                       register_symlink_changes(patch->new_name, SYMLINK_IN_RESULT);
+       }
+}
+
+static int path_is_beyond_symlink_1(struct strbuf *name)
+{
+       do {
+               unsigned int change;
+
+               while (--name->len && name->buf[name->len] != '/')
+                       ; /* scan backwards */
+               if (!name->len)
+                       break;
+               name->buf[name->len] = '\0';
+               change = check_symlink_changes(name->buf);
+               if (change & SYMLINK_IN_RESULT)
+                       return 1;
+               if (change & SYMLINK_GOES_AWAY)
+                       /*
+                        * This cannot be "return 0", because we may
+                        * see a new one created at a higher level.
+                        */
+                       continue;
+
+               /* otherwise, check the preimage */
+               if (check_index) {
+                       struct cache_entry *ce;
+
+                       ce = cache_file_exists(name->buf, name->len, ignore_case);
+                       if (ce && S_ISLNK(ce->ce_mode))
+                               return 1;
+               } else {
+                       struct stat st;
+                       if (!lstat(name->buf, &st) && S_ISLNK(st.st_mode))
+                               return 1;
+               }
+       } while (1);
+       return 0;
+}
+
+static int path_is_beyond_symlink(const char *name_)
+{
+       int ret;
+       struct strbuf name = STRBUF_INIT;
+
+       assert(*name_ != '\0');
+       strbuf_addstr(&name, name_);
+       ret = path_is_beyond_symlink_1(&name);
+       strbuf_release(&name);
+
+       return ret;
+}
+
+static void die_on_unsafe_path(struct patch *patch)
+{
+       const char *old_name = NULL;
+       const char *new_name = NULL;
+       if (patch->is_delete)
+               old_name = patch->old_name;
+       else if (!patch->is_new && !patch->is_copy)
+               old_name = patch->old_name;
+       if (!patch->is_delete)
+               new_name = patch->new_name;
+
+       if (old_name && !verify_path(old_name))
+               die(_("invalid path '%s'"), old_name);
+       if (new_name && !verify_path(new_name))
+               die(_("invalid path '%s'"), new_name);
+}
+
 /*
  * Check and apply the patch in-core; leave the result in patch->result
  * for the caller to write it out to the final destination.
@@ -3631,6 +3777,22 @@ static int check_patch(struct patch *patch)
                }
        }
 
+       if (!unsafe_paths)
+               die_on_unsafe_path(patch);
+
+       /*
+        * An attempt to read from or delete a path that is beyond a
+        * symbolic link will be prevented by load_patch_target() that
+        * is called at the beginning of apply_data() so we do not
+        * have to worry about a patch marked with "is_delete" bit
+        * here.  We however need to make sure that the patch result
+        * is not deposited to a path that is beyond a symbolic link
+        * here.
+        */
+       if (!patch->is_delete && path_is_beyond_symlink(patch->new_name))
+               return error(_("affected file '%s' is beyond a symbolic link"),
+                            patch->new_name);
+
        if (apply_data(patch, &st, ce) < 0)
                return error(_("%s: patch does not apply"), name);
        patch->rejected = 0;
@@ -3641,6 +3803,7 @@ static int check_patch_list(struct patch *patch)
 {
        int err = 0;
 
+       prepare_symlink_changes(patch);
        prepare_fn_table(patch);
        while (patch) {
                if (apply_verbosely)
@@ -4379,6 +4542,8 @@ int cmd_apply(int argc, const char **argv, const char *prefix_)
                        N_("make sure the patch is applicable to the current index")),
                OPT_BOOL(0, "cached", &cached,
                        N_("apply a patch without touching the working tree")),
+               OPT_BOOL(0, "unsafe-paths", &unsafe_paths,
+                       N_("accept a patch that touches outside the working area")),
                OPT_BOOL(0, "apply", &force_apply,
                        N_("also apply the patch (use with --stat/--summary/--check)")),
                OPT_BOOL('3', "3way", &threeway,
@@ -4451,6 +4616,9 @@ int cmd_apply(int argc, const char **argv, const char *prefix_)
                        die(_("--cached outside a repository"));
                check_index = 1;
        }
+       if (check_index)
+               unsafe_paths = 0;
+
        for (i = 0; i < argc; i++) {
                const char *arg = argv[i];
                int fd;
index 44b0134ea295baf0eb8cd8b3de0b8aa8a5dce02e..06484c2e0e23237bff711bbe3cda6e1382004ef3 100644 (file)
@@ -2085,7 +2085,6 @@ static void find_alignment(struct scoreboard *sb, int *option)
 
        for (e = sb->ent; e; e = e->next) {
                struct origin *suspect = e->suspect;
-               struct commit_info ci;
                int num;
 
                if (compute_auto_abbrev)
@@ -2096,6 +2095,7 @@ static void find_alignment(struct scoreboard *sb, int *option)
                if (longest_file < num)
                        longest_file = num;
                if (!(suspect->commit->object.flags & METAINFO_SHOWN)) {
+                       struct commit_info ci;
                        suspect->commit->object.flags |= METAINFO_SHOWN;
                        get_commit_info(suspect->commit, &ci, 1);
                        if (*option & OUTPUT_SHOW_EMAIL)
@@ -2104,6 +2104,7 @@ static void find_alignment(struct scoreboard *sb, int *option)
                                num = utf8_strwidth(ci.author.buf);
                        if (longest_author < num)
                                longest_author = num;
+                       commit_info_destroy(&ci);
                }
                num = e->s_lno + e->num_lines;
                if (longest_src_lines < num)
@@ -2113,8 +2114,6 @@ static void find_alignment(struct scoreboard *sb, int *option)
                        longest_dst_lines = num;
                if (largest_score < ent_score(sb, e))
                        largest_score = ent_score(sb, e);
-
-               commit_info_destroy(&ci);
        }
        max_orig_digits = decimal_width(longest_src_lines);
        max_digits = decimal_width(longest_dst_lines);
index 6a25957e9f9daff6ab127f8feb91d9349075741e..1d150378e91cd47c4cd555bfc858ec0b7ea9d604 100644 (file)
@@ -589,9 +589,16 @@ static char *get_head_description(void)
        else if (state.bisect_in_progress)
                strbuf_addf(&desc, _("(no branch, bisect started on %s)"),
                            state.branch);
-       else if (state.detached_from)
-               strbuf_addf(&desc, _("(detached from %s)"),
-                           state.detached_from);
+       else if (state.detached_from) {
+               /* TRANSLATORS: make sure these match _("HEAD detached at ")
+                  and _("HEAD detached from ") in wt-status.c */
+               if (state.detached_at)
+                       strbuf_addf(&desc, _("(HEAD detached at %s)"),
+                               state.detached_from);
+               else
+                       strbuf_addf(&desc, _("(HEAD detached from %s)"),
+                               state.detached_from);
+       }
        else
                strbuf_addstr(&desc, _("(no branch)"));
        free(state.branch);
index 7e7fdcfe54a547c90a5a6911eb59b0ec22151ac6..98c103fa8b4faa83c33a62e5d7871c1e9d888c38 100644 (file)
@@ -754,7 +754,8 @@ static int ask_each_cmd(void)
                /* Ctrl-D should stop removing files */
                if (!eof) {
                        qname = quote_path_relative(item->string, NULL, &buf);
-                       printf(_("remove %s? "), qname);
+                       /* TRANSLATORS: Make sure to keep [y/N] as is */
+                       printf(_("Remove %s [y/N]? "), qname);
                        if (strbuf_getline(&confirm, stdin, '\n') != EOF) {
                                strbuf_trim(&confirm);
                        } else {
index 7f467133b88c10e2440c878a0218bee981b3acd7..961e467242747dac07aa6f5e619e2d1a50570b06 100644 (file)
@@ -1050,7 +1050,7 @@ static const char *find_author_by_nickname(const char *name)
                clear_mailmap(&mailmap);
                return strbuf_detach(&buf, NULL);
        }
-       die(_("No existing author found with '%s'"), name);
+       die(_("--author '%s' is not 'Name <email>' and matches no existing author"), name);
 }
 
 
@@ -1766,8 +1766,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
        if (!transaction ||
            ref_transaction_update(transaction, "HEAD", sha1,
                                   current_head
-                                  ? current_head->object.sha1 : NULL,
-                                  0, !!current_head, sb.buf, &err) ||
+                                  ? current_head->object.sha1 : null_sha1,
+                                  0, sb.buf, &err) ||
            ref_transaction_commit(transaction, &err)) {
                rollback_index_files();
                die("%s", err.buf);
index 7b84d35d83498bc51b06915818f63d1f365eec91..f9512652cf1389a770bd94fd170d123206e024c5 100644 (file)
@@ -11,7 +11,6 @@
 #include "run-command.h"
 #include "parse-options.h"
 #include "sigchain.h"
-#include "transport.h"
 #include "submodule.h"
 #include "connected.h"
 #include "argv-array.h"
@@ -416,8 +415,10 @@ static int s_update_ref(const char *action,
 
        transaction = ref_transaction_begin(&err);
        if (!transaction ||
-           ref_transaction_update(transaction, ref->name, ref->new_sha1,
-                                  ref->old_sha1, 0, check_old, msg, &err))
+           ref_transaction_update(transaction, ref->name,
+                                  ref->new_sha1,
+                                  check_old ? ref->old_sha1 : NULL,
+                                  0, msg, &err))
                goto fail;
 
        ret = ref_transaction_commit(transaction, &err);
index 19be78a943d303700379f665d64c8843c69848d5..83f9cf91633a514e9301762fe774ee91be092848 100644 (file)
@@ -178,11 +178,10 @@ static const char *find_next(const char *cp)
 static int verify_format(const char *format)
 {
        const char *cp, *sp;
-       static const char color_reset[] = "color:reset";
 
        need_color_reset_at_eol = 0;
        for (cp = format; *cp && (sp = find_next(cp)); ) {
-               const char *ep = strchr(sp, ')');
+               const char *color, *ep = strchr(sp, ')');
                int at;
 
                if (!ep)
@@ -191,8 +190,8 @@ static int verify_format(const char *format)
                at = parse_atom(sp + 2, ep);
                cp = ep + 1;
 
-               if (starts_with(used_atom[at], "color:"))
-                       need_color_reset_at_eol = !!strcmp(used_atom[at], color_reset);
+               if (skip_prefix(used_atom[at], "color:", &color))
+                       need_color_reset_at_eol = !!strcmp(color, "reset");
        }
        return 0;
 }
index 9262b73b6f5efd28756db221f2775671430c7fd2..335f25d0ad69a41ee2ea1e1e38aecbc2c121cb8c 100644 (file)
@@ -641,7 +641,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                OPT_BOOL(0, "untracked", &untracked,
                        N_("search in both tracked and untracked files")),
                OPT_SET_INT(0, "exclude-standard", &opt_exclude,
-                           N_("search also in ignored files"), 1),
+                           N_("ignore files specified via '.gitignore'"), 1),
                OPT_GROUP(""),
                OPT_BOOL('v', "invert-match", &opt.invert,
                        N_("show non-matching lines")),
index 6133fe496b00e30a33d03c2d49b22a6ff81f9c77..3422e7307998b9da91f85512084aeae515022a60 100644 (file)
@@ -171,7 +171,7 @@ static void exec_man_cmd(const char *cmd, const char *page)
 {
        struct strbuf shell_cmd = STRBUF_INIT;
        strbuf_addf(&shell_cmd, "%s %s", cmd, page);
-       execl("/bin/sh", "sh", "-c", shell_cmd.buf, (char *)NULL);
+       execl(SHELL_PATH, SHELL_PATH, "-c", shell_cmd.buf, (char *)NULL);
        warning(_("failed to exec '%s': %s"), cmd, strerror(errno));
 }
 
@@ -456,7 +456,7 @@ static void list_common_guides_help(void)
 int cmd_help(int argc, const char **argv, const char *prefix)
 {
        int nongit;
-       const char *alias;
+       char *alias;
        enum help_format parsed_help_format;
 
        argc = parse_options(argc, argv, prefix, builtin_help_options,
@@ -499,6 +499,7 @@ int cmd_help(int argc, const char **argv, const char *prefix)
        alias = alias_lookup(argv[0]);
        if (alias && !is_git_command(argv[0])) {
                printf_ln(_("`git %s' is aliased to `%s'"), argv[0], alias);
+               free(alias);
                return 0;
        }
 
index 46321176719808dd53a38675dd0d9c558ae336dd..cf654df09b3734063f415b2b735f3062706f75a0 100644 (file)
@@ -1204,7 +1204,6 @@ static int write_compressed(struct sha1file *f, void *in, unsigned int size)
        int status;
        unsigned char outbuf[4096];
 
-       memset(&stream, 0, sizeof(stream));
        git_deflate_init(&stream, zlib_compression_level);
        stream.next_in = in;
        stream.avail_in = size;
index 131edc245fdc0f5f8cb1e5d3da4120d072858d3f..ea8093f6769e278c4f7871faf405fe1e3f0a7544 100644 (file)
@@ -90,7 +90,8 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
 
        if (ret >= 0) {
                const char *filename = argv[0];
-               FILE *f = to_stdout ? stdout : fopen(filename, "wb");
+               const char *fpath = prefix_filename(prefix, prefixlen, argv[0]);
+               FILE *f = to_stdout ? stdout : fopen(fpath, "wb");
 
                if (!f)
                        ret = error("Could not open %s for writing", filename);
index d8165878e1d466e49719038b1badc524d5627270..c3a75166bd10918d21d3df19832880c4373dc8d7 100644 (file)
@@ -125,7 +125,6 @@ static unsigned long do_compress(void **pptr, unsigned long size)
        void *in, *out;
        unsigned long maxsize;
 
-       memset(&stream, 0, sizeof(stream));
        git_deflate_init(&stream, pack_compression_level);
        maxsize = git_deflate_bound(&stream, size);
 
@@ -153,7 +152,6 @@ static unsigned long write_large_blob_data(struct git_istream *st, struct sha1fi
        unsigned char obuf[1024 * 16];
        unsigned long olen = 0;
 
-       memset(&stream, 0, sizeof(stream));
        git_deflate_init(&stream, pack_compression_level);
 
        for (;;) {
index e0ce78e5a069670b00da6f3d67b991525c6dd29c..70e9ce5f96f3e8da78e4b5746580869f9ae65330 100644 (file)
@@ -953,8 +953,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
                if (ref_transaction_delete(transaction,
                                           namespaced_name,
                                           old_sha1,
-                                          0, old_sha1 != NULL,
-                                          "push", &err)) {
+                                          0, "push", &err)) {
                        rp_error("%s", err.buf);
                        strbuf_release(&err);
                        return "failed to delete";
@@ -971,7 +970,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
                if (ref_transaction_update(transaction,
                                           namespaced_name,
                                           new_sha1, old_sha1,
-                                          0, 1, "push",
+                                          0, "push",
                                           &err)) {
                        rp_error("%s", err.buf);
                        strbuf_release(&err);
index 49c64f96d8adba41261741cfa48f0e36fcd9f3bb..8182b648b9c9693ec6f23f6b2100e432bfa794ba 100644 (file)
@@ -8,14 +8,11 @@
 #include "revision.h"
 #include "reachable.h"
 
-/*
- * reflog expire
- */
-
+/* NEEDSWORK: switch to using parse_options */
 static const char reflog_expire_usage[] =
-"git reflog expire [--verbose] [--dry-run] [--stale-fix] [--expire=<time>] [--expire-unreachable=<time>] [--all] <refs>...";
+"git reflog expire [--expire=<time>] [--expire-unreachable=<time>] [--rewrite] [--updateref] [--stale-fix] [--dry-run | -n] [--verbose] [--all] <refs>...";
 static const char reflog_delete_usage[] =
-"git reflog delete [--verbose] [--dry-run] [--rewrite] [--updateref] <refs>...";
+"git reflog delete [--rewrite] [--updateref] [--dry-run | -n] [--verbose] <refs>...";
 
 static unsigned long default_reflog_expire;
 static unsigned long default_reflog_expire_unreachable;
index 85d39b58d8aa35f0cd644273821ffd047ac50df0..54bf01acb4ca060a1dae43b399a6aefb1abe4eee 100644 (file)
@@ -172,7 +172,7 @@ static int replace_object_sha1(const char *object_ref,
        transaction = ref_transaction_begin(&err);
        if (!transaction ||
            ref_transaction_update(transaction, ref, repl, prev,
-                                  0, 1, NULL, &err) ||
+                                  0, NULL, &err) ||
            ref_transaction_commit(transaction, &err))
                die("%s", err.buf);
 
index 6dc85a9d5e16e921a99a9f90c5d1f453bf9450bd..6f07ac6b93c3e36a1bc69d43e6e12ca3367b4c34 100644 (file)
@@ -605,13 +605,13 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
                OPT_STRING('u', "local-user", &keyid, N_("key-id"),
                                        N_("use another key to sign the tag")),
                OPT__FORCE(&force, N_("replace the tag if exists")),
+
+               OPT_GROUP(N_("Tag listing options")),
                OPT_COLUMN(0, "column", &colopts, N_("show tag list in columns")),
                {
                        OPTION_CALLBACK, 0, "sort", &tag_sort, N_("type"), N_("sort tags"),
                        PARSE_OPT_NONEG, parse_opt_sort
                },
-
-               OPT_GROUP(N_("Tag listing options")),
                {
                        OPTION_CALLBACK, 0, "contains", &with_commit, N_("commit"),
                        N_("print only tags that contain the commit"),
@@ -733,7 +733,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
        transaction = ref_transaction_begin(&err);
        if (!transaction ||
            ref_transaction_update(transaction, ref.buf, object, prev,
-                                  0, 1, NULL, &err) ||
+                                  0, NULL, &err) ||
            ref_transaction_commit(transaction, &err))
                die("%s", err.buf);
        ref_transaction_free(transaction);
index 2497ba4303a03fa244b4f3913c22b45acd0a989c..3d79a46b036fa7bea29bbc0941442b5dd92f648c 100644 (file)
@@ -198,8 +198,9 @@ static const char *parse_cmd_update(struct ref_transaction *transaction,
        if (*next != line_termination)
                die("update %s: extra input: %s", refname, next);
 
-       if (ref_transaction_update(transaction, refname, new_sha1, old_sha1,
-                                  update_flags, have_old, msg, &err))
+       if (ref_transaction_update(transaction, refname,
+                                  new_sha1, have_old ? old_sha1 : NULL,
+                                  update_flags, msg, &err))
                die("%s", err.buf);
 
        update_flags = 0;
@@ -264,8 +265,9 @@ static const char *parse_cmd_delete(struct ref_transaction *transaction,
        if (*next != line_termination)
                die("delete %s: extra input: %s", refname, next);
 
-       if (ref_transaction_delete(transaction, refname, old_sha1,
-                                  update_flags, have_old, msg, &err))
+       if (ref_transaction_delete(transaction, refname,
+                                  have_old ? old_sha1 : NULL,
+                                  update_flags, msg, &err))
                die("%s", err.buf);
 
        update_flags = 0;
@@ -280,7 +282,6 @@ static const char *parse_cmd_verify(struct ref_transaction *transaction,
 {
        struct strbuf err = STRBUF_INIT;
        char *refname;
-       unsigned char new_sha1[20];
        unsigned char old_sha1[20];
 
        refname = parse_refname(input, &next);
@@ -291,13 +292,11 @@ static const char *parse_cmd_verify(struct ref_transaction *transaction,
                            PARSE_SHA1_OLD))
                hashclr(old_sha1);
 
-       hashcpy(new_sha1, old_sha1);
-
        if (*next != line_termination)
                die("verify %s: extra input: %s", refname, next);
 
-       if (ref_transaction_update(transaction, refname, new_sha1, old_sha1,
-                                  update_flags, 1, msg, &err))
+       if (ref_transaction_verify(transaction, refname, old_sha1,
+                                  update_flags, &err))
                die("%s", err.buf);
 
        update_flags = 0;
@@ -353,7 +352,8 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
 {
        const char *refname, *oldval;
        unsigned char sha1[20], oldsha1[20];
-       int delete = 0, no_deref = 0, read_stdin = 0, end_null = 0, flags = 0;
+       int delete = 0, no_deref = 0, read_stdin = 0, end_null = 0;
+       unsigned int flags = 0;
        struct option options[] = {
                OPT_STRING( 'm', NULL, &msg, N_("reason"), N_("reason of the update")),
                OPT_BOOL('d', NULL, &delete, N_("delete the reference")),
index 0c4b8a7cad085fa1c7760e6290f21213830eda3d..8d157eba455f15a00cc7bf9b970f1862167ee1bb 100644 (file)
@@ -105,7 +105,6 @@ static int stream_to_pack(struct bulk_checkin_state *state,
        int write_object = (flags & HASH_WRITE_OBJECT);
        off_t offset = 0;
 
-       memset(&s, 0, sizeof(s));
        git_deflate_init(&s, pack_compression_level);
 
        hdrlen = encode_in_pack_object_header(type, size, obuf);
index 2e2dbd50efbf2eca2b36f6dd7ceeb68bbecc90ba..f732c920aadd7515d56f7d344f771fb9d362f042 100644 (file)
--- a/bundle.c
+++ b/bundle.c
@@ -334,7 +334,7 @@ static int write_bundle_refs(int bundle_fd, struct rev_info *revs)
                if (e->item->flags & UNINTERESTING)
                        continue;
                if (dwim_ref(e->name, strlen(e->name), sha1, &ref) != 1)
-                       continue;
+                       goto skip_write_ref;
                if (read_ref_full(e->name, RESOLVE_REF_READING, sha1, &flag))
                        flag = 0;
                display_ref = (flag & REF_ISSYMREF) ? e->name : ref;
@@ -342,7 +342,7 @@ static int write_bundle_refs(int bundle_fd, struct rev_info *revs)
                if (e->item->type == OBJ_TAG &&
                                !is_tag_in_date_range(e->item, revs)) {
                        e->item->flags |= UNINTERESTING;
-                       continue;
+                       goto skip_write_ref;
                }
 
                /*
@@ -357,8 +357,7 @@ static int write_bundle_refs(int bundle_fd, struct rev_info *revs)
                if (!(e->item->flags & SHOWN) && e->item->type == OBJ_COMMIT) {
                        warning(_("ref '%s' is excluded by the rev-list options"),
                                e->name);
-                       free(ref);
-                       continue;
+                       goto skip_write_ref;
                }
                /*
                 * If you run "git bundle create bndl v1.0..v2.0", the
@@ -388,8 +387,7 @@ static int write_bundle_refs(int bundle_fd, struct rev_info *revs)
                                obj->flags |= SHOWN;
                                add_pending_object(revs, obj, e->name);
                        }
-                       free(ref);
-                       continue;
+                       goto skip_write_ref;
                }
 
                ref_count++;
@@ -397,6 +395,7 @@ static int write_bundle_refs(int bundle_fd, struct rev_info *revs)
                write_or_die(bundle_fd, " ", 1);
                write_or_die(bundle_fd, display_ref, strlen(display_ref));
                write_or_die(bundle_fd, "\n", 1);
+ skip_write_ref:
                free(ref);
        }
 
diff --git a/cache.h b/cache.h
index f704af5df0984e092fe318e535596921c4ea7122..761c5704b2e21f5dcd68fdcc9c3b1247ab0cfd18 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -568,7 +568,7 @@ extern void update_index_if_able(struct index_state *, struct lock_file *);
 extern int hold_locked_index(struct lock_file *, int);
 extern void set_alternate_index_output(const char *);
 
-extern int delete_ref(const char *, const unsigned char *sha1, int delopt);
+extern int delete_ref(const char *, const unsigned char *sha1, unsigned int flags);
 
 /* Environment bits from configuration mechanism */
 extern int trust_executable_bit;
@@ -1254,6 +1254,10 @@ extern int unpack_object_header(struct packed_git *, struct pack_window **, off_
  *
  * Any callback that is NULL will be ignored. Callbacks returning non-zero
  * will end the iteration.
+ *
+ * In the "buf" variant, "path" is a strbuf which will also be used as a
+ * scratch buffer, but restored to its original contents before
+ * the function returns.
  */
 typedef int each_loose_object_fn(const unsigned char *sha1,
                                 const char *path,
@@ -1269,6 +1273,11 @@ int for_each_loose_file_in_objdir(const char *path,
                                  each_loose_cruft_fn cruft_cb,
                                  each_loose_subdir_fn subdir_cb,
                                  void *data);
+int for_each_loose_file_in_objdir_buf(struct strbuf *path,
+                                     each_loose_object_fn obj_cb,
+                                     each_loose_cruft_fn cruft_cb,
+                                     each_loose_subdir_fn subdir_cb,
+                                     void *data);
 
 /*
  * Iterate over loose and packed objects in both the local
@@ -1498,7 +1507,7 @@ extern const char *pager_program;
 extern int pager_in_use(void);
 extern int pager_use_color;
 extern int term_columns(void);
-extern int decimal_width(int);
+extern int decimal_width(uintmax_t);
 extern int check_pager_config(const char *cmd);
 
 extern const char *editor_program;
index 07cff69d8e5c5fdbca47b603dbc2e9c067d369fd..a0aaf3a3473cadb162f8c39175b0ceb6cee1535a 100755 (executable)
@@ -3,7 +3,7 @@
 {
        cat <<\EOF
 sayIt:
-       $(foreach b,$(BUILT_INS),echo XXX $b YYY;)
+       $(foreach b,$(BUILT_INS),echo XXX $(b:$X=) YYY;)
 EOF
        cat Makefile
 } |
index e5e64dc60fa4890a99b556c31a8665b7c92375d3..66c0a51bce529e4c027f11017697a62dd737b3bd 100644 (file)
--- a/config.c
+++ b/config.c
@@ -73,8 +73,12 @@ static int config_buf_fgetc(struct config_source *conf)
 
 static int config_buf_ungetc(int c, struct config_source *conf)
 {
-       if (conf->u.buf.pos > 0)
-               return conf->u.buf.buf[--conf->u.buf.pos];
+       if (conf->u.buf.pos > 0) {
+               conf->u.buf.pos--;
+               if (conf->u.buf.buf[conf->u.buf.pos] != c)
+                       die("BUG: config_buf can only ungetc the same character");
+               return c;
+       }
 
        return EOF;
 }
@@ -235,7 +239,8 @@ static int get_next_char(void)
                /* DOS like systems */
                c = cf->do_fgetc(cf);
                if (c != '\n') {
-                       cf->do_ungetc(c, cf);
+                       if (c != EOF)
+                               cf->do_ungetc(c, cf);
                        c = '\r';
                }
        }
index b64b63c34c315561110c5d9f3e334ebd633d095b..f4e77cb9e5099cd3de723ad98894c92d516f176e 100644 (file)
@@ -107,6 +107,7 @@ ifeq ($(uname_S),Darwin)
        COMPAT_OBJS += compat/precompose_utf8.o
        BASIC_CFLAGS += -DPRECOMPOSE_UNICODE
        BASIC_CFLAGS += -DPROTECT_HFS_DEFAULT=1
+       HAVE_BSD_SYSCTL = YesPlease
 endif
 ifeq ($(uname_S),SunOS)
        NEEDS_SOCKET = YesPlease
@@ -199,6 +200,7 @@ ifeq ($(uname_S),FreeBSD)
        PYTHON_PATH = /usr/local/bin/python
        HAVE_PATHS_H = YesPlease
        GMTIME_UNRELIABLE_ERRORS = UnfortunatelyYes
+       HAVE_BSD_SYSCTL = YesPlease
 endif
 ifeq ($(uname_S),OpenBSD)
        NO_STRCASESTR = YesPlease
@@ -208,6 +210,7 @@ ifeq ($(uname_S),OpenBSD)
        BASIC_CFLAGS += -I/usr/local/include
        BASIC_LDFLAGS += -L/usr/local/lib
        HAVE_PATHS_H = YesPlease
+       HAVE_BSD_SYSCTL = YesPlease
 endif
 ifeq ($(uname_S),MirBSD)
        NO_STRCASESTR = YesPlease
@@ -215,6 +218,7 @@ ifeq ($(uname_S),MirBSD)
        USE_ST_TIMESPEC = YesPlease
        NEEDS_LIBICONV = YesPlease
        HAVE_PATHS_H = YesPlease
+       HAVE_BSD_SYSCTL = YesPlease
 endif
 ifeq ($(uname_S),NetBSD)
        ifeq ($(shell expr "$(uname_R)" : '[01]\.'),2)
@@ -225,6 +229,7 @@ ifeq ($(uname_S),NetBSD)
        USE_ST_TIMESPEC = YesPlease
        NO_MKSTEMPS = YesPlease
        HAVE_PATHS_H = YesPlease
+       HAVE_BSD_SYSCTL = YesPlease
 endif
 ifeq ($(uname_S),AIX)
        DEFAULT_PAGER = more
index 55e5a9b3e6c39f15d9d4cf419a72ee963713b662..bbdde85c3dcca460dd0aebee6415ccce184885dc 100644 (file)
@@ -1046,6 +1046,29 @@ GIT_CONF_SUBST([NO_INITGROUPS])
 #
 # Define NO_ICONV if your libc does not properly support iconv.
 
+AC_DEFUN([BSD_SYSCTL_SRC], [
+AC_LANG_PROGRAM([[
+#include <stddef.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+]],[[
+int val, mib[2];
+size_t len;
+mib[0] = CTL_HW;
+mib[1] = 1;
+len = sizeof(val);
+return sysctl(mib, 2, &val, &len, NULL, 0) ? 1 : 0;
+]])])
+
+#
+# Define HAVE_BSD_SYSCTL=YesPlease if a BSD-compatible sysctl function is available.
+AC_MSG_CHECKING([for BSD sysctl])
+AC_COMPILE_IFELSE([BSD_SYSCTL_SRC],
+       [AC_MSG_RESULT([yes])
+       HAVE_BSD_SYSCTL=YesPlease],
+       [AC_MSG_RESULT([no])
+       HAVE_BSD_SYSCTL=])
+GIT_CONF_SUBST([HAVE_BSD_SYSCTL])
 
 ## Other checks.
 # Define USE_PIC if you need the main git objects to be built with -fPIC
index 062e133aa39b9e522bf3a03c5e57ac67c03ad88e..6090211fe9fad7fb3a2392e399976bc3ea528a4e 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -157,8 +157,7 @@ struct ref **get_remote_heads(int in, char *src_buf, size_t src_len,
                        server_capabilities = xstrdup(name + name_len + 1);
                }
 
-               if (extra_have &&
-                   name_len == 5 && !memcmp(".have", name, 5)) {
+               if (extra_have && !strcmp(name, ".have")) {
                        sha1_array_append(extra_have, old_sha1);
                        continue;
                }
@@ -274,28 +273,44 @@ static enum protocol get_protocol(const char *name)
        die("I don't handle protocol '%s'", name);
 }
 
+static char *host_end(char **hoststart, int removebrackets)
+{
+       char *host = *hoststart;
+       char *end;
+       char *start = strstr(host, "@[");
+       if (start)
+               start++; /* Jump over '@' */
+       else
+               start = host;
+       if (start[0] == '[') {
+               end = strchr(start + 1, ']');
+               if (end) {
+                       if (removebrackets) {
+                               *end = 0;
+                               memmove(start, start + 1, end - start);
+                               end++;
+                       }
+               } else
+                       end = host;
+       } else
+               end = host;
+       return end;
+}
+
 #define STR_(s)        # s
 #define STR(s) STR_(s)
 
 static void get_host_and_port(char **host, const char **port)
 {
        char *colon, *end;
-
-       if (*host[0] == '[') {
-               end = strchr(*host + 1, ']');
-               if (end) {
-                       *end = 0;
-                       end++;
-                       (*host)++;
-               } else
-                       end = *host;
-       } else
-               end = *host;
+       end = host_end(host, 1);
        colon = strchr(end, ':');
-
        if (colon) {
-               *colon = 0;
-               *port = colon + 1;
+               long portnr = strtol(colon + 1, &end, 10);
+               if (end != colon + 1 && *end == '\0' && 0 <= portnr && portnr < 65536) {
+                       *colon = 0;
+                       *port = colon + 1;
+               }
        }
 }
 
@@ -547,13 +562,16 @@ static struct child_process *git_proxy_connect(int fd[2], char *host)
        return proxy;
 }
 
-static const char *get_port_numeric(const char *p)
+static char *get_port(char *host)
 {
        char *end;
+       char *p = strchr(host, ':');
+
        if (p) {
                long port = strtol(p + 1, &end, 10);
                if (end != p + 1 && *end == '\0' && 0 <= port && port < 65536) {
-                       return p;
+                       *p = '\0';
+                       return p+1;
                }
        }
 
@@ -595,14 +613,7 @@ static enum protocol parse_connect_url(const char *url_orig, char **ret_host,
         * Don't do destructive transforms as protocol code does
         * '[]' unwrapping in get_host_and_port()
         */
-       if (host[0] == '[') {
-               end = strchr(host + 1, ']');
-               if (end) {
-                       end++;
-               } else
-                       end = host;
-       } else
-               end = host;
+       end = host_end(&host, 0);
 
        if (protocol == PROTO_LOCAL)
                path = end;
@@ -663,17 +674,27 @@ struct child_process *git_connect(int fd[2], const char *url,
        signal(SIGCHLD, SIG_DFL);
 
        protocol = parse_connect_url(url, &hostandport, &path);
-       if (flags & CONNECT_DIAG_URL) {
+       if ((flags & CONNECT_DIAG_URL) && (protocol != PROTO_SSH)) {
                printf("Diag: url=%s\n", url ? url : "NULL");
                printf("Diag: protocol=%s\n", prot_name(protocol));
                printf("Diag: hostandport=%s\n", hostandport ? hostandport : "NULL");
                printf("Diag: path=%s\n", path ? path : "NULL");
                conn = NULL;
        } else if (protocol == PROTO_GIT) {
+               /*
+                * Set up virtual host information based on where we will
+                * connect, unless the user has overridden us in
+                * the environment.
+                */
+               char *target_host = getenv("GIT_OVERRIDE_VIRTUAL_HOST");
+               if (target_host)
+                       target_host = xstrdup(target_host);
+               else
+                       target_host = xstrdup(hostandport);
+
                /* These underlying connection commands die() if they
                 * cannot connect.
                 */
-               char *target_host = xstrdup(hostandport);
                if (git_use_proxy(hostandport))
                        conn = git_proxy_connect(fd, hostandport);
                else
@@ -705,28 +726,43 @@ struct child_process *git_connect(int fd[2], const char *url,
                        char *ssh_host = hostandport;
                        const char *port = NULL;
                        get_host_and_port(&ssh_host, &port);
-                       port = get_port_numeric(port);
 
-                       ssh = getenv("GIT_SSH_COMMAND");
-                       if (ssh) {
-                               conn->use_shell = 1;
-                               putty = 0;
-                       } else {
-                               ssh = getenv("GIT_SSH");
-                               if (!ssh)
-                                       ssh = "ssh";
-                               putty = !!strcasestr(ssh, "plink");
-                       }
+                       if (!port)
+                               port = get_port(ssh_host);
+
+                       if (flags & CONNECT_DIAG_URL) {
+                               printf("Diag: url=%s\n", url ? url : "NULL");
+                               printf("Diag: protocol=%s\n", prot_name(protocol));
+                               printf("Diag: userandhost=%s\n", ssh_host ? ssh_host : "NULL");
+                               printf("Diag: port=%s\n", port ? port : "NONE");
+                               printf("Diag: path=%s\n", path ? path : "NULL");
 
-                       argv_array_push(&conn->args, ssh);
-                       if (putty && !strcasestr(ssh, "tortoiseplink"))
-                               argv_array_push(&conn->args, "-batch");
-                       if (port) {
-                               /* P is for PuTTY, p is for OpenSSH */
-                               argv_array_push(&conn->args, putty ? "-P" : "-p");
-                               argv_array_push(&conn->args, port);
+                               free(hostandport);
+                               free(path);
+                               free(conn);
+                               return NULL;
+                       } else {
+                               ssh = getenv("GIT_SSH_COMMAND");
+                               if (ssh) {
+                                       conn->use_shell = 1;
+                                       putty = 0;
+                               } else {
+                                       ssh = getenv("GIT_SSH");
+                                       if (!ssh)
+                                               ssh = "ssh";
+                                       putty = !!strcasestr(ssh, "plink");
+                               }
+
+                               argv_array_push(&conn->args, ssh);
+                               if (putty && !strcasestr(ssh, "tortoiseplink"))
+                                       argv_array_push(&conn->args, "-batch");
+                               if (port) {
+                                       /* P is for PuTTY, p is for OpenSSH */
+                                       argv_array_push(&conn->args, putty ? "-P" : "-p");
+                                       argv_array_push(&conn->args, port);
+                               }
+                               argv_array_push(&conn->args, ssh_host);
                        }
-                       argv_array_push(&conn->args, ssh_host);
                } else {
                        /* remove repo-local variables from the environment */
                        conn->env = local_repo_env;
index cffb2b8d66c624b1267a512ca09a5fe6b62293fa..51d81d85990a061a6a95b67a153e335dc0fef0a8 100644 (file)
@@ -411,12 +411,9 @@ __git_refs_remotes ()
 
 __git_remotes ()
 {
-       local i IFS=$'\n' d="$(__gitdir)"
+       local d="$(__gitdir)"
        test -d "$d/remotes" && ls -1 "$d/remotes"
-       for i in $(git --git-dir="$d" config --get-regexp 'remote\..*\.url' 2>/dev/null); do
-               i="${i#remote.}"
-               echo "${i/.url*/}"
-       done
+       git --git-dir="$d" remote
 }
 
 __git_list_merge_strategies ()
@@ -2014,6 +2011,7 @@ _git_config ()
                color.status.changed
                color.status.header
                color.status.nobranch
+               color.status.unmerged
                color.status.untracked
                color.status.updated
                color.ui
index a1d38f035bea404aa9a5fa37518f0af21143dbf0..006134043a472edd54720d6d4237e9484476d3a3 100644 (file)
@@ -111,14 +111,23 @@ static void write_item(const char *what, LPCWSTR wbuf, int wlen)
  * Match an (optional) expected string and a delimiter in the target string,
  * consuming the matched text by updating the target pointer.
  */
-static int match_part(LPCWSTR *ptarget, LPCWSTR want, LPCWSTR delim)
+
+static LPCWSTR wcsstr_last(LPCWSTR str, LPCWSTR find)
+{
+       LPCWSTR res = NULL, pos;
+       for (pos = wcsstr(str, find); pos; pos = wcsstr(pos + 1, find))
+               res = pos;
+       return res;
+}
+
+static int match_part_with_last(LPCWSTR *ptarget, LPCWSTR want, LPCWSTR delim, int last)
 {
        LPCWSTR delim_pos, start = *ptarget;
        int len;
 
        /* find start of delimiter (or end-of-string if delim is empty) */
        if (*delim)
-               delim_pos = wcsstr(start, delim);
+               delim_pos = last ? wcsstr_last(start, delim) : wcsstr(start, delim);
        else
                delim_pos = start + wcslen(start);
 
@@ -138,6 +147,16 @@ static int match_part(LPCWSTR *ptarget, LPCWSTR want, LPCWSTR delim)
        return !want || (!wcsncmp(want, start, len) && !want[len]);
 }
 
+static int match_part(LPCWSTR *ptarget, LPCWSTR want, LPCWSTR delim)
+{
+       return match_part_with_last(ptarget, want, delim, 0);
+}
+
+static int match_part_last(LPCWSTR *ptarget, LPCWSTR want, LPCWSTR delim)
+{
+       return match_part_with_last(ptarget, want, delim, 1);
+}
+
 static int match_cred(const CREDENTIALW *cred)
 {
        LPCWSTR target = cred->TargetName;
@@ -146,7 +165,7 @@ static int match_cred(const CREDENTIALW *cred)
 
        return match_part(&target, L"git", L":") &&
                match_part(&target, protocol, L"://") &&
-               match_part(&target, wusername, L"@") &&
+               match_part_last(&target, wusername, L"@") &&
                match_part(&target, host, L"/") &&
                match_part(&target, path, L"");
 }
diff --git a/ctype.c b/ctype.c
index 0bfebb4e75866ba0e97713fab5394490290831c0..fc0225cebd1a4b43654772270826e06fd941a128 100644 (file)
--- a/ctype.c
+++ b/ctype.c
@@ -30,7 +30,7 @@ const unsigned char sane_ctype[256] = {
 };
 
 /* For case-insensitive kwset */
-const char tolower_trans_tbl[256] = {
+const unsigned char tolower_trans_tbl[256] = {
        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
index 54a03bd527a81485b498e33225ed54c54c0dbff7..9ee21877cd952a7aa47c793d877174d858488794 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -43,9 +43,6 @@ static const char *base_path;
 static const char *interpolated_path;
 static int base_path_relaxed;
 
-/* Flag indicating client sent extra args. */
-static int saw_extended_args;
-
 /* If defined, ~user notation is allowed and the string is inserted
  * after ~user/.  E.g. a request to git://host/~alice/frotz would
  * go to /home/alice/pub_git/frotz with --user-path=pub_git.
@@ -56,10 +53,28 @@ static const char *user_path;
 static unsigned int timeout;
 static unsigned int init_timeout;
 
-static char *hostname;
-static char *canon_hostname;
-static char *ip_address;
-static char *tcp_port;
+struct hostinfo {
+       struct strbuf hostname;
+       struct strbuf canon_hostname;
+       struct strbuf ip_address;
+       struct strbuf tcp_port;
+       unsigned int hostname_lookup_done:1;
+       unsigned int saw_extended_args:1;
+};
+
+static void lookup_hostname(struct hostinfo *hi);
+
+static const char *get_canon_hostname(struct hostinfo *hi)
+{
+       lookup_hostname(hi);
+       return hi->canon_hostname.buf;
+}
+
+static const char *get_ip_address(struct hostinfo *hi)
+{
+       lookup_hostname(hi);
+       return hi->ip_address.buf;
+}
 
 static void logreport(int priority, const char *err, va_list params)
 {
@@ -106,7 +121,43 @@ static void NORETURN daemon_die(const char *err, va_list params)
        exit(1);
 }
 
-static const char *path_ok(const char *directory)
+struct expand_path_context {
+       const char *directory;
+       struct hostinfo *hostinfo;
+};
+
+static size_t expand_path(struct strbuf *sb, const char *placeholder, void *ctx)
+{
+       struct expand_path_context *context = ctx;
+       struct hostinfo *hi = context->hostinfo;
+
+       switch (placeholder[0]) {
+       case 'H':
+               strbuf_addbuf(sb, &hi->hostname);
+               return 1;
+       case 'C':
+               if (placeholder[1] == 'H') {
+                       strbuf_addstr(sb, get_canon_hostname(hi));
+                       return 2;
+               }
+               break;
+       case 'I':
+               if (placeholder[1] == 'P') {
+                       strbuf_addstr(sb, get_ip_address(hi));
+                       return 2;
+               }
+               break;
+       case 'P':
+               strbuf_addbuf(sb, &hi->tcp_port);
+               return 1;
+       case 'D':
+               strbuf_addstr(sb, context->directory);
+               return 1;
+       }
+       return 0;
+}
+
+static const char *path_ok(const char *directory, struct hostinfo *hi)
 {
        static char rpath[PATH_MAX];
        static char interp_path[PATH_MAX];
@@ -142,16 +193,13 @@ static const char *path_ok(const char *directory)
                        dir = rpath;
                }
        }
-       else if (interpolated_path && saw_extended_args) {
+       else if (interpolated_path && hi->saw_extended_args) {
                struct strbuf expanded_path = STRBUF_INIT;
-               struct strbuf_expand_dict_entry dict[6];
-
-               dict[0].placeholder = "H"; dict[0].value = hostname;
-               dict[1].placeholder = "CH"; dict[1].value = canon_hostname;
-               dict[2].placeholder = "IP"; dict[2].value = ip_address;
-               dict[3].placeholder = "P"; dict[3].value = tcp_port;
-               dict[4].placeholder = "D"; dict[4].value = directory;
-               dict[5].placeholder = NULL; dict[5].value = NULL;
+               struct expand_path_context context;
+
+               context.directory = directory;
+               context.hostinfo = hi;
+
                if (*dir != '/') {
                        /* Allow only absolute */
                        logerror("'%s': Non-absolute path denied (interpolated-path active)", dir);
@@ -159,7 +207,7 @@ static const char *path_ok(const char *directory)
                }
 
                strbuf_expand(&expanded_path, interpolated_path,
-                               strbuf_expand_dict_cb, &dict);
+                             expand_path, &context);
                strlcpy(interp_path, expanded_path.buf, PATH_MAX);
                strbuf_release(&expanded_path);
                loginfo("Interpolated dir '%s'", interp_path);
@@ -240,7 +288,8 @@ static int daemon_error(const char *dir, const char *msg)
 
 static const char *access_hook;
 
-static int run_access_hook(struct daemon_service *service, const char *dir, const char *path)
+static int run_access_hook(struct daemon_service *service, const char *dir,
+                          const char *path, struct hostinfo *hi)
 {
        struct child_process child = CHILD_PROCESS_INIT;
        struct strbuf buf = STRBUF_INIT;
@@ -249,16 +298,14 @@ static int run_access_hook(struct daemon_service *service, const char *dir, cons
        char *eol;
        int seen_errors = 0;
 
-#define STRARG(x) ((x) ? (x) : "")
        *arg++ = access_hook;
        *arg++ = service->name;
        *arg++ = path;
-       *arg++ = STRARG(hostname);
-       *arg++ = STRARG(canon_hostname);
-       *arg++ = STRARG(ip_address);
-       *arg++ = STRARG(tcp_port);
+       *arg++ = hi->hostname.buf;
+       *arg++ = get_canon_hostname(hi);
+       *arg++ = get_ip_address(hi);
+       *arg++ = hi->tcp_port.buf;
        *arg = NULL;
-#undef STRARG
 
        child.use_shell = 1;
        child.argv = argv;
@@ -302,7 +349,8 @@ static int run_access_hook(struct daemon_service *service, const char *dir, cons
        return -1;
 }
 
-static int run_service(const char *dir, struct daemon_service *service)
+static int run_service(const char *dir, struct daemon_service *service,
+                      struct hostinfo *hi)
 {
        const char *path;
        int enabled = service->enabled;
@@ -316,7 +364,7 @@ static int run_service(const char *dir, struct daemon_service *service)
                return daemon_error(dir, "service not enabled");
        }
 
-       if (!(path = path_ok(dir)))
+       if (!(path = path_ok(dir, hi)))
                return daemon_error(dir, "no such repository");
 
        /*
@@ -352,7 +400,7 @@ static int run_service(const char *dir, struct daemon_service *service)
         * Optionally, a hook can choose to deny access to the
         * repository depending on the phase of the moon.
         */
-       if (access_hook && run_access_hook(service, dir, path))
+       if (access_hook && run_access_hook(service, dir, path, hi))
                return -1;
 
        /*
@@ -484,17 +532,47 @@ static void parse_host_and_port(char *hostport, char **host,
        }
 }
 
+/*
+ * Sanitize a string from the client so that it's OK to be inserted into a
+ * filesystem path. Specifically, we disallow slashes, runs of "..", and
+ * trailing and leading dots, which means that the client cannot escape
+ * our base path via ".." traversal.
+ */
+static void sanitize_client(struct strbuf *out, const char *in)
+{
+       for (; *in; in++) {
+               if (*in == '/')
+                       continue;
+               if (*in == '.' && (!out->len || out->buf[out->len - 1] == '.'))
+                       continue;
+               strbuf_addch(out, *in);
+       }
+
+       while (out->len && out->buf[out->len - 1] == '.')
+               strbuf_setlen(out, out->len - 1);
+}
+
+/*
+ * Like sanitize_client, but we also perform any canonicalization
+ * to make life easier on the admin.
+ */
+static void canonicalize_client(struct strbuf *out, const char *in)
+{
+       sanitize_client(out, in);
+       strbuf_tolower(out);
+}
+
 /*
  * Read the host as supplied by the client connection.
  */
-static void parse_host_arg(char *extra_args, int buflen)
+static void parse_host_arg(struct hostinfo *hi, char *extra_args, int buflen)
 {
        char *val;
        int vallen;
        char *end = extra_args + buflen;
 
        if (extra_args < end && *extra_args) {
-               saw_extended_args = 1;
+               hi->saw_extended_args = 1;
                if (strncasecmp("host=", extra_args, 5) == 0) {
                        val = extra_args + 5;
                        vallen = strlen(val) + 1;
@@ -503,12 +581,10 @@ static void parse_host_arg(char *extra_args, int buflen)
                                char *host;
                                char *port;
                                parse_host_and_port(val, &host, &port);
-                               if (port) {
-                                       free(tcp_port);
-                                       tcp_port = xstrdup(port);
-                               }
-                               free(hostname);
-                               hostname = xstrdup_tolower(host);
+                               if (port)
+                                       sanitize_client(&hi->tcp_port, port);
+                               canonicalize_client(&hi->hostname, host);
+                               hi->hostname_lookup_done = 0;
                        }
 
                        /* On to the next one */
@@ -517,11 +593,14 @@ static void parse_host_arg(char *extra_args, int buflen)
                if (extra_args < end && *extra_args)
                        die("Invalid request");
        }
+}
 
-       /*
-        * Locate canonical hostname and its IP address.
-        */
-       if (hostname) {
+/*
+ * Locate canonical hostname and its IP address.
+ */
+static void lookup_hostname(struct hostinfo *hi)
+{
+       if (!hi->hostname_lookup_done && hi->hostname.len) {
 #ifndef NO_IPV6
                struct addrinfo hints;
                struct addrinfo *ai;
@@ -531,18 +610,20 @@ static void parse_host_arg(char *extra_args, int buflen)
                memset(&hints, 0, sizeof(hints));
                hints.ai_flags = AI_CANONNAME;
 
-               gai = getaddrinfo(hostname, NULL, &hints, &ai);
+               gai = getaddrinfo(hi->hostname.buf, NULL, &hints, &ai);
                if (!gai) {
                        struct sockaddr_in *sin_addr = (void *)ai->ai_addr;
 
                        inet_ntop(AF_INET, &sin_addr->sin_addr,
                                  addrbuf, sizeof(addrbuf));
-                       free(ip_address);
-                       ip_address = xstrdup(addrbuf);
+                       strbuf_addstr(&hi->ip_address, addrbuf);
 
-                       free(canon_hostname);
-                       canon_hostname = xstrdup(ai->ai_canonname ?
-                                                ai->ai_canonname : ip_address);
+                       if (ai->ai_canonname)
+                               sanitize_client(&hi->canon_hostname,
+                                               ai->ai_canonname);
+                       else
+                               strbuf_addbuf(&hi->canon_hostname,
+                                             &hi->ip_address);
 
                        freeaddrinfo(ai);
                }
@@ -552,7 +633,7 @@ static void parse_host_arg(char *extra_args, int buflen)
                char **ap;
                static char addrbuf[HOST_NAME_MAX + 1];
 
-               hent = gethostbyname(hostname);
+               hent = gethostbyname(hostname.buf);
                if (hent) {
                        ap = hent->h_addr_list;
                        memset(&sa, 0, sizeof sa);
@@ -563,21 +644,39 @@ static void parse_host_arg(char *extra_args, int buflen)
                        inet_ntop(hent->h_addrtype, &sa.sin_addr,
                                  addrbuf, sizeof(addrbuf));
 
-                       free(canon_hostname);
-                       canon_hostname = xstrdup(hent->h_name);
-                       free(ip_address);
-                       ip_address = xstrdup(addrbuf);
+                       sanitize_client(&hi->canon_hostname, hent->h_name);
+                       strbuf_addstr(&hi->ip_address, addrbuf);
                }
 #endif
+               hi->hostname_lookup_done = 1;
        }
 }
 
+static void hostinfo_init(struct hostinfo *hi)
+{
+       memset(hi, 0, sizeof(*hi));
+       strbuf_init(&hi->hostname, 0);
+       strbuf_init(&hi->canon_hostname, 0);
+       strbuf_init(&hi->ip_address, 0);
+       strbuf_init(&hi->tcp_port, 0);
+}
+
+static void hostinfo_clear(struct hostinfo *hi)
+{
+       strbuf_release(&hi->hostname);
+       strbuf_release(&hi->canon_hostname);
+       strbuf_release(&hi->ip_address);
+       strbuf_release(&hi->tcp_port);
+}
 
 static int execute(void)
 {
        char *line = packet_buffer;
        int pktlen, len, i;
        char *addr = getenv("REMOTE_ADDR"), *port = getenv("REMOTE_PORT");
+       struct hostinfo hi;
+
+       hostinfo_init(&hi);
 
        if (addr)
                loginfo("Connection from %s:%s", addr, port);
@@ -596,14 +695,8 @@ static int execute(void)
                pktlen--;
        }
 
-       free(hostname);
-       free(canon_hostname);
-       free(ip_address);
-       free(tcp_port);
-       hostname = canon_hostname = ip_address = tcp_port = NULL;
-
        if (len != pktlen)
-               parse_host_arg(line + len + 1, pktlen - len - 1);
+               parse_host_arg(&hi, line + len + 1, pktlen - len - 1);
 
        for (i = 0; i < ARRAY_SIZE(daemon_service); i++) {
                struct daemon_service *s = &(daemon_service[i]);
@@ -616,10 +709,13 @@ static int execute(void)
                         * Note: The directory here is probably context sensitive,
                         * and might depend on the actual service being performed.
                         */
-                       return run_service(arg, s);
+                       int rc = run_service(arg, s, &hi);
+                       hostinfo_clear(&hi);
+                       return rc;
                }
        }
 
+       hostinfo_clear(&hi);
        logerror("Protocol error: '%s'", line);
        return -1;
 }
index 875aff864391ed037627462ac39c314f248b5ae6..a85c4971ac8ece6397c05d0674bbac8c75cf219f 100644 (file)
@@ -101,6 +101,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
                struct cache_entry *ce = active_cache[i];
                int changed;
                unsigned dirty_submodule = 0;
+               const unsigned char *old_sha1, *new_sha1;
 
                if (diff_can_quit_early(&revs->diffopt))
                        break;
@@ -224,9 +225,12 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
                                continue;
                }
                oldmode = ce->ce_mode;
+               old_sha1 = ce->sha1;
+               new_sha1 = changed ? null_sha1 : ce->sha1;
                diff_change(&revs->diffopt, oldmode, newmode,
-                           ce->sha1, (changed ? null_sha1 : ce->sha1),
-                           !is_null_sha1(ce->sha1), (changed ? 0 : !is_null_sha1(ce->sha1)),
+                           old_sha1, new_sha1,
+                           !is_null_sha1(old_sha1),
+                           !is_null_sha1(new_sha1),
                            ce->name, 0, dirty_submodule);
 
        }
diff --git a/diff.c b/diff.c
index d1bd534caeaf662b0ee0d547d3aa2012310fff57..7500c5509550ccd9a86d620e06c51a71d61f8b6c 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -2093,7 +2093,6 @@ static unsigned char *deflate_it(char *data,
        unsigned char *deflated;
        git_zstream stream;
 
-       memset(&stream, 0, sizeof(stream));
        git_deflate_init(&stream, zlib_compression_level);
        bound = git_deflate_bound(&stream, size);
        deflated = xmalloc(bound);
@@ -4541,7 +4540,7 @@ void diff_flush(struct diff_options *options)
                        show_stats(&diffstat, options);
                if (output_format & DIFF_FORMAT_SHORTSTAT)
                        show_shortstats(&diffstat, options);
-               if (output_format & DIFF_FORMAT_DIRSTAT)
+               if (output_format & DIFF_FORMAT_DIRSTAT && dirstat_by_line)
                        show_dirstat_by_line(&diffstat, options);
                free_diffstat_info(&diffstat);
                separator++;
index 4e132f1fdb68ed3c930ca8224a5403c9b406cc3b..af1fe08861e6862985ac8fb9311b17568cb9e547 100644 (file)
@@ -15,8 +15,7 @@ static struct diff_rename_dst {
 } *rename_dst;
 static int rename_dst_nr, rename_dst_alloc;
 
-static struct diff_rename_dst *locate_rename_dst(struct diff_filespec *two,
-                                                int insert_ok)
+static int find_rename_dst(struct diff_filespec *two)
 {
        int first, last;
 
@@ -27,16 +26,33 @@ static struct diff_rename_dst *locate_rename_dst(struct diff_filespec *two,
                struct diff_rename_dst *dst = &(rename_dst[next]);
                int cmp = strcmp(two->path, dst->two->path);
                if (!cmp)
-                       return dst;
+                       return next;
                if (cmp < 0) {
                        last = next;
                        continue;
                }
                first = next+1;
        }
-       /* not found */
-       if (!insert_ok)
-               return NULL;
+       return -first - 1;
+}
+
+static struct diff_rename_dst *locate_rename_dst(struct diff_filespec *two)
+{
+       int ofs = find_rename_dst(two);
+       return ofs < 0 ? NULL : &rename_dst[ofs];
+}
+
+/*
+ * Returns 0 on success, -1 if we found a duplicate.
+ */
+static int add_rename_dst(struct diff_filespec *two)
+{
+       int first = find_rename_dst(two);
+
+       if (first >= 0)
+               return -1;
+       first = -first - 1;
+
        /* insert to make it at "first" */
        ALLOC_GROW(rename_dst, rename_dst_nr + 1, rename_dst_alloc);
        rename_dst_nr++;
@@ -46,7 +62,7 @@ static struct diff_rename_dst *locate_rename_dst(struct diff_filespec *two,
        rename_dst[first].two = alloc_filespec(two->path);
        fill_filespec(rename_dst[first].two, two->sha1, two->sha1_valid, two->mode);
        rename_dst[first].pair = NULL;
-       return &(rename_dst[first]);
+       return 0;
 }
 
 /* Table of rename/copy src files */
@@ -450,8 +466,12 @@ void diffcore_rename(struct diff_options *options)
                        else if (!DIFF_OPT_TST(options, RENAME_EMPTY) &&
                                 is_empty_blob_sha1(p->two->sha1))
                                continue;
-                       else
-                               locate_rename_dst(p->two, 1);
+                       else if (add_rename_dst(p->two) < 0) {
+                               warning("skipping rename detection, detected"
+                                       " duplicate destination '%s'",
+                                       p->two->path);
+                               goto cleanup;
+                       }
                }
                else if (!DIFF_OPT_TST(options, RENAME_EMPTY) &&
                         is_empty_blob_sha1(p->one->sha1))
@@ -582,8 +602,7 @@ void diffcore_rename(struct diff_options *options)
                         * We would output this create record if it has
                         * not been turned into a rename/copy already.
                         */
-                       struct diff_rename_dst *dst =
-                               locate_rename_dst(p->two, 0);
+                       struct diff_rename_dst *dst = locate_rename_dst(p->two);
                        if (dst && dst->pair) {
                                diff_q(&outq, dst->pair);
                                pair_to_free = p;
@@ -613,8 +632,7 @@ void diffcore_rename(struct diff_options *options)
                         */
                        if (DIFF_PAIR_BROKEN(p)) {
                                /* broken delete */
-                               struct diff_rename_dst *dst =
-                                       locate_rename_dst(p->one, 0);
+                               struct diff_rename_dst *dst = locate_rename_dst(p->one);
                                if (dst && dst->pair)
                                        /* counterpart is now rename/copy */
                                        pair_to_free = p;
index f6ad190a038a55e39a0b8b135c995413192f80e3..13c6e20412591ed3bc56b38b17419a540264f6c5 100644 (file)
@@ -47,7 +47,8 @@ static inline uint32_t ewah_bit_popcount64(uint64_t x)
        return (x * 0x0101010101010101ULL) >> 56;
 }
 
-#ifdef __GNUC__
+/* __builtin_ctzll was not available until 3.4.0 */
+#if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3  && __GNUC_MINOR > 3))
 #define ewah_bit_ctz64(x) __builtin_ctzll(x)
 #else
 static inline int ewah_bit_ctz64(uint64_t x)
index d0bd285a16d0161b50d0b43e0315f8fa003e0e32..e78ca107b3d66d7e537c86eb10dc7503be8681b9 100644 (file)
@@ -947,9 +947,12 @@ static void unkeep_all_packs(void)
 
 static void end_packfile(void)
 {
-       if (!pack_data)
+       static int running;
+
+       if (running || !pack_data)
                return;
 
+       running = 1;
        clear_delta_base_cache();
        if (object_count) {
                struct packed_git *new_p;
@@ -999,6 +1002,7 @@ static void end_packfile(void)
        }
        free(pack_data);
        pack_data = NULL;
+       running = 0;
 
        /* We can't carry a delta across packfiles. */
        strbuf_release(&last_blob.data);
@@ -1058,7 +1062,6 @@ static int store_object(
        } else
                delta = NULL;
 
-       memset(&s, 0, sizeof(s));
        git_deflate_init(&s, pack_compression_level);
        if (delta) {
                s.next_in = delta;
@@ -1086,7 +1089,6 @@ static int store_object(
                        free(delta);
                        delta = NULL;
 
-                       memset(&s, 0, sizeof(s));
                        git_deflate_init(&s, pack_compression_level);
                        s.next_in = (void *)dat->buf;
                        s.avail_in = dat->len;
@@ -1186,7 +1188,6 @@ static void stream_blob(uintmax_t len, unsigned char *sha1out, uintmax_t mark)
 
        crc32_begin(pack_file);
 
-       memset(&s, 0, sizeof(s));
        git_deflate_init(&s, pack_compression_level);
 
        hdrlen = encode_in_pack_object_header(OBJ_BLOB, len, out_buf);
@@ -1716,7 +1717,7 @@ static int update_branch(struct branch *b)
        transaction = ref_transaction_begin(&err);
        if (!transaction ||
            ref_transaction_update(transaction, b->name, b->sha1, old_sha1,
-                                  0, 1, msg, &err) ||
+                                  0, msg, &err) ||
            ref_transaction_commit(transaction, &err)) {
                ref_transaction_free(transaction);
                error("%s", err.buf);
@@ -1756,8 +1757,8 @@ static void dump_tags(void)
                strbuf_reset(&ref_name);
                strbuf_addf(&ref_name, "refs/tags/%s", t->name);
 
-               if (ref_transaction_update(transaction, ref_name.buf, t->sha1,
-                                          NULL, 0, 0, msg, &err)) {
+               if (ref_transaction_update(transaction, ref_name.buf,
+                                          t->sha1, NULL, 0, msg, &err)) {
                        failure |= error("%s", err.buf);
                        goto cleanup;
                }
index 8b2da4641f8b20ff3cc70c63636de878eec72470..7378ba287f0c449810250fb7b019f69e4f6a3497 100644 (file)
--- a/gettext.c
+++ b/gettext.c
 #      endif
 #endif
 
+/*
+ * Guess the user's preferred languages from the value in LANGUAGE environment
+ * variable and LC_MESSAGES locale category if NO_GETTEXT is not defined.
+ *
+ * The result can be a colon-separated list like "ko:ja:en".
+ */
+const char *get_preferred_languages(void)
+{
+       const char *retval;
+
+       retval = getenv("LANGUAGE");
+       if (retval && *retval)
+               return retval;
+
+#ifndef NO_GETTEXT
+       retval = setlocale(LC_MESSAGES, NULL);
+       if (retval && *retval &&
+               strcmp(retval, "C") &&
+               strcmp(retval, "POSIX"))
+               return retval;
+#endif
+
+       return NULL;
+}
+
 #ifdef GETTEXT_POISON
 int use_gettext_poison(void)
 {
index dc1722dd4bc6b1aa7d998cb055a40000c05a0b5e..33696a40b8a11262d090a2eec4dfdce0fed6af0f 100644 (file)
--- a/gettext.h
+++ b/gettext.h
@@ -89,4 +89,6 @@ const char *Q_(const char *msgid, const char *plu, unsigned long n)
 #define N_(msgid) (msgid)
 #endif
 
+const char *get_preferred_languages(void);
+
 #endif
index c7256741cc2a28f333d6a9be5f12e248df99ed5e..77876d433a1ba2384a690155b51dac8118fa27b4 100755 (executable)
@@ -515,6 +515,9 @@ sub error_msg {
 sub list_and_choose {
        my ($opts, @stuff) = @_;
        my (@chosen, @return);
+       if (!@stuff) {
+           return @return;
+       }
        my $i;
        my @prefixes = find_unique_prefixes(@stuff) unless $opts->{LIST_ONLY};
 
@@ -725,6 +728,8 @@ sub add_untracked_cmd {
        if (@add) {
                system(qw(git update-index --add --), @add);
                say_n_paths('added', @add);
+       } else {
+               print "No untracked files.\n";
        }
        print "\n";
 }
index 68c07af9d465ce92d78b11d347ae0396299a1855..bc8fc8cf854e96badfdf4d96673d33b799207ff3 100644 (file)
 #else
 #include <poll.h>
 #endif
+#ifdef HAVE_BSD_SYSCTL
+#include <sys/sysctl.h>
+#endif
 
 #if defined(__MINGW32__)
 /* pull in Windows compatibility stuff */
 typedef long intptr_t;
 typedef unsigned long uintptr_t;
 #endif
-#if defined(__CYGWIN__)
-#undef _XOPEN_SOURCE
-#include <grp.h>
-#define _XOPEN_SOURCE 600
-#else
 #undef _ALL_SOURCE /* AIX 5.3L defines a struct list with _ALL_SOURCE. */
 #include <grp.h>
 #define _ALL_SOURCE 1
 #endif
-#endif
 
 /* used on Mac OS X */
 #ifdef PRECOMPOSE_UNICODE
@@ -212,12 +209,15 @@ extern char *gitbasename(char *);
 #endif
 
 #ifndef NO_OPENSSL
+#ifdef __APPLE__
 #define __AVAILABILITY_MACROS_USES_AVAILABILITY 0
-#define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_6
+#include <AvailabilityMacros.h>
+#undef DEPRECATED_ATTRIBUTE
+#define DEPRECATED_ATTRIBUTE
+#undef __AVAILABILITY_MACROS_USES_AVAILABILITY
+#endif
 #include <openssl/ssl.h>
 #include <openssl/err.h>
-#undef MAC_OS_X_VERSION_MIN_REQUIRED
-#undef __AVAILABILITY_MACROS_USES_AVAILABILITY
 #ifdef NO_HMAC_CTX_CLEANUP
 #define HMAC_CTX_cleanup HMAC_cleanup
 #endif
@@ -691,7 +691,7 @@ static inline size_t xsize_t(off_t len)
 }
 
 /* in ctype.c, for kwset users */
-extern const char tolower_trans_tbl[256];
+extern const unsigned char tolower_trans_tbl[256];
 
 /* Sane ctype - no locale, and works with signed chars */
 #undef isascii
@@ -879,4 +879,8 @@ struct tm *git_gmtime_r(const time_t *, struct tm *);
 #define USE_PARENS_AROUND_GETTEXT_N 1
 #endif
 
+#ifndef SHELL_PATH
+# define SHELL_PATH "/bin/sh"
+#endif
+
 #endif
index 513efa662e86cb157b8690bfb025556fa0c836f0..47e38f34c3a871349630660e6e3387d554c29d36 100755 (executable)
@@ -20,6 +20,7 @@ start          start the web server
 restart        restart the web server
 "
 
+SUBDIRECTORY_OK=Yes
 . git-sh-setup
 
 fqgitdir="$GIT_DIR"
@@ -204,7 +205,7 @@ webrick_conf () {
        # actual gitweb.cgi using a shell script to force it
   wrapper="$fqgitdir/gitweb/$httpd/wrapper.sh"
        cat > "$wrapper" <<EOF
-#!/bin/sh
+#!@SHELL_PATH@
 # we use this shell script wrapper around the real gitweb.cgi since
 # there appears to be no other way to pass arbitrary environment variables
 # into the CGI process
index c6a4629cbc2b69d3e6dfabe5e124384fe7fe611c..f7deeb096e24f4de69bdfe08f0aa35ebf170577a 100644 (file)
@@ -961,14 +961,13 @@ else
        revisions=$onto...$orig_head
        shortrevisions=$shorthead
 fi
-git rev-list $merges_option --pretty=oneline --abbrev-commit \
-       --abbrev=7 --reverse --left-right --topo-order \
+git rev-list $merges_option --pretty=oneline --reverse --left-right --topo-order \
        $revisions ${restrict_revision+^$restrict_revision} | \
        sed -n "s/^>//p" |
-while read -r shortsha1 rest
+while read -r sha1 rest
 do
 
-       if test -z "$keep_empty" && is_empty_commit $shortsha1 && ! is_merge_commit $shortsha1
+       if test -z "$keep_empty" && is_empty_commit $sha1 && ! is_merge_commit $sha1
        then
                comment_out="$comment_char "
        else
@@ -977,9 +976,8 @@ do
 
        if test t != "$preserve_merges"
        then
-               printf '%s\n' "${comment_out}pick $shortsha1 $rest" >>"$todo"
+               printf '%s\n' "${comment_out}pick $sha1 $rest" >>"$todo"
        else
-               sha1=$(git rev-parse $shortsha1)
                if test -z "$rebase_root"
                then
                        preserve=t
@@ -996,7 +994,7 @@ do
                if test f = "$preserve"
                then
                        touch "$rewritten"/$sha1
-                       printf '%s\n' "${comment_out}pick $shortsha1 $rest" >>"$todo"
+                       printf '%s\n' "${comment_out}pick $sha1 $rest" >>"$todo"
                fi
        fi
 done
@@ -1020,8 +1018,8 @@ then
                        # just the history of its first-parent for others that will
                        # be rebasing on top of it
                        git rev-list --parents -1 $rev | cut -d' ' -s -f2 > "$dropped"/$rev
-                       short=$(git rev-list -1 --abbrev-commit --abbrev=7 $rev)
-                       sane_grep -v "^[a-z][a-z]* $short" <"$todo" > "${todo}2" ; mv "${todo}2" "$todo"
+                       sha1=$(git rev-list -1 $rev)
+                       sane_grep -v "^[a-z][a-z]* $sha1" <"$todo" > "${todo}2" ; mv "${todo}2" "$todo"
                        rm "$rewritten"/$rev
                fi
        done
@@ -1032,10 +1030,11 @@ test -n "$autosquash" && rearrange_squash "$todo"
 test -n "$cmd" && add_exec_commands "$todo"
 
 todocount=$(git stripspace --strip-comments <"$todo" | wc -l)
+todocount=${todocount##* }
 
 cat >>"$todo" <<EOF
 
-$comment_char Rebase $shortrevisions onto $shortonto ($todocount TODO item(s))
+$comment_char Rebase $shortrevisions onto $shortonto ($todocount command(s))
 EOF
 append_todo_help
 git stripspace --comment-lines >>"$todo" <<\EOF
@@ -1054,6 +1053,7 @@ has_action "$todo" ||
        return 2
 
 cp "$todo" "$todo".backup
+collapse_todo_ids
 git_sequence_editor "$todo" ||
        die_abort "Could not execute editor"
 
index a9c75a2360fec7a9ce5f22877a471f70bc405ff1..752c763eb666e197304efbc7ea006325a36ff870 100755 (executable)
@@ -1,7 +1,13 @@
 #!/bin/sh
 # Copyright (c) 2012 Felipe Contreras
 
-alias=$1
+# The first argument can be a url when the fetch/push command was a url
+# instead of a configured remote. In this case, use a generic alias.
+if test "$1" = "testgit::$2"; then
+       alias=_
+else
+       alias=$1
+fi
 url=$2
 
 dir="$GIT_DIR/testgit/$alias"
index 3092ab356c765cd593d2a988d020665c8b626ea1..e1e9b1460ced5f660b32796890df7336bc3d01af 100755 (executable)
@@ -299,6 +299,7 @@ sub signal_handler {
                    "bcc=s" => \@bcclist,
                    "no-bcc" => \$no_bcc,
                    "chain-reply-to!" => \$chain_reply_to,
+                   "no-chain-reply-to" => sub {$chain_reply_to = 0},
                    "smtp-server=s" => \$smtp_server,
                    "smtp-server-option=s" => \@smtp_server_options,
                    "smtp-server-port=s" => \$smtp_server_port,
@@ -311,25 +312,34 @@ sub signal_handler {
                    "smtp-domain:s" => \$smtp_domain,
                    "identity=s" => \$identity,
                    "annotate!" => \$annotate,
+                   "no-annotate" => sub {$annotate = 0},
                    "compose" => \$compose,
                    "quiet" => \$quiet,
                    "cc-cmd=s" => \$cc_cmd,
                    "suppress-from!" => \$suppress_from,
+                   "no-suppress-from" => sub {$suppress_from = 0},
                    "suppress-cc=s" => \@suppress_cc,
                    "signed-off-cc|signed-off-by-cc!" => \$signed_off_by_cc,
+                   "no-signed-off-cc|no-signed-off-by-cc" => sub {$signed_off_by_cc = 0},
                    "cc-cover|cc-cover!" => \$cover_cc,
+                   "no-cc-cover" => sub {$cover_cc = 0},
                    "to-cover|to-cover!" => \$cover_to,
+                   "no-to-cover" => sub {$cover_to = 0},
                    "confirm=s" => \$confirm,
                    "dry-run" => \$dry_run,
                    "envelope-sender=s" => \$envelope_sender,
                    "thread!" => \$thread,
+                   "no-thread" => sub {$thread = 0},
                    "validate!" => \$validate,
+                   "no-validate" => sub {$validate = 0},
                    "transfer-encoding=s" => \$target_xfer_encoding,
                    "format-patch!" => \$format_patch,
+                   "no-format-patch" => sub {$format_patch = 0},
                    "8bit-encoding=s" => \$auto_8bit_encoding,
                    "compose-encoding=s" => \$compose_encoding,
                    "force" => \$force,
                    "xmailer!" => \$use_xmailer,
+                   "no-xmailer" => sub {$use_xmailer = 0},
         );
 
 usage() if $help;
@@ -752,6 +762,7 @@ sub file_declares_8bit_cte {
                print "    $f\n";
        }
        $auto_8bit_encoding = ask("Which 8bit encoding should I declare [UTF-8]? ",
+                                 valid_re => qr/.{4}/, confirm_only => 1,
                                  default => "UTF-8");
 }
 
index 9245abfd4263881bdd6d0f21f648b46201b52a2d..36797c3c00f4890cfb6f176f298e050da7eb5a34 100755 (executable)
@@ -423,7 +423,7 @@ cmd_add()
                sed -e '
                        s|//*|/|g
                        s|^\(\./\)*||
-                       s|/\./|/|g
+                       s|/\(\./\)*|/|g
                        :start
                        s|\([^/]*\)/\.\./||
                        tstart
index 32d109ebdf89399ac0d834cc98393324dfca7850..36f7240c99249198512689ffecdd9c95f06b8eff 100755 (executable)
 $VERSION = '@@GIT_VERSION@@';
 
 use Carp qw/croak/;
-use Digest::MD5;
-use IO::File qw//;
 use File::Basename qw/dirname basename/;
 use File::Path qw/mkpath/;
 use File::Spec;
-use File::Find;
 use Getopt::Long qw/:config gnu_getopt no_ignore_case auto_abbrev/;
-use IPC::Open3;
 use Memoize;
 
 use Git::SVN;
@@ -298,7 +294,6 @@ sub _req_svn {
                {} ],
 );
 
-use Term::ReadLine;
 package FakeTerm;
 sub new {
        my ($class, $reason) = @_;
@@ -313,6 +308,7 @@ package main;
 my $term;
 sub term_init {
        $term = eval {
+               require Term::ReadLine;
                $ENV{"GIT_SVN_NOTTY"}
                        ? new Term::ReadLine 'git-svn', \*STDIN, \*STDOUT
                        : new Term::ReadLine 'git-svn';
@@ -1173,6 +1169,7 @@ sub cmd_branch {
        }
 
        ::_req_svn();
+       require SVN::Client;
 
        my $ctx = SVN::Client->new(
                config => SVN::Core::config_get_config(
@@ -1693,11 +1690,13 @@ sub cmd_reset {
 }
 
 sub cmd_gc {
+       require File::Find;
        if (!can_compress()) {
                warn "Compress::Zlib could not be found; unhandled.log " .
                     "files will not be compressed.\n";
        }
-       find({ wanted => \&gc_directory, no_chdir => 1}, "$ENV{GIT_DIR}/svn");
+       File::Find::find({ wanted => \&gc_directory, no_chdir => 1},
+                        "$ENV{GIT_DIR}/svn");
 }
 
 ########################### utility functions #########################
@@ -2122,6 +2121,7 @@ sub find_file_type_and_diff_status {
 sub md5sum {
        my $arg = shift;
        my $ref = ref $arg;
+       require Digest::MD5;
        my $md5 = Digest::MD5->new();
         if ($ref eq 'GLOB' || $ref eq 'IO::File' || $ref eq 'File::Temp') {
                $md5->addfile($arg) or croak $!;
@@ -2148,6 +2148,7 @@ sub gc_directory {
                        $gz->gzwrite($str) or
                                die "Unable to write: ".$gz->gzerror()."!\n";
                }
+               no warnings 'once'; # $File::Find::name would warn
                unlink $_ or die "unlink $File::Find::name: $!\n";
        } elsif (-f $_ && basename($_) eq "index") {
                unlink $_ or die "unlink $_: $!\n";
diff --git a/git.c b/git.c
index 8c7ee9c83000765afa3808f3dd0941aa484ca1ec..42a4ee57843f569fb754121f01bb8c46feee2fd3 100644 (file)
--- a/git.c
+++ b/git.c
@@ -204,10 +204,12 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
                                fprintf(stderr, "No directory given for -C.\n" );
                                usage(git_usage_string);
                        }
-                       if (chdir((*argv)[1]))
-                               die_errno("Cannot change to '%s'", (*argv)[1]);
-                       if (envchanged)
-                               *envchanged = 1;
+                       if ((*argv)[1][0]) {
+                               if (chdir((*argv)[1]))
+                                       die_errno("Cannot change to '%s'", (*argv)[1]);
+                               if (envchanged)
+                                       *envchanged = 1;
+                       }
                        (*argv)++;
                        (*argc)--;
                } else {
@@ -618,6 +620,7 @@ int main(int argc, char **av)
 {
        const char **argv = (const char **) av;
        const char *cmd;
+       int done_help = 0;
 
        startup_info = &git_startup_info;
 
@@ -680,9 +683,7 @@ int main(int argc, char **av)
        setup_path();
 
        while (1) {
-               static int done_help = 0;
-               static int was_alias = 0;
-               was_alias = run_argv(&argc, &argv);
+               int was_alias = run_argv(&argc, &argv);
                if (errno != ENOENT)
                        break;
                if (was_alias) {
diff --git a/hex.c b/hex.c
index 9ebc050637532765b775cbd8e3b92951a67ea333..cfd9d722fd92f137a79ee2bf6be44b4b393c6da6 100644 (file)
--- a/hex.c
+++ b/hex.c
@@ -59,7 +59,7 @@ int get_sha1_hex(const char *hex, unsigned char *sha1)
 char *sha1_to_hex(const unsigned char *sha1)
 {
        static int bufno;
-       static char hexbuffer[4][50];
+       static char hexbuffer[4][41];
        static const char hex[] = "0123456789abcdef";
        char *buffer = hexbuffer[3 & ++bufno], *buf = buffer;
        int i;
index 0beb7ab67ffc93a6c8fe8517d711945e2c033b7d..bfb1c9605b46e8308e91a80c38643ea920cd4d1b 100644 (file)
@@ -365,7 +365,6 @@ static void start_put(struct transfer_request *request)
        hdrlen = sprintf(hdr, "%s %lu", typename(type), len) + 1;
 
        /* Set it up */
-       memset(&stream, 0, sizeof(stream));
        git_deflate_init(&stream, zlib_compression_level);
        size = git_deflate_bound(&stream, len + hdrlen);
        strbuf_init(&request->buffer.buf, size);
diff --git a/http.c b/http.c
index 4ecf9e8f7b2ac87e96bc5faeaf9392d2b5248465..9c825afefdda70b8f8ccda0b9ed06e5d54333a50 100644 (file)
--- a/http.c
+++ b/http.c
@@ -8,6 +8,7 @@
 #include "credential.h"
 #include "version.h"
 #include "pkt-line.h"
+#include "gettext.h"
 
 int active_requests;
 int http_is_verbose;
@@ -71,6 +72,8 @@ static struct curl_slist *no_pragma_header;
 
 static struct active_request_slot *active_queue_head;
 
+static char *cached_accept_language;
+
 size_t fread_buffer(char *ptr, size_t eltsize, size_t nmemb, void *buffer_)
 {
        size_t size = eltsize * nmemb;
@@ -403,7 +406,9 @@ static CURL *get_curl_handle(void)
 
        if (curl_http_proxy) {
                curl_easy_setopt(result, CURLOPT_PROXY, curl_http_proxy);
+#if LIBCURL_VERSION_NUM >= 0x070a07
                curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
+#endif
        }
 
        set_curl_keepalive(result);
@@ -549,6 +554,9 @@ void http_cleanup(void)
                cert_auth.password = NULL;
        }
        ssl_cert_password_required = 0;
+
+       free(cached_accept_language);
+       cached_accept_language = NULL;
 }
 
 struct active_request_slot *get_active_slot(void)
@@ -995,6 +1003,116 @@ static void extract_content_type(struct strbuf *raw, struct strbuf *type,
                strbuf_addstr(charset, "ISO-8859-1");
 }
 
+static void write_accept_language(struct strbuf *buf)
+{
+       /*
+        * MAX_DECIMAL_PLACES must not be larger than 3. If it is larger than
+        * that, q-value will be smaller than 0.001, the minimum q-value the
+        * HTTP specification allows. See
+        * http://tools.ietf.org/html/rfc7231#section-5.3.1 for q-value.
+        */
+       const int MAX_DECIMAL_PLACES = 3;
+       const int MAX_LANGUAGE_TAGS = 1000;
+       const int MAX_ACCEPT_LANGUAGE_HEADER_SIZE = 4000;
+       char **language_tags = NULL;
+       int num_langs = 0;
+       const char *s = get_preferred_languages();
+       int i;
+       struct strbuf tag = STRBUF_INIT;
+
+       /* Don't add Accept-Language header if no language is preferred. */
+       if (!s)
+               return;
+
+       /*
+        * Split the colon-separated string of preferred languages into
+        * language_tags array.
+        */
+       do {
+               /* collect language tag */
+               for (; *s && (isalnum(*s) || *s == '_'); s++)
+                       strbuf_addch(&tag, *s == '_' ? '-' : *s);
+
+               /* skip .codeset, @modifier and any other unnecessary parts */
+               while (*s && *s != ':')
+                       s++;
+
+               if (tag.len) {
+                       num_langs++;
+                       REALLOC_ARRAY(language_tags, num_langs);
+                       language_tags[num_langs - 1] = strbuf_detach(&tag, NULL);
+                       if (num_langs >= MAX_LANGUAGE_TAGS - 1) /* -1 for '*' */
+                               break;
+               }
+       } while (*s++);
+
+       /* write Accept-Language header into buf */
+       if (num_langs) {
+               int last_buf_len = 0;
+               int max_q;
+               int decimal_places;
+               char q_format[32];
+
+               /* add '*' */
+               REALLOC_ARRAY(language_tags, num_langs + 1);
+               language_tags[num_langs++] = "*"; /* it's OK; this won't be freed */
+
+               /* compute decimal_places */
+               for (max_q = 1, decimal_places = 0;
+                    max_q < num_langs && decimal_places <= MAX_DECIMAL_PLACES;
+                    decimal_places++, max_q *= 10)
+                       ;
+
+               sprintf(q_format, ";q=0.%%0%dd", decimal_places);
+
+               strbuf_addstr(buf, "Accept-Language: ");
+
+               for (i = 0; i < num_langs; i++) {
+                       if (i > 0)
+                               strbuf_addstr(buf, ", ");
+
+                       strbuf_addstr(buf, language_tags[i]);
+
+                       if (i > 0)
+                               strbuf_addf(buf, q_format, max_q - i);
+
+                       if (buf->len > MAX_ACCEPT_LANGUAGE_HEADER_SIZE) {
+                               strbuf_remove(buf, last_buf_len, buf->len - last_buf_len);
+                               break;
+                       }
+
+                       last_buf_len = buf->len;
+               }
+       }
+
+       /* free language tags -- last one is a static '*' */
+       for (i = 0; i < num_langs - 1; i++)
+               free(language_tags[i]);
+       free(language_tags);
+}
+
+/*
+ * Get an Accept-Language header which indicates user's preferred languages.
+ *
+ * Examples:
+ *   LANGUAGE= -> ""
+ *   LANGUAGE=ko:en -> "Accept-Language: ko, en; q=0.9, *; q=0.1"
+ *   LANGUAGE=ko_KR.UTF-8:sr@latin -> "Accept-Language: ko-KR, sr; q=0.9, *; q=0.1"
+ *   LANGUAGE=ko LANG=en_US.UTF-8 -> "Accept-Language: ko, *; q=0.1"
+ *   LANGUAGE= LANG=en_US.UTF-8 -> "Accept-Language: en-US, *; q=0.1"
+ *   LANGUAGE= LANG=C -> ""
+ */
+static const char *get_accept_language(void)
+{
+       if (!cached_accept_language) {
+               struct strbuf buf = STRBUF_INIT;
+               write_accept_language(&buf);
+               if (buf.len > 0)
+                       cached_accept_language = strbuf_detach(&buf, NULL);
+       }
+
+       return cached_accept_language;
+}
 
 /* http_request() targets */
 #define HTTP_REQUEST_STRBUF    0
@@ -1008,6 +1126,7 @@ static int http_request(const char *url,
        struct slot_results results;
        struct curl_slist *headers = NULL;
        struct strbuf buf = STRBUF_INIT;
+       const char *accept_language;
        int ret;
 
        slot = get_active_slot();
@@ -1033,6 +1152,11 @@ static int http_request(const char *url,
                                         fwrite_buffer);
        }
 
+       accept_language = get_accept_language();
+
+       if (accept_language)
+               headers = curl_slist_append(headers, accept_language);
+
        strbuf_addstr(&buf, "Pragma:");
        if (options && options->no_cache)
                strbuf_addstr(&buf, " no-cache");
@@ -1250,7 +1374,7 @@ static int fetch_and_setup_pack_index(struct packed_git **packs_head,
        int ret;
 
        if (has_pack_index(sha1)) {
-               new_pack = parse_pack_index(sha1, NULL);
+               new_pack = parse_pack_index(sha1, sha1_pack_index_name(sha1));
                if (!new_pack)
                        return -1; /* parse_pack_index() already issued error message */
                goto add_pack;
index d69887da5a8530b204a5f5baf7081787224fc3bd..37ac4aa86a740ecc8430afff3b9d3c7a0c753a34 100644 (file)
@@ -34,8 +34,16 @@ typedef void *SSL;
 #include "http.h"
 #endif
 
+#if defined(USE_CURL_FOR_IMAP_SEND) && defined(NO_OPENSSL)
+/* only available option */
+#define USE_CURL_DEFAULT 1
+#else
+/* strictly opt in */
+#define USE_CURL_DEFAULT 0
+#endif
+
 static int verbosity;
-static int use_curl; /* strictly opt in */
+static int use_curl = USE_CURL_DEFAULT;
 
 static const char * const imap_send_usage[] = { "git imap-send [-v] [-q] [--[no-]curl] < <mbox>", NULL };
 
@@ -1504,9 +1512,14 @@ int main(int argc, char **argv)
 
 #ifndef USE_CURL_FOR_IMAP_SEND
        if (use_curl) {
-               warning("--use-curl not supported in this build");
+               warning("--curl not supported in this build");
                use_curl = 0;
        }
+#elif defined(NO_OPENSSL)
+       if (!use_curl) {
+               warning("--no-curl not supported in this build");
+               use_curl = 1;
+       }
 #endif
 
        if (!server.port)
diff --git a/kwset.c b/kwset.c
index a0f49b3aca934008465842dd37e52d11d099e23e..e6236a0359cb3661acb8b1e609be236f6fb9d4bf 100644 (file)
--- a/kwset.c
+++ b/kwset.c
@@ -80,13 +80,13 @@ struct kwset
   struct trie *next[NCHAR];    /* Table of children of the root. */
   char *target;                        /* Target string if there's only one. */
   int mind2;                   /* Used in Boyer-Moore search for one string. */
-  char const *trans;           /* Character translation table. */
+  unsigned char const *trans;  /* Character translation table. */
 };
 
 /* Allocate and initialize a keyword set object, returning an opaque
    pointer to it.  Return NULL if memory is not available. */
 kwset_t
-kwsalloc (char const *trans)
+kwsalloc (unsigned char const *trans)
 {
   struct kwset *kwset;
 
@@ -381,7 +381,7 @@ kwsprep (kwset_t kws)
   register struct kwset *kwset;
   register int i;
   register struct trie *curr;
-  register char const *trans;
+  register unsigned char const *trans;
   unsigned char delta[NCHAR];
 
   kwset = (struct kwset *) kws;
@@ -590,7 +590,7 @@ cwexec (kwset_t kws, char const *text, size_t len, struct kwsmatch *kwsmatch)
   register int d;
   register char const *end, *qlim;
   register struct tree const *tree;
-  register char const *trans;
+  register unsigned char const *trans;
 
   accept = NULL;
 
diff --git a/kwset.h b/kwset.h
index a21b2eadfdf9f760c170f10c069a06853105eee5..61a134f256cee951f726c9619861b614fb66f9d6 100644 (file)
--- a/kwset.h
+++ b/kwset.h
@@ -39,7 +39,7 @@ typedef struct kwset_t* kwset_t;
    if enough memory cannot be obtained.  The argument if non-NULL
    specifies a table of character translations to be applied to all
    pattern and search text. */
-extern kwset_t kwsalloc(char const *);
+extern kwset_t kwsalloc(unsigned char const *);
 
 /* Incrementally extend the keyword set to include the given string.
    Return NULL for success, or an error message.  Remember an index
index 7f0890e4ac14348e78f7f1e305629fa745a79392..2c1ed0fa90170438e00a2eadbf74e15d89531613 100644 (file)
@@ -172,6 +172,43 @@ static void show_children(struct rev_info *opt, struct commit *commit, int abbre
        }
 }
 
+/*
+ * Do we have HEAD in the output, and also the branch it points at?
+ * If so, find that decoration entry for that current branch.
+ */
+static const struct name_decoration *current_pointed_by_HEAD(const struct name_decoration *decoration)
+{
+       const struct name_decoration *list, *head = NULL;
+       const char *branch_name = NULL;
+       unsigned char unused[20];
+       int rru_flags;
+
+       /* First find HEAD */
+       for (list = decoration; list; list = list->next)
+               if (list->type == DECORATION_REF_HEAD) {
+                       head = list;
+                       break;
+               }
+       if (!head)
+               return NULL;
+
+       /* Now resolve and find the matching current branch */
+       branch_name = resolve_ref_unsafe("HEAD", 0, unused, &rru_flags);
+       if (!(rru_flags & REF_ISSYMREF))
+               return NULL;
+       if (!skip_prefix(branch_name, "refs/heads/", &branch_name))
+               return NULL;
+
+       /* OK, do we have that ref in the list? */
+       for (list = decoration; list; list = list->next)
+               if ((list->type == DECORATION_REF_LOCAL) &&
+                   !strcmp(branch_name, list->name)) {
+                       return list;
+               }
+
+       return NULL;
+}
+
 /*
  * The caller makes sure there is no funny color before calling.
  * format_decorations_extended makes sure the same after return.
@@ -184,6 +221,7 @@ void format_decorations_extended(struct strbuf *sb,
                        const char *suffix)
 {
        const struct name_decoration *decoration;
+       const struct name_decoration *current_and_HEAD;
        const char *color_commit =
                diff_get_color(use_color, DIFF_COMMIT);
        const char *color_reset =
@@ -192,15 +230,37 @@ void format_decorations_extended(struct strbuf *sb,
        decoration = get_name_decoration(&commit->object);
        if (!decoration)
                return;
+
+       current_and_HEAD = current_pointed_by_HEAD(decoration);
        while (decoration) {
-               strbuf_addstr(sb, color_commit);
-               strbuf_addstr(sb, prefix);
-               strbuf_addstr(sb, decorate_get_color(use_color, decoration->type));
-               if (decoration->type == DECORATION_REF_TAG)
-                       strbuf_addstr(sb, "tag: ");
-               strbuf_addstr(sb, decoration->name);
-               strbuf_addstr(sb, color_reset);
-               prefix = separator;
+               /*
+                * When both current and HEAD are there, only
+                * show HEAD->current where HEAD would have
+                * appeared, skipping the entry for current.
+                */
+               if (decoration != current_and_HEAD) {
+                       strbuf_addstr(sb, color_commit);
+                       strbuf_addstr(sb, prefix);
+                       strbuf_addstr(sb, color_reset);
+                       strbuf_addstr(sb, decorate_get_color(use_color, decoration->type));
+                       if (decoration->type == DECORATION_REF_TAG)
+                               strbuf_addstr(sb, "tag: ");
+
+                       strbuf_addstr(sb, decoration->name);
+
+                       if (current_and_HEAD &&
+                           decoration->type == DECORATION_REF_HEAD) {
+                               strbuf_addstr(sb, color_reset);
+                               strbuf_addstr(sb, color_commit);
+                               strbuf_addstr(sb, " -> ");
+                               strbuf_addstr(sb, color_reset);
+                               strbuf_addstr(sb, decorate_get_color(use_color, current_and_HEAD->type));
+                               strbuf_addstr(sb, current_and_HEAD->name);
+                       }
+                       strbuf_addstr(sb, color_reset);
+
+                       prefix = separator;
+               }
                decoration = decoration->next;
        }
        strbuf_addstr(sb, color_commit);
diff --git a/pager.c b/pager.c
index f6e8c331924496ca6656cd05d7de6497310502ab..98b26823c9e0c0bd220a7a41a97675626c8e65ec 100644 (file)
--- a/pager.c
+++ b/pager.c
@@ -133,12 +133,12 @@ int term_columns(void)
 /*
  * How many columns do we need to show this number in decimal?
  */
-int decimal_width(int number)
+int decimal_width(uintmax_t number)
 {
-       int i, width;
+       int width;
 
-       for (width = 1, i = 10; i <= number; width++)
-               i *= 10;
+       for (width = 1; number >= 10; width++)
+               number /= 10;
        return width;
 }
 
index b5905ee1ad03fe9973e3cf7d46fa29c5cf184215..9026a7bb980a984086a62536f46ec3837588f277 100644 (file)
@@ -695,7 +695,7 @@ sub config_path {
 is simple decimal number.  An optional value suffix of 'k', 'm',
 or 'g' in the config file will cause the value to be multiplied
 by 1024, 1048576 (1024^2), or 1073741824 (1024^3) prior to output.
-It would return C<undef> if configuration variable is not defined,
+It would return C<undef> if configuration variable is not defined.
 
 =cut
 
@@ -704,7 +704,7 @@ sub config_int {
 }
 
 # Common subroutine to implement bulk of what the config* family of methods
-# do. This curently wraps command('config') so it is not so fast.
+# do. This currently wraps command('config') so it is not so fast.
 sub _config_common {
        my ($opts) = shift @_;
        my ($self, $var) = _maybe_self(@_);
index 8e4af7153eb8a8957bd4172e0c044c1bfc748ddb..152fb7e9274c779cb66de099878b4de40e5406e4 100644 (file)
@@ -9,11 +9,10 @@ package Git::SVN;
            $_use_log_author $_add_author_from $_localtime/;
 use Carp qw/croak/;
 use File::Path qw/mkpath/;
-use File::Copy qw/copy/;
 use IPC::Open3;
 use Memoize;  # core since 5.8.0, Jul 2002
-use Memoize::Storable;
 use POSIX qw(:signal_h);
+use Time::Local;
 
 use Git qw(
     command
@@ -32,11 +31,7 @@ package Git::SVN;
        add_path_to_url
 );
 
-my $can_use_yaml;
-BEGIN {
-       $can_use_yaml = eval { require Git::SVN::Memoize::YAML; 1};
-}
-
+my $memo_backend;
 our $_follow_parent  = 1;
 our $_minimize_url   = 'unset';
 our $default_repo_id = 'svn';
@@ -1332,7 +1327,7 @@ sub parse_svn_date {
                $ENV{TZ} = 'UTC';
 
                my $epoch_in_UTC =
-                   POSIX::strftime('%s', $S, $M, $H, $d, $m - 1, $Y - 1900);
+                   Time::Local::timelocal($S, $M, $H, $d, $m - 1, $Y - 1900);
 
                # Determine our local timezone (including DST) at the
                # time of $epoch_in_UTC.  $Git::SVN::Log::TZ stored the
@@ -1578,7 +1573,16 @@ sub tie_for_persistent_memoization {
        my $hash = shift;
        my $path = shift;
 
-       if ($can_use_yaml) {
+       unless ($memo_backend) {
+               if (eval { require Git::SVN::Memoize::YAML; 1}) {
+                       $memo_backend = 1;
+               } else {
+                       require Memoize::Storable;
+                       $memo_backend = -1;
+               }
+       }
+
+       if ($memo_backend > 0) {
                tie %$hash => 'Git::SVN::Memoize::YAML', "$path.yaml";
        } else {
                tie %$hash => 'Memoize::Storable', "$path.db", 'nstore';
@@ -2188,8 +2192,9 @@ sub rev_map_set {
        # both of these options make our .rev_db file very, very important
        # and we can't afford to lose it because rebuild() won't work
        if ($self->use_svm_props || $self->no_metadata) {
+               require File::Copy;
                $sync = 1;
-               copy($db, $db_lock) or die "rev_map_set(@_): ",
+               File::Copy::copy($db, $db_lock) or die "rev_map_set(@_): ",
                                           "Failed to copy: ",
                                           "$db => $db_lock ($!)\n";
        } else {
index 4088f13e723a51a6e1cee0c616a7c279a780461d..c50176eec9418c50e5c63921c24e76a87b6123ab 100644 (file)
@@ -5,7 +5,6 @@ package Git::SVN::Editor;
 use SVN::Core;
 use SVN::Delta;
 use Carp qw/croak/;
-use IO::File;
 use Git qw/command command_oneline command_noisy command_output_pipe
            command_input_pipe command_close_pipe
            command_bidi_pipe command_close_bidi_pipe/;
@@ -586,7 +585,7 @@ =head1 DESCRIPTION
 =head1 DEPENDENCIES
 
 Subversion perl bindings,
-the core L<Carp> and L<IO::File> modules,
+the core L<Carp> module,
 and git's L<Git> helper module.
 
 C<Git::SVN::Editor> has not been tested using callers other than
index 10edb27732f439e5290a7b354efefeb10d219669..d8c21ad91549b4e52ce95c5e694db2f53f9931c9 100644 (file)
@@ -7,7 +7,6 @@ package Git::SVN::Fetcher;
 use SVN::Delta;
 use Carp qw/croak/;
 use File::Basename qw/dirname/;
-use IO::File qw//;
 use Git qw/command command_oneline command_noisy command_output_pipe
            command_input_pipe command_close_pipe
            command_bidi_pipe command_close_bidi_pipe/;
@@ -322,6 +321,14 @@ sub apply_textdelta {
        # (but $base does not,) so dup() it for reading in close_file
        open my $dup, '<&', $fh or croak $!;
        my $base = $::_repository->temp_acquire("git_blob_${$}_$suffix");
+       # close_file may call temp_acquire on 'svn_hash', but because of the
+       # call chain, if the temp_acquire call from close_file ends up being the
+       # call that first creates the 'svn_hash' temp file, then the FileHandle
+       # that's created as a result will end up in an SVN::Pool that we clear
+       # in SVN::Ra::gs_fetch_loop_common.  Avoid that by making sure the
+       # 'svn_hash' FileHandle is already created before close_file is called.
+       my $tmp_fh = $::_repository->temp_acquire('svn_hash');
+       $::_repository->temp_release($tmp_fh, 1);
 
        if ($fb->{blob}) {
                my ($base_is_link, $size);
@@ -600,7 +607,7 @@ =head1 DESCRIPTION
 =head1 DEPENDENCIES
 
 L<SVN::Delta> from the Subversion perl bindings,
-the core L<Carp>, L<File::Basename>, and L<IO::File> modules,
+the core L<Carp> and L<File::Basename> modules,
 and git's L<Git> helper module.
 
 C<Git::SVN::Fetcher> has not been tested using callers other than
index 622535e21760f9fd5c6b63f97d41b48be9c04db6..4a499fcb38daf4ab8d3e20ca0fa10e5732e684a9 100644 (file)
@@ -3,7 +3,6 @@ package Git::SVN::Ra;
 use strict;
 use warnings;
 use Memoize;
-use SVN::Client;
 use Git::SVN::Utils qw(
        canonicalize_url
        canonicalize_path
@@ -42,6 +41,7 @@ END
 }
 
 sub _auth_providers () {
+       require SVN::Client;
        my @rv = (
          SVN::Client::get_simple_provider(),
          SVN::Client::get_ssl_server_trust_file_provider(),
@@ -247,7 +247,10 @@ sub get_log {
        $ret;
 }
 
+# uncommon, only for ancient SVN (<= 1.4.2)
 sub trees_match {
+       require IO::File;
+       require SVN::Client;
        my ($self, $url1, $rev1, $url2, $rev2) = @_;
        my $ctx = SVN::Client->new(auth => _auth_providers);
        my $out = IO::File->new_tmpfile;
@@ -391,6 +394,9 @@ sub longest_common_path {
 sub gs_fetch_loop_common {
        my ($self, $base, $head, $gsv, $globs) = @_;
        return if ($base > $head);
+       # Make sure the cat_blob open2 FileHandle is created before calling
+       # SVN::Pool::new_default so that it does not incorrectly end up in the pool.
+       $::_repository->_open_cat_blob_if_needed;
        my $gpool = SVN::Pool->new_default;
        my $ra_url = $self->url;
        my $reload_ra = sub {
index 9d34d02db11bd6761d48484327fbc6d1704ad555..7b493041814dc8514bde0778497d39868c8455d7 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -567,7 +567,7 @@ static char *replace_encoding_header(char *buf, const char *encoding)
        char *cp = buf;
 
        /* guess if there is an encoding header before a \n\n */
-       while (strncmp(cp, "encoding ", strlen("encoding "))) {
+       while (!starts_with(cp, "encoding ")) {
                cp = strchr(cp, '\n');
                if (!cp || *++cp == '\n')
                        return buf;
index 9cff715d6b669ecf05f861bc553b61d20d04191d..8d71860f692ffa5deafe7f23774b1b9ab2f31378 100644 (file)
@@ -725,7 +725,7 @@ struct cache_entry *make_cache_entry(unsigned int mode,
                unsigned int refresh_options)
 {
        int size, len;
-       struct cache_entry *ce;
+       struct cache_entry *ce, *ret;
 
        if (!verify_path(path)) {
                error("Invalid path '%s'", path);
@@ -742,7 +742,13 @@ struct cache_entry *make_cache_entry(unsigned int mode,
        ce->ce_namelen = len;
        ce->ce_mode = create_ce_mode(mode);
 
-       return refresh_cache_entry(ce, refresh_options);
+       ret = refresh_cache_entry(ce, refresh_options);
+       if (!ret) {
+               free(ce);
+               return NULL;
+       } else {
+               return ret;
+       }
 }
 
 int ce_same_name(const struct cache_entry *a, const struct cache_entry *b)
diff --git a/refs.c b/refs.c
index ab2f2a92cd9119a3c67d8b3b7741ae1279d747f3..e23542b3869b38e47f59f102d28648d30d506574 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -12,7 +12,6 @@ struct ref_lock {
        struct lock_file *lk;
        unsigned char old_sha1[20];
        int lock_fd;
-       int force_write;
 };
 
 /*
@@ -35,10 +34,29 @@ static unsigned char refname_disposition[256] = {
 };
 
 /*
- * Used as a flag to ref_transaction_delete when a loose ref is being
+ * Flag passed to lock_ref_sha1_basic() telling it to tolerate broken
+ * refs (i.e., because the reference is about to be deleted anyway).
+ */
+#define REF_DELETING   0x02
+
+/*
+ * Used as a flag in ref_update::flags when a loose ref is being
  * pruned.
  */
-#define REF_ISPRUNING  0x0100
+#define REF_ISPRUNING  0x04
+
+/*
+ * Used as a flag in ref_update::flags when the reference should be
+ * updated to new_sha1.
+ */
+#define REF_HAVE_NEW   0x08
+
+/*
+ * Used as a flag in ref_update::flags when old_sha1 should be
+ * checked.
+ */
+#define REF_HAVE_OLD   0x10
+
 /*
  * Try to read one refname component from the front of refname.
  * Return the length of the component found, or -1 if the component is
@@ -2249,7 +2267,7 @@ int dwim_log(const char *str, int len, unsigned char *sha1, char **log)
 static struct ref_lock *lock_ref_sha1_basic(const char *refname,
                                            const unsigned char *old_sha1,
                                            const struct string_list *skip,
-                                           int flags, int *type_p)
+                                           unsigned int flags, int *type_p)
 {
        char *ref_file;
        const char *orig_refname = refname;
@@ -2258,7 +2276,6 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
        int type, lflags;
        int mustexist = (old_sha1 && !is_null_sha1(old_sha1));
        int resolve_flags = 0;
-       int missing = 0;
        int attempts_remaining = 3;
 
        lock = xcalloc(1, sizeof(struct ref_lock));
@@ -2297,13 +2314,13 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
                        orig_refname, strerror(errno));
                goto error_return;
        }
-       missing = is_null_sha1(lock->old_sha1);
-       /* When the ref did not exist and we are creating it,
-        * make sure there is no existing ref that is packed
-        * whose name begins with our refname, nor a ref whose
-        * name is a proper prefix of our refname.
+       /*
+        * If the ref did not exist and we are creating it, make sure
+        * there is no existing packed ref whose name begins with our
+        * refname, nor a packed ref whose name is a proper prefix of
+        * our refname.
         */
-       if (missing &&
+       if (is_null_sha1(lock->old_sha1) &&
             !is_refname_available(refname, skip, get_packed_refs(&ref_cache))) {
                last_errno = ENOTDIR;
                goto error_return;
@@ -2319,10 +2336,6 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
        lock->ref_name = xstrdup(refname);
        lock->orig_ref_name = xstrdup(orig_refname);
        ref_file = git_path("%s", refname);
-       if (missing)
-               lock->force_write = 1;
-       if ((flags & REF_NODEREF) && (type & REF_ISSYMREF))
-               lock->force_write = 1;
 
  retry:
        switch (safe_create_leading_directories(ref_file)) {
@@ -2563,7 +2576,7 @@ static void prune_ref(struct ref_to_prune *r)
        transaction = ref_transaction_begin(&err);
        if (!transaction ||
            ref_transaction_delete(transaction, r->name, r->sha1,
-                                  REF_ISPRUNING, 1, NULL, &err) ||
+                                  REF_ISPRUNING, NULL, &err) ||
            ref_transaction_commit(transaction, &err)) {
                ref_transaction_free(transaction);
                error("%s", err.buf);
@@ -2733,15 +2746,16 @@ static int delete_ref_loose(struct ref_lock *lock, int flag, struct strbuf *err)
        return 0;
 }
 
-int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
+int delete_ref(const char *refname, const unsigned char *sha1, unsigned int flags)
 {
        struct ref_transaction *transaction;
        struct strbuf err = STRBUF_INIT;
 
        transaction = ref_transaction_begin(&err);
        if (!transaction ||
-           ref_transaction_delete(transaction, refname, sha1, delopt,
-                                  sha1 && !is_null_sha1(sha1), NULL, &err) ||
+           ref_transaction_delete(transaction, refname,
+                                  (sha1 && !is_null_sha1(sha1)) ? sha1 : NULL,
+                                  flags, NULL, &err) ||
            ref_transaction_commit(transaction, &err)) {
                error("%s", err.buf);
                ref_transaction_free(transaction);
@@ -2877,7 +2891,6 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms
                error("unable to lock %s for update", newrefname);
                goto rollback;
        }
-       lock->force_write = 1;
        hashcpy(lock->old_sha1, orig_sha1);
        if (write_ref_sha1(lock, orig_sha1, logmsg)) {
                error("unable to write current sha1 into %s", newrefname);
@@ -2893,7 +2906,6 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms
                goto rollbacklog;
        }
 
-       lock->force_write = 1;
        flag = log_all_ref_updates;
        log_all_ref_updates = 0;
        if (write_ref_sha1(lock, orig_sha1, NULL))
@@ -3079,14 +3091,6 @@ static int write_ref_sha1(struct ref_lock *lock,
        static char term = '\n';
        struct object *o;
 
-       if (!lock) {
-               errno = EINVAL;
-               return -1;
-       }
-       if (!lock->force_write && !hashcmp(lock->old_sha1, sha1)) {
-               unlock_ref(lock);
-               return 0;
-       }
        o = parse_object(sha1);
        if (!o) {
                error("Trying to write ref %s with nonexistent object %s",
@@ -3556,16 +3560,27 @@ int for_each_reflog(each_ref_fn fn, void *cb_data)
 }
 
 /**
- * Information needed for a single ref update.  Set new_sha1 to the
- * new value or to zero to delete the ref.  To check the old value
- * while locking the ref, set have_old to 1 and set old_sha1 to the
- * value or to zero to ensure the ref does not exist before update.
+ * Information needed for a single ref update. Set new_sha1 to the new
+ * value or to null_sha1 to delete the ref. To check the old value
+ * while the ref is locked, set (flags & REF_HAVE_OLD) and set
+ * old_sha1 to the old value, or to null_sha1 to ensure the ref does
+ * not exist before update.
  */
 struct ref_update {
+       /*
+        * If (flags & REF_HAVE_NEW), set the reference to this value:
+        */
        unsigned char new_sha1[20];
+       /*
+        * If (flags & REF_HAVE_OLD), check that the reference
+        * previously had this value:
+        */
        unsigned char old_sha1[20];
-       int flags; /* REF_NODEREF? */
-       int have_old; /* 1 if old_sha1 is valid, 0 otherwise */
+       /*
+        * One or more of REF_HAVE_NEW, REF_HAVE_OLD, REF_NODEREF,
+        * REF_DELETING, and REF_ISPRUNING:
+        */
+       unsigned int flags;
        struct ref_lock *lock;
        int type;
        char *msg;
@@ -3637,7 +3652,7 @@ int ref_transaction_update(struct ref_transaction *transaction,
                           const char *refname,
                           const unsigned char *new_sha1,
                           const unsigned char *old_sha1,
-                          int flags, int have_old, const char *msg,
+                          unsigned int flags, const char *msg,
                           struct strbuf *err)
 {
        struct ref_update *update;
@@ -3647,10 +3662,7 @@ int ref_transaction_update(struct ref_transaction *transaction,
        if (transaction->state != REF_TRANSACTION_OPEN)
                die("BUG: update called for transaction that is not open");
 
-       if (have_old && !old_sha1)
-               die("BUG: have_old is true but old_sha1 is NULL");
-
-       if (!is_null_sha1(new_sha1) &&
+       if (new_sha1 && !is_null_sha1(new_sha1) &&
            check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {
                strbuf_addf(err, "refusing to update ref with bad name %s",
                            refname);
@@ -3658,11 +3670,15 @@ int ref_transaction_update(struct ref_transaction *transaction,
        }
 
        update = add_update(transaction, refname);
-       hashcpy(update->new_sha1, new_sha1);
-       update->flags = flags;
-       update->have_old = have_old;
-       if (have_old)
+       if (new_sha1) {
+               hashcpy(update->new_sha1, new_sha1);
+               flags |= REF_HAVE_NEW;
+       }
+       if (old_sha1) {
                hashcpy(update->old_sha1, old_sha1);
+               flags |= REF_HAVE_OLD;
+       }
+       update->flags = flags;
        if (msg)
                update->msg = xstrdup(msg);
        return 0;
@@ -3671,34 +3687,52 @@ int ref_transaction_update(struct ref_transaction *transaction,
 int ref_transaction_create(struct ref_transaction *transaction,
                           const char *refname,
                           const unsigned char *new_sha1,
-                          int flags, const char *msg,
+                          unsigned int flags, const char *msg,
                           struct strbuf *err)
 {
+       if (!new_sha1 || is_null_sha1(new_sha1))
+               die("BUG: create called without valid new_sha1");
        return ref_transaction_update(transaction, refname, new_sha1,
-                                     null_sha1, flags, 1, msg, err);
+                                     null_sha1, flags, msg, err);
 }
 
 int ref_transaction_delete(struct ref_transaction *transaction,
                           const char *refname,
                           const unsigned char *old_sha1,
-                          int flags, int have_old, const char *msg,
+                          unsigned int flags, const char *msg,
+                          struct strbuf *err)
+{
+       if (old_sha1 && is_null_sha1(old_sha1))
+               die("BUG: delete called with old_sha1 set to zeros");
+       return ref_transaction_update(transaction, refname,
+                                     null_sha1, old_sha1,
+                                     flags, msg, err);
+}
+
+int ref_transaction_verify(struct ref_transaction *transaction,
+                          const char *refname,
+                          const unsigned char *old_sha1,
+                          unsigned int flags,
                           struct strbuf *err)
 {
-       return ref_transaction_update(transaction, refname, null_sha1,
-                                     old_sha1, flags, have_old, msg, err);
+       if (!old_sha1)
+               die("BUG: verify called with old_sha1 set to NULL");
+       return ref_transaction_update(transaction, refname,
+                                     NULL, old_sha1,
+                                     flags, NULL, err);
 }
 
-int update_ref(const char *action, const char *refname,
-              const unsigned char *sha1, const unsigned char *oldval,
-              int flags, enum action_on_err onerr)
+int update_ref(const char *msg, const char *refname,
+              const unsigned char *new_sha1, const unsigned char *old_sha1,
+              unsigned int flags, enum action_on_err onerr)
 {
        struct ref_transaction *t;
        struct strbuf err = STRBUF_INIT;
 
        t = ref_transaction_begin(&err);
        if (!t ||
-           ref_transaction_update(t, refname, sha1, oldval, flags,
-                                  !!oldval, action, &err) ||
+           ref_transaction_update(t, refname, new_sha1, old_sha1,
+                                  flags, msg, &err) ||
            ref_transaction_commit(t, &err)) {
                const char *str = "update_ref failed for ref '%s': %s";
 
@@ -3774,17 +3808,17 @@ int ref_transaction_commit(struct ref_transaction *transaction,
        /* Acquire all locks while verifying old values */
        for (i = 0; i < n; i++) {
                struct ref_update *update = updates[i];
-               int flags = update->flags;
+               unsigned int flags = update->flags;
 
-               if (is_null_sha1(update->new_sha1))
+               if ((flags & REF_HAVE_NEW) && is_null_sha1(update->new_sha1))
                        flags |= REF_DELETING;
-               update->lock = lock_ref_sha1_basic(update->refname,
-                                                  (update->have_old ?
-                                                   update->old_sha1 :
-                                                   NULL),
-                                                  NULL,
-                                                  flags,
-                                                  &update->type);
+               update->lock = lock_ref_sha1_basic(
+                               update->refname,
+                               ((update->flags & REF_HAVE_OLD) ?
+                                update->old_sha1 : NULL),
+                               NULL,
+                               flags,
+                               &update->type);
                if (!update->lock) {
                        ret = (errno == ENOTDIR)
                                ? TRANSACTION_NAME_CONFLICT
@@ -3798,31 +3832,46 @@ int ref_transaction_commit(struct ref_transaction *transaction,
        /* Perform updates first so live commits remain referenced */
        for (i = 0; i < n; i++) {
                struct ref_update *update = updates[i];
+               int flags = update->flags;
+
+               if ((flags & REF_HAVE_NEW) && !is_null_sha1(update->new_sha1)) {
+                       int overwriting_symref = ((update->type & REF_ISSYMREF) &&
+                                                 (update->flags & REF_NODEREF));
 
-               if (!is_null_sha1(update->new_sha1)) {
-                       if (write_ref_sha1(update->lock, update->new_sha1,
-                                          update->msg)) {
+                       if (!overwriting_symref
+                           && !hashcmp(update->lock->old_sha1, update->new_sha1)) {
+                               /*
+                                * The reference already has the desired
+                                * value, so we don't need to write it.
+                                */
+                               unlock_ref(update->lock);
+                               update->lock = NULL;
+                       } else if (write_ref_sha1(update->lock, update->new_sha1,
+                                                 update->msg)) {
                                update->lock = NULL; /* freed by write_ref_sha1 */
                                strbuf_addf(err, "Cannot update the ref '%s'.",
                                            update->refname);
                                ret = TRANSACTION_GENERIC_ERROR;
                                goto cleanup;
+                       } else {
+                               /* freed by write_ref_sha1(): */
+                               update->lock = NULL;
                        }
-                       update->lock = NULL; /* freed by write_ref_sha1 */
                }
        }
 
        /* Perform deletes now that updates are safely completed */
        for (i = 0; i < n; i++) {
                struct ref_update *update = updates[i];
+               int flags = update->flags;
 
-               if (update->lock) {
+               if ((flags & REF_HAVE_NEW) && is_null_sha1(update->new_sha1)) {
                        if (delete_ref_loose(update->lock, update->type, err)) {
                                ret = TRANSACTION_GENERIC_ERROR;
                                goto cleanup;
                        }
 
-                       if (!(update->flags & REF_ISPRUNING))
+                       if (!(flags & REF_ISPRUNING))
                                string_list_append(&refs_to_delete,
                                                   update->lock->ref_name);
                }
@@ -4031,6 +4080,7 @@ int reflog_expire(const char *refname, const unsigned char *sha1,
        struct ref_lock *lock;
        char *log_file;
        int status = 0;
+       int type;
 
        memset(&cb, 0, sizeof(cb));
        cb.flags = flags;
@@ -4042,7 +4092,7 @@ int reflog_expire(const char *refname, const unsigned char *sha1,
         * reference itself, plus we might need to update the
         * reference if --updateref was specified:
         */
-       lock = lock_ref_sha1_basic(refname, sha1, NULL, 0, NULL);
+       lock = lock_ref_sha1_basic(refname, sha1, NULL, 0, &type);
        if (!lock)
                return error("cannot lock ref '%s'", refname);
        if (!reflog_exists(refname)) {
@@ -4079,10 +4129,21 @@ int reflog_expire(const char *refname, const unsigned char *sha1,
        (*cleanup_fn)(cb.policy_cb);
 
        if (!(flags & EXPIRE_REFLOGS_DRY_RUN)) {
+               /*
+                * It doesn't make sense to adjust a reference pointed
+                * to by a symbolic ref based on expiring entries in
+                * the symbolic reference's reflog. Nor can we update
+                * a reference if there are no remaining reflog
+                * entries.
+                */
+               int update = (flags & EXPIRE_REFLOGS_UPDATE_REF) &&
+                       !(type & REF_ISSYMREF) &&
+                       !is_null_sha1(cb.last_kept_sha1);
+
                if (close_lock_file(&reflog_lock)) {
                        status |= error("couldn't write %s: %s", log_file,
                                        strerror(errno));
-               } else if ((flags & EXPIRE_REFLOGS_UPDATE_REF) &&
+               } else if (update &&
                        (write_in_full(lock->lock_fd,
                                sha1_to_hex(cb.last_kept_sha1), 40) != 40 ||
                         write_str_in_full(lock->lock_fd, "\n") != 1 ||
@@ -4093,7 +4154,7 @@ int reflog_expire(const char *refname, const unsigned char *sha1,
                } else if (commit_lock_file(&reflog_lock)) {
                        status |= error("unable to commit reflog '%s' (%s)",
                                        log_file, strerror(errno));
-               } else if ((flags & EXPIRE_REFLOGS_UPDATE_REF) && commit_ref(lock)) {
+               } else if (update && commit_ref(lock)) {
                        status |= error("couldn't set %s", lock->ref_name);
                }
        }
diff --git a/refs.h b/refs.h
index afa3c4decd5562c85978e49a9e1c2a34c128b055..cf642e6ddc438be77d64797a4dbcf790262a9fed 100644 (file)
--- a/refs.h
+++ b/refs.h
@@ -183,12 +183,10 @@ extern int peel_ref(const char *refname, unsigned char *sha1);
  * Flags controlling ref_transaction_update(), ref_transaction_create(), etc.
  * REF_NODEREF: act on the ref directly, instead of dereferencing
  *              symbolic references.
- * REF_DELETING: tolerate broken refs
  *
- * Flags >= 0x100 are reserved for internal use.
+ * Other flags are reserved for internal use.
  */
 #define REF_NODEREF    0x01
-#define REF_DELETING   0x02
 
 /*
  * Setup reflog before using. Set errno to something meaningful on failure.
@@ -257,57 +255,95 @@ enum action_on_err {
 struct ref_transaction *ref_transaction_begin(struct strbuf *err);
 
 /*
- * The following functions add a reference check or update to a
- * ref_transaction.  In all of them, refname is the name of the
- * reference to be affected.  The functions make internal copies of
- * refname and msg, so the caller retains ownership of these parameters.
- * flags can be REF_NODEREF; it is passed to update_ref_lock().
+ * Reference transaction updates
+ *
+ * The following four functions add a reference check or update to a
+ * ref_transaction.  They have some common similar parameters:
+ *
+ *     transaction -- a pointer to an open ref_transaction, obtained
+ *         from ref_transaction_begin().
+ *
+ *     refname -- the name of the reference to be affected.
+ *
+ *     flags -- flags affecting the update, passed to
+ *         update_ref_lock(). Can be REF_NODEREF, which means that
+ *         symbolic references should not be followed.
+ *
+ *     msg -- a message describing the change (for the reflog).
+ *
+ *     err -- a strbuf for receiving a description of any error that
+ *         might have occured.
+ *
+ * The functions make internal copies of refname and msg, so the
+ * caller retains ownership of these parameters.
+ *
+ * The functions return 0 on success and non-zero on failure. A
+ * failure means that the transaction as a whole has failed and needs
+ * to be rolled back.
  */
 
 /*
- * Add a reference update to transaction.  new_sha1 is the value that
- * the reference should have after the update, or null_sha1 if it should
- * be deleted.  If have_old is true, then old_sha1 holds the value
- * that the reference should have had before the update, or zeros if
- * it must not have existed beforehand.
- * Function returns 0 on success and non-zero on failure. A failure to update
- * means that the transaction as a whole has failed and will need to be
- * rolled back.
+ * Add a reference update to transaction. new_sha1 is the value that
+ * the reference should have after the update, or null_sha1 if it
+ * should be deleted. If new_sha1 is NULL, then the reference is not
+ * changed at all. old_sha1 is the value that the reference must have
+ * before the update, or null_sha1 if it must not have existed
+ * beforehand. The old value is checked after the lock is taken to
+ * prevent races. If the old value doesn't agree with old_sha1, the
+ * whole transaction fails. If old_sha1 is NULL, then the previous
+ * value is not checked.
+ *
+ * See the above comment "Reference transaction updates" for more
+ * information.
  */
 int ref_transaction_update(struct ref_transaction *transaction,
                           const char *refname,
                           const unsigned char *new_sha1,
                           const unsigned char *old_sha1,
-                          int flags, int have_old, const char *msg,
+                          unsigned int flags, const char *msg,
                           struct strbuf *err);
 
 /*
- * Add a reference creation to transaction.  new_sha1 is the value
- * that the reference should have after the update; it must not be the
- * null SHA-1.  It is verified that the reference does not exist
+ * Add a reference creation to transaction. new_sha1 is the value that
+ * the reference should have after the update; it must not be
+ * null_sha1. It is verified that the reference does not exist
  * already.
- * Function returns 0 on success and non-zero on failure. A failure to create
- * means that the transaction as a whole has failed and will need to be
- * rolled back.
+ *
+ * See the above comment "Reference transaction updates" for more
+ * information.
  */
 int ref_transaction_create(struct ref_transaction *transaction,
                           const char *refname,
                           const unsigned char *new_sha1,
-                          int flags, const char *msg,
+                          unsigned int flags, const char *msg,
                           struct strbuf *err);
 
 /*
- * Add a reference deletion to transaction.  If have_old is true, then
- * old_sha1 holds the value that the reference should have had before
- * the update (which must not be the null SHA-1).
- * Function returns 0 on success and non-zero on failure. A failure to delete
- * means that the transaction as a whole has failed and will need to be
- * rolled back.
+ * Add a reference deletion to transaction. If old_sha1 is non-NULL,
+ * then it holds the value that the reference should have had before
+ * the update (which must not be null_sha1).
+ *
+ * See the above comment "Reference transaction updates" for more
+ * information.
  */
 int ref_transaction_delete(struct ref_transaction *transaction,
                           const char *refname,
                           const unsigned char *old_sha1,
-                          int flags, int have_old, const char *msg,
+                          unsigned int flags, const char *msg,
+                          struct strbuf *err);
+
+/*
+ * Verify, within a transaction, that refname has the value old_sha1,
+ * or, if old_sha1 is null_sha1, then verify that the reference
+ * doesn't exist. old_sha1 must be non-NULL.
+ *
+ * See the above comment "Reference transaction updates" for more
+ * information.
+ */
+int ref_transaction_verify(struct ref_transaction *transaction,
+                          const char *refname,
+                          const unsigned char *old_sha1,
+                          unsigned int flags,
                           struct strbuf *err);
 
 /*
@@ -328,10 +364,17 @@ int ref_transaction_commit(struct ref_transaction *transaction,
  */
 void ref_transaction_free(struct ref_transaction *transaction);
 
-/** Lock a ref and then write its file */
-int update_ref(const char *action, const char *refname,
-               const unsigned char *sha1, const unsigned char *oldval,
-               int flags, enum action_on_err onerr);
+/**
+ * Lock, update, and unlock a single reference. This function
+ * basically does a transaction containing a single call to
+ * ref_transaction_update(). The parameters to this function have the
+ * same meaning as the corresponding parameters to
+ * ref_transaction_update(). Handle errors as requested by the `onerr`
+ * argument.
+ */
+int update_ref(const char *msg, const char *refname,
+              const unsigned char *new_sha1, const unsigned char *old_sha1,
+              unsigned int flags, enum action_on_err onerr);
 
 extern int parse_hide_refs_config(const char *var, const char *value, const char *);
 extern int ref_is_hidden(const char *);
index dd63bc27abf8ae4b9e480ba1bb88942db11a0e48..af7b6786dc091035e3216c710dbc0ebc3c234a8a 100644 (file)
@@ -567,7 +567,6 @@ static int post_rpc(struct rpc_state *rpc)
                git_zstream stream;
                int ret;
 
-               memset(&stream, 0, sizeof(stream));
                git_deflate_init_gzip(&stream, Z_BEST_COMPRESSION);
                gzip_size = git_deflate_bound(&stream, rpc->len);
                gzip_body = xmalloc(gzip_size);
@@ -760,7 +759,7 @@ static int fetch_git(struct discovery *heads,
 
        for (i = 0; i < nr_heads; i++) {
                struct ref *ref = to_fetch[i];
-               if (!ref->name || !*ref->name)
+               if (!*ref->name)
                        die("cannot fetch by sha1 over smart http");
                packet_buf_write(&preamble, "%s %s\n",
                                 sha1_to_hex(ref->old_sha1), ref->name);
@@ -962,6 +961,8 @@ int main(int argc, const char **argv)
        struct strbuf buf = STRBUF_INIT;
        int nongit;
 
+       git_setup_gettext();
+
        git_extract_argv0_path(argv[0]);
        setup_git_directory_gently(&nongit);
        if (argc < 2) {
index 0b432cc9713251b4d116bedf52ae1f51bd9d80cf..3afb124c79dcb234344e17795205153d4a2e0643 100644 (file)
@@ -4,10 +4,6 @@
 #include "sigchain.h"
 #include "argv-array.h"
 
-#ifndef SHELL_PATH
-# define SHELL_PATH "/bin/sh"
-#endif
-
 void child_process_init(struct child_process *child)
 {
        memset(child, 0, sizeof(*child));
index 77a1266760718b8e5b029636409634e241981888..c4f4b7d571fa088f80a0dbba815491a35f0c153f 100644 (file)
@@ -252,7 +252,7 @@ static int fast_forward_to(const unsigned char *to, const unsigned char *from,
        if (!transaction ||
            ref_transaction_update(transaction, "HEAD",
                                   to, unborn ? null_sha1 : from,
-                                  0, 1, sb.buf, &err) ||
+                                  0, sb.buf, &err) ||
            ref_transaction_commit(transaction, &err)) {
                ref_transaction_free(transaction);
                error("%s", err.buf);
@@ -373,6 +373,7 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,
 {
        struct argv_array array;
        int rc;
+       const char *value;
 
        argv_array_init(&array);
        argv_array_push(&array, "commit");
@@ -385,6 +386,10 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,
        if (!opts->edit) {
                argv_array_push(&array, "-F");
                argv_array_push(&array, defmsg);
+               if (!opts->signoff &&
+                   !opts->record_origin &&
+                   git_config_get_value("commit.cleanup", &value))
+                       argv_array_push(&array, "--cleanup=verbatim");
        }
 
        if (allow_empty)
index 30995e61b38fbfd1733acc5c3c5866b61d9f09e1..88f06bac926008dd40b6a53e0696274438278cfc 100644 (file)
@@ -2943,7 +2943,6 @@ static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen,
        }
 
        /* Set it up */
-       memset(&stream, 0, sizeof(stream));
        git_deflate_init(&stream, zlib_compression_level);
        stream.next_out = compressed;
        stream.avail_out = sizeof(compressed);
@@ -3359,31 +3358,42 @@ static int for_each_file_in_obj_subdir(int subdir_nr,
        return r;
 }
 
-int for_each_loose_file_in_objdir(const char *path,
+int for_each_loose_file_in_objdir_buf(struct strbuf *path,
                            each_loose_object_fn obj_cb,
                            each_loose_cruft_fn cruft_cb,
                            each_loose_subdir_fn subdir_cb,
                            void *data)
 {
-       struct strbuf buf = STRBUF_INIT;
-       size_t baselen;
+       size_t baselen = path->len;
        int r = 0;
        int i;
 
-       strbuf_addstr(&buf, path);
-       strbuf_addch(&buf, '/');
-       baselen = buf.len;
-
        for (i = 0; i < 256; i++) {
-               strbuf_addf(&buf, "%02x", i);
-               r = for_each_file_in_obj_subdir(i, &buf, obj_cb, cruft_cb,
+               strbuf_addf(path, "/%02x", i);
+               r = for_each_file_in_obj_subdir(i, path, obj_cb, cruft_cb,
                                                subdir_cb, data);
-               strbuf_setlen(&buf, baselen);
+               strbuf_setlen(path, baselen);
                if (r)
                        break;
        }
 
+       return r;
+}
+
+int for_each_loose_file_in_objdir(const char *path,
+                                 each_loose_object_fn obj_cb,
+                                 each_loose_cruft_fn cruft_cb,
+                                 each_loose_subdir_fn subdir_cb,
+                                 void *data)
+{
+       struct strbuf buf = STRBUF_INIT;
+       int r;
+
+       strbuf_addstr(&buf, path);
+       r = for_each_loose_file_in_objdir_buf(&buf, obj_cb, cruft_cb,
+                                             subdir_cb, data);
        strbuf_release(&buf);
+
        return r;
 }
 
@@ -3396,9 +3406,16 @@ static int loose_from_alt_odb(struct alternate_object_database *alt,
                              void *vdata)
 {
        struct loose_alt_odb_data *data = vdata;
-       return for_each_loose_file_in_objdir(alt->base,
-                                            data->cb, NULL, NULL,
-                                            data->data);
+       struct strbuf buf = STRBUF_INIT;
+       int r;
+
+       /* copy base not including trailing '/' */
+       strbuf_add(&buf, alt->base, alt->name - alt->base - 1);
+       r = for_each_loose_file_in_objdir_buf(&buf,
+                                             data->cb, NULL, NULL,
+                                             data->data);
+       strbuf_release(&buf);
+       return r;
 }
 
 int for_each_loose_object(each_loose_object_fn cb, void *data)
index cf2a83b14381ae02e737e6135561aab401f1f7e8..6d10f052b5050c64de5589733c2a8600e2ddb3dc 100644 (file)
@@ -757,7 +757,7 @@ static int get_describe_name(const char *name, int len, unsigned char *sha1)
 
        for (cp = name + len - 1; name + 2 <= cp; cp--) {
                char ch = *cp;
-               if (hexval(ch) & ~0377) {
+               if (!isxdigit(ch)) {
                        /* We must be looking at g in "SOMETHING-g"
                         * for it to be describe output.
                         */
@@ -1391,9 +1391,7 @@ static int get_sha1_with_context_1(const char *name,
                        namelen = strlen(cp);
                }
 
-               strncpy(oc->path, cp,
-                       sizeof(oc->path));
-               oc->path[sizeof(oc->path)-1] = '\0';
+               strlcpy(oc->path, cp, sizeof(oc->path));
 
                if (!active_cache)
                        read_cache();
@@ -1443,9 +1441,7 @@ static int get_sha1_with_context_1(const char *name,
                                                           name, len);
                        }
                        hashcpy(oc->tree, tree_sha1);
-                       strncpy(oc->path, filename,
-                               sizeof(oc->path));
-                       oc->path[sizeof(oc->path)-1] = '\0';
+                       strlcpy(oc->path, filename, sizeof(oc->path));
 
                        free(new_filename);
                        return ret;
index 652b6c432b325aaed29d7d374994a2a95d11a7c8..1883494ca3ad4931640c2a295c94800e287c1664 100644 (file)
--- a/strbuf.h
+++ b/strbuf.h
 #ifndef STRBUF_H
 #define STRBUF_H
 
-/* See Documentation/technical/api-strbuf.txt */
+/**
+ * strbuf's are meant to be used with all the usual C string and memory
+ * APIs. Given that the length of the buffer is known, it's often better to
+ * use the mem* functions than a str* one (memchr vs. strchr e.g.).
+ * Though, one has to be careful about the fact that str* functions often
+ * stop on NULs and that strbufs may have embedded NULs.
+ *
+ * A strbuf is NUL terminated for convenience, but no function in the
+ * strbuf API actually relies on the string being free of NULs.
+ *
+ * strbufs have some invariants that are very important to keep in mind:
+ *
+ *  - The `buf` member is never NULL, so it can be used in any usual C
+ *    string operations safely. strbuf's _have_ to be initialized either by
+ *    `strbuf_init()` or by `= STRBUF_INIT` before the invariants, though.
+ *
+ *    Do *not* assume anything on what `buf` really is (e.g. if it is
+ *    allocated memory or not), use `strbuf_detach()` to unwrap a memory
+ *    buffer from its strbuf shell in a safe way. That is the sole supported
+ *    way. This will give you a malloced buffer that you can later `free()`.
+ *
+ *    However, it is totally safe to modify anything in the string pointed by
+ *    the `buf` member, between the indices `0` and `len-1` (inclusive).
+ *
+ *  - The `buf` member is a byte array that has at least `len + 1` bytes
+ *    allocated. The extra byte is used to store a `'\0'`, allowing the
+ *    `buf` member to be a valid C-string. Every strbuf function ensure this
+ *    invariant is preserved.
+ *
+ *    NOTE: It is OK to "play" with the buffer directly if you work it this
+ *    way:
+ *
+ *        strbuf_grow(sb, SOME_SIZE); <1>
+ *        strbuf_setlen(sb, sb->len + SOME_OTHER_SIZE);
+ *
+ *    <1> Here, the memory array starting at `sb->buf`, and of length
+ *    `strbuf_avail(sb)` is all yours, and you can be sure that
+ *    `strbuf_avail(sb)` is at least `SOME_SIZE`.
+ *
+ *    NOTE: `SOME_OTHER_SIZE` must be smaller or equal to `strbuf_avail(sb)`.
+ *
+ *    Doing so is safe, though if it has to be done in many places, adding the
+ *    missing API to the strbuf module is the way to go.
+ *
+ *    WARNING: Do _not_ assume that the area that is yours is of size `alloc
+ *    - 1` even if it's true in the current implementation. Alloc is somehow a
+ *    "private" member that should not be messed with. Use `strbuf_avail()`
+ *    instead.
+*/
+
+/**
+ * Data Structures
+ * ---------------
+ */
 
-extern char strbuf_slopbuf[];
+/**
+ * This is the string buffer structure. The `len` member can be used to
+ * determine the current length of the string, and `buf` member provides
+ * access to the string itself.
+ */
 struct strbuf {
        size_t alloc;
        size_t len;
        char *buf;
 };
 
+extern char strbuf_slopbuf[];
 #define STRBUF_INIT  { 0, 0, strbuf_slopbuf }
 
-/*----- strbuf life cycle -----*/
+/**
+ * Life Cycle Functions
+ * --------------------
+ */
+
+/**
+ * Initialize the structure. The second parameter can be zero or a bigger
+ * number to allocate memory, in case you want to prevent further reallocs.
+ */
 extern void strbuf_init(struct strbuf *, size_t);
+
+/**
+ * Release a string buffer and the memory it used. You should not use the
+ * string buffer after using this function, unless you initialize it again.
+ */
 extern void strbuf_release(struct strbuf *);
+
+/**
+ * Detach the string from the strbuf and returns it; you now own the
+ * storage the string occupies and it is your responsibility from then on
+ * to release it with `free(3)` when you are done with it.
+ */
 extern char *strbuf_detach(struct strbuf *, size_t *);
+
+/**
+ * Attach a string to a buffer. You should specify the string to attach,
+ * the current length of the string and the amount of allocated memory.
+ * The amount must be larger than the string length, because the string you
+ * pass is supposed to be a NUL-terminated string.  This string _must_ be
+ * malloc()ed, and after attaching, the pointer cannot be relied upon
+ * anymore, and neither be free()d directly.
+ */
 extern void strbuf_attach(struct strbuf *, void *, size_t, size_t);
+
+/**
+ * Swap the contents of two string buffers.
+ */
 static inline void strbuf_swap(struct strbuf *a, struct strbuf *b)
 {
        struct strbuf tmp = *a;
@@ -24,14 +114,36 @@ static inline void strbuf_swap(struct strbuf *a, struct strbuf *b)
        *b = tmp;
 }
 
-/*----- strbuf size related -----*/
+
+/**
+ * Functions related to the size of the buffer
+ * -------------------------------------------
+ */
+
+/**
+ * Determine the amount of allocated but unused memory.
+ */
 static inline size_t strbuf_avail(const struct strbuf *sb)
 {
        return sb->alloc ? sb->alloc - sb->len - 1 : 0;
 }
 
+/**
+ * Ensure that at least this amount of unused memory is available after
+ * `len`. This is used when you know a typical size for what you will add
+ * and want to avoid repetitive automatic resizing of the underlying buffer.
+ * This is never a needed operation, but can be critical for performance in
+ * some cases.
+ */
 extern void strbuf_grow(struct strbuf *, size_t);
 
+/**
+ * Set the length of the buffer to a given value. This function does *not*
+ * allocate new memory, so you should not perform a `strbuf_setlen()` to a
+ * length that is larger than `len + strbuf_avail()`. `strbuf_setlen()` is
+ * just meant as a 'please fix invariants from this strbuf I just messed
+ * with'.
+ */
 static inline void strbuf_setlen(struct strbuf *sb, size_t len)
 {
        if (len > (sb->alloc ? sb->alloc - 1 : 0))
@@ -39,78 +151,58 @@ static inline void strbuf_setlen(struct strbuf *sb, size_t len)
        sb->len = len;
        sb->buf[len] = '\0';
 }
+
+/**
+ * Empty the buffer by setting the size of it to zero.
+ */
 #define strbuf_reset(sb)  strbuf_setlen(sb, 0)
 
-/*----- content related -----*/
+
+/**
+ * Functions related to the contents of the buffer
+ * -----------------------------------------------
+ */
+
+/**
+ * Strip whitespace from the beginning (`ltrim`), end (`rtrim`), or both side
+ * (`trim`) of a string.
+ */
 extern void strbuf_trim(struct strbuf *);
 extern void strbuf_rtrim(struct strbuf *);
 extern void strbuf_ltrim(struct strbuf *);
-extern int strbuf_reencode(struct strbuf *sb, const char *from, const char *to);
-extern void strbuf_tolower(struct strbuf *sb);
-extern int strbuf_cmp(const struct strbuf *, const struct strbuf *);
 
-static inline int strbuf_strip_suffix(struct strbuf *sb, const char *suffix)
-{
-       if (strip_suffix_mem(sb->buf, &sb->len, suffix)) {
-               strbuf_setlen(sb, sb->len);
-               return 1;
-       } else
-               return 0;
-}
-
-/*
- * Split str (of length slen) at the specified terminator character.
- * Return a null-terminated array of pointers to strbuf objects
- * holding the substrings.  The substrings include the terminator,
- * except for the last substring, which might be unterminated if the
- * original string did not end with a terminator.  If max is positive,
- * then split the string into at most max substrings (with the last
- * substring containing everything following the (max-1)th terminator
- * character).
- *
- * For lighter-weight alternatives, see string_list_split() and
- * string_list_split_in_place().
+/**
+ * Replace the contents of the strbuf with a reencoded form.  Returns -1
+ * on error, 0 on success.
  */
-extern struct strbuf **strbuf_split_buf(const char *, size_t,
-                                       int terminator, int max);
+extern int strbuf_reencode(struct strbuf *sb, const char *from, const char *to);
 
-/*
- * Split a NUL-terminated string at the specified terminator
- * character.  See strbuf_split_buf() for more information.
+/**
+ * Lowercase each character in the buffer using `tolower`.
  */
-static inline struct strbuf **strbuf_split_str(const char *str,
-                                              int terminator, int max)
-{
-       return strbuf_split_buf(str, strlen(str), terminator, max);
-}
+extern void strbuf_tolower(struct strbuf *sb);
 
-/*
- * Split a strbuf at the specified terminator character.  See
- * strbuf_split_buf() for more information.
+/**
+ * Compare two buffers. Returns an integer less than, equal to, or greater
+ * than zero if the first buffer is found, respectively, to be less than,
+ * to match, or be greater than the second buffer.
  */
-static inline struct strbuf **strbuf_split_max(const struct strbuf *sb,
-                                               int terminator, int max)
-{
-       return strbuf_split_buf(sb->buf, sb->len, terminator, max);
-}
+extern int strbuf_cmp(const struct strbuf *, const struct strbuf *);
 
-/*
- * Split a strbuf at the specified terminator character.  See
- * strbuf_split_buf() for more information.
- */
-static inline struct strbuf **strbuf_split(const struct strbuf *sb,
-                                          int terminator)
-{
-       return strbuf_split_max(sb, terminator, 0);
-}
 
-/*
- * Free a NULL-terminated list of strbufs (for example, the return
- * values of the strbuf_split*() functions).
+/**
+ * Adding data to the buffer
+ * -------------------------
+ *
+ * NOTE: All of the functions in this section will grow the buffer as
+ * necessary.  If they fail for some reason other than memory shortage and the
+ * buffer hadn't been allocated before (i.e. the `struct strbuf` was set to
+ * `STRBUF_INIT`), then they will free() it.
  */
-extern void strbuf_list_free(struct strbuf **);
 
-/*----- add data in your buffer -----*/
+/**
+ * Add a single character to the buffer.
+ */
 static inline void strbuf_addch(struct strbuf *sb, int c)
 {
        strbuf_grow(sb, 1);
@@ -118,47 +210,276 @@ static inline void strbuf_addch(struct strbuf *sb, int c)
        sb->buf[sb->len] = '\0';
 }
 
+/**
+ * Add a character the specified number of times to the buffer.
+ */
+extern void strbuf_addchars(struct strbuf *sb, int c, size_t n);
+
+/**
+ * Insert data to the given position of the buffer. The remaining contents
+ * will be shifted, not overwritten.
+ */
 extern void strbuf_insert(struct strbuf *, size_t pos, const void *, size_t);
+
+/**
+ * Remove given amount of data from a given position of the buffer.
+ */
 extern void strbuf_remove(struct strbuf *, size_t pos, size_t len);
 
-/* splice pos..pos+len with given data */
+/**
+ * Remove the bytes between `pos..pos+len` and replace it with the given
+ * data.
+ */
 extern void strbuf_splice(struct strbuf *, size_t pos, size_t len,
-                          const void *, size_t);
+                         const void *, size_t);
 
+/**
+ * Add a NUL-terminated string to the buffer. Each line will be prepended
+ * by a comment character and a blank.
+ */
 extern void strbuf_add_commented_lines(struct strbuf *out, const char *buf, size_t size);
 
+
+/**
+ * Add data of given length to the buffer.
+ */
 extern void strbuf_add(struct strbuf *, const void *, size_t);
+
+/**
+ * Add a NUL-terminated string to the buffer.
+ *
+ * NOTE: This function will *always* be implemented as an inline or a macro
+ * using strlen, meaning that this is efficient to write things like:
+ *
+ *     strbuf_addstr(sb, "immediate string");
+ *
+ */
 static inline void strbuf_addstr(struct strbuf *sb, const char *s)
 {
        strbuf_add(sb, s, strlen(s));
 }
+
+/**
+ * Copy the contents of another buffer at the end of the current one.
+ */
 static inline void strbuf_addbuf(struct strbuf *sb, const struct strbuf *sb2)
 {
        strbuf_grow(sb, sb2->len);
        strbuf_add(sb, sb2->buf, sb2->len);
 }
+
+/**
+ * Copy part of the buffer from a given position till a given length to the
+ * end of the buffer.
+ */
 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);
 
+/**
+ * This function can be used to expand a format string containing
+ * placeholders. To that end, it parses the string and calls the specified
+ * function for every percent sign found.
+ *
+ * The callback function is given a pointer to the character after the `%`
+ * and a pointer to the struct strbuf.  It is expected to add the expanded
+ * version of the placeholder to the strbuf, e.g. to add a newline
+ * character if the letter `n` appears after a `%`.  The function returns
+ * the length of the placeholder recognized and `strbuf_expand()` skips
+ * over it.
+ *
+ * The format `%%` is automatically expanded to a single `%` as a quoting
+ * mechanism; callers do not need to handle the `%` placeholder themselves,
+ * and the callback function will not be invoked for this placeholder.
+ *
+ * All other characters (non-percent and not skipped ones) are copied
+ * verbatim to the strbuf.  If the callback returned zero, meaning that the
+ * placeholder is unknown, then the percent sign is copied, too.
+ *
+ * In order to facilitate caching and to make it possible to give
+ * parameters to the callback, `strbuf_expand()` passes a context pointer,
+ * which can be used by the programmer of the callback as she sees fit.
+ */
 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);
+
+/**
+ * Used as callback for `strbuf_expand()`, expects an array of
+ * struct strbuf_expand_dict_entry as context, i.e. pairs of
+ * placeholder and replacement string.  The array needs to be
+ * terminated by an entry with placeholder set to NULL.
+ */
 struct strbuf_expand_dict_entry {
        const char *placeholder;
        const char *value;
 };
 extern size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder, void *context);
+
+/**
+ * Append the contents of one strbuf to another, quoting any
+ * percent signs ("%") into double-percents ("%%") in the
+ * destination. This is useful for literal data to be fed to either
+ * strbuf_expand or to the *printf family of functions.
+ */
 extern void strbuf_addbuf_percentquote(struct strbuf *dst, const struct strbuf *src);
 
+/**
+ * Append the given byte size as a human-readable string (i.e. 12.23 KiB,
+ * 3.50 MiB).
+ */
+extern void strbuf_humanise_bytes(struct strbuf *buf, off_t bytes);
+
+/**
+ * Add a formatted string to the buffer.
+ */
 __attribute__((format (printf,2,3)))
 extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...);
+
+/**
+ * Add a formatted string prepended by a comment character and a
+ * blank to the buffer.
+ */
 __attribute__((format (printf, 2, 3)))
 extern void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...);
+
 __attribute__((format (printf,2,0)))
 extern void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap);
 
+/**
+ * Read a given size of data from a FILE* pointer to the buffer.
+ *
+ * NOTE: The buffer is rewound if the read fails. If -1 is returned,
+ * `errno` must be consulted, like you would do for `read(3)`.
+ * `strbuf_read()`, `strbuf_read_file()` and `strbuf_getline()` has the
+ * same behaviour as well.
+ */
+extern size_t strbuf_fread(struct strbuf *, size_t, FILE *);
+
+/**
+ * Read the contents of a given file descriptor. The third argument can be
+ * used to give a hint about the file size, to avoid reallocs.  If read fails,
+ * any partial read is undone.
+ */
+extern ssize_t strbuf_read(struct strbuf *, int fd, size_t hint);
+
+/**
+ * Read the contents of a file, specified by its path. The third argument
+ * can be used to give a hint about the file size, to avoid reallocs.
+ */
+extern int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint);
+
+/**
+ * Read the target of a symbolic link, specified by its path.  The third
+ * argument can be used to give a hint about the size, to avoid reallocs.
+ */
+extern int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint);
+
+/**
+ * Read a line from a FILE *, overwriting the existing contents
+ * of the strbuf. The second argument specifies the line
+ * terminator character, typically `'\n'`.
+ * Reading stops after the terminator or at EOF.  The terminator
+ * is removed from the buffer before returning.  Returns 0 unless
+ * there was nothing left before EOF, in which case it returns `EOF`.
+ */
+extern int strbuf_getline(struct strbuf *, FILE *, int);
+
+/**
+ * Like `strbuf_getline`, but keeps the trailing terminator (if
+ * any) in the buffer.
+ */
+extern int strbuf_getwholeline(struct strbuf *, FILE *, int);
+
+/**
+ * Like `strbuf_getwholeline`, but operates on a file descriptor.
+ * It reads one character at a time, so it is very slow.  Do not
+ * use it unless you need the correct position in the file
+ * descriptor.
+ */
+extern int strbuf_getwholeline_fd(struct strbuf *, int, int);
+
+/**
+ * Set the buffer to the path of the current working directory.
+ */
+extern int strbuf_getcwd(struct strbuf *sb);
+
+/**
+ * Add a path to a buffer, converting a relative path to an
+ * absolute one in the process.  Symbolic links are not
+ * resolved.
+ */
+extern void strbuf_add_absolute_path(struct strbuf *sb, const char *path);
+
+/**
+ * Strip whitespace from a buffer. The second parameter controls if
+ * comments are considered contents to be removed or not.
+ */
+extern void stripspace(struct strbuf *buf, int skip_comments);
+
+static inline int strbuf_strip_suffix(struct strbuf *sb, const char *suffix)
+{
+       if (strip_suffix_mem(sb->buf, &sb->len, suffix)) {
+               strbuf_setlen(sb, sb->len);
+               return 1;
+       } else
+               return 0;
+}
+
+/**
+ * Split str (of length slen) at the specified terminator character.
+ * Return a null-terminated array of pointers to strbuf objects
+ * holding the substrings.  The substrings include the terminator,
+ * except for the last substring, which might be unterminated if the
+ * original string did not end with a terminator.  If max is positive,
+ * then split the string into at most max substrings (with the last
+ * substring containing everything following the (max-1)th terminator
+ * character).
+ *
+ * The most generic form is `strbuf_split_buf`, which takes an arbitrary
+ * pointer/len buffer. The `_str` variant takes a NUL-terminated string,
+ * the `_max` variant takes a strbuf, and just `strbuf_split` is a convenience
+ * wrapper to drop the `max` parameter.
+ *
+ * For lighter-weight alternatives, see string_list_split() and
+ * string_list_split_in_place().
+ */
+extern struct strbuf **strbuf_split_buf(const char *, size_t,
+                                       int terminator, int max);
+
+static inline struct strbuf **strbuf_split_str(const char *str,
+                                              int terminator, int max)
+{
+       return strbuf_split_buf(str, strlen(str), terminator, max);
+}
+
+static inline struct strbuf **strbuf_split_max(const struct strbuf *sb,
+                                               int terminator, int max)
+{
+       return strbuf_split_buf(sb->buf, sb->len, terminator, max);
+}
+
+static inline struct strbuf **strbuf_split(const struct strbuf *sb,
+                                          int terminator)
+{
+       return strbuf_split_max(sb, terminator, 0);
+}
+
+/**
+ * Free a NULL-terminated list of strbufs (for example, the return
+ * values of the strbuf_split*() functions).
+ */
+extern void strbuf_list_free(struct strbuf **);
+
+/**
+ * Launch the user preferred editor to edit a file and fill the buffer
+ * with the file's contents upon the user completing their editing. The
+ * third argument can be used to set the environment which the editor is
+ * run in. If the buffer is NULL the editor is launched as usual but the
+ * file's contents are not read into the buffer upon completion.
+ */
+extern int launch_editor(const char *path, struct strbuf *buffer, const char *const *env);
+
 extern void strbuf_add_lines(struct strbuf *sb, const char *prefix, const char *buf, size_t size);
 
-/*
+/**
  * Append s to sb, with the characters '<', '>', '&' and '"' converted
  * into XML entities.
  */
@@ -170,28 +491,11 @@ static inline void strbuf_complete_line(struct strbuf *sb)
                strbuf_addch(sb, '\n');
 }
 
-extern size_t strbuf_fread(struct strbuf *, size_t, FILE *);
-/* XXX: if read fails, any partial read is undone */
-extern ssize_t strbuf_read(struct strbuf *, int fd, size_t hint);
-extern int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint);
-extern int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint);
-extern int strbuf_getcwd(struct strbuf *sb);
-
-extern int strbuf_getwholeline(struct strbuf *, FILE *, int);
-extern int strbuf_getline(struct strbuf *, FILE *, int);
-extern int strbuf_getwholeline_fd(struct strbuf *, int, int);
-
-extern void stripspace(struct strbuf *buf, int skip_comments);
-extern int launch_editor(const char *path, struct strbuf *buffer, const char *const *env);
-
 extern int strbuf_branchname(struct strbuf *sb, const char *name);
 extern int strbuf_check_branch_ref(struct strbuf *sb, const char *name);
 
 extern void strbuf_addstr_urlencode(struct strbuf *, const char *,
                                    int reserved);
-extern void strbuf_humanise_bytes(struct strbuf *buf, off_t bytes);
-
-extern void strbuf_add_absolute_path(struct strbuf *sb, const char *path);
 
 __attribute__((format (printf,1,2)))
 extern int printf_ln(const char *fmt, ...);
@@ -200,7 +504,7 @@ extern int fprintf_ln(FILE *fp, const char *fmt, ...);
 
 char *xstrdup_tolower(const char *);
 
-/*
+/**
  * Create a newly allocated string using printf format. You can do this easily
  * with a strbuf, but this provides a shortcut to save a few lines.
  */
index 75a35fcd0699940aea51534b5fe954847bed7bb9..c211dc40eed98fc58c953d2e3b1f7ba752f98a02 100644 (file)
@@ -1,6 +1,6 @@
 :
 
-sanitize_diff_raw='/^:/s/ '"$_x40"' '"$_x40"' \([A-Z]\)[0-9]*  / X X \1#       /'
+sanitize_diff_raw='/^:/s/ '"\($_x40\)"' '"\($_x40\)"' \([A-Z]\)[0-9]*  / \1 \2 \3#     /'
 compare_diff_raw () {
     # When heuristics are improved, the score numbers would change.
     # Ignore them while comparing.
diff --git a/t/diff-lib/COPYING b/t/diff-lib/COPYING
new file mode 100644 (file)
index 0000000..6ff87c4
--- /dev/null
@@ -0,0 +1,361 @@
+
+ Note that the only valid version of the GPL as far as this project
+ is concerned is _this_ particular version of the license (ie v2, not
+ v2.2 or v3.x or whatever), unless explicitly otherwise stated.
+
+ HOWEVER, in order to allow a migration to GPLv3 if that seems like
+ a good idea, I also ask that people involved with the project make
+ their preferences known. In particular, if you trust me to make that
+ decision, you might note so in your copyright message, ie something
+ like
+
+       This file is licensed under the GPL v2, or a later version
+       at the discretion of Linus.
+
+  might avoid issues. But we can also just decide to synchronize and
+  contact all copyright holders on record if/when the occasion arises.
+
+                       Linus Torvalds
+
+----------------------------------------
+
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/t/diff-lib/README b/t/diff-lib/README
new file mode 100644 (file)
index 0000000..548142c
--- /dev/null
@@ -0,0 +1,46 @@
+////////////////////////////////////////////////////////////////
+
+       GIT - the stupid content tracker
+
+////////////////////////////////////////////////////////////////
+
+"git" can mean anything, depending on your mood.
+
+ - random three-letter combination that is pronounceable, and not
+   actually used by any common UNIX command.  The fact that it is a
+   mispronunciation of "get" may or may not be relevant.
+ - stupid. contemptible and despicable. simple. Take your pick from the
+   dictionary of slang.
+ - "global information tracker": you're in a good mood, and it actually
+   works for you. Angels sing, and a light suddenly fills the room.
+ - "goddamn idiotic truckload of sh*t": when it breaks
+
+Git is a fast, scalable, distributed revision control system with an
+unusually rich command set that provides both high-level operations
+and full access to internals.
+
+Git is an Open Source project covered by the GNU General Public License.
+It was originally written by Linus Torvalds with help of a group of
+hackers around the net. It is currently maintained by Junio C Hamano.
+
+Please read the file INSTALL for installation instructions.
+See Documentation/tutorial.txt to get started, then see
+Documentation/everyday.txt for a useful minimum set of commands,
+and "man git-commandname" for documentation of each command.
+CVS users may also want to read Documentation/cvs-migration.txt.
+
+Many Git online resources are accessible from http://git.or.cz/
+including full documentation and Git related tools.
+
+The user discussion and development of Git take place on the Git
+mailing list -- everyone is welcome to post bug reports, feature
+requests, comments and patches to git@vger.kernel.org. To subscribe
+to the list, send an email with just "subscribe git" in the body to
+majordomo@vger.kernel.org. The mailing list archives are available at
+http://marc.theaimsgroup.com/?l=git and other archival sites.
+
+The messages titled "A note from the maintainer", "What's in
+git.git (stable)" and "What's cooking in git.git (topics)" and
+the discussion following them on the mailing list give a good
+reference for project status, development direction and
+remaining tasks.
index d88da29f77d23fe2f3efc86a15daf198dddbeb69..db2ef22e8f76a54c851424dd19c1232f6061392c 100755 (executable)
@@ -23,6 +23,8 @@ else
                # To write armored exported key to keyring:
                #       gpg --homedir /tmp/gpghome --export-secret-keys \
                #               --armor 0xDEADBEEF >> lib-gpg/keyring.gpg
+               #       gpg --homedir /tmp/gpghome --export \
+               #               --armor 0xDEADBEEF >> lib-gpg/keyring.gpg
                # To export ownertrust:
                #       gpg --homedir /tmp/gpghome --export-ownertrust \
                #               > lib-gpg/ownertrust
@@ -34,6 +36,8 @@ else
                        "$TEST_DIRECTORY"/lib-gpg/keyring.gpg &&
                gpg --homedir "${GNUPGHOME}" 2>/dev/null --import-ownertrust \
                        "$TEST_DIRECTORY"/lib-gpg/ownertrust &&
+               gpg --homedir "${GNUPGHOME}" </dev/null >/dev/null 2>&1 \
+                       --sign -u committer@example.com &&
                test_set_prereq GPG
                ;;
        esac
index fb1f048c22fc9bdc32c27ac931f149c65f89ed24..d4754a1f19c7984b3286cfd9dfa9740a790800e0 100644 (file)
@@ -86,3 +86,57 @@ Z9Ei+zj6JD5Pcdi3BJhQo9WOLOVEJ0NHmewTYqk9QVXH/0v1Hdl4LMJtgcbdbDWk
 BOW78WUxzhu0YJTLKy+iKCjg5HS5dx6OC+e4aEEgfhNPCMkbvDsJjtQ=
 =hieJ
 -----END PGP PRIVATE KEY BLOCK-----
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1
+
+mQGiBEZnyykRBACzCPjIpTYNL7Y2tQqlEGTTDlvZcWNLjF5f7ZzuyOqNOidLUgFD
+36qch1LZLSZkShdR3Gae+bsolyjxrlFuFP0eXRPMtqK20aLw7WZvPFpEV1ThMne+
+PRJjYrvghWw3L0VVIAIZ8GXwrVBuU99uEjHEI0ojYloOvFc2jVPgSaoBvwCg48Tj
+fol2foSoJa7XUu9yAL8szg8D/RUsTzNF+I9hSRHl7MYKFMYoKEY9BDgrgAujp7YY
+8qdGsiUb0Ggyzp2kRjZFt4lpcvKhGfHn5GEjmtk+fRbD5qPfMqKFW+T0NPfYlYmL
+JJ4fs4qZ8Lx7x6iG6X51u+YNwsQuIGjMCC3CeNi3F7or651kkNYASbaQ1NROkCIN
+NudyA/0aasvoZUoNJAc2cP5Ifs6WhXMWLfMR2p2XbfKwKNYneec60usnSComcKqh
+sJVk0Gytvr3FOYVhRkXnKAbx+0W2urFP8OFVBTEKO6Ts2VygWGgneQYoHnqzwlUE
+yjOjlr+lyf7u2s/KAxpKA6jnttEdRZAmzWkhuox1wwAUkr27/bQiQyBPIE1pdHRl
+ciA8Y29tbWl0dGVyQGV4YW1wbGUuY29tPoheBBMRAgAeBQJGZ8spAhsDBgsJCAcD
+AgMVAgMDFgIBAh4BAheAAAoJEBO29R7N3kMNdB0AoL3Z/7A6tORuY8R/676oD8a/
+oHFDAJ9DXbwlcKLcykwHy0jYqajXm1iCebkCDQRGZ8tOEAgAzrl5P1Pr6CDR8mf5
+DGGzcUUM+PEroA4FLdKJ5ZaZc7qy1lmmW9vuvb6xdinwcwee2c5fdNE+iUjHV2x2
+S/dbfDzJTN/0uajZcw+xnf+KxZ0Rs4gDSs7cHXHBtA7u8ShYd4Hu7JggXpiwgfSk
+yrGQiZyLAHW2ck8H07Go8eUP8fLIeva+iPqeYQZo9BaPz92R/J6debpeY1lRkv+y
+WTq1GE3C/hxbdBAuHf2duLP2uq9kwoVdfzCRjgV1CQmMIbCrMb7vIlzIe96bb3+K
+r/+NEtmB2I3wHBXcwJMnIOnz9Zv933KNlxSbVF23BGLB+F9D7OanKymbs7Eg18fr
+mt/t/wAEDQgAtGIxGz944Pn2OtheY9JlBRuIAuVskm24/Zz03dZnk6CuEOIBb5IM
+g36GAPKcn1vsLZ0TfE1q53jNpcAAXjgngnRsCjZm1mglqPD4ZfBpl+Hhnuc80fAR
+xsUPj+5c8KP2M+Rws4moaZRjVpd3KCi3ceflT/OjwnE9DzdhslCGTMA5n8cajAs2
+oqAaQssefVf2prLQLGV9NB4Q3lFnKXdvipHMaAYAsW+iF7JkhTDVNuNGlufeSqUm
+igRBjTZXBcVd8sj8vDOCWKUfqxJyS+zRYcotn7QvpvcKAkc3ZGxntDHAIGLVp6ay
++vrkV4Ren8BjFobl25Ruy6Abw+CgnTpuwYhJBBgRAgAJBQJGZ8tOAhsMAAoJEBO2
+9R7N3kMNwewAoNBygC0NYkW6lVGqV4EJ7PHhDaSEAJwKz78u0Twtv2EL7Zy+ve4f
+mnzYApkBDQRRTJZHAQgAyYv8ZwBfMiN+Dx4pUgmzO1bThTte6BTJKbuHIDdkKT7j
+OTFY8nL68ykoLmRbzwgy83gBSVtbj8S+Eh2h0pIrAqxYYox+ziVnDjzT0hQsLvop
+wKALLx5uJ7OqXw2ckY1Ux0mOK3TCEqihUaM2l7vLx3gUcyIRZ7mwQnqSmVtO6Cj5
+65xC1U1VElFSPunpfCRZiSFscSzS4X0UUjxdL+DA1zxf/4glomQyPidaS70OVf3+
+2LX7AxldKD2Ouie9gRSRueeXigbbZzWPdNS5iN6HJ+T+YlZ1w2qjBJcOxSqZwDV7
+nIGNx+JC8jZCN7NydAhm1yO29zAVrY3LboVr9athuQARAQABtCRFcmlzIERpc2Nv
+cmRpYSA8ZGlzY29yZEBleGFtcGxlLm5ldD6JATgEEwECACIFAlFMlkcCGwMGCwkI
+BwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEGEJLoW3InGJWKMH+wfn/hQ3C1X8PF8x
+pSpLtRejyNchgrewDDtvyZJjuC5YB7iIBaanuW/14ypdCLEXG1S4raoiKJHPLvux
+/MmFOuww5Yqu7dYKgcvqk4Uh3IJ+ljCk2qgqjhNo8x8qrpSAM0LCUPnOUkaHxGQC
+k+EGtg8vp7Klg6SBO/GiXdFZ5JPVOh9lbgAb1HjfyDIL8T6+duaPqwQ+y1OCdwrT
+s31frDuvt93WvgZvVIZEeLQuB/59XQzdSWLsQUG4MU6v4fJinuP+/2L8vuVrGHfe
+mUSxNmRVnll7SpMJmG0ONht0mVF2mfEfDrW08lK42xSoqTuML18Ico7tZfXMQLK3
+GusW0gi5AQ0EUUyWRwEIAKk7TxXE16jPlKO2zqKPnXB4vFw3//F0hJmXzCnP1OaU
+kwZO4dYEirhs4xdp98EJugPPtdNb0y2kOj6BQxVvLkAdNJo8phq0Q2BYM/G44Z2n
+pGZwOF04a9UTo334DIbN7k6Qnm3VfpS/CtKCUx3N/Uzy04NtwxXEUgzftwESSUu/
+gkQSG7fS+YDm6YAOB1Gqf6OjeztOK0Dj1PNzAKp8KNiUzvw3ndM6GndFaN9TZpOB
+firxBOdn7Rh23e8qiFBigbdknkwIfOdGnC3jWT/ldWO2rQQq+/85viaR1qvTh+/z
+aJpRCJMS/Fg7fBnwCqKmYKnny/gAhJy2wLdXbt39BbMAEQEAAYkBHwQYAQIACQUC
+UUyWRwIbDAAKCRBhCS6FtyJxiexxCADF5DH+HDlppwLr73EptyqS4IblopPXcn59
+bGPyBuWraCivsqZlf05QZTGahUM7jyCUE/FS25sbS5Q4SRtOC2yOnPGsSGcTjmSi
+8uZ000stes7ahHku3onxyz2YNVBRchBCENV1tAjQwHrliofdBEY8peAoOz51kmfR
+Ivs4+iQ+T3HYtwSYUKPVjizlRCdDR5nsE2KpPUFVx/9L9R3ZeCzCbYHG3Ww1pOFE
+5F24PaZ97pgoJDSd1bPH1pyFjvSM3a9v8KxWNib1E+2L5fsLDSFmrbzhMxsu5wTl
+u/FlMc4btGCUyysvoigo4OR0uXcejgvnuGhBIH4TTwjJG7w7CY7U
+=iYv/
+-----END PGP PUBLIC KEY BLOCK-----
index fd53b5718780e25f03924e38438706acc54598db..e6adf2f82d59027279e06e0d273e719226d82184 100644 (file)
@@ -37,7 +37,7 @@ then
        test_done
 fi
 
-if ! test_have_prereq SANITY; then
+if ! test_have_prereq NOT_ROOT; then
        test_skip_or_die $GIT_TEST_HTTPD \
                "Cannot run httpd tests as root"
 fi
@@ -79,6 +79,7 @@ HTTPD_DOCUMENT_ROOT_PATH=$HTTPD_ROOT_PATH/www
 # hack to suppress apache PassEnv warnings
 GIT_VALGRIND=$GIT_VALGRIND; export GIT_VALGRIND
 GIT_VALGRIND_OPTIONS=$GIT_VALGRIND_OPTIONS; export GIT_VALGRIND_OPTIONS
+GIT_TRACE=$GIT_TRACE; export GIT_TRACE
 
 if ! test -x "$LIB_HTTPD_PATH"
 then
index 03a4c2ee842e51e13b14774f1f86a4e7b22ae10c..0b81a0047b8d9cd60266500907e95ddc5b87742c 100644 (file)
@@ -70,6 +70,7 @@ PassEnv GIT_VALGRIND
 PassEnv GIT_VALGRIND_OPTIONS
 PassEnv GNUPGHOME
 PassEnv ASAN_OPTIONS
+PassEnv GIT_TRACE
 
 Alias /dumb/ www/
 Alias /auth/dumb/ www/auth/dumb/
index 99c037703a676dd63e4c2b53ea87601fc2503b88..2630e756dab7322a5360a67766a648a80a5a7222 100755 (executable)
@@ -14,6 +14,16 @@ test_expect_success '"git -C <path>" runs git from the directory <path>' '
        test_cmp expected actual
 '
 
+test_expect_success '"git -C <path>" with an empty <path> is a no-op' '
+       (
+               mkdir -p dir1/subdir &&
+               cd dir1/subdir &&
+               git -C "" rev-parse --show-prefix >actual &&
+               echo subdir/ >expect &&
+               test_cmp expect actual
+       )
+'
+
 test_expect_success 'Multiple -C options: "-C dir1 -C dir2" is equivalent to "-C dir1/dir2"' '
        test_create_repo dir1/dir2 &&
        echo 1 >dir1/dir2/b.txt &&
index 17e969df609f71b0b4562cff8fda112632d27442..9acf628726fe0c648279fb724f1917435db206f7 100755 (executable)
@@ -34,7 +34,7 @@ test_expect_success POSIXPERM 'run_command reports EACCES' '
        grep "fatal: cannot exec.*hello.sh" err
 '
 
-test_expect_success POSIXPERM 'unreadable directory in PATH' '
+test_expect_success POSIXPERM,SANITY 'unreadable directory in PATH' '
        mkdir local-command &&
        test_when_finished "chmod u+rwx local-command && rm -fr local-command" &&
        git config alias.nitfol "!echo frotz" &&
index fdc257e66fdc121b9f125466bf38431e3233dd19..3c6791e6be705bc823ff180cd481fef3dc939734 100755 (executable)
@@ -67,4 +67,13 @@ test_expect_success 'parse errors in blobs are properly attributed' '
        grep "HEAD:config" err
 '
 
+test_expect_success 'can parse blob ending with CR' '
+       printf "[some]key = value\\r" >config &&
+       git add config &&
+       git commit -m CR &&
+       echo value >expect &&
+       git config --blob=HEAD:config some.key >actual &&
+       test_cmp expect actual
+'
+
 test_done
index 335420fd87f87727f323156f461e520374b7da0b..b6977d4b390ec9a3f4f3b621db88908a2c40f689 100755 (executable)
@@ -98,8 +98,16 @@ test_foobar_foobar() {
        '
 }
 
-if ! test_have_prereq POSIXPERM || ! [ -w / ]; then
-       skip_all="Dangerous test skipped. Read this test if you want to execute it"
+if ! test -w /
+then
+       skip_all="Test requiring writable / skipped. Read this test if you want to run it"
+       test_done
+fi
+
+if  test -e /refs || test -e /objects || test -e /info || test -e /hooks ||
+    test -e /.git || test -e /foo || test -e /me
+then
+       skip_all="Skip test that clobbers existing files in /"
        test_done
 fi
 
@@ -108,8 +116,9 @@ if [ "$IKNOWWHATIAMDOING" != "YES" ]; then
        test_done
 fi
 
-if [ "$UID" = 0 ]; then
-       skip_all="No you can't run this with root"
+if ! test_have_prereq NOT_ROOT
+then
+       skip_all="No you can't run this as root"
        test_done
 fi
 
index ba4f98e800f262242ef7925f82dc8d13272fe3ca..f51d0f3cadcb4f97f4cf9f2d79aad9ed401781d8 100755 (executable)
@@ -96,7 +96,7 @@ test_expect_success 'git branch -v pattern does not show branch summaries' '
 
 test_expect_success 'git branch shows detached HEAD properly' '
        cat >expect <<EOF &&
-* (detached from $(git rev-parse --short HEAD^0))
+* (HEAD detached at $(git rev-parse --short HEAD^0))
   branch-one
   branch-two
   master
@@ -106,4 +106,41 @@ EOF
        test_i18ncmp expect actual
 '
 
+test_expect_success 'git branch shows detached HEAD properly after moving' '
+       cat >expect <<EOF &&
+* (HEAD detached from $(git rev-parse --short HEAD))
+  branch-one
+  branch-two
+  master
+EOF
+       git reset --hard HEAD^1 &&
+       git branch >actual &&
+       test_i18ncmp expect actual
+'
+
+test_expect_success 'git branch shows detached HEAD properly from tag' '
+       cat >expect <<EOF &&
+* (HEAD detached at fromtag)
+  branch-one
+  branch-two
+  master
+EOF
+       git tag fromtag master &&
+       git checkout fromtag &&
+       git branch >actual &&
+       test_i18ncmp expect actual
+'
+
+test_expect_success 'git branch shows detached HEAD properly after moving from tag' '
+       cat >expect <<EOF &&
+* (HEAD detached from fromtag)
+  branch-one
+  branch-two
+  master
+EOF
+       git reset --hard HEAD^1 &&
+       git branch >actual &&
+       test_i18ncmp expect actual
+'
+
 test_done
index 8197ed29a9ecedb43679200f1485a7b50984fdff..034eb35cdf3f13686f10737267567c08e749ad1c 100755 (executable)
@@ -1039,4 +1039,20 @@ test_expect_success 'short SHA-1 collide' '
        )
 '
 
+test_expect_success 'respect core.abbrev' '
+       git config core.abbrev 12 &&
+       set_cat_todo_editor &&
+       test_must_fail git rebase -i HEAD~4 >todo-list &&
+       test 4 = $(grep -c "pick [0-9a-f]\{12,\}" todo-list)
+'
+
+test_expect_success 'todo count' '
+       write_script dump-raw.sh <<-\EOF &&
+               cat "$1"
+       EOF
+       test_set_editor "$(pwd)/dump-raw.sh" &&
+       git rebase -i HEAD~4 >actual &&
+       grep "^# Rebase ..* onto ..* ([0-9]" actual
+'
+
 test_done
index f97727975b880ae52394c6af11dde15b71ac6eb7..b7dff09d0656930332f347bd3106d1473015abd0 100755 (executable)
@@ -36,6 +36,20 @@ mesg_with_cherry_footer="$mesg_with_footer_sob
 (cherry picked from commit da39a3ee5e6b4b0d3255bfef95601890afd80709)
 Tested-by: C.U. Thor <cuthor@example.com>"
 
+mesg_unclean="$mesg_one_line
+
+
+leading empty lines
+
+
+consecutive empty lines
+
+# hash tag comment
+
+trailing empty lines
+
+
+"
 
 test_expect_success setup '
        git config advice.detachedhead false &&
@@ -53,6 +67,10 @@ test_expect_success setup '
        test_commit "$mesg_with_footer_sob" foo b mesg-with-footer-sob &&
        git reset --hard initial &&
        test_commit "$mesg_with_cherry_footer" foo b mesg-with-cherry-footer &&
+       git reset --hard initial &&
+       test_config commit.cleanup verbatim &&
+       test_commit "$mesg_unclean" foo b mesg-unclean &&
+       test_unconfig commit.cleanup &&
        pristine_detach initial &&
        test_commit conflicting unrelated
 '
@@ -216,4 +234,14 @@ test_expect_success 'cherry-pick -x -s treats "(cherry picked from..." line as p
        test_cmp expect actual
 '
 
+test_expect_success 'cherry-pick preserves commit message' '
+       pristine_detach initial &&
+       printf "$mesg_unclean" >expect &&
+       git log -1 --pretty=format:%B mesg-unclean >actual &&
+       test_cmp expect actual &&
+       git cherry-pick mesg-unclean &&
+       git log -1 --pretty=format:%B >actual &&
+       test_cmp expect actual
+'
+
 test_done
index bfa88356382ab9f37e6e510516bf1fc6a3811961..df2accb6555d4202c789b8ffb13ae3943268586d 100755 (executable)
@@ -11,7 +11,7 @@ test_description='More rename detection
 
 test_expect_success \
     'prepare reference tree' \
-    'cat "$TEST_DIRECTORY"/../COPYING >COPYING &&
+    'cat "$TEST_DIRECTORY"/diff-lib/COPYING >COPYING &&
      echo frotz >rezrov &&
     git update-index --add COPYING rezrov &&
     tree=$(git write-tree) &&
@@ -99,7 +99,7 @@ test_expect_success \
 
 test_expect_success \
     'prepare work tree once again' \
-    'cat "$TEST_DIRECTORY"/../COPYING >COPYING &&
+    'cat "$TEST_DIRECTORY"/diff-lib/COPYING >COPYING &&
      git update-index --add --remove COPYING COPYING.1'
 
 # tree has COPYING and rezrov.  work tree has COPYING and COPYING.1,
index 7d2c6e13a2a7f5d8e9e863d83e6b7b716810c970..135addbfbdae8e39ba0462e71278f41dfc552620 100755 (executable)
@@ -11,7 +11,7 @@ test_description='Same rename detection as t4003 but testing diff-raw.
 
 test_expect_success \
     'prepare reference tree' \
-    'cat "$TEST_DIRECTORY"/../COPYING >COPYING &&
+    'cat "$TEST_DIRECTORY"/diff-lib/COPYING >COPYING &&
      echo frotz >rezrov &&
     git update-index --add COPYING rezrov &&
     tree=$(git write-tree) &&
@@ -71,7 +71,7 @@ test_expect_success \
 
 test_expect_success \
     'prepare work tree once again' \
-    'cat "$TEST_DIRECTORY"/../COPYING >COPYING &&
+    'cat "$TEST_DIRECTORY"/diff-lib/COPYING >COPYING &&
      git update-index --add --remove COPYING COPYING.1'
 
 git diff-index -C --find-copies-harder $tree >current
index 11502b750997aba0ecfb6aa5b07c9aad1c45d592..dae327fabbfe390a3dc707ef2ebc665c9c6e3cb3 100755 (executable)
@@ -11,7 +11,7 @@ test_description='Rename interaction with pathspec.
 
 test_expect_success 'prepare reference tree' '
        mkdir path0 path1 &&
-       cp "$TEST_DIRECTORY"/../COPYING path0/COPYING &&
+       cp "$TEST_DIRECTORY"/diff-lib/COPYING path0/COPYING &&
        git update-index --add path0/COPYING &&
        tree=$(git write-tree) &&
        echo $tree
index 89204648965b2b6b7d7984e3398b3ef21a8d7c7e..9dd1bc5e162bb0b8821337a1e43cd8ad85423507 100755 (executable)
@@ -10,179 +10,145 @@ We have two very different files, file0 and file1, registered in a tree.
 We update file1 so drastically that it is more similar to file0, and
 then remove file0.  With -B, changes to file1 should be broken into
 separate delete and create, resulting in removal of file0, removal of
-original file1 and creation of completely rewritten file1.
+original file1 and creation of completely rewritten file1.  The latter
+two are then merged back into a single "complete rewrite".
 
 Further, with -B and -M together, these three modifications should
 turn into rename-edit of file0 into file1.
 
 Starting from the same two files in the tree, we swap file0 and file1.
-With -B, this should be detected as two complete rewrites, resulting in
-four changes in total.
+With -B, this should be detected as two complete rewrites.
 
 Further, with -B and -M together, these should turn into two renames.
 '
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/diff-lib.sh ;# test-lib chdir's into trash
 
-test_expect_success \
-    setup \
-    'cat "$TEST_DIRECTORY"/../README >file0 &&
-     cat "$TEST_DIRECTORY"/../COPYING >file1 &&
-    git update-index --add file0 file1 &&
-    tree=$(git write-tree) &&
-    echo "$tree"'
-
-test_expect_success \
-    'change file1 with copy-edit of file0 and remove file0' \
-    'sed -e "s/git/GIT/" file0 >file1 &&
-     rm -f file0 &&
-    git update-index --remove file0 file1'
-
-test_expect_success \
-    'run diff with -B' \
-    'git diff-index -B --cached "$tree" >current'
-
-cat >expected <<\EOF
-:100644 000000 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 0000000000000000000000000000000000000000 D     file0
-:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 11e331465a89c394dc25c780de230043750c1ec8 M100  file1
-EOF
-
-test_expect_success \
-    'validate result of -B (#1)' \
-    'compare_diff_raw expected current'
-
-test_expect_success \
-    'run diff with -B and -M' \
-    'git diff-index -B -M "$tree" >current'
-
-cat >expected <<\EOF
-:100644 100644 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 08bb2fb671deff4c03a4d4a0a1315dff98d5732c R100  file0   file1
-EOF
-
-test_expect_success \
-    'validate result of -B -M (#2)' \
-    'compare_diff_raw expected current'
-
-test_expect_success \
-    'swap file0 and file1' \
-    'rm -f file0 file1 &&
-     git read-tree -m $tree &&
-     git checkout-index -f -u -a &&
-     mv file0 tmp &&
-     mv file1 file0 &&
-     mv tmp file1 &&
-     git update-index file0 file1'
-
-test_expect_success \
-    'run diff with -B' \
-    'git diff-index -B "$tree" >current'
-
-cat >expected <<\EOF
-:100644 100644 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 6ff87c4664981e4397625791c8ea3bbb5f2279a3 M100  file0
-:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 M100  file1
-EOF
-
-test_expect_success \
-    'validate result of -B (#3)' \
-    'compare_diff_raw expected current'
-
-test_expect_success \
-    'run diff with -B and -M' \
-    'git diff-index -B -M "$tree" >current'
-
-cat >expected <<\EOF
-:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 6ff87c4664981e4397625791c8ea3bbb5f2279a3 R100  file1   file0
-:100644 100644 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 R100  file0   file1
-EOF
-
-test_expect_success \
-    'validate result of -B -M (#4)' \
-    'compare_diff_raw expected current'
-
-test_expect_success \
-    'make file0 into something completely different' \
-    'rm -f file0 &&
-     test_ln_s_add frotz file0 &&
-     git update-index file1'
-
-test_expect_success \
-    'run diff with -B' \
-    'git diff-index -B "$tree" >current'
-
-cat >expected <<\EOF
-:100644 120000 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 67be421f88824578857624f7b3dc75e99a8a1481 T     file0
-:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 M100  file1
-EOF
-
-test_expect_success \
-    'validate result of -B (#5)' \
-    'compare_diff_raw expected current'
-
-test_expect_success \
-    'run diff with -B -M' \
-    'git diff-index -B -M "$tree" >current'
-
-# file0 changed from regular to symlink.  file1 is very close to the preimage of file0.
-# the change does not make file0 disappear, so file1 is denoted as a copy of file0
-cat >expected <<\EOF
-:100644 120000 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 67be421f88824578857624f7b3dc75e99a8a1481 T     file0
-:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 C     file0   file1
-EOF
-
-test_expect_success \
-    'validate result of -B -M (#6)' \
-    'compare_diff_raw expected current'
-
-test_expect_success \
-    'run diff with -M' \
-    'git diff-index -M "$tree" >current'
-
-# This should not mistake file0 as the copy source of new file1
-# due to type differences.
-cat >expected <<\EOF
-:100644 120000 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 67be421f88824578857624f7b3dc75e99a8a1481 T     file0
-:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 M     file1
-EOF
-
-test_expect_success \
-    'validate result of -M (#7)' \
-    'compare_diff_raw expected current'
-
-test_expect_success \
-    'file1 edited to look like file0 and file0 rename-edited to file2' \
-    'rm -f file0 file1 &&
-     git read-tree -m $tree &&
-     git checkout-index -f -u -a &&
-     sed -e "s/git/GIT/" file0 >file1 &&
-     sed -e "s/git/GET/" file0 >file2 &&
-     rm -f file0 &&
-     git update-index --add --remove file0 file1 file2'
-
-test_expect_success \
-    'run diff with -B' \
-    'git diff-index -B "$tree" >current'
-
-cat >expected <<\EOF
-:100644 000000 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 0000000000000000000000000000000000000000 D     file0
-:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 08bb2fb671deff4c03a4d4a0a1315dff98d5732c M100  file1
-:000000 100644 0000000000000000000000000000000000000000 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 A     file2
-EOF
-
-test_expect_success \
-    'validate result of -B (#8)' \
-    'compare_diff_raw expected current'
-
-test_expect_success \
-    'run diff with -B -C' \
-    'git diff-index -B -C "$tree" >current'
-
-cat >expected <<\EOF
-:100644 100644 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 08bb2fb671deff4c03a4d4a0a1315dff98d5732c C095  file0   file1
-:100644 100644 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 59f832e5c8b3f7e486be15ad0cd3e95ba9af8998 R095  file0   file2
-EOF
-
-test_expect_success \
-    'validate result of -B -M (#9)' \
-    'compare_diff_raw expected current'
+test_expect_success setup '
+       cat "$TEST_DIRECTORY"/diff-lib/README >file0 &&
+       cat "$TEST_DIRECTORY"/diff-lib/COPYING >file1 &&
+       git update-index --add file0 file1 &&
+       git tag reference $(git write-tree)
+'
+
+test_expect_success 'change file1 with copy-edit of file0 and remove file0' '
+       sed -e "s/git/GIT/" file0 >file1 &&
+       rm -f file0 &&
+       git update-index --remove file0 file1
+'
+
+test_expect_success 'run diff with -B (#1)' '
+       git diff-index -B --cached reference >current &&
+       cat >expect <<-\EOF &&
+       :100644 000000 548142c327a6790ff8821d67c2ee1eff7a656b52 0000000000000000000000000000000000000000 D      file0
+       :100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 2fbedd0b5d4b8126e4750c3bee305e8ff79f80ec M100   file1
+       EOF
+       compare_diff_raw expect current
+'
+
+test_expect_success 'run diff with -B and -M (#2)' '
+       git diff-index -B -M reference >current &&
+       cat >expect <<-\EOF &&
+       :100644 100644 548142c327a6790ff8821d67c2ee1eff7a656b52 2fbedd0b5d4b8126e4750c3bee305e8ff79f80ec R100   file0   file1
+       EOF
+       compare_diff_raw expect current
+'
+
+test_expect_success 'swap file0 and file1' '
+       rm -f file0 file1 &&
+       git read-tree -m reference &&
+       git checkout-index -f -u -a &&
+       mv file0 tmp &&
+       mv file1 file0 &&
+       mv tmp file1 &&
+       git update-index file0 file1
+'
+
+test_expect_success 'run diff with -B (#3)' '
+       git diff-index -B reference >current &&
+       cat >expect <<-\EOF &&
+       :100644 100644 548142c327a6790ff8821d67c2ee1eff7a656b52 6ff87c4664981e4397625791c8ea3bbb5f2279a3 M100   file0
+       :100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 548142c327a6790ff8821d67c2ee1eff7a656b52 M100   file1
+       EOF
+       compare_diff_raw expect current
+'
+
+test_expect_success 'run diff with -B and -M (#4)' '
+       git diff-index -B -M reference >current &&
+       cat >expect <<-\EOF &&
+       :100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 6ff87c4664981e4397625791c8ea3bbb5f2279a3 R100   file1   file0
+       :100644 100644 548142c327a6790ff8821d67c2ee1eff7a656b52 548142c327a6790ff8821d67c2ee1eff7a656b52 R100   file0   file1
+       EOF
+       compare_diff_raw expect current
+'
+
+test_expect_success 'make file0 into something completely different' '
+       rm -f file0 &&
+       test_ln_s_add frotz file0 &&
+       git update-index file1
+'
+
+test_expect_success 'run diff with -B (#5)' '
+       git diff-index -B reference >current &&
+       cat >expect <<-\EOF &&
+       :100644 120000 548142c327a6790ff8821d67c2ee1eff7a656b52 67be421f88824578857624f7b3dc75e99a8a1481 T      file0
+       :100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 548142c327a6790ff8821d67c2ee1eff7a656b52 M100   file1
+       EOF
+       compare_diff_raw expect current
+'
+
+test_expect_success 'run diff with -B -M (#6)' '
+       git diff-index -B -M reference >current &&
+
+       # file0 changed from regular to symlink.  file1 is the same as the preimage
+       # of file0.  Because the change does not make file0 disappear, file1 is
+       # denoted as a copy of file0
+       cat >expect <<-\EOF &&
+       :100644 120000 548142c327a6790ff8821d67c2ee1eff7a656b52 67be421f88824578857624f7b3dc75e99a8a1481 T      file0
+       :100644 100644 548142c327a6790ff8821d67c2ee1eff7a656b52 548142c327a6790ff8821d67c2ee1eff7a656b52 C      file0   file1
+       EOF
+       compare_diff_raw expect current
+'
+
+test_expect_success 'run diff with -M (#7)' '
+       git diff-index -M reference >current &&
+
+       # This should not mistake file0 as the copy source of new file1
+       # due to type differences.
+       cat >expect <<-\EOF &&
+       :100644 120000 548142c327a6790ff8821d67c2ee1eff7a656b52 67be421f88824578857624f7b3dc75e99a8a1481 T      file0
+       :100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 548142c327a6790ff8821d67c2ee1eff7a656b52 M      file1
+       EOF
+       compare_diff_raw expect current
+'
+
+test_expect_success 'file1 edited to look like file0 and file0 rename-edited to file2' '
+       rm -f file0 file1 &&
+       git read-tree -m reference &&
+       git checkout-index -f -u -a &&
+       sed -e "s/git/GIT/" file0 >file1 &&
+       sed -e "s/git/GET/" file0 >file2 &&
+       rm -f file0 &&
+       git update-index --add --remove file0 file1 file2
+'
+
+test_expect_success 'run diff with -B (#8)' '
+       git diff-index -B reference >current &&
+       cat >expect <<-\EOF &&
+       :100644 000000 548142c327a6790ff8821d67c2ee1eff7a656b52 0000000000000000000000000000000000000000 D      file0
+       :100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 2fbedd0b5d4b8126e4750c3bee305e8ff79f80ec M100   file1
+       :000000 100644 0000000000000000000000000000000000000000 69a939f651686f56322566e2fd76715947a24162 A      file2
+       EOF
+       compare_diff_raw expect current
+'
+
+test_expect_success 'run diff with -B -C (#9)' '
+       git diff-index -B -C reference >current &&
+       cat >expect <<-\EOF &&
+       :100644 100644 548142c327a6790ff8821d67c2ee1eff7a656b52 2fbedd0b5d4b8126e4750c3bee305e8ff79f80ec C095   file0   file1
+       :100644 100644 548142c327a6790ff8821d67c2ee1eff7a656b52 69a939f651686f56322566e2fd76715947a24162 R095   file0   file2
+       EOF
+       compare_diff_raw expect current
+'
 
 test_done
index 57c094fdcea160a7816680d66efac9c05dd57cc8..3641fd84d68612786ab55beb780209c89311e105 100755 (executable)
@@ -11,7 +11,7 @@ test_description='Same rename detection as t4003 but testing diff-raw -z.
 
 test_expect_success \
     'prepare reference tree' \
-    'cat "$TEST_DIRECTORY"/../COPYING >COPYING &&
+    'cat "$TEST_DIRECTORY"/diff-lib/COPYING >COPYING &&
      echo frotz >rezrov &&
     git update-index --add COPYING rezrov &&
     tree=$(git write-tree) &&
@@ -78,7 +78,7 @@ test_expect_success \
 
 test_expect_success \
     'prepare work tree once again' \
-    'cat "$TEST_DIRECTORY"/../COPYING >COPYING &&
+    'cat "$TEST_DIRECTORY"/diff-lib/COPYING >COPYING &&
      git update-index --add --remove COPYING COPYING.1'
 
 git diff-index -z -C --find-copies-harder $tree >current
index bf078418662c4bab4e512be8fc22a5aa76466119..43c488b545e6acc02bab9d496e33c37b99f49c7a 100755 (executable)
@@ -56,7 +56,7 @@ test_expect_success \
      compare_diff_raw current expected'
 
 cat >expected <<\EOF
-:100644 100644 766498d93a4b06057a8e49d23f4068f1170ff38f 0a41e115ab61be0328a19b29f18cdcb49338d516 M     file0
+:100644 100644 8e4020bb5a8d8c873b25de15933e75cc0fc275df dca6b92303befc93086aa025d90a5facd7eb2812 M     file0
 EOF
 test_expect_success \
     'limit to file0 should show file0' \
index 27d3eabc26f35401581d64f0a933fb552e5f4d52..3aa16a9e423bae96815718d0aef235060659a7c1 100644 (file)
@@ -5,7 +5,7 @@ Date:   Mon Jun 26 00:06:00 2006 +0000
 
     Rearranged lines in dir/sub
 
-commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD, master)
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD -> master)
 Merge: 9a6d494 c7a2ab9
 Author: A U Thor <author@example.com>
 Date:   Mon Jun 26 00:04:00 2006 +0000
index ed7e093366bcbdaa177bac4294a07fc52d4233ed..0d50dce97e86a26bac7c798f020a1807936cc3c3 100755 (executable)
@@ -973,4 +973,18 @@ test_expect_success 'diff.dirstat=future_param,0,lines should warn, but still wo
        test_i18ngrep -q "diff\\.dirstat" actual_error
 '
 
+test_expect_success '--shortstat --dirstat should output only one dirstat' '
+       git diff --shortstat --dirstat=changes HEAD^..HEAD >out &&
+       grep " dst/copy/changed/$" out >actual_diff_shortstat_dirstat_changes &&
+       test_line_count = 1 actual_diff_shortstat_dirstat_changes &&
+
+       git diff --shortstat --dirstat=lines HEAD^..HEAD >out &&
+       grep " dst/copy/changed/$" out >actual_diff_shortstat_dirstat_lines &&
+       test_line_count = 1 actual_diff_shortstat_dirstat_lines &&
+
+       git diff --shortstat --dirstat=files HEAD^..HEAD >out &&
+       grep " dst/copy/changed/$" out >actual_diff_shortstat_dirstat_files &&
+       test_line_count = 1 actual_diff_shortstat_dirstat_files
+'
+
 test_done
diff --git a/t/t4058-diff-duplicates.sh b/t/t4058-diff-duplicates.sh
new file mode 100755 (executable)
index 0000000..0a23242
--- /dev/null
@@ -0,0 +1,79 @@
+#!/bin/sh
+
+test_description='test tree diff when trees have duplicate entries'
+. ./test-lib.sh
+
+# make_tree_entry <mode> <mode> <sha1>
+#
+# We have to rely on perl here because not all printfs understand
+# hex escapes (only octal), and xxd is not portable.
+make_tree_entry () {
+       printf '%s %s\0' "$1" "$2" &&
+       perl -e 'print chr(hex($_)) for ($ARGV[0] =~ /../g)' "$3"
+}
+
+# Like git-mktree, but without all of the pesky sanity checking.
+# Arguments come in groups of three, each group specifying a single
+# tree entry (see make_tree_entry above).
+make_tree () {
+       while test $# -gt 2; do
+               make_tree_entry "$1" "$2" "$3"
+               shift; shift; shift
+       done |
+       git hash-object -w -t tree --stdin
+}
+
+# this is kind of a convoluted setup, but matches
+# a real-world case. Each tree contains four entries
+# for the given path, one with one sha1, and three with
+# the other. The first tree has them split across
+# two subtrees (which are themselves duplicate entries in
+# the root tree), and the second has them all in a single subtree.
+test_expect_success 'create trees with duplicate entries' '
+       blob_one=$(echo one | git hash-object -w --stdin) &&
+       blob_two=$(echo two | git hash-object -w --stdin) &&
+       inner_one_a=$(make_tree \
+               100644 inner $blob_one
+       ) &&
+       inner_one_b=$(make_tree \
+               100644 inner $blob_two \
+               100644 inner $blob_two \
+               100644 inner $blob_two
+       ) &&
+       outer_one=$(make_tree \
+               040000 outer $inner_one_a \
+               040000 outer $inner_one_b
+       ) &&
+       inner_two=$(make_tree \
+               100644 inner $blob_one \
+               100644 inner $blob_two \
+               100644 inner $blob_two \
+               100644 inner $blob_two
+       ) &&
+       outer_two=$(make_tree \
+               040000 outer $inner_two
+       ) &&
+       git tag one $outer_one &&
+       git tag two $outer_two
+'
+
+test_expect_success 'diff-tree between trees' '
+       {
+               printf ":000000 100644 $_z40 $blob_two A\touter/inner\n" &&
+               printf ":000000 100644 $_z40 $blob_two A\touter/inner\n" &&
+               printf ":000000 100644 $_z40 $blob_two A\touter/inner\n" &&
+               printf ":100644 000000 $blob_two $_z40 D\touter/inner\n" &&
+               printf ":100644 000000 $blob_two $_z40 D\touter/inner\n" &&
+               printf ":100644 000000 $blob_two $_z40 D\touter/inner\n"
+       } >expect &&
+       git diff-tree -r --no-abbrev one two >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'diff-tree with renames' '
+       # same expectation as above, since we disable rename detection
+       git diff-tree -M -r --no-abbrev one two >actual &&
+       test_cmp expect actual
+'
+
+test_done
index 70b3a06e1dc7a92ac5a0806854e100af02c2346b..4acb3f336ed3fac10c7ddf68868c3ff56db94978 100755 (executable)
@@ -3,17 +3,10 @@
 test_description='apply to deeper directory without getting fooled with symlink'
 . ./test-lib.sh
 
-lecho () {
-       for l_
-       do
-               echo "$l_"
-       done
-}
-
 test_expect_success setup '
 
        mkdir -p arch/i386/boot arch/x86_64 &&
-       lecho 1 2 3 4 5 >arch/i386/boot/Makefile &&
+       test_write_lines 1 2 3 4 5 >arch/i386/boot/Makefile &&
        test_ln_s_add ../i386/boot arch/x86_64/boot &&
        git add . &&
        test_tick &&
@@ -22,7 +15,7 @@ test_expect_success setup '
 
        rm arch/x86_64/boot &&
        mkdir arch/x86_64/boot &&
-       lecho 2 3 4 5 6 >arch/x86_64/boot/Makefile &&
+       test_write_lines 2 3 4 5 6 >arch/x86_64/boot/Makefile &&
        git add . &&
        test_tick &&
        git commit -a -m second &&
@@ -52,4 +45,110 @@ test_expect_success 'check result' '
 
 '
 
+test_expect_success SYMLINKS 'do not read from beyond symbolic link' '
+       git reset --hard &&
+       mkdir -p arch/x86_64/dir &&
+       >arch/x86_64/dir/file &&
+       git add arch/x86_64/dir/file &&
+       echo line >arch/x86_64/dir/file &&
+       git diff >patch &&
+       git reset --hard &&
+
+       mkdir arch/i386/dir &&
+       >arch/i386/dir/file &&
+       ln -s ../i386/dir arch/x86_64/dir &&
+
+       test_must_fail git apply patch &&
+       test_must_fail git apply --cached patch &&
+       test_must_fail git apply --index patch
+
+'
+
+test_expect_success SYMLINKS 'do not follow symbolic link (setup)' '
+
+       rm -rf arch/i386/dir arch/x86_64/dir &&
+       git reset --hard &&
+       ln -s ../i386/dir arch/x86_64/dir &&
+       git add arch/x86_64/dir &&
+       git diff HEAD >add_symlink.patch &&
+       git reset --hard &&
+
+       mkdir arch/x86_64/dir &&
+       >arch/x86_64/dir/file &&
+       git add arch/x86_64/dir/file &&
+       git diff HEAD >add_file.patch &&
+       git diff -R HEAD >del_file.patch &&
+       git reset --hard &&
+       rm -fr arch/x86_64/dir &&
+
+       cat add_symlink.patch add_file.patch >patch &&
+       cat add_symlink.patch del_file.patch >tricky_del &&
+
+       mkdir arch/i386/dir
+'
+
+test_expect_success SYMLINKS 'do not follow symbolic link (same input)' '
+
+       # same input creates a confusing symbolic link
+       test_must_fail git apply patch 2>error-wt &&
+       test_i18ngrep "beyond a symbolic link" error-wt &&
+       test_path_is_missing arch/x86_64/dir &&
+       test_path_is_missing arch/i386/dir/file &&
+
+       test_must_fail git apply --index patch 2>error-ix &&
+       test_i18ngrep "beyond a symbolic link" error-ix &&
+       test_path_is_missing arch/x86_64/dir &&
+       test_path_is_missing arch/i386/dir/file &&
+       test_must_fail git ls-files --error-unmatch arch/x86_64/dir &&
+       test_must_fail git ls-files --error-unmatch arch/i386/dir &&
+
+       test_must_fail git apply --cached patch 2>error-ct &&
+       test_i18ngrep "beyond a symbolic link" error-ct &&
+       test_must_fail git ls-files --error-unmatch arch/x86_64/dir &&
+       test_must_fail git ls-files --error-unmatch arch/i386/dir &&
+
+       >arch/i386/dir/file &&
+       git add arch/i386/dir/file &&
+
+       test_must_fail git apply tricky_del &&
+       test_path_is_file arch/i386/dir/file &&
+
+       test_must_fail git apply --index tricky_del &&
+       test_path_is_file arch/i386/dir/file &&
+       test_must_fail git ls-files --error-unmatch arch/x86_64/dir &&
+       git ls-files --error-unmatch arch/i386/dir &&
+
+       test_must_fail git apply --cached tricky_del &&
+       test_must_fail git ls-files --error-unmatch arch/x86_64/dir &&
+       git ls-files --error-unmatch arch/i386/dir
+'
+
+test_expect_success SYMLINKS 'do not follow symbolic link (existing)' '
+
+       # existing symbolic link
+       git reset --hard &&
+       ln -s ../i386/dir arch/x86_64/dir &&
+       git add arch/x86_64/dir &&
+
+       test_must_fail git apply add_file.patch 2>error-wt-add &&
+       test_i18ngrep "beyond a symbolic link" error-wt-add &&
+       test_path_is_missing arch/i386/dir/file &&
+
+       mkdir arch/i386/dir &&
+       >arch/i386/dir/file &&
+       test_must_fail git apply del_file.patch 2>error-wt-del &&
+       test_i18ngrep "beyond a symbolic link" error-wt-del &&
+       test_path_is_file arch/i386/dir/file &&
+       rm arch/i386/dir/file &&
+
+       test_must_fail git apply --index add_file.patch 2>error-ix-add &&
+       test_i18ngrep "beyond a symbolic link" error-ix-add &&
+       test_path_is_missing arch/i386/dir/file &&
+       test_must_fail git ls-files --error-unmatch arch/i386/dir &&
+
+       test_must_fail git apply --cached add_file.patch 2>error-ct-file &&
+       test_i18ngrep "beyond a symbolic link" error-ct-file &&
+       test_must_fail git ls-files --error-unmatch arch/i386/dir
+'
+
 test_done
diff --git a/t/t4138-apply-ws-expansion.sh b/t/t4138-apply-ws-expansion.sh
new file mode 100755 (executable)
index 0000000..0ffe33f
--- /dev/null
@@ -0,0 +1,121 @@
+#!/bin/sh
+#
+# Copyright (C) 2015 Kyle J. McKay
+#
+
+test_description='git apply test patches with whitespace expansion.'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+       #
+       ## create test-N, patchN.patch, expect-N files
+       #
+
+       # test 1
+       printf "\t%s\n" 1 2 3 4 5 6 >before &&
+       printf "\t%s\n" 1 2 3 >after &&
+       printf "%64s\n" a b c >>after &&
+       printf "\t%s\n" 4 5 6 >>after &&
+       git diff --no-index before after |
+               sed -e "s/before/test-1/" -e "s/after/test-1/" >patch1.patch &&
+       printf "%64s\n" 1 2 3 4 5 6 >test-1 &&
+       printf "%64s\n" 1 2 3 a b c 4 5 6 >expect-1 &&
+
+       # test 2
+       printf "\t%s\n" a b c d e f >before &&
+       printf "\t%s\n" a b c >after &&
+       n=10 &&
+       x=1 &&
+       while test $x -lt $n
+       do
+               printf "%63s%d\n" "" $x >>after
+               x=$(( $x + 1 ))
+       done &&
+       printf "\t%s\n" d e f >>after &&
+       git diff --no-index before after |
+               sed -e "s/before/test-2/" -e "s/after/test-2/" >patch2.patch &&
+       printf "%64s\n" a b c d e f >test-2 &&
+       printf "%64s\n" a b c >expect-2 &&
+       x=1 &&
+       while test $x -lt $n
+       do
+               printf "%63s%d\n" "" $x >>expect-2
+               x=$(( $x + 1 ))
+       done &&
+       printf "%64s\n" d e f >>expect-2 &&
+
+       # test 3
+       printf "\t%s\n" a b c d e f >before &&
+       printf "\t%s\n" a b c >after &&
+       n=100 &&
+       x=0 &&
+       while test $x -lt $n
+       do
+               printf "%63s%02d\n" "" $x >>after
+               x=$(( $x + 1 ))
+       done &&
+       printf "\t%s\n" d e f >>after &&
+       git diff --no-index before after |
+       sed -e "s/before/test-3/" -e "s/after/test-3/" >patch3.patch &&
+       printf "%64s\n" a b c d e f >test-3 &&
+       printf "%64s\n" a b c >expect-3 &&
+       x=0 &&
+       while test $x -lt $n
+       do
+               printf "%63s%02d\n" "" $x >>expect-3
+               x=$(( $x + 1 ))
+       done &&
+       printf "%64s\n" d e f >>expect-3 &&
+
+       # test 4
+       >before &&
+       x=0 &&
+       while test $x -lt 50
+       do
+               printf "\t%02d\n" $x >>before
+               x=$(( $x + 1 ))
+       done &&
+       cat before >after &&
+       printf "%64s\n" a b c >>after &&
+       while test $x -lt 100
+       do
+               printf "\t%02d\n" $x >>before
+               printf "\t%02d\n" $x >>after
+               x=$(( $x + 1 ))
+       done &&
+       git diff --no-index before after |
+       sed -e "s/before/test-4/" -e "s/after/test-4/" >patch4.patch &&
+       >test-4 &&
+       x=0 &&
+       while test $x -lt 50
+       do
+               printf "%63s%02d\n" "" $x >>test-4
+               x=$(( $x + 1 ))
+       done &&
+       cat test-4 >expect-4 &&
+       printf "%64s\n" a b c >>expect-4 &&
+       while test $x -lt 100
+       do
+               printf "%63s%02d\n" "" $x >>test-4
+               printf "%63s%02d\n" "" $x >>expect-4
+               x=$(( $x + 1 ))
+       done &&
+
+       git config core.whitespace tab-in-indent,tabwidth=63 &&
+       git config apply.whitespace fix
+
+'
+
+# Note that `patch` can successfully apply all patches when run
+# with the --ignore-whitespace option.
+
+for t in 1 2 3 4
+do
+       test_expect_success 'apply with ws expansion (t=$t)' '
+               git apply patch$t.patch &&
+               test_cmp test-$t expect-$t
+       '
+done
+
+test_done
diff --git a/t/t4139-apply-escape.sh b/t/t4139-apply-escape.sh
new file mode 100755 (executable)
index 0000000..45b5660
--- /dev/null
@@ -0,0 +1,141 @@
+#!/bin/sh
+
+test_description='paths written by git-apply cannot escape the working tree'
+. ./test-lib.sh
+
+# tests will try to write to ../foo, and we do not
+# want them to escape the trash directory when they
+# fail
+test_expect_success 'bump git repo one level down' '
+       mkdir inside &&
+       mv .git inside/ &&
+       cd inside
+'
+
+# $1 = name of file
+# $2 = current path to file (if different)
+mkpatch_add () {
+       rm -f "${2:-$1}" &&
+       cat <<-EOF
+       diff --git a/$1 b/$1
+       new file mode 100644
+       index 0000000..53c74cd
+       --- /dev/null
+       +++ b/$1
+       @@ -0,0 +1 @@
+       +evil
+       EOF
+}
+
+mkpatch_del () {
+       echo evil >"${2:-$1}" &&
+       cat <<-EOF
+       diff --git a/$1 b/$1
+       deleted file mode 100644
+       index 53c74cd..0000000
+       --- a/$1
+       +++ /dev/null
+       @@ -1 +0,0 @@
+       -evil
+       EOF
+}
+
+# $1 = name of file
+# $2 = content of symlink
+mkpatch_symlink () {
+       rm -f "$1" &&
+       cat <<-EOF
+       diff --git a/$1 b/$1
+       new file mode 120000
+       index 0000000..$(printf "%s" "$2" | git hash-object --stdin)
+       --- /dev/null
+       +++ b/$1
+       @@ -0,0 +1 @@
+       +$2
+       \ No newline at end of file
+       EOF
+}
+
+test_expect_success 'cannot create file containing ..' '
+       mkpatch_add ../foo >patch &&
+       test_must_fail git apply patch &&
+       test_path_is_missing ../foo
+'
+
+test_expect_success 'can create file containing .. with --unsafe-paths' '
+       mkpatch_add ../foo >patch &&
+       git apply --unsafe-paths patch &&
+       test_path_is_file ../foo
+'
+
+test_expect_success  'cannot create file containing .. (index)' '
+       mkpatch_add ../foo >patch &&
+       test_must_fail git apply --index patch &&
+       test_path_is_missing ../foo
+'
+
+test_expect_success  'cannot create file containing .. with --unsafe-paths (index)' '
+       mkpatch_add ../foo >patch &&
+       test_must_fail git apply --index --unsafe-paths patch &&
+       test_path_is_missing ../foo
+'
+
+test_expect_success 'cannot delete file containing ..' '
+       mkpatch_del ../foo >patch &&
+       test_must_fail git apply patch &&
+       test_path_is_file ../foo
+'
+
+test_expect_success 'can delete file containing .. with --unsafe-paths' '
+       mkpatch_del ../foo >patch &&
+       git apply --unsafe-paths patch &&
+       test_path_is_missing ../foo
+'
+
+test_expect_success 'cannot delete file containing .. (index)' '
+       mkpatch_del ../foo >patch &&
+       test_must_fail git apply --index patch &&
+       test_path_is_file ../foo
+'
+
+test_expect_success SYMLINKS 'symlink escape via ..' '
+       {
+               mkpatch_symlink tmp .. &&
+               mkpatch_add tmp/foo ../foo
+       } >patch &&
+       test_must_fail git apply patch &&
+       test_path_is_missing tmp &&
+       test_path_is_missing ../foo
+'
+
+test_expect_success SYMLINKS 'symlink escape via .. (index)' '
+       {
+               mkpatch_symlink tmp .. &&
+               mkpatch_add tmp/foo ../foo
+       } >patch &&
+       test_must_fail git apply --index patch &&
+       test_path_is_missing tmp &&
+       test_path_is_missing ../foo
+'
+
+test_expect_success SYMLINKS 'symlink escape via absolute path' '
+       {
+               mkpatch_symlink tmp "$(pwd)" &&
+               mkpatch_add tmp/foo ../foo
+       } >patch &&
+       test_must_fail git apply patch &&
+       test_path_is_missing tmp &&
+       test_path_is_missing ../foo
+'
+
+test_expect_success SYMLINKS 'symlink escape via absolute path (index)' '
+       {
+               mkpatch_symlink tmp "$(pwd)" &&
+               mkpatch_add tmp/foo ../foo
+       } >patch &&
+       test_must_fail git apply --index patch &&
+       test_path_is_missing tmp &&
+       test_path_is_missing ../foo
+'
+
+test_done
index 925f577a3c4652bed253787d5f540a415b16fccf..f8008b6a3d2a5fc200665998288d121d1c35dd25 100755 (executable)
@@ -44,15 +44,15 @@ test_expect_success setup '
 '
 
 cat >expected <<EOF
-${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_HEAD}HEAD${c_reset}${c_commit},\
- ${c_tag}tag: v1.0${c_reset}${c_commit},\
- ${c_tag}tag: B${c_reset}${c_commit},\
- ${c_branch}master${c_reset}${c_commit})${c_reset} B
-${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_tag}tag: A1${c_reset}${c_commit},\
- ${c_remoteBranch}other/master${c_reset}${c_commit})${c_reset} A1
-${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_stash}refs/stash${c_reset}${c_commit})${c_reset}\
+${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD${c_reset}${c_commit} ->\
+ ${c_reset}${c_branch}master${c_reset}${c_commit},\
+ ${c_reset}${c_tag}tag: v1.0${c_reset}${c_commit},\
+ ${c_reset}${c_tag}tag: B${c_reset}${c_commit})${c_reset} B
+${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: A1${c_reset}${c_commit},\
+ ${c_reset}${c_remoteBranch}other/master${c_reset}${c_commit})${c_reset} A1
+${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_stash}refs/stash${c_reset}${c_commit})${c_reset}\
  On master: Changes to A.t
-${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_tag}tag: A${c_reset}${c_commit})${c_reset} A
+${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: A${c_reset}${c_commit})${c_reset} A
 EOF
 
 # We want log to show all, but the second parent to refs/stash is irrelevant
index c929db563326614e01962b3e322f087640fa19d9..14744b2a4b1e646890176ec53970d36de6f8ec3b 100755 (executable)
@@ -33,6 +33,37 @@ check_zip() {
        test_expect_success UNZIP " validate file contents" "
                diff -r a ${dir_with_prefix}a
        "
+
+       dir=eol_$1
+       dir_with_prefix=$dir/$2
+       extracted=${dir_with_prefix}a
+       original=a
+
+       test_expect_success UNZIP " extract ZIP archive with EOL conversion" '
+               (mkdir $dir && cd $dir && "$GIT_UNZIP" -a ../$zipfile)
+       '
+
+       test_expect_success UNZIP " validate that text files are converted" "
+               test_cmp_bin $extracted/text.cr $extracted/text.crlf &&
+               test_cmp_bin $extracted/text.cr $extracted/text.lf
+       "
+
+       test_expect_success UNZIP " validate that binary files are unchanged" "
+               test_cmp_bin $original/binary.cr   $extracted/binary.cr &&
+               test_cmp_bin $original/binary.crlf $extracted/binary.crlf &&
+               test_cmp_bin $original/binary.lf   $extracted/binary.lf
+       "
+
+       test_expect_success UNZIP " validate that diff files are converted" "
+               test_cmp_bin $extracted/diff.cr $extracted/diff.crlf &&
+               test_cmp_bin $extracted/diff.cr $extracted/diff.lf
+       "
+
+       test_expect_success UNZIP " validate that -diff files are unchanged" "
+               test_cmp_bin $original/nodiff.cr   $extracted/nodiff.cr &&
+               test_cmp_bin $original/nodiff.crlf $extracted/nodiff.crlf &&
+               test_cmp_bin $original/nodiff.lf   $extracted/nodiff.lf
+       "
 }
 
 test_expect_success \
@@ -41,6 +72,18 @@ test_expect_success \
      echo simple textfile >a/a &&
      mkdir a/bin &&
      cp /bin/sh a/bin &&
+     printf "text\r"   >a/text.cr &&
+     printf "text\r\n" >a/text.crlf &&
+     printf "text\n"   >a/text.lf &&
+     printf "text\r"   >a/nodiff.cr &&
+     printf "text\r\n" >a/nodiff.crlf &&
+     printf "text\n"   >a/nodiff.lf &&
+     printf "\0\r"     >a/binary.cr &&
+     printf "\0\r\n"   >a/binary.crlf &&
+     printf "\0\n"     >a/binary.lf &&
+     printf "\0\r"     >a/diff.cr &&
+     printf "\0\r\n"   >a/diff.crlf &&
+     printf "\0\n"     >a/diff.lf &&
      printf "A\$Format:%s\$O" "$SUBSTFORMAT" >a/substfile1 &&
      printf "A not substituted O" >a/substfile2 &&
      (p=long_path_to_a_file && cd a &&
@@ -66,7 +109,9 @@ test_expect_success 'add files to repository' '
        GIT_COMMITTER_DATE="2005-05-27 22:00" git commit -m initial
 '
 
-test_expect_success 'setup export-subst' '
+test_expect_success 'setup export-subst and diff attributes' '
+       echo "a/nodiff.* -diff" >>.git/info/attributes &&
+       echo "a/diff.* diff" >>.git/info/attributes &&
        echo "substfile?" export-subst >>.git/info/attributes &&
        git log --max-count=1 "--pretty=format:A${SUBSTFORMAT}O" HEAD \
                >a/substfile1
index e32e46dee10e96a0b0e51df0eeefd343373f662e..0794d33dad6cddcb6be58663c16cbe67be600e47 100755 (executable)
@@ -253,4 +253,12 @@ test_expect_success 'prune .git/shallow' '
        test_path_is_missing .git/shallow
 '
 
+test_expect_success 'prune: handle alternate object database' '
+       test_create_repo A &&
+       git -C A commit --allow-empty -m "initial commit" &&
+       git clone --shared A B &&
+       git -C B commit --allow-empty -m "next commit" &&
+       git -C B prune
+'
+
 test_done
index 5b2b1c2c130387332778f6e49043b739dd2d7d21..bd37f040b6ce13406ef009944d46d2f1cc6c8d7b 100755 (executable)
@@ -541,13 +541,30 @@ check_prot_path () {
        test_cmp expected actual
 }
 
-check_prot_host_path () {
-       cat >expected <<-EOF &&
+check_prot_host_port_path () {
+       local diagport
+       case "$2" in
+               *ssh*)
+               pp=ssh
+               uah=userandhost
+               ehost=$(echo $3 | tr -d "[]")
+               diagport="Diag: port=$4"
+               ;;
+               *)
+               pp=$p
+               uah=hostandport
+               ehost=$(echo $3$4 | sed -e "s/22$/:22/" -e "s/NONE//")
+               diagport=""
+               ;;
+       esac
+       cat >exp <<-EOF &&
        Diag: url=$1
-       Diag: protocol=$2
-       Diag: hostandport=$3
-       Diag: path=$4
+       Diag: protocol=$pp
+       Diag: $uah=$ehost
+       $diagport
+       Diag: path=$5
        EOF
+       grep -v "^$" exp >expected
        git fetch-pack --diag-url "$1" >actual &&
        test_cmp expected actual
 }
@@ -557,22 +574,20 @@ do
        # git or ssh with scheme
        for p in "ssh+git" "git+ssh" git ssh
        do
-               for h in host host:12 [::1] [::1]:23
+               for h in host user@host user@[::1] user@::1
                do
-                       case "$p" in
-                       *ssh*)
-                               pp=ssh
-                               ;;
-                       *)
-                               pp=$p
-                       ;;
-                       esac
                        test_expect_success "fetch-pack --diag-url $p://$h/$r" '
-                               check_prot_host_path $p://$h/$r $pp "$h" "/$r"
+                               check_prot_host_port_path $p://$h/$r $p "$h" NONE "/$r"
                        '
                        # "/~" -> "~" conversion
                        test_expect_success "fetch-pack --diag-url $p://$h/~$r" '
-                               check_prot_host_path $p://$h/~$r $pp "$h" "~$r"
+                               check_prot_host_port_path $p://$h/~$r $p "$h" NONE "~$r"
+                       '
+               done
+               for h in host User@host User@[::1]
+               do
+                       test_expect_success "fetch-pack --diag-url $p://$h:22/$r" '
+                               check_prot_host_port_path $p://$h:22/$r $p "$h" 22 "/$r"
                        '
                done
        done
@@ -603,11 +618,11 @@ do
        for h in host [::1]
        do
                test_expect_success "fetch-pack --diag-url $h:$r" '
-                       check_prot_path $h:$r $p "$r"
+                       check_prot_host_port_path $h:$r $p "$h" NONE "$r"
                '
                # Do "/~" -> "~" conversion
                test_expect_success "fetch-pack --diag-url $h:/~$r" '
-                       check_prot_host_path $h:/~$r $p "$h" "~$r"
+                       check_prot_host_port_path $h:/~$r $p "$h" NONE "~$r"
                '
        done
 done
index e4436c170088a69b9efc5712a55bbe1d4bb8113f..630885d6df2fed0b8ba35005f150ccd3838dfcca 100755 (executable)
@@ -238,7 +238,7 @@ test_expect_success 'push with pushInsteadOf' '
 test_expect_success 'push with pushInsteadOf and explicit pushurl (pushInsteadOf should not rewrite)' '
        mk_empty testrepo &&
        test_config "url.trash2/.pushInsteadOf" testrepo/ &&
-       test_config "url.trash3/.pusnInsteadOf" trash/wrong &&
+       test_config "url.trash3/.pushInsteadOf" trash/wrong &&
        test_config remote.r.url trash/wrong &&
        test_config remote.r.pushurl "testrepo/" &&
        git push r refs/heads/master:refs/remotes/origin/master &&
index cc7451908baa815467606dae49a36d0df26492dc..73f4bb63465e50aa12de824859903e5293696a85 100755 (executable)
@@ -26,7 +26,7 @@ check_pushed_commit () {
 # $2 = expected target branch for the push
 # $3 = [optional] repo to check for actual output (repo1 by default)
 test_push_success () {
-       git ${1:+-c push.default="$1"} push &&
+       git ${1:+-c} ${1:+push.default="$1"} push &&
        check_pushed_commit HEAD "$2" "$3"
 }
 
@@ -34,7 +34,7 @@ test_push_success () {
 # check that push fails and does not modify any remote branch
 test_push_failure () {
        git --git-dir=repo1 log --no-walk --format='%h %s' --all >expect &&
-       test_must_fail git ${1:+-c push.default="$1"} push &&
+       test_must_fail git ${1:+-c} ${1:+push.default="$1"} push &&
        git --git-dir=repo1 log --no-walk --format='%h %s' --all >actual &&
        test_cmp expect actual
 }
index d2c681ebfde39fcccef190c3a242dfae9d8af2f2..1ecb5881acf720e7c0dc8b885750f6e641764591 100755 (executable)
@@ -324,12 +324,6 @@ 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 |
index ac71418a1b26bc17a1252d6831869b96a8d8c176..2731ad4cea951744ea82b94a038a71ef01a228a2 100755 (executable)
@@ -165,6 +165,24 @@ test_expect_success 'fetch notices corrupt idx' '
        )
 '
 
+test_expect_success 'fetch can handle previously-fetched .idx files' '
+       git checkout --orphan branch1 &&
+       echo base >file &&
+       git add file &&
+       git commit -m base &&
+       git --bare init "$HTTPD_DOCUMENT_ROOT_PATH"/repo_packed_branches.git &&
+       git push "$HTTPD_DOCUMENT_ROOT_PATH"/repo_packed_branches.git branch1 &&
+       git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH"/repo_packed_branches.git repack -d &&
+       git checkout -b branch2 branch1 &&
+       echo b2 >>file &&
+       git commit -a -m b2 &&
+       git push "$HTTPD_DOCUMENT_ROOT_PATH"/repo_packed_branches.git branch2 &&
+       git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH"/repo_packed_branches.git repack -d &&
+       git --bare init clone_packed_branches.git &&
+       git --git-dir=clone_packed_branches.git fetch "$HTTPD_URL"/dumb/repo_packed_branches.git branch1:branch1 &&
+       git --git-dir=clone_packed_branches.git fetch "$HTTPD_URL"/dumb/repo_packed_branches.git branch2:branch2
+'
+
 test_expect_success 'did not use upload-pack service' '
        grep '/git-upload-pack' <"$HTTPD_ROOT_PATH"/access.log >act
        : >exp
@@ -196,5 +214,47 @@ test_expect_success 'reencoding is robust to whitespace oddities' '
        grep "this is the error message" stderr
 '
 
+check_language () {
+       case "$2" in
+       '')
+               >expect
+               ;;
+       ?*)
+               echo "Accept-Language: $1" >expect
+               ;;
+       esac &&
+       GIT_CURL_VERBOSE=1 \
+       LANGUAGE=$2 \
+       git ls-remote "$HTTPD_URL/dumb/repo.git" >output 2>&1 &&
+       tr -d '\015' <output |
+       sort -u |
+       sed -ne '/^Accept-Language:/ p' >actual &&
+       test_cmp expect actual
+}
+
+test_expect_success 'git client sends Accept-Language based on LANGUAGE' '
+       check_language "ko-KR, *;q=0.9" ko_KR.UTF-8'
+
+test_expect_success 'git client sends Accept-Language correctly with unordinary LANGUAGE' '
+       check_language "ko-KR, *;q=0.9" "ko_KR:" &&
+       check_language "ko-KR, en-US;q=0.9, *;q=0.8" "ko_KR::en_US" &&
+       check_language "ko-KR, *;q=0.9" ":::ko_KR" &&
+       check_language "ko-KR, en-US;q=0.9, *;q=0.8" "ko_KR!!:en_US" &&
+       check_language "ko-KR, ja-JP;q=0.9, *;q=0.8" "ko_KR en_US:ja_JP"'
+
+test_expect_success 'git client sends Accept-Language with many preferred languages' '
+       check_language "ko-KR, en-US;q=0.9, fr-CA;q=0.8, de;q=0.7, sr;q=0.6, \
+ja;q=0.5, zh;q=0.4, sv;q=0.3, pt;q=0.2, *;q=0.1" \
+               ko_KR.EUC-KR:en_US.UTF-8:fr_CA:de.UTF-8@euro:sr@latin:ja:zh:sv:pt &&
+       check_language "ko-KR, en-US;q=0.99, fr-CA;q=0.98, de;q=0.97, sr;q=0.96, \
+ja;q=0.95, zh;q=0.94, sv;q=0.93, pt;q=0.92, nb;q=0.91, *;q=0.90" \
+               ko_KR.EUC-KR:en_US.UTF-8:fr_CA:de.UTF-8@euro:sr@latin:ja:zh:sv:pt:nb
+'
+
+test_expect_success 'git client does not send an empty Accept-Language' '
+       GIT_CURL_VERBOSE=1 LANGUAGE= git ls-remote "$HTTPD_URL/dumb/repo.git" 2>stderr &&
+       ! grep "^Accept-Language:" stderr
+'
+
 stop_httpd
 test_done
index 6cbc12d9a7ad059f77967c0bdb702d8a5ec75bb9..df47851752f6b9b085d0feab8d6ba24ef2d0da29 100755 (executable)
@@ -213,10 +213,21 @@ test_expect_success 'cookies stored in http.cookiefile when http.savecookies set
        test_cmp expect_cookies.txt cookies_tail.txt
 '
 
-test_expect_success EXPENSIVE 'create 50,000 tags in the repo' '
+test_expect_success 'transfer.hiderefs works over smart-http' '
+       test_commit hidden &&
+       test_commit visible &&
+       git push public HEAD^:refs/heads/a HEAD:refs/heads/b &&
+       git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \
+               config transfer.hiderefs refs/heads/a &&
+       git clone --bare "$HTTPD_URL/smart/repo.git" hidden.git &&
+       test_must_fail git -C hidden.git rev-parse --verify a &&
+       git -C hidden.git rev-parse --verify b
+'
+
+test_expect_success 'create 2,000 tags in the repo' '
        (
        cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
-       for i in `test_seq 50000`
+       for i in $(test_seq 2000)
        do
                echo "commit refs/heads/too-many-refs"
                echo "mark :$i"
@@ -237,13 +248,22 @@ test_expect_success EXPENSIVE 'create 50,000 tags in the repo' '
        )
 '
 
-test_expect_success EXPENSIVE 'clone the 50,000 tag repo to check OS command line overflow' '
-       git clone $HTTPD_URL/smart/repo.git too-many-refs &&
+test_expect_success CMDLINE_LIMIT \
+       'clone the 2,000 tag repo to check OS command line overflow' '
+       run_with_limited_cmdline git clone $HTTPD_URL/smart/repo.git too-many-refs &&
        (
                cd too-many-refs &&
-               test $(git for-each-ref refs/tags | wc -l) = 50000
+               git for-each-ref refs/tags >actual &&
+               test_line_count = 2000 actual
        )
 '
 
+test_expect_success 'large fetch-pack requests can be split across POSTs' '
+       GIT_CURL_VERBOSE=1 git -c http.postbuffer=65536 \
+               clone --bare "$HTTPD_URL/smart/repo.git" split.git 2>err &&
+       grep "^> POST" err >posts &&
+       test_line_count = 2 posts
+'
+
 stop_httpd
 test_done
index 6b163799510fa608fc6effa146accf295d0068f5..b7e283252d7d73e937ef87096801f2d252e95961 100755 (executable)
@@ -141,5 +141,32 @@ test_expect_success 'push disabled'      "test_remote_error    'service not enab
 test_expect_success 'read access denied' "test_remote_error -x 'no such repository'      fetch repo.git       "
 test_expect_success 'not exported'       "test_remote_error -n 'repository not exported' fetch repo.git       "
 
+stop_git_daemon
+start_git_daemon --interpolated-path="$GIT_DAEMON_DOCUMENT_ROOT_PATH/%H%D"
+
+test_expect_success 'access repo via interpolated hostname' '
+       repo="$GIT_DAEMON_DOCUMENT_ROOT_PATH/localhost/interp.git" &&
+       git init --bare "$repo" &&
+       git push "$repo" HEAD &&
+       >"$repo"/git-daemon-export-ok &&
+       rm -rf tmp.git &&
+       GIT_OVERRIDE_VIRTUAL_HOST=localhost \
+               git clone --bare "$GIT_DAEMON_URL/interp.git" tmp.git &&
+       rm -rf tmp.git &&
+       GIT_OVERRIDE_VIRTUAL_HOST=LOCALHOST \
+               git clone --bare "$GIT_DAEMON_URL/interp.git" tmp.git
+'
+
+test_expect_success 'hostname cannot break out of directory' '
+       rm -rf tmp.git &&
+       repo="$GIT_DAEMON_DOCUMENT_ROOT_PATH/../escape.git" &&
+       git init --bare "$repo" &&
+       git push "$repo" HEAD &&
+       >"$repo"/git-daemon-export-ok &&
+       test_must_fail \
+               env GIT_OVERRIDE_VIRTUAL_HOST=.. \
+               git clone --bare "$GIT_DAEMON_URL/escape.git" tmp.git
+'
+
 stop_git_daemon
 test_done
index e4f10c0f68b94bfa719c3d208f622541506c86b3..02b40b117faa1c6de816001018d1c7deda15ad7d 100755 (executable)
@@ -301,11 +301,17 @@ expect_ssh () {
                (cd "$TRASH_DIRECTORY" && rm -f ssh-expect && >ssh-output)
        ' &&
        {
-               case "$1" in
-               none)
+               case "$#" in
+               1)
                        ;;
-               *)
+               2)
                        echo "ssh: $1 git-upload-pack '$2'"
+                       ;;
+               3)
+                       echo "ssh: $1 $2 git-upload-pack '$3'"
+                       ;;
+               *)
+                       echo "ssh: $1 $2 git-upload-pack '$3' $4"
                esac
        } >"$TRASH_DIRECTORY/ssh-expect" &&
        (cd "$TRASH_DIRECTORY" && test_cmp ssh-expect ssh-output)
@@ -326,7 +332,7 @@ test_expect_success !MINGW,!CYGWIN 'clone local path foo:bar' '
 
 test_expect_success 'bracketed hostnames are still ssh' '
        git clone "[myhost:123]:src" ssh-bracket-clone &&
-       expect_ssh myhost:123 src
+       expect_ssh myhost '-p 123' src
 '
 
 counter=0
@@ -336,7 +342,8 @@ counter=0
 test_clone_url () {
        counter=$(($counter + 1))
        test_might_fail git clone "$1" tmp$counter &&
-       expect_ssh "$2" "$3"
+       shift &&
+       expect_ssh "$@"
 }
 
 test_expect_success !MINGW 'clone c:temp is ssl' '
@@ -359,7 +366,7 @@ done
 for repo in rep rep/home/project 123
 do
        test_expect_success "clone [::1]:$repo" '
-               test_clone_url [::1]:$repo ::1 $repo
+               test_clone_url [::1]:$repo ::1 "$repo"
        '
 done
 #home directory
@@ -400,24 +407,40 @@ test_expect_success 'clone ssh://host.xz:22/~repo' '
 '
 
 #IPv6
-test_expect_success 'clone ssh://[::1]/home/user/repo' '
-       test_clone_url "ssh://[::1]/home/user/repo" "::1" "/home/user/repo"
-'
+for tuah in ::1 [::1] user@::1 user@[::1] [user@::1]
+do
+       ehost=$(echo $tuah | tr -d "[]")
+       test_expect_success "clone ssh://$tuah/home/user/repo" "
+         test_clone_url ssh://$tuah/home/user/repo $ehost /home/user/repo
+       "
+done
 
 #IPv6 from home directory
-test_expect_success 'clone ssh://[::1]/~repo' '
-       test_clone_url "ssh://[::1]/~repo" "::1" "~repo"
-'
+for tuah in ::1 [::1] user@::1 user@[::1] [user@::1]
+do
+       euah=$(echo $tuah | tr -d "[]")
+       test_expect_success "clone ssh://$tuah/~repo" "
+         test_clone_url ssh://$tuah/~repo $euah '~repo'
+       "
+done
 
 #IPv6 with port number
-test_expect_success 'clone ssh://[::1]:22/home/user/repo' '
-       test_clone_url "ssh://[::1]:22/home/user/repo" "-p 22 ::1" "/home/user/repo"
-'
+for tuah in [::1] user@[::1] [user@::1]
+do
+       euah=$(echo $tuah | tr -d "[]")
+       test_expect_success "clone ssh://$tuah:22/home/user/repo" "
+         test_clone_url ssh://$tuah:22/home/user/repo '-p 22' $euah /home/user/repo
+       "
+done
 
 #IPv6 from home directory with port number
-test_expect_success 'clone ssh://[::1]:22/~repo' '
-       test_clone_url "ssh://[::1]:22/~repo" "-p 22 ::1" "~repo"
-'
+for tuah in [::1] user@[::1] [user@::1]
+do
+       euah=$(echo $tuah | tr -d "[]")
+       test_expect_success "clone ssh://$tuah:22/~repo" "
+         test_clone_url ssh://$tuah:22/~repo '-p 22' $euah '~repo'
+       "
+done
 
 test_expect_success 'clone from a repository with two identical branches' '
 
index 24194075468819881826c24c08b1aa97bacb9897..c9d3ed14c3a3238208b44ce815e37123298dea77 100755 (executable)
@@ -281,4 +281,28 @@ test_expect_success 'push messages' '
        )
 '
 
+test_expect_success 'fetch HEAD' '
+       (cd server &&
+       git checkout master &&
+       echo more >>file &&
+       git commit -a -m more
+       ) &&
+       (cd local &&
+       git fetch origin HEAD
+       ) &&
+       compare_refs server HEAD local FETCH_HEAD
+'
+
+test_expect_success 'fetch url' '
+       (cd server &&
+       git checkout master &&
+       echo more >>file &&
+       git commit -a -m more
+       ) &&
+       (cd local &&
+       git fetch "testgit::${PWD}/../server"
+       ) &&
+       compare_refs server HEAD local FETCH_HEAD
+'
+
 test_done
index 3758961765635c4ce504eec1540605f65efd386a..190ee903cf6269071809e82d61d6065f1de679c6 100755 (executable)
@@ -69,7 +69,8 @@ test_expect_success 'works in subdirectory' '
        cp new1.txt dir/a.txt &&
        cp orig.txt dir/o.txt &&
        cp new2.txt dir/b.txt &&
-       ( cd dir && git merge-file a.txt o.txt b.txt )
+       ( cd dir && git merge-file a.txt o.txt b.txt ) &&
+       test_path_is_missing a.txt
 '
 
 cp new1.txt test.txt
index 35c805a44e817c637c667b1d1d14d97b4ee46803..8bfeef9b0bf6eedcd1f0b31a141efc87a37041f8 100755 (executable)
@@ -1459,6 +1459,34 @@ test_expect_success 'invalid sort parameter in configuratoin' '
        test_cmp expect actual
 '
 
+test_expect_success 'version sort with prerelease reordering' '
+       git config --unset tag.sort &&
+       git config versionsort.prereleaseSuffix -rc &&
+       git tag foo1.6-rc1 &&
+       git tag foo1.6-rc2 &&
+       git tag -l --sort=version:refname "foo*" >actual &&
+       cat >expect <<-\EOF &&
+       foo1.3
+       foo1.6-rc1
+       foo1.6-rc2
+       foo1.6
+       foo1.10
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success 'reverse version sort with prerelease reordering' '
+       git tag -l --sort=-version:refname "foo*" >actual &&
+       cat >expect <<-\EOF &&
+       foo1.10
+       foo1.6
+       foo1.6-rc2
+       foo1.6-rc1
+       foo1.3
+       EOF
+       test_cmp expect actual
+'
+
 run_with_limited_stack () {
        (ulimit -s 128 && "$@")
 }
index 7c882450317b85ffdeabc105ee62a18ce3b04ca9..5811a982f472e3b79f31cc50dcdef92dcdb4a58c 100755 (executable)
@@ -171,6 +171,23 @@ test_expect_success 'submodule add with ./ in path' '
        test_cmp empty untracked
 '
 
+test_expect_success 'submodule add with /././ in path' '
+       echo "refs/heads/master" >expect &&
+       >empty &&
+
+       (
+               cd addtest &&
+               git submodule add "$submodurl" dotslashdotsubmod/././frotz/./ &&
+               git submodule init
+       ) &&
+
+       rm -f heads head untracked &&
+       inspect addtest/dotslashdotsubmod/frotz ../../.. &&
+       test_cmp expect heads &&
+       test_cmp expect head &&
+       test_cmp empty untracked
+'
+
 test_expect_success 'submodule add with // in path' '
        echo "refs/heads/master" >expect &&
        >empty &&
index 8ed5788808055889208ac9451054f098538a6878..6b16bcb64031e32c7200deac8ceb46711a8e7bed 100755 (executable)
@@ -66,6 +66,12 @@ strip_comments () {
        rm "$1" && mv "$1".tmp "$1"
 }
 
+cat >.gitignore <<\EOF
+.gitignore
+expect*
+output*
+EOF
+
 test_expect_success 'status --column' '
        cat >expect <<\EOF &&
 # On branch master
@@ -83,8 +89,8 @@ test_expect_success 'status --column' '
 # Untracked files:
 #   (use "git add <file>..." to include in what will be committed)
 #
-#      dir1/untracked dir2/untracked output
-#      dir2/modified  expect         untracked
+#      dir1/untracked dir2/untracked
+#      dir2/modified  untracked
 #
 EOF
        COLUMNS=50 git -c status.displayCommentPrefix=true status --column="column dense" >output &&
@@ -116,8 +122,6 @@ cat >expect <<\EOF
 #      dir1/untracked
 #      dir2/modified
 #      dir2/untracked
-#      expect
-#      output
 #      untracked
 #
 EOF
@@ -133,6 +137,23 @@ test_expect_success 'status with status.displayCommentPrefix=false' '
        test_i18ncmp expect output
 '
 
+test_expect_success 'status -v' '
+       (cat expect && git diff --cached) >expect-with-v &&
+       git status -v >output &&
+       test_i18ncmp expect-with-v output
+'
+
+test_expect_success 'status -v -v' '
+       (cat expect &&
+        echo "Changes to be committed:" &&
+        git -c diff.mnemonicprefix=true diff --cached &&
+        echo "--------------------------------------------------" &&
+        echo "Changes not staged for commit:" &&
+        git -c diff.mnemonicprefix=true diff) >expect-with-v &&
+       git status -v -v >output &&
+       test_i18ncmp expect-with-v output
+'
+
 test_expect_success 'setup fake editor' '
        cat >.git/editor <<-\EOF &&
        #! /bin/sh
@@ -167,8 +188,6 @@ Untracked files:
        dir1/untracked
        dir2/modified
        dir2/untracked
-       expect
-       output
        untracked
 
 EOF
@@ -186,8 +205,6 @@ A  dir2/added
 ?? dir1/untracked
 ?? dir2/modified
 ?? dir2/untracked
-?? expect
-?? output
 ?? untracked
 EOF
 
@@ -201,7 +218,7 @@ test_expect_success 'status -s' '
 test_expect_success 'status with gitignore' '
        {
                echo ".gitignore" &&
-               echo "expect" &&
+               echo "expect*" &&
                echo "output" &&
                echo "untracked"
        } >.gitignore &&
@@ -222,6 +239,7 @@ test_expect_success 'status with gitignore' '
        !! dir1/untracked
        !! dir2/untracked
        !! expect
+       !! expect-with-v
        !! output
        !! untracked
        EOF
@@ -253,6 +271,7 @@ Ignored files:
        dir1/untracked
        dir2/untracked
        expect
+       expect-with-v
        output
        untracked
 
@@ -264,7 +283,7 @@ EOF
 test_expect_success 'status with gitignore (nothing untracked)' '
        {
                echo ".gitignore" &&
-               echo "expect" &&
+               echo "expect*" &&
                echo "dir2/modified" &&
                echo "output" &&
                echo "untracked"
@@ -285,6 +304,7 @@ test_expect_success 'status with gitignore (nothing untracked)' '
        !! dir2/modified
        !! dir2/untracked
        !! expect
+       !! expect-with-v
        !! output
        !! untracked
        EOF
@@ -312,6 +332,7 @@ Ignored files:
        dir2/modified
        dir2/untracked
        expect
+       expect-with-v
        output
        untracked
 
@@ -320,7 +341,11 @@ EOF
        test_i18ncmp expect output
 '
 
-rm -f .gitignore
+cat >.gitignore <<\EOF
+.gitignore
+expect*
+output*
+EOF
 
 cat >expect <<\EOF
 ## master
@@ -329,8 +354,6 @@ A  dir2/added
 ?? dir1/untracked
 ?? dir2/modified
 ?? dir2/untracked
-?? expect
-?? output
 ?? untracked
 EOF
 
@@ -434,8 +457,6 @@ Untracked files:
        dir2/modified
        dir2/untracked
        dir3/
-       expect
-       output
        untracked
 
 EOF
@@ -456,8 +477,6 @@ A  dir2/added
 ?? dir2/modified
 ?? dir2/untracked
 ?? dir3/
-?? expect
-?? output
 ?? untracked
 EOF
 test_expect_success 'status -s -unormal' '
@@ -493,8 +512,6 @@ Untracked files:
        dir2/untracked
        dir3/untracked1
        dir3/untracked2
-       expect
-       output
        untracked
 
 EOF
@@ -518,8 +535,6 @@ A  dir2/added
 ?? dir1/untracked
 ?? dir2/modified
 ?? dir2/untracked
-?? expect
-?? output
 ?? untracked
 EOF
 test_expect_success 'status -s -uall' '
@@ -554,8 +569,6 @@ Untracked files:
        untracked
        ../dir2/modified
        ../dir2/untracked
-       ../expect
-       ../output
        ../untracked
 
 EOF
@@ -569,8 +582,6 @@ A  ../dir2/added
 ?? untracked
 ?? ../dir2/modified
 ?? ../dir2/untracked
-?? ../expect
-?? ../output
 ?? ../untracked
 EOF
 test_expect_success 'status -s with relative paths' '
@@ -586,8 +597,6 @@ A  dir2/added
 ?? dir1/untracked
 ?? dir2/modified
 ?? dir2/untracked
-?? expect
-?? output
 ?? untracked
 EOF
 
@@ -625,8 +634,6 @@ Untracked files:
        <BLUE>dir1/untracked<RESET>
        <BLUE>dir2/modified<RESET>
        <BLUE>dir2/untracked<RESET>
-       <BLUE>expect<RESET>
-       <BLUE>output<RESET>
        <BLUE>untracked<RESET>
 
 EOF
@@ -647,8 +654,6 @@ cat >expect <<\EOF
 <BLUE>??<RESET> dir1/untracked
 <BLUE>??<RESET> dir2/modified
 <BLUE>??<RESET> dir2/untracked
-<BLUE>??<RESET> expect
-<BLUE>??<RESET> output
 <BLUE>??<RESET> untracked
 EOF
 
@@ -676,8 +681,6 @@ cat >expect <<\EOF
 <BLUE>??<RESET> dir1/untracked
 <BLUE>??<RESET> dir2/modified
 <BLUE>??<RESET> dir2/untracked
-<BLUE>??<RESET> expect
-<BLUE>??<RESET> output
 <BLUE>??<RESET> untracked
 EOF
 
@@ -694,8 +697,6 @@ A  dir2/added
 ?? dir1/untracked
 ?? dir2/modified
 ?? dir2/untracked
-?? expect
-?? output
 ?? untracked
 EOF
 
@@ -755,8 +756,6 @@ Untracked files:
        dir1/untracked
        dir2/modified
        dir2/untracked
-       expect
-       output
        untracked
 
 EOF
@@ -772,8 +771,6 @@ A  dir2/added
 ?? dir1/untracked
 ?? dir2/modified
 ?? dir2/untracked
-?? expect
-?? output
 ?? untracked
 EOF
 
@@ -798,8 +795,6 @@ Untracked files:
 
        dir1/untracked
        dir2/
-       expect
-       output
        untracked
 
 EOF
@@ -848,8 +843,6 @@ Untracked files:
        dir1/untracked
        dir2/modified
        dir2/untracked
-       expect
-       output
        untracked
 
 EOF
@@ -870,8 +863,6 @@ A  sm
 ?? dir1/untracked
 ?? dir2/modified
 ?? dir2/untracked
-?? expect
-?? output
 ?? untracked
 EOF
 test_expect_success 'status -s submodule summary is disabled by default' '
@@ -913,8 +904,6 @@ Untracked files:
        dir1/untracked
        dir2/modified
        dir2/untracked
-       expect
-       output
        untracked
 
 EOF
@@ -940,8 +929,6 @@ A  sm
 ?? dir1/untracked
 ?? dir2/modified
 ?? dir2/untracked
-?? expect
-?? output
 ?? untracked
 EOF
 test_expect_success 'status -s submodule summary' '
@@ -964,8 +951,6 @@ Untracked files:
        dir1/untracked
        dir2/modified
        dir2/untracked
-       expect
-       output
        untracked
 
 no changes added to commit (use "git add" and/or "git commit -a")
@@ -983,8 +968,6 @@ cat >expect <<EOF
 ?? dir1/untracked
 ?? dir2/modified
 ?? dir2/untracked
-?? expect
-?? output
 ?? untracked
 EOF
 test_expect_success 'status -s submodule summary (clean submodule)' '
@@ -1025,8 +1008,6 @@ Untracked files:
        dir1/untracked
        dir2/modified
        dir2/untracked
-       expect
-       output
        untracked
 
 EOF
@@ -1080,8 +1061,6 @@ Untracked files:
        dir1/untracked
        dir2/modified
        dir2/untracked
-       expect
-       output
        untracked
 
 EOF
@@ -1192,8 +1171,6 @@ Untracked files:
        dir1/untracked
        dir2/modified
        dir2/untracked
-       expect
-       output
        untracked
 
 EOF
@@ -1254,8 +1231,6 @@ Untracked files:
        dir1/untracked
        dir2/modified
        dir2/untracked
-       expect
-       output
        untracked
 
 EOF
@@ -1336,8 +1311,6 @@ cat > expect << EOF
 ;      dir1/untracked
 ;      dir2/modified
 ;      dir2/untracked
-;      expect
-;      output
 ;      untracked
 ;
 EOF
@@ -1369,8 +1342,6 @@ Untracked files:
        dir1/untracked
        dir2/modified
        dir2/untracked
-       expect
-       output
        untracked
 
 no changes added to commit (use "git add" and/or "git commit -a")
@@ -1400,8 +1371,6 @@ Untracked files:
        dir1/untracked
        dir2/modified
        dir2/untracked
-       expect
-       output
        untracked
 
 EOF
index 474dab381aef027207026cb938df7a09cc7a9056..3cef18cfdaa587d12aafec5fe32742f0356fc501 100755 (executable)
@@ -86,8 +86,8 @@ test_expect_success GPG 'show signed commit with signature' '
        git show -s --show-signature initial >show &&
        git verify-commit -v initial >verify.1 2>verify.2 &&
        git cat-file commit initial >cat &&
-       grep -v "gpg: " show >show.commit &&
-       grep "gpg: " show >show.gpg &&
+       grep -v -e "gpg: " -e "Warning: " show >show.commit &&
+       grep -e "gpg: " -e "Warning: " show >show.gpg &&
        grep -v "^ " cat | grep -v "^gpgsig " >cat.commit &&
        test_cmp show.commit commit &&
        test_cmp show.gpg verify.2 &&
diff --git a/t/t7516-commit-races.sh b/t/t7516-commit-races.sh
new file mode 100755 (executable)
index 0000000..f2ce14e
--- /dev/null
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+test_description='git commit races'
+. ./test-lib.sh
+
+test_expect_success 'race to create orphan commit' '
+       write_script hare-editor <<-\EOF &&
+       git commit --allow-empty -m hare
+       EOF
+       test_must_fail env EDITOR=./hare-editor git commit --allow-empty -m tortoise -e &&
+       git show -s --pretty=format:%s >subject &&
+       grep hare subject &&
+       test -z "$(git show -s --pretty=format:%P)"
+'
+
+test_expect_success 'race to create non-orphan commit' '
+       write_script airplane-editor <<-\EOF &&
+       git commit --allow-empty -m airplane
+       EOF
+       git checkout --orphan branch &&
+       git commit --allow-empty -m base &&
+       git rev-parse HEAD >base &&
+       test_must_fail env EDITOR=./airplane-editor git commit --allow-empty -m ship -e &&
+       git show -s --pretty=format:%s >subject &&
+       grep airplane subject &&
+       git rev-parse HEAD^ >parent &&
+       test_cmp base parent
+'
+
+test_done
index af6a3e8904ab1d953b359707de1e0c9a09b3ce1f..051305545c414481b6883fa619ffb39134187de0 100755 (executable)
@@ -392,7 +392,7 @@ test_expect_success $PREREQ 'allow long lines with --no-validate' '
                --from="Example <nobody@example.com>" \
                --to=nobody@example.com \
                --smtp-server="$(pwd)/fake.sendmail" \
-               --novalidate \
+               --no-validate \
                $patches longline.patch \
                2>errors
 '
@@ -426,7 +426,7 @@ test_expect_success $PREREQ 'In-Reply-To without --chain-reply-to' '
        git send-email \
                --from="Example <nobody@example.com>" \
                --to=nobody@example.com \
-               --nochain-reply-to \
+               --no-chain-reply-to \
                --in-reply-to="$(cat expect)" \
                --smtp-server="$(pwd)/fake.sendmail" \
                $patches $patches $patches \
@@ -1067,7 +1067,7 @@ test_expect_success $PREREQ 'in-reply-to but no threading' '
                --from="Example <nobody@example.com>" \
                --to=nobody@example.com \
                --in-reply-to="<in-reply-id@example.com>" \
-               --nothread \
+               --no-thread \
                $patches |
        grep "In-Reply-To: <in-reply-id@example.com>"
 '
@@ -1077,7 +1077,7 @@ test_expect_success $PREREQ 'no in-reply-to and no threading' '
                --dry-run \
                --from="Example <nobody@example.com>" \
                --to=nobody@example.com \
-               --nothread \
+               --no-thread \
                $patches $patches >stdout &&
        ! grep "In-Reply-To: " stdout
 '
@@ -1088,7 +1088,7 @@ test_expect_success $PREREQ 'threading but no chain-reply-to' '
                --from="Example <nobody@example.com>" \
                --to=nobody@example.com \
                --thread \
-               --nochain-reply-to \
+               --no-chain-reply-to \
                $patches $patches >stdout &&
        grep "In-Reply-To: " stdout
 '
index 37c2d633f0d2fefdb530266b8b250ef59e8704d3..c538e0a4e97c942dcb64b3e5bdd9afa10591f33e 100755 (executable)
@@ -552,8 +552,8 @@ test_expect_success 'D: verify pack' '
 '
 
 cat >expect <<EOF
-:000000 100755 0000000000000000000000000000000000000000 35a59026a33beac1569b1c7f66f3090ce9c09afc A     newdir/exec.sh
-:000000 100644 0000000000000000000000000000000000000000 046d0371e9220107917db0d0e030628de8a1de9b A     newdir/interesting
+:000000 100755 0000000000000000000000000000000000000000 e74b7d465e52746be2b4bae983670711e6e66657 A     newdir/exec.sh
+:000000 100644 0000000000000000000000000000000000000000 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 A     newdir/interesting
 EOF
 git diff-tree -M -r branch^ branch >actual
 test_expect_success \
index f10a75290e6e854763d10fa571b8c50901dce981..7a883d1a674dbed174611470c93ffe32f4f8a4bc 100755 (executable)
@@ -351,6 +351,25 @@ test_expect_success '__gitcomp_nl - doesnt fail because of invalid variable name
        __gitcomp_nl "$invalid_variable_name"
 '
 
+test_expect_success '__git_remotes - list remotes from $GIT_DIR/remotes and from config file' '
+       cat >expect <<-EOF &&
+       remote_from_file_1
+       remote_from_file_2
+       remote_in_config_1
+       remote_in_config_2
+       EOF
+       test_when_finished "rm -rf .git/remotes" &&
+       mkdir -p .git/remotes &&
+       >.git/remotes/remote_from_file_1 &&
+       >.git/remotes/remote_from_file_2 &&
+       test_when_finished "git remote remove remote_in_config_1" &&
+       git remote add remote_in_config_1 git://remote_1 &&
+       test_when_finished "git remote remove remote_in_config_2" &&
+       git remote add remote_in_config_2 git://remote_2 &&
+       __git_remotes >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'basic' '
        run_completion "git " &&
        # built-in
index 0d93e33de4759bff71739c19be803cac981f0770..0698ce7908cb958c6e94a8cfa11c1019de692710 100644 (file)
@@ -745,7 +745,9 @@ test_ln_s_add () {
        else
                printf '%s' "$1" >"$2" &&
                ln_s_obj=$(git hash-object -w "$2") &&
-               git update-index --add --cacheinfo 120000 $ln_s_obj "$2"
+               git update-index --add --cacheinfo 120000 $ln_s_obj "$2" &&
+               # pick up stat info from the file
+               git update-index "$2"
        fi
 }
 
index bb1402de944de11ee54a73dab7c33441ae1450c5..9914d3e1cfe20f09b47fdc02896dc18ed0f61e45 100644 (file)
@@ -152,10 +152,7 @@ unset UNZIP
 
 case $(echo $GIT_TRACE |tr "[A-Z]" "[a-z]") in
 1|2|true)
-       echo "* warning: Some tests will not work if GIT_TRACE" \
-               "is set as to trace on STDERR ! *"
-       echo "* warning: Please set GIT_TRACE to something" \
-               "other than 1, 2 or true ! *"
+       GIT_TRACE=4
        ;;
 esac
 
@@ -299,6 +296,7 @@ die () {
 
 GIT_EXIT_OK=
 trap 'die' EXIT
+trap 'exit $?' INT
 
 # The user-facing functions are loaded from a separate file so that
 # test_perf subshells can have them too
@@ -1031,12 +1029,42 @@ test_lazy_prereq USR_BIN_TIME '
        test -x /usr/bin/time
 '
 
-# When the tests are run as root, permission tests will report that
-# things are writable when they shouldn't be.
-test -w / || test_set_prereq SANITY
+test_lazy_prereq NOT_ROOT '
+       uid=$(id -u) &&
+       test "$uid" != 0
+'
+
+# On a filesystem that lacks SANITY, a file can be deleted even if
+# the containing directory doesn't have write permissions, or a file
+# can be accessed even if the containing directory doesn't have read
+# or execute permissions, causing our tests that validate that Git
+# works sensibly in such situations.
+test_lazy_prereq SANITY '
+       mkdir SANETESTD.1 SANETESTD.2 &&
+
+       chmod +w SANETESTD.1 SANETESTD.2 &&
+       >SANETESTD.1/x 2>SANETESTD.2/x &&
+       chmod -w SANETESTD.1 &&
+       chmod -rx SANETESTD.2 ||
+       error "bug in test sript: cannot prepare SANETESTD"
+
+       ! rm SANETESTD.1/x && ! test -f SANETESTD.2/x
+       status=$?
+
+       chmod +rwx SANETESTD.1 SANETESTD.2 &&
+       rm -rf SANETESTD.1 SANETESTD.2 ||
+       error "bug in test sript: cannot clean SANETESTD"
+       return $status
+'
 
 GIT_UNZIP=${GIT_UNZIP:-unzip}
 test_lazy_prereq UNZIP '
        "$GIT_UNZIP" -v
        test $? -ne 127
 '
+
+run_with_limited_cmdline () {
+       (ulimit -s 128 && "$@")
+}
+
+test_lazy_prereq CMDLINE_LIMIT 'run_with_limited_cmdline true'
index 97396a75ae4fc3f118750dd687fba85e3fc526cc..a2135e0743ac60d8d4512210a81bac2102948fa1 100644 (file)
@@ -35,7 +35,23 @@ int online_cpus(void)
 
        if (!pstat_getdynamic(&psd, sizeof(psd), (size_t)1, 0))
                return (int)psd.psd_proc_cnt;
-#endif
+#elif defined(HAVE_BSD_SYSCTL) && defined(HW_NCPU)
+       int mib[2];
+       size_t len;
+       int cpucount;
+
+       mib[0] = CTL_HW;
+#  ifdef HW_AVAILCPU
+       mib[1] = HW_AVAILCPU;
+       len = sizeof(cpucount);
+       if (!sysctl(mib, 2, &cpucount, &len, NULL, 0))
+               return cpucount;
+#  endif /* HW_AVAILCPU */
+       mib[1] = HW_NCPU;
+       len = sizeof(cpucount);
+       if (!sysctl(mib, 2, &cpucount, &len, NULL, 0))
+               return cpucount;
+#endif /* defined(HAVE_BSD_SYSCTL) && defined(HW_NCPU) */
 
 #ifdef _SC_NPROCESSORS_ONLN
        if ((ncpus = (long)sysconf(_SC_NPROCESSORS_ONLN)) > 0)
index 623adeb02d0e06a83d7b17a9b605ff8c6475a0bd..05b3859b476dc19f37d8715ac012c29373e8f91e 100644 (file)
--- a/trailer.c
+++ b/trailer.c
@@ -1,7 +1,6 @@
 #include "cache.h"
 #include "string-list.h"
 #include "run-command.h"
-#include "string-list.h"
 #include "commit.h"
 #include "trailer.h"
 /*
index 0224687a2316798c57315093315eafae0da0b1aa..5d99a6bc2e7a10d40f6d8213e2f3cad254dbdb04 100644 (file)
@@ -5,7 +5,6 @@
 #include "commit.h"
 #include "diff.h"
 #include "revision.h"
-#include "quote.h"
 #include "remote.h"
 #include "string-list.h"
 #include "thread-utils.h"
@@ -98,6 +97,8 @@ static void do_take_over(struct transport *transport)
        free(data);
 }
 
+static void standard_options(struct transport *t);
+
 static struct child_process *get_helper(struct transport *transport)
 {
        struct helper_data *data = transport->data;
@@ -212,6 +213,7 @@ static struct child_process *get_helper(struct transport *transport)
        strbuf_release(&buf);
        if (debug)
                fprintf(stderr, "Debug: Capabilities complete.\n");
+       standard_options(transport);
        return data->helper;
 }
 
@@ -339,24 +341,14 @@ static int fetch_with_fetch(struct transport *transport,
        int i;
        struct strbuf buf = STRBUF_INIT;
 
-       standard_options(transport);
-       if (data->check_connectivity &&
-           data->transport_options.check_self_contained_and_connected)
-               set_helper_option(transport, "check-connectivity", "true");
-
-       if (transport->cloning)
-               set_helper_option(transport, "cloning", "true");
-
-       if (data->transport_options.update_shallow)
-               set_helper_option(transport, "update-shallow", "true");
-
        for (i = 0; i < nr_heads; i++) {
                const struct ref *posn = to_fetch[i];
                if (posn->status & REF_STATUS_UPTODATE)
                        continue;
 
                strbuf_addf(&buf, "fetch %s %s\n",
-                           sha1_to_hex(posn->old_sha1), posn->name);
+                           sha1_to_hex(posn->old_sha1),
+                           posn->symref ? posn->symref : posn->name);
        }
 
        strbuf_addch(&buf, '\n');
@@ -454,7 +446,8 @@ static int fetch_with_import(struct transport *transport,
                if (posn->status & REF_STATUS_UPTODATE)
                        continue;
 
-               strbuf_addf(&buf, "import %s\n", posn->name);
+               strbuf_addf(&buf, "import %s\n",
+                           posn->symref ? posn->symref : posn->name);
                sendline(data, &buf);
                strbuf_reset(&buf);
        }
@@ -487,14 +480,15 @@ static int fetch_with_import(struct transport *transport,
         * fast-forward or this is a forced update.
         */
        for (i = 0; i < nr_heads; i++) {
-               char *private;
+               char *private, *name;
                posn = to_fetch[i];
                if (posn->status & REF_STATUS_UPTODATE)
                        continue;
+               name = posn->symref ? posn->symref : posn->name;
                if (data->refspecs)
-                       private = apply_refspecs(data->refspecs, data->refspec_nr, posn->name);
+                       private = apply_refspecs(data->refspecs, data->refspec_nr, name);
                else
-                       private = xstrdup(posn->name);
+                       private = xstrdup(name);
                if (private) {
                        read_ref(private, posn->old_sha1);
                        free(private);
@@ -620,6 +614,16 @@ static int fetch(struct transport *transport,
        if (!count)
                return 0;
 
+       if (data->check_connectivity &&
+           data->transport_options.check_self_contained_and_connected)
+               set_helper_option(transport, "check-connectivity", "true");
+
+       if (transport->cloning)
+               set_helper_option(transport, "cloning", "true");
+
+       if (data->transport_options.update_shallow)
+               set_helper_option(transport, "update-shallow", "true");
+
        if (data->fetch)
                return fetch_with_fetch(transport, nr_heads, to_fetch);
 
@@ -824,7 +828,6 @@ static int push_refs_with_push(struct transport *transport,
                return 0;
        }
 
-       standard_options(transport);
        for_each_string_list_item(cas_option, &cas_options)
                set_helper_option(transport, "cas", cas_option->string);
 
@@ -860,7 +863,7 @@ static int push_refs_with_export(struct transport *transport,
                        die("helper %s does not support dry-run", data->name);
        } else if (flags & TRANSPORT_PUSH_CERT) {
                if (set_helper_option(transport, TRANS_OPT_PUSH_CERT, "true") != 0)
-                       die("helper %s does not support dry-run", data->name);
+                       die("helper %s does not support --signed", data->name);
        }
 
        if (flags & TRANSPORT_PUSH_FORCE) {
index 0694a7cf3e4a8bd7bec9fefcd440d65423021a1b..00f39d9f5ba8c024ec2b9c6c2a054a0045eadbbb 100644 (file)
@@ -117,7 +117,7 @@ static void insert_packed_refs(const char *packed_refs, struct ref **list)
                        return;
                }
 
-               if (hexval(buffer[0]) > 0xf)
+               if (!isxdigit(buffer[0]))
                        continue;
                len = strlen(buffer);
                if (len && buffer[len - 1] == '\n')
index b531a325d2864e94bdc86e689f78663255bb7cf2..aa845765009ac7fb9105851306c3288b3f602369 100644 (file)
@@ -681,7 +681,7 @@ static void receive_needs(void)
 }
 
 /* return non-zero if the ref is hidden, otherwise 0 */
-static int mark_our_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
+static int mark_our_ref(const char *refname, const unsigned char *sha1)
 {
        struct object *o = lookup_unknown_object(sha1);
 
@@ -689,12 +689,16 @@ static int mark_our_ref(const char *refname, const unsigned char *sha1, int flag
                o->flags |= HIDDEN_REF;
                return 1;
        }
-       if (!o)
-               die("git upload-pack: cannot find object %s:", sha1_to_hex(sha1));
        o->flags |= OUR_REF;
        return 0;
 }
 
+static int check_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
+{
+       mark_our_ref(refname, sha1);
+       return 0;
+}
+
 static void format_symref_info(struct strbuf *buf, struct string_list *symref)
 {
        struct string_list_item *item;
@@ -713,7 +717,7 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo
        const char *refname_nons = strip_namespace(refname);
        unsigned char peeled[20];
 
-       if (mark_our_ref(refname, sha1, flag, NULL))
+       if (mark_our_ref(refname, sha1))
                return 0;
 
        if (capabilities) {
@@ -767,8 +771,8 @@ static void upload_pack(void)
                advertise_shallow_grafts(1);
                packet_flush(1);
        } else {
-               head_ref_namespaced(mark_our_ref, NULL);
-               for_each_namespaced_ref(mark_our_ref, NULL);
+               head_ref_namespaced(check_ref, NULL);
+               for_each_namespaced_ref(check_ref, NULL);
        }
        string_list_clear(&symref, 1);
        if (advertise_refs)
index fad52d6392fab8aadc8f6555db5aafcde224a120..2ccbee50cb69171062e84c9a1b36baf7e31be2f8 100644 (file)
@@ -1,6 +1,5 @@
 #include "cache.h"
 #include "userdiff.h"
-#include "cache.h"
 #include "attr.h"
 
 static struct userdiff_driver *drivers;
index 7511e08271fb60276008c0b364a45b9512f49cea..80bfd109fa1285a24dbfa8e9aabdfc3b3bd59801 100644 (file)
@@ -1,4 +1,5 @@
 #include "cache.h"
+#include "string-list.h"
 
 /*
  * versioncmp(): copied from string/strverscmp.c in glibc commit
 #define  CMP    2
 #define  LEN    3
 
+static const struct string_list *prereleases;
+static int initialized;
+
+/*
+ * p1 and p2 point to the first different character in two strings. If
+ * either p1 or p2 starts with a prerelease suffix, it will be forced
+ * to be on top.
+ *
+ * If both p1 and p2 start with (different) suffix, the order is
+ * determined by config file.
+ *
+ * Note that we don't have to deal with the situation when both p1 and
+ * p2 start with the same suffix because the common part is already
+ * consumed by the caller.
+ *
+ * Return non-zero if *diff contains the return value for versioncmp()
+ */
+static int swap_prereleases(const void *p1_,
+                           const void *p2_,
+                           int *diff)
+{
+       const char *p1 = p1_;
+       const char *p2 = p2_;
+       int i, i1 = -1, i2 = -1;
+
+       for (i = 0; i < prereleases->nr; i++) {
+               const char *suffix = prereleases->items[i].string;
+               if (i1 == -1 && starts_with(p1, suffix))
+                       i1 = i;
+               if (i2 == -1 && starts_with(p2, suffix))
+                       i2 = i;
+       }
+       if (i1 == -1 && i2 == -1)
+               return 0;
+       if (i1 >= 0 && i2 >= 0)
+               *diff = i1 - i2;
+       else if (i1 >= 0)
+               *diff = -1;
+       else /* if (i2 >= 0) */
+               *diff = 1;
+       return 1;
+}
 
 /*
  * Compare S1 and S2 as strings holding indices/version numbers,
@@ -74,6 +117,13 @@ int versioncmp(const char *s1, const char *s2)
                state += (c1 == '0') + (isdigit (c1) != 0);
        }
 
+       if (!initialized) {
+               initialized = 1;
+               prereleases = git_config_get_value_multi("versionsort.prereleasesuffix");
+       }
+       if (prereleases && swap_prereleases(p1 - 1, p2 - 1, &diff))
+               return diff;
+
        state = result_type[state * 3 + (((c2 == '0') + (isdigit (c2) != 0)))];
 
        switch (state) {
index 483da4e0fb5771b8a64d62648624258dcf3fdcb0..58ffeca264b765326a234b21356a02a3152e1c38 100644 (file)
--- a/walker.c
+++ b/walker.c
@@ -299,7 +299,7 @@ int walker_fetch(struct walker *walker, int targets, char **target,
                strbuf_reset(&refname);
                strbuf_addf(&refname, "refs/%s", write_ref[i]);
                if (ref_transaction_update(transaction, refname.buf,
-                                          &sha1[20 * i], NULL, 0, 0,
+                                          &sha1[20 * i], NULL, 0,
                                           msg ? msg : "fetch (unknown)",
                                           &err)) {
                        error("%s", err.buf);
index 007ec0d8eac529579cc00b14f9baaddb7ac68487..d5a6cef2be0fb13b262bed2e0b58bd58fbb5454d 100644 (file)
--- a/wrapper.c
+++ b/wrapper.c
@@ -172,8 +172,22 @@ void *xcalloc(size_t nmemb, size_t size)
  * 64-bit is buggy, returning EINVAL if len >= INT_MAX; and even in
  * the absence of bugs, large chunks can result in bad latencies when
  * you decide to kill the process.
+ *
+ * We pick 8 MiB as our default, but if the platform defines SSIZE_MAX
+ * that is smaller than that, clip it to SSIZE_MAX, as a call to
+ * read(2) or write(2) larger than that is allowed to fail.  As the last
+ * resort, we allow a port to pass via CFLAGS e.g. "-DMAX_IO_SIZE=value"
+ * to override this, if the definition of SSIZE_MAX given by the platform
+ * is broken.
  */
-#define MAX_IO_SIZE (8*1024*1024)
+#ifndef MAX_IO_SIZE
+# define MAX_IO_SIZE_DEFAULT (8*1024*1024)
+# if defined(SSIZE_MAX) && (SSIZE_MAX < MAX_IO_SIZE_DEFAULT)
+#  define MAX_IO_SIZE SSIZE_MAX
+# else
+#  define MAX_IO_SIZE MAX_IO_SIZE_DEFAULT
+# endif
+#endif
 
 /*
  * xread() is the same a read(), but it automatically restarts read()
index b54eac5af6233de183144230259bd317cf24513a..7036fa28dc39f72ed2064ca0ad15f2e381808020 100644 (file)
@@ -849,6 +849,8 @@ static void wt_status_print_verbose(struct wt_status *s)
 {
        struct rev_info rev;
        struct setup_revision_opt opt;
+       int dirty_submodules;
+       const char *c = color(WT_STATUS_HEADER, s);
 
        init_revisions(&rev, NULL);
        DIFF_OPT_SET(&rev.diffopt, ALLOW_TEXTCONV);
@@ -873,7 +875,25 @@ static void wt_status_print_verbose(struct wt_status *s)
                rev.diffopt.use_color = 0;
                wt_status_add_cut_line(s->fp);
        }
+       if (s->verbose > 1 && s->commitable) {
+               /* print_updated() printed a header, so do we */
+               if (s->fp != stdout)
+                       wt_status_print_trailer(s);
+               status_printf_ln(s, c, _("Changes to be committed:"));
+               rev.diffopt.a_prefix = "c/";
+               rev.diffopt.b_prefix = "i/";
+       } /* else use prefix as per user config */
        run_diff_index(&rev, 1);
+       if (s->verbose > 1 &&
+           wt_status_check_worktree_changes(s, &dirty_submodules)) {
+               status_printf_ln(s, c,
+                       "--------------------------------------------------");
+               status_printf_ln(s, c, _("Changes not staged for commit:"));
+               setup_work_tree();
+               rev.diffopt.a_prefix = "i/";
+               rev.diffopt.b_prefix = "w/";
+               run_diff_files(&rev, 0);
+       }
 }
 
 static void wt_status_print_tracking(struct wt_status *s)
@@ -1140,7 +1160,7 @@ static char *read_and_strip_branch(const char *path)
        if (strbuf_read_file(&sb, git_path("%s", path), 0) <= 0)
                goto got_nothing;
 
-       while (&sb.len && sb.buf[sb.len - 1] == '\n')
+       while (sb.len && sb.buf[sb.len - 1] == '\n')
                strbuf_setlen(&sb, sb.len - 1);
        if (!sb.len)
                goto got_nothing;
@@ -1222,6 +1242,8 @@ static void wt_status_get_detached_from(struct wt_status_state *state)
                state->detached_from =
                        xstrdup(find_unique_abbrev(cb.nsha1, DEFAULT_ABBREV));
        hashcpy(state->detached_sha1, cb.nsha1);
+       state->detached_at = !get_sha1("HEAD", sha1) &&
+                            !hashcmp(sha1, state->detached_sha1);
 
        free(ref);
        strbuf_release(&cb.buf);
@@ -1310,10 +1332,8 @@ void wt_status_print(struct wt_status *s)
                                on_what = _("rebase in progress; onto ");
                                branch_name = state.onto;
                        } else if (state.detached_from) {
-                               unsigned char sha1[20];
                                branch_name = state.detached_from;
-                               if (!get_sha1("HEAD", sha1) &&
-                                   !hashcmp(sha1, state.detached_sha1))
+                               if (state.detached_at)
                                        on_what = _("HEAD detached at ");
                                else
                                        on_what = _("HEAD detached from ");
index 283a9fef0335ce272c6799a5af17274e4798e15f..e0a99f75c745acd3e7fb6fd8aecd06a4d3bd5522 100644 (file)
@@ -84,6 +84,7 @@ struct wt_status_state {
        int cherry_pick_in_progress;
        int bisect_in_progress;
        int revert_in_progress;
+       int detached_at;
        char *branch;
        char *onto;
        char *detached_from;
diff --git a/zlib.c b/zlib.c
index 61e6df0fdce6dfaf38da7af996d7fe801db8f00c..4223f1a8c57a281d5e41c329a4f983a7bb3b57a0 100644 (file)
--- a/zlib.c
+++ b/zlib.c
@@ -159,6 +159,7 @@ void git_deflate_init(git_zstream *strm, int level)
 {
        int status;
 
+       memset(strm, 0, sizeof(*strm));
        zlib_pre_call(strm);
        status = deflateInit(&strm->z, level);
        zlib_post_call(strm);
@@ -172,6 +173,7 @@ static void do_git_deflate_init(git_zstream *strm, int level, int windowBits)
 {
        int status;
 
+       memset(strm, 0, sizeof(*strm));
        zlib_pre_call(strm);
        status = deflateInit2(&strm->z, level,
                                  Z_DEFLATED, windowBits,