Imported Upstream version 2.19.2 upstream/2.19.2
authorDongHun Kwak <dh0128.kwak@samsung.com>
Wed, 3 Mar 2021 06:16:43 +0000 (15:16 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Wed, 3 Mar 2021 06:16:43 +0000 (15:16 +0900)
150 files changed:
.gitattributes
.mailmap
.travis.yml
Documentation/CodingGuidelines
Documentation/Makefile
Documentation/RelNotes/2.19.2.txt [new file with mode: 0644]
Documentation/config.txt
Documentation/git-archimport.txt
Documentation/git-bisect-lk2009.txt
Documentation/git-checkout.txt
Documentation/git-column.txt
Documentation/git-commit-graph.txt
Documentation/git-describe.txt
Documentation/git-diff.txt
Documentation/git-interpret-trailers.txt
Documentation/git-merge-base.txt
Documentation/git-rebase.txt
Documentation/git-show-branch.txt
Documentation/git-tag.txt
Documentation/git-update-ref.txt
Documentation/git-upload-pack.txt
Documentation/git-worktree.txt
Documentation/git.txt
Documentation/gitattributes.txt
Documentation/gitcredentials.txt
Documentation/gitmodules.txt
Documentation/gitsubmodules.txt
Documentation/gitweb.conf.txt
Documentation/howto/update-hook-example.txt
Documentation/howto/using-merge-subtree.txt
Documentation/rev-list-options.txt
Documentation/technical/api-history-graph.txt
Documentation/technical/commit-graph.txt
GIT-VERSION-GEN
Makefile
RelNotes
archive.c
attr.c
attr.h
builtin/add.c
builtin/branch.c
builtin/cat-file.c
builtin/check-attr.c
builtin/commit-graph.c
builtin/commit.c
builtin/interpret-trailers.c
builtin/pack-objects.c
builtin/prune.c
builtin/receive-pack.c
builtin/remote.c
builtin/repack.c
builtin/replace.c
builtin/rev-list.c
builtin/update-ref.c
cache.h
command-list.txt
commit-graph.c
commit-graph.h
commit.c
commit.h
compat/mingw.c
config.mak.dev
contrib/coccinelle/preincr.cocci [new file with mode: 0644]
contrib/completion/git-completion.bash
convert.c
diff.c
fetch-object.c
fetch-object.h
fetch-pack.c
fetch-pack.h
fsck.c
graph.c
linear-assignment.c
ll-merge.c
lockfile.h
merge-recursive.c
pack-objects.c
pack-objects.h
path.c
pretty.c
read-cache.c
ref-filter.c
refs.c
refs.h
refs/iterator.c
refs/refs-internal.h
remote-curl.c
replace-object.c
replace-object.h
rerere.c
revision.c
revision.h
run-command.c
sequencer.c
sequencer.h
sha1-file.c
shallow.c
split-index.c
strbuf.h
string-list.c
string-list.h
submodule.c
t/README
t/helper/test-repository.c
t/helper/test-tool.c
t/helper/test-tool.h
t/helper/test-windows-named-pipe.c [new file with mode: 0644]
t/lib-rebase.sh
t/t0051-windows-named-pipe.sh [new file with mode: 0755]
t/t0061-run-command.sh
t/t0090-cache-tree.sh
t/t0410-partial-clone.sh
t/t1400-update-ref.sh
t/t1450-fsck.sh
t/t1500-rev-parse.sh
t/t1700-split-index.sh
t/t1701-racy-split-index.sh [new file with mode: 0755]
t/t3206-range-diff.sh
t/t3404-rebase-interactive.sh
t/t3405-rebase-malformed.sh
t/t3415-rebase-autosquash.sh
t/t3505-cherry-pick-empty.sh
t/t3701-add-interactive.sh
t/t4053-diff-no-index.sh
t/t4200-rerere.sh
t/t4202-log.sh
t/t4205-log-pretty-formats.sh
t/t4214-log-graph-octopus.sh [new file with mode: 0755]
t/t5318-commit-graph.sh
t/t5321-pack-large-objects.sh [new file with mode: 0755]
t/t5505-remote.sh
t/t5516-fetch-push.sh
t/t5537-fetch-shallow.sh
t/t5551-http-fetch-smart.sh
t/t6135-pathspec-with-attrs.sh
t/t6300-for-each-ref.sh
t/t7005-editor.sh
t/t7500-commit.sh
t/t7501-commit.sh
t/t7513-interpret-trailers.sh
t/t8002-blame.sh
t/test-lib.sh
tempfile.c
tempfile.h
trailer.c
trailer.h
unpack-trees.c
upload-pack.c
userdiff.c
ws.c

index 1bdc91e..49b3051 100644 (file)
@@ -9,3 +9,7 @@
 /command-list.txt eol=lf
 /GIT-VERSION-GEN eol=lf
 /mergetools/* eol=lf
+/Documentation/git-merge.txt conflict-marker-size=32
+/Documentation/gitk.txt conflict-marker-size=32
+/Documentation/user-manual.txt conflict-marker-size=32
+/t/t????-*.sh conflict-marker-size=32
index f165222..bef3352 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -25,7 +25,7 @@ Ben Walton <bdwalton@gmail.com> <bwalton@artsci.utoronto.ca>
 Benoit Sigoure <tsunanet@gmail.com> <tsuna@lrde.epita.fr>
 Bernt Hansen <bernt@norang.ca> <bernt@alumni.uwaterloo.ca>
 Brandon Casey <drafnel@gmail.com> <casey@nrlssc.navy.mil>
-brian m. carlson <sandals@crustytoothpaste.net> Brian M. Carlson <sandals@crustytoothpaste.ath.cx>
+brian m. carlson <sandals@crustytoothpaste.net>
 brian m. carlson <sandals@crustytoothpaste.net> <sandals@crustytoothpaste.ath.cx>
 Bryan Larsen <bryan@larsen.st> <bryan.larsen@gmail.com>
 Bryan Larsen <bryan@larsen.st> <bryanlarsen@yahoo.com>
index 4d4e26c..8d24997 100644 (file)
@@ -1,7 +1,5 @@
 language: c
 
-sudo: false
-
 cache:
   directories:
     - $HOME/travis-cache
index 48aa4ed..8dddb50 100644 (file)
@@ -358,7 +358,10 @@ For C programs:
    string_list for sorted string lists, a hash map (mapping struct
    objects) named "struct decorate", amongst other things.
 
- - When you come up with an API, document it.
+ - When you come up with an API, document its functions and structures
+   in the header file that exposes the API to its callers. Use what is
+   in "strbuf.h" as a model for the appropriate tone and level of
+   detail.
 
  - The first #include in C files, except in platform specific compat/
    implementations, must be either "git-compat-util.h", "cache.h" or
index a42dcfc..95f6a32 100644 (file)
@@ -344,7 +344,7 @@ $(OBSOLETE_HTML): %.html : %.txto asciidoc.conf
        mv $@+ $@
 
 manpage-base-url.xsl: manpage-base-url.xsl.in
-       sed "s|@@MAN_BASE_URL@@|$(MAN_BASE_URL)|" $< > $@
+       $(QUIET_GEN)sed "s|@@MAN_BASE_URL@@|$(MAN_BASE_URL)|" $< > $@
 
 %.1 %.5 %.7 : %.xml manpage-base-url.xsl
        $(QUIET_XMLTO)$(RM) $@ && \
diff --git a/Documentation/RelNotes/2.19.2.txt b/Documentation/RelNotes/2.19.2.txt
new file mode 100644 (file)
index 0000000..759e6ca
--- /dev/null
@@ -0,0 +1,108 @@
+Git v2.19.2 Release Notes
+=========================
+
+Fixes since v2.19.1
+-------------------
+
+ * "git interpret-trailers" and its underlying machinery had a buggy
+   code that attempted to ignore patch text after commit log message,
+   which triggered in various codepaths that will always get the log
+   message alone and never get such an input.
+
+ * "git rebase -i" did not clear the state files correctly when a run
+   of "squash/fixup" is aborted and then the user manually amended the
+   commit instead, which has been corrected.
+
+ * When fsmonitor is in use, after operation on submodules updates
+   .gitmodules, we lost track of the fact that we did so and relied on
+   stale fsmonitor data.
+
+ * Fix for a long-standing bug that leaves the index file corrupt when
+   it shrinks during a partial commit.
+
+ * Further fix for O_APPEND emulation on Windows
+
+ * A corner case bugfix in "git rerere" code.
+
+ * "git add ':(attr:foo)'" is not supported and is supposed to be
+   rejected while the command line arguments are parsed, but we fail
+   to reject such a command line upfront.
+
+ * "git rebase" etc. in Git 2.19 fails to abort when given an empty
+   commit log message as result of editing, which has been corrected.
+
+ * The code to backfill objects in lazily cloned repository did not
+   work correctly, which has been corrected.
+
+ * Update error messages given by "git remote" and make them consistent.
+
+ * "git update-ref" learned to make both "--no-deref" and "--stdin"
+   work at the same time.
+
+ * Recently added "range-diff" had a corner-case bug to cause it
+   segfault, which has been corrected.
+
+ * The recently introduced commit-graph auxiliary data is incompatible
+   with mechanisms such as replace & grafts that "breaks" immutable
+   nature of the object reference relationship.  Disable optimizations
+   based on its use (and updating existing commit-graph) when these
+   incompatible features are in use in the repository.
+
+ * The mailmap file update.
+
+ * The code in "git status" sometimes hit an assertion failure.  This
+   was caused by a structure that was reused without cleaning the data
+   used for the first run, which has been corrected.
+
+ * A corner-case bugfix.
+
+ * A partial clone that is configured to lazily fetch missing objects
+   will on-demand issue a "git fetch" request to the originating
+   repository to fill not-yet-obtained objects.  The request has been
+   optimized for requesting a tree object (and not the leaf blob
+   objects contained in it) by telling the originating repository that
+   no blobs are needed.
+
+ * The codepath to support the experimental split-index mode had
+   remaining "racily clean" issues fixed.
+
+ * "git log --graph" showing an octopus merge sometimes miscounted the
+   number of display columns it is consuming to show the merge and its
+   parent commits, which has been corrected.
+
+ * The implementation of run_command() API on the UNIX platforms had a
+   bug that caused a command not on $PATH to be found in the current
+   directory.
+
+ * A mutex used in "git pack-objects" were not correctly initialized
+   and this caused "git repack" to dump core on Windows.
+
+ * Under certain circumstances, "git diff D:/a/b/c D:/a/b/d" on
+   Windows would strip initial parts from the paths because they
+   were not recognized as absolute, which has been corrected.
+
+ * The receive.denyCurrentBranch=updateInstead codepath kicked in even
+   when the push should have been rejected due to other reasons, such
+   as it does not fast-forward or the update-hook rejects it, which
+   has been corrected.
+
+ * "git repack" in a shallow clone did not correctly update the
+   shallow points in the repository, leading to a repository that
+   does not pass fsck.
+
+ * Operations on promisor objects make sense in the context of only a
+   small subset of the commands that internally use the revisions
+   machinery, but the "--exclude-promisor-objects" option were taken
+   and led to nonsense results by commands like "log", to which it
+   didn't make much sense.  This has been corrected.
+
+ * The "container" mode of TravisCI is going away.  Our .travis.yml
+   file is getting prepared for the transition.
+
+ * Our test scripts can now take the '-V' option as a synonym for the
+   '--verbose-log' option.
+
+ * A regression in Git 2.12 era made "git fsck" fall into an infinite
+   loop while processing truncated loose objects.
+
+Also contains various documentation updates and code clean-ups.
index eb66a11..09a2385 100644 (file)
@@ -2828,6 +2828,8 @@ protocol.version::
 * `1` - the original wire protocol with the addition of a version string
   in the initial response from the server.
 
+* `2` - link:technical/protocol-v2.html[wire protocol version 2].
+
 --
 
 pull.ff::
@@ -3632,15 +3634,15 @@ uploadpack.packObjectsHook::
        was run. I.e., `upload-pack` will feed input intended for
        `pack-objects` to the hook, and expects a completed packfile on
        stdout.
-
-uploadpack.allowFilter::
-       If this option is set, `upload-pack` will support partial
-       clone and partial fetch object filtering.
 +
 Note that this configuration variable is ignored if it is seen in the
 repository-level config (this is a safety measure against fetching from
 untrusted repositories).
 
+uploadpack.allowFilter::
+       If this option is set, `upload-pack` will support partial
+       clone and partial fetch object filtering.
+
 uploadpack.allowRefInWant::
        If this option is set, `upload-pack` will support the `ref-in-want`
        feature of the protocol version 2 `fetch` command.  This feature
index ea70653..a595a0f 100644 (file)
@@ -3,7 +3,7 @@ git-archimport(1)
 
 NAME
 ----
-git-archimport - Import an Arch repository into Git
+git-archimport - Import a GNU Arch repository into Git
 
 
 SYNOPSIS
@@ -14,7 +14,8 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
-Imports a project from one or more Arch repositories. It will follow branches
+Imports a project from one or more GNU Arch repositories.
+It will follow branches
 and repositories within the namespaces defined by the <archive/branch>
 parameters supplied. If it cannot find the remote branch a merge comes from
 it will just import it as a regular commit. If it can find it, it will mark it
index 0f9ef2f..e999251 100644 (file)
@@ -633,11 +633,11 @@ and so at step 3) we compute f(X).
 Let's take the following graph as an example:
 
 -------------
-           G-H-I-J
-          /       \
+            G-H-I-J
+           /       \
 A-B-C-D-E-F         O
-          \       /
-           K-L-M-N
+           \       /
+            K-L-M-N
 -------------
 
 If we compute the following non optimal function on it:
@@ -649,25 +649,25 @@ g(X) = min(number_of_ancestors(X), number_of_descendants(X))
 we get:
 
 -------------
-           4 3 2 1
-           G-H-I-J
+            4 3 2 1
+            G-H-I-J
 1 2 3 4 5 6/       \0
 A-B-C-D-E-F         O
-          \       /
-           K-L-M-N
-           4 3 2 1
+           \       /
+            K-L-M-N
+            4 3 2 1
 -------------
 
 but with the algorithm used by git bisect we get:
 
 -------------
-           7 7 6 5
-           G-H-I-J
+            7 7 6 5
+            G-H-I-J
 1 2 3 4 5 6/       \0
 A-B-C-D-E-F         O
-          \       /
-           K-L-M-N
-           7 7 6 5
+           \       /
+            K-L-M-N
+            7 7 6 5
 -------------
 
 So we chose G, H, K or L as the best bisection point, which is better
@@ -773,7 +773,7 @@ forked of the main branch at a commit named "D" like this:
 -------------
 A-B-C-D-E-F-G  <--main
        \
-       H-I-J  <--dev
+        H-I-J  <--dev
 -------------
 
 The commit "D" is called a "merge base" for branch "main" and "dev"
index 9db0292..801de2f 100644 (file)
@@ -311,9 +311,9 @@ branch refers to a specific commit. Let's look at a repo with three
 commits, one of them tagged, and with branch 'master' checked out:
 
 ------------
-          HEAD (refers to branch 'master')
-           |
-           v
+           HEAD (refers to branch 'master')
+            |
+            v
 a---b---c  branch 'master' (refers to commit 'c')
     ^
     |
@@ -329,9 +329,9 @@ to commit 'd':
 ------------
 $ edit; git add; git commit
 
-              HEAD (refers to branch 'master')
-               |
-               v
+               HEAD (refers to branch 'master')
+                |
+                v
 a---b---c---d  branch 'master' (refers to commit 'd')
     ^
     |
@@ -398,7 +398,7 @@ at what happens when we then checkout master:
 ------------
 $ git checkout master
 
-              HEAD (refers to branch 'master')
+               HEAD (refers to branch 'master')
       e---f     |
      /          v
 a---b---c---d  branch 'master' (refers to commit 'd')
index 03d1846..763afab 100644 (file)
@@ -13,7 +13,10 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
-This command formats its input into multiple columns.
+This command formats the lines of its standard input into a table with
+multiple columns. Each input line occupies one cell of the table. It
+is used internally by other git commands to format output into
+columns.
 
 OPTIONS
 -------
@@ -23,7 +26,7 @@ OPTIONS
 
 --mode=<mode>::
        Specify layout mode. See configuration variable column.ui for option
-       syntax.
+       syntax in linkgit:git-config[1].
 
 --raw-mode=<n>::
        Same as --mode but take mode encoded as a number. This is mainly used
@@ -43,6 +46,34 @@ OPTIONS
 --padding=<N>::
        The number of spaces between columns. One space by default.
 
+EXAMPLES
+------
+
+Format data by columns:
+------------
+$ seq 1 24 | git column --mode=column --padding=5
+1      4      7      10     13     16     19     22
+2      5      8      11     14     17     20     23
+3      6      9      12     15     18     21     24
+------------
+
+Format data by rows:
+------------
+$ seq 1 21 | git column --mode=row --padding=5
+1      2      3      4      5      6      7
+8      9      10     11     12     13     14
+15     16     17     18     19     20     21
+------------
+
+List some tags in a table with unequal column widths:
+------------
+$ git tag --list 'v2.4.*' --column=row,dense
+v2.4.0  v2.4.0-rc0  v2.4.0-rc1  v2.4.0-rc2  v2.4.0-rc3
+v2.4.1  v2.4.10     v2.4.11     v2.4.12     v2.4.2
+v2.4.3  v2.4.4      v2.4.5      v2.4.6      v2.4.7
+v2.4.8  v2.4.9
+------------
+
 GIT
 ---
 Part of the linkgit:git[1] suite
index dececb7..624470e 100644 (file)
@@ -3,7 +3,7 @@ git-commit-graph(1)
 
 NAME
 ----
-git-commit-graph - Write and verify Git commit graph files
+git-commit-graph - Write and verify Git commit-graph files
 
 
 SYNOPSIS
@@ -17,24 +17,24 @@ SYNOPSIS
 DESCRIPTION
 -----------
 
-Manage the serialized commit graph file.
+Manage the serialized commit-graph file.
 
 
 OPTIONS
 -------
 --object-dir::
-       Use given directory for the location of packfiles and commit graph
+       Use given directory for the location of packfiles and commit-graph
        file. This parameter exists to specify the location of an alternate
-       that only has the objects directory, not a full .git directory. The
-       commit graph file is expected to be at <dir>/info/commit-graph and
-       the packfiles are expected to be in <dir>/pack.
+       that only has the objects directory, not a full `.git` directory. The
+       commit-graph file is expected to be at `<dir>/info/commit-graph` and
+       the packfiles are expected to be in `<dir>/pack`.
 
 
 COMMANDS
 --------
 'write'::
 
-Write a commit graph file based on the commits found in packfiles.
+Write a commit-graph file based on the commits found in packfiles.
 +
 With the `--stdin-packs` option, generate the new commit graph by
 walking objects only in the specified pack-indexes. (Cannot be combined
@@ -54,8 +54,8 @@ existing commit-graph file.
 
 'read'::
 
-Read a graph file given by the commit-graph file and output basic
-details about the graph file. Used for debugging purposes.
+Read the commit-graph file and output basic details about it.
+Used for debugging purposes.
 
 'verify'::
 
@@ -66,27 +66,28 @@ database. Used to check for corrupted data.
 EXAMPLES
 --------
 
-* Write a commit graph file for the packed commits in your local .git folder.
+* Write a commit-graph file for the packed commits in your local `.git`
+  directory.
 +
 ------------------------------------------------
 $ git commit-graph write
 ------------------------------------------------
 
-* Write a graph file, extending the current graph file using commits
-* in <pack-index>.
+* Write a commit-graph file, extending the current commit-graph file
+  using commits in `<pack-index>`.
 +
 ------------------------------------------------
 $ echo <pack-index> | git commit-graph write --stdin-packs
 ------------------------------------------------
 
-* Write a graph file containing all reachable commits.
+* Write a commit-graph file containing all reachable commits.
 +
 ------------------------------------------------
 $ git show-ref -s | git commit-graph write --stdin-commits
 ------------------------------------------------
 
-* Write a graph file containing all commits in the current
-* commit-graph file along with those reachable from HEAD.
+* Write a commit-graph file containing all commits in the current
+  commit-graph file along with those reachable from `HEAD`.
 +
 ------------------------------------------------
 $ git rev-parse HEAD | git commit-graph write --stdin-commits --append
index e027fb8..ccdc5f8 100644 (file)
@@ -18,7 +18,9 @@ The command finds the most recent tag that is reachable from a
 commit.  If the tag points to the commit, then only the tag is
 shown.  Otherwise, it suffixes the tag name with the number of
 additional commits on top of the tagged object and the
-abbreviated object name of the most recent commit.
+abbreviated object name of the most recent commit. The result
+is a "human-readable" object name which can also be used to
+identify the commit to other git commands.
 
 By default (without --all or --tags) `git describe` only shows
 annotated tags.  For more information about creating annotated tags
index b180f1f..030f162 100644 (file)
@@ -72,10 +72,10 @@ two blob objects, or changes between two files on disk.
        This form is to view the changes on the branch containing
        and up to the second <commit>, starting at a common ancestor
        of both <commit>.  "git diff A\...B" is equivalent to
-       "git diff $(git-merge-base A B) B".  You can omit any one
+       "git diff $(git merge-base A B) B".  You can omit any one
        of <commit>, which has the same effect as using HEAD instead.
 
-Just in case if you are doing something exotic, it should be
+Just in case you are doing something exotic, it should be
 noted that all of the <commit> in the above description, except
 in the last two forms that use ".." notations, can be any
 <tree>.
index b8fafb1..a5e8b36 100644 (file)
@@ -56,8 +56,9 @@ least one Git-generated or user-configured trailer and consists of at
 least 25% trailers.
 The group must be preceded by one or more empty (or whitespace-only) lines.
 The group must either be at the end of the message or be the last
-non-whitespace lines before a line that starts with '---'. Such three
-minus signs start the patch part of the message.
+non-whitespace lines before a line that starts with '---' (followed by a
+space or the end of the line). Such three minus signs start the patch
+part of the message. See also `--no-divider` below.
 
 When reading trailers, there can be whitespaces after the
 token, the separator and the value. There can also be whitespaces
@@ -125,6 +126,11 @@ OPTIONS
        A convenience alias for `--only-trailers --only-input
        --unfold`.
 
+--no-divider::
+       Do not treat `---` as the end of the commit message. Use this
+       when you know your input contains just the commit message itself
+       (and not an email or the output of `git format-patch`).
+
 CONFIGURATION VARIABLES
 -----------------------
 
index 502e00e..9f07f4f 100644 (file)
@@ -154,13 +154,13 @@ topic origin/master`, the history of remote-tracking branch
 `origin/master` may have been rewound and rebuilt, leading to a
 history of this shape:
 
-                        o---B2
+                        o---B2
                        /
        ---o---o---B1--o---o---o---B (origin/master)
                \
-                B0
+                B0
                  \
-                  D0---D1---D (topic)
+                  D0---D1---D (topic)
 
 where `origin/master` used to point at commits B0, B1, B2 and now it
 points at B, and your `topic` branch was started on top of it back
index 1fbc6eb..432baab 100644 (file)
@@ -954,7 +954,7 @@ command fails, it is rescheduled immediately, with a helpful message how
 to proceed.
 
 The `reset` command resets the HEAD, index and worktree to the specified
-revision. It is isimilar to an `exec git reset --hard <label>`, but
+revision. It is similar to an `exec git reset --hard <label>`, but
 refuses to overwrite untracked files. If the `reset` command fails, it is
 rescheduled immediately, with a helpful message how to edit the todo list
 (this typically happens when a `reset` command was inserted into the todo
index 262db04..4a01371 100644 (file)
@@ -19,7 +19,7 @@ DESCRIPTION
 -----------
 
 Shows the commit ancestry graph starting from the commits named
-with <rev>s or <globs>s (or all refs under refs/heads
+with <rev>s or <glob>s (or all refs under refs/heads
 and/or refs/tags) semi-visually.
 
 It cannot show more than 29 branches and commits at a time.
index 92f9c12..f2d644e 100644 (file)
@@ -187,6 +187,12 @@ This option is only applicable when listing tags without annotation lines.
        `--create-reflog`, but currently does not negate the setting of
        `core.logAllRefUpdates`.
 
+--format=<format>::
+       A string that interpolates `%(fieldname)` from a tag ref being shown
+       and the object it points at.  The format is the same as
+       that of linkgit:git-for-each-ref[1].  When unspecified,
+       defaults to `%(refname:strip=2)`.
+
 <tagname>::
        The name of the tag to create, delete, or describe.
        The new tag name must pass all checks defined by
@@ -198,12 +204,6 @@ This option is only applicable when listing tags without annotation lines.
        The object that the new tag will refer to, usually a commit.
        Defaults to HEAD.
 
-<format>::
-       A string that interpolates `%(fieldname)` from a tag ref being shown
-       and the object it points at.  The format is the same as
-       that of linkgit:git-for-each-ref[1].  When unspecified,
-       defaults to `%(refname:strip=2)`.
-
 CONFIGURATION
 -------------
 By default, 'git tag' in sign-with-default mode (-s) will use your
index bc8fdfd..9671423 100644 (file)
@@ -8,7 +8,7 @@ git-update-ref - Update the object name stored in a ref safely
 SYNOPSIS
 --------
 [verse]
-'git update-ref' [-m <reason>] (-d <ref> [<oldvalue>] | [--no-deref] [--create-reflog] <ref> <newvalue> [<oldvalue>] | --stdin [-z])
+'git update-ref' [-m <reason>] [--no-deref] (-d <ref> [<oldvalue>] | [--create-reflog] <ref> <newvalue> [<oldvalue>] | --stdin [-z])
 
 DESCRIPTION
 -----------
@@ -129,8 +129,8 @@ a line to the log file "$GIT_DIR/logs/<ref>" (dereferencing all
 symbolic refs before creating the log name) describing the change
 in ref value.  Log lines are formatted as:
 
-    oldsha1 SP newsha1 SP committer LF
-+
+    oldsha1 SP newsha1 SP committer LF
+
 Where "oldsha1" is the 40 character hexadecimal value previously
 stored in <ref>, "newsha1" is the 40 character hexadecimal value of
 <newvalue> and "committer" is the committer's name, email address
@@ -138,8 +138,8 @@ and date in the standard Git committer ident format.
 
 Optionally with -m:
 
-    oldsha1 SP newsha1 SP committer TAB message LF
-+
+    oldsha1 SP newsha1 SP committer TAB message LF
+
 Where all fields are as described above and "message" is the
 value supplied to the -m option.
 
index 822ad59..998f52d 100644 (file)
@@ -11,6 +11,7 @@ SYNOPSIS
 [verse]
 'git-upload-pack' [--[no-]strict] [--timeout=<n>] [--stateless-rpc]
                  [--advertise-refs] <directory>
+
 DESCRIPTION
 -----------
 Invoked by 'git fetch-pack', learns what
index 29a5b7e..d707e61 100644 (file)
@@ -262,8 +262,8 @@ Porcelain Format
 The porcelain format has a line per attribute.  Attributes are listed with a
 label and value separated by a single space.  Boolean attributes (like 'bare'
 and 'detached') are listed as a label only, and are only present if and only
-if the value is true.  An empty line indicates the end of a worktree.  For
-example:
+if the value is true.  The first attribute of a worktree is always `worktree`,
+an empty line indicates the end of the record.  For example:
 
 ------------
 $ git worktree list --porcelain
index dba7f0c..254f063 100644 (file)
@@ -402,11 +402,11 @@ Git so take care if using a foreign front-end.
        of Git object directories which can be used to search for Git
        objects. New objects will not be written to these directories.
 +
-       Entries that begin with `"` (double-quote) will be interpreted
-       as C-style quoted paths, removing leading and trailing
-       double-quotes and respecting backslash escapes. E.g., the value
-       `"path-with-\"-and-:-in-it":vanilla-path` has two paths:
-       `path-with-"-and-:-in-it` and `vanilla-path`.
+Entries that begin with `"` (double-quote) will be interpreted
+as C-style quoted paths, removing leading and trailing
+double-quotes and respecting backslash escapes. E.g., the value
+`"path-with-\"-and-:-in-it":vanilla-path` has two paths:
+`path-with-"-and-:-in-it` and `vanilla-path`.
 
 `GIT_DIR`::
        If the `GIT_DIR` environment variable is set then it
@@ -599,8 +599,8 @@ trace messages into this file descriptor.
 +
 Alternatively, if the variable is set to an absolute path
 (starting with a '/' character), Git will interpret this
-as a file path and will try to write the trace messages
-into it.
+as a file path and will try to append the trace messages
+to it.
 +
 Unsetting the variable, or setting it to empty, "0" or
 "false" (case insensitive) disables trace messages.
@@ -858,7 +858,9 @@ Reporting Bugs
 
 Report bugs to the Git mailing list <git@vger.kernel.org> where the
 development and maintenance is primarily done.  You do not have to be
-subscribed to the list to send a message there.
+subscribed to the list to send a message there.  See the list archive
+at https://public-inbox.org/git for previous bug reports and other
+discussions.
 
 Issues which are security relevant should be disclosed privately to
 the Git Security mailing list <git-security@googlegroups.com>.
index 92010b0..b8392fc 100644 (file)
@@ -303,21 +303,21 @@ number of pitfalls:
   attribute. If you decide to use the `working-tree-encoding` attribute
   in your repository, then it is strongly recommended to ensure that all
   clients working with the repository support it.
-
-  For example, Microsoft Visual Studio resources files (`*.rc`) or
-  PowerShell script files (`*.ps1`) are sometimes encoded in UTF-16.
-  If you declare `*.ps1` as files as UTF-16 and you add `foo.ps1` with
-  a `working-tree-encoding` enabled Git client, then `foo.ps1` will be
-  stored as UTF-8 internally. A client without `working-tree-encoding`
-  support will checkout `foo.ps1` as UTF-8 encoded file. This will
-  typically cause trouble for the users of this file.
-
-  If a Git client, that does not support the `working-tree-encoding`
-  attribute, adds a new file `bar.ps1`, then `bar.ps1` will be
-  stored "as-is" internally (in this example probably as UTF-16).
-  A client with `working-tree-encoding` support will interpret the
-  internal contents as UTF-8 and try to convert it to UTF-16 on checkout.
-  That operation will fail and cause an error.
++
+For example, Microsoft Visual Studio resources files (`*.rc`) or
+PowerShell script files (`*.ps1`) are sometimes encoded in UTF-16.
+If you declare `*.ps1` as files as UTF-16 and you add `foo.ps1` with
+a `working-tree-encoding` enabled Git client, then `foo.ps1` will be
+stored as UTF-8 internally. A client without `working-tree-encoding`
+support will checkout `foo.ps1` as UTF-8 encoded file. This will
+typically cause trouble for the users of this file.
++
+If a Git client, that does not support the `working-tree-encoding`
+attribute, adds a new file `bar.ps1`, then `bar.ps1` will be
+stored "as-is" internally (in this example probably as UTF-16).
+A client with `working-tree-encoding` support will interpret the
+internal contents as UTF-8 and try to convert it to UTF-16 on checkout.
+That operation will fail and cause an error.
 
 - Reencoding content to non-UTF encodings can cause errors as the
   conversion might not be UTF-8 round trip safe. If you suspect your
index f970196..adc7596 100644 (file)
@@ -133,6 +133,12 @@ compares hostnames exactly, without considering whether two hosts are part of
 the same domain. Likewise, a config entry for `http://example.com` would not
 match: Git compares the protocols exactly.
 
+If the "pattern" URL does include a path component, then this too must match
+exactly: the context `https://example.com/bar/baz.git` will match a config
+entry for `https://example.com/bar/baz.git` (in addition to matching the config
+entry for `https://example.com`) but will not match a config entry for
+`https://example.com/bar`.
+
 
 CONFIGURATION OPTIONS
 ---------------------
index 4d63def..312b6f9 100644 (file)
@@ -67,7 +67,8 @@ submodule.<name>.fetchRecurseSubmodules::
 submodule.<name>.ignore::
        Defines under what circumstances "git status" and the diff family show
        a submodule as modified. The following values are supported:
-
++
+--
        all;; The submodule will never be considered modified (but will
            nonetheless show up in the output of status and commit when it has
            been staged).
@@ -84,12 +85,14 @@ 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
-       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
-       "--ignore-submodule" option. The 'git submodule' commands are not
-       affected by this setting.
+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.
+
+Both settings can be overridden on the command line by using the
+"--ignore-submodule" option. The 'git submodule' commands are not
+affected by this setting.
+--
 
 submodule.<name>.shallow::
        When set to true, a clone of this submodule will be performed as a
index 504c5f1..57999e9 100644 (file)
@@ -169,11 +169,15 @@ ACTIVE SUBMODULES
 
 A submodule is considered active,
 
-  (a) if `submodule.<name>.active` is set to `true`
-     or
-  (b) if the submodule's path matches the pathspec in `submodule.active`
-     or
-  (c) if `submodule.<name>.url` is set.
+  a. if `submodule.<name>.active` is set to `true`
++
+or
+
+  b. if the submodule's path matches the pathspec in `submodule.active`
++
+or
+
+  c. if `submodule.<name>.url` is set.
 
 and these are evaluated in this order.
 
index 9c8982e..c0a326e 100644 (file)
@@ -19,10 +19,12 @@ end of a line is ignored.  See *perlsyn*(1) for details.
 
 An example:
 
-    # gitweb configuration file for http://git.example.org
-    #
-    our $projectroot = "/srv/git"; # FHS recommendation
-    our $site_name = 'Example.org >> Repos';
+------------------------------------------------
+# gitweb configuration file for http://git.example.org
+#
+our $projectroot = "/srv/git"; # FHS recommendation
+our $site_name = 'Example.org >> Repos';
+------------------------------------------------
 
 
 The configuration file is used to override the default settings that
@@ -357,6 +359,7 @@ $home_link_str::
 +
 For example, the following setting produces a breadcrumb trail like
 "home / dev / projects / ..." where "projects" is the home link.
++
 ----------------------------------------------------------------------------
     our @extra_breadcrumbs = (
       [ 'home' => 'https://www.example.org/' ],
@@ -901,14 +904,16 @@ To enable blame, pickaxe search, and snapshot support (allowing "tar.gz" and
 "zip" snapshots), while allowing individual projects to turn them off, put
 the following in your GITWEB_CONFIG file:
 
-       $feature{'blame'}{'default'} = [1];
-       $feature{'blame'}{'override'} = 1;
+--------------------------------------------------------------------------------
+$feature{'blame'}{'default'} = [1];
+$feature{'blame'}{'override'} = 1;
 
-       $feature{'pickaxe'}{'default'} = [1];
-       $feature{'pickaxe'}{'override'} = 1;
+$feature{'pickaxe'}{'default'} = [1];
+$feature{'pickaxe'}{'override'} = 1;
 
-       $feature{'snapshot'}{'default'} = ['zip', 'tgz'];
-       $feature{'snapshot'}{'override'} = 1;
+$feature{'snapshot'}{'default'} = ['zip', 'tgz'];
+$feature{'snapshot'}{'override'} = 1;
+--------------------------------------------------------------------------------
 
 If you allow overriding for the snapshot feature, you can specify which
 snapshot formats are globally disabled. You can also add any command-line
index a5193b1..89821ec 100644 (file)
@@ -80,7 +80,7 @@ case "$1" in
       info "The branch '$1' is new..."
     else
       # updating -- make sure it is a fast-forward
-      mb=$(git-merge-base "$2" "$3")
+      mb=$(git merge-base "$2" "$3")
       case "$mb,$2" in
         "$2,$mb") info "Update is fast-forward" ;;
        *)        noff=y; info "This is not a fast-forward update.";;
index 1ae8d12..a499a94 100644 (file)
@@ -33,7 +33,7 @@ Here is the command sequence you need:
 
 ----------------
 $ git remote add -f Bproject /path/to/B <1>
-$ git merge -s ours --no-commit Bproject/master <2>
+$ git merge -s ours --no-commit --allow-unrelated-histories Bproject/master <2>
 $ git read-tree --prefix=dir-B/ -u Bproject/master <3>
 $ git commit -m "Merge B project as our subdirectory" <4>
 
index 7b27363..21978eb 100644 (file)
@@ -756,7 +756,6 @@ Unexpected missing objects will raise an error.
 +
 The form '--missing=print' is like 'allow-any', but will also print a
 list of the missing objects.  Object IDs are prefixed with a ``?'' character.
-endif::git-rev-list[]
 
 --exclude-promisor-objects::
        (For internal use only.)  Prefilter object traversal at
@@ -764,6 +763,7 @@ endif::git-rev-list[]
        stronger than `--missing=allow-promisor` because it limits the
        traversal, rather than just silencing errors about missing
        objects.
+endif::git-rev-list[]
 
 --no-walk[=(sorted|unsorted)]::
        Only show the given commits, but do not traverse their ancestors.
index 18142b6..d0d1707 100644 (file)
@@ -80,7 +80,7 @@ Calling sequence
   it is invoked.
 
 * For each commit, call `graph_next_line()` repeatedly, until
-  `graph_is_commit_finished()` returns non-zero.  Each call go
+  `graph_is_commit_finished()` returns non-zero.  Each call to
   `graph_next_line()` will output a single line of the graph.  The resulting
   lines will not contain any newlines.  `graph_next_line()` returns 1 if the
   resulting line contains the current commit, or 0 if this is merely a line
@@ -115,7 +115,6 @@ struct commit *commit;
 struct git_graph *graph = graph_init(opts);
 
 while ((commit = get_revision(opts)) != NULL) {
-       graph_update(graph, commit);
        while (!graph_is_commit_finished(graph))
        {
                struct strbuf sb;
index c664acb..7805b09 100644 (file)
@@ -15,13 +15,13 @@ There are two main costs here:
 1. Decompressing and parsing commits.
 2. Walking the entire graph to satisfy topological order constraints.
 
-The commit graph file is a supplemental data structure that accelerates
+The commit-graph file is a supplemental data structure that accelerates
 commit graph walks. If a user downgrades or disables the 'core.commitGraph'
 config setting, then the existing ODB is sufficient. The file is stored
 as "commit-graph" either in the .git/objects/info directory or in the info
 directory of an alternate.
 
-The commit graph file stores the commit graph structure along with some
+The commit-graph file stores the commit graph structure along with some
 extra metadata to speed up graph walks. By listing commit OIDs in lexi-
 cographic order, we can identify an integer position for each commit and
 refer to the parents of a commit using those integer positions. We use
@@ -103,7 +103,7 @@ that of a parent.
 Design Details
 --------------
 
-- The commit graph file is stored in a file named 'commit-graph' in the
+- The commit-graph file is stored in a file named 'commit-graph' in the
   .git/objects/info directory. This could be stored in the info directory
   of an alternate.
 
@@ -112,12 +112,24 @@ Design Details
 - The file format includes parameters for the object ID hash function,
   so a future change of hash algorithm does not require a change in format.
 
+- Commit grafts and replace objects can change the shape of the commit
+  history. The latter can also be enabled/disabled on the fly using
+  `--no-replace-objects`. This leads to difficultly storing both possible
+  interpretations of a commit id, especially when computing generation
+  numbers. The commit-graph will not be read or written when
+  replace-objects or grafts are present.
+
+- Shallow clones create grafts of commits by dropping their parents. This
+  leads the commit-graph to think those commits have generation number 1.
+  If and when those commits are made unshallow, those generation numbers
+  become invalid. Since shallow clones are intended to restrict the commit
+  history to a very small set of commits, the commit-graph feature is less
+  helpful for these clones, anyway. The commit-graph will not be read or
+  written when shallow commits are present.
+
 Future Work
 -----------
 
-- The commit graph feature currently does not honor commit grafts. This can
-  be remedied by duplicating or refactoring the current graft logic.
-
 - After computing and storing generation numbers, we must make graph
   walks aware of generation numbers to gain the performance benefits they
   enable. This will mostly be accomplished by swapping a commit-date-ordered
@@ -127,7 +139,7 @@ Future Work
     - 'log --topo-order'
     - 'tag --merged'
 
-- A server could provide a commit graph file as part of the network protocol
+- A server could provide a commit-graph file as part of the network protocol
   to avoid extra calculations by clients. This feature is only of benefit if
   the user is willing to trust the file, because verifying the file is correct
   is as hard as computing it from scratch.
index 164fa4f..1b9ba0a 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v2.19.1
+DEF_VER=v2.19.2
 
 LF='
 '
index 5a969f5..02a452b 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -738,6 +738,7 @@ TEST_BUILTINS_OBJS += test-submodule-config.o
 TEST_BUILTINS_OBJS += test-subprocess.o
 TEST_BUILTINS_OBJS += test-urlmatch-normalization.o
 TEST_BUILTINS_OBJS += test-wildmatch.o
+TEST_BUILTINS_OBJS += test-windows-named-pipe.o
 TEST_BUILTINS_OBJS += test-write-cache.o
 
 TEST_PROGRAMS_NEED_X += test-dump-fsmonitor
index 5c08e40..2d9f750 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.19.1.txt
\ No newline at end of file
+Documentation/RelNotes/2.19.2.txt
\ No newline at end of file
index 0a07b14..c187010 100644 (file)
--- a/archive.c
+++ b/archive.c
@@ -110,7 +110,8 @@ static const struct attr_check *get_archive_attrs(struct index_state *istate,
        static struct attr_check *check;
        if (!check)
                check = attr_check_initl("export-ignore", "export-subst", NULL);
-       return git_check_attr(istate, path, check) ? NULL : check;
+       git_check_attr(istate, path, check);
+       return check;
 }
 
 static int check_attr_export_ignore(const struct attr_check *check)
diff --git a/attr.c b/attr.c
index 98e4953..60d2847 100644 (file)
--- a/attr.c
+++ b/attr.c
@@ -1143,9 +1143,9 @@ static void collect_some_attrs(const struct index_state *istate,
        fill(path, pathlen, basename_offset, check->stack, check->all_attrs, rem);
 }
 
-int git_check_attr(const struct index_state *istate,
-                  const char *path,
-                  struct attr_check *check)
+void git_check_attr(const struct index_state *istate,
+                   const char *path,
+                   struct attr_check *check)
 {
        int i;
 
@@ -1158,8 +1158,6 @@ int git_check_attr(const struct index_state *istate,
                        value = ATTR__UNSET;
                check->items[i].value = value;
        }
-
-       return 0;
 }
 
 void git_all_attrs(const struct index_state *istate,
diff --git a/attr.h b/attr.h
index 2be86db..b0378bf 100644 (file)
--- a/attr.h
+++ b/attr.h
@@ -63,8 +63,8 @@ void attr_check_free(struct attr_check *check);
  */
 const char *git_attr_name(const struct git_attr *);
 
-int git_check_attr(const struct index_state *istate,
-                  const char *path, struct attr_check *check);
+void git_check_attr(const struct index_state *istate,
+                   const char *path, struct attr_check *check);
 
 /*
  * Retrieve all attributes that apply to the specified path.
index 9916498..0b64bcd 100644 (file)
@@ -454,7 +454,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
         * Check the "pathspec '%s' did not match any files" block
         * below before enabling new magic.
         */
-       parse_pathspec(&pathspec, 0,
+       parse_pathspec(&pathspec, PATHSPEC_ATTR,
                       PATHSPEC_PREFER_FULL |
                       PATHSPEC_SYMLINK_LEADING_PATH,
                       prefix, argv);
index bbd006a..ca9ed0a 100644 (file)
@@ -735,8 +735,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                print_columns(&output, colopts, NULL);
                string_list_clear(&output, 0);
                return 0;
-       }
-       else if (edit_description) {
+       } else if (edit_description) {
                const char *branch_name;
                struct strbuf branch_ref = STRBUF_INIT;
 
@@ -828,11 +827,6 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                git_config_set_multivar(buf.buf, NULL, NULL, 1);
                strbuf_release(&buf);
        } else if (argc > 0 && argc <= 2) {
-               struct branch *branch = branch_get(argv[0]);
-
-               if (!branch)
-                       die(_("no such branch '%s'"), argv[0]);
-
                if (filter.kind != FILTER_REFS_BRANCHES)
                        die(_("-a and -r options to 'git branch' do not make sense with a branch name"));
 
index 64ec174..0520cec 100644 (file)
@@ -50,6 +50,13 @@ static int filter_object(const char *path, unsigned mode,
        return 0;
 }
 
+static int stream_blob(const struct object_id *oid)
+{
+       if (stream_blob_to_fd(1, oid, NULL, 0))
+               die("unable to stream %s to stdout", oid_to_hex(oid));
+       return 0;
+}
+
 static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
                        int unknown_type)
 {
@@ -131,7 +138,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
                }
 
                if (type == OBJ_BLOB)
-                       return stream_blob_to_fd(1, &oid, NULL, 0);
+                       return stream_blob(&oid);
                buf = read_object_file(&oid, &type, &size);
                if (!buf)
                        die("Cannot read object %s", obj_name);
@@ -154,7 +161,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
                                oidcpy(&blob_oid, &oid);
 
                        if (oid_object_info(the_repository, &blob_oid, NULL) == OBJ_BLOB)
-                               return stream_blob_to_fd(1, &blob_oid, NULL, 0);
+                               return stream_blob(&blob_oid);
                        /*
                         * we attempted to dereference a tag to a blob
                         * and failed; there may be new dereference
@@ -317,8 +324,9 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
                                BUG("invalid cmdmode: %c", opt->cmdmode);
                        batch_write(opt, contents, size);
                        free(contents);
-               } else if (stream_blob_to_fd(1, oid, NULL, 0) < 0)
-                       die("unable to stream %s to stdout", oid_to_hex(oid));
+               } else {
+                       stream_blob(oid);
+               }
        }
        else {
                enum object_type type;
index c05573f..30a2f84 100644 (file)
@@ -65,8 +65,7 @@ static void check_attr(const char *prefix,
        if (collect_all) {
                git_all_attrs(&the_index, full_path, check);
        } else {
-               if (git_check_attr(&the_index, full_path, check))
-                       die("git_check_attr died");
+               git_check_attr(&the_index, full_path, check);
        }
        output_attr(check, file);
 
index 0bf0c48..da737df 100644 (file)
@@ -120,6 +120,8 @@ static int graph_read(int argc, const char **argv)
        return 0;
 }
 
+extern int read_replace_refs;
+
 static int graph_write(int argc, const char **argv)
 {
        struct string_list *pack_indexes = NULL;
@@ -150,6 +152,8 @@ static int graph_write(int argc, const char **argv)
        if (!opts.obj_dir)
                opts.obj_dir = get_object_directory();
 
+       read_replace_refs = 0;
+
        if (opts.reachable) {
                write_commit_graph_reachable(opts.obj_dir, opts.append);
                return 0;
index 0d9828e..83233ca 100644 (file)
@@ -872,6 +872,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
                s->use_color = 0;
                commitable = run_status(s->fp, index_file, prefix, 1, s);
                s->use_color = saved_color_setting;
+               string_list_clear(&s->change, 1);
        } else {
                struct object_id oid;
                const char *parent = "HEAD";
index b742539..4b87e0d 100644 (file)
@@ -104,6 +104,7 @@ int cmd_interpret_trailers(int argc, const char **argv, const char *prefix)
                OPT_BOOL(0, "unfold", &opts.unfold, N_("join whitespace-continued values")),
                { OPTION_CALLBACK, 0, "parse", &opts, NULL, N_("set parsing options"),
                        PARSE_OPT_NOARG | PARSE_OPT_NONEG, parse_opt_parse },
+               OPT_BOOL(0, "no-divider", &opts.no_divider, N_("do not treat --- specially")),
                OPT_CALLBACK(0, "trailer", &trailers, N_("trailer"),
                                N_("trailer(s) to add"), option_parse_trailer),
                OPT_END()
index d1144a8..2eba0a6 100644 (file)
@@ -951,8 +951,7 @@ static int no_try_delta(const char *path)
 
        if (!check)
                check = attr_check_initl("delta", NULL);
-       if (git_check_attr(&the_index, path, check))
-               return 0;
+       git_check_attr(&the_index, path, check);
        if (ATTR_FALSE(check->items[0].value))
                return 1;
        return 0;
@@ -2299,7 +2298,6 @@ static void init_threaded_search(void)
        pthread_mutex_init(&cache_mutex, NULL);
        pthread_mutex_init(&progress_mutex, NULL);
        pthread_cond_init(&progress_cond, NULL);
-       pthread_mutex_init(&to_pack.lock, NULL);
        old_try_to_free_routine = set_try_to_free_routine(try_to_free_from_threads);
 }
 
@@ -2991,6 +2989,7 @@ static void get_object_list(int ac, const char **av)
 
        init_revisions(&revs, NULL);
        save_commit_buffer = 0;
+       revs.allow_exclude_promisor_objects_opt = 1;
        setup_revisions(ac, av, &revs, NULL);
 
        /* make sure shallows are read */
index 4916a4d..d356ad7 100644 (file)
@@ -120,6 +120,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
        save_commit_buffer = 0;
        read_replace_refs = 0;
        ref_paranoia = 1;
+       revs.allow_exclude_promisor_objects_opt = 1;
        init_revisions(&revs, prefix);
 
        argc = parse_options(argc, argv, prefix, options, prune_usage, 0);
@@ -161,7 +162,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
        free(s);
 
        if (is_repository_shallow(the_repository))
-               prune_shallow(show_only);
+               prune_shallow(show_only ? PRUNE_SHOW_ONLY : 0);
 
        return 0;
 }
index c17ce94..95eb700 100644 (file)
@@ -465,7 +465,7 @@ static char *prepare_push_cert_nonce(const char *path, timestamp_t stamp)
        unsigned char sha1[GIT_SHA1_RAWSZ];
 
        strbuf_addf(&buf, "%s:%"PRItime, path, stamp);
-       hmac_sha1(sha1, buf.buf, buf.len, cert_nonce_seed, strlen(cert_nonce_seed));;
+       hmac_sha1(sha1, buf.buf, buf.len, cert_nonce_seed, strlen(cert_nonce_seed));
        strbuf_release(&buf);
 
        /* RFC 2104 5. HMAC-SHA1-80 */
@@ -1025,6 +1025,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
        const char *ret;
        struct object_id *old_oid = &cmd->old_oid;
        struct object_id *new_oid = &cmd->new_oid;
+       int do_update_worktree = 0;
 
        /* only refs/... are allowed */
        if (!starts_with(name, "refs/") || check_refname_format(name + 5, 0)) {
@@ -1050,9 +1051,8 @@ static const char *update(struct command *cmd, struct shallow_info *si)
                                refuse_unconfigured_deny();
                        return "branch is currently checked out";
                case DENY_UPDATE_INSTEAD:
-                       ret = update_worktree(new_oid->hash);
-                       if (ret)
-                               return ret;
+                       /* pass -- let other checks intervene first */
+                       do_update_worktree = 1;
                        break;
                }
        }
@@ -1117,6 +1117,12 @@ static const char *update(struct command *cmd, struct shallow_info *si)
                return "hook declined";
        }
 
+       if (do_update_worktree) {
+               ret = update_worktree(new_oid->hash);
+               if (ret)
+                       return ret;
+       }
+
        if (is_null_oid(new_oid)) {
                struct strbuf err = STRBUF_INIT;
                if (!parse_object(the_repository, old_oid)) {
@@ -1833,7 +1839,7 @@ static void prepare_shallow_update(struct command *commands,
        /*
         * keep hooks happy by forcing a temporary shallow file via
         * env variable because we can't add --shallow-file to every
-        * command. check_everything_connected() will be done with
+        * command. check_connected() will be done with
         * true .git/shallow though.
         */
        setenv(GIT_SHALLOW_FILE_ENVIRONMENT, alt_shallow_file, 1);
index 7876db1..5fd1012 100644 (file)
@@ -625,7 +625,7 @@ static int mv(int argc, const char **argv)
 
        oldremote = remote_get(rename.old_name);
        if (!remote_is_configured(oldremote, 1))
-               die(_("No such remote: %s"), rename.old_name);
+               die(_("No such remote: '%s'"), rename.old_name);
 
        if (!strcmp(rename.old_name, rename.new_name) && oldremote->origin != REMOTE_CONFIG)
                return migrate_file(oldremote);
@@ -761,7 +761,7 @@ static int rm(int argc, const char **argv)
 
        remote = remote_get(argv[1]);
        if (!remote_is_configured(remote, 1))
-               die(_("No such remote: %s"), argv[1]);
+               die(_("No such remote: '%s'"), argv[1]);
 
        known_remotes.to_delete = remote;
        for_each_remote(add_known_remote, &known_remotes);
@@ -860,7 +860,7 @@ static int get_remote_ref_states(const char *name,
 
        states->remote = remote_get(name);
        if (!states->remote)
-               return error(_("No such remote: %s"), name);
+               return error(_("No such remote: '%s'"), name);
 
        read_branches();
 
index d588603..3c30e16 100644 (file)
@@ -531,6 +531,12 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
                if (!po_args.quiet && isatty(2))
                        opts |= PRUNE_PACKED_VERBOSE;
                prune_packed_objects(opts);
+
+               if (!keep_unreachable &&
+                   (!(pack_everything & LOOSEN_UNREACHABLE) ||
+                    unpack_unreachable) &&
+                   is_repository_shallow(the_repository))
+                       prune_shallow(PRUNE_QUICK);
        }
 
        if (!no_update_server_info)
index 4f05791..17868a9 100644 (file)
@@ -39,7 +39,8 @@ struct show_data {
        enum replace_format format;
 };
 
-static int show_reference(const char *refname, const struct object_id *oid,
+static int show_reference(struct repository *r, const char *refname,
+                         const struct object_id *oid,
                          int flag, void *cb_data)
 {
        struct show_data *data = cb_data;
@@ -56,9 +57,8 @@ static int show_reference(const char *refname, const struct object_id *oid,
                        if (get_oid(refname, &object))
                                return error(_("failed to resolve '%s' as a valid ref"), refname);
 
-                       obj_type = oid_object_info(the_repository, &object,
-                                                  NULL);
-                       repl_type = oid_object_info(the_repository, oid, NULL);
+                       obj_type = oid_object_info(r, &object, NULL);
+                       repl_type = oid_object_info(r, oid, NULL);
 
                        printf("%s (%s) -> %s (%s)\n", refname, type_name(obj_type),
                               oid_to_hex(oid), type_name(repl_type));
index 5b07f3f..41dd33c 100644 (file)
@@ -372,6 +372,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
        git_config(git_default_config, NULL);
        init_revisions(&revs, prefix);
        revs.abbrev = DEFAULT_ABBREV;
+       revs.allow_exclude_promisor_objects_opt = 1;
        revs.commit_format = CMIT_FMT_UNSPECIFIED;
 
        /*
index 4fa3c0a..2d8f7f0 100644 (file)
@@ -14,7 +14,8 @@ static const char * const git_update_ref_usage[] = {
 };
 
 static char line_termination = '\n';
-static int update_flags;
+static unsigned int update_flags;
+static unsigned int default_flags;
 static unsigned create_reflog_flag;
 static const char *msg;
 
@@ -205,7 +206,7 @@ static const char *parse_cmd_update(struct ref_transaction *transaction,
                                   msg, &err))
                die("%s", err.buf);
 
-       update_flags = 0;
+       update_flags = default_flags;
        free(refname);
        strbuf_release(&err);
 
@@ -237,7 +238,7 @@ static const char *parse_cmd_create(struct ref_transaction *transaction,
                                   msg, &err))
                die("%s", err.buf);
 
-       update_flags = 0;
+       update_flags = default_flags;
        free(refname);
        strbuf_release(&err);
 
@@ -273,7 +274,7 @@ static const char *parse_cmd_delete(struct ref_transaction *transaction,
                                   update_flags, msg, &err))
                die("%s", err.buf);
 
-       update_flags = 0;
+       update_flags = default_flags;
        free(refname);
        strbuf_release(&err);
 
@@ -302,7 +303,7 @@ static const char *parse_cmd_verify(struct ref_transaction *transaction,
                                   update_flags, &err))
                die("%s", err.buf);
 
-       update_flags = 0;
+       update_flags = default_flags;
        free(refname);
        strbuf_release(&err);
 
@@ -357,7 +358,6 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
        const char *refname, *oldval;
        struct object_id oid, oldoid;
        int delete = 0, no_deref = 0, read_stdin = 0, end_null = 0;
-       unsigned int flags = 0;
        int create_reflog = 0;
        struct option options[] = {
                OPT_STRING( 'm', NULL, &msg, N_("reason"), N_("reason of the update")),
@@ -378,6 +378,11 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
 
        create_reflog_flag = create_reflog ? REF_FORCE_CREATE_REFLOG : 0;
 
+       if (no_deref) {
+               default_flags = REF_NO_DEREF;
+               update_flags = default_flags;
+       }
+
        if (read_stdin) {
                struct strbuf err = STRBUF_INIT;
                struct ref_transaction *transaction;
@@ -385,7 +390,7 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
                transaction = ref_transaction_begin(&err);
                if (!transaction)
                        die("%s", err.buf);
-               if (delete || no_deref || argc > 0)
+               if (delete || argc > 0)
                        usage_with_options(git_update_ref_usage, options);
                if (end_null)
                        line_termination = '\0';
@@ -427,8 +432,6 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
                        die("%s: not a valid old SHA1", oldval);
        }
 
-       if (no_deref)
-               flags = REF_NO_DEREF;
        if (delete)
                /*
                 * For purposes of backwards compatibility, we treat
@@ -436,9 +439,9 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
                 */
                return delete_ref(msg, refname,
                                  (oldval && !is_null_oid(&oldoid)) ? &oldoid : NULL,
-                                 flags);
+                                 default_flags);
        else
                return update_ref(msg, refname, &oid, oldval ? &oldoid : NULL,
-                                 flags | create_reflog_flag,
+                                 default_flags | create_reflog_flag,
                                  UPDATE_REFS_DIE_ON_ERR);
 }
diff --git a/cache.h b/cache.h
index 4d01454..3f419b6 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -781,6 +781,8 @@ extern void *read_blob_data_from_index(const struct index_state *, const char *,
 #define CE_MATCH_REFRESH               0x10
 /* don't refresh_fsmonitor state or do stat comparison even if CE_FSMONITOR_VALID is true */
 #define CE_MATCH_IGNORE_FSMONITOR 0X20
+extern int is_racy_timestamp(const struct index_state *istate,
+                            const struct cache_entry *ce);
 extern int ie_match_stat(struct index_state *, const struct cache_entry *, struct stat *, unsigned int);
 extern int ie_modified(struct index_state *, const struct cache_entry *, struct stat *, unsigned int);
 
index a9dda3b..93f3076 100644 (file)
@@ -62,7 +62,7 @@ git-check-mailmap                       purehelpers
 git-checkout                            mainporcelain           history
 git-checkout-index                      plumbingmanipulators
 git-check-ref-format                    purehelpers
-git-cherry                              ancillaryinterrogators          complete
+git-cherry                              plumbinginterrogators          complete
 git-cherry-pick                         mainporcelain
 git-citool                              mainporcelain
 git-clean                               mainporcelain
@@ -96,7 +96,7 @@ git-for-each-ref                        plumbinginterrogators
 git-format-patch                        mainporcelain
 git-fsck                                ancillaryinterrogators          complete
 git-gc                                  mainporcelain
-git-get-tar-commit-id                   ancillaryinterrogators
+git-get-tar-commit-id                   plumbinginterrogators
 git-grep                                mainporcelain           info
 git-gui                                 mainporcelain
 git-hash-object                         plumbingmanipulators
@@ -152,7 +152,7 @@ git-rerere                              ancillaryinterrogators
 git-reset                               mainporcelain           worktree
 git-revert                              mainporcelain
 git-rev-list                            plumbinginterrogators
-git-rev-parse                           ancillaryinterrogators
+git-rev-parse                           plumbinginterrogators
 git-rm                                  mainporcelain           worktree
 git-send-email                          foreignscminterface             complete
 git-send-pack                           synchingrepositories
index 8a1bec7..7cfa779 100644 (file)
@@ -13,6 +13,8 @@
 #include "commit-graph.h"
 #include "object-store.h"
 #include "alloc.h"
+#include "hashmap.h"
+#include "replace-object.h"
 
 #define GRAPH_SIGNATURE 0x43475048 /* "CGPH" */
 #define GRAPH_CHUNKID_OIDFANOUT 0x4f494446 /* "OIDF" */
@@ -56,6 +58,28 @@ static struct commit_graph *alloc_commit_graph(void)
        return g;
 }
 
+extern int read_replace_refs;
+
+static int commit_graph_compatible(struct repository *r)
+{
+       if (!r->gitdir)
+               return 0;
+
+       if (read_replace_refs) {
+               prepare_replace_object(r);
+               if (hashmap_get_size(&r->objects->replace_map->map))
+                       return 0;
+       }
+
+       prepare_commit_graft(r);
+       if (r->parsed_objects && r->parsed_objects->grafts_nr)
+               return 0;
+       if (is_repository_shallow(r))
+               return 0;
+
+       return 1;
+}
+
 struct commit_graph *load_commit_graph_one(const char *graph_file)
 {
        void *graph_map;
@@ -223,6 +247,9 @@ static int prepare_commit_graph(struct repository *r)
                 */
                return 0;
 
+       if (!commit_graph_compatible(r))
+               return 0;
+
        obj_dir = r->objects->objectdir;
        prepare_commit_graph_one(r, obj_dir);
        prepare_alt_odb(r);
@@ -233,10 +260,10 @@ static int prepare_commit_graph(struct repository *r)
        return !!r->objects->commit_graph;
 }
 
-static void close_commit_graph(void)
+void close_commit_graph(struct repository *r)
 {
-       free_commit_graph(the_repository->objects->commit_graph);
-       the_repository->objects->commit_graph = NULL;
+       free_commit_graph(r->objects->commit_graph);
+       r->objects->commit_graph = NULL;
 }
 
 static int bsearch_graph(struct commit_graph *g, struct object_id *oid, uint32_t *pos)
@@ -693,6 +720,9 @@ void write_commit_graph(const char *obj_dir,
        int num_extra_edges;
        struct commit_list *parent;
 
+       if (!commit_graph_compatible(the_repository))
+               return;
+
        oids.nr = 0;
        oids.alloc = approximate_object_count() / 4;
 
@@ -845,7 +875,7 @@ void write_commit_graph(const char *obj_dir,
        write_graph_chunk_data(f, GRAPH_OID_LEN, commits.list, commits.nr);
        write_graph_chunk_large_edges(f, commits.list, commits.nr);
 
-       close_commit_graph();
+       close_commit_graph(the_repository);
        finalize_hashfile(f, NULL, CSUM_HASH_IN_STREAM | CSUM_FSYNC);
        commit_lock_file(&lk);
 
index eea62f8..b62d1b0 100644 (file)
@@ -60,6 +60,7 @@ void write_commit_graph(const char *obj_dir,
 
 int verify_commit_graph(struct repository *r, struct commit_graph *g);
 
+void close_commit_graph(struct repository *);
 void free_commit_graph(struct commit_graph *);
 
 #endif
index 449c1f4..fb4c99c 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -209,7 +209,7 @@ static int read_graft_file(struct repository *r, const char *graft_file)
        return 0;
 }
 
-static void prepare_commit_graft(struct repository *r)
+void prepare_commit_graft(struct repository *r)
 {
        char *graft_file;
 
@@ -1787,10 +1787,10 @@ const char *find_commit_header(const char *msg, const char *key, size_t *out_len
  * Returns the number of bytes from the tail to ignore, to be fed as
  * the second parameter to append_signoff().
  */
-int ignore_non_trailer(const char *buf, size_t len)
+size_t ignore_non_trailer(const char *buf, size_t len)
 {
-       int boc = 0;
-       int bol = 0;
+       size_t boc = 0;
+       size_t bol = 0;
        int in_old_conflicts_block = 0;
        size_t cutoff = wt_status_locate_end(buf, len);
 
index da0db36..dc51072 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -202,6 +202,7 @@ typedef int (*each_commit_graft_fn)(const struct commit_graft *, void *);
 
 struct commit_graft *read_graft_line(struct strbuf *line);
 int register_commit_graft(struct repository *r, struct commit_graft *, int);
+void prepare_commit_graft(struct repository *r);
 struct commit_graft *lookup_commit_graft(struct repository *r, const struct object_id *oid);
 
 extern struct commit_list *get_merge_bases(struct commit *rev1, struct commit *rev2);
@@ -255,7 +256,9 @@ extern void assign_shallow_commits_to_refs(struct shallow_info *info,
                                           uint32_t **used,
                                           int *ref_status);
 extern int delayed_reachability_test(struct shallow_info *si, int c);
-extern void prune_shallow(int show_only);
+#define PRUNE_SHOW_ONLY 1
+#define PRUNE_QUICK 2
+extern void prune_shallow(unsigned options);
 extern struct trace_key trace_shallow;
 
 int is_descendant_of(struct commit *, struct commit_list *);
@@ -322,7 +325,7 @@ extern const char *find_commit_header(const char *msg, const char *key,
                                      size_t *out_len);
 
 /* Find the end of the log message, the right place for a new trailer. */
-extern int ignore_non_trailer(const char *buf, size_t len);
+extern size_t ignore_non_trailer(const char *buf, size_t len);
 
 typedef int (*each_mergetag_fn)(struct commit *commit, struct commit_extra_header *extra,
                                 void *cb_data);
index 858ca14..18caf21 100644 (file)
@@ -341,6 +341,19 @@ int mingw_mkdir(const char *path, int mode)
        return ret;
 }
 
+/*
+ * Calling CreateFile() using FILE_APPEND_DATA and without FILE_WRITE_DATA
+ * is documented in [1] as opening a writable file handle in append mode.
+ * (It is believed that) this is atomic since it is maintained by the
+ * kernel unlike the O_APPEND flag which is racily maintained by the CRT.
+ *
+ * [1] https://docs.microsoft.com/en-us/windows/desktop/fileio/file-access-rights-constants
+ *
+ * This trick does not appear to work for named pipes.  Instead it creates
+ * a named pipe client handle that cannot be written to.  Callers should
+ * just use the regular _wopen() for them.  (And since client handle gets
+ * bound to a unique server handle, it isn't really an issue.)
+ */
 static int mingw_open_append(wchar_t const *wfilename, int oflags, ...)
 {
        HANDLE handle;
@@ -360,10 +373,12 @@ static int mingw_open_append(wchar_t const *wfilename, int oflags, ...)
                        NULL, create, FILE_ATTRIBUTE_NORMAL, NULL);
        if (handle == INVALID_HANDLE_VALUE)
                return errno = err_win_to_posix(GetLastError()), -1;
+
        /*
         * No O_APPEND here, because the CRT uses it only to reset the
-        * file pointer to EOF on write(); but that is not necessary
-        * for a file created with FILE_APPEND_DATA.
+        * file pointer to EOF before each write(); but that is not
+        * necessary (and may lead to races) for a file created with
+        * FILE_APPEND_DATA.
         */
        fd = _open_osfhandle((intptr_t)handle, O_BINARY);
        if (fd < 0)
@@ -371,6 +386,21 @@ static int mingw_open_append(wchar_t const *wfilename, int oflags, ...)
        return fd;
 }
 
+/*
+ * Does the pathname map to the local named pipe filesystem?
+ * That is, does it have a "//./pipe/" prefix?
+ */
+static int is_local_named_pipe_path(const char *filename)
+{
+       return (is_dir_sep(filename[0]) &&
+               is_dir_sep(filename[1]) &&
+               filename[2] == '.'  &&
+               is_dir_sep(filename[3]) &&
+               !strncasecmp(filename+4, "pipe", 4) &&
+               is_dir_sep(filename[8]) &&
+               filename[9]);
+}
+
 int mingw_open (const char *filename, int oflags, ...)
 {
        typedef int (*open_fn_t)(wchar_t const *wfilename, int oflags, ...);
@@ -387,7 +417,7 @@ int mingw_open (const char *filename, int oflags, ...)
        if (filename && !strcmp(filename, "/dev/null"))
                filename = "nul";
 
-       if (oflags & O_APPEND)
+       if ((oflags & O_APPEND) && !is_local_named_pipe_path(filename))
                open_fn = mingw_open_append;
        else
                open_fn = _wopen;
index 9a99814..92d2681 100644 (file)
@@ -7,6 +7,7 @@ CFLAGS += -pedantic
 CFLAGS += -DUSE_PARENS_AROUND_GETTEXT_N=0
 endif
 CFLAGS += -Wdeclaration-after-statement
+CFLAGS += -Wformat-security
 CFLAGS += -Wno-format-zero-length
 CFLAGS += -Wold-style-definition
 CFLAGS += -Woverflow
diff --git a/contrib/coccinelle/preincr.cocci b/contrib/coccinelle/preincr.cocci
new file mode 100644 (file)
index 0000000..7fe1e8d
--- /dev/null
@@ -0,0 +1,5 @@
+@ preincrement @
+identifier i;
+@@
+- ++i > 1
++ i++
index d63d2df..12f7ce0 100644 (file)
@@ -1340,17 +1340,6 @@ _git_checkout ()
        esac
 }
 
-_git_cherry ()
-{
-       case "$cur" in
-       --*)
-               __gitcomp_builtin cherry
-               return
-       esac
-
-       __git_complete_refs
-}
-
 __git_cherry_pick_inprogress_options="--continue --quit --abort"
 
 _git_cherry_pick ()
index 6057f1f..e084822 100644 (file)
--- a/convert.c
+++ b/convert.c
@@ -1297,6 +1297,7 @@ static void convert_attrs(const struct index_state *istate,
                          struct conv_attrs *ca, const char *path)
 {
        static struct attr_check *check;
+       struct attr_check_item *ccheck = NULL;
 
        if (!check) {
                check = attr_check_initl("crlf", "ident", "filter",
@@ -1306,30 +1307,25 @@ static void convert_attrs(const struct index_state *istate,
                git_config(read_convert_config, NULL);
        }
 
-       if (!git_check_attr(istate, path, check)) {
-               struct attr_check_item *ccheck = check->items;
-               ca->crlf_action = git_path_check_crlf(ccheck + 4);
-               if (ca->crlf_action == CRLF_UNDEFINED)
-                       ca->crlf_action = git_path_check_crlf(ccheck + 0);
-               ca->ident = git_path_check_ident(ccheck + 1);
-               ca->drv = git_path_check_convert(ccheck + 2);
-               if (ca->crlf_action != CRLF_BINARY) {
-                       enum eol eol_attr = git_path_check_eol(ccheck + 3);
-                       if (ca->crlf_action == CRLF_AUTO && eol_attr == EOL_LF)
-                               ca->crlf_action = CRLF_AUTO_INPUT;
-                       else if (ca->crlf_action == CRLF_AUTO && eol_attr == EOL_CRLF)
-                               ca->crlf_action = CRLF_AUTO_CRLF;
-                       else if (eol_attr == EOL_LF)
-                               ca->crlf_action = CRLF_TEXT_INPUT;
-                       else if (eol_attr == EOL_CRLF)
-                               ca->crlf_action = CRLF_TEXT_CRLF;
-               }
-               ca->working_tree_encoding = git_path_check_encoding(ccheck + 5);
-       } else {
-               ca->drv = NULL;
-               ca->crlf_action = CRLF_UNDEFINED;
-               ca->ident = 0;
+       git_check_attr(istate, path, check);
+       ccheck = check->items;
+       ca->crlf_action = git_path_check_crlf(ccheck + 4);
+       if (ca->crlf_action == CRLF_UNDEFINED)
+               ca->crlf_action = git_path_check_crlf(ccheck + 0);
+       ca->ident = git_path_check_ident(ccheck + 1);
+       ca->drv = git_path_check_convert(ccheck + 2);
+       if (ca->crlf_action != CRLF_BINARY) {
+               enum eol eol_attr = git_path_check_eol(ccheck + 3);
+               if (ca->crlf_action == CRLF_AUTO && eol_attr == EOL_LF)
+                       ca->crlf_action = CRLF_AUTO_INPUT;
+               else if (ca->crlf_action == CRLF_AUTO && eol_attr == EOL_CRLF)
+                       ca->crlf_action = CRLF_AUTO_CRLF;
+               else if (eol_attr == EOL_LF)
+                       ca->crlf_action = CRLF_TEXT_INPUT;
+               else if (eol_attr == EOL_CRLF)
+                       ca->crlf_action = CRLF_TEXT_CRLF;
        }
+       ca->working_tree_encoding = git_path_check_encoding(ccheck + 5);
 
        /* Save attr and make a decision for action */
        ca->attr_action = ca->crlf_action;
diff --git a/diff.c b/diff.c
index 145cfba..db5e5e9 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -4256,12 +4256,12 @@ static void diff_fill_oid_info(struct diff_filespec *one)
 static void strip_prefix(int prefix_length, const char **namep, const char **otherp)
 {
        /* Strip the prefix but do not molest /dev/null and absolute paths */
-       if (*namep && **namep != '/') {
+       if (*namep && !is_absolute_path(*namep)) {
                *namep += prefix_length;
                if (**namep == '/')
                        ++*namep;
        }
-       if (*otherp && **otherp != '/') {
+       if (*otherp && !is_absolute_path(*otherp)) {
                *otherp += prefix_length;
                if (**otherp == '/')
                        ++*otherp;
index 853624f..4266548 100644 (file)
@@ -23,21 +23,16 @@ static void fetch_refs(const char *remote_name, struct ref *ref)
        fetch_if_missing = original_fetch_if_missing;
 }
 
-void fetch_object(const char *remote_name, const unsigned char *sha1)
-{
-       struct ref *ref = alloc_ref(sha1_to_hex(sha1));
-       hashcpy(ref->old_oid.hash, sha1);
-       fetch_refs(remote_name, ref);
-}
-
-void fetch_objects(const char *remote_name, const struct oid_array *to_fetch)
+void fetch_objects(const char *remote_name, const struct object_id *oids,
+                  int oid_nr)
 {
        struct ref *ref = NULL;
        int i;
 
-       for (i = 0; i < to_fetch->nr; i++) {
-               struct ref *new_ref = alloc_ref(oid_to_hex(&to_fetch->oid[i]));
-               oidcpy(&new_ref->old_oid, &to_fetch->oid[i]);
+       for (i = 0; i < oid_nr; i++) {
+               struct ref *new_ref = alloc_ref(oid_to_hex(&oids[i]));
+               oidcpy(&new_ref->old_oid, &oids[i]);
+               new_ref->exact_oid = 1;
                new_ref->next = ref;
                ref = new_ref;
        }
index 4b269d0..d2f996d 100644 (file)
@@ -1,11 +1,7 @@
 #ifndef FETCH_OBJECT_H
 #define FETCH_OBJECT_H
 
-#include "sha1-array.h"
-
-extern void fetch_object(const char *remote_name, const unsigned char *sha1);
-
-extern void fetch_objects(const char *remote_name,
-                         const struct oid_array *to_fetch);
+void fetch_objects(const char *remote_name, const struct object_id *oids,
+                  int oid_nr);
 
 #endif
index 88a078e..79007f9 100644 (file)
@@ -253,8 +253,10 @@ static int find_common(struct fetch_negotiator *negotiator,
        if (args->stateless_rpc && multi_ack == 1)
                die(_("--stateless-rpc requires multi_ack_detailed"));
 
-       mark_tips(negotiator, args->negotiation_tips);
-       for_each_cached_alternate(negotiator, insert_one_alternate_object);
+       if (!args->no_dependents) {
+               mark_tips(negotiator, args->negotiation_tips);
+               for_each_cached_alternate(negotiator, insert_one_alternate_object);
+       }
 
        fetching = 0;
        for ( ; refs ; refs = refs->next) {
@@ -271,8 +273,12 @@ static int find_common(struct fetch_negotiator *negotiator,
                 * We use lookup_object here because we are only
                 * interested in the case we *know* the object is
                 * reachable and we have already scanned it.
+                *
+                * Do this only if args->no_dependents is false (if it is true,
+                * we cannot trust the object flags).
                 */
-               if (((o = lookup_object(the_repository, remote->hash)) != NULL) &&
+               if (!args->no_dependents &&
+                   ((o = lookup_object(the_repository, remote->hash)) != NULL) &&
                                (o->flags & COMPLETE)) {
                        continue;
                }
@@ -710,31 +716,29 @@ static void mark_complete_and_common_ref(struct fetch_negotiator *negotiator,
 
        oidset_clear(&loose_oid_set);
 
-       if (!args->no_dependents) {
-               if (!args->deepen) {
-                       for_each_ref(mark_complete_oid, NULL);
-                       for_each_cached_alternate(NULL, mark_alternate_complete);
-                       commit_list_sort_by_date(&complete);
-                       if (cutoff)
-                               mark_recent_complete_commits(args, cutoff);
-               }
+       if (!args->deepen) {
+               for_each_ref(mark_complete_oid, NULL);
+               for_each_cached_alternate(NULL, mark_alternate_complete);
+               commit_list_sort_by_date(&complete);
+               if (cutoff)
+                       mark_recent_complete_commits(args, cutoff);
+       }
 
-               /*
-                * Mark all complete remote refs as common refs.
-                * Don't mark them common yet; the server has to be told so first.
-                */
-               for (ref = *refs; ref; ref = ref->next) {
-                       struct object *o = deref_tag(the_repository,
-                                                    lookup_object(the_repository,
-                                                    ref->old_oid.hash),
-                                                    NULL, 0);
+       /*
+        * Mark all complete remote refs as common refs.
+        * Don't mark them common yet; the server has to be told so first.
+        */
+       for (ref = *refs; ref; ref = ref->next) {
+               struct object *o = deref_tag(the_repository,
+                                            lookup_object(the_repository,
+                                            ref->old_oid.hash),
+                                            NULL, 0);
 
-                       if (!o || o->type != OBJ_COMMIT || !(o->flags & COMPLETE))
-                               continue;
+               if (!o || o->type != OBJ_COMMIT || !(o->flags & COMPLETE))
+                       continue;
 
-                       negotiator->known_common(negotiator,
-                                                (struct commit *)o);
-               }
+               negotiator->known_common(negotiator,
+                                        (struct commit *)o);
        }
 
        save_commit_buffer = old_save_commit_buffer;
@@ -990,11 +994,15 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
        if (!server_supports("deepen-relative") && args->deepen_relative)
                die(_("Server does not support --deepen"));
 
-       mark_complete_and_common_ref(&negotiator, args, &ref);
-       filter_refs(args, &ref, sought, nr_sought);
-       if (everything_local(args, &ref)) {
-               packet_flush(fd[1]);
-               goto all_done;
+       if (!args->no_dependents) {
+               mark_complete_and_common_ref(&negotiator, args, &ref);
+               filter_refs(args, &ref, sought, nr_sought);
+               if (everything_local(args, &ref)) {
+                       packet_flush(fd[1]);
+                       goto all_done;
+               }
+       } else {
+               filter_refs(args, &ref, sought, nr_sought);
        }
        if (find_common(&negotiator, args, fd, &oid, ref) < 0)
                if (!args->keep_pack)
@@ -1040,7 +1048,7 @@ static void add_shallow_requests(struct strbuf *req_buf,
        }
 }
 
-static void add_wants(const struct ref *wants, struct strbuf *req_buf)
+static void add_wants(int no_dependents, const struct ref *wants, struct strbuf *req_buf)
 {
        int use_ref_in_want = server_supports_feature("fetch", "ref-in-want", 0);
 
@@ -1057,8 +1065,12 @@ static void add_wants(const struct ref *wants, struct strbuf *req_buf)
                 * We use lookup_object here because we are only
                 * interested in the case we *know* the object is
                 * reachable and we have already scanned it.
+                *
+                * Do this only if args->no_dependents is false (if it is true,
+                * we cannot trust the object flags).
                 */
-               if (((o = lookup_object(the_repository, remote->hash)) != NULL) &&
+               if (!no_dependents &&
+                   ((o = lookup_object(the_repository, remote->hash)) != NULL) &&
                    (o->flags & COMPLETE)) {
                        continue;
                }
@@ -1155,7 +1167,7 @@ static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out,
        }
 
        /* add wants */
-       add_wants(wants, &req_buf);
+       add_wants(args->no_dependents, wants, &req_buf);
 
        if (args->no_dependents) {
                packet_buf_write(&req_buf, "done");
@@ -1346,16 +1358,21 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
                                args->deepen = 1;
 
                        /* Filter 'ref' by 'sought' and those that aren't local */
-                       mark_complete_and_common_ref(&negotiator, args, &ref);
-                       filter_refs(args, &ref, sought, nr_sought);
-                       if (everything_local(args, &ref))
-                               state = FETCH_DONE;
-                       else
+                       if (!args->no_dependents) {
+                               mark_complete_and_common_ref(&negotiator, args, &ref);
+                               filter_refs(args, &ref, sought, nr_sought);
+                               if (everything_local(args, &ref))
+                                       state = FETCH_DONE;
+                               else
+                                       state = FETCH_SEND_REQUEST;
+
+                               mark_tips(&negotiator, args->negotiation_tips);
+                               for_each_cached_alternate(&negotiator,
+                                                         insert_one_alternate_object);
+                       } else {
+                               filter_refs(args, &ref, sought, nr_sought);
                                state = FETCH_SEND_REQUEST;
-
-                       mark_tips(&negotiator, args->negotiation_tips);
-                       for_each_cached_alternate(&negotiator,
-                                                 insert_one_alternate_object);
+                       }
                        break;
                case FETCH_SEND_REQUEST:
                        if (send_fetch_request(&negotiator, fd[1], args, ref,
@@ -1598,6 +1615,20 @@ struct ref *fetch_pack(struct fetch_pack_args *args,
        if (nr_sought)
                nr_sought = remove_duplicates_in_refs(sought, nr_sought);
 
+       if (args->no_dependents && !args->filter_options.choice) {
+               /*
+                * The protocol does not support requesting that only the
+                * wanted objects be sent, so approximate this by setting a
+                * "blob:none" filter if no filter is already set. This works
+                * for all object types: note that wanted blobs will still be
+                * sent because they are directly specified as a "want".
+                *
+                * NEEDSWORK: Add an option in the protocol to request that
+                * only the wanted objects be sent, and implement it.
+                */
+               parse_list_objects_filter(&args->filter_options, "blob:none");
+       }
+
        if (!ref) {
                packet_flush(fd[1]);
                die(_("no matching remote head"));
index 5b6e868..43ec344 100644 (file)
@@ -43,6 +43,13 @@ struct fetch_pack_args {
        unsigned from_promisor:1;
 
        /*
+        * Attempt to fetch only the wanted objects, and not any objects
+        * referred to by them. Due to protocol limitations, extraneous
+        * objects may still be included. (When fetching non-blob
+        * objects, only blobs are excluded; when fetching a blob, the
+        * blob itself will still be sent. The client does not need to
+        * know whether a wanted object is a blob or not.)
+        *
         * If 1, fetch_pack() will also not modify any object flags.
         * This allows fetch_pack() to safely be called by any function,
         * regardless of which object flags it uses (if any).
diff --git a/fsck.c b/fsck.c
index 0f56977..d44c46c 100644 (file)
--- a/fsck.c
+++ b/fsck.c
@@ -485,7 +485,7 @@ static int fsck_walk_commit(struct commit *commit, void *data, struct fsck_optio
                if (name) {
                        struct object *obj = &parents->item->object;
 
-                       if (++counter > 1)
+                       if (counter++)
                                put_object_name(options, obj, "%s^%d",
                                        name, counter);
                        else if (generation > 0)
diff --git a/graph.c b/graph.c
index e1f6d3b..f531354 100644 (file)
--- a/graph.c
+++ b/graph.c
@@ -842,27 +842,55 @@ static void graph_output_commit_char(struct git_graph *graph, struct strbuf *sb)
 }
 
 /*
- * Draw an octopus merge and return the number of characters written.
+ * Draw the horizontal dashes of an octopus merge and return the number of
+ * characters written.
  */
 static int graph_draw_octopus_merge(struct git_graph *graph,
                                    struct strbuf *sb)
 {
        /*
-        * Here dashless_commits represents the number of parents
-        * which don't need to have dashes (because their edges fit
-        * neatly under the commit).
-        */
-       const int dashless_commits = 2;
-       int col_num, i;
-       int num_dashes =
-               ((graph->num_parents - dashless_commits) * 2) - 1;
-       for (i = 0; i < num_dashes; i++) {
-               col_num = (i / 2) + dashless_commits + graph->commit_index;
-               strbuf_write_column(sb, &graph->new_columns[col_num], '-');
+        * Here dashless_parents represents the number of parents which don't
+        * need to have dashes (the edges labeled "0" and "1").  And
+        * dashful_parents are the remaining ones.
+        *
+        * | *---.
+        * | |\ \ \
+        * | | | | |
+        * x 0 1 2 3
+        *
+        */
+       const int dashless_parents = 2;
+       int dashful_parents = graph->num_parents - dashless_parents;
+
+       /*
+        * Usually, we add one new column for each parent (like the diagram
+        * above) but sometimes the first parent goes into an existing column,
+        * like this:
+        *
+        * | *---.
+        * | |\ \ \
+        * |/ / / /
+        * x 0 1 2
+        *
+        * In which case the number of parents will be one greater than the
+        * number of added columns.
+        */
+       int added_cols = (graph->num_new_columns - graph->num_columns);
+       int parent_in_old_cols = graph->num_parents - added_cols;
+
+       /*
+        * In both cases, commit_index corresponds to the edge labeled "0".
+        */
+       int first_col = graph->commit_index + dashless_parents
+           - parent_in_old_cols;
+
+       int i;
+       for (i = 0; i < dashful_parents; i++) {
+               strbuf_write_column(sb, &graph->new_columns[i+first_col], '-');
+               strbuf_write_column(sb, &graph->new_columns[i+first_col],
+                                   i == dashful_parents-1 ? '.' : '-');
        }
-       col_num = (i / 2) + dashless_commits + graph->commit_index;
-       strbuf_write_column(sb, &graph->new_columns[col_num], '.');
-       return num_dashes + 1;
+       return 2 * dashful_parents;
 }
 
 static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb)
index 9b3e56e..ecffc09 100644 (file)
@@ -19,6 +19,12 @@ void compute_assignment(int column_count, int row_count, int *cost,
        int *free_row, free_count = 0, saved_free_count, *pred, *col;
        int i, j, phase;
 
+       if (column_count < 2) {
+               memset(column2row, 0, sizeof(int) * column_count);
+               memset(row2column, 0, sizeof(int) * row_count);
+               return;
+       }
+
        memset(column2row, -1, sizeof(int) * column_count);
        memset(row2column, -1, sizeof(int) * row_count);
        ALLOC_ARRAY(v, column_count);
index 0e2800f..1936fee 100644 (file)
@@ -371,13 +371,12 @@ int ll_merge(mmbuffer_t *result_buf,
        if (!check)
                check = attr_check_initl("merge", "conflict-marker-size", NULL);
 
-       if (!git_check_attr(&the_index, path, check)) {
-               ll_driver_name = check->items[0].value;
-               if (check->items[1].value) {
-                       marker_size = atoi(check->items[1].value);
-                       if (marker_size <= 0)
-                               marker_size = DEFAULT_CONFLICT_MARKER_SIZE;
-               }
+       git_check_attr(&the_index, path, check);
+       ll_driver_name = check->items[0].value;
+       if (check->items[1].value) {
+               marker_size = atoi(check->items[1].value);
+               if (marker_size <= 0)
+                       marker_size = DEFAULT_CONFLICT_MARKER_SIZE;
        }
        driver = find_ll_merge_driver(ll_driver_name);
 
@@ -398,7 +397,8 @@ int ll_merge_marker_size(const char *path)
 
        if (!check)
                check = attr_check_initl("conflict-marker-size", NULL);
-       if (!git_check_attr(&the_index, path, check) && check->items[0].value) {
+       git_check_attr(&the_index, path, check);
+       if (check->items[0].value) {
                marker_size = atoi(check->items[0].value);
                if (marker_size <= 0)
                        marker_size = DEFAULT_CONFLICT_MARKER_SIZE;
index f401c97..35403cc 100644 (file)
@@ -263,8 +263,8 @@ static inline int close_lock_file_gently(struct lock_file *lk)
  *   nobody else) to inspect the contents you wrote, while still
  *   holding the lock yourself.
  *
- * * `reopen_lock_file()` to reopen the lockfile. Make further updates
- *   to the contents.
+ * * `reopen_lock_file()` to reopen the lockfile, truncating the existing
+ *   contents. Write out the new contents.
  *
  * * `commit_lock_file()` to make the final version permanent.
  */
index e5243db..1b5c255 100644 (file)
@@ -2239,7 +2239,7 @@ static struct dir_rename_entry *check_dir_renamed(const char *path,
 {
        char *temp = xstrdup(path);
        char *end;
-       struct dir_rename_entry *entry = NULL;;
+       struct dir_rename_entry *entry = NULL;
 
        while ((end = strrchr(temp, '/'))) {
                *end = '\0';
index 6ef87e5..f73f609 100644 (file)
@@ -148,6 +148,9 @@ void prepare_packing_data(struct packing_data *pdata)
                                             1U << OE_SIZE_BITS);
        pdata->oe_delta_size_limit = git_env_ulong("GIT_TEST_OE_DELTA_SIZE",
                                                   1UL << OE_DELTA_SIZE_BITS);
+#ifndef NO_PTHREADS
+       pthread_mutex_init(&pdata->lock, NULL);
+#endif
 }
 
 struct object_entry *packlist_alloc(struct packing_data *pdata,
index 62806cc..c340361 100644 (file)
@@ -356,7 +356,7 @@ static inline unsigned long oe_delta_size(struct packing_data *pack,
                return e->delta_size_;
 
        /*
-        * pack->detla_size[] can't be NULL because oe_set_delta_size()
+        * pack->delta_size[] can't be NULL because oe_set_delta_size()
         * must have been called when a new delta is saved with
         * oe_set_delta().
         * If oe_delta() returns NULL (i.e. default state, which means
diff --git a/path.c b/path.c
index 34f0f98..ba06ec5 100644 (file)
--- a/path.c
+++ b/path.c
@@ -1369,7 +1369,7 @@ only_spaces_and_periods:
                        saw_tilde = 1;
                } else if (i >= 6)
                        return 0;
-               else if (name[i] 0) {
+               else if (name[i] & 0x80) {
                        /*
                         * We know our needles contain only ASCII, so we clamp
                         * here to make the results of tolower() sane.
index 98cf522..8ca29e9 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -1304,6 +1304,9 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 
        if (skip_prefix(placeholder, "(trailers", &arg)) {
                struct process_trailer_options opts = PROCESS_TRAILER_OPTIONS_INIT;
+
+               opts.no_divider = 1;
+
                if (*arg == ':') {
                        arg++;
                        for (;;) {
index 7b1354d..8f644f6 100644 (file)
@@ -337,7 +337,7 @@ static int is_racy_stat(const struct index_state *istate,
                );
 }
 
-static int is_racy_timestamp(const struct index_state *istate,
+int is_racy_timestamp(const struct index_state *istate,
                             const struct cache_entry *ce)
 {
        return (!S_ISGITLINK(ce->ce_mode) &&
index 0bccfce..3e8ee04 100644 (file)
@@ -263,6 +263,8 @@ static int trailers_atom_parser(const struct ref_format *format, struct used_ato
        struct string_list params = STRING_LIST_INIT_DUP;
        int i;
 
+       atom->u.contents.trailer_opts.no_divider = 1;
+
        if (arg) {
                string_list_split(&params, arg, ',', -1);
                for (i = 0; i < params.nr; i++) {
diff --git a/refs.c b/refs.c
index de81c7b..9a318c8 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -1394,17 +1394,50 @@ struct ref_iterator *refs_ref_iterator_begin(
  * non-zero value, stop the iteration and return that value;
  * otherwise, return 0.
  */
+static int do_for_each_repo_ref(struct repository *r, const char *prefix,
+                               each_repo_ref_fn fn, int trim, int flags,
+                               void *cb_data)
+{
+       struct ref_iterator *iter;
+       struct ref_store *refs = get_main_ref_store(r);
+
+       if (!refs)
+               return 0;
+
+       iter = refs_ref_iterator_begin(refs, prefix, trim, flags);
+
+       return do_for_each_repo_ref_iterator(r, iter, fn, cb_data);
+}
+
+struct do_for_each_ref_help {
+       each_ref_fn *fn;
+       void *cb_data;
+};
+
+static int do_for_each_ref_helper(struct repository *r,
+                                 const char *refname,
+                                 const struct object_id *oid,
+                                 int flags,
+                                 void *cb_data)
+{
+       struct do_for_each_ref_help *hp = cb_data;
+
+       return hp->fn(refname, oid, flags, hp->cb_data);
+}
+
 static int do_for_each_ref(struct ref_store *refs, const char *prefix,
                           each_ref_fn fn, int trim, int flags, void *cb_data)
 {
        struct ref_iterator *iter;
+       struct do_for_each_ref_help hp = { fn, cb_data };
 
        if (!refs)
                return 0;
 
        iter = refs_ref_iterator_begin(refs, prefix, trim, flags);
 
-       return do_for_each_ref_iterator(iter, fn, cb_data);
+       return do_for_each_repo_ref_iterator(the_repository, iter,
+                                       do_for_each_ref_helper, &hp);
 }
 
 int refs_for_each_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
@@ -1449,12 +1482,11 @@ int refs_for_each_fullref_in(struct ref_store *refs, const char *prefix,
        return do_for_each_ref(refs, prefix, fn, 0, flag, cb_data);
 }
 
-int for_each_replace_ref(struct repository *r, each_ref_fn fn, void *cb_data)
+int for_each_replace_ref(struct repository *r, each_repo_ref_fn fn, void *cb_data)
 {
-       return do_for_each_ref(get_main_ref_store(r),
-                              git_replace_ref_base, fn,
-                              strlen(git_replace_ref_base),
-                              DO_FOR_EACH_INCLUDE_BROKEN, cb_data);
+       return do_for_each_repo_ref(r, git_replace_ref_base, fn,
+                                   strlen(git_replace_ref_base),
+                                   DO_FOR_EACH_INCLUDE_BROKEN, cb_data);
 }
 
 int for_each_namespaced_ref(each_ref_fn fn, void *cb_data)
@@ -2033,10 +2065,12 @@ cleanup:
 int refs_for_each_reflog(struct ref_store *refs, each_ref_fn fn, void *cb_data)
 {
        struct ref_iterator *iter;
+       struct do_for_each_ref_help hp = { fn, cb_data };
 
        iter = refs->be->reflog_iterator_begin(refs);
 
-       return do_for_each_ref_iterator(iter, fn, cb_data);
+       return do_for_each_repo_ref_iterator(the_repository, iter,
+                                            do_for_each_ref_helper, &hp);
 }
 
 int for_each_reflog(each_ref_fn fn, void *cb_data)
diff --git a/refs.h b/refs.h
index bd52c1b..6cc0397 100644 (file)
--- a/refs.h
+++ b/refs.h
@@ -277,6 +277,16 @@ typedef int each_ref_fn(const char *refname,
                        const struct object_id *oid, int flags, void *cb_data);
 
 /*
+ * The same as each_ref_fn, but also with a repository argument that
+ * contains the repository associated with the callback.
+ */
+typedef int each_repo_ref_fn(struct repository *r,
+                            const char *refname,
+                            const struct object_id *oid,
+                            int flags,
+                            void *cb_data);
+
+/*
  * The following functions invoke the specified callback function for
  * each reference indicated.  If the function ever returns a nonzero
  * value, stop the iteration and return that value.  Please note that
@@ -309,7 +319,7 @@ int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data,
 int for_each_tag_ref(each_ref_fn fn, void *cb_data);
 int for_each_branch_ref(each_ref_fn fn, void *cb_data);
 int for_each_remote_ref(each_ref_fn fn, void *cb_data);
-int for_each_replace_ref(struct repository *r, each_ref_fn fn, void *cb_data);
+int for_each_replace_ref(struct repository *r, each_repo_ref_fn fn, void *cb_data);
 int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data);
 int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,
                         const char *prefix, void *cb_data);
index 2ac91ac..629e00a 100644 (file)
@@ -407,15 +407,15 @@ struct ref_iterator *prefix_ref_iterator_begin(struct ref_iterator *iter0,
 
 struct ref_iterator *current_ref_iter = NULL;
 
-int do_for_each_ref_iterator(struct ref_iterator *iter,
-                            each_ref_fn fn, void *cb_data)
+int do_for_each_repo_ref_iterator(struct repository *r, struct ref_iterator *iter,
+                                 each_repo_ref_fn fn, void *cb_data)
 {
        int retval = 0, ok;
        struct ref_iterator *old_ref_iter = current_ref_iter;
 
        current_ref_iter = iter;
        while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
-               retval = fn(iter->refname, iter->oid, iter->flags, cb_data);
+               retval = fn(r, iter->refname, iter->oid, iter->flags, cb_data);
                if (retval) {
                        /*
                         * If ref_iterator_abort() returns ITER_ERROR,
index 04425d6..b425ae4 100644 (file)
@@ -282,7 +282,7 @@ int refs_rename_ref_available(struct ref_store *refs,
  *
  *             // Access information about the current reference:
  *             if (!(iter->flags & REF_ISSYMREF))
- *                     printf("%s is %s\n", iter->refname, oid_to_hex(&iter->oid));
+ *                     printf("%s is %s\n", iter->refname, oid_to_hex(iter->oid));
  *
  *             // If you need to peel the reference:
  *             ref_iterator_peel(iter, &oid);
@@ -474,8 +474,9 @@ extern struct ref_iterator *current_ref_iter;
  * adapter between the callback style of reference iteration and the
  * iterator style.
  */
-int do_for_each_ref_iterator(struct ref_iterator *iter,
-                            each_ref_fn fn, void *cb_data);
+int do_for_each_repo_ref_iterator(struct repository *r,
+                                 struct ref_iterator *iter,
+                                 each_repo_ref_fn fn, void *cb_data);
 
 /*
  * Only include per-worktree refs in a do_for_each_ref*() iteration.
index fb28309..762a55a 100644 (file)
@@ -178,7 +178,7 @@ static int set_option(const char *name, const char *value)
                options.no_dependents = 1;
                return 0;
        } else if (!strcmp(name, "filter")) {
-               options.filter = xstrdup(value);;
+               options.filter = xstrdup(value);
                return 0;
        } else {
                return 1 /* unsupported */;
index 4ec77ce..e295e87 100644 (file)
@@ -6,7 +6,8 @@
 #include "repository.h"
 #include "commit.h"
 
-static int register_replace_ref(const char *refname,
+static int register_replace_ref(struct repository *r,
+                               const char *refname,
                                const struct object_id *oid,
                                int flag, void *cb_data)
 {
@@ -25,13 +26,13 @@ static int register_replace_ref(const char *refname,
        oidcpy(&repl_obj->replacement, oid);
 
        /* Register new object */
-       if (oidmap_put(the_repository->objects->replace_map, repl_obj))
+       if (oidmap_put(r->objects->replace_map, repl_obj))
                die(_("duplicate replace ref: %s"), refname);
 
        return 0;
 }
 
-static void prepare_replace_object(struct repository *r)
+void prepare_replace_object(struct repository *r)
 {
        if (r->objects->replace_map)
                return;
index 9345e10..16528df 100644 (file)
@@ -10,6 +10,8 @@ struct replace_object {
        struct object_id replacement;
 };
 
+void prepare_replace_object(struct repository *r);
+
 /*
  * This internal function is only declared here for the benefit of
  * lookup_replace_object().  Please do not call it directly.
index c7787aa..783d4da 100644 (file)
--- a/rerere.c
+++ b/rerere.c
@@ -533,7 +533,7 @@ static int check_one_conflict(int i, int *type)
        }
 
        *type = PUNTED;
-       while (ce_stage(active_cache[i]) == 1)
+       while (i < active_nr && ce_stage(active_cache[i]) == 1)
                i++;
 
        /* Only handle regular files with both stages #2 and #3 */
index de4dce6..e411802 100644 (file)
@@ -2133,7 +2133,8 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
                revs->limited = 1;
        } else if (!strcmp(arg, "--ignore-missing")) {
                revs->ignore_missing = 1;
-       } else if (!strcmp(arg, "--exclude-promisor-objects")) {
+       } else if (revs->allow_exclude_promisor_objects_opt &&
+                  !strcmp(arg, "--exclude-promisor-objects")) {
                if (fetch_if_missing)
                        BUG("exclude_promisor_objects can only be used when fetch_if_missing is 0");
                revs->exclude_promisor_objects = 1;
index 007278c..701a497 100644 (file)
@@ -127,6 +127,7 @@ struct rev_info {
                        tree_blobs_in_commit_order:1,
 
                        /* for internal use only */
+                       allow_exclude_promisor_objects_opt:1,
                        exclude_promisor_objects:1;
 
        /* Diff flags */
index 84b883c..d679cc2 100644 (file)
@@ -380,7 +380,7 @@ static void child_err_spew(struct child_process *cmd, struct child_err *cerr)
        set_error_routine(old_errfn);
 }
 
-static void prepare_cmd(struct argv_array *out, const struct child_process *cmd)
+static int prepare_cmd(struct argv_array *out, const struct child_process *cmd)
 {
        if (!cmd->argv[0])
                BUG("command is empty");
@@ -403,16 +403,22 @@ static void prepare_cmd(struct argv_array *out, const struct child_process *cmd)
        /*
         * If there are no '/' characters in the command then perform a path
         * lookup and use the resolved path as the command to exec.  If there
-        * are no '/' characters or if the command wasn't found in the path,
-        * have exec attempt to invoke the command directly.
+        * are '/' characters, we have exec attempt to invoke the command
+        * directly.
         */
        if (!strchr(out->argv[1], '/')) {
                char *program = locate_in_PATH(out->argv[1]);
                if (program) {
                        free((char *)out->argv[1]);
                        out->argv[1] = program;
+               } else {
+                       argv_array_clear(out);
+                       errno = ENOENT;
+                       return -1;
                }
        }
+
+       return 0;
 }
 
 static char **prep_childenv(const char *const *deltaenv)
@@ -719,6 +725,12 @@ fail_pipe:
        struct child_err cerr;
        struct atfork_state as;
 
+       if (prepare_cmd(&argv, cmd) < 0) {
+               failed_errno = errno;
+               cmd->pid = -1;
+               goto end_of_spawn;
+       }
+
        if (pipe(notify_pipe))
                notify_pipe[0] = notify_pipe[1] = -1;
 
@@ -729,7 +741,6 @@ fail_pipe:
                set_cloexec(null_fd);
        }
 
-       prepare_cmd(&argv, cmd);
        childenv = prep_childenv(cmd->env);
        atfork_prepare(&as);
 
@@ -857,6 +868,8 @@ fail_pipe:
        argv_array_clear(&argv);
        free(childenv);
 }
+end_of_spawn:
+
 #else
 {
        int fhin = 0, fhout = 1, fherr = 2;
index dc2c58d..24451bb 100644 (file)
@@ -225,13 +225,16 @@ static const char *get_todo_path(const struct replay_opts *opts)
  * Returns 3 when sob exists within conforming footer as last entry
  */
 static int has_conforming_footer(struct strbuf *sb, struct strbuf *sob,
-       int ignore_footer)
+       size_t ignore_footer)
 {
+       struct process_trailer_options opts = PROCESS_TRAILER_OPTIONS_INIT;
        struct trailer_info info;
-       int i;
+       size_t i;
        int found_sob = 0, found_sob_last = 0;
 
-       trailer_info_get(&info, sb->buf);
+       opts.no_divider = 1;
+
+       trailer_info_get(&info, sb->buf, &opts);
 
        if (info.trailer_start == info.trailer_end)
                return 0;
@@ -899,7 +902,7 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,
        if ((flags & ALLOW_EMPTY))
                argv_array_push(&cmd.args, "--allow-empty");
 
-       if (opts->allow_empty_message)
+       if (!(flags & EDIT_MSG))
                argv_array_push(&cmd.args, "--allow-empty-message");
 
        if (cmd.err == -1) {
@@ -1313,7 +1316,7 @@ static int try_to_commit(struct strbuf *msg, const char *author,
 
        if (cleanup != COMMIT_MSG_CLEANUP_NONE)
                strbuf_stripspace(msg, cleanup == COMMIT_MSG_CLEANUP_ALL);
-       if (!opts->allow_empty_message && message_is_empty(msg, cleanup)) {
+       if ((flags & EDIT_MSG) && message_is_empty(msg, cleanup)) {
                res = 1; /* run 'git commit' to display error message */
                goto out;
        }
@@ -3607,9 +3610,20 @@ static int commit_staged_changes(struct replay_opts *opts,
                 * the commit message and if there was a squash, let the user
                 * edit it.
                 */
-               if (is_clean && !oidcmp(&head, &to_amend) &&
-                   opts->current_fixup_count > 0 &&
-                   file_exists(rebase_path_stopped_sha())) {
+               if (!is_clean || !opts->current_fixup_count)
+                       ; /* this is not the final fixup */
+               else if (oidcmp(&head, &to_amend) ||
+                        !file_exists(rebase_path_stopped_sha())) {
+                       /* was a final fixup or squash done manually? */
+                       if (!is_fixup(peek_command(todo_list, 0))) {
+                               unlink(rebase_path_fixup_msg());
+                               unlink(rebase_path_squash_msg());
+                               unlink(rebase_path_current_fixups());
+                               strbuf_reset(&opts->current_fixups);
+                               opts->current_fixup_count = 0;
+                       }
+               } else {
+                       /* we are in a fixup/squash chain */
                        const char *p = opts->current_fixups.buf;
                        int len = opts->current_fixups.len;
 
@@ -3828,7 +3842,7 @@ int sequencer_pick_revisions(struct replay_opts *opts)
        return res;
 }
 
-void append_signoff(struct strbuf *msgbuf, int ignore_footer, unsigned flag)
+void append_signoff(struct strbuf *msgbuf, size_t ignore_footer, unsigned flag)
 {
        unsigned no_dup_sob = flag & APPEND_SIGNOFF_DEDUP;
        struct strbuf sob = STRBUF_INIT;
@@ -4131,9 +4145,7 @@ static int make_script_with_merges(struct pretty_print_context *pp,
                        struct object_id *oid = &parent->item->object.oid;
                        if (!oidset_contains(&interesting, oid))
                                continue;
-                       if (!oidset_contains(&child_seen, oid))
-                               oidset_insert(&child_seen, oid);
-                       else
+                       if (oidset_insert(&child_seen, oid))
                                label_oid(oid, "branch-point", &state);
                }
 
index c751c9d..c986bc8 100644 (file)
@@ -90,7 +90,14 @@ int rearrange_squash(void);
 
 extern const char sign_off_header[];
 
-void append_signoff(struct strbuf *msgbuf, int ignore_footer, unsigned flag);
+/*
+ * Append a signoff to the commit message in "msgbuf". The ignore_footer
+ * parameter specifies the number of bytes at the end of msgbuf that should
+ * not be considered at all. I.e., they are not checked for existing trailers,
+ * and the new signoff will be spliced into the buffer before those bytes.
+ */
+void append_signoff(struct strbuf *msgbuf, size_t ignore_footer, unsigned flag);
+
 void append_conflicts_hint(struct strbuf *msgbuf);
 int message_is_empty(const struct strbuf *sb,
                     enum commit_msg_cleanup_mode cleanup_mode);
index 97b7423..03b86ae 100644 (file)
@@ -1317,7 +1317,7 @@ int oid_object_info_extended(struct repository *r, const struct object_id *oid,
                         * TODO Pass a repository struct through fetch_object,
                         * such that arbitrary repositories work.
                         */
-                       fetch_object(repository_format_partial_clone, real->hash);
+                       fetch_objects(repository_format_partial_clone, real, 1);
                        already_retried = 1;
                        continue;
                }
@@ -2191,7 +2191,8 @@ static int check_stream_sha1(git_zstream *stream,
         * see the comment in unpack_sha1_rest for details.
         */
        while (total_read <= size &&
-              (status == Z_OK || status == Z_BUF_ERROR)) {
+              (status == Z_OK ||
+               (status == Z_BUF_ERROR && !stream->avail_out))) {
                stream->next_out = buf;
                stream->avail_out = sizeof(buf);
                if (size - total_read < stream->avail_out)
index dbe8a2a..c1b6853 100644 (file)
--- a/shallow.c
+++ b/shallow.c
@@ -246,6 +246,7 @@ static void check_shallow_file_for_update(struct repository *r)
 
 #define SEEN_ONLY 1
 #define VERBOSE   2
+#define QUICK 4
 
 struct write_shallow_data {
        struct strbuf *out;
@@ -260,7 +261,10 @@ static int write_one_shallow(const struct commit_graft *graft, void *cb_data)
        const char *hex = oid_to_hex(&graft->oid);
        if (graft->nr_parent != -1)
                return 0;
-       if (data->flags & SEEN_ONLY) {
+       if (data->flags & QUICK) {
+               if (!has_object_file(&graft->oid))
+                       return 0;
+       } else if (data->flags & SEEN_ONLY) {
                struct commit *c = lookup_commit(the_repository, &graft->oid);
                if (!c || !(c->object.flags & SEEN)) {
                        if (data->flags & VERBOSE)
@@ -370,16 +374,23 @@ void advertise_shallow_grafts(int fd)
 
 /*
  * mark_reachable_objects() should have been run prior to this and all
- * reachable commits marked as "SEEN".
+ * reachable commits marked as "SEEN", except when quick_prune is non-zero,
+ * in which case lines are excised from the shallow file if they refer to
+ * commits that do not exist (any longer).
  */
-void prune_shallow(int show_only)
+void prune_shallow(unsigned options)
 {
        struct lock_file shallow_lock = LOCK_INIT;
        struct strbuf sb = STRBUF_INIT;
+       unsigned flags = SEEN_ONLY;
        int fd;
 
-       if (show_only) {
-               write_shallow_commits_1(&sb, 0, NULL, SEEN_ONLY | VERBOSE);
+       if (options & PRUNE_QUICK)
+               flags |= QUICK;
+
+       if (options & PRUNE_SHOW_ONLY) {
+               flags |= VERBOSE;
+               write_shallow_commits_1(&sb, 0, NULL, flags);
                strbuf_release(&sb);
                return;
        }
@@ -387,7 +398,7 @@ void prune_shallow(int show_only)
                                       git_path_shallow(the_repository),
                                       LOCK_DIE_ON_ERROR);
        check_shallow_file_for_update(the_repository);
-       if (write_shallow_commits_1(&sb, 0, NULL, SEEN_ONLY)) {
+       if (write_shallow_commits_1(&sb, 0, NULL, flags)) {
                if (write_in_full(fd, sb.buf, sb.len) < 0)
                        die_errno("failed to write to %s",
                                  get_lock_file_path(&shallow_lock));
index 84f067e..5820412 100644 (file)
@@ -111,7 +111,7 @@ static void mark_entry_for_delete(size_t pos, void *data)
                die("position for delete %d exceeds base index size %d",
                    (int)pos, istate->cache_nr);
        istate->cache[pos]->ce_flags |= CE_REMOVE;
-       istate->split_index->nr_deletions = 1;
+       istate->split_index->nr_deletions++;
 }
 
 static void replace_entry(size_t pos, void *data)
@@ -188,6 +188,30 @@ void merge_base_index(struct index_state *istate)
        si->saved_cache_nr = 0;
 }
 
+/*
+ * Compare most of the fields in two cache entries, i.e. all except the
+ * hashmap_entry and the name.
+ */
+static int compare_ce_content(struct cache_entry *a, struct cache_entry *b)
+{
+       const unsigned int ondisk_flags = CE_STAGEMASK | CE_VALID |
+                                         CE_EXTENDED_FLAGS;
+       unsigned int ce_flags = a->ce_flags;
+       unsigned int base_flags = b->ce_flags;
+       int ret;
+
+       /* only on-disk flags matter */
+       a->ce_flags &= ondisk_flags;
+       b->ce_flags &= ondisk_flags;
+       ret = memcmp(&a->ce_stat_data, &b->ce_stat_data,
+                    offsetof(struct cache_entry, name) -
+                    offsetof(struct cache_entry, ce_stat_data));
+       a->ce_flags = ce_flags;
+       b->ce_flags = base_flags;
+
+       return ret;
+}
+
 void prepare_to_write_split_index(struct index_state *istate)
 {
        struct split_index *si = init_split_index(istate);
@@ -207,38 +231,109 @@ void prepare_to_write_split_index(struct index_state *istate)
                 */
                for (i = 0; i < istate->cache_nr; i++) {
                        struct cache_entry *base;
-                       /* namelen is checked separately */
-                       const unsigned int ondisk_flags =
-                               CE_STAGEMASK | CE_VALID | CE_EXTENDED_FLAGS;
-                       unsigned int ce_flags, base_flags, ret;
                        ce = istate->cache[i];
-                       if (!ce->index)
+                       if (!ce->index) {
+                               /*
+                                * During simple update index operations this
+                                * is a cache entry that is not present in
+                                * the shared index.  It will be added to the
+                                * split index.
+                                *
+                                * However, it might also represent a file
+                                * that already has a cache entry in the
+                                * shared index, but a new index has just
+                                * been constructed by unpack_trees(), and
+                                * this entry now refers to different content
+                                * than what was recorded in the original
+                                * index, e.g. during 'read-tree -m HEAD^' or
+                                * 'checkout HEAD^'.  In this case the
+                                * original entry in the shared index will be
+                                * marked as deleted, and this entry will be
+                                * added to the split index.
+                                */
                                continue;
+                       }
                        if (ce->index > si->base->cache_nr) {
-                               ce->index = 0;
-                               continue;
+                               BUG("ce refers to a shared ce at %d, which is beyond the shared index size %d",
+                                   ce->index, si->base->cache_nr);
                        }
                        ce->ce_flags |= CE_MATCHED; /* or "shared" */
                        base = si->base->cache[ce->index - 1];
-                       if (ce == base)
+                       if (ce == base) {
+                               /* The entry is present in the shared index. */
+                               if (ce->ce_flags & CE_UPDATE_IN_BASE) {
+                                       /*
+                                        * Already marked for inclusion in
+                                        * the split index, either because
+                                        * the corresponding file was
+                                        * modified and the cached stat data
+                                        * was refreshed, or because there
+                                        * is already a replacement entry in
+                                        * the split index.
+                                        * Nothing more to do here.
+                                        */
+                               } else if (!ce_uptodate(ce) &&
+                                          is_racy_timestamp(istate, ce)) {
+                                       /*
+                                        * A racily clean cache entry stored
+                                        * only in the shared index: it must
+                                        * be added to the split index, so
+                                        * the subsequent do_write_index()
+                                        * can smudge its stat data.
+                                        */
+                                       ce->ce_flags |= CE_UPDATE_IN_BASE;
+                               } else {
+                                       /*
+                                        * The entry is only present in the
+                                        * shared index and it was not
+                                        * refreshed.
+                                        * Just leave it there.
+                                        */
+                               }
                                continue;
+                       }
                        if (ce->ce_namelen != base->ce_namelen ||
                            strcmp(ce->name, base->name)) {
                                ce->index = 0;
                                continue;
                        }
-                       ce_flags = ce->ce_flags;
-                       base_flags = base->ce_flags;
-                       /* only on-disk flags matter */
-                       ce->ce_flags   &= ondisk_flags;
-                       base->ce_flags &= ondisk_flags;
-                       ret = memcmp(&ce->ce_stat_data, &base->ce_stat_data,
-                                    offsetof(struct cache_entry, name) -
-                                    offsetof(struct cache_entry, ce_stat_data));
-                       ce->ce_flags = ce_flags;
-                       base->ce_flags = base_flags;
-                       if (ret)
+                       /*
+                        * This is the copy of a cache entry that is present
+                        * in the shared index, created by unpack_trees()
+                        * while it constructed a new index.
+                        */
+                       if (ce->ce_flags & CE_UPDATE_IN_BASE) {
+                               /*
+                                * Already marked for inclusion in the split
+                                * index, either because the corresponding
+                                * file was modified and the cached stat data
+                                * was refreshed, or because the original
+                                * entry already had a replacement entry in
+                                * the split index.
+                                * Nothing to do.
+                                */
+                       } else if (!ce_uptodate(ce) &&
+                                  is_racy_timestamp(istate, ce)) {
+                               /*
+                                * A copy of a racily clean cache entry from
+                                * the shared index.  It must be added to
+                                * the split index, so the subsequent
+                                * do_write_index() can smudge its stat data.
+                                */
                                ce->ce_flags |= CE_UPDATE_IN_BASE;
+                       } else {
+                               /*
+                                * Thoroughly compare the cached data to see
+                                * whether it should be marked for inclusion
+                                * in the split index.
+                                *
+                                * This comparison might be unnecessary, as
+                                * code paths modifying the cached data do
+                                * set CE_UPDATE_IN_BASE as well.
+                                */
+                               if (compare_ce_content(ce, base))
+                                       ce->ce_flags |= CE_UPDATE_IN_BASE;
+                       }
                        discard_cache_entry(base);
                        si->base->cache[ce->index - 1] = ce;
                }
index 60a35ae..bf18fdd 100644 (file)
--- a/strbuf.h
+++ b/strbuf.h
@@ -87,7 +87,7 @@ struct object_id;
  * Initialize the structure. The second parameter can be zero or a bigger
  * number to allocate memory, in case you want to prevent further reallocs.
  */
-extern void strbuf_init(struct strbuf *, size_t);
+void strbuf_init(struct strbuf *sb, size_t alloc);
 
 /**
  * Release a string buffer and the memory it used. After this call, the
@@ -97,7 +97,7 @@ extern void strbuf_init(struct strbuf *, size_t);
  * To clear a strbuf in preparation for further use without the overhead
  * of free()ing and malloc()ing again, use strbuf_reset() instead.
  */
-extern void strbuf_release(struct strbuf *);
+void strbuf_release(struct strbuf *sb);
 
 /**
  * Detach the string from the strbuf and returns it; you now own the
@@ -107,7 +107,7 @@ extern void strbuf_release(struct strbuf *);
  * The strbuf that previously held the string is reset to `STRBUF_INIT` so
  * it can be reused after calling this function.
  */
-extern char *strbuf_detach(struct strbuf *, size_t *);
+char *strbuf_detach(struct strbuf *sb, size_t *sz);
 
 /**
  * Attach a string to a buffer. You should specify the string to attach,
@@ -117,7 +117,7 @@ extern char *strbuf_detach(struct strbuf *, size_t *);
  * malloc()ed, and after attaching, the pointer cannot be relied upon
  * anymore, and neither be free()d directly.
  */
-extern void strbuf_attach(struct strbuf *, void *, size_t, size_t);
+void strbuf_attach(struct strbuf *sb, void *str, size_t len, size_t mem);
 
 /**
  * Swap the contents of two string buffers.
@@ -148,7 +148,7 @@ static inline size_t strbuf_avail(const struct strbuf *sb)
  * This is never a needed operation, but can be critical for performance in
  * some cases.
  */
-extern void strbuf_grow(struct strbuf *, size_t);
+void strbuf_grow(struct strbuf *sb, size_t amount);
 
 /**
  * Set the length of the buffer to a given value. This function does *not*
@@ -183,30 +183,30 @@ static inline void strbuf_setlen(struct strbuf *sb, size_t len)
  * Strip whitespace from the beginning (`ltrim`), end (`rtrim`), or both side
  * (`trim`) of a string.
  */
-extern void strbuf_trim(struct strbuf *);
-extern void strbuf_rtrim(struct strbuf *);
-extern void strbuf_ltrim(struct strbuf *);
+void strbuf_trim(struct strbuf *sb);
+void strbuf_rtrim(struct strbuf *sb);
+void strbuf_ltrim(struct strbuf *sb);
 
 /* Strip trailing directory separators */
-extern void strbuf_trim_trailing_dir_sep(struct strbuf *);
+void strbuf_trim_trailing_dir_sep(struct strbuf *sb);
 
 /**
  * Replace the contents of the strbuf with a reencoded form.  Returns -1
  * on error, 0 on success.
  */
-extern int strbuf_reencode(struct strbuf *sb, const char *from, const char *to);
+int strbuf_reencode(struct strbuf *sb, const char *from, const char *to);
 
 /**
  * Lowercase each character in the buffer using `tolower`.
  */
-extern void strbuf_tolower(struct strbuf *sb);
+void strbuf_tolower(struct strbuf *sb);
 
 /**
  * Compare two buffers. Returns an integer less than, equal to, or greater
  * than zero if the first buffer is found, respectively, to be less than,
  * to match, or be greater than the second buffer.
  */
-extern int strbuf_cmp(const struct strbuf *, const struct strbuf *);
+int strbuf_cmp(const struct strbuf *first, const struct strbuf *second);
 
 
 /**
@@ -233,37 +233,38 @@ static inline void strbuf_addch(struct strbuf *sb, int c)
 /**
  * Add a character the specified number of times to the buffer.
  */
-extern void strbuf_addchars(struct strbuf *sb, int c, size_t n);
+void strbuf_addchars(struct strbuf *sb, int c, size_t n);
 
 /**
  * Insert data to the given position of the buffer. The remaining contents
  * will be shifted, not overwritten.
  */
-extern void strbuf_insert(struct strbuf *, size_t pos, const void *, size_t);
+void strbuf_insert(struct strbuf *sb, size_t pos, const void *, size_t);
 
 /**
  * Remove given amount of data from a given position of the buffer.
  */
-extern void strbuf_remove(struct strbuf *, size_t pos, size_t len);
+void strbuf_remove(struct strbuf *sb, size_t pos, size_t len);
 
 /**
  * Remove the bytes between `pos..pos+len` and replace it with the given
  * data.
  */
-extern void strbuf_splice(struct strbuf *, size_t pos, size_t len,
-                         const void *, size_t);
+void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,
+                  const void *data, size_t data_len);
 
 /**
  * Add a NUL-terminated string to the buffer. Each line will be prepended
  * by a comment character and a blank.
  */
-extern void strbuf_add_commented_lines(struct strbuf *out, const char *buf, size_t size);
+void strbuf_add_commented_lines(struct strbuf *out,
+                               const char *buf, size_t size);
 
 
 /**
  * Add data of given length to the buffer.
  */
-extern void strbuf_add(struct strbuf *, const void *, size_t);
+void strbuf_add(struct strbuf *sb, const void *data, size_t len);
 
 /**
  * Add a NUL-terminated string to the buffer.
@@ -282,7 +283,7 @@ static inline void strbuf_addstr(struct strbuf *sb, const char *s)
 /**
  * Copy the contents of another buffer at the end of the current one.
  */
-extern void strbuf_addbuf(struct strbuf *sb, const struct strbuf *sb2);
+void strbuf_addbuf(struct strbuf *sb, const struct strbuf *sb2);
 
 /**
  * This function can be used to expand a format string containing
@@ -308,8 +309,13 @@ extern void strbuf_addbuf(struct strbuf *sb, const struct strbuf *sb2);
  * parameters to the callback, `strbuf_expand()` passes a context pointer,
  * which can be used by the programmer of the callback as she sees fit.
  */
-typedef size_t (*expand_fn_t) (struct strbuf *sb, const char *placeholder, void *context);
-extern void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn, void *context);
+typedef size_t (*expand_fn_t) (struct strbuf *sb,
+                              const char *placeholder,
+                              void *context);
+void strbuf_expand(struct strbuf *sb,
+                  const char *format,
+                  expand_fn_t fn,
+                  void *context);
 
 /**
  * Used as callback for `strbuf_expand()`, expects an array of
@@ -321,7 +327,9 @@ struct strbuf_expand_dict_entry {
        const char *placeholder;
        const char *value;
 };
-extern size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder, void *context);
+size_t strbuf_expand_dict_cb(struct strbuf *sb,
+                            const char *placeholder,
+                            void *context);
 
 /**
  * Append the contents of one strbuf to another, quoting any
@@ -329,29 +337,29 @@ extern size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder,
  * destination. This is useful for literal data to be fed to either
  * strbuf_expand or to the *printf family of functions.
  */
-extern void strbuf_addbuf_percentquote(struct strbuf *dst, const struct strbuf *src);
+void strbuf_addbuf_percentquote(struct strbuf *dst, const struct strbuf *src);
 
 /**
  * Append the given byte size as a human-readable string (i.e. 12.23 KiB,
  * 3.50 MiB).
  */
-extern void strbuf_humanise_bytes(struct strbuf *buf, off_t bytes);
+void strbuf_humanise_bytes(struct strbuf *buf, off_t bytes);
 
 /**
  * Add a formatted string to the buffer.
  */
 __attribute__((format (printf,2,3)))
-extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...);
+void strbuf_addf(struct strbuf *sb, const char *fmt, ...);
 
 /**
  * Add a formatted string prepended by a comment character and a
  * blank to the buffer.
  */
 __attribute__((format (printf, 2, 3)))
-extern void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...);
+void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...);
 
 __attribute__((format (printf,2,0)))
-extern void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap);
+void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap);
 
 /**
  * Add the time specified by `tm`, as formatted by `strftime`.
@@ -361,9 +369,9 @@ extern void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap);
  * `suppress_tz_name`, when set, expands %Z internally to the empty
  * string rather than passing it to `strftime`.
  */
-extern void strbuf_addftime(struct strbuf *sb, const char *fmt,
-                           const struct tm *tm, int tz_offset,
-                           int suppress_tz_name);
+void strbuf_addftime(struct strbuf *sb, const char *fmt,
+                   const struct tm *tm, int tz_offset,
+                   int suppress_tz_name);
 
 /**
  * Read a given size of data from a FILE* pointer to the buffer.
@@ -373,14 +381,14 @@ extern void strbuf_addftime(struct strbuf *sb, const char *fmt,
  * `strbuf_read()`, `strbuf_read_file()` and `strbuf_getline_*()`
  * family of functions have the same behaviour as well.
  */
-extern size_t strbuf_fread(struct strbuf *, size_t, FILE *);
+size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *file);
 
 /**
  * Read the contents of a given file descriptor. The third argument can be
  * used to give a hint about the file size, to avoid reallocs.  If read fails,
  * any partial read is undone.
  */
-extern ssize_t strbuf_read(struct strbuf *, int fd, size_t hint);
+ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint);
 
 /**
  * Read the contents of a given file descriptor partially by using only one
@@ -388,7 +396,7 @@ extern ssize_t strbuf_read(struct strbuf *, int fd, size_t hint);
  * file size, to avoid reallocs. Returns the number of new bytes appended to
  * the sb.
  */
-extern ssize_t strbuf_read_once(struct strbuf *, int fd, size_t hint);
+ssize_t strbuf_read_once(struct strbuf *sb, int fd, size_t hint);
 
 /**
  * Read the contents of a file, specified by its path. The third argument
@@ -396,19 +404,19 @@ extern ssize_t strbuf_read_once(struct strbuf *, int fd, size_t hint);
  * Return the number of bytes read or a negative value if some error
  * occurred while opening or reading the file.
  */
-extern ssize_t strbuf_read_file(struct strbuf *sb, const char *path, size_t hint);
+ssize_t strbuf_read_file(struct strbuf *sb, const char *path, size_t hint);
 
 /**
  * Read the target of a symbolic link, specified by its path.  The third
  * argument can be used to give a hint about the size, to avoid reallocs.
  */
-extern int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint);
+int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint);
 
 /**
  * Write the whole content of the strbuf to the stream not stopping at
  * NUL bytes.
  */
-extern ssize_t strbuf_write(struct strbuf *sb, FILE *stream);
+ssize_t strbuf_write(struct strbuf *sb, FILE *stream);
 
 /**
  * Read a line from a FILE *, overwriting the existing contents of
@@ -422,10 +430,10 @@ extern ssize_t strbuf_write(struct strbuf *sb, FILE *stream);
 typedef int (*strbuf_getline_fn)(struct strbuf *, FILE *);
 
 /* Uses LF as the line terminator */
-extern int strbuf_getline_lf(struct strbuf *sb, FILE *fp);
+int strbuf_getline_lf(struct strbuf *sb, FILE *fp);
 
 /* Uses NUL as the line terminator */
-extern int strbuf_getline_nul(struct strbuf *sb, FILE *fp);
+int strbuf_getline_nul(struct strbuf *sb, FILE *fp);
 
 /*
  * Similar to strbuf_getline_lf(), but additionally treats a CR that
@@ -434,14 +442,14 @@ extern int strbuf_getline_nul(struct strbuf *sb, FILE *fp);
  * that can come from platforms whose native text format is CRLF
  * terminated.
  */
-extern int strbuf_getline(struct strbuf *, FILE *);
+int strbuf_getline(struct strbuf *sb, FILE *file);
 
 
 /**
  * Like `strbuf_getline`, but keeps the trailing terminator (if
  * any) in the buffer.
  */
-extern int strbuf_getwholeline(struct strbuf *, FILE *, int);
+int strbuf_getwholeline(struct strbuf *sb, FILE *file, int term);
 
 /**
  * Like `strbuf_getwholeline`, but operates on a file descriptor.
@@ -449,19 +457,19 @@ extern int strbuf_getwholeline(struct strbuf *, FILE *, int);
  * use it unless you need the correct position in the file
  * descriptor.
  */
-extern int strbuf_getwholeline_fd(struct strbuf *, int, int);
+int strbuf_getwholeline_fd(struct strbuf *sb, int fd, int term);
 
 /**
  * Set the buffer to the path of the current working directory.
  */
-extern int strbuf_getcwd(struct strbuf *sb);
+int strbuf_getcwd(struct strbuf *sb);
 
 /**
  * Add a path to a buffer, converting a relative path to an
  * absolute one in the process.  Symbolic links are not
  * resolved.
  */
-extern void strbuf_add_absolute_path(struct strbuf *sb, const char *path);
+void strbuf_add_absolute_path(struct strbuf *sb, const char *path);
 
 /**
  * Canonize `path` (make it absolute, resolve symlinks, remove extra
@@ -475,7 +483,7 @@ extern void strbuf_add_absolute_path(struct strbuf *sb, const char *path);
  * Callers that don't mind links should use the more lightweight
  * strbuf_add_absolute_path() instead.
  */
-extern void strbuf_add_real_path(struct strbuf *sb, const char *path);
+void strbuf_add_real_path(struct strbuf *sb, const char *path);
 
 
 /**
@@ -483,13 +491,13 @@ extern void strbuf_add_real_path(struct strbuf *sb, const char *path);
  * normalize_path_copy() for details. If an error occurs, the contents of "sb"
  * are left untouched, and -1 is returned.
  */
-extern int strbuf_normalize_path(struct strbuf *sb);
+int strbuf_normalize_path(struct strbuf *sb);
 
 /**
  * Strip whitespace from a buffer. The second parameter controls if
  * comments are considered contents to be removed or not.
  */
-extern void strbuf_stripspace(struct strbuf *buf, int skip_comments);
+void strbuf_stripspace(struct strbuf *buf, int skip_comments);
 
 static inline int strbuf_strip_suffix(struct strbuf *sb, const char *suffix)
 {
@@ -518,8 +526,8 @@ static inline int strbuf_strip_suffix(struct strbuf *sb, const char *suffix)
  * For lighter-weight alternatives, see string_list_split() and
  * string_list_split_in_place().
  */
-extern struct strbuf **strbuf_split_buf(const char *, size_t,
-                                       int terminator, int max);
+struct strbuf **strbuf_split_buf(const char *str, size_t len,
+                                int terminator, int max);
 
 static inline struct strbuf **strbuf_split_str(const char *str,
                                               int terminator, int max)
@@ -528,7 +536,7 @@ static inline struct strbuf **strbuf_split_str(const char *str,
 }
 
 static inline struct strbuf **strbuf_split_max(const struct strbuf *sb,
-                                               int terminator, int max)
+                                              int terminator, int max)
 {
        return strbuf_split_buf(sb->buf, sb->len, terminator, max);
 }
@@ -549,23 +557,23 @@ static inline struct strbuf **strbuf_split(const struct strbuf *sb,
  *   'element1, element2, ..., elementN'
  * to str.  If only one element, just write "element1" to str.
  */
-extern void strbuf_add_separated_string_list(struct strbuf *str,
-                                            const char *sep,
-                                            struct string_list *slist);
+void strbuf_add_separated_string_list(struct strbuf *str,
+                                     const char *sep,
+                                     struct string_list *slist);
 
 /**
  * Free a NULL-terminated list of strbufs (for example, the return
  * values of the strbuf_split*() functions).
  */
-extern void strbuf_list_free(struct strbuf **);
+void strbuf_list_free(struct strbuf **list);
 
 /**
  * Add the abbreviation, as generated by find_unique_abbrev, of `sha1` to
  * the strbuf `sb`.
  */
-extern void strbuf_add_unique_abbrev(struct strbuf *sb,
-                                    const struct object_id *oid,
-                                    int abbrev_len);
+void strbuf_add_unique_abbrev(struct strbuf *sb,
+                             const struct object_id *oid,
+                             int abbrev_len);
 
 /**
  * Launch the user preferred editor to edit a file and fill the buffer
@@ -574,15 +582,21 @@ extern void strbuf_add_unique_abbrev(struct strbuf *sb,
  * run in. If the buffer is NULL the editor is launched as usual but the
  * file's contents are not read into the buffer upon completion.
  */
-extern int launch_editor(const char *path, struct strbuf *buffer, const char *const *env);
+int launch_editor(const char *path,
+                 struct strbuf *buffer,
+                 const char *const *env);
 
-extern void strbuf_add_lines(struct strbuf *sb, const char *prefix, const char *buf, size_t size);
+void strbuf_add_lines(struct strbuf *sb,
+                     const char *prefix,
+                     const char *buf,
+                     size_t size);
 
 /**
  * Append s to sb, with the characters '<', '>', '&' and '"' converted
  * into XML entities.
  */
-extern void strbuf_addstr_xml_quoted(struct strbuf *sb, const char *s);
+void strbuf_addstr_xml_quoted(struct strbuf *sb,
+                             const char *s);
 
 /**
  * "Complete" the contents of `sb` by ensuring that either it ends with the
@@ -612,8 +626,8 @@ static inline void strbuf_complete_line(struct strbuf *sb)
  * If "allowed" is non-zero, restrict the set of allowed expansions. See
  * interpret_branch_name() for details.
  */
-extern void strbuf_branchname(struct strbuf *sb, const char *name,
-                             unsigned allowed);
+void strbuf_branchname(struct strbuf *sb, const char *name,
+                      unsigned allowed);
 
 /*
  * Like strbuf_branchname() above, but confirm that the result is
@@ -621,15 +635,15 @@ extern void strbuf_branchname(struct strbuf *sb, const char *name,
  *
  * The return value is "0" if the result is valid, and "-1" otherwise.
  */
-extern int strbuf_check_branch_ref(struct strbuf *sb, const char *name);
+int strbuf_check_branch_ref(struct strbuf *sb, const char *name);
 
-extern void strbuf_addstr_urlencode(struct strbuf *, const char *,
-                                   int reserved);
+void strbuf_addstr_urlencode(struct strbuf *sb, const char *name,
+                            int reserved);
 
 __attribute__((format (printf,1,2)))
-extern int printf_ln(const char *fmt, ...);
+int printf_ln(const char *fmt, ...);
 __attribute__((format (printf,2,3)))
-extern int fprintf_ln(FILE *fp, const char *fmt, ...);
+int fprintf_ln(FILE *fp, const char *fmt, ...);
 
 char *xstrdup_tolower(const char *);
 char *xstrdup_toupper(const char *);
index 771c455..1f6063f 100644 (file)
@@ -195,16 +195,6 @@ void string_list_clear_func(struct string_list *list, string_list_clear_func_t c
        list->nr = list->alloc = 0;
 }
 
-
-void print_string_list(const struct string_list *p, const char *text)
-{
-       int i;
-       if ( text )
-               printf("%s\n", text);
-       for (i = 0; i < p->nr; i++)
-               printf("%s:%p\n", p->items[i].string, p->items[i].util);
-}
-
 struct string_list_item *string_list_append_nodup(struct string_list *list,
                                                  char *string)
 {
index ff8f609..18c718c 100644 (file)
@@ -114,14 +114,6 @@ void filter_string_list(struct string_list *list, int free_util,
                        string_list_each_func_t want, void *cb_data);
 
 /**
- * Dump a string_list to stdout, useful mainly for debugging
- * purposes. It can take an optional header argument and it writes out
- * the string-pointer pairs of the string_list, each one in its own
- * line.
- */
-void print_string_list(const struct string_list *p, const char *text);
-
-/**
  * Free a string_list. The `string` pointer of the items will be freed
  * in case the `strdup_strings` member of the string_list is set. The
  * second parameter controls if the `util` pointer of the items should
index a2b266f..f27f14e 100644 (file)
@@ -65,8 +65,7 @@ int is_staging_gitmodules_ok(struct index_state *istate)
        if ((pos >= 0) && (pos < istate->cache_nr)) {
                struct stat st;
                if (lstat(GITMODULES_FILE, &st) == 0 &&
-                   ie_match_stat(istate, istate->cache[pos], &st,
-                                 CE_MATCH_IGNORE_FSMONITOR) & DATA_CHANGED)
+                   ie_match_stat(istate, istate->cache[pos], &st, 0) & DATA_CHANGED)
                        return 0;
        }
 
@@ -1880,7 +1879,7 @@ const char *get_superproject_working_tree(void)
                 * We're only interested in the name after the tab.
                 */
                super_sub = strchr(sb.buf, '\t') + 1;
-               super_sub_len = sb.buf + sb.len - super_sub - 1;
+               super_sub_len = strlen(super_sub);
 
                if (super_sub_len > cwd_len ||
                    strcmp(&cwd[cwd_len - super_sub_len], super_sub))
index 9028b47..0c31792 100644 (file)
--- a/t/README
+++ b/t/README
@@ -154,6 +154,7 @@ appropriately before running "make".
        As the names depend on the tests' file names, it is safe to
        run the tests with this option in parallel.
 
+-V::
 --verbose-log::
        Write verbose output to the same logfile as `--tee`, but do
        _not_ write it to stdout. Unlike `--tee --verbose`, this option
index 2762ca6..6a84a53 100644 (file)
@@ -15,7 +15,10 @@ static void test_parse_commit_in_graph(const char *gitdir, const char *worktree,
        struct commit *c;
        struct commit_list *parent;
 
-       repo_init(&r, gitdir, worktree);
+       setup_git_env(gitdir);
+
+       if (repo_init(&r, gitdir, worktree))
+               die("Couldn't init repo");
 
        c = lookup_commit(&r, commit_oid);
 
@@ -38,7 +41,10 @@ static void test_get_commit_tree_in_graph(const char *gitdir,
        struct commit *c;
        struct tree *tree;
 
-       repo_init(&r, gitdir, worktree);
+       setup_git_env(gitdir);
+
+       if (repo_init(&r, gitdir, worktree))
+               die("Couldn't init repo");
 
        c = lookup_commit(&r, commit_oid);
 
index 0edafcf..db19131 100644 (file)
@@ -43,6 +43,9 @@ static struct test_cmd cmds[] = {
        { "subprocess", cmd__subprocess },
        { "urlmatch-normalization", cmd__urlmatch_normalization },
        { "wildmatch", cmd__wildmatch },
+#ifdef GIT_WINDOWS_NATIVE
+       { "windows-named-pipe", cmd__windows_named_pipe },
+#endif
        { "write-cache", cmd__write_cache },
 };
 
index e954e8c..4914001 100644 (file)
@@ -39,6 +39,9 @@ int cmd__submodule_config(int argc, const char **argv);
 int cmd__subprocess(int argc, const char **argv);
 int cmd__urlmatch_normalization(int argc, const char **argv);
 int cmd__wildmatch(int argc, const char **argv);
+#ifdef GIT_WINDOWS_NATIVE
+int cmd__windows_named_pipe(int argc, const char **argv);
+#endif
 int cmd__write_cache(int argc, const char **argv);
 
 #endif
diff --git a/t/helper/test-windows-named-pipe.c b/t/helper/test-windows-named-pipe.c
new file mode 100644 (file)
index 0000000..b4b752b
--- /dev/null
@@ -0,0 +1,72 @@
+#include "test-tool.h"
+#include "git-compat-util.h"
+#include "strbuf.h"
+
+#ifdef GIT_WINDOWS_NATIVE
+static const char *usage_string = "<pipe-filename>";
+
+#define TEST_BUFSIZE (4096)
+
+int cmd__windows_named_pipe(int argc, const char **argv)
+{
+       const char *filename;
+       struct strbuf pathname = STRBUF_INIT;
+       int err;
+       HANDLE h;
+       BOOL connected;
+       char buf[TEST_BUFSIZE + 1];
+
+       if (argc < 2)
+               goto print_usage;
+       filename = argv[1];
+       if (strchr(filename, '/') || strchr(filename, '\\'))
+               goto print_usage;
+       strbuf_addf(&pathname, "//./pipe/%s", filename);
+
+       /*
+        * Create a single instance of the server side of the named pipe.
+        * This will allow exactly one client instance to connect to it.
+        */
+       h = CreateNamedPipeA(
+               pathname.buf,
+               PIPE_ACCESS_INBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE,
+               PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
+               PIPE_UNLIMITED_INSTANCES,
+               TEST_BUFSIZE, TEST_BUFSIZE, 0, NULL);
+       if (h == INVALID_HANDLE_VALUE) {
+               err = err_win_to_posix(GetLastError());
+               fprintf(stderr, "CreateNamedPipe failed: %s\n",
+                       strerror(err));
+               return err;
+       }
+
+       connected = ConnectNamedPipe(h, NULL)
+               ? TRUE
+               : (GetLastError() == ERROR_PIPE_CONNECTED);
+       if (!connected) {
+               err = err_win_to_posix(GetLastError());
+               fprintf(stderr, "ConnectNamedPipe failed: %s\n",
+                       strerror(err));
+               CloseHandle(h);
+               return err;
+       }
+
+       while (1) {
+               DWORD nbr;
+               BOOL success = ReadFile(h, buf, TEST_BUFSIZE, &nbr, NULL);
+               if (!success || nbr == 0)
+                       break;
+               buf[nbr] = 0;
+
+               write(1, buf, nbr);
+       }
+
+       DisconnectNamedPipe(h);
+       CloseHandle(h);
+       return 0;
+
+print_usage:
+       fprintf(stderr, "usage: %s %s\n", argv[0], usage_string);
+       return 1;
+}
+#endif
index 2ca9fb6..0c93d00 100644 (file)
@@ -47,9 +47,9 @@ set_fake_editor () {
        action=pick
        for line in $FAKE_LINES; do
                case $line in
-               pick|squash|fixup|edit|reword|drop)
+               pick|p|squash|s|fixup|f|edit|e|reword|r|drop|d)
                        action="$line";;
-               exec*)
+               exec_*|x_*)
                        echo "$line" | sed 's/_/ /g' >> "$1";;
                "#")
                        echo '# comment' >> "$1";;
diff --git a/t/t0051-windows-named-pipe.sh b/t/t0051-windows-named-pipe.sh
new file mode 100755 (executable)
index 0000000..10ac92d
--- /dev/null
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+test_description='Windows named pipes'
+
+. ./test-lib.sh
+
+test_expect_success MINGW 'o_append write to named pipe' '
+       GIT_TRACE="$(pwd)/expect" git status >/dev/null 2>&1 &&
+       { test-tool windows-named-pipe t0051 >actual 2>&1 & } &&
+       pid=$! &&
+       sleep 1 &&
+       GIT_TRACE=//./pipe/t0051 git status >/dev/null 2>warning &&
+       wait $pid &&
+       test_cmp expect actual
+'
+
+test_done
index 3e131c5..cf932c8 100755 (executable)
@@ -12,10 +12,14 @@ cat >hello-script <<-EOF
        cat hello-script
 EOF
 
-test_expect_success 'start_command reports ENOENT' '
+test_expect_success 'start_command reports ENOENT (slash)' '
        test-tool run-command start-command-ENOENT ./does-not-exist
 '
 
+test_expect_success 'start_command reports ENOENT (no slash)' '
+       test-tool run-command start-command-ENOENT does-not-exist
+'
+
 test_expect_success 'run_command can run a command' '
        cat hello-script >hello.sh &&
        chmod +x hello.sh &&
@@ -25,6 +29,13 @@ test_expect_success 'run_command can run a command' '
        test_must_be_empty err
 '
 
+test_expect_success 'run_command is restricted to PATH' '
+       write_script should-not-run <<-\EOF &&
+       echo yikes
+       EOF
+       test_must_fail test-tool run-command run-command should-not-run
+'
+
 test_expect_success !MINGW 'run_command can run a script without a #! line' '
        cat >hello <<-\EOF &&
        cat hello-script
index 7de4014..504334e 100755 (executable)
@@ -161,6 +161,24 @@ test_expect_success PERL 'commit --interactive gives cache-tree on partial commi
        test_cache_tree
 '
 
+test_expect_success PERL 'commit -p with shrinking cache-tree' '
+       mkdir -p deep/subdir &&
+       echo content >deep/subdir/file &&
+       git add deep &&
+       git commit -m add &&
+       git rm -r deep &&
+
+       before=$(wc -c <.git/index) &&
+       git commit -m delete -p &&
+       after=$(wc -c <.git/index) &&
+
+       # double check that the index shrank
+       test $before -gt $after &&
+
+       # and that our index was not corrupted
+       git fsck
+'
+
 test_expect_success 'commit in child dir has cache-tree' '
        mkdir dir &&
        >dir/child.t &&
@@ -243,13 +261,16 @@ test_expect_success 'no phantom error when switching trees' '
 '
 
 test_expect_success 'switching trees does not invalidate shared index' '
-       git update-index --split-index &&
-       >split &&
-       git add split &&
-       test-tool dump-split-index .git/index | grep -v ^own >before &&
-       git commit -m "as-is" &&
-       test-tool dump-split-index .git/index | grep -v ^own >after &&
-       test_cmp before after
+       (
+               sane_unset GIT_TEST_SPLIT_INDEX &&
+               git update-index --split-index &&
+               >split &&
+               git add split &&
+               test-tool dump-split-index .git/index | grep -v ^own >before &&
+               git commit -m "as-is" &&
+               test-tool dump-split-index .git/index | grep -v ^own >after &&
+               test_cmp before after
+       )
 '
 
 test_done
index 1281300..7762f89 100755 (executable)
@@ -170,6 +170,59 @@ test_expect_success 'fetching of missing objects' '
        git verify-pack --verbose "$IDX" | grep "$HASH"
 '
 
+test_expect_success 'fetching of missing objects works with ref-in-want enabled' '
+       # ref-in-want requires protocol version 2
+       git -C server config protocol.version 2 &&
+       git -C server config uploadpack.allowrefinwant 1 &&
+       git -C repo config protocol.version 2 &&
+
+       rm -rf repo/.git/objects/* &&
+       rm -f trace &&
+       GIT_TRACE_PACKET="$(pwd)/trace" git -C repo cat-file -p "$HASH" &&
+       grep "git< fetch=.*ref-in-want" trace
+'
+
+test_expect_success 'fetching of missing blobs works' '
+       rm -rf server repo &&
+       test_create_repo server &&
+       test_commit -C server foo &&
+       git -C server repack -a -d --write-bitmap-index &&
+
+       git clone "file://$(pwd)/server" repo &&
+       git hash-object repo/foo.t >blobhash &&
+       rm -rf repo/.git/objects/* &&
+
+       git -C server config uploadpack.allowanysha1inwant 1 &&
+       git -C server config uploadpack.allowfilter 1 &&
+       git -C repo config core.repositoryformatversion 1 &&
+       git -C repo config extensions.partialclone "origin" &&
+
+       git -C repo cat-file -p $(cat blobhash)
+'
+
+test_expect_success 'fetching of missing trees does not fetch blobs' '
+       rm -rf server repo &&
+       test_create_repo server &&
+       test_commit -C server foo &&
+       git -C server repack -a -d --write-bitmap-index &&
+
+       git clone "file://$(pwd)/server" repo &&
+       git -C repo rev-parse foo^{tree} >treehash &&
+       git hash-object repo/foo.t >blobhash &&
+       rm -rf repo/.git/objects/* &&
+
+       git -C server config uploadpack.allowanysha1inwant 1 &&
+       git -C server config uploadpack.allowfilter 1 &&
+       git -C repo config core.repositoryformatversion 1 &&
+       git -C repo config extensions.partialclone "origin" &&
+       git -C repo cat-file -p $(cat treehash) &&
+
+       # Ensure that the tree, but not the blob, is fetched
+       git -C repo rev-list --objects --missing=print $(cat treehash) >objects &&
+       grep "^$(cat treehash)" objects &&
+       grep "^[?]$(cat blobhash)" objects
+'
+
 test_expect_success 'rev-list stops traversal at missing and promised commit' '
        rm -rf repo &&
        test_create_repo repo &&
index 7c8df20..b72beeb 100755 (executable)
@@ -366,7 +366,7 @@ test_expect_success 'Query master@{2005-05-25} (before history)' '
        test_when_finished "rm -f o e" &&
        git rev-parse --verify master@{2005-05-25} >o 2>e &&
        test $C = $(cat o) &&
-       echo test "warning: Log for '\''master'\'' only goes back to $ed." = "$(cat e)"
+       test "warning: Log for '\''master'\'' only goes back to $ed." = "$(cat e)"
 '
 test_expect_success 'Query "master@{May 26 2005 23:31:59}" (1 second before history)' '
        test_when_finished "rm -f o e" &&
@@ -807,6 +807,37 @@ test_expect_success 'stdin delete symref works option no-deref' '
        test_cmp expect actual
 '
 
+test_expect_success 'stdin update symref works flag --no-deref' '
+       git symbolic-ref TESTSYMREFONE $b &&
+       git symbolic-ref TESTSYMREFTWO $b &&
+       cat >stdin <<-EOF &&
+       update TESTSYMREFONE $a $b
+       update TESTSYMREFTWO $a $b
+       EOF
+       git update-ref --no-deref --stdin <stdin &&
+       git rev-parse TESTSYMREFONE TESTSYMREFTWO >expect &&
+       git rev-parse $a $a >actual &&
+       test_cmp expect actual &&
+       git rev-parse $m~1 >expect &&
+       git rev-parse $b >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'stdin delete symref works flag --no-deref' '
+       git symbolic-ref TESTSYMREFONE $b &&
+       git symbolic-ref TESTSYMREFTWO $b &&
+       cat >stdin <<-EOF &&
+       delete TESTSYMREFONE $b
+       delete TESTSYMREFTWO $b
+       EOF
+       git update-ref --no-deref --stdin <stdin &&
+       test_must_fail git rev-parse --verify -q TESTSYMREFONE &&
+       test_must_fail git rev-parse --verify -q TESTSYMREFTWO &&
+       git rev-parse $m~1 >expect &&
+       git rev-parse $b >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'stdin delete ref works with right old value' '
        echo "delete $b $m~1" >stdin &&
        git update-ref --stdin <stdin &&
index 0f2dd26..b5677d2 100755 (executable)
@@ -673,16 +673,35 @@ test_expect_success 'fsck detects trailing loose garbage (commit)' '
        test_i18ngrep "garbage.*$commit" out
 '
 
-test_expect_success 'fsck detects trailing loose garbage (blob)' '
+test_expect_success 'fsck detects trailing loose garbage (large blob)' '
        blob=$(echo trailing | git hash-object -w --stdin) &&
        file=$(sha1_file $blob) &&
        test_when_finished "remove_object $blob" &&
        chmod +w "$file" &&
        echo garbage >>"$file" &&
-       test_must_fail git fsck 2>out &&
+       test_must_fail git -c core.bigfilethreshold=5 fsck 2>out &&
        test_i18ngrep "garbage.*$blob" out
 '
 
+test_expect_success 'fsck detects truncated loose object' '
+       # make it big enough that we know we will truncate in the data
+       # portion, not the header
+       test-tool genrandom truncate 4096 >file &&
+       blob=$(git hash-object -w file) &&
+       file=$(sha1_file $blob) &&
+       test_when_finished "remove_object $blob" &&
+       test_copy_bytes 1024 <"$file" >tmp &&
+       rm "$file" &&
+       mv -f tmp "$file" &&
+
+       # check both regular and streaming code paths
+       test_must_fail git fsck 2>out &&
+       test_i18ngrep corrupt.*$blob out &&
+
+       test_must_fail git -c core.bigfilethreshold=128 fsck 2>out &&
+       test_i18ngrep corrupt.*$blob out
+'
+
 # for each of type, we have one version which is referenced by another object
 # (and so while unreachable, not dangling), and another variant which really is
 # dangling.
index 5c715fe..01abee5 100755 (executable)
@@ -142,6 +142,22 @@ test_expect_success 'showing the superproject correctly' '
        git -C super submodule add ../sub dir/sub &&
        echo $(pwd)/super >expect  &&
        git -C super/dir/sub rev-parse --show-superproject-working-tree >out &&
+       test_cmp expect out &&
+
+       test_commit -C super submodule_add &&
+       git -C super checkout -b branch1 &&
+       git -C super/dir/sub checkout -b branch1 &&
+       test_commit -C super/dir/sub branch1_commit &&
+       git -C super add dir/sub &&
+       test_commit -C super branch1_commit &&
+       git -C super checkout -b branch2 master &&
+       git -C super/dir/sub checkout -b branch2 master &&
+       test_commit -C super/dir/sub branch2_commit &&
+       git -C super add dir/sub &&
+       test_commit -C super branch2_commit &&
+       test_must_fail git -C super merge branch1 &&
+
+       git -C super/dir/sub rev-parse --show-superproject-working-tree >out &&
        test_cmp expect out
 '
 
index b3b4d83..f053bf8 100755 (executable)
@@ -6,8 +6,18 @@ test_description='split index mode tests'
 
 # We need total control of index splitting here
 sane_unset GIT_TEST_SPLIT_INDEX
+# A couple of tests expect the index to have a specific checksum,
+# but the presence of the optional FSMN extension would interfere
+# with those checks, so disable it in this test script.
 sane_unset GIT_FSMONITOR_TEST
 
+# Create a file named as $1 with content read from stdin.
+# Set the file's mtime to a few seconds in the past to avoid racy situations.
+create_non_racy_file () {
+       cat >"$1" &&
+       test-tool chmtime =-5 "$1"
+}
+
 test_expect_success 'enable split index' '
        git config splitIndex.maxPercentChange 100 &&
        git update-index --split-index &&
@@ -31,7 +41,7 @@ test_expect_success 'enable split index' '
 '
 
 test_expect_success 'add one file' '
-       : >one &&
+       create_non_racy_file one &&
        git update-index --add one &&
        git ls-files --stage >ls-files.actual &&
        cat >ls-files.expect <<-EOF &&
@@ -57,7 +67,7 @@ test_expect_success 'disable split index' '
        EOF
        test_cmp ls-files.expect ls-files.actual &&
 
-       BASE=$(test-tool dump-split-index .git/index | grep "^own" | sed "s/own/base/") &&
+       BASE=$(test-tool dump-split-index .git/index | sed -n "s/^own/base/p") &&
        test-tool dump-split-index .git/index | sed "/^own/d" >actual &&
        cat >expect <<-EOF &&
        not a split index
@@ -83,7 +93,7 @@ test_expect_success 'enable split index again, "one" now belongs to base index"'
 '
 
 test_expect_success 'modify original file, base index untouched' '
-       echo modified >one &&
+       echo modified | create_non_racy_file one &&
        git update-index one &&
        git ls-files --stage >ls-files.actual &&
        cat >ls-files.expect <<-EOF &&
@@ -102,7 +112,7 @@ test_expect_success 'modify original file, base index untouched' '
 '
 
 test_expect_success 'add another file, which stays index' '
-       : >two &&
+       create_non_racy_file two &&
        git update-index --add two &&
        git ls-files --stage >ls-files.actual &&
        cat >ls-files.expect <<-EOF &&
@@ -155,7 +165,7 @@ test_expect_success 'remove file in base index' '
 '
 
 test_expect_success 'add original file back' '
-       : >one &&
+       create_non_racy_file one &&
        git update-index --add one &&
        git ls-files --stage >ls-files.actual &&
        cat >ls-files.expect <<-EOF &&
@@ -174,7 +184,7 @@ test_expect_success 'add original file back' '
 '
 
 test_expect_success 'add new file' '
-       : >two &&
+       create_non_racy_file two &&
        git update-index --add two &&
        git ls-files --stage >actual &&
        cat >expect <<-EOF &&
@@ -218,7 +228,7 @@ test_expect_success 'rev-parse --shared-index-path' '
 
 test_expect_success 'set core.splitIndex config variable to true' '
        git config core.splitIndex true &&
-       : >three &&
+       create_non_racy_file three &&
        git update-index --add three &&
        git ls-files --stage >ls-files.actual &&
        cat >ls-files.expect <<-EOF &&
@@ -253,9 +263,9 @@ test_expect_success 'set core.splitIndex config variable to false' '
        test_cmp expect actual
 '
 
-test_expect_success 'set core.splitIndex config variable to true' '
+test_expect_success 'set core.splitIndex config variable back to true' '
        git config core.splitIndex true &&
-       : >three &&
+       create_non_racy_file three &&
        git update-index --add three &&
        BASE=$(test-tool dump-split-index .git/index | grep "^base") &&
        test-tool dump-split-index .git/index | sed "/^own/d" >actual &&
@@ -265,7 +275,7 @@ test_expect_success 'set core.splitIndex config variable to true' '
        deletions:
        EOF
        test_cmp expect actual &&
-       : >four &&
+       create_non_racy_file four &&
        git update-index --add four &&
        test-tool dump-split-index .git/index | sed "/^own/d" >actual &&
        cat >expect <<-EOF &&
@@ -279,7 +289,7 @@ test_expect_success 'set core.splitIndex config variable to true' '
 
 test_expect_success 'check behavior with splitIndex.maxPercentChange unset' '
        git config --unset splitIndex.maxPercentChange &&
-       : >five &&
+       create_non_racy_file five &&
        git update-index --add five &&
        BASE=$(test-tool dump-split-index .git/index | grep "^base") &&
        test-tool dump-split-index .git/index | sed "/^own/d" >actual &&
@@ -289,7 +299,7 @@ test_expect_success 'check behavior with splitIndex.maxPercentChange unset' '
        deletions:
        EOF
        test_cmp expect actual &&
-       : >six &&
+       create_non_racy_file six &&
        git update-index --add six &&
        test-tool dump-split-index .git/index | sed "/^own/d" >actual &&
        cat >expect <<-EOF &&
@@ -303,7 +313,7 @@ test_expect_success 'check behavior with splitIndex.maxPercentChange unset' '
 
 test_expect_success 'check splitIndex.maxPercentChange set to 0' '
        git config splitIndex.maxPercentChange 0 &&
-       : >seven &&
+       create_non_racy_file seven &&
        git update-index --add seven &&
        BASE=$(test-tool dump-split-index .git/index | grep "^base") &&
        test-tool dump-split-index .git/index | sed "/^own/d" >actual &&
@@ -313,7 +323,7 @@ test_expect_success 'check splitIndex.maxPercentChange set to 0' '
        deletions:
        EOF
        test_cmp expect actual &&
-       : >eight &&
+       create_non_racy_file eight &&
        git update-index --add eight &&
        BASE=$(test-tool dump-split-index .git/index | grep "^base") &&
        test-tool dump-split-index .git/index | sed "/^own/d" >actual &&
@@ -326,17 +336,17 @@ test_expect_success 'check splitIndex.maxPercentChange set to 0' '
 '
 
 test_expect_success 'shared index files expire after 2 weeks by default' '
-       : >ten &&
+       create_non_racy_file ten &&
        git update-index --add ten &&
        test $(ls .git/sharedindex.* | wc -l) -gt 2 &&
        just_under_2_weeks_ago=$((5-14*86400)) &&
        test-tool chmtime =$just_under_2_weeks_ago .git/sharedindex.* &&
-       : >eleven &&
+       create_non_racy_file eleven &&
        git update-index --add eleven &&
        test $(ls .git/sharedindex.* | wc -l) -gt 2 &&
        just_over_2_weeks_ago=$((-1-14*86400)) &&
        test-tool chmtime =$just_over_2_weeks_ago .git/sharedindex.* &&
-       : >twelve &&
+       create_non_racy_file twelve &&
        git update-index --add twelve &&
        test $(ls .git/sharedindex.* | wc -l) -le 2
 '
@@ -344,12 +354,12 @@ test_expect_success 'shared index files expire after 2 weeks by default' '
 test_expect_success 'check splitIndex.sharedIndexExpire set to 16 days' '
        git config splitIndex.sharedIndexExpire "16.days.ago" &&
        test-tool chmtime =$just_over_2_weeks_ago .git/sharedindex.* &&
-       : >thirteen &&
+       create_non_racy_file thirteen &&
        git update-index --add thirteen &&
        test $(ls .git/sharedindex.* | wc -l) -gt 2 &&
        just_over_16_days_ago=$((-1-16*86400)) &&
        test-tool chmtime =$just_over_16_days_ago .git/sharedindex.* &&
-       : >fourteen &&
+       create_non_racy_file fourteen &&
        git update-index --add fourteen &&
        test $(ls .git/sharedindex.* | wc -l) -le 2
 '
@@ -358,13 +368,13 @@ test_expect_success 'check splitIndex.sharedIndexExpire set to "never" and "now"
        git config splitIndex.sharedIndexExpire never &&
        just_10_years_ago=$((-365*10*86400)) &&
        test-tool chmtime =$just_10_years_ago .git/sharedindex.* &&
-       : >fifteen &&
+       create_non_racy_file fifteen &&
        git update-index --add fifteen &&
        test $(ls .git/sharedindex.* | wc -l) -gt 2 &&
        git config splitIndex.sharedIndexExpire now &&
        just_1_second_ago=-1 &&
        test-tool chmtime =$just_1_second_ago .git/sharedindex.* &&
-       : >sixteen &&
+       create_non_racy_file sixteen &&
        git update-index --add sixteen &&
        test $(ls .git/sharedindex.* | wc -l) -le 2
 '
@@ -379,7 +389,7 @@ do
                # Create one new shared index file
                git config core.sharedrepository "$mode" &&
                git config core.splitIndex true &&
-               : >one &&
+               create_non_racy_file one &&
                git update-index --add one &&
                echo "$modebits" >expect &&
                test_modebits .git/index >actual &&
diff --git a/t/t1701-racy-split-index.sh b/t/t1701-racy-split-index.sh
new file mode 100755 (executable)
index 0000000..5dc221e
--- /dev/null
@@ -0,0 +1,214 @@
+#!/bin/sh
+
+# This test can give false success if your machine is sufficiently
+# slow or all trials happened to happen on second boundaries.
+
+test_description='racy split index'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+       # Only split the index when the test explicitly says so.
+       sane_unset GIT_TEST_SPLIT_INDEX &&
+       git config splitIndex.maxPercentChange 100 &&
+
+       echo "cached content" >racy-file &&
+       git add racy-file &&
+       git commit -m initial &&
+
+       echo something >other-file &&
+       # No raciness with this file.
+       test-tool chmtime =-20 other-file &&
+
+       echo "+cached content" >expect
+'
+
+check_cached_diff () {
+       git diff-index --patch --cached $EMPTY_TREE racy-file >diff &&
+       tail -1 diff >actual &&
+       test_cmp expect actual
+}
+
+trials="0 1 2 3 4"
+for trial in $trials
+do
+       test_expect_success "split the index while adding a racily clean file #$trial" '
+               rm -f .git/index .git/sharedindex.* &&
+
+               # The next three commands must be run within the same
+               # second (so both writes to racy-file result in the same
+               # mtime) to create the interesting racy situation.
+               echo "cached content" >racy-file &&
+
+               # Update and split the index.  The cache entry of
+               # racy-file will be stored only in the shared index.
+               git update-index --split-index --add racy-file &&
+
+               # File size must stay the same.
+               echo "dirty worktree" >racy-file &&
+
+               # Subsequent git commands should notice that racy-file
+               # and the split index have the same mtime, and check
+               # the content of the file to see if it is actually
+               # clean.
+               check_cached_diff
+       '
+done
+
+for trial in $trials
+do
+       test_expect_success "add a racily clean file to an already split index #$trial" '
+               rm -f .git/index .git/sharedindex.* &&
+
+               git update-index --split-index &&
+
+               # The next three commands must be run within the same
+               # second.
+               echo "cached content" >racy-file &&
+
+               # Update the split index.  The cache entry of racy-file
+               # will be stored only in the split index.
+               git update-index --add racy-file &&
+
+               # File size must stay the same.
+               echo "dirty worktree" >racy-file &&
+
+               # Subsequent git commands should notice that racy-file
+               # and the split index have the same mtime, and check
+               # the content of the file to see if it is actually
+               # clean.
+               check_cached_diff
+       '
+done
+
+for trial in $trials
+do
+       test_expect_success "split the index when the index contains a racily clean cache entry #$trial" '
+               rm -f .git/index .git/sharedindex.* &&
+
+               # The next three commands must be run within the same
+               # second.
+               echo "cached content" >racy-file &&
+
+               git update-index --add racy-file &&
+
+               # File size must stay the same.
+               echo "dirty worktree" >racy-file &&
+
+               # Now wait a bit to ensure that the split index written
+               # below will get a more recent mtime than racy-file.
+               sleep 1 &&
+
+               # Update and split the index when the index contains
+               # the racily clean cache entry of racy-file.
+               # A corresponding replacement cache entry with smudged
+               # stat data should be added to the new split index.
+               git update-index --split-index --add other-file &&
+
+               # Subsequent git commands should notice the smudged
+               # stat data in the replacement cache entry and that it
+               # doesnt match with the file the worktree.
+               check_cached_diff
+       '
+done
+
+for trial in $trials
+do
+       test_expect_success "update the split index when it contains a new racily clean cache entry #$trial" '
+               rm -f .git/index .git/sharedindex.* &&
+
+               git update-index --split-index &&
+
+               # The next three commands must be run within the same
+               # second.
+               echo "cached content" >racy-file &&
+
+               # Update the split index.  The cache entry of racy-file
+               # will be stored only in the split index.
+               git update-index --add racy-file &&
+
+               # File size must stay the same.
+               echo "dirty worktree" >racy-file &&
+
+               # Now wait a bit to ensure that the split index written
+               # below will get a more recent mtime than racy-file.
+               sleep 1 &&
+
+               # Update the split index when the racily clean cache
+               # entry of racy-file is only stored in the split index.
+               # An updated cache entry with smudged stat data should
+               # be added to the new split index.
+               git update-index --add other-file &&
+
+               # Subsequent git commands should notice the smudged
+               # stat data.
+               check_cached_diff
+       '
+done
+
+for trial in $trials
+do
+       test_expect_success "update the split index when a racily clean cache entry is stored only in the shared index #$trial" '
+               rm -f .git/index .git/sharedindex.* &&
+
+               # The next three commands must be run within the same
+               # second.
+               echo "cached content" >racy-file &&
+
+               # Update and split the index.  The cache entry of
+               # racy-file will be stored only in the shared index.
+               git update-index --split-index --add racy-file &&
+
+               # File size must stay the same.
+               echo "dirty worktree" >racy-file &&
+
+               # Now wait a bit to ensure that the split index written
+               # below will get a more recent mtime than racy-file.
+               sleep 1 &&
+
+               # Update the split index when the racily clean cache
+               # entry of racy-file is only stored in the shared index.
+               # A corresponding replacement cache entry with smudged
+               # stat data should be added to the new split index.
+               git update-index --add other-file &&
+
+               # Subsequent git commands should notice the smudged
+               # stat data.
+               check_cached_diff
+       '
+done
+
+for trial in $trials
+do
+       test_expect_success "update the split index after unpack trees() copied a racily clean cache entry from the shared index #$trial" '
+               rm -f .git/index .git/sharedindex.* &&
+
+               # The next three commands must be run within the same
+               # second.
+               echo "cached content" >racy-file &&
+
+               # Update and split the index.  The cache entry of
+               # racy-file will be stored only in the shared index.
+               git update-index --split-index --add racy-file &&
+
+               # File size must stay the same.
+               echo "dirty worktree" >racy-file &&
+
+               # Now wait a bit to ensure that the split index written
+               # below will get a more recent mtime than racy-file.
+               sleep 1 &&
+
+               # Update the split index after unpack_trees() copied the
+               # racily clean cache entry of racy-file from the shared
+               # index.  A corresponding replacement cache entry
+               # with smudged stat data should be added to the new
+               # split index.
+               git read-tree -m HEAD &&
+
+               # Subsequent git commands should notice the smudged
+               # stat data.
+               check_cached_diff
+       '
+done
+
+test_done
index 2237c7f..fb4c13a 100755 (executable)
@@ -142,4 +142,9 @@ test_expect_success 'changed message' '
        test_cmp expected actual
 '
 
+test_expect_success 'no commits on one side' '
+       git commit --amend -m "new message" &&
+       git range-diff master HEAD@{1} HEAD
+'
+
 test_done
index 86bba5e..0075ac5 100755 (executable)
@@ -114,7 +114,7 @@ test_expect_success 'rebase -i with exec allows git commands in subdirs' '
        git checkout master &&
        mkdir subdir && (cd subdir &&
        set_fake_editor &&
-       FAKE_LINES="1 exec_cd_subdir_&&_git_rev-parse_--is-inside-work-tree" \
+       FAKE_LINES="1 x_cd_subdir_&&_git_rev-parse_--is-inside-work-tree" \
                git rebase -i HEAD^
        )
 '
@@ -515,7 +515,7 @@ test_expect_success 'squash works as expected' '
        git checkout -b squash-works no-conflict-branch &&
        one=$(git rev-parse HEAD~3) &&
        set_fake_editor &&
-       FAKE_LINES="1 squash 3 2" EXPECT_HEADER_COUNT=2 \
+       FAKE_LINES="1 s 3 2" EXPECT_HEADER_COUNT=2 \
                git rebase -i HEAD~3 &&
        test $one = $(git rev-parse HEAD~2)
 '
@@ -569,16 +569,15 @@ test_expect_success '--continue tries to commit, even for "edit"' '
 '
 
 test_expect_success 'aborted --continue does not squash commits after "edit"' '
-       test_when_finished "git rebase --abort" &&
        old=$(git rev-parse HEAD) &&
        test_tick &&
        set_fake_editor &&
        FAKE_LINES="edit 1" git rebase -i HEAD^ &&
        echo "edited again" > file7 &&
        git add file7 &&
-       echo all the things >>conflict &&
-       test_must_fail git rebase --continue &&
-       test $old = $(git rev-parse HEAD)
+       test_must_fail env FAKE_COMMIT_MESSAGE=" " git rebase --continue &&
+       test $old = $(git rev-parse HEAD) &&
+       git rebase --abort
 '
 
 test_expect_success 'auto-amend only edited commits after "edit"' '
@@ -749,7 +748,7 @@ test_expect_success 'reword' '
        git show HEAD^ | grep "D changed" &&
        FAKE_LINES="reword 1 2 3 4" FAKE_COMMIT_MESSAGE="B changed" git rebase -i A &&
        git show HEAD~3 | grep "B changed" &&
-       FAKE_LINES="1 reword 2 3 4" FAKE_COMMIT_MESSAGE="C changed" git rebase -i A &&
+       FAKE_LINES="1 r 2 pick 3 p 4" FAKE_COMMIT_MESSAGE="C changed" git rebase -i A &&
        git show HEAD~2 | grep "C changed"
 '
 
@@ -775,7 +774,7 @@ test_expect_success 'rebase -i can copy notes over a fixup' '
        git reset --hard n3 &&
        git notes add -m"an earlier note" n2 &&
        set_fake_editor &&
-       GIT_NOTES_REWRITE_MODE=concatenate FAKE_LINES="1 fixup 2" git rebase -i n1 &&
+       GIT_NOTES_REWRITE_MODE=concatenate FAKE_LINES="1 f 2" git rebase -i n1 &&
        git notes show > output &&
        test_cmp expect output
 '
@@ -1252,7 +1251,7 @@ rebase_setup_and_clean () {
 test_expect_success 'drop' '
        rebase_setup_and_clean drop-test &&
        set_fake_editor &&
-       FAKE_LINES="1 drop 2 3 drop 4 5" git rebase -i --root &&
+       FAKE_LINES="1 drop 2 3 d 4 5" git rebase -i --root &&
        test E = $(git cat-file commit HEAD | sed -ne \$p) &&
        test C = $(git cat-file commit HEAD^ | sed -ne \$p) &&
        test A = $(git cat-file commit HEAD^^ | sed -ne \$p)
index da94ddd..860e63e 100755 (executable)
@@ -83,7 +83,7 @@ test_expect_success 'rebase -m commit with empty message' '
 test_expect_success 'rebase -i commit with empty message' '
        git checkout diff-in-message &&
        set_fake_editor &&
-       env FAKE_COMMIT_MESSAGE=" " FAKE_LINES="reword 1" \
+       test_must_fail env FAKE_COMMIT_MESSAGE=" " FAKE_LINES="reword 1" \
                git rebase -i HEAD^
 '
 
index e364c12..13f5688 100755 (executable)
@@ -330,4 +330,23 @@ test_expect_success 'wrapped original subject' '
        test $base = $parent
 '
 
+test_expect_success 'abort last squash' '
+       test_when_finished "test_might_fail git rebase --abort" &&
+       test_when_finished "git checkout master" &&
+
+       git checkout -b some-squashes &&
+       git commit --allow-empty -m first &&
+       git commit --allow-empty --squash HEAD &&
+       git commit --allow-empty -m second &&
+       git commit --allow-empty --squash HEAD &&
+
+       test_must_fail git -c core.editor="grep -q ^pick" \
+               rebase -ki --autosquash HEAD~4 &&
+       : do not finish the squash, but resolve it manually &&
+       git commit --allow-empty --amend -m edited-first &&
+       git rebase --skip &&
+       git show >actual &&
+       ! grep first actual
+'
+
 test_done
index fbdc47c..5f911bb 100755 (executable)
@@ -11,17 +11,14 @@ test_expect_success setup '
        test_tick &&
        git commit -m "first" &&
 
-       git checkout -b empty-branch &&
-       test_tick &&
-       git commit --allow-empty -m "empty" &&
-
+       git checkout -b empty-message-branch &&
        echo third >> file1 &&
        git add file1 &&
        test_tick &&
        git commit --allow-empty-message -m "" &&
 
        git checkout master &&
-       git checkout -b empty-branch2 &&
+       git checkout -b empty-change-branch &&
        test_tick &&
        git commit --allow-empty -m "empty"
 
@@ -29,7 +26,7 @@ test_expect_success setup '
 
 test_expect_success 'cherry-pick an empty commit' '
        git checkout master &&
-       test_expect_code 1 git cherry-pick empty-branch^
+       test_expect_code 1 git cherry-pick empty-change-branch
 '
 
 test_expect_success 'index lockfile was removed' '
@@ -37,8 +34,9 @@ test_expect_success 'index lockfile was removed' '
 '
 
 test_expect_success 'cherry-pick a commit with an empty message' '
+       test_when_finished "git reset --hard empty-message-branch~1" &&
        git checkout master &&
-       test_expect_code 1 git cherry-pick empty-branch
+       git cherry-pick empty-message-branch
 '
 
 test_expect_success 'index lockfile was removed' '
@@ -47,7 +45,7 @@ test_expect_success 'index lockfile was removed' '
 
 test_expect_success 'cherry-pick a commit with an empty message with --allow-empty-message' '
        git checkout -f master &&
-       git cherry-pick --allow-empty-message empty-branch
+       git cherry-pick --allow-empty-message empty-message-branch
 '
 
 test_expect_success 'cherry pick an empty non-ff commit without --allow-empty' '
@@ -55,12 +53,12 @@ test_expect_success 'cherry pick an empty non-ff commit without --allow-empty' '
        echo fourth >>file2 &&
        git add file2 &&
        git commit -m "fourth" &&
-       test_must_fail git cherry-pick empty-branch2
+       test_must_fail git cherry-pick empty-change-branch
 '
 
 test_expect_success 'cherry pick an empty non-ff commit with --allow-empty' '
        git checkout master &&
-       git cherry-pick --allow-empty empty-branch2
+       git cherry-pick --allow-empty empty-change-branch
 '
 
 test_expect_success 'cherry pick with --keep-redundant-commits' '
index 609fbfd..65dfbc0 100755 (executable)
@@ -540,7 +540,7 @@ test_expect_success 'add -p does not expand argument lists' '
        # update it, but we want to be sure that our "." pathspec
        # was not expanded into the argument list of any command.
        # So look only for "not-changed".
-       ! grep not-changed trace.out
+       ! grep -E "^trace: (built-in|exec|run_command): .*not-changed" trace.out
 '
 
 test_expect_success 'hunk-editing handles custom comment char' '
index 453e6c3..6e0dd6f 100755 (executable)
@@ -127,4 +127,14 @@ test_expect_success 'diff --no-index from repo subdir respects config (implicit)
        test_cmp expect actual.head
 '
 
+test_expect_success 'diff --no-index from repo subdir with absolute paths' '
+       cat <<-EOF >expect &&
+       1       1       $(pwd)/non/git/{a => b}
+       EOF
+       test_expect_code 1 \
+               git -C repo/sub diff --numstat \
+               "$(pwd)/non/git/a" "$(pwd)/non/git/b" >actual &&
+       test_cmp expect actual
+'
+
 test_done
index 65da74c..313222d 100755 (executable)
@@ -577,4 +577,33 @@ test_expect_success 'multiple identical conflicts' '
        count_pre_post 0 0
 '
 
+test_expect_success 'setup simple stage 1 handling' '
+       test_create_repo stage_1_handling &&
+       (
+               cd stage_1_handling &&
+
+               test_seq 1 10 >original &&
+               git add original &&
+               git commit -m original &&
+
+               git checkout -b A master &&
+               git mv original A &&
+               git commit -m "rename to A" &&
+
+               git checkout -b B master &&
+               git mv original B &&
+               git commit -m "rename to B"
+       )
+'
+
+test_expect_success 'test simple stage 1 handling' '
+       (
+               cd stage_1_handling &&
+
+               git config rerere.enabled true &&
+               git checkout A^0 &&
+               test_must_fail git merge B^0
+       )
+'
+
 test_done
index 153a506..819c24d 100755 (executable)
@@ -1703,4 +1703,8 @@ test_expect_success 'log --source paints symmetric ranges' '
        test_cmp expect actual
 '
 
+test_expect_success '--exclude-promisor-objects does not BUG-crash' '
+       test_must_fail git log --exclude-promisor-objects source-a
+'
+
 test_done
index 2052cad..978a8a6 100755 (executable)
@@ -598,4 +598,27 @@ test_expect_success ':only and :unfold work together' '
        test_cmp expect actual
 '
 
+test_expect_success 'trailer parsing not fooled by --- line' '
+       git commit --allow-empty -F - <<-\EOF &&
+       this is the subject
+
+       This is the body. The message has a "---" line which would confuse a
+       message+patch parser. But here we know we have only a commit message,
+       so we get it right.
+
+       trailer: wrong
+       ---
+       This is more body.
+
+       trailer: right
+       EOF
+
+       {
+               echo "trailer: right" &&
+               echo
+       } >expect &&
+       git log --no-walk --format="%(trailers)" >actual &&
+       test_cmp expect actual
+'
+
 test_done
diff --git a/t/t4214-log-graph-octopus.sh b/t/t4214-log-graph-octopus.sh
new file mode 100755 (executable)
index 0000000..dab96c8
--- /dev/null
@@ -0,0 +1,102 @@
+#!/bin/sh
+
+test_description='git log --graph of skewed left octopus merge.'
+
+. ./test-lib.sh
+
+test_expect_success 'set up merge history' '
+       cat >expect.uncolored <<-\EOF &&
+       * left
+       | *---.   octopus-merge
+       | |\ \ \
+       |/ / / /
+       | | | * 4
+       | | * | 3
+       | | |/
+       | * | 2
+       | |/
+       * | 1
+       |/
+       * initial
+       EOF
+       cat >expect.colors <<-\EOF &&
+       * left
+       <RED>|<RESET> *<BLUE>-<RESET><BLUE>-<RESET><MAGENTA>-<RESET><MAGENTA>.<RESET>   octopus-merge
+       <RED>|<RESET> <RED>|<RESET><YELLOW>\<RESET> <BLUE>\<RESET> <MAGENTA>\<RESET>
+       <RED>|<RESET><RED>/<RESET> <YELLOW>/<RESET> <BLUE>/<RESET> <MAGENTA>/<RESET>
+       <RED>|<RESET> <YELLOW>|<RESET> <BLUE>|<RESET> * 4
+       <RED>|<RESET> <YELLOW>|<RESET> * <MAGENTA>|<RESET> 3
+       <RED>|<RESET> <YELLOW>|<RESET> <MAGENTA>|<RESET><MAGENTA>/<RESET>
+       <RED>|<RESET> * <MAGENTA>|<RESET> 2
+       <RED>|<RESET> <MAGENTA>|<RESET><MAGENTA>/<RESET>
+       * <MAGENTA>|<RESET> 1
+       <MAGENTA>|<RESET><MAGENTA>/<RESET>
+       * initial
+       EOF
+       test_commit initial &&
+       for i in 1 2 3 4 ; do
+               git checkout master -b $i || return $?
+               # Make tag name different from branch name, to avoid
+               # ambiguity error when calling checkout.
+               test_commit $i $i $i tag$i || return $?
+       done &&
+       git checkout 1 -b merge &&
+       test_tick &&
+       git merge -m octopus-merge 1 2 3 4 &&
+       git checkout 1 -b L &&
+       test_commit left
+'
+
+test_expect_success 'log --graph with tricky octopus merge with colors' '
+       test_config log.graphColors red,green,yellow,blue,magenta,cyan &&
+       git log --color=always --graph --date-order --pretty=tformat:%s --all >actual.colors.raw &&
+       test_decode_color <actual.colors.raw | sed "s/ *\$//" >actual.colors &&
+       test_cmp expect.colors actual.colors
+'
+
+test_expect_success 'log --graph with tricky octopus merge, no color' '
+       git log --color=never --graph --date-order --pretty=tformat:%s --all >actual.raw &&
+       sed "s/ *\$//" actual.raw >actual &&
+       test_cmp expect.uncolored actual
+'
+
+# Repeat the previous two tests with "normal" octopus merge (i.e.,
+# without the first parent skewing to the "left" branch column).
+
+test_expect_success 'log --graph with normal octopus merge, no color' '
+       cat >expect.uncolored <<-\EOF &&
+       *---.   octopus-merge
+       |\ \ \
+       | | | * 4
+       | | * | 3
+       | | |/
+       | * | 2
+       | |/
+       * | 1
+       |/
+       * initial
+       EOF
+       git log --color=never --graph --date-order --pretty=tformat:%s merge >actual.raw &&
+       sed "s/ *\$//" actual.raw >actual &&
+       test_cmp expect.uncolored actual
+'
+
+test_expect_success 'log --graph with normal octopus merge with colors' '
+       cat >expect.colors <<-\EOF &&
+       *<YELLOW>-<RESET><YELLOW>-<RESET><BLUE>-<RESET><BLUE>.<RESET>   octopus-merge
+       <RED>|<RESET><GREEN>\<RESET> <YELLOW>\<RESET> <BLUE>\<RESET>
+       <RED>|<RESET> <GREEN>|<RESET> <YELLOW>|<RESET> * 4
+       <RED>|<RESET> <GREEN>|<RESET> * <BLUE>|<RESET> 3
+       <RED>|<RESET> <GREEN>|<RESET> <BLUE>|<RESET><BLUE>/<RESET>
+       <RED>|<RESET> * <BLUE>|<RESET> 2
+       <RED>|<RESET> <BLUE>|<RESET><BLUE>/<RESET>
+       * <BLUE>|<RESET> 1
+       <BLUE>|<RESET><BLUE>/<RESET>
+       * initial
+       EOF
+       test_config log.graphColors red,green,yellow,blue,magenta,cyan &&
+       git log --color=always --graph --date-order --pretty=tformat:%s merge >actual.colors.raw &&
+       test_decode_color <actual.colors.raw | sed "s/ *\$//" >actual.colors &&
+       test_cmp expect.colors actual.colors
+'
+test_done
index 0c500f7..2799969 100755 (executable)
@@ -259,6 +259,66 @@ test_expect_success 'check that gc computes commit-graph' '
        test_cmp_bin commit-graph-after-gc $objdir/info/commit-graph
 '
 
+test_expect_success 'replace-objects invalidates commit-graph' '
+       cd "$TRASH_DIRECTORY" &&
+       test_when_finished rm -rf replace &&
+       git clone full replace &&
+       (
+               cd replace &&
+               git commit-graph write --reachable &&
+               test_path_is_file .git/objects/info/commit-graph &&
+               git replace HEAD~1 HEAD~2 &&
+               git -c core.commitGraph=false log >expect &&
+               git -c core.commitGraph=true log >actual &&
+               test_cmp expect actual &&
+               git commit-graph write --reachable &&
+               git -c core.commitGraph=false --no-replace-objects log >expect &&
+               git -c core.commitGraph=true --no-replace-objects log >actual &&
+               test_cmp expect actual &&
+               rm -rf .git/objects/info/commit-graph &&
+               git commit-graph write --reachable &&
+               test_path_is_file .git/objects/info/commit-graph
+       )
+'
+
+test_expect_success 'commit grafts invalidate commit-graph' '
+       cd "$TRASH_DIRECTORY" &&
+       test_when_finished rm -rf graft &&
+       git clone full graft &&
+       (
+               cd graft &&
+               git commit-graph write --reachable &&
+               test_path_is_file .git/objects/info/commit-graph &&
+               H1=$(git rev-parse --verify HEAD~1) &&
+               H3=$(git rev-parse --verify HEAD~3) &&
+               echo "$H1 $H3" >.git/info/grafts &&
+               git -c core.commitGraph=false log >expect &&
+               git -c core.commitGraph=true log >actual &&
+               test_cmp expect actual &&
+               git commit-graph write --reachable &&
+               git -c core.commitGraph=false --no-replace-objects log >expect &&
+               git -c core.commitGraph=true --no-replace-objects log >actual &&
+               test_cmp expect actual &&
+               rm -rf .git/objects/info/commit-graph &&
+               git commit-graph write --reachable &&
+               test_path_is_missing .git/objects/info/commit-graph
+       )
+'
+
+test_expect_success 'replace-objects invalidates commit-graph' '
+       cd "$TRASH_DIRECTORY" &&
+       test_when_finished rm -rf shallow &&
+       git clone --depth 2 "file://$TRASH_DIRECTORY/full" shallow &&
+       (
+               cd shallow &&
+               git commit-graph write --reachable &&
+               test_path_is_missing .git/objects/info/commit-graph &&
+               git fetch origin --unshallow &&
+               git commit-graph write --reachable &&
+               test_path_is_file .git/objects/info/commit-graph
+       )
+'
+
 # the verify tests below expect the commit-graph to contain
 # exactly the commits reachable from the commits/8 branch.
 # If the file changes the set of commits in the list, then the
diff --git a/t/t5321-pack-large-objects.sh b/t/t5321-pack-large-objects.sh
new file mode 100755 (executable)
index 0000000..a75eab8
--- /dev/null
@@ -0,0 +1,32 @@
+#!/bin/sh
+#
+# Copyright (c) 2018 Johannes Schindelin
+#
+
+test_description='git pack-object with "large" deltas
+
+'
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-pack.sh
+
+# Two similar-ish objects that we have computed deltas between.
+A=01d7713666f4de822776c7622c10f1b07de280dc
+B=e68fe8129b546b101aee9510c5328e7f21ca1d18
+
+test_expect_success 'setup' '
+       clear_packs &&
+       {
+               pack_header 2 &&
+               pack_obj $A $B &&
+               pack_obj $B
+       } >ab.pack &&
+       pack_trailer ab.pack &&
+       git index-pack --stdin <ab.pack
+'
+
+test_expect_success 'repack large deltas' '
+       printf "%s\\n" $A $B |
+       GIT_TEST_OE_DELTA_SIZE=2 git pack-objects tmp-pack
+'
+
+test_done
index 241e6a3..d2a2cdd 100755 (executable)
@@ -145,7 +145,7 @@ test_expect_success 'remove remote protects local branches' '
 test_expect_success 'remove errors out early when deleting non-existent branch' '
        (
                cd test &&
-               echo "fatal: No such remote: foo" >expect &&
+               echo "fatal: No such remote: '\''foo'\''" >expect &&
                test_must_fail git remote rm foo 2>actual &&
                test_i18ncmp expect actual
        )
@@ -173,7 +173,7 @@ test_expect_success 'remove remote with a branch without configured merge' '
 test_expect_success 'rename errors out early when deleting non-existent branch' '
        (
                cd test &&
-               echo "fatal: No such remote: foo" >expect &&
+               echo "fatal: No such remote: '\''foo'\''" >expect &&
                test_must_fail git remote rename foo bar 2>actual &&
                test_i18ncmp expect actual
        )
index 539c25a..bb0a365 100755 (executable)
@@ -1552,7 +1552,13 @@ test_expect_success 'receive.denyCurrentBranch = updateInstead' '
                test $(git -C .. rev-parse master) = $(git rev-parse HEAD) &&
                git diff --quiet &&
                git diff --cached --quiet
-       )
+       ) &&
+
+       # (6) updateInstead intervened by fast-forward check
+       test_must_fail git push void master^:master &&
+       test $(git -C void rev-parse HEAD) = $(git rev-parse master) &&
+       git -C void diff --quiet &&
+       git -C void diff --cached --quiet
 '
 
 test_expect_success 'updateInstead with push-to-checkout hook' '
index 7045685..6faf17e 100755 (executable)
@@ -186,6 +186,33 @@ EOF
        test_cmp expect actual
 '
 
+test_expect_success '.git/shallow is edited by repack' '
+       git init shallow-server &&
+       test_commit -C shallow-server A &&
+       test_commit -C shallow-server B &&
+       git -C shallow-server checkout -b branch &&
+       test_commit -C shallow-server C &&
+       test_commit -C shallow-server E &&
+       test_commit -C shallow-server D &&
+       d="$(git -C shallow-server rev-parse --verify D^0)" &&
+       git -C shallow-server checkout master &&
+
+       git clone --depth=1 --no-tags --no-single-branch \
+               "file://$PWD/shallow-server" shallow-client &&
+
+       : now remove the branch and fetch with prune &&
+       git -C shallow-server branch -D branch &&
+       git -C shallow-client fetch --prune --depth=1 \
+               origin "+refs/heads/*:refs/remotes/origin/*" &&
+       git -C shallow-client repack -adfl &&
+       test_must_fail git -C shallow-client rev-parse --verify $d^0 &&
+       ! grep $d shallow-client/.git/shallow &&
+
+       git -C shallow-server branch branch-orig $d &&
+       git -C shallow-client fetch --prune --depth=2 \
+               origin "+refs/heads/*:refs/remotes/origin/*"
+'
+
 . "$TEST_DIRECTORY"/lib-httpd.sh
 start_httpd
 
index 771f36f..3dc8f8e 100755 (executable)
@@ -23,26 +23,26 @@ test_expect_success 'create http-accessible bare repository' '
 
 setup_askpass_helper
 
-cat >exp <<EOF
-> GET /smart/repo.git/info/refs?service=git-upload-pack HTTP/1.1
-> Accept: */*
-> Accept-Encoding: ENCODINGS
-> Pragma: no-cache
-< HTTP/1.1 200 OK
-< Pragma: no-cache
-< Cache-Control: no-cache, max-age=0, must-revalidate
-< Content-Type: application/x-git-upload-pack-advertisement
-> POST /smart/repo.git/git-upload-pack HTTP/1.1
-> Accept-Encoding: ENCODINGS
-> Content-Type: application/x-git-upload-pack-request
-> Accept: application/x-git-upload-pack-result
-> Content-Length: xxx
-< HTTP/1.1 200 OK
-< Pragma: no-cache
-< Cache-Control: no-cache, max-age=0, must-revalidate
-< Content-Type: application/x-git-upload-pack-result
-EOF
 test_expect_success 'clone http repository' '
+       cat >exp <<-\EOF &&
+       > GET /smart/repo.git/info/refs?service=git-upload-pack HTTP/1.1
+       > Accept: */*
+       > Accept-Encoding: ENCODINGS
+       > Pragma: no-cache
+       < HTTP/1.1 200 OK
+       < Pragma: no-cache
+       < Cache-Control: no-cache, max-age=0, must-revalidate
+       < Content-Type: application/x-git-upload-pack-advertisement
+       > POST /smart/repo.git/git-upload-pack HTTP/1.1
+       > Accept-Encoding: ENCODINGS
+       > Content-Type: application/x-git-upload-pack-request
+       > Accept: application/x-git-upload-pack-result
+       > Content-Length: xxx
+       < HTTP/1.1 200 OK
+       < Pragma: no-cache
+       < Cache-Control: no-cache, max-age=0, must-revalidate
+       < Content-Type: application/x-git-upload-pack-result
+       EOF
        GIT_TRACE_CURL=true git clone --quiet $HTTPD_URL/smart/repo.git clone 2>err &&
        test_cmp file clone/file &&
        tr '\''\015'\'' Q <err |
@@ -96,13 +96,13 @@ test_expect_success 'fetch changes via http' '
        test_cmp file clone/file
 '
 
-cat >exp <<EOF
-GET  /smart/repo.git/info/refs?service=git-upload-pack HTTP/1.1 200
-POST /smart/repo.git/git-upload-pack HTTP/1.1 200
-GET  /smart/repo.git/info/refs?service=git-upload-pack HTTP/1.1 200
-POST /smart/repo.git/git-upload-pack HTTP/1.1 200
-EOF
 test_expect_success 'used upload-pack service' '
+       cat >exp <<-\EOF &&
+       GET  /smart/repo.git/info/refs?service=git-upload-pack HTTP/1.1 200
+       POST /smart/repo.git/git-upload-pack HTTP/1.1 200
+       GET  /smart/repo.git/info/refs?service=git-upload-pack HTTP/1.1 200
+       POST /smart/repo.git/git-upload-pack HTTP/1.1 200
+       EOF
        check_access_log exp
 '
 
@@ -203,19 +203,19 @@ test_expect_success 'dumb clone via http-backend respects namespace' '
        test_cmp expect actual
 '
 
-cat >cookies.txt <<EOF
-127.0.0.1      FALSE   /smart_cookies/ FALSE   0       othername       othervalue
-EOF
-cat >expect_cookies.txt <<EOF
-
-127.0.0.1      FALSE   /smart_cookies/ FALSE   0       othername       othervalue
-127.0.0.1      FALSE   /smart_cookies/repo.git/info/   FALSE   0       name    value
-EOF
 test_expect_success 'cookies stored in http.cookiefile when http.savecookies set' '
+       cat >cookies.txt <<-\EOF &&
+       127.0.0.1       FALSE   /smart_cookies/ FALSE   0       othername       othervalue
+       EOF
+       sort >expect_cookies.txt <<-\EOF &&
+
+       127.0.0.1       FALSE   /smart_cookies/ FALSE   0       othername       othervalue
+       127.0.0.1       FALSE   /smart_cookies/repo.git/info/   FALSE   0       name    value
+       EOF
        git config http.cookiefile cookies.txt &&
        git config http.savecookies true &&
        git ls-remote $HTTPD_URL/smart_cookies/repo.git master &&
-       tail -3 cookies.txt >cookies_tail.txt &&
+       tail -3 cookies.txt | sort >cookies_tail.txt &&
        test_cmp expect_cookies.txt cookies_tail.txt
 '
 
index 77b8cef..e436a73 100755 (executable)
@@ -166,7 +166,7 @@ test_expect_success 'fail if attr magic is used places not implemented' '
        # though, but git-add is convenient as it has its own internal pathspec
        # parsing.
        test_must_fail git add ":(attr:labelB)" 2>actual &&
-       test_i18ngrep "unsupported magic" actual
+       test_i18ngrep "magic not supported" actual
 '
 
 test_expect_success 'abort on giving invalid label on the command line' '
index 024f8c0..97bfbee 100755 (executable)
@@ -715,6 +715,29 @@ test_expect_success 'basic atom: head contents:trailers' '
        test_cmp expect actual.clean
 '
 
+test_expect_success 'trailer parsing not fooled by --- line' '
+       git commit --allow-empty -F - <<-\EOF &&
+       this is the subject
+
+       This is the body. The message has a "---" line which would confuse a
+       message+patch parser. But here we know we have only a commit message,
+       so we get it right.
+
+       trailer: wrong
+       ---
+       This is more body.
+
+       trailer: right
+       EOF
+
+       {
+               echo "trailer: right" &&
+               echo
+       } >expect &&
+       git for-each-ref --format="%(trailers)" refs/heads/master >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'Add symbolic ref for the following tests' '
        git symbolic-ref refs/heads/sym refs/heads/master
 '
index b2ca77b..5fcf281 100755 (executable)
@@ -112,7 +112,7 @@ do
 done
 
 test_expect_success 'editor with a space' '
-       echo "echo space >\$1" >"e space.sh" &&
+       echo "echo space >\"\$1\"" >"e space.sh" &&
        chmod a+x "e space.sh" &&
        GIT_EDITOR="./e\ space.sh" git commit --amend &&
        test space = "$(git show -s --pretty=format:%s)"
index 170b481..31ab608 100755 (executable)
@@ -359,4 +359,27 @@ test_expect_success 'new line found before status message in commit template' '
        test_i18ncmp expected-template editor-input
 '
 
+test_expect_success 'setup empty commit with unstaged rename and copy' '
+       test_create_repo unstaged_rename_and_copy &&
+       (
+               cd unstaged_rename_and_copy &&
+
+               echo content >orig &&
+               git add orig &&
+               test_commit orig &&
+
+               cp orig new_copy &&
+               mv orig new_rename &&
+               git add -N new_copy new_rename
+       )
+'
+
+test_expect_success 'check commit with unstaged rename and copy' '
+       (
+               cd unstaged_rename_and_copy &&
+
+               test_must_fail git -c diff.renames=copy commit
+       )
+'
+
 test_done
index 4cae928..1a6773e 100755 (executable)
@@ -517,6 +517,22 @@ Myfooter: x" &&
        test_cmp expected actual
 '
 
+test_expect_success 'signoff not confused by ---' '
+       cat >expected <<-EOF &&
+               subject
+
+               body
+               ---
+               these dashes confuse the parser!
+
+               Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>
+       EOF
+       # should be a noop, since we already signed
+       git commit --allow-empty --signoff -F expected &&
+       git log -1 --pretty=format:%B >actual &&
+       test_cmp expected actual
+'
+
 test_expect_success 'multiple -m' '
 
        >negative &&
index 164719d..c441861 100755 (executable)
@@ -1417,4 +1417,46 @@ test_expect_success 'unfold' '
        test_cmp expected actual
 '
 
+test_expect_success 'handling of --- lines in input' '
+       echo "real-trailer: just right" >expected &&
+
+       git interpret-trailers --parse >actual <<-\EOF &&
+       subject
+
+       body
+
+       not-a-trailer: too soon
+       ------ this is just a line in the commit message with a bunch of
+       ------ dashes; it does not have any syntactic meaning.
+
+       real-trailer: just right
+       ---
+       below the dashed line may be a patch, etc.
+
+       not-a-trailer: too late
+       EOF
+
+       test_cmp expected actual
+'
+
+test_expect_success 'suppress --- handling' '
+       echo "real-trailer: just right" >expected &&
+
+       git interpret-trailers --parse --no-divider >actual <<-\EOF &&
+       subject
+
+       This commit message has a "---" in it, but because we tell
+       interpret-trailers not to respect that, it has no effect.
+
+       not-a-trailer: too soon
+       ---
+
+       This is still the commit message body.
+
+       real-trailer: just right
+       EOF
+
+       test_cmp expected actual
+'
+
 test_done
index 380e1c1..eea048e 100755 (executable)
@@ -118,4 +118,8 @@ test_expect_success '--no-abbrev works like --abbrev=40' '
        check_abbrev 40 --no-abbrev
 '
 
+test_expect_success '--exclude-promisor-objects does not BUG-crash' '
+       test_must_fail git blame --exclude-promisor-objects one
+'
+
 test_done
index 44288cb..1373fd4 100644 (file)
@@ -67,7 +67,7 @@ case "$GIT_TEST_TEE_STARTED, $* " in
 done,*)
        # do not redirect again
        ;;
-*' --tee '*|*' --va'*|*' --verbose-log '*)
+*' --tee '*|*' --va'*|*' -V '*|*' --verbose-log '*)
        mkdir -p "$TEST_OUTPUT_DIRECTORY/test-results"
        BASE="$TEST_OUTPUT_DIRECTORY/test-results/$(basename "$0" .sh)"
 
@@ -285,7 +285,7 @@ do
                        echo >&2 "warning: ignoring -x; '$0' is untraceable without BASH_XTRACEFD"
                fi
                shift ;;
-       --verbose-log)
+       -V|--verbose-log)
                verbose_log=t
                shift ;;
        *)
index 139ecd9..d43ad8c 100644 (file)
@@ -279,7 +279,7 @@ int reopen_tempfile(struct tempfile *tempfile)
                BUG("reopen_tempfile called for an inactive object");
        if (0 <= tempfile->fd)
                BUG("reopen_tempfile called for an open object");
-       tempfile->fd = open(tempfile->filename.buf, O_WRONLY);
+       tempfile->fd = open(tempfile->filename.buf, O_WRONLY|O_TRUNC);
        return tempfile->fd;
 }
 
index 36434eb..61d8dc4 100644 (file)
@@ -236,8 +236,8 @@ extern int close_tempfile_gently(struct tempfile *tempfile);
  *   it (and nobody else) to inspect or even modify the file's
  *   contents.
  *
- * * `reopen_tempfile()` to reopen the temporary file. Make further
- *   updates to the contents.
+ * * `reopen_tempfile()` to reopen the temporary file, truncating the existing
+ *   contents. Write out the new contents.
  *
  * * `rename_tempfile()` to move the file to its permanent location.
  */
index 4e30946..0796f32 100644 (file)
--- a/trailer.c
+++ b/trailer.c
@@ -585,7 +585,7 @@ static const char *token_from_item(struct arg_item *item, char *tok)
        return item->conf.name;
 }
 
-static int token_matches_item(const char *tok, struct arg_item *item, int tok_len)
+static int token_matches_item(const char *tok, struct arg_item *item, size_t tok_len)
 {
        if (!strncasecmp(tok, item->conf.name, tok_len))
                return 1;
@@ -603,7 +603,7 @@ static int token_matches_item(const char *tok, struct arg_item *item, int tok_le
  * distinguished from the non-well-formed-line case (in which this function
  * returns -1) because some callers of this function need such a distinction.
  */
-static int find_separator(const char *line, const char *separators)
+static ssize_t find_separator(const char *line, const char *separators)
 {
        int whitespace_found = 0;
        const char *c;
@@ -630,10 +630,10 @@ static int find_separator(const char *line, const char *separators)
  */
 static void parse_trailer(struct strbuf *tok, struct strbuf *val,
                         const struct conf_info **conf, const char *trailer,
-                        int separator_pos)
+                        ssize_t separator_pos)
 {
        struct arg_item *item;
-       int tok_len;
+       size_t tok_len;
        struct list_head *pos;
 
        if (separator_pos != -1) {
@@ -721,7 +721,7 @@ static void process_command_line_args(struct list_head *arg_head,
        list_for_each(pos, new_trailer_head) {
                struct new_trailer_item *tr =
                        list_entry(pos, struct new_trailer_item, list);
-               int separator_pos = find_separator(tr->text, cl_separators);
+               ssize_t separator_pos = find_separator(tr->text, cl_separators);
 
                if (separator_pos == 0) {
                        struct strbuf sb = STRBUF_INIT;
@@ -763,9 +763,9 @@ static const char *next_line(const char *str)
 /*
  * Return the position of the start of the last line. If len is 0, return -1.
  */
-static int last_line(const char *buf, size_t len)
+static ssize_t last_line(const char *buf, size_t len)
 {
-       int i;
+       ssize_t i;
        if (len == 0)
                return -1;
        if (len == 1)
@@ -788,12 +788,14 @@ static int last_line(const char *buf, size_t len)
  * Return the position of the start of the patch or the length of str if there
  * is no patch in the message.
  */
-static int find_patch_start(const char *str)
+static size_t find_patch_start(const char *str)
 {
        const char *s;
 
        for (s = str; *s; s = next_line(s)) {
-               if (starts_with(s, "---"))
+               const char *v;
+
+               if (skip_prefix(s, "---", &v) && isspace(*v))
                        return s - str;
        }
 
@@ -804,10 +806,11 @@ static int find_patch_start(const char *str)
  * Return the position of the first trailer line or len if there are no
  * trailers.
  */
-static int find_trailer_start(const char *buf, size_t len)
+static size_t find_trailer_start(const char *buf, size_t len)
 {
        const char *s;
-       int end_of_title, l, only_spaces = 1;
+       ssize_t end_of_title, l;
+       int only_spaces = 1;
        int recognized_prefix = 0, trailer_lines = 0, non_trailer_lines = 0;
        /*
         * Number of possible continuation lines encountered. This will be
@@ -838,7 +841,7 @@ static int find_trailer_start(const char *buf, size_t len)
             l = last_line(buf, l)) {
                const char *bol = buf + l;
                const char **p;
-               int separator_pos;
+               ssize_t separator_pos;
 
                if (bol[0] == comment_line_char) {
                        non_trailer_lines += possible_continuation_lines;
@@ -899,14 +902,14 @@ continue_outer_loop:
 }
 
 /* Return the position of the end of the trailers. */
-static int find_trailer_end(const char *buf, size_t len)
+static size_t find_trailer_end(const char *buf, size_t len)
 {
        return len - ignore_non_trailer(buf, len);
 }
 
 static int ends_with_blank_line(const char *buf, size_t len)
 {
-       int ll = last_line(buf, len);
+       ssize_t ll = last_line(buf, len);
        if (ll < 0)
                return 0;
        return is_blank_line(buf + ll);
@@ -939,17 +942,17 @@ static void unfold_value(struct strbuf *val)
        strbuf_release(&out);
 }
 
-static int process_input_file(FILE *outfile,
-                             const char *str,
-                             struct list_head *head,
-                             const struct process_trailer_options *opts)
+static size_t process_input_file(FILE *outfile,
+                                const char *str,
+                                struct list_head *head,
+                                const struct process_trailer_options *opts)
 {
        struct trailer_info info;
        struct strbuf tok = STRBUF_INIT;
        struct strbuf val = STRBUF_INIT;
-       int i;
+       size_t i;
 
-       trailer_info_get(&info, str);
+       trailer_info_get(&info, str, opts);
 
        /* Print lines before the trailers as is */
        if (!opts->only_trailers)
@@ -1032,7 +1035,7 @@ void process_trailers(const char *file,
 {
        LIST_HEAD(head);
        struct strbuf sb = STRBUF_INIT;
-       int trailer_end;
+       size_t trailer_end;
        FILE *outfile = stdout;
 
        ensure_configured();
@@ -1066,7 +1069,8 @@ void process_trailers(const char *file,
        strbuf_release(&sb);
 }
 
-void trailer_info_get(struct trailer_info *info, const char *str)
+void trailer_info_get(struct trailer_info *info, const char *str,
+                     const struct process_trailer_options *opts)
 {
        int patch_start, trailer_end, trailer_start;
        struct strbuf **trailer_lines, **ptr;
@@ -1076,7 +1080,11 @@ void trailer_info_get(struct trailer_info *info, const char *str)
 
        ensure_configured();
 
-       patch_start = find_patch_start(str);
+       if (opts->no_divider)
+               patch_start = strlen(str);
+       else
+               patch_start = find_patch_start(str);
+
        trailer_end = find_trailer_end(str, patch_start);
        trailer_start = find_trailer_start(str, trailer_end);
 
@@ -1111,7 +1119,7 @@ void trailer_info_get(struct trailer_info *info, const char *str)
 
 void trailer_info_release(struct trailer_info *info)
 {
-       int i;
+       size_t i;
        for (i = 0; i < info->trailer_nr; i++)
                free(info->trailers[i]);
        free(info->trailers);
@@ -1121,7 +1129,7 @@ static void format_trailer_info(struct strbuf *out,
                                const struct trailer_info *info,
                                const struct process_trailer_options *opts)
 {
-       int i;
+       size_t i;
 
        /* If we want the whole block untouched, we can take the fast path. */
        if (!opts->only_trailers && !opts->unfold) {
@@ -1132,7 +1140,7 @@ static void format_trailer_info(struct strbuf *out,
 
        for (i = 0; i < info->trailer_nr; i++) {
                char *trailer = info->trailers[i];
-               int separator_pos = find_separator(trailer, separators);
+               ssize_t separator_pos = find_separator(trailer, separators);
 
                if (separator_pos >= 1) {
                        struct strbuf tok = STRBUF_INIT;
@@ -1158,7 +1166,7 @@ void format_trailers_from_commit(struct strbuf *out, const char *msg,
 {
        struct trailer_info info;
 
-       trailer_info_get(&info, msg);
+       trailer_info_get(&info, msg, opts);
        format_trailer_info(out, &info, opts);
        trailer_info_release(&info);
 }
index 9c10026..b997739 100644 (file)
--- a/trailer.h
+++ b/trailer.h
@@ -71,6 +71,7 @@ struct process_trailer_options {
        int only_trailers;
        int only_input;
        int unfold;
+       int no_divider;
 };
 
 #define PROCESS_TRAILER_OPTIONS_INIT {0}
@@ -79,7 +80,8 @@ void process_trailers(const char *file,
                      const struct process_trailer_options *opts,
                      struct list_head *new_trailer_head);
 
-void trailer_info_get(struct trailer_info *info, const char *str);
+void trailer_info_get(struct trailer_info *info, const char *str,
+                     const struct process_trailer_options *opts);
 
 void trailer_info_release(struct trailer_info *info);
 
index f25089b..82a83db 100644 (file)
@@ -392,7 +392,7 @@ static int check_updates(struct unpack_trees_options *o)
                }
                if (to_fetch.nr)
                        fetch_objects(repository_format_partial_clone,
-                                     &to_fetch);
+                                     to_fetch.oid, to_fetch.nr);
                fetch_if_missing = fetch_if_missing_store;
                oid_array_clear(&to_fetch);
        }
index 82b393e..9d4d6ad 100644 (file)
@@ -24,6 +24,7 @@
 #include "quote.h"
 #include "upload-pack.h"
 #include "serve.h"
+#include "commit-graph.h"
 
 /* Remember to update object flag allocation in object.h */
 #define THEY_HAVE      (1u << 11)
@@ -740,6 +741,7 @@ static void deepen_by_rev_list(int ac, const char **av,
 {
        struct commit_list *result;
 
+       close_commit_graph(the_repository);
        result = get_shallow_commits_by_rev_list(ac, av, SHALLOW, NOT_SHALLOW);
        send_shallow(result);
        free_commit_list(result);
@@ -1074,14 +1076,17 @@ static int upload_pack_config(const char *var, const char *value, void *unused)
                keepalive = git_config_int(var, value);
                if (!keepalive)
                        keepalive = -1;
-       } else if (current_config_scope() != CONFIG_SCOPE_REPO) {
-               if (!strcmp("uploadpack.packobjectshook", var))
-                       return git_config_string(&pack_objects_hook, var, value);
        } else if (!strcmp("uploadpack.allowfilter", var)) {
                allow_filter = git_config_bool(var, value);
        } else if (!strcmp("uploadpack.allowrefinwant", var)) {
                allow_ref_in_want = git_config_bool(var, value);
        }
+
+       if (current_config_scope() != CONFIG_SCOPE_REPO) {
+               if (!strcmp("uploadpack.packobjectshook", var))
+                       return git_config_string(&pack_objects_hook, var, value);
+       }
+
        return parse_hide_refs_config(var, value, "uploadpack");
 }
 
index f3f4be5..f565f67 100644 (file)
@@ -278,8 +278,7 @@ struct userdiff_driver *userdiff_find_by_path(const char *path)
                check = attr_check_initl("diff", NULL);
        if (!path)
                return NULL;
-       if (git_check_attr(&the_index, path, check))
-               return NULL;
+       git_check_attr(&the_index, path, check);
 
        if (ATTR_TRUE(check->items[0].value))
                return &driver_true;
diff --git a/ws.c b/ws.c
index 5b67b42..a64ab51 100644 (file)
--- a/ws.c
+++ b/ws.c
@@ -74,35 +74,31 @@ unsigned parse_whitespace_rule(const char *string)
 unsigned whitespace_rule(const char *pathname)
 {
        static struct attr_check *attr_whitespace_rule;
+       const char *value;
 
        if (!attr_whitespace_rule)
                attr_whitespace_rule = attr_check_initl("whitespace", NULL);
 
-       if (!git_check_attr(&the_index, pathname, attr_whitespace_rule)) {
-               const char *value;
-
-               value = attr_whitespace_rule->items[0].value;
-               if (ATTR_TRUE(value)) {
-                       /* true (whitespace) */
-                       unsigned all_rule = ws_tab_width(whitespace_rule_cfg);
-                       int i;
-                       for (i = 0; i < ARRAY_SIZE(whitespace_rule_names); i++)
-                               if (!whitespace_rule_names[i].loosens_error &&
-                                   !whitespace_rule_names[i].exclude_default)
-                                       all_rule |= whitespace_rule_names[i].rule_bits;
-                       return all_rule;
-               } else if (ATTR_FALSE(value)) {
-                       /* false (-whitespace) */
-                       return ws_tab_width(whitespace_rule_cfg);
-               } else if (ATTR_UNSET(value)) {
-                       /* reset to default (!whitespace) */
-                       return whitespace_rule_cfg;
-               } else {
-                       /* string */
-                       return parse_whitespace_rule(value);
-               }
-       } else {
+       git_check_attr(&the_index, pathname, attr_whitespace_rule);
+       value = attr_whitespace_rule->items[0].value;
+       if (ATTR_TRUE(value)) {
+               /* true (whitespace) */
+               unsigned all_rule = ws_tab_width(whitespace_rule_cfg);
+               int i;
+               for (i = 0; i < ARRAY_SIZE(whitespace_rule_names); i++)
+                       if (!whitespace_rule_names[i].loosens_error &&
+                           !whitespace_rule_names[i].exclude_default)
+                               all_rule |= whitespace_rule_names[i].rule_bits;
+               return all_rule;
+       } else if (ATTR_FALSE(value)) {
+               /* false (-whitespace) */
+               return ws_tab_width(whitespace_rule_cfg);
+       } else if (ATTR_UNSET(value)) {
+               /* reset to default (!whitespace) */
                return whitespace_rule_cfg;
+       } else {
+               /* string */
+               return parse_whitespace_rule(value);
        }
 }