Sync with v2.3.4
authorJunio C Hamano <gitster@pobox.com>
Mon, 23 Mar 2015 18:37:49 +0000 (11:37 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 23 Mar 2015 18:37:49 +0000 (11:37 -0700)
201 files changed:
Documentation/CodingGuidelines
Documentation/RelNotes/2.4.0.txt [new file with mode: 0644]
Documentation/blame-options.txt
Documentation/config.txt
Documentation/diff-config.txt
Documentation/diff-options.txt
Documentation/fetch-options.txt
Documentation/git-add.txt
Documentation/git-apply.txt
Documentation/git-branch.txt
Documentation/git-check-ignore.txt
Documentation/git-checkout.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-init.txt
Documentation/git-instaweb.txt
Documentation/git-log.txt
Documentation/git-merge.txt
Documentation/git-p4.txt
Documentation/git-pull.txt
Documentation/git-push.txt
Documentation/git-rebase.txt
Documentation/git-receive-pack.txt
Documentation/git-reflog.txt
Documentation/git-repack.txt
Documentation/git-rerere.txt
Documentation/git-send-email.txt
Documentation/git-send-pack.txt
Documentation/git-status.txt
Documentation/git-tag.txt
Documentation/git.txt
Documentation/gitattributes.txt
Documentation/gitcredentials.txt
Documentation/githooks.txt
Documentation/gitignore.txt
Documentation/gitweb.conf.txt
Documentation/merge-config.txt
Documentation/pretty-options.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/technical/protocol-capabilities.txt
Documentation/user-manual.txt
GIT-VERSION-GEN
Makefile
RelNotes
advice.c
archive-zip.c
archive.c
attr.c
branch.c
builtin/add.c
builtin/apply.c
builtin/blame.c
builtin/branch.c
builtin/cat-file.c
builtin/check-attr.c
builtin/check-ignore.c
builtin/check-mailmap.c
builtin/check-ref-format.c
builtin/checkout-index.c
builtin/checkout.c
builtin/clean.c
builtin/clone.c
builtin/column.c
builtin/commit.c
builtin/config.c
builtin/describe.c
builtin/diff-files.c
builtin/diff-index.c
builtin/diff-tree.c
builtin/fetch-pack.c
builtin/fetch.c
builtin/fmt-merge-msg.c
builtin/for-each-ref.c
builtin/fsck.c
builtin/gc.c
builtin/grep.c
builtin/hash-object.c
builtin/help.c
builtin/init-db.c
builtin/log.c
builtin/ls-files.c
builtin/ls-remote.c
builtin/mailinfo.c
builtin/merge-base.c
builtin/merge-file.c
builtin/merge-index.c
builtin/merge.c
builtin/mv.c
builtin/name-rev.c
builtin/notes.c
builtin/pack-redundant.c
builtin/pack-refs.c
builtin/prune-packed.c
builtin/push.c
builtin/receive-pack.c
builtin/reflog.c
builtin/remote.c
builtin/repack.c
builtin/replace.c
builtin/rerere.c
builtin/rev-parse.c
builtin/revert.c
builtin/rm.c
builtin/send-pack.c
builtin/shortlog.c
builtin/show-branch.c
builtin/show-ref.c
builtin/symbolic-ref.c
builtin/tag.c
builtin/update-index.c
builtin/update-ref.c
builtin/verify-commit.c
builtin/verify-pack.c
builtin/verify-tag.c
bundle.c
cache.h
check-builtins.sh
commit.h
config.mak.uname
configure.ac
connect.c
contrib/completion/git-completion.bash
credential-store.c
daemon.c
diff-lib.c
fast-import.c
gettext.c
gettext.h
git-bisect.sh
git-compat-util.h
git-instaweb.sh
git-p4.py
git-send-email.perl
git-svn.perl
git.c
http.c
http.h
line-log.c
line-log.h
log-tree.c
pack-bitmap.c
pack-bitmap.h
perl/Git/SVN.pm
perl/Git/SVN/Editor.pm
perl/Git/SVN/Fetcher.pm
perl/Git/SVN/Ra.pm
prompt.c
prompt.h
refs.c
refs.h
remote-curl.c
remote.c
remote.h
revision.c
revision.h
run-command.c
send-pack.c
send-pack.h
sequencer.c
shallow.c
strbuf.h
t/lib-httpd.sh
t/lib-httpd/apache.conf
t/lib-terminal.sh
t/t3203-branch-output.sh
t/t3511-cherry-pick-x.sh
t/t4013/diff.log_--decorate_--all
t/t4122-apply-symlink-inside.sh
t/t4202-log.sh
t/t4207-log-decoration-colors.sh
t/t5003-archive-zip.sh
t/t5516-fetch-push.sh
t/t5528-push-default.sh
t/t5541-http-push-smart.sh
t/t5543-atomic-push.sh [new file with mode: 0755]
t/t5550-http-fetch-dumb.sh
t/t5551-http-fetch-smart.sh
t/t7004-tag.sh
t/t7508-status.sh
t/t7516-commit-races.sh [new file with mode: 0755]
t/t9817-git-p4-exclude.sh [new file with mode: 0755]
t/test-lib.sh
thread-utils.c
transport-helper.c
transport.c
transport.h
upload-pack.c
urlmatch.c
urlmatch.h
versioncmp.c
walker.c
wrapper.c
wt-status.c
wt-status.h
index 0f8cccf52da4882377a56042a4de3ff754d357b9..376d5ec4f8dbbc0034416192fc13a1a527c7ca4b 100644 (file)
@@ -328,9 +328,14 @@ For C programs:
 
  - When you come up with an API, document it.
 
- - The first #include in C files, except in platform specific
-   compat/ implementations, should be git-compat-util.h or another
-   header file that includes it, such as cache.h or builtin.h.
+ - The first #include in C files, except in platform specific compat/
+   implementations, must be either "git-compat-util.h", "cache.h" or
+   "builtin.h".  You do not have to include more than one of these.
+
+ - A C file must directly include the header files that declare the
+   functions and the types it uses, except for the functions and types
+   that are made available to it by including one of the header files
+   it must include by the previous rule.
 
  - If you are planning a new command, consider writing it in shell
    or perl first, so that changes in semantics can be easily
@@ -464,6 +469,10 @@ Writing Documentation:
    --sort=<key>
    --abbrev[=<n>]
 
+ If a placeholder has multiple words, they are separated by dashes:
+   <new-branch-name>
+   --template=<template-directory>
+
  Possibility of multiple occurrences is indicated by three dots:
    <file>...
    (One or more of <file>.)
@@ -480,12 +489,12 @@ Writing Documentation:
    (Zero or more of <patch>.  Note that the dots are inside, not
    outside the brackets.)
 
- Multiple alternatives are indicated with vertical bar:
+ Multiple alternatives are indicated with vertical bars:
    [-q | --quiet]
    [--utf8 | --no-utf8]
 
  Parentheses are used for grouping:
-   [(<rev>|<range>)...]
+   [(<rev> | <range>)...]
    (Any number of either <rev> or <range>.  Parens are needed to make
    it clear that "..." pertains to both <rev> and <range>.)
 
@@ -517,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.4.0.txt b/Documentation/RelNotes/2.4.0.txt
new file mode 100644 (file)
index 0000000..f052162
--- /dev/null
@@ -0,0 +1,414 @@
+Git 2.4 Release Notes
+=====================
+
+Backward compatibility warning(s)
+---------------------------------
+
+This release has a few changes in the user-visible output from
+Porcelain commands, which the users may want to be aware of.
+
+ * 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)
+     ...
+
+ * The phrasing "git branch" uses to describe a detached HEAD has been
+   updated to match that of "git status":
+
+    - When the HEAD is at the same commit as it was originally
+      detached, they now both show "detached at <commit object name>".
+
+    - When the HEAD has moved since it was originally detached,
+      they now both show "detached from <commit object name>".
+
+    Earlier "git branch" always used "from"
+
+
+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.
+
+ * "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.
+
+ * A new "push.followTags" configuration turns the "--follow-tags"
+   option on by default for the "git push" command.
+
+
+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.
+
+ * "git push" codepath has been restructured to make it easier to add
+   new configuration bits.
+
+
+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).
+
+ * The code that reads from the ctags file in the completion script
+   (in contrib/) did not spell ${param/pattern/string} substitution
+   correctly, which happened to work with bash but not with zsh.
+   (merge db8d750 js/completion-ctags-pattern-substitution-fix later to maint).
+
+ * The transfer.hiderefs support did not quite work for smart-http
+   transport.
+   (merge 8ddf3ca jk/smart-http-hide-refs later to maint).
+
+ * "git tag -h" used to show the "--column" and "--sort" options
+   that are about listing in a wrong section.
+   (merge dd059c6 jk/tag-h-column-is-a-listing-option later to maint).
+
+ * Code cleanups and documentation 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).
+   (merge 376e4b3 jk/test-annoyances 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 1a8ddb41c7fff8cce5d2c0a51a9d642e3bf0fd42..2e5ceaf71974b1e5404de79103648da1829eaf42 100644 (file)
@@ -154,9 +154,8 @@ color::
        `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).
+       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
@@ -270,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
@@ -279,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).
@@ -309,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
@@ -519,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
@@ -582,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
@@ -591,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'
@@ -600,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.
 
@@ -614,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
@@ -683,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
@@ -691,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
@@ -762,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.
@@ -774,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,
@@ -786,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").
@@ -797,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.
 
@@ -839,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
@@ -965,7 +964,7 @@ 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
@@ -1065,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
@@ -1178,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.
 
@@ -1188,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.
 
@@ -1212,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
@@ -1251,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
@@ -1269,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".
 
@@ -1308,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].
 
@@ -1320,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
@@ -1333,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
@@ -1341,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
@@ -1349,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::
@@ -1363,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.
@@ -1381,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.
 
@@ -1410,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".
 
@@ -1430,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".
 
@@ -1447,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.
@@ -1477,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
@@ -1500,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.
 
@@ -1516,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::
@@ -1528,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
@@ -1537,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
@@ -1549,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
@@ -1630,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
@@ -1703,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].)
 
@@ -1719,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.
@@ -1728,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
@@ -1756,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
@@ -1993,7 +1992,7 @@ pack.useBitmaps::
        true. You should not generally need to turn this off unless
        you are debugging pack bitmaps.
 
-pack.writebitmaps (deprecated)::
+pack.writeBitmaps (deprecated)::
        This is a deprecated synonym for `repack.writeBitmaps`.
 
 pack.writeBitmapHashCache::
@@ -2112,14 +2111,20 @@ new default).
 
 --
 
+push.followTags::
+       If set to true enable '--follow-tags' option by default.  You
+       may override this configuration at time of push by specifying
+       '--no-follow-tags'.
+
+
 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.
@@ -2127,18 +2132,23 @@ rebase.autostash::
        successful rebase might result in non-trivial conflicts.
        Defaults to false.
 
+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.
+
 receive.autogc::
        By default, git-receive-pack will run "git-gc --auto" after
        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"
@@ -2186,11 +2196,15 @@ receive.denyCurrentBranch::
        message. Defaults to "refuse".
 +
 Another option is "updateInstead" which will update the working
-directory (must be clean) if pushing into the current branch. This option is
+tree if pushing into the current branch.  This option is
 intended for synchronizing working directories when one side is not easily
 accessible via interactive ssh (e.g. a live web site, hence the requirement
 that the working directory be clean). This mode also comes in handy when
 developing inside a VM to test and fix code on different Operating Systems.
++
+By default, "updateInstead" will refuse the push if the working tree or
+the index have any difference from the HEAD, but the `push-to-checkout`
+hook can be used to customize this.  See linkgit:githooks[5].
 
 receive.denyNonFastForwards::
        If set to true, git-receive-pack will deny a ref update which is
@@ -2198,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
@@ -2207,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
@@ -2262,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
@@ -2284,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
@@ -2307,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.
@@ -2326,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)::
-       Deprecated alias for 'sendemail.smtpencryption = ssl'.
+       Deprecated alias for 'sendemail.smtpEncryption = ssl'.
 
 sendemail.smtpsslcertpath::
        Path to ca-certificates (either a directory or a single file).
@@ -2343,29 +2357,29 @@ 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.
@@ -2417,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
@@ -2492,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::
@@ -2509,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
@@ -2519,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
@@ -2532,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::
@@ -2569,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 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 9489664cfa6c15725a5153ed3856b70061c6787f..d9ed6a1a4ea6dc0068144eac4c5e0f5ef33a04cb 100644 (file)
@@ -242,7 +242,7 @@ 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 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 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 6ab5f9497ab353e38c15708443527e1d047d39e8..a1664b9f684bae0d3e715b36760ce62f4745ed06 100644 (file)
@@ -241,6 +241,9 @@ Git repository:
        Use a client spec to find the list of interesting files in p4.
        See the "CLIENT SPEC" section below.
 
+-/ <path>::
+       Exclude selected depot paths when cloning or syncing.
+
 Clone options
 ~~~~~~~~~~~~~
 These options can be used in an initial 'clone', along with the 'sync'
@@ -254,9 +257,6 @@ options described above.
 --bare::
        Perform a bare clone.  See linkgit:git-clone[1].
 
--/ <path>::
-       Exclude selected depot paths when cloning.
-
 Submit options
 ~~~~~~~~~~~~~~
 These options can be used to modify 'git p4 submit' behavior.
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 58cc59f20cc5a3338f782e09639b8ae8bdc97ae3..5171086181f86b995f89ddc68de94bd2359561a3 100644 (file)
@@ -9,7 +9,7 @@ git-push - Update remote refs along with associated objects
 SYNOPSIS
 --------
 [verse]
-'git push' [--all | --mirror | --tags] [--follow-tags] [-n | --dry-run] [--receive-pack=<git-receive-pack>]
+'git push' [--all | --mirror | --tags] [--follow-tags] [--atomic] [-n | --dry-run] [--receive-pack=<git-receive-pack>]
           [--repo=<repository>] [-f | --force] [--prune] [-v | --verbose]
           [-u | --set-upstream] [--signed]
           [--force-with-lease[=<refname>[:<expect>]]]
@@ -128,7 +128,10 @@ already exists on the remote side.
        Push all the refs that would be pushed without this option,
        and also push annotated tags in `refs/tags` that are missing
        from the remote but are pointing at commit-ish that are
-       reachable from the refs being pushed.
+       reachable from the refs being pushed.  This can also be specified
+       with configuration variable 'push.followTags'.  For more
+       information, see 'push.followTags' in linkgit:git-config[1].
+
 
 --signed::
        GPG-sign the push request to update refs on the receiving
@@ -136,6 +139,11 @@ already exists on the remote side.
        logged.  See linkgit:git-receive-pack[1] for the details
        on the receiving end.
 
+--[no-]atomic::
+       Use an atomic transaction on the remote side if available.
+       Either all refs are updated, or on error, no refs are updated.
+       If the server does not support atomic pushes the push will fail.
+
 --receive-pack=<git-receive-pack>::
 --exec=<git-receive-pack>::
        Path to the 'git-receive-pack' program on the remote
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 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 2a0de42a75d482a4bbafefd19991dad25b3e67f9..45c7725dc303eed198fc0ed370f603a71d1fa8c1 100644 (file)
@@ -9,7 +9,7 @@ git-send-pack - Push objects over Git protocol to another repository
 SYNOPSIS
 --------
 [verse]
-'git send-pack' [--all] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]
+'git send-pack' [--all] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [--atomic] [<host>:]<directory> [<ref>...]
 
 DESCRIPTION
 -----------
@@ -62,6 +62,11 @@ be in a separate packet, and the list must end with a flush packet.
        Send a "thin" pack, which records objects in deltified form based
        on objects not included in the pack to reduce network traffic.
 
+--atomic::
+       Use an atomic transaction for updating the refs. If any of the refs
+       fails to update then the entire push will fail without changing any
+       refs.
+
 <host>::
        A remote host to house the repository.  When this
        part is specified, 'git-receive-pack' is invoked via
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 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 9c7561705198e56ebb48897c30ebebf15a76bc1a..4749d1b4dfb5b0209588490063d035c90b79fb76 100644 (file)
@@ -920,7 +920,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 9ef2469373a5d7ddc511d9569ed57ca587cc2c6d..7ba0ac965dd6266404d4b3fad74d59a4e79be0dd 100644 (file)
@@ -341,6 +341,36 @@ Both standard output and standard error output are forwarded to
 'git send-pack' on the other end, so you can simply `echo` messages
 for the user.
 
+push-to-checkout
+~~~~~~~~~~~~~~~~
+
+This hook is invoked by 'git-receive-pack' on the remote repository,
+which happens when a 'git push' is done on a local repository, when
+the push tries to update the branch that is currently checked out
+and the `receive.denyCurrentBranch` configuration variable is set to
+`updateInstead`.  Such a push by default is refused if the working
+tree and the index of the remote repository has any difference from
+the currently checked out commit; when both the working tree and the
+index match the current commit, they are updated to match the newly
+pushed tip of the branch.  This hook is to be used to override the
+default behaviour.
+
+The hook receives the commit with which the tip of the current
+branch is going to be updated.  It can exit with a non-zero status
+to refuse the push (when it does so, it must not modify the index or
+the working tree).  Or it can make any necessary changes to the
+working tree and to the index to bring them to the desired state
+when the tip of the current branch is updated to the new commit, and
+exit with a zero status.
+
+For example, the hook can simply run `git read-tree -u -m HEAD "$1"`
+in order to emulate 'git fetch' that is run in the reverse direction
+with `git push`, as the two-tree form of `read-tree -u -m` is
+essentially the same as `git checkout` that switches branches while
+keeping the local changes in the working tree that do not interfere
+with the difference between the branches.
+
+
 pre-auto-gc
 ~~~~~~~~~~~
 
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 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 8569e29d08784cb5eb053af919e4b7514b1c296b..74aa01a0ec27b6cc0fbb9763b8e583a3f996da25 100644 (file)
@@ -3,9 +3,13 @@
 
        Pretty-print the contents of the commit logs in a given format,
        where '<format>' can be one of 'oneline', 'short', 'medium',
-       'full', 'fuller', 'email', 'raw' and 'format:<string>'.  See
-       the "PRETTY FORMATS" section for some additional details for each
-       format.  When omitted, the format defaults to 'medium'.
+       'full', 'fuller', 'email', 'raw', 'format:<string>'
+       and 'tformat:<string>'.  When '<format>' is none of the above,
+       and has '%placeholder' in it, it acts as if
+       '--pretty=tformat:<format>' were given.
++
+See the "PRETTY FORMATS" section for some additional details for each
+format.  When '=<format>' part is omitted, it defaults to 'medium'.
 +
 Note: you can specify the default pretty format in the repository
 configuration (see linkgit:git-config[1]).
index 97ef2e8e71c1f8898453df4ed81877434097f7a1..4ed8587c846d78a03e154ec6a4716d78882840b5 100644 (file)
@@ -66,6 +66,10 @@ if it is part of the log message.
        Limit the commits output to ones that match all given `--grep`,
        instead of ones that match at least one.
 
+--invert-grep::
+       Limit the commits output to ones with log message that do not
+       match the pattern specified with `--grep=<pattern>`.
+
 -i::
 --regexp-ignore-case::
        Match the regular expression limiting patterns without regard to letter
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 6d5424c1bde5d97118be7dfe4ac4d682350d9e4a..4f8a7bfb4c68e42e4969c8c9d0b3555b880a7e58 100644 (file)
@@ -18,8 +18,9 @@ was sent.  Server MUST NOT ignore capabilities that client requested
 and server advertised.  As a consequence of these rules, server MUST
 NOT advertise capabilities it does not understand.
 
-The 'report-status', 'delete-refs', 'quiet', and 'push-cert' capabilities
-are sent and recognized by the receive-pack (push to server) process.
+The 'atomic', 'report-status', 'delete-refs', 'quiet', and 'push-cert'
+capabilities are sent and recognized by the receive-pack (push to server)
+process.
 
 The 'ofs-delta' and 'side-band-64k' capabilities are sent and recognized
 by both upload-pack and receive-pack protocols.  The 'agent' capability
@@ -244,6 +245,14 @@ respond with the 'quiet' capability to suppress server-side progress
 reporting if the local progress reporting is also being suppressed
 (e.g., via `push -q`, or if stderr does not go to a tty).
 
+atomic
+------
+
+If the server sends the 'atomic' capability it is capable of accepting
+atomic pushes. If the pushing client requests this capability, the server
+will update the refs in one atomic transaction. Either all refs are
+updated or none.
+
 allow-tip-sha1-in-want
 ----------------------
 
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 9905751fc2406d135ee2f855e3d9f9897f95da84..734fa9b4347ac1f65ad35ada88098404d92fcb25 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v2.3.4
+DEF_VER=v2.3.3.GIT
 
 LF='
 '
index 20058f1de7815bd00655bd36676e9bb7be072e96..5f3987fe3bd945fb5a84c9f45a8de7da5581f79a 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -348,6 +348,17 @@ all::
 #
 # Define NO_HMAC_CTX_CLEANUP if your OpenSSL is version 0.9.6b or earlier to
 # cleanup the HMAC context with the older HMAC_cleanup function.
+#
+# Define USE_PARENS_AROUND_GETTEXT_N to "yes" if your compiler happily
+# compiles the following initialization:
+#
+#   static const char s[] = ("FOO");
+#
+# 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
@@ -955,6 +966,14 @@ ifneq (,$(SOCKLEN_T))
        BASIC_CFLAGS += -Dsocklen_t=$(SOCKLEN_T)
 endif
 
+ifeq (yes,$(USE_PARENS_AROUND_GETTEXT_N))
+       BASIC_CFLAGS += -DUSE_PARENS_AROUND_GETTEXT_N=1
+else
+ifeq (no,$(USE_PARENS_AROUND_GETTEXT_N))
+       BASIC_CFLAGS += -DUSE_PARENS_AROUND_GETTEXT_N=0
+endif
+endif
+
 ifeq ($(uname_S),Darwin)
        ifndef NO_FINK
                ifeq ($(shell test -d /sw/lib && echo y),y)
@@ -1414,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
index f631b25aa35a19b7bba840dbf838424562d40b98..1addbec92533510e6e368c607deb36e504bbc438 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.3.4.txt
\ No newline at end of file
+Documentation/RelNotes/2.4.0.txt
\ No newline at end of file
index 3b8bf3c6da6afdd5ef4cfcc77131690ccbbf3757..575bec20b35a31e653e49125386f3dcee880c217 100644 (file)
--- a/advice.c
+++ b/advice.c
@@ -105,7 +105,7 @@ void detach_advice(const char *new_name)
        "state without impacting any branches by performing another checkout.\n\n"
        "If you want to create a new branch to retain commits you create, you may\n"
        "do so (now or later) by using -b with the checkout command again. Example:\n\n"
-       "  git checkout -b new_branch_name\n\n";
+       "  git checkout -b <new-branch-name>\n\n";
 
        fprintf(stderr, fmt, new_name);
 }
index 1a54e1b187178e9818ee3e3f90279c2985fa7b63..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;
@@ -188,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,
@@ -209,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);
 
@@ -255,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;
@@ -299,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);
 
@@ -327,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);
@@ -359,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;
@@ -403,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);
index 9e30246b6402454e8d92fb6aa24a1a07c534b0ef..96057ed830e521a5f12b0a73b4a04a6b5e581e87 100644 (file)
--- a/archive.c
+++ b/archive.c
@@ -8,9 +8,9 @@
 #include "dir.h"
 
 static char const * const archive_usage[] = {
-       N_("git archive [options] <tree-ish> [<path>...]"),
+       N_("git archive [<options>] <tree-ish> [<path>...]"),
        N_("git archive --list"),
-       N_("git archive --remote <repo> [--exec <cmd>] [options] <tree-ish> [<path>...]"),
+       N_("git archive --remote <repo> [--exec <cmd>] [<options>] <tree-ish> [<path>...]"),
        N_("git archive --remote <repo> [--exec <cmd>] --list"),
        NULL
 };
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 1074e3234964deb279c3a487e9efd164afdb9c6c..3390933d68b2dd6c7296a7d2103d009fa27f2ca8 100644 (file)
@@ -19,7 +19,7 @@
 #include "argv-array.h"
 
 static const char * const builtin_add_usage[] = {
-       N_("git add [options] [--] <pathspec>..."),
+       N_("git add [<options>] [--] <pathspec>..."),
        NULL
 };
 static int patch_interactive, add_interactive, edit_interactive;
index 0ca687fa6b049b29d12ec417afcbec8491ecdc2c..65b97eee69d4814bf80f87b1fd6857b8ed80cb90 100644 (file)
@@ -56,7 +56,7 @@ static const char *fake_ancestor;
 static int line_termination = '\n';
 static unsigned int p_context = UINT_MAX;
 static const char * const apply_usage[] = {
-       N_("git apply [options] [<patch>...]"),
+       N_("git apply [<options>] [<patch>...]"),
        NULL
 };
 
@@ -1601,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 &&
index 2b1f9dd6cd01be506c65441685b8d4b79cc74010..06484c2e0e23237bff711bbe3cda6e1382004ef3 100644 (file)
 #include "line-range.h"
 #include "line-log.h"
 
-static char blame_usage[] = N_("git blame [options] [rev-opts] [rev] [--] file");
+static char blame_usage[] = N_("git blame [<options>] [<rev-opts>] [<rev>] [--] file");
 
 static const char *blame_opt_usage[] = {
        blame_usage,
        "",
-       N_("[rev-opts] are documented in git-rev-list(1)"),
+       N_("<rev-opts> are documented in git-rev-list(1)"),
        NULL
 };
 
index dc6f0b266c9cf621486b9dba111c2e7b37d3bc1b..1d150378e91cd47c4cd555bfc858ec0b7ea9d604 100644 (file)
 #include "wt-status.h"
 
 static const char * const builtin_branch_usage[] = {
-       N_("git branch [options] [-r | -a] [--merged | --no-merged]"),
-       N_("git branch [options] [-l] [-f] <branchname> [<start-point>]"),
-       N_("git branch [options] [-r] (-d | -D) <branchname>..."),
-       N_("git branch [options] (-m | -M) [<oldbranch>] <newbranch>"),
+       N_("git branch [<options>] [-r | -a] [--merged | --no-merged]"),
+       N_("git branch [<options>] [-l] [-f] <branch-name> [<start-point>]"),
+       N_("git branch [<options>] [-r] (-d | -D) <branch-name>..."),
+       N_("git branch [<options>] (-m | -M) [<old-branch>] <new-branch>"),
        NULL
 };
 
@@ -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 31b133b357f34e9bc0a63dec5ce2dbceba43e765..df99df4db1ddb058368fe88f07c890d87600e6d9 100644 (file)
@@ -323,8 +323,8 @@ static int batch_objects(struct batch_options *opt)
 }
 
 static const char * const cat_file_usage[] = {
-       N_("git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>"),
-       N_("git cat-file (--batch|--batch-check) < <list_of_objects>"),
+       N_("git cat-file (-t | -s | -e | -p | <type> | --textconv) <object>"),
+       N_("git cat-file (--batch | --batch-check) < <list-of-objects>"),
        NULL
 };
 
index 5600ec3f6165ae04682f30481142452438f856af..21d2bedcc930ab216f2a55ec90ba188b2b66dfce 100644 (file)
@@ -8,8 +8,8 @@ static int all_attrs;
 static int cached_attrs;
 static int stdin_paths;
 static const char * const check_attr_usage[] = {
-N_("git check-attr [-a | --all | attr...] [--] pathname..."),
-N_("git check-attr --stdin [-z] [-a | --all | attr...] < <list-of-paths>"),
+N_("git check-attr [-a | --all | <attr>...] [--] <pathname>..."),
+N_("git check-attr --stdin [-z] [-a | --all | <attr>...] < <list-of-paths>"),
 NULL
 };
 
index 594463a11bcba3cf99748ccdaeb055bd79283ddd..dc8d97c56c60991ec5c1b5cc9eb6e20a76e5e405 100644 (file)
@@ -7,8 +7,8 @@
 
 static int quiet, verbose, stdin_paths, show_non_matching, no_index;
 static const char * const check_ignore_usage[] = {
-"git check-ignore [options] pathname...",
-"git check-ignore [options] --stdin < <list-of-paths>",
+"git check-ignore [<options>] <pathname>...",
+"git check-ignore [<options>] --stdin < <list-of-paths>",
 NULL
 };
 
index 8f4d809bd8c00558b34022cc0c46423a6b19243c..eaaea546d30871ad7442456f7eec4ae849f68374 100644 (file)
@@ -5,7 +5,7 @@
 
 static int use_stdin;
 static const char * const check_mailmap_usage[] = {
-N_("git check-mailmap [options] <contact>..."),
+N_("git check-mailmap [<options>] <contact>..."),
 NULL
 };
 
index 28a7320271a9555356170bfdb06ffb4b07bc9b92..fd915d59841ecc1098e2d8a4356947215377d4da 100644 (file)
@@ -8,7 +8,7 @@
 #include "strbuf.h"
 
 static const char builtin_check_ref_format_usage[] =
-"git check-ref-format [--normalize] [options] <refname>\n"
+"git check-ref-format [--normalize] [<options>] <refname>\n"
 "   or: git check-ref-format --branch <branchname-shorthand>";
 
 /*
index 031780f49e0b3a3e7a8e1aa4904e33858f11542d..9ca2da15836d161d5c28b9919eff0edf4347a446 100644 (file)
@@ -123,7 +123,7 @@ static void checkout_all(const char *prefix, int prefix_length)
 }
 
 static const char * const builtin_checkout_index_usage[] = {
-       N_("git checkout-index [options] [--] [<file>...]"),
+       N_("git checkout-index [<options>] [--] [<file>...]"),
        NULL
 };
 
index 52d6cbb0a84e2693fc53c88ca1fb4cd899b26a91..3e141fc1491949a2dbb47c59d7d156ae6fe4eb47 100644 (file)
@@ -22,8 +22,8 @@
 #include "argv-array.h"
 
 static const char * const checkout_usage[] = {
-       N_("git checkout [options] <branch>"),
-       N_("git checkout [options] [<branch>] -- <file>..."),
+       N_("git checkout [<options>] <branch>"),
+       N_("git checkout [<options>] [<branch>] -- <file>..."),
        NULL,
 };
 
@@ -746,7 +746,7 @@ static void suggest_reattach(struct commit *commit, struct rev_info *revs)
                        _(
                        "If you want to keep them by creating a new branch, "
                        "this may be a good time\nto do so with:\n\n"
-                       " git branch new_branch_name %s\n\n"),
+                       " git branch <new-branch-name> %s\n\n"),
                        find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV));
 }
 
@@ -1127,7 +1127,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
                OPT_BOOL(0, "ignore-skip-worktree-bits", &opts.ignore_skipworktree,
                         N_("do not limit pathspecs to sparse entries only")),
                OPT_HIDDEN_BOOL(0, "guess", &dwim_new_local_branch,
-                               N_("second guess 'git checkout no-such-branch'")),
+                               N_("second guess 'git checkout <no-such-branch>'")),
                OPT_END(),
        };
 
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 316c75d0b342d039696608c18adfabaa3366b0e7..957246723e94ef6ad6df918ec18f8a1e5848a303 100644 (file)
@@ -34,7 +34,7 @@
  *
  */
 static const char * const builtin_clone_usage[] = {
-       N_("git clone [options] [--] <repo> [<dir>]"),
+       N_("git clone [<options>] [--] <repo> [<dir>]"),
        NULL
 };
 
index 75818520e1b74de607620e48d2d3afb131c6e896..449413c8a873ebcfa2ceaccae6b89a3f1245c117 100644 (file)
@@ -6,7 +6,7 @@
 #include "column.h"
 
 static const char * const builtin_column_usage[] = {
-       N_("git column [options]"),
+       N_("git column [<options>]"),
        NULL
 };
 static unsigned int colopts;
index 714638c5d625f370ce87f26b55375f874290ed95..961e467242747dac07aa6f5e619e2d1a50570b06 100644 (file)
 #include "mailmap.h"
 
 static const char * const builtin_commit_usage[] = {
-       N_("git commit [options] [--] <pathspec>..."),
+       N_("git commit [<options>] [--] <pathspec>..."),
        NULL
 };
 
 static const char * const builtin_status_usage[] = {
-       N_("git status [options] [--] <pathspec>..."),
+       N_("git status [<options>] [--] <pathspec>..."),
        NULL
 };
 
@@ -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 15a7bea936d667042cef27f83c86a863df2caa8f..d32c5327e53e14a7af72e4ec91efc1b42a414659 100644 (file)
@@ -5,7 +5,7 @@
 #include "urlmatch.h"
 
 static const char *const builtin_config_usage[] = {
-       N_("git config [options]"),
+       N_("git config [<options>]"),
        NULL
 };
 
index 9103193b4f65dc9e224051fb1e19eda6d9c7ae6a..e00a75b121826e89ee70cbedbfad760dc29640a0 100644 (file)
@@ -14,8 +14,8 @@
 #define MAX_TAGS       (FLAG_BITS - 1)
 
 static const char * const describe_usage[] = {
-       N_("git describe [options] <commit-ish>*"),
-       N_("git describe [options] --dirty"),
+       N_("git describe [<options>] [<commit-ish>...]"),
+       N_("git describe [<options>] --dirty"),
        NULL
 };
 
index 9200069363ff016d167f6885688650158c12e507..8ed2eb8813a442b64c8f43ed23acbdbd1c0dd452 100644 (file)
@@ -11,7 +11,7 @@
 #include "submodule.h"
 
 static const char diff_files_usage[] =
-"git diff-files [-q] [-0/-1/2/3 |-c|--cc] [<common diff options>] [<path>...]"
+"git diff-files [-q] [-0 | -1 | -2 | -3 | -c | --cc] [<common-diff-options>] [<path>...]"
 COMMON_DIFF_OPTIONS_HELP;
 
 int cmd_diff_files(int argc, const char **argv, const char *prefix)
index ce15b23042d8472573b88e0ee9a6032673321ea3..d979824f9395a0cbc8ffffa9cede524589710d43 100644 (file)
@@ -7,7 +7,7 @@
 
 static const char diff_cache_usage[] =
 "git diff-index [-m] [--cached] "
-"[<common diff options>] <tree-ish> [<path>...]"
+"[<common-diff-options>] <tree-ish> [<path>...]"
 COMMON_DIFF_OPTIONS_HELP;
 
 int cmd_diff_index(int argc, const char **argv, const char *prefix)
index 1c4ad6223eb9547666ec21f81f410ef1a459ec92..12b683d0217856a23cb4c3271a173ce1b7bfbe68 100644 (file)
@@ -82,7 +82,7 @@ static int diff_tree_stdin(char *line)
 
 static const char diff_tree_usage[] =
 "git diff-tree [--stdin] [-m] [-c] [--cc] [-s] [-v] [--pretty] [-t] [-r] [--root] "
-"[<common diff options>] <tree-ish> [<tree-ish>] [<path>...]\n"
+"[<common-diff-options>] <tree-ish> [<tree-ish>] [<path>...]\n"
 "  -r            diff recursively\n"
 "  --root        include the initial commit as diff against /dev/null\n"
 COMMON_DIFF_OPTIONS_HELP;
index 1262b405f8212e71d088f4e090b8121fa304699a..4a6b340ab67622a1e0c57a2bd38e2de4f1ad91a5 100644 (file)
@@ -6,7 +6,7 @@
 #include "sha1-array.h"
 
 static const char fetch_pack_usage[] =
-"git fetch-pack [--all] [--stdin] [--quiet|-q] [--keep|-k] [--thin] "
+"git fetch-pack [--all] [--stdin] [--quiet | -q] [--keep | -k] [--thin] "
 "[--include-tag] [--upload-pack=<git-upload-pack>] [--depth=<n>] "
 "[--no-progress] [--diag-url] [-v] [<host>:]<directory> [<refs>...]";
 
index 75a55e590bdc3411e5e4aeee6275fbfff4451904..f9512652cf1389a770bd94fd170d123206e024c5 100644 (file)
@@ -415,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 af7919e51e717923260080f8be3305bbe1b56d39..1d962dc569eaafc8429c4cec815922f382c576b9 100644 (file)
@@ -10,7 +10,7 @@
 #include "gpg-interface.h"
 
 static const char * const fmt_merge_msg_usage[] = {
-       N_("git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]"),
+       N_("git fmt-merge-msg [-m <message>] [--log[=<n>] | --no-log] [--file <file>]"),
        NULL
 };
 
index 008513c2f135b5a77d1642ff88e272a7e2f9f9d5..83f9cf91633a514e9301762fe774ee91be092848 100644 (file)
@@ -1060,7 +1060,7 @@ static int opt_parse_sort(const struct option *opt, const char *arg, int unset)
 }
 
 static char const * const for_each_ref_usage[] = {
-       N_("git for-each-ref [options] [<pattern>]"),
+       N_("git for-each-ref [<options>] [<pattern>]"),
        NULL
 };
 
index a27515aeaa2debabdb14a03d271fe423d13b19d2..0c757862e8cd414c087b27a608281b66c8608a4b 100644 (file)
@@ -600,7 +600,7 @@ static int fsck_cache_tree(struct cache_tree *it)
 }
 
 static char const * const fsck_usage[] = {
-       N_("git fsck [options] [<object>...]"),
+       N_("git fsck [<options>] [<object>...]"),
        NULL
 };
 
index 005adbebea80a83a8d0dbb1de744cb50bf689de6..5c634afc0022c0ea7a8cd8c81727935ad79a6333 100644 (file)
@@ -21,7 +21,7 @@
 #define FAILED_RUN "failed to run %s"
 
 static const char * const builtin_gc_usage[] = {
-       N_("git gc [options]"),
+       N_("git gc [<options>]"),
        NULL
 };
 
index e77f7cf109a02a10b2f38132b1a169b43d3c11d9..335f25d0ad69a41ee2ea1e1e38aecbc2c121cb8c 100644 (file)
@@ -20,7 +20,7 @@
 #include "pathspec.h"
 
 static char const * const grep_usage[] = {
-       N_("git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]"),
+       N_("git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]"),
        NULL
 };
 
index 61583633182da359556fc65795a8eb740167675c..207b90c7b13e103b29305b68aa99d1b9b09342e7 100644 (file)
@@ -79,7 +79,7 @@ static void hash_stdin_paths(const char *type, int no_filters, unsigned flags,
 int cmd_hash_object(int argc, const char **argv, const char *prefix)
 {
        static const char * const hash_object_usage[] = {
-               N_("git hash-object [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin] [--] <file>..."),
+               N_("git hash-object [-t <type>] [-w] [--path=<file> | --no-filters] [--stdin] [--] <file>..."),
                N_("git hash-object  --stdin-paths < <list-of-paths>"),
                NULL
        };
index e78c135e010afa3f9447992ae85a7cc404d0192b..3422e7307998b9da91f85512084aeae515022a60 100644 (file)
@@ -49,7 +49,7 @@ static struct option builtin_help_options[] = {
 };
 
 static const char * const builtin_help_usage[] = {
-       N_("git help [--all] [--guides] [--man|--web|--info] [command]"),
+       N_("git help [--all] [--guides] [--man | --web | --info] [<command>]"),
        NULL
 };
 
@@ -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 9966522b4a97a0d1ae430e581125fbfd1d5609ac..6723d39c3baf3571552a57732e4da16278269edf 100644 (file)
@@ -472,7 +472,7 @@ static int shared_callback(const struct option *opt, const char *arg, int unset)
 }
 
 static const char *const init_db_usage[] = {
-       N_("git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared[=<permissions>]] [directory]"),
+       N_("git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared[=<permissions>]] [<directory>]"),
        NULL
 };
 
index a131992c52f96daeb7c72b447c5ed6929c01a96a..dd8f3fcfc451780b244f6e6fd9e77298f484ad1a 100644 (file)
@@ -39,7 +39,7 @@ static const char *fmt_pretty;
 
 static const char * const builtin_log_usage[] = {
        N_("git log [<options>] [<revision range>] [[--] <path>...]"),
-       N_("git show [options] <object>..."),
+       N_("git show [<options>] <object>..."),
        NULL
 };
 
@@ -1023,7 +1023,7 @@ static const char *set_outdir(const char *prefix, const char *output_directory)
 }
 
 static const char * const builtin_format_patch_usage[] = {
-       N_("git format-patch [options] [<since> | <revision range>]"),
+       N_("git format-patch [<options>] [<since> | <revision-range>]"),
        NULL
 };
 
index 99cee20fb07ce7ed03da230bfa031c277f584fc1..914054d36734ba1b98c924aa640e748dced8b9fa 100644 (file)
@@ -398,7 +398,7 @@ int report_path_error(const char *ps_matched,
 }
 
 static const char * const ls_files_usage[] = {
-       N_("git ls-files [options] [<file>...]"),
+       N_("git ls-files [<options>] [<file>...]"),
        NULL
 };
 
index b2a4b92992748ab52fc6fd3f31041dd88dca54f8..4554dbc8a98c0daaa67c8ea65f5ddf5c48f19383 100644 (file)
@@ -5,7 +5,7 @@
 
 static const char ls_remote_usage[] =
 "git ls-remote [--heads] [--tags]  [-u <exec> | --upload-pack <exec>]\n"
-"                     [-q|--quiet] [--exit-code] [--get-url] [<repository> [<refs>...]]";
+"                     [-q | --quiet] [--exit-code] [--get-url] [<repository> [<refs>...]]";
 
 /*
  * Is there one among the list of patterns that match the tail part
index c8a47c173d011713a57dc744a5f5e5ea5434eefa..999a5250fbe7e6d38a2c8927fa3c37233142ef19 100644 (file)
@@ -1031,7 +1031,7 @@ static int git_mailinfo_config(const char *var, const char *value, void *unused)
 }
 
 static const char mailinfo_usage[] =
-       "git mailinfo [-k|-b] [-m | --message-id] [-u | --encoding=<encoding> | -n] [--scissors | --no-scissors] msg patch < mail >info";
+       "git mailinfo [-k | -b] [-m | --message-id] [-u | --encoding=<encoding> | -n] [--scissors | --no-scissors] <msg> <patch> < mail >info";
 
 int cmd_mailinfo(int argc, const char **argv, const char *prefix)
 {
index fdebef6fa157e920a4560e68c1215665f1e20baf..08a8217890df599100ad0da04dc2cfaabd3a11f6 100644 (file)
@@ -26,8 +26,8 @@ static int show_merge_base(struct commit **rev, int rev_nr, int show_all)
 }
 
 static const char * const merge_base_usage[] = {
-       N_("git merge-base [-a|--all] <commit> <commit>..."),
-       N_("git merge-base [-a|--all] --octopus <commit>..."),
+       N_("git merge-base [-a | --all] <commit> <commit>..."),
+       N_("git merge-base [-a | --all] --octopus <commit>..."),
        N_("git merge-base --independent <commit>..."),
        N_("git merge-base --is-ancestor <commit> <commit>"),
        N_("git merge-base --fork-point <ref> [<commit>]"),
index 232b76857cf4f6dbd9bec12fa12266e1afc90a5c..ea8093f6769e278c4f7871faf405fe1e3f0a7544 100644 (file)
@@ -5,7 +5,7 @@
 #include "parse-options.h"
 
 static const char *const merge_file_usage[] = {
-       N_("git merge-file [options] [-L name1 [-L orig [-L name2]]] file1 orig_file file2"),
+       N_("git merge-file [<options>] [-L <name1> [-L <orig> [-L <name2>]]] <file1> <orig-file> <file2>"),
        NULL
 };
 
@@ -42,7 +42,7 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
                            N_("for conflicts, use this marker size")),
                OPT__QUIET(&quiet, N_("do not warn about conflicts")),
                OPT_CALLBACK('L', NULL, names, N_("name"),
-                            N_("set labels for file1/orig_file/file2"), &label_cb),
+                            N_("set labels for file1/orig-file/file2"), &label_cb),
                OPT_END(),
        };
 
index b416d928492c43e78dc7ac0b3bd1d7a99abfe78b..1a1eafa6fdc2e9dc66c98d3a81b7ee50e44727da 100644 (file)
@@ -75,7 +75,7 @@ int cmd_merge_index(int argc, const char **argv, const char *prefix)
        signal(SIGCHLD, SIG_DFL);
 
        if (argc < 3)
-               usage("git merge-index [-o] [-q] <merge-program> (-a | [--] <filename>*)");
+               usage("git merge-index [-o] [-q] <merge-program> (-a | [--] [<filename>...])");
 
        read_cache();
 
index c638fd5a9a8165c58d46d4edeeb0f3bbe8c0f9a1..3b0f8f96d4168463139d15f1cde655facc73426c 100644 (file)
@@ -42,8 +42,8 @@ struct strategy {
 };
 
 static const char * const builtin_merge_usage[] = {
-       N_("git merge [options] [<commit>...]"),
-       N_("git merge [options] <msg> HEAD <commit>"),
+       N_("git merge [<options>] [<commit>...]"),
+       N_("git merge [<options>] <msg> HEAD <commit>"),
        N_("git merge --abort"),
        NULL
 };
index 563d05ba1af21c9ae73edceba060161969434c76..d1d43168ae79d0157f8adf9dc36a4d2683afe91b 100644 (file)
@@ -12,7 +12,7 @@
 #include "submodule.h"
 
 static const char * const builtin_mv_usage[] = {
-       N_("git mv [options] <source>... <destination>"),
+       N_("git mv [<options>] <source>... <destination>"),
        NULL
 };
 
index 3c8f319be675d14a6ee60d303335190b7bdce9c8..9736d4452f28728b4f970bbf52af502d94edba86 100644 (file)
@@ -252,9 +252,9 @@ static void show_name(const struct object *obj,
 }
 
 static char const * const name_rev_usage[] = {
-       N_("git name-rev [options] <commit>..."),
-       N_("git name-rev [options] --all"),
-       N_("git name-rev [options] --stdin"),
+       N_("git name-rev [<options>] <commit>..."),
+       N_("git name-rev [<options>] --all"),
+       N_("git name-rev [<options>] --stdin"),
        NULL
 };
 
index a9f37d045641236ee910f3eb22be6ac8d04e386a..63f95fc55439060670879fd987033000b8ba3401 100644 (file)
 #include "notes-utils.h"
 
 static const char * const git_notes_usage[] = {
-       N_("git notes [--ref <notes_ref>] [list [<object>]]"),
-       N_("git notes [--ref <notes_ref>] add [-f] [--allow-empty] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
-       N_("git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>"),
-       N_("git notes [--ref <notes_ref>] append [--allow-empty] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
-       N_("git notes [--ref <notes_ref>] edit [--allow-empty] [<object>]"),
-       N_("git notes [--ref <notes_ref>] show [<object>]"),
-       N_("git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>"),
+       N_("git notes [--ref <notes-ref>] [list [<object>]]"),
+       N_("git notes [--ref <notes-ref>] add [-f] [--allow-empty] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
+       N_("git notes [--ref <notes-ref>] copy [-f] <from-object> <to-object>"),
+       N_("git notes [--ref <notes-ref>] append [--allow-empty] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
+       N_("git notes [--ref <notes-ref>] edit [--allow-empty] [<object>]"),
+       N_("git notes [--ref <notes-ref>] show [<object>]"),
+       N_("git notes [--ref <notes-ref>] merge [-v | -q] [-s <strategy>] <notes-ref>"),
        N_("git notes merge --commit [-v | -q]"),
        N_("git notes merge --abort [-v | -q]"),
-       N_("git notes [--ref <notes_ref>] remove [<object>...]"),
-       N_("git notes [--ref <notes_ref>] prune [-n | -v]"),
-       N_("git notes [--ref <notes_ref>] get-ref"),
+       N_("git notes [--ref <notes-ref>] remove [<object>...]"),
+       N_("git notes [--ref <notes-ref>] prune [-n | -v]"),
+       N_("git notes [--ref <notes-ref>] get-ref"),
        NULL
 };
 
@@ -68,7 +68,7 @@ static const char * const git_notes_show_usage[] = {
 };
 
 static const char * const git_notes_merge_usage[] = {
-       N_("git notes merge [<options>] <notes_ref>"),
+       N_("git notes merge [<options>] <notes-ref>"),
        N_("git notes merge --commit [<options>]"),
        N_("git notes merge --abort [<options>]"),
        NULL
@@ -951,7 +951,7 @@ int cmd_notes(int argc, const char **argv, const char *prefix)
        const char *override_notes_ref = NULL;
        struct option options[] = {
                OPT_STRING(0, "ref", &override_notes_ref, N_("notes-ref"),
-                          N_("use notes from <notes_ref>")),
+                          N_("use notes from <notes-ref>")),
                OPT_END()
        };
 
index 649c3aaa93ccdaae21b7884209bd4f28fb558f3e..d0532f66b1d4a479360263bb031e001f4cb42a46 100644 (file)
@@ -11,7 +11,7 @@
 #define BLKSIZE 512
 
 static const char pack_redundant_usage[] =
-"git pack-redundant [ --verbose ] [ --alt-odb ] < --all | <.pack filename> ...>";
+"git pack-redundant [--verbose] [--alt-odb] (--all | <filename.pack>...)";
 
 static int load_all_packs, verbose, alt_odb;
 
index b20b1ec4c117f7529a1a3f2a8151fa0297dffb6a..39f9a55d16736d93b43e6aa16a33634039e55de4 100644 (file)
@@ -3,7 +3,7 @@
 #include "refs.h"
 
 static char const * const pack_refs_usage[] = {
-       N_("git pack-refs [options]"),
+       N_("git pack-refs [<options>]"),
        NULL
 };
 
index f24a2c2bdca81fd2cb6d7b4968e46ad6922a9c9f..7cf900ea0765e334f02df5600f0911d41563a027 100644 (file)
@@ -4,7 +4,7 @@
 #include "parse-options.h"
 
 static const char * const prune_packed_usage[] = {
-       N_("git prune-packed [-n|--dry-run] [-q|--quiet]"),
+       N_("git prune-packed [-n | --dry-run] [-q | --quiet]"),
        NULL
 };
 
index 12f5e69393bc2981dd5ff1433e34bc4932c0ee22..57c138bd7bc972bfa337de4c615cbfffb99ecc71 100644 (file)
@@ -473,13 +473,22 @@ static int option_parse_recurse_submodules(const struct option *opt,
 
 static int git_push_config(const char *k, const char *v, void *cb)
 {
-       struct wt_status *s = cb;
+       int *flags = cb;
        int status;
 
        status = git_gpg_config(k, v, NULL);
        if (status)
                return status;
-       return git_default_config(k, v, s);
+
+       if (!strcmp(k, "push.followtags")) {
+               if (git_config_bool(k, v))
+                       *flags |= TRANSPORT_PUSH_FOLLOW_TAGS;
+               else
+                       *flags &= ~TRANSPORT_PUSH_FOLLOW_TAGS;
+               return 0;
+       }
+
+       return git_default_config(k, v, NULL);
 }
 
 int cmd_push(int argc, const char **argv, const char *prefix)
@@ -518,11 +527,12 @@ int cmd_push(int argc, const char **argv, const char *prefix)
                OPT_BIT(0, "follow-tags", &flags, N_("push missing but relevant tags"),
                        TRANSPORT_PUSH_FOLLOW_TAGS),
                OPT_BIT(0, "signed", &flags, N_("GPG sign the push"), TRANSPORT_PUSH_CERT),
+               OPT_BIT(0, "atomic", &flags, N_("request atomic transaction on remote side"), TRANSPORT_PUSH_ATOMIC),
                OPT_END()
        };
 
        packet_trace_identity("push");
-       git_config(git_push_config, NULL);
+       git_config(git_push_config, &flags);
        argc = parse_options(argc, argv, prefix, options, push_usage, 0);
 
        if (deleterefs && (tags || (flags & (TRANSPORT_PUSH_ALL | TRANSPORT_PUSH_MIRROR))))
index 8266c1fccf0c0b5908c14a726d443dec36a22d58..70e9ce5f96f3e8da78e4b5746580869f9ae65330 100644 (file)
@@ -38,9 +38,11 @@ static int receive_fsck_objects = -1;
 static int transfer_fsck_objects = -1;
 static int receive_unpack_limit = -1;
 static int transfer_unpack_limit = -1;
+static int advertise_atomic_push = 1;
 static int unpack_limit = 100;
 static int report_status;
 static int use_sideband;
+static int use_atomic;
 static int quiet;
 static int prefer_ofs_delta = 1;
 static int auto_update_server_info;
@@ -67,6 +69,7 @@ static const char *NONCE_SLOP = "SLOP";
 static const char *nonce_status;
 static long nonce_stamp_slop;
 static unsigned long nonce_stamp_slop_limit;
+static struct ref_transaction *transaction;
 
 static enum deny_action parse_deny_action(const char *var, const char *value)
 {
@@ -160,6 +163,11 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
                return 0;
        }
 
+       if (strcmp(var, "receive.advertiseatomic") == 0) {
+               advertise_atomic_push = git_config_bool(var, value);
+               return 0;
+       }
+
        return git_default_config(var, value, cb);
 }
 
@@ -175,6 +183,8 @@ static void show_ref(const char *path, const unsigned char *sha1)
 
                strbuf_addstr(&cap,
                              "report-status delete-refs side-band-64k quiet");
+               if (advertise_atomic_push)
+                       strbuf_addstr(&cap, " atomic");
                if (prefer_ofs_delta)
                        strbuf_addstr(&cap, " ofs-delta");
                if (push_cert_nonce)
@@ -733,7 +743,9 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
        return 0;
 }
 
-static const char *update_worktree(unsigned char *sha1)
+static const char *push_to_deploy(unsigned char *sha1,
+                                 struct argv_array *env,
+                                 const char *work_tree)
 {
        const char *update_refresh[] = {
                "update-index", "-q", "--ignore-submodules", "--refresh", NULL
@@ -748,69 +760,87 @@ static const char *update_worktree(unsigned char *sha1)
        const char *read_tree[] = {
                "read-tree", "-u", "-m", NULL, NULL
        };
-       const char *work_tree = git_work_tree_cfg ? git_work_tree_cfg : "..";
-       struct argv_array env = ARGV_ARRAY_INIT;
        struct child_process child = CHILD_PROCESS_INIT;
 
-       if (is_bare_repository())
-               return "denyCurrentBranch = updateInstead needs a worktree";
-
-       argv_array_pushf(&env, "GIT_DIR=%s", absolute_path(get_git_dir()));
-
        child.argv = update_refresh;
-       child.env = env.argv;
+       child.env = env->argv;
        child.dir = work_tree;
        child.no_stdin = 1;
        child.stdout_to_stderr = 1;
        child.git_cmd = 1;
-       if (run_command(&child)) {
-               argv_array_clear(&env);
+       if (run_command(&child))
                return "Up-to-date check failed";
-       }
 
        /* run_command() does not clean up completely; reinitialize */
        child_process_init(&child);
        child.argv = diff_files;
-       child.env = env.argv;
+       child.env = env->argv;
        child.dir = work_tree;
        child.no_stdin = 1;
        child.stdout_to_stderr = 1;
        child.git_cmd = 1;
-       if (run_command(&child)) {
-               argv_array_clear(&env);
+       if (run_command(&child))
                return "Working directory has unstaged changes";
-       }
 
        child_process_init(&child);
        child.argv = diff_index;
-       child.env = env.argv;
+       child.env = env->argv;
        child.no_stdin = 1;
        child.no_stdout = 1;
        child.stdout_to_stderr = 0;
        child.git_cmd = 1;
-       if (run_command(&child)) {
-               argv_array_clear(&env);
+       if (run_command(&child))
                return "Working directory has staged changes";
-       }
 
        read_tree[3] = sha1_to_hex(sha1);
        child_process_init(&child);
        child.argv = read_tree;
-       child.env = env.argv;
+       child.env = env->argv;
        child.dir = work_tree;
        child.no_stdin = 1;
        child.no_stdout = 1;
        child.stdout_to_stderr = 0;
        child.git_cmd = 1;
-       if (run_command(&child)) {
-               argv_array_clear(&env);
+       if (run_command(&child))
                return "Could not update working tree to new HEAD";
-       }
 
-       argv_array_clear(&env);
        return NULL;
 }
 
+static const char *push_to_checkout_hook = "push-to-checkout";
+
+static const char *push_to_checkout(unsigned char *sha1,
+                                   struct argv_array *env,
+                                   const char *work_tree)
+{
+       argv_array_pushf(env, "GIT_WORK_TREE=%s", absolute_path(work_tree));
+       if (run_hook_le(env->argv, push_to_checkout_hook,
+                       sha1_to_hex(sha1), NULL))
+               return "push-to-checkout hook declined";
+       else
+               return NULL;
+}
+
+static const char *update_worktree(unsigned char *sha1)
+{
+       const char *retval;
+       const char *work_tree = git_work_tree_cfg ? git_work_tree_cfg : "..";
+       struct argv_array env = ARGV_ARRAY_INIT;
+
+       if (is_bare_repository())
+               return "denyCurrentBranch = updateInstead needs a worktree";
+
+       argv_array_pushf(&env, "GIT_DIR=%s", absolute_path(get_git_dir()));
+
+       if (!find_hook(push_to_checkout_hook))
+               retval = push_to_deploy(sha1, &env, work_tree);
+       else
+               retval = push_to_checkout(sha1, &env, work_tree);
+
+       argv_array_clear(&env);
+       return retval;
+}
+
 static const char *update(struct command *cmd, struct shallow_info *si)
 {
        const char *name = cmd->ref_name;
@@ -910,6 +940,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
        }
 
        if (is_null_sha1(new_sha1)) {
+               struct strbuf err = STRBUF_INIT;
                if (!parse_object(old_sha1)) {
                        old_sha1 = NULL;
                        if (ref_exists(name)) {
@@ -919,35 +950,35 @@ static const char *update(struct command *cmd, struct shallow_info *si)
                                cmd->did_not_exist = 1;
                        }
                }
-               if (delete_ref(namespaced_name, old_sha1, 0)) {
-                       rp_error("failed to delete %s", name);
+               if (ref_transaction_delete(transaction,
+                                          namespaced_name,
+                                          old_sha1,
+                                          0, "push", &err)) {
+                       rp_error("%s", err.buf);
+                       strbuf_release(&err);
                        return "failed to delete";
                }
+               strbuf_release(&err);
                return NULL; /* good */
        }
        else {
                struct strbuf err = STRBUF_INIT;
-               struct ref_transaction *transaction;
-
                if (shallow_update && si->shallow_ref[cmd->index] &&
                    update_shallow_ref(cmd, si))
                        return "shallow error";
 
-               transaction = ref_transaction_begin(&err);
-               if (!transaction ||
-                   ref_transaction_update(transaction, namespaced_name,
-                                          new_sha1, old_sha1, 0, 1, "push",
-                                          &err) ||
-                   ref_transaction_commit(transaction, &err)) {
-                       ref_transaction_free(transaction);
-
+               if (ref_transaction_update(transaction,
+                                          namespaced_name,
+                                          new_sha1, old_sha1,
+                                          0, "push",
+                                          &err)) {
                        rp_error("%s", err.buf);
                        strbuf_release(&err);
+
                        return "failed to update ref";
                }
-
-               ref_transaction_free(transaction);
                strbuf_release(&err);
+
                return NULL; /* good */
        }
 }
@@ -1131,11 +1162,105 @@ static void reject_updates_to_hidden(struct command *commands)
        }
 }
 
+static int should_process_cmd(struct command *cmd)
+{
+       return !cmd->error_string && !cmd->skip_update;
+}
+
+static void warn_if_skipped_connectivity_check(struct command *commands,
+                                              struct shallow_info *si)
+{
+       struct command *cmd;
+       int checked_connectivity = 1;
+
+       for (cmd = commands; cmd; cmd = cmd->next) {
+               if (should_process_cmd(cmd) && si->shallow_ref[cmd->index]) {
+                       error("BUG: connectivity check has not been run on ref %s",
+                             cmd->ref_name);
+                       checked_connectivity = 0;
+               }
+       }
+       if (!checked_connectivity)
+               die("BUG: connectivity check skipped???");
+}
+
+static void execute_commands_non_atomic(struct command *commands,
+                                       struct shallow_info *si)
+{
+       struct command *cmd;
+       struct strbuf err = STRBUF_INIT;
+
+       for (cmd = commands; cmd; cmd = cmd->next) {
+               if (!should_process_cmd(cmd))
+                       continue;
+
+               transaction = ref_transaction_begin(&err);
+               if (!transaction) {
+                       rp_error("%s", err.buf);
+                       strbuf_reset(&err);
+                       cmd->error_string = "transaction failed to start";
+                       continue;
+               }
+
+               cmd->error_string = update(cmd, si);
+
+               if (!cmd->error_string
+                   && ref_transaction_commit(transaction, &err)) {
+                       rp_error("%s", err.buf);
+                       strbuf_reset(&err);
+                       cmd->error_string = "failed to update ref";
+               }
+               ref_transaction_free(transaction);
+       }
+       strbuf_release(&err);
+}
+
+static void execute_commands_atomic(struct command *commands,
+                                       struct shallow_info *si)
+{
+       struct command *cmd;
+       struct strbuf err = STRBUF_INIT;
+       const char *reported_error = "atomic push failure";
+
+       transaction = ref_transaction_begin(&err);
+       if (!transaction) {
+               rp_error("%s", err.buf);
+               strbuf_reset(&err);
+               reported_error = "transaction failed to start";
+               goto failure;
+       }
+
+       for (cmd = commands; cmd; cmd = cmd->next) {
+               if (!should_process_cmd(cmd))
+                       continue;
+
+               cmd->error_string = update(cmd, si);
+
+               if (cmd->error_string)
+                       goto failure;
+       }
+
+       if (ref_transaction_commit(transaction, &err)) {
+               rp_error("%s", err.buf);
+               reported_error = "atomic transaction failed";
+               goto failure;
+       }
+       goto cleanup;
+
+failure:
+       for (cmd = commands; cmd; cmd = cmd->next)
+               if (!cmd->error_string)
+                       cmd->error_string = reported_error;
+
+cleanup:
+       ref_transaction_free(transaction);
+       strbuf_release(&err);
+}
+
 static void execute_commands(struct command *commands,
                             const char *unpacker_error,
                             struct shallow_info *si)
 {
-       int checked_connectivity;
        struct command *cmd;
        unsigned char sha1[20];
        struct iterate_data data;
@@ -1166,27 +1291,13 @@ static void execute_commands(struct command *commands,
        free(head_name_to_free);
        head_name = head_name_to_free = resolve_refdup("HEAD", 0, sha1, NULL);
 
-       checked_connectivity = 1;
-       for (cmd = commands; cmd; cmd = cmd->next) {
-               if (cmd->error_string)
-                       continue;
-
-               if (cmd->skip_update)
-                       continue;
-
-               cmd->error_string = update(cmd, si);
-               if (shallow_update && !cmd->error_string &&
-                   si->shallow_ref[cmd->index]) {
-                       error("BUG: connectivity check has not been run on ref %s",
-                             cmd->ref_name);
-                       checked_connectivity = 0;
-               }
-       }
+       if (use_atomic)
+               execute_commands_atomic(commands, si);
+       else
+               execute_commands_non_atomic(commands, si);
 
-       if (shallow_update && !checked_connectivity)
-               error("BUG: run 'git fsck' for safety.\n"
-                     "If there are errors, try to remove "
-                     "the reported refs above");
+       if (shallow_update)
+               warn_if_skipped_connectivity_check(commands, si);
 }
 
 static struct command **queue_command(struct command **tail,
@@ -1268,6 +1379,9 @@ static struct command *read_head_info(struct sha1_array *shallow)
                                use_sideband = LARGE_PACKET_MAX;
                        if (parse_feature_request(feature_list, "quiet"))
                                quiet = 1;
+                       if (advertise_atomic_push
+                           && parse_feature_request(feature_list, "atomic"))
+                               use_atomic = 1;
                }
 
                if (!strcmp(line, "push-cert")) {
index 2d85d260ca66deb060b837f86d81a7aad2761b69..8182b648b9c9693ec6f23f6b2100e432bfa794ba 100644 (file)
@@ -8,32 +8,24 @@
 #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;
 
 struct cmd_reflog_expire_cb {
        struct rev_info revs;
-       int dry_run;
        int stalefix;
-       int rewrite;
-       int updateref;
-       int verbose;
        unsigned long expire_total;
        unsigned long expire_unreachable;
        int recno;
 };
 
-struct expire_reflog_cb {
-       FILE *newlog;
+struct expire_reflog_policy_cb {
        enum {
                UE_NORMAL,
                UE_ALWAYS,
@@ -41,14 +33,16 @@ struct expire_reflog_cb {
        } unreachable_expire_kind;
        struct commit_list *mark_list;
        unsigned long mark_limit;
-       struct cmd_reflog_expire_cb *cmd;
-       unsigned char last_kept_sha1[20];
+       struct cmd_reflog_expire_cb cmd;
+       struct commit *tip_commit;
+       struct commit_list *tips;
 };
 
 struct collected_reflog {
        unsigned char sha1[20];
        char reflog[FLEX_ARRAY];
 };
+
 struct collect_reflog_cb {
        struct collected_reflog **e;
        int alloc;
@@ -220,7 +214,7 @@ static int keep_entry(struct commit **it, unsigned char *sha1)
  * the expire_limit and queue them back, so that the caller can call
  * us again to restart the traversal with longer expire_limit.
  */
-static void mark_reachable(struct expire_reflog_cb *cb)
+static void mark_reachable(struct expire_reflog_policy_cb *cb)
 {
        struct commit *commit;
        struct commit_list *pending;
@@ -259,7 +253,7 @@ static void mark_reachable(struct expire_reflog_cb *cb)
        cb->mark_list = leftover;
 }
 
-static int unreachable(struct expire_reflog_cb *cb, struct commit *commit, unsigned char *sha1)
+static int unreachable(struct expire_reflog_policy_cb *cb, struct commit *commit, unsigned char *sha1)
 {
        /*
         * We may or may not have the commit yet - if not, look it
@@ -288,55 +282,39 @@ static int unreachable(struct expire_reflog_cb *cb, struct commit *commit, unsig
        return !(commit->object.flags & REACHABLE);
 }
 
-static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
-               const char *email, unsigned long timestamp, int tz,
-               const char *message, void *cb_data)
+/*
+ * Return true iff the specified reflog entry should be expired.
+ */
+static int should_expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
+                                   const char *email, unsigned long timestamp, int tz,
+                                   const char *message, void *cb_data)
 {
-       struct expire_reflog_cb *cb = cb_data;
+       struct expire_reflog_policy_cb *cb = cb_data;
        struct commit *old, *new;
 
-       if (timestamp < cb->cmd->expire_total)
-               goto prune;
-
-       if (cb->cmd->rewrite)
-               osha1 = cb->last_kept_sha1;
+       if (timestamp < cb->cmd.expire_total)
+               return 1;
 
        old = new = NULL;
-       if (cb->cmd->stalefix &&
+       if (cb->cmd.stalefix &&
            (!keep_entry(&old, osha1) || !keep_entry(&new, nsha1)))
-               goto prune;
+               return 1;
 
-       if (timestamp < cb->cmd->expire_unreachable) {
+       if (timestamp < cb->cmd.expire_unreachable) {
                if (cb->unreachable_expire_kind == UE_ALWAYS)
-                       goto prune;
+                       return 1;
                if (unreachable(cb, old, osha1) || unreachable(cb, new, nsha1))
-                       goto prune;
+                       return 1;
        }
 
-       if (cb->cmd->recno && --(cb->cmd->recno) == 0)
-               goto prune;
-
-       if (cb->newlog) {
-               char sign = (tz < 0) ? '-' : '+';
-               int zone = (tz < 0) ? (-tz) : tz;
-               fprintf(cb->newlog, "%s %s %s %lu %c%04d\t%s",
-                       sha1_to_hex(osha1), sha1_to_hex(nsha1),
-                       email, timestamp, sign, zone,
-                       message);
-               hashcpy(cb->last_kept_sha1, nsha1);
-       }
-       if (cb->cmd->verbose)
-               printf("keep %s", message);
-       return 0;
- prune:
-       if (!cb->newlog)
-               printf("would prune %s", message);
-       else if (cb->cmd->verbose)
-               printf("prune %s", message);
+       if (cb->cmd.recno && --(cb->cmd.recno) == 0)
+               return 1;
+
        return 0;
 }
 
-static int push_tip_to_list(const char *refname, const unsigned char *sha1, int flags, void *cb_data)
+static int push_tip_to_list(const char *refname, const unsigned char *sha1,
+                           int flags, void *cb_data)
 {
        struct commit_list **list = cb_data;
        struct commit *tip_commit;
@@ -349,104 +327,56 @@ static int push_tip_to_list(const char *refname, const unsigned char *sha1, int
        return 0;
 }
 
-static int expire_reflog(const char *ref, const unsigned char *sha1, int unused, void *cb_data)
+static void reflog_expiry_prepare(const char *refname,
+                                 const unsigned char *sha1,
+                                 void *cb_data)
 {
-       struct cmd_reflog_expire_cb *cmd = cb_data;
-       struct expire_reflog_cb cb;
-       struct ref_lock *lock;
-       char *log_file, *newlog_path = NULL;
-       struct commit *tip_commit;
-       struct commit_list *tips;
-       int status = 0;
-
-       memset(&cb, 0, sizeof(cb));
-
-       /*
-        * we take the lock for the ref itself to prevent it from
-        * getting updated.
-        */
-       lock = lock_any_ref_for_update(ref, sha1, 0, NULL);
-       if (!lock)
-               return error("cannot lock ref '%s'", ref);
-       log_file = git_pathdup("logs/%s", ref);
-       if (!reflog_exists(ref))
-               goto finish;
-       if (!cmd->dry_run) {
-               newlog_path = git_pathdup("logs/%s.lock", ref);
-               cb.newlog = fopen(newlog_path, "w");
-       }
+       struct expire_reflog_policy_cb *cb = cb_data;
 
-       cb.cmd = cmd;
-
-       if (!cmd->expire_unreachable || !strcmp(ref, "HEAD")) {
-               tip_commit = NULL;
-               cb.unreachable_expire_kind = UE_HEAD;
+       if (!cb->cmd.expire_unreachable || !strcmp(refname, "HEAD")) {
+               cb->tip_commit = NULL;
+               cb->unreachable_expire_kind = UE_HEAD;
        } else {
-               tip_commit = lookup_commit_reference_gently(sha1, 1);
-               if (!tip_commit)
-                       cb.unreachable_expire_kind = UE_ALWAYS;
+               cb->tip_commit = lookup_commit_reference_gently(sha1, 1);
+               if (!cb->tip_commit)
+                       cb->unreachable_expire_kind = UE_ALWAYS;
                else
-                       cb.unreachable_expire_kind = UE_NORMAL;
+                       cb->unreachable_expire_kind = UE_NORMAL;
        }
 
-       if (cmd->expire_unreachable <= cmd->expire_total)
-               cb.unreachable_expire_kind = UE_ALWAYS;
+       if (cb->cmd.expire_unreachable <= cb->cmd.expire_total)
+               cb->unreachable_expire_kind = UE_ALWAYS;
 
-       cb.mark_list = NULL;
-       tips = NULL;
-       if (cb.unreachable_expire_kind != UE_ALWAYS) {
-               if (cb.unreachable_expire_kind == UE_HEAD) {
+       cb->mark_list = NULL;
+       cb->tips = NULL;
+       if (cb->unreachable_expire_kind != UE_ALWAYS) {
+               if (cb->unreachable_expire_kind == UE_HEAD) {
                        struct commit_list *elem;
-                       for_each_ref(push_tip_to_list, &tips);
-                       for (elem = tips; elem; elem = elem->next)
-                               commit_list_insert(elem->item, &cb.mark_list);
+                       for_each_ref(push_tip_to_list, &cb->tips);
+                       for (elem = cb->tips; elem; elem = elem->next)
+                               commit_list_insert(elem->item, &cb->mark_list);
                } else {
-                       commit_list_insert(tip_commit, &cb.mark_list);
+                       commit_list_insert(cb->tip_commit, &cb->mark_list);
                }
-               cb.mark_limit = cmd->expire_total;
-               mark_reachable(&cb);
+               cb->mark_limit = cb->cmd.expire_total;
+               mark_reachable(cb);
        }
+}
 
-       for_each_reflog_ent(ref, expire_reflog_ent, &cb);
+static void reflog_expiry_cleanup(void *cb_data)
+{
+       struct expire_reflog_policy_cb *cb = cb_data;
 
-       if (cb.unreachable_expire_kind != UE_ALWAYS) {
-               if (cb.unreachable_expire_kind == UE_HEAD) {
+       if (cb->unreachable_expire_kind != UE_ALWAYS) {
+               if (cb->unreachable_expire_kind == UE_HEAD) {
                        struct commit_list *elem;
-                       for (elem = tips; elem; elem = elem->next)
+                       for (elem = cb->tips; elem; elem = elem->next)
                                clear_commit_marks(elem->item, REACHABLE);
-                       free_commit_list(tips);
+                       free_commit_list(cb->tips);
                } else {
-                       clear_commit_marks(tip_commit, REACHABLE);
+                       clear_commit_marks(cb->tip_commit, REACHABLE);
                }
        }
- finish:
-       if (cb.newlog) {
-               if (fclose(cb.newlog)) {
-                       status |= error("%s: %s", strerror(errno),
-                                       newlog_path);
-                       unlink(newlog_path);
-               } else if (cmd->updateref &&
-                       (write_in_full(lock->lock_fd,
-                               sha1_to_hex(cb.last_kept_sha1), 40) != 40 ||
-                        write_str_in_full(lock->lock_fd, "\n") != 1 ||
-                        close_ref(lock) < 0)) {
-                       status |= error("Couldn't write %s",
-                                       lock->lk->filename.buf);
-                       unlink(newlog_path);
-               } else if (rename(newlog_path, log_file)) {
-                       status |= error("cannot rename %s to %s",
-                                       newlog_path, log_file);
-                       unlink(newlog_path);
-               } else if (cmd->updateref && commit_ref(lock)) {
-                       status |= error("Couldn't set %s", lock->ref_name);
-               } else {
-                       adjust_shared_perm(log_file);
-               }
-       }
-       free(newlog_path);
-       free(log_file);
-       unlock_ref(lock);
-       return status;
 }
 
 static int collect_reflog(const char *ref, const unsigned char *sha1, int unused, void *cb_data)
@@ -590,10 +520,11 @@ static void set_reflog_expiry_param(struct cmd_reflog_expire_cb *cb, int slot, c
 
 static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
 {
-       struct cmd_reflog_expire_cb cb;
+       struct expire_reflog_policy_cb cb;
        unsigned long now = time(NULL);
        int i, status, do_all;
        int explicit_expiry = 0;
+       unsigned int flags = 0;
 
        default_reflog_expire_unreachable = now - 30 * 24 * 3600;
        default_reflog_expire = now - 90 * 24 * 3600;
@@ -603,33 +534,33 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
        do_all = status = 0;
        memset(&cb, 0, sizeof(cb));
 
-       cb.expire_total = default_reflog_expire;
-       cb.expire_unreachable = default_reflog_expire_unreachable;
+       cb.cmd.expire_total = default_reflog_expire;
+       cb.cmd.expire_unreachable = default_reflog_expire_unreachable;
 
        for (i = 1; i < argc; i++) {
                const char *arg = argv[i];
                if (!strcmp(arg, "--dry-run") || !strcmp(arg, "-n"))
-                       cb.dry_run = 1;
+                       flags |= EXPIRE_REFLOGS_DRY_RUN;
                else if (starts_with(arg, "--expire=")) {
-                       if (parse_expiry_date(arg + 9, &cb.expire_total))
+                       if (parse_expiry_date(arg + 9, &cb.cmd.expire_total))
                                die(_("'%s' is not a valid timestamp"), arg);
                        explicit_expiry |= EXPIRE_TOTAL;
                }
                else if (starts_with(arg, "--expire-unreachable=")) {
-                       if (parse_expiry_date(arg + 21, &cb.expire_unreachable))
+                       if (parse_expiry_date(arg + 21, &cb.cmd.expire_unreachable))
                                die(_("'%s' is not a valid timestamp"), arg);
                        explicit_expiry |= EXPIRE_UNREACH;
                }
                else if (!strcmp(arg, "--stale-fix"))
-                       cb.stalefix = 1;
+                       cb.cmd.stalefix = 1;
                else if (!strcmp(arg, "--rewrite"))
-                       cb.rewrite = 1;
+                       flags |= EXPIRE_REFLOGS_REWRITE;
                else if (!strcmp(arg, "--updateref"))
-                       cb.updateref = 1;
+                       flags |= EXPIRE_REFLOGS_UPDATE_REF;
                else if (!strcmp(arg, "--all"))
                        do_all = 1;
                else if (!strcmp(arg, "--verbose"))
-                       cb.verbose = 1;
+                       flags |= EXPIRE_REFLOGS_VERBOSE;
                else if (!strcmp(arg, "--")) {
                        i++;
                        break;
@@ -645,12 +576,12 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
         * even in older repository.  We cannot trust what's reachable
         * from reflog if the repository was pruned with older git.
         */
-       if (cb.stalefix) {
-               init_revisions(&cb.revs, prefix);
-               if (cb.verbose)
+       if (cb.cmd.stalefix) {
+               init_revisions(&cb.cmd.revs, prefix);
+               if (flags & EXPIRE_REFLOGS_VERBOSE)
                        printf("Marking reachable objects...");
-               mark_reachable_objects(&cb.revs, 0, 0, NULL);
-               if (cb.verbose)
+               mark_reachable_objects(&cb.cmd.revs, 0, 0, NULL);
+               if (flags & EXPIRE_REFLOGS_VERBOSE)
                        putchar('\n');
        }
 
@@ -662,8 +593,12 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
                for_each_reflog(collect_reflog, &collected);
                for (i = 0; i < collected.nr; i++) {
                        struct collected_reflog *e = collected.e[i];
-                       set_reflog_expiry_param(&cb, explicit_expiry, e->reflog);
-                       status |= expire_reflog(e->reflog, e->sha1, 0, &cb);
+                       set_reflog_expiry_param(&cb.cmd, explicit_expiry, e->reflog);
+                       status |= reflog_expire(e->reflog, e->sha1, flags,
+                                               reflog_expiry_prepare,
+                                               should_expire_reflog_ent,
+                                               reflog_expiry_cleanup,
+                                               &cb);
                        free(e);
                }
                free(collected.e);
@@ -676,8 +611,12 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
                        status |= error("%s points nowhere!", argv[i]);
                        continue;
                }
-               set_reflog_expiry_param(&cb, explicit_expiry, ref);
-               status |= expire_reflog(ref, sha1, 0, &cb);
+               set_reflog_expiry_param(&cb.cmd, explicit_expiry, ref);
+               status |= reflog_expire(ref, sha1, flags,
+                                       reflog_expiry_prepare,
+                                       should_expire_reflog_ent,
+                                       reflog_expiry_cleanup,
+                                       &cb);
        }
        return status;
 }
@@ -686,29 +625,30 @@ static int count_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
                const char *email, unsigned long timestamp, int tz,
                const char *message, void *cb_data)
 {
-       struct cmd_reflog_expire_cb *cb = cb_data;
-       if (!cb->expire_total || timestamp < cb->expire_total)
-               cb->recno++;
+       struct expire_reflog_policy_cb *cb = cb_data;
+       if (!cb->cmd.expire_total || timestamp < cb->cmd.expire_total)
+               cb->cmd.recno++;
        return 0;
 }
 
 static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
 {
-       struct cmd_reflog_expire_cb cb;
+       struct expire_reflog_policy_cb cb;
        int i, status = 0;
+       unsigned int flags = 0;
 
        memset(&cb, 0, sizeof(cb));
 
        for (i = 1; i < argc; i++) {
                const char *arg = argv[i];
                if (!strcmp(arg, "--dry-run") || !strcmp(arg, "-n"))
-                       cb.dry_run = 1;
+                       flags |= EXPIRE_REFLOGS_DRY_RUN;
                else if (!strcmp(arg, "--rewrite"))
-                       cb.rewrite = 1;
+                       flags |= EXPIRE_REFLOGS_REWRITE;
                else if (!strcmp(arg, "--updateref"))
-                       cb.updateref = 1;
+                       flags |= EXPIRE_REFLOGS_UPDATE_REF;
                else if (!strcmp(arg, "--verbose"))
-                       cb.verbose = 1;
+                       flags |= EXPIRE_REFLOGS_VERBOSE;
                else if (!strcmp(arg, "--")) {
                        i++;
                        break;
@@ -740,15 +680,19 @@ static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
 
                recno = strtoul(spec + 2, &ep, 10);
                if (*ep == '}') {
-                       cb.recno = -recno;
+                       cb.cmd.recno = -recno;
                        for_each_reflog_ent(ref, count_reflog_ent, &cb);
                } else {
-                       cb.expire_total = approxidate(spec + 2);
+                       cb.cmd.expire_total = approxidate(spec + 2);
                        for_each_reflog_ent(ref, count_reflog_ent, &cb);
-                       cb.expire_total = 0;
+                       cb.cmd.expire_total = 0;
                }
 
-               status |= expire_reflog(ref, sha1, 0, &cb);
+               status |= reflog_expire(ref, sha1, flags,
+                                       reflog_expiry_prepare,
+                                       should_expire_reflog_ent,
+                                       reflog_expiry_cleanup,
+                                       &cb);
                free(ref);
        }
        return status;
index b4ff4689770e402675faba2ce400150b4803a360..5d3ab906bc7ef6cc8cc9c65a3b86cf4c1ff443fb 100644 (file)
 
 static const char * const builtin_remote_usage[] = {
        N_("git remote [-v | --verbose]"),
-       N_("git remote add [-t <branch>] [-m <master>] [-f] [--tags|--no-tags] [--mirror=<fetch|push>] <name> <url>"),
+       N_("git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--mirror=<fetch|push>] <name> <url>"),
        N_("git remote rename <old> <new>"),
        N_("git remote remove <name>"),
-       N_("git remote set-head <name> (-a | --auto | -d | --delete |<branch>)"),
+       N_("git remote set-head <name> (-a | --auto | -d | --delete | <branch>)"),
        N_("git remote [-v | --verbose] show [-n] <name>"),
        N_("git remote prune [-n | --dry-run] <name>"),
        N_("git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]"),
index 3f852f35d1e786b2584d435d640ae830a9f34639..28fbc7099a84c7406a71128f2a8d3136c145bf57 100644 (file)
@@ -14,7 +14,7 @@ static int write_bitmaps;
 static char *packdir, *packtmp;
 
 static const char *const git_repack_usage[] = {
-       N_("git repack [options]"),
+       N_("git repack [<options>]"),
        NULL
 };
 
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 98eb8c5404914e4046fdb886866b611351deeacf..7afadd2eadd59d8d3f4b77ad902bc24c94af9ec6 100644 (file)
@@ -9,7 +9,7 @@
 #include "pathspec.h"
 
 static const char * const rerere_usage[] = {
-       N_("git rerere [clear | forget path... | status | remaining | diff | gc]"),
+       N_("git rerere [clear | forget <path>... | status | remaining | diff | gc]"),
        NULL,
 };
 
index 95328b80d930260915ad86a30a21ecd3c1b7d1f4..3626c61da67abbe418e492c7828f6e153f6055d8 100644 (file)
@@ -358,7 +358,7 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
 {
        static int keep_dashdash = 0, stop_at_non_option = 0;
        static char const * const parseopt_usage[] = {
-               N_("git rev-parse --parseopt [options] -- [<args>...]"),
+               N_("git rev-parse --parseopt [<options>] -- [<args>...]"),
                NULL
        };
        static struct option parseopt_opts[] = {
@@ -496,9 +496,9 @@ static void die_no_single_rev(int quiet)
 }
 
 static const char builtin_rev_parse_usage[] =
-N_("git rev-parse --parseopt [options] -- [<args>...]\n"
+N_("git rev-parse --parseopt [<options>] -- [<args>...]\n"
    "   or: git rev-parse --sq-quote [<arg>...]\n"
-   "   or: git rev-parse [options] [<arg>...]\n"
+   "   or: git rev-parse [<options>] [<arg>...]\n"
    "\n"
    "Run \"git rev-parse --parseopt -h\" for more information on the first usage.");
 
index f9ed5bd5d03675931609f533e92da3b0a82f0f46..56a2c366698f838146bcf62d7b2c7a8a115287e1 100644 (file)
  */
 
 static const char * const revert_usage[] = {
-       N_("git revert [options] <commit-ish>..."),
+       N_("git revert [<options>] <commit-ish>..."),
        N_("git revert <subcommand>"),
        NULL
 };
 
 static const char * const cherry_pick_usage[] = {
-       N_("git cherry-pick [options] <commit-ish>..."),
+       N_("git cherry-pick [<options>] <commit-ish>..."),
        N_("git cherry-pick <subcommand>"),
        NULL
 };
index d8a9c86dd135e62583f4aeeb3885012da385960a..3304bff42a2fb91f66b9bbca1117746eaa22352a 100644 (file)
@@ -14,7 +14,7 @@
 #include "pathspec.h"
 
 static const char * const builtin_rm_usage[] = {
-       N_("git rm [options] [--] <file>..."),
+       N_("git rm [<options>] [--] <file>..."),
        NULL
 };
 
index b564a778455c352379127c3f06349e0ebbc81c98..b961e5ae7856626ebc063e94bfeee75383d27aeb 100644 (file)
@@ -13,7 +13,7 @@
 #include "sha1-array.h"
 
 static const char send_pack_usage[] =
-"git send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n"
+"git send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [--atomic] [<host>:]<directory> [<ref>...]\n"
 "  --all and explicit <ref> specification are mutually exclusive.";
 
 static struct send_pack_args args;
@@ -170,6 +170,10 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
                                args.use_thin_pack = 1;
                                continue;
                        }
+                       if (!strcmp(arg, "--atomic")) {
+                               args.atomic = 1;
+                               continue;
+                       }
                        if (!strcmp(arg, "--stateless-rpc")) {
                                args.stateless_rpc = 1;
                                continue;
index 4b7e53623fc9cf0c86ed0e7e87d4b3357d765d86..c0bab6aaa9755f5a0264601defd0414b0b458e17 100644 (file)
@@ -10,7 +10,7 @@
 #include "parse-options.h"
 
 static char const * const shortlog_usage[] = {
-       N_("git shortlog [<options>] [<revision range>] [[--] [<path>...]]"),
+       N_("git shortlog [<options>] [<revision-range>] [[--] [<path>...]]"),
        NULL
 };
 
index 365228aa8d805bdf86a6eecccdc088068ba000d2..f3fb5fb2bf28019dafcbd2bfbd6b1a024aa6da2f 100644 (file)
@@ -6,11 +6,11 @@
 #include "parse-options.h"
 
 static const char* show_branch_usage[] = {
-    N_("git show-branch [-a|--all] [-r|--remotes] [--topo-order | --date-order]\n"
+    N_("git show-branch [-a | --all] [-r | --remotes] [--topo-order | --date-order]\n"
        "               [--current] [--color[=<when>] | --no-color] [--sparse]\n"
        "               [--more=<n> | --list | --independent | --merge-base]\n"
        "               [--no-name | --sha1-name] [--topics] [(<rev> | <glob>)...]"),
-    N_("git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]"),
+    N_("git show-branch (-g | --reflog)[=<n>[,<base>]] [--list] [<ref>]"),
     NULL
 };
 
index 5ba1f3083890c693f8ce82166fe1cb1f6440b106..afb10309d6365a5fbc88ff1a88e26559b5b5f582 100644 (file)
@@ -7,7 +7,7 @@
 #include "parse-options.h"
 
 static const char * const show_ref_usage[] = {
-       N_("git show-ref [-q|--quiet] [--verify] [--head] [-d|--dereference] [-s|--hash[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [pattern*] "),
+       N_("git show-ref [-q | --quiet] [--verify] [--head] [-d | --dereference] [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [<pattern>...]"),
        N_("git show-ref --exclude-existing[=pattern] < ref-list"),
        NULL
 };
index 29fb3f1c201682674f8a473c235dd2f1f539f287..ce0fde705c0350ad99678541f434df5e07f5a263 100644 (file)
@@ -4,8 +4,8 @@
 #include "parse-options.h"
 
 static const char * const git_symbolic_ref_usage[] = {
-       N_("git symbolic-ref [options] name [ref]"),
-       N_("git symbolic-ref -d [-q] name"),
+       N_("git symbolic-ref [<options>] <name> [<ref>]"),
+       N_("git symbolic-ref -d [-q] <name>"),
        NULL
 };
 
index e633f4efdbb8963449fddb5c3357fa657283430e..6f07ac6b93c3e36a1bc69d43e6e12ca3367b4c34 100644 (file)
@@ -19,9 +19,9 @@
 #include "column.h"
 
 static const char * const git_tag_usage[] = {
-       N_("git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]"),
+       N_("git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] <tagname> [<head>]"),
        N_("git tag -d <tagname>..."),
-       N_("git tag -l [-n[<num>]] [--contains <commit>] [--points-at <object>] "
+       N_("git tag -l [-n[<num>]] [--contains <commit>] [--points-at <object>]"
                "\n\t\t[<pattern>...]"),
        N_("git tag -v <tagname>..."),
        NULL
@@ -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 b0e3dc91055ec7e7579fb5f1964879a99fd71606..587898624c0550749a9a241e2742785f20ec1bd5 100644 (file)
@@ -400,7 +400,7 @@ static void read_index_info(int line_termination)
 }
 
 static const char * const update_index_usage[] = {
-       N_("git update-index [options] [--] [<file>...]"),
+       N_("git update-index [<options>] [--] [<file>...]"),
        NULL
 };
 
index 1993529521c0ef20860795168392d1dd7209c991..3d79a46b036fa7bea29bbc0941442b5dd92f648c 100644 (file)
@@ -6,9 +6,9 @@
 #include "argv-array.h"
 
 static const char * const git_update_ref_usage[] = {
-       N_("git update-ref [options] -d <refname> [<oldval>]"),
-       N_("git update-ref [options]    <refname> <newval> [<oldval>]"),
-       N_("git update-ref [options] --stdin [-z]"),
+       N_("git update-ref [<options>] -d <refname> [<old-val>]"),
+       N_("git update-ref [<options>]    <refname> <new-val> [<old-val>]"),
+       N_("git update-ref [<options>] --stdin [-z]"),
        NULL
 };
 
@@ -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 b0f85042b234a33ec4b69541e0d6570015551536..ec0c4e3d836f9242a8e34dd7fffa5ddfb835907b 100644 (file)
@@ -14,7 +14,7 @@
 #include "gpg-interface.h"
 
 static const char * const verify_commit_usage[] = {
-               N_("git verify-commit [-v|--verbose] <commit>..."),
+               N_("git verify-commit [-v | --verbose] <commit>..."),
                NULL
 };
 
index 7747537beb72aba52377a13b9b3d61829f3a2fa8..c94e156932c0c8e0ba0c2dc302043c0f3ec0336d 100644 (file)
@@ -51,7 +51,7 @@ static int verify_one_pack(const char *path, unsigned int flags)
 }
 
 static const char * const verify_pack_usage[] = {
-       N_("git verify-pack [-v|--verbose] [-s|--stat-only] <pack>..."),
+       N_("git verify-pack [-v | --verbose] [-s | --stat-only] <pack>..."),
        NULL
 };
 
index 9cdf332333b95b3ab2ea6e133f345105bd67d019..53c68fce3ac182db907224d12d89659469f4b9d6 100644 (file)
@@ -14,7 +14,7 @@
 #include "gpg-interface.h"
 
 static const char * const verify_tag_usage[] = {
-               N_("git verify-tag [-v|--verbose] <tag>..."),
+               N_("git verify-tag [-v | --verbose] <tag>..."),
                NULL
 };
 
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 4d02efc905456e61ce841ec1db2cc19491346257..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;
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 5cc1e7ec9ee80965d1669e0f96dfeab03f3b0798..9f189cb054266cd8f8c084853afbb678ca56c9e9 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -254,7 +254,6 @@ extern int for_each_commit_graft(each_commit_graft_fn, void *);
 extern int is_repository_shallow(void);
 extern struct commit_list *get_shallow_commits(struct object_array *heads,
                int depth, int shallow_flag, int not_shallow_flag);
-extern void check_shallow_file_for_update(void);
 extern void set_alternate_shallow_file(const char *path, int override);
 extern int write_shallow_commits(struct strbuf *out, int use_pack_protocol,
                                 const struct sha1_array *extra);
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 ce0e1214234244236a407e9f3004e619d26c54a8..6090211fe9fad7fb3a2392e399976bc3ea528a4e 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -739,6 +739,7 @@ struct child_process *git_connect(int fd[2], const char *url,
 
                                free(hostandport);
                                free(path);
+                               free(conn);
                                return NULL;
                        } else {
                                ssh = getenv("GIT_SSH_COMMAND");
index b8929084d079ef29987f7074dfb926f923b7697e..931eac29ad73e84abaf87bf1d7a39f56b9a25b34 100644 (file)
@@ -1302,7 +1302,7 @@ _git_gitk ()
 }
 
 __git_match_ctag() {
-       awk "/^${1////\\/}/ { print \$1 }" "$2"
+       awk "/^${1//\//\\/}/ { print \$1 }" "$2"
 }
 
 _git_grep ()
@@ -1422,7 +1422,7 @@ __git_log_gitk_options="
 # Options that go well for log and shortlog (not gitk)
 __git_log_shortlog_options="
        --author= --committer= --grep=
-       --all-match
+       --all-match --invert-grep
 "
 
 __git_log_pretty_formats="oneline short medium full fuller email raw format:"
@@ -2186,6 +2186,7 @@ _git_config ()
                pull.octopus
                pull.twohead
                push.default
+               push.followTags
                rebase.autosquash
                rebase.stat
                receive.autogc
index d435514cbe29aa01d9cebadb947a6c6c8a1e2527..925d3f40247d7f41d709b4e6b3eaabaf646572b6 100644 (file)
@@ -118,7 +118,7 @@ static int lookup_credential(const char *fn, struct credential *c)
 int main(int argc, char **argv)
 {
        const char * const usage[] = {
-               "git credential-store [options] <action>",
+               "git credential-store [<options>] <action>",
                NULL
        };
        const char *op;
index c3edd960ec5bf686b66fa55dcfea712e455fe772..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,25 +53,27 @@ 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;
-
-static int hostname_lookup_done;
+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(void);
+static void lookup_hostname(struct hostinfo *hi);
 
-static const char *get_canon_hostname(void)
+static const char *get_canon_hostname(struct hostinfo *hi)
 {
-       lookup_hostname();
-       return canon_hostname;
+       lookup_hostname(hi);
+       return hi->canon_hostname.buf;
 }
 
-static const char *get_ip_address(void)
+static const char *get_ip_address(struct hostinfo *hi)
 {
-       lookup_hostname();
-       return ip_address;
+       lookup_hostname(hi);
+       return hi->ip_address.buf;
 }
 
 static void logreport(int priority, const char *err, va_list params)
@@ -122,38 +121,34 @@ static void NORETURN daemon_die(const char *err, va_list params)
        exit(1);
 }
 
-static void strbuf_addstr_or_null(struct strbuf *sb, const char *s)
-{
-       if (s)
-               strbuf_addstr(sb, s);
-}
-
 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_addstr_or_null(sb, hostname);
+               strbuf_addbuf(sb, &hi->hostname);
                return 1;
        case 'C':
                if (placeholder[1] == 'H') {
-                       strbuf_addstr_or_null(sb, get_canon_hostname());
+                       strbuf_addstr(sb, get_canon_hostname(hi));
                        return 2;
                }
                break;
        case 'I':
                if (placeholder[1] == 'P') {
-                       strbuf_addstr_or_null(sb, get_ip_address());
+                       strbuf_addstr(sb, get_ip_address(hi));
                        return 2;
                }
                break;
        case 'P':
-               strbuf_addstr_or_null(sb, tcp_port);
+               strbuf_addbuf(sb, &hi->tcp_port);
                return 1;
        case 'D':
                strbuf_addstr(sb, context->directory);
@@ -162,7 +157,7 @@ static size_t expand_path(struct strbuf *sb, const char *placeholder, void *ctx)
        return 0;
 }
 
-static const char *path_ok(const char *directory)
+static const char *path_ok(const char *directory, struct hostinfo *hi)
 {
        static char rpath[PATH_MAX];
        static char interp_path[PATH_MAX];
@@ -198,11 +193,12 @@ 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 expand_path_context context;
 
                context.directory = directory;
+               context.hostinfo = hi;
 
                if (*dir != '/') {
                        /* Allow only absolute */
@@ -292,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;
@@ -301,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(get_canon_hostname());
-       *arg++ = STRARG(get_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;
@@ -354,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;
@@ -368,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");
 
        /*
@@ -404,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;
 
        /*
@@ -542,7 +538,7 @@ static void parse_host_and_port(char *hostport, char **host,
  * trailing and leading dots, which means that the client cannot escape
  * our base path via ".." traversal.
  */
-static void sanitize_client_strbuf(struct strbuf *out, const char *in)
+static void sanitize_client(struct strbuf *out, const char *in)
 {
        for (; *in; in++) {
                if (*in == '/')
@@ -556,36 +552,27 @@ static void sanitize_client_strbuf(struct strbuf *out, const char *in)
                strbuf_setlen(out, out->len - 1);
 }
 
-static char *sanitize_client(const char *in)
-{
-       struct strbuf out = STRBUF_INIT;
-       sanitize_client_strbuf(&out, in);
-       return strbuf_detach(&out, NULL);
-}
-
 /*
  * Like sanitize_client, but we also perform any canonicalization
  * to make life easier on the admin.
  */
-static char *canonicalize_client(const char *in)
+static void canonicalize_client(struct strbuf *out, const char *in)
 {
-       struct strbuf out = STRBUF_INIT;
-       sanitize_client_strbuf(&out, in);
-       strbuf_tolower(&out);
-       return strbuf_detach(&out, NULL);
+       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;
@@ -594,13 +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 = sanitize_client(port);
-                               }
-                               free(hostname);
-                               hostname = canonicalize_client(host);
-                               hostname_lookup_done = 0;
+                               if (port)
+                                       sanitize_client(&hi->tcp_port, port);
+                               canonicalize_client(&hi->hostname, host);
+                               hi->hostname_lookup_done = 0;
                        }
 
                        /* On to the next one */
@@ -614,9 +598,9 @@ static void parse_host_arg(char *extra_args, int buflen)
 /*
  * Locate canonical hostname and its IP address.
  */
-static void lookup_hostname(void)
+static void lookup_hostname(struct hostinfo *hi)
 {
-       if (!hostname_lookup_done && hostname) {
+       if (!hi->hostname_lookup_done && hi->hostname.len) {
 #ifndef NO_IPV6
                struct addrinfo hints;
                struct addrinfo *ai;
@@ -626,19 +610,20 @@ static void lookup_hostname(void)
                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 = ai->ai_canonname ?
-                               sanitize_client(ai->ai_canonname) :
-                               xstrdup(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);
                }
@@ -648,7 +633,7 @@ static void lookup_hostname(void)
                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);
@@ -659,22 +644,39 @@ static void lookup_hostname(void)
                        inet_ntop(hent->h_addrtype, &sa.sin_addr,
                                  addrbuf, sizeof(addrbuf));
 
-                       free(canon_hostname);
-                       canon_hostname = sanitize_client(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
-               hostname_lookup_done = 1;
+               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);
@@ -693,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]);
@@ -713,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);
 
        }
index 77fb2ff368d79647dcb4bab6f5bd21bb4a642159..e78ca107b3d66d7e537c86eb10dc7503be8681b9 100644 (file)
@@ -1717,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);
@@ -1757,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 7671d09d04bb87541b11209b5cdbddbb9e4e59b8..33696a40b8a11262d090a2eec4dfdce0fed6af0f 100644 (file)
--- a/gettext.h
+++ b/gettext.h
@@ -63,6 +63,32 @@ const char *Q_(const char *msgid, const char *plu, unsigned long n)
 }
 
 /* Mark msgid for translation but do not translate it. */
+#if !USE_PARENS_AROUND_GETTEXT_N
 #define N_(msgid) msgid
+#else
+/*
+ * Strictly speaking, this will lead to invalid C when
+ * used this way:
+ *     static const char s[] = N_("FOO");
+ * which will expand to
+ *     static const char s[] = ("FOO");
+ * and in valid C, the initializer on the right hand side must
+ * be without the parentheses.  But many compilers do accept it
+ * as a language extension and it will allow us to catch mistakes
+ * like:
+ *     static const char *msgs[] = {
+ *             N_("one")
+ *             N_("two"),
+ *             N_("three"),
+ *             NULL
+ *     };
+ * (notice the missing comma on one of the lines) by forcing
+ * a compilation error, because parenthesised ("one") ("two")
+ * will not get silently turned into ("onetwo").
+ */
+#define N_(msgid) (msgid)
+#endif
+
+const char *get_preferred_languages(void);
 
 #endif
index 2fc07acb0f242154fec868207cfd77f448929200..ae3fec22c48a296cdc1962def9030aa5bb7ce68a 100755 (executable)
@@ -127,7 +127,7 @@ bisect_start() {
                if test "z$mode" != "z--no-checkout"
                then
                        git checkout "$start_head" -- ||
-                       die "$(eval_gettext "Checking out '\$start_head' failed. Try 'git bisect reset <validbranch>'.")"
+                       die "$(eval_gettext "Checking out '\$start_head' failed. Try 'git bisect reset <valid-branch>'.")"
                fi
        else
                # Get rev from where we start.
index 35b3fe0b3be6097bc98516a0469b25c1338fdbca..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 */
@@ -872,4 +875,12 @@ struct tm *git_gmtime_r(const time_t *, struct tm *);
 #define gmtime_r git_gmtime_r
 #endif
 
+#if !defined(USE_PARENS_AROUND_GETTEXT_N) && defined(__GNUC__)
+#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 ff132b2117c5ed7529d6b1237a9f26069cb4ef8a..549022e97c83e4a2f1898dc005331e5bca3f0ded 100755 (executable)
--- a/git-p4.py
+++ b/git-p4.py
@@ -1442,7 +1442,7 @@ def applyCommit(self, id):
             print "  " + self.clientPath
             print
             print "To submit, use \"p4 submit\" to write a new description,"
-            print "or \"p4 submit -i %s\" to use the one prepared by" \
+            print "or \"p4 submit -i <%s\" to use the one prepared by" \
                   " \"git p4\"." % fileName
             print "You can delete the file \"%s\" when finished." % fileName
 
@@ -1915,7 +1915,10 @@ def __init__(self):
                 optparse.make_option("--keep-path", dest="keepRepoPath", action='store_true',
                                      help="Keep entire BRANCH/DIR/SUBDIR prefix during import"),
                 optparse.make_option("--use-client-spec", dest="useClientSpec", action='store_true',
-                                     help="Only sync files that are included in the Perforce Client Spec")
+                                     help="Only sync files that are included in the Perforce Client Spec"),
+                optparse.make_option("-/", dest="cloneExclude",
+                                     action="append", type="string",
+                                     help="exclude depot path"),
         ]
         self.description = """Imports from Perforce into a git repository.\n
     example:
@@ -1950,6 +1953,12 @@ def __init__(self):
         if gitConfig("git-p4.syncFromOrigin") == "false":
             self.syncWithOrigin = False
 
+    # This is required for the "append" cloneExclude action
+    def ensure_value(self, attr, value):
+        if not hasattr(self, attr) or getattr(self, attr) is None:
+            setattr(self, attr, value)
+        return getattr(self, attr)
+
     # Force a checkpoint in fast-import and wait for it to finish
     def checkpoint(self):
         self.gitStream.write("checkpoint\n\n")
@@ -3101,9 +3110,6 @@ def __init__(self):
             optparse.make_option("--destination", dest="cloneDestination",
                                  action='store', default=None,
                                  help="where to leave result of the clone"),
-            optparse.make_option("-/", dest="cloneExclude",
-                                 action="append", type="string",
-                                 help="exclude depot path"),
             optparse.make_option("--bare", dest="cloneBare",
                                  action="store_true", default=False),
         ]
@@ -3111,12 +3117,6 @@ def __init__(self):
         self.needsGit = False
         self.cloneBare = False
 
-    # This is required for the "append" cloneExclude action
-    def ensure_value(self, attr, value):
-        if not hasattr(self, attr) or getattr(self, attr) is None:
-            setattr(self, attr, value)
-        return getattr(self, attr)
-
     def defaultDestination(self, args):
         ## TODO: use common prefix of args?
         depotPath = args[0]
index a18a7959ed81e9385b490e475bb87bd6875eb0e1..e1e9b1460ced5f660b32796890df7336bc3d01af 100755 (executable)
@@ -762,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 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 6a255839e7163020533d89fc41280e2479eae4a8..42a4ee57843f569fb754121f01bb8c46feee2fd3 100644 (file)
--- a/git.c
+++ b/git.c
@@ -6,7 +6,7 @@
 const char git_usage_string[] =
        "git [--version] [--help] [-C <path>] [-c name=value]\n"
        "           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n"
-       "           [-p|--paginate|--no-pager] [--no-replace-objects] [--bare]\n"
+       "           [-p | --paginate | --no-pager] [--no-replace-objects] [--bare]\n"
        "           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
        "           <command> [<args>]";
 
diff --git a/http.c b/http.c
index 67986200655f88f5545e3df3669c2f4bbe688247..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;
@@ -117,6 +120,37 @@ size_t fwrite_null(char *ptr, size_t eltsize, size_t nmemb, void *strbuf)
        return eltsize * nmemb;
 }
 
+static void closedown_active_slot(struct active_request_slot *slot)
+{
+       active_requests--;
+       slot->in_use = 0;
+}
+
+static void finish_active_slot(struct active_request_slot *slot)
+{
+       closedown_active_slot(slot);
+       curl_easy_getinfo(slot->curl, CURLINFO_HTTP_CODE, &slot->http_code);
+
+       if (slot->finished != NULL)
+               (*slot->finished) = 1;
+
+       /* Store slot results so they can be read after the slot is reused */
+       if (slot->results != NULL) {
+               slot->results->curl_result = slot->curl_result;
+               slot->results->http_code = slot->http_code;
+#if LIBCURL_VERSION_NUM >= 0x070a08
+               curl_easy_getinfo(slot->curl, CURLINFO_HTTPAUTH_AVAIL,
+                                 &slot->results->auth_avail);
+#else
+               slot->results->auth_avail = 0;
+#endif
+       }
+
+       /* Run callback if appropriate */
+       if (slot->callback_func != NULL)
+               slot->callback_func(slot->callback_data);
+}
+
 #ifdef USE_CURL_MULTI
 static void process_curl_messages(void)
 {
@@ -372,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);
@@ -518,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)
@@ -736,12 +775,6 @@ void run_active_slot(struct active_request_slot *slot)
 #endif
 }
 
-static void closedown_active_slot(struct active_request_slot *slot)
-{
-       active_requests--;
-       slot->in_use = 0;
-}
-
 static void release_active_slot(struct active_request_slot *slot)
 {
        closedown_active_slot(slot);
@@ -758,31 +791,6 @@ static void release_active_slot(struct active_request_slot *slot)
 #endif
 }
 
-void finish_active_slot(struct active_request_slot *slot)
-{
-       closedown_active_slot(slot);
-       curl_easy_getinfo(slot->curl, CURLINFO_HTTP_CODE, &slot->http_code);
-
-       if (slot->finished != NULL)
-               (*slot->finished) = 1;
-
-       /* Store slot results so they can be read after the slot is reused */
-       if (slot->results != NULL) {
-               slot->results->curl_result = slot->curl_result;
-               slot->results->http_code = slot->http_code;
-#if LIBCURL_VERSION_NUM >= 0x070a08
-               curl_easy_getinfo(slot->curl, CURLINFO_HTTPAUTH_AVAIL,
-                                 &slot->results->auth_avail);
-#else
-               slot->results->auth_avail = 0;
-#endif
-       }
-
-       /* Run callback if appropriate */
-       if (slot->callback_func != NULL)
-               slot->callback_func(slot->callback_data);
-}
-
 void finish_all_active_slots(void)
 {
        struct active_request_slot *slot = active_queue_head;
@@ -845,7 +853,7 @@ char *get_remote_object_url(const char *url, const char *hex,
        return strbuf_detach(&buf, NULL);
 }
 
-int handle_curl_result(struct slot_results *results)
+static int handle_curl_result(struct slot_results *results)
 {
        /*
         * If we see a failing http code with CURLE_OK, we have turned off
@@ -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");
diff --git a/http.h b/http.h
index 473179b14d5648635853af4c5bf425116c32b6fe..49afe39279d02785f3567aad2fec55c623a53d5f 100644 (file)
--- a/http.h
+++ b/http.h
@@ -85,9 +85,7 @@ extern curlioerr ioctl_buffer(CURL *handle, int cmd, void *clientp);
 extern struct active_request_slot *get_active_slot(void);
 extern int start_active_slot(struct active_request_slot *slot);
 extern void run_active_slot(struct active_request_slot *slot);
-extern void finish_active_slot(struct active_request_slot *slot);
 extern void finish_all_active_slots(void);
-extern int handle_curl_result(struct slot_results *results);
 
 /*
  * This will run one slot to completion in a blocking manner, similar to how
index b7864ad5869eb076e778c352e2f64666dc77a525..a490efea07519edb006e515c8a0fdf60241e546d 100644 (file)
@@ -237,7 +237,7 @@ static void diff_ranges_release(struct diff_ranges *diff)
        range_set_release(&diff->target);
 }
 
-void line_log_data_init(struct line_log_data *r)
+static void line_log_data_init(struct line_log_data *r)
 {
        memset(r, 0, sizeof(struct line_log_data));
        range_set_init(&r->ranges, 0);
index a9212d84e492304b4e57da1e0327189b3b6434ed..7a5c24e2df40c09274077928574bc91349d475d1 100644 (file)
@@ -54,8 +54,6 @@ struct line_log_data {
        struct diff_ranges diff;
 };
 
-extern void line_log_data_init(struct line_log_data *r);
-
 extern void line_log_init(struct rev_info *rev, const char *prefix, struct string_list *args);
 
 extern int line_log_filter(struct rev_info *rev);
index 53bb52659b41c5a2fddc61af05a3a2ef90528b15..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,16 +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, 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);
-               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);
index 6a818419ca46f8d66adbeb0027da49e6bab1bfa3..365f9d92ed8b57c1e766a126b6e6571009eedde5 100644 (file)
@@ -60,7 +60,7 @@ static struct bitmap_index {
        struct ewah_bitmap *blobs;
        struct ewah_bitmap *tags;
 
-       /* Map from SHA1 -> `stored_bitmap` for all the bitmapped comits */
+       /* Map from SHA1 -> `stored_bitmap` for all the bitmapped commits */
        khash_sha1 *bitmaps;
 
        /* Number of bitmapped commits */
@@ -252,6 +252,20 @@ static int load_bitmap_entries_v1(struct bitmap_index *index)
        return 0;
 }
 
+static char *pack_bitmap_filename(struct packed_git *p)
+{
+       char *idx_name;
+       int len;
+
+       len = strlen(p->pack_name) - strlen(".pack");
+       idx_name = xmalloc(len + strlen(".bitmap") + 1);
+
+       memcpy(idx_name, p->pack_name, len);
+       memcpy(idx_name + len, ".bitmap", strlen(".bitmap") + 1);
+
+       return idx_name;
+}
+
 static int open_pack_bitmap_1(struct packed_git *packfile)
 {
        int fd;
@@ -322,20 +336,6 @@ static int load_pack_bitmap(void)
        return -1;
 }
 
-char *pack_bitmap_filename(struct packed_git *p)
-{
-       char *idx_name;
-       int len;
-
-       len = strlen(p->pack_name) - strlen(".pack");
-       idx_name = xmalloc(len + strlen(".bitmap") + 1);
-
-       memcpy(idx_name, p->pack_name, len);
-       memcpy(idx_name + len, ".bitmap", strlen(".bitmap") + 1);
-
-       return idx_name;
-}
-
 static int open_pack_bitmap(void)
 {
        struct packed_git *p;
index 487600b18c79be22c4c611fc4c3d29d817f1f304..0adcef77b58cc13822f1b400d5418ec6f8b34421 100644 (file)
@@ -38,7 +38,6 @@ int prepare_bitmap_git(void);
 void count_bitmap_commit_list(uint32_t *commits, uint32_t *trees, uint32_t *blobs, uint32_t *tags);
 void traverse_bitmap_commit_list(show_reachable_fn show_reachable);
 void test_bitmap_walk(struct rev_info *revs);
-char *pack_bitmap_filename(struct packed_git *p);
 int prepare_bitmap_walk(struct rev_info *revs);
 int reuse_partial_packfile_from_bitmap(struct packed_git **packfile, uint32_t *entries, off_t *up_to);
 int rebuild_existing_bitmaps(struct packing_data *mapping, khash_sha1 *reused_bitmaps, int show_progress);
index f24372645b40f81faf75e735e402a1f4c400b2ed..152fb7e9274c779cb66de099878b4de40e5406e4 100644 (file)
@@ -9,10 +9,8 @@ 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;
 
@@ -33,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';
@@ -1579,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';
@@ -2189,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 613055a3f5f794d02644e32dbaf91f907836b396..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/;
@@ -608,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 32e2f19ea41b2dfed735cf1fa5e1fa49f3fed915..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;
index 8181eebbfcd0080540bc580416336436ced98297..75406390c6fdabf74e74d4c2a90e6ac92afc4ccc 100644 (file)
--- a/prompt.c
+++ b/prompt.c
@@ -73,8 +73,3 @@ char *git_prompt(const char *prompt, int flags)
        }
        return r;
 }
-
-char *git_getpass(const char *prompt)
-{
-       return git_prompt(prompt, PROMPT_ASKPASS);
-}
index 04f321a781d37af780b906c2a4564c08eea830c8..e04cced030ca4df6d729c2132ca4671b959952b4 100644 (file)
--- a/prompt.h
+++ b/prompt.h
@@ -5,6 +5,5 @@
 #define PROMPT_ECHO    (1<<1)
 
 char *git_prompt(const char *prompt, int flags);
-char *git_getpass(const char *prompt);
 
 #endif /* PROMPT_H */
diff --git a/refs.c b/refs.c
index 9edf18b04e7e29b12fa3808aab2239efcc404dca..e23542b3869b38e47f59f102d28648d30d506574 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -6,6 +6,14 @@
 #include "dir.h"
 #include "string-list.h"
 
+struct ref_lock {
+       char *ref_name;
+       char *orig_ref_name;
+       struct lock_file *lk;
+       unsigned char old_sha1[20];
+       int lock_fd;
+};
+
 /*
  * How to handle various characters in refnames:
  * 0: An acceptable character for refs
@@ -26,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
@@ -2093,6 +2120,16 @@ int refname_match(const char *abbrev_name, const char *full_name)
        return 0;
 }
 
+static void unlock_ref(struct ref_lock *lock)
+{
+       /* Do not free lock->lk -- atexit() still looks at them */
+       if (lock->lk)
+               rollback_lock_file(lock->lk);
+       free(lock->ref_name);
+       free(lock->orig_ref_name);
+       free(lock);
+}
+
 /* This function should make sure errno is meaningful on error */
 static struct ref_lock *verify_lock(struct ref_lock *lock,
        const unsigned char *old_sha1, int mustexist)
@@ -2230,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;
@@ -2239,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));
@@ -2278,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;
@@ -2300,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)) {
@@ -2345,13 +2377,6 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
        return NULL;
 }
 
-struct ref_lock *lock_any_ref_for_update(const char *refname,
-                                        const unsigned char *old_sha1,
-                                        int flags, int *type_p)
-{
-       return lock_ref_sha1_basic(refname, old_sha1, NULL, flags, type_p);
-}
-
 /*
  * Write an entry to the packed-refs file for the specified refname.
  * If peeled is non-NULL, write it as the entry's peeled value.
@@ -2551,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);
@@ -2721,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);
@@ -2865,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);
@@ -2881,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))
@@ -2900,7 +2924,7 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms
        return 1;
 }
 
-int close_ref(struct ref_lock *lock)
+static int close_ref(struct ref_lock *lock)
 {
        if (close_lock_file(lock->lk))
                return -1;
@@ -2908,7 +2932,7 @@ int close_ref(struct ref_lock *lock)
        return 0;
 }
 
-int commit_ref(struct ref_lock *lock)
+static int commit_ref(struct ref_lock *lock)
 {
        if (commit_lock_file(lock->lk))
                return -1;
@@ -2916,16 +2940,6 @@ int commit_ref(struct ref_lock *lock)
        return 0;
 }
 
-void unlock_ref(struct ref_lock *lock)
-{
-       /* Do not free lock->lk -- atexit() still looks at them */
-       if (lock->lk)
-               rollback_lock_file(lock->lk);
-       free(lock->ref_name);
-       free(lock->orig_ref_name);
-       free(lock);
-}
-
 /*
  * copy the reflog message msg to buf, which has been allocated sufficiently
  * large, while cleaning up the whitespaces.  Especially, convert LF to space,
@@ -3002,15 +3016,37 @@ int log_ref_setup(const char *refname, char *logfile, int bufsize)
        return 0;
 }
 
+static int log_ref_write_fd(int fd, const unsigned char *old_sha1,
+                           const unsigned char *new_sha1,
+                           const char *committer, const char *msg)
+{
+       int msglen, written;
+       unsigned maxlen, len;
+       char *logrec;
+
+       msglen = msg ? strlen(msg) : 0;
+       maxlen = strlen(committer) + msglen + 100;
+       logrec = xmalloc(maxlen);
+       len = sprintf(logrec, "%s %s %s\n",
+                     sha1_to_hex(old_sha1),
+                     sha1_to_hex(new_sha1),
+                     committer);
+       if (msglen)
+               len += copy_msg(logrec + len - 1, msg) - 1;
+
+       written = len <= maxlen ? write_in_full(fd, logrec, len) : -1;
+       free(logrec);
+       if (written != len)
+               return -1;
+
+       return 0;
+}
+
 static int log_ref_write(const char *refname, const unsigned char *old_sha1,
                         const unsigned char *new_sha1, const char *msg)
 {
-       int logfd, result, written, oflags = O_APPEND | O_WRONLY;
-       unsigned maxlen, len;
-       int msglen;
+       int logfd, result, oflags = O_APPEND | O_WRONLY;
        char log_file[PATH_MAX];
-       char *logrec;
-       const char *committer;
 
        if (log_all_ref_updates < 0)
                log_all_ref_updates = !is_bare_repository();
@@ -3022,19 +3058,9 @@ static int log_ref_write(const char *refname, const unsigned char *old_sha1,
        logfd = open(log_file, oflags);
        if (logfd < 0)
                return 0;
-       msglen = msg ? strlen(msg) : 0;
-       committer = git_committer_info(0);
-       maxlen = strlen(committer) + msglen + 100;
-       logrec = xmalloc(maxlen);
-       len = sprintf(logrec, "%s %s %s\n",
-                     sha1_to_hex(old_sha1),
-                     sha1_to_hex(new_sha1),
-                     committer);
-       if (msglen)
-               len += copy_msg(logrec + len - 1, msg) - 1;
-       written = len <= maxlen ? write_in_full(logfd, logrec, len) : -1;
-       free(logrec);
-       if (written != len) {
+       result = log_ref_write_fd(logfd, old_sha1, new_sha1,
+                                 git_committer_info(0), msg);
+       if (result) {
                int save_errno = errno;
                close(logfd);
                error("Unable to append to %s", log_file);
@@ -3065,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",
@@ -3542,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;
@@ -3623,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;
@@ -3633,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);
@@ -3644,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;
@@ -3657,75 +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)
 {
-       struct ref_update *update;
-
-       assert(err);
-
-       if (transaction->state != REF_TRANSACTION_OPEN)
-               die("BUG: create called for transaction that is not open");
-
        if (!new_sha1 || is_null_sha1(new_sha1))
-               die("BUG: create ref with null new_sha1");
-
-       if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {
-               strbuf_addf(err, "refusing to create ref with bad name %s",
-                           refname);
-               return -1;
-       }
-
-       update = add_update(transaction, refname);
-
-       hashcpy(update->new_sha1, new_sha1);
-       hashclr(update->old_sha1);
-       update->flags = flags;
-       update->have_old = 1;
-       if (msg)
-               update->msg = xstrdup(msg);
-       return 0;
+               die("BUG: create called without valid new_sha1");
+       return ref_transaction_update(transaction, refname, new_sha1,
+                                     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)
 {
-       struct ref_update *update;
-
-       assert(err);
-
-       if (transaction->state != REF_TRANSACTION_OPEN)
-               die("BUG: delete called for transaction that is not open");
-
-       if (have_old && !old_sha1)
-               die("BUG: have_old is true but old_sha1 is NULL");
+       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);
+}
 
-       update = add_update(transaction, refname);
-       update->flags = flags;
-       update->have_old = have_old;
-       if (have_old) {
-               assert(!is_null_sha1(old_sha1));
-               hashcpy(update->old_sha1, old_sha1);
-       }
-       if (msg)
-               update->msg = xstrdup(msg);
-       return 0;
+int ref_transaction_verify(struct ref_transaction *transaction,
+                          const char *refname,
+                          const unsigned char *old_sha1,
+                          unsigned int flags,
+                          struct strbuf *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";
 
@@ -3801,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
@@ -3825,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);
                }
@@ -4008,3 +4030,141 @@ int ref_is_hidden(const char *refname)
        }
        return 0;
 }
+
+struct expire_reflog_cb {
+       unsigned int flags;
+       reflog_expiry_should_prune_fn *should_prune_fn;
+       void *policy_cb;
+       FILE *newlog;
+       unsigned char last_kept_sha1[20];
+};
+
+static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
+                            const char *email, unsigned long timestamp, int tz,
+                            const char *message, void *cb_data)
+{
+       struct expire_reflog_cb *cb = cb_data;
+       struct expire_reflog_policy_cb *policy_cb = cb->policy_cb;
+
+       if (cb->flags & EXPIRE_REFLOGS_REWRITE)
+               osha1 = cb->last_kept_sha1;
+
+       if ((*cb->should_prune_fn)(osha1, nsha1, email, timestamp, tz,
+                                  message, policy_cb)) {
+               if (!cb->newlog)
+                       printf("would prune %s", message);
+               else if (cb->flags & EXPIRE_REFLOGS_VERBOSE)
+                       printf("prune %s", message);
+       } else {
+               if (cb->newlog) {
+                       fprintf(cb->newlog, "%s %s %s %lu %+05d\t%s",
+                               sha1_to_hex(osha1), sha1_to_hex(nsha1),
+                               email, timestamp, tz, message);
+                       hashcpy(cb->last_kept_sha1, nsha1);
+               }
+               if (cb->flags & EXPIRE_REFLOGS_VERBOSE)
+                       printf("keep %s", message);
+       }
+       return 0;
+}
+
+int reflog_expire(const char *refname, const unsigned char *sha1,
+                unsigned int flags,
+                reflog_expiry_prepare_fn prepare_fn,
+                reflog_expiry_should_prune_fn should_prune_fn,
+                reflog_expiry_cleanup_fn cleanup_fn,
+                void *policy_cb_data)
+{
+       static struct lock_file reflog_lock;
+       struct expire_reflog_cb cb;
+       struct ref_lock *lock;
+       char *log_file;
+       int status = 0;
+       int type;
+
+       memset(&cb, 0, sizeof(cb));
+       cb.flags = flags;
+       cb.policy_cb = policy_cb_data;
+       cb.should_prune_fn = should_prune_fn;
+
+       /*
+        * The reflog file is locked by holding the lock on the
+        * reference itself, plus we might need to update the
+        * reference if --updateref was specified:
+        */
+       lock = lock_ref_sha1_basic(refname, sha1, NULL, 0, &type);
+       if (!lock)
+               return error("cannot lock ref '%s'", refname);
+       if (!reflog_exists(refname)) {
+               unlock_ref(lock);
+               return 0;
+       }
+
+       log_file = git_pathdup("logs/%s", refname);
+       if (!(flags & EXPIRE_REFLOGS_DRY_RUN)) {
+               /*
+                * Even though holding $GIT_DIR/logs/$reflog.lock has
+                * no locking implications, we use the lock_file
+                * machinery here anyway because it does a lot of the
+                * work we need, including cleaning up if the program
+                * exits unexpectedly.
+                */
+               if (hold_lock_file_for_update(&reflog_lock, log_file, 0) < 0) {
+                       struct strbuf err = STRBUF_INIT;
+                       unable_to_lock_message(log_file, errno, &err);
+                       error("%s", err.buf);
+                       strbuf_release(&err);
+                       goto failure;
+               }
+               cb.newlog = fdopen_lock_file(&reflog_lock, "w");
+               if (!cb.newlog) {
+                       error("cannot fdopen %s (%s)",
+                             reflog_lock.filename.buf, strerror(errno));
+                       goto failure;
+               }
+       }
+
+       (*prepare_fn)(refname, sha1, cb.policy_cb);
+       for_each_reflog_ent(refname, expire_reflog_ent, &cb);
+       (*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 (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 ||
+                        close_ref(lock) < 0)) {
+                       status |= error("couldn't write %s",
+                                       lock->lk->filename.buf);
+                       rollback_lock_file(&reflog_lock);
+               } else if (commit_lock_file(&reflog_lock)) {
+                       status |= error("unable to commit reflog '%s' (%s)",
+                                       log_file, strerror(errno));
+               } else if (update && commit_ref(lock)) {
+                       status |= error("couldn't set %s", lock->ref_name);
+               }
+       }
+       free(log_file);
+       unlock_ref(lock);
+       return status;
+
+ failure:
+       rollback_lock_file(&reflog_lock);
+       free(log_file);
+       unlock_ref(lock);
+       return -1;
+}
diff --git a/refs.h b/refs.h
index 405c6572f1135d06b68b6f60543e67343b117227..cf642e6ddc438be77d64797a4dbcf790262a9fed 100644 (file)
--- a/refs.h
+++ b/refs.h
@@ -1,15 +1,6 @@
 #ifndef REFS_H
 #define REFS_H
 
-struct ref_lock {
-       char *ref_name;
-       char *orig_ref_name;
-       struct lock_file *lk;
-       unsigned char old_sha1[20];
-       int lock_fd;
-       int force_write;
-};
-
 /*
  * A ref_transaction represents a collection of ref updates
  * that should succeed or fail together.
@@ -189,31 +180,13 @@ extern int is_branch(const char *refname);
 extern int peel_ref(const char *refname, unsigned char *sha1);
 
 /*
- * Flags controlling lock_any_ref_for_update(), ref_transaction_update(),
- * ref_transaction_create(), etc.
+ * 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
-/*
- * This function sets errno to something meaningful on failure.
- */
-extern struct ref_lock *lock_any_ref_for_update(const char *refname,
-                                               const unsigned char *old_sha1,
-                                               int flags, int *type_p);
-
-/** Close the file descriptor owned by a lock and return the status */
-extern int close_ref(struct ref_lock *lock);
-
-/** Close and commit the ref locked by the lock */
-extern int commit_ref(struct ref_lock *lock);
-
-/** Release any lock taken but not written. **/
-extern void unlock_ref(struct ref_lock *lock);
 
 /*
  * Setup reflog before using. Set errno to something meaningful on failure.
@@ -282,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 zeros 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);
 
 /*
@@ -353,12 +364,65 @@ 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 *);
 
+enum expire_reflog_flags {
+       EXPIRE_REFLOGS_DRY_RUN = 1 << 0,
+       EXPIRE_REFLOGS_UPDATE_REF = 1 << 1,
+       EXPIRE_REFLOGS_VERBOSE = 1 << 2,
+       EXPIRE_REFLOGS_REWRITE = 1 << 3
+};
+
+/*
+ * The following interface is used for reflog expiration. The caller
+ * calls reflog_expire(), supplying it with three callback functions,
+ * of the following types. The callback functions define the
+ * expiration policy that is desired.
+ *
+ * reflog_expiry_prepare_fn -- Called once after the reference is
+ *     locked.
+ *
+ * reflog_expiry_should_prune_fn -- Called once for each entry in the
+ *     existing reflog. It should return true iff that entry should be
+ *     pruned.
+ *
+ * reflog_expiry_cleanup_fn -- Called once before the reference is
+ *     unlocked again.
+ */
+typedef void reflog_expiry_prepare_fn(const char *refname,
+                                     const unsigned char *sha1,
+                                     void *cb_data);
+typedef int reflog_expiry_should_prune_fn(unsigned char *osha1,
+                                         unsigned char *nsha1,
+                                         const char *email,
+                                         unsigned long timestamp, int tz,
+                                         const char *message, void *cb_data);
+typedef void reflog_expiry_cleanup_fn(void *cb_data);
+
+/*
+ * Expire reflog entries for the specified reference. sha1 is the old
+ * value of the reference. flags is a combination of the constants in
+ * enum expire_reflog_flags. The three function pointers are described
+ * above. On success, return zero.
+ */
+extern int reflog_expire(const char *refname, const unsigned char *sha1,
+                        unsigned int flags,
+                        reflog_expiry_prepare_fn prepare_fn,
+                        reflog_expiry_should_prune_fn should_prune_fn,
+                        reflog_expiry_cleanup_fn cleanup_fn,
+                        void *policy_cb_data);
+
 #endif /* REFS_H */
index 696a5ecf05d116bb24847079b5741fffe905a2f3..af7b6786dc091035e3216c710dbc0ebc3c234a8a 100644 (file)
@@ -961,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 7b71ebf4bfca0ce6490a122afc5c321d2b35690c..68901b0070d257dc31b59e9292cd7b6d7ef2e952 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -2156,7 +2156,7 @@ struct ref *get_stale_heads(struct refspec *refs, int ref_count, struct ref *fet
 /*
  * Compare-and-swap
  */
-void clear_cas_option(struct push_cas_option *cas)
+static void clear_cas_option(struct push_cas_option *cas)
 {
        int i;
 
index 8b62efd2adcb74c7e46d3f918a25658d6f6ce16f..02d66ceff5c962995de37f351a09fe91055d6364 100644 (file)
--- a/remote.h
+++ b/remote.h
@@ -115,7 +115,8 @@ struct ref {
                REF_STATUS_REJECT_SHALLOW,
                REF_STATUS_UPTODATE,
                REF_STATUS_REMOTE_REJECT,
-               REF_STATUS_EXPECTING_REPORT
+               REF_STATUS_EXPECTING_REPORT,
+               REF_STATUS_ATOMIC_PUSH_FAILED
        } status;
        char *remote_status;
        struct ref *peer_ref; /* when renaming */
@@ -260,7 +261,6 @@ struct push_cas_option {
 
 extern int parseopt_push_cas_option(const struct option *, const char *arg, int unset);
 extern int parse_push_cas_option(struct push_cas_option *, const char *arg, int unset);
-extern void clear_cas_option(struct push_cas_option *);
 
 extern int is_empty_cas(const struct push_cas_option *);
 void apply_push_cas(struct push_cas_option *, struct remote *, struct ref *);
index 86406a26a2d4599ea401d1faa9a817cadb3b7bcd..66520c671ee1141b1c0edb7ab776dd9d9df04726 100644 (file)
@@ -2017,6 +2017,8 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
                grep_set_pattern_type_option(GREP_PATTERN_TYPE_PCRE, &revs->grep_filter);
        } else if (!strcmp(arg, "--all-match")) {
                revs->grep_filter.all_match = 1;
+       } else if (!strcmp(arg, "--invert-grep")) {
+               revs->invert_grep = 1;
        } else if ((argcount = parse_long_opt("encoding", argv, &optarg))) {
                if (strcmp(optarg, "none"))
                        git_log_output_encoding = xstrdup(optarg);
@@ -2915,7 +2917,7 @@ static int commit_match(struct commit *commit, struct rev_info *opt)
                                     (char *)message, strlen(message));
        strbuf_release(&buf);
        unuse_commit_buffer(commit, message);
-       return retval;
+       return opt->invert_grep ? !retval : retval;
 }
 
 static inline int want_ancestry(const struct rev_info *revs)
@@ -2968,6 +2970,61 @@ enum commit_action get_commit_action(struct rev_info *revs, struct commit *commi
        return commit_show;
 }
 
+define_commit_slab(saved_parents, struct commit_list *);
+
+#define EMPTY_PARENT_LIST ((struct commit_list *)-1)
+
+/*
+ * You may only call save_parents() once per commit (this is checked
+ * for non-root commits).
+ */
+static void save_parents(struct rev_info *revs, struct commit *commit)
+{
+       struct commit_list **pp;
+
+       if (!revs->saved_parents_slab) {
+               revs->saved_parents_slab = xmalloc(sizeof(struct saved_parents));
+               init_saved_parents(revs->saved_parents_slab);
+       }
+
+       pp = saved_parents_at(revs->saved_parents_slab, commit);
+
+       /*
+        * When walking with reflogs, we may visit the same commit
+        * several times: once for each appearance in the reflog.
+        *
+        * In this case, save_parents() will be called multiple times.
+        * We want to keep only the first set of parents.  We need to
+        * store a sentinel value for an empty (i.e., NULL) parent
+        * list to distinguish it from a not-yet-saved list, however.
+        */
+       if (*pp)
+               return;
+       if (commit->parents)
+               *pp = copy_commit_list(commit->parents);
+       else
+               *pp = EMPTY_PARENT_LIST;
+}
+
+static void free_saved_parents(struct rev_info *revs)
+{
+       if (revs->saved_parents_slab)
+               clear_saved_parents(revs->saved_parents_slab);
+}
+
+struct commit_list *get_saved_parents(struct rev_info *revs, const struct commit *commit)
+{
+       struct commit_list *parents;
+
+       if (!revs->saved_parents_slab)
+               return commit->parents;
+
+       parents = *saved_parents_at(revs->saved_parents_slab, commit);
+       if (parents == EMPTY_PARENT_LIST)
+               return NULL;
+       return parents;
+}
+
 enum commit_action simplify_commit(struct rev_info *revs, struct commit *commit)
 {
        enum commit_action action = get_commit_action(revs, commit);
@@ -3267,54 +3324,3 @@ void put_revision_mark(const struct rev_info *revs, const struct commit *commit)
        fputs(mark, stdout);
        putchar(' ');
 }
-
-define_commit_slab(saved_parents, struct commit_list *);
-
-#define EMPTY_PARENT_LIST ((struct commit_list *)-1)
-
-void save_parents(struct rev_info *revs, struct commit *commit)
-{
-       struct commit_list **pp;
-
-       if (!revs->saved_parents_slab) {
-               revs->saved_parents_slab = xmalloc(sizeof(struct saved_parents));
-               init_saved_parents(revs->saved_parents_slab);
-       }
-
-       pp = saved_parents_at(revs->saved_parents_slab, commit);
-
-       /*
-        * When walking with reflogs, we may visit the same commit
-        * several times: once for each appearance in the reflog.
-        *
-        * In this case, save_parents() will be called multiple times.
-        * We want to keep only the first set of parents.  We need to
-        * store a sentinel value for an empty (i.e., NULL) parent
-        * list to distinguish it from a not-yet-saved list, however.
-        */
-       if (*pp)
-               return;
-       if (commit->parents)
-               *pp = copy_commit_list(commit->parents);
-       else
-               *pp = EMPTY_PARENT_LIST;
-}
-
-struct commit_list *get_saved_parents(struct rev_info *revs, const struct commit *commit)
-{
-       struct commit_list *parents;
-
-       if (!revs->saved_parents_slab)
-               return commit->parents;
-
-       parents = *saved_parents_at(revs->saved_parents_slab, commit);
-       if (parents == EMPTY_PARENT_LIST)
-               return NULL;
-       return parents;
-}
-
-void free_saved_parents(struct rev_info *revs)
-{
-       if (revs->saved_parents_slab)
-               clear_saved_parents(revs->saved_parents_slab);
-}
index 033a24460e71b723f95ef91f4b6f0dbfd8c2c390..0ea8b4e25555e30d852f47ce37ec2a75a61043e3 100644 (file)
@@ -169,6 +169,8 @@ struct rev_info {
 
        /* Filter by commit log message */
        struct grep_opt grep_filter;
+       /* Negate the match of grep_filter */
+       int invert_grep;
 
        /* Display history graph */
        struct git_graph *graph;
@@ -298,18 +300,14 @@ extern int rewrite_parents(struct rev_info *revs, struct commit *commit,
        rewrite_parent_fn_t rewrite_parent);
 
 /*
- * Save a copy of the parent list, and return the saved copy.  This is
- * used by the log machinery to retrieve the original parents when
- * commit->parents has been modified by history simpification.
- *
- * You may only call save_parents() once per commit (this is checked
- * for non-root commits).
+ * The log machinery saves the original parent list so that
+ * get_saved_parents() can later tell what the real parents of the
+ * commits are, when commit->parents has been modified by history
+ * simpification.
  *
  * get_saved_parents() will transparently return commit->parents if
  * history simplification is off.
  */
-extern void save_parents(struct rev_info *revs, struct commit *commit);
 extern struct commit_list *get_saved_parents(struct rev_info *revs, const struct commit *commit);
-extern void free_saved_parents(struct rev_info *revs);
 
 #endif
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 25947d7df9dd3af6e665d5d5eb63ec970617aef1..9d2b0c52ed8235425795772db99fc14ea9c2bf2b 100644 (file)
@@ -193,10 +193,13 @@ static void advertise_shallow_grafts_buf(struct strbuf *sb)
        for_each_commit_graft(advertise_shallow_grafts_cb, sb);
 }
 
-static int ref_update_to_be_sent(const struct ref *ref, const struct send_pack_args *args)
+#define CHECK_REF_NO_PUSH -1
+#define CHECK_REF_STATUS_REJECTED -2
+#define CHECK_REF_UPTODATE -3
+static int check_to_send_update(const struct ref *ref, const struct send_pack_args *args)
 {
        if (!ref->peer_ref && !args->send_mirror)
-               return 0;
+               return CHECK_REF_NO_PUSH;
 
        /* Check for statuses set by set_ref_status_for_push() */
        switch (ref->status) {
@@ -206,10 +209,11 @@ static int ref_update_to_be_sent(const struct ref *ref, const struct send_pack_a
        case REF_STATUS_REJECT_NEEDS_FORCE:
        case REF_STATUS_REJECT_STALE:
        case REF_STATUS_REJECT_NODELETE:
+               return CHECK_REF_STATUS_REJECTED;
        case REF_STATUS_UPTODATE:
-               return 0;
+               return CHECK_REF_UPTODATE;
        default:
-               return 1;
+               return 0;
        }
 }
 
@@ -253,7 +257,7 @@ static int generate_push_cert(struct strbuf *req_buf,
        strbuf_addstr(&cert, "\n");
 
        for (ref = remote_refs; ref; ref = ref->next) {
-               if (!ref_update_to_be_sent(ref, args))
+               if (check_to_send_update(ref, args) < 0)
                        continue;
                update_seen = 1;
                strbuf_addf(&cert, "%s %s %s\n",
@@ -281,6 +285,29 @@ static int generate_push_cert(struct strbuf *req_buf,
        return update_seen;
 }
 
+
+static int atomic_push_failure(struct send_pack_args *args,
+                              struct ref *remote_refs,
+                              struct ref *failing_ref)
+{
+       struct ref *ref;
+       /* Mark other refs as failed */
+       for (ref = remote_refs; ref; ref = ref->next) {
+               if (!ref->peer_ref && !args->send_mirror)
+                       continue;
+
+               switch (ref->status) {
+               case REF_STATUS_EXPECTING_REPORT:
+                       ref->status = REF_STATUS_ATOMIC_PUSH_FAILED;
+                       continue;
+               default:
+                       break; /* do nothing */
+               }
+       }
+       return error("atomic push failed for ref %s. status: %d\n",
+                    failing_ref->name, failing_ref->status);
+}
+
 int send_pack(struct send_pack_args *args,
              int fd[], struct child_process *conn,
              struct ref *remote_refs,
@@ -297,6 +324,8 @@ int send_pack(struct send_pack_args *args,
        int use_sideband = 0;
        int quiet_supported = 0;
        int agent_supported = 0;
+       int use_atomic = 0;
+       int atomic_supported = 0;
        unsigned cmds_sent = 0;
        int ret;
        struct async demux;
@@ -317,6 +346,8 @@ int send_pack(struct send_pack_args *args,
                agent_supported = 1;
        if (server_supports("no-thin"))
                args->use_thin_pack = 0;
+       if (server_supports("atomic"))
+               atomic_supported = 1;
        if (args->push_cert) {
                int len;
 
@@ -331,6 +362,10 @@ int send_pack(struct send_pack_args *args,
                        "Perhaps you should specify a branch such as 'master'.\n");
                return 0;
        }
+       if (args->atomic && !atomic_supported)
+               die(_("server does not support --atomic push"));
+
+       use_atomic = atomic_supported && args->atomic;
 
        if (status_report)
                strbuf_addstr(&cap_buf, " report-status");
@@ -338,6 +373,8 @@ int send_pack(struct send_pack_args *args,
                strbuf_addstr(&cap_buf, " side-band-64k");
        if (quiet_supported && (args->quiet || !args->progress))
                strbuf_addstr(&cap_buf, " quiet");
+       if (use_atomic)
+               strbuf_addstr(&cap_buf, " atomic");
        if (agent_supported)
                strbuf_addf(&cap_buf, " agent=%s", git_user_agent_sanitized());
 
@@ -362,9 +399,21 @@ int send_pack(struct send_pack_args *args,
         * the pack data.
         */
        for (ref = remote_refs; ref; ref = ref->next) {
-               if (!ref_update_to_be_sent(ref, args))
+               switch (check_to_send_update(ref, args)) {
+               case 0: /* no error */
+                       break;
+               case CHECK_REF_STATUS_REJECTED:
+                       /*
+                        * When we know the server would reject a ref update if
+                        * we were to send it and we're trying to send the refs
+                        * atomically, abort the whole operation.
+                        */
+                       if (use_atomic)
+                               return atomic_push_failure(args, remote_refs, ref);
+                       /* Fallthrough for non atomic case. */
+               default:
                        continue;
-
+               }
                if (!ref->deletion)
                        need_pack_data = 1;
 
@@ -383,7 +432,7 @@ int send_pack(struct send_pack_args *args,
                if (args->dry_run || args->push_cert)
                        continue;
 
-               if (!ref_update_to_be_sent(ref, args))
+               if (check_to_send_update(ref, args) < 0)
                        continue;
 
                old_hex = sha1_to_hex(ref->old_sha1);
index 56354577467acfe1bf98652f6bfad9ad7e5db851..b6646488aaf93814c5053d79528c1b5a4d19bcb5 100644 (file)
@@ -13,7 +13,8 @@ struct send_pack_args {
                use_ofs_delta:1,
                dry_run:1,
                push_cert:1,
-               stateless_rpc:1;
+               stateless_rpc:1,
+               atomic:1;
 };
 
 int send_pack(struct send_pack_args *args,
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 f5e67204a4084ff79beec0d5a5dd0fb06966cc3f..d8bf40ad4bed3bc846bb71945f1c2bfce76a202d 100644 (file)
--- a/shallow.c
+++ b/shallow.c
@@ -137,7 +137,7 @@ struct commit_list *get_shallow_commits(struct object_array *heads, int depth,
        return result;
 }
 
-void check_shallow_file_for_update(void)
+static void check_shallow_file_for_update(void)
 {
        if (is_shallow == -1)
                die("BUG: shallow must be initialized by now");
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 d154d1ed1dd8f3449ad21e0aeefdce7d3120e1fb..e6adf2f82d59027279e06e0d273e719226d82184 100644 (file)
@@ -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 51845491bb42ee72a1f7ec33c504e65c5bf8b248..cd220e378e201fc5bfbaf9c78b0a3183ebf12d11 100644 (file)
@@ -1,7 +1,7 @@
 # Helpers for terminal output tests.
 
 # Catch tests which should depend on TTY but forgot to. There's no need
-# to aditionally check that the TTY prereq is set here.  If the test declared
+# to additionally check that the TTY prereq is set here.  If the test declared
 # it and we are running the test, then it must have been set.
 test_terminal () {
        if ! test_declared_prereq TTY
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 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 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 1779c0a5687c471b1e6d2e78a8509b9ca6c31307..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 &&
index 99ab7ca21f2673e646232d9c07f77c8ed2f5f998..5f2b290d2b803a4af971a1c03021e97a16951847 100755 (executable)
@@ -212,6 +212,21 @@ test_expect_success 'log --grep' '
        test_cmp expect actual
 '
 
+cat > expect << EOF
+second
+initial
+EOF
+test_expect_success 'log --invert-grep --grep' '
+       git log --pretty="tformat:%s" --invert-grep --grep=th --grep=Sec >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'log --invert-grep --grep -i' '
+       echo initial >expect &&
+       git log --pretty="tformat:%s" --invert-grep -i --grep=th --grep=Sec >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'log --grep option parsing' '
        echo second >expect &&
        git log -1 --pretty="tformat:%s" --grep sec >actual &&
index 6b8ad4f5b0db4ba4e667c091225d35fe486bee5e..f8008b6a3d2a5fc200665998288d121d1c35dd25 100755 (executable)
@@ -44,10 +44,10 @@ test_expect_success setup '
 '
 
 cat >expected <<EOF
-${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD${c_reset}${c_commit},\
+${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}${c_branch}master${c_reset}${c_commit})${c_reset} B
+ ${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}\
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 594d7a6998ea96ba6a3de22abfe9cc05fb6a105f..630885d6df2fed0b8ba35005f150ccd3838dfcca 100755 (executable)
@@ -1434,4 +1434,67 @@ test_expect_success 'receive.denyCurrentBranch = updateInstead' '
 
 '
 
+test_expect_success 'updateInstead with push-to-checkout hook' '
+       rm -fr testrepo &&
+       git init testrepo &&
+       (
+               cd testrepo &&
+               git pull .. master &&
+               git reset --hard HEAD^^ &&
+               git tag initial &&
+               git config receive.denyCurrentBranch updateInstead &&
+               write_script .git/hooks/push-to-checkout <<-\EOF
+               echo >&2 updating from $(git rev-parse HEAD)
+               echo >&2 updating to "$1"
+
+               git update-index -q --refresh &&
+               git read-tree -u -m HEAD "$1" || {
+                       status=$?
+                       echo >&2 read-tree failed
+                       exit $status
+               }
+               EOF
+       ) &&
+
+       # Try pushing into a pristine
+       git push testrepo master &&
+       (
+               cd testrepo &&
+               git diff --quiet &&
+               git diff HEAD --quiet &&
+               test $(git -C .. rev-parse HEAD) = $(git rev-parse HEAD)
+       ) &&
+
+       # Try pushing into a repository with conflicting change
+       (
+               cd testrepo &&
+               git reset --hard initial &&
+               echo conflicting >path2
+       ) &&
+       test_must_fail git push testrepo master &&
+       (
+               cd testrepo &&
+               test $(git rev-parse initial) = $(git rev-parse HEAD) &&
+               test conflicting = "$(cat path2)" &&
+               git diff-index --quiet --cached HEAD
+       ) &&
+
+       # Try pushing into a repository with unrelated change
+       (
+               cd testrepo &&
+               git reset --hard initial &&
+               echo unrelated >path1 &&
+               echo irrelevant >path5 &&
+               git add path5
+       ) &&
+       git push testrepo master &&
+       (
+               cd testrepo &&
+               test "$(cat path1)" = unrelated &&
+               test "$(cat path5)" = irrelevant &&
+               test "$(git diff --name-only --cached HEAD)" = path5 &&
+               test $(git -C .. rev-parse HEAD) = $(git rev-parse HEAD)
+       )
+'
+
 test_done
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 |
diff --git a/t/t5543-atomic-push.sh b/t/t5543-atomic-push.sh
new file mode 100755 (executable)
index 0000000..3480b33
--- /dev/null
@@ -0,0 +1,194 @@
+#!/bin/sh
+
+test_description='pushing to a repository using the atomic push option'
+
+. ./test-lib.sh
+
+mk_repo_pair () {
+       rm -rf workbench upstream &&
+       test_create_repo upstream &&
+       test_create_repo workbench &&
+       (
+               cd upstream &&
+               git config receive.denyCurrentBranch warn
+       ) &&
+       (
+               cd workbench &&
+               git remote add up ../upstream
+       )
+}
+
+# Compare the ref ($1) in upstream with a ref value from workbench ($2)
+# i.e. test_refs second HEAD@{2}
+test_refs () {
+       test $# = 2 &&
+       git -C upstream rev-parse --verify "$1" >expect &&
+       git -C workbench rev-parse --verify "$2" >actual &&
+       test_cmp expect actual
+}
+
+test_expect_success 'atomic push works for a single branch' '
+       mk_repo_pair &&
+       (
+               cd workbench &&
+               test_commit one &&
+               git push --mirror up &&
+               test_commit two &&
+               git push --atomic up master
+       ) &&
+       test_refs master master
+'
+
+test_expect_success 'atomic push works for two branches' '
+       mk_repo_pair &&
+       (
+               cd workbench &&
+               test_commit one &&
+               git branch second &&
+               git push --mirror up &&
+               test_commit two &&
+               git checkout second &&
+               test_commit three &&
+               git push --atomic up master second
+       ) &&
+       test_refs master master &&
+       test_refs second second
+'
+
+test_expect_success 'atomic push works in combination with --mirror' '
+       mk_repo_pair &&
+       (
+               cd workbench &&
+               test_commit one &&
+               git checkout -b second &&
+               test_commit two &&
+               git push --atomic --mirror up
+       ) &&
+       test_refs master master &&
+       test_refs second second
+'
+
+test_expect_success 'atomic push works in combination with --force' '
+       mk_repo_pair &&
+       (
+               cd workbench &&
+               test_commit one &&
+               git branch second master &&
+               test_commit two_a &&
+               git checkout second &&
+               test_commit two_b &&
+               test_commit three_b &&
+               test_commit four &&
+               git push --mirror up &&
+               # The actual test is below
+               git checkout master &&
+               test_commit three_a &&
+               git checkout second &&
+               git reset --hard HEAD^ &&
+               git push --force --atomic up master second
+       ) &&
+       test_refs master master &&
+       test_refs second second
+'
+
+# set up two branches where master can be pushed but second can not
+# (non-fast-forward). Since second can not be pushed the whole operation
+# will fail and leave master untouched.
+test_expect_success 'atomic push fails if one branch fails' '
+       mk_repo_pair &&
+       (
+               cd workbench &&
+               test_commit one &&
+               git checkout -b second master &&
+               test_commit two &&
+               test_commit three &&
+               test_commit four &&
+               git push --mirror up &&
+               git reset --hard HEAD~2 &&
+               test_commit five &&
+               git checkout master &&
+               test_commit six &&
+               test_must_fail git push --atomic --all up
+       ) &&
+       test_refs master HEAD@{7} &&
+       test_refs second HEAD@{4}
+'
+
+test_expect_success 'atomic push fails if one tag fails remotely' '
+       # prepare the repo
+       mk_repo_pair &&
+       (
+               cd workbench &&
+               test_commit one &&
+               git checkout -b second master &&
+               test_commit two &&
+               git push --mirror up
+       ) &&
+       # a third party modifies the server side:
+       (
+               cd upstream &&
+               git checkout second &&
+               git tag test_tag second
+       ) &&
+       # see if we can now push both branches.
+       (
+               cd workbench &&
+               git checkout master &&
+               test_commit three &&
+               git checkout second &&
+               test_commit four &&
+               git tag test_tag &&
+               test_must_fail git push --tags --atomic up master second
+       ) &&
+       test_refs master HEAD@{3} &&
+       test_refs second HEAD@{1}
+'
+
+test_expect_success 'atomic push obeys update hook preventing a branch to be pushed' '
+       mk_repo_pair &&
+       (
+               cd workbench &&
+               test_commit one &&
+               git checkout -b second master &&
+               test_commit two &&
+               git push --mirror up
+       ) &&
+       (
+               cd upstream &&
+               HOOKDIR="$(git rev-parse --git-dir)/hooks" &&
+               HOOK="$HOOKDIR/update" &&
+               mkdir -p "$HOOKDIR" &&
+               write_script "$HOOK" <<-\EOF
+                       # only allow update to master from now on
+                       test "$1" = "refs/heads/master"
+               EOF
+       ) &&
+       (
+               cd workbench &&
+               git checkout master &&
+               test_commit three &&
+               git checkout second &&
+               test_commit four &&
+               test_must_fail git push --atomic up master second
+       ) &&
+       test_refs master HEAD@{3} &&
+       test_refs second HEAD@{1}
+'
+
+test_expect_success 'atomic push is not advertised if configured' '
+       mk_repo_pair &&
+       (
+               cd upstream
+               git config receive.advertiseatomic 0
+       ) &&
+       (
+               cd workbench &&
+               test_commit one &&
+               git push --mirror up &&
+               test_commit two &&
+               test_must_fail git push --atomic up master
+       ) &&
+       test_refs master HEAD@{1}
+'
+
+test_done
index 6da942243101c4f5358b4aaf3c62cf6390c258b4..2731ad4cea951744ea82b94a038a71ef01a228a2 100755 (executable)
@@ -214,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 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 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
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
diff --git a/t/t9817-git-p4-exclude.sh b/t/t9817-git-p4-exclude.sh
new file mode 100755 (executable)
index 0000000..aac568e
--- /dev/null
@@ -0,0 +1,71 @@
+#!/bin/sh
+
+test_description='git p4 tests for excluded paths during clone and sync'
+
+. ./lib-git-p4.sh
+
+test_expect_success 'start p4d' '
+       start_p4d
+'
+
+# Create a repo with the structure:
+#
+#    //depot/wanted/foo
+#    //depot/discard/foo
+#
+# Check that we can exclude a subdirectory with both
+# clone and sync operations.
+
+test_expect_success 'create exclude repo' '
+       (
+               cd "$cli" &&
+               mkdir -p wanted discard &&
+               echo wanted >wanted/foo &&
+               echo discard >discard/foo &&
+               p4 add wanted/foo discard/foo &&
+               p4 submit -d "initial revision"
+       )
+'
+
+test_expect_success 'check the repo was created correctly' '
+       test_when_finished cleanup_git &&
+       git p4 clone --dest="$git" //depot/...@all &&
+       (
+               cd "$git" &&
+               test_path_is_file wanted/foo &&
+               test_path_is_file discard/foo
+       )
+'
+
+test_expect_success 'clone, excluding part of repo' '
+       test_when_finished cleanup_git &&
+       git p4 clone -//depot/discard/... --dest="$git" //depot/...@all &&
+       (
+               cd "$git" &&
+               test_path_is_file wanted/foo &&
+               test_path_is_missing discard/foo
+       )
+'
+
+test_expect_success 'clone, then sync with exclude' '
+       test_when_finished cleanup_git &&
+       git p4 clone -//depot/discard/... --dest="$git" //depot/...@all &&
+       (
+               cd "$cli" &&
+               p4 edit wanted/foo discard/foo &&
+               date >>wanted/foo &&
+               date >>discard/foo &&
+               p4 submit -d "updating" &&
+
+               cd "$git" &&
+               git p4 sync -//depot/discard/... &&
+               test_path_is_file wanted/foo &&
+               test_path_is_missing discard/foo
+       )
+'
+
+test_expect_success 'kill p4d' '
+       kill_p4d
+'
+
+test_done
index c09677802cce067a946a2550cdd2d8ef33434e81..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
@@ -1064,3 +1062,9 @@ 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 7dc4a443aee0c6220dc0581d4bcfdd1d65da1d8a..5d99a6bc2e7a10d40f6d8213e2f3cad254dbdb04 100644 (file)
@@ -97,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;
@@ -211,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;
 }
 
@@ -338,17 +341,6 @@ 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)
@@ -622,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);
 
@@ -826,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);
 
index 862f63f4e1a5250d3d701699e4c5bb4e71a6b2e9..00f39d9f5ba8c024ec2b9c6c2a054a0045eadbbb 100644 (file)
@@ -728,6 +728,10 @@ static int print_one_push_status(struct ref *ref, const char *dest, int count, i
                                                 ref->deletion ? NULL : ref->peer_ref,
                                                 "remote failed to report status", porcelain);
                break;
+       case REF_STATUS_ATOMIC_PUSH_FAILED:
+               print_ref_status('!', "[rejected]", ref, ref->peer_ref,
+                                                "atomic push failed", porcelain);
+               break;
        case REF_STATUS_OK:
                print_ok_ref_status(ref, porcelain);
                break;
@@ -826,6 +830,7 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
        args.dry_run = !!(flags & TRANSPORT_PUSH_DRY_RUN);
        args.porcelain = !!(flags & TRANSPORT_PUSH_PORCELAIN);
        args.push_cert = !!(flags & TRANSPORT_PUSH_CERT);
+       args.atomic = !!(flags & TRANSPORT_PUSH_ATOMIC);
        args.url = transport->url;
 
        ret = send_pack(&args, data->fd, data->conn, remote_refs,
index 3e0091eaabe406759005bc24ce2ff39144caa72d..18d2cf8275e1f5f6ff3d18afde55d06ed7586af9 100644 (file)
@@ -125,6 +125,7 @@ struct transport {
 #define TRANSPORT_PUSH_NO_HOOK 512
 #define TRANSPORT_PUSH_FOLLOW_TAGS 1024
 #define TRANSPORT_PUSH_CERT 2048
+#define TRANSPORT_PUSH_ATOMIC 4096
 
 #define TRANSPORT_SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)
 #define TRANSPORT_SUMMARY(x) (int)(TRANSPORT_SUMMARY_WIDTH + strlen(x) - gettext_width(x)), (x)
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 618d2164919758b141aa9d6408c57a4fb99c922c..132d342bc12bf790f9964f179385aa4f08e6ae00 100644 (file)
@@ -412,9 +412,9 @@ static size_t url_match_prefix(const char *url,
        return 0;
 }
 
-int match_urls(const struct url_info *url,
-              const struct url_info *url_prefix,
-              int *exactusermatch)
+static int match_urls(const struct url_info *url,
+                     const struct url_info *url_prefix,
+                     int *exactusermatch)
 {
        /*
         * url_prefix matches url if the scheme, host and port of url_prefix
index b461dfd3dfee2c37eb65e5abb28f6f128f40096b..528862adc55c43ed26763b3c05e1d27d558a1b74 100644 (file)
@@ -31,7 +31,6 @@ struct url_info {
 };
 
 extern char *url_normalize(const char *, struct url_info *);
-extern int match_urls(const struct url_info *url, const struct url_info *url_prefix, int *exactusermatch);
 
 struct urlmatch_item {
        size_t matched_len;
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 29666d0dbaa5af768aca86f3ca0b644ac9720648..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)
@@ -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;