Imported Upstream version 2.30.1 upstream upstream/2.30.1
authorDongHun Kwak <dh0128.kwak@samsung.com>
Wed, 3 Mar 2021 06:17:24 +0000 (15:17 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Wed, 3 Mar 2021 06:17:24 +0000 (15:17 +0900)
72 files changed:
.github/workflows/main.yml
Documentation/RelNotes/2.30.1.txt [new file with mode: 0644]
Documentation/SubmittingPatches
Documentation/config/http.txt
Documentation/config/trace2.txt
Documentation/git-clone.txt
Documentation/git-fsck.txt
Documentation/git-ls-files.txt
Documentation/git-maintenance.txt
Documentation/git-p4.txt
Documentation/git-send-email.txt
Documentation/git-status.txt
Documentation/git-update-index.txt
Documentation/githooks.txt
Documentation/gitmodules.txt
Documentation/technical/pack-format.txt
Documentation/technical/packfile-uri.txt
Documentation/technical/reftable.txt
GIT-VERSION-GEN
Makefile
RelNotes
builtin/am.c
builtin/blame.c
builtin/branch.c
builtin/commit-graph.c
builtin/fast-export.c
builtin/for-each-ref.c
builtin/for-each-repo.c
builtin/gc.c
builtin/log.c
builtin/rebase.c
builtin/shortlog.c
builtin/stash.c
builtin/submodule--helper.c
builtin/tag.c
ci/install-dependencies.sh
commit-graph.c
connect.c
fsck.c
gettext.c
git-mergetool--lib.sh
git-p4.py
midx.c
parse-options.h
patch-ids.c
patch-ids.h
read-cache.c
ref-filter.c
ref-filter.h
refs/files-backend.c
revision.c
submodule.c
t/annotate-tests.sh
t/lib-submodule-update.sh
t/perf/p5303-many-packs.sh
t/perf/p7519-fsmonitor.sh
t/t0068-for-each-repo.sh
t/t1300-config.sh
t/t3203-branch-output.sh
t/t4129-apply-samemode.sh
t/t5516-fetch-push.sh
t/t5526-fetch-submodules.sh
t/t5570-git-daemon.sh
t/t6007-rev-list-cherry-pick-file.sh
t/t6016-rev-list-graph-simplify-history.sh
t/t6030-bisect-porcelain.sh
t/t7012-skip-worktree-writing.sh
t/t7416-submodule-dash-url.sh
t/t7610-mergetool.sh
t/test-lib-functions.sh
wt-status.c
wt-status.h

index aef6643..f6885e8 100644 (file)
@@ -123,6 +123,7 @@ jobs:
     runs-on: windows-latest
     needs: [windows-build]
     strategy:
+      fail-fast: false
       matrix:
         nr: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
     steps:
@@ -227,6 +228,7 @@ jobs:
     runs-on: windows-latest
     needs: [vs-build, windows-build]
     strategy:
+      fail-fast: false
       matrix:
         nr: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
     steps:
@@ -272,6 +274,7 @@ jobs:
     needs: ci-config
     if: needs.ci-config.outputs.enabled == 'yes'
     strategy:
+      fail-fast: false
       matrix:
         vector:
           - jobname: linux-clang
@@ -309,6 +312,7 @@ jobs:
     needs: ci-config
     if: needs.ci-config.outputs.enabled == 'yes'
     strategy:
+      fail-fast: false
       matrix:
         vector:
         - jobname: linux-musl
diff --git a/Documentation/RelNotes/2.30.1.txt b/Documentation/RelNotes/2.30.1.txt
new file mode 100644 (file)
index 0000000..249ef14
--- /dev/null
@@ -0,0 +1,55 @@
+Git v2.30.1 Release Notes
+=========================
+
+This release is primarily to merge fixes accumulated on the 'master'
+front to prepare for 2.31 release that are still relevant to 2.30.x
+maintenance track.
+
+Fixes since v2.30
+-----------------
+
+ * "git fetch --recurse-submodules" failed to update a submodule
+   when it has an uninitialized (hence of no interest to the user)
+   sub-submodule, which has been corrected.
+
+ * Command line error of "git rebase" are diagnosed earlier.
+
+ * "git stash" did not work well in a sparsely checked out working
+   tree.
+
+ * Some tests expect that "ls -l" output has either '-' or 'x' for
+   group executable bit, but setgid bit can be inherited from parent
+   directory and make these fields 'S' or 's' instead, causing test
+   failures.
+
+ * "git for-each-repo --config=<var> <cmd>" should not run <cmd> for
+   any repository when the configuration variable <var> is not defined
+   even once.
+
+ * "git mergetool --tool-help" was broken in 2.29 and failed to list
+   all the available tools.
+
+ * Fix for procedure to building CI test environment for mac.
+
+ * Newline characters in the host and path part of git:// URL are
+   now forbidden.
+
+ * When more than one commit with the same patch ID appears on one
+   side, "git log --cherry-pick A...B" did not exclude them all when a
+   commit with the same patch ID appears on the other side.  Now it
+   does.
+
+ * Documentation for "git fsck" lost stale bits that has become
+   incorrect.
+
+ * Doc for packfile URI feature has been clarified.
+
+ * The implementation of "git branch --sort" wrt the detached HEAD
+   display has always been hacky, which has been cleaned up.
+
+ * Our setting of GitHub CI test jobs were a bit too eager to give up
+   once there is even one failure found.  Tweak the knob to allow
+   other jobs keep running even when we see a failure, so that we can
+   find more failures in a single run.
+
+Also contains minor documentation updates and code clean-ups.
index d12094b..0452db2 100644 (file)
@@ -307,7 +307,7 @@ wrote the patch or have the right to pass it on under the same license
 as ours, by "signing off" your patch.  Without sign-off, we cannot
 accept your patches.
 
-If you can certify the below D-C-O:
+If (and only if) you certify the below D-C-O:
 
 [[dco]]
 .Developer's Certificate of Origin 1.1
index 3968fbb..7003661 100644 (file)
@@ -42,12 +42,12 @@ http.proxySSLKey::
 http.proxySSLCertPasswordProtected::
        Enable Git's password prompt for the proxy SSL certificate.  Otherwise OpenSSL
        will prompt the user, possibly many times, if the certificate or private key
-       is encrypted. Can be overriden by the `GIT_PROXY_SSL_CERT_PASSWORD_PROTECTED`
+       is encrypted. Can be overridden by the `GIT_PROXY_SSL_CERT_PASSWORD_PROTECTED`
        environment variable.
 
 http.proxySSLCAInfo::
        Pathname to the file containing the certificate bundle that should be used to
-       verify the proxy with when using an HTTPS proxy. Can be overriden by the
+       verify the proxy with when using an HTTPS proxy. Can be overridden by the
        `GIT_PROXY_SSL_CAINFO` environment variable.
 
 http.emptyAuth::
index 01d3afd..fe1642f 100644 (file)
@@ -54,7 +54,7 @@ trace2.envVars::
        `GIT_HTTP_USER_AGENT,GIT_CONFIG` would cause the trace2 output to
        contain events listing the overrides for HTTP user agent and the
        location of the Git configuration file (assuming any are set).  May be
-       overriden by the `GIT_TRACE2_ENV_VARS` environment variable.  Unset by
+       overridden by the `GIT_TRACE2_ENV_VARS` environment variable.  Unset by
        default.
 
 trace2.destinationDebug::
index 876aedc..02d9c19 100644 (file)
@@ -57,6 +57,10 @@ repository is specified as a URL, then this flag is ignored (and we
 never use the local optimizations).  Specifying `--no-local` will
 override the default when `/path/to/repo` is given, using the regular
 Git transport instead.
++
+*NOTE*: this operation can race with concurrent modification to the
+source repository, similar to running `cp -r src dst` while modifying
+`src`.
 
 --no-hardlinks::
        Force the cloning process from a repository on a local
index d72d15b..bd59661 100644 (file)
@@ -129,14 +129,6 @@ using 'git commit-graph verify'. See linkgit:git-commit-graph[1].
 Extracted Diagnostics
 ---------------------
 
-expect dangling commits - potential heads - due to lack of head information::
-       You haven't specified any nodes as heads so it won't be
-       possible to differentiate between un-parented commits and
-       root nodes.
-
-missing sha1 directory '<dir>'::
-       The directory holding the sha1 objects is missing.
-
 unreachable <type> <object>::
        The <type> object <object>, isn't actually referred to directly
        or indirectly in any of the trees or commits seen. This can
index cbcf526..0a3b526 100644 (file)
@@ -23,9 +23,8 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
-This merges the file listing in the directory cache index with the
-actual working directory list, and shows different combinations of the
-two.
+This merges the file listing in the index with the actual working
+directory list, and shows different combinations of the two.
 
 One or more of the options below may be used to determine the files
 shown:
index d1f9b51..6fe1e5e 100644 (file)
@@ -38,7 +38,7 @@ register::
        for running in the background without disrupting foreground
        processes.
 +
-The `register` subcomand will also set the `maintenance.strategy` config
+The `register` subcommand will also set the `maintenance.strategy` config
 value to `incremental`, if this value is not previously set. The
 `incremental` strategy uses the following schedule for each maintenance
 task:
index ec233ac..f89e68b 100644 (file)
@@ -397,7 +397,7 @@ changelist text. Exiting with a non-zero status from the script
 will abort the process.
 
 The purpose of the hook is to edit the message file in place,
-and it is not supressed by the `--no-verify` option. This hook
+and it is not suppressed by the `--no-verify` option. This hook
 is called even if `--prepare-p4-only` is set.
 
 p4-changelist
index b7bbbea..93708ae 100644 (file)
@@ -494,10 +494,14 @@ edit ~/.gitconfig to specify your account settings:
        smtpServerPort = 587
 ----
 
-If you have multifactor authentication setup on your gmail account, you will
+If you have multi-factor authentication set up on your Gmail account, you will
 need to generate an app-specific password for use with 'git send-email'. Visit
 https://security.google.com/settings/security/apppasswords to create it.
 
+If you do not have multi-factor authentication set up on your Gmail account,
+you will need to allow less secure app access. Visit
+https://myaccount.google.com/lesssecureapps to enable it.
+
 Once your commits are ready to be sent to the mailing list, run the
 following commands:
 
index 7731b45..c0764e8 100644 (file)
@@ -184,11 +184,26 @@ characters, that field will be quoted in the manner of a C string
 literal: surrounded by ASCII double quote (34) characters, and with
 interior special characters backslash-escaped.
 
-For paths with merge conflicts, `X` and `Y` show the modification
-states of each side of the merge. For paths that do not have merge
-conflicts, `X` shows the status of the index, and `Y` shows the status
-of the work tree.  For untracked paths, `XY` are `??`.  Other status
-codes can be interpreted as follows:
+There are three different types of states that are shown using this format, and
+each one uses the `XY` syntax differently:
+
+* When a merge is occurring and the merge was successful, or outside of a merge
+       situation, `X` shows the status of the index and `Y` shows the status of the
+       working tree.
+* When a merge conflict has occurred and has not yet been resolved, `X` and `Y`
+       show the state introduced by each head of the merge, relative to the common
+       ancestor. These paths are said to be _unmerged_.
+* When a path is untracked, `X` and `Y` are always the same, since they are
+       unknown to the index. `??` is used for untracked paths. Ignored files are
+       not listed unless `--ignored` is used; if it is, ignored files are indicated
+       by `!!`.
+
+Note that the term _merge_ here also includes rebases using the default
+`--merge` strategy, cherry-picks, and anything else using the merge machinery.
+
+In the following table, these three classes are shown in separate sections, and
+these characters are used for `X` and `Y` fields for the first two sections that
+show tracked paths:
 
 * ' ' = unmodified
 * 'M' = modified
@@ -198,9 +213,6 @@ codes can be interpreted as follows:
 * 'C' = copied
 * 'U' = updated but unmerged
 
-Ignored files are not listed, unless `--ignored` option is in effect,
-in which case `XY` are `!!`.
-
 ....
 X          Y     Meaning
 -------------------------------------------------
index 1489cb0..2853f16 100644 (file)
@@ -30,9 +30,8 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
-Modifies the index or directory cache. Each file mentioned is updated
-into the index and any 'unmerged' or 'needs updating' state is
-cleared.
+Modifies the index. Each file mentioned is updated into the index and
+any 'unmerged' or 'needs updating' state is cleared.
 
 See also linkgit:git-add[1] for a more user-friendly way to do some of
 the most common operations on the index.
index ffccfc7..1f3b57d 100644 (file)
@@ -644,7 +644,7 @@ changelist text. Exiting with a non-zero status from the script
 will abort the process.
 
 The purpose of the hook is to edit the message file in place,
-and it is not supressed by the `--no-verify` option. This hook
+and it is not suppressed by the `--no-verify` option. This hook
 is called even if `--prepare-p4-only` is set.
 
 Run `git-p4 submit --help` for details.
index 539b4e1..8e333dd 100644 (file)
@@ -7,7 +7,7 @@ gitmodules - Defining submodule properties
 
 SYNOPSIS
 --------
-$GIT_WORK_DIR/.gitmodules
+$GIT_WORK_TREE/.gitmodules
 
 
 DESCRIPTION
@@ -27,19 +27,19 @@ submodule.<name>.path::
        Defines the path, relative to the top-level directory of the Git
        working tree, where the submodule is expected to be checked out.
        The path name must not end with a `/`. All submodule paths must
-       be unique within the .gitmodules file.
+       be unique within the `.gitmodules` file.
 
 submodule.<name>.url::
        Defines a URL from which the submodule repository can be cloned.
        This may be either an absolute URL ready to be passed to
-       linkgit:git-clone[1] or (if it begins with ./ or ../) a location
+       linkgit:git-clone[1] or (if it begins with `./` or `../`) a location
        relative to the superproject's origin repository.
 
 In addition, there are a number of optional keys:
 
 submodule.<name>.update::
        Defines the default update procedure for the named submodule,
-       i.e. how the submodule is updated by "git submodule update"
+       i.e. how the submodule is updated by the `git submodule update`
        command in the superproject. This is only used by `git
        submodule init` to initialize the configuration variable of
        the same name. Allowed values here are 'checkout', 'rebase',
@@ -49,7 +49,7 @@ submodule.<name>.update::
 
 submodule.<name>.branch::
        A remote branch name for tracking updates in the upstream submodule.
-       If the option is not specified, it defaults to the remote 'HEAD'.
+       If the option is not specified, it defaults to the remote `HEAD`.
        A special value of `.` is used to indicate that the name of the branch
        in the submodule should be the same name as the current branch in the
        current repository.  See the `--remote` documentation in
@@ -57,14 +57,14 @@ submodule.<name>.branch::
 
 submodule.<name>.fetchRecurseSubmodules::
        This option can be used to control recursive fetching of this
-       submodule. If this option is also present in the submodules entry in
-       .git/config of the superproject, the setting there will override the
-       one found in .gitmodules.
+       submodule. If this option is also present in the submodule's entry in
+       `.git/config` of the superproject, the setting there will override the
+       one found in `.gitmodules`.
        Both settings can be overridden on the command line by using the
-       "--[no-]recurse-submodules" option to "git fetch" and "git pull".
+       `--[no-]recurse-submodules` option to `git fetch` and `git pull`.
 
 submodule.<name>.ignore::
-       Defines under what circumstances "git status" and the diff family show
+       Defines under what circumstances `git status` and the diff family show
        a submodule as modified. The following values are supported:
 +
 --
@@ -73,7 +73,7 @@ submodule.<name>.ignore::
            been staged).
 
        dirty;; All changes to the submodule's work tree will be ignored, only
-           committed differences between the HEAD of the submodule and its
+           committed differences between the `HEAD` of the submodule and its
            recorded state in the superproject are taken into account.
 
        untracked;; Only untracked files in submodules will be ignored.
@@ -84,12 +84,12 @@ submodule.<name>.ignore::
            differences, and modifications to tracked and untracked files are
            shown. This is the default option.
 
-If this option is also present in the submodules entry in .git/config
+If this option is also present in the submodule's entry in `.git/config`
 of the superproject, the setting there will override the one found in
-.gitmodules.
+`.gitmodules`.
 
 Both settings can be overridden on the command line by using the
-"--ignore-submodules" option. The 'git submodule' commands are not
+`--ignore-submodules` option. The `git submodule` commands are not
 affected by this setting.
 --
 
@@ -102,7 +102,7 @@ submodule.<name>.shallow::
 EXAMPLES
 --------
 
-Consider the following .gitmodules file:
+Consider the following `.gitmodules` file:
 
 ----
 [submodule "libfoo"]
index f96b2e6..96d2fc5 100644 (file)
@@ -55,6 +55,18 @@ Valid object types are:
 
 Type 5 is reserved for future expansion. Type 0 is invalid.
 
+=== Size encoding
+
+This document uses the following "size encoding" of non-negative
+integers: From each byte, the seven least significant bits are
+used to form the resulting integer. As long as the most significant
+bit is 1, this process continues; the byte with MSB 0 provides the
+last seven bits.  The seven-bit chunks are concatenated. Later
+values are more significant.
+
+This size encoding should not be confused with the "offset encoding",
+which is also used in this document.
+
 === Deltified representation
 
 Conceptually there are only four object types: commit, tree, tag and
@@ -73,7 +85,10 @@ Ref-delta can also refer to an object outside the pack (i.e. the
 so-called "thin pack"). When stored on disk however, the pack should
 be self contained to avoid cyclic dependency.
 
-The delta data is a sequence of instructions to reconstruct an object
+The delta data starts with the size of the base object and the
+size of the object to be reconstructed. These sizes are
+encoded using the size encoding from above.  The remainder of
+the delta data is a sequence of instructions to reconstruct the object
 from the base object. If the base object is deltified, it must be
 converted to canonical form first. Each instruction appends more and
 more data to the target object until it's complete. There are two
index 318713a..f7eabc6 100644 (file)
@@ -37,8 +37,11 @@ at least so that we can test the client.
 This is the implementation: a feature, marked experimental, that allows the
 server to be configured by one or more `uploadpack.blobPackfileUri=<sha1>
 <uri>` entries. Whenever the list of objects to be sent is assembled, all such
-blobs are excluded, replaced with URIs. The client will download those URIs,
-expecting them to each point to packfiles containing single blobs.
+blobs are excluded, replaced with URIs. As noted in "Future work" below, the
+server can evolve in the future to support excluding other objects (or other
+implementations of servers could be made that support excluding other objects)
+without needing a protocol change, so clients should not expect that packfiles
+downloaded in this way only contain single blobs.
 
 Client design
 -------------
index 2951840..8095ab2 100644 (file)
@@ -446,7 +446,7 @@ especially if readers will not use the object name to ref mapping.
 Object blocks use unique, abbreviated 2-32 object name keys, mapping to
 ref blocks containing references pointing to that object directly, or as
 the peeled value of an annotated tag. Like ref blocks, object blocks use
-the file's standard block size. The abbrevation length is available in
+the file's standard block size. The abbreviation length is available in
 the footer as `obj_id_len`.
 
 To save space in small files, object blocks may be omitted if the ref
index 5085ef1..b0019d4 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v2.30.0
+DEF_VER=v2.30.1
 
 LF='
 '
index 7b64106..4128b45 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -777,20 +777,6 @@ BUILT_INS += git-status$X
 BUILT_INS += git-switch$X
 BUILT_INS += git-whatchanged$X
 
-# what 'all' will build and 'install' will install in gitexecdir,
-# excluding programs for built-in commands
-ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
-ALL_COMMANDS_TO_INSTALL = $(ALL_PROGRAMS)
-ifeq (,$(SKIP_DASHED_BUILT_INS))
-ALL_COMMANDS_TO_INSTALL += $(BUILT_INS)
-else
-# git-upload-pack, git-receive-pack and git-upload-archive are special: they
-# are _expected_ to be present in the `bin/` directory in their dashed form.
-ALL_COMMANDS_TO_INSTALL += git-receive-pack$(X)
-ALL_COMMANDS_TO_INSTALL += git-upload-archive$(X)
-ALL_COMMANDS_TO_INSTALL += git-upload-pack$(X)
-endif
-
 # what 'all' will build but not install in gitexecdir
 OTHER_PROGRAMS = git$X
 
@@ -1226,6 +1212,20 @@ ifdef DEVELOPER
 include config.mak.dev
 endif
 
+# what 'all' will build and 'install' will install in gitexecdir,
+# excluding programs for built-in commands
+ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
+ALL_COMMANDS_TO_INSTALL = $(ALL_PROGRAMS)
+ifeq (,$(SKIP_DASHED_BUILT_INS))
+ALL_COMMANDS_TO_INSTALL += $(BUILT_INS)
+else
+# git-upload-pack, git-receive-pack and git-upload-archive are special: they
+# are _expected_ to be present in the `bin/` directory in their dashed form.
+ALL_COMMANDS_TO_INSTALL += git-receive-pack$(X)
+ALL_COMMANDS_TO_INSTALL += git-upload-archive$(X)
+ALL_COMMANDS_TO_INSTALL += git-upload-pack$(X)
+endif
+
 ALL_CFLAGS = $(DEVELOPER_CFLAGS) $(CPPFLAGS) $(CFLAGS)
 ALL_LDFLAGS = $(LDFLAGS)
 
@@ -1554,9 +1554,6 @@ endif
 ifdef NO_SYMLINK_HEAD
        BASIC_CFLAGS += -DNO_SYMLINK_HEAD
 endif
-ifdef GETTEXT_POISON
-$(warning The GETTEXT_POISON option has been removed in favor of runtime GIT_TEST_GETTEXT_POISON. See t/README!)
-endif
 ifdef NO_GETTEXT
        BASIC_CFLAGS += -DNO_GETTEXT
        USE_GETTEXT_SCHEME ?= fallthrough
index dc8c04b..679c206 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.30.0.txt
\ No newline at end of file
+Documentation/RelNotes/2.30.1.txt
\ No newline at end of file
index f22c73a..8355e35 100644 (file)
@@ -2284,10 +2284,10 @@ int cmd_am(int argc, const char **argv, const char *prefix)
                        N_("skip the current patch"),
                        RESUME_SKIP),
                OPT_CMDMODE(0, "abort", &resume.mode,
-                       N_("restore the original branch and abort the patching operation."),
+                       N_("restore the original branch and abort the patching operation"),
                        RESUME_ABORT),
                OPT_CMDMODE(0, "quit", &resume.mode,
-                       N_("abort the patching operation but keep HEAD where it is."),
+                       N_("abort the patching operation but keep HEAD where it is"),
                        RESUME_QUIT),
                { OPTION_CALLBACK, 0, "show-current-patch", &resume.mode,
                  "(diff|raw)",
index 6f7e324..2c1c02c 100644 (file)
@@ -866,33 +866,33 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
        const char *revs_file = NULL;
        const char *contents_from = NULL;
        const struct option options[] = {
-               OPT_BOOL(0, "incremental", &incremental, N_("Show blame entries as we find them, incrementally")),
-               OPT_BOOL('b', NULL, &blank_boundary, N_("Do not show object names of boundary commits (Default: off)")),
-               OPT_BOOL(0, "root", &show_root, N_("Do not treat root commits as boundaries (Default: off)")),
-               OPT_BOOL(0, "show-stats", &show_stats, N_("Show work cost statistics")),
-               OPT_BOOL(0, "progress", &show_progress, N_("Force progress reporting")),
-               OPT_BIT(0, "score-debug", &output_option, N_("Show output score for blame entries"), OUTPUT_SHOW_SCORE),
-               OPT_BIT('f', "show-name", &output_option, N_("Show original filename (Default: auto)"), OUTPUT_SHOW_NAME),
-               OPT_BIT('n', "show-number", &output_option, N_("Show original linenumber (Default: off)"), OUTPUT_SHOW_NUMBER),
-               OPT_BIT('p', "porcelain", &output_option, N_("Show in a format designed for machine consumption"), OUTPUT_PORCELAIN),
-               OPT_BIT(0, "line-porcelain", &output_option, N_("Show porcelain format with per-line commit information"), OUTPUT_PORCELAIN|OUTPUT_LINE_PORCELAIN),
-               OPT_BIT('c', NULL, &output_option, N_("Use the same output mode as git-annotate (Default: off)"), OUTPUT_ANNOTATE_COMPAT),
-               OPT_BIT('t', NULL, &output_option, N_("Show raw timestamp (Default: off)"), OUTPUT_RAW_TIMESTAMP),
-               OPT_BIT('l', NULL, &output_option, N_("Show long commit SHA1 (Default: off)"), OUTPUT_LONG_OBJECT_NAME),
-               OPT_BIT('s', NULL, &output_option, N_("Suppress author name and timestamp (Default: off)"), OUTPUT_NO_AUTHOR),
-               OPT_BIT('e', "show-email", &output_option, N_("Show author email instead of name (Default: off)"), OUTPUT_SHOW_EMAIL),
-               OPT_BIT('w', NULL, &xdl_opts, N_("Ignore whitespace differences"), XDF_IGNORE_WHITESPACE),
-               OPT_STRING_LIST(0, "ignore-rev", &ignore_rev_list, N_("rev"), N_("Ignore <rev> when blaming")),
-               OPT_STRING_LIST(0, "ignore-revs-file", &ignore_revs_file_list, N_("file"), N_("Ignore revisions from <file>")),
+               OPT_BOOL(0, "incremental", &incremental, N_("show blame entries as we find them, incrementally")),
+               OPT_BOOL('b', NULL, &blank_boundary, N_("do not show object names of boundary commits (Default: off)")),
+               OPT_BOOL(0, "root", &show_root, N_("do not treat root commits as boundaries (Default: off)")),
+               OPT_BOOL(0, "show-stats", &show_stats, N_("show work cost statistics")),
+               OPT_BOOL(0, "progress", &show_progress, N_("force progress reporting")),
+               OPT_BIT(0, "score-debug", &output_option, N_("show output score for blame entries"), OUTPUT_SHOW_SCORE),
+               OPT_BIT('f', "show-name", &output_option, N_("show original filename (Default: auto)"), OUTPUT_SHOW_NAME),
+               OPT_BIT('n', "show-number", &output_option, N_("show original linenumber (Default: off)"), OUTPUT_SHOW_NUMBER),
+               OPT_BIT('p', "porcelain", &output_option, N_("show in a format designed for machine consumption"), OUTPUT_PORCELAIN),
+               OPT_BIT(0, "line-porcelain", &output_option, N_("show porcelain format with per-line commit information"), OUTPUT_PORCELAIN|OUTPUT_LINE_PORCELAIN),
+               OPT_BIT('c', NULL, &output_option, N_("use the same output mode as git-annotate (Default: off)"), OUTPUT_ANNOTATE_COMPAT),
+               OPT_BIT('t', NULL, &output_option, N_("show raw timestamp (Default: off)"), OUTPUT_RAW_TIMESTAMP),
+               OPT_BIT('l', NULL, &output_option, N_("show long commit SHA1 (Default: off)"), OUTPUT_LONG_OBJECT_NAME),
+               OPT_BIT('s', NULL, &output_option, N_("suppress author name and timestamp (Default: off)"), OUTPUT_NO_AUTHOR),
+               OPT_BIT('e', "show-email", &output_option, N_("show author email instead of name (Default: off)"), OUTPUT_SHOW_EMAIL),
+               OPT_BIT('w', NULL, &xdl_opts, N_("ignore whitespace differences"), XDF_IGNORE_WHITESPACE),
+               OPT_STRING_LIST(0, "ignore-rev", &ignore_rev_list, N_("rev"), N_("ignore <rev> when blaming")),
+               OPT_STRING_LIST(0, "ignore-revs-file", &ignore_revs_file_list, N_("file"), N_("ignore revisions from <file>")),
                OPT_BIT(0, "color-lines", &output_option, N_("color redundant metadata from previous line differently"), OUTPUT_COLOR_LINE),
                OPT_BIT(0, "color-by-age", &output_option, N_("color lines by age"), OUTPUT_SHOW_AGE_WITH_COLOR),
-               OPT_BIT(0, "minimal", &xdl_opts, N_("Spend extra cycles to find better match"), XDF_NEED_MINIMAL),
-               OPT_STRING('S', NULL, &revs_file, N_("file"), N_("Use revisions from <file> instead of calling git-rev-list")),
-               OPT_STRING(0, "contents", &contents_from, N_("file"), N_("Use <file>'s contents as the final image")),
-               OPT_CALLBACK_F('C', NULL, &opt, N_("score"), N_("Find line copies within and across files"), PARSE_OPT_OPTARG, blame_copy_callback),
-               OPT_CALLBACK_F('M', NULL, &opt, N_("score"), N_("Find line movements within and across files"), PARSE_OPT_OPTARG, blame_move_callback),
+               OPT_BIT(0, "minimal", &xdl_opts, N_("spend extra cycles to find better match"), XDF_NEED_MINIMAL),
+               OPT_STRING('S', NULL, &revs_file, N_("file"), N_("use revisions from <file> instead of calling git-rev-list")),
+               OPT_STRING(0, "contents", &contents_from, N_("file"), N_("use <file>'s contents as the final image")),
+               OPT_CALLBACK_F('C', NULL, &opt, N_("score"), N_("find line copies within and across files"), PARSE_OPT_OPTARG, blame_copy_callback),
+               OPT_CALLBACK_F('M', NULL, &opt, N_("score"), N_("find line movements within and across files"), PARSE_OPT_OPTARG, blame_move_callback),
                OPT_STRING_LIST('L', NULL, &range_list, N_("range"),
-                               N_("Process only line range <start>,<end> or function :<funcname>")),
+                               N_("process only line range <start>,<end> or function :<funcname>")),
                OPT__ABBREV(&abbrev),
                OPT_END()
        };
index 9b68591..8c0b428 100644 (file)
@@ -726,7 +726,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                print_current_branch_name();
                return 0;
        } else if (list) {
-               /*  git branch --local also shows HEAD when it is detached */
+               /*  git branch --list also shows HEAD when it is detached */
                if ((filter.kind & FILTER_REFS_BRANCHES) && filter.detached)
                        filter.kind |= FILTER_REFS_DETACHED_HEAD;
                filter.name_patterns = argv;
@@ -739,7 +739,9 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                 */
                if (!sorting)
                        sorting = ref_default_sorting();
-               ref_sorting_icase_all(sorting, icase);
+               ref_sorting_set_sort_flags_all(sorting, REF_SORTING_ICASE, icase);
+               ref_sorting_set_sort_flags_all(
+                       sorting, REF_SORTING_DETACHED_HEAD_FIRST, 1);
                print_ref_list(&filter, sorting, &format);
                print_columns(&output, colopts, NULL);
                string_list_clear(&output, 0);
index 78fa08f..cd86315 100644 (file)
@@ -78,7 +78,7 @@ static int graph_verify(int argc, const char **argv)
        static struct option builtin_commit_graph_verify_options[] = {
                OPT_STRING(0, "object-dir", &opts.obj_dir,
                           N_("dir"),
-                          N_("The object directory to store the graph")),
+                          N_("the object directory to store the graph")),
                OPT_BOOL(0, "shallow", &opts.shallow,
                         N_("if the commit-graph is split, only verify the tip file")),
                OPT_BOOL(0, "progress", &opts.progress, N_("force progress reporting")),
@@ -208,7 +208,7 @@ static int graph_write(int argc, const char **argv)
        static struct option builtin_commit_graph_write_options[] = {
                OPT_STRING(0, "object-dir", &opts.obj_dir,
                        N_("dir"),
-                       N_("The object directory to store the graph")),
+                       N_("the object directory to store the graph")),
                OPT_BOOL(0, "reachable", &opts.reachable,
                        N_("start walk at all refs")),
                OPT_BOOL(0, "stdin-packs", &opts.stdin_packs,
@@ -314,7 +314,7 @@ int cmd_commit_graph(int argc, const char **argv, const char *prefix)
        static struct option builtin_commit_graph_options[] = {
                OPT_STRING(0, "object-dir", &opts.obj_dir,
                        N_("dir"),
-                       N_("The object directory to store the graph")),
+                       N_("the object directory to store the graph")),
                OPT_END(),
        };
 
index 0a60356..85a76e0 100644 (file)
@@ -1205,32 +1205,32 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
                             N_("select handling of commit messages in an alternate encoding"),
                             parse_opt_reencode_mode),
                OPT_STRING(0, "export-marks", &export_filename, N_("file"),
-                            N_("Dump marks to this file")),
+                            N_("dump marks to this file")),
                OPT_STRING(0, "import-marks", &import_filename, N_("file"),
-                            N_("Import marks from this file")),
+                            N_("import marks from this file")),
                OPT_STRING(0, "import-marks-if-exists",
                             &import_filename_if_exists,
                             N_("file"),
-                            N_("Import marks from this file if it exists")),
+                            N_("import marks from this file if it exists")),
                OPT_BOOL(0, "fake-missing-tagger", &fake_missing_tagger,
-                        N_("Fake a tagger when tags lack one")),
+                        N_("fake a tagger when tags lack one")),
                OPT_BOOL(0, "full-tree", &full_tree,
-                        N_("Output full tree for each commit")),
+                        N_("output full tree for each commit")),
                OPT_BOOL(0, "use-done-feature", &use_done_feature,
-                            N_("Use the done feature to terminate the stream")),
-               OPT_BOOL(0, "no-data", &no_data, N_("Skip output of blob data")),
+                            N_("use the done feature to terminate the stream")),
+               OPT_BOOL(0, "no-data", &no_data, N_("skip output of blob data")),
                OPT_STRING_LIST(0, "refspec", &refspecs_list, N_("refspec"),
-                            N_("Apply refspec to exported refs")),
+                            N_("apply refspec to exported refs")),
                OPT_BOOL(0, "anonymize", &anonymize, N_("anonymize output")),
                OPT_CALLBACK_F(0, "anonymize-map", &anonymized_seeds, N_("from:to"),
                               N_("convert <from> to <to> in anonymized output"),
                               PARSE_OPT_NONEG, parse_opt_anonymize_map),
                OPT_BOOL(0, "reference-excluded-parents",
-                        &reference_excluded_commits, N_("Reference parents which are not in fast-export stream by object id")),
+                        &reference_excluded_commits, N_("reference parents which are not in fast-export stream by object id")),
                OPT_BOOL(0, "show-original-ids", &show_original_ids,
-                           N_("Show original object ids of blobs/commits")),
+                           N_("show original object ids of blobs/commits")),
                OPT_BOOL(0, "mark-tags", &mark_tags,
-                           N_("Label tags with mark ids")),
+                           N_("label tags with mark ids")),
 
                OPT_END()
        };
index 9d1ecda..cb9c81a 100644 (file)
@@ -70,7 +70,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
 
        if (!sorting)
                sorting = ref_default_sorting();
-       ref_sorting_icase_all(sorting, icase);
+       ref_sorting_set_sort_flags_all(sorting, REF_SORTING_ICASE, icase);
        filter.ignore_case = icase;
 
        filter.name_patterns = argv;
index 5bba623..52be64a 100644 (file)
@@ -51,6 +51,13 @@ int cmd_for_each_repo(int argc, const char **argv, const char *prefix)
        values = repo_config_get_value_multi(the_repository,
                                             config_key);
 
+       /*
+        * Do nothing on an empty list, which is equivalent to the case
+        * where the config variable does not exist at all.
+        */
+       if (!values)
+               return 0;
+
        for (i = 0; !result && i < values->nr; i++)
                result = run_command_on_repo(values->items[i].string, &args);
 
index 4c24f41..64f2b52 100644 (file)
@@ -92,7 +92,7 @@ static void process_log_file(void)
                 */
                int saved_errno = errno;
                fprintf(stderr, _("Failed to fstat %s: %s"),
-                       get_tempfile_path(log_lock.tempfile),
+                       get_lock_file_path(&log_lock),
                        strerror(saved_errno));
                fflush(stderr);
                commit_lock_file(&log_lock);
@@ -1518,7 +1518,7 @@ static int update_background_schedule(int run_maintenance)
        strvec_split(&crontab_list.args, crontab_name);
        strvec_push(&crontab_list.args, "-l");
        crontab_list.in = -1;
-       crontab_list.out = dup(lk.tempfile->fd);
+       crontab_list.out = dup(get_lock_file_fd(&lk));
        crontab_list.git_cmd = 0;
 
        if (start_command(&crontab_list)) {
@@ -1533,7 +1533,7 @@ static int update_background_schedule(int run_maintenance)
         * Read from the .lock file, filtering out the old
         * schedule while appending the new schedule.
         */
-       cron_list = fdopen(lk.tempfile->fd, "r");
+       cron_list = fdopen(get_lock_file_fd(&lk), "r");
        rewind(cron_list);
 
        strvec_split(&crontab_edit.args, crontab_name);
index bd6ff4f..f23ccdb 100644 (file)
@@ -177,7 +177,7 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
        const struct option builtin_log_options[] = {
                OPT__QUIET(&quiet, N_("suppress diff output")),
                OPT_BOOL(0, "source", &source, N_("show source")),
-               OPT_BOOL(0, "use-mailmap", &mailmap, N_("Use mail map file")),
+               OPT_BOOL(0, "use-mailmap", &mailmap, N_("use mail map file")),
                OPT_ALIAS(0, "mailmap", "use-mailmap"),
                OPT_STRING_LIST(0, "decorate-refs", &decorate_refs_include,
                                N_("pattern"), N_("only decorate refs that match <pattern>")),
@@ -186,7 +186,7 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
                OPT_CALLBACK_F(0, "decorate", NULL, NULL, N_("decorate options"),
                               PARSE_OPT_OPTARG, decorate_callback),
                OPT_CALLBACK('L', NULL, &line_cb, "range:file",
-                            N_("Trace the evolution of line range <start>,<end> or function :<funcname> in <file>"),
+                            N_("trace the evolution of line range <start>,<end> or function :<funcname> in <file>"),
                             log_line_range_callback),
                OPT_END()
        };
@@ -1757,13 +1757,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                OPT_INTEGER(0, "filename-max-length", &fmt_patch_name_max,
                            N_("max length of output filename")),
                OPT_CALLBACK_F(0, "rfc", &rev, NULL,
-                           N_("Use [RFC PATCH] instead of [PATCH]"),
+                           N_("use [RFC PATCH] instead of [PATCH]"),
                            PARSE_OPT_NOARG | PARSE_OPT_NONEG, rfc_callback),
                OPT_STRING(0, "cover-from-description", &cover_from_description_arg,
                            N_("cover-from-description-mode"),
                            N_("generate parts of a cover letter based on a branch's description")),
                OPT_CALLBACK_F(0, "subject-prefix", &rev, N_("prefix"),
-                           N_("Use [<prefix>] instead of [PATCH]"),
+                           N_("use [<prefix>] instead of [PATCH]"),
                            PARSE_OPT_NONEG, subject_prefix_callback),
                OPT_CALLBACK_F('o', "output-directory", &output_directory,
                            N_("dir"), N_("store resulting files in <dir>"),
index 19c7b37..840dbd7 100644 (file)
@@ -1917,7 +1917,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                        die_if_checked_out(buf.buf, 1);
                        options.head_name = xstrdup(buf.buf);
                /* If not is it a valid ref (branch or commit)? */
-               } else if (!get_oid(branch_name, &options.orig_head))
+               } else if (!get_oid(branch_name, &options.orig_head) &&
+                          lookup_commit_reference(the_repository,
+                                                  &options.orig_head))
                        options.head_name = NULL;
                else
                        die(_("fatal: no such branch/commit '%s'"),
index c52e4cc..1c0b3a9 100644 (file)
@@ -360,19 +360,19 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
 
        const struct option options[] = {
                OPT_BIT('c', "committer", &log.groups,
-                       N_("Group by committer rather than author"),
+                       N_("group by committer rather than author"),
                        SHORTLOG_GROUP_COMMITTER),
                OPT_BOOL('n', "numbered", &log.sort_by_number,
                         N_("sort output according to the number of commits per author")),
                OPT_BOOL('s', "summary", &log.summary,
-                        N_("Suppress commit descriptions, only provides commit count")),
+                        N_("suppress commit descriptions, only provides commit count")),
                OPT_BOOL('e', "email", &log.email,
-                        N_("Show the email address of each author")),
+                        N_("show the email address of each author")),
                OPT_CALLBACK_F('w', NULL, &log, N_("<w>[,<i1>[,<i2>]]"),
-                       N_("Linewrap output"), PARSE_OPT_OPTARG,
+                       N_("linewrap output"), PARSE_OPT_OPTARG,
                        &parse_wrap_args),
                OPT_CALLBACK(0, "group", &log, N_("field"),
-                       N_("Group by field"), parse_group_option),
+                       N_("group by field"), parse_group_option),
                OPT_END(),
        };
 
index e1f8235..9bc85f9 100644 (file)
@@ -325,35 +325,6 @@ static void add_diff_to_buf(struct diff_queue_struct *q,
        }
 }
 
-static int get_newly_staged(struct strbuf *out, struct object_id *c_tree)
-{
-       struct child_process cp = CHILD_PROCESS_INIT;
-       const char *c_tree_hex = oid_to_hex(c_tree);
-
-       /*
-        * diff-index is very similar to diff-tree above, and should be
-        * converted together with update_index.
-        */
-       cp.git_cmd = 1;
-       strvec_pushl(&cp.args, "diff-index", "--cached", "--name-only",
-                    "--diff-filter=A", NULL);
-       strvec_push(&cp.args, c_tree_hex);
-       return pipe_command(&cp, NULL, 0, out, 0, NULL, 0);
-}
-
-static int update_index(struct strbuf *out)
-{
-       struct child_process cp = CHILD_PROCESS_INIT;
-
-       /*
-        * Update-index is very complicated and may need to have a public
-        * function exposed in order to remove this forking.
-        */
-       cp.git_cmd = 1;
-       strvec_pushl(&cp.args, "update-index", "--add", "--stdin", NULL);
-       return pipe_command(&cp, out->buf, out->len, NULL, 0, NULL, 0);
-}
-
 static int restore_untracked(struct object_id *u_tree)
 {
        int res;
@@ -385,6 +356,121 @@ static int restore_untracked(struct object_id *u_tree)
        return res;
 }
 
+static void unstage_changes_unless_new(struct object_id *orig_tree)
+{
+       /*
+        * When we enter this function, there has been a clean merge of
+        * relevant trees, and the merge logic always stages whatever merges
+        * cleanly.  We want to unstage those changes, unless it corresponds
+        * to a file that didn't exist as of orig_tree.
+        *
+        * However, if any SKIP_WORKTREE path is modified relative to
+        * orig_tree, then we want to clear the SKIP_WORKTREE bit and write
+        * it to the worktree before unstaging.
+        */
+
+       struct checkout state = CHECKOUT_INIT;
+       struct diff_options diff_opts;
+       struct lock_file lock = LOCK_INIT;
+       int i;
+
+       /* If any entries have skip_worktree set, we'll have to check 'em out */
+       state.force = 1;
+       state.quiet = 1;
+       state.refresh_cache = 1;
+       state.istate = &the_index;
+
+       /*
+        * Step 1: get a difference between orig_tree (which corresponding
+        * to the index before a merge was run) and the current index
+        * (reflecting the changes brought in by the merge).
+        */
+       diff_setup(&diff_opts);
+       diff_opts.flags.recursive = 1;
+       diff_opts.detect_rename = 0;
+       diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
+       diff_setup_done(&diff_opts);
+
+       do_diff_cache(orig_tree, &diff_opts);
+       diffcore_std(&diff_opts);
+
+       /* Iterate over the paths that changed due to the merge... */
+       for (i = 0; i < diff_queued_diff.nr; i++) {
+               struct diff_filepair *p;
+               struct cache_entry *ce;
+               int pos;
+
+               /* Look up the path's position in the current index. */
+               p = diff_queued_diff.queue[i];
+               pos = index_name_pos(&the_index, p->two->path,
+                                    strlen(p->two->path));
+
+               /*
+                * Step 2: Place changes in the working tree
+                *
+                * Stash is about restoring changes *to the working tree*.
+                * So if the merge successfully got a new version of some
+                * path, but left it out of the working tree, then clear the
+                * SKIP_WORKTREE bit and write it to the working tree.
+                */
+               if (pos >= 0 && ce_skip_worktree(active_cache[pos])) {
+                       struct stat st;
+
+                       ce = active_cache[pos];
+                       if (!lstat(ce->name, &st)) {
+                               /* Conflicting path present; relocate it */
+                               struct strbuf new_path = STRBUF_INIT;
+                               int fd;
+
+                               strbuf_addf(&new_path,
+                                           "%s.stash.XXXXXX", ce->name);
+                               fd = xmkstemp(new_path.buf);
+                               close(fd);
+                               printf(_("WARNING: Untracked file in way of "
+                                        "tracked file!  Renaming\n "
+                                        "           %s -> %s\n"
+                                        "         to make room.\n"),
+                                      ce->name, new_path.buf);
+                               if (rename(ce->name, new_path.buf))
+                                       die("Failed to move %s to %s\n",
+                                           ce->name, new_path.buf);
+                               strbuf_release(&new_path);
+                       }
+                       checkout_entry(ce, &state, NULL, NULL);
+                       ce->ce_flags &= ~CE_SKIP_WORKTREE;
+               }
+
+               /*
+                * Step 3: "unstage" changes, as long as they are still tracked
+                */
+               if (p->one->oid_valid) {
+                       /*
+                        * Path existed in orig_tree; restore index entry
+                        * from that tree in order to "unstage" the changes.
+                        */
+                       int option = ADD_CACHE_OK_TO_REPLACE;
+                       if (pos < 0)
+                               option = ADD_CACHE_OK_TO_ADD;
+
+                       ce = make_cache_entry(&the_index,
+                                             p->one->mode,
+                                             &p->one->oid,
+                                             p->one->path,
+                                             0, 0);
+                       add_index_entry(&the_index, ce, option);
+               }
+       }
+       diff_flush(&diff_opts);
+
+       /*
+        * Step 4: write the new index to disk
+        */
+       repo_hold_locked_index(the_repository, &lock, LOCK_DIE_ON_ERROR);
+       if (write_locked_index(&the_index, &lock,
+                              COMMIT_LOCK | SKIP_IF_UNCHANGED))
+               die(_("Unable to write index."));
+}
+
 static int do_apply_stash(const char *prefix, struct stash_info *info,
                          int index, int quiet)
 {
@@ -467,26 +553,7 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
                if (reset_tree(&index_tree, 0, 0))
                        return -1;
        } else {
-               struct strbuf out = STRBUF_INIT;
-
-               if (get_newly_staged(&out, &c_tree)) {
-                       strbuf_release(&out);
-                       return -1;
-               }
-
-               if (reset_tree(&c_tree, 0, 1)) {
-                       strbuf_release(&out);
-                       return -1;
-               }
-
-               ret = update_index(&out);
-               strbuf_release(&out);
-               if (ret)
-                       return -1;
-
-               /* read back the result of update_index() back from the disk */
-               discard_cache();
-               read_cache();
+               unstage_changes_unless_new(&c_tree);
        }
 
        if (!quiet) {
index c30896c..c2bd882 100644 (file)
@@ -562,9 +562,9 @@ static int module_foreach(int argc, const char **argv, const char *prefix)
        struct module_list list = MODULE_LIST_INIT;
 
        struct option module_foreach_options[] = {
-               OPT__QUIET(&info.quiet, N_("Suppress output of entering each submodule command")),
+               OPT__QUIET(&info.quiet, N_("suppress output of entering each submodule command")),
                OPT_BOOL(0, "recursive", &info.recursive,
-                        N_("Recurse into nested submodules")),
+                        N_("recurse into nested submodules")),
                OPT_END()
        };
 
@@ -706,7 +706,7 @@ static int module_init(int argc, const char **argv, const char *prefix)
        int quiet = 0;
 
        struct option module_init_options[] = {
-               OPT__QUIET(&quiet, N_("Suppress output for initializing a submodule")),
+               OPT__QUIET(&quiet, N_("suppress output for initializing a submodule")),
                OPT_END()
        };
 
@@ -883,8 +883,8 @@ static int module_status(int argc, const char **argv, const char *prefix)
        int quiet = 0;
 
        struct option module_status_options[] = {
-               OPT__QUIET(&quiet, N_("Suppress submodule status output")),
-               OPT_BIT(0, "cached", &info.flags, N_("Use commit stored in the index instead of the one stored in the submodule HEAD"), OPT_CACHED),
+               OPT__QUIET(&quiet, N_("suppress submodule status output")),
+               OPT_BIT(0, "cached", &info.flags, N_("use commit stored in the index instead of the one stored in the submodule HEAD"), OPT_CACHED),
                OPT_BIT(0, "recursive", &info.flags, N_("recurse into nested submodules"), OPT_RECURSIVE),
                OPT_END()
        };
@@ -1482,9 +1482,9 @@ static int module_sync(int argc, const char **argv, const char *prefix)
        int recursive = 0;
 
        struct option module_sync_options[] = {
-               OPT__QUIET(&quiet, N_("Suppress output of synchronizing submodule url")),
+               OPT__QUIET(&quiet, N_("suppress output of synchronizing submodule url")),
                OPT_BOOL(0, "recursive", &recursive,
-                       N_("Recurse into nested submodules")),
+                       N_("recurse into nested submodules")),
                OPT_END()
        };
 
@@ -1620,9 +1620,9 @@ static int module_deinit(int argc, const char **argv, const char *prefix)
        int all = 0;
 
        struct option module_deinit_options[] = {
-               OPT__QUIET(&quiet, N_("Suppress submodule status output")),
-               OPT__FORCE(&force, N_("Remove submodule working trees even if they contain local changes"), 0),
-               OPT_BOOL(0, "all", &all, N_("Unregister all submodules")),
+               OPT__QUIET(&quiet, N_("suppress submodule status output")),
+               OPT__FORCE(&force, N_("remove submodule working trees even if they contain local changes"), 0),
+               OPT_BOOL(0, "all", &all, N_("unregister all submodules")),
                OPT_END()
        };
 
@@ -2337,7 +2337,7 @@ static int update_clone(int argc, const char **argv, const char *prefix)
                OPT_BOOL(0, "dissociate", &suc.dissociate,
                           N_("use --reference only while cloning")),
                OPT_STRING(0, "depth", &suc.depth, "<depth>",
-                          N_("Create a shallow clone truncated to the "
+                          N_("create a shallow clone truncated to the "
                              "specified number of revisions")),
                OPT_INTEGER('j', "jobs", &suc.max_jobs,
                            N_("parallel jobs")),
@@ -2678,7 +2678,7 @@ static int module_set_url(int argc, const char **argv, const char *prefix)
        char *config_name;
 
        struct option options[] = {
-               OPT__QUIET(&quiet, N_("Suppress output for setting url of a submodule")),
+               OPT__QUIET(&quiet, N_("suppress output for setting url of a submodule")),
                OPT_END()
        };
        const char *const usage[] = {
index ecf0117..24d35b7 100644 (file)
@@ -485,7 +485,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
        }
        if (!sorting)
                sorting = ref_default_sorting();
-       ref_sorting_icase_all(sorting, icase);
+       ref_sorting_set_sort_flags_all(sorting, REF_SORTING_ICASE, icase);
        filter.ignore_case = icase;
        if (cmdmode == 'l') {
                int ret;
index 0229a77..0b1184e 100755 (executable)
@@ -44,13 +44,13 @@ osx-clang|osx-gcc)
        test -z "$BREW_INSTALL_PACKAGES" ||
        brew install $BREW_INSTALL_PACKAGES
        brew link --force gettext
-       brew cask install --no-quarantine perforce || {
+       brew install --cask --no-quarantine perforce || {
                # Update the definitions and try again
                cask_repo="$(brew --repository)"/Library/Taps/homebrew/homebrew-cask &&
-               git -C "$cask_repo" pull --no-stat &&
-               brew cask install --no-quarantine perforce
+               git -C "$cask_repo" pull --no-stat --ff-only &&
+               brew install --cask --no-quarantine perforce
        } ||
-       brew install caskroom/cask/perforce
+       brew install homebrew/cask/perforce
        case "$jobname" in
        osx-gcc)
                brew install gcc@9
index 06f8dc1..0316410 100644 (file)
@@ -1694,8 +1694,8 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
        } else {
                hold_lock_file_for_update_mode(&lk, ctx->graph_name,
                                               LOCK_DIE_ON_ERROR, 0444);
-               fd = lk.tempfile->fd;
-               f = hashfd(lk.tempfile->fd, lk.tempfile->filename.buf);
+               fd = get_lock_file_fd(&lk);
+               f = hashfd(fd, get_lock_file_path(&lk));
        }
 
        chunks[0].id = GRAPH_CHUNKID_OIDFANOUT;
@@ -1833,7 +1833,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
                result = rename(ctx->graph_name, final_graph_name);
 
                for (i = 0; i < ctx->num_commit_graphs_after; i++)
-                       fprintf(lk.tempfile->fp, "%s\n", ctx->commit_graph_hash_after[i]);
+                       fprintf(get_lock_file_fp(&lk), "%s\n", ctx->commit_graph_hash_after[i]);
 
                if (result) {
                        error(_("failed to rename temporary commit-graph file"));
index 8b8f56c..9c97fee 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -1160,6 +1160,8 @@ static struct child_process *git_connect_git(int fd[2], char *hostandport,
                target_host = xstrdup(hostandport);
 
        transport_check_allowed("git");
+       if (strchr(target_host, '\n') || strchr(path, '\n'))
+               die(_("newline is forbidden in git:// hosts and repo paths"));
 
        /*
         * These underlying connection commands die() if they
diff --git a/fsck.c b/fsck.c
index f82e2fe..5e282b3 100644 (file)
--- a/fsck.c
+++ b/fsck.c
@@ -1082,7 +1082,7 @@ static int check_submodule_url(const char *url)
        if (looks_like_command_line_option(url))
                return -1;
 
-       if (submodule_url_is_relative(url)) {
+       if (submodule_url_is_relative(url) || starts_with(url, "git://")) {
                char *decoded;
                const char *next;
                int has_nl;
index 35d2c12..1b56421 100644 (file)
--- a/gettext.c
+++ b/gettext.c
@@ -87,88 +87,24 @@ static int test_vsnprintf(const char *fmt, ...)
 
 static void init_gettext_charset(const char *domain)
 {
-       /*
-          This trick arranges for messages to be emitted in the user's
-          requested encoding, but avoids setting LC_CTYPE from the
-          environment for the whole program.
-
-          This primarily done to avoid a bug in vsnprintf in the GNU C
-          Library [1]. which triggered a "your vsnprintf is broken" error
-          on Git's own repository when inspecting v0.99.6~1 under a UTF-8
-          locale.
-
-          That commit contains a ISO-8859-1 encoded author name, which
-          the locale aware vsnprintf(3) won't interpolate in the format
-          argument, due to mismatch between the data encoding and the
-          locale.
-
-          Even if it wasn't for that bug we wouldn't want to use LC_CTYPE at
-          this point, because it'd require auditing all the code that uses C
-          functions whose semantics are modified by LC_CTYPE.
-
-          But only setting LC_MESSAGES as we do creates a problem, since
-          we declare the encoding of our PO files[2] the gettext
-          implementation will try to recode it to the user's locale, but
-          without LC_CTYPE it'll emit something like this on 'git init'
-          under the Icelandic locale:
-
-              Bj? til t?ma Git lind ? /hlagh/.git/
-
-          Gettext knows about the encoding of our PO file, but we haven't
-          told it about the user's encoding, so all the non-US-ASCII
-          characters get encoded to question marks.
-
-          But we're in luck! We can set LC_CTYPE from the environment
-          only while we call nl_langinfo and
-          bind_textdomain_codeset. That suffices to tell gettext what
-          encoding it should emit in, so it'll now say:
-
-              Bjó til tóma Git lind Ã­ /hlagh/.git/
-
-          And the equivalent ISO-8859-1 string will be emitted under a
-          ISO-8859-1 locale.
-
-          With this change way we get the advantages of setting LC_CTYPE
-          (talk to the user in his language/encoding), without the major
-          drawbacks (changed semantics for C functions we rely on).
-
-          However foreign functions using other message catalogs that
-          aren't using our neat trick will still have a problem, e.g. if
-          we have to call perror(3):
-
-          #include <stdio.h>
-          #include <locale.h>
-          #include <errno.h>
-
-          int main(void)
-          {
-                  setlocale(LC_MESSAGES, "");
-                  setlocale(LC_CTYPE, "C");
-                  errno = ENODEV;
-                  perror("test");
-                  return 0;
-          }
-
-          Running that will give you a message with question marks:
-
-          $ LANGUAGE= LANG=de_DE.utf8 ./test
-          test: Kein passendes Ger?t gefunden
-
-          The vsnprintf bug has been fixed since glibc 2.17.
-
-          Then we could simply set LC_CTYPE from the environment, which would
-          make things like the external perror(3) messages work.
-
-          See t/t0203-gettext-setlocale-sanity.sh's "gettext.c" tests for
-          regression tests.
-
-          1. http://sourceware.org/bugzilla/show_bug.cgi?id=6530
-          2. E.g. "Content-Type: text/plain; charset=UTF-8\n" in po/is.po
-       */
        setlocale(LC_CTYPE, "");
        charset = locale_charset();
        bind_textdomain_codeset(domain, charset);
-       /* the string is taken from v0.99.6~1 */
+
+       /*
+        * Work around an old bug fixed in glibc 2.17 (released on
+        * 2012-12-24), at the cost of potentially making translated
+        * messages from external functions like perror() emitted in
+        * the wrong encoding.
+        *
+        * The bug affected e.g. git.git's own 7eb93c89651 ([PATCH]
+        * Simplify git script, 2005-09-07), which is the origin of
+        * the "David_K\345gedal" test string.
+        *
+        * See a much longer comment added to this file in 5e9637c6297
+        * (i18n: add infrastructure for translating Git with gettext,
+        * 2011-11-18) for more details.
+        */
        if (test_vsnprintf("%.*s", 13, "David_K\345gedal") < 0)
                setlocale(LC_CTYPE, "C");
 }
index 7225abd..78f3647 100644 (file)
@@ -46,9 +46,11 @@ show_tool_names () {
                while read scriptname
                do
                        setup_tool "$scriptname" 2>/dev/null
-                       variants="$variants$(list_tool_variants)\n"
+                       # We need an actual line feed here
+                       variants="$variants
+$(list_tool_variants)"
                done
-               variants="$(echo "$variants" | sort | uniq)"
+               variants="$(echo "$variants" | sort -u)"
 
                for toolname in $variants
                do
index 6ae5bbf..09c9e93 100755 (executable)
--- a/git-p4.py
+++ b/git-p4.py
@@ -3031,7 +3031,7 @@ class P4Sync(Command, P4UserMap):
             regexp = re.compile(pattern, re.VERBOSE)
             text = ''.join(decode_text_stream(c) for c in contents)
             text = regexp.sub(r'$\1$', text)
-            contents = [ text ]
+            contents = [ encode_text_stream(text) ]
 
         if self.largeFileSystem:
             (git_mode, contents) = self.largeFileSystem.processContent(git_mode, relPath, contents)
diff --git a/midx.c b/midx.c
index 79c282b..9d41b9c 100644 (file)
--- a/midx.c
+++ b/midx.c
@@ -918,7 +918,7 @@ static int write_midx_internal(const char *object_dir, struct multi_pack_index *
                                        (pack_name_concat_len % MIDX_CHUNK_ALIGNMENT);
 
        hold_lock_file_for_update(&lk, midx_name, LOCK_DIE_ON_ERROR);
-       f = hashfd(lk.tempfile->fd, lk.tempfile->filename.buf);
+       f = hashfd(get_lock_file_fd(&lk), get_lock_file_path(&lk));
        FREE_AND_NULL(midx_name);
 
        if (packs.m)
index 7030d8f..ff6506a 100644 (file)
@@ -82,9 +82,9 @@ typedef enum parse_opt_result parse_opt_ll_cb(struct parse_opt_ctx_t *ctx,
  *   stores pointers to the values to be filled.
  *
  * `argh`::
- *   token to explain the kind of argument this option wants. Keep it
- *   homogeneous across the repository. Should be wrapped by N_() for
- *   translation.
+ *   token to explain the kind of argument this option wants. Does not
+ *   begin in capital letter, and does not end with a full stop.
+ *   Should be wrapped by N_() for translation.
  *
  * `help`::
  *   the short help associated to what the option does.
index 21973e4..f51021a 100644 (file)
@@ -89,7 +89,7 @@ static int init_patch_id_entry(struct patch_id *patch,
        return 0;
 }
 
-struct patch_id *has_commit_patch_id(struct commit *commit,
+struct patch_id *patch_id_iter_first(struct commit *commit,
                                     struct patch_ids *ids)
 {
        struct patch_id patch;
@@ -104,6 +104,18 @@ struct patch_id *has_commit_patch_id(struct commit *commit,
        return hashmap_get_entry(&ids->patches, &patch, ent, NULL);
 }
 
+struct patch_id *patch_id_iter_next(struct patch_id *cur,
+                                   struct patch_ids *ids)
+{
+       return hashmap_get_next_entry(&ids->patches, cur, ent);
+}
+
+int has_commit_patch_id(struct commit *commit,
+                       struct patch_ids *ids)
+{
+       return !!patch_id_iter_first(commit, ids);
+}
+
 struct patch_id *add_commit_patch_id(struct commit *commit,
                                     struct patch_ids *ids)
 {
index 03bb04e..ab6c6a6 100644 (file)
@@ -23,7 +23,25 @@ int commit_patch_id(struct commit *commit, struct diff_options *options,
                    struct object_id *oid, int, int);
 int init_patch_ids(struct repository *, struct patch_ids *);
 int free_patch_ids(struct patch_ids *);
+
+/* Add a patch_id for a single commit to the set. */
 struct patch_id *add_commit_patch_id(struct commit *, struct patch_ids *);
-struct patch_id *has_commit_patch_id(struct commit *, struct patch_ids *);
+
+/* Returns true if the patch-id of "commit" is present in the set. */
+int has_commit_patch_id(struct commit *commit, struct patch_ids *);
+
+/*
+ * Iterate over all commits in the set whose patch id matches that of
+ * "commit", like:
+ *
+ *   struct patch_id *cur;
+ *   for (cur = patch_id_iter_first(commit, ids);
+ *        cur;
+ *        cur = patch_id_iter_next(cur, ids) {
+ *           ... look at cur->commit
+ *   }
+ */
+struct patch_id *patch_id_iter_first(struct commit *commit, struct patch_ids *);
+struct patch_id *patch_id_iter_next(struct patch_id *cur, struct patch_ids *);
 
 #endif /* PATCH_IDS_H */
index ecf6f68..29144cf 100644 (file)
@@ -3014,10 +3014,10 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
        if (ce_flush(&c, newfd, istate->oid.hash))
                return -1;
        if (close_tempfile_gently(tempfile)) {
-               error(_("could not close '%s'"), tempfile->filename.buf);
+               error(_("could not close '%s'"), get_tempfile_path(tempfile));
                return -1;
        }
-       if (stat(tempfile->filename.buf, &st))
+       if (stat(get_tempfile_path(tempfile), &st))
                return -1;
        istate->timestamp.sec = (unsigned int)st.st_mtime;
        istate->timestamp.nsec = ST_MTIME_NSEC(st);
@@ -3058,10 +3058,10 @@ static int do_write_locked_index(struct index_state *istate, struct lock_file *l
         * that is associated with the given "istate".
         */
        trace2_region_enter_printf("index", "do_write_index", the_repository,
-                                  "%s", lock->tempfile->filename.buf);
+                                  "%s", get_lock_file_path(lock));
        ret = do_write_index(istate, lock->tempfile, 0);
        trace2_region_leave_printf("index", "do_write_index", the_repository,
-                                  "%s", lock->tempfile->filename.buf);
+                                  "%s", get_lock_file_path(lock));
 
        if (ret)
                return ret;
@@ -3158,10 +3158,10 @@ static int write_shared_index(struct index_state *istate,
        move_cache_to_base_index(istate);
 
        trace2_region_enter_printf("index", "shared/do_write_index",
-                                  the_repository, "%s", (*temp)->filename.buf);
+                                  the_repository, "%s", get_tempfile_path(*temp));
        ret = do_write_index(si->base, *temp, 1);
        trace2_region_leave_printf("index", "shared/do_write_index",
-                                  the_repository, "%s", (*temp)->filename.buf);
+                                  the_repository, "%s", get_tempfile_path(*temp));
 
        if (ret)
                return ret;
index aa260bf..ee337df 100644 (file)
@@ -1536,36 +1536,27 @@ char *get_head_description(void)
        struct wt_status_state state;
        memset(&state, 0, sizeof(state));
        wt_status_get_state(the_repository, &state, 1);
-
-       /*
-        * The ( character must be hard-coded and not part of a localizable
-        * string, since the description is used as a sort key and compared
-        * with ref names.
-        */
-       strbuf_addch(&desc, '(');
        if (state.rebase_in_progress ||
            state.rebase_interactive_in_progress) {
                if (state.branch)
-                       strbuf_addf(&desc, _("no branch, rebasing %s"),
+                       strbuf_addf(&desc, _("(no branch, rebasing %s)"),
                                    state.branch);
                else
-                       strbuf_addf(&desc, _("no branch, rebasing detached HEAD %s"),
+                       strbuf_addf(&desc, _("(no branch, rebasing detached HEAD %s)"),
                                    state.detached_from);
        } else if (state.bisect_in_progress)
-               strbuf_addf(&desc, _("no branch, bisect started on %s"),
+               strbuf_addf(&desc, _("(no branch, bisect started on %s)"),
                            state.branch);
        else if (state.detached_from) {
                if (state.detached_at)
-                       strbuf_addstr(&desc, HEAD_DETACHED_AT);
+                       strbuf_addf(&desc, _("(HEAD detached at %s)"),
+                               state.detached_from);
                else
-                       strbuf_addstr(&desc, HEAD_DETACHED_FROM);
-               strbuf_addstr(&desc, state.detached_from);
-       }
-       else
-               strbuf_addstr(&desc, _("no branch"));
-       strbuf_addch(&desc, ')');
+                       strbuf_addf(&desc, _("(HEAD detached from %s)"),
+                               state.detached_from);
+       } else
+               strbuf_addstr(&desc, _("(no branch)"));
 
-       wt_status_state_free_buffers(&state);
        return strbuf_detach(&desc, NULL);
 }
 
@@ -2350,12 +2341,24 @@ int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int
        return ret;
 }
 
+static int compare_detached_head(struct ref_array_item *a, struct ref_array_item *b)
+{
+       if (!(a->kind ^ b->kind))
+               BUG("ref_kind_from_refname() should only mark one ref as HEAD");
+       if (a->kind & FILTER_REFS_DETACHED_HEAD)
+               return -1;
+       else if (b->kind & FILTER_REFS_DETACHED_HEAD)
+               return 1;
+       BUG("should have died in the xor check above");
+       return 0;
+}
+
 static int cmp_ref_sorting(struct ref_sorting *s, struct ref_array_item *a, struct ref_array_item *b)
 {
        struct atom_value *va, *vb;
        int cmp;
+       int cmp_detached_head = 0;
        cmp_type cmp_type = used_atom[s->atom].type;
-       int (*cmp_fn)(const char *, const char *);
        struct strbuf err = STRBUF_INIT;
 
        if (get_ref_atom_value(a, s->atom, &va, &err))
@@ -2363,12 +2366,18 @@ static int cmp_ref_sorting(struct ref_sorting *s, struct ref_array_item *a, stru
        if (get_ref_atom_value(b, s->atom, &vb, &err))
                die("%s", err.buf);
        strbuf_release(&err);
-       cmp_fn = s->ignore_case ? strcasecmp : strcmp;
-       if (s->version)
+       if (s->sort_flags & REF_SORTING_DETACHED_HEAD_FIRST &&
+           ((a->kind | b->kind) & FILTER_REFS_DETACHED_HEAD)) {
+               cmp = compare_detached_head(a, b);
+               cmp_detached_head = 1;
+       } else if (s->sort_flags & REF_SORTING_VERSION) {
                cmp = versioncmp(va->s, vb->s);
-       else if (cmp_type == FIELD_STR)
+       } else if (cmp_type == FIELD_STR) {
+               int (*cmp_fn)(const char *, const char *);
+               cmp_fn = s->sort_flags & REF_SORTING_ICASE
+                       ? strcasecmp : strcmp;
                cmp = cmp_fn(va->s, vb->s);
-       else {
+       else {
                if (va->value < vb->value)
                        cmp = -1;
                else if (va->value == vb->value)
@@ -2377,7 +2386,8 @@ static int cmp_ref_sorting(struct ref_sorting *s, struct ref_array_item *a, stru
                        cmp = 1;
        }
 
-       return (s->reverse) ? -cmp : cmp;
+       return (s->sort_flags & REF_SORTING_REVERSE && !cmp_detached_head)
+               ? -cmp : cmp;
 }
 
 static int compare_refs(const void *a_, const void *b_, void *ref_sorting)
@@ -2392,15 +2402,20 @@ static int compare_refs(const void *a_, const void *b_, void *ref_sorting)
                        return cmp;
        }
        s = ref_sorting;
-       return s && s->ignore_case ?
+       return s && s->sort_flags & REF_SORTING_ICASE ?
                strcasecmp(a->refname, b->refname) :
                strcmp(a->refname, b->refname);
 }
 
-void ref_sorting_icase_all(struct ref_sorting *sorting, int flag)
+void ref_sorting_set_sort_flags_all(struct ref_sorting *sorting,
+                                   unsigned int mask, int on)
 {
-       for (; sorting; sorting = sorting->next)
-               sorting->ignore_case = !!flag;
+       for (; sorting; sorting = sorting->next) {
+               if (on)
+                       sorting->sort_flags |= mask;
+               else
+                       sorting->sort_flags &= ~mask;
+       }
 }
 
 void ref_array_sort(struct ref_sorting *sorting, struct ref_array *array)
@@ -2537,12 +2552,12 @@ void parse_ref_sorting(struct ref_sorting **sorting_tail, const char *arg)
        *sorting_tail = s;
 
        if (*arg == '-') {
-               s->reverse = 1;
+               s->sort_flags |= REF_SORTING_REVERSE;
                arg++;
        }
        if (skip_prefix(arg, "version:", &arg) ||
            skip_prefix(arg, "v:", &arg))
-               s->version = 1;
+               s->sort_flags |= REF_SORTING_VERSION;
        s->atom = parse_sorting_atom(arg);
 }
 
index feaef4a..19ea4c4 100644 (file)
@@ -28,9 +28,12 @@ struct atom_value;
 struct ref_sorting {
        struct ref_sorting *next;
        int atom; /* index into used_atom array (internal) */
-       unsigned reverse : 1,
-               ignore_case : 1,
-               version : 1;
+       enum {
+               REF_SORTING_REVERSE = 1<<0,
+               REF_SORTING_ICASE = 1<<1,
+               REF_SORTING_VERSION = 1<<2,
+               REF_SORTING_DETACHED_HEAD_FIRST = 1<<3,
+       } sort_flags;
 };
 
 struct ref_array_item {
@@ -109,8 +112,8 @@ void ref_array_clear(struct ref_array *array);
 int verify_ref_format(struct ref_format *format);
 /*  Sort the given ref_array as per the ref_sorting provided */
 void ref_array_sort(struct ref_sorting *sort, struct ref_array *array);
-/*  Set the ignore_case flag for all elements of a sorting list */
-void ref_sorting_icase_all(struct ref_sorting *sorting, int flag);
+/*  Set REF_SORTING_* sort_flags for all elements of a sorting list */
+void ref_sorting_set_sort_flags_all(struct ref_sorting *sorting, unsigned int mask, int on);
 /*  Based on the given format and quote_style, fill the strbuf */
 int format_ref_array_item(struct ref_array_item *info,
                          const struct ref_format *format,
index 04e85e7..4fdc688 100644 (file)
@@ -1824,12 +1824,12 @@ static int create_symref_locked(struct files_ref_store *refs,
 
        if (!fdopen_lock_file(&lock->lk, "w"))
                return error("unable to fdopen %s: %s",
-                            lock->lk.tempfile->filename.buf, strerror(errno));
+                            get_lock_file_path(&lock->lk), strerror(errno));
 
        update_symref_reflog(refs, lock, refname, target, logmsg);
 
        /* no error check; commit_ref will check ferror */
-       fprintf(lock->lk.tempfile->fp, "ref: %s\n", target);
+       fprintf(get_lock_file_fp(&lock->lk), "ref: %s\n", target);
        if (commit_ref(lock) < 0)
                return error("unable to write symref for %s: %s", refname,
                             strerror(errno));
index 9dff845..7ec9b63 100644 (file)
@@ -1241,12 +1241,14 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)
                /*
                 * Have we seen the same patch id?
                 */
-               id = has_commit_patch_id(commit, &ids);
+               id = patch_id_iter_first(commit, &ids);
                if (!id)
                        continue;
 
                commit->object.flags |= cherry_flag;
-               id->commit->object.flags |= cherry_flag;
+               do {
+                       id->commit->object.flags |= cherry_flag;
+               } while ((id = patch_id_iter_next(id, &ids)));
        }
 
        free_patch_ids(&ids);
index b3bb59f..b561445 100644 (file)
@@ -1477,6 +1477,7 @@ static int get_next_submodule(struct child_process *cp,
                        strbuf_release(&submodule_prefix);
                        return 1;
                } else {
+                       struct strbuf empty_submodule_path = STRBUF_INIT;
 
                        fetch_task_release(task);
                        free(task);
@@ -1485,13 +1486,17 @@ static int get_next_submodule(struct child_process *cp,
                         * An empty directory is normal,
                         * the submodule is not initialized
                         */
+                       strbuf_addf(&empty_submodule_path, "%s/%s/",
+                                                       spf->r->worktree,
+                                                       ce->name);
                        if (S_ISGITLINK(ce->ce_mode) &&
-                           !is_empty_dir(ce->name)) {
+                           !is_empty_dir(empty_submodule_path.buf)) {
                                spf->result = 1;
                                strbuf_addf(err,
                                            _("Could not access submodule '%s'\n"),
                                            ce->name);
                        }
+                       strbuf_release(&empty_submodule_path);
                }
        }
 
index 3aee61d..a2e4657 100644 (file)
@@ -483,12 +483,12 @@ test_expect_success 'setup -L :funcname with userdiff driver' '
        echo "fortran-* diff=fortran" >.gitattributes &&
        fortran_file=fortran-external-function &&
        orig_file="$TEST_DIRECTORY/t4018/$fortran_file" &&
-       cp $orig_file . &&
-       git add $fortran_file &&
+       cp "$orig_file" . &&
+       git add "$fortran_file" &&
        GIT_AUTHOR_NAME="A" GIT_AUTHOR_EMAIL="A@test.git" \
        git commit -m "add fortran file" &&
-       sed -e "s/ChangeMe/IWasChanged/" <"$orig_file" >$fortran_file &&
-       git add $fortran_file &&
+       sed -e "s/ChangeMe/IWasChanged/" <"$orig_file" >"$fortran_file" &&
+       git add "$fortran_file" &&
        GIT_AUTHOR_NAME="B" GIT_AUTHOR_EMAIL="B@test.git" \
        git commit -m "change fortran file"
 '
index bd3fa3c..4b714e9 100644 (file)
@@ -316,14 +316,7 @@ test_submodule_switch_common () {
        command="$1"
        ######################### Appearing submodule #########################
        # Switching to a commit letting a submodule appear creates empty dir ...
-       if test "$KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES" = 1
-       then
-               # Restoring stash fails to restore submodule index entry
-               RESULT="failure"
-       else
-               RESULT="success"
-       fi
-       test_expect_$RESULT "$command: added submodule creates empty directory" '
+       test_expect_success "$command: added submodule creates empty directory" '
                prolog &&
                reset_work_tree_to no_submodule &&
                (
@@ -337,6 +330,13 @@ test_submodule_switch_common () {
                )
        '
        # ... and doesn't care if it already exists.
+       if test "$KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES" = 1
+       then
+               # Restoring stash fails to restore submodule index entry
+               RESULT="failure"
+       else
+               RESULT="success"
+       fi
        test_expect_$RESULT "$command: added submodule leaves existing empty directory alone" '
                prolog &&
                reset_work_tree_to no_submodule &&
index f4c2ab0..ce0c42c 100755 (executable)
@@ -21,10 +21,14 @@ repack_into_n () {
        mkdir staging &&
 
        git rev-list --first-parent HEAD |
-       sed -n '1~5p' |
-       head -n "$1" |
-       perl -e 'print reverse <>' \
-       >pushes
+       perl -e '
+               my $n = shift;
+               while (<>) {
+                       last unless @commits < $n;
+                       push @commits, $_ if $. % 5 == 1;
+               }
+               print reverse @commits;
+       ' "$1" >pushes
 
        # create base packfile
        head -n 1 pushes |
index 9b43342..1e20a18 100755 (executable)
@@ -129,7 +129,12 @@ setup_for_fsmonitor() {
 
        git config core.fsmonitor "$INTEGRATION_SCRIPT" &&
        git update-index --fsmonitor 2>error &&
-       test_must_be_empty error  # ensure no silent error
+       if test_have_prereq WATCHMAN
+       then
+               test_must_be_empty error  # ensure no silent error
+       else
+               grep "Empty last update token" error
+       fi
 }
 
 test_perf_w_drop_caches () {
index 136b4ec..4675e85 100755 (executable)
@@ -27,4 +27,10 @@ test_expect_success 'run based on configured value' '
        grep again message
 '
 
+test_expect_success 'do nothing on empty config' '
+       # the whole thing would fail if for-each-ref iterated even
+       # once, because "git help --no-such-option" would fail
+       git for-each-repo --config=bogus.config -- help --no-such-option
+'
+
 test_done
index 97a04c6..1a4156c 100755 (executable)
@@ -12,75 +12,75 @@ test_expect_success 'clear default config' '
 '
 
 cat > expect << EOF
-[core]
+[section]
        penguin = little blue
 EOF
 test_expect_success 'initial' '
-       git config core.penguin "little blue" &&
+       git config section.penguin "little blue" &&
        test_cmp expect .git/config
 '
 
 cat > expect << EOF
-[core]
+[section]
        penguin = little blue
        Movie = BadPhysics
 EOF
 test_expect_success 'mixed case' '
-       git config Core.Movie BadPhysics &&
+       git config Section.Movie BadPhysics &&
        test_cmp expect .git/config
 '
 
 cat > expect << EOF
-[core]
+[section]
        penguin = little blue
        Movie = BadPhysics
-[Cores]
+[Sections]
        WhatEver = Second
 EOF
 test_expect_success 'similar section' '
-       git config Cores.WhatEver Second &&
+       git config Sections.WhatEver Second &&
        test_cmp expect .git/config
 '
 
 cat > expect << EOF
-[core]
+[section]
        penguin = little blue
        Movie = BadPhysics
        UPPERCASE = true
-[Cores]
+[Sections]
        WhatEver = Second
 EOF
 test_expect_success 'uppercase section' '
-       git config CORE.UPPERCASE true &&
+       git config SECTION.UPPERCASE true &&
        test_cmp expect .git/config
 '
 
 test_expect_success 'replace with non-match' '
-       git config core.penguin kingpin !blue
+       git config section.penguin kingpin !blue
 '
 
 test_expect_success 'replace with non-match (actually matching)' '
-       git config core.penguin "very blue" !kingpin
+       git config section.penguin "very blue" !kingpin
 '
 
 cat > expect << EOF
-[core]
+[section]
        penguin = very blue
        Movie = BadPhysics
        UPPERCASE = true
        penguin = kingpin
-[Cores]
+[Sections]
        WhatEver = Second
 EOF
 
 test_expect_success 'non-match result' 'test_cmp expect .git/config'
 
 test_expect_success 'find mixed-case key by canonical name' '
-       test_cmp_config Second cores.whatever
+       test_cmp_config Second sections.whatever
 '
 
 test_expect_success 'find mixed-case key by non-canonical name' '
-       test_cmp_config Second CoReS.WhAtEvEr
+       test_cmp_config Second SeCtIoNs.WhAtEvEr
 '
 
 test_expect_success 'subsections are not canonicalized by git-config' '
@@ -469,7 +469,8 @@ test_expect_success 'new variable inserts into proper section' '
 '
 
 test_expect_success 'alternative --file (non-existing file should fail)' '
-       test_must_fail git config --file non-existing-config -l
+       test_must_fail git config --file non-existing-config -l &&
+       test_must_fail git config --file non-existing-config test.xyzzy
 '
 
 cat > other-config << EOF
@@ -506,10 +507,6 @@ test_expect_success 'editing stdin is an error' '
 
 test_expect_success 'refer config from subdirectory' '
        mkdir x &&
-       test_cmp_config -C x strasse --get --file ../other-config ein.bahn
-'
-
-test_expect_success 'refer config from subdirectory via --file' '
        test_cmp_config -C x strasse --file=../other-config --get ein.bahn
 '
 
@@ -1036,11 +1033,6 @@ test_expect_success SYMLINKS 'symlinked configuration' '
        test_cmp expect actual
 '
 
-test_expect_success 'nonexistent configuration' '
-       test_must_fail git config --file=doesnotexist --list &&
-       test_must_fail git config --file=doesnotexist test.xyzzy
-'
-
 test_expect_success SYMLINKS 'symlink to nonexistent configuration' '
        ln -s doesnotexist linktonada &&
        ln -s linktonada linktolinktonada &&
@@ -1065,12 +1057,12 @@ test_expect_success 'git -c "key=value" support' '
        true
        EOF
        {
-               git -c core.name=value config core.name &&
+               git -c section.name=value config section.name &&
                git -c foo.CamelCase=value config foo.camelcase &&
                git -c foo.flag config --bool foo.flag
        } >actual &&
        test_cmp expect actual &&
-       test_must_fail git -c name=value config core.name
+       test_must_fail git -c name=value config section.name
 '
 
 # We just need a type-specifier here that cares about the
@@ -1115,7 +1107,7 @@ test_expect_success 'aliases can be CamelCased' '
 
 test_expect_success 'git -c does not split values on equals' '
        echo "value with = in it" >expect &&
-       git -c core.foo="value with = in it" config core.foo >actual &&
+       git -c section.foo="value with = in it" config section.foo >actual &&
        test_cmp expect actual
 '
 
@@ -1846,53 +1838,53 @@ do
 done
 
 cat >.git/config <<-\EOF &&
-[core]
+[section]
 foo = true
 number = 10
 big = 1M
 EOF
 
 test_expect_success 'identical modern --type specifiers are allowed' '
-       test_cmp_config 1048576 --type=int --type=int core.big
+       test_cmp_config 1048576 --type=int --type=int section.big
 '
 
 test_expect_success 'identical legacy --type specifiers are allowed' '
-       test_cmp_config 1048576 --int --int core.big
+       test_cmp_config 1048576 --int --int section.big
 '
 
 test_expect_success 'identical mixed --type specifiers are allowed' '
-       test_cmp_config 1048576 --int --type=int core.big
+       test_cmp_config 1048576 --int --type=int section.big
 '
 
 test_expect_success 'non-identical modern --type specifiers are not allowed' '
-       test_must_fail git config --type=int --type=bool core.big 2>error &&
+       test_must_fail git config --type=int --type=bool section.big 2>error &&
        test_i18ngrep "only one type at a time" error
 '
 
 test_expect_success 'non-identical legacy --type specifiers are not allowed' '
-       test_must_fail git config --int --bool core.big 2>error &&
+       test_must_fail git config --int --bool section.big 2>error &&
        test_i18ngrep "only one type at a time" error
 '
 
 test_expect_success 'non-identical mixed --type specifiers are not allowed' '
-       test_must_fail git config --type=int --bool core.big 2>error &&
+       test_must_fail git config --type=int --bool section.big 2>error &&
        test_i18ngrep "only one type at a time" error
 '
 
 test_expect_success '--type allows valid type specifiers' '
-       test_cmp_config true  --type=bool core.foo
+       test_cmp_config true  --type=bool section.foo
 '
 
 test_expect_success '--no-type unsets type specifiers' '
-       test_cmp_config 10 --type=bool --no-type core.number
+       test_cmp_config 10 --type=bool --no-type section.number
 '
 
 test_expect_success 'unset type specifiers may be reset to conflicting ones' '
-       test_cmp_config 1048576 --type=bool --no-type --type=int core.big
+       test_cmp_config 1048576 --type=bool --no-type --type=int section.big
 '
 
 test_expect_success '--type rejects unknown specifiers' '
-       test_must_fail git config --type=nonsense core.foo 2>error &&
+       test_must_fail git config --type=nonsense section.foo 2>error &&
        test_i18ngrep "unrecognized --type argument" error
 '
 
index b945faf..5e0577d 100755 (executable)
@@ -210,7 +210,7 @@ EOF
        test_i18ncmp expect actual
 '
 
-test_expect_success 'git branch `--sort` option' '
+test_expect_success 'git branch `--sort=[-]objectsize` option' '
        cat >expect <<-\EOF &&
        * (HEAD detached from fromtag)
          branch-two
@@ -218,6 +218,55 @@ test_expect_success 'git branch `--sort` option' '
          main
        EOF
        git branch --sort=objectsize >actual &&
+       test_i18ncmp expect actual &&
+
+       cat >expect <<-\EOF &&
+       * (HEAD detached from fromtag)
+         branch-one
+         main
+         branch-two
+       EOF
+       git branch --sort=-objectsize >actual &&
+       test_i18ncmp expect actual
+'
+
+test_expect_success 'git branch `--sort=[-]type` option' '
+       cat >expect <<-\EOF &&
+       * (HEAD detached from fromtag)
+         branch-one
+         branch-two
+         main
+       EOF
+       git branch --sort=type >actual &&
+       test_i18ncmp expect actual &&
+
+       cat >expect <<-\EOF &&
+       * (HEAD detached from fromtag)
+         branch-one
+         branch-two
+         main
+       EOF
+       git branch --sort=-type >actual &&
+       test_i18ncmp expect actual
+'
+
+test_expect_success 'git branch `--sort=[-]version:refname` option' '
+       cat >expect <<-\EOF &&
+       * (HEAD detached from fromtag)
+         branch-one
+         branch-two
+         main
+       EOF
+       git branch --sort=version:refname >actual &&
+       test_i18ncmp expect actual &&
+
+       cat >expect <<-\EOF &&
+       * (HEAD detached from fromtag)
+         main
+         branch-two
+         branch-one
+       EOF
+       git branch --sort=-version:refname >actual &&
        test_i18ncmp expect actual
 '
 
index 41818d8..576632f 100755 (executable)
@@ -78,7 +78,7 @@ test_expect_success POSIXPERM 'do not use core.sharedRepository for working tree
        test_config core.sharedRepository 0666 &&
        (
                # Remove a default ACL if possible.
-               (setfacl -k newdir 2>/dev/null || true) &&
+               (setfacl -k . 2>/dev/null || true) &&
                umask 0077 &&
 
                # Test both files (f1) and leading dirs (d)
index 01004ff..3ed121d 100755 (executable)
@@ -1260,7 +1260,9 @@ do
                        git cat-file commit $SHA1_2 &&
                        test_must_fail env GIT_TEST_PROTOCOL_VERSION=0 \
                                git fetch ../testrepo/.git $SHA1_3 2>err &&
-                       test_i18ngrep "remote error:.*not our ref.*$SHA1_3\$" err
+                       # ideally we would insist this be on a "remote error:"
+                       # line, but it is racy; see the commit message
+                       test_i18ngrep "not our ref.*$SHA1_3\$" err
                )
        '
 done
index a877dd1..53d7b8e 100755 (executable)
@@ -722,4 +722,121 @@ test_expect_success 'fetch new submodule commit intermittently referenced by sup
        )
 '
 
+add_commit_push () {
+       dir="$1" &&
+       msg="$2" &&
+       shift 2 &&
+       git -C "$dir" add "$@" &&
+       git -C "$dir" commit -a -m "$msg" &&
+       git -C "$dir" push
+}
+
+compare_refs_in_dir () {
+       fail= &&
+       if test "x$1" = 'x!'
+       then
+               fail='!' &&
+               shift
+       fi &&
+       git -C "$1" rev-parse --verify "$2" >expect &&
+       git -C "$3" rev-parse --verify "$4" >actual &&
+       eval $fail test_cmp expect actual
+}
+
+
+test_expect_success 'setup nested submodule fetch test' '
+       # does not depend on any previous test setups
+
+       for repo in outer middle inner
+       do
+               git init --bare $repo &&
+               git clone $repo ${repo}_content &&
+               echo "$repo" >"${repo}_content/file" &&
+               add_commit_push ${repo}_content "initial" file ||
+               return 1
+       done &&
+
+       git clone outer A &&
+       git -C A submodule add "$pwd/middle" &&
+       git -C A/middle/ submodule add "$pwd/inner" &&
+       add_commit_push A/middle/ "adding inner sub" .gitmodules inner &&
+       add_commit_push A/ "adding middle sub" .gitmodules middle &&
+
+       git clone outer B &&
+       git -C B/ submodule update --init middle &&
+
+       compare_refs_in_dir A HEAD B HEAD &&
+       compare_refs_in_dir A/middle HEAD B/middle HEAD &&
+       test_path_is_file B/file &&
+       test_path_is_file B/middle/file &&
+       test_path_is_missing B/middle/inner/file &&
+
+       echo "change on inner repo of A" >"A/middle/inner/file" &&
+       add_commit_push A/middle/inner "change on inner" file &&
+       add_commit_push A/middle "change on inner" inner &&
+       add_commit_push A "change on inner" middle
+'
+
+test_expect_success 'fetching a superproject containing an uninitialized sub/sub project' '
+       # depends on previous test for setup
+
+       git -C B/ fetch &&
+       compare_refs_in_dir A origin/HEAD B origin/HEAD
+'
+
+fetch_with_recursion_abort () {
+       # In a regression the following git call will run into infinite recursion.
+       # To handle that, we connect the sed command to the git call by a pipe
+       # so that sed can kill the infinite recursion when detected.
+       # The recursion creates git output like:
+       # Fetching submodule sub
+       # Fetching submodule sub/sub              <-- [1]
+       # Fetching submodule sub/sub/sub
+       # ...
+       # [1] sed will stop reading and cause git to eventually stop and die
+
+       git -C "$1" fetch --recurse-submodules 2>&1 |
+               sed "/Fetching submodule $2[^$]/q" >out &&
+       ! grep "Fetching submodule $2[^$]" out
+}
+
+test_expect_success 'setup recursive fetch with uninit submodule' '
+       # does not depend on any previous test setups
+
+       test_create_repo super &&
+       test_commit -C super initial &&
+       test_create_repo sub &&
+       test_commit -C sub initial &&
+       git -C sub rev-parse HEAD >expect &&
+
+       git -C super submodule add ../sub &&
+       git -C super commit -m "add sub" &&
+
+       git clone super superclone &&
+       git -C superclone submodule status >out &&
+       sed -e "s/^-//" -e "s/ sub.*$//" out >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'recursive fetch with uninit submodule' '
+       # depends on previous test for setup
+
+       fetch_with_recursion_abort superclone sub &&
+       git -C superclone submodule status >out &&
+       sed -e "s/^-//" -e "s/ sub$//" out >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'recursive fetch after deinit a submodule' '
+       # depends on previous test for setup
+
+       git -C superclone submodule update --init sub &&
+       git -C superclone submodule deinit -f sub &&
+
+       fetch_with_recursion_abort superclone sub &&
+       git -C superclone submodule status >out &&
+       sed -e "s/^-//" -e "s/ sub$//" out >actual &&
+       test_cmp expect actual
+'
+
 test_done
index 8f69a78..0fbb194 100755 (executable)
@@ -103,6 +103,11 @@ test_expect_success 'fetch notices corrupt idx' '
        )
 '
 
+test_expect_success 'client refuses to ask for repo with newline' '
+       test_must_fail git clone "$GIT_DAEMON_URL/repo$LF.git" dst 2>stderr &&
+       test_i18ngrep newline.is.forbidden stderr
+'
+
 test_remote_error()
 {
        do_export=YesPlease
index f026837..8bf5ae2 100755 (executable)
@@ -245,6 +245,18 @@ test_expect_success '--count --left-right' '
        test_cmp expect actual
 '
 
+test_expect_success '--cherry-pick with duplicates on each side' '
+       git checkout -b dup-orig &&
+       test_commit dup-base &&
+       git revert dup-base &&
+       git cherry-pick dup-base &&
+       git checkout -b dup-side HEAD~3 &&
+       test_tick &&
+       git cherry-pick -3 dup-orig &&
+       git rev-list --cherry-pick dup-orig...dup-side >actual &&
+       test_must_be_empty actual
+'
+
 # Corrupt the object store deliberately to make sure
 # the object is not even checked for its existence.
 remove_loose_object () {
index f5e6e92..f79df8b 100755 (executable)
@@ -8,6 +8,12 @@
 test_description='--graph and simplified history'
 
 . ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-log-graph.sh
+
+check_graph () {
+       cat >expect &&
+       lib_test_cmp_graph --format=%s "$@"
+}
 
 test_expect_success 'set up rev-list --graph test' '
        # 3 commits on branch A
@@ -28,7 +34,7 @@ test_expect_success 'set up rev-list --graph test' '
 
        # Octopus merge B and C into branch A
        git checkout A &&
-       git merge B C &&
+       git merge B C -m A4 &&
        git tag A4 &&
 
        test_commit A5 bar.txt &&
@@ -38,81 +44,64 @@ test_expect_success 'set up rev-list --graph test' '
        test_commit C3 foo.txt &&
        test_commit C4 bar.txt &&
        git checkout A &&
-       git merge -s ours C &&
+       git merge -s ours C -m A6 &&
        git tag A6 &&
 
-       test_commit A7 bar.txt &&
-
-       # Store commit names in variables for later use
-       A1=$(git rev-parse --verify A1) &&
-       A2=$(git rev-parse --verify A2) &&
-       A3=$(git rev-parse --verify A3) &&
-       A4=$(git rev-parse --verify A4) &&
-       A5=$(git rev-parse --verify A5) &&
-       A6=$(git rev-parse --verify A6) &&
-       A7=$(git rev-parse --verify A7) &&
-       B1=$(git rev-parse --verify B1) &&
-       B2=$(git rev-parse --verify B2) &&
-       C1=$(git rev-parse --verify C1) &&
-       C2=$(git rev-parse --verify C2) &&
-       C3=$(git rev-parse --verify C3) &&
-       C4=$(git rev-parse --verify C4)
-       '
+       test_commit A7 bar.txt
+'
 
 test_expect_success '--graph --all' '
-       rm -f expected &&
-       echo "* $A7" >> expected &&
-       echo "*   $A6" >> expected &&
-       echo "|\\  " >> expected &&
-       echo "| * $C4" >> expected &&
-       echo "| * $C3" >> expected &&
-       echo "* | $A5" >> expected &&
-       echo "| |   " >> expected &&
-       echo "|  \\  " >> expected &&
-       echo "*-. | $A4" >> expected &&
-       echo "|\\ \\| " >> expected &&
-       echo "| | * $C2" >> expected &&
-       echo "| | * $C1" >> expected &&
-       echo "| * | $B2" >> expected &&
-       echo "| * | $B1" >> expected &&
-       echo "* | | $A3" >> expected &&
-       echo "| |/  " >> expected &&
-       echo "|/|   " >> expected &&
-       echo "* | $A2" >> expected &&
-       echo "|/  " >> expected &&
-       echo "* $A1" >> expected &&
-       git rev-list --graph --all > actual &&
-       test_cmp expected actual
-       '
+       check_graph --all <<-\EOF
+       * A7
+       *   A6
+       |\
+       | * C4
+       | * C3
+       * | A5
+       | |
+       |  \
+       *-. | A4
+       |\ \|
+       | | * C2
+       | | * C1
+       | * | B2
+       | * | B1
+       * | | A3
+       | |/
+       |/|
+       * | A2
+       |/
+       * A1
+       EOF
+'
 
 # Make sure the graph_is_interesting() code still realizes
 # that undecorated merges are interesting, even with --simplify-by-decoration
 test_expect_success '--graph --simplify-by-decoration' '
-       rm -f expected &&
        git tag -d A4 &&
-       echo "* $A7" >> expected &&
-       echo "*   $A6" >> expected &&
-       echo "|\\  " >> expected &&
-       echo "| * $C4" >> expected &&
-       echo "| * $C3" >> expected &&
-       echo "* | $A5" >> expected &&
-       echo "| |   " >> expected &&
-       echo "|  \\  " >> expected &&
-       echo "*-. | $A4" >> expected &&
-       echo "|\\ \\| " >> expected &&
-       echo "| | * $C2" >> expected &&
-       echo "| | * $C1" >> expected &&
-       echo "| * | $B2" >> expected &&
-       echo "| * | $B1" >> expected &&
-       echo "* | | $A3" >> expected &&
-       echo "| |/  " >> expected &&
-       echo "|/|   " >> expected &&
-       echo "* | $A2" >> expected &&
-       echo "|/  " >> expected &&
-       echo "* $A1" >> expected &&
-       git rev-list --graph --all --simplify-by-decoration > actual &&
-       test_cmp expected actual
-       '
+       check_graph --all --simplify-by-decoration <<-\EOF
+       * A7
+       *   A6
+       |\
+       | * C4
+       | * C3
+       * | A5
+       | |
+       |  \
+       *-. | A4
+       |\ \|
+       | | * C2
+       | | * C1
+       | * | B2
+       | * | B1
+       * | | A3
+       | |/
+       |/|
+       * | A2
+       |/
+       * A1
+       EOF
+'
 
 test_expect_success 'setup: get rid of decorations on B' '
        git tag -d B2 &&
@@ -122,142 +111,133 @@ test_expect_success 'setup: get rid of decorations on B' '
 
 # Graph with branch B simplified away
 test_expect_success '--graph --simplify-by-decoration prune branch B' '
-       rm -f expected &&
-       echo "* $A7" >> expected &&
-       echo "*   $A6" >> expected &&
-       echo "|\\  " >> expected &&
-       echo "| * $C4" >> expected &&
-       echo "| * $C3" >> expected &&
-       echo "* | $A5" >> expected &&
-       echo "* | $A4" >> expected &&
-       echo "|\\| " >> expected &&
-       echo "| * $C2" >> expected &&
-       echo "| * $C1" >> expected &&
-       echo "* | $A3" >> expected &&
-       echo "|/  " >> expected &&
-       echo "* $A2" >> expected &&
-       echo "* $A1" >> expected &&
-       git rev-list --graph --simplify-by-decoration --all > actual &&
-       test_cmp expected actual
-       '
+       check_graph --simplify-by-decoration --all <<-\EOF
+       * A7
+       *   A6
+       |\
+       | * C4
+       | * C3
+       * | A5
+       * | A4
+       |\|
+       | * C2
+       | * C1
+       * | A3
+       |/
+       * A2
+       * A1
+       EOF
+'
 
 test_expect_success '--graph --full-history -- bar.txt' '
-       rm -f expected &&
-       echo "* $A7" >> expected &&
-       echo "*   $A6" >> expected &&
-       echo "|\\  " >> expected &&
-       echo "| * $C4" >> expected &&
-       echo "* | $A5" >> expected &&
-       echo "* | $A4" >> expected &&
-       echo "|\\| " >> expected &&
-       echo "* | $A3" >> expected &&
-       echo "|/  " >> expected &&
-       echo "* $A2" >> expected &&
-       git rev-list --graph --full-history --all -- bar.txt > actual &&
-       test_cmp expected actual
-       '
+       check_graph --full-history --all -- bar.txt <<-\EOF
+       * A7
+       *   A6
+       |\
+       | * C4
+       * | A5
+       * | A4
+       |\|
+       * | A3
+       |/
+       * A2
+       EOF
+'
 
 test_expect_success '--graph --full-history --simplify-merges -- bar.txt' '
-       rm -f expected &&
-       echo "* $A7" >> expected &&
-       echo "*   $A6" >> expected &&
-       echo "|\\  " >> expected &&
-       echo "| * $C4" >> expected &&
-       echo "* | $A5" >> expected &&
-       echo "* | $A3" >> expected &&
-       echo "|/  " >> expected &&
-       echo "* $A2" >> expected &&
-       git rev-list --graph --full-history --simplify-merges --all \
-               -- bar.txt > actual &&
-       test_cmp expected actual
-       '
+       check_graph --full-history --simplify-merges --all -- bar.txt <<-\EOF
+       * A7
+       *   A6
+       |\
+       | * C4
+       * | A5
+       * | A3
+       |/
+       * A2
+       EOF
+'
 
 test_expect_success '--graph -- bar.txt' '
-       rm -f expected &&
-       echo "* $A7" >> expected &&
-       echo "* $A5" >> expected &&
-       echo "* $A3" >> expected &&
-       echo "| * $C4" >> expected &&
-       echo "|/  " >> expected &&
-       echo "* $A2" >> expected &&
-       git rev-list --graph --all -- bar.txt > actual &&
-       test_cmp expected actual
-       '
+       check_graph --all -- bar.txt <<-\EOF
+       * A7
+       * A5
+       * A3
+       | * C4
+       |/
+       * A2
+       EOF
+'
 
 test_expect_success '--graph --sparse -- bar.txt' '
-       rm -f expected &&
-       echo "* $A7" >> expected &&
-       echo "* $A6" >> expected &&
-       echo "* $A5" >> expected &&
-       echo "* $A4" >> expected &&
-       echo "* $A3" >> expected &&
-       echo "| * $C4" >> expected &&
-       echo "| * $C3" >> expected &&
-       echo "| * $C2" >> expected &&
-       echo "| * $C1" >> expected &&
-       echo "|/  " >> expected &&
-       echo "* $A2" >> expected &&
-       echo "* $A1" >> expected &&
-       git rev-list --graph --sparse --all -- bar.txt > actual &&
-       test_cmp expected actual
-       '
+       check_graph --sparse --all -- bar.txt <<-\EOF
+       * A7
+       * A6
+       * A5
+       * A4
+       * A3
+       | * C4
+       | * C3
+       | * C2
+       | * C1
+       |/
+       * A2
+       * A1
+       EOF
+'
 
 test_expect_success '--graph ^C4' '
-       rm -f expected &&
-       echo "* $A7" >> expected &&
-       echo "* $A6" >> expected &&
-       echo "* $A5" >> expected &&
-       echo "*   $A4" >> expected &&
-       echo "|\\  " >> expected &&
-       echo "| * $B2" >> expected &&
-       echo "| * $B1" >> expected &&
-       echo "* $A3" >> expected &&
-       git rev-list --graph --all ^C4 > actual &&
-       test_cmp expected actual
-       '
+       check_graph --all ^C4 <<-\EOF
+       * A7
+       * A6
+       * A5
+       *   A4
+       |\
+       | * B2
+       | * B1
+       * A3
+       EOF
+'
 
 test_expect_success '--graph ^C3' '
-       rm -f expected &&
-       echo "* $A7" >> expected &&
-       echo "*   $A6" >> expected &&
-       echo "|\\  " >> expected &&
-       echo "| * $C4" >> expected &&
-       echo "* $A5" >> expected &&
-       echo "*   $A4" >> expected &&
-       echo "|\\  " >> expected &&
-       echo "| * $B2" >> expected &&
-       echo "| * $B1" >> expected &&
-       echo "* $A3" >> expected &&
-       git rev-list --graph --all ^C3 > actual &&
-       test_cmp expected actual
-       '
+       check_graph --all ^C3 <<-\EOF
+       * A7
+       *   A6
+       |\
+       | * C4
+       * A5
+       *   A4
+       |\
+       | * B2
+       | * B1
+       * A3
+       EOF
+'
 
 # I don't think the ordering of the boundary commits is really
 # that important, but this test depends on it.  If the ordering ever changes
 # in the code, we'll need to update this test.
 test_expect_success '--graph --boundary ^C3' '
-       rm -f expected &&
-       echo "* $A7" >> expected &&
-       echo "*   $A6" >> expected &&
-       echo "|\\  " >> expected &&
-       echo "| * $C4" >> expected &&
-       echo "* | $A5" >> expected &&
-       echo "| |     " >> expected &&
-       echo "|  \\    " >> expected &&
-       echo "*-. \\   $A4" >> expected &&
-       echo "|\\ \\ \\  " >> expected &&
-       echo "| * | | $B2" >> expected &&
-       echo "| * | | $B1" >> expected &&
-       echo "* | | | $A3" >> expected &&
-       echo "o | | | $A2" >> expected &&
-       echo "|/ / /  " >> expected &&
-       echo "o / / $A1" >> expected &&
-       echo " / /  " >> expected &&
-       echo "| o $C3" >> expected &&
-       echo "|/  " >> expected &&
-       echo "o $C2" >> expected &&
-       git rev-list --graph --boundary --all ^C3 > actual &&
-       test_cmp expected actual
-       '
+       check_graph --boundary --all ^C3 <<-\EOF
+       * A7
+       *   A6
+       |\
+       | * C4
+       * | A5
+       | |
+       |  \
+       *-. \   A4
+       |\ \ \
+       | * | | B2
+       | * | | B1
+       * | | | A3
+       o | | | A2
+       |/ / /
+       o / / A1
+        / /
+       | o C3
+       |/
+       o C2
+       EOF
+'
 
 test_done
index aa22638..52614ee 100755 (executable)
@@ -926,14 +926,14 @@ test_expect_success 'git bisect reset cleans bisection state properly' '
        git bisect bad $HASH4 &&
        git bisect reset &&
        test -z "$(git for-each-ref "refs/bisect/*")" &&
-       test_path_is_missing "$GIT_DIR/BISECT_EXPECTED_REV" &&
-       test_path_is_missing "$GIT_DIR/BISECT_ANCESTORS_OK" &&
-       test_path_is_missing "$GIT_DIR/BISECT_LOG" &&
-       test_path_is_missing "$GIT_DIR/BISECT_RUN" &&
-       test_path_is_missing "$GIT_DIR/BISECT_TERMS" &&
-       test_path_is_missing "$GIT_DIR/head-name" &&
-       test_path_is_missing "$GIT_DIR/BISECT_HEAD" &&
-       test_path_is_missing "$GIT_DIR/BISECT_START"
+       test_path_is_missing ".git/BISECT_EXPECTED_REV" &&
+       test_path_is_missing ".git/BISECT_ANCESTORS_OK" &&
+       test_path_is_missing ".git/BISECT_LOG" &&
+       test_path_is_missing ".git/BISECT_RUN" &&
+       test_path_is_missing ".git/BISECT_TERMS" &&
+       test_path_is_missing ".git/head-name" &&
+       test_path_is_missing ".git/BISECT_HEAD" &&
+       test_path_is_missing ".git/BISECT_START"
 '
 
 test_done
index 7476781..e5c6a03 100755 (executable)
@@ -149,6 +149,94 @@ test_expect_success '--ignore-skip-worktree-entries leaves worktree alone' '
                --diff-filter=D -- keep-me.t
 '
 
+test_expect_success 'stash restore in sparse checkout' '
+       test_create_repo stash-restore &&
+       (
+               cd stash-restore &&
+
+               mkdir subdir &&
+               echo A >subdir/A &&
+               echo untouched >untouched &&
+               echo removeme >removeme &&
+               echo modified >modified &&
+               git add . &&
+               git commit -m Initial &&
+
+               echo AA >>subdir/A &&
+               echo addme >addme &&
+               echo tweaked >>modified &&
+               rm removeme &&
+               git add addme &&
+
+               git stash push &&
+
+               git sparse-checkout set subdir &&
+
+               # Ensure after sparse-checkout we only have expected files
+               cat >expect <<-EOF &&
+               S modified
+               S removeme
+               H subdir/A
+               S untouched
+               EOF
+               git ls-files -t >actual &&
+               test_cmp expect actual &&
+
+               test_path_is_missing addme &&
+               test_path_is_missing modified &&
+               test_path_is_missing removeme &&
+               test_path_is_file    subdir/A &&
+               test_path_is_missing untouched &&
+
+               # Put a file in the working directory in the way
+               echo in the way >modified &&
+               git stash apply &&
+
+               # Ensure stash vivifies modifies paths...
+               cat >expect <<-EOF &&
+               H addme
+               H modified
+               H removeme
+               H subdir/A
+               S untouched
+               EOF
+               git ls-files -t >actual &&
+               test_cmp expect actual &&
+
+               # ...and that the paths show up in status as changed...
+               cat >expect <<-EOF &&
+               A  addme
+                M modified
+                D removeme
+                M subdir/A
+               ?? actual
+               ?? expect
+               ?? modified.stash.XXXXXX
+               EOF
+               git status --porcelain | \
+                       sed -e s/stash......./stash.XXXXXX/ >actual &&
+               test_cmp expect actual &&
+
+               # ...and that working directory reflects the files correctly
+               test_path_is_file    addme &&
+               test_path_is_file    modified &&
+               test_path_is_missing removeme &&
+               test_path_is_file    subdir/A &&
+               test_path_is_missing untouched &&
+
+               # ...including that we have the expected "modified" file...
+               cat >expect <<-EOF &&
+               modified
+               tweaked
+               EOF
+               test_cmp expect modified &&
+
+               # ...and that the other "modified" file is still present...
+               echo in the way >expect &&
+               test_cmp expect modified.stash.*
+       )
+'
+
 #TODO test_expect_failure 'git-apply adds file' false
 #TODO test_expect_failure 'git-apply updates file' false
 #TODO test_expect_failure 'git-apply removes file' false
index eec96e0..d21dc8b 100755 (executable)
@@ -201,4 +201,19 @@ test_expect_success 'fsck rejects embedded newline in relative url' '
        grep gitmodulesUrl err
 '
 
+test_expect_success 'fsck rejects embedded newline in git url' '
+       git checkout --orphan git-newline &&
+       cat >.gitmodules <<-\EOF &&
+       [submodule "foo"]
+       url = "git://example.com:1234/repo%0a.git"
+       EOF
+       git add .gitmodules &&
+       git commit -m "git url with newline" &&
+       test_when_finished "rm -rf dst" &&
+       git init --bare dst &&
+       git -C dst config transfer.fsckObjects true &&
+       test_must_fail git push dst HEAD 2>err &&
+       grep gitmodulesUrl err
+'
+
 test_done
index 70afdd0..6ac75b5 100755 (executable)
@@ -828,4 +828,15 @@ test_expect_success 'mergetool -Oorder-file is honored' '
        test_cmp expect actual
 '
 
+test_expect_success 'mergetool --tool-help shows recognized tools' '
+       # Check a few known tools are correctly shown
+       git mergetool --tool-help >mergetools &&
+       grep vimdiff mergetools &&
+       grep vimdiff3 mergetools &&
+       grep gvimdiff2 mergetools &&
+       grep araxis mergetools &&
+       grep xxdiff mergetools &&
+       grep meld mergetools
+'
+
 test_done
index 999982f..2f08ce7 100644 (file)
@@ -367,9 +367,14 @@ test_chmod () {
        git update-index --add "--chmod=$@"
 }
 
-# Get the modebits from a file or directory.
+# Get the modebits from a file or directory, ignoring the setgid bit (g+s).
+# This bit is inherited by subdirectories at their creation. So we remove it
+# from the returning string to prevent callers from having to worry about the
+# state of the bit in the test directory.
+#
 test_modebits () {
-       ls -ld "$1" | sed -e 's|^\(..........\).*|\1|'
+       ls -ld "$1" | sed -e 's|^\(..........\).*|\1|' \
+                         -e 's|^\(......\)S|\1-|' -e 's|^\(......\)s|\1x|'
 }
 
 # Unset a configuration variable, but don't fail if it doesn't exist.
index 7074bbd..40b59be 100644 (file)
@@ -1742,9 +1742,9 @@ static void wt_longstatus_print(struct wt_status *s)
                        } else if (s->state.detached_from) {
                                branch_name = s->state.detached_from;
                                if (s->state.detached_at)
-                                       on_what = HEAD_DETACHED_AT;
+                                       on_what = _("HEAD detached at ");
                                else
-                                       on_what = HEAD_DETACHED_FROM;
+                                       on_what = _("HEAD detached from ");
                        } else {
                                branch_name = "";
                                on_what = _("Not currently on any branch.");
index 35b44c3..0d32799 100644 (file)
@@ -77,8 +77,6 @@ enum wt_status_format {
        STATUS_FORMAT_UNSPECIFIED
 };
 
-#define HEAD_DETACHED_AT _("HEAD detached at ")
-#define HEAD_DETACHED_FROM _("HEAD detached from ")
 #define SPARSE_CHECKOUT_DISABLED -1
 
 struct wt_status_state {