Merge branch 'jc/am-state-fix'
authorJunio C Hamano <gitster@pobox.com>
Mon, 31 Aug 2015 22:39:01 +0000 (15:39 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 31 Aug 2015 22:39:03 +0000 (15:39 -0700)
Recent reimplementation of "git am" changed the format of state
files kept in $GIT_DIR/rebase-apply/ without meaning to do so,
primarily because write_file() API was cumbersome to use and it was
easy to mistakenly make text files with incomplete lines.  Update
write_file() interface to make it harder to misuse.

* jc/am-state-fix:
  write_file(): drop caller-supplied LF from calls to create a one-liner file
  write_file_v(): do not leave incomplete line at the end
  write_file(): drop "fatal" parameter
  builtin/am: make sure state files are text
  builtin/am: introduce write_state_*() helper functions

150 files changed:
.gitignore
Documentation/RelNotes/2.4.8.txt [new file with mode: 0644]
Documentation/RelNotes/2.5.1.txt [new file with mode: 0644]
Documentation/RelNotes/2.6.0.txt [new file with mode: 0644]
Documentation/config.txt
Documentation/git-bisect.txt
Documentation/git-check-ref-format.txt
Documentation/git-config.txt
Documentation/git-reflog.txt
Documentation/git-send-email.txt
Documentation/git-tag.txt
Documentation/git-tools.txt
Documentation/git-update-ref.txt
Documentation/git-worktree.txt
Documentation/git.txt
Documentation/gitattributes.txt
Documentation/gitrepository-layout.txt
Documentation/glossary-content.txt
Documentation/pretty-formats.txt
Documentation/pretty-options.txt
Documentation/rev-list-options.txt
Documentation/technical/api-lockfile.txt [deleted file]
Documentation/technical/api-submodule-config.txt [new file with mode: 0644]
Documentation/technical/index-format.txt
GIT-VERSION-GEN
Makefile
RelNotes
alias.c
attr.c
bisect.c
bisect.h
branch.c
branch.h
builtin/add.c
builtin/am.c
builtin/blame.c
builtin/checkout.c
builtin/clone.c
builtin/commit.c
builtin/config.c
builtin/fetch.c
builtin/fsck.c
builtin/gc.c
builtin/index-pack.c
builtin/log.c
builtin/ls-files.c
builtin/merge.c
builtin/notes.c
builtin/pull.c
builtin/receive-pack.c
builtin/reflog.c
builtin/remote.c
builtin/repack.c
builtin/reset.c
builtin/rev-list.c
builtin/send-pack.c
builtin/tag.c
builtin/update-ref.c
builtin/worktree.c
bundle.c
cache.h
compat/mingw.c
config.c
contrib/completion/git-completion.bash
contrib/examples/builtin-fetch--tool.c
contrib/examples/git-pull.sh
contrib/subtree/git-subtree.sh
contrib/subtree/t/t7900-subtree.sh
credential-cache--daemon.c
credential-store.c
diff.c
dir.c
fast-import.c
fetch-pack.c
generate-cmdlist.perl [deleted file]
generate-cmdlist.sh [new file with mode: 0755]
git-bisect.sh
git-compat-util.h
git-send-email.perl
git-stash.sh
http-backend.c
http.c
lockfile.c
lockfile.h
notes-merge.c
pager.c
parse-options.h
path.c
po/README
read-cache.c
refs.c
refs.h
rerere.c
revision.c
run-command.c
run-command.h
sequencer.c
sha1_file.c
shallow.c
strbuf.c
submodule-config.c [new file with mode: 0644]
submodule-config.h [new file with mode: 0644]
submodule.c
submodule.h
t/t0090-cache-tree.sh
t/t1090-sparse-checkout-scope.sh [new file with mode: 0755]
t/t1300-repo-config.sh
t/t1400-update-ref.sh
t/t1402-check-ref-format.sh
t/t1410-reflog.sh
t/t1411-reflog-show.sh
t/t1503-rev-parse-verify.sh
t/t1509-root-worktree.sh
t/t2019-checkout-ambiguous-ref.sh
t/t2025-worktree-add.sh
t/t3020-ls-files-error-unmatch.sh
t/t3200-branch.sh
t/t3210-pack-refs.sh
t/t3320-notes-merge-worktrees.sh [new file with mode: 0755]
t/t3404-rebase-interactive.sh
t/t3903-stash.sh
t/t4018-diff-funcname.sh
t/t4018/fountain-scene [new file with mode: 0644]
t/t4151-am-abort.sh
t/t5312-prune-corruption.sh
t/t5511-refspec.sh
t/t5512-ls-remote.sh
t/t5520-pull.sh
t/t5603-clone-dirname.sh [new file with mode: 0755]
t/t5700-clone-reference.sh
t/t6030-bisect-porcelain.sh
t/t6501-freshen-objects.sh
t/t7004-tag.sh
t/t7006-pager.sh
t/t7063-status-untracked-cache.sh
t/t7300-clean.sh
t/t7411-submodule-config.sh [new file with mode: 0755]
t/t7509-commit.sh
t/t7513-interpret-trailers.sh
t/test-lib.sh
tempfile.c [new file with mode: 0644]
tempfile.h [new file with mode: 0644]
test-submodule-config.c [new file with mode: 0644]
trailer.c
transport-helper.c
unpack-trees.c
usage.c
userdiff.c
wt-status.c
wt-status.h

index a685ec1..4fd81ba 100644 (file)
 /test-sha1-array
 /test-sigchain
 /test-string-list
+/test-submodule-config
 /test-subprocess
 /test-svn-fe
 /test-urlmatch-normalization
diff --git a/Documentation/RelNotes/2.4.8.txt b/Documentation/RelNotes/2.4.8.txt
new file mode 100644 (file)
index 0000000..ad946b2
--- /dev/null
@@ -0,0 +1,21 @@
+Git v2.4.8 Release Notes
+========================
+
+Fixes since v2.4.7
+------------------
+
+ * Abandoning an already applied change in "git rebase -i" with
+   "--continue" left CHERRY_PICK_HEAD and confused later steps.
+
+ * Various fixes around "git am" that applies a patch to a history
+   that is not there yet.
+
+ * "git for-each-ref" reported "missing object" for 0{40} when it
+   encounters a broken ref.  The lack of object whose name is 0{40} is
+   not the problem; the ref being broken is.
+
+ * "git commit --cleanup=scissors" was not careful enough to protect
+   against getting fooled by a line that looked like scissors.
+
+Also contains typofixes, documentation updates and trivial code
+clean-ups.
diff --git a/Documentation/RelNotes/2.5.1.txt b/Documentation/RelNotes/2.5.1.txt
new file mode 100644 (file)
index 0000000..b705533
--- /dev/null
@@ -0,0 +1,65 @@
+Git v2.5.1 Release Notes
+========================
+
+Fixes since v2.5
+----------------
+
+ * Running an aliased command from a subdirectory when the .git thing
+   in the working tree is a gitfile pointing elsewhere did not work.
+
+ * Often a fast-import stream builds a new commit on top of the
+   previous commit it built, and it often unconditionally emits a
+   "from" command to specify the first parent, which can be omitted in
+   such a case.  This caused fast-import to forget the tree of the
+   previous commit and then re-read it from scratch, which was
+   inefficient.  Optimize for this common case.
+
+ * The "rev-parse --parseopt" mode parsed the option specification
+   and the argument hint in a strange way to allow '=' and other
+   special characters in the option name while forbidding them from
+   the argument hint.  This made it impossible to define an option
+   like "--pair <key>=<value>" with "pair=key=value" specification,
+   which instead would have defined a "--pair=key <value>" option.
+
+ * A "rebase" replays changes of the local branch on top of something
+   else, as such they are placed in stage #3 and referred to as
+   "theirs", while the changes in the new base, typically a foreign
+   work, are placed in stage #2 and referred to as "ours".  Clarify
+   the "checkout --ours/--theirs".
+
+ * An experimental "untracked cache" feature used uname(2) in a
+   slightly unportable way.
+
+ * "sparse checkout" misbehaved for a path that is excluded from the
+   checkout when switching between branches that differ at the path.
+
+ * The low-level "git send-pack" did not honor 'user.signingkey'
+   configuration variable when sending a signed-push.
+
+ * An attempt to delete a ref by pushing into a repository whose HEAD
+   symbolic reference points at an unborn branch that cannot be
+   created due to ref D/F conflict (e.g. refs/heads/a/b exists, HEAD
+   points at refs/heads/a) failed.
+
+ * "git subtree" (in contrib/) depended on "git log" output to be
+   stable, which was a no-no.  Apply a workaround to force a
+   particular date format.
+
+ * "git clone $URL" in recent releases of Git contains a regression in
+   the code that invents a new repository name incorrectly based on
+   the $URL.  This has been corrected.
+   (merge db2e220 jk/guess-repo-name-regression-fix later to maint).
+
+ * Running tests with the "-x" option to make them verbose had some
+   unpleasant interactions with other features of the test suite.
+   (merge 9b5fe78 jk/test-with-x later to maint).
+
+ * "git pull" in recent releases of Git has a regression in the code
+   that allows custom path to the --upload-pack=<program>.  This has
+   been corrected.
+
+ * pipe() emulation used in Git for Windows looked at a wrong variable
+   when checking for an error from an _open_osfhandle() call.
+
+Also contains typofixes, documentation updates and trivial code
+clean-ups.
diff --git a/Documentation/RelNotes/2.6.0.txt b/Documentation/RelNotes/2.6.0.txt
new file mode 100644 (file)
index 0000000..050371d
--- /dev/null
@@ -0,0 +1,281 @@
+Git 2.6 Release Notes
+=====================
+
+Updates since v2.5
+------------------
+
+UI, Workflows & Features
+
+ * An asterisk as a substring (as opposed to the entirety) of a path
+   component for both side of a refspec, e.g.
+   "refs/heads/o*:refs/remotes/heads/i*", is now allowed.
+
+ * New userdiff pattern definition for fountain screenwriting markup
+   format has been added.
+
+ * "git log" and friends learned a new "--date=format:..." option to
+   format timestamps using system's strftime(3).
+
+ * "git fast-import" learned to respond to the get-mark command via
+   its cat-blob-fd interface.
+
+ * "git rebase -i" learned "drop commit-object-name subject" command
+   as another way to skip replaying of a commit.
+
+ * A new configuration variable can enable "--follow" automatically
+   when "git log" is run with one pathspec argument.
+
+ * "git status" learned to show a more detailed information regarding
+   the "rebase -i" session in progress.
+
+ * "git cat-file" learned "--batch-all-objects" option to enumerate all
+   available objects in the repository more quickly than "rev-list
+   --all --objects" (the output includes unreachable objects, though).
+
+ * "git fsck" learned to ignore errors on a set of known-to-be-bad
+   objects, and also allows the warning levels of various kinds of
+   non-critical breakages to be tweaked.
+
+ * "git rebase -i"'s list of todo is made configurable.
+
+ * "git send-email" now performs alias-expansion on names that are
+   given via --cccmd, etc.
+
+ * An environment variable GIT_REPLACE_REF_BASE tells Git to look into
+   refs hierarchy other than refs/replace/ for the object replacement
+   data.
+
+ * Allow untracked cache (experimental) to be used when sparse
+   checkout (experimental) is also in use.
+
+ * "git pull --rebase" has been taught to pay attention to
+   rebase.autostash configuration.
+
+ * The command-line completion script (in contrib/) has been updated.
+
+ * A negative !ref entry in multi-value transfer.hideRefs
+   configuration can be used to say "don't hide this one".
+
+ * After "git am" without "-3" stops, running "git am -" pays attention
+   to "-3" only for the patch that caused the original invocation
+   to stop.
+
+ * When linked worktree is used, simultaneous "notes merge" instances
+   for the same ref in refs/notes/* are prevented from stomping on
+   each other.
+
+ * "git send-email" learned a new option --smtp-auth to limit the SMTP
+   AUTH mechanisms to be used to a subset of what the system library
+   supports.
+
+ * A new configuration variable http.sslVersion can be used to specify
+   what specific version of SSL/TLS to use to make a connection.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * In preparation for allowing different "backends" to store the refs
+   in a way different from the traditional "one ref per file in
+   $GIT_DIR or in a $GIT_DIR/packed-refs file" filesystem storage,
+   direct filesystem access to ref-like things like CHERRY_PICK_HEAD
+   from scripts and programs has been reduced.
+
+ * Computation of untracked status indicator by bash prompt
+   script (in contrib/) has been optimized.
+
+ * Memory use reduction when commit-slab facility is used to annotate
+   sparsely (which is not recommended in the first place).
+
+ * Clean up refs API and make "git clone" less intimate with the
+   implementation detail.
+
+ * "git pull" was reimplemented in C.
+
+ * The packet tracing machinery allows to capture an incoming pack
+   data to a file for debugging.
+
+ * Move machinery to parse human-readable scaled numbers like 1k, 4M,
+   and 2G as an option parameter's value from pack-objects to
+   parse-options API, to make it available to other codepaths.
+
+ * "git verify-tag" and "git verify-commit" have been taught to share
+   more code, and then learned to optionally show the verification
+   message from the underlying GPG implementation.
+
+ * Various enhancements around "git am" reading patches generated by
+   foreign SCM have been made.
+
+ * Ref listing by "git branch -l" and "git tag -l" commands has
+   started to be rebuilt, based on the for-each-ref machinery.
+
+ * The code to perform multi-tree merges has been taught to repopulate
+   the cache-tree upon a successful merge into the index, so that
+   subsequent "diff-index --cached" (hence "status") and "write-tree"
+   (hence "commit") will go faster.
+
+   The same logic in "git checkout" may now be removed, but that is a
+   separate issue.
+
+ * Tests that assume how reflogs are represented on the filesystem too
+   much have been corrected.
+
+ * "git am" has been rewritten in "C".
+
+ * git_path() and mkpath() are handy helper functions but it is easy
+   to misuse, as the callers need to be careful to keep the number of
+   active results below 4.  Their uses have been reduced.
+
+ * The "lockfile" API has been rebuilt on top of a new "tempfile" API.
+
+ * To prepare for allowing a different "ref" backend to be plugged in
+   to the system, update_ref()/delete_ref() have been taught about
+   ref-like things like MERGE_HEAD that are per-worktree (they will
+   always be written to the filesystem inside $GIT_DIR).
+
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v2.5
+----------------
+
+Unless otherwise noted, all the fixes since v2.5 in the maintenance
+track are contained in this release (see the maintenance releases'
+notes for details).
+
+ * "git subtree" (in contrib/) depended on "git log" output to be
+   stable, which was a no-no.  Apply a workaround to force a
+   particular date format.
+   (merge e7aac44 da/subtree-date-confusion later to maint).
+
+ * An attempt to delete a ref by pushing into a repository whose HEAD
+   symbolic reference points at an unborn branch that cannot be
+   created due to ref D/F conflict (e.g. refs/heads/a/b exists, HEAD
+   points at refs/heads/a) failed.
+   (merge b112b14 jx/do-not-crash-receive-pack-wo-head later to maint).
+
+ * The low-level "git send-pack" did not honor 'user.signingkey'
+   configuration variable when sending a signed-push.
+   (merge d830d39 db/send-pack-user-signingkey later to maint).
+
+ * "sparse checkout" misbehaved for a path that is excluded from the
+   checkout when switching between branches that differ at the path.
+   (merge 7d78241 as/sparse-checkout-removal later to maint).
+
+ * An experimental "untracked cache" feature used uname(2) in a
+   slightly unportable way.
+   (merge 100e433 cb/uname-in-untracked later to maint).
+
+ * A "rebase" replays changes of the local branch on top of something
+   else, as such they are placed in stage #3 and referred to as
+   "theirs", while the changes in the new base, typically a foreign
+   work, are placed in stage #2 and referred to as "ours".  Clarify
+   the "checkout --ours/--theirs".
+   (merge f303016 se/doc-checkout-ours-theirs later to maint).
+
+ * The "rev-parse --parseopt" mode parsed the option specification
+   and the argument hint in a strange way to allow '=' and other
+   special characters in the option name while forbidding them from
+   the argument hint.  This made it impossible to define an option
+   like "--pair <key>=<value>" with "pair=key=value" specification,
+   which instead would have defined a "--pair=key <value>" option.
+   (merge 2d893df ib/scripted-parse-opt-better-hint-string later to maint).
+
+ * Often a fast-import stream builds a new commit on top of the
+   previous commit it built, and it often unconditionally emits a
+   "from" command to specify the first parent, which can be omitted in
+   such a case.  This caused fast-import to forget the tree of the
+   previous commit and then re-read it from scratch, which was
+   inefficient.  Optimize for this common case.
+   (merge 0df3245 mh/fast-import-optimize-current-from later to maint).
+
+ * Running an aliased command from a subdirectory when the .git thing
+   in the working tree is a gitfile pointing elsewhere did not work.
+   (merge d95138e nd/export-worktree later to maint).
+
+ * "Is this subdirectory a separate repository that should not be
+   touched?" check "git clean" was inefficient.  This was replaced
+   with a more optimized check.
+   (merge 38ae878 ee/clean-remove-dirs later to maint).
+
+ * The "new-worktree-mode" hack in "checkout" that was added in
+   nd/multiple-work-trees topic has been removed by updating the
+   implementation of new "worktree add".
+   (merge 65f9b75 es/worktree-add-cleanup later to maint).
+
+ * Remove remaining cruft from  "git checkout --to", which
+   transitioned to "git worktree add".
+   (merge 114ff88 es/worktree-add later to maint).
+
+ * An off-by-one error made "git remote" to mishandle a remote with a
+   single letter nickname.
+   (merge bc598c3 mh/get-remote-group-fix later to maint).
+
+ * "git clone $URL", when cloning from a site whose sole purpose is to
+   host a single repository (hence, no path after <scheme>://<site>/),
+   tried to use the site name as the new repository name, but did not
+   remove username or password when <site> part was of the form
+   <user>@<pass>:<host>.  The code is taught to redact these.
+   (merge adef956 ps/guess-repo-name-at-root later to maint).
+
+ * Running tests with the "-x" option to make them verbose had some
+   unpleasant interactions with other features of the test suite.
+   (merge 9b5fe78 jk/test-with-x later to maint).
+
+ * t1509 test that requires a dedicated VM environment had some
+   bitrot, which has been corrected.
+   (merge faacc5a ps/t1509-chroot-test-fixup later to maint).
+
+ * "git pull" in recent releases of Git has a regression in the code
+   that allows custom path to the --upload-pack=<program>.  This has
+   been corrected.
+
+   Note that this is irrelevant for 'master' with "git pull" rewritten
+   in C.
+   (merge 22d6857 mm/pull-upload-pack later to maint).
+
+ * When trying to see that an object does not exist, a state errno
+   leaked from our "first try to open a packfile with O_NOATIME and
+   then if it fails retry without it" logic on a system that refuses
+   O_NOATIME.  This confused us and caused us to die, saying that the
+   packfile is unreadable, when we should have just reported that the
+   object does not exist in that packfile to the caller.
+   (merge dff6f28 cb/open-noatime-clear-errno later to maint).
+
+ * The codepath to produce error messages had a hard-coded limit to
+   the size of the message, primarily to avoid memory allocation while
+   calling die().
+   (merge f4c3edc jk/long-error-messages later to maint).
+
+ * strbuf_read() used to have one extra iteration (and an unnecessary
+   strbuf_grow() of 8kB), which was eliminated.
+   (merge 3ebbd00 jh/strbuf-read-use-read-in-full later to maint).
+
+ * We rewrote one of the build scripts in Perl but this reimplements
+   in Bourne shell.
+   (merge 82aec45 sg/help-group later to maint).
+
+ * The experimental untracked-cache feature were buggy when paths with
+   a few levels of subdirectories are involved.
+   (merge 73f9145 dt/untracked-subdir later to maint).
+
+ * "interpret-trailers" helper mistook a single-liner log message that
+   has a colon as the end of existing trailer.
+   (merge 6262fe9 cc/trailers-corner-case-fix later to maint).
+
+ * Code cleanups and documentation updates.
+   (merge 1c601af es/doc-clean-outdated-tools later to maint).
+   (merge 3581304 kn/tag-doc-fix later to maint).
+   (merge 3a59e59 kb/i18n-doc later to maint).
+   (merge 45abdee sb/remove-unused-var-from-builtin-add later to maint).
+   (merge 14691e3 sb/parse-options-codeformat later to maint).
+   (merge 4a6ada3 ad/bisect-cleanup later to maint).
+   (merge da4c5ad ta/docfix-index-format-tech later to maint).
+   (merge ae25fd3 sb/check-return-from-read-ref later to maint).
+   (merge b3325df nd/dwim-wildcards-as-pathspecs later to maint).
+   (merge 7aa9b9b sg/wt-status-header-inclusion later to maint).
+   (merge f04c690 as/docfix-reflog-expire-unreachable later to maint).
+   (merge 1269847 sg/t3020-typofix later to maint).
+   (merge 8b54c23 jc/calloc-pathspec later to maint).
+   (merge a6926b8 po/po-readme later to maint).
+   (merge 54d160e ss/fix-config-fd-leak later to maint).
index fb3fc57..f5d15ff 100644 (file)
@@ -1307,28 +1307,34 @@ gc.packRefs::
 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::
-       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.
+       "now" may be used to disable this grace period and always prune
+       unreachable objects immediately, or "never" may be used to
+       suppress pruning.
+
+gc.worktreePruneExpire::
+       When 'git gc' is run, it calls
+       'git worktree prune --expire 3.months.ago'.
+       This config variable can be used to set a different grace
+       period. The value "now" may be used to disable the grace
+       period and prune $GIT_DIR/worktrees immediately, or "never"
+       may be used to suppress pruning.
 
 gc.reflogExpire::
 gc.<pattern>.reflogExpire::
        'git reflog expire' removes reflog entries older than
-       this time; defaults to 90 days.  With "<pattern>" (e.g.
+       this time; defaults to 90 days. The value "now" expires all
+       entries immediately, and "never" suppresses expiration
+       altogether. 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.<pattern>.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")
+       defaults to 30 days. The value "now" expires all entries
+       immediately, and "never" suppresses expiration altogether.
+       With "<pattern>" (e.g. "refs/stash")
        in the middle, the setting applies only to the refs that
        match the <pattern>.
 
@@ -1603,6 +1609,29 @@ 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.sslVersion::
+       The SSL version to use when negotiating an SSL connection, if you
+       want to force the default.  The available and default version
+       depend on whether libcurl was built against NSS or OpenSSL and the
+       particular configuration of the crypto library in use. Internally
+       this sets the 'CURLOPT_SSL_VERSION' option; see the libcurl
+       documentation for more details on the format of this option and
+       for the ssl version supported. Actually the possible values of
+       this option are:
+
+       - sslv2
+       - sslv3
+       - tlsv1
+       - tlsv1.0
+       - tlsv1.1
+       - tlsv1.2
+
++
+Can be overridden by the 'GIT_SSL_VERSION' environment variable.
+To force git to use libcurl's default ssl version and ignore any
+explicit http.sslversion option, set 'GIT_SSL_VERSION' to the
+empty string.
+
 http.sslCipherList::
   A list of SSL ciphers to use when negotiating an SSL connection.
   The available ciphers depend on whether libcurl was built against
@@ -2307,13 +2336,10 @@ receive.denyNonFastForwards::
        set when initializing a shared repository.
 
 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
-       are under the hierarchies listed on the value of this
-       variable is excluded, and is hidden when responding to `git
-       push`, and an attempt to update or delete a hidden ref by
-       `git push` is rejected.
+       This variable is the same as `transfer.hideRefs`, but applies
+       only to `receive-pack` (and so affects pushes, but not fetches).
+       An attempt to update or delete a hidden ref by `git push` is
+       rejected.
 
 receive.updateServerInfo::
        If set to true, git-receive-pack will run git-update-server-info
@@ -2601,9 +2627,18 @@ transfer.fsckObjects::
        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
-       values.  See entries for these other variables.
+       String(s) `receive-pack` and `upload-pack` use to decide which
+       refs to omit from their initial advertisements.  Use more than
+       one definition to specify multiple prefix strings. A ref that is
+       under the hierarchies listed in the value of this variable is
+       excluded, and is hidden when responding to `git push` or `git
+       fetch`.  See `receive.hideRefs` and `uploadpack.hideRefs` for
+       program-specific versions of this config.
++
+You may also include a `!` in front of the ref name to negate the entry,
+explicitly exposing it, even if an earlier entry marked it as hidden.
+If you have multiple hideRefs values, later entries override earlier ones
+(and entries in more-specific config files override less-specific ones).
 
 transfer.unpackLimit::
        When `fetch.unpackLimit` or `receive.unpackLimit` are
@@ -2618,13 +2653,10 @@ uploadarchive.allowUnreachable::
        `false`.
 
 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
-       are under the hierarchies listed on the value of this
-       variable is excluded, and is hidden from `git ls-remote`,
-       `git fetch`, etc.  An attempt to fetch a hidden ref by `git
-       fetch` will fail.  See also `uploadpack.allowTipSHA1InWant`.
+       This variable is the same as `transfer.hideRefs`, but applies
+       only to `upload-pack` (and so affects only fetches, not pushes).
+       An attempt to fetch a hidden ref by `git fetch` will fail.  See
+       also `uploadpack.allowTipSHA1InWant`.
 
 uploadpack.allowTipSHA1InWant::
        When `uploadpack.hideRefs` is in effect, allow `upload-pack`
index 4cb52a7..e97f2de 100644 (file)
@@ -3,7 +3,7 @@ git-bisect(1)
 
 NAME
 ----
-git-bisect - Find by binary search the change that introduced a bug
+git-bisect - Use binary search to find the commit that introduced a bug
 
 
 SYNOPSIS
@@ -16,7 +16,6 @@ DESCRIPTION
 The command takes various subcommands, and different options depending
 on the subcommand:
 
- git bisect help
  git bisect start [--no-checkout] [<bad> [<good>...]] [--] [<paths>...]
  git bisect bad [<rev>]
  git bisect good [<rev>...]
@@ -26,64 +25,71 @@ on the subcommand:
  git bisect replay <logfile>
  git bisect log
  git bisect run <cmd>...
+ git bisect help
 
-This command uses 'git rev-list --bisect' to help drive the
-binary search process to find which change introduced a bug, given an
-old "good" commit object name and a later "bad" commit object name.
-
-Getting help
-~~~~~~~~~~~~
-
-Use "git bisect" to get a short usage description, and "git bisect
-help" or "git bisect -h" to get a long usage description.
+This command uses a binary search algorithm to find which commit in
+your project's history introduced a bug. You use it by first telling
+it a "bad" commit that is known to contain the bug, and a "good"
+commit that is known to be before the bug was introduced. Then `git
+bisect` picks a commit between those two endpoints and asks you
+whether the selected commit is "good" or "bad". It continues narrowing
+down the range until it finds the exact commit that introduced the
+change.
 
 Basic bisect commands: start, bad, good
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-Using the Linux kernel tree as an example, basic use of the bisect
-command is as follows:
+As an example, suppose you are trying to find the commit that broke a
+feature that was known to work in version `v2.6.13-rc2` of your
+project. You start a bisect session as follows:
 
 ------------------------------------------------
 $ git bisect start
 $ git bisect bad                 # Current version is bad
-$ git bisect good v2.6.13-rc2    # v2.6.13-rc2 was the last version
-                                 # tested that was good
+$ git bisect good v2.6.13-rc2    # v2.6.13-rc2 is known to be good
 ------------------------------------------------
 
-When you have specified at least one bad and one good version, the
-command bisects the revision tree and outputs something similar to
-the following:
+Once you have specified at least one bad and one good commit, `git
+bisect` selects a commit in the middle of that range of history,
+checks it out, and outputs something similar to the following:
 
 ------------------------------------------------
-Bisecting: 675 revisions left to test after this
+Bisecting: 675 revisions left to test after this (roughly 10 steps)
 ------------------------------------------------
 
-The state in the middle of the set of revisions is then checked out.
-You would now compile that kernel and boot it. If the booted kernel
-works correctly, you would then issue the following command:
+You should now compile the checked-out version and test it. If that
+version works correctly, type
 
 ------------------------------------------------
-$ git bisect good                      # this one is good
+$ git bisect good
 ------------------------------------------------
 
-The output of this command would be something similar to the following:
+If that version is broken, type
 
 ------------------------------------------------
-Bisecting: 337 revisions left to test after this
+$ git bisect bad
 ------------------------------------------------
 
-You keep repeating this process, compiling the tree, testing it, and
-depending on whether it is good or bad issuing the command "git bisect good"
-or "git bisect bad" to ask for the next bisection.
+Then `git bisect` will respond with something like
+
+------------------------------------------------
+Bisecting: 337 revisions left to test after this (roughly 9 steps)
+------------------------------------------------
+
+Keep repeating the process: compile the tree, test it, and depending
+on whether it is good or bad run `git bisect good` or `git bisect bad`
+to ask for the next commit that needs testing.
+
+Eventually there will be no more revisions left to inspect, and the
+command will print out a description of the first bad commit. The
+reference `refs/bisect/bad` will be left pointing at that commit.
 
-Eventually there will be no more revisions left to bisect, and you
-will have been left with the first bad kernel revision in "refs/bisect/bad".
 
 Bisect reset
 ~~~~~~~~~~~~
 
 After a bisect session, to clean up the bisection state and return to
-the original HEAD (i.e., to quit bisecting), issue the following command:
+the original HEAD, issue the following command:
 
 ------------------------------------------------
 $ git bisect reset
@@ -100,9 +106,10 @@ instead:
 $ git bisect reset <commit>
 ------------------------------------------------
 
-For example, `git bisect reset HEAD` will leave you on the current
-bisection commit and avoid switching commits at all, while `git bisect
-reset bisect/bad` will check out the first bad revision.
+For example, `git bisect reset bisect/bad` will check out the first
+bad revision, while `git bisect reset HEAD` will leave you on the
+current bisection commit and avoid switching commits at all.
+
 
 Bisect visualize
 ~~~~~~~~~~~~~~~~
@@ -147,17 +154,17 @@ $ git bisect replay that-file
 Avoiding testing a commit
 ~~~~~~~~~~~~~~~~~~~~~~~~~
 
-If, in the middle of a bisect session, you know that the next suggested
-revision is not a good one to test (e.g. the change the commit
-introduces is known not to work in your environment and you know it
-does not have anything to do with the bug you are chasing), you may
-want to find a nearby commit and try that instead.
+If, in the middle of a bisect session, you know that the suggested
+revision is not a good one to test (e.g. it fails to build and you
+know that the failure does not have anything to do with the bug you
+are chasing), you can manually select a nearby commit and test that
+one instead.
 
 For example:
 
 ------------
 $ git bisect good/bad                  # previous round was good or bad.
-Bisecting: 337 revisions left to test after this
+Bisecting: 337 revisions left to test after this (roughly 9 steps)
 $ git bisect visualize                 # oops, that is uninteresting.
 $ git reset --hard HEAD~3              # try 3 revisions before what
                                        # was suggested
@@ -169,18 +176,19 @@ the revision as good or bad in the usual manner.
 Bisect skip
 ~~~~~~~~~~~~
 
-Instead of choosing by yourself a nearby commit, you can ask Git
-to do it for you by issuing the command:
+Instead of choosing a nearby commit by yourself, you can ask Git to do
+it for you by issuing the command:
 
 ------------
 $ git bisect skip                 # Current version cannot be tested
 ------------
 
-But Git may eventually be unable to tell the first bad commit among
-a bad commit and one or more skipped commits.
+However, if you skip a commit adjacent to the one you are looking for,
+Git will be unable to tell exactly which of those commits was the
+first bad one.
 
-You can even skip a range of commits, instead of just one commit,
-using the "'<commit1>'..'<commit2>'" notation. For example:
+You can also skip a range of commits, instead of just one commit,
+using range notation. For example:
 
 ------------
 $ git bisect skip v2.5..v2.6
@@ -196,8 +204,8 @@ would issue the command:
 $ git bisect skip v2.5 v2.5..v2.6
 ------------
 
-This tells the bisect process that the commits between `v2.5` included
-and `v2.6` included should be skipped.
+This tells the bisect process that the commits between `v2.5` and
+`v2.6` (inclusive) should be skipped.
 
 
 Cutting down bisection by giving more parameters to bisect start
@@ -231,14 +239,14 @@ or bad, you can bisect by issuing the command:
 $ git bisect run my_script arguments
 ------------
 
-Note that the script (`my_script` in the above example) should
-exit with code 0 if the current source code is good, and exit with a
-code between 1 and 127 (inclusive), except 125, if the current
-source code is bad.
+Note that the script (`my_script` in the above example) should exit
+with code 0 if the current source code is good/old, and exit with a
+code between 1 and 127 (inclusive), except 125, if the current source
+code is bad/new.
 
 Any other exit code will abort the bisect process. It should be noted
-that a program that terminates via "exit(-1)" leaves $? = 255, (see the
-exit(3) manual page), as the value is chopped with "& 0377".
+that a program that terminates via `exit(-1)` leaves $? = 255, (see the
+exit(3) manual page), as the value is chopped with `& 0377`.
 
 The special exit code 125 should be used when the current source code
 cannot be tested. If the script exits with this code, the current
@@ -247,7 +255,7 @@ as the highest sensible value to use for this purpose, because 126 and 127
 are used by POSIX shells to signal specific error status (127 is for
 command not found, 126 is for command found but not executable---these
 details do not matter, as they are normal errors in the script, as far as
-"bisect run" is concerned).
+`bisect run` is concerned).
 
 You may often find that during a bisect session you want to have
 temporary modifications (e.g. s/#define DEBUG 0/#define DEBUG 1/ in a
@@ -260,7 +268,7 @@ next revision to test, the script can apply the patch
 before compiling, run the real test, and afterwards decide if the
 revision (possibly with the needed patch) passed the test and then
 rewind the tree to the pristine state.  Finally the script should exit
-with the status of the real test to let the "git bisect run" command loop
+with the status of the real test to let the `git bisect run` command loop
 determine the eventual outcome of the bisect session.
 
 OPTIONS
@@ -307,12 +315,12 @@ $ git bisect run ~/test.sh
 $ git bisect reset                   # quit the bisect session
 ------------
 +
-Here we use a "test.sh" custom script. In this script, if "make"
+Here we use a `test.sh` custom script. In this script, if `make`
 fails, we skip the current commit.
-"check_test_case.sh" should "exit 0" if the test case passes,
-and "exit 1" otherwise.
+`check_test_case.sh` should `exit 0` if the test case passes,
+and `exit 1` otherwise.
 +
-It is safer if both "test.sh" and "check_test_case.sh" are
+It is safer if both `test.sh` and `check_test_case.sh` are
 outside the repository to prevent interactions between the bisect,
 make and test processes and the scripts.
 
@@ -379,6 +387,11 @@ In this case, when 'git bisect run' finishes, bisect/bad will refer to a commit
 has at least one parent whose reachable graph is fully traversable in the sense
 required by 'git pack objects'.
 
+Getting help
+~~~~~~~~~~~~
+
+Use `git bisect` to get a short usage description, and `git bisect
+help` or `git bisect -h` to get a long usage description.
 
 SEE ALSO
 --------
index fc02959..9044dfa 100644 (file)
@@ -94,8 +94,8 @@ OPTIONS
        Interpret <refname> as a reference name pattern for a refspec
        (as used with remote repositories).  If this option is
        enabled, <refname> is allowed to contain a single `*`
-       in place of a one full pathname component (e.g.,
-       `foo/*/bar` but not `foo/bar*`).
+       in the refspec (e.g., `foo/bar*/baz` or `foo/bar*baz/`
+       but not `foo/bar*/baz*`).
 
 --normalize::
        Normalize 'refname' by removing any leading slash (`/`)
index 02ec096..2608ca7 100644 (file)
@@ -14,13 +14,13 @@ SYNOPSIS
 'git config' [<file-option>] [type] --replace-all name value [value_regex]
 'git config' [<file-option>] [type] [-z|--null] --get name [value_regex]
 'git config' [<file-option>] [type] [-z|--null] --get-all name [value_regex]
-'git config' [<file-option>] [type] [-z|--null] --get-regexp name_regex [value_regex]
+'git config' [<file-option>] [type] [-z|--null] [--name-only] --get-regexp name_regex [value_regex]
 'git config' [<file-option>] [type] [-z|--null] --get-urlmatch name URL
 'git config' [<file-option>] --unset name [value_regex]
 'git config' [<file-option>] --unset-all name [value_regex]
 'git config' [<file-option>] --rename-section old_name new_name
 'git config' [<file-option>] --remove-section name
-'git config' [<file-option>] [-z|--null] -l | --list
+'git config' [<file-option>] [-z|--null] [--name-only] -l | --list
 'git config' [<file-option>] --get-color name [default]
 'git config' [<file-option>] --get-colorbool name [stdout-is-tty]
 'git config' [<file-option>] -e | --edit
@@ -159,7 +159,7 @@ See also <<FILES>>.
 
 -l::
 --list::
-       List all variables set in config file.
+       List all variables set in config file, along with their values.
 
 --bool::
        'git config' will ensure that the output is "true" or "false"
@@ -190,6 +190,10 @@ See also <<FILES>>.
        output without getting confused e.g. by values that
        contain line breaks.
 
+--name-only::
+       Output only the names of config variables for `--list` or
+       `--get-regexp`.
+
 --get-colorbool name [stdout-is-tty]::
 
        Find the color setting for `name` (e.g. `color.diff`) and output
index 5e7908e..44c736f 100644 (file)
@@ -23,6 +23,7 @@ depending on the subcommand:
        [--dry-run] [--verbose] [--all | <refs>...]
 'git reflog delete' [--rewrite] [--updateref]
        [--dry-run] [--verbose] ref@\{specifier\}...
+'git reflog exists' <ref>
 
 Reference logs, or "reflogs", record when the tips of branches and
 other references were updated in the local repository. Reflogs are
@@ -52,6 +53,9 @@ argument must be an _exact_ entry (e.g. "`git reflog delete
 master@{2}`"). This subcommand is also typically not used directly by
 end users.
 
+The "exists" subcommand checks whether a ref has a reflog.  It exits
+with zero status if the reflog exists, and non-zero status if it does
+not.
 
 OPTIONS
 -------
index f14705e..b9134d2 100644 (file)
@@ -171,6 +171,19 @@ Sending
        to determine your FQDN automatically.  Default is the value of
        'sendemail.smtpDomain'.
 
+--smtp-auth=<mechanisms>::
+       Whitespace-separated list of allowed SMTP-AUTH mechanisms. This setting
+       forces using only the listed mechanisms. Example:
++
+------
+$ git send-email --smtp-auth="PLAIN LOGIN GSSAPI" ...
+------
++
+If at least one of the specified mechanisms matches the ones advertised by the
+SMTP server and if it is supported by the utilized SASL library, the mechanism
+is used for authentication. If neither 'sendemail.smtpAuth' nor '--smtp-auth'
+is specified, all mechanisms supported by the SASL library can be used.
+
 --smtp-pass[=<password>]::
        Password for SMTP-AUTH. The argument is optional: If no
        argument is specified, then the empty string is used as
index 4b04c2b..84f6496 100644 (file)
@@ -13,7 +13,7 @@ SYNOPSIS
        <tagname> [<commit> | <object>]
 'git tag' -d <tagname>...
 'git tag' [-n[<num>]] -l [--contains <commit>] [--points-at <object>]
-       [--column[=<options>] | --no-column] [<pattern>...]
+       [--column[=<options>] | --no-column] [--create-reflog] [<pattern>...]
 'git tag' -v <tagname>...
 
 DESCRIPTION
@@ -142,6 +142,9 @@ This option is only applicable when listing tags without annotation lines.
        all, 'whitespace' removes just leading/trailing whitespace lines and
        'strip' removes both whitespace and commentary.
 
+--create-reflog::
+       Create a reflog for the tag.
+
 <tagname>::
        The name of the tag to create, delete, or describe.
        The new tag name must pass all checks defined by
index 78a0d95..2f4ff50 100644 (file)
-A short Git tools survey
-========================
+Git Tools
+=========
 
+When Git was young, people looking for third-party Git-related tools came
+to the Git project itself to find them, thus a list of such tools was
+maintained here. These days, however, search engines fill that role much
+more efficiently, so this manually-maintained list has been retired.
 
-Introduction
-------------
-
-Apart from Git contrib/ area there are some others third-party tools
-you may want to look.
-
-This document presents a brief summary of each tool and the corresponding
-link.
-
-
-Alternative/Augmentative Porcelains
------------------------------------
-
-   - *Cogito* (http://www.kernel.org/pub/software/scm/cogito/)
-
-   Cogito is a version control system layered on top of the Git tree history
-   storage system. It aims at seamless user interface and ease of use,
-   providing generally smoother user experience than the "raw" Core Git
-   itself and indeed many other version control systems.
-
-   Cogito is no longer maintained as most of its functionality
-   is now in core Git.
-
-
-   - *pg* (http://www.spearce.org/category/projects/scm/pg/)
-
-   pg is a shell script wrapper around Git to help the user manage a set of
-   patches to files. pg is somewhat like quilt or StGit, but it does have a
-   slightly different feature set.
-
-
-   - *StGit* (http://www.procode.org/stgit/)
-
-   Stacked Git provides a quilt-like patch management functionality in the
-   Git environment. You can easily manage your patches in the scope of Git
-   until they get merged upstream.
-
-
-History Viewers
----------------
-
-   - *gitk* (shipped with git-core)
-
-   gitk is a simple Tk GUI for browsing history of Git repositories easily.
-
-
-   - *gitview*  (contrib/)
-
-   gitview is a GTK based repository browser for Git
-
-
-   - *gitweb* (shipped with git-core)
-
-   Gitweb provides full-fledged web interface for Git repositories.
-
-
-   - *qgit* (http://digilander.libero.it/mcostalba/)
-
-   QGit is a git/StGit GUI viewer built on Qt/C++. QGit could be used
-   to browse history and directory tree, view annotated files, commit
-   changes cherry picking single files or applying patches.
-   Currently it is the fastest and most feature rich among the Git
-   viewers and commit tools.
-
-   - *tig* (http://jonas.nitro.dk/tig/)
-
-   tig by Jonas Fonseca is a simple Git repository browser
-   written using ncurses. Basically, it just acts as a front-end
-   for git-log and git-show/git-diff. Additionally, you can also
-   use it as a pager for Git commands.
-
-
-Foreign SCM interface
----------------------
-
-   - *git-svn* (shipped with git-core)
-
-   git-svn is a simple conduit for changesets between a single Subversion
-   branch and Git.
-
-
-   - *quilt2git / git2quilt* (http://home-tj.org/wiki/index.php/Misc)
-
-   These utilities convert patch series in a quilt repository and commit
-   series in Git back and forth.
-
-
-   - *hg-to-git* (contrib/)
-
-   hg-to-git converts a Mercurial repository into a Git one, and
-   preserves the full branch history in the process. hg-to-git can
-   also be used in an incremental way to keep the Git repository
-   in sync with the master Mercurial repository.
-
-
-Others
-------
-
-   - *(h)gct* (http://www.cyd.liu.se/users/~freku045/gct/)
-
-   Commit Tool or (h)gct is a GUI enabled commit tool for Git and
-   Mercurial (hg). It allows the user to view diffs, select which files
-   to committed (or ignored / reverted) write commit messages and
-   perform the commit itself.
-
-   - *git.el* (contrib/)
-
-   This is an Emacs interface for Git. The user interface is modelled on
-   pcl-cvs. It has been developed on Emacs 21 and will probably need some
-   tweaking to work on XEmacs.
-
-
-http://git.or.cz/gitwiki/InterfacesFrontendsAndTools has more
-comprehensive list.
+See also the `contrib/` area, and the Git wiki:
+http://git.or.cz/gitwiki/InterfacesFrontendsAndTools
index c8f5ae5..969bfab 100644 (file)
@@ -8,7 +8,7 @@ git-update-ref - Update the object name stored in a ref safely
 SYNOPSIS
 --------
 [verse]
-'git update-ref' [-m <reason>] (-d <ref> [<oldvalue>] | [--no-deref] <ref> <newvalue> [<oldvalue>] | --stdin [-z])
+'git update-ref' [-m <reason>] (-d <ref> [<oldvalue>] | [--no-deref] [--create-reflog] <ref> <newvalue> [<oldvalue>] | --stdin [-z])
 
 DESCRIPTION
 -----------
@@ -67,6 +67,9 @@ performs all modifications together.  Specify commands of the form:
        verify SP <ref> [SP <oldvalue>] LF
        option SP <opt> LF
 
+With `--create-reflog`, update-ref will create a reflog for each ref
+even if one would not ordinarily be created.
+
 Quote fields containing whitespace as if they were strings in C source
 code; i.e., surrounded by double-quotes and with backslash escapes.
 Use 40 "0" characters or the empty string to specify a zero value.  To
index 3387e2f..fb68156 100644 (file)
@@ -3,7 +3,7 @@ git-worktree(1)
 
 NAME
 ----
-git-worktree - Manage multiple worktrees
+git-worktree - Manage multiple working trees
 
 
 SYNOPSIS
@@ -15,7 +15,7 @@ SYNOPSIS
 DESCRIPTION
 -----------
 
-Manage multiple worktrees attached to the same repository.
+Manage multiple working trees attached to the same repository.
 
 A git repository can support multiple working trees, allowing you to check
 out more than one branch at a time.  With `git worktree add` a new working
@@ -27,19 +27,19 @@ bare repository) and zero or more linked working trees.
 When you are done with a linked working tree you can simply delete it.
 The working tree's administrative files in the repository (see
 "DETAILS" below) will eventually be removed automatically (see
-`gc.pruneworktreesexpire` in linkgit::git-config[1]), or you can run
+`gc.worktreePruneExpire` in linkgit:git-config[1]), or you can run
 `git worktree prune` in the main or any linked working tree to
 clean up any stale administrative files.
 
-If you move a linked working directory to another file system, or
+If you move a linked working tree 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
+at least one git command inside the linked working tree
 (e.g. `git status`) in order to update its administrative files in the
 repository so that they do not get automatically pruned.
 
 If a linked working tree is stored on a portable device or network share
 which is not always mounted, you can prevent its administrative files from
-being pruned by creating a file named 'lock' alongside the other
+being pruned by creating a file named 'locked' alongside the other
 administrative files, optionally containing a plain text reason that
 pruning should be suppressed. See section "DETAILS" for more information.
 
@@ -51,9 +51,9 @@ Create `<path>` and checkout `<branch>` into it. The new working directory
 is linked to the current repository, sharing everything except working
 directory specific files such as HEAD, index, etc.
 +
-If `<branch>` is omitted and neither `-b` nor `-B` is used, then, as a
-convenience, a new branch based at HEAD is created automatically, as if
-`-b $(basename <path>)` was specified.
+If `<branch>` is omitted and neither `-b` nor `-B` nor `--detached` used,
+then, as a convenience, a new branch based at HEAD is created automatically,
+as if `-b $(basename <path>)` was specified.
 
 prune::
 
@@ -64,22 +64,22 @@ OPTIONS
 
 -f::
 --force::
-       By default, `add` refuses to create a new worktree when `<branch>`
-       is already checked out by another worktree. This option overrides
+       By default, `add` refuses to create a new working tree when `<branch>`
+       is already checked out by another working tree. This option overrides
        that safeguard.
 
 -b <new-branch>::
 -B <new-branch>::
        With `add`, create a new branch named `<new-branch>` starting at
-       `<branch>`, and check out `<new-branch>` into the new worktree.
+       `<branch>`, and check out `<new-branch>` into the new working tree.
        If `<branch>` is omitted, it defaults to HEAD.
        By default, `-b` refuses to create a new branch if it already
        exists. `-B` overrides this safeguard, resetting `<new-branch>` to
        `<branch>`.
 
 --detach::
-       With `add`, detach HEAD in the new worktree. See "DETACHED HEAD" in
-       linkgit:git-checkout[1].
+       With `add`, detach HEAD in the new working tree. See "DETACHED HEAD"
+       in linkgit:git-checkout[1].
 
 -n::
 --dry-run::
@@ -91,7 +91,7 @@ OPTIONS
        With `prune`, report all removals.
 
 --expire <time>::
-       With `prune`, only expire unused worktrees older than <time>.
+       With `prune`, only expire unused working trees older than <time>.
 
 DETAILS
 -------
@@ -124,7 +124,7 @@ 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.
 
-To prevent a $GIT_DIR/worktrees entry from from being pruned (which
+To prevent a $GIT_DIR/worktrees entry 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
@@ -139,9 +139,9 @@ EXAMPLES
 You are in the middle of a refactoring session and your boss comes in and
 demands that you fix something immediately. You might typically use
 linkgit:git-stash[1] to store your changes away temporarily, however, your
-worktree is in such a state of disarray (with new, moved, and removed files,
-and other bits and pieces strewn around) that you don't want to risk
-disturbing any of it. Instead, you create a temporary linked worktree to
+working tree is in such a state of disarray (with new, moved, and removed
+files, and other bits and pieces strewn around) that you don't want to risk
+disturbing any of it. Instead, you create a temporary linked working tree to
 make the emergency fix, remove it when done, and then resume your earlier
 refactoring session.
 
@@ -164,12 +164,12 @@ checkouts of a superproject.
 git-worktree could provide more automation for tasks currently
 performed manually, such as:
 
-- `remove` to remove a linked worktree and its administrative files (and
-  warn if the worktree is dirty)
-- `mv` to move or rename a worktree and update its administrative files
-- `list` to list linked worktrees
+- `remove` to remove a linked working tree and its administrative files (and
+  warn if the working tree is dirty)
+- `mv` to move or rename a working tree and update its administrative files
+- `list` to list linked working trees
 - `lock` to prevent automatic pruning of administrative files (for instance,
-  for a worktree on a portable device)
+  for a working tree on a portable device)
 
 GIT
 ---
index f87d332..4e5d55b 100644 (file)
@@ -43,14 +43,16 @@ unreleased) version of Git, that is available from the 'master'
 branch of the `git.git` repository.
 Documentation for older releases are available here:
 
-* link:v2.5.0/git.html[documentation for release 2.5]
+* link:v2.5.1/git.html[documentation for release 2.5.1]
 
 * release notes for
-  link:RelNotes/2.5.0.txt[2.5],
+  link:RelNotes/2.5.1.txt[2.5.1],
+  link:RelNotes/2.5.0.txt[2.5].
 
-* link:v2.4.7/git.html[documentation for release 2.4.7]
+* link:v2.4.8/git.html[documentation for release 2.4.8]
 
 * release notes for
+  link:RelNotes/2.4.8.txt[2.4.8],
   link:RelNotes/2.4.7.txt[2.4.7],
   link:RelNotes/2.4.6.txt[2.4.6],
   link:RelNotes/2.4.5.txt[2.4.5],
@@ -780,7 +782,7 @@ The Git Repository
 ~~~~~~~~~~~~~~~~~~
 These environment variables apply to 'all' core Git commands. Nb: it
 is worth noting that they may be used/overridden by SCMS sitting above
-Git so take care if using Cogito etc.
+Git so take care if using a foreign front-end.
 
 'GIT_INDEX_FILE'::
        This environment allows the specification of an alternate
index 81fe586..e3b1de8 100644 (file)
@@ -527,6 +527,8 @@ patterns are available:
 
 - `fortran` suitable for source code in the Fortran language.
 
+- `fountain` suitable for Fountain documents.
+
 - `html` suitable for HTML/XHTML documents.
 
 - `java` suitable for source code in the Java language.
index 7173b38..577ee84 100644 (file)
@@ -251,25 +251,25 @@ modules::
        Contains the git-repositories of the submodules.
 
 worktrees::
-       Contains worktree specific information of linked
-       checkouts. Each subdirectory contains the worktree-related
-       part of a linked checkout. This directory is ignored if
-       $GIT_COMMON_DIR is set and "$GIT_COMMON_DIR/worktrees" will be
-       used instead.
+       Contains administrative data for linked
+       working trees. Each subdirectory contains the working tree-related
+       part of a linked working tree. This directory is ignored if
+       $GIT_COMMON_DIR is set, in which case
+       "$GIT_COMMON_DIR/worktrees" will be used instead.
 
 worktrees/<id>/gitdir::
        A text file containing the absolute path back to the .git file
        that points to here. This is used to check if the linked
        repository has been manually removed and there is no need to
-       keep this directory any more. mtime of this file should be
+       keep this directory any more. The mtime of this file should be
        updated every time the linked repository is accessed.
 
 worktrees/<id>/locked::
-       If this file exists, the linked repository may be on a
-       portable device and not available. It does not mean that the
-       linked repository is gone and `worktrees/<id>` could be
-       removed. The file's content contains a reason string on why
-       the repository is locked.
+       If this file exists, the linked working tree may be on a
+       portable device and not available. The presence of this file
+       prevents `worktrees/<id>` from being pruned either automatically
+       or manually by `git worktree prune`. The file may contain a string
+       explaining why the repository is locked.
 
 worktrees/<id>/link::
        If this file exists, it is a hard link to the linked .git
index ab18f4b..8c6478b 100644 (file)
@@ -411,6 +411,27 @@ exclude;;
        core Git. Porcelains expose more of a <<def_SCM,SCM>>
        interface than the <<def_plumbing,plumbing>>.
 
+[[def_per_worktree_ref]]per-worktree ref::
+       Refs that are per-<<def_working_tree,worktree>>, rather than
+       global.  This is presently only <<def_HEAD,HEAD>>, but might
+       later include other unusual refs.
+
+[[def_pseudoref]]pseudoref::
+       Pseudorefs are a class of files under `$GIT_DIR` which behave
+       like refs for the purposes of rev-parse, but which are treated
+       specially by git.  Pseudorefs both have names that are all-caps,
+       and always start with a line consisting of a
+       <<def_SHA1,SHA-1>> followed by whitespace.  So, HEAD is not a
+       pseudoref, because it is sometimes a symbolic ref.  They might
+       optionally contain some additional data.  `MERGE_HEAD` and
+       `CHERRY_PICK_HEAD` are examples.  Unlike
+       <<def_per_worktree_ref,per-worktree refs>>, these files cannot
+       be symbolic refs, and never have reflogs.  They also cannot be
+       updated through the normal ref update machinery.  Instead,
+       they are updated by directly writing to the files.  However,
+       they can be read as if they were refs, so `git rev-parse
+       MERGE_HEAD` will work.
+
 [[def_pull]]pull::
        Pulling a <<def_branch,branch>> means to <<def_fetch,fetch>> it and
        <<def_merge,merge>> it.  See also linkgit:git-pull[1].
index dc865cb..671cebd 100644 (file)
@@ -139,7 +139,9 @@ The placeholders are:
 - '%f': sanitized subject line, suitable for a filename
 - '%b': body
 - '%B': raw body (unwrapped subject and body)
+ifndef::git-rev-list[]
 - '%N': commit notes
+endif::git-rev-list[]
 - '%GG': raw verification message from GPG for a signed commit
 - '%G?': show "G" for a Good signature, "B" for a Bad signature, "U" for a good,
   untrusted signature and "N" for no signature
index 642af6e..8d6c5ce 100644 (file)
@@ -42,6 +42,7 @@ people using 80-column terminals.
        verbatim; this means that invalid sequences in the original
        commit may be copied to the output.
 
+ifndef::git-rev-list[]
 --notes[=<ref>]::
        Show the notes (see linkgit:git-notes[1]) that annotate the
        commit, when showing the commit log message.  This is the default
@@ -73,6 +74,7 @@ being displayed. Examples: "--notes=foo" will show only notes from
 --[no-]standard-notes::
        These options are deprecated. Use the above --notes/--no-notes
        options instead.
+endif::git-rev-list[]
 
 --show-signature::
        Check the validity of a signed commit object by passing the signature
index a9b808f..f1c5220 100644 (file)
@@ -58,9 +58,11 @@ endif::git-rev-list[]
        more than one `--grep=<pattern>`, commits whose message
        matches any of the given patterns are chosen (but see
        `--all-match`).
+ifndef::git-rev-list[]
 +
 When `--show-notes` is in effect, the message from the notes is
 matched as if it were part of the log message.
+endif::git-rev-list[]
 
 --all-match::
        Limit the commits output to ones that match all given `--grep`,
diff --git a/Documentation/technical/api-lockfile.txt b/Documentation/technical/api-lockfile.txt
deleted file mode 100644 (file)
index 93b5f23..0000000
+++ /dev/null
@@ -1,220 +0,0 @@
-lockfile API
-============
-
-The lockfile API serves two purposes:
-
-* Mutual exclusion and atomic file updates. When we want to change a
-  file, we create a lockfile `<filename>.lock`, write the new file
-  contents into it, and then rename the lockfile to its final
-  destination `<filename>`. We create the `<filename>.lock` file with
-  `O_CREAT|O_EXCL` so that we can notice and fail if somebody else has
-  already locked the file, then atomically rename the lockfile to its
-  final destination to commit the changes and unlock the file.
-
-* Automatic cruft removal. If the program exits after we lock a file
-  but before the changes have been committed, we want to make sure
-  that we remove the lockfile. This is done by remembering the
-  lockfiles we have created in a linked list and setting up an
-  `atexit(3)` handler and a signal handler that clean up the
-  lockfiles. This mechanism ensures that outstanding lockfiles are
-  cleaned up if the program exits (including when `die()` is called)
-  or if the program dies on a signal.
-
-Please note that lockfiles only block other writers. Readers do not
-block, but they are guaranteed to see either the old contents of the
-file or the new contents of the file (assuming that the filesystem
-implements `rename(2)` atomically).
-
-
-Calling sequence
-----------------
-
-The caller:
-
-* Allocates a `struct lock_file` either as a static variable or on the
-  heap, initialized to zeros. Once you use the structure to call the
-  `hold_lock_file_*` family of functions, it belongs to the lockfile
-  subsystem and its storage must remain valid throughout the life of
-  the program (i.e. you cannot use an on-stack variable to hold this
-  structure).
-
-* Attempts to create a lockfile by passing that variable and the path
-  of the final destination (e.g. `$GIT_DIR/index`) to
-  `hold_lock_file_for_update` or `hold_lock_file_for_append`.
-
-* Writes new content for the destination file by either:
-
-  * writing to the file descriptor returned by the `hold_lock_file_*`
-    functions (also available via `lock->fd`).
-
-  * calling `fdopen_lock_file` to get a `FILE` pointer for the open
-    file and writing to the file using stdio.
-
-When finished writing, the caller can:
-
-* Close the file descriptor and rename the lockfile to its final
-  destination by calling `commit_lock_file` or `commit_lock_file_to`.
-
-* Close the file descriptor and remove the lockfile by calling
-  `rollback_lock_file`.
-
-* Close the file descriptor without removing or renaming the lockfile
-  by calling `close_lock_file`, and later call `commit_lock_file`,
-  `commit_lock_file_to`, `rollback_lock_file`, or `reopen_lock_file`.
-
-Even after the lockfile is committed or rolled back, the `lock_file`
-object must not be freed or altered by the caller. However, it may be
-reused; just pass it to another call of `hold_lock_file_for_update` or
-`hold_lock_file_for_append`.
-
-If the program exits before you have called one of `commit_lock_file`,
-`commit_lock_file_to`, `rollback_lock_file`, or `close_lock_file`, an
-`atexit(3)` handler will close and remove the lockfile, rolling back
-any uncommitted changes.
-
-If you need to close the file descriptor you obtained from a
-`hold_lock_file_*` function yourself, do so by calling
-`close_lock_file`. You should never call `close(2)` or `fclose(3)`
-yourself! Otherwise the `struct lock_file` structure would still think
-that the file descriptor needs to be closed, and a commit or rollback
-would result in duplicate calls to `close(2)`. Worse yet, if you close
-and then later open another file descriptor for a completely different
-purpose, then a commit or rollback might close that unrelated file
-descriptor.
-
-
-Error handling
---------------
-
-The `hold_lock_file_*` functions return a file descriptor on success
-or -1 on failure (unless `LOCK_DIE_ON_ERROR` is used; see below). On
-errors, `errno` describes the reason for failure. Errors can be
-reported by passing `errno` to one of the following helper functions:
-
-unable_to_lock_message::
-
-       Append an appropriate error message to a `strbuf`.
-
-unable_to_lock_error::
-
-       Emit an appropriate error message using `error()`.
-
-unable_to_lock_die::
-
-       Emit an appropriate error message and `die()`.
-
-Similarly, `commit_lock_file`, `commit_lock_file_to`, and
-`close_lock_file` return 0 on success. On failure they set `errno`
-appropriately, do their best to roll back the lockfile, and return -1.
-
-
-Flags
------
-
-The following flags can be passed to `hold_lock_file_for_update` or
-`hold_lock_file_for_append`:
-
-LOCK_NO_DEREF::
-
-       Usually symbolic links in the destination path are resolved
-       and the lockfile is created by adding ".lock" to the resolved
-       path. If `LOCK_NO_DEREF` is set, then the lockfile is created
-       by adding ".lock" to the path argument itself. This option is
-       used, for example, when locking a symbolic reference, which
-       for backwards-compatibility reasons can be a symbolic link
-       containing the name of the referred-to-reference.
-
-LOCK_DIE_ON_ERROR::
-
-       If a lock is already taken for the file, `die()` with an error
-       message. If this option is not specified, trying to lock a
-       file that is already locked returns -1 to the caller.
-
-
-The functions
--------------
-
-hold_lock_file_for_update::
-
-       Take a pointer to `struct lock_file`, the path of the file to
-       be locked (e.g. `$GIT_DIR/index`) and a flags argument (see
-       above). Attempt to create a lockfile for the destination and
-       return the file descriptor for writing to the file.
-
-hold_lock_file_for_append::
-
-       Like `hold_lock_file_for_update`, but before returning copy
-       the existing contents of the file (if any) to the lockfile and
-       position its write pointer at the end of the file.
-
-fdopen_lock_file::
-
-       Associate a stdio stream with the lockfile. Return NULL
-       (*without* rolling back the lockfile) on error. The stream is
-       closed automatically when `close_lock_file` is called or when
-       the file is committed or rolled back.
-
-get_locked_file_path::
-
-       Return the path of the file that is locked by the specified
-       lock_file object. The caller must free the memory.
-
-commit_lock_file::
-
-       Take a pointer to the `struct lock_file` initialized with an
-       earlier call to `hold_lock_file_for_update` or
-       `hold_lock_file_for_append`, close the file descriptor, and
-       rename the lockfile to its final destination. Return 0 upon
-       success. On failure, roll back the lock file and return -1,
-       with `errno` set to the value from the failing call to
-       `close(2)` or `rename(2)`. It is a bug to call
-       `commit_lock_file` for a `lock_file` object that is not
-       currently locked.
-
-commit_lock_file_to::
-
-       Like `commit_lock_file()`, except that it takes an explicit
-       `path` argument to which the lockfile should be renamed. The
-       `path` must be on the same filesystem as the lock file.
-
-rollback_lock_file::
-
-       Take a pointer to the `struct lock_file` initialized with an
-       earlier call to `hold_lock_file_for_update` or
-       `hold_lock_file_for_append`, close the file descriptor and
-       remove the lockfile. It is a NOOP to call
-       `rollback_lock_file()` for a `lock_file` object that has
-       already been committed or rolled back.
-
-close_lock_file::
-
-       Take a pointer to the `struct lock_file` initialized with an
-       earlier call to `hold_lock_file_for_update` or
-       `hold_lock_file_for_append`. Close the file descriptor (and
-       the file pointer if it has been opened using
-       `fdopen_lock_file`). Return 0 upon success. On failure to
-       `close(2)`, return a negative value and roll back the lock
-       file. Usually `commit_lock_file`, `commit_lock_file_to`, or
-       `rollback_lock_file` should eventually be called if
-       `close_lock_file` succeeds.
-
-reopen_lock_file::
-
-       Re-open a lockfile that has been closed (using
-       `close_lock_file`) but not yet committed or rolled back. This
-       can be used to implement a sequence of operations like the
-       following:
-
-       * Lock file.
-
-       * Write new contents to lockfile, then `close_lock_file` to
-         cause the contents to be written to disk.
-
-       * Pass the name of the lockfile to another program to allow it
-         (and nobody else) to inspect the contents you wrote, while
-         still holding the lock yourself.
-
-       * `reopen_lock_file` to reopen the lockfile. Make further
-         updates to the contents.
-
-       * `commit_lock_file` to make the final version permanent.
diff --git a/Documentation/technical/api-submodule-config.txt b/Documentation/technical/api-submodule-config.txt
new file mode 100644 (file)
index 0000000..941fa17
--- /dev/null
@@ -0,0 +1,62 @@
+submodule config cache API
+==========================
+
+The submodule config cache API allows to read submodule
+configurations/information from specified revisions. Internally
+information is lazily read into a cache that is used to avoid
+unnecessary parsing of the same .gitmodule files. Lookups can be done by
+submodule path or name.
+
+Usage
+-----
+
+To initialize the cache with configurations from the worktree the caller
+typically first calls `gitmodules_config()` to read values from the
+worktree .gitmodules and then to overlay the local git config values
+`parse_submodule_config_option()` from the config parsing
+infrastructure.
+
+The caller can look up information about submodules by using the
+`submodule_from_path()` or `submodule_from_name()` functions. They return
+a `struct submodule` which contains the values. The API automatically
+initializes and allocates the needed infrastructure on-demand. If the
+caller does only want to lookup values from revisions the initialization
+can be skipped.
+
+If the internal cache might grow too big or when the caller is done with
+the API, all internally cached values can be freed with submodule_free().
+
+Data Structures
+---------------
+
+`struct submodule`::
+
+       This structure is used to return the information about one
+       submodule for a certain revision. It is returned by the lookup
+       functions.
+
+Functions
+---------
+
+`void submodule_free()`::
+
+       Use these to free the internally cached values.
+
+`int parse_submodule_config_option(const char *var, const char *value)`::
+
+       Can be passed to the config parsing infrastructure to parse
+       local (worktree) submodule configurations.
+
+`const struct submodule *submodule_from_path(const unsigned char *commit_sha1, const char *path)`::
+
+       Lookup values for one submodule by its commit_sha1 and path.
+
+`const struct submodule *submodule_from_name(const unsigned char *commit_sha1, const char *name)`::
+
+       The same as above but lookup by name.
+
+If given the null_sha1 as commit_sha1 the local configuration of a
+submodule will be returned (e.g. consolidated values from local git
+configuration and the .gitmodules file in the worktree).
+
+For an example usage see test-submodule-config.c.
index b7093af..7392ff6 100644 (file)
@@ -275,7 +275,7 @@ Git index format
 
     - The directory name terminated by NUL.
 
-    - A number of untrached file/dir names terminated by NUL.
+    - A number of untracked file/dir names terminated by NUL.
 
 The remaining data of each directory block is grouped by type:
 
index cd96820..fc45283 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v2.5.0
+DEF_VER=v2.5.0.GIT
 
 LF='
 '
@@ -38,5 +38,3 @@ test "$VN" = "$VC" || {
        echo >&2 "GIT_VERSION = $VN"
        echo "GIT_VERSION = $VN" >$GVF
 }
-
-
index e39ca6c..e326fa0 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -593,6 +593,7 @@ TEST_PROGRAMS_NEED_X += test-sha1
 TEST_PROGRAMS_NEED_X += test-sha1-array
 TEST_PROGRAMS_NEED_X += test-sigchain
 TEST_PROGRAMS_NEED_X += test-string-list
+TEST_PROGRAMS_NEED_X += test-submodule-config
 TEST_PROGRAMS_NEED_X += test-subprocess
 TEST_PROGRAMS_NEED_X += test-svn-fe
 TEST_PROGRAMS_NEED_X += test-urlmatch-normalization
@@ -784,8 +785,10 @@ LIB_OBJS += strbuf.o
 LIB_OBJS += streaming.o
 LIB_OBJS += string-list.o
 LIB_OBJS += submodule.o
+LIB_OBJS += submodule-config.o
 LIB_OBJS += symlinks.o
 LIB_OBJS += tag.o
+LIB_OBJS += tempfile.o
 LIB_OBJS += trace.o
 LIB_OBJS += trailer.o
 LIB_OBJS += transport.o
@@ -1697,10 +1700,10 @@ $(BUILT_INS): git$X
        ln -s $< $@ 2>/dev/null || \
        cp $< $@
 
-common-cmds.h: generate-cmdlist.perl command-list.txt
+common-cmds.h: generate-cmdlist.sh command-list.txt
 
 common-cmds.h: $(wildcard Documentation/git-*.txt)
-       $(QUIET_GEN)$(PERL_PATH) generate-cmdlist.perl command-list.txt > $@+ && mv $@+ $@
+       $(QUIET_GEN)./generate-cmdlist.sh command-list.txt >$@+ && mv $@+ $@
 
 SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):$(GIT_VERSION):\
        $(localedir_SQ):$(NO_CURL):$(USE_GETTEXT_SCHEME):$(SANE_TOOL_PATH_SQ):\
index 3295d66..84a20c8 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.5.0.txt
\ No newline at end of file
+Documentation/RelNotes/2.6.0.txt
\ No newline at end of file
diff --git a/alias.c b/alias.c
index 6aa164a..a11229d 100644 (file)
--- a/alias.c
+++ b/alias.c
@@ -5,7 +5,8 @@ char *alias_lookup(const char *alias)
        char *v = NULL;
        struct strbuf key = STRBUF_INIT;
        strbuf_addf(&key, "alias.%s", alias);
-       git_config_get_string(key.buf, &v);
+       if (git_config_key_is_valid(key.buf))
+               git_config_get_string(key.buf, &v);
        strbuf_release(&key);
        return v;
 }
diff --git a/attr.c b/attr.c
index 8f2ac6c..086c08d 100644 (file)
--- a/attr.c
+++ b/attr.c
@@ -490,6 +490,8 @@ static int git_attr_system(void)
        return !git_env_bool("GIT_ATTR_NOSYSTEM", 0);
 }
 
+static GIT_PATH_FUNC(git_path_info_attributes, INFOATTRIBUTES_FILE)
+
 static void bootstrap_attr_stack(void)
 {
        struct attr_stack *elem;
@@ -531,7 +533,7 @@ static void bootstrap_attr_stack(void)
                debug_push(elem);
        }
 
-       elem = read_attr_from_file(git_path(INFOATTRIBUTES_FILE), 1);
+       elem = read_attr_from_file(git_path_info_attributes(), 1);
        if (!elem)
                elem = xcalloc(1, sizeof(*elem));
        elem->origin = NULL;
index 03d5cd9..041a13d 100644 (file)
--- a/bisect.c
+++ b/bisect.c
@@ -19,7 +19,9 @@ static struct object_id *current_bad_oid;
 
 static const char *argv_checkout[] = {"checkout", "-q", NULL, "--", NULL};
 static const char *argv_show_branch[] = {"show-branch", NULL, NULL};
-static const char *argv_update_ref[] = {"update-ref", "--no-deref", "BISECT_HEAD", NULL, NULL};
+
+static const char *term_bad;
+static const char *term_good;
 
 /* Remember to update object flag allocation in object.h */
 #define COUNTED                (1u<<16)
@@ -403,15 +405,21 @@ struct commit_list *find_bisection(struct commit_list *list,
 static int register_ref(const char *refname, const struct object_id *oid,
                        int flags, void *cb_data)
 {
-       if (!strcmp(refname, "bad")) {
+       struct strbuf good_prefix = STRBUF_INIT;
+       strbuf_addstr(&good_prefix, term_good);
+       strbuf_addstr(&good_prefix, "-");
+
+       if (!strcmp(refname, term_bad)) {
                current_bad_oid = xmalloc(sizeof(*current_bad_oid));
                oidcpy(current_bad_oid, oid);
-       } else if (starts_with(refname, "good-")) {
+       } else if (starts_with(refname, good_prefix.buf)) {
                sha1_array_append(&good_revs, oid->hash);
        } else if (starts_with(refname, "skip-")) {
                sha1_array_append(&skipped_revs, oid->hash);
        }
 
+       strbuf_release(&good_prefix);
+
        return 0;
 }
 
@@ -420,10 +428,13 @@ static int read_bisect_refs(void)
        return for_each_ref_in("refs/bisect/", register_ref, NULL);
 }
 
+static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
+static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
+
 static void read_bisect_paths(struct argv_array *array)
 {
        struct strbuf str = STRBUF_INIT;
-       const char *filename = git_path("BISECT_NAMES");
+       const char *filename = git_path_bisect_names();
        FILE *fp = fopen(filename, "r");
 
        if (!fp)
@@ -634,7 +645,7 @@ static void exit_if_skipped_commits(struct commit_list *tried,
                return;
 
        printf("There are only 'skip'ped commits left to test.\n"
-              "The first bad commit could be any of:\n");
+              "The first %s commit could be any of:\n", term_bad);
        print_commit_list(tried, "%s\n", "%s\n");
        if (bad)
                printf("%s\n", oid_to_hex(bad));
@@ -644,7 +655,7 @@ static void exit_if_skipped_commits(struct commit_list *tried,
 
 static int is_expected_rev(const struct object_id *oid)
 {
-       const char *filename = git_path("BISECT_EXPECTED_REV");
+       const char *filename = git_path_bisect_expected_rev();
        struct stat st;
        struct strbuf str = STRBUF_INIT;
        FILE *fp;
@@ -666,34 +677,16 @@ static int is_expected_rev(const struct object_id *oid)
        return res;
 }
 
-static void mark_expected_rev(char *bisect_rev_hex)
-{
-       int len = strlen(bisect_rev_hex);
-       const char *filename = git_path("BISECT_EXPECTED_REV");
-       int fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0600);
-
-       if (fd < 0)
-               die_errno("could not create file '%s'", filename);
-
-       bisect_rev_hex[len] = '\n';
-       write_or_die(fd, bisect_rev_hex, len + 1);
-       bisect_rev_hex[len] = '\0';
-
-       if (close(fd) < 0)
-               die("closing file %s: %s", filename, strerror(errno));
-}
-
-static int bisect_checkout(char *bisect_rev_hex, int no_checkout)
+static int bisect_checkout(const unsigned char *bisect_rev, int no_checkout)
 {
+       char bisect_rev_hex[GIT_SHA1_HEXSZ + 1];
 
-       mark_expected_rev(bisect_rev_hex);
+       memcpy(bisect_rev_hex, sha1_to_hex(bisect_rev), GIT_SHA1_HEXSZ + 1);
+       update_ref(NULL, "BISECT_EXPECTED_REV", bisect_rev, NULL, 0, UPDATE_REFS_DIE_ON_ERR);
 
        argv_checkout[2] = bisect_rev_hex;
        if (no_checkout) {
-               argv_update_ref[3] = bisect_rev_hex;
-               if (run_command_v_opt(argv_update_ref, RUN_GIT_CMD))
-                       die("update-ref --no-deref HEAD failed on %s",
-                           bisect_rev_hex);
+               update_ref(NULL, "BISECT_HEAD", bisect_rev, NULL, 0, UPDATE_REFS_DIE_ON_ERR);
        } else {
                int res;
                res = run_command_v_opt(argv_checkout, RUN_GIT_CMD);
@@ -732,18 +725,24 @@ static void handle_bad_merge_base(void)
        if (is_expected_rev(current_bad_oid)) {
                char *bad_hex = oid_to_hex(current_bad_oid);
                char *good_hex = join_sha1_array_hex(&good_revs, ' ');
-
-               fprintf(stderr, "The merge base %s is bad.\n"
-                       "This means the bug has been fixed "
-                       "between %s and [%s].\n",
-                       bad_hex, bad_hex, good_hex);
-
+               if (!strcmp(term_bad, "bad") && !strcmp(term_good, "good")) {
+                       fprintf(stderr, "The merge base %s is bad.\n"
+                               "This means the bug has been fixed "
+                               "between %s and [%s].\n",
+                               bad_hex, bad_hex, good_hex);
+               } else {
+                       fprintf(stderr, "The merge base %s is %s.\n"
+                               "This means the first '%s' commit is "
+                               "between %s and [%s].\n",
+                               bad_hex, term_bad, term_good, bad_hex, good_hex);
+               }
                exit(3);
        }
 
-       fprintf(stderr, "Some good revs are not ancestor of the bad rev.\n"
+       fprintf(stderr, "Some %s revs are not ancestor of the %s rev.\n"
                "git bisect cannot work properly in this case.\n"
-               "Maybe you mistake good and bad revs?\n");
+               "Maybe you mistook %s and %s revs?\n",
+               term_good, term_bad, term_good, term_bad);
        exit(1);
 }
 
@@ -755,10 +754,10 @@ static void handle_skipped_merge_base(const unsigned char *mb)
 
        warning("the merge base between %s and [%s] "
                "must be skipped.\n"
-               "So we cannot be sure the first bad commit is "
+               "So we cannot be sure the first %s commit is "
                "between %s and %s.\n"
                "We continue anyway.",
-               bad_hex, good_hex, mb_hex, bad_hex);
+               bad_hex, good_hex, term_bad, mb_hex, bad_hex);
        free(good_hex);
 }
 
@@ -789,7 +788,7 @@ static void check_merge_bases(int no_checkout)
                        handle_skipped_merge_base(mb);
                } else {
                        printf("Bisecting: a merge base must be tested\n");
-                       exit(bisect_checkout(sha1_to_hex(mb), no_checkout));
+                       exit(bisect_checkout(mb, no_checkout));
                }
        }
 
@@ -839,7 +838,7 @@ static void check_good_are_ancestors_of_bad(const char *prefix, int no_checkout)
        int fd;
 
        if (!current_bad_oid)
-               die("a bad revision is needed");
+               die("a %s revision is needed", term_bad);
 
        /* Check if file BISECT_ANCESTORS_OK exists. */
        if (!stat(filename, &st) && S_ISREG(st.st_mode))
@@ -889,6 +888,36 @@ static void show_diff_tree(const char *prefix, struct commit *commit)
        log_tree_commit(&opt, commit);
 }
 
+/*
+ * The terms used for this bisect session are stored in BISECT_TERMS.
+ * We read them and store them to adapt the messages accordingly.
+ * Default is bad/good.
+ */
+void read_bisect_terms(const char **read_bad, const char **read_good)
+{
+       struct strbuf str = STRBUF_INIT;
+       const char *filename = git_path("BISECT_TERMS");
+       FILE *fp = fopen(filename, "r");
+
+       if (!fp) {
+               if (errno == ENOENT) {
+                       *read_bad = "bad";
+                       *read_good = "good";
+                       return;
+               } else {
+                       die("could not read file '%s': %s", filename,
+                               strerror(errno));
+               }
+       } else {
+               strbuf_getline(&str, fp, '\n');
+               *read_bad = strbuf_detach(&str, NULL);
+               strbuf_getline(&str, fp, '\n');
+               *read_good = strbuf_detach(&str, NULL);
+       }
+       strbuf_release(&str);
+       fclose(fp);
+}
+
 /*
  * We use the convention that exiting with an exit code 10 means that
  * the bisection process finished successfully.
@@ -903,8 +932,8 @@ int bisect_next_all(const char *prefix, int no_checkout)
        struct commit_list *tried;
        int reaches = 0, all = 0, nr, steps;
        const unsigned char *bisect_rev;
-       char bisect_rev_hex[GIT_SHA1_HEXSZ + 1];
 
+       read_bisect_terms(&term_bad, &term_good);
        if (read_bisect_refs())
                die("reading bisect refs failed");
 
@@ -926,8 +955,10 @@ int bisect_next_all(const char *prefix, int no_checkout)
                 */
                exit_if_skipped_commits(tried, NULL);
 
-               printf("%s was both good and bad\n",
-                      oid_to_hex(current_bad_oid));
+               printf("%s was both %s and %s\n",
+                      oid_to_hex(current_bad_oid),
+                      term_good,
+                      term_bad);
                exit(1);
        }
 
@@ -938,11 +969,11 @@ int bisect_next_all(const char *prefix, int no_checkout)
        }
 
        bisect_rev = revs.commits->item->object.sha1;
-       memcpy(bisect_rev_hex, sha1_to_hex(bisect_rev), GIT_SHA1_HEXSZ + 1);
 
        if (!hashcmp(bisect_rev, current_bad_oid->hash)) {
                exit_if_skipped_commits(tried, current_bad_oid);
-               printf("%s is the first bad commit\n", bisect_rev_hex);
+               printf("%s is the first %s commit\n", sha1_to_hex(bisect_rev),
+                       term_bad);
                show_diff_tree(prefix, revs.commits->item);
                /* This means the bisection process succeeded. */
                exit(10);
@@ -954,7 +985,7 @@ int bisect_next_all(const char *prefix, int no_checkout)
               "(roughly %d step%s)\n", nr, (nr == 1 ? "" : "s"),
               steps, (steps == 1 ? "" : "s"));
 
-       return bisect_checkout(bisect_rev_hex, no_checkout);
+       return bisect_checkout(bisect_rev, no_checkout);
 }
 
 static inline int log2i(int n)
index 2a6c831..acd12ef 100644 (file)
--- a/bisect.h
+++ b/bisect.h
@@ -26,4 +26,6 @@ extern int bisect_next_all(const char *prefix, int no_checkout);
 
 extern int estimate_bisect_steps(int all);
 
+extern void read_bisect_terms(const char **bad, const char **good);
+
 #endif
index b002435..d013374 100644 (file)
--- a/branch.c
+++ b/branch.c
@@ -302,11 +302,100 @@ void create_branch(const char *head,
 
 void remove_branch_state(void)
 {
-       unlink(git_path("CHERRY_PICK_HEAD"));
-       unlink(git_path("REVERT_HEAD"));
-       unlink(git_path("MERGE_HEAD"));
-       unlink(git_path("MERGE_RR"));
-       unlink(git_path("MERGE_MSG"));
-       unlink(git_path("MERGE_MODE"));
-       unlink(git_path("SQUASH_MSG"));
+       unlink(git_path_cherry_pick_head());
+       unlink(git_path_revert_head());
+       unlink(git_path_merge_head());
+       unlink(git_path_merge_rr());
+       unlink(git_path_merge_msg());
+       unlink(git_path_merge_mode());
+       unlink(git_path_squash_msg());
+}
+
+static char *find_linked_symref(const char *symref, const char *branch,
+                               const char *id)
+{
+       struct strbuf sb = STRBUF_INIT;
+       struct strbuf path = STRBUF_INIT;
+       struct strbuf gitdir = STRBUF_INIT;
+       char *existing = NULL;
+
+       /*
+        * $GIT_COMMON_DIR/$symref (e.g. HEAD) is practically outside
+        * $GIT_DIR so resolve_ref_unsafe() won't work (it uses
+        * git_path). Parse the ref ourselves.
+        */
+       if (id)
+               strbuf_addf(&path, "%s/worktrees/%s/%s", get_git_common_dir(), id, symref);
+       else
+               strbuf_addf(&path, "%s/%s", get_git_common_dir(), symref);
+
+       if (!strbuf_readlink(&sb, path.buf, 0)) {
+               if (!starts_with(sb.buf, "refs/") ||
+                   check_refname_format(sb.buf, 0))
+                       goto done;
+       } else if (strbuf_read_file(&sb, path.buf, 0) >= 0 &&
+           starts_with(sb.buf, "ref:")) {
+               strbuf_remove(&sb, 0, strlen("ref:"));
+               strbuf_trim(&sb);
+       } else
+               goto done;
+       if (strcmp(sb.buf, branch))
+               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());
+       strbuf_strip_suffix(&gitdir, ".git");
+
+       existing = strbuf_detach(&gitdir, NULL);
+done:
+       strbuf_release(&path);
+       strbuf_release(&sb);
+       strbuf_release(&gitdir);
+
+       return existing;
+}
+
+char *find_shared_symref(const char *symref, const char *target)
+{
+       struct strbuf path = STRBUF_INIT;
+       DIR *dir;
+       struct dirent *d;
+       char *existing;
+
+       if ((existing = find_linked_symref(symref, target, NULL)))
+               return existing;
+
+       strbuf_addf(&path, "%s/worktrees", get_git_common_dir());
+       dir = opendir(path.buf);
+       strbuf_release(&path);
+       if (!dir)
+               return NULL;
+
+       while ((d = readdir(dir)) != NULL) {
+               if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
+                       continue;
+               existing = find_linked_symref(symref, target, d->d_name);
+               if (existing)
+                       goto done;
+       }
+done:
+       closedir(dir);
+
+       return existing;
+}
+
+void die_if_checked_out(const char *branch)
+{
+       char *existing;
+
+       existing = find_shared_symref("HEAD", branch);
+       if (existing) {
+               skip_prefix(branch, "refs/heads/", &branch);
+               die(_("'%s' is already checked out at '%s'"), branch, existing);
+       }
 }
index 64173ab..d3446ed 100644 (file)
--- a/branch.h
+++ b/branch.h
@@ -52,4 +52,19 @@ extern void install_branch_config(int flag, const char *local, const char *origi
  */
 extern int read_branch_desc(struct strbuf *, const char *branch_name);
 
+/*
+ * Check if a branch is checked out in the main worktree or any linked
+ * worktree and die (with a message describing its checkout location) if
+ * it is.
+ */
+extern void die_if_checked_out(const char *branch);
+
+/*
+ * Check if a per-worktree symref points to a ref in the main worktree
+ * or any linked worktree, and return the path to the exising worktree
+ * if it is.  Returns NULL if there is no existing ref.  The caller is
+ * responsible for freeing the returned path.
+ */
+extern char *find_shared_symref(const char *symref, const char *target);
+
 #endif
index 4bd98b7..b2a5c57 100644 (file)
@@ -375,7 +375,6 @@ int cmd_add(int argc, const char **argv, const char *prefix)
 
        if (add_new_files) {
                int baselen;
-               struct pathspec empty_pathspec;
 
                /* Set up the default git porcelain excludes */
                memset(&dir, 0, sizeof(dir));
@@ -384,7 +383,6 @@ int cmd_add(int argc, const char **argv, const char *prefix)
                        setup_standard_excludes(&dir);
                }
 
-               memset(&empty_pathspec, 0, sizeof(empty_pathspec));
                /* This picks up the paths that are not tracked */
                baselen = fill_directory(&dir, &pathspec);
                if (pathspec.nr)
index 486ff59..27165a6 100644 (file)
@@ -10,6 +10,7 @@
 #include "dir.h"
 #include "run-command.h"
 #include "quote.h"
+#include "tempfile.h"
 #include "lockfile.h"
 #include "cache-tree.h"
 #include "refs.h"
@@ -1975,16 +1976,49 @@ static int fast_forward_to(struct tree *head, struct tree *remote, int reset)
        return 0;
 }
 
+/**
+ * Merges a tree into the index. The index's stat info will take precedence
+ * over the merged tree's. Returns 0 on success, -1 on failure.
+ */
+static int merge_tree(struct tree *tree)
+{
+       struct lock_file *lock_file;
+       struct unpack_trees_options opts;
+       struct tree_desc t[1];
+
+       if (parse_tree(tree))
+               return -1;
+
+       lock_file = xcalloc(1, sizeof(struct lock_file));
+       hold_locked_index(lock_file, 1);
+
+       memset(&opts, 0, sizeof(opts));
+       opts.head_idx = 1;
+       opts.src_index = &the_index;
+       opts.dst_index = &the_index;
+       opts.merge = 1;
+       opts.fn = oneway_merge;
+       init_tree_desc(&t[0], tree->buffer, tree->size);
+
+       if (unpack_trees(1, t, &opts)) {
+               rollback_lock_file(lock_file);
+               return -1;
+       }
+
+       if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
+               die(_("unable to write new index file"));
+
+       return 0;
+}
+
 /**
  * Clean the index without touching entries that are not modified between
  * `head` and `remote`.
  */
 static int clean_index(const unsigned char *head, const unsigned char *remote)
 {
-       struct lock_file *lock_file;
        struct tree *head_tree, *remote_tree, *index_tree;
        unsigned char index[GIT_SHA1_RAWSZ];
-       struct pathspec pathspec;
 
        head_tree = parse_tree_indirect(head);
        if (!head_tree)
@@ -2009,18 +2043,8 @@ static int clean_index(const unsigned char *head, const unsigned char *remote)
        if (fast_forward_to(index_tree, remote_tree, 0))
                return -1;
 
-       memset(&pathspec, 0, sizeof(pathspec));
-
-       lock_file = xcalloc(1, sizeof(struct lock_file));
-       hold_locked_index(lock_file, 1);
-
-       if (read_tree(remote_tree, 0, &pathspec)) {
-               rollback_lock_file(lock_file);
+       if (merge_tree(remote_tree))
                return -1;
-       }
-
-       if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
-               die(_("unable to write new index file"));
 
        remove_branch_state();
 
@@ -2181,7 +2205,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
                OPT_BOOL('i', "interactive", &state.interactive,
                        N_("run interactively")),
                OPT_HIDDEN_BOOL('b', "binary", &binary,
-                       N_("(historical option -- no-op")),
+                       N_("historical option -- no-op")),
                OPT_BOOL('3', "3way", &state.threeway,
                        N_("allow fall back on 3way merging if needed")),
                OPT__QUIET(&state.quiet, N_("be quiet")),
index 04e4864..4db01c1 100644 (file)
@@ -2227,20 +2227,19 @@ static struct commit_list **append_parent(struct commit_list **tail, const unsig
 static void append_merge_parents(struct commit_list **tail)
 {
        int merge_head;
-       const char *merge_head_file = git_path("MERGE_HEAD");
        struct strbuf line = STRBUF_INIT;
 
-       merge_head = open(merge_head_file, O_RDONLY);
+       merge_head = open(git_path_merge_head(), O_RDONLY);
        if (merge_head < 0) {
                if (errno == ENOENT)
                        return;
-               die("cannot open '%s' for reading", merge_head_file);
+               die("cannot open '%s' for reading", git_path_merge_head());
        }
 
        while (!strbuf_getwholeline_fd(&line, merge_head, '\n')) {
                unsigned char sha1[20];
                if (line.len < 40 || get_sha1_hex(line.buf, sha1))
-                       die("unknown line in '%s': %s", merge_head_file, line.buf);
+                       die("unknown line in '%s': %s", git_path_merge_head(), line.buf);
                tail = append_parent(tail, sha1);
        }
        close(merge_head);
index f71844a..bc703c0 100644 (file)
@@ -18,6 +18,7 @@
 #include "xdiff-interface.h"
 #include "ll-merge.h"
 #include "resolve-undo.h"
+#include "submodule-config.h"
 #include "submodule.h"
 
 static const char * const checkout_usage[] = {
@@ -48,8 +49,6 @@ struct checkout_opts {
        const char *prefix;
        struct pathspec pathspec;
        struct tree *source_tree;
-
-       int new_worktree_mode;
 };
 
 static int post_checkout_hook(struct commit *old, struct commit *new,
@@ -282,7 +281,7 @@ static int checkout_paths(const struct checkout_opts *opts,
        if (opts->source_tree)
                read_tree_some(opts->source_tree, &opts->pathspec);
 
-       ps_matched = xcalloc(1, opts->pathspec.nr);
+       ps_matched = xcalloc(opts->pathspec.nr, 1);
 
        /*
         * Make sure all pathspecs participated in locating the paths
@@ -509,7 +508,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
                        topts.dir->flags |= DIR_SHOW_IGNORED;
                        setup_standard_excludes(topts.dir);
                }
-               tree = parse_tree_indirect(old->commit && !opts->new_worktree_mode ?
+               tree = parse_tree_indirect(old->commit ?
                                           old->commit->object.sha1 :
                                           EMPTY_TREE_SHA1_BIN);
                init_tree_desc(&trees[0], tree->buffer, tree->size);
@@ -612,22 +611,20 @@ static void update_refs_for_switch(const struct checkout_opts *opts,
        if (opts->new_branch) {
                if (opts->new_orphan_branch) {
                        if (opts->new_branch_log && !log_all_ref_updates) {
-                               int temp;
-                               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;
-                               ret = log_ref_setup(ref_name, &log_file);
-                               log_all_ref_updates = temp;
-                               strbuf_release(&log_file);
+                               char *refname;
+                               struct strbuf err = STRBUF_INIT;
+
+                               refname = mkpathdup("refs/heads/%s", opts->new_orphan_branch);
+                               ret = safe_create_reflog(refname, 1, &err);
+                               free(refname);
                                if (ret) {
-                                       fprintf(stderr, _("Can not do reflog for '%s'\n"),
-                                           opts->new_orphan_branch);
+                                       fprintf(stderr, _("Can not do reflog for '%s': %s\n"),
+                                               opts->new_orphan_branch, err.buf);
+                                       strbuf_release(&err);
                                        return;
                                }
+                               strbuf_release(&err);
                        }
                }
                else
@@ -832,8 +829,7 @@ static int switch_branches(const struct checkout_opts *opts,
                return ret;
        }
 
-       if (!opts->quiet && !old.path && old.commit &&
-           new->commit != old.commit && !opts->new_worktree_mode)
+       if (!opts->quiet && !old.path && old.commit && new->commit != old.commit)
                orphaned_commit_warning(old.commit, new->commit);
 
        update_refs_for_switch(opts, &old, new);
@@ -898,71 +894,6 @@ static const char *unique_tracking_name(const char *name, unsigned char *sha1)
        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,
@@ -1170,14 +1101,14 @@ static int checkout_branch(struct checkout_opts *opts,
                die(_("Cannot switch branch to a non-commit '%s'"),
                    new->name);
 
-       if (new->path && !opts->force_detach && !opts->new_branch) {
+       if (new->path && !opts->force_detach && !opts->new_branch &&
+           !opts->ignore_other_worktrees) {
                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);
+                   (!(flag & REF_ISSYMREF) || strcmp(head_ref, new->path)))
+                       die_if_checked_out(new->path);
                free(head_ref);
        }
 
@@ -1241,8 +1172,6 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
        argc = parse_options(argc, argv, prefix, options, checkout_usage,
                             PARSE_OPT_KEEP_DASHDASH);
 
-       opts.new_worktree_mode = getenv("GIT_CHECKOUT_NEW_WORKTREE") != NULL;
-
        if (conflict_style) {
                opts.merge = 1; /* implied */
                git_xmerge_config("merge.conflictstyle", conflict_style, NULL);
index 303a3a7..578da85 100644 (file)
@@ -99,82 +99,140 @@ static const char *argv_submodule[] = {
        "submodule", "update", "--init", "--recursive", NULL
 };
 
-static char *get_repo_path(const char *repo, int *is_bundle)
+static const char *get_repo_path_1(struct strbuf *path, int *is_bundle)
 {
        static char *suffix[] = { "/.git", "", ".git/.git", ".git" };
        static char *bundle_suffix[] = { ".bundle", "" };
+       size_t baselen = path->len;
        struct stat st;
        int i;
 
        for (i = 0; i < ARRAY_SIZE(suffix); i++) {
-               const char *path;
-               path = mkpath("%s%s", repo, suffix[i]);
-               if (stat(path, &st))
+               strbuf_setlen(path, baselen);
+               strbuf_addstr(path, suffix[i]);
+               if (stat(path->buf, &st))
                        continue;
-               if (S_ISDIR(st.st_mode) && is_git_directory(path)) {
+               if (S_ISDIR(st.st_mode) && is_git_directory(path->buf)) {
                        *is_bundle = 0;
-                       return xstrdup(absolute_path(path));
+                       return path->buf;
                } else if (S_ISREG(st.st_mode) && st.st_size > 8) {
                        /* Is it a "gitfile"? */
                        char signature[8];
-                       int len, fd = open(path, O_RDONLY);
+                       const char *dst;
+                       int len, fd = open(path->buf, O_RDONLY);
                        if (fd < 0)
                                continue;
                        len = read_in_full(fd, signature, 8);
                        close(fd);
                        if (len != 8 || strncmp(signature, "gitdir: ", 8))
                                continue;
-                       path = read_gitfile(path);
-                       if (path) {
+                       dst = read_gitfile(path->buf);
+                       if (dst) {
                                *is_bundle = 0;
-                               return xstrdup(absolute_path(path));
+                               return dst;
                        }
                }
        }
 
        for (i = 0; i < ARRAY_SIZE(bundle_suffix); i++) {
-               const char *path;
-               path = mkpath("%s%s", repo, bundle_suffix[i]);
-               if (!stat(path, &st) && S_ISREG(st.st_mode)) {
+               strbuf_setlen(path, baselen);
+               strbuf_addstr(path, bundle_suffix[i]);
+               if (!stat(path->buf, &st) && S_ISREG(st.st_mode)) {
                        *is_bundle = 1;
-                       return xstrdup(absolute_path(path));
+                       return path->buf;
                }
        }
 
        return NULL;
 }
 
+static char *get_repo_path(const char *repo, int *is_bundle)
+{
+       struct strbuf path = STRBUF_INIT;
+       const char *raw;
+       char *canon;
+
+       strbuf_addstr(&path, repo);
+       raw = get_repo_path_1(&path, is_bundle);
+       canon = raw ? xstrdup(absolute_path(raw)) : NULL;
+       strbuf_release(&path);
+       return canon;
+}
+
 static char *guess_dir_name(const char *repo, int is_bundle, int is_bare)
 {
-       const char *end = repo + strlen(repo), *start;
+       const char *end = repo + strlen(repo), *start, *ptr;
        size_t len;
        char *dir;
 
+       /*
+        * Skip scheme.
+        */
+       start = strstr(repo, "://");
+       if (start == NULL)
+               start = repo;
+       else
+               start += 3;
+
+       /*
+        * Skip authentication data. The stripping does happen
+        * greedily, such that we strip up to the last '@' inside
+        * the host part.
+        */
+       for (ptr = start; ptr < end && !is_dir_sep(*ptr); ptr++) {
+               if (*ptr == '@')
+                       start = ptr + 1;
+       }
+
        /*
         * Strip trailing spaces, slashes and /.git
         */
-       while (repo < end && (is_dir_sep(end[-1]) || isspace(end[-1])))
+       while (start < end && (is_dir_sep(end[-1]) || isspace(end[-1])))
                end--;
-       if (end - repo > 5 && is_dir_sep(end[-5]) &&
+       if (end - start > 5 && is_dir_sep(end[-5]) &&
            !strncmp(end - 4, ".git", 4)) {
                end -= 5;
-               while (repo < end && is_dir_sep(end[-1]))
+               while (start < end && is_dir_sep(end[-1]))
                        end--;
        }
 
        /*
-        * Find last component, but be prepared that repo could have
-        * the form  "remote.example.com:foo.git", i.e. no slash
-        * in the directory part.
+        * Strip trailing port number if we've got only a
+        * hostname (that is, there is no dir separator but a
+        * colon). This check is required such that we do not
+        * strip URI's like '/foo/bar:2222.git', which should
+        * result in a dir '2222' being guessed due to backwards
+        * compatibility.
         */
-       start = end;
-       while (repo < start && !is_dir_sep(start[-1]) && start[-1] != ':')
-               start--;
+       if (memchr(start, '/', end - start) == NULL
+           && memchr(start, ':', end - start) != NULL) {
+               ptr = end;
+               while (start < ptr && isdigit(ptr[-1]) && ptr[-1] != ':')
+                       ptr--;
+               if (start < ptr && ptr[-1] == ':')
+                       end = ptr - 1;
+       }
+
+       /*
+        * Find last component. To remain backwards compatible we
+        * also regard colons as path separators, such that
+        * cloning a repository 'foo:bar.git' would result in a
+        * directory 'bar' being guessed.
+        */
+       ptr = end;
+       while (start < ptr && !is_dir_sep(ptr[-1]) && ptr[-1] != ':')
+               ptr--;
+       start = ptr;
 
        /*
         * Strip .{bundle,git}.
         */
-       strip_suffix(start, is_bundle ? ".bundle" : ".git" , &len);
+       len = end - start;
+       strip_suffix_mem(start, &len, is_bundle ? ".bundle" : ".git");
+
+       if (!len || (len == 1 && *start == '/'))
+           die("No directory name could be guessed.\n"
+               "Please specify a directory on the command line");
 
        if (is_bare)
                dir = xstrfmt("%.*s.git", (int)len, start);
index 7314f33..b37cb6c 100644 (file)
@@ -166,9 +166,9 @@ static int opt_parse_m(const struct option *opt, const char *arg, int unset)
 
 static void determine_whence(struct wt_status *s)
 {
-       if (file_exists(git_path("MERGE_HEAD")))
+       if (file_exists(git_path_merge_head()))
                whence = FROM_MERGE;
-       else if (file_exists(git_path("CHERRY_PICK_HEAD"))) {
+       else if (file_exists(git_path_cherry_pick_head())) {
                whence = FROM_CHERRY_PICK;
                if (file_exists(git_path(SEQ_DIR)))
                        sequencer_in_use = 1;
@@ -324,6 +324,7 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
        struct string_list partial;
        struct pathspec pathspec;
        int refresh_flags = REFRESH_QUIET;
+       const char *ret;
 
        if (is_status)
                refresh_flags |= REFRESH_UNMERGED;
@@ -344,7 +345,7 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
                        die(_("unable to create temporary index"));
 
                old_index_env = getenv(INDEX_ENVIRONMENT);
-               setenv(INDEX_ENVIRONMENT, index_lock.filename.buf, 1);
+               setenv(INDEX_ENVIRONMENT, get_lock_file_path(&index_lock), 1);
 
                if (interactive_add(argc, argv, prefix, patch_interactive) != 0)
                        die(_("interactive add failed"));
@@ -355,7 +356,7 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
                        unsetenv(INDEX_ENVIRONMENT);
 
                discard_cache();
-               read_cache_from(index_lock.filename.buf);
+               read_cache_from(get_lock_file_path(&index_lock));
                if (update_main_cache_tree(WRITE_TREE_SILENT) == 0) {
                        if (reopen_lock_file(&index_lock) < 0)
                                die(_("unable to write index file"));
@@ -365,7 +366,7 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
                        warning(_("Failed to update main cache tree"));
 
                commit_style = COMMIT_NORMAL;
-               return index_lock.filename.buf;
+               return get_lock_file_path(&index_lock);
        }
 
        /*
@@ -388,7 +389,7 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
                if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))
                        die(_("unable to write new_index file"));
                commit_style = COMMIT_NORMAL;
-               return index_lock.filename.buf;
+               return get_lock_file_path(&index_lock);
        }
 
        /*
@@ -475,9 +476,9 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
                die(_("unable to write temporary index file"));
 
        discard_cache();
-       read_cache_from(false_lock.filename.buf);
-
-       return false_lock.filename.buf;
+       ret = get_lock_file_path(&false_lock);
+       read_cache_from(ret);
+       return ret;
 }
 
 static int run_status(FILE *fp, const char *index_file, const char *prefix, int nowarn,
@@ -725,12 +726,12 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
                format_commit_message(commit, "fixup! %s\n\n",
                                      &sb, &ctx);
                hook_arg1 = "message";
-       } else if (!stat(git_path("MERGE_MSG"), &statbuf)) {
-               if (strbuf_read_file(&sb, git_path("MERGE_MSG"), 0) < 0)
+       } else if (!stat(git_path_merge_msg(), &statbuf)) {
+               if (strbuf_read_file(&sb, git_path_merge_msg(), 0) < 0)
                        die_errno(_("could not read MERGE_MSG"));
                hook_arg1 = "merge";
-       } else if (!stat(git_path("SQUASH_MSG"), &statbuf)) {
-               if (strbuf_read_file(&sb, git_path("SQUASH_MSG"), 0) < 0)
+       } else if (!stat(git_path_squash_msg(), &statbuf)) {
+               if (strbuf_read_file(&sb, git_path_squash_msg(), 0) < 0)
                        die_errno(_("could not read SQUASH_MSG"));
                hook_arg1 = "squash";
        } else if (template_file) {
@@ -1684,10 +1685,10 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
                if (!reflog_msg)
                        reflog_msg = "commit (merge)";
                pptr = &commit_list_insert(current_head, pptr)->next;
-               fp = fopen(git_path("MERGE_HEAD"), "r");
+               fp = fopen(git_path_merge_head(), "r");
                if (fp == NULL)
                        die_errno(_("could not open '%s' for reading"),
-                                 git_path("MERGE_HEAD"));
+                                 git_path_merge_head());
                while (strbuf_getline(&m, fp, '\n') != EOF) {
                        struct commit *parent;
 
@@ -1698,8 +1699,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
                }
                fclose(fp);
                strbuf_release(&m);
-               if (!stat(git_path("MERGE_MODE"), &statbuf)) {
-                       if (strbuf_read_file(&sb, git_path("MERGE_MODE"), 0) < 0)
+               if (!stat(git_path_merge_mode(), &statbuf)) {
+                       if (strbuf_read_file(&sb, git_path_merge_mode(), 0) < 0)
                                die_errno(_("could not read MERGE_MODE"));
                        if (!strcmp(sb.buf, "no-ff"))
                                allow_fast_forward = 0;
@@ -1775,12 +1776,12 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
        }
        ref_transaction_free(transaction);
 
-       unlink(git_path("CHERRY_PICK_HEAD"));
-       unlink(git_path("REVERT_HEAD"));
-       unlink(git_path("MERGE_HEAD"));
-       unlink(git_path("MERGE_MSG"));
-       unlink(git_path("MERGE_MODE"));
-       unlink(git_path("SQUASH_MSG"));
+       unlink(git_path_cherry_pick_head());
+       unlink(git_path_revert_head());
+       unlink(git_path_merge_head());
+       unlink(git_path_merge_msg());
+       unlink(git_path_merge_mode());
+       unlink(git_path_squash_msg());
 
        if (commit_index_files())
                die (_("Repository has been updated, but unable to write\n"
index 7188405..71acc44 100644 (file)
@@ -13,6 +13,7 @@ static char *key;
 static regex_t *key_regexp;
 static regex_t *regexp;
 static int show_keys;
+static int omit_values;
 static int use_key_regexp;
 static int do_all;
 static int do_not_match;
@@ -78,6 +79,7 @@ static struct option builtin_config_options[] = {
        OPT_BIT(0, "path", &types, N_("value is a path (file or directory name)"), TYPE_PATH),
        OPT_GROUP(N_("Other")),
        OPT_BOOL('z', "null", &end_null, N_("terminate values with NUL byte")),
+       OPT_BOOL(0, "name-only", &omit_values, N_("show variable names only")),
        OPT_BOOL(0, "includes", &respect_includes, N_("respect include directives on lookup")),
        OPT_END(),
 };
@@ -91,7 +93,7 @@ static void check_argc(int argc, int min, int max) {
 
 static int show_all_config(const char *key_, const char *value_, void *cb)
 {
-       if (value_)
+       if (!omit_values && value_)
                printf("%s%c%s%c", key_, delim, value_, term);
        else
                printf("%s%c", key_, term);
@@ -106,48 +108,40 @@ struct strbuf_list {
 
 static int format_config(struct strbuf *buf, const char *key_, const char *value_)
 {
-       int must_free_vptr = 0;
-       int must_print_delim = 0;
-       char value[256];
-       const char *vptr = value;
-
-       strbuf_init(buf, 0);
-
-       if (show_keys) {
+       if (show_keys)
                strbuf_addstr(buf, key_);
-               must_print_delim = 1;
-       }
-       if (types == TYPE_INT)
-               sprintf(value, "%"PRId64,
-                       git_config_int64(key_, value_ ? value_ : ""));
-       else if (types == TYPE_BOOL)
-               vptr = git_config_bool(key_, value_) ? "true" : "false";
-       else if (types == TYPE_BOOL_OR_INT) {
-               int is_bool, v;
-               v = git_config_bool_or_int(key_, value_, &is_bool);
-               if (is_bool)
-                       vptr = v ? "true" : "false";
-               else
-                       sprintf(value, "%d", v);
-       } else if (types == TYPE_PATH) {
-               if (git_config_pathname(&vptr, key_, value_) < 0)
-                       return -1;
-               must_free_vptr = 1;
-       } else if (value_) {
-               vptr = value_;
-       } else {
-               /* Just show the key name */
-               vptr = "";
-               must_print_delim = 0;
-       }
+       if (!omit_values) {
+               if (show_keys)
+                       strbuf_addch(buf, key_delim);
 
-       if (must_print_delim)
-               strbuf_addch(buf, key_delim);
-       strbuf_addstr(buf, vptr);
+               if (types == TYPE_INT)
+                       strbuf_addf(buf, "%"PRId64,
+                                   git_config_int64(key_, value_ ? value_ : ""));
+               else if (types == TYPE_BOOL)
+                       strbuf_addstr(buf, git_config_bool(key_, value_) ?
+                                     "true" : "false");
+               else if (types == TYPE_BOOL_OR_INT) {
+                       int is_bool, v;
+                       v = git_config_bool_or_int(key_, value_, &is_bool);
+                       if (is_bool)
+                               strbuf_addstr(buf, v ? "true" : "false");
+                       else
+                               strbuf_addf(buf, "%d", v);
+               } else if (types == TYPE_PATH) {
+                       const char *v;
+                       if (git_config_pathname(&v, key_, value_) < 0)
+                               return -1;
+                       strbuf_addstr(buf, v);
+                       free((char *)v);
+               } else if (value_) {
+                       strbuf_addstr(buf, value_);
+               } else {
+                       /* Just show the key name; back out delimiter */
+                       if (show_keys)
+                               strbuf_setlen(buf, buf->len - 1);
+               }
+       }
        strbuf_addch(buf, term);
-
-       if (must_free_vptr)
-               free((char *)vptr);
        return 0;
 }
 
@@ -164,6 +158,7 @@ static int collect_config(const char *key_, const char *value_, void *cb)
                return 0;
 
        ALLOC_GROW(values->items, values->nr + 1, values->alloc);
+       strbuf_init(&values->items[values->nr], 0);
 
        return format_config(&values->items[values->nr++], key_, value_);
 }
@@ -430,14 +425,11 @@ static int get_urlmatch(const char *var, const char *url)
 
        for_each_string_list_item(item, &values) {
                struct urlmatch_current_candidate_value *matched = item->util;
-               struct strbuf key = STRBUF_INIT;
                struct strbuf buf = STRBUF_INIT;
 
-               strbuf_addstr(&key, item->string);
-               format_config(&buf, key.buf,
+               format_config(&buf, item->string,
                              matched->value_is_null ? NULL : matched->value.buf);
                fwrite(buf.buf, 1, buf.len, stdout);
-               strbuf_release(&key);
                strbuf_release(&buf);
 
                strbuf_release(&matched->value);
@@ -549,7 +541,11 @@ int cmd_config(int argc, const char **argv, const char *prefix)
                default:
                        usage_with_options(builtin_config_usage, builtin_config_options);
                }
-
+       if (omit_values &&
+           !(actions == ACTION_LIST || actions == ACTION_GET_REGEXP)) {
+               error("--name-only is only applicable to --list or --get-regexp");
+               usage_with_options(builtin_config_usage, builtin_config_options);
+       }
        if (actions == ACTION_LIST) {
                check_argc(argc, 0, 0);
                if (git_config_with_options(show_all_config, NULL,
index 34b6f5e..9a3869f 100644 (file)
@@ -11,6 +11,7 @@
 #include "run-command.h"
 #include "parse-options.h"
 #include "sigchain.h"
+#include "submodule-config.h"
 #include "submodule.h"
 #include "connected.h"
 #include "argv-array.h"
@@ -591,7 +592,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
        const char *what, *kind;
        struct ref *rm;
        char *url;
-       const char *filename = dry_run ? "/dev/null" : git_path("FETCH_HEAD");
+       const char *filename = dry_run ? "/dev/null" : git_path_fetch_head();
        int want_status;
 
        fp = fopen(filename, "a");
@@ -834,7 +835,7 @@ static void check_not_current_branch(struct ref *ref_map)
 
 static int truncate_fetch_head(void)
 {
-       const char *filename = git_path("FETCH_HEAD");
+       const char *filename = git_path_fetch_head();
        FILE *fp = fopen(filename, "w");
 
        if (!fp)
@@ -988,17 +989,15 @@ static int get_remote_group(const char *key, const char *value, void *priv)
 {
        struct remote_group_data *g = priv;
 
-       if (starts_with(key, "remotes.") &&
-                       !strcmp(key + 8, g->name)) {
+       if (skip_prefix(key, "remotes.", &key) && !strcmp(key, g->name)) {
                /* split list by white space */
-               int space = strcspn(value, " \t\n");
                while (*value) {
-                       if (space > 1) {
+                       size_t wordlen = strcspn(value, " \t\n");
+
+                       if (wordlen >= 1)
                                string_list_append(g->list,
-                                                  xstrndup(value, space));
-                       }
-                       value += space + (value[space] != '\0');
-                       space = strcspn(value, " \t\n");
+                                                  xstrndup(value, wordlen));
+                       value += wordlen + (value[wordlen] != '\0');
                }
        }
 
index f4b87e9..0794703 100644 (file)
@@ -243,13 +243,14 @@ static void check_unreachable_object(struct object *obj)
                        printf("dangling %s %s\n", typename(obj->type),
                               sha1_to_hex(obj->sha1));
                if (write_lost_and_found) {
-                       const char *filename = git_path("lost-found/%s/%s",
+                       char *filename = git_pathdup("lost-found/%s/%s",
                                obj->type == OBJ_COMMIT ? "commit" : "other",
                                sha1_to_hex(obj->sha1));
                        FILE *f;
 
                        if (safe_create_leading_directories_const(filename)) {
                                error("Could not create lost-found");
+                               free(filename);
                                return;
                        }
                        if (!(f = fopen(filename, "w")))
@@ -262,6 +263,7 @@ static void check_unreachable_object(struct object *obj)
                        if (fclose(f))
                                die_errno("Could not finish '%s'",
                                          filename);
+                       free(filename);
                }
                return;
        }
index 4957c39..0ad8d30 100644 (file)
@@ -11,6 +11,7 @@
  */
 
 #include "builtin.h"
+#include "tempfile.h"
 #include "lockfile.h"
 #include "parse-options.h"
 #include "run-command.h"
@@ -42,20 +43,7 @@ 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;
-
-static void remove_pidfile(void)
-{
-       if (pidfile)
-               unlink(pidfile);
-}
-
-static void remove_pidfile_on_signal(int signo)
-{
-       remove_pidfile();
-       sigchain_pop(signo);
-       raise(signo);
-}
+static struct tempfile pidfile;
 
 static void git_config_date_string(const char *key, const char **output)
 {
@@ -85,7 +73,7 @@ static void gc_config(void)
        git_config_get_int("gc.autopacklimit", &gc_auto_pack_limit);
        git_config_get_bool("gc.autodetach", &detach_auto);
        git_config_date_string("gc.pruneexpire", &prune_expire);
-       git_config_date_string("gc.pruneworktreesexpire", &prune_worktrees_expire);
+       git_config_date_string("gc.worktreepruneexpire", &prune_worktrees_expire);
        git_config(git_default_config, NULL);
 }
 
@@ -199,20 +187,22 @@ static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
        uintmax_t pid;
        FILE *fp;
        int fd;
+       char *pidfile_path;
 
-       if (pidfile)
+       if (is_tempfile_active(&pidfile))
                /* already locked */
                return NULL;
 
        if (gethostname(my_host, sizeof(my_host)))
                strcpy(my_host, "unknown");
 
-       fd = hold_lock_file_for_update(&lock, git_path("gc.pid"),
+       pidfile_path = git_pathdup("gc.pid");
+       fd = hold_lock_file_for_update(&lock, pidfile_path,
                                       LOCK_DIE_ON_ERROR);
        if (!force) {
                static char locking_host[128];
                int should_exit;
-               fp = fopen(git_path("gc.pid"), "r");
+               fp = fopen(pidfile_path, "r");
                memset(locking_host, 0, sizeof(locking_host));
                should_exit =
                        fp != NULL &&
@@ -236,6 +226,7 @@ static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
                        if (fd >= 0)
                                rollback_lock_file(&lock);
                        *ret_pid = pid;
+                       free(pidfile_path);
                        return locking_host;
                }
        }
@@ -245,11 +236,8 @@ static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
        write_in_full(fd, sb.buf, sb.len);
        strbuf_release(&sb);
        commit_lock_file(&lock);
-
-       pidfile = git_pathdup("gc.pid");
-       sigchain_push_common(remove_pidfile_on_signal);
-       atexit(remove_pidfile);
-
+       register_tempfile(&pidfile, pidfile_path);
+       free(pidfile_path);
        return NULL;
 }
 
index 3f10840..3431de2 100644 (file)
@@ -1421,7 +1421,7 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
                                 get_object_directory(), sha1_to_hex(sha1));
                        final_pack_name = name;
                }
-               if (move_temp_to_file(curr_pack_name, final_pack_name))
+               if (finalize_object_file(curr_pack_name, final_pack_name))
                        die(_("cannot store pack file"));
        } else if (from_stdin)
                chmod(final_pack_name, 0444);
@@ -1432,7 +1432,7 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
                                 get_object_directory(), sha1_to_hex(sha1));
                        final_index_name = name;
                }
-               if (move_temp_to_file(curr_index_name, final_index_name))
+               if (finalize_object_file(curr_index_name, final_index_name))
                        die(_("cannot store index file"));
        } else
                chmod(final_index_name, 0444);
index b50ef75..a491d3d 100644 (file)
@@ -342,8 +342,7 @@ static int cmd_log_walk(struct rev_info *rev)
         * retain that state information if replacing rev->diffopt in this loop
         */
        while ((commit = get_revision(rev)) != NULL) {
-               if (!log_tree_commit(rev, commit) &&
-                   rev->max_count >= 0)
+               if (!log_tree_commit(rev, commit) && rev->max_count >= 0)
                        /*
                         * We decremented max_count in get_revision,
                         * but we didn't actually show the commit.
@@ -504,7 +503,8 @@ static int show_tree_object(const unsigned char *sha1,
        return 0;
 }
 
-static void show_rev_tweak_rev(struct rev_info *rev, struct setup_revision_opt *opt)
+static void show_setup_revisions_tweak(struct rev_info *rev,
+                                      struct setup_revision_opt *opt)
 {
        if (rev->ignore_merges) {
                /* There was no "-m" on the command line */
@@ -539,7 +539,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
 
        memset(&opt, 0, sizeof(opt));
        opt.def = "HEAD";
-       opt.tweak = show_rev_tweak_rev;
+       opt.tweak = show_setup_revisions_tweak;
        cmd_log_init(argc, argv, prefix, &rev, &opt);
 
        if (!rev.no_walk)
@@ -626,12 +626,20 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix)
        return cmd_log_walk(&rev);
 }
 
-static void default_follow_tweak(struct rev_info *rev,
-                                struct setup_revision_opt *opt)
+static void log_setup_revisions_tweak(struct rev_info *rev,
+                                     struct setup_revision_opt *opt)
 {
        if (DIFF_OPT_TST(&rev->diffopt, DEFAULT_FOLLOW_RENAMES) &&
            rev->prune_data.nr == 1)
                DIFF_OPT_SET(&rev->diffopt, FOLLOW_RENAMES);
+
+       /* Turn --cc/-c into -p --cc/-c when -p was not given */
+       if (!rev->diffopt.output_format && rev->combine_merges)
+               rev->diffopt.output_format = DIFF_FORMAT_PATCH;
+
+       /* Turn -m on when --cc/-c was given */
+       if (rev->combine_merges)
+               rev->ignore_merges = 0;
 }
 
 int cmd_log(int argc, const char **argv, const char *prefix)
@@ -647,7 +655,7 @@ int cmd_log(int argc, const char **argv, const char *prefix)
        memset(&opt, 0, sizeof(opt));
        opt.def = "HEAD";
        opt.revarg_opt = REVARG_COMMITTISH;
-       opt.tweak = default_follow_tweak;
+       opt.tweak = log_setup_revisions_tweak;
        cmd_log_init(argc, argv, prefix, &rev, &opt);
        return cmd_log_walk(&rev);
 }
@@ -1455,8 +1463,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                        continue;
                }
 
-               if (ignore_if_in_upstream &&
-                               has_commit_patch_id(commit, &ids))
+               if (ignore_if_in_upstream && has_commit_patch_id(commit, &ids))
                        continue;
 
                nr++;
index 6fa2205..b6a7cb0 100644 (file)
@@ -516,7 +516,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 
        /* Treat unmatching pathspec elements as errors */
        if (pathspec.nr && error_unmatch)
-               ps_matched = xcalloc(1, pathspec.nr);
+               ps_matched = xcalloc(pathspec.nr, 1);
 
        if ((dir.flags & DIR_SHOW_IGNORED) && !exc_given)
                die("ls-files --ignored needs some exclude pattern");
index 85c54dc..a0edaca 100644 (file)
@@ -231,9 +231,9 @@ static struct option builtin_merge_options[] = {
 /* Cleans up metadata that is uninteresting after a succeeded merge. */
 static void drop_save(void)
 {
-       unlink(git_path("MERGE_HEAD"));
-       unlink(git_path("MERGE_MSG"));
-       unlink(git_path("MERGE_MODE"));
+       unlink(git_path_merge_head());
+       unlink(git_path_merge_msg());
+       unlink(git_path_merge_mode());
 }
 
 static int save_state(unsigned char *stash)
@@ -338,7 +338,7 @@ static void squash_message(struct commit *commit, struct commit_list *remotehead
        struct pretty_print_context ctx = {0};
 
        printf(_("Squash commit -- not updating HEAD\n"));
-       filename = git_path("SQUASH_MSG");
+       filename = git_path_squash_msg();
        fd = open(filename, O_WRONLY | O_CREAT, 0666);
        if (fd < 0)
                die_errno(_("Could not write to '%s'"), filename);
@@ -754,7 +754,7 @@ static void add_strategies(const char *string, unsigned attr)
 
 static void write_merge_msg(struct strbuf *msg)
 {
-       const char *filename = git_path("MERGE_MSG");
+       const char *filename = git_path_merge_msg();
        int fd = open(filename, O_WRONLY | O_CREAT, 0666);
        if (fd < 0)
                die_errno(_("Could not open '%s' for writing"),
@@ -766,7 +766,7 @@ static void write_merge_msg(struct strbuf *msg)
 
 static void read_merge_msg(struct strbuf *msg)
 {
-       const char *filename = git_path("MERGE_MSG");
+       const char *filename = git_path_merge_msg();
        strbuf_reset(msg);
        if (strbuf_read_file(msg, filename, 0) < 0)
                die_errno(_("Could not read from '%s'"), filename);
@@ -799,10 +799,10 @@ static void prepare_to_commit(struct commit_list *remoteheads)
                strbuf_commented_addf(&msg, _(merge_editor_comment), comment_line_char);
        write_merge_msg(&msg);
        if (run_commit_hook(0 < option_edit, get_index_file(), "prepare-commit-msg",
-                           git_path("MERGE_MSG"), "merge", NULL))
+                           git_path_merge_msg(), "merge", NULL))
                abort_commit(remoteheads, NULL);
        if (0 < option_edit) {
-               if (launch_editor(git_path("MERGE_MSG"), NULL, NULL))
+               if (launch_editor(git_path_merge_msg(), NULL, NULL))
                        abort_commit(remoteheads, NULL);
        }
        read_merge_msg(&msg);
@@ -865,7 +865,7 @@ static int suggest_conflicts(void)
        FILE *fp;
        struct strbuf msgbuf = STRBUF_INIT;
 
-       filename = git_path("MERGE_MSG");
+       filename = git_path_merge_msg();
        fp = fopen(filename, "a");
        if (!fp)
                die_errno(_("Could not open '%s' for writing"), filename);
@@ -967,7 +967,7 @@ static void write_merge_state(struct commit_list *remoteheads)
                }
                strbuf_addf(&buf, "%s\n", sha1_to_hex(sha1));
        }
-       filename = git_path("MERGE_HEAD");
+       filename = git_path_merge_head();
        fd = open(filename, O_WRONLY | O_CREAT, 0666);
        if (fd < 0)
                die_errno(_("Could not open '%s' for writing"), filename);
@@ -977,7 +977,7 @@ static void write_merge_state(struct commit_list *remoteheads)
        strbuf_addch(&merge_msg, '\n');
        write_merge_msg(&merge_msg);
 
-       filename = git_path("MERGE_MODE");
+       filename = git_path_merge_mode();
        fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
        if (fd < 0)
                die_errno(_("Could not open '%s' for writing"), filename);
@@ -1070,7 +1070,7 @@ static void handle_fetch_head(struct commit_list **remotes, struct strbuf *merge
        if (!merge_names)
                merge_names = &fetch_head_file;
 
-       filename = git_path("FETCH_HEAD");
+       filename = git_path_fetch_head();
        fd = open(filename, O_RDONLY);
        if (fd < 0)
                die_errno(_("could not open '%s' for reading"), filename);
@@ -1204,7 +1204,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                int nargc = 2;
                const char *nargv[] = {"reset", "--merge", NULL};
 
-               if (!file_exists(git_path("MERGE_HEAD")))
+               if (!file_exists(git_path_merge_head()))
                        die(_("There is no merge to abort (MERGE_HEAD missing)."));
 
                /* Invoke 'git reset --merge' */
@@ -1215,7 +1215,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
        if (read_cache_unmerged())
                die_resolve_conflict("merge");
 
-       if (file_exists(git_path("MERGE_HEAD"))) {
+       if (file_exists(git_path_merge_head())) {
                /*
                 * There is no unmerged entry, don't advise 'git
                 * add/rm <file>', just 'git commit'.
@@ -1226,7 +1226,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                else
                        die(_("You have not concluded your merge (MERGE_HEAD exists)."));
        }
-       if (file_exists(git_path("CHERRY_PICK_HEAD"))) {
+       if (file_exists(git_path_cherry_pick_head())) {
                if (advice_resolve_conflict)
                        die(_("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
                            "Please, commit your changes before you merge."));
index 63f95fc..0423480 100644 (file)
@@ -19,6 +19,7 @@
 #include "string-list.h"
 #include "notes-merge.h"
 #include "notes-utils.h"
+#include "branch.h"
 
 static const char * const git_notes_usage[] = {
        N_("git notes [--ref <notes-ref>] [list [<object>]]"),
@@ -825,10 +826,15 @@ static int merge(int argc, const char **argv, const char *prefix)
                update_ref(msg.buf, default_notes_ref(), result_sha1, NULL,
                           0, UPDATE_REFS_DIE_ON_ERR);
        else { /* Merge has unresolved conflicts */
+               char *existing;
                /* Update .git/NOTES_MERGE_PARTIAL with partial merge result */
                update_ref(msg.buf, "NOTES_MERGE_PARTIAL", result_sha1, NULL,
                           0, UPDATE_REFS_DIE_ON_ERR);
                /* Store ref-to-be-updated into .git/NOTES_MERGE_REF */
+               existing = find_shared_symref("NOTES_MERGE_REF", default_notes_ref());
+               if (existing)
+                       die(_("A notes merge into %s is already in-progress at %s"),
+                           default_notes_ref(), existing);
                if (create_symref("NOTES_MERGE_REF", default_notes_ref(), NULL))
                        die("Failed to store link to current notes ref (%s)",
                            default_notes_ref());
index 722a83c..7e3c11e 100644 (file)
@@ -15,6 +15,7 @@
 #include "dir.h"
 #include "refs.h"
 #include "revision.h"
+#include "tempfile.h"
 #include "lockfile.h"
 
 enum rebase_type {
@@ -823,10 +824,14 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
                hashclr(orig_head);
 
        if (opt_rebase) {
+               int autostash = 0;
+
                if (is_null_sha1(orig_head) && !is_cache_unborn())
                        die(_("Updating an unborn branch with changes added to the index."));
 
-               die_on_unclean_work_tree(prefix);
+               git_config_get_bool("rebase.autostash", &autostash);
+               if (!autostash)
+                       die_on_unclean_work_tree(prefix);
 
                if (get_rebase_fork_point(rebase_fork_point, repo, *refspecs))
                        hashclr(rebase_fork_point);
index 4ced2eb..e6b93d0 100644 (file)
@@ -933,7 +933,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
                        return "deletion prohibited";
                }
 
-               if (!strcmp(namespaced_name, head_name)) {
+               if (head_name && !strcmp(namespaced_name, head_name)) {
                        switch (deny_delete_current) {
                        case DENY_IGNORE:
                                break;
index c2eb8ff..7ed0e85 100644 (file)
@@ -13,6 +13,8 @@ static const char reflog_expire_usage[] =
 "git reflog expire [--expire=<time>] [--expire-unreachable=<time>] [--rewrite] [--updateref] [--stale-fix] [--dry-run | -n] [--verbose] [--all] <refs>...";
 static const char reflog_delete_usage[] =
 "git reflog delete [--rewrite] [--updateref] [--dry-run | -n] [--verbose] <refs>...";
+static const char reflog_exists_usage[] =
+"git reflog exists <ref>";
 
 static unsigned long default_reflog_expire;
 static unsigned long default_reflog_expire_unreachable;
@@ -699,12 +701,38 @@ static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
        return status;
 }
 
+static int cmd_reflog_exists(int argc, const char **argv, const char *prefix)
+{
+       int i, start = 0;
+
+       for (i = 1; i < argc; i++) {
+               const char *arg = argv[i];
+               if (!strcmp(arg, "--")) {
+                       i++;
+                       break;
+               }
+               else if (arg[0] == '-')
+                       usage(reflog_exists_usage);
+               else
+                       break;
+       }
+
+       start = i;
+
+       if (argc - start != 1)
+               usage(reflog_exists_usage);
+
+       if (check_refname_format(argv[start], REFNAME_ALLOW_ONELEVEL))
+               die("invalid ref format: %s", argv[start]);
+       return !reflog_exists(argv[start]);
+}
+
 /*
  * main "reflog"
  */
 
 static const char reflog_usage[] =
-"git reflog [ show | expire | delete ]";
+"git reflog [ show | expire | delete | exists ]";
 
 int cmd_reflog(int argc, const char **argv, const char *prefix)
 {
@@ -724,5 +752,8 @@ int cmd_reflog(int argc, const char **argv, const char *prefix)
        if (!strcmp(argv[1], "delete"))
                return cmd_reflog_delete(argc - 1, argv + 1, prefix);
 
+       if (!strcmp(argv[1], "exists"))
+               return cmd_reflog_exists(argc - 1, argv + 1, prefix);
+
        return cmd_log_reflog(argc, argv, prefix);
 }
index cc3c741..181668d 100644 (file)
@@ -581,7 +581,6 @@ static int migrate_file(struct remote *remote)
 {
        struct strbuf buf = STRBUF_INIT;
        int i;
-       const char *path = NULL;
 
        strbuf_addf(&buf, "remote.%s.url", remote->name);
        for (i = 0; i < remote->url_nr; i++)
@@ -601,11 +600,9 @@ static int migrate_file(struct remote *remote)
                        return error(_("Could not append '%s' to '%s'"),
                                        remote->fetch_refspec[i], buf.buf);
        if (remote->origin == REMOTE_REMOTES)
-               path = git_path("remotes/%s", remote->name);
+               unlink_or_warn(git_path("remotes/%s", remote->name));
        else if (remote->origin == REMOTE_BRANCHES)
-               path = git_path("branches/%s", remote->name);
-       if (path)
-               unlink_or_warn(path);
+               unlink_or_warn(git_path("branches/%s", remote->name));
        return 0;
 }
 
index af7340c..70b9b1e 100644 (file)
@@ -285,8 +285,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
        failed = 0;
        for_each_string_list_item(item, &names) {
                for (ext = 0; ext < ARRAY_SIZE(exts); ext++) {
-                       const char *fname_old;
-                       char *fname;
+                       char *fname, *fname_old;
                        fname = mkpathdup("%s/pack-%s%s", packdir,
                                                item->string, exts[ext].name);
                        if (!file_exists(fname)) {
@@ -294,7 +293,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
                                continue;
                        }
 
-                       fname_old = mkpath("%s/old-%s%s", packdir,
+                       fname_old = mkpathdup("%s/old-%s%s", packdir,
                                                item->string, exts[ext].name);
                        if (file_exists(fname_old))
                                if (unlink(fname_old))
@@ -302,10 +301,12 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 
                        if (!failed && rename(fname, fname_old)) {
                                free(fname);
+                               free(fname_old);
                                failed = 1;
                                break;
                        } else {
                                string_list_append(&rollback, fname);
+                               free(fname_old);
                        }
                }
                if (failed)
@@ -314,13 +315,13 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
        if (failed) {
                struct string_list rollback_failure = STRING_LIST_INIT_DUP;
                for_each_string_list_item(item, &rollback) {
-                       const char *fname_old;
-                       char *fname;
+                       char *fname, *fname_old;
                        fname = mkpathdup("%s/%s", packdir, item->string);
-                       fname_old = mkpath("%s/old-%s", packdir, item->string);
+                       fname_old = mkpathdup("%s/old-%s", packdir, item->string);
                        if (rename(fname_old, fname))
                                string_list_append(&rollback_failure, fname);
                        free(fname);
+                       free(fname_old);
                }
 
                if (rollback_failure.nr) {
@@ -368,13 +369,14 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
        /* Remove the "old-" files */
        for_each_string_list_item(item, &names) {
                for (ext = 0; ext < ARRAY_SIZE(exts); ext++) {
-                       const char *fname;
-                       fname = mkpath("%s/old-%s%s",
-                                       packdir,
-                                       item->string,
-                                       exts[ext].name);
+                       char *fname;
+                       fname = mkpathdup("%s/old-%s%s",
+                                         packdir,
+                                         item->string,
+                                         exts[ext].name);
                        if (remove_path(fname))
                                warning(_("removing '%s' failed"), fname);
+                       free(fname);
                }
        }
 
index 4c08ddc..c503e75 100644 (file)
@@ -36,7 +36,7 @@ static const char *reset_type_names[] = {
 
 static inline int is_merge(void)
 {
-       return !access(git_path("MERGE_HEAD"), F_OK);
+       return !access(git_path_merge_head(), F_OK);
 }
 
 static int reset_index(const unsigned char *sha1, int reset_type, int quiet)
index c0b4b53..d80d1ed 100644 (file)
@@ -350,6 +350,9 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
            revs.diff)
                usage(rev_list_usage);
 
+       if (revs.show_notes)
+               die(_("rev-list does not support display of notes"));
+
        save_commit_buffer = (revs.verbose_header ||
                              revs.grep_filter.pattern_list ||
                              revs.grep_filter.header_list);
index b961e5a..23b2962 100644 (file)
@@ -11,6 +11,7 @@
 #include "transport.h"
 #include "version.h"
 #include "sha1-array.h"
+#include "gpg-interface.h"
 
 static const char send_pack_usage[] =
 "git send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [--atomic] [<host>:]<directory> [<ref>...]\n"
@@ -113,6 +114,8 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
        int from_stdin = 0;
        struct push_cas_option cas = {0};
 
+       git_config(git_gpg_config, NULL);
+
        argv++;
        for (i = 1; i < argc; i++, argv++) {
                const char *arg = *argv;
index 5f6cdc5..cccca99 100644 (file)
@@ -579,6 +579,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
        struct create_tag_options opt;
        char *cleanup_arg = NULL;
        int annotate = 0, force = 0, lines = -1;
+       int create_reflog = 0;
        int cmdmode = 0;
        const char *msgfile = NULL, *keyid = NULL;
        struct msg_arg msg = { 0, STRBUF_INIT };
@@ -605,6 +606,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
                OPT_STRING('u', "local-user", &keyid, N_("key-id"),
                                        N_("use another key to sign the tag")),
                OPT__FORCE(&force, N_("replace the tag if exists")),
+               OPT_BOOL(0, "create-reflog", &create_reflog, N_("create_reflog")),
 
                OPT_GROUP(N_("Tag listing options")),
                OPT_COLUMN(0, "column", &colopts, N_("show tag list in columns")),
@@ -733,7 +735,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
        transaction = ref_transaction_begin(&err);
        if (!transaction ||
            ref_transaction_update(transaction, ref.buf, object, prev,
-                                  0, NULL, &err) ||
+                                  create_reflog ? REF_FORCE_CREATE_REFLOG : 0,
+                                  NULL, &err) ||
            ref_transaction_commit(transaction, &err))
                die("%s", err.buf);
        ref_transaction_free(transaction);
index 6763cf1..04dd00f 100644 (file)
@@ -14,6 +14,7 @@ static const char * const git_update_ref_usage[] = {
 
 static char line_termination = '\n';
 static int update_flags;
+static unsigned create_reflog_flag;
 static const char *msg;
 
 /*
@@ -200,7 +201,8 @@ static const char *parse_cmd_update(struct ref_transaction *transaction,
 
        if (ref_transaction_update(transaction, refname,
                                   new_sha1, have_old ? old_sha1 : NULL,
-                                  update_flags, msg, &err))
+                                  update_flags | create_reflog_flag,
+                                  msg, &err))
                die("%s", err.buf);
 
        update_flags = 0;
@@ -231,7 +233,8 @@ static const char *parse_cmd_create(struct ref_transaction *transaction,
                die("create %s: extra input: %s", refname, next);
 
        if (ref_transaction_create(transaction, refname, new_sha1,
-                                  update_flags, msg, &err))
+                                  update_flags | create_reflog_flag,
+                                  msg, &err))
                die("%s", err.buf);
 
        update_flags = 0;
@@ -354,6 +357,7 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
        unsigned char sha1[20], oldsha1[20];
        int delete = 0, no_deref = 0, read_stdin = 0, end_null = 0;
        unsigned int flags = 0;
+       int create_reflog = 0;
        struct option options[] = {
                OPT_STRING( 'm', NULL, &msg, N_("reason"), N_("reason of the update")),
                OPT_BOOL('d', NULL, &delete, N_("delete the reference")),
@@ -361,6 +365,7 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
                                        N_("update <refname> not the one it points to")),
                OPT_BOOL('z', NULL, &end_null, N_("stdin has NUL-terminated arguments")),
                OPT_BOOL( 0 , "stdin", &read_stdin, N_("read updates from stdin")),
+               OPT_BOOL( 0 , "create-reflog", &create_reflog, N_("create_reflog")),
                OPT_END(),
        };
 
@@ -370,6 +375,8 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
        if (msg && !*msg)
                die("Refusing to perform update with empty message.");
 
+       create_reflog_flag = create_reflog ? REF_FORCE_CREATE_REFLOG : 0;
+
        if (read_stdin) {
                struct strbuf err = STRBUF_INIT;
                struct ref_transaction *transaction;
@@ -431,5 +438,6 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
                                  flags);
        else
                return update_ref(msg, refname, sha1, oldval ? oldsha1 : NULL,
-                                 flags, UPDATE_REFS_DIE_ON_ERR);
+                                 flags | create_reflog_flag,
+                                 UPDATE_REFS_DIE_ON_ERR);
 }
index bbb169a..71bb770 100644 (file)
@@ -3,6 +3,8 @@
 #include "dir.h"
 #include "parse-options.h"
 #include "argv-array.h"
+#include "branch.h"
+#include "refs.h"
 #include "run-command.h"
 #include "sigchain.h"
 #include "refs.h"
@@ -13,6 +15,13 @@ static const char * const worktree_usage[] = {
        NULL
 };
 
+struct add_opts {
+       int force;
+       int detach;
+       const char *new_branch;
+       int force_new_branch;
+};
+
 static int show_only;
 static int verbose;
 static unsigned long expire;
@@ -172,19 +181,35 @@ static const char *worktree_basename(const char *path, int *olen)
        return name;
 }
 
-static int add_worktree(const char *path, const char **child_argv)
+static int add_worktree(const char *path, const char *refname,
+                       const struct add_opts *opts)
 {
        struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;
        struct strbuf sb = STRBUF_INIT;
        const char *name;
        struct stat st;
        struct child_process cp;
+       struct argv_array child_env = ARGV_ARRAY_INIT;
        int counter = 0, len, ret;
-       unsigned char rev[20];
+       struct strbuf symref = STRBUF_INIT;
+       struct commit *commit = NULL;
 
        if (file_exists(path) && !is_empty_dir(path))
                die(_("'%s' already exists"), path);
 
+       /* is 'refname' a branch or commit? */
+       if (opts->force_new_branch) /* definitely a branch */
+               ;
+       else if (!opts->detach && !strbuf_check_branch_ref(&symref, refname) &&
+                ref_exists(symref.buf)) { /* it's a branch */
+               if (!opts->force)
+                       die_if_checked_out(symref.buf);
+       } else { /* must be a commit */
+               commit = lookup_commit_reference_by_name(refname);
+               if (!commit)
+                       die(_("invalid reference: %s"), refname);
+       }
+
        name = worktree_basename(path, &len);
        strbuf_addstr(&sb_repo,
                      git_path("worktrees/%.*s", (int)(path + len - name), name));
@@ -228,32 +253,40 @@ static int add_worktree(const char *path, const char **child_argv)
                   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. Moreover, HEAD
-        * in the new worktree must resolve to the same value as HEAD in
-        * the current tree since the command invoked to populate the new
-        * worktree will be handed the branch/ref specified by the user.
-        * For instance, if the user asks for the new worktree to be based
-        * at HEAD~5, then the resolved HEAD~5 in the new worktree must
-        * match the resolved HEAD~5 in the current tree in order to match
-        * the user's expectation.
+        * or is_git_directory() will reject the directory. Any value which
+        * looks like an object ID will do since it will be immediately
+        * replaced by the symbolic-ref or update-ref invocation in the new
+        * worktree.
         */
-       if (!resolve_ref_unsafe("HEAD", 0, rev, NULL))
-               die(_("unable to resolve HEAD"));
        strbuf_reset(&sb);
        strbuf_addf(&sb, "%s/HEAD", sb_repo.buf);
-       write_file(sb.buf, "%s", sha1_to_hex(rev));
+       write_file(sb.buf, "0000000000000000000000000000000000000000");
        strbuf_reset(&sb);
        strbuf_addf(&sb, "%s/commondir", sb_repo.buf);
        write_file(sb.buf, "../..");
 
-       fprintf_ln(stderr, _("Enter %s (identifier %s)"), path, name);
+       fprintf_ln(stderr, _("Preparing %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);
+       argv_array_pushf(&child_env, "%s=%s", GIT_DIR_ENVIRONMENT, sb_git.buf);
+       argv_array_pushf(&child_env, "%s=%s", GIT_WORK_TREE_ENVIRONMENT, path);
        memset(&cp, 0, sizeof(cp));
        cp.git_cmd = 1;
-       cp.argv = child_argv;
+
+       if (commit)
+               argv_array_pushl(&cp.args, "update-ref", "HEAD",
+                                sha1_to_hex(commit->object.sha1), NULL);
+       else
+               argv_array_pushl(&cp.args, "symbolic-ref", "HEAD",
+                                symref.buf, NULL);
+       cp.env = child_env.argv;
+       ret = run_command(&cp);
+       if (ret)
+               goto done;
+
+       cp.argv = NULL;
+       argv_array_clear(&cp.args);
+       argv_array_pushl(&cp.args, "reset", "--hard", NULL);
+       cp.env = child_env.argv;
        ret = run_command(&cp);
        if (!ret) {
                is_junk = 0;
@@ -262,10 +295,13 @@ static int add_worktree(const char *path, const char **child_argv)
                junk_work_tree = NULL;
                junk_git_dir = NULL;
        }
+done:
        strbuf_reset(&sb);
        strbuf_addf(&sb, "%s/locked", sb_repo.buf);
        unlink_or_warn(sb.buf);
+       argv_array_clear(&child_env);
        strbuf_release(&sb);
+       strbuf_release(&symref);
        strbuf_release(&sb_repo);
        strbuf_release(&sb_git);
        return ret;
@@ -273,47 +309,54 @@ static int add_worktree(const char *path, const char **child_argv)
 
 static int add(int ac, const char **av, const char *prefix)
 {
-       int force = 0, detach = 0;
-       const char *new_branch = NULL, *new_branch_force = NULL;
+       struct add_opts opts;
+       const char *new_branch_force = NULL;
        const char *path, *branch;
-       struct argv_array cmd = ARGV_ARRAY_INIT;
        struct option options[] = {
-               OPT__FORCE(&force, N_("checkout <branch> even if already checked out in other worktree")),
-               OPT_STRING('b', NULL, &new_branch, N_("branch"),
+               OPT__FORCE(&opts.force, N_("checkout <branch> even if already checked out in other worktree")),
+               OPT_STRING('b', NULL, &opts.new_branch, N_("branch"),
                           N_("create a new branch")),
                OPT_STRING('B', NULL, &new_branch_force, N_("branch"),
                           N_("create or reset a branch")),
-               OPT_BOOL(0, "detach", &detach, N_("detach HEAD at named commit")),
+               OPT_BOOL(0, "detach", &opts.detach, N_("detach HEAD at named commit")),
                OPT_END()
        };
 
+       memset(&opts, 0, sizeof(opts));
        ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
-       if (new_branch && new_branch_force)
-               die(_("-b and -B are mutually exclusive"));
+       if (!!opts.detach + !!opts.new_branch + !!new_branch_force > 1)
+               die(_("-b, -B, and --detach are mutually exclusive"));
        if (ac < 1 || ac > 2)
                usage_with_options(worktree_usage, options);
 
        path = prefix ? prefix_filename(prefix, strlen(prefix), av[0]) : av[0];
        branch = ac < 2 ? "HEAD" : av[1];
 
-       if (ac < 2 && !new_branch && !new_branch_force) {
+       opts.force_new_branch = !!new_branch_force;
+       if (opts.force_new_branch)
+               opts.new_branch = new_branch_force;
+
+       if (ac < 2 && !opts.new_branch && !opts.detach) {
                int n;
                const char *s = worktree_basename(path, &n);
-               new_branch = xstrndup(s, n);
+               opts.new_branch = xstrndup(s, n);
+       }
+
+       if (opts.new_branch) {
+               struct child_process cp;
+               memset(&cp, 0, sizeof(cp));
+               cp.git_cmd = 1;
+               argv_array_push(&cp.args, "branch");
+               if (opts.force_new_branch)
+                       argv_array_push(&cp.args, "--force");
+               argv_array_push(&cp.args, opts.new_branch);
+               argv_array_push(&cp.args, branch);
+               if (run_command(&cp))
+                       return -1;
+               branch = opts.new_branch;
        }
 
-       argv_array_push(&cmd, "checkout");
-       if (force)
-               argv_array_push(&cmd, "--ignore-other-worktrees");
-       if (new_branch)
-               argv_array_pushl(&cmd, "-b", new_branch, NULL);
-       if (new_branch_force)
-               argv_array_pushl(&cmd, "-B", new_branch_force, NULL);
-       if (detach)
-               argv_array_push(&cmd, "--detach");
-       argv_array_push(&cmd, branch);
-
-       return add_worktree(path, cmd.argv);
+       return add_worktree(path, branch, &opts);
 }
 
 int cmd_worktree(int ac, const char **av, const char *prefix)
index f732c92..b9dacc0 100644 (file)
--- a/bundle.c
+++ b/bundle.c
@@ -235,7 +235,9 @@ out:
        return result;
 }
 
-static int write_pack_data(int bundle_fd, struct lock_file *lock, struct rev_info *revs)
+
+/* Write the pack data to bundle_fd, then close it if it is > 1. */
+static int write_pack_data(int bundle_fd, struct rev_info *revs)
 {
        struct child_process pack_objects = CHILD_PROCESS_INIT;
        int i;
@@ -250,13 +252,6 @@ static int write_pack_data(int bundle_fd, struct lock_file *lock, struct rev_inf
        if (start_command(&pack_objects))
                return error(_("Could not spawn pack-objects"));
 
-       /*
-        * start_command closed bundle_fd if it was > 1
-        * so set the lock fd to -1 so commit_lock_file()
-        * won't fail trying to close it.
-        */
-       lock->fd = -1;
-
        for (i = 0; i < revs->pending.nr; i++) {
                struct object *object = revs->pending.objects[i].item;
                if (object->flags & UNINTERESTING)
@@ -416,10 +411,21 @@ int create_bundle(struct bundle_header *header, const char *path,
        bundle_to_stdout = !strcmp(path, "-");
        if (bundle_to_stdout)
                bundle_fd = 1;
-       else
+       else {
                bundle_fd = hold_lock_file_for_update(&lock, path,
                                                      LOCK_DIE_ON_ERROR);
 
+               /*
+                * write_pack_data() will close the fd passed to it,
+                * but commit_lock_file() will also try to close the
+                * lockfile's fd. So make a copy of the file
+                * descriptor to avoid trying to close it twice.
+                */
+               bundle_fd = dup(bundle_fd);
+               if (bundle_fd < 0)
+                       die_errno("unable to dup file descriptor");
+       }
+
        /* write signature */
        write_or_die(bundle_fd, bundle_signature, strlen(bundle_signature));
 
@@ -445,7 +451,7 @@ int create_bundle(struct bundle_header *header, const char *path,
                return -1;
 
        /* write pack */
-       if (write_pack_data(bundle_fd, &lock, &revs))
+       if (write_pack_data(bundle_fd, &revs))
                return -1;
 
        if (!bundle_to_stdout) {
diff --git a/cache.h b/cache.h
index 3f79e6b..e5a6b7f 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -708,22 +708,59 @@ extern int check_repository_format(void);
 #define DATA_CHANGED    0x0020
 #define TYPE_CHANGED    0x0040
 
+/*
+ * Return a statically allocated filename, either generically (mkpath), in
+ * the repository directory (git_path), or in a submodule's repository
+ * directory (git_path_submodule). In all cases, note that the result
+ * may be overwritten by another call to _any_ of the functions. Consider
+ * using the safer "dup" or "strbuf" formats below (in some cases, the
+ * unsafe versions have already been removed).
+ */
+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 char *mksnpath(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 void strbuf_git_path_submodule(struct strbuf *sb, const char *path,
+                                     const char *fmt, ...)
+       __attribute__((format (printf, 3, 4)));
 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 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, ...)
+extern char *git_pathdup_submodule(const char *path, const char *fmt, ...)
        __attribute__((format (printf, 2, 3)));
+
 extern void report_linked_checkout_garbage(void);
 
+/*
+ * You can define a static memoized git path like:
+ *
+ *    static GIT_PATH_FUNC(git_path_foo, "FOO");
+ *
+ * or use one of the global ones below.
+ */
+#define GIT_PATH_FUNC(func, filename) \
+       const char *func(void) \
+       { \
+               static char *ret; \
+               if (!ret) \
+                       ret = git_pathdup(filename); \
+               return ret; \
+       }
+
+const char *git_path_cherry_pick_head(void);
+const char *git_path_revert_head(void);
+const char *git_path_squash_msg(void);
+const char *git_path_merge_msg(void);
+const char *git_path_merge_rr(void);
+const char *git_path_merge_mode(void);
+const char *git_path_merge_head(void);
+const char *git_path_fetch_head(void);
+const char *git_path_shallow(void);
+
 /*
  * Return the name of the file in the local object database that would
  * be used to store a loose object with the specified sha1.  The
@@ -945,7 +982,7 @@ extern int do_check_packed_object_crc;
 
 extern int check_sha1_signature(const unsigned char *sha1, void *buf, unsigned long size, const char *type);
 
-extern int move_temp_to_file(const char *tmpfile, const char *filename);
+extern int finalize_object_file(const char *tmpfile, const char *filename);
 
 extern int has_sha1_pack(const unsigned char *sha1);
 
@@ -1403,6 +1440,7 @@ extern int git_config_pathname(const char **, const char *, const char *);
 extern int git_config_set_in_file(const char *, const char *, const char *);
 extern int git_config_set(const char *, const char *);
 extern int git_config_parse_key(const char *, char **, int *);
+extern int git_config_key_is_valid(const char *key);
 extern int git_config_set_multivar(const char *, const char *, const char *, int);
 extern int git_config_set_multivar_in_file(const char *, const char *, const char *, const char *, int);
 extern int git_config_rename_section(const char *, const char *);
index 496e6f8..f74da23 100644 (file)
@@ -681,7 +681,7 @@ int pipe(int filedes[2])
                return -1;
        }
        filedes[1] = _open_osfhandle((int)h[1], O_NOINHERIT);
-       if (filedes[0] < 0) {
+       if (filedes[1] < 0) {
                close(filedes[0]);
                CloseHandle(h[1]);
                return -1;
index 9fd275f..6c8d91a 100644 (file)
--- a/config.c
+++ b/config.c
@@ -1848,7 +1848,7 @@ int git_config_set(const char *key, const char *value)
  * baselen - pointer to int which will hold the length of the
  *           section + subsection part, can be NULL
  */
-int git_config_parse_key(const char *key, char **store_key, int *baselen_)
+static int git_config_parse_key_1(const char *key, char **store_key, int *baselen_, int quiet)
 {
        int i, dot, baselen;
        const char *last_dot = strrchr(key, '.');
@@ -1859,12 +1859,14 @@ int git_config_parse_key(const char *key, char **store_key, int *baselen_)
         */
 
        if (last_dot == NULL || last_dot == key) {
-               error("key does not contain a section: %s", key);
+               if (!quiet)
+                       error("key does not contain a section: %s", key);
                return -CONFIG_NO_SECTION_OR_NAME;
        }
 
        if (!last_dot[1]) {
-               error("key does not contain variable name: %s", key);
+               if (!quiet)
+                       error("key does not contain variable name: %s", key);
                return -CONFIG_NO_SECTION_OR_NAME;
        }
 
@@ -1875,7 +1877,8 @@ int git_config_parse_key(const char *key, char **store_key, int *baselen_)
        /*
         * Validate the key and while at it, lower case it for matching.
         */
-       *store_key = xmalloc(strlen(key) + 1);
+       if (store_key)
+               *store_key = xmalloc(strlen(key) + 1);
 
        dot = 0;
        for (i = 0; key[i]; i++) {
@@ -1886,26 +1889,42 @@ int git_config_parse_key(const char *key, char **store_key, int *baselen_)
                if (!dot || i > baselen) {
                        if (!iskeychar(c) ||
                            (i == baselen + 1 && !isalpha(c))) {
-                               error("invalid key: %s", key);
+                               if (!quiet)
+                                       error("invalid key: %s", key);
                                goto out_free_ret_1;
                        }
                        c = tolower(c);
                } else if (c == '\n') {
-                       error("invalid key (newline): %s", key);
+                       if (!quiet)
+                               error("invalid key (newline): %s", key);
                        goto out_free_ret_1;
                }
-               (*store_key)[i] = c;
+               if (store_key)
+                       (*store_key)[i] = c;
        }
-       (*store_key)[i] = 0;
+       if (store_key)
+               (*store_key)[i] = 0;
 
        return 0;
 
 out_free_ret_1:
-       free(*store_key);
-       *store_key = NULL;
+       if (store_key) {
+               free(*store_key);
+               *store_key = NULL;
+       }
        return -CONFIG_INVALID_KEY;
 }
 
+int git_config_parse_key(const char *key, char **store_key, int *baselen)
+{
+       return git_config_parse_key_1(key, store_key, baselen, 0);
+}
+
+int git_config_key_is_valid(const char *key)
+{
+       return !git_config_parse_key_1(key, NULL, NULL, 1);
+}
+
 /*
  * If value==NULL, unset in (remove from) config,
  * if value_regex!=NULL, disregard key/value pairs where value does not match.
@@ -1935,7 +1954,7 @@ int git_config_set_multivar_in_file(const char *config_filename,
                                const char *key, const char *value,
                                const char *value_regex, int multi_replace)
 {
-       int fd = -1, in_fd;
+       int fd = -1, in_fd = -1;
        int ret;
        struct lock_file *lock = NULL;
        char *filename_buf = NULL;
@@ -2065,10 +2084,11 @@ int git_config_set_multivar_in_file(const char *config_filename,
                        goto out_free;
                }
                close(in_fd);
+               in_fd = -1;
 
-               if (chmod(lock->filename.buf, st.st_mode & 07777) < 0) {
+               if (chmod(get_lock_file_path(lock), st.st_mode & 07777) < 0) {
                        error("chmod on %s failed: %s",
-                               lock->filename.buf, strerror(errno));
+                             get_lock_file_path(lock), strerror(errno));
                        ret = CONFIG_NO_WRITE;
                        goto out_free;
                }
@@ -2148,10 +2168,12 @@ out_free:
        free(filename_buf);
        if (contents)
                munmap(contents, contents_sz);
+       if (in_fd >= 0)
+               close(in_fd);
        return ret;
 
 write_err_out:
-       ret = write_error(lock->filename.buf);
+       ret = write_error(get_lock_file_path(lock));
        goto out_free;
 
 }
@@ -2252,9 +2274,9 @@ int git_config_rename_section_in_file(const char *config_filename,
 
        fstat(fileno(config_file), &st);
 
-       if (chmod(lock->filename.buf, st.st_mode & 07777) < 0) {
+       if (chmod(get_lock_file_path(lock), st.st_mode & 07777) < 0) {
                ret = error("chmod on %s failed: %s",
-                               lock->filename.buf, strerror(errno));
+                           get_lock_file_path(lock), strerror(errno));
                goto out;
        }
 
@@ -2275,7 +2297,7 @@ int git_config_rename_section_in_file(const char *config_filename,
                                }
                                store.baselen = strlen(new_name);
                                if (!store_write_section(out_fd, new_name)) {
-                                       ret = write_error(lock->filename.buf);
+                                       ret = write_error(get_lock_file_path(lock));
                                        goto out;
                                }
                                /*
@@ -2301,7 +2323,7 @@ int git_config_rename_section_in_file(const char *config_filename,
                        continue;
                length = strlen(output);
                if (write_in_full(out_fd, output, length) != length) {
-                       ret = write_error(lock->filename.buf);
+                       ret = write_error(get_lock_file_path(lock));
                        goto out;
                }
        }
index c97c648..482ca84 100644 (file)
@@ -744,9 +744,8 @@ __git_compute_porcelain_commands ()
 __git_get_config_variables ()
 {
        local section="$1" i IFS=$'\n'
-       for i in $(git --git-dir="$(__gitdir)" config --get-regexp "^$section\..*" 2>/dev/null); do
-               i="${i#$section.}"
-               echo "${i/ */}"
+       for i in $(git --git-dir="$(__gitdir)" config --name-only --get-regexp "^$section\..*" 2>/dev/null); do
+               echo "${i#$section.}"
        done
 }
 
@@ -1667,7 +1666,10 @@ _git_push ()
 _git_rebase ()
 {
        local dir="$(__gitdir)"
-       if [ -d "$dir"/rebase-apply ] || [ -d "$dir"/rebase-merge ]; then
+       if [ -f "$dir"/rebase-merge/interactive ]; then
+               __gitcomp "--continue --skip --abort --edit-todo"
+               return
+       elif [ -d "$dir"/rebase-apply ] || [ -d "$dir"/rebase-merge ]; then
                __gitcomp "--continue --skip --abort"
                return
        fi
@@ -1774,15 +1776,7 @@ __git_config_get_set_variables ()
                c=$((--c))
        done
 
-       git --git-dir="$(__gitdir)" config $config_file --list 2>/dev/null |
-       while read -r line
-       do
-               case "$line" in
-               *.*=*)
-                       echo "${line/=*/}"
-                       ;;
-               esac
-       done
+       git --git-dir="$(__gitdir)" config $config_file --name-only --list 2>/dev/null
 }
 
 _git_config ()
@@ -1887,6 +1881,7 @@ _git_config ()
                        --get --get-all --get-regexp
                        --add --unset --unset-all
                        --remove-section --rename-section
+                       --name-only
                        "
                return
                ;;
@@ -2118,6 +2113,7 @@ _git_config ()
                http.postBuffer
                http.proxy
                http.sslCipherList
+               http.sslVersion
                http.sslCAInfo
                http.sslCAPath
                http.sslCert
index ee19166..a3eb19d 100644 (file)
@@ -516,7 +516,7 @@ int cmd_fetch__tool(int argc, const char **argv, const char *prefix)
 
                if (argc != 8)
                        return error("append-fetch-head takes 6 args");
-               filename = git_path("FETCH_HEAD");
+               filename = git_path_fetch_head();
                fp = fopen(filename, "a");
                if (!fp)
                        return error("cannot open %s: %s", filename, strerror(errno));
@@ -534,7 +534,7 @@ int cmd_fetch__tool(int argc, const char **argv, const char *prefix)
 
                if (argc != 5)
                        return error("fetch-native-store takes 3 args");
-               filename = git_path("FETCH_HEAD");
+               filename = git_path_fetch_head();
                fp = fopen(filename, "a");
                if (!fp)
                        return error("cannot open %s: %s", filename, strerror(errno));
index a814bf6..e8dc2e0 100755 (executable)
@@ -295,7 +295,7 @@ test true = "$rebase" && {
 }
 orig_head=$(git rev-parse -q --verify HEAD)
 git fetch $verbosity $progress $dry_run $recurse_submodules $all $append \
-$upload_pack $force $tags $prune $keep $depth $unshallow $update_shallow \
+${upload_pack:+"$upload_pack"} $force $tags $prune $keep $depth $unshallow $update_shallow \
 $refmap --update-head-ok "$@" || exit 1
 test -z "$dry_run" || exit 0
 
index 07bd77c..9f06571 100755 (executable)
@@ -305,7 +305,7 @@ copy_commit()
        # We're going to set some environment vars here, so
        # do it in a subshell to get rid of them safely later
        debug copy_commit "{$1}" "{$2}" "{$3}"
-       git log -1 --pretty=format:'%an%n%ae%n%ad%n%cn%n%ce%n%cd%n%B' "$1" |
+       git log -1 --pretty=format:'%an%n%ae%n%aD%n%cn%n%ce%n%cD%n%B' "$1" |
        (
                read GIT_AUTHOR_NAME
                read GIT_AUTHOR_EMAIL
index bd3df97..9051982 100755 (executable)
@@ -94,6 +94,10 @@ test_expect_success 'add sub3' '
 # Back to mainline
 cd ..
 
+test_expect_success 'enable log.date=relative to catch errors' '
+       git config log.date relative
+'
+
 test_expect_success 'add main4' '
        create main4 &&
        git commit -m "main4" &&
index c2f0049..eef6fce 100644 (file)
@@ -1,23 +1,11 @@
 #include "cache.h"
+#include "tempfile.h"
 #include "credential.h"
 #include "unix-socket.h"
 #include "sigchain.h"
 #include "parse-options.h"
 
-static const char *socket_path;
-
-static void cleanup_socket(void)
-{
-       if (socket_path)
-               unlink(socket_path);
-}
-
-static void cleanup_socket_on_signal(int sig)
-{
-       cleanup_socket();
-       sigchain_pop(sig);
-       raise(sig);
-}
+static struct tempfile socket_file;
 
 struct credential_cache_entry {
        struct credential item;
@@ -221,7 +209,6 @@ static void serve_cache(const char *socket_path, int debug)
                ; /* nothing */
 
        close(fd);
-       unlink(socket_path);
 }
 
 static const char permissions_advice[] =
@@ -257,6 +244,7 @@ static void check_socket_directory(const char *path)
 
 int main(int argc, const char **argv)
 {
+       const char *socket_path;
        static const char *usage[] = {
                "git-credential-cache--daemon [opts] <socket_path>",
                NULL
@@ -273,12 +261,11 @@ int main(int argc, const char **argv)
 
        if (!socket_path)
                usage_with_options(usage, options);
-       check_socket_directory(socket_path);
-
-       atexit(cleanup_socket);
-       sigchain_push_common(cleanup_socket_on_signal);
 
+       check_socket_directory(socket_path);
+       register_tempfile(&socket_file, socket_path);
        serve_cache(socket_path, debug);
+       delete_tempfile(&socket_file);
 
        return 0;
 }
index f692509..00aea3a 100644 (file)
@@ -52,7 +52,7 @@ static void print_entry(struct credential *c)
 static void print_line(struct strbuf *buf)
 {
        strbuf_addch(buf, '\n');
-       write_or_die(credential_lock.fd, buf->buf, buf->len);
+       write_or_die(get_lock_file_fd(&credential_lock), buf->buf, buf->len);
 }
 
 static void rewrite_credential_file(const char *fn, struct credential *c,
diff --git a/diff.c b/diff.c
index 7deac90..08508f6 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -2,6 +2,7 @@
  * Copyright (C) 2005 Junio C Hamano
  */
 #include "cache.h"
+#include "tempfile.h"
 #include "quote.h"
 #include "diff.h"
 #include "diffcore.h"
@@ -13,6 +14,7 @@
 #include "utf8.h"
 #include "userdiff.h"
 #include "sigchain.h"
+#include "submodule-config.h"
 #include "submodule.h"
 #include "ll-merge.h"
 #include "string-list.h"
@@ -308,11 +310,26 @@ static const char *external_diff(void)
        return external_diff_cmd;
 }
 
+/*
+ * Keep track of files used for diffing. Sometimes such an entry
+ * refers to a temporary file, sometimes to an existing file, and
+ * sometimes to "/dev/null".
+ */
 static struct diff_tempfile {
-       const char *name; /* filename external diff should read from */
+       /*
+        * filename external diff should read from, or NULL if this
+        * entry is currently not in use:
+        */
+       const char *name;
+
        char hex[41];
        char mode[10];
-       char tmp_path[PATH_MAX];
+
+       /*
+        * If this diff_tempfile instance refers to a temporary file,
+        * this tempfile object is used to manage its lifetime.
+        */
+       struct tempfile tempfile;
 } diff_temp[2];
 
 typedef unsigned long (*sane_truncate_fn)(char *line, unsigned long len);
@@ -597,25 +614,16 @@ static struct diff_tempfile *claim_diff_tempfile(void) {
        die("BUG: diff is failing to clean up its tempfiles");
 }
 
-static int remove_tempfile_installed;
-
 static void remove_tempfile(void)
 {
        int i;
        for (i = 0; i < ARRAY_SIZE(diff_temp); i++) {
-               if (diff_temp[i].name == diff_temp[i].tmp_path)
-                       unlink_or_warn(diff_temp[i].name);
+               if (is_tempfile_active(&diff_temp[i].tempfile))
+                       delete_tempfile(&diff_temp[i].tempfile);
                diff_temp[i].name = NULL;
        }
 }
 
-static void remove_tempfile_on_signal(int signo)
-{
-       remove_tempfile();
-       sigchain_pop(signo);
-       raise(signo);
-}
-
 static void print_line_count(FILE *file, int count)
 {
        switch (count) {
@@ -2858,8 +2866,7 @@ static void prep_temp_blob(const char *path, struct diff_tempfile *temp,
        strbuf_addstr(&template, "XXXXXX_");
        strbuf_addstr(&template, base);
 
-       fd = git_mkstemps(temp->tmp_path, PATH_MAX, template.buf,
-                       strlen(base) + 1);
+       fd = mks_tempfile_ts(&temp->tempfile, template.buf, strlen(base) + 1);
        if (fd < 0)
                die_errno("unable to create temp-file");
        if (convert_to_working_tree(path,
@@ -2869,8 +2876,8 @@ static void prep_temp_blob(const char *path, struct diff_tempfile *temp,
        }
        if (write_in_full(fd, blob, size) != size)
                die_errno("unable to write temp-file");
-       close(fd);
-       temp->name = temp->tmp_path;
+       close_tempfile(&temp->tempfile);
+       temp->name = get_tempfile_path(&temp->tempfile);
        strcpy(temp->hex, sha1_to_hex(sha1));
        temp->hex[40] = 0;
        sprintf(temp->mode, "%06o", mode);
@@ -2895,12 +2902,6 @@ static struct diff_tempfile *prepare_temp_file(const char *name,
                return temp;
        }
 
-       if (!remove_tempfile_installed) {
-               atexit(remove_tempfile);
-               sigchain_push_common(remove_tempfile_on_signal);
-               remove_tempfile_installed = 1;
-       }
-
        if (!S_ISGITLINK(one->mode) &&
            (!one->sha1_valid ||
             reuse_worktree_file(name, one->sha1, 1))) {
diff --git a/dir.c b/dir.c
index 1d42811..7b25634 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -1078,10 +1078,9 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
                    (!untracked || !untracked->valid ||
                     /*
                      * .. and .gitignore does not exist before
-                     * (i.e. null exclude_sha1 and skip_worktree is
-                     * not set). Then we can skip loading .gitignore,
-                     * which would result in ENOENT anyway.
-                     * skip_worktree is taken care in read_directory()
+                     * (i.e. null exclude_sha1). Then we can skip
+                     * loading .gitignore, which would result in
+                     * ENOENT anyway.
                      */
                     !is_null_sha1(untracked->exclude_sha1))) {
                        /*
@@ -1298,7 +1297,7 @@ static enum exist_status directory_exists_in_index(const char *dirname, int len)
  */
 static enum path_treatment treat_directory(struct dir_struct *dir,
        struct untracked_cache_dir *untracked,
-       const char *dirname, int len, int exclude,
+       const char *dirname, int len, int baselen, int exclude,
        const struct path_simplify *simplify)
 {
        /* The "len-1" is to strip the final '/' */
@@ -1325,7 +1324,8 @@ static enum path_treatment treat_directory(struct dir_struct *dir,
        if (!(dir->flags & DIR_HIDE_EMPTY_DIRECTORIES))
                return exclude ? path_excluded : path_untracked;
 
-       untracked = lookup_untracked(dir->untracked, untracked, dirname, len);
+       untracked = lookup_untracked(dir->untracked, untracked,
+                                    dirname + baselen, len - baselen);
        return read_directory_recursive(dir, dirname, len,
                                        untracked, 1, simplify);
 }
@@ -1445,6 +1445,7 @@ static int get_dtype(struct dirent *de, const char *path, int len)
 static enum path_treatment treat_one_path(struct dir_struct *dir,
                                          struct untracked_cache_dir *untracked,
                                          struct strbuf *path,
+                                         int baselen,
                                          const struct path_simplify *simplify,
                                          int dtype, struct dirent *de)
 {
@@ -1496,8 +1497,8 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,
                return path_none;
        case DT_DIR:
                strbuf_addch(path, '/');
-               return treat_directory(dir, untracked, path->buf, path->len, exclude,
-                       simplify);
+               return treat_directory(dir, untracked, path->buf, path->len,
+                                      baselen, exclude, simplify);
        case DT_REG:
        case DT_LNK:
                return exclude ? path_excluded : path_untracked;
@@ -1558,7 +1559,7 @@ static enum path_treatment treat_path(struct dir_struct *dir,
                return path_none;
 
        dtype = DTYPE(de);
-       return treat_one_path(dir, untracked, path, simplify, dtype, de);
+       return treat_one_path(dir, untracked, path, baselen, simplify, dtype, de);
 }
 
 static void add_untracked(struct untracked_cache_dir *dir, const char *name)
@@ -1828,7 +1829,7 @@ static int treat_leading_path(struct dir_struct *dir,
                        break;
                if (simplify_away(sb.buf, sb.len, simplify))
                        break;
-               if (treat_one_path(dir, NULL, &sb, simplify,
+               if (treat_one_path(dir, NULL, &sb, baselen, simplify,
                                   DT_DIR, NULL) == path_none)
                        break; /* do not recurse into it */
                if (len <= baselen) {
@@ -1880,7 +1881,6 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d
                                                      const struct pathspec *pathspec)
 {
        struct untracked_cache_dir *root;
-       int i;
 
        if (!dir->untracked || getenv("GIT_DISABLE_UNTRACKED_CACHE"))
                return NULL;
@@ -1932,15 +1932,6 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d
        if (dir->exclude_list_group[EXC_CMDL].nr)
                return NULL;
 
-       /*
-        * An optimization in prep_exclude() does not play well with
-        * CE_SKIP_WORKTREE. It's a rare case anyway, if a single
-        * entry has that bit set, disable the whole untracked cache.
-        */
-       for (i = 0; i < active_nr; i++)
-               if (ce_skip_worktree(active_cache[i]))
-                       return NULL;
-
        if (!ident_in_untracked(dir->untracked)) {
                warning(_("Untracked cache is disabled on this system."));
                return NULL;
@@ -2185,6 +2176,8 @@ int remove_dir_recursively(struct strbuf *path, int flag)
        return remove_dir_recurse(path, flag, NULL);
 }
 
+static GIT_PATH_FUNC(git_path_info_exclude, "info/exclude")
+
 void setup_standard_excludes(struct dir_struct *dir)
 {
        const char *path;
@@ -2199,7 +2192,7 @@ void setup_standard_excludes(struct dir_struct *dir)
                                         dir->untracked ? &dir->ss_excludes_file : NULL);
 
        /* per repository user preference */
-       path = git_path("info/exclude");
+       path = git_path_info_exclude();
        if (!access_or_warn(path, R_OK, 0))
                add_excludes_from_file_1(dir, path,
                                         dir->untracked ? &dir->ss_info_exclude : NULL);
@@ -2625,23 +2618,67 @@ done2:
        return uc;
 }
 
+static void invalidate_one_directory(struct untracked_cache *uc,
+                                    struct untracked_cache_dir *ucd)
+{
+       uc->dir_invalidated++;
+       ucd->valid = 0;
+       ucd->untracked_nr = 0;
+}
+
+/*
+ * Normally when an entry is added or removed from a directory,
+ * invalidating that directory is enough. No need to touch its
+ * ancestors. When a directory is shown as "foo/bar/" in git-status
+ * however, deleting or adding an entry may have cascading effect.
+ *
+ * Say the "foo/bar/file" has become untracked, we need to tell the
+ * untracked_cache_dir of "foo" that "bar/" is not an untracked
+ * directory any more (because "bar" is managed by foo as an untracked
+ * "file").
+ *
+ * Similarly, if "foo/bar/file" moves from untracked to tracked and it
+ * was the last untracked entry in the entire "foo", we should show
+ * "foo/" instead. Which means we have to invalidate past "bar" up to
+ * "foo".
+ *
+ * This function traverses all directories from root to leaf. If there
+ * is a chance of one of the above cases happening, we invalidate back
+ * to root. Otherwise we just invalidate the leaf. There may be a more
+ * sophisticated way than checking for SHOW_OTHER_DIRECTORIES to
+ * detect these cases and avoid unnecessary invalidation, for example,
+ * checking for the untracked entry named "bar/" in "foo", but for now
+ * stick to something safe and simple.
+ */
+static int invalidate_one_component(struct untracked_cache *uc,
+                                   struct untracked_cache_dir *dir,
+                                   const char *path, int len)
+{
+       const char *rest = strchr(path, '/');
+
+       if (rest) {
+               int component_len = rest - path;
+               struct untracked_cache_dir *d =
+                       lookup_untracked(uc, dir, path, component_len);
+               int ret =
+                       invalidate_one_component(uc, d, rest + 1,
+                                                len - (component_len + 1));
+               if (ret)
+                       invalidate_one_directory(uc, dir);
+               return ret;
+       }
+
+       invalidate_one_directory(uc, dir);
+       return uc->dir_flags & DIR_SHOW_OTHER_DIRECTORIES;
+}
+
 void untracked_cache_invalidate_path(struct index_state *istate,
                                     const char *path)
 {
-       const char *sep;
-       struct untracked_cache_dir *d;
        if (!istate->untracked || !istate->untracked->root)
                return;
-       sep = strrchr(path, '/');
-       if (sep)
-               d = lookup_untracked(istate->untracked,
-                                    istate->untracked->root,
-                                    path, sep - path);
-       else
-               d = istate->untracked->root;
-       istate->untracked->dir_invalidated++;
-       d->valid = 0;
-       d->untracked_nr = 0;
+       invalidate_one_component(istate->untracked, istate->untracked->root,
+                                path, strlen(path));
 }
 
 void untracked_cache_remove_from_index(struct index_state *istate,
index 2ad4fee..6c7c3c9 100644 (file)
@@ -407,7 +407,7 @@ static void dump_marks_helper(FILE *, uintmax_t, struct mark_set *);
 
 static void write_crash_report(const char *err)
 {
-       const char *loc = git_path("fast_import_crash_%"PRIuMAX, (uintmax_t) getpid());
+       char *loc = git_pathdup("fast_import_crash_%"PRIuMAX, (uintmax_t) getpid());
        FILE *rpt = fopen(loc, "w");
        struct branch *b;
        unsigned long lu;
@@ -415,6 +415,7 @@ static void write_crash_report(const char *err)
 
        if (!rpt) {
                error("can't write crash report %s: %s", loc, strerror(errno));
+               free(loc);
                return;
        }
 
@@ -488,6 +489,7 @@ static void write_crash_report(const char *err)
        fputs("-------------------\n", rpt);
        fputs("END OF CRASH REPORT\n", rpt);
        fclose(rpt);
+       free(loc);
 }
 
 static void end_packfile(void);
@@ -923,12 +925,12 @@ static char *keep_pack(const char *curr_index_name)
 
        snprintf(name, sizeof(name), "%s/pack/pack-%s.pack",
                 get_object_directory(), sha1_to_hex(pack_data->sha1));
-       if (move_temp_to_file(pack_data->pack_name, name))
+       if (finalize_object_file(pack_data->pack_name, name))
                die("cannot store pack file");
 
        snprintf(name, sizeof(name), "%s/pack/pack-%s.idx",
                 get_object_directory(), sha1_to_hex(pack_data->sha1));
-       if (move_temp_to_file(curr_index_name, name))
+       if (finalize_object_file(curr_index_name, name))
                die("cannot store index file");
        free((void *)curr_index_name);
        return name;
index a136772..820251a 100644 (file)
@@ -948,7 +948,7 @@ static void update_shallow(struct fetch_pack_args *args,
 
        if (args->depth > 0 && alternate_shallow_file) {
                if (*alternate_shallow_file == '\0') { /* --unshallow */
-                       unlink_or_warn(git_path("shallow"));
+                       unlink_or_warn(git_path_shallow());
                        rollback_lock_file(&shallow_lock);
                } else
                        commit_lock_file(&shallow_lock);
diff --git a/generate-cmdlist.perl b/generate-cmdlist.perl
deleted file mode 100755 (executable)
index 31516e3..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/usr/bin/perl
-use strict;
-use warnings;
-
-print <<"EOT";
-/* Automatically generated by $0 */
-
-struct cmdname_help {
-       char name[16];
-       char help[80];
-       unsigned char group;
-};
-
-static char *common_cmd_groups[] = {
-EOT
-
-my $n = 0;
-my %grp;
-while (<>) {
-       last if /^### command list/;
-       next if (1../^### common groups/) || /^#/ || /^\s*$/;
-       chop;
-       my ($k, $v) = split ' ', $_, 2;
-       $grp{$k} = $n++;
-       print "\tN_(\"$v\"),\n";
-}
-
-print "};\n\nstatic struct cmdname_help common_cmds[] = {\n";
-
-while (<>) {
-       next if /^#/ || /^\s*$/;
-       my @tags = split;
-       my $cmd = shift @tags;
-       for my $t (@tags) {
-               if (exists $grp{$t}) {
-                       my $s;
-                       open my $f, '<', "Documentation/$cmd.txt" or die;
-                       while (<$f>) {
-                               ($s) = /^$cmd - (.+)$/;
-                               last if $s;
-                       }
-                       close $f;
-                       $cmd =~ s/^git-//;
-                       print "\t{\"$cmd\", N_(\"$s\"), $grp{$t}},\n";
-                       last;
-               }
-       }
-}
-
-print "};\n";
diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh
new file mode 100755 (executable)
index 0000000..ab0d1b0
--- /dev/null
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+echo "/* Automatically generated by $0 */
+struct cmdname_help {
+       char name[16];
+       char help[80];
+       unsigned char group;
+};
+
+static const char *common_cmd_groups[] = {"
+
+grps=grps$$.tmp
+match=match$$.tmp
+trap "rm -f '$grps' '$match'" 0 1 2 3 15
+
+sed -n '
+       1,/^### common groups/b
+       /^### command list/q
+       /^#/b
+       /^[     ]*$/b
+       h;s/^[^         ][^     ]*[     ][      ]*\(.*\)/       N_("\1"),/p
+       g;s/^\([^       ][^     ]*\)[   ].*/\1/w '$grps'
+       ' "$1"
+printf '};\n\n'
+
+n=0
+substnum=
+while read grp
+do
+       echo "^git-..*[         ]$grp"
+       substnum="$substnum${substnum:+;}s/[    ]$grp/$n/"
+       n=$(($n+1))
+done <"$grps" >"$match"
+
+printf 'static struct cmdname_help common_cmds[] = {\n'
+grep -f "$match" "$1" |
+sed 's/^git-//' |
+sort |
+while read cmd tags
+do
+       tag=$(echo "$tags" | sed "$substnum; s/[^0-9]//g")
+       sed -n '
+               /^NAME/,/git-'"$cmd"'/H
+               ${
+                       x
+                       s/.*git-'"$cmd"' - \(.*\)/      {"'"$cmd"'", N_("\1"), '$tag'},/
+                       p
+               }' "Documentation/git-$cmd.txt"
+done
+echo "};"
index ae3fec2..ea63223 100755 (executable)
@@ -32,6 +32,8 @@ OPTIONS_SPEC=
 
 _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
 _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
+TERM_BAD=bad
+TERM_GOOD=good
 
 bisect_head()
 {
@@ -75,6 +77,8 @@ bisect_start() {
        orig_args=$(git rev-parse --sq-quote "$@")
        bad_seen=0
        eval=''
+       must_write_terms=0
+       revs=''
        if test "z$(git rev-parse --is-bare-repository)" != zfalse
        then
                mode=--no-checkout
@@ -99,16 +103,27 @@ bisect_start() {
                                die "$(eval_gettext "'\$arg' does not appear to be a valid revision")"
                                break
                        }
-                       case $bad_seen in
-                       0) state='bad' ; bad_seen=1 ;;
-                       *) state='good' ;;
-                       esac
-                       eval="$eval bisect_write '$state' '$rev' 'nolog' &&"
+                       revs="$revs $rev"
                        shift
                        ;;
                esac
        done
 
+       for rev in $revs
+       do
+               # The user ran "git bisect start <sha1>
+               # <sha1>", hence did not explicitly specify
+               # the terms, but we are already starting to
+               # set references named with the default terms,
+               # and won't be able to change afterwards.
+               must_write_terms=1
+
+               case $bad_seen in
+               0) state=$TERM_BAD ; bad_seen=1 ;;
+               *) state=$TERM_GOOD ;;
+               esac
+               eval="$eval bisect_write '$state' '$rev' 'nolog' &&"
+       done
        #
        # Verify HEAD.
        #
@@ -170,6 +185,10 @@ bisect_start() {
        } &&
        git rev-parse --sq-quote "$@" >"$GIT_DIR/BISECT_NAMES" &&
        eval "$eval true" &&
+       if test $must_write_terms -eq 1
+       then
+               write_terms "$TERM_BAD" "$TERM_GOOD"
+       fi &&
        echo "git bisect start$orig_args" >>"$GIT_DIR/BISECT_LOG" || exit
        #
        # Check if we can proceed to the next bisect state.
@@ -184,9 +203,12 @@ bisect_write() {
        rev="$2"
        nolog="$3"
        case "$state" in
-               bad)            tag="$state" ;;
-               good|skip)      tag="$state"-"$rev" ;;
-               *)              die "$(eval_gettext "Bad bisect_write argument: \$state")" ;;
+               "$TERM_BAD")
+                       tag="$state" ;;
+               "$TERM_GOOD"|skip)
+                       tag="$state"-"$rev" ;;
+               *)
+                       die "$(eval_gettext "Bad bisect_write argument: \$state")" ;;
        esac
        git update-ref "refs/bisect/$tag" "$rev" || exit
        echo "# $state: $(git show-branch $rev)" >>"$GIT_DIR/BISECT_LOG"
@@ -227,15 +249,16 @@ bisect_skip() {
 bisect_state() {
        bisect_autostart
        state=$1
+       check_and_set_terms $state
        case "$#,$state" in
        0,*)
                die "$(gettext "Please call 'bisect_state' with at least one argument.")" ;;
-       1,bad|1,good|1,skip)
+       1,"$TERM_BAD"|1,"$TERM_GOOD"|1,skip)
                rev=$(git rev-parse --verify $(bisect_head)) ||
                        die "$(gettext "Bad rev input: $(bisect_head)")"
                bisect_write "$state" "$rev"
                check_expected_revs "$rev" ;;
-       2,bad|*,good|*,skip)
+       2,"$TERM_BAD"|*,"$TERM_GOOD"|*,skip)
                shift
                hash_list=''
                for rev in "$@"
@@ -249,8 +272,8 @@ bisect_state() {
                        bisect_write "$state" "$rev"
                done
                check_expected_revs $hash_list ;;
-       *,bad)
-               die "$(gettext "'git bisect bad' can take only one argument.")" ;;
+       *,"$TERM_BAD")
+               die "$(eval_gettext "'git bisect \$TERM_BAD' can take only one argument.")" ;;
        *)
                usage ;;
        esac
@@ -259,21 +282,21 @@ bisect_state() {
 
 bisect_next_check() {
        missing_good= missing_bad=
-       git show-ref -q --verify refs/bisect/bad || missing_bad=t
-       test -n "$(git for-each-ref "refs/bisect/good-*")" || missing_good=t
+       git show-ref -q --verify refs/bisect/$TERM_BAD || missing_bad=t
+       test -n "$(git for-each-ref "refs/bisect/$TERM_GOOD-*")" || missing_good=t
 
        case "$missing_good,$missing_bad,$1" in
        ,,*)
-               : have both good and bad - ok
+               : have both $TERM_GOOD and $TERM_BAD - ok
                ;;
        *,)
                # do not have both but not asked to fail - just report.
                false
                ;;
-       t,,good)
+       t,,"$TERM_GOOD")
                # have bad but not good.  we could bisect although
                # this is less optimum.
-               gettextln "Warning: bisecting only with a bad commit." >&2
+               eval_gettextln "Warning: bisecting only with a \$TERM_BAD commit." >&2
                if test -t 0
                then
                        # TRANSLATORS: Make sure to include [Y] and [n] in your
@@ -283,18 +306,20 @@ bisect_next_check() {
                        read yesno
                        case "$yesno" in [Nn]*) exit 1 ;; esac
                fi
-               : bisect without good...
+               : bisect without $TERM_GOOD...
                ;;
        *)
-
+               bad_syn=$(bisect_voc bad)
+               good_syn=$(bisect_voc good)
                if test -s "$GIT_DIR/BISECT_START"
                then
-                       gettextln "You need to give me at least one good and one bad revision.
-(You can use \"git bisect bad\" and \"git bisect good\" for that.)" >&2
+
+                       eval_gettextln "You need to give me at least one \$bad_syn and one \$good_syn revision.
+(You can use \"git bisect \$bad_syn\" and \"git bisect \$good_syn\" for that.)" >&2
                else
-                       gettextln "You need to start by \"git bisect start\".
-You then need to give me at least one good and one bad revision.
-(You can use \"git bisect bad\" and \"git bisect good\" for that.)" >&2
+                       eval_gettextln "You need to start by \"git bisect start\".
+You then need to give me at least one \$good_syn and one \$bad_syn revision.
+(You can use \"git bisect \$bad_syn\" and \"git bisect \$good_syn\" for that.)" >&2
                fi
                exit 1 ;;
        esac
@@ -307,7 +332,7 @@ bisect_auto_next() {
 bisect_next() {
        case "$#" in 0) ;; *) usage ;; esac
        bisect_autostart
-       bisect_next_check good
+       bisect_next_check $TERM_GOOD
 
        # Perform all bisection computation, display and checkout
        git bisect--helper --next-all $(test -f "$GIT_DIR/BISECT_HEAD" && echo --no-checkout)
@@ -316,18 +341,18 @@ bisect_next() {
        # Check if we should exit because bisection is finished
        if test $res -eq 10
        then
-               bad_rev=$(git show-ref --hash --verify refs/bisect/bad)
+               bad_rev=$(git show-ref --hash --verify refs/bisect/$TERM_BAD)
                bad_commit=$(git show-branch $bad_rev)
-               echo "# first bad commit: $bad_commit" >>"$GIT_DIR/BISECT_LOG"
+               echo "# first $TERM_BAD commit: $bad_commit" >>"$GIT_DIR/BISECT_LOG"
                exit 0
        elif test $res -eq 2
        then
                echo "# only skipped commits left to test" >>"$GIT_DIR/BISECT_LOG"
-               good_revs=$(git for-each-ref --format="%(objectname)" "refs/bisect/good-*")
-               for skipped in $(git rev-list refs/bisect/bad --not $good_revs)
+               good_revs=$(git for-each-ref --format="%(objectname)" "refs/bisect/$TERM_GOOD-*")
+               for skipped in $(git rev-list refs/bisect/$TERM_BAD --not $good_revs)
                do
                        skipped_commit=$(git show-branch $skipped)
-                       echo "# possible first bad commit: $skipped_commit" >>"$GIT_DIR/BISECT_LOG"
+                       echo "# possible first $TERM_BAD commit: $skipped_commit" >>"$GIT_DIR/BISECT_LOG"
                done
                exit $res
        fi
@@ -397,6 +422,7 @@ bisect_clean_state() {
        rm -f "$GIT_DIR/BISECT_LOG" &&
        rm -f "$GIT_DIR/BISECT_NAMES" &&
        rm -f "$GIT_DIR/BISECT_RUN" &&
+       rm -f "$GIT_DIR/BISECT_TERMS" &&
        # Cleanup head-name if it got left by an old version of git-bisect
        rm -f "$GIT_DIR/head-name" &&
        git update-ref -d --no-deref BISECT_HEAD &&
@@ -417,11 +443,13 @@ bisect_replay () {
                        rev="$command"
                        command="$bisect"
                fi
+               get_terms
+               check_and_set_terms "$command"
                case "$command" in
                start)
                        cmd="bisect_start $rev"
                        eval "$cmd" ;;
-               good|bad|skip)
+               "$TERM_GOOD"|"$TERM_BAD"|skip)
                        bisect_write "$command" "$rev" ;;
                *)
                        die "$(gettext "?? what are you talking about?")" ;;
@@ -455,9 +483,9 @@ exit code \$res from '\$command' is < 0 or >= 128" >&2
                        state='skip'
                elif [ $res -gt 0 ]
                then
-                       state='bad'
+                       state="$TERM_BAD"
                else
-                       state='good'
+                       state="$TERM_GOOD"
                fi
 
                # We have to use a subshell because "bisect_state" can exit.
@@ -466,7 +494,7 @@ exit code \$res from '\$command' is < 0 or >= 128" >&2
 
                cat "$GIT_DIR/BISECT_RUN"
 
-               if sane_grep "first bad commit could be any of" "$GIT_DIR/BISECT_RUN" \
+               if sane_grep "first $TERM_BAD commit could be any of" "$GIT_DIR/BISECT_RUN" \
                        >/dev/null
                then
                        gettextln "bisect run cannot continue any more" >&2
@@ -480,7 +508,7 @@ exit code \$res from '\$command' is < 0 or >= 128" >&2
                        exit $res
                fi
 
-               if sane_grep "is the first bad commit" "$GIT_DIR/BISECT_RUN" >/dev/null
+               if sane_grep "is the first $TERM_BAD commit" "$GIT_DIR/BISECT_RUN" >/dev/null
                then
                        gettextln "bisect run success"
                        exit 0;
@@ -494,18 +522,62 @@ bisect_log () {
        cat "$GIT_DIR/BISECT_LOG"
 }
 
+get_terms () {
+       if test -s "$GIT_DIR/BISECT_TERMS"
+       then
+               {
+               read TERM_BAD
+               read TERM_GOOD
+               } <"$GIT_DIR/BISECT_TERMS"
+       fi
+}
+
+write_terms () {
+       TERM_BAD=$1
+       TERM_GOOD=$2
+       printf '%s\n%s\n' "$TERM_BAD" "$TERM_GOOD" >"$GIT_DIR/BISECT_TERMS"
+}
+
+check_and_set_terms () {
+       cmd="$1"
+       case "$cmd" in
+       skip|start|terms) ;;
+       *)
+               if test -s "$GIT_DIR/BISECT_TERMS" && test "$cmd" != "$TERM_BAD" && test "$cmd" != "$TERM_GOOD"
+               then
+                       die "$(eval_gettext "Invalid command: you're currently in a \$TERM_BAD/\$TERM_GOOD bisect.")"
+               fi
+               case "$cmd" in
+               bad|good)
+                       if ! test -s "$GIT_DIR/BISECT_TERMS"
+                       then
+                               write_terms bad good
+                       fi
+                       ;;
+               esac ;;
+       esac
+}
+
+bisect_voc () {
+       case "$1" in
+       bad) echo "bad" ;;
+       good) echo "good" ;;
+       esac
+}
+
 case "$#" in
 0)
        usage ;;
 *)
        cmd="$1"
+       get_terms
        shift
        case "$cmd" in
        help)
                git bisect -h ;;
        start)
                bisect_start "$@" ;;
-       bad|good)
+       bad|good|"$TERM_BAD"|"$TERM_GOOD")
                bisect_state "$cmd" "$@" ;;
        skip)
                bisect_skip "$@" ;;
index 392da79..f649e81 100644 (file)
@@ -389,7 +389,6 @@ struct strbuf;
 
 /* General helper functions */
 extern void vreportf(const char *prefix, const char *err, va_list params);
-extern void vwritef(int fd, const char *prefix, const char *err, va_list params);
 extern NORETURN void usage(const char *err);
 extern NORETURN void usagef(const char *err, ...) __attribute__((format (printf, 1, 2)));
 extern NORETURN void die(const char *err, ...) __attribute__((format (printf, 1, 2)));
@@ -425,6 +424,7 @@ static inline int const_error(void)
 extern void set_die_routine(NORETURN_PTR void (*routine)(const char *err, va_list params));
 extern void set_error_routine(void (*routine)(const char *err, va_list params));
 extern void set_die_is_recursing_routine(int (*routine)(void));
+extern void set_error_handle(FILE *);
 
 extern int starts_with(const char *str, const char *prefix);
 
index b660cc2..c5a3f76 100755 (executable)
@@ -75,6 +75,8 @@ git send-email [options] <file | directory | rev-list options >
                                      Pass an empty string to disable certificate
                                      verification.
     --smtp-domain           <str>  * The domain name sent to HELO/EHLO handshake
+    --smtp-auth             <str>  * Space-separated list of allowed AUTH mechanisms.
+                                     This setting forces to use one of the listed mechanisms.
     --smtp-debug            <0|1>  * Disable, enable Net::SMTP debug.
 
   Automating:
@@ -208,7 +210,7 @@ my ($cover_cc, $cover_to);
 my ($to_cmd, $cc_cmd);
 my ($smtp_server, $smtp_server_port, @smtp_server_options);
 my ($smtp_authuser, $smtp_encryption, $smtp_ssl_cert_path);
-my ($identity, $aliasfiletype, @alias_files, $smtp_domain);
+my ($identity, $aliasfiletype, @alias_files, $smtp_domain, $smtp_auth);
 my ($validate, $confirm);
 my (@suppress_cc);
 my ($auto_8bit_encoding);
@@ -239,6 +241,7 @@ my %config_settings = (
     "smtppass" => \$smtp_authpass,
     "smtpsslcertpath" => \$smtp_ssl_cert_path,
     "smtpdomain" => \$smtp_domain,
+    "smtpauth" => \$smtp_auth,
     "to" => \@initial_to,
     "tocmd" => \$to_cmd,
     "cc" => \@initial_cc,
@@ -310,6 +313,7 @@ my $rc = GetOptions("h" => \$help,
                    "smtp-ssl-cert-path=s" => \$smtp_ssl_cert_path,
                    "smtp-debug:i" => \$debug_net_smtp,
                    "smtp-domain:s" => \$smtp_domain,
+                   "smtp-auth=s" => \$smtp_auth,
                    "identity=s" => \$identity,
                    "annotate!" => \$annotate,
                    "no-annotate" => sub {$annotate = 0},
@@ -1130,6 +1134,12 @@ sub smtp_auth_maybe {
                Authen::SASL->import(qw(Perl));
        };
 
+       # Check mechanism naming as defined in:
+       # https://tools.ietf.org/html/rfc4422#page-8
+       if ($smtp_auth !~ /^(\b[A-Z0-9-_]{1,20}\s*)*$/) {
+               die "invalid smtp auth: '${smtp_auth}'";
+       }
+
        # TODO: Authentication may fail not because credentials were
        # invalid but due to other reasons, in which we should not
        # reject credentials.
@@ -1142,6 +1152,20 @@ sub smtp_auth_maybe {
                'password' => $smtp_authpass
        }, sub {
                my $cred = shift;
+
+               if ($smtp_auth) {
+                       my $sasl = Authen::SASL->new(
+                               mechanism => $smtp_auth,
+                               callback => {
+                                       user => $cred->{'username'},
+                                       pass => $cred->{'password'},
+                                       authname => $cred->{'username'},
+                               }
+                       );
+
+                       return !!$smtp->auth($sasl);
+               }
+
                return !!$smtp->auth($cred->{'username'}, $cred->{'password'});
        });
 
index 8e9e2cd..1d5ba7a 100755 (executable)
@@ -183,9 +183,7 @@ store_stash () {
                stash_msg="Created via \"git stash store\"."
        fi
 
-       # Make sure the reflog for stash is kept.
-       : >>"$(git rev-parse --git-path logs/$ref_stash)"
-       git update-ref -m "$stash_msg" $ref_stash $w_commit
+       git update-ref --create-reflog -m "$stash_msg" $ref_stash $w_commit
        ret=$?
        test $ret != 0 && test -z $quiet &&
        die "$(eval_gettext "Cannot update \$ref_stash with \$w_commit")"
@@ -262,7 +260,7 @@ save_stash () {
                say "$(gettext "No local changes to save")"
                exit 0
        fi
-       test -f "$(git rev-parse --git-path logs/$ref_stash)" ||
+       git reflog exists $ref_stash ||
                clear_stash || die "$(gettext "Cannot initialize stash")"
 
        create_stash "$stash_msg" $untracked
index b977c00..bac40ef 100644 (file)
@@ -164,7 +164,7 @@ static void send_strbuf(const char *type, struct strbuf *buf)
 
 static void send_local_file(const char *the_type, const char *name)
 {
-       const char *p = git_path("%s", name);
+       char *p = git_pathdup("%s", name);
        size_t buf_alloc = 8192;
        char *buf = xmalloc(buf_alloc);
        int fd;
@@ -191,6 +191,7 @@ static void send_local_file(const char *the_type, const char *name)
        }
        close(fd);
        free(buf);
+       free(p);
 }
 
 static void get_text_file(char *name)
diff --git a/http.c b/http.c
index e9c6fdd..9dce380 100644 (file)
--- a/http.c
+++ b/http.c
@@ -37,6 +37,20 @@ static int curl_ssl_verify = -1;
 static int curl_ssl_try;
 static const char *ssl_cert;
 static const char *ssl_cipherlist;
+static const char *ssl_version;
+static struct {
+       const char *name;
+       long ssl_version;
+} sslversions[] = {
+       { "sslv2", CURL_SSLVERSION_SSLv2 },
+       { "sslv3", CURL_SSLVERSION_SSLv3 },
+       { "tlsv1", CURL_SSLVERSION_TLSv1 },
+#if LIBCURL_VERSION_NUM >= 0x072200
+       { "tlsv1.0", CURL_SSLVERSION_TLSv1_0 },
+       { "tlsv1.1", CURL_SSLVERSION_TLSv1_1 },
+       { "tlsv1.2", CURL_SSLVERSION_TLSv1_2 },
+#endif
+};
 #if LIBCURL_VERSION_NUM >= 0x070903
 static const char *ssl_key;
 #endif
@@ -190,6 +204,8 @@ static int http_options(const char *var, const char *value, void *cb)
        }
        if (!strcmp("http.sslcipherlist", var))
                return git_config_string(&ssl_cipherlist, var, value);
+       if (!strcmp("http.sslversion", var))
+               return git_config_string(&ssl_version, var, value);
        if (!strcmp("http.sslcert", var))
                return git_config_string(&ssl_cert, var, value);
 #if LIBCURL_VERSION_NUM >= 0x070903
@@ -364,9 +380,24 @@ static CURL *get_curl_handle(void)
        if (http_proactive_auth)
                init_curl_http_auth(result);
 
+       if (getenv("GIT_SSL_VERSION"))
+               ssl_version = getenv("GIT_SSL_VERSION");
+       if (ssl_version && *ssl_version) {
+               int i;
+               for (i = 0; i < ARRAY_SIZE(sslversions); i++) {
+                       if (!strcmp(ssl_version, sslversions[i].name)) {
+                               curl_easy_setopt(result, CURLOPT_SSLVERSION,
+                                                sslversions[i].ssl_version);
+                               break;
+                       }
+               }
+               if (i == ARRAY_SIZE(sslversions))
+                       warning("unsupported ssl version %s: using default",
+                               ssl_version);
+       }
+
        if (getenv("GIT_SSL_CIPHER_LIST"))
                ssl_cipherlist = getenv("GIT_SSL_CIPHER_LIST");
-
        if (ssl_cipherlist != NULL && *ssl_cipherlist)
                curl_easy_setopt(result, CURLOPT_SSL_CIPHER_LIST,
                                ssl_cipherlist);
@@ -1318,7 +1349,7 @@ static int http_get_file(const char *url, const char *filename,
        ret = http_request_reauth(url, result, HTTP_REQUEST_FILE, options);
        fclose(result);
 
-       if (ret == HTTP_OK && move_temp_to_file(tmpfile.buf, filename))
+       if (ret == HTTP_OK && finalize_object_file(tmpfile.buf, filename))
                ret = HTTP_ERROR;
 cleanup:
        strbuf_release(&tmpfile);
@@ -1405,7 +1436,7 @@ static int fetch_and_setup_pack_index(struct packed_git **packs_head,
        ret = verify_pack_index(new_pack);
        if (!ret) {
                close_pack_index(new_pack);
-               ret = move_temp_to_file(tmp_idx, sha1_pack_index_name(sha1));
+               ret = finalize_object_file(tmp_idx, sha1_pack_index_name(sha1));
        }
        free(tmp_idx);
        if (ret)
@@ -1517,8 +1548,8 @@ int finish_http_pack_request(struct http_pack_request *preq)
 
        unlink(sha1_pack_index_name(p->sha1));
 
-       if (move_temp_to_file(preq->tmpfile, sha1_pack_name(p->sha1))
-        || move_temp_to_file(tmp_idx, sha1_pack_index_name(p->sha1))) {
+       if (finalize_object_file(preq->tmpfile, sha1_pack_name(p->sha1))
+        || finalize_object_file(tmp_idx, sha1_pack_index_name(p->sha1))) {
                free(tmp_idx);
                return -1;
        }
@@ -1782,7 +1813,7 @@ int finish_http_object_request(struct http_object_request *freq)
                return -1;
        }
        freq->rename =
-               move_temp_to_file(freq->tmpfile, sha1_file_name(freq->sha1));
+               finalize_object_file(freq->tmpfile, sha1_file_name(freq->sha1));
 
        return freq->rename;
 }
index 993bb82..637b8cf 100644 (file)
@@ -1,38 +1,9 @@
 /*
  * Copyright (c) 2005, Junio C Hamano
  */
+
 #include "cache.h"
 #include "lockfile.h"
-#include "sigchain.h"
-
-static struct lock_file *volatile lock_file_list;
-
-static void remove_lock_files(int skip_fclose)
-{
-       pid_t me = getpid();
-
-       while (lock_file_list) {
-               if (lock_file_list->owner == me) {
-                       /* fclose() is not safe to call in a signal handler */
-                       if (skip_fclose)
-                               lock_file_list->fp = NULL;
-                       rollback_lock_file(lock_file_list);
-               }
-               lock_file_list = lock_file_list->next;
-       }
-}
-
-static void remove_lock_files_on_exit(void)
-{
-       remove_lock_files(0);
-}
-
-static void remove_lock_files_on_signal(int signo)
-{
-       remove_lock_files(1);
-       sigchain_pop(signo);
-       raise(signo);
-}
 
 /*
  * path = absolute or relative path name
@@ -101,60 +72,17 @@ static void resolve_symlink(struct strbuf *path)
 /* Make sure errno contains a meaningful value on error */
 static int lock_file(struct lock_file *lk, const char *path, int flags)
 {
-       size_t pathlen = strlen(path);
-
-       if (!lock_file_list) {
-               /* One-time initialization */
-               sigchain_push_common(remove_lock_files_on_signal);
-               atexit(remove_lock_files_on_exit);
-       }
-
-       if (lk->active)
-               die("BUG: cannot lock_file(\"%s\") using active struct lock_file",
-                   path);
-       if (!lk->on_list) {
-               /* Initialize *lk and add it to lock_file_list: */
-               lk->fd = -1;
-               lk->fp = NULL;
-               lk->active = 0;
-               lk->owner = 0;
-               strbuf_init(&lk->filename, pathlen + LOCK_SUFFIX_LEN);
-               lk->next = lock_file_list;
-               lock_file_list = lk;
-               lk->on_list = 1;
-       } else if (lk->filename.len) {
-               /* This shouldn't happen, but better safe than sorry. */
-               die("BUG: lock_file(\"%s\") called with improperly-reset lock_file object",
-                   path);
-       }
+       int fd;
+       struct strbuf filename = STRBUF_INIT;
 
-       if (flags & LOCK_NO_DEREF) {
-               strbuf_add_absolute_path(&lk->filename, path);
-       } else {
-               struct strbuf resolved_path = STRBUF_INIT;
-
-               strbuf_add(&resolved_path, path, pathlen);
-               resolve_symlink(&resolved_path);
-               strbuf_add_absolute_path(&lk->filename, resolved_path.buf);
-               strbuf_release(&resolved_path);
-       }
+       strbuf_addstr(&filename, path);
+       if (!(flags & LOCK_NO_DEREF))
+               resolve_symlink(&filename);
 
-       strbuf_addstr(&lk->filename, LOCK_SUFFIX);
-       lk->fd = open(lk->filename.buf, O_RDWR | O_CREAT | O_EXCL, 0666);
-       if (lk->fd < 0) {
-               strbuf_reset(&lk->filename);
-               return -1;
-       }
-       lk->owner = getpid();
-       lk->active = 1;
-       if (adjust_shared_perm(lk->filename.buf)) {
-               int save_errno = errno;
-               error("cannot fix permission bits on %s", lk->filename.buf);
-               rollback_lock_file(lk);
-               errno = save_errno;
-               return -1;
-       }
-       return lk->fd;
+       strbuf_addstr(&filename, LOCK_SUFFIX);
+       fd = create_tempfile(&lk->tempfile, filename.buf);
+       strbuf_release(&filename);
+       return fd;
 }
 
 /*
@@ -287,116 +215,29 @@ int hold_lock_file_for_append(struct lock_file *lk, const char *path, int flags)
        return fd;
 }
 
-FILE *fdopen_lock_file(struct lock_file *lk, const char *mode)
-{
-       if (!lk->active)
-               die("BUG: fdopen_lock_file() called for unlocked object");
-       if (lk->fp)
-               die("BUG: fdopen_lock_file() called twice for file '%s'", lk->filename.buf);
-
-       lk->fp = fdopen(lk->fd, mode);
-       return lk->fp;
-}
-
 char *get_locked_file_path(struct lock_file *lk)
 {
-       if (!lk->active)
-               die("BUG: get_locked_file_path() called for unlocked object");
-       if (lk->filename.len <= LOCK_SUFFIX_LEN)
-               die("BUG: get_locked_file_path() called for malformed lock object");
-       return xmemdupz(lk->filename.buf, lk->filename.len - LOCK_SUFFIX_LEN);
-}
-
-int close_lock_file(struct lock_file *lk)
-{
-       int fd = lk->fd;
-       FILE *fp = lk->fp;
-       int err;
-
-       if (fd < 0)
-               return 0;
-
-       lk->fd = -1;
-       if (fp) {
-               lk->fp = NULL;
-
-               /*
-                * Note: no short-circuiting here; we want to fclose()
-                * in any case!
-                */
-               err = ferror(fp) | fclose(fp);
-       } else {
-               err = close(fd);
-       }
+       struct strbuf ret = STRBUF_INIT;
 
-       if (err) {
-               int save_errno = errno;
-               rollback_lock_file(lk);
-               errno = save_errno;
-               return -1;
-       }
-
-       return 0;
-}
-
-int reopen_lock_file(struct lock_file *lk)
-{
-       if (0 <= lk->fd)
-               die(_("BUG: reopen a lockfile that is still open"));
-       if (!lk->active)
-               die(_("BUG: reopen a lockfile that has been committed"));
-       lk->fd = open(lk->filename.buf, O_WRONLY);
-       return lk->fd;
+       strbuf_addstr(&ret, get_tempfile_path(&lk->tempfile));
+       if (ret.len <= LOCK_SUFFIX_LEN ||
+           strcmp(ret.buf + ret.len - LOCK_SUFFIX_LEN, LOCK_SUFFIX))
+               die("BUG: get_locked_file_path() called for malformed lock object");
+       /* remove ".lock": */
+       strbuf_setlen(&ret, ret.len - LOCK_SUFFIX_LEN);
+       return strbuf_detach(&ret, NULL);
 }
 
-int commit_lock_file_to(struct lock_file *lk, const char *path)
+int commit_lock_file(struct lock_file *lk)
 {
-       if (!lk->active)
-               die("BUG: attempt to commit unlocked object to \"%s\"", path);
+       char *result_path = get_locked_file_path(lk);
 
-       if (close_lock_file(lk))
-               return -1;
-
-       if (rename(lk->filename.buf, path)) {
+       if (commit_lock_file_to(lk, result_path)) {
                int save_errno = errno;
-               rollback_lock_file(lk);
+               free(result_path);
                errno = save_errno;
                return -1;
        }
-
-       lk->active = 0;
-       strbuf_reset(&lk->filename);
+       free(result_path);
        return 0;
 }
-
-int commit_lock_file(struct lock_file *lk)
-{
-       static struct strbuf result_file = STRBUF_INIT;
-       int err;
-
-       if (!lk->active)
-               die("BUG: attempt to commit unlocked object");
-
-       if (lk->filename.len <= LOCK_SUFFIX_LEN ||
-           strcmp(lk->filename.buf + lk->filename.len - LOCK_SUFFIX_LEN, LOCK_SUFFIX))
-               die("BUG: lockfile filename corrupt");
-
-       /* remove ".lock": */
-       strbuf_add(&result_file, lk->filename.buf,
-                  lk->filename.len - LOCK_SUFFIX_LEN);
-       err = commit_lock_file_to(lk, result_file.buf);
-       strbuf_reset(&result_file);
-       return err;
-}
-
-void rollback_lock_file(struct lock_file *lk)
-{
-       if (!lk->active)
-               return;
-
-       if (!close_lock_file(lk)) {
-               unlink_or_warn(lk->filename.buf);
-               lk->active = 0;
-               strbuf_reset(&lk->filename);
-       }
-}
index b4abc61..8131fa3 100644 (file)
 /*
  * File write-locks as used by Git.
  *
- * For an overview of how to use the lockfile API, please see
- *
- *     Documentation/technical/api-lockfile.txt
- *
- * This module keeps track of all locked files in lock_file_list for
- * use at cleanup. This list and the lock_file objects that comprise
- * it must be kept in self-consistent states at all time, because the
- * program can be interrupted any time by a signal, in which case the
- * signal handler will walk through the list attempting to clean up
- * any open lock files.
- *
- * A lockfile is owned by the process that created it. The lock_file
- * object has an "owner" field that records its owner. This field is
- * used to prevent a forked process from closing a lockfile created by
- * its parent.
- *
- * The possible states of a lock_file object are as follows:
- *
- * - Uninitialized.  In this state the object's on_list field must be
- *   zero but the rest of its contents need not be initialized.  As
- *   soon as the object is used in any way, it is irrevocably
- *   registered in the lock_file_list, and on_list is set.
- *
- * - Locked, lockfile open (after hold_lock_file_for_update(),
- *   hold_lock_file_for_append(), or reopen_lock_file()). In this
- *   state:
- *   - the lockfile exists
- *   - active is set
- *   - filename holds the filename of the lockfile
- *   - fd holds a file descriptor open for writing to the lockfile
- *   - fp holds a pointer to an open FILE object if and only if
- *     fdopen_lock_file() has been called on the object
- *   - owner holds the PID of the process that locked the file
- *
- * - Locked, lockfile closed (after successful close_lock_file()).
- *   Same as the previous state, except that the lockfile is closed
- *   and fd is -1.
- *
- * - Unlocked (after commit_lock_file(), commit_lock_file_to(),
- *   rollback_lock_file(), a failed attempt to lock, or a failed
- *   close_lock_file()).  In this state:
- *   - active is unset
- *   - filename is empty (usually, though there are transitory
- *     states in which this condition doesn't hold). Client code should
- *     *not* rely on the filename being empty in this state.
- *   - fd is -1
- *   - the object is left registered in the lock_file_list, and
- *     on_list is set.
+ * The lockfile API serves two purposes:
+ *
+ * * Mutual exclusion and atomic file updates. When we want to change
+ *   a file, we create a lockfile `<filename>.lock`, write the new
+ *   file contents into it, and then rename the lockfile to its final
+ *   destination `<filename>`. We create the `<filename>.lock` file
+ *   with `O_CREAT|O_EXCL` so that we can notice and fail if somebody
+ *   else has already locked the file, then atomically rename the
+ *   lockfile to its final destination to commit the changes and
+ *   unlock the file.
+ *
+ * * Automatic cruft removal. If the program exits after we lock a
+ *   file but before the changes have been committed, we want to make
+ *   sure that we remove the lockfile. This is done by remembering the
+ *   lockfiles we have created in a linked list and setting up an
+ *   `atexit(3)` handler and a signal handler that clean up the
+ *   lockfiles. This mechanism ensures that outstanding lockfiles are
+ *   cleaned up if the program exits (including when `die()` is
+ *   called) or if the program is terminated by a signal.
+ *
+ * Please note that lockfiles only block other writers. Readers do not
+ * block, but they are guaranteed to see either the old contents of
+ * the file or the new contents of the file (assuming that the
+ * filesystem implements `rename(2)` atomically).
+ *
+ * Most of the heavy lifting is done by the tempfile module (see
+ * "tempfile.h").
+ *
+ * Calling sequence
+ * ----------------
+ *
+ * The caller:
+ *
+ * * Allocates a `struct lock_file` either as a static variable or on
+ *   the heap, initialized to zeros. Once you use the structure to
+ *   call the `hold_lock_file_for_*()` family of functions, it belongs
+ *   to the lockfile subsystem and its storage must remain valid
+ *   throughout the life of the program (i.e. you cannot use an
+ *   on-stack variable to hold this structure).
+ *
+ * * Attempts to create a lockfile by calling
+ *   `hold_lock_file_for_update()` or `hold_lock_file_for_append()`.
+ *
+ * * Writes new content for the destination file by either:
+ *
+ *   * writing to the file descriptor returned by the
+ *     `hold_lock_file_for_*()` functions (also available via
+ *     `lock->fd`).
+ *
+ *   * calling `fdopen_lock_file()` to get a `FILE` pointer for the
+ *     open file and writing to the file using stdio.
+ *
+ * When finished writing, the caller can:
+ *
+ * * Close the file descriptor and rename the lockfile to its final
+ *   destination by calling `commit_lock_file()` or
+ *   `commit_lock_file_to()`.
+ *
+ * * Close the file descriptor and remove the lockfile by calling
+ *   `rollback_lock_file()`.
+ *
+ * * Close the file descriptor without removing or renaming the
+ *   lockfile by calling `close_lock_file()`, and later call
+ *   `commit_lock_file()`, `commit_lock_file_to()`,
+ *   `rollback_lock_file()`, or `reopen_lock_file()`.
+ *
+ * Even after the lockfile is committed or rolled back, the
+ * `lock_file` object must not be freed or altered by the caller.
+ * However, it may be reused; just pass it to another call of
+ * `hold_lock_file_for_update()` or `hold_lock_file_for_append()`.
+ *
+ * If the program exits before `commit_lock_file()`,
+ * `commit_lock_file_to()`, or `rollback_lock_file()` is called, the
+ * tempfile module will close and remove the lockfile, thereby rolling
+ * back any uncommitted changes.
+ *
+ * If you need to close the file descriptor you obtained from a
+ * `hold_lock_file_for_*()` function yourself, do so by calling
+ * `close_lock_file()`. See "tempfile.h" for more information.
+ *
+ *
+ * Under the covers, a lockfile is just a tempfile with a few helper
+ * functions. In particular, the state diagram and the cleanup
+ * machinery are all implemented in the tempfile module.
+ *
+ *
+ * Error handling
+ * --------------
+ *
+ * The `hold_lock_file_for_*()` functions return a file descriptor on
+ * success or -1 on failure (unless `LOCK_DIE_ON_ERROR` is used; see
+ * "flags" below). On errors, `errno` describes the reason for
+ * failure. Errors can be reported by passing `errno` to
+ * `unable_to_lock_message()` or `unable_to_lock_die()`.
+ *
+ * Similarly, `commit_lock_file`, `commit_lock_file_to`, and
+ * `close_lock_file` return 0 on success. On failure they set `errno`
+ * appropriately, do their best to roll back the lockfile, and return
+ * -1.
  */
 
+#include "tempfile.h"
+
 struct lock_file {
-       struct lock_file *volatile next;
-       volatile sig_atomic_t active;
-       volatile int fd;
-       FILE *volatile fp;
-       volatile pid_t owner;
-       char on_list;
-       struct strbuf filename;
+       struct tempfile tempfile;
 };
 
 /* String appended to a filename to derive the lockfile name: */
 #define LOCK_SUFFIX ".lock"
 #define LOCK_SUFFIX_LEN 5
 
+
+/*
+ * Flags
+ * -----
+ *
+ * The following flags can be passed to `hold_lock_file_for_update()`
+ * or `hold_lock_file_for_append()`.
+ */
+
+/*
+ * If a lock is already taken for the file, `die()` with an error
+ * message. If this flag is not specified, trying to lock a file that
+ * is already locked returns -1 to the caller.
+ */
 #define LOCK_DIE_ON_ERROR 1
+
+/*
+ * Usually symbolic links in the destination path are resolved. This
+ * means that (1) the lockfile is created by adding ".lock" to the
+ * resolved path, and (2) upon commit, the resolved path is
+ * overwritten. However, if `LOCK_NO_DEREF` is set, then the lockfile
+ * is created by adding ".lock" to the path argument itself. This
+ * option is used, for example, when detaching a symbolic reference,
+ * which for backwards-compatibility reasons, can be a symbolic link
+ * containing the name of the referred-to-reference.
+ */
 #define LOCK_NO_DEREF 2
 
-extern void unable_to_lock_message(const char *path, int err,
-                                  struct strbuf *buf);
-extern NORETURN void unable_to_lock_die(const char *path, int err);
+/*
+ * Attempt to create a lockfile for the file at `path` and return a
+ * file descriptor for writing to it, or -1 on error. If the file is
+ * currently locked, retry with quadratic backoff for at least
+ * timeout_ms milliseconds. If timeout_ms is 0, try exactly once; if
+ * timeout_ms is -1, retry indefinitely. The flags argument and error
+ * handling are described above.
+ */
 extern int hold_lock_file_for_update_timeout(
                struct lock_file *lk, const char *path,
                int flags, long timeout_ms);
 
+/*
+ * Attempt to create a lockfile for the file at `path` and return a
+ * file descriptor for writing to it, or -1 on error. The flags
+ * argument and error handling are described above.
+ */
 static inline int hold_lock_file_for_update(
                struct lock_file *lk, const char *path,
                int flags)
@@ -85,15 +167,135 @@ static inline int hold_lock_file_for_update(
        return hold_lock_file_for_update_timeout(lk, path, flags, 0);
 }
 
-extern int hold_lock_file_for_append(struct lock_file *lk, const char *path,
-                                    int flags);
+/*
+ * Like `hold_lock_file_for_update()`, but before returning copy the
+ * existing contents of the file (if any) to the lockfile and position
+ * its write pointer at the end of the file. The flags argument and
+ * error handling are described above.
+ */
+extern int hold_lock_file_for_append(struct lock_file *lk,
+                                    const char *path, int flags);
+
+/*
+ * Append an appropriate error message to `buf` following the failure
+ * of `hold_lock_file_for_update()` or `hold_lock_file_for_append()`
+ * to lock `path`. `err` should be the `errno` set by the failing
+ * call.
+ */
+extern void unable_to_lock_message(const char *path, int err,
+                                  struct strbuf *buf);
 
-extern FILE *fdopen_lock_file(struct lock_file *, const char *mode);
-extern char *get_locked_file_path(struct lock_file *);
-extern int commit_lock_file_to(struct lock_file *, const char *path);
-extern int commit_lock_file(struct lock_file *);
-extern int reopen_lock_file(struct lock_file *);
-extern int close_lock_file(struct lock_file *);
-extern void rollback_lock_file(struct lock_file *);
+/*
+ * Emit an appropriate error message and `die()` following the failure
+ * of `hold_lock_file_for_update()` or `hold_lock_file_for_append()`
+ * to lock `path`. `err` should be the `errno` set by the failing
+ * call.
+ */
+extern NORETURN void unable_to_lock_die(const char *path, int err);
+
+/*
+ * Associate a stdio stream with the lockfile (which must still be
+ * open). Return `NULL` (*without* rolling back the lockfile) on
+ * error. The stream is closed automatically when `close_lock_file()`
+ * is called or when the file is committed or rolled back.
+ */
+static inline FILE *fdopen_lock_file(struct lock_file *lk, const char *mode)
+{
+       return fdopen_tempfile(&lk->tempfile, mode);
+}
+
+/*
+ * Return the path of the lockfile. The return value is a pointer to a
+ * field within the lock_file object and should not be freed.
+ */
+static inline const char *get_lock_file_path(struct lock_file *lk)
+{
+       return get_tempfile_path(&lk->tempfile);
+}
+
+static inline int get_lock_file_fd(struct lock_file *lk)
+{
+       return get_tempfile_fd(&lk->tempfile);
+}
+
+static inline FILE *get_lock_file_fp(struct lock_file *lk)
+{
+       return get_tempfile_fp(&lk->tempfile);
+}
+
+/*
+ * Return the path of the file that is locked by the specified
+ * lock_file object. The caller must free the memory.
+ */
+extern char *get_locked_file_path(struct lock_file *lk);
+
+/*
+ * If the lockfile is still open, close it (and the file pointer if it
+ * has been opened using `fdopen_lock_file()`) without renaming the
+ * lockfile over the file being locked. Return 0 upon success. On
+ * failure to `close(2)`, return a negative value and roll back the
+ * lock file. Usually `commit_lock_file()`, `commit_lock_file_to()`,
+ * or `rollback_lock_file()` should eventually be called if
+ * `close_lock_file()` succeeds.
+ */
+static inline int close_lock_file(struct lock_file *lk)
+{
+       return close_tempfile(&lk->tempfile);
+}
+
+/*
+ * Re-open a lockfile that has been closed using `close_lock_file()`
+ * but not yet committed or rolled back. This can be used to implement
+ * a sequence of operations like the following:
+ *
+ * * Lock file.
+ *
+ * * Write new contents to lockfile, then `close_lock_file()` to
+ *   cause the contents to be written to disk.
+ *
+ * * Pass the name of the lockfile to another program to allow it (and
+ *   nobody else) to inspect the contents you wrote, while still
+ *   holding the lock yourself.
+ *
+ * * `reopen_lock_file()` to reopen the lockfile. Make further updates
+ *   to the contents.
+ *
+ * * `commit_lock_file()` to make the final version permanent.
+ */
+static inline int reopen_lock_file(struct lock_file *lk)
+{
+       return reopen_tempfile(&lk->tempfile);
+}
+
+/*
+ * Commit the change represented by `lk`: close the file descriptor
+ * and/or file pointer if they are still open and rename the lockfile
+ * to its final destination. Return 0 upon success. On failure, roll
+ * back the lock file and return -1, with `errno` set to the value
+ * from the failing call to `close(2)` or `rename(2)`. It is a bug to
+ * call `commit_lock_file()` for a `lock_file` object that is not
+ * currently locked.
+ */
+extern int commit_lock_file(struct lock_file *lk);
+
+/*
+ * Like `commit_lock_file()`, but rename the lockfile to the provided
+ * `path`. `path` must be on the same filesystem as the lock file.
+ */
+static inline int commit_lock_file_to(struct lock_file *lk, const char *path)
+{
+       return rename_tempfile(&lk->tempfile, path);
+}
+
+/*
+ * Roll back `lk`: close the file descriptor and/or file pointer and
+ * remove the lockfile. It is a NOOP to call `rollback_lock_file()`
+ * for a `lock_file` object that has already been committed or rolled
+ * back.
+ */
+static inline void rollback_lock_file(struct lock_file *lk)
+{
+       delete_tempfile(&lk->tempfile);
+}
 
 #endif /* LOCKFILE_H */
index 0b2b82c..b3d1dab 100644 (file)
@@ -295,7 +295,7 @@ static void write_buf_to_worktree(const unsigned char *obj,
                                  const char *buf, unsigned long size)
 {
        int fd;
-       const char *path = git_path(NOTES_MERGE_WORKTREE "/%s", sha1_to_hex(obj));
+       char *path = git_pathdup(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))
@@ -320,6 +320,7 @@ static void write_buf_to_worktree(const unsigned char *obj,
        }
 
        close(fd);
+       free(path);
 }
 
 static void write_note_to_worktree(const unsigned char *obj,
diff --git a/pager.c b/pager.c
index 070dc11..27d4c8a 100644 (file)
--- a/pager.c
+++ b/pager.c
@@ -150,7 +150,8 @@ int check_pager_config(const char *cmd)
        struct strbuf key = STRBUF_INIT;
        const char *value = NULL;
        strbuf_addf(&key, "pager.%s", cmd);
-       if (!git_config_get_value(key.buf, &value)) {
+       if (git_config_key_is_valid(key.buf) &&
+           !git_config_get_value(key.buf, &value)) {
                int b = git_config_maybe_bool(key.buf, value);
                if (b >= 0)
                        want = b;
index 6ca8388..3f1cc3a 100644 (file)
@@ -127,7 +127,7 @@ struct option {
 #define OPT_BOOL(s, l, v, h)        OPT_SET_INT(s, l, v, h, 1)
 #define OPT_HIDDEN_BOOL(s, l, v, h) { OPTION_SET_INT, (s), (l), (v), NULL, \
                                      (h), PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, NULL, 1}
-#define OPT_CMDMODE(s, l, v, h, i) { OPTION_CMDMODE, (s), (l), (v), NULL, \
+#define OPT_CMDMODE(s, l, v, h, i)  { OPTION_CMDMODE, (s), (l), (v), NULL, \
                                      (h), PARSE_OPT_NOARG|PARSE_OPT_NONEG, NULL, (i) }
 #define OPT_INTEGER(s, l, v, h)     { OPTION_INTEGER, (s), (l), (v), N_("n"), (h) }
 #define OPT_MAGNITUDE(s, l, v, h)   { OPTION_MAGNITUDE, (s), (l), (v), \
diff --git a/path.c b/path.c
index 10f4cbf..95acbaf 100644 (file)
--- a/path.c
+++ b/path.c
@@ -224,11 +224,10 @@ const char *mkpath(const char *fmt, ...)
        return cleanup_path(pathname->buf);
 }
 
-const char *git_path_submodule(const char *path, const char *fmt, ...)
+static void do_submodule_path(struct strbuf *buf, const char *path,
+                             const char *fmt, va_list args)
 {
-       struct strbuf *buf = get_pathname();
        const char *git_dir;
-       va_list args;
 
        strbuf_addstr(buf, path);
        if (buf->len && buf->buf[buf->len - 1] != '/')
@@ -242,11 +241,27 @@ const char *git_path_submodule(const char *path, const char *fmt, ...)
        }
        strbuf_addch(buf, '/');
 
-       va_start(args, fmt);
        strbuf_vaddf(buf, fmt, args);
-       va_end(args);
        strbuf_cleanup_path(buf);
-       return buf->buf;
+}
+
+char *git_pathdup_submodule(const char *path, const char *fmt, ...)
+{
+       va_list args;
+       struct strbuf buf = STRBUF_INIT;
+       va_start(args, fmt);
+       do_submodule_path(&buf, path, fmt, args);
+       va_end(args);
+       return strbuf_detach(&buf, NULL);
+}
+
+void strbuf_git_path_submodule(struct strbuf *buf, const char *path,
+                              const char *fmt, ...)
+{
+       va_list args;
+       va_start(args, fmt);
+       do_submodule_path(buf, path, fmt, args);
+       va_end(args);
 }
 
 int validate_headref(const char *path)
@@ -918,3 +933,13 @@ char *xdg_config_home(const char *filename)
                return mkpathdup("%s/.config/git/%s", home, filename);
        return NULL;
 }
+
+GIT_PATH_FUNC(git_path_cherry_pick_head, "CHERRY_PICK_HEAD")
+GIT_PATH_FUNC(git_path_revert_head, "REVERT_HEAD")
+GIT_PATH_FUNC(git_path_squash_msg, "SQUASH_MSG")
+GIT_PATH_FUNC(git_path_merge_msg, "MERGE_MSG")
+GIT_PATH_FUNC(git_path_merge_rr, "MERGE_RR")
+GIT_PATH_FUNC(git_path_merge_mode, "MERGE_MODE")
+GIT_PATH_FUNC(git_path_merge_head, "MERGE_HEAD")
+GIT_PATH_FUNC(git_path_fetch_head, "FETCH_HEAD")
+GIT_PATH_FUNC(git_path_shallow, "shallow")
index d8c9111..fef4c0f 100644 (file)
--- a/po/README
+++ b/po/README
@@ -10,10 +10,26 @@ coordinates our localization effort in the l10 coordinator repository:
 
         https://github.com/git-l10n/git-po/
 
+The two character language translation codes are defined by ISO_639-1, as
+stated in the gettext(1) full manual, appendix A.1, Usual Language Codes.
+
+
+Contributing to an existing translation
+---------------------------------------
 As a contributor for a language XX, you should first check TEAMS file in
 this directory to see whether a dedicated repository for your language XX
 exists. Fork the dedicated repository and start to work if it exists.
 
+Sometime, contributors may find that the translations of their Git
+distributions are quite different with the translations of the
+corresponding version from Git official. This is because some Git
+distributions (such as from Ubuntu, etc.) have their own l10n workflow.
+For this case, wrong translations should be reported and fixed through
+their workflows.
+
+
+Creating a new language translation
+-----------------------------------
 If you are the first contributor for the language XX, please fork this
 repository, prepare and/or update the translated message file po/XX.po
 (described later), and ask the l10n coordinator to pull your work.
@@ -23,6 +39,9 @@ coordinate among yourselves and nominate the team leader for your
 language, so that the l10n coordinator only needs to interact with one
 person per language.
 
+
+Translation Process Flow
+------------------------
 The overall data-flow looks like this:
 
     +-------------------+            +------------------+
index 89dbc08..ab1bfc9 100644 (file)
@@ -5,6 +5,7 @@
  */
 #define NO_THE_INDEX_COMPATIBILITY_MACROS
 #include "cache.h"
+#include "tempfile.h"
 #include "lockfile.h"
 #include "cache-tree.h"
 #include "refs.h"
@@ -2113,7 +2114,7 @@ static int commit_locked_index(struct lock_file *lk)
 static int do_write_locked_index(struct index_state *istate, struct lock_file *lock,
                                 unsigned flags)
 {
-       int ret = do_write_index(istate, lock->fd, 0);
+       int ret = do_write_index(istate, get_lock_file_fd(lock), 0);
        if (ret)
                return ret;
        assert((flags & (COMMIT_LOCK | CLOSE_LOCK)) !=
@@ -2137,54 +2138,27 @@ static int write_split_index(struct index_state *istate,
        return ret;
 }
 
-static char *temporary_sharedindex;
-
-static void remove_temporary_sharedindex(void)
-{
-       if (temporary_sharedindex) {
-               unlink_or_warn(temporary_sharedindex);
-               free(temporary_sharedindex);
-               temporary_sharedindex = NULL;
-       }
-}
-
-static void remove_temporary_sharedindex_on_signal(int signo)
-{
-       remove_temporary_sharedindex();
-       sigchain_pop(signo);
-       raise(signo);
-}
+static struct tempfile temporary_sharedindex;
 
 static int write_shared_index(struct index_state *istate,
                              struct lock_file *lock, unsigned flags)
 {
        struct split_index *si = istate->split_index;
-       static int installed_handler;
        int fd, ret;
 
-       temporary_sharedindex = git_pathdup("sharedindex_XXXXXX");
-       fd = mkstemp(temporary_sharedindex);
+       fd = mks_tempfile(&temporary_sharedindex, git_path("sharedindex_XXXXXX"));
        if (fd < 0) {
-               free(temporary_sharedindex);
-               temporary_sharedindex = NULL;
                hashclr(si->base_sha1);
                return do_write_locked_index(istate, lock, flags);
        }
-       if (!installed_handler) {
-               atexit(remove_temporary_sharedindex);
-               sigchain_push_common(remove_temporary_sharedindex_on_signal);
-       }
        move_cache_to_base_index(istate);
        ret = do_write_index(si->base, fd, 1);
-       close(fd);
        if (ret) {
-               remove_temporary_sharedindex();
+               delete_tempfile(&temporary_sharedindex);
                return ret;
        }
-       ret = rename(temporary_sharedindex,
-                    git_path("sharedindex.%s", sha1_to_hex(si->base->sha1)));
-       free(temporary_sharedindex);
-       temporary_sharedindex = NULL;
+       ret = rename_tempfile(&temporary_sharedindex,
+                             git_path("sharedindex.%s", sha1_to_hex(si->base->sha1)));
        if (!ret)
                hashcpy(si->base_sha1, si->base->sha1);
        return ret;
diff --git a/refs.c b/refs.c
index ce8cd8d..4e15f60 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -19,12 +19,14 @@ struct ref_lock {
  * 1: End-of-component
  * 2: ., look for a preceding . to reject .. in refs
  * 3: {, look for a preceding @ to reject @{ in refs
- * 4: A bad character: ASCII control characters, "~", "^", ":" or SP
+ * 4: A bad character: ASCII control characters, and
+ *    ":", "?", "[", "\", "^", "~", SP, or TAB
+ * 5: *, reject unless REFNAME_REFSPEC_PATTERN is set
  */
 static unsigned char refname_disposition[256] = {
        1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
        4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
-       4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 2, 1,
+       4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 2, 1,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 4,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 4, 0,
@@ -62,6 +64,11 @@ static unsigned char refname_disposition[256] = {
  */
 #define REF_NEEDS_COMMIT 0x20
 
+/*
+ * 0x40 is REF_FORCE_CREATE_REFLOG, so skip it if you're adding a
+ * value to ref_update::flags
+ */
+
 /*
  * Try to read one refname component from the front of refname.
  * Return the length of the component found, or -1 if the component is
@@ -70,12 +77,14 @@ static unsigned char refname_disposition[256] = {
  *
  * - any path component of it begins with ".", or
  * - it has double dots "..", or
- * - it has ASCII control character, "~", "^", ":" or SP, anywhere, or
- * - it ends with a "/".
- * - it ends with ".lock"
- * - it contains a "\" (backslash)
+ * - it has ASCII control characters, or
+ * - it has ":", "?", "[", "\", "^", "~", SP, or TAB anywhere, or
+ * - it has "*" anywhere unless REFNAME_REFSPEC_PATTERN is set, or
+ * - it ends with a "/", or
+ * - it ends with ".lock", or
+ * - it contains a "@{" portion
  */
-static int check_refname_component(const char *refname, int flags)
+static int check_refname_component(const char *refname, int *flags)
 {
        const char *cp;
        char last = '\0';
@@ -96,6 +105,16 @@ static int check_refname_component(const char *refname, int flags)
                        break;
                case 4:
                        return -1;
+               case 5:
+                       if (!(*flags & REFNAME_REFSPEC_PATTERN))
+                               return -1; /* refspec can't be a pattern */
+
+                       /*
+                        * Unset the pattern flag so that we only accept
+                        * a single asterisk for one side of refspec.
+                        */
+                       *flags &= ~ REFNAME_REFSPEC_PATTERN;
+                       break;
                }
                last = ch;
        }
@@ -120,18 +139,10 @@ int check_refname_format(const char *refname, int flags)
 
        while (1) {
                /* We are at the start of a path component. */
-               component_len = check_refname_component(refname, flags);
-               if (component_len <= 0) {
-                       if ((flags & REFNAME_REFSPEC_PATTERN) &&
-                                       refname[0] == '*' &&
-                                       (refname[1] == '\0' || refname[1] == '/')) {
-                               /* Accept one wildcard as a full refname component. */
-                               flags &= ~REFNAME_REFSPEC_PATTERN;
-                               component_len = 1;
-                       } else {
-                               return -1;
-                       }
-               }
+               component_len = check_refname_component(refname, &flags);
+               if (component_len <= 0)
+                       return -1;
+
                component_count++;
                if (refname[component_len] == '\0')
                        break;
@@ -1277,12 +1288,12 @@ static void read_packed_refs(FILE *f, struct ref_dir *dir)
  */
 static struct packed_ref_cache *get_packed_ref_cache(struct ref_cache *refs)
 {
-       const char *packed_refs_file;
+       char *packed_refs_file;
 
        if (*refs->name)
-               packed_refs_file = git_path_submodule(refs->name, "packed-refs");
+               packed_refs_file = git_pathdup_submodule(refs->name, "packed-refs");
        else
-               packed_refs_file = git_path("packed-refs");
+               packed_refs_file = git_pathdup("packed-refs");
 
        if (refs->packed &&
            !stat_validity_check(&refs->packed->validity, packed_refs_file))
@@ -1301,6 +1312,7 @@ static struct packed_ref_cache *get_packed_ref_cache(struct ref_cache *refs)
                        fclose(f);
                }
        }
+       free(packed_refs_file);
        return refs->packed;
 }
 
@@ -1340,19 +1352,23 @@ static void read_loose_refs(const char *dirname, struct ref_dir *dir)
 {
        struct ref_cache *refs = dir->ref_cache;
        DIR *d;
-       const char *path;
        struct dirent *de;
        int dirnamelen = strlen(dirname);
        struct strbuf refname;
+       struct strbuf path = STRBUF_INIT;
+       size_t path_baselen;
 
        if (*refs->name)
-               path = git_path_submodule(refs->name, "%s", dirname);
+               strbuf_git_path_submodule(&path, refs->name, "%s", dirname);
        else
-               path = git_path("%s", dirname);
+               strbuf_git_path(&path, "%s", dirname);
+       path_baselen = path.len;
 
-       d = opendir(path);
-       if (!d)
+       d = opendir(path.buf);
+       if (!d) {
+               strbuf_release(&path);
                return;
+       }
 
        strbuf_init(&refname, dirnamelen + 257);
        strbuf_add(&refname, dirname, dirnamelen);
@@ -1361,17 +1377,14 @@ static void read_loose_refs(const char *dirname, struct ref_dir *dir)
                unsigned char sha1[20];
                struct stat st;
                int flag;
-               const char *refdir;
 
                if (de->d_name[0] == '.')
                        continue;
                if (ends_with(de->d_name, ".lock"))
                        continue;
                strbuf_addstr(&refname, de->d_name);
-               refdir = *refs->name
-                       ? git_path_submodule(refs->name, "%s", refname.buf)
-                       : git_path("%s", refname.buf);
-               if (stat(refdir, &st) < 0) {
+               strbuf_addstr(&path, de->d_name);
+               if (stat(path.buf, &st) < 0) {
                        ; /* silently ignore */
                } else if (S_ISDIR(st.st_mode)) {
                        strbuf_addch(&refname, '/');