Merge branch 'nd/multiple-work-trees'
authorJunio C Hamano <gitster@pobox.com>
Mon, 11 May 2015 21:23:39 +0000 (14:23 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 11 May 2015 21:23:39 +0000 (14:23 -0700)
A replacement for contrib/workdir/git-new-workdir that does not
rely on symbolic links and make sharing of objects and refs safer
by making the borrowee and borrowers aware of each other.

* nd/multiple-work-trees: (41 commits)
prune --worktrees: fix expire vs worktree existence condition
t1501: fix test with split index
t2026: fix broken &&-chain
t2026 needs procondition SANITY
git-checkout.txt: a note about multiple checkout support for submodules
checkout: add --ignore-other-wortrees
checkout: pass whole struct to parse_branchname_arg instead of individual flags
git-common-dir: make "modules/" per-working-directory directory
checkout: do not fail if target is an empty directory
t2025: add a test to make sure grafts is working from a linked checkout
checkout: don't require a work tree when checking out into a new one
git_path(): keep "info/sparse-checkout" per work-tree
count-objects: report unused files in $GIT_DIR/worktrees/...
gc: support prune --worktrees
gc: factor out gc.pruneexpire parsing code
gc: style change -- no SP before closing parenthesis
checkout: clean up half-prepared directories in --to mode
checkout: reject if the branch is already checked out elsewhere
prune: strategies for linked checkouts
checkout: support checking out into a new working directory
...

35 files changed:
1  2 
Documentation/config.txt
Documentation/git-checkout.txt
Documentation/git.txt
builtin/branch.c
builtin/checkout.c
builtin/clone.c
builtin/commit.c
builtin/fetch.c
builtin/fsck.c
builtin/gc.c
builtin/init-db.c
builtin/prune.c
builtin/receive-pack.c
builtin/remote.c
builtin/repack.c
builtin/rev-parse.c
cache.h
daemon.c
environment.c
fast-import.c
git-am.sh
git-rebase--interactive.sh
git-sh-setup.sh
git.c
notes-merge.c
path.c
refs.c
refs.h
run-command.c
run-command.h
sha1_file.c
submodule.c
trace.c
transport.c
wrapper.c
diff --combined Documentation/config.txt
index 2e5ceaf71974b1e5404de79103648da1829eaf42,2700a1bb834050036d074c9f9b6058aa212344ee..948b8b0e5c8e8639e989d2f14dbd310fe146278b
@@@ -14,8 -14,7 +14,8 @@@ the fully qualified variable name of th
  dot-separated segment and the section name is everything before the last
  dot. The variable names are case-insensitive, allow only alphanumeric
  characters and `-`, and must start with an alphabetic character.  Some
 -variables may appear multiple times.
 +variables may appear multiple times; we say then that the variable is
 +multivalued.
  
  Syntax
  ~~~~~~
@@@ -26,7 -25,7 +26,7 @@@ blank lines are ignored
  
  The file consists of sections and variables.  A section begins with
  the name of the section in square brackets and continues until the next
 -section begins.  Section names are not case sensitive.  Only alphanumeric
 +section begins.  Section names are case-insensitive.  Only alphanumeric
  characters, `-` and `.` are allowed in section names.  Each variable
  must belong to some section, which means that there must be a section
  header before the first setting of a variable.
@@@ -41,8 -40,8 +41,8 @@@ in the section header, like in the exam
  --------
  
  Subsection names are case sensitive and can contain any characters except
 -newline (doublequote `"` and backslash have to be escaped as `\"` and `\\`,
 -respectively).  Section headers cannot span multiple
 +newline (doublequote `"` and backslash can be included by escaping them
 +as `\"` and `\\`, respectively).  Section headers cannot span multiple
  lines.  Variables may belong directly to a section or to a given subsection.
  You can have `[section]` if you have `[section "subsection"]`, but you
  don't need to.
@@@ -54,27 -53,38 +54,27 @@@ restrictions as section names
  
  All the other lines (and the remainder of the line after the section
  header) are recognized as setting variables, in the form
 -'name = value'.  If there is no equal sign on the line, the entire line
 -is taken as 'name' and the variable is recognized as boolean "true".
 +'name = value' (or just 'name', which is a short-hand to say that
 +the variable is the boolean "true").
  The variable names are case-insensitive, allow only alphanumeric characters
 -and `-`, and must start with an alphabetic character.  There can be more
 -than one value for a given variable; we say then that the variable is
 -multivalued.
 -
 -Leading and trailing whitespace in a variable value is discarded.
 -Internal whitespace within a variable value is retained verbatim.
 +and `-`, and must start with an alphabetic character.
  
 -The values following the equals sign in variable assign are all either
 -a string, an integer, or a boolean.  Boolean values may be given as yes/no,
 -1/0, true/false or on/off.  Case is not significant in boolean values, when
 -converting value to the canonical form using '--bool' type specifier;
 -'git config' will ensure that the output is "true" or "false".
 +A line that defines a value can be continued to the next line by
 +ending it with a `\`; the backquote and the end-of-line are
 +stripped.  Leading whitespaces after 'name =', the remainder of the
 +line after the first comment character '#' or ';', and trailing
 +whitespaces of the line are discarded unless they are enclosed in
 +double quotes.  Internal whitespaces within the value are retained
 +verbatim.
  
 -String values may be entirely or partially enclosed in double quotes.
 -You need to enclose variable values in double quotes if you want to
 -preserve leading or trailing whitespace, or if the variable value contains
 -comment characters (i.e. it contains '#' or ';').
 -Double quote `"` and backslash `\` characters in variable values must
 -be escaped: use `\"` for `"` and `\\` for `\`.
 +Inside double quotes, double quote `"` and backslash `\` characters
 +must be escaped: use `\"` for `"` and `\\` for `\`.
  
  The following escape sequences (beside `\"` and `\\`) are recognized:
  `\n` for newline character (NL), `\t` for horizontal tabulation (HT, TAB)
  and `\b` for backspace (BS).  Other char escape sequences (including octal
  escape sequences) are invalid.
  
 -Variable values ending in a `\` are continued on the next line in the
 -customary UNIX fashion.
 -
 -Some variables may require a special value format.
  
  Includes
  ~~~~~~~~
@@@ -116,60 -126,6 +116,60 @@@ Exampl
                path = foo ; expand "foo" relative to the current file
                path = ~/foo ; expand "foo" in your $HOME directory
  
 +
 +Values
 +~~~~~~
 +
 +Values of many variables are treated as a simple string, but there
 +are variables that take values of specific types and there are rules
 +as to how to spell them.
 +
 +boolean::
 +
 +       When a variable is said to take a boolean value, many
 +       synonyms are accepted for 'true' and 'false'; these are all
 +       case-insensitive.
 +
 +       true;; Boolean true can be spelled as `yes`, `on`, `true`,
 +              or `1`.  Also, a variable defined without `= <value>`
 +              is taken as true.
 +
 +       false;; Boolean false can be spelled as `no`, `off`,
 +              `false`, or `0`.
 ++
 +When converting value to the canonical form using '--bool' type
 +specifier; 'git config' will ensure that the output is "true" or
 +"false" (spelled in lowercase).
 +
 +integer::
 +       The value for many variables that specify various sizes can
 +       be suffixed with `k`, `M`,... to mean "scale the number by
 +       1024", "by 1024x1024", etc.
 +
 +color::
 +       The value for a variables that takes a color is a list of
 +       colors (at most two) and attributes (at most one), separated
 +       by spaces.  The colors accepted are `normal`, `black`,
 +       `red`, `green`, `yellow`, `blue`, `magenta`, `cyan` and
 +       `white`; the attributes are `bold`, `dim`, `ul`, `blink` and
 +       `reverse`.  The first color given is the foreground; the
 +       second is the background.  The position of the attribute, if
 +       any, doesn't matter. Attributes may be turned off specifically
 +       by prefixing them with `no` (e.g., `noreverse`, `noul`, etc).
 ++
 +Colors (foreground and background) may also be given as numbers between
 +0 and 255; these use ANSI 256-color mode (but note that not all
 +terminals may support this).  If your terminal supports it, you may also
 +specify 24-bit RGB values as hex, like `#ff0ab3`.
 ++
 +The attributes are meant to be reset at the beginning of each item
 +in the colored output, so setting color.decorate.branch to `black`
 +will paint that branch name in a plain `black`, even if the previous
 +thing on the same output line (e.g. opening parenthesis before the
 +list of branch names in `log --decorate` output) is set to be
 +painted with `bold` or some other attribute.
 +
 +
  Variables
  ~~~~~~~~~
  
@@@ -269,7 -225,7 +269,7 @@@ See linkgit:git-update-index[1]
  +
  The default is true (when core.filemode is not specified in the config file).
  
 -core.ignorecase::
 +core.ignoreCase::
        If true, this option enables various workarounds to enable
        Git to work better on filesystems that are not case sensitive,
        like FAT. For example, if a directory listing finds
        "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).
        When false, file names are handled fully transparent by Git,
        which is backward compatible with older versions of Git.
  
 +core.protectHFS::
 +      If set to true, do not allow checkout of paths that would
 +      be considered equivalent to `.git` on an HFS+ filesystem.
 +      Defaults to `true` on Mac OS, and `false` elsewhere.
 +
 +core.protectNTFS::
 +      If set to true, do not allow checkout of paths that would
 +      cause problems with the NTFS filesystem, e.g. conflict with
 +      8.3 "short" names.
 +      Defaults to `true` on Windows, and `false` elsewhere.
 +
  core.trustctime::
        If false, the ctime differences between the index and the
        working tree are ignored; useful when the inode change time
        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
@@@ -419,19 -364,14 +419,19 @@@ This is useful for excluding servers in
  proxy use, while defaulting to a common proxy for external domains.
  
  core.ignoreStat::
 -      If true, commands which modify both the working tree and the index
 -      will mark the updated paths with the "assume unchanged" bit in the
 -      index. These marked files are then assumed to stay unchanged in the
 -      working tree, until you mark them otherwise manually - Git will not
 -      detect the file changes by lstat() calls. This is useful on systems
 -      where those are very slow, such as Microsoft Windows.
 -      See linkgit:git-update-index[1].
 -      False by default.
 +      If true, Git will avoid using lstat() calls to detect if files have
 +      changed by setting the "assume-unchanged" bit for those tracked files
 +      which it has updated identically in both the index and working tree.
 ++
 +When files are modified outside of Git, the user will need to stage
 +the modified files explicitly (e.g. see 'Examples' section in
 +linkgit:git-update-index[1]).
 +Git will not normally detect changes to those files.
 ++
 +This is useful on systems where lstat() calls are very slow, such as
 +CIFS/Microsoft Windows.
 ++
 +False by default.
  
  core.preferSymlinkRefs::
        Instead of the default "symref" format for HEAD
@@@ -453,6 -393,8 +453,8 @@@ false), while all other repositories ar
  
  core.worktree::
        Set the path to the root of the working tree.
+       If GIT_COMMON_DIR environment variable is set, core.worktree
+       is ignored and not used for determining the root of working tree.
        This can be overridden by the GIT_WORK_TREE environment
        variable and the '--work-tree' command-line option.
        The value can be an absolute path or relative to the path to
@@@ -518,9 -460,9 +520,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
@@@ -581,7 -523,7 +583,7 @@@ be delta compressed, but larger binary 
  +
  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
        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'
        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.
  
@@@ -613,7 -555,7 +615,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
@@@ -682,7 -624,7 +684,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
@@@ -690,7 -632,7 +692,7 @@@ data writes properly, but can be usefu
  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
@@@ -727,13 -669,14 +729,13 @@@ core.abbrev:
        for abbreviated object names to stay unique for sufficiently long
        time.
  
 -add.ignore-errors::
  add.ignoreErrors::
 +add.ignore-errors (deprecated)::
        Tells 'git add' to continue adding files when some files cannot be
        added due to indexing errors. Equivalent to the '--ignore-errors'
 -      option of linkgit:git-add[1].  Older versions of Git accept only
 -      `add.ignore-errors`, which does not follow the usual naming
 -      convention for configuration variables.  Newer versions of Git
 -      honor `add.ignoreErrors` as well.
 +      option of linkgit:git-add[1].  `add.ignore-errors` is deprecated,
 +      as it does not follow the usual naming convention for configuration
 +      variables.
  
  alias.*::
        Command aliases for the linkgit:git[1] command wrapper - e.g.
@@@ -761,7 -704,7 +763,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.
@@@ -773,7 -716,7 +775,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,
        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").
        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.
  
@@@ -838,7 -781,7 +840,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
@@@ -890,6 -833,14 +892,6 @@@ color.branch.<slot>:
        `remote` (a remote-tracking branch in refs/remotes/),
        `upstream` (upstream tracking branch), `plain` (other
        refs).
 -+
 -The value for these configuration variables is a list of colors (at most
 -two) and attributes (at most one), separated by spaces.  The colors
 -accepted are `normal`, `black`, `red`, `green`, `yellow`, `blue`,
 -`magenta`, `cyan` and `white`; the attributes are `bold`, `dim`, `ul`,
 -`blink` and `reverse`.  The first color given is the foreground; the
 -second is the background.  The position of the attribute, if any,
 -doesn't matter.
  
  color.diff::
        Whether to use ANSI escape sequences to add color to patches.
@@@ -909,7 -860,8 +911,7 @@@ color.diff.<slot>:
        of `plain` (context text), `meta` (metainformation), `frag`
        (hunk header), 'func' (function in hunk header), `old` (removed lines),
        `new` (added lines), `commit` (commit headers), or `whitespace`
 -      (highlighting whitespace errors). The values of these variables may be
 -      specified as in color.branch.<slot>.
 +      (highlighting whitespace errors).
  
  color.decorate.<slot>::
        Use customized color for 'git log --decorate' output.  `<slot>` is one
@@@ -946,6 -898,8 +948,6 @@@ color.grep.<slot>:
        separators between fields on a line (`:`, `-`, and `=`)
        and between hunks (`--`)
  --
 -+
 -The values of these variables may be specified as in color.branch.<slot>.
  
  color.interactive::
        When set to `always`, always use colors for interactive prompts
@@@ -958,13 -912,14 +960,13 @@@ color.interactive.<slot>:
        Use customized color for 'git add --interactive' and 'git clean
        --interactive' output. `<slot>` may be `prompt`, `header`, `help`
        or `error`, for four distinct types of normal output from
 -      interactive commands.  The values of these variables may be
 -      specified as in color.branch.<slot>.
 +      interactive commands.
  
  color.pager::
        A boolean to enable/disable colored output when the pager is in
        use (default is true).
  
 -color.showbranch::
 +color.showBranch::
        A boolean to enable/disable color in the output of
        linkgit:git-show-branch[1]. May be set to `always`,
        `false` (or `never`) or `auto` (or `true`), in which case colors are used
@@@ -982,10 -937,10 +984,10 @@@ color.status.<slot>:
        `added` or `updated` (files which are added but not committed),
        `changed` (files which are changed but not added in the index),
        `untracked` (files which are not tracked by Git),
 -      `branch` (the current branch), or
 +      `branch` (the current branch),
        `nobranch` (the color the 'no branch' warning is shown in, defaulting
 -      to red). The values of these variables may be specified as in
 -      color.branch.<slot>.
 +      to red), or
 +      `unmerged` (files which have unmerged changes).
  
  color.ui::
        This variable determines the default value for variables such
@@@ -1064,7 -1019,7 +1066,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
@@@ -1177,7 -1132,7 +1179,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.
  
@@@ -1187,7 -1142,7 +1189,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.
  
@@@ -1211,7 -1166,7 +1213,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
@@@ -1250,17 -1205,17 +1252,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
        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.pruneworktreesexpire::
++gc.pruneWorktreesExpire::
+       When 'git gc' is run, it will call
+       'prune --worktrees --expire 3.months.ago'.
+       Override the grace period with this config variable. The value
+       "now" may be used to disable the grace period and prune
+       $GIT_DIR/worktrees 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".
  
@@@ -1307,7 -1269,7 +1316,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].
  
@@@ -1319,10 -1281,10 +1328,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
        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
        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
        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::
        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.
@@@ -1380,7 -1342,7 +1389,7 @@@ gitweb.highlight:
  gitweb.patches::
  gitweb.pickaxe::
  gitweb.remote_heads::
 -gitweb.showsizes::
 +gitweb.showSizes::
  gitweb.snapshot::
        See linkgit:gitweb.conf[5] for description.
  
@@@ -1409,15 -1371,15 +1418,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".
  
@@@ -1429,16 -1391,16 +1438,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".
  
@@@ -1446,17 -1408,17 +1455,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.
@@@ -1476,22 -1438,22 +1485,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
        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.
  
@@@ -1515,7 -1477,7 +1524,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::
@@@ -1527,7 -1489,7 +1536,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
        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
@@@ -1548,17 -1510,17 +1557,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
@@@ -1629,7 -1591,7 +1638,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
@@@ -1702,7 -1664,7 +1711,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].)
  
@@@ -1718,7 -1680,7 +1727,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.
@@@ -1727,7 -1689,7 +1736,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
@@@ -1755,7 -1717,7 +1764,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
@@@ -1765,13 -1727,6 +1774,13 @@@ log.mailmap:
        If true, makes linkgit:git-log[1], linkgit:git-show[1], and
        linkgit:git-whatchanged[1] assume `--use-mailmap`.
  
 +mailinfo.scissors::
 +      If true, makes linkgit:git-mailinfo[1] (and therefore
 +      linkgit:git-am[1]) act by default as if the --scissors option
 +      was provided on the command-line. When active, this features
 +      removes everything from the message body before a scissors
 +      line (i.e. consisting mainly of ">8", "8<" and "-").
 +
  mailmap.file::
        The location of an augmenting mailmap file. The default
        mailmap, located in the root of the repository, is loaded
@@@ -1992,7 -1947,7 +2001,7 @@@ pack.useBitmaps:
        true. You should not generally need to turn this off unless
        you are debugging pack bitmaps.
  
 -pack.writebitmaps::
 +pack.writeBitmaps (deprecated)::
        This is a deprecated synonym for `repack.writeBitmaps`.
  
  pack.writeBitmapHashCache::
@@@ -2111,20 -2066,14 +2120,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.
        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"
@@@ -2194,17 -2138,6 +2203,17 @@@ receive.denyCurrentBranch:
        print a warning of such a push to stderr, but allow the push to
        proceed. If set to false or "ignore", allow such pushes with no
        message. Defaults to "refuse".
 ++
 +Another option is "updateInstead" which will update the working
 +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
        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
        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
@@@ -2276,7 -2209,7 +2285,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
@@@ -2298,7 -2231,7 +2307,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
@@@ -2321,7 -2254,7 +2330,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.
@@@ -2340,12 -2273,12 +2349,12 @@@ sendemail.identity:
        values in the 'sendemail' section. The default identity is
        the value of 'sendemail.identity'.
  
 -sendemail.smtpencryption::
 +sendemail.smtpEncryption::
        See linkgit:git-send-email[1] for description.  Note that this
        setting is not subject to the 'identity' mechanism.
  
 -sendemail.smtpssl::
 -      Deprecated alias for 'sendemail.smtpencryption = ssl'.
 +sendemail.smtpssl (deprecated)::
 +      Deprecated alias for 'sendemail.smtpEncryption = ssl'.
  
  sendemail.smtpsslcertpath::
        Path to ca-certificates (either a directory or a single file).
@@@ -2357,34 -2290,32 +2366,34 @@@ sendemail.<identity>.*:
        identity is selected, through command-line or
        'sendemail.identity'.
  
 -sendemail.aliasesfile::
 -sendemail.aliasfiletype::
 +sendemail.aliasesFile::
 +sendemail.aliasFileType::
  sendemail.annotate::
  sendemail.bcc::
  sendemail.cc::
 -sendemail.cccmd::
 -sendemail.chainreplyto::
 +sendemail.ccCmd::
 +sendemail.chainReplyTo::
  sendemail.confirm::
 -sendemail.envelopesender::
 +sendemail.envelopeSender::
  sendemail.from::
 -sendemail.multiedit::
 +sendemail.multiEdit::
  sendemail.signedoffbycc::
 -sendemail.smtppass::
 +sendemail.smtpPass::
  sendemail.suppresscc::
 -sendemail.suppressfrom::
 +sendemail.suppressFrom::
  sendemail.to::
 -sendemail.smtpdomain::
 -sendemail.smtpserver::
 -sendemail.smtpserverport::
 -sendemail.smtpserveroption::
 -sendemail.smtpuser::
 +sendemail.smtpDomain::
 +sendemail.smtpServer::
 +sendemail.smtpServerPort::
 +sendemail.smtpServerOption::
 +sendemail.smtpUser::
  sendemail.thread::
 +sendemail.transferEncoding::
  sendemail.validate::
 +sendemail.xmailer::
        See linkgit:git-send-email[1] for description.
  
 -sendemail.signedoffcc::
 +sendemail.signedoffcc (deprecated)::
        Deprecated alias for 'sendemail.signedoffbycc'.
  
  showbranch.default::
@@@ -2431,7 -2362,7 +2440,7 @@@ If this variable is not specified, it d
  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
  
  submodule.<name>.path::
  submodule.<name>.url::
 +      The path within this project and URL for a submodule. These
 +      variables are initially populated by 'git submodule init'. See
 +      linkgit:git-submodule[1] and linkgit:gitmodules[5] for
 +      details.
 +
  submodule.<name>.update::
 -      The path within this project, URL, and the updating strategy
 -      for a submodule.  These variables are initially populated
 -      by 'git submodule init'; edit them to override the
 -      URL and other values found in the `.gitmodules` file.  See
 -      linkgit:git-submodule[1] and linkgit:gitmodules[5] for details.
 +      The default update procedure for a submodule. This variable
 +      is populated by `git submodule init` from the
 +      linkgit:gitmodules[5] file. See description of 'update'
 +      command in linkgit:git-submodule[1].
  
  submodule.<name>.branch::
        The remote branch name for a submodule, used by `git submodule
@@@ -2506,9 -2433,9 +2515,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::
@@@ -2523,7 -2450,7 +2532,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
        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
        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::
@@@ -2583,25 -2510,13 +2592,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 d5041082e88349d7c814ae1c036b15841f47a6d0,72def5b689b6e5952be2227e0debf72f2a93b5d6..d263a5652f06777b987eefae4f14f2003d53448b
@@@ -144,7 -144,7 +144,7 @@@ explicitly give a name with '-b' in suc
  
  --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 +210,7 @@@ the conflicted merge in the specified p
  --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).
  
@@@ -225,6 -225,19 +225,19 @@@ This means that you can use `git checko
  edits from your current working tree. See the ``Interactive Mode''
  section of linkgit:git-add[1] to learn how to operate the `--patch` mode.
  
+ --to=<path>::
+       Check out a branch in a separate working directory at
+       `<path>`. A new working directory is linked to the current
+       repository, sharing everything except working directory
+       specific files such as HEAD, index... See "MULTIPLE WORKING
+       TREES" section for more information.
+ --ignore-other-worktrees::
+       `git checkout` refuses when the wanted ref is already checked
+       out by another worktree. This option makes it check the ref
+       out anyway. In other words, the ref can be held by more than one
+       worktree.
  <branch>::
        Branch to checkout; if it refers to a branch (i.e., a name that,
        when prepended with "refs/heads/", is a valid ref), then that
@@@ -388,6 -401,71 +401,71 @@@ $ git reflog -2 HEAD # o
  $ git log -g -2 HEAD
  ------------
  
+ MULTIPLE WORKING TREES
+ ----------------------
+ A git repository can support multiple working trees, allowing you to check
+ out more than one branch at a time.  With `git checkout --to` a new working
+ tree is associated with the repository.  This new working tree is called a
+ "linked working tree" as opposed to the "main working tree" prepared by "git
+ init" or "git clone".  A repository has one main working tree (if it's not a
+ bare repository) and zero or more linked working trees.
+ Each linked working tree has a private sub-directory in the repository's
+ $GIT_DIR/worktrees directory.  The private sub-directory's name is usually
+ the base name of the linked working tree's path, possibly appended with a
+ number to make it unique.  For example, when `$GIT_DIR=/path/main/.git` the
+ command `git checkout --to /path/other/test-next next` creates the linked
+ working tree in `/path/other/test-next` and also creates a
+ `$GIT_DIR/worktrees/test-next` directory (or `$GIT_DIR/worktrees/test-next1`
+ if `test-next` is already taken).
+ Within a linked working tree, $GIT_DIR is set to point to this private
+ directory (e.g. `/path/main/.git/worktrees/test-next` in the example) and
+ $GIT_COMMON_DIR is set to point back to the main working tree's $GIT_DIR
+ (e.g. `/path/main/.git`). These settings are made in a `.git` file located at
+ the top directory of the linked working tree.
+ Path resolution via `git rev-parse --git-path` uses either
+ $GIT_DIR or $GIT_COMMON_DIR depending on the path. For example, in the
+ linked working tree `git rev-parse --git-path HEAD` returns
+ `/path/main/.git/worktrees/test-next/HEAD` (not
+ `/path/other/test-next/.git/HEAD` or `/path/main/.git/HEAD`) while `git
+ rev-parse --git-path refs/heads/master` uses
+ $GIT_COMMON_DIR and returns `/path/main/.git/refs/heads/master`,
+ since refs are shared across all working trees.
+ See linkgit:gitrepository-layout[5] for more information. The rule of
+ thumb is do not make any assumption about whether a path belongs to
+ $GIT_DIR or $GIT_COMMON_DIR when you need to directly access something
+ inside $GIT_DIR. Use `git rev-parse --git-path` to get the final path.
+ When you are done with a linked working tree you can simply delete it.
+ The working tree's entry in the repository's $GIT_DIR/worktrees
+ directory will eventually be removed automatically (see
+ `gc.pruneworktreesexpire` in linkgit::git-config[1]), or you can run
+ `git prune --worktrees` in the main or any linked working tree to
+ clean up any stale entries in $GIT_DIR/worktrees.
+ If you move a linked working directory to another file system, or
+ within a file system that does not support hard links, you need to run
+ at least one git command inside the linked working directory
+ (e.g. `git status`) in order to update its entry in $GIT_DIR/worktrees
+ so that it does not get automatically removed.
+ To prevent a $GIT_DIR/worktrees entry from from being pruned (which
+ can be useful in some situations, such as when the
+ entry's working tree is stored on a portable device), add a file named
+ 'locked' to the entry's directory. The file contains the reason in
+ plain text. For example, if a linked working tree's `.git` file points
+ to `/path/main/.git/worktrees/test-next` then a file named
+ `/path/main/.git/worktrees/test-next/locked` will prevent the
+ `test-next` entry from being pruned.  See
+ linkgit:gitrepository-layout[5] for details.
+ Multiple checkout support for submodules is incomplete. It is NOT
+ recommended to make multiple checkouts of a superproject.
  EXAMPLES
  --------
  
diff --combined Documentation/git.txt
index c71e818cf445d55e793229dd9cb46777e5f53a98,0c2dcfa9cc4f3cc3e3066104ee5a61f0b46fcfde..2789da4f8fb4b06c26cfc27abfecf01392e75ae5
@@@ -43,63 -43,40 +43,63 @@@ unreleased) version of Git, that is ava
  branch of the `git.git` repository.
  Documentation for older releases are available here:
  
 -* link:v2.2.0/git.html[documentation for release 2.2]
 +* link:v2.4.0/git.html[documentation for release 2.4]
  
  * release notes for
 +  link:RelNotes/2.4.0.txt[2.4].
 +
 +* link:v2.3.7/git.html[documentation for release 2.3.7]
 +
 +* release notes for
 +  link:RelNotes/2.3.7.txt[2.3.7],
 +  link:RelNotes/2.3.6.txt[2.3.6],
 +  link:RelNotes/2.3.5.txt[2.3.5],
 +  link:RelNotes/2.3.4.txt[2.3.4],
 +  link:RelNotes/2.3.3.txt[2.3.3],
 +  link:RelNotes/2.3.2.txt[2.3.2],
 +  link:RelNotes/2.3.1.txt[2.3.1],
 +  link:RelNotes/2.3.0.txt[2.3].
 +
 +* link:v2.2.2/git.html[documentation for release 2.2.2]
 +
 +* release notes for
 +  link:RelNotes/2.2.2.txt[2.2.2],
 +  link:RelNotes/2.2.1.txt[2.2.1],
    link:RelNotes/2.2.0.txt[2.2].
  
 -* link:v2.1.3/git.html[documentation for release 2.1.3]
 +* link:v2.1.4/git.html[documentation for release 2.1.4]
  
  * release notes for
 +  link:RelNotes/2.1.4.txt[2.1.4],
    link:RelNotes/2.1.3.txt[2.1.3],
    link:RelNotes/2.1.2.txt[2.1.2],
    link:RelNotes/2.1.1.txt[2.1.1],
    link:RelNotes/2.1.0.txt[2.1].
  
 -* link:v2.0.4/git.html[documentation for release 2.0.4]
 +* link:v2.0.5/git.html[documentation for release 2.0.5]
  
  * release notes for
 +  link:RelNotes/2.0.5.txt[2.0.5],
    link:RelNotes/2.0.4.txt[2.0.4],
    link:RelNotes/2.0.3.txt[2.0.3],
    link:RelNotes/2.0.2.txt[2.0.2],
    link:RelNotes/2.0.1.txt[2.0.1],
    link:RelNotes/2.0.0.txt[2.0.0].
  
 -* link:v1.9.4/git.html[documentation for release 1.9.4]
 +* link:v1.9.5/git.html[documentation for release 1.9.5]
  
  * release notes for
 +  link:RelNotes/1.9.5.txt[1.9.5],
    link:RelNotes/1.9.4.txt[1.9.4],
    link:RelNotes/1.9.3.txt[1.9.3],
    link:RelNotes/1.9.2.txt[1.9.2],
    link:RelNotes/1.9.1.txt[1.9.1],
    link:RelNotes/1.9.0.txt[1.9.0].
  
 -* link:v1.8.5.5/git.html[documentation for release 1.8.5.5]
 +* link:v1.8.5.6/git.html[documentation for release 1.8.5.6]
  
  * release notes for
 +  link:RelNotes/1.8.5.6.txt[1.8.5.6],
    link:RelNotes/1.8.5.5.txt[1.8.5.5],
    link:RelNotes/1.8.5.4.txt[1.8.5.4],
    link:RelNotes/1.8.5.3.txt[1.8.5.3],
@@@ -777,8 -754,7 +777,8 @@@ Git so take care if using Cogito etc
  'GIT_INDEX_VERSION'::
        This environment variable allows the specification of an index
        version for new repositories.  It won't affect existing index
 -      files.  By default index file version [23] is used.
 +      files.  By default index file version 2 or 3 is used. See
 +      linkgit:git-update-index[1] for more information.
  
  'GIT_OBJECT_DIRECTORY'::
        If the object storage directory is specified via this
        an explicit repository directory set via 'GIT_DIR' or on the
        command line.
  
+ 'GIT_COMMON_DIR'::
+       If this variable is set to a path, non-worktree files that are
+       normally in $GIT_DIR will be taken from this path
+       instead. Worktree-specific files such as HEAD or index are
+       taken from $GIT_DIR. See linkgit:gitrepository-layout[5] and
+       the section 'MULTIPLE CHECKOUT MODE' in linkgit:checkout[1]
+       details. This variable has lower precedence than other path
+       variables such as GIT_INDEX_FILE, GIT_OBJECT_DIRECTORY...
  Git Commits
  ~~~~~~~~~~~
  'GIT_AUTHOR_NAME'::
@@@ -905,21 -890,19 +914,21 @@@ othe
        and the `core.editor` option in linkgit:git-config[1].
  
  'GIT_SSH'::
 -      If this environment variable is set then 'git fetch'
 -      and 'git push' will use this command instead
 -      of 'ssh' when they need to connect to a remote system.
 -      The '$GIT_SSH' command will be given exactly two or
 -      four arguments: the 'username@host' (or just 'host')
 -      from the URL and the shell command to execute on that
 -      remote system, optionally preceded by '-p' (literally) and
 -      the 'port' from the URL when it specifies something other
 -      than the default SSH port.
 +'GIT_SSH_COMMAND'::
 +      If either of these environment variables is set then 'git fetch'
 +      and 'git push' will use the specified command instead of 'ssh'
 +      when they need to connect to a remote system.
 +      The command will be given exactly two or four arguments: the
 +      'username@host' (or just 'host') from the URL and the shell
 +      command to execute on that remote system, optionally preceded by
 +      '-p' (literally) and the 'port' from the URL when it specifies
 +      something other than the default SSH port.
  +
 -To pass options to the program that you want to list in GIT_SSH
 -you will need to wrap the program and options into a shell script,
 -then set GIT_SSH to refer to the shell script.
 +`$GIT_SSH_COMMAND` takes precedence over `$GIT_SSH`, and is interpreted
 +by the shell, which allows additional arguments to be included.
 +`$GIT_SSH` on the other hand must be just the path to a program
 +(which can be a wrapper shell script, if additional arguments are
 +needed).
  +
  Usually it is easier to configure any desired options through your
  personal `.ssh/config` file.  Please consult your ssh documentation
@@@ -929,13 -912,9 +938,13 @@@ 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'::
 +      If this environment variable is set to `0`, git will not prompt
 +      on the terminal (e.g., when asking for HTTP authentication).
 +
  'GIT_CONFIG_NOSYSTEM'::
        Whether to skip reading settings from the system-wide
        `$(prefix)/etc/gitconfig` file.  This environment variable can
@@@ -1036,17 -1015,6 +1045,17 @@@ GIT_ICASE_PATHSPECS:
        variable when it is invoked as the top level command by the
        end user, to be recorded in the body of the reflog.
  
 +`GIT_REF_PARANOIA`::
 +      If set to `1`, include broken or badly named refs when iterating
 +      over lists of refs. In a normal, non-corrupted repository, this
 +      does nothing. However, enabling it may help git to detect and
 +      abort some operations in the presence of broken refs. Git sets
 +      this variable automatically when performing destructive
 +      operations like linkgit:git-prune[1]. You should not need to set
 +      it yourself unless you want to be paranoid about making sure
 +      an operation has touched every ref (e.g., because you are
 +      cloning a repository to make a backup).
 +
  
  Discussion[[Discussion]]
  ------------------------
diff --combined builtin/branch.c
index 1d150378e91cd47c4cd555bfc858ec0b7ea9d604,1a475d8e94a2ce98344e8732ace444e35ccd9bfb..258fe2ff9b6d08182b21b765191ee79e9a81f322
  #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,16 -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);
@@@ -771,7 -764,6 +771,6 @@@ static const char edit_description[] = 
  
  static int edit_branch_description(const char *branch_name)
  {
-       FILE *fp;
        int status;
        struct strbuf buf = STRBUF_INIT;
        struct strbuf name = STRBUF_INIT;
                    "  %s\n"
                    "Lines starting with '%c' will be stripped.\n",
                    branch_name, comment_line_char);
-       fp = fopen(git_path(edit_description), "w");
-       if ((fwrite(buf.buf, 1, buf.len, fp) < buf.len) || fclose(fp)) {
+       if (write_file(git_path(edit_description), 0, "%s", buf.buf)) {
                strbuf_release(&buf);
                return error(_("could not write branch description template: %s"),
                             strerror(errno));
  
  int cmd_branch(int argc, const char **argv, const char *prefix)
  {
 -      int delete = 0, rename = 0, force_create = 0, list = 0;
 +      int delete = 0, rename = 0, force = 0, list = 0;
        int verbose = 0, abbrev = -1, detached = 0;
        int reflog = 0, edit_description = 0;
        int quiet = 0, unset_upstream = 0;
                OPT_BOOL('l', "create-reflog", &reflog, N_("create the branch's reflog")),
                OPT_BOOL(0, "edit-description", &edit_description,
                         N_("edit the description for the branch")),
 -              OPT__FORCE(&force_create, N_("force creation (when already exists)")),
 +              OPT__FORCE(&force, N_("force creation, move/rename, deletion")),
                {
                        OPTION_CALLBACK, 0, "no-merged", &merge_filter_ref,
                        N_("commit"), N_("print only not merged branches"),
        if (with_commit || merge_filter != NO_FILTER)
                list = 1;
  
 -      if (!!delete + !!rename + !!force_create + !!new_upstream +
 +      if (!!delete + !!rename + !!new_upstream +
            list + unset_upstream > 1)
                usage_with_options(builtin_branch_usage, options);
  
                colopts = 0;
        }
  
 +      if (force) {
 +              delete *= 2;
 +              rename *= 2;
 +      }
 +
        if (delete) {
                if (!argc)
                        die(_("branch name required"));
  
                branch_existed = ref_exists(branch->refname);
                create_branch(head, argv[0], (argc == 2) ? argv[1] : head,
 -                            force_create, reflog, 0, quiet, track);
 +                            force, reflog, 0, quiet, track);
  
                /*
                 * We only show the instructions if the user gave us
diff --combined builtin/checkout.c
index 4aad49aaa1d984bb6852361118932db0c984491b,8b2bf2093bfe3ce1dbae7d5d7c50886386be6f7b..2f92328db46b4ff81e32b32339ad830c4b76688b
  #include "resolve-undo.h"
  #include "submodule.h"
  #include "argv-array.h"
+ #include "sigchain.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,
  };
  
@@@ -36,6 -37,7 +37,7 @@@ struct checkout_opts 
        int writeout_stage;
        int overwrite_ignore;
        int ignore_skipworktree;
+       int ignore_other_worktrees;
  
        const char *new_branch;
        const char *new_branch_force;
        const char *prefix;
        struct pathspec pathspec;
        struct tree *source_tree;
+       const char *new_worktree;
+       const char **saved_argv;
+       int new_worktree_mode;
  };
  
  static int post_checkout_hook(struct commit *old, struct commit *new,
  
  }
  
 -static int update_some(const unsigned char *sha1, const char *base, int baselen,
 +static int update_some(const unsigned char *sha1, struct strbuf *base,
                const char *pathname, unsigned mode, int stage, void *context)
  {
        int len;
        struct cache_entry *ce;
 +      int pos;
  
        if (S_ISDIR(mode))
                return READ_TREE_RECURSIVE;
  
 -      len = baselen + strlen(pathname);
 +      len = base->len + strlen(pathname);
        ce = xcalloc(1, cache_entry_size(len));
        hashcpy(ce->sha1, sha1);
 -      memcpy(ce->name, base, baselen);
 -      memcpy(ce->name + baselen, pathname, len - baselen);
 +      memcpy(ce->name, base->buf, base->len);
 +      memcpy(ce->name + base->len, pathname, len - base->len);
        ce->ce_flags = create_ce_flags(0) | CE_UPDATE;
        ce->ce_namelen = len;
        ce->ce_mode = create_ce_mode(mode);
 +
 +      /*
 +       * If the entry is the same as the current index, we can leave the old
 +       * entry in place. Whether it is UPTODATE or not, checkout_entry will
 +       * do the right thing.
 +       */
 +      pos = cache_name_pos(ce->name, ce->ce_namelen);
 +      if (pos >= 0) {
 +              struct cache_entry *old = active_cache[pos];
 +              if (ce->ce_mode == old->ce_mode &&
 +                  !hashcmp(ce->sha1, old->sha1)) {
 +                      old->ce_flags |= CE_UPDATE;
 +                      free(ce);
 +                      return 0;
 +              }
 +      }
 +
        add_cache_entry(ce, ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
        return 0;
  }
@@@ -267,6 -255,9 +273,9 @@@ static int checkout_paths(const struct 
                die(_("Cannot update paths and switch to branch '%s' at the same time."),
                    opts->new_branch);
  
+       if (opts->new_worktree)
+               die(_("'%s' cannot be used with updating paths"), "--to");
        if (opts->patch_mode)
                return run_add_interactive(revision, "--patch=checkout",
                                           &opts->pathspec);
@@@ -441,6 -432,11 +450,11 @@@ struct branch_info 
        const char *name; /* The short name used */
        const char *path; /* The full name of a real branch */
        struct commit *commit; /* The named commit */
+       /*
+        * if not null the branch is detached because it's already
+        * checked out in this checkout
+        */
+       char *checkout;
  };
  
  static void setup_branch_path(struct branch_info *branch)
@@@ -502,7 -498,7 +516,7 @@@ static int merge_working_tree(const str
                        topts.dir->flags |= DIR_SHOW_IGNORED;
                        setup_standard_excludes(topts.dir);
                }
-               tree = parse_tree_indirect(old->commit ?
+               tree = parse_tree_indirect(old->commit && !opts->new_worktree_mode ?
                                           old->commit->object.sha1 :
                                           EMPTY_TREE_SHA1_BIN);
                init_tree_desc(&trees[0], tree->buffer, tree->size);
@@@ -606,18 -602,21 +620,21 @@@ static void update_refs_for_switch(cons
                if (opts->new_orphan_branch) {
                        if (opts->new_branch_log && !log_all_ref_updates) {
                                int temp;
-                               char log_file[PATH_MAX];
-                               char *ref_name = mkpath("refs/heads/%s", opts->new_orphan_branch);
+                               struct strbuf log_file = STRBUF_INIT;
+                               int ret;
+                               const char *ref_name;
  
+                               ref_name = mkpath("refs/heads/%s", opts->new_orphan_branch);
                                temp = log_all_ref_updates;
                                log_all_ref_updates = 1;
-                               if (log_ref_setup(ref_name, log_file, sizeof(log_file))) {
+                               ret = log_ref_setup(ref_name, &log_file);
+                               log_all_ref_updates = temp;
+                               strbuf_release(&log_file);
+                               if (ret) {
                                        fprintf(stderr, _("Can not do reflog for '%s'\n"),
                                            opts->new_orphan_branch);
-                                       log_all_ref_updates = temp;
                                        return;
                                }
-                               log_all_ref_updates = temp;
                        }
                }
                else
@@@ -743,17 -742,10 +760,17 @@@ static void suggest_reattach(struct com
  
        if (advice_detached_head)
                fprintf(stderr,
 -                      _(
 +                      Q_(
 +                      /* The singular version */
 +                      "If you want to keep it 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",
 +                      /* The plural version */
                        "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",
 +                      /* Give ngettext() the count */
 +                      lost),
                        find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV));
  }
  
@@@ -822,7 -814,8 +839,8 @@@ static int switch_branches(const struc
                return ret;
        }
  
-       if (!opts->quiet && !old.path && old.commit && new->commit != old.commit)
+       if (!opts->quiet && !old.path && old.commit &&
+           new->commit != old.commit && !opts->new_worktree_mode)
                orphaned_commit_warning(old.commit, new->commit);
  
        update_refs_for_switch(opts, &old, new);
        return ret || writeout_error;
  }
  
+ static char *junk_work_tree;
+ static char *junk_git_dir;
+ static int is_junk;
+ static pid_t junk_pid;
+ static void remove_junk(void)
+ {
+       struct strbuf sb = STRBUF_INIT;
+       if (!is_junk || getpid() != junk_pid)
+               return;
+       if (junk_git_dir) {
+               strbuf_addstr(&sb, junk_git_dir);
+               remove_dir_recursively(&sb, 0);
+               strbuf_reset(&sb);
+       }
+       if (junk_work_tree) {
+               strbuf_addstr(&sb, junk_work_tree);
+               remove_dir_recursively(&sb, 0);
+       }
+       strbuf_release(&sb);
+ }
+ static void remove_junk_on_signal(int signo)
+ {
+       remove_junk();
+       sigchain_pop(signo);
+       raise(signo);
+ }
+ static int prepare_linked_checkout(const struct checkout_opts *opts,
+                                  struct branch_info *new)
+ {
+       struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;
+       struct strbuf sb = STRBUF_INIT;
+       const char *path = opts->new_worktree, *name;
+       struct stat st;
+       struct child_process cp;
+       int counter = 0, len, ret;
+       if (!new->commit)
+               die(_("no branch specified"));
+       if (file_exists(path) && !is_empty_dir(path))
+               die(_("'%s' already exists"), path);
+       len = strlen(path);
+       while (len && is_dir_sep(path[len - 1]))
+               len--;
+       for (name = path + len - 1; name > path; name--)
+               if (is_dir_sep(*name)) {
+                       name++;
+                       break;
+               }
+       strbuf_addstr(&sb_repo,
+                     git_path("worktrees/%.*s", (int)(path + len - name), name));
+       len = sb_repo.len;
+       if (safe_create_leading_directories_const(sb_repo.buf))
+               die_errno(_("could not create leading directories of '%s'"),
+                         sb_repo.buf);
+       while (!stat(sb_repo.buf, &st)) {
+               counter++;
+               strbuf_setlen(&sb_repo, len);
+               strbuf_addf(&sb_repo, "%d", counter);
+       }
+       name = strrchr(sb_repo.buf, '/') + 1;
+       junk_pid = getpid();
+       atexit(remove_junk);
+       sigchain_push_common(remove_junk_on_signal);
+       if (mkdir(sb_repo.buf, 0777))
+               die_errno(_("could not create directory of '%s'"), sb_repo.buf);
+       junk_git_dir = xstrdup(sb_repo.buf);
+       is_junk = 1;
+       /*
+        * lock the incomplete repo so prune won't delete it, unlock
+        * after the preparation is over.
+        */
+       strbuf_addf(&sb, "%s/locked", sb_repo.buf);
+       write_file(sb.buf, 1, "initializing\n");
+       strbuf_addf(&sb_git, "%s/.git", path);
+       if (safe_create_leading_directories_const(sb_git.buf))
+               die_errno(_("could not create leading directories of '%s'"),
+                         sb_git.buf);
+       junk_work_tree = xstrdup(path);
+       strbuf_reset(&sb);
+       strbuf_addf(&sb, "%s/gitdir", sb_repo.buf);
+       write_file(sb.buf, 1, "%s\n", real_path(sb_git.buf));
+       write_file(sb_git.buf, 1, "gitdir: %s/worktrees/%s\n",
+                  real_path(get_git_common_dir()), name);
+       /*
+        * This is to keep resolve_ref() happy. We need a valid HEAD
+        * or is_git_directory() will reject the directory. Any valid
+        * value would do because this value will be ignored and
+        * replaced at the next (real) checkout.
+        */
+       strbuf_reset(&sb);
+       strbuf_addf(&sb, "%s/HEAD", sb_repo.buf);
+       write_file(sb.buf, 1, "%s\n", sha1_to_hex(new->commit->object.sha1));
+       strbuf_reset(&sb);
+       strbuf_addf(&sb, "%s/commondir", sb_repo.buf);
+       write_file(sb.buf, 1, "../..\n");
+       if (!opts->quiet)
+               fprintf_ln(stderr, _("Enter %s (identifier %s)"), path, name);
+       setenv("GIT_CHECKOUT_NEW_WORKTREE", "1", 1);
+       setenv(GIT_DIR_ENVIRONMENT, sb_git.buf, 1);
+       setenv(GIT_WORK_TREE_ENVIRONMENT, path, 1);
+       memset(&cp, 0, sizeof(cp));
+       cp.git_cmd = 1;
+       cp.argv = opts->saved_argv;
+       ret = run_command(&cp);
+       if (!ret) {
+               is_junk = 0;
+               free(junk_work_tree);
+               free(junk_git_dir);
+               junk_work_tree = NULL;
+               junk_git_dir = NULL;
+       }
+       strbuf_reset(&sb);
+       strbuf_addf(&sb, "%s/locked", sb_repo.buf);
+       unlink_or_warn(sb.buf);
+       strbuf_release(&sb);
+       strbuf_release(&sb_repo);
+       strbuf_release(&sb_git);
+       return ret;
+ }
  static int git_checkout_config(const char *var, const char *value, void *cb)
  {
        if (!strcmp(var, "diff.ignoresubmodules")) {
@@@ -887,13 -1012,80 +1037,80 @@@ static const char *unique_tracking_name
        return NULL;
  }
  
+ static void check_linked_checkout(struct branch_info *new, const char *id)
+ {
+       struct strbuf sb = STRBUF_INIT;
+       struct strbuf path = STRBUF_INIT;
+       struct strbuf gitdir = STRBUF_INIT;
+       const char *start, *end;
+       if (id)
+               strbuf_addf(&path, "%s/worktrees/%s/HEAD", get_git_common_dir(), id);
+       else
+               strbuf_addf(&path, "%s/HEAD", get_git_common_dir());
+       if (strbuf_read_file(&sb, path.buf, 0) < 0 ||
+           !skip_prefix(sb.buf, "ref:", &start))
+               goto done;
+       while (isspace(*start))
+               start++;
+       end = start;
+       while (*end && !isspace(*end))
+               end++;
+       if (strncmp(start, new->path, end - start) || new->path[end - start] != '\0')
+               goto done;
+       if (id) {
+               strbuf_reset(&path);
+               strbuf_addf(&path, "%s/worktrees/%s/gitdir", get_git_common_dir(), id);
+               if (strbuf_read_file(&gitdir, path.buf, 0) <= 0)
+                       goto done;
+               strbuf_rtrim(&gitdir);
+       } else
+               strbuf_addstr(&gitdir, get_git_common_dir());
+       die(_("'%s' is already checked out at '%s'"), new->name, gitdir.buf);
+ done:
+       strbuf_release(&path);
+       strbuf_release(&sb);
+       strbuf_release(&gitdir);
+ }
+ static void check_linked_checkouts(struct branch_info *new)
+ {
+       struct strbuf path = STRBUF_INIT;
+       DIR *dir;
+       struct dirent *d;
+       strbuf_addf(&path, "%s/worktrees", get_git_common_dir());
+       if ((dir = opendir(path.buf)) == NULL) {
+               strbuf_release(&path);
+               return;
+       }
+       /*
+        * $GIT_COMMON_DIR/HEAD is practically outside
+        * $GIT_DIR so resolve_ref_unsafe() won't work (it
+        * uses git_path). Parse the ref ourselves.
+        */
+       check_linked_checkout(new, NULL);
+       while ((d = readdir(dir)) != NULL) {
+               if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
+                       continue;
+               check_linked_checkout(new, d->d_name);
+       }
+       strbuf_release(&path);
+       closedir(dir);
+ }
  static int parse_branchname_arg(int argc, const char **argv,
                                int dwim_new_local_branch_ok,
                                struct branch_info *new,
-                               struct tree **source_tree,
-                               unsigned char rev[20],
-                               const char **new_branch)
+                               struct checkout_opts *opts,
+                               unsigned char rev[20])
  {
+       struct tree **source_tree = &opts->source_tree;
+       const char **new_branch = &opts->new_branch;
+       int force_detach = opts->force_detach;
        int argcount = 0;
        unsigned char branch_rev[20];
        const char *arg;
        else
                new->path = NULL; /* not an existing branch */
  
+       if (new->path && !force_detach && !*new_branch) {
+               unsigned char sha1[20];
+               int flag;
+               char *head_ref = resolve_refdup("HEAD", 0, sha1, &flag);
+               if (head_ref &&
+                   (!(flag & REF_ISSYMREF) || strcmp(head_ref, new->path)) &&
+                   !opts->ignore_other_worktrees)
+                       check_linked_checkouts(new);
+               free(head_ref);
+       }
        new->commit = lookup_commit_reference_gently(rev, 1);
        if (!new->commit) {
                /* not a commit */
@@@ -1093,6 -1296,9 +1321,9 @@@ static int checkout_branch(struct check
                die(_("Cannot switch branch to a non-commit '%s'"),
                    new->name);
  
+       if (opts->new_worktree)
+               return prepare_linked_checkout(opts, new);
        if (!new->commit && opts->new_branch) {
                unsigned char rev[20];
                int flag;
@@@ -1134,7 -1340,11 +1365,11 @@@ int cmd_checkout(int argc, const char *
                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_FILENAME(0, "to", &opts.new_worktree,
+                          N_("check a branch out in a separate working directory")),
+               OPT_BOOL(0, "ignore-other-worktrees", &opts.ignore_other_worktrees,
+                        N_("do not check if another worktree is holding the given ref")),
                OPT_END(),
        };
  
        opts.overwrite_ignore = 1;
        opts.prefix = prefix;
  
+       opts.saved_argv = xmalloc(sizeof(const char *) * (argc + 2));
+       memcpy(opts.saved_argv, argv, sizeof(const char *) * (argc + 1));
        gitmodules_config();
        git_config(git_checkout_config, &opts);
  
        argc = parse_options(argc, argv, prefix, options, checkout_usage,
                             PARSE_OPT_KEEP_DASHDASH);
  
+       /* recursive execution from checkout_new_worktree() */
+       opts.new_worktree_mode = getenv("GIT_CHECKOUT_NEW_WORKTREE") != NULL;
+       if (opts.new_worktree_mode)
+               opts.new_worktree = NULL;
+       if (!opts.new_worktree)
+               setup_work_tree();
        if (conflict_style) {
                opts.merge = 1; /* implied */
                git_xmerge_config("merge.conflictstyle", conflict_style, NULL);
                        opts.track == BRANCH_TRACK_UNSPECIFIED &&
                        !opts.new_branch;
                int n = parse_branchname_arg(argc, argv, dwim_ok,
-                                            &new, &opts.source_tree,
-                                            rev, &opts.new_branch);
+                                            &new, &opts, rev);
                argv += n;
                argc -= n;
        }
diff --combined builtin/clone.c
index 53a2e5af35ebfc37b378442a238f1894e5bec962,a9af3f2bdec263742e52e30875502b5f6893f9ef..166a645e2dcedc66b1d2f20ca01010a5ae2ee9d8
@@@ -34,7 -34,7 +34,7 @@@
   *
   */
  static const char * const builtin_clone_usage[] = {
 -      N_("git clone [options] [--] <repo> [<dir>]"),
 +      N_("git clone [<options>] [--] <repo> [<dir>]"),
        NULL
  };
  
@@@ -49,7 -49,6 +49,7 @@@ static int option_verbosity
  static int option_progress = -1;
  static struct string_list option_config;
  static struct string_list option_reference;
 +static int option_dissociate;
  
  static int opt_parse_reference(const struct option *opt, const char *arg, int unset)
  {
@@@ -95,8 -94,6 +95,8 @@@ static struct option builtin_clone_opti
                    N_("create a shallow clone of that depth")),
        OPT_BOOL(0, "single-branch", &option_single_branch,
                    N_("clone only one branch, HEAD or --branch")),
 +      OPT_BOOL(0, "dissociate", &option_dissociate,
 +               N_("use --reference only while cloning")),
        OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"),
                   N_("separate git dir from working tree")),
        OPT_STRING_LIST('c', "config", &option_config, N_("key=value"),
@@@ -293,16 -290,17 +293,17 @@@ static void copy_alternates(struct strb
        struct strbuf line = STRBUF_INIT;
  
        while (strbuf_getline(&line, in, '\n') != EOF) {
-               char *abs_path, abs_buf[PATH_MAX];
+               char *abs_path;
                if (!line.len || line.buf[0] == '#')
                        continue;
                if (is_absolute_path(line.buf)) {
                        add_to_alternates_file(line.buf);
                        continue;
                }
-               abs_path = mkpath("%s/objects/%s", src_repo, line.buf);
-               normalize_path_copy(abs_buf, abs_path);
-               add_to_alternates_file(abs_buf);
+               abs_path = mkpathdup("%s/objects/%s", src_repo, line.buf);
+               normalize_path_copy(abs_path, abs_path);
+               add_to_alternates_file(abs_path);
+               free(abs_path);
        }
        strbuf_release(&line);
        fclose(in);
@@@ -738,16 -736,6 +739,16 @@@ static void write_refspec_config(const 
        strbuf_release(&value);
  }
  
 +static void dissociate_from_references(void)
 +{
 +      static const char* argv[] = { "repack", "-a", "-d", NULL };
 +
 +      if (run_command_v_opt(argv, RUN_GIT_CMD|RUN_COMMAND_NO_STDIN))
 +              die(_("cannot repack to clean up"));
 +      if (unlink(git_path("objects/info/alternates")) && errno != ENOENT)
 +              die_errno(_("cannot unlink temporary alternates file"));
 +}
 +
  int cmd_clone(int argc, const char **argv, const char *prefix)
  {
        int is_bundle = 0, is_local;
                git_dir = mkpathdup("%s/.git", dir);
        }
  
 +      atexit(remove_junk);
 +      sigchain_push_common(remove_junk_on_signal);
 +
        if (!option_bare) {
 -              junk_work_tree = work_tree;
                if (safe_create_leading_directories_const(work_tree) < 0)
                        die_errno(_("could not create leading directories of '%s'"),
                                  work_tree);
                if (!dest_exists && mkdir(work_tree, 0777))
 -                      die_errno(_("could not create work tree dir '%s'."),
 +                      die_errno(_("could not create work tree dir '%s'"),
                                  work_tree);
 +              junk_work_tree = work_tree;
                set_git_work_tree(work_tree);
        }
 -      junk_git_dir = git_dir;
 -      atexit(remove_junk);
 -      sigchain_push_common(remove_junk_on_signal);
  
 +      junk_git_dir = git_dir;
        if (safe_create_leading_directories_const(git_dir) < 0)
                die(_("could not create leading directories of '%s'"), git_dir);
  
  
        if (option_reference.nr)
                setup_reference();
 +      else if (option_dissociate) {
 +              warning(_("--dissociate given, but there is no --reference"));
 +              option_dissociate = 0;
 +      }
  
        fetch_pattern = value.buf;
        refspec = parse_fetch_refspec(1, &fetch_pattern);
        transport_unlock_pack(transport);
        transport_disconnect(transport);
  
 +      if (option_dissociate)
 +              dissociate_from_references();
 +
        junk_mode = JUNK_LEAVE_REPO;
        err = checkout();
  
diff --combined builtin/commit.c
index da79ac4bc7a7247017e2f952b35642a1976c8101,3f02686800a3c964d40d1cdb22608c38d62039a9..310674cfd0f25c52b9952678eeb3ee164fd97fea
  #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
  };
  
@@@ -170,7 -170,7 +170,7 @@@ static void determine_whence(struct wt_
                whence = FROM_MERGE;
        else if (file_exists(git_path("CHERRY_PICK_HEAD"))) {
                whence = FROM_CHERRY_PICK;
-               if (file_exists(git_path("sequencer")))
+               if (file_exists(git_path(SEQ_DIR)))
                        sequencer_in_use = 1;
        }
        else
@@@ -229,7 -229,7 +229,7 @@@ static int commit_index_files(void
  static int list_paths(struct string_list *list, const char *with_tree,
                      const char *prefix, const struct pathspec *pattern)
  {
 -      int i;
 +      int i, ret;
        char *m;
  
        if (!pattern->nr)
                        item->util = item; /* better a valid pointer than a fake one */
        }
  
 -      return report_path_error(m, pattern, prefix);
 +      ret = report_path_error(m, pattern, prefix);
 +      free(m);
 +      return ret;
  }
  
  static void add_remove_files(struct string_list *list)
@@@ -524,12 -522,6 +524,12 @@@ static int is_a_merge(const struct comm
        return !!(current_head->parents && current_head->parents->next);
  }
  
 +static void assert_split_ident(struct ident_split *id, const struct strbuf *buf)
 +{
 +      if (split_ident_line(id, buf->buf, buf->len) || !id->date_begin)
 +              die("BUG: unable to parse our own ident: %s", buf->buf);
 +}
 +
  static void export_one(const char *var, const char *s, const char *e, int hack)
  {
        struct strbuf buf = STRBUF_INIT;
        strbuf_release(&buf);
  }
  
 -static int sane_ident_split(struct ident_split *person)
 -{
 -      if (!person->name_begin || !person->name_end ||
 -          person->name_begin == person->name_end)
 -              return 0; /* no human readable name */
 -      if (!person->mail_begin || !person->mail_end ||
 -          person->mail_begin == person->mail_end)
 -              return 0; /* no usable mail */
 -      if (!person->date_begin || !person->date_end ||
 -          !person->tz_begin || !person->tz_end)
 -              return 0;
 -      return 1;
 -}
 -
  static int parse_force_date(const char *in, struct strbuf *out)
  {
        strbuf_addch(out, '@');
@@@ -561,14 -567,20 +561,14 @@@ static void set_ident_var(char **buf, c
        *buf = val;
  }
  
 -static char *envdup(const char *var)
 -{
 -      const char *val = getenv(var);
 -      return val ? xstrdup(val) : NULL;
 -}
 -
  static void determine_author_info(struct strbuf *author_ident)
  {
        char *name, *email, *date;
        struct ident_split author;
  
 -      name = envdup("GIT_AUTHOR_NAME");
 -      email = envdup("GIT_AUTHOR_EMAIL");
 -      date = envdup("GIT_AUTHOR_DATE");
 +      name = xstrdup_or_null(getenv("GIT_AUTHOR_NAME"));
 +      email = xstrdup_or_null(getenv("GIT_AUTHOR_EMAIL"));
 +      date = xstrdup_or_null(getenv("GIT_AUTHOR_DATE"));
  
        if (author_message) {
                struct ident_split ident;
        }
  
        strbuf_addstr(author_ident, fmt_ident(name, email, date, IDENT_STRICT));
 -      if (!split_ident_line(&author, author_ident->buf, author_ident->len) &&
 -          sane_ident_split(&author)) {
 -              export_one("GIT_AUTHOR_NAME", author.name_begin, author.name_end, 0);
 -              export_one("GIT_AUTHOR_EMAIL", author.mail_begin, author.mail_end, 0);
 -              export_one("GIT_AUTHOR_DATE", author.date_begin, author.tz_end, '@');
 -      }
 -
 +      assert_split_ident(&author, author_ident);
 +      export_one("GIT_AUTHOR_NAME", author.name_begin, author.name_end, 0);
 +      export_one("GIT_AUTHOR_EMAIL", author.mail_begin, author.mail_end, 0);
 +      export_one("GIT_AUTHOR_DATE", author.date_begin, author.tz_end, '@');
        free(name);
        free(email);
        free(date);
  }
  
 -static void split_ident_or_die(struct ident_split *id, const struct strbuf *buf)
 -{
 -      if (split_ident_line(id, buf->buf, buf->len) ||
 -          !sane_ident_split(id))
 -              die(_("Malformed ident string: '%s'"), buf->buf);
 -}
 -
  static int author_date_is_interesting(void)
  {
        return author_message || force_date;
@@@ -778,8 -800,32 +778,8 @@@ static int prepare_to_commit(const cha
        if (clean_message_contents)
                stripspace(&sb, 0);
  
 -      if (signoff) {
 -              /*
 -               * See if we have a Conflicts: block at the end. If yes, count
 -               * its size, so we can ignore it.
 -               */
 -              int ignore_footer = 0;
 -              int i, eol, previous = 0;
 -              const char *nl;
 -
 -              for (i = 0; i < sb.len; i++) {
 -                      nl = memchr(sb.buf + i, '\n', sb.len - i);
 -                      if (nl)
 -                              eol = nl - sb.buf;
 -                      else
 -                              eol = sb.len;
 -                      if (starts_with(sb.buf + previous, "\nConflicts:\n")) {
 -                              ignore_footer = sb.len - previous;
 -                              break;
 -                      }
 -                      while (i < eol)
 -                              i++;
 -                      previous = eol;
 -              }
 -
 -              append_signoff(&sb, ignore_footer, 0);
 -      }
 +      if (signoff)
 +              append_signoff(&sb, ignore_non_trailer(&sb), 0);
  
        if (fwrite(sb.buf, 1, sb.len, s->fp) < sb.len)
                die_errno(_("could not write commit template"));
                        status_printf_ln(s, GIT_COLOR_NORMAL,
                                        "%s", only_include_assumed);
  
 -              split_ident_or_die(&ai, author_ident);
 -              split_ident_or_die(&ci, &committer_ident);
 +              /*
 +               * These should never fail because they come from our own
 +               * fmt_ident. They may fail the sane_ident test, but we know
 +               * that the name and mail pointers will at least be valid,
 +               * which is enough for our tests and printing here.
 +               */
 +              assert_split_ident(&ai, author_ident);
 +              assert_split_ident(&ci, &committer_ident);
  
                if (ident_cmp(&ai, &ci))
                        status_printf_ln(s, GIT_COLOR_NORMAL,
@@@ -1052,7 -1092,7 +1052,7 @@@ static const char *find_author_by_nickn
                clear_mailmap(&mailmap);
                return strbuf_detach(&buf, NULL);
        }
 -      die(_("No existing author found with '%s'"), name);
 +      die(_("--author '%s' is not 'Name <email>' and matches no existing author"), name);
  }
  
  
@@@ -1768,8 -1808,8 +1768,8 @@@ int cmd_commit(int argc, const char **a
        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);
diff --combined builtin/fetch.c
index f9512652cf1389a770bd94fd170d123206e024c5,cb54936df02516d91a4902a91e45692fc8c23d92..7910419c93275c58f4881202905ae1f24bfe8c91
@@@ -11,6 -11,7 +11,6 @@@
  #include "run-command.h"
  #include "parse-options.h"
  #include "sigchain.h"
 -#include "transport.h"
  #include "submodule.h"
  #include "connected.h"
  #include "argv-array.h"
@@@ -415,10 -416,8 +415,10 @@@ static int s_update_ref(const char *act
  
        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);
@@@ -588,7 -587,8 +588,8 @@@ static int store_updated_refs(const cha
        struct strbuf note = STRBUF_INIT;
        const char *what, *kind;
        struct ref *rm;
-       char *url, *filename = dry_run ? "/dev/null" : git_path("FETCH_HEAD");
+       char *url;
+       const char *filename = dry_run ? "/dev/null" : git_path("FETCH_HEAD");
        int want_status;
  
        fp = fopen(filename, "a");
@@@ -822,7 -822,7 +823,7 @@@ static void check_not_current_branch(st
  
  static int truncate_fetch_head(void)
  {
-       char *filename = git_path("FETCH_HEAD");
+       const char *filename = git_path("FETCH_HEAD");
        FILE *fp = fopen(filename, "w");
  
        if (!fp)
diff --combined builtin/fsck.c
index 0c757862e8cd414c087b27a608281b66c8608a4b,b92aefff422083e43afc624e90d982eb2ed9a876..4783896fd65f0206f3382bddc68a0dad8b5dd896
@@@ -225,12 -225,12 +225,12 @@@ static void check_unreachable_object(st
                        printf("dangling %s %s\n", typename(obj->type),
                               sha1_to_hex(obj->sha1));
                if (write_lost_and_found) {
-                       char *filename = git_path("lost-found/%s/%s",
+                       const char *filename = git_path("lost-found/%s/%s",
                                obj->type == OBJ_COMMIT ? "commit" : "other",
                                sha1_to_hex(obj->sha1));
                        FILE *f;
  
-                       if (safe_create_leading_directories(filename)) {
+                       if (safe_create_leading_directories_const(filename)) {
                                error("Could not create lost-found");
                                return;
                        }
@@@ -600,7 -600,7 +600,7 @@@ static int fsck_cache_tree(struct cache
  }
  
  static char const * const fsck_usage[] = {
 -      N_("git fsck [options] [<object>...]"),
 +      N_("git fsck [<options>] [<object>...]"),
        NULL
  };
  
diff --combined builtin/gc.c
index 5c634afc0022c0ea7a8cd8c81727935ad79a6333,fa87ad355ccebfe22f8e5dc5f90586b482020f0e..36fe33300f644fc9c7e5139b452a9703548ba2a2
@@@ -21,7 -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
  };
  
@@@ -33,11 -33,13 +33,13 @@@ static int gc_auto_threshold = 6700
  static int gc_auto_pack_limit = 50;
  static int detach_auto = 1;
  static const char *prune_expire = "2.weeks.ago";
+ static const char *prune_worktrees_expire = "3.months.ago";
  
  static struct argv_array pack_refs_cmd = ARGV_ARRAY_INIT;
  static struct argv_array reflog = ARGV_ARRAY_INIT;
  static struct argv_array repack = ARGV_ARRAY_INIT;
  static struct argv_array prune = ARGV_ARRAY_INIT;
+ static struct argv_array prune_worktrees = ARGV_ARRAY_INIT;
  static struct argv_array rerere = ARGV_ARRAY_INIT;
  
  static char *pidfile;
@@@ -55,6 -57,17 +57,17 @@@ static void remove_pidfile_on_signal(in
        raise(signo);
  }
  
+ static void git_config_date_string(const char *key, const char **output)
+ {
+       if (git_config_get_string_const(key, output))
+               return;
+       if (strcmp(*output, "now")) {
+               unsigned long now = approxidate("now");
+               if (approxidate(*output) >= now)
+                       git_die_config(key, _("Invalid %s: '%s'"), key, *output);
+       }
+ }
  static void gc_config(void)
  {
        const char *value;
        git_config_get_int("gc.auto", &gc_auto_threshold);
        git_config_get_int("gc.autopacklimit", &gc_auto_pack_limit);
        git_config_get_bool("gc.autodetach", &detach_auto);
-       if (!git_config_get_string_const("gc.pruneexpire", &prune_expire)) {
-               if (strcmp(prune_expire, "now")) {
-                       unsigned long now = approxidate("now");
-                       if (approxidate(prune_expire) >= now) {
-                               git_die_config("gc.pruneexpire", _("Invalid gc.pruneexpire: '%s'"),
-                                               prune_expire);
-                       }
-               }
-       }
+       git_config_date_string("gc.pruneexpire", &prune_expire);
+       git_config_date_string("gc.pruneworktreesexpire", &prune_worktrees_expire);
        git_config(git_default_config, NULL);
  }
  
@@@ -287,7 -292,8 +292,8 @@@ int cmd_gc(int argc, const char **argv
        argv_array_pushl(&pack_refs_cmd, "pack-refs", "--all", "--prune", NULL);
        argv_array_pushl(&reflog, "reflog", "expire", "--all", NULL);
        argv_array_pushl(&repack, "repack", "-d", "-l", NULL);
-       argv_array_pushl(&prune, "prune", "--expire", NULL );
+       argv_array_pushl(&prune, "prune", "--expire", NULL);
+       argv_array_pushl(&prune_worktrees, "prune", "--worktrees", "--expire", NULL);
        argv_array_pushl(&rerere, "rerere", "gc", NULL);
  
        gc_config();
                        return error(FAILED_RUN, prune.argv[0]);
        }
  
+       if (prune_worktrees_expire) {
+               argv_array_push(&prune_worktrees, prune_worktrees_expire);
+               if (run_command_v_opt(prune_worktrees.argv, RUN_GIT_CMD))
+                       return error(FAILED_RUN, prune_worktrees.argv[0]);
+       }
        if (run_command_v_opt(rerere.argv, RUN_GIT_CMD))
                return error(FAILED_RUN, rerere.argv[0]);
  
diff --combined builtin/init-db.c
index ab9f86b8890ed99547144096ff56c3cbef780505,6b7fa5f21ab524d2749099b5e7dd22ac6498cf02..4335738135df32aeea3712cbdae88bd862015969
@@@ -119,18 -119,15 +119,18 @@@ static void copy_templates(const char *
        DIR *dir;
        const char *git_dir = get_git_dir();
        int len = strlen(git_dir);
 +      char *to_free = NULL;
  
        if (!template_dir)
                template_dir = getenv(TEMPLATE_DIR_ENVIRONMENT);
        if (!template_dir)
                template_dir = init_db_template_dir;
        if (!template_dir)
 -              template_dir = system_path(DEFAULT_GIT_TEMPLATE_DIR);
 -      if (!template_dir[0])
 +              template_dir = to_free = system_path(DEFAULT_GIT_TEMPLATE_DIR);
 +      if (!template_dir[0]) {
 +              free(to_free);
                return;
 +      }
        template_len = strlen(template_dir);
        if (PATH_MAX <= (template_len+strlen("/config")))
                die(_("insanely long template path %s"), template_dir);
        dir = opendir(template_path);
        if (!dir) {
                warning(_("templates not found %s"), template_dir);
 -              return;
 +              goto free_return;
        }
  
        /* Make sure that template is from the correct vintage */
                        "a wrong format version %d from '%s'"),
                        repository_format_version,
                        template_dir);
 -              closedir(dir);
 -              return;
 +              goto close_free_return;
        }
  
        memcpy(path, git_dir, len);
        copy_templates_1(path, len,
                         template_path, template_len,
                         dir);
 +close_free_return:
        closedir(dir);
 +free_return:
 +      free(to_free);
  }
  
  static int git_init_db_config(const char *k, const char *v, void *cb)
        return 0;
  }
  
 +/*
 + * If the git_dir is not directly inside the working tree, then git will not
 + * find it by default, and we need to set the worktree explicitly.
 + */
 +static int needs_work_tree_config(const char *git_dir, const char *work_tree)
 +{
 +      if (!strcmp(work_tree, "/") && !strcmp(git_dir, "/.git"))
 +              return 0;
 +      if (skip_prefix(git_dir, work_tree, &git_dir) &&
 +          !strcmp(git_dir, "/.git"))
 +              return 0;
 +      return 1;
 +}
 +
  static int create_default_files(const char *template_path)
  {
        const char *git_dir = get_git_dir();
                struct stat st2;
                filemode = (!chmod(path, st1.st_mode ^ S_IXUSR) &&
                                !lstat(path, &st2) &&
 -                              st1.st_mode != st2.st_mode);
 +                              st1.st_mode != st2.st_mode &&
 +                              !chmod(path, st1.st_mode));
 +              if (filemode && !reinit && (st1.st_mode & S_IXUSR))
 +                      filemode = 0;
        }
        git_config_set("core.filemode", filemode ? "true" : "false");
  
                /* allow template config file to override the default */
                if (log_all_ref_updates == -1)
                    git_config_set("core.logallrefupdates", "true");
 -              if (!starts_with(git_dir, work_tree) ||
 -                  strcmp(git_dir + strlen(work_tree), "/.git")) {
 +              if (needs_work_tree_config(git_dir, work_tree))
                        git_config_set("core.worktree", work_tree);
 -              }
        }
  
        if (!reinit) {
@@@ -362,7 -342,6 +362,6 @@@ int set_git_dir_init(const char *git_di
  static void separate_git_dir(const char *git_dir)
  {
        struct stat st;
-       FILE *fp;
  
        if (!stat(git_link, &st)) {
                const char *src;
                        die_errno(_("unable to move %s to %s"), src, git_dir);
        }
  
-       fp = fopen(git_link, "w");
-       if (!fp)
-               die(_("Could not create git link %s"), git_link);
-       fprintf(fp, "gitdir: %s\n", git_dir);
-       fclose(fp);
+       write_file(git_link, 1, "gitdir: %s\n", git_dir);
  }
  
  int init_db(const char *template_dir, unsigned int flags)
@@@ -484,7 -459,7 +479,7 @@@ static int shared_callback(const struc
  }
  
  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
  };
  
diff --combined builtin/prune.c
index 17094ad954c9da68bc5e251dce1a87ec67c00146,86282b244758d7c248dc2829291c8b6b05a4708e..0c73246c721b3307f0d68b4e58f7c684aebce2e9
@@@ -76,6 -76,95 +76,95 @@@ static int prune_subdir(int nr, const c
        return 0;
  }
  
+ static int prune_worktree(const char *id, struct strbuf *reason)
+ {
+       struct stat st;
+       char *path;
+       int fd, len;
+       if (!is_directory(git_path("worktrees/%s", id))) {
+               strbuf_addf(reason, _("Removing worktrees/%s: not a valid directory"), id);
+               return 1;
+       }
+       if (file_exists(git_path("worktrees/%s/locked", id)))
+               return 0;
+       if (stat(git_path("worktrees/%s/gitdir", id), &st)) {
+               strbuf_addf(reason, _("Removing worktrees/%s: gitdir file does not exist"), id);
+               return 1;
+       }
+       fd = open(git_path("worktrees/%s/gitdir", id), O_RDONLY);
+       if (fd < 0) {
+               strbuf_addf(reason, _("Removing worktrees/%s: unable to read gitdir file (%s)"),
+                           id, strerror(errno));
+               return 1;
+       }
+       len = st.st_size;
+       path = xmalloc(len + 1);
+       read_in_full(fd, path, len);
+       close(fd);
+       while (len && (path[len - 1] == '\n' || path[len - 1] == '\r'))
+               len--;
+       if (!len) {
+               strbuf_addf(reason, _("Removing worktrees/%s: invalid gitdir file"), id);
+               free(path);
+               return 1;
+       }
+       path[len] = '\0';
+       if (!file_exists(path)) {
+               struct stat st_link;
+               free(path);
+               /*
+                * the repo is moved manually and has not been
+                * accessed since?
+                */
+               if (!stat(git_path("worktrees/%s/link", id), &st_link) &&
+                   st_link.st_nlink > 1)
+                       return 0;
+               if (st.st_mtime <= expire) {
+                       strbuf_addf(reason, _("Removing worktrees/%s: gitdir file points to non-existent location"), id);
+                       return 1;
+               } else {
+                       return 0;
+               }
+       }
+       free(path);
+       return 0;
+ }
+ static void prune_worktrees(void)
+ {
+       struct strbuf reason = STRBUF_INIT;
+       struct strbuf path = STRBUF_INIT;
+       DIR *dir = opendir(git_path("worktrees"));
+       struct dirent *d;
+       int ret;
+       if (!dir)
+               return;
+       while ((d = readdir(dir)) != NULL) {
+               if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
+                       continue;
+               strbuf_reset(&reason);
+               if (!prune_worktree(d->d_name, &reason))
+                       continue;
+               if (show_only || verbose)
+                       printf("%s\n", reason.buf);
+               if (show_only)
+                       continue;
+               strbuf_reset(&path);
+               strbuf_addstr(&path, git_path("worktrees/%s", d->d_name));
+               ret = remove_dir_recursively(&path, 0);
+               if (ret < 0 && errno == ENOTDIR)
+                       ret = unlink(path.buf);
+               if (ret)
+                       error(_("failed to remove: %s"), strerror(errno));
+       }
+       closedir(dir);
+       if (!show_only)
+               rmdir(git_path("worktrees"));
+       strbuf_release(&reason);
+       strbuf_release(&path);
+ }
  /*
   * Write errors (particularly out of space) can result in
   * failed temporary packs (and more rarely indexes and other
@@@ -102,10 -191,12 +191,12 @@@ int cmd_prune(int argc, const char **ar
  {
        struct rev_info revs;
        struct progress *progress = NULL;
+       int do_prune_worktrees = 0;
        const struct option options[] = {
                OPT__DRY_RUN(&show_only, N_("do not remove, show only")),
                OPT__VERBOSE(&verbose, N_("report pruned objects")),
                OPT_BOOL(0, "progress", &show_progress, N_("show progress")),
+               OPT_BOOL(0, "worktrees", &do_prune_worktrees, N_("prune .git/worktrees")),
                OPT_EXPIRY_DATE(0, "expire", &expire,
                                N_("expire objects older than <time>")),
                OPT_END()
        expire = ULONG_MAX;
        save_commit_buffer = 0;
        check_replace_refs = 0;
 +      ref_paranoia = 1;
        init_revisions(&revs, prefix);
  
        argc = parse_options(argc, argv, prefix, options, prune_usage, 0);
+       if (do_prune_worktrees) {
+               if (argc)
+                       die(_("--worktrees does not take extra arguments"));
+               prune_worktrees();
+               return 0;
+       }
        while (argc--) {
                unsigned char sha1[20];
                const char *name = *argv++;
diff --combined builtin/receive-pack.c
index 5292bb5a506805778c6b9c164523c80a44da3edd,3b8f420d04c9693419ccbdf3bc30b73cd27836e6..d2ec52bca983d9dfe1094cffe6049c902049e4d6
@@@ -26,8 -26,7 +26,8 @@@ enum deny_action 
        DENY_UNCONFIGURED,
        DENY_IGNORE,
        DENY_WARN,
 -      DENY_REFUSE
 +      DENY_REFUSE,
 +      DENY_UPDATE_INSTEAD
  };
  
  static int deny_deletes;
@@@ -38,11 -37,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;
@@@ -69,7 -66,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)
  {
@@@ -80,8 -76,6 +80,8 @@@
                        return DENY_WARN;
                if (!strcasecmp(value, "refuse"))
                        return DENY_REFUSE;
 +              if (!strcasecmp(value, "updateinstead"))
 +                      return DENY_UPDATE_INSTEAD;
        }
        if (git_config_bool(var, value))
                return DENY_REFUSE;
@@@ -163,11 -157,6 +163,11 @@@ static int receive_pack_config(const ch
                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);
  }
  
@@@ -183,8 -172,6 +183,8 @@@ static void show_ref(const char *path, 
  
                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)
@@@ -444,7 -431,7 +444,7 @@@ static const char *check_nonce(const ch
        nonce_stamp_slop = (long)ostamp - (long)stamp;
  
        if (nonce_stamp_slop_limit &&
 -          abs(nonce_stamp_slop) <= nonce_stamp_slop_limit) {
 +          labs(nonce_stamp_slop) <= nonce_stamp_slop_limit) {
                /*
                 * Pretend as if the received nonce (which passes the
                 * HMAC check, so it is not a forged by third-party)
@@@ -743,128 -730,11 +743,128 @@@ static int update_shallow_ref(struct co
        return 0;
  }
  
 +/*
 + * NEEDSWORK: we should consolidate various implementions of "are we
 + * on an unborn branch?" test into one, and make the unified one more
 + * robust. !get_sha1() based check used here and elsewhere would not
 + * allow us to tell an unborn branch from corrupt ref, for example.
 + * For the purpose of fixing "deploy-to-update does not work when
 + * pushing into an empty repository" issue, this should suffice for
 + * now.
 + */
 +static int head_has_history(void)
 +{
 +      unsigned char sha1[20];
 +
 +      return !get_sha1("HEAD", 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
 +      };
 +      const char *diff_files[] = {
 +              "diff-files", "--quiet", "--ignore-submodules", "--", NULL
 +      };
 +      const char *diff_index[] = {
 +              "diff-index", "--quiet", "--cached", "--ignore-submodules",
 +              NULL, "--", NULL
 +      };
 +      const char *read_tree[] = {
 +              "read-tree", "-u", "-m", NULL, NULL
 +      };
 +      struct child_process child = CHILD_PROCESS_INIT;
 +
 +      child.argv = update_refresh;
 +      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))
 +              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.dir = work_tree;
 +      child.no_stdin = 1;
 +      child.stdout_to_stderr = 1;
 +      child.git_cmd = 1;
 +      if (run_command(&child))
 +              return "Working directory has unstaged changes";
 +
 +      /* diff-index with either HEAD or an empty tree */
 +      diff_index[4] = head_has_history() ? "HEAD" : EMPTY_TREE_SHA1_HEX;
 +
 +      child_process_init(&child);
 +      child.argv = diff_index;
 +      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))
 +              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.dir = work_tree;
 +      child.no_stdin = 1;
 +      child.no_stdout = 1;
 +      child.stdout_to_stderr = 0;
 +      child.git_cmd = 1;
 +      if (run_command(&child))
 +              return "Could not update working tree to new HEAD";
 +
 +      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;
        struct strbuf namespaced_name_buf = STRBUF_INIT;
 -      const char *namespaced_name;
 +      const char *namespaced_name, *ret;
        unsigned char *old_sha1 = cmd->old_sha1;
        unsigned char *new_sha1 = cmd->new_sha1;
  
                        if (deny_current_branch == DENY_UNCONFIGURED)
                                refuse_unconfigured_deny();
                        return "branch is currently checked out";
 +              case DENY_UPDATE_INSTEAD:
 +                      ret = update_worktree(new_sha1);
 +                      if (ret)
 +                              return ret;
 +                      break;
                }
        }
  
                                break;
                        case DENY_REFUSE:
                        case DENY_UNCONFIGURED:
 +                      case DENY_UPDATE_INSTEAD:
                                if (deny_delete_current == DENY_UNCONFIGURED)
                                        refuse_unconfigured_deny_delete_current();
                                rp_error("refusing to delete the current branch: %s", name);
                                return "deletion of the current branch prohibited";
 +                      default:
 +                              return "Invalid denyDeleteCurrent setting";
                        }
                }
        }
        }
  
        if (is_null_sha1(new_sha1)) {
 +              struct strbuf err = STRBUF_INIT;
                if (!parse_object(old_sha1)) {
                        old_sha1 = NULL;
                        if (ref_exists(name)) {
                                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 */
        }
  }
@@@ -1008,7 -869,7 +1008,7 @@@ static void run_update_post_hook(struc
        int argc;
        const char **argv;
        struct child_process proc = CHILD_PROCESS_INIT;
-       char *hook;
+       const char *hook;
  
        hook = find_hook("post-update");
        for (argc = 0, cmd = commands; cmd; cmd = cmd->next) {
@@@ -1103,7 -964,7 +1103,7 @@@ static void check_aliased_updates(struc
                        string_list_append(&ref_list, cmd->ref_name);
                item->util = (void *)cmd;
        }
 -      sort_string_list(&ref_list);
 +      string_list_sort(&ref_list);
  
        for (cmd = commands; cmd; cmd = cmd->next) {
                if (!cmd->error_string)
@@@ -1181,105 -1042,11 +1181,105 @@@ static void reject_updates_to_hidden(st
        }
  }
  
 +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;
        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,
@@@ -1398,9 -1179,6 +1398,9 @@@ static struct command *read_head_info(s
                                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")) {
diff --combined builtin/remote.c
index 5d3ab906bc7ef6cc8cc9c65a3b86cf4c1ff443fb,4ce396fdffcd3f0b7742e5e1b9119691cd3fb5f6..ad57fc984edc8a7ea7f3784e14068e247a5d27ad
  
  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>)...]"),
@@@ -180,9 -180,7 +180,9 @@@ static int add(int argc, const char **a
        url = argv[1];
  
        remote = remote_get(name);
 -      if (remote && (remote->url_nr > 1 || strcmp(name, remote->url[0]) ||
 +      if (remote && (remote->url_nr > 1 ||
 +                      (strcmp(name, remote->url[0]) &&
 +                              strcmp(url, remote->url[0])) ||
                        remote->fetch_refspec_nr))
                die(_("remote %s already exists."), name);
  
@@@ -354,9 -352,9 +354,9 @@@ static int get_ref_states(const struct 
        free_refs(stale_refs);
        free_refs(fetch_map);
  
 -      sort_string_list(&states->new);
 -      sort_string_list(&states->tracked);
 -      sort_string_list(&states->stale);
 +      string_list_sort(&states->new);
 +      string_list_sort(&states->tracked);
 +      string_list_sort(&states->stale);
  
        return 0;
  }
@@@ -584,7 -582,7 +584,7 @@@ static int migrate_file(struct remote *
  {
        struct strbuf buf = STRBUF_INIT;
        int i;
-       char *path = NULL;
+       const char *path = NULL;
  
        strbuf_addf(&buf, "remote.%s.url", remote->name);
        for (i = 0; i < remote->url_nr; i++)
@@@ -752,11 -750,16 +752,11 @@@ static int mv(int argc, const char **ar
  static int remove_branches(struct string_list *branches)
  {
        struct strbuf err = STRBUF_INIT;
 -      const char **branch_names;
        int i, result = 0;
  
 -      branch_names = xmalloc(branches->nr * sizeof(*branch_names));
 -      for (i = 0; i < branches->nr; i++)
 -              branch_names[i] = branches->items[i].string;
 -      if (repack_without_refs(branch_names, branches->nr, &err))
 +      if (repack_without_refs(branches, &err))
                result |= error("%s", err.buf);
        strbuf_release(&err);
 -      free(branch_names);
  
        for (i = 0; i < branches->nr; i++) {
                struct string_list_item *item = branches->items + i;
@@@ -911,7 -914,7 +911,7 @@@ static int get_remote_ref_states(const 
                        get_push_ref_states(remote_refs, states);
        } else {
                for_each_ref(append_ref_to_tracked_list, states);
 -              sort_string_list(&states->tracked);
 +              string_list_sort(&states->tracked);
                get_push_ref_states_noquery(states);
        }
  
@@@ -1130,7 -1133,7 +1130,7 @@@ static int show_all(void
        if (!result) {
                int i;
  
 -              sort_string_list(&list);
 +              string_list_sort(&list);
                for (i = 0; i < list.nr; i++) {
                        struct string_list_item *item = list.items + i;
                        if (verbose)
@@@ -1311,10 -1314,10 +1311,10 @@@ static int set_head(int argc, const cha
  
  static int prune_remote(const char *remote, int dry_run)
  {
 -      int result = 0, i;
 +      int result = 0;
        struct ref_states states;
 -      struct string_list delete_refs_list = STRING_LIST_INIT_NODUP;
 -      const char **delete_refs;
 +      struct string_list refs_to_prune = STRING_LIST_INIT_NODUP;
 +      struct string_list_item *item;
        const char *dangling_msg = dry_run
                ? _(" %s will become dangling!")
                : _(" %s has become dangling!");
        memset(&states, 0, sizeof(states));
        get_remote_ref_states(remote, &states, GET_REF_STATES);
  
 -      if (states.stale.nr) {
 -              printf_ln(_("Pruning %s"), remote);
 -              printf_ln(_("URL: %s"),
 -                     states.remote->url_nr
 -                     ? states.remote->url[0]
 -                     : _("(no URL)"));
 -
 -              delete_refs = xmalloc(states.stale.nr * sizeof(*delete_refs));
 -              for (i = 0; i < states.stale.nr; i++)
 -                      delete_refs[i] = states.stale.items[i].util;
 -              if (!dry_run) {
 -                      struct strbuf err = STRBUF_INIT;
 -                      if (repack_without_refs(delete_refs, states.stale.nr,
 -                                              &err))
 -                              result |= error("%s", err.buf);
 -                      strbuf_release(&err);
 -              }
 -              free(delete_refs);
 +      if (!states.stale.nr) {
 +              free_remote_ref_states(&states);
 +              return 0;
        }
  
 -      for (i = 0; i < states.stale.nr; i++) {
 -              const char *refname = states.stale.items[i].util;
 +      printf_ln(_("Pruning %s"), remote);
 +      printf_ln(_("URL: %s"),
 +                states.remote->url_nr
 +                ? states.remote->url[0]
 +                : _("(no URL)"));
 +
 +      for_each_string_list_item(item, &states.stale)
 +              string_list_append(&refs_to_prune, item->util);
 +      string_list_sort(&refs_to_prune);
 +
 +      if (!dry_run) {
 +              struct strbuf err = STRBUF_INIT;
 +              if (repack_without_refs(&refs_to_prune, &err))
 +                      result |= error("%s", err.buf);
 +              strbuf_release(&err);
 +      }
  
 -              string_list_insert(&delete_refs_list, refname);
 +      for_each_string_list_item(item, &states.stale) {
 +              const char *refname = item->util;
  
                if (!dry_run)
                        result |= delete_ref(refname, NULL, 0);
                               abbrev_ref(refname, "refs/remotes/"));
        }
  
 -      warn_dangling_symrefs(stdout, dangling_msg, &delete_refs_list);
 -      string_list_clear(&delete_refs_list, 0);
 +      warn_dangling_symrefs(stdout, dangling_msg, &refs_to_prune);
  
 +      string_list_clear(&refs_to_prune, 0);
        free_remote_ref_states(&states);
        return result;
  }
diff --combined builtin/repack.c
index f2edeb0f4ca2b81246ee37d7ca5f53f58161ad6f,9c04e1d8ec1c2e4ffe03c6ab1c0e7d8215f9788f..af7340c7bafbfbbf991f782139775e18b6ac570a
@@@ -14,7 -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
  };
  
@@@ -135,6 -135,7 +135,6 @@@ int cmd_repack(int argc, const char **a
        };
        struct child_process cmd = CHILD_PROCESS_INIT;
        struct string_list_item *item;
 -      struct argv_array cmd_args = ARGV_ARRAY_INIT;
        struct string_list names = STRING_LIST_INIT_DUP;
        struct string_list rollback = STRING_LIST_INIT_NODUP;
        struct string_list existing_packs = STRING_LIST_INIT_DUP;
  
        sigchain_push_common(remove_pack_on_signal);
  
 -      argv_array_push(&cmd_args, "pack-objects");
 -      argv_array_push(&cmd_args, "--keep-true-parents");
 +      argv_array_push(&cmd.args, "pack-objects");
 +      argv_array_push(&cmd.args, "--keep-true-parents");
        if (!pack_kept_objects)
 -              argv_array_push(&cmd_args, "--honor-pack-keep");
 -      argv_array_push(&cmd_args, "--non-empty");
 -      argv_array_push(&cmd_args, "--all");
 -      argv_array_push(&cmd_args, "--reflog");
 -      argv_array_push(&cmd_args, "--indexed-objects");
 +              argv_array_push(&cmd.args, "--honor-pack-keep");
 +      argv_array_push(&cmd.args, "--non-empty");
 +      argv_array_push(&cmd.args, "--all");
 +      argv_array_push(&cmd.args, "--reflog");
 +      argv_array_push(&cmd.args, "--indexed-objects");
        if (window)
 -              argv_array_pushf(&cmd_args, "--window=%s", window);
 +              argv_array_pushf(&cmd.args, "--window=%s", window);
        if (window_memory)
 -              argv_array_pushf(&cmd_args, "--window-memory=%s", window_memory);
 +              argv_array_pushf(&cmd.args, "--window-memory=%s", window_memory);
        if (depth)
 -              argv_array_pushf(&cmd_args, "--depth=%s", depth);
 +              argv_array_pushf(&cmd.args, "--depth=%s", depth);
        if (max_pack_size)
 -              argv_array_pushf(&cmd_args, "--max-pack-size=%s", max_pack_size);
 +              argv_array_pushf(&cmd.args, "--max-pack-size=%s", max_pack_size);
        if (no_reuse_delta)
 -              argv_array_pushf(&cmd_args, "--no-reuse-delta");
 +              argv_array_pushf(&cmd.args, "--no-reuse-delta");
        if (no_reuse_object)
 -              argv_array_pushf(&cmd_args, "--no-reuse-object");
 +              argv_array_pushf(&cmd.args, "--no-reuse-object");
        if (write_bitmaps)
 -              argv_array_push(&cmd_args, "--write-bitmap-index");
 +              argv_array_push(&cmd.args, "--write-bitmap-index");
  
        if (pack_everything & ALL_INTO_ONE) {
                get_non_kept_pack_filenames(&existing_packs);
  
                if (existing_packs.nr && delete_redundant) {
 -                      if (unpack_unreachable)
 -                              argv_array_pushf(&cmd_args,
 +                      if (unpack_unreachable) {
 +                              argv_array_pushf(&cmd.args,
                                                "--unpack-unreachable=%s",
                                                unpack_unreachable);
 -                      else if (pack_everything & LOOSEN_UNREACHABLE)
 -                              argv_array_push(&cmd_args,
 +                              argv_array_push(&cmd.env_array, "GIT_REF_PARANOIA=1");
 +                      } else if (pack_everything & LOOSEN_UNREACHABLE) {
 +                              argv_array_push(&cmd.args,
                                                "--unpack-unreachable");
 +                      } else {
 +                              argv_array_push(&cmd.env_array, "GIT_REF_PARANOIA=1");
 +                      }
                }
        } else {
 -              argv_array_push(&cmd_args, "--unpacked");
 -              argv_array_push(&cmd_args, "--incremental");
 +              argv_array_push(&cmd.args, "--unpacked");
 +              argv_array_push(&cmd.args, "--incremental");
        }
  
        if (local)
 -              argv_array_push(&cmd_args,  "--local");
 +              argv_array_push(&cmd.args,  "--local");
        if (quiet)
 -              argv_array_push(&cmd_args,  "--quiet");
 +              argv_array_push(&cmd.args,  "--quiet");
        if (delta_base_offset)
 -              argv_array_push(&cmd_args,  "--delta-base-offset");
 +              argv_array_push(&cmd.args,  "--delta-base-offset");
  
 -      argv_array_push(&cmd_args, packtmp);
 +      argv_array_push(&cmd.args, packtmp);
  
 -      cmd.argv = cmd_args.argv;
        cmd.git_cmd = 1;
        cmd.out = -1;
        cmd.no_stdin = 1;
        ret = finish_command(&cmd);
        if (ret)
                return ret;
 -      argv_array_clear(&cmd_args);
  
        if (!names.nr && !quiet)
                printf("Nothing new to pack.\n");
        failed = 0;
        for_each_string_list_item(item, &names) {
                for (ext = 0; ext < ARRAY_SIZE(exts); ext++) {
-                       char *fname, *fname_old;
+                       const char *fname_old;
+                       char *fname;
                        fname = mkpathdup("%s/pack-%s%s", packdir,
                                                item->string, exts[ext].name);
                        if (!file_exists(fname)) {
        if (failed) {
                struct string_list rollback_failure = STRING_LIST_INIT_DUP;
                for_each_string_list_item(item, &rollback) {
-                       char *fname, *fname_old;
+                       const char *fname_old;
+                       char *fname;
                        fname = mkpathdup("%s/%s", packdir, item->string);
                        fname_old = mkpath("%s/old-%s", packdir, item->string);
                        if (rename(fname_old, fname))
        /* Remove the "old-" files */
        for_each_string_list_item(item, &names) {
                for (ext = 0; ext < ARRAY_SIZE(exts); ext++) {
-                       char *fname;
+                       const char *fname;
                        fname = mkpath("%s/old-%s%s",
                                        packdir,
                                        item->string,
  
        if (delete_redundant) {
                int opts = 0;
 -              sort_string_list(&names);
 +              string_list_sort(&names);
                for_each_string_list_item(item, &existing_packs) {
                        char *sha1;
                        size_t len = strlen(item->string);
diff --combined builtin/rev-parse.c
index 3626c61da67abbe418e492c7828f6e153f6055d8,5799f3558d47ed071c1910bb349b86458ee1e361..4d10dd9545af70c32f9e19533b2cfc9b00b7f00a
@@@ -279,7 -279,7 +279,7 @@@ static int try_difference(const char *a
                        struct commit *a, *b;
                        a = lookup_commit_reference(sha1);
                        b = lookup_commit_reference(end);
 -                      exclude = get_merge_bases(a, b, 1);
 +                      exclude = get_merge_bases(a, b);
                        while (exclude) {
                                struct commit_list *n = exclude->next;
                                show_rev(REVERSED,
@@@ -358,7 -358,7 +358,7 @@@ static int cmd_parseopt(int argc, cons
  {
        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 +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.");
  
@@@ -533,6 -533,13 +533,13 @@@ int cmd_rev_parse(int argc, const char 
        for (i = 1; i < argc; i++) {
                const char *arg = argv[i];
  
+               if (!strcmp(arg, "--git-path")) {
+                       if (!argv[i + 1])
+                               die("--git-path requires an argument");
+                       puts(git_path("%s", argv[i + 1]));
+                       i++;
+                       continue;
+               }
                if (as_is) {
                        if (show_file(arg, output_prefix) && as_is < 2)
                                verify_filename(prefix, arg, 0);
                                free(cwd);
                                continue;
                        }
+                       if (!strcmp(arg, "--git-common-dir")) {
+                               puts(get_git_common_dir());
+                               continue;
+                       }
                        if (!strcmp(arg, "--resolve-git-dir")) {
                                const char *gitdir = argv[++i];
                                if (!gitdir)
diff --combined cache.h
index b34447ffcf3a97ee1cec76ce090f274f604b926d,670e8614df9597e5cb445c223cabd4167b112e65..771b775621595e312484295abd9ca768ece6f6ea
+++ b/cache.h
@@@ -43,14 -43,6 +43,14 @@@ int git_deflate_end_gently(git_zstream 
  int git_deflate(git_zstream *, int flush);
  unsigned long git_deflate_bound(git_zstream *, unsigned long);
  
 +/* The length in bytes and in hex digits of an object name (SHA-1 value). */
 +#define GIT_SHA1_RAWSZ 20
 +#define GIT_SHA1_HEXSZ (2 * GIT_SHA1_RAWSZ)
 +
 +struct object_id {
 +      unsigned char hash[GIT_SHA1_RAWSZ];
 +};
 +
  #if defined(DT_UNKNOWN) && !defined(NO_D_TYPE_IN_DIRENT)
  #define DTYPE(de)     ((de)->d_type)
  #else
   *
   * The value 0160000 is not normally a valid mode, and
   * also just happens to be S_IFDIR + S_IFLNK
 - *
 - * NOTE! We *really* shouldn't depend on the S_IFxxx macros
 - * always having the same values everywhere. We should use
 - * our internal git values for these things, and then we can
 - * translate that to the OS-specific value. It just so
 - * happens that everybody shares the same bit representation
 - * in the UNIX world (and apparently wider too..)
   */
  #define S_IFGITLINK   0160000
  #define S_ISGITLINK(m)        (((m) & S_IFMT) == S_IFGITLINK)
@@@ -378,6 -377,7 +378,7 @@@ static inline enum object_type object_t
  
  /* Double-check local_repo_env below if you add to this list. */
  #define GIT_DIR_ENVIRONMENT "GIT_DIR"
+ #define GIT_COMMON_DIR_ENVIRONMENT "GIT_COMMON_DIR"
  #define GIT_NAMESPACE_ENVIRONMENT "GIT_NAMESPACE"
  #define GIT_WORK_TREE_ENVIRONMENT "GIT_WORK_TREE"
  #define GIT_PREFIX_ENVIRONMENT "GIT_PREFIX"
@@@ -431,11 -431,13 +432,13 @@@ extern int is_inside_git_dir(void)
  extern char *git_work_tree_cfg;
  extern int is_inside_work_tree(void);
  extern const char *get_git_dir(void);
+ extern const char *get_git_common_dir(void);
  extern int is_git_directory(const char *path);
  extern char *get_object_directory(void);
  extern char *get_index_file(void);
  extern char *get_graft_file(void);
  extern int set_git_dir(const char *path);
+ extern int get_common_dir(struct strbuf *sb, const char *gitdir);
  extern const char *get_git_namespace(void);
  extern const char *strip_namespace(const char *namespaced_ref);
  extern const char *get_git_work_tree(void);
@@@ -576,7 -578,7 +579,7 @@@ extern void update_index_if_able(struc
  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;
@@@ -618,17 -620,8 +621,18 @@@ extern int fsync_object_files
  extern int core_preload_index;
  extern int core_apply_sparse_checkout;
  extern int precomposed_unicode;
 +extern int protect_hfs;
 +extern int protect_ntfs;
+ extern int git_db_env, git_index_env, git_graft_env, git_common_dir_env;
  
 +/*
 + * Include broken refs in all ref iterations, which will
 + * generally choke dangerous operations rather than letting
 + * them silently proceed without taking the broken ref into
 + * account.
 + */
 +extern int ref_paranoia;
 +
  /*
   * The character that begins a commented line in user-editable file
   * that is subject to stripspace.
@@@ -690,18 -683,19 +694,19 @@@ extern int check_repository_format(void
  
  extern char *mksnpath(char *buf, size_t n, const char *fmt, ...)
        __attribute__((format (printf, 3, 4)));
- extern char *git_snpath(char *buf, size_t n, const char *fmt, ...)
-       __attribute__((format (printf, 3, 4)));
+ extern void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
+       __attribute__((format (printf, 2, 3)));
  extern char *git_pathdup(const char *fmt, ...)
        __attribute__((format (printf, 1, 2)));
  extern char *mkpathdup(const char *fmt, ...)
        __attribute__((format (printf, 1, 2)));
  
  /* Return a statically allocated filename matching the sha1 signature */
- extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
- extern char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
- extern char *git_path_submodule(const char *path, const char *fmt, ...)
+ extern const char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
+ extern const char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
+ extern const char *git_path_submodule(const char *path, const char *fmt, ...)
        __attribute__((format (printf, 2, 3)));
+ extern void report_linked_checkout_garbage(void);
  
  /*
   * Return the name of the file in the local object database that would
@@@ -726,13 -720,13 +731,13 @@@ extern char *sha1_pack_name(const unsig
  extern char *sha1_pack_index_name(const unsigned char *sha1);
  
  extern const char *find_unique_abbrev(const unsigned char *sha1, int);
 -extern const unsigned char null_sha1[20];
 +extern const unsigned char null_sha1[GIT_SHA1_RAWSZ];
  
  static inline int hashcmp(const unsigned char *sha1, const unsigned char *sha2)
  {
        int i;
  
 -      for (i = 0; i < 20; i++, sha1++, sha2++) {
 +      for (i = 0; i < GIT_SHA1_RAWSZ; i++, sha1++, sha2++) {
                if (*sha1 != *sha2)
                        return *sha1 - *sha2;
        }
        return 0;
  }
  
 +static inline int oidcmp(const struct object_id *oid1, const struct object_id *oid2)
 +{
 +      return hashcmp(oid1->hash, oid2->hash);
 +}
 +
  static inline int is_null_sha1(const unsigned char *sha1)
  {
        return !hashcmp(sha1, null_sha1);
  }
  
 +static inline int is_null_oid(const struct object_id *oid)
 +{
 +      return !hashcmp(oid->hash, null_sha1);
 +}
 +
  static inline void hashcpy(unsigned char *sha_dst, const unsigned char *sha_src)
  {
 -      memcpy(sha_dst, sha_src, 20);
 +      memcpy(sha_dst, sha_src, GIT_SHA1_RAWSZ);
 +}
 +
 +static inline void oidcpy(struct object_id *dst, const struct object_id *src)
 +{
 +      hashcpy(dst->hash, src->hash);
  }
 +
  static inline void hashclr(unsigned char *hash)
  {
 -      memset(hash, 0, 20);
 +      memset(hash, 0, GIT_SHA1_RAWSZ);
  }
  
 +static inline void oidclr(struct object_id *oid)
 +{
 +      hashclr(oid->hash);
 +}
 +
 +
  #define EMPTY_TREE_SHA1_HEX \
        "4b825dc642cb6eb9a060e54bf8d69288fbee4904"
  #define EMPTY_TREE_SHA1_BIN_LITERAL \
@@@ -864,7 -836,6 +869,7 @@@ int normalize_path_copy(char *dst, cons
  int longest_ancestor_length(const char *path, struct string_list *prefixes);
  char *strip_path_suffix(const char *path, const char *suffix);
  int daemon_avoid_alias(const char *path);
 +extern int is_ntfs_dotgit(const char *name);
  
  /* object replacement */
  #define LOOKUP_REPLACE_OBJECT 1
@@@ -982,10 -953,8 +987,10 @@@ extern int for_each_abbrev(const char *
   * null-terminated string.
   */
  extern int get_sha1_hex(const char *hex, unsigned char *sha1);
 +extern int get_oid_hex(const char *hex, struct object_id *sha1);
  
  extern char *sha1_to_hex(const unsigned char *sha1);  /* static buffer result! */
 +extern char *oid_to_hex(const struct object_id *oid); /* same static buffer as sha1_to_hex */
  extern int read_ref_full(const char *refname, int resolve_flags,
                         unsigned char *sha1, int *flags);
  extern int read_ref(const char *refname, unsigned char *sha1);
@@@ -1206,7 -1175,6 +1211,7 @@@ extern struct packed_git 
        int pack_fd;
        unsigned pack_local:1,
                 pack_keep:1,
 +               freshened:1,
                 do_not_close:1;
        unsigned char sha1[20];
        /* something like ".git/objects/pack/xxxxx.pack" */
@@@ -1295,10 -1263,6 +1300,10 @@@ extern int unpack_object_header(struct 
   *
   * Any callback that is NULL will be ignored. Callbacks returning non-zero
   * will end the iteration.
 + *
 + * In the "buf" variant, "path" is a strbuf which will also be used as a
 + * scratch buffer, but restored to its original contents before
 + * the function returns.
   */
  typedef int each_loose_object_fn(const unsigned char *sha1,
                                 const char *path,
@@@ -1314,24 -1278,17 +1319,24 @@@ int for_each_loose_file_in_objdir(cons
                                  each_loose_cruft_fn cruft_cb,
                                  each_loose_subdir_fn subdir_cb,
                                  void *data);
 +int for_each_loose_file_in_objdir_buf(struct strbuf *path,
 +                                    each_loose_object_fn obj_cb,
 +                                    each_loose_cruft_fn cruft_cb,
 +                                    each_loose_subdir_fn subdir_cb,
 +                                    void *data);
  
  /*
   * Iterate over loose and packed objects in both the local
 - * repository and any alternates repositories.
 + * repository and any alternates repositories (unless the
 + * LOCAL_ONLY flag is set).
   */
 +#define FOR_EACH_OBJECT_LOCAL_ONLY 0x1
  typedef int each_packed_object_fn(const unsigned char *sha1,
                                  struct packed_git *pack,
                                  uint32_t pos,
                                  void *data);
 -extern int for_each_loose_object(each_loose_object_fn, void *);
 -extern int for_each_packed_object(each_packed_object_fn, void *);
 +extern int for_each_loose_object(each_loose_object_fn, void *, unsigned flags);
 +extern int for_each_packed_object(each_packed_object_fn, void *, unsigned flags);
  
  struct object_info {
        /* Request */
@@@ -1543,6 -1500,8 +1548,8 @@@ static inline ssize_t write_str_in_full
  {
        return write_in_full(fd, str, strlen(str));
  }
+ __attribute__((format (printf, 3, 4)))
+ extern int write_file(const char *path, int fatal, const char *fmt, ...);
  
  /* pager.c */
  extern void setup_pager(void);
@@@ -1550,7 -1509,7 +1557,7 @@@ extern const char *pager_program
  extern int pager_in_use(void);
  extern int pager_use_color;
  extern int term_columns(void);
 -extern int decimal_width(int);
 +extern int decimal_width(uintmax_t);
  extern int check_pager_config(const char *cmd);
  
  extern const char *editor_program;
@@@ -1612,6 -1571,7 +1619,6 @@@ extern int ws_blank_line(const char *li
  #define ws_tab_width(rule)     ((rule) & WS_TAB_WIDTH_MASK)
  
  /* ls-files */
 -int report_path_error(const char *ps_matched, const struct pathspec *pathspec, const char *prefix);
  void overlay_tree_on_cache(const char *tree_name, const char *prefix);
  
  char *alias_lookup(const char *alias);
diff --combined daemon.c
index 9ee21877cd952a7aa47c793d877174d858488794,60bbab6bda0fa1e20ead36988afe444551ba6d64..ac2bc852d1dfa20783de63c3dceec83a79e4df6a
+++ b/daemon.c
@@@ -43,6 -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.
@@@ -53,28 -56,10 +53,28 @@@ static const char *user_path
  static unsigned int timeout;
  static unsigned int init_timeout;
  
 -static char *hostname;
 -static char *canon_hostname;
 -static char *ip_address;
 -static char *tcp_port;
 +struct hostinfo {
 +      struct strbuf hostname;
 +      struct strbuf canon_hostname;
 +      struct strbuf ip_address;
 +      struct strbuf tcp_port;
 +      unsigned int hostname_lookup_done:1;
 +      unsigned int saw_extended_args:1;
 +};
 +
 +static void lookup_hostname(struct hostinfo *hi);
 +
 +static const char *get_canon_hostname(struct hostinfo *hi)
 +{
 +      lookup_hostname(hi);
 +      return hi->canon_hostname.buf;
 +}
 +
 +static const char *get_ip_address(struct hostinfo *hi)
 +{
 +      lookup_hostname(hi);
 +      return hi->ip_address.buf;
 +}
  
  static void logreport(int priority, const char *err, va_list params)
  {
@@@ -121,43 -106,7 +121,43 @@@ static void NORETURN daemon_die(const c
        exit(1);
  }
  
 -static const char *path_ok(const char *directory)
 +struct expand_path_context {
 +      const char *directory;
 +      struct hostinfo *hostinfo;
 +};
 +
 +static size_t expand_path(struct strbuf *sb, const char *placeholder, void *ctx)
 +{
 +      struct expand_path_context *context = ctx;
 +      struct hostinfo *hi = context->hostinfo;
 +
 +      switch (placeholder[0]) {
 +      case 'H':
 +              strbuf_addbuf(sb, &hi->hostname);
 +              return 1;
 +      case 'C':
 +              if (placeholder[1] == 'H') {
 +                      strbuf_addstr(sb, get_canon_hostname(hi));
 +                      return 2;
 +              }
 +              break;
 +      case 'I':
 +              if (placeholder[1] == 'P') {
 +                      strbuf_addstr(sb, get_ip_address(hi));
 +                      return 2;
 +              }
 +              break;
 +      case 'P':
 +              strbuf_addbuf(sb, &hi->tcp_port);
 +              return 1;
 +      case 'D':
 +              strbuf_addstr(sb, context->directory);
 +              return 1;
 +      }
 +      return 0;
 +}
 +
 +static const char *path_ok(const char *directory, struct hostinfo *hi)
  {
        static char rpath[PATH_MAX];
        static char interp_path[PATH_MAX];
                        dir = rpath;
                }
        }
 -      else if (interpolated_path && saw_extended_args) {
 +      else if (interpolated_path && hi->saw_extended_args) {
                struct strbuf expanded_path = STRBUF_INIT;
 -              struct strbuf_expand_dict_entry dict[6];
 -
 -              dict[0].placeholder = "H"; dict[0].value = hostname;
 -              dict[1].placeholder = "CH"; dict[1].value = canon_hostname;
 -              dict[2].placeholder = "IP"; dict[2].value = ip_address;
 -              dict[3].placeholder = "P"; dict[3].value = tcp_port;
 -              dict[4].placeholder = "D"; dict[4].value = directory;
 -              dict[5].placeholder = NULL; dict[5].value = NULL;
 +              struct expand_path_context context;
 +
 +              context.directory = directory;
 +              context.hostinfo = hi;
 +
                if (*dir != '/') {
                        /* Allow only absolute */
                        logerror("'%s': Non-absolute path denied (interpolated-path active)", dir);
                }
  
                strbuf_expand(&expanded_path, interpolated_path,
 -                              strbuf_expand_dict_cb, &dict);
 +                            expand_path, &context);
                strlcpy(interp_path, expanded_path.buf, PATH_MAX);
                strbuf_release(&expanded_path);
                loginfo("Interpolated dir '%s'", interp_path);
@@@ -288,8 -240,7 +288,8 @@@ static int daemon_error(const char *dir
  
  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;
        char *eol;
        int seen_errors = 0;
  
 -#define STRARG(x) ((x) ? (x) : "")
        *arg++ = access_hook;
        *arg++ = service->name;
        *arg++ = path;
 -      *arg++ = STRARG(hostname);
 -      *arg++ = STRARG(canon_hostname);
 -      *arg++ = STRARG(ip_address);
 -      *arg++ = STRARG(tcp_port);
 +      *arg++ = hi->hostname.buf;
 +      *arg++ = get_canon_hostname(hi);
 +      *arg++ = get_ip_address(hi);
 +      *arg++ = hi->tcp_port.buf;
        *arg = NULL;
 -#undef STRARG
  
        child.use_shell = 1;
        child.argv = argv;
@@@ -349,8 -302,7 +349,8 @@@ error_return
        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;
                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");
  
        /*
         * 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;
  
        /*
@@@ -532,47 -484,17 +532,47 @@@ static void parse_host_and_port(char *h
        }
  }
  
 +/*
 + * Sanitize a string from the client so that it's OK to be inserted into a
 + * filesystem path. Specifically, we disallow slashes, runs of "..", and
 + * trailing and leading dots, which means that the client cannot escape
 + * our base path via ".." traversal.
 + */
 +static void sanitize_client(struct strbuf *out, const char *in)
 +{
 +      for (; *in; in++) {
 +              if (*in == '/')
 +                      continue;
 +              if (*in == '.' && (!out->len || out->buf[out->len - 1] == '.'))
 +                      continue;
 +              strbuf_addch(out, *in);
 +      }
 +
 +      while (out->len && out->buf[out->len - 1] == '.')
 +              strbuf_setlen(out, out->len - 1);
 +}
 +
 +/*
 + * Like sanitize_client, but we also perform any canonicalization
 + * to make life easier on the admin.
 + */
 +static void canonicalize_client(struct strbuf *out, const char *in)
 +{
 +      sanitize_client(out, in);
 +      strbuf_tolower(out);
 +}
 +
  /*
   * Read the host as supplied by the client connection.
   */
 -static void parse_host_arg(char *extra_args, int buflen)
 +static void parse_host_arg(struct hostinfo *hi, char *extra_args, int buflen)
  {
        char *val;
        int vallen;
        char *end = extra_args + buflen;
  
        if (extra_args < end && *extra_args) {
 -              saw_extended_args = 1;
 +              hi->saw_extended_args = 1;
                if (strncasecmp("host=", extra_args, 5) == 0) {
                        val = extra_args + 5;
                        vallen = strlen(val) + 1;
                                char *host;
                                char *port;
                                parse_host_and_port(val, &host, &port);
 -                              if (port) {
 -                                      free(tcp_port);
 -                                      tcp_port = xstrdup(port);
 -                              }
 -                              free(hostname);
 -                              hostname = xstrdup_tolower(host);
 +                              if (port)
 +                                      sanitize_client(&hi->tcp_port, port);
 +                              canonicalize_client(&hi->hostname, host);
 +                              hi->hostname_lookup_done = 0;
                        }
  
                        /* On to the next one */
                if (extra_args < end && *extra_args)
                        die("Invalid request");
        }
 +}
  
 -      /*
 -       * Locate canonical hostname and its IP address.
 -       */
 -      if (hostname) {
 +/*
 + * Locate canonical hostname and its IP address.
 + */
 +static void lookup_hostname(struct hostinfo *hi)
 +{
 +      if (!hi->hostname_lookup_done && hi->hostname.len) {
  #ifndef NO_IPV6
                struct addrinfo hints;
                struct addrinfo *ai;
                memset(&hints, 0, sizeof(hints));
                hints.ai_flags = AI_CANONNAME;
  
 -              gai = getaddrinfo(hostname, NULL, &hints, &ai);
 +              gai = getaddrinfo(hi->hostname.buf, NULL, &hints, &ai);
                if (!gai) {
                        struct sockaddr_in *sin_addr = (void *)ai->ai_addr;
  
                        inet_ntop(AF_INET, &sin_addr->sin_addr,
                                  addrbuf, sizeof(addrbuf));
 -                      free(ip_address);
 -                      ip_address = xstrdup(addrbuf);
 +                      strbuf_addstr(&hi->ip_address, addrbuf);
  
 -                      free(canon_hostname);
 -                      canon_hostname = xstrdup(ai->ai_canonname ?
 -                                               ai->ai_canonname : ip_address);
 +                      if (ai->ai_canonname)
 +                              sanitize_client(&hi->canon_hostname,
 +                                              ai->ai_canonname);
 +                      else
 +                              strbuf_addbuf(&hi->canon_hostname,
 +                                            &hi->ip_address);
  
                        freeaddrinfo(ai);
                }
                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);
                        inet_ntop(hent->h_addrtype, &sa.sin_addr,
                                  addrbuf, sizeof(addrbuf));
  
 -                      free(canon_hostname);
 -                      canon_hostname = xstrdup(hent->h_name);
 -                      free(ip_address);
 -                      ip_address = xstrdup(addrbuf);
 +                      sanitize_client(&hi->canon_hostname, hent->h_name);
 +                      strbuf_addstr(&hi->ip_address, addrbuf);
                }
  #endif
 +              hi->hostname_lookup_done = 1;
        }
  }
  
 +static void hostinfo_init(struct hostinfo *hi)
 +{
 +      memset(hi, 0, sizeof(*hi));
 +      strbuf_init(&hi->hostname, 0);
 +      strbuf_init(&hi->canon_hostname, 0);
 +      strbuf_init(&hi->ip_address, 0);
 +      strbuf_init(&hi->tcp_port, 0);
 +}
 +
 +static void hostinfo_clear(struct hostinfo *hi)
 +{
 +      strbuf_release(&hi->hostname);
 +      strbuf_release(&hi->canon_hostname);
 +      strbuf_release(&hi->ip_address);
 +      strbuf_release(&hi->tcp_port);
 +}
  
  static int execute(void)
  {
        char *line = packet_buffer;
        int pktlen, len, i;
        char *addr = getenv("REMOTE_ADDR"), *port = getenv("REMOTE_PORT");
 +      struct hostinfo hi;
 +
 +      hostinfo_init(&hi);
  
        if (addr)
                loginfo("Connection from %s:%s", addr, port);
                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]);
                         * 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;
  }
@@@ -1166,15 -1070,6 +1166,6 @@@ static struct credentials *prepare_cred
  }
  #endif
  
- static void store_pid(const char *path)
- {
-       FILE *f = fopen(path, "w");
-       if (!f)
-               die_errno("cannot open pid file '%s'", path);
-       if (fprintf(f, "%"PRIuMAX"\n", (uintmax_t) getpid()) < 0 || fclose(f) != 0)
-               die_errno("failed to write pid file '%s'", path);
- }
  static int serve(struct string_list *listen_addr, int listen_port,
      struct credentials *cred)
  {
@@@ -1385,7 -1280,7 +1376,7 @@@ int main(int argc, char **argv
                sanitize_stdfds();
  
        if (pid_file)
-               store_pid(pid_file);
+               write_file(pid_file, 1, "%"PRIuMAX"\n", (uintmax_t) getpid());
  
        /* prepare argv for serving-processes */
        cld_argv = xmalloc(sizeof (char *) * (argc + 2));
diff --combined environment.c
index a40044c3bf8040a36ddfb5c260b389ec63683abd,8351007b30c7a7a1f74866f799efb8c2e9f38cfb..61c685b8d93091666891f0091d5005fe62543fc2
@@@ -24,7 -24,6 +24,7 @@@ int is_bare_repository_cfg = -1; /* uns
  int log_all_ref_updates = -1; /* unspecified */
  int warn_ambiguous_refs = 1;
  int warn_on_object_refname_ambiguity = 1;
 +int ref_paranoia = -1;
  int repository_format_version;
  const char *git_commit_encoding;
  const char *git_log_output_encoding;
@@@ -65,16 -64,6 +65,16 @@@ int precomposed_unicode = -1; /* see pr
  struct startup_info *startup_info;
  unsigned long pack_size_limit_cfg;
  
 +#ifndef PROTECT_HFS_DEFAULT
 +#define PROTECT_HFS_DEFAULT 0
 +#endif
 +int protect_hfs = PROTECT_HFS_DEFAULT;
 +
 +#ifndef PROTECT_NTFS_DEFAULT
 +#define PROTECT_NTFS_DEFAULT 0
 +#endif
 +int protect_ntfs = PROTECT_NTFS_DEFAULT;
 +
  /*
   * The character that begins a commented line in user-editable file
   * that is subject to stripspace.
@@@ -92,8 -81,9 +92,9 @@@ static char *work_tree
  static const char *namespace;
  static size_t namespace_len;
  
- static const char *git_dir;
+ static const char *git_dir, *git_common_dir;
  static char *git_object_dir, *git_index_file, *git_graft_file;
+ int git_db_env, git_index_env, git_graft_env, git_common_dir_env;
  
  /*
   * Repository-local GIT_* environment variables; see cache.h for details.
@@@ -111,6 -101,7 +112,7 @@@ const char * const local_repo_env[] = 
        NO_REPLACE_OBJECTS_ENVIRONMENT,
        GIT_PREFIX_ENVIRONMENT,
        GIT_SHALLOW_FILE_ENVIRONMENT,
+       GIT_COMMON_DIR_ENVIRONMENT,
        NULL
  };
  
@@@ -135,14 -126,23 +137,23 @@@ static char *expand_namespace(const cha
        return strbuf_detach(&buf, NULL);
  }
  
- static char *git_path_from_env(const char *envvar, const char *path)
+ static char *git_path_from_env(const char *envvar, const char *git_dir,
+                              const char *path, int *fromenv)
  {
        const char *value = getenv(envvar);
-       return value ? xstrdup(value) : git_pathdup("%s", path);
+       if (!value) {
+               char *buf = xmalloc(strlen(git_dir) + strlen(path) + 2);
+               sprintf(buf, "%s/%s", git_dir, path);
+               return buf;
+       }
+       if (fromenv)
+               *fromenv = 1;
+       return xstrdup(value);
  }
  
  static void setup_git_env(void)
  {
+       struct strbuf sb = STRBUF_INIT;
        const char *gitfile;
        const char *shallow_file;
  
                git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
        gitfile = read_gitfile(git_dir);
        git_dir = xstrdup(gitfile ? gitfile : git_dir);
-       git_object_dir = git_path_from_env(DB_ENVIRONMENT, "objects");
-       git_index_file = git_path_from_env(INDEX_ENVIRONMENT, "index");
-       git_graft_file = git_path_from_env(GRAFT_ENVIRONMENT, "info/grafts");
+       if (get_common_dir(&sb, git_dir))
+               git_common_dir_env = 1;
+       git_common_dir = strbuf_detach(&sb, NULL);
+       git_object_dir = git_path_from_env(DB_ENVIRONMENT, git_common_dir,
+                                          "objects", &git_db_env);
+       git_index_file = git_path_from_env(INDEX_ENVIRONMENT, git_dir,
+                                          "index", &git_index_env);
+       git_graft_file = git_path_from_env(GRAFT_ENVIRONMENT, git_common_dir,
+                                          "info/grafts", &git_graft_env);
        if (getenv(NO_REPLACE_OBJECTS_ENVIRONMENT))
                check_replace_refs = 0;
        namespace = expand_namespace(getenv(GIT_NAMESPACE_ENVIRONMENT));
@@@ -176,6 -182,11 +193,11 @@@ const char *get_git_dir(void
        return git_dir;
  }
  
+ const char *get_git_common_dir(void)
+ {
+       return git_common_dir;
+ }
  const char *get_git_namespace(void)
  {
        if (!namespace)
diff --combined fast-import.c
index e78ca107b3d66d7e537c86eb10dc7503be8681b9,1b5092378a66d6f9d344385741bd5a2e03a9eaa5..6378726993445694581ac36d6351f817fe488c72
@@@ -405,7 -405,7 +405,7 @@@ static void dump_marks_helper(FILE *, u
  
  static void write_crash_report(const char *err)
  {
-       char *loc = git_path("fast_import_crash_%"PRIuMAX, (uintmax_t) getpid());
+       const char *loc = git_path("fast_import_crash_%"PRIuMAX, (uintmax_t) getpid());
        FILE *rpt = fopen(loc, "w");
        struct branch *b;
        unsigned long lu;
@@@ -947,12 -947,9 +947,12 @@@ static void unkeep_all_packs(void
  
  static void end_packfile(void)
  {
 -      if (!pack_data)
 +      static int running;
 +
 +      if (running || !pack_data)
                return;
  
 +      running = 1;
        clear_delta_base_cache();
        if (object_count) {
                struct packed_git *new_p;
        }
        free(pack_data);
        pack_data = NULL;
 +      running = 0;
  
        /* We can't carry a delta across packfiles. */
        strbuf_release(&last_blob.data);
@@@ -1062,6 -1058,7 +1062,6 @@@ static int store_object
        } else
                delta = NULL;
  
 -      memset(&s, 0, sizeof(s));
        git_deflate_init(&s, pack_compression_level);
        if (delta) {
                s.next_in = delta;
                        free(delta);
                        delta = NULL;
  
 -                      memset(&s, 0, sizeof(s));
                        git_deflate_init(&s, pack_compression_level);
                        s.next_in = (void *)dat->buf;
                        s.avail_in = dat->len;
@@@ -1188,6 -1186,7 +1188,6 @@@ static void stream_blob(uintmax_t len, 
  
        crc32_begin(pack_file);
  
 -      memset(&s, 0, sizeof(s));
        git_deflate_init(&s, pack_compression_level);
  
        hdrlen = encode_in_pack_object_header(OBJ_BLOB, len, out_buf);
@@@ -1717,7 -1716,7 +1717,7 @@@ static int update_branch(struct branch 
        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 -1756,8 +1757,8 @@@ static void dump_tags(void
                strbuf_reset(&ref_name);
                strbuf_addf(&ref_name, "refs/tags/%s", t->name);
  
 -              if (ref_transaction_update(transaction, ref_name.buf, t->sha1,
 -                                         NULL, 0, 0, msg, &err)) {
 +              if (ref_transaction_update(transaction, ref_name.buf,
 +                                         t->sha1, NULL, 0, msg, &err)) {
                        failure |= error("%s", err.buf);
                        goto cleanup;
                }
@@@ -3113,12 -3112,9 +3113,9 @@@ static void parse_progress(void
  
  static char* make_fast_import_path(const char *path)
  {
-       struct strbuf abs_path = STRBUF_INIT;
        if (!relative_marks_paths || is_absolute_path(path))
                return xstrdup(path);
-       strbuf_addf(&abs_path, "%s/info/fast-import/%s", get_git_dir(), path);
-       return strbuf_detach(&abs_path, NULL);
+       return xstrdup(git_path("info/fast-import/%s", path));
  }
  
  static void option_import_marks(const char *marks,
diff --combined git-am.sh
index a67d0f98989706fa69df4cf7d6242ad9531eb337,66803d12764d0df8970092ba057ded9442c86352..761befbd37088c176a65e4d3a12e8a8281e47553
+++ b/git-am.sh
@@@ -17,7 -17,6 +17,7 @@@ s,signoff       add a Signed-off-by lin
  u,utf8          recode into utf8 (default)
  k,keep          pass -k flag to git-mailinfo
  keep-non-patch  pass -b flag to git-mailinfo
 +m,message-id    pass -m flag to git-mailinfo
  keep-cr         pass --keep-cr flag to git-mailsplit for mbox format
  no-keep-cr      do not pass --keep-cr flag to git-mailsplit independent of am.keepcr
  c,scissors      strip everything before a scissors line
@@@ -372,18 -371,13 +372,18 @@@ split_patches () 
  prec=4
  dotest="$GIT_DIR/rebase-apply"
  sign= utf8=t keep= keepcr= skip= interactive= resolved= rebasing= abort=
 -resolvemsg= resume= scissors= no_inbody_headers=
 +messageid= resolvemsg= resume= scissors= no_inbody_headers=
  git_apply_opt=
  committer_date_is_author_date=
  ignore_date=
  allow_rerere_autoupdate=
  gpg_sign_opt=
  
 +if test "$(git config --bool --get am.messageid)" = true
 +then
 +    messageid=t
 +fi
 +
  if test "$(git config --bool --get am.keepcr)" = true
  then
      keepcr=t
@@@ -406,10 -400,6 +406,10 @@@ it will be removed. Please do not use i
                utf8=t ;; # this is now default
        --no-utf8)
                utf8= ;;
 +      -m|--message-id)
 +              messageid=t ;;
 +      --no-message-id)
 +              messageid=f ;;
        -k|--keep)
                keep=t ;;
        --keep-non-patch)
@@@ -577,7 -567,6 +577,7 @@@ Use \"git am --abort\" to remove it.")
        echo "$sign" >"$dotest/sign"
        echo "$utf8" >"$dotest/utf8"
        echo "$keep" >"$dotest/keep"
 +      echo "$messageid" >"$dotest/messageid"
        echo "$scissors" >"$dotest/scissors"
        echo "$no_inbody_headers" >"$dotest/no_inbody_headers"
        echo "$GIT_QUIET" >"$dotest/quiet"
  *)
        keep= ;;
  esac
 +case "$(cat "$dotest/messageid")" in
 +t)
 +      messageid=-m ;;
 +f)
 +      messageid= ;;
 +esac
  case "$(cat "$dotest/scissors")" in
  t)
        scissors=--scissors ;;
@@@ -709,7 -692,7 +709,7 @@@ d
                        get_author_ident_from_commit "$commit" >"$dotest/author-script"
                        git diff-tree --root --binary --full-index "$commit" >"$dotest/patch"
                else
 -                      git mailinfo $keep $no_inbody_headers $scissors $utf8 "$dotest/msg" "$dotest/patch" \
 +                      git mailinfo $keep $no_inbody_headers $messageid $scissors $utf8 "$dotest/msg" "$dotest/patch" \
                                <"$dotest/$msgnum" >"$dotest/info" ||
                                stop_here $this
  
@@@ -827,10 -810,10 +827,10 @@@ To restore the original branch and sto
                continue
        fi
  
-       if test -x "$GIT_DIR"/hooks/applypatch-msg
+       hook="$(git rev-parse --git-path hooks/applypatch-msg)"
+       if test -x "$hook"
        then
-               "$GIT_DIR"/hooks/applypatch-msg "$dotest/final-commit" ||
-               stop_here $this
+               "$hook" "$dotest/final-commit" || stop_here $this
        fi
  
        if test -f "$dotest/final-commit"
@@@ -904,9 -887,10 +904,10 @@@ did you forget to use 'git add'?
                stop_here_user_resolve $this
        fi
  
-       if test -x "$GIT_DIR"/hooks/pre-applypatch
+       hook="$(git rev-parse --git-path hooks/pre-applypatch)"
+       if test -x "$hook"
        then
-               "$GIT_DIR"/hooks/pre-applypatch || stop_here $this
+               "$hook" || stop_here $this
        fi
  
        tree=$(git write-tree) &&
                echo "$(cat "$dotest/original-commit") $commit" >> "$dotest/rewritten"
        fi
  
-       if test -x "$GIT_DIR"/hooks/post-applypatch
-       then
-               "$GIT_DIR"/hooks/post-applypatch
-       fi
+       hook="$(git rev-parse --git-path hooks/post-applypatch)"
+       test -x "$hook" && "$hook"
  
        go_next
  done
  
  if test -s "$dotest"/rewritten; then
      git notes copy --for-rewrite=rebase < "$dotest"/rewritten
-     if test -x "$GIT_DIR"/hooks/post-rewrite; then
-       "$GIT_DIR"/hooks/post-rewrite rebase < "$dotest"/rewritten
+     hook="$(git rev-parse --git-path hooks/post-rewrite)"
+     if test -x "$hook"; then
+       "$hook" rebase < "$dotest"/rewritten
      fi
  fi
  
index f7deeb096e24f4de69bdfe08f0aa35ebf170577a,b32f797aa91bff965c8d35c0e2b591ff52f1fb4e..08e5d86fe5b5eda37f2ab44c3cce6dabb42c54e1
@@@ -642,9 -642,9 +642,9 @@@ do_next () 
                git notes copy --for-rewrite=rebase < "$rewritten_list" ||
                true # we don't care if this copying failed
        } &&
-       if test -x "$GIT_DIR"/hooks/post-rewrite &&
-               test -s "$rewritten_list"; then
-               "$GIT_DIR"/hooks/post-rewrite rebase < "$rewritten_list"
+       hook="$(git rev-parse --git-path hooks/post-rewrite)"
+       if test -x "$hook" && test -s "$rewritten_list"; then
+               "$hook" rebase < "$rewritten_list"
                true # we don't care if this hook failed
        fi &&
        warn "Successfully rebased and updated $head_name."
@@@ -961,13 -961,14 +961,13 @@@ els
        revisions=$onto...$orig_head
        shortrevisions=$shorthead
  fi
 -git rev-list $merges_option --pretty=oneline --abbrev-commit \
 -      --abbrev=7 --reverse --left-right --topo-order \
 +git rev-list $merges_option --pretty=oneline --reverse --left-right --topo-order \
        $revisions ${restrict_revision+^$restrict_revision} | \
        sed -n "s/^>//p" |
 -while read -r shortsha1 rest
 +while read -r sha1 rest
  do
  
 -      if test -z "$keep_empty" && is_empty_commit $shortsha1 && ! is_merge_commit $shortsha1
 +      if test -z "$keep_empty" && is_empty_commit $sha1 && ! is_merge_commit $sha1
        then
                comment_out="$comment_char "
        else
  
        if test t != "$preserve_merges"
        then
 -              printf '%s\n' "${comment_out}pick $shortsha1 $rest" >>"$todo"
 +              printf '%s\n' "${comment_out}pick $sha1 $rest" >>"$todo"
        else
 -              sha1=$(git rev-parse $shortsha1)
                if test -z "$rebase_root"
                then
                        preserve=t
                if test f = "$preserve"
                then
                        touch "$rewritten"/$sha1
 -                      printf '%s\n' "${comment_out}pick $shortsha1 $rest" >>"$todo"
 +                      printf '%s\n' "${comment_out}pick $sha1 $rest" >>"$todo"
                fi
        fi
  done
@@@ -1018,8 -1020,8 +1018,8 @@@ the
                        # just the history of its first-parent for others that will
                        # be rebasing on top of it
                        git rev-list --parents -1 $rev | cut -d' ' -s -f2 > "$dropped"/$rev
 -                      short=$(git rev-list -1 --abbrev-commit --abbrev=7 $rev)
 -                      sane_grep -v "^[a-z][a-z]* $short" <"$todo" > "${todo}2" ; mv "${todo}2" "$todo"
 +                      sha1=$(git rev-list -1 $rev)
 +                      sane_grep -v "^[a-z][a-z]* $sha1" <"$todo" > "${todo}2" ; mv "${todo}2" "$todo"
                        rm "$rewritten"/$rev
                fi
        done
@@@ -1029,12 -1031,9 +1029,12 @@@ test -s "$todo" || echo noop >> "$todo
  test -n "$autosquash" && rearrange_squash "$todo"
  test -n "$cmd" && add_exec_commands "$todo"
  
 +todocount=$(git stripspace --strip-comments <"$todo" | wc -l)
 +todocount=${todocount##* }
 +
  cat >>"$todo" <<EOF
  
 -$comment_char Rebase $shortrevisions onto $shortonto
 +$comment_char Rebase $shortrevisions onto $shortonto ($todocount command(s))
  EOF
  append_todo_help
  git stripspace --comment-lines >>"$todo" <<\EOF
@@@ -1053,7 -1052,6 +1053,7 @@@ has_action "$todo" |
        return 2
  
  cp "$todo" "$todo".backup
 +collapse_todo_ids
  git_sequence_editor "$todo" ||
        die_abort "Could not execute editor"
  
diff --combined git-sh-setup.sh
index c42c6e6365090e22ec7892baa51b919f2898e956,94a5c6d9572b1115a6304191ba0fd0b7bbce3aea..4691fbcb64fe7ecbc58930bb96d4e6b28e2b87a7
@@@ -81,7 -81,7 +81,7 @@@ if test -n "$OPTIONS_SPEC"; the
                echo exit $?
        )"
  else
 -      dashless=$(basename "$0" | sed -e 's/-/ /')
 +      dashless=$(basename -- "$0" | sed -e 's/-/ /')
        usage() {
                die "usage: $dashless $USAGE"
        }
@@@ -344,7 -344,7 +344,7 @@@ git_dir_init () 
                echo >&2 "Unable to determine absolute path of git directory"
                exit 1
        }
-       : ${GIT_OBJECT_DIRECTORY="$GIT_DIR/objects"}
+       : ${GIT_OBJECT_DIRECTORY="$(git rev-parse --git-path objects)"}
  }
  
  if test -z "$NONGIT_OK"
diff --combined git.c
index 42a4ee57843f569fb754121f01bb8c46feee2fd3,160896a9439007b1ca110b56bac327d3b0e6af3d..44374b1d9b6b73b3669f0f851bee058f45ee4f32
--- 1/git.c
--- 2/git.c
+++ b/git.c
@@@ -1,12 -1,15 +1,12 @@@
  #include "builtin.h"
 -#include "cache.h"
  #include "exec_cmd.h"
  #include "help.h"
 -#include "quote.h"
  #include "run-command.h"
 -#include "commit.h"
  
  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>]";
  
@@@ -204,12 -207,10 +204,12 @@@ static int handle_options(const char **
                                fprintf(stderr, "No directory given for -C.\n" );
                                usage(git_usage_string);
                        }
 -                      if (chdir((*argv)[1]))
 -                              die_errno("Cannot change to '%s'", (*argv)[1]);
 -                      if (envchanged)
 -                              *envchanged = 1;
 +                      if ((*argv)[1][0]) {
 +                              if (chdir((*argv)[1]))
 +                                      die_errno("Cannot change to '%s'", (*argv)[1]);
 +                              if (envchanged)
 +                                      *envchanged = 1;
 +                      }
                        (*argv)++;
                        (*argc)--;
                } else {
@@@ -382,7 -383,7 +382,7 @@@ static struct cmd_struct commands[] = 
        { "check-ignore", cmd_check_ignore, RUN_SETUP | NEED_WORK_TREE },
        { "check-mailmap", cmd_check_mailmap, RUN_SETUP },
        { "check-ref-format", cmd_check_ref_format },
-       { "checkout", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },
+       { "checkout", cmd_checkout, RUN_SETUP },
        { "checkout-index", cmd_checkout_index,
                RUN_SETUP | NEED_WORK_TREE},
        { "cherry", cmd_cherry, RUN_SETUP },
        { "write-tree", cmd_write_tree, RUN_SETUP },
  };
  
 -int is_builtin(const char *s)
 +static struct cmd_struct *get_builtin(const char *s)
  {
        int i;
        for (i = 0; i < ARRAY_SIZE(commands); i++) {
 -              struct cmd_struct *p = commands+i;
 +              struct cmd_struct *p = commands + i;
                if (!strcmp(s, p->cmd))
 -                      return 1;
 +                      return p;
        }
 -      return 0;
 +      return NULL;
 +}
 +
 +int is_builtin(const char *s)
 +{
 +      return !!get_builtin(s);
  }
  
  static void handle_builtin(int argc, const char **argv)
        const char *cmd = argv[0];
        int i;
        static const char ext[] = STRIP_EXTENSION;
 +      struct cmd_struct *builtin;
  
        if (sizeof(ext) > 1) {
                i = strlen(argv[0]) - strlen(ext);
                argv[0] = cmd = "help";
        }
  
 -      for (i = 0; i < ARRAY_SIZE(commands); i++) {
 -              struct cmd_struct *p = commands+i;
 -              if (strcmp(p->cmd, cmd))
 -                      continue;
 -              if (saved_environment && (p->option & NO_SETUP)) {
 +      builtin = get_builtin(cmd);
 +      if (builtin) {
 +              if (saved_environment && (builtin->option & NO_SETUP))
                        restore_env();
 -                      break;
 -              }
 -              exit(run_builtin(p, argc, argv));
 +              else
 +                      exit(run_builtin(builtin, argc, argv));
        }
  }
  
@@@ -620,7 -618,6 +620,7 @@@ int main(int argc, char **av
  {
        const char **argv = (const char **) av;
        const char *cmd;
 +      int done_help = 0;
  
        startup_info = &git_startup_info;
  
        setup_path();
  
        while (1) {
 -              static int done_help = 0;
 -              static int was_alias = 0;
 -              was_alias = run_argv(&argc, &argv);
 +              int was_alias = run_argv(&argc, &argv);
                if (errno != ENOENT)
                        break;
                if (was_alias) {
diff --combined notes-merge.c
index 109ff4ef410b77a814cca282f728f1b88948e4ec,f39e906a34695d4f21b7c8d5f99ebdecf3ae861e..0b2b82c41fc043a48e9bf458c4f75f992ead7175
@@@ -280,7 -280,7 +280,7 @@@ static void check_notes_merge_worktree(
                                    "(%s exists).", git_path("NOTES_MERGE_*"));
                }
  
-               if (safe_create_leading_directories(git_path(
+               if (safe_create_leading_directories_const(git_path(
                                NOTES_MERGE_WORKTREE "/.test")))
                        die_errno("unable to create directory %s",
                                  git_path(NOTES_MERGE_WORKTREE));
@@@ -295,8 -295,8 +295,8 @@@ static void write_buf_to_worktree(cons
                                  const char *buf, unsigned long size)
  {
        int fd;
-       char *path = git_path(NOTES_MERGE_WORKTREE "/%s", sha1_to_hex(obj));
-       if (safe_create_leading_directories(path))
+       const char *path = git_path(NOTES_MERGE_WORKTREE "/%s", sha1_to_hex(obj));
+       if (safe_create_leading_directories_const(path))
                die_errno("unable to create directory for '%s'", path);
        if (file_exists(path))
                die("found existing file at '%s'", path);
@@@ -594,7 -594,7 +594,7 @@@ int notes_merge(struct notes_merge_opti
        assert(local && remote);
  
        /* Find merge bases */
 -      bases = get_merge_bases(local, remote, 1);
 +      bases = get_merge_bases(local, remote);
        if (!bases) {
                base_sha1 = null_sha1;
                base_tree_sha1 = EMPTY_TREE_SHA1_BIN;
diff --combined path.c
index 595da81ca67096bae9592d9455bdade442b92628,a5c51a33bd03158f1ac9624e98e7d6b4ddf32e18..586f2c90a3c0def34016a692a14e335a46c015ed
--- 1/path.c
--- 2/path.c
+++ b/path.c
@@@ -4,6 -4,7 +4,7 @@@
  #include "cache.h"
  #include "strbuf.h"
  #include "string-list.h"
+ #include "dir.h"
  
  static int get_st_mode_bits(const char *path, int *mode)
  {
  
  static char bad_path[] = "/bad-path/";
  
- static char *get_pathname(void)
+ static struct strbuf *get_pathname(void)
  {
-       static char pathname_array[4][PATH_MAX];
+       static struct strbuf pathname_array[4] = {
+               STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
+       };
        static int index;
-       return pathname_array[3 & ++index];
+       struct strbuf *sb = &pathname_array[3 & ++index];
+       strbuf_reset(sb);
+       return sb;
  }
  
  static char *cleanup_path(char *path)
        return path;
  }
  
+ static void strbuf_cleanup_path(struct strbuf *sb)
+ {
+       char *path = cleanup_path(sb->buf);
+       if (path > sb->buf)
+               strbuf_remove(sb, 0, path - sb->buf);
+ }
  char *mksnpath(char *buf, size_t n, const char *fmt, ...)
  {
        va_list args;
        return cleanup_path(buf);
  }
  
- static char *vsnpath(char *buf, size_t n, const char *fmt, va_list args)
+ static int dir_prefix(const char *buf, const char *dir)
  {
-       const char *git_dir = get_git_dir();
-       size_t len;
+       int len = strlen(dir);
+       return !strncmp(buf, dir, len) &&
+               (is_dir_sep(buf[len]) || buf[len] == '\0');
+ }
  
-       len = strlen(git_dir);
-       if (n < len + 1)
-               goto bad;
-       memcpy(buf, git_dir, len);
-       if (len && !is_dir_sep(git_dir[len-1]))
-               buf[len++] = '/';
-       len += vsnprintf(buf + len, n - len, fmt, args);
-       if (len >= n)
-               goto bad;
-       return cleanup_path(buf);
- bad:
-       strlcpy(buf, bad_path, n);
-       return buf;
+ /* $buf =~ m|$dir/+$file| but without regex */
+ static int is_dir_file(const char *buf, const char *dir, const char *file)
+ {
+       int len = strlen(dir);
+       if (strncmp(buf, dir, len) || !is_dir_sep(buf[len]))
+               return 0;
+       while (is_dir_sep(buf[len]))
+               len++;
+       return !strcmp(buf + len, file);
+ }
+ static void replace_dir(struct strbuf *buf, int len, const char *newdir)
+ {
+       int newlen = strlen(newdir);
+       int need_sep = (buf->buf[len] && !is_dir_sep(buf->buf[len])) &&
+               !is_dir_sep(newdir[newlen - 1]);
+       if (need_sep)
+               len--;   /* keep one char, to be replaced with '/'  */
+       strbuf_splice(buf, 0, len, newdir, newlen);
+       if (need_sep)
+               buf->buf[newlen] = '/';
+ }
+ static const char *common_list[] = {
+       "/branches", "/hooks", "/info", "!/logs", "/lost-found",
+       "/objects", "/refs", "/remotes", "/worktrees", "/rr-cache", "/svn",
+       "config", "!gc.pid", "packed-refs", "shallow",
+       NULL
+ };
+ static void update_common_dir(struct strbuf *buf, int git_dir_len)
+ {
+       char *base = buf->buf + git_dir_len;
+       const char **p;
+       if (is_dir_file(base, "logs", "HEAD") ||
+           is_dir_file(base, "info", "sparse-checkout"))
+               return; /* keep this in $GIT_DIR */
+       for (p = common_list; *p; p++) {
+               const char *path = *p;
+               int is_dir = 0;
+               if (*path == '!')
+                       path++;
+               if (*path == '/') {
+                       path++;
+                       is_dir = 1;
+               }
+               if (is_dir && dir_prefix(base, path)) {
+                       replace_dir(buf, git_dir_len, get_git_common_dir());
+                       return;
+               }
+               if (!is_dir && !strcmp(base, path)) {
+                       replace_dir(buf, git_dir_len, get_git_common_dir());
+                       return;
+               }
+       }
+ }
+ void report_linked_checkout_garbage(void)
+ {
+       struct strbuf sb = STRBUF_INIT;
+       const char **p;
+       int len;
+       if (!git_common_dir_env)
+               return;
+       strbuf_addf(&sb, "%s/", get_git_dir());
+       len = sb.len;
+       for (p = common_list; *p; p++) {
+               const char *path = *p;
+               if (*path == '!')
+                       continue;
+               strbuf_setlen(&sb, len);
+               strbuf_addstr(&sb, path);
+               if (file_exists(sb.buf))
+                       report_garbage("unused in linked checkout", sb.buf);
+       }
+       strbuf_release(&sb);
  }
  
- char *git_snpath(char *buf, size_t n, const char *fmt, ...)
+ static void adjust_git_path(struct strbuf *buf, int git_dir_len)
+ {
+       const char *base = buf->buf + git_dir_len;
+       if (git_graft_env && is_dir_file(base, "info", "grafts"))
+               strbuf_splice(buf, 0, buf->len,
+                             get_graft_file(), strlen(get_graft_file()));
+       else if (git_index_env && !strcmp(base, "index"))
+               strbuf_splice(buf, 0, buf->len,
+                             get_index_file(), strlen(get_index_file()));
+       else if (git_db_env && dir_prefix(base, "objects"))
+               replace_dir(buf, git_dir_len + 7, get_object_directory());
+       else if (git_common_dir_env)
+               update_common_dir(buf, git_dir_len);
+ }
+ static void do_git_path(struct strbuf *buf, const char *fmt, va_list args)
+ {
+       int gitdir_len;
+       strbuf_addstr(buf, get_git_dir());
+       if (buf->len && !is_dir_sep(buf->buf[buf->len - 1]))
+               strbuf_addch(buf, '/');
+       gitdir_len = buf->len;
+       strbuf_vaddf(buf, fmt, args);
+       adjust_git_path(buf, gitdir_len);
+       strbuf_cleanup_path(buf);
+ }
+ void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
  {
-       char *ret;
        va_list args;
        va_start(args, fmt);
-       ret = vsnpath(buf, n, fmt, args);
+       do_git_path(sb, fmt, args);
        va_end(args);
-       return ret;
  }
  
- char *git_pathdup(const char *fmt, ...)
+ const char *git_path(const char *fmt, ...)
  {
-       char path[PATH_MAX], *ret;
+       struct strbuf *pathname = get_pathname();
        va_list args;
        va_start(args, fmt);
-       ret = vsnpath(path, sizeof(path), fmt, args);
+       do_git_path(pathname, fmt, args);
        va_end(args);
-       return xstrdup(ret);
+       return pathname->buf;
  }
  
- char *mkpathdup(const char *fmt, ...)
+ char *git_pathdup(const char *fmt, ...)
  {
-       char *path;
-       struct strbuf sb = STRBUF_INIT;
+       struct strbuf path = STRBUF_INIT;
        va_list args;
        va_start(args, fmt);
-       strbuf_vaddf(&sb, fmt, args);
+       do_git_path(&path, fmt, args);
        va_end(args);
-       path = xstrdup(cleanup_path(sb.buf));
-       strbuf_release(&sb);
-       return path;
+       return strbuf_detach(&path, NULL);
  }
  
- char *mkpath(const char *fmt, ...)
+ char *mkpathdup(const char *fmt, ...)
  {
+       struct strbuf sb = STRBUF_INIT;
        va_list args;
-       unsigned len;
-       char *pathname = get_pathname();
        va_start(args, fmt);
-       len = vsnprintf(pathname, PATH_MAX, fmt, args);
+       strbuf_vaddf(&sb, fmt, args);
        va_end(args);
-       if (len >= PATH_MAX)
-               return bad_path;
-       return cleanup_path(pathname);
+       strbuf_cleanup_path(&sb);
+       return strbuf_detach(&sb, NULL);
  }
  
- char *git_path(const char *fmt, ...)
+ const char *mkpath(const char *fmt, ...)
  {
-       char *pathname = get_pathname();
        va_list args;
-       char *ret;
+       struct strbuf *pathname = get_pathname();
        va_start(args, fmt);
-       ret = vsnpath(pathname, PATH_MAX, fmt, args);
+       strbuf_vaddf(pathname, fmt, args);
        va_end(args);
-       return ret;
+       return cleanup_path(pathname->buf);
  }
  
  void home_config_paths(char **global, char **xdg, char *file)
        free(to_free);
  }
  
- char *git_path_submodule(const char *path, const char *fmt, ...)
+ const char *git_path_submodule(const char *path, const char *fmt, ...)
  {
-       char *pathname = get_pathname();
-       struct strbuf buf = STRBUF_INIT;
+       struct strbuf *buf = get_pathname();
        const char *git_dir;
        va_list args;
-       unsigned len;
  
-       len = strlen(path);
-       if (len > PATH_MAX-100)
-               return bad_path;
+       strbuf_addstr(buf, path);
+       if (buf->len && buf->buf[buf->len - 1] != '/')
+               strbuf_addch(buf, '/');
+       strbuf_addstr(buf, ".git");
  
-       strbuf_addstr(&buf, path);
-       if (len && path[len-1] != '/')
-               strbuf_addch(&buf, '/');
-       strbuf_addstr(&buf, ".git");
-       git_dir = read_gitfile(buf.buf);
+       git_dir = read_gitfile(buf->buf);
        if (git_dir) {
-               strbuf_reset(&buf);
-               strbuf_addstr(&buf, git_dir);
+               strbuf_reset(buf);
+               strbuf_addstr(buf, git_dir);
        }
-       strbuf_addch(&buf, '/');
-       if (buf.len >= PATH_MAX)
-               return bad_path;
-       memcpy(pathname, buf.buf, buf.len + 1);
-       strbuf_release(&buf);
-       len = strlen(pathname);
+       strbuf_addch(buf, '/');
  
        va_start(args, fmt);
-       len += vsnprintf(pathname + len, PATH_MAX - len, fmt, args);
+       strbuf_vaddf(buf, fmt, args);
        va_end(args);
-       if (len >= PATH_MAX)
-               return bad_path;
-       return cleanup_path(pathname);
+       strbuf_cleanup_path(buf);
+       return buf->buf;
  }
  
  int validate_headref(const char *path)
@@@ -303,9 -383,14 +383,9 @@@ return_null
   * (3) "relative/path" to mean cwd relative directory; or
   * (4) "/absolute/path" to mean absolute directory.
   *
 - * Unless "strict" is given, we try access() for existence of "%s.git/.git",
 - * "%s/.git", "%s.git", "%s" in this order.  The first one that exists is
 - * what we try.
 - *
 - * Second, we try chdir() to that.  Upon failure, we return NULL.
 - *
 - * Then, we try if the current directory is a valid git repository.
 - * Upon failure, we return NULL.
 + * Unless "strict" is given, we check "%s/.git", "%s", "%s.git/.git", "%s.git"
 + * in this order. We select the first one that is a valid git repository, and
 + * chdir() to it. If none match, or we fail to chdir, we return NULL.
   *
   * If all goes well, we return the directory we used to chdir() (but
   * before ~user is expanded), avoiding getcwd() resolving symbolic
@@@ -818,36 -903,3 +898,36 @@@ int daemon_avoid_alias(const char *p
                }
        }
  }
 +
 +static int only_spaces_and_periods(const char *path, size_t len, size_t skip)
 +{
 +      if (len < skip)
 +              return 0;
 +      len -= skip;
 +      path += skip;
 +      while (len-- > 0) {
 +              char c = *(path++);
 +              if (c != ' ' && c != '.')
 +                      return 0;
 +      }
 +      return 1;
 +}
 +
 +int is_ntfs_dotgit(const char *name)
 +{
 +      int len;
 +
 +      for (len = 0; ; len++)
 +              if (!name[len] || name[len] == '\\' || is_dir_sep(name[len])) {
 +                      if (only_spaces_and_periods(name, len, 4) &&
 +                                      !strncasecmp(name, ".git", 4))
 +                              return 1;
 +                      if (only_spaces_and_periods(name, len, 5) &&
 +                                      !strncasecmp(name, "git~1", 5))
 +                              return 1;
 +                      if (name[len] != '\\')
 +                              return 0;
 +                      name += len + 1;
 +                      len = -1;
 +              }
 +}
diff --combined refs.c
index 47e4e5380a1e0fc04f8b81837c51c023f35871cf,5ed991bd92856bc8b2c5978923a118b8122a6eb5..0312f052575046f0dd539b19897b61eddc2862e0
--- 1/refs.c
--- 2/refs.c
+++ b/refs.c
@@@ -6,14 -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
@@@ -34,29 -26,10 +34,29 @@@ static unsigned char refname_dispositio
  };
  
  /*
 - * 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
@@@ -1095,10 -1068,8 +1095,10 @@@ static const char PACKED_REFS_HEADER[] 
   * Return a pointer to the refname within the line (null-terminated),
   * or NULL if there was a problem.
   */
 -static const char *parse_ref_line(char *line, unsigned char *sha1)
 +static const char *parse_ref_line(struct strbuf *line, unsigned char *sha1)
  {
 +      const char *ref;
 +
        /*
         * 42: the answer to everything.
         *
         *  +1 (space in between hex and name)
         *  +1 (newline at the end of the line)
         */
 -      int len = strlen(line) - 42;
 -
 -      if (len <= 0)
 +      if (line->len <= 42)
                return NULL;
 -      if (get_sha1_hex(line, sha1) < 0)
 +
 +      if (get_sha1_hex(line->buf, sha1) < 0)
                return NULL;
 -      if (!isspace(line[40]))
 +      if (!isspace(line->buf[40]))
                return NULL;
 -      line += 41;
 -      if (isspace(*line))
 +
 +      ref = line->buf + 41;
 +      if (isspace(*ref))
                return NULL;
 -      if (line[len] != '\n')
 +
 +      if (line->buf[line->len - 1] != '\n')
                return NULL;
 -      line[len] = 0;
 +      line->buf[--line->len] = 0;
  
 -      return line;
 +      return ref;
  }
  
  /*
  static void read_packed_refs(FILE *f, struct ref_dir *dir)
  {
        struct ref_entry *last = NULL;
 -      char refline[PATH_MAX];
 +      struct strbuf line = STRBUF_INIT;
        enum { PEELED_NONE, PEELED_TAGS, PEELED_FULLY } peeled = PEELED_NONE;
  
 -      while (fgets(refline, sizeof(refline), f)) {
 +      while (strbuf_getwholeline(&line, f, '\n') != EOF) {
                unsigned char sha1[20];
                const char *refname;
 -              static const char header[] = "# pack-refs with:";
 +              const char *traits;
  
 -              if (!strncmp(refline, header, sizeof(header)-1)) {
 -                      const char *traits = refline + sizeof(header) - 1;
 +              if (skip_prefix(line.buf, "# pack-refs with:", &traits)) {
                        if (strstr(traits, " fully-peeled "))
                                peeled = PEELED_FULLY;
                        else if (strstr(traits, " peeled "))
                        continue;
                }
  
 -              refname = parse_ref_line(refline, sha1);
 +              refname = parse_ref_line(&line, sha1);
                if (refname) {
                        int flag = REF_ISPACKED;
  
                        continue;
                }
                if (last &&
 -                  refline[0] == '^' &&
 -                  strlen(refline) == PEELED_LINE_LENGTH &&
 -                  refline[PEELED_LINE_LENGTH - 1] == '\n' &&
 -                  !get_sha1_hex(refline + 1, sha1)) {
 +                  line.buf[0] == '^' &&
 +                  line.len == PEELED_LINE_LENGTH &&
 +                  line.buf[PEELED_LINE_LENGTH - 1] == '\n' &&
 +                  !get_sha1_hex(line.buf + 1, sha1)) {
                        hashcpy(last->u.value.peeled, sha1);
                        /*
                         * Regardless of what the file header said,
                        last->flag |= REF_KNOWS_PEELED;
                }
        }
 +
 +      strbuf_release(&line);
  }
  
  /*
@@@ -1382,7 -1351,7 +1382,7 @@@ static int resolve_gitlink_ref_recursiv
  {
        int fd, len;
        char buffer[128], *p;
-       char *path;
+       const char *path;
  
        if (recursion > MAXDEPTH || strlen(refname) > MAXREFLEN)
                return -1;
@@@ -1475,7 -1444,11 +1475,11 @@@ static int resolve_missing_loose_ref(co
  }
  
  /* This function needs to return a meaningful errno on failure */
- const char *resolve_ref_unsafe(const char *refname, int resolve_flags, unsigned char *sha1, int *flags)
+ static const char *resolve_ref_unsafe_1(const char *refname,
+                                       int resolve_flags,
+                                       unsigned char *sha1,
+                                       int *flags,
+                                       struct strbuf *sb_path)
  {
        int depth = MAXDEPTH;
        ssize_t len;
                bad_name = 1;
        }
        for (;;) {
-               char path[PATH_MAX];
+               const char *path;
                struct stat st;
                char *buf;
                int fd;
                        return NULL;
                }
  
-               git_snpath(path, sizeof(path), "%s", refname);
+               strbuf_reset(sb_path);
+               strbuf_git_path(sb_path, "%s", refname);
+               path = sb_path->buf;
  
                /*
                 * We might have to loop back here to avoid a race
        }
  }
  
+ const char *resolve_ref_unsafe(const char *refname, int resolve_flags,
+                              unsigned char *sha1, int *flags)
+ {
+       struct strbuf sb_path = STRBUF_INIT;
+       const char *ret = resolve_ref_unsafe_1(refname, resolve_flags,
+                                              sha1, flags, &sb_path);
+       strbuf_release(&sb_path);
+       return ret;
+ }
  char *resolve_refdup(const char *ref, int resolve_flags, unsigned char *sha1, int *flags)
  {
 -      const char *ret = resolve_ref_unsafe(ref, resolve_flags, sha1, flags);
 -      return ret ? xstrdup(ret) : NULL;
 +      return xstrdup_or_null(resolve_ref_unsafe(ref, resolve_flags, sha1, flags));
  }
  
  /* The argument to filter_refs */
@@@ -1934,11 -1920,6 +1950,11 @@@ static int do_for_each_ref(struct ref_c
        data.fn = fn;
        data.cb_data = cb_data;
  
 +      if (ref_paranoia < 0)
 +              ref_paranoia = git_env_bool("GIT_REF_PARANOIA", 0);
 +      if (ref_paranoia)
 +              data.flags |= DO_FOR_EACH_INCLUDE_BROKEN;
 +
        return do_for_each_entry(refs, base, do_one_ref, &data);
  }
  
@@@ -2125,16 -2106,6 +2141,16 @@@ int refname_match(const char *abbrev_na
        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)
@@@ -2272,15 -2243,16 +2288,15 @@@ int dwim_log(const char *str, int len, 
  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 *ref_file;
        const char *orig_refname = refname;
        struct ref_lock *lock;
        int last_errno = 0;
        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));
                        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;
        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)) {
+       switch (safe_create_leading_directories_const(ref_file)) {
        case SCLD_OK:
                break; /* success */
        case SCLD_VANISHED:
  
        lock->lock_fd = hold_lock_file_for_update(lock->lk, ref_file, lflags);
        if (lock->lock_fd < 0) {
 +              last_errno = errno;
                if (errno == ENOENT && --attempts_remaining > 0)
                        /*
                         * Maybe somebody just deleted one of the
                         * again:
                         */
                        goto retry;
 -              else
 -                      unable_to_lock_die(ref_file, errno);
 +              else {
 +                      struct strbuf err = STRBUF_INIT;
 +                      unable_to_lock_message(ref_file, errno, &err);
 +                      error("%s", err.buf);
 +                      strbuf_release(&err);
 +                      goto error_return;
 +              }
        }
        return old_sha1 ? verify_lock(lock, old_sha1, mustexist) : lock;
  
        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.
@@@ -2581,7 -2558,7 +2597,7 @@@ static void prune_ref(struct ref_to_pru
        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);
@@@ -2621,24 -2598,79 +2637,24 @@@ int pack_refs(unsigned int flags
        return 0;
  }
  
 -/*
 - * If entry is no longer needed in packed-refs, add it to the string
 - * list pointed to by cb_data.  Reasons for deleting entries:
 - *
 - * - Entry is broken.
 - * - Entry is overridden by a loose ref.
 - * - Entry does not point at a valid object.
 - *
 - * In the first and third cases, also emit an error message because these
 - * are indications of repository corruption.
 - */
 -static int curate_packed_ref_fn(struct ref_entry *entry, void *cb_data)
 -{
 -      struct string_list *refs_to_delete = cb_data;
 -
 -      if (entry->flag & REF_ISBROKEN) {
 -              /* This shouldn't happen to packed refs. */
 -              error("%s is broken!", entry->name);
 -              string_list_append(refs_to_delete, entry->name);
 -              return 0;
 -      }
 -      if (!has_sha1_file(entry->u.value.sha1)) {
 -              unsigned char sha1[20];
 -              int flags;
 -
 -              if (read_ref_full(entry->name, 0, sha1, &flags))
 -                      /* We should at least have found the packed ref. */
 -                      die("Internal error");
 -              if ((flags & REF_ISSYMREF) || !(flags & REF_ISPACKED)) {
 -                      /*
 -                       * This packed reference is overridden by a
 -                       * loose reference, so it is OK that its value
 -                       * is no longer valid; for example, it might
 -                       * refer to an object that has been garbage
 -                       * collected.  For this purpose we don't even
 -                       * care whether the loose reference itself is
 -                       * invalid, broken, symbolic, etc.  Silently
 -                       * remove the packed reference.
 -                       */
 -                      string_list_append(refs_to_delete, entry->name);
 -                      return 0;
 -              }
 -              /*
 -               * There is no overriding loose reference, so the fact
 -               * that this reference doesn't refer to a valid object
 -               * indicates some kind of repository corruption.
 -               * Report the problem, then omit the reference from
 -               * the output.
 -               */
 -              error("%s does not point to a valid object!", entry->name);
 -              string_list_append(refs_to_delete, entry->name);
 -              return 0;
 -      }
 -
 -      return 0;
 -}
 -
 -int repack_without_refs(const char **refnames, int n, struct strbuf *err)
 +int repack_without_refs(struct string_list *refnames, struct strbuf *err)
  {
        struct ref_dir *packed;
 -      struct string_list refs_to_delete = STRING_LIST_INIT_DUP;
 -      struct string_list_item *ref_to_delete;
 -      int i, ret, removed = 0;
 +      struct string_list_item *refname;
 +      int ret, needs_repacking = 0, removed = 0;
  
        assert(err);
  
        /* Look for a packed ref */
 -      for (i = 0; i < n; i++)
 -              if (get_packed_ref(refnames[i]))
 +      for_each_string_list_item(refname, refnames) {
 +              if (get_packed_ref(refname->string)) {
 +                      needs_repacking = 1;
                        break;
 +              }
 +      }
  
        /* Avoid locking if we have nothing to do */
 -      if (i == n)
 +      if (!needs_repacking)
                return 0; /* no refname exists in packed refs */
  
        if (lock_packed_refs(0)) {
        packed = get_packed_refs(&ref_cache);
  
        /* Remove refnames from the cache */
 -      for (i = 0; i < n; i++)
 -              if (remove_entry(packed, refnames[i]) != -1)
 +      for_each_string_list_item(refname, refnames)
 +              if (remove_entry(packed, refname->string) != -1)
                        removed = 1;
        if (!removed) {
                /*
                return 0;
        }
  
 -      /* Remove any other accumulated cruft */
 -      do_for_each_entry_in_dir(packed, 0, curate_packed_ref_fn, &refs_to_delete);
 -      for_each_string_list_item(ref_to_delete, &refs_to_delete) {
 -              if (remove_entry(packed, ref_to_delete->string) == -1)
 -                      die("internal error");
 -      }
 -
        /* Write what remains */
        ret = commit_packed_refs();
        if (ret)
@@@ -2686,16 -2725,15 +2702,16 @@@ static int delete_ref_loose(struct ref_
        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);
@@@ -2721,7 -2759,7 +2737,7 @@@ static int rename_tmp_log(const char *n
        int attempts_remaining = 4;
  
   retry:
-       switch (safe_create_leading_directories(git_path("logs/%s", newrefname))) {
+       switch (safe_create_leading_directories_const(git_path("logs/%s", newrefname))) {
        case SCLD_OK:
                break; /* success */
        case SCLD_VANISHED:
@@@ -2831,6 -2869,7 +2847,6 @@@ int rename_ref(const char *oldrefname, 
                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);
                goto rollbacklog;
        }
  
 -      lock->force_write = 1;
        flag = log_all_ref_updates;
        log_all_ref_updates = 0;
        if (write_ref_sha1(lock, orig_sha1, NULL))
        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;
        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;
        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,
@@@ -2907,11 -2957,15 +2923,15 @@@ static int copy_msg(char *buf, const ch
  }
  
  /* This function must set a meaningful errno on failure */
- int log_ref_setup(const char *refname, char *logfile, int bufsize)
+ int log_ref_setup(const char *refname, struct strbuf *sb_logfile)
  {
        int logfd, oflags = O_APPEND | O_WRONLY;
+       char *logfile;
  
-       git_snpath(logfile, bufsize, "logs/%s", refname);
+       strbuf_git_path(sb_logfile, "logs/%s", refname);
+       logfile = sb_logfile->buf;
+       /* make sure the rest of the function can't change "logfile" */
+       sb_logfile = NULL;
        if (log_all_ref_updates &&
            (starts_with(refname, "refs/heads/") ||
             starts_with(refname, "refs/remotes/") ||
        return 0;
  }
  
- static int log_ref_write(const char *refname, const unsigned char *old_sha1,
-                        const unsigned char *new_sha1, const char *msg)
 +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_1(const char *refname, const unsigned char *old_sha1,
+                          const unsigned char *new_sha1, const char *msg,
+                          struct strbuf *sb_log_file)
  {
 -      int logfd, result, written, oflags = O_APPEND | O_WRONLY;
 -      unsigned maxlen, len;
 -      int msglen;
 -      const char *log_file;
 -      char *logrec;
 -      const char *committer;
 +      int logfd, result, oflags = O_APPEND | O_WRONLY;
-       char log_file[PATH_MAX];
++      char *log_file;
  
        if (log_all_ref_updates < 0)
                log_all_ref_updates = !is_bare_repository();
  
-       result = log_ref_setup(refname, log_file, sizeof(log_file));
+       result = log_ref_setup(refname, sb_log_file);
        if (result)
                return result;
+       log_file = sb_log_file->buf;
+       /* make sure the rest of the function can't change "log_file" */
+       sb_log_file = NULL;
  
        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);
        return 0;
  }
  
+ static int log_ref_write(const char *refname, const unsigned char *old_sha1,
+                        const unsigned char *new_sha1, const char *msg)
+ {
+       struct strbuf sb = STRBUF_INIT;
+       int ret = log_ref_write_1(refname, old_sha1, new_sha1, msg, &sb);
+       strbuf_release(&sb);
+       return ret;
+ }
  int is_branch(const char *refname)
  {
        return !strcmp(refname, "HEAD") || starts_with(refname, "refs/heads/");
@@@ -3031,6 -3086,14 +3064,6 @@@ static int write_ref_sha1(struct ref_lo
        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",
@@@ -3374,54 -3437,29 +3407,54 @@@ int for_each_reflog_ent_reverse(const c
  
                        bp = find_beginning_of_line(buf, scanp);
  
 -                      if (*bp != '\n') {
 -                              strbuf_splice(&sb, 0, 0, buf, endp - buf);
 -                              if (pos)
 -                                      break; /* need to fill another block */
 -                              scanp = buf - 1; /* leave loop */
 -                      } else {
 +                      if (*bp == '\n') {
                                /*
 -                               * (bp + 1) thru endp is the beginning of the
 -                               * current line we have in sb
 +                               * The newline is the end of the previous line,
 +                               * so we know we have complete line starting
 +                               * at (bp + 1). Prefix it onto any prior data
 +                               * we collected for the line and process it.
                                 */
                                strbuf_splice(&sb, 0, 0, bp + 1, endp - (bp + 1));
                                scanp = bp;
                                endp = bp + 1;
 +                              ret = show_one_reflog_ent(&sb, fn, cb_data);
 +                              strbuf_reset(&sb);
 +                              if (ret)
 +                                      break;
 +                      } else if (!pos) {
 +                              /*
 +                               * We are at the start of the buffer, and the
 +                               * start of the file; there is no previous
 +                               * line, and we have everything for this one.
 +                               * Process it, and we can end the loop.
 +                               */
 +                              strbuf_splice(&sb, 0, 0, buf, endp - buf);
 +                              ret = show_one_reflog_ent(&sb, fn, cb_data);
 +                              strbuf_reset(&sb);
 +                              break;
                        }
 -                      ret = show_one_reflog_ent(&sb, fn, cb_data);
 -                      strbuf_reset(&sb);
 -                      if (ret)
 +
 +                      if (bp == buf) {
 +                              /*
 +                               * We are at the start of the buffer, and there
 +                               * is more file to read backwards. Which means
 +                               * we are in the middle of a line. Note that we
 +                               * may get here even if *bp was a newline; that
 +                               * just means we are at the exact end of the
 +                               * previous line, rather than some spot in the
 +                               * middle.
 +                               *
 +                               * Save away what we have to be combined with
 +                               * the data from the next read.
 +                               */
 +                              strbuf_splice(&sb, 0, 0, buf, endp - buf);
                                break;
 +                      }
                }
  
        }
        if (!ret && sb.len)
 -              ret = show_one_reflog_ent(&sb, fn, cb_data);
 +              die("BUG: reverse reflog parser had leftover data");
  
        fclose(logfp);
        strbuf_release(&sb);
@@@ -3500,27 -3538,16 +3533,27 @@@ int for_each_reflog(each_ref_fn fn, voi
  }
  
  /**
 - * 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;
@@@ -3592,7 -3619,7 +3625,7 @@@ int ref_transaction_update(struct ref_t
                           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;
        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);
        }
  
        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;
  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";
  
@@@ -3722,11 -3771,10 +3755,11 @@@ static int ref_update_reject_duplicates
  int ref_transaction_commit(struct ref_transaction *transaction,
                           struct strbuf *err)
  {
 -      int ret = 0, delnum = 0, i;
 -      const char **delnames;
 +      int ret = 0, i;
        int n = transaction->nr;
        struct ref_update **updates = transaction->updates;
 +      struct string_list refs_to_delete = STRING_LIST_INIT_NODUP;
 +      struct string_list_item *ref_to_delete;
  
        assert(err);
  
                return 0;
        }
  
 -      /* Allocate work space */
 -      delnames = xmalloc(sizeof(*delnames) * n);
 -
        /* Copy, sort, and reject duplicate refs */
        qsort(updates, n, sizeof(*updates), ref_update_compare);
        if (ref_update_reject_duplicates(updates, n, err)) {
        /* 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
        /* 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 (!is_null_sha1(update->new_sha1)) {
 -                      if (write_ref_sha1(update->lock, update->new_sha1,
 -                                         update->msg)) {
 +              if ((flags & REF_HAVE_NEW) && !is_null_sha1(update->new_sha1)) {
 +                      int overwriting_symref = ((update->type & REF_ISSYMREF) &&
 +                                                (update->flags & REF_NODEREF));
 +
 +                      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))
 -                              delnames[delnum++] = update->lock->ref_name;
 +                      if (!(flags & REF_ISPRUNING))
 +                              string_list_append(&refs_to_delete,
 +                                                 update->lock->ref_name);
                }
        }
  
 -      if (repack_without_refs(delnames, delnum, err)) {
 +      if (repack_without_refs(&refs_to_delete, err)) {
                ret = TRANSACTION_GENERIC_ERROR;
                goto cleanup;
        }
 -      for (i = 0; i < delnum; i++)
 -              unlink_or_warn(git_path("logs/%s", delnames[i]));
 +      for_each_string_list_item(ref_to_delete, &refs_to_delete)
 +              unlink_or_warn(git_path("logs/%s", ref_to_delete->string));
        clear_loose_ref_cache(&ref_cache);
  
  cleanup:
        for (i = 0; i < n; i++)
                if (updates[i]->lock)
                        unlock_ref(updates[i]->lock);
 -      free(delnames);
 +      string_list_clear(&refs_to_delete, 0);
        return ret;
  }
  
@@@ -3970,141 -4005,3 +4003,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 --combined refs.h
index cf642e6ddc438be77d64797a4dbcf790262a9fed,1f882209595485cb7ba164a5750511bf46fb0c17..6d7d9b40f318119eea1e3240cca3a96d2c64e2a6
--- 1/refs.h
--- 2/refs.h
+++ b/refs.h
@@@ -1,6 -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.
@@@ -154,15 -163,7 +154,15 @@@ extern void rollback_packed_refs(void)
   */
  int pack_refs(unsigned int flags);
  
 -extern int repack_without_refs(const char **refnames, int n,
 +/*
 + * Rewrite the packed-refs file, omitting any refs listed in
 + * 'refnames'. On error, packed-refs will be unchanged, the return
 + * value is nonzero, and a message about the error is written to the
 + * 'err' strbuf.
 + *
 + * The refs in 'refnames' needn't be sorted. `err` must not be NULL.
 + */
 +extern int repack_without_refs(struct string_list *refnames,
                               struct strbuf *err);
  
  extern int ref_exists(const char *);
@@@ -180,18 -181,36 +180,18 @@@ extern int is_branch(const char *refnam
  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.
   */
- int log_ref_setup(const char *refname, char *logfile, int bufsize);
+ int log_ref_setup(const char *refname, struct strbuf *logfile);
  
  /** Reads log for the value of ref during at_time. **/
  extern int read_ref_at(const char *refname, unsigned int flags,
@@@ -255,95 -274,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);
  
  /*
@@@ -364,65 -345,12 +364,65 @@@ int ref_transaction_commit(struct ref_t
   */
  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 */
diff --combined run-command.c
index aad03ab705f301268980079282fcf370b9275c5a,c4a62aa0e8fb8eba8d6972461eed07097a52a976..4d73e90fad159184bfdd204b82dd8637ad28a955
@@@ -4,6 -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));
@@@ -557,12 -561,7 +557,12 @@@ int finish_command(struct child_proces
  
  int run_command(struct child_process *cmd)
  {
 -      int code = start_command(cmd);
 +      int code;
 +
 +      if (cmd->out < 0 || cmd->err < 0)
 +              die("BUG: run_command with a pipe can cause deadlock");
 +
 +      code = start_command(cmd);
        if (code)
                return code;
        return finish_command(cmd);
@@@ -795,9 -794,9 +795,9 @@@ int finish_async(struct async *async
  #endif
  }
  
- char *find_hook(const char *name)
+ const char *find_hook(const char *name)
  {
-       char *path = git_path("hooks/%s", name);
+       const char *path = git_path("hooks/%s", name);
        if (access(path, X_OK) < 0)
                path = NULL;
  
@@@ -835,18 -834,19 +835,18 @@@ int run_hook_le(const char *const *env
        return ret;
  }
  
 -int run_hook_with_custom_index(const char *index_file, const char *name, ...)
 +int capture_command(struct child_process *cmd, struct strbuf *buf, size_t hint)
  {
 -      const char *hook_env[3] =  { NULL };
 -      char index[PATH_MAX];
 -      va_list args;
 -      int ret;
 -
 -      snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file);
 -      hook_env[0] = index;
 +      cmd->out = -1;
 +      if (start_command(cmd) < 0)
 +              return -1;
  
 -      va_start(args, name);
 -      ret = run_hook_ve(hook_env, name, args);
 -      va_end(args);
 +      if (strbuf_read(buf, cmd->out, hint) < 0) {
 +              close(cmd->out);
 +              finish_command(cmd); /* throw away exit code */
 +              return -1;
 +      }
  
 -      return ret;
 +      close(cmd->out);
 +      return finish_command(cmd);
  }
diff --combined run-command.h
index 263b9662adeba011adcd018f77b7ccbbcd53e94a,892892de128b9dc9673fedba823159be9e5fff4a..1103805af1b01e8396de15f48fbd06f75313fb0d
@@@ -52,11 -52,15 +52,11 @@@ int start_command(struct child_process 
  int finish_command(struct child_process *);
  int run_command(struct child_process *);
  
- extern char *find_hook(const char *name);
+ extern const char *find_hook(const char *name);
  LAST_ARG_MUST_BE_NULL
  extern int run_hook_le(const char *const *env, const char *name, ...);
  extern int run_hook_ve(const char *const *env, const char *name, va_list args);
  
 -LAST_ARG_MUST_BE_NULL
 -__attribute__((deprecated))
 -extern int run_hook_with_custom_index(const char *index_file, const char *name, ...);
 -
  #define RUN_COMMAND_NO_STDIN 1
  #define RUN_GIT_CMD        2  /*If this is to be git sub-command */
  #define RUN_COMMAND_STDOUT_TO_STDERR 4
@@@ -71,19 -75,6 +71,19 @@@ int run_command_v_opt(const char **argv
   */
  int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const char *const *env);
  
 +/**
 + * Execute the given command, capturing its stdout in the given strbuf.
 + * Returns -1 if starting the command fails or reading fails, and otherwise
 + * returns the exit code of the command. The output collected in the
 + * buffer is kept even if the command returns a non-zero exit. The hint field
 + * gives a starting size for the strbuf allocation.
 + *
 + * The fields of "cmd" should be set up as they would for a normal run_command
 + * invocation. But note that there is no need to set cmd->out; the function
 + * sets it up for the caller.
 + */
 +int capture_command(struct child_process *cmd, struct strbuf *buf, size_t hint);
 +
  /*
   * The purpose of the following functions is to feed a pipe by running
   * a function asynchronously and providing output that the caller reads.
diff --combined sha1_file.c
index f860d67744784f69b83733757b9a894df3563de7,1ed74f955fa66ab15790d5e634ceca43d416a4e4..47c4929eb7060724411532dd0cec894067393d5e
@@@ -405,7 -405,7 +405,7 @@@ void add_to_alternates_file(const char 
  {
        struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
        int fd = hold_lock_file_for_append(lock, git_path("objects/info/alternates"), LOCK_DIE_ON_ERROR);
-       char *alt = mkpath("%s\n", reference);
+       const char *alt = mkpath("%s\n", reference);
        write_or_die(fd, alt, strlen(alt));
        if (commit_lock_file(lock))
                die("could not close alternates file");
@@@ -1198,7 -1198,7 +1198,7 @@@ static void report_pack_garbage(struct 
        if (!report_garbage)
                return;
  
 -      sort_string_list(list);
 +      string_list_sort(list);
  
        for (i = 0; i < list->nr; i++) {
                const char *path = list->items[i].string;
@@@ -2943,6 -2943,7 +2943,6 @@@ static int write_loose_object(const uns
        }
  
        /* Set it up */
 -      memset(&stream, 0, sizeof(stream));
        git_deflate_init(&stream, zlib_compression_level);
        stream.next_out = compressed;
        stream.avail_out = sizeof(compressed);
@@@ -2999,14 -3000,7 +2999,14 @@@ static int freshen_loose_object(const u
  static int freshen_packed_object(const unsigned char *sha1)
  {
        struct pack_entry e;
 -      return find_pack_entry(sha1, &e) && freshen_file(e.p->pack_name);
 +      if (!find_pack_entry(sha1, &e))
 +              return 0;
 +      if (e.p->freshened)
 +              return 1;
 +      if (!freshen_file(e.p->pack_name))
 +              return 0;
 +      e.p->freshened = 1;
 +      return 1;
  }
  
  int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *returnsha1)
        write_sha1_file_prepare(buf, len, type, sha1, hdr, &hdrlen);
        if (returnsha1)
                hashcpy(returnsha1, sha1);
 -      if (freshen_loose_object(sha1) || freshen_packed_object(sha1))
 +      if (freshen_packed_object(sha1) || freshen_loose_object(sha1))
                return 0;
        return write_loose_object(sha1, hdr, hdrlen, buf, len, 0);
  }
@@@ -3365,42 -3359,31 +3365,42 @@@ static int for_each_file_in_obj_subdir(
        return r;
  }
  
 -int for_each_loose_file_in_objdir(const char *path,
 +int for_each_loose_file_in_objdir_buf(struct strbuf *path,
                            each_loose_object_fn obj_cb,
                            each_loose_cruft_fn cruft_cb,
                            each_loose_subdir_fn subdir_cb,
                            void *data)
  {
 -      struct strbuf buf = STRBUF_INIT;
 -      size_t baselen;
 +      size_t baselen = path->len;
        int r = 0;
        int i;
  
 -      strbuf_addstr(&buf, path);
 -      strbuf_addch(&buf, '/');
 -      baselen = buf.len;
 -
        for (i = 0; i < 256; i++) {
 -              strbuf_addf(&buf, "%02x", i);
 -              r = for_each_file_in_obj_subdir(i, &buf, obj_cb, cruft_cb,
 +              strbuf_addf(path, "/%02x", i);
 +              r = for_each_file_in_obj_subdir(i, path, obj_cb, cruft_cb,
                                                subdir_cb, data);
 -              strbuf_setlen(&buf, baselen);
 +              strbuf_setlen(path, baselen);
                if (r)
                        break;
        }
  
 +      return r;
 +}
 +
 +int for_each_loose_file_in_objdir(const char *path,
 +                                each_loose_object_fn obj_cb,
 +                                each_loose_cruft_fn cruft_cb,
 +                                each_loose_subdir_fn subdir_cb,
 +                                void *data)
 +{
 +      struct strbuf buf = STRBUF_INIT;
 +      int r;
 +
 +      strbuf_addstr(&buf, path);
 +      r = for_each_loose_file_in_objdir_buf(&buf, obj_cb, cruft_cb,
 +                                            subdir_cb, data);
        strbuf_release(&buf);
 +
        return r;
  }
  
@@@ -3413,19 -3396,12 +3413,19 @@@ static int loose_from_alt_odb(struct al
                              void *vdata)
  {
        struct loose_alt_odb_data *data = vdata;
 -      return for_each_loose_file_in_objdir(alt->base,
 -                                           data->cb, NULL, NULL,
 -                                           data->data);
 +      struct strbuf buf = STRBUF_INIT;
 +      int r;
 +
 +      /* copy base not including trailing '/' */
 +      strbuf_add(&buf, alt->base, alt->name - alt->base - 1);
 +      r = for_each_loose_file_in_objdir_buf(&buf,
 +                                            data->cb, NULL, NULL,
 +                                            data->data);
 +      strbuf_release(&buf);
 +      return r;
  }
  
 -int for_each_loose_object(each_loose_object_fn cb, void *data)
 +int for_each_loose_object(each_loose_object_fn cb, void *data, unsigned flags)
  {
        struct loose_alt_odb_data alt;
        int r;
        if (r)
                return r;
  
 +      if (flags & FOR_EACH_OBJECT_LOCAL_ONLY)
 +              return 0;
 +
        alt.cb = cb;
        alt.data = data;
        return foreach_alt_odb(loose_from_alt_odb, &alt);
@@@ -3462,15 -3435,13 +3462,15 @@@ static int for_each_object_in_pack(stru
        return r;
  }
  
 -int for_each_packed_object(each_packed_object_fn cb, void *data)
 +int for_each_packed_object(each_packed_object_fn cb, void *data, unsigned flags)
  {
        struct packed_git *p;
        int r = 0;
  
        prepare_packed_git();
        for (p = packed_git; p; p = p->next) {
 +              if ((flags & FOR_EACH_OBJECT_LOCAL_ONLY) && !p->pack_local)
 +                      continue;
                r = for_each_object_in_pack(p, cb, data);
                if (r)
                        break;
diff --combined submodule.c
index c0e6c81fc4656342fedeb4b5b68d9b938cb44b84,34094f5e97bbd63d6be2d697f656986c327c74ea..d491e6a7717ef0e1b9f7efd91becb024b98e0161
@@@ -301,7 -301,7 +301,7 @@@ static int prepare_submodule_summary(st
        left->object.flags |= SYMMETRIC_LEFT;
        add_pending_object(rev, &left->object, path);
        add_pending_object(rev, &right->object, path);
 -      merge_bases = get_merge_bases(left, right, 1);
 +      merge_bases = get_merge_bases(left, right);
        if (merge_bases) {
                if (merge_bases->item == left)
                        *fast_forward = 1;
@@@ -576,10 -576,12 +576,10 @@@ static int is_submodule_commit_present(
                cp.env = local_repo_env;
                cp.git_cmd = 1;
                cp.no_stdin = 1;
 -              cp.out = -1;
                cp.dir = path;
 -              if (!run_command(&cp) && !strbuf_read(&buf, cp.out, 1024))
 +              if (!capture_command(&cp, &buf, 1024) && !buf.len)
                        is_present = 1;
  
 -              close(cp.out);
                strbuf_release(&buf);
        }
        return is_present;
@@@ -1100,16 -1102,11 +1100,11 @@@ void connect_work_tree_and_git_dir(cons
        struct strbuf file_name = STRBUF_INIT;
        struct strbuf rel_path = STRBUF_INIT;
        const char *real_work_tree = xstrdup(real_path(work_tree));
-       FILE *fp;
  
        /* Update gitfile */
        strbuf_addf(&file_name, "%s/.git", work_tree);
-       fp = fopen(file_name.buf, "w");
-       if (!fp)
-               die(_("Could not create git link %s"), file_name.buf);
-       fprintf(fp, "gitdir: %s\n", relative_path(git_dir, real_work_tree,
-                                                 &rel_path));
-       fclose(fp);
+       write_file(file_name.buf, 1, "gitdir: %s\n",
+                  relative_path(git_dir, real_work_tree, &rel_path));
  
        /* Update core.worktree setting */
        strbuf_reset(&file_name);
diff --combined trace.c
index 1dc5c7c912d000699b753b1aab5c09a114e26557,bc3f53d29abf56209284248c6524961a8c1f4b5e..3c3bd8fc98742075d6adc673ed2abc4f7e715b62
+++ b/trace.c
@@@ -122,7 -122,9 +122,7 @@@ static int prepare_trace_line(const cha
  
  static void print_trace_line(struct trace_key *key, struct strbuf *buf)
  {
 -      /* append newline if missing */
 -      if (buf->len && buf->buf[buf->len - 1] != '\n')
 -              strbuf_addch(buf, '\n');
 +      strbuf_complete_line(buf);
  
        write_or_whine_pipe(get_trace_fd(key), buf->buf, buf->len, err_msg);
        strbuf_release(buf);
@@@ -310,6 -312,7 +310,7 @@@ void trace_repo_setup(const char *prefi
                prefix = "(null)";
  
        trace_printf_key(&key, "setup: git_dir: %s\n", quote_crnl(get_git_dir()));
+       trace_printf_key(&key, "setup: git_common_dir: %s\n", quote_crnl(get_git_common_dir()));
        trace_printf_key(&key, "setup: worktree: %s\n", quote_crnl(git_work_tree));
        trace_printf_key(&key, "setup: cwd: %s\n", quote_crnl(cwd));
        trace_printf_key(&key, "setup: prefix: %s\n", quote_crnl(prefix));
@@@ -322,7 -325,7 +323,7 @@@ int trace_want(struct trace_key *key
        return !!get_trace_fd(key);
  }
  
 -#ifdef HAVE_CLOCK_GETTIME
 +#if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_CLOCK_MONOTONIC)
  
  static inline uint64_t highres_nanos(void)
  {
diff --combined transport.c
index eca9b8c817bd723532d7f92da8cfa9f8ee82bb43,051b7ac175e4b1bb0d2e5c30528651fa59e381b0..f080e93dcd50e5f2329b180bae93c59a461810f8
@@@ -117,7 -117,7 +117,7 @@@ static void insert_packed_refs(const ch
                        return;
                }
  
 -              if (hexval(buffer[0]) > 0xf)
 +              if (!isxdigit(buffer[0]))
                        continue;
                len = strlen(buffer);
                if (len && buffer[len - 1] == '\n')
@@@ -283,7 -283,6 +283,6 @@@ static int write_one_ref(const char *na
  {
        struct strbuf *buf = data;
        int len = buf->len;
-       FILE *f;
  
        /* when called via for_each_ref(), flags is non-zero */
        if (flags && !starts_with(name, "refs/heads/") &&
  
        strbuf_addstr(buf, name);
        if (safe_create_leading_directories(buf->buf) ||
-                       !(f = fopen(buf->buf, "w")) ||
-                       fprintf(f, "%s\n", sha1_to_hex(sha1)) < 0 ||
-                       fclose(f))
-               return error("problems writing temporary file %s", buf->buf);
+           write_file(buf->buf, 0, "%s\n", sha1_to_hex(sha1)))
+               return error("problems writing temporary file %s: %s",
+                            buf->buf, strerror(errno));
        strbuf_setlen(buf, len);
        return 0;
  }
@@@ -519,7 -517,7 +517,7 @@@ static int fetch_refs_via_pack(struct t
                               int nr_heads, struct ref **to_fetch)
  {
        struct git_transport_data *data = transport->data;
 -      const struct ref *refs;
 +      struct ref *refs;
        char *dest = xstrdup(transport->url);
        struct fetch_pack_args args;
        struct ref *refs_tmp = NULL;
                          &transport->pack_lockfile);
        close(data->fd[0]);
        close(data->fd[1]);
 -      if (finish_connect(data->conn))
 +      if (finish_connect(data->conn)) {
 +              free_refs(refs);
                refs = NULL;
 +      }
        data->conn = NULL;
        data->got_remote_heads = 0;
        data->options.self_contained_and_connected =
                args.self_contained_and_connected;
  
        free_refs(refs_tmp);
 -
 +      free_refs(refs);
        free(dest);
        return (refs ? 0 : -1);
  }
@@@ -730,10 -726,6 +728,10 @@@ static int print_one_push_status(struc
                                                 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;
@@@ -832,7 -824,6 +830,7 @@@ static int git_transport_push(struct tr
        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,
@@@ -978,7 -969,9 +976,7 @@@ struct transport *transport_get(struct 
        } else {
                /* Unknown protocol in URL. Pass to external handler. */
                int len = external_specification_len(url);
 -              char *handler = xmalloc(len + 1);
 -              handler[len] = 0;
 -              strncpy(handler, url, len);
 +              char *handler = xmemdupz(url, len);
                transport_helper_init(ret, handler);
        }
  
diff --combined wrapper.c
index d5a6cef2be0fb13b262bed2e0b58bd58fbb5454d,a2dff8e5be019f0aca58f3858d7a880f290b69e1..c1a663fd592133b3e26314f3d598a8bca8bcceb1
+++ b/wrapper.c
@@@ -172,22 -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()
@@@ -564,3 -550,34 +564,34 @@@ char *xgetcwd(void
                die_errno(_("unable to get current working directory"));
        return strbuf_detach(&sb, NULL);
  }
+ int write_file(const char *path, int fatal, const char *fmt, ...)
+ {
+       struct strbuf sb = STRBUF_INIT;
+       va_list params;
+       int fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0666);
+       if (fd < 0) {
+               if (fatal)
+                       die_errno(_("could not open %s for writing"), path);
+               return -1;
+       }
+       va_start(params, fmt);
+       strbuf_vaddf(&sb, fmt, params);
+       va_end(params);
+       if (write_in_full(fd, sb.buf, sb.len) != sb.len) {
+               int err = errno;
+               close(fd);
+               strbuf_release(&sb);
+               errno = err;
+               if (fatal)
+                       die_errno(_("could not write to %s"), path);
+               return -1;
+       }
+       strbuf_release(&sb);
+       if (close(fd)) {
+               if (fatal)
+                       die_errno(_("could not close %s"), path);
+               return -1;
+       }
+       return 0;
+ }