]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Merge branch 'jk/slimmed-down'
authorJunio C Hamano <gitster@pobox.com>
Thu, 3 Sep 2020 19:37:02 +0000 (12:37 -0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 3 Sep 2020 19:37:02 +0000 (12:37 -0700)
Trim an unused binary and turn a bunch of commands into built-in.

* jk/slimmed-down:
  drop vcs-svn experiment
  make git-fast-import a builtin
  make git-bugreport a builtin
  make credential helpers builtins
  Makefile: drop builtins from MSVC pdb list

236 files changed:
.github/workflows/main.yml
Documentation/MyFirstContribution.txt
Documentation/RelNotes/2.29.0.txt
Documentation/blame-options.txt
Documentation/config/sendemail.txt
Documentation/diff-options.txt
Documentation/fetch-options.txt
Documentation/git-apply.txt
Documentation/git-bisect.txt
Documentation/git-index-pack.txt
Documentation/git-init.txt
Documentation/git-log.txt
Documentation/git-multi-pack-index.txt
Documentation/git-pack-objects.txt
Documentation/git-rebase.txt
Documentation/git-show-index.txt
Documentation/git-update-ref.txt
Documentation/git.txt
Documentation/object-format-disclaimer.txt [new file with mode: 0644]
Documentation/rev-list-options.txt
Documentation/technical/commit-graph-format.txt
Documentation/technical/commit-graph.txt
Documentation/technical/hash-function-transition.txt
Documentation/technical/http-protocol.txt
Documentation/technical/index-format.txt
Documentation/technical/pack-format.txt
Documentation/technical/protocol-capabilities.txt
Documentation/technical/shallow.txt
add-patch.c
apply.c
bisect.c
bisect.h
blame.c
builtin/add.c
builtin/am.c
builtin/bisect--helper.c
builtin/blame.c
builtin/bugreport.c
builtin/check-ignore.c
builtin/checkout.c
builtin/clean.c
builtin/commit.c
builtin/fast-import.c
builtin/fetch.c
builtin/fsck.c
builtin/grep.c
builtin/index-pack.c
builtin/init-db.c
builtin/log.c
builtin/ls-files.c
builtin/ls-remote.c
builtin/merge.c
builtin/name-rev.c
builtin/pack-objects.c
builtin/rebase.c
builtin/remote.c
builtin/rev-list.c
builtin/stash.c
builtin/submodule--helper.c
cache.h
checkout.c
commit-graph.c
commit.c
commit.h
compat/mingw.c
config.c
config.h
connect.c
connected.c
contrib/completion/git-completion.bash
contrib/subtree/git-subtree.txt
diff-lib.c
diff.c
dir.c
dir.h
editor.c
entry.c
environment.c
fetch-pack.c
fetch-pack.h
git-bisect.sh
git-compat-util.h
git-cvsexportcommit.perl
git-mergetool--lib.sh
git-rebase--preserve-merges.sh
git-send-email.perl
help.c
ident.c
mem-pool.c
mem-pool.h
merge.c
mergetools/bc
mergetools/bc3 [deleted file]
mergetools/gvimdiff3 [deleted file]
mergetools/nvimdiff [moved from mergetools/gvimdiff2 with 100% similarity]
mergetools/vimdiff
mergetools/vimdiff2 [deleted file]
mergetools/vimdiff3 [deleted file]
midx.c
object-store.h
parse-options.c
parse-options.h
path.c
path.h
perl/Git.pm
po/fr.po
progress.c
protocol.c
read-cache.c
ref-filter.c
refs.c
refs.h
refs/files-backend.c
refs/packed-backend.c
refs/refs-internal.h
refspec.h
remote-curl.c
revision.c
revision.h
sequencer.c
sequencer.h
sha1-file.c
sideband.c
split-index.c
submodule.c
t/README
t/helper/test-config.c
t/helper/test-read-midx.c
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/t0040-parse-options.sh
t/t1400-update-ref.sh
t/t1405-main-ref-store.sh
t/t1416-ref-transaction-hooks.sh
t/t2025-checkout-no-overlay.sh
t/t2072-restore-pathspec-file.sh
t/t3000-ls-files-others.sh
t/t3404-rebase-interactive.sh
t/t3422-rebase-incompatible-options.sh
t/t3436-rebase-more-options.sh [new file with mode: 0755]
t/t3500-cherry.sh
t/t3501-revert-cherry-pick.sh
t/t3507-cherry-pick-conflict.sh
t/t4005-diff-rename-2.sh
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/t4013/diff.log_--diff-merges=off_-p_--first-parent_master [new file with mode: 0644]
t/t4013/diff.log_--first-parent_--diff-merges=off_-p_master [new file with mode: 0644]
t/t4013/diff.log_--no-diff-merges_-p_--first-parent_master [new file with mode: 0644]
t/t4013/diff.log_-p_--first-parent_master
t/t4018/fortran-block-data [new file with mode: 0644]
t/t4018/fortran-comment [new file with mode: 0644]
t/t4018/fortran-comment-keyword [new file with mode: 0644]
t/t4018/fortran-comment-legacy [new file with mode: 0644]
t/t4018/fortran-comment-legacy-star [new file with mode: 0644]
t/t4018/fortran-external-function [new file with mode: 0644]
t/t4018/fortran-external-subroutine [new file with mode: 0644]
t/t4018/fortran-module [new file with mode: 0644]
t/t4018/fortran-module-procedure [new file with mode: 0644]
t/t4018/fortran-program [new file with mode: 0644]
t/t4034-diff-words.sh
t/t4104-apply-boundary.sh
t/t4140-apply-ita.sh [new file with mode: 0755]
t/t4150-am.sh
t/t4200-rerere.sh
t/t4202-log.sh
t/t4216-log-bloom.sh
t/t5302-pack-index.sh
t/t5318-commit-graph.sh
t/t5319-multi-pack-index.sh
t/t5324-split-commit-graph.sh
t/t5510-fetch.sh
t/t5521-pull-options.sh
t/t5553-set-upstream.sh
t/t5616-partial-clone.sh
t/t5702-protocol-v2.sh
t/t6000-rev-list-misc.sh
t/t6002-rev-list-bisect.sh
t/t6018-rev-list-glob.sh
t/t6030-bisect-porcelain.sh
t/t6300-for-each-ref.sh
t/t6400-merge-df.sh [moved from t/t6020-merge-df.sh with 100% similarity]
t/t6401-merge-criss-cross.sh [moved from t/t6021-merge-criss-cross.sh with 100% similarity]
t/t6402-merge-rename.sh [moved from t/t6022-merge-rename.sh with 100% similarity]
t/t6403-merge-file.sh [moved from t/t6023-merge-file.sh with 100% similarity]
t/t6404-recursive-merge.sh [moved from t/t6024-recursive-merge.sh with 100% similarity]
t/t6405-merge-symlinks.sh [moved from t/t6025-merge-symlinks.sh with 100% similarity]
t/t6406-merge-attr.sh [moved from t/t6026-merge-attr.sh with 98% similarity]
t/t6407-merge-binary.sh [moved from t/t6027-merge-binary.sh with 100% similarity]
t/t6408-merge-up-to-date.sh [moved from t/t6028-merge-up-to-date.sh with 100% similarity]
t/t6409-merge-subtree.sh [moved from t/t6029-merge-subtree.sh with 100% similarity]
t/t6411-merge-filemode.sh [moved from t/t6031-merge-filemode.sh with 100% similarity]
t/t6412-merge-large-rename.sh [moved from t/t6032-merge-large-rename.sh with 100% similarity]
t/t6413-merge-crlf.sh [moved from t/t6033-merge-crlf.sh with 100% similarity]
t/t6414-merge-rename-nocruft.sh [moved from t/t6034-merge-rename-nocruft.sh with 100% similarity]
t/t6415-merge-dir-to-symlink.sh [moved from t/t6035-merge-dir-to-symlink.sh with 100% similarity]
t/t6416-recursive-corner-cases.sh [moved from t/t6036-recursive-corner-cases.sh with 99% similarity]
t/t6417-merge-ours-theirs.sh [moved from t/t6037-merge-ours-theirs.sh with 100% similarity]
t/t6418-merge-text-auto.sh [moved from t/t6038-merge-text-auto.sh with 99% similarity]
t/t6419-merge-ignorecase.sh [moved from t/t6039-merge-ignorecase.sh with 100% similarity]
t/t6422-merge-rename-corner-cases.sh [moved from t/t6042-merge-rename-corner-cases.sh with 94% similarity]
t/t6423-merge-rename-directories.sh [moved from t/t6043-merge-rename-directories.sh with 98% similarity]
t/t6424-merge-unrelated-index-changes.sh [moved from t/t6044-merge-unrelated-index-changes.sh with 100% similarity]
t/t6425-merge-rename-delete.sh [moved from t/t6045-merge-rename-delete.sh with 72% similarity]
t/t6426-merge-skip-unneeded-updates.sh [moved from t/t6046-merge-skip-unneeded-updates.sh with 99% similarity]
t/t6427-diff3-conflict-markers.sh [moved from t/t6047-diff3-conflict-markers.sh with 100% similarity]
t/t6430-merge-recursive.sh [moved from t/t3030-merge-recursive.sh with 100% similarity]
t/t6431-merge-criscross.sh [moved from t/t3031-merge-criscross.sh with 100% similarity]
t/t6432-merge-recursive-space-options.sh [moved from t/t3032-merge-recursive-space-options.sh with 100% similarity]
t/t6433-merge-toplevel.sh [moved from t/t3033-merge-toplevel.sh with 100% similarity]
t/t6434-merge-recursive-rename-options.sh [moved from t/t3034-merge-recursive-rename-options.sh with 100% similarity]
t/t6435-merge-sparse.sh [moved from t/t3035-merge-sparse.sh with 100% similarity]
t/t6436-merge-overwrite.sh [moved from t/t7607-merge-overwrite.sh with 100% similarity]
t/t6437-submodule-merge.sh [moved from t/t7405-submodule-merge.sh with 100% similarity]
t/t6438-submodule-directory-file-conflicts.sh [moved from t/t7613-merge-submodule.sh with 100% similarity]
t/t6439-merge-co-error-msgs.sh [moved from t/t7609-merge-co-error-msgs.sh with 100% similarity]
t/t7001-mv.sh
t/t7401-submodule-summary.sh
t/t7518-ident-corner-cases.sh
t/t7600-merge.sh
t/t8003-blame-corner-cases.sh
t/t9001-send-email.sh
t/t9100-git-svn-basic.sh
t/t9401-git-cvsserver-crlf.sh
t/t9402-git-cvsserver-refs.sh
t/test-lib-functions.sh
transport.c
transport.h
upload-pack.c
userdiff.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 d85c9b5143cec2f315c33886c497576e0c5591b8..4f85a089ef9d99e868dd1550992ac234e13266ff 100644 (file)
@@ -319,14 +319,14 @@ function body:
 ...
 
        git_config(git_default_config, NULL);
-       if (git_config_get_string_const("user.name", &cfg_name) > 0)
+       if (git_config_get_string_tmp("user.name", &cfg_name) > 0)
                printf(_("No name is found in config\n"));
        else
                printf(_("Your name: %s\n"), cfg_name);
 ----
 
 `git_config()` will grab the configuration from config files known to Git and
-apply standard precedence rules. `git_config_get_string_const()` will look up
+apply standard precedence rules. `git_config_get_string_tmp()` will look up
 a specific key ("user.name") and give you the value. There are a number of
 single-key lookup functions like this one; you can see them all (and more info
 about how to use `git_config()`) in `Documentation/technical/api-config.txt`.
index 06025e8824d4d32656097343d02646cfb6ceca97..a020dadab762bd7407c01832e79d0fdfca5637cd 100644 (file)
@@ -19,6 +19,42 @@ UI, Workflows & Features
    configurable to selectively allow or reject object filtering
    specification used for partial cloning.
 
+ * Stop when "sendmail.*" configuration variables are defined, which
+   could be a mistaken attempt to define "sendemail.*" variables.
+
+ * The existing backends for "git mergetool" based on variants of vim
+   have been refactored and then support for "nvim" has been added.
+
+ * "git bisect" learns the "--first-parent" option to find the first
+   breakage along the first-parent chain.
+
+ * "git log --first-parent -p" showed patches only for single-parent
+   commits on the first-parent chain; the "--first-parent" option has
+   been made to imply "-m".  Use "--no-diff-merges" to restore the
+   previous behaviour to omit patches for merge commits.
+
+ * The commit labels used to explain each side of conflicted hunks
+   placed by the sequencer machinery have been made more readable by
+   humans.
+
+ * The "--batch-size" option of "git multi-pack-index repack" command
+   is now used to specify that very small packfiles are collected into
+   one until the total size roughly exceeds it.
+
+ * The recent addition of SHA-256 support is marked as experimental in
+   the documentation.
+
+ * "git fetch" learned --no-write-fetch-head option to avoid writing
+   the FETCH_HEAD file.
+
+ * Command line completion (in contrib/) usually omits redundant,
+   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.
 
@@ -52,10 +88,39 @@ Performance, Internal Implementation, Development Support etc.
    to a certain degree.  It has been renamed to "strvec" to reduce the
    barrier to adoption.
 
- * The final leg of SHA-256 transition.
+ * The final leg of SHA-256 transition plus doc updates.  Note that
+   there is no inter-operability between SHA-1 and SHA-256
+   repositories yet.
 
  * CMake support to build with MSVC for Windows bypassing the Makefile.
 
+ * A new helper function has_object() has been introduced to make it
+   easier to mark object existence checks that do and don't want to
+   trigger lazy fetches, and a few such checks are converted using it.
+
+ * A no-op replacement function implemented as a C preprocessor macro
+   does not perform as good a job as one implemented as a "static
+   inline" function in catching errors in parameters; replace the
+   former with the latter in <git-compat-util.h> header.
+
+ * Test framework update.
+   (merge d572f52a64 es/test-cmp-typocatcher later to maint).
+
+ * Updates to "git merge" tests, in preparation for a new merge
+   strategy backend.
+
+ * midx and commit-graph files now use the byte defined in their file
+   format specification for identifying the hash function used for
+   object names.
+
+ * The FETCH_HEAD is now always read from the filesystem regardless of
+   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.
+
 
 Fixes since v2.28
 -----------------
@@ -102,6 +167,102 @@ Fixes since v2.28
  * Doc cleanup around "worktree".
    (merge dc9c144be5 es/worktree-doc-cleanups later to maint).
 
+ * The "git blame --first-parent" option was not documented, but now
+   it is.
+   (merge 11bc12ae1e rp/blame-first-parent-doc later to maint).
+
+ * The logic to find the ref transaction hook script attempted to
+   cache the path to the found hook without realizing that it needed
+   to keep a copied value, as the API it used returned a transitory
+   buffer space.  This has been corrected.
+   (merge 09b2aa30c9 ps/ref-transaction-hook later to maint).
+
+ * Recent versions of "git diff-files" shows a diff between the index
+   and the working tree for "intent-to-add" paths as a "new file"
+   patch; "git apply --cached" should be able to take "git diff-files"
+   and should act as an equivalent to "git add" for the path, but the
+   command failed to do so for such a path.
+   (merge 4c025c667e rp/apply-cached-with-i-t-a later to maint).
+
+ * "git diff [<tree-ish>] $path" for a $path that is marked with i-t-a
+   bit was not showing the mode bits from the working tree.
+   (merge cb0dd22b82 rp/ita-diff-modefix later to maint).
+
+ * Ring buffer with size 4 used for bin-hex translation resulted in a
+   wrong object name in the sequencer's todo output, which has been
+   corrected.
+   (merge 5da69c0dac ak/sequencer-fix-find-uniq-abbrev later to maint).
+
+ * When given more than one target line ranges, "git blame -La,b
+   -Lc,d" was over-eager to coalesce groups of original lines and
+   showed incorrect results, which has been corrected.
+   (merge c2ebaa27d6 jk/blame-coalesce-fix later to maint).
+
+ * The regexp to identify the function boundary for FORTRAN programs
+   has been updated.
+   (merge 75c3b6b2e8 pb/userdiff-fortran-update later to maint).
+
+ * A few end-user facing messages have been updated to be
+   hash-algorithm agnostic.
+   (merge 4279000d3e jc/object-names-are-not-sha-1 later to maint).
+
+ * "unlink" emulation on MinGW has been optimized.
+   (merge 680e0b4524 jh/mingw-unlink later to maint).
+
+ * The purpose of "git init --separate-git-dir" is to initialize a
+   new project with the repository separate from the working tree,
+   or, in the case of an existing project, to move the repository
+   (the .git/ directory) out of the working tree. It does not make
+   sense to use --separate-git-dir with a bare repository for which
+   there is no working tree, so disallow its use with bare
+   repositories.
+   (merge ccf236a23a es/init-no-separate-git-dir-in-bare later to maint).
+
+ * "ls-files -o" mishandled the top-level directory of another git
+   working tree that hangs in the current git working tree.
+   (merge ab282aa548 en/dir-nonbare-embedded later to maint).
+
+ * Fix some incorrect UNLEAK() annotations.
+   (merge 3e19816dc0 jk/unleak-fixes later to maint).
+
+ * Use more buffered I/O where we used to call many small write(2)s.
+   (merge a698d67b08 rs/more-buffered-io later to maint).
+
+ * The patch-id computation did not ignore the "incomplete last line"
+   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).
+
  * Other code cleanup, docfix, build fix, etc.
    (merge 84544f2ea3 sk/typofixes later to maint).
    (merge b17f411ab5 ar/help-guides-doc later to maint).
@@ -115,3 +276,12 @@ Fixes since v2.28
    (merge 7d23ff818f rs/bisect-oid-to-hex-fix later to maint).
    (merge de20baf2c9 ny/notes-doc-sample-update later to maint).
    (merge f649aaaf82 so/rev-parser-errormessage-fix later to maint).
+   (merge 6103d58b7f bc/sha-256-cvs-svn-updates later to maint).
+   (merge ac900fddb7 ma/stop-progress-null-fix later to maint).
+   (merge e767963ab6 rs/upload-pack-sigchain-fix later to maint).
+   (merge a831908599 rs/preserve-merges-unused-code-removal later to maint).
+   (merge 6dfefe70a9 jb/commit-graph-doc-fix later to maint).
+   (merge 847b37271e pb/set-url-docfix later to maint).
+   (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).
index 5d122db6e9e6863fcf1e69ebc14feb1393501e0b..88750af7ae19672dd1b44a6131b180acdc77ba16 100644 (file)
@@ -36,6 +36,12 @@ include::line-range-format.txt[]
        START.  `git blame --reverse START` is taken as `git blame
        --reverse START..HEAD` for convenience.
 
+--first-parent::
+       Follow only the first parent commit upon seeing a merge
+       commit. This option can be used to determine when a line
+       was introduced to a particular integration branch, rather
+       than when it was introduced to the history overall.
+
 -p::
 --porcelain::
        Show in a format designed for machine consumption.
index 0006faf800ae69cd4ee3cde99b5e661e06ae6893..cbc5af42fdf05c1d9450c55a4342c58714e9a766 100644 (file)
@@ -61,3 +61,8 @@ sendemail.smtpBatchSize::
 sendemail.smtpReloginDelay::
        Seconds wait before reconnecting to smtp server.
        See also the `--relogin-delay` option of linkgit:git-send-email[1].
+
+sendemail.forbidSendmailVariables::
+       To avoid common misconfiguration mistakes, linkgit:git-send-email[1]
+       will abort with a warning if any configuration options for "sendmail"
+       exist. Set this variable to bypass the check.
index 7987d72b0212e1247ff5ea14b553d4a322c1f5f5..573fb9bb71e2b7df1062258289a0af308c50bf5b 100644 (file)
@@ -73,6 +73,11 @@ ifndef::git-format-patch[]
        Synonym for `-p --raw`.
 endif::git-format-patch[]
 
+ifdef::git-log[]
+-t::
+       Show the tree objects in the diff output.
+endif::git-log[]
+
 --indent-heuristic::
        Enable the heuristic that shifts diff hunk boundaries to make patches
        easier to read. This is the default.
@@ -441,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 6e2a160a47cb8c07a72600d2fc7ad404bf2bc1c1..e8104c082ed16e3829e39f10be211d16e7c81510 100644 (file)
@@ -64,6 +64,15 @@ documented in linkgit:git-config[1].
 --dry-run::
        Show what would be done, without making any changes.
 
+ifndef::git-pull[]
+--[no-]write-fetch-head::
+       Write the list of remote refs fetched in the `FETCH_HEAD`
+       file directly under `$GIT_DIR`.  This is the default.
+       Passing `--no-write-fetch-head` from the command line tells
+       Git not to write the file.  Under `--dry-run` option, the
+       file is never written.
+endif::git-pull[]
+
 -f::
 --force::
        When 'git fetch' is used with `<src>:<dst>` refspec it may
@@ -186,7 +195,7 @@ ifndef::git-pull[]
 endif::git-pull[]
 
 --set-upstream::
-       If the remote is fetched successfully, pull and add upstream
+       If the remote is fetched successfully, add upstream
        (tracking) reference, used by argument-less
        linkgit:git-pull[1] and other commands. For more information,
        see `branch.<name>.merge` and `branch.<name>.remote` in
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 7586c5a8437edfc146fa3b802bc5e72e5070ee9a..0e993e458717743e4e2f136d27f7291101853bba 100644 (file)
@@ -17,7 +17,7 @@ The command takes various subcommands, and different options depending
 on the subcommand:
 
  git bisect start [--term-{old,good}=<term> --term-{new,bad}=<term>]
-                 [--no-checkout] [<bad> [<good>...]] [--] [<paths>...]
+                 [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]
  git bisect (bad|new|<term-new>) [<rev>]
  git bisect (good|old|<term-old>) [<rev>...]
  git bisect terms [--term-good | --term-bad]
@@ -365,6 +365,17 @@ does not require a checked out tree.
 +
 If the repository is bare, `--no-checkout` is assumed.
 
+--first-parent::
++
+Follow only the first parent commit upon seeing a merge commit.
++
+In detecting regressions introduced through the merging of a branch, the merge
+commit will be identified as introduction of the bug and its ancestors will be
+ignored.
++
+This option is particularly useful in avoiding false positives when a merged
+branch contained broken or non-buildable commits, but the merge itself was OK.
+
 EXAMPLES
 --------
 
index ac74d058e01d13830b276616dce25d5745b64699..af0c26232c1e775cf5f4d56ee67c07b6a73a9104 100644 (file)
@@ -100,6 +100,8 @@ OPTIONS
        value is set or outside a repository.
 +
 This option cannot be used with --stdin.
++
+include::object-format-disclaimer.txt[]
 
 NOTES
 -----
index ddfe265da5b6524f30d972bfea990bb2a89b5611..f35f70f13d0385e24ba2c0727e3720b4a068a048 100644 (file)
@@ -53,6 +53,8 @@ current working directory.
 
 Specify the given object format (hash algorithm) for the repository.  The valid
 values are 'sha1' and (if enabled) 'sha256'.  'sha1' is the default.
++
+include::object-format-disclaimer.txt[]
 
 --template=<template_directory>::
 
index 3fd26d52122b5a1b694fb33de9e34a37233d72f4..2b8ac5ff882ae84d52d08458c2439f314d2a0370 100644 (file)
@@ -114,8 +114,51 @@ include::rev-list-options.txt[]
 
 include::pretty-formats.txt[]
 
-COMMON DIFF OPTIONS
--------------------
+DIFF FORMATTING
+---------------
+
+By default, `git log` does not generate any diff output. The options
+below can be used to show the changes made by each commit.
+
+Note that unless one of `-c`, `--cc`, or `-m` is given, merge commits
+will never show a diff, even if a diff format like `--patch` is
+selected, nor will they match search options like `-S`. The exception is
+when `--first-parent` is in use, in which merges are treated like normal
+single-parent commits (this can be overridden by providing a
+combined-diff option or with `--no-diff-merges`).
+
+-c::
+       With this option, diff output for a merge commit
+       shows the differences from each of the parents to the merge result
+       simultaneously instead of showing pairwise diff between a parent
+       and the result one at a time. Furthermore, it lists only files
+       which were modified from all parents.
+
+--cc::
+       This flag implies the `-c` option and further compresses the
+       patch output by omitting uninteresting hunks whose contents in
+       the parents have only two variants and the merge result picks
+       one of them without modification.
+
+--combined-all-paths::
+       This flag causes combined diffs (used for merge commits) to
+       list the name of the file from all parents.  It thus only has
+       effect when -c or --cc are specified, and is likely only
+       useful if filename changes are detected (i.e. when either
+       rename or copy detection have been requested).
+
+-m::
+       This flag makes the merge commits show the full diff like
+       regular commits; for each merge parent, a separate log entry
+       and diff is generated. An exception is that only diff against
+       the first parent is shown when `--first-parent` option is given;
+       in that case, the output represents the changes the merge
+       brought _into_ the then-current branch.
+
+--diff-merges=off::
+--no-diff-merges::
+       Disable output of diffs for merge commits (default). Useful to
+       override `-m`, `-c`, or `--cc`.
 
 :git-log: 1
 include::diff-options.txt[]
index 0c6619493c1eddd92323c620e4ae374a7c6a4b91..eb0caa04393a7136e125c95038b6b740bc215086 100644 (file)
@@ -51,11 +51,12 @@ repack::
        multi-pack-index, then divide by the total number of objects in
        the pack and multiply by the pack size. We select packs with
        expected size below the batch size until the set of packs have
-       total expected size at least the batch size. If the total size
-       does not reach the batch size, then do nothing. If a new pack-
-       file is created, rewrite the multi-pack-index to reference the
-       new pack-file. A later run of 'git multi-pack-index expire' will
-       delete the pack-files that were part of this batch.
+       total expected size at least the batch size, or all pack-files
+       are considered. If only one pack-file is selected, then do
+       nothing. If a new pack-file is created, rewrite the
+       multi-pack-index to reference the new pack-file. A later run of
+       'git multi-pack-index expire' will delete the pack-files that
+       were part of this batch.
 +
 If `repack.packKeptObjects` is `false`, then any pack-files with an
 associated `.keep` file will not be selected for the batch to repack.
index eaa2f2a4041f2eed78aea08131b1120fb195aaf7..54d715ead1373d0feb4eee512fbe8ea8b446216c 100644 (file)
@@ -270,15 +270,18 @@ So does `git bundle` (see linkgit:git-bundle[1]) when it creates a bundle.
        This option specifies how missing objects are handled.
 +
 The form '--missing=error' requests that pack-objects stop with an error if
-a missing object is encountered.  This is the default action.
+a missing object is encountered.  If the repository is a partial clone, an
+attempt to fetch missing objects will be made before declaring them missing.
+This is the default action.
 +
 The form '--missing=allow-any' will allow object traversal to continue
-if a missing object is encountered.  Missing objects will silently be
-omitted from the results.
+if a missing object is encountered.  No fetch of a missing object will occur.
+Missing objects will silently be omitted from the results.
 +
 The form '--missing=allow-promisor' is like 'allow-any', but will only
 allow object traversal to continue for EXPECTED promisor missing objects.
-Unexpected missing object will raise an error.
+No fetch of a missing object will occur.  An unexpected missing object will
+raise an error.
 
 --exclude-promisor-objects::
        Omit objects that are known to be in the promisor remote.  (This
index 374d2486f71c6659d48ea6105e877d89b9fe8d28..e8df8d521467e433aeaa2568772957dfa1f2bf35 100644 (file)
@@ -459,17 +459,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 +628,6 @@ INCOMPATIBLE OPTIONS
 The following options:
 
  * --apply
- * --committer-date-is-author-date
- * --ignore-date
- * --ignore-whitespace
  * --whitespace
  * -C
 
@@ -636,6 +654,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 39b1d8eaa1456f60af07de2e30f0653f9d5efd64..e49318a5a0aec7f46c6d23dbff5afcb920fae236 100644 (file)
@@ -44,6 +44,8 @@ OPTIONS
        valid values are 'sha1' and (if enabled) 'sha256'.  The default is the
        algorithm for the current repository (set by `extensions.objectFormat`), or
        'sha1' if no value is set or outside a repository..
++
+include::object-format-disclaimer.txt[]
 
 GIT
 ---
index 3e737c236074849377e3766c55f4533a270c436f..d401234b03ce85722ff9624acb16c125d3780b27 100644 (file)
@@ -148,12 +148,13 @@ still see a subset of the modifications.
 
 LOGGING UPDATES
 ---------------
-If config parameter "core.logAllRefUpdates" is true and the ref is one under
-"refs/heads/", "refs/remotes/", "refs/notes/", or the symbolic ref HEAD; or
-the file "$GIT_DIR/logs/<ref>" exists then `git update-ref` will append
-a line to the log file "$GIT_DIR/logs/<ref>" (dereferencing all
-symbolic refs before creating the log name) describing the change
-in ref value.  Log lines are formatted as:
+If config parameter "core.logAllRefUpdates" is true and the ref is one
+under "refs/heads/", "refs/remotes/", "refs/notes/", or a pseudoref
+like HEAD or ORIG_HEAD; or the file "$GIT_DIR/logs/<ref>" exists then
+`git update-ref` will append a line to the log file
+"$GIT_DIR/logs/<ref>" (dereferencing all symbolic refs before creating
+the log name) describing the change in ref value.  Log lines are
+formatted as:
 
     oldsha1 SP newsha1 SP committer LF
 
index 81349a84e73f76a8303dffa3d0d9a5bc71314f3e..2fc92586b52386c770bed28a11275c64eea3414a 100644 (file)
@@ -504,7 +504,8 @@ double-quotes and respecting backslash escapes. E.g., the value
        If this variable is set, the default hash algorithm for new
        repositories will be set to this value. This value is currently
        ignored when cloning; the setting of the remote repository
-       is used instead. The default is "sha1".
+       is used instead. The default is "sha1". THIS VARIABLE IS
+       EXPERIMENTAL! See `--object-format` in linkgit:git-init[1].
 
 Git Commits
 ~~~~~~~~~~~
diff --git a/Documentation/object-format-disclaimer.txt b/Documentation/object-format-disclaimer.txt
new file mode 100644 (file)
index 0000000..4cb106f
--- /dev/null
@@ -0,0 +1,6 @@
+THIS OPTION IS EXPERIMENTAL! SHA-256 support is experimental and still
+in an early stage.  A SHA-256 repository will in general not be able to
+share work with "regular" SHA-1 repositories.  It should be assumed
+that, e.g., Git internal file formats in relation to SHA-256
+repositories may change in backwards-incompatible ways.  Only use
+`--object-format=sha256` for testing purposes.
index b01b2b677303aeb2575a594c5af781e8391fae51..002379056a072cb87f7c65bbcaedaa4ebed7387a 100644 (file)
@@ -128,8 +128,7 @@ parents) and `--max-parents=-1` (negative numbers denote no upper limit).
        because merges into a topic branch tend to be only about
        adjusting to updated upstream from time to time, and
        this option allows you to ignore the individual commits
-       brought in to your history by such a merge. Cannot be
-       combined with --bisect.
+       brought in to your history by such a merge.
 
 --not::
        Reverses the meaning of the '{caret}' prefix (or lack thereof)
@@ -207,7 +206,7 @@ ifndef::git-rev-list[]
        Pretend as if the bad bisection ref `refs/bisect/bad`
        was listed and as if it was followed by `--not` and the good
        bisection refs `refs/bisect/good-*` on the command
-       line. Cannot be combined with --first-parent.
+       line.
 endif::git-rev-list[]
 
 --stdin::
@@ -743,7 +742,7 @@ outputs 'midpoint', the output of the two commands
 would be of roughly the same length.  Finding the change which
 introduces a regression is thus reduced to a binary search: repeatedly
 generate and test new 'midpoint's until the commit chain is of length
-one. Cannot be combined with --first-parent.
+one.
 
 --bisect-vars::
        This calculates the same as `--bisect`, except that refs in
@@ -1117,48 +1116,3 @@ ifdef::git-rev-list[]
        by a tab.
 endif::git-rev-list[]
 endif::git-shortlog[]
-
-ifndef::git-shortlog[]
-ifndef::git-rev-list[]
-Diff Formatting
-~~~~~~~~~~~~~~~
-
-Listed below are options that control the formatting of diff output.
-Some of them are specific to linkgit:git-rev-list[1], however other diff
-options may be given. See linkgit:git-diff-files[1] for more options.
-
--c::
-       With this option, diff output for a merge commit
-       shows the differences from each of the parents to the merge result
-       simultaneously instead of showing pairwise diff between a parent
-       and the result one at a time. Furthermore, it lists only files
-       which were modified from all parents.
-
---cc::
-       This flag implies the `-c` option and further compresses the
-       patch output by omitting uninteresting hunks whose contents in
-       the parents have only two variants and the merge result picks
-       one of them without modification.
-
---combined-all-paths::
-       This flag causes combined diffs (used for merge commits) to
-       list the name of the file from all parents.  It thus only has
-       effect when -c or --cc are specified, and is likely only
-       useful if filename changes are detected (i.e. when either
-       rename or copy detection have been requested).
-
--m::
-       This flag makes the merge commits show the full diff like
-       regular commits; for each merge parent, a separate log entry
-       and diff is generated. An exception is that only diff against
-       the first parent is shown when `--first-parent` option is given;
-       in that case, the output represents the changes the merge
-       brought _into_ the then-current branch.
-
--r::
-       Show recursive diffs.
-
--t::
-       Show the tree objects in the diff output. This implies `-r`.
-endif::git-rev-list[]
-endif::git-shortlog[]
index 440541045d45c2ef162ca747f9f2ad4dc7d88c92..6ddbceba15c9708385ba51f339bf232c15753648 100644 (file)
@@ -42,8 +42,13 @@ HEADER:
   1-byte version number:
       Currently, the only valid version is 1.
 
-  1-byte Hash Version (1 = SHA-1)
-      We infer the hash length (H) from this value.
+  1-byte Hash Version
+      We infer the hash length (H) from this value:
+       1 => SHA-1
+       2 => SHA-256
+      If the hash type does not match the repository's hash algorithm, the
+      commit-graph file should be ignored with a warning presented to the
+      user.
 
   1-byte number (C) of "chunks"
 
index 808fa30b99f26456ed0867caffc0294676a9afa0..f14a7659aa8733a2a992eb949caf1d4e7a67accf 100644 (file)
@@ -210,12 +210,12 @@ file.
                            +---------------------+
                            |                     |
  +-----------------------+  +---------------------+
- |  graph-{hash2} |->|                     |
+ |  graph-{hash2}        |->|                     |
  +-----------------------+  +---------------------+
          |                 |                     |
  +-----------------------+  +---------------------+
  |                       |  |                     |
- |  graph-{hash1} |->|                     |
+ |  graph-{hash1}        |->|                     |
  |                       |  |                     |
  +-----------------------+  +---------------------+
          |                  tmp_graphXXX
@@ -223,7 +223,7 @@ file.
  |                       |
  |                       |
  |                       |
- |  graph-{hash0} |
+ |  graph-{hash0}        |
  |                       |
  |                       |
  |                       |
index 5b2db3be1ecc448ade0529fea12752be53fa1930..6fd20ebbc254472936238a8db590585e93d5eb91 100644 (file)
@@ -650,7 +650,6 @@ Some initial steps can be implemented independently of one another:
 
 The first user-visible change is the introduction of the objectFormat
 extension (without compatObjectFormat). This requires:
-- implementing the loose-object-idx
 - teaching fsck about this mode of operation
 - using the hash function API (vtable) when computing object names
 - signing objects and verifying signatures
@@ -658,6 +657,7 @@ extension (without compatObjectFormat). This requires:
   repository
 
 Next comes introduction of compatObjectFormat:
+- implementing the loose-object-idx
 - translating object names between object formats
 - translating object content between object formats
 - generating and verifying signatures in the compat format
index 51a79e63de9b77656ec225ea3e8d38289d9e4ae8..96d89ea9b226136603a041e96789709c979883fd 100644 (file)
@@ -401,8 +401,9 @@ at all in the request stream:
 The stream is terminated by a pkt-line flush (`0000`).
 
 A single "want" or "have" command MUST have one hex formatted
-SHA-1 as its value.  Multiple SHA-1s MUST be sent by sending
-multiple commands.
+object name as its value.  Multiple object names MUST be sent by sending
+multiple commands. Object names MUST be given using the object format
+negotiated through the `object-format` capability (default SHA-1).
 
 The `have` list is created by popping the first 32 commits
 from `c_pending`.  Less can be supplied if `c_pending` empties.
index faa25c5c527e72bb63ae66e834b20e7f3f1a519a..f9a3644711b903336587333923a0203fa5fe9d86 100644 (file)
@@ -3,8 +3,11 @@ Git index format
 
 == The Git index file has the following format
 
-  All binary numbers are in network byte order. Version 2 is described
-  here unless stated otherwise.
+  All binary numbers are in network byte order.
+  In a repository using the traditional SHA-1, checksums and object IDs
+  (object names) mentioned below are all computed using SHA-1.  Similarly,
+  in SHA-256 repositories, these values are computed using SHA-256.
+  Version 2 is described here unless stated otherwise.
 
    - A 12-byte header consisting of
 
@@ -32,8 +35,7 @@ Git index format
 
      Extension data
 
-   - 160-bit SHA-1 over the content of the index file before this
-     checksum.
+   - Hash checksum over the content of the index file before this checksum.
 
 == Index entry
 
@@ -80,7 +82,7 @@ Git index format
   32-bit file size
     This is the on-disk size from stat(2), truncated to 32-bit.
 
-  160-bit SHA-1 for the represented object
+  Object name for the represented object
 
   A 16-bit 'flags' field split into (high to low bits)
 
@@ -160,8 +162,8 @@ Git index format
 
   - A newline (ASCII 10); and
 
-  - 160-bit object name for the object that would result from writing
-    this span of index as a tree.
+  - Object name for the object that would result from writing this span
+    of index as a tree.
 
   An entry can be in an invalidated state and is represented by having
   a negative number in the entry_count field. In this case, there is no
@@ -198,7 +200,7 @@ Git index format
     stage 1 to 3 (a missing stage is represented by "0" in this field);
     and
 
-  - At most three 160-bit object names of the entry in stages from 1 to 3
+  - At most three object names of the entry in stages from 1 to 3
     (nothing is written for a missing stage).
 
 === Split index
@@ -211,8 +213,8 @@ Git index format
 
   The extension consists of:
 
-  - 160-bit SHA-1 of the shared index file. The shared index file path
-    is $GIT_DIR/sharedindex.<SHA-1>. If all 160 bits are zero, the
+  - Hash of the shared index file. The shared index file path
+    is $GIT_DIR/sharedindex.<hash>. If all bits are zero, the
     index does not require a shared index file.
 
   - An ewah-encoded delete bitmap, each bit represents an entry in the
@@ -253,10 +255,10 @@ Git index format
 
   - 32-bit dir_flags (see struct dir_struct)
 
-  - 160-bit SHA-1 of $GIT_DIR/info/exclude. Null SHA-1 means the file
+  - Hash of $GIT_DIR/info/exclude. A null hash means the file
     does not exist.
 
-  - 160-bit SHA-1 of core.excludesfile. Null SHA-1 means the file does
+  - Hash of core.excludesfile. A null hash means the file does
     not exist.
 
   - NUL-terminated string of per-dir exclude file name. This usually
@@ -285,13 +287,13 @@ The remaining data of each directory block is grouped by type:
   - An ewah bitmap, the n-th bit records "check-only" bit of
     read_directory_recursive() for the n-th directory.
 
-  - An ewah bitmap, the n-th bit indicates whether SHA-1 and stat data
+  - An ewah bitmap, the n-th bit indicates whether hash and stat data
     is valid for the n-th directory and exists in the next data.
 
   - An array of stat data. The n-th data corresponds with the n-th
     "one" bit in the previous ewah bitmap.
 
-  - An array of SHA-1. The n-th SHA-1 corresponds with the n-th "one" bit
+  - An array of hashes. The n-th hash corresponds with the n-th "one" bit
     in the previous ewah bitmap.
 
   - One NUL.
@@ -330,12 +332,12 @@ The remaining data of each directory block is grouped by type:
 
   - 32-bit offset to the end of the index entries
 
-  - 160-bit SHA-1 over the extension types and their sizes (but not
+  - Hash over the extension types and their sizes (but not
        their contents).  E.g. if we have "TREE" extension that is N-bytes
        long, "REUC" extension that is M-bytes long, followed by "EOIE",
        then the hash would be:
 
-       SHA-1("TREE" + <binary representation of N> +
+       Hash("TREE" + <binary representation of N> +
                "REUC" + <binary representation of M>)
 
 == Index Entry Offset Table
index d3a142c6520258033f95b7e427be41f930883f99..f96b2e605f3486d389c0bb0674c060d7f52fe38a 100644 (file)
@@ -1,6 +1,12 @@
 Git pack format
 ===============
 
+== Checksums and object IDs
+
+In a repository using the traditional SHA-1, pack checksums, index checksums,
+and object IDs (object names) mentioned below are all computed using SHA-1.
+Similarly, in SHA-256 repositories, these values are computed using SHA-256.
+
 == pack-*.pack files have the following format:
 
    - A header appears at the beginning and consists of the following:
@@ -26,7 +32,7 @@ Git pack format
 
      (deltified representation)
      n-byte type and length (3-bit type, (n-1)*7+4-bit length)
-     20-byte base object name if OBJ_REF_DELTA or a negative relative
+     base object name if OBJ_REF_DELTA or a negative relative
         offset from the delta object's position in the pack if this
         is an OBJ_OFS_DELTA object
      compressed delta data
@@ -34,7 +40,7 @@ Git pack format
      Observation: length of each object is encoded in a variable
      length format and is not constrained to 32-bit or anything.
 
-  - The trailer records 20-byte SHA-1 checksum of all of the above.
+  - The trailer records a pack checksum of all of the above.
 
 === Object types
 
@@ -58,8 +64,8 @@ ofs-delta and ref-delta, which is only valid in a pack file.
 
 Both ofs-delta and ref-delta store the "delta" to be applied to
 another object (called 'base object') to reconstruct the object. The
-difference between them is, ref-delta directly encodes 20-byte base
-object name. If the base object is in the same pack, ofs-delta encodes
+difference between them is, ref-delta directly encodes base object
+name. If the base object is in the same pack, ofs-delta encodes
 the offset of the base object in the pack instead.
 
 The base object could also be deltified if it's in the same pack.
@@ -143,14 +149,14 @@ This is the instruction reserved for future expansion.
     object is stored in the packfile as the offset from the
     beginning.
 
-    20-byte object name.
+    one object name of the appropriate size.
 
   - The file is concluded with a trailer:
 
-    A copy of the 20-byte SHA-1 checksum at the end of
-    corresponding packfile.
+    A copy of the pack checksum at the end of the corresponding
+    packfile.
 
-    20-byte SHA-1-checksum of all of the above.
+    Index checksum of all of the above.
 
 Pack Idx file:
 
@@ -198,7 +204,7 @@ Pack file entry: <+
         If it is not DELTA, then deflated bytes (the size above
                is the size before compression).
        If it is REF_DELTA, then
-         20-byte base object name SHA-1 (the size above is the
+         base object name (the size above is the
                size of the delta data that follows).
           delta data, deflated.
        If it is OFS_DELTA, then
@@ -227,9 +233,9 @@ Pack file entry: <+
 
   - A 256-entry fan-out table just like v1.
 
-  - A table of sorted 20-byte SHA-1 object names.  These are
-    packed together without offset values to reduce the cache
-    footprint of the binary search for a specific object name.
+  - A table of sorted object names.  These are packed together
+    without offset values to reduce the cache footprint of the
+    binary search for a specific object name.
 
   - A table of 4-byte CRC32 values of the packed object data.
     This is new in v2 so compressed data can be copied directly
@@ -248,10 +254,10 @@ Pack file entry: <+
 
   - The same trailer as a v1 pack file:
 
-    A copy of the 20-byte SHA-1 checksum at the end of
+    A copy of the pack checksum at the end of
     corresponding packfile.
 
-    20-byte SHA-1-checksum of all of the above.
+    Index checksum of all of the above.
 
 == multi-pack-index (MIDX) files have the following format:
 
@@ -273,7 +279,12 @@ HEADER:
            Git only writes or recognizes version 1.
 
        1-byte Object Id Version
-           Git only writes or recognizes version 1 (SHA1).
+           We infer the length of object IDs (OIDs) from this value:
+               1 => SHA-1
+               2 => SHA-256
+           If the hash type does not match the repository's hash algorithm,
+           the multi-pack-index file should be ignored with a warning
+           presented to the user.
 
        1-byte number of "chunks"
 
@@ -329,4 +340,4 @@ CHUNK DATA:
 
 TRAILER:
 
-       20-byte SHA1-checksum of the above contents.
+       Index checksum of the above contents.
index 36ccd14f97ed4631078fbac5cf65940840d3e197..124d716807eb3e90802282782705dd096be99e43 100644 (file)
@@ -324,15 +324,19 @@ allow-tip-sha1-in-want
 ----------------------
 
 If the upload-pack server advertises this capability, fetch-pack may
-send "want" lines with SHA-1s that exist at the server but are not
-advertised by upload-pack.
+send "want" lines with object names that exist at the server but are not
+advertised by upload-pack. For historical reasons, the name of this
+capability contains "sha1". Object names are always given using the
+object format negotiated through the 'object-format' capability.
 
 allow-reachable-sha1-in-want
 ----------------------------
 
 If the upload-pack server advertises this capability, fetch-pack may
-send "want" lines with SHA-1s that exist at the server but are not
-advertised by upload-pack.
+send "want" lines with object names that exist at the server but are not
+advertised by upload-pack. For historical reasons, the name of this
+capability contains "sha1". Object names are always given using the
+object format negotiated through the 'object-format' capability.
 
 push-cert=<nonce>
 -----------------
index 01dedfe9ffedc28c2c6ac5ef15dbb3c5fe519cc0..f3738baa0f0580cc92e3c1a604e16715ac2608a3 100644 (file)
@@ -13,7 +13,7 @@ pretend as if they are root commits (e.g. "git log" traversal
 stops after showing them; "git fsck" does not complain saying
 the commits listed on their "parent" lines do not exist).
 
-Each line contains exactly one SHA-1. When read, a commit_graft
+Each line contains exactly one object name. When read, a commit_graft
 will be constructed, which has nr_parent < 0 to make it easier
 to discern from user provided grafts.
 
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;
diff --git a/apply.c b/apply.c
index 8bff604dbe203402d93bd13fe5b03d635a7a50ee..76dba93c974b3814117e3856d875e7e4381d2f62 100644 (file)
--- a/apply.c
+++ b/apply.c
@@ -30,8 +30,8 @@ struct gitdiff_data {
 
 static void git_apply_config(void)
 {
-       git_config_get_string_const("apply.whitespace", &apply_default_whitespace);
-       git_config_get_string_const("apply.ignorewhitespace", &apply_default_ignorewhitespace);
+       git_config_get_string("apply.whitespace", &apply_default_whitespace);
+       git_config_get_string("apply.ignorewhitespace", &apply_default_ignorewhitespace);
        git_config(git_xmerge_config, NULL);
 }
 
@@ -3178,7 +3178,7 @@ static int apply_binary(struct apply_state *state,
                return 0; /* deletion patch */
        }
 
-       if (has_object_file(&oid)) {
+       if (has_object(the_repository, &oid, 0)) {
                /* We already have the postimage */
                enum object_type type;
                unsigned long size;
@@ -3740,6 +3740,7 @@ static int check_preimage(struct apply_state *state,
 
 #define EXISTS_IN_INDEX 1
 #define EXISTS_IN_WORKTREE 2
+#define EXISTS_IN_INDEX_AS_ITA 3
 
 static int check_to_create(struct apply_state *state,
                           const char *new_name,
@@ -3747,10 +3748,23 @@ static int check_to_create(struct apply_state *state,
 {
        struct stat nst;
 
-       if (state->check_index &&
-           index_name_pos(state->repo->index, new_name, strlen(new_name)) >= 0 &&
-           !ok_if_exists)
-               return EXISTS_IN_INDEX;
+       if (state->check_index && (!ok_if_exists || !state->cached)) {
+               int pos;
+
+               pos = index_name_pos(state->repo->index, new_name, strlen(new_name));
+               if (pos >= 0) {
+                       struct cache_entry *ce = state->repo->index->cache[pos];
+
+                       /* allow ITA, as they do not yet exist in the index */
+                       if (!ok_if_exists && !(ce->ce_flags & CE_INTENT_TO_ADD))
+                               return EXISTS_IN_INDEX;
+
+                       /* ITA entries can never match working tree files */
+                       if (!state->cached && (ce->ce_flags & CE_INTENT_TO_ADD))
+                               return EXISTS_IN_INDEX_AS_ITA;
+               }
+       }
+
        if (state->cached)
                return 0;
 
@@ -3935,6 +3949,9 @@ static int check_patch(struct apply_state *state, struct patch *patch)
                case EXISTS_IN_INDEX:
                        return error(_("%s: already exists in index"), new_name);
                        break;
+               case EXISTS_IN_INDEX_AS_ITA:
+                       return error(_("%s: does not match index"), new_name);
+                       break;
                case EXISTS_IN_WORKTREE:
                        return error(_("%s: already exists in working directory"),
                                     new_name);
index a088a0f82eec47247fc1eb938afcb6636d071ff2..d42a3a3767d60bd36af1d57aabd8adc1be5fd378 100644 (file)
--- a/bisect.c
+++ b/bisect.c
@@ -15,6 +15,7 @@
 #include "commit-slab.h"
 #include "commit-reach.h"
 #include "object-store.h"
+#include "dir.h"
 
 static struct oid_array good_revs;
 static struct oid_array skipped_revs;
@@ -88,15 +89,16 @@ static inline void weight_set(struct commit_list *elem, int weight)
        **commit_weight_at(&commit_weight, elem->item) = weight;
 }
 
-static int count_interesting_parents(struct commit *commit)
+static int count_interesting_parents(struct commit *commit, unsigned bisect_flags)
 {
        struct commit_list *p;
        int count;
 
        for (count = 0, p = commit->parents; p; p = p->next) {
-               if (p->item->object.flags & UNINTERESTING)
-                       continue;
-               count++;
+               if (!(p->item->object.flags & UNINTERESTING))
+                       count++;
+               if (bisect_flags & FIND_BISECTION_FIRST_PARENT_ONLY)
+                       break;
        }
        return count;
 }
@@ -135,7 +137,7 @@ static void show_list(const char *debug, int counted, int nr,
        for (p = list; p; p = p->next) {
                struct commit_list *pp;
                struct commit *commit = p->item;
-               unsigned flags = commit->object.flags;
+               unsigned commit_flags = commit->object.flags;
                enum object_type type;
                unsigned long size;
                char *buf = read_object_file(&commit->object.oid, &type,
@@ -144,9 +146,9 @@ static void show_list(const char *debug, int counted, int nr,
                int subject_len;
 
                fprintf(stderr, "%c%c%c ",
-                       (flags & TREESAME) ? ' ' : 'T',
-                       (flags & UNINTERESTING) ? 'U' : ' ',
-                       (flags & COUNTED) ? 'C' : ' ');
+                       (commit_flags & TREESAME) ? ' ' : 'T',
+                       (commit_flags & UNINTERESTING) ? 'U' : ' ',
+                       (commit_flags & COUNTED) ? 'C' : ' ');
                if (*commit_weight_at(&commit_weight, p->item))
                        fprintf(stderr, "%3d", weight(p));
                else
@@ -171,9 +173,9 @@ static struct commit_list *best_bisection(struct commit_list *list, int nr)
        best = list;
        for (p = list; p; p = p->next) {
                int distance;
-               unsigned flags = p->item->object.flags;
+               unsigned commit_flags = p->item->object.flags;
 
-               if (flags & TREESAME)
+               if (commit_flags & TREESAME)
                        continue;
                distance = weight(p);
                if (nr - distance < distance)
@@ -212,9 +214,9 @@ static struct commit_list *best_bisection_sorted(struct commit_list *list, int n
 
        for (p = list, cnt = 0; p; p = p->next) {
                int distance;
-               unsigned flags = p->item->object.flags;
+               unsigned commit_flags = p->item->object.flags;
 
-               if (flags & TREESAME)
+               if (commit_flags & TREESAME)
                        continue;
                distance = weight(p);
                if (nr - distance < distance)
@@ -259,7 +261,7 @@ static struct commit_list *best_bisection_sorted(struct commit_list *list, int n
  */
 static struct commit_list *do_find_bisection(struct commit_list *list,
                                             int nr, int *weights,
-                                            int find_all)
+                                            unsigned bisect_flags)
 {
        int n, counted;
        struct commit_list *p;
@@ -268,12 +270,12 @@ static struct commit_list *do_find_bisection(struct commit_list *list,
 
        for (n = 0, p = list; p; p = p->next) {
                struct commit *commit = p->item;
-               unsigned flags = commit->object.flags;
+               unsigned commit_flags = commit->object.flags;
 
                *commit_weight_at(&commit_weight, p->item) = &weights[n++];
-               switch (count_interesting_parents(commit)) {
+               switch (count_interesting_parents(commit, bisect_flags)) {
                case 0:
-                       if (!(flags & TREESAME)) {
+                       if (!(commit_flags & TREESAME)) {
                                weight_set(p, 1);
                                counted++;
                                show_list("bisection 2 count one",
@@ -314,11 +316,13 @@ static struct commit_list *do_find_bisection(struct commit_list *list,
                        continue;
                if (weight(p) != -2)
                        continue;
+               if (bisect_flags & FIND_BISECTION_FIRST_PARENT_ONLY)
+                       BUG("shouldn't be calling count-distance in fp mode");
                weight_set(p, count_distance(p));
                clear_distance(list);
 
                /* Does it happen to be at exactly half-way? */
-               if (!find_all && halfway(p, nr))
+               if (!(bisect_flags & FIND_BISECTION_ALL) && halfway(p, nr))
                        return p;
                counted++;
        }
@@ -328,11 +332,14 @@ static struct commit_list *do_find_bisection(struct commit_list *list,
        while (counted < nr) {
                for (p = list; p; p = p->next) {
                        struct commit_list *q;
-                       unsigned flags = p->item->object.flags;
+                       unsigned commit_flags = p->item->object.flags;
 
                        if (0 <= weight(p))
                                continue;
-                       for (q = p->item->parents; q; q = q->next) {
+
+                       for (q = p->item->parents;
+                            q;
+                            q = bisect_flags & FIND_BISECTION_FIRST_PARENT_ONLY ? NULL : q->next) {
                                if (q->item->object.flags & UNINTERESTING)
                                        continue;
                                if (0 <= weight(q))
@@ -346,7 +353,7 @@ static struct commit_list *do_find_bisection(struct commit_list *list,
                         * add one for p itself if p is to be counted,
                         * otherwise inherit it from q directly.
                         */
-                       if (!(flags & TREESAME)) {
+                       if (!(commit_flags & TREESAME)) {
                                weight_set(p, weight(q)+1);
                                counted++;
                                show_list("bisection 2 count one",
@@ -356,21 +363,21 @@ static struct commit_list *do_find_bisection(struct commit_list *list,
                                weight_set(p, weight(q));
 
                        /* Does it happen to be at exactly half-way? */
-                       if (!find_all && halfway(p, nr))
+                       if (!(bisect_flags & FIND_BISECTION_ALL) && halfway(p, nr))
                                return p;
                }
        }
 
        show_list("bisection 2 counted all", counted, nr, list);
 
-       if (!find_all)
+       if (!(bisect_flags & FIND_BISECTION_ALL))
                return best_bisection(list, nr);
        else
                return best_bisection_sorted(list, nr);
 }
 
 void find_bisection(struct commit_list **commit_list, int *reaches,
-                   int *all, int find_all)
+                   int *all, unsigned bisect_flags)
 {
        int nr, on_list;
        struct commit_list *list, *p, *best, *next, *last;
@@ -386,16 +393,16 @@ void find_bisection(struct commit_list **commit_list, int *reaches,
        for (nr = on_list = 0, last = NULL, p = *commit_list;
             p;
             p = next) {
-               unsigned flags = p->item->object.flags;
+               unsigned commit_flags = p->item->object.flags;
 
                next = p->next;
-               if (flags & UNINTERESTING) {
+               if (commit_flags & UNINTERESTING) {
                        free(p);
                        continue;
                }
                p->next = last;
                last = p;
-               if (!(flags & TREESAME))
+               if (!(commit_flags & TREESAME))
                        nr++;
                on_list++;
        }
@@ -406,9 +413,9 @@ void find_bisection(struct commit_list **commit_list, int *reaches,
        weights = xcalloc(on_list, sizeof(*weights));
 
        /* Do the real work of finding bisection commit. */
-       best = do_find_bisection(list, nr, weights, find_all);
+       best = do_find_bisection(list, nr, weights, bisect_flags);
        if (best) {
-               if (!find_all) {
+               if (!(bisect_flags & FIND_BISECTION_ALL)) {
                        list->item = best->item;
                        free_commit_list(list->next);
                        best = list;
@@ -454,6 +461,7 @@ static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
 static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
 static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
 static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS")
+static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
 static GIT_PATH_FUNC(git_path_head_name, "head-name")
 
 static void read_bisect_paths(struct strvec *array)
@@ -983,7 +991,7 @@ void read_bisect_terms(const char **read_bad, const char **read_good)
  * If no_checkout is non-zero, the bisection process does not
  * checkout the trial commit but instead simply updates BISECT_HEAD.
  */
-enum bisect_error bisect_next_all(struct repository *r, const char *prefix, int no_checkout)
+enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
 {
        struct rev_info revs;
        struct commit_list *tried;
@@ -991,21 +999,31 @@ enum bisect_error bisect_next_all(struct repository *r, const char *prefix, int
        enum bisect_error res = BISECT_OK;
        struct object_id *bisect_rev;
        char *steps_msg;
+       int no_checkout = ref_exists("BISECT_HEAD");
+       unsigned bisect_flags = 0;
 
        read_bisect_terms(&term_bad, &term_good);
        if (read_bisect_refs())
                die(_("reading bisect refs failed"));
 
+       if (file_exists(git_path_bisect_first_parent()))
+               bisect_flags |= FIND_BISECTION_FIRST_PARENT_ONLY;
+
+       if (skipped_revs.nr)
+               bisect_flags |= FIND_BISECTION_ALL;
+
        res = check_good_are_ancestors_of_bad(r, prefix, no_checkout);
        if (res)
                return res;
 
        bisect_rev_setup(r, &revs, prefix, "%s", "^%s", 1);
+
+       revs.first_parent_only = !!(bisect_flags & FIND_BISECTION_FIRST_PARENT_ONLY);
        revs.limited = 1;
 
        bisect_common(&revs);
 
-       find_bisection(&revs.commits, &reaches, &all, !!skipped_revs.nr);
+       find_bisection(&revs.commits, &reaches, &all, bisect_flags);
        revs.commits = managed_skipped(revs.commits, &tried);
 
        if (!revs.commits) {
@@ -1133,6 +1151,7 @@ int bisect_clean_state(void)
        unlink_or_warn(git_path_bisect_names());
        unlink_or_warn(git_path_bisect_run());
        unlink_or_warn(git_path_bisect_terms());
+       unlink_or_warn(git_path_bisect_first_parent());
        /* Cleanup head-name if it got left by an old version of git-bisect */
        unlink_or_warn(git_path_head_name());
        /*
index 8bad8d8391546f347ec91324eca21f74bda8e68f..ec24ac2d7ee9d18fa6a9188534040602fd728e38 100644 (file)
--- a/bisect.h
+++ b/bisect.h
@@ -12,7 +12,7 @@ struct repository;
  * best commit, as chosen by `find_all`.
  */
 void find_bisection(struct commit_list **list, int *reaches, int *all,
-                   int find_all);
+                   unsigned bisect_flags);
 
 struct commit_list *filter_skipped(struct commit_list *list,
                                   struct commit_list **tried,
@@ -23,6 +23,9 @@ struct commit_list *filter_skipped(struct commit_list *list,
 #define BISECT_SHOW_ALL                (1<<0)
 #define REV_LIST_QUIET         (1<<1)
 
+#define FIND_BISECTION_ALL                     (1u<<0)
+#define FIND_BISECTION_FIRST_PARENT_ONLY       (1u<<1)
+
 struct rev_list_info {
        struct rev_info *revs;
        int flags;
@@ -58,9 +61,7 @@ enum bisect_error {
        BISECT_INTERNAL_SUCCESS_MERGE_BASE = -11
 };
 
-enum bisect_error bisect_next_all(struct repository *r,
-                   const char *prefix,
-                   int no_checkout);
+enum bisect_error bisect_next_all(struct repository *r, const char *prefix);
 
 int estimate_bisect_steps(int all);
 
diff --git a/blame.c b/blame.c
index 82fa16d6585b90e3635d87f6adc1e4856524f7d6..1be1cd82a29b781e6761f7281d8a8c3df89a0535 100644 (file)
--- a/blame.c
+++ b/blame.c
@@ -1184,6 +1184,7 @@ void blame_coalesce(struct blame_scoreboard *sb)
        for (ent = sb->ent; ent && (next = ent->next); ent = next) {
                if (ent->suspect == next->suspect &&
                    ent->s_lno + ent->num_lines == next->s_lno &&
+                   ent->lno + ent->num_lines == next->lno &&
                    ent->ignored == next->ignored &&
                    ent->unblamable == next->unblamable) {
                        ent->num_lines += next->num_lines;
index ab39a60a0d69e0cd1aa4f7be4166c74af9c49887..b36a99eb7c847fe3f67a716316b148c347d1792b 100644 (file)
@@ -534,11 +534,11 @@ int cmd_add(int argc, const char **argv, const char *prefix)
        die_in_unpopulated_submodule(&the_index, prefix);
        die_path_inside_submodule(&the_index, &pathspec);
 
+       dir_init(&dir);
        if (add_new_files) {
                int baselen;
 
                /* Set up the default git porcelain excludes */
-               memset(&dir, 0, sizeof(dir));
                if (!ignored_too) {
                        dir.flags |= DIR_COLLECT_IGNORED;
                        setup_standard_excludes(&dir);
@@ -611,7 +611,7 @@ finish:
                               COMMIT_LOCK | SKIP_IF_UNCHANGED))
                die(_("Unable to write new index file"));
 
+       dir_clear(&dir);
        UNLEAK(pathspec);
-       UNLEAK(dir);
        return exit_status;
 }
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 d19300687fe9dff04c5af08de8a63cce15e46f98..cdda279b23ca3c8ede39058a52a1b3a0f303b43d 100644 (file)
@@ -16,9 +16,10 @@ static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
 static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
 static GIT_PATH_FUNC(git_path_head_name, "head-name")
 static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
+static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
 
 static const char * const git_bisect_helper_usage[] = {
-       N_("git bisect--helper --next-all [--no-checkout]"),
+       N_("git bisect--helper --next-all"),
        N_("git bisect--helper --write-terms <bad_term> <good_term>"),
        N_("git bisect--helper --bisect-clean-state"),
        N_("git bisect--helper --bisect-reset [<commit>]"),
@@ -27,7 +28,7 @@ static const char * const git_bisect_helper_usage[] = {
        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>]"
-                                            "[--no-checkout] [<bad> [<good>...]] [--] [<paths>...]"),
+                                           " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
        NULL
 };
 
@@ -420,9 +421,10 @@ finish:
        return res;
 }
 
-static int bisect_start(struct bisect_terms *terms, int no_checkout,
-                       const char **argv, int argc)
+static int bisect_start(struct bisect_terms *terms, const char **argv, int argc)
 {
+       int no_checkout = 0;
+       int first_parent_only = 0;
        int i, has_double_dash = 0, must_write_terms = 0, bad_seen = 0;
        int flags, pathspec_pos, res = 0;
        struct string_list revs = STRING_LIST_INIT_DUP;
@@ -452,6 +454,8 @@ static int bisect_start(struct bisect_terms *terms, int no_checkout,
                        break;
                } else if (!strcmp(arg, "--no-checkout")) {
                        no_checkout = 1;
+               } else if (!strcmp(arg, "--first-parent")) {
+                       first_parent_only = 1;
                } else if (!strcmp(arg, "--term-good") ||
                         !strcmp(arg, "--term-old")) {
                        i++;
@@ -576,6 +580,9 @@ static int bisect_start(struct bisect_terms *terms, int no_checkout,
         */
        write_file(git_path_bisect_start(), "%s\n", start_head.buf);
 
+       if (first_parent_only)
+               write_file(git_path_bisect_first_parent(), "\n");
+
        if (no_checkout) {
                if (get_oid(start_head.buf, &oid) < 0) {
                        res = error(_("invalid ref: '%s'"), start_head.buf);
@@ -631,7 +638,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
                BISECT_TERMS,
                BISECT_START
        } cmdmode = 0;
-       int no_checkout = 0, res = 0, nolog = 0;
+       int res = 0, nolog = 0;
        struct option options[] = {
                OPT_CMDMODE(0, "next-all", &cmdmode,
                         N_("perform 'git bisect next'"), NEXT_ALL),
@@ -653,8 +660,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
                         N_("print out the bisect terms"), BISECT_TERMS),
                OPT_CMDMODE(0, "bisect-start", &cmdmode,
                         N_("start the bisect session"), BISECT_START),
-               OPT_BOOL(0, "no-checkout", &no_checkout,
-                        N_("update BISECT_HEAD instead of checking out the current commit")),
                OPT_BOOL(0, "no-log", &nolog,
                         N_("no log for BISECT_WRITE")),
                OPT_END()
@@ -670,7 +675,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 
        switch (cmdmode) {
        case NEXT_ALL:
-               res = bisect_next_all(the_repository, prefix, no_checkout);
+               res = bisect_next_all(the_repository, prefix);
                break;
        case WRITE_TERMS:
                if (argc != 2)
@@ -712,7 +717,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
                break;
        case BISECT_START:
                set_terms(&terms, "bad", "good");
-               res = bisect_start(&terms, no_checkout, argv, argc);
+               res = bisect_start(&terms, argv, argc);
                break;
        default:
                return error("BUG: unknown subcommand '%d'", cmdmode);
index 94ef57c1cc304963452772e24125e5939dff0481..eb513fbe60c34a6de505a9b99da0ff033f612622 100644 (file)
@@ -842,7 +842,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
        const char *contents_from = NULL;
        const struct option options[] = {
                OPT_BOOL(0, "incremental", &incremental, N_("Show blame entries as we find them, incrementally")),
-               OPT_BOOL('b', NULL, &blank_boundary, N_("Show blank SHA-1 for boundary commits (Default: off)")),
+               OPT_BOOL('b', NULL, &blank_boundary, N_("Do not show object names of boundary commits (Default: off)")),
                OPT_BOOL(0, "root", &show_root, N_("Do not treat root commits as boundaries (Default: off)")),
                OPT_BOOL(0, "show-stats", &show_stats, N_("Show work cost statistics")),
                OPT_BOOL(0, "progress", &show_progress, N_("Force progress reporting")),
index 9c920cc065895a3df8bf89795382daef7e718424..3ad4b9b62e8498c51d550358bc63724b74eabbce 100644 (file)
@@ -171,10 +171,8 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
        /* fopen doesn't offer us an O_EXCL alternative, except with glibc. */
        report = open(report_path.buf, O_CREAT | O_EXCL | O_WRONLY, 0666);
 
-       if (report < 0) {
-               UNLEAK(report_path);
+       if (report < 0)
                die(_("couldn't create a new file at '%s'"), report_path.buf);
-       }
 
        if (write_in_full(report, buffer.buf, buffer.len) < 0)
                die_errno(_("unable to write to %s"), report_path.buf);
index ea5d0ae3a6a6fff59424909b8be47aaabb824b7c..3c652748d58c69dec4378d01de58212f65763328 100644 (file)
@@ -180,7 +180,7 @@ int cmd_check_ignore(int argc, const char **argv, const char *prefix)
        if (!no_index && read_cache() < 0)
                die(_("index file corrupt"));
 
-       memset(&dir, 0, sizeof(dir));
+       dir_init(&dir);
        setup_standard_excludes(&dir);
 
        if (stdin_paths) {
@@ -190,7 +190,7 @@ int cmd_check_ignore(int argc, const char **argv, const char *prefix)
                maybe_flush_or_die(stdout, "ignore to stdout");
        }
 
-       clear_directory(&dir);
+       dir_clear(&dir);
 
        return !num_ignored;
 }
index 283719549120f23fff4441d450da604598c320c0..6ec82097a2a29c73d0b69a9329c93d8057dbb955 100644 (file)
@@ -1120,8 +1120,10 @@ static void setup_new_branch_info_and_source_tree(
        if (!check_refname_format(new_branch_info->path, 0) &&
            !read_ref(new_branch_info->path, &branch_rev))
                oidcpy(rev, &branch_rev);
-       else
+       else {
+               free((char *)new_branch_info->path);
                new_branch_info->path = NULL; /* not an existing branch */
+       }
 
        new_branch_info->commit = lookup_commit_reference_gently(the_repository, rev, 1);
        if (!new_branch_info->commit) {
@@ -1707,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 5a9c29a558bb1efc383b41256972b3113845be4e..e53ea52d89bbb473e26666e453d549e6720a9cc2 100644 (file)
@@ -667,7 +667,7 @@ static int filter_by_patterns_cmd(void)
                if (!confirm.len)
                        break;
 
-               memset(&dir, 0, sizeof(dir));
+               dir_init(&dir);
                pl = add_pattern_list(&dir, EXC_CMDL, "manual exclude");
                ignore_list = strbuf_split_max(&confirm, ' ', 0);
 
@@ -698,7 +698,7 @@ static int filter_by_patterns_cmd(void)
                }
 
                strbuf_list_free(ignore_list);
-               clear_directory(&dir);
+               dir_clear(&dir);
        }
 
        strbuf_release(&confirm);
@@ -923,7 +923,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
        argc = parse_options(argc, argv, prefix, options, builtin_clean_usage,
                             0);
 
-       memset(&dir, 0, sizeof(dir));
+       dir_init(&dir);
        if (!interactive && !dry_run && !force) {
                if (config_set)
                        die(_("clean.requireForce set to true and neither -i, -n, nor -f given; "
@@ -1021,11 +1021,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
                string_list_append(&del_list, rel);
        }
 
-       for (i = 0; i < dir.nr; i++)
-               free(dir.entries[i]);
-
-       for (i = 0; i < dir.ignored_nr; i++)
-               free(dir.ignored[i]);
+       dir_clear(&dir);
 
        if (interactive && del_list.nr > 0)
                interactive_main_loop();
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"));
        }
index 8cc5d09c6444ba4046a7d16cdbfcb764e34e4640..1c85eafe43eb2a4ed46b5aa2687eedf72fe61d54 100644 (file)
@@ -526,14 +526,6 @@ static unsigned int hc_str(const char *s, size_t len)
        return r;
 }
 
-static char *pool_strdup(const char *s)
-{
-       size_t len = strlen(s) + 1;
-       char *r = mem_pool_alloc(&fi_mem_pool, len);
-       memcpy(r, s, len);
-       return r;
-}
-
 static void insert_mark(struct mark_set *s, uintmax_t idnum, struct object_entry *oe)
 {
        while ((idnum >> s->shift) >= 1024) {
@@ -615,7 +607,7 @@ static struct branch *new_branch(const char *name)
                die("Branch name doesn't conform to GIT standards: %s", name);
 
        b = mem_pool_calloc(&fi_mem_pool, 1, sizeof(struct branch));
-       b->name = pool_strdup(name);
+       b->name = mem_pool_strdup(&fi_mem_pool, name);
        b->table_next_branch = branch_table[hc];
        b->branch_tree.versions[0].mode = S_IFDIR;
        b->branch_tree.versions[1].mode = S_IFDIR;
@@ -2806,7 +2798,7 @@ static void parse_new_tag(const char *arg)
 
        t = mem_pool_alloc(&fi_mem_pool, sizeof(struct tag));
        memset(t, 0, sizeof(struct tag));
-       t->name = pool_strdup(arg);
+       t->name = mem_pool_strdup(&fi_mem_pool, arg);
        if (last_tag)
                last_tag->next_tag = t;
        else
index c49f0e975203b039cbcf2ccab9860904f3f67e47..0f23dd4b8ce942dae6b9a5a0ee6352b225b99e43 100644 (file)
@@ -56,6 +56,7 @@ static int prune_tags = -1; /* unspecified */
 #define PRUNE_TAGS_BY_DEFAULT 0 /* do we prune tags by default? */
 
 static int all, append, dry_run, force, keep, multiple, update_head_ok;
+static int write_fetch_head = 1;
 static int verbosity, deepen_relative, set_upstream;
 static int progress = -1;
 static int enable_auto_gc = 1;
@@ -162,6 +163,8 @@ static struct option builtin_fetch_options[] = {
                    PARSE_OPT_OPTARG, option_fetch_parse_recurse_submodules),
        OPT_BOOL(0, "dry-run", &dry_run,
                 N_("dry run")),
+       OPT_BOOL(0, "write-fetch-head", &write_fetch_head,
+                N_("write fetched references to the FETCH_HEAD file")),
        OPT_BOOL('k', "keep", &keep, N_("keep downloaded pack")),
        OPT_BOOL('u', "update-head-ok", &update_head_ok,
                    N_("allow updating of HEAD ref")),
@@ -645,7 +648,7 @@ static void prepare_format_display(struct ref *ref_map)
        struct ref *rm;
        const char *format = "full";
 
-       git_config_get_string_const("fetch.output", &format);
+       git_config_get_string_tmp("fetch.output", &format);
        if (!strcasecmp(format, "full"))
                compact_format = 0;
        else if (!strcasecmp(format, "compact"))
@@ -893,7 +896,9 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
        const char *what, *kind;
        struct ref *rm;
        char *url;
-       const char *filename = dry_run ? "/dev/null" : git_path_fetch_head(the_repository);
+       const char *filename = (!write_fetch_head
+                               ? "/dev/null"
+                               : git_path_fetch_head(the_repository));
        int want_status;
        int summary_width = transport_summary_width(ref_map);
 
@@ -1327,7 +1332,7 @@ static int do_fetch(struct transport *transport,
        }
 
        /* if not appending, truncate FETCH_HEAD */
-       if (!append && !dry_run) {
+       if (!append && write_fetch_head) {
                retcode = truncate_fetch_head();
                if (retcode)
                        goto cleanup;
@@ -1594,7 +1599,7 @@ static int fetch_multiple(struct string_list *list, int max_children)
        int i, result = 0;
        struct strvec argv = STRVEC_INIT;
 
-       if (!append && !dry_run) {
+       if (!append && write_fetch_head) {
                int errcode = truncate_fetch_head();
                if (errcode)
                        return errcode;
@@ -1795,6 +1800,10 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
        if (depth || deepen_since || deepen_not.nr)
                deepen = 1;
 
+       /* FETCH_HEAD never gets updated in --dry-run mode */
+       if (dry_run)
+               write_fetch_head = 0;
+
        if (all) {
                if (argc == 1)
                        die(_("fetch --all does not take a repository argument"));
index 37aa07da78ebe9130c4d48865810bfc87d9f4ea0..fbf26cafcfd7d42fa779f449cf53eb7d9a6d5ea0 100644 (file)
@@ -168,7 +168,7 @@ static int mark_object(struct object *obj, int type, void *data, struct fsck_opt
                return 0;
 
        if (!(obj->flags & HAS_OBJ)) {
-               if (parent && !has_object_file(&obj->oid)) {
+               if (parent && !has_object(the_repository, &obj->oid, 1)) {
                        printf_ln(_("broken link from %7s %s\n"
                                    "              to %7s %s"),
                                  printable_type(&parent->oid, parent->type),
index cee9db3477631f55d54b4b32d5396db8830076bd..f58979bc3f07a6ca5adbd8704b1df41bf4215048 100644 (file)
@@ -693,7 +693,7 @@ static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec,
        struct dir_struct dir;
        int i, hit = 0;
 
-       memset(&dir, 0, sizeof(dir));
+       dir_init(&dir);
        if (!use_index)
                dir.flags |= DIR_NO_GITLINKS;
        if (exc_std)
@@ -705,6 +705,7 @@ static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec,
                if (hit && opt->status_only)
                        break;
        }
+       dir_clear(&dir);
        return hit;
 }
 
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 f70076d38eb3d439b521554b386e3132e33c6ceb..bbc9bc78f9d5a32ed9d167a79426ba0329bdea95 100644 (file)
@@ -563,6 +563,9 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
 
        argc = parse_options(argc, argv, prefix, init_db_options, init_db_usage, 0);
 
+       if (real_git_dir && is_bare_repository_cfg == 1)
+               die(_("--separate-git-dir and --bare are mutually exclusive"));
+
        if (real_git_dir && !is_absolute_path(real_git_dir))
                real_git_dir = real_pathdup(real_git_dir, 1);
 
@@ -658,6 +661,8 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
                                   get_git_work_tree());
        }
        else {
+               if (real_git_dir)
+                       die(_("--separate-git-dir incompatible with bare repository"));
                if (work_tree)
                        set_git_work_tree(work_tree);
        }
index 33528fefa9de4754fce37c9f660241a10fdd22e3..b58f8da09ef7a16a1df0a99aba36003dc8732a24 100644 (file)
@@ -599,8 +599,8 @@ static int show_tree_object(const struct object_id *oid,
 static void show_setup_revisions_tweak(struct rev_info *rev,
                                       struct setup_revision_opt *opt)
 {
-       if (rev->ignore_merges) {
-               /* There was no "-m" on the command line */
+       if (rev->ignore_merges < 0) {
+               /* There was no "-m" variant on the command line */
                rev->ignore_merges = 0;
                if (!rev->first_parent_only && !rev->combine_merges) {
                        /* No "--first-parent", "-c", or "--cc" */
@@ -732,8 +732,7 @@ static void log_setup_revisions_tweak(struct rev_info *rev,
        if (!rev->diffopt.output_format && rev->combine_merges)
                rev->diffopt.output_format = DIFF_FORMAT_PATCH;
 
-       /* Turn -m on when --cc/-c was given */
-       if (rev->combine_merges)
+       if (rev->first_parent_only && rev->ignore_merges < 0)
                rev->ignore_merges = 0;
 }
 
index 30a4c10334982e9ea34729a979a83027fa83c940..c8eae899b82a83ebc3487ffa99ba2bcf73d3369f 100644 (file)
@@ -584,7 +584,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
        if (argc == 2 && !strcmp(argv[1], "-h"))
                usage_with_options(ls_files_usage, builtin_ls_files_options);
 
-       memset(&dir, 0, sizeof(dir));
+       dir_init(&dir);
        prefix = cmd_prefix;
        if (prefix)
                prefix_len = strlen(prefix);
@@ -688,6 +688,6 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
                return bad ? 1 : 0;
        }
 
-       UNLEAK(dir);
+       dir_clear(&dir);
        return 0;
 }
index ea91679f330a96469f04ea7184d27b3494cf64b9..092917eca29b76f27bce31cbf6a5fff562fae7f0 100644 (file)
@@ -83,6 +83,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
                             PARSE_OPT_STOP_AT_NON_OPTION);
        dest = argv[0];
 
+       UNLEAK(sorting);
+
        if (argc > 1) {
                int i;
                pattern = xcalloc(argc, sizeof(const char *));
@@ -107,7 +109,6 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
 
        if (get_url) {
                printf("%s\n", *remote->url);
-               UNLEAK(sorting);
                return 0;
        }
 
@@ -122,10 +123,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
                int hash_algo = hash_algo_by_ptr(transport_get_hash_algo(transport));
                repo_set_hash_algo(the_repository, hash_algo);
        }
-       if (transport_disconnect(transport)) {
-               UNLEAK(sorting);
+       if (transport_disconnect(transport))
                return 1;
-       }
 
        if (!dest && !quiet)
                fprintf(stderr, "From %s\n", *remote->url);
@@ -150,7 +149,6 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
                status = 0; /* we found something */
        }
 
-       UNLEAK(sorting);
        ref_array_clear(&ref_array);
        return status;
 }
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 a9dcd25e46477ef5294dd501f1048816b27b3cdf..725dd04519133595dc212ce6c68e511b07c6b92a 100644 (file)
@@ -521,7 +521,7 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
        int all = 0, transform_stdin = 0, allow_undefined = 1, always = 0, peel_tag = 0;
        struct name_ref_data data = { 0, 0, STRING_LIST_INIT_NODUP, STRING_LIST_INIT_NODUP };
        struct option opts[] = {
-               OPT_BOOL(0, "name-only", &data.name_only, N_("print only names (no SHA-1)")),
+               OPT_BOOL(0, "name-only", &data.name_only, N_("print only ref-based names (no object names)")),
                OPT_BOOL(0, "tags", &data.tags_only, N_("only use tags to name the commits")),
                OPT_STRING_LIST(0, "refs", &data.ref_filters, N_("pattern"),
                                   N_("only use refs matching <pattern>")),
index ada47d1a57425745975f089d8a3d05a4f37b8f40..5617c01b5aae0dafd33467cecabe8b58fd36d568 100644 (file)
@@ -3048,7 +3048,7 @@ static void show_object__ma_allow_any(struct object *obj, const char *name, void
         * Quietly ignore ALL missing objects.  This avoids problems with
         * staging them now and getting an odd error later.
         */
-       if (!has_object_file(&obj->oid))
+       if (!has_object(the_repository, &obj->oid, 0))
                return;
 
        show_object(obj, name, data);
@@ -3062,7 +3062,7 @@ static void show_object__ma_allow_promisor(struct object *obj, const char *name,
         * Quietly ignore EXPECTED missing objects.  This avoids problems with
         * staging them now and getting an odd error later.
         */
-       if (!has_object_file(&obj->oid) && is_promisor_object(&obj->oid))
+       if (!has_object(the_repository, &obj->oid, 0) && is_promisor_object(&obj->oid))
                return;
 
        show_object(obj, name, data);
@@ -3357,7 +3357,7 @@ static void get_object_list(int ac, const char **av)
                        if (starts_with(line, "--shallow ")) {
                                struct object_id oid;
                                if (get_oid_hex(line + 10, &oid))
-                                       die("not an SHA-1 '%s'", line + 10);
+                                       die("not an object name '%s'", line + 10);
                                register_shallow(the_repository, &oid);
                                use_bitmap_index = 0;
                                continue;
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 f520111eda09f1d167524b31919daaea3e5a5a31..25c6c3b38d4b120687bb02220c3db25af2ae66de 100644 (file)
@@ -637,8 +637,15 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
 
        if (bisect_list) {
                int reaches, all;
+               unsigned bisect_flags = 0;
 
-               find_bisection(&revs.commits, &reaches, &all, bisect_find_all);
+               if (bisect_find_all)
+                       bisect_flags |= FIND_BISECTION_ALL;
+
+               if (revs.first_parent_only)
+                       bisect_flags |= FIND_BISECTION_FIRST_PARENT_ONLY;
+
+               find_bisection(&revs.commits, &reaches, &all, bisect_flags);
 
                if (bisect_show_vars)
                        return show_bisect_vars(&info, reaches, all);
index 10d87630cd0017f177b8c33929e5a94adaee6b0e..4bdfaf839705a69c58fa631055eb4fc8fdff0ed4 100644 (file)
@@ -864,7 +864,7 @@ static int get_untracked_files(const struct pathspec *ps, int include_untracked,
        int found = 0;
        struct dir_struct dir;
 
-       memset(&dir, 0, sizeof(dir));
+       dir_init(&dir);
        if (include_untracked != INCLUDE_ALL_FILES)
                setup_standard_excludes(&dir);
 
@@ -875,12 +875,9 @@ static int get_untracked_files(const struct pathspec *ps, int include_untracked,
                strbuf_addstr(untracked_files, ent->name);
                /* NUL-terminate: will be fed to update-index -z */
                strbuf_addch(untracked_files, '\0');
-               free(ent);
        }
 
-       free(dir.entries);
-       free(dir.ignored);
-       clear_directory(&dir);
+       dir_clear(&dir);
        return found;
 }
 
index df135abbf10342472f692203d9006943af79294f..a59d8e4bda615cf843515da2312febdf2c72c213 100644 (file)
@@ -1511,7 +1511,7 @@ static void determine_submodule_update_strategy(struct repository *r,
                if (parse_submodule_update_strategy(update, out) < 0)
                        die(_("Invalid update mode '%s' for submodule path '%s'"),
                                update, path);
-       } else if (!repo_config_get_string_const(r, key, &val)) {
+       } else if (!repo_config_get_string_tmp(r, key, &val)) {
                if (parse_submodule_update_strategy(val, out) < 0)
                        die(_("Invalid update mode '%s' configured for submodule path '%s'"),
                                val, path);
@@ -1667,7 +1667,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
        }
 
        key = xstrfmt("submodule.%s.update", sub->name);
-       if (!repo_config_get_string_const(the_repository, key, &update_string)) {
+       if (!repo_config_get_string_tmp(the_repository, key, &update_string)) {
                update_type = parse_submodule_update_type(update_string);
        } else {
                update_type = sub->update_strategy.type;
@@ -1690,7 +1690,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
 
        strbuf_reset(&sb);
        strbuf_addf(&sb, "submodule.%s.url", sub->name);
-       if (repo_config_get_string_const(the_repository, sb.buf, &url)) {
+       if (repo_config_get_string_tmp(the_repository, sb.buf, &url)) {
                if (starts_with_dot_slash(sub->url) ||
                    starts_with_dot_dot_slash(sub->url)) {
                        url = compute_submodule_clone_url(sub->url);
@@ -1747,8 +1747,8 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
                                              "--no-single-branch");
 
 cleanup:
-       strbuf_reset(&displaypath_sb);
-       strbuf_reset(&sb);
+       strbuf_release(&displaypath_sb);
+       strbuf_release(&sb);
        if (need_free_url)
                free((void*)url);
 
@@ -1976,7 +1976,7 @@ static const char *remote_submodule_branch(const char *path)
                return NULL;
 
        key = xstrfmt("submodule.%s.branch", sub->name);
-       if (repo_config_get_string_const(the_repository, key, &branch))
+       if (repo_config_get_string_tmp(the_repository, key, &branch))
                branch = sub->branch;
        free(key);
 
@@ -2101,7 +2101,7 @@ static int ensure_core_worktree(int argc, const char **argv, const char *prefix)
 {
        const struct submodule *sub;
        const char *path;
-       char *cw;
+       const char *cw;
        struct repository subrepo;
 
        if (argc != 2)
@@ -2116,7 +2116,7 @@ static int ensure_core_worktree(int argc, const char **argv, const char *prefix)
        if (repo_submodule_init(&subrepo, the_repository, sub))
                die(_("could not get a repository handle for submodule '%s'"), path);
 
-       if (!repo_config_get_string(&subrepo, "core.worktree", &cw)) {
+       if (!repo_config_get_string_tmp(&subrepo, "core.worktree", &cw)) {
                char *cfg_file, *abs_path;
                const char *rel_path;
                struct strbuf sb = STRBUF_INIT;
diff --git a/cache.h b/cache.h
index 0290849c1909fe64d0e749768fd0dea0f965edd7..4cad61ffa4eecf4e793971a4009d199f7c2f3a50 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -921,8 +921,8 @@ extern int assume_unchanged;
 extern int prefer_symlink_refs;
 extern int warn_ambiguous_refs;
 extern int warn_on_object_refname_ambiguity;
-extern const char *apply_default_whitespace;
-extern const char *apply_default_ignorewhitespace;
+extern char *apply_default_whitespace;
+extern char *apply_default_ignorewhitespace;
 extern const char *git_attributes_file;
 extern const char *git_hooks_path;
 extern int zlib_compression_level;
index c72e9f9773e173c0dbcb5de88bde54d5434cf808..6586e30ca5a64fe61ec982f3d5dbe188d9194258 100644 (file)
@@ -47,7 +47,7 @@ const char *unique_tracking_name(const char *name, struct object_id *oid,
 {
        struct tracking_name_data cb_data = TRACKING_NAME_DATA_INIT;
        const char *default_remote = NULL;
-       if (!git_config_get_string_const("checkout.defaultremote", &default_remote))
+       if (!git_config_get_string_tmp("checkout.defaultremote", &default_remote))
                cb_data.default_remote = default_remote;
        cb_data.src_ref = xstrfmt("refs/heads/%s", name);
        cb_data.dst_oid = oid;
@@ -55,7 +55,6 @@ const char *unique_tracking_name(const char *name, struct object_id *oid,
        if (dwim_remotes_matched)
                *dwim_remotes_matched = cb_data.num_matches;
        free(cb_data.src_ref);
-       free((char *)default_remote);
        if (cb_data.num_matches == 1) {
                free(cb_data.default_dst_ref);
                free(cb_data.default_dst_oid);
index e51c91dd5b0af4e4946091e5ca7f06707b3a0c5b..0ed003e218fb9bb2c024fb913a2af4fca9441039 100644 (file)
@@ -179,7 +179,14 @@ static char *get_chain_filename(struct object_directory *odb)
 
 static uint8_t oid_version(void)
 {
-       return 1;
+       switch (hash_algo_by_ptr(the_hash_algo)) {
+       case GIT_HASH_SHA1:
+               return 1;
+       case GIT_HASH_SHA256:
+               return 2;
+       default:
+               die(_("invalid hash version"));
+       }
 }
 
 static struct commit_graph *alloc_commit_graph(void)
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 4454b3e67b7488be2701fdc0001aa608362fd002..a00f3312300ac36773bf42aec80b4514f31b1293 100644 (file)
@@ -290,6 +290,9 @@ int mingw_unlink(const char *pathname)
        if (xutftowcs_path(wpathname, pathname) < 0)
                return -1;
 
+       if (DeleteFileW(wpathname))
+               return 0;
+
        /* read-only files cannot be removed */
        _wchmod(wpathname, 0666);
        while ((ret = _wunlink(wpathname)) == -1 && tries < ARRAY_SIZE(delay)) {
index 2b79fe76adf791813faf980af340886aefcf38aa..2bdff4457be7d5b1e1fd5f6acb558ac41b946a8c 100644 (file)
--- a/config.c
+++ b/config.c
@@ -2006,18 +2006,27 @@ const struct string_list *git_configset_get_value_multi(struct config_set *cs, c
        return e ? &e->value_list : NULL;
 }
 
-int git_configset_get_string_const(struct config_set *cs, const char *key, const char **dest)
+int git_configset_get_string(struct config_set *cs, const char *key, char **dest)
 {
        const char *value;
        if (!git_configset_get_value(cs, key, &value))
-               return git_config_string(dest, key, value);
+               return git_config_string((const char **)dest, key, value);
        else
                return 1;
 }
 
-int git_configset_get_string(struct config_set *cs, const char *key, char **dest)
+int git_configset_get_string_tmp(struct config_set *cs, const char *key,
+                                const char **dest)
 {
-       return git_configset_get_string_const(cs, key, (const char **)dest);
+       const char *value;
+       if (!git_configset_get_value(cs, key, &value)) {
+               if (!value)
+                       return config_error_nonbool(key);
+               *dest = value;
+               return 0;
+       } else {
+               return 1;
+       }
 }
 
 int git_configset_get_int(struct config_set *cs, const char *key, int *dest)
@@ -2147,22 +2156,26 @@ const struct string_list *repo_config_get_value_multi(struct repository *repo,
        return git_configset_get_value_multi(repo->config, key);
 }
 
-int repo_config_get_string_const(struct repository *repo,
-                                const char *key, const char **dest)
+int repo_config_get_string(struct repository *repo,
+                          const char *key, char **dest)
 {
        int ret;
        git_config_check_init(repo);
-       ret = git_configset_get_string_const(repo->config, key, dest);
+       ret = git_configset_get_string(repo->config, key, dest);
        if (ret < 0)
                git_die_config(key, NULL);
        return ret;
 }
 
-int repo_config_get_string(struct repository *repo,
-                          const char *key, char **dest)
+int repo_config_get_string_tmp(struct repository *repo,
+                              const char *key, const char **dest)
 {
+       int ret;
        git_config_check_init(repo);
-       return repo_config_get_string_const(repo, key, (const char **)dest);
+       ret = git_configset_get_string_tmp(repo->config, key, dest);
+       if (ret < 0)
+               git_die_config(key, NULL);
+       return ret;
 }
 
 int repo_config_get_int(struct repository *repo,
@@ -2232,14 +2245,14 @@ const struct string_list *git_config_get_value_multi(const char *key)
        return repo_config_get_value_multi(the_repository, key);
 }
 
-int git_config_get_string_const(const char *key, const char **dest)
+int git_config_get_string(const char *key, char **dest)
 {
-       return repo_config_get_string_const(the_repository, key, dest);
+       return repo_config_get_string(the_repository, key, dest);
 }
 
-int git_config_get_string(const char *key, char **dest)
+int git_config_get_string_tmp(const char *key, const char **dest)
 {
-       return repo_config_get_string(the_repository, key, dest);
+       return repo_config_get_string_tmp(the_repository, key, dest);
 }
 
 int git_config_get_int(const char *key, int *dest)
@@ -2274,7 +2287,7 @@ int git_config_get_pathname(const char *key, const char **dest)
 
 int git_config_get_expiry(const char *key, const char **output)
 {
-       int ret = git_config_get_string_const(key, output);
+       int ret = git_config_get_string(key, (char **)output);
        if (ret)
                return ret;
        if (strcmp(*output, "now")) {
@@ -2287,11 +2300,11 @@ int git_config_get_expiry(const char *key, const char **output)
 
 int git_config_get_expiry_in_days(const char *key, timestamp_t *expiry, timestamp_t now)
 {
-       char *expiry_string;
+       const char *expiry_string;
        intmax_t days;
        timestamp_t when;
 
-       if (git_config_get_string(key, &expiry_string))
+       if (git_config_get_string_tmp(key, &expiry_string))
                return 1; /* no such thing */
 
        if (git_parse_signed(expiry_string, &days, maximum_signed_value_of_type(int))) {
index 060874488f413cd6453e1633cd69c971d6e5d613..91cdfbfb414fdcc7835a3a467ea680b5780a74c8 100644 (file)
--- a/config.h
+++ b/config.h
@@ -458,8 +458,8 @@ void git_configset_clear(struct config_set *cs);
  */
 int git_configset_get_value(struct config_set *cs, const char *key, const char **dest);
 
-int git_configset_get_string_const(struct config_set *cs, const char *key, const char **dest);
 int git_configset_get_string(struct config_set *cs, const char *key, char **dest);
+int git_configset_get_string_tmp(struct config_set *cs, const char *key, const char **dest);
 int git_configset_get_int(struct config_set *cs, const char *key, int *dest);
 int git_configset_get_ulong(struct config_set *cs, const char *key, unsigned long *dest);
 int git_configset_get_bool(struct config_set *cs, const char *key, int *dest);
@@ -474,10 +474,10 @@ int repo_config_get_value(struct repository *repo,
                          const char *key, const char **value);
 const struct string_list *repo_config_get_value_multi(struct repository *repo,
                                                      const char *key);
-int repo_config_get_string_const(struct repository *repo,
-                                const char *key, const char **dest);
 int repo_config_get_string(struct repository *repo,
                           const char *key, char **dest);
+int repo_config_get_string_tmp(struct repository *repo,
+                              const char *key, const char **dest);
 int repo_config_get_int(struct repository *repo,
                        const char *key, int *dest);
 int repo_config_get_ulong(struct repository *repo,
@@ -529,13 +529,14 @@ void git_config_clear(void);
  * error message and returns -1. When the configuration variable `key` is
  * not found, returns 1 without touching `dest`.
  */
-int git_config_get_string_const(const char *key, const char **dest);
+int git_config_get_string(const char *key, char **dest);
 
 /**
- * Similar to `git_config_get_string_const`, except that retrieved value
- * copied into the `dest` parameter is a mutable string.
+ * Similar to `git_config_get_string`, but does not allocate any new
+ * memory; on success `dest` will point to memory owned by the config
+ * machinery, which could be invalidated if it is discarded and reloaded.
  */
-int git_config_get_string(const char *key, char **dest);
+int git_config_get_string_tmp(const char *key, const char **dest);
 
 /**
  * Finds and parses the value to an integer for the configuration variable
index 0b6aba177e0f4dd3a999e3382d61cc71cf5b33e2..8b8f56cf6d230b23c46bb980755cb6d1fc3684ef 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -1052,7 +1052,7 @@ static const char *get_ssh_command(void)
        if ((ssh = getenv("GIT_SSH_COMMAND")))
                return ssh;
 
-       if (!git_config_get_string_const("core.sshcommand", &ssh))
+       if (!git_config_get_string_tmp("core.sshcommand", &ssh))
                return ssh;
 
        return NULL;
@@ -1071,7 +1071,7 @@ static void override_ssh_variant(enum ssh_variant *ssh_variant)
 {
        const char *variant = getenv("GIT_SSH_VARIANT");
 
-       if (!variant && git_config_get_string_const("ssh.variant", &variant))
+       if (!variant && git_config_get_string_tmp("ssh.variant", &variant))
                return;
 
        if (!strcmp(variant, "auto"))
index 21c1ebe9fbfcc832b13e0c0f4f2f6d1fa8d62667..b18299fdf0e5224924915810d66196a1d38cbe56 100644 (file)
@@ -22,14 +22,13 @@ int check_connected(oid_iterate_fn fn, void *cb_data,
                    struct check_connected_options *opt)
 {
        struct child_process rev_list = CHILD_PROCESS_INIT;
+       FILE *rev_list_in;
        struct check_connected_options defaults = CHECK_CONNECTED_INIT;
-       char commit[GIT_MAX_HEXSZ + 1];
        struct object_id oid;
        int err = 0;
        struct packed_git *new_pack = NULL;
        struct transport *transport;
        size_t base_len;
-       const unsigned hexsz = the_hash_algo->hexsz;
 
        if (!opt)
                opt = &defaults;
@@ -122,7 +121,8 @@ no_promisor_pack_found:
 
        sigchain_push(SIGPIPE, SIG_IGN);
 
-       commit[hexsz] = '\n';
+       rev_list_in = xfdopen(rev_list.in, "w");
+
        do {
                /*
                 * If index-pack already checked that:
@@ -135,16 +135,17 @@ no_promisor_pack_found:
                if (new_pack && find_pack_entry_one(oid.hash, new_pack))
                        continue;
 
-               memcpy(commit, oid_to_hex(&oid), hexsz);
-               if (write_in_full(rev_list.in, commit, hexsz + 1) < 0) {
-                       if (errno != EPIPE && errno != EINVAL)
-                               error_errno(_("failed write to rev-list"));
-                       err = -1;
+               if (fprintf(rev_list_in, "%s\n", oid_to_hex(&oid)) < 0)
                        break;
-               }
        } while (!fn(cb_data, &oid));
 
-       if (close(rev_list.in))
+       if (ferror(rev_list_in) || fflush(rev_list_in)) {
+               if (errno != EPIPE && errno != EINVAL)
+                       error_errno(_("failed write to rev-list"));
+               err = -1;
+       }
+
+       if (fclose(rev_list_in))
                err = error_errno(_("failed to close rev-list's stdin"));
 
        sigchain_pop(SIGPIPE);
index 0fdb5da83bed06a4c0b9bbb7cb8876fd54774b4f..9147fba3d5c34e617f94129b02459d4579595da8 100644 (file)
 #     When set to "1", do not include "DWIM" suggestions in git-checkout
 #     and git-switch completion (e.g., completing "foo" when "origin/foo"
 #     exists).
+#
+#   GIT_COMPLETION_SHOW_ALL
+#
+#     When set to "1" suggest all options, including options which are
+#     typically hidden (e.g. '--allow-empty' for 'git commit').
 
 case "$COMP_WORDBREAKS" in
 *:*) : great ;;
@@ -411,10 +416,17 @@ __gitcomp_builtin ()
        local options
        eval "options=\${$var-}"
 
+       local completion_helper
+       if [ "$GIT_COMPLETION_SHOW_ALL" = "1" ]; then
+               completion_helper="--git-completion-helper-all"
+       else
+               completion_helper="--git-completion-helper"
+       fi
+
        if [ -z "$options" ]; then
                # leading and trailing spaces are significant to make
                # option removal work correctly.
-               options=" $incl $(__git ${cmd/_/ } --git-completion-helper) " || return
+               options=" $incl $(__git ${cmd/_/ } $completion_helper) " || return
 
                for i in $excl; do
                        options="${options/ $i / }"
@@ -1712,8 +1724,8 @@ _git_diff ()
 }
 
 __git_mergetools_common="diffuse diffmerge ecmerge emerge kdiff3 meld opendiff
-                       tkdiff vimdiff gvimdiff xxdiff araxis p4merge bc
-                       codecompare smerge
+                       tkdiff vimdiff nvimdiff gvimdiff xxdiff araxis p4merge
+                       bc codecompare smerge
 "
 
 _git_difftool ()
index 352deda69dcfd009ff025615dff07dd0a5d015d1..0db02fe3c09528cdb2b26982b4b9cf60e7e94429 100644 (file)
@@ -139,12 +139,12 @@ OPTIONS
 
 -m <message>::
 --message=<message>::
-       This option is only valid for add, merge and pull (unsure).
+       This option is only valid for add, merge, pull, and split --rejoin.
        Specify <message> as the commit message for the merge commit.
 
 
-OPTIONS FOR add, merge, push, pull
-----------------------------------
+OPTIONS FOR add, merge, and pull
+--------------------------------
 --squash::
        This option is only valid for add, merge, and pull
        commands.
index 25fd2dee19c4a8f6408d768d44d8dc92aeaf0ed3..50521e2093fc581ce3cedc76b3036a61f31bef35 100644 (file)
@@ -219,7 +219,8 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
                                continue;
                        } else if (revs->diffopt.ita_invisible_in_index &&
                                   ce_intent_to_add(ce)) {
-                               diff_addremove(&revs->diffopt, '+', ce->ce_mode,
+                               newmode = ce_mode_from_stat(ce, st.st_mode);
+                               diff_addremove(&revs->diffopt, '+', newmode,
                                               &null_oid, 0, ce->name, 0);
                                continue;
                        }
diff --git a/diff.c b/diff.c
index f9709de7b4540d1ddf7dda7bbb38a54bbbb8d952..e3a5ee3bee8c93f1480747891cadaa824f259262 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -4319,7 +4319,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;
@@ -6044,6 +6047,8 @@ static void patch_id_consume(void *priv, char *line, unsigned long len)
        struct patch_id_t *data = priv;
        int new_len;
 
+       if (len > 12 && starts_with(line, "\\ "))
+               return;
        new_len = remove_space(line, len);
 
        the_hash_algo->update_fn(data->ctx, line, new_len);
diff --git a/dir.c b/dir.c
index fe64be30ed651de44f2aeb6c9527416e4af3da53..3018a657b059868c5a3a739d0a039311eedda5b9 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -54,6 +54,11 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,
 static int resolve_dtype(int dtype, struct index_state *istate,
                         const char *path, int len);
 
+void dir_init(struct dir_struct *dir)
+{
+       memset(dir, 0, sizeof(*dir));
+}
+
 int count_slashes(const char *s)
 {
        int cnt = 0;
@@ -916,6 +921,8 @@ void clear_pattern_list(struct pattern_list *pl)
                free(pl->patterns[i]);
        free(pl->patterns);
        free(pl->filebuf);
+       hashmap_free_entries(&pl->recursive_hashmap, struct pattern_entry, ent);
+       hashmap_free_entries(&pl->parent_hashmap, struct pattern_entry, ent);
 
        memset(pl, 0, sizeof(*pl));
 }
@@ -1792,9 +1799,12 @@ static enum path_treatment treat_directory(struct dir_struct *dir,
                nested_repo = is_nonbare_repository_dir(&sb);
                strbuf_release(&sb);
        }
-       if (nested_repo)
-               return ((dir->flags & DIR_SKIP_NESTED_GIT) ? path_none :
-                       (excluded ? path_excluded : path_untracked));
+       if (nested_repo) {
+               if ((dir->flags & DIR_SKIP_NESTED_GIT) ||
+                   (matches_how == MATCHED_RECURSIVELY_LEADING_PATHSPEC))
+                       return path_none;
+               return excluded ? path_excluded : path_untracked;
+       }
 
        if (!(dir->flags & DIR_SHOW_OTHER_DIRECTORIES)) {
                if (excluded &&
@@ -3009,10 +3019,10 @@ int remove_path(const char *name)
 }
 
 /*
- * Frees memory within dir which was allocated for exclude lists and
- * the exclude_stack.  Does not free dir itself.
+ * Frees memory within dir which was allocated, and resets fields for further
+ * use.  Does not free dir itself.
  */
-void clear_directory(struct dir_struct *dir)
+void dir_clear(struct dir_struct *dir)
 {
        int i, j;
        struct exclude_list_group *group;
@@ -3030,6 +3040,13 @@ void clear_directory(struct dir_struct *dir)
                free(group->pl);
        }
 
+       for (i = 0; i < dir->ignored_nr; i++)
+               free(dir->ignored[i]);
+       for (i = 0; i < dir->nr; i++)
+               free(dir->entries[i]);
+       free(dir->ignored);
+       free(dir->entries);
+
        stk = dir->exclude_stack;
        while (stk) {
                struct exclude_stack *prev = stk->prev;
@@ -3037,6 +3054,8 @@ void clear_directory(struct dir_struct *dir)
                stk = prev;
        }
        strbuf_release(&dir->basebuf);
+
+       dir_init(dir);
 }
 
 struct ondisk_untracked_cache {
diff --git a/dir.h b/dir.h
index 5855c065a610b794b3777405bba6f343230b7ea2..a3c40dec5165425ec00181a152b1ddac37dba43d 100644 (file)
--- a/dir.h
+++ b/dir.h
  * CE_SKIP_WORKTREE marked. If you want to exclude files, make sure you have
  * loaded the index first.
  *
- * - Prepare `struct dir_struct dir` and clear it with `memset(&dir, 0,
- * sizeof(dir))`.
+ * - Prepare `struct dir_struct dir` using `dir_init()` function.
  *
  * - To add single exclude pattern, call `add_pattern_list()` and then
  *   `add_pattern()`.
  *
  * - To add patterns from a file (e.g. `.git/info/exclude`), call
- *   `add_patterns_from_file()` , and/or set `dir.exclude_per_dir`.  A
- *   short-hand function `setup_standard_excludes()` can be used to set
- *   up the standard set of exclude settings.
+ *   `add_patterns_from_file()` , and/or set `dir.exclude_per_dir`.
  *
- * - Set options described in the Data Structure section above.
+ * - A short-hand function `setup_standard_excludes()` can be used to set
+ *   up the standard set of exclude settings, instead of manually calling
+ *   the add_pattern*() family of functions.
  *
- * - Call `read_directory()`.
+ * - Call `fill_directory()`.
  *
- * - Use `dir.entries[]`.
+ * - Use `dir.entries[]` and `dir.ignored[]`.
  *
- * - Call `clear_directory()` when none of the contained elements are no longer in use.
+ * - Call `dir_clear()` when the contained elements are no longer in use.
  *
  */
 
@@ -362,6 +361,8 @@ int match_pathspec(const struct index_state *istate,
 int report_path_error(const char *ps_matched, const struct pathspec *pathspec);
 int within_depth(const char *name, int namelen, int depth, int max_depth);
 
+void dir_init(struct dir_struct *dir);
+
 int fill_directory(struct dir_struct *dir,
                   struct index_state *istate,
                   const struct pathspec *pathspec);
@@ -428,7 +429,7 @@ void parse_path_pattern(const char **string, int *patternlen, unsigned *flags, i
 void add_pattern(const char *string, const char *base,
                 int baselen, struct pattern_list *pl, int srcpos);
 void clear_pattern_list(struct pattern_list *pl);
-void clear_directory(struct dir_struct *dir);
+void dir_clear(struct dir_struct *dir);
 
 int repo_file_exists(struct repository *repo, const char *path);
 int file_exists(const char *);
index 91989ee8a116aa44502a2c60dfbd02ba4528a34f..6303ae0ab0d52b7b54a00bd9bf687a91aac998fd 100644 (file)
--- a/editor.c
+++ b/editor.c
@@ -40,7 +40,7 @@ const char *git_sequence_editor(void)
        const char *editor = getenv("GIT_SEQUENCE_EDITOR");
 
        if (!editor)
-               git_config_get_string_const("sequence.editor", &editor);
+               git_config_get_string_tmp("sequence.editor", &editor);
        if (!editor)
                editor = git_editor();
 
diff --git a/entry.c b/entry.c
index 449bd32dee555d9a52481e30226cd4450e80409e..a0532f1f00007be7c9b675a54a7e8c48c000d638 100644 (file)
--- a/entry.c
+++ b/entry.c
@@ -510,8 +510,6 @@ int checkout_entry(struct cache_entry *ce, const struct checkout *state,
                        /* If it is a gitlink, leave it alone! */
                        if (S_ISGITLINK(ce->ce_mode))
                                return 0;
-                       if (!state->force)
-                               return error("%s is a directory", path.buf);
                        remove_subtree(&path);
                } else if (unlink(path.buf))
                        return error_errno("unable to unlink old '%s'", path.buf);
index 52e0c979ba06e48f427c283a133f39fc7216b7b0..bb518c61cd259caf74f65fc8a080096b54168e48 100644 (file)
@@ -35,8 +35,8 @@ int repository_format_precious_objects;
 int repository_format_worktree_config;
 const char *git_commit_encoding;
 const char *git_log_output_encoding;
-const char *apply_default_whitespace;
-const char *apply_default_ignorewhitespace;
+char *apply_default_whitespace;
+char *apply_default_ignorewhitespace;
 const char *git_attributes_file;
 const char *git_hooks_path;
 int zlib_compression_level = Z_BEST_SPEED;
index 7f20eca4f81ce401f951361ce59e1be6aa31cd67..5eb6ed6165511c249f2604f6a6e7428286482d69 100644 (file)
@@ -794,6 +794,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 +870,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 +899,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
index 85d1e39fe752ddc625ba7801faa5373db57b796c..5e747daea8976e942c046b9bd4a9eeb09102c21b 100644 (file)
@@ -40,6 +40,14 @@ struct fetch_pack_args {
        unsigned cloning:1;
        unsigned update_shallow:1;
        unsigned deepen:1;
+
+       /*
+        * 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 from_promisor:1;
 
        /*
index f03fbb18f00403b2786f5b4cb1b18e30b1e820b2..c28e35b0fa8039f9d9ccf0925c1e17ac79c70dbe 100755 (executable)
@@ -4,7 +4,7 @@ USAGE='[help|start|bad|good|new|old|terms|skip|next|reset|visualize|view|replay|
 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>...]
+                [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]
        reset bisect state and start bisection.
 git bisect (bad|new) [<rev>]
        mark <rev> a known-bad revision/
@@ -153,7 +153,7 @@ bisect_next() {
        git bisect--helper --bisect-next-check $TERM_GOOD $TERM_BAD $TERM_GOOD|| exit
 
        # Perform all bisection computation, display and checkout
-       git bisect--helper --next-all $(git rev-parse --verify -q BISECT_HEAD > /dev/null && echo --no-checkout)
+       git bisect--helper --next-all
        res=$?
 
        # Check if we should exit because bisection is finished
index 5637114b8dcf41a2ab09a8f1787de53fc5a3a443..7a0fb7a04597a4b6fa7ea48194aa334852104eb9 100644 (file)
@@ -252,8 +252,10 @@ typedef unsigned long uintptr_t;
 #ifdef PRECOMPOSE_UNICODE
 #include "compat/precompose_utf8.h"
 #else
-#define precompose_str(in,i_nfd2nfc)
-#define precompose_argv(c,v)
+static inline void precompose_argv(int argc, const char **argv)
+{
+       ; /* nothing */
+}
 #define probe_utf8_pathname_composition()
 #endif
 
@@ -270,7 +272,9 @@ struct itimerval {
 #endif
 
 #ifdef NO_SETITIMER
-#define setitimer(which,value,ovalue)
+static inline int setitimer(int which, const struct itimerval *value, struct itimerval *newvalue) {
+       ; /* nothing */
+}
 #endif
 
 #ifndef NO_LIBGEN_H
@@ -1231,8 +1235,14 @@ int warn_on_fopen_errors(const char *path);
 #endif
 
 #ifndef _POSIX_THREAD_SAFE_FUNCTIONS
-#define flockfile(fh)
-#define funlockfile(fh)
+static inline void flockfile(FILE *fh)
+{
+       ; /* nothing */
+}
+static inline void funlockfile(FILE *fh)
+{
+       ; /* nothing */
+}
 #define getc_unlocked(fh) getc(fh)
 #endif
 
index 6483d792d337f6c0c0aa1dc0074df230bff8f378..0ae8bce3fb0675ea206e962ef576d08d5d608ada 100755 (executable)
@@ -22,7 +22,7 @@ die "Need at least one commit identifier!" unless @ARGV;
 my $repo = Git->repository();
 $opt_w = $repo->config('cvsexportcommit.cvsdir') unless defined $opt_w;
 
-my $tmpdir = File::Temp->newdir;
+my $tmpdir = File::Temp::tempdir(CLEANUP => 1);
 my $hash_algo = $repo->config('extensions.objectformat') || 'sha1';
 my $hexsz = $hash_algo eq 'sha256' ? 64 : 40;
 
index 204a5acd66f5444412f0088b8df6cb0ae2fd6b41..2defef28cd931fc9dca041ee7ec0ea5d440c3dd7 100644 (file)
@@ -43,7 +43,14 @@ show_tool_names () {
 
        shown_any=
        ( cd "$MERGE_TOOLS_DIR" && ls ) | {
-               while read toolname
+               while read scriptname
+               do
+                       setup_tool "$scriptname" 2>/dev/null
+                       variants="$variants$(list_tool_variants)\n"
+               done
+               variants="$(echo "$variants" | sort | uniq)"
+
+               for toolname in $variants
                do
                        if setup_tool "$toolname" 2>/dev/null &&
                                (eval "$condition" "$toolname")
@@ -157,6 +164,10 @@ setup_tool () {
                echo "$1"
        }
 
+       list_tool_variants () {
+               echo "$tool"
+       }
+
        # Most tools' exit codes cannot be trusted, so By default we ignore
        # their exit code and check the merged file's modification time in
        # check_unchanged() to determine whether or not the merge was
@@ -178,19 +189,26 @@ setup_tool () {
                false
        }
 
-
-       if ! test -f "$MERGE_TOOLS_DIR/$tool"
+       if test -f "$MERGE_TOOLS_DIR/$tool"
+       then
+               . "$MERGE_TOOLS_DIR/$tool"
+       elif test -f "$MERGE_TOOLS_DIR/${tool%[0-9]}"
        then
+               . "$MERGE_TOOLS_DIR/${tool%[0-9]}"
+       else
                setup_user_tool
                return $?
        fi
 
-       # Load the redefined functions
-       . "$MERGE_TOOLS_DIR/$tool"
        # Now let the user override the default command for the tool.  If
        # they have not done so then this will return 1 which we ignore.
        setup_user_tool
 
+       if ! list_tool_variants | grep -q "^$tool$"
+       then
+               return 1
+       fi
+
        if merge_mode && ! can_merge
        then
                echo "error: '$tool' can not be used to resolve merges" >&2
@@ -286,11 +304,14 @@ list_merge_tool_candidates () {
                tools="$tools smerge"
        fi
        case "${VISUAL:-$EDITOR}" in
+       *nvim*)
+               tools="$tools nvimdiff vimdiff emerge"
+               ;;
        *vim*)
-               tools="$tools vimdiff emerge"
+               tools="$tools vimdiff nvimdiff emerge"
                ;;
        *)
-               tools="$tools emerge vimdiff"
+               tools="$tools emerge vimdiff nvimdiff"
                ;;
        esac
 }
index dec90e9af67785e23bbe7cc553a1c23a5f0a1fd3..b9c71d2a71bdd32ed595da0d217f1e6c854f5ffc 100644 (file)
@@ -193,16 +193,6 @@ mark_action_done () {
        fi
 }
 
-# Put the last action marked done at the beginning of the todo list
-# again. If there has not been an action marked done yet, leave the list of
-# items on the todo list unchanged.
-reschedule_last_action () {
-       tail -n 1 "$done" | cat - "$todo" >"$todo".new
-       sed -e \$d <"$done" >"$done".new
-       mv -f "$todo".new "$todo"
-       mv -f "$done".new "$done"
-}
-
 append_todo_help () {
        gettext "
 Commands:
index 36c47bae1d1f1a0d3558fe43dcdbd5eb49a3d27c..1f425c08091d400e1d2e94533411c1b778f561de 100755 (executable)
@@ -250,6 +250,7 @@ my $chain_reply_to = 0;
 my $use_xmailer = 1;
 my $validate = 1;
 my $target_xfer_encoding = 'auto';
+my $forbid_sendmail_variables = 1;
 
 my %config_bool_settings = (
     "thread" => \$thread,
@@ -263,6 +264,7 @@ my %config_bool_settings = (
     "multiedit" => \$multiedit,
     "annotate" => \$annotate,
     "xmailer" => \$use_xmailer,
+    "forbidsendmailvariables" => \$forbid_sendmail_variables,
 );
 
 my %config_settings = (
@@ -478,6 +480,12 @@ unless ($rc) {
     usage();
 }
 
+if ($forbid_sendmail_variables && (scalar Git::config_regexp("^sendmail[.]")) != 0) {
+       die __("fatal: found configuration options for 'sendmail'\n" .
+               "git-send-email is configured with the sendemail.* options - note the 'e'.\n" .
+               "Set sendemail.forbidSendmailVariables to false to disable this check.\n");
+}
+
 die __("Cannot run git format-patch from outside a repository\n")
        if $format_patch and not $repo;
 
diff --git a/help.c b/help.c
index d478afb2af2631857e2431e1d83e48114995ee00..4e2468a44dfe3154642299dbca0761ab114cb859 100644 (file)
--- a/help.c
+++ b/help.c
@@ -375,7 +375,7 @@ void list_cmds_by_config(struct string_list *list)
 {
        const char *cmd_list;
 
-       if (git_config_get_string_const("completion.commands", &cmd_list))
+       if (git_config_get_string_tmp("completion.commands", &cmd_list))
                return;
 
        string_list_sort(list);
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)
index a2841a4a9ad7e4871282031f1b18fd62f18e9638..8401761dda0a2a585f6593e2212ff41db7135170 100644 (file)
  * `insert_after`. If `insert_after` is NULL, then insert block at the
  * head of the linked list.
  */
-static struct mp_block *mem_pool_alloc_block(struct mem_pool *mem_pool, size_t block_alloc, struct mp_block *insert_after)
+static struct mp_block *mem_pool_alloc_block(struct mem_pool *pool,
+                                            size_t block_alloc,
+                                            struct mp_block *insert_after)
 {
        struct mp_block *p;
 
-       mem_pool->pool_alloc += sizeof(struct mp_block) + block_alloc;
+       pool->pool_alloc += sizeof(struct mp_block) + block_alloc;
        p = xmalloc(st_add(sizeof(struct mp_block), block_alloc));
 
        p->next_free = (char *)p->space;
@@ -26,35 +28,27 @@ static struct mp_block *mem_pool_alloc_block(struct mem_pool *mem_pool, size_t b
                p->next_block = insert_after->next_block;
                insert_after->next_block = p;
        } else {
-               p->next_block = mem_pool->mp_block;
-               mem_pool->mp_block = p;
+               p->next_block = pool->mp_block;
+               pool->mp_block = p;
        }
 
        return p;
 }
 
-void mem_pool_init(struct mem_pool **mem_pool, size_t initial_size)
+void mem_pool_init(struct mem_pool *pool, size_t initial_size)
 {
-       struct mem_pool *pool;
-
-       if (*mem_pool)
-               return;
-
-       pool = xcalloc(1, sizeof(*pool));
-
+       memset(pool, 0, sizeof(*pool));
        pool->block_alloc = BLOCK_GROWTH_SIZE;
 
        if (initial_size > 0)
                mem_pool_alloc_block(pool, initial_size, NULL);
-
-       *mem_pool = pool;
 }
 
-void mem_pool_discard(struct mem_pool *mem_pool, int invalidate_memory)
+void mem_pool_discard(struct mem_pool *pool, int invalidate_memory)
 {
        struct mp_block *block, *block_to_free;
 
-       block = mem_pool->mp_block;
+       block = pool->mp_block;
        while (block)
        {
                block_to_free = block;
@@ -66,10 +60,11 @@ void mem_pool_discard(struct mem_pool *mem_pool, int invalidate_memory)
                free(block_to_free);
        }
 
-       free(mem_pool);
+       pool->mp_block = NULL;
+       pool->pool_alloc = 0;
 }
 
-void *mem_pool_alloc(struct mem_pool *mem_pool, size_t len)
+void *mem_pool_alloc(struct mem_pool *pool, size_t len)
 {
        struct mp_block *p = NULL;
        void *r;
@@ -78,15 +73,15 @@ void *mem_pool_alloc(struct mem_pool *mem_pool, size_t len)
        if (len & (sizeof(uintmax_t) - 1))
                len += sizeof(uintmax_t) - (len & (sizeof(uintmax_t) - 1));
 
-       if (mem_pool->mp_block &&
-           mem_pool->mp_block->end - mem_pool->mp_block->next_free >= len)
-               p = mem_pool->mp_block;
+       if (pool->mp_block &&
+           pool->mp_block->end - pool->mp_block->next_free >= len)
+               p = pool->mp_block;
 
        if (!p) {
-               if (len >= (mem_pool->block_alloc / 2))
-                       return mem_pool_alloc_block(mem_pool, len, mem_pool->mp_block);
+               if (len >= (pool->block_alloc / 2))
+                       return mem_pool_alloc_block(pool, len, pool->mp_block);
 
-               p = mem_pool_alloc_block(mem_pool, mem_pool->block_alloc, NULL);
+               p = mem_pool_alloc_block(pool, pool->block_alloc, NULL);
        }
 
        r = p->next_free;
@@ -94,20 +89,38 @@ void *mem_pool_alloc(struct mem_pool *mem_pool, size_t len)
        return r;
 }
 
-void *mem_pool_calloc(struct mem_pool *mem_pool, size_t count, size_t size)
+void *mem_pool_calloc(struct mem_pool *pool, size_t count, size_t size)
 {
        size_t len = st_mult(count, size);
-       void *r = mem_pool_alloc(mem_pool, len);
+       void *r = mem_pool_alloc(pool, len);
        memset(r, 0, len);
        return r;
 }
 
-int mem_pool_contains(struct mem_pool *mem_pool, void *mem)
+char *mem_pool_strdup(struct mem_pool *pool, const char *str)
+{
+       size_t len = strlen(str) + 1;
+       char *ret = mem_pool_alloc(pool, len);
+
+       return memcpy(ret, str, len);
+}
+
+char *mem_pool_strndup(struct mem_pool *pool, const char *str, size_t len)
+{
+       char *p = memchr(str, '\0', len);
+       size_t actual_len = (p ? p - str : len);
+       char *ret = mem_pool_alloc(pool, actual_len+1);
+
+       ret[actual_len] = '\0';
+       return memcpy(ret, str, actual_len);
+}
+
+int mem_pool_contains(struct mem_pool *pool, void *mem)
 {
        struct mp_block *p;
 
        /* Check if memory is allocated in a block */
-       for (p = mem_pool->mp_block; p; p = p->next_block)
+       for (p = pool->mp_block; p; p = p->next_block)
                if ((mem >= ((void *)p->space)) &&
                    (mem < ((void *)p->end)))
                        return 1;
index 999d3c3a52cc49b6dec896fc1e6b31ea8ac078d5..fe7507f022bba40d74aab341e99269ead7171695 100644 (file)
@@ -24,12 +24,12 @@ struct mem_pool {
 /*
  * Initialize mem_pool with specified initial size.
  */
-void mem_pool_init(struct mem_pool **mem_pool, size_t initial_size);
+void mem_pool_init(struct mem_pool *pool, size_t initial_size);
 
 /*
- * Discard a memory pool and free all the memory it is responsible for.
+ * Discard all the memory the memory pool is responsible for.
  */
-void mem_pool_discard(struct mem_pool *mem_pool, int invalidate_memory);
+void mem_pool_discard(struct mem_pool *pool, int invalidate_memory);
 
 /*
  * Alloc memory from the mem_pool.
@@ -41,6 +41,12 @@ void *mem_pool_alloc(struct mem_pool *pool, size_t len);
  */
 void *mem_pool_calloc(struct mem_pool *pool, size_t count, size_t size);
 
+/*
+ * Allocate memory from the memory pool and copy str into it.
+ */
+char *mem_pool_strdup(struct mem_pool *pool, const char *str);
+char *mem_pool_strndup(struct mem_pool *pool, const char *str, size_t len);
+
 /*
  * Move the memory associated with the 'src' pool to the 'dst' pool. The 'src'
  * pool will be empty and not contain any memory. It still needs to be free'd
@@ -52,6 +58,6 @@ void mem_pool_combine(struct mem_pool *dst, struct mem_pool *src);
  * Check if a memory pointed at by 'mem' is part of the range of
  * memory managed by the specified mem_pool.
  */
-int mem_pool_contains(struct mem_pool *mem_pool, void *mem);
+int mem_pool_contains(struct mem_pool *pool, void *mem);
 
 #endif
diff --git a/merge.c b/merge.c
index 753e461659e62812e60fe863bf76269cc8784f82..5fb88af10254a75557697345fd25cfcf19df9748 100644 (file)
--- a/merge.c
+++ b/merge.c
@@ -80,8 +80,8 @@ int checkout_fast_forward(struct repository *r,
        }
 
        memset(&opts, 0, sizeof(opts));
+       dir_init(&dir);
        if (overwrite_ignore) {
-               memset(&dir, 0, sizeof(dir));
                dir.flags |= DIR_SHOW_IGNORED;
                setup_standard_excludes(&dir);
                opts.dir = &dir;
@@ -102,6 +102,7 @@ int checkout_fast_forward(struct repository *r,
                clear_unpack_trees_porcelain(&opts);
                return -1;
        }
+       dir_clear(&dir);
        clear_unpack_trees_porcelain(&opts);
 
        if (write_locked_index(r->index, &lock_file, COMMIT_LOCK))
index 3a69e60faa9c95dcf388cd295d040e9b88e0defd..a89086ee720f842359eefe58f369af2774457438 100644 (file)
@@ -21,3 +21,8 @@ translate_merge_tool_path() {
                echo bcompare
        fi
 }
+
+list_tool_variants () {
+       echo bc
+       echo bc3
+}
diff --git a/mergetools/bc3 b/mergetools/bc3
deleted file mode 100644 (file)
index 5d8dd48..0000000
+++ /dev/null
@@ -1 +0,0 @@
-. "$MERGE_TOOLS_DIR/bc"
diff --git a/mergetools/gvimdiff3 b/mergetools/gvimdiff3
deleted file mode 100644 (file)
index 04a5bb0..0000000
+++ /dev/null
@@ -1 +0,0 @@
-. "$MERGE_TOOLS_DIR/vimdiff"
similarity index 100%
rename from mergetools/gvimdiff2
rename to mergetools/nvimdiff
index 10d86f3e19304125cecf06ddad928b9ffe2d0c08..abc8ce4ec44e190812ba46b39b8ba2dec1cc14fe 100644 (file)
@@ -5,7 +5,7 @@ diff_cmd () {
 
 merge_cmd () {
        case "$1" in
-       gvimdiff|vimdiff)
+       *vimdiff)
                if $base_present
                then
                        "$merge_tool_path" -f -d -c '4wincmd w | wincmd J' \
@@ -15,11 +15,11 @@ merge_cmd () {
                                "$LOCAL" "$MERGED" "$REMOTE"
                fi
                ;;
-       gvimdiff2|vimdiff2)
+       *vimdiff2)
                "$merge_tool_path" -f -d -c 'wincmd l' \
                        "$LOCAL" "$MERGED" "$REMOTE"
                ;;
-       gvimdiff3|vimdiff3)
+       *vimdiff3)
                if $base_present
                then
                        "$merge_tool_path" -f -d -c 'hid | hid | hid' \
@@ -34,10 +34,13 @@ merge_cmd () {
 
 translate_merge_tool_path() {
        case "$1" in
-       gvimdiff|gvimdiff2|gvimdiff3)
+       nvimdiff*)
+               echo nvim
+               ;;
+       gvimdiff*)
                echo gvim
                ;;
-       vimdiff|vimdiff2|vimdiff3)
+       vimdiff*)
                echo vim
                ;;
        esac
@@ -46,3 +49,11 @@ translate_merge_tool_path() {
 exit_code_trustable () {
        true
 }
+
+list_tool_variants () {
+       for prefix in '' g n; do
+               for suffix in '' 2 3; do
+                       echo "${prefix}vimdiff${suffix}"
+               done
+       done
+}
diff --git a/mergetools/vimdiff2 b/mergetools/vimdiff2
deleted file mode 100644 (file)
index 04a5bb0..0000000
+++ /dev/null
@@ -1 +0,0 @@
-. "$MERGE_TOOLS_DIR/vimdiff"
diff --git a/mergetools/vimdiff3 b/mergetools/vimdiff3
deleted file mode 100644 (file)
index 04a5bb0..0000000
+++ /dev/null
@@ -1 +0,0 @@
-. "$MERGE_TOOLS_DIR/vimdiff"
diff --git a/midx.c b/midx.c
index a5fb797edeeae46b76f8f926d4b9d40b2236878d..e9b2e1253a678836dab68a1f15cdaf954444cfea 100644 (file)
--- a/midx.c
+++ b/midx.c
@@ -17,7 +17,6 @@
 #define MIDX_BYTE_HASH_VERSION 5
 #define MIDX_BYTE_NUM_CHUNKS 6
 #define MIDX_BYTE_NUM_PACKS 8
-#define MIDX_HASH_VERSION 1
 #define MIDX_HEADER_SIZE 12
 #define MIDX_MIN_SIZE (MIDX_HEADER_SIZE + the_hash_algo->rawsz)
 
 
 #define PACK_EXPIRED UINT_MAX
 
+static uint8_t oid_version(void)
+{
+       switch (hash_algo_by_ptr(the_hash_algo)) {
+       case GIT_HASH_SHA1:
+               return 1;
+       case GIT_HASH_SHA256:
+               return 2;
+       default:
+               die(_("invalid hash version"));
+       }
+}
+
 static char *get_midx_filename(const char *object_dir)
 {
        return xstrfmt("%s/pack/multi-pack-index", object_dir);
@@ -90,8 +101,11 @@ struct multi_pack_index *load_multi_pack_index(const char *object_dir, int local
                      m->version);
 
        hash_version = m->data[MIDX_BYTE_HASH_VERSION];
-       if (hash_version != MIDX_HASH_VERSION)
-               die(_("hash version %u does not match"), hash_version);
+       if (hash_version != oid_version()) {
+               error(_("multi-pack-index hash version %u does not match version %u"),
+                     hash_version, oid_version());
+               goto cleanup_fail;
+       }
        m->hash_len = the_hash_algo->rawsz;
 
        m->num_chunks = m->data[MIDX_BYTE_NUM_CHUNKS];
@@ -418,7 +432,7 @@ static size_t write_midx_header(struct hashfile *f,
 
        hashwrite_be32(f, MIDX_SIGNATURE);
        byte_values[0] = MIDX_VERSION;
-       byte_values[1] = MIDX_HASH_VERSION;
+       byte_values[1] = oid_version();
        byte_values[2] = num_chunks;
        byte_values[3] = 0; /* unused */
        hashwrite(f, byte_values, sizeof(byte_values));
@@ -807,11 +821,9 @@ static int write_midx_internal(const char *object_dir, struct multi_pack_index *
        int result = 0;
 
        midx_name = get_midx_filename(object_dir);
-       if (safe_create_leading_directories(midx_name)) {
-               UNLEAK(midx_name);
+       if (safe_create_leading_directories(midx_name))
                die_errno(_("unable to create leading directories of %s"),
                          midx_name);
-       }
 
        if (m)
                packs.m = m;
@@ -1051,10 +1063,8 @@ void clear_midx_file(struct repository *r)
                r->objects->multi_pack_index = NULL;
        }
 
-       if (remove_path(midx)) {
-               UNLEAK(midx);
+       if (remove_path(midx))
                die(_("failed to clear multi-pack-index at %s"), midx);
-       }
 
        free(midx);
 }
@@ -1105,8 +1115,17 @@ int verify_midx_file(struct repository *r, const char *object_dir, unsigned flag
        struct multi_pack_index *m = load_multi_pack_index(object_dir, 1);
        verify_midx_error = 0;
 
-       if (!m)
-               return 0;
+       if (!m) {
+               int result = 0;
+               struct stat sb;
+               char *filename = get_midx_filename(object_dir);
+               if (!stat(filename, &sb)) {
+                       error(_("multi-pack-index file exists, but failed to parse"));
+                       result = 1;
+               }
+               free(filename);
+               return result;
+       }
 
        if (flags & MIDX_PROGRESS)
                progress = start_progress(_("Looking for referenced packfiles"),
@@ -1371,7 +1390,7 @@ static int fill_included_packs_batch(struct repository *r,
 
        free(pack_info);
 
-       if (total_size < batch_size || packs_to_repack < 2)
+       if (packs_to_repack < 2)
                return 1;
 
        return 0;
@@ -1383,6 +1402,7 @@ int midx_repack(struct repository *r, const char *object_dir, size_t batch_size,
        uint32_t i;
        unsigned char *include_pack;
        struct child_process cmd = CHILD_PROCESS_INIT;
+       FILE *cmd_in;
        struct strbuf base_name = STRBUF_INIT;
        struct multi_pack_index *m = load_multi_pack_index(object_dir, 1);
 
@@ -1435,6 +1455,8 @@ int midx_repack(struct repository *r, const char *object_dir, size_t batch_size,
                goto cleanup;
        }
 
+       cmd_in = xfdopen(cmd.in, "w");
+
        for (i = 0; i < m->num_objects; i++) {
                struct object_id oid;
                uint32_t pack_int_id = nth_midxed_pack_int_id(m, i);
@@ -1443,10 +1465,9 @@ int midx_repack(struct repository *r, const char *object_dir, size_t batch_size,
                        continue;
 
                nth_midxed_object_oid(&oid, m, i);
-               xwrite(cmd.in, oid_to_hex(&oid), the_hash_algo->hexsz);
-               xwrite(cmd.in, "\n", 1);
+               fprintf(cmd_in, "%s\n", oid_to_hex(&oid));
        }
-       close(cmd.in);
+       fclose(cmd_in);
 
        if (finish_command(&cmd)) {
                error(_("could not finish pack-objects"));
index f439d47af81d1b8772b181cead999bba28980e21..c4fc9dd74ea81c20830ec1b79788a69faaccaf9a 100644 (file)
@@ -239,12 +239,33 @@ int read_loose_object(const char *path,
                      unsigned long *size,
                      void **contents);
 
+/* Retry packed storage after checking packed and loose storage */
+#define HAS_OBJECT_RECHECK_PACKED 1
+
+/*
+ * Returns 1 if the object exists. This function will not lazily fetch objects
+ * in a partial clone.
+ */
+int has_object(struct repository *r, const struct object_id *oid,
+              unsigned flags);
+
+/*
+ * These macros and functions are deprecated. If checking existence for an
+ * object that is likely to be missing and/or whose absence is relatively
+ * inconsequential (or is consequential but the caller is prepared to handle
+ * it), use has_object(), which has better defaults (no lazy fetch in a partial
+ * clone and no rechecking of packed storage). In the unlikely event that a
+ * caller needs to assert existence of an object that it fully expects to
+ * exist, and wants to trigger a lazy fetch in a partial clone, use
+ * oid_object_info_extended() with a NULL struct object_info.
+ *
+ * These functions can be removed once all callers have migrated to
+ * has_object() and/or oid_object_info_extended().
+ */
 #ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
 #define has_sha1_file_with_flags(sha1, flags) repo_has_sha1_file_with_flags(the_repository, sha1, flags)
 #define has_sha1_file(sha1) repo_has_sha1_file(the_repository, sha1)
 #endif
-
-/* Same as the above, except for struct object_id. */
 int repo_has_object_file(struct repository *r, const struct object_id *oid);
 int repo_has_object_file_with_flags(struct repository *r,
                                    const struct object_id *oid, int flags);
index c57618d53736c754cee32b341f7c97d881c3036c..f0507432ee35ba8646a510d1a28ec3561f6bcb30 100644 (file)
@@ -525,7 +525,8 @@ void parse_options_start(struct parse_opt_ctx_t *ctx,
        parse_options_start_1(ctx, argc, argv, prefix, options, flags);
 }
 
-static void show_negated_gitcomp(const struct option *opts, int nr_noopts)
+static void show_negated_gitcomp(const struct option *opts, int show_all,
+                                int nr_noopts)
 {
        int printed_dashdash = 0;
 
@@ -535,7 +536,8 @@ static void show_negated_gitcomp(const struct option *opts, int nr_noopts)
 
                if (!opts->long_name)
                        continue;
-               if (opts->flags & (PARSE_OPT_HIDDEN | PARSE_OPT_NOCOMPLETE))
+               if (!show_all &&
+                       (opts->flags & (PARSE_OPT_HIDDEN | PARSE_OPT_NOCOMPLETE)))
                        continue;
                if (opts->flags & PARSE_OPT_NONEG)
                        continue;
@@ -572,7 +574,7 @@ static void show_negated_gitcomp(const struct option *opts, int nr_noopts)
        }
 }
 
-static int show_gitcomp(const struct option *opts)
+static int show_gitcomp(const struct option *opts, int show_all)
 {
        const struct option *original_opts = opts;
        int nr_noopts = 0;
@@ -582,7 +584,8 @@ static int show_gitcomp(const struct option *opts)
 
                if (!opts->long_name)
                        continue;
-               if (opts->flags & (PARSE_OPT_HIDDEN | PARSE_OPT_NOCOMPLETE))
+               if (!show_all &&
+                       (opts->flags & (PARSE_OPT_HIDDEN | PARSE_OPT_NOCOMPLETE)))
                        continue;
 
                switch (opts->type) {
@@ -610,8 +613,8 @@ static int show_gitcomp(const struct option *opts)
                        nr_noopts++;
                printf(" --%s%s", opts->long_name, suffix);
        }
-       show_negated_gitcomp(original_opts, -1);
-       show_negated_gitcomp(original_opts, nr_noopts);
+       show_negated_gitcomp(original_opts, show_all, -1);
+       show_negated_gitcomp(original_opts, show_all, nr_noopts);
        fputc('\n', stdout);
        return PARSE_OPT_COMPLETE;
 }
@@ -723,9 +726,14 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
                if (internal_help && ctx->total == 1 && !strcmp(arg + 1, "h"))
                        goto show_usage;
 
-               /* lone --git-completion-helper is asked by git-completion.bash */
-               if (ctx->total == 1 && !strcmp(arg + 1, "-git-completion-helper"))
-                       return show_gitcomp(options);
+               /*
+                * lone --git-completion-helper and --git-completion-helper-all
+                * are asked by git-completion.bash
+                */
+               if (ctx->total == 1 && !strcmp(arg, "--git-completion-helper"))
+                       return show_gitcomp(options, 0);
+               if (ctx->total == 1 && !strcmp(arg, "--git-completion-helper-all"))
+                       return show_gitcomp(options, 1);
 
                if (arg[1] != '-') {
                        ctx->opt = arg + 1;
index 46af94209305529253c0308a69db9caabd8b6624..7030d8f3da6328cde9557f91cfd80ae60040cfd6 100644 (file)
@@ -314,7 +314,7 @@ int parse_opt_passthru_argv(const struct option *, const char *, int);
 #define OPT__FORCE(var, h, f) OPT_COUNTUP_F('f', "force",   (var), (h), (f))
 #define OPT__ABBREV(var)  \
        { OPTION_CALLBACK, 0, "abbrev", (var), N_("n"), \
-         N_("use <n> digits to display SHA-1s"),       \
+         N_("use <n> digits to display object names"), \
          PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }
 #define OPT__COLOR(var, h) \
        OPT_COLOR_FLAG(0, "color", (var), (h))
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 54c9ed0ddee52e4d5b59b59b74e0dbc738ae3ac9..10df990959e63938e1742d1cdaf0d009b61bee96 100644 (file)
@@ -723,6 +723,32 @@ sub config_int {
        return scalar _config_common({'kind' => '--int'}, @_);
 }
 
+=item config_regexp ( RE )
+
+Retrieve the list of configuration key names matching the regular
+expression C<RE>. The return value is a list of strings matching
+this regex.
+
+=cut
+
+sub config_regexp {
+       my ($self, $regex) = _maybe_self(@_);
+       try {
+               my @cmd = ('config', '--name-only', '--get-regexp', $regex);
+               unshift @cmd, $self if $self;
+               my @matches = command(@cmd);
+               return @matches;
+       } catch Git::Error::Command with {
+               my $E = shift;
+               if ($E->value() == 1) {
+                       my @matches = ();
+                       return @matches;
+               } else {
+                       throw $E;
+               }
+       };
+}
+
 # Common subroutine to implement bulk of what the config* family of methods
 # do. This currently wraps command('config') so it is not so fast.
 sub _config_common {
index d20fc440aba9fd39d9f0290b5d58fded5344fdd9..75b1e75f6ae4b031a1c40b74768af833945a6cf4 100644 (file)
--- a/po/fr.po
+++ b/po/fr.po
@@ -6503,7 +6503,7 @@ msgstr "'%s' ne peut pas Ãªtre résolue comme une branche"
 #: remote.c:1088
 #, c-format
 msgid "unable to delete '%s': remote ref does not exist"
-msgstr "suppression d '%s' impossible : la référence distante n'existe pas"
+msgstr "suppression de '%s' impossible : la référence distante n'existe pas"
 
 #: remote.c:1100
 #, c-format
index 3eda914518bfdcd211552d41b5439125b1ea27ed..31014e6fca0512d16b0fbcc35c7fbfd43426e5c8 100644 (file)
@@ -319,9 +319,12 @@ static void finish_if_sparse(struct progress *progress)
 
 void stop_progress(struct progress **p_progress)
 {
+       if (!p_progress)
+               BUG("don't provide NULL to stop_progress");
+
        finish_if_sparse(*p_progress);
 
-       if (p_progress && *p_progress) {
+       if (*p_progress) {
                trace2_data_intmax("progress", the_repository, "total_objects",
                                   (*p_progress)->total);
 
@@ -338,7 +341,12 @@ void stop_progress(struct progress **p_progress)
 
 void stop_progress_msg(struct progress **p_progress, const char *msg)
 {
-       struct progress *progress = *p_progress;
+       struct progress *progress;
+
+       if (!p_progress)
+               BUG("don't provide NULL to stop_progress_msg");
+
+       progress = *p_progress;
        if (!progress)
                return;
        *p_progress = NULL;
index d1dd3424bbaa56e21950e6b95a56fcde87cd5450..8d964fc65edcff60fe011d540211cb244a60032e 100644 (file)
@@ -21,7 +21,7 @@ enum protocol_version get_protocol_version_config(void)
        const char *git_test_k = "GIT_TEST_PROTOCOL_VERSION";
        const char *git_test_v;
 
-       if (!git_config_get_string_const("protocol.version", &value)) {
+       if (!git_config_get_string_tmp("protocol.version", &value)) {
                enum protocol_version version = parse_protocol_version(value);
 
                if (version == protocol_unknown_version)
index 8ed1c29b541121214ab50b21a2f262edc406c807..fa291cdbee0bb435122194c3e0fa8efdb750c47e 100644 (file)
@@ -89,8 +89,10 @@ static struct mem_pool *find_mem_pool(struct index_state *istate)
        else
                pool_ptr = &istate->ce_mem_pool;
 
-       if (!*pool_ptr)
-               mem_pool_init(pool_ptr, 0);
+       if (!*pool_ptr) {
+               *pool_ptr = xmalloc(sizeof(**pool_ptr));
+               mem_pool_init(*pool_ptr, 0);
+       }
 
        return *pool_ptr;
 }
@@ -2006,11 +2008,12 @@ static unsigned long load_all_cache_entries(struct index_state *istate,
 {
        unsigned long consumed;
 
+       istate->ce_mem_pool = xmalloc(sizeof(*istate->ce_mem_pool));
        if (istate->version == 4) {
-               mem_pool_init(&istate->ce_mem_pool,
+               mem_pool_init(istate->ce_mem_pool,
                                estimate_cache_size_from_compressed(istate->cache_nr));
        } else {
-               mem_pool_init(&istate->ce_mem_pool,
+               mem_pool_init(istate->ce_mem_pool,
                                estimate_cache_size(mmap_size, istate->cache_nr));
        }
 
@@ -2070,7 +2073,8 @@ static unsigned long load_cache_entries_threaded(struct index_state *istate, con
        if (istate->name_hash_initialized)
                BUG("the name hash isn't thread safe");
 
-       mem_pool_init(&istate->ce_mem_pool, 0);
+       istate->ce_mem_pool = xmalloc(sizeof(*istate->ce_mem_pool));
+       mem_pool_init(istate->ce_mem_pool, 0);
 
        /* ensure we have no more threads than we have blocks to process */
        if (nr_threads > ieot->nr)
@@ -2097,11 +2101,12 @@ static unsigned long load_cache_entries_threaded(struct index_state *istate, con
                nr = 0;
                for (j = p->ieot_start; j < p->ieot_start + p->ieot_blocks; j++)
                        nr += p->ieot->entries[j].nr;
+               istate->ce_mem_pool = xmalloc(sizeof(*istate->ce_mem_pool));
                if (istate->version == 4) {
-                       mem_pool_init(&p->ce_mem_pool,
+                       mem_pool_init(p->ce_mem_pool,
                                estimate_cache_size_from_compressed(nr));
                } else {
-                       mem_pool_init(&p->ce_mem_pool,
+                       mem_pool_init(p->ce_mem_pool,
                                estimate_cache_size(mmap_size, nr));
                }
 
@@ -2358,7 +2363,7 @@ int discard_index(struct index_state *istate)
 
        if (istate->ce_mem_pool) {
                mem_pool_discard(istate->ce_mem_pool, should_validate_cache_entries());
-               istate->ce_mem_pool = NULL;
+               FREE_AND_NULL(istate->ce_mem_pool);
        }
 
        return 0;
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 9e28912f73aa5f2a9cf0b9430e71bfde96485d3e..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);
 }
@@ -708,10 +708,9 @@ int dwim_log(const char *str, int len, struct object_id *oid, char **log)
 
 static int is_per_worktree_ref(const char *refname)
 {
-       return !strcmp(refname, "HEAD") ||
-               starts_with(refname, "refs/worktree/") ||
-               starts_with(refname, "refs/bisect/") ||
-               starts_with(refname, "refs/rewritten/");
+       return starts_with(refname, "refs/worktree/") ||
+              starts_with(refname, "refs/bisect/") ||
+              starts_with(refname, "refs/rewritten/");
 }
 
 static int is_pseudoref_syntax(const char *refname)
@@ -771,102 +770,6 @@ long get_files_ref_lock_timeout_ms(void)
        return timeout_ms;
 }
 
-static int write_pseudoref(const char *pseudoref, const struct object_id *oid,
-                          const struct object_id *old_oid, struct strbuf *err)
-{
-       const char *filename;
-       int fd;
-       struct lock_file lock = LOCK_INIT;
-       struct strbuf buf = STRBUF_INIT;
-       int ret = -1;
-
-       if (!oid)
-               return 0;
-
-       strbuf_addf(&buf, "%s\n", oid_to_hex(oid));
-
-       filename = git_path("%s", pseudoref);
-       fd = hold_lock_file_for_update_timeout(&lock, filename, 0,
-                                              get_files_ref_lock_timeout_ms());
-       if (fd < 0) {
-               strbuf_addf(err, _("could not open '%s' for writing: %s"),
-                           filename, strerror(errno));
-               goto done;
-       }
-
-       if (old_oid) {
-               struct object_id actual_old_oid;
-
-               if (read_ref(pseudoref, &actual_old_oid)) {
-                       if (!is_null_oid(old_oid)) {
-                               strbuf_addf(err, _("could not read ref '%s'"),
-                                           pseudoref);
-                               rollback_lock_file(&lock);
-                               goto done;
-                       }
-               } else if (is_null_oid(old_oid)) {
-                       strbuf_addf(err, _("ref '%s' already exists"),
-                                   pseudoref);
-                       rollback_lock_file(&lock);
-                       goto done;
-               } else if (!oideq(&actual_old_oid, old_oid)) {
-                       strbuf_addf(err, _("unexpected object ID when writing '%s'"),
-                                   pseudoref);
-                       rollback_lock_file(&lock);
-                       goto done;
-               }
-       }
-
-       if (write_in_full(fd, buf.buf, buf.len) < 0) {
-               strbuf_addf(err, _("could not write to '%s'"), filename);
-               rollback_lock_file(&lock);
-               goto done;
-       }
-
-       commit_lock_file(&lock);
-       ret = 0;
-done:
-       strbuf_release(&buf);
-       return ret;
-}
-
-static int delete_pseudoref(const char *pseudoref, const struct object_id *old_oid)
-{
-       const char *filename;
-
-       filename = git_path("%s", pseudoref);
-
-       if (old_oid && !is_null_oid(old_oid)) {
-               struct lock_file lock = LOCK_INIT;
-               int fd;
-               struct object_id actual_old_oid;
-
-               fd = hold_lock_file_for_update_timeout(
-                               &lock, filename, 0,
-                               get_files_ref_lock_timeout_ms());
-               if (fd < 0) {
-                       error_errno(_("could not open '%s' for writing"),
-                                   filename);
-                       return -1;
-               }
-               if (read_ref(pseudoref, &actual_old_oid))
-                       die(_("could not read ref '%s'"), pseudoref);
-               if (!oideq(&actual_old_oid, old_oid)) {
-                       error(_("unexpected object ID when deleting '%s'"),
-                             pseudoref);
-                       rollback_lock_file(&lock);
-                       return -1;
-               }
-
-               unlink(filename);
-               rollback_lock_file(&lock);
-       } else {
-               unlink(filename);
-       }
-
-       return 0;
-}
-
 int refs_delete_ref(struct ref_store *refs, const char *msg,
                    const char *refname,
                    const struct object_id *old_oid,
@@ -875,11 +778,6 @@ int refs_delete_ref(struct ref_store *refs, const char *msg,
        struct ref_transaction *transaction;
        struct strbuf err = STRBUF_INIT;
 
-       if (ref_type(refname) == REF_TYPE_PSEUDOREF) {
-               assert(refs == get_main_ref_store(the_repository));
-               return delete_pseudoref(refname, old_oid);
-       }
-
        transaction = ref_store_transaction_begin(refs, &err);
        if (!transaction ||
            ref_transaction_delete(transaction, refname, old_oid,
@@ -1210,18 +1108,13 @@ int refs_update_ref(struct ref_store *refs, const char *msg,
        struct strbuf err = STRBUF_INIT;
        int ret = 0;
 
-       if (ref_type(refname) == REF_TYPE_PSEUDOREF) {
-               assert(refs == get_main_ref_store(the_repository));
-               ret = write_pseudoref(refname, new_oid, old_oid, &err);
-       } else {
-               t = ref_store_transaction_begin(refs, &err);
-               if (!t ||
-                   ref_transaction_update(t, refname, new_oid, old_oid,
-                                          flags, msg, &err) ||
-                   ref_transaction_commit(t, &err)) {
-                       ret = 1;
-                       ref_transaction_free(t);
-               }
+       t = ref_store_transaction_begin(refs, &err);
+       if (!t ||
+           ref_transaction_update(t, refname, new_oid, old_oid, flags, msg,
+                                  &err) ||
+           ref_transaction_commit(t, &err)) {
+               ret = 1;
+               ref_transaction_free(t);
        }
        if (ret) {
                const char *str = _("update_ref failed for ref '%s': %s");
@@ -1634,11 +1527,37 @@ int for_each_rawref(each_ref_fn fn, void *cb_data)
        return refs_for_each_rawref(get_main_ref_store(the_repository), fn, cb_data);
 }
 
+static int refs_read_special_head(struct ref_store *ref_store,
+                                 const char *refname, struct object_id *oid,
+                                 struct strbuf *referent, unsigned int *type)
+{
+       struct strbuf full_path = STRBUF_INIT;
+       struct strbuf content = STRBUF_INIT;
+       int result = -1;
+       strbuf_addf(&full_path, "%s/%s", ref_store->gitdir, refname);
+
+       if (strbuf_read_file(&content, full_path.buf, 0) < 0)
+               goto done;
+
+       result = parse_loose_ref_contents(content.buf, oid, referent, type);
+
+done:
+       strbuf_release(&full_path);
+       strbuf_release(&content);
+       return result;
+}
+
 int refs_read_raw_ref(struct ref_store *ref_store,
                      const char *refname, struct object_id *oid,
                      struct strbuf *referent, unsigned int *type)
 {
-       return ref_store->be->read_raw_ref(ref_store, refname, oid, referent, type);
+       if (!strcmp(refname, "FETCH_HEAD") || !strcmp(refname, "MERGE_HEAD")) {
+               return refs_read_special_head(ref_store, refname, oid, referent,
+                                             type);
+       }
+
+       return ref_store->be->read_raw_ref(ref_store, refname, oid, referent,
+                                          type);
 }
 
 /* This function needs to return a meaningful errno on failure */
@@ -2031,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 = 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 985631f33edf92afc706061b0d208bd35fab4bdc..dd712e47f4190e6a0f7a1a5ecc446790827e9563 100644 (file)
@@ -67,7 +67,6 @@ struct files_ref_store {
        struct ref_store base;
        unsigned int store_flags;
 
-       char *gitdir;
        char *gitcommondir;
 
        struct ref_cache *loose;
@@ -94,18 +93,17 @@ static struct ref_store *files_ref_store_create(const char *gitdir,
        struct ref_store *ref_store = (struct ref_store *)refs;
        struct strbuf sb = STRBUF_INIT;
 
+       ref_store->gitdir = xstrdup(gitdir);
        base_ref_store_init(ref_store, &refs_be_files);
        refs->store_flags = flags;
 
-       refs->gitdir = xstrdup(gitdir);
        get_common_dir_noenv(&sb, gitdir);
        refs->gitcommondir = strbuf_detach(&sb, NULL);
        strbuf_addf(&sb, "%s/packed-refs", refs->gitcommondir);
        refs->packed_ref_store = packed_ref_store_create(sb.buf, flags);
        strbuf_release(&sb);
 
-       chdir_notify_reparent("files-backend $GIT_DIR",
-                             &refs->gitdir);
+       chdir_notify_reparent("files-backend $GIT_DIR", &refs->base.gitdir);
        chdir_notify_reparent("files-backend $GIT_COMMONDIR",
                              &refs->gitcommondir);
 
@@ -176,7 +174,7 @@ static void files_reflog_path(struct files_ref_store *refs,
        switch (ref_type(refname)) {
        case REF_TYPE_PER_WORKTREE:
        case REF_TYPE_PSEUDOREF:
-               strbuf_addf(sb, "%s/logs/%s", refs->gitdir, refname);
+               strbuf_addf(sb, "%s/logs/%s", refs->base.gitdir, refname);
                break;
        case REF_TYPE_OTHER_PSEUDOREF:
        case REF_TYPE_MAIN_PSEUDOREF:
@@ -198,7 +196,7 @@ static void files_ref_path(struct files_ref_store *refs,
        switch (ref_type(refname)) {
        case REF_TYPE_PER_WORKTREE:
        case REF_TYPE_PSEUDOREF:
-               strbuf_addf(sb, "%s/%s", refs->gitdir, refname);
+               strbuf_addf(sb, "%s/%s", refs->base.gitdir, refname);
                break;
        case REF_TYPE_MAIN_PSEUDOREF:
                if (!skip_prefix(refname, "main-worktree/", &refname))
@@ -360,7 +358,6 @@ static int files_read_raw_ref(struct ref_store *ref_store,
        struct strbuf sb_path = STRBUF_INIT;
        const char *path;
        const char *buf;
-       const char *p;
        struct stat st;
        int fd;
        int ret = -1;
@@ -465,6 +462,21 @@ stat_ref:
        close(fd);
        strbuf_rtrim(&sb_contents);
        buf = sb_contents.buf;
+
+       ret = parse_loose_ref_contents(buf, oid, referent, type);
+
+out:
+       save_errno = errno;
+       strbuf_release(&sb_path);
+       strbuf_release(&sb_contents);
+       errno = save_errno;
+       return ret;
+}
+
+int parse_loose_ref_contents(const char *buf, struct object_id *oid,
+                            struct strbuf *referent, unsigned int *type)
+{
+       const char *p;
        if (skip_prefix(buf, "ref:", &buf)) {
                while (isspace(*buf))
                        buf++;
@@ -472,29 +484,19 @@ stat_ref:
                strbuf_reset(referent);
                strbuf_addstr(referent, buf);
                *type |= REF_ISSYMREF;
-               ret = 0;
-               goto out;
+               return 0;
        }
 
        /*
-        * Please note that FETCH_HEAD has additional
-        * data after the sha.
+        * FETCH_HEAD has additional data after the sha.
         */
        if (parse_oid_hex(buf, oid, &p) ||
            (*p != '\0' && !isspace(*p))) {
                *type |= REF_ISBROKEN;
                errno = EINVAL;
-               goto out;
+               return -1;
        }
-
-       ret = 0;
-
-out:
-       save_errno = errno;
-       strbuf_release(&sb_path);
-       strbuf_release(&sb_contents);
-       errno = save_errno;
-       return ret;
+       return 0;
 }
 
 static void unlock_ref(struct ref_lock *lock)
@@ -2199,12 +2201,11 @@ static struct ref_iterator *files_reflog_iterator_begin(struct ref_store *ref_st
                files_downcast(ref_store, REF_STORE_READ,
                               "reflog_iterator_begin");
 
-       if (!strcmp(refs->gitdir, refs->gitcommondir)) {
+       if (!strcmp(refs->base.gitdir, refs->gitcommondir)) {
                return reflog_iterator_begin(ref_store, refs->gitcommondir);
        } else {
                return merge_ref_iterator_begin(
-                       0,
-                       reflog_iterator_begin(ref_store, refs->gitdir),
+                       0, reflog_iterator_begin(ref_store, refs->base.gitdir),
                        reflog_iterator_begin(ref_store, refs->gitcommondir),
                        reflog_iterator_select, refs);
        }
index 4458a0f69ccb216681dc515bd2986ecdce456c0f..b912f2505fee298225d3daa5719cbe6bdeba2365 100644 (file)
@@ -200,6 +200,7 @@ struct ref_store *packed_ref_store_create(const char *path,
        struct ref_store *ref_store = (struct ref_store *)refs;
 
        base_ref_store_init(ref_store, &refs_be_packed);
+       ref_store->gitdir = xstrdup(path);
        refs->store_flags = store_flags;
 
        refs->path = xstrdup(path);
index 357359a0be4a5bc4e360dd0e13d33ae6c04c4c70..527b0a6e2e636b129cfcff2a88c1c112c41a8c57 100644 (file)
@@ -667,13 +667,22 @@ extern struct ref_storage_be refs_be_packed;
 /*
  * A representation of the reference store for the main repository or
  * a submodule. The ref_store instances for submodules are kept in a
- * linked list.
+ * hash map; see get_submodule_ref_store() for more info.
  */
 struct ref_store {
        /* The backend describing this ref_store's storage scheme: */
        const struct ref_storage_be *be;
+
+       /* The gitdir that this ref_store applies to: */
+       char *gitdir;
 };
 
+/*
+ * Parse contents of a loose ref file.
+ */
+int parse_loose_ref_contents(const char *buf, struct object_id *oid,
+                            struct strbuf *referent, unsigned int *type);
+
 /*
  * Fill in the generic part of refs and add it to our collection of
  * reference stores.
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..0c1833dcb68e15876af63868f2af104df36e0d39 100644 (file)
@@ -39,7 +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;
index 3dcf689341d34f6647b0564ee2f84e11a4c9b3ff..08c2ad23af668a42cca30a5cebfcc2feee1ce895 100644 (file)
@@ -1815,7 +1815,7 @@ void repo_init_revisions(struct repository *r,
 
        revs->repo = r;
        revs->abbrev = DEFAULT_ABBREV;
-       revs->ignore_merges = 1;
+       revs->ignore_merges = -1;
        revs->simplify_history = 1;
        revs->pruning.repo = r;
        revs->pruning.flags.recursive = 1;
@@ -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)
 {
@@ -2345,6 +2353,15 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
                revs->diffopt.flags.tree_in_recursive = 1;
        } else if (!strcmp(arg, "-m")) {
                revs->ignore_merges = 0;
+       } else if ((argcount = parse_long_opt("diff-merges", argv, &optarg))) {
+               if (!strcmp(optarg, "off")) {
+                       revs->ignore_merges = 1;
+               } else {
+                       die(_("unknown value for --diff-merges: %s"), optarg);
+               }
+               return argcount;
+       } else if (!strcmp(arg, "--no-diff-merges")) {
+               revs->ignore_merges = 1;
        } else if (!strcmp(arg, "-c")) {
                revs->diff = 1;
                revs->dense_combined_merges = 0;
@@ -2694,7 +2711,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;
@@ -2783,8 +2800,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) {
@@ -2813,7 +2828,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;
@@ -2854,8 +2869,10 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
                        copy_pathspec(&revs->diffopt.pathspec,
                                      &revs->prune_data);
        }
-       if (revs->combine_merges)
+       if (revs->combine_merges && revs->ignore_merges < 0)
                revs->ignore_merges = 0;
+       if (revs->ignore_merges < 0)
+               revs->ignore_merges = 1;
        if (revs->combined_all_paths && !revs->combine_merges)
                die("--combined-all-paths makes no sense without -c or --cc");
 
@@ -2889,9 +2906,6 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
        if (!revs->reflog_info && revs->grep_filter.use_reflog_filter)
                die("cannot use --grep-reflog without --walk-reflogs");
 
-       if (revs->first_parent_only && revs->bisect)
-               die(_("--first-parent is incompatible with --bisect"));
-
        if (revs->line_level_traverse &&
            (revs->diffopt.output_format & ~(DIFF_FORMAT_PATCH | DIFF_FORMAT_NO_OUTPUT)))
                die(_("-L does not yet support diff formats besides -p and -s"));
index 889216c2d8bd0c330e05ccb439e446b5e0543542..c1e5bcf139d7a31d9bf851ada3bc8373f5ab932e 100644 (file)
@@ -190,11 +190,11 @@ struct rev_info {
                        show_root_diff:1,
                        no_commit_id:1,
                        verbose_header:1,
-                       ignore_merges:1,
                        combine_merges:1,
                        combined_all_paths:1,
                        dense_combined_merges:1,
                        always_show_header:1;
+       int             ignore_merges:2;
 
        /* Format info */
        int             show_notes;
index cc3f8fa88ea96df3480a8721a20fa61a08c2114c..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++)
@@ -355,7 +359,7 @@ static int get_message(struct commit *commit, struct commit_message *out)
        subject_len = find_commit_subject(out->message, &subject);
 
        out->subject = xmemdupz(subject, subject_len);
-       out->label = xstrfmt("%s... %s", abbrev, out->subject);
+       out->label = xstrfmt("%s (%s)", abbrev, out->subject);
        out->parent_label = xstrfmt("parent of %s", out->label);
 
        return 0;
@@ -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;
@@ -5178,13 +5309,14 @@ int complete_action(struct repository *r, struct replay_opts *opts, unsigned fla
                    struct string_list *commands, unsigned autosquash,
                    struct todo_list *todo_list)
 {
-       const char *shortonto, *todo_file = rebase_path_todo();
+       char shortonto[GIT_MAX_HEXSZ + 1];
+       const char *todo_file = rebase_path_todo();
        struct todo_list new_todo = TODO_LIST_INIT;
        struct strbuf *buf = &todo_list->buf, buf2 = STRBUF_INIT;
        struct object_id oid = onto->object.oid;
        int res;
 
-       shortonto = find_unique_abbrev(&oid, DEFAULT_ABBREV);
+       find_unique_abbrev_r(shortonto, &oid, DEFAULT_ABBREV);
 
        if (buf->len == 0) {
                struct todo_item *item = append_new_todo(todo_list);
@@ -5250,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;
 
@@ -5442,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 8904559da2898c05d0144669f5fca28ccf2f7594..dd65bd5c681513c1f7c9bf908dc9f8675e24a829 100644 (file)
@@ -1989,6 +1989,18 @@ int force_object_loose(const struct object_id *oid, time_t mtime)
        return ret;
 }
 
+int has_object(struct repository *r, const struct object_id *oid,
+              unsigned flags)
+{
+       int quick = !(flags & HAS_OBJECT_RECHECK_PACKED);
+       unsigned object_info_flags = OBJECT_INFO_SKIP_FETCH_OBJECT |
+               (quick ? OBJECT_INFO_QUICK : 0);
+
+       if (!startup_info->have_repository)
+               return 0;
+       return oid_object_info_extended(r, oid, NULL, object_info_flags) >= 0;
+}
+
 int repo_has_object_file_with_flags(struct repository *r,
                                    const struct object_id *oid, int flags)
 {
index ef851113c44ee91e594734bf68567110b7ac8c6b..0a60662fa64b34a9b70c9c362fac02aa8c61083c 100644 (file)
@@ -147,7 +147,7 @@ int demultiplex_sideband(const char *me, char *buf, int len,
        switch (band) {
        case 3:
                if (die_on_error)
-                       die("remote error: %s", buf + 1);
+                       die(_("remote error: %s"), buf + 1);
                strbuf_addf(scratch, "%s%s", scratch->len ? "\n" : "",
                            DISPLAY_PREFIX);
                maybe_colorize_sideband(scratch, buf + 1, len);
index e6154e4ea9552cfc2b868453f017ba786cd24a2f..c0e8ad670d0a17a28fd049b6814d8e77c7654dc2 100644 (file)
@@ -79,8 +79,10 @@ void move_cache_to_base_index(struct index_state *istate)
        if (si->base &&
                si->base->ce_mem_pool) {
 
-               if (!istate->ce_mem_pool)
-                       mem_pool_init(&istate->ce_mem_pool, 0);
+               if (!istate->ce_mem_pool) {
+                       istate->ce_mem_pool = xmalloc(sizeof(struct mem_pool));
+                       mem_pool_init(istate->ce_mem_pool, 0);
+               }
 
                mem_pool_combine(istate->ce_mem_pool, istate->split_index->base->ce_mem_pool);
        }
index a52b93a87f8112b2a14c3ea5732dca595c415673..d0b70ca536143adc41d66a448e6b3f9243067076 100644 (file)
@@ -194,7 +194,7 @@ void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,
                char *key;
 
                key = xstrfmt("submodule.%s.ignore", submodule->name);
-               if (repo_config_get_string_const(the_repository, key, &ignore))
+               if (repo_config_get_string_tmp(the_repository, key, &ignore))
                        ignore = submodule->ignore;
                free(key);
 
@@ -1299,7 +1299,7 @@ static int get_fetch_recurse_config(const struct submodule *submodule,
 
                int fetch_recurse = submodule->fetch_recurse;
                key = xstrfmt("submodule.%s.fetchRecurseSubmodules", submodule->name);
-               if (!repo_config_get_string_const(spf->r, key, &value)) {
+               if (!repo_config_get_string_tmp(spf->r, key, &value)) {
                        fetch_recurse = parse_fetch_recurse_submodules_arg(key, value);
                }
                free(key);
index 70ec61cf887fcacb3e7f9ffe09cee636caa37732..2adaf7c2d2747a1426b11a8d75e0cac667232b60 100644 (file)
--- a/t/README
+++ b/t/README
@@ -421,6 +421,10 @@ GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS=<boolean>, when true (which is
 the default when running tests), errors out when an abbreviated option
 is used.
 
+GIT_TEST_DEFAULT_HASH=<hash-algo> specifies which hash algorithm to
+use in the test scripts. Recognized values for <hash-algo> are "sha1"
+and "sha256".
+
 Naming Tests
 ------------
 
index 234c722b485e1ecdf9f00ba56d119c8364a6f949..a6e936721fe660bb110e3d691d61dad80fddc307 100644 (file)
@@ -126,7 +126,7 @@ int cmd__config(int argc, const char **argv)
                        goto exit1;
                }
        } else if (argc == 3 && !strcmp(argv[1], "get_string")) {
-               if (!git_config_get_string_const(argv[2], &v)) {
+               if (!git_config_get_string_tmp(argv[2], &v)) {
                        printf("%s\n", v);
                        goto exit0;
                } else {
index 831b586d022215ff75b4e426d79e7149b3bfb3bb..2430880f78f8ec674666d2fd04f7fded4e00ef89 100644 (file)
@@ -7,14 +7,18 @@
 static int read_midx_file(const char *object_dir)
 {
        uint32_t i;
-       struct multi_pack_index *m = load_multi_pack_index(object_dir, 1);
+       struct multi_pack_index *m;
+
+       setup_git_directory();
+       m = load_multi_pack_index(object_dir, 1);
 
        if (!m)
                return 1;
 
-       printf("header: %08x %d %d %d\n",
+       printf("header: %08x %d %d %d %d\n",
               m->signature,
               m->version,
+              m->hash_len,
               m->num_chunks,
               m->num_packs);
 
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 d71d4c7238210ec3fc3769abb7a6345fb5922480..50222a10c5b1c68d5509c7e4952bdde79bc1a86c 100755 (executable)
@@ -316,6 +316,19 @@ test_expect_success 'init with separate gitdir' '
        test_path_is_dir realgitdir/refs
 '
 
+test_expect_success 'explicit bare & --separate-git-dir incompatible' '
+       test_must_fail git init --bare --separate-git-dir goop.git bare.git 2>err &&
+       test_i18ngrep "mutually exclusive" err
+'
+
+test_expect_success 'implicit bare & --separate-git-dir incompatible' '
+       test_when_finished "rm -rf bare.git" &&
+       mkdir -p bare.git &&
+       test_must_fail env GIT_DIR=. \
+               git -C bare.git init --separate-git-dir goop.git 2>err &&
+       test_i18ngrep "incompatible" err
+'
+
 test_lazy_prereq GETCWD_IGNORES_PERMS '
        base=GETCWD_TEST_BASE_DIR &&
        mkdir -p $base/dir &&
index f8178ee4e392fa5cfdbef07b0f42710ea68bc67b..14cafc138b7875013afeee01d74dbbeb2e56d495 100755 (executable)
@@ -44,7 +44,7 @@ Magic arguments
     --no-ambiguous        negative ambiguity
 
 Standard options
-    --abbrev[=<n>]        use <n> digits to display SHA-1s
+    --abbrev[=<n>]        use <n> digits to display object names
     -v, --verbose         be verbose
     -n, --dry-run         dry run
     -q, --quiet           be quiet
index 27171f826129168aa1e52262e2b2a9b4ca327989..770e7be363cdaa0fbbfc52a03cbc195c0920aad1 100755 (executable)
@@ -160,10 +160,10 @@ test_expect_success 'core.logAllRefUpdates=always creates reflog by default' '
        git reflog exists $outside
 '
 
-test_expect_success 'core.logAllRefUpdates=always creates no reflog for ORIG_HEAD' '
+test_expect_success 'core.logAllRefUpdates=always creates reflog for ORIG_HEAD' '
        test_config core.logAllRefUpdates always &&
        git update-ref ORIG_HEAD $A &&
-       test_must_fail git reflog exists ORIG_HEAD
+       git reflog exists ORIG_HEAD
 '
 
 test_expect_success '--no-create-reflog overrides core.logAllRefUpdates=always' '
@@ -324,7 +324,7 @@ test_expect_success "create $m (logged by config)" '
 test_expect_success "update $m (logged by config)" '
        test_config core.logAllRefUpdates true &&
        GIT_COMMITTER_DATE="2005-05-26 23:33" \
-       git update-ref HEAD'" $B $A "'-m "Switch" &&
+       git update-ref HEAD $B $A -m "Switch" &&
        test $B = $(git show-ref -s --verify $m)
 '
 test_expect_success "set $m (logged by config)" '
@@ -475,57 +475,57 @@ test_expect_success 'git cat-file blob master@{2005-05-26 23:42}:F (expect OTHER
 
 test_expect_success 'given old value for missing pseudoref, do not create' '
        test_must_fail git update-ref PSEUDOREF $A $B 2>err &&
-       test_path_is_missing .git/PSEUDOREF &&
-       test_i18ngrep "could not read ref" err
+       test_must_fail git rev-parse PSEUDOREF &&
+       test_i18ngrep "unable to resolve reference" err
 '
 
 test_expect_success 'create pseudoref' '
        git update-ref PSEUDOREF $A &&
-       test $A = $(cat .git/PSEUDOREF)
+       test $A = $(git rev-parse PSEUDOREF)
 '
 
 test_expect_success 'overwrite pseudoref with no old value given' '
        git update-ref PSEUDOREF $B &&
-       test $B = $(cat .git/PSEUDOREF)
+       test $B = $(git rev-parse PSEUDOREF)
 '
 
 test_expect_success 'overwrite pseudoref with correct old value' '
        git update-ref PSEUDOREF $C $B &&
-       test $C = $(cat .git/PSEUDOREF)
+       test $C = $(git rev-parse PSEUDOREF)
 '
 
 test_expect_success 'do not overwrite pseudoref with wrong old value' '
        test_must_fail git update-ref PSEUDOREF $D $E 2>err &&
-       test $C = $(cat .git/PSEUDOREF) &&
-       test_i18ngrep "unexpected object ID" err
+       test $C = $(git rev-parse PSEUDOREF) &&
+       test_i18ngrep "cannot lock ref.*expected" err
 '
 
 test_expect_success 'delete pseudoref' '
        git update-ref -d PSEUDOREF &&
-       test_path_is_missing .git/PSEUDOREF
+       test_must_fail git rev-parse PSEUDOREF
 '
 
 test_expect_success 'do not delete pseudoref with wrong old value' '
        git update-ref PSEUDOREF $A &&
        test_must_fail git update-ref -d PSEUDOREF $B 2>err &&
-       test $A = $(cat .git/PSEUDOREF) &&
-       test_i18ngrep "unexpected object ID" err
+       test $A = $(git rev-parse PSEUDOREF) &&
+       test_i18ngrep "cannot lock ref.*expected" err
 '
 
 test_expect_success 'delete pseudoref with correct old value' '
        git update-ref -d PSEUDOREF $A &&
-       test_path_is_missing .git/PSEUDOREF
+       test_must_fail git rev-parse PSEUDOREF
 '
 
 test_expect_success 'create pseudoref with old OID zero' '
        git update-ref PSEUDOREF $A $Z &&
-       test $A = $(cat .git/PSEUDOREF)
+       test $A = $(git rev-parse PSEUDOREF)
 '
 
 test_expect_success 'do not overwrite pseudoref with old OID zero' '
        test_when_finished git update-ref -d PSEUDOREF &&
        test_must_fail git update-ref PSEUDOREF $B $Z 2>err &&
-       test $A = $(cat .git/PSEUDOREF) &&
+       test $A = $(git rev-parse PSEUDOREF) &&
        test_i18ngrep "already exists" err
 '
 
index 331899ddc4bd33805c83ebad8983233da7d67ec8..74af927fbaa7300ed3a20fb51fe32f8b5fcd1835 100755 (executable)
@@ -31,7 +31,10 @@ test_expect_success 'create_symref(FOO, refs/heads/master)' '
 test_expect_success 'delete_refs(FOO, refs/tags/new-tag)' '
        git rev-parse FOO -- &&
        git rev-parse refs/tags/new-tag -- &&
-       $RUN delete-refs 0 nothing FOO refs/tags/new-tag &&
+       m=$(git rev-parse master) &&
+       REF_NO_DEREF=1 &&
+       $RUN delete-refs $REF_NO_DEREF nothing FOO refs/tags/new-tag &&
+       test_must_fail git rev-parse --symbolic-full-name FOO &&
        test_must_fail git rev-parse FOO -- &&
        test_must_fail git rev-parse refs/tags/new-tag --
 '
index da58d867a56f57360c7090bced0911350bc5fef0..f6e741c6c055a4e62fdbb16f50eedc7dcd4b383d 100755 (executable)
@@ -7,6 +7,7 @@ test_description='reference transaction hooks'
 test_expect_success setup '
        mkdir -p .git/hooks &&
        test_commit PRE &&
+       PRE_OID=$(git rev-parse PRE) &&
        test_commit POST &&
        POST_OID=$(git rev-parse POST)
 '
@@ -106,4 +107,30 @@ test_expect_success 'hook gets all queued updates in aborted state' '
        test_cmp expect actual
 '
 
+test_expect_success 'interleaving hook calls succeed' '
+       test_when_finished "rm -r target-repo.git" &&
+
+       git init --bare target-repo.git &&
+
+       write_script target-repo.git/hooks/reference-transaction <<-\EOF &&
+               echo $0 "$@" >>actual
+       EOF
+
+       write_script target-repo.git/hooks/update <<-\EOF &&
+               echo $0 "$@" >>actual
+       EOF
+
+       cat >expect <<-EOF &&
+               hooks/update refs/tags/PRE $ZERO_OID $PRE_OID
+               hooks/reference-transaction prepared
+               hooks/reference-transaction committed
+               hooks/update refs/tags/POST $ZERO_OID $POST_OID
+               hooks/reference-transaction prepared
+               hooks/reference-transaction committed
+       EOF
+
+       git push ./target-repo.git PRE POST &&
+       test_cmp expect target-repo.git/actual
+'
+
 test_done
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
index ffdfb16f580571a50e542b8ddb50915db8ad0584..740ce56eab5c78b18a85834e9dc9c091d195c2d1 100755 (executable)
@@ -152,7 +152,7 @@ test_expect_success 'ls-files -o --directory with mix dir/file pathspecs' '
        )
 '
 
-test_expect_success 'ls-files --o --directory with glob filetype match' '
+test_expect_success 'ls-files -o --directory with glob filetype match' '
        (
                cd nested &&
 
@@ -168,7 +168,7 @@ test_expect_success 'ls-files --o --directory with glob filetype match' '
        )
 '
 
-test_expect_success 'ls-files --o --directory with mix of tracked states' '
+test_expect_success 'ls-files -o --directory with mix of tracked states' '
        (
                cd nested &&
 
@@ -184,7 +184,7 @@ test_expect_success 'ls-files --o --directory with mix of tracked states' '
        )
 '
 
-test_expect_success 'ls-files --o --directory with glob filetype match only' '
+test_expect_success 'ls-files -o --directory with glob filetype match only' '
        (
                cd nested &&
 
@@ -198,7 +198,7 @@ test_expect_success 'ls-files --o --directory with glob filetype match only' '
        )
 '
 
-test_expect_success 'ls-files --o --directory to get immediate paths under one dir only' '
+test_expect_success 'ls-files -o --directory to get immediate paths under one dir only' '
        (
                cd nested &&
 
@@ -212,4 +212,20 @@ test_expect_success 'ls-files --o --directory to get immediate paths under one d
        )
 '
 
+test_expect_success 'ls-files -o avoids listing untracked non-matching gitdir' '
+       test_when_finished "rm -rf nested/untracked/deep/empty" &&
+       (
+               cd nested &&
+
+               git init untracked/deep/empty &&
+               git ls-files --others "untracked/*.c" >actual &&
+
+               cat <<-EOF >expect &&
+               untracked/deep/foo.c
+               EOF
+
+               test_cmp expect actual
+       )
+'
+
 test_done
index 9744e88760c9b1ba2621c82e2474e44c8f16e9a7..07a1617351dad9729b1b440422fced90a01cc25f 100755 (executable)
@@ -256,7 +256,7 @@ test_expect_success 'stop on conflicting pick' '
        D
        =======
        G
-       >>>>>>> $commit... G
+       >>>>>>> $commit (G)
        EOF
        git tag new-branch1 &&
        test_must_fail git rebase -i master &&
@@ -1791,6 +1791,12 @@ test_expect_success 'correct error message for commit --amend after empty pick'
        test_i18ngrep "middle of a rebase -- cannot amend." err
 '
 
+test_expect_success 'todo has correct onto hash' '
+       GIT_SEQUENCE_EDITOR=cat git rebase -i no-conflict-branch~4 no-conflict-branch >actual &&
+       onto=$(git rev-parse --short HEAD~4) &&
+       test_i18ngrep "^# Rebase ..* onto $onto" actual
+'
+
 # This must be the last test in this file
 test_expect_success '$EDITOR and friends are unchanged' '
        test_editor_unchanged
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 f038f34b7c03b419b9341770a6924767a0b8e8d7..2b8d9cb38ed3e3c39dd386b767f88d13e06532af 100755 (executable)
@@ -55,4 +55,27 @@ test_expect_success \
      expr "$(echo $(git cherry master my-topic-branch) )" : "+ [^ ]* - .*"
 '
 
+test_expect_success 'cherry ignores whitespace' '
+       git switch --orphan=upstream-with-space &&
+       test_commit initial file &&
+       >expect &&
+       git switch --create=feature-without-space &&
+
+       # A spaceless file on the feature branch.  Expect a match upstream.
+       printf space >file &&
+       git add file &&
+       git commit -m"file without space" &&
+       git log --format="- %H" -1 >>expect &&
+
+       # A further change.  Should not match upstream.
+       test_commit change file &&
+       git log --format="+ %H" -1 >>expect &&
+
+       git switch upstream-with-space &&
+       # Same as the spaceless file, just with spaces and on upstream.
+       test_commit "file with space" file "s p a c e" file-with-space &&
+       git cherry upstream-with-space feature-without-space >actual &&
+       test_cmp expect actual
+'
+
 test_done
index 7c1da21df1493a501dc25e34c339c1bd5aecc2cf..3669dfb1bed5bee1130f672aace510dca020ae7c 100755 (executable)
@@ -47,7 +47,7 @@ test_expect_success 'cherry-pick --nonsense' '
        git diff --exit-code HEAD &&
        test_must_fail git cherry-pick --nonsense 2>msg &&
        git diff --exit-code HEAD "$pos" &&
-       test_i18ngrep '[Uu]sage:' msg
+       test_i18ngrep "[Uu]sage:" msg
 '
 
 test_expect_success 'revert --nonsense' '
@@ -56,7 +56,7 @@ test_expect_success 'revert --nonsense' '
        git diff --exit-code HEAD &&
        test_must_fail git revert --nonsense 2>msg &&
        git diff --exit-code HEAD "$pos" &&
-       test_i18ngrep '[Uu]sage:' msg
+       test_i18ngrep "[Uu]sage:" msg
 '
 
 test_expect_success 'cherry-pick after renaming branch' '
index 752bc43487196a4be33ff7df770384f331a68315..a21adcf0e43a6d6003e60809a3dc8f20772fef2e 100755 (executable)
@@ -283,12 +283,12 @@ test_expect_success 'failed cherry-pick describes conflict in work tree' '
        a
        =======
        c
-       >>>>>>> objid picked
+       >>>>>>> objid (picked)
        EOF
 
        test_must_fail git cherry-pick picked &&
 
-       sed "s/[a-f0-9]*\.\.\./objid/" foo >actual &&
+       sed "s/[a-f0-9]* (/objid (/" foo >actual &&
        test_cmp expected actual
 '
 
@@ -298,16 +298,16 @@ test_expect_success 'diff3 -m style' '
        cat <<-EOF >expected &&
        <<<<<<< HEAD
        a
-       ||||||| parent of objid picked
+       ||||||| parent of objid (picked)
        b
        =======
        c
-       >>>>>>> objid picked
+       >>>>>>> objid (picked)
        EOF
 
        test_must_fail git cherry-pick picked &&
 
-       sed "s/[a-f0-9]*\.\.\./objid/" foo >actual &&
+       sed "s/[a-f0-9]* (/objid (/" foo >actual &&
        test_cmp expected actual
 '
 
@@ -319,7 +319,7 @@ test_expect_success 'revert also handles conflicts sanely' '
        a
        =======
        b
-       >>>>>>> parent of objid picked
+       >>>>>>> parent of objid (picked)
        EOF
        {
                git checkout picked -- foo &&
@@ -345,7 +345,7 @@ test_expect_success 'revert also handles conflicts sanely' '
        test_must_fail git update-index --refresh -q &&
        test_must_fail git diff-index --exit-code HEAD &&
        test_cmp expected-stages actual-stages &&
-       sed "s/[a-f0-9]*\.\.\./objid/" foo >actual &&
+       sed "s/[a-f0-9]* (/objid (/" foo >actual &&
        test_cmp expected actual
 '
 
@@ -429,16 +429,16 @@ test_expect_success 'revert conflict, diff3 -m style' '
        cat <<-EOF >expected &&
        <<<<<<< HEAD
        a
-       ||||||| objid picked
+       ||||||| objid (picked)
        c
        =======
        b
-       >>>>>>> parent of objid picked
+       >>>>>>> parent of objid (picked)
        EOF
 
        test_must_fail git revert picked &&
 
-       sed "s/[a-f0-9]*\.\.\./objid/" foo >actual &&
+       sed "s/[a-f0-9]* (/objid (/" foo >actual &&
        test_cmp expected actual
 '
 
@@ -512,7 +512,7 @@ test_expect_success 'commit after failed cherry-pick adds -s at the right place'
        Signed-off-by: C O Mitter <committer@example.com>
        # Conflicts:
        EOF
-       grep -e "^# Conflicts:" -e '^Signed-off-by' .git/COMMIT_EDITMSG >actual &&
+       grep -e "^# Conflicts:" -e "^Signed-off-by" .git/COMMIT_EDITMSG >actual &&
        test_cmp expect actual &&
 
        cat <<-\EOF >expected &&
@@ -541,7 +541,7 @@ test_expect_success 'commit --amend -s places the sign-off at the right place' '
        Signed-off-by: C O Mitter <committer@example.com>
        Conflicts:
        EOF
-       grep -e "^Conflicts:" -e '^Signed-off-by' .git/COMMIT_EDITMSG >actual &&
+       grep -e "^Conflicts:" -e "^Signed-off-by" .git/COMMIT_EDITMSG >actual &&
        test_cmp expect actual
 '
 
index f542d2929d2316fa8d858fc29c1bdfb5ef4c3c71..d18a80493c2274d19a6f779bd1c67c50b63a6290 100755 (executable)
@@ -14,8 +14,8 @@ test_expect_success 'setup reference tree' '
        git update-index --add COPYING rezrov &&
        tree=$(git write-tree) &&
        echo $tree &&
-       sed -e 's/HOWEVER/However/' <COPYING >COPYING.1 &&
-       sed -e 's/GPL/G.P.L/g' <COPYING >COPYING.2 &&
+       sed -e "s/HOWEVER/However/" <COPYING >COPYING.1 &&
+       sed -e "s/GPL/G.P.L/g" <COPYING >COPYING.2 &&
        origoid=$(git hash-object COPYING) &&
        oid1=$(git hash-object COPYING.1) &&
        oid2=$(git hash-object COPYING.2)
index 3f60f7d96ce1998cd977751158c09cadfd926d15..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
@@ -297,6 +318,9 @@ log --root --patch-with-stat --summary master
 log --root -c --patch-with-stat --summary master
 # improved by Timo's patch
 log --root --cc --patch-with-stat --summary master
+log --no-diff-merges -p --first-parent master
+log --diff-merges=off -p --first-parent master
+log --first-parent --diff-merges=off -p master
 log -p --first-parent master
 log -m -p --first-parent master
 log -m -p master
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
+$
diff --git a/t/t4013/diff.log_--diff-merges=off_-p_--first-parent_master b/t/t4013/diff.log_--diff-merges=off_-p_--first-parent_master
new file mode 100644 (file)
index 0000000..194e893
--- /dev/null
@@ -0,0 +1,78 @@
+$ git log --diff-merges=off -p --first-parent master
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64
+Merge: 9a6d494 c7a2ab9
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:04:00 2006 +0000
+
+    Merge branch 'side'
+
+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:02:00 2006 +0000
+
+    Third
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
+
+commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:01:00 2006 +0000
+
+    Second
+    
+    This is the second commit.
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..8422d40 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++C
++D
+diff --git a/file0 b/file0
+index 01e79c3..b414108 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++4
++5
++6
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:00:00 2006 +0000
+
+    Initial
+$
diff --git a/t/t4013/diff.log_--first-parent_--diff-merges=off_-p_master b/t/t4013/diff.log_--first-parent_--diff-merges=off_-p_master
new file mode 100644 (file)
index 0000000..5d7461a
--- /dev/null
@@ -0,0 +1,78 @@
+$ git log --first-parent --diff-merges=off -p master
+commit 80e25ffa65bcdbe82ef654b4d06dbbde7945c37f
+Merge: 9a6d494 c7a2ab9
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:04:00 2006 +0000
+
+    Merge branch 'side'
+
+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:02:00 2006 +0000
+
+    Third
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
+
+commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:01:00 2006 +0000
+
+    Second
+    
+    This is the second commit.
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..8422d40 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++C
++D
+diff --git a/file0 b/file0
+index 01e79c3..b414108 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++4
++5
++6
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:00:00 2006 +0000
+
+    Initial
+$
diff --git a/t/t4013/diff.log_--no-diff-merges_-p_--first-parent_master b/t/t4013/diff.log_--no-diff-merges_-p_--first-parent_master
new file mode 100644 (file)
index 0000000..5970022
--- /dev/null
@@ -0,0 +1,78 @@
+$ git log --no-diff-merges -p --first-parent master
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64
+Merge: 9a6d494 c7a2ab9
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:04:00 2006 +0000
+
+    Merge branch 'side'
+
+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:02:00 2006 +0000
+
+    Third
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
+
+commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:01:00 2006 +0000
+
+    Second
+    
+    This is the second commit.
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..8422d40 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++C
++D
+diff --git a/file0 b/file0
+index 01e79c3..b414108 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++4
++5
++6
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:00:00 2006 +0000
+
+    Initial
+$
index 3fc896d424f9471aa793cd6e9e0dda41264acb9b..28840ebea1e33a41402b392833093df2e92f8035 100644 (file)
@@ -6,6 +6,28 @@ Date:   Mon Jun 26 00:04:00 2006 +0000
 
     Merge branch 'side'
 
+diff --git a/dir/sub b/dir/sub
+index cead32e..992913c 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -4,3 +4,5 @@ C
+ D
+ E
+ F
++1
++2
+diff --git a/file0 b/file0
+index b414108..10a8a9f 100644
+--- a/file0
++++ b/file0
+@@ -4,3 +4,6 @@
+ 4
+ 5
+ 6
++A
++B
++C
+
 commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
 Author: A U Thor <author@example.com>
 Date:   Mon Jun 26 00:02:00 2006 +0000
diff --git a/t/t4018/fortran-block-data b/t/t4018/fortran-block-data
new file mode 100644 (file)
index 0000000..63d4e21
--- /dev/null
@@ -0,0 +1,5 @@
+       BLOCK DATA RIGHT
+       
+       COMMON /B/ C, ChangeMe
+       DATA C, ChangeMe  / 2.0, 6.0 / 
+       END 
diff --git a/t/t4018/fortran-comment b/t/t4018/fortran-comment
new file mode 100644 (file)
index 0000000..7b10d17
--- /dev/null
@@ -0,0 +1,13 @@
+      module a
+
+      contains
+
+      ! subroutine wrong
+      subroutine RIGHT
+      ! subroutine wrong
+
+      real ChangeMe
+
+      end subroutine RIGHT
+
+      end module a
diff --git a/t/t4018/fortran-comment-keyword b/t/t4018/fortran-comment-keyword
new file mode 100644 (file)
index 0000000..e9206a5
--- /dev/null
@@ -0,0 +1,14 @@
+      module a
+
+      contains
+
+      subroutine RIGHT (funcA, funcB)
+
+      real funcA  ! grid function a
+      real funcB  ! grid function b
+
+      real ChangeMe
+
+      end subroutine RIGHT
+
+      end module a
diff --git a/t/t4018/fortran-comment-legacy b/t/t4018/fortran-comment-legacy
new file mode 100644 (file)
index 0000000..53cd062
--- /dev/null
@@ -0,0 +1,13 @@
+      module a
+
+      contains
+
+C subroutine wrong
+      subroutine RIGHT
+C subroutine wrong
+
+      real ChangeMe
+
+      end subroutine RIGHT
+
+      end module a
diff --git a/t/t4018/fortran-comment-legacy-star b/t/t4018/fortran-comment-legacy-star
new file mode 100644 (file)
index 0000000..2cbcdc3
--- /dev/null
@@ -0,0 +1,13 @@
+      module a
+
+      contains
+
+* subroutine wrong
+      subroutine RIGHT
+* subroutine wrong
+
+      real ChangeMe
+
+      end subroutine RIGHT
+
+      end module a
diff --git a/t/t4018/fortran-external-function b/t/t4018/fortran-external-function
new file mode 100644 (file)
index 0000000..5a2d85d
--- /dev/null
@@ -0,0 +1,9 @@
+function RIGHT(a, b) result(c)
+
+integer, intent(in) :: ChangeMe
+integer, intent(in) :: b
+integer, intent(out) :: c
+
+c = a+b
+
+end function RIGHT
diff --git a/t/t4018/fortran-external-subroutine b/t/t4018/fortran-external-subroutine
new file mode 100644 (file)
index 0000000..4ce85fe
--- /dev/null
@@ -0,0 +1,5 @@
+subroutine RIGHT
+
+real ChangeMe
+
+end subroutine RIGHT
diff --git a/t/t4018/fortran-module b/t/t4018/fortran-module
new file mode 100644 (file)
index 0000000..c4b737d
--- /dev/null
@@ -0,0 +1,5 @@
+module RIGHT
+
+use ChangeMe
+
+end module RIGHT
diff --git a/t/t4018/fortran-module-procedure b/t/t4018/fortran-module-procedure
new file mode 100644 (file)
index 0000000..1ce6d85
--- /dev/null
@@ -0,0 +1,13 @@
+ module RIGHT
+
+   implicit none
+   private
+
+   interface letters  ! generic interface
+      module procedure aaaa, &
+                       bbbb, &
+                       ChangeMe, &
+                       dddd
+   end interface
+   
+end module RIGHT
diff --git a/t/t4018/fortran-program b/t/t4018/fortran-program
new file mode 100644 (file)
index 0000000..4616895
--- /dev/null
@@ -0,0 +1,5 @@
+program RIGHT
+
+call ChangeMe
+
+end program RIGHT
index fb145aa173ee4ea4c79bcb01336c433e16fa81e5..0c8fb39cedaa31f6f586895cd57a878158624f13 100755 (executable)
@@ -102,7 +102,7 @@ test_expect_success 'word diff with runs of whitespace' '
 '
 
 test_expect_success '--word-diff=porcelain' '
-       sed 's/#.*$//' >expect <<-EOF &&
+       sed "s/#.*$//" >expect <<-EOF &&
                diff --git a/pre b/post
                index $pre..$post 100644
                --- a/pre
index 32e3b0ee0b9d00516602934353d92da35e8b19f1..71ef4132d153b7be4b4f3d4ebfb1a85ee4bfa9ab 100755 (executable)
@@ -3,80 +3,55 @@
 # Copyright (c) 2005 Junio C Hamano
 #
 
-test_description='git apply boundary tests
+test_description='git apply boundary tests'
 
-'
 . ./test-lib.sh
 
 L="c d e f g h i j k l m n o p q r s t u v w x"
 
 test_expect_success setup '
-       for i in b '"$L"' y
-       do
-               echo $i
-       done >victim &&
+       test_write_lines b $L y >victim &&
        cat victim >original &&
        git update-index --add victim &&
 
        # add to the head
-       for i in a b '"$L"' y
-       do
-               echo $i
-       done >victim &&
+       test_write_lines a b $L y >victim &&
        cat victim >add-a-expect &&
        git diff victim >add-a-patch.with &&
        git diff --unified=0 >add-a-patch.without &&
 
        # insert at line two
-       for i in b a '"$L"' y
-       do
-               echo $i
-       done >victim &&
+       test_write_lines b a $L y >victim &&
        cat victim >insert-a-expect &&
        git diff victim >insert-a-patch.with &&
        git diff --unified=0 >insert-a-patch.without &&
 
        # modify at the head
-       for i in a '"$L"' y
-       do
-               echo $i
-       done >victim &&
+       test_write_lines a $L y >victim &&
        cat victim >mod-a-expect &&
        git diff victim >mod-a-patch.with &&
        git diff --unified=0 >mod-a-patch.without &&
 
        # remove from the head
-       for i in '"$L"' y
-       do
-               echo $i
-       done >victim &&
+       test_write_lines $L y >victim &&
        cat victim >del-a-expect &&
        git diff victim >del-a-patch.with &&
        git diff --unified=0 >del-a-patch.without &&
 
        # add to the tail
-       for i in b '"$L"' y z
-       do
-               echo $i
-       done >victim &&
+       test_write_lines b $L y z >victim &&
        cat victim >add-z-expect &&
        git diff victim >add-z-patch.with &&
        git diff --unified=0 >add-z-patch.without &&
 
        # modify at the tail
-       for i in b '"$L"' z
-       do
-               echo $i
-       done >victim &&
+       test_write_lines b $L z >victim &&
        cat victim >mod-z-expect &&
        git diff victim >mod-z-patch.with &&
        git diff --unified=0 >mod-z-patch.without &&
 
        # remove from the tail
-       for i in b '"$L"'
-       do
-               echo $i
-       done >victim &&
+       test_write_lines b $L >victim &&
        cat victim >del-z-expect &&
        git diff victim >del-z-patch.with &&
        git diff --unified=0 >del-z-patch.without
@@ -88,15 +63,15 @@ for with in with without
 do
        case "$with" in
        with) u= ;;
-       without) u='--unidiff-zero ' ;;
+       without) u=--unidiff-zero ;;
        esac
        for kind in add-a add-z insert-a mod-a mod-z del-a del-z
        do
                test_expect_success "apply $kind-patch $with context" '
                        cat original >victim &&
                        git update-index victim &&
-                       git apply --index '"$u$kind-patch.$with"' &&
-                       test_cmp '"$kind"'-expect victim
+                       git apply --index $u "$kind-patch.$with" &&
+                       test_cmp "$kind-expect" victim
                '
        done
 done
@@ -110,13 +85,12 @@ do
        test_expect_success "apply non-git $kind-patch without context" '
                cat original >victim &&
                git update-index victim &&
-               git apply --unidiff-zero --index '"$kind-ng.without"' &&
-               test_cmp '"$kind"'-expect victim
+               git apply --unidiff-zero --index "$kind-ng.without" &&
+               test_cmp "$kind-expect" victim
        '
 done
 
 test_expect_success 'two lines' '
-
        >file &&
        git add file &&
        echo aaa >file &&
@@ -125,11 +99,10 @@ test_expect_success 'two lines' '
        echo bbb >file &&
        git add file &&
        test_must_fail git apply --check patch
-
 '
 
 test_expect_success 'apply patch with 3 context lines matching at end' '
-       { echo a; echo b; echo c; echo d; } >file &&
+       test_write_lines a b c d >file &&
        git add file &&
        echo e >>file &&
        git diff >patch &&
diff --git a/t/t4140-apply-ita.sh b/t/t4140-apply-ita.sh
new file mode 100755 (executable)
index 0000000..c614eaf
--- /dev/null
@@ -0,0 +1,56 @@
+#!/bin/sh
+
+test_description='git apply of i-t-a file'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+       test_write_lines 1 2 3 4 5 >blueprint &&
+
+       cat blueprint >test-file &&
+       git add -N test-file &&
+       git diff >creation-patch &&
+       grep "new file mode 100644" creation-patch &&
+
+       rm -f test-file &&
+       git diff >deletion-patch &&
+       grep "deleted file mode 100644" deletion-patch
+'
+
+test_expect_success 'apply creation patch to ita path (--cached)' '
+       git rm -f test-file &&
+       cat blueprint >test-file &&
+       git add -N test-file &&
+
+       git apply --cached creation-patch &&
+       git cat-file blob :test-file >actual &&
+       test_cmp blueprint actual
+'
+
+test_expect_success 'apply creation patch to ita path (--index)' '
+       git rm -f test-file &&
+       cat blueprint >test-file &&
+       git add -N test-file &&
+       rm -f test-file &&
+
+       test_must_fail git apply --index creation-patch
+'
+
+test_expect_success 'apply deletion patch to ita path (--cached)' '
+       git rm -f test-file &&
+       cat blueprint >test-file &&
+       git add -N test-file &&
+
+       git apply --cached deletion-patch &&
+       test_must_fail git ls-files --stage --error-unmatch test-file
+'
+
+test_expect_success 'apply deletion patch to ita path (--index)' '
+       cat blueprint >test-file &&
+       git add -N test-file &&
+
+       test_must_fail git apply --index deletion-patch &&
+       git ls-files --stage --error-unmatch test-file
+'
+
+test_done
index bda4586a7951a234b50ffbb28cdd4d7df05e4c56..1da8ab120b37a01fa02fdf12c55c11e38ce4fd31 100755 (executable)
@@ -989,7 +989,7 @@ test_expect_success 'am -s unexpected trailer block' '
        Signed-off-by: J C H <j@c.h>
        EOF
        git commit -F msg &&
-       git cat-file commit HEAD | sed -e '1,/^$/d' >original &&
+       git cat-file commit HEAD | sed -e "1,/^$/d" >original &&
        git format-patch --stdout -1 >patch &&
 
        git reset --hard HEAD^ &&
@@ -998,7 +998,7 @@ test_expect_success 'am -s unexpected trailer block' '
                cat original &&
                echo "Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>"
        ) >expect &&
-       git cat-file commit HEAD | sed -e '1,/^$/d' >actual &&
+       git cat-file commit HEAD | sed -e "1,/^$/d" >actual &&
        test_cmp expect actual &&
 
        cat >msg <<-\EOF &&
@@ -1009,7 +1009,7 @@ test_expect_success 'am -s unexpected trailer block' '
        EOF
        git reset HEAD^ &&
        git commit -F msg file &&
-       git cat-file commit HEAD | sed -e '1,/^$/d' >original &&
+       git cat-file commit HEAD | sed -e "1,/^$/d" >original &&
        git format-patch --stdout -1 >patch &&
 
        git reset --hard HEAD^ &&
@@ -1020,7 +1020,7 @@ test_expect_success 'am -s unexpected trailer block' '
                echo &&
                echo "Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>"
        ) >expect &&
-       git cat-file commit HEAD | sed -e '1,/^$/d' >actual &&
+       git cat-file commit HEAD | sed -e "1,/^$/d" >actual &&
        test_cmp expect actual
 '
 
@@ -1133,4 +1133,20 @@ test_expect_success 'am and .gitattibutes' '
        )
 '
 
+test_expect_success 'apply binary blob in partial clone' '
+       printf "\\000" >binary &&
+       git add binary &&
+       git commit -m "binary blob" &&
+       git format-patch --stdout -m HEAD^ >patch &&
+
+       test_create_repo server &&
+       test_config -C server uploadpack.allowfilter 1 &&
+       test_config -C server uploadpack.allowanysha1inwant 1 &&
+       git clone --filter=blob:none "file://$(pwd)/server" client &&
+       test_when_finished "rm -rf client" &&
+
+       # Exercise to make sure that it works
+       git -C client am ../patch
+'
+
 test_done
index d94d25e4f002f7926d0e7a661bb4aa81a3b35028..b12b43e9e980f3c1fcdd032685a25f600bde169b 100755 (executable)
@@ -363,7 +363,7 @@ test_expect_success 'set up an unresolved merge' '
        git reset --hard &&
        git checkout version2 &&
        fifth=$(git rev-parse fifth) &&
-       echo "$fifth            branch 'fifth' of ." |
+       echo "$fifth            branch fifth of ." |
        git fmt-merge-msg >msg &&
        ancestor=$(git merge-base version2 fifth) &&
        test_must_fail git merge-recursive "$ancestor" -- HEAD fifth &&
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 c21cc160f3bb9dac91ce222e4fda5216927c1859..4bb9e9dbe28bf22d86d7e4ef8629d4f73328d815 100755 (executable)
@@ -30,12 +30,17 @@ test_expect_success 'setup test - repo, commits, commit graph, log outputs' '
        rm file_to_be_deleted &&
        git add . &&
        git commit -m "file removed" &&
-       git commit-graph write --reachable --changed-paths
+       git commit-graph write --reachable --changed-paths &&
+
+       test_oid_cache <<-EOF
+       oid_version sha1:1
+       oid_version sha256:2
+       EOF
 '
 graph_read_expect () {
        NUM_CHUNKS=5
        cat >expect <<- EOF
-       header: 43475048 1 1 $NUM_CHUNKS 0
+       header: 43475048 1 $(test_oid oid_version) $NUM_CHUNKS 0
        num_commits: $1
        chunks: oid_fanout oid_lookup commit_metadata bloom_indexes bloom_data
        EOF
index 119494bd6414fca0241ee3c7a97b1cf492e6d35f..c92e553a2f87d59f73f2dc8bf52bd256713241db 100755 (executable)
@@ -14,7 +14,7 @@ test_expect_success 'setup' '
        i=1 &&
        while test $i -le 100
        do
-               iii=$(printf '%03i' $i)
+               iii=$(printf "%03i" $i)
                test-tool genrandom "bar" 200 > wide_delta_$iii &&
                test-tool genrandom "baz $iii" 50 >> wide_delta_$iii &&
                test-tool genrandom "foo"$i 100 > deep_delta_$iii &&
index 044cf8a3def493e4a0e7395613eaadda1c236f02..2ed0c1544da120c10db3afedb656429f12a45613 100755 (executable)
@@ -10,7 +10,12 @@ test_expect_success 'setup full repo' '
        cd "$TRASH_DIRECTORY/full" &&
        git init &&
        git config core.commitGraph true &&
-       objdir=".git/objects"
+       objdir=".git/objects" &&
+
+       test_oid_cache <<-EOF
+       oid_version sha1:1
+       oid_version sha256:2
+       EOF
 '
 
 test_expect_success POSIXPERM 'tweak umask for modebit tests' '
@@ -77,7 +82,7 @@ graph_read_expect() {
                NUM_CHUNKS=$((3 + $(echo "$2" | wc -w)))
        fi
        cat >expect <<- EOF
-       header: 43475048 1 1 $NUM_CHUNKS 0
+       header: 43475048 1 $(test_oid oid_version) $NUM_CHUNKS 0
        num_commits: $1
        chunks: oid_fanout oid_lookup commit_metadata$OPTIONAL
        EOF
@@ -412,6 +417,35 @@ test_expect_success 'replace-objects invalidates commit-graph' '
        )
 '
 
+test_expect_success 'warn on improper hash version' '
+       git init --object-format=sha1 sha1 &&
+       (
+               cd sha1 &&
+               test_commit 1 &&
+               git commit-graph write --reachable &&
+               mv .git/objects/info/commit-graph ../cg-sha1
+       ) &&
+       git init --object-format=sha256 sha256 &&
+       (
+               cd sha256 &&
+               test_commit 1 &&
+               git commit-graph write --reachable &&
+               mv .git/objects/info/commit-graph ../cg-sha256
+       ) &&
+       (
+               cd sha1 &&
+               mv ../cg-sha256 .git/objects/info/commit-graph &&
+               git log -1 2>err &&
+               test_i18ngrep "commit-graph hash version 2 does not match version 1" err
+       ) &&
+       (
+               cd sha256 &&
+               mv ../cg-sha1 .git/objects/info/commit-graph &&
+               git log -1 2>err &&
+               test_i18ngrep "commit-graph hash version 1 does not match version 2" err
+       )
+'
+
 # the verify tests below expect the commit-graph to contain
 # exactly the commits reachable from the commits/8 branch.
 # If the file changes the set of commits in the list, then the
index 7dfff0f8f43e9a488c84a3efc63e3d00489c8919..43b1b5b2af6e978f5dc84543f5be1707941a2d38 100755 (executable)
@@ -5,6 +5,8 @@ test_description='multi-pack-indexes'
 
 objdir=.git/objects
 
+HASH_LEN=$(test_oid rawsz)
+
 midx_read_expect () {
        NUM_PACKS=$1
        NUM_OBJECTS=$2
@@ -13,7 +15,7 @@ midx_read_expect () {
        EXTRA_CHUNKS="$5"
        {
                cat <<-EOF &&
-               header: 4d494458 1 $NUM_CHUNKS $NUM_PACKS
+               header: 4d494458 1 $HASH_LEN $NUM_CHUNKS $NUM_PACKS
                chunks: pack-names oid-fanout oid-lookup object-offsets$EXTRA_CHUNKS
                num_objects: $NUM_OBJECTS
                packs:
@@ -46,7 +48,7 @@ test_expect_success "don't write midx with no packs" '
        test_path_is_missing pack/multi-pack-index
 '
 
-test_expect_success "Warn if a midx contains no oid" '
+test_expect_success SHA1 'warn if a midx contains no oid' '
        cp "$TEST_DIRECTORY"/t5319/no-objects.midx $objdir/pack/multi-pack-index &&
        test_must_fail git multi-pack-index verify &&
        rm $objdir/pack/multi-pack-index
@@ -198,6 +200,40 @@ test_expect_success 'write midx with twelve packs' '
 
 compare_results_with_midx "twelve packs"
 
+test_expect_success 'warn on improper hash version' '
+       git init --object-format=sha1 sha1 &&
+       (
+               cd sha1 &&
+               git config core.multiPackIndex true &&
+               test_commit 1 &&
+               git repack -a &&
+               git multi-pack-index write &&
+               mv .git/objects/pack/multi-pack-index ../mpi-sha1
+       ) &&
+       git init --object-format=sha256 sha256 &&
+       (
+               cd sha256 &&
+               git config core.multiPackIndex true &&
+               test_commit 1 &&
+               git repack -a &&
+               git multi-pack-index write &&
+               mv .git/objects/pack/multi-pack-index ../mpi-sha256
+       ) &&
+       (
+               cd sha1 &&
+               mv ../mpi-sha256 .git/objects/pack/multi-pack-index &&
+               git log -1 2>err &&
+               test_i18ngrep "multi-pack-index hash version 2 does not match version 1" err
+       ) &&
+       (
+               cd sha256 &&
+               mv ../mpi-sha1 .git/objects/pack/multi-pack-index &&
+               git log -1 2>err &&
+               test_i18ngrep "multi-pack-index hash version 1 does not match version 2" err
+       )
+'
+
+
 test_expect_success 'verify multi-pack-index success' '
        git multi-pack-index verify --object-dir=$objdir
 '
@@ -243,7 +279,6 @@ test_expect_success 'verify bad signature' '
                "multi-pack-index signature"
 '
 
-HASH_LEN=$(test_oid rawsz)
 NUM_OBJECTS=74
 MIDX_BYTE_VERSION=4
 MIDX_BYTE_OID_VERSION=5
@@ -272,7 +307,7 @@ test_expect_success 'verify bad version' '
 '
 
 test_expect_success 'verify bad OID version' '
-       corrupt_midx_and_verify $MIDX_BYTE_OID_VERSION "\02" $objdir \
+       corrupt_midx_and_verify $MIDX_BYTE_OID_VERSION "\03" $objdir \
                "hash version"
 '
 
@@ -642,6 +677,7 @@ test_expect_success 'expire respects .keep files' '
 '
 
 test_expect_success 'repack --batch-size=0 repacks everything' '
+       cp -r dup dup2 &&
        (
                cd dup &&
                rm .git/objects/pack/*.keep &&
@@ -661,4 +697,21 @@ test_expect_success 'repack --batch-size=0 repacks everything' '
        )
 '
 
+test_expect_success 'repack --batch-size=<large> repacks everything' '
+       (
+               cd dup2 &&
+               rm .git/objects/pack/*.keep &&
+               ls .git/objects/pack/*idx >idx-list &&
+               test_line_count = 2 idx-list &&
+               git multi-pack-index repack --batch-size=2000000 &&
+               ls .git/objects/pack/*idx >idx-list &&
+               test_line_count = 3 idx-list &&
+               test-tool read-midx .git/objects | grep idx >midx-list &&
+               test_line_count = 3 midx-list &&
+               git multi-pack-index expire &&
+               ls -al .git/objects/pack/*idx >idx-list &&
+               test_line_count = 1 idx-list
+       )
+'
+
 test_done
index ea28d522b8375678c9a54d6c4b6717ef8f11ab6f..18216463c7db99e965833788ccd990f1e8515397 100755 (executable)
@@ -18,6 +18,9 @@ test_expect_success 'setup repo' '
 
        base sha1:1376
        base sha256:1496
+
+       oid_version sha1:1
+       oid_version sha256:2
        EOM
 '
 
@@ -28,7 +31,7 @@ graph_read_expect() {
                NUM_BASE=$2
        fi
        cat >expect <<- EOF
-       header: 43475048 1 1 3 $NUM_BASE
+       header: 43475048 1 $(test_oid oid_version) 3 $NUM_BASE
        num_commits: $1
        chunks: oid_fanout oid_lookup commit_metadata
        EOF
index e567cba38d07b6cae4473d36a74faa065ca5aa81..2a1abe91f0fd34b7929aa636ab43542c6e45ea54 100755 (executable)
@@ -213,7 +213,7 @@ test_expect_success 'fetch tags when there is no tags' '
 test_expect_success 'fetch following tags' '
 
        cd "$D" &&
-       git tag -a -m 'annotated' anno HEAD &&
+       git tag -a -m "annotated" anno HEAD &&
        git tag light HEAD &&
 
        mkdir four &&
@@ -335,7 +335,7 @@ test_expect_success 'bundle does not prerequisite objects' '
 test_expect_success 'bundle should be able to create a full history' '
 
        cd "$D" &&
-       git tag -a -m '1.0' v1.0 master &&
+       git tag -a -m "1.0" v1.0 master &&
        git bundle create bundle4 v1.0
 
 '
@@ -543,13 +543,24 @@ test_expect_success 'fetch into the current branch with --update-head-ok' '
 
 '
 
-test_expect_success 'fetch --dry-run' '
-
+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 '--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 '--write-fetch-head gets defeated by --dry-run' '
+       rm -f .git/FETCH_HEAD &&
+       git fetch --dry-run --write-fetch-head . &&
+       ! test -f .git/FETCH_HEAD
+'
+
 test_expect_success "should be able to fetch with duplicate refspecs" '
        mkdir dups &&
        (
index 159afa7ac81396e1d9915335f030cd0fcc8b7b3f..db1a381cd91c3470b7007b747e3b3a82f4da162f 100755 (executable)
@@ -85,6 +85,13 @@ test_expect_success 'git pull --cleanup errors early on invalid argument' '
        test -s err)
 '
 
+test_expect_success 'git pull --no-write-fetch-head fails' '
+       mkdir clonedwfh &&
+       (cd clonedwfh && git init &&
+       test_expect_code 129 git pull --no-write-fetch-head "../parent" >out 2>err &&
+       test_must_be_empty out &&
+       test_i18ngrep "no-write-fetch-head" err)
+'
 
 test_expect_success 'git pull --force' '
        mkdir clonedoldstyle &&
index 81975ad8f9ebcbe22d5066da228e333e2cd613df..7622981cbf25941260f5a7f21bd60f84cf8797f8 100755 (executable)
@@ -81,7 +81,7 @@ test_expect_success 'fetch --set-upstream http://nosuchdomain.example.com fails
 
 test_expect_success 'fetch --set-upstream with valid URL sets upstream to URL' '
        clear_config other other2 &&
-       url="file://'"$PWD"'" &&
+       url="file://$PWD" &&
        git fetch --set-upstream "$url" &&
        check_config master "$url" HEAD &&
        check_config_missing other &&
@@ -158,7 +158,7 @@ test_expect_success 'pull --set-upstream upstream with more than one branch does
 test_expect_success 'pull --set-upstream with valid URL sets upstream to URL' '
        clear_config master other other2 &&
        git checkout master &&
-       url="file://'"$PWD"'" &&
+       url="file://$PWD" &&
        git pull --set-upstream "$url" &&
        check_config master "$url" HEAD &&
        check_config_missing other &&
@@ -168,7 +168,7 @@ test_expect_success 'pull --set-upstream with valid URL sets upstream to URL' '
 test_expect_success 'pull --set-upstream with valid URL and branch sets branch' '
        clear_config master other other2 &&
        git checkout master &&
-       url="file://'"$PWD"'" &&
+       url="file://$PWD" &&
        git pull --set-upstream "$url" master &&
        check_config master "$url" refs/heads/master &&
        check_config_missing other &&
index 8827c2ed18394f3f7f5ae4bd35c3514a36eacc9d..5a01466db4837e1f80aac7236cd3a71e5aaee03d 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 &&
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 3bb0e4ff8f812627bea07fe82b3be97e562d3ccc..fc4d55dcb2e28d34b9a971f59872d30dfc87afcd 100755 (executable)
@@ -128,8 +128,8 @@ test_expect_success 'rev-list can negate index objects' '
        test_cmp expect actual
 '
 
-test_expect_success '--bisect and --first-parent can not be combined' '
-       test_must_fail git rev-list --bisect --first-parent HEAD
+test_expect_success '--bisect and --first-parent can be combined' '
+       git rev-list --bisect --first-parent HEAD
 '
 
 test_expect_success '--header shows a NUL after each commit' '
index a6614080388353c828fdd3894c093ef03f71511d..b95a0212adff71632d0b91cf96432b276c86a44c 100755 (executable)
@@ -263,4 +263,49 @@ test_expect_success 'rev-parse --bisect can default to good/bad refs' '
        test_cmp expect.sorted actual.sorted
 '
 
+test_output_expect_success '--bisect --first-parent' 'git rev-list --bisect --first-parent E ^F' <<EOF
+e4
+EOF
+
+test_output_expect_success '--first-parent' 'git rev-list --first-parent E ^F' <<EOF
+E
+e1
+e2
+e3
+e4
+e5
+e6
+e7
+e8
+EOF
+
+test_output_expect_success '--bisect-vars --first-parent' 'git rev-list --bisect-vars --first-parent E ^F' <<EOF
+bisect_rev='e5'
+bisect_nr=4
+bisect_good=4
+bisect_bad=3
+bisect_all=9
+bisect_steps=2
+EOF
+
+test_expect_success '--bisect-all --first-parent' '
+       cat >expect.unsorted <<-EOF &&
+       $(git rev-parse E) (tag: E, dist=0)
+       $(git rev-parse e1) (tag: e1, dist=1)
+       $(git rev-parse e2) (tag: e2, dist=2)
+       $(git rev-parse e3) (tag: e3, dist=3)
+       $(git rev-parse e4) (tag: e4, dist=4)
+       $(git rev-parse e5) (tag: e5, dist=4)
+       $(git rev-parse e6) (tag: e6, dist=3)
+       $(git rev-parse e7) (tag: e7, dist=2)
+       $(git rev-parse e8) (tag: e8, dist=1)
+       EOF
+
+       # expect results to be ordered by distance (descending),
+       # commit hash (ascending)
+       sort -k4,4r -k1,1 expect.unsorted >expect &&
+       git rev-list --bisect-all --first-parent E ^F >actual &&
+       test_cmp expect actual
+'
+
 test_done
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 36d9b2b2e485ffa8a794e61229dedc8c7d47ea46..b886529e5963ff9855e070747e8d010151c55c67 100755 (executable)
@@ -243,32 +243,30 @@ test_expect_success 'bisect skip: with commit both bad and skipped' '
 '
 
 # We want to automatically find the commit that
-# introduced "Another" into hello.
-test_expect_success \
-    '"git bisect run" simple case' \
-    'echo "#"\!"/bin/sh" > test_script.sh &&
-     echo "grep Another hello > /dev/null" >> test_script.sh &&
-     echo "test \$? -ne 0" >> test_script.sh &&
-     chmod +x test_script.sh &&
-     git bisect start &&
-     git bisect good $HASH1 &&
-     git bisect bad $HASH4 &&
-     git bisect run ./test_script.sh > my_bisect_log.txt &&
-     grep "$HASH3 is the first bad commit" my_bisect_log.txt &&
-     git bisect reset'
+# added "Another" into hello.
+test_expect_success '"git bisect run" simple case' '
+       write_script test_script.sh <<-\EOF &&
+       ! grep Another hello >/dev/null
+       EOF
+       git bisect start &&
+       git bisect good $HASH1 &&
+       git bisect bad $HASH4 &&
+       git bisect run ./test_script.sh >my_bisect_log.txt &&
+       grep "$HASH3 is the first bad commit" my_bisect_log.txt &&
+       git bisect reset
+'
 
 # We want to automatically find the commit that
-# introduced "Ciao" into hello.
-test_expect_success \
-    '"git bisect run" with more complex "git bisect start"' \
-    'echo "#"\!"/bin/sh" > test_script.sh &&
-     echo "grep Ciao hello > /dev/null" >> test_script.sh &&
-     echo "test \$? -ne 0" >> test_script.sh &&
-     chmod +x test_script.sh &&
-     git bisect start $HASH4 $HASH1 &&
-     git bisect run ./test_script.sh > my_bisect_log.txt &&
-     grep "$HASH4 is the first bad commit" my_bisect_log.txt &&
-     git bisect reset'
+# added "Ciao" into hello.
+test_expect_success '"git bisect run" with more complex "git bisect start"' '
+       write_script test_script.sh <<-\EOF &&
+       ! grep Ciao hello >/dev/null
+       EOF
+       git bisect start $HASH4 $HASH1 &&
+       git bisect run ./test_script.sh >my_bisect_log.txt &&
+       grep "$HASH4 is the first bad commit" my_bisect_log.txt &&
+       git bisect reset
+'
 
 # $HASH1 is good, $HASH5 is bad, we skip $HASH3
 # but $HASH4 is good,
@@ -295,24 +293,17 @@ HASH6=
 test_expect_success 'bisect run & skip: cannot tell between 2' '
        add_line_into_file "6: Yet a line." hello &&
        HASH6=$(git rev-parse --verify HEAD) &&
-       echo "#"\!"/bin/sh" > test_script.sh &&
-       echo "sed -ne \\\$p hello | grep Ciao > /dev/null && exit 125" >> test_script.sh &&
-       echo "grep line hello > /dev/null" >> test_script.sh &&
-       echo "test \$? -ne 0" >> test_script.sh &&
-       chmod +x test_script.sh &&
+       write_script test_script.sh <<-\EOF &&
+       sed -ne \$p hello | grep Ciao >/dev/null && exit 125
+       ! grep line hello >/dev/null
+       EOF
        git bisect start $HASH6 $HASH1 &&
-       if git bisect run ./test_script.sh > my_bisect_log.txt
-       then
-               echo Oops, should have failed.
-               false
-       else
-               test $? -eq 2 &&
-               grep "first bad commit could be any of" my_bisect_log.txt &&
-               ! grep $HASH3 my_bisect_log.txt &&
-               ! grep $HASH6 my_bisect_log.txt &&
-               grep $HASH4 my_bisect_log.txt &&
-               grep $HASH5 my_bisect_log.txt
-       fi
+       test_expect_code 2 git bisect run ./test_script.sh >my_bisect_log.txt &&
+       grep "first bad commit could be any of" my_bisect_log.txt &&
+       ! grep $HASH3 my_bisect_log.txt &&
+       ! grep $HASH6 my_bisect_log.txt &&
+       grep $HASH4 my_bisect_log.txt &&
+       grep $HASH5 my_bisect_log.txt
 '
 
 HASH7=
@@ -320,14 +311,13 @@ test_expect_success 'bisect run & skip: find first bad' '
        git bisect reset &&
        add_line_into_file "7: Should be the last line." hello &&
        HASH7=$(git rev-parse --verify HEAD) &&
-       echo "#"\!"/bin/sh" > test_script.sh &&
-       echo "sed -ne \\\$p hello | grep Ciao > /dev/null && exit 125" >> test_script.sh &&
-       echo "sed -ne \\\$p hello | grep day > /dev/null && exit 125" >> test_script.sh &&
-       echo "grep Yet hello > /dev/null" >> test_script.sh &&
-       echo "test \$? -ne 0" >> test_script.sh &&
-       chmod +x test_script.sh &&
+       write_script test_script.sh <<-\EOF &&
+       sed -ne \$p hello | grep Ciao >/dev/null && exit 125
+       sed -ne \$p hello | grep day >/dev/null && exit 125
+       ! grep Yet hello >/dev/null
+       EOF
        git bisect start $HASH7 $HASH1 &&
-       git bisect run ./test_script.sh > my_bisect_log.txt &&
+       git bisect run ./test_script.sh >my_bisect_log.txt &&
        grep "$HASH6 is the first bad commit" my_bisect_log.txt
 '
 
@@ -458,6 +448,24 @@ test_expect_success 'many merge bases creation' '
        grep "$SIDE_HASH5" merge_bases.txt
 '
 
+# We want to automatically find the merge that
+# added "line" into hello.
+test_expect_success '"git bisect run --first-parent" simple case' '
+       git rev-list --first-parent $B_HASH ^$HASH4 >first_parent_chain.txt &&
+       write_script test_script.sh <<-\EOF &&
+       grep $(git rev-parse HEAD) first_parent_chain.txt || exit -1
+       ! grep line hello >/dev/null
+       EOF
+       git bisect start --first-parent &&
+       test_path_is_file ".git/BISECT_FIRST_PARENT" &&
+       git bisect good $HASH4 &&
+       git bisect bad $B_HASH &&
+       git bisect run ./test_script.sh >my_bisect_log.txt &&
+       grep "$B_HASH is the first bad commit" my_bisect_log.txt &&
+       git bisect reset &&
+       test_path_is_missing .git/BISECT_FIRST_PARENT
+'
+
 test_expect_success 'good merge bases when good and bad are siblings' '
        git bisect start "$B_HASH" "$A_HASH" > my_bisect_log.txt &&
        test_i18ngrep "merge base must be tested" my_bisect_log.txt &&
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
 '
 
similarity index 100%
rename from t/t6020-merge-df.sh
rename to t/t6400-merge-df.sh
similarity index 100%
rename from t/t6023-merge-file.sh
rename to t/t6403-merge-file.sh
similarity index 98%
rename from t/t6026-merge-attr.sh
rename to t/t6406-merge-attr.sh
index 5900358ce9c0b7605a23266d9179bedba5ad32e6..76a55f838c4ac03cfba678c0f188f67d4f724e6a 100755 (executable)
@@ -122,7 +122,7 @@ test_expect_success 'custom merge backend' '
        o=$(git unpack-file master^:text) &&
        a=$(git unpack-file side^:text) &&
        b=$(git unpack-file master:text) &&
-       sh -c "./custom-merge $o $a $b 0 'text'" &&
+       sh -c "./custom-merge $o $a $b 0 text" &&
        sed -e 1,3d $a >check-2 &&
        cmp check-1 check-2 &&
        rm -f $o $a $b
@@ -149,7 +149,7 @@ test_expect_success 'custom merge backend' '
        o=$(git unpack-file master^:text) &&
        a=$(git unpack-file anchor:text) &&
        b=$(git unpack-file master:text) &&
-       sh -c "./custom-merge $o $a $b 0 'text'" &&
+       sh -c "./custom-merge $o $a $b 0 text" &&
        sed -e 1,3d $a >check-2 &&
        cmp check-1 check-2 &&
        sed -e 1,3d -e 4q $a >check-3 &&
similarity index 100%
rename from t/t6033-merge-crlf.sh
rename to t/t6413-merge-crlf.sh
similarity index 99%
rename from t/t6036-recursive-corner-cases.sh
rename to t/t6416-recursive-corner-cases.sh
index b3bf4626178681cd1acb8dc0e7a70d20dcd95cfb..fd98989b1476e4e1e35893350981d3a1f25a37fa 100755 (executable)
@@ -452,7 +452,7 @@ test_expect_success 'git detects conflict merging criss-cross+modify/delete, rev
 #
 # So choice 5 at least provides some kind of conflict for the original case,
 # and can merge cleanly as expected with D1 and E3.  It also made things just
-# slightly funny for merging D1 and e$, where E4 is defined as:
+# slightly funny for merging D1 and E4, where E4 is defined as:
 #   Commit E4: Merge B & C, modifying 'a' and renaming to 'a2', and deleting 'a/'
 # in this case, we'll get a rename/rename(1to2) conflict because a~$UNIQUE
 # gets renamed to 'a' in D1 and to 'a2' in E4.  But that's better than having
@@ -1144,7 +1144,7 @@ test_expect_failure 'check symlink add/add' '
                test_must_fail git merge -s recursive E^0 &&
 
                git ls-files -s >out &&
-               test_line_count = 2 out &&
+               test_line_count = 3 out &&
                git ls-files -u >out &&
                test_line_count = 2 out &&
                git ls-files -o >out &&
similarity index 99%
rename from t/t6038-merge-text-auto.sh
rename to t/t6418-merge-text-auto.sh
index 89c86d4e56ca6e5133e50dfbc92f069c55b2fb0e..30983d18b1bad5ff25f38317839493ac65bf71f5 100755 (executable)
@@ -197,7 +197,8 @@ test_expect_success 'Test delete/normalize conflict' '
        git commit -m "remove file" &&
        git checkout master &&
        git reset --hard a^ &&
-       git merge side
+       git merge side &&
+       test_path_is_missing file
 '
 
 test_done
similarity index 94%
rename from t/t6042-merge-rename-corner-cases.sh
rename to t/t6422-merge-rename-corner-cases.sh
index f163893ff97125c7750b9bd11c273ae8b738436c..3375eaf4e76daa23c0a9e65fd6b7e060cc04f601 100755 (executable)
@@ -457,7 +457,7 @@ test_expect_success 'handle rename-with-content-merge vs. add' '
                git checkout A^0 &&
 
                test_must_fail git merge -s recursive B^0 >out &&
-               test_i18ngrep "CONFLICT (rename/add)" out &&
+               test_i18ngrep "CONFLICT (.*/add)" out &&
 
                git ls-files -s >out &&
                test_line_count = 2 out &&
@@ -503,7 +503,7 @@ test_expect_success 'handle rename-with-content-merge vs. add, merge other way'
                git checkout B^0 &&
 
                test_must_fail git merge -s recursive A^0 >out &&
-               test_i18ngrep "CONFLICT (rename/add)" out &&
+               test_i18ngrep "CONFLICT (.*/add)" out &&
 
                git ls-files -s >out &&
                test_line_count = 2 out &&
@@ -583,7 +583,7 @@ test_expect_success 'handle rename/rename (2to1) conflict correctly' '
                git checkout B^0 &&
 
                test_must_fail git merge -s recursive C^0 >out &&
-               test_i18ngrep "CONFLICT (rename/rename)" out &&
+               test_i18ngrep "CONFLICT (\(.*\)/\1)" out &&
 
                git ls-files -s >out &&
                test_line_count = 2 out &&
@@ -886,12 +886,17 @@ test_expect_failure 'rad-check: rename/add/delete conflict' '
                git checkout B^0 &&
                test_must_fail git merge -s recursive A^0 >out 2>err &&
 
-               # Not sure whether the output should contain just one
-               # "CONFLICT (rename/add/delete)" line, or if it should break
-               # it into a pair of "CONFLICT (rename/delete)" and
-               # "CONFLICT (rename/add)"; allow for either.
-               test_i18ngrep "CONFLICT (rename.*add)" out &&
-               test_i18ngrep "CONFLICT (rename.*delete)" out &&
+               # Instead of requiring the output to contain one combined line
+               #   CONFLICT (rename/add/delete)
+               # or perhaps two lines:
+               #   CONFLICT (rename/add): new file collides with rename target
+               #   CONFLICT (rename/delete): rename source removed on other side
+               # and instead of requiring "rename/add" instead of "add/add",
+               # be flexible in the type of console output message(s) reported
+               # for this particular case; we will be more stringent about the
+               # contents of the index and working directory.
+               test_i18ngrep "CONFLICT (.*/add)" out &&
+               test_i18ngrep "CONFLICT (rename.*/delete)" out &&
                test_must_be_empty err &&
 
                git ls-files -s >file_count &&
@@ -899,14 +904,14 @@ test_expect_failure 'rad-check: rename/add/delete conflict' '
                git ls-files -u >file_count &&
                test_line_count = 2 file_count &&
                git ls-files -o >file_count &&
-               test_line_count = 2 file_count &&
+               test_line_count = 3 file_count &&
 
                git rev-parse >actual \
                        :2:bar :3:bar &&
                git rev-parse >expect \
                        B:bar  A:bar  &&
 
-               test_cmp file_is_missing foo &&
+               test_path_is_missing foo &&
                # bar should have two-way merged contents of the different
                # versions of bar; check that content from both sides is
                # present.
@@ -954,11 +959,17 @@ test_expect_failure 'rrdd-check: rename/rename(2to1)/delete/delete conflict' '
                git checkout A^0 &&
                test_must_fail git merge -s recursive B^0 >out 2>err &&
 
-               # Not sure whether the output should contain just one
-               # "CONFLICT (rename/rename/delete/delete)" line, or if it
-               # should break it into three: "CONFLICT (rename/rename)" and
-               # two "CONFLICT (rename/delete)" lines; allow for either.
-               test_i18ngrep "CONFLICT (rename/rename)" out &&
+               # Instead of requiring the output to contain one combined line
+               #   CONFLICT (rename/rename/delete/delete)
+               # or perhaps two lines:
+               #   CONFLICT (rename/rename): ...
+               #   CONFLICT (rename/delete): info about pair 1
+               #   CONFLICT (rename/delete): info about pair 2
+               # and instead of requiring "rename/rename" instead of "add/add",
+               # be flexible in the type of console output message(s) reported
+               # for this particular case; we will be more stringent about the
+               # contents of the index and working directory.
+               test_i18ngrep "CONFLICT (\(.*\)/\1)" out &&
                test_i18ngrep "CONFLICT (rename.*delete)" out &&
                test_must_be_empty err &&
 
@@ -967,15 +978,15 @@ test_expect_failure 'rrdd-check: rename/rename(2to1)/delete/delete conflict' '
                git ls-files -u >file_count &&
                test_line_count = 2 file_count &&
                git ls-files -o >file_count &&
-               test_line_count = 2 file_count &&
+               test_line_count = 3 file_count &&
 
                git rev-parse >actual \
                        :2:baz :3:baz &&
                git rev-parse >expect \
                        O:foo  O:bar  &&
 
-               test_cmp file_is_missing foo &&
-               test_cmp file_is_missing bar &&
+               test_path_is_missing foo &&
+               test_path_is_missing bar &&
                # baz should have two-way merged contents of the original
                # contents of foo and bar; check that content from both sides
                # is present.
@@ -1042,25 +1053,25 @@ test_expect_failure 'mod6-check: chains of rename/rename(1to2) and rename/rename
                test_must_be_empty err &&
 
                git ls-files -s >file_count &&
-               test_line_count = 6 file_count &&
+               test_line_count = 9 file_count &&
                git ls-files -u >file_count &&
-               test_line_count = 6 file_count &&
+               test_line_count = 9 file_count &&
                git ls-files -o >file_count &&
                test_line_count = 3 file_count &&
 
                test_seq 10 20 >merged-one &&
                test_seq 51 60 >merged-five &&
                # Determine what the merge of three would give us.
-               test_seq 30 40 >three-side-A &&
+               test_seq 31 39 >three-base &&
+               test_seq 31 40 >three-side-A &&
                test_seq 31 39 >three-side-B &&
-               echo forty >three-side-B &&
-               >empty &&
+               echo forty >>three-side-B &&
                test_must_fail git merge-file \
-                       -L "HEAD" \
+                       -L "HEAD:four" \
                        -L "" \
-                       -L "B^0" \
-                       three-side-A empty three-side-B &&
-               sed -e "s/^\([<=>]\)/\1\1\1/" three-side-A >merged-three &&
+                       -L "B^0:two" \
+                       three-side-A three-base three-side-B &&
+               sed -e "s/^\([<=>]\)/\1\1/" three-side-A >merged-three &&
 
                # Verify the index is as expected
                git rev-parse >actual         \
@@ -1075,6 +1086,7 @@ test_expect_failure 'mod6-check: chains of rename/rename(1to2) and rename/rename
 
                git cat-file -p :2:two >expect &&
                git cat-file -p :3:two >other &&
+               >empty &&
                test_must_fail git merge-file    \
                        -L "HEAD"  -L ""  -L "B^0" \
                        expect     empty  other &&
similarity index 98%
rename from t/t6043-merge-rename-directories.sh
rename to t/t6423-merge-rename-directories.sh
index 83792c5ef1f5ebbdd49bb1455b262ef9d01145f9..f7ecbb886d6191c4bb2e8c1da8b23e0a1e22d47d 100755 (executable)
@@ -275,7 +275,7 @@ test_expect_success '1d: Directory renames cause a rename/rename(2to1) conflict'
                git checkout A^0 &&
 
                test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
-               test_i18ngrep "CONFLICT (rename/rename)" out &&
+               test_i18ngrep "CONFLICT (\(.*\)/\1)" out &&
 
                git ls-files -s >out &&
                test_line_count = 8 out &&
@@ -1686,7 +1686,7 @@ test_expect_success '7b: rename/rename(2to1), but only due to transitive rename'
                git checkout A^0 &&
 
                test_must_fail git -c merge.directoryRenames=true merge -s recursive B^0 >out &&
-               test_i18ngrep "CONFLICT (rename/rename)" out &&
+               test_i18ngrep "CONFLICT (\(.*\)/\1)" out &&
 
                git ls-files -s >out &&
                test_line_count = 4 out &&
@@ -2260,24 +2260,23 @@ test_expect_success '8d: rename/delete...or not?' '
 #   Commit B: w/{b,c}, z/d
 #
 # Possible Resolutions:
-#   w/o dir-rename detection: z/d, CONFLICT(z/b -> y/b vs. w/b),
-#                                  CONFLICT(z/c -> y/c vs. w/c)
-#   Currently expected:       y/d, CONFLICT(z/b -> y/b vs. w/b),
-#                                  CONFLICT(z/c -> y/c vs. w/c)
-#   Optimal:                  ??
+#   if z not considered renamed: z/d, CONFLICT(z/b -> y/b vs. w/b),
+#                                     CONFLICT(z/c -> y/c vs. w/c)
+#   if z->y rename considered:   y/d, CONFLICT(z/b -> y/b vs. w/b),
+#                                     CONFLICT(z/c -> y/c vs. w/c)
+#   Optimal:                     ??
 #
 # Notes: In commit A, directory z got renamed to y.  In commit B, directory z
 #        did NOT get renamed; the directory is still present; instead it is
 #        considered to have just renamed a subset of paths in directory z
-#        elsewhere.  Therefore, the directory rename done in commit A to z/
-#        applies to z/d and maps it to y/d.
+#        elsewhere.  However, this is much like testcase 6b (where commit B
+#        moves all the original paths out of z/ but opted to keep d
+#        within z/).  This makes it hard to judge where d should end up.
 #
 #        It's possible that users would get confused about this, but what
-#        should we do instead?  Silently leaving at z/d seems just as bad or
-#        maybe even worse.  Perhaps we could print a big warning about z/d
-#        and how we're moving to y/d in this case, but when I started thinking
-#        about the ramifications of doing that, I didn't know how to rule out
-#        that opening other weird edge and corner cases so I just punted.
+#        should we do instead?  It's not at all clear to me whether z/d or
+#        y/d or something else is a better resolution here, and other cases
+#        start getting really tricky, so I just picked one.
 
 test_setup_8e () {
        test_create_repo 8e &&
@@ -2844,6 +2843,14 @@ test_expect_success '9f: Renamed directory that only contained immediate subdirs
 #   Commit A: priority/{alpha,bravo}/$more_files
 #   Commit B: goal/{a,b}/$more_files, goal/c
 #   Expected: priority/{alpha,bravo}/$more_files, priority/c
+# We currently fail this test because the directory renames we detect are
+#   goal/a/ -> priority/alpha/
+#   goal/b/ -> priority/bravo/
+# We do not detect
+#   goal/   -> priority/
+# because of no files found within goal/, and the fact that "a" != "alpha"
+# and "b" != "bravo".  But I'm not sure it's really a failure given that
+# viewpoint...
 
 test_setup_9g () {
        test_create_repo 9g &&
@@ -2880,6 +2887,7 @@ test_setup_9g () {
 }
 
 test_expect_failure '9g: Renamed directory that only contained immediate subdirs, immediate subdirs renamed' '
+       test_setup_9g &&
        (
                cd 9g &&
 
@@ -3362,6 +3370,7 @@ test_setup_10e () {
 }
 
 test_expect_failure '10e: Does git complain about untracked file that is not really in the way?' '
+       test_setup_10e &&
        (
                cd 10e &&
 
@@ -4403,7 +4412,7 @@ test_expect_success '13b(info): messages for transitive rename with conflicted c
 #   Commit O: z/{b,c},   x/{d,e}
 #   Commit A: y/{b,c,d}, x/e
 #   Commit B: z/{b,c,d}, x/e
-#   Expected: y/{b,c,d}, with info or conflict messages for d (
+#   Expected: y/{b,c,d}, x/e, with info or conflict messages for d
 #             A: renamed x/d -> z/d; B: renamed z/ -> y/ AND renamed x/d to y/d
 #             One could argue A had partial knowledge of what was done with
 #             d and B had full knowledge, but that's a slippery slope as
similarity index 72%
rename from t/t6045-merge-rename-delete.sh
rename to t/t6425-merge-rename-delete.sh
index 5d33577d2f79f3ef1248d0090028ab350b6b9ea3..f79d021590215f63b5699d985c4e058b98bb03a7 100755 (executable)
@@ -17,7 +17,8 @@ test_expect_success 'rename/delete' '
        git commit -m "delete" &&
 
        test_must_fail git merge --strategy=recursive rename >output &&
-       test_i18ngrep "CONFLICT (rename/delete): A deleted in HEAD and renamed to B in rename. Version rename of B left in tree." output
+       test_i18ngrep "CONFLICT (rename/delete): A.* renamed .*to B.* in rename" output &&
+       test_i18ngrep "CONFLICT (rename/delete): A.*deleted in HEAD." output
 '
 
 test_done
similarity index 99%
rename from t/t6046-merge-skip-unneeded-updates.sh
rename to t/t6426-merge-skip-unneeded-updates.sh
index 5a2d07e5164364dfaf63b85a1e9000fbfc1d6e98..699813671c8c1fb5e1624c46415b44711d44a89f 100755 (executable)
@@ -374,7 +374,7 @@ test_expect_success '2c: Modify b & add c VS rename b->c' '
                export GIT_MERGE_VERBOSITY &&
                test_must_fail git merge -s recursive B^0 >out 2>err &&
 
-               test_i18ngrep "CONFLICT (rename/add): Rename b->c" out &&
+               test_i18ngrep "CONFLICT (.*/add):" out &&
                test_must_be_empty err &&
 
                # Make sure c WAS updated
index c978b6dee4a2559d5d4e4a8a9329f9288de93231..63d5f41a1247839412b9c6022fb3f4a07c4e6b0e 100755 (executable)
@@ -177,7 +177,7 @@ test_expect_success "Sergey Vlasov's test case" '
        date >ab.c &&
        date >ab/d &&
        git add ab.c ab &&
-       git commit -m 'initial' &&
+       git commit -m "initial" &&
        git mv ab a
 '
 
index 9bc841d085ee74cbc4a103b3c2f07c7e4b86e82d..cc87d26619477dfc1c330ae3a0a6cf498e5bdad1 100755 (executable)
@@ -5,8 +5,11 @@
 
 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.
 '
+# 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
 
@@ -16,12 +19,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 +41,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 +55,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 +76,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 +89,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 +113,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 +128,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 +147,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 +180,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 +202,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 +214,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 +237,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 +252,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 +275,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' "
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
        )
 '
 
index 5883a6adc31b5f0580b9fea5a7863174e803dc99..1c85f7555507695b301428b7aabea3b65a199b40 100755 (executable)
@@ -246,7 +246,7 @@ test_expect_success 'merge --squash c3 with c7' '
        #       file
        EOF
        git cat-file commit HEAD >raw &&
-       sed -e '1,/^$/d' raw >actual &&
+       sed -e "1,/^$/d" raw >actual &&
        test_cmp expect actual
 '
 
@@ -268,7 +268,7 @@ test_expect_success 'merge c3 with c7 with commit.cleanup = scissors' '
        #       file
        EOF
        git cat-file commit HEAD >raw &&
-       sed -e '1,/^$/d' raw >actual &&
+       sed -e "1,/^$/d" raw >actual &&
        test_i18ncmp expect actual
 '
 
@@ -292,7 +292,7 @@ test_expect_success 'merge c3 with c7 with --squash commit.cleanup = scissors' '
        #       file
        EOF
        git cat-file commit HEAD >raw &&
-       sed -e '1,/^$/d' raw >actual &&
+       sed -e "1,/^$/d" raw >actual &&
        test_i18ncmp expect actual
 '
 
index b871dd4f8611d2e1a1b431f55ac82cc918c9e8e8..ba8013b00285afd7f43e7090284e52fa8921224d 100755 (executable)
@@ -273,18 +273,14 @@ test_expect_success 'blame file with CRLF core.autocrlf=true' '
        grep "A U Thor" actual
 '
 
-# Tests the splitting and merging of blame entries in blame_coalesce().
-# The output of blame is the same, regardless of whether blame_coalesce() runs
-# or not, so we'd likely only notice a problem if blame crashes or assigned
-# blame to the "splitting" commit ('SPLIT' below).
-test_expect_success 'blame coalesce' '
+test_expect_success 'setup coalesce tests' '
        cat >giraffe <<-\EOF &&
        ABC
        DEF
        EOF
        git add giraffe &&
        git commit -m "original file" &&
-       oid=$(git rev-parse HEAD) &&
+       orig=$(git rev-parse HEAD) &&
 
        cat >giraffe <<-\EOF &&
        ABC
@@ -293,6 +289,7 @@ test_expect_success 'blame coalesce' '
        EOF
        git add giraffe &&
        git commit -m "interior SPLIT line" &&
+       split=$(git rev-parse HEAD) &&
 
        cat >giraffe <<-\EOF &&
        ABC
@@ -300,12 +297,25 @@ test_expect_success 'blame coalesce' '
        EOF
        git add giraffe &&
        git commit -m "same contents as original" &&
+       final=$(git rev-parse HEAD)
+'
+
+test_expect_success 'blame coalesce' '
+       cat >expect <<-EOF &&
+       $orig 1 1 2
+       $orig 2 2
+       EOF
+       git blame --porcelain $final giraffe >actual.raw &&
+       grep "^$orig" actual.raw >actual &&
+       test_cmp expect actual
+'
 
+test_expect_success 'blame does not coalesce non-adjacent result lines' '
        cat >expect <<-EOF &&
-       $oid 1) ABC
-       $oid 2) DEF
+       $orig 1) ABC
+       $orig 3) DEF
        EOF
-       git -c core.abbrev=$(test_oid hexsz) blame -s giraffe >actual &&
+       git blame --no-abbrev -s -L1,1 -L3,3 $split giraffe >actual &&
        test_cmp expect actual
 '
 
index ec261085ec68fdb8c9e9b54a9973be880a5c7db5..a08f72596ab4f622033c820f6251ccea92e38d11 100755 (executable)
@@ -1551,7 +1551,7 @@ test_expect_success $PREREQ '8-bit and sendemail.transferencoding=quoted-printab
                --smtp-server="$(pwd)/fake.sendmail" \
                email-using-8bit \
                2>errors >out &&
-       sed '1,/^$/d' msgtxt1 >actual &&
+       sed "1,/^$/d" msgtxt1 >actual &&
        test_cmp expected actual
 '
 
@@ -1568,7 +1568,7 @@ test_expect_success $PREREQ '8-bit and sendemail.transferencoding=base64' '
                --smtp-server="$(pwd)/fake.sendmail" \
                email-using-8bit \
                2>errors >out &&
-       sed '1,/^$/d' msgtxt1 >actual &&
+       sed "1,/^$/d" msgtxt1 >actual &&
        test_cmp expected actual
 '
 
@@ -1594,7 +1594,7 @@ test_expect_success $PREREQ 'convert from quoted-printable to base64' '
                --smtp-server="$(pwd)/fake.sendmail" \
                email-using-qp \
                2>errors >out &&
-       sed '1,/^$/d' msgtxt1 >actual &&
+       sed "1,/^$/d" msgtxt1 >actual &&
        test_cmp expected actual
 '
 
@@ -1624,7 +1624,7 @@ test_expect_success $PREREQ 'CRLF and sendemail.transferencoding=quoted-printabl
                --smtp-server="$(pwd)/fake.sendmail" \
                email-using-crlf \
                2>errors >out &&
-       sed '1,/^$/d' msgtxt1 >actual &&
+       sed "1,/^$/d" msgtxt1 >actual &&
        test_cmp expected actual
 '
 
@@ -1641,7 +1641,7 @@ test_expect_success $PREREQ 'CRLF and sendemail.transferencoding=base64' '
                --smtp-server="$(pwd)/fake.sendmail" \
                email-using-crlf \
                2>errors >out &&
-       sed '1,/^$/d' msgtxt1 >actual &&
+       sed "1,/^$/d" msgtxt1 >actual &&
        test_cmp expected actual
 '
 
@@ -2142,4 +2142,33 @@ test_expect_success $PREREQ 'test that send-email works outside a repo' '
                "$(pwd)/0001-add-master.patch"
 '
 
+test_expect_success $PREREQ 'test that sendmail config is rejected' '
+       test_config sendmail.program sendmail &&
+       test_must_fail git send-email \
+               --from="Example <nobody@example.com>" \
+               --to=nobody@example.com \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               HEAD^ 2>err &&
+       test_i18ngrep "found configuration options for '"'"sendmail"'"'" err
+'
+
+test_expect_success $PREREQ 'test that sendmail config rejection is specific' '
+       test_config resendmail.program sendmail &&
+       git send-email \
+               --from="Example <nobody@example.com>" \
+               --to=nobody@example.com \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               HEAD^
+'
+
+test_expect_success $PREREQ 'test forbidSendmailVariables behavior override' '
+       test_config sendmail.program sendmail &&
+       test_config sendemail.forbidSendmailVariables false &&
+       git send-email \
+               --from="Example <nobody@example.com>" \
+               --to=nobody@example.com \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               HEAD^
+'
+
 test_done
index 3055943a2208e00de53c3e4ec5d50c09a440972c..e4bb22034ee63d92d8a304f3e9754df9ec4131b8 100755 (executable)
@@ -63,16 +63,16 @@ test_expect_success "$name" '
 
 
 name='detect node change from file to directory #1'
-test_expect_success "$name" "
+test_expect_success "$name" '
        mkdir dir/new_file &&
        mv dir/file dir/new_file/file &&
        mv dir/new_file dir/file &&
        git update-index --remove dir/file &&
        git update-index --add dir/file/file &&
-       git commit -m '$name' &&
+       git commit -m "$name" &&
        test_must_fail git svn set-tree --find-copies-harder --rmdir \
                remotes/git-svn..mybranch
-"
+'
 
 
 name='detect node change from directory to file #1'
index 84787eee9acec4b65f2404356e06b2f4904cea42..c7a0dd84a4b8b8145b498ab1fa9cd8d82300c9c5 100755 (executable)
@@ -167,10 +167,10 @@ test_expect_success 'adding files' '
 
 test_expect_success 'updating' '
     git pull gitcvs.git &&
-    echo 'hi' > subdir/newfile.bin &&
-    echo 'junk' > subdir/file.h &&
-    echo 'hi' > subdir/newfile.c &&
-    echo 'hello' >> binfile.bin &&
+    echo "hi" >subdir/newfile.bin &&
+    echo "junk" >subdir/file.h &&
+    echo "hi" >subdir/newfile.c &&
+    echo "hello" >>binfile.bin &&
     git add subdir/newfile.bin subdir/file.h subdir/newfile.c binfile.bin &&
     git commit -q -m "Add and change some files" &&
     git push gitcvs.git >/dev/null &&
index cf31ace66763741a7f53e3b9a1cb3c0019255f56..6436c91a3cb73be56ee2e972b64fdaf5a386ee5e 100755 (executable)
@@ -178,7 +178,7 @@ test_expect_success 'setup v1.2 on b1' '
        mkdir cdir &&
        echo "cdir/cfile" >cdir/cfile &&
        git add -A cdir adir t3 t2 &&
-       git commit -q -m 'v1.2' &&
+       git commit -q -m "v1.2" &&
        git tag v1.2 &&
        git push --tags gitcvs.git b1:b1
 '
index 6d9ea1bb67b85641462b038a85bbf768c96fd9ea..f9904066feed6d609d8d568dbd16080957ed7aa3 100644 (file)
@@ -952,7 +952,13 @@ test_expect_code () {
 # - not all diff versions understand "-u"
 
 test_cmp() {
-       eval "$GIT_TEST_CMP" '"$@"'
+       test $# -eq 2 || BUG "test_cmp requires two arguments"
+       if ! eval "$GIT_TEST_CMP" '"$@"'
+       then
+               test "x$1" = x- || test -e "$1" || BUG "test_cmp '$1' missing"
+               test "x$2" = x- || test -e "$2" || BUG "test_cmp '$2' missing"
+               return 1
+       fi
 }
 
 # Check that the given config key has the expected value.
@@ -981,7 +987,13 @@ test_cmp_config() {
 # test_cmp_bin - helper to compare binary files
 
 test_cmp_bin() {
-       cmp "$@"
+       test $# -eq 2 || BUG "test_cmp_bin requires two arguments"
+       if ! cmp "$@"
+       then
+               test "x$1" = x- || test -e "$1" || BUG "test_cmp_bin '$1' missing"
+               test "x$2" = x- || test -e "$2" || BUG "test_cmp_bin '$2' missing"
+               return 1
+       fi
 }
 
 # Use this instead of test_cmp to compare files that contain expected and
index 2d4fd851dc0f8f317e3925e84d2567ff7467fc7f..419be0b6ea4b01933766c1cd6dfa0a3e33e154c4 100644 (file)
@@ -443,6 +443,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..298d9eedc9d0273fbc53419cafbc73182a9c934f 100644 (file)
@@ -15,7 +15,10 @@ 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;
 
        /*
index 80ad9a38d81e4e8dbe50e03b1346b3acb2c5e9f1..3b858eb457e557592dada080f95f3fe7e218b24b 100644 (file)
@@ -603,9 +603,8 @@ static int do_reachable_revlist(struct child_process *cmd,
                "rev-list", "--stdin", NULL,
        };
        struct object *o;
-       char namebuf[GIT_MAX_HEXSZ + 2]; /* ^ + hash + LF */
+       FILE *cmd_in = NULL;
        int i;
-       const unsigned hexsz = the_hash_algo->hexsz;
 
        cmd->argv = argv;
        cmd->git_cmd = 1;
@@ -623,8 +622,8 @@ static int do_reachable_revlist(struct child_process *cmd,
        if (start_command(cmd))
                goto error;
 
-       namebuf[0] = '^';
-       namebuf[hexsz + 1] = '\n';
+       cmd_in = xfdopen(cmd->in, "w");
+
        for (i = get_max_object_index(); 0 < i; ) {
                o = get_indexed_object(--i);
                if (!o)
@@ -633,11 +632,9 @@ static int do_reachable_revlist(struct child_process *cmd,
                        o->flags &= ~TMP_MARK;
                if (!is_our_ref(o, allow_uor))
                        continue;
-               memcpy(namebuf + 1, oid_to_hex(&o->oid), hexsz);
-               if (write_in_full(cmd->in, namebuf, hexsz + 2) < 0)
+               if (fprintf(cmd_in, "^%s\n", oid_to_hex(&o->oid)) < 0)
                        goto error;
        }
-       namebuf[hexsz] = '\n';
        for (i = 0; i < src->nr; i++) {
                o = src->objects[i].item;
                if (is_our_ref(o, allow_uor)) {
@@ -647,11 +644,12 @@ static int do_reachable_revlist(struct child_process *cmd,
                }
                if (reachable && o->type == OBJ_COMMIT)
                        o->flags |= TMP_MARK;
-               memcpy(namebuf, oid_to_hex(&o->oid), hexsz);
-               if (write_in_full(cmd->in, namebuf, hexsz + 1) < 0)
+               if (fprintf(cmd_in, "%s\n", oid_to_hex(&o->oid)) < 0)
                        goto error;
        }
-       close(cmd->in);
+       if (ferror(cmd_in) || fflush(cmd_in))
+               goto error;
+       fclose(cmd_in);
        cmd->in = -1;
        sigchain_pop(SIGPIPE);
 
@@ -660,8 +658,8 @@ static int do_reachable_revlist(struct child_process *cmd,
 error:
        sigchain_pop(SIGPIPE);
 
-       if (cmd->in >= 0)
-               close(cmd->in);
+       if (cmd_in)
+               fclose(cmd_in);
        if (cmd->out >= 0)
                close(cmd->out);
        return -1;
@@ -739,7 +737,6 @@ static int has_unreachable(struct object_array *src, enum allow_uor allow_uor)
        return 0;
 
 error:
-       sigchain_pop(SIGPIPE);
        if (cmd.out >= 0)
                close(cmd.out);
        return 1;
index 1df884ef0bbfbba5a751eafc1922369ad818fce5..fde02f225b2b9ed17a8246913c3bddfa6483c98b 100644 (file)
@@ -46,10 +46,14 @@ PATTERNS("elixir",
         /* Not real operators, but should be grouped */
         "|:?%[A-Za-z0-9_.]\\{\\}?"),
 IPATTERN("fortran",
+        /* Don't match comment lines */
         "!^([C*]|[ \t]*!)\n"
+        /* Don't match 'module procedure' lines */
         "!^[ \t]*MODULE[ \t]+PROCEDURE[ \t]\n"
+        /* Program, module, block data */
         "^[ \t]*((END[ \t]+)?(PROGRAM|MODULE|BLOCK[ \t]+DATA"
-               "|([^'\" \t]+[ \t]+)*(SUBROUTINE|FUNCTION))[ \t]+[A-Z].*)$",
+               /* Subroutines and functions */
+               "|([^!'\" \t]+[ \t]+)*(SUBROUTINE|FUNCTION))[ \t]+[A-Z].*)$",
         /* -- */
         "[a-zA-Z][a-zA-Z0-9_]*"
         "|\\.([Ee][Qq]|[Nn][Ee]|[Gg][TtEe]|[Ll][TtEe]|[Tt][Rr][Uu][Ee]|[Ff][Aa][Ll][Ss][Ee]|[Aa][Nn][Dd]|[Oo][Rr]|[Nn]?[Ee][Qq][Vv]|[Nn][Oo][Tt])\\."
index d75399085dead1ad52b36a12b505eef02b2036cc..bb0f9120de40f70578867dece592eeecdf0e1e23 100644 (file)
@@ -703,7 +703,7 @@ static void wt_status_collect_untracked(struct wt_status *s)
        if (!s->show_untracked_files)
                return;
 
-       memset(&dir, 0, sizeof(dir));
+       dir_init(&dir);
        if (s->show_untracked_files != SHOW_ALL_UNTRACKED_FILES)
                dir.flags |=
                        DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES;
@@ -724,19 +724,15 @@ static void wt_status_collect_untracked(struct wt_status *s)
                struct dir_entry *ent = dir.entries[i];
                if (index_name_is_other(istate, ent->name, ent->len))
                        string_list_insert(&s->untracked, ent->name);
-               free(ent);
        }
 
        for (i = 0; i < dir.ignored_nr; i++) {
                struct dir_entry *ent = dir.ignored[i];
                if (index_name_is_other(istate, ent->name, ent->len))
                        string_list_insert(&s->ignored, ent->name);
-               free(ent);
        }
 
-       free(dir.entries);
-       free(dir.ignored);
-       clear_directory(&dir);
+       dir_clear(&dir);
 
        if (advice_status_u_option)
                s->untracked_in_ms = (getnanotime() - t_begin) / 1000000;
@@ -1672,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);