]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Merge branch 'so/separate-field-for-m-and-diff-merges'
authorJunio C Hamano <gitster@pobox.com>
Wed, 9 Sep 2020 20:53:07 +0000 (13:53 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 9 Sep 2020 20:53:07 +0000 (13:53 -0700)
Internal API clean-up to handle two options "diff-index" and "log"
have, which happen to share the same short form, more sensibly.

* so/separate-field-for-m-and-diff-merges:
  revision: add separate field for "-m" of "diff-index -m"

131 files changed:
.github/workflows/main.yml
.gitignore
Documentation/RelNotes/2.29.0.txt
Documentation/config/fetch.txt
Documentation/diff-generate-patch.txt
Documentation/diff-options.txt
Documentation/git-apply.txt
Documentation/git-bisect.txt
Documentation/git-fetch.txt
Documentation/git-rebase.txt
Documentation/git-worktree.txt
Documentation/git.txt
Documentation/githooks.txt
Documentation/pretty-options.txt
Documentation/technical/partial-clone.txt
Makefile
add-patch.c
builtin.h
builtin/am.c
builtin/bisect--helper.c
builtin/bugreport.c [moved from bugreport.c with 96% similarity]
builtin/checkout.c
builtin/commit.c
builtin/credential-cache--daemon.c [moved from credential-cache--daemon.c with 91% similarity]
builtin/credential-cache.c [moved from credential-cache.c with 80% similarity]
builtin/credential-store.c [moved from credential-store.c with 96% similarity]
builtin/fast-import.c [moved from fast-import.c with 99% similarity]
builtin/fetch-pack.c
builtin/fetch.c
builtin/index-pack.c
builtin/init-db.c
builtin/merge.c
builtin/rebase.c
builtin/remote.c
builtin/repack.c
builtin/submodule--helper.c
builtin/worktree.c
commit.c
commit.h
contrib/buildsystems/CMakeLists.txt
contrib/svn-fe/.gitignore [deleted file]
contrib/svn-fe/Makefile [deleted file]
contrib/svn-fe/svn-fe.c [deleted file]
contrib/svn-fe/svn-fe.txt [deleted file]
contrib/svn-fe/svnrdump_sim.py [deleted file]
convert.c
credential.c
diff.c
fetch-negotiator.c
fetch-pack.c
fetch-pack.h
git-bisect.sh
git-cvsexportcommit.perl
git-submodule.sh
git.c
ident.c
midx.c
negotiator/noop.c [new file with mode: 0644]
negotiator/noop.h [new file with mode: 0644]
packfile.c
packfile.h
path.c
path.h
promisor-remote.c
ref-filter.c
refs.c
refs.h
refspec.h
remote-curl.c
remote-testsvn.c [deleted file]
repo-settings.c
repository.h
revision.c
sequencer.c
sequencer.h
submodule-config.c
submodule.c
submodule.h
t/helper/.gitignore
t/helper/test-line-buffer.c [deleted file]
t/helper/test-svn-fe.c [deleted file]
t/perf/README
t/perf/p1400-update-ref.sh
t/perf/p5302-pack-index.sh
t/perf/perf-lib.sh
t/t0001-init.sh
t/t0081-line-buffer.sh [deleted file]
t/t0410-partial-clone.sh
t/t2025-checkout-no-overlay.sh
t/t2072-restore-pathspec-file.sh
t/t2406-worktree-repair.sh [new file with mode: 0755]
t/t3422-rebase-incompatible-options.sh
t/t3436-rebase-more-options.sh [new file with mode: 0755]
t/t4013-diff-various.sh
t/t4013/diff.diff-tree_--root_-p_--abbrev=10_initial [new file with mode: 0644]
t/t4013/diff.diff-tree_--root_-p_--full-index_--abbrev=10_initial [new file with mode: 0644]
t/t4013/diff.diff-tree_--root_-p_--full-index_initial [new file with mode: 0644]
t/t4015-diff-whitespace.sh
t/t4067-diff-partial-clone.sh
t/t4202-log.sh
t/t5300-pack-object.sh
t/t5319-multi-pack-index.sh
t/t5510-fetch.sh
t/t5554-noop-fetch-negotiator.sh [new file with mode: 0755]
t/t5601-clone.sh
t/t5616-partial-clone.sh
t/t5702-protocol-v2.sh
t/t6018-rev-list-glob.sh
t/t6300-for-each-ref.sh
t/t7401-submodule-summary.sh
t/t7421-submodule-summary-add.sh [new file with mode: 0755]
t/t7518-ident-corner-cases.sh
t/t9010-svn-fe.sh [deleted file]
t/t9011-svn-da.sh [deleted file]
t/t9020-remote-svn.sh [deleted file]
t/test-lib-functions.sh
trailer.c
transport-helper.c
transport.c
transport.h
vcs-svn/LICENSE [deleted file]
vcs-svn/fast_export.c [deleted file]
vcs-svn/line_buffer.c [deleted file]
vcs-svn/line_buffer.txt [deleted file]
vcs-svn/sliding_window.c [deleted file]
vcs-svn/svndiff.c [deleted file]
vcs-svn/svndump.c [deleted file]
worktree.c
worktree.h
wrapper.c
wt-status.c

index 44e0fe5839de50425abe385bd156c48b996cff3d..30425404eb3fb8bc66ebf2c16803763f5d1247d0 100644 (file)
@@ -7,34 +7,34 @@ env:
 
 jobs:
   ci-config:
-      runs-on: ubuntu-latest
-      outputs:
-        enabled: ${{ steps.check-ref.outputs.enabled }}
-      steps:
-        - name: try to clone ci-config branch
-          continue-on-error: true
-          run: |
-            git -c protocol.version=2 clone \
-              --no-tags \
-              --single-branch \
-              -b ci-config \
-              --depth 1 \
-              --no-checkout \
-              --filter=blob:none \
-              https://github.com/${{ github.repository }} \
-              config-repo &&
-              cd config-repo &&
-              git checkout HEAD -- ci/config
-        - id: check-ref
-          name: check whether CI is enabled for ref
-          run: |
-            enabled=yes
-            if test -x config-repo/ci/config/allow-ref &&
-               ! config-repo/ci/config/allow-ref '${{ github.ref }}'
-            then
-              enabled=no
-            fi
-            echo "::set-output name=enabled::$enabled"
+    runs-on: ubuntu-latest
+    outputs:
+      enabled: ${{ steps.check-ref.outputs.enabled }}
+    steps:
+      - name: try to clone ci-config branch
+        continue-on-error: true
+        run: |
+          git -c protocol.version=2 clone \
+            --no-tags \
+            --single-branch \
+            -b ci-config \
+            --depth 1 \
+            --no-checkout \
+            --filter=blob:none \
+            https://github.com/${{ github.repository }} \
+            config-repo &&
+            cd config-repo &&
+            git checkout HEAD -- ci/config
+      - id: check-ref
+        name: check whether CI is enabled for ref
+        run: |
+          enabled=yes
+          if test -x config-repo/ci/config/allow-ref &&
+             ! config-repo/ci/config/allow-ref '${{ github.ref }}'
+          then
+            enabled=no
+          fi
+          echo "::set-output name=enabled::$enabled"
 
   windows-build:
     needs: ci-config
index ee509a2ad263989fcebe3c3543aa32efed1cacda..9673e792db80d75260cb08fd169488888492b6f1 100644 (file)
 /git-remote-fd
 /git-remote-ext
 /git-remote-testpy
-/git-remote-testsvn
 /git-repack
 /git-replace
 /git-request-pull
index 334e63a49711f9b8ed48d26f941b3cd331299341..a640fbc02f2d40cfa91fb4141d2735548fcd42f4 100644 (file)
@@ -51,6 +51,10 @@ UI, Workflows & Features
    deprecated and/or dangerous options from its output; it learned to
    optionally include all of them.
 
+ * The output from the "diff" family of the commands had abbreviated
+   object names of blobs involved in the patch, but its length was not
+   affected by the --abbrev option.  Now it is.
+
 
 Performance, Internal Implementation, Development Support etc.
 
@@ -113,6 +117,17 @@ Performance, Internal Implementation, Development Support etc.
    the ref backend in use, as its format is much richer than the
    normal refs, and written directly by "git fetch" as a plain file..
 
+ * A handful of places in in-tree code still relied on being able to
+   execute the git subcommands, especially built-ins, in "git-foo"
+   form, which have been corrected.
+
+ * An unused binary has been discarded, and and a bunch of commands
+   have been turned into into built-in.
+
+ * A handful of places in in-tree code still relied on being able to
+   execute the git subcommands, especially built-ins, in "git-foo"
+   form, which have been corrected.
+
 
 Fixes since v2.28
 -----------------
@@ -224,6 +239,53 @@ Fixes since v2.28
    marker like whitespaces.
    (merge 82a62015a7 rs/patch-id-with-incomplete-line later to maint).
 
+ * Updates into a lazy/partial clone with a submodule did not work
+   well with transfer.fsckobjects set.
+
+ * The parser for "git for-each-ref --format=..." was too loose when
+   parsing the "%(trailers...)" atom, and forgot that "trailers" and
+   "trailers:<modifiers>" are the only two allowed forms, which has
+   been corrected.
+   (merge 2c22e102f8 hv/ref-filter-trailers-atom-parsing-fix later to maint).
+
+ * Long ago, we decided to use 3 threads by default when running the
+   index-pack task in parallel, which has been adjusted a bit upwards.
+   (merge fbff95b67f jk/index-pack-w-more-threads later to maint).
+
+ * "git restore/checkout --no-overlay" with wildcarded pathspec
+   mistakenly removed matching paths in subdirectories, which has been
+   corrected.
+   (merge bfda204ade rs/checkout-no-overlay-pathspec-fix later to maint).
+
+ * The description of --cached/--index options in "git apply --help"
+   has been updated.
+   (merge d064702be3 rp/apply-cached-doc later to maint).
+
+ * Feeding "$ZERO_OID" to "git log --ignore-missing --stdin", and
+   running "git log --ignore-missing $ZERO_OID" fell back to start
+   digging from HEAD; it has been corrected to become a no-op, like
+   "git log --tags=no-tag-matches-this-pattern" does.
+   (merge 04a0e98515 jk/rev-input-given-fix later to maint).
+
+ * Various callers of run_command API has been modernized.
+   (merge afbdba391e jc/run-command-use-embedded-args later to maint).
+
+ * List of options offered and accepted by "git add -i/-p" were
+   inconsistent, which have been corrected.
+   (merge ce910287e7 pw/add-p-allowed-options-fix later to maint).
+
+ * Various callers of run_command API has been modernized.
+   (merge afbdba391e jc/run-command-use-embedded-args later to maint).
+
+ * "git diff --stat -w" showed 0-line changes for paths whose changes
+   were only whitespaces, which was not intuitive.  We now omit such
+   paths from the stat output.
+   (merge 1cf3d5db9b mr/diff-hide-stat-wo-textual-change later to maint).
+
+ * It was possible for xrealloc() to send a non-NULL pointer that has
+   been freed, which has been fixed.
+   (merge 6479ea4a8a jk/xrealloc-avoid-use-after-free later to maint).
+
  * Other code cleanup, docfix, build fix, etc.
    (merge 84544f2ea3 sk/typofixes later to maint).
    (merge b17f411ab5 ar/help-guides-doc later to maint).
@@ -246,3 +308,6 @@ Fixes since v2.28
    (merge 748f733d54 mt/checkout-entry-dead-code-removal later to maint).
    (merge ce820cbd58 dl/subtree-docs later to maint).
    (merge 55fe225dde jk/leakfix later to maint).
+   (merge ee22a29215 so/pretty-abbrev-doc later to maint).
+   (merge 3100fd5588 jc/post-checkout-doc later to maint).
+   (merge 17bae89476 pb/doc-external-diff-env later to maint).
index b20394038d1eef83d7e454cf0fee7ceb8a457a0f..6af6f5edb278f53ceb2f4c69f47f72d6ef120e2f 100644 (file)
@@ -60,7 +60,10 @@ fetch.negotiationAlgorithm::
        sent when negotiating the contents of the packfile to be sent by the
        server. Set to "skipping" to use an algorithm that skips commits in an
        effort to converge faster, but may result in a larger-than-necessary
-       packfile; The default is "default" which instructs Git to use the default algorithm
+       packfile; or set to "noop" to not send any information at all, which
+       will almost certainly result in a larger-than-necessary packfile, but
+       will skip the negotiation step.
+       The default is "default" which instructs Git to use the default algorithm
        that never skips commits (unless the server has acknowledged it or one
        of its descendants). If `feature.experimental` is enabled, then this
        setting defaults to "skipping".
index e8ed6470fb3a64e2bf713c6a4ed98e9b9e04b4a9..b10ff4caa6c52aefc485fec9e71e19c6121946bf 100644 (file)
@@ -10,7 +10,8 @@ linkgit:git-diff-tree[1], or
 linkgit:git-diff-files[1]
 with the `-p` option produces patch text.
 You can customize the creation of patch text via the
-`GIT_EXTERNAL_DIFF` and the `GIT_DIFF_OPTS` environment variables.
+`GIT_EXTERNAL_DIFF` and the `GIT_DIFF_OPTS` environment variables
+(see linkgit:git[1]).
 
 What the -p option produces is slightly different from the traditional
 diff format:
index b7af973d9c9d119f43fb19f7f787c4f9317f192c..573fb9bb71e2b7df1062258289a0af308c50bf5b 100644 (file)
@@ -446,10 +446,11 @@ endif::git-format-patch[]
 --abbrev[=<n>]::
        Instead of showing the full 40-byte hexadecimal object
        name in diff-raw format output and diff-tree header
-       lines, show only a partial prefix.  This is
-       independent of the `--full-index` option above, which controls
-       the diff-patch output format.  Non default number of
-       digits can be specified with `--abbrev=<n>`.
+       lines, show only a partial prefix.
+       In diff-patch output format, `--full-index` takes higher
+       precedence, i.e. if `--full-index` is specified, full blob
+       names will be shown regardless of `--abbrev`.
+       Non default number of digits can be specified with `--abbrev=<n>`.
 
 -B[<n>][/<m>]::
 --break-rewrites[=[<n>][/<m>]]::
index b9aa39000fc8aa77d69751d9409a957139c2cff7..91d9a8601c8c316d4649c405af42e531c39991a8 100644 (file)
@@ -61,18 +61,18 @@ OPTIONS
        file and detects errors.  Turns off "apply".
 
 --index::
-       When `--check` is in effect, or when applying the patch
-       (which is the default when none of the options that
-       disables it is in effect), make sure the patch is
-       applicable to what the current index file records.  If
-       the file to be patched in the working tree is not
-       up to date, it is flagged as an error.  This flag also
-       causes the index file to be updated.
+       Apply the patch to both the index and the working tree (or
+       merely check that it would apply cleanly to both if `--check` is
+       in effect). Note that `--index` expects index entries and
+       working tree copies for relevant paths to be identical (their
+       contents and metadata such as file mode must match), and will
+       raise an error if they are not, even if the patch would apply
+       cleanly to both the index and the working tree in isolation.
 
 --cached::
-       Apply a patch without touching the working tree. Instead take the
-       cached data, apply the patch, and store the result in the index
-       without using the working tree. This implies `--index`.
+       Apply the patch to just the index, without touching the working
+       tree. If `--check` is in effect, merely check that it would
+       apply cleanly to the index entry.
 
 --intent-to-add::
        When applying the patch only to the working tree, mark new
index 0e993e458717743e4e2f136d27f7291101853bba..fbb39fbdf5d62a455c8b62d4870817998d0434ad 100644 (file)
@@ -16,7 +16,7 @@ DESCRIPTION
 The command takes various subcommands, and different options depending
 on the subcommand:
 
- git bisect start [--term-{old,good}=<term> --term-{new,bad}=<term>]
+ git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]
                  [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]
  git bisect (bad|new|<term-new>) [<rev>]
  git bisect (good|old|<term-old>) [<rev>...]
index 45b6d8e633ccf20675349b1a23072b90c0a46709..9067c2079e44c140fcb46c34ec708842f7dde5b4 100644 (file)
@@ -48,6 +48,10 @@ include::fetch-options.txt[]
 
 include::pull-fetch-param.txt[]
 
+--stdin::
+       Read refspecs, one per line, from stdin in addition to those provided
+       as arguments. The "tag <name>" format is not supported.
+
 include::urls-remotes.txt[]
 
 
index 374d2486f71c6659d48ea6105e877d89b9fe8d28..38e15488f651718bf220453504a39fb8ef0800f7 100644 (file)
@@ -204,6 +204,7 @@ CONFIGURATION
 -------------
 
 include::config/rebase.txt[]
+include::config/sequencer.txt[]
 
 OPTIONS
 -------
@@ -459,17 +460,38 @@ with `--keep-base` in order to drop those commits from your branch.
 See also INCOMPATIBLE OPTIONS below.
 
 --ignore-whitespace::
+       Ignore whitespace differences when trying to reconcile
+differences. Currently, each backend implements an approximation of
+this behavior:
++
+apply backend: When applying a patch, ignore changes in whitespace in
+context lines. Unfortunately, this means that if the "old" lines being
+replaced by the patch differ only in whitespace from the existing
+file, you will get a merge conflict instead of a successful patch
+application.
++
+merge backend: Treat lines with only whitespace changes as unchanged
+when merging. Unfortunately, this means that any patch hunks that were
+intended to modify whitespace and nothing else will be dropped, even
+if the other side had no changes that conflicted.
+
 --whitespace=<option>::
-       These flags are passed to the 'git apply' program
+       This flag is passed to the 'git apply' program
        (see linkgit:git-apply[1]) that applies the patch.
        Implies --apply.
 +
 See also INCOMPATIBLE OPTIONS below.
 
 --committer-date-is-author-date::
+       Instead of using the current time as the committer date, use
+       the author date of the commit being rebased as the committer
+       date. This option implies `--force-rebase`.
+
 --ignore-date::
-       These flags are passed to 'git am' to easily change the dates
-       of the rebased commits (see linkgit:git-am[1]).
+--reset-author-date::
+       Instead of using the author date of the original commit, use
+       the current time as the author date of the rebased commit.  This
+       option implies `--force-rebase`.
 +
 See also INCOMPATIBLE OPTIONS below.
 
@@ -607,9 +629,6 @@ INCOMPATIBLE OPTIONS
 The following options:
 
  * --apply
- * --committer-date-is-author-date
- * --ignore-date
- * --ignore-whitespace
  * --whitespace
  * -C
 
@@ -636,6 +655,9 @@ In addition, the following pairs of options are incompatible:
  * --preserve-merges and --signoff
  * --preserve-merges and --rebase-merges
  * --preserve-merges and --empty=
+ * --preserve-merges and --ignore-whitespace
+ * --preserve-merges and --committer-date-is-author-date
+ * --preserve-merges and --ignore-date
  * --keep-base and --onto
  * --keep-base and --root
  * --fork-point and --root
index 6ee6ec79824a6a8e43d2411b9226c72a49d52c9e..f70cda4b36428ac1bfe2f5fc742f8353c19097d6 100644 (file)
@@ -15,6 +15,7 @@ SYNOPSIS
 'git worktree move' <worktree> <new-path>
 'git worktree prune' [-n] [-v] [--expire <expire>]
 'git worktree remove' [-f] <worktree>
+'git worktree repair' [<path>...]
 'git worktree unlock' <worktree>
 
 DESCRIPTION
@@ -97,7 +98,10 @@ with `--reason`.
 move::
 
 Move a working tree to a new location. Note that the main working tree
-or linked working trees containing submodules cannot be moved.
+or linked working trees containing submodules cannot be moved with this
+command. (The `git worktree repair` command, however, can reestablish
+the connection with linked working trees if you move the main working
+tree manually.)
 
 prune::
 
@@ -110,6 +114,23 @@ and no modification in tracked files) can be removed. Unclean working
 trees or ones with submodules can be removed with `--force`. The main
 working tree cannot be removed.
 
+repair [<path>...]::
+
+Repair working tree administrative files, if possible, if they have
+become corrupted or outdated due to external factors.
++
+For instance, if the main working tree (or bare repository) is moved,
+linked working trees will be unable to locate it. Running `repair` in
+the main working tree will reestablish the connection from linked
+working trees back to the main working tree.
++
+Similarly, if a linked working tree is moved without using `git worktree
+move`, the main working tree (or bare repository) will be unable to
+locate it. Running `repair` within the recently-moved working tree will
+reestablish the connection. If multiple linked working trees are moved,
+running `repair` from any working tree with each tree's new `<path>` as
+an argument, will reestablish the connection to all the specified paths.
+
 unlock::
 
 Unlock a working tree, allowing it to be pruned, moved or deleted.
@@ -303,7 +324,8 @@ in the entry's directory. For example, if a linked working tree is moved
 to `/newpath/test-next` and its `.git` file points to
 `/path/main/.git/worktrees/test-next`, then update
 `/path/main/.git/worktrees/test-next/gitdir` to reference `/newpath/test-next`
-instead.
+instead. Better yet, run `git worktree repair` to reestablish the connection
+automatically.
 
 To prevent a `$GIT_DIR/worktrees` entry from being pruned (which
 can be useful in some situations, such as when the
index 2fc92586b52386c770bed28a11275c64eea3414a..2f72b10224a0eb70835ff1ff70172fb6019f1462 100644 (file)
@@ -551,8 +551,9 @@ Git Diffs
 
 `GIT_EXTERNAL_DIFF`::
        When the environment variable `GIT_EXTERNAL_DIFF` is set, the
-       program named by it is called, instead of the diff invocation
-       described above.  For a path that is added, removed, or modified,
+       program named by it is called to generate diffs, and Git
+       does not use its builtin diff machinery.
+       For a path that is added, removed, or modified,
        `GIT_EXTERNAL_DIFF` is called with 7 parameters:
 
        path old-file old-hex old-mode new-file new-hex new-mode
@@ -605,6 +606,12 @@ other
        an editor is to be launched. See also linkgit:git-var[1]
        and the `core.editor` option in linkgit:git-config[1].
 
+`GIT_SEQUENCE_EDITOR`::
+       This environment variable overrides the configured Git editor
+       when editing the todo list of an interactive rebase. See also
+       linkit::git-rebase[1] and the `sequence.editor` option in
+       linkit::git-config[1].
+
 `GIT_SSH`::
 `GIT_SSH_COMMAND`::
        If either of these environment variables is set then 'git fetch'
index 31b601e4bce9c9fbb7f96f2f5308d0166f92f999..cf95d6d02b1c181a646b2140f9d95a1e3d80e291 100644 (file)
@@ -193,7 +193,9 @@ worktree.  The hook is given three parameters: the ref of the previous HEAD,
 the ref of the new HEAD (which may or may not have changed), and a flag
 indicating whether the checkout was a branch checkout (changing branches,
 flag=1) or a file checkout (retrieving a file from the index, flag=0).
-This hook cannot affect the outcome of `git switch` or `git checkout`.
+This hook cannot affect the outcome of `git switch` or `git checkout`,
+other than that the hook's exit status becomes the exit status of
+these two commands.
 
 It is also run after linkgit:git-clone[1], unless the `--no-checkout` (`-n`) option is
 used. The first parameter given to the hook is the null-ref, the second the
index 7a6da6db780eb422fa03ae4d05e0dd3ec8ecf4b5..17c5aac4b71d5af126a0bd85d3ffef2e94468e3c 100644 (file)
@@ -25,8 +25,8 @@ people using 80-column terminals.
 
 --no-abbrev-commit::
        Show the full 40-byte hexadecimal commit object name. This negates
-       `--abbrev-commit` and those options which imply it such as
-       "--oneline". It also overrides the `log.abbrevCommit` variable.
+       `--abbrev-commit`, either explicit or implied by other options such
+       as "--oneline". It also overrides the `log.abbrevCommit` variable.
 
 --oneline::
        This is a shorthand for "--pretty=oneline --abbrev-commit"
index b9e17e7a28784a5b3ab1345db94940eb05e5b6c6..0780d30caca6aa1e93a77b9bfb2dc15103fd1a99 100644 (file)
@@ -171,20 +171,13 @@ additional flag.
 Fetching Missing Objects
 ------------------------
 
-- Fetching of objects is done using the existing transport mechanism using
-  transport_fetch_refs(), setting a new transport option
-  TRANS_OPT_NO_DEPENDENTS to indicate that only the objects themselves are
-  desired, not any object that they refer to.
-+
-Because some transports invoke fetch_pack() in the same process, fetch_pack()
-has been updated to not use any object flags when the corresponding argument
-(no_dependents) is set.
+- Fetching of objects is done by invoking a "git fetch" subprocess.
 
 - The local repository sends a request with the hashes of all requested
-  objects as "want" lines, and does not perform any packfile negotiation.
+  objects, and does not perform any packfile negotiation.
   It then receives a packfile.
 
-- Because we are reusing the existing fetch-pack mechanism, fetching
+- Because we are reusing the existing fetch mechanism, fetching
   currently fetches all objects referred to by the requested objects, even
   though they are not necessary.
 
index 65f8cfb2368d2d6099bdfd845a7beb505702b86f..86e5411f39ddbba20f5633848eb538ae9ecd277b 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -569,7 +569,6 @@ BUILT_INS =
 COMPAT_CFLAGS =
 COMPAT_OBJS =
 XDIFF_OBJS =
-VCSSVN_OBJS =
 GENERATED_H =
 EXTRA_CPPFLAGS =
 FUZZ_OBJS =
@@ -671,13 +670,9 @@ EXTRA_PROGRAMS =
 # ... and all the rest that could be moved out of bindir to gitexecdir
 PROGRAMS += $(EXTRA_PROGRAMS)
 
-PROGRAM_OBJS += bugreport.o
-PROGRAM_OBJS += credential-store.o
 PROGRAM_OBJS += daemon.o
-PROGRAM_OBJS += fast-import.o
 PROGRAM_OBJS += http-backend.o
 PROGRAM_OBJS += imap-send.o
-PROGRAM_OBJS += remote-testsvn.o
 PROGRAM_OBJS += sh-i18n--envsubst.o
 PROGRAM_OBJS += shell.o
 
@@ -749,8 +744,6 @@ TEST_BUILTINS_OBJS += test-xml-encode.o
 # Do not add more tests here unless they have extra dependencies. Add
 # them in TEST_BUILTINS_OBJS above.
 TEST_PROGRAMS_NEED_X += test-fake-ssh
-TEST_PROGRAMS_NEED_X += test-line-buffer
-TEST_PROGRAMS_NEED_X += test-svn-fe
 TEST_PROGRAMS_NEED_X += test-tool
 
 TEST_PROGRAMS = $(patsubst %,t/helper/%$X,$(TEST_PROGRAMS_NEED_X))
@@ -806,7 +799,6 @@ TEST_SHELL_PATH = $(SHELL_PATH)
 
 LIB_FILE = libgit.a
 XDIFF_LIB = xdiff/lib.a
-VCSSVN_LIB = vcs-svn/lib.a
 
 GENERATED_H += config-list.h
 GENERATED_H += command-list.h
@@ -916,6 +908,7 @@ LIB_OBJS += mergesort.o
 LIB_OBJS += midx.o
 LIB_OBJS += name-hash.o
 LIB_OBJS += negotiator/default.o
+LIB_OBJS += negotiator/noop.o
 LIB_OBJS += negotiator/skipping.o
 LIB_OBJS += notes-cache.o
 LIB_OBJS += notes-merge.o
@@ -1042,6 +1035,7 @@ BUILTIN_OBJS += builtin/archive.o
 BUILTIN_OBJS += builtin/bisect--helper.o
 BUILTIN_OBJS += builtin/blame.o
 BUILTIN_OBJS += builtin/branch.o
+BUILTIN_OBJS += builtin/bugreport.o
 BUILTIN_OBJS += builtin/bundle.o
 BUILTIN_OBJS += builtin/cat-file.o
 BUILTIN_OBJS += builtin/check-attr.o
@@ -1052,6 +1046,9 @@ BUILTIN_OBJS += builtin/checkout-index.o
 BUILTIN_OBJS += builtin/checkout.o
 BUILTIN_OBJS += builtin/clean.o
 BUILTIN_OBJS += builtin/clone.o
+BUILTIN_OBJS += builtin/credential-cache.o
+BUILTIN_OBJS += builtin/credential-cache--daemon.o
+BUILTIN_OBJS += builtin/credential-store.o
 BUILTIN_OBJS += builtin/column.o
 BUILTIN_OBJS += builtin/commit-graph.o
 BUILTIN_OBJS += builtin/commit-tree.o
@@ -1067,6 +1064,7 @@ BUILTIN_OBJS += builtin/diff.o
 BUILTIN_OBJS += builtin/difftool.o
 BUILTIN_OBJS += builtin/env--helper.o
 BUILTIN_OBJS += builtin/fast-export.o
+BUILTIN_OBJS += builtin/fast-import.o
 BUILTIN_OBJS += builtin/fetch-pack.o
 BUILTIN_OBJS += builtin/fetch.o
 BUILTIN_OBJS += builtin/fmt-merge-msg.o
@@ -1634,11 +1632,8 @@ ifdef NO_INET_PTON
 endif
 ifdef NO_UNIX_SOCKETS
        BASIC_CFLAGS += -DNO_UNIX_SOCKETS
-       EXCLUDED_PROGRAMS += git-credential-cache git-credential-cache--daemon
 else
        LIB_OBJS += unix-socket.o
-       PROGRAM_OBJS += credential-cache.o
-       PROGRAM_OBJS += credential-cache--daemon.o
 endif
 
 ifdef NO_ICONV
@@ -2346,16 +2341,9 @@ XDIFF_OBJS += xdiff/xpatience.o
 XDIFF_OBJS += xdiff/xprepare.o
 XDIFF_OBJS += xdiff/xutils.o
 
-VCSSVN_OBJS += vcs-svn/fast_export.o
-VCSSVN_OBJS += vcs-svn/line_buffer.o
-VCSSVN_OBJS += vcs-svn/sliding_window.o
-VCSSVN_OBJS += vcs-svn/svndiff.o
-VCSSVN_OBJS += vcs-svn/svndump.o
-
 TEST_OBJS := $(patsubst %$X,%.o,$(TEST_PROGRAMS)) $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS))
 OBJECTS := $(LIB_OBJS) $(BUILTIN_OBJS) $(PROGRAM_OBJS) $(TEST_OBJS) \
        $(XDIFF_OBJS) \
-       $(VCSSVN_OBJS) \
        $(FUZZ_OBJS) \
        common-main.o \
        git.o
@@ -2459,10 +2447,6 @@ endif
 git-%$X: %.o GIT-LDFLAGS $(GITLIBS)
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
 
-git-bugreport$X: bugreport.o GIT-LDFLAGS $(GITLIBS)
-       $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
-               $(LIBS)
-
 git-imap-send$X: imap-send.o $(IMAP_SEND_BUILDDEPS) GIT-LDFLAGS $(GITLIBS)
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
                $(IMAP_SEND_LDFLAGS) $(LIBS)
@@ -2474,10 +2458,6 @@ git-http-push$X: http.o http-push.o GIT-LDFLAGS $(GITLIBS)
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
                $(CURL_LIBCURL) $(EXPAT_LIBEXPAT) $(LIBS)
 
-git-remote-testsvn$X: remote-testsvn.o GIT-LDFLAGS $(GITLIBS) $(VCSSVN_LIB)
-       $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) \
-       $(VCSSVN_LIB)
-
 $(REMOTE_CURL_ALIASES): $(REMOTE_CURL_PRIMARY)
        $(QUIET_LNCP)$(RM) $@ && \
        ln $< $@ 2>/dev/null || \
@@ -2494,9 +2474,6 @@ $(LIB_FILE): $(LIB_OBJS)
 $(XDIFF_LIB): $(XDIFF_OBJS)
        $(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
 
-$(VCSSVN_LIB): $(VCSSVN_OBJS)
-       $(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
-
 export DEFAULT_EDITOR DEFAULT_PAGER
 
 Documentation/GIT-EXCLUDED-PROGRAMS: FORCE
@@ -2771,10 +2748,6 @@ perf: all
 
 .PHONY: test perf
 
-t/helper/test-line-buffer$X: $(VCSSVN_LIB)
-
-t/helper/test-svn-fe$X: $(VCSSVN_LIB)
-
 .PRECIOUS: $(TEST_OBJS)
 
 t/helper/test-tool$X: $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS))
@@ -2901,18 +2874,13 @@ ifdef MSVC
        # because it is just a copy/hardlink of git.exe, rather than a unique binary.
        $(INSTALL) git.pdb '$(DESTDIR_SQ)$(bindir_SQ)'
        $(INSTALL) git-shell.pdb '$(DESTDIR_SQ)$(bindir_SQ)'
-       $(INSTALL) git-upload-pack.pdb '$(DESTDIR_SQ)$(bindir_SQ)'
-       $(INSTALL) git-credential-store.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
        $(INSTALL) git-daemon.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
-       $(INSTALL) git-fast-import.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
        $(INSTALL) git-http-backend.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
        $(INSTALL) git-http-fetch.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
        $(INSTALL) git-http-push.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
        $(INSTALL) git-imap-send.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
        $(INSTALL) git-remote-http.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
-       $(INSTALL) git-remote-testsvn.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
        $(INSTALL) git-sh-i18n--envsubst.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
-       $(INSTALL) git-show-index.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
 ifndef DEBUG
        $(INSTALL) $(vcpkg_rel_bin)/*.dll '$(DESTDIR_SQ)$(bindir_SQ)'
        $(INSTALL) $(vcpkg_rel_bin)/*.pdb '$(DESTDIR_SQ)$(bindir_SQ)'
@@ -3112,7 +3080,7 @@ cocciclean:
 clean: profile-clean coverage-clean cocciclean
        $(RM) *.res
        $(RM) $(OBJECTS)
-       $(RM) $(LIB_FILE) $(XDIFF_LIB) $(VCSSVN_LIB)
+       $(RM) $(LIB_FILE) $(XDIFF_LIB)
        $(RM) $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git$X
        $(RM) $(TEST_PROGRAMS)
        $(RM) $(FUZZ_PROGRAMS)
index f67b304a552947553e5990a239e6aa18ee745a52..457b8c550eb1b9711a67ceda65c27841ee7e3150 100644 (file)
@@ -457,11 +457,9 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
                        eol = pend;
 
                if (starts_with(p, "diff ")) {
-                       s->file_diff_nr++;
-                       ALLOC_GROW(s->file_diff, s->file_diff_nr,
+                       ALLOC_GROW_BY(s->file_diff, s->file_diff_nr, 1,
                                   file_diff_alloc);
                        file_diff = s->file_diff + s->file_diff_nr - 1;
-                       memset(file_diff, 0, sizeof(*file_diff));
                        hunk = &file_diff->head;
                        hunk->start = p - plain->buf;
                        if (colored_p)
@@ -483,11 +481,9 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
                                 */
                                hunk->splittable_into++;
 
-                       file_diff->hunk_nr++;
-                       ALLOC_GROW(file_diff->hunk, file_diff->hunk_nr,
+                       ALLOC_GROW_BY(file_diff->hunk, file_diff->hunk_nr, 1,
                                   file_diff->hunk_alloc);
                        hunk = file_diff->hunk + file_diff->hunk_nr - 1;
-                       memset(hunk, 0, sizeof(*hunk));
 
                        hunk->start = p - plain->buf;
                        if (colored)
@@ -511,7 +507,7 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
                        if (file_diff->mode_change)
                                BUG("double mode change?\n\n%.*s",
                                    (int)(eol - plain->buf), plain->buf);
-                       if (file_diff->hunk_nr++)
+                       if (file_diff->hunk_nr)
                                BUG("mode change in the middle?\n\n%.*s",
                                    (int)(eol - plain->buf), plain->buf);
 
@@ -520,9 +516,8 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
                         * is _part of_ the header "hunk".
                         */
                        file_diff->mode_change = 1;
-                       ALLOC_GROW(file_diff->hunk, file_diff->hunk_nr,
+                       ALLOC_GROW_BY(file_diff->hunk, file_diff->hunk_nr, 1,
                                   file_diff->hunk_alloc);
-                       memset(file_diff->hunk, 0, sizeof(struct hunk));
                        file_diff->hunk->start = p - plain->buf;
                        if (colored_p)
                                file_diff->hunk->colored_start =
@@ -1357,6 +1352,15 @@ static int patch_update_file(struct add_p_state *s,
        struct child_process cp = CHILD_PROCESS_INIT;
        int colored = !!s->colored.len, quit = 0;
        enum prompt_mode_type prompt_mode_type;
+       enum {
+               ALLOW_GOTO_PREVIOUS_HUNK = 1 << 0,
+               ALLOW_GOTO_PREVIOUS_UNDECIDED_HUNK = 1 << 1,
+               ALLOW_GOTO_NEXT_HUNK = 1 << 2,
+               ALLOW_GOTO_NEXT_UNDECIDED_HUNK = 1 << 3,
+               ALLOW_SEARCH_AND_GOTO = 1 << 4,
+               ALLOW_SPLIT = 1 << 5,
+               ALLOW_EDIT = 1 << 6
+       } permitted = 0;
 
        if (!file_diff->hunk_nr)
                return 0;
@@ -1393,22 +1397,35 @@ static int patch_update_file(struct add_p_state *s,
                fputs(s->buf.buf, stdout);
 
                strbuf_reset(&s->buf);
-               if (undecided_previous >= 0)
+               if (undecided_previous >= 0) {
+                       permitted |= ALLOW_GOTO_PREVIOUS_UNDECIDED_HUNK;
                        strbuf_addstr(&s->buf, ",k");
-               if (hunk_index)
+               }
+               if (hunk_index) {
+                       permitted |= ALLOW_GOTO_PREVIOUS_HUNK;
                        strbuf_addstr(&s->buf, ",K");
-               if (undecided_next >= 0)
+               }
+               if (undecided_next >= 0) {
+                       permitted |= ALLOW_GOTO_NEXT_UNDECIDED_HUNK;
                        strbuf_addstr(&s->buf, ",j");
-               if (hunk_index + 1 < file_diff->hunk_nr)
+               }
+               if (hunk_index + 1 < file_diff->hunk_nr) {
+                       permitted |= ALLOW_GOTO_NEXT_HUNK;
                        strbuf_addstr(&s->buf, ",J");
-               if (file_diff->hunk_nr > 1)
+               }
+               if (file_diff->hunk_nr > 1) {
+                       permitted |= ALLOW_SEARCH_AND_GOTO;
                        strbuf_addstr(&s->buf, ",g,/");
-               if (hunk->splittable_into > 1)
+               }
+               if (hunk->splittable_into > 1) {
+                       permitted |= ALLOW_SPLIT;
                        strbuf_addstr(&s->buf, ",s");
+               }
                if (hunk_index + 1 > file_diff->mode_change &&
-                   !file_diff->deleted)
+                   !file_diff->deleted) {
+                       permitted |= ALLOW_EDIT;
                        strbuf_addstr(&s->buf, ",e");
-
+               }
                if (file_diff->deleted)
                        prompt_mode_type = PROMPT_DELETION;
                else if (file_diff->added)
@@ -1457,22 +1474,22 @@ soft_increment:
                                break;
                        }
                } else if (s->answer.buf[0] == 'K') {
-                       if (hunk_index)
+                       if (permitted & ALLOW_GOTO_PREVIOUS_HUNK)
                                hunk_index--;
                        else
                                err(s, _("No previous hunk"));
                } else if (s->answer.buf[0] == 'J') {
-                       if (hunk_index + 1 < file_diff->hunk_nr)
+                       if (permitted & ALLOW_GOTO_NEXT_HUNK)
                                hunk_index++;
                        else
                                err(s, _("No next hunk"));
                } else if (s->answer.buf[0] == 'k') {
-                       if (undecided_previous >= 0)
+                       if (permitted & ALLOW_GOTO_PREVIOUS_UNDECIDED_HUNK)
                                hunk_index = undecided_previous;
                        else
                                err(s, _("No previous hunk"));
                } else if (s->answer.buf[0] == 'j') {
-                       if (undecided_next >= 0)
+                       if (permitted & ALLOW_GOTO_NEXT_UNDECIDED_HUNK)
                                hunk_index = undecided_next;
                        else
                                err(s, _("No next hunk"));
@@ -1480,7 +1497,7 @@ soft_increment:
                        char *pend;
                        unsigned long response;
 
-                       if (file_diff->hunk_nr < 2) {
+                       if (!(permitted & ALLOW_SEARCH_AND_GOTO)) {
                                err(s, _("No other hunks to goto"));
                                continue;
                        }
@@ -1517,7 +1534,7 @@ soft_increment:
                        regex_t regex;
                        int ret;
 
-                       if (file_diff->hunk_nr < 2) {
+                       if (!(permitted & ALLOW_SEARCH_AND_GOTO)) {
                                err(s, _("No other hunks to search"));
                                continue;
                        }
@@ -1562,7 +1579,7 @@ soft_increment:
                        hunk_index = i;
                } else if (s->answer.buf[0] == 's') {
                        size_t splittable_into = hunk->splittable_into;
-                       if (splittable_into < 2)
+                       if (!(permitted & ALLOW_SPLIT))
                                err(s, _("Sorry, cannot split this hunk"));
                        else if (!split_hunk(s, file_diff,
                                             hunk - file_diff->hunk))
@@ -1570,7 +1587,7 @@ soft_increment:
                                                 _("Split into %d hunks."),
                                                 (int)splittable_into);
                } else if (s->answer.buf[0] == 'e') {
-                       if (hunk_index + 1 == file_diff->mode_change)
+                       if (!(permitted & ALLOW_EDIT))
                                err(s, _("Sorry, cannot edit this hunk"));
                        else if (edit_hunk_loop(s, file_diff, hunk) >= 0) {
                                hunk->use = USE_HUNK;
index a5ae15bfe54b652465b0164872923c8386d03ae9..ba954e180c56a3543e73f181a086b494cba88c38 100644 (file)
--- a/builtin.h
+++ b/builtin.h
@@ -119,6 +119,7 @@ int cmd_archive(int argc, const char **argv, const char *prefix);
 int cmd_bisect__helper(int argc, const char **argv, const char *prefix);
 int cmd_blame(int argc, const char **argv, const char *prefix);
 int cmd_branch(int argc, const char **argv, const char *prefix);
+int cmd_bugreport(int argc, const char **argv, const char *prefix);
 int cmd_bundle(int argc, const char **argv, const char *prefix);
 int cmd_cat_file(int argc, const char **argv, const char *prefix);
 int cmd_checkout(int argc, const char **argv, const char *prefix);
@@ -138,6 +139,9 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix);
 int cmd_config(int argc, const char **argv, const char *prefix);
 int cmd_count_objects(int argc, const char **argv, const char *prefix);
 int cmd_credential(int argc, const char **argv, const char *prefix);
+int cmd_credential_cache(int argc, const char **argv, const char *prefix);
+int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix);
+int cmd_credential_store(int argc, const char **argv, const char *prefix);
 int cmd_describe(int argc, const char **argv, const char *prefix);
 int cmd_diff_files(int argc, const char **argv, const char *prefix);
 int cmd_diff_index(int argc, const char **argv, const char *prefix);
@@ -146,6 +150,7 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix);
 int cmd_difftool(int argc, const char **argv, const char *prefix);
 int cmd_env__helper(int argc, const char **argv, const char *prefix);
 int cmd_fast_export(int argc, const char **argv, const char *prefix);
+int cmd_fast_import(int argc, const char **argv, const char *prefix);
 int cmd_fetch(int argc, const char **argv, const char *prefix);
 int cmd_fetch_pack(int argc, const char **argv, const char *prefix);
 int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix);
index dd4e6c2d9b7f478c322a469fd64cbaf3de285d17..b5c63ddf1df8ea5be5b11944b23f3411686b0287 100644 (file)
@@ -98,6 +98,8 @@ struct am_state {
        char *author_name;
        char *author_email;
        char *author_date;
+       char *committer_name;
+       char *committer_email;
        char *msg;
        size_t msg_len;
 
@@ -130,6 +132,8 @@ struct am_state {
  */
 static void am_state_init(struct am_state *state)
 {
+       const char *committer;
+       struct ident_split id;
        int gpgsign;
 
        memset(state, 0, sizeof(*state));
@@ -150,6 +154,14 @@ static void am_state_init(struct am_state *state)
 
        if (!git_config_get_bool("commit.gpgsign", &gpgsign))
                state->sign_commit = gpgsign ? "" : NULL;
+
+       committer = git_committer_info(IDENT_STRICT);
+       if (split_ident_line(&id, committer, strlen(committer)) < 0)
+               die(_("invalid committer: %s"), committer);
+       state->committer_name =
+               xmemdupz(id.name_begin, id.name_end - id.name_begin);
+       state->committer_email =
+               xmemdupz(id.mail_begin, id.mail_end - id.mail_end);
 }
 
 /**
@@ -161,6 +173,8 @@ static void am_state_release(struct am_state *state)
        free(state->author_name);
        free(state->author_email);
        free(state->author_date);
+       free(state->committer_name);
+       free(state->committer_email);
        free(state->msg);
        strvec_clear(&state->git_apply_opts);
 }
@@ -1556,7 +1570,7 @@ static void do_commit(const struct am_state *state)
        struct object_id tree, parent, commit;
        const struct object_id *old_oid;
        struct commit_list *parents = NULL;
-       const char *reflog_msg, *author;
+       const char *reflog_msg, *author, *committer = NULL;
        struct strbuf sb = STRBUF_INIT;
 
        if (run_hook_le(NULL, "pre-applypatch", NULL))
@@ -1580,11 +1594,15 @@ static void do_commit(const struct am_state *state)
                        IDENT_STRICT);
 
        if (state->committer_date_is_author_date)
-               setenv("GIT_COMMITTER_DATE",
-                       state->ignore_date ? "" : state->author_date, 1);
-
-       if (commit_tree(state->msg, state->msg_len, &tree, parents, &commit,
-                       author, state->sign_commit))
+               committer = fmt_ident(state->committer_name,
+                                     state->author_email, WANT_COMMITTER_IDENT,
+                                     state->ignore_date ? NULL
+                                                        : state->author_date,
+                                     IDENT_STRICT);
+
+       if (commit_tree_extended(state->msg, state->msg_len, &tree, parents,
+                                &commit, author, committer, state->sign_commit,
+                                NULL))
                die(_("failed to write commit object"));
 
        reflog_msg = getenv("GIT_REFLOG_ACTION");
index cdda279b23ca3c8ede39058a52a1b3a0f303b43d..7dcc1b518831fed008f0f06463554099d60cff68 100644 (file)
@@ -27,7 +27,7 @@ static const char * const git_bisect_helper_usage[] = {
        N_("git bisect--helper --bisect-check-and-set-terms <command> <good_term> <bad_term>"),
        N_("git bisect--helper --bisect-next-check <good_term> <bad_term> [<term>]"),
        N_("git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]"),
-       N_("git bisect--helper --bisect-start [--term-{old,good}=<term> --term-{new,bad}=<term>]"
+       N_("git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
                                            " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
        NULL
 };
similarity index 96%
rename from bugreport.c
rename to builtin/bugreport.c
index 7ca0fba1b8ed46a86290bd6ed966cb9aa8233de6..3ad4b9b62e8498c51d550358bc63724b74eabbce 100644 (file)
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "builtin.h"
 #include "parse-options.h"
 #include "strbuf.h"
 #include "help.h"
@@ -119,7 +119,7 @@ static void get_header(struct strbuf *buf, const char *title)
        strbuf_addf(buf, "\n\n[%s]\n", title);
 }
 
-int cmd_main(int argc, const char **argv)
+int cmd_bugreport(int argc, const char **argv, const char *prefix)
 {
        struct strbuf buffer = STRBUF_INIT;
        struct strbuf report_path = STRBUF_INIT;
@@ -127,8 +127,6 @@ int cmd_main(int argc, const char **argv)
        time_t now = time(NULL);
        char *option_output = NULL;
        char *option_suffix = "%Y-%m-%d-%H%M";
-       int nongit_ok = 0;
-       const char *prefix = NULL;
        const char *user_relative_path = NULL;
 
        const struct option bugreport_options[] = {
@@ -139,8 +137,6 @@ int cmd_main(int argc, const char **argv)
                OPT_END()
        };
 
-       prefix = setup_git_directory_gently(&nongit_ok);
-
        argc = parse_options(argc, argv, prefix, bugreport_options,
                             bugreport_usage, 0);
 
@@ -170,7 +166,7 @@ int cmd_main(int argc, const char **argv)
        get_system_info(&buffer);
 
        get_header(&buffer, _("Enabled Hooks"));
-       get_populated_hooks(&buffer, nongit_ok);
+       get_populated_hooks(&buffer, !startup_info->have_repository);
 
        /* fopen doesn't offer us an O_EXCL alternative, except with glibc. */
        report = open(report_path.buf, O_CREAT | O_EXCL | O_WRONLY, 0666);
index bba64108af1e077a517c0de43aa4a9c18e342232..6ec82097a2a29c73d0b69a9329c93d8057dbb955 100644 (file)
@@ -1709,6 +1709,8 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
                die(_("--pathspec-file-nul requires --pathspec-from-file"));
        }
 
+       opts->pathspec.recursive = 1;
+
        if (opts->pathspec.nr) {
                if (1 < !!opts->writeout_stage + !!opts->force + !!opts->merge)
                        die(_("git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
index 69ac78d5e524f49e5da993e16cf3b74cf080926e..5d91b13a5c37e0e1477d05d86cfdd53fe21995a4 100644 (file)
@@ -847,21 +847,19 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
                        if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
                                !merge_contains_scissors)
                                wt_status_add_cut_line(s->fp);
-                       status_printf_ln(s, GIT_COLOR_NORMAL,
-                           whence == FROM_MERGE
-                               ? _("\n"
-                                       "It looks like you may be committing a merge.\n"
-                                       "If this is not correct, please remove the file\n"
-                                       "       %s\n"
-                                       "and try again.\n")
-                               : _("\n"
-                                       "It looks like you may be committing a cherry-pick.\n"
-                                       "If this is not correct, please remove the file\n"
-                                       "       %s\n"
-                                       "and try again.\n"),
+                       status_printf_ln(
+                               s, GIT_COLOR_NORMAL,
                                whence == FROM_MERGE ?
-                                       git_path_merge_head(the_repository) :
-                                       git_path_cherry_pick_head(the_repository));
+                                             _("\n"
+                                         "It looks like you may be committing a merge.\n"
+                                         "If this is not correct, please run\n"
+                                         "     git update-ref -d MERGE_HEAD\n"
+                                         "and try again.\n") :
+                                             _("\n"
+                                         "It looks like you may be committing a cherry-pick.\n"
+                                         "If this is not correct, please run\n"
+                                         "     git update-ref -d CHERRY_PICK_HEAD\n"
+                                         "and try again.\n"));
                }
 
                fprintf(s->fp, "\n");
@@ -1674,8 +1672,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
        }
 
        if (commit_tree_extended(sb.buf, sb.len, &active_cache_tree->oid,
-                                parents, &oid, author_ident.buf, sign_commit,
-                                extra)) {
+                                parents, &oid, author_ident.buf, NULL,
+                                sign_commit, extra)) {
                rollback_index_files();
                die(_("failed to write commit object"));
        }
similarity index 91%
rename from credential-cache--daemon.c
rename to builtin/credential-cache--daemon.c
index ec1271f89ce08b3b117fe09715f61730c7943bea..c61f123a3b81beef04d418142d0fae8b0ffd9dbe 100644 (file)
@@ -1,9 +1,12 @@
-#include "cache.h"
+#include "builtin.h"
+#include "parse-options.h"
+
+#ifndef NO_UNIX_SOCKETS
+
 #include "config.h"
 #include "tempfile.h"
 #include "credential.h"
 #include "unix-socket.h"
-#include "parse-options.h"
 
 struct credential_cache_entry {
        struct credential item;
@@ -257,7 +260,7 @@ static void init_socket_directory(const char *path)
        free(path_copy);
 }
 
-int cmd_main(int argc, const char **argv)
+int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix)
 {
        struct tempfile *socket_file;
        const char *socket_path;
@@ -275,7 +278,7 @@ int cmd_main(int argc, const char **argv)
 
        git_config_get_bool("credentialcache.ignoresighup", &ignore_sighup);
 
-       argc = parse_options(argc, argv, NULL, options, usage, 0);
+       argc = parse_options(argc, argv, prefix, options, usage, 0);
        socket_path = argv[0];
 
        if (!socket_path)
@@ -295,3 +298,21 @@ int cmd_main(int argc, const char **argv)
 
        return 0;
 }
+
+#else
+
+int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix)
+{
+       const char * const usage[] = {
+               "git credential-cache--daemon [options] <action>",
+               "",
+               "credential-cache--daemon is disabled in this build of Git",
+               NULL
+       };
+       struct option options[] = { OPT_END() };
+
+       argc = parse_options(argc, argv, prefix, options, usage, 0);
+       die(_("credential-cache--daemon unavailable; no unix socket support"));
+}
+
+#endif /* NO_UNIX_SOCKET */
similarity index 80%
rename from credential-cache.c
rename to builtin/credential-cache.c
index 1cccc3a0b9cfb2a14e9c87d5afc29234fa62adc4..9b3f709905979ef213e76069b573390f4eda7333 100644 (file)
@@ -1,7 +1,10 @@
-#include "cache.h"
+#include "builtin.h"
+#include "parse-options.h"
+
+#ifndef NO_UNIX_SOCKETS
+
 #include "credential.h"
 #include "string-list.h"
-#include "parse-options.h"
 #include "unix-socket.h"
 #include "run-command.h"
 
@@ -39,13 +42,13 @@ static int send_request(const char *socket, const struct strbuf *out)
 static void spawn_daemon(const char *socket)
 {
        struct child_process daemon = CHILD_PROCESS_INIT;
-       const char *argv[] = { NULL, NULL, NULL };
        char buf[128];
        int r;
 
-       argv[0] = "git-credential-cache--daemon";
-       argv[1] = socket;
-       daemon.argv = argv;
+       strvec_pushl(&daemon.args,
+                    "credential-cache--daemon", socket,
+                    NULL);
+       daemon.git_cmd = 1;
        daemon.no_stdin = 1;
        daemon.out = -1;
 
@@ -96,7 +99,7 @@ static char *get_socket_path(void)
        return socket;
 }
 
-int cmd_main(int argc, const char **argv)
+int cmd_credential_cache(int argc, const char **argv, const char *prefix)
 {
        char *socket_path = NULL;
        int timeout = 900;
@@ -113,7 +116,7 @@ int cmd_main(int argc, const char **argv)
                OPT_END()
        };
 
-       argc = parse_options(argc, argv, NULL, options, usage, 0);
+       argc = parse_options(argc, argv, prefix, options, usage, 0);
        if (!argc)
                usage_with_options(usage, options);
        op = argv[0];
@@ -134,3 +137,21 @@ int cmd_main(int argc, const char **argv)
 
        return 0;
 }
+
+#else
+
+int cmd_credential_cache(int argc, const char **argv, const char *prefix)
+{
+       const char * const usage[] = {
+               "git credential-cache [options] <action>",
+               "",
+               "credential-cache is disabled in this build of Git",
+               NULL
+       };
+       struct option options[] = { OPT_END() };
+
+       argc = parse_options(argc, argv, prefix, options, usage, 0);
+       die(_("credential-cache unavailable; no unix socket support"));
+}
+
+#endif /* NO_UNIX_SOCKETS */
similarity index 96%
rename from credential-store.c
rename to builtin/credential-store.c
index 294e77168156225efcb3b6840bc1dd7883c6dcac..5331ab151a6f6052dc532ab32875f864070e3b72 100644 (file)
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "builtin.h"
 #include "lockfile.h"
 #include "credential.h"
 #include "string-list.h"
@@ -143,7 +143,7 @@ static void lookup_credential(const struct string_list *fns, struct credential *
                        return; /* Found credential */
 }
 
-int cmd_main(int argc, const char **argv)
+int cmd_credential_store(int argc, const char **argv, const char *prefix)
 {
        const char * const usage[] = {
                "git credential-store [<options>] <action>",
@@ -161,7 +161,7 @@ int cmd_main(int argc, const char **argv)
 
        umask(077);
 
-       argc = parse_options(argc, (const char **)argv, NULL, options, usage, 0);
+       argc = parse_options(argc, (const char **)argv, prefix, options, usage, 0);
        if (argc != 1)
                usage_with_options(usage, options);
        op = argv[0];
similarity index 99%
rename from fast-import.c
rename to builtin/fast-import.c
index c45fe7474c6b83f5591554e994fb30407cdc5c8a..1c85eafe43eb2a4ed46b5aa2687eedf72fe61d54 100644 (file)
@@ -3511,14 +3511,13 @@ static void parse_argv(void)
        build_mark_map(&sub_marks_from, &sub_marks_to);
 }
 
-int cmd_main(int argc, const char **argv)
+int cmd_fast_import(int argc, const char **argv, const char *prefix)
 {
        unsigned int i;
 
        if (argc == 2 && !strcmp(argv[1], "-h"))
                usage(fast_import_usage);
 
-       setup_git_directory();
        reset_pack_idx_option(&pack_idx_opts);
        git_pack_config();
 
index bbb5c96167017fe7f718d3fae5d9f726e928d142..58b7c1fbdc47b7f3bf866e1e9bcdf924a10e8033 100644 (file)
@@ -153,10 +153,6 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
                        args.from_promisor = 1;
                        continue;
                }
-               if (!strcmp("--no-dependents", arg)) {
-                       args.no_dependents = 1;
-                       continue;
-               }
                if (skip_prefix(arg, ("--" CL_ARG__FILTER "="), &arg)) {
                        parse_list_objects_filter(&args.filter_options, arg);
                        continue;
index 0f23dd4b8ce942dae6b9a5a0ee6352b225b99e43..a6d326866112758f62b50d7b36eab1314bda5e6f 100644 (file)
@@ -80,6 +80,7 @@ static struct list_objects_filter_options filter_options;
 static struct string_list server_options = STRING_LIST_INIT_DUP;
 static struct string_list negotiation_tip = STRING_LIST_INIT_NODUP;
 static int fetch_write_commit_graph = -1;
+static int stdin_refspecs = 0;
 
 static int git_fetch_config(const char *k, const char *v, void *cb)
 {
@@ -205,6 +206,8 @@ static struct option builtin_fetch_options[] = {
                 N_("check for forced-updates on all updated branches")),
        OPT_BOOL(0, "write-commit-graph", &fetch_write_commit_graph,
                 N_("write the commit-graph after fetching")),
+       OPT_BOOL(0, "stdin", &stdin_refspecs,
+                N_("accept refspecs from stdin")),
        OPT_END()
 };
 
@@ -442,6 +445,7 @@ static struct ref *get_ref_map(struct remote *remote,
        struct ref *orefs = NULL, **oref_tail = &orefs;
 
        struct hashmap existing_refs;
+       int existing_refs_populated = 0;
 
        if (rs->nr) {
                struct refspec *fetch_refspec;
@@ -535,15 +539,18 @@ static struct ref *get_ref_map(struct remote *remote,
 
        ref_map = ref_remove_duplicates(ref_map);
 
-       refname_hash_init(&existing_refs);
-       for_each_ref(add_one_refname, &existing_refs);
-
        for (rm = ref_map; rm; rm = rm->next) {
                if (rm->peer_ref) {
                        const char *refname = rm->peer_ref->name;
                        struct refname_hash_entry *peer_item;
                        unsigned int hash = strhash(refname);
 
+                       if (!existing_refs_populated) {
+                               refname_hash_init(&existing_refs);
+                               for_each_ref(add_one_refname, &existing_refs);
+                               existing_refs_populated = 1;
+                       }
+
                        peer_item = hashmap_get_entry_from_hash(&existing_refs,
                                                hash, refname,
                                                struct refname_hash_entry, ent);
@@ -553,7 +560,8 @@ static struct ref *get_ref_map(struct remote *remote,
                        }
                }
        }
-       hashmap_free_entries(&existing_refs, struct refname_hash_entry, ent);
+       if (existing_refs_populated)
+               hashmap_free_entries(&existing_refs, struct refname_hash_entry, ent);
 
        return ref_map;
 }
@@ -1015,11 +1023,17 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
                                rc |= update_local_ref(ref, what, rm, &note,
                                                       summary_width);
                                free(ref);
-                       } else
+                       } else if (write_fetch_head || dry_run) {
+                               /*
+                                * Display fetches written to FETCH_HEAD (or
+                                * would be written to FETCH_HEAD, if --dry-run
+                                * is set).
+                                */
                                format_display(&note, '*',
                                               *kind ? kind : "branch", NULL,
                                               *what ? what : "HEAD",
                                               "FETCH_HEAD", summary_width);
+                       }
                        if (note.len) {
                                if (verbosity >= 0 && !shown_url) {
                                        fprintf(stderr, _("From %.*s\n"),
@@ -1680,7 +1694,8 @@ static inline void fetch_one_setup_partial(struct remote *remote)
        return;
 }
 
-static int fetch_one(struct remote *remote, int argc, const char **argv, int prune_tags_ok)
+static int fetch_one(struct remote *remote, int argc, const char **argv,
+                    int prune_tags_ok, int use_stdin_refspecs)
 {
        struct refspec rs = REFSPEC_INIT_FETCH;
        int i;
@@ -1737,6 +1752,13 @@ static int fetch_one(struct remote *remote, int argc, const char **argv, int pru
                }
        }
 
+       if (use_stdin_refspecs) {
+               struct strbuf line = STRBUF_INIT;
+               while (strbuf_getline_lf(&line, stdin) != EOF)
+                       refspec_append(&rs, line.buf);
+               strbuf_release(&line);
+       }
+
        if (server_options.nr)
                gtransport->server_options = &server_options;
 
@@ -1771,12 +1793,18 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
                free(anon);
        }
 
-       fetch_config_from_gitmodules(&submodule_fetch_jobs_config,
-                                    &recurse_submodules);
        git_config(git_fetch_config, NULL);
 
        argc = parse_options(argc, argv, prefix,
                             builtin_fetch_options, builtin_fetch_usage, 0);
+       if (recurse_submodules != RECURSE_SUBMODULES_OFF) {
+               int *sfjc = submodule_fetch_jobs_config == -1
+                           ? &submodule_fetch_jobs_config : NULL;
+               int *rs = recurse_submodules == RECURSE_SUBMODULES_DEFAULT
+                         ? &recurse_submodules : NULL;
+
+               fetch_config_from_gitmodules(sfjc, rs);
+       }
 
        if (deepen_relative) {
                if (deepen_relative < 0)
@@ -1837,7 +1865,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
        if (remote) {
                if (filter_options.choice || has_promisor_remote())
                        fetch_one_setup_partial(remote);
-               result = fetch_one(remote, argc, argv, prune_tags_ok);
+               result = fetch_one(remote, argc, argv, prune_tags_ok, stdin_refspecs);
        } else {
                int max_children = max_jobs;
 
@@ -1845,6 +1873,10 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
                        die(_("--filter can only be used with the remote "
                              "configured in extensions.partialclone"));
 
+               if (stdin_refspecs)
+                       die(_("--stdin can only be used when fetching "
+                             "from one remote"));
+
                if (max_children < 0)
                        max_children = fetch_parallel_config;
 
index f865666db9ee62ba0b1dd60111912b233df47d7c..9721bf1ffe8eafad1d002203541d6a9d30a91f8e 100644 (file)
@@ -1798,9 +1798,22 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
 
        if (HAVE_THREADS && !nr_threads) {
                nr_threads = online_cpus();
-               /* An experiment showed that more threads does not mean faster */
-               if (nr_threads > 3)
-                       nr_threads = 3;
+               /*
+                * Experiments show that going above 20 threads doesn't help,
+                * no matter how many cores you have. Below that, we tend to
+                * max at half the number of online_cpus(), presumably because
+                * half of those are hyperthreads rather than full cores. We'll
+                * never reduce the level below "3", though, to match a
+                * historical value that nobody complained about.
+                */
+               if (nr_threads < 4)
+                       ; /* too few cores to consider capping */
+               else if (nr_threads < 6)
+                       nr_threads = 3; /* historic cap */
+               else if (nr_threads < 40)
+                       nr_threads /= 2;
+               else
+                       nr_threads = 20; /* hard cap */
        }
 
        curr_pack = open_pack_file(pack_name);
index bbc9bc78f9d5a32ed9d167a79426ba0329bdea95..cd3e7605417dad82417294644b9f6de376792379 100644 (file)
@@ -9,6 +9,7 @@
 #include "builtin.h"
 #include "exec-cmd.h"
 #include "parse-options.h"
+#include "worktree.h"
 
 #ifndef DEFAULT_GIT_TEMPLATE_DIR
 #define DEFAULT_GIT_TEMPLATE_DIR "/usr/share/git-core/templates"
@@ -364,6 +365,7 @@ static void separate_git_dir(const char *git_dir, const char *git_link)
 
                if (rename(src, git_dir))
                        die_errno(_("unable to move %s to %s"), src, git_dir);
+               repair_worktrees(NULL, NULL);
        }
 
        write_file(git_link, "gitdir: %s", git_dir);
@@ -640,6 +642,30 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
        if (!git_dir)
                git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
 
+       /*
+        * When --separate-git-dir is used inside a linked worktree, take
+        * care to ensure that the common .git/ directory is relocated, not
+        * the worktree-specific .git/worktrees/<id>/ directory.
+        */
+       if (real_git_dir) {
+               int err;
+               const char *p;
+               struct strbuf sb = STRBUF_INIT;
+
+               p = read_gitfile_gently(git_dir, &err);
+               if (p && get_common_dir(&sb, p)) {
+                       struct strbuf mainwt = STRBUF_INIT;
+
+                       strbuf_addbuf(&mainwt, &sb);
+                       strbuf_strip_suffix(&mainwt, "/.git");
+                       if (chdir(mainwt.buf) < 0)
+                               die_errno(_("cannot chdir to %s"), mainwt.buf);
+                       strbuf_release(&mainwt);
+                       git_dir = strbuf_detach(&sb, NULL);
+               }
+               strbuf_release(&sb);
+       }
+
        if (is_bare_repository_cfg < 0)
                is_bare_repository_cfg = guess_repository_type(git_dir);
 
index 74829a838e2104868aef6401ba945e7e84952820..b9a89ba858a366a162ea21a54a63c857f70278c7 100644 (file)
@@ -1348,7 +1348,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                else
                        die(_("You have not concluded your merge (MERGE_HEAD exists)."));
        }
-       if (file_exists(git_path_cherry_pick_head(the_repository))) {
+       if (ref_exists("CHERRY_PICK_HEAD")) {
                if (advice_resolve_conflict)
                        die(_("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
                            "Please, commit your changes before you merge."));
index dadb52fa92e7f28e0c81b27b74b9a23b289e4be9..c4ff2039ef08635798365084f4a9a2847c280ba6 100644 (file)
@@ -92,6 +92,8 @@ struct rebase_options {
        int autosquash;
        char *gpg_sign_opt;
        int autostash;
+       int committer_date_is_author_date;
+       int ignore_date;
        char *cmd;
        int allow_empty_message;
        int rebase_merges, rebase_cousins;
@@ -130,8 +132,12 @@ static struct replay_opts get_replay_opts(const struct rebase_options *opts)
        replay.quiet = !(opts->flags & REBASE_NO_QUIET);
        replay.verbose = opts->flags & REBASE_VERBOSE;
        replay.reschedule_failed_exec = opts->reschedule_failed_exec;
+       replay.committer_date_is_author_date =
+                                       opts->committer_date_is_author_date;
+       replay.ignore_date = opts->ignore_date;
        replay.gpg_sign = xstrdup_or_null(opts->gpg_sign_opt);
        replay.strategy = opts->strategy;
+
        if (opts->strategy_opts)
                parse_strategy_opts(&replay, opts->strategy_opts);
 
@@ -1289,6 +1295,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
        struct strbuf revisions = STRBUF_INIT;
        struct strbuf buf = STRBUF_INIT;
        struct object_id merge_base;
+       int ignore_whitespace = 0;
        enum action action = ACTION_NONE;
        const char *gpg_sign = NULL;
        struct string_list exec = STRING_LIST_INIT_NODUP;
@@ -1318,16 +1325,17 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                        PARSE_OPT_NOARG, NULL, REBASE_DIFFSTAT },
                OPT_BOOL(0, "signoff", &options.signoff,
                         N_("add a Signed-off-by: line to each commit")),
-               OPT_PASSTHRU_ARGV(0, "ignore-whitespace", &options.git_am_opts,
-                                 NULL, N_("passed to 'git am'"),
-                                 PARSE_OPT_NOARG),
-               OPT_PASSTHRU_ARGV(0, "committer-date-is-author-date",
-                                 &options.git_am_opts, NULL,
-                                 N_("passed to 'git am'"), PARSE_OPT_NOARG),
-               OPT_PASSTHRU_ARGV(0, "ignore-date", &options.git_am_opts, NULL,
-                                 N_("passed to 'git am'"), PARSE_OPT_NOARG),
+               OPT_BOOL(0, "committer-date-is-author-date",
+                        &options.committer_date_is_author_date,
+                        N_("make committer date match author date")),
+               OPT_BOOL(0, "reset-author-date", &options.ignore_date,
+                        N_("ignore author date and use current date")),
+               OPT_HIDDEN_BOOL(0, "ignore-date", &options.ignore_date,
+                               N_("synonym of --reset-author-date")),
                OPT_PASSTHRU_ARGV('C', NULL, &options.git_am_opts, N_("n"),
                                  N_("passed to 'git apply'"), 0),
+               OPT_BOOL(0, "ignore-whitespace", &ignore_whitespace,
+                        N_("ignore changes in whitespace")),
                OPT_PASSTHRU_ARGV(0, "whitespace", &options.git_am_opts,
                                  N_("action"), N_("passed to 'git apply'"), 0),
                OPT_BIT('f', "force-rebase", &options.flags,
@@ -1624,12 +1632,12 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
            options.autosquash) {
                allow_preemptive_ff = 0;
        }
+       if (options.committer_date_is_author_date || options.ignore_date)
+               options.flags |= REBASE_FORCE;
 
        for (i = 0; i < options.git_am_opts.nr; i++) {
                const char *option = options.git_am_opts.v[i], *p;
-               if (!strcmp(option, "--committer-date-is-author-date") ||
-                   !strcmp(option, "--ignore-date") ||
-                   !strcmp(option, "--whitespace=fix") ||
+               if (!strcmp(option, "--whitespace=fix") ||
                    !strcmp(option, "--whitespace=strip"))
                        allow_preemptive_ff = 0;
                else if (skip_prefix(option, "-C", &p)) {
@@ -1682,6 +1690,23 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                imply_merge(&options, "--rebase-merges");
        }
 
+       if (options.type == REBASE_APPLY) {
+               if (ignore_whitespace)
+                       strvec_push(&options.git_am_opts,
+                                   "--ignore-whitespace");
+               if (options.committer_date_is_author_date)
+                       strvec_push(&options.git_am_opts,
+                                   "--committer-date-is-author-date");
+               if (options.ignore_date)
+                       strvec_push(&options.git_am_opts, "--ignore-date");
+       } else {
+               /* REBASE_MERGE and PRESERVE_MERGES */
+               if (ignore_whitespace) {
+                       string_list_append(&strategy_options,
+                                          "ignore-space-change");
+               }
+       }
+
        if (strategy_options.nr) {
                int i;
 
index c8240e9fcd58b838086dc667414dc78fb3f2912a..542f56e3878b6694e7da6c6141b5e249c511a51e 100644 (file)
@@ -478,6 +478,7 @@ static int get_head_names(const struct ref *remote_refs, struct ref_states *stat
        struct ref *fetch_map = NULL, **fetch_map_tail = &fetch_map;
        struct refspec_item refspec;
 
+       memset(&refspec, 0, sizeof(refspec));
        refspec.force = 0;
        refspec.pattern = 1;
        refspec.src = refspec.dst = "refs/heads/*";
index 04c5ceaf7ec7e6de32b21d4a07ebb8384ee3068f..01e7767c792866086ca889d7ea9d0310238c7c84 100644 (file)
@@ -133,7 +133,11 @@ static void get_non_kept_pack_filenames(struct string_list *fname_list,
 static void remove_redundant_pack(const char *dir_name, const char *base_name)
 {
        struct strbuf buf = STRBUF_INIT;
-       strbuf_addf(&buf, "%s/%s.pack", dir_name, base_name);
+       struct multi_pack_index *m = get_local_multi_pack_index(the_repository);
+       strbuf_addf(&buf, "%s.pack", base_name);
+       if (m && midx_contains_pack(m, buf.buf))
+               clear_midx_file(the_repository);
+       strbuf_insertf(&buf, 0, "%s/", dir_name);
        unlink_pack_path(buf.buf, 1);
        strbuf_release(&buf);
 }
@@ -286,7 +290,6 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
        int keep_unreachable = 0;
        struct string_list keep_pack_list = STRING_LIST_INIT_NODUP;
        int no_update_server_info = 0;
-       int midx_cleared = 0;
        struct pack_objects_args po_args = {NULL};
 
        struct option builtin_repack_options[] = {
@@ -439,11 +442,6 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
                for (ext = 0; ext < ARRAY_SIZE(exts); ext++) {
                        char *fname, *fname_old;
 
-                       if (!midx_cleared) {
-                               clear_midx_file(the_repository);
-                               midx_cleared = 1;
-                       }
-
                        fname = mkpathdup("%s/pack-%s%s", packdir,
                                                item->string, exts[ext].name);
                        if (!file_exists(fname)) {
index a59d8e4bda615cf843515da2312febdf2c72c213..b9df79befc0773ca4821654011d83efe8ea8fd40 100644 (file)
@@ -612,7 +612,6 @@ struct init_cb {
        const char *prefix;
        unsigned int flags;
 };
-
 #define INIT_CB_INIT { NULL, 0 }
 
 static void init_submodule(const char *path, const char *prefix,
@@ -742,7 +741,6 @@ struct status_cb {
        const char *prefix;
        unsigned int flags;
 };
-
 #define STATUS_CB_INIT { NULL, 0 }
 
 static void print_status(unsigned int flags, char state, const char *path,
@@ -929,11 +927,438 @@ static int module_name(int argc, const char **argv, const char *prefix)
        return 0;
 }
 
+struct module_cb {
+       unsigned int mod_src;
+       unsigned int mod_dst;
+       struct object_id oid_src;
+       struct object_id oid_dst;
+       char status;
+       const char *sm_path;
+};
+#define MODULE_CB_INIT { 0, 0, NULL, NULL, '\0', NULL }
+
+struct module_cb_list {
+       struct module_cb **entries;
+       int alloc, nr;
+};
+#define MODULE_CB_LIST_INIT { NULL, 0, 0 }
+
+struct summary_cb {
+       int argc;
+       const char **argv;
+       const char *prefix;
+       unsigned int cached: 1;
+       unsigned int for_status: 1;
+       unsigned int files: 1;
+       int summary_limit;
+};
+#define SUMMARY_CB_INIT { 0, NULL, NULL, 0, 0, 0, 0 }
+
+enum diff_cmd {
+       DIFF_INDEX,
+       DIFF_FILES
+};
+
+static char* verify_submodule_committish(const char *sm_path,
+                                        const char *committish)
+{
+       struct child_process cp_rev_parse = CHILD_PROCESS_INIT;
+       struct strbuf result = STRBUF_INIT;
+
+       cp_rev_parse.git_cmd = 1;
+       cp_rev_parse.dir = sm_path;
+       prepare_submodule_repo_env(&cp_rev_parse.env_array);
+       strvec_pushl(&cp_rev_parse.args, "rev-parse", "-q", "--short", NULL);
+       strvec_pushf(&cp_rev_parse.args, "%s^0", committish);
+       strvec_push(&cp_rev_parse.args, "--");
+
+       if (capture_command(&cp_rev_parse, &result, 0))
+               return NULL;
+
+       strbuf_trim_trailing_newline(&result);
+       return strbuf_detach(&result, NULL);
+}
+
+static void print_submodule_summary(struct summary_cb *info, char* errmsg,
+                                   int total_commits, const char *displaypath,
+                                   const char *src_abbrev, const char *dst_abbrev,
+                                   int missing_src, int missing_dst,
+                                   struct module_cb *p)
+{
+       if (p->status == 'T') {
+               if (S_ISGITLINK(p->mod_dst))
+                       printf(_("* %s %s(blob)->%s(submodule)"),
+                                displaypath, src_abbrev, dst_abbrev);
+               else
+                       printf(_("* %s %s(submodule)->%s(blob)"),
+                                displaypath, src_abbrev, dst_abbrev);
+       } else {
+               printf("* %s %s...%s",
+                       displaypath, src_abbrev, dst_abbrev);
+       }
+
+       if (total_commits < 0)
+               printf(":\n");
+       else
+               printf(" (%d):\n", total_commits);
+
+       if (errmsg) {
+               printf(_("%s"), errmsg);
+       } else if (total_commits > 0) {
+               struct child_process cp_log = CHILD_PROCESS_INIT;
+
+               cp_log.git_cmd = 1;
+               cp_log.dir = p->sm_path;
+               prepare_submodule_repo_env(&cp_log.env_array);
+               strvec_pushl(&cp_log.args, "log", NULL);
+
+               if (S_ISGITLINK(p->mod_src) && S_ISGITLINK(p->mod_dst)) {
+                       if (info->summary_limit > 0)
+                               strvec_pushf(&cp_log.args, "-%d",
+                                            info->summary_limit);
+
+                       strvec_pushl(&cp_log.args, "--pretty=  %m %s",
+                                    "--first-parent", NULL);
+                       strvec_pushf(&cp_log.args, "%s...%s",
+                                    src_abbrev, dst_abbrev);
+               } else if (S_ISGITLINK(p->mod_dst)) {
+                       strvec_pushl(&cp_log.args, "--pretty=  > %s",
+                                    "-1", dst_abbrev, NULL);
+               } else {
+                       strvec_pushl(&cp_log.args, "--pretty=  < %s",
+                                    "-1", src_abbrev, NULL);
+               }
+               run_command(&cp_log);
+       }
+       printf("\n");
+}
+
+static void generate_submodule_summary(struct summary_cb *info,
+                                      struct module_cb *p)
+{
+       char *displaypath, *src_abbrev, *dst_abbrev;
+       int missing_src = 0, missing_dst = 0;
+       char *errmsg = NULL;
+       int total_commits = -1;
+
+       if (!info->cached && oideq(&p->oid_dst, &null_oid)) {
+               if (S_ISGITLINK(p->mod_dst)) {
+                       struct ref_store *refs = get_submodule_ref_store(p->sm_path);
+                       if (refs)
+                               refs_head_ref(refs, handle_submodule_head_ref, &p->oid_dst);
+               } else if (S_ISLNK(p->mod_dst) || S_ISREG(p->mod_dst)) {
+                       struct stat st;
+                       int fd = open(p->sm_path, O_RDONLY);
+
+                       if (fd < 0 || fstat(fd, &st) < 0 ||
+                           index_fd(&the_index, &p->oid_dst, fd, &st, OBJ_BLOB,
+                                    p->sm_path, 0))
+                               error(_("couldn't hash object from '%s'"), p->sm_path);
+               } else {
+                       /* for a submodule removal (mode:0000000), don't warn */
+                       if (p->mod_dst)
+                               warning(_("unexpected mode %d\n"), p->mod_dst);
+               }
+       }
+
+       if (S_ISGITLINK(p->mod_src)) {
+               src_abbrev = verify_submodule_committish(p->sm_path,
+                                                        oid_to_hex(&p->oid_src));
+               if (!src_abbrev) {
+                       missing_src = 1;
+                       /*
+                        * As `rev-parse` failed, we fallback to getting
+                        * the abbreviated hash using oid_src. We do
+                        * this as we might still need the abbreviated
+                        * hash in cases like a submodule type change, etc.
+                        */
+                       src_abbrev = xstrndup(oid_to_hex(&p->oid_src), 7);
+               }
+       } else {
+               /*
+                * The source does not point to a submodule.
+                * So, we fallback to getting the abbreviation using
+                * oid_src as we might still need the abbreviated
+                * hash in cases like submodule add, etc.
+                */
+               src_abbrev = xstrndup(oid_to_hex(&p->oid_src), 7);
+       }
+
+       if (S_ISGITLINK(p->mod_dst)) {
+               dst_abbrev = verify_submodule_committish(p->sm_path,
+                                                        oid_to_hex(&p->oid_dst));
+               if (!dst_abbrev) {
+                       missing_dst = 1;
+                       /*
+                        * As `rev-parse` failed, we fallback to getting
+                        * the abbreviated hash using oid_dst. We do
+                        * this as we might still need the abbreviated
+                        * hash in cases like a submodule type change, etc.
+                        */
+                       dst_abbrev = xstrndup(oid_to_hex(&p->oid_dst), 7);
+               }
+       } else {
+               /*
+                * The destination does not point to a submodule.
+                * So, we fallback to getting the abbreviation using
+                * oid_dst as we might still need the abbreviated
+                * hash in cases like a submodule removal, etc.
+                */
+               dst_abbrev = xstrndup(oid_to_hex(&p->oid_dst), 7);
+       }
+
+       displaypath = get_submodule_displaypath(p->sm_path, info->prefix);
+
+       if (!missing_src && !missing_dst) {
+               struct child_process cp_rev_list = CHILD_PROCESS_INIT;
+               struct strbuf sb_rev_list = STRBUF_INIT;
+
+               strvec_pushl(&cp_rev_list.args, "rev-list",
+                            "--first-parent", "--count", NULL);
+               if (S_ISGITLINK(p->mod_src) && S_ISGITLINK(p->mod_dst))
+                       strvec_pushf(&cp_rev_list.args, "%s...%s",
+                                    src_abbrev, dst_abbrev);
+               else
+                       strvec_push(&cp_rev_list.args, S_ISGITLINK(p->mod_src) ?
+                                   src_abbrev : dst_abbrev);
+               strvec_push(&cp_rev_list.args, "--");
+
+               cp_rev_list.git_cmd = 1;
+               cp_rev_list.dir = p->sm_path;
+               prepare_submodule_repo_env(&cp_rev_list.env_array);
+
+               if (!capture_command(&cp_rev_list, &sb_rev_list, 0))
+                       total_commits = atoi(sb_rev_list.buf);
+
+               strbuf_release(&sb_rev_list);
+       } else {
+               /*
+                * Don't give error msg for modification whose dst is not
+                * submodule, i.e., deleted or changed to blob
+                */
+               if (S_ISGITLINK(p->mod_dst)) {
+                       struct strbuf errmsg_str = STRBUF_INIT;
+                       if (missing_src && missing_dst) {
+                               strbuf_addf(&errmsg_str, "  Warn: %s doesn't contain commits %s and %s\n",
+                                           displaypath, oid_to_hex(&p->oid_src),
+                                           oid_to_hex(&p->oid_dst));
+                       } else {
+                               strbuf_addf(&errmsg_str, "  Warn: %s doesn't contain commit %s\n",
+                                           displaypath, missing_src ?
+                                           oid_to_hex(&p->oid_src) :
+                                           oid_to_hex(&p->oid_dst));
+                       }
+                       errmsg = strbuf_detach(&errmsg_str, NULL);
+               }
+       }
+
+       print_submodule_summary(info, errmsg, total_commits,
+                               displaypath, src_abbrev,
+                               dst_abbrev, missing_src,
+                               missing_dst, p);
+
+       free(displaypath);
+       free(src_abbrev);
+       free(dst_abbrev);
+}
+
+static void prepare_submodule_summary(struct summary_cb *info,
+                                     struct module_cb_list *list)
+{
+       int i;
+       for (i = 0; i < list->nr; i++) {
+               const struct submodule *sub;
+               struct module_cb *p = list->entries[i];
+               struct strbuf sm_gitdir = STRBUF_INIT;
+
+               if (p->status == 'D' || p->status == 'T') {
+                       generate_submodule_summary(info, p);
+                       continue;
+               }
+
+               if (info->for_status && p->status != 'A' &&
+                   (sub = submodule_from_path(the_repository,
+                                              &null_oid, p->sm_path))) {
+                       char *config_key = NULL;
+                       const char *value;
+                       int ignore_all = 0;
+
+                       config_key = xstrfmt("submodule.%s.ignore",
+                                            sub->name);
+                       if (!git_config_get_string_tmp(config_key, &value))
+                               ignore_all = !strcmp(value, "all");
+                       else if (sub->ignore)
+                               ignore_all = !strcmp(sub->ignore, "all");
+
+                       free(config_key);
+                       if (ignore_all)
+                               continue;
+               }
+
+               /* Also show added or modified modules which are checked out */
+               strbuf_addstr(&sm_gitdir, p->sm_path);
+               if (is_nonbare_repository_dir(&sm_gitdir))
+                       generate_submodule_summary(info, p);
+               strbuf_release(&sm_gitdir);
+       }
+}
+
+static void submodule_summary_callback(struct diff_queue_struct *q,
+                                      struct diff_options *options,
+                                      void *data)
+{
+       int i;
+       struct module_cb_list *list = data;
+       for (i = 0; i < q->nr; i++) {
+               struct diff_filepair *p = q->queue[i];
+               struct module_cb *temp;
+
+               if (!S_ISGITLINK(p->one->mode) && !S_ISGITLINK(p->two->mode))
+                       continue;
+               temp = (struct module_cb*)malloc(sizeof(struct module_cb));
+               temp->mod_src = p->one->mode;
+               temp->mod_dst = p->two->mode;
+               temp->oid_src = p->one->oid;
+               temp->oid_dst = p->two->oid;
+               temp->status = p->status;
+               temp->sm_path = xstrdup(p->one->path);
+
+               ALLOC_GROW(list->entries, list->nr + 1, list->alloc);
+               list->entries[list->nr++] = temp;
+       }
+}
+
+static const char *get_diff_cmd(enum diff_cmd diff_cmd)
+{
+       switch (diff_cmd) {
+       case DIFF_INDEX: return "diff-index";
+       case DIFF_FILES: return "diff-files";
+       default: BUG("bad diff_cmd value %d", diff_cmd);
+       }
+}
+
+static int compute_summary_module_list(struct object_id *head_oid,
+                                      struct summary_cb *info,
+                                      enum diff_cmd diff_cmd)
+{
+       struct strvec diff_args = STRVEC_INIT;
+       struct rev_info rev;
+       struct module_cb_list list = MODULE_CB_LIST_INIT;
+
+       strvec_push(&diff_args, get_diff_cmd(diff_cmd));
+       if (info->cached)
+               strvec_push(&diff_args, "--cached");
+       strvec_pushl(&diff_args, "--ignore-submodules=dirty", "--raw", NULL);
+       if (head_oid)
+               strvec_push(&diff_args, oid_to_hex(head_oid));
+       strvec_push(&diff_args, "--");
+       if (info->argc)
+               strvec_pushv(&diff_args, info->argv);
+
+       git_config(git_diff_basic_config, NULL);
+       init_revisions(&rev, info->prefix);
+       rev.abbrev = 0;
+       precompose_argv(diff_args.nr, diff_args.v);
+       setup_revisions(diff_args.nr, diff_args.v, &rev, NULL);
+       rev.diffopt.output_format = DIFF_FORMAT_NO_OUTPUT | DIFF_FORMAT_CALLBACK;
+       rev.diffopt.format_callback = submodule_summary_callback;
+       rev.diffopt.format_callback_data = &list;
+
+       if (!info->cached) {
+               if (diff_cmd == DIFF_INDEX)
+                       setup_work_tree();
+               if (read_cache_preload(&rev.diffopt.pathspec) < 0) {
+                       perror("read_cache_preload");
+                       return -1;
+               }
+       } else if (read_cache() < 0) {
+               perror("read_cache");
+               return -1;
+       }
+
+       if (diff_cmd == DIFF_INDEX)
+               run_diff_index(&rev, info->cached);
+       else
+               run_diff_files(&rev, 0);
+       prepare_submodule_summary(info, &list);
+       strvec_clear(&diff_args);
+       return 0;
+}
+
+static int module_summary(int argc, const char **argv, const char *prefix)
+{
+       struct summary_cb info = SUMMARY_CB_INIT;
+       int cached = 0;
+       int for_status = 0;
+       int files = 0;
+       int summary_limit = -1;
+       enum diff_cmd diff_cmd = DIFF_INDEX;
+       struct object_id head_oid;
+       int ret;
+
+       struct option module_summary_options[] = {
+               OPT_BOOL(0, "cached", &cached,
+                        N_("use the commit stored in the index instead of the submodule HEAD")),
+               OPT_BOOL(0, "files", &files,
+                        N_("to compare the commit in the index with that in the submodule HEAD")),
+               OPT_BOOL(0, "for-status", &for_status,
+                        N_("skip submodules with 'ignore_config' value set to 'all'")),
+               OPT_INTEGER('n', "summary-limit", &summary_limit,
+                            N_("limit the summary size")),
+               OPT_END()
+       };
+
+       const char *const git_submodule_helper_usage[] = {
+               N_("git submodule--helper summary [<options>] [commit] [--] [<path>]"),
+               NULL
+       };
+
+       argc = parse_options(argc, argv, prefix, module_summary_options,
+                            git_submodule_helper_usage, 0);
+
+       if (!summary_limit)
+               return 0;
+
+       if (!get_oid(argc ? argv[0] : "HEAD", &head_oid)) {
+               if (argc) {
+                       argv++;
+                       argc--;
+               }
+       } else if (!argc || !strcmp(argv[0], "HEAD")) {
+               /* before the first commit: compare with an empty tree */
+               oidcpy(&head_oid, the_hash_algo->empty_tree);
+               if (argc) {
+                       argv++;
+                       argc--;
+               }
+       } else {
+               if (get_oid("HEAD", &head_oid))
+                       die(_("could not fetch a revision for HEAD"));
+       }
+
+       if (files) {
+               if (cached)
+                       die(_("--cached and --files are mutually exclusive"));
+               diff_cmd = DIFF_FILES;
+       }
+
+       info.argc = argc;
+       info.argv = argv;
+       info.prefix = prefix;
+       info.cached = !!cached;
+       info.files = !!files;
+       info.for_status = !!for_status;
+       info.summary_limit = summary_limit;
+
+       ret = compute_summary_module_list((diff_cmd == DIFF_INDEX) ? &head_oid : NULL,
+                                         &info, diff_cmd);
+       return ret;
+}
+
 struct sync_cb {
        const char *prefix;
        unsigned int flags;
 };
-
 #define SYNC_CB_INIT { NULL, 0 }
 
 static void sync_submodule(const char *path, const char *prefix,
@@ -2344,6 +2769,7 @@ static struct cmd_struct commands[] = {
        {"print-default-remote", print_default_remote, 0},
        {"sync", module_sync, SUPPORT_SUPER_PREFIX},
        {"deinit", module_deinit, 0},
+       {"summary", module_summary, SUPPORT_SUPER_PREFIX},
        {"remote-branch", resolve_remote_submodule_branch, 0},
        {"push-check", push_check, 0},
        {"absorb-git-dirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX},
index 378f332b5d07edb55b48559ba328f980b84927e6..bb70fde97e218580a6e0d5f39dbd00458196bfee 100644 (file)
@@ -924,7 +924,6 @@ static int move_worktree(int ac, const char **av, const char *prefix)
 static void check_clean_worktree(struct worktree *wt,
                                 const char *original_path)
 {
-       struct strvec child_env = STRVEC_INIT;
        struct child_process cp;
        char buf[1];
        int ret;
@@ -935,15 +934,14 @@ static void check_clean_worktree(struct worktree *wt,
         */
        validate_no_submodules(wt);
 
-       strvec_pushf(&child_env, "%s=%s/.git",
+       child_process_init(&cp);
+       strvec_pushf(&cp.env_array, "%s=%s/.git",
                     GIT_DIR_ENVIRONMENT, wt->path);
-       strvec_pushf(&child_env, "%s=%s",
+       strvec_pushf(&cp.env_array, "%s=%s",
                     GIT_WORK_TREE_ENVIRONMENT, wt->path);
-       memset(&cp, 0, sizeof(cp));
        strvec_pushl(&cp.args, "status",
                     "--porcelain", "--ignore-submodules=none",
                     NULL);
-       cp.env = child_env.v;
        cp.git_cmd = 1;
        cp.dir = wt->path;
        cp.out = -1;
@@ -1030,6 +1028,34 @@ static int remove_worktree(int ac, const char **av, const char *prefix)
        return ret;
 }
 
+static void report_repair(int iserr, const char *path, const char *msg, void *cb_data)
+{
+       if (!iserr) {
+               printf_ln(_("repair: %s: %s"), msg, path);
+       } else {
+               int *exit_status = (int *)cb_data;
+               fprintf_ln(stderr, _("error: %s: %s"), msg, path);
+               *exit_status = 1;
+       }
+}
+
+static int repair(int ac, const char **av, const char *prefix)
+{
+       const char **p;
+       const char *self[] = { ".", NULL };
+       struct option options[] = {
+               OPT_END()
+       };
+       int rc = 0;
+
+       ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
+       repair_worktrees(report_repair, &rc);
+       p = ac > 0 ? av : self;
+       for (; *p; p++)
+               repair_worktree_at_path(*p, report_repair, &rc);
+       return rc;
+}
+
 int cmd_worktree(int ac, const char **av, const char *prefix)
 {
        struct option options[] = {
@@ -1056,5 +1082,7 @@ int cmd_worktree(int ac, const char **av, const char *prefix)
                return move_worktree(ac - 1, av + 1, prefix);
        if (!strcmp(av[1], "remove"))
                return remove_worktree(ac - 1, av + 1, prefix);
+       if (!strcmp(av[1], "repair"))
+               return repair(ac - 1, av + 1, prefix);
        usage_with_options(worktree_usage, options);
 }
index 4ce8cb38d5efe01a51648b4187acc291f588c012..bc741e78ad7dc09eab6c7f24d56377ec1397040e 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -1316,8 +1316,8 @@ int commit_tree(const char *msg, size_t msg_len, const struct object_id *tree,
        int result;
 
        append_merge_tag_headers(parents, &tail);
-       result = commit_tree_extended(msg, msg_len, tree, parents, ret,
-                                     author, sign_commit, extra);
+       result = commit_tree_extended(msg, msg_len, tree, parents, ret, author,
+                                     NULL, sign_commit, extra);
        free_commit_extra_headers(extra);
        return result;
 }
@@ -1440,7 +1440,8 @@ N_("Warning: commit message did not conform to UTF-8.\n"
 int commit_tree_extended(const char *msg, size_t msg_len,
                         const struct object_id *tree,
                         struct commit_list *parents, struct object_id *ret,
-                        const char *author, const char *sign_commit,
+                        const char *author, const char *committer,
+                        const char *sign_commit,
                         struct commit_extra_header *extra)
 {
        int result;
@@ -1473,7 +1474,9 @@ int commit_tree_extended(const char *msg, size_t msg_len,
        if (!author)
                author = git_author_info(IDENT_STRICT);
        strbuf_addf(&buffer, "author %s\n", author);
-       strbuf_addf(&buffer, "committer %s\n", git_committer_info(IDENT_STRICT));
+       if (!committer)
+               committer = git_committer_info(IDENT_STRICT);
+       strbuf_addf(&buffer, "committer %s\n", committer);
        if (!encoding_is_utf8)
                strbuf_addf(&buffer, "encoding %s\n", git_commit_encoding);
 
index e90153890954a458fa83671dea14b07a76621747..bd73b8447203cb668742f5f809b57842d319a6aa 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -270,10 +270,9 @@ int commit_tree(const char *msg, size_t msg_len,
 
 int commit_tree_extended(const char *msg, size_t msg_len,
                         const struct object_id *tree,
-                        struct commit_list *parents,
-                        struct object_id *ret, const char *author,
-                        const char *sign_commit,
-                        struct commit_extra_header *);
+                        struct commit_list *parents, struct object_id *ret,
+                        const char *author, const char *committer,
+                        const char *sign_commit, struct commit_extra_header *);
 
 struct commit_extra_header *read_commit_extra_headers(struct commit *, const char **);
 
index 47215df25beaaa2a37749e13b407c55fef66c11c..5007f173f1ed324ba5c557dafbfeead7c9befc08 100644 (file)
@@ -501,14 +501,8 @@ unset(CMAKE_REQUIRED_INCLUDES)
 
 #programs
 set(PROGRAMS_BUILT
-       git git-bugreport git-credential-store git-daemon git-fast-import git-http-backend git-sh-i18n--envsubst
-       git-shell git-remote-testsvn)
-
-if(NO_UNIX_SOCKETS)
-       list(APPEND excluded_progs git-credential-cache git-credential-cache--daemon)
-else()
-       list(APPEND PROGRAMS_BUILT git-credential-cache git-credential-cache--daemon)
-endif()
+       git git-daemon git-http-backend git-sh-i18n--envsubst
+       git-shell)
 
 if(NOT CURL_FOUND)
        list(APPEND excluded_progs git-http-fetch git-http-push)
@@ -574,12 +568,6 @@ parse_makefile_for_sources(libxdiff_SOURCES "XDIFF_OBJS")
 list(TRANSFORM libxdiff_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/")
 add_library(xdiff STATIC ${libxdiff_SOURCES})
 
-#libvcs-svn
-parse_makefile_for_sources(libvcs-svn_SOURCES "VCSSVN_OBJS")
-
-list(TRANSFORM libvcs-svn_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/")
-add_library(vcs-svn STATIC ${libvcs-svn_SOURCES})
-
 if(WIN32)
        if(NOT MSVC)#use windres when compiling with gcc and clang
                add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/git.res
@@ -630,18 +618,9 @@ list(TRANSFORM git_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/")
 add_executable(git ${CMAKE_SOURCE_DIR}/git.c ${git_SOURCES})
 target_link_libraries(git common-main)
 
-add_executable(git-bugreport ${CMAKE_SOURCE_DIR}/bugreport.c)
-target_link_libraries(git-bugreport common-main)
-
-add_executable(git-credential-store ${CMAKE_SOURCE_DIR}/credential-store.c)
-target_link_libraries(git-credential-store common-main)
-
 add_executable(git-daemon ${CMAKE_SOURCE_DIR}/daemon.c)
 target_link_libraries(git-daemon common-main)
 
-add_executable(git-fast-import ${CMAKE_SOURCE_DIR}/fast-import.c)
-target_link_libraries(git-fast-import common-main)
-
 add_executable(git-http-backend ${CMAKE_SOURCE_DIR}/http-backend.c)
 target_link_libraries(git-http-backend common-main)
 
@@ -669,18 +648,6 @@ if(CURL_FOUND)
        endif()
 endif()
 
-add_executable(git-remote-testsvn ${CMAKE_SOURCE_DIR}/remote-testsvn.c)
-target_link_libraries(git-remote-testsvn common-main vcs-svn)
-
-if(NOT NO_UNIX_SOCKETS)
-       add_executable(git-credential-cache ${CMAKE_SOURCE_DIR}/credential-cache.c)
-       target_link_libraries(git-credential-cache common-main)
-
-       add_executable(git-credential-cache--daemon ${CMAKE_SOURCE_DIR}/credential-cache--daemon.c)
-       target_link_libraries(git-credential-cache--daemon common-main)
-endif()
-
-
 set(git_builtin_extra
        cherry cherry-pick format-patch fsck-objects
        init merge-subtree restore show
@@ -856,12 +823,6 @@ if(BUILD_TESTING)
 add_executable(test-fake-ssh ${CMAKE_SOURCE_DIR}/t/helper/test-fake-ssh.c)
 target_link_libraries(test-fake-ssh common-main)
 
-add_executable(test-line-buffer ${CMAKE_SOURCE_DIR}/t/helper/test-line-buffer.c)
-target_link_libraries(test-line-buffer common-main vcs-svn)
-
-add_executable(test-svn-fe ${CMAKE_SOURCE_DIR}/t/helper/test-svn-fe.c)
-target_link_libraries(test-svn-fe common-main vcs-svn)
-
 #test-tool
 parse_makefile_for_sources(test-tool_SOURCES "TEST_BUILTINS_OBJS")
 
@@ -869,13 +830,13 @@ list(TRANSFORM test-tool_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/t/helper/")
 add_executable(test-tool ${CMAKE_SOURCE_DIR}/t/helper/test-tool.c ${test-tool_SOURCES})
 target_link_libraries(test-tool common-main)
 
-set_target_properties(test-fake-ssh test-line-buffer test-svn-fe test-tool
+set_target_properties(test-fake-ssh test-tool
                        PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/t/helper)
 
 if(MSVC)
-       set_target_properties(test-fake-ssh test-line-buffer test-svn-fe test-tool
+       set_target_properties(test-fake-ssh test-tool
                                PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}/t/helper)
-       set_target_properties(test-fake-ssh test-line-buffer test-svn-fe test-tool
+       set_target_properties(test-fake-ssh test-tool
                                PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/t/helper)
 endif()
 
@@ -884,7 +845,7 @@ set(wrapper_scripts
        git git-upload-pack git-receive-pack git-upload-archive git-shell git-remote-ext)
 
 set(wrapper_test_scripts
-       test-fake-ssh test-line-buffer test-svn-fe test-tool)
+       test-fake-ssh test-tool)
 
 
 foreach(script ${wrapper_scripts})
@@ -985,7 +946,6 @@ if(NOT ${CMAKE_BINARY_DIR}/CMakeCache.txt STREQUAL ${CACHE_PATH})
        file(COPY ${CMAKE_SOURCE_DIR}/mergetools/tkdiff DESTINATION ${CMAKE_BINARY_DIR}/mergetools/)
        file(COPY ${CMAKE_SOURCE_DIR}/contrib/completion/git-prompt.sh DESTINATION ${CMAKE_BINARY_DIR}/contrib/completion/)
        file(COPY ${CMAKE_SOURCE_DIR}/contrib/completion/git-completion.bash DESTINATION ${CMAKE_BINARY_DIR}/contrib/completion/)
-       file(COPY ${CMAKE_SOURCE_DIR}/contrib/svn-fe/svnrdump_sim.py DESTINATION ${CMAKE_BINARY_DIR}/contrib/svn-fe/)
 endif()
 
 file(GLOB test_scipts "${CMAKE_SOURCE_DIR}/t/t[0-9]*.sh")
diff --git a/contrib/svn-fe/.gitignore b/contrib/svn-fe/.gitignore
deleted file mode 100644 (file)
index 02a7791..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-/*.xml
-/*.1
-/*.html
-/svn-fe
diff --git a/contrib/svn-fe/Makefile b/contrib/svn-fe/Makefile
deleted file mode 100644 (file)
index e8651aa..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-all:: svn-fe$X
-
-CC = cc
-RM = rm -f
-MV = mv
-
-CFLAGS = -g -O2 -Wall
-LDFLAGS =
-EXTLIBS = -lz
-
-include ../../config.mak.uname
--include ../../config.mak.autogen
--include ../../config.mak
-
-ifeq ($(uname_S),Darwin)
-       ifndef NO_FINK
-               ifeq ($(shell test -d /sw/lib && echo y),y)
-                       CFLAGS += -I/sw/include
-                       LDFLAGS += -L/sw/lib
-               endif
-       endif
-       ifndef NO_DARWIN_PORTS
-               ifeq ($(shell test -d /opt/local/lib && echo y),y)
-                       CFLAGS += -I/opt/local/include
-                       LDFLAGS += -L/opt/local/lib
-               endif
-       endif
-endif
-
-ifndef NO_OPENSSL
-       EXTLIBS += -lssl
-       ifdef NEEDS_CRYPTO_WITH_SSL
-               EXTLIBS += -lcrypto
-       endif
-endif
-
-ifndef NO_PTHREADS
-       CFLAGS += $(PTHREADS_CFLAGS)
-       EXTLIBS += $(PTHREAD_LIBS)
-endif
-
-ifdef HAVE_CLOCK_GETTIME
-       CFLAGS += -DHAVE_CLOCK_GETTIME
-       EXTLIBS += -lrt
-endif
-
-ifdef NEEDS_LIBICONV
-       EXTLIBS += -liconv
-endif
-
-GIT_LIB = ../../libgit.a
-VCSSVN_LIB = ../../vcs-svn/lib.a
-XDIFF_LIB = ../../xdiff/lib.a
-
-LIBS = $(VCSSVN_LIB) $(GIT_LIB) $(XDIFF_LIB)
-
-QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
-QUIET_SUBDIR1 =
-
-ifneq ($(findstring $(MAKEFLAGS),w),w)
-PRINT_DIR = --no-print-directory
-else # "make -w"
-NO_SUBDIR = :
-endif
-
-ifneq ($(findstring $(MAKEFLAGS),s),s)
-ifndef V
-       QUIET_CC      = @echo '   ' CC $@;
-       QUIET_LINK    = @echo '   ' LINK $@;
-       QUIET_SUBDIR0 = +@subdir=
-       QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo '   ' SUBDIR $$subdir; \
-                       $(MAKE) $(PRINT_DIR) -C $$subdir
-endif
-endif
-
-svn-fe$X: svn-fe.o $(VCSSVN_LIB) $(XDIFF_LIB) $(GIT_LIB)
-       $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(EXTLIBS) -o $@ svn-fe.o $(LIBS)
-
-svn-fe.o: svn-fe.c ../../vcs-svn/svndump.h
-       $(QUIET_CC)$(CC) $(CFLAGS) -I../../vcs-svn -o $*.o -c $<
-
-svn-fe.html: svn-fe.txt
-       $(QUIET_SUBDIR0)../../Documentation $(QUIET_SUBDIR1) \
-               MAN_TXT=../contrib/svn-fe/svn-fe.txt \
-               ../contrib/svn-fe/$@
-
-svn-fe.1: svn-fe.txt
-       $(QUIET_SUBDIR0)../../Documentation $(QUIET_SUBDIR1) \
-               MAN_TXT=../contrib/svn-fe/svn-fe.txt \
-               ../contrib/svn-fe/$@
-       $(MV) ../../Documentation/svn-fe.1 .
-
-../../vcs-svn/lib.a: FORCE
-       $(QUIET_SUBDIR0)../.. $(QUIET_SUBDIR1) vcs-svn/lib.a
-
-../../xdiff/lib.a: FORCE
-       $(QUIET_SUBDIR0)../.. $(QUIET_SUBDIR1) xdiff/lib.a
-
-../../libgit.a: FORCE
-       $(QUIET_SUBDIR0)../.. $(QUIET_SUBDIR1) libgit.a
-
-clean:
-       $(RM) svn-fe$X svn-fe.o svn-fe.html svn-fe.xml svn-fe.1
-
-.PHONY: all clean FORCE
diff --git a/contrib/svn-fe/svn-fe.c b/contrib/svn-fe/svn-fe.c
deleted file mode 100644 (file)
index f363505..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * This file is in the public domain.
- * You may freely use, modify, distribute, and relicense it.
- */
-
-#include <stdlib.h>
-#include "svndump.h"
-
-int main(int argc, char **argv)
-{
-       if (svndump_init(NULL))
-               return 1;
-       svndump_read((argc > 1) ? argv[1] : NULL, "refs/heads/master",
-                       "refs/notes/svn/revs");
-       svndump_deinit();
-       svndump_reset();
-       return 0;
-}
diff --git a/contrib/svn-fe/svn-fe.txt b/contrib/svn-fe/svn-fe.txt
deleted file mode 100644 (file)
index 19333fc..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-svn-fe(1)
-=========
-
-NAME
-----
-svn-fe - convert an SVN "dumpfile" to a fast-import stream
-
-SYNOPSIS
---------
-[verse]
-mkfifo backchannel &&
-svnadmin dump --deltas REPO |
-       svn-fe [url] 3<backchannel |
-       git fast-import --cat-blob-fd=3 3>backchannel
-
-DESCRIPTION
------------
-
-Converts a Subversion dumpfile into input suitable for
-git-fast-import(1) and similar importers. REPO is a path to a
-Subversion repository mirrored on the local disk. Remote Subversion
-repositories can be mirrored on local disk using the `svnsync`
-command.
-
-Note: this tool is very young.  The details of its commandline
-interface may change in backward incompatible ways.
-
-INPUT FORMAT
-------------
-Subversion's repository dump format is documented in full in
-`notes/dump-load-format.txt` from the Subversion source tree.
-Files in this format can be generated using the 'svnadmin dump' or
-'svk admin dump' command.
-
-OUTPUT FORMAT
--------------
-The fast-import format is documented by the git-fast-import(1)
-manual page.
-
-NOTES
------
-Subversion dumps do not record a separate author and committer for
-each revision, nor do they record a separate display name and email
-address for each author.  Like git-svn(1), 'svn-fe' will use the name
-
----------
-user <user@UUID>
----------
-
-as committer, where 'user' is the value of the `svn:author` property
-and 'UUID' the repository's identifier.
-
-To support incremental imports, 'svn-fe' puts a `git-svn-id` line at
-the end of each commit log message if passed a URL on the command
-line.  This line has the form `git-svn-id: URL@REVNO UUID`.
-
-The resulting repository will generally require further processing
-to put each project in its own repository and to separate the history
-of each branch.  The 'git filter-repo --subdirectory-filter' command
-may be useful for this purpose.
-
-BUGS
-----
-Empty directories and unknown properties are silently discarded.
-
-The exit status does not reflect whether an error was detected.
-
-SEE ALSO
---------
-git-svn(1), svn2git(1), svk(1), git-filter-repo(1), git-fast-import(1),
-https://svn.apache.org/repos/asf/subversion/trunk/notes/dump-load-format.txt
diff --git a/contrib/svn-fe/svnrdump_sim.py b/contrib/svn-fe/svnrdump_sim.py
deleted file mode 100755 (executable)
index 8a3cee6..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-#!/usr/bin/env python
-"""
-Simulates svnrdump by replaying an existing dump from a file, taking care
-of the specified revision range.
-To simulate incremental imports the environment variable SVNRMAX can be set
-to the highest revision that should be available.
-"""
-import sys
-import os
-
-if sys.hexversion < 0x02040000:
-    # The limiter is the ValueError() calls. This may be too conservative
-    sys.stderr.write("svnrdump-sim.py: requires Python 2.4 or later.\n")
-    sys.exit(1)
-
-
-def getrevlimit():
-    var = 'SVNRMAX'
-    if var in os.environ:
-        return os.environ[var]
-    return None
-
-
-def writedump(url, lower, upper):
-    if url.startswith('sim://'):
-        filename = url[6:]
-        if filename[-1] == '/':
-            filename = filename[:-1]  # remove terminating slash
-    else:
-        raise ValueError('sim:// url required')
-    f = open(filename, 'r')
-    state = 'header'
-    wroterev = False
-    while(True):
-        l = f.readline()
-        if l == '':
-            break
-        if state == 'header' and l.startswith('Revision-number: '):
-            state = 'prefix'
-        if state == 'prefix' and l == 'Revision-number: %s\n' % lower:
-            state = 'selection'
-        if not upper == 'HEAD' and state == 'selection' and \
-                l == 'Revision-number: %s\n' % upper:
-            break
-
-        if state == 'header' or state == 'selection':
-            if state == 'selection':
-                wroterev = True
-            sys.stdout.write(l)
-    return wroterev
-
-if __name__ == "__main__":
-    if not (len(sys.argv) in (3, 4, 5)):
-        print("usage: %s dump URL -rLOWER:UPPER")
-        sys.exit(1)
-    if not sys.argv[1] == 'dump':
-        raise NotImplementedError('only "dump" is supported.')
-    url = sys.argv[2]
-    r = ('0', 'HEAD')
-    if len(sys.argv) == 4 and sys.argv[3][0:2] == '-r':
-        r = sys.argv[3][2:].lstrip().split(':')
-    if not getrevlimit() is None:
-        r[1] = getrevlimit()
-    if writedump(url, r[0], r[1]):
-        ret = 0
-    else:
-        ret = 1
-    sys.exit(ret)
index 572449825c5a4c8fd1ff65bb0c947d0c567d002b..8e6c2924215a4ee754658cbc9008856845fc071c 100644 (file)
--- a/convert.c
+++ b/convert.c
@@ -638,7 +638,6 @@ static int filter_buffer_or_fd(int in, int out, void *data)
        struct child_process child_process = CHILD_PROCESS_INIT;
        struct filter_params *params = (struct filter_params *)data;
        int write_err, status;
-       const char *argv[] = { NULL, NULL };
 
        /* apply % substitution to cmd */
        struct strbuf cmd = STRBUF_INIT;
@@ -656,9 +655,7 @@ static int filter_buffer_or_fd(int in, int out, void *data)
        strbuf_expand(&cmd, params->cmd, strbuf_expand_dict_cb, &dict);
        strbuf_release(&path);
 
-       argv[0] = cmd.buf;
-
-       child_process.argv = argv;
+       strvec_push(&child_process.args, cmd.buf);
        child_process.use_shell = 1;
        child_process.in = -1;
        child_process.out = out;
index d8d226b97e34805735cc14bdc3e549d012b33f8d..efc29dc5e1d28e0b2f6f92051de291dfb13e57ae 100644 (file)
@@ -274,11 +274,9 @@ static int run_credential_helper(struct credential *c,
                                 int want_output)
 {
        struct child_process helper = CHILD_PROCESS_INIT;
-       const char *argv[] = { NULL, NULL };
        FILE *fp;
 
-       argv[0] = cmd;
-       helper.argv = argv;
+       strvec_push(&helper.args, cmd);
        helper.use_shell = 1;
        helper.in = -1;
        if (want_output)
diff --git a/diff.c b/diff.c
index f175019eb7a1e6f61a88ffb9bebbe3b419d1de84..a5114fa86468ceff56005ed83fcb10f129dc0fc2 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -3153,16 +3153,19 @@ static void show_dirstat_by_line(struct diffstat_t *data, struct diff_options *o
        gather_dirstat(options, &dir, changed, "", 0);
 }
 
+static void free_diffstat_file(struct diffstat_file *f)
+{
+       free(f->print_name);
+       free(f->name);
+       free(f->from_name);
+       free(f);
+}
+
 void free_diffstat_info(struct diffstat_t *diffstat)
 {
        int i;
-       for (i = 0; i < diffstat->nr; i++) {
-               struct diffstat_file *f = diffstat->files[i];
-               free(f->print_name);
-               free(f->name);
-               free(f->from_name);
-               free(f);
-       }
+       for (i = 0; i < diffstat->nr; i++)
+               free_diffstat_file(diffstat->files[i]);
        free(diffstat->files);
 }
 
@@ -3429,7 +3432,7 @@ static void builtin_diff(const char *name_a,
        if (o->submodule_format == DIFF_SUBMODULE_LOG &&
            (!one->mode || S_ISGITLINK(one->mode)) &&
            (!two->mode || S_ISGITLINK(two->mode))) {
-               show_submodule_summary(o, one->path ? one->path : two->path,
+               show_submodule_diff_summary(o, one->path ? one->path : two->path,
                                &one->oid, &two->oid,
                                two->dirty_submodule);
                return;
@@ -3718,6 +3721,27 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
                if (xdi_diff_outf(&mf1, &mf2, discard_hunk_line,
                                  diffstat_consume, diffstat, &xpp, &xecfg))
                        die("unable to generate diffstat for %s", one->path);
+
+               if (DIFF_FILE_VALID(one) && DIFF_FILE_VALID(two)) {
+                       struct diffstat_file *file =
+                               diffstat->files[diffstat->nr - 1];
+                       /*
+                        * Omit diffstats of modified files where nothing changed.
+                        * Even if !same_contents, this might be the case due to
+                        * ignoring whitespace changes, etc.
+                        *
+                        * But note that we special-case additions, deletions,
+                        * renames, and mode changes as adding an empty file,
+                        * for example is still of interest.
+                        */
+                       if ((p->status == DIFF_STATUS_MODIFIED)
+                               && !file->added
+                               && !file->deleted
+                               && one->mode == two->mode) {
+                               free_diffstat_file(file);
+                               diffstat->nr--;
+                       }
+               }
        }
 
        diff_free_filespec_data(one);
@@ -4319,7 +4343,10 @@ static void fill_metainfo(struct strbuf *msg,
        }
        if (one && two && !oideq(&one->oid, &two->oid)) {
                const unsigned hexsz = the_hash_algo->hexsz;
-               int abbrev = o->flags.full_index ? hexsz : DEFAULT_ABBREV;
+               int abbrev = o->abbrev ? o->abbrev : DEFAULT_ABBREV;
+
+               if (o->flags.full_index)
+                       abbrev = hexsz;
 
                if (o->flags.binary) {
                        mmfile_t mf;
index 0a1357dc9d55b34992ff5a6f65e3bdf77375465e..57ed5784e1468aa661d59446273ba9cbbad760ca 100644 (file)
@@ -2,6 +2,7 @@
 #include "fetch-negotiator.h"
 #include "negotiator/default.h"
 #include "negotiator/skipping.h"
+#include "negotiator/noop.h"
 #include "repository.h"
 
 void fetch_negotiator_init(struct repository *r,
@@ -13,6 +14,10 @@ void fetch_negotiator_init(struct repository *r,
                skipping_negotiator_init(negotiator);
                return;
 
+       case FETCH_NEGOTIATION_NOOP:
+               noop_negotiator_init(negotiator);
+               return;
+
        case FETCH_NEGOTIATION_DEFAULT:
        default:
                default_negotiator_init(negotiator);
index 7f20eca4f81ce401f951361ce59e1be6aa31cd67..b10c4323155b77f2ef271564cef862147a880596 100644 (file)
@@ -108,24 +108,48 @@ static void for_each_cached_alternate(struct fetch_negotiator *negotiator,
                cb(negotiator, cache.items[i]);
 }
 
+static struct commit *deref_without_lazy_fetch(const struct object_id *oid,
+                                              int mark_tags_complete)
+{
+       enum object_type type;
+       struct object_info info = { .typep = &type };
+
+       while (1) {
+               if (oid_object_info_extended(the_repository, oid, &info,
+                                            OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_QUICK))
+                       return NULL;
+               if (type == OBJ_TAG) {
+                       struct tag *tag = (struct tag *)
+                               parse_object(the_repository, oid);
+
+                       if (!tag->tagged)
+                               return NULL;
+                       if (mark_tags_complete)
+                               tag->object.flags |= COMPLETE;
+                       oid = &tag->tagged->oid;
+               } else {
+                       break;
+               }
+       }
+       if (type == OBJ_COMMIT)
+               return (struct commit *) parse_object(the_repository, oid);
+       return NULL;
+}
+
 static int rev_list_insert_ref(struct fetch_negotiator *negotiator,
-                              const char *refname,
                               const struct object_id *oid)
 {
-       struct object *o = deref_tag(the_repository,
-                                    parse_object(the_repository, oid),
-                                    refname, 0);
-
-       if (o && o->type == OBJ_COMMIT)
-               negotiator->add_tip(negotiator, (struct commit *)o);
+       struct commit *c = deref_without_lazy_fetch(oid, 0);
 
+       if (c)
+               negotiator->add_tip(negotiator, c);
        return 0;
 }
 
 static int rev_list_insert_ref_oid(const char *refname, const struct object_id *oid,
                                   int flag, void *cb_data)
 {
-       return rev_list_insert_ref(cb_data, refname, oid);
+       return rev_list_insert_ref(cb_data, oid);
 }
 
 enum ack_type {
@@ -201,7 +225,7 @@ static void send_request(struct fetch_pack_args *args,
 static void insert_one_alternate_object(struct fetch_negotiator *negotiator,
                                        struct object *obj)
 {
-       rev_list_insert_ref(negotiator, NULL, &obj->oid);
+       rev_list_insert_ref(negotiator, &obj->oid);
 }
 
 #define INITIAL_FLUSH 16
@@ -230,13 +254,12 @@ static void mark_tips(struct fetch_negotiator *negotiator,
        int i;
 
        if (!negotiation_tips) {
-               for_each_ref(rev_list_insert_ref_oid, negotiator);
+               for_each_rawref(rev_list_insert_ref_oid, negotiator);
                return;
        }
 
        for (i = 0; i < negotiation_tips->nr; i++)
-               rev_list_insert_ref(negotiator, NULL,
-                                   &negotiation_tips->oid[i]);
+               rev_list_insert_ref(negotiator, &negotiation_tips->oid[i]);
        return;
 }
 
@@ -262,10 +285,8 @@ static int find_common(struct fetch_negotiator *negotiator,
                           PACKET_READ_CHOMP_NEWLINE |
                           PACKET_READ_DIE_ON_ERR_PACKET);
 
-       if (!args->no_dependents) {
-               mark_tips(negotiator, args->negotiation_tips);
-               for_each_cached_alternate(negotiator, insert_one_alternate_object);
-       }
+       mark_tips(negotiator, args->negotiation_tips);
+       for_each_cached_alternate(negotiator, insert_one_alternate_object);
 
        fetching = 0;
        for ( ; refs ; refs = refs->next) {
@@ -282,12 +303,8 @@ 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 (!args->no_dependents &&
-                   ((o = lookup_object(the_repository, remote)) != NULL) &&
+               if (((o = lookup_object(the_repository, remote)) != NULL) &&
                                (o->flags & COMPLETE)) {
                        continue;
                }
@@ -387,8 +404,6 @@ static int find_common(struct fetch_negotiator *negotiator,
        trace2_region_enter("fetch-pack", "negotiation_v0_v1", the_repository);
        flushes = 0;
        retval = -1;
-       if (args->no_dependents)
-               goto done;
        while ((oid = negotiator->next(negotiator))) {
                packet_buf_write(&req_buf, "have %s\n", oid_to_hex(oid));
                print_verbose(args, "have %s", oid_to_hex(oid));
@@ -503,21 +518,11 @@ static struct commit_list *complete;
 
 static int mark_complete(const struct object_id *oid)
 {
-       struct object *o = parse_object(the_repository, oid);
-
-       while (o && o->type == OBJ_TAG) {
-               struct tag *t = (struct tag *) o;
-               if (!t->tagged)
-                       break; /* broken repository */
-               o->flags |= COMPLETE;
-               o = parse_object(the_repository, &t->tagged->oid);
-       }
-       if (o && o->type == OBJ_COMMIT) {
-               struct commit *commit = (struct commit *)o;
-               if (!(commit->object.flags & COMPLETE)) {
-                       commit->object.flags |= COMPLETE;
-                       commit_list_insert(commit, &complete);
-               }
+       struct commit *commit = deref_without_lazy_fetch(oid, 1);
+
+       if (commit && !(commit->object.flags & COMPLETE)) {
+               commit->object.flags |= COMPLETE;
+               commit_list_insert(commit, &complete);
        }
        return 0;
 }
@@ -653,9 +658,7 @@ struct loose_object_iter {
 
 /*
  * Mark recent commits available locally and reachable from a local ref as
- * COMPLETE. If args->no_dependents is false, also mark COMPLETE remote refs as
- * COMMON_REF (otherwise, we are not planning to participate in negotiation, and
- * thus do not need COMMON_REF marks).
+ * COMPLETE.
  *
  * The cutoff time for recency is determined by this heuristic: it is the
  * earliest commit time of the objects in refs that are commits and that we know
@@ -702,7 +705,7 @@ static void mark_complete_and_common_ref(struct fetch_negotiator *negotiator,
         */
        trace2_region_enter("fetch-pack", "mark_complete_local_refs", NULL);
        if (!args->deepen) {
-               for_each_ref(mark_complete_oid, NULL);
+               for_each_rawref(mark_complete_oid, NULL);
                for_each_cached_alternate(NULL, mark_alternate_complete);
                commit_list_sort_by_date(&complete);
                if (cutoff)
@@ -716,16 +719,12 @@ static void mark_complete_and_common_ref(struct fetch_negotiator *negotiator,
         */
        trace2_region_enter("fetch-pack", "mark_common_remote_refs", NULL);
        for (ref = *refs; ref; ref = ref->next) {
-               struct object *o = deref_tag(the_repository,
-                                            lookup_object(the_repository,
-                                            &ref->old_oid),
-                                            NULL, 0);
+               struct commit *c = deref_without_lazy_fetch(&ref->old_oid, 0);
 
-               if (!o || o->type != OBJ_COMMIT || !(o->flags & COMPLETE))
+               if (!c || !(c->object.flags & COMPLETE))
                        continue;
 
-               negotiator->known_common(negotiator,
-                                        (struct commit *)o);
+               negotiator->known_common(negotiator, c);
        }
        trace2_region_leave("fetch-pack", "mark_common_remote_refs", NULL);
 
@@ -794,6 +793,10 @@ static void write_promisor_file(const char *keep_name,
        strbuf_release(&promisor_name);
 }
 
+/*
+ * Pass 1 as "only_packfile" if the pack received is the only pack in this
+ * fetch request (that is, if there were no packfile URIs provided).
+ */
 static int get_pack(struct fetch_pack_args *args,
                    int xd[2], struct string_list *pack_lockfiles,
                    int only_packfile,
@@ -866,13 +869,16 @@ static int get_pack(struct fetch_pack_args *args,
                         * have this responsibility.
                         */
                        args->check_self_contained_and_connected = 0;
-               /*
-                * If we're obtaining the filename of a lockfile, we'll use
-                * that filename to write a .promisor file with more
-                * information below. If not, we need index-pack to do it for
-                * us.
-                */
-               if (!(do_keep && pack_lockfiles) && args->from_promisor)
+
+               if (args->from_promisor)
+                       /*
+                        * write_promisor_file() may be called afterwards but
+                        * we still need index-pack to know that this is a
+                        * promisor pack. For example, if transfer.fsckobjects
+                        * is true, index-pack needs to know that .gitmodules
+                        * is a promisor object (so that it won't complain if
+                        * it is missing).
+                        */
                        strvec_push(&cmd.args, "--promisor");
        }
        else {
@@ -892,7 +898,7 @@ static int get_pack(struct fetch_pack_args *args,
            : transfer_fsck_objects >= 0
            ? transfer_fsck_objects
            : 0) {
-               if (args->from_promisor)
+               if (args->from_promisor || !only_packfile)
                        /*
                         * We cannot use --strict in index-pack because it
                         * checks both broken objects and links, but we only
@@ -960,12 +966,8 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
        struct fetch_negotiator negotiator_alloc;
        struct fetch_negotiator *negotiator;
 
-       if (args->no_dependents) {
-               negotiator = NULL;
-       } else {
-               negotiator = &negotiator_alloc;
-               fetch_negotiator_init(r, negotiator);
-       }
+       negotiator = &negotiator_alloc;
+       fetch_negotiator_init(r, negotiator);
 
        sort_ref_list(&ref, ref_compare_name);
        QSORT(sought, nr_sought, cmp_ref_by_name);
@@ -1053,15 +1055,11 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
        if (!server_supports_hash(the_hash_algo->name, NULL))
                die(_("Server does not support this repository's object format"));
 
-       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);
+       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 (find_common(negotiator, args, fd, &oid, ref) < 0)
                if (!args->keep_pack)
@@ -1110,7 +1108,7 @@ static void add_shallow_requests(struct strbuf *req_buf,
                packet_buf_write(req_buf, "deepen-relative\n");
 }
 
-static void add_wants(int no_dependents, const struct ref *wants, struct strbuf *req_buf)
+static void add_wants(const struct ref *wants, struct strbuf *req_buf)
 {
        int use_ref_in_want = server_supports_feature("fetch", "ref-in-want", 0);
 
@@ -1127,12 +1125,8 @@ static void add_wants(int no_dependents, const struct ref *wants, struct strbuf
                 * 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 (!no_dependents &&
-                   ((o = lookup_object(the_repository, remote)) != NULL) &&
+               if (((o = lookup_object(the_repository, remote)) != NULL) &&
                    (o->flags & COMPLETE)) {
                        continue;
                }
@@ -1266,19 +1260,14 @@ static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out,
        }
 
        /* add wants */
-       add_wants(args->no_dependents, wants, &req_buf);
+       add_wants(wants, &req_buf);
 
-       if (args->no_dependents) {
-               packet_buf_write(&req_buf, "done");
-               ret = 1;
-       } else {
-               /* Add all of the common commits we've found in previous rounds */
-               add_common(&req_buf, common);
+       /* Add all of the common commits we've found in previous rounds */
+       add_common(&req_buf, common);
 
-               /* Add initial haves */
-               ret = add_haves(negotiator, seen_ack, &req_buf,
-                               haves_to_send, in_vain);
-       }
+       /* Add initial haves */
+       ret = add_haves(negotiator, seen_ack, &req_buf,
+                       haves_to_send, in_vain);
 
        /* Send request */
        packet_buf_flush(&req_buf);
@@ -1538,12 +1527,8 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
        struct string_list packfile_uris = STRING_LIST_INIT_DUP;
        int i;
 
-       if (args->no_dependents) {
-               negotiator = NULL;
-       } else {
-               negotiator = &negotiator_alloc;
-               fetch_negotiator_init(r, negotiator);
-       }
+       negotiator = &negotiator_alloc;
+       fetch_negotiator_init(r, negotiator);
 
        packet_reader_init(&reader, fd[0], NULL, 0,
                           PACKET_READ_CHOMP_NEWLINE |
@@ -1567,21 +1552,16 @@ 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 */
-                       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);
+                       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);
                        break;
                case FETCH_SEND_REQUEST:
                        if (!negotiation_started) {
@@ -1902,20 +1882,6 @@ 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 (version != protocol_v2 && !ref) {
                packet_flush(fd[1]);
                die(_("no matching remote head"));
index 85d1e39fe752ddc625ba7801faa5373db57b796c..736a3dae467ac08a402e6b45e305bab0e7911a37 100644 (file)
@@ -40,21 +40,15 @@ struct fetch_pack_args {
        unsigned cloning:1;
        unsigned update_shallow:1;
        unsigned deepen:1;
-       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).
+        * Indicate that the remote of this request is a promisor remote. The
+        * pack received does not need all referred-to objects to be present in
+        * the local object store, and fetch-pack will store the pack received
+        * together with a ".promisor" file indicating that the aforementioned
+        * pack is a promisor pack.
         */
-       unsigned no_dependents:1;
+       unsigned from_promisor:1;
 
        /*
         * Because fetch_pack() overwrites the shallow file upon a
index c7580e51a0f9953b2a68296fedbd3cfe2f7c05e6..2f60fefcfaa12c3a4579818d4cd616232340108f 100755 (executable)
@@ -3,8 +3,8 @@
 USAGE='[help|start|bad|good|new|old|terms|skip|next|reset|visualize|view|replay|log|run]'
 LONG_USAGE='git bisect help
        print this long help message.
-git bisect start [--term-{old,good}=<term> --term-{new,bad}=<term>]
-                [--no-checkout] [<bad> [<good>...]] [--] [<pathspec>...]
+git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]
+                [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]
        reset bisect state and start bisection.
 git bisect (bad|new) [<rev>]
        mark <rev> a known-bad revision/
index 0ae8bce3fb0675ea206e962ef576d08d5d608ada..289d4bc684dc26256f497636ca5c080fc6589226 100755 (executable)
@@ -30,7 +30,7 @@ if ($opt_w || $opt_W) {
        # Remember where GIT_DIR is before changing to CVS checkout
        unless ($ENV{GIT_DIR}) {
                # No GIT_DIR set. Figure it out for ourselves
-               my $gd =`git-rev-parse --git-dir`;
+               my $gd =`git rev-parse --git-dir`;
                chomp($gd);
                $ENV{GIT_DIR} = $gd;
        }
@@ -66,7 +66,7 @@ if ($opt_d) {
 # resolve target commit
 my $commit;
 $commit = pop @ARGV;
-$commit = safe_pipe_capture('git-rev-parse', '--verify', "$commit^0");
+$commit = safe_pipe_capture('git', 'rev-parse', '--verify', "$commit^0");
 chomp $commit;
 if ($?) {
     die "The commit reference $commit did not resolve!";
@@ -76,7 +76,7 @@ if ($?) {
 my $parent;
 if (@ARGV) {
     $parent = pop @ARGV;
-    $parent =  safe_pipe_capture('git-rev-parse', '--verify', "$parent^0");
+    $parent =  safe_pipe_capture('git', 'rev-parse', '--verify', "$parent^0");
     chomp $parent;
     if ($?) {
        die "The parent reference did not resolve!";
@@ -84,7 +84,7 @@ if (@ARGV) {
 }
 
 # find parents from the commit itself
-my @commit  = safe_pipe_capture('git-cat-file', 'commit', $commit);
+my @commit  = safe_pipe_capture('git', 'cat-file', 'commit', $commit);
 my @parents;
 my $committer;
 my $author;
@@ -162,9 +162,9 @@ if ($opt_a) {
 close MSG;
 
 if ($parent eq $noparent) {
-    `git-diff-tree --binary -p --root $commit >.cvsexportcommit.diff`;# || die "Cannot diff";
+    `git diff-tree --binary -p --root $commit >.cvsexportcommit.diff`;# || die "Cannot diff";
 } else {
-    `git-diff-tree --binary -p $parent $commit >.cvsexportcommit.diff`;# || die "Cannot diff";
+    `git diff-tree --binary -p $parent $commit >.cvsexportcommit.diff`;# || die "Cannot diff";
 }
 
 ## apply non-binary changes
@@ -178,7 +178,7 @@ my $context = $opt_p ? '' : '-C1';
 print "Checking if patch will apply\n";
 
 my @stat;
-open APPLY, "GIT_INDEX_FILE=$tmpdir/index git-apply $context --summary --numstat<.cvsexportcommit.diff|" || die "cannot patch";
+open APPLY, "GIT_INDEX_FILE=$tmpdir/index git apply $context --summary --numstat<.cvsexportcommit.diff|" || die "cannot patch";
 @stat=<APPLY>;
 close APPLY || die "Cannot patch";
 my (@bfiles,@files,@afiles,@dfiles);
@@ -333,7 +333,7 @@ print "Applying\n";
 if ($opt_W) {
     system("git checkout -q $commit^0") && die "cannot patch";
 } else {
-    `GIT_INDEX_FILE=$tmpdir/index git-apply $context --summary --numstat --apply <.cvsexportcommit.diff` || die "cannot patch";
+    `GIT_INDEX_FILE=$tmpdir/index git apply $context --summary --numstat --apply <.cvsexportcommit.diff` || die "cannot patch";
 }
 
 print "Patch applied successfully. Adding new files and directories to CVS\n";
index 43eb6051d23f90cccc94c1fb4c58ad14d4ece3e6..6fb12585cb07c3eb1f0a9ff1263c8d51de26962c 100755 (executable)
@@ -59,31 +59,6 @@ die_if_unmatched ()
        fi
 }
 
-#
-# Print a submodule configuration setting
-#
-# $1 = submodule name
-# $2 = option name
-# $3 = default value
-#
-# Checks in the usual git-config places first (for overrides),
-# otherwise it falls back on .gitmodules.  This allows you to
-# distribute project-wide defaults in .gitmodules, while still
-# customizing individual repositories if necessary.  If the option is
-# not in .gitmodules either, print a default value.
-#
-get_submodule_config () {
-       name="$1"
-       option="$2"
-       default="$3"
-       value=$(git config submodule."$name"."$option")
-       if test -z "$value"
-       then
-               value=$(git submodule--helper config submodule."$name"."$option")
-       fi
-       printf '%s' "${value:-$default}"
-}
-
 isnumber()
 {
        n=$(($1 + 0)) 2>/dev/null && test "$n" = "$1"
@@ -831,166 +806,7 @@ cmd_summary() {
                shift
        done
 
-       test $summary_limit = 0 && return
-
-       if rev=$(git rev-parse -q --verify --default HEAD ${1+"$1"})
-       then
-               head=$rev
-               test $# = 0 || shift
-       elif test -z "$1" || test "$1" = "HEAD"
-       then
-               # before the first commit: compare with an empty tree
-               head=$(git hash-object -w -t tree --stdin </dev/null)
-               test -z "$1" || shift
-       else
-               head="HEAD"
-       fi
-
-       if [ -n "$files" ]
-       then
-               test -n "$cached" &&
-               die "$(gettext "The --cached option cannot be used with the --files option")"
-               diff_cmd=diff-files
-               head=
-       fi
-
-       cd_to_toplevel
-       eval "set $(git rev-parse --sq --prefix "$wt_prefix" -- "$@")"
-       # Get modified modules cared by user
-       modules=$(git $diff_cmd $cached --ignore-submodules=dirty --raw $head -- "$@" |
-               sane_egrep '^:([0-7]* )?160000' |
-               while read -r mod_src mod_dst sha1_src sha1_dst status sm_path
-               do
-                       # Always show modules deleted or type-changed (blob<->module)
-                       if test "$status" = D || test "$status" = T
-                       then
-                               printf '%s\n' "$sm_path"
-                               continue
-                       fi
-                       # Respect the ignore setting for --for-status.
-                       if test -n "$for_status"
-                       then
-                               name=$(git submodule--helper name "$sm_path")
-                               ignore_config=$(get_submodule_config "$name" ignore none)
-                               test $status != A && test $ignore_config = all && continue
-                       fi
-                       # Also show added or modified modules which are checked out
-                       GIT_DIR="$sm_path/.git" git rev-parse --git-dir >/dev/null 2>&1 &&
-                       printf '%s\n' "$sm_path"
-               done
-       )
-
-       test -z "$modules" && return
-
-       git $diff_cmd $cached --ignore-submodules=dirty --raw $head -- $modules |
-       sane_egrep '^:([0-7]* )?160000' |
-       cut -c2- |
-       while read -r mod_src mod_dst sha1_src sha1_dst status name
-       do
-               if test -z "$cached" &&
-                       is_zero_oid $sha1_dst
-               then
-                       case "$mod_dst" in
-                       160000)
-                               sha1_dst=$(GIT_DIR="$name/.git" git rev-parse HEAD)
-                               ;;
-                       100644 | 100755 | 120000)
-                               sha1_dst=$(git hash-object $name)
-                               ;;
-                       000000)
-                               ;; # removed
-                       *)
-                               # unexpected type
-                               eval_gettextln "unexpected mode \$mod_dst" >&2
-                               continue ;;
-                       esac
-               fi
-               missing_src=
-               missing_dst=
-
-               test $mod_src = 160000 &&
-               ! GIT_DIR="$name/.git" git rev-parse -q --verify $sha1_src^0 >/dev/null &&
-               missing_src=t
-
-               test $mod_dst = 160000 &&
-               ! GIT_DIR="$name/.git" git rev-parse -q --verify $sha1_dst^0 >/dev/null &&
-               missing_dst=t
-
-               display_name=$(git submodule--helper relative-path "$name" "$wt_prefix")
-
-               total_commits=
-               case "$missing_src,$missing_dst" in
-               t,)
-                       errmsg="$(eval_gettext "  Warn: \$display_name doesn't contain commit \$sha1_src")"
-                       ;;
-               ,t)
-                       errmsg="$(eval_gettext "  Warn: \$display_name doesn't contain commit \$sha1_dst")"
-                       ;;
-               t,t)
-                       errmsg="$(eval_gettext "  Warn: \$display_name doesn't contain commits \$sha1_src and \$sha1_dst")"
-                       ;;
-               *)
-                       errmsg=
-                       total_commits=$(
-                       if test $mod_src = 160000 && test $mod_dst = 160000
-                       then
-                               range="$sha1_src...$sha1_dst"
-                       elif test $mod_src = 160000
-                       then
-                               range=$sha1_src
-                       else
-                               range=$sha1_dst
-                       fi
-                       GIT_DIR="$name/.git" \
-                       git rev-list --first-parent $range -- | wc -l
-                       )
-                       total_commits=" ($(($total_commits + 0)))"
-                       ;;
-               esac
-
-               sha1_abbr_src=$(GIT_DIR="$name/.git" git rev-parse --short $sha1_src 2>/dev/null ||
-                       echo $sha1_src | cut -c1-7)
-               sha1_abbr_dst=$(GIT_DIR="$name/.git" git rev-parse --short $sha1_dst 2>/dev/null ||
-                       echo $sha1_dst | cut -c1-7)
-
-               if test $status = T
-               then
-                       blob="$(gettext "blob")"
-                       submodule="$(gettext "submodule")"
-                       if test $mod_dst = 160000
-                       then
-                               echo "* $display_name $sha1_abbr_src($blob)->$sha1_abbr_dst($submodule)$total_commits:"
-                       else
-                               echo "* $display_name $sha1_abbr_src($submodule)->$sha1_abbr_dst($blob)$total_commits:"
-                       fi
-               else
-                       echo "* $display_name $sha1_abbr_src...$sha1_abbr_dst$total_commits:"
-               fi
-               if test -n "$errmsg"
-               then
-                       # Don't give error msg for modification whose dst is not submodule
-                       # i.e. deleted or changed to blob
-                       test $mod_dst = 160000 && echo "$errmsg"
-               else
-                       if test $mod_src = 160000 && test $mod_dst = 160000
-                       then
-                               limit=
-                               test $summary_limit -gt 0 && limit="-$summary_limit"
-                               GIT_DIR="$name/.git" \
-                               git log $limit --pretty='format:  %m %s' \
-                               --first-parent $sha1_src...$sha1_dst
-                       elif test $mod_dst = 160000
-                       then
-                               GIT_DIR="$name/.git" \
-                               git log --pretty='format:  > %s' -1 $sha1_dst
-                       else
-                               GIT_DIR="$name/.git" \
-                               git log --pretty='format:  < %s' -1 $sha1_src
-                       fi
-                       echo
-               fi
-               echo
-       done
+       git ${wt_prefix:+-C "$wt_prefix"} submodule--helper summary ${prefix:+--prefix "$prefix"} ${files:+--files} ${cached:+--cached} ${for_status:+--for-status} ${summary_limit:+-n $summary_limit} -- "$@"
 }
 #
 # List all submodules, prefixed with:
diff --git a/git.c b/git.c
index 8bd1d7551daa28dcde69935046a055243c4b4d99..01c456edce923cd895a95a83ac211b6a5e5a3e0c 100644 (file)
--- a/git.c
+++ b/git.c
@@ -479,6 +479,7 @@ static struct cmd_struct commands[] = {
        { "bisect--helper", cmd_bisect__helper, RUN_SETUP },
        { "blame", cmd_blame, RUN_SETUP },
        { "branch", cmd_branch, RUN_SETUP | DELAY_PAGER_CONFIG },
+       { "bugreport", cmd_bugreport, RUN_SETUP_GENTLY },
        { "bundle", cmd_bundle, RUN_SETUP_GENTLY | NO_PARSEOPT },
        { "cat-file", cmd_cat_file, RUN_SETUP },
        { "check-attr", cmd_check_attr, RUN_SETUP },
@@ -499,6 +500,9 @@ static struct cmd_struct commands[] = {
        { "config", cmd_config, RUN_SETUP_GENTLY | DELAY_PAGER_CONFIG },
        { "count-objects", cmd_count_objects, RUN_SETUP },
        { "credential", cmd_credential, RUN_SETUP_GENTLY | NO_PARSEOPT },
+       { "credential-cache", cmd_credential_cache },
+       { "credential-cache--daemon", cmd_credential_cache_daemon },
+       { "credential-store", cmd_credential_store },
        { "describe", cmd_describe, RUN_SETUP },
        { "diff", cmd_diff, NO_PARSEOPT },
        { "diff-files", cmd_diff_files, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT },
@@ -507,6 +511,7 @@ static struct cmd_struct commands[] = {
        { "difftool", cmd_difftool, RUN_SETUP_GENTLY },
        { "env--helper", cmd_env__helper },
        { "fast-export", cmd_fast_export, RUN_SETUP },
+       { "fast-import", cmd_fast_import, RUN_SETUP | NO_PARSEOPT },
        { "fetch", cmd_fetch, RUN_SETUP },
        { "fetch-pack", cmd_fetch_pack, RUN_SETUP | NO_PARSEOPT },
        { "fmt-merge-msg", cmd_fmt_merge_msg, RUN_SETUP },
diff --git a/ident.c b/ident.c
index e666ee4e598eb7de70b524bd56c7d04a27549971..6aba4b5cb6f2cb3bf469f4f9111845a70a0e5031 100644 (file)
--- a/ident.c
+++ b/ident.c
@@ -345,27 +345,45 @@ person_only:
        return 0;
 }
 
-static const char *env_hint =
-N_("\n"
-   "*** Please tell me who you are.\n"
-   "\n"
-   "Run\n"
-   "\n"
-   "  git config --global user.email \"you@example.com\"\n"
-   "  git config --global user.name \"Your Name\"\n"
-   "\n"
-   "to set your account\'s default identity.\n"
-   "Omit --global to set the identity only in this repository.\n"
-   "\n");
+
+static void ident_env_hint(enum want_ident whose_ident)
+{
+       switch (whose_ident) {
+       case WANT_AUTHOR_IDENT:
+               fputs(_("Author identity unknown\n"), stderr);
+               break;
+       case WANT_COMMITTER_IDENT:
+               fputs(_("Committer identity unknown\n"), stderr);
+               break;
+       default:
+               break;
+       }
+
+       fputs(_("\n"
+               "*** Please tell me who you are.\n"
+               "\n"
+               "Run\n"
+               "\n"
+               "  git config --global user.email \"you@example.com\"\n"
+               "  git config --global user.name \"Your Name\"\n"
+               "\n"
+               "to set your account\'s default identity.\n"
+               "Omit --global to set the identity only in this repository.\n"
+               "\n"), stderr);
+}
 
 const char *fmt_ident(const char *name, const char *email,
                      enum want_ident whose_ident, const char *date_str, int flag)
 {
-       static struct strbuf ident = STRBUF_INIT;
+       static int index;
+       static struct strbuf ident_pool[2] = { STRBUF_INIT, STRBUF_INIT };
        int strict = (flag & IDENT_STRICT);
        int want_date = !(flag & IDENT_NO_DATE);
        int want_name = !(flag & IDENT_NO_NAME);
 
+       struct strbuf *ident = &ident_pool[index];
+       index = (index + 1) % ARRAY_SIZE(ident_pool);
+
        if (!email) {
                if (whose_ident == WANT_AUTHOR_IDENT && git_author_email.len)
                        email = git_author_email.buf;
@@ -375,12 +393,12 @@ const char *fmt_ident(const char *name, const char *email,
        if (!email) {
                if (strict && ident_use_config_only
                    && !(ident_config_given & IDENT_MAIL_GIVEN)) {
-                       fputs(_(env_hint), stderr);
+                       ident_env_hint(whose_ident);
                        die(_("no email was given and auto-detection is disabled"));
                }
                email = ident_default_email();
                if (strict && default_email_is_bogus) {
-                       fputs(_(env_hint), stderr);
+                       ident_env_hint(whose_ident);
                        die(_("unable to auto-detect email address (got '%s')"), email);
                }
        }
@@ -397,13 +415,13 @@ const char *fmt_ident(const char *name, const char *email,
                if (!name) {
                        if (strict && ident_use_config_only
                            && !(ident_config_given & IDENT_NAME_GIVEN)) {
-                               fputs(_(env_hint), stderr);
+                               ident_env_hint(whose_ident);
                                die(_("no name was given and auto-detection is disabled"));
                        }
                        name = ident_default_name();
                        using_default = 1;
                        if (strict && default_name_is_bogus) {
-                               fputs(_(env_hint), stderr);
+                               ident_env_hint(whose_ident);
                                die(_("unable to auto-detect name (got '%s')"), name);
                        }
                }
@@ -411,7 +429,7 @@ const char *fmt_ident(const char *name, const char *email,
                        struct passwd *pw;
                        if (strict) {
                                if (using_default)
-                                       fputs(_(env_hint), stderr);
+                                       ident_env_hint(whose_ident);
                                die(_("empty ident name (for <%s>) not allowed"), email);
                        }
                        pw = xgetpwuid_self(NULL);
@@ -421,25 +439,25 @@ const char *fmt_ident(const char *name, const char *email,
                        die(_("name consists only of disallowed characters: %s"), name);
        }
 
-       strbuf_reset(&ident);
+       strbuf_reset(ident);
        if (want_name) {
-               strbuf_addstr_without_crud(&ident, name);
-               strbuf_addstr(&ident, " <");
+               strbuf_addstr_without_crud(ident, name);
+               strbuf_addstr(ident, " <");
        }
-       strbuf_addstr_without_crud(&ident, email);
+       strbuf_addstr_without_crud(ident, email);
        if (want_name)
-                       strbuf_addch(&ident, '>');
+               strbuf_addch(ident, '>');
        if (want_date) {
-               strbuf_addch(&ident, ' ');
+               strbuf_addch(ident, ' ');
                if (date_str && date_str[0]) {
-                       if (parse_date(date_str, &ident) < 0)
+                       if (parse_date(date_str, ident) < 0)
                                die(_("invalid date format: %s"), date_str);
                }
                else
-                       strbuf_addstr(&ident, ident_default_date());
+                       strbuf_addstr(ident, ident_default_date());
        }
 
-       return ident.buf;
+       return ident->buf;
 }
 
 const char *fmt_name(enum want_ident whose_ident)
diff --git a/midx.c b/midx.c
index e9b2e1253a678836dab68a1f15cdaf954444cfea..cc19b6615281475f25cc4119ff2246e2961497fa 100644 (file)
--- a/midx.c
+++ b/midx.c
@@ -416,8 +416,12 @@ int prepare_multi_pack_index_one(struct repository *r, const char *object_dir, i
        m = load_multi_pack_index(object_dir, local);
 
        if (m) {
-               m->next = r->objects->multi_pack_index;
-               r->objects->multi_pack_index = m;
+               struct multi_pack_index *mp = r->objects->multi_pack_index;
+               if (mp) {
+                       m->next = mp->next;
+                       mp->next = m;
+               } else
+                       r->objects->multi_pack_index = m;
                return 1;
        }
 
diff --git a/negotiator/noop.c b/negotiator/noop.c
new file mode 100644 (file)
index 0000000..60569b8
--- /dev/null
@@ -0,0 +1,44 @@
+#include "cache.h"
+#include "noop.h"
+#include "../commit.h"
+#include "../fetch-negotiator.h"
+
+static void known_common(struct fetch_negotiator *n, struct commit *c)
+{
+       /* do nothing */
+}
+
+static void add_tip(struct fetch_negotiator *n, struct commit *c)
+{
+       /* do nothing */
+}
+
+static const struct object_id *next(struct fetch_negotiator *n)
+{
+       return NULL;
+}
+
+static int ack(struct fetch_negotiator *n, struct commit *c)
+{
+       /*
+        * This negotiator does not emit any commits, so there is no commit to
+        * be acknowledged. If there is any ack, there is a bug.
+        */
+       BUG("ack with noop negotiator, which does not emit any commits");
+       return 0;
+}
+
+static void release(struct fetch_negotiator *n)
+{
+       /* nothing to release */
+}
+
+void noop_negotiator_init(struct fetch_negotiator *negotiator)
+{
+       negotiator->known_common = known_common;
+       negotiator->add_tip = add_tip;
+       negotiator->next = next;
+       negotiator->ack = ack;
+       negotiator->release = release;
+       negotiator->data = NULL;
+}
diff --git a/negotiator/noop.h b/negotiator/noop.h
new file mode 100644 (file)
index 0000000..2b4ec5d
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef NEGOTIATOR_NOOP_H
+#define NEGOTIATOR_NOOP_H
+
+struct fetch_negotiator;
+
+void noop_negotiator_init(struct fetch_negotiator *negotiator);
+
+#endif
index 6ab5233613e2417f8ee9ce0991ae532726b59b20..9ef27508f2ed6d2685e5d85cd92667ac735140d5 100644 (file)
@@ -1027,6 +1027,17 @@ struct multi_pack_index *get_multi_pack_index(struct repository *r)
        return r->objects->multi_pack_index;
 }
 
+struct multi_pack_index *get_local_multi_pack_index(struct repository *r)
+{
+       struct multi_pack_index *m = get_multi_pack_index(r);
+
+       /* no need to iterate; we always put the local one first (if any) */
+       if (m && m->local)
+               return m;
+
+       return NULL;
+}
+
 struct packed_git *get_all_packs(struct repository *r)
 {
        struct multi_pack_index *m;
index 240aa73b95a64912fb2cde5be049f57d91e53b84..a58fc738e06319624b666c80e2636217400cdda9 100644 (file)
@@ -57,6 +57,7 @@ void install_packed_git(struct repository *r, struct packed_git *pack);
 struct packed_git *get_packed_git(struct repository *r);
 struct list_head *get_packed_git_mru(struct repository *r);
 struct multi_pack_index *get_multi_pack_index(struct repository *r);
+struct multi_pack_index *get_local_multi_pack_index(struct repository *r);
 struct packed_git *get_all_packs(struct repository *r);
 
 /*
diff --git a/path.c b/path.c
index 8b2c7531919eef89b340b3323d1cbd806ba57b0c..7b385e5eb282276f5d2e0becde48d5e09434d6b1 100644 (file)
--- a/path.c
+++ b/path.c
@@ -1528,8 +1528,6 @@ char *xdg_cache_home(const char *filename)
        return NULL;
 }
 
-REPO_GIT_PATH_FUNC(cherry_pick_head, "CHERRY_PICK_HEAD")
-REPO_GIT_PATH_FUNC(revert_head, "REVERT_HEAD")
 REPO_GIT_PATH_FUNC(squash_msg, "SQUASH_MSG")
 REPO_GIT_PATH_FUNC(merge_msg, "MERGE_MSG")
 REPO_GIT_PATH_FUNC(merge_rr, "MERGE_RR")
diff --git a/path.h b/path.h
index 1f1bf8f87a86d4444879d3fdc0a30076b2c111f3..e7e77da6aaa5cf8e4652141ecf785ee18effeaca 100644 (file)
--- a/path.h
+++ b/path.h
@@ -170,8 +170,6 @@ void report_linked_checkout_garbage(void);
        }
 
 struct path_cache {
-       const char *cherry_pick_head;
-       const char *revert_head;
        const char *squash_msg;
        const char *merge_msg;
        const char *merge_rr;
@@ -182,10 +180,11 @@ struct path_cache {
        const char *shallow;
 };
 
-#define PATH_CACHE_INIT { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
+#define PATH_CACHE_INIT                                        \
+       {                                                      \
+               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL \
+       }
 
-const char *git_path_cherry_pick_head(struct repository *r);
-const char *git_path_revert_head(struct repository *r);
 const char *git_path_squash_msg(struct repository *r);
 const char *git_path_merge_msg(struct repository *r);
 const char *git_path_merge_rr(struct repository *r);
index baaea12fd69b3b2c86f9fe5308a06c65e2eff3eb..6530e26f98cc4df511527a10fda2d605ac5b1e20 100644 (file)
@@ -3,6 +3,7 @@
 #include "promisor-remote.h"
 #include "config.h"
 #include "transport.h"
+#include "strvec.h"
 
 static char *repository_format_partial_clone;
 static const char *core_partial_clone_filter_default;
@@ -12,39 +13,34 @@ void set_repository_format_partial_clone(char *partial_clone)
        repository_format_partial_clone = xstrdup_or_null(partial_clone);
 }
 
-static int fetch_refs(const char *remote_name, struct ref *ref)
-{
-       struct remote *remote;
-       struct transport *transport;
-       int res;
-
-       remote = remote_get(remote_name);
-       if (!remote->url[0])
-               die(_("Remote with no URL"));
-       transport = transport_get(remote, remote->url[0]);
-
-       transport_set_option(transport, TRANS_OPT_FROM_PROMISOR, "1");
-       transport_set_option(transport, TRANS_OPT_NO_DEPENDENTS, "1");
-       res = transport_fetch_refs(transport, ref);
-
-       return res;
-}
-
 static int fetch_objects(const char *remote_name,
                         const struct object_id *oids,
                         int oid_nr)
 {
-       struct ref *ref = NULL;
+       struct child_process child = CHILD_PROCESS_INIT;
        int i;
+       FILE *child_in;
+
+       child.git_cmd = 1;
+       child.in = -1;
+       strvec_pushl(&child.args, "-c", "fetch.negotiationAlgorithm=noop",
+                    "fetch", remote_name, "--no-tags",
+                    "--no-write-fetch-head", "--recurse-submodules=no",
+                    "--filter=blob:none", "--stdin", NULL);
+       if (start_command(&child))
+               die(_("promisor-remote: unable to fork off fetch subprocess"));
+       child_in = xfdopen(child.in, "w");
 
        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;
+               if (fputs(oid_to_hex(&oids[i]), child_in) < 0)
+                       die_errno(_("promisor-remote: could not write to fetch subprocess"));
+               if (fputc('\n', child_in) < 0)
+                       die_errno(_("promisor-remote: could not write to fetch subprocess"));
        }
-       return fetch_refs(remote_name, ref);
+
+       if (fclose(child_in) < 0)
+               die_errno(_("promisor-remote: could not close stdin to fetch subprocess"));
+       return finish_command(&child) ? -1 : 0;
 }
 
 static struct promisor_remote *promisors;
index ba85869755e07195cf0dc2f1dccd127fda4e9fa0..8ba0e31915021e3d60b814332c6a10c10f3a147e 100644 (file)
@@ -345,9 +345,11 @@ static int contents_atom_parser(const struct ref_format *format, struct used_ato
                atom->u.contents.option = C_SIG;
        else if (!strcmp(arg, "subject"))
                atom->u.contents.option = C_SUB;
-       else if (skip_prefix(arg, "trailers", &arg)) {
-               skip_prefix(arg, ":", &arg);
-               if (trailers_atom_parser(format, atom, *arg ? arg : NULL, err))
+       else if (!strcmp(arg, "trailers")) {
+               if (trailers_atom_parser(format, atom, NULL, err))
+                       return -1;
+       } else if (skip_prefix(arg, "trailers:", &arg)) {
+               if (trailers_atom_parser(format, atom, arg, err))
                        return -1;
        } else if (skip_prefix(arg, "lines=", &arg)) {
                atom->u.contents.option = C_LINES;
diff --git a/refs.c b/refs.c
index 3ee3afaf4177c31c37c71e3af3133941faf60532..156fdcd459f22b2f9b7c54c5d85afb086c54fe57 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -313,7 +313,7 @@ int read_ref(const char *refname, struct object_id *oid)
        return read_ref_full(refname, RESOLVE_REF_READING, oid, NULL);
 }
 
-static int refs_ref_exists(struct ref_store *refs, const char *refname)
+int refs_ref_exists(struct ref_store *refs, const char *refname)
 {
        return !!refs_resolve_ref_unsafe(refs, refname, RESOLVE_REF_READING, NULL, NULL);
 }
@@ -1950,24 +1950,17 @@ int ref_update_reject_duplicates(struct string_list *refnames,
        return 0;
 }
 
-static const char hook_not_found;
-static const char *hook;
-
 static int run_transaction_hook(struct ref_transaction *transaction,
                                const char *state)
 {
        struct child_process proc = CHILD_PROCESS_INIT;
        struct strbuf buf = STRBUF_INIT;
+       const char *hook;
        int ret = 0, i;
 
-       if (hook == &hook_not_found)
-               return ret;
+       hook = find_hook("reference-transaction");
        if (!hook)
-               hook = xstrdup_or_null(find_hook("reference-transaction"));
-       if (!hook) {
-               hook = &hook_not_found;
                return ret;
-       }
 
        strvec_pushl(&proc.args, hook, state, NULL);
        proc.in = -1;
diff --git a/refs.h b/refs.h
index 29e28124cd5630cba9e5f251497f2fc64b978863..04bd25019f344b72a3e05470f675dab9b4ffc19d 100644 (file)
--- a/refs.h
+++ b/refs.h
@@ -105,6 +105,8 @@ int refs_verify_refname_available(struct ref_store *refs,
                                  const struct string_list *skip,
                                  struct strbuf *err);
 
+int refs_ref_exists(struct ref_store *refs, const char *refname);
+
 int ref_exists(const char *refname);
 
 int should_autocreate_reflog(const char *refname);
index 23e1555b88acb431b3b2cee9fabbe8e4eb33fee6..8d654e3a3ac40940c7d05f7ce671f538b7d250f2 100644 (file)
--- a/refspec.h
+++ b/refspec.h
@@ -4,6 +4,19 @@
 #define TAG_REFSPEC "refs/tags/*:refs/tags/*"
 extern const struct refspec_item *tag_refspec;
 
+/**
+ * A struct refspec_item holds the parsed interpretation of a refspec.  If it will
+ * force updates (starts with a '+'), force is true.  If it is a pattern
+ * (sides end with '*') pattern is true.  src and dest are the two sides
+ * (including '*' characters if present); if there is only one side, it is src,
+ * and dst is NULL; if sides exist but are empty (i.e., the refspec either
+ * starts or ends with ':'), the corresponding side is "".
+ *
+ * remote_find_tracking(), given a remote and a struct refspec_item with either src
+ * or dst filled out, will fill out the other such that the result is in the
+ * "fetch" specification for the remote (note that this evaluates patterns and
+ * returns a single result).
+ */
 struct refspec_item {
        unsigned force : 1;
        unsigned pattern : 1;
@@ -21,20 +34,8 @@ struct refspec_item {
 #define REFSPEC_INIT_PUSH { .fetch = REFSPEC_PUSH }
 
 /**
- * A struct refspec holds the parsed interpretation of a refspec.  If it will
- * force updates (starts with a '+'), force is true.  If it is a pattern
- * (sides end with '*') pattern is true.  src and dest are the two sides
- * (including '*' characters if present); if there is only one side, it is src,
- * and dst is NULL; if sides exist but are empty (i.e., the refspec either
- * starts or ends with ':'), the corresponding side is "".
- *
- * An array of strings can be parsed into an array of struct refspecs using
+ * An array of strings can be parsed into a struct refspec using
  * parse_fetch_refspec() or parse_push_refspec().
- *
- * remote_find_tracking(), given a remote and a struct refspec with either src
- * or dst filled out, will fill out the other such that the result is in the
- * "fetch" specification for the remote (note that this evaluates patterns and
- * returns a single result).
  */
 struct refspec {
        struct refspec_item *items;
index 62b3a45cde26b028fcfe2c242dbd79f6dab25a80..32cc4a0c553b3e6f953be247bd593e07222dd5b5 100644 (file)
@@ -39,8 +39,10 @@ struct options {
                /* One of the SEND_PACK_PUSH_CERT_* constants. */
                push_cert : 2,
                deepen_relative : 1,
+
+               /* see documentation of corresponding flag in fetch-pack.h */
                from_promisor : 1,
-               no_dependents : 1,
+
                atomic : 1,
                object_format : 1;
        const struct git_hash_algo *hash_algo;
@@ -190,9 +192,6 @@ static int set_option(const char *name, const char *value)
        } else if (!strcmp(name, "from-promisor")) {
                options.from_promisor = 1;
                return 0;
-       } else if (!strcmp(name, "no-dependents")) {
-               options.no_dependents = 1;
-               return 0;
        } else if (!strcmp(name, "filter")) {
                options.filter = xstrdup(value);
                return 0;
@@ -1175,8 +1174,6 @@ static int fetch_git(struct discovery *heads,
                strvec_push(&args, "--deepen-relative");
        if (options.from_promisor)
                strvec_push(&args, "--from-promisor");
-       if (options.no_dependents)
-               strvec_push(&args, "--no-dependents");
        if (options.filter)
                strvec_pushf(&args, "--filter=%s", options.filter);
        strvec_push(&args, url.buf);
diff --git a/remote-testsvn.c b/remote-testsvn.c
deleted file mode 100644 (file)
index 636b2b6..0000000
+++ /dev/null
@@ -1,341 +0,0 @@
-#include "cache.h"
-#include "refs.h"
-#include "remote.h"
-#include "object-store.h"
-#include "strbuf.h"
-#include "url.h"
-#include "exec-cmd.h"
-#include "run-command.h"
-#include "vcs-svn/svndump.h"
-#include "notes.h"
-#include "strvec.h"
-
-static const char *url;
-static int dump_from_file;
-static const char *private_ref;
-static char *remote_ref;
-static const char *marksfilename, *notes_ref;
-struct rev_note { unsigned int rev_nr; };
-
-static int cmd_capabilities(const char *line);
-static int cmd_import(const char *line);
-static int cmd_list(const char *line);
-
-typedef int (*input_command_handler)(const char *);
-struct input_command_entry {
-       const char *name;
-       input_command_handler fn;
-       unsigned char batchable;        /* whether the command starts or is part of a batch */
-};
-
-static const struct input_command_entry input_command_list[] = {
-       { "capabilities", cmd_capabilities, 0 },
-       { "import", cmd_import, 1 },
-       { "list", cmd_list, 0 },
-       { NULL, NULL }
-};
-
-static int cmd_capabilities(const char *line)
-{
-       printf("import\n");
-       printf("bidi-import\n");
-       printf("refspec %s:%s\n\n", remote_ref, private_ref);
-       fflush(stdout);
-       return 0;
-}
-
-static void terminate_batch(void)
-{
-       /* terminate a current batch's fast-import stream */
-       printf("done\n");
-       fflush(stdout);
-}
-
-/* NOTE: 'ref' refers to a git reference, while 'rev' refers to a svn revision. */
-static char *read_ref_note(const struct object_id *oid)
-{
-       const struct object_id *note_oid;
-       char *msg = NULL;
-       unsigned long msglen;
-       enum object_type type;
-
-       init_notes(NULL, notes_ref, NULL, 0);
-       if (!(note_oid = get_note(NULL, oid)))
-               return NULL;    /* note tree not found */
-       if (!(msg = read_object_file(note_oid, &type, &msglen)))
-               error("Empty notes tree. %s", notes_ref);
-       else if (!msglen || type != OBJ_BLOB) {
-               error("Note contains unusable content. "
-                       "Is something else using this notes tree? %s", notes_ref);
-               FREE_AND_NULL(msg);
-       }
-       free_notes(NULL);
-       return msg;
-}
-
-static int parse_rev_note(const char *msg, struct rev_note *res)
-{
-       const char *key, *value, *end;
-       size_t len;
-
-       while (*msg) {
-               end = strchrnul(msg, '\n');
-               len = end - msg;
-
-               key = "Revision-number: ";
-               if (starts_with(msg, key)) {
-                       long i;
-                       char *end;
-                       value = msg + strlen(key);
-                       i = strtol(value, &end, 0);
-                       if (end == value || i < 0 || i > UINT32_MAX)
-                               return -1;
-                       res->rev_nr = i;
-                       return 0;
-               }
-               msg += len + 1;
-       }
-       /* didn't find it */
-       return -1;
-}
-
-static int note2mark_cb(const struct object_id *object_oid,
-               const struct object_id *note_oid, char *note_path,
-               void *cb_data)
-{
-       FILE *file = (FILE *)cb_data;
-       char *msg;
-       unsigned long msglen;
-       enum object_type type;
-       struct rev_note note;
-
-       if (!(msg = read_object_file(note_oid, &type, &msglen)) ||
-                       !msglen || type != OBJ_BLOB) {
-               free(msg);
-               return 1;
-       }
-       if (parse_rev_note(msg, &note))
-               return 2;
-       if (fprintf(file, ":%d %s\n", note.rev_nr, oid_to_hex(object_oid)) < 1)
-               return 3;
-       return 0;
-}
-
-static void regenerate_marks(void)
-{
-       int ret;
-       FILE *marksfile = xfopen(marksfilename, "w+");
-
-       ret = for_each_note(NULL, 0, note2mark_cb, marksfile);
-       if (ret)
-               die("Regeneration of marks failed, returned %d.", ret);
-       fclose(marksfile);
-}
-
-static void check_or_regenerate_marks(int latestrev)
-{
-       FILE *marksfile;
-       struct strbuf sb = STRBUF_INIT;
-       struct strbuf line = STRBUF_INIT;
-       int found = 0;
-
-       if (latestrev < 1)
-               return;
-
-       init_notes(NULL, notes_ref, NULL, 0);
-       marksfile = fopen(marksfilename, "r");
-       if (!marksfile) {
-               regenerate_marks();
-               marksfile = xfopen(marksfilename, "r");
-               fclose(marksfile);
-       } else {
-               strbuf_addf(&sb, ":%d ", latestrev);
-               while (strbuf_getline_lf(&line, marksfile) != EOF) {
-                       if (starts_with(line.buf, sb.buf)) {
-                               found++;
-                               break;
-                       }
-               }
-               fclose(marksfile);
-               if (!found)
-                       regenerate_marks();
-       }
-       free_notes(NULL);
-       strbuf_release(&sb);
-       strbuf_release(&line);
-}
-
-static int cmd_import(const char *line)
-{
-       int code;
-       int dumpin_fd;
-       char *note_msg;
-       struct object_id head_oid;
-       unsigned int startrev;
-       struct child_process svndump_proc = CHILD_PROCESS_INIT;
-       const char *command = "svnrdump";
-
-       if (read_ref(private_ref, &head_oid))
-               startrev = 0;
-       else {
-               note_msg = read_ref_note(&head_oid);
-               if(note_msg == NULL) {
-                       warning("No note found for %s.", private_ref);
-                       startrev = 0;
-               } else {
-                       struct rev_note note = { 0 };
-                       if (parse_rev_note(note_msg, &note))
-                               die("Revision number couldn't be parsed from note.");
-                       startrev = note.rev_nr + 1;
-                       free(note_msg);
-               }
-       }
-       check_or_regenerate_marks(startrev - 1);
-
-       if (dump_from_file) {
-               dumpin_fd = open(url, O_RDONLY);
-               if(dumpin_fd < 0)
-                       die_errno("Couldn't open svn dump file %s.", url);
-       } else {
-               svndump_proc.out = -1;
-               strvec_push(&svndump_proc.args, command);
-               strvec_push(&svndump_proc.args, "dump");
-               strvec_push(&svndump_proc.args, url);
-               strvec_pushf(&svndump_proc.args, "-r%u:HEAD", startrev);
-
-               code = start_command(&svndump_proc);
-               if (code)
-                       die("Unable to start %s, code %d", command, code);
-               dumpin_fd = svndump_proc.out;
-       }
-       /* setup marks file import/export */
-       printf("feature import-marks-if-exists=%s\n"
-                       "feature export-marks=%s\n", marksfilename, marksfilename);
-
-       svndump_init_fd(dumpin_fd, STDIN_FILENO);
-       svndump_read(url, private_ref, notes_ref);
-       svndump_deinit();
-       svndump_reset();
-
-       close(dumpin_fd);
-       if (!dump_from_file) {
-               code = finish_command(&svndump_proc);
-               if (code)
-                       warning("%s, returned %d", command, code);
-       }
-
-       return 0;
-}
-
-static int cmd_list(const char *line)
-{
-       printf("? %s\n\n", remote_ref);
-       fflush(stdout);
-       return 0;
-}
-
-static int do_command(struct strbuf *line)
-{
-       const struct input_command_entry *p = input_command_list;
-       static struct string_list batchlines = STRING_LIST_INIT_DUP;
-       static const struct input_command_entry *batch_cmd;
-       /*
-        * commands can be grouped together in a batch.
-        * Batches are ended by \n. If no batch is active the program ends.
-        * During a batch all lines are buffered and passed to the handler function
-        * when the batch is terminated.
-        */
-       if (line->len == 0) {
-               if (batch_cmd) {
-                       struct string_list_item *item;
-                       for_each_string_list_item(item, &batchlines)
-                               batch_cmd->fn(item->string);
-                       terminate_batch();
-                       batch_cmd = NULL;
-                       string_list_clear(&batchlines, 0);
-                       return 0;       /* end of the batch, continue reading other commands. */
-               }
-               return 1;       /* end of command stream, quit */
-       }
-       if (batch_cmd) {
-               if (!starts_with(batch_cmd->name, line->buf))
-                       die("Active %s batch interrupted by %s", batch_cmd->name, line->buf);
-               /* buffer batch lines */
-               string_list_append(&batchlines, line->buf);
-               return 0;
-       }
-
-       for (p = input_command_list; p->name; p++) {
-               if (starts_with(line->buf, p->name) && (strlen(p->name) == line->len ||
-                               line->buf[strlen(p->name)] == ' ')) {
-                       if (p->batchable) {
-                               batch_cmd = p;
-                               string_list_append(&batchlines, line->buf);
-                               return 0;
-                       }
-                       return p->fn(line->buf);
-               }
-       }
-       die("Unknown command '%s'\n", line->buf);
-       return 0;
-}
-
-int cmd_main(int argc, const char **argv)
-{
-       struct strbuf buf = STRBUF_INIT, url_sb = STRBUF_INIT,
-                       private_ref_sb = STRBUF_INIT, marksfilename_sb = STRBUF_INIT,
-                       notes_ref_sb = STRBUF_INIT;
-       static struct remote *remote;
-       const char *url_in, *remote_ref_short;
-
-       setup_git_directory();
-       if (argc < 2 || argc > 3) {
-               usage("git-remote-svn <remote-name> [<url>]");
-               return 1;
-       }
-
-       remote_ref_short = git_default_branch_name();
-       remote_ref = xstrfmt("refs/heads/%s", remote_ref_short);
-
-       remote = remote_get(argv[1]);
-       url_in = (argc == 3) ? argv[2] : remote->url[0];
-
-       if (starts_with(url_in, "file://")) {
-               dump_from_file = 1;
-               url = url_decode(url_in + sizeof("file://")-1);
-       } else {
-               dump_from_file = 0;
-               end_url_with_slash(&url_sb, url_in);
-               url = url_sb.buf;
-       }
-
-       strbuf_addf(&private_ref_sb, "refs/svn/%s/%s",
-                   remote->name, remote_ref_short);
-       private_ref = private_ref_sb.buf;
-
-       strbuf_addf(&notes_ref_sb, "refs/notes/%s/revs", remote->name);
-       notes_ref = notes_ref_sb.buf;
-
-       strbuf_addf(&marksfilename_sb, "%s/info/fast-import/remote-svn/%s.marks",
-               get_git_dir(), remote->name);
-       marksfilename = marksfilename_sb.buf;
-
-       while (1) {
-               if (strbuf_getline_lf(&buf, stdin) == EOF) {
-                       if (ferror(stdin))
-                               die("Error reading command stream");
-                       else
-                               die("Unexpected end of command stream");
-               }
-               if (do_command(&buf))
-                       break;
-               strbuf_reset(&buf);
-       }
-
-       strbuf_release(&buf);
-       strbuf_release(&url_sb);
-       strbuf_release(&private_ref_sb);
-       strbuf_release(&notes_ref_sb);
-       strbuf_release(&marksfilename_sb);
-       return 0;
-}
index 0918408b34436a02589cdb850da8345671e4a5f1..aa61a35338138edb31ff6791ad08d560b674c04b 100644 (file)
@@ -39,6 +39,8 @@ void prepare_repo_settings(struct repository *r)
        if (!repo_config_get_string(r, "fetch.negotiationalgorithm", &strval)) {
                if (!strcasecmp(strval, "skipping"))
                        r->settings.fetch_negotiation_algorithm = FETCH_NEGOTIATION_SKIPPING;
+               else if (!strcasecmp(strval, "noop"))
+                       r->settings.fetch_negotiation_algorithm = FETCH_NEGOTIATION_NOOP;
                else
                        r->settings.fetch_negotiation_algorithm = FETCH_NEGOTIATION_DEFAULT;
        }
index 3c1f7d54bd37a55f6cd1b1ac1f936dc0c17b3dab..628c8343672dbcbbb6b36f732a6d225c726546e0 100644 (file)
@@ -23,6 +23,7 @@ enum fetch_negotiation_setting {
        FETCH_NEGOTIATION_NONE = 0,
        FETCH_NEGOTIATION_DEFAULT = 1,
        FETCH_NEGOTIATION_SKIPPING = 2,
+       FETCH_NEGOTIATION_NOOP = 3,
 };
 
 struct repo_settings {
index 73e3d14cc16500d61ab58e7ccf8daef9537a9cf9..0d67b842fd8b14fb6997e0ebfd9113135123b373 100644 (file)
@@ -2017,7 +2017,7 @@ static int handle_dotdot(const char *arg,
        return ret;
 }
 
-int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsigned revarg_opt)
+static int handle_revision_arg_1(const char *arg_, struct rev_info *revs, int flags, unsigned revarg_opt)
 {
        struct object_context oc;
        char *mark;
@@ -2092,6 +2092,14 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsi
        return 0;
 }
 
+int handle_revision_arg(const char *arg, struct rev_info *revs, int flags, unsigned revarg_opt)
+{
+       int ret = handle_revision_arg_1(arg, revs, flags, revarg_opt);
+       if (!ret)
+               revs->rev_input_given = 1;
+       return ret;
+}
+
 static void read_pathspec_from_stdin(struct strbuf *sb,
                                     struct strvec *prune)
 {
@@ -2709,7 +2717,7 @@ static void NORETURN diagnose_missing_default(const char *def)
  */
 int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct setup_revision_opt *opt)
 {
-       int i, flags, left, seen_dashdash, got_rev_arg = 0, revarg_opt;
+       int i, flags, left, seen_dashdash, revarg_opt;
        struct strvec prune_data = STRVEC_INIT;
        const char *submodule = NULL;
        int seen_end_of_options = 0;
@@ -2798,8 +2806,6 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
                        strvec_pushv(&prune_data, argv + i);
                        break;
                }
-               else
-                       got_rev_arg = 1;
        }
 
        if (prune_data.nr) {
@@ -2828,7 +2834,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
                opt->tweak(revs, opt);
        if (revs->show_merge)
                prepare_show_merge(revs);
-       if (revs->def && !revs->pending.nr && !revs->rev_input_given && !got_rev_arg) {
+       if (revs->def && !revs->pending.nr && !revs->rev_input_given) {
                struct object_id oid;
                struct object *object;
                struct object_context oc;
index 2425896911a7f5dd3979bde17f854c3a98c15177..e8676e965fca6813d49cb4b30cc4fab5b8da3390 100644 (file)
@@ -150,6 +150,8 @@ static GIT_PATH_FUNC(rebase_path_refs_to_delete, "rebase-merge/refs-to-delete")
  * command-line.
  */
 static GIT_PATH_FUNC(rebase_path_gpg_sign_opt, "rebase-merge/gpg_sign_opt")
+static GIT_PATH_FUNC(rebase_path_cdate_is_adate, "rebase-merge/cdate_is_adate")
+static GIT_PATH_FUNC(rebase_path_ignore_date, "rebase-merge/ignore_date")
 static GIT_PATH_FUNC(rebase_path_orig_head, "rebase-merge/orig-head")
 static GIT_PATH_FUNC(rebase_path_verbose, "rebase-merge/verbose")
 static GIT_PATH_FUNC(rebase_path_quiet, "rebase-merge/quiet")
@@ -303,6 +305,8 @@ int sequencer_remove_state(struct replay_opts *opts)
                }
        }
 
+       free(opts->committer_name);
+       free(opts->committer_email);
        free(opts->gpg_sign);
        free(opts->strategy);
        for (i = 0; i < opts->xopts_nr; i++)
@@ -381,7 +385,8 @@ static void print_advice(struct repository *r, int show_hint,
                 * (typically rebase --interactive) wants to take care
                 * of the commit itself so remove CHERRY_PICK_HEAD
                 */
-               unlink(git_path_cherry_pick_head(r));
+               refs_delete_ref(get_main_ref_store(r), "", "CHERRY_PICK_HEAD",
+                               NULL, 0);
                return;
        }
 
@@ -863,6 +868,22 @@ static char *get_author(const char *message)
        return NULL;
 }
 
+static const char *author_date_from_env_array(const struct strvec *env)
+{
+       int i;
+       const char *date;
+
+       for (i = 0; i < env->nr; i++)
+               if (skip_prefix(env->v[i],
+                               "GIT_AUTHOR_DATE=", &date))
+                       return date;
+       /*
+        * If GIT_AUTHOR_DATE is missing we should have already errored out when
+        * reading the script
+        */
+       BUG("GIT_AUTHOR_DATE missing from author script");
+}
+
 static const char staged_changes_advice[] =
 N_("you have staged changes in your working tree\n"
 "If these changes are meant to be squashed into the previous commit, run:\n"
@@ -929,6 +950,14 @@ static int run_git_commit(struct repository *r,
                             gpg_opt, gpg_opt);
        }
 
+       if (opts->committer_date_is_author_date)
+               strvec_pushf(&cmd.env_array, "GIT_COMMITTER_DATE=%s",
+                            opts->ignore_date ?
+                            "" :
+                            author_date_from_env_array(&cmd.env_array));
+       if (opts->ignore_date)
+               strvec_push(&cmd.env_array, "GIT_AUTHOR_DATE=");
+
        strvec_push(&cmd.args, "commit");
 
        if (!(flags & VERIFY_MSG))
@@ -1308,6 +1337,7 @@ static int try_to_commit(struct repository *r,
        struct strbuf err = STRBUF_INIT;
        struct strbuf commit_msg = STRBUF_INIT;
        char *amend_author = NULL;
+       const char *committer = NULL;
        const char *hook_commit = NULL;
        enum commit_msg_cleanup_mode cleanup;
        int res = 0;
@@ -1399,10 +1429,57 @@ static int try_to_commit(struct repository *r,
                goto out;
        }
 
-       reset_ident_date();
+       if (opts->committer_date_is_author_date) {
+               struct ident_split id;
+               struct strbuf date = STRBUF_INIT;
+
+               if (!opts->ignore_date) {
+                       if (split_ident_line(&id, author, (int)strlen(author)) < 0) {
+                               res = error(_("invalid author identity '%s'"),
+                                           author);
+                               goto out;
+                       }
+                       if (!id.date_begin) {
+                               res = error(_(
+                                       "corrupt author: missing date information"));
+                               goto out;
+                       }
+                       strbuf_addf(&date, "@%.*s %.*s",
+                                   (int)(id.date_end - id.date_begin),
+                                   id.date_begin,
+                                   (int)(id.tz_end - id.tz_begin),
+                                   id.tz_begin);
+               } else {
+                       reset_ident_date();
+               }
+               committer = fmt_ident(opts->committer_name,
+                                     opts->committer_email,
+                                     WANT_COMMITTER_IDENT,
+                                     opts->ignore_date ? NULL : date.buf,
+                                     IDENT_STRICT);
+               strbuf_release(&date);
+       } else {
+               reset_ident_date();
+       }
+
+       if (opts->ignore_date) {
+               struct ident_split id;
+               char *name, *email;
+
+               if (split_ident_line(&id, author, strlen(author)) < 0) {
+                       error(_("invalid author identity '%s'"), author);
+                       goto out;
+               }
+               name = xmemdupz(id.name_begin, id.name_end - id.name_begin);
+               email = xmemdupz(id.mail_begin, id.mail_end - id.mail_begin);
+               author = fmt_ident(name, email, WANT_AUTHOR_IDENT, NULL,
+                                  IDENT_STRICT);
+               free(name);
+               free(email);
+       }
 
-       if (commit_tree_extended(msg->buf, msg->len, &tree, parents,
-                                oid, author, opts->gpg_sign, extra)) {
+       if (commit_tree_extended(msg->buf, msg->len, &tree, parents, oid,
+                                author, committer, opts->gpg_sign, extra)) {
                res = error(_("failed to write commit object"));
                goto out;
        }
@@ -1455,7 +1532,8 @@ static int do_commit(struct repository *r,
                                    author, opts, flags, &oid);
                strbuf_release(&sb);
                if (!res) {
-                       unlink(git_path_cherry_pick_head(r));
+                       refs_delete_ref(get_main_ref_store(r), "",
+                                       "CHERRY_PICK_HEAD", NULL, 0);
                        unlink(git_path_merge_msg(r));
                        if (!is_rebase_i(opts))
                                print_commit_summary(r, NULL, &oid,
@@ -1966,7 +2044,8 @@ static int do_pick_commit(struct repository *r,
                flags |= ALLOW_EMPTY;
        } else if (allow == 2) {
                drop_commit = 1;
-               unlink(git_path_cherry_pick_head(r));
+               refs_delete_ref(get_main_ref_store(r), "", "CHERRY_PICK_HEAD",
+                               NULL, 0);
                unlink(git_path_merge_msg(r));
                fprintf(stderr,
                        _("dropping %s %s -- patch contents already upstream\n"),
@@ -2305,15 +2384,19 @@ void sequencer_post_commit_cleanup(struct repository *r, int verbose)
        struct replay_opts opts = REPLAY_OPTS_INIT;
        int need_cleanup = 0;
 
-       if (file_exists(git_path_cherry_pick_head(r))) {
-               if (!unlink(git_path_cherry_pick_head(r)) && verbose)
+       if (refs_ref_exists(get_main_ref_store(r), "CHERRY_PICK_HEAD")) {
+               if (!refs_delete_ref(get_main_ref_store(r), "",
+                                    "CHERRY_PICK_HEAD", NULL, 0) &&
+                   verbose)
                        warning(_("cancelling a cherry picking in progress"));
                opts.action = REPLAY_PICK;
                need_cleanup = 1;
        }
 
-       if (file_exists(git_path_revert_head(r))) {
-               if (!unlink(git_path_revert_head(r)) && verbose)
+       if (refs_ref_exists(get_main_ref_store(r), "REVERT_HEAD")) {
+               if (!refs_delete_ref(get_main_ref_store(r), "", "REVERT_HEAD",
+                                    NULL, 0) &&
+                   verbose)
                        warning(_("cancelling a revert in progress"));
                opts.action = REPLAY_REVERT;
                need_cleanup = 1;
@@ -2528,6 +2611,16 @@ static int read_populate_opts(struct replay_opts *opts)
                        opts->signoff = 1;
                }
 
+               if (file_exists(rebase_path_cdate_is_adate())) {
+                       opts->allow_ff = 0;
+                       opts->committer_date_is_author_date = 1;
+               }
+
+               if (file_exists(rebase_path_ignore_date())) {
+                       opts->allow_ff = 0;
+                       opts->ignore_date = 1;
+               }
+
                if (file_exists(rebase_path_reschedule_failed_exec()))
                        opts->reschedule_failed_exec = 1;
 
@@ -2623,6 +2716,10 @@ int write_basic_state(struct replay_opts *opts, const char *head_name,
                write_file(rebase_path_drop_redundant_commits(), "%s", "");
        if (opts->keep_redundant_commits)
                write_file(rebase_path_keep_redundant_commits(), "%s", "");
+       if (opts->committer_date_is_author_date)
+               write_file(rebase_path_cdate_is_adate(), "%s", "");
+       if (opts->ignore_date)
+               write_file(rebase_path_ignore_date(), "%s", "");
        if (opts->reschedule_failed_exec)
                write_file(rebase_path_reschedule_failed_exec(), "%s", "");
 
@@ -2671,8 +2768,9 @@ static int create_seq_dir(struct repository *r)
        enum replay_action action;
        const char *in_progress_error = NULL;
        const char *in_progress_advice = NULL;
-       unsigned int advise_skip = file_exists(git_path_revert_head(r)) ||
-                               file_exists(git_path_cherry_pick_head(r));
+       unsigned int advise_skip =
+               refs_ref_exists(get_main_ref_store(r), "REVERT_HEAD") ||
+               refs_ref_exists(get_main_ref_store(r), "CHERRY_PICK_HEAD");
 
        if (!sequencer_get_last_command(r, &action)) {
                switch (action) {
@@ -2771,8 +2869,8 @@ static int rollback_single_pick(struct repository *r)
 {
        struct object_id head_oid;
 
-       if (!file_exists(git_path_cherry_pick_head(r)) &&
-           !file_exists(git_path_revert_head(r)))
+       if (!refs_ref_exists(get_main_ref_store(r), "CHERRY_PICK_HEAD") &&
+           !refs_ref_exists(get_main_ref_store(r), "REVERT_HEAD"))
                return error(_("no cherry-pick or revert in progress"));
        if (read_ref_full("HEAD", 0, &head_oid, NULL))
                return error(_("cannot resolve HEAD"));
@@ -2866,7 +2964,7 @@ int sequencer_skip(struct repository *r, struct replay_opts *opts)
         */
        switch (opts->action) {
        case REPLAY_REVERT:
-               if (!file_exists(git_path_revert_head(r))) {
+               if (!refs_ref_exists(get_main_ref_store(r), "REVERT_HEAD")) {
                        if (action != REPLAY_REVERT)
                                return error(_("no revert in progress"));
                        if (!rollback_is_safe())
@@ -2874,7 +2972,8 @@ int sequencer_skip(struct repository *r, struct replay_opts *opts)
                }
                break;
        case REPLAY_PICK:
-               if (!file_exists(git_path_cherry_pick_head(r))) {
+               if (!refs_ref_exists(get_main_ref_store(r),
+                                    "CHERRY_PICK_HEAD")) {
                        if (action != REPLAY_PICK)
                                return error(_("no cherry-pick in progress"));
                        if (!rollback_is_safe())
@@ -3543,6 +3642,14 @@ static int do_merge(struct repository *r,
                        goto leave_merge;
                }
 
+               if (opts->committer_date_is_author_date)
+                       strvec_pushf(&cmd.env_array, "GIT_COMMITTER_DATE=%s",
+                                    opts->ignore_date ?
+                                    "" :
+                                    author_date_from_env_array(&cmd.env_array));
+               if (opts->ignore_date)
+                       strvec_push(&cmd.env_array, "GIT_AUTHOR_DATE=");
+
                cmd.git_cmd = 1;
                strvec_push(&cmd.args, "merge");
                strvec_push(&cmd.args, "-s");
@@ -3569,7 +3676,8 @@ static int do_merge(struct repository *r,
                                    oid_to_hex(&j->item->object.oid));
 
                strbuf_release(&ref_name);
-               unlink(git_path_cherry_pick_head(r));
+               refs_delete_ref(get_main_ref_store(r), "", "CHERRY_PICK_HEAD",
+                               NULL, 0);
                rollback_lock_file(&lock);
 
                rollback_lock_file(&lock);
@@ -3906,7 +4014,9 @@ static int pick_commits(struct repository *r,
        prev_reflog_action = xstrdup(getenv(GIT_REFLOG_ACTION));
        if (opts->allow_ff)
                assert(!(opts->signoff || opts->no_commit ||
-                               opts->record_origin || opts->edit));
+                        opts->record_origin || opts->edit ||
+                        opts->committer_date_is_author_date ||
+                        opts->ignore_date));
        if (read_and_refresh_cache(r, opts))
                return -1;
 
@@ -4201,8 +4311,8 @@ static int continue_single_pick(struct repository *r)
 {
        const char *argv[] = { "commit", NULL };
 
-       if (!file_exists(git_path_cherry_pick_head(r)) &&
-           !file_exists(git_path_revert_head(r)))
+       if (!refs_ref_exists(get_main_ref_store(r), "CHERRY_PICK_HEAD") &&
+           !refs_ref_exists(get_main_ref_store(r), "REVERT_HEAD"))
                return error(_("no cherry-pick or revert in progress"));
        return run_command_v_opt(argv, RUN_GIT_CMD);
 }
@@ -4318,9 +4428,10 @@ static int commit_staged_changes(struct repository *r,
        }
 
        if (is_clean) {
-               const char *cherry_pick_head = git_path_cherry_pick_head(r);
-
-               if (file_exists(cherry_pick_head) && unlink(cherry_pick_head))
+               if (refs_ref_exists(get_main_ref_store(r),
+                                   "CHERRY_PICK_HEAD") &&
+                   refs_delete_ref(get_main_ref_store(r), "",
+                                   "CHERRY_PICK_HEAD", NULL, 0))
                        return error(_("could not remove CHERRY_PICK_HEAD"));
                if (!final_fixup)
                        return 0;
@@ -4347,6 +4458,22 @@ static int commit_staged_changes(struct repository *r,
        return 0;
 }
 
+static int init_committer(struct replay_opts *opts)
+{
+       struct ident_split id;
+       const char *committer;
+
+       committer = git_committer_info(IDENT_STRICT);
+       if (split_ident_line(&id, committer, strlen(committer)) < 0)
+               return error(_("invalid committer '%s'"), committer);
+       opts->committer_name =
+               xmemdupz(id.name_begin, id.name_end - id.name_begin);
+       opts->committer_email =
+               xmemdupz(id.mail_begin, id.mail_end - id.mail_end);
+
+       return 0;
+}
+
 int sequencer_continue(struct repository *r, struct replay_opts *opts)
 {
        struct todo_list todo_list = TODO_LIST_INIT;
@@ -4358,6 +4485,9 @@ int sequencer_continue(struct repository *r, struct replay_opts *opts)
        if (read_populate_opts(opts))
                return -1;
        if (is_rebase_i(opts)) {
+               if (opts->committer_date_is_author_date && init_committer(opts))
+                       return -1;
+
                if ((res = read_populate_todo(r, &todo_list, opts)))
                        goto release_todo_list;
 
@@ -4379,8 +4509,9 @@ int sequencer_continue(struct repository *r, struct replay_opts *opts)
 
        if (!is_rebase_i(opts)) {
                /* Verify that the conflict has been resolved */
-               if (file_exists(git_path_cherry_pick_head(r)) ||
-                   file_exists(git_path_revert_head(r))) {
+               if (refs_ref_exists(get_main_ref_store(r),
+                                   "CHERRY_PICK_HEAD") ||
+                   refs_ref_exists(get_main_ref_store(r), "REVERT_HEAD")) {
                        res = continue_single_pick(r);
                        if (res)
                                goto release_todo_list;
@@ -5251,6 +5382,9 @@ int complete_action(struct repository *r, struct replay_opts *opts, unsigned fla
 
        res = -1;
 
+       if (opts->committer_date_is_author_date && init_committer(opts))
+               goto cleanup;
+
        if (checkout_onto(r, opts, onto_name, &oid, orig_head))
                goto cleanup;
 
@@ -5443,7 +5577,7 @@ int todo_list_rearrange_squash(struct todo_list *todo_list)
 
 int sequencer_determine_whence(struct repository *r, enum commit_whence *whence)
 {
-       if (file_exists(git_path_cherry_pick_head(r))) {
+       if (refs_ref_exists(get_main_ref_store(r), "CHERRY_PICK_HEAD")) {
                struct object_id cherry_pick_head, rebase_head;
 
                if (file_exists(git_path_seq_dir()))
index d31c41f018cb398e3da8e412f99925a8b30bde22..b2a501e445316fc5a6d5befb341be3cfc1c74077 100644 (file)
@@ -45,9 +45,13 @@ struct replay_opts {
        int verbose;
        int quiet;
        int reschedule_failed_exec;
+       int committer_date_is_author_date;
+       int ignore_date;
 
        int mainline;
 
+       char *committer_name;
+       char *committer_email;
        char *gpg_sign;
        enum commit_msg_cleanup_mode default_msg_cleanup;
        int explicit_cleanup;
index e175dfbc388ab50a55429bfff287541bb2a48530..c569e22aa3678bf694c080785f499d619b4d2e23 100644 (file)
@@ -777,10 +777,14 @@ static int gitmodules_fetch_config(const char *var, const char *value, void *cb)
 {
        struct fetch_config *config = cb;
        if (!strcmp(var, "submodule.fetchjobs")) {
-               *(config->max_children) = parse_submodule_fetchjobs(var, value);
+               if (config->max_children)
+                       *(config->max_children) =
+                               parse_submodule_fetchjobs(var, value);
                return 0;
        } else if (!strcmp(var, "fetch.recursesubmodules")) {
-               *(config->recurse_submodules) = parse_fetch_recurse_submodules_arg(var, value);
+               if (config->recurse_submodules)
+                       *(config->recurse_submodules) =
+                               parse_fetch_recurse_submodules_arg(var, value);
                return 0;
        }
 
index d0b70ca536143adc41d66a448e6b3f9243067076..6f8002fc9e2e33d650a5a3792b1faf48b4a969bf 100644 (file)
@@ -438,7 +438,7 @@ void handle_ignore_submodules_arg(struct diff_options *diffopt,
         */
 }
 
-static int prepare_submodule_summary(struct rev_info *rev, const char *path,
+static int prepare_submodule_diff_summary(struct rev_info *rev, const char *path,
                struct commit *left, struct commit *right,
                struct commit_list *merge_bases)
 {
@@ -459,7 +459,7 @@ static int prepare_submodule_summary(struct rev_info *rev, const char *path,
        return prepare_revision_walk(rev);
 }
 
-static void print_submodule_summary(struct repository *r, struct rev_info *rev, struct diff_options *o)
+static void print_submodule_diff_summary(struct repository *r, struct rev_info *rev, struct diff_options *o)
 {
        static const char format[] = "  %m %s";
        struct strbuf sb = STRBUF_INIT;
@@ -610,7 +610,7 @@ output_header:
        strbuf_release(&sb);
 }
 
-void show_submodule_summary(struct diff_options *o, const char *path,
+void show_submodule_diff_summary(struct diff_options *o, const char *path,
                struct object_id *one, struct object_id *two,
                unsigned dirty_submodule)
 {
@@ -632,12 +632,12 @@ void show_submodule_summary(struct diff_options *o, const char *path,
                goto out;
 
        /* Treat revision walker failure the same as missing commits */
-       if (prepare_submodule_summary(&rev, path, left, right, merge_bases)) {
+       if (prepare_submodule_diff_summary(&rev, path, left, right, merge_bases)) {
                diff_emit_submodule_error(o, "(revision walker failed)\n");
                goto out;
        }
 
-       print_submodule_summary(sub, &rev, o);
+       print_submodule_diff_summary(sub, &rev, o);
 
 out:
        if (merge_bases)
@@ -1726,14 +1726,6 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked)
 int submodule_uses_gitfile(const char *path)
 {
        struct child_process cp = CHILD_PROCESS_INIT;
-       const char *argv[] = {
-               "submodule",
-               "foreach",
-               "--quiet",
-               "--recursive",
-               "test -f .git",
-               NULL,
-       };
        struct strbuf buf = STRBUF_INIT;
        const char *git_dir;
 
@@ -1746,7 +1738,10 @@ int submodule_uses_gitfile(const char *path)
        strbuf_release(&buf);
 
        /* Now test that all nested submodules use a gitfile too */
-       cp.argv = argv;
+       strvec_pushl(&cp.args,
+                    "submodule", "foreach", "--quiet", "--recursive",
+                    "test -f .git", NULL);
+
        prepare_submodule_repo_env(&cp.env_array);
        cp.git_cmd = 1;
        cp.no_stdin = 1;
index 9ce85c03fed9950d366edb4bf550db22ffced06b..4ac6e31cf1f7dd672995a7ec642720cd3c5fc0b8 100644 (file)
@@ -69,7 +69,7 @@ int parse_submodule_update_strategy(const char *value,
                                    struct submodule_update_strategy *dst);
 const char *submodule_strategy_to_string(const struct submodule_update_strategy *s);
 void handle_ignore_submodules_arg(struct diff_options *, const char *);
-void show_submodule_summary(struct diff_options *o, const char *path,
+void show_submodule_diff_summary(struct diff_options *o, const char *path,
                            struct object_id *one, struct object_id *two,
                            unsigned dirty_submodule);
 void show_submodule_inline_diff(struct diff_options *o, const char *path,
index 48c7bb0bbb1dc8632d52db7886f8bc77c41cadf0..8c2ddcce95f7aada00d9a7dd8545fb4892562c42 100644 (file)
@@ -1,4 +1,2 @@
 /test-tool
 /test-fake-ssh
-/test-line-buffer
-/test-svn-fe
diff --git a/t/helper/test-line-buffer.c b/t/helper/test-line-buffer.c
deleted file mode 100644 (file)
index 078dd7e..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * test-line-buffer.c: code to exercise the svn importer's input helper
- */
-
-#include "git-compat-util.h"
-#include "strbuf.h"
-#include "vcs-svn/line_buffer.h"
-
-static uint32_t strtouint32(const char *s)
-{
-       char *end;
-       uintmax_t n = strtoumax(s, &end, 10);
-       if (*s == '\0' || *end != '\0')
-               die("invalid count: %s", s);
-       return (uint32_t) n;
-}
-
-static void handle_command(const char *command, const char *arg, struct line_buffer *buf)
-{
-       if (starts_with(command, "binary ")) {
-               struct strbuf sb = STRBUF_INIT;
-               strbuf_addch(&sb, '>');
-               buffer_read_binary(buf, &sb, strtouint32(arg));
-               fwrite(sb.buf, 1, sb.len, stdout);
-               strbuf_release(&sb);
-       } else if (starts_with(command, "copy ")) {
-               buffer_copy_bytes(buf, strtouint32(arg));
-       } else if (starts_with(command, "skip ")) {
-               buffer_skip_bytes(buf, strtouint32(arg));
-       } else {
-               die("unrecognized command: %s", command);
-       }
-}
-
-static void handle_line(const char *line, struct line_buffer *stdin_buf)
-{
-       const char *arg = strchr(line, ' ');
-       if (!arg)
-               die("no argument in line: %s", line);
-       handle_command(line, arg + 1, stdin_buf);
-}
-
-int cmd_main(int argc, const char **argv)
-{
-       struct line_buffer stdin_buf = LINE_BUFFER_INIT;
-       struct line_buffer file_buf = LINE_BUFFER_INIT;
-       struct line_buffer *input = &stdin_buf;
-       const char *filename;
-       char *s;
-
-       if (argc == 1)
-               filename = NULL;
-       else if (argc == 2)
-               filename = argv[1];
-       else
-               usage("test-line-buffer [file | &fd] < script");
-
-       if (buffer_init(&stdin_buf, NULL))
-               die_errno("open error");
-       if (filename) {
-               if (*filename == '&') {
-                       if (buffer_fdinit(&file_buf, strtouint32(filename + 1)))
-                               die_errno("error opening fd %s", filename + 1);
-               } else {
-                       if (buffer_init(&file_buf, filename))
-                               die_errno("error opening %s", filename);
-               }
-               input = &file_buf;
-       }
-
-       while ((s = buffer_read_line(&stdin_buf)))
-               handle_line(s, input);
-
-       if (filename && buffer_deinit(&file_buf))
-               die("error reading from %s", filename);
-       if (buffer_deinit(&stdin_buf))
-               die("input error");
-       if (ferror(stdout))
-               die("output error");
-       return 0;
-}
diff --git a/t/helper/test-svn-fe.c b/t/helper/test-svn-fe.c
deleted file mode 100644 (file)
index 7667c08..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * test-svn-fe: Code to exercise the svn import lib
- */
-
-#include "git-compat-util.h"
-#include "vcs-svn/svndump.h"
-#include "vcs-svn/svndiff.h"
-#include "vcs-svn/sliding_window.h"
-#include "vcs-svn/line_buffer.h"
-
-static const char test_svnfe_usage[] =
-       "test-svn-fe (<dumpfile> | [-d] <preimage> <delta> <len>)";
-
-static int apply_delta(int argc, const char **argv)
-{
-       struct line_buffer preimage = LINE_BUFFER_INIT;
-       struct line_buffer delta = LINE_BUFFER_INIT;
-       struct sliding_view preimage_view = SLIDING_VIEW_INIT(&preimage, -1);
-
-       if (argc != 5)
-               usage(test_svnfe_usage);
-
-       if (buffer_init(&preimage, argv[2]))
-               die_errno("cannot open preimage");
-       if (buffer_init(&delta, argv[3]))
-               die_errno("cannot open delta");
-       if (svndiff0_apply(&delta, (off_t) strtoumax(argv[4], NULL, 0),
-                                       &preimage_view, stdout))
-               return 1;
-       if (buffer_deinit(&preimage))
-               die_errno("cannot close preimage");
-       if (buffer_deinit(&delta))
-               die_errno("cannot close delta");
-       strbuf_release(&preimage_view.buf);
-       return 0;
-}
-
-int cmd_main(int argc, const char **argv)
-{
-       if (argc == 2) {
-               if (svndump_init(argv[1]))
-                       return 1;
-               svndump_read(NULL, "refs/heads/master", "refs/notes/svn/revs");
-               svndump_deinit();
-               svndump_reset();
-               return 0;
-       }
-
-       if (argc >= 2 && !strcmp(argv[1], "-d"))
-               return apply_delta(argc, argv);
-       usage(test_svnfe_usage);
-}
index c7b70e2d28ba3f8b24a3c4dfe4bb436b1f4acfa5..bd649afa978393373c209b507f3713c8f716986c 100644 (file)
@@ -84,6 +84,15 @@ You can set the following variables (also in your config.mak):
        probably be about linux.git size for optimal results.
        Both default to the git.git you are running from.
 
+    GIT_PERF_EXTRA
+       Boolean to enable additional tests. Most test scripts are
+       written to detect regressions between two versions of Git, and
+       the output will compare timings for individual tests between
+       those versions. Some scripts have additional tests which are not
+       run by default, that show patterns within a single version of
+       Git (e.g., performance of index-pack as the number of threads
+       changes). These can be enabled with GIT_PERF_EXTRA.
+
 You can also pass the options taken by ordinary git tests; the most
 useful one is:
 
index d275a81248b04adaab5e37ea20504a82d572e649..ce5ac3ed85e10efc2b4dd784e5d8949d8f269a75 100755 (executable)
@@ -7,11 +7,13 @@ test_description="Tests performance of update-ref"
 test_perf_fresh_repo
 
 test_expect_success "setup" '
+       git init --bare target-repo.git &&
        test_commit PRE &&
        test_commit POST &&
        printf "create refs/heads/%d PRE\n" $(test_seq 1000) >create &&
        printf "update refs/heads/%d POST PRE\n" $(test_seq 1000) >update &&
-       printf "delete refs/heads/%d POST\n" $(test_seq 1000) >delete
+       printf "delete refs/heads/%d POST\n" $(test_seq 1000) >delete &&
+       git update-ref --stdin <create
 '
 
 test_perf "update-ref" '
@@ -24,9 +26,14 @@ test_perf "update-ref" '
 '
 
 test_perf "update-ref --stdin" '
-       git update-ref --stdin <create &&
        git update-ref --stdin <update &&
-       git update-ref --stdin <delete
+       git update-ref --stdin <delete &&
+       git update-ref --stdin <create
+'
+
+test_perf "nonatomic push" '
+       git push ./target-repo.git $(test_seq 1000) &&
+       git push --delete ./target-repo.git $(test_seq 1000)
 '
 
 test_done
index a9b3e112d98223134d791727ffcde01e9123b117..228593d9ad6b3a5c9a0b45eb5814a3a8746d42bc 100755 (executable)
@@ -13,35 +13,36 @@ test_expect_success 'repack' '
        export PACK
 '
 
-test_perf 'index-pack 0 threads' '
-       rm -rf repo.git &&
-       git init --bare repo.git &&
-       GIT_DIR=repo.git git index-pack --threads=1 --stdin < $PACK
-'
-
-test_perf 'index-pack 1 thread ' '
-       rm -rf repo.git &&
-       git init --bare repo.git &&
-       GIT_DIR=repo.git GIT_FORCE_THREADS=1 git index-pack --threads=1 --stdin < $PACK
+# Rather than counting up and doubling each time, count down from the endpoint,
+# halving each time. That ensures that our final test uses as many threads as
+# CPUs, even if it isn't a power of 2.
+test_expect_success 'set up thread-counting tests' '
+       t=$(test-tool online-cpus) &&
+       threads= &&
+       while test $t -gt 0
+       do
+               threads="$t $threads"
+               t=$((t / 2))
+       done
 '
 
-test_perf 'index-pack 2 threads' '
+test_perf PERF_EXTRA 'index-pack 0 threads' '
        rm -rf repo.git &&
        git init --bare repo.git &&
-       GIT_DIR=repo.git git index-pack --threads=2 --stdin < $PACK
-'
-
-test_perf 'index-pack 4 threads' '
-       rm -rf repo.git &&
-       git init --bare repo.git &&
-       GIT_DIR=repo.git git index-pack --threads=4 --stdin < $PACK
+       GIT_DIR=repo.git git index-pack --threads=1 --stdin < $PACK
 '
 
-test_perf 'index-pack 8 threads' '
-       rm -rf repo.git &&
-       git init --bare repo.git &&
-       GIT_DIR=repo.git git index-pack --threads=8 --stdin < $PACK
-'
+for t in $threads
+do
+       THREADS=$t
+       export THREADS
+       test_perf PERF_EXTRA "index-pack $t threads" '
+               rm -rf repo.git &&
+               git init --bare repo.git &&
+               GIT_DIR=repo.git GIT_FORCE_THREADS=1 \
+               git index-pack --threads=$THREADS --stdin <$PACK
+       '
+done
 
 test_perf 'index-pack default number of threads' '
        rm -rf repo.git &&
index 13e389367a4e091c59d52b1e2567f3ca6cb121fb..821581a88548a38ec9c0542f50ef54bbc8815b4b 100644 (file)
@@ -245,3 +245,5 @@ test_at_end_hook_ () {
 test_export () {
        export "$@"
 }
+
+test_lazy_prereq PERF_EXTRA 'test_bool_env GIT_PERF_EXTRA false'
index 50222a10c5b1c68d5509c7e4952bdde79bc1a86c..2f7c3dcd0f85d41409a0a40520d2af821b2c147d 100755 (executable)
@@ -329,6 +329,15 @@ test_expect_success 'implicit bare & --separate-git-dir incompatible' '
        test_i18ngrep "incompatible" err
 '
 
+test_expect_success 'bare & --separate-git-dir incompatible within worktree' '
+       test_when_finished "rm -rf bare.git linkwt seprepo" &&
+       test_commit gumby &&
+       git clone --bare . bare.git &&
+       git -C bare.git worktree add --detach ../linkwt &&
+       test_must_fail git -C linkwt init --separate-git-dir seprepo 2>err &&
+       test_i18ngrep "incompatible" err
+'
+
 test_lazy_prereq GETCWD_IGNORES_PERMS '
        base=GETCWD_TEST_BASE_DIR &&
        mkdir -p $base/dir &&
@@ -405,6 +414,25 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' '
        test_path_is_dir realgitdir/refs
 '
 
+sep_git_dir_worktree ()  {
+       test_when_finished "rm -rf mainwt linkwt seprepo" &&
+       git init mainwt &&
+       test_commit -C mainwt gumby &&
+       git -C mainwt worktree add --detach ../linkwt &&
+       git -C "$1" init --separate-git-dir ../seprepo &&
+       git -C mainwt rev-parse --git-common-dir >expect &&
+       git -C linkwt rev-parse --git-common-dir >actual &&
+       test_cmp expect actual
+}
+
+test_expect_success 're-init to move gitdir with linked worktrees' '
+       sep_git_dir_worktree mainwt
+'
+
+test_expect_success 're-init to move gitdir within linked worktree' '
+       sep_git_dir_worktree linkwt
+'
+
 test_expect_success MINGW '.git hidden' '
        rm -rf newdir &&
        (
diff --git a/t/t0081-line-buffer.sh b/t/t0081-line-buffer.sh
deleted file mode 100755 (executable)
index ce92e6a..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-#!/bin/sh
-
-test_description="Test the svn importer's input handling routines.
-
-These tests provide some simple checks that the line_buffer API
-behaves as advertised.
-
-While at it, check that input of newlines and null bytes are handled
-correctly.
-"
-. ./test-lib.sh
-
-test_expect_success 'hello world' '
-       echo ">HELLO" >expect &&
-       test-line-buffer <<-\EOF >actual &&
-       binary 6
-       HELLO
-       EOF
-       test_cmp expect actual
-'
-
-test_expect_success '0-length read, send along greeting' '
-       echo ">HELLO" >expect &&
-       test-line-buffer <<-\EOF >actual &&
-       binary 0
-       copy 6
-       HELLO
-       EOF
-       test_cmp expect actual
-'
-
-test_expect_success !MINGW 'read from file descriptor' '
-       rm -f input &&
-       echo hello >expect &&
-       echo hello >input &&
-       echo copy 6 |
-       test-line-buffer "&4" 4<input >actual &&
-       test_cmp expect actual
-'
-
-test_expect_success 'skip, copy null byte' '
-       echo Q | q_to_nul >expect &&
-       q_to_nul <<-\EOF | test-line-buffer >actual &&
-       skip 2
-       Q
-       copy 2
-       Q
-       EOF
-       test_cmp expect actual
-'
-
-test_expect_success 'read null byte' '
-       echo ">QhelloQ" | q_to_nul >expect &&
-       q_to_nul <<-\EOF | test-line-buffer >actual &&
-       binary 8
-       QhelloQ
-       EOF
-       test_cmp expect actual
-'
-
-test_expect_success 'long reads are truncated' '
-       echo ">foo" >expect &&
-       test-line-buffer <<-\EOF >actual &&
-       binary 5
-       foo
-       EOF
-       test_cmp expect actual
-'
-
-test_expect_success 'long copies are truncated' '
-       printf "%s\n" ">" foo >expect &&
-       test-line-buffer <<-\EOF >actual &&
-       binary 1
-
-       copy 5
-       foo
-       EOF
-       test_cmp expect actual
-'
-
-test_expect_success 'long binary reads are truncated' '
-       echo ">foo" >expect &&
-       test-line-buffer <<-\EOF >actual &&
-       binary 5
-       foo
-       EOF
-       test_cmp expect actual
-'
-
-test_done
index a5ebdf9ff3cd79091de98c8aca7b27bfcda94c2c..584a039b851dbbf727d35d469e7d05895f9ec4e8 100755 (executable)
@@ -183,7 +183,7 @@ test_expect_success 'missing CLI object, but promised, passes fsck' '
 '
 
 test_expect_success 'fetching of missing objects' '
-       rm -rf repo &&
+       rm -rf repo err &&
        test_create_repo server &&
        test_commit -C server foo &&
        git -C server repack -a -d --write-bitmap-index &&
@@ -194,7 +194,10 @@ test_expect_success 'fetching of missing objects' '
 
        git -C repo config core.repositoryformatversion 1 &&
        git -C repo config extensions.partialclone "origin" &&
-       git -C repo cat-file -p "$HASH" &&
+       git -C repo cat-file -p "$HASH" 2>err &&
+
+       # Ensure that no spurious FETCH_HEAD messages are written
+       ! grep FETCH_HEAD err &&
 
        # Ensure that the .promisor file is written, and check that its
        # associated packfile contains the object
@@ -214,7 +217,7 @@ test_expect_success 'fetching of missing objects works with ref-in-want enabled'
        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
+       grep "fetch< fetch=.*ref-in-want" trace
 '
 
 test_expect_success 'fetching of missing objects from another promisor remote' '
index 76330cb5ab79ab0ddfd97e0c06a8f4fb3a74d6c6..fa9e0987063bd409592f45b5f71f67478a2f9f25 100755 (executable)
@@ -44,4 +44,16 @@ test_expect_success '--no-overlay --theirs with D/F conflict deletes file' '
        test_path_is_missing file1
 '
 
+test_expect_success 'wildcard pathspec matches file in subdirectory' '
+       git reset --hard &&
+       mkdir subdir &&
+       test_commit file3-1 subdir/file3 &&
+       test_commit file3-2 subdir/file3 &&
+
+       git checkout --no-overlay file3-1 "*file3" &&
+       echo file3-1 >expect &&
+       test_path_is_file subdir/file3 &&
+       test_cmp expect subdir/file3
+'
+
 test_done
index 0d47946e8a9b06f044542e373f3de477e53e3261..b48345bf95f4a34df369d385e74e49d94be96e5f 100755 (executable)
@@ -9,18 +9,21 @@ test_tick
 test_expect_success setup '
        test_commit file0 &&
 
+       mkdir dir1 &&
+       echo 1 >dir1/file &&
        echo 1 >fileA.t &&
        echo 1 >fileB.t &&
        echo 1 >fileC.t &&
        echo 1 >fileD.t &&
-       git add fileA.t fileB.t fileC.t fileD.t &&
+       git add dir1 fileA.t fileB.t fileC.t fileD.t &&
        git commit -m "files 1" &&
 
+       echo 2 >dir1/file &&
        echo 2 >fileA.t &&
        echo 2 >fileB.t &&
        echo 2 >fileC.t &&
        echo 2 >fileD.t &&
-       git add fileA.t fileB.t fileC.t fileD.t &&
+       git add dir1 fileA.t fileB.t fileC.t fileD.t &&
        git commit -m "files 2" &&
 
        git tag checkpoint
@@ -31,7 +34,7 @@ restore_checkpoint () {
 }
 
 verify_expect () {
-       git status --porcelain --untracked-files=no -- fileA.t fileB.t fileC.t fileD.t >actual &&
+       git status --porcelain --untracked-files=no -- dir1 fileA.t fileB.t fileC.t fileD.t >actual &&
        test_cmp expect actual
 }
 
@@ -161,4 +164,14 @@ test_expect_success 'error conditions' '
        test_i18ngrep -e "you must specify path(s) to restore" err
 '
 
+test_expect_success 'wildcard pathspec matches file in subdirectory' '
+       restore_checkpoint &&
+
+       echo "*file" | git restore --pathspec-from-file=- --source=HEAD^1 &&
+       cat >expect <<-\EOF &&
+        M dir1/file
+       EOF
+       verify_expect
+'
+
 test_done
diff --git a/t/t2406-worktree-repair.sh b/t/t2406-worktree-repair.sh
new file mode 100755 (executable)
index 0000000..1fe468b
--- /dev/null
@@ -0,0 +1,179 @@
+#!/bin/sh
+
+test_description='test git worktree repair'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+       test_commit init
+'
+
+test_expect_success 'skip missing worktree' '
+       test_when_finished "git worktree prune" &&
+       git worktree add --detach missing &&
+       rm -rf missing &&
+       git worktree repair >out 2>err &&
+       test_must_be_empty out &&
+       test_must_be_empty err
+'
+
+test_expect_success 'worktree path not directory' '
+       test_when_finished "git worktree prune" &&
+       git worktree add --detach notdir &&
+       rm -rf notdir &&
+       >notdir &&
+       test_must_fail git worktree repair >out 2>err &&
+       test_must_be_empty out &&
+       test_i18ngrep "not a directory" err
+'
+
+test_expect_success "don't clobber .git repo" '
+       test_when_finished "rm -rf repo && git worktree prune" &&
+       git worktree add --detach repo &&
+       rm -rf repo &&
+       test_create_repo repo &&
+       test_must_fail git worktree repair >out 2>err &&
+       test_must_be_empty out &&
+       test_i18ngrep ".git is not a file" err
+'
+
+test_corrupt_gitfile () {
+       butcher=$1 &&
+       problem=$2 &&
+       repairdir=${3:-.} &&
+       test_when_finished 'rm -rf corrupt && git worktree prune' &&
+       git worktree add --detach corrupt &&
+       git -C corrupt rev-parse --absolute-git-dir >expect &&
+       eval "$butcher" &&
+       git -C "$repairdir" worktree repair >out 2>err &&
+       test_i18ngrep "$problem" out &&
+       test_must_be_empty err &&
+       git -C corrupt rev-parse --absolute-git-dir >actual &&
+       test_cmp expect actual
+}
+
+test_expect_success 'repair missing .git file' '
+       test_corrupt_gitfile "rm -f corrupt/.git" ".git file broken"
+'
+
+test_expect_success 'repair bogus .git file' '
+       test_corrupt_gitfile "echo \"gitdir: /nowhere\" >corrupt/.git" \
+               ".git file broken"
+'
+
+test_expect_success 'repair incorrect .git file' '
+       test_when_finished "rm -rf other && git worktree prune" &&
+       test_create_repo other &&
+       other=$(git -C other rev-parse --absolute-git-dir) &&
+       test_corrupt_gitfile "echo \"gitdir: $other\" >corrupt/.git" \
+               ".git file incorrect"
+'
+
+test_expect_success 'repair .git file from main/.git' '
+       test_corrupt_gitfile "rm -f corrupt/.git" ".git file broken" .git
+'
+
+test_expect_success 'repair .git file from linked worktree' '
+       test_when_finished "rm -rf other && git worktree prune" &&
+       git worktree add --detach other &&
+       test_corrupt_gitfile "rm -f corrupt/.git" ".git file broken" other
+'
+
+test_expect_success 'repair .git file from bare.git' '
+       test_when_finished "rm -rf bare.git corrupt && git worktree prune" &&
+       git clone --bare . bare.git &&
+       git -C bare.git worktree add --detach ../corrupt &&
+       git -C corrupt rev-parse --absolute-git-dir >expect &&
+       rm -f corrupt/.git &&
+       git -C bare.git worktree repair &&
+       git -C corrupt rev-parse --absolute-git-dir >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'invalid worktree path' '
+       test_must_fail git worktree repair /notvalid >out 2>err &&
+       test_must_be_empty out &&
+       test_i18ngrep "not a valid path" err
+'
+
+test_expect_success 'repo not found; .git not file' '
+       test_when_finished "rm -rf not-a-worktree" &&
+       test_create_repo not-a-worktree &&
+       test_must_fail git worktree repair not-a-worktree >out 2>err &&
+       test_must_be_empty out &&
+       test_i18ngrep ".git is not a file" err
+'
+
+test_expect_success 'repo not found; .git file broken' '
+       test_when_finished "rm -rf orig moved && git worktree prune" &&
+       git worktree add --detach orig &&
+       echo /invalid >orig/.git &&
+       mv orig moved &&
+       test_must_fail git worktree repair moved >out 2>err &&
+       test_must_be_empty out &&
+       test_i18ngrep ".git file broken" err
+'
+
+test_expect_success 'repair broken gitdir' '
+       test_when_finished "rm -rf orig moved && git worktree prune" &&
+       git worktree add --detach orig &&
+       sed s,orig/\.git$,moved/.git, .git/worktrees/orig/gitdir >expect &&
+       rm .git/worktrees/orig/gitdir &&
+       mv orig moved &&
+       git worktree repair moved >out 2>err &&
+       test_cmp expect .git/worktrees/orig/gitdir &&
+       test_i18ngrep "gitdir unreadable" out &&
+       test_must_be_empty err
+'
+
+test_expect_success 'repair incorrect gitdir' '
+       test_when_finished "rm -rf orig moved && git worktree prune" &&
+       git worktree add --detach orig &&
+       sed s,orig/\.git$,moved/.git, .git/worktrees/orig/gitdir >expect &&
+       mv orig moved &&
+       git worktree repair moved >out 2>err &&
+       test_cmp expect .git/worktrees/orig/gitdir &&
+       test_i18ngrep "gitdir incorrect" out &&
+       test_must_be_empty err
+'
+
+test_expect_success 'repair gitdir (implicit) from linked worktree' '
+       test_when_finished "rm -rf orig moved && git worktree prune" &&
+       git worktree add --detach orig &&
+       sed s,orig/\.git$,moved/.git, .git/worktrees/orig/gitdir >expect &&
+       mv orig moved &&
+       git -C moved worktree repair >out 2>err &&
+       test_cmp expect .git/worktrees/orig/gitdir &&
+       test_i18ngrep "gitdir incorrect" out &&
+       test_must_be_empty err
+'
+
+test_expect_success 'unable to repair gitdir (implicit) from main worktree' '
+       test_when_finished "rm -rf orig moved && git worktree prune" &&
+       git worktree add --detach orig &&
+       cat .git/worktrees/orig/gitdir >expect &&
+       mv orig moved &&
+       git worktree repair >out 2>err &&
+       test_cmp expect .git/worktrees/orig/gitdir &&
+       test_must_be_empty out &&
+       test_must_be_empty err
+'
+
+test_expect_success 'repair multiple gitdir files' '
+       test_when_finished "rm -rf orig1 orig2 moved1 moved2 &&
+               git worktree prune" &&
+       git worktree add --detach orig1 &&
+       git worktree add --detach orig2 &&
+       sed s,orig1/\.git$,moved1/.git, .git/worktrees/orig1/gitdir >expect1 &&
+       sed s,orig2/\.git$,moved2/.git, .git/worktrees/orig2/gitdir >expect2 &&
+       mv orig1 moved1 &&
+       mv orig2 moved2 &&
+       git worktree repair moved1 moved2 >out 2>err &&
+       test_cmp expect1 .git/worktrees/orig1/gitdir &&
+       test_cmp expect2 .git/worktrees/orig2/gitdir &&
+       test_i18ngrep "gitdir incorrect:.*orig1/gitdir$" out &&
+       test_i18ngrep "gitdir incorrect:.*orig2/gitdir$" out &&
+       test_must_be_empty err
+'
+
+test_done
index 50e7960702da4fa0306818f305f5d735f2292f53..c8234062c6c8322d92f5054cf76b164446227cfc 100755 (executable)
@@ -61,8 +61,6 @@ test_rebase_am_only () {
 }
 
 test_rebase_am_only --whitespace=fix
-test_rebase_am_only --ignore-whitespace
-test_rebase_am_only --committer-date-is-author-date
 test_rebase_am_only -C4
 
 test_expect_success REBASE_P '--preserve-merges incompatible with --signoff' '
diff --git a/t/t3436-rebase-more-options.sh b/t/t3436-rebase-more-options.sh
new file mode 100755 (executable)
index 0000000..996e827
--- /dev/null
@@ -0,0 +1,180 @@
+#!/bin/sh
+#
+# Copyright (c) 2019 Rohit Ashiwal
+#
+
+test_description='tests to ensure compatibility between am and interactive backends'
+
+. ./test-lib.sh
+
+. "$TEST_DIRECTORY"/lib-rebase.sh
+
+GIT_AUTHOR_DATE="1999-04-02T08:03:20+05:30"
+export GIT_AUTHOR_DATE
+
+# This is a special case in which both am and interactive backends
+# provide the same output. It was done intentionally because
+# both the backends fall short of optimal behaviour.
+test_expect_success 'setup' '
+       git checkout -b topic &&
+       test_write_lines "line 1" "     line 2" "line 3" >file &&
+       git add file &&
+       git commit -m "add file" &&
+
+       test_write_lines "line 1" "new line 2" "line 3" >file &&
+       git commit -am "update file" &&
+       git tag side &&
+       test_commit commit1 foo foo1 &&
+       test_commit commit2 foo foo2 &&
+       test_commit commit3 foo foo3 &&
+
+       git checkout --orphan master &&
+       rm foo &&
+       test_write_lines "line 1" "        line 2" "line 3" >file &&
+       git commit -am "add file" &&
+       git tag main &&
+
+       mkdir test-bin &&
+       write_script test-bin/git-merge-test <<-\EOF
+       exec git merge-recursive "$@"
+       EOF
+'
+
+test_expect_success '--ignore-whitespace works with apply backend' '
+       test_must_fail git rebase --apply main side &&
+       git rebase --abort &&
+       git rebase --apply --ignore-whitespace main side &&
+       git diff --exit-code side
+'
+
+test_expect_success '--ignore-whitespace works with merge backend' '
+       test_must_fail git rebase --merge main side &&
+       git rebase --abort &&
+       git rebase --merge --ignore-whitespace main side &&
+       git diff --exit-code side
+'
+
+test_expect_success '--ignore-whitespace is remembered when continuing' '
+       (
+               set_fake_editor &&
+               FAKE_LINES="break 1" git rebase -i --ignore-whitespace \
+                       main side &&
+               git rebase --continue
+       ) &&
+       git diff --exit-code side
+'
+
+test_ctime_is_atime () {
+       git log $1 --format=%ai >authortime &&
+       git log $1 --format=%ci >committertime &&
+       test_cmp authortime committertime
+}
+
+test_expect_success '--committer-date-is-author-date works with apply backend' '
+       GIT_AUTHOR_DATE="@1234 +0300" git commit --amend --reset-author &&
+       git rebase --apply --committer-date-is-author-date HEAD^ &&
+       test_ctime_is_atime -1
+'
+
+test_expect_success '--committer-date-is-author-date works with merge backend' '
+       GIT_AUTHOR_DATE="@1234 +0300" git commit --amend --reset-author &&
+       git rebase -m --committer-date-is-author-date HEAD^ &&
+       test_ctime_is_atime -1
+'
+
+test_expect_success '--committer-date-is-author-date works with rebase -r' '
+       git checkout side &&
+       GIT_AUTHOR_DATE="@1234 +0300" git merge --no-ff commit3 &&
+       git rebase -r --root --committer-date-is-author-date &&
+       test_ctime_is_atime
+'
+
+test_expect_success '--committer-date-is-author-date works when forking merge' '
+       git checkout side &&
+       GIT_AUTHOR_DATE="@1234 +0300" git merge --no-ff commit3 &&
+       PATH="./test-bin:$PATH" git rebase -r --root --strategy=test \
+                                       --committer-date-is-author-date &&
+       test_ctime_is_atime
+'
+
+test_expect_success '--committer-date-is-author-date works when committing conflict resolution' '
+       git checkout commit2 &&
+       GIT_AUTHOR_DATE="@1980 +0000" git commit --amend --only --reset-author &&
+       test_must_fail git rebase -m --committer-date-is-author-date \
+               --onto HEAD^^ HEAD^ &&
+       echo resolved > foo &&
+       git add foo &&
+       git rebase --continue &&
+       test_ctime_is_atime -1
+'
+
+# Checking for +0000 in the author date is sufficient since the
+# default timezone is UTC but the timezone used while committing is
+# +0530. The inverted logic in the grep is necessary to check all the
+# author dates in the file.
+test_atime_is_ignored () {
+       git log $1 --format=%ai >authortime &&
+       ! grep -v +0000 authortime
+}
+
+test_expect_success '--reset-author-date works with apply backend' '
+       git commit --amend --date="$GIT_AUTHOR_DATE" &&
+       git rebase --apply --reset-author-date HEAD^ &&
+       test_atime_is_ignored -1
+'
+
+test_expect_success '--reset-author-date works with merge backend' '
+       git commit --amend --date="$GIT_AUTHOR_DATE" &&
+       git rebase --reset-author-date -m HEAD^ &&
+       test_atime_is_ignored -1
+'
+
+test_expect_success '--reset-author-date works after conflict resolution' '
+       test_must_fail git rebase --reset-author-date -m \
+               --onto commit2^^ commit2^ commit2 &&
+       echo resolved >foo &&
+       git add foo &&
+       git rebase --continue &&
+       test_atime_is_ignored -1
+'
+
+test_expect_success '--reset-author-date works with rebase -r' '
+       git checkout side &&
+       git merge --no-ff commit3 &&
+       git rebase -r --root --reset-author-date &&
+       test_atime_is_ignored
+'
+
+test_expect_success '--reset-author-date with --committer-date-is-author-date works' '
+       test_must_fail git rebase -m --committer-date-is-author-date \
+               --reset-author-date --onto commit2^^ commit2^ commit3 &&
+       git checkout --theirs foo &&
+       git add foo &&
+       git rebase --continue &&
+       test_ctime_is_atime -2 &&
+       test_atime_is_ignored -2
+'
+
+test_expect_success '--reset-author-date --committer-date-is-author-date works when forking merge' '
+       GIT_SEQUENCE_EDITOR="echo \"merge -C $(git rev-parse HEAD) commit3\">" \
+               PATH="./test-bin:$PATH" git rebase -i --strategy=test \
+                               --reset-author-date \
+                               --committer-date-is-author-date side side &&
+       test_ctime_is_atime -1 &&
+       test_atime_is_ignored -1
+ '
+
+test_expect_success '--ignore-date is an alias for --reset-author-date' '
+       git commit --amend --date="$GIT_AUTHOR_DATE" &&
+       git rebase --apply --ignore-date HEAD^ &&
+       git commit --allow-empty -m empty --date="$GIT_AUTHOR_DATE" &&
+       git rebase -m --ignore-date HEAD^ &&
+       test_atime_is_ignored -2
+'
+
+# This must be the last test in this file
+test_expect_success '$EDITOR and friends are unchanged' '
+       test_editor_unchanged
+'
+
+test_done
index 5f97dd6d6565c45d6afe4262d82d6750d756ec3d..5c7b0122b4f194d327d488d4b5dd6b8ad28e7673 100755 (executable)
@@ -130,27 +130,45 @@ test_expect_success setup '
 EOF
 
 process_diffs () {
-       _x04="[0-9a-f][0-9a-f][0-9a-f][0-9a-f]" &&
-       _x07="$_x05[0-9a-f][0-9a-f]" &&
-       sed -e "s/$OID_REGEX/$ZERO_OID/g" \
-           -e "s/From $_x40 /From $ZERO_OID /" \
-           -e "s/from $_x40)/from $ZERO_OID)/" \
-           -e "s/commit $_x40\$/commit $ZERO_OID/" \
-           -e "s/commit $_x40 (/commit $ZERO_OID (/" \
-           -e "s/$_x40 $_x40 $_x40/$ZERO_OID $ZERO_OID $ZERO_OID/" \
-           -e "s/$_x40 $_x40 /$ZERO_OID $ZERO_OID /" \
-           -e "s/^$_x40 $_x40$/$ZERO_OID $ZERO_OID/" \
-           -e "s/^$_x40 /$ZERO_OID /" \
-           -e "s/^$_x40$/$ZERO_OID/" \
-           -e "s/$_x07\.\.$_x07/fffffff..fffffff/g" \
-           -e "s/$_x07,$_x07\.\.$_x07/fffffff,fffffff..fffffff/g" \
-           -e "s/$_x07 $_x07 $_x07/fffffff fffffff fffffff/g" \
-           -e "s/$_x07 $_x07 /fffffff fffffff /g" \
-           -e "s/Merge: $_x07 $_x07/Merge: fffffff fffffff/g" \
-           -e "s/$_x07\.\.\./fffffff.../g" \
-           -e "s/ $_x04\.\.\./ ffff.../g" \
-           -e "s/ $_x04/ ffff/g" \
-           "$1"
+       perl -e '
+               my $oid_length = length($ARGV[0]);
+               my $x40 = "[0-9a-f]{40}";
+               my $xab = "[0-9a-f]{4,16}";
+               my $orx = "[0-9a-f]" x $oid_length;
+
+               sub munge_oid {
+                       my ($oid) = @_;
+                       my $x;
+
+                       return "" unless length $oid;
+
+                       if ($oid =~ /^(100644|100755|120000)$/) {
+                               return $oid;
+                       }
+
+                       if ($oid =~ /^0*$/) {
+                               $x = "0";
+                       } else {
+                               $x = "f";
+                       }
+
+                       if (length($oid) == 40) {
+                               return $x x $oid_length;
+                       } else {
+                               return $x x length($oid);
+                       }
+               }
+
+               while (<STDIN>) {
+                       s/($orx)/munge_oid($1)/ge;
+                       s/From ($x40)( |\))/"From " . munge_oid($1) . $2/ge;
+                       s/commit ($x40)($| \(from )($x40?)/"commit " .  munge_oid($1) . $2 . munge_oid($3)/ge;
+                       s/\b($x40)( |\.\.|$)/munge_oid($1) . $2/ge;
+                       s/^($x40)($| )/munge_oid($1) . $2/e;
+                       s/($xab)(\.\.|,| |\.\.\.|$)/munge_oid($1) . $2/ge;
+                       print;
+               }
+       ' "$ZERO_OID" <"$1"
 }
 
 V=$(git version | sed -e 's/^git version //' -e 's/\./\\./g')
@@ -221,6 +239,9 @@ diff-tree --root -r --abbrev=4 initial
 :noellipses diff-tree --root -r --abbrev=4 initial
 diff-tree -p initial
 diff-tree --root -p initial
+diff-tree --root -p --abbrev=10 initial
+diff-tree --root -p --full-index initial
+diff-tree --root -p --full-index --abbrev=10 initial
 diff-tree --patch-with-stat initial
 diff-tree --root --patch-with-stat initial
 diff-tree --patch-with-raw initial
diff --git a/t/t4013/diff.diff-tree_--root_-p_--abbrev=10_initial b/t/t4013/diff.diff-tree_--root_-p_--abbrev=10_initial
new file mode 100644 (file)
index 0000000..7518a90
--- /dev/null
@@ -0,0 +1,29 @@
+$ git diff-tree --root -p --abbrev=10 initial
+444ac553ac7612cc88969031b02b3767fb8a353a
+diff --git a/dir/sub b/dir/sub
+new file mode 100644
+index 0000000000..35d242ba79
+--- /dev/null
++++ b/dir/sub
+@@ -0,0 +1,2 @@
++A
++B
+diff --git a/file0 b/file0
+new file mode 100644
+index 0000000000..01e79c32a8
+--- /dev/null
++++ b/file0
+@@ -0,0 +1,3 @@
++1
++2
++3
+diff --git a/file2 b/file2
+new file mode 100644
+index 0000000000..01e79c32a8
+--- /dev/null
++++ b/file2
+@@ -0,0 +1,3 @@
++1
++2
++3
+$
diff --git a/t/t4013/diff.diff-tree_--root_-p_--full-index_--abbrev=10_initial b/t/t4013/diff.diff-tree_--root_-p_--full-index_--abbrev=10_initial
new file mode 100644 (file)
index 0000000..69f913f
--- /dev/null
@@ -0,0 +1,29 @@
+$ git diff-tree --root -p --full-index --abbrev=10 initial
+444ac553ac7612cc88969031b02b3767fb8a353a
+diff --git a/dir/sub b/dir/sub
+new file mode 100644
+index 0000000000000000000000000000000000000000..35d242ba79ae89ac695e26b3d4c27a8e6f028f9e
+--- /dev/null
++++ b/dir/sub
+@@ -0,0 +1,2 @@
++A
++B
+diff --git a/file0 b/file0
+new file mode 100644
+index 0000000000000000000000000000000000000000..01e79c32a8c99c557f0757da7cb6d65b3414466d
+--- /dev/null
++++ b/file0
+@@ -0,0 +1,3 @@
++1
++2
++3
+diff --git a/file2 b/file2
+new file mode 100644
+index 0000000000000000000000000000000000000000..01e79c32a8c99c557f0757da7cb6d65b3414466d
+--- /dev/null
++++ b/file2
+@@ -0,0 +1,3 @@
++1
++2
++3
+$
diff --git a/t/t4013/diff.diff-tree_--root_-p_--full-index_initial b/t/t4013/diff.diff-tree_--root_-p_--full-index_initial
new file mode 100644 (file)
index 0000000..1b0b671
--- /dev/null
@@ -0,0 +1,29 @@
+$ git diff-tree --root -p --full-index initial
+444ac553ac7612cc88969031b02b3767fb8a353a
+diff --git a/dir/sub b/dir/sub
+new file mode 100644
+index 0000000000000000000000000000000000000000..35d242ba79ae89ac695e26b3d4c27a8e6f028f9e
+--- /dev/null
++++ b/dir/sub
+@@ -0,0 +1,2 @@
++A
++B
+diff --git a/file0 b/file0
+new file mode 100644
+index 0000000000000000000000000000000000000000..01e79c32a8c99c557f0757da7cb6d65b3414466d
+--- /dev/null
++++ b/file0
+@@ -0,0 +1,3 @@
++1
++2
++3
+diff --git a/file2 b/file2
+new file mode 100644
+index 0000000000000000000000000000000000000000..01e79c32a8c99c557f0757da7cb6d65b3414466d
+--- /dev/null
++++ b/file2
+@@ -0,0 +1,3 @@
++1
++2
++3
+$
index 88d3026894f87f4d86cb6f4178898b6879630e73..8bdaa0a693fa52adf2314d5777a195d035d6009c 100755 (executable)
@@ -789,7 +789,7 @@ test_expect_success 'checkdiff allows new blank lines' '
        git diff --check
 '
 
-test_expect_success 'whitespace-only changes not reported' '
+test_expect_success 'whitespace-only changes not reported (diff)' '
        git reset --hard &&
        echo >x "hello world" &&
        git add x &&
@@ -799,10 +799,44 @@ test_expect_success 'whitespace-only changes not reported' '
        test_must_be_empty actual
 '
 
-test_expect_success 'whitespace-only changes reported across renames' '
+test_expect_success 'whitespace-only changes not reported (diffstat)' '
+       # reuse state from previous test
+       git diff --stat -b >actual &&
+       test_must_be_empty actual
+'
+
+test_expect_success 'whitespace changes with modification reported (diffstat)' '
+       git reset --hard &&
+       echo >x "hello  world" &&
+       git update-index --chmod=+x x &&
+       git diff --stat --cached -b >actual &&
+       cat <<-EOF >expect &&
+        x | 0
+        1 file changed, 0 insertions(+), 0 deletions(-)
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success 'whitespace-only changes reported across renames (diffstat)' '
        git reset --hard &&
        for i in 1 2 3 4 5 6 7 8 9; do echo "$i$i$i$i$i$i"; done >x &&
        git add x &&
+       git commit -m "base" &&
+       sed -e "5s/^/ /" x >z &&
+       git rm x &&
+       git add z &&
+       git diff -w -M --cached --stat >actual &&
+       cat <<-EOF >expect &&
+        x => z | 0
+        1 file changed, 0 insertions(+), 0 deletions(-)
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success 'whitespace-only changes reported across renames' '
+       git reset --hard HEAD~1 &&
+       for i in 1 2 3 4 5 6 7 8 9; do echo "$i$i$i$i$i$i"; done >x &&
+       git add x &&
        hash_x=$(git hash-object x) &&
        before=$(git rev-parse --short "$hash_x") &&
        git commit -m "base" &&
index ef8e0e9cb01f1aae472c7606e33a5ef7d24a08f4..804f2a82e8315d4f5936894adf7846769d2e201d 100755 (executable)
@@ -20,7 +20,7 @@ test_expect_success 'git show batches blobs' '
        # Ensure that there is exactly 1 negotiation by checking that there is
        # only 1 "done" line sent. ("done" marks the end of negotiation.)
        GIT_TRACE_PACKET="$(pwd)/trace" git -C client show HEAD &&
-       grep "git> done" trace >done_lines &&
+       grep "fetch> done" trace >done_lines &&
        test_line_count = 1 done_lines
 '
 
@@ -44,7 +44,7 @@ test_expect_success 'diff batches blobs' '
        # Ensure that there is exactly 1 negotiation by checking that there is
        # only 1 "done" line sent. ("done" marks the end of negotiation.)
        GIT_TRACE_PACKET="$(pwd)/trace" git -C client diff HEAD^ HEAD &&
-       grep "git> done" trace >done_lines &&
+       grep "fetch> done" trace >done_lines &&
        test_line_count = 1 done_lines
 '
 
@@ -127,7 +127,7 @@ test_expect_success 'diff with rename detection batches blobs' '
        # only 1 "done" line sent. ("done" marks the end of negotiation.)
        GIT_TRACE_PACKET="$(pwd)/trace" git -C client diff --raw -M HEAD^ HEAD >out &&
        grep ":100644 100644.*R[0-9][0-9][0-9].*b.*c" out &&
-       grep "git> done" trace >done_lines &&
+       grep "fetch> done" trace >done_lines &&
        test_line_count = 1 done_lines
 '
 
@@ -175,7 +175,7 @@ test_expect_success 'diff --break-rewrites fetches only if necessary, and batche
        # by checking that there is only 1 "done" line sent. ("done" marks the
        # end of negotiation.)
        GIT_TRACE_PACKET="$(pwd)/trace" git -C client diff --break-rewrites --raw -M HEAD^ HEAD &&
-       grep "git> done" trace >done_lines &&
+       grep "fetch> done" trace >done_lines &&
        test_line_count = 1 done_lines
 '
 
index a0930599aaa5b18915792c68c3f84b4b184bb27c..56d34ed465bce63b7a2676f23b89c90cd51b8925 100755 (executable)
@@ -1850,6 +1850,16 @@ test_expect_success 'log does not default to HEAD when rev input is given' '
        test_must_be_empty actual
 '
 
+test_expect_success 'do not default to HEAD with ignored object on cmdline' '
+       git log --ignore-missing $ZERO_OID >actual &&
+       test_must_be_empty actual
+'
+
+test_expect_success 'do not default to HEAD with ignored object on stdin' '
+       echo $ZERO_OID | git log --ignore-missing --stdin >actual &&
+       test_must_be_empty actual
+'
+
 test_expect_success 'set up --source tests' '
        git checkout --orphan source-a &&
        test_commit one &&
index 3d6a93343adc6b14d096f6b42e5b9548bf1f0e55..392201cabdfece945104c6cc8bde3e87f3edd99f 100755 (executable)
@@ -528,7 +528,7 @@ test_expect_success 'prefetch objects' '
        TWO=$(git -C server rev-parse three_branch^) &&
        git -C client fetch --filter=blob:none origin "$TWO" &&
        GIT_TRACE_PACKET=$(pwd)/trace git -C client push origin "$TWO":refs/heads/two_branch &&
-       grep "git> done" trace >donelines &&
+       grep "fetch> done" trace >donelines &&
        test_line_count = 1 donelines
 '
 
index 43b1b5b2af6e978f5dc84543f5be1707941a2d38..f340b376bca55f0aa7af191f91527f8da076bf19 100755 (executable)
@@ -382,12 +382,52 @@ test_expect_success 'repack with the --no-progress option' '
        test_line_count = 0 err
 '
 
-test_expect_success 'repack removes multi-pack-index' '
+test_expect_success 'repack removes multi-pack-index when deleting packs' '
        test_path_is_file $objdir/pack/multi-pack-index &&
-       GIT_TEST_MULTI_PACK_INDEX=0 git repack -adf &&
+       # Set GIT_TEST_MULTI_PACK_INDEX to 0 to avoid writing a new
+       # multi-pack-index after repacking, but set "core.multiPackIndex" to
+       # true so that "git repack" can read the existing MIDX.
+       GIT_TEST_MULTI_PACK_INDEX=0 git -c core.multiPackIndex repack -adf &&
        test_path_is_missing $objdir/pack/multi-pack-index
 '
 
+test_expect_success 'repack preserves multi-pack-index when creating packs' '
+       git init preserve &&
+       test_when_finished "rm -fr preserve" &&
+       (
+               cd preserve &&
+               packdir=.git/objects/pack &&
+               midx=$packdir/multi-pack-index &&
+
+               test_commit 1 &&
+               pack1=$(git pack-objects --all $packdir/pack) &&
+               touch $packdir/pack-$pack1.keep &&
+               test_commit 2 &&
+               pack2=$(git pack-objects --revs $packdir/pack) &&
+               touch $packdir/pack-$pack2.keep &&
+
+               git multi-pack-index write &&
+               cp $midx $midx.bak &&
+
+               cat >pack-input <<-EOF &&
+               HEAD
+               ^HEAD~1
+               EOF
+               test_commit 3 &&
+               pack3=$(git pack-objects --revs $packdir/pack <pack-input) &&
+               test_commit 4 &&
+               pack4=$(git pack-objects --revs $packdir/pack <pack-input) &&
+
+               GIT_TEST_MULTI_PACK_INDEX=0 git -c core.multiPackIndex repack -ad &&
+               ls -la $packdir &&
+               test_path_is_file $packdir/pack-$pack1.pack &&
+               test_path_is_file $packdir/pack-$pack2.pack &&
+               test_path_is_missing $packdir/pack-$pack3.pack &&
+               test_path_is_missing $packdir/pack-$pack4.pack &&
+               test_cmp_bin $midx.bak $midx
+       )
+'
+
 compare_results_with_midx "after repack"
 
 test_expect_success 'multi-pack-index and pack-bitmap' '
index 2a1abe91f0fd34b7929aa636ab43542c6e45ea54..759aec9305e46abb7f5ab3da5a9b99a7502a7d3b 100755 (executable)
@@ -543,16 +543,18 @@ test_expect_success 'fetch into the current branch with --update-head-ok' '
 
 '
 
-test_expect_success 'fetch --dry-run does not touch FETCH_HEAD' '
-       rm -f .git/FETCH_HEAD &&
-       git fetch --dry-run . &&
-       ! test -f .git/FETCH_HEAD
+test_expect_success 'fetch --dry-run does not touch FETCH_HEAD, but still prints what would be written' '
+       rm -f .git/FETCH_HEAD err &&
+       git fetch --dry-run . 2>err &&
+       ! test -f .git/FETCH_HEAD &&
+       grep FETCH_HEAD err
 '
 
-test_expect_success '--no-write-fetch-head does not touch FETCH_HEAD' '
-       rm -f .git/FETCH_HEAD &&
-       git fetch --no-write-fetch-head . &&
-       ! test -f .git/FETCH_HEAD
+test_expect_success '--no-write-fetch-head does not touch FETCH_HEAD, and does not print what would be written' '
+       rm -f .git/FETCH_HEAD err &&
+       git fetch --no-write-fetch-head . 2>err &&
+       ! test -f .git/FETCH_HEAD &&
+       ! grep FETCH_HEAD err
 '
 
 test_expect_success '--write-fetch-head gets defeated by --dry-run' '
diff --git a/t/t5554-noop-fetch-negotiator.sh b/t/t5554-noop-fetch-negotiator.sh
new file mode 100755 (executable)
index 0000000..2ac7b58
--- /dev/null
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+test_description='test noop fetch negotiator'
+. ./test-lib.sh
+
+test_expect_success 'noop negotiator does not emit any "have"' '
+       rm -f trace &&
+
+       test_create_repo server &&
+       test_commit -C server to_fetch &&
+
+       test_create_repo client &&
+       test_commit -C client we_have &&
+
+       test_config -C client fetch.negotiationalgorithm noop &&
+       GIT_TRACE_PACKET="$(pwd)/trace" git -C client fetch "$(pwd)/server" &&
+
+       ! grep "fetch> have" trace &&
+       grep "fetch> done" trace
+'
+
+test_done
index eb9a093e25fadce8f8e6964e1e4b208256419cad..15fb64c18d860e582542c0ae225897b9b22e89d0 100755 (executable)
@@ -704,7 +704,7 @@ test_expect_success 'batch missing blob request during checkout' '
        # Ensure that there is only one negotiation by checking that there is
        # only "done" line sent. ("done" marks the end of negotiation.)
        GIT_TRACE_PACKET="$(pwd)/trace" git -C client checkout HEAD^ &&
-       grep "git> done" trace >done_lines &&
+       grep "fetch> done" trace >done_lines &&
        test_line_count = 1 done_lines
 '
 
index 8827c2ed18394f3f7f5ae4bd35c3514a36eacc9d..f4d49d833577c33f741adfb8e5ded0cdae2a4a8b 100755 (executable)
@@ -163,6 +163,22 @@ test_expect_success 'manual prefetch of missing objects' '
        test_line_count = 0 observed.oids
 '
 
+test_expect_success 'partial clone with transfer.fsckobjects=1 works with submodules' '
+       test_create_repo submodule &&
+       test_commit -C submodule mycommit &&
+
+       test_create_repo src_with_sub &&
+       test_config -C src_with_sub uploadpack.allowfilter 1 &&
+       test_config -C src_with_sub uploadpack.allowanysha1inwant 1 &&
+
+       git -C src_with_sub submodule add "file://$(pwd)/submodule" mysub &&
+       git -C src_with_sub commit -m "commit with submodule" &&
+
+       git -c transfer.fsckobjects=1 \
+               clone --filter="blob:none" "file://$(pwd)/src_with_sub" dst &&
+       test_when_finished rm -rf dst
+'
+
 test_expect_success 'partial clone with transfer.fsckobjects=1 uses index-pack --fsck-objects' '
        git init src &&
        test_commit -C src x &&
@@ -417,6 +433,26 @@ test_expect_success 'fetch lazy-fetches only to resolve deltas, protocol v2' '
        grep "want $(cat hash)" trace
 '
 
+test_expect_success 'fetch does not lazy-fetch missing targets of its refs' '
+       rm -rf server client trace &&
+
+       test_create_repo server &&
+       test_config -C server uploadpack.allowfilter 1 &&
+       test_config -C server uploadpack.allowanysha1inwant 1 &&
+       test_commit -C server foo &&
+
+       git clone --filter=blob:none "file://$(pwd)/server" client &&
+       # Make all refs point to nothing by deleting all objects.
+       rm client/.git/objects/pack/* &&
+
+       test_commit -C server bar &&
+       GIT_TRACE_PACKET="$(pwd)/trace" git -C client fetch \
+               --no-tags --recurse-submodules=no \
+               origin refs/tags/bar &&
+       FOO_HASH=$(git -C server rev-parse foo) &&
+       ! grep "want $FOO_HASH" trace
+'
+
 # The following two tests must be in this order. It is important that
 # the srv.bare repository did not have tags during clone, but has tags
 # in the fetch.
index 5a60fbe3edb3b00ad61995ab7dee309777d6ba3e..7d5b17909bb811148458f0566d624722f5cb8aff 100755 (executable)
@@ -883,6 +883,59 @@ test_expect_success 'fetching with valid packfile URI but invalid hash fails' '
        test_i18ngrep "pack downloaded from.*does not match expected hash" err
 '
 
+test_expect_success 'packfile-uri with transfer.fsckobjects' '
+       P="$HTTPD_DOCUMENT_ROOT_PATH/http_parent" &&
+       rm -rf "$P" http_child log &&
+
+       git init "$P" &&
+       git -C "$P" config "uploadpack.allowsidebandall" "true" &&
+
+       echo my-blob >"$P/my-blob" &&
+       git -C "$P" add my-blob &&
+       git -C "$P" commit -m x &&
+
+       configure_exclusion "$P" my-blob >h &&
+
+       sane_unset GIT_TEST_SIDEBAND_ALL &&
+       git -c protocol.version=2 -c transfer.fsckobjects=1 \
+               -c fetch.uriprotocols=http,https \
+               clone "$HTTPD_URL/smart/http_parent" http_child &&
+
+       # Ensure that there are exactly 4 files (2 .pack and 2 .idx).
+       ls http_child/.git/objects/pack/* >filelist &&
+       test_line_count = 4 filelist
+'
+
+test_expect_success 'packfile-uri with transfer.fsckobjects fails on bad object' '
+       P="$HTTPD_DOCUMENT_ROOT_PATH/http_parent" &&
+       rm -rf "$P" http_child log &&
+
+       git init "$P" &&
+       git -C "$P" config "uploadpack.allowsidebandall" "true" &&
+
+       cat >bogus-commit <<-EOF &&
+       tree $EMPTY_TREE
+       author Bugs Bunny 1234567890 +0000
+       committer Bugs Bunny <bugs@bun.ni> 1234567890 +0000
+
+       This commit object intentionally broken
+       EOF
+       BOGUS=$(git -C "$P" hash-object -t commit -w --stdin <bogus-commit) &&
+       git -C "$P" branch bogus-branch "$BOGUS" &&
+
+       echo my-blob >"$P/my-blob" &&
+       git -C "$P" add my-blob &&
+       git -C "$P" commit -m x &&
+
+       configure_exclusion "$P" my-blob >h &&
+
+       sane_unset GIT_TEST_SIDEBAND_ALL &&
+       test_must_fail git -c protocol.version=2 -c transfer.fsckobjects=1 \
+               -c fetch.uriprotocols=http,https \
+               clone "$HTTPD_URL/smart/http_parent" http_child 2>error &&
+       test_i18ngrep "invalid author/committer line - missing email" error
+'
+
 # DO NOT add non-httpd-specific tests here, because the last part of this
 # test script is only executed when httpd is available and enabled.
 
index bb5aeac07f8341ed44bfe25aba6238a92e1fc9e7..b31ff7eeec0e560fcfab90cf17bda796091d449a 100755 (executable)
@@ -345,6 +345,11 @@ test_expect_success 'rev-list should succeed with empty output with empty glob'
        test_must_be_empty actual
 '
 
+test_expect_success 'rev-list should succeed with empty output when ignoring missing' '
+       git rev-list --ignore-missing $ZERO_OID >actual &&
+       test_must_be_empty actual
+'
+
 test_expect_success 'shortlog accepts --glob/--tags/--remotes' '
 
        compare shortlog "subspace/one subspace/two" --branches=subspace &&
index a83579fbdf1c202979be589bec71ff2a886a03bf..58adee7d18ced9b18924cdd33e17bbc6368b9a9a 100755 (executable)
@@ -776,61 +776,40 @@ test_expect_success 'set up trailers for next test' '
 '
 
 test_expect_success '%(trailers:unfold) unfolds trailers' '
-       git for-each-ref --format="%(trailers:unfold)" refs/heads/master >actual &&
        {
                unfold <trailers
                echo
        } >expect &&
+       git for-each-ref --format="%(trailers:unfold)" refs/heads/master >actual &&
+       test_cmp expect actual &&
+       git for-each-ref --format="%(contents:trailers:unfold)" refs/heads/master >actual &&
        test_cmp expect actual
 '
 
 test_expect_success '%(trailers:only) shows only "key: value" trailers' '
-       git for-each-ref --format="%(trailers:only)" refs/heads/master >actual &&
        {
                grep -v patch.description <trailers &&
                echo
        } >expect &&
+       git for-each-ref --format="%(trailers:only)" refs/heads/master >actual &&
+       test_cmp expect actual &&
+       git for-each-ref --format="%(contents:trailers:only)" refs/heads/master >actual &&
        test_cmp expect actual
 '
 
 test_expect_success '%(trailers:only) and %(trailers:unfold) work together' '
-       git for-each-ref --format="%(trailers:only,unfold)" refs/heads/master >actual &&
-       git for-each-ref --format="%(trailers:unfold,only)" refs/heads/master >reverse &&
-       test_cmp actual reverse &&
        {
                grep -v patch.description <trailers | unfold &&
                echo
        } >expect &&
-       test_cmp expect actual
-'
-
-test_expect_success '%(contents:trailers:unfold) unfolds trailers' '
-       git for-each-ref --format="%(contents:trailers:unfold)" refs/heads/master >actual &&
-       {
-               unfold <trailers
-               echo
-       } >expect &&
-       test_cmp expect actual
-'
-
-test_expect_success '%(contents:trailers:only) shows only "key: value" trailers' '
-       git for-each-ref --format="%(contents:trailers:only)" refs/heads/master >actual &&
-       {
-               grep -v patch.description <trailers &&
-               echo
-       } >expect &&
-       test_cmp expect actual
-'
-
-test_expect_success '%(contents:trailers:only) and %(contents:trailers:unfold) work together' '
+       git for-each-ref --format="%(trailers:only,unfold)" refs/heads/master >actual &&
+       test_cmp expect actual &&
+       git for-each-ref --format="%(trailers:unfold,only)" refs/heads/master >actual &&
+       test_cmp actual actual &&
        git for-each-ref --format="%(contents:trailers:only,unfold)" refs/heads/master >actual &&
-       git for-each-ref --format="%(contents:trailers:unfold,only)" refs/heads/master >reverse &&
-       test_cmp actual reverse &&
-       {
-               grep -v patch.description <trailers | unfold &&
-               echo
-       } >expect &&
-       test_cmp expect actual
+       test_cmp expect actual &&
+       git for-each-ref --format="%(contents:trailers:unfold,only)" refs/heads/master >actual &&
+       test_cmp actual actual
 '
 
 test_expect_success '%(trailers) rejects unknown trailers arguments' '
@@ -839,15 +818,16 @@ test_expect_success '%(trailers) rejects unknown trailers arguments' '
        fatal: unknown %(trailers) argument: unsupported
        EOF
        test_must_fail git for-each-ref --format="%(trailers:unsupported)" 2>actual &&
+       test_i18ncmp expect actual &&
+       test_must_fail git for-each-ref --format="%(contents:trailers:unsupported)" 2>actual &&
        test_i18ncmp expect actual
 '
 
-test_expect_success '%(contents:trailers) rejects unknown trailers arguments' '
-       # error message cannot be checked under i18n
+test_expect_success 'if arguments, %(contents:trailers) shows error if colon is missing' '
        cat >expect <<-EOF &&
-       fatal: unknown %(trailers) argument: unsupported
+       fatal: unrecognized %(contents) argument: trailersonly
        EOF
-       test_must_fail git for-each-ref --format="%(contents:trailers:unsupported)" 2>actual &&
+       test_must_fail git for-each-ref --format="%(contents:trailersonly)" 2>actual &&
        test_i18ncmp expect actual
 '
 
index 9bc841d085ee74cbc4a103b3c2f07c7e4b86e82d..76088147089c9bacdf0cb9f7cb570c55c1ec3f4d 100755 (executable)
@@ -5,9 +5,18 @@
 
 test_description='Summary support for submodules
 
-This test tries to verify the sanity of summary subcommand of git submodule.
+This test script tries to verify the sanity of summary subcommand of git submodule.
 '
 
+# NOTE: This test script uses 'git add' instead of 'git submodule add' to add
+# submodules to the superproject. Some submodule subcommands such as init and
+# deinit might not work as expected in this script. t7421 does not have this
+# caveat.
+#
+# NEEDSWORK: This test script is old fashioned and may need a big cleanup due to
+# various reasons, one of them being that there are lots of commands taking place
+# outside of 'test_expect_success' block, which is no longer in good-style.
+
 . ./test-lib.sh
 
 add_file () {
@@ -16,12 +25,12 @@ add_file () {
        owd=$(pwd)
        cd "$sm"
        for name; do
-               echo "$name" > "$name" &&
+               echo "$name" >"$name" &&
                git add "$name" &&
                test_tick &&
                git commit -m "Add $name"
        done >/dev/null
-       git rev-parse --verify HEAD | cut -c1-7
+       git rev-parse --short HEAD
        cd "$owd"
 }
 commit_file () {
@@ -38,10 +47,10 @@ test_expect_success 'added submodule' "
        git add sm1 &&
        git submodule summary >actual &&
        cat >expected <<-EOF &&
-* sm1 0000000...$head1 (2):
-  > Add foo2
+       * sm1 0000000...$head1 (2):
+         > Add foo2
 
-EOF
+       EOF
        test_cmp expected actual
 "
 
@@ -52,10 +61,10 @@ test_expect_success 'added submodule (subdirectory)' "
                git submodule summary >../actual
        ) &&
        cat >expected <<-EOF &&
-* ../sm1 0000000...$head1 (2):
-  > Add foo2
+       * ../sm1 0000000...$head1 (2):
+         > Add foo2
 
-EOF
+       EOF
        test_cmp expected actual
 "
 
@@ -73,10 +82,10 @@ test_expect_success 'added submodule (subdirectory with explicit path)' "
                git submodule summary ../sm1 >../actual
        ) &&
        cat >expected <<-EOF &&
-* ../sm1 0000000...$head1 (2):
-  > Add foo2
+       * ../sm1 0000000...$head1 (2):
+         > Add foo2
 
-EOF
+       EOF
        test_cmp expected actual
 "
 
@@ -86,20 +95,20 @@ head2=$(add_file sm1 foo3)
 test_expect_success 'modified submodule(forward)' "
        git submodule summary >actual &&
        cat >expected <<-EOF &&
-* sm1 $head1...$head2 (1):
-  > Add foo3
+       * sm1 $head1...$head2 (1):
+         > Add foo3
 
-EOF
+       EOF
        test_cmp expected actual
 "
 
 test_expect_success 'modified submodule(forward), --files' "
        git submodule summary --files >actual &&
        cat >expected <<-EOF &&
-* sm1 $head1...$head2 (1):
-  > Add foo3
+       * sm1 $head1...$head2 (1):
+         > Add foo3
 
-EOF
+       EOF
        test_cmp expected actual
 "
 
@@ -110,10 +119,10 @@ test_expect_success 'no ignore=all setting has any effect' "
        git config diff.ignoreSubmodules all &&
        git submodule summary >actual &&
        cat >expected <<-EOF &&
-* sm1 $head1...$head2 (1):
-  > Add foo3
+       * sm1 $head1...$head2 (1):
+         > Add foo3
 
-EOF
+       EOF
        test_cmp expected actual &&
        git config --unset diff.ignoreSubmodules &&
        git config --remove-section submodule.sm1 &&
@@ -125,17 +134,17 @@ commit_file sm1 &&
 head3=$(
        cd sm1 &&
        git reset --hard HEAD~2 >/dev/null &&
-       git rev-parse --verify HEAD | cut -c1-7
+       git rev-parse --short HEAD
 )
 
 test_expect_success 'modified submodule(backward)' "
        git submodule summary >actual &&
        cat >expected <<-EOF &&
-* sm1 $head2...$head3 (2):
-  < Add foo3
-  < Add foo2
+       * sm1 $head2...$head3 (2):
+         < Add foo3
+         < Add foo2
 
-EOF
+       EOF
        test_cmp expected actual
 "
 
@@ -144,25 +153,25 @@ head4_full=$(GIT_DIR=sm1/.git git rev-parse --verify HEAD)
 test_expect_success 'modified submodule(backward and forward)' "
        git submodule summary >actual &&
        cat >expected <<-EOF &&
-* sm1 $head2...$head4 (4):
-  > Add foo5
-  > Add foo4
-  < Add foo3
-  < Add foo2
+       * sm1 $head2...$head4 (4):
+         > Add foo5
+         > Add foo4
+         < Add foo3
+         < Add foo2
 
-EOF
+       EOF
        test_cmp expected actual
 "
 
 test_expect_success '--summary-limit' "
        git submodule summary -n 3 >actual &&
        cat >expected <<-EOF &&
-* sm1 $head2...$head4 (4):
-  > Add foo5
-  > Add foo4
-  < Add foo3
+       * sm1 $head2...$head4 (4):
+         > Add foo5
+         > Add foo4
+         < Add foo3
 
-EOF
+       EOF
        test_cmp expected actual
 "
 
@@ -177,21 +186,21 @@ mv sm1-bak sm1
 test_expect_success 'typechanged submodule(submodule->blob), --cached' "
        git submodule summary --cached >actual &&
        cat >expected <<-EOF &&
-* sm1 $head4(submodule)->$head5(blob) (3):
-  < Add foo5
+       * sm1 $head4(submodule)->$head5(blob) (3):
+         < Add foo5
 
-EOF
-       test_i18ncmp actual expected
+       EOF
+       test_i18ncmp expected actual
 "
 
 test_expect_success 'typechanged submodule(submodule->blob), --files' "
        git submodule summary --files >actual &&
        cat >expected <<-EOF &&
-* sm1 $head5(blob)->$head4(submodule) (3):
-  > Add foo5
+       * sm1 $head5(blob)->$head4(submodule) (3):
+         > Add foo5
 
-EOF
-       test_i18ncmp actual expected
+       EOF
+       test_i18ncmp expected actual
 "
 
 rm -rf sm1 &&
@@ -199,10 +208,10 @@ git checkout-index sm1
 test_expect_success 'typechanged submodule(submodule->blob)' "
        git submodule summary >actual &&
        cat >expected <<-EOF &&
-* sm1 $head4(submodule)->$head5(blob):
+       * sm1 $head4(submodule)->$head5(blob):
 
-EOF
-       test_i18ncmp actual expected
+       EOF
+       test_i18ncmp expected actual
 "
 
 rm -f sm1 &&
@@ -211,21 +220,21 @@ head6=$(add_file sm1 foo6 foo7)
 test_expect_success 'nonexistent commit' "
        git submodule summary >actual &&
        cat >expected <<-EOF &&
-* sm1 $head4...$head6:
-  Warn: sm1 doesn't contain commit $head4_full
+       * sm1 $head4...$head6:
+         Warn: sm1 doesn't contain commit $head4_full
 
-EOF
-       test_i18ncmp actual expected
+       EOF
+       test_i18ncmp expected actual
 "
 
 commit_file
 test_expect_success 'typechanged submodule(blob->submodule)' "
        git submodule summary >actual &&
        cat >expected <<-EOF &&
-* sm1 $head5(blob)->$head6(submodule) (2):
-  > Add foo7
+       * sm1 $head5(blob)->$head6(submodule) (2):
+         > Add foo7
 
-EOF
+       EOF
        test_i18ncmp expected actual
 "
 
@@ -234,9 +243,9 @@ rm -rf sm1
 test_expect_success 'deleted submodule' "
        git submodule summary >actual &&
        cat >expected <<-EOF &&
-* sm1 $head6...0000000:
+       * sm1 $head6...0000000:
 
-EOF
+       EOF
        test_cmp expected actual
 "
 
@@ -249,22 +258,22 @@ test_expect_success 'create second submodule' '
 test_expect_success 'multiple submodules' "
        git submodule summary >actual &&
        cat >expected <<-EOF &&
-* sm1 $head6...0000000:
+       * sm1 $head6...0000000:
 
-* sm2 0000000...$head7 (2):
-  > Add foo9
+       * sm2 0000000...$head7 (2):
+         > Add foo9
 
-EOF
+       EOF
        test_cmp expected actual
 "
 
 test_expect_success 'path filter' "
        git submodule summary sm2 >actual &&
        cat >expected <<-EOF &&
-* sm2 0000000...$head7 (2):
-  > Add foo9
+       * sm2 0000000...$head7 (2):
+         > Add foo9
 
-EOF
+       EOF
        test_cmp expected actual
 "
 
@@ -272,24 +281,24 @@ commit_file sm2
 test_expect_success 'given commit' "
        git submodule summary HEAD^ >actual &&
        cat >expected <<-EOF &&
-* sm1 $head6...0000000:
+       * sm1 $head6...0000000:
 
-* sm2 0000000...$head7 (2):
-  > Add foo9
+       * sm2 0000000...$head7 (2):
+         > Add foo9
 
-EOF
+       EOF
        test_cmp expected actual
 "
 
 test_expect_success '--for-status' "
        git submodule summary --for-status HEAD^ >actual &&
-       test_i18ncmp actual - <<EOF
-* sm1 $head6...0000000:
+       test_i18ncmp - actual <<-EOF
+       * sm1 $head6...0000000:
 
-* sm2 0000000...$head7 (2):
-  > Add foo9
+       * sm2 0000000...$head7 (2):
+         > Add foo9
 
-EOF
+       EOF
 "
 
 test_expect_success 'fail when using --files together with --cached' "
diff --git a/t/t7421-submodule-summary-add.sh b/t/t7421-submodule-summary-add.sh
new file mode 100755 (executable)
index 0000000..59a9b00
--- /dev/null
@@ -0,0 +1,69 @@
+#!/bin/sh
+#
+# Copyright (C) 2020 Shourya Shukla
+#
+
+test_description='Summary support for submodules, adding them using git submodule add
+
+This test script tries to verify the sanity of summary subcommand of git submodule
+while making sure to add submodules using `git submodule add` instead of
+`git add` as done in t7401.
+'
+
+. ./test-lib.sh
+
+test_expect_success 'summary test environment setup' '
+       git init sm &&
+       test_commit -C sm "add file" file file-content file-tag &&
+
+       git submodule add ./sm my-subm &&
+       test_tick &&
+       git commit -m "add submodule"
+'
+
+test_expect_success 'submodule summary output for initialized submodule' '
+       test_commit -C sm "add file2" file2 file2-content file2-tag &&
+       git submodule update --remote &&
+       test_tick &&
+       git commit -m "update submodule" my-subm &&
+       git submodule summary HEAD^ >actual &&
+       rev1=$(git -C sm rev-parse --short HEAD^) &&
+       rev2=$(git -C sm rev-parse --short HEAD) &&
+       cat >expected <<-EOF &&
+       * my-subm ${rev1}...${rev2} (1):
+         > add file2
+
+       EOF
+       test_cmp expected actual
+'
+
+test_expect_success 'submodule summary output for deinitialized submodule' '
+       git submodule deinit my-subm &&
+       git submodule summary HEAD^ >actual &&
+       test_must_be_empty actual &&
+       git submodule update --init my-subm &&
+       git submodule summary HEAD^ >actual &&
+       rev1=$(git -C sm rev-parse --short HEAD^) &&
+       rev2=$(git -C sm rev-parse --short HEAD) &&
+       cat >expected <<-EOF &&
+       * my-subm ${rev1}...${rev2} (1):
+         > add file2
+
+       EOF
+       test_cmp expected actual
+'
+
+test_expect_success 'submodule summary output for submodules with changed paths' '
+       git mv my-subm subm &&
+       git commit -m "change submodule path" &&
+       rev=$(git -C sm rev-parse --short HEAD^) &&
+       git submodule summary HEAD^^ -- my-subm >actual 2>err &&
+       grep "fatal:.*my-subm" err &&
+       cat >expected <<-EOF &&
+       * my-subm ${rev}...0000000:
+
+       EOF
+       test_cmp expected actual
+'
+
+test_done
index b22f631261f0a666ff5c4dc226be4f758f002709..dc3e9c8c88b1d1037e355155b9325b4d4ded27db 100755 (executable)
@@ -29,7 +29,18 @@ test_expect_success 'empty configured name does not auto-detect' '
                sane_unset GIT_AUTHOR_NAME &&
                test_must_fail \
                        git -c user.name= commit --allow-empty -m foo 2>err &&
-               test_i18ngrep "empty ident name" err
+               test_i18ngrep "empty ident name" err &&
+               test_i18ngrep "Author identity unknown" err
+       )
+'
+
+test_expect_success 'empty configured name does not auto-detect for committer' '
+       (
+               sane_unset GIT_COMMITTER_NAME &&
+               test_must_fail \
+                       git -c user.name= commit --allow-empty -m foo 2>err &&
+               test_i18ngrep "empty ident name" err &&
+               test_i18ngrep "Committer identity unknown" err
        )
 '
 
diff --git a/t/t9010-svn-fe.sh b/t/t9010-svn-fe.sh
deleted file mode 100755 (executable)
index 83f8f5c..0000000
+++ /dev/null
@@ -1,1105 +0,0 @@
-#!/bin/sh
-
-test_description='check svn dumpfile importer'
-
-. ./test-lib.sh
-
-if test_have_prereq !PIPE
-then
-       skip_all="svn dumpfile importer testing requires the PIPE prerequisite"
-       test_done
-fi
-
-reinit_git () {
-       rm -fr .git &&
-       rm -f stream backflow &&
-       git init &&
-       mkfifo stream backflow
-}
-
-try_dump () {
-       input=$1 &&
-       maybe_fail_svnfe=${2:+test_$2} &&
-       maybe_fail_fi=${3:+test_$3} &&
-
-       {
-               $maybe_fail_svnfe test-svn-fe "$input" >stream 3<backflow &
-       } &&
-       $maybe_fail_fi git fast-import --cat-blob-fd=3 <stream 3>backflow &&
-       wait $!
-}
-
-properties () {
-       while test "$#" -ne 0
-       do
-               property="$1" &&
-               value="$2" &&
-               printf "%s\n" "K ${#property}" &&
-               printf "%s\n" "$property" &&
-               printf "%s\n" "V ${#value}" &&
-               printf "%s\n" "$value" &&
-               shift 2 ||
-               return 1
-       done
-}
-
-text_no_props () {
-       text="$1
-" &&
-       printf "%s\n" "Prop-content-length: 10" &&
-       printf "%s\n" "Text-content-length: ${#text}" &&
-       printf "%s\n" "Content-length: $((${#text} + 10))" &&
-       printf "%s\n" "" "PROPS-END" &&
-       printf "%s\n" "$text"
-}
-
-test_expect_success 'empty dump' '
-       reinit_git &&
-       echo "SVN-fs-dump-format-version: 2" >input &&
-       try_dump input
-'
-
-test_expect_success 'v4 dumps not supported' '
-       reinit_git &&
-       echo "SVN-fs-dump-format-version: 4" >v4.dump &&
-       try_dump v4.dump must_fail
-'
-
-test_expect_failure 'empty revision' '
-       reinit_git &&
-       printf "rev <nobody, nobody@local>: %s\n" "" "" >expect &&
-       cat >emptyrev.dump <<-\EOF &&
-       SVN-fs-dump-format-version: 3
-
-       Revision-number: 1
-       Prop-content-length: 0
-       Content-length: 0
-
-       Revision-number: 2
-       Prop-content-length: 0
-       Content-length: 0
-
-       EOF
-       try_dump emptyrev.dump &&
-       git log -p --format="rev <%an, %ae>: %s" HEAD >actual &&
-       test_cmp expect actual
-'
-
-test_expect_success 'empty properties' '
-       reinit_git &&
-       printf "rev <nobody, nobody@local>: %s\n" "" "" >expect &&
-       cat >emptyprop.dump <<-\EOF &&
-       SVN-fs-dump-format-version: 3
-
-       Revision-number: 1
-       Prop-content-length: 10
-       Content-length: 10
-
-       PROPS-END
-
-       Revision-number: 2
-       Prop-content-length: 10
-       Content-length: 10
-
-       PROPS-END
-       EOF
-       try_dump emptyprop.dump &&
-       git log -p --format="rev <%an, %ae>: %s" HEAD >actual &&
-       test_cmp expect actual
-'
-
-test_expect_success 'author name and commit message' '
-       reinit_git &&
-       echo "<author@example.com, author@example.com@local>" >expect.author &&
-       cat >message <<-\EOF &&
-       A concise summary of the change
-
-       A detailed description of the change, why it is needed, what
-       was broken and why applying this is the best course of action.
-
-       * file.c
-           Details pertaining to an individual file.
-       EOF
-       {
-               properties \
-                       svn:author author@example.com \
-                       svn:log "$(cat message)" &&
-               echo PROPS-END
-       } >props &&
-       {
-               echo "SVN-fs-dump-format-version: 3" &&
-               echo &&
-               echo "Revision-number: 1" &&
-               echo Prop-content-length: $(wc -c <props) &&
-               echo Content-length: $(wc -c <props) &&
-               echo &&
-               cat props
-       } >log.dump &&
-       try_dump log.dump &&
-       git log -p --format="%B" HEAD >actual.log &&
-       git log --format="<%an, %ae>" >actual.author &&
-       test_cmp message actual.log &&
-       test_cmp expect.author actual.author
-'
-
-test_expect_success 'unsupported properties are ignored' '
-       reinit_git &&
-       echo author >expect &&
-       cat >extraprop.dump <<-\EOF &&
-       SVN-fs-dump-format-version: 3
-
-       Revision-number: 1
-       Prop-content-length: 56
-       Content-length: 56
-
-       K 8
-       nonsense
-       V 1
-       y
-       K 10
-       svn:author
-       V 6
-       author
-       PROPS-END
-       EOF
-       try_dump extraprop.dump &&
-       git log -p --format=%an HEAD >actual &&
-       test_cmp expect actual
-'
-
-test_expect_failure 'timestamp and empty file' '
-       echo author@example.com >expect.author &&
-       echo 1999-01-01 >expect.date &&
-       echo file >expect.files &&
-       reinit_git &&
-       {
-               properties \
-                       svn:author author@example.com \
-                       svn:date "1999-01-01T00:01:002.000000Z" \
-                       svn:log "add empty file" &&
-               echo PROPS-END
-       } >props &&
-       {
-               cat <<-EOF &&
-               SVN-fs-dump-format-version: 3
-
-               Revision-number: 1
-               EOF
-               echo Prop-content-length: $(wc -c <props) &&
-               echo Content-length: $(wc -c <props) &&
-               echo &&
-               cat props &&
-               cat <<-\EOF
-
-               Node-path: empty-file
-               Node-kind: file
-               Node-action: add
-               Content-length: 0
-
-               EOF
-       } >emptyfile.dump &&
-       try_dump emptyfile.dump &&
-       git log --format=%an HEAD >actual.author &&
-       git log --date=short --format=%ad HEAD >actual.date &&
-       git ls-tree -r --name-only HEAD >actual.files &&
-       test_cmp expect.author actual.author &&
-       test_cmp expect.date actual.date &&
-       test_cmp expect.files actual.files &&
-       git checkout HEAD empty-file &&
-       test_must_be_empty file
-'
-
-test_expect_success 'directory with files' '
-       reinit_git &&
-       printf "%s\n" directory/file1 directory/file2 >expect.files &&
-       echo hi >hi &&
-       echo hello >hello &&
-       {
-               properties \
-                       svn:author author@example.com \
-                       svn:date "1999-02-01T00:01:002.000000Z" \
-                       svn:log "add directory with some files in it" &&
-               echo PROPS-END
-       } >props &&
-       {
-               cat <<-EOF &&
-               SVN-fs-dump-format-version: 3
-
-               Revision-number: 1
-               EOF
-               echo Prop-content-length: $(wc -c <props) &&
-               echo Content-length: $(wc -c <props) &&
-               echo &&
-               cat props &&
-               cat <<-\EOF &&
-
-               Node-path: directory
-               Node-kind: dir
-               Node-action: add
-               Prop-content-length: 10
-               Content-length: 10
-
-               PROPS-END
-
-               Node-path: directory/file1
-               Node-kind: file
-               Node-action: add
-               EOF
-               text_no_props hello &&
-               cat <<-\EOF &&
-               Node-path: directory/file2
-               Node-kind: file
-               Node-action: add
-               EOF
-               text_no_props hi
-       } >directory.dump &&
-       try_dump directory.dump &&
-
-       git ls-tree -r --name-only HEAD >actual.files &&
-       git checkout HEAD directory &&
-       test_cmp expect.files actual.files &&
-       test_cmp hello directory/file1 &&
-       test_cmp hi directory/file2
-'
-
-test_expect_success 'branch name with backslash' '
-       reinit_git &&
-       sort <<-\EOF >expect.branch-files &&
-       trunk/file1
-       trunk/file2
-       "branches/UpdateFOPto094\\/file1"
-       "branches/UpdateFOPto094\\/file2"
-       EOF
-
-       echo hi >hi &&
-       echo hello >hello &&
-       {
-               properties \
-                       svn:author author@example.com \
-                       svn:date "1999-02-02T00:01:02.000000Z" \
-                       svn:log "add directory with some files in it" &&
-               echo PROPS-END
-       } >props.setup &&
-       {
-               properties \
-                       svn:author brancher@example.com \
-                       svn:date "2007-12-06T21:38:34.000000Z" \
-                       svn:log "Updating fop to .94 and adjust fo-stylesheets" &&
-               echo PROPS-END
-       } >props.branch &&
-       {
-               cat <<-EOF &&
-               SVN-fs-dump-format-version: 3
-
-               Revision-number: 1
-               EOF
-               echo Prop-content-length: $(wc -c <props.setup) &&
-               echo Content-length: $(wc -c <props.setup) &&
-               echo &&
-               cat props.setup &&
-               cat <<-\EOF &&
-
-               Node-path: trunk
-               Node-kind: dir
-               Node-action: add
-               Prop-content-length: 10
-               Content-length: 10
-
-               PROPS-END
-
-               Node-path: branches
-               Node-kind: dir
-               Node-action: add
-               Prop-content-length: 10
-               Content-length: 10
-
-               PROPS-END
-
-               Node-path: trunk/file1
-               Node-kind: file
-               Node-action: add
-               EOF
-               text_no_props hello &&
-               cat <<-\EOF &&
-               Node-path: trunk/file2
-               Node-kind: file
-               Node-action: add
-               EOF
-               text_no_props hi &&
-               cat <<-\EOF &&
-
-               Revision-number: 2
-               EOF
-               echo Prop-content-length: $(wc -c <props.branch) &&
-               echo Content-length: $(wc -c <props.branch) &&
-               echo &&
-               cat props.branch &&
-               cat <<-\EOF
-
-               Node-path: branches/UpdateFOPto094\
-               Node-kind: dir
-               Node-action: add
-               Node-copyfrom-rev: 1
-               Node-copyfrom-path: trunk
-
-               Node-kind: dir
-               Node-action: add
-               Prop-content-length: 34
-               Content-length: 34
-
-               K 13
-               svn:mergeinfo
-               V 0
-
-               PROPS-END
-               EOF
-       } >branch.dump &&
-       try_dump branch.dump &&
-
-       git ls-tree -r --name-only HEAD |
-       sort >actual.branch-files &&
-       test_cmp expect.branch-files actual.branch-files
-'
-
-test_expect_success 'node without action' '
-       reinit_git &&
-       cat >inaction.dump <<-\EOF &&
-       SVN-fs-dump-format-version: 3
-
-       Revision-number: 1
-       Prop-content-length: 10
-       Content-length: 10
-
-       PROPS-END
-
-       Node-path: directory
-       Node-kind: dir
-       Prop-content-length: 10
-       Content-length: 10
-
-       PROPS-END
-       EOF
-       try_dump inaction.dump must_fail
-'
-
-test_expect_success 'action: add node without text' '
-       reinit_git &&
-       cat >textless.dump <<-\EOF &&
-       SVN-fs-dump-format-version: 3
-
-       Revision-number: 1
-       Prop-content-length: 10
-       Content-length: 10
-
-       PROPS-END
-
-       Node-path: textless
-       Node-kind: file
-       Node-action: add
-       Prop-content-length: 10
-       Content-length: 10
-
-       PROPS-END
-       EOF
-       try_dump textless.dump must_fail
-'
-
-test_expect_failure 'change file mode but keep old content' '
-       reinit_git &&
-       cat >expect <<-\EOF &&
-       OBJID
-       :120000 100644 OBJID OBJID T    greeting
-       OBJID
-       :100644 120000 OBJID OBJID T    greeting
-       OBJID
-       :000000 100644 OBJID OBJID A    greeting
-       EOF
-       echo "link hello" >expect.blob &&
-       echo hello >hello &&
-       cat >filemode.dump <<-\EOF &&
-       SVN-fs-dump-format-version: 3
-
-       Revision-number: 1
-       Prop-content-length: 10
-       Content-length: 10
-
-       PROPS-END
-
-       Node-path: greeting
-       Node-kind: file
-       Node-action: add
-       Prop-content-length: 10
-       Text-content-length: 11
-       Content-length: 21
-
-       PROPS-END
-       link hello
-
-       Revision-number: 2
-       Prop-content-length: 10
-       Content-length: 10
-
-       PROPS-END
-
-       Node-path: greeting
-       Node-kind: file
-       Node-action: change
-       Prop-content-length: 33
-       Content-length: 33
-
-       K 11
-       svn:special
-       V 1
-       *
-       PROPS-END
-
-       Revision-number: 3
-       Prop-content-length: 10
-       Content-length: 10
-
-       PROPS-END
-
-       Node-path: greeting
-       Node-kind: file
-       Node-action: change
-       Prop-content-length: 10
-       Content-length: 10
-
-       PROPS-END
-       EOF
-       try_dump filemode.dump &&
-       {
-               git rev-list HEAD |
-               git diff-tree --root --stdin |
-               sed "s/$OID_REGEX/OBJID/g"
-       } >actual &&
-       git show HEAD:greeting >actual.blob &&
-       git show HEAD^:greeting >actual.target &&
-       test_cmp expect actual &&
-       test_cmp expect.blob actual.blob &&
-       test_cmp hello actual.target
-'
-
-test_expect_success 'NUL in property value' '
-       reinit_git &&
-       echo "commit message" >expect.message &&
-       {
-               properties \
-                       unimportant "something with a NUL (Q)" \
-                       svn:log "commit message" &&
-               echo PROPS-END
-       } |
-       q_to_nul >props &&
-       {
-               cat <<-\EOF &&
-               SVN-fs-dump-format-version: 3
-
-               Revision-number: 1
-               EOF
-               echo Prop-content-length: $(wc -c <props) &&
-               echo Content-length: $(wc -c <props) &&
-               echo &&
-               cat props
-       } >nulprop.dump &&
-       try_dump nulprop.dump &&
-       git diff-tree --always -s --format=%s HEAD >actual.message &&
-       test_cmp expect.message actual.message
-'
-
-test_expect_success 'NUL in log message, file content, and property name' '
-       # Caveat: svnadmin 1.6.16 (r1073529) truncates at \0 in the
-       # svn:specialQnotreally example.
-       reinit_git &&
-       cat >expect <<-\EOF &&
-       OBJID
-       :100644 100644 OBJID OBJID M    greeting
-       OBJID
-       :000000 100644 OBJID OBJID A    greeting
-       EOF
-       printf "\n%s\n" "something with an ASCII NUL (Q)" >expect.message &&
-       printf "%s\n" "helQo" >expect.hello1 &&
-       printf "%s\n" "link hello" >expect.hello2 &&
-       {
-               properties svn:log "something with an ASCII NUL (Q)" &&
-               echo PROPS-END
-       } |
-       q_to_nul >props &&
-       {
-               q_to_nul <<-\EOF &&
-               SVN-fs-dump-format-version: 3
-
-               Revision-number: 1
-               Prop-content-length: 10
-               Content-length: 10
-
-               PROPS-END
-
-               Node-path: greeting
-               Node-kind: file
-               Node-action: add
-               Prop-content-length: 10
-               Text-content-length: 6
-               Content-length: 16
-
-               PROPS-END
-               helQo
-
-               Revision-number: 2
-               EOF
-               echo Prop-content-length: $(wc -c <props) &&
-               echo Content-length: $(wc -c <props) &&
-               echo &&
-               cat props &&
-               q_to_nul <<-\EOF
-
-               Node-path: greeting
-               Node-kind: file
-               Node-action: change
-               Prop-content-length: 43
-               Text-content-length: 11
-               Content-length: 54
-
-               K 21
-               svn:specialQnotreally
-               V 1
-               *
-               PROPS-END
-               link hello
-               EOF
-       } >8bitclean.dump &&
-       try_dump 8bitclean.dump &&
-       {
-               git rev-list HEAD |
-               git diff-tree --root --stdin |
-               sed "s/$OID_REGEX/OBJID/g"
-       } >actual &&
-       {
-               git cat-file commit HEAD | nul_to_q &&
-               echo
-       } |
-       sed -ne "/^\$/,\$ p" >actual.message &&
-       git cat-file blob HEAD^:greeting | nul_to_q >actual.hello1 &&
-       git cat-file blob HEAD:greeting | nul_to_q >actual.hello2 &&
-       test_cmp expect actual &&
-       test_cmp expect.message actual.message &&
-       test_cmp expect.hello1 actual.hello1 &&
-       test_cmp expect.hello2 actual.hello2
-'
-
-test_expect_success 'change file mode and reiterate content' '
-       reinit_git &&
-       cat >expect <<-\EOF &&
-       OBJID
-       :120000 100644 OBJID OBJID T    greeting
-       OBJID
-       :100644 120000 OBJID OBJID T    greeting
-       OBJID
-       :000000 100644 OBJID OBJID A    greeting
-       EOF
-       echo "link hello" >expect.blob &&
-       echo hello >hello &&
-       cat >filemode2.dump <<-\EOF &&
-       SVN-fs-dump-format-version: 3
-
-       Revision-number: 1
-       Prop-content-length: 10
-       Content-length: 10
-
-       PROPS-END
-
-       Node-path: greeting
-       Node-kind: file
-       Node-action: add
-       Prop-content-length: 10
-       Text-content-length: 11
-       Content-length: 21
-
-       PROPS-END
-       link hello
-
-       Revision-number: 2
-       Prop-content-length: 10
-       Content-length: 10
-
-       PROPS-END
-
-       Node-path: greeting
-       Node-kind: file
-       Node-action: change
-       Prop-content-length: 33
-       Text-content-length: 11
-       Content-length: 44
-
-       K 11
-       svn:special
-       V 1
-       *
-       PROPS-END
-       link hello
-
-       Revision-number: 3
-       Prop-content-length: 10
-       Content-length: 10
-
-       PROPS-END
-
-       Node-path: greeting
-       Node-kind: file
-       Node-action: change
-       Prop-content-length: 10
-       Text-content-length: 11
-       Content-length: 21
-
-       PROPS-END
-       link hello
-       EOF
-       try_dump filemode2.dump &&
-       {
-               git rev-list HEAD |
-               git diff-tree --root --stdin |
-               sed "s/$OID_REGEX/OBJID/g"
-       } >actual &&
-       git show HEAD:greeting >actual.blob &&
-       git show HEAD^:greeting >actual.target &&
-       test_cmp expect actual &&
-       test_cmp expect.blob actual.blob &&
-       test_cmp hello actual.target
-'
-
-test_expect_success 'deltas supported' '
-       reinit_git &&
-       {
-               # (old) h + (inline) ello + (old) \n
-               printf "SVNQ%b%b%s" "Q\003\006\005\004" "\001Q\0204\001\002" "ello" |
-               q_to_nul
-       } >delta &&
-       {
-               properties \
-                       svn:author author@example.com \
-                       svn:date "1999-01-05T00:01:002.000000Z" \
-                       svn:log "add greeting" &&
-               echo PROPS-END
-       } >props &&
-       {
-               properties \
-                       svn:author author@example.com \
-                       svn:date "1999-01-06T00:01:002.000000Z" \
-                       svn:log "change it" &&
-               echo PROPS-END
-       } >props2 &&
-       {
-               echo SVN-fs-dump-format-version: 3 &&
-               echo &&
-               echo Revision-number: 1 &&
-               echo Prop-content-length: $(wc -c <props) &&
-               echo Content-length: $(wc -c <props) &&
-               echo &&
-               cat props &&
-               cat <<-\EOF &&
-
-               Node-path: hello
-               Node-kind: file
-               Node-action: add
-               Prop-content-length: 10
-               Text-content-length: 3
-               Content-length: 13
-
-               PROPS-END
-               hi
-
-               EOF
-               echo Revision-number: 2 &&
-               echo Prop-content-length: $(wc -c <props2) &&
-               echo Content-length: $(wc -c <props2) &&
-               echo &&
-               cat props2 &&
-               cat <<-\EOF &&
-
-               Node-path: hello
-               Node-kind: file
-               Node-action: change
-               Text-delta: true
-               Prop-content-length: 10
-               EOF
-               echo Text-content-length: $(wc -c <delta) &&
-               echo Content-length: $((10 + $(wc -c <delta))) &&
-               echo &&
-               echo PROPS-END &&
-               cat delta
-       } >delta.dump &&
-       try_dump delta.dump
-'
-
-test_expect_success 'property deltas supported' '
-       reinit_git &&
-       cat >expect <<-\EOF &&
-       OBJID
-       :100755 100644 OBJID OBJID M    script.sh
-       EOF
-       {
-               properties \
-                       svn:author author@example.com \
-                       svn:date "1999-03-06T00:01:002.000000Z" \
-                       svn:log "make an executable, or chmod -x it" &&
-               echo PROPS-END
-       } >revprops &&
-       {
-               echo SVN-fs-dump-format-version: 3 &&
-               echo &&
-               echo Revision-number: 1 &&
-               echo Prop-content-length: $(wc -c <revprops) &&
-               echo Content-length: $(wc -c <revprops) &&
-               echo &&
-               cat revprops &&
-               echo &&
-               cat <<-\EOF &&
-               Node-path: script.sh
-               Node-kind: file
-               Node-action: add
-               Text-content-length: 0
-               Prop-content-length: 39
-               Content-length: 39
-
-               K 14
-               svn:executable
-               V 4
-               true
-               PROPS-END
-
-               EOF
-               echo Revision-number: 2 &&
-               echo Prop-content-length: $(wc -c <revprops) &&
-               echo Content-length: $(wc -c <revprops) &&
-               echo &&
-               cat revprops &&
-               echo &&
-               cat <<-\EOF
-               Node-path: script.sh
-               Node-kind: file
-               Node-action: change
-               Prop-delta: true
-               Prop-content-length: 30
-               Content-length: 30
-
-               D 14
-               svn:executable
-               PROPS-END
-               EOF
-       } >propdelta.dump &&
-       try_dump propdelta.dump &&
-       {
-               git rev-list HEAD |
-               git diff-tree --stdin |
-               sed "s/$OID_REGEX/OBJID/g"
-       } >actual &&
-       test_cmp expect actual
-'
-
-test_expect_success 'properties on /' '
-       reinit_git &&
-       cat <<-\EOF >expect &&
-       OBJID
-       OBJID
-       :000000 100644 OBJID OBJID A    greeting
-       EOF
-       sed -e "s/X$//" <<-\EOF >changeroot.dump &&
-       SVN-fs-dump-format-version: 3
-
-       Revision-number: 1
-       Prop-content-length: 10
-       Content-length: 10
-
-       PROPS-END
-
-       Node-path: greeting
-       Node-kind: file
-       Node-action: add
-       Text-content-length: 0
-       Prop-content-length: 10
-       Content-length: 10
-
-       PROPS-END
-
-       Revision-number: 2
-       Prop-content-length: 10
-       Content-length: 10
-
-       PROPS-END
-
-       Node-path: X
-       Node-kind: dir
-       Node-action: change
-       Prop-delta: true
-       Prop-content-length: 43
-       Content-length: 43
-
-       K 10
-       svn:ignore
-       V 11
-       build-area
-
-       PROPS-END
-       EOF
-       try_dump changeroot.dump &&
-       {
-               git rev-list HEAD |
-               git diff-tree --root --always --stdin |
-               sed "s/$OID_REGEX/OBJID/g"
-       } >actual &&
-       test_cmp expect actual
-'
-
-test_expect_success 'deltas for typechange' '
-       reinit_git &&
-       cat >expect <<-\EOF &&
-       OBJID
-       :120000 100644 OBJID OBJID T    test-file
-       OBJID
-       :100755 120000 OBJID OBJID T    test-file
-       OBJID
-       :000000 100755 OBJID OBJID A    test-file
-       EOF
-       cat >deleteprop.dump <<-\EOF &&
-       SVN-fs-dump-format-version: 3
-
-       Revision-number: 1
-       Prop-content-length: 10
-       Content-length: 10
-
-       PROPS-END
-
-       Node-path: test-file
-       Node-kind: file
-       Node-action: add
-       Prop-delta: true
-       Prop-content-length: 35
-       Text-content-length: 17
-       Content-length: 52
-
-       K 14
-       svn:executable
-       V 0
-
-       PROPS-END
-       link testing 123
-
-       Revision-number: 2
-       Prop-content-length: 10
-       Content-length: 10
-
-       PROPS-END
-
-       Node-path: test-file
-       Node-kind: file
-       Node-action: change
-       Prop-delta: true
-       Prop-content-length: 53
-       Text-content-length: 17
-       Content-length: 70
-
-       K 11
-       svn:special
-       V 1
-       *
-       D 14
-       svn:executable
-       PROPS-END
-       link testing 231
-
-       Revision-number: 3
-       Prop-content-length: 10
-       Content-length: 10
-
-       PROPS-END
-
-       Node-path: test-file
-       Node-kind: file
-       Node-action: change
-       Prop-delta: true
-       Prop-content-length: 27
-       Text-content-length: 17
-       Content-length: 44
-
-       D 11
-       svn:special
-       PROPS-END
-       link testing 321
-       EOF
-       try_dump deleteprop.dump &&
-       {
-               git rev-list HEAD |
-               git diff-tree --root --stdin |
-               sed "s/$OID_REGEX/OBJID/g"
-       } >actual &&
-       test_cmp expect actual
-'
-
-test_expect_success 'deltas need not consume the whole preimage' '
-       reinit_git &&
-       cat >expect <<-\EOF &&
-       OBJID
-       :120000 100644 OBJID OBJID T    postimage
-       OBJID
-       :100644 120000 OBJID OBJID T    postimage
-       OBJID
-       :000000 100644 OBJID OBJID A    postimage
-       EOF
-       echo "first preimage" >expect.1 &&
-       printf target >expect.2 &&
-       printf lnk >expect.3 &&
-       {
-               printf "SVNQ%b%b%b" "QQ\017\001\017" "\0217" "first preimage\n" |
-               q_to_nul
-       } >delta.1 &&
-       {
-               properties svn:special "*" &&
-               echo PROPS-END
-       } >symlink.props &&
-       {
-               printf "SVNQ%b%b%b" "Q\002\013\004\012" "\0201\001\001\0211" "lnk target" |
-               q_to_nul
-       } >delta.2 &&
-       {
-               printf "SVNQ%b%b" "Q\004\003\004Q" "\001Q\002\002" |
-               q_to_nul
-       } >delta.3 &&
-       {
-               cat <<-\EOF &&
-               SVN-fs-dump-format-version: 3
-
-               Revision-number: 1
-               Prop-content-length: 10
-               Content-length: 10
-
-               PROPS-END
-
-               Node-path: postimage
-               Node-kind: file
-               Node-action: add
-               Text-delta: true
-               Prop-content-length: 10
-               EOF
-               echo Text-content-length: $(wc -c <delta.1) &&
-               echo Content-length: $((10 + $(wc -c <delta.1))) &&
-               echo &&
-               echo PROPS-END &&
-               cat delta.1 &&
-               cat <<-\EOF &&
-
-               Revision-number: 2
-               Prop-content-length: 10
-               Content-length: 10
-
-               PROPS-END
-
-               Node-path: postimage
-               Node-kind: file
-               Node-action: change
-               Text-delta: true
-               EOF
-               echo Prop-content-length: $(wc -c <symlink.props) &&
-               echo Text-content-length: $(wc -c <delta.2) &&
-               echo Content-length: $(($(wc -c <symlink.props) + $(wc -c <delta.2))) &&
-               echo &&
-               cat symlink.props &&
-               cat delta.2 &&
-               cat <<-\EOF &&
-
-               Revision-number: 3
-               Prop-content-length: 10
-               Content-length: 10
-
-               PROPS-END
-
-               Node-path: postimage
-               Node-kind: file
-               Node-action: change
-               Text-delta: true
-               Prop-content-length: 10
-               EOF
-               echo Text-content-length: $(wc -c <delta.3) &&
-               echo Content-length: $((10 + $(wc -c <delta.3))) &&
-               echo &&
-               echo PROPS-END &&
-               cat delta.3 &&
-               echo
-       } >deltapartial.dump &&
-       try_dump deltapartial.dump &&
-       {
-               git rev-list HEAD |
-               git diff-tree --root --stdin |
-               sed "s/$OID_REGEX/OBJID/g"
-       } >actual &&
-       test_cmp expect actual &&
-       git show HEAD:postimage >actual.3 &&
-       git show HEAD^:postimage >actual.2 &&
-       git show HEAD^^:postimage >actual.1 &&
-       test_cmp expect.1 actual.1 &&
-       test_cmp expect.2 actual.2 &&
-       test_cmp expect.3 actual.3
-'
-
-test_expect_success 'no hang for delta trying to read past end of preimage' '
-       reinit_git &&
-       {
-               # COPY 1
-               printf "SVNQ%b%b" "Q\001\001\002Q" "\001Q" |
-               q_to_nul
-       } >greedy.delta &&
-       {
-               cat <<-\EOF &&
-               SVN-fs-dump-format-version: 3
-
-               Revision-number: 1
-               Prop-content-length: 10
-               Content-length: 10
-
-               PROPS-END
-
-               Node-path: bootstrap
-               Node-kind: file
-               Node-action: add
-               Text-delta: true
-               Prop-content-length: 10
-               EOF
-               echo Text-content-length: $(wc -c <greedy.delta) &&
-               echo Content-length: $((10 + $(wc -c <greedy.delta))) &&
-               echo &&
-               echo PROPS-END &&
-               cat greedy.delta &&
-               echo
-       } >greedydelta.dump &&
-       try_dump greedydelta.dump must_fail might_fail
-'
-
-test_expect_success 'set up svn repo' '
-       svnconf=$PWD/svnconf &&
-       mkdir -p "$svnconf" &&
-
-       if
-               svnadmin -h >/dev/null 2>&1 &&
-               svnadmin create simple-svn &&
-               svnadmin load simple-svn <"$TEST_DIRECTORY/t9135/svn.dump" &&
-               svn export --config-dir "$svnconf" "file://$PWD/simple-svn" simple-svnco
-       then
-               test_set_prereq SVNREPO
-       fi
-'
-
-test_expect_success SVNREPO 't9135/svn.dump' '
-       mkdir -p simple-git &&
-       (
-               cd simple-git &&
-               reinit_git &&
-               try_dump "$TEST_DIRECTORY/t9135/svn.dump"
-       ) &&
-       (
-               cd simple-svnco &&
-               git init &&
-               git add . &&
-               git fetch ../simple-git master &&
-               git diff --exit-code FETCH_HEAD
-       )
-'
-
-test_done
diff --git a/t/t9011-svn-da.sh b/t/t9011-svn-da.sh
deleted file mode 100755 (executable)
index ab1ef28..0000000
+++ /dev/null
@@ -1,248 +0,0 @@
-#!/bin/sh
-
-test_description='test parsing of svndiff0 files
-
-Using the "test-svn-fe -d" helper, check that svn-fe correctly
-interprets deltas using various facilities (some from the spec,
-some only learned from practice).
-'
-. ./test-lib.sh
-
->empty
-printf foo >preimage
-
-test_expect_success 'reject empty delta' '
-       test_must_fail test-svn-fe -d preimage empty 0
-'
-
-test_expect_success 'delta can empty file' '
-       printf "SVNQ" | q_to_nul >clear.delta &&
-       test-svn-fe -d preimage clear.delta 4 >actual &&
-       test_must_be_empty actual
-'
-
-test_expect_success 'reject svndiff2' '
-       printf "SVN\002" >bad.filetype &&
-       test_must_fail test-svn-fe -d preimage bad.filetype 4
-'
-
-test_expect_success 'one-window empty delta' '
-       printf "SVNQ%s" "QQQQQ" | q_to_nul >clear.onewindow &&
-       test-svn-fe -d preimage clear.onewindow 9 >actual &&
-       test_must_be_empty actual
-'
-
-test_expect_success 'reject incomplete window header' '
-       printf "SVNQ%s" "QQQQQ" | q_to_nul >clear.onewindow &&
-       printf "SVNQ%s" "QQ" | q_to_nul >clear.partialwindow &&
-       test_must_fail test-svn-fe -d preimage clear.onewindow 6 &&
-       test_must_fail test-svn-fe -d preimage clear.partialwindow 6
-'
-
-test_expect_success 'reject declared delta longer than actual delta' '
-       printf "SVNQ%s" "QQQQQ" | q_to_nul >clear.onewindow &&
-       printf "SVNQ%s" "QQ" | q_to_nul >clear.partialwindow &&
-       test_must_fail test-svn-fe -d preimage clear.onewindow 14 &&
-       test_must_fail test-svn-fe -d preimage clear.partialwindow 9
-'
-
-test_expect_success 'two-window empty delta' '
-       printf "SVNQ%s%s" "QQQQQ" "QQQQQ" | q_to_nul >clear.twowindow &&
-       test-svn-fe -d preimage clear.twowindow 14 >actual &&
-       test_must_fail test-svn-fe -d preimage clear.twowindow 13 &&
-       test_must_be_empty actual
-'
-
-test_expect_success 'noisy zeroes' '
-       printf "SVNQ%s" \
-               "RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQ" |
-               tr R "\200" |
-               q_to_nul >clear.noisy &&
-       len=$(wc -c <clear.noisy) &&
-       test-svn-fe -d preimage clear.noisy $len &&
-       test_must_be_empty actual
-'
-
-test_expect_success 'reject variable-length int in magic' '
-       printf "SVNRQ" | tr R "\200" | q_to_nul >clear.badmagic &&
-       test_must_fail test-svn-fe -d preimage clear.badmagic 5
-'
-
-test_expect_success 'reject truncated integer' '
-       printf "SVNQ%s%s" "QQQQQ" "QQQQRRQ" |
-               tr R "\200" |
-               q_to_nul >clear.fullint &&
-       printf "SVNQ%s%s" "QQQQQ" "QQQQRR" |
-               tr RT "\201" |
-               q_to_nul >clear.partialint &&
-       test_must_fail test-svn-fe -d preimage clear.fullint 15 &&
-       test-svn-fe -d preimage clear.fullint 16 &&
-       test_must_fail test-svn-fe -d preimage clear.partialint 15
-'
-
-test_expect_success 'nonempty (but unused) preimage view' '
-       printf "SVNQ%b" "Q\003QQQ" | q_to_nul >clear.readpreimage &&
-       test-svn-fe -d preimage clear.readpreimage 9 >actual &&
-       test_must_be_empty actual
-'
-
-test_expect_success 'preimage view: right endpoint cannot backtrack' '
-       printf "SVNQ%b%b" "Q\003QQQ" "Q\002QQQ" |
-               q_to_nul >clear.backtrack &&
-       test_must_fail test-svn-fe -d preimage clear.backtrack 14
-'
-
-test_expect_success 'preimage view: left endpoint can advance' '
-       printf "SVNQ%b%b" "Q\003QQQ" "\001\002QQQ" |
-               q_to_nul >clear.preshrink &&
-       printf "SVNQ%b%b" "Q\003QQQ" "\001\001QQQ" |
-               q_to_nul >clear.shrinkbacktrack &&
-       test-svn-fe -d preimage clear.preshrink 14 >actual &&
-       test_must_fail test-svn-fe -d preimage clear.shrinkbacktrack 14 &&
-       test_must_be_empty actual
-'
-
-test_expect_success 'preimage view: offsets compared by value' '
-       printf "SVNQ%b%b" "\001\001QQQ" "\0200Q\003QQQ" |
-               q_to_nul >clear.noisybacktrack &&
-       printf "SVNQ%b%b" "\001\001QQQ" "\0200\001\002QQQ" |
-               q_to_nul >clear.noisyadvance &&
-       test_must_fail test-svn-fe -d preimage clear.noisybacktrack 15 &&
-       test-svn-fe -d preimage clear.noisyadvance 15 &&
-       test_must_be_empty actual
-'
-
-test_expect_success 'preimage view: reject truncated preimage' '
-       printf "SVNQ%b" "\010QQQQ" | q_to_nul >clear.lateemptyread &&
-       printf "SVNQ%b" "\010\001QQQ" | q_to_nul >clear.latenonemptyread &&
-       printf "SVNQ%b" "\001\010QQQ" | q_to_nul >clear.longread &&
-       test_must_fail test-svn-fe -d preimage clear.lateemptyread 9 &&
-       test_must_fail test-svn-fe -d preimage clear.latenonemptyread 9 &&
-       test_must_fail test-svn-fe -d preimage clear.longread 9
-'
-
-test_expect_success 'forbid unconsumed inline data' '
-       printf "SVNQ%b%s%b%s" "QQQQ\003" "bar" "QQQQ\001" "x" |
-               q_to_nul >inline.clear &&
-       test_must_fail test-svn-fe -d preimage inline.clear 18 >actual
-'
-
-test_expect_success 'reject truncated inline data' '
-       printf "SVNQ%b%s" "QQQQ\003" "b" | q_to_nul >inline.trunc &&
-       test_must_fail test-svn-fe -d preimage inline.trunc 10
-'
-
-test_expect_success 'reject truncated inline data (after instruction section)' '
-       printf "SVNQ%b%b%s" "QQ\001\001\003" "\0201" "b" | q_to_nul >insn.trunc &&
-       test_must_fail test-svn-fe -d preimage insn.trunc 11
-'
-
-test_expect_success 'copyfrom_data' '
-       echo hi >expect &&
-       printf "SVNQ%b%b%b" "QQ\003\001\003" "\0203" "hi\n" | q_to_nul >copydat &&
-       test-svn-fe -d preimage copydat 13 >actual &&
-       test_cmp expect actual
-'
-
-test_expect_success 'multiple copyfrom_data' '
-       echo hi >expect &&
-       printf "SVNQ%b%b%b%b%b" "QQ\003\002\003" "\0201\0202" "hi\n" \
-               "QQQ\002Q" "\0200Q" | q_to_nul >copy.multi &&
-       len=$(wc -c <copy.multi) &&
-       test-svn-fe -d preimage copy.multi $len >actual &&
-       test_cmp expect actual
-'
-
-test_expect_success 'incomplete multiple insn' '
-       printf "SVNQ%b%b%b" "QQ\003\002\003" "\0203\0200" "hi\n" |
-               q_to_nul >copy.partial &&
-       len=$(wc -c <copy.partial) &&
-       test_must_fail test-svn-fe -d preimage copy.partial $len
-'
-
-test_expect_success 'catch attempt to copy missing data' '
-       printf "SVNQ%b%b%s%b%s" "QQ\002\002\001" "\0201\0201" "X" \
-                       "QQQQ\002" "YZ" |
-               q_to_nul >copy.incomplete &&
-       len=$(wc -c <copy.incomplete) &&
-       test_must_fail test-svn-fe -d preimage copy.incomplete $len
-'
-
-test_expect_success 'copyfrom target to repeat data' '
-       printf foofoo >expect &&
-       printf "SVNQ%b%b%s" "QQ\006\004\003" "\0203\0100\003Q" "foo" |
-               q_to_nul >copytarget.repeat &&
-       len=$(wc -c <copytarget.repeat) &&
-       test-svn-fe -d preimage copytarget.repeat $len >actual &&
-       test_cmp expect actual
-'
-
-test_expect_success 'copyfrom target out of order' '
-       printf foooof >expect &&
-       printf "SVNQ%b%b%s" \
-               "QQ\006\007\003" "\0203\0101\002\0101\001\0101Q" "foo" |
-               q_to_nul >copytarget.reverse &&
-       len=$(wc -c <copytarget.reverse) &&
-       test-svn-fe -d preimage copytarget.reverse $len >actual &&
-       test_cmp expect actual
-'
-
-test_expect_success 'catch copyfrom future' '
-       printf "SVNQ%b%b%s" "QQ\004\004\003" "\0202\0101\002\0201" "XYZ" |
-               q_to_nul >copytarget.infuture &&
-       len=$(wc -c <copytarget.infuture) &&
-       test_must_fail test-svn-fe -d preimage copytarget.infuture $len
-'
-
-test_expect_success 'copy to sustain' '
-       printf XYXYXYXYXYXZ >expect &&
-       printf "SVNQ%b%b%s" "QQ\014\004\003" "\0202\0111Q\0201" "XYZ" |
-               q_to_nul >copytarget.sustain &&
-       len=$(wc -c <copytarget.sustain) &&
-       test-svn-fe -d preimage copytarget.sustain $len >actual &&
-       test_cmp expect actual
-'
-
-test_expect_success 'catch copy that overflows' '
-       printf "SVNQ%b%b%s" "QQ\003\003\001" "\0201\0177Q" X |
-               q_to_nul >copytarget.overflow &&
-       len=$(wc -c <copytarget.overflow) &&
-       test_must_fail test-svn-fe -d preimage copytarget.overflow $len
-'
-
-test_expect_success 'copyfrom source' '
-       printf foo >expect &&
-       printf "SVNQ%b%b" "Q\003\003\002Q" "\003Q" | q_to_nul >copysource.all &&
-       test-svn-fe -d preimage copysource.all 11 >actual &&
-       test_cmp expect actual
-'
-
-test_expect_success 'copy backwards' '
-       printf oof >expect &&
-       printf "SVNQ%b%b" "Q\003\003\006Q" "\001\002\001\001\001Q" |
-               q_to_nul >copysource.rev &&
-       test-svn-fe -d preimage copysource.rev 15 >actual &&
-       test_cmp expect actual
-'
-
-test_expect_success 'offsets are relative to window' '
-       printf fo >expect &&
-       printf "SVNQ%b%b%b%b" "Q\003\001\002Q" "\001Q" \
-               "\002\001\001\002Q" "\001Q" |
-               q_to_nul >copysource.two &&
-       test-svn-fe -d preimage copysource.two 18 >actual &&
-       test_cmp expect actual
-'
-
-test_expect_success 'example from notes/svndiff' '
-       printf aaaaccccdddddddd >expect &&
-       printf aaaabbbbcccc >source &&
-       printf "SVNQ%b%b%s" "Q\014\020\007\001" \
-               "\004Q\004\010\0201\0107\010" d |
-               q_to_nul >delta.example &&
-       len=$(wc -c <delta.example) &&
-       test-svn-fe -d source delta.example $len >actual &&
-       test_cmp expect actual
-'
-
-test_done
diff --git a/t/t9020-remote-svn.sh b/t/t9020-remote-svn.sh
deleted file mode 100755 (executable)
index 754c4a3..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-#!/bin/sh
-
-test_description='tests remote-svn'
-
-. ./test-lib.sh
-
-MARKSPATH=.git/info/fast-import/remote-svn
-
-if ! test_have_prereq PYTHON
-then
-       skip_all='skipping remote-svn tests, python not available'
-       test_done
-fi
-
-# Override svnrdump with our simulator
-PATH="$HOME:$PATH"
-export PATH PYTHON_PATH GIT_BUILD_DIR
-
-write_script "$HOME/svnrdump" <<\EOF
-exec "$PYTHON_PATH" "$GIT_BUILD_DIR/contrib/svn-fe/svnrdump_sim.py" "$@"
-EOF
-
-init_git () {
-       rm -fr .git &&
-       git init &&
-       #git remote add svnsim testsvn::sim:///$TEST_DIRECTORY/t9020/example.svnrdump
-       # let's reuse an existing dump file!?
-       git remote add svnsim "testsvn::sim://$TEST_DIRECTORY/t9154/svn.dump"
-       git remote add svnfile "testsvn::file://$TEST_DIRECTORY/t9154/svn.dump"
-}
-
-if test -e "$GIT_BUILD_DIR/git-remote-testsvn"
-then
-       test_set_prereq REMOTE_SVN
-fi
-
-test_debug '
-       git --version
-       type git
-       type svnrdump
-'
-
-test_expect_success REMOTE_SVN 'simple fetch' '
-       init_git &&
-       git fetch svnsim &&
-       test_cmp .git/refs/svn/svnsim/master .git/refs/remotes/svnsim/master  &&
-       cp .git/refs/remotes/svnsim/master master.good
-'
-
-test_debug '
-       git show-ref -s refs/svn/svnsim/master
-       git show-ref -s refs/remotes/svnsim/master
-'
-
-test_expect_success REMOTE_SVN 'repeated fetch, nothing shall change' '
-       git fetch svnsim &&
-       test_cmp master.good .git/refs/remotes/svnsim/master
-'
-
-test_expect_success REMOTE_SVN 'fetch from a file:// url gives the same result' '
-       git fetch svnfile
-'
-
-test_expect_failure REMOTE_SVN 'the sha1 differ because the git-svn-id line in the commit msg contains the url' '
-       test_cmp .git/refs/remotes/svnfile/master .git/refs/remotes/svnsim/master
-'
-
-test_expect_success REMOTE_SVN 'mark-file regeneration' '
-       # filter out any other marks, that can not be regenerated. Only up to 3 digit revisions are allowed here
-       grep ":[0-9]\{1,3\} " $MARKSPATH/svnsim.marks > $MARKSPATH/svnsim.marks.old &&
-       rm $MARKSPATH/svnsim.marks &&
-       git fetch svnsim &&
-       test_cmp $MARKSPATH/svnsim.marks.old $MARKSPATH/svnsim.marks
-'
-
-test_expect_success REMOTE_SVN 'incremental imports must lead to the same head' '
-       SVNRMAX=3 &&
-       export SVNRMAX &&
-       init_git &&
-       git fetch svnsim &&
-       test_cmp .git/refs/svn/svnsim/master .git/refs/remotes/svnsim/master  &&
-       unset SVNRMAX &&
-       git fetch svnsim &&
-       test_cmp master.good .git/refs/remotes/svnsim/master
-'
-
-test_expect_success REMOTE_SVN 'respects configured default initial branch' '
-       git -c init.defaultBranch=trunk remote add -f trunk \
-               "testsvn::file://$TEST_DIRECTORY/t9154/svn.dump" &&
-       git rev-parse --verify refs/remotes/trunk/trunk
-'
-
-test_debug 'git branch -a'
-
-test_done
index 6a8e194a99088f13e1c5a449686804a7a6611d99..f9904066feed6d609d8d568dbd16080957ed7aa3 100644 (file)
@@ -820,7 +820,7 @@ test_must_fail_acceptable () {
        fi
 
        case "$1" in
-       git|__git*|test-tool|test-svn-fe|test_terminal)
+       git|__git*|test-tool|test_terminal)
                return 0
                ;;
        *)
index 0c414f2fed2b5701f616eb2d88a386e5da16fda8..68dabc2556c8232e1df268ae9f82d539505541ef 100644 (file)
--- a/trailer.c
+++ b/trailer.c
@@ -221,15 +221,13 @@ static char *apply_command(const char *command, const char *arg)
        struct strbuf cmd = STRBUF_INIT;
        struct strbuf buf = STRBUF_INIT;
        struct child_process cp = CHILD_PROCESS_INIT;
-       const char *argv[] = {NULL, NULL};
        char *result;
 
        strbuf_addstr(&cmd, command);
        if (arg)
                strbuf_replace(&cmd, TRAILER_ARG_STRING, arg);
 
-       argv[0] = cmd.buf;
-       cp.argv = argv;
+       strvec_push(&cp.args, cmd.buf);
        cp.env = local_repo_env;
        cp.no_stdin = 1;
        cp.use_shell = 1;
index defafbf4c1bc6788c4f7b9692cdcfcda1181116b..c52c99d829d739047b867d2f431ab9eda48cb9dc 100644 (file)
@@ -128,10 +128,10 @@ static struct child_process *get_helper(struct transport *transport)
        helper->in = -1;
        helper->out = -1;
        helper->err = 0;
-       strvec_pushf(&helper->args, "git-remote-%s", data->name);
+       strvec_pushf(&helper->args, "remote-%s", data->name);
        strvec_push(&helper->args, transport->remote->name);
        strvec_push(&helper->args, remove_ext_force(transport->url));
-       helper->git_cmd = 0;
+       helper->git_cmd = 1;
        helper->silent_exec_failure = 1;
 
        if (have_git_dir())
index 2d4fd851dc0f8f317e3925e84d2567ff7467fc7f..43e24bf1e539db89fcbc8b5b778558054ea8674f 100644 (file)
@@ -232,9 +232,6 @@ static int set_git_option(struct git_transport_options *opts,
        } else if (!strcmp(name, TRANS_OPT_FROM_PROMISOR)) {
                opts->from_promisor = !!value;
                return 0;
-       } else if (!strcmp(name, TRANS_OPT_NO_DEPENDENTS)) {
-               opts->no_dependents = !!value;
-               return 0;
        } else if (!strcmp(name, TRANS_OPT_LIST_OBJECTS_FILTER)) {
                list_objects_filter_die_if_populated(&opts->filter_options);
                parse_list_objects_filter(&opts->filter_options, value);
@@ -359,7 +356,6 @@ static int fetch_refs_via_pack(struct transport *transport,
        args.cloning = transport->cloning;
        args.update_shallow = data->options.update_shallow;
        args.from_promisor = data->options.from_promisor;
-       args.no_dependents = data->options.no_dependents;
        args.filter_options = data->options.filter_options;
        args.stateless_rpc = transport->stateless_rpc;
        args.server_options = transport->server_options;
@@ -443,6 +439,7 @@ void transport_update_tracking_ref(struct remote *remote, struct ref *ref, int v
        if (ref->status != REF_STATUS_OK && ref->status != REF_STATUS_UPTODATE)
                return;
 
+       memset(&rs, 0, sizeof(rs));
        rs.src = ref->name;
        rs.dst = NULL;
 
index 1be4013dec4fa7f8a7f17321f4e16de47e4e1137..ca409ea1e407c1c67e70e764e734946f7e22372e 100644 (file)
@@ -15,8 +15,9 @@ struct git_transport_options {
        unsigned self_contained_and_connected : 1;
        unsigned update_shallow : 1;
        unsigned deepen_relative : 1;
+
+       /* see documentation of corresponding flag in fetch-pack.h */
        unsigned from_promisor : 1;
-       unsigned no_dependents : 1;
 
        /*
         * If this transport supports connect or stateless-connect,
@@ -201,12 +202,6 @@ void transport_check_allowed(const char *type);
 /* Indicate that these objects are being fetched by a promisor */
 #define TRANS_OPT_FROM_PROMISOR "from-promisor"
 
-/*
- * Indicate that only the objects wanted need to be fetched, not their
- * dependents
- */
-#define TRANS_OPT_NO_DEPENDENTS "no-dependents"
-
 /* Filter objects for partial clone and fetch */
 #define TRANS_OPT_LIST_OBJECTS_FILTER "filter"
 
diff --git a/vcs-svn/LICENSE b/vcs-svn/LICENSE
deleted file mode 100644 (file)
index eb91858..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-Copyright (C) 2010 David Barr <david.barr@cordelta.com>.
-All rights reserved.
-
-Copyright (C) 2010 Jonathan Nieder <jrnieder@gmail.com>.
-
-Copyright (C) 2005 Stefan Hegny, hydrografix Consulting GmbH,
-Frankfurt/Main, Germany
-and others, see http://svn2cc.sarovar.org
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice(s), this list of conditions and the following disclaimer
-   unmodified other than the allowable addition of one or more
-   copyright notices.
-2. Redistributions in binary form must reproduce the above copyright
-   notice(s), this list of conditions and the following disclaimer in
-   the documentation and/or other materials provided with the
-   distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
-EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
-OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
-EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c
deleted file mode 100644 (file)
index b5b8913..0000000
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
- * Licensed under a two-clause BSD-style license.
- * See LICENSE for details.
- */
-
-#include "cache.h"
-#include "quote.h"
-#include "fast_export.h"
-#include "strbuf.h"
-#include "svndiff.h"
-#include "sliding_window.h"
-#include "line_buffer.h"
-
-#define MAX_GITSVN_LINE_LEN 4096
-
-static uint32_t first_commit_done;
-static struct line_buffer postimage = LINE_BUFFER_INIT;
-static struct line_buffer report_buffer = LINE_BUFFER_INIT;
-
-/* NEEDSWORK: move to fast_export_init() */
-static int init_postimage(void)
-{
-       static int postimage_initialized;
-       if (postimage_initialized)
-               return 0;
-       postimage_initialized = 1;
-       return buffer_tmpfile_init(&postimage);
-}
-
-void fast_export_init(int fd)
-{
-       first_commit_done = 0;
-       if (buffer_fdinit(&report_buffer, fd))
-               die_errno("cannot read from file descriptor %d", fd);
-}
-
-void fast_export_deinit(void)
-{
-       if (buffer_deinit(&report_buffer))
-               die_errno("error closing fast-import feedback stream");
-}
-
-void fast_export_delete(const char *path)
-{
-       putchar('D');
-       putchar(' ');
-       quote_c_style(path, NULL, stdout, 0);
-       putchar('\n');
-}
-
-static void fast_export_truncate(const char *path, uint32_t mode)
-{
-       fast_export_modify(path, mode, "inline");
-       printf("data 0\n\n");
-}
-
-void fast_export_modify(const char *path, uint32_t mode, const char *dataref)
-{
-       /* Mode must be 100644, 100755, 120000, or 160000. */
-       if (!dataref) {
-               fast_export_truncate(path, mode);
-               return;
-       }
-       printf("M %06"PRIo32" %s ", mode, dataref);
-       quote_c_style(path, NULL, stdout, 0);
-       putchar('\n');
-}
-
-void fast_export_begin_note(uint32_t revision, const char *author,
-               const char *log, timestamp_t timestamp, const char *note_ref)
-{
-       static int firstnote = 1;
-       size_t loglen = strlen(log);
-       printf("commit %s\n", note_ref);
-       printf("committer %s <%s@%s> %"PRItime" +0000\n", author, author, "local", timestamp);
-       printf("data %"PRIuMAX"\n", (uintmax_t)loglen);
-       fwrite(log, loglen, 1, stdout);
-       if (firstnote) {
-               if (revision > 1)
-                       printf("from %s^0", note_ref);
-               firstnote = 0;
-       }
-       fputc('\n', stdout);
-}
-
-void fast_export_note(const char *committish, const char *dataref)
-{
-       printf("N %s %s\n", dataref, committish);
-}
-
-static char gitsvnline[MAX_GITSVN_LINE_LEN];
-void fast_export_begin_commit(uint32_t revision, const char *author,
-                       const struct strbuf *log,
-                       const char *uuid, const char *url,
-                       timestamp_t timestamp, const char *local_ref)
-{
-       static const struct strbuf empty = STRBUF_INIT;
-       if (!log)
-               log = &empty;
-       if (*uuid && *url) {
-               snprintf(gitsvnline, MAX_GITSVN_LINE_LEN,
-                               "\n\ngit-svn-id: %s@%"PRIu32" %s\n",
-                                url, revision, uuid);
-       } else {
-               *gitsvnline = '\0';
-       }
-       printf("commit %s\n", local_ref);
-       printf("mark :%"PRIu32"\n", revision);
-       printf("committer %s <%s@%s> %"PRItime" +0000\n",
-                  *author ? author : "nobody",
-                  *author ? author : "nobody",
-                  *uuid ? uuid : "local", timestamp);
-       printf("data %"PRIuMAX"\n",
-               (uintmax_t) (log->len + strlen(gitsvnline)));
-       fwrite(log->buf, log->len, 1, stdout);
-       printf("%s\n", gitsvnline);
-       if (!first_commit_done) {
-               if (revision > 1)
-                       printf("from :%"PRIu32"\n", revision - 1);
-               first_commit_done = 1;
-       }
-}
-
-void fast_export_end_commit(uint32_t revision)
-{
-       printf("progress Imported commit %"PRIu32".\n\n", revision);
-}
-
-static void ls_from_rev(uint32_t rev, const char *path)
-{
-       /* ls :5 path/to/old/file */
-       printf("ls :%"PRIu32" ", rev);
-       quote_c_style(path, NULL, stdout, 0);
-       putchar('\n');
-       fflush(stdout);
-}
-
-static void ls_from_active_commit(const char *path)
-{
-       /* ls "path/to/file" */
-       printf("ls \"");
-       quote_c_style(path, NULL, stdout, 1);
-       printf("\"\n");
-       fflush(stdout);
-}
-
-static const char *get_response_line(void)
-{
-       const char *line = buffer_read_line(&report_buffer);
-       if (line)
-               return line;
-       if (buffer_ferror(&report_buffer))
-               die_errno("error reading from fast-import");
-       die("unexpected end of fast-import feedback");
-}
-
-static void die_short_read(struct line_buffer *input)
-{
-       if (buffer_ferror(input))
-               die_errno("error reading dump file");
-       die("invalid dump: unexpected end of file");
-}
-
-static int parse_cat_response_line(const char *header, off_t *len)
-{
-       uintmax_t n;
-       const char *type;
-       const char *end;
-
-       if (ends_with(header, " missing"))
-               return error("cat-blob reports missing blob: %s", header);
-       type = strstr(header, " blob ");
-       if (!type)
-               return error("cat-blob header has wrong object type: %s", header);
-       n = strtoumax(type + strlen(" blob "), (char **) &end, 10);
-       if (end == type + strlen(" blob "))
-               return error("cat-blob header does not contain length: %s", header);
-       if (memchr(type + strlen(" blob "), '-', end - type - strlen(" blob ")))
-               return error("cat-blob header contains negative length: %s", header);
-       if (n == UINTMAX_MAX || n > maximum_signed_value_of_type(off_t))
-               return error("blob too large for current definition of off_t");
-       *len = n;
-       if (*end)
-               return error("cat-blob header contains garbage after length: %s", header);
-       return 0;
-}
-
-static void check_preimage_overflow(off_t a, off_t b)
-{
-       if (signed_add_overflows(a, b))
-               die("blob too large for current definition of off_t");
-}
-
-static long apply_delta(off_t len, struct line_buffer *input,
-                       const char *old_data, uint32_t old_mode)
-{
-       long ret;
-       struct sliding_view preimage = SLIDING_VIEW_INIT(&report_buffer, 0);
-       FILE *out;
-
-       if (init_postimage() || !(out = buffer_tmpfile_rewind(&postimage)))
-               die("cannot open temporary file for blob retrieval");
-       if (old_data) {
-               const char *response;
-               printf("cat-blob %s\n", old_data);
-               fflush(stdout);
-               response = get_response_line();
-               if (parse_cat_response_line(response, &preimage.max_off))
-                       die("invalid cat-blob response: %s", response);
-               check_preimage_overflow(preimage.max_off, 1);
-       }
-       if (old_mode == S_IFLNK) {
-               strbuf_addstr(&preimage.buf, "link ");
-               check_preimage_overflow(preimage.max_off, strlen("link "));
-               preimage.max_off += strlen("link ");
-               check_preimage_overflow(preimage.max_off, 1);
-       }
-       if (svndiff0_apply(input, len, &preimage, out))
-               die("cannot apply delta");
-       if (old_data) {
-               /* Read the remainder of preimage and trailing newline. */
-               assert(!signed_add_overflows(preimage.max_off, 1));
-               preimage.max_off++;     /* room for newline */
-               if (move_window(&preimage, preimage.max_off - 1, 1))
-                       die("cannot seek to end of input");
-               if (preimage.buf.buf[0] != '\n')
-                       die("missing newline after cat-blob response");
-       }
-       ret = buffer_tmpfile_prepare_to_read(&postimage);
-       if (ret < 0)
-               die("cannot read temporary file for blob retrieval");
-       strbuf_release(&preimage.buf);
-       return ret;
-}
-
-void fast_export_buf_to_data(const struct strbuf *data)
-{
-       printf("data %"PRIuMAX"\n", (uintmax_t)data->len);
-       fwrite(data->buf, data->len, 1, stdout);
-       fputc('\n', stdout);
-}
-
-void fast_export_data(uint32_t mode, off_t len, struct line_buffer *input)
-{
-       assert(len >= 0);
-       if (mode == S_IFLNK) {
-               /* svn symlink blobs start with "link " */
-               if (len < 5)
-                       die("invalid dump: symlink too short for \"link\" prefix");
-               len -= 5;
-               if (buffer_skip_bytes(input, 5) != 5)
-                       die_short_read(input);
-       }
-       printf("data %"PRIuMAX"\n", (uintmax_t) len);
-       if (buffer_copy_bytes(input, len) != len)
-               die_short_read(input);
-       fputc('\n', stdout);
-}
-
-static int parse_ls_response(const char *response, uint32_t *mode,
-                                       struct strbuf *dataref)
-{
-       const char *tab;
-       const char *response_end;
-
-       assert(response);
-       response_end = response + strlen(response);
-
-       if (*response == 'm') { /* Missing. */
-               errno = ENOENT;
-               return -1;
-       }
-
-       /* Mode. */
-       if (response_end - response < (signed) strlen("100644") ||
-           response[strlen("100644")] != ' ')
-               die("invalid ls response: missing mode: %s", response);
-       *mode = 0;
-       for (; *response != ' '; response++) {
-               char ch = *response;
-               if (ch < '0' || ch > '7')
-                       die("invalid ls response: mode is not octal: %s", response);
-               *mode *= 8;
-               *mode += ch - '0';
-       }
-
-       /* ' blob ' or ' tree ' */
-       if (response_end - response < (signed) strlen(" blob ") ||
-           (response[1] != 'b' && response[1] != 't'))
-               die("unexpected ls response: not a tree or blob: %s", response);
-       response += strlen(" blob ");
-
-       /* Dataref. */
-       tab = memchr(response, '\t', response_end - response);
-       if (!tab)
-               die("invalid ls response: missing tab: %s", response);
-       strbuf_add(dataref, response, tab - response);
-       return 0;
-}
-
-int fast_export_ls_rev(uint32_t rev, const char *path,
-                               uint32_t *mode, struct strbuf *dataref)
-{
-       ls_from_rev(rev, path);
-       return parse_ls_response(get_response_line(), mode, dataref);
-}
-
-int fast_export_ls(const char *path, uint32_t *mode, struct strbuf *dataref)
-{
-       ls_from_active_commit(path);
-       return parse_ls_response(get_response_line(), mode, dataref);
-}
-
-const char *fast_export_read_path(const char *path, uint32_t *mode_out)
-{
-       int err;
-       static struct strbuf buf = STRBUF_INIT;
-
-       strbuf_reset(&buf);
-       err = fast_export_ls(path, mode_out, &buf);
-       if (err) {
-               if (errno != ENOENT)
-                       BUG("unexpected fast_export_ls error: %s",
-                           strerror(errno));
-               /* Treat missing paths as directories. */
-               *mode_out = S_IFDIR;
-               return NULL;
-       }
-       return buf.buf;
-}
-
-void fast_export_copy(uint32_t revision, const char *src, const char *dst)
-{
-       int err;
-       uint32_t mode;
-       static struct strbuf data = STRBUF_INIT;
-
-       strbuf_reset(&data);
-       err = fast_export_ls_rev(revision, src, &mode, &data);
-       if (err) {
-               if (errno != ENOENT)
-                       BUG("unexpected fast_export_ls_rev error: %s",
-                           strerror(errno));
-               fast_export_delete(dst);
-               return;
-       }
-       fast_export_modify(dst, mode, data.buf);
-}
-
-void fast_export_blob_delta(uint32_t mode,
-                               uint32_t old_mode, const char *old_data,
-                               off_t len, struct line_buffer *input)
-{
-       long postimage_len;
-
-       assert(len >= 0);
-       postimage_len = apply_delta(len, input, old_data, old_mode);
-       if (mode == S_IFLNK) {
-               buffer_skip_bytes(&postimage, strlen("link "));
-               postimage_len -= strlen("link ");
-       }
-       printf("data %ld\n", postimage_len);
-       buffer_copy_bytes(&postimage, postimage_len);
-       fputc('\n', stdout);
-}
diff --git a/vcs-svn/line_buffer.c b/vcs-svn/line_buffer.c
deleted file mode 100644 (file)
index e416caf..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Licensed under a two-clause BSD-style license.
- * See LICENSE for details.
- */
-
-#include "git-compat-util.h"
-#include "line_buffer.h"
-#include "strbuf.h"
-
-#define COPY_BUFFER_LEN 4096
-
-int buffer_init(struct line_buffer *buf, const char *filename)
-{
-       buf->infile = filename ? fopen(filename, "r") : stdin;
-       if (!buf->infile)
-               return -1;
-       return 0;
-}
-
-int buffer_fdinit(struct line_buffer *buf, int fd)
-{
-       buf->infile = fdopen(fd, "r");
-       if (!buf->infile)
-               return -1;
-       return 0;
-}
-
-int buffer_tmpfile_init(struct line_buffer *buf)
-{
-       buf->infile = tmpfile();
-       if (!buf->infile)
-               return -1;
-       return 0;
-}
-
-int buffer_deinit(struct line_buffer *buf)
-{
-       int err;
-       if (buf->infile == stdin)
-               return ferror(buf->infile);
-       err = ferror(buf->infile);
-       err |= fclose(buf->infile);
-       return err;
-}
-
-FILE *buffer_tmpfile_rewind(struct line_buffer *buf)
-{
-       rewind(buf->infile);
-       return buf->infile;
-}
-
-long buffer_tmpfile_prepare_to_read(struct line_buffer *buf)
-{
-       long pos = ftell(buf->infile);
-       if (pos < 0)
-               return error_errno("ftell error");
-       if (fseek(buf->infile, 0, SEEK_SET))
-               return error_errno("seek error");
-       return pos;
-}
-
-int buffer_ferror(struct line_buffer *buf)
-{
-       return ferror(buf->infile);
-}
-
-int buffer_read_char(struct line_buffer *buf)
-{
-       return fgetc(buf->infile);
-}
-
-/* Read a line without trailing newline. */
-char *buffer_read_line(struct line_buffer *buf)
-{
-       char *end;
-       if (!fgets(buf->line_buffer, sizeof(buf->line_buffer), buf->infile))
-               /* Error or data exhausted. */
-               return NULL;
-       end = buf->line_buffer + strlen(buf->line_buffer);
-       if (end[-1] == '\n')
-               end[-1] = '\0';
-       else if (feof(buf->infile))
-               ; /* No newline at end of file.  That's fine. */
-       else
-               /*
-                * Line was too long.
-                * There is probably a saner way to deal with this,
-                * but for now let's return an error.
-                */
-               return NULL;
-       return buf->line_buffer;
-}
-
-size_t buffer_read_binary(struct line_buffer *buf,
-                               struct strbuf *sb, size_t size)
-{
-       return strbuf_fread(sb, size, buf->infile);
-}
-
-off_t buffer_copy_bytes(struct line_buffer *buf, off_t nbytes)
-{
-       char byte_buffer[COPY_BUFFER_LEN];
-       off_t done = 0;
-       while (done < nbytes && !feof(buf->infile) && !ferror(buf->infile)) {
-               off_t len = nbytes - done;
-               size_t in = len < COPY_BUFFER_LEN ? len : COPY_BUFFER_LEN;
-               in = fread(byte_buffer, 1, in, buf->infile);
-               done += in;
-               fwrite(byte_buffer, 1, in, stdout);
-               if (ferror(stdout))
-                       return done + buffer_skip_bytes(buf, nbytes - done);
-       }
-       return done;
-}
-
-off_t buffer_skip_bytes(struct line_buffer *buf, off_t nbytes)
-{
-       char byte_buffer[COPY_BUFFER_LEN];
-       off_t done = 0;
-       while (done < nbytes && !feof(buf->infile) && !ferror(buf->infile)) {
-               off_t len = nbytes - done;
-               size_t in = len < COPY_BUFFER_LEN ? len : COPY_BUFFER_LEN;
-               done += fread(byte_buffer, 1, in, buf->infile);
-       }
-       return done;
-}
diff --git a/vcs-svn/line_buffer.txt b/vcs-svn/line_buffer.txt
deleted file mode 100644 (file)
index 8e139eb..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-line_buffer API
-===============
-
-The line_buffer library provides a convenient interface for
-mostly-line-oriented input.
-
-Each line is not permitted to exceed 10000 bytes.  The provided
-functions are not thread-safe or async-signal-safe, and like
-`fgets()`, they generally do not function correctly if interrupted
-by a signal without SA_RESTART set.
-
-Calling sequence
-----------------
-
-The calling program:
-
- - initializes a `struct line_buffer` to LINE_BUFFER_INIT
- - specifies a file to read with `buffer_init`
- - processes input with `buffer_read_line`, `buffer_skip_bytes`,
-   and `buffer_copy_bytes`
- - closes the file with `buffer_deinit`, perhaps to start over and
-   read another file.
-
-When finished, the caller can use `buffer_reset` to deallocate
-resources.
-
-Using temporary files
----------------------
-
-Temporary files provide a place to store data that should not outlive
-the calling program.  A program
-
- - initializes a `struct line_buffer` to LINE_BUFFER_INIT
- - requests a temporary file with `buffer_tmpfile_init`
- - acquires an output handle by calling `buffer_tmpfile_rewind`
- - uses standard I/O functions like `fprintf` and `fwrite` to fill
-   the temporary file
- - declares writing is over with `buffer_tmpfile_prepare_to_read`
- - can re-read what was written with `buffer_read_line`,
-   `buffer_copy_bytes`, and so on
- - can reuse the temporary file by calling `buffer_tmpfile_rewind`
-   again
- - removes the temporary file with `buffer_deinit`, perhaps to
-   reuse the line_buffer for some other file.
-
-When finished, the calling program can use `buffer_reset` to deallocate
-resources.
-
-Functions
----------
-
-`buffer_init`, `buffer_fdinit`::
-       Open the named file or file descriptor for input.
-       buffer_init(buf, NULL) prepares to read from stdin.
-       On failure, returns -1 (with errno indicating the nature
-       of the failure).
-
-`buffer_deinit`::
-       Stop reading from the current file (closing it unless
-       it was stdin).  Returns nonzero if `fclose` fails or
-       the error indicator was set.
-
-`buffer_read_line`::
-       Read a line and strip off the trailing newline.
-       On failure or end of file, returns NULL.
-
-`buffer_copy_bytes`::
-       Read `len` bytes of input and dump them to the standard output
-       stream.  Returns early for error or end of file.
-
-`buffer_skip_bytes`::
-       Discards `len` bytes from the input stream (stopping early
-       if necessary because of an error or eof).  Return value is
-       the number of bytes successfully read.
-
-`buffer_reset`::
-       Deallocates non-static buffers.
diff --git a/vcs-svn/sliding_window.c b/vcs-svn/sliding_window.c
deleted file mode 100644 (file)
index 06d273c..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Licensed under a two-clause BSD-style license.
- * See LICENSE for details.
- */
-
-#include "git-compat-util.h"
-#include "sliding_window.h"
-#include "line_buffer.h"
-#include "strbuf.h"
-
-static int input_error(struct line_buffer *file)
-{
-       if (!buffer_ferror(file))
-               return error("delta preimage ends early");
-       return error_errno("cannot read delta preimage");
-}
-
-static int skip_or_whine(struct line_buffer *file, off_t gap)
-{
-       if (buffer_skip_bytes(file, gap) != gap)
-               return input_error(file);
-       return 0;
-}
-
-static int read_to_fill_or_whine(struct line_buffer *file,
-                               struct strbuf *buf, size_t width)
-{
-       buffer_read_binary(file, buf, width - buf->len);
-       if (buf->len != width)
-               return input_error(file);
-       return 0;
-}
-
-static int check_offset_overflow(off_t offset, uintmax_t len)
-{
-       if (len > maximum_signed_value_of_type(off_t))
-               return error("unrepresentable length in delta: "
-                               "%"PRIuMAX" > OFF_MAX", len);
-       if (signed_add_overflows(offset, (off_t) len))
-               return error("unrepresentable offset in delta: "
-                               "%"PRIuMAX" + %"PRIuMAX" > OFF_MAX",
-                               (uintmax_t) offset, len);
-       return 0;
-}
-
-int move_window(struct sliding_view *view, off_t off, size_t width)
-{
-       off_t file_offset;
-       assert(view);
-       assert(view->width <= view->buf.len);
-       assert(!check_offset_overflow(view->off, view->buf.len));
-
-       if (check_offset_overflow(off, width))
-               return -1;
-       if (off < view->off || off + width < view->off + view->width)
-               return error("invalid delta: window slides left");
-       if (view->max_off >= 0 && view->max_off < off + (off_t) width)
-               return error("delta preimage ends early");
-
-       file_offset = view->off + view->buf.len;
-       if (off < file_offset) {
-               /* Move the overlapping region into place. */
-               strbuf_remove(&view->buf, 0, off - view->off);
-       } else {
-               /* Seek ahead to skip the gap. */
-               if (skip_or_whine(view->file, off - file_offset))
-                       return -1;
-               strbuf_setlen(&view->buf, 0);
-       }
-
-       if (view->buf.len > width)
-               ; /* Already read. */
-       else if (read_to_fill_or_whine(view->file, &view->buf, width))
-               return -1;
-
-       view->off = off;
-       view->width = width;
-       return 0;
-}
diff --git a/vcs-svn/svndiff.c b/vcs-svn/svndiff.c
deleted file mode 100644 (file)
index 75c7531..0000000
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * Licensed under a two-clause BSD-style license.
- * See LICENSE for details.
- */
-
-#include "git-compat-util.h"
-#include "sliding_window.h"
-#include "line_buffer.h"
-#include "svndiff.h"
-
-/*
- * svndiff0 applier
- *
- * See http://svn.apache.org/repos/asf/subversion/trunk/notes/svndiff.
- *
- * svndiff0 ::= 'SVN\0' window*
- * window ::= int int int int int instructions inline_data;
- * instructions ::= instruction*;
- * instruction ::= view_selector int int
- *   | copyfrom_data int
- *   | packed_view_selector int
- *   | packed_copyfrom_data
- *   ;
- * view_selector ::= copyfrom_source
- *   | copyfrom_target
- *   ;
- * copyfrom_source ::= # binary 00 000000;
- * copyfrom_target ::= # binary 01 000000;
- * copyfrom_data ::= # binary 10 000000;
- * packed_view_selector ::= # view_selector OR-ed with 6 bit value;
- * packed_copyfrom_data ::= # copyfrom_data OR-ed with 6 bit value;
- * int ::= highdigit* lowdigit;
- * highdigit ::= # binary 1000 0000 OR-ed with 7 bit value;
- * lowdigit ::= # 7 bit value;
- */
-
-#define INSN_MASK      0xc0
-#define INSN_COPYFROM_SOURCE   0x00
-#define INSN_COPYFROM_TARGET   0x40
-#define INSN_COPYFROM_DATA     0x80
-#define OPERAND_MASK   0x3f
-
-#define VLI_CONTINUE   0x80
-#define VLI_DIGIT_MASK 0x7f
-#define VLI_BITS_PER_DIGIT 7
-
-struct window {
-       struct sliding_view *in;
-       struct strbuf out;
-       struct strbuf instructions;
-       struct strbuf data;
-};
-
-#define WINDOW_INIT(w) { (w), STRBUF_INIT, STRBUF_INIT, STRBUF_INIT }
-
-static void window_release(struct window *ctx)
-{
-       strbuf_release(&ctx->out);
-       strbuf_release(&ctx->instructions);
-       strbuf_release(&ctx->data);
-}
-
-static int write_strbuf(struct strbuf *sb, FILE *out)
-{
-       if (fwrite(sb->buf, 1, sb->len, out) == sb->len)        /* Success. */
-               return 0;
-       return error_errno("cannot write delta postimage");
-}
-
-static int error_short_read(struct line_buffer *input)
-{
-       if (buffer_ferror(input))
-               return error_errno("error reading delta");
-       return error("invalid delta: unexpected end of file");
-}
-
-static int read_chunk(struct line_buffer *delta, off_t *delta_len,
-                     struct strbuf *buf, size_t len)
-{
-       assert(*delta_len >= 0);
-       strbuf_reset(buf);
-       if (len > (uintmax_t) *delta_len ||
-           buffer_read_binary(delta, buf, len) != len)
-               return error_short_read(delta);
-       *delta_len -= buf->len;
-       return 0;
-}
-
-static int read_magic(struct line_buffer *in, off_t *len)
-{
-       static const char magic[] = {'S', 'V', 'N', '\0'};
-       struct strbuf sb = STRBUF_INIT;
-
-       if (read_chunk(in, len, &sb, sizeof(magic))) {
-               strbuf_release(&sb);
-               return -1;
-       }
-       if (memcmp(sb.buf, magic, sizeof(magic))) {
-               strbuf_release(&sb);
-               return error("invalid delta: unrecognized file type");
-       }
-       strbuf_release(&sb);
-       return 0;
-}
-
-static int read_int(struct line_buffer *in, uintmax_t *result, off_t *len)
-{
-       uintmax_t rv = 0;
-       off_t sz;
-       for (sz = *len; sz; sz--) {
-               const int ch = buffer_read_char(in);
-               if (ch == EOF)
-                       break;
-
-               rv <<= VLI_BITS_PER_DIGIT;
-               rv += (ch & VLI_DIGIT_MASK);
-               if (ch & VLI_CONTINUE)
-                       continue;
-
-               *result = rv;
-               *len = sz - 1;
-               return 0;
-       }
-       return error_short_read(in);
-}
-
-static int parse_int(const char **buf, size_t *result, const char *end)
-{
-       size_t rv = 0;
-       const char *pos;
-       for (pos = *buf; pos != end; pos++) {
-               unsigned char ch = *pos;
-
-               rv <<= VLI_BITS_PER_DIGIT;
-               rv += (ch & VLI_DIGIT_MASK);
-               if (ch & VLI_CONTINUE)
-                       continue;
-
-               *result = rv;
-               *buf = pos + 1;
-               return 0;
-       }
-       return error("invalid delta: unexpected end of instructions section");
-}
-
-static int read_offset(struct line_buffer *in, off_t *result, off_t *len)
-{
-       uintmax_t val;
-       if (read_int(in, &val, len))
-               return -1;
-       if (val > maximum_signed_value_of_type(off_t))
-               return error("unrepresentable offset in delta: %"PRIuMAX"", val);
-       *result = val;
-       return 0;
-}
-
-static int read_length(struct line_buffer *in, size_t *result, off_t *len)
-{
-       uintmax_t val;
-       if (read_int(in, &val, len))
-               return -1;
-       if (val > SIZE_MAX)
-               return error("unrepresentable length in delta: %"PRIuMAX"", val);
-       *result = val;
-       return 0;
-}
-
-static int copyfrom_source(struct window *ctx, const char **instructions,
-                          size_t nbytes, const char *insns_end)
-{
-       size_t offset;
-       if (parse_int(instructions, &offset, insns_end))
-               return -1;
-       if (unsigned_add_overflows(offset, nbytes) ||
-           offset + nbytes > ctx->in->width)
-               return error("invalid delta: copies source data outside view");
-       strbuf_add(&ctx->out, ctx->in->buf.buf + offset, nbytes);
-       return 0;
-}
-
-static int copyfrom_target(struct window *ctx, const char **instructions,
-                          size_t nbytes, const char *instructions_end)
-{
-       size_t offset;
-       if (parse_int(instructions, &offset, instructions_end))
-               return -1;
-       if (offset >= ctx->out.len)
-               return error("invalid delta: copies from the future");
-       for (; nbytes > 0; nbytes--)
-               strbuf_addch(&ctx->out, ctx->out.buf[offset++]);
-       return 0;
-}
-
-static int copyfrom_data(struct window *ctx, size_t *data_pos, size_t nbytes)
-{
-       const size_t pos = *data_pos;
-       if (unsigned_add_overflows(pos, nbytes) ||
-           pos + nbytes > ctx->data.len)
-               return error("invalid delta: copies unavailable inline data");
-       strbuf_add(&ctx->out, ctx->data.buf + pos, nbytes);
-       *data_pos += nbytes;
-       return 0;
-}
-
-static int parse_first_operand(const char **buf, size_t *out, const char *end)
-{
-       size_t result = (unsigned char) *(*buf)++ & OPERAND_MASK;
-       if (result) {   /* immediate operand */
-               *out = result;
-               return 0;
-       }
-       return parse_int(buf, out, end);
-}
-
-static int execute_one_instruction(struct window *ctx,
-                               const char **instructions, size_t *data_pos)
-{
-       unsigned int instruction;
-       const char *insns_end = ctx->instructions.buf + ctx->instructions.len;
-       size_t nbytes;
-       assert(ctx);
-       assert(instructions && *instructions);
-       assert(data_pos);
-
-       instruction = (unsigned char) **instructions;
-       if (parse_first_operand(instructions, &nbytes, insns_end))
-               return -1;
-       switch (instruction & INSN_MASK) {
-       case INSN_COPYFROM_SOURCE:
-               return copyfrom_source(ctx, instructions, nbytes, insns_end);
-       case INSN_COPYFROM_TARGET:
-               return copyfrom_target(ctx, instructions, nbytes, insns_end);
-       case INSN_COPYFROM_DATA:
-               return copyfrom_data(ctx, data_pos, nbytes);
-       default:
-               return error("invalid delta: unrecognized instruction");
-       }
-}
-
-static int apply_window_in_core(struct window *ctx)
-{
-       const char *instructions;
-       size_t data_pos = 0;
-
-       /*
-        * Fill ctx->out.buf using data from the source, target,
-        * and inline data views.
-        */
-       for (instructions = ctx->instructions.buf;
-            instructions != ctx->instructions.buf + ctx->instructions.len;
-            )
-               if (execute_one_instruction(ctx, &instructions, &data_pos))
-                       return -1;
-       if (data_pos != ctx->data.len)
-               return error("invalid delta: does not copy all inline data");
-       return 0;
-}
-
-static int apply_one_window(struct line_buffer *delta, off_t *delta_len,
-                           struct sliding_view *preimage, FILE *out)
-{
-       int rv = -1;
-       struct window ctx = WINDOW_INIT(preimage);
-       size_t out_len;
-       size_t instructions_len;
-       size_t data_len;
-       assert(delta_len);
-
-       /* "source view" offset and length already handled; */
-       if (read_length(delta, &out_len, delta_len) ||
-           read_length(delta, &instructions_len, delta_len) ||
-           read_length(delta, &data_len, delta_len) ||
-           read_chunk(delta, delta_len, &ctx.instructions, instructions_len) ||
-           read_chunk(delta, delta_len, &ctx.data, data_len))
-               goto error_out;
-       strbuf_grow(&ctx.out, out_len);
-       if (apply_window_in_core(&ctx))
-               goto error_out;
-       if (ctx.out.len != out_len) {
-               rv = error("invalid delta: incorrect postimage length");
-               goto error_out;
-       }
-       if (write_strbuf(&ctx.out, out))
-               goto error_out;
-       rv = 0;
-error_out:
-       window_release(&ctx);
-       return rv;
-}
-
-int svndiff0_apply(struct line_buffer *delta, off_t delta_len,
-                       struct sliding_view *preimage, FILE *postimage)
-{
-       assert(delta && preimage && postimage && delta_len >= 0);
-
-       if (read_magic(delta, &delta_len))
-               return -1;
-       while (delta_len) {     /* For each window: */
-               off_t pre_off = -1;
-               size_t pre_len;
-
-               if (read_offset(delta, &pre_off, &delta_len) ||
-                   read_length(delta, &pre_len, &delta_len) ||
-                   move_window(preimage, pre_off, pre_len) ||
-                   apply_one_window(delta, &delta_len, preimage, postimage))
-                       return -1;
-       }
-       return 0;
-}
diff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c
deleted file mode 100644 (file)
index 08d136b..0000000
+++ /dev/null
@@ -1,540 +0,0 @@
-/*
- * Parse and rearrange a svnadmin dump.
- * Create the dump with:
- * svnadmin dump --incremental -r<startrev>:<endrev> <repository> >outfile
- *
- * Licensed under a two-clause BSD-style license.
- * See LICENSE for details.
- */
-
-#include "cache.h"
-#include "fast_export.h"
-#include "line_buffer.h"
-#include "strbuf.h"
-#include "svndump.h"
-
-/*
- * Compare start of string to literal of equal length;
- * must be guarded by length test.
- */
-#define constcmp(s, ref) memcmp(s, ref, sizeof(ref) - 1)
-
-#define REPORT_FILENO 3
-
-#define NODEACT_REPLACE 4
-#define NODEACT_DELETE 3
-#define NODEACT_ADD 2
-#define NODEACT_CHANGE 1
-#define NODEACT_UNKNOWN 0
-
-/* States: */
-#define DUMP_CTX 0     /* dump metadata */
-#define REV_CTX  1     /* revision metadata */
-#define NODE_CTX 2     /* node metadata */
-#define INTERNODE_CTX 3        /* between nodes */
-
-#define DATE_RFC2822_LEN 31
-
-static struct line_buffer input = LINE_BUFFER_INIT;
-
-static struct {
-       uint32_t action, srcRev, type;
-       off_t prop_length, text_length;
-       struct strbuf src, dst;
-       uint32_t text_delta, prop_delta;
-} node_ctx;
-
-static struct {
-       uint32_t revision;
-       timestamp_t timestamp;
-       struct strbuf log, author, note;
-} rev_ctx;
-
-static struct {
-       uint32_t version;
-       struct strbuf uuid, url;
-} dump_ctx;
-
-static void reset_node_ctx(char *fname)
-{
-       node_ctx.type = 0;
-       node_ctx.action = NODEACT_UNKNOWN;
-       node_ctx.prop_length = -1;
-       node_ctx.text_length = -1;
-       strbuf_reset(&node_ctx.src);
-       node_ctx.srcRev = 0;
-       strbuf_reset(&node_ctx.dst);
-       if (fname)
-               strbuf_addstr(&node_ctx.dst, fname);
-       node_ctx.text_delta = 0;
-       node_ctx.prop_delta = 0;
-}
-
-static void reset_rev_ctx(uint32_t revision)
-{
-       rev_ctx.revision = revision;
-       rev_ctx.timestamp = 0;
-       strbuf_reset(&rev_ctx.log);
-       strbuf_reset(&rev_ctx.author);
-       strbuf_reset(&rev_ctx.note);
-}
-
-static void reset_dump_ctx(const char *url)
-{
-       strbuf_reset(&dump_ctx.url);
-       if (url)
-               strbuf_addstr(&dump_ctx.url, url);
-       dump_ctx.version = 1;
-       strbuf_reset(&dump_ctx.uuid);
-}
-
-static void handle_property(const struct strbuf *key_buf,
-                               struct strbuf *val,
-                               uint32_t *type_set)
-{
-       const char *key = key_buf->buf;
-       size_t keylen = key_buf->len;
-
-       switch (keylen + 1) {
-       case sizeof("svn:log"):
-               if (constcmp(key, "svn:log"))
-                       break;
-               if (!val)
-                       die("invalid dump: unsets svn:log");
-               strbuf_swap(&rev_ctx.log, val);
-               break;
-       case sizeof("svn:author"):
-               if (constcmp(key, "svn:author"))
-                       break;
-               if (!val)
-                       strbuf_reset(&rev_ctx.author);
-               else
-                       strbuf_swap(&rev_ctx.author, val);
-               break;
-       case sizeof("svn:date"):
-               if (constcmp(key, "svn:date"))
-                       break;
-               if (!val)
-                       die("invalid dump: unsets svn:date");
-               if (parse_date_basic(val->buf, &rev_ctx.timestamp, NULL))
-                       warning("invalid timestamp: %s", val->buf);
-               break;
-       case sizeof("svn:executable"):
-       case sizeof("svn:special"):
-               if (keylen == strlen("svn:executable") &&
-                   constcmp(key, "svn:executable"))
-                       break;
-               if (keylen == strlen("svn:special") &&
-                   constcmp(key, "svn:special"))
-                       break;
-               if (*type_set) {
-                       if (!val)
-                               return;
-                       die("invalid dump: sets type twice");
-               }
-               if (!val) {
-                       node_ctx.type = S_IFREG | 0644;
-                       return;
-               }
-               *type_set = 1;
-               node_ctx.type = keylen == strlen("svn:executable") ?
-                               (S_IFREG | 0755) :
-                               S_IFLNK;
-       }
-}
-
-static void die_short_read(void)
-{
-       if (buffer_ferror(&input))
-               die_errno("error reading dump file");
-       die("invalid dump: unexpected end of file");
-}
-
-static void read_props(void)
-{
-       static struct strbuf key = STRBUF_INIT;
-       static struct strbuf val = STRBUF_INIT;
-       const char *t;
-       /*
-        * NEEDSWORK: to support simple mode changes like
-        *      K 11
-        *      svn:special
-        *      V 1
-        *      *
-        *      D 14
-        *      svn:executable
-        * we keep track of whether a mode has been set and reset to
-        * plain file only if not.  We should be keeping track of the
-        * symlink and executable bits separately instead.
-        */
-       uint32_t type_set = 0;
-       while ((t = buffer_read_line(&input)) && strcmp(t, "PROPS-END")) {
-               uint32_t len;
-               const char type = t[0];
-               int ch;
-
-               if (!type || t[1] != ' ')
-                       die("invalid property line: %s", t);
-               len = atoi(&t[2]);
-               strbuf_reset(&val);
-               buffer_read_binary(&input, &val, len);
-               if (val.len < len)
-                       die_short_read();
-
-               /* Discard trailing newline. */
-               ch = buffer_read_char(&input);
-               if (ch == EOF)
-                       die_short_read();
-               if (ch != '\n')
-                       die("invalid dump: expected newline after %s", val.buf);
-
-               switch (type) {
-               case 'K':
-                       strbuf_swap(&key, &val);
-                       continue;
-               case 'D':
-                       handle_property(&val, NULL, &type_set);
-                       continue;
-               case 'V':
-                       handle_property(&key, &val, &type_set);
-                       strbuf_reset(&key);
-                       continue;
-               default:
-                       die("invalid property line: %s", t);
-               }
-       }
-}
-
-static void handle_node(void)
-{
-       const uint32_t type = node_ctx.type;
-       const int have_props = node_ctx.prop_length != -1;
-       const int have_text = node_ctx.text_length != -1;
-       /*
-        * Old text for this node:
-        *  NULL        - directory or bug
-        *  empty_blob  - empty
-        *  "<dataref>" - data retrievable from fast-import
-        */
-       static const char *const empty_blob = "::empty::";
-       const char *old_data = NULL;
-       uint32_t old_mode = S_IFREG | 0644;
-
-       if (node_ctx.action == NODEACT_DELETE) {
-               if (have_text || have_props || node_ctx.srcRev)
-                       die("invalid dump: deletion node has "
-                               "copyfrom info, text, or properties");
-               fast_export_delete(node_ctx.dst.buf);
-               return;
-       }
-       if (node_ctx.action == NODEACT_REPLACE) {
-               fast_export_delete(node_ctx.dst.buf);
-               node_ctx.action = NODEACT_ADD;
-       }
-       if (node_ctx.srcRev) {
-               fast_export_copy(node_ctx.srcRev, node_ctx.src.buf, node_ctx.dst.buf);
-               if (node_ctx.action == NODEACT_ADD)
-                       node_ctx.action = NODEACT_CHANGE;
-       }
-       if (have_text && type == S_IFDIR)
-               die("invalid dump: directories cannot have text attached");
-
-       /*
-        * Find old content (old_data) and decide on the new mode.
-        */
-       if (node_ctx.action == NODEACT_CHANGE && !*node_ctx.dst.buf) {
-               if (type != S_IFDIR)
-                       die("invalid dump: root of tree is not a regular file");
-               old_data = NULL;
-       } else if (node_ctx.action == NODEACT_CHANGE) {
-               uint32_t mode;
-               old_data = fast_export_read_path(node_ctx.dst.buf, &mode);
-               if (mode == S_IFDIR && type != S_IFDIR)
-                       die("invalid dump: cannot modify a directory into a file");
-               if (mode != S_IFDIR && type == S_IFDIR)
-                       die("invalid dump: cannot modify a file into a directory");
-               node_ctx.type = mode;
-               old_mode = mode;
-       } else if (node_ctx.action == NODEACT_ADD) {
-               if (type == S_IFDIR)
-                       old_data = NULL;
-               else if (have_text)
-                       old_data = empty_blob;
-               else
-                       die("invalid dump: adds node without text");
-       } else {
-               die("invalid dump: Node-path block lacks Node-action");
-       }
-
-       /*
-        * Adjust mode to reflect properties.
-        */
-       if (have_props) {
-               if (!node_ctx.prop_delta)
-                       node_ctx.type = type;
-               if (node_ctx.prop_length)
-                       read_props();
-       }
-
-       /*
-        * Save the result.
-        */
-       if (type == S_IFDIR)    /* directories are not tracked. */
-               return;
-       assert(old_data);
-       if (old_data == empty_blob)
-               /* For the fast_export_* functions, NULL means empty. */
-               old_data = NULL;
-       if (!have_text) {
-               fast_export_modify(node_ctx.dst.buf, node_ctx.type, old_data);
-               return;
-       }
-       if (!node_ctx.text_delta) {
-               fast_export_modify(node_ctx.dst.buf, node_ctx.type, "inline");
-               fast_export_data(node_ctx.type, node_ctx.text_length, &input);
-               return;
-       }
-       fast_export_modify(node_ctx.dst.buf, node_ctx.type, "inline");
-       fast_export_blob_delta(node_ctx.type, old_mode, old_data,
-                               node_ctx.text_length, &input);
-}
-
-static void begin_revision(const char *remote_ref)
-{
-       if (!rev_ctx.revision)  /* revision 0 gets no git commit. */
-               return;
-       fast_export_begin_commit(rev_ctx.revision, rev_ctx.author.buf,
-               &rev_ctx.log, dump_ctx.uuid.buf, dump_ctx.url.buf,
-               rev_ctx.timestamp, remote_ref);
-}
-
-static void end_revision(const char *note_ref)
-{
-       struct strbuf mark = STRBUF_INIT;
-       if (rev_ctx.revision) {
-               fast_export_end_commit(rev_ctx.revision);
-               fast_export_begin_note(rev_ctx.revision, "remote-svn",
-                               "Note created by remote-svn.", rev_ctx.timestamp, note_ref);
-               strbuf_addf(&mark, ":%"PRIu32, rev_ctx.revision);
-               fast_export_note(mark.buf, "inline");
-               fast_export_buf_to_data(&rev_ctx.note);
-               strbuf_release(&mark);
-       }
-}
-
-void svndump_read(const char *url, const char *local_ref, const char *notes_ref)
-{
-       char *val;
-       char *t;
-       uint32_t active_ctx = DUMP_CTX;
-       uint32_t len;
-
-       reset_dump_ctx(url);
-       while ((t = buffer_read_line(&input))) {
-               val = strchr(t, ':');
-               if (!val)
-                       continue;
-               val++;
-               if (*val != ' ')
-                       continue;
-               val++;
-
-               /* strlen(key) + 1 */
-               switch (val - t - 1) {
-               case sizeof("SVN-fs-dump-format-version"):
-                       if (constcmp(t, "SVN-fs-dump-format-version"))
-                               continue;
-                       dump_ctx.version = atoi(val);
-                       if (dump_ctx.version > 3)
-                               die("expected svn dump format version <= 3, found %"PRIu32,
-                                   dump_ctx.version);
-                       break;
-               case sizeof("UUID"):
-                       if (constcmp(t, "UUID"))
-                               continue;
-                       strbuf_reset(&dump_ctx.uuid);
-                       strbuf_addstr(&dump_ctx.uuid, val);
-                       break;
-               case sizeof("Revision-number"):
-                       if (constcmp(t, "Revision-number"))
-                               continue;
-                       if (active_ctx == NODE_CTX)
-                               handle_node();
-                       if (active_ctx == REV_CTX)
-                               begin_revision(local_ref);
-                       if (active_ctx != DUMP_CTX)
-                               end_revision(notes_ref);
-                       active_ctx = REV_CTX;
-                       reset_rev_ctx(atoi(val));
-                       strbuf_addf(&rev_ctx.note, "%s\n", t);
-                       break;
-               case sizeof("Node-path"):
-                       if (constcmp(t, "Node-"))
-                               continue;
-                       if (!constcmp(t + strlen("Node-"), "path")) {
-                               if (active_ctx == NODE_CTX)
-                                       handle_node();
-                               if (active_ctx == REV_CTX)
-                                       begin_revision(local_ref);
-                               active_ctx = NODE_CTX;
-                               reset_node_ctx(val);
-                               strbuf_addf(&rev_ctx.note, "%s\n", t);
-                               break;
-                       }
-                       if (constcmp(t + strlen("Node-"), "kind"))
-                               continue;
-                       strbuf_addf(&rev_ctx.note, "%s\n", t);
-                       if (!strcmp(val, "dir"))
-                               node_ctx.type = S_IFDIR;
-                       else if (!strcmp(val, "file"))
-                               node_ctx.type = S_IFREG | 0644;
-                       else
-                               fprintf(stderr, "Unknown node-kind: %s\n", val);
-                       break;
-               case sizeof("Node-action"):
-                       if (constcmp(t, "Node-action"))
-                               continue;
-                       strbuf_addf(&rev_ctx.note, "%s\n", t);
-                       if (!strcmp(val, "delete")) {
-                               node_ctx.action = NODEACT_DELETE;
-                       } else if (!strcmp(val, "add")) {
-                               node_ctx.action = NODEACT_ADD;
-                       } else if (!strcmp(val, "change")) {
-                               node_ctx.action = NODEACT_CHANGE;
-                       } else if (!strcmp(val, "replace")) {
-                               node_ctx.action = NODEACT_REPLACE;
-                       } else {
-                               fprintf(stderr, "Unknown node-action: %s\n", val);
-                               node_ctx.action = NODEACT_UNKNOWN;
-                       }
-                       break;
-               case sizeof("Node-copyfrom-path"):
-                       if (constcmp(t, "Node-copyfrom-path"))
-                               continue;
-                       strbuf_reset(&node_ctx.src);
-                       strbuf_addstr(&node_ctx.src, val);
-                       strbuf_addf(&rev_ctx.note, "%s\n", t);
-                       break;
-               case sizeof("Node-copyfrom-rev"):
-                       if (constcmp(t, "Node-copyfrom-rev"))
-                               continue;
-                       node_ctx.srcRev = atoi(val);
-                       strbuf_addf(&rev_ctx.note, "%s\n", t);
-                       break;
-               case sizeof("Text-content-length"):
-                       if (constcmp(t, "Text") && constcmp(t, "Prop"))
-                               continue;
-                       if (constcmp(t + 4, "-content-length"))
-                               continue;
-                       {
-                               char *end;
-                               uintmax_t len;
-
-                               len = strtoumax(val, &end, 10);
-                               if (!isdigit(*val) || *end)
-                                       die("invalid dump: non-numeric length %s", val);
-                               if (len > maximum_signed_value_of_type(off_t))
-                                       die("unrepresentable length in dump: %s", val);
-
-                               if (*t == 'T')
-                                       node_ctx.text_length = (off_t) len;
-                               else
-                                       node_ctx.prop_length = (off_t) len;
-                               break;
-                       }
-               case sizeof("Text-delta"):
-                       if (!constcmp(t, "Text-delta")) {
-                               node_ctx.text_delta = !strcmp(val, "true");
-                               break;
-                       }
-                       if (constcmp(t, "Prop-delta"))
-                               continue;
-                       node_ctx.prop_delta = !strcmp(val, "true");
-                       break;
-               case sizeof("Content-length"):
-                       if (constcmp(t, "Content-length"))
-                               continue;
-                       len = atoi(val);
-                       t = buffer_read_line(&input);
-                       if (!t)
-                               die_short_read();
-                       if (*t)
-                               die("invalid dump: expected blank line after content length header");
-                       if (active_ctx == REV_CTX) {
-                               read_props();
-                       } else if (active_ctx == NODE_CTX) {
-                               handle_node();
-                               active_ctx = INTERNODE_CTX;
-                       } else {
-                               fprintf(stderr, "Unexpected content length header: %"PRIu32"\n", len);
-                               if (buffer_skip_bytes(&input, len) != len)
-                                       die_short_read();
-                       }
-               }
-       }
-       if (buffer_ferror(&input))
-               die_short_read();
-       if (active_ctx == NODE_CTX)
-               handle_node();
-       if (active_ctx == REV_CTX)
-               begin_revision(local_ref);
-       if (active_ctx != DUMP_CTX)
-               end_revision(notes_ref);
-}
-
-static void init(int report_fd)
-{
-       fast_export_init(report_fd);
-       strbuf_init(&dump_ctx.uuid, 4096);
-       strbuf_init(&dump_ctx.url, 4096);
-       strbuf_init(&rev_ctx.log, 4096);
-       strbuf_init(&rev_ctx.author, 4096);
-       strbuf_init(&rev_ctx.note, 4096);
-       strbuf_init(&node_ctx.src, 4096);
-       strbuf_init(&node_ctx.dst, 4096);
-       reset_dump_ctx(NULL);
-       reset_rev_ctx(0);
-       reset_node_ctx(NULL);
-       return;
-}
-
-int svndump_init(const char *filename)
-{
-       if (buffer_init(&input, filename))
-               return error_errno("cannot open %s", filename ? filename : "NULL");
-       init(REPORT_FILENO);
-       return 0;
-}
-
-int svndump_init_fd(int in_fd, int back_fd)
-{
-       if(buffer_fdinit(&input, xdup(in_fd)))
-               return error_errno("cannot open fd %d", in_fd);
-       init(xdup(back_fd));
-       return 0;
-}
-
-void svndump_deinit(void)
-{
-       fast_export_deinit();
-       reset_dump_ctx(NULL);
-       reset_rev_ctx(0);
-       reset_node_ctx(NULL);
-       strbuf_release(&rev_ctx.log);
-       strbuf_release(&rev_ctx.author);
-       strbuf_release(&rev_ctx.note);
-       strbuf_release(&node_ctx.src);
-       strbuf_release(&node_ctx.dst);
-       if (buffer_deinit(&input))
-               fprintf(stderr, "Input error\n");
-       if (ferror(stdout))
-               fprintf(stderr, "Output error\n");
-}
-
-void svndump_reset(void)
-{
-       strbuf_release(&dump_ctx.uuid);
-       strbuf_release(&dump_ctx.url);
-       strbuf_release(&rev_ctx.log);
-       strbuf_release(&rev_ctx.author);
-}
index 62217b4a6b26b4efad52643d25f21e7c98a2fa3e..46a5fb844766a74afee9223354801f26b7e3a908 100644 (file)
@@ -571,3 +571,138 @@ int other_head_refs(each_ref_fn fn, void *cb_data)
        free_worktrees(worktrees);
        return ret;
 }
+
+/*
+ * Repair worktree's /path/to/worktree/.git file if missing, corrupt, or not
+ * pointing at <repo>/worktrees/<id>.
+ */
+static void repair_gitfile(struct worktree *wt,
+                          worktree_repair_fn fn, void *cb_data)
+{
+       struct strbuf dotgit = STRBUF_INIT;
+       struct strbuf repo = STRBUF_INIT;
+       char *backlink;
+       const char *repair = NULL;
+       int err;
+
+       /* missing worktree can't be repaired */
+       if (!file_exists(wt->path))
+               return;
+
+       if (!is_directory(wt->path)) {
+               fn(1, wt->path, _("not a directory"), cb_data);
+               return;
+       }
+
+       strbuf_realpath(&repo, git_common_path("worktrees/%s", wt->id), 1);
+       strbuf_addf(&dotgit, "%s/.git", wt->path);
+       backlink = xstrdup_or_null(read_gitfile_gently(dotgit.buf, &err));
+
+       if (err == READ_GITFILE_ERR_NOT_A_FILE)
+               fn(1, wt->path, _(".git is not a file"), cb_data);
+       else if (err)
+               repair = _(".git file broken");
+       else if (fspathcmp(backlink, repo.buf))
+               repair = _(".git file incorrect");
+
+       if (repair) {
+               fn(0, wt->path, repair, cb_data);
+               write_file(dotgit.buf, "gitdir: %s", repo.buf);
+       }
+
+       free(backlink);
+       strbuf_release(&repo);
+       strbuf_release(&dotgit);
+}
+
+static void repair_noop(int iserr, const char *path, const char *msg,
+                       void *cb_data)
+{
+       /* nothing */
+}
+
+void repair_worktrees(worktree_repair_fn fn, void *cb_data)
+{
+       struct worktree **worktrees = get_worktrees();
+       struct worktree **wt = worktrees + 1; /* +1 skips main worktree */
+
+       if (!fn)
+               fn = repair_noop;
+       for (; *wt; wt++)
+               repair_gitfile(*wt, fn, cb_data);
+       free_worktrees(worktrees);
+}
+
+static int is_main_worktree_path(const char *path)
+{
+       struct strbuf target = STRBUF_INIT;
+       struct strbuf maindir = STRBUF_INIT;
+       int cmp;
+
+       strbuf_add_real_path(&target, path);
+       strbuf_strip_suffix(&target, "/.git");
+       strbuf_add_real_path(&maindir, get_git_common_dir());
+       strbuf_strip_suffix(&maindir, "/.git");
+       cmp = fspathcmp(maindir.buf, target.buf);
+
+       strbuf_release(&maindir);
+       strbuf_release(&target);
+       return !cmp;
+}
+
+/*
+ * Repair <repo>/worktrees/<id>/gitdir if missing, corrupt, or not pointing at
+ * the worktree's path.
+ */
+void repair_worktree_at_path(const char *path,
+                            worktree_repair_fn fn, void *cb_data)
+{
+       struct strbuf dotgit = STRBUF_INIT;
+       struct strbuf realdotgit = STRBUF_INIT;
+       struct strbuf gitdir = STRBUF_INIT;
+       struct strbuf olddotgit = STRBUF_INIT;
+       char *backlink = NULL;
+       const char *repair = NULL;
+       int err;
+
+       if (!fn)
+               fn = repair_noop;
+
+       if (is_main_worktree_path(path))
+               goto done;
+
+       strbuf_addf(&dotgit, "%s/.git", path);
+       if (!strbuf_realpath(&realdotgit, dotgit.buf, 0)) {
+               fn(1, path, _("not a valid path"), cb_data);
+               goto done;
+       }
+
+       backlink = xstrdup_or_null(read_gitfile_gently(realdotgit.buf, &err));
+       if (err == READ_GITFILE_ERR_NOT_A_FILE) {
+               fn(1, realdotgit.buf, _("unable to locate repository; .git is not a file"), cb_data);
+               goto done;
+       } else if (err) {
+               fn(1, realdotgit.buf, _("unable to locate repository; .git file broken"), cb_data);
+               goto done;
+       }
+
+       strbuf_addf(&gitdir, "%s/gitdir", backlink);
+       if (strbuf_read_file(&olddotgit, gitdir.buf, 0) < 0)
+               repair = _("gitdir unreadable");
+       else {
+               strbuf_rtrim(&olddotgit);
+               if (fspathcmp(olddotgit.buf, realdotgit.buf))
+                       repair = _("gitdir incorrect");
+       }
+
+       if (repair) {
+               fn(0, gitdir.buf, repair, cb_data);
+               write_file(gitdir.buf, "%s", realdotgit.buf);
+       }
+done:
+       free(backlink);
+       strbuf_release(&olddotgit);
+       strbuf_release(&gitdir);
+       strbuf_release(&realdotgit);
+       strbuf_release(&dotgit);
+}
index 516744c433f1e627abe85a347d72e6516f98c171..ff7b62e43414d24e5c61c619352f47f034484aeb 100644 (file)
@@ -89,6 +89,29 @@ int validate_worktree(const struct worktree *wt,
 void update_worktree_location(struct worktree *wt,
                              const char *path_);
 
+typedef void (* worktree_repair_fn)(int iserr, const char *path,
+                                   const char *msg, void *cb_data);
+
+/*
+ * Visit each registered linked worktree and repair corruptions. For each
+ * repair made or error encountered while attempting a repair, the callback
+ * function, if non-NULL, is called with the path of the worktree and a
+ * description of the repair or error, along with the callback user-data.
+ */
+void repair_worktrees(worktree_repair_fn, void *cb_data);
+
+/*
+ * Repair administrative files corresponding to the worktree at the given path.
+ * The worktree's .git file pointing at the repository must be intact for the
+ * repair to succeed. Useful for re-associating an orphaned worktree with the
+ * repository if the worktree has been moved manually (without using "git
+ * worktree move"). For each repair made or error encountered while attempting
+ * a repair, the callback function, if non-NULL, is called with the path of the
+ * worktree and a description of the repair or error, along with the callback
+ * user-data.
+ */
+void repair_worktree_at_path(const char *, worktree_repair_fn, void *cb_data);
+
 /*
  * Free up the memory for worktree(s)
  */
index 4ff4a9c3db0e1c797bce777eac5358d74c0bc5c6..bcda41e3744c1f0a94b7717c67a7f85195088821 100644 (file)
--- a/wrapper.c
+++ b/wrapper.c
@@ -117,10 +117,13 @@ void *xrealloc(void *ptr, size_t size)
 {
        void *ret;
 
+       if (!size) {
+               free(ptr);
+               return xmalloc(0);
+       }
+
        memory_limit_check(size, 0);
        ret = realloc(ptr, size);
-       if (!ret && !size)
-               ret = realloc(ptr, 1);
        if (!ret)
                die("Out of memory, realloc failed");
        return ret;
index 7ce58b8aae06a94a3615f0acdd07e0e10ffbd32f..bb0f9120de40f70578867dece592eeecdf0e1e23 100644 (file)
@@ -1668,13 +1668,13 @@ void wt_status_get_state(struct repository *r,
                state->merge_in_progress = 1;
        } else if (wt_status_check_rebase(NULL, state)) {
                ;               /* all set */
-       } else if (!stat(git_path_cherry_pick_head(r), &st) &&
-                       !get_oid("CHERRY_PICK_HEAD", &oid)) {
+       } else if (refs_ref_exists(get_main_ref_store(r), "CHERRY_PICK_HEAD") &&
+                  !get_oid("CHERRY_PICK_HEAD", &oid)) {
                state->cherry_pick_in_progress = 1;
                oidcpy(&state->cherry_pick_head_oid, &oid);
        }
        wt_status_check_bisect(NULL, state);
-       if (!stat(git_path_revert_head(r), &st) &&
+       if (refs_ref_exists(get_main_ref_store(r), "REVERT_HEAD") &&
            !get_oid("REVERT_HEAD", &oid)) {
                state->revert_in_progress = 1;
                oidcpy(&state->revert_head_oid, &oid);