Merge branch 'sl/const'
authorJunio C Hamano <gitster@pobox.com>
Thu, 7 Feb 2019 06:05:27 +0000 (22:05 -0800)
committerJunio C Hamano <gitster@pobox.com>
Thu, 7 Feb 2019 06:05:28 +0000 (22:05 -0800)
Code cleanup.

* sl/const:
various: tighten constness of some local variables

259 files changed:
.gitignore
.travis.yml
Documentation/RelNotes/2.21.0.txt
Documentation/config/core.txt
Documentation/config/pack.txt
Documentation/git-add.txt
Documentation/git-branch.txt
Documentation/git-cat-file.txt
Documentation/git-checkout.txt
Documentation/git-cherry-pick.txt
Documentation/git-diff.txt
Documentation/git-fetch.txt
Documentation/git-format-patch.txt
Documentation/git-fsck.txt
Documentation/git-help.txt
Documentation/git-init.txt
Documentation/git-instaweb.txt
Documentation/git-log.txt
Documentation/git-p4.txt
Documentation/git-pack-objects.txt
Documentation/git-rebase.txt
Documentation/git-reset.txt
Documentation/git-send-email.txt
Documentation/git-tag.txt
Documentation/git-upload-pack.txt
Documentation/gitattributes.txt
Documentation/rev-list-options.txt
Documentation/technical/commit-graph-format.txt
Documentation/technical/pack-protocol.txt
Documentation/technical/protocol-v2.txt
Makefile
README.md
alloc.c
alloc.h
apply.c
attr.c
azure-pipelines.yml [new file with mode: 0644]
bisect.c
blame.c
builtin/add.c
builtin/am.c
builtin/archive.c
builtin/bisect--helper.c
builtin/blame.c
builtin/bundle.c
builtin/cat-file.c
builtin/check-attr.c
builtin/check-ignore.c
builtin/checkout-index.c
builtin/checkout.c
builtin/clean.c
builtin/clone.c
builtin/commit-graph.c
builtin/commit-tree.c
builtin/commit.c
builtin/describe.c
builtin/diff-files.c
builtin/diff-index.c
builtin/diff-tree.c
builtin/diff.c
builtin/difftool.c
builtin/fetch-pack.c
builtin/fetch.c
builtin/fsck.c
builtin/grep.c
builtin/hash-object.c
builtin/index-pack.c
builtin/log.c
builtin/ls-files.c
builtin/merge-index.c
builtin/merge-ours.c
builtin/merge-recursive.c
builtin/merge-tree.c
builtin/merge.c
builtin/mv.c
builtin/notes.c
builtin/pack-objects.c
builtin/pull.c
builtin/read-tree.c
builtin/rebase--interactive.c
builtin/rebase.c
builtin/receive-pack.c
builtin/reflog.c
builtin/replace.c
builtin/reset.c
builtin/rev-list.c
builtin/rev-parse.c
builtin/rm.c
builtin/send-pack.c
builtin/show-ref.c
builtin/submodule--helper.c
builtin/update-index.c
builtin/write-tree.c
bulk-checkin.c
bundle.c
bundle.h
cache-tree.c
cache-tree.h
cache.h
ci/install-dependencies.sh
ci/lib-travisci.sh [deleted file]
ci/lib.sh [new file with mode: 0755]
ci/make-test-artifacts.sh [new file with mode: 0755]
ci/mount-fileshare.sh [new file with mode: 0755]
ci/print-test-failures.sh
ci/run-build-and-tests.sh
ci/run-linux32-build.sh
ci/run-linux32-docker.sh
ci/run-static-analysis.sh
ci/run-test-slice.sh [new file with mode: 0755]
ci/run-windows-build.sh
ci/test-documentation.sh
column.c
combine-diff.c
commit-graph.c
commit-graph.h
commit-reach.c
commit-reach.h
commit.c
commit.h
compat/mingw.c
compat/obstack.c
compat/obstack.h
compat/precompose_utf8.c
config.c
connect.c
contrib/coccinelle/strbuf.cocci
contrib/coccinelle/the_repository.pending.cocci [new file with mode: 0644]
convert.c
date.c
diff.c
dir.c
fetch-pack.c
fuzz-commit-graph.c [new file with mode: 0644]
git-bisect.sh
git-instaweb.sh
git-legacy-rebase.sh
git-p4.py
git-rebase--am.sh
git-rebase--common.sh
git-rebase--merge.sh [deleted file]
git-submodule.sh
git.c
help.c
http-push.c
http-walker.c
http.c
http.h
list-objects-filter-options.c
list-objects-filter-options.h
list-objects-filter.c
list-objects.c
list-objects.h
ls-refs.c
match-trees.c
merge-recursive.c
merge-recursive.h
merge.c
name-hash.c
notes-merge.c
notes-utils.c
notes-utils.h
object-store.h
object.c
pack-objects.c
pack-objects.h
packfile.c
packfile.h
path.h
pathspec.c
pkt-line.c
pkt-line.h
preload-index.c
pretty.c
pretty.h
read-cache.c
refs.c
remote-curl.c
repository.c
repository.h
rerere.c
revision.c
revision.h
send-pack.c
sequencer.c
sequencer.h
serve.c
setup.c
sha1-file.c
sha1-name.c
sideband.c
sideband.h
streaming.c
submodule.c
t/.gitignore
t/README
t/check-non-portable-shell.pl
t/helper/test-date.c
t/helper/test-dump-fsmonitor.c
t/helper/test-dump-untracked-cache.c
t/helper/test-path-utils.c
t/helper/test-ref-store.c
t/helper/test-repository.c
t/helper/test-tool.c
t/helper/test-tool.h
t/helper/test-xml-encode.c [new file with mode: 0644]
t/lib-httpd/apache.conf
t/t0003-attributes.sh
t/t0006-date.sh
t/t0021-conversion.sh
t/t0025-crlf-renormalize.sh
t/t0028-working-tree-encoding.sh
t/t0061-run-command.sh
t/t1050-large.sh
t/t1450-fsck.sh
t/t1512-rev-parse-disambiguation.sh
t/t2018-checkout-branch.sh
t/t3404-rebase-interactive.sh
t/t3406-rebase-message.sh
t/t3420-rebase-autostash.sh
t/t3421-rebase-topology-linear.sh
t/t3425-rebase-topology-merges.sh
t/t3430-rebase-merges.sh
t/t3700-add.sh
t/t4006-diff-mode.sh
t/t4013-diff-various.sh
t/t4013/diff.diff-tree_--cc_--shortstat_master [new file with mode: 0644]
t/t4013/diff.diff-tree_--cc_--summary_REVERSE [new file with mode: 0644]
t/t4013/diff.diff_--dirstat_--cc_master~1_master [new file with mode: 0644]
t/t4066-diff-emit-delay.sh [new file with mode: 0755]
t/t5315-pack-objects-compression.sh
t/t5318-commit-graph.sh
t/t5322-pack-objects-sparse.sh [new file with mode: 0755]
t/t5407-post-rewrite-hook.sh
t/t5537-fetch-shallow.sh
t/t5580-clone-push-unc.sh
t/t5701-git-serve.sh
t/t5702-protocol-v2.sh
t/t5703-upload-pack-ref-in-want.sh
t/t6030-bisect-porcelain.sh
t/t6042-merge-rename-corner-cases.sh
t/t6112-rev-list-filters-objects.sh
t/t7505-prepare-commit-msg-hook.sh
t/t7510-signed-commit.sh
t/t9303-fast-import-compression.sh
t/t9807-git-p4-submit.sh
t/t9903-bash-prompt.sh
t/test-lib.sh
transport-helper.c
transport.c
tree-walk.c
tree-walk.h
tree.c
unpack-trees.c
upload-pack.c
utf8.c
utf8.h
wrapper.c
wt-status.c
index 0d77ea5894274c43c4b348c8b52b8e665a1a339e..7374587f9df901cba0a6990ad48fac17f8a5be57 100644 (file)
@@ -1,3 +1,4 @@
+/fuzz-commit-graph
 /fuzz_corpora
 /fuzz-pack-headers
 /fuzz-pack-idx
 /git-rebase--am
 /git-rebase--common
 /git-rebase--interactive
-/git-rebase--merge
 /git-rebase--preserve-merges
 /git-receive-pack
 /git-reflog
 *.pdb
 /Debug/
 /Release/
+*.dSYM
index 03c8e4c613015476fffe3f1e071c0c9d6609df0e..36cbdea7f4f37e7eb4d5172daa4431cffcb4b46c 100644 (file)
@@ -8,6 +8,8 @@ os:
   - linux
   - osx
 
+osx_image: xcode10.1
+
 compiler:
   - clang
   - gcc
index 4596d9e01a8edebac8b0cb15c38fd35830490c68..5ad2233c9950b1b3d0c3b558ac9c81bb3b7cf2f0 100644 (file)
@@ -59,6 +59,9 @@ UI, Workflows & Features
  * Custom userformat "log --format" learned %S atom that stands for
    the tip the traversal reached the commit from, i.e. --source.
 
+ * "git instaweb" learned to drive http.server that comes with
+   "batteries included" Python installation (both Python2 & 3).
+
 
 Performance, Internal Implementation, Development Support etc.
 
@@ -101,6 +104,26 @@ Performance, Internal Implementation, Development Support etc.
  * The code to walk tree objects has been taught that we may be
    working with object names that are not computed with SHA-1.
 
+ * The in-core repository instances are passed through more codepaths.
+
+ * Update the protocol message specification to allow only the limited
+   use of scaled quantities.  This is ensure potential compatibility
+   issues will not go out of hand.
+
+ * Micro-optimize the code that prepares commit objects to be walked
+   by "git rev-list" when the commit-graph is available.
+
+ * "git fetch" and "git upload-pack" learned to send all exchange over
+   the sideband channel while talking the v2 protocol.
+
+ * The codepath to write out commit-graph has been optimized by
+   following the usual pattern of visiting objects in in-pack order.
+
+ * The codepath to show progress meter while writing out commit-graph
+   file has been improved.
+
+ * Cocci rules have been updated to encourage use of strbuf_addbuf().
+
 
 Fixes since v2.20
 -----------------
@@ -221,6 +244,71 @@ Fixes since v2.20
    temporary file.
    (merge fa6f225e01 js/add-e-clear-patch-before-stating later to maint).
 
+ * "git p4" failed to update a shelved change when there were moved
+   files, which has been corrected.
+   (merge 7a10946ab9 ld/git-p4-shelve-update-fix later to maint).
+
+ * The codepath to read from the commit-graph file attempted to read
+   past the end of it when the file's table-of-contents was corrupt.
+
+ * The compat/obstack code had casts that -Wcast-function-type
+   compilation option found questionable.
+   (merge 764473d257 sg/obstack-cast-function-type-fix later to maint).
+
+ * An obvious typo in an assertion error message has been fixed.
+   (merge 3c27e2e059 cc/test-ref-store-typofix later to maint).
+
+ * In Git for Windows, "git clone \\server\share\path" etc. that uses
+   UNC paths from command line had bad interaction with its shell
+   emulation.
+
+ * "git add --ignore-errors" did not work as advertised and instead
+   worked as an unintended synonym for "git add --renormalize", which
+   has been fixed.
+   (merge 9e5da3d055 jk/add-ignore-errors-bit-assignment-fix later to maint).
+
+ * On a case-insensitive filesystem, we failed to compare the part of
+   the path that is above the worktree directory in an absolute
+   pathname, which has been corrected.
+
+ * Asking "git check-attr" about a macro (e.g. "binary") on a specific
+   path did not work correctly, even though "git check-attr -a" listed
+   such a macro correctly.  This has been corrected.
+   (merge 7b95849be4 jk/attr-macro-fix later to maint).
+
+ * "git pack-objects" incorrectly used uninitialized mutex, which has
+   been corrected.
+   (merge edb673cf10 ph/pack-objects-mutex-fix later to maint).
+
+ * "git checkout -b <new> [HEAD]" to create a new branch from the
+   current commit and check it out ought to be a no-op in the index
+   and the working tree in normal cases, but there are corner cases
+   that do require updates to the index and the working tree.  Running
+   it immediately after "git clone --no-checkout" is one of these
+   cases that an earlier optimization kicked in incorrectly, which has
+   been fixed.
+   (merge 8424bfd45b bp/checkout-new-branch-optim later to maint).
+
+ * "git diff --color-moved --cc --stat -p" did not work well due to
+   funny interaction between a bug in color-moved and the rest, which
+   has been fixed.
+   (merge dac03b5518 jk/diff-cc-stat-fixes later to maint).
+
+ * When GIT_SEQUENCE_EDITOR is set, the command was incorrectly
+   started when modes of "git rebase" that implicitly uses the
+   machinery for the interactive rebase are run, which has been
+   corrected.
+   (merge 891d4a0313 pw/no-editor-in-rebase-i-implicit later to maint).
+
+ * The commit-graph facility did not work when in-core objects that
+   are promoted from unknown type to commit (e.g. a commit that is
+   accessed via a tag that refers to it) were involved, which has been
+   corrected.
+   (merge 4468d4435c sg/object-as-type-commit-graph-fix later to maint).
+
+ * "git fetch" output cleanup.
+   (merge dc40b24df4 nd/fetch-compact-update later to maint).
+
  * Code cleanup, docfix, build fix, etc.
    (merge 89ba9a79ae hb/t0061-dot-in-path-fix later to maint).
    (merge d173e799ea sb/diff-color-moved-config-option-fixup later to maint).
@@ -240,3 +328,5 @@ Fixes since v2.20
    (merge 1747125e2c cc/parial-clone-doc-typofix later to maint).
    (merge e01378753d cc/fetch-error-message-fix later to maint).
    (merge 54e8c11215 jk/remote-insteadof-cleanup later to maint).
+   (merge d609615f48 js/test-git-installed later to maint).
+   (merge ba170517be ja/doc-style-fix later to maint).
index d0e6635fe0b56b87826240bc80cfef40b722bef4..7e9b6c8f4c2d36116be6699c0dc822222393dae6 100644 (file)
@@ -121,11 +121,14 @@ core.quotePath::
 
 core.eol::
        Sets the line ending type to use in the working directory for
-       files that have the `text` property set when core.autocrlf is false.
+       files that are marked as text (either by having the `text`
+       attribute set, or by having `text=auto` and Git auto-detecting
+       the contents as text).
        Alternatives are 'lf', 'crlf' and 'native', which uses the platform's
        native line ending.  The default value is `native`.  See
        linkgit:gitattributes[5] for more information on end-of-line
-       conversion.
+       conversion. Note that this value is ignored if `core.autocrlf`
+       is set to `true` or `input`.
 
 core.safecrlf::
        If true, makes Git check if converting `CRLF` is reversible when
index edac75c83f471bee7e9f560b1ec2defc13e0482e..425c73aa521a67f87941bd8fc11c69b52432cb00 100644 (file)
@@ -105,6 +105,15 @@ pack.useBitmaps::
        true. You should not generally need to turn this off unless
        you are debugging pack bitmaps.
 
+pack.useSparse::
+       When true, git will default to using the '--sparse' option in
+       'git pack-objects' when the '--revs' option is present. This
+       algorithm only walks trees that appear in paths that introduce new
+       objects. This can have significant performance benefits when
+       computing a pack to send a small change. However, it is possible
+       that extra objects are added to the pack-file if the included
+       commits contain certain types of direct renames.
+
 pack.writeBitmaps (deprecated)::
        This is a deprecated synonym for `repack.writeBitmaps`.
 
index 45652fe4a6a51c251f773776576956745701d677..37bcab94d5e435849c22ddd0473be5cfb1c56140 100644 (file)
@@ -58,9 +58,9 @@ OPTIONS
        specifying `dir` will record not just a file `dir/file1`
        modified in the working tree, a file `dir/file2` added to
        the working tree, but also a file `dir/file3` removed from
-       the working tree Note that older versions of Git used
+       the working tree). Note that older versions of Git used
        to ignore removed files; use `--no-all` option if you want
-       to add modified or new files but ignore removed ones.
+       to add modified or new files but ignore removed ones.
 +
 For more details about the <pathspec> syntax, see the 'pathspec' entry
 in linkgit:gitglossary[7].
@@ -124,7 +124,7 @@ subdirectories).
 --no-ignore-removal::
        Update the index not only where the working tree has a file
        matching <pathspec> but also where the index already has an
-       entry.  This adds, modifies, and removes index entries to
+       entry. This adds, modifies, and removes index entries to
        match the working tree.
 +
 If no <pathspec> is given when `-A` option is used, all
@@ -206,7 +206,7 @@ EXAMPLES
 --------
 
 * Adds content from all `*.txt` files under `Documentation` directory
-and its subdirectories:
+  and its subdirectories:
 +
 ------------
 $ git add Documentation/\*.txt
index bf5316ffa929a88aa98f5b3c7a892ee43638a098..3bd83a7cbdd9d62c9b10057bd4bf3f03d57b1085 100644 (file)
@@ -297,7 +297,7 @@ $ git checkout my2.6.14
 ------------
 +
 <1> This step and the next one could be combined into a single step with
-"checkout -b my2.6.14 v2.6.14".
+    "checkout -b my2.6.14 v2.6.14".
 
 Delete an unneeded branch::
 +
@@ -309,10 +309,10 @@ $ git branch -D test                                    <2>
 ------------
 +
 <1> Delete the remote-tracking branches "todo", "html" and "man". The next
-'fetch' or 'pull' will create them again unless you configure them not to.
-See linkgit:git-fetch[1].
+    'fetch' or 'pull' will create them again unless you configure them not to.
+    See linkgit:git-fetch[1].
 <2> Delete the "test" branch even if the "master" branch (or whichever branch
-is currently checked out) does not have all commits from the test branch.
+    is currently checked out) does not have all commits from the test branch.
 
 
 NOTES
index 9a2e9cdafba59cf731f8e7c2bc564d7942977996..8eca671b8278cfe02692605b80a9121bc5717567 100644 (file)
@@ -252,6 +252,12 @@ the repository, then `cat-file` will ignore any custom format and print:
 <object> SP missing LF
 ------------
 
+If a name is specified that might refer to more than one object (an ambiguous short sha), then `cat-file` will ignore any custom format and print:
+
+------------
+<object> SP ambiguous LF
+------------
+
 If --follow-symlinks is used, and a symlink in the repository points
 outside the repository, then `cat-file` will ignore any custom format
 and print:
index 6acc3d98e7422be7f313b0a203a61565fae212c5..9a396498d106e1f3ff581d465c072d90686f8c21 100644 (file)
@@ -424,14 +424,14 @@ $ git tag foo           <3>
 ------------
 
 <1> creates a new branch 'foo', which refers to commit 'f', and then
-updates HEAD to refer to branch 'foo'. In other words, we'll no longer
-be in detached HEAD state after this command.
+    updates HEAD to refer to branch 'foo'. In other words, we'll no longer
+    be in detached HEAD state after this command.
 
 <2> similarly creates a new branch 'foo', which refers to commit 'f',
-but leaves HEAD detached.
+    but leaves HEAD detached.
 
 <3> creates a new tag 'foo', which refers to commit 'f',
-leaving HEAD detached.
+    leaving HEAD detached.
 
 If we have moved away from commit 'f', then we must first recover its object
 name (typically by using git reflog), and then we can create a reference to
@@ -459,8 +459,8 @@ EXAMPLES
 --------
 
 . The following sequence checks out the `master` branch, reverts
-the `Makefile` to two revisions back, deletes hello.c by
-mistake, and gets it back from the index.
+  the `Makefile` to two revisions back, deletes hello.c by
+  mistake, and gets it back from the index.
 +
 ------------
 $ git checkout master             <1>
@@ -494,7 +494,7 @@ $ git checkout -- hello.c
 ------------
 
 . After working in the wrong branch, switching to the correct
-branch would be done using:
+  branch would be done using:
 +
 ------------
 $ git checkout mytopic
@@ -522,7 +522,7 @@ registered in your index file, so `git diff` would show you what
 changes you made since the tip of the new branch.
 
 . When a merge conflict happens during switching branches with
-the `-m` option, you would see something like this:
+  the `-m` option, you would see something like this:
 +
 ------------
 $ git checkout -m mytopic
index d35d771fc8172e12958b4a9521c51a5f65cddebe..b8cfeec67e5fbdcfe1705a3b249f97b284932e79 100644 (file)
@@ -213,16 +213,16 @@ $ git reset --merge ORIG_HEAD        <3>
 $ git cherry-pick -Xpatience topic^  <4>
 ------------
 <1> apply the change that would be shown by `git show topic^`.
-In this example, the patch does not apply cleanly, so
-information about the conflict is written to the index and
-working tree and no new commit results.
+    In this example, the patch does not apply cleanly, so
+    information about the conflict is written to the index and
+    working tree and no new commit results.
 <2> summarize changes to be reconciled
 <3> cancel the cherry-pick.  In other words, return to the
-pre-cherry-pick state, preserving any local modifications you had in
-the working tree.
+    pre-cherry-pick state, preserving any local modifications
+    you had in the working tree.
 <4> try to apply the change introduced by `topic^` again,
-spending extra time to avoid mistakes based on incorrectly matching
-context lines.
+    spending extra time to avoid mistakes based on incorrectly
+    matching context lines.
 
 SEE ALSO
 --------
index 030f162f301608c329fecae04953620eb78f0b14..72179d993cb9b68766e2d9093f323cb3720e38f4 100644 (file)
@@ -132,9 +132,9 @@ $ git diff HEAD       <3>
 +
 <1> Changes in the working tree not yet staged for the next commit.
 <2> Changes between the index and your last commit; what you
-would be committing if you run "git commit" without "-a" option.
+    would be committing if you run "git commit" without "-a" option.
 <3> Changes in the working tree since your last commit; what you
-would be committing if you run "git commit -a"
+    would be committing if you run "git commit -a"
 
 Comparing with arbitrary commits::
 +
@@ -145,10 +145,10 @@ $ git diff HEAD^ HEAD      <3>
 ------------
 +
 <1> Instead of using the tip of the current branch, compare with the
-tip of "test" branch.
+    tip of "test" branch.
 <2> Instead of comparing with the tip of "test" branch, compare with
-the tip of the current branch, but limit the comparison to the
-file "test".
+    the tip of the current branch, but limit the comparison to the
+    file "test".
 <3> Compare the version before the last commit and the last commit.
 
 Comparing branches::
@@ -162,7 +162,7 @@ $ git diff topic...master  <3>
 <1> Changes between the tips of the topic and the master branches.
 <2> Same as above.
 <3> Changes that occurred on the master branch since when the topic
-branch was started off it.
+    branch was started off it.
 
 Limiting the diff output::
 +
@@ -173,9 +173,9 @@ $ git diff arch/i386 include/asm-i386   <3>
 ------------
 +
 <1> Show only modification, rename, and copy, but not addition
-or deletion.
+    or deletion.
 <2> Show only names and the nature of change, but not actual
-diff output.
+    diff output.
 <3> Limit diff output to named subtrees.
 
 Munging the diff output::
@@ -186,7 +186,7 @@ $ git diff -R                          <2>
 ------------
 +
 <1> Spend extra cycles to find renames, copies and complete
-rewrites (very expensive).
+    rewrites (very expensive).
 <2> Output diff in reverse.
 
 SEE ALSO
index e3199355978880b21668bc1aff0e42f610c02bd6..266d63cf111c8a73420c5fa945543384e9825b55 100644 (file)
@@ -266,7 +266,7 @@ The `pu` branch will be updated even if it is does not fast-forward,
 because it is prefixed with a plus sign; `tmp` will not be.
 
 * Peek at a remote's branch, without configuring the remote in your local
-repository:
+  repository:
 +
 ------------------------------------------------
 $ git fetch git://git.kernel.org/pub/scm/git/git.git maint
index 27304428a12ce9d0ee46e10e3c63069b4677838a..1af85d404f5191c18a8c587df06e7c0620066236 100644 (file)
@@ -504,9 +504,9 @@ Toggle it to make sure it is set to `false`. Also, search for
 "mailnews.wraplength" and set the value to 0.
 
 3. Disable the use of format=flowed:
-Edit..Preferences..Advanced..Config Editor.  Search for
-"mailnews.send_plaintext_flowed".
-Toggle it to make sure it is set to `false`.
+   Edit..Preferences..Advanced..Config Editor.  Search for
+   "mailnews.send_plaintext_flowed".
+   Toggle it to make sure it is set to `false`.
 
 After that is done, you should be able to compose email as you
 otherwise would (cut + paste, 'git format-patch' | 'git imap-send', etc),
@@ -629,14 +629,14 @@ EXAMPLES
 --------
 
 * Extract commits between revisions R1 and R2, and apply them on top of
-the current branch using 'git am' to cherry-pick them:
+  the current branch using 'git am' to cherry-pick them:
 +
 ------------
 $ git format-patch -k --stdout R1..R2 | git am -3 -k
 ------------
 
 * Extract all commits which are in the current branch but not in the
-origin branch:
+  origin branch:
 +
 ------------
 $ git format-patch origin
@@ -645,7 +645,7 @@ $ git format-patch origin
 For each commit a separate file is created in the current directory.
 
 * Extract all commits that lead to 'origin' since the inception of the
-project:
+  project:
 +
 ------------
 $ git format-patch --root origin
@@ -664,7 +664,7 @@ Note that non-Git "patch" programs won't understand renaming patches, so
 use it only when you know the recipient uses Git to apply your patch.
 
 * Extract three topmost commits from the current branch and format them
-as e-mailable patches:
+  as e-mailable patches:
 +
 ------------
 $ git format-patch -3
index ab9a93fb9b8fb7291362cc419a7aca8b464d3d76..55950d9eea9edb5157352fa3e6316ef3507e99bf 100644 (file)
@@ -140,9 +140,9 @@ dangling <type> <object>::
        The <type> object <object>, is present in the database but never
        'directly' used. A dangling commit could be a root node.
 
-sha1 mismatch <object>::
-       The database has an object who's sha1 doesn't match the
-       database value.
+hash mismatch <object>::
+       The database has an object whose hash doesn't match the
+       object database value.
        This indicates a serious data integrity problem.
 
 Environment Variables
index aab5453bbbb239931ee2006095135c8db9f0f9ea..c318bf87e174f18798a2fcb0530bec05a34c4c92 100644 (file)
@@ -118,9 +118,9 @@ format is chosen. The following values are currently supported:
 
 * "man": use the 'man' program as usual,
 * "woman": use 'emacsclient' to launch the "woman" mode in emacs
-(this only works starting with emacsclient versions 22),
+  (this only works starting with emacsclient versions 22),
 * "konqueror": use 'kfmclient' to open the man page in a new konqueror
-tab (see 'Note about konqueror' below).
+  tab (see 'Note about konqueror' below).
 
 Values for other tools can be used if there is a corresponding
 `man.<tool>.cmd` configuration entry (see below).
index 057076ca38eecfc6d25caeb90110efc4c30e83a1..32880aafb0c55ce29f35490fd734587c38095066 100644 (file)
@@ -128,7 +128,7 @@ The template directory will be one of the following (in order):
 The default template directory includes some directory structure, suggested
 "exclude patterns" (see linkgit:gitignore[5]), and sample hook files.
 
-The sample hooks are all disabled by default, To enable one of the
+The sample hooks are all disabled by default. To enable one of the
 sample hooks rename it by removing its `.sample` suffix.
 
 See linkgit:githooks[5] for more general info on hook execution.
index e8ecdbf927ba5e7af79d3852a9a939c10052e45f..a54fe4401bd1a21c6bd133745ab8864882ca73d4 100644 (file)
@@ -29,7 +29,8 @@ OPTIONS
        The HTTP daemon command-line that will be executed.
        Command-line options may be specified here, and the
        configuration file will be added at the end of the command-line.
-       Currently apache2, lighttpd, mongoose, plackup and webrick are supported.
+       Currently apache2, lighttpd, mongoose, plackup, python and
+       webrick are supported.
        (Default: lighttpd)
 
 -m::
index 90761f169444c165f0e94ebc3b7731cd8d85d3f0..b02e922dc33d248493df4bf6e1bb42f342e38daa 100644 (file)
@@ -192,6 +192,10 @@ log.date::
        Default format for human-readable dates.  (Compare the
        `--date` option.)  Defaults to "default", which means to write
        dates like `Sat May 8 19:35:34 2010 -0500`.
++
+If the format is set to "auto:foo" and the pager is in use, format
+"foo" will be the used for the date format. Otherwise "default" will
+be used.
 
 log.follow::
        If `true`, `git log` will act as if the `--follow` option was used when
index f0a0280954f18532a1f12d4e5e6cae094c778784..3494a1db3ebf4991ed05011a8f4035807db7a9f6 100644 (file)
@@ -71,12 +71,12 @@ $ git p4 clone //depot/path/project
 ------------
 This:
 
-1.   Creates an empty Git repository in a subdirectory called 'project'.
+1. Creates an empty Git repository in a subdirectory called 'project'.
 +
-2.   Imports the full contents of the head revision from the given p4
-depot path into a single commit in the Git branch 'refs/remotes/p4/master'.
+2. Imports the full contents of the head revision from the given p4
+   depot path into a single commit in the Git branch 'refs/remotes/p4/master'.
 +
-3.   Creates a local branch, 'master' from this remote and checks it out.
+3. Creates a local branch, 'master' from this remote and checks it out.
 
 To reproduce the entire p4 history in Git, use the '@all' modifier on
 the depot path:
index 40c825c38197f4e335ebfb162415cdcc52bbdf1e..e45f3e680d3632c8122db01b2a51cc3971c27922 100644 (file)
@@ -14,7 +14,7 @@ SYNOPSIS
        [--local] [--incremental] [--window=<n>] [--depth=<n>]
        [--revs [--unpacked | --all]] [--keep-pack=<pack-name>]
        [--stdout [--filter=<filter-spec>] | base-name]
-       [--shallow] [--keep-true-parents] < object-list
+       [--shallow] [--keep-true-parents] [--sparse] < object-list
 
 
 DESCRIPTION
@@ -196,6 +196,15 @@ depth is 4095.
        Add --no-reuse-object if you want to force a uniform compression
        level on all data no matter the source.
 
+--sparse::
+       Use the "sparse" algorithm to determine which objects to include in
+       the pack, when combined with the "--revs" option. This algorithm
+       only walks trees that appear in paths that introduce new objects.
+       This can have significant performance benefits when computing
+       a pack to send a small change. However, it is possible that extra
+       objects are added to the pack-file if the included commits contain
+       certain types of direct renames.
+
 --thin::
        Create a "thin" pack by omitting the common objects between a
        sender and a receiver in order to reduce network transfer. This
index 4dd5853d6e0235c846caa1bdd05c7ab25d6ac31d..7e695b30e455245d8c187b7be0402e35bb83362c 100644 (file)
@@ -515,15 +515,7 @@ See also INCOMPATIBLE OPTIONS below.
 INCOMPATIBLE OPTIONS
 --------------------
 
-git-rebase has many flags that are incompatible with each other,
-predominantly due to the fact that it has three different underlying
-implementations:
-
- * one based on linkgit:git-am[1] (the default)
- * one based on git-merge-recursive (merge backend)
- * one based on linkgit:git-cherry-pick[1] (interactive backend)
-
-Flags only understood by the am backend:
+The following options:
 
  * --committer-date-is-author-date
  * --ignore-date
@@ -531,15 +523,12 @@ Flags only understood by the am backend:
  * --ignore-whitespace
  * -C
 
-Flags understood by both merge and interactive backends:
+are incompatible with the following options:
 
  * --merge
  * --strategy
  * --strategy-option
  * --allow-empty-message
-
-Flags only understood by the interactive backend:
-
  * --[no-]autosquash
  * --rebase-merges
  * --preserve-merges
@@ -550,7 +539,7 @@ Flags only understood by the interactive backend:
  * --edit-todo
  * --root when used in combination with --onto
 
-Other incompatible flag pairs:
+In addition, the following pairs of options are incompatible:
 
  * --preserve-merges and --interactive
  * --preserve-merges and --signoff
index 9f69ae8b693a15184f26f65a44e552fb31a0bd32..132f8e55f67b2e2a40f0058888f4f8260c51f270 100644 (file)
@@ -115,17 +115,17 @@ $ git pull git://info.example.com/ nitfol  <4>
 ------------
 +
 <1> You are happily working on something, and find the changes
-in these files are in good order.  You do not want to see them
-when you run `git diff`, because you plan to work on other files
-and changes with these files are distracting.
+    in these files are in good order.  You do not want to see them
+    when you run `git diff`, because you plan to work on other files
+    and changes with these files are distracting.
 <2> Somebody asks you to pull, and the changes sound worthy of merging.
 <3> However, you already dirtied the index (i.e. your index does
-not match the `HEAD` commit).  But you know the pull you are going
-to make does not affect `frotz.c` or `filfre.c`, so you revert the
-index changes for these two files.  Your changes in working tree
-remain there.
+    not match the `HEAD` commit).  But you know the pull you are going
+    to make does not affect `frotz.c` or `filfre.c`, so you revert the
+    index changes for these two files.  Your changes in working tree
+    remain there.
 <4> Then you can pull and merge, leaving `frotz.c` and `filfre.c`
-changes still in the working tree.
+    changes still in the working tree.
 
 Undo a commit and redo::
 +
@@ -137,12 +137,12 @@ $ git commit -a -c ORIG_HEAD  <3>
 ------------
 +
 <1> This is most often done when you remembered what you
-just committed is incomplete, or you misspelled your commit
-message, or both.  Leaves working tree as it was before "reset".
+    just committed is incomplete, or you misspelled your commit
+    message, or both.  Leaves working tree as it was before "reset".
 <2> Make corrections to working tree files.
 <3> "reset" copies the old head to `.git/ORIG_HEAD`; redo the
-commit by starting with its log message.  If you do not need to
-edit the message further, you can give `-C` option instead.
+    commit by starting with its log message.  If you do not need to
+    edit the message further, you can give `-C` option instead.
 +
 See also the `--amend` option to linkgit:git-commit[1].
 
@@ -155,9 +155,9 @@ $ git checkout topic/wip   <3>
 ------------
 +
 <1> You have made some commits, but realize they were premature
-to be in the `master` branch.  You want to continue polishing
-them in a topic branch, so create `topic/wip` branch off of the
-current `HEAD`.
+    to be in the `master` branch.  You want to continue polishing
+    them in a topic branch, so create `topic/wip` branch off of the
+    current `HEAD`.
 <2> Rewind the master branch to get rid of those three commits.
 <3> Switch to `topic/wip` branch and keep working.
 
@@ -169,10 +169,10 @@ $ git reset --hard HEAD~3   <1>
 ------------
 +
 <1> The last three commits (`HEAD`, `HEAD^`, and `HEAD~2`) were bad
-and you do not want to ever see them again.  Do *not* do this if
-you have already given these commits to somebody else.  (See the
-"RECOVERING FROM UPSTREAM REBASE" section in linkgit:git-rebase[1] for
-the implications of doing so.)
+    and you do not want to ever see them again.  Do *not* do this if
+    you have already given these commits to somebody else.  (See the
+    "RECOVERING FROM UPSTREAM REBASE" section in linkgit:git-rebase[1]
+    for the implications of doing so.)
 
 Undo a merge or pull::
 +
@@ -189,18 +189,18 @@ $ git reset --hard ORIG_HEAD       <4>
 ------------
 +
 <1> Try to update from the upstream resulted in a lot of
-conflicts; you were not ready to spend a lot of time merging
-right now, so you decide to do that later.
+    conflicts; you were not ready to spend a lot of time merging
+    right now, so you decide to do that later.
 <2> "pull" has not made merge commit, so `git reset --hard`
-which is a synonym for `git reset --hard HEAD` clears the mess
-from the index file and the working tree.
+    which is a synonym for `git reset --hard HEAD` clears the mess
+    from the index file and the working tree.
 <3> Merge a topic branch into the current branch, which resulted
-in a fast-forward.
+    in a fast-forward.
 <4> But you decided that the topic branch is not ready for public
-consumption yet.  "pull" or "merge" always leaves the original
-tip of the current branch in `ORIG_HEAD`, so resetting hard to it
-brings your index file and the working tree back to that state,
-and resets the tip of the branch to that commit.
+    consumption yet.  "pull" or "merge" always leaves the original
+    tip of the current branch in `ORIG_HEAD`, so resetting hard to it
+    brings your index file and the working tree back to that state,
+    and resets the tip of the branch to that commit.
 
 Undo a merge or pull inside a dirty working tree::
 +
@@ -214,14 +214,14 @@ $ git reset --merge ORIG_HEAD      <2>
 ------------
 +
 <1> Even if you may have local modifications in your
-working tree, you can safely say `git pull` when you know
-that the change in the other branch does not overlap with
-them.
+    working tree, you can safely say `git pull` when you know
+    that the change in the other branch does not overlap with
+    them.
 <2> After inspecting the result of the merge, you may find
-that the change in the other branch is unsatisfactory.  Running
-`git reset --hard ORIG_HEAD` will let you go back to where you
-were, but it will discard your local changes, which you do not
-want.  `git reset --merge` keeps your local changes.
+    that the change in the other branch is unsatisfactory.  Running
+    `git reset --hard ORIG_HEAD` will let you go back to where you
+    were, but it will discard your local changes, which you do not
+    want.  `git reset --merge` keeps your local changes.
 
 
 Interrupted workflow::
index 62c6c76f2736e0ee2dd61d3ac25a4962a9db0fc7..1afe9fc858ea7dcd05ae5f77c994af8f17f5bf52 100644 (file)
@@ -33,7 +33,7 @@ This is what linkgit:git-format-patch[1] generates.  Most headers and MIME
 formatting are ignored.
 
 2. The original format used by Greg Kroah-Hartman's 'send_lots_of_email.pl'
-script
+   script
 +
 This format expects the first line of the file to contain the "Cc:" value
 and the "Subject:" of the message as the second line.
index f2d644e3af1849d842567bfb7a2c38083984545d..a74e7b926d030f6f385e49be68714133f6e3c06e 100644 (file)
@@ -237,16 +237,16 @@ your repository directly), then others will have already seen
 the old tag. In that case you can do one of two things:
 
 . The sane thing.
-Just admit you screwed up, and use a different name. Others have
-already seen one tag-name, and if you keep the same name, you
-may be in the situation that two people both have "version X",
-but they actually have 'different' "X"'s.  So just call it "X.1"
-and be done with it.
+  Just admit you screwed up, and use a different name. Others have
+  already seen one tag-name, and if you keep the same name, you
+  may be in the situation that two people both have "version X",
+  but they actually have 'different' "X"'s.  So just call it "X.1"
+  and be done with it.
 
 . The insane thing.
-You really want to call the new version "X" too, 'even though'
-others have already seen the old one. So just use 'git tag -f'
-again, as if you hadn't already published the old one.
+  You really want to call the new version "X" too, 'even though'
+  others have already seen the old one. So just use 'git tag -f'
+  again, as if you hadn't already published the old one.
 
 However, Git does *not* (and it should not) change tags behind
 users back. So if somebody already got the old tag, doing a
index 998f52d3df71e29d4178251de375d70cd570a1d8..9822c1eb1add168cdb30426bab04d925504d0205 100644 (file)
@@ -22,7 +22,6 @@ The UI for the protocol is on the 'git fetch-pack' side, and the
 program pair is meant to be used to pull updates from a remote
 repository.  For push operations, see 'git send-pack'.
 
-
 OPTIONS
 -------
 
index b8392fc3300cfa7d7c37e37dd069246f20ceadb1..9b41f81c06ef9fd2386b0e424d4d62cb27195ae3 100644 (file)
@@ -124,7 +124,9 @@ text file is normalized, its line endings are converted to LF in the
 repository.  To control what line ending style is used in the working
 directory, use the `eol` attribute for a single file and the
 `core.eol` configuration variable for all text files.
-Note that `core.autocrlf` overrides `core.eol`
+Note that setting `core.autocrlf` to `true` or `input` overrides
+`core.eol` (see the definitions of those options in
+linkgit:git-config[1]).
 
 Set::
 
@@ -344,7 +346,9 @@ automatic line ending conversion based on your platform.
 
 Use the following attributes if your '*.ps1' files are UTF-16 little
 endian encoded without BOM and you want Git to use Windows line endings
-in the working directory. Please note, it is highly recommended to
+in the working directory (use `UTF-16-LE-BOM` instead of `UTF-16LE` if
+you want UTF-16 little endian with BOM).
+Please note, it is highly recommended to
 explicitly define the line endings with `eol` if the `working-tree-encoding`
 attribute is used to avoid ambiguity.
 
index 98b538bc779635fcf59afd1a8cb366e9e57ed7ae..cad711ce0ac060d9356e49599ffc13d130fc593c 100644 (file)
@@ -270,13 +270,13 @@ depending on a few rules:
 +
 --
 1. If the starting point is specified as `ref@{Nth}`, show the index
-format.
+   format.
 +
 2. If the starting point was specified as `ref@{now}`, show the
-timestamp format.
+   timestamp format.
 +
 3. If neither was used, but `--date` was given on the command line, show
-the timestamp in the format requested by `--date`.
+   the timestamp in the format requested by `--date`.
 +
 4. Otherwise, show the index format.
 --
@@ -730,8 +730,13 @@ specification contained in <path>.
 +
 The form '--filter=tree:<depth>' omits all blobs and trees whose depth
 from the root tree is >= <depth> (minimum depth if an object is located
-at multiple depths in the commits traversed). Currently, only <depth>=0
-is supported, which omits all blobs and trees.
+at multiple depths in the commits traversed). <depth>=0 will not include
+any trees or blobs unless included explicitly in the command-line (or
+standard input when --stdin is used). <depth>=1 will include only the
+tree and blobs which are referenced directly by a commit reachable from
+<commit> or an explicitly-given object. <depth>=2 is like <depth>=1
+while also including trees and blobs one more level removed from an
+explicitly-given commit or tree.
 
 --no-filter::
        Turn off any previous `--filter=` argument.
@@ -831,6 +836,13 @@ Note that the `-local` option does not affect the seconds-since-epoch
 value (which is always measured in UTC), but does switch the accompanying
 timezone value.
 +
+`--date=human` shows the timezone if the timezone does not match the
+current time-zone, and doesn't print the whole date if that matches
+(ie skip printing year for dates that are "this year", but also skip
+the whole date itself if it's in the last few days and we can just say
+what weekday it was).  For older dates the hour and minute is also
+omitted.
++
 `--date=unix` shows the date as a Unix epoch timestamp (seconds since
 1970).  As with `--raw`, this is always in UTC and therefore `-local`
 has no effect.
index cc0474ba3ee4b04153752340328233437d5c7b05..16452a0504c8fa5b9b1b62cb907b96315db43942 100644 (file)
@@ -76,7 +76,7 @@ CHUNK DATA:
       of the ith commit. Stores value 0x7000000 if no parent in that
       position. If there are more than two parents, the second value
       has its most-significant bit on and the other bits store an array
-      position into the Large Edge List chunk.
+      position into the Extra Edge List chunk.
     * The next 8 bytes store the generation number of the commit and
       the commit time in seconds since EPOCH. The generation number
       uses the higher 30 bits of the first 4 bytes, while the commit
@@ -84,7 +84,7 @@ CHUNK DATA:
       2 bits of the lowest byte, storing the 33rd and 34th bit of the
       commit time.
 
-  Large Edge List (ID: {'E', 'D', 'G', 'E'}) [Optional]
+  Extra Edge List (ID: {'E', 'D', 'G', 'E'}) [Optional]
       This list of 4-byte values store the second through nth parents for
       all octopus merges. The second parent value in the commit data stores
       an array position within this list along with the most-significant bit
index 6ac774d5f665614848cdaba9e4c97d86a2453913..7a2375a55d074514c5ebd851fe55ff27541c207c 100644 (file)
@@ -22,6 +22,16 @@ protocol-common.txt. When the grammar indicate `PKT-LINE(...)`, unless
 otherwise noted the usual pkt-line LF rules apply: the sender SHOULD
 include a LF, but the receiver MUST NOT complain if it is not present.
 
+An error packet is a special pkt-line that contains an error string.
+
+----
+  error-line     =  PKT-LINE("ERR" SP explanation-text)
+----
+
+Throughout the protocol, where `PKT-LINE(...)` is expected, an error packet MAY
+be sent. Once this packet is sent by a client or a server, the data transfer
+process defined in this protocol is terminated.
+
 Transports
 ----------
 There are three transports over which the packfile protocol is
@@ -89,13 +99,6 @@ process on the server side over the Git protocol is this:
      "0039git-upload-pack /schacon/gitbook.git\0host=example.com\0" |
      nc -v example.com 9418
 
-If the server refuses the request for some reasons, it could abort
-gracefully with an error message.
-
-----
-  error-line     =  PKT-LINE("ERR" SP explanation-text)
-----
-
 
 SSH Transport
 -------------
@@ -398,12 +401,11 @@ from the client).
 Then the server will start sending its packfile data.
 
 ----
-  server-response = *ack_multi ack / nak / error-line
+  server-response = *ack_multi ack / nak
   ack_multi       = PKT-LINE("ACK" SP obj-id ack_status)
   ack_status      = "continue" / "common" / "ready"
   ack             = PKT-LINE("ACK" SP obj-id)
   nak             = PKT-LINE("NAK")
-  error-line     =  PKT-LINE("ERR" SP explanation-text)
 ----
 
 A simple clone may look like this (with no 'have' lines):
index 09e4e0273fd515254b41cf2d36e3b6083de1d4ee..ead85ce35cf2342335af69221e4b4e956b9f66fd 100644 (file)
@@ -296,7 +296,13 @@ included in the client's request:
        Request that various objects from the packfile be omitted
        using one of several filtering techniques. These are intended
        for use with partial clone and partial fetch operations. See
-       `rev-list` for possible "filter-spec" values.
+       `rev-list` for possible "filter-spec" values. When communicating
+       with other processes, senders SHOULD translate scaled integers
+       (e.g. "1k") into a fully-expanded form (e.g. "1024") to aid
+       interoperability with older receivers that may not understand
+       newly-invented scaling suffixes. However, receivers SHOULD
+       accept the following suffixes: 'k', 'm', and 'g' for 1024,
+       1048576, and 1073741824, respectively.
 
 If the 'ref-in-want' feature is advertised, the following argument can
 be included in the client's request as well as the potential addition of
@@ -307,6 +313,16 @@ the 'wanted-refs' section in the server's response as explained below.
        particular ref, where <ref> is the full name of a ref on the
        server.
 
+If the 'sideband-all' feature is advertised, the following argument can be
+included in the client's request:
+
+    sideband-all
+       Instruct the server to send the whole response multiplexed, not just
+       the packfile section. All non-flush and non-delim PKT-LINE in the
+       response (not only in the packfile section) will then start with a byte
+       indicating its sideband (1, 2, or 3), and the server may send "0005\2"
+       (a PKT-LINE of sideband 2 with no payload) as a keepalive packet.
+
 The response of `fetch` is broken into a number of sections separated by
 delimiter packets (0001), with each section beginning with its section
 header.
index 6e8d017e8ed04da7a0319400cc7a3f4f9a74e711..45e6d700a73b52746e54c69c69ca7f6dcd9cb112 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -634,7 +634,6 @@ SCRIPT_LIB += git-parse-remote
 SCRIPT_LIB += git-rebase--am
 SCRIPT_LIB += git-rebase--common
 SCRIPT_LIB += git-rebase--preserve-merges
-SCRIPT_LIB += git-rebase--merge
 SCRIPT_LIB += git-sh-setup
 SCRIPT_LIB += git-sh-i18n
 
@@ -690,6 +689,7 @@ SCRIPTS = $(SCRIPT_SH_INS) \
 
 ETAGS_TARGET = TAGS
 
+FUZZ_OBJS += fuzz-commit-graph.o
 FUZZ_OBJS += fuzz-pack-headers.o
 FUZZ_OBJS += fuzz-pack-idx.o
 
@@ -763,6 +763,7 @@ TEST_BUILTINS_OBJS += test-submodule-config.o
 TEST_BUILTINS_OBJS += test-submodule-nested-repo-config.o
 TEST_BUILTINS_OBJS += test-subprocess.o
 TEST_BUILTINS_OBJS += test-urlmatch-normalization.o
+TEST_BUILTINS_OBJS += test-xml-encode.o
 TEST_BUILTINS_OBJS += test-wildmatch.o
 TEST_BUILTINS_OBJS += test-windows-named-pipe.o
 TEST_BUILTINS_OBJS += test-write-cache.o
@@ -2948,6 +2949,16 @@ rpm::
        @false
 .PHONY: rpm
 
+artifacts-tar:: $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) $(OTHER_PROGRAMS) \
+               GIT-BUILD-OPTIONS $(TEST_PROGRAMS) $(test_bindir_programs) \
+               $(NO_INSTALL) $(MOFILES)
+       $(QUIET_SUBDIR0)templates $(QUIET_SUBDIR1) \
+               SHELL_PATH='$(SHELL_PATH_SQ)' PERL_PATH='$(PERL_PATH_SQ)'
+       test -n "$(ARTIFACTS_DIRECTORY)"
+       mkdir -p "$(ARTIFACTS_DIRECTORY)"
+       $(TAR) czf "$(ARTIFACTS_DIRECTORY)/artifacts.tar.gz" $^ templates/blt/
+.PHONY: artifacts-tar
+
 htmldocs = git-htmldocs-$(GIT_VERSION)
 manpages = git-manpages-$(GIT_VERSION)
 .PHONY: dist-doc distclean
@@ -3125,7 +3136,7 @@ cover_db_html: cover_db
 # An example command to build against libFuzzer from LLVM 4.0.0:
 #
 # make CC=clang CXX=clang++ \
-#      FUZZ_CXXFLAGS="-fsanitize-coverage=trace-pc-guard -fsanitize=address" \
+#      CFLAGS="-fsanitize-coverage=trace-pc-guard -fsanitize=address" \
 #      LIB_FUZZING_ENGINE=/usr/lib/llvm-4.0/lib/libFuzzer.a \
 #      fuzz-all
 #
index f920a42fad3423b0b20639afd765b64ac2750d8a..764c480c66f9822998d6b5dc8d591155b8467c56 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,3 +1,5 @@
+[![Build Status](https://dev.azure.com/git/git/_apis/build/status/test-git.git)](https://dev.azure.com/git/git/_build/latest?definitionId=2)
+
 Git - fast, scalable, distributed revision control system
 =========================================================
 
diff --git a/alloc.c b/alloc.c
index e7aa81b7aa48c14f2a98894eb6e8c2e28998945e..1c64c4dd1629c63a8bb2fff6e580ee0c648a0730 100644 (file)
--- a/alloc.c
+++ b/alloc.c
@@ -99,18 +99,23 @@ void *alloc_object_node(struct repository *r)
        return obj;
 }
 
-unsigned int alloc_commit_index(struct repository *r)
+static unsigned int alloc_commit_index(struct repository *r)
 {
        return r->parsed_objects->commit_count++;
 }
 
-void *alloc_commit_node(struct repository *r)
+void init_commit_node(struct repository *r, struct commit *c)
 {
-       struct commit *c = alloc_node(r->parsed_objects->commit_state, sizeof(struct commit));
        c->object.type = OBJ_COMMIT;
        c->index = alloc_commit_index(r);
        c->graph_pos = COMMIT_NOT_FROM_GRAPH;
        c->generation = GENERATION_NUMBER_INFINITY;
+}
+
+void *alloc_commit_node(struct repository *r)
+{
+       struct commit *c = alloc_node(r->parsed_objects->commit_state, sizeof(struct commit));
+       init_commit_node(r, c);
        return c;
 }
 
diff --git a/alloc.h b/alloc.h
index ba356ed8478d13f05f49efd5bacccaac3e69dfd7..ed1071c11ea3a6d0f7d55da46df4acf524a32565 100644 (file)
--- a/alloc.h
+++ b/alloc.h
@@ -9,11 +9,11 @@ struct repository;
 
 void *alloc_blob_node(struct repository *r);
 void *alloc_tree_node(struct repository *r);
+void init_commit_node(struct repository *r, struct commit *c);
 void *alloc_commit_node(struct repository *r);
 void *alloc_tag_node(struct repository *r);
 void *alloc_object_node(struct repository *r);
 void alloc_report(struct repository *r);
-unsigned int alloc_commit_index(struct repository *r);
 
 struct alloc_state *allocate_alloc_state(void);
 void clear_alloc_state(struct alloc_state *s);
diff --git a/apply.c b/apply.c
index 3703bfc8d03deb3be3a3fa9a45a2dd64b0a8eafd..892ede5a318f751c80fcceab036a8cbaee391774 100644 (file)
--- a/apply.c
+++ b/apply.c
@@ -467,7 +467,6 @@ static char *squash_slash(char *name)
 
 static char *find_name_gnu(struct apply_state *state,
                           const char *line,
-                          const char *def,
                           int p_value)
 {
        struct strbuf name = STRBUF_INIT;
@@ -714,7 +713,7 @@ static char *find_name(struct apply_state *state,
                       int terminate)
 {
        if (*line == '"') {
-               char *name = find_name_gnu(state, line, def, p_value);
+               char *name = find_name_gnu(state, line, p_value);
                if (name)
                        return name;
        }
@@ -731,7 +730,7 @@ static char *find_name_traditional(struct apply_state *state,
        size_t date_len;
 
        if (*line == '"') {
-               char *name = find_name_gnu(state, line, def, p_value);
+               char *name = find_name_gnu(state, line, p_value);
                if (name)
                        return name;
        }
@@ -3183,7 +3182,7 @@ static int apply_binary(struct apply_state *state,
                return 0; /* deletion patch */
        }
 
-       if (has_sha1_file(oid.hash)) {
+       if (has_object_file(&oid)) {
                /* We already have the postimage */
                enum object_type type;
                unsigned long size;
@@ -4020,7 +4019,7 @@ static int read_apply_cache(struct apply_state *state)
                return read_index_from(state->repo->index, state->index_file,
                                       get_git_dir());
        else
-               return read_index(state->repo->index);
+               return repo_read_index(state->repo);
 }
 
 /* This function tries to read the object name from the current index */
@@ -4713,7 +4712,8 @@ static int apply_patch(struct apply_state *state,
                                                  state->index_file,
                                                  LOCK_DIE_ON_ERROR);
                else
-                       hold_locked_index(&state->lock_file, LOCK_DIE_ON_ERROR);
+                       repo_hold_locked_index(state->repo, &state->lock_file,
+                                              LOCK_DIE_ON_ERROR);
        }
 
        if (state->check_index && read_apply_cache(state) < 0) {
diff --git a/attr.c b/attr.c
index b63fe0fc0e99caa07dc2e6da816e1ac8d5942df6..fdd110bec55cb3bc5c8ebbb8cffbc33cced530b2 100644 (file)
--- a/attr.c
+++ b/attr.c
@@ -7,7 +7,6 @@
  * an insanely large number of attributes.
  */
 
-#define NO_THE_INDEX_COMPATIBILITY_MACROS
 #include "cache.h"
 #include "config.h"
 #include "exec-cmd.h"
@@ -1092,7 +1091,7 @@ static void collect_some_attrs(const struct index_state *istate,
                               const char *path,
                               struct attr_check *check)
 {
-       int i, pathlen, rem, dirlen;
+       int pathlen, rem, dirlen;
        const char *cp, *last_slash = NULL;
        int basename_offset;
 
@@ -1113,20 +1112,6 @@ static void collect_some_attrs(const struct index_state *istate,
        all_attrs_init(&g_attr_hashmap, check);
        determine_macros(check->all_attrs, check->stack);
 
-       if (check->nr) {
-               rem = 0;
-               for (i = 0; i < check->nr; i++) {
-                       int n = check->items[i].attr->attr_nr;
-                       struct all_attrs_item *item = &check->all_attrs[n];
-                       if (item->macro) {
-                               item->value = ATTR__UNSET;
-                               rem++;
-                       }
-               }
-               if (rem == check->nr)
-                       return;
-       }
-
        rem = check->all_attrs_nr;
        fill(path, pathlen, basename_offset, check->stack, check->all_attrs, rem);
 }
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
new file mode 100644 (file)
index 0000000..c329b72
--- /dev/null
@@ -0,0 +1,387 @@
+resources:
+- repo: self
+  fetchDepth: 1
+
+jobs:
+- job: windows_build
+  displayName: Windows Build
+  condition: succeeded()
+  pool: Hosted
+  timeoutInMinutes: 240
+  steps:
+  - powershell: |
+      if ("$GITFILESHAREPWD" -ne "" -and "$GITFILESHAREPWD" -ne "`$`(gitfileshare.pwd)") {
+        net use s: \\gitfileshare.file.core.windows.net\test-cache "$GITFILESHAREPWD" /user:AZURE\gitfileshare /persistent:no
+        cmd /c mklink /d "$(Build.SourcesDirectory)\test-cache" S:\
+      }
+    displayName: 'Mount test-cache'
+    env:
+      GITFILESHAREPWD: $(gitfileshare.pwd)
+  - powershell: |
+      $urlbase = "https://dev.azure.com/git-for-windows/git/_apis/build/builds"
+      $id = ((Invoke-WebRequest -UseBasicParsing "${urlbase}?definitions=22&statusFilter=completed&resultFilter=succeeded&`$top=1").content | ConvertFrom-JSON).value[0].id
+      $downloadUrl = ((Invoke-WebRequest -UseBasicParsing "${urlbase}/$id/artifacts").content | ConvertFrom-JSON).value[1].resource.downloadUrl
+      (New-Object Net.WebClient).DownloadFile($downloadUrl,"git-sdk-64-minimal.zip")
+      Expand-Archive git-sdk-64-minimal.zip -DestinationPath . -Force
+      Remove-Item git-sdk-64-minimal.zip
+
+      # Let Git ignore the SDK and the test-cache
+      "/git-sdk-64-minimal/`n/test-cache/`n" | Out-File -NoNewLine -Encoding ascii -Append "$(Build.SourcesDirectory)\.git\info\exclude"
+    displayName: 'Download git-sdk-64-minimal'
+  - powershell: |
+      & git-sdk-64-minimal\usr\bin\bash.exe -lc @"
+        ci/make-test-artifacts.sh artifacts
+      "@
+      if (!$?) { exit(1) }
+    displayName: Build
+    env:
+      HOME: $(Build.SourcesDirectory)
+      MSYSTEM: MINGW64
+      DEVELOPER: 1
+      NO_PERL: 1
+  - task: PublishPipelineArtifact@0
+    displayName: 'Publish Pipeline Artifact: test artifacts'
+    inputs:
+      artifactName: 'windows-artifacts'
+      targetPath: '$(Build.SourcesDirectory)\artifacts'
+  - task: PublishPipelineArtifact@0
+    displayName: 'Publish Pipeline Artifact: git-sdk-64-minimal'
+    inputs:
+      artifactName: 'git-sdk-64-minimal'
+      targetPath: '$(Build.SourcesDirectory)\git-sdk-64-minimal'
+  - powershell: |
+      if ("$GITFILESHAREPWD" -ne "" -and "$GITFILESHAREPWD" -ne "`$`(gitfileshare.pwd)") {
+        cmd /c rmdir "$(Build.SourcesDirectory)\test-cache"
+      }
+    displayName: 'Unmount test-cache'
+    condition: true
+    env:
+      GITFILESHAREPWD: $(gitfileshare.pwd)
+
+- job: windows_test
+  displayName: Windows Test
+  dependsOn: windows_build
+  condition: succeeded()
+  pool: Hosted
+  timeoutInMinutes: 240
+  strategy:
+    parallel: 10
+  steps:
+  - powershell: |
+      if ("$GITFILESHAREPWD" -ne "" -and "$GITFILESHAREPWD" -ne "`$`(gitfileshare.pwd)") {
+        net use s: \\gitfileshare.file.core.windows.net\test-cache "$GITFILESHAREPWD" /user:AZURE\gitfileshare /persistent:no
+        cmd /c mklink /d "$(Build.SourcesDirectory)\test-cache" S:\
+      }
+    displayName: 'Mount test-cache'
+    env:
+      GITFILESHAREPWD: $(gitfileshare.pwd)
+  - task: DownloadPipelineArtifact@0
+    displayName: 'Download Pipeline Artifact: test artifacts'
+    inputs:
+      artifactName: 'windows-artifacts'
+      targetPath: '$(Build.SourcesDirectory)'
+  - task: DownloadPipelineArtifact@0
+    displayName: 'Download Pipeline Artifact: git-sdk-64-minimal'
+    inputs:
+      artifactName: 'git-sdk-64-minimal'
+      targetPath: '$(Build.SourcesDirectory)\git-sdk-64-minimal'
+  - powershell: |
+      & git-sdk-64-minimal\usr\bin\bash.exe -lc @"
+        test -f artifacts.tar.gz || {
+          echo No test artifacts found\; skipping >&2
+          exit 0
+        }
+        tar xf artifacts.tar.gz || exit 1
+
+        # Let Git ignore the SDK and the test-cache
+        printf '%s\n' /git-sdk-64-minimal/ /test-cache/ >>.git/info/exclude
+
+        ci/run-test-slice.sh `$SYSTEM_JOBPOSITIONINPHASE `$SYSTEM_TOTALJOBSINPHASE || {
+          ci/print-test-failures.sh
+          exit 1
+        }
+      "@
+      if (!$?) { exit(1) }
+    displayName: 'Test (parallel)'
+    env:
+      HOME: $(Build.SourcesDirectory)
+      MSYSTEM: MINGW64
+      NO_SVN_TESTS: 1
+      GIT_TEST_SKIP_REBASE_P: 1
+  - powershell: |
+      if ("$GITFILESHAREPWD" -ne "" -and "$GITFILESHAREPWD" -ne "`$`(gitfileshare.pwd)") {
+        cmd /c rmdir "$(Build.SourcesDirectory)\test-cache"
+      }
+    displayName: 'Unmount test-cache'
+    condition: true
+    env:
+      GITFILESHAREPWD: $(gitfileshare.pwd)
+  - task: PublishTestResults@2
+    displayName: 'Publish Test Results **/TEST-*.xml'
+    inputs:
+      mergeTestResults: true
+      testRunTitle: 'windows'
+      platform: Windows
+      publishRunAttachments: false
+    condition: succeededOrFailed()
+  - task: PublishBuildArtifacts@1
+    displayName: 'Publish trash directories of failed tests'
+    condition: failed()
+    inputs:
+      PathtoPublish: t/failed-test-artifacts
+      ArtifactName: failed-test-artifacts
+
+- job: linux_clang
+  displayName: linux-clang
+  condition: succeeded()
+  pool: Hosted Ubuntu 1604
+  steps:
+  - bash: |
+       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
+
+       sudo apt-get update &&
+       sudo apt-get -y install git gcc make libssl-dev libcurl4-openssl-dev libexpat-dev tcl tk gettext git-email zlib1g-dev apache2-bin &&
+
+       export CC=clang || exit 1
+
+       ci/install-dependencies.sh || exit 1
+       ci/run-build-and-tests.sh || {
+           ci/print-test-failures.sh
+           exit 1
+       }
+
+       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || sudo umount "$HOME/test-cache" || exit 1
+    displayName: 'ci/run-build-and-tests.sh'
+    env:
+      GITFILESHAREPWD: $(gitfileshare.pwd)
+  - task: PublishTestResults@2
+    displayName: 'Publish Test Results **/TEST-*.xml'
+    inputs:
+      mergeTestResults: true
+      testRunTitle: 'linux-clang'
+      platform: Linux
+      publishRunAttachments: false
+    condition: succeededOrFailed()
+  - task: PublishBuildArtifacts@1
+    displayName: 'Publish trash directories of failed tests'
+    condition: failed()
+    inputs:
+      PathtoPublish: t/failed-test-artifacts
+      ArtifactName: failed-test-artifacts
+
+- job: linux_gcc
+  displayName: linux-gcc
+  condition: succeeded()
+  pool: Hosted Ubuntu 1604
+  steps:
+  - bash: |
+       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
+
+       sudo add-apt-repository ppa:ubuntu-toolchain-r/test &&
+       sudo apt-get update &&
+       sudo apt-get -y install git gcc make libssl-dev libcurl4-openssl-dev libexpat-dev tcl tk gettext git-email zlib1g-dev apache2 language-pack-is git-svn gcc-8 || exit 1
+
+       ci/install-dependencies.sh || exit 1
+       ci/run-build-and-tests.sh || {
+           ci/print-test-failures.sh
+           exit 1
+       }
+
+       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || sudo umount "$HOME/test-cache" || exit 1
+    displayName: 'ci/run-build-and-tests.sh'
+    env:
+      GITFILESHAREPWD: $(gitfileshare.pwd)
+  - task: PublishTestResults@2
+    displayName: 'Publish Test Results **/TEST-*.xml'
+    inputs:
+      mergeTestResults: true
+      testRunTitle: 'linux-gcc'
+      platform: Linux
+      publishRunAttachments: false
+    condition: succeededOrFailed()
+  - task: PublishBuildArtifacts@1
+    displayName: 'Publish trash directories of failed tests'
+    condition: failed()
+    inputs:
+      PathtoPublish: t/failed-test-artifacts
+      ArtifactName: failed-test-artifacts
+
+- job: osx_clang
+  displayName: osx-clang
+  condition: succeeded()
+  pool: Hosted macOS
+  steps:
+  - bash: |
+       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
+
+       export CC=clang
+
+       ci/install-dependencies.sh || exit 1
+       ci/run-build-and-tests.sh || {
+           ci/print-test-failures.sh
+           exit 1
+       }
+
+       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || umount "$HOME/test-cache" || exit 1
+    displayName: 'ci/run-build-and-tests.sh'
+    env:
+      GITFILESHAREPWD: $(gitfileshare.pwd)
+  - task: PublishTestResults@2
+    displayName: 'Publish Test Results **/TEST-*.xml'
+    inputs:
+      mergeTestResults: true
+      testRunTitle: 'osx-clang'
+      platform: macOS
+      publishRunAttachments: false
+    condition: succeededOrFailed()
+  - task: PublishBuildArtifacts@1
+    displayName: 'Publish trash directories of failed tests'
+    condition: failed()
+    inputs:
+      PathtoPublish: t/failed-test-artifacts
+      ArtifactName: failed-test-artifacts
+
+- job: osx_gcc
+  displayName: osx-gcc
+  condition: succeeded()
+  pool: Hosted macOS
+  steps:
+  - bash: |
+       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
+
+       ci/install-dependencies.sh || exit 1
+       ci/run-build-and-tests.sh || {
+           ci/print-test-failures.sh
+           exit 1
+       }
+
+       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || umount "$HOME/test-cache" || exit 1
+    displayName: 'ci/run-build-and-tests.sh'
+    env:
+      GITFILESHAREPWD: $(gitfileshare.pwd)
+  - task: PublishTestResults@2
+    displayName: 'Publish Test Results **/TEST-*.xml'
+    inputs:
+      mergeTestResults: true
+      testRunTitle: 'osx-gcc'
+      platform: macOS
+      publishRunAttachments: false
+    condition: succeededOrFailed()
+  - task: PublishBuildArtifacts@1
+    displayName: 'Publish trash directories of failed tests'
+    condition: failed()
+    inputs:
+      PathtoPublish: t/failed-test-artifacts
+      ArtifactName: failed-test-artifacts
+
+- job: gettext_poison
+  displayName: GETTEXT_POISON
+  condition: succeeded()
+  pool: Hosted Ubuntu 1604
+  steps:
+  - bash: |
+       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
+
+       sudo apt-get update &&
+       sudo apt-get -y install git gcc make libssl-dev libcurl4-openssl-dev libexpat-dev tcl tk gettext git-email zlib1g-dev &&
+
+       export jobname=GETTEXT_POISON || exit 1
+
+       ci/run-build-and-tests.sh || {
+           ci/print-test-failures.sh
+           exit 1
+       }
+
+       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || sudo umount "$HOME/test-cache" || exit 1
+    displayName: 'ci/run-build-and-tests.sh'
+    env:
+      GITFILESHAREPWD: $(gitfileshare.pwd)
+  - task: PublishTestResults@2
+    displayName: 'Publish Test Results **/TEST-*.xml'
+    inputs:
+      mergeTestResults: true
+      testRunTitle: 'gettext-poison'
+      platform: Linux
+      publishRunAttachments: false
+    condition: succeededOrFailed()
+  - task: PublishBuildArtifacts@1
+    displayName: 'Publish trash directories of failed tests'
+    condition: failed()
+    inputs:
+      PathtoPublish: t/failed-test-artifacts
+      ArtifactName: failed-test-artifacts
+
+- job: linux32
+  displayName: Linux32
+  condition: succeeded()
+  pool: Hosted Ubuntu 1604
+  steps:
+  - bash: |
+       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
+
+       res=0
+       sudo AGENT_OS="$AGENT_OS" BUILD_BUILDNUMBER="$BUILD_BUILDNUMBER" BUILD_REPOSITORY_URI="$BUILD_REPOSITORY_URI" BUILD_SOURCEBRANCH="$BUILD_SOURCEBRANCH" BUILD_SOURCEVERSION="$BUILD_SOURCEVERSION" SYSTEM_PHASENAME="$SYSTEM_PHASENAME" SYSTEM_TASKDEFINITIONSURI="$SYSTEM_TASKDEFINITIONSURI" SYSTEM_TEAMPROJECT="$SYSTEM_TEAMPROJECT" CC=$CC MAKEFLAGS="$MAKEFLAGS" bash -lxc ci/run-linux32-docker.sh || res=1
+
+       sudo chmod a+r t/out/TEST-*.xml
+       test ! -d t/failed-test-artifacts || sudo chmod a+r t/failed-test-artifacts
+
+       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || sudo umount "$HOME/test-cache" || res=1
+       exit $res
+    displayName: 'ci/run-linux32-docker.sh'
+    env:
+      GITFILESHAREPWD: $(gitfileshare.pwd)
+  - task: PublishTestResults@2
+    displayName: 'Publish Test Results **/TEST-*.xml'
+    inputs:
+      mergeTestResults: true
+      testRunTitle: 'linux32'
+      platform: Linux
+      publishRunAttachments: false
+    condition: succeededOrFailed()
+  - task: PublishBuildArtifacts@1
+    displayName: 'Publish trash directories of failed tests'
+    condition: failed()
+    inputs:
+      PathtoPublish: t/failed-test-artifacts
+      ArtifactName: failed-test-artifacts
+
+- job: static_analysis
+  displayName: StaticAnalysis
+  condition: succeeded()
+  pool: Hosted Ubuntu 1604
+  steps:
+  - bash: |
+       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
+
+       sudo apt-get update &&
+       sudo apt-get install -y coccinelle &&
+
+       export jobname=StaticAnalysis &&
+
+       ci/run-static-analysis.sh || exit 1
+
+       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || sudo umount "$HOME/test-cache" || exit 1
+    displayName: 'ci/run-static-analysis.sh'
+    env:
+      GITFILESHAREPWD: $(gitfileshare.pwd)
+
+- job: documentation
+  displayName: Documentation
+  condition: succeeded()
+  pool: Hosted Ubuntu 1604
+  steps:
+  - bash: |
+       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
+
+       sudo apt-get update &&
+       sudo apt-get install -y asciidoc xmlto asciidoctor &&
+
+       export ALREADY_HAVE_ASCIIDOCTOR=yes. &&
+       export jobname=Documentation &&
+
+       ci/test-documentation.sh || exit 1
+
+       test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || sudo umount "$HOME/test-cache" || exit 1
+    displayName: 'ci/test-documentation.sh'
+    env:
+      GITFILESHAREPWD: $(gitfileshare.pwd)
index 6bf521138a590496a7b3fa7c2515ac53f815a1e3..3af955c4bc4e1c7cd155a5f2e460cee38af732cd 100644 (file)
--- a/bisect.c
+++ b/bisect.c
@@ -658,7 +658,7 @@ static void bisect_common(struct rev_info *revs)
        if (prepare_revision_walk(revs))
                die("revision walk setup failed");
        if (revs->tree_objects)
-               mark_edges_uninteresting(revs, NULL);
+               mark_edges_uninteresting(revs, NULL, 0);
 }
 
 static void exit_if_skipped_commits(struct commit_list *tried,
diff --git a/blame.c b/blame.c
index 43861437f749849e85d448eba692b42488ec459d..da57233cbbd98d41bdfeba46e861b1f5f61dfbe2 100644 (file)
--- a/blame.c
+++ b/blame.c
@@ -188,7 +188,7 @@ static struct commit *fake_working_tree_commit(struct repository *r,
        unsigned mode;
        struct strbuf msg = STRBUF_INIT;
 
-       read_index(r->index);
+       repo_read_index(r);
        time(&now);
        commit = alloc_commit_node(r);
        commit->object.parsed = 1;
@@ -270,7 +270,7 @@ static struct commit *fake_working_tree_commit(struct repository *r,
         * want to run "diff-index --cached".
         */
        discard_index(r->index);
-       read_index(r->index);
+       repo_read_index(r);
 
        len = strlen(path);
        if (!mode) {
index d461ba08b9b2663b4cadd9a1cb756523ffe8eb1f..db2dfa43502d0059219189f01731e143982345ab 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 2006 Linus Torvalds
  */
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "cache.h"
 #include "config.h"
 #include "builtin.h"
@@ -137,7 +138,7 @@ static int renormalize_tracked_files(const struct pathspec *pathspec, int flags)
                        continue; /* do not touch non blobs */
                if (pathspec && !ce_path_match(&the_index, ce, pathspec, NULL))
                        continue;
-               retval |= add_file_to_cache(ce->name, flags | HASH_RENORMALIZE);
+               retval |= add_file_to_cache(ce->name, flags | ADD_CACHE_RENORMALIZE);
        }
 
        return retval;
index 95370313b66daad8cabcc3b855136e29afb3133f..58a2aef28bbcd715660422dc37042e79d4d350c1 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Based on git-am.sh by Junio C Hamano.
  */
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "cache.h"
 #include "config.h"
 #include "builtin.h"
 #include "packfile.h"
 #include "repository.h"
 
-/**
- * Returns 1 if the file is empty or does not exist, 0 otherwise.
- */
-static int is_empty_file(const char *filename)
-{
-       struct stat st;
-
-       if (stat(filename, &st) < 0) {
-               if (errno == ENOENT)
-                       return 1;
-               die_errno(_("could not stat %s"), filename);
-       }
-
-       return !st.st_size;
-}
-
 /**
  * Returns the length of the first line of msg.
  */
@@ -527,7 +512,7 @@ static int copy_notes_for_rebase(const struct am_state *state)
        }
 
 finish:
-       finish_copy_notes_for_rewrite(c, msg);
+       finish_copy_notes_for_rewrite(the_repository, c, msg);
        fclose(fp);
        strbuf_release(&sb);
        return ret;
@@ -1220,7 +1205,7 @@ static int parse_mail(struct am_state *state, const char *mail)
                goto finish;
        }
 
-       if (is_empty_file(am_path(state, "patch"))) {
+       if (is_empty_or_missing_file(am_path(state, "patch"))) {
                printf_ln(_("Patch is empty."));
                die_user_resolve(state);
        }
@@ -1545,7 +1530,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
         * changes.
         */
 
-       init_merge_options(&o);
+       init_merge_options(&o, the_repository);
 
        o.branch1 = "HEAD";
        their_tree_name = xstrfmt("%.*s", linelen(state->msg), state->msg);
@@ -1719,7 +1704,7 @@ static void am_run(struct am_state *state, int resume)
 
        refresh_and_write_cache();
 
-       if (index_has_changes(&the_index, NULL, &sb)) {
+       if (repo_index_has_changes(the_repository, NULL, &sb)) {
                write_state_bool(state, "dirtyindex", 1);
                die(_("Dirty index: cannot apply patches (dirty: %s)"), sb.buf);
        }
@@ -1777,7 +1762,7 @@ static void am_run(struct am_state *state, int resume)
                         * the result may have produced the same tree as ours.
                         */
                        if (!apply_status &&
-                           !index_has_changes(&the_index, NULL, NULL)) {
+                           !repo_index_has_changes(the_repository, NULL, NULL)) {
                                say(state, stdout, _("No changes -- Patch already applied."));
                                goto next;
                        }
@@ -1803,7 +1788,7 @@ static void am_run(struct am_state *state, int resume)
                resume = 0;
        }
 
-       if (!is_empty_file(am_path(state, "rewritten"))) {
+       if (!is_empty_or_missing_file(am_path(state, "rewritten"))) {
                assert(state->rebasing);
                copy_notes_for_rebase(state);
                run_post_rewrite_hook(state);
@@ -1831,7 +1816,7 @@ static void am_resolve(struct am_state *state)
 
        say(state, stdout, _("Applying: %.*s"), linelen(state->msg), state->msg);
 
-       if (!index_has_changes(&the_index, NULL, NULL)) {
+       if (!repo_index_has_changes(the_repository, NULL, NULL)) {
                printf_ln(_("No changes - did you forget to use 'git add'?\n"
                        "If there is nothing left to stage, chances are that something else\n"
                        "already introduced the same changes; you might want to skip this patch."));
@@ -2000,6 +1985,15 @@ static void am_skip(struct am_state *state)
        if (clean_index(&head, &head))
                die(_("failed to clean index"));
 
+       if (state->rebasing) {
+               FILE *fp = xfopen(am_path(state, "rewritten"), "a");
+
+               assert(!is_null_oid(&state->orig_commit));
+               fprintf(fp, "%s ", oid_to_hex(&state->orig_commit));
+               fprintf(fp, "%s\n", oid_to_hex(&head));
+               fclose(fp);
+       }
+
        am_next(state);
        am_load(state);
        am_run(state, 0);
@@ -2278,7 +2272,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
        /* Ensure a valid committer ident can be constructed */
        git_committer_info(IDENT_STRICT);
 
-       if (read_index_preload(&the_index, NULL, 0) < 0)
+       if (repo_read_index_preload(the_repository, NULL, 0) < 0)
                die(_("failed to read the index"));
 
        if (in_progress) {
index d2455237ce04d68de624ed60157dc90a4ee4e477..45d11669aae459caf95bb6b4737558297debae89 100644 (file)
@@ -27,10 +27,10 @@ static int run_remote_archiver(int argc, const char **argv,
                               const char *remote, const char *exec,
                               const char *name_hint)
 {
-       char *buf;
        int fd[2], i, rv;
        struct transport *transport;
        struct remote *_remote;
+       struct packet_reader reader;
 
        _remote = remote_get(remote);
        if (!_remote->url[0])
@@ -53,18 +53,19 @@ static int run_remote_archiver(int argc, const char **argv,
                packet_write_fmt(fd[1], "argument %s\n", argv[i]);
        packet_flush(fd[1]);
 
-       buf = packet_read_line(fd[0], NULL);
-       if (!buf)
+       packet_reader_init(&reader, fd[0], NULL, 0,
+                          PACKET_READ_CHOMP_NEWLINE |
+                          PACKET_READ_DIE_ON_ERR_PACKET);
+
+       if (packet_reader_read(&reader) != PACKET_READ_NORMAL)
                die(_("git archive: expected ACK/NAK, got a flush packet"));
-       if (strcmp(buf, "ACK")) {
-               if (starts_with(buf, "NACK "))
-                       die(_("git archive: NACK %s"), buf + 5);
-               if (starts_with(buf, "ERR "))
-                       die(_("remote error: %s"), buf + 4);
+       if (strcmp(reader.line, "ACK")) {
+               if (starts_with(reader.line, "NACK "))
+                       die(_("git archive: NACK %s"), reader.line + 5);
                die(_("git archive: protocol error"));
        }
 
-       if (packet_read_line(fd[0], NULL))
+       if (packet_reader_read(&reader) != PACKET_READ_FLUSH)
                die(_("git archive: expected a flush"));
 
        /* Now, start reading from fd[0] and spit it out to stdout */
index 417d141c09ad2698c17cf4738ad6ce7177456088..c1cff3266114323f466133b98050f5aec71c5f91 100644 (file)
@@ -3,18 +3,58 @@
 #include "parse-options.h"
 #include "bisect.h"
 #include "refs.h"
+#include "dir.h"
+#include "argv-array.h"
+#include "run-command.h"
+#include "prompt.h"
+#include "quote.h"
 
 static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS")
 static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
 static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, "BISECT_ANCESTORS_OK")
+static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
+static GIT_PATH_FUNC(git_path_bisect_head, "BISECT_HEAD")
+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 const char * const git_bisect_helper_usage[] = {
        N_("git bisect--helper --next-all [--no-checkout]"),
        N_("git bisect--helper --write-terms <bad_term> <good_term>"),
        N_("git bisect--helper --bisect-clean-state"),
+       N_("git bisect--helper --bisect-reset [<commit>]"),
+       N_("git bisect--helper --bisect-write [--no-log] <state> <revision> <good_term> <bad_term>"),
+       N_("git bisect--helper --bisect-check-and-set-terms <command> <good_term> <bad_term>"),
+       N_("git bisect--helper --bisect-next-check <good_term> <bad_term> [<term>]"),
+       N_("git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]"),
+       N_("git bisect--helper --bisect-start [--term-{old,good}=<term> --term-{new,bad}=<term>]"
+                                            "[--no-checkout] [<bad> [<good>...]] [--] [<paths>...]"),
        NULL
 };
 
+struct bisect_terms {
+       char *term_good;
+       char *term_bad;
+};
+
+static void free_terms(struct bisect_terms *terms)
+{
+       FREE_AND_NULL(terms->term_good);
+       FREE_AND_NULL(terms->term_bad);
+}
+
+static void set_terms(struct bisect_terms *terms, const char *bad,
+                     const char *good)
+{
+       free((void *)terms->term_good);
+       terms->term_good = xstrdup(good);
+       free((void *)terms->term_bad);
+       terms->term_bad = xstrdup(bad);
+}
+
+static const char *vocab_bad = "bad|new";
+static const char *vocab_good = "good|old";
+
 /*
  * Check whether the string `term` belongs to the set of strings
  * included in the variable arguments.
@@ -106,15 +146,482 @@ static void check_expected_revs(const char **revs, int rev_nr)
        }
 }
 
+static int bisect_reset(const char *commit)
+{
+       struct strbuf branch = STRBUF_INIT;
+
+       if (!commit) {
+               if (strbuf_read_file(&branch, git_path_bisect_start(), 0) < 1) {
+                       printf(_("We are not bisecting.\n"));
+                       return 0;
+               }
+               strbuf_rtrim(&branch);
+       } else {
+               struct object_id oid;
+
+               if (get_oid_commit(commit, &oid))
+                       return error(_("'%s' is not a valid commit"), commit);
+               strbuf_addstr(&branch, commit);
+       }
+
+       if (!file_exists(git_path_bisect_head())) {
+               struct argv_array argv = ARGV_ARRAY_INIT;
+
+               argv_array_pushl(&argv, "checkout", branch.buf, "--", NULL);
+               if (run_command_v_opt(argv.argv, RUN_GIT_CMD)) {
+                       strbuf_release(&branch);
+                       argv_array_clear(&argv);
+                       return error(_("could not check out original"
+                                      " HEAD '%s'. Try 'git bisect"
+                                      "reset <commit>'."), branch.buf);
+               }
+               argv_array_clear(&argv);
+       }
+
+       strbuf_release(&branch);
+       return bisect_clean_state();
+}
+
+static void log_commit(FILE *fp, char *fmt, const char *state,
+                      struct commit *commit)
+{
+       struct pretty_print_context pp = {0};
+       struct strbuf commit_msg = STRBUF_INIT;
+       char *label = xstrfmt(fmt, state);
+
+       format_commit_message(commit, "%s", &commit_msg, &pp);
+
+       fprintf(fp, "# %s: [%s] %s\n", label, oid_to_hex(&commit->object.oid),
+               commit_msg.buf);
+
+       strbuf_release(&commit_msg);
+       free(label);
+}
+
+static int bisect_write(const char *state, const char *rev,
+                       const struct bisect_terms *terms, int nolog)
+{
+       struct strbuf tag = STRBUF_INIT;
+       struct object_id oid;
+       struct commit *commit;
+       FILE *fp = NULL;
+       int retval = 0;
+
+       if (!strcmp(state, terms->term_bad)) {
+               strbuf_addf(&tag, "refs/bisect/%s", state);
+       } else if (one_of(state, terms->term_good, "skip", NULL)) {
+               strbuf_addf(&tag, "refs/bisect/%s-%s", state, rev);
+       } else {
+               retval = error(_("Bad bisect_write argument: %s"), state);
+               goto finish;
+       }
+
+       if (get_oid(rev, &oid)) {
+               retval = error(_("couldn't get the oid of the rev '%s'"), rev);
+               goto finish;
+       }
+
+       if (update_ref(NULL, tag.buf, &oid, NULL, 0,
+                      UPDATE_REFS_MSG_ON_ERR)) {
+               retval = -1;
+               goto finish;
+       }
+
+       fp = fopen(git_path_bisect_log(), "a");
+       if (!fp) {
+               retval = error_errno(_("couldn't open the file '%s'"), git_path_bisect_log());
+               goto finish;
+       }
+
+       commit = lookup_commit_reference(the_repository, &oid);
+       log_commit(fp, "%s", state, commit);
+
+       if (!nolog)
+               fprintf(fp, "git bisect %s %s\n", state, rev);
+
+finish:
+       if (fp)
+               fclose(fp);
+       strbuf_release(&tag);
+       return retval;
+}
+
+static int check_and_set_terms(struct bisect_terms *terms, const char *cmd)
+{
+       int has_term_file = !is_empty_or_missing_file(git_path_bisect_terms());
+
+       if (one_of(cmd, "skip", "start", "terms", NULL))
+               return 0;
+
+       if (has_term_file && strcmp(cmd, terms->term_bad) &&
+           strcmp(cmd, terms->term_good))
+               return error(_("Invalid command: you're currently in a "
+                               "%s/%s bisect"), terms->term_bad,
+                               terms->term_good);
+
+       if (!has_term_file) {
+               if (one_of(cmd, "bad", "good", NULL)) {
+                       set_terms(terms, "bad", "good");
+                       return write_terms(terms->term_bad, terms->term_good);
+               }
+               if (one_of(cmd, "new", "old", NULL)) {
+                       set_terms(terms, "new", "old");
+                       return write_terms(terms->term_bad, terms->term_good);
+               }
+       }
+
+       return 0;
+}
+
+static int mark_good(const char *refname, const struct object_id *oid,
+                    int flag, void *cb_data)
+{
+       int *m_good = (int *)cb_data;
+       *m_good = 0;
+       return 1;
+}
+
+static const char *need_bad_and_good_revision_warning =
+       N_("You need to give me at least one %s and %s revision.\n"
+          "You can use \"git bisect %s\" and \"git bisect %s\" for that.");
+
+static const char *need_bisect_start_warning =
+       N_("You need to start by \"git bisect start\".\n"
+          "You then need to give me at least one %s and %s revision.\n"
+          "You can use \"git bisect %s\" and \"git bisect %s\" for that.");
+
+static int bisect_next_check(const struct bisect_terms *terms,
+                            const char *current_term)
+{
+       int missing_good = 1, missing_bad = 1, retval = 0;
+       const char *bad_ref = xstrfmt("refs/bisect/%s", terms->term_bad);
+       const char *good_glob = xstrfmt("%s-*", terms->term_good);
+
+       if (ref_exists(bad_ref))
+               missing_bad = 0;
+
+       for_each_glob_ref_in(mark_good, good_glob, "refs/bisect/",
+                            (void *) &missing_good);
+
+       if (!missing_good && !missing_bad)
+               goto finish;
+
+       if (!current_term) {
+               retval = -1;
+               goto finish;
+       }
+
+       if (missing_good && !missing_bad &&
+           !strcmp(current_term, terms->term_good)) {
+               char *yesno;
+               /*
+                * have bad (or new) but not good (or old). We could bisect
+                * although this is less optimum.
+                */
+               warning(_("bisecting only with a %s commit"), terms->term_bad);
+               if (!isatty(0))
+                       goto finish;
+               /*
+                * TRANSLATORS: Make sure to include [Y] and [n] in your
+                * translation. The program will only accept English input
+                * at this point.
+                */
+               yesno = git_prompt(_("Are you sure [Y/n]? "), PROMPT_ECHO);
+               if (starts_with(yesno, "N") || starts_with(yesno, "n"))
+                       retval = -1;
+               goto finish;
+       }
+       if (!is_empty_or_missing_file(git_path_bisect_start())) {
+               retval = error(_(need_bad_and_good_revision_warning),
+                              vocab_bad, vocab_good, vocab_bad, vocab_good);
+       } else {
+               retval = error(_(need_bisect_start_warning),
+                              vocab_good, vocab_bad, vocab_good, vocab_bad);
+       }
+
+finish:
+       free((void *) good_glob);
+       free((void *) bad_ref);
+       return retval;
+}
+
+static int get_terms(struct bisect_terms *terms)
+{
+       struct strbuf str = STRBUF_INIT;
+       FILE *fp = NULL;
+       int res = 0;
+
+       fp = fopen(git_path_bisect_terms(), "r");
+       if (!fp) {
+               res = -1;
+               goto finish;
+       }
+
+       free_terms(terms);
+       strbuf_getline_lf(&str, fp);
+       terms->term_bad = strbuf_detach(&str, NULL);
+       strbuf_getline_lf(&str, fp);
+       terms->term_good = strbuf_detach(&str, NULL);
+
+finish:
+       if (fp)
+               fclose(fp);
+       strbuf_release(&str);
+       return res;
+}
+
+static int bisect_terms(struct bisect_terms *terms, const char *option)
+{
+       if (get_terms(terms))
+               return error(_("no terms defined"));
+
+       if (option == NULL) {
+               printf(_("Your current terms are %s for the old state\n"
+                        "and %s for the new state.\n"),
+                      terms->term_good, terms->term_bad);
+               return 0;
+       }
+       if (one_of(option, "--term-good", "--term-old", NULL))
+               printf("%s\n", terms->term_good);
+       else if (one_of(option, "--term-bad", "--term-new", NULL))
+               printf("%s\n", terms->term_bad);
+       else
+               return error(_("invalid argument %s for 'git bisect terms'.\n"
+                              "Supported options are: "
+                              "--term-good|--term-old and "
+                              "--term-bad|--term-new."), option);
+
+       return 0;
+}
+
+static int bisect_append_log_quoted(const char **argv)
+{
+       int retval = 0;
+       FILE *fp = fopen(git_path_bisect_log(), "a");
+       struct strbuf orig_args = STRBUF_INIT;
+
+       if (!fp)
+               return -1;
+
+       if (fprintf(fp, "git bisect start") < 1) {
+               retval = -1;
+               goto finish;
+       }
+
+       sq_quote_argv(&orig_args, argv);
+       if (fprintf(fp, "%s\n", orig_args.buf) < 1)
+               retval = -1;
+
+finish:
+       fclose(fp);
+       strbuf_release(&orig_args);
+       return retval;
+}
+
+static int bisect_start(struct bisect_terms *terms, int no_checkout,
+                       const char **argv, int argc)
+{
+       int i, has_double_dash = 0, must_write_terms = 0, bad_seen = 0;
+       int flags, pathspec_pos, retval = 0;
+       struct string_list revs = STRING_LIST_INIT_DUP;
+       struct string_list states = STRING_LIST_INIT_DUP;
+       struct strbuf start_head = STRBUF_INIT;
+       struct strbuf bisect_names = STRBUF_INIT;
+       struct object_id head_oid;
+       struct object_id oid;
+       const char *head;
+
+       if (is_bare_repository())
+               no_checkout = 1;
+
+       /*
+        * Check for one bad and then some good revisions
+        */
+       for (i = 0; i < argc; i++) {
+               if (!strcmp(argv[i], "--")) {
+                       has_double_dash = 1;
+                       break;
+               }
+       }
+
+       for (i = 0; i < argc; i++) {
+               const char *arg = argv[i];
+               if (!strcmp(argv[i], "--")) {
+                       break;
+               } else if (!strcmp(arg, "--no-checkout")) {
+                       no_checkout = 1;
+               } else if (!strcmp(arg, "--term-good") ||
+                        !strcmp(arg, "--term-old")) {
+                       must_write_terms = 1;
+                       free((void *) terms->term_good);
+                       terms->term_good = xstrdup(argv[++i]);
+               } else if (skip_prefix(arg, "--term-good=", &arg) ||
+                          skip_prefix(arg, "--term-old=", &arg)) {
+                       must_write_terms = 1;
+                       free((void *) terms->term_good);
+                       terms->term_good = xstrdup(arg);
+               } else if (!strcmp(arg, "--term-bad") ||
+                        !strcmp(arg, "--term-new")) {
+                       must_write_terms = 1;
+                       free((void *) terms->term_bad);
+                       terms->term_bad = xstrdup(argv[++i]);
+               } else if (skip_prefix(arg, "--term-bad=", &arg) ||
+                          skip_prefix(arg, "--term-new=", &arg)) {
+                       must_write_terms = 1;
+                       free((void *) terms->term_bad);
+                       terms->term_bad = xstrdup(arg);
+               } else if (starts_with(arg, "--") &&
+                        !one_of(arg, "--term-good", "--term-bad", NULL)) {
+                       return error(_("unrecognized option: '%s'"), arg);
+               } else {
+                       char *commit_id = xstrfmt("%s^{commit}", arg);
+                       if (get_oid(commit_id, &oid) && has_double_dash)
+                               die(_("'%s' does not appear to be a valid "
+                                     "revision"), arg);
+
+                       string_list_append(&revs, oid_to_hex(&oid));
+                       free(commit_id);
+               }
+       }
+       pathspec_pos = i;
+
+       /*
+        * The user ran "git bisect start <sha1> <sha1>", hence did not
+        * explicitly specify the terms, but we are already starting to
+        * set references named with the default terms, and won't be able
+        * to change afterwards.
+        */
+       if (revs.nr)
+               must_write_terms = 1;
+       for (i = 0; i < revs.nr; i++) {
+               if (bad_seen) {
+                       string_list_append(&states, terms->term_good);
+               } else {
+                       bad_seen = 1;
+                       string_list_append(&states, terms->term_bad);
+               }
+       }
+
+       /*
+        * Verify HEAD
+        */
+       head = resolve_ref_unsafe("HEAD", 0, &head_oid, &flags);
+       if (!head)
+               if (get_oid("HEAD", &head_oid))
+                       return error(_("bad HEAD - I need a HEAD"));
+
+       /*
+        * Check if we are bisecting
+        */
+       if (!is_empty_or_missing_file(git_path_bisect_start())) {
+               /* Reset to the rev from where we started */
+               strbuf_read_file(&start_head, git_path_bisect_start(), 0);
+               strbuf_trim(&start_head);
+               if (!no_checkout) {
+                       struct argv_array argv = ARGV_ARRAY_INIT;
+
+                       argv_array_pushl(&argv, "checkout", start_head.buf,
+                                        "--", NULL);
+                       if (run_command_v_opt(argv.argv, RUN_GIT_CMD)) {
+                               retval = error(_("checking out '%s' failed."
+                                                " Try 'git bisect start "
+                                                "<valid-branch>'."),
+                                              start_head.buf);
+                               goto finish;
+                       }
+               }
+       } else {
+               /* Get the rev from where we start. */
+               if (!get_oid(head, &head_oid) &&
+                   !starts_with(head, "refs/heads/")) {
+                       strbuf_reset(&start_head);
+                       strbuf_addstr(&start_head, oid_to_hex(&head_oid));
+               } else if (!get_oid(head, &head_oid) &&
+                          skip_prefix(head, "refs/heads/", &head)) {
+                       /*
+                        * This error message should only be triggered by
+                        * cogito usage, and cogito users should understand
+                        * it relates to cg-seek.
+                        */
+                       if (!is_empty_or_missing_file(git_path_head_name()))
+                               return error(_("won't bisect on cg-seek'ed tree"));
+                       strbuf_addstr(&start_head, head);
+               } else {
+                       return error(_("bad HEAD - strange symbolic ref"));
+               }
+       }
+
+       /*
+        * Get rid of any old bisect state.
+        */
+       if (bisect_clean_state())
+               return -1;
+
+       /*
+        * In case of mistaken revs or checkout error, or signals received,
+        * "bisect_auto_next" below may exit or misbehave.
+        * We have to trap this to be able to clean up using
+        * "bisect_clean_state".
+        */
+
+       /*
+        * Write new start state
+        */
+       write_file(git_path_bisect_start(), "%s\n", start_head.buf);
+
+       if (no_checkout) {
+               get_oid(start_head.buf, &oid);
+               if (update_ref(NULL, "BISECT_HEAD", &oid, NULL, 0,
+                              UPDATE_REFS_MSG_ON_ERR)) {
+                       retval = -1;
+                       goto finish;
+               }
+       }
+
+       if (pathspec_pos < argc - 1)
+               sq_quote_argv(&bisect_names, argv + pathspec_pos);
+       write_file(git_path_bisect_names(), "%s\n", bisect_names.buf);
+
+       for (i = 0; i < states.nr; i++)
+               if (bisect_write(states.items[i].string,
+                                revs.items[i].string, terms, 1)) {
+                       retval = -1;
+                       goto finish;
+               }
+
+       if (must_write_terms && write_terms(terms->term_bad,
+                                           terms->term_good)) {
+               retval = -1;
+               goto finish;
+       }
+
+       retval = bisect_append_log_quoted(argv);
+       if (retval)
+               retval = -1;
+
+finish:
+       string_list_clear(&revs, 0);
+       string_list_clear(&states, 0);
+       strbuf_release(&start_head);
+       strbuf_release(&bisect_names);
+       return retval;
+}
+
 int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 {
        enum {
                NEXT_ALL = 1,
                WRITE_TERMS,
                BISECT_CLEAN_STATE,
-               CHECK_EXPECTED_REVS
+               CHECK_EXPECTED_REVS,
+               BISECT_RESET,
+               BISECT_WRITE,
+               CHECK_AND_SET_TERMS,
+               BISECT_NEXT_CHECK,
+               BISECT_TERMS,
+               BISECT_START
        } cmdmode = 0;
-       int no_checkout = 0;
+       int no_checkout = 0, res = 0, nolog = 0;
        struct option options[] = {
                OPT_CMDMODE(0, "next-all", &cmdmode,
                         N_("perform 'git bisect next'"), NEXT_ALL),
@@ -124,13 +631,29 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
                         N_("cleanup the bisection state"), BISECT_CLEAN_STATE),
                OPT_CMDMODE(0, "check-expected-revs", &cmdmode,
                         N_("check for expected revs"), CHECK_EXPECTED_REVS),
+               OPT_CMDMODE(0, "bisect-reset", &cmdmode,
+                        N_("reset the bisection state"), BISECT_RESET),
+               OPT_CMDMODE(0, "bisect-write", &cmdmode,
+                        N_("write out the bisection state in BISECT_LOG"), BISECT_WRITE),
+               OPT_CMDMODE(0, "check-and-set-terms", &cmdmode,
+                        N_("check and set terms in a bisection state"), CHECK_AND_SET_TERMS),
+               OPT_CMDMODE(0, "bisect-next-check", &cmdmode,
+                        N_("check whether bad or good terms exist"), BISECT_NEXT_CHECK),
+               OPT_CMDMODE(0, "bisect-terms", &cmdmode,
+                        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()
        };
+       struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
 
        argc = parse_options(argc, argv, prefix, options,
-                            git_bisect_helper_usage, 0);
+                            git_bisect_helper_usage,
+                            PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);
 
        if (!cmdmode)
                usage_with_options(git_bisect_helper_usage, options);
@@ -149,8 +672,40 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
        case CHECK_EXPECTED_REVS:
                check_expected_revs(argv, argc);
                return 0;
+       case BISECT_RESET:
+               if (argc > 1)
+                       return error(_("--bisect-reset requires either no argument or a commit"));
+               return !!bisect_reset(argc ? argv[0] : NULL);
+       case BISECT_WRITE:
+               if (argc != 4 && argc != 5)
+                       return error(_("--bisect-write requires either 4 or 5 arguments"));
+               set_terms(&terms, argv[3], argv[2]);
+               res = bisect_write(argv[0], argv[1], &terms, nolog);
+               break;
+       case CHECK_AND_SET_TERMS:
+               if (argc != 3)
+                       return error(_("--check-and-set-terms requires 3 arguments"));
+               set_terms(&terms, argv[2], argv[1]);
+               res = check_and_set_terms(&terms, argv[0]);
+               break;
+       case BISECT_NEXT_CHECK:
+               if (argc != 2 && argc != 3)
+                       return error(_("--bisect-next-check requires 2 or 3 arguments"));
+               set_terms(&terms, argv[1], argv[0]);
+               res = bisect_next_check(&terms, argc == 3 ? argv[2] : NULL);
+               break;
+       case BISECT_TERMS:
+               if (argc > 1)
+                       return error(_("--bisect-terms requires 0 or 1 argument"));
+               res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
+               break;
+       case BISECT_START:
+               set_terms(&terms, "bad", "good");
+               res = bisect_start(&terms, no_checkout, argv, argc);
+               break;
        default:
                return error("BUG: unknown subcommand '%d'", cmdmode);
        }
-       return 0;
+       free_terms(&terms);
+       return !!res;
 }
index 6d798f99392e54b4392713846652111d457787bb..581de0d8322681ef11026b3e36a81c7baf0fda38 100644 (file)
@@ -925,6 +925,10 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
                 */
                blame_date_width = utf8_strwidth(_("4 years, 11 months ago")) + 1; /* add the null */
                break;
+       case DATE_HUMAN:
+               /* If the year is shown, no time is shown */
+               blame_date_width = sizeof("Thu Oct 19 16:00");
+               break;
        case DATE_NORMAL:
                blame_date_width = sizeof("Thu Oct 19 16:00:04 2006 -0700");
                break;
@@ -1007,7 +1011,8 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
                long bottom, top;
                if (parse_range_arg(range_list.items[range_i].string,
                                    nth_line_cb, &sb, lno, anchor,
-                                   &bottom, &top, sb.path, &the_index))
+                                   &bottom, &top, sb.path,
+                                   the_repository->index))
                        usage(blame_usage);
                if ((!lno && (top || bottom)) || lno < bottom)
                        die(Q_("file %s has only %lu line",
index 9e9c65d9c698cae2ab735463edf378d5dd3a9815..1ea4bfdfc19868d9cb89bb7014c138f145f7dd67 100644 (file)
@@ -56,8 +56,7 @@ int cmd_bundle(int argc, const char **argv, const char *prefix)
                }
                if (!startup_info->have_repository)
                        die(_("Need a repository to create a bundle."));
-               return !!create_bundle(the_repository, &header,
-                                      bundle_file, argc, argv);
+               return !!create_bundle(the_repository, bundle_file, argc, argv);
        } else if (!strcmp(cmd, "unbundle")) {
                if (!startup_info->have_repository)
                        die(_("Need a repository to unbundle."));
index 2ca56fd086bf6bef7595ad008d9eda2c64901cf5..0f092382e175cf7ebe43d2f53ef1c5c79c338568 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright (C) Linus Torvalds, 2005
  */
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "cache.h"
 #include "config.h"
 #include "builtin.h"
@@ -73,7 +74,8 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
        if (unknown_type)
                flags |= OBJECT_INFO_ALLOW_UNKNOWN_TYPE;
 
-       if (get_oid_with_context(obj_name, GET_OID_RECORD_PATH,
+       if (get_oid_with_context(the_repository, obj_name,
+                                GET_OID_RECORD_PATH,
                                 &oid, &obj_context))
                die("Not a valid object name %s", obj_name);
 
@@ -209,14 +211,14 @@ struct expand_data {
 
        /*
         * After a mark_query run, this object_info is set up to be
-        * passed to sha1_object_info_extended. It will point to the data
+        * passed to oid_object_info_extended. It will point to the data
         * elements above, so you can retrieve the response from there.
         */
        struct object_info info;
 
        /*
         * This flag will be true if the requested batch format and options
-        * don't require us to call sha1_object_info, which can then be
+        * don't require us to call oid_object_info, which can then be
         * optimized out.
         */
        unsigned skip_object_info : 1;
@@ -380,14 +382,18 @@ static void batch_one_object(const char *obj_name,
 {
        struct object_context ctx;
        int flags = opt->follow_symlinks ? GET_OID_FOLLOW_SYMLINKS : 0;
-       enum follow_symlinks_result result;
+       enum get_oid_result result;
 
-       result = get_oid_with_context(obj_name, flags, &data->oid, &ctx);
+       result = get_oid_with_context(the_repository, obj_name,
+                                     flags, &data->oid, &ctx);
        if (result != FOUND) {
                switch (result) {
                case MISSING_OBJECT:
                        printf("%s missing\n", obj_name);
                        break;
+               case SHORT_NAME_AMBIGUOUS:
+                       printf("%s ambiguous\n", obj_name);
+                       break;
                case DANGLING_SYMLINK:
                        printf("dangling %"PRIuMAX"\n%s\n",
                               (uintmax_t)strlen(obj_name), obj_name);
@@ -490,7 +496,7 @@ static int batch_objects(struct batch_options *opt)
 
        /*
         * Expand once with our special mark_query flag, which will prime the
-        * object_info to be handed to sha1_object_info_extended for each
+        * object_info to be handed to oid_object_info_extended for each
         * object.
         */
        memset(&data, 0, sizeof(data));
index 30a2f84274d32977769f778d5704accb599cf0e7..dd833977864d79a3abde9fc66042d7bda56b8e82 100644 (file)
@@ -1,3 +1,4 @@
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "builtin.h"
 #include "cache.h"
 #include "config.h"
index ec9a959e08d0e3dfa0d2b08529cacbe8d2e04c6e..599097304b77fa5a3f464b8831e71d6a3f56077a 100644 (file)
@@ -1,3 +1,4 @@
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "builtin.h"
 #include "cache.h"
 #include "config.h"
index a2a726ad8d8fa65d2fbcd1b111d71bad61c5cee8..1ac1cc290ed7db86d3ae42b7df2246dad1c507e3 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright (C) 2005 Linus Torvalds
  *
  */
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "builtin.h"
 #include "config.h"
 #include "lockfile.h"
index 6fadf412e830ba4aeaa8d2940fd9a7aab9bd8fa5..ece4eb14bf1e92742b9fc0723a150e595883d8c6 100644 (file)
@@ -1,3 +1,4 @@
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "builtin.h"
 #include "config.h"
 #include "checkout.h"
@@ -288,7 +289,7 @@ static int checkout_paths(const struct checkout_opts *opts,
                return run_add_interactive(revision, "--patch=checkout",
                                           &opts->pathspec);
 
-       hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
+       repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
        if (read_cache_preload(&opts->pathspec) < 0)
                return error(_("index file corrupt"));
 
@@ -592,6 +593,14 @@ static int skip_merge_working_tree(const struct checkout_opts *opts,
         * Remaining variables are not checkout options but used to track state
         */
 
+        /*
+         * Do the merge if this is the initial checkout. We cannot use
+         * is_cache_unborn() here because the index hasn't been loaded yet
+         * so cache_nr and timestamp.sec are always zero.
+         */
+       if (!file_exists(get_index_file()))
+               return 0;
+
        return 1;
 }
 
@@ -693,7 +702,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
                         * a pain; plumb in an option to set
                         * o.renormalize?
                         */
-                       init_merge_options(&o);
+                       init_merge_options(&o, the_repository);
                        o.verbosity = 0;
                        work = write_tree_from_memory(&o);
 
index bbcdeb2d9e7f275309609a2a21a5dd4baf1cf1bd..aaba4af3c26de2150ad655a0b162fc85a69a466d 100644 (file)
@@ -6,6 +6,7 @@
  * Based on git-clean.sh by Pavel Roskin
  */
 
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "builtin.h"
 #include "cache.h"
 #include "config.h"
index 7c7f98c72c80cfcb12f3d3f61a13f46b19967a8f..50bde9961809b1d55c74fb6d3cbfbf5a86ddf5c7 100644 (file)
@@ -8,6 +8,7 @@
  * Clone a repository into a different directory that does not yet exist.
  */
 
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "builtin.h"
 #include "config.h"
 #include "lockfile.h"
@@ -1136,9 +1137,13 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                                     option_upload_pack);
 
        if (filter_options.choice) {
+               struct strbuf expanded_filter_spec = STRBUF_INIT;
+               expand_list_objects_filter_spec(&filter_options,
+                                               &expanded_filter_spec);
                transport_set_option(transport, TRANS_OPT_LIST_OBJECTS_FILTER,
-                                    filter_options.filter_spec);
+                                    expanded_filter_spec.buf);
                transport_set_option(transport, TRANS_OPT_FROM_PROMISOR, "1");
+               strbuf_release(&expanded_filter_spec);
        }
 
        if (transport->smart_options && !deepen && !filter_options.choice)
index c02a3f1221d625ad6407317199cc35c7a56a09ba..4ae502754c292d0e743ed8fbfdf9d5dda00d1dba 100644 (file)
@@ -110,8 +110,8 @@ static int graph_read(int argc, const char **argv)
                printf(" oid_lookup");
        if (graph->chunk_commit_data)
                printf(" commit_metadata");
-       if (graph->chunk_large_edges)
-               printf(" large_edges");
+       if (graph->chunk_extra_edges)
+               printf(" extra_edges");
        printf("\n");
 
        UNLEAK(graph);
index 9ec36a82b63c0216cca11a709310e12174726e91..12cc403bd7eac3f3c195ce6533feee1865139bae 100644 (file)
@@ -66,7 +66,13 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
                        continue;
                }
 
-               if (skip_prefix(arg, "-S", &sign_commit))
+               if (!strcmp(arg, "--gpg-sign")) {
+                   sign_commit = "";
+                   continue;
+               }
+
+               if (skip_prefix(arg, "-S", &sign_commit) ||
+                       skip_prefix(arg, "--gpg-sign=", &sign_commit))
                        continue;
 
                if (!strcmp(arg, "--no-gpg-sign")) {
index 7d2e0b61e5fc73a9b338a4f37b9a51ddc6cbf306..2986553d5ffb97f0798e4d4eb921073439fb9a92 100644 (file)
@@ -5,6 +5,7 @@
  * Based on git-commit.sh by Junio C Hamano and Linus Torvalds
  */
 
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "cache.h"
 #include "config.h"
 #include "lockfile.h"
@@ -1368,7 +1369,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
        if (status_format != STATUS_FORMAT_PORCELAIN &&
            status_format != STATUS_FORMAT_PORCELAIN_V2)
                progress_flag = REFRESH_PROGRESS;
-       read_index(&the_index);
+       repo_read_index(the_repository);
        refresh_index(&the_index,
                      REFRESH_QUIET|REFRESH_UNMERGED|progress_flag,
                      &s.pathspec, NULL, NULL);
@@ -1397,7 +1398,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
        wt_status_collect(&s);
 
        if (0 <= fd)
-               update_index_if_able(&the_index, &index_lock);
+               repo_update_index_if_able(the_repository, &index_lock);
 
        if (s.relative_paths)
                s.prefix = prefix;
@@ -1675,7 +1676,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
        run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
        run_commit_hook(use_editor, get_index_file(), "post-commit", NULL);
        if (amend && !no_post_rewrite) {
-               commit_post_rewrite(current_head, &oid);
+               commit_post_rewrite(the_repository, current_head, &oid);
        }
        if (!quiet) {
                unsigned int flags = 0;
index cc118448ee00d2c4336422afbad1799babfb5783..02ec56417a197b7e252625561fa462a215499a4d 100644 (file)
@@ -1,3 +1,4 @@
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "cache.h"
 #include "config.h"
 #include "lockfile.h"
@@ -634,7 +635,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
                                      NULL, NULL, NULL);
                        fd = hold_locked_index(&index_lock, 0);
                        if (0 <= fd)
-                               update_index_if_able(&the_index, &index_lock);
+                               repo_update_index_if_able(the_repository, &index_lock);
 
                        repo_init_revisions(the_repository, &revs, prefix);
                        argv_array_pushv(&args, diff_index_args);
index 48cfcb935d0413fcf3850e0c28ec237b642b38a2..86ae474fbfb410f026d42ce9f36e9805a98cfc82 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright (C) Linus Torvalds, 2005
  */
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "cache.h"
 #include "config.h"
 #include "diff.h"
index fcccd1f10dc95cd47a994b5139226af438049f87..93ec6424234c65f486dcfca724c77a48e5e91f91 100644 (file)
@@ -1,3 +1,4 @@
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "cache.h"
 #include "config.h"
 #include "diff.h"
index ef996126d7b521ea1de2c837e4ed97fdcb6f1e71..a90681bcbafcba04af3b669f0758c78ccecdd11f 100644 (file)
@@ -1,3 +1,4 @@
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "cache.h"
 #include "config.h"
 #include "diff.h"
@@ -165,7 +166,7 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
 
                if (opt->diffopt.detect_rename) {
                        if (!the_index.cache)
-                               read_index(&the_index);
+                               repo_read_index(the_repository);
                        opt->diffopt.setup |= DIFF_SETUP_USE_SIZE_CACHE;
                }
                while (fgets(line, sizeof(line), stdin)) {
index 84a362ff5625bc6ef776bcd067fa2dcb2d55038a..9f6109224b7ea75689e9780c5f79343f55e1e3e5 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright (c) 2006 Junio C Hamano
  */
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "cache.h"
 #include "config.h"
 #include "lockfile.h"
@@ -212,7 +213,7 @@ static void refresh_index_quietly(void)
        discard_cache();
        read_cache();
        refresh_cache(REFRESH_QUIET|REFRESH_UNMERGED);
-       update_index_if_able(&the_index, &lock_file);
+       repo_update_index_if_able(the_repository, &lock_file);
 }
 
 static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv)
index 71318c26e177e8aa4176201e4f23e6f43b63b630..a3ea60ea71428ee59ab20a67f6e9ccf76c841f85 100644 (file)
@@ -11,6 +11,7 @@
  *
  * Copyright (C) 2016 Johannes Schindelin
  */
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "cache.h"
 #include "config.h"
 #include "builtin.h"
index f6a513495ea77e4350aa6ec5282c3ab2969ee027..153a2bd282cac47ba72c101eaf0ca1b867d3f2cd 100644 (file)
@@ -218,7 +218,8 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
 
        packet_reader_init(&reader, fd[0], NULL, 0,
                           PACKET_READ_CHOMP_NEWLINE |
-                          PACKET_READ_GENTLE_ON_EOF);
+                          PACKET_READ_GENTLE_ON_EOF |
+                          PACKET_READ_DIE_ON_ERR_PACKET);
 
        version = discover_version(&reader);
        switch (version) {
index c316c03ba206b8b04b598cdab8dd259a59014ea5..5a09fe24cddac79bb66f90b0405f5bcc9855dbee 100644 (file)
@@ -317,8 +317,7 @@ static void find_non_local_tags(const struct ref *refs,
                            !has_object_file_with_flags(&ref->old_oid,
                                                        OBJECT_INFO_QUICK) &&
                            !will_fetch(head, ref->old_oid.hash) &&
-                           !has_sha1_file_with_flags(item->oid.hash,
-                                                     OBJECT_INFO_QUICK) &&
+                           !has_object_file_with_flags(&item->oid, OBJECT_INFO_QUICK) &&
                            !will_fetch(head, item->oid.hash))
                                oidclr(&item->oid);
                        item = NULL;
@@ -332,7 +331,7 @@ static void find_non_local_tags(const struct ref *refs,
                 * fetch.
                 */
                if (item &&
-                   !has_sha1_file_with_flags(item->oid.hash, OBJECT_INFO_QUICK) &&
+                   !has_object_file_with_flags(&item->oid, OBJECT_INFO_QUICK) &&
                    !will_fetch(head, item->oid.hash))
                        oidclr(&item->oid);
 
@@ -353,7 +352,7 @@ static void find_non_local_tags(const struct ref *refs,
         * checked to see if it needs fetching.
         */
        if (item &&
-           !has_sha1_file_with_flags(item->oid.hash, OBJECT_INFO_QUICK) &&
+           !has_object_file_with_flags(&item->oid, OBJECT_INFO_QUICK) &&
            !will_fetch(head, item->oid.hash))
                oidclr(&item->oid);
 
@@ -629,9 +628,14 @@ static int find_and_replace(struct strbuf *haystack,
                            const char *needle,
                            const char *placeholder)
 {
-       const char *p = strstr(haystack->buf, needle);
+       const char *p = NULL;
        int plen, nlen;
 
+       nlen = strlen(needle);
+       if (ends_with(haystack->buf, needle))
+               p = haystack->buf + haystack->len - nlen;
+       else
+               p = strstr(haystack->buf, needle);
        if (!p)
                return 0;
 
@@ -639,7 +643,6 @@ static int find_and_replace(struct strbuf *haystack,
                return 0;
 
        plen = strlen(p);
-       nlen = strlen(needle);
        if (plen > nlen && p[nlen] != '/')
                return 0;
 
@@ -1165,6 +1168,7 @@ static void add_negotiation_tips(struct git_transport_options *smart_options)
 static struct transport *prepare_transport(struct remote *remote, int deepen)
 {
        struct transport *transport;
+
        transport = transport_get(remote, NULL);
        transport_set_verbosity(transport, verbosity, progress);
        transport->family = family;
@@ -1184,9 +1188,13 @@ static struct transport *prepare_transport(struct remote *remote, int deepen)
        if (update_shallow)
                set_option(transport, TRANS_OPT_UPDATE_SHALLOW, "yes");
        if (filter_options.choice) {
+               struct strbuf expanded_filter_spec = STRBUF_INIT;
+               expand_list_objects_filter_spec(&filter_options,
+                                               &expanded_filter_spec);
                set_option(transport, TRANS_OPT_LIST_OBJECTS_FILTER,
-                          filter_options.filter_spec);
+                          expanded_filter_spec.buf);
                set_option(transport, TRANS_OPT_FROM_PROMISOR, "1");
+               strbuf_release(&expanded_filter_spec);
        }
        if (negotiation_tip.nr) {
                if (transport->smart_options)
index bf5ddff43f74e0dba77d05e04bc14c0c59884287..bb4227bebc606dfac8337d7aa3e78705113a79b5 100644 (file)
@@ -1,3 +1,4 @@
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "builtin.h"
 #include "cache.h"
 #include "repository.h"
@@ -401,7 +402,8 @@ static int fsck_obj(struct object *obj, void *buffer, unsigned long size)
        if (obj->type == OBJ_TREE)
                free_tree_buffer((struct tree *)obj);
        if (obj->type == OBJ_COMMIT)
-               free_commit_buffer((struct commit *)obj);
+               free_commit_buffer(the_repository->parsed_objects,
+                                  (struct commit *)obj);
        return err;
 }
 
index dd52ea968baf1b5b971c5f59152a561744cf9b92..580fd38f41704b6d534c04f2dee1bf85eee67c3c 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright (c) 2006 Junio C Hamano
  */
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "cache.h"
 #include "repository.h"
 #include "config.h"
@@ -393,21 +394,22 @@ static void run_pager(struct grep_opt *opt, const char *prefix)
                exit(status);
 }
 
-static int grep_cache(struct grep_opt *opt, struct repository *repo,
+static int grep_cache(struct grep_opt *opt,
                      const struct pathspec *pathspec, int cached);
 static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
                     struct tree_desc *tree, struct strbuf *base, int tn_len,
-                    int check_attr, struct repository *repo);
+                    int check_attr);
 
-static int grep_submodule(struct grep_opt *opt, struct repository *superproject,
+static int grep_submodule(struct grep_opt *opt,
                          const struct pathspec *pathspec,
                          const struct object_id *oid,
                          const char *filename, const char *path)
 {
        struct repository subrepo;
+       struct repository *superproject = opt->repo;
        const struct submodule *sub = submodule_from_path(superproject,
                                                          &null_oid, path);
-
+       struct grep_opt subopt;
        int hit;
 
        /*
@@ -443,6 +445,9 @@ static int grep_submodule(struct grep_opt *opt, struct repository *superproject,
        add_to_alternates_memory(subrepo.objects->odb->path);
        grep_read_unlock();
 
+       memcpy(&subopt, opt, sizeof(subopt));
+       subopt.repo = &subrepo;
+
        if (oid) {
                struct object *object;
                struct tree_desc tree;
@@ -464,21 +469,22 @@ static int grep_submodule(struct grep_opt *opt, struct repository *superproject,
                strbuf_addch(&base, '/');
 
                init_tree_desc(&tree, data, size);
-               hit = grep_tree(opt, pathspec, &tree, &base, base.len,
-                               object->type == OBJ_COMMIT, &subrepo);
+               hit = grep_tree(&subopt, pathspec, &tree, &base, base.len,
+                               object->type == OBJ_COMMIT);
                strbuf_release(&base);
                free(data);
        } else {
-               hit = grep_cache(opt, &subrepo, pathspec, 1);
+               hit = grep_cache(&subopt, pathspec, 1);
        }
 
        repo_clear(&subrepo);
        return hit;
 }
 
-static int grep_cache(struct grep_opt *opt, struct repository *repo,
+static int grep_cache(struct grep_opt *opt,
                      const struct pathspec *pathspec, int cached)
 {
+       struct repository *repo = opt->repo;
        int hit = 0;
        int nr;
        struct strbuf name = STRBUF_INIT;
@@ -516,7 +522,7 @@ static int grep_cache(struct grep_opt *opt, struct repository *repo,
                        }
                } else if (recurse_submodules && S_ISGITLINK(ce->ce_mode) &&
                           submodule_path_match(repo->index, pathspec, name.buf, NULL)) {
-                       hit |= grep_submodule(opt, repo, pathspec, NULL, ce->name, ce->name);
+                       hit |= grep_submodule(opt, pathspec, NULL, ce->name, ce->name);
                } else {
                        continue;
                }
@@ -538,8 +544,9 @@ static int grep_cache(struct grep_opt *opt, struct repository *repo,
 
 static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
                     struct tree_desc *tree, struct strbuf *base, int tn_len,
-                    int check_attr, struct repository *repo)
+                    int check_attr)
 {
+       struct repository *repo = opt->repo;
        int hit = 0;
        enum interesting match = entry_not_interesting;
        struct name_entry entry;
@@ -586,10 +593,10 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
                        strbuf_addch(base, '/');
                        init_tree_desc(&sub, data, size);
                        hit |= grep_tree(opt, pathspec, &sub, base, tn_len,
-                                        check_attr, repo);
+                                        check_attr);
                        free(data);
                } else if (recurse_submodules && S_ISGITLINK(entry.mode)) {
-                       hit |= grep_submodule(opt, repo, pathspec, &entry.oid,
+                       hit |= grep_submodule(opt, pathspec, &entry.oid,
                                              base->buf, base->buf + tn_len);
                }
 
@@ -631,7 +638,7 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
                }
                init_tree_desc(&tree, data, size);
                hit = grep_tree(opt, pathspec, &tree, &base, base.len,
-                               obj->type == OBJ_COMMIT, the_repository);
+                               obj->type == OBJ_COMMIT);
                strbuf_release(&base);
                free(data);
                return hit;
@@ -648,12 +655,12 @@ static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec,
 
        for (i = 0; i < nr; i++) {
                struct object *real_obj;
-               real_obj = deref_tag(the_repository, list->objects[i].item,
+               real_obj = deref_tag(opt->repo, list->objects[i].item,
                                     NULL, 0);
 
                /* load the gitmodules file for this rev */
                if (recurse_submodules) {
-                       submodule_free(the_repository);
+                       submodule_free(opt->repo);
                        gitmodules_config_oid(&real_obj->oid);
                }
                if (grep_object(opt, pathspec, real_obj, list->objects[i].name,
@@ -678,9 +685,9 @@ static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec,
        if (exc_std)
                setup_standard_excludes(&dir);
 
-       fill_directory(&dir, &the_index, pathspec);
+       fill_directory(&dir, opt->repo->index, pathspec);
        for (i = 0; i < dir.nr; i++) {
-               if (!dir_path_match(&the_index, dir.entries[i], pathspec, 0, NULL))
+               if (!dir_path_match(opt->repo->index, dir.entries[i], pathspec, 0, NULL))
                        continue;
                hit |= grep_file(opt, dir.entries[i]->name);
                if (hit && opt->status_only)
@@ -1018,7 +1025,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                        break;
                }
 
-               if (get_oid_with_context(arg, GET_OID_RECORD_PATH,
+               if (get_oid_with_context(the_repository, arg,
+                                        GET_OID_RECORD_PATH,
                                         &oid, &oc)) {
                        if (seen_dashdash)
                                die(_("unable to resolve revision: %s"), arg);
@@ -1121,7 +1129,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                if (!cached)
                        setup_work_tree();
 
-               hit = grep_cache(&opt, the_repository, &pathspec, cached);
+               hit = grep_cache(&opt, &pathspec, cached);
        } else {
                if (cached)
                        die(_("both --cached and trees are given"));
index d6f06ea32f51272efa5ccb3fdd396b5916e98e45..e055c1110310bc3b6ccef4fa83dae84316fcc75f 100644 (file)
@@ -40,7 +40,8 @@ static void hash_fd(int fd, const char *type, const char *path, unsigned flags,
        if (fstat(fd, &st) < 0 ||
            (literally
             ? hash_literally(&oid, fd, type, flags)
-            : index_fd(&the_index, &oid, fd, &st, type_from_string(type), path, flags)))
+            : index_fd(the_repository->index, &oid, fd, &st,
+                       type_from_string(type), path, flags)))
                die((flags & HASH_WRITE_OBJECT)
                    ? "Unable to add %s to database"
                    : "Unable to hash %s", path);
index ac1f4ea9a782508e89f269bb1bf000a4a805c793..31046c7a0a3776fe61e81c30e83f4139e980e1c8 100644 (file)
@@ -772,7 +772,7 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
        if (startup_info->have_repository) {
                read_lock();
                collision_test_needed =
-                       has_sha1_file_with_flags(oid->hash, OBJECT_INFO_QUICK);
+                       has_object_file_with_flags(oid, OBJECT_INFO_QUICK);
                read_unlock();
        }
 
index a479642eb98681d54a3dd802e2245ea672f2e9df..57869267d8d75e06a1a34e4dea104102aac21a65 100644 (file)
@@ -4,6 +4,7 @@
  * (C) Copyright 2006 Linus Torvalds
  *              2006 Junio Hamano
  */
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "cache.h"
 #include "config.h"
 #include "refs.h"
@@ -397,7 +398,8 @@ static int cmd_log_walk(struct rev_info *rev)
                         * We may show a given commit multiple times when
                         * walking the reflogs.
                         */
-                       free_commit_buffer(commit);
+                       free_commit_buffer(the_repository->parsed_objects,
+                                          commit);
                        free_commit_list(commit->parents);
                        commit->parents = NULL;
                }
@@ -508,7 +510,8 @@ static int show_blob_object(const struct object_id *oid, struct rev_info *rev, c
            !rev->diffopt.flags.allow_textconv)
                return stream_blob_to_fd(1, oid, NULL, 0);
 
-       if (get_oid_with_context(obj_name, GET_OID_RECORD_PATH,
+       if (get_oid_with_context(the_repository, obj_name,
+                                GET_OID_RECORD_PATH,
                                 &oidc, &obj_context))
                die(_("Not a valid object name %s"), obj_name);
        if (!obj_context.path ||
@@ -1940,7 +1943,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                    open_next_file(rev.numbered_files ? NULL : commit, NULL, &rev, quiet))
                        die(_("Failed to create output files"));
                shown = log_tree_commit(&rev, commit);
-               free_commit_buffer(commit);
+               free_commit_buffer(the_repository->parsed_objects,
+                                  commit);
 
                /* We put one extra blank line between formatted
                 * patches and this flag is used by log-tree code
index cde87cbeeb8e8d7389c95c33ff60e6e5c39e10cd..29a8762d46eb7aa9a9b456e2564062fdbdb48a06 100644 (file)
@@ -5,7 +5,6 @@
  *
  * Copyright (C) Linus Torvalds, 2005
  */
-#define NO_THE_INDEX_COMPATIBILITY_MACROS
 #include "cache.h"
 #include "repository.h"
 #include "config.h"
index c99443b095bd8abbe02d4ea87a452d916681c53f..38ea6ad6ca25d5a969afdbfc5b3510ba44e49a33 100644 (file)
@@ -1,3 +1,4 @@
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "builtin.h"
 #include "run-command.h"
 
index 0b07263415785e11c7fc5b1a6da40a25e969b73c..4594507420533262a7b6611386a340cfdb96b25f 100644 (file)
@@ -7,6 +7,7 @@
  *
  * Pretend we resolved the heads, but declare our tree trumps everybody else.
  */
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "git-compat-util.h"
 #include "builtin.h"
 #include "diff.h"
index 7545136c2a6da526ab7998106f2a28bfcbe8bd81..5b910e351e4dede4527d23a04a8294e17ebd371c 100644 (file)
@@ -29,7 +29,7 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix)
        char *better1, *better2;
        struct commit *result;
 
-       init_merge_options(&o);
+       init_merge_options(&o, the_repository);
        if (argv[0] && ends_with(argv[0], "-subtree"))
                o.subtree_shift = "";
 
index 5541ad091eb8c4b975d25be6386ea79be4831e5b..34ca0258b12ae4e4a04c495c244fb9c18268e7d8 100644 (file)
@@ -1,3 +1,4 @@
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "builtin.h"
 #include "tree-walk.h"
 #include "xdiff-interface.h"
@@ -76,7 +77,8 @@ static void *result(struct merge_list *entry, unsigned long *size)
        their = NULL;
        if (entry)
                their = entry->blob;
-       return merge_blobs(&the_index, path, base, our, their, size);
+       return merge_blobs(the_repository->index, path,
+                          base, our, their, size);
 }
 
 static void *origin(struct merge_list *entry, unsigned long *size)
index dc0b7cc521c26f4c0ef1c6440d17c0f35ac1c983..e47d77baeebe888cfb67f8e03804ffc3ee3715c0 100644 (file)
@@ -6,6 +6,7 @@
  * Based on git-merge.sh by Junio C Hamano.
  */
 
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "cache.h"
 #include "config.h"
 #include "parse-options.h"
@@ -702,7 +703,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
                        return 2;
                }
 
-               init_merge_options(&o);
+               init_merge_options(&o, the_repository);
                if (!strcmp(strategy, "subtree"))
                        o.subtree_shift = "";
 
index 80bb967a63f154eb44ebc1a6dd7f833d01dce83e..be15ba7044e0eeeee216a9e6c4615214cd7cdc1e 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 2006 Johannes Schindelin
  */
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "builtin.h"
 #include "config.h"
 #include "pathspec.h"
index 4996a670f71333de09e1a0311fde85d6985c9c91..02e97f55c5a01be452bb3eaa97ec396f58e2ed99 100644 (file)
@@ -330,10 +330,10 @@ static int notes_copy_from_stdin(int force, const char *rewrite_cmd)
        }
 
        if (!rewrite_cmd) {
-               commit_notes(t, msg);
+               commit_notes(the_repository, t, msg);
                free_notes(t);
        } else {
-               finish_copy_notes_for_rewrite(c, msg);
+               finish_copy_notes_for_rewrite(the_repository, c, msg);
        }
        strbuf_release(&buf);
        return ret;
@@ -469,12 +469,14 @@ static int add(int argc, const char **argv, const char *prefix)
                write_note_data(&d, &new_note);
                if (add_note(t, &object, &new_note, combine_notes_overwrite))
                        BUG("combine_notes_overwrite failed");
-               commit_notes(t, "Notes added by 'git notes add'");
+               commit_notes(the_repository, t,
+                            "Notes added by 'git notes add'");
        } else {
                fprintf(stderr, _("Removing note for object %s\n"),
                        oid_to_hex(&object));
                remove_note(t, object.hash);
-               commit_notes(t, "Notes removed by 'git notes add'");
+               commit_notes(the_repository, t,
+                            "Notes removed by 'git notes add'");
        }
 
        free_note_data(&d);
@@ -552,7 +554,8 @@ static int copy(int argc, const char **argv, const char *prefix)
 
        if (add_note(t, &object, from_note, combine_notes_overwrite))
                BUG("combine_notes_overwrite failed");
-       commit_notes(t, "Notes added by 'git notes copy'");
+       commit_notes(the_repository, t,
+                    "Notes added by 'git notes copy'");
 out:
        free_notes(t);
        return retval;
@@ -636,7 +639,7 @@ static int append_edit(int argc, const char **argv, const char *prefix)
                remove_note(t, object.hash);
                logmsg = xstrfmt("Notes removed by 'git notes %s'", argv[0]);
        }
-       commit_notes(t, logmsg);
+       commit_notes(the_repository, t, logmsg);
 
        free(logmsg);
        free_note_data(&d);
@@ -937,7 +940,8 @@ static int remove_cmd(int argc, const char **argv, const char *prefix)
                strbuf_release(&sb);
        }
        if (!retval)
-               commit_notes(t, "Notes removed by 'git notes remove'");
+               commit_notes(the_repository, t,
+                            "Notes removed by 'git notes remove'");
        free_notes(t);
        return retval;
 }
@@ -965,7 +969,8 @@ static int prune(int argc, const char **argv, const char *prefix)
        prune_notes(t, (verbose ? NOTES_PRUNE_VERBOSE : 0) |
                (show_only ? NOTES_PRUNE_VERBOSE|NOTES_PRUNE_DRYRUN : 0) );
        if (!show_only)
-               commit_notes(t, "Notes removed by 'git notes prune'");
+               commit_notes(the_repository, t,
+                            "Notes removed by 'git notes prune'");
        free_notes(t);
        return 0;
 }
index 5c406ab4945f5995b898823078d4e1d803bd8fa9..a9fac7c128c1eb45026965a79db1387a8bdb92de 100644 (file)
@@ -84,6 +84,7 @@ static unsigned long pack_size_limit;
 static int depth = 50;
 static int delta_search_threads;
 static int pack_to_stdout;
+static int sparse;
 static int thin;
 static int num_preferred_base;
 static struct progress *progress_state;
@@ -970,7 +971,7 @@ static int no_try_delta(const char *path)
 
        if (!check)
                check = attr_check_initl("delta", NULL);
-       git_check_attr(&the_index, path, check);
+       git_check_attr(the_repository->index, path, check);
        if (ATTR_FALSE(check->items[0].value))
                return 1;
        return 0;
@@ -1642,7 +1643,7 @@ static void check_object(struct object_entry *entry)
 
                /*
                 * No choice but to fall back to the recursive delta walk
-                * with sha1_object_info() to find about the object type
+                * with oid_object_info() to find about the object type
                 * at this point...
                 */
                give_up:
@@ -1718,7 +1719,7 @@ static void drop_reused_delta(struct object_entry *entry)
        if (packed_object_info(the_repository, IN_PACK(entry), entry->in_pack_offset, &oi) < 0) {
                /*
                 * We failed to get the info from this pack for some reason;
-                * fall back to sha1_object_info, which may find another copy.
+                * fall back to oid_object_info, which may find another copy.
                 * And if that fails, the error will be recorded in oe_type(entry)
                 * and dealt with in prepare_pack().
                 */
@@ -1953,11 +1954,6 @@ static int delta_cacheable(unsigned long src_size, unsigned long trg_size,
        return 0;
 }
 
-/* Protect access to object database */
-static pthread_mutex_t read_mutex;
-#define read_lock()            pthread_mutex_lock(&read_mutex)
-#define read_unlock()          pthread_mutex_unlock(&read_mutex)
-
 /* Protect delta_cache_size */
 static pthread_mutex_t cache_mutex;
 #define cache_lock()           pthread_mutex_lock(&cache_mutex)
@@ -1993,11 +1989,11 @@ unsigned long oe_get_size_slow(struct packing_data *pack,
        unsigned long used, avail, size;
 
        if (e->type_ != OBJ_OFS_DELTA && e->type_ != OBJ_REF_DELTA) {
-               read_lock();
+               packing_data_lock(&to_pack);
                if (oid_object_info(the_repository, &e->idx.oid, &size) < 0)
                        die(_("unable to get size of %s"),
                            oid_to_hex(&e->idx.oid));
-               read_unlock();
+               packing_data_unlock(&to_pack);
                return size;
        }
 
@@ -2005,7 +2001,7 @@ unsigned long oe_get_size_slow(struct packing_data *pack,
        if (!p)
                BUG("when e->type is a delta, it must belong to a pack");
 
-       read_lock();
+       packing_data_lock(&to_pack);
        w_curs = NULL;
        buf = use_pack(p, &w_curs, e->in_pack_offset, &avail);
        used = unpack_object_header_buffer(buf, avail, &type, &size);
@@ -2014,7 +2010,7 @@ unsigned long oe_get_size_slow(struct packing_data *pack,
                    oid_to_hex(&e->idx.oid));
 
        unuse_pack(&w_curs);
-       read_unlock();
+       packing_data_unlock(&to_pack);
        return size;
 }
 
@@ -2076,9 +2072,9 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
 
        /* Load data if not already done */
        if (!trg->data) {
-               read_lock();
+               packing_data_lock(&to_pack);
                trg->data = read_object_file(&trg_entry->idx.oid, &type, &sz);
-               read_unlock();
+               packing_data_unlock(&to_pack);
                if (!trg->data)
                        die(_("object %s cannot be read"),
                            oid_to_hex(&trg_entry->idx.oid));
@@ -2089,9 +2085,9 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
                *mem_usage += sz;
        }
        if (!src->data) {
-               read_lock();
+               packing_data_lock(&to_pack);
                src->data = read_object_file(&src_entry->idx.oid, &type, &sz);
-               read_unlock();
+               packing_data_unlock(&to_pack);
                if (!src->data) {
                        if (src_entry->preferred_base) {
                                static int warned = 0;
@@ -2337,9 +2333,9 @@ static void find_deltas(struct object_entry **list, unsigned *list_size,
 
 static void try_to_free_from_threads(size_t size)
 {
-       read_lock();
+       packing_data_lock(&to_pack);
        release_pack_memory(size);
-       read_unlock();
+       packing_data_unlock(&to_pack);
 }
 
 static try_to_free_t old_try_to_free_routine;
@@ -2381,7 +2377,6 @@ static pthread_cond_t progress_cond;
  */
 static void init_threaded_search(void)
 {
-       init_recursive_mutex(&read_mutex);
        pthread_mutex_init(&cache_mutex, NULL);
        pthread_mutex_init(&progress_mutex, NULL);
        pthread_cond_init(&progress_cond, NULL);
@@ -2392,7 +2387,6 @@ static void cleanup_threaded_search(void)
 {
        set_try_to_free_routine(old_try_to_free_routine);
        pthread_cond_destroy(&progress_cond);
-       pthread_mutex_destroy(&read_mutex);
        pthread_mutex_destroy(&cache_mutex);
        pthread_mutex_destroy(&progress_mutex);
 }
@@ -2710,6 +2704,10 @@ static int git_pack_config(const char *k, const char *v, void *cb)
                use_bitmap_index_default = git_config_bool(k, v);
                return 0;
        }
+       if (!strcmp(k, "pack.usesparse")) {
+               sparse = git_config_bool(k, v);
+               return 0;
+       }
        if (!strcmp(k, "pack.threads")) {
                delta_search_threads = git_config_int(k, v);
                if (delta_search_threads < 0)
@@ -3137,7 +3135,7 @@ static void get_object_list(int ac, const char **av)
 
        if (prepare_revision_walk(&revs))
                die(_("revision walk setup failed"));
-       mark_edges_uninteresting(&revs, show_edge);
+       mark_edges_uninteresting(&revs, show_edge, sparse);
 
        if (!fn_show_object)
                fn_show_object = show_object;
@@ -3294,6 +3292,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
                { OPTION_CALLBACK, 0, "unpack-unreachable", NULL, N_("time"),
                  N_("unpack unreachable objects newer than <time>"),
                  PARSE_OPT_OPTARG, option_parse_unpack_unreachable },
+               OPT_BOOL(0, "sparse", &sparse,
+                        N_("use the sparse reachability algorithm")),
                OPT_BOOL(0, "thin", &thin,
                         N_("create thin packs")),
                OPT_BOOL(0, "shallow", &shallow,
@@ -3326,6 +3326,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
 
        read_replace_refs = 0;
 
+       sparse = git_env_bool("GIT_TEST_PACK_SPARSE", 0);
        reset_pack_idx_option(&pack_idx_opts);
        git_config(git_pack_config, NULL);
 
index 74808b94554a78e720128a721f21dc0d20dd839e..701d1473dc59e018247f337d37f00fe04f83cb98 100644 (file)
@@ -5,6 +5,7 @@
  *
  * Fetch one or more remote refs and merge it/them into the current HEAD.
  */
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "cache.h"
 #include "config.h"
 #include "builtin.h"
index ac255ad2c243192a9afd3b4578a2a501eb250aff..9083dcfa28a38f7f804c1fdcaa56fb4260b4e6f0 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright (C) Linus Torvalds, 2005
  */
 
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "cache.h"
 #include "config.h"
 #include "lockfile.h"
index c2c2d51a3b03edf17de5b37811dadd66ca4f774b..888390f9114321a489f8210659487ef2d2897fae 100644 (file)
@@ -1,3 +1,4 @@
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "builtin.h"
 #include "cache.h"
 #include "config.h"
index 774264bae8dba0815f95e3000d10ff495c477569..b9d61771ab3c17f97bce90f3f847c9284eb14a9a 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright (c) 2018 Pratik Karki
  */
 
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "builtin.h"
 #include "run-command.h"
 #include "exec-cmd.h"
@@ -123,7 +124,7 @@ static void imply_interactive(struct rebase_options *opts, const char *option)
        case REBASE_PRESERVE_MERGES:
                break;
        case REBASE_MERGE:
-               /* we silently *upgrade* --merge to --interactive if needed */
+               /* we now implement --merge via --interactive */
        default:
                opts->type = REBASE_INTERACTIVE; /* implied */
                break;
@@ -186,10 +187,7 @@ static int read_basic_state(struct rebase_options *opts)
        if (get_oid(buf.buf, &opts->orig_head))
                return error(_("invalid orig-head: '%s'"), buf.buf);
 
-       strbuf_reset(&buf);
-       if (read_one(state_dir_path("quiet", opts), &buf))
-               return -1;
-       if (buf.len)
+       if (file_exists(state_dir_path("quiet", opts)))
                opts->flags &= ~REBASE_NO_QUIET;
        else
                opts->flags |= REBASE_NO_QUIET;
@@ -247,6 +245,37 @@ static int read_basic_state(struct rebase_options *opts)
        return 0;
 }
 
+static int write_basic_state(struct rebase_options *opts)
+{
+       write_file(state_dir_path("head-name", opts), "%s",
+                  opts->head_name ? opts->head_name : "detached HEAD");
+       write_file(state_dir_path("onto", opts), "%s",
+                  opts->onto ? oid_to_hex(&opts->onto->object.oid) : "");
+       write_file(state_dir_path("orig-head", opts), "%s",
+                  oid_to_hex(&opts->orig_head));
+       write_file(state_dir_path("quiet", opts), "%s",
+                  opts->flags & REBASE_NO_QUIET ? "" : "t");
+       if (opts->flags & REBASE_VERBOSE)
+               write_file(state_dir_path("verbose", opts), "%s", "");
+       if (opts->strategy)
+               write_file(state_dir_path("strategy", opts), "%s",
+                          opts->strategy);
+       if (opts->strategy_opts)
+               write_file(state_dir_path("strategy_opts", opts), "%s",
+                          opts->strategy_opts);
+       if (opts->allow_rerere_autoupdate >= 0)
+               write_file(state_dir_path("allow_rerere_autoupdate", opts),
+                          "-%s-rerere-autoupdate",
+                          opts->allow_rerere_autoupdate ? "" : "-no");
+       if (opts->gpg_sign_opt)
+               write_file(state_dir_path("gpg_sign_opt", opts), "%s",
+                          opts->gpg_sign_opt);
+       if (opts->signoff)
+               write_file(state_dir_path("strategy", opts), "--signoff");
+
+       return 0;
+}
+
 static int apply_autostash(struct rebase_options *opts)
 {
        const char *path = state_dir_path("autostash", opts);
@@ -334,6 +363,161 @@ static void add_var(struct strbuf *buf, const char *name, const char *value)
        }
 }
 
+#define GIT_REFLOG_ACTION_ENVIRONMENT "GIT_REFLOG_ACTION"
+
+#define RESET_HEAD_DETACH (1<<0)
+#define RESET_HEAD_HARD (1<<1)
+#define RESET_HEAD_RUN_POST_CHECKOUT_HOOK (1<<2)
+#define RESET_HEAD_REFS_ONLY (1<<3)
+
+static int reset_head(struct object_id *oid, const char *action,
+                     const char *switch_to_branch, unsigned flags,
+                     const char *reflog_orig_head, const char *reflog_head)
+{
+       unsigned detach_head = flags & RESET_HEAD_DETACH;
+       unsigned reset_hard = flags & RESET_HEAD_HARD;
+       unsigned run_hook = flags & RESET_HEAD_RUN_POST_CHECKOUT_HOOK;
+       unsigned refs_only = flags & RESET_HEAD_REFS_ONLY;
+       struct object_id head_oid;
+       struct tree_desc desc[2] = { { NULL }, { NULL } };
+       struct lock_file lock = LOCK_INIT;
+       struct unpack_trees_options unpack_tree_opts;
+       struct tree *tree;
+       const char *reflog_action;
+       struct strbuf msg = STRBUF_INIT;
+       size_t prefix_len;
+       struct object_id *orig = NULL, oid_orig,
+               *old_orig = NULL, oid_old_orig;
+       int ret = 0, nr = 0;
+
+       if (switch_to_branch && !starts_with(switch_to_branch, "refs/"))
+               BUG("Not a fully qualified branch: '%s'", switch_to_branch);
+
+       if (!refs_only && hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0) {
+               ret = -1;
+               goto leave_reset_head;
+       }
+
+       if ((!oid || !reset_hard) && get_oid("HEAD", &head_oid)) {
+               ret = error(_("could not determine HEAD revision"));
+               goto leave_reset_head;
+       }
+
+       if (!oid)
+               oid = &head_oid;
+
+       if (refs_only)
+               goto reset_head_refs;
+
+       memset(&unpack_tree_opts, 0, sizeof(unpack_tree_opts));
+       setup_unpack_trees_porcelain(&unpack_tree_opts, action);
+       unpack_tree_opts.head_idx = 1;
+       unpack_tree_opts.src_index = the_repository->index;
+       unpack_tree_opts.dst_index = the_repository->index;
+       unpack_tree_opts.fn = reset_hard ? oneway_merge : twoway_merge;
+       unpack_tree_opts.update = 1;
+       unpack_tree_opts.merge = 1;
+       if (!detach_head)
+               unpack_tree_opts.reset = 1;
+
+       if (repo_read_index_unmerged(the_repository) < 0) {
+               ret = error(_("could not read index"));
+               goto leave_reset_head;
+       }
+
+       if (!reset_hard && !fill_tree_descriptor(&desc[nr++], &head_oid)) {
+               ret = error(_("failed to find tree of %s"),
+                           oid_to_hex(&head_oid));
+               goto leave_reset_head;
+       }
+
+       if (!fill_tree_descriptor(&desc[nr++], oid)) {
+               ret = error(_("failed to find tree of %s"), oid_to_hex(oid));
+               goto leave_reset_head;
+       }
+
+       if (unpack_trees(nr, desc, &unpack_tree_opts)) {
+               ret = -1;
+               goto leave_reset_head;
+       }
+
+       tree = parse_tree_indirect(oid);
+       prime_cache_tree(the_repository, the_repository->index, tree);
+
+       if (write_locked_index(the_repository->index, &lock, COMMIT_LOCK) < 0) {
+               ret = error(_("could not write index"));
+               goto leave_reset_head;
+       }
+
+reset_head_refs:
+       reflog_action = getenv(GIT_REFLOG_ACTION_ENVIRONMENT);
+       strbuf_addf(&msg, "%s: ", reflog_action ? reflog_action : "rebase");
+       prefix_len = msg.len;
+
+       if (!get_oid("ORIG_HEAD", &oid_old_orig))
+               old_orig = &oid_old_orig;
+       if (!get_oid("HEAD", &oid_orig)) {
+               orig = &oid_orig;
+               if (!reflog_orig_head) {
+                       strbuf_addstr(&msg, "updating ORIG_HEAD");
+                       reflog_orig_head = msg.buf;
+               }
+               update_ref(reflog_orig_head, "ORIG_HEAD", orig, old_orig, 0,
+                          UPDATE_REFS_MSG_ON_ERR);
+       } else if (old_orig)
+               delete_ref(NULL, "ORIG_HEAD", old_orig, 0);
+       if (!reflog_head) {
+               strbuf_setlen(&msg, prefix_len);
+               strbuf_addstr(&msg, "updating HEAD");
+               reflog_head = msg.buf;
+       }
+       if (!switch_to_branch)
+               ret = update_ref(reflog_head, "HEAD", oid, orig,
+                                detach_head ? REF_NO_DEREF : 0,
+                                UPDATE_REFS_MSG_ON_ERR);
+       else {
+               ret = update_ref(reflog_orig_head, switch_to_branch, oid,
+                                NULL, 0, UPDATE_REFS_MSG_ON_ERR);
+               if (!ret)
+                       ret = create_symref("HEAD", switch_to_branch,
+                                           reflog_head);
+       }
+       if (run_hook)
+               run_hook_le(NULL, "post-checkout",
+                           oid_to_hex(orig ? orig : &null_oid),
+                           oid_to_hex(oid), "1", NULL);
+
+leave_reset_head:
+       strbuf_release(&msg);
+       rollback_lock_file(&lock);
+       while (nr)
+               free((void *)desc[--nr].buffer);
+       return ret;
+}
+
+static int move_to_original_branch(struct rebase_options *opts)
+{
+       struct strbuf orig_head_reflog = STRBUF_INIT, head_reflog = STRBUF_INIT;
+       int ret;
+
+       if (!opts->head_name)
+               return 0; /* nothing to move back to */
+
+       if (!opts->onto)
+               BUG("move_to_original_branch without onto");
+
+       strbuf_addf(&orig_head_reflog, "rebase finished: %s onto %s",
+                   opts->head_name, oid_to_hex(&opts->onto->object.oid));
+       strbuf_addf(&head_reflog, "rebase finished: returning to %s",
+                   opts->head_name);
+       ret = reset_head(NULL, "", opts->head_name, RESET_HEAD_REFS_ONLY,
+                        orig_head_reflog.buf, head_reflog.buf);
+
+       strbuf_release(&orig_head_reflog);
+       strbuf_release(&head_reflog);
+       return ret;
+}
+
 static const char *resolvemsg =
 N_("Resolve all conflicts manually, mark them as resolved with\n"
 "\"git add/rm <conflicted_files>\", then run \"git rebase --continue\".\n"
@@ -341,6 +525,126 @@ N_("Resolve all conflicts manually, mark them as resolved with\n"
 "To abort and get back to the state before \"git rebase\", run "
 "\"git rebase --abort\".");
 
+static int run_am(struct rebase_options *opts)
+{
+       struct child_process am = CHILD_PROCESS_INIT;
+       struct child_process format_patch = CHILD_PROCESS_INIT;
+       struct strbuf revisions = STRBUF_INIT;
+       int status;
+       char *rebased_patches;
+
+       am.git_cmd = 1;
+       argv_array_push(&am.args, "am");
+
+       if (opts->action && !strcmp("continue", opts->action)) {
+               argv_array_push(&am.args, "--resolved");
+               argv_array_pushf(&am.args, "--resolvemsg=%s", resolvemsg);
+               if (opts->gpg_sign_opt)
+                       argv_array_push(&am.args, opts->gpg_sign_opt);
+               status = run_command(&am);
+               if (status)
+                       return status;
+
+               return move_to_original_branch(opts);
+       }
+       if (opts->action && !strcmp("skip", opts->action)) {
+               argv_array_push(&am.args, "--skip");
+               argv_array_pushf(&am.args, "--resolvemsg=%s", resolvemsg);
+               status = run_command(&am);
+               if (status)
+                       return status;
+
+               return move_to_original_branch(opts);
+       }
+       if (opts->action && !strcmp("show-current-patch", opts->action)) {
+               argv_array_push(&am.args, "--show-current-patch");
+               return run_command(&am);
+       }
+
+       strbuf_addf(&revisions, "%s...%s",
+                   oid_to_hex(opts->root ?
+                              /* this is now equivalent to !opts->upstream */
+                              &opts->onto->object.oid :
+                              &opts->upstream->object.oid),
+                   oid_to_hex(&opts->orig_head));
+
+       rebased_patches = xstrdup(git_path("rebased-patches"));
+       format_patch.out = open(rebased_patches,
+                               O_WRONLY | O_CREAT | O_TRUNC, 0666);
+       if (format_patch.out < 0) {
+               status = error_errno(_("could not open '%s' for writing"),
+                                    rebased_patches);
+               free(rebased_patches);
+               argv_array_clear(&am.args);
+               return status;
+       }
+
+       format_patch.git_cmd = 1;
+       argv_array_pushl(&format_patch.args, "format-patch", "-k", "--stdout",
+                        "--full-index", "--cherry-pick", "--right-only",
+                        "--src-prefix=a/", "--dst-prefix=b/", "--no-renames",
+                        "--no-cover-letter", "--pretty=mboxrd", "--topo-order", NULL);
+       if (opts->git_format_patch_opt.len)
+               argv_array_split(&format_patch.args,
+                                opts->git_format_patch_opt.buf);
+       argv_array_push(&format_patch.args, revisions.buf);
+       if (opts->restrict_revision)
+               argv_array_pushf(&format_patch.args, "^%s",
+                                oid_to_hex(&opts->restrict_revision->object.oid));
+
+       status = run_command(&format_patch);
+       if (status) {
+               unlink(rebased_patches);
+               free(rebased_patches);
+               argv_array_clear(&am.args);
+
+               reset_head(&opts->orig_head, "checkout", opts->head_name, 0,
+                          "HEAD", NULL);
+               error(_("\ngit encountered an error while preparing the "
+                       "patches to replay\n"
+                       "these revisions:\n"
+                       "\n    %s\n\n"
+                       "As a result, git cannot rebase them."),
+                     opts->revisions);
+
+               strbuf_release(&revisions);
+               return status;
+       }
+       strbuf_release(&revisions);
+
+       am.in = open(rebased_patches, O_RDONLY);
+       if (am.in < 0) {
+               status = error_errno(_("could not open '%s' for reading"),
+                                    rebased_patches);
+               free(rebased_patches);
+               argv_array_clear(&am.args);
+               return status;
+       }
+
+       argv_array_pushv(&am.args, opts->git_am_opts.argv);
+       argv_array_push(&am.args, "--rebasing");
+       argv_array_pushf(&am.args, "--resolvemsg=%s", resolvemsg);
+       argv_array_push(&am.args, "--patch-format=mboxrd");
+       if (opts->allow_rerere_autoupdate > 0)
+               argv_array_push(&am.args, "--rerere-autoupdate");
+       else if (opts->allow_rerere_autoupdate == 0)
+               argv_array_push(&am.args, "--no-rerere-autoupdate");
+       if (opts->gpg_sign_opt)
+               argv_array_push(&am.args, opts->gpg_sign_opt);
+       status = run_command(&am);
+       unlink(rebased_patches);
+       free(rebased_patches);
+
+       if (!status) {
+               return move_to_original_branch(opts);
+       }
+
+       if (is_directory(opts->state_dir))
+               write_basic_state(opts);
+
+       return status;
+}
+
 static int run_specific_rebase(struct rebase_options *opts)
 {
        const char *argv[] = { NULL, NULL };
@@ -355,7 +659,8 @@ static int run_specific_rebase(struct rebase_options *opts)
                argv_array_pushf(&child.env_array, "GIT_CHERRY_PICK_HELP=%s",
                                 resolvemsg);
                if (!(opts->flags & REBASE_INTERACTIVE_EXPLICIT)) {
-                       argv_array_push(&child.env_array, "GIT_EDITOR=:");
+                       argv_array_push(&child.env_array,
+                                       "GIT_SEQUENCE_EDITOR=:");
                        opts->autosquash = 0;
                }
 
@@ -423,6 +728,11 @@ static int run_specific_rebase(struct rebase_options *opts)
                goto finished_rebase;
        }
 
+       if (opts->type == REBASE_AM) {
+               status = run_am(opts);
+               goto finished_rebase;
+       }
+
        add_var(&script_snippet, "GIT_DIR", absolute_path(get_git_dir()));
        add_var(&script_snippet, "state_dir", opts->state_dir);
 
@@ -478,7 +788,7 @@ static int run_specific_rebase(struct rebase_options *opts)
        if (is_interactive(opts) &&
            !(opts->flags & REBASE_INTERACTIVE_EXPLICIT)) {
                strbuf_addstr(&script_snippet,
-                             "GIT_EDITOR=:; export GIT_EDITOR; ");
+                             "GIT_SEQUENCE_EDITOR=:; export GIT_SEQUENCE_EDITOR; ");
                opts->autosquash = 0;
        }
 
@@ -487,10 +797,6 @@ static int run_specific_rebase(struct rebase_options *opts)
                backend = "git-rebase--am";
                backend_func = "git_rebase__am";
                break;
-       case REBASE_MERGE:
-               backend = "git-rebase--merge";
-               backend_func = "git_rebase__merge";
-               break;
        case REBASE_PRESERVE_MERGES:
                backend = "git-rebase--preserve-merges";
                backend_func = "git_rebase__preserve_merges";
@@ -529,131 +835,6 @@ static int run_specific_rebase(struct rebase_options *opts)
        return status ? -1 : 0;
 }
 
-#define GIT_REFLOG_ACTION_ENVIRONMENT "GIT_REFLOG_ACTION"
-
-#define RESET_HEAD_DETACH (1<<0)
-#define RESET_HEAD_HARD (1<<1)
-#define RESET_HEAD_RUN_POST_CHECKOUT_HOOK (1<<2)
-
-static int reset_head(struct object_id *oid, const char *action,
-                     const char *switch_to_branch, unsigned flags,
-                     const char *reflog_orig_head, const char *reflog_head)
-{
-       unsigned detach_head = flags & RESET_HEAD_DETACH;
-       unsigned reset_hard = flags & RESET_HEAD_HARD;
-       unsigned run_hook = flags & RESET_HEAD_RUN_POST_CHECKOUT_HOOK;
-       struct object_id head_oid;
-       struct tree_desc desc[2] = { { NULL }, { NULL } };
-       struct lock_file lock = LOCK_INIT;
-       struct unpack_trees_options unpack_tree_opts;
-       struct tree *tree;
-       const char *reflog_action;
-       struct strbuf msg = STRBUF_INIT;
-       size_t prefix_len;
-       struct object_id *orig = NULL, oid_orig,
-               *old_orig = NULL, oid_old_orig;
-       int ret = 0, nr = 0;
-
-       if (switch_to_branch && !starts_with(switch_to_branch, "refs/"))
-               BUG("Not a fully qualified branch: '%s'", switch_to_branch);
-
-       if (hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0) {
-               ret = -1;
-               goto leave_reset_head;
-       }
-
-       if ((!oid || !reset_hard) && get_oid("HEAD", &head_oid)) {
-               ret = error(_("could not determine HEAD revision"));
-               goto leave_reset_head;
-       }
-
-       if (!oid)
-               oid = &head_oid;
-
-       memset(&unpack_tree_opts, 0, sizeof(unpack_tree_opts));
-       setup_unpack_trees_porcelain(&unpack_tree_opts, action);
-       unpack_tree_opts.head_idx = 1;
-       unpack_tree_opts.src_index = the_repository->index;
-       unpack_tree_opts.dst_index = the_repository->index;
-       unpack_tree_opts.fn = reset_hard ? oneway_merge : twoway_merge;
-       unpack_tree_opts.update = 1;
-       unpack_tree_opts.merge = 1;
-       if (!detach_head)
-               unpack_tree_opts.reset = 1;
-
-       if (read_index_unmerged(the_repository->index) < 0) {
-               ret = error(_("could not read index"));
-               goto leave_reset_head;
-       }
-
-       if (!reset_hard && !fill_tree_descriptor(&desc[nr++], &head_oid)) {
-               ret = error(_("failed to find tree of %s"),
-                           oid_to_hex(&head_oid));
-               goto leave_reset_head;
-       }
-
-       if (!fill_tree_descriptor(&desc[nr++], oid)) {
-               ret = error(_("failed to find tree of %s"), oid_to_hex(oid));
-               goto leave_reset_head;
-       }
-
-       if (unpack_trees(nr, desc, &unpack_tree_opts)) {
-               ret = -1;
-               goto leave_reset_head;
-       }
-
-       tree = parse_tree_indirect(oid);
-       prime_cache_tree(the_repository, the_repository->index, tree);
-
-       if (write_locked_index(the_repository->index, &lock, COMMIT_LOCK) < 0) {
-               ret = error(_("could not write index"));
-               goto leave_reset_head;
-       }
-
-       reflog_action = getenv(GIT_REFLOG_ACTION_ENVIRONMENT);
-       strbuf_addf(&msg, "%s: ", reflog_action ? reflog_action : "rebase");
-       prefix_len = msg.len;
-
-       if (!get_oid("ORIG_HEAD", &oid_old_orig))
-               old_orig = &oid_old_orig;
-       if (!get_oid("HEAD", &oid_orig)) {
-               orig = &oid_orig;
-               if (!reflog_orig_head) {
-                       strbuf_addstr(&msg, "updating ORIG_HEAD");
-                       reflog_orig_head = msg.buf;
-               }
-               update_ref(reflog_orig_head, "ORIG_HEAD", orig, old_orig, 0,
-                          UPDATE_REFS_MSG_ON_ERR);
-       } else if (old_orig)
-               delete_ref(NULL, "ORIG_HEAD", old_orig, 0);
-       if (!reflog_head) {
-               strbuf_setlen(&msg, prefix_len);
-               strbuf_addstr(&msg, "updating HEAD");
-               reflog_head = msg.buf;
-       }
-       if (!switch_to_branch)
-               ret = update_ref(reflog_head, "HEAD", oid, orig,
-                                detach_head ? REF_NO_DEREF : 0,
-                                UPDATE_REFS_MSG_ON_ERR);
-       else {
-               ret = create_symref("HEAD", switch_to_branch, msg.buf);
-               if (!ret)
-                       ret = update_ref(reflog_head, "HEAD", oid, NULL, 0,
-                                        UPDATE_REFS_MSG_ON_ERR);
-       }
-       if (run_hook)
-               run_hook_le(NULL, "post-checkout",
-                           oid_to_hex(orig ? orig : &null_oid),
-                           oid_to_hex(oid), "1", NULL);
-
-leave_reset_head:
-       strbuf_release(&msg);
-       rollback_lock_file(&lock);
-       while (nr)
-               free((void *)desc[--nr].buffer);
-       return ret;
-}
-
 static int rebase_config(const char *var, const char *value, void *data)
 {
        struct rebase_options *opts = data;
@@ -824,6 +1005,19 @@ static void set_reflog_action(struct rebase_options *options)
        strbuf_release(&buf);
 }
 
+static int check_exec_cmd(const char *cmd)
+{
+       if (strchr(cmd, '\n'))
+               return error(_("exec commands cannot contain newlines"));
+
+       /* Does the command consist purely of whitespace? */
+       if (!cmd[strspn(cmd, " \t\r\f\v")])
+               return error(_("empty exec command"));
+
+       return 0;
+}
+
+
 int cmd_rebase(int argc, const char **argv, const char *prefix)
 {
        struct rebase_options options = {
@@ -1053,13 +1247,12 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                        die(_("Cannot read HEAD"));
 
                fd = hold_locked_index(&lock_file, 0);
-               if (read_index(the_repository->index) < 0)
+               if (repo_read_index(the_repository) < 0)
                        die(_("could not read index"));
                refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL,
                              NULL);
                if (0 <= fd)
-                       update_index_if_able(the_repository->index,
-                                            &lock_file);
+                       repo_update_index_if_able(the_repository, &lock_file);
                rollback_lock_file(&lock_file);
 
                if (has_unstaged_changes(the_repository, 1)) {
@@ -1168,6 +1361,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                }
        }
 
+       for (i = 0; i < exec.nr; i++)
+               if (check_exec_cmd(exec.items[i].string))
+                       exit(1);
+
        if (!(options.flags & REBASE_NO_QUIET))
                argv_array_push(&options.git_am_opts, "-q");
 
@@ -1232,6 +1429,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                }
        }
 
+       if (options.type == REBASE_MERGE)
+               imply_interactive(&options, "--merge");
+
        if (options.root && !options.onto_name)
                imply_interactive(&options, "--root without --onto");
 
@@ -1264,14 +1464,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                                break;
 
                if (is_interactive(&options) && i >= 0)
-                       die(_("error: cannot combine interactive options "
-                             "(--interactive, --exec, --rebase-merges, "
-                             "--preserve-merges, --keep-empty, --root + "
-                             "--onto) with am options (%s)"), buf.buf);
-               if (options.type == REBASE_MERGE && i >= 0)
-                       die(_("error: cannot combine merge options (--merge, "
-                             "--strategy, --strategy-option) with am options "
-                             "(%s)"), buf.buf);
+                       die(_("cannot combine am options with either "
+                             "interactive or merge options"));
        }
 
        if (options.signoff) {
@@ -1289,7 +1483,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                 *       git-rebase.txt caveats with "unless you know what you are doing"
                 */
                if (options.rebase_merges)
-                       die(_("error: cannot combine '--preserve-merges' with "
+                       die(_("cannot combine '--preserve-merges' with "
                              "'--rebase-merges'"));
 
                if (options.reschedule_failed_exec)
@@ -1299,10 +1493,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 
        if (options.rebase_merges) {
                if (strategy_options.nr)
-                       die(_("error: cannot combine '--rebase-merges' with "
+                       die(_("cannot combine '--rebase-merges' with "
                              "'--strategy-option'"));
                if (options.strategy)
-                       die(_("error: cannot combine '--rebase-merges' with "
+                       die(_("cannot combine '--rebase-merges' with "
                              "'--strategy'"));
        }
 
@@ -1414,7 +1608,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                        get_fork_point(options.upstream_name, head);
        }
 
-       if (read_index(the_repository->index) < 0)
+       if (repo_read_index(the_repository) < 0)
                die(_("could not read index"));
 
        if (options.autostash) {
@@ -1424,7 +1618,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                fd = hold_locked_index(&lock_file, 0);
                refresh_cache(REFRESH_QUIET);
                if (0 <= fd)
-                       update_index_if_able(&the_index, &lock_file);
+                       repo_update_index_if_able(the_repository, &lock_file);
                rollback_lock_file(&lock_file);
 
                if (has_unstaged_changes(the_repository, 1) ||
@@ -1469,7 +1663,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                        putchar('\n');
 
                        if (discard_index(the_repository->index) < 0 ||
-                               read_index(the_repository->index) < 0)
+                               repo_read_index(the_repository) < 0)
                                die(_("could not read index"));
                }
        }
index 33187bd8e90252c283b7154bc7026e01d4e754ef..d58b7750b6b46565ca4ebb8299e5260943aa364e 100644 (file)
@@ -1569,30 +1569,29 @@ static void queue_commands_from_cert(struct command **tail,
        }
 }
 
-static struct command *read_head_info(struct oid_array *shallow)
+static struct command *read_head_info(struct packet_reader *reader,
+                                     struct oid_array *shallow)
 {
        struct command *commands = NULL;
        struct command **p = &commands;
        for (;;) {
-               char *line;
-               int len, linelen;
+               int linelen;
 
-               line = packet_read_line(0, &len);
-               if (!line)
+               if (packet_reader_read(reader) != PACKET_READ_NORMAL)
                        break;
 
-               if (len > 8 && starts_with(line, "shallow ")) {
+               if (reader->pktlen > 8 && starts_with(reader->line, "shallow ")) {
                        struct object_id oid;
-                       if (get_oid_hex(line + 8, &oid))
+                       if (get_oid_hex(reader->line + 8, &oid))
                                die("protocol error: expected shallow sha, got '%s'",
-                                   line + 8);
+                                   reader->line + 8);
                        oid_array_append(shallow, &oid);
                        continue;
                }
 
-               linelen = strlen(line);
-               if (linelen < len) {
-                       const char *feature_list = line + linelen + 1;
+               linelen = strlen(reader->line);
+               if (linelen < reader->pktlen) {
+                       const char *feature_list = reader->line + linelen + 1;
                        if (parse_feature_request(feature_list, "report-status"))
                                report_status = 1;
                        if (parse_feature_request(feature_list, "side-band-64k"))
@@ -1607,28 +1606,32 @@ static struct command *read_head_info(struct oid_array *shallow)
                                use_push_options = 1;
                }
 
-               if (!strcmp(line, "push-cert")) {
+               if (!strcmp(reader->line, "push-cert")) {
                        int true_flush = 0;
-                       char certbuf[1024];
+                       int saved_options = reader->options;
+                       reader->options &= ~PACKET_READ_CHOMP_NEWLINE;
 
                        for (;;) {
-                               len = packet_read(0, NULL, NULL,
-                                                 certbuf, sizeof(certbuf), 0);
-                               if (!len) {
+                               packet_reader_read(reader);
+                               if (reader->status == PACKET_READ_FLUSH) {
                                        true_flush = 1;
                                        break;
                                }
-                               if (!strcmp(certbuf, "push-cert-end\n"))
+                               if (reader->status != PACKET_READ_NORMAL) {
+                                       die("protocol error: got an unexpected packet");
+                               }
+                               if (!strcmp(reader->line, "push-cert-end\n"))
                                        break; /* end of cert */
-                               strbuf_addstr(&push_cert, certbuf);
+                               strbuf_addstr(&push_cert, reader->line);
                        }
+                       reader->options = saved_options;
 
                        if (true_flush)
                                break;
                        continue;
                }
 
-               p = queue_command(p, line, linelen);
+               p = queue_command(p, reader->line, linelen);
        }
 
        if (push_cert.len)
@@ -1637,18 +1640,14 @@ static struct command *read_head_info(struct oid_array *shallow)
        return commands;
 }
 
-static void read_push_options(struct string_list *options)
+static void read_push_options(struct packet_reader *reader,
+                             struct string_list *options)
 {
        while (1) {
-               char *line;
-               int len;
-
-               line = packet_read_line(0, &len);
-
-               if (!line)
+               if (packet_reader_read(reader) != PACKET_READ_NORMAL)
                        break;
 
-               string_list_append(options, line);
+               string_list_append(options, reader->line);
        }
 }
 
@@ -1924,6 +1923,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
        struct oid_array shallow = OID_ARRAY_INIT;
        struct oid_array ref = OID_ARRAY_INIT;
        struct shallow_info si;
+       struct packet_reader reader;
 
        struct option options[] = {
                OPT__QUIET(&quiet, N_("quiet")),
@@ -1986,12 +1986,16 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
        if (advertise_refs)
                return 0;
 
-       if ((commands = read_head_info(&shallow)) != NULL) {
+       packet_reader_init(&reader, 0, NULL, 0,
+                          PACKET_READ_CHOMP_NEWLINE |
+                          PACKET_READ_DIE_ON_ERR_PACKET);
+
+       if ((commands = read_head_info(&reader, &shallow)) != NULL) {
                const char *unpack_status = NULL;
                struct string_list push_options = STRING_LIST_INIT_DUP;
 
                if (use_push_options)
-                       read_push_options(&push_options);
+                       read_push_options(&reader, &push_options);
                if (!check_cert_push_options(&push_options)) {
                        struct command *cmd;
                        for (cmd = commands; cmd; cmd = cmd->next)
index 1f1010e2d9aec2b95487007ec30509fcbda605d6..4d3430900d06d82e8e06441f8fdfea00f7aecf78 100644 (file)
@@ -94,7 +94,7 @@ static int tree_is_complete(const struct object_id *oid)
        init_tree_desc(&desc, tree->buffer, tree->size);
        complete = 1;
        while (tree_entry(&desc, &entry)) {
-               if (!has_sha1_file(entry.oid.hash) ||
+               if (!has_object_file(&entry.oid) ||
                    (S_ISDIR(entry.mode) && !tree_is_complete(&entry.oid))) {
                        tree->object.flags |= INCOMPLETE;
                        complete = 0;
index affcdfb4169899c2affee51593f0453d5d9b9add..5b80b7f21141d6f85d8444d669dffe289f3a60f5 100644 (file)
@@ -295,7 +295,7 @@ static int import_object(struct object_id *oid, enum object_type type,
                        close(fd);
                        return -1;
                }
-               if (index_fd(&the_index, oid, fd, &st, type, NULL, flags) < 0)
+               if (index_fd(the_repository->index, oid, fd, &st, type, NULL, flags) < 0)
                        return error(_("unable to write object to database"));
                /* index_fd close()s fd for us */
        }
index 59898c972eee5e8065c2a68b7c937cc3af11f513..4d18a461fab631dd752adec3b95197a3a2657a62 100644 (file)
@@ -7,6 +7,7 @@
  *
  * Copyright (c) 2005, 2006 Linus Torvalds and Junio C Hamano
  */
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "builtin.h"
 #include "config.h"
 #include "lockfile.h"
index 51e9e1267e848b345ff7c78fe036e7e66bb6f055..5b5b6dbb1c9b6f9893f3d0420c99655eb19501a8 100644 (file)
@@ -197,7 +197,8 @@ static void finish_commit(struct commit *commit, void *data)
                free_commit_list(commit->parents);
                commit->parents = NULL;
        }
-       free_commit_buffer(commit);
+       free_commit_buffer(the_repository->parsed_objects,
+                          commit);
 }
 
 static inline void finish_object__ma(struct object *obj)
@@ -545,7 +546,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
        if (prepare_revision_walk(&revs))
                die("revision walk setup failed");
        if (revs.tree_objects)
-               mark_edges_uninteresting(&revs, show_edge);
+               mark_edges_uninteresting(&revs, show_edge, 0);
 
        if (bisect_list) {
                int reaches, all;
index 10d4dab894e25a73d6a761205ce53c88019a4a8b..f8bbe6d47ec397f55bec62d6a71bc6db8f08b54b 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright (C) Linus Torvalds, 2005
  */
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "cache.h"
 #include "config.h"
 #include "commit.h"
@@ -933,7 +934,8 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
                        name++;
                        type = REVERSED;
                }
-               if (!get_oid_with_context(name, flags, &oid, &unused)) {
+               if (!get_oid_with_context(the_repository, name,
+                                         flags, &oid, &unused)) {
                        if (verify)
                                revs_count++;
                        else
index 17086d3d97c536522720c589ea8f35d366536ea8..db85b339823cc0aa5ab5d03220335d4e4240d656 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright (C) Linus Torvalds 2006
  */
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "builtin.h"
 #include "config.h"
 #include "lockfile.h"
index 8e3c7490f70df79497ee064ab13c0164de11fe9e..098ebf22d0d65a6f98606c7ea567467641976f6b 100644 (file)
@@ -250,7 +250,8 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
 
        packet_reader_init(&reader, fd[0], NULL, 0,
                           PACKET_READ_CHOMP_NEWLINE |
-                          PACKET_READ_GENTLE_ON_EOF);
+                          PACKET_READ_GENTLE_ON_EOF |
+                          PACKET_READ_DIE_ON_ERR_PACKET);
 
        switch (discover_version(&reader)) {
        case protocol_v2:
index ed888ffa48ce1d5ef80859b8f5b3bf1720e49abd..6a706c02a6f9782ee4abb289cfafe468253aca1f 100644 (file)
@@ -23,7 +23,7 @@ static void show_one(const char *refname, const struct object_id *oid)
        const char *hex;
        struct object_id peeled;
 
-       if (!has_sha1_file(oid->hash))
+       if (!has_object_file(oid))
                die("git show-ref: bad ref %s (%s)", refname,
                    oid_to_hex(oid));
 
index 0e140f176ce3b559478a5bc4245bf36905c543cf..b80fc4ba3d88b56436fa3f6b9a132bfe9e82b79b 100644 (file)
@@ -1,3 +1,4 @@
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "builtin.h"
 #include "repository.h"
 #include "cache.h"
index e19da77edcaa024cc2bffc6fa8818c2b1cf0d4b6..02ace602b9ae23d6ab74abac016948410b30fcde 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright (C) Linus Torvalds, 2005
  */
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "cache.h"
 #include "config.h"
 #include "lockfile.h"
index cdcbf8264e8c6e9b56977b99ad28160754d8fb7c..3d46d22ee5261d2cf1233913b7b544e812c26122 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright (C) Linus Torvalds, 2005
  */
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "builtin.h"
 #include "cache.h"
 #include "config.h"
index 409ecb566b3c863e453d10650d1bb21955e2dee3..39ee7d6107c15f3e5e439992bea8a8f3413aae05 100644 (file)
@@ -67,7 +67,7 @@ static int already_written(struct bulk_checkin_state *state, struct object_id *o
        int i;
 
        /* The object may already exist in the repository */
-       if (has_sha1_file(oid->hash))
+       if (has_object_file(oid))
                return 1;
 
        /* Might want to keep the list sorted */
index 37b1daa6918bafb6b21faba47d25fcc6433698ba..b45666c49b1c19a63d816527a761d0177d9633ce 100644 (file)
--- a/bundle.c
+++ b/bundle.c
@@ -424,8 +424,8 @@ static int write_bundle_refs(int bundle_fd, struct rev_info *revs)
        return ref_count;
 }
 
-int create_bundle(struct repository *r, struct bundle_header *header,
-                 const char *path, int argc, const char **argv)
+int create_bundle(struct repository *r, const char *path,
+                 int argc, const char **argv)
 {
        struct lock_file lock = LOCK_INIT;
        int bundle_fd = -1;
index 781e6f5c3a837ac65e6911ec5e0ae458b8b6a5c7..37c37d7f653c68ab6752fab8203b59783e2f5c40 100644 (file)
--- a/bundle.h
+++ b/bundle.h
@@ -18,8 +18,8 @@ struct bundle_header {
 
 int is_bundle(const char *path, int quiet);
 int read_bundle_header(const char *path, struct bundle_header *header);
-int create_bundle(struct repository *r, struct bundle_header *header,
-                 const char *path, int argc, const char **argv);
+int create_bundle(struct repository *r, const char *path,
+                 int argc, const char **argv);
 int verify_bundle(struct repository *r, struct bundle_header *header, int verbose);
 #define BUNDLE_VERBOSE 1
 int unbundle(struct repository *r, struct bundle_header *header,
index c4b8a1fa16d4e1376c1df3f2784db32c20001314..b13bfaf71e9e1554173beca4cfd8acf5929bc9ce 100644 (file)
@@ -225,7 +225,7 @@ int cache_tree_fully_valid(struct cache_tree *it)
        int i;
        if (!it)
                return 0;
-       if (it->entry_count < 0 || !has_sha1_file(it->oid.hash))
+       if (it->entry_count < 0 || !has_object_file(&it->oid))
                return 0;
        for (i = 0; i < it->subtree_nr; i++) {
                if (!cache_tree_fully_valid(it->down[i]->cache_tree))
@@ -253,7 +253,7 @@ static int update_one(struct cache_tree *it,
 
        *skip_count = 0;
 
-       if (0 <= it->entry_count && has_sha1_file(it->oid.hash))
+       if (0 <= it->entry_count && has_object_file(&it->oid))
                return it->entry_count;
 
        /*
index 326209198b60fa8a6fdbd171c46132b8a5062e04..757bbc48bca155fe539d07a268087b96ae7aa7f6 100644 (file)
@@ -51,7 +51,7 @@ void prime_cache_tree(struct repository *, struct index_state *, struct tree *);
 
 int cache_tree_matches_traversal(struct cache_tree *, struct name_entry *ent, struct traverse_info *info);
 
-#ifndef NO_THE_INDEX_COMPATIBILITY_MACROS
+#ifdef USE_THE_INDEX_COMPATIBILITY_MACROS
 static inline int write_cache_as_tree(struct object_id *oid, int flags, const char *prefix)
 {
        return write_index_as_tree(oid, &the_index, get_index_file(), flags, prefix);
diff --git a/cache.h b/cache.h
index 009e8b3b150eaab7c5c3705c0d466773743dbe0f..27fe635f622c49e2a21ffcb91d3113d3b3fbad8c 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -348,8 +348,6 @@ struct index_state {
        struct mem_pool *ce_mem_pool;
 };
 
-extern struct index_state the_index;
-
 /* Name hashing */
 extern int test_lazy_init_name_hash(struct index_state *istate, int try_threaded);
 extern void add_name_hash(struct index_state *istate, struct cache_entry *ce);
@@ -411,18 +409,20 @@ struct cache_entry *dup_cache_entry(const struct cache_entry *ce, struct index_s
  */
 void validate_cache_entries(const struct index_state *istate);
 
-#ifndef NO_THE_INDEX_COMPATIBILITY_MACROS
+#ifdef USE_THE_INDEX_COMPATIBILITY_MACROS
+extern struct index_state the_index;
+
 #define active_cache (the_index.cache)
 #define active_nr (the_index.cache_nr)
 #define active_alloc (the_index.cache_alloc)
 #define active_cache_changed (the_index.cache_changed)
 #define active_cache_tree (the_index.cache_tree)
 
-#define read_cache() read_index(&the_index)
+#define read_cache() repo_read_index(the_repository)
 #define read_cache_from(path) read_index_from(&the_index, (path), (get_git_dir()))
-#define read_cache_preload(pathspec) read_index_preload(&the_index, (pathspec), 0)
+#define read_cache_preload(pathspec) repo_read_index_preload(the_repository, (pathspec), 0)
 #define is_cache_unborn() is_index_unborn(&the_index)
-#define read_cache_unmerged() read_index_unmerged(&the_index)
+#define read_cache_unmerged() repo_read_index_unmerged(the_repository)
 #define discard_cache() discard_index(&the_index)
 #define unmerged_cache() unmerged_index(&the_index)
 #define cache_name_pos(name, namelen) index_name_pos(&the_index,(name),(namelen))
@@ -443,6 +443,7 @@ void validate_cache_entries(const struct index_state *istate);
 #define unmerge_cache_entry_at(at) unmerge_index_entry_at(&the_index, at)
 #define unmerge_cache(pathspec) unmerge_index(&the_index, pathspec)
 #define read_blob_data_from_cache(path, sz) read_blob_data_from_index(&the_index, (path), (sz))
+#define hold_locked_index(lock_file, flags) repo_hold_locked_index(the_repository, (lock_file), (flags))
 #endif
 
 #define TYPE_BITS 3
@@ -670,19 +671,14 @@ extern int daemonize(void);
 
 /* Initialize and use the cache information */
 struct lock_file;
-extern int read_index(struct index_state *);
 extern void preload_index(struct index_state *index,
                          const struct pathspec *pathspec,
                          unsigned int refresh_flags);
-extern int read_index_preload(struct index_state *,
-                             const struct pathspec *pathspec,
-                             unsigned int refresh_flags);
 extern int do_read_index(struct index_state *istate, const char *path,
                         int must_exist); /* for testting only! */
 extern int read_index_from(struct index_state *, const char *path,
                           const char *gitdir);
 extern int is_index_unborn(struct index_state *);
-extern int read_index_unmerged(struct index_state *);
 
 /* For use with `write_locked_index()`. */
 #define COMMIT_LOCK            (1 << 0)
@@ -720,9 +716,9 @@ extern int unmerged_index(const struct index_state *);
  * provided, the space-separated list of files that differ will be appended
  * to it.
  */
-extern int index_has_changes(struct index_state *istate,
-                            struct tree *tree,
-                            struct strbuf *sb);
+extern int repo_index_has_changes(struct repository *repo,
+                                 struct tree *tree,
+                                 struct strbuf *sb);
 
 extern int verify_path(const char *path, unsigned mode);
 extern int strcmp_offset(const char *s1, const char *s2, size_t *first_change);
@@ -755,6 +751,7 @@ extern int index_name_pos(const struct index_state *, const char *name, int name
 #define ADD_CACHE_JUST_APPEND 8                /* Append only; tree.c::read_tree() */
 #define ADD_CACHE_NEW_ONLY 16          /* Do not replace existing ones */
 #define ADD_CACHE_KEEP_CACHE_TREE 32   /* Do not invalidate cache-tree */
+#define ADD_CACHE_RENORMALIZE 64        /* Pass along HASH_RENORMALIZE */
 extern int add_index_entry(struct index_state *, struct cache_entry *ce, int option);
 extern void rename_index_entry_at(struct index_state *, int pos, const char *new_name);
 
@@ -837,13 +834,6 @@ extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
 extern int refresh_index(struct index_state *, unsigned int flags, const struct pathspec *pathspec, char *seen, const char *header_msg);
 extern struct cache_entry *refresh_cache_entry(struct index_state *, struct cache_entry *, unsigned int);
 
-/*
- * Opportunistically update the index but do not complain if we can't.
- * The lockfile is always committed or rolled back.
- */
-extern void update_index_if_able(struct index_state *, struct lock_file *);
-
-extern int hold_locked_index(struct lock_file *, int);
 extern void set_alternate_index_output(const char *);
 
 extern int verify_index_checksum;
@@ -1281,8 +1271,8 @@ extern char *xdg_cache_home(const char *filename);
 
 extern int git_open_cloexec(const char *name, int flags);
 #define git_open(name) git_open_cloexec(name, O_RDONLY)
-extern int unpack_sha1_header(git_zstream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz);
-extern int parse_sha1_header(const char *hdr, unsigned long *sizep);
+extern int unpack_loose_header(git_zstream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz);
+extern int parse_loose_header(const char *hdr, unsigned long *sizep);
 
 extern int check_object_signature(const struct object_id *oid, void *buf, unsigned long size, const char *type);
 
@@ -1344,6 +1334,24 @@ struct object_context {
        GET_OID_TREE | GET_OID_TREEISH | \
        GET_OID_BLOB)
 
+enum get_oid_result {
+       FOUND = 0,
+       MISSING_OBJECT = -1, /* The requested object is missing */
+       SHORT_NAME_AMBIGUOUS = -2,
+       /* The following only apply when symlinks are followed */
+       DANGLING_SYMLINK = -4, /*
+                               * The initial symlink is there, but
+                               * (transitively) points to a missing
+                               * in-tree file
+                               */
+       SYMLINK_LOOP = -5,
+       NOT_DIR = -6, /*
+                      * Somewhere along the symlink chain, a path is
+                      * requested which contains a file as a
+                      * non-final element.
+                      */
+};
+
 extern int get_oid(const char *str, struct object_id *oid);
 extern int get_oid_commit(const char *str, struct object_id *oid);
 extern int get_oid_committish(const char *str, struct object_id *oid);
@@ -1351,8 +1359,9 @@ extern int get_oid_tree(const char *str, struct object_id *oid);
 extern int get_oid_treeish(const char *str, struct object_id *oid);
 extern int get_oid_blob(const char *str, struct object_id *oid);
 extern void maybe_die_on_misspelt_object_name(const char *name, const char *prefix);
-extern int get_oid_with_context(const char *str, unsigned flags, struct object_id *oid, struct object_context *oc);
-
+extern enum get_oid_result get_oid_with_context(struct repository *repo, const char *str,
+                               unsigned flags, struct object_id *oid,
+                               struct object_context *oc);
 
 typedef int each_abbrev_fn(const struct object_id *oid, void *);
 extern int for_each_abbrev(const char *prefix, each_abbrev_fn, void *);
@@ -1454,6 +1463,7 @@ extern struct object *peel_to_type(const char *name, int namelen,
 
 enum date_mode_type {
        DATE_NORMAL = 0,
+       DATE_HUMAN,
        DATE_RELATIVE,
        DATE_SHORT,
        DATE_ISO8601,
@@ -1479,7 +1489,9 @@ struct date_mode {
 struct date_mode *date_mode_from_type(enum date_mode_type type);
 
 const char *show_date(timestamp_t time, int timezone, const struct date_mode *mode);
-void show_date_relative(timestamp_t time, int tz, const struct timeval *now,
+void show_date_relative(timestamp_t time, const struct timeval *now,
+                       struct strbuf *timebuf);
+void show_date_human(timestamp_t time, int tz, const struct timeval *now,
                        struct strbuf *timebuf);
 int parse_date(const char *date, struct strbuf *out);
 int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset);
@@ -1607,7 +1619,7 @@ extern int odb_mkstemp(struct strbuf *temp_filename, const char *pattern);
 extern int odb_pack_keep(const char *name);
 
 /*
- * Set this to 0 to prevent sha1_object_info_extended() from fetching missing
+ * Set this to 0 to prevent oid_object_info_extended() from fetching missing
  * blobs. This has a difference only if extensions.partialClone is set.
  *
  * Its default value is 1.
@@ -1803,4 +1815,7 @@ void safe_create_dir(const char *dir, int share);
  */
 extern int print_sha1_ellipsis(void);
 
+/* Return 1 if the file is empty or does not exists, 0 otherwise. */
+extern int is_empty_or_missing_file(const char *filename);
+
 #endif /* CACHE_H */
index 06c3546e1ed4e1a78cea4d7a1801145066a895d8..608ff964dee0c15c2c2a97c15fc5a86d5138488a 100755 (executable)
@@ -3,7 +3,7 @@
 # Install dependencies required to build and test Git on Linux and macOS
 #
 
-. ${0%/*}/lib-travisci.sh
+. ${0%/*}/lib.sh
 
 P4WHENCE=http://filehost.perforce.com/perforce/r$LINUX_P4_VERSION
 LFSWHENCE=https://github.com/github/git-lfs/releases/download/v$LINUX_GIT_LFS_VERSION
@@ -37,9 +37,15 @@ osx-clang|osx-gcc)
        brew update --quiet
        # Uncomment this if you want to run perf tests:
        # brew install gnu-time
-       brew install git-lfs gettext
+       test -z "$BREW_INSTALL_PACKAGES" ||
+       brew install $BREW_INSTALL_PACKAGES
        brew link --force gettext
        brew install caskroom/cask/perforce
+       case "$jobname" in
+       osx-gcc)
+               brew link gcc@8
+               ;;
+       esac
        ;;
 StaticAnalysis)
        sudo apt-get -q update
diff --git a/ci/lib-travisci.sh b/ci/lib-travisci.sh
deleted file mode 100755 (executable)
index 69dff4d..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-# Library of functions shared by all CI scripts
-
-skip_branch_tip_with_tag () {
-       # Sometimes, a branch is pushed at the same time the tag that points
-       # at the same commit as the tip of the branch is pushed, and building
-       # both at the same time is a waste.
-       #
-       # Travis gives a tagname e.g. v2.14.0 in $TRAVIS_BRANCH when
-       # the build is triggered by a push to a tag.  Let's see if
-       # $TRAVIS_BRANCH is exactly at a tag, and if so, if it is
-       # different from $TRAVIS_BRANCH.  That way, we can tell if
-       # we are building the tip of a branch that is tagged and
-       # we can skip the build because we won't be skipping a build
-       # of a tag.
-
-       if TAG=$(git describe --exact-match "$TRAVIS_BRANCH" 2>/dev/null) &&
-               test "$TAG" != "$TRAVIS_BRANCH"
-       then
-               echo "$(tput setaf 2)Tip of $TRAVIS_BRANCH is exactly at $TAG$(tput sgr0)"
-               exit 0
-       fi
-}
-
-# Save some info about the current commit's tree, so we can skip the build
-# job if we encounter the same tree again and can provide a useful info
-# message.
-save_good_tree () {
-       echo "$(git rev-parse $TRAVIS_COMMIT^{tree}) $TRAVIS_COMMIT $TRAVIS_JOB_NUMBER $TRAVIS_JOB_ID" >>"$good_trees_file"
-       # limit the file size
-       tail -1000 "$good_trees_file" >"$good_trees_file".tmp
-       mv "$good_trees_file".tmp "$good_trees_file"
-}
-
-# Skip the build job if the same tree has already been built and tested
-# successfully before (e.g. because the branch got rebased, changing only
-# the commit messages).
-skip_good_tree () {
-       if ! good_tree_info="$(grep "^$(git rev-parse $TRAVIS_COMMIT^{tree}) " "$good_trees_file")"
-       then
-               # Haven't seen this tree yet, or no cached good trees file yet.
-               # Continue the build job.
-               return
-       fi
-
-       echo "$good_tree_info" | {
-               read tree prev_good_commit prev_good_job_number prev_good_job_id
-
-               if test "$TRAVIS_JOB_ID" = "$prev_good_job_id"
-               then
-                       cat <<-EOF
-                       $(tput setaf 2)Skipping build job for commit $TRAVIS_COMMIT.$(tput sgr0)
-                       This commit has already been built and tested successfully by this build job.
-                       To force a re-build delete the branch's cache and then hit 'Restart job'.
-                       EOF
-               else
-                       cat <<-EOF
-                       $(tput setaf 2)Skipping build job for commit $TRAVIS_COMMIT.$(tput sgr0)
-                       This commit's tree has already been built and tested successfully in build job $prev_good_job_number for commit $prev_good_commit.
-                       The log of that build job is available at https://travis-ci.org/$TRAVIS_REPO_SLUG/jobs/$prev_good_job_id
-                       To force a re-build delete the branch's cache and then hit 'Restart job'.
-                       EOF
-               fi
-       }
-
-       exit 0
-}
-
-check_unignored_build_artifacts ()
-{
-       ! git ls-files --other --exclude-standard --error-unmatch \
-               -- ':/*' 2>/dev/null ||
-       {
-               echo "$(tput setaf 1)error: found unignored build artifacts$(tput sgr0)"
-               false
-       }
-}
-
-# Set 'exit on error' for all CI scripts to let the caller know that
-# something went wrong.
-# Set tracing executed commands, primarily setting environment variables
-# and installing dependencies.
-set -ex
-
-cache_dir="$HOME/travis-cache"
-good_trees_file="$cache_dir/good-trees"
-
-mkdir -p "$cache_dir"
-
-skip_branch_tip_with_tag
-skip_good_tree
-
-if test -z "$jobname"
-then
-       jobname="$TRAVIS_OS_NAME-$CC"
-fi
-
-export DEVELOPER=1
-export DEFAULT_TEST_TARGET=prove
-export GIT_PROVE_OPTS="--timer --jobs 3 --state=failed,slow,save"
-export GIT_TEST_OPTS="--verbose-log -x --immediate"
-export GIT_TEST_CLONE_2GB=YesPlease
-if [ "$jobname" = linux-gcc ]; then
-       export CC=gcc-8
-fi
-
-case "$jobname" in
-linux-clang|linux-gcc)
-       export GIT_TEST_HTTPD=YesPlease
-
-       # The Linux build installs the defined dependency versions below.
-       # The OS X build installs the latest available versions. Keep that
-       # in mind when you encounter a broken OS X build!
-       export LINUX_P4_VERSION="16.2"
-       export LINUX_GIT_LFS_VERSION="1.5.2"
-
-       P4_PATH="$HOME/custom/p4"
-       GIT_LFS_PATH="$HOME/custom/git-lfs"
-       export PATH="$GIT_LFS_PATH:$P4_PATH:$PATH"
-       ;;
-osx-clang|osx-gcc)
-       # t9810 occasionally fails on Travis CI OS X
-       # t9816 occasionally fails with "TAP out of sequence errors" on
-       # Travis CI OS X
-       export GIT_SKIP_TESTS="t9810 t9816"
-       ;;
-GIT_TEST_GETTEXT_POISON)
-       export GIT_TEST_GETTEXT_POISON=YesPlease
-       ;;
-esac
diff --git a/ci/lib.sh b/ci/lib.sh
new file mode 100755 (executable)
index 0000000..16f4ecb
--- /dev/null
+++ b/ci/lib.sh
@@ -0,0 +1,188 @@
+# Library of functions shared by all CI scripts
+
+skip_branch_tip_with_tag () {
+       # Sometimes, a branch is pushed at the same time the tag that points
+       # at the same commit as the tip of the branch is pushed, and building
+       # both at the same time is a waste.
+       #
+       # When the build is triggered by a push to a tag, $CI_BRANCH will
+       # have that tagname, e.g. v2.14.0.  Let's see if $CI_BRANCH is
+       # exactly at a tag, and if so, if it is different from $CI_BRANCH.
+       # That way, we can tell if we are building the tip of a branch that
+       # is tagged and we can skip the build because we won't be skipping a
+       # build of a tag.
+
+       if TAG=$(git describe --exact-match "$CI_BRANCH" 2>/dev/null) &&
+               test "$TAG" != "$CI_BRANCH"
+       then
+               echo "$(tput setaf 2)Tip of $CI_BRANCH is exactly at $TAG$(tput sgr0)"
+               exit 0
+       fi
+}
+
+# Save some info about the current commit's tree, so we can skip the build
+# job if we encounter the same tree again and can provide a useful info
+# message.
+save_good_tree () {
+       echo "$(git rev-parse $CI_COMMIT^{tree}) $CI_COMMIT $CI_JOB_NUMBER $CI_JOB_ID" >>"$good_trees_file"
+       # limit the file size
+       tail -1000 "$good_trees_file" >"$good_trees_file".tmp
+       mv "$good_trees_file".tmp "$good_trees_file"
+}
+
+# Skip the build job if the same tree has already been built and tested
+# successfully before (e.g. because the branch got rebased, changing only
+# the commit messages).
+skip_good_tree () {
+       if ! good_tree_info="$(grep "^$(git rev-parse $CI_COMMIT^{tree}) " "$good_trees_file")"
+       then
+               # Haven't seen this tree yet, or no cached good trees file yet.
+               # Continue the build job.
+               return
+       fi
+
+       echo "$good_tree_info" | {
+               read tree prev_good_commit prev_good_job_number prev_good_job_id
+
+               if test "$CI_JOB_ID" = "$prev_good_job_id"
+               then
+                       cat <<-EOF
+                       $(tput setaf 2)Skipping build job for commit $CI_COMMIT.$(tput sgr0)
+                       This commit has already been built and tested successfully by this build job.
+                       To force a re-build delete the branch's cache and then hit 'Restart job'.
+                       EOF
+               else
+                       cat <<-EOF
+                       $(tput setaf 2)Skipping build job for commit $CI_COMMIT.$(tput sgr0)
+                       This commit's tree has already been built and tested successfully in build job $prev_good_job_number for commit $prev_good_commit.
+                       The log of that build job is available at $(url_for_job_id $prev_good_job_id)
+                       To force a re-build delete the branch's cache and then hit 'Restart job'.
+                       EOF
+               fi
+       }
+
+       exit 0
+}
+
+check_unignored_build_artifacts ()
+{
+       ! git ls-files --other --exclude-standard --error-unmatch \
+               -- ':/*' 2>/dev/null ||
+       {
+               echo "$(tput setaf 1)error: found unignored build artifacts$(tput sgr0)"
+               false
+       }
+}
+
+# Set 'exit on error' for all CI scripts to let the caller know that
+# something went wrong.
+# Set tracing executed commands, primarily setting environment variables
+# and installing dependencies.
+set -ex
+
+if test true = "$TRAVIS"
+then
+       CI_TYPE=travis
+       # When building a PR, TRAVIS_BRANCH refers to the *target* branch. Not
+       # what we want here. We want the source branch instead.
+       CI_BRANCH="${TRAVIS_PULL_REQUEST_BRANCH:-$TRAVIS_BRANCH}"
+       CI_COMMIT="$TRAVIS_COMMIT"
+       CI_JOB_ID="$TRAVIS_JOB_ID"
+       CI_JOB_NUMBER="$TRAVIS_JOB_NUMBER"
+       CI_OS_NAME="$TRAVIS_OS_NAME"
+       CI_REPO_SLUG="$TRAVIS_REPO_SLUG"
+
+       cache_dir="$HOME/travis-cache"
+
+       url_for_job_id () {
+               echo "https://travis-ci.org/$CI_REPO_SLUG/jobs/$1"
+       }
+
+       BREW_INSTALL_PACKAGES="git-lfs gettext"
+       export GIT_PROVE_OPTS="--timer --jobs 3 --state=failed,slow,save"
+       export GIT_TEST_OPTS="--verbose-log -x --immediate"
+       export MAKEFLAGS="--jobs=2"
+elif test -n "$SYSTEM_COLLECTIONURI" || test -n "$SYSTEM_TASKDEFINITIONSURI"
+then
+       CI_TYPE=azure-pipelines
+       # We are running in Azure Pipelines
+       CI_BRANCH="$BUILD_SOURCEBRANCH"
+       CI_COMMIT="$BUILD_SOURCEVERSION"
+       CI_JOB_ID="$BUILD_BUILDID"
+       CI_JOB_NUMBER="$BUILD_BUILDNUMBER"
+       CI_OS_NAME="$(echo "$AGENT_OS" | tr A-Z a-z)"
+       test darwin != "$CI_OS_NAME" || CI_OS_NAME=osx
+       CI_REPO_SLUG="$(expr "$BUILD_REPOSITORY_URI" : '.*/\([^/]*/[^/]*\)$')"
+       CC="${CC:-gcc}"
+
+       # use a subdirectory of the cache dir (because the file share is shared
+       # among *all* phases)
+       cache_dir="$HOME/test-cache/$SYSTEM_PHASENAME"
+
+       url_for_job_id () {
+               echo "$SYSTEM_TASKDEFINITIONSURI$SYSTEM_TEAMPROJECT/_build/results?buildId=$1"
+       }
+
+       BREW_INSTALL_PACKAGES=gcc@8
+       export GIT_PROVE_OPTS="--timer --jobs 10 --state=failed,slow,save"
+       export GIT_TEST_OPTS="--verbose-log -x --write-junit-xml"
+       export MAKEFLAGS="--jobs=10"
+       test windows_nt != "$CI_OS_NAME" ||
+       GIT_TEST_OPTS="--no-chain-lint --no-bin-wrappers $GIT_TEST_OPTS"
+else
+       echo "Could not identify CI type" >&2
+       exit 1
+fi
+
+good_trees_file="$cache_dir/good-trees"
+
+mkdir -p "$cache_dir"
+
+skip_branch_tip_with_tag
+skip_good_tree
+
+if test -z "$jobname"
+then
+       jobname="$CI_OS_NAME-$CC"
+fi
+
+export DEVELOPER=1
+export DEFAULT_TEST_TARGET=prove
+export GIT_TEST_CLONE_2GB=YesPlease
+
+case "$jobname" in
+linux-clang|linux-gcc)
+       if [ "$jobname" = linux-gcc ]
+       then
+               export CC=gcc-8
+       fi
+
+       export GIT_TEST_HTTPD=YesPlease
+
+       # The Linux build installs the defined dependency versions below.
+       # The OS X build installs the latest available versions. Keep that
+       # in mind when you encounter a broken OS X build!
+       export LINUX_P4_VERSION="16.2"
+       export LINUX_GIT_LFS_VERSION="1.5.2"
+
+       P4_PATH="$HOME/custom/p4"
+       GIT_LFS_PATH="$HOME/custom/git-lfs"
+       export PATH="$GIT_LFS_PATH:$P4_PATH:$PATH"
+       ;;
+osx-clang|osx-gcc)
+       if [ "$jobname" = osx-gcc ]
+       then
+               export CC=gcc-8
+       fi
+
+       # t9810 occasionally fails on Travis CI OS X
+       # t9816 occasionally fails with "TAP out of sequence errors" on
+       # Travis CI OS X
+       export GIT_SKIP_TESTS="t9810 t9816"
+       ;;
+GIT_TEST_GETTEXT_POISON)
+       export GIT_TEST_GETTEXT_POISON=YesPlease
+       ;;
+esac
+
+export MAKEFLAGS="CC=${CC:-cc}"
diff --git a/ci/make-test-artifacts.sh b/ci/make-test-artifacts.sh
new file mode 100755 (executable)
index 0000000..6469674
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/sh
+#
+# Build Git and store artifacts for testing
+#
+
+mkdir -p "$1" # in case ci/lib.sh decides to quit early
+
+. ${0%/*}/lib.sh
+
+make artifacts-tar ARTIFACTS_DIRECTORY="$1"
+
+check_unignored_build_artifacts
diff --git a/ci/mount-fileshare.sh b/ci/mount-fileshare.sh
new file mode 100755 (executable)
index 0000000..26b58a8
--- /dev/null
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+die () {
+       echo "$*" >&2
+       exit 1
+}
+
+test $# = 4 ||
+die "Usage: $0 <share> <username> <password> <mountpoint>"
+
+mkdir -p "$4" || die "Could not create $4"
+
+case "$(uname -s)" in
+Linux)
+       sudo mount -t cifs -o vers=3.0,username="$2",password="$3",dir_mode=0777,file_mode=0777,serverino "$1" "$4"
+       ;;
+Darwin)
+       pass="$(echo "$3" | sed -e 's/\//%2F/g' -e 's/+/%2B/g')" &&
+       mount -t smbfs,soft "smb://$2:$pass@${1#//}" "$4"
+       ;;
+*)
+       die "No support for $(uname -s)"
+       ;;
+esac ||
+die "Could not mount $4"
index d55460a21287018aafe8a4133dc5238e50496a36..e688a26f0d61464c473fd7f0c7fce1a805269b2c 100755 (executable)
@@ -3,7 +3,7 @@
 # Print output of failing tests
 #
 
-. ${0%/*}/lib-travisci.sh
+. ${0%/*}/lib.sh
 
 # Tracing executed commands would produce too much noise in the loop below.
 set +x
@@ -38,6 +38,19 @@ do
                test_name="${TEST_EXIT%.exit}"
                test_name="${test_name##*/}"
                trash_dir="trash directory.$test_name"
+               case "$CI_TYPE" in
+               travis)
+                       ;;
+               azure-pipelines)
+                       mkdir -p failed-test-artifacts
+                       mv "$trash_dir" failed-test-artifacts
+                       continue
+                       ;;
+               *)
+                       echo "Unhandled CI type: $CI_TYPE" >&2
+                       exit 1
+                       ;;
+               esac
                trash_tgz_b64="trash.$test_name.base64"
                if [ -d "$trash_dir" ]
                then
index cda170d5c27bab7c511d6fe70fc9852b21cc0180..cdd291344047394b26c17635d4507ad7ce14b542 100755 (executable)
@@ -3,12 +3,15 @@
 # Build and test Git
 #
 
-. ${0%/*}/lib-travisci.sh
+. ${0%/*}/lib.sh
 
-ln -s "$cache_dir/.prove" t/.prove
+case "$CI_OS_NAME" in
+windows*) cmd //c mklink //j t\\.prove "$(cygpath -aw "$cache_dir/.prove")";;
+*) ln -s "$cache_dir/.prove" t/.prove;;
+esac
 
-make --jobs=2
-make --quiet test
+make
+make test
 if test "$jobname" = "linux-gcc"
 then
        export GIT_TEST_SPLIT_INDEX=yes
@@ -17,7 +20,7 @@ then
        export GIT_TEST_OE_DELTA_SIZE=5
        export GIT_TEST_COMMIT_GRAPH=1
        export GIT_TEST_MULTI_PACK_INDEX=1
-       make --quiet test
+       make test
 fi
 
 check_unignored_build_artifacts
index 2c60d2e70ae56b59b1ff8046a21b9bc4bf87e3e6..e3a193adbce39cb62b3be20b269444188a900613 100755 (executable)
@@ -55,6 +55,6 @@ linux32 --32bit i386 su -m -l $CI_USER -c '
        set -ex
        cd /usr/src/git
        test -n "$cache_dir" && ln -s "$cache_dir/.prove" t/.prove
-       make --jobs=2
-       make --quiet test
+       make
+       make test
 '
index 21637903ce0790b1689907f64cca302b32285028..751acfcf8a8c5c894f40e7fe2e96b8a395f2eab4 100755 (executable)
@@ -3,7 +3,7 @@
 # Download and run Docker image to build and test 32-bit Git
 #
 
-. ${0%/*}/lib-travisci.sh
+. ${0%/*}/lib.sh
 
 docker pull daald/ubuntu32:xenial
 
index 5688f261d0813d4b2b55baeb5e404fcfef80b5d7..a19aa7ebbc0931fa56acfccdcc0d8bc1ad94ea2c 100755 (executable)
@@ -3,9 +3,9 @@
 # Perform various static code analysis checks
 #
 
-. ${0%/*}/lib-travisci.sh
+. ${0%/*}/lib.sh
 
-make --jobs=2 coccicheck
+make coccicheck
 
 set +x
 
diff --git a/ci/run-test-slice.sh b/ci/run-test-slice.sh
new file mode 100755 (executable)
index 0000000..f8c2c31
--- /dev/null
@@ -0,0 +1,17 @@
+#!/bin/sh
+#
+# Test Git in parallel
+#
+
+. ${0%/*}/lib.sh
+
+case "$CI_OS_NAME" in
+windows*) cmd //c mklink //j t\\.prove "$(cygpath -aw "$cache_dir/.prove")";;
+*) ln -s "$cache_dir/.prove" t/.prove;;
+esac
+
+make --quiet -C t T="$(cd t &&
+       ./helper/test-tool path-utils slice-tests "$1" "$2" t[0-9]*.sh |
+       tr '\n' ' ')"
+
+check_unignored_build_artifacts
index d99a180e528084a43dff3f640ad3036f4f9dbf07..a73a4eca0aa6053913aa81846453a3257af31595 100755 (executable)
@@ -6,7 +6,7 @@
 # supported) and a commit hash.
 #
 
-. ${0%/*}/lib-travisci.sh
+. ${0%/*}/lib.sh
 
 test $# -ne 2 && echo "Unexpected number of parameters" && exit 1
 test -z "$GFW_CI_TOKEN" && echo "GFW_CI_TOKEN not defined" && exit
index a20de9ca127f82ba916534dfb12f3932595dda05..be3b7d376ac47391be71a3822a320e327f7a3a2d 100755 (executable)
@@ -3,15 +3,16 @@
 # Perform sanity checks on documentation and build it.
 #
 
-. ${0%/*}/lib-travisci.sh
+. ${0%/*}/lib.sh
 
+test -n "$ALREADY_HAVE_ASCIIDOCTOR" ||
 gem install asciidoctor
 
 make check-builtins
 make check-docs
 
 # Build docs with AsciiDoc
-make --jobs=2 doc > >(tee stdout.log) 2> >(tee stderr.log >&2)
+make doc > >(tee stdout.log) 2> >(tee stderr.log >&2)
 ! test -s stderr.log
 test -s Documentation/git.html
 test -s Documentation/git.xml
@@ -23,7 +24,7 @@ check_unignored_build_artifacts
 
 # Build docs with AsciiDoctor
 make clean
-make --jobs=2 USE_ASCIIDOCTOR=1 doc > >(tee stdout.log) 2> >(tee stderr.log >&2)
+make USE_ASCIIDOCTOR=1 doc > >(tee stdout.log) 2> >(tee stderr.log >&2)
 sed '/^GIT_VERSION = / d' stderr.log
 ! test -s stderr.log
 test -s Documentation/git.html
index 2165297608ec92c3f5a9cc9abfba072f9d43be1f..7a17c14b822faac1a00b62412611825f0952a935 100644 (file)
--- a/column.c
+++ b/column.c
@@ -21,7 +21,7 @@ struct column_data {
 };
 
 /* return length of 's' in letters, ANSI escapes stripped */
-static int item_length(unsigned int colopts, const char *s)
+static int item_length(const char *s)
 {
        int len, i = 0;
        struct strbuf str = STRBUF_INIT;
@@ -167,7 +167,7 @@ static void display_table(const struct string_list *list,
 
        ALLOC_ARRAY(data.len, list->nr);
        for (i = 0; i < list->nr; i++)
-               data.len[i] = item_length(colopts, list->items[i].string);
+               data.len[i] = item_length(list->items[i].string);
 
        layout(&data, &initial_width);
 
index a143c006341170fad8c42604eca8f9bbf3226de8..23d8fabe75d9d80b2811acfc20f62d210ec6bba8 100644 (file)
@@ -1321,6 +1321,14 @@ static const char *path_path(void *obj)
        return path->path;
 }
 
+/*
+ * Diff stat formats which we always compute solely against the first parent.
+ */
+#define STAT_FORMAT_MASK (DIFF_FORMAT_NUMSTAT \
+                         | DIFF_FORMAT_SHORTSTAT \
+                         | DIFF_FORMAT_SUMMARY \
+                         | DIFF_FORMAT_DIRSTAT \
+                         | DIFF_FORMAT_DIFFSTAT)
 
 /* find set of paths that every parent touches */
 static struct combine_diff_path *find_paths_generic(const struct object_id *oid,
@@ -1342,8 +1350,7 @@ static struct combine_diff_path *find_paths_generic(const struct object_id *oid,
                 * show stat against the first parent even when doing
                 * combined diff.
                 */
-               int stat_opt = (output_format &
-                               (DIFF_FORMAT_NUMSTAT|DIFF_FORMAT_DIFFSTAT));
+               int stat_opt = output_format & STAT_FORMAT_MASK;
                if (i == 0 && stat_opt)
                        opt->output_format = stat_opt;
                else
@@ -1470,8 +1477,7 @@ void diff_tree_combined(const struct object_id *oid,
                 * show stat against the first parent even
                 * when doing combined diff.
                 */
-               stat_opt = (opt->output_format &
-                               (DIFF_FORMAT_NUMSTAT|DIFF_FORMAT_DIFFSTAT));
+               stat_opt = opt->output_format & STAT_FORMAT_MASK;
                if (stat_opt) {
                        diffopts.output_format = stat_opt;
 
@@ -1515,8 +1521,7 @@ void diff_tree_combined(const struct object_id *oid,
                                show_raw_diff(p, num_parent, rev);
                        needsep = 1;
                }
-               else if (opt->output_format &
-                        (DIFF_FORMAT_NUMSTAT|DIFF_FORMAT_DIFFSTAT))
+               else if (opt->output_format & STAT_FORMAT_MASK)
                        needsep = 1;
                else if (opt->output_format & DIFF_FORMAT_CALLBACK)
                        handle_combined_callback(opt, paths, num_parent, num_paths);
index 3f9c03afd57ef1b45a1aa65f648f4cf153aaad96..47e9be0a3aad883c17221b11c972b8376a70a555 100644 (file)
 #define GRAPH_CHUNKID_OIDFANOUT 0x4f494446 /* "OIDF" */
 #define GRAPH_CHUNKID_OIDLOOKUP 0x4f49444c /* "OIDL" */
 #define GRAPH_CHUNKID_DATA 0x43444154 /* "CDAT" */
-#define GRAPH_CHUNKID_LARGEEDGES 0x45444745 /* "EDGE" */
+#define GRAPH_CHUNKID_EXTRAEDGES 0x45444745 /* "EDGE" */
 
 #define GRAPH_DATA_WIDTH (the_hash_algo->rawsz + 16)
 
 #define GRAPH_VERSION_1 0x1
 #define GRAPH_VERSION GRAPH_VERSION_1
 
-#define GRAPH_OCTOPUS_EDGES_NEEDED 0x80000000
+#define GRAPH_EXTRA_EDGES_NEEDED 0x80000000
 #define GRAPH_EDGE_LAST_MASK 0x7fffffff
 #define GRAPH_PARENT_NONE 0x70000000
 
@@ -83,16 +83,10 @@ static int commit_graph_compatible(struct repository *r)
 struct commit_graph *load_commit_graph_one(const char *graph_file)
 {
        void *graph_map;
-       const unsigned char *data, *chunk_lookup;
        size_t graph_size;
        struct stat st;
-       uint32_t i;
-       struct commit_graph *graph;
+       struct commit_graph *ret;
        int fd = git_open(graph_file);
-       uint64_t last_chunk_offset;
-       uint32_t last_chunk_id;
-       uint32_t graph_signature;
-       unsigned char graph_version, hash_version;
 
        if (fd < 0)
                return NULL;
@@ -107,27 +101,55 @@ struct commit_graph *load_commit_graph_one(const char *graph_file)
                die(_("graph file %s is too small"), graph_file);
        }
        graph_map = xmmap(NULL, graph_size, PROT_READ, MAP_PRIVATE, fd, 0);
+       ret = parse_commit_graph(graph_map, fd, graph_size);
+
+       if (!ret) {
+               munmap(graph_map, graph_size);
+               close(fd);
+               exit(1);
+       }
+
+       return ret;
+}
+
+struct commit_graph *parse_commit_graph(void *graph_map, int fd,
+                                       size_t graph_size)
+{
+       const unsigned char *data, *chunk_lookup;
+       uint32_t i;
+       struct commit_graph *graph;
+       uint64_t last_chunk_offset;
+       uint32_t last_chunk_id;
+       uint32_t graph_signature;
+       unsigned char graph_version, hash_version;
+
+       if (!graph_map)
+               return NULL;
+
+       if (graph_size < GRAPH_MIN_SIZE)
+               return NULL;
+
        data = (const unsigned char *)graph_map;
 
        graph_signature = get_be32(data);
        if (graph_signature != GRAPH_SIGNATURE) {
                error(_("graph signature %X does not match signature %X"),
                      graph_signature, GRAPH_SIGNATURE);
-               goto cleanup_fail;
+               return NULL;
        }
 
        graph_version = *(unsigned char*)(data + 4);
        if (graph_version != GRAPH_VERSION) {
                error(_("graph version %X does not match version %X"),
                      graph_version, GRAPH_VERSION);
-               goto cleanup_fail;
+               return NULL;
        }
 
        hash_version = *(unsigned char*)(data + 5);
        if (hash_version != oid_version()) {
                error(_("hash version %X does not match version %X"),
                      hash_version, oid_version());
-               goto cleanup_fail;
+               return NULL;
        }
 
        graph = alloc_commit_graph();
@@ -142,16 +164,27 @@ struct commit_graph *load_commit_graph_one(const char *graph_file)
        last_chunk_offset = 8;
        chunk_lookup = data + 8;
        for (i = 0; i < graph->num_chunks; i++) {
-               uint32_t chunk_id = get_be32(chunk_lookup + 0);
-               uint64_t chunk_offset = get_be64(chunk_lookup + 4);
+               uint32_t chunk_id;
+               uint64_t chunk_offset;
                int chunk_repeated = 0;
 
+               if (data + graph_size - chunk_lookup <
+                   GRAPH_CHUNKLOOKUP_WIDTH) {
+                       error(_("chunk lookup table entry missing; graph file may be incomplete"));
+                       free(graph);
+                       return NULL;
+               }
+
+               chunk_id = get_be32(chunk_lookup + 0);
+               chunk_offset = get_be64(chunk_lookup + 4);
+
                chunk_lookup += GRAPH_CHUNKLOOKUP_WIDTH;
 
                if (chunk_offset > graph_size - the_hash_algo->rawsz) {
                        error(_("improper chunk offset %08x%08x"), (uint32_t)(chunk_offset >> 32),
                              (uint32_t)chunk_offset);
-                       goto cleanup_fail;
+                       free(graph);
+                       return NULL;
                }
 
                switch (chunk_id) {
@@ -176,17 +209,18 @@ struct commit_graph *load_commit_graph_one(const char *graph_file)
                                graph->chunk_commit_data = data + chunk_offset;
                        break;
 
-               case GRAPH_CHUNKID_LARGEEDGES:
-                       if (graph->chunk_large_edges)
+               case GRAPH_CHUNKID_EXTRAEDGES:
+                       if (graph->chunk_extra_edges)
                                chunk_repeated = 1;
                        else
-                               graph->chunk_large_edges = data + chunk_offset;
+                               graph->chunk_extra_edges = data + chunk_offset;
                        break;
                }
 
                if (chunk_repeated) {
                        error(_("chunk id %08x appears multiple times"), chunk_id);
-                       goto cleanup_fail;
+                       free(graph);
+                       return NULL;
                }
 
                if (last_chunk_id == GRAPH_CHUNKID_OIDLOOKUP)
@@ -200,11 +234,6 @@ struct commit_graph *load_commit_graph_one(const char *graph_file)
        }
 
        return graph;
-
-cleanup_fail:
-       munmap(graph_map, graph_size);
-       close(fd);
-       exit(1);
 }
 
 static void prepare_commit_graph_one(struct repository *r, const char *obj_dir)
@@ -288,7 +317,8 @@ static int bsearch_graph(struct commit_graph *g, struct object_id *oid, uint32_t
                            g->chunk_oid_lookup, g->hash_len, pos);
 }
 
-static struct commit_list **insert_parent_or_die(struct commit_graph *g,
+static struct commit_list **insert_parent_or_die(struct repository *r,
+                                                struct commit_graph *g,
                                                 uint64_t pos,
                                                 struct commit_list **pptr)
 {
@@ -299,7 +329,7 @@ static struct commit_list **insert_parent_or_die(struct commit_graph *g,
                die("invalid parent position %"PRIu64, pos);
 
        hashcpy(oid.hash, g->chunk_oid_lookup + g->hash_len * pos);
-       c = lookup_commit(the_repository, &oid);
+       c = lookup_commit(r, &oid);
        if (!c)
                die(_("could not find commit %s"), oid_to_hex(&oid));
        c->graph_pos = pos;
@@ -313,7 +343,9 @@ static void fill_commit_graph_info(struct commit *item, struct commit_graph *g,
        item->generation = get_be32(commit_data + g->hash_len + 8) >> 2;
 }
 
-static int fill_commit_in_graph(struct commit *item, struct commit_graph *g, uint32_t pos)
+static int fill_commit_in_graph(struct repository *r,
+                               struct commit *item,
+                               struct commit_graph *g, uint32_t pos)
 {
        uint32_t edge_value;
        uint32_t *parent_data_ptr;
@@ -337,21 +369,21 @@ static int fill_commit_in_graph(struct commit *item, struct commit_graph *g, uin
        edge_value = get_be32(commit_data + g->hash_len);
        if (edge_value == GRAPH_PARENT_NONE)
                return 1;
-       pptr = insert_parent_or_die(g, edge_value, pptr);
+       pptr = insert_parent_or_die(r, g, edge_value, pptr);
 
        edge_value = get_be32(commit_data + g->hash_len + 4);
        if (edge_value == GRAPH_PARENT_NONE)
                return 1;
-       if (!(edge_value & GRAPH_OCTOPUS_EDGES_NEEDED)) {
-               pptr = insert_parent_or_die(g, edge_value, pptr);
+       if (!(edge_value & GRAPH_EXTRA_EDGES_NEEDED)) {
+               pptr = insert_parent_or_die(r, g, edge_value, pptr);
                return 1;
        }
 
-       parent_data_ptr = (uint32_t*)(g->chunk_large_edges +
+       parent_data_ptr = (uint32_t*)(g->chunk_extra_edges +
                          4 * (uint64_t)(edge_value & GRAPH_EDGE_LAST_MASK));
        do {
                edge_value = get_be32(parent_data_ptr);
-               pptr = insert_parent_or_die(g,
+               pptr = insert_parent_or_die(r, g,
                                            edge_value & GRAPH_EDGE_LAST_MASK,
                                            pptr);
                parent_data_ptr++;
@@ -370,7 +402,9 @@ static int find_commit_in_graph(struct commit *item, struct commit_graph *g, uin
        }
 }
 
-static int parse_commit_in_graph_one(struct commit_graph *g, struct commit *item)
+static int parse_commit_in_graph_one(struct repository *r,
+                                    struct commit_graph *g,
+                                    struct commit *item)
 {
        uint32_t pos;
 
@@ -378,7 +412,7 @@ static int parse_commit_in_graph_one(struct commit_graph *g, struct commit *item
                return 1;
 
        if (find_commit_in_graph(item, g, &pos))
-               return fill_commit_in_graph(item, g, pos);
+               return fill_commit_in_graph(r, item, g, pos);
 
        return 0;
 }
@@ -387,7 +421,7 @@ int parse_commit_in_graph(struct repository *r, struct commit *item)
 {
        if (!prepare_commit_graph(r))
                return 0;
-       return parse_commit_in_graph_one(r->objects->commit_graph, item);
+       return parse_commit_in_graph_one(r, r->objects->commit_graph, item);
 }
 
 void load_commit_graph_info(struct repository *r, struct commit *item)
@@ -399,19 +433,22 @@ void load_commit_graph_info(struct repository *r, struct commit *item)
                fill_commit_graph_info(item, r->objects->commit_graph, pos);
 }
 
-static struct tree *load_tree_for_commit(struct commit_graph *g, struct commit *c)
+static struct tree *load_tree_for_commit(struct repository *r,
+                                        struct commit_graph *g,
+                                        struct commit *c)
 {
        struct object_id oid;
        const unsigned char *commit_data = g->chunk_commit_data +
                                           GRAPH_DATA_WIDTH * (c->graph_pos);
 
        hashcpy(oid.hash, commit_data);
-       c->maybe_tree = lookup_tree(the_repository, &oid);
+       c->maybe_tree = lookup_tree(r, &oid);
 
        return c->maybe_tree;
 }
 
-static struct tree *get_commit_tree_in_graph_one(struct commit_graph *g,
+static struct tree *get_commit_tree_in_graph_one(struct repository *r,
+                                                struct commit_graph *g,
                                                 const struct commit *c)
 {
        if (c->maybe_tree)
@@ -419,17 +456,19 @@ static struct tree *get_commit_tree_in_graph_one(struct commit_graph *g,
        if (c->graph_pos == COMMIT_NOT_FROM_GRAPH)
                BUG("get_commit_tree_in_graph_one called from non-commit-graph commit");
 
-       return load_tree_for_commit(g, (struct commit *)c);
+       return load_tree_for_commit(r, g, (struct commit *)c);
 }
 
 struct tree *get_commit_tree_in_graph(struct repository *r, const struct commit *c)
 {
-       return get_commit_tree_in_graph_one(r->objects->commit_graph, c);
+       return get_commit_tree_in_graph_one(r, r->objects->commit_graph, c);
 }
 
 static void write_graph_chunk_fanout(struct hashfile *f,
                                     struct commit **commits,
-                                    int nr_commits)
+                                    int nr_commits,
+                                    struct progress *progress,
+                                    uint64_t *progress_cnt)
 {
        int i, count = 0;
        struct commit **list = commits;
@@ -443,6 +482,7 @@ static void write_graph_chunk_fanout(struct hashfile *f,
                while (count < nr_commits) {
                        if ((*list)->object.oid.hash[0] != i)
                                break;
+                       display_progress(progress, ++*progress_cnt);
                        count++;
                        list++;
                }
@@ -452,12 +492,16 @@ static void write_graph_chunk_fanout(struct hashfile *f,
 }
 
 static void write_graph_chunk_oids(struct hashfile *f, int hash_len,
-                                  struct commit **commits, int nr_commits)
+                                  struct commit **commits, int nr_commits,
+                                  struct progress *progress,
+                                  uint64_t *progress_cnt)
 {
        struct commit **list = commits;
        int count;
-       for (count = 0; count < nr_commits; count++, list++)
+       for (count = 0; count < nr_commits; count++, list++) {
+               display_progress(progress, ++*progress_cnt);
                hashwrite(f, (*list)->object.oid.hash, (int)hash_len);
+       }
 }
 
 static const unsigned char *commit_to_sha1(size_t index, void *table)
@@ -467,7 +511,9 @@ static const unsigned char *commit_to_sha1(size_t index, void *table)
 }
 
 static void write_graph_chunk_data(struct hashfile *f, int hash_len,
-                                  struct commit **commits, int nr_commits)
+                                  struct commit **commits, int nr_commits,
+                                  struct progress *progress,
+                                  uint64_t *progress_cnt)
 {
        struct commit **list = commits;
        struct commit **last = commits + nr_commits;
@@ -477,6 +523,7 @@ static void write_graph_chunk_data(struct hashfile *f, int hash_len,
                struct commit_list *parent;
                int edge_value;
                uint32_t packedDate[2];
+               display_progress(progress, ++*progress_cnt);
 
                parse_commit(*list);
                hashwrite(f, get_commit_tree_oid(*list)->hash, hash_len);
@@ -505,7 +552,7 @@ static void write_graph_chunk_data(struct hashfile *f, int hash_len,
                if (!parent)
                        edge_value = GRAPH_PARENT_NONE;
                else if (parent->next)
-                       edge_value = GRAPH_OCTOPUS_EDGES_NEEDED | num_extra_edges;
+                       edge_value = GRAPH_EXTRA_EDGES_NEEDED | num_extra_edges;
                else {
                        edge_value = sha1_pos(parent->item->object.oid.hash,
                                              commits,
@@ -519,7 +566,7 @@ static void write_graph_chunk_data(struct hashfile *f, int hash_len,
 
                hashwrite_be32(f, edge_value);
 
-               if (edge_value & GRAPH_OCTOPUS_EDGES_NEEDED) {
+               if (edge_value & GRAPH_EXTRA_EDGES_NEEDED) {
                        do {
                                num_extra_edges++;
                                parent = parent->next;
@@ -540,9 +587,11 @@ static void write_graph_chunk_data(struct hashfile *f, int hash_len,
        }
 }
 
-static void write_graph_chunk_large_edges(struct hashfile *f,
+static void write_graph_chunk_extra_edges(struct hashfile *f,
                                          struct commit **commits,
-                                         int nr_commits)
+                                         int nr_commits,
+                                         struct progress *progress,
+                                         uint64_t *progress_cnt)
 {
        struct commit **list = commits;
        struct commit **last = commits + nr_commits;
@@ -550,6 +599,9 @@ static void write_graph_chunk_large_edges(struct hashfile *f,
 
        while (list < last) {
                int num_parents = 0;
+
+               display_progress(progress, ++*progress_cnt);
+
                for (parent = (*list)->parents; num_parents < 3 && parent;
                     parent = parent->next)
                        num_parents++;
@@ -643,15 +695,15 @@ static void add_missing_parents(struct packed_oid_list *oids, struct commit *com
 
 static void close_reachable(struct packed_oid_list *oids, int report_progress)
 {
-       int i, j;
+       int i;
        struct commit *commit;
        struct progress *progress = NULL;
 
        if (report_progress)
                progress = start_delayed_progress(
-                       _("Loading known commits in commit graph"), j = 0);
+                       _("Loading known commits in commit graph"), oids->nr);
        for (i = 0; i < oids->nr; i++) {
-               display_progress(progress, ++j);
+               display_progress(progress, i + 1);
                commit = lookup_commit(the_repository, &oids->list[i]);
                if (commit)
                        commit->object.flags |= UNINTERESTING;
@@ -665,9 +717,9 @@ static void close_reachable(struct packed_oid_list *oids, int report_progress)
         */
        if (report_progress)
                progress = start_delayed_progress(
-                       _("Expanding reachable commits in commit graph"), j = 0);
+                       _("Expanding reachable commits in commit graph"), oids->nr);
        for (i = 0; i < oids->nr; i++) {
-               display_progress(progress, ++j);
+               display_progress(progress, i + 1);
                commit = lookup_commit(the_repository, &oids->list[i]);
 
                if (commit && !parse_commit(commit))
@@ -677,9 +729,9 @@ static void close_reachable(struct packed_oid_list *oids, int report_progress)
 
        if (report_progress)
                progress = start_delayed_progress(
-                       _("Clearing commit marks in commit graph"), j = 0);
+                       _("Clearing commit marks in commit graph"), oids->nr);
        for (i = 0; i < oids->nr; i++) {
-               display_progress(progress, ++j);
+               display_progress(progress, i + 1);
                commit = lookup_commit(the_repository, &oids->list[i]);
 
                if (commit)
@@ -774,12 +826,16 @@ void write_commit_graph(const char *obj_dir,
        struct commit_list *parent;
        struct progress *progress = NULL;
        const unsigned hashsz = the_hash_algo->rawsz;
+       uint64_t progress_cnt = 0;
+       struct strbuf progress_title = STRBUF_INIT;
+       unsigned long approx_nr_objects;
 
        if (!commit_graph_compatible(the_repository))
                return;
 
        oids.nr = 0;
-       oids.alloc = approximate_object_count() / 32;
+       approx_nr_objects = approximate_object_count();
+       oids.alloc = approx_nr_objects / 32;
        oids.progress = NULL;
        oids.progress_done = 0;
 
@@ -809,8 +865,12 @@ void write_commit_graph(const char *obj_dir,
                strbuf_addf(&packname, "%s/pack/", obj_dir);
                dirlen = packname.len;
                if (report_progress) {
-                       oids.progress = start_delayed_progress(
-                               _("Finding commits for commit graph"), 0);
+                       strbuf_addf(&progress_title,
+                                   Q_("Finding commits for commit graph in %d pack",
+                                      "Finding commits for commit graph in %d packs",
+                                      pack_indexes->nr),
+                                   pack_indexes->nr);
+                       oids.progress = start_delayed_progress(progress_title.buf, 0);
                        oids.progress_done = 0;
                }
                for (i = 0; i < pack_indexes->nr; i++) {
@@ -822,19 +882,26 @@ void write_commit_graph(const char *obj_dir,
                                die(_("error adding pack %s"), packname.buf);
                        if (open_pack_index(p))
                                die(_("error opening index for %s"), packname.buf);
-                       for_each_object_in_pack(p, add_packed_commits, &oids, 0);
+                       for_each_object_in_pack(p, add_packed_commits, &oids,
+                                               FOR_EACH_OBJECT_PACK_ORDER);
                        close_pack(p);
                        free(p);
                }
                stop_progress(&oids.progress);
+               strbuf_reset(&progress_title);
                strbuf_release(&packname);
        }
 
        if (commit_hex) {
-               if (report_progress)
-                       progress = start_delayed_progress(
-                               _("Finding commits for commit graph"),
-                               commit_hex->nr);
+               if (report_progress) {
+                       strbuf_addf(&progress_title,
+                                   Q_("Finding commits for commit graph from %d ref",
+                                      "Finding commits for commit graph from %d refs",
+                                      commit_hex->nr),
+                                   commit_hex->nr);
+                       progress = start_delayed_progress(progress_title.buf,
+                                                         commit_hex->nr);
+               }
                for (i = 0; i < commit_hex->nr; i++) {
                        const char *end;
                        struct object_id oid;
@@ -854,25 +921,36 @@ void write_commit_graph(const char *obj_dir,
                        }
                }
                stop_progress(&progress);
+               strbuf_reset(&progress_title);
        }
 
        if (!pack_indexes && !commit_hex) {
                if (report_progress)
                        oids.progress = start_delayed_progress(
-                               _("Finding commits for commit graph"), 0);
-               for_each_packed_object(add_packed_commits, &oids, 0);
+                               _("Finding commits for commit graph among packed objects"),
+                               approx_nr_objects);
+               for_each_packed_object(add_packed_commits, &oids,
+                                      FOR_EACH_OBJECT_PACK_ORDER);
+               if (oids.progress_done < approx_nr_objects)
+                       display_progress(oids.progress, approx_nr_objects);
                stop_progress(&oids.progress);
        }
 
        close_reachable(&oids, report_progress);
 
+       if (report_progress)
+               progress = start_delayed_progress(
+                       _("Counting distinct commits in commit graph"),
+                       oids.nr);
+       display_progress(progress, 0); /* TODO: Measure QSORT() progress */
        QSORT(oids.list, oids.nr, commit_compare);
-
        count_distinct = 1;
        for (i = 1; i < oids.nr; i++) {
+               display_progress(progress, i + 1);
                if (!oideq(&oids.list[i - 1], &oids.list[i]))
                        count_distinct++;
        }
+       stop_progress(&progress);
 
        if (count_distinct >= GRAPH_EDGE_LAST_MASK)
                die(_("the commit graph format cannot write %d commits"), count_distinct);
@@ -882,8 +960,13 @@ void write_commit_graph(const char *obj_dir,
        ALLOC_ARRAY(commits.list, commits.alloc);
 
        num_extra_edges = 0;
+       if (report_progress)
+               progress = start_delayed_progress(
+                       _("Finding extra edges in commit graph"),
+                       oids.nr);
        for (i = 0; i < oids.nr; i++) {
                int num_parents = 0;
+               display_progress(progress, i + 1);
                if (i > 0 && oideq(&oids.list[i - 1], &oids.list[i]))
                        continue;
 
@@ -900,6 +983,7 @@ void write_commit_graph(const char *obj_dir,
                commits.nr++;
        }
        num_chunks = num_extra_edges ? 4 : 3;
+       stop_progress(&progress);
 
        if (commits.nr >= GRAPH_EDGE_LAST_MASK)
                die(_("too many commits to write graph"));
@@ -927,7 +1011,7 @@ void write_commit_graph(const char *obj_dir,
        chunk_ids[1] = GRAPH_CHUNKID_OIDLOOKUP;
        chunk_ids[2] = GRAPH_CHUNKID_DATA;
        if (num_extra_edges)
-               chunk_ids[3] = GRAPH_CHUNKID_LARGEEDGES;
+               chunk_ids[3] = GRAPH_CHUNKID_EXTRAEDGES;
        else
                chunk_ids[3] = 0;
        chunk_ids[4] = 0;
@@ -947,10 +1031,23 @@ void write_commit_graph(const char *obj_dir,
                hashwrite(f, chunk_write, 12);
        }
 
-       write_graph_chunk_fanout(f, commits.list, commits.nr);
-       write_graph_chunk_oids(f, hashsz, commits.list, commits.nr);
-       write_graph_chunk_data(f, hashsz, commits.list, commits.nr);
-       write_graph_chunk_large_edges(f, commits.list, commits.nr);
+       if (report_progress) {
+               strbuf_addf(&progress_title,
+                           Q_("Writing out commit graph in %d pass",
+                              "Writing out commit graph in %d passes",
+                              num_chunks),
+                           num_chunks);
+               progress = start_delayed_progress(
+                       progress_title.buf,
+                       num_chunks * commits.nr);
+       }
+       write_graph_chunk_fanout(f, commits.list, commits.nr, progress, &progress_cnt);
+       write_graph_chunk_oids(f, hashsz, commits.list, commits.nr, progress, &progress_cnt);
+       write_graph_chunk_data(f, hashsz, commits.list, commits.nr, progress, &progress_cnt);
+       if (num_extra_edges)
+               write_graph_chunk_extra_edges(f, commits.list, commits.nr, progress, &progress_cnt);
+       stop_progress(&progress);
+       strbuf_release(&progress_title);
 
        close_commit_graph(the_repository);
        finalize_hashfile(f, NULL, CSUM_HASH_IN_STREAM | CSUM_FSYNC);
@@ -1035,7 +1132,7 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g)
                }
 
                graph_commit = lookup_commit(r, &cur_oid);
-               if (!parse_commit_in_graph_one(g, graph_commit))
+               if (!parse_commit_in_graph_one(r, g, graph_commit))
                        graph_report("failed to parse %s from commit-graph",
                                     oid_to_hex(&cur_oid));
        }
@@ -1071,7 +1168,7 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g)
                        continue;
                }
 
-               if (!oideq(&get_commit_tree_in_graph_one(g, graph_commit)->object.oid,
+               if (!oideq(&get_commit_tree_in_graph_one(r, g, graph_commit)->object.oid,
                           get_commit_tree_oid(odb_commit)))
                        graph_report("root tree OID for commit %s in commit-graph is %s != %s",
                                     oid_to_hex(&cur_oid),
index 9db40b4d3aadb75b4dcea5027d07d373bdf169e1..096d8bac340514916c852268ef37c7b97190799a 100644 (file)
@@ -49,11 +49,14 @@ struct commit_graph {
        const uint32_t *chunk_oid_fanout;
        const unsigned char *chunk_oid_lookup;
        const unsigned char *chunk_commit_data;
-       const unsigned char *chunk_large_edges;
+       const unsigned char *chunk_extra_edges;
 };
 
 struct commit_graph *load_commit_graph_one(const char *graph_file);
 
+struct commit_graph *parse_commit_graph(void *graph_map, int fd,
+                                       size_t graph_size);
+
 /*
  * Return 1 if and only if the repository has a commit-graph
  * file and generation numbers are computed in that file.
index d5a39defd3d5144f83d4f48e43e54e1f7f49ab29..3ea174788a4f0229460bad65373e974cc3f87c64 100644 (file)
@@ -30,7 +30,8 @@ static int queue_has_nonstale(struct prio_queue *queue)
 }
 
 /* all input commits in one and twos[] must have been parsed! */
-static struct commit_list *paint_down_to_common(struct commit *one, int n,
+static struct commit_list *paint_down_to_common(struct repository *r,
+                                               struct commit *one, int n,
                                                struct commit **twos,
                                                int min_generation)
 {
@@ -83,7 +84,7 @@ static struct commit_list *paint_down_to_common(struct commit *one, int n,
                        parents = parents->next;
                        if ((p->object.flags & flags) == flags)
                                continue;
-                       if (parse_commit(p))
+                       if (repo_parse_commit(r, p))
                                return NULL;
                        p->object.flags |= flags;
                        prio_queue_put(&queue, p);
@@ -94,7 +95,9 @@ static struct commit_list *paint_down_to_common(struct commit *one, int n,
        return result;
 }
 
-static struct commit_list *merge_bases_many(struct commit *one, int n, struct commit **twos)
+static struct commit_list *merge_bases_many(struct repository *r,
+                                           struct commit *one, int n,
+                                           struct commit **twos)
 {
        struct commit_list *list = NULL;
        struct commit_list *result = NULL;
@@ -109,14 +112,14 @@ static struct commit_list *merge_bases_many(struct commit *one, int n, struct co
                        return commit_list_insert(one, &result);
        }
 
-       if (parse_commit(one))
+       if (repo_parse_commit(r, one))
                return NULL;
        for (i = 0; i < n; i++) {
-               if (parse_commit(twos[i]))
+               if (repo_parse_commit(r, twos[i]))
                        return NULL;
        }
 
-       list = paint_down_to_common(one, n, twos, 0);
+       list = paint_down_to_common(r, one, n, twos, 0);
 
        while (list) {
                struct commit *commit = pop_commit(&list);
@@ -153,7 +156,7 @@ struct commit_list *get_octopus_merge_bases(struct commit_list *in)
        return ret;
 }
 
-static int remove_redundant(struct commit **array, int cnt)
+static int remove_redundant(struct repository *r, struct commit **array, int cnt)
 {
        /*
         * Some commit in the array may be an ancestor of
@@ -171,7 +174,7 @@ static int remove_redundant(struct commit **array, int cnt)
        ALLOC_ARRAY(filled_index, cnt - 1);
 
        for (i = 0; i < cnt; i++)
-               parse_commit(array[i]);
+               repo_parse_commit(r, array[i]);
        for (i = 0; i < cnt; i++) {
                struct commit_list *common;
                uint32_t min_generation = array[i]->generation;
@@ -187,8 +190,8 @@ static int remove_redundant(struct commit **array, int cnt)
                        if (array[j]->generation < min_generation)
                                min_generation = array[j]->generation;
                }
-               common = paint_down_to_common(array[i], filled, work,
-                                             min_generation);
+               common = paint_down_to_common(r, array[i], filled,
+                                             work, min_generation);
                if (array[i]->object.flags & PARENT2)
                        redundant[i] = 1;
                for (j = 0; j < filled; j++)
@@ -213,7 +216,8 @@ static int remove_redundant(struct commit **array, int cnt)
        return filled;
 }
 
-static struct commit_list *get_merge_bases_many_0(struct commit *one,
+static struct commit_list *get_merge_bases_many_0(struct repository *r,
+                                                 struct commit *one,
                                                  int n,
                                                  struct commit **twos,
                                                  int cleanup)
@@ -223,7 +227,7 @@ static struct commit_list *get_merge_bases_many_0(struct commit *one,
        struct commit_list *result;
        int cnt, i;
 
-       result = merge_bases_many(one, n, twos);
+       result = merge_bases_many(r, one, n, twos);
        for (i = 0; i < n; i++) {
                if (one == twos[i])
                        return result;
@@ -246,7 +250,7 @@ static struct commit_list *get_merge_bases_many_0(struct commit *one,
        clear_commit_marks(one, all_flags);
        clear_commit_marks_many(n, twos, all_flags);
 
-       cnt = remove_redundant(rslt, cnt);
+       cnt = remove_redundant(r, rslt, cnt);
        result = NULL;
        for (i = 0; i < cnt; i++)
                commit_list_insert_by_date(rslt[i], &result);
@@ -254,23 +258,27 @@ static struct commit_list *get_merge_bases_many_0(struct commit *one,
        return result;
 }
 
-struct commit_list *get_merge_bases_many(struct commit *one,
-                                        int n,
-                                        struct commit **twos)
+struct commit_list *repo_get_merge_bases_many(struct repository *r,
+                                             struct commit *one,
+                                             int n,
+                                             struct commit **twos)
 {
-       return get_merge_bases_many_0(one, n, twos, 1);
+       return get_merge_bases_many_0(r, one, n, twos, 1);
 }
 
-struct commit_list *get_merge_bases_many_dirty(struct commit *one,
-                                              int n,
-                                              struct commit **twos)
+struct commit_list *repo_get_merge_bases_many_dirty(struct repository *r,
+                                                   struct commit *one,
+                                                   int n,
+                                                   struct commit **twos)
 {
-       return get_merge_bases_many_0(one, n, twos, 0);
+       return get_merge_bases_many_0(r, one, n, twos, 0);
 }
 
-struct commit_list *get_merge_bases(struct commit *one, struct commit *two)
+struct commit_list *repo_get_merge_bases(struct repository *r,
+                                        struct commit *one,
+                                        struct commit *two)
 {
-       return get_merge_bases_many_0(one, 1, &two, 1);
+       return get_merge_bases_many_0(r, one, 1, &two, 1);
 }
 
 /*
@@ -304,16 +312,17 @@ int is_descendant_of(struct commit *commit, struct commit_list *with_commit)
 /*
  * Is "commit" an ancestor of one of the "references"?
  */
-int in_merge_bases_many(struct commit *commit, int nr_reference, struct commit **reference)
+int repo_in_merge_bases_many(struct repository *r, struct commit *commit,
+                            int nr_reference, struct commit **reference)
 {
        struct commit_list *bases;
        int ret = 0, i;
        uint32_t min_generation = GENERATION_NUMBER_INFINITY;
 
-       if (parse_commit(commit))
+       if (repo_parse_commit(r, commit))
                return ret;
        for (i = 0; i < nr_reference; i++) {
-               if (parse_commit(reference[i]))
+               if (repo_parse_commit(r, reference[i]))
                        return ret;
                if (reference[i]->generation < min_generation)
                        min_generation = reference[i]->generation;
@@ -322,7 +331,9 @@ int in_merge_bases_many(struct commit *commit, int nr_reference, struct commit *
        if (commit->generation > min_generation)
                return ret;
 
-       bases = paint_down_to_common(commit, nr_reference, reference, commit->generation);
+       bases = paint_down_to_common(r, commit,
+                                    nr_reference, reference,
+                                    commit->generation);
        if (commit->object.flags & PARENT2)
                ret = 1;
        clear_commit_marks(commit, all_flags);
@@ -334,9 +345,11 @@ int in_merge_bases_many(struct commit *commit, int nr_reference, struct commit *
 /*
  * Is "commit" an ancestor of (i.e. reachable from) the "reference"?
  */
-int in_merge_bases(struct commit *commit, struct commit *reference)
+int repo_in_merge_bases(struct repository *r,
+                       struct commit *commit,
+                       struct commit *reference)
 {
-       return in_merge_bases_many(commit, 1, &reference);
+       return repo_in_merge_bases_many(r, commit, 1, &reference);
 }
 
 struct commit_list *reduce_heads(struct commit_list *heads)
@@ -365,7 +378,7 @@ struct commit_list *reduce_heads(struct commit_list *heads)
                        p->item->object.flags &= ~STALE;
                }
        }
-       num_head = remove_redundant(array, num_head);
+       num_head = remove_redundant(the_repository, array, num_head);
        for (i = 0; i < num_head; i++)
                tail = &commit_list_insert(array[i], tail)->next;
        free(array);
index fb8082a2ece94a94cf2f9a55ba95950caa41a914..99a43e8b64fc803d7b7f4d09d11c2ec31fdb0a76 100644 (file)
@@ -9,21 +9,35 @@ struct ref_filter;
 struct object_id;
 struct object_array;
 
-struct commit_list *get_merge_bases_many(struct commit *one,
-                                        int n,
-                                        struct commit **twos);
-struct commit_list *get_merge_bases_many_dirty(struct commit *one,
-                                              int n,
-                                              struct commit **twos);
-struct commit_list *get_merge_bases(struct commit *one, struct commit *two);
-struct commit_list *get_octopus_merge_bases(struct commit_list *in);
-
+struct commit_list *repo_get_merge_bases(struct repository *r,
+                                        struct commit *rev1,
+                                        struct commit *rev2);
+struct commit_list *repo_get_merge_bases_many(struct repository *r,
+                                             struct commit *one, int n,
+                                             struct commit **twos);
 /* To be used only when object flags after this call no longer matter */
-struct commit_list *get_merge_bases_many_dirty(struct commit *one, int n, struct commit **twos);
+struct commit_list *repo_get_merge_bases_many_dirty(struct repository *r,
+                                                   struct commit *one, int n,
+                                                   struct commit **twos);
+#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
+#define get_merge_bases(r1, r2)           repo_get_merge_bases(the_repository, r1, r2)
+#define get_merge_bases_many(one, n, two) repo_get_merge_bases_many(the_repository, one, n, two)
+#define get_merge_bases_many_dirty(one, n, twos) repo_get_merge_bases_many_dirty(the_repository, one, n, twos)
+#endif
+
+struct commit_list *get_octopus_merge_bases(struct commit_list *in);
 
 int is_descendant_of(struct commit *commit, struct commit_list *with_commit);
-int in_merge_bases_many(struct commit *commit, int nr_reference, struct commit **reference);
-int in_merge_bases(struct commit *commit, struct commit *reference);
+int repo_in_merge_bases(struct repository *r,
+                       struct commit *commit,
+                       struct commit *reference);
+int repo_in_merge_bases_many(struct repository *r,
+                            struct commit *commit,
+                            int nr_reference, struct commit **reference);
+#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
+#define in_merge_bases(c1, c2) repo_in_merge_bases(the_repository, c1, c2)
+#define in_merge_bases_many(c1, n, cs) repo_in_merge_bases_many(the_repository, c1, n, cs)
+#endif
 
 /*
  * Takes a list of commits and returns a new list where those
index d13a7bc3746406bdaf0bda0975c25b40111afe47..a5333c7ac6c373a13f9298b36be5ff94a90a3e3f 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -299,13 +299,15 @@ const void *get_cached_commit_buffer(struct repository *r, const struct commit *
        return v->buffer;
 }
 
-const void *get_commit_buffer(const struct commit *commit, unsigned long *sizep)
+const void *repo_get_commit_buffer(struct repository *r,
+                                  const struct commit *commit,
+                                  unsigned long *sizep)
 {
-       const void *ret = get_cached_commit_buffer(the_repository, commit, sizep);
+       const void *ret = get_cached_commit_buffer(r, commit, sizep);
        if (!ret) {
                enum object_type type;
                unsigned long size;
-               ret = read_object_file(&commit->object.oid, &type, &size);
+               ret = repo_read_object_file(r, &commit->object.oid, &type, &size);
                if (!ret)
                        die("cannot read commit object %s",
                            oid_to_hex(&commit->object.oid));
@@ -318,18 +320,20 @@ const void *get_commit_buffer(const struct commit *commit, unsigned long *sizep)
        return ret;
 }
 
-void unuse_commit_buffer(const struct commit *commit, const void *buffer)
+void repo_unuse_commit_buffer(struct repository *r,
+                             const struct commit *commit,
+                             const void *buffer)
 {
        struct commit_buffer *v = buffer_slab_peek(
-               the_repository->parsed_objects->buffer_slab, commit);
+               r->parsed_objects->buffer_slab, commit);
        if (!(v && v->buffer == buffer))
                free((void *)buffer);
 }
 
-void free_commit_buffer(struct commit *commit)
+void free_commit_buffer(struct parsed_object_pool *pool, struct commit *commit)
 {
        struct commit_buffer *v = buffer_slab_peek(
-               the_repository->parsed_objects->buffer_slab, commit);
+               pool->buffer_slab, commit);
        if (v) {
                FREE_AND_NULL(v->buffer);
                v->size = 0;
@@ -352,13 +356,12 @@ struct object_id *get_commit_tree_oid(const struct commit *commit)
        return &get_commit_tree(commit)->object.oid;
 }
 
-void release_commit_memory(struct commit *c)
+void release_commit_memory(struct parsed_object_pool *pool, struct commit *c)
 {
        c->maybe_tree = NULL;
        c->index = 0;
-       free_commit_buffer(c);
+       free_commit_buffer(pool, c);
        free_commit_list(c->parents);
-       /* TODO: what about commit->util? */
 
        c->object.parsed = 0;
 }
@@ -445,7 +448,10 @@ int parse_commit_buffer(struct repository *r, struct commit *item, const void *b
        return 0;
 }
 
-int parse_commit_internal(struct commit *item, int quiet_on_missing, int use_commit_graph)
+int repo_parse_commit_internal(struct repository *r,
+                              struct commit *item,
+                              int quiet_on_missing,
+                              int use_commit_graph)
 {
        enum object_type type;
        void *buffer;
@@ -456,9 +462,9 @@ int parse_commit_internal(struct commit *item, int quiet_on_missing, int use_com
                return -1;
        if (item->object.parsed)
                return 0;
-       if (use_commit_graph && parse_commit_in_graph(the_repository, item))
+       if (use_commit_graph && parse_commit_in_graph(r, item))
                return 0;
-       buffer = read_object_file(&item->object.oid, &type, &size);
+       buffer = repo_read_object_file(r, &item->object.oid, &type, &size);
        if (!buffer)
                return quiet_on_missing ? -1 :
                        error("Could not read %s",
@@ -469,18 +475,19 @@ int parse_commit_internal(struct commit *item, int quiet_on_missing, int use_com
                             oid_to_hex(&item->object.oid));
        }
 
-       ret = parse_commit_buffer(the_repository, item, buffer, size, 0);
+       ret = parse_commit_buffer(r, item, buffer, size, 0);
        if (save_commit_buffer && !ret) {
-               set_commit_buffer(the_repository, item, buffer, size);
+               set_commit_buffer(r, item, buffer, size);
                return 0;
        }
        free(buffer);
        return ret;
 }
 
-int parse_commit_gently(struct commit *item, int quiet_on_missing)
+int repo_parse_commit_gently(struct repository *r,
+                            struct commit *item, int quiet_on_missing)
 {
-       return parse_commit_internal(item, quiet_on_missing, 1);
+       return repo_parse_commit_internal(r, item, quiet_on_missing, 1);
 }
 
 void parse_commit_or_die(struct commit *item)
index 98664536cb82c65f04a1742c3e5c1e269afc9493..42728c2906608a9f4f1724e02b16d913b74b8728 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -80,12 +80,21 @@ struct commit *lookup_commit_reference_by_name(const char *name);
 struct commit *lookup_commit_or_die(const struct object_id *oid, const char *ref_name);
 
 int parse_commit_buffer(struct repository *r, struct commit *item, const void *buffer, unsigned long size, int check_graph);
-int parse_commit_internal(struct commit *item, int quiet_on_missing, int use_commit_graph);
-int parse_commit_gently(struct commit *item, int quiet_on_missing);
-static inline int parse_commit(struct commit *item)
+int repo_parse_commit_internal(struct repository *r, struct commit *item,
+                              int quiet_on_missing, int use_commit_graph);
+int repo_parse_commit_gently(struct repository *r,
+                            struct commit *item,
+                            int quiet_on_missing);
+static inline int repo_parse_commit(struct repository *r, struct commit *item)
 {
-       return parse_commit_gently(item, 0);
+       return repo_parse_commit_gently(r, item, 0);
 }
+#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
+#define parse_commit_internal(item, quiet, use) repo_parse_commit_internal(the_repository, item, quiet, use)
+#define parse_commit_gently(item, quiet) repo_parse_commit_gently(the_repository, item, quiet)
+#define parse_commit(item) repo_parse_commit(the_repository, item)
+#endif
+
 void parse_commit_or_die(struct commit *item);
 
 struct buffer_slab;
@@ -109,7 +118,12 @@ const void *get_cached_commit_buffer(struct repository *, const struct commit *,
  * from disk. The resulting memory should not be modified, and must be given
  * to unuse_commit_buffer when the caller is done.
  */
-const void *get_commit_buffer(const struct commit *, unsigned long *size);
+const void *repo_get_commit_buffer(struct repository *r,
+                                  const struct commit *,
+                                  unsigned long *size);
+#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
+#define get_commit_buffer(c, s) repo_get_commit_buffer(the_repository, c, s)
+#endif
 
 /*
  * Tell the commit subsytem that we are done with a particular commit buffer.
@@ -117,12 +131,17 @@ const void *get_commit_buffer(const struct commit *, unsigned long *size);
  * from an earlier call to get_commit_buffer.  The buffer may or may not be
  * freed by this call; callers should not access the memory afterwards.
  */
-void unuse_commit_buffer(const struct commit *, const void *buffer);
+void repo_unuse_commit_buffer(struct repository *r,
+                             const struct commit *,
+                             const void *buffer);
+#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
+#define unuse_commit_buffer(c, b) repo_unuse_commit_buffer(the_repository, c, b)
+#endif
 
 /*
  * Free any cached object buffer associated with the commit.
  */
-void free_commit_buffer(struct commit *);
+void free_commit_buffer(struct parsed_object_pool *pool, struct commit *);
 
 struct tree *get_commit_tree(const struct commit *);
 struct object_id *get_commit_tree_oid(const struct commit *);
@@ -131,7 +150,7 @@ struct object_id *get_commit_tree_oid(const struct commit *);
  * Release memory related to a commit, including the parent list and
  * any cached object buffer.
  */
-void release_commit_memory(struct commit *c);
+void release_commit_memory(struct parsed_object_pool *pool, struct commit *c);
 
 /*
  * Disassociate any cached object buffer from the commit, but do not free it.
@@ -162,6 +181,14 @@ extern int has_non_ascii(const char *text);
 extern const char *logmsg_reencode(const struct commit *commit,
                                   char **commit_encoding,
                                   const char *output_encoding);
+const char *repo_logmsg_reencode(struct repository *r,
+                                const struct commit *commit,
+                                char **commit_encoding,
+                                const char *output_encoding);
+#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
+#define logmsg_reencode(c, enc, out) repo_logmsg_reencode(the_repository, c, enc, out)
+#endif
+
 extern const char *skip_blank_lines(const char *msg);
 
 /** Removes the first commit from a list sorted by date, and adds all
index b459e1a291ab0fe906c9a53a0fbcc61ad2c7e153..4276297595e21064abe2c0fb496f90d39455e200 100644 (file)
@@ -7,6 +7,7 @@
 #include "../cache.h"
 #include "win32/lazyload.h"
 #include "../config.h"
+#include "dir.h"
 
 #define HCAST(type, handle) ((type)(intptr_t)handle)
 
@@ -1031,7 +1032,7 @@ char *mingw_getcwd(char *pointer, int len)
  * See "Parsing C++ Command-Line Arguments" at Microsoft's Docs:
  * https://docs.microsoft.com/en-us/cpp/cpp/parsing-cpp-command-line-arguments
  */
-static const char *quote_arg(const char *arg)
+static const char *quote_arg_msvc(const char *arg)
 {
        /* count chars to quote */
        int len = 0, n = 0;
@@ -1086,6 +1087,37 @@ static const char *quote_arg(const char *arg)
        return q;
 }
 
+#include "quote.h"
+
+static const char *quote_arg_msys2(const char *arg)
+{
+       struct strbuf buf = STRBUF_INIT;
+       const char *p2 = arg, *p;
+
+       for (p = arg; *p; p++) {
+               int ws = isspace(*p);
+               if (!ws && *p != '\\' && *p != '"' && *p != '{')
+                       continue;
+               if (!buf.len)
+                       strbuf_addch(&buf, '"');
+               if (p != p2)
+                       strbuf_add(&buf, p2, p - p2);
+               if (!ws && *p != '{')
+                       strbuf_addch(&buf, '\\');
+               p2 = p;
+       }
+
+       if (p == arg)
+               strbuf_addch(&buf, '"');
+       else if (!buf.len)
+               return arg;
+       else
+               strbuf_add(&buf, p2, p - p2),
+
+       strbuf_addch(&buf, '"');
+       return strbuf_detach(&buf, 0);
+}
+
 static const char *parse_interpreter(const char *cmd)
 {
        static char buf[100];
@@ -1317,6 +1349,47 @@ struct pinfo_t {
 static struct pinfo_t *pinfo = NULL;
 CRITICAL_SECTION pinfo_cs;
 
+/* Used to match and chomp off path components */
+static inline int match_last_path_component(const char *path, size_t *len,
+                                           const char *component)
+{
+       size_t component_len = strlen(component);
+       if (*len < component_len + 1 ||
+           !is_dir_sep(path[*len - component_len - 1]) ||
+           fspathncmp(path + *len - component_len, component, component_len))
+               return 0;
+       *len -= component_len + 1;
+       /* chomp off repeated dir separators */
+       while (*len > 0 && is_dir_sep(path[*len - 1]))
+               (*len)--;
+       return 1;
+}
+
+static int is_msys2_sh(const char *cmd)
+{
+       if (cmd && !strcmp(cmd, "sh")) {
+               static int ret = -1;
+               char *p;
+
+               if (ret >= 0)
+                       return ret;
+
+               p = path_lookup(cmd, 0);
+               if (!p)
+                       ret = 0;
+               else {
+                       size_t len = strlen(p);
+
+                       ret = match_last_path_component(p, &len, "sh.exe") &&
+                               match_last_path_component(p, &len, "bin") &&
+                               match_last_path_component(p, &len, "usr");
+                       free(p);
+               }
+               return ret;
+       }
+       return 0;
+}
+
 static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaenv,
                              const char *dir,
                              int prepend_cmd, int fhin, int fhout, int fherr)
@@ -1328,6 +1401,8 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
        unsigned flags = CREATE_UNICODE_ENVIRONMENT;
        BOOL ret;
        HANDLE cons;
+       const char *(*quote_arg)(const char *arg) =
+               is_msys2_sh(*argv) ? quote_arg_msys2 : quote_arg_msvc;
 
        do_unset_environment_variables();
 
@@ -2100,7 +2175,7 @@ static void stop_timer_thread(void)
        if (timer_event)
                SetEvent(timer_event);  /* tell thread to terminate */
        if (timer_thread) {
-               int rc = WaitForSingleObject(timer_thread, 1000);
+               int rc = WaitForSingleObject(timer_thread, 10000);
                if (rc == WAIT_TIMEOUT)
                        error("timer thread did not terminate timely");
                else if (rc != WAIT_OBJECT_0)
index 4d1d95beeb509b3bb159b4eaadf20deeb498e73a..27cd5c1ea1f9b3885740b25a161d152b515b43b6 100644 (file)
@@ -112,15 +112,15 @@ compat_symbol (libc, _obstack_compat, _obstack, GLIBC_2_0);
 
 # define CALL_CHUNKFUN(h, size) \
   (((h) -> use_extra_arg) \
-   ? (*(h)->chunkfun) ((h)->extra_arg, (size)) \
-   : (*(struct _obstack_chunk *(*) (long)) (h)->chunkfun) ((size)))
+   ? (*(h)->chunkfun.extra) ((h)->extra_arg, (size)) \
+   : (*(h)->chunkfun.plain) ((size)))
 
 # define CALL_FREEFUN(h, old_chunk) \
   do { \
     if ((h) -> use_extra_arg) \
-      (*(h)->freefun) ((h)->extra_arg, (old_chunk)); \
+      (*(h)->freefun.extra) ((h)->extra_arg, (old_chunk)); \
     else \
-      (*(void (*) (void *)) (h)->freefun) ((old_chunk)); \
+      (*(h)->freefun.plain) ((old_chunk)); \
   } while (0)
 
 \f
@@ -159,8 +159,8 @@ _obstack_begin (struct obstack *h,
       size = 4096 - extra;
     }
 
-  h->chunkfun = (struct _obstack_chunk * (*)(void *, long)) chunkfun;
-  h->freefun = (void (*) (void *, struct _obstack_chunk *)) freefun;
+  h->chunkfun.plain = chunkfun;
+  h->freefun.plain = freefun;
   h->chunk_size = size;
   h->alignment_mask = alignment - 1;
   h->use_extra_arg = 0;
@@ -206,8 +206,9 @@ _obstack_begin_1 (struct obstack *h, int size, int alignment,
       size = 4096 - extra;
     }
 
-  h->chunkfun = (struct _obstack_chunk * (*)(void *,long)) chunkfun;
-  h->freefun = (void (*) (void *, struct _obstack_chunk *)) freefun;
+  h->chunkfun.extra = (struct _obstack_chunk * (*)(void *,long)) chunkfun;
+  h->freefun.extra = (void (*) (void *, struct _obstack_chunk *)) freefun;
+
   h->chunk_size = size;
   h->alignment_mask = alignment - 1;
   h->extra_arg = arg;
index 6bc24b76445686b2ef55fe5461273e4c5b2cd4f7..ced94d01180a66b2f2d471c1ebaef4eec07e6c49 100644 (file)
@@ -160,11 +160,15 @@ struct obstack            /* control current object in current chunk */
     void *tempptr;
   } temp;                      /* Temporary for some macros.  */
   int   alignment_mask;                /* Mask of alignment for each object. */
-  /* These prototypes vary based on `use_extra_arg', and we use
-     casts to the prototypeless function type in all assignments,
-     but having prototypes here quiets -Wstrict-prototypes.  */
-  struct _obstack_chunk *(*chunkfun) (void *, long);
-  void (*freefun) (void *, struct _obstack_chunk *);
+  /* These prototypes vary based on `use_extra_arg'. */
+  union {
+    void *(*plain) (long);
+    struct _obstack_chunk *(*extra) (void *, long);
+  } chunkfun;
+  union {
+    void (*plain) (void *);
+    void (*extra) (void *, struct _obstack_chunk *);
+  } freefun;
   void *extra_arg;             /* first arg for chunk alloc/dealloc funcs */
   unsigned use_extra_arg:1;    /* chunk alloc/dealloc funcs take extra arg */
   unsigned maybe_empty_object:1;/* There is a possibility that the current
@@ -235,10 +239,10 @@ extern void (*obstack_alloc_failed_handler) (void);
                    (void (*) (void *, void *)) (freefun), (arg))
 
 #define obstack_chunkfun(h, newchunkfun) \
-  ((h) -> chunkfun = (struct _obstack_chunk *(*)(void *, long)) (newchunkfun))
+  ((h)->chunkfun.extra = (struct _obstack_chunk *(*)(void *, long)) (newchunkfun))
 
 #define obstack_freefun(h, newfreefun) \
-  ((h) -> freefun = (void (*)(void *, struct _obstack_chunk *)) (newfreefun))
+  ((h)->freefun.extra = (void (*)(void *, struct _obstack_chunk *)) (newfreefun))
 
 #define obstack_1grow_fast(h,achar) (*((h)->next_free)++ = (achar))
 
index de61c15d3483fc4a9e8e163bd7cfa5280996c61a..136250fbf6c4f7e707c25dba936e2effebd847f2 100644 (file)
@@ -79,7 +79,7 @@ void precompose_argv(int argc, const char **argv)
                size_t namelen;
                oldarg = argv[i];
                if (has_non_ascii(oldarg, (size_t)-1, &namelen)) {
-                       newarg = reencode_string_iconv(oldarg, namelen, ic_precompose, NULL);
+                       newarg = reencode_string_iconv(oldarg, namelen, ic_precompose, 0, NULL);
                        if (newarg)
                                argv[i] = newarg;
                }
index ff521eb27ad243b27c7bd95f3ad7a1b777a4ae00..24ad1a985400168e33778781d01d6e9e6c6ededf 100644 (file)
--- a/config.c
+++ b/config.c
@@ -2565,7 +2565,6 @@ static ssize_t write_pair(int fd, const char *key, const char *value,
  * entry (which all are to be removed).
  */
 static void maybe_remove_section(struct config_store_data *store,
-                                const char *contents,
                                 size_t *begin_offset, size_t *end_offset,
                                 int *seen_ptr)
 {
@@ -2850,7 +2849,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
                                replace_end = store.parsed[j].end;
                                copy_end = store.parsed[j].begin;
                                if (!value)
-                                       maybe_remove_section(&store, contents,
+                                       maybe_remove_section(&store,
                                                             &copy_end,
                                                             &replace_end, &i);
                                /*
index 24281b608284ee74b262237c467ff054874d8a8e..4813f005ab05279a72ef2894cfae8887965d9640 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -296,7 +296,6 @@ struct ref **get_remote_heads(struct packet_reader *reader,
        struct ref **orig_list = list;
        int len = 0;
        enum get_remote_heads_state state = EXPECTING_FIRST_REF;
-       const char *arg;
 
        *list = NULL;
 
@@ -306,8 +305,6 @@ struct ref **get_remote_heads(struct packet_reader *reader,
                        die_initial_contact(1);
                case PACKET_READ_NORMAL:
                        len = reader->pktlen;
-                       if (len > 4 && skip_prefix(reader->line, "ERR ", &arg))
-                               die(_("remote error: %s"), arg);
                        break;
                case PACKET_READ_FLUSH:
                        state = EXPECTING_DONE;
index e34eada1ad52933230c7fcace595677747f9e1d6..d9ada69b4323f2e9611aa6add5b21a77e622a7c8 100644 (file)
@@ -12,6 +12,36 @@ constant fmt !~ "%";
 )
   );
 
+@@
+expression E;
+struct strbuf SB;
+format F =~ "s";
+@@
+- strbuf_addf(E, "%@F@", SB.buf);
++ strbuf_addbuf(E, &SB);
+
+@@
+expression E;
+struct strbuf *SBP;
+format F =~ "s";
+@@
+- strbuf_addf(E, "%@F@", SBP->buf);
++ strbuf_addbuf(E, SBP);
+
+@@
+expression E;
+struct strbuf SB;
+@@
+- strbuf_addstr(E, SB.buf);
++ strbuf_addbuf(E, &SB);
+
+@@
+expression E;
+struct strbuf *SBP;
+@@
+- strbuf_addstr(E, SBP->buf);
++ strbuf_addbuf(E, SBP);
+
 @@
 expression E1, E2;
 format F =~ "s";
diff --git a/contrib/coccinelle/the_repository.pending.cocci b/contrib/coccinelle/the_repository.pending.cocci
new file mode 100644 (file)
index 0000000..2ee702e
--- /dev/null
@@ -0,0 +1,144 @@
+// This file is used for the ongoing refactoring of
+// bringing the index or repository struct in all of
+// our code base.
+
+@@
+expression E;
+expression F;
+expression G;
+@@
+- read_object_file(
++ repo_read_object_file(the_repository,
+  E, F, G)
+
+@@
+expression E;
+@@
+- has_sha1_file(
++ repo_has_sha1_file(the_repository,
+  E)
+
+@@
+expression E;
+expression F;
+@@
+- has_sha1_file_with_flags(
++ repo_has_sha1_file_with_flags(the_repository,
+  E)
+
+@@
+expression E;
+@@
+- has_object_file(
++ repo_has_object_file(the_repository,
+  E)
+
+@@
+expression E;
+expression F;
+@@
+- has_object_file_with_flags(
++ repo_has_object_file_with_flags(the_repository,
+  E)
+
+@@
+expression E;
+expression F;
+expression G;
+@@
+- parse_commit_internal(
++ repo_parse_commit_internal(the_repository,
+  E, F, G)
+
+@@
+expression E;
+expression F;
+@@
+- parse_commit_gently(
++ repo_parse_commit_gently(the_repository,
+  E, F)
+
+@@
+expression E;
+@@
+- parse_commit(
++ repo_parse_commit(the_repository,
+  E)
+
+@@
+expression E;
+expression F;
+@@
+- get_merge_bases(
++ repo_get_merge_bases(the_repository,
+  E, F);
+
+@@
+expression E;
+expression F;
+expression G;
+@@
+- get_merge_bases_many(
++ repo_get_merge_bases_many(the_repository,
+  E, F, G);
+
+@@
+expression E;
+expression F;
+expression G;
+@@
+- get_merge_bases_many_dirty(
++ repo_get_merge_bases_many_dirty(the_repository,
+  E, F, G);
+
+@@
+expression E;
+expression F;
+@@
+- in_merge_bases(
++ repo_in_merge_bases(the_repository,
+  E, F);
+
+@@
+expression E;
+expression F;
+expression G;
+@@
+- in_merge_bases_many(
++ repo_in_merge_bases_many(the_repository,
+  E, F, G);
+
+@@
+expression E;
+expression F;
+@@
+- get_commit_buffer(
++ repo_get_commit_buffer(the_repository,
+  E, F);
+
+@@
+expression E;
+expression F;
+@@
+- unuse_commit_buffer(
++ repo_unuse_commit_buffer(the_repository,
+  E, F);
+
+@@
+expression E;
+expression F;
+expression G;
+@@
+- logmsg_reencode(
++ repo_logmsg_reencode(the_repository,
+  E, F, G);
+
+@@
+expression E;
+expression F;
+expression G;
+expression H;
+@@
+- format_commit_message(
++ repo_format_commit_message(the_repository,
+  E, F, G, H);
index 0d89ae7c2302a4bff3a6fdcb4a7015a81eeb8025..5d0307fc1004f215c48a6f653e21da41bee71baa 100644 (file)
--- a/convert.c
+++ b/convert.c
@@ -1,4 +1,3 @@
-#define NO_THE_INDEX_COMPATIBILITY_MACROS
 #include "cache.h"
 #include "config.h"
 #include "object-store.h"
@@ -92,7 +91,7 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat *
  * The same heuristics as diff.c::mmfile_is_binary()
  * We treat files with bare CR as binary
  */
-static int convert_is_binary(unsigned long size, const struct text_stat *stats)
+static int convert_is_binary(const struct text_stat *stats)
 {
        if (stats->lonecr)
                return 1;
@@ -110,7 +109,7 @@ static unsigned int gather_convert_stats(const char *data, unsigned long size)
        if (!data || !size)
                return 0;
        gather_stats(data, size, &stats);
-       if (convert_is_binary(size, &stats))
+       if (convert_is_binary(&stats))
                ret |= CONVERT_STAT_BITS_BIN;
        if (stats.crlf)
                ret |= CONVERT_STAT_BITS_TXT_CRLF;
@@ -245,7 +244,7 @@ static int has_crlf_in_index(const struct index_state *istate, const char *path)
        return has_crlf;
 }
 
-static int will_convert_lf_to_crlf(size_t len, struct text_stat *stats,
+static int will_convert_lf_to_crlf(struct text_stat *stats,
                                   enum crlf_action crlf_action)
 {
        if (output_eol(crlf_action) != EOL_CRLF)
@@ -260,7 +259,7 @@ static int will_convert_lf_to_crlf(size_t len, struct text_stat *stats,
                if (stats->lonecr || stats->crlf)
                        return 0;
 
-               if (convert_is_binary(len, stats))
+               if (convert_is_binary(stats))
                        return 0;
        }
        return 1;
@@ -527,7 +526,7 @@ static int crlf_to_git(const struct index_state *istate,
        convert_crlf_into_lf = !!stats.crlf;
 
        if (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {
-               if (convert_is_binary(len, &stats))
+               if (convert_is_binary(&stats))
                        return 0;
                /*
                 * If the file in the index has any CR in it, do not
@@ -549,7 +548,7 @@ static int crlf_to_git(const struct index_state *istate,
                        new_stats.crlf = 0;
                }
                /* simulate "git checkout" */
-               if (will_convert_lf_to_crlf(len, &new_stats, crlf_action)) {
+               if (will_convert_lf_to_crlf(&new_stats, crlf_action)) {
                        new_stats.crlf += new_stats.lonelf;
                        new_stats.lonelf = 0;
                }
@@ -591,7 +590,7 @@ static int crlf_to_git(const struct index_state *istate,
        return 1;
 }
 
-static int crlf_to_worktree(const char *path, const char *src, size_t len,
+static int crlf_to_worktree(const char *src, size_t len,
                            struct strbuf *buf, enum crlf_action crlf_action)
 {
        char *to_free = NULL;
@@ -601,7 +600,7 @@ static int crlf_to_worktree(const char *path, const char *src, size_t len,
                return 0;
 
        gather_stats(src, len, &stats);
-       if (!will_convert_lf_to_crlf(len, &stats, crlf_action))
+       if (!will_convert_lf_to_crlf(&stats, crlf_action))
                return 0;
 
        /* are we "faking" in place editing ? */
@@ -1091,7 +1090,7 @@ static int count_ident(const char *cp, unsigned long size)
        return cnt;
 }
 
-static int ident_to_git(const char *path, const char *src, size_t len,
+static int ident_to_git(const char *src, size_t len,
                        struct strbuf *buf, int ident)
 {
        char *dst, *dollar;
@@ -1135,7 +1134,7 @@ static int ident_to_git(const char *path, const char *src, size_t len,
        return 1;
 }
 
-static int ident_to_worktree(const char *path, const char *src, size_t len,
+static int ident_to_worktree(const char *src, size_t len,
                             struct strbuf *buf, int ident)
 {
        struct object_id oid;
@@ -1416,7 +1415,7 @@ int convert_to_git(const struct index_state *istate,
                        len = dst->len;
                }
        }
-       return ret | ident_to_git(path, src, len, dst, ca.ident);
+       return ret | ident_to_git(src, len, dst, ca.ident);
 }
 
 void convert_to_git_filter_fd(const struct index_state *istate,
@@ -1434,7 +1433,7 @@ void convert_to_git_filter_fd(const struct index_state *istate,
 
        encode_to_git(path, dst->buf, dst->len, dst, ca.working_tree_encoding, conv_flags);
        crlf_to_git(istate, path, dst->buf, dst->len, dst, ca.crlf_action, conv_flags);
-       ident_to_git(path, dst->buf, dst->len, dst, ca.ident);
+       ident_to_git(dst->buf, dst->len, dst, ca.ident);
 }
 
 static int convert_to_working_tree_internal(const struct index_state *istate,
@@ -1447,7 +1446,7 @@ static int convert_to_working_tree_internal(const struct index_state *istate,
 
        convert_attrs(istate, &ca, path);
 
-       ret |= ident_to_worktree(path, src, len, dst, ca.ident);
+       ret |= ident_to_worktree(src, len, dst, ca.ident);
        if (ret) {
                src = dst->buf;
                len = dst->len;
@@ -1458,7 +1457,7 @@ static int convert_to_working_tree_internal(const struct index_state *istate,
         * support smudge).  The filters might expect CRLFs.
         */
        if ((ca.drv && (ca.drv->smudge || ca.drv->process)) || !normalizing) {
-               ret |= crlf_to_worktree(path, src, len, dst, ca.crlf_action);
+               ret |= crlf_to_worktree(src, len, dst, ca.crlf_action);
                if (ret) {
                        src = dst->buf;
                        len = dst->len;
diff --git a/date.c b/date.c
index 9bc15df6f9dfa635fe91760914473d953b7c970b..9c5870e102951ed25f5def2103dab15bf8ed5c99 100644 (file)
--- a/date.c
+++ b/date.c
@@ -77,22 +77,16 @@ static struct tm *time_to_tm_local(timestamp_t time)
 }
 
 /*
- * What value of "tz" was in effect back then at "time" in the
- * local timezone?
+ * Fill in the localtime 'struct tm' for the supplied time,
+ * and return the local tz.
  */
-static int local_tzoffset(timestamp_t time)
+static int local_time_tzoffset(time_t t, struct tm *tm)
 {
-       time_t t, t_local;
-       struct tm tm;
+       time_t t_local;
        int offset, eastwest;
 
-       if (date_overflows(time))
-               die("Timestamp too large for this system: %"PRItime, time);
-
-       t = (time_t)time;
-       localtime_r(&t, &tm);
-       t_local = tm_to_time_t(&tm);
-
+       localtime_r(&t, tm);
+       t_local = tm_to_time_t(tm);
        if (t_local == -1)
                return 0; /* error; just use +0000 */
        if (t_local < t) {
@@ -107,9 +101,36 @@ static int local_tzoffset(timestamp_t time)
        return offset * eastwest;
 }
 
-void show_date_relative(timestamp_t time, int tz,
-                              const struct timeval *now,
-                              struct strbuf *timebuf)
+/*
+ * What value of "tz" was in effect back then at "time" in the
+ * local timezone?
+ */
+static int local_tzoffset(timestamp_t time)
+{
+       struct tm tm;
+
+       if (date_overflows(time))
+               die("Timestamp too large for this system: %"PRItime, time);
+
+       return local_time_tzoffset((time_t)time, &tm);
+}
+
+static void get_time(struct timeval *now)
+{
+       const char *x;
+
+       x = getenv("GIT_TEST_DATE_NOW");
+       if (x) {
+               now->tv_sec = atoi(x);
+               now->tv_usec = 0;
+       }
+       else
+               gettimeofday(now, NULL);
+}
+
+void show_date_relative(timestamp_t time,
+                       const struct timeval *now,
+                       struct strbuf *timebuf)
 {
        timestamp_t diff;
        if (now->tv_sec < time) {
@@ -191,9 +212,80 @@ struct date_mode *date_mode_from_type(enum date_mode_type type)
        return &mode;
 }
 
+static void show_date_normal(struct strbuf *buf, timestamp_t time, struct tm *tm, int tz, struct tm *human_tm, int human_tz, int local)
+{
+       struct {
+               unsigned int    year:1,
+                               date:1,
+                               wday:1,
+                               time:1,
+                               seconds:1,
+                               tz:1;
+       } hide = { 0 };
+
+       hide.tz = local || tz == human_tz;
+       hide.year = tm->tm_year == human_tm->tm_year;
+       if (hide.year) {
+               if (tm->tm_mon == human_tm->tm_mon) {
+                       if (tm->tm_mday > human_tm->tm_mday) {
+                               /* Future date: think timezones */
+                       } else if (tm->tm_mday == human_tm->tm_mday) {
+                               hide.date = hide.wday = 1;
+                       } else if (tm->tm_mday + 5 > human_tm->tm_mday) {
+                               /* Leave just weekday if it was a few days ago */
+                               hide.date = 1;
+                       }
+               }
+       }
+
+       /* Show "today" times as just relative times */
+       if (hide.wday) {
+               struct timeval now;
+               get_time(&now);
+               show_date_relative(time, &now, buf);
+               return;
+       }
+
+       /*
+        * Always hide seconds for human-readable.
+        * Hide timezone if showing date.
+        * Hide weekday and time if showing year.
+        *
+        * The logic here is two-fold:
+        *  (a) only show details when recent enough to matter
+        *  (b) keep the maximum length "similar", and in check
+        */
+       if (human_tm->tm_year) {
+               hide.seconds = 1;
+               hide.tz |= !hide.date;
+               hide.wday = hide.time = !hide.year;
+       }
+
+       if (!hide.wday)
+               strbuf_addf(buf, "%.3s ", weekday_names[tm->tm_wday]);
+       if (!hide.date)
+               strbuf_addf(buf, "%.3s %d ", month_names[tm->tm_mon], tm->tm_mday);
+
+       /* Do we want AM/PM depending on locale? */
+       if (!hide.time) {
+               strbuf_addf(buf, "%02d:%02d", tm->tm_hour, tm->tm_min);
+               if (!hide.seconds)
+                       strbuf_addf(buf, ":%02d", tm->tm_sec);
+       } else
+               strbuf_rtrim(buf);
+
+       if (!hide.year)
+               strbuf_addf(buf, " %d", tm->tm_year + 1900);
+
+       if (!hide.tz)
+               strbuf_addf(buf, " %+05d", tz);
+}
+
 const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)
 {
        struct tm *tm;
+       struct tm human_tm = { 0 };
+       int human_tz = -1;
        static struct strbuf timebuf = STRBUF_INIT;
 
        if (mode->type == DATE_UNIX) {
@@ -202,6 +294,15 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)
                return timebuf.buf;
        }
 
+       if (mode->type == DATE_HUMAN) {
+               struct timeval now;
+
+               get_time(&now);
+
+               /* Fill in the data for "current time" in human_tz and human_tm */
+               human_tz = local_time_tzoffset(now.tv_sec, &human_tm);
+       }
+
        if (mode->local)
                tz = local_tzoffset(time);
 
@@ -215,8 +316,8 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)
                struct timeval now;
 
                strbuf_reset(&timebuf);
-               gettimeofday(&now, NULL);
-               show_date_relative(time, tz, &now, &timebuf);
+               get_time(&now);
+               show_date_relative(time, &now, &timebuf);
                return timebuf.buf;
        }
 
@@ -258,14 +359,7 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)
                strbuf_addftime(&timebuf, mode->strftime_fmt, tm, tz,
                                !mode->local);
        else
-               strbuf_addf(&timebuf, "%.3s %.3s %d %02d:%02d:%02d %d%c%+05d",
-                               weekday_names[tm->tm_wday],
-                               month_names[tm->tm_mon],
-                               tm->tm_mday,
-                               tm->tm_hour, tm->tm_min, tm->tm_sec,
-                               tm->tm_year + 1900,
-                               mode->local ? 0 : ' ',
-                               tz);
+               show_date_normal(&timebuf, time, tm, tz, &human_tm, human_tz, mode->local);
        return timebuf.buf;
 }
 
@@ -819,6 +913,8 @@ static enum date_mode_type parse_date_type(const char *format, const char **end)
                return DATE_SHORT;
        if (skip_prefix(format, "default", end))
                return DATE_NORMAL;
+       if (skip_prefix(format, "human", end))
+               return DATE_HUMAN;
        if (skip_prefix(format, "raw", end))
                return DATE_RAW;
        if (skip_prefix(format, "unix", end))
@@ -833,6 +929,14 @@ void parse_date_format(const char *format, struct date_mode *mode)
 {
        const char *p;
 
+       /* "auto:foo" is "if tty/pager, then foo, otherwise normal" */
+       if (skip_prefix(format, "auto:", &p)) {
+               if (isatty(1) || pager_in_use())
+                       format = p;
+               else
+                       format = "default";
+       }
+
        /* historical alias */
        if (!strcmp(format, "local"))
                format = "default-local";
@@ -1205,7 +1309,7 @@ timestamp_t approxidate_careful(const char *date, int *error_ret)
                return timestamp;
        }
 
-       gettimeofday(&tv, NULL);
+       get_time(&tv);
        return approxidate_str(date, &tv, error_ret);
 }
 
diff --git a/diff.c b/diff.c
index e8c3e8081f9be0c4e9560a834b0f3df75ca81b72..5306c48652db59e84c26383d68cf4a7d896647d4 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -5962,8 +5962,10 @@ static void diff_flush_patch_all_file_pairs(struct diff_options *o)
 
                for (i = 0; i < esm.nr; i++)
                        free((void *)esm.buf[i].line);
+               esm.nr = 0;
+
+               o->emitted_symbols = NULL;
        }
-       esm.nr = 0;
 }
 
 void diff_flush(struct diff_options *options)
diff --git a/dir.c b/dir.c
index 21284482198147687fb03892265f97ac5ed58d18..b2cabadf2503b22cc10b3e47c548a5904d77158e 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -7,7 +7,6 @@
  * Copyright (C) Linus Torvalds, 2005-2006
  *              Junio Hamano, 2005-2006
  */
-#define NO_THE_INDEX_COMPATIBILITY_MACROS
 #include "cache.h"
 #include "config.h"
 #include "dir.h"
index 577faa6229d073768195dff6bcb0f113e5fbd4be..08b3b356faeabdeeff90918142f7225ce5460e8c 100644 (file)
@@ -135,38 +135,42 @@ enum ack_type {
        ACK_ready
 };
 
-static void consume_shallow_list(struct fetch_pack_args *args, int fd)
+static void consume_shallow_list(struct fetch_pack_args *args,
+                                struct packet_reader *reader)
 {
        if (args->stateless_rpc && args->deepen) {
                /* If we sent a depth we will get back "duplicate"
                 * shallow and unshallow commands every time there
                 * is a block of have lines exchanged.
                 */
-               char *line;
-               while ((line = packet_read_line(fd, NULL))) {
-                       if (starts_with(line, "shallow "))
+               while (packet_reader_read(reader) == PACKET_READ_NORMAL) {
+                       if (starts_with(reader->line, "shallow "))
                                continue;
-                       if (starts_with(line, "unshallow "))
+                       if (starts_with(reader->line, "unshallow "))
                                continue;
                        die(_("git fetch-pack: expected shallow list"));
                }
+               if (reader->status != PACKET_READ_FLUSH)
+                       die(_("git fetch-pack: expected a flush packet after shallow list"));
        }
 }
 
-static enum ack_type get_ack(int fd, struct object_id *result_oid)
+static enum ack_type get_ack(struct packet_reader *reader,
+                            struct object_id *result_oid)
 {
        int len;
-       char *line = packet_read_line(fd, &len);
        const char *arg;
 
-       if (!line)
+       if (packet_reader_read(reader) != PACKET_READ_NORMAL)
                die(_("git fetch-pack: expected ACK/NAK, got a flush packet"));
-       if (!strcmp(line, "NAK"))
+       len = reader->pktlen;
+
+       if (!strcmp(reader->line, "NAK"))
                return NAK;
-       if (skip_prefix(line, "ACK ", &arg)) {
+       if (skip_prefix(reader->line, "ACK ", &arg)) {
                if (!get_oid_hex(arg, result_oid)) {
                        arg += 40;
-                       len -= arg - line;
+                       len -= arg - reader->line;
                        if (len < 1)
                                return ACK;
                        if (strstr(arg, "continue"))
@@ -178,9 +182,7 @@ static enum ack_type get_ack(int fd, struct object_id *result_oid)
                        return ACK;
                }
        }
-       if (skip_prefix(line, "ERR ", &arg))
-               die(_("remote error: %s"), arg);
-       die(_("git fetch-pack: expected ACK/NAK, got '%s'"), line);
+       die(_("git fetch-pack: expected ACK/NAK, got '%s'"), reader->line);
 }
 
 static void send_request(struct fetch_pack_args *args,
@@ -248,10 +250,15 @@ static int find_common(struct fetch_negotiator *negotiator,
        int got_ready = 0;
        struct strbuf req_buf = STRBUF_INIT;
        size_t state_len = 0;
+       struct packet_reader reader;
 
        if (args->stateless_rpc && multi_ack == 1)
                die(_("--stateless-rpc requires multi_ack_detailed"));
 
+       packet_reader_init(&reader, fd[0], NULL, 0,
+                          PACKET_READ_CHOMP_NEWLINE |
+                          PACKET_READ_DIE_ON_ERR_PACKET);
+
        if (!args->no_dependents) {
                mark_tips(negotiator, args->negotiation_tips);
                for_each_cached_alternate(negotiator, insert_one_alternate_object);
@@ -329,38 +336,42 @@ static int find_common(struct fetch_negotiator *negotiator,
                        packet_buf_write(&req_buf, "deepen-not %s", s->string);
                }
        }
-       if (server_supports_filtering && args->filter_options.choice)
+       if (server_supports_filtering && args->filter_options.choice) {
+               struct strbuf expanded_filter_spec = STRBUF_INIT;
+               expand_list_objects_filter_spec(&args->filter_options,
+                                               &expanded_filter_spec);
                packet_buf_write(&req_buf, "filter %s",
-                                args->filter_options.filter_spec);
+                                expanded_filter_spec.buf);
+               strbuf_release(&expanded_filter_spec);
+       }
        packet_buf_flush(&req_buf);
        state_len = req_buf.len;
 
        if (args->deepen) {
-               char *line;
                const char *arg;
                struct object_id oid;
 
                send_request(args, fd[1], &req_buf);
-               while ((line = packet_read_line(fd[0], NULL))) {
-                       if (skip_prefix(line, "shallow ", &arg)) {
+               while (packet_reader_read(&reader) == PACKET_READ_NORMAL) {
+                       if (skip_prefix(reader.line, "shallow ", &arg)) {
                                if (get_oid_hex(arg, &oid))
-                                       die(_("invalid shallow line: %s"), line);
+                                       die(_("invalid shallow line: %s"), reader.line);
                                register_shallow(the_repository, &oid);
                                continue;
                        }
-                       if (skip_prefix(line, "unshallow ", &arg)) {
+                       if (skip_prefix(reader.line, "unshallow ", &arg)) {
                                if (get_oid_hex(arg, &oid))
-                                       die(_("invalid unshallow line: %s"), line);
+                                       die(_("invalid unshallow line: %s"), reader.line);
                                if (!lookup_object(the_repository, oid.hash))
-                                       die(_("object not found: %s"), line);
+                                       die(_("object not found: %s"), reader.line);
                                /* make sure that it is parsed as shallow */
                                if (!parse_object(the_repository, &oid))
-                                       die(_("error in object: %s"), line);
+                                       die(_("error in object: %s"), reader.line);
                                if (unregister_shallow(&oid))
-                                       die(_("no shallow found: %s"), line);
+                                       die(_("no shallow found: %s"), reader.line);
                                continue;
                        }
-                       die(_("expected shallow/unshallow, got %s"), line);
+                       die(_("expected shallow/unshallow, got %s"), reader.line);
                }
        } else if (!args->stateless_rpc)
                send_request(args, fd[1], &req_buf);
@@ -397,9 +408,9 @@ static int find_common(struct fetch_negotiator *negotiator,
                        if (!args->stateless_rpc && count == INITIAL_FLUSH)
                                continue;
 
-                       consume_shallow_list(args, fd[0]);
+                       consume_shallow_list(args, &reader);
                        do {
-                               ack = get_ack(fd[0], result_oid);
+                               ack = get_ack(&reader, result_oid);
                                if (ack)
                                        print_verbose(args, _("got %s %d %s"), "ack",
                                                      ack, oid_to_hex(result_oid));
@@ -469,9 +480,9 @@ static int find_common(struct fetch_negotiator *negotiator,
        strbuf_release(&req_buf);
 
        if (!got_ready || !no_done)
-               consume_shallow_list(args, fd[0]);
+               consume_shallow_list(args, &reader);
        while (flushes || multi_ack) {
-               int ack = get_ack(fd[0], result_oid);
+               int ack = get_ack(&reader, result_oid);
                if (ack) {
                        print_verbose(args, _("got %s (%d) %s"), "ack",
                                      ack, oid_to_hex(result_oid));
@@ -1086,7 +1097,8 @@ static int add_haves(struct fetch_negotiator *negotiator,
 static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out,
                              const struct fetch_pack_args *args,
                              const struct ref *wants, struct oidset *common,
-                             int *haves_to_send, int *in_vain)
+                             int *haves_to_send, int *in_vain,
+                             int sideband_all)
 {
        int ret = 0;
        struct strbuf req_buf = STRBUF_INIT;
@@ -1112,6 +1124,8 @@ static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out,
                packet_buf_write(&req_buf, "include-tag");
        if (prefer_ofs_delta)
                packet_buf_write(&req_buf, "ofs-delta");
+       if (sideband_all)
+               packet_buf_write(&req_buf, "sideband-all");
 
        /* Add shallow-info and deepen request */
        if (server_supports_feature("fetch", "shallow", 0))
@@ -1122,9 +1136,13 @@ static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out,
        /* Add filter */
        if (server_supports_feature("fetch", "filter", 0) &&
            args->filter_options.choice) {
+               struct strbuf expanded_filter_spec = STRBUF_INIT;
                print_verbose(args, _("Server supports filter"));
+               expand_list_objects_filter_spec(&args->filter_options,
+                                               &expanded_filter_spec);
                packet_buf_write(&req_buf, "filter %s",
-                                args->filter_options.filter_spec);
+                                expanded_filter_spec.buf);
+               strbuf_release(&expanded_filter_spec);
        } else if (args->filter_options.choice) {
                warning("filtering not recognized by server, ignoring");
        }
@@ -1325,7 +1343,13 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
        struct fetch_negotiator negotiator;
        fetch_negotiator_init(&negotiator, negotiation_algorithm);
        packet_reader_init(&reader, fd[0], NULL, 0,
-                          PACKET_READ_CHOMP_NEWLINE);
+                          PACKET_READ_CHOMP_NEWLINE |
+                          PACKET_READ_DIE_ON_ERR_PACKET);
+       if (git_env_bool("GIT_TEST_SIDEBAND_ALL", 1) &&
+           server_supports_feature("fetch", "sideband-all", 0)) {
+               reader.use_sideband = 1;
+               reader.me = "fetch-pack";
+       }
 
        while (state != FETCH_DONE) {
                switch (state) {
@@ -1359,7 +1383,8 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
                case FETCH_SEND_REQUEST:
                        if (send_fetch_request(&negotiator, fd[1], args, ref,
                                               &common,
-                                              &haves_to_send, &in_vain))
+                                              &haves_to_send, &in_vain,
+                                              reader.use_sideband))
                                state = FETCH_GET_PACK;
                        else
                                state = FETCH_PROCESS_ACKS;
diff --git a/fuzz-commit-graph.c b/fuzz-commit-graph.c
new file mode 100644 (file)
index 0000000..cf790c9
--- /dev/null
@@ -0,0 +1,16 @@
+#include "commit-graph.h"
+
+struct commit_graph *parse_commit_graph(void *graph_map, int fd,
+                                       size_t graph_size);
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+       struct commit_graph *g;
+
+       g = parse_commit_graph((void *)data, -1, size);
+       free(g);
+
+       return 0;
+}
index 54cbfecc5ab0531513ff9e069be55d74339ad427..efee12b8b1e6d53d3cd5275683ebb0a4198b4b95 100755 (executable)
@@ -71,122 +71,7 @@ bisect_autostart() {
 }
 
 bisect_start() {
-       #
-       # Check for one bad and then some good revisions.
-       #
-       has_double_dash=0
-       for arg; do
-               case "$arg" in --) has_double_dash=1; break ;; esac
-       done
-       orig_args=$(git rev-parse --sq-quote "$@")
-       bad_seen=0
-       eval=''
-       must_write_terms=0
-       revs=''
-       if test "z$(git rev-parse --is-bare-repository)" != zfalse
-       then
-               mode=--no-checkout
-       else
-               mode=''
-       fi
-       while [ $# -gt 0 ]; do
-               arg="$1"
-               case "$arg" in
-               --)
-                       shift
-                       break
-               ;;
-               --no-checkout)
-                       mode=--no-checkout
-                       shift ;;
-               --term-good|--term-old)
-                       shift
-                       must_write_terms=1
-                       TERM_GOOD=$1
-                       shift ;;
-               --term-good=*|--term-old=*)
-                       must_write_terms=1
-                       TERM_GOOD=${1#*=}
-                       shift ;;
-               --term-bad|--term-new)
-                       shift
-                       must_write_terms=1
-                       TERM_BAD=$1
-                       shift ;;
-               --term-bad=*|--term-new=*)
-                       must_write_terms=1
-                       TERM_BAD=${1#*=}
-                       shift ;;
-               --*)
-                       die "$(eval_gettext "unrecognised option: '\$arg'")" ;;
-               *)
-                       rev=$(git rev-parse -q --verify "$arg^{commit}") || {
-                               test $has_double_dash -eq 1 &&
-                               die "$(eval_gettext "'\$arg' does not appear to be a valid revision")"
-                               break
-                       }
-                       revs="$revs $rev"
-                       shift
-                       ;;
-               esac
-       done
-
-       for rev in $revs
-       do
-               # The user ran "git bisect start <sha1>
-               # <sha1>", hence did not explicitly specify
-               # the terms, but we are already starting to
-               # set references named with the default terms,
-               # and won't be able to change afterwards.
-               must_write_terms=1
-
-               case $bad_seen in
-               0) state=$TERM_BAD ; bad_seen=1 ;;
-               *) state=$TERM_GOOD ;;
-               esac
-               eval="$eval bisect_write '$state' '$rev' 'nolog' &&"
-       done
-       #
-       # Verify HEAD.
-       #
-       head=$(GIT_DIR="$GIT_DIR" git symbolic-ref -q HEAD) ||
-       head=$(GIT_DIR="$GIT_DIR" git rev-parse --verify HEAD) ||
-       die "$(gettext "Bad HEAD - I need a HEAD")"
-
-       #
-       # Check if we are bisecting.
-       #
-       start_head=''
-       if test -s "$GIT_DIR/BISECT_START"
-       then
-               # Reset to the rev from where we started.
-               start_head=$(cat "$GIT_DIR/BISECT_START")
-               if test "z$mode" != "z--no-checkout"
-               then
-                       git checkout "$start_head" -- ||
-                       die "$(eval_gettext "Checking out '\$start_head' failed. Try 'git bisect reset <valid-branch>'.")"
-               fi
-       else
-               # Get rev from where we start.
-               case "$head" in
-               refs/heads/*|$_x40)
-                       # This error message should only be triggered by
-                       # cogito usage, and cogito users should understand
-                       # it relates to cg-seek.
-                       [ -s "$GIT_DIR/head-name" ] &&
-                               die "$(gettext "won't bisect on cg-seek'ed tree")"
-                       start_head="${head#refs/heads/}"
-                       ;;
-               *)
-                       die "$(gettext "Bad HEAD - strange symbolic ref")"
-                       ;;
-               esac
-       fi
-
-       #
-       # Get rid of any old bisect state.
-       #
-       git bisect--helper --bisect-clean-state || exit
+       git bisect--helper --bisect-start $@ || exit
 
        #
        # Change state.
@@ -198,45 +83,15 @@ bisect_start() {
        trap 'git bisect--helper --bisect-clean-state' 0
        trap 'exit 255' 1 2 3 15
 
-       #
-       # Write new start state.
-       #
-       echo "$start_head" >"$GIT_DIR/BISECT_START" && {
-               test "z$mode" != "z--no-checkout" ||
-               git update-ref --no-deref BISECT_HEAD "$start_head"
-       } &&
-       git rev-parse --sq-quote "$@" >"$GIT_DIR/BISECT_NAMES" &&
-       eval "$eval true" &&
-       if test $must_write_terms -eq 1
-       then
-               git bisect--helper --write-terms "$TERM_BAD" "$TERM_GOOD" || exit
-       fi &&
-       echo "git bisect start$orig_args" >>"$GIT_DIR/BISECT_LOG" || exit
        #
        # Check if we can proceed to the next bisect state.
        #
+       get_terms
        bisect_auto_next
 
        trap '-' 0
 }
 
-bisect_write() {
-       state="$1"
-       rev="$2"
-       nolog="$3"
-       case "$state" in
-               "$TERM_BAD")
-                       tag="$state" ;;
-               "$TERM_GOOD"|skip)
-                       tag="$state"-"$rev" ;;
-               *)
-                       die "$(eval_gettext "Bad bisect_write argument: \$state")" ;;
-       esac
-       git update-ref "refs/bisect/$tag" "$rev" || exit
-       echo "# $state: $(git show-branch $rev)" >>"$GIT_DIR/BISECT_LOG"
-       test -n "$nolog" || echo "git bisect $state $rev" >>"$GIT_DIR/BISECT_LOG"
-}
-
 bisect_skip() {
        all=''
        for arg in "$@"
@@ -255,7 +110,8 @@ bisect_skip() {
 bisect_state() {
        bisect_autostart
        state=$1
-       check_and_set_terms $state
+       git bisect--helper --check-and-set-terms $state $TERM_GOOD $TERM_BAD || exit
+       get_terms
        case "$#,$state" in
        0,*)
                die "Please call 'bisect_state' with at least one argument." ;;
@@ -263,7 +119,7 @@ bisect_state() {
                bisected_head=$(bisect_head)
                rev=$(git rev-parse --verify "$bisected_head") ||
                        die "$(eval_gettext "Bad rev input: \$bisected_head")"
-               bisect_write "$state" "$rev"
+               git bisect--helper --bisect-write "$state" "$rev" "$TERM_GOOD" "$TERM_BAD" || exit
                git bisect--helper --check-expected-revs "$rev" ;;
        2,"$TERM_BAD"|*,"$TERM_GOOD"|*,skip)
                shift
@@ -276,7 +132,7 @@ bisect_state() {
                done
                for rev in $hash_list
                do
-                       bisect_write "$state" "$rev"
+                       git bisect--helper --bisect-write "$state" "$rev" "$TERM_GOOD" "$TERM_BAD" || exit
                done
                git bisect--helper --check-expected-revs $hash_list ;;
        *,"$TERM_BAD")
@@ -287,59 +143,14 @@ bisect_state() {
        bisect_auto_next
 }
 
-bisect_next_check() {
-       missing_good= missing_bad=
-       git show-ref -q --verify refs/bisect/$TERM_BAD || missing_bad=t
-       test -n "$(git for-each-ref "refs/bisect/$TERM_GOOD-*")" || missing_good=t
-
-       case "$missing_good,$missing_bad,$1" in
-       ,,*)
-               : have both $TERM_GOOD and $TERM_BAD - ok
-               ;;
-       *,)
-               # do not have both but not asked to fail - just report.
-               false
-               ;;
-       t,,"$TERM_GOOD")
-               # have bad (or new) but not good (or old).  we could bisect although
-               # this is less optimum.
-               eval_gettextln "Warning: bisecting only with a \$TERM_BAD commit." >&2
-               if test -t 0
-               then
-                       # TRANSLATORS: Make sure to include [Y] and [n] in your
-                       # translation. The program will only accept English input
-                       # at this point.
-                       gettext "Are you sure [Y/n]? " >&2
-                       read yesno
-                       case "$yesno" in [Nn]*) exit 1 ;; esac
-               fi
-               : bisect without $TERM_GOOD...
-               ;;
-       *)
-               bad_syn=$(bisect_voc bad)
-               good_syn=$(bisect_voc good)
-               if test -s "$GIT_DIR/BISECT_START"
-               then
-
-                       eval_gettextln "You need to give me at least one \$bad_syn and one \$good_syn revision.
-(You can use \"git bisect \$bad_syn\" and \"git bisect \$good_syn\" for that.)" >&2
-               else
-                       eval_gettextln "You need to start by \"git bisect start\".
-You then need to give me at least one \$good_syn and one \$bad_syn revision.
-(You can use \"git bisect \$bad_syn\" and \"git bisect \$good_syn\" for that.)" >&2
-               fi
-               exit 1 ;;
-       esac
-}
-
 bisect_auto_next() {
-       bisect_next_check && bisect_next || :
+       git bisect--helper --bisect-next-check $TERM_GOOD $TERM_BAD && bisect_next || :
 }
 
 bisect_next() {
        case "$#" in 0) ;; *) usage ;; esac
        bisect_autostart
-       bisect_next_check $TERM_GOOD
+       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 $(test -f "$GIT_DIR/BISECT_HEAD" && echo --no-checkout)
@@ -371,7 +182,7 @@ bisect_next() {
 }
 
 bisect_visualize() {
-       bisect_next_check fail
+       git bisect--helper --bisect-next-check $TERM_GOOD $TERM_BAD fail || exit
 
        if test $# = 0
        then
@@ -393,35 +204,11 @@ bisect_visualize() {
        eval '"$@"' --bisect -- $(cat "$GIT_DIR/BISECT_NAMES")
 }
 
-bisect_reset() {
-       test -s "$GIT_DIR/BISECT_START" || {
-               gettextln "We are not bisecting."
-               return
-       }
-       case "$#" in
-       0) branch=$(cat "$GIT_DIR/BISECT_START") ;;
-       1) git rev-parse --quiet --verify "$1^{commit}" >/dev/null || {
-                       invalid="$1"
-                       die "$(eval_gettext "'\$invalid' is not a valid commit")"
-               }
-               branch="$1" ;;
-       *)
-               usage ;;
-       esac
-
-       if ! test -f "$GIT_DIR/BISECT_HEAD" && ! git checkout "$branch" --
-       then
-               die "$(eval_gettext "Could not check out original HEAD '\$branch'.
-Try 'git bisect reset <commit>'.")"
-       fi
-       git bisect--helper --bisect-clean-state || exit
-}
-
 bisect_replay () {
        file="$1"
        test "$#" -eq 1 || die "$(gettext "No logfile given")"
        test -r "$file" || die "$(eval_gettext "cannot read \$file for replaying")"
-       bisect_reset
+       git bisect--helper --bisect-reset || exit
        while read git bisect command rev
        do
                test "$git $bisect" = "git bisect" || test "$git" = "git-bisect" || continue
@@ -431,15 +218,16 @@ bisect_replay () {
                        command="$bisect"
                fi
                get_terms
-               check_and_set_terms "$command"
+               git bisect--helper --check-and-set-terms "$command" "$TERM_GOOD" "$TERM_BAD" || exit
+               get_terms
                case "$command" in
                start)
                        cmd="bisect_start $rev"
                        eval "$cmd" ;;
                "$TERM_GOOD"|"$TERM_BAD"|skip)
-                       bisect_write "$command" "$rev" ;;
+                       git bisect--helper --bisect-write "$command" "$rev" "$TERM_GOOD" "$TERM_BAD" || exit;;
                terms)
-                       bisect_terms $rev ;;
+                       git bisect--helper --bisect-terms $rev || exit;;
                *)
                        die "$(gettext "?? what are you talking about?")" ;;
                esac
@@ -448,7 +236,7 @@ bisect_replay () {
 }
 
 bisect_run () {
-       bisect_next_check fail
+       git bisect--helper --bisect-next-check $TERM_GOOD $TERM_BAD fail || exit
 
        test -n "$*" || die "$(gettext "bisect run failed: no command provided.")"
 
@@ -523,74 +311,6 @@ get_terms () {
        fi
 }
 
-check_and_set_terms () {
-       cmd="$1"
-       case "$cmd" in
-       skip|start|terms) ;;
-       *)
-               if test -s "$GIT_DIR/BISECT_TERMS" && test "$cmd" != "$TERM_BAD" && test "$cmd" != "$TERM_GOOD"
-               then
-                       die "$(eval_gettext "Invalid command: you're currently in a \$TERM_BAD/\$TERM_GOOD bisect.")"
-               fi
-               case "$cmd" in
-               bad|good)
-                       if ! test -s "$GIT_DIR/BISECT_TERMS"
-                       then
-                               TERM_BAD=bad
-                               TERM_GOOD=good
-                               git bisect--helper --write-terms "$TERM_BAD" "$TERM_GOOD" || exit
-                       fi
-                       ;;
-               new|old)
-                       if ! test -s "$GIT_DIR/BISECT_TERMS"
-                       then
-                               TERM_BAD=new
-                               TERM_GOOD=old
-                               git bisect--helper --write-terms "$TERM_BAD" "$TERM_GOOD" || exit
-                       fi
-                       ;;
-               esac ;;
-       esac
-}
-
-bisect_voc () {
-       case "$1" in
-       bad) echo "bad|new" ;;
-       good) echo "good|old" ;;
-       esac
-}
-
-bisect_terms () {
-       get_terms
-       if ! test -s "$GIT_DIR/BISECT_TERMS"
-       then
-               die "$(gettext "no terms defined")"
-       fi
-       case "$#" in
-       0)
-               gettextln "Your current terms are $TERM_GOOD for the old state
-and $TERM_BAD for the new state."
-               ;;
-       1)
-               arg=$1
-               case "$arg" in
-                       --term-good|--term-old)
-                               printf '%s\n' "$TERM_GOOD"
-                               ;;
-                       --term-bad|--term-new)
-                               printf '%s\n' "$TERM_BAD"
-                               ;;
-                       *)
-                               die "$(eval_gettext "invalid argument \$arg for 'git bisect terms'.
-Supported options are: --term-good|--term-old and --term-bad|--term-new.")"
-                               ;;
-               esac
-               ;;
-       *)
-               usage ;;
-       esac
-}
-
 case "$#" in
 0)
        usage ;;
@@ -613,7 +333,7 @@ case "$#" in
        visualize|view)
                bisect_visualize "$@" ;;
        reset)
-               bisect_reset "$@" ;;
+               git bisect--helper --bisect-reset "$@" ;;
        replay)
                bisect_replay "$@" ;;
        log)
@@ -621,7 +341,7 @@ case "$#" in
        run)
                bisect_run "$@" ;;
        terms)
-               bisect_terms "$@" ;;
+               git bisect--helper --bisect-terms "$@" || exit;;
        *)
                usage ;;
        esac
index eec264e6303684c5886804361c630e1572c1fe09..7c55229773e2bdb0f138b1180ab22d05c74ff904 100755 (executable)
@@ -67,6 +67,13 @@ resolve_full_httpd () {
                httpd_only="${httpd%% *}" # cut on first space
                return
                ;;
+       *python*)
+               # server is started by running via generated gitweb.py in
+               # $fqgitdir/gitweb
+               full_httpd="$fqgitdir/gitweb/gitweb.py"
+               httpd_only="${httpd%% *}" # cut on first space
+               return
+               ;;
        esac
 
        httpd_only="$(echo $httpd | cut -f1 -d' ')"
@@ -110,7 +117,7 @@ start_httpd () {
 
        # don't quote $full_httpd, there can be arguments to it (-f)
        case "$httpd" in
-       *mongoose*|*plackup*)
+       *mongoose*|*plackup*|*python*)
                #These servers don't have a daemon mode so we'll have to fork it
                $full_httpd "$conf" &
                #Save the pid before doing anything else (we'll print it later)
@@ -595,6 +602,121 @@ EOF
        rm -f "$conf"
 }
 
+python_conf() {
+       # Python's builtin http.server and its CGI support is very limited.
+       # CGI handler is capable of running CGI script only from inside a directory.
+       # Trying to set cgi_directories=["/"] will add double slash to SCRIPT_NAME
+       # and that in turn breaks gitweb's relative link generation.
+
+       # create a simple web root where $fqgitdir/gitweb/$httpd_only is our root
+       mkdir -p "$fqgitdir/gitweb/$httpd_only/cgi-bin"
+       # Python http.server follows the symlinks
+       ln -sf "$root/gitweb.cgi" "$fqgitdir/gitweb/$httpd_only/cgi-bin/gitweb.cgi"
+       ln -sf "$root/static" "$fqgitdir/gitweb/$httpd_only/"
+
+       # generate a standalone 'python http.server' script in $fqgitdir/gitweb
+       # This asumes that python is in user's $PATH
+       # This script is Python 2 and 3 compatible
+       cat > "$fqgitdir/gitweb/gitweb.py" <<EOF
+#!/usr/bin/env python
+import os
+import sys
+
+# Open log file in line buffering mode
+accesslogfile = open("$fqgitdir/gitweb/access.log", 'a', buffering=1)
+errorlogfile = open("$fqgitdir/gitweb/error.log", 'a', buffering=1)
+
+# and replace our stdout and stderr with log files
+# also do a lowlevel duplicate of the logfile file descriptors so that
+# our CGI child process writes any stderr warning also to the log file
+_orig_stdout_fd = sys.stdout.fileno()
+sys.stdout.close()
+os.dup2(accesslogfile.fileno(), _orig_stdout_fd)
+sys.stdout = accesslogfile
+
+_orig_stderr_fd = sys.stderr.fileno()
+sys.stderr.close()
+os.dup2(errorlogfile.fileno(), _orig_stderr_fd)
+sys.stderr = errorlogfile
+
+from functools import partial
+
+if sys.version_info < (3, 0):  # Python 2
+       from CGIHTTPServer import CGIHTTPRequestHandler
+       from BaseHTTPServer import HTTPServer as ServerClass
+else:  # Python 3
+       from http.server import CGIHTTPRequestHandler
+       from http.server import HTTPServer as ServerClass
+
+
+# Those environment variables will be passed to the cgi script
+os.environ.update({
+       "GIT_EXEC_PATH": "$GIT_EXEC_PATH",
+       "GIT_DIR": "$GIT_DIR",
+       "GITWEB_CONFIG": "$GITWEB_CONFIG"
+})
+
+
+class GitWebRequestHandler(CGIHTTPRequestHandler):
+
+       def log_message(self, format, *args):
+               # Write access logs to stdout
+               sys.stdout.write("%s - - [%s] %s\n" %
+                               (self.address_string(),
+                               self.log_date_time_string(),
+                               format%args))
+
+       def do_HEAD(self):
+               self.redirect_path()
+               CGIHTTPRequestHandler.do_HEAD(self)
+
+       def do_GET(self):
+               if self.path == "/":
+                       self.send_response(303, "See Other")
+                       self.send_header("Location", "/cgi-bin/gitweb.cgi")
+                       self.end_headers()
+                       return
+               self.redirect_path()
+               CGIHTTPRequestHandler.do_GET(self)
+
+       def do_POST(self):
+               self.redirect_path()
+               CGIHTTPRequestHandler.do_POST(self)
+
+       # rewrite path of every request that is not gitweb.cgi to out of cgi-bin
+       def redirect_path(self):
+               if not self.path.startswith("/cgi-bin/gitweb.cgi"):
+                       self.path = self.path.replace("/cgi-bin/", "/")
+
+       # gitweb.cgi is the only thing that is ever going to be run here.
+       # Ignore everything else
+       def is_cgi(self):
+               result = False
+               if self.path.startswith('/cgi-bin/gitweb.cgi'):
+                       result = CGIHTTPRequestHandler.is_cgi(self)
+               return result
+
+
+bind = "127.0.0.1"
+if "$local" == "true":
+       bind = "0.0.0.0"
+
+# Set our http root directory
+# This is a work around for a missing directory argument in older Python versions
+# as this was added to SimpleHTTPRequestHandler in Python 3.7
+os.chdir("$fqgitdir/gitweb/$httpd_only/")
+
+GitWebRequestHandler.protocol_version = "HTTP/1.0"
+httpd = ServerClass((bind, $port), GitWebRequestHandler)
+
+sa = httpd.socket.getsockname()
+print("Serving HTTP on", sa[0], "port", sa[1], "...")
+httpd.serve_forever()
+EOF
+
+       chmod a+x "$fqgitdir/gitweb/gitweb.py"
+}
+
 gitweb_conf() {
        cat > "$fqgitdir/gitweb/gitweb_config.perl" <<EOF
 #!@@PERL@@
@@ -623,6 +745,9 @@ configure_httpd() {
        *plackup*)
                plackup_conf
                ;;
+       *python*)
+               python_conf
+               ;;
        *)
                echo "Unknown httpd specified: $httpd"
                exit 1
index 3bb0682db5897f514d267946979fa2b9cfa43f20..8d6c9aca6584f76689246604abe047a85504671e 100755 (executable)
@@ -118,7 +118,7 @@ read_basic_state () {
        else
                orig_head=$(cat "$state_dir"/head)
        fi &&
-       GIT_QUIET=$(cat "$state_dir"/quiet) &&
+       test -f "$state_dir"/quiet && GIT_QUIET=t
        test -f "$state_dir"/verbose && verbose=t
        test -f "$state_dir"/strategy && strategy="$(cat "$state_dir"/strategy)"
        test -f "$state_dir"/strategy_opts &&
@@ -176,8 +176,8 @@ run_interactive () {
 
 run_specific_rebase () {
        if [ "$interactive_rebase" = implied ]; then
-               GIT_EDITOR=:
-               export GIT_EDITOR
+               GIT_SEQUENCE_EDITOR=:
+               export GIT_SEQUENCE_EDITOR
                autosquash=
        fi
 
@@ -226,6 +226,7 @@ then
        state_dir="$apply_dir"
 elif test -d "$merge_dir"
 then
+       type=interactive
        if test -d "$merge_dir"/rewritten
        then
                type=preserve-merges
@@ -233,10 +234,7 @@ then
                preserve_merges=t
        elif test -f "$merge_dir"/interactive
        then
-               type=interactive
                interactive_rebase=explicit
-       else
-               type=merge
        fi
        state_dir="$merge_dir"
 fi
@@ -496,6 +494,7 @@ then
        test -z "$interactive_rebase" && interactive_rebase=implied
 fi
 
+actually_interactive=
 if test -n "$interactive_rebase"
 then
        if test -z "$preserve_merges"
@@ -504,11 +503,12 @@ then
        else
                type=preserve-merges
        fi
-
+       actually_interactive=t
        state_dir="$merge_dir"
 elif test -n "$do_merge"
 then
-       type=merge
+       interactive_rebase=implied
+       type=interactive
        state_dir="$merge_dir"
 else
        type=am
@@ -520,28 +520,20 @@ then
        git_format_patch_opt="$git_format_patch_opt --progress"
 fi
 
-if test -n "$git_am_opt"; then
-       incompatible_opts=$(echo " $git_am_opt " | \
-                           sed -e 's/ -q / /g' -e 's/^ \(.*\) $/\1/')
-       if test -n "$interactive_rebase"
+incompatible_opts=$(echo " $git_am_opt " | \
+                   sed -e 's/ -q / /g' -e 's/^ \(.*\) $/\1/')
+if test -n "$incompatible_opts"
+then
+       if test -n "$actually_interactive" || test "$do_merge"
        then
-               if test -n "$incompatible_opts"
-               then
-                       die "$(gettext "error: cannot combine interactive options (--interactive, --exec, --rebase-merges, --preserve-merges, --keep-empty, --root + --onto) with am options ($incompatible_opts)")"
-               fi
-       fi
-       if test -n "$do_merge"; then
-               if test -n "$incompatible_opts"
-               then
-                       die "$(gettext "error: cannot combine merge options (--merge, --strategy, --strategy-option) with am options ($incompatible_opts)")"
-               fi
+               die "$(gettext "fatal: cannot combine am options with either interactive or merge options")"
        fi
 fi
 
 if test -n "$signoff"
 then
        test -n "$preserve_merges" &&
-               die "$(gettext "error: cannot combine '--signoff' with '--preserve-merges'")"
+               die "$(gettext "fatal: cannot combine '--signoff' with '--preserve-merges'")"
        git_am_opt="$git_am_opt $signoff"
        force_rebase=t
 fi
@@ -552,7 +544,7 @@ then
        # Note: incompatibility with --interactive is just a strong warning;
        #       git-rebase.txt caveats with "unless you know what you are doing"
        test -n "$rebase_merges" &&
-               die "$(gettext "error: cannot combine '--preserve-merges' with '--rebase-merges'")"
+               die "$(gettext "fatal: cannot combine '--preserve-merges' with '--rebase-merges'")"
 
        test -n "$reschedule_failed_exec" &&
                die "$(gettext "error: cannot combine '--preserve-merges' with '--reschedule-failed-exec'")"
@@ -561,9 +553,9 @@ fi
 if test -n "$rebase_merges"
 then
        test -n "$strategy_opts" &&
-               die "$(gettext "error: cannot combine '--rebase-merges' with '--strategy-option'")"
+               die "$(gettext "fatal: cannot combine '--rebase-merges' with '--strategy-option'")"
        test -n "$strategy" &&
-               die "$(gettext "error: cannot combine '--rebase-merges' with '--strategy'")"
+               die "$(gettext "fatal: cannot combine '--rebase-merges' with '--strategy'")"
 fi
 
 if test -z "$rebase_root"
@@ -702,7 +694,7 @@ require_clean_work_tree "rebase" "$(gettext "Please commit or stash them.")"
 # but this should be done only when upstream and onto are the same
 # and if this is not an interactive rebase.
 mb=$(git merge-base "$onto" "$orig_head")
-if test -z "$interactive_rebase" && test "$upstream" = "$onto" &&
+if test -z "$actually_interactive" && test "$upstream" = "$onto" &&
        test "$mb" = "$onto" && test -z "$restrict_revision" &&
        # linear history?
        ! (git rev-list --parents "$onto".."$orig_head" | sane_grep " .* ") > /dev/null
@@ -752,6 +744,19 @@ then
        GIT_PAGER='' git diff --stat --summary "$mb_tree" "$onto"
 fi
 
+if test -z "$actually_interactive" && test "$mb" = "$orig_head"
+then
+       say "$(eval_gettext "Fast-forwarded \$branch_name to \$onto_name.")"
+       GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" \
+               git checkout -q "$onto^0" || die "could not detach HEAD"
+       # If the $onto is a proper descendant of the tip of the branch, then
+       # we just fast-forwarded.
+       git update-ref ORIG_HEAD $orig_head
+       move_to_original_branch
+       finish_rebase
+       exit 0
+fi
+
 test -n "$interactive_rebase" && run_specific_rebase
 
 # Detach HEAD and reset the tree
@@ -761,16 +766,6 @@ GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" \
        git checkout -q "$onto^0" || die "could not detach HEAD"
 git update-ref ORIG_HEAD $orig_head
 
-# If the $onto is a proper descendant of the tip of the branch, then
-# we just fast-forwarded.
-if test "$mb" = "$orig_head"
-then
-       say "$(eval_gettext "Fast-forwarded \$branch_name to \$onto_name.")"
-       move_to_original_branch
-       finish_rebase
-       exit 0
-fi
-
 if test -n "$rebase_root"
 then
        revisions="$onto..$orig_head"
index 3e12774f96bb185bb6860290ad187c986ec7fa76..5b79920f46a972437ff05966d042a84d44f050d9 100755 (executable)
--- a/git-p4.py
+++ b/git-p4.py
@@ -1861,6 +1861,7 @@ def applyCommit(self, id):
                     filesToAdd.remove(path)
             elif modifier == "C":
                 src, dest = diff['src'], diff['dst']
+                all_files.append(dest)
                 p4_integrate(src, dest)
                 pureRenameCopy.add(dest)
                 if diff['src_sha1'] != diff['dst_sha1']:
@@ -1877,6 +1878,7 @@ def applyCommit(self, id):
                 editedFiles.add(dest)
             elif modifier == "R":
                 src, dest = diff['src'], diff['dst']
+                all_files.append(dest)
                 if self.p4HasMoveCommand:
                     p4_edit(src)        # src must be open before move
                     p4_move(src, dest)  # opens for (move/delete, move/add)
index 99b8c177875a7f26ae6c7f70be42c9d97231f7b9..6416716ee620cfac7803f9f00cef309a41b08f31 100644 (file)
@@ -36,7 +36,7 @@ rm -f "$GIT_DIR/rebased-patches"
 
 git format-patch -k --stdout --full-index --cherry-pick --right-only \
        --src-prefix=a/ --dst-prefix=b/ --no-renames --no-cover-letter \
-       --pretty=mboxrd \
+       --pretty=mboxrd --topo-order \
        $git_format_patch_opt \
        "$revisions" ${restrict_revision+^$restrict_revision} \
        >"$GIT_DIR/rebased-patches"
index a8a44608e03b23d93f4c95783d0ebbbb528ac096..f00e13e5d04df09558dba65afd4fe1ed44375fa9 100644 (file)
@@ -10,7 +10,7 @@ write_basic_state () {
        echo "$head_name" > "$state_dir"/head-name &&
        echo "$onto" > "$state_dir"/onto &&
        echo "$orig_head" > "$state_dir"/orig-head &&
-       echo "$GIT_QUIET" > "$state_dir"/quiet &&
+       test t = "$GIT_QUIET" && : > "$state_dir"/quiet
        test t = "$verbose" && : > "$state_dir"/verbose
        test -n "$strategy" && echo "$strategy" > "$state_dir"/strategy
        test -n "$strategy_opts" && echo "$strategy_opts" > \
diff --git a/git-rebase--merge.sh b/git-rebase--merge.sh
deleted file mode 100644 (file)
index aa2f2f0..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-# This shell script fragment is sourced by git-rebase to implement
-# its merge-based non-interactive mode that copes well with renamed
-# files.
-#
-# Copyright (c) 2010 Junio C Hamano.
-#
-
-prec=4
-
-read_state () {
-       onto_name=$(cat "$state_dir"/onto_name) &&
-       end=$(cat "$state_dir"/end) &&
-       msgnum=$(cat "$state_dir"/msgnum)
-}
-
-continue_merge () {
-       test -d "$state_dir" || die "$state_dir directory does not exist"
-
-       unmerged=$(git ls-files -u)
-       if test -n "$unmerged"
-       then
-               echo "You still have unmerged paths in your index"
-               echo "did you forget to use git add?"
-               die "$resolvemsg"
-       fi
-
-       cmt=$(cat "$state_dir/current")
-       if ! git diff-index --quiet --ignore-submodules HEAD --
-       then
-               if ! git commit ${gpg_sign_opt:+"$gpg_sign_opt"} $signoff $allow_empty_message \
-                       --no-verify -C "$cmt"
-               then
-                       echo "Commit failed, please do not call \"git commit\""
-                       echo "directly, but instead do one of the following: "
-                       die "$resolvemsg"
-               fi
-               if test -z "$GIT_QUIET"
-               then
-                       printf "Committed: %0${prec}d " $msgnum
-               fi
-               echo "$cmt $(git rev-parse HEAD^0)" >> "$state_dir/rewritten"
-       else
-               if test -z "$GIT_QUIET"
-               then
-                       printf "Already applied: %0${prec}d " $msgnum
-               fi
-       fi
-       test -z "$GIT_QUIET" &&
-       GIT_PAGER='' git log --format=%s -1 "$cmt"
-
-       # onto the next patch:
-       msgnum=$(($msgnum + 1))
-       echo "$msgnum" >"$state_dir/msgnum"
-}
-
-call_merge () {
-       msgnum="$1"
-       echo "$msgnum" >"$state_dir/msgnum"
-       cmt="$(cat "$state_dir/cmt.$msgnum")"
-       echo "$cmt" > "$state_dir/current"
-       git update-ref REBASE_HEAD "$cmt"
-       hd=$(git rev-parse --verify HEAD)
-       cmt_name=$(git symbolic-ref HEAD 2> /dev/null || echo HEAD)
-       eval GITHEAD_$cmt='"${cmt_name##refs/heads/}~$(($end - $msgnum))"'
-       eval GITHEAD_$hd='$onto_name'
-       export GITHEAD_$cmt GITHEAD_$hd
-       if test -n "$GIT_QUIET"
-       then
-               GIT_MERGE_VERBOSITY=1 && export GIT_MERGE_VERBOSITY
-       fi
-       test -z "$strategy" && strategy=recursive
-       # If cmt doesn't have a parent, don't include it as a base
-       base=$(git rev-parse --verify --quiet $cmt^)
-       eval 'git merge-$strategy' $strategy_opts $base ' -- "$hd" "$cmt"'
-       rv=$?
-       case "$rv" in
-       0)
-               unset GITHEAD_$cmt GITHEAD_$hd
-               return
-               ;;
-       1)
-               git rerere $allow_rerere_autoupdate
-               die "$resolvemsg"
-               ;;
-       2)
-               echo "Strategy: $strategy failed, try another" 1>&2
-               die "$resolvemsg"
-               ;;
-       *)
-               die "Unknown exit code ($rv) from command:" \
-                       "git merge-$strategy $cmt^ -- HEAD $cmt"
-               ;;
-       esac
-}
-
-finish_rb_merge () {
-       move_to_original_branch
-       if test -s "$state_dir"/rewritten
-       then
-               git notes copy --for-rewrite=rebase <"$state_dir"/rewritten
-               hook="$(git rev-parse --git-path hooks/post-rewrite)"
-               test -x "$hook" && "$hook" rebase <"$state_dir"/rewritten
-       fi
-       say All done.
-}
-
-git_rebase__merge () {
-
-case "$action" in
-continue)
-       read_state
-       continue_merge
-       while test "$msgnum" -le "$end"
-       do
-               call_merge "$msgnum"
-               continue_merge
-       done
-       finish_rb_merge
-       return
-       ;;
-skip)
-       read_state
-       git rerere clear
-       msgnum=$(($msgnum + 1))
-       while test "$msgnum" -le "$end"
-       do
-               call_merge "$msgnum"
-               continue_merge
-       done
-       finish_rb_merge
-       return
-       ;;
-show-current-patch)
-       exec git show REBASE_HEAD --
-       ;;
-esac
-
-mkdir -p "$state_dir"
-echo "$onto_name" > "$state_dir/onto_name"
-write_basic_state
-rm -f "$(git rev-parse --git-path REBASE_HEAD)"
-
-msgnum=0
-for cmt in $(git rev-list --reverse --no-merges "$revisions")
-do
-       msgnum=$(($msgnum + 1))
-       echo "$cmt" > "$state_dir/cmt.$msgnum"
-done
-
-echo 1 >"$state_dir/msgnum"
-echo $msgnum >"$state_dir/end"
-
-end=$msgnum
-msgnum=1
-
-while test "$msgnum" -le "$end"
-do
-       call_merge "$msgnum"
-       continue_merge
-done
-
-finish_rb_merge
-
-}
index 5e608f8bad305fea40e9063b854bf1be24ebd448..b5f2beee60ab59a04b5b236da8df39403009db1b 100755 (executable)
@@ -548,7 +548,7 @@ cmd_update()
        do
                die_if_unmatched "$quickabort" "$sha1"
 
-               git submodule--helper ensure-core-worktree "$sm_path"
+               git submodule--helper ensure-core-worktree "$sm_path" || exit 1
 
                update_module=$(git submodule--helper update-module-mode $just_cloned "$sm_path" $update)
 
@@ -850,8 +850,11 @@ cmd_summary() {
                        ;;
                esac
 
-               sha1_abbr_src=$(echo $sha1_src | cut -c1-7)
-               sha1_abbr_dst=$(echo $sha1_dst | cut -c1-7)
+               sha1_abbr_src=$(GIT_DIR="$name/.git" git rev-parse --short $sha1_src 2>/dev/null ||
+                       echo $sha1_src | cut -c1-7)
+               sha1_abbr_dst=$(GIT_DIR="$name/.git" git rev-parse --short $sha1_dst 2>/dev/null ||
+                       echo $sha1_dst | cut -c1-7)
+
                if test $status = T
                then
                        blob="$(gettext "blob")"
diff --git a/git.c b/git.c
index 0ce0e13f0f4879ae4608bd61d3a6a1f55ef7892e..2dd588674f621e2df2af1a3833c2cb3fa8417de4 100644 (file)
--- a/git.c
+++ b/git.c
@@ -418,9 +418,9 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
 
        trace_argv_printf(argv, "trace: built-in: git");
 
-       validate_cache_entries(&the_index);
+       validate_cache_entries(the_repository->index);
        status = p->fn(argc, argv, prefix);
-       validate_cache_entries(&the_index);
+       validate_cache_entries(the_repository->index);
 
        if (status)
                return status;
diff --git a/help.c b/help.c
index ff05fd22dff064f0f872434d20d4ea1eacded07d..520c9080e8e4abf7793af0966588aa370f09d316 100644 (file)
--- a/help.c
+++ b/help.c
@@ -85,7 +85,8 @@ static void print_command_list(const struct cmdname_help *cmds,
                if (cmds[i].category & mask) {
                        size_t len = strlen(cmds[i].name);
                        printf("   %s   ", cmds[i].name);
-                       mput_char(' ', longest > len ? longest - len : 1);
+                       if (longest > len)
+                               mput_char(' ', longest - len);
                        puts(_(cmds[i].help));
                }
        }
index bb802d80ee08945b0008d8f6862e29c783410b35..b22c7caea0c3facd8264a9ff5e779cec01003060 100644 (file)
@@ -255,7 +255,7 @@ static void start_fetch_loose(struct transfer_request *request)
        struct active_request_slot *slot;
        struct http_object_request *obj_req;
 
-       obj_req = new_http_object_request(repo->url, request->obj->oid.hash);
+       obj_req = new_http_object_request(repo->url, &request->obj->oid);
        if (obj_req == NULL) {
                request->state = ABORTED;
                return;
@@ -1933,7 +1933,7 @@ int cmd_main(int argc, const char **argv)
                pushing = 0;
                if (prepare_revision_walk(&revs))
                        die("revision walk setup failed");
-               mark_edges_uninteresting(&revs, NULL);
+               mark_edges_uninteresting(&revs, NULL, 0);
                objects_to_send = get_delta(&revs, ref_lock);
                finish_all_active_slots();
 
index 0a392c85b67af254ddeca382faa79458c4ec3ca8..8ae5d76c6aa216e92c26b875f72b7bb991b6e3cd 100644 (file)
@@ -58,7 +58,7 @@ static void start_object_request(struct walker *walker,
        struct active_request_slot *slot;
        struct http_object_request *req;
 
-       req = new_http_object_request(obj_req->repo->base, obj_req->oid.hash);
+       req = new_http_object_request(obj_req->repo->base, &obj_req->oid);
        if (req == NULL) {
                obj_req->state = ABORTED;
                return;
@@ -131,7 +131,7 @@ static int fill_active_slot(struct walker *walker)
        list_for_each_safe(pos, tmp, head) {
                obj_req = list_entry(pos, struct object_request, node);
                if (obj_req->state == WAITING) {
-                       if (has_sha1_file(obj_req->oid.hash))
+                       if (has_object_file(&obj_req->oid))
                                obj_req->state = COMPLETE;
                        else {
                                start_object_request(walker, obj_req);
@@ -489,7 +489,7 @@ static int fetch_object(struct walker *walker, unsigned char *sha1)
        if (obj_req == NULL)
                return error("Couldn't find request for %s in the queue", hex);
 
-       if (has_sha1_file(obj_req->oid.hash)) {
+       if (has_object_file(&obj_req->oid)) {
                if (obj_req->req != NULL)
                        abort_http_object_request(obj_req->req);
                abort_object_request(obj_req);
@@ -543,11 +543,11 @@ static int fetch_object(struct walker *walker, unsigned char *sha1)
        } else if (req->zret != Z_STREAM_END) {
                walker->corrupt_object_found++;
                ret = error("File %s (%s) corrupt", hex, req->url);
-       } else if (!hasheq(obj_req->oid.hash, req->real_sha1)) {
+       } else if (!oideq(&obj_req->oid, &req->real_oid)) {
                ret = error("File %s has bad hash", hex);
        } else if (req->rename < 0) {
                struct strbuf buf = STRBUF_INIT;
-               loose_object_path(the_repository, &buf, req->sha1);
+               loose_object_path(the_repository, &buf, &req->oid);
                ret = error("unable to write sha1 filename %s", buf.buf);
                strbuf_release(&buf);
        }
diff --git a/http.c b/http.c
index 954bebf6842510ea3fb83334ffe2684ade072f05..a32ad36ddf6b813ce0e02c85e7b61b4613517a9c 100644 (file)
--- a/http.c
+++ b/http.c
@@ -2343,9 +2343,9 @@ static size_t fwrite_sha1_file(char *ptr, size_t eltsize, size_t nmemb,
 }
 
 struct http_object_request *new_http_object_request(const char *base_url,
-       unsigned char *sha1)
+                                                   const struct object_id *oid)
 {
-       char *hex = sha1_to_hex(sha1);
+       char *hex = oid_to_hex(oid);
        struct strbuf filename = STRBUF_INIT;
        struct strbuf prevfile = STRBUF_INIT;
        int prevlocal;
@@ -2356,10 +2356,10 @@ struct http_object_request *new_http_object_request(const char *base_url,
 
        freq = xcalloc(1, sizeof(*freq));
        strbuf_init(&freq->tmpfile, 0);
-       hashcpy(freq->sha1, sha1);
+       oidcpy(&freq->oid, oid);
        freq->localfile = -1;
 
-       loose_object_path(the_repository, &filename, sha1);
+       loose_object_path(the_repository, &filename, oid);
        strbuf_addf(&freq->tmpfile, "%s.temp", filename.buf);
 
        strbuf_addf(&prevfile, "%s.prev", filename.buf);
@@ -2501,16 +2501,16 @@ int finish_http_object_request(struct http_object_request *freq)
        }
 
        git_inflate_end(&freq->stream);
-       git_SHA1_Final(freq->real_sha1, &freq->c);
+       git_SHA1_Final(freq->real_oid.hash, &freq->c);
        if (freq->zret != Z_STREAM_END) {
                unlink_or_warn(freq->tmpfile.buf);
                return -1;
        }
-       if (!hasheq(freq->sha1, freq->real_sha1)) {
+       if (!oideq(&freq->oid, &freq->real_oid)) {
                unlink_or_warn(freq->tmpfile.buf);
                return -1;
        }
-       loose_object_path(the_repository, &filename, freq->sha1);
+       loose_object_path(the_repository, &filename, &freq->oid);
        freq->rename = finalize_object_file(freq->tmpfile.buf, filename.buf);
        strbuf_release(&filename);
 
diff --git a/http.h b/http.h
index eebf40688cf6f695d12f9fe78e8e6b99bb44a8c4..4eb4e808e5731a3a9a650ca4c1efb3e471604d05 100644 (file)
--- a/http.h
+++ b/http.h
@@ -223,8 +223,8 @@ struct http_object_request {
        CURLcode curl_result;
        char errorstr[CURL_ERROR_SIZE];
        long http_code;
-       unsigned char sha1[20];
-       unsigned char real_sha1[20];
+       struct object_id oid;
+       struct object_id real_oid;
        git_SHA_CTX c;
        git_zstream stream;
        int zret;
@@ -233,7 +233,7 @@ struct http_object_request {
 };
 
 extern struct http_object_request *new_http_object_request(
-       const char *base_url, unsigned char *sha1);
+       const char *base_url, const struct object_id *oid);
 extern void process_http_object_request(struct http_object_request *freq);
 extern int finish_http_object_request(struct http_object_request *freq);
 extern void abort_http_object_request(struct http_object_request *freq);
index e8da2e8581b2df956411f19e796ceb94adcef903..b71bd1fb65bc6b9d6c6889b7dcf8d210d57f1e53 100644 (file)
@@ -18,8 +18,9 @@
  * See Documentation/rev-list-options.txt for allowed values for <arg>.
  *
  * Capture the given arg as the "filter_spec".  This can be forwarded to
- * subordinate commands when necessary.  We also "intern" the arg for
- * the convenience of the current command.
+ * subordinate commands when necessary (although it's better to pass it through
+ * expand_list_objects_filter_spec() first).  We also "intern" the arg for the
+ * convenience of the current command.
  */
 static int gently_parse_list_objects_filter(
        struct list_objects_filter_options *filter_options,
@@ -50,16 +51,15 @@ static int gently_parse_list_objects_filter(
                }
 
        } else if (skip_prefix(arg, "tree:", &v0)) {
-               unsigned long depth;
-               if (!git_parse_ulong(v0, &depth) || depth != 0) {
+               if (!git_parse_ulong(v0, &filter_options->tree_exclude_depth)) {
                        if (errbuf) {
                                strbuf_addstr(
                                        errbuf,
-                                       _("only 'tree:0' is supported"));
+                                       _("expected 'tree:<depth>'"));
                        }
                        return 1;
                }
-               filter_options->choice = LOFC_TREE_NONE;
+               filter_options->choice = LOFC_TREE_DEPTH;
                return 0;
 
        } else if (skip_prefix(arg, "sparse:oid=", &v0)) {
@@ -71,7 +71,7 @@ static int gently_parse_list_objects_filter(
                 * command, but DO NOT complain if we don't have the blob or
                 * ref locally.
                 */
-               if (!get_oid_with_context(v0, GET_OID_BLOB,
+               if (!get_oid_with_context(the_repository, v0, GET_OID_BLOB,
                                          &sparse_oid, &oc))
                        filter_options->sparse_oid_value = oiddup(&sparse_oid);
                filter_options->choice = LOFC_SPARSE_OID;
@@ -112,6 +112,21 @@ int opt_parse_list_objects_filter(const struct option *opt,
        return parse_list_objects_filter(filter_options, arg);
 }
 
+void expand_list_objects_filter_spec(
+       const struct list_objects_filter_options *filter,
+       struct strbuf *expanded_spec)
+{
+       strbuf_init(expanded_spec, strlen(filter->filter_spec));
+       if (filter->choice == LOFC_BLOB_LIMIT)
+               strbuf_addf(expanded_spec, "blob:limit=%lu",
+                           filter->blob_limit_value);
+       else if (filter->choice == LOFC_TREE_DEPTH)
+               strbuf_addf(expanded_spec, "tree:%lu",
+                           filter->tree_exclude_depth);
+       else
+               strbuf_addstr(expanded_spec, filter->filter_spec);
+}
+
 void list_objects_filter_release(
        struct list_objects_filter_options *filter_options)
 {
index af64e5c66fc4a242f9cc534380a9b3e8f1e67d00..e3adc78ebf74717d3b4e544c5bbb5215d9402a92 100644 (file)
@@ -2,6 +2,7 @@
 #define LIST_OBJECTS_FILTER_OPTIONS_H
 
 #include "parse-options.h"
+#include "strbuf.h"
 
 /*
  * The list of defined filters for list-objects.
@@ -10,7 +11,7 @@ enum list_objects_filter_choice {
        LOFC_DISABLED = 0,
        LOFC_BLOB_NONE,
        LOFC_BLOB_LIMIT,
-       LOFC_TREE_NONE,
+       LOFC_TREE_DEPTH,
        LOFC_SPARSE_OID,
        LOFC_SPARSE_PATH,
        LOFC__COUNT /* must be last */
@@ -20,8 +21,9 @@ struct list_objects_filter_options {
        /*
         * 'filter_spec' is the raw argument value given on the command line
         * or protocol request.  (The part after the "--keyword=".)  For
-        * commands that launch filtering sub-processes, this value should be
-        * passed to them as received by the current process.
+        * commands that launch filtering sub-processes, or for communication
+        * over the network, don't use this value; use the result of
+        * expand_list_objects_filter_spec() instead.
         */
        char *filter_spec;
 
@@ -44,6 +46,7 @@ struct list_objects_filter_options {
        struct object_id *sparse_oid_value;
        char *sparse_path_value;
        unsigned long blob_limit_value;
+       unsigned long tree_exclude_depth;
 };
 
 /* Normalized command line arguments */
@@ -61,6 +64,17 @@ int opt_parse_list_objects_filter(const struct option *opt,
          N_("object filtering"), 0, \
          opt_parse_list_objects_filter }
 
+/*
+ * Translates abbreviated numbers in the filter's filter_spec into their
+ * fully-expanded forms (e.g., "limit:blob=1k" becomes "limit:blob=1024").
+ *
+ * This form should be used instead of the raw filter_spec field when
+ * communicating with a remote process or subprocess.
+ */
+void expand_list_objects_filter_spec(
+       const struct list_objects_filter_options *filter,
+       struct strbuf *expanded_spec);
+
 void list_objects_filter_release(
        struct list_objects_filter_options *filter_options);
 
index a62624a1ced704156395b3e30312f264aa46b862..ee449de3f77e2b8663d1ae2d43da049f15269249 100644 (file)
@@ -10,6 +10,7 @@
 #include "list-objects.h"
 #include "list-objects-filter.h"
 #include "list-objects-filter-options.h"
+#include "oidmap.h"
 #include "oidset.h"
 #include "object-store.h"
 
@@ -84,11 +85,44 @@ static void *filter_blobs_none__init(
  * A filter for list-objects to omit ALL trees and blobs from the traversal.
  * Can OPTIONALLY collect a list of the omitted OIDs.
  */
-struct filter_trees_none_data {
+struct filter_trees_depth_data {
        struct oidset *omits;
+
+       /*
+        * Maps trees to the minimum depth at which they were seen. It is not
+        * necessary to re-traverse a tree at deeper or equal depths than it has
+        * already been traversed.
+        *
+        * We can't use LOFR_MARK_SEEN for tree objects since this will prevent
+        * it from being traversed at shallower depths.
+        */
+       struct oidmap seen_at_depth;
+
+       unsigned long exclude_depth;
+       unsigned long current_depth;
 };
 
-static enum list_objects_filter_result filter_trees_none(
+struct seen_map_entry {
+       struct oidmap_entry base;
+       size_t depth;
+};
+
+/* Returns 1 if the oid was in the omits set before it was invoked. */
+static int filter_trees_update_omits(
+       struct object *obj,
+       struct filter_trees_depth_data *filter_data,
+       int include_it)
+{
+       if (!filter_data->omits)
+               return 0;
+
+       if (include_it)
+               return oidset_remove(filter_data->omits, &obj->oid);
+       else
+               return oidset_insert(filter_data->omits, &obj->oid);
+}
+
+static enum list_objects_filter_result filter_trees_depth(
        struct repository *r,
        enum list_objects_filter_situation filter_situation,
        struct object *obj,
@@ -96,43 +130,91 @@ static enum list_objects_filter_result filter_trees_none(
        const char *filename,
        void *filter_data_)
 {
-       struct filter_trees_none_data *filter_data = filter_data_;
+       struct filter_trees_depth_data *filter_data = filter_data_;
+       struct seen_map_entry *seen_info;
+       int include_it = filter_data->current_depth <
+               filter_data->exclude_depth;
+       int filter_res;
+       int already_seen;
+
+       /*
+        * Note that we do not use _MARK_SEEN in order to allow re-traversal in
+        * case we encounter a tree or blob again at a shallower depth.
+        */
 
        switch (filter_situation) {
        default:
                BUG("unknown filter_situation: %d", filter_situation);
 
-       case LOFS_BEGIN_TREE:
+       case LOFS_END_TREE:
+               assert(obj->type == OBJ_TREE);
+               filter_data->current_depth--;
+               return LOFR_ZERO;
+
        case LOFS_BLOB:
-               if (filter_data->omits) {
-                       oidset_insert(filter_data->omits, &obj->oid);
-                       /* _MARK_SEEN but not _DO_SHOW (hard omit) */
-                       return LOFR_MARK_SEEN;
+               filter_trees_update_omits(obj, filter_data, include_it);
+               return include_it ? LOFR_MARK_SEEN | LOFR_DO_SHOW : LOFR_ZERO;
+
+       case LOFS_BEGIN_TREE:
+               seen_info = oidmap_get(
+                       &filter_data->seen_at_depth, &obj->oid);
+               if (!seen_info) {
+                       seen_info = xcalloc(1, sizeof(*seen_info));
+                       oidcpy(&seen_info->base.oid, &obj->oid);
+                       seen_info->depth = filter_data->current_depth;
+                       oidmap_put(&filter_data->seen_at_depth, seen_info);
+                       already_seen = 0;
                } else {
-                       /*
-                        * Not collecting omits so no need to to traverse tree.
-                        */
-                       return LOFR_SKIP_TREE | LOFR_MARK_SEEN;
+                       already_seen =
+                               filter_data->current_depth >= seen_info->depth;
                }
 
-       case LOFS_END_TREE:
-               assert(obj->type == OBJ_TREE);
-               return LOFR_ZERO;
+               if (already_seen) {
+                       filter_res = LOFR_SKIP_TREE;
+               } else {
+                       int been_omitted = filter_trees_update_omits(
+                               obj, filter_data, include_it);
+                       seen_info->depth = filter_data->current_depth;
+
+                       if (include_it)
+                               filter_res = LOFR_DO_SHOW;
+                       else if (filter_data->omits && !been_omitted)
+                               /*
+                                * Must update omit information of children
+                                * recursively; they have not been omitted yet.
+                                */
+                               filter_res = LOFR_ZERO;
+                       else
+                               filter_res = LOFR_SKIP_TREE;
+               }
 
+               filter_data->current_depth++;
+               return filter_res;
        }
 }
 
-static void* filter_trees_none__init(
+static void filter_trees_free(void *filter_data) {
+       struct filter_trees_depth_data *d = filter_data;
+       if (!d)
+               return;
+       oidmap_free(&d->seen_at_depth, 1);
+       free(d);
+}
+
+static void *filter_trees_depth__init(
        struct oidset *omitted,
        struct list_objects_filter_options *filter_options,
        filter_object_fn *filter_fn,
        filter_free_fn *filter_free_fn)
 {
-       struct filter_trees_none_data *d = xcalloc(1, sizeof(*d));
+       struct filter_trees_depth_data *d = xcalloc(1, sizeof(*d));
        d->omits = omitted;
+       oidmap_init(&d->seen_at_depth, 0);
+       d->exclude_depth = filter_options->tree_exclude_depth;
+       d->current_depth = 0;
 
-       *filter_fn = filter_trees_none;
-       *filter_free_fn = free;
+       *filter_fn = filter_trees_depth;
+       *filter_free_fn = filter_trees_free;
        return d;
 }
 
@@ -430,7 +512,7 @@ static filter_init_fn s_filters[] = {
        NULL,
        filter_blobs_none__init,
        filter_blobs_limit__init,
-       filter_trees_none__init,
+       filter_trees_depth__init,
        filter_sparse_oid__init,
        filter_sparse_path__init,
 };
index a2296a8e7b42a3d5d044c648d353ac94f9b4ed81..dc77361e11d02a4eaa994f4351310a0d54d33ef6 100644 (file)
@@ -226,25 +226,73 @@ static void mark_edge_parents_uninteresting(struct commit *commit,
        }
 }
 
-void mark_edges_uninteresting(struct rev_info *revs, show_edge_fn show_edge)
+static void add_edge_parents(struct commit *commit,
+                            struct rev_info *revs,
+                            show_edge_fn show_edge,
+                            struct oidset *set)
+{
+       struct commit_list *parents;
+
+       for (parents = commit->parents; parents; parents = parents->next) {
+               struct commit *parent = parents->item;
+               struct tree *tree = get_commit_tree(parent);
+
+               if (!tree)
+                       continue;
+
+               oidset_insert(set, &tree->object.oid);
+
+               if (!(parent->object.flags & UNINTERESTING))
+                       continue;
+               tree->object.flags |= UNINTERESTING;
+
+               if (revs->edge_hint && !(parent->object.flags & SHOWN)) {
+                       parent->object.flags |= SHOWN;
+                       show_edge(parent);
+               }
+       }
+}
+
+void mark_edges_uninteresting(struct rev_info *revs,
+                             show_edge_fn show_edge,
+                             int sparse)
 {
        struct commit_list *list;
        int i;
 
-       for (list = revs->commits; list; list = list->next) {
-               struct commit *commit = list->item;
+       if (sparse) {
+               struct oidset set;
+               oidset_init(&set, 16);
 
-               if (commit->object.flags & UNINTERESTING) {
-                       mark_tree_uninteresting(revs->repo,
-                                               get_commit_tree(commit));
-                       if (revs->edge_hint_aggressive && !(commit->object.flags & SHOWN)) {
-                               commit->object.flags |= SHOWN;
-                               show_edge(commit);
+               for (list = revs->commits; list; list = list->next) {
+                       struct commit *commit = list->item;
+                       struct tree *tree = get_commit_tree(commit);
+
+                       if (commit->object.flags & UNINTERESTING)
+                               tree->object.flags |= UNINTERESTING;
+
+                       oidset_insert(&set, &tree->object.oid);
+                       add_edge_parents(commit, revs, show_edge, &set);
+               }
+
+               mark_trees_uninteresting_sparse(revs->repo, &set);
+               oidset_clear(&set);
+       } else {
+               for (list = revs->commits; list; list = list->next) {
+                       struct commit *commit = list->item;
+                       if (commit->object.flags & UNINTERESTING) {
+                               mark_tree_uninteresting(revs->repo,
+                                                       get_commit_tree(commit));
+                               if (revs->edge_hint_aggressive && !(commit->object.flags & SHOWN)) {
+                                       commit->object.flags |= SHOWN;
+                                       show_edge(commit);
+                               }
+                               continue;
                        }
-                       continue;
+                       mark_edge_parents_uninteresting(commit, revs, show_edge);
                }
-               mark_edge_parents_uninteresting(commit, revs, show_edge);
        }
+
        if (revs->edge_hint_aggressive) {
                for (i = 0; i < revs->cmdline.nr; i++) {
                        struct object *obj = revs->cmdline.rev[i].item;
index ad407629269a7e7c77953390beccf036fd2452f6..a952680e46671db2543bc4abff78a2d898cd1408 100644 (file)
@@ -10,7 +10,9 @@ typedef void (*show_object_fn)(struct object *, const char *, void *);
 void traverse_commit_list(struct rev_info *, show_commit_fn, show_object_fn, void *);
 
 typedef void (*show_edge_fn)(struct commit *);
-void mark_edges_uninteresting(struct rev_info *, show_edge_fn);
+void mark_edges_uninteresting(struct rev_info *revs,
+                             show_edge_fn show_edge,
+                             int sparse);
 
 struct oidset;
 struct list_objects_filter_options;
index 9c9a7c647f26249d68319786449eefd7d6de1eba..0a7dbc6442fad37fd9e2ce72866b04b134818181 100644 (file)
--- a/ls-refs.c
+++ b/ls-refs.c
@@ -44,7 +44,7 @@ static int send_ref(const char *refname, const struct object_id *oid,
        if (ref_is_hidden(refname_nons, refname))
                return 0;
 
-       if (!ref_match(&data->prefixes, refname))
+       if (!ref_match(&data->prefixes, refname_nons))
                return 0;
 
        strbuf_addf(&refline, "%s %s", oid_to_hex(oid), refname_nons);
index 18ab825bef57f3ea63f70adf9a5c4e4a4f000bc4..ddc4d398456363cede9f3f5d4fa602efb402b5bd 100644 (file)
@@ -3,7 +3,7 @@
 #include "tree-walk.h"
 #include "object-store.h"
 
-static int score_missing(unsigned mode, const char *path)
+static int score_missing(unsigned mode)
 {
        int score;
 
@@ -16,7 +16,7 @@ static int score_missing(unsigned mode, const char *path)
        return score;
 }
 
-static int score_differs(unsigned mode1, unsigned mode2, const char *path)
+static int score_differs(unsigned mode1, unsigned mode2)
 {
        int score;
 
@@ -29,7 +29,7 @@ static int score_differs(unsigned mode1, unsigned mode2, const char *path)
        return score;
 }
 
-static int score_matches(unsigned mode1, unsigned mode2, const char *path)
+static int score_matches(unsigned mode1, unsigned mode2)
 {
        int score;
 
@@ -98,24 +98,22 @@ static int score_trees(const struct object_id *hash1, const struct object_id *ha
 
                if (cmp < 0) {
                        /* path1 does not appear in two */
-                       score += score_missing(one.entry.mode, one.entry.path);
+                       score += score_missing(one.entry.mode);
                        update_tree_entry(&one);
                } else if (cmp > 0) {
                        /* path2 does not appear in one */
-                       score += score_missing(two.entry.mode, two.entry.path);
+                       score += score_missing(two.entry.mode);
                        update_tree_entry(&two);
                } else {
                        /* path appears in both */
                        if (!oideq(&one.entry.oid, &two.entry.oid)) {
                                /* they are different */
                                score += score_differs(one.entry.mode,
-                                                      two.entry.mode,
-                                                      one.entry.path);
+                                                      two.entry.mode);
                        } else {
                                /* same subtree or blob */
                                score += score_matches(one.entry.mode,
-                                                      two.entry.mode,
-                                                      one.entry.path);
+                                                      two.entry.mode);
                        }
                        update_tree_entry(&one);
                        update_tree_entry(&two);
index 59ba4b4a1a083b07050c5e6eba8306cb63736a3e..4851825aebf29d129aa4b82d860adcbb2697a300 100644 (file)
@@ -146,7 +146,8 @@ static int err(struct merge_options *o, const char *err, ...)
        return -1;
 }
 
-static struct tree *shift_tree_object(struct tree *one, struct tree *two,
+static struct tree *shift_tree_object(struct repository *repo,
+                                     struct tree *one, struct tree *two,
                                      const char *subtree_shift)
 {
        struct object_id shifted;
@@ -159,12 +160,14 @@ static struct tree *shift_tree_object(struct tree *one, struct tree *two,
        }
        if (oideq(&two->object.oid, &shifted))
                return two;
-       return lookup_tree(the_repository, &shifted);
+       return lookup_tree(repo, &shifted);
 }
 
-static struct commit *make_virtual_commit(struct tree *tree, const char *comment)
+static struct commit *make_virtual_commit(struct repository *repo,
+                                         struct tree *tree,
+                                         const char *comment)
 {
-       struct commit *commit = alloc_commit_node(the_repository);
+       struct commit *commit = alloc_commit_node(repo);
 
        set_merge_remote_desc(commit, comment, (struct object *)commit);
        commit->maybe_tree = tree;
@@ -343,22 +346,24 @@ static int add_cacheinfo(struct merge_options *o,
                         unsigned int mode, const struct object_id *oid,
                         const char *path, int stage, int refresh, int options)
 {
+       struct index_state *istate = o->repo->index;
        struct cache_entry *ce;
        int ret;
 
-       ce = make_cache_entry(&the_index, mode, oid ? oid : &null_oid, path, stage, 0);
+       ce = make_cache_entry(istate, mode, oid ? oid : &null_oid, path, stage, 0);
        if (!ce)
                return err(o, _("add_cacheinfo failed for path '%s'; merge aborting."), path);
 
-       ret = add_cache_entry(ce, options);
+       ret = add_index_entry(istate, ce, options);
        if (refresh) {
                struct cache_entry *nce;
 
-               nce = refresh_cache_entry(&the_index, ce, CE_MATCH_REFRESH | CE_MATCH_IGNORE_MISSING);
+               nce = refresh_cache_entry(istate, ce,
+                                         CE_MATCH_REFRESH | CE_MATCH_IGNORE_MISSING);
                if (!nce)
                        return err(o, _("add_cacheinfo failed to refresh for path '%s'; merge aborting."), path);
                if (nce != ce)
-                       ret = add_cache_entry(nce, options);
+                       ret = add_index_entry(istate, nce, options);
        }
        return ret;
 }
@@ -386,7 +391,7 @@ static int unpack_trees_start(struct merge_options *o,
        o->unpack_opts.merge = 1;
        o->unpack_opts.head_idx = 2;
        o->unpack_opts.fn = threeway_merge;
-       o->unpack_opts.src_index = &the_index;
+       o->unpack_opts.src_index = o->repo->index;
        o->unpack_opts.dst_index = &tmp_index;
        o->unpack_opts.aggressive = !merge_detect_rename(o);
        setup_unpack_trees_porcelain(&o->unpack_opts, "merge");
@@ -396,16 +401,16 @@ static int unpack_trees_start(struct merge_options *o,
        init_tree_desc_from_tree(t+2, merge);
 
        rc = unpack_trees(3, t, &o->unpack_opts);
-       cache_tree_free(&active_cache_tree);
+       cache_tree_free(&o->repo->index->cache_tree);
 
        /*
-        * Update the_index to match the new results, AFTER saving a copy
+        * Update o->repo->index to match the new results, AFTER saving a copy
         * in o->orig_index.  Update src_index to point to the saved copy.
         * (verify_uptodate() checks src_index, and the original index is
         * the one that had the necessary modification timestamps.)
         */
-       o->orig_index = the_index;
-       the_index = tmp_index;
+       o->orig_index = *o->repo->index;
+       *o->repo->index = tmp_index;
        o->unpack_opts.src_index = &o->orig_index;
 
        return rc;
@@ -420,12 +425,13 @@ static void unpack_trees_finish(struct merge_options *o)
 struct tree *write_tree_from_memory(struct merge_options *o)
 {
        struct tree *result = NULL;
+       struct index_state *istate = o->repo->index;
 
-       if (unmerged_cache()) {
+       if (unmerged_index(istate)) {
                int i;
                fprintf(stderr, "BUG: There are unmerged index entries:\n");
-               for (i = 0; i < active_nr; i++) {
-                       const struct cache_entry *ce = active_cache[i];
+               for (i = 0; i < istate->cache_nr; i++) {
+                       const struct cache_entry *ce = istate->cache[i];
                        if (ce_stage(ce))
                                fprintf(stderr, "BUG: %d %.*s\n", ce_stage(ce),
                                        (int)ce_namelen(ce), ce->name);
@@ -433,16 +439,16 @@ struct tree *write_tree_from_memory(struct merge_options *o)
                BUG("unmerged index entries in merge-recursive.c");
        }
 
-       if (!active_cache_tree)
-               active_cache_tree = cache_tree();
+       if (!istate->cache_tree)
+               istate->cache_tree = cache_tree();
 
-       if (!cache_tree_fully_valid(active_cache_tree) &&
-           cache_tree_update(&the_index, 0) < 0) {
+       if (!cache_tree_fully_valid(istate->cache_tree) &&
+           cache_tree_update(istate, 0) < 0) {
                err(o, _("error building trees"));
                return NULL;
        }
 
-       result = lookup_tree(the_repository, &active_cache_tree->oid);
+       result = lookup_tree(o->repo, &istate->cache_tree->oid);
 
        return result;
 }
@@ -513,17 +519,17 @@ static struct stage_data *insert_stage_data(const char *path,
  * Create a dictionary mapping file names to stage_data objects. The
  * dictionary contains one entry for every path with a non-zero stage entry.
  */
-static struct string_list *get_unmerged(void)
+static struct string_list *get_unmerged(struct index_state *istate)
 {
        struct string_list *unmerged = xcalloc(1, sizeof(struct string_list));
        int i;
 
        unmerged->strdup_strings = 1;
 
-       for (i = 0; i < active_nr; i++) {
+       for (i = 0; i < istate->cache_nr; i++) {
                struct string_list_item *item;
                struct stage_data *e;
-               const struct cache_entry *ce = active_cache[i];
+               const struct cache_entry *ce = istate->cache[i];
                if (!ce_stage(ce))
                        continue;
 
@@ -683,7 +689,7 @@ static int update_stages(struct merge_options *opt, const char *path,
        int clear = 1;
        int options = ADD_CACHE_OK_TO_ADD | ADD_CACHE_SKIP_DFCHECK;
        if (clear)
-               if (remove_file_from_cache(path))
+               if (remove_file_from_index(opt->repo->index, path))
                        return -1;
        if (o)
                if (add_cacheinfo(opt, o->mode, &o->oid, path, 1, 0, options))
@@ -718,13 +724,14 @@ static int remove_file(struct merge_options *o, int clean,
        int update_working_directory = !o->call_depth && !no_wd;
 
        if (update_cache) {
-               if (remove_file_from_cache(path))
+               if (remove_file_from_index(o->repo->index, path))
                        return -1;
        }
        if (update_working_directory) {
                if (ignore_case) {
                        struct cache_entry *ce;
-                       ce = cache_file_exists(path, strlen(path), ignore_case);
+                       ce = index_file_exists(o->repo->index, path, strlen(path),
+                                              ignore_case);
                        if (ce && ce_stage(ce) == 0 && strcmp(path, ce->name))
                                return 0;
                }
@@ -774,7 +781,8 @@ static char *unique_path(struct merge_options *o, const char *path, const char *
  * check the working directory.  If empty_ok is non-zero, also return
  * 0 in the case where the working-tree dir exists but is empty.
  */
-static int dir_in_way(const char *path, int check_working_copy, int empty_ok)
+static int dir_in_way(struct index_state *istate, const char *path,
+                     int check_working_copy, int empty_ok)
 {
        int pos;
        struct strbuf dirpath = STRBUF_INIT;
@@ -783,12 +791,12 @@ static int dir_in_way(const char *path, int check_working_copy, int empty_ok)
        strbuf_addstr(&dirpath, path);
        strbuf_addch(&dirpath, '/');
 
-       pos = cache_name_pos(dirpath.buf, dirpath.len);
+       pos = index_name_pos(istate, dirpath.buf, dirpath.len);
 
        if (pos < 0)
                pos = -1 - pos;
-       if (pos < active_nr &&
-           !strncmp(dirpath.buf, active_cache[pos]->name, dirpath.len)) {
+       if (pos < istate->cache_nr &&
+           !strncmp(dirpath.buf, istate->cache[pos]->name, dirpath.len)) {
                strbuf_release(&dirpath);
                return 1;
        }
@@ -831,8 +839,10 @@ static int was_tracked(struct merge_options *o, const char *path)
        return 0;
 }
 
-static int would_lose_untracked(const char *path)
+static int would_lose_untracked(struct merge_options *o, const char *path)
 {
+       struct index_state *istate = o->repo->index;
+
        /*
         * This may look like it can be simplified to:
         *   return !was_tracked(o, path) && file_exists(path)
@@ -850,19 +860,19 @@ static int would_lose_untracked(const char *path)
         * update_file()/would_lose_untracked(); see every comment in this
         * file which mentions "update_stages".
         */
-       int pos = cache_name_pos(path, strlen(path));
+       int pos = index_name_pos(istate, path, strlen(path));
 
        if (pos < 0)
                pos = -1 - pos;
-       while (pos < active_nr &&
-              !strcmp(path, active_cache[pos]->name)) {
+       while (pos < istate->cache_nr &&
+              !strcmp(path, istate->cache[pos]->name)) {
                /*
                 * If stage #0, it is definitely tracked.
                 * If it has stage #2 then it was tracked
                 * before this merge started.  All other
                 * cases the path was not tracked.
                 */
-               switch (ce_stage(active_cache[pos])) {
+               switch (ce_stage(istate->cache[pos])) {
                case 0:
                case 2:
                        return 0;
@@ -922,7 +932,7 @@ static int make_room_for_path(struct merge_options *o, const char *path)
         * Do not unlink a file in the work tree if we are not
         * tracking it.
         */
-       if (would_lose_untracked(path))
+       if (would_lose_untracked(o, path))
                return err(o, _("refusing to lose untracked file at '%s'"),
                           path);
 
@@ -972,7 +982,7 @@ static int update_file_flags(struct merge_options *o,
                }
                if (S_ISREG(mode)) {
                        struct strbuf strbuf = STRBUF_INIT;
-                       if (convert_to_working_tree(&the_index, path, buf, size, &strbuf)) {
+                       if (convert_to_working_tree(o->repo->index, path, buf, size, &strbuf)) {
                                free(buf);
                                size = strbuf.len;
                                buf = strbuf_detach(&strbuf, NULL);
@@ -1092,7 +1102,7 @@ static int merge_3way(struct merge_options *o,
 
        merge_status = ll_merge(result_buf, a->path, &orig, base_name,
                                &src1, name1, &src2, name2,
-                               &the_index, &ll_opts);
+                               o->repo->index, &ll_opts);
 
        free(base_name);
        free(name1);
@@ -1103,7 +1113,8 @@ static int merge_3way(struct merge_options *o,
        return merge_status;
 }
 
-static int find_first_merges(struct object_array *result, const char *path,
+static int find_first_merges(struct repository *repo,
+                            struct object_array *result, const char *path,
                             struct commit *a, struct commit *b)
 {
        int i, j;
@@ -1123,7 +1134,7 @@ static int find_first_merges(struct object_array *result, const char *path,
        /* get all revisions that merge commit a */
        xsnprintf(merged_revision, sizeof(merged_revision), "^%s",
                  oid_to_hex(&a->object.oid));
-       repo_init_revisions(the_repository, &revs, NULL);
+       repo_init_revisions(repo, &revs, NULL);
        rev_opts.submodule = path;
        /* FIXME: can't handle linked worktrees in submodules yet */
        revs.single_worktree = path != NULL;
@@ -1201,9 +1212,9 @@ static int merge_submodule(struct merge_options *o,
                return 0;
        }
 
-       if (!(commit_base = lookup_commit_reference(the_repository, base)) ||
-           !(commit_a = lookup_commit_reference(the_repository, a)) ||
-           !(commit_b = lookup_commit_reference(the_repository, b))) {
+       if (!(commit_base = lookup_commit_reference(o->repo, base)) ||
+           !(commit_a = lookup_commit_reference(o->repo, a)) ||
+           !(commit_b = lookup_commit_reference(o->repo, b))) {
                output(o, 1, _("Failed to merge submodule %s (commits not present)"), path);
                return 0;
        }
@@ -1253,7 +1264,8 @@ static int merge_submodule(struct merge_options *o,
                return 0;
 
        /* find commit which merges them */
-       parent_count = find_first_merges(&merges, path, commit_a, commit_b);
+       parent_count = find_first_merges(o->repo, &merges, path,
+                                        commit_a, commit_b);
        switch (parent_count) {
        case 0:
                output(o, 1, _("Failed to merge submodule %s (merge following commits not found)"), path);
@@ -1401,7 +1413,7 @@ static int handle_rename_via_dir(struct merge_options *o,
         */
        const struct diff_filespec *dest = pair->two;
 
-       if (!o->call_depth && would_lose_untracked(dest->path)) {
+       if (!o->call_depth && would_lose_untracked(o, dest->path)) {
                char *alt_path = unique_path(o, dest->path, rename_branch);
 
                output(o, 1, _("Error: Refusing to lose untracked file at %s; "
@@ -1439,8 +1451,8 @@ static int handle_change_delete(struct merge_options *o,
        const char *update_path = path;
        int ret = 0;
 
-       if (dir_in_way(path, !o->call_depth, 0) ||
-           (!o->call_depth && would_lose_untracked(path))) {
+       if (dir_in_way(o->repo->index, path, !o->call_depth, 0) ||
+           (!o->call_depth && would_lose_untracked(o, path))) {
                update_path = alt_path = unique_path(o, path, change_branch);
        }
 
@@ -1450,7 +1462,7 @@ static int handle_change_delete(struct merge_options *o,
                 * correct; since there is no true "middle point" between
                 * them, simply reuse the base version for virtual merge base.
                 */
-               ret = remove_file_from_cache(path);
+               ret = remove_file_from_index(o->repo->index, path);
                if (!ret)
                        ret = update_file(o, 0, o_oid, o_mode, update_path);
        } else {
@@ -1526,7 +1538,7 @@ static int handle_rename_delete(struct merge_options *o,
                return -1;
 
        if (o->call_depth)
-               return remove_file_from_cache(dest->path);
+               return remove_file_from_index(o->repo->index, dest->path);
        else
                return update_stages(o, dest->path, NULL,
                                     rename_branch == o->branch1 ? dest : NULL,
@@ -1607,10 +1619,10 @@ static int handle_file_collision(struct merge_options *o,
        /* Remove rename sources if rename/add or rename/rename(2to1) */
        if (prev_path1)
                remove_file(o, 1, prev_path1,
-                           o->call_depth || would_lose_untracked(prev_path1));
+                           o->call_depth || would_lose_untracked(o, prev_path1));
        if (prev_path2)
                remove_file(o, 1, prev_path2,
-                           o->call_depth || would_lose_untracked(prev_path2));
+                           o->call_depth || would_lose_untracked(o, prev_path2));
 
        /*
         * Remove the collision path, if it wouldn't cause dirty contents
@@ -1621,7 +1633,7 @@ static int handle_file_collision(struct merge_options *o,
                output(o, 1, _("Refusing to lose dirty file at %s"),
                       collide_path);
                update_path = alt_path = unique_path(o, collide_path, "merged");
-       } else if (would_lose_untracked(collide_path)) {
+       } else if (would_lose_untracked(o, collide_path)) {
                /*
                 * Only way we get here is if both renames were from
                 * a directory rename AND user had an untracked file
@@ -1717,12 +1729,12 @@ static char *find_path_for_conflict(struct merge_options *o,
                                    const char *branch2)
 {
        char *new_path = NULL;
-       if (dir_in_way(path, !o->call_depth, 0)) {
+       if (dir_in_way(o->repo->index, path, !o->call_depth, 0)) {
                new_path = unique_path(o, path, branch1);
                output(o, 1, _("%s is a directory in %s adding "
                               "as %s instead"),
                       path, branch2, new_path);
-       } else if (would_lose_untracked(path)) {
+       } else if (would_lose_untracked(o, path)) {
                new_path = unique_path(o, path, branch1);
                output(o, 1, _("Refusing to lose untracked file"
                               " at %s; adding as %s instead"),
@@ -1783,14 +1795,14 @@ static int handle_rename_rename_1to2(struct merge_options *o,
                                return -1;
                }
                else
-                       remove_file_from_cache(a->path);
+                       remove_file_from_index(o->repo->index, a->path);
                add = filespec_from_entry(&other, ci->dst_entry2, 3 ^ 1);
                if (add) {
                        if (update_file(o, 0, &add->oid, add->mode, b->path))
                                return -1;
                }
                else
-                       remove_file_from_cache(b->path);
+                       remove_file_from_index(o->repo->index, b->path);
        } else {
                /*
                 * For each destination path, we need to see if there is a
@@ -1887,7 +1899,7 @@ static struct diff_queue_struct *get_diffpairs(struct merge_options *o,
        struct diff_queue_struct *ret;
        struct diff_options opts;
 
-       repo_diff_setup(the_repository, &opts);
+       repo_diff_setup(o->repo, &opts);
        opts.flags.recursive = 1;
        opts.flags.rename_empty = 0;
        opts.detect_rename = merge_detect_rename(o);
@@ -3042,8 +3054,8 @@ static int blob_unchanged(struct merge_options *opt,
         * performed.  Comparison can be skipped if both files are
         * unchanged since their sha1s have already been compared.
         */
-       if (renormalize_buffer(&the_index, path, o.buf, o.len, &o) |
-           renormalize_buffer(&the_index, path, a.buf, a.len, &a))
+       if (renormalize_buffer(opt->repo->index, path, o.buf, o.len, &o) |
+           renormalize_buffer(opt->repo->index, path, a.buf, a.len, &a))
                ret = (o.len == a.len && !memcmp(o.buf, a.buf, o.len));
 
 error_return:
@@ -3124,7 +3136,7 @@ static int handle_content_merge(struct merge_options *o,
                a.path = (char *)path1;
                b.path = (char *)path2;
 
-               if (dir_in_way(path, !o->call_depth,
+               if (dir_in_way(o->repo->index, path, !o->call_depth,
                               S_ISGITLINK(pair1->two->mode)))
                        df_conflict_remains = 1;
        }
@@ -3158,8 +3170,8 @@ static int handle_content_merge(struct merge_options *o,
                pos = index_name_pos(&o->orig_index, path, strlen(path));
                ce = o->orig_index.cache[pos];
                if (ce_skip_worktree(ce)) {
-                       pos = index_name_pos(&the_index, path, strlen(path));
-                       ce = the_index.cache[pos];
+                       pos = index_name_pos(o->repo->index, path, strlen(path));
+                       ce = o->repo->index->cache[pos];
                        ce->ce_flags |= CE_SKIP_WORKTREE;
                }
                return mfi.clean;
@@ -3178,7 +3190,7 @@ static int handle_content_merge(struct merge_options *o,
        if (df_conflict_remains || is_dirty) {
                char *new_path;
                if (o->call_depth) {
-                       remove_file_from_cache(path);
+                       remove_file_from_index(o->repo->index, path);
                } else {
                        if (!mfi.clean) {
                                if (update_stages(o, path, &one, &a, &b))
@@ -3338,7 +3350,7 @@ static int process_entry(struct merge_options *o,
                        oid = b_oid;
                        conf = _("directory/file");
                }
-               if (dir_in_way(path,
+               if (dir_in_way(o->repo->index, path,
                               !o->call_depth && !S_ISGITLINK(a_mode),
                               0)) {
                        char *new_path = unique_path(o, path, add_branch);
@@ -3349,7 +3361,7 @@ static int process_entry(struct merge_options *o,
                        if (update_file(o, 0, oid, mode, new_path))
                                clean_merge = -1;
                        else if (o->call_depth)
-                               remove_file_from_cache(path);
+                               remove_file_from_index(o->repo->index, path);
                        free(new_path);
                } else {
                        output(o, 2, _("Adding %s"), path);
@@ -3397,18 +3409,19 @@ int merge_trees(struct merge_options *o,
                struct tree *common,
                struct tree **result)
 {
+       struct index_state *istate = o->repo->index;
        int code, clean;
        struct strbuf sb = STRBUF_INIT;
 
-       if (!o->call_depth && index_has_changes(&the_index, head, &sb)) {
+       if (!o->call_depth && repo_index_has_changes(o->repo, head, &sb)) {
                err(o, _("Your local changes to the following files would be overwritten by merge:\n  %s"),
                    sb.buf);
                return -1;
        }
 
        if (o->subtree_shift) {
-               merge = shift_tree_object(head, merge, o->subtree_shift);
-               common = shift_tree_object(head, common, o->subtree_shift);
+               merge = shift_tree_object(o->repo, head, merge, o->subtree_shift);
+               common = shift_tree_object(o->repo, head, common, o->subtree_shift);
        }
 
        if (oid_eq(&common->object.oid, &merge->object.oid)) {
@@ -3428,7 +3441,7 @@ int merge_trees(struct merge_options *o,
                return -1;
        }
 
-       if (unmerged_cache()) {
+       if (unmerged_index(istate)) {
                struct string_list *entries;
                struct rename_info re_info;
                int i;
@@ -3443,7 +3456,7 @@ int merge_trees(struct merge_options *o,
                get_files_dirs(o, head);
                get_files_dirs(o, merge);
 
-               entries = get_unmerged();
+               entries = get_unmerged(o->repo->index);
                clean = detect_and_process_renames(o, common, head, merge,
                                                   entries, &re_info);
                record_df_conflict_files(o, entries);
@@ -3544,8 +3557,8 @@ int merge_recursive(struct merge_options *o,
                /* if there is no common ancestor, use an empty tree */
                struct tree *tree;
 
-               tree = lookup_tree(the_repository, the_repository->hash_algo->empty_tree);
-               merged_common_ancestors = make_virtual_commit(tree, "ancestor");
+               tree = lookup_tree(o->repo, o->repo->hash_algo->empty_tree);
+               merged_common_ancestors = make_virtual_commit(o->repo, tree, "ancestor");
        }
 
        for (iter = ca; iter; iter = iter->next) {
@@ -3559,7 +3572,7 @@ int merge_recursive(struct merge_options *o,
                 * overwritten it: the committed "conflicts" were
                 * already resolved.
                 */
-               discard_cache();
+               discard_index(o->repo->index);
                saved_b1 = o->branch1;
                saved_b2 = o->branch2;
                o->branch1 = "Temporary merge branch 1";
@@ -3575,9 +3588,9 @@ int merge_recursive(struct merge_options *o,
                        return err(o, _("merge returned no commit"));
        }
 
-       discard_cache();
+       discard_index(o->repo->index);
        if (!o->call_depth)
-               read_cache();
+               repo_read_index(o->repo);
 
        o->ancestor = "merged common ancestors";
        clean = merge_trees(o, get_commit_tree(h1), get_commit_tree(h2),
@@ -3589,7 +3602,7 @@ int merge_recursive(struct merge_options *o,
        }
 
        if (o->call_depth) {
-               *result = make_virtual_commit(mrtree, "merged tree");
+               *result = make_virtual_commit(o->repo, mrtree, "merged tree");
                commit_list_insert(h1, &(*result)->parents);
                commit_list_insert(h2, &(*result)->parents->next);
        }
@@ -3602,17 +3615,17 @@ int merge_recursive(struct merge_options *o,
        return clean;
 }
 
-static struct commit *get_ref(const struct object_id *oid, const char *name)
+static struct commit *get_ref(struct repository *repo, const struct object_id *oid,
+                             const char *name)
 {
        struct object *object;
 
-       object = deref_tag(the_repository, parse_object(the_repository, oid),
-                          name,
-                          strlen(name));
+       object = deref_tag(repo, parse_object(repo, oid),
+                          name, strlen(name));
        if (!object)
                return NULL;
        if (object->type == OBJ_TREE)
-               return make_virtual_commit((struct tree*)object, name);
+               return make_virtual_commit(repo, (struct tree*)object, name);
        if (object->type != OBJ_COMMIT)
                return NULL;
        if (parse_commit((struct commit *)object))
@@ -3629,22 +3642,22 @@ int merge_recursive_generic(struct merge_options *o,
 {
        int clean;
        struct lock_file lock = LOCK_INIT;
-       struct commit *head_commit = get_ref(head, o->branch1);
-       struct commit *next_commit = get_ref(merge, o->branch2);
+       struct commit *head_commit = get_ref(o->repo, head, o->branch1);
+       struct commit *next_commit = get_ref(o->repo, merge, o->branch2);
        struct commit_list *ca = NULL;
 
        if (base_list) {
                int i;
                for (i = 0; i < num_base_list; ++i) {
                        struct commit *base;
-                       if (!(base = get_ref(base_list[i], oid_to_hex(base_list[i]))))
+                       if (!(base = get_ref(o->repo, base_list[i], oid_to_hex(base_list[i]))))
                                return err(o, _("Could not parse object '%s'"),
                                           oid_to_hex(base_list[i]));
                        commit_list_insert(base, &ca);
                }
        }
 
-       hold_locked_index(&lock, LOCK_DIE_ON_ERROR);
+       repo_hold_locked_index(o->repo, &lock, LOCK_DIE_ON_ERROR);
        clean = merge_recursive(o, head_commit, next_commit, ca,
                                result);
        if (clean < 0) {
@@ -3652,7 +3665,7 @@ int merge_recursive_generic(struct merge_options *o,
                return clean;
        }
 
-       if (write_locked_index(&the_index, &lock,
+       if (write_locked_index(o->repo->index, &lock,
                               COMMIT_LOCK | SKIP_IF_UNCHANGED))
                return err(o, _("Unable to write index."));
 
@@ -3676,10 +3689,12 @@ static void merge_recursive_config(struct merge_options *o)
        git_config(git_xmerge_config, NULL);
 }
 
-void init_merge_options(struct merge_options *o)
+void init_merge_options(struct merge_options *o,
+                       struct repository *repo)
 {
        const char *merge_verbosity;
        memset(o, 0, sizeof(struct merge_options));
+       o->repo = repo;
        o->verbosity = 2;
        o->buffer_output = 1;
        o->diff_rename_limit = -1;
index e6a0828ecacd81d820feb8caa07c90707e97f8b4..c2b7bb65c62ff51af1b89087bbf6692060b5962e 100644 (file)
@@ -6,6 +6,8 @@
 
 struct commit;
 
+struct repository;
+
 struct merge_options {
        const char *ancestor;
        const char *branch1;
@@ -34,6 +36,7 @@ struct merge_options {
        struct string_list df_conflict_file_set;
        struct unpack_trees_options unpack_opts;
        struct index_state orig_index;
+       struct repository *repo;
 };
 
 /*
@@ -92,7 +95,8 @@ int merge_recursive_generic(struct merge_options *o,
                            const struct object_id **ca,
                            struct commit **result);
 
-void init_merge_options(struct merge_options *o);
+void init_merge_options(struct merge_options *o,
+                       struct repository *repo);
 struct tree *write_tree_from_memory(struct merge_options *o);
 
 int parse_merge_opt(struct merge_options *out, const char *s);
diff --git a/merge.c b/merge.c
index 91008f760223e4f6c65a5d344bb6403dd5885d28..7c1d756c3fad6f9570b31c2c36f96e9f90df39f4 100644 (file)
--- a/merge.c
+++ b/merge.c
@@ -37,7 +37,7 @@ int try_merge_command(struct repository *r,
        argv_array_clear(&args);
 
        discard_index(r->index);
-       if (read_index(r->index) < 0)
+       if (repo_read_index(r) < 0)
                die(_("failed to read the cache"));
        resolve_undo_clear_index(r->index);
 
@@ -58,7 +58,7 @@ int checkout_fast_forward(struct repository *r,
 
        refresh_index(r->index, REFRESH_QUIET, NULL, NULL, NULL);
 
-       if (hold_locked_index(&lock_file, LOCK_REPORT_ON_ERROR) < 0)
+       if (repo_hold_locked_index(r, &lock_file, LOCK_REPORT_ON_ERROR) < 0)
                return -1;
 
        memset(&trees, 0, sizeof(trees));
index 623ca6923a9ec78b9bb7d7cc899af72057d101d3..b4861bc7b02a93bd5f3659098764f535bb1f51c1 100644 (file)
@@ -5,7 +5,6 @@
  *
  * Copyright (C) 2008 Linus Torvalds
  */
-#define NO_THE_INDEX_COMPATIBILITY_MACROS
 #include "cache.h"
 #include "thread-utils.h"
 
index 72688d301b7dd41ed1aa8ab5d3e5e61a6f4054c5..280aa8e6c1b04136d4718b970adca19a1a9eb9cf 100644 (file)
@@ -649,7 +649,7 @@ int notes_merge(struct notes_merge_options *o,
                struct commit_list *parents = NULL;
                commit_list_insert(remote, &parents); /* LIFO order */
                commit_list_insert(local, &parents);
-               create_notes_commit(local_tree, parents, o->commit_msg.buf,
+               create_notes_commit(o->repo, local_tree, parents, o->commit_msg.buf,
                                    o->commit_msg.len, result_oid);
        }
 
@@ -724,7 +724,7 @@ int notes_merge_commit(struct notes_merge_options *o,
                strbuf_setlen(&path, baselen);
        }
 
-       create_notes_commit(partial_tree, partial_commit->parents, msg,
+       create_notes_commit(o->repo, partial_tree, partial_commit->parents, msg,
                            strlen(msg), result_oid);
        unuse_commit_buffer(partial_commit, buffer);
        if (o->verbosity >= 4)
index 14ea03178e9c44c8c8a05fb70ab038df5ad1b5f8..a8194106987388a590b10e246327f49fd550f448 100644 (file)
@@ -5,7 +5,9 @@
 #include "notes-utils.h"
 #include "repository.h"
 
-void create_notes_commit(struct notes_tree *t, struct commit_list *parents,
+void create_notes_commit(struct repository *r,
+                        struct notes_tree *t,
+                        struct commit_list *parents,
                         const char *msg, size_t msg_len,
                         struct object_id *result_oid)
 {
@@ -20,8 +22,7 @@ void create_notes_commit(struct notes_tree *t, struct commit_list *parents,
                /* Deduce parent commit from t->ref */
                struct object_id parent_oid;
                if (!read_ref(t->ref, &parent_oid)) {
-                       struct commit *parent = lookup_commit(the_repository,
-                                                             &parent_oid);
+                       struct commit *parent = lookup_commit(r, &parent_oid);
                        if (parse_commit(parent))
                                die("Failed to find/parse commit %s", t->ref);
                        commit_list_insert(parent, &parents);
@@ -34,7 +35,7 @@ void create_notes_commit(struct notes_tree *t, struct commit_list *parents,
                die("Failed to commit notes tree to database");
 }
 
-void commit_notes(struct notes_tree *t, const char *msg)
+void commit_notes(struct repository *r, struct notes_tree *t, const char *msg)
 {
        struct strbuf buf = STRBUF_INIT;
        struct object_id commit_oid;
@@ -50,7 +51,7 @@ void commit_notes(struct notes_tree *t, const char *msg)
        strbuf_addstr(&buf, msg);
        strbuf_complete_line(&buf);
 
-       create_notes_commit(t, NULL, buf.buf, buf.len, &commit_oid);
+       create_notes_commit(r, t, NULL, buf.buf, buf.len, &commit_oid);
        strbuf_insert(&buf, 0, "notes: ", 7); /* commit message starts at index 7 */
        update_ref(buf.buf, t->update_ref, &commit_oid, NULL, 0,
                   UPDATE_REFS_DIE_ON_ERR);
@@ -171,11 +172,13 @@ int copy_note_for_rewrite(struct notes_rewrite_cfg *c,
        return ret;
 }
 
-void finish_copy_notes_for_rewrite(struct notes_rewrite_cfg *c, const char *msg)
+void finish_copy_notes_for_rewrite(struct repository *r,
+                                  struct notes_rewrite_cfg *c,
+                                  const char *msg)
 {
        int i;
        for (i = 0; c->trees[i]; i++) {
-               commit_notes(c->trees[i], msg);
+               commit_notes(r, c->trees[i], msg);
                free_notes(c->trees[i]);
        }
        free(c->trees);
index 54083065283f681d8354af633b805a4896c8b036..d9b3c09eaf09819f9444cfcf68ca5443aa918b78 100644 (file)
@@ -5,6 +5,7 @@
 
 struct commit_list;
 struct object_id;
+struct repository;
 
 /*
  * Create new notes commit from the given notes tree
@@ -17,11 +18,13 @@ struct object_id;
  *
  * The resulting commit SHA1 is stored in result_sha1.
  */
-void create_notes_commit(struct notes_tree *t, struct commit_list *parents,
+void create_notes_commit(struct repository *r,
+                        struct notes_tree *t,
+                        struct commit_list *parents,
                         const char *msg, size_t msg_len,
                         struct object_id *result_oid);
 
-void commit_notes(struct notes_tree *t, const char *msg);
+void commit_notes(struct repository *r, struct notes_tree *t, const char *msg);
 
 enum notes_merge_strategy {
                NOTES_MERGE_RESOLVE_MANUAL = 0,
@@ -45,6 +48,8 @@ int parse_notes_merge_strategy(const char *v, enum notes_merge_strategy *s);
 struct notes_rewrite_cfg *init_copy_notes_for_rewrite(const char *cmd);
 int copy_note_for_rewrite(struct notes_rewrite_cfg *c,
                          const struct object_id *from_obj, const struct object_id *to_obj);
-void finish_copy_notes_for_rewrite(struct notes_rewrite_cfg *c, const char *msg);
+void finish_copy_notes_for_rewrite(struct repository *r,
+                                  struct notes_rewrite_cfg *c,
+                                  const char *msg);
 
 #endif
index e16aa38caebe69ae9bb3ace066f8103a60457407..14fc935bd1bf8b4fec70489825661dd7f6f2255c 100644 (file)
@@ -154,19 +154,28 @@ void raw_object_store_clear(struct raw_object_store *o);
 
 /*
  * Put in `buf` the name of the file in the local object database that
- * would be used to store a loose object with the specified sha1.
+ * would be used to store a loose object with the specified oid.
  */
-const char *loose_object_path(struct repository *r, struct strbuf *buf, const unsigned char *sha1);
+const char *loose_object_path(struct repository *r, struct strbuf *buf,
+                             const struct object_id *oid);
 
-void *map_sha1_file(struct repository *r, const unsigned char *sha1, unsigned long *size);
+void *map_loose_object(struct repository *r, const struct object_id *oid,
+                      unsigned long *size);
 
-extern void *read_object_file_extended(const struct object_id *oid,
+extern void *read_object_file_extended(struct repository *r,
+                                      const struct object_id *oid,
                                       enum object_type *type,
                                       unsigned long *size, int lookup_replace);
-static inline void *read_object_file(const struct object_id *oid, enum object_type *type, unsigned long *size)
+static inline void *repo_read_object_file(struct repository *r,
+                                         const struct object_id *oid,
+                                         enum object_type *type,
+                                         unsigned long *size)
 {
-       return read_object_file_extended(oid, type, size, 1);
+       return read_object_file_extended(r, oid, type, size, 1);
 }
+#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
+#define read_object_file(oid, type, size) repo_read_object_file(the_repository, oid, type, size)
+#endif
 
 /* Read and unpack an object file into memory, write memory to an object file */
 int oid_object_info(struct repository *r, const struct object_id *, unsigned long *);
@@ -199,20 +208,19 @@ int read_loose_object(const char *path,
                      unsigned long *size,
                      void **contents);
 
-/*
- * Convenience for sha1_object_info_extended() with a NULL struct
- * object_info. OBJECT_INFO_SKIP_CACHED is automatically set; pass
- * nonzero flags to also set other flags.
- */
-extern int has_sha1_file_with_flags(const unsigned char *sha1, int flags);
-static inline int has_sha1_file(const unsigned char *sha1)
-{
-       return has_sha1_file_with_flags(sha1, 0);
-}
+#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. */
-extern int has_object_file(const struct object_id *oid);
-extern int has_object_file_with_flags(const struct object_id *oid, int flags);
+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);
+#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
+#define has_object_file(oid) repo_has_object_file(the_repository, oid)
+#define has_object_file_with_flags(oid, flags) repo_has_object_file_with_flags(the_repository, oid, flags)
+#endif
 
 /*
  * Return true iff an alternate object database has a loose object
index a5c5cf830fc52d03adb4283cafd097218e1117a0..59ea24c4aab6e58ac64ef55598182da460acd6ad 100644 (file)
--- a/object.c
+++ b/object.c
@@ -164,8 +164,9 @@ void *object_as_type(struct repository *r, struct object *obj, enum object_type
                return obj;
        else if (obj->type == OBJ_NONE) {
                if (type == OBJ_COMMIT)
-                       ((struct commit *)obj)->index = alloc_commit_index(r);
-               obj->type = type;
+                       init_commit_node(r, (struct commit *) obj);
+               else
+                       obj->type = type;
                return obj;
        }
        else {
@@ -259,22 +260,22 @@ struct object *parse_object(struct repository *r, const struct object_id *oid)
        if (obj && obj->parsed)
                return obj;
 
-       if ((obj && obj->type == OBJ_BLOB && has_object_file(oid)) ||
-           (!obj && has_object_file(oid) &&
+       if ((obj && obj->type == OBJ_BLOB && repo_has_object_file(r, oid)) ||
+           (!obj && repo_has_object_file(r, oid) &&
             oid_object_info(r, oid, NULL) == OBJ_BLOB)) {
                if (check_object_signature(repl, NULL, 0, NULL) < 0) {
-                       error(_("sha1 mismatch %s"), oid_to_hex(oid));
+                       error(_("hash mismatch %s"), oid_to_hex(oid));
                        return NULL;
                }
                parse_blob_buffer(lookup_blob(r, oid), NULL, 0);
                return lookup_object(r, oid->hash);
        }
 
-       buffer = read_object_file(oid, &type, &size);
+       buffer = repo_read_object_file(r, oid, &type, &size);
        if (buffer) {
                if (check_object_signature(repl, buffer, size, type_name(type)) < 0) {
                        free(buffer);
-                       error(_("sha1 mismatch %s"), oid_to_hex(repl));
+                       error(_("hash mismatch %s"), oid_to_hex(repl));
                        return NULL;
                }
 
@@ -540,7 +541,7 @@ void parsed_object_pool_clear(struct parsed_object_pool *o)
                if (obj->type == OBJ_TREE)
                        free_tree_buffer((struct tree*)obj);
                else if (obj->type == OBJ_COMMIT)
-                       release_commit_memory((struct commit*)obj);
+                       release_commit_memory(o, (struct commit*)obj);
                else if (obj->type == OBJ_TAG)
                        release_tag_memory((struct tag*)obj);
        }
index 9c45842df389270baf73f4aa5b65df2004c9ba4d..e7cd337bee53cb02282a14c8aa88f2342edd2eb2 100644 (file)
@@ -150,9 +150,7 @@ void prepare_packing_data(struct repository *r, struct packing_data *pdata)
                                             1U << OE_SIZE_BITS);
        pdata->oe_delta_size_limit = git_env_ulong("GIT_TEST_OE_DELTA_SIZE",
                                                   1UL << OE_DELTA_SIZE_BITS);
-#ifndef NO_PTHREADS
-       pthread_mutex_init(&pdata->lock, NULL);
-#endif
+       init_recursive_mutex(&pdata->odb_lock);
 }
 
 struct object_entry *packlist_alloc(struct packing_data *pdata,
index 3cd8d1f00a95978a5a8c86805506b9927aefcd0e..6bfacc7d2cedd7f399d7807b7746b6ed66737eed 100644 (file)
@@ -148,7 +148,11 @@ struct packing_data {
        struct packed_git **in_pack_by_idx;
        struct packed_git **in_pack;
 
-       pthread_mutex_t lock;
+       /*
+        * During packing with multiple threads, protect the in-core
+        * object database from concurrent accesses.
+        */
+       pthread_mutex_t odb_lock;
 
        /*
         * This list contains entries for bases which we know the other side
@@ -168,13 +172,14 @@ struct packing_data {
 
 void prepare_packing_data(struct repository *r, struct packing_data *pdata);
 
+/* Protect access to object database */
 static inline void packing_data_lock(struct packing_data *pdata)
 {
-       pthread_mutex_lock(&pdata->lock);
+       pthread_mutex_lock(&pdata->odb_lock);
 }
 static inline void packing_data_unlock(struct packing_data *pdata)
 {
-       pthread_mutex_unlock(&pdata->lock);
+       pthread_mutex_unlock(&pdata->odb_lock);
 }
 
 struct object_entry *packlist_alloc(struct packing_data *pdata,
index ac6bb64bc39968801bc829389abcb077750a834f..16bcb75262d918fc7b88cc5141213e951be145cc 100644 (file)
@@ -1148,12 +1148,13 @@ void mark_bad_packed_object(struct packed_git *p, const unsigned char *sha1)
        p->num_bad_objects++;
 }
 
-const struct packed_git *has_packed_and_bad(const unsigned char *sha1)
+const struct packed_git *has_packed_and_bad(struct repository *r,
+                                           const unsigned char *sha1)
 {
        struct packed_git *p;
        unsigned i;
 
-       for (p = the_repository->objects->packed_git; p; p = p->next)
+       for (p = r->objects->packed_git; p; p = p->next)
                for (i = 0; i < p->num_bad_objects; i++)
                        if (hasheq(sha1,
                                   p->bad_object_sha1 + the_hash_algo->rawsz * i))
index 6c4037605d0dfee59a084c440506f1af11708d63..d70c6d9afb94c77c285fe8ee3237f7a40867157a 100644 (file)
@@ -146,7 +146,7 @@ extern int packed_object_info(struct repository *r,
                              off_t offset, struct object_info *);
 
 extern void mark_bad_packed_object(struct packed_git *p, const unsigned char *sha1);
-extern const struct packed_git *has_packed_and_bad(const unsigned char *sha1);
+extern const struct packed_git *has_packed_and_bad(struct repository *r, const unsigned char *sha1);
 
 /*
  * Iff a pack file in the given repository contains the object named by sha1,
diff --git a/path.h b/path.h
index b654ea8ff5f2e701239ec17b8d1fc81cebfc25dd..651e6157fc480264e3495bd508a88d0835de1379 100644 (file)
--- a/path.h
+++ b/path.h
@@ -165,7 +165,7 @@ extern void report_linked_checkout_garbage(void);
        const char *git_path_##var(struct repository *r) \
        { \
                if (!r->cached_paths.var) \
-                       r->cached_paths.var = git_pathdup(filename); \
+                       r->cached_paths.var = repo_git_path(r, filename); \
                return r->cached_paths.var; \
        }
 
index e85298f68cfeee14494466b0604e572a5c345810..12c2b322b30a59d2091d2c87df1bed88246d5950 100644 (file)
@@ -1,4 +1,3 @@
-#define NO_THE_INDEX_COMPATIBILITY_MACROS
 #include "cache.h"
 #include "config.h"
 #include "dir.h"
index 04d10bbd037b393574f8453cbd00f94e0b2e7e99..d4b71d3e82b0e54ef4105748fdfdc15b438badfb 100644 (file)
@@ -129,12 +129,14 @@ static void set_packet_header(char *buf, const int size)
        #undef hex
 }
 
-static void format_packet(struct strbuf *out, const char *fmt, va_list args)
+static void format_packet(struct strbuf *out, const char *prefix,
+                         const char *fmt, va_list args)
 {
        size_t orig_len, n;
 
        orig_len = out->len;
        strbuf_addstr(out, "0000");
+       strbuf_addstr(out, prefix);
        strbuf_vaddf(out, fmt, args);
        n = out->len - orig_len;
 
@@ -145,13 +147,13 @@ static void format_packet(struct strbuf *out, const char *fmt, va_list args)
        packet_trace(out->buf + orig_len + 4, n - 4, 1);
 }
 
-static int packet_write_fmt_1(int fd, int gently,
+static int packet_write_fmt_1(int fd, int gently, const char *prefix,
                              const char *fmt, va_list args)
 {
        static struct strbuf buf = STRBUF_INIT;
 
        strbuf_reset(&buf);
-       format_packet(&buf, fmt, args);
+       format_packet(&buf, prefix, fmt, args);
        if (write_in_full(fd, buf.buf, buf.len) < 0) {
                if (!gently) {
                        check_pipe(errno);
@@ -168,7 +170,7 @@ void packet_write_fmt(int fd, const char *fmt, ...)
        va_list args;
 
        va_start(args, fmt);
-       packet_write_fmt_1(fd, 0, fmt, args);
+       packet_write_fmt_1(fd, 0, "", fmt, args);
        va_end(args);
 }
 
@@ -178,7 +180,7 @@ int packet_write_fmt_gently(int fd, const char *fmt, ...)
        va_list args;
 
        va_start(args, fmt);
-       status = packet_write_fmt_1(fd, 1, fmt, args);
+       status = packet_write_fmt_1(fd, 1, "", fmt, args);
        va_end(args);
        return status;
 }
@@ -211,7 +213,7 @@ void packet_buf_write(struct strbuf *buf, const char *fmt, ...)
        va_list args;
 
        va_start(args, fmt);
-       format_packet(buf, fmt, args);
+       format_packet(buf, "", fmt, args);
        va_end(args);
 }
 
@@ -346,6 +348,10 @@ enum packet_read_status packet_read_with_status(int fd, char **src_buffer,
                return PACKET_READ_EOF;
        }
 
+       if ((options & PACKET_READ_DIE_ON_ERR_PACKET) &&
+           starts_with(buffer, "ERR "))
+               die(_("remote error: %s"), buffer + 4);
+
        if ((options & PACKET_READ_CHOMP_NEWLINE) &&
            len && buffer[len-1] == '\n')
                len--;
@@ -433,6 +439,29 @@ ssize_t read_packetized_to_strbuf(int fd_in, struct strbuf *sb_out)
        return sb_out->len - orig_len;
 }
 
+int recv_sideband(const char *me, int in_stream, int out)
+{
+       char buf[LARGE_PACKET_MAX + 1];
+       int len;
+       struct strbuf scratch = STRBUF_INIT;
+       enum sideband_type sideband_type;
+
+       while (1) {
+               len = packet_read(in_stream, NULL, NULL, buf, LARGE_PACKET_MAX,
+                                 0);
+               if (!demultiplex_sideband(me, buf, len, 0, &scratch,
+                                         &sideband_type))
+                       continue;
+               switch (sideband_type) {
+               case SIDEBAND_PRIMARY:
+                       write_or_die(out, buf + 1, len - 1);
+                       break;
+               default: /* errors: message already written */
+                       return sideband_type;
+               }
+       }
+}
+
 /* Packet Reader Functions */
 void packet_reader_init(struct packet_reader *reader, int fd,
                        char *src_buffer, size_t src_len,
@@ -446,25 +475,43 @@ void packet_reader_init(struct packet_reader *reader, int fd,
        reader->buffer = packet_buffer;
        reader->buffer_size = sizeof(packet_buffer);
        reader->options = options;
+       reader->me = "git";
 }
 
 enum packet_read_status packet_reader_read(struct packet_reader *reader)
 {
+       struct strbuf scratch = STRBUF_INIT;
+
        if (reader->line_peeked) {
                reader->line_peeked = 0;
                return reader->status;
        }
 
-       reader->status = packet_read_with_status(reader->fd,
-                                                &reader->src_buffer,
-                                                &reader->src_len,
-                                                reader->buffer,
-                                                reader->buffer_size,
-                                                &reader->pktlen,
-                                                reader->options);
+       /*
+        * Consume all progress packets until a primary payload packet is
+        * received
+        */
+       while (1) {
+               enum sideband_type sideband_type;
+               reader->status = packet_read_with_status(reader->fd,
+                                                        &reader->src_buffer,
+                                                        &reader->src_len,
+                                                        reader->buffer,
+                                                        reader->buffer_size,
+                                                        &reader->pktlen,
+                                                        reader->options);
+               if (!reader->use_sideband)
+                       break;
+               if (demultiplex_sideband(reader->me, reader->buffer,
+                                        reader->pktlen, 1, &scratch,
+                                        &sideband_type))
+                       break;
+       }
 
        if (reader->status == PACKET_READ_NORMAL)
-               reader->line = reader->buffer;
+               /* Skip the sideband designator if sideband is used */
+               reader->line = reader->use_sideband ?
+                       reader->buffer + 1 : reader->buffer;
        else
                reader->line = NULL;
 
@@ -482,3 +529,39 @@ enum packet_read_status packet_reader_peek(struct packet_reader *reader)
        reader->line_peeked = 1;
        return reader->status;
 }
+
+void packet_writer_init(struct packet_writer *writer, int dest_fd)
+{
+       writer->dest_fd = dest_fd;
+       writer->use_sideband = 0;
+}
+
+void packet_writer_write(struct packet_writer *writer, const char *fmt, ...)
+{
+       va_list args;
+
+       va_start(args, fmt);
+       packet_write_fmt_1(writer->dest_fd, 0,
+                          writer->use_sideband ? "\001" : "", fmt, args);
+       va_end(args);
+}
+
+void packet_writer_error(struct packet_writer *writer, const char *fmt, ...)
+{
+       va_list args;
+
+       va_start(args, fmt);
+       packet_write_fmt_1(writer->dest_fd, 0,
+                          writer->use_sideband ? "\003" : "ERR ", fmt, args);
+       va_end(args);
+}
+
+void packet_writer_delim(struct packet_writer *writer)
+{
+       packet_delim(writer->dest_fd);
+}
+
+void packet_writer_flush(struct packet_writer *writer)
+{
+       packet_flush(writer->dest_fd);
+}
index 5b28d43472db41a59f0a44845953f163748593b0..ad9a4a2cd7c332cb1c4d1f26268f1ef45f2d7639 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "git-compat-util.h"
 #include "strbuf.h"
+#include "sideband.h"
 
 /*
  * Write a packetized stream, where each line is preceded by
@@ -62,9 +63,13 @@ int write_packetized_from_buf(const char *src_in, size_t len, int fd_out);
  *
  * If options contains PACKET_READ_CHOMP_NEWLINE, a trailing newline (if
  * present) is removed from the buffer before returning.
+ *
+ * If options contains PACKET_READ_DIE_ON_ERR_PACKET, it dies when it sees an
+ * ERR packet.
  */
-#define PACKET_READ_GENTLE_ON_EOF (1u<<0)
-#define PACKET_READ_CHOMP_NEWLINE (1u<<1)
+#define PACKET_READ_GENTLE_ON_EOF     (1u<<0)
+#define PACKET_READ_CHOMP_NEWLINE     (1u<<1)
+#define PACKET_READ_DIE_ON_ERR_PACKET (1u<<2)
 int packet_read(int fd, char **src_buffer, size_t *src_len, char
                *buffer, unsigned size, int options);
 
@@ -116,6 +121,21 @@ char *packet_read_line_buf(char **src_buf, size_t *src_len, int *size);
  */
 ssize_t read_packetized_to_strbuf(int fd_in, struct strbuf *sb_out);
 
+/*
+ * Receive multiplexed output stream over git native protocol.
+ * in_stream is the input stream from the remote, which carries data
+ * in pkt_line format with band designator.  Demultiplex it into out
+ * and err and return error appropriately.  Band #1 carries the
+ * primary payload.  Things coming over band #2 is not necessarily
+ * error; they are usually informative message on the standard error
+ * stream, aka "verbose").  A message over band #3 is a signal that
+ * the remote died unexpectedly.  A flush() concludes the stream.
+ *
+ * Returns SIDEBAND_FLUSH upon a normal conclusion, and SIDEBAND_PROTOCOL_ERROR
+ * or SIDEBAND_REMOTE_ERROR if an error occurred.
+ */
+int recv_sideband(const char *me, int in_stream, int out);
+
 struct packet_reader {
        /* source file descriptor */
        int fd;
@@ -142,6 +162,9 @@ struct packet_reader {
 
        /* indicates if a line has been peeked */
        int line_peeked;
+
+       unsigned use_sideband : 1;
+       const char *me;
 };
 
 /*
@@ -179,4 +202,19 @@ extern enum packet_read_status packet_reader_peek(struct packet_reader *reader);
 #define LARGE_PACKET_DATA_MAX (LARGE_PACKET_MAX - 4)
 extern char packet_buffer[LARGE_PACKET_MAX];
 
+struct packet_writer {
+       int dest_fd;
+       unsigned use_sideband : 1;
+};
+
+void packet_writer_init(struct packet_writer *writer, int dest_fd);
+
+/* These functions die upon failure. */
+__attribute__((format (printf, 2, 3)))
+void packet_writer_write(struct packet_writer *writer, const char *fmt, ...);
+__attribute__((format (printf, 2, 3)))
+void packet_writer_error(struct packet_writer *writer, const char *fmt, ...);
+void packet_writer_delim(struct packet_writer *writer);
+void packet_writer_flush(struct packet_writer *writer);
+
 #endif
index c7dc3f2b9f62a762efd7f590d6e8959fc1707479..e73600ee7841a299e060369ca9eecf46d5a7fb0f 100644 (file)
@@ -8,6 +8,7 @@
 #include "config.h"
 #include "progress.h"
 #include "thread-utils.h"
+#include "repository.h"
 
 /*
  * Mostly randomly chosen maximum thread counts: we
@@ -146,12 +147,12 @@ void preload_index(struct index_state *index,
        trace_performance_leave("preload index");
 }
 
-int read_index_preload(struct index_state *index,
-                      const struct pathspec *pathspec,
-                      unsigned int refresh_flags)
+int repo_read_index_preload(struct repository *repo,
+                           const struct pathspec *pathspec,
+                           unsigned int refresh_flags)
 {
-       int retval = read_index(index);
+       int retval = repo_read_index(repo);
 
-       preload_index(index, pathspec, refresh_flags);
+       preload_index(repo->index, pathspec, refresh_flags);
        return retval;
 }
index 1b453fbb59a9414f947ad4f2253a54e6e9ad68f0..0ab45d10d702373e212fb36e4fa66feb26669ee7 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -595,14 +595,15 @@ static char *replace_encoding_header(char *buf, const char *encoding)
        return strbuf_detach(&tmp, NULL);
 }
 
-const char *logmsg_reencode(const struct commit *commit,
-                           char **commit_encoding,
-                           const char *output_encoding)
+const char *repo_logmsg_reencode(struct repository *r,
+                                const struct commit *commit,
+                                char **commit_encoding,
+                                const char *output_encoding)
 {
        static const char *utf8 = "UTF-8";
        const char *use_encoding;
        char *encoding;
-       const char *msg = get_commit_buffer(commit, NULL);
+       const char *msg = repo_get_commit_buffer(r, commit, NULL);
        char *out;
 
        if (!output_encoding || !*output_encoding) {
@@ -630,7 +631,7 @@ const char *logmsg_reencode(const struct commit *commit,
                 * the cached copy from get_commit_buffer, we need to duplicate it
                 * to avoid munging the cached copy.
                 */
-               if (msg == get_cached_commit_buffer(the_repository, commit, NULL))
+               if (msg == get_cached_commit_buffer(r, commit, NULL))
                        out = xstrdup(msg);
                else
                        out = (char *)msg;
@@ -644,7 +645,7 @@ const char *logmsg_reencode(const struct commit *commit,
                 */
                out = reencode_string(msg, output_encoding, use_encoding);
                if (out)
-                       unuse_commit_buffer(commit, msg);
+                       repo_unuse_commit_buffer(r, commit, msg);
        }
 
        /*
@@ -1527,9 +1528,10 @@ void userformat_find_requirements(const char *fmt, struct userformat_want *w)
        strbuf_release(&dummy);
 }
 
-void format_commit_message(const struct commit *commit,
-                          const char *format, struct strbuf *sb,
-                          const struct pretty_print_context *pretty_ctx)
+void repo_format_commit_message(struct repository *r,
+                               const struct commit *commit,
+                               const char *format, struct strbuf *sb,
+                               const struct pretty_print_context *pretty_ctx)
 {
        struct format_commit_context context;
        const char *output_enc = pretty_ctx->output_encoding;
@@ -1543,9 +1545,9 @@ void format_commit_message(const struct commit *commit,
         * convert a commit message to UTF-8 first
         * as far as 'format_commit_item' assumes it in UTF-8
         */
-       context.message = logmsg_reencode(commit,
-                                         &context.commit_encoding,
-                                         utf8);
+       context.message = repo_logmsg_reencode(r, commit,
+                                              &context.commit_encoding,
+                                              utf8);
 
        strbuf_expand(sb, format, format_commit_item, &context);
        rewrap_message_tail(sb, &context, 0, 0, 0);
@@ -1569,7 +1571,7 @@ void format_commit_message(const struct commit *commit,
        }
 
        free(context.commit_encoding);
-       unuse_commit_buffer(commit, context.message);
+       repo_unuse_commit_buffer(r, commit, context.message);
 }
 
 static void pp_header(struct pretty_print_context *pp,
index 87ca5dfcbad73fca39e5a8f346bb2cc36996eb80..4ad1fc31ff33408881abf2ea5e28ab813d6c1f85 100644 (file)
--- a/pretty.h
+++ b/pretty.h
@@ -104,9 +104,14 @@ void pp_remainder(struct pretty_print_context *pp, const char **msg_p,
  * Put the result to "sb".
  * Please use this function for custom formats.
  */
-void format_commit_message(const struct commit *commit,
+void repo_format_commit_message(struct repository *r,
+                       const struct commit *commit,
                        const char *format, struct strbuf *sb,
                        const struct pretty_print_context *context);
+#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
+#define format_commit_message(c, f, s, con) \
+       repo_format_commit_message(the_repository, c, f, s, con)
+#endif
 
 /*
  * Parse given arguments from "arg", check it for correctness and
index bfff271a3db92cfaaa93d23c5bf52297dda0419e..a66c87bc7a8346d1df529cae5154c8f35ba9d1ca 100644 (file)
@@ -3,7 +3,6 @@
  *
  * Copyright (C) Linus Torvalds, 2005
  */
-#define NO_THE_INDEX_COMPATIBILITY_MACROS
 #include "cache.h"
 #include "config.h"
 #include "diff.h"
@@ -95,7 +94,6 @@ static struct mem_pool *find_mem_pool(struct index_state *istate)
        return *pool_ptr;
 }
 
-struct index_state the_index;
 static const char *alternate_index_output;
 
 static void set_index_entry(struct index_state *istate, int nr, struct cache_entry *ce)
@@ -703,10 +701,10 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
        int intent_only = flags & ADD_CACHE_INTENT;
        int add_option = (ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE|
                          (intent_only ? ADD_CACHE_NEW_ONLY : 0));
-       int newflags = HASH_WRITE_OBJECT;
+       int hash_flags = HASH_WRITE_OBJECT;
 
-       if (flags & HASH_RENORMALIZE)
-               newflags |= HASH_RENORMALIZE;
+       if (flags & ADD_CACHE_RENORMALIZE)
+               hash_flags |= HASH_RENORMALIZE;
 
        if (!S_ISREG(st_mode) && !S_ISLNK(st_mode) && !S_ISDIR(st_mode))
                return error(_("%s: can only add regular files, symbolic links or git-directories"), path);
@@ -762,7 +760,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
                }
        }
        if (!intent_only) {
-               if (index_path(istate, &ce->oid, path, st, newflags)) {
+               if (index_path(istate, &ce->oid, path, st, hash_flags)) {
                        discard_cache_entry(ce);
                        return error(_("unable to index file '%s'"), path);
                }
@@ -1733,16 +1731,6 @@ static int read_index_extension(struct index_state *istate,
        return 0;
 }
 
-int hold_locked_index(struct lock_file *lk, int lock_flags)
-{
-       return hold_lock_file_for_update(lk, get_index_file(), lock_flags);
-}
-
-int read_index(struct index_state *istate)
-{
-       return read_index_from(istate, get_index_file(), get_git_dir());
-}
-
 static struct cache_entry *create_from_disk(struct mem_pool *ce_mem_pool,
                                            unsigned int version,
                                            struct ondisk_cache_entry *ondisk,
@@ -2375,22 +2363,20 @@ int unmerged_index(const struct index_state *istate)
        return 0;
 }
 
-int index_has_changes(struct index_state *istate,
-                     struct tree *tree,
-                     struct strbuf *sb)
+int repo_index_has_changes(struct repository *repo,
+                          struct tree *tree,
+                          struct strbuf *sb)
 {
+       struct index_state *istate = repo->index;
        struct object_id cmp;
        int i;
 
-       if (istate != &the_index) {
-               BUG("index_has_changes cannot yet accept istate != &the_index; do_diff_cache needs updating first.");
-       }
        if (tree)
                cmp = tree->object.oid;
        if (tree || !get_oid_tree("HEAD", &cmp)) {
                struct diff_options opt;
 
-               repo_diff_setup(the_repository, &opt);
+               repo_diff_setup(repo, &opt);
                opt.flags.exit_with_status = 1;
                if (!sb)
                        opt.flags.quick = 1;
@@ -2664,9 +2650,9 @@ static int verify_index_from(const struct index_state *istate, const char *path)
        return 0;
 }
 
-static int verify_index(const struct index_state *istate)
+static int repo_verify_index(struct repository *repo)
 {
-       return verify_index_from(istate, get_index_file());
+       return verify_index_from(repo->index, repo->index_file);
 }
 
 static int has_racy_timestamp(struct index_state *istate)
@@ -2682,11 +2668,13 @@ static int has_racy_timestamp(struct index_state *istate)
        return 0;
 }
 
-void update_index_if_able(struct index_state *istate, struct lock_file *lockfile)
+void repo_update_index_if_able(struct repository *repo,
+                              struct lock_file *lockfile)
 {
-       if ((istate->cache_changed || has_racy_timestamp(istate)) &&
-           verify_index(istate))
-               write_locked_index(istate, lockfile, COMMIT_LOCK);
+       if ((repo->index->cache_changed ||
+            has_racy_timestamp(repo->index)) &&
+           repo_verify_index(repo))
+               write_locked_index(repo->index, lockfile, COMMIT_LOCK);
        else
                rollback_lock_file(lockfile);
 }
@@ -3223,12 +3211,14 @@ int write_locked_index(struct index_state *istate, struct lock_file *lock,
  * state can call this and check its return value, instead of calling
  * read_cache().
  */
-int read_index_unmerged(struct index_state *istate)
+int repo_read_index_unmerged(struct repository *repo)
 {
+       struct index_state *istate;
        int i;
        int unmerged = 0;
 
-       read_index(istate);
+       repo_read_index(repo);
+       istate = repo->index;
        for (i = 0; i < istate->cache_nr; i++) {
                struct cache_entry *ce = istate->cache[i];
                struct cache_entry *new_ce;
diff --git a/refs.c b/refs.c
index f9936355cda6a1515f3192151f7fc14d0c2d7522..142888a40a611370240864e2f27f097832db11e9 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -188,7 +188,7 @@ int ref_resolves_to_object(const char *refname,
 {
        if (flags & REF_ISBROKEN)
                return 0;
-       if (!has_sha1_file(oid->hash)) {
+       if (!has_object_file(oid)) {
                error(_("%s does not point to a valid object!"), refname);
                return 0;
        }
index 6ff9c66b90bab5d5e8d45b5baeff99143196b7cd..2e04d53ac8e79c9f5a3839a7ab97fd67f2588021 100644 (file)
@@ -204,7 +204,8 @@ static struct ref *parse_git_refs(struct discovery *heads, int for_push)
 
        packet_reader_init(&reader, -1, heads->buf, heads->len,
                           PACKET_READ_CHOMP_NEWLINE |
-                          PACKET_READ_GENTLE_ON_EOF);
+                          PACKET_READ_GENTLE_ON_EOF |
+                          PACKET_READ_DIE_ON_ERR_PACKET);
 
        heads->version = discover_version(&reader);
        switch (heads->version) {
@@ -408,28 +409,37 @@ static struct discovery *discover_refs(const char *service, int for_push)
        if (maybe_smart &&
            (5 <= last->len && last->buf[4] == '#') &&
            !strbuf_cmp(&exp, &type)) {
-               char *line;
+               struct packet_reader reader;
+               packet_reader_init(&reader, -1, last->buf, last->len,
+                                  PACKET_READ_CHOMP_NEWLINE |
+                                  PACKET_READ_DIE_ON_ERR_PACKET);
 
                /*
                 * smart HTTP response; validate that the service
                 * pkt-line matches our request.
                 */
-               line = packet_read_line_buf(&last->buf, &last->len, NULL);
-               if (!line)
+               if (packet_reader_read(&reader) != PACKET_READ_NORMAL)
                        die("invalid server response; expected service, got flush packet");
 
                strbuf_reset(&exp);
                strbuf_addf(&exp, "# service=%s", service);
-               if (strcmp(line, exp.buf))
-                       die("invalid server response; got '%s'", line);
+               if (strcmp(reader.line, exp.buf))
+                       die("invalid server response; got '%s'", reader.line);
                strbuf_release(&exp);
 
                /* The header can include additional metadata lines, up
                 * until a packet flush marker.  Ignore these now, but
                 * in the future we might start to scan them.
                 */
-               while (packet_read_line_buf(&last->buf, &last->len, NULL))
-                       ;
+               for (;;) {
+                       packet_reader_read(&reader);
+                       if (reader.pktlen <= 0) {
+                               break;
+                       }
+               }
+
+               last->buf = reader.src_buffer;
+               last->len = reader.src_len;
 
                last->proto_git = 1;
        } else if (maybe_smart &&
@@ -1194,7 +1204,8 @@ static void proxy_state_init(struct proxy_state *p, const char *service_name,
                p->headers = curl_slist_append(p->headers, buf.buf);
 
        packet_reader_init(&p->reader, p->in, NULL, 0,
-                          PACKET_READ_GENTLE_ON_EOF);
+                          PACKET_READ_GENTLE_ON_EOF |
+                          PACKET_READ_DIE_ON_ERR_PACKET);
 
        strbuf_release(&buf);
 }
index 20c509a9226645b1890c8433b22a7182699fc847..65e6f8b8fdfcf89e5c86cbee9590aa555f7b0b47 100644 (file)
@@ -1,13 +1,20 @@
+/*
+ * not really _using_ the compat macros, just make sure the_index
+ * declaration matches the definition in this file.
+ */
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "cache.h"
 #include "repository.h"
 #include "object-store.h"
 #include "config.h"
 #include "object.h"
+#include "lockfile.h"
 #include "submodule-config.h"
 
 /* The main repository */
 static struct repository the_repo;
 struct repository *the_repository;
+struct index_state the_index;
 
 void initialize_the_repository(void)
 {
@@ -256,3 +263,12 @@ int repo_read_index(struct repository *repo)
 
        return read_index_from(repo->index, repo->index_file, repo->gitdir);
 }
+
+int repo_hold_locked_index(struct repository *repo,
+                          struct lock_file *lf,
+                          int flags)
+{
+       if (!repo->index_file)
+               BUG("the repo hasn't been setup");
+       return hold_lock_file_for_update(lf, repo->index_file, flags);
+}
index 0e482b7d49e82c3cf46d81523e057e3a02d2e8f4..8981649d43736ee283fcd23cd3185288252d5357 100644 (file)
@@ -6,6 +6,8 @@
 struct config_set;
 struct git_hash_algo;
 struct index_state;
+struct lock_file;
+struct pathspec;
 struct raw_object_store;
 struct submodule_cache;
 
@@ -138,5 +140,19 @@ void repo_clear(struct repository *repo);
  * populated then the number of entries will simply be returned.
  */
 int repo_read_index(struct repository *repo);
+int repo_hold_locked_index(struct repository *repo,
+                          struct lock_file *lf,
+                          int flags);
+
+int repo_read_index_preload(struct repository *,
+                           const struct pathspec *pathspec,
+                           unsigned refresh_flags);
+int repo_read_index_unmerged(struct repository *);
+/*
+ * Opportunistically update the index but do not complain if we can't.
+ * The lockfile is always committed or rolled back.
+ */
+void repo_update_index_if_able(struct repository *, struct lock_file *);
+
 
 #endif /* REPOSITORY_H */
index 13624038e66c2084c478711599ed9f005cf2e53d..17abb47321f14ada67f8ffc6cbfb2ce0d527fa82 100644 (file)
--- a/rerere.c
+++ b/rerere.c
@@ -561,7 +561,7 @@ static int find_conflict(struct repository *r, struct string_list *conflict)
 {
        int i;
 
-       if (read_index(r->index) < 0)
+       if (repo_read_index(r) < 0)
                return error(_("index file corrupt"));
 
        for (i = 0; i < r->index->cache_nr;) {
@@ -595,7 +595,7 @@ int rerere_remaining(struct repository *r, struct string_list *merge_rr)
 
        if (setup_rerere(r, merge_rr, RERERE_READONLY))
                return 0;
-       if (read_index(r->index) < 0)
+       if (repo_read_index(r) < 0)
                return error(_("index file corrupt"));
 
        for (i = 0; i < r->index->cache_nr;) {
@@ -705,7 +705,7 @@ static void update_paths(struct repository *r, struct string_list *update)
        struct lock_file index_lock = LOCK_INIT;
        int i;
 
-       hold_locked_index(&index_lock, LOCK_DIE_ON_ERROR);
+       repo_hold_locked_index(r, &index_lock, LOCK_DIE_ON_ERROR);
 
        for (i = 0; i < update->nr; i++) {
                struct string_list_item *item = &update->items[i];
@@ -1107,7 +1107,7 @@ int rerere_forget(struct repository *r, struct pathspec *pathspec)
        struct string_list conflict = STRING_LIST_INIT_DUP;
        struct string_list merge_rr = STRING_LIST_INIT_DUP;
 
-       if (read_index(r->index) < 0)
+       if (repo_read_index(r) < 0)
                return error(_("index file corrupt"));
 
        fd = setup_rerere(r, &merge_rr, RERERE_NOAUTOUPDATE);
index 119947ced0ba74cd20a007daf43f61386a393a6a..162d511d4686bc43f2032a57fa95e3601eb3d6b2 100644 (file)
@@ -27,6 +27,7 @@
 #include "commit-reach.h"
 #include "commit-graph.h"
 #include "prio-queue.h"
+#include "hashmap.h"
 
 volatile show_early_output_fn_t show_early_output;
 
@@ -99,6 +100,148 @@ void mark_tree_uninteresting(struct repository *r, struct tree *tree)
        mark_tree_contents_uninteresting(r, tree);
 }
 
+struct path_and_oids_entry {
+       struct hashmap_entry ent;
+       char *path;
+       struct oidset trees;
+};
+
+static int path_and_oids_cmp(const void *hashmap_cmp_fn_data,
+                            const struct path_and_oids_entry *e1,
+                            const struct path_and_oids_entry *e2,
+                            const void *keydata)
+{
+       return strcmp(e1->path, e2->path);
+}
+
+static void paths_and_oids_init(struct hashmap *map)
+{
+       hashmap_init(map, (hashmap_cmp_fn) path_and_oids_cmp, NULL, 0);
+}
+
+static void paths_and_oids_clear(struct hashmap *map)
+{
+       struct hashmap_iter iter;
+       struct path_and_oids_entry *entry;
+       hashmap_iter_init(map, &iter);
+
+       while ((entry = (struct path_and_oids_entry *)hashmap_iter_next(&iter))) {
+               oidset_clear(&entry->trees);
+               free(entry->path);
+       }
+
+       hashmap_free(map, 1);
+}
+
+static void paths_and_oids_insert(struct hashmap *map,
+                                 const char *path,
+                                 const struct object_id *oid)
+{
+       int hash = strhash(path);
+       struct path_and_oids_entry key;
+       struct path_and_oids_entry *entry;
+
+       hashmap_entry_init(&key, hash);
+
+       /* use a shallow copy for the lookup */
+       key.path = (char *)path;
+       oidset_init(&key.trees, 0);
+
+       if (!(entry = (struct path_and_oids_entry *)hashmap_get(map, &key, NULL))) {
+               entry = xcalloc(1, sizeof(struct path_and_oids_entry));
+               hashmap_entry_init(entry, hash);
+               entry->path = xstrdup(key.path);
+               oidset_init(&entry->trees, 16);
+               hashmap_put(map, entry);
+       }
+
+       oidset_insert(&entry->trees, oid);
+}
+
+static void add_children_by_path(struct repository *r,
+                                struct tree *tree,
+                                struct hashmap *map)
+{
+       struct tree_desc desc;
+       struct name_entry entry;
+
+       if (!tree)
+               return;
+
+       if (parse_tree_gently(tree, 1) < 0)
+               return;
+
+       init_tree_desc(&desc, tree->buffer, tree->size);
+       while (tree_entry(&desc, &entry)) {
+               switch (object_type(entry.mode)) {
+               case OBJ_TREE:
+                       paths_and_oids_insert(map, entry.path, &entry.oid);
+
+                       if (tree->object.flags & UNINTERESTING) {
+                               struct tree *child = lookup_tree(r, &entry.oid);
+                               if (child)
+                                       child->object.flags |= UNINTERESTING;
+                       }
+                       break;
+               case OBJ_BLOB:
+                       if (tree->object.flags & UNINTERESTING) {
+                               struct blob *child = lookup_blob(r, &entry.oid);
+                               if (child)
+                                       child->object.flags |= UNINTERESTING;
+                       }
+                       break;
+               default:
+                       /* Subproject commit - not in this repository */
+                       break;
+               }
+       }
+
+       free_tree_buffer(tree);
+}
+
+void mark_trees_uninteresting_sparse(struct repository *r,
+                                    struct oidset *trees)
+{
+       unsigned has_interesting = 0, has_uninteresting = 0;
+       struct hashmap map;
+       struct hashmap_iter map_iter;
+       struct path_and_oids_entry *entry;
+       struct object_id *oid;
+       struct oidset_iter iter;
+
+       oidset_iter_init(trees, &iter);
+       while ((!has_interesting || !has_uninteresting) &&
+              (oid = oidset_iter_next(&iter))) {
+               struct tree *tree = lookup_tree(r, oid);
+
+               if (!tree)
+                       continue;
+
+               if (tree->object.flags & UNINTERESTING)
+                       has_uninteresting = 1;
+               else
+                       has_interesting = 1;
+       }
+
+       /* Do not walk unless we have both types of trees. */
+       if (!has_uninteresting || !has_interesting)
+               return;
+
+       paths_and_oids_init(&map);
+
+       oidset_iter_init(trees, &iter);
+       while ((oid = oidset_iter_next(&iter))) {
+               struct tree *tree = lookup_tree(r, oid);
+               add_children_by_path(r, tree, &map);
+       }
+
+       hashmap_iter_init(&map, &map_iter);
+       while ((entry = hashmap_iter_next(&map_iter)))
+               mark_trees_uninteresting_sparse(r, &entry->trees);
+
+       paths_and_oids_clear(&map);
+}
+
 struct commit_stack {
        struct commit **items;
        size_t nr, alloc;
@@ -213,7 +356,20 @@ static struct object *get_reference(struct rev_info *revs, const char *name,
 {
        struct object *object;
 
-       object = parse_object(revs->repo, oid);
+       /*
+        * If the repository has commit graphs, repo_parse_commit() avoids
+        * reading the object buffer, so use it whenever possible.
+        */
+       if (oid_object_info(revs->repo, oid, NULL) == OBJ_COMMIT) {
+               struct commit *c = lookup_commit(revs->repo, oid);
+               if (!repo_parse_commit(revs->repo, c))
+                       object = (struct object *) c;
+               else
+                       object = NULL;
+       } else {
+               object = parse_object(revs->repo, oid);
+       }
+
        if (!object) {
                if (revs->ignore_missing)
                        return object;
@@ -1384,7 +1540,7 @@ void add_index_objects_to_pending(struct rev_info *revs, unsigned int flags)
 {
        struct worktree **worktrees, **p;
 
-       read_index(revs->repo->index);
+       repo_read_index(revs->repo);
        do_add_index_objects_to_pending(revs, revs->repo->index, flags);
 
        if (revs->single_worktree)
@@ -1531,7 +1687,7 @@ static void prepare_show_merge(struct rev_info *revs)
        head->object.flags |= SYMMETRIC_LEFT;
 
        if (!istate->cache_nr)
-               read_index(istate);
+               repo_read_index(revs->repo);
        for (i = 0; i < istate->cache_nr; i++) {
                const struct cache_entry *ce = istate->cache[i];
                if (!ce_stage(ce))
@@ -1590,8 +1746,8 @@ static int handle_dotdot_1(const char *arg, char *dotdot,
        if (!*b_name)
                b_name = "HEAD";
 
-       if (get_oid_with_context(a_name, oc_flags, &a_oid, a_oc) ||
-           get_oid_with_context(b_name, oc_flags, &b_oid, b_oc))
+       if (get_oid_with_context(revs->repo, a_name, oc_flags, &a_oid, a_oc) ||
+           get_oid_with_context(revs->repo, b_name, oc_flags, &b_oid, b_oc))
                return -1;
 
        if (!cant_be_filename) {
@@ -1725,7 +1881,7 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsi
        if (revarg_opt & REVARG_COMMITTISH)
                get_sha1_flags |= GET_OID_COMMITTISH;
 
-       if (get_oid_with_context(arg, get_sha1_flags, &oid, &oc))
+       if (get_oid_with_context(revs->repo, arg, get_sha1_flags, &oid, &oc))
                return revs->ignore_missing ? 0 : -1;
        if (!cant_be_filename)
                verify_non_filename(revs->prefix, arg);
@@ -2458,7 +2614,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
                struct object_id oid;
                struct object *object;
                struct object_context oc;
-               if (get_oid_with_context(revs->def, 0, &oid, &oc))
+               if (get_oid_with_context(revs->repo, revs->def, 0, &oid, &oc))
                        diagnose_missing_default(revs->def);
                object = get_reference(revs, revs->def, &oid, 0);
                add_pending_object_with_mode(revs, object, revs->def, oc.mode);
index 52e5a88ff5725862dced5c72fbc2aa6435b94e3b..d32d62abc6a7e65ba04a9f25c5024d6f5bbb5f49 100644 (file)
@@ -67,6 +67,7 @@ struct rev_cmdline_info {
 #define REVISION_WALK_NO_WALK_SORTED 1
 #define REVISION_WALK_NO_WALK_UNSORTED 2
 
+struct oidset;
 struct topo_walk_info;
 
 struct rev_info {
@@ -327,6 +328,7 @@ void put_revision_mark(const struct rev_info *revs,
 
 void mark_parents_uninteresting(struct commit *commit);
 void mark_tree_uninteresting(struct repository *r, struct tree *tree);
+void mark_trees_uninteresting_sparse(struct repository *r, struct oidset *trees);
 
 void show_object_with_name(FILE *, struct object *, const char *);
 
index f692686770f69b49d44bf6dbabdb17886d85ea1a..6dc16c3211631402432207dcf99b1ef4e87f012b 100644 (file)
@@ -40,7 +40,7 @@ int option_parse_push_signed(const struct option *opt,
 
 static void feed_object(const struct object_id *oid, FILE *fh, int negative)
 {
-       if (negative && !has_sha1_file(oid->hash))
+       if (negative && !has_object_file(oid))
                return;
 
        if (negative)
@@ -135,38 +135,36 @@ static int pack_objects(int fd, struct ref *refs, struct oid_array *extra, struc
        return 0;
 }
 
-static int receive_unpack_status(int in)
+static int receive_unpack_status(struct packet_reader *reader)
 {
-       const char *line = packet_read_line(in, NULL);
-       if (!line)
+       if (packet_reader_read(reader) != PACKET_READ_NORMAL)
                return error(_("unexpected flush packet while reading remote unpack status"));
-       if (!skip_prefix(line, "unpack ", &line))
-               return error(_("unable to parse remote unpack status: %s"), line);
-       if (strcmp(line, "ok"))
-               return error(_("remote unpack failed: %s"), line);
+       if (!skip_prefix(reader->line, "unpack ", &reader->line))
+               return error(_("unable to parse remote unpack status: %s"), reader->line);
+       if (strcmp(reader->line, "ok"))
+               return error(_("remote unpack failed: %s"), reader->line);
        return 0;
 }
 
-static int receive_status(int in, struct ref *refs)
+static int receive_status(struct packet_reader *reader, struct ref *refs)
 {
        struct ref *hint;
        int ret;
 
        hint = NULL;
-       ret = receive_unpack_status(in);
+       ret = receive_unpack_status(reader);
        while (1) {
-               char *refname;
+               const char *refname;
                char *msg;
-               char *line = packet_read_line(in, NULL);
-               if (!line)
+               if (packet_reader_read(reader) != PACKET_READ_NORMAL)
                        break;
-               if (!starts_with(line, "ok ") && !starts_with(line, "ng ")) {
-                       error("invalid ref status from remote: %s", line);
+               if (!starts_with(reader->line, "ok ") && !starts_with(reader->line, "ng ")) {
+                       error("invalid ref status from remote: %s", reader->line);
                        ret = -1;
                        break;
                }
 
-               refname = line + 3;
+               refname = reader->line + 3;
                msg = strchr(refname, ' ');
                if (msg)
                        *msg++ = '\0';
@@ -187,7 +185,7 @@ static int receive_status(int in, struct ref *refs)
                        continue;
                }
 
-               if (line[0] == 'o' && line[1] == 'k')
+               if (reader->line[0] == 'o' && reader->line[1] == 'k')
                        hint->status = REF_STATUS_OK;
                else {
                        hint->status = REF_STATUS_REMOTE_REJECT;
@@ -390,6 +388,7 @@ int send_pack(struct send_pack_args *args,
        int ret;
        struct async demux;
        const char *push_cert_nonce = NULL;
+       struct packet_reader reader;
 
        /* Does the other end support the reporting? */
        if (server_supports("report-status"))
@@ -559,6 +558,10 @@ int send_pack(struct send_pack_args *args,
                in = demux.out;
        }
 
+       packet_reader_init(&reader, in, NULL, 0,
+                          PACKET_READ_CHOMP_NEWLINE |
+                          PACKET_READ_DIE_ON_ERR_PACKET);
+
        if (need_pack_data && cmds_sent) {
                if (pack_objects(out, remote_refs, extra_have, args) < 0) {
                        for (ref = remote_refs; ref; ref = ref->next)
@@ -573,7 +576,7 @@ int send_pack(struct send_pack_args *args,
                         * are failing, and just want the error() side effects.
                         */
                        if (status_report)
-                               receive_unpack_status(in);
+                               receive_unpack_status(&reader);
 
                        if (use_sideband) {
                                close(demux.out);
@@ -590,7 +593,7 @@ int send_pack(struct send_pack_args *args,
                packet_flush(out);
 
        if (status_report && cmds_sent)
-               ret = receive_status(in, remote_refs);
+               ret = receive_status(&reader, remote_refs);
        else
                ret = 0;
        if (args->stateless_rpc)
index 213815dbfc116bc7d9a11b1c7acc429fb078f732..972402e8c0a09de5ec9069826cbb7ecae1ac9803 100644 (file)
@@ -150,6 +150,7 @@ static GIT_PATH_FUNC(rebase_path_refs_to_delete, "rebase-merge/refs-to-delete")
 static GIT_PATH_FUNC(rebase_path_gpg_sign_opt, "rebase-merge/gpg_sign_opt")
 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")
 static GIT_PATH_FUNC(rebase_path_signoff, "rebase-merge/signoff")
 static GIT_PATH_FUNC(rebase_path_head_name, "rebase-merge/head-name")
 static GIT_PATH_FUNC(rebase_path_onto, "rebase-merge/onto")
@@ -157,7 +158,6 @@ static GIT_PATH_FUNC(rebase_path_autostash, "rebase-merge/autostash")
 static GIT_PATH_FUNC(rebase_path_strategy, "rebase-merge/strategy")
 static GIT_PATH_FUNC(rebase_path_strategy_opts, "rebase-merge/strategy_opts")
 static GIT_PATH_FUNC(rebase_path_allow_rerere_autoupdate, "rebase-merge/allow_rerere_autoupdate")
-static GIT_PATH_FUNC(rebase_path_quiet, "rebase-merge/quiet")
 static GIT_PATH_FUNC(rebase_path_reschedule_failed_exec, "rebase-merge/reschedule-failed-exec")
 
 static int git_sequencer_config(const char *k, const char *v, void *cb)
@@ -447,9 +447,9 @@ static struct tree *empty_tree(struct repository *r)
        return lookup_tree(r, the_hash_algo->empty_tree);
 }
 
-static int error_dirty_index(struct index_state *istate, struct replay_opts *opts)
+static int error_dirty_index(struct repository *repo, struct replay_opts *opts)
 {
-       if (read_index_unmerged(istate))
+       if (repo_read_index_unmerged(repo))
                return error_resolve_conflict(_(action_name(opts)));
 
        error(_("your local changes would be overwritten by %s."),
@@ -484,7 +484,7 @@ static int fast_forward_to(struct repository *r,
        struct strbuf sb = STRBUF_INIT;
        struct strbuf err = STRBUF_INIT;
 
-       read_index(r->index);
+       repo_read_index(r);
        if (checkout_fast_forward(r, from, to, 1))
                return -1; /* the callee should have complained already */
 
@@ -541,12 +541,12 @@ static int do_recursive_merge(struct repository *r,
        char **xopt;
        struct lock_file index_lock = LOCK_INIT;
 
-       if (hold_locked_index(&index_lock, LOCK_REPORT_ON_ERROR) < 0)
+       if (repo_hold_locked_index(r, &index_lock, LOCK_REPORT_ON_ERROR) < 0)
                return -1;
 
-       read_index(r->index);
+       repo_read_index(r);
 
-       init_merge_options(&o);
+       init_merge_options(&o, r);
        o.ancestor = base ? base_label : "(empty tree)";
        o.branch1 = "HEAD";
        o.branch2 = next ? next_label : "(empty tree)";
@@ -1116,7 +1116,8 @@ static int run_rewrite_hook(const struct object_id *oldoid,
        return finish_command(&proc);
 }
 
-void commit_post_rewrite(const struct commit *old_head,
+void commit_post_rewrite(struct repository *r,
+                        const struct commit *old_head,
                         const struct object_id *new_head)
 {
        struct notes_rewrite_cfg *cfg;
@@ -1125,7 +1126,7 @@ void commit_post_rewrite(const struct commit *old_head,
        if (cfg) {
                /* we are amending, so old_head is not NULL */
                copy_note_for_rewrite(cfg, &old_head->object.oid, new_head);
-               finish_copy_notes_for_rewrite(cfg, "Notes added by 'git commit --amend'");
+               finish_copy_notes_for_rewrite(r, cfg, "Notes added by 'git commit --amend'");
        }
        run_rewrite_hook(&old_head->object.oid, new_head);
 }
@@ -1406,7 +1407,7 @@ static int try_to_commit(struct repository *r,
        }
 
        if (flags & AMEND_MSG)
-               commit_post_rewrite(current_head, oid);
+               commit_post_rewrite(r, current_head, oid);
 
 out:
        free_commit_extra_headers(extra);
@@ -1768,7 +1769,7 @@ static int do_pick_commit(struct repository *r,
                        oidcpy(&head, the_hash_algo->empty_tree);
                if (index_differs_from(r, unborn ? empty_tree_oid_hex() : "HEAD",
                                       NULL, 0))
-                       return error_dirty_index(r->index, opts);
+                       return error_dirty_index(r, opts);
        }
        discard_index(r->index);
 
@@ -1998,8 +1999,8 @@ static int read_and_refresh_cache(struct repository *r,
                                  struct replay_opts *opts)
 {
        struct lock_file index_lock = LOCK_INIT;
-       int index_fd = hold_locked_index(&index_lock, 0);
-       if (read_index(r->index) < 0) {
+       int index_fd = repo_hold_locked_index(r, &index_lock, 0);
+       if (repo_read_index(r) < 0) {
                rollback_lock_file(&index_lock);
                return error(_("git %s: failed to read the index"),
                        _(action_name(opts)));
@@ -2390,6 +2391,9 @@ static int read_populate_opts(struct replay_opts *opts)
                if (file_exists(rebase_path_verbose()))
                        opts->verbose = 1;
 
+               if (file_exists(rebase_path_quiet()))
+                       opts->quiet = 1;
+
                if (file_exists(rebase_path_signoff())) {
                        opts->allow_ff = 0;
                        opts->signoff = 1;
@@ -2460,9 +2464,6 @@ int write_basic_state(struct replay_opts *opts, const char *head_name,
 
        if (quiet)
                write_file(rebase_path_quiet(), "%s\n", quiet);
-       else
-               write_file(rebase_path_quiet(), "\n");
-
        if (opts->verbose)
                write_file(rebase_path_verbose(), "%s", "");
        if (opts->strategy)
@@ -2865,7 +2866,7 @@ static int do_exec(struct repository *r, const char *command_line)
                                          child_env.argv);
 
        /* force re-reading of the cache */
-       if (discard_index(r->index) < 0 || read_index(r->index) < 0)
+       if (discard_index(r->index) < 0 || repo_read_index(r) < 0)
                return error(_("could not read index"));
 
        dirty = require_clean_work_tree(r, "rebase", NULL, 1, 1);
@@ -2989,7 +2990,7 @@ static int do_reset(struct repository *r,
        struct unpack_trees_options unpack_tree_opts;
        int ret = 0;
 
-       if (hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0)
+       if (repo_hold_locked_index(r, &lock, LOCK_REPORT_ON_ERROR) < 0)
                return -1;
 
        if (len == 10 && !strncmp("[new root]", name, len)) {
@@ -3034,7 +3035,7 @@ static int do_reset(struct repository *r,
        unpack_tree_opts.merge = 1;
        unpack_tree_opts.update = 1;
 
-       if (read_index_unmerged(r->index)) {
+       if (repo_read_index_unmerged(r)) {
                rollback_lock_file(&lock);
                strbuf_release(&ref_name);
                return error_resolve_conflict(_(action_name(opts)));
@@ -3107,7 +3108,7 @@ static int do_merge(struct repository *r,
        static struct lock_file lock;
        const char *p;
 
-       if (hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0) {
+       if (repo_hold_locked_index(r, &lock, LOCK_REPORT_ON_ERROR) < 0) {
                ret = -1;
                goto leave_merge;
        }
@@ -3288,7 +3289,7 @@ static int do_merge(struct repository *r,
 
                /* force re-reading of the cache */
                if (!ret && (discard_index(r->index) < 0 ||
-                            read_index(r->index) < 0))
+                            repo_read_index(r) < 0))
                        ret = error(_("could not read index"));
                goto leave_merge;
        }
@@ -3310,8 +3311,8 @@ static int do_merge(struct repository *r,
                commit_list_insert(j->item, &reversed);
        free_commit_list(bases);
 
-       read_index(r->index);
-       init_merge_options(&o);
+       repo_read_index(r);
+       init_merge_options(&o, r);
        o.branch1 = "HEAD";
        o.branch2 = ref_name.buf;
        o.buffer_output = 2;
@@ -3555,10 +3556,11 @@ static int pick_commits(struct repository *r,
                                        fprintf(f, "%d\n", todo_list->done_nr);
                                        fclose(f);
                                }
-                               fprintf(stderr, "Rebasing (%d/%d)%s",
-                                       todo_list->done_nr,
-                                       todo_list->total_nr,
-                                       opts->verbose ? "\n" : "\r");
+                               if (!opts->quiet)
+                                       fprintf(stderr, "Rebasing (%d/%d)%s",
+                                               todo_list->done_nr,
+                                               todo_list->total_nr,
+                                               opts->verbose ? "\n" : "\r");
                        }
                        unlink(rebase_path_message());
                        unlink(rebase_path_author_script());
@@ -3792,8 +3794,10 @@ static int pick_commits(struct repository *r,
                }
                apply_autostash(opts);
 
-               fprintf(stderr, "Successfully rebased and updated %s.\n",
-                       head_ref.buf);
+               if (!opts->quiet)
+                       fprintf(stderr,
+                               "Successfully rebased and updated %s.\n",
+                               head_ref.buf);
 
                strbuf_release(&buf);
                strbuf_release(&head_ref);
@@ -3984,7 +3988,7 @@ int sequencer_continue(struct repository *r, struct replay_opts *opts)
                                goto release_todo_list;
                }
                if (index_differs_from(r, "HEAD", NULL, 0)) {
-                       res = error_dirty_index(r->index, opts);
+                       res = error_dirty_index(r, opts);
                        goto release_todo_list;
                }
                todo_list.current++;
index 5d7bc04751ad853326e1563fc6176f101d485139..93e891309bb7982c283c77e8950ba8848fdd7d2b 100644 (file)
@@ -40,6 +40,7 @@ struct replay_opts {
        int allow_empty_message;
        int keep_redundant_commits;
        int verbose;
+       int quiet;
        int reschedule_failed_exec;
 
        int mainline;
@@ -125,7 +126,8 @@ int update_head_with_reflog(const struct commit *old_head,
                            const struct object_id *new_head,
                            const char *action, const struct strbuf *msg,
                            struct strbuf *err);
-void commit_post_rewrite(const struct commit *current_head,
+void commit_post_rewrite(struct repository *r,
+                        const struct commit *current_head,
                         const struct object_id *new_head);
 
 int prepare_branch_to_be_rebased(struct replay_opts *opts, const char *commit);
diff --git a/serve.c b/serve.c
index bda085f09c8e10314c2c497dbca978fd9241e7b5..317256c1a493c4b2cc730a6212add4d1ef5696d4 100644 (file)
--- a/serve.c
+++ b/serve.c
@@ -167,7 +167,8 @@ static int process_request(void)
 
        packet_reader_init(&reader, 0, NULL, 0,
                           PACKET_READ_CHOMP_NEWLINE |
-                          PACKET_READ_GENTLE_ON_EOF);
+                          PACKET_READ_GENTLE_ON_EOF |
+                          PACKET_READ_DIE_ON_ERR_PACKET);
 
        /*
         * Check to see if the client closed their end before sending another
@@ -175,7 +176,7 @@ static int process_request(void)
         */
        if (packet_reader_peek(&reader) == PACKET_READ_EOF)
                return 1;
-       reader.options = PACKET_READ_CHOMP_NEWLINE;
+       reader.options &= ~PACKET_READ_GENTLE_ON_EOF;
 
        while (state != PROCESS_REQUEST_DONE) {
                switch (packet_reader_peek(&reader)) {
diff --git a/setup.c b/setup.c
index 12bf25a0ebad33a8d8db9b8f9a44b0e6e04977d4..ca9e8a949ed869183f16c57520f19fb361100a02 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -39,7 +39,7 @@ static int abspath_part_inside_repo(char *path)
        off = offset_1st_component(path);
 
        /* check if work tree is already the prefix */
-       if (wtlen <= len && !strncmp(path, work_tree, wtlen)) {
+       if (wtlen <= len && !fspathncmp(path, work_tree, wtlen)) {
                if (path[wtlen] == '/') {
                        memmove(path, path + wtlen + 1, len - wtlen);
                        return 0;
@@ -59,7 +59,7 @@ static int abspath_part_inside_repo(char *path)
                path++;
                if (*path == '/') {
                        *path = '\0';
-                       if (strcmp(real_path(path0), work_tree) == 0) {
+                       if (fspathcmp(real_path(path0), work_tree) == 0) {
                                memmove(path0, path + 1, len - (path - path0));
                                return 0;
                        }
@@ -68,7 +68,7 @@ static int abspath_part_inside_repo(char *path)
        }
 
        /* check whole path */
-       if (strcmp(real_path(path0), work_tree) == 0) {
+       if (fspathcmp(real_path(path0), work_tree) == 0) {
                *path0 = '\0';
                return 0;
        }
index 10f9e9936aa0a9e5285ac3efb41af3c939dd0ac7..494606f7716923468e6f838dae0486a61b454101 100644 (file)
@@ -192,7 +192,7 @@ int hash_algo_by_id(uint32_t format_id)
 
 /*
  * This is meant to hold a *small* number of objects that you would
- * want read_sha1_file() to be able to return, but yet you do not want
+ * want read_object_file() to be able to return, but yet you do not want
  * to write them into the object store (e.g. a browse-only
  * application).
  */
@@ -401,12 +401,12 @@ int raceproof_create_file(const char *path, create_file_fn fn, void *cb)
        return ret;
 }
 
-static void fill_sha1_path(struct strbuf *buf, const unsigned char *sha1)
+static void fill_loose_path(struct strbuf *buf, const struct object_id *oid)
 {
        int i;
        for (i = 0; i < the_hash_algo->rawsz; i++) {
                static char hex[] = "0123456789abcdef";
-               unsigned int val = sha1[i];
+               unsigned int val = oid->hash[i];
                strbuf_addch(buf, hex[val >> 4]);
                strbuf_addch(buf, hex[val & 0xf]);
                if (!i)
@@ -416,19 +416,19 @@ static void fill_sha1_path(struct strbuf *buf, const unsigned char *sha1)
 
 static const char *odb_loose_path(struct object_directory *odb,
                                  struct strbuf *buf,
-                                 const unsigned char *sha1)
+                                 const struct object_id *oid)
 {
        strbuf_reset(buf);
        strbuf_addstr(buf, odb->path);
        strbuf_addch(buf, '/');
-       fill_sha1_path(buf, sha1);
+       fill_loose_path(buf, oid);
        return buf->buf;
 }
 
 const char *loose_object_path(struct repository *r, struct strbuf *buf,
-                             const unsigned char *sha1)
+                             const struct object_id *oid)
 {
-       return odb_loose_path(r->objects->odb, buf, sha1);
+       return odb_loose_path(r->objects->odb, buf, oid);
 }
 
 /*
@@ -789,7 +789,7 @@ static int check_and_freshen_odb(struct object_directory *odb,
                                 int freshen)
 {
        static struct strbuf path = STRBUF_INIT;
-       odb_loose_path(odb, &path, oid->hash);
+       odb_loose_path(odb, &path, oid);
        return check_and_freshen_file(path.buf, freshen);
 }
 
@@ -866,8 +866,8 @@ void *xmmap(void *start, size_t length,
 
 /*
  * With an in-core object data in "map", rehash it to make sure the
- * object name actually matches "sha1" to detect object corruption.
- * With "map" == NULL, try reading the object named with "sha1" using
+ * object name actually matches "oid" to detect object corruption.
+ * With "map" == NULL, try reading the object named with "oid" using
  * the streaming interface and rehash it to do the same.
  */
 int check_object_signature(const struct object_id *oid, void *map,
@@ -940,22 +940,22 @@ int git_open_cloexec(const char *name, int flags)
 }
 
 /*
- * Find "sha1" as a loose object in the local repository or in an alternate.
+ * Find "oid" as a loose object in the local repository or in an alternate.
  * Returns 0 on success, negative on failure.
  *
  * The "path" out-parameter will give the path of the object we found (if any).
  * Note that it may point to static storage and is only valid until another
- * call to stat_sha1_file().
+ * call to stat_loose_object().
  */
-static int stat_sha1_file(struct repository *r, const unsigned char *sha1,
-                         struct stat *st, const char **path)
+static int stat_loose_object(struct repository *r, const struct object_id *oid,
+                            struct stat *st, const char **path)
 {
        struct object_directory *odb;
        static struct strbuf buf = STRBUF_INIT;
 
        prepare_alt_odb(r);
        for (odb = r->objects->odb; odb; odb = odb->next) {
-               *path = odb_loose_path(odb, &buf, sha1);
+               *path = odb_loose_path(odb, &buf, oid);
                if (!lstat(*path, st))
                        return 0;
        }
@@ -964,11 +964,11 @@ static int stat_sha1_file(struct repository *r, const unsigned char *sha1,
 }
 
 /*
- * Like stat_sha1_file(), but actually open the object and return the
+ * Like stat_loose_object(), but actually open the object and return the
  * descriptor. See the caveats on the "path" parameter above.
  */
-static int open_sha1_file(struct repository *r,
-                         const unsigned char *sha1, const char **path)
+static int open_loose_object(struct repository *r,
+                            const struct object_id *oid, const char **path)
 {
        int fd;
        struct object_directory *odb;
@@ -977,7 +977,7 @@ static int open_sha1_file(struct repository *r,
 
        prepare_alt_odb(r);
        for (odb = r->objects->odb; odb; odb = odb->next) {
-               *path = odb_loose_path(odb, &buf, sha1);
+               *path = odb_loose_path(odb, &buf, oid);
                fd = git_open(*path);
                if (fd >= 0)
                        return fd;
@@ -990,16 +990,13 @@ static int open_sha1_file(struct repository *r,
 }
 
 static int quick_has_loose(struct repository *r,
-                          const unsigned char *sha1)
+                          const struct object_id *oid)
 {
-       struct object_id oid;
        struct object_directory *odb;
 
-       hashcpy(oid.hash, sha1);
-
        prepare_alt_odb(r);
        for (odb = r->objects->odb; odb; odb = odb->next) {
-               if (oid_array_lookup(odb_loose_cache(odb, &oid), &oid) >= 0)
+               if (oid_array_lookup(odb_loose_cache(odb, oid), oid) >= 0)
                        return 1;
        }
        return 0;
@@ -1007,10 +1004,10 @@ static int quick_has_loose(struct repository *r,
 
 /*
  * Map the loose object at "path" if it is not NULL, or the path found by
- * searching for a loose object named "sha1".
+ * searching for a loose object named "oid".
  */
-static void *map_sha1_file_1(struct repository *r, const char *path,
-                            const unsigned char *sha1, unsigned long *size)
+static void *map_loose_object_1(struct repository *r, const char *path,
+                            const struct object_id *oid, unsigned long *size)
 {
        void *map;
        int fd;
@@ -1018,7 +1015,7 @@ static void *map_sha1_file_1(struct repository *r, const char *path,
        if (path)
                fd = git_open(path);
        else
-               fd = open_sha1_file(r, sha1, &path);
+               fd = open_loose_object(r, oid, &path);
        map = NULL;
        if (fd >= 0) {
                struct stat st;
@@ -1038,15 +1035,16 @@ static void *map_sha1_file_1(struct repository *r, const char *path,
        return map;
 }
 
-void *map_sha1_file(struct repository *r,
-                   const unsigned char *sha1, unsigned long *size)
+void *map_loose_object(struct repository *r,
+                      const struct object_id *oid,
+                      unsigned long *size)
 {
-       return map_sha1_file_1(r, NULL, sha1, size);
+       return map_loose_object_1(r, NULL, oid, size);
 }
 
-static int unpack_sha1_short_header(git_zstream *stream,
-                                   unsigned char *map, unsigned long mapsize,
-                                   void *buffer, unsigned long bufsiz)
+static int unpack_loose_short_header(git_zstream *stream,
+                                    unsigned char *map, unsigned long mapsize,
+                                    void *buffer, unsigned long bufsiz)
 {
        /* Get the data stream */
        memset(stream, 0, sizeof(*stream));
@@ -1059,12 +1057,12 @@ static int unpack_sha1_short_header(git_zstream *stream,
        return git_inflate(stream, 0);
 }
 
-int unpack_sha1_header(git_zstream *stream,
-                      unsigned char *map, unsigned long mapsize,
-                      void *buffer, unsigned long bufsiz)
+int unpack_loose_header(git_zstream *stream,
+                       unsigned char *map, unsigned long mapsize,
+                       void *buffer, unsigned long bufsiz)
 {
-       int status = unpack_sha1_short_header(stream, map, mapsize,
-                                             buffer, bufsiz);
+       int status = unpack_loose_short_header(stream, map, mapsize,
+                                              buffer, bufsiz);
 
        if (status < Z_OK)
                return status;
@@ -1075,13 +1073,13 @@ int unpack_sha1_header(git_zstream *stream,
        return 0;
 }
 
-static int unpack_sha1_header_to_strbuf(git_zstream *stream, unsigned char *map,
-                                       unsigned long mapsize, void *buffer,
-                                       unsigned long bufsiz, struct strbuf *header)
+static int unpack_loose_header_to_strbuf(git_zstream *stream, unsigned char *map,
+                                        unsigned long mapsize, void *buffer,
+                                        unsigned long bufsiz, struct strbuf *header)
 {
        int status;
 
-       status = unpack_sha1_short_header(stream, map, mapsize, buffer, bufsiz);
+       status = unpack_loose_short_header(stream, map, mapsize, buffer, bufsiz);
        if (status < Z_OK)
                return -1;
 
@@ -1111,7 +1109,9 @@ static int unpack_sha1_header_to_strbuf(git_zstream *stream, unsigned char *map,
        return -1;
 }
 
-static void *unpack_sha1_rest(git_zstream *stream, void *buffer, unsigned long size, const unsigned char *sha1)
+static void *unpack_loose_rest(git_zstream *stream,
+                              void *buffer, unsigned long size,
+                              const struct object_id *oid)
 {
        int bytes = strlen(buffer) + 1;
        unsigned char *buf = xmallocz(size);
@@ -1148,10 +1148,10 @@ static void *unpack_sha1_rest(git_zstream *stream, void *buffer, unsigned long s
        }
 
        if (status < 0)
-               error(_("corrupt loose object '%s'"), sha1_to_hex(sha1));
+               error(_("corrupt loose object '%s'"), oid_to_hex(oid));
        else if (stream->avail_in)
                error(_("garbage at end of loose object '%s'"),
-                     sha1_to_hex(sha1));
+                     oid_to_hex(oid));
        free(buf);
        return NULL;
 }
@@ -1161,8 +1161,8 @@ static void *unpack_sha1_rest(git_zstream *stream, void *buffer, unsigned long s
  * too permissive for what we want to check. So do an anal
  * object header parse by hand.
  */
-static int parse_sha1_header_extended(const char *hdr, struct object_info *oi,
-                              unsigned int flags)
+static int parse_loose_header_extended(const char *hdr, struct object_info *oi,
+                                      unsigned int flags)
 {
        const char *type_buf = hdr;
        unsigned long size;
@@ -1222,17 +1222,17 @@ static int parse_sha1_header_extended(const char *hdr, struct object_info *oi,
        return *hdr ? -1 : type;
 }
 
-int parse_sha1_header(const char *hdr, unsigned long *sizep)
+int parse_loose_header(const char *hdr, unsigned long *sizep)
 {
        struct object_info oi = OBJECT_INFO_INIT;
 
        oi.sizep = sizep;
-       return parse_sha1_header_extended(hdr, &oi, 0);
+       return parse_loose_header_extended(hdr, &oi, 0);
 }
 
-static int sha1_loose_object_info(struct repository *r,
-                                 const unsigned char *sha1,
-                                 struct object_info *oi, int flags)
+static int loose_object_info(struct repository *r,
+                            const struct object_id *oid,
+                            struct object_info *oi, int flags)
 {
        int status = 0;
        unsigned long mapsize;
@@ -1257,15 +1257,15 @@ static int sha1_loose_object_info(struct repository *r,
                const char *path;
                struct stat st;
                if (!oi->disk_sizep && (flags & OBJECT_INFO_QUICK))
-                       return quick_has_loose(r, sha1) ? 0 : -1;
-               if (stat_sha1_file(r, sha1, &st, &path) < 0)
+                       return quick_has_loose(r, oid) ? 0 : -1;
+               if (stat_loose_object(r, oid, &st, &path) < 0)
                        return -1;
                if (oi->disk_sizep)
                        *oi->disk_sizep = st.st_size;
                return 0;
        }
 
-       map = map_sha1_file(r, sha1, &mapsize);
+       map = map_loose_object(r, oid, &mapsize);
        if (!map)
                return -1;
 
@@ -1275,24 +1275,24 @@ static int sha1_loose_object_info(struct repository *r,
        if (oi->disk_sizep)
                *oi->disk_sizep = mapsize;
        if ((flags & OBJECT_INFO_ALLOW_UNKNOWN_TYPE)) {
-               if (unpack_sha1_header_to_strbuf(&stream, map, mapsize, hdr, sizeof(hdr), &hdrbuf) < 0)
+               if (unpack_loose_header_to_strbuf(&stream, map, mapsize, hdr, sizeof(hdr), &hdrbuf) < 0)
                        status = error(_("unable to unpack %s header with --allow-unknown-type"),
-                                      sha1_to_hex(sha1));
-       } else if (unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr)) < 0)
+                                      oid_to_hex(oid));
+       } else if (unpack_loose_header(&stream, map, mapsize, hdr, sizeof(hdr)) < 0)
                status = error(_("unable to unpack %s header"),
-                              sha1_to_hex(sha1));
+                              oid_to_hex(oid));
        if (status < 0)
                ; /* Do nothing */
        else if (hdrbuf.len) {
-               if ((status = parse_sha1_header_extended(hdrbuf.buf, oi, flags)) < 0)
+               if ((status = parse_loose_header_extended(hdrbuf.buf, oi, flags)) < 0)
                        status = error(_("unable to parse %s header with --allow-unknown-type"),
-                                      sha1_to_hex(sha1));
-       } else if ((status = parse_sha1_header_extended(hdr, oi, flags)) < 0)
-               status = error(_("unable to parse %s header"), sha1_to_hex(sha1));
+                                      oid_to_hex(oid));
+       } else if ((status = parse_loose_header_extended(hdr, oi, flags)) < 0)
+               status = error(_("unable to parse %s header"), oid_to_hex(oid));
 
        if (status >= 0 && oi->contentp) {
-               *oi->contentp = unpack_sha1_rest(&stream, hdr,
-                                                *oi->sizep, sha1);
+               *oi->contentp = unpack_loose_rest(&stream, hdr,
+                                                 *oi->sizep, oid);
                if (!*oi->contentp) {
                        git_inflate_end(&stream);
                        status = -1;
@@ -1358,7 +1358,7 @@ int oid_object_info_extended(struct repository *r, const struct object_id *oid,
                        return -1;
 
                /* Most likely it's a loose object. */
-               if (!sha1_loose_object_info(r, real->hash, oi, flags))
+               if (!loose_object_info(r, real, oi, flags))
                        return 0;
 
                /* Not a loose object; someone else may have just packed it. */
@@ -1421,19 +1421,17 @@ int oid_object_info(struct repository *r,
        return type;
 }
 
-static void *read_object(const unsigned char *sha1, enum object_type *type,
+static void *read_object(struct repository *r,
+                        const struct object_id *oid, enum object_type *type,
                         unsigned long *size)
 {
-       struct object_id oid;
        struct object_info oi = OBJECT_INFO_INIT;
        void *content;
        oi.typep = type;
        oi.sizep = size;
        oi.contentp = &content;
 
-       hashcpy(oid.hash, sha1);
-
-       if (oid_object_info_extended(the_repository, &oid, &oi, 0) < 0)
+       if (oid_object_info_extended(r, oid, &oi, 0) < 0)
                return NULL;
        return content;
 }
@@ -1444,7 +1442,7 @@ int pretend_object_file(void *buf, unsigned long len, enum object_type type,
        struct cached_object *co;
 
        hash_object_file(buf, len, type_name(type), oid);
-       if (has_sha1_file(oid->hash) || find_cached_object(oid))
+       if (has_object_file(oid) || find_cached_object(oid))
                return 0;
        ALLOC_GROW(cached_objects, cached_object_nr + 1, cached_object_alloc);
        co = &cached_objects[cached_object_nr++];
@@ -1461,7 +1459,8 @@ int pretend_object_file(void *buf, unsigned long len, enum object_type type,
  * deal with them should arrange to call read_object() and give error
  * messages themselves.
  */
-void *read_object_file_extended(const struct object_id *oid,
+void *read_object_file_extended(struct repository *r,
+                               const struct object_id *oid,
                                enum object_type *type,
                                unsigned long *size,
                                int lookup_replace)
@@ -1471,10 +1470,10 @@ void *read_object_file_extended(const struct object_id *oid,
        const char *path;
        struct stat st;
        const struct object_id *repl = lookup_replace ?
-               lookup_replace_object(the_repository, oid) : oid;
+               lookup_replace_object(r, oid) : oid;
 
        errno = 0;
-       data = read_object(repl->hash, type, size);
+       data = read_object(r, repl, type, size);
        if (data)
                return data;
 
@@ -1486,11 +1485,11 @@ void *read_object_file_extended(const struct object_id *oid,
                die(_("replacement %s not found for %s"),
                    oid_to_hex(repl), oid_to_hex(oid));
 
-       if (!stat_sha1_file(the_repository, repl->hash, &st, &path))
+       if (!stat_loose_object(r, repl, &st, &path))
                die(_("loose object %s (stored in %s) is corrupt"),
                    oid_to_hex(repl), path);
 
-       if ((p = has_packed_and_bad(repl->hash)) != NULL)
+       if ((p = has_packed_and_bad(r, repl->hash)) != NULL)
                die(_("packed object %s (stored in %s) is corrupt"),
                    oid_to_hex(repl), p->pack_name);
 
@@ -1593,7 +1592,7 @@ int finalize_object_file(const char *tmpfile, const char *filename)
        unlink_or_warn(tmpfile);
        if (ret) {
                if (ret != EEXIST) {
-                       return error_errno(_("unable to write sha1 filename %s"), filename);
+                       return error_errno(_("unable to write file %s"), filename);
                }
                /* FIXME!!! Collision check here ? */
        }
@@ -1621,12 +1620,12 @@ int hash_object_file(const void *buf, unsigned long len, const char *type,
 }
 
 /* Finalize a file on disk, and close it. */
-static void close_sha1_file(int fd)
+static void close_loose_object(int fd)
 {
        if (fsync_object_files)
-               fsync_or_die(fd, "sha1 file");
+               fsync_or_die(fd, "loose object file");
        if (close(fd) != 0)
-               die_errno(_("error when closing sha1 file"));
+               die_errno(_("error when closing loose object file"));
 }
 
 /* Size of directory component, including the ending '/' */
@@ -1686,7 +1685,7 @@ static int write_loose_object(const struct object_id *oid, char *hdr,
        static struct strbuf tmp_file = STRBUF_INIT;
        static struct strbuf filename = STRBUF_INIT;
 
-       loose_object_path(the_repository, &filename, oid->hash);
+       loose_object_path(the_repository, &filename, oid);
 
        fd = create_tmpfile(&tmp_file, filename.buf);
        if (fd < 0) {
@@ -1717,7 +1716,7 @@ static int write_loose_object(const struct object_id *oid, char *hdr,
                ret = git_deflate(&stream, Z_FINISH);
                the_hash_algo->update_fn(&c, in0, stream.next_in - in0);
                if (write_buffer(fd, compressed, stream.next_out - compressed) < 0)
-                       die(_("unable to write sha1 file"));
+                       die(_("unable to write loose object file"));
                stream.next_out = compressed;
                stream.avail_out = sizeof(compressed);
        } while (ret == Z_OK);
@@ -1734,7 +1733,7 @@ static int write_loose_object(const struct object_id *oid, char *hdr,
                die(_("confused by unstable object source data for %s"),
                    oid_to_hex(oid));
 
-       close_sha1_file(fd);
+       close_loose_object(fd);
 
        if (mtime) {
                struct utimbuf utb;
@@ -1814,9 +1813,9 @@ int force_object_loose(const struct object_id *oid, time_t mtime)
 
        if (has_loose_object(oid))
                return 0;
-       buf = read_object(oid->hash, &type, &len);
+       buf = read_object(the_repository, oid, &type, &len);
        if (!buf)
-               return error(_("cannot read sha1_file for %s"), oid_to_hex(oid));
+               return error(_("cannot read object for %s"), oid_to_hex(oid));
        hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %"PRIuMAX , type_name(type), (uintmax_t)len) + 1;
        ret = write_loose_object(oid, hdr, hdrlen, buf, len, mtime);
        free(buf);
@@ -1824,24 +1823,19 @@ int force_object_loose(const struct object_id *oid, time_t mtime)
        return ret;
 }
 
-int has_sha1_file_with_flags(const unsigned char *sha1, int flags)
+int repo_has_object_file_with_flags(struct repository *r,
+                                   const struct object_id *oid, int flags)
 {
-       struct object_id oid;
        if (!startup_info->have_repository)
                return 0;
-       hashcpy(oid.hash, sha1);
-       return oid_object_info_extended(the_repository, &oid, NULL,
+       return oid_object_info_extended(r, oid, NULL,
                                        flags | OBJECT_INFO_SKIP_CACHED) >= 0;
 }
 
-int has_object_file(const struct object_id *oid)
+int repo_has_object_file(struct repository *r,
+                        const struct object_id *oid)
 {
-       return has_sha1_file(oid->hash);
-}
-
-int has_object_file_with_flags(const struct object_id *oid, int flags)
-{
-       return has_sha1_file_with_flags(oid->hash, flags);
+       return repo_has_object_file_with_flags(r, oid, 0);
 }
 
 static void check_tree(const void *buf, size_t size)
@@ -2252,14 +2246,14 @@ void odb_clear_loose_cache(struct object_directory *odb)
               sizeof(odb->loose_objects_subdir_seen));
 }
 
-static int check_stream_sha1(git_zstream *stream,
-                            const char *hdr,
-                            unsigned long size,
-                            const char *path,
-                            const unsigned char *expected_sha1)
+static int check_stream_oid(git_zstream *stream,
+                           const char *hdr,
+                           unsigned long size,
+                           const char *path,
+                           const struct object_id *expected_oid)
 {
        git_hash_ctx c;
-       unsigned char real_sha1[GIT_MAX_RAWSZ];
+       struct object_id real_oid;
        unsigned char buf[4096];
        unsigned long total_read;
        int status = Z_OK;
@@ -2275,7 +2269,7 @@ static int check_stream_sha1(git_zstream *stream,
 
        /*
         * This size comparison must be "<=" to read the final zlib packets;
-        * see the comment in unpack_sha1_rest for details.
+        * see the comment in unpack_loose_rest for details.
         */
        while (total_read <= size &&
               (status == Z_OK ||
@@ -2291,19 +2285,19 @@ static int check_stream_sha1(git_zstream *stream,
        git_inflate_end(stream);
 
        if (status != Z_STREAM_END) {
-               error(_("corrupt loose object '%s'"), sha1_to_hex(expected_sha1));
+               error(_("corrupt loose object '%s'"), oid_to_hex(expected_oid));
                return -1;
        }
        if (stream->avail_in) {
                error(_("garbage at end of loose object '%s'"),
-                     sha1_to_hex(expected_sha1));
+                     oid_to_hex(expected_oid));
                return -1;
        }
 
-       the_hash_algo->final_fn(real_sha1, &c);
-       if (!hasheq(expected_sha1, real_sha1)) {
-               error(_("sha1 mismatch for %s (expected %s)"), path,
-                     sha1_to_hex(expected_sha1));
+       the_hash_algo->final_fn(real_oid.hash, &c);
+       if (!oideq(expected_oid, &real_oid)) {
+               error(_("hash mismatch for %s (expected %s)"), path,
+                     oid_to_hex(expected_oid));
                return -1;
        }
 
@@ -2324,18 +2318,18 @@ int read_loose_object(const char *path,
 
        *contents = NULL;
 
-       map = map_sha1_file_1(the_repository, path, NULL, &mapsize);
+       map = map_loose_object_1(the_repository, path, NULL, &mapsize);
        if (!map) {
                error_errno(_("unable to mmap %s"), path);
                goto out;
        }
 
-       if (unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr)) < 0) {
+       if (unpack_loose_header(&stream, map, mapsize, hdr, sizeof(hdr)) < 0) {
                error(_("unable to unpack header of %s"), path);
                goto out;
        }
 
-       *type = parse_sha1_header(hdr, size);
+       *type = parse_loose_header(hdr, size);
        if (*type < 0) {
                error(_("unable to parse header of %s"), path);
                git_inflate_end(&stream);
@@ -2343,10 +2337,10 @@ int read_loose_object(const char *path,
        }
 
        if (*type == OBJ_BLOB && *size > big_file_threshold) {
-               if (check_stream_sha1(&stream, hdr, *size, path, expected_oid->hash) < 0)
+               if (check_stream_oid(&stream, hdr, *size, path, expected_oid) < 0)
                        goto out;
        } else {
-               *contents = unpack_sha1_rest(&stream, hdr, *size, expected_oid->hash);
+               *contents = unpack_loose_rest(&stream, hdr, *size, expected_oid);
                if (!*contents) {
                        error(_("unable to unpack contents of %s"), path);
                        git_inflate_end(&stream);
@@ -2354,7 +2348,7 @@ int read_loose_object(const char *path,
                }
                if (check_object_signature(expected_oid, *contents,
                                         *size, type_name(*type))) {
-                       error(_("sha1 mismatch for %s (expected %s)"), path,
+                       error(_("hash mismatch for %s (expected %s)"), path,
                              oid_to_hex(expected_oid));
                        free(*contents);
                        goto out;
index a656481c6aa9fbfe3eeff2367232690208ab8566..d1cc77c124c11ffd49be472b1368baeda3afbe17 100644 (file)
@@ -190,9 +190,6 @@ static void find_short_packed_object(struct disambiguate_state *ds)
                unique_in_pack(p, ds);
 }
 
-#define SHORT_NAME_NOT_FOUND (-1)
-#define SHORT_NAME_AMBIGUOUS (-2)
-
 static int finish_object_disambiguation(struct disambiguate_state *ds,
                                        struct object_id *oid)
 {
@@ -200,7 +197,7 @@ static int finish_object_disambiguation(struct disambiguate_state *ds,
                return SHORT_NAME_AMBIGUOUS;
 
        if (!ds->candidate_exists)
-               return SHORT_NAME_NOT_FOUND;
+               return MISSING_OBJECT;
 
        if (!ds->candidate_checked)
                /*
@@ -414,8 +411,9 @@ static int sort_ambiguous(const void *a, const void *b)
        return a_type_sort > b_type_sort ? 1 : -1;
 }
 
-static int get_short_oid(const char *name, int len, struct object_id *oid,
-                         unsigned flags)
+static enum get_oid_result get_short_oid(const char *name, int len,
+                                        struct object_id *oid,
+                                        unsigned flags)
 {
        int status;
        struct disambiguate_state ds;
@@ -733,7 +731,7 @@ static inline int push_mark(const char *string, int len)
        return at_mark(string, len, suffix, ARRAY_SIZE(suffix));
 }
 
-static int get_oid_1(const char *name, int len, struct object_id *oid, unsigned lookup_flags);
+static enum get_oid_result get_oid_1(const char *name, int len, struct object_id *oid, unsigned lookup_flags);
 static int interpret_nth_prior_checkout(const char *name, int namelen, struct strbuf *buf);
 
 static int get_oid_basic(const char *str, int len, struct object_id *oid,
@@ -883,11 +881,12 @@ static int get_oid_basic(const char *str, int len, struct object_id *oid,
        return 0;
 }
 
-static int get_parent(const char *name, int len,
-                     struct object_id *result, int idx)
+static enum get_oid_result get_parent(const char *name, int len,
+                                     struct object_id *result, int idx)
 {
        struct object_id oid;
-       int ret = get_oid_1(name, len, &oid, GET_OID_COMMITTISH);
+       enum get_oid_result ret = get_oid_1(name, len, &oid,
+                                           GET_OID_COMMITTISH);
        struct commit *commit;
        struct commit_list *p;
 
@@ -895,24 +894,25 @@ static int get_parent(const char *name, int len,
                return ret;
        commit = lookup_commit_reference(the_repository, &oid);
        if (parse_commit(commit))
-               return -1;
+               return MISSING_OBJECT;
        if (!idx) {
                oidcpy(result, &commit->object.oid);
-               return 0;
+               return FOUND;
        }
        p = commit->parents;
        while (p) {
                if (!--idx) {
                        oidcpy(result, &p->item->object.oid);
-                       return 0;
+                       return FOUND;
                }
                p = p->next;
        }
-       return -1;
+       return MISSING_OBJECT;
 }
 
-static int get_nth_ancestor(const char *name, int len,
-                           struct object_id *result, int generation)
+static enum get_oid_result get_nth_ancestor(const char *name, int len,
+                                           struct object_id *result,
+                                           int generation)
 {
        struct object_id oid;
        struct commit *commit;
@@ -923,15 +923,15 @@ static int get_nth_ancestor(const char *name, int len,
                return ret;
        commit = lookup_commit_reference(the_repository, &oid);
        if (!commit)
-               return -1;
+               return MISSING_OBJECT;
 
        while (generation--) {
                if (parse_commit(commit) || !commit->parents)
-                       return -1;
+                       return MISSING_OBJECT;
                commit = commit->parents->item;
        }
        oidcpy(result, &commit->object.oid);
-       return 0;
+       return FOUND;
 }
 
 struct object *peel_to_type(const char *name, int namelen,
@@ -1077,7 +1077,9 @@ static int get_describe_name(const char *name, int len, struct object_id *oid)
        return -1;
 }
 
-static int get_oid_1(const char *name, int len, struct object_id *oid, unsigned lookup_flags)
+static enum get_oid_result get_oid_1(const char *name, int len,
+                                    struct object_id *oid,
+                                    unsigned lookup_flags)
 {
        int ret, has_suffix;
        const char *cp;
@@ -1111,16 +1113,16 @@ static int get_oid_1(const char *name, int len, struct object_id *oid, unsigned
 
        ret = peel_onion(name, len, oid, lookup_flags);
        if (!ret)
-               return 0;
+               return FOUND;
 
        ret = get_oid_basic(name, len, oid, lookup_flags);
        if (!ret)
-               return 0;
+               return FOUND;
 
        /* It could be describe output that is "SOMETHING-gXXXX" */
        ret = get_describe_name(name, len, oid);
        if (!ret)
-               return 0;
+               return FOUND;
 
        return get_short_oid(name, len, oid, lookup_flags);
 }
@@ -1513,7 +1515,7 @@ int strbuf_check_branch_ref(struct strbuf *sb, const char *name)
 int get_oid(const char *name, struct object_id *oid)
 {
        struct object_context unused;
-       return get_oid_with_context(name, 0, oid, &unused);
+       return get_oid_with_context(the_repository, name, 0, oid, &unused);
 }
 
 
@@ -1530,35 +1532,40 @@ int get_oid(const char *name, struct object_id *oid)
 int get_oid_committish(const char *name, struct object_id *oid)
 {
        struct object_context unused;
-       return get_oid_with_context(name, GET_OID_COMMITTISH,
+       return get_oid_with_context(the_repository,
+                                   name, GET_OID_COMMITTISH,
                                    oid, &unused);
 }
 
 int get_oid_treeish(const char *name, struct object_id *oid)
 {
        struct object_context unused;
-       return get_oid_with_context(name, GET_OID_TREEISH,
+       return get_oid_with_context(the_repository,
+                                   name, GET_OID_TREEISH,
                                    oid, &unused);
 }
 
 int get_oid_commit(const char *name, struct object_id *oid)
 {
        struct object_context unused;
-       return get_oid_with_context(name, GET_OID_COMMIT,
+       return get_oid_with_context(the_repository,
+                                   name, GET_OID_COMMIT,
                                    oid, &unused);
 }
 
 int get_oid_tree(const char *name, struct object_id *oid)
 {
        struct object_context unused;
-       return get_oid_with_context(name, GET_OID_TREE,
+       return get_oid_with_context(the_repository,
+                                   name, GET_OID_TREE,
                                    oid, &unused);
 }
 
 int get_oid_blob(const char *name, struct object_id *oid)
 {
        struct object_context unused;
-       return get_oid_with_context(name, GET_OID_BLOB,
+       return get_oid_with_context(the_repository,
+                                   name, GET_OID_BLOB,
                                    oid, &unused);
 }
 
@@ -1597,7 +1604,8 @@ static void diagnose_invalid_oid_path(const char *prefix,
 }
 
 /* Must be called only when :stage:filename doesn't exist. */
-static void diagnose_invalid_index_path(int stage,
+static void diagnose_invalid_index_path(struct index_state *istate,
+                                       int stage,
                                        const char *prefix,
                                        const char *filename)
 {
@@ -1610,11 +1618,11 @@ static void diagnose_invalid_index_path(int stage,
                prefix = "";
 
        /* Wrong stage number? */
-       pos = cache_name_pos(filename, namelen);
+       pos = index_name_pos(istate, filename, namelen);
        if (pos < 0)
                pos = -pos - 1;
-       if (pos < active_nr) {
-               ce = active_cache[pos];
+       if (pos < istate->cache_nr) {
+               ce = istate->cache[pos];
                if (ce_namelen(ce) == namelen &&
                    !memcmp(ce->name, filename, namelen))
                        die("Path '%s' is in the index, but not at stage %d.\n"
@@ -1626,11 +1634,11 @@ static void diagnose_invalid_index_path(int stage,
        /* Confusion between relative and absolute filenames? */
        strbuf_addstr(&fullname, prefix);
        strbuf_addstr(&fullname, filename);
-       pos = cache_name_pos(fullname.buf, fullname.len);
+       pos = index_name_pos(istate, fullname.buf, fullname.len);
        if (pos < 0)
                pos = -pos - 1;
-       if (pos < active_nr) {
-               ce = active_cache[pos];
+       if (pos < istate->cache_nr) {
+               ce = istate->cache[pos];
                if (ce_namelen(ce) == fullname.len &&
                    !memcmp(ce->name, fullname.buf, fullname.len))
                        die("Path '%s' is in the index, but not '%s'.\n"
@@ -1664,7 +1672,8 @@ static char *resolve_relative_path(const char *rel)
                           rel);
 }
 
-static int get_oid_with_context_1(const char *name,
+static enum get_oid_result get_oid_with_context_1(struct repository *repo,
+                                 const char *name,
                                  unsigned flags,
                                  const char *prefix,
                                  struct object_id *oid,
@@ -1723,13 +1732,13 @@ static int get_oid_with_context_1(const char *name,
                if (flags & GET_OID_RECORD_PATH)
                        oc->path = xstrdup(cp);
 
-               if (!active_cache)
-                       read_cache();
-               pos = cache_name_pos(cp, namelen);
+               if (!repo->index->cache)
+                       repo_read_index(the_repository);
+               pos = index_name_pos(repo->index, cp, namelen);
                if (pos < 0)
                        pos = -pos - 1;
-               while (pos < active_nr) {
-                       ce = active_cache[pos];
+               while (pos < repo->index->cache_nr) {
+                       ce = repo->index->cache[pos];
                        if (ce_namelen(ce) != namelen ||
                            memcmp(ce->name, cp, namelen))
                                break;
@@ -1742,7 +1751,7 @@ static int get_oid_with_context_1(const char *name,
                        pos++;
                }
                if (only_to_die && name[1] && name[1] != '/')
-                       diagnose_invalid_index_path(stage, prefix, cp);
+                       diagnose_invalid_index_path(repo->index, stage, prefix, cp);
                free(new_path);
                return -1;
        }
@@ -1807,12 +1816,15 @@ void maybe_die_on_misspelt_object_name(const char *name, const char *prefix)
 {
        struct object_context oc;
        struct object_id oid;
-       get_oid_with_context_1(name, GET_OID_ONLY_TO_DIE, prefix, &oid, &oc);
+       get_oid_with_context_1(the_repository, name, GET_OID_ONLY_TO_DIE,
+                              prefix, &oid, &oc);
 }
 
-int get_oid_with_context(const char *str, unsigned flags, struct object_id *oid, struct object_context *oc)
+int get_oid_with_context(struct repository *repo, const char *str,
+                        unsigned flags, struct object_id *oid,
+                        struct object_context *oc)
 {
        if (flags & GET_OID_FOLLOW_SYMLINKS && flags & GET_OID_ONLY_TO_DIE)
                BUG("incompatible flags for get_sha1_with_context");
-       return get_oid_with_context_1(str, flags, NULL, oid, oc);
+       return get_oid_with_context_1(repo, str, flags, NULL, oid, oc);
 }
index 7c3d33d3f87965fc96720ad47674a81a804f43dd..ef851113c44ee91e594734bf68567110b7ac8c6b 100644 (file)
@@ -1,7 +1,6 @@
 #include "cache.h"
 #include "color.h"
 #include "config.h"
-#include "pkt-line.h"
 #include "sideband.h"
 #include "help.h"
 
@@ -110,109 +109,104 @@ static void maybe_colorize_sideband(struct strbuf *dest, const char *src, int n)
 }
 
 
-/*
- * Receive multiplexed output stream over git native protocol.
- * in_stream is the input stream from the remote, which carries data
- * in pkt_line format with band designator.  Demultiplex it into out
- * and err and return error appropriately.  Band #1 carries the
- * primary payload.  Things coming over band #2 is not necessarily
- * error; they are usually informative message on the standard error
- * stream, aka "verbose").  A message over band #3 is a signal that
- * the remote died unexpectedly.  A flush() concludes the stream.
- */
-
 #define DISPLAY_PREFIX "remote: "
 
 #define ANSI_SUFFIX "\033[K"
 #define DUMB_SUFFIX "        "
 
-int recv_sideband(const char *me, int in_stream, int out)
+int demultiplex_sideband(const char *me, char *buf, int len,
+                        int die_on_error,
+                        struct strbuf *scratch,
+                        enum sideband_type *sideband_type)
 {
-       const char *suffix;
-       char buf[LARGE_PACKET_MAX + 1];
-       struct strbuf outbuf = STRBUF_INIT;
-       int retval = 0;
-
-       if (isatty(2) && !is_terminal_dumb())
-               suffix = ANSI_SUFFIX;
-       else
-               suffix = DUMB_SUFFIX;
-
-       while (!retval) {
-               const char *b, *brk;
-               int band, len;
-               len = packet_read(in_stream, NULL, NULL, buf, LARGE_PACKET_MAX, 0);
-               if (len == 0)
-                       break;
-               if (len < 1) {
-                       strbuf_addf(&outbuf,
-                                   "%s%s: protocol error: no band designator",
-                                   outbuf.len ? "\n" : "", me);
-                       retval = SIDEBAND_PROTOCOL_ERROR;
-                       break;
-               }
-               band = buf[0] & 0xff;
-               buf[len] = '\0';
-               len--;
-               switch (band) {
-               case 3:
-                       strbuf_addf(&outbuf, "%s%s", outbuf.len ? "\n" : "",
-                                   DISPLAY_PREFIX);
-                       maybe_colorize_sideband(&outbuf, buf + 1, len);
-
-                       retval = SIDEBAND_REMOTE_ERROR;
-                       break;
-               case 2:
-                       b = buf + 1;
-
-                       /*
-                        * Append a suffix to each nonempty line to clear the
-                        * end of the screen line.
-                        *
-                        * The output is accumulated in a buffer and
-                        * each line is printed to stderr using
-                        * write(2) to ensure inter-process atomicity.
-                        */
-                       while ((brk = strpbrk(b, "\n\r"))) {
-                               int linelen = brk - b;
-
-                               if (!outbuf.len)
-                                       strbuf_addstr(&outbuf, DISPLAY_PREFIX);
-                               if (linelen > 0) {
-                                       maybe_colorize_sideband(&outbuf, b, linelen);
-                                       strbuf_addstr(&outbuf, suffix);
-                               }
-
-                               strbuf_addch(&outbuf, *brk);
-                               xwrite(2, outbuf.buf, outbuf.len);
-                               strbuf_reset(&outbuf);
-
-                               b = brk + 1;
-                       }
+       static const char *suffix;
+       const char *b, *brk;
+       int band;
+
+       if (!suffix) {
+               if (isatty(2) && !is_terminal_dumb())
+                       suffix = ANSI_SUFFIX;
+               else
+                       suffix = DUMB_SUFFIX;
+       }
 
-                       if (*b) {
-                               strbuf_addstr(&outbuf, outbuf.len ?
-                                           "" : DISPLAY_PREFIX);
-                               maybe_colorize_sideband(&outbuf, b, strlen(b));
+       if (len == 0) {
+               *sideband_type = SIDEBAND_FLUSH;
+               goto cleanup;
+       }
+       if (len < 1) {
+               strbuf_addf(scratch,
+                           "%s%s: protocol error: no band designator",
+                           scratch->len ? "\n" : "", me);
+               *sideband_type = SIDEBAND_PROTOCOL_ERROR;
+               goto cleanup;
+       }
+       band = buf[0] & 0xff;
+       buf[len] = '\0';
+       len--;
+       switch (band) {
+       case 3:
+               if (die_on_error)
+                       die("remote error: %s", buf + 1);
+               strbuf_addf(scratch, "%s%s", scratch->len ? "\n" : "",
+                           DISPLAY_PREFIX);
+               maybe_colorize_sideband(scratch, buf + 1, len);
+
+               *sideband_type = SIDEBAND_REMOTE_ERROR;
+               break;
+       case 2:
+               b = buf + 1;
+
+               /*
+                * Append a suffix to each nonempty line to clear the
+                * end of the screen line.
+                *
+                * The output is accumulated in a buffer and
+                * each line is printed to stderr using
+                * write(2) to ensure inter-process atomicity.
+                */
+               while ((brk = strpbrk(b, "\n\r"))) {
+                       int linelen = brk - b;
+
+                       if (!scratch->len)
+                               strbuf_addstr(scratch, DISPLAY_PREFIX);
+                       if (linelen > 0) {
+                               maybe_colorize_sideband(scratch, b, linelen);
+                               strbuf_addstr(scratch, suffix);
                        }
-                       break;
-               case 1:
-                       write_or_die(out, buf + 1, len);
-                       break;
-               default:
-                       strbuf_addf(&outbuf, "%s%s: protocol error: bad band #%d",
-                                   outbuf.len ? "\n" : "", me, band);
-                       retval = SIDEBAND_PROTOCOL_ERROR;
-                       break;
+
+                       strbuf_addch(scratch, *brk);
+                       xwrite(2, scratch->buf, scratch->len);
+                       strbuf_reset(scratch);
+
+                       b = brk + 1;
+               }
+
+               if (*b) {
+                       strbuf_addstr(scratch, scratch->len ?
+                                   "" : DISPLAY_PREFIX);
+                       maybe_colorize_sideband(scratch, b, strlen(b));
                }
+               return 0;
+       case 1:
+               *sideband_type = SIDEBAND_PRIMARY;
+               break;
+       default:
+               strbuf_addf(scratch, "%s%s: protocol error: bad band #%d",
+                           scratch->len ? "\n" : "", me, band);
+               *sideband_type = SIDEBAND_PROTOCOL_ERROR;
+               break;
        }
 
-       if (outbuf.len) {
-               strbuf_addch(&outbuf, '\n');
-               xwrite(2, outbuf.buf, outbuf.len);
+cleanup:
+       if (die_on_error && *sideband_type == SIDEBAND_PROTOCOL_ERROR)
+               die("%s", scratch->buf);
+       if (scratch->len) {
+               strbuf_addch(scratch, '\n');
+               xwrite(2, scratch->buf, scratch->len);
        }
-       strbuf_release(&outbuf);
-       return retval;
+       strbuf_release(scratch);
+       return 1;
 }
 
 /*
index 7a8146f161b7b460d29baea82230c0b6c11c5322..227740a58e58bd25c4625bc1963106542bd99779 100644 (file)
@@ -1,10 +1,29 @@
 #ifndef SIDEBAND_H
 #define SIDEBAND_H
 
-#define SIDEBAND_PROTOCOL_ERROR -2
-#define SIDEBAND_REMOTE_ERROR -1
+enum sideband_type {
+       SIDEBAND_PROTOCOL_ERROR = -2,
+       SIDEBAND_REMOTE_ERROR = -1,
+       SIDEBAND_FLUSH = 0,
+       SIDEBAND_PRIMARY = 1
+};
+
+/*
+ * Inspects a multiplexed packet read from the remote. If this packet is a
+ * progress packet and thus should not be processed by the caller, returns 0.
+ * Otherwise, returns 1, releases scratch, and sets sideband_type.
+ *
+ * If this packet is SIDEBAND_PROTOCOL_ERROR, SIDEBAND_REMOTE_ERROR, or a
+ * progress packet, also prints a message to stderr.
+ *
+ * scratch must be a struct strbuf allocated by the caller. It is used to store
+ * progress messages split across multiple packets.
+ */
+int demultiplex_sideband(const char *me, char *buf, int len,
+                        int die_on_error,
+                        struct strbuf *scratch,
+                        enum sideband_type *sideband_type);
 
-int recv_sideband(const char *me, int in_stream, int out);
 void send_sideband(int fd, int band, const char *data, ssize_t sz, int packet_max);
 
 #endif
index ac7c7a22f90b7320a235f23db9387fd91ba5b2cd..fcd63032192ff4056946ce3a0a266c7fb021353b 100644 (file)
@@ -338,16 +338,16 @@ static struct stream_vtbl loose_vtbl = {
 
 static open_method_decl(loose)
 {
-       st->u.loose.mapped = map_sha1_file(the_repository,
-                                          oid->hash, &st->u.loose.mapsize);
+       st->u.loose.mapped = map_loose_object(the_repository,
+                                             oid, &st->u.loose.mapsize);
        if (!st->u.loose.mapped)
                return -1;
-       if ((unpack_sha1_header(&st->z,
-                               st->u.loose.mapped,
-                               st->u.loose.mapsize,
-                               st->u.loose.hdr,
-                               sizeof(st->u.loose.hdr)) < 0) ||
-           (parse_sha1_header(st->u.loose.hdr, &st->size) < 0)) {
+       if ((unpack_loose_header(&st->z,
+                                st->u.loose.mapped,
+                                st->u.loose.mapsize,
+                                st->u.loose.hdr,
+                                sizeof(st->u.loose.hdr)) < 0) ||
+           (parse_loose_header(st->u.loose.hdr, &st->size) < 0)) {
                git_inflate_end(&st->z);
                munmap(st->u.loose.mapped, st->u.loose.mapsize);
                return -1;
@@ -499,7 +499,7 @@ static struct stream_vtbl incore_vtbl = {
 
 static open_method_decl(incore)
 {
-       st->u.incore.buf = read_object_file_extended(oid, type, &st->size, 0);
+       st->u.incore.buf = read_object_file_extended(the_repository, oid, type, &st->size, 0);
        st->u.incore.read_ptr = 0;
        st->vtbl = &incore_vtbl;
 
index 7b5cea8522edb9a2b12b46a7ba2055345b64da88..934ecfa2943bcb5ee87e7ac431b5332a5f3adcde 100644 (file)
@@ -1,4 +1,3 @@
-#define NO_THE_INDEX_COMPATIBILITY_MACROS
 
 #include "cache.h"
 #include "repository.h"
@@ -456,7 +455,7 @@ static int prepare_submodule_summary(struct rev_info *rev, const char *path,
        return prepare_revision_walk(rev);
 }
 
-static void print_submodule_summary(struct rev_info *rev, struct diff_options *o)
+static void print_submodule_summary(struct repository *r, struct rev_info *rev, struct diff_options *o)
 {
        static const char format[] = "  %m %s";
        struct strbuf sb = STRBUF_INIT;
@@ -467,7 +466,8 @@ static void print_submodule_summary(struct rev_info *rev, struct diff_options *o
                ctx.date_mode = rev->date_mode;
                ctx.output_encoding = get_log_output_encoding();
                strbuf_setlen(&sb, 0);
-               format_commit_message(commit, format, &sb, &ctx);
+               repo_format_commit_message(r, commit, format, &sb,
+                                     &ctx);
                strbuf_addch(&sb, '\n');
                if (commit->object.flags & SYMMETRIC_LEFT)
                        diff_emit_submodule_del(o, sb.buf);
@@ -500,14 +500,46 @@ static void prepare_submodule_repo_env_in_gitdir(struct argv_array *out)
        argv_array_pushf(out, "%s=.", GIT_DIR_ENVIRONMENT);
 }
 
-/* Helper function to display the submodule header line prior to the full
- * summary output. If it can locate the submodule objects directory it will
- * attempt to lookup both the left and right commits and put them into the
- * left and right pointers.
+/*
+ * Initialize a repository struct for a submodule based on the provided 'path'.
+ *
+ * Unlike repo_submodule_init, this tolerates submodules not present
+ * in .gitmodules. This function exists only to preserve historical behavior,
+ *
+ * Returns the repository struct on success,
+ * NULL when the submodule is not present.
+ */
+static struct repository *open_submodule(const char *path)
+{
+       struct strbuf sb = STRBUF_INIT;
+       struct repository *out = xmalloc(sizeof(*out));
+
+       if (submodule_to_gitdir(&sb, path) || repo_init(out, sb.buf, NULL)) {
+               strbuf_release(&sb);
+               free(out);
+               return NULL;
+       }
+
+       /* Mark it as a submodule */
+       out->submodule_prefix = xstrdup(path);
+
+       strbuf_release(&sb);
+       return out;
+}
+
+/*
+ * Helper function to display the submodule header line prior to the full
+ * summary output.
+ *
+ * If it can locate the submodule git directory it will create a repository
+ * handle for the submodule and lookup both the left and right commits and
+ * put them into the left and right pointers.
  */
-static void show_submodule_header(struct diff_options *o, const char *path,
+static void show_submodule_header(struct diff_options *o,
+               const char *path,
                struct object_id *one, struct object_id *two,
                unsigned dirty_submodule,
+               struct repository *sub,
                struct commit **left, struct commit **right,
                struct commit_list **merge_bases)
 {
@@ -526,7 +558,7 @@ static void show_submodule_header(struct diff_options *o, const char *path,
        else if (is_null_oid(two))
                message = "(submodule deleted)";
 
-       if (add_submodule_odb(path)) {
+       if (!sub) {
                if (!message)
                        message = "(commits not present)";
                goto output_header;
@@ -536,8 +568,8 @@ static void show_submodule_header(struct diff_options *o, const char *path,
         * Attempt to lookup the commit references, and determine if this is
         * a fast forward or fast backwards update.
         */
-       *left = lookup_commit_reference(the_repository, one);
-       *right = lookup_commit_reference(the_repository, two);
+       *left = lookup_commit_reference(sub, one);
+       *right = lookup_commit_reference(sub, two);
 
        /*
         * Warn about missing commits in the submodule project, but only if
@@ -547,7 +579,7 @@ static void show_submodule_header(struct diff_options *o, const char *path,
             (!is_null_oid(two) && !*right))
                message = "(commits not present)";
 
-       *merge_bases = get_merge_bases(*left, *right);
+       *merge_bases = repo_get_merge_bases(sub, *left, *right);
        if (*merge_bases) {
                if ((*merge_bases)->item == *left)
                        fast_forward = 1;
@@ -581,16 +613,18 @@ void show_submodule_summary(struct diff_options *o, const char *path,
        struct rev_info rev;
        struct commit *left = NULL, *right = NULL;
        struct commit_list *merge_bases = NULL;
+       struct repository *sub;
 
+       sub = open_submodule(path);
        show_submodule_header(o, path, one, two, dirty_submodule,
-                             &left, &right, &merge_bases);
+                             sub, &left, &right, &merge_bases);
 
        /*
         * If we don't have both a left and a right pointer, there is no
         * reason to try and display a summary. The header line should contain
         * all the information the user needs.
         */
-       if (!left || !right)
+       if (!left || !right || !sub)
                goto out;
 
        /* Treat revision walker failure the same as missing commits */
@@ -599,13 +633,17 @@ void show_submodule_summary(struct diff_options *o, const char *path,
                goto out;
        }
 
-       print_submodule_summary(&rev, o);
+       print_submodule_summary(sub, &rev, o);
 
 out:
        if (merge_bases)
                free_commit_list(merge_bases);
        clear_commit_marks(left, ~0);
        clear_commit_marks(right, ~0);
+       if (sub) {
+               repo_clear(sub);
+               free(sub);
+       }
 }
 
 void show_submodule_inline_diff(struct diff_options *o, const char *path,
@@ -617,9 +655,11 @@ void show_submodule_inline_diff(struct diff_options *o, const char *path,
        struct commit_list *merge_bases = NULL;
        struct child_process cp = CHILD_PROCESS_INIT;
        struct strbuf sb = STRBUF_INIT;
+       struct repository *sub;
 
+       sub = open_submodule(path);
        show_submodule_header(o, path, one, two, dirty_submodule,
-                             &left, &right, &merge_bases);
+                             sub, &left, &right, &merge_bases);
 
        /* We need a valid left and right commit to display a difference */
        if (!(left || is_null_oid(one)) ||
@@ -680,6 +720,10 @@ void show_submodule_inline_diff(struct diff_options *o, const char *path,
                clear_commit_marks(left, ~0);
        if (right)
                clear_commit_marks(right, ~0);
+       if (sub) {
+               repo_clear(sub);
+               free(sub);
+       }
 }
 
 int should_update_submodules(void)
@@ -1004,9 +1048,6 @@ static int push_submodule(const char *path,
                          const struct string_list *push_options,
                          int dry_run)
 {
-       if (add_submodule_odb(path))
-               return 1;
-
        if (for_each_remote_ref_submodule(path, has_remote, NULL) > 0) {
                struct child_process cp = CHILD_PROCESS_INIT;
                argv_array_push(&cp.args, "push");
index 348715f0e4bcfebf9df680fda5b9c4be4f3e7527..91cf5772fe5643dbe075da98ed5166e1899b9a54 100644 (file)
@@ -2,3 +2,4 @@
 /test-results
 /.prove
 /chainlinttmp
+/out/
index 11ce7675e32e7042f0ae5ddee1b65a0f6516f175..1326fd7505fde3a9e34fef1e197623c8d409d6ff 100644 (file)
--- a/t/README
+++ b/t/README
@@ -170,6 +170,15 @@ appropriately before running "make".
        implied by other options like --valgrind and
        GIT_TEST_INSTALLED.
 
+--no-bin-wrappers::
+       By default, the test suite uses the wrappers in
+       `../bin-wrappers/` to execute `git` and friends. With this option,
+       `../git` and friends are run directly. This is not recommended
+       in general, as the wrappers contain safeguards to ensure that no
+       files from an installed Git are used, but can speed up test runs
+       especially on platforms where running shell scripts is expensive
+       (most notably, Windows).
+
 --root=<directory>::
        Create "trash" directories used to store all temporary data during
        testing under <directory>, instead of the t/ directory.
@@ -358,6 +367,10 @@ GIT_TEST_INDEX_VERSION=<n> exercises the index read/write code path
 for the index version specified.  Can be set to any valid version
 (currently 2, 3, or 4).
 
+GIT_TEST_PACK_SPARSE=<boolean> if enabled will default the pack-objects
+builtin to use the sparse object walk. This can still be overridden by
+the --no-sparse command-line argument.
+
 GIT_TEST_PRELOAD_INDEX=<boolean> exercises the preload-index code path
 by overriding the minimum number of cache entries required per thread.
 
@@ -374,6 +387,11 @@ GIT_TEST_MULTI_PACK_INDEX=<boolean>, when true, forces the multi-pack-
 index to be written after every 'git repack' command, and overrides the
 'core.multiPackIndex' setting to true.
 
+GIT_TEST_SIDEBAND_ALL=<boolean>, when true, overrides the
+'uploadpack.allowSidebandAll' setting to true, and when false, forces
+fetch-pack to not request sideband-all (even if the server advertises
+sideband-all).
+
 Naming Tests
 ------------
 
index 8037eef7777b4f65af44b3c8cc3e4b46d48259ae..166d64d4a2f05e76f3966080f188b864bf6bf4bb 100755 (executable)
@@ -36,7 +36,7 @@ sub err {
        }
 
        /\bcp\s+-a/ and err 'cp -a is not portable';
-       /\bsed\s+-i/ and err 'sed -i is not portable';
+       /\bsed\s+-[^efn]\s+/ and err 'sed option not portable (use only -n, -e, -f)';
        /\becho\s+-[neE]/ and err 'echo with option is not portable (use printf)';
        /^\s*declare\s+/ and err 'arrays/declare not portable';
        /^\s*[^#]\s*which\s/ and err 'which is not portable (use type)';
index a0837371aba17956331ddcdb04847c6c9edeefd2..b3253803ac8ce66625e346fcbce3ca9c9a16ae55 100644 (file)
@@ -3,10 +3,12 @@
 
 static const char *usage_msg = "\n"
 "  test-tool date relative [time_t]...\n"
+"  test-tool date human [time_t]...\n"
 "  test-tool date show:<format> [time_t]...\n"
 "  test-tool date parse [date]...\n"
 "  test-tool date approxidate [date]...\n"
 "  test-tool date timestamp [date]...\n"
+"  test-tool date getnanos [start-nanos]\n"
 "  test-tool date is64bit\n"
 "  test-tool date time_t-is64bit\n";
 
@@ -16,12 +18,20 @@ static void show_relative_dates(const char **argv, struct timeval *now)
 
        for (; *argv; argv++) {
                time_t t = atoi(*argv);
-               show_date_relative(t, 0, now, &buf);
+               show_date_relative(t, now, &buf);
                printf("%s -> %s\n", *argv, buf.buf);
        }
        strbuf_release(&buf);
 }
 
+static void show_human_dates(const char **argv)
+{
+       for (; *argv; argv++) {
+               time_t t = atoi(*argv);
+               printf("%s -> %s\n", *argv, show_date(t, 0, DATE_MODE(HUMAN)));
+       }
+}
+
 static void show_dates(const char **argv, const char *format)
 {
        struct date_mode mode;
@@ -82,12 +92,21 @@ static void parse_approx_timestamp(const char **argv, struct timeval *now)
        }
 }
 
+static void getnanos(const char **argv)
+{
+       double seconds = getnanotime() / 1.0e9;
+
+       if (*argv)
+               seconds -= strtod(*argv, NULL);
+       printf("%lf\n", seconds);
+}
+
 int cmd__date(int argc, const char **argv)
 {
        struct timeval now;
        const char *x;
 
-       x = getenv("TEST_DATE_NOW");
+       x = getenv("GIT_TEST_DATE_NOW");
        if (x) {
                now.tv_sec = atoi(x);
                now.tv_usec = 0;
@@ -100,6 +119,8 @@ int cmd__date(int argc, const char **argv)
                usage(usage_msg);
        if (!strcmp(*argv, "relative"))
                show_relative_dates(argv+1, &now);
+       else if (!strcmp(*argv, "human"))
+               show_human_dates(argv+1);
        else if (skip_prefix(*argv, "show:", &x))
                show_dates(argv+1, x);
        else if (!strcmp(*argv, "parse"))
@@ -108,6 +129,8 @@ int cmd__date(int argc, const char **argv)
                parse_approxidate(argv+1, &now);
        else if (!strcmp(*argv, "timestamp"))
                parse_approx_timestamp(argv+1, &now);
+       else if (!strcmp(*argv, "getnanos"))
+               getnanos(argv+1);
        else if (!strcmp(*argv, "is64bit"))
                return sizeof(timestamp_t) == 8 ? 0 : 1;
        else if (!strcmp(*argv, "time_t-is64bit"))
index 08e3684aff223670fb0786d80426d18bb8800a44..2786f47088e975608c839f193527e1e70e84cee9 100644 (file)
@@ -3,11 +3,11 @@
 
 int cmd__dump_fsmonitor(int ac, const char **av)
 {
-       struct index_state *istate = &the_index;
+       struct index_state *istate = the_repository->index;
        int i;
 
        setup_git_directory();
-       if (do_read_index(istate, get_index_file(), 0) < 0)
+       if (do_read_index(istate, the_repository->index_file, 0) < 0)
                die("unable to read index file");
        if (!istate->fsmonitor_last_update) {
                printf("no fsmonitor\n");
index 52870ebbb3ea7b2d69aecb1bb429dbbaf6388b51..cf0f2c7228e8293c5982168f21b004bc7daa2ff0 100644 (file)
@@ -1,3 +1,4 @@
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "test-tool.h"
 #include "cache.h"
 #include "dir.h"
index ae091d9b3e63cb506b2530217d40048b301faaa3..5d543ad21f89c76534e8efe32d6ead512dc7d0c3 100644 (file)
@@ -177,6 +177,14 @@ static int is_dotgitmodules(const char *path)
        return is_hfs_dotgitmodules(path) || is_ntfs_dotgitmodules(path);
 }
 
+static int cmp_by_st_size(const void *a, const void *b)
+{
+       intptr_t x = (intptr_t)((struct string_list_item *)a)->util;
+       intptr_t y = (intptr_t)((struct string_list_item *)b)->util;
+
+       return x > y ? -1 : (x < y ? +1 : 0);
+}
+
 int cmd__path_utils(int argc, const char **argv)
 {
        if (argc == 3 && !strcmp(argv[1], "normalize_path_copy")) {
@@ -291,6 +299,62 @@ int cmd__path_utils(int argc, const char **argv)
                return !!res;
        }
 
+       if (argc > 2 && !strcmp(argv[1], "file-size")) {
+               int res = 0, i;
+               struct stat st;
+
+               for (i = 2; i < argc; i++)
+                       if (stat(argv[i], &st))
+                               res = error_errno("Cannot stat '%s'", argv[i]);
+                       else
+                               printf("%"PRIuMAX"\n", (uintmax_t)st.st_size);
+               return !!res;
+       }
+
+       if (argc == 4 && !strcmp(argv[1], "skip-n-bytes")) {
+               int fd = open(argv[2], O_RDONLY), offset = atoi(argv[3]);
+               char buffer[65536];
+
+               if (fd < 0)
+                       die_errno("could not open '%s'", argv[2]);
+               if (lseek(fd, offset, SEEK_SET) < 0)
+                       die_errno("could not skip %d bytes", offset);
+               for (;;) {
+                       ssize_t count = read(fd, buffer, sizeof(buffer));
+                       if (count < 0)
+                               die_errno("could not read '%s'", argv[2]);
+                       if (!count)
+                               break;
+                       if (write(1, buffer, count) < 0)
+                               die_errno("could not write to stdout");
+               }
+               close(fd);
+               return 0;
+       }
+
+       if (argc > 5 && !strcmp(argv[1], "slice-tests")) {
+               int res = 0;
+               long offset, stride, i;
+               struct string_list list = STRING_LIST_INIT_NODUP;
+               struct stat st;
+
+               offset = strtol(argv[2], NULL, 10);
+               stride = strtol(argv[3], NULL, 10);
+               if (stride < 1)
+                       stride = 1;
+               for (i = 4; i < argc; i++)
+                       if (stat(argv[i], &st))
+                               res = error_errno("Cannot stat '%s'", argv[i]);
+                       else
+                               string_list_append(&list, argv[i])->util =
+                                       (void *)(intptr_t)st.st_size;
+               QSORT(list.items, list.nr, cmp_by_st_size);
+               for (i = offset; i < list.nr; i+= stride)
+                       printf("%s\n", list.items[i].string);
+
+               return !!res;
+       }
+
        fprintf(stderr, "%s: unknown function name: %s\n", argv[0],
                argv[1] ? argv[1] : "(there was none)");
        return 1;
index e9e0541276c50d1739b6d39f2c01ba8ecb782adc..799fc00aa15b1e4cfe9fe8a6d32ebc2063003cb4 100644 (file)
@@ -233,7 +233,7 @@ static int cmd_update_ref(struct ref_store *refs, const char **argv)
 {
        const char *msg = notnull(*argv++, "msg");
        const char *refname = notnull(*argv++, "refname");
-       const char *new_sha1_buf = notnull(*argv++, "old-sha1");
+       const char *new_sha1_buf = notnull(*argv++, "new-sha1");
        const char *old_sha1_buf = notnull(*argv++, "old-sha1");
        unsigned int flags = arg_flags(*argv++, "flags");
        struct object_id old_oid;
index 6a84a53efbf6919c83d3f1fd73786acd92ee7abf..f7f861844560e0578eda989e39c4bd0572dcd5d6 100644 (file)
@@ -17,6 +17,11 @@ static void test_parse_commit_in_graph(const char *gitdir, const char *worktree,
 
        setup_git_env(gitdir);
 
+       memset(the_repository, 0, sizeof(*the_repository));
+
+       /* TODO: Needed for temporary hack in hashcmp, see 183a638b7da. */
+       repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
+
        if (repo_init(&r, gitdir, worktree))
                die("Couldn't init repo");
 
@@ -43,6 +48,11 @@ static void test_get_commit_tree_in_graph(const char *gitdir,
 
        setup_git_env(gitdir);
 
+       memset(the_repository, 0, sizeof(*the_repository));
+
+       /* TODO: Needed for temporary hack in hashcmp, see 183a638b7da. */
+       repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
+
        if (repo_init(&r, gitdir, worktree))
                die("Couldn't init repo");
 
index 5b137874e1d21166c92d00f540f6ecd68c18780a..50c55f8b1a3baf2df88214824b01fb707966ebc7 100644 (file)
@@ -51,6 +51,7 @@ static struct test_cmd cmds[] = {
        { "submodule-nested-repo-config", cmd__submodule_nested_repo_config },
        { "subprocess", cmd__subprocess },
        { "urlmatch-normalization", cmd__urlmatch_normalization },
+       { "xml-encode", cmd__xml_encode },
        { "wildmatch", cmd__wildmatch },
 #ifdef GIT_WINDOWS_NATIVE
        { "windows-named-pipe", cmd__windows_named_pipe },
index ca5c88edb2ac8ae99090ec21e6b3d636bc03e96c..a563df49bf086b92eb24b3f90f6194eed059de81 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef TEST_TOOL_H
 #define TEST_TOOL_H
 
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "git-compat-util.h"
 
 int cmd__chmtime(int argc, const char **argv);
@@ -47,6 +48,7 @@ int cmd__submodule_config(int argc, const char **argv);
 int cmd__submodule_nested_repo_config(int argc, const char **argv);
 int cmd__subprocess(int argc, const char **argv);
 int cmd__urlmatch_normalization(int argc, const char **argv);
+int cmd__xml_encode(int argc, const char **argv);
 int cmd__wildmatch(int argc, const char **argv);
 #ifdef GIT_WINDOWS_NATIVE
 int cmd__windows_named_pipe(int argc, const char **argv);
diff --git a/t/helper/test-xml-encode.c b/t/helper/test-xml-encode.c
new file mode 100644 (file)
index 0000000..a648bbd
--- /dev/null
@@ -0,0 +1,80 @@
+#include "test-tool.h"
+
+static const char *utf8_replace_character = "&#xfffd;";
+
+/*
+ * Encodes (possibly incorrect) UTF-8 on <stdin> to <stdout>, to be embedded
+ * in an XML file.
+ */
+int cmd__xml_encode(int argc, const char **argv)
+{
+       unsigned char buf[1024], tmp[4], *tmp2 = NULL;
+       ssize_t cur = 0, len = 1, remaining = 0;
+       unsigned char ch;
+
+       for (;;) {
+               if (++cur == len) {
+                       len = xread(0, buf, sizeof(buf));
+                       if (!len)
+                               return 0;
+                       if (len < 0)
+                               die_errno("Could not read <stdin>");
+                       cur = 0;
+               }
+               ch = buf[cur];
+
+               if (tmp2) {
+                       if ((ch & 0xc0) != 0x80) {
+                               fputs(utf8_replace_character, stdout);
+                               tmp2 = NULL;
+                               cur--;
+                               continue;
+                       }
+                       *tmp2 = ch;
+                       tmp2++;
+                       if (--remaining == 0) {
+                               fwrite(tmp, tmp2 - tmp, 1, stdout);
+                               tmp2 = NULL;
+                       }
+                       continue;
+               }
+
+               if (!(ch & 0x80)) {
+                       /* 0xxxxxxx */
+                       if (ch == '&')
+                               fputs("&amp;", stdout);
+                       else if (ch == '\'')
+                               fputs("&apos;", stdout);
+                       else if (ch == '"')
+                               fputs("&quot;", stdout);
+                       else if (ch == '<')
+                               fputs("&lt;", stdout);
+                       else if (ch == '>')
+                               fputs("&gt;", stdout);
+                       else if (ch >= 0x20)
+                               fputc(ch, stdout);
+                       else if (ch == 0x09 || ch == 0x0a || ch == 0x0d)
+                               fprintf(stdout, "&#x%02x;", ch);
+                       else
+                               fputs(utf8_replace_character, stdout);
+               } else if ((ch & 0xe0) == 0xc0) {
+                       /* 110XXXXx 10xxxxxx */
+                       tmp[0] = ch;
+                       remaining = 1;
+                       tmp2 = tmp + 1;
+               } else if ((ch & 0xf0) == 0xe0) {
+                       /* 1110XXXX 10Xxxxxx 10xxxxxx */
+                       tmp[0] = ch;
+                       remaining = 2;
+                       tmp2 = tmp + 1;
+               } else if ((ch & 0xf8) == 0xf0) {
+                       /* 11110XXX 10XXxxxx 10xxxxxx 10xxxxxx */
+                       tmp[0] = ch;
+                       remaining = 3;
+                       tmp2 = tmp + 1;
+               } else
+                       fputs(utf8_replace_character, stdout);
+       }
+
+       return 0;
+}
index cc4b87507e7e8c45725d600c550c4ce200bf7c0d..5d63ed90c51cf215dd24bf634f47413c2fa27368 100644 (file)
@@ -78,6 +78,7 @@ PassEnv GNUPGHOME
 PassEnv ASAN_OPTIONS
 PassEnv GIT_TRACE
 PassEnv GIT_CONFIG_NOSYSTEM
+PassEnv GIT_TEST_SIDEBAND_ALL
 
 SetEnvIf Git-Protocol ".*" GIT_PROTOCOL=$0
 
index 22499bce5f50637e574961f744b567b974a4d3d0..71e63d8b509d34fa4b860bac9ba1531e674799d7 100755 (executable)
@@ -322,4 +322,24 @@ test_expect_success 'bare repository: test info/attributes' '
        )
 '
 
+test_expect_success 'binary macro expanded by -a' '
+       echo "file binary" >.gitattributes &&
+       cat >expect <<-\EOF &&
+       file: binary: set
+       file: diff: unset
+       file: merge: unset
+       file: text: unset
+       EOF
+       git check-attr -a file >actual &&
+       test_cmp expect actual
+'
+
+
+test_expect_success 'query binary macro directly' '
+       echo "file binary" >.gitattributes &&
+       echo file: binary: set >expect &&
+       git check-attr binary file >actual &&
+       test_cmp expect actual
+'
+
 test_done
index ffb2975e4875287bd510503a3becfd90fd7d325b..d9fcc829a9e6cb10088e6503841928cf85d1d697 100755 (executable)
@@ -4,10 +4,10 @@ test_description='test date parsing and printing'
 . ./test-lib.sh
 
 # arbitrary reference time: 2009-08-30 19:20:00
-TEST_DATE_NOW=1251660000; export TEST_DATE_NOW
+GIT_TEST_DATE_NOW=1251660000; export GIT_TEST_DATE_NOW
 
 check_relative() {
-       t=$(($TEST_DATE_NOW - $1))
+       t=$(($GIT_TEST_DATE_NOW - $1))
        echo "$t -> $2" >expect
        test_expect_${3:-success} "relative date ($2)" "
        test-tool date relative $t >actual &&
@@ -128,4 +128,22 @@ check_approxidate '6AM, June 7, 2009' '2009-06-07 06:00:00'
 check_approxidate '2008-12-01' '2008-12-01 19:20:00'
 check_approxidate '2009-12-01' '2009-12-01 19:20:00'
 
+check_date_format_human() {
+       t=$(($GIT_TEST_DATE_NOW - $1))
+       echo "$t -> $2" >expect
+       test_expect_success "human date $t" '
+               test-tool date human $t >actual &&
+               test_i18ncmp expect actual
+'
+}
+
+check_date_format_human 18000 "5 hours ago" # 5 hours ago
+check_date_format_human 432000 "Tue Aug 25 19:20" # 5 days ago
+check_date_format_human 1728000 "Mon Aug 10 19:20" # 3 weeks ago
+check_date_format_human 13000000 "Thu Apr 2 08:13" # 5 months ago
+check_date_format_human 31449600 "Aug 31 2008" # 12 months ago
+check_date_format_human 37500000 "Jun 22 2008" # 1 year, 2 months ago
+check_date_format_human 55188000 "Dec 1 2007" # 1 year, 9 months ago
+check_date_format_human 630000000 "Sep 13 1989" # 20 years ago
+
 test_done
index fd5f1ac649dc411bf3c70dcb54f7965e4006aca8..e10f5f787fca8b3f7789bcf9043d7c81929f070e 100755 (executable)
@@ -24,7 +24,7 @@ generate_random_characters () {
 }
 
 file_size () {
-       perl -e 'print -s $ARGV[0]' "$1"
+       test-tool path-utils file-size "$1"
 }
 
 filter_git () {
index 9d9e02a21112197a2a57a2877db24951d41a2996..e13363ade5cf500e6f57677eb961c5ca01197a12 100755 (executable)
@@ -27,4 +27,13 @@ test_expect_success 'renormalize CRLF in repo' '
        test_cmp expect actual
 '
 
+test_expect_success 'ignore-errors not mistaken for renormalize' '
+       git reset --hard &&
+       echo "*.txt text=auto" >.gitattributes &&
+       git ls-files --eol >expect &&
+       git add --ignore-errors "*.txt" &&
+       git ls-files --eol >actual &&
+       test_cmp expect actual
+'
+
 test_done
index 7e87b5a200a3f6483ea2e243fa0c497205ce4e61..e58ecbfc44037fa1d38707b30545e803e1401b4f 100755 (executable)
@@ -11,9 +11,12 @@ test_expect_success 'setup test files' '
 
        text="hallo there!\ncan you read me?" &&
        echo "*.utf16 text working-tree-encoding=utf-16" >.gitattributes &&
+       echo "*.utf16lebom text working-tree-encoding=UTF-16LE-BOM" >>.gitattributes &&
        printf "$text" >test.utf8.raw &&
        printf "$text" | iconv -f UTF-8 -t UTF-16 >test.utf16.raw &&
        printf "$text" | iconv -f UTF-8 -t UTF-32 >test.utf32.raw &&
+       printf "\377\376"                         >test.utf16lebom.raw &&
+       printf "$text" | iconv -f UTF-8 -t UTF-32LE >>test.utf16lebom.raw &&
 
        # Line ending tests
        printf "one\ntwo\nthree\n" >lf.utf8.raw &&
@@ -32,7 +35,8 @@ test_expect_success 'setup test files' '
        # Add only UTF-16 file, we will add the UTF-32 file later
        cp test.utf16.raw test.utf16 &&
        cp test.utf32.raw test.utf32 &&
-       git add .gitattributes test.utf16 &&
+       cp test.utf16lebom.raw test.utf16lebom &&
+       git add .gitattributes test.utf16 test.utf16lebom &&
        git commit -m initial
 '
 
@@ -51,6 +55,12 @@ test_expect_success 're-encode to UTF-16 on checkout' '
        test_cmp_bin test.utf16.raw test.utf16
 '
 
+test_expect_success 're-encode to UTF-16-LE-BOM on checkout' '
+       rm test.utf16lebom &&
+       git checkout test.utf16lebom &&
+       test_cmp_bin test.utf16lebom.raw test.utf16lebom
+'
+
 test_expect_success 'check $GIT_DIR/info/attributes support' '
        test_when_finished "rm -f test.utf32.git" &&
        test_when_finished "git reset --hard HEAD" &&
index 99a614bc7c45ca792c7bbce7d16f793ab6107896..ebc49561acc08e916b2ab78cd84e6729c65f5803 100755 (executable)
@@ -166,7 +166,8 @@ test_trace () {
        expect="$1"
        shift
        GIT_TRACE=1 test-tool run-command "$@" run-command true 2>&1 >/dev/null | \
-               sed -e 's/.* run_command: //' -e '/trace: .*/d' >actual &&
+               sed -e 's/.* run_command: //' -e '/trace: .*/d' \
+                       -e '/RUNTIME_PREFIX requested/d' >actual &&
        echo "$expect true" >expect &&
        test_cmp expect actual
 }
@@ -199,4 +200,14 @@ test_expect_success 'GIT_TRACE with environment variables' '
        )
 '
 
+test_expect_success MINGW 'verify curlies are quoted properly' '
+       : force the rev-parse through the MSYS2 Bash &&
+       git -c alias.r="!git rev-parse" r -- a{b}c >actual &&
+       cat >expect <<-\EOF &&
+       --
+       a{b}c
+       EOF
+       test_cmp expect actual
+'
+
 test_done
index 1a9b21b2934b0a4fae7f74bb8c4da65d32218ca0..dcb4dbba673eb2eb6e13117babb6b75e8e59a49a 100755 (executable)
@@ -8,7 +8,7 @@ test_description='adding and checking out large blobs'
 # This should be moved to test-lib.sh together with the
 # copy in t0021 after both topics have graduated to 'master'.
 file_size () {
-       perl -e 'print -s $ARGV[0]' "$1"
+       test-tool path-utils file-size "$1"
 }
 
 test_expect_success setup '
index 2e5e979336c5c67bf59667bbf5e0183b632ea2da..c61f97214137f5fcf5a9d6b7dd98ea8162e9916d 100755 (executable)
@@ -406,7 +406,7 @@ test_expect_success 'rev-list --verify-objects with bad sha1' '
 
        test_might_fail git rev-list --verify-objects refs/heads/bogus >/dev/null 2>out &&
        cat out &&
-       test_i18ngrep -q "error: sha1 mismatch 63ffffffffffffffffffffffffffffffffffffff" out
+       test_i18ngrep -q "error: hash mismatch 63ffffffffffffffffffffffffffffffffffffff" out
 '
 
 test_expect_success 'force fsck to ignore double author' '
index e4d5b56014822ff760d3eab6d7c798f8d932ca45..c19fb500cb225273fce730c656fea00a3ada624d 100755 (executable)
@@ -388,4 +388,14 @@ test_expect_success C_LOCALE_OUTPUT 'ambiguous commits are printed by type first
        done
 '
 
+test_expect_success 'cat-file --batch and --batch-check show ambiguous' '
+       echo "0000 ambiguous" >expect &&
+       echo 0000 | git cat-file --batch-check >actual 2>err &&
+       test_cmp expect actual &&
+       test_i18ngrep hint: err &&
+       echo 0000 | git cat-file --batch >actual 2>err &&
+       test_cmp expect actual &&
+       test_i18ngrep hint: err
+'
+
 test_done
index 2131fb2a5682c50faf64e6066f03080702168b94..c5014ad9a63f2451f84db5076f902a0132d318c1 100755 (executable)
@@ -198,4 +198,13 @@ test_expect_success 'checkout -B to the current branch works' '
        test_dirty_mergeable
 '
 
+test_expect_success 'checkout -b after clone --no-checkout does a checkout of HEAD' '
+       git init src &&
+       test_commit -C src a &&
+       rev="$(git -C src rev-parse HEAD)" &&
+       git clone --no-checkout src dest &&
+       git -C dest checkout "$rev" -b branch &&
+       test_path_is_file dest/a.t
+'
+
 test_done
index 7a440e08d8257487ae2f47b159d11e37a5166df8..52fa41c707699692db1f387263774c93560e6663 100755 (executable)
@@ -147,6 +147,25 @@ test_expect_success 'rebase -i with the exec command checks tree cleanness' '
        git rebase --continue
 '
 
+test_expect_success 'rebase -x with empty command fails' '
+       test_when_finished "git rebase --abort ||:" &&
+       test_must_fail git rebase -x "" @ 2>actual &&
+       test_write_lines "error: empty exec command" >expected &&
+       test_i18ncmp expected actual &&
+       test_must_fail git rebase -x " " @ 2>actual &&
+       test_i18ncmp expected actual
+'
+
+LF='
+'
+test_expect_success 'rebase -x with newline in command fails' '
+       test_when_finished "git rebase --abort ||:" &&
+       test_must_fail git rebase -x "a${LF}b" @ 2>actual &&
+       test_write_lines "error: exec commands cannot contain newlines" \
+                        >expected &&
+       test_i18ncmp expected actual
+'
+
 test_expect_success 'rebase -i with exec of inexistent command' '
        git checkout master &&
        test_when_finished "git rebase --abort" &&
@@ -156,6 +175,11 @@ test_expect_success 'rebase -i with exec of inexistent command' '
        ! grep "Maybe git-rebase is broken" actual
 '
 
+test_expect_success 'implicit interactive rebase does not invoke sequence editor' '
+       test_when_finished "git rebase --abort ||:" &&
+       GIT_SEQUENCE_EDITOR="echo bad >" git rebase -x"echo one" @^
+'
+
 test_expect_success 'no changes are a nop' '
        git checkout branch2 &&
        set_fake_editor &&
index f64b130cb805bbca8475f3c262693fa0faa2cafe..b393e1e9fee88bb9b3df6ecc8544dfa370086e41 100755 (executable)
@@ -17,14 +17,9 @@ test_expect_success 'setup' '
        git tag start
 '
 
-cat >expect <<\EOF
-Already applied: 0001 A
-Already applied: 0002 B
-Committed: 0003 Z
-EOF
-
 test_expect_success 'rebase -m' '
        git rebase -m master >report &&
+       >expect &&
        sed -n -e "/^Already applied: /p" \
                -e "/^Committed: /p" report >actual &&
        test_cmp expect actual
index 4c7494cc8f77a3ff92373cb130974825c4418ada..2d1094e4831a88205133558d2ca6ac5ac07209d1 100755 (executable)
@@ -53,41 +53,6 @@ create_expected_success_interactive () {
        EOF
 }
 
-create_expected_success_merge () {
-       cat >expected <<-EOF
-       $(grep "^Created autostash: [0-9a-f][0-9a-f]*\$" actual)
-       HEAD is now at $(git rev-parse --short feature-branch) third commit
-       First, rewinding head to replay your work on top of it...
-       Merging unrelated-onto-branch with HEAD~1
-       Merging:
-       $(git rev-parse --short unrelated-onto-branch) unrelated commit
-       $(git rev-parse --short feature-branch^) second commit
-       found 1 common ancestor:
-       $(git rev-parse --short feature-branch~2) initial commit
-       [detached HEAD $(git rev-parse --short rebased-feature-branch~1)] second commit
-        Author: A U Thor <author@example.com>
-        Date: Thu Apr 7 15:14:13 2005 -0700
-        2 files changed, 2 insertions(+)
-        create mode 100644 file1
-        create mode 100644 file2
-       Committed: 0001 second commit
-       Merging unrelated-onto-branch with HEAD~0
-       Merging:
-       $(git rev-parse --short rebased-feature-branch~1) second commit
-       $(git rev-parse --short feature-branch) third commit
-       found 1 common ancestor:
-       $(git rev-parse --short feature-branch~1) second commit
-       [detached HEAD $(git rev-parse --short rebased-feature-branch)] third commit
-        Author: A U Thor <author@example.com>
-        Date: Thu Apr 7 15:15:13 2005 -0700
-        1 file changed, 1 insertion(+)
-        create mode 100644 file3
-       Committed: 0002 third commit
-       All done.
-       Applied autostash.
-       EOF
-}
-
 create_expected_failure_am () {
        cat >expected <<-EOF
        $(grep "^Created autostash: [0-9a-f][0-9a-f]*\$" actual)
@@ -112,43 +77,6 @@ create_expected_failure_interactive () {
        EOF
 }
 
-create_expected_failure_merge () {
-       cat >expected <<-EOF
-       $(grep "^Created autostash: [0-9a-f][0-9a-f]*\$" actual)
-       HEAD is now at $(git rev-parse --short feature-branch) third commit
-       First, rewinding head to replay your work on top of it...
-       Merging unrelated-onto-branch with HEAD~1
-       Merging:
-       $(git rev-parse --short unrelated-onto-branch) unrelated commit
-       $(git rev-parse --short feature-branch^) second commit
-       found 1 common ancestor:
-       $(git rev-parse --short feature-branch~2) initial commit
-       [detached HEAD $(git rev-parse --short rebased-feature-branch~1)] second commit
-        Author: A U Thor <author@example.com>
-        Date: Thu Apr 7 15:14:13 2005 -0700
-        2 files changed, 2 insertions(+)
-        create mode 100644 file1
-        create mode 100644 file2
-       Committed: 0001 second commit
-       Merging unrelated-onto-branch with HEAD~0
-       Merging:
-       $(git rev-parse --short rebased-feature-branch~1) second commit
-       $(git rev-parse --short feature-branch) third commit
-       found 1 common ancestor:
-       $(git rev-parse --short feature-branch~1) second commit
-       [detached HEAD $(git rev-parse --short rebased-feature-branch)] third commit
-        Author: A U Thor <author@example.com>
-        Date: Thu Apr 7 15:15:13 2005 -0700
-        1 file changed, 1 insertion(+)
-        create mode 100644 file3
-       Committed: 0002 third commit
-       All done.
-       Applying autostash resulted in conflicts.
-       Your changes are safe in the stash.
-       You can run "git stash pop" or "git stash drop" at any time.
-       EOF
-}
-
 testrebase () {
        type=$1
        dotest=$2
@@ -177,6 +105,9 @@ testrebase () {
        test_expect_success "rebase$type --autostash: check output" '
                test_when_finished git branch -D rebased-feature-branch &&
                suffix=${type#\ --} && suffix=${suffix:-am} &&
+               if test ${suffix} = "merge"; then
+                       suffix=interactive
+               fi &&
                create_expected_success_$suffix &&
                test_i18ncmp expected actual
        '
@@ -274,6 +205,9 @@ testrebase () {
        test_expect_success "rebase$type: check output with conflicting stash" '
                test_when_finished git branch -D rebased-feature-branch &&
                suffix=${type#\ --} && suffix=${suffix:-am} &&
+               if test ${suffix} = "merge"; then
+                       suffix=interactive
+               fi &&
                create_expected_failure_$suffix &&
                test_i18ncmp expected actual
        '
index 23ad4cff35a74c9ffb8656f61e777d633459cb77..7274dca40b1ccf0d32aeb98e7b0acec59daaa14d 100755 (executable)
@@ -111,7 +111,7 @@ test_run_rebase () {
        "
 }
 test_run_rebase success ''
-test_run_rebase failure -m
+test_run_rebase success -m
 test_run_rebase success -i
 test_have_prereq !REBASE_P || test_run_rebase success -p
 
@@ -126,7 +126,7 @@ test_run_rebase () {
        "
 }
 test_run_rebase success ''
-test_run_rebase failure -m
+test_run_rebase success -m
 test_run_rebase success -i
 test_have_prereq !REBASE_P || test_run_rebase success -p
 
@@ -141,7 +141,7 @@ test_run_rebase () {
        "
 }
 test_run_rebase success ''
-test_run_rebase failure -m
+test_run_rebase success -m
 test_run_rebase success -i
 test_have_prereq !REBASE_P || test_run_rebase success -p
 
@@ -284,7 +284,7 @@ test_run_rebase () {
        "
 }
 test_run_rebase success ''
-test_run_rebase failure -m
+test_run_rebase success -m
 test_run_rebase success -i
 test_have_prereq !REBASE_P || test_run_rebase success -p
 
@@ -315,7 +315,7 @@ test_run_rebase () {
        "
 }
 test_run_rebase success ''
-test_run_rebase failure -m
+test_run_rebase success -m
 test_run_rebase success -i
 test_have_prereq !REBASE_P || test_run_rebase failure -p
 
index 5f892e33d7e53e8871df256b3344ebd0476712ee..fd8efe84fe8f74d062d73f27fb63d95cc5bed4c8 100755 (executable)
@@ -70,9 +70,8 @@ test_run_rebase () {
                test_linear_range "\'"$expected"\'" d..
        "
 }
-#TODO: make order consistent across all flavors of rebase
-test_run_rebase success 'e n o' ''
-test_run_rebase success 'e n o' -m
+test_run_rebase success 'n o e' ''
+test_run_rebase success 'n o e' -m
 test_run_rebase success 'n o e' -i
 
 test_run_rebase () {
@@ -87,9 +86,8 @@ test_run_rebase () {
                test_linear_range "\'"$expected"\'" c..
        "
 }
-#TODO: make order consistent across all flavors of rebase
-test_run_rebase success 'd e n o' ''
-test_run_rebase success 'd e n o' -m
+test_run_rebase success 'd n o e' ''
+test_run_rebase success 'd n o e' -m
 test_run_rebase success 'd n o e' -i
 
 test_run_rebase () {
@@ -104,9 +102,8 @@ test_run_rebase () {
                test_linear_range "\'"$expected"\'" c..
        "
 }
-#TODO: make order consistent across all flavors of rebase
-test_run_rebase success 'd e n o' ''
-test_run_rebase success 'd e n o' -m
+test_run_rebase success 'd n o e' ''
+test_run_rebase success 'd n o e' -m
 test_run_rebase success 'd n o e' -i
 
 if ! test_have_prereq REBASE_P; then
index cc5646836fce1aaaa01556450a9b017c7a853088..4c69255ee6b14bdd52b6f840e2e528c182cb23ec 100755 (executable)
@@ -125,7 +125,7 @@ test_expect_success '`reset` refuses to overwrite untracked files' '
        : >dont-overwrite-untracked.t &&
        echo "reset refs/tags/dont-overwrite-untracked" >script-from-scratch &&
        test_config sequence.editor \""$PWD"/replace-editor.sh\" &&
-       test_must_fail git rebase -r HEAD &&
+       test_must_fail git rebase -ir HEAD &&
        git rebase --abort
 '
 
index 37729ba2582119047d559d22df8c522f9c0ab0f1..be582a513b1b99a71c10279aacc72cb36bd4bf7b 100755 (executable)
@@ -402,4 +402,11 @@ test_expect_success 'all statuses changed in folder if . is given' '
        test $(git ls-files --stage | grep ^100755 | wc -l) -eq 0
 '
 
+test_expect_success CASE_INSENSITIVE_FS 'path is case-insensitive' '
+       path="$(pwd)/BLUB" &&
+       touch "$path" &&
+       downcased="$(echo "$path" | tr A-Z a-z)" &&
+       git add "$downcased"
+'
+
 test_done
index a8e01eccd158131118019ca7c9b05d08a65d07e3..03489aff14ea72921f66605eeac3ccddd694e923 100755 (executable)
@@ -32,28 +32,37 @@ test_expect_success 'prepare binary file' '
        git commit -m binbin
 '
 
-# test_expect_success '--stat output after text chmod' '
-#      test_chmod -x rezrov &&
-#      echo " 0 files changed" >expect &&
-#      git diff HEAD --stat >actual &&
-#      test_i18ncmp expect actual
-# '
-#
-# test_expect_success '--shortstat output after text chmod' '
-#      git diff HEAD --shortstat >actual &&
-#      test_i18ncmp expect actual
-# '
-#
-# test_expect_success '--stat output after binary chmod' '
-#      test_chmod +x binbin &&
-#      echo " 0 files changed" >expect &&
-#      git diff HEAD --stat >actual &&
-#      test_i18ncmp expect actual
-# '
-#
-# test_expect_success '--shortstat output after binary chmod' '
-#      git diff HEAD --shortstat >actual &&
-#      test_i18ncmp expect actual
-# '
+test_expect_success '--stat output after text chmod' '
+       test_chmod -x rezrov &&
+       cat >expect <<-\EOF &&
+        rezrov | 0
+        1 file changed, 0 insertions(+), 0 deletions(-)
+       EOF
+       git diff HEAD --stat >actual &&
+       test_i18ncmp expect actual
+'
+
+test_expect_success '--shortstat output after text chmod' '
+       tail -n 1 <expect >expect.short &&
+       git diff HEAD --shortstat >actual &&
+       test_i18ncmp expect.short actual
+'
+
+test_expect_success '--stat output after binary chmod' '
+       test_chmod +x binbin &&
+       cat >expect <<-EOF &&
+        binbin | Bin
+        rezrov |   0
+        2 files changed, 0 insertions(+), 0 deletions(-)
+       EOF
+       git diff HEAD --stat >actual &&
+       test_i18ncmp expect actual
+'
+
+test_expect_success '--shortstat output after binary chmod' '
+       tail -n 1 <expect >expect.short &&
+       git diff HEAD --shortstat >actual &&
+       test_i18ncmp expect.short actual
+'
 
 test_done
index 7d985ff6b1bff3c73e4309cde675f67c813d93da..9f8f0e84ad4f35b72da73ef8ddfee0a3cddfbe1a 100755 (executable)
@@ -98,6 +98,12 @@ test_expect_success setup '
        git commit -m "update mode" &&
        git checkout -f master &&
 
+       # Same merge as master, but with parents reversed. Hide it in a
+       # pseudo-ref to avoid impacting tests with --all.
+       commit=$(echo reverse |
+                git commit-tree -p master^2 -p master^1 master^{tree}) &&
+       git update-ref REVERSE $commit &&
+
        git config diff.renames false &&
 
        git show-branch
@@ -239,6 +245,8 @@ diff-tree --cc --stat --summary master
 # stat summary should show the diffstat and summary with the first parent
 diff-tree -c --stat --summary side
 diff-tree --cc --stat --summary side
+diff-tree --cc --shortstat master
+diff-tree --cc --summary REVERSE
 # improved by Timo's patch
 diff-tree --cc --patch-with-stat master
 # improved by Timo's patch
@@ -350,6 +358,7 @@ diff --line-prefix=abc master master^ side
 diff --dirstat master~1 master~2
 diff --dirstat initial rearrange
 diff --dirstat-by-file initial rearrange
+diff --dirstat --cc master~1 master
 # No-index --abbrev and --no-abbrev
 diff --raw initial
 :noellipses diff --raw initial
diff --git a/t/t4013/diff.diff-tree_--cc_--shortstat_master b/t/t4013/diff.diff-tree_--cc_--shortstat_master
new file mode 100644 (file)
index 0000000..a4ca42d
--- /dev/null
@@ -0,0 +1,4 @@
+$ git diff-tree --cc --shortstat master
+59d314ad6f356dd08601a4cd5e530381da3e3c64
+ 2 files changed, 5 insertions(+)
+$
diff --git a/t/t4013/diff.diff-tree_--cc_--summary_REVERSE b/t/t4013/diff.diff-tree_--cc_--summary_REVERSE
new file mode 100644 (file)
index 0000000..e208dd5
--- /dev/null
@@ -0,0 +1,6 @@
+$ git diff-tree --cc --summary REVERSE
+2562325a7ee916efb2481da93073b82cec801cbc
+ create mode 100644 file1
+ delete mode 100644 file2
+ delete mode 100644 file3
+$
diff --git a/t/t4013/diff.diff_--dirstat_--cc_master~1_master b/t/t4013/diff.diff_--dirstat_--cc_master~1_master
new file mode 100644 (file)
index 0000000..fba4e34
--- /dev/null
@@ -0,0 +1,3 @@
+$ git diff --dirstat --cc master~1 master
+  40.0% dir/
+$
diff --git a/t/t4066-diff-emit-delay.sh b/t/t4066-diff-emit-delay.sh
new file mode 100755 (executable)
index 0000000..5df6b5e
--- /dev/null
@@ -0,0 +1,79 @@
+#!/bin/sh
+
+test_description='test combined/stat/moved interaction'
+. ./test-lib.sh
+
+# This test covers a weird 3-way interaction between "--cc -p", which will run
+# the combined diff code, along with "--stat", which will be computed as a
+# first-parent stat during the combined diff, and "--color-moved", which
+# enables the emitted_symbols list to store the diff in memory.
+
+test_expect_success 'set up history with a merge' '
+       test_commit A &&
+       test_commit B &&
+       git checkout -b side HEAD^ &&
+       test_commit C &&
+       git merge -m M master &&
+       test_commit D
+'
+
+test_expect_success 'log --cc -p --stat --color-moved' '
+       cat >expect <<-\EOF &&
+       commit D
+       ---
+        D.t | 1 +
+        1 file changed, 1 insertion(+)
+
+       diff --git a/D.t b/D.t
+       new file mode 100644
+       index 0000000..1784810
+       --- /dev/null
+       +++ b/D.t
+       @@ -0,0 +1 @@
+       +D
+       commit M
+
+        B.t | 1 +
+        1 file changed, 1 insertion(+)
+       commit C
+       ---
+        C.t | 1 +
+        1 file changed, 1 insertion(+)
+
+       diff --git a/C.t b/C.t
+       new file mode 100644
+       index 0000000..3cc58df
+       --- /dev/null
+       +++ b/C.t
+       @@ -0,0 +1 @@
+       +C
+       commit B
+       ---
+        B.t | 1 +
+        1 file changed, 1 insertion(+)
+
+       diff --git a/B.t b/B.t
+       new file mode 100644
+       index 0000000..223b783
+       --- /dev/null
+       +++ b/B.t
+       @@ -0,0 +1 @@
+       +B
+       commit A
+       ---
+        A.t | 1 +
+        1 file changed, 1 insertion(+)
+
+       diff --git a/A.t b/A.t
+       new file mode 100644
+       index 0000000..f70f10e
+       --- /dev/null
+       +++ b/A.t
+       @@ -0,0 +1 @@
+       +A
+       EOF
+       git log --format="commit %s" --cc -p --stat --color-moved >actual &&
+       test_cmp expect actual
+'
+
+test_done
index 34c47dae09966bb3b1de8178769b078509625b1e..df970d75845e782980835d853176acb580ab70d4 100755 (executable)
@@ -7,7 +7,7 @@ test_description='pack-object compression configuration'
 # This should be moved to test-lib.sh together with the
 # copy in t0021 after both topics have graduated to 'master'.
 file_size () {
-       perl -e 'print -s $ARGV[0]' "$1"
+       test-tool path-utils file-size "$1"
 }
 
 test_expect_success setup '
index 5fe21db99f43aa79dc36ab36bf6d40ca2f47264d..16d10ebce82fa1fc2e4396f8d30911541b96d7b6 100755 (executable)
@@ -122,7 +122,7 @@ test_expect_success 'write graph with merges' '
        cd "$TRASH_DIRECTORY/full" &&
        git commit-graph write &&
        test_path_is_file $objdir/info/commit-graph &&
-       graph_read_expect "10" "large_edges"
+       graph_read_expect "10" "extra_edges"
 '
 
 graph_git_behavior 'merge 1 vs 2' full merge/1 merge/2
@@ -157,7 +157,7 @@ test_expect_success 'write graph with new commit' '
        cd "$TRASH_DIRECTORY/full" &&
        git commit-graph write &&
        test_path_is_file $objdir/info/commit-graph &&
-       graph_read_expect "11" "large_edges"
+       graph_read_expect "11" "extra_edges"
 '
 
 graph_git_behavior 'full graph, commit 8 vs merge 1' full commits/8 merge/1
@@ -167,7 +167,7 @@ test_expect_success 'write graph with nothing new' '
        cd "$TRASH_DIRECTORY/full" &&
        git commit-graph write &&
        test_path_is_file $objdir/info/commit-graph &&
-       graph_read_expect "11" "large_edges"
+       graph_read_expect "11" "extra_edges"
 '
 
 graph_git_behavior 'cleared graph, commit 8 vs merge 1' full commits/8 merge/1
@@ -177,7 +177,7 @@ test_expect_success 'build graph from latest pack with closure' '
        cd "$TRASH_DIRECTORY/full" &&
        cat new-idx | git commit-graph write --stdin-packs &&
        test_path_is_file $objdir/info/commit-graph &&
-       graph_read_expect "9" "large_edges"
+       graph_read_expect "9" "extra_edges"
 '
 
 graph_git_behavior 'graph from pack, commit 8 vs merge 1' full commits/8 merge/1
@@ -200,7 +200,7 @@ test_expect_success 'build graph from commits with append' '
        cd "$TRASH_DIRECTORY/full" &&
        git rev-parse merge/3 | git commit-graph write --stdin-commits --append &&
        test_path_is_file $objdir/info/commit-graph &&
-       graph_read_expect "10" "large_edges"
+       graph_read_expect "10" "extra_edges"
 '
 
 graph_git_behavior 'append graph, commit 8 vs merge 1' full commits/8 merge/1
@@ -210,7 +210,7 @@ test_expect_success 'build graph using --reachable' '
        cd "$TRASH_DIRECTORY/full" &&
        git commit-graph write --reachable &&
        test_path_is_file $objdir/info/commit-graph &&
-       graph_read_expect "11" "large_edges"
+       graph_read_expect "11" "extra_edges"
 '
 
 graph_git_behavior 'append graph, commit 8 vs merge 1' full commits/8 merge/1
@@ -231,7 +231,7 @@ test_expect_success 'write graph in bare repo' '
        cd "$TRASH_DIRECTORY/bare" &&
        git commit-graph write &&
        test_path_is_file $baredir/info/commit-graph &&
-       graph_read_expect "11" "large_edges"
+       graph_read_expect "11" "extra_edges"
 '
 
 graph_git_behavior 'bare repo with graph, commit 8 vs merge 1' bare commits/8 merge/1
@@ -366,9 +366,10 @@ GRAPH_OCTOPUS_DATA_OFFSET=$(($GRAPH_COMMIT_DATA_OFFSET + \
 GRAPH_BYTE_OCTOPUS=$(($GRAPH_OCTOPUS_DATA_OFFSET + 4))
 GRAPH_BYTE_FOOTER=$(($GRAPH_OCTOPUS_DATA_OFFSET + 4 * $NUM_OCTOPUS_EDGES))
 
-# usage: corrupt_graph_and_verify <position> <data> <string>
+# usage: corrupt_graph_and_verify <position> <data> <string> [<zero_pos>]
 # Manipulates the commit-graph file at the position
-# by inserting the data, then runs 'git commit-graph verify'
+# by inserting the data, optionally zeroing the file
+# starting at <zero_pos>, then runs 'git commit-graph verify'
 # and places the output in the file 'err'. Test 'err' for
 # the given string.
 corrupt_graph_and_verify() {
@@ -376,11 +377,15 @@ corrupt_graph_and_verify() {
        data="${2:-\0}"
        grepstr=$3
        cd "$TRASH_DIRECTORY/full" &&
+       orig_size=$(wc -c < $objdir/info/commit-graph) &&
+       zero_pos=${4:-${orig_size}} &&
        test_when_finished mv commit-graph-backup $objdir/info/commit-graph &&
        cp $objdir/info/commit-graph commit-graph-backup &&
        printf "$data" | dd of="$objdir/info/commit-graph" bs=1 seek="$pos" conv=notrunc &&
+       dd of="$objdir/info/commit-graph" bs=1 seek="$zero_pos" count=0 &&
+       dd if=/dev/zero of="$objdir/info/commit-graph" bs=1 seek="$zero_pos" count=$(($orig_size - $zero_pos)) &&
        test_must_fail git commit-graph verify 2>test_err &&
-       grep -v "^+" test_err >err
+       grep -v "^+" test_err >err &&
        test_i18ngrep "$grepstr" err
 }
 
@@ -484,6 +489,11 @@ test_expect_success 'detect invalid checksum hash' '
                "incorrect checksum"
 '
 
+test_expect_success 'detect incorrect chunk count' '
+       corrupt_graph_and_verify $GRAPH_BYTE_CHUNK_COUNT "\377" \
+               "chunk lookup table entry missing" $GRAPH_CHUNK_LOOKUP_OFFSET
+'
+
 test_expect_success 'git fsck (checks commit-graph)' '
        cd "$TRASH_DIRECTORY/full" &&
        git fsck &&
diff --git a/t/t5322-pack-objects-sparse.sh b/t/t5322-pack-objects-sparse.sh
new file mode 100755 (executable)
index 0000000..7124b55
--- /dev/null
@@ -0,0 +1,136 @@
+#!/bin/sh
+
+test_description='pack-objects object selection using sparse algorithm'
+. ./test-lib.sh
+
+test_expect_success 'setup repo' '
+       test_commit initial &&
+       for i in $(test_seq 1 3)
+       do
+               mkdir f$i &&
+               for j in $(test_seq 1 3)
+               do
+                       mkdir f$i/f$j &&
+                       echo $j >f$i/f$j/data.txt
+               done
+       done &&
+       git add . &&
+       git commit -m "Initialized trees" &&
+       for i in $(test_seq 1 3)
+       do
+               git checkout -b topic$i master &&
+               echo change-$i >f$i/f$i/data.txt &&
+               git commit -a -m "Changed f$i/f$i/data.txt"
+       done &&
+       cat >packinput.txt <<-EOF &&
+       topic1
+       ^topic2
+       ^topic3
+       EOF
+       git rev-parse                   \
+               topic1                  \
+               topic1^{tree}           \
+               topic1:f1               \
+               topic1:f1/f1            \
+               topic1:f1/f1/data.txt | sort >expect_objects.txt
+'
+
+test_expect_success 'non-sparse pack-objects' '
+       git pack-objects --stdout --revs --no-sparse <packinput.txt >nonsparse.pack &&
+       git index-pack -o nonsparse.idx nonsparse.pack &&
+       git show-index <nonsparse.idx | awk "{print \$2}" >nonsparse_objects.txt &&
+       test_cmp expect_objects.txt nonsparse_objects.txt
+'
+
+test_expect_success 'sparse pack-objects' '
+       git pack-objects --stdout --revs --sparse <packinput.txt >sparse.pack &&
+       git index-pack -o sparse.idx sparse.pack &&
+       git show-index <sparse.idx | awk "{print \$2}" >sparse_objects.txt &&
+       test_cmp expect_objects.txt sparse_objects.txt
+'
+
+test_expect_success 'duplicate a folder from f3 and commit to topic1' '
+       git checkout topic1 &&
+       echo change-3 >f3/f3/data.txt &&
+       git commit -a -m "Changed f3/f3/data.txt" &&
+       git rev-parse                   \
+               topic1~1                \
+               topic1~1^{tree}         \
+               topic1^{tree}           \
+               topic1                  \
+               topic1:f1               \
+               topic1:f1/f1            \
+               topic1:f1/f1/data.txt | sort >required_objects.txt
+'
+
+test_expect_success 'non-sparse pack-objects' '
+       git pack-objects --stdout --revs --no-sparse <packinput.txt >nonsparse.pack &&
+       git index-pack -o nonsparse.idx nonsparse.pack &&
+       git show-index <nonsparse.idx | awk "{print \$2}" >nonsparse_objects.txt &&
+       comm -1 -2 required_objects.txt nonsparse_objects.txt >nonsparse_required_objects.txt &&
+       test_cmp required_objects.txt nonsparse_required_objects.txt
+'
+
+test_expect_success 'sparse pack-objects' '
+       git pack-objects --stdout --revs --sparse <packinput.txt >sparse.pack &&
+       git index-pack -o sparse.idx sparse.pack &&
+       git show-index <sparse.idx | awk "{print \$2}" >sparse_objects.txt &&
+       comm -1 -2 required_objects.txt sparse_objects.txt >sparse_required_objects.txt &&
+       test_cmp required_objects.txt sparse_required_objects.txt
+'
+
+# Demonstrate that the algorithms differ when we copy a tree wholesale
+# from one folder to another.
+
+test_expect_success 'duplicate a folder from f1 into f3' '
+       mkdir f3/f4 &&
+       cp -r f1/f1/* f3/f4 &&
+       git add f3/f4 &&
+       git commit -m "Copied f1/f1 to f3/f4" &&
+       cat >packinput.txt <<-EOF &&
+       topic1
+       ^topic1~1
+       EOF
+       git rev-parse           \
+               topic1          \
+               topic1^{tree}   \
+               topic1:f3 | sort >required_objects.txt
+'
+
+test_expect_success 'non-sparse pack-objects' '
+       git pack-objects --stdout --revs --no-sparse <packinput.txt >nonsparse.pack &&
+       git index-pack -o nonsparse.idx nonsparse.pack &&
+       git show-index <nonsparse.idx | awk "{print \$2}" >nonsparse_objects.txt &&
+       comm -1 -2 required_objects.txt nonsparse_objects.txt >nonsparse_required_objects.txt &&
+       test_cmp required_objects.txt nonsparse_required_objects.txt
+'
+
+test_expect_success 'sparse pack-objects' '
+       git rev-parse                   \
+               topic1                  \
+               topic1^{tree}           \
+               topic1:f3               \
+               topic1:f3/f4            \
+               topic1:f3/f4/data.txt | sort >expect_sparse_objects.txt &&
+       git pack-objects --stdout --revs --sparse <packinput.txt >sparse.pack &&
+       git index-pack -o sparse.idx sparse.pack &&
+       git show-index <sparse.idx | awk "{print \$2}" >sparse_objects.txt &&
+       test_cmp expect_sparse_objects.txt sparse_objects.txt
+'
+
+test_expect_success 'pack.useSparse enables algorithm' '
+       git config pack.useSparse true &&
+       git pack-objects --stdout --revs <packinput.txt >sparse.pack &&
+       git index-pack -o sparse.idx sparse.pack &&
+       git show-index <sparse.idx | awk "{print \$2}" >sparse_objects.txt &&
+       test_cmp expect_sparse_objects.txt sparse_objects.txt
+'
+
+test_expect_success 'pack.useSparse overridden' '
+       git pack-objects --stdout --revs --no-sparse <packinput.txt >sparse.pack &&
+       git index-pack -o sparse.idx sparse.pack &&
+       git show-index <sparse.idx | awk "{print \$2}" >sparse_objects.txt &&
+       test_cmp required_objects.txt sparse_objects.txt
+'
+
+test_done
index 9b2a274c71f40ace060069212055a29f9a3c4203..a4a5903cbaee5c2a67963d8746d0252ba59bf163 100755 (executable)
@@ -78,6 +78,7 @@ test_expect_success 'git rebase --skip' '
        git rebase --continue &&
        echo rebase >expected.args &&
        cat >expected.data <<-EOF &&
+       $(git rev-parse C) $(git rev-parse HEAD^)
        $(git rev-parse D) $(git rev-parse HEAD)
        EOF
        verify_hook_input
@@ -91,6 +92,7 @@ test_expect_success 'git rebase --skip the last one' '
        echo rebase >expected.args &&
        cat >expected.data <<-EOF &&
        $(git rev-parse E) $(git rev-parse HEAD)
+       $(git rev-parse F) $(git rev-parse HEAD)
        EOF
        verify_hook_input
 '
@@ -120,6 +122,38 @@ test_expect_success 'git rebase -m --skip' '
        git rebase --continue &&
        echo rebase >expected.args &&
        cat >expected.data <<-EOF &&
+       $(git rev-parse C) $(git rev-parse HEAD^)
+       $(git rev-parse D) $(git rev-parse HEAD)
+       EOF
+       verify_hook_input
+'
+
+test_expect_success 'git rebase with implicit use of interactive backend' '
+       git reset --hard D &&
+       clear_hook_input &&
+       test_must_fail git rebase --keep --onto A B &&
+       echo C > foo &&
+       git add foo &&
+       git rebase --continue &&
+       echo rebase >expected.args &&
+       cat >expected.data <<-EOF &&
+       $(git rev-parse C) $(git rev-parse HEAD^)
+       $(git rev-parse D) $(git rev-parse HEAD)
+       EOF
+       verify_hook_input
+'
+
+test_expect_success 'git rebase --skip with implicit use of interactive backend' '
+       git reset --hard D &&
+       clear_hook_input &&
+       test_must_fail git rebase --keep --onto A B &&
+       test_must_fail git rebase --skip &&
+       echo D > foo &&
+       git add foo &&
+       git rebase --continue &&
+       echo rebase >expected.args &&
+       cat >expected.data <<-EOF &&
+       $(git rev-parse C) $(git rev-parse HEAD^)
        $(git rev-parse D) $(git rev-parse HEAD)
        EOF
        verify_hook_input
index 6faf17e17a133f31245f89fd0fe9bad1687ac5fa..6caf628efaaa400473ddfb46fdef0b847b4edd39 100755 (executable)
@@ -243,7 +243,8 @@ test_expect_success 'shallow fetches check connectivity before writing shallow f
               "$(git -C "$REPO" rev-parse HEAD)" \
               "$(git -C "$REPO" rev-parse HEAD^)" \
               >"$HTTPD_ROOT_PATH/one-time-sed" &&
-       test_must_fail git -C client fetch --depth=1 "$HTTPD_URL/one_time_sed/repo" \
+       test_must_fail env GIT_TEST_SIDEBAND_ALL=0 git -C client \
+               fetch --depth=1 "$HTTPD_URL/one_time_sed/repo" \
                master:a_branch &&
 
        # Ensure that the one-time-sed script was used.
index ba548df4a918243ee1b2bcedab525e6ec7eff7d6..217adf3a632b49e9322de1db78c3e1a588c3b7bd 100755 (executable)
@@ -40,6 +40,11 @@ test_expect_success clone '
        git clone "file://$UNCPATH" clone
 '
 
+test_expect_success 'clone with backslashed path' '
+       BACKSLASHED="$(echo "$UNCPATH" | tr / \\\\)" &&
+       git clone "$BACKSLASHED" backslashed
+'
+
 test_expect_success push '
        (
                cd clone &&
index ae79c6bbc0d66e9a7a184b2d1726a316a0affbbe..fe45bf828d09cd9d95a66742ef938837d35141a3 100755 (executable)
@@ -14,7 +14,7 @@ test_expect_success 'test capability advertisement' '
        0000
        EOF
 
-       git serve --advertise-capabilities >out &&
+       GIT_TEST_SIDEBAND_ALL=0 git serve --advertise-capabilities >out &&
        test-tool pkt-line unpack <out >actual &&
        test_cmp expect actual
 '
index a738c0c4ce828718f92d0c4955d9ac2eadfb752e..db4ae09f2f81ff77b9c29b99c21363e66c81f222 100755 (executable)
@@ -561,6 +561,27 @@ test_expect_success 'fetch with http:// using protocol v2' '
        grep "git< version 2" log
 '
 
+test_expect_success 'fetch from namespaced repo respects namespaces' '
+       test_when_finished "rm -f log" &&
+
+       git init "$HTTPD_DOCUMENT_ROOT_PATH/nsrepo" &&
+       test_commit -C "$HTTPD_DOCUMENT_ROOT_PATH/nsrepo" one &&
+       test_commit -C "$HTTPD_DOCUMENT_ROOT_PATH/nsrepo" two &&
+       git -C "$HTTPD_DOCUMENT_ROOT_PATH/nsrepo" \
+               update-ref refs/namespaces/ns/refs/heads/master one &&
+
+       GIT_TRACE_PACKET="$(pwd)/log" git -C http_child -c protocol.version=2 \
+               fetch "$HTTPD_URL/smart_namespace/nsrepo" \
+               refs/heads/master:refs/heads/theirs &&
+
+       # Server responded using protocol v2
+       grep "fetch< version 2" log &&
+
+       git -C "$HTTPD_DOCUMENT_ROOT_PATH/nsrepo" rev-parse one >expect &&
+       git -C http_child rev-parse theirs >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'push with http:// and a config of v2 does not request v2' '
        test_when_finished "rm -f log" &&
        # Till v2 for push is designed, make sure that if a client has
@@ -630,8 +651,8 @@ test_expect_success 'when server does not send "ready", expect FLUSH' '
        test_must_fail env GIT_TRACE_PACKET="$(pwd)/log" git -C http_child \
                -c protocol.version=2 \
                fetch "$HTTPD_URL/one_time_sed/http_parent" 2> err &&
-       grep "fetch< acknowledgments" log &&
-       ! grep "fetch< ready" log &&
+       grep "fetch< .*acknowledgments" log &&
+       ! grep "fetch< .*ready" log &&
        test_i18ngrep "expected no other sections to be sent after no .ready." err
 '
 
index 7053899cb5a0cbd5cca10cb4029b70df866dbff8..f87b2f6df329975e243ab9c00b510ee4cc588d0b 100755 (executable)
@@ -208,7 +208,7 @@ test_expect_success 'server is initially ahead - no ref in want' '
        cp -r "$LOCAL_PRISTINE" local &&
        inconsistency master 1234567890123456789012345678901234567890 &&
        test_must_fail git -C local fetch 2>err &&
-       test_i18ngrep "ERR upload-pack: not our ref" err
+       test_i18ngrep "fatal: remote error: upload-pack: not our ref" err
 '
 
 test_expect_success 'server is initially ahead - ref in want' '
@@ -254,7 +254,7 @@ test_expect_success 'server loses a ref - ref in want' '
        echo "s/master/raster/" >"$HTTPD_ROOT_PATH/one-time-sed" &&
        test_must_fail git -C local fetch 2>err &&
 
-       test_i18ngrep "ERR unknown ref refs/heads/raster" err
+       test_i18ngrep "fatal: remote error: unknown ref refs/heads/raster" err
 '
 
 stop_httpd
index f84ff941c3624be821fd87a67922ad1d2ca00b34..55835ee4a47158e1f7aeaa9aeb393f1f3d619791 100755 (executable)
@@ -802,7 +802,7 @@ test_expect_success 'bisect terms needs 0 or 1 argument' '
        test_must_fail git bisect terms only-one &&
        test_must_fail git bisect terms 1 2 &&
        test_must_fail git bisect terms 2>actual &&
-       echo "no terms defined" >expected &&
+       echo "error: no terms defined" >expected &&
        test_i18ncmp expected actual
 '
 
index 7cc34e75797b406096407ba1799a1ca54e48333c..09dfa8bd92b51e7a90fcd01f07c62a6fdf65a528 100755 (executable)
@@ -1175,7 +1175,7 @@ test_expect_success 'setup nested conflicts from rename/rename(2to1)' '
 
                # Handle the left side
                git checkout L &&
-               git mv one three &&
+               git rm one two &&
                mv -f file_v2 three &&
                mv -f file_v5 two &&
                git add two three &&
@@ -1183,7 +1183,7 @@ test_expect_success 'setup nested conflicts from rename/rename(2to1)' '
 
                # Handle the right side
                git checkout R &&
-               git mv two three &&
+               git rm one two &&
                mv -f file_v3 one &&
                mv -f file_v6 three &&
                git add one three &&
index eb32505a6ef8804f4f7762ce0332f00beeacbe99..9c114277196e5c231869dbfe51f88760c40ae0b8 100755 (executable)
@@ -283,7 +283,7 @@ test_expect_success 'verify tree:0 includes trees in "filtered" output' '
 
 # Make sure tree:0 does not iterate through any trees.
 
-test_expect_success 'filter a GIANT tree through tree:0' '
+test_expect_success 'verify skipping tree iteration when not collecting omits' '
        GIT_TRACE=1 git -C r3 rev-list \
                --objects --filter=tree:0 HEAD 2>filter_trace &&
        grep "Skipping contents of tree [.][.][.]" filter_trace >actual &&
@@ -294,6 +294,126 @@ test_expect_success 'filter a GIANT tree through tree:0' '
        ! grep "Skipping contents of tree [^.]" filter_trace
 '
 
+# Test tree:# filters.
+
+expect_has () {
+       commit=$1 &&
+       name=$2 &&
+
+       hash=$(git -C r3 rev-parse $commit:$name) &&
+       grep "^$hash $name$" actual
+}
+
+test_expect_success 'verify tree:1 includes root trees' '
+       git -C r3 rev-list --objects --filter=tree:1 HEAD >actual &&
+
+       # We should get two root directories and two commits.
+       expect_has HEAD "" &&
+       expect_has HEAD~1 ""  &&
+       test_line_count = 4 actual
+'
+
+test_expect_success 'verify tree:2 includes root trees and immediate children' '
+       git -C r3 rev-list --objects --filter=tree:2 HEAD >actual &&
+
+       expect_has HEAD "" &&
+       expect_has HEAD~1 "" &&
+       expect_has HEAD dir1 &&
+       expect_has HEAD pattern &&
+       expect_has HEAD sparse1 &&
+       expect_has HEAD sparse2 &&
+
+       # There are also 2 commit objects
+       test_line_count = 8 actual
+'
+
+test_expect_success 'verify tree:3 includes everything expected' '
+       git -C r3 rev-list --objects --filter=tree:3 HEAD >actual &&
+
+       expect_has HEAD "" &&
+       expect_has HEAD~1 "" &&
+       expect_has HEAD dir1 &&
+       expect_has HEAD dir1/sparse1 &&
+       expect_has HEAD dir1/sparse2 &&
+       expect_has HEAD pattern &&
+       expect_has HEAD sparse1 &&
+       expect_has HEAD sparse2 &&
+
+       # There are also 2 commit objects
+       test_line_count = 10 actual
+'
+
+# Test provisional omit collection logic with a repo that has objects appearing
+# at multiple depths - first deeper than the filter's threshold, then shallow.
+
+test_expect_success 'setup r4' '
+       git init r4 &&
+
+       echo foo > r4/foo &&
+       mkdir r4/subdir &&
+       echo bar > r4/subdir/bar &&
+
+       mkdir r4/filt &&
+       cp -r r4/foo r4/subdir r4/filt &&
+
+       git -C r4 add foo subdir filt &&
+       git -C r4 commit -m "commit msg"
+'
+
+expect_has_with_different_name () {
+       repo=$1 &&
+       name=$2 &&
+
+       hash=$(git -C $repo rev-parse HEAD:$name) &&
+       ! grep "^$hash $name$" actual &&
+       grep "^$hash " actual &&
+       ! grep "~$hash" actual
+}
+
+test_expect_success 'test tree:# filter provisional omit for blob and tree' '
+       git -C r4 rev-list --objects --filter-print-omitted --filter=tree:2 \
+               HEAD >actual &&
+       expect_has_with_different_name r4 filt/foo &&
+       expect_has_with_different_name r4 filt/subdir
+'
+
+test_expect_success 'verify skipping tree iteration when collecting omits' '
+       GIT_TRACE=1 git -C r4 rev-list --filter-print-omitted \
+               --objects --filter=tree:0 HEAD 2>filter_trace &&
+       grep "^Skipping contents of tree " filter_trace >actual &&
+
+       echo "Skipping contents of tree subdir/..." >expect &&
+       test_cmp expect actual
+'
+
+# Test tree:<depth> where a tree is iterated to twice - once where a subentry is
+# too deep to be included, and again where the blob inside it is shallow enough
+# to be included. This makes sure we don't use LOFR_MARK_SEEN incorrectly (we
+# can't use it because a tree can be iterated over again at a lower depth).
+
+test_expect_success 'tree:<depth> where we iterate over tree at two levels' '
+       git init r5 &&
+
+       mkdir -p r5/a/subdir/b &&
+       echo foo > r5/a/subdir/b/foo &&
+
+       mkdir -p r5/subdir/b &&
+       echo foo > r5/subdir/b/foo &&
+
+       git -C r5 add a subdir &&
+       git -C r5 commit -m "commit msg" &&
+
+       git -C r5 rev-list --objects --filter=tree:4 HEAD >actual &&
+       expect_has_with_different_name r5 a/subdir/b/foo
+'
+
+test_expect_success 'tree:<depth> which filters out blob but given as arg' '
+       blob_hash=$(git -C r4 rev-parse HEAD:subdir/bar) &&
+
+       git -C r4 rev-list --objects --filter=tree:1 HEAD $blob_hash >actual &&
+       grep ^$blob_hash actual
+'
+
 # Delete some loose objects and use rev-list, but WITHOUT any filtering.
 # This models previously omitted objects that we did not receive.
 
@@ -324,4 +444,21 @@ test_expect_success 'rev-list W/ missing=allow-any' '
        git -C r1 rev-list --quiet --missing=allow-any --objects HEAD
 '
 
+# Test expansion of filter specs.
+
+test_expect_success 'expand blob limit in protocol' '
+       git -C r2 config --local uploadpack.allowfilter 1 &&
+       GIT_TRACE_PACKET="$(pwd)/trace" git -c protocol.version=2 clone \
+               --filter=blob:limit=1k "file://$(pwd)/r2" limit &&
+       ! grep "blob:limit=1k" trace &&
+       grep "blob:limit=1024" trace
+'
+
+test_expect_success 'expand tree depth limit in protocol' '
+       GIT_TRACE_PACKET="$(pwd)/tree_trace" git -c protocol.version=2 clone \
+               --filter=tree:0k "file://$(pwd)/r2" tree &&
+       ! grep "tree:0k" tree_trace &&
+       grep "tree:0" tree_trace
+'
+
 test_done
index ebfcad9c4c7d3c6766907d76c5e0c794a0720e1c..ba8bd1b51497df1aedf2280210a98b389f12b9e7 100755 (executable)
@@ -215,7 +215,7 @@ test_expect_success 'with hook and editor (merge)' '
 test_rebase () {
        expect=$1 &&
        mode=$2 &&
-       test_expect_$expect C_LOCALE_OUTPUT "with hook (rebase $mode)" '
+       test_expect_$expect C_LOCALE_OUTPUT "with hook (rebase ${mode:--i})" '
                test_when_finished "\
                        git rebase --abort
                        git checkout -f master
@@ -225,7 +225,7 @@ test_rebase () {
                GIT_EDITOR="\"$FAKE_EDITOR\"" &&
                (
                        export GIT_SEQUENCE_EDITOR GIT_EDITOR &&
-                       test_must_fail git rebase $mode b &&
+                       test_must_fail git rebase -i $mode b &&
                        echo x >a &&
                        git add a &&
                        test_must_fail git rebase --continue &&
@@ -241,18 +241,18 @@ test_rebase () {
                        git add b &&
                        git rebase --continue
                ) &&
-               if test $mode = -p # reword amended after pick
+               if test "$mode" = -p # reword amended after pick
                then
                        n=18
                else
                        n=17
                fi &&
                git log --pretty=%s -g -n$n HEAD@{1} >actual &&
-               test_cmp "$TEST_DIRECTORY/t7505/expected-rebase$mode" actual
+               test_cmp "$TEST_DIRECTORY/t7505/expected-rebase${mode:--i}" actual
        '
 }
 
-test_rebase success -i
+test_rebase success
 test_have_prereq !REBASE_P || test_rebase success -p
 
 test_expect_success 'with hook (cherry-pick)' '
index 86d3f93fa22e45ba9dda24c49ec02df14e22ebc3..682b23a06818cddf6ff89e11b4395d32cebe9758 100755 (executable)
@@ -49,15 +49,28 @@ test_expect_success GPG 'create signed commits' '
        git tag eighth-signed-alt &&
 
        # commit.gpgsign is still on but this must not be signed
-       git tag ninth-unsigned $(echo 9 | git commit-tree HEAD^{tree}) &&
+       echo 9 | git commit-tree HEAD^{tree} >oid &&
+       test_line_count = 1 oid &&
+       git tag ninth-unsigned $(cat oid) &&
        # explicit -S of course must sign.
-       git tag tenth-signed $(echo 9 | git commit-tree -S HEAD^{tree})
+       echo 10 | git commit-tree -S HEAD^{tree} >oid &&
+       test_line_count = 1 oid &&
+       git tag tenth-signed $(cat oid) &&
+
+       # --gpg-sign[=<key-id>] must sign.
+       echo 11 | git commit-tree --gpg-sign HEAD^{tree} >oid &&
+       test_line_count = 1 oid &&
+       git tag eleventh-signed $(cat oid) &&
+       echo 12 | git commit-tree --gpg-sign=B7227189 HEAD^{tree} >oid &&
+       test_line_count = 1 oid &&
+       git tag twelfth-signed-alt $(cat oid)
 '
 
 test_expect_success GPG 'verify and show signatures' '
        (
                for commit in initial second merge fourth-signed \
-                       fifth-signed sixth-signed seventh-signed tenth-signed
+                       fifth-signed sixth-signed seventh-signed tenth-signed \
+                       eleventh-signed
                do
                        git verify-commit $commit &&
                        git show --pretty=short --show-signature $commit >actual &&
@@ -78,7 +91,7 @@ test_expect_success GPG 'verify and show signatures' '
                done
        ) &&
        (
-               for commit in eighth-signed-alt
+               for commit in eighth-signed-alt twelfth-signed-alt
                do
                        git show --pretty=short --show-signature $commit >actual &&
                        grep "Good signature from" actual &&
index 856219f46a7fc47332789d66a13f6fd4603520cb..5045f02a5331fcf4cb3973e81cff22620f0ad628 100755 (executable)
@@ -6,7 +6,7 @@ test_description='compression setting of fast-import utility'
 # This should be moved to test-lib.sh together with the
 # copy in t0021 after both topics have graduated to 'master'.
 file_size () {
-       perl -e 'print -s $ARGV[0]' "$1"
+       test-tool path-utils file-size "$1"
 }
 
 import_large () {
index 2325599ee60f5bf9b179f4a33ccbe866458c0740..850d97911966fe78f22035dab78ac0556a82fd99 100755 (executable)
@@ -500,6 +500,10 @@ test_expect_success 'submit --shelve' '
        )
 '
 
+last_shelve () {
+       p4 -G changes -s shelved -m 1 //depot/... | marshal_dump change
+}
+
 make_shelved_cl() {
        test_commit "$1" >/dev/null &&
        git p4 submit --origin HEAD^ --shelve >/dev/null &&
@@ -533,12 +537,59 @@ test_expect_success 'submit --update-shelve' '
        ) &&
        (
                cd "$cli" &&
-               change=$(p4 -G changes -s shelved -m 1 //depot/... | \
-                        marshal_dump change) &&
+               change=$(last_shelve) &&
                p4 unshelve -c $change -s $change &&
                grep -q updated-line shelf.t &&
                p4 describe -S $change | grep added-file.t &&
-               test_path_is_missing shelved-change-1.t
+               test_path_is_missing shelved-change-1.t &&
+               p4 revert ...
+       )
+'
+
+test_expect_success 'update a shelve involving moved and copied files' '
+       test_when_finished cleanup_git &&
+       (
+               cd "$cli" &&
+               : >file_to_move &&
+               p4 add file_to_move &&
+               p4 submit -d "change1" &&
+               p4 edit file_to_move &&
+               echo change >>file_to_move &&
+               p4 submit -d "change2" &&
+               p4 opened
+       ) &&
+       git p4 clone --dest="$git" //depot &&
+       (
+               cd "$git" &&
+               git config git-p4.detectCopies true &&
+               git config git-p4.detectRenames true &&
+               git config git-p4.skipSubmitEdit true &&
+               mkdir moved &&
+               cp file_to_move copy_of_file &&
+               git add copy_of_file &&
+               git mv file_to_move moved/ &&
+               git commit -m "rename a file" &&
+               git p4 submit -M --shelve --origin HEAD^ &&
+               : >new_file &&
+               git add new_file &&
+               git commit --amend &&
+               git show --stat HEAD &&
+               change=$(last_shelve) &&
+               git p4 submit -M --update-shelve $change --commit HEAD
+       ) &&
+       (
+               cd "$cli" &&
+               change=$(last_shelve) &&
+               echo change=$change &&
+               p4 unshelve -s $change &&
+               p4 submit -d "Testing update-shelve" &&
+               test_path_is_file copy_of_file &&
+               test_path_is_file moved/file_to_move &&
+               test_path_is_missing file_to_move &&
+               test_path_is_file new_file &&
+               echo "unshelved and submitted change $change" &&
+               p4 changes moved/file_to_move | grep "Testing update-shelve" &&
+               p4 changes copy_of_file | grep "Testing update-shelve"
        )
 '
 
index 81a5179e28bf529bc2f0a8bc197108fcb69fba72..5cadedb2a9bc6eb66b9ead3ccae037e62a655f2c 100755 (executable)
@@ -180,7 +180,7 @@ test_expect_success 'prompt - interactive rebase' '
 '
 
 test_expect_success 'prompt - rebase merge' '
-       printf " (b2|REBASE-m 1/3)" >expected &&
+       printf " (b2|REBASE-i 1/3)" >expected &&
        git checkout b2 &&
        test_when_finished "git checkout master" &&
        test_must_fail git rebase --merge b1 b2 &&
index a1abb1177a15c85ef7c75f0b9b056a59ff9843e9..42b1a0aa7f0b8f5b06735293089f640b7f228f62 100644 (file)
@@ -111,6 +111,8 @@ do
                test -z "$HARNESS_ACTIVE" && quiet=t ;;
        --with-dashes)
                with_dashes=t ;;
+       --no-bin-wrappers)
+               no_bin_wrappers=t ;;
        --no-color)
                color= ;;
        --va|--val|--valg|--valgr|--valgri|--valgrin|--valgrind)
@@ -139,6 +141,9 @@ do
                verbose_log=t
                tee=t
                ;;
+       --write-junit-xml)
+               write_junit_xml=t
+               ;;
        --stress)
                stress=t ;;
        --stress=*)
@@ -622,11 +627,35 @@ trap 'exit $?' INT TERM HUP
 # the test_expect_* functions instead.
 
 test_ok_ () {
+       if test -n "$write_junit_xml"
+       then
+               write_junit_xml_testcase "$*"
+       fi
        test_success=$(($test_success + 1))
        say_color "" "ok $test_count - $@"
 }
 
 test_failure_ () {
+       if test -n "$write_junit_xml"
+       then
+               junit_insert="<failure message=\"not ok $test_count -"
+               junit_insert="$junit_insert $(xml_attr_encode "$1")\">"
+               junit_insert="$junit_insert $(xml_attr_encode \
+                       "$(if test -n "$GIT_TEST_TEE_OUTPUT_FILE"
+                          then
+                               test-tool path-utils skip-n-bytes \
+                                       "$GIT_TEST_TEE_OUTPUT_FILE" $GIT_TEST_TEE_OFFSET
+                          else
+                               printf '%s\n' "$@" | sed 1d
+                          fi)")"
+               junit_insert="$junit_insert</failure>"
+               if test -n "$GIT_TEST_TEE_OUTPUT_FILE"
+               then
+                       junit_insert="$junit_insert<system-err>$(xml_attr_encode \
+                               "$(cat "$GIT_TEST_TEE_OUTPUT_FILE")")</system-err>"
+               fi
+               write_junit_xml_testcase "$1" "      $junit_insert"
+       fi
        test_failure=$(($test_failure + 1))
        say_color error "not ok $test_count - $1"
        shift
@@ -635,11 +664,19 @@ test_failure_ () {
 }
 
 test_known_broken_ok_ () {
+       if test -n "$write_junit_xml"
+       then
+               write_junit_xml_testcase "$* (breakage fixed)"
+       fi
        test_fixed=$(($test_fixed+1))
        say_color error "ok $test_count - $@ # TODO known breakage vanished"
 }
 
 test_known_broken_failure_ () {
+       if test -n "$write_junit_xml"
+       then
+               write_junit_xml_testcase "$* (known breakage)"
+       fi
        test_broken=$(($test_broken+1))
        say_color warn "not ok $test_count - $@ # TODO known breakage"
 }
@@ -897,12 +934,21 @@ test_start_ () {
        test_count=$(($test_count+1))
        maybe_setup_verbose
        maybe_setup_valgrind
+       if test -n "$write_junit_xml"
+       then
+               junit_start=$(test-tool date getnanos)
+       fi
 }
 
 test_finish_ () {
        echo >&3 ""
        maybe_teardown_valgrind
        maybe_teardown_verbose
+       if test -n "$GIT_TEST_TEE_OFFSET"
+       then
+               GIT_TEST_TEE_OFFSET=$(test-tool path-utils file-size \
+                       "$GIT_TEST_TEE_OUTPUT_FILE")
+       fi
 }
 
 test_skip () {
@@ -934,6 +980,13 @@ test_skip () {
 
        case "$to_skip" in
        t)
+               if test -n "$write_junit_xml"
+               then
+                       message="$(xml_attr_encode "$skipped_reason")"
+                       write_junit_xml_testcase "$1" \
+                               "      <skipped message=\"$message\" />"
+               fi
+
                say_color skip >&3 "skipping test: $@"
                say_color skip "ok $test_count # skip $1 ($skipped_reason)"
                : true
@@ -949,9 +1002,51 @@ test_at_end_hook_ () {
        :
 }
 
+write_junit_xml () {
+       case "$1" in
+       --truncate)
+               >"$junit_xml_path"
+               junit_have_testcase=
+               shift
+               ;;
+       esac
+       printf '%s\n' "$@" >>"$junit_xml_path"
+}
+
+xml_attr_encode () {
+       printf '%s\n' "$@" | test-tool xml-encode
+}
+
+write_junit_xml_testcase () {
+       junit_attrs="name=\"$(xml_attr_encode "$this_test.$test_count $1")\""
+       shift
+       junit_attrs="$junit_attrs classname=\"$this_test\""
+       junit_attrs="$junit_attrs time=\"$(test-tool \
+               date getnanos $junit_start)\""
+       write_junit_xml "$(printf '%s\n' \
+               "    <testcase $junit_attrs>" "$@" "    </testcase>")"
+       junit_have_testcase=t
+}
+
 test_done () {
        GIT_EXIT_OK=t
 
+       if test -n "$write_junit_xml" && test -n "$junit_xml_path"
+       then
+               test -n "$junit_have_testcase" || {
+                       junit_start=$(test-tool date getnanos)
+                       write_junit_xml_testcase "all tests skipped"
+               }
+
+               # adjust the overall time
+               junit_time=$(test-tool date getnanos $junit_suite_start)
+               sed "s/<testsuite [^>]*/& time=\"$junit_time\"/" \
+                       <"$junit_xml_path" >"$junit_xml_path.new"
+               mv "$junit_xml_path.new" "$junit_xml_path"
+
+               write_junit_xml "  </testsuite>" "</testsuites>"
+       fi
+
        if test -z "$HARNESS_ACTIVE"
        then
                mkdir -p "$TEST_RESULTS_DIR"
@@ -1011,7 +1106,11 @@ test_done () {
                        error "Tests passed but trash directory already removed before test cleanup; aborting"
 
                        cd "$TRASH_DIRECTORY/.." &&
-                       rm -fr "$TRASH_DIRECTORY" ||
+                       rm -fr "$TRASH_DIRECTORY" || {
+                               # try again in a bit
+                               sleep 5;
+                               rm -fr "$TRASH_DIRECTORY"
+                       } ||
                        error "Tests passed but test cleanup failed; aborting"
                fi
                test_at_end_hook_
@@ -1117,20 +1216,25 @@ then
        PATH=$GIT_TEST_INSTALLED:$GIT_BUILD_DIR/t/helper:$PATH
        GIT_EXEC_PATH=${GIT_TEST_EXEC_PATH:-$GIT_EXEC_PATH}
 else # normal case, use ../bin-wrappers only unless $with_dashes:
-       git_bin_dir="$GIT_BUILD_DIR/bin-wrappers"
-       if ! test -x "$git_bin_dir/git"
+       if test -n "$no_bin_wrappers"
        then
-               if test -z "$with_dashes"
+               with_dashes=t
+       else
+               git_bin_dir="$GIT_BUILD_DIR/bin-wrappers"
+               if ! test -x "$git_bin_dir/git"
                then
-                       say "$git_bin_dir/git is not executable; using GIT_EXEC_PATH"
+                       if test -z "$with_dashes"
+                       then
+                               say "$git_bin_dir/git is not executable; using GIT_EXEC_PATH"
+                       fi
+                       with_dashes=t
                fi
-               with_dashes=t
+               PATH="$git_bin_dir:$PATH"
        fi
-       PATH="$git_bin_dir:$PATH"
        GIT_EXEC_PATH=$GIT_BUILD_DIR
        if test -n "$with_dashes"
        then
-               PATH="$GIT_BUILD_DIR:$PATH"
+               PATH="$GIT_BUILD_DIR:$GIT_BUILD_DIR/t/helper:$PATH"
        fi
 fi
 GIT_TEMPLATE_DIR="$GIT_BUILD_DIR"/templates/blt
@@ -1154,7 +1258,7 @@ test -d "$GIT_BUILD_DIR"/templates/blt || {
        error "You haven't built things yet, have you?"
 }
 
-if ! test -x "$GIT_BUILD_DIR"/t/helper/test-tool
+if ! test -x "$GIT_BUILD_DIR"/t/helper/test-tool$X
 then
        echo >&2 'You need to build test-tool:'
        echo >&2 'Run "make t/helper/test-tool" in the source (toplevel) directory'
@@ -1178,6 +1282,7 @@ then
 else
        mkdir -p "$TRASH_DIRECTORY"
 fi
+
 # Use -P to resolve symlinks in our working directory so that the cwd
 # in subprocesses like git equals our $PWD (for pathname comparisons).
 cd -P "$TRASH_DIRECTORY" || exit 1
@@ -1191,6 +1296,23 @@ then
        test_done
 fi
 
+if test -n "$write_junit_xml"
+then
+       junit_xml_dir="$TEST_OUTPUT_DIRECTORY/out"
+       mkdir -p "$junit_xml_dir"
+       junit_xml_base=${0##*/}
+       junit_xml_path="$junit_xml_dir/TEST-${junit_xml_base%.sh}.xml"
+       junit_attrs="name=\"${junit_xml_base%.sh}\""
+       junit_attrs="$junit_attrs timestamp=\"$(TZ=UTC \
+               date +%Y-%m-%dT%H:%M:%S)\""
+       write_junit_xml --truncate "<testsuites>" "  <testsuite $junit_attrs>"
+       junit_suite_start=$(test-tool date getnanos)
+       if test -n "$GIT_TEST_TEE_OUTPUT_FILE"
+       then
+               GIT_TEST_TEE_OFFSET=0
+       fi
+fi
+
 # Provide an implementation of the 'yes' utility
 yes () {
        if test $# = 0
index 6cf3bb324e149c0180d332497edf2b2c15a6b71c..1f52c95fd87b1a02968727bde71dcc1eddc50410 100644 (file)
@@ -679,10 +679,15 @@ static int fetch(struct transport *transport,
        if (data->transport_options.update_shallow)
                set_helper_option(transport, "update-shallow", "true");
 
-       if (data->transport_options.filter_options.choice)
-               set_helper_option(
-                       transport, "filter",
-                       data->transport_options.filter_options.filter_spec);
+       if (data->transport_options.filter_options.choice) {
+               struct strbuf expanded_filter_spec = STRBUF_INIT;
+               expand_list_objects_filter_spec(
+                       &data->transport_options.filter_options,
+                       &expanded_filter_spec);
+               set_helper_option(transport, "filter",
+                                 expanded_filter_spec.buf);
+               strbuf_release(&expanded_filter_spec);
+       }
 
        if (data->transport_options.negotiation_tips)
                warning("Ignoring --negotiation-tip because the protocol does not support it.");
index 99678153c13a3ca442088595273fbcd6caacda29..e078812897eddefcd5a55a7d474dd4a7a89434fc 100644 (file)
@@ -273,7 +273,8 @@ static struct ref *handshake(struct transport *transport, int for_push,
 
        packet_reader_init(&reader, data->fd[0], NULL, 0,
                           PACKET_READ_CHOMP_NEWLINE |
-                          PACKET_READ_GENTLE_ON_EOF);
+                          PACKET_READ_GENTLE_ON_EOF |
+                          PACKET_READ_DIE_ON_ERR_PACKET);
 
        data->version = discover_version(&reader);
        switch (data->version) {
index 277e3b3243011725cb24578e676309ed4444e485..1e4bbc8a0e48c6afe61dc8aab76488356d7e1cbc 100644 (file)
@@ -582,10 +582,10 @@ int get_tree_entry(const struct object_id *tree_oid, const char *name, struct ob
  * with the sha1 of the found object, and *mode will hold the mode of
  * the object.
  *
- * See the code for enum follow_symlink_result for a description of
+ * See the code for enum get_oid_result for a description of
  * the return values.
  */
-enum follow_symlinks_result get_tree_entry_follow_symlinks(struct object_id *tree_oid, const char *name, struct object_id *result, struct strbuf *result_path, unsigned *mode)
+enum get_oid_result get_tree_entry_follow_symlinks(struct object_id *tree_oid, const char *name, struct object_id *result, struct strbuf *result_path, unsigned *mode)
 {
        int retval = MISSING_OBJECT;
        struct dir_state *parents = NULL;
index a4ad28ea5e62926b3450a4c7b093c9aa811107cd..82251718666eb5dceb33d6140e86de5a627baab1 100644 (file)
@@ -51,23 +51,7 @@ struct traverse_info;
 typedef int (*traverse_callback_t)(int n, unsigned long mask, unsigned long dirmask, struct name_entry *entry, struct traverse_info *);
 int traverse_trees(struct index_state *istate, int n, struct tree_desc *t, struct traverse_info *info);
 
-enum follow_symlinks_result {
-       FOUND = 0, /* This includes out-of-tree links */
-       MISSING_OBJECT = -1, /* The initial symlink is missing */
-       DANGLING_SYMLINK = -2, /*
-                               * The initial symlink is there, but
-                               * (transitively) points to a missing
-                               * in-tree file
-                               */
-       SYMLINK_LOOP = -3,
-       NOT_DIR = -4, /*
-                      * Somewhere along the symlink chain, a path is
-                      * requested which contains a file as a
-                      * non-final element.
-                      */
-};
-
-enum follow_symlinks_result get_tree_entry_follow_symlinks(struct object_id *tree_oid, const char *name, struct object_id *result, struct strbuf *result_path, unsigned *mode);
+enum get_oid_result get_tree_entry_follow_symlinks(struct object_id *tree_oid, const char *name, struct object_id *result, struct strbuf *result_path, unsigned *mode);
 
 struct traverse_info {
        const char *traverse_path;
diff --git a/tree.c b/tree.c
index 9f0457c05acf1e4d7bd9f215dd3c710b3cb2df4f..f416afc57d784f8f63ba66ec8c7424ef1e4fcaa1 100644 (file)
--- a/tree.c
+++ b/tree.c
@@ -1,4 +1,3 @@
-#define NO_THE_INDEX_COMPATIBILITY_MACROS
 #include "cache.h"
 #include "cache-tree.h"
 #include "tree.h"
index 01c2175f7c12f2bbfe6d24c73d32c60131fdc723..3563daae1aa6bceb4f7a4715ee574e1359622239 100644 (file)
@@ -1,4 +1,3 @@
-#define NO_THE_INDEX_COMPATIBILITY_MACROS
 #include "cache.h"
 #include "argv-array.h"
 #include "repository.h"
index 9df27b55a098135629ef4eccea4cb18aadb7dad3..d098ef598289d16956309cb73d4518a92c1206af 100644 (file)
@@ -70,6 +70,8 @@ static int allow_filter;
 static int allow_ref_in_want;
 static struct list_objects_filter_options filter_options;
 
+static int allow_sideband_all;
+
 static void reset_timeout(void)
 {
        alarm(timeout);
@@ -139,14 +141,17 @@ static void create_pack_file(const struct object_array *have_obj,
        if (use_include_tag)
                argv_array_push(&pack_objects.args, "--include-tag");
        if (filter_options.filter_spec) {
+               struct strbuf expanded_filter_spec = STRBUF_INIT;
+               expand_list_objects_filter_spec(&filter_options,
+                                               &expanded_filter_spec);
                if (pack_objects.use_shell) {
                        struct strbuf buf = STRBUF_INIT;
-                       sq_quote_buf(&buf, filter_options.filter_spec);
+                       sq_quote_buf(&buf, expanded_filter_spec.buf);
                        argv_array_pushf(&pack_objects.args, "--filter=%s", buf.buf);
                        strbuf_release(&buf);
                } else {
                        argv_array_pushf(&pack_objects.args, "--filter=%s",
-                                        filter_options.filter_spec);
+                                        expanded_filter_spec.buf);
                }
        }
 
@@ -353,7 +358,8 @@ static int ok_to_give_up(const struct object_array *have_obj,
                                            min_generation);
 }
 
-static int get_common_commits(struct object_array *have_obj,
+static int get_common_commits(struct packet_reader *reader,
+                             struct object_array *have_obj,
                              struct object_array *want_obj)
 {
        struct object_id oid;
@@ -365,12 +371,11 @@ static int get_common_commits(struct object_array *have_obj,
        save_commit_buffer = 0;
 
        for (;;) {
-               char *line = packet_read_line(0, NULL);
                const char *arg;
 
                reset_timeout();
 
-               if (!line) {
+               if (packet_reader_read(reader) != PACKET_READ_NORMAL) {
                        if (multi_ack == 2 && got_common
                            && !got_other && ok_to_give_up(have_obj, want_obj)) {
                                sent_ready = 1;
@@ -389,7 +394,7 @@ static int get_common_commits(struct object_array *have_obj,
                        got_other = 0;
                        continue;
                }
-               if (skip_prefix(line, "have ", &arg)) {
+               if (skip_prefix(reader->line, "have ", &arg)) {
                        switch (got_oid(arg, &oid, have_obj)) {
                        case -1: /* they have what we do not */
                                got_other = 1;
@@ -415,7 +420,7 @@ static int get_common_commits(struct object_array *have_obj,
                        }
                        continue;
                }
-               if (!strcmp(line, "done")) {
+               if (!strcmp(reader->line, "done")) {
                        if (have_obj->nr > 0) {
                                if (multi_ack)
                                        packet_write_fmt(1, "ACK %s\n", last_hex);
@@ -424,7 +429,7 @@ static int get_common_commits(struct object_array *have_obj,
                        packet_write_fmt(1, "NAK\n");
                        return -1;
                }
-               die("git upload-pack: expected SHA1 list, got '%s'", line);
+               die("git upload-pack: expected SHA1 list, got '%s'", reader->line);
        }
 }
 
@@ -612,13 +617,14 @@ static void check_non_tip(struct object_array *want_obj)
        }
 }
 
-static void send_shallow(struct commit_list *result)
+static void send_shallow(struct packet_writer *writer,
+                        struct commit_list *result)
 {
        while (result) {
                struct object *object = &result->item->object;
                if (!(object->flags & (CLIENT_SHALLOW|NOT_SHALLOW))) {
-                       packet_write_fmt(1, "shallow %s",
-                                        oid_to_hex(&object->oid));
+                       packet_writer_write(writer, "shallow %s",
+                                           oid_to_hex(&object->oid));
                        register_shallow(the_repository, &object->oid);
                        shallow_nr++;
                }
@@ -626,7 +632,8 @@ static void send_shallow(struct commit_list *result)
        }
 }
 
-static void send_unshallow(const struct object_array *shallows,
+static void send_unshallow(struct packet_writer *writer,
+                          const struct object_array *shallows,
                           struct object_array *want_obj)
 {
        int i;
@@ -635,8 +642,8 @@ static void send_unshallow(const struct object_array *shallows,
                struct object *object = shallows->objects[i].item;
                if (object->flags & NOT_SHALLOW) {
                        struct commit_list *parents;
-                       packet_write_fmt(1, "unshallow %s",
-                                        oid_to_hex(&object->oid));
+                       packet_writer_write(writer, "unshallow %s",
+                                           oid_to_hex(&object->oid));
                        object->flags &= ~CLIENT_SHALLOW;
                        /*
                         * We want to _register_ "object" as shallow, but we
@@ -663,8 +670,7 @@ static void send_unshallow(const struct object_array *shallows,
 
 static int check_ref(const char *refname_full, const struct object_id *oid,
                     int flag, void *cb_data);
-
-static void deepen(int depth, int deepen_relative,
+static void deepen(struct packet_writer *writer, int depth, int deepen_relative,
                   struct object_array *shallows, struct object_array *want_obj)
 {
        if (depth == INFINITE_DEPTH && !is_repository_shallow(the_repository)) {
@@ -689,7 +695,7 @@ static void deepen(int depth, int deepen_relative,
                result = get_shallow_commits(&reachable_shallows,
                                             depth + 1,
                                             SHALLOW, NOT_SHALLOW);
-               send_shallow(result);
+               send_shallow(writer, result);
                free_commit_list(result);
                object_array_clear(&reachable_shallows);
        } else {
@@ -697,14 +703,15 @@ static void deepen(int depth, int deepen_relative,
 
                result = get_shallow_commits(want_obj, depth,
                                             SHALLOW, NOT_SHALLOW);
-               send_shallow(result);
+               send_shallow(writer, result);
                free_commit_list(result);
        }
 
-       send_unshallow(shallows, want_obj);
+       send_unshallow(writer, shallows, want_obj);
 }
 
-static void deepen_by_rev_list(int ac, const char **av,
+static void deepen_by_rev_list(struct packet_writer *writer, int ac,
+                              const char **av,
                               struct object_array *shallows,
                               struct object_array *want_obj)
 {
@@ -712,13 +719,14 @@ static void deepen_by_rev_list(int ac, const char **av,
 
        close_commit_graph(the_repository);
        result = get_shallow_commits_by_rev_list(ac, av, SHALLOW, NOT_SHALLOW);
-       send_shallow(result);
+       send_shallow(writer, result);
        free_commit_list(result);
-       send_unshallow(shallows, want_obj);
+       send_unshallow(writer, shallows, want_obj);
 }
 
 /* Returns 1 if a shallow list is sent or 0 otherwise */
-static int send_shallow_list(int depth, int deepen_rev_list,
+static int send_shallow_list(struct packet_writer *writer,
+                            int depth, int deepen_rev_list,
                             timestamp_t deepen_since,
                             struct string_list *deepen_not,
                             int deepen_relative,
@@ -730,7 +738,7 @@ static int send_shallow_list(int depth, int deepen_rev_list,
        if (depth > 0 && deepen_rev_list)
                die("git upload-pack: deepen and deepen-since (or deepen-not) cannot be used together");
        if (depth > 0) {
-               deepen(depth, deepen_relative, shallows, want_obj);
+               deepen(writer, depth, deepen_relative, shallows, want_obj);
                ret = 1;
        } else if (deepen_rev_list) {
                struct argv_array av = ARGV_ARRAY_INIT;
@@ -751,7 +759,7 @@ static int send_shallow_list(int depth, int deepen_rev_list,
                        struct object *o = want_obj->objects[i].item;
                        argv_array_push(&av, oid_to_hex(&o->oid));
                }
-               deepen_by_rev_list(av.argc, av.argv, shallows, want_obj);
+               deepen_by_rev_list(writer, av.argc, av.argv, shallows, want_obj);
                argv_array_clear(&av);
                ret = 1;
        } else {
@@ -836,7 +844,7 @@ static int process_deepen_not(const char *line, struct string_list *deepen_not,
        return 0;
 }
 
-static void receive_needs(struct object_array *want_obj)
+static void receive_needs(struct packet_reader *reader, struct object_array *want_obj)
 {
        struct object_array shallows = OBJECT_ARRAY_INIT;
        struct string_list deepen_not = STRING_LIST_INIT_DUP;
@@ -845,39 +853,40 @@ static void receive_needs(struct object_array *want_obj)
        timestamp_t deepen_since = 0;
        int deepen_rev_list = 0;
        int deepen_relative = 0;
+       struct packet_writer writer;
 
        shallow_nr = 0;
+       packet_writer_init(&writer, 1);
        for (;;) {
                struct object *o;
                const char *features;
                struct object_id oid_buf;
-               char *line = packet_read_line(0, NULL);
                const char *arg;
 
                reset_timeout();
-               if (!line)
+               if (packet_reader_read(reader) != PACKET_READ_NORMAL)
                        break;
 
-               if (process_shallow(line, &shallows))
+               if (process_shallow(reader->line, &shallows))
                        continue;
-               if (process_deepen(line, &depth))
+               if (process_deepen(reader->line, &depth))
                        continue;
-               if (process_deepen_since(line, &deepen_since, &deepen_rev_list))
+               if (process_deepen_since(reader->line, &deepen_since, &deepen_rev_list))
                        continue;
-               if (process_deepen_not(line, &deepen_not, &deepen_rev_list))
+               if (process_deepen_not(reader->line, &deepen_not, &deepen_rev_list))
                        continue;
 
-               if (skip_prefix(line, "filter ", &arg)) {
+               if (skip_prefix(reader->line, "filter ", &arg)) {
                        if (!filter_capability_requested)
                                die("git upload-pack: filtering capability not negotiated");
                        parse_list_objects_filter(&filter_options, arg);
                        continue;
                }
 
-               if (!skip_prefix(line, "want ", &arg) ||
+               if (!skip_prefix(reader->line, "want ", &arg) ||
                    parse_oid_hex(arg, &oid_buf, &features))
                        die("git upload-pack: protocol error, "
-                           "expected to get object ID, not '%s'", line);
+                           "expected to get object ID, not '%s'", reader->line);
 
                if (parse_feature_request(features, "deepen-relative"))
                        deepen_relative = 1;
@@ -904,9 +913,9 @@ static void receive_needs(struct object_array *want_obj)
 
                o = parse_object(the_repository, &oid_buf);
                if (!o) {
-                       packet_write_fmt(1,
-                                        "ERR upload-pack: not our ref %s",
-                                        oid_to_hex(&oid_buf));
+                       packet_writer_error(&writer,
+                                           "upload-pack: not our ref %s",
+                                           oid_to_hex(&oid_buf));
                        die("git upload-pack: not our ref %s",
                            oid_to_hex(&oid_buf));
                }
@@ -935,7 +944,7 @@ static void receive_needs(struct object_array *want_obj)
        if (depth == 0 && !deepen_rev_list && shallows.nr == 0)
                return;
 
-       if (send_shallow_list(depth, deepen_rev_list, deepen_since,
+       if (send_shallow_list(&writer, depth, deepen_rev_list, deepen_since,
                              &deepen_not, deepen_relative, &shallows,
                              want_obj))
                packet_flush(1);
@@ -1053,6 +1062,8 @@ static int upload_pack_config(const char *var, const char *value, void *unused)
                allow_filter = git_config_bool(var, value);
        } else if (!strcmp("uploadpack.allowrefinwant", var)) {
                allow_ref_in_want = git_config_bool(var, value);
+       } else if (!strcmp("uploadpack.allowsidebandall", var)) {
+               allow_sideband_all = git_config_bool(var, value);
        }
 
        if (current_config_scope() != CONFIG_SCOPE_REPO) {
@@ -1067,6 +1078,7 @@ void upload_pack(struct upload_pack_options *options)
 {
        struct string_list symref = STRING_LIST_INIT_DUP;
        struct object_array want_obj = OBJECT_ARRAY_INIT;
+       struct packet_reader reader;
 
        stateless_rpc = options->stateless_rpc;
        timeout = options->timeout;
@@ -1090,10 +1102,14 @@ void upload_pack(struct upload_pack_options *options)
        if (options->advertise_refs)
                return;
 
-       receive_needs(&want_obj);
+       packet_reader_init(&reader, 0, NULL, 0,
+                          PACKET_READ_CHOMP_NEWLINE |
+                          PACKET_READ_DIE_ON_ERR_PACKET);
+
+       receive_needs(&reader, &want_obj);
        if (want_obj.nr) {
                struct object_array have_obj = OBJECT_ARRAY_INIT;
-               get_common_commits(&have_obj, &want_obj);
+               get_common_commits(&reader, &have_obj, &want_obj);
                create_pack_file(&have_obj, &want_obj);
        }
 }
@@ -1110,6 +1126,8 @@ struct upload_pack_data {
        int deepen_rev_list;
        int deepen_relative;
 
+       struct packet_writer writer;
+
        unsigned stateless_rpc : 1;
 
        unsigned use_thin_pack : 1;
@@ -1133,6 +1151,7 @@ static void upload_pack_data_init(struct upload_pack_data *data)
        data->haves = haves;
        data->shallows = shallows;
        data->deepen_not = deepen_not;
+       packet_writer_init(&data->writer, 1);
 }
 
 static void upload_pack_data_clear(struct upload_pack_data *data)
@@ -1144,7 +1163,8 @@ static void upload_pack_data_clear(struct upload_pack_data *data)
        string_list_clear(&data->deepen_not, 0);
 }
 
-static int parse_want(const char *line, struct object_array *want_obj)
+static int parse_want(struct packet_writer *writer, const char *line,
+                     struct object_array *want_obj)
 {
        const char *arg;
        if (skip_prefix(line, "want ", &arg)) {
@@ -1157,9 +1177,9 @@ static int parse_want(const char *line, struct object_array *want_obj)
 
                o = parse_object(the_repository, &oid);
                if (!o) {
-                       packet_write_fmt(1,
-                                        "ERR upload-pack: not our ref %s",
-                                        oid_to_hex(&oid));
+                       packet_writer_error(writer,
+                                           "upload-pack: not our ref %s",
+                                           oid_to_hex(&oid));
                        die("git upload-pack: not our ref %s",
                            oid_to_hex(&oid));
                }
@@ -1175,7 +1195,8 @@ static int parse_want(const char *line, struct object_array *want_obj)
        return 0;
 }
 
-static int parse_want_ref(const char *line, struct string_list *wanted_refs,
+static int parse_want_ref(struct packet_writer *writer, const char *line,
+                         struct string_list *wanted_refs,
                          struct object_array *want_obj)
 {
        const char *arg;
@@ -1185,7 +1206,7 @@ static int parse_want_ref(const char *line, struct string_list *wanted_refs,
                struct object *o;
 
                if (read_ref(arg, &oid)) {
-                       packet_write_fmt(1, "ERR unknown ref %s", arg);
+                       packet_writer_error(writer, "unknown ref %s", arg);
                        die("unknown ref %s", arg);
                }
 
@@ -1228,10 +1249,11 @@ static void process_args(struct packet_reader *request,
                const char *p;
 
                /* process want */
-               if (parse_want(arg, want_obj))
+               if (parse_want(&data->writer, arg, want_obj))
                        continue;
                if (allow_ref_in_want &&
-                   parse_want_ref(arg, &data->wanted_refs, want_obj))
+                   parse_want_ref(&data->writer, arg, &data->wanted_refs,
+                                  want_obj))
                        continue;
                /* process have line */
                if (parse_have(arg, &data->haves))
@@ -1280,6 +1302,13 @@ static void process_args(struct packet_reader *request,
                        continue;
                }
 
+               if ((git_env_bool("GIT_TEST_SIDEBAND_ALL", 0) ||
+                    allow_sideband_all) &&
+                   !strcmp(arg, "sideband-all")) {
+                       data->writer.use_sideband = 1;
+                       continue;
+               }
+
                /* ignore unknown lines maybe? */
                die("unexpected line: '%s'", arg);
        }
@@ -1325,26 +1354,26 @@ static int process_haves(struct oid_array *haves, struct oid_array *common,
        return 0;
 }
 
-static int send_acks(struct oid_array *acks, struct strbuf *response,
+static int send_acks(struct packet_writer *writer, struct oid_array *acks,
                     const struct object_array *have_obj,
                     struct object_array *want_obj)
 {
        int i;
 
-       packet_buf_write(response, "acknowledgments\n");
+       packet_writer_write(writer, "acknowledgments\n");
 
        /* Send Acks */
        if (!acks->nr)
-               packet_buf_write(response, "NAK\n");
+               packet_writer_write(writer, "NAK\n");
 
        for (i = 0; i < acks->nr; i++) {
-               packet_buf_write(response, "ACK %s\n",
-                                oid_to_hex(&acks->oid[i]));
+               packet_writer_write(writer, "ACK %s\n",
+                                   oid_to_hex(&acks->oid[i]));
        }
 
        if (ok_to_give_up(have_obj, want_obj)) {
                /* Send Ready */
-               packet_buf_write(response, "ready\n");
+               packet_writer_write(writer, "ready\n");
                return 1;
        }
 
@@ -1356,25 +1385,20 @@ static int process_haves_and_send_acks(struct upload_pack_data *data,
                                       struct object_array *want_obj)
 {
        struct oid_array common = OID_ARRAY_INIT;
-       struct strbuf response = STRBUF_INIT;
        int ret = 0;
 
        process_haves(&data->haves, &common, have_obj);
        if (data->done) {
                ret = 1;
-       } else if (send_acks(&common, &response, have_obj, want_obj)) {
-               packet_buf_delim(&response);
+       } else if (send_acks(&data->writer, &common, have_obj, want_obj)) {
+               packet_writer_delim(&data->writer);
                ret = 1;
        } else {
                /* Add Flush */
-               packet_buf_flush(&response);
+               packet_writer_flush(&data->writer);
                ret = 0;
        }
 
-       /* Send response */
-       write_or_die(1, response.buf, response.len);
-       strbuf_release(&response);
-
        oid_array_clear(&data->haves);
        oid_array_clear(&common);
        return ret;
@@ -1387,15 +1411,15 @@ static void send_wanted_ref_info(struct upload_pack_data *data)
        if (!data->wanted_refs.nr)
                return;
 
-       packet_write_fmt(1, "wanted-refs\n");
+       packet_writer_write(&data->writer, "wanted-refs\n");
 
        for_each_string_list_item(item, &data->wanted_refs) {
-               packet_write_fmt(1, "%s %s\n",
-                                oid_to_hex(item->util),
-                                item->string);
+               packet_writer_write(&data->writer, "%s %s\n",
+                                   oid_to_hex(item->util),
+                                   item->string);
        }
 
-       packet_delim(1);
+       packet_writer_delim(&data->writer);
 }
 
 static void send_shallow_info(struct upload_pack_data *data,
@@ -1406,15 +1430,16 @@ static void send_shallow_info(struct upload_pack_data *data,
            !is_repository_shallow(the_repository))
                return;
 
-       packet_write_fmt(1, "shallow-info\n");
+       packet_writer_write(&data->writer, "shallow-info\n");
 
-       if (!send_shallow_list(data->depth, data->deepen_rev_list,
+       if (!send_shallow_list(&data->writer, data->depth,
+                              data->deepen_rev_list,
                               data->deepen_since, &data->deepen_not,
                               data->deepen_relative,
                               &data->shallows, want_obj) &&
            is_repository_shallow(the_repository))
-               deepen(INFINITE_DEPTH, data->deepen_relative, &data->shallows,
-                      want_obj);
+               deepen(&data->writer, INFINITE_DEPTH, data->deepen_relative,
+                      &data->shallows, want_obj);
 
        packet_delim(1);
 }
@@ -1476,7 +1501,7 @@ int upload_pack_v2(struct repository *r, struct argv_array *keys,
                        send_wanted_ref_info(&data);
                        send_shallow_info(&data, &want_obj);
 
-                       packet_write_fmt(1, "packfile\n");
+                       packet_writer_write(&data.writer, "packfile\n");
                        create_pack_file(&have_obj, &want_obj);
                        state = FETCH_DONE;
                        break;
@@ -1497,6 +1522,7 @@ int upload_pack_advertise(struct repository *r,
        if (value) {
                int allow_filter_value;
                int allow_ref_in_want;
+               int allow_sideband_all_value;
 
                strbuf_addstr(value, "shallow");
 
@@ -1511,6 +1537,13 @@ int upload_pack_advertise(struct repository *r,
                                         &allow_ref_in_want) &&
                    allow_ref_in_want)
                        strbuf_addstr(value, " ref-in-want");
+
+               if (git_env_bool("GIT_TEST_SIDEBAND_ALL", 0) ||
+                   (!repo_config_get_bool(the_repository,
+                                          "uploadpack.allowsidebandall",
+                                          &allow_sideband_all_value) &&
+                    allow_sideband_all_value))
+                       strbuf_addstr(value, " sideband-all");
        }
 
        return 1;
diff --git a/utf8.c b/utf8.c
index eb785875042920b84e56abbd235ef9eb7ef22ac4..83824dc2f4ab151a19418c61c46e0c1ffbb0e42c 100644 (file)
--- a/utf8.c
+++ b/utf8.c
@@ -4,6 +4,11 @@
 
 /* This code is originally from http://www.cl.cam.ac.uk/~mgk25/ucs/ */
 
+static const char utf16_be_bom[] = {'\xFE', '\xFF'};
+static const char utf16_le_bom[] = {'\xFF', '\xFE'};
+static const char utf32_be_bom[] = {'\0', '\0', '\xFE', '\xFF'};
+static const char utf32_le_bom[] = {'\xFF', '\xFE', '\0', '\0'};
+
 struct interval {
        ucs_char_t first;
        ucs_char_t last;
@@ -470,16 +475,17 @@ int utf8_fprintf(FILE *stream, const char *format, ...)
 #else
        typedef char * iconv_ibp;
 #endif
-char *reencode_string_iconv(const char *in, size_t insz, iconv_t conv, size_t *outsz_p)
+char *reencode_string_iconv(const char *in, size_t insz, iconv_t conv,
+                           size_t bom_len, size_t *outsz_p)
 {
        size_t outsz, outalloc;
        char *out, *outpos;
        iconv_ibp cp;
 
        outsz = insz;
-       outalloc = st_add(outsz, 1); /* for terminating NUL */
+       outalloc = st_add(outsz, 1 + bom_len); /* for terminating NUL */
        out = xmalloc(outalloc);
-       outpos = out;
+       outpos = out + bom_len;
        cp = (iconv_ibp)in;
 
        while (1) {
@@ -540,10 +546,30 @@ char *reencode_string_len(const char *in, size_t insz,
 {
        iconv_t conv;
        char *out;
+       const char *bom_str = NULL;
+       size_t bom_len = 0;
 
        if (!in_encoding)
                return NULL;
 
+       /* UTF-16LE-BOM is the same as UTF-16 for reading */
+       if (same_utf_encoding("UTF-16LE-BOM", in_encoding))
+               in_encoding = "UTF-16";
+
+       /*
+        * For writing, UTF-16 iconv typically creates "UTF-16BE-BOM"
+        * Some users under Windows want the little endian version
+        */
+       if (same_utf_encoding("UTF-16LE-BOM", out_encoding)) {
+               bom_str = utf16_le_bom;
+               bom_len = sizeof(utf16_le_bom);
+               out_encoding = "UTF-16LE";
+       } else if (same_utf_encoding("UTF-16BE-BOM", out_encoding)) {
+               bom_str = utf16_be_bom;
+               bom_len = sizeof(utf16_be_bom);
+               out_encoding = "UTF-16BE";
+       }
+
        conv = iconv_open(out_encoding, in_encoding);
        if (conv == (iconv_t) -1) {
                in_encoding = fallback_encoding(in_encoding);
@@ -553,9 +579,10 @@ char *reencode_string_len(const char *in, size_t insz,
                if (conv == (iconv_t) -1)
                        return NULL;
        }
-
-       out = reencode_string_iconv(in, insz, conv, outsz);
+       out = reencode_string_iconv(in, insz, conv, bom_len, outsz);
        iconv_close(conv);
+       if (out && bom_str && bom_len)
+               memcpy(out, bom_str, bom_len);
        return out;
 }
 #endif
@@ -566,11 +593,6 @@ static int has_bom_prefix(const char *data, size_t len,
        return data && bom && (len >= bom_len) && !memcmp(data, bom, bom_len);
 }
 
-static const char utf16_be_bom[] = {'\xFE', '\xFF'};
-static const char utf16_le_bom[] = {'\xFF', '\xFE'};
-static const char utf32_be_bom[] = {'\0', '\0', '\xFE', '\xFF'};
-static const char utf32_le_bom[] = {'\xFF', '\xFE', '\0', '\0'};
-
 int has_prohibited_utf_bom(const char *enc, const char *data, size_t len)
 {
        return (
diff --git a/utf8.h b/utf8.h
index edea55e093a4713dcd0056da9a31b63f0cb51272..84efbfcb1fa163b5b799add81b4464ff6eb88611 100644 (file)
--- a/utf8.h
+++ b/utf8.h
@@ -27,7 +27,7 @@ void strbuf_utf8_replace(struct strbuf *sb, int pos, int width,
 
 #ifndef NO_ICONV
 char *reencode_string_iconv(const char *in, size_t insz,
-                           iconv_t conv, size_t *outsz);
+                           iconv_t conv, size_t bom_len, size_t *outsz);
 char *reencode_string_len(const char *in, size_t insz,
                          const char *out_encoding,
                          const char *in_encoding,
index e4fa9d84cd076770306114ff4f284155a5cdd2a1..ea3cf64d4c399ae84c156b850002459a8ffde72c 100644 (file)
--- a/wrapper.c
+++ b/wrapper.c
@@ -690,3 +690,16 @@ int xgethostname(char *buf, size_t len)
                buf[len - 1] = 0;
        return ret;
 }
+
+int is_empty_or_missing_file(const char *filename)
+{
+       struct stat st;
+
+       if (stat(filename, &st) < 0) {
+               if (errno == ENOENT)
+                       return 1;
+               die_errno(_("could not stat %s"), filename);
+       }
+
+       return !st.st_size;
+}
index 0fe3bcd4cd057b72a61cfc6d46e892ac890f0634..1f564b12d259956fa71fb0dce78c6e4c3c006897 100644 (file)
@@ -2375,10 +2375,10 @@ int require_clean_work_tree(struct repository *r,
        struct lock_file lock_file = LOCK_INIT;
        int err = 0, fd;
 
-       fd = hold_locked_index(&lock_file, 0);
+       fd = repo_hold_locked_index(r, &lock_file, 0);
        refresh_index(r->index, REFRESH_QUIET, NULL, NULL, NULL);
        if (0 <= fd)
-               update_index_if_able(r->index, &lock_file);
+               repo_update_index_if_able(r, &lock_file);
        rollback_lock_file(&lock_file);
 
        if (has_unstaged_changes(r, ignore_submodules)) {