Merge branch 'sg/test-i18ngrep'
authorJunio C Hamano <gitster@pobox.com>
Wed, 21 Feb 2018 20:45:05 +0000 (12:45 -0800)
committerJunio C Hamano <gitster@pobox.com>
Wed, 21 Feb 2018 20:45:05 +0000 (12:45 -0800)
Test fixes.

* sg/test-i18ngrep:
  t: make 'test_i18ngrep' more informative on failure
  t: validate 'test_i18ngrep's parameters
  t: move 'test_i18ncmp' and 'test_i18ngrep' to 'test-lib-functions.sh'
  t5536: let 'test_i18ngrep' read the file without redirection
  t5510: consolidate 'grep' and 'test_i18ngrep' patterns
  t4001: don't run 'git status' upstream of a pipe
  t6022: don't run 'git merge' upstream of a pipe
  t5812: add 'test_i18ngrep's missing filename parameter
  t5541: add 'test_i18ngrep's missing filename parameter

223 files changed:
.clang-format
Documentation/Makefile
Documentation/RelNotes/2.16.2.txt [new file with mode: 0644]
Documentation/RelNotes/2.17.0.txt [new file with mode: 0644]
Documentation/config.txt
Documentation/diff-options.txt
Documentation/git-cat-file.txt
Documentation/git-commit.txt
Documentation/git-daemon.txt
Documentation/git-pack-objects.txt
Documentation/git-read-tree.txt
Documentation/git-rebase.txt
Documentation/git-show.txt
Documentation/git-status.txt
Documentation/git-submodule.txt
Documentation/git.txt
Documentation/gitattributes.txt
Documentation/gitignore.txt
Documentation/gitremote-helpers.txt
Documentation/gitsubmodules.txt
Documentation/rev-list-options.txt
Documentation/technical/api-object-access.txt
Documentation/technical/long-running-process-protocol.txt [new file with mode: 0644]
Documentation/technical/pack-protocol.txt
Documentation/technical/protocol-capabilities.txt
Documentation/technical/repository-version.txt
GIT-VERSION-GEN
INSTALL
Makefile
RelNotes
apply.c
bisect.c
blame.c
builtin/am.c
builtin/cat-file.c
builtin/checkout.c
builtin/clone.c
builtin/commit-tree.c
builtin/commit.c
builtin/describe.c
builtin/fetch-pack.c
builtin/fetch.c
builtin/fsck.c
builtin/gc.c
builtin/hash-object.c
builtin/index-pack.c
builtin/log.c
builtin/merge.c
builtin/mktag.c
builtin/mktree.c
builtin/notes.c
builtin/pack-objects.c
builtin/prune.c
builtin/pull.c
builtin/rebase--helper.c
builtin/receive-pack.c
builtin/repack.c
builtin/replace.c
builtin/reset.c
builtin/rev-list.c
builtin/rev-parse.c
builtin/revert.c
builtin/submodule--helper.c
builtin/tag.c
builtin/unpack-objects.c
builtin/worktree.c
bulk-checkin.c
bundle.c
cache-tree.c
cache.h
ci/lib-travisci.sh
ci/run-linux32-build.sh
ci/run-linux32-docker.sh
ci/run-tests.sh
combine-diff.c
commit.c
commit.h
config.c
connected.c
contrib/coccinelle/strbuf.cocci
contrib/completion/git-completion.bash
contrib/examples/git-difftool.perl
convert.c
convert.h
csum-file.c
csum-file.h
daemon.c
diff-lib.c
diff.c
diff.h
diffcore-pickaxe.c
diffcore-rename.c
dir.c
dir.h
environment.c
fast-import.c
fetch-object.c [new file with mode: 0644]
fetch-object.h [new file with mode: 0644]
fetch-pack.c
fetch-pack.h
git-add--interactive.perl
git-rebase--am.sh
git-rebase--interactive.sh
git-rebase--merge.sh
git-rebase.sh
git-send-email.perl
git-stash.sh
git-submodule.sh
git-svn.perl
hash.h
hashmap.h
http-push.c
http-walker.c
http.c
list-objects-filter-options.c
list-objects-filter-options.h
list-objects.c
log-tree.c
mailinfo.c
match-trees.c
merge-recursive.c
mru.c [deleted file]
mru.h [deleted file]
name-hash.c
notes-cache.c
notes-merge.c
notes-utils.c
notes-utils.h
notes.c
notes.h
object.c
object.h
oidmap.c
pack-bitmap-write.c
pack-check.c
pack-revindex.c
pack-write.c
pack.h
packfile.c
packfile.h
parse-options.c
perl/.gitignore
perl/Git.pm
perl/Git/Error.pm [new file with mode: 0644]
perl/Git/FromCPAN/Error.pm [moved from perl/private-Error.pm with 100% similarity]
perl/Git/FromCPAN/Mail/Address.pm [new file with mode: 0644]
perl/Git/I18N.pm
perl/Git/Mail/Address.pm [new file with mode: 0755]
perl/Makefile [deleted file]
perl/Makefile.PL [deleted file]
preload-index.c
quote.c
quote.h
read-cache.c
ref-filter.c
refs/files-backend.c
refs/packed-backend.c
refs/ref-cache.c
remote-curl.c
replace_object.c
repository.c
rerere.c
revision.c
revision.h
run-command.c
sequencer.c
sequencer.h
setup.c
sha1_file.c
sha1dc_git.h
split-index.c
sub-process.h
submodule.c
t/helper/test-dump-untracked-cache.c
t/helper/test-run-command.c
t/helper/test-wildmatch.c
t/lib-git-daemon.sh
t/lib-submodule-update.sh
t/perf/aggregate.perl
t/perf/p7820-grep-engines.sh
t/perf/p7821-grep-engines-fixed.sh
t/perf/run
t/t0061-run-command.sh
t/t0410-partial-clone.sh [new file with mode: 0755]
t/t1700-split-index.sh
t/t2203-add-intent.sh
t/t3070-wildmatch.sh
t/t3404-rebase-interactive.sh
t/t3405-rebase-malformed.sh
t/t3501-revert-cherry-pick.sh
t/t3512-cherry-pick-submodule.sh
t/t3513-revert-submodule.sh
t/t3701-add-interactive.sh
t/t3903-stash.sh
t/t4052-stat-output.sh
t/t4064-diff-oidfind.sh [new file with mode: 0755]
t/t5500-fetch-pack.sh
t/t5551-http-fetch-smart.sh
t/t5570-git-daemon.sh
t/t5600-clone-fail-cleanup.sh
t/t5601-clone.sh
t/t5616-partial-clone.sh [new file with mode: 0755]
t/t6037-merge-ours-theirs.sh
t/t6120-describe.sh
t/t7500-commit.sh
t/t7505-prepare-commit-msg-hook.sh
t/t7505/expected-rebase-i [new file with mode: 0644]
t/t7505/expected-rebase-p [new file with mode: 0644]
t/t7607-merge-overwrite.sh
t/t9000-addresses.sh [deleted file]
t/t9000/test.pl [deleted file]
t/t9001-send-email.sh
t/test-lib-functions.sh
t/test-lib.sh
trace.c
transport-helper.c
transport.c
transport.h
unpack-trees.c
upload-pack.c
wrap-for-bin.sh
wt-status.c
wt-status.h

index 611ab47..12a89f9 100644 (file)
@@ -163,7 +163,7 @@ PenaltyBreakComment: 10
 PenaltyBreakFirstLessLess: 0
 PenaltyBreakString: 10
 PenaltyExcessCharacter: 100
-PenaltyReturnTypeOnItsOwnLine: 5
+PenaltyReturnTypeOnItsOwnLine: 60
 
 # Don't sort #include's
 SortIncludes: false
index 4ae9ba5..6232143 100644 (file)
@@ -72,6 +72,7 @@ TECH_DOCS += SubmittingPatches
 TECH_DOCS += technical/hash-function-transition
 TECH_DOCS += technical/http-protocol
 TECH_DOCS += technical/index-format
+TECH_DOCS += technical/long-running-process-protocol
 TECH_DOCS += technical/pack-format
 TECH_DOCS += technical/pack-heuristics
 TECH_DOCS += technical/pack-protocol
diff --git a/Documentation/RelNotes/2.16.2.txt b/Documentation/RelNotes/2.16.2.txt
new file mode 100644 (file)
index 0000000..a216466
--- /dev/null
@@ -0,0 +1,30 @@
+Git v2.16.2 Release Notes
+=========================
+
+Fixes since v2.16.1
+-------------------
+
+ * An old regression in "git describe --all $annotated_tag^0" has been
+   fixed.
+
+ * "git svn dcommit" did not take into account the fact that a
+   svn+ssh:// URL with a username@ (typically used for pushing) refers
+   to the same SVN repository without the username@ and failed when
+   svn.pushmergeinfo option is set.
+
+ * "git merge -Xours/-Xtheirs" learned to use our/their version when
+   resolving a conflicting updates to a symbolic link.
+
+ * "git clone $there $here" is allowed even when here directory exists
+   as long as it is an empty directory, but the command incorrectly
+   removed it upon a failure of the operation.
+
+ * "git stash -- <pathspec>" incorrectly blew away untracked files in
+   the directory that matched the pathspec, which has been corrected.
+
+ * "git add -p" was taught to ignore local changes to submodules as
+   they do not interfere with the partial addition of regular changes
+   anyway.
+
+
+Also contains various documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.17.0.txt b/Documentation/RelNotes/2.17.0.txt
new file mode 100644 (file)
index 0000000..1fe7b61
--- /dev/null
@@ -0,0 +1,187 @@
+Git 2.17 Release Notes
+======================
+
+Updates since v2.16
+-------------------
+
+UI, Workflows & Features
+
+ * "diff" family of commands learned "--find-object=<object-id>" option
+   to limit the findings to changes that involve the named object.
+   (merge 4d8c51aa19 sb/diff-blobfind-pickaxe later to maint).
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * More perf tests for threaded grep
+   (merge 7b31b55db1 ab/perf-grep-threads later to maint).
+
+ * "perf" test output can be sent to codespeed server.
+   (merge 19cf57a92e cc/codespeed later to maint).
+
+ * The build procedure for perl/ part has been greatly simplified by
+   weaning ourselves off of MakeMaker.
+
+ * In preparation for implementing narrow/partial clone, the machinery
+   for checking object connectivity used by gc and fsck has been
+   taught that a missing object is OK when it is referenced by a
+   packfile specially marked as coming from trusted repository that
+   promises to make them available on-demand and lazily.
+
+ * The machinery to clone & fetch, which in turn involves packing and
+   unpacking objects, has been told how to omit certain objects using
+   the filtering mechanism introduced by another topic.  It now knows
+   to mark the resulting pack as a promisor pack to tolerate missing
+   objects, laying foundation for "narrow" clones.
+
+ * The first step to getting rid of mru API and using the
+   doubly-linked list API directly instead.
+
+ * Retire mru API as it does not give enough abstraction over
+   underlying list API to be worth it.
+
+ * Rewrite two more "git submodule" subcommands in C.
+
+ * The tracing machinery learned to report tweaking of environment
+   variables as well.
+   (merge 090a09272a nd/trace-with-env later to maint).
+
+ * Update Coccinelle rules to catch and optimize strbuf_addf(&buf, "%s", str)
+   (merge cd9a4b6d93 rs/strbuf-cocci-workaround later to maint).
+
+ * Prevent "clang-format" from breaking line after function return type.
+   (merge a3715d43e8 po/clang-format-functype-weight later to maint).
+
+ * The sequencer infrastructure is shared across "git cherry-pick",
+   "git rebase -i", etc., and has always spawned "git commit" when it
+   needs to create a commit.  It has been taught to do so internally,
+   when able, by reusing the codepath "git commit" itself uses, which
+   gives performance boost for a few tens of percents in some sample
+   scenarios.
+
+ * Push the submodule version of collision-detecting SHA-1 hash
+   implementation a bit harder on builders.
+
+ * Avoid mmapping small files while using packed refs (especially ones
+   with zero size, which would cause later munmap() to fail).
+   (merge ba41a8b600 kg/packed-ref-cache-fix later to maint).
+
+ * Conversion from uchar[20] to struct object_id continues.
+
+ * More tests for wildmatch functions.
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v2.16
+-----------------
+
+ * An old regression in "git describe --all $annotated_tag^0" has been
+   fixed.
+   (merge 1bba00130a dk/describe-all-output-fix later to maint).
+
+ * "git status" after moving a path in the working tree (hence making
+   it appear "removed") and then adding with the -N option (hence
+   making that appear "added") detected it as a rename, but did not
+   report the  old and new pathnames correctly.
+   (merge 176ea74793 nd/ita-wt-renames-in-status later to maint).
+
+ * "git svn dcommit" did not take into account the fact that a
+   svn+ssh:// URL with a username@ (typically used for pushing) refers
+   to the same SVN repository without the username@ and failed when
+   svn.pushmergeinfo option is set.
+   (merge 8aaed892fd jm/svn-pushmergeinfo-fix later to maint).
+
+ * API clean-up around revision traversal.
+   (merge 6fcec2f9ae rs/lose-leak-pending later to maint).
+
+ * "git merge -Xours/-Xtheirs" learned to use our/their version when
+   resolving a conflicting updates to a symbolic link.
+   (merge fd48b46474 jc/merge-symlink-ours-theirs later to maint).
+
+ * "git clone $there $here" is allowed even when here directory exists
+   as long as it is an empty directory, but the command incorrectly
+   removed it upon a failure of the operation.
+   (merge d45420c1c8 jk/abort-clone-with-existing-dest later to maint).
+
+ * "git commit --fixup" did not allow "-m<message>" option to be used
+   at the same time; allow it to annotate resulting commit with more
+   text.
+   (merge 30884c9afc ab/commit-m-with-fixup later to maint).
+
+ * When resetting the working tree files recursively, the working tree
+   of submodules are now also reset to match.
+   (merge 7dcc1f4df8 sb/submodule-update-reset-fix later to maint).
+
+ * "git stash -- <pathspec>" incorrectly blew away untracked files in
+   the directory that matched the pathspec, which has been corrected.
+   (merge bba067d2fa tg/stash-with-pathspec-fix later to maint).
+
+ * Instead of maintaining home-grown email address parsing code, ship
+   a copy of reasonably recent Mail::Address to be used as a fallback
+   in 'git send-email' when the platform lacks it.
+   (merge d60be8acab mm/send-email-fallback-to-local-mail-address later to maint).
+
+ * "git add -p" was taught to ignore local changes to submodules as
+   they do not interfere with the partial addition of regular changes
+   anyway.
+   (merge 12434efc1d nd/add-i-ignore-submodules later to maint).
+
+ * Avoid showing a warning message in the middle of a line of "git
+   diff" output.
+   (merge 4e056c989f nd/diff-flush-before-warning later to maint).
+
+ * The http tracing code, often used to debug connection issues,
+   learned to redact potentially sensitive information from its output
+   so that it can be more safely sharable.
+   (merge 8ba18e6fa4 jt/http-redact-cookies later to maint).
+
+ * Crash fix for a corner case where an error codepath tried to unlock
+   what it did not acquire lock on.
+   (merge 81fcb698e0 mr/packed-ref-store-fix later to maint).
+
+ * The split-index mode had a few corner case bugs fixed.
+   (merge ae59a4e44f tg/split-index-fixes later to maint).
+
+ * Assorted fixes to "git daemon".
+   (merge ed15e58efe jk/daemon-fixes later to maint).
+
+ * Completion of "git merge -s<strategy>" (in contrib/) did not work
+   well in non-C locale.
+   (merge 7cc763aaa3 nd/list-merge-strategy later to maint).
+
+ * Workaround for segfault with more recent versions of SVN.
+   (merge 7f6f75e97a ew/svn-branch-segfault-fix later to maint).
+
+ * Plug recently introduced leaks in fsck.
+   (merge ba3a08ca0e jt/fsck-code-cleanup later to maint).
+
+ * "git pull --rebase" did not pass verbosity setting down when
+   recursing into a submodule.
+   (merge a56771a668 sb/pull-rebase-submodule later to maint).
+
+ * The way "git reset --hard" reports the commit the updated HEAD
+   points at is made consistent with the way how the commit title is
+   generated by the other parts of the system.  This matters when the
+   title is spread across physically multiple lines.
+   (merge 1cf823fb68 tg/reset-hard-show-head-with-pretty later to maint).
+
+ * Other minor doc, test and build updates and code cleanups.
+   (merge e2a5a028c7 bw/oidmap-autoinit later to maint).
+   (merge f0a6068a9f ys/bisect-object-id-missing-conversion-fix later to maint).
+   (merge 30221a3389 as/read-tree-prefix-doc-fix later to maint).
+   (merge 9bd2ce5432 ab/doc-cat-file-e-still-shows-errors later to maint).
+   (merge ec3b4b06f8 cl/t9001-cleanup later to maint).
+   (merge e1b3f3dd38 ks/submodule-doc-updates later to maint).
+   (merge fbac558a9b rs/describe-unique-abbrev later to maint).
+   (merge 8462ff43e4 tb/crlf-conv-flags later to maint).
+   (merge 7d68bb0766 rb/hashmap-h-compilation-fix later to maint).
+   (merge 3449847168 cc/sha1-file-name later to maint).
+   (merge ad622a256f ds/use-get-be64 later to maint).
+   (merge f919ffebed sg/cocci-move-array later to maint).
+   (merge 4e801463c7 jc/mailinfo-cleanup-fix later to maint).
+   (merge ef5b3a6c5e nd/shared-index-fix later to maint).
+   (merge 9f5258cbb8 tz/doc-show-defaults-to-head later to maint).
+   (merge b780e4407d jc/worktree-add-short-help later to maint).
+   (merge ae239fc8e5 rs/cocci-strbuf-addf-to-addstr later to maint).
+   (merge 2e22a85e5c nd/ignore-glob-doc-update later to maint).
index 0e25b2c..f57e9cf 100644 (file)
@@ -3343,6 +3343,10 @@ uploadpack.packObjectsHook::
        was run. I.e., `upload-pack` will feed input intended for
        `pack-objects` to the hook, and expects a completed packfile on
        stdout.
+
+uploadpack.allowFilter::
+       If this option is set, `upload-pack` will advertise partial
+       clone and partial fetch object filtering.
 +
 Note that this configuration variable is ignored if it is seen in the
 repository-level config (this is a safety measure against fetching from
index 743af97..c330c01 100644 (file)
@@ -508,6 +508,15 @@ occurrences of that string did not change).
 See the 'pickaxe' entry in linkgit:gitdiffcore[7] for more
 information.
 
+--find-object=<object-id>::
+       Look for differences that change the number of occurrences of
+       the specified object. Similar to `-S`, just the argument is different
+       in that it doesn't search for a specific string but for a specific
+       object id.
++
+The object can be a blob or a submodule commit. It implies the `-t` option in
+`git-log` to also find trees.
+
 --pickaxe-all::
        When `-S` or `-G` finds a change, show all the changes in that
        changeset, not just the files that contain the change
@@ -516,6 +525,7 @@ information.
 --pickaxe-regex::
        Treat the <string> given to `-S` as an extended POSIX regular
        expression to match.
+
 endif::git-format-patch[]
 
 -O<orderfile>::
index fb09cd6..f90f09b 100644 (file)
@@ -42,8 +42,9 @@ OPTIONS
        <object>.
 
 -e::
-       Suppress all output; instead exit with zero status if <object>
-       exists and is a valid object.
+       Exit with zero status if <object> exists and is a valid
+       object. If <object> is of an invalid format exit with non-zero and
+       emits an error on stderr.
 
 -p::
        Pretty-print the contents of <object> based on its type.
@@ -168,7 +169,7 @@ If `-t` is specified, one of the <type>.
 
 If `-s` is specified, the size of the <object> in bytes.
 
-If `-e` is specified, no output.
+If `-e` is specified, no output, unless the <object> is malformed.
 
 If `-p` is specified, the contents of <object> are pretty-printed.
 
index 8c74a2c..f970a43 100644 (file)
@@ -144,6 +144,8 @@ OPTIONS
        Use the given <msg> as the commit message.
        If multiple `-m` options are given, their values are
        concatenated as separate paragraphs.
++
+The `-m` option is mutually exclusive with `-c`, `-C`, and `-F`.
 
 -t <file>::
 --template=<file>::
index 3c91db7..56d54a4 100644 (file)
@@ -20,6 +20,7 @@ SYNOPSIS
             [--inetd |
              [--listen=<host_or_ipaddr>] [--port=<n>]
              [--user=<user> [--group=<group>]]]
+            [--log-destination=(stderr|syslog|none)]
             [<directory>...]
 
 DESCRIPTION
@@ -80,7 +81,8 @@ OPTIONS
        do not have the 'git-daemon-export-ok' file.
 
 --inetd::
-       Have the server run as an inetd service. Implies --syslog.
+       Have the server run as an inetd service. Implies --syslog (may be
+       overridden with `--log-destination=`).
        Incompatible with --detach, --port, --listen, --user and --group
        options.
 
@@ -110,8 +112,28 @@ OPTIONS
        zero for no limit.
 
 --syslog::
-       Log to syslog instead of stderr. Note that this option does not imply
-       --verbose, thus by default only error conditions will be logged.
+       Short for `--log-destination=syslog`.
+
+--log-destination=<destination>::
+       Send log messages to the specified destination.
+       Note that this option does not imply --verbose,
+       thus by default only error conditions will be logged.
+       The <destination> must be one of:
++
+--
+stderr::
+       Write to standard error.
+       Note that if `--detach` is specified,
+       the process disconnects from the real standard error,
+       making this destination effectively equivalent to `none`.
+syslog::
+       Write to syslog, using the `git-daemon` identifier.
+none::
+       Disable all logging.
+--
++
+The default destination is `syslog` if `--inetd` or `--detach` is specified,
+otherwise `stderr`.
 
 --user-path::
 --user-path=<path>::
index aa403d0..81bc490 100644 (file)
@@ -255,6 +255,17 @@ a missing object is encountered.  This is the default action.
 The form '--missing=allow-any' will allow object traversal to continue
 if a missing object is encountered.  Missing objects will silently be
 omitted from the results.
++
+The form '--missing=allow-promisor' is like 'allow-any', but will only
+allow object traversal to continue for EXPECTED promisor missing objects.
+Unexpected missing object will raise an error.
+
+--exclude-promisor-objects::
+       Omit objects that are known to be in the promisor remote.  (This
+       option has the purpose of operating only on locally created objects,
+       so that when we repack, we still maintain a distinction between
+       locally created objects [without .promisor] and objects from the
+       promisor remote [with .promisor].)  This is used with partial clone.
 
 SEE ALSO
 --------
index 72bd809..f2a07d5 100644 (file)
@@ -81,12 +81,11 @@ OPTIONS
 * when both sides add a path identically.  The resolution
   is to add that path.
 
---prefix=<prefix>/::
+--prefix=<prefix>::
        Keep the current index contents, and read the contents
        of the named tree-ish under the directory at `<prefix>`.
        The command will refuse to overwrite entries that already
-       existed in the original index file. Note that the `<prefix>/`
-       value must end with a slash.
+       existed in the original index file.
 
 --exclude-per-directory=<gitignore>::
        When running the command with `-u` and `-m` options, the
index 8a861c1..d713951 100644 (file)
@@ -244,6 +244,11 @@ leave out at most one of A and B, in which case it defaults to HEAD.
        Keep the commits that do not change anything from its
        parents in the result.
 
+--allow-empty-message::
+       By default, rebasing commits with an empty message will fail.
+       This option overrides that behavior, allowing commits with empty
+       messages to be rebased.
+
 --skip::
        Restart the rebasing process by skipping the current patch.
 
index 82a4125..e73ef54 100644 (file)
@@ -9,7 +9,7 @@ git-show - Show various types of objects
 SYNOPSIS
 --------
 [verse]
-'git show' [options] <object>...
+'git show' [options] [<object>...]
 
 DESCRIPTION
 -----------
@@ -35,7 +35,7 @@ This manual page describes only the most frequently used options.
 OPTIONS
 -------
 <object>...::
-       The names of objects to show.
+       The names of objects to show (defaults to 'HEAD').
        For a more complete list of ways to spell object names, see
        "SPECIFYING REVISIONS" section in linkgit:gitrevisions[7].
 
index 81cab9a..72bfb87 100644 (file)
@@ -149,14 +149,15 @@ the status.relativePaths config option below.
 Short Format
 ~~~~~~~~~~~~
 
-In the short-format, the status of each path is shown as
+In the short-format, the status of each path is shown as one of these
+forms
 
-       XY PATH1 -> PATH2
+       XY PATH
+       XY ORIG_PATH -> PATH
 
-where `PATH1` is the path in the `HEAD`, and the " `-> PATH2`" part is
-shown only when `PATH1` corresponds to a different path in the
-index/worktree (i.e. the file is renamed). The `XY` is a two-letter
-status code.
+where `ORIG_PATH` is where the renamed/copied contents came
+from. `ORIG_PATH` is only shown when the entry is renamed or
+copied. The `XY` is a two-letter status code.
 
 The fields (including the `->`) are separated from each other by a
 single space. If a filename contains whitespace or other nonprintable
@@ -192,6 +193,8 @@ in which case `XY` are `!!`.
     [MARC]           index and work tree matches
     [ MARC]     M    work tree changed since index
     [ MARC]     D    deleted in work tree
+    [ D]        R    renamed in work tree
+    [ D]        C    copied in work tree
     -------------------------------------------------
     D           D    unmerged, both deleted
     A           U    unmerged, added by us
@@ -309,13 +312,13 @@ Renamed or copied entries have the following format:
                of similarity between the source and target of the
                move or copy). For example "R100" or "C75".
     <path>      The pathname.  In a renamed/copied entry, this
-               is the path in the index and in the working tree.
+               is the target path.
     <sep>       When the `-z` option is used, the 2 pathnames are separated
                with a NUL (ASCII 0x00) byte; otherwise, a tab (ASCII 0x09)
                byte separates them.
-    <origPath>  The pathname in the commit at HEAD.  This is only
-               present in a renamed/copied entry, and tells
-               where the renamed/copied contents came from.
+    <origPath>  The pathname in the commit at HEAD or in the index.
+               This is only present in a renamed/copied entry, and
+               tells where the renamed/copied contents came from.
     --------------------------------------------------------
 
 Unmerged entries have the following format; the first character is
index ff61200..71c5618 100644 (file)
@@ -70,8 +70,8 @@ status [--cached] [--recursive] [--] [<path>...]::
        Show the status of the submodules. This will print the SHA-1 of the
        currently checked out commit for each submodule, along with the
        submodule path and the output of 'git describe' for the
-       SHA-1. Each SHA-1 will be prefixed with `-` if the submodule is not
-       initialized, `+` if the currently checked out submodule commit
+       SHA-1. Each SHA-1 will possibly be prefixed with `-` if the submodule is
+       not initialized, `+` if the currently checked out submodule commit
        does not match the SHA-1 found in the index of the containing
        repository and `U` if the submodule has merge conflicts.
 +
@@ -132,15 +132,15 @@ expects by cloning missing submodules and updating the working tree of
 the submodules. The "updating" can be done in several ways depending
 on command line options and the value of `submodule.<name>.update`
 configuration variable. The command line option takes precedence over
-the configuration variable. if neither is given, a checkout is performed.
-update procedures supported both from the command line as well as setting
-`submodule.<name>.update`:
+the configuration variable. If neither is given, a 'checkout' is performed.
+The 'update' procedures supported both from the command line as well as
+through the `submodule.<name>.update` configuration are:
 
        checkout;; the commit recorded in the superproject will be
            checked out in the submodule on a detached HEAD.
 +
 If `--force` is specified, the submodule will be checked out (using
-`git checkout --force` if appropriate), even if the commit specified
+`git checkout --force`), even if the commit specified
 in the index of the containing repository already matches the commit
 checked out in the submodule.
 
@@ -150,8 +150,8 @@ checked out in the submodule.
        merge;; the commit recorded in the superproject will be merged
            into the current branch in the submodule.
 
-The following procedures are only available via the `submodule.<name>.update`
-configuration variable:
+The following 'update' procedures are only available via the
+`submodule.<name>.update` configuration variable:
 
        custom command;; arbitrary shell command that takes a single
            argument (the sha1 of the commit recorded in the
index 3f4161a..8163b57 100644 (file)
@@ -646,6 +646,16 @@ of clones and fetches.
        variable.
        See `GIT_TRACE` for available trace output options.
 
+`GIT_TRACE_CURL_NO_DATA`::
+       When a curl trace is enabled (see `GIT_TRACE_CURL` above), do not dump
+       data (that is, only dump info lines and headers).
+
+`GIT_REDACT_COOKIES`::
+       This can be set to a comma-separated list of strings. When a curl trace
+       is enabled (see `GIT_TRACE_CURL` above), whenever a "Cookies:" header
+       sent by the client is dumped, values of cookies whose key is in that
+       list (case-sensitive) are redacted.
+
 `GIT_LITERAL_PATHSPECS`::
        Setting this variable to `1` will cause Git to treat all
        pathspecs literally, rather than as glob patterns. For example,
index 30687de..c21f5ca 100644 (file)
@@ -392,46 +392,14 @@ Long Running Filter Process
 If the filter command (a string value) is defined via
 `filter.<driver>.process` then Git can process all blobs with a
 single filter invocation for the entire life of a single Git
-command. This is achieved by using a packet format (pkt-line,
-see technical/protocol-common.txt) based protocol over standard
-input and standard output as follows. All packets, except for the
-"*CONTENT" packets and the "0000" flush packet, are considered
-text and therefore are terminated by a LF.
-
-Git starts the filter when it encounters the first file
-that needs to be cleaned or smudged. After the filter started
-Git sends a welcome message ("git-filter-client"), a list of supported
-protocol version numbers, and a flush packet. Git expects to read a welcome
-response message ("git-filter-server"), exactly one protocol version number
-from the previously sent list, and a flush packet. All further
-communication will be based on the selected version. The remaining
-protocol description below documents "version=2". Please note that
-"version=42" in the example below does not exist and is only there
-to illustrate how the protocol would look like with more than one
-version.
-
-After the version negotiation Git sends a list of all capabilities that
-it supports and a flush packet. Git expects to read a list of desired
-capabilities, which must be a subset of the supported capabilities list,
-and a flush packet as response:
-------------------------
-packet:          git> git-filter-client
-packet:          git> version=2
-packet:          git> version=42
-packet:          git> 0000
-packet:          git< git-filter-server
-packet:          git< version=2
-packet:          git< 0000
-packet:          git> capability=clean
-packet:          git> capability=smudge
-packet:          git> capability=not-yet-invented
-packet:          git> 0000
-packet:          git< capability=clean
-packet:          git< capability=smudge
-packet:          git< 0000
-------------------------
-Supported filter capabilities in version 2 are "clean", "smudge",
-and "delay".
+command. This is achieved by using the long-running process protocol
+(described in technical/long-running-process-protocol.txt).
+
+When Git encounters the first file that needs to be cleaned or smudged,
+it starts the filter and performs the handshake. In the handshake, the
+welcome message sent by Git is "git-filter-client", only version 2 is
+suppported, and the supported capabilities are "clean", "smudge", and
+"delay".
 
 Afterwards Git sends a list of "key=value" pairs terminated with
 a flush packet. The list will contain at least the filter command
@@ -517,12 +485,6 @@ the protocol then Git will stop the filter process and restart it
 with the next file that needs to be processed. Depending on the
 `filter.<driver>.required` flag Git will interpret that as error.
 
-After the filter has processed a command it is expected to wait for
-a "key=value" list containing the next command. Git will close
-the command pipe on exit. The filter is expected to detect EOF
-and exit gracefully on its own. Git will wait until the filter
-process has stopped.
-
 Delay
 ^^^^^
 
index 63260f0..ff5d7f9 100644 (file)
@@ -102,12 +102,11 @@ PATTERN FORMAT
    (relative to the toplevel of the work tree if not from a
    `.gitignore` file).
 
- - Otherwise, Git treats the pattern as a shell glob suitable
-   for consumption by fnmatch(3) with the FNM_PATHNAME flag:
-   wildcards in the pattern will not match a / in the pathname.
-   For example, "Documentation/{asterisk}.html" matches
-   "Documentation/git.html" but not "Documentation/ppc/ppc.html"
-   or "tools/perf/Documentation/perf.html".
+ - Otherwise, Git treats the pattern as a shell glob: "`*`" matches
+   anything except "`/`", "`?`" matches any one character except "`/`"
+   and "`[]`" matches one character in a selected range. See
+   fnmatch(3) and the FNM_PATHNAME flag for a more detailed
+   description.
 
  - A leading slash matches the beginning of the pathname.
    For example, "/{asterisk}.c" matches "cat-file.c" but not
index 4a584f3..4b8c93e 100644 (file)
@@ -466,6 +466,13 @@ set by Git if the remote helper has the 'option' capability.
        Transmit <string> as a push option. As the push option
        must not contain LF or NUL characters, the string is not encoded.
 
+'option from-promisor' {'true'|'false'}::
+       Indicate that these objects are being fetched from a promisor.
+
+'option no-dependents' {'true'|'false'}::
+       Indicate that only the objects wanted need to be fetched, not
+       their dependents.
+
 SEE ALSO
 --------
 linkgit:git-remote[1]
index 46cf120..4d6c177 100644 (file)
@@ -36,8 +36,8 @@ The `gitlink` entry contains the object name of the commit that the
 superproject expects the submodule’s working directory to be at.
 
 The section `submodule.foo.*` in the `.gitmodules` file gives additional
-hints to Gits porcelain layer such as where to obtain the submodule via
-the `submodule.foo.url` setting.
+hints to Git's porcelain layer. For example, the `submodule.foo.url`
+setting specifies where to obtain the submodule.
 
 Submodules can be used for at least two different use cases:
 
@@ -51,18 +51,21 @@ Submodules can be used for at least two different use cases:
 
 2. Splitting a (logically single) project into multiple
    repositories and tying them back together. This can be used to
-   overcome current limitations of Gits implementation to have
+   overcome current limitations of Git's implementation to have
    finer grained access:
 
-    * Size of the git repository:
+    * Size of the Git repository:
       In its current form Git scales up poorly for large repositories containing
       content that is not compressed by delta computation between trees.
-      However you can also use submodules to e.g. hold large binary assets
-      and these repositories are then shallowly cloned such that you do not
+      For example, you can use submodules to hold large binary assets
+      and these repositories can be shallowly cloned such that you do not
       have a large history locally.
     * Transfer size:
       In its current form Git requires the whole working tree present. It
       does not allow partial trees to be transferred in fetch or clone.
+      If the project you work on consists of multiple repositories tied
+      together as submodules in a superproject, you can avoid fetching the
+      working trees of the repositories you are not interested in.
     * Access control:
       By restricting user access to submodules, this can be used to implement
       read/write policies for different users.
@@ -73,9 +76,10 @@ The configuration of submodules
 Submodule operations can be configured using the following mechanisms
 (from highest to lowest precedence):
 
- * The command line for those commands that support taking submodule specs.
-   Most commands have a boolean flag '--recurse-submodules' whether to
-   recurse into submodules. Examples are `ls-files` or `checkout`.
+ * The command line for those commands that support taking submodules
+   as part of their pathspecs. Most commands have a boolean flag
+   `--recurse-submodules` which specify whether to recurse into submodules.
+   Examples are `grep` and `checkout`.
    Some commands take enums, such as `fetch` and `push`, where you can
    specify how submodules are affected.
 
@@ -87,8 +91,8 @@ Submodule operations can be configured using the following mechanisms
 For example an effect from the submodule's `.gitignore` file
 would be observed when you run `git status --ignore-submodules=none` in
 the superproject. This collects information from the submodule's working
-directory by running `status` in the submodule, which does pay attention
-to its `.gitignore` file.
+directory by running `status` in the submodule while paying attention
+to the `.gitignore` file of the submodule.
 +
 The submodule's `$GIT_DIR/config` file would come into play when running
 `git push --recurse-submodules=check` in the superproject, as this would
@@ -97,20 +101,20 @@ remotes are configured in the submodule as usual in the `$GIT_DIR/config`
 file.
 
  * The configuration file `$GIT_DIR/config` in the superproject.
-   Typical configuration at this place is controlling if a submodule
-   is recursed into at all via the `active` flag for example.
+   Git only recurses into active submodules (see "ACTIVE SUBMODULES"
+   section below).
 +
 If the submodule is not yet initialized, then the configuration
-inside the submodule does not exist yet, so configuration where to
+inside the submodule does not exist yet, so where to
 obtain the submodule from is configured here for example.
 
- * the `.gitmodules` file inside the superproject. Additionally to the
-   required mapping between submodule's name and path, a project usually
+ * The `.gitmodules` file inside the superproject. A project usually
    uses this file to suggest defaults for the upstream collection
-   of repositories.
+   of repositories for the mapping that is required between a
+   submodule's name and its path.
 +
-This file mainly serves as the mapping between name and path in
-the superproject, such that the submodule's git directory can be
+This file mainly serves as the mapping between the name and path of submodules
+in the superproject, such that the submodule's Git directory can be
 located.
 +
 If the submodule has never been initialized, this is the only place
@@ -137,8 +141,8 @@ directory is automatically moved to `$GIT_DIR/modules/<name>/`
 of the superproject.
 
  * Deinitialized submodule: A `gitlink`, and a `.gitmodules` entry,
-but no submodule working directory. The submodule’s git directory
-may be there as after deinitializing the git directory is kept around.
+but no submodule working directory. The submodule’s Git directory
+may be there as after deinitializing the Git directory is kept around.
 The directory which is supposed to be the working directory is empty instead.
 +
 A submodule can be deinitialized by running `git submodule deinit`.
@@ -160,6 +164,60 @@ from another repository.
 To completely remove a submodule, manually delete
 `$GIT_DIR/modules/<name>/`.
 
+ACTIVE SUBMODULES
+-----------------
+
+A submodule is considered active,
+
+  (a) if `submodule.<name>.active` is set to `true`
+     or
+  (b) if the submodule's path matches the pathspec in `submodule.active`
+     or
+  (c) if `submodule.<name>.url` is set.
+
+and these are evaluated in this order.
+
+For example:
+
+  [submodule "foo"]
+    active = false
+    url = https://example.org/foo
+  [submodule "bar"]
+    active = true
+    url = https://example.org/bar
+  [submodule "baz"]
+    url = https://example.org/baz
+
+In the above config only the submodule 'bar' and 'baz' are active,
+'bar' due to (a) and 'baz' due to (c). 'foo' is inactive because
+(a) takes precedence over (c)
+
+Note that (c) is a historical artefact and will be ignored if the
+(a) and (b) specify that the submodule is not active. In other words,
+if we have an `submodule.<name>.active` set to `false` or if the
+submodule's path is excluded in the pathspec in `submodule.active`, the
+url doesn't matter whether it is present or not. This is illustrated in
+the example that follows.
+
+  [submodule "foo"]
+    active = true
+    url = https://example.org/foo
+  [submodule "bar"]
+    url = https://example.org/bar
+  [submodule "baz"]
+    url = https://example.org/baz
+  [submodule "bob"]
+    ignore = true
+  [submodule]
+    active = b*
+    active = :(exclude) baz
+
+In here all submodules except 'baz' (foo, bar, bob) are active.
+'foo' due to its own active flag and all the others due to the
+submodule active pathspec, which specifies that any submodule
+starting with 'b' except 'baz' are also active, regardless of the
+presence of the .url field.
+
 Workflow for a third party library
 ----------------------------------
 
index 22f5c9b..7b27363 100644 (file)
@@ -750,10 +750,21 @@ The form '--missing=allow-any' will allow object traversal to continue
 if a missing object is encountered.  Missing objects will silently be
 omitted from the results.
 +
+The form '--missing=allow-promisor' is like 'allow-any', but will only
+allow object traversal to continue for EXPECTED promisor missing objects.
+Unexpected missing objects will raise an error.
++
 The form '--missing=print' is like 'allow-any', but will also print a
 list of the missing objects.  Object IDs are prefixed with a ``?'' character.
 endif::git-rev-list[]
 
+--exclude-promisor-objects::
+       (For internal use only.)  Prefilter object traversal at
+       promisor boundary.  This is used with partial clone.  This is
+       stronger than `--missing=allow-promisor` because it limits the
+       traversal, rather than just silencing errors about missing
+       objects.
+
 --no-walk[=(sorted|unsorted)]::
        Only show the given commits, but do not traverse their ancestors.
        This has no effect if a range is specified. If the argument
index 03bb0e9..a1162e5 100644 (file)
@@ -7,7 +7,7 @@ Talk about <sha1_file.c> and <object.h> family, things like
 * read_object_with_reference()
 * has_sha1_file()
 * write_sha1_file()
-* pretend_sha1_file()
+* pretend_object_file()
 * lookup_{object,commit,tag,blob,tree}
 * parse_{object,commit,tag,blob,tree}
 * Use of object flags
diff --git a/Documentation/technical/long-running-process-protocol.txt b/Documentation/technical/long-running-process-protocol.txt
new file mode 100644 (file)
index 0000000..aa0aa9a
--- /dev/null
@@ -0,0 +1,50 @@
+Long-running process protocol
+=============================
+
+This protocol is used when Git needs to communicate with an external
+process throughout the entire life of a single Git command. All
+communication is in pkt-line format (see technical/protocol-common.txt)
+over standard input and standard output.
+
+Handshake
+---------
+
+Git starts by sending a welcome message (for example,
+"git-filter-client"), a list of supported protocol version numbers, and
+a flush packet. Git expects to read the welcome message with "server"
+instead of "client" (for example, "git-filter-server"), exactly one
+protocol version number from the previously sent list, and a flush
+packet. All further communication will be based on the selected version.
+The remaining protocol description below documents "version=2". Please
+note that "version=42" in the example below does not exist and is only
+there to illustrate how the protocol would look like with more than one
+version.
+
+After the version negotiation Git sends a list of all capabilities that
+it supports and a flush packet. Git expects to read a list of desired
+capabilities, which must be a subset of the supported capabilities list,
+and a flush packet as response:
+------------------------
+packet:          git> git-filter-client
+packet:          git> version=2
+packet:          git> version=42
+packet:          git> 0000
+packet:          git< git-filter-server
+packet:          git< version=2
+packet:          git< 0000
+packet:          git> capability=clean
+packet:          git> capability=smudge
+packet:          git> capability=not-yet-invented
+packet:          git> 0000
+packet:          git< capability=clean
+packet:          git< capability=smudge
+packet:          git< 0000
+------------------------
+
+Shutdown
+--------
+
+Git will close
+the command pipe on exit. The filter is expected to detect EOF
+and exit gracefully on its own. Git will wait until the filter
+process has stopped.
index cd31edc..7fee6b7 100644 (file)
@@ -241,6 +241,7 @@ out of what the server said it could do with the first 'want' line.
   upload-request    =  want-list
                       *shallow-line
                       *1depth-request
+                      [filter-request]
                       flush-pkt
 
   want-list         =  first-want
@@ -256,6 +257,8 @@ out of what the server said it could do with the first 'want' line.
   additional-want   =  PKT-LINE("want" SP obj-id)
 
   depth             =  1*DIGIT
+
+  filter-request    =  PKT-LINE("filter" SP filter-spec)
 ----
 
 Clients MUST send all the obj-ids it wants from the reference
@@ -278,6 +281,11 @@ complete those commits. Commits whose parents are not received as a
 result are defined as shallow and marked as such in the server. This
 information is sent back to the client in the next step.
 
+The client can optionally request that pack-objects omit various
+objects from the packfile 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.
+
 Once all the 'want's and 'shallow's (and optional 'deepen') are
 transferred, clients MUST send a flush-pkt, to tell the server side
 that it is done sending the list.
index 26dcc6f..332d209 100644 (file)
@@ -309,3 +309,11 @@ to accept a signed push certificate, and asks the <nonce> to be
 included in the push certificate.  A send-pack client MUST NOT
 send a push-cert packet unless the receive-pack server advertises
 this capability.
+
+filter
+------
+
+If the upload-pack server advertises the 'filter' capability,
+fetch-pack may send "filter" commands to request a partial clone
+or partial fetch and request that the server omit various objects
+from the packfile.
index 00ad379..e03eacc 100644 (file)
@@ -86,3 +86,15 @@ for testing format-1 compatibility.
 When the config key `extensions.preciousObjects` is set to `true`,
 objects in the repository MUST NOT be deleted (e.g., by `git-prune` or
 `git repack -d`).
+
+`partialclone`
+~~~~~~~~~~~~~~
+
+When the config key `extensions.partialclone` is set, it indicates
+that the repo was created with a partial clone (or later performed
+a partial fetch) and that the remote may have omitted sending
+certain unwanted objects.  Such a remote is called a "promisor remote"
+and it promises that all such omitted objects can be fetched from it
+in the future.
+
+The value of this key is the name of the promisor remote.
index 470f7b7..0c86f1c 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v2.16.1
+DEF_VER=v2.16.GIT
 
 LF='
 '
diff --git a/INSTALL b/INSTALL
index ffb071e..808e07b 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -84,9 +84,24 @@ Issues of note:
 
        GIT_EXEC_PATH=`pwd`
        PATH=`pwd`:$PATH
-       GITPERLLIB=`pwd`/perl/blib/lib
+       GITPERLLIB=`pwd`/perl/build/lib
        export GIT_EXEC_PATH PATH GITPERLLIB
 
+ - By default (unless NO_PERL is provided) Git will ship various perl
+   scripts & libraries it needs. However, for simplicity it doesn't
+   use the ExtUtils::MakeMaker toolchain to decide where to place the
+   perl libraries. Depending on the system this can result in the perl
+   libraries not being where you'd like them if they're expected to be
+   used by things other than Git itself.
+
+   Manually supplying a perllibdir prefix should fix this, if this is
+   a problem you care about, e.g.:
+
+       prefix=/usr perllibdir=/usr/$(/usr/bin/perl -MConfig -wle 'print substr $Config{installsitelib}, 1 + length $Config{siteprefixexp}')
+
+   Will result in e.g. perllibdir=/usr/share/perl/5.26.1 on Debian,
+   perllibdir=/usr/share/perl5 (which we'd use by default) on CentOS.
+
  - Git is reasonably self-sufficient, but does depend on a few external
    programs and libraries.  Git can be used without most of them by adding
    the approriate "NO_<LIBRARY>=YesPlease" to the make command line or
index 1a9b23b..c56fdc1 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -294,9 +294,6 @@ all::
 #
 # Define PERL_PATH to the path of your Perl binary (usually /usr/bin/perl).
 #
-# Define NO_PERL_MAKEMAKER if you cannot use Makefiles generated by perl's
-# MakeMaker (e.g. using ActiveState under Cygwin).
-#
 # Define NO_PERL if you do not want Perl scripts or libraries at all.
 #
 # Define PYTHON_PATH to the path of your Python binary (often /usr/bin/python
@@ -479,6 +476,7 @@ gitexecdir = libexec/git-core
 mergetoolsdir = $(gitexecdir)/mergetools
 sharedir = $(prefix)/share
 gitwebdir = $(sharedir)/gitweb
+perllibdir = $(sharedir)/perl5
 localedir = $(sharedir)/locale
 template_dir = share/git-core/templates
 htmldir = $(prefix)/share/doc/git-doc
@@ -492,7 +490,7 @@ mandir_relative = $(patsubst $(prefix)/%,%,$(mandir))
 infodir_relative = $(patsubst $(prefix)/%,%,$(infodir))
 htmldir_relative = $(patsubst $(prefix)/%,%,$(htmldir))
 
-export prefix bindir sharedir sysconfdir gitwebdir localedir
+export prefix bindir sharedir sysconfdir gitwebdir perllibdir localedir
 
 CC = cc
 AR = ar
@@ -804,6 +802,7 @@ LIB_OBJS += ewah/ewah_bitmap.o
 LIB_OBJS += ewah/ewah_io.o
 LIB_OBJS += ewah/ewah_rlw.o
 LIB_OBJS += exec_cmd.o
+LIB_OBJS += fetch-object.o
 LIB_OBJS += fetch-pack.o
 LIB_OBJS += fsck.o
 LIB_OBJS += fsmonitor.o
@@ -832,7 +831,6 @@ LIB_OBJS += merge.o
 LIB_OBJS += merge-blobs.o
 LIB_OBJS += merge-recursive.o
 LIB_OBJS += mergesort.o
-LIB_OBJS += mru.o
 LIB_OBJS += name-hash.o
 LIB_OBJS += notes.o
 LIB_OBJS += notes-cache.o
@@ -1515,7 +1513,9 @@ else
        LIB_OBJS += sha1dc_git.o
 ifdef DC_SHA1_EXTERNAL
        ifdef DC_SHA1_SUBMODULE
+               ifneq ($(DC_SHA1_SUBMODULE),auto)
 $(error Only set DC_SHA1_EXTERNAL or DC_SHA1_SUBMODULE, not both)
+               endif
        endif
        BASIC_CFLAGS += -DDC_SHA1_EXTERNAL
        EXTLIBS += -lsha1detectcoll
@@ -1543,9 +1543,6 @@ ifdef SHA1_MAX_BLOCK_SIZE
        LIB_OBJS += compat/sha1-chunked.o
        BASIC_CFLAGS += -DSHA1_MAX_BLOCK_SIZE="$(SHA1_MAX_BLOCK_SIZE)"
 endif
-ifdef NO_PERL_MAKEMAKER
-       export NO_PERL_MAKEMAKER
-endif
 ifdef NO_HSTRERROR
        COMPAT_CFLAGS += -DNO_HSTRERROR
        COMPAT_OBJS += compat/hstrerror.o
@@ -1732,8 +1729,10 @@ ETC_GITATTRIBUTES_SQ = $(subst ','\'',$(ETC_GITATTRIBUTES))
 DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
 bindir_SQ = $(subst ','\'',$(bindir))
 bindir_relative_SQ = $(subst ','\'',$(bindir_relative))
+mandir_SQ = $(subst ','\'',$(mandir))
 mandir_relative_SQ = $(subst ','\'',$(mandir_relative))
 infodir_relative_SQ = $(subst ','\'',$(infodir_relative))
+perllibdir_SQ = $(subst ','\'',$(perllibdir))
 localedir_SQ = $(subst ','\'',$(localedir))
 gitexecdir_SQ = $(subst ','\'',$(gitexecdir))
 template_dir_SQ = $(subst ','\'',$(template_dir))
@@ -1843,9 +1842,6 @@ all::
 ifndef NO_TCLTK
        $(QUIET_SUBDIR0)git-gui $(QUIET_SUBDIR1) gitexecdir='$(gitexec_instdir_SQ)' all
        $(QUIET_SUBDIR0)gitk-git $(QUIET_SUBDIR1) all
-endif
-ifndef NO_PERL
-       $(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' localedir='$(localedir_SQ)' all
 endif
        $(QUIET_SUBDIR0)templates $(QUIET_SUBDIR1) SHELL_PATH='$(SHELL_PATH_SQ)' PERL_PATH='$(PERL_PATH_SQ)'
 
@@ -1928,7 +1924,8 @@ common-cmds.h: $(wildcard Documentation/git-*.txt)
 
 SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):$(GIT_VERSION):\
        $(localedir_SQ):$(NO_CURL):$(USE_GETTEXT_SCHEME):$(SANE_TOOL_PATH_SQ):\
-       $(gitwebdir_SQ):$(PERL_PATH_SQ):$(SANE_TEXT_GREP):$(PAGER_ENV)
+       $(gitwebdir_SQ):$(PERL_PATH_SQ):$(SANE_TEXT_GREP):$(PAGER_ENV):\
+       $(perllibdir_SQ)
 define cmd_munge_script
 $(RM) $@ $@+ && \
 sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
@@ -1972,23 +1969,12 @@ git.res: git.rc GIT-VERSION-FILE
 $(SCRIPT_PERL_GEN): GIT-BUILD-OPTIONS
 
 ifndef NO_PERL
-$(SCRIPT_PERL_GEN): perl/perl.mak
+$(SCRIPT_PERL_GEN):
 
-perl/perl.mak: perl/PM.stamp
-
-perl/PM.stamp: FORCE
-       @$(FIND) perl -type f -name '*.pm' | sort >$@+ && \
-       $(PERL_PATH) -V >>$@+ && \
-       { cmp $@+ $@ >/dev/null 2>/dev/null || mv $@+ $@; } && \
-       $(RM) $@+
-
-perl/perl.mak: GIT-CFLAGS GIT-PREFIX perl/Makefile perl/Makefile.PL
-       $(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' $(@F)
-
-PERL_DEFINES = $(PERL_PATH_SQ):$(PERLLIB_EXTRA_SQ)
-$(SCRIPT_PERL_GEN): % : %.perl perl/perl.mak GIT-PERL-DEFINES GIT-VERSION-FILE
+PERL_DEFINES = $(PERL_PATH_SQ):$(PERLLIB_EXTRA_SQ):$(perllibdir_SQ)
+$(SCRIPT_PERL_GEN): % : %.perl GIT-PERL-DEFINES GIT-VERSION-FILE
        $(QUIET_GEN)$(RM) $@ $@+ && \
-       INSTLIBDIR=`MAKEFLAGS= $(MAKE) -C perl -s --no-print-directory instlibdir` && \
+       INSTLIBDIR='$(perllibdir_SQ)' && \
        INSTLIBDIR_EXTRA='$(PERLLIB_EXTRA_SQ)' && \
        INSTLIBDIR="$$INSTLIBDIR$${INSTLIBDIR_EXTRA:+:$$INSTLIBDIR_EXTRA}" && \
        sed -e '1{' \
@@ -2312,6 +2298,21 @@ endif
 po/build/locale/%/LC_MESSAGES/git.mo: po/%.po
        $(QUIET_MSGFMT)mkdir -p $(dir $@) && $(MSGFMT) -o $@ $<
 
+LIB_PERL := $(wildcard perl/Git.pm perl/Git/*.pm perl/Git/*/*.pm perl/Git/*/*/*.pm)
+LIB_PERL_GEN := $(patsubst perl/%.pm,perl/build/lib/%.pm,$(LIB_PERL))
+
+ifndef NO_PERL
+all:: $(LIB_PERL_GEN)
+endif
+
+perl/build/lib/%.pm: perl/%.pm
+       $(QUIET_GEN)mkdir -p $(dir $@) && \
+       sed -e 's|@@LOCALEDIR@@|$(localedir_SQ)|g' < $< > $@
+
+perl/build/man/man3/Git.3pm: perl/Git.pm
+       $(QUIET_GEN)mkdir -p $(dir $@) && \
+       pod2man $< $@
+
 FIND_SOURCE_FILES = ( \
        git ls-files \
                '*.[hcS]' \
@@ -2572,7 +2573,9 @@ ifndef NO_GETTEXT
        (cd '$(DESTDIR_SQ)$(localedir_SQ)' && umask 022 && $(TAR) xof -)
 endif
 ifndef NO_PERL
-       $(MAKE) -C perl prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install
+       $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perllibdir_SQ)'
+       (cd perl/build/lib && $(TAR) cf - .) | \
+       (cd '$(DESTDIR_SQ)$(perllibdir_SQ)' && umask 022 && $(TAR) xof -)
        $(MAKE) -C gitweb install
 endif
 ifndef NO_TCLTK
@@ -2622,12 +2625,17 @@ endif
 install-gitweb:
        $(MAKE) -C gitweb install
 
-install-doc:
+install-doc: install-man-perl
        $(MAKE) -C Documentation install
 
-install-man:
+install-man: install-man-perl
        $(MAKE) -C Documentation install-man
 
+install-man-perl: perl/build/man/man3/Git.3pm
+       $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(mandir_SQ)/man3'
+       (cd perl/build/man/man3 && $(TAR) cf - .) | \
+       (cd '$(DESTDIR_SQ)$(mandir_SQ)/man3' && umask 022 && $(TAR) xof -)
+
 install-html:
        $(MAKE) -C Documentation install-html
 
@@ -2662,6 +2670,21 @@ dist: git-archive$(X) configure
                $(GIT_TARNAME)/configure \
                $(GIT_TARNAME)/version \
                $(GIT_TARNAME)/git-gui/version
+ifdef DC_SHA1_SUBMODULE
+       @mkdir -p $(GIT_TARNAME)/sha1collisiondetection/lib
+       @cp sha1collisiondetection/LICENSE.txt \
+               $(GIT_TARNAME)/sha1collisiondetection/
+       @cp sha1collisiondetection/LICENSE.txt \
+               $(GIT_TARNAME)/sha1collisiondetection/
+       @cp sha1collisiondetection/lib/sha1.[ch] \
+               $(GIT_TARNAME)/sha1collisiondetection/lib/
+       @cp sha1collisiondetection/lib/ubc_check.[ch] \
+               $(GIT_TARNAME)/sha1collisiondetection/lib/
+       $(TAR) rf $(GIT_TARNAME).tar \
+               $(GIT_TARNAME)/sha1collisiondetection/LICENSE.txt \
+               $(GIT_TARNAME)/sha1collisiondetection/lib/sha1.[ch] \
+               $(GIT_TARNAME)/sha1collisiondetection/lib/ubc_check.[ch]
+endif
        @$(RM) -r $(GIT_TARNAME)
        gzip -f -9 $(GIT_TARNAME).tar
 
@@ -2719,7 +2742,7 @@ clean: profile-clean coverage-clean
        $(MAKE) -C Documentation/ clean
 ifndef NO_PERL
        $(MAKE) -C gitweb clean
-       $(MAKE) -C perl clean
+       $(RM) -r perl/build/
 endif
        $(MAKE) -C templates/ clean
        $(MAKE) -C t/ clean
index 0172894..7a6dc06 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.16.1.txt
\ No newline at end of file
+Documentation/RelNotes/2.17.0.txt
\ No newline at end of file
diff --git a/apply.c b/apply.c
index 321a9fa..40a368b 100644 (file)
--- a/apply.c
+++ b/apply.c
@@ -2263,8 +2263,8 @@ static void show_stats(struct apply_state *state, struct patch *patch)
 static int read_old_data(struct stat *st, struct patch *patch,
                         const char *path, struct strbuf *buf)
 {
-       enum safe_crlf safe_crlf = patch->crlf_in_old ?
-               SAFE_CRLF_KEEP_CRLF : SAFE_CRLF_RENORMALIZE;
+       int conv_flags = patch->crlf_in_old ?
+               CONV_EOL_KEEP_CRLF : CONV_EOL_RENORMALIZE;
        switch (st->st_mode & S_IFMT) {
        case S_IFLNK:
                if (strbuf_readlink(buf, path, st->st_size) < 0)
@@ -2281,7 +2281,7 @@ static int read_old_data(struct stat *st, struct patch *patch,
                 * should never look at the index when explicit crlf option
                 * is given.
                 */
-               convert_to_git(NULL, path, buf->buf, buf->len, buf, safe_crlf);
+               convert_to_git(NULL, path, buf->buf, buf->len, buf, conv_flags);
                return 0;
        default:
                return -1;
@@ -3154,7 +3154,7 @@ static int apply_binary(struct apply_state *state,
                 * See if the old one matches what the patch
                 * applies to.
                 */
-               hash_sha1_file(img->buf, img->len, blob_type, oid.hash);
+               hash_object_file(img->buf, img->len, blob_type, &oid);
                if (strcmp(oid_to_hex(&oid), patch->old_sha1_prefix))
                        return error(_("the patch applies to '%s' (%s), "
                                       "which does not match the "
@@ -3199,7 +3199,7 @@ static int apply_binary(struct apply_state *state,
                                     name);
 
                /* verify that the result matches */
-               hash_sha1_file(img->buf, img->len, blob_type, oid.hash);
+               hash_object_file(img->buf, img->len, blob_type, &oid);
                if (strcmp(oid_to_hex(&oid), patch->new_sha1_prefix))
                        return error(_("binary patch to '%s' creates incorrect result (expecting %s, got %s)"),
                                name, patch->new_sha1_prefix, oid_to_hex(&oid));
@@ -3554,7 +3554,7 @@ static int try_threeway(struct apply_state *state,
 
        /* Preimage the patch was prepared for */
        if (patch->is_new)
-               write_sha1_file("", 0, blob_type, pre_oid.hash);
+               write_object_file("", 0, blob_type, &pre_oid);
        else if (get_oid(patch->old_sha1_prefix, &pre_oid) ||
                 read_blob_object(&buf, &pre_oid, patch->old_mode))
                return error(_("repository lacks the necessary blob to fall back on 3-way merge."));
@@ -3570,7 +3570,7 @@ static int try_threeway(struct apply_state *state,
                return -1;
        }
        /* post_oid is theirs */
-       write_sha1_file(tmp_image.buf, tmp_image.len, blob_type, post_oid.hash);
+       write_object_file(tmp_image.buf, tmp_image.len, blob_type, &post_oid);
        clear_image(&tmp_image);
 
        /* our_oid is ours */
@@ -3583,7 +3583,7 @@ static int try_threeway(struct apply_state *state,
                        return error(_("cannot read the current contents of '%s'"),
                                     patch->old_name);
        }
-       write_sha1_file(tmp_image.buf, tmp_image.len, blob_type, our_oid.hash);
+       write_object_file(tmp_image.buf, tmp_image.len, blob_type, &our_oid);
        clear_image(&tmp_image);
 
        /* in-core three-way merge between post and our using pre as base */
@@ -4291,7 +4291,7 @@ static int add_index_file(struct apply_state *state,
                        }
                        fill_stat_cache_info(ce, &st);
                }
-               if (write_sha1_file(buf, size, blob_type, ce->oid.hash) < 0) {
+               if (write_object_file(buf, size, blob_type, &ce->oid) < 0) {
                        free(ce);
                        return error(_("unable to create backing store "
                                       "for newly created file %s"), path);
index 2f3008b..f6d05bd 100644 (file)
--- a/bisect.c
+++ b/bisect.c
@@ -132,7 +132,7 @@ static void show_list(const char *debug, int counted, int nr,
                unsigned flags = commit->object.flags;
                enum object_type type;
                unsigned long size;
-               char *buf = read_sha1_file(commit->object.sha1, &type, &size);
+               char *buf = read_sha1_file(commit->object.oid.hash, &type, &size);
                const char *subject_start;
                int subject_len;
 
@@ -144,10 +144,10 @@ static void show_list(const char *debug, int counted, int nr,
                        fprintf(stderr, "%3d", weight(p));
                else
                        fprintf(stderr, "---");
-               fprintf(stderr, " %.*s", 8, sha1_to_hex(commit->object.sha1));
+               fprintf(stderr, " %.*s", 8, sha1_to_hex(commit->object.oid.hash));
                for (pp = commit->parents; pp; pp = pp->next)
                        fprintf(stderr, " %.*s", 8,
-                               sha1_to_hex(pp->item->object.sha1));
+                               sha1_to_hex(pp->item->object.oid.hash));
 
                subject_len = find_commit_subject(buf, &subject_start);
                if (subject_len)
@@ -792,11 +792,9 @@ static void handle_skipped_merge_base(const struct object_id *mb)
  * - If one is "skipped", we can't know but we should warn.
  * - If we don't know, we should check it out and ask the user to test.
  */
-static void check_merge_bases(int no_checkout)
+static void check_merge_bases(int rev_nr, struct commit **rev, int no_checkout)
 {
        struct commit_list *result;
-       int rev_nr;
-       struct commit **rev = get_bad_and_good_commits(&rev_nr);
 
        result = get_merge_bases_many(rev[0], rev_nr - 1, rev + 1);
 
@@ -814,34 +812,21 @@ static void check_merge_bases(int no_checkout)
                }
        }
 
-       free(rev);
        free_commit_list(result);
 }
 
-static int check_ancestors(const char *prefix)
+static int check_ancestors(int rev_nr, struct commit **rev, const char *prefix)
 {
        struct rev_info revs;
-       struct object_array pending_copy;
        int res;
 
        bisect_rev_setup(&revs, prefix, "^%s", "%s", 0);
 
-       /* Save pending objects, so they can be cleaned up later. */
-       pending_copy = revs.pending;
-       revs.leak_pending = 1;
-
-       /*
-        * bisect_common calls prepare_revision_walk right away, which
-        * (together with .leak_pending = 1) makes us the sole owner of
-        * the list of pending objects.
-        */
        bisect_common(&revs);
        res = (revs.commits != NULL);
 
        /* Clean up objects used, as they will be reused. */
-       clear_commit_marks_for_object_array(&pending_copy, ALL_REV_FLAGS);
-
-       object_array_clear(&pending_copy);
+       clear_commit_marks_many(rev_nr, rev, ALL_REV_FLAGS);
 
        return res;
 }
@@ -858,7 +843,8 @@ static void check_good_are_ancestors_of_bad(const char *prefix, int no_checkout)
 {
        char *filename = git_pathdup("BISECT_ANCESTORS_OK");
        struct stat st;
-       int fd;
+       int fd, rev_nr;
+       struct commit **rev;
 
        if (!current_bad_oid)
                die(_("a %s revision is needed"), term_bad);
@@ -872,8 +858,10 @@ static void check_good_are_ancestors_of_bad(const char *prefix, int no_checkout)
                goto done;
 
        /* Check if all good revs are ancestor of the bad rev. */
-       if (check_ancestors(prefix))
-               check_merge_bases(no_checkout);
+       rev = get_bad_and_good_commits(&rev_nr);
+       if (check_ancestors(rev_nr, rev, prefix))
+               check_merge_bases(rev_nr, rev, no_checkout);
+       free(rev);
 
        /* Create file BISECT_ANCESTORS_OK. */
        fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0600);
diff --git a/blame.c b/blame.c
index 2893f3c..1fc22b3 100644 (file)
--- a/blame.c
+++ b/blame.c
@@ -232,7 +232,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
        convert_to_git(&the_index, path, buf.buf, buf.len, &buf, 0);
        origin->file.ptr = buf.buf;
        origin->file.size = buf.len;
-       pretend_sha1_file(buf.buf, buf.len, OBJ_BLOB, origin->blob_oid.hash);
+       pretend_object_file(buf.buf, buf.len, OBJ_BLOB, &origin->blob_oid);
 
        /*
         * Read the current index, replace the path entry with
index acfe9d3..6661edc 100644 (file)
@@ -1061,7 +1061,7 @@ static void am_setup(struct am_state *state, enum patch_format patch_format,
        }
        write_state_text(state, "scissors", str);
 
-       sq_quote_argv(&sb, state->git_apply_opts.argv, 0);
+       sq_quote_argv(&sb, state->git_apply_opts.argv);
        write_state_text(state, "apply-opt", sb.buf);
 
        if (state->rebasing)
@@ -1641,8 +1641,8 @@ static void do_commit(const struct am_state *state)
                setenv("GIT_COMMITTER_DATE",
                        state->ignore_date ? "" : state->author_date, 1);
 
-       if (commit_tree(state->msg, state->msg_len, tree.hash, parents, commit.hash,
-                               author, state->sign_commit))
+       if (commit_tree(state->msg, state->msg_len, &tree, parents, &commit,
+                       author, state->sign_commit))
                die(_("failed to write commit object"));
 
        reflog_msg = getenv("GIT_REFLOG_ACTION");
index f5fa4fd..cf9ea5c 100644 (file)
@@ -475,6 +475,8 @@ static int batch_objects(struct batch_options *opt)
 
                for_each_loose_object(batch_loose_object, &sa, 0);
                for_each_packed_object(batch_packed_object, &sa, 0);
+               if (repository_format_partial_clone)
+                       warning("This repository has extensions.partialClone set. Some objects may not be loaded.");
 
                cb.opt = opt;
                cb.expand = &data;
index 8bdc927..191b96c 100644 (file)
@@ -227,8 +227,7 @@ static int checkout_merged(int pos, const struct checkout *state)
         * (it also writes the merge result to the object database even
         * when it may contain conflicts).
         */
-       if (write_sha1_file(result_buf.ptr, result_buf.size,
-                           blob_type, oid.hash))
+       if (write_object_file(result_buf.ptr, result_buf.size, blob_type, &oid))
                die(_("Unable to add merge result for '%s'"), path);
        free(result_buf.ptr);
        ce = make_cache_entry(mode, oid.hash, path, 2, 0);
@@ -791,7 +790,6 @@ static void orphaned_commit_warning(struct commit *old, struct commit *new)
 {
        struct rev_info revs;
        struct object *object = &old->object;
-       struct object_array refs;
 
        init_revisions(&revs, NULL);
        setup_revisions(0, NULL, &revs, NULL);
@@ -802,14 +800,6 @@ static void orphaned_commit_warning(struct commit *old, struct commit *new)
        for_each_ref(add_pending_uninteresting_ref, &revs);
        add_pending_oid(&revs, "HEAD", &new->object.oid, UNINTERESTING);
 
-       /* Save pending objects, so they can be cleaned up later. */
-       refs = revs.pending;
-       revs.leak_pending = 1;
-
-       /*
-        * prepare_revision_walk (together with .leak_pending = 1) makes us
-        * the sole owner of the list of pending objects.
-        */
        if (prepare_revision_walk(&revs))
                die(_("internal error in revision walk"));
        if (!(old->object.flags & UNINTERESTING))
@@ -818,9 +808,7 @@ static void orphaned_commit_warning(struct commit *old, struct commit *new)
                describe_detached_head(_("Previous HEAD position was"), old);
 
        /* Clean up objects used, as they will be reused. */
-       clear_commit_marks_for_object_array(&refs, ALL_REV_FLAGS);
-
-       object_array_clear(&refs);
+       clear_commit_marks_all(ALL_REV_FLAGS);
 }
 
 static int switch_branches(const struct checkout_opts *opts,
index 2da71db..101c27a 100644 (file)
@@ -26,6 +26,7 @@
 #include "run-command.h"
 #include "connected.h"
 #include "packfile.h"
+#include "list-objects-filter-options.h"
 
 /*
  * Overall FIXMEs:
@@ -60,6 +61,7 @@ static struct string_list option_optional_reference = STRING_LIST_INIT_NODUP;
 static int option_dissociate;
 static int max_jobs = -1;
 static struct string_list option_recurse_submodules = STRING_LIST_INIT_NODUP;
+static struct list_objects_filter_options filter_options;
 
 static int recurse_submodules_cb(const struct option *opt,
                                 const char *arg, int unset)
@@ -135,6 +137,7 @@ static struct option builtin_clone_options[] = {
                        TRANSPORT_FAMILY_IPV4),
        OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
                        TRANSPORT_FAMILY_IPV6),
+       OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
        OPT_END()
 };
 
@@ -473,7 +476,9 @@ static void clone_local(const char *src_repo, const char *dest_repo)
 }
 
 static const char *junk_work_tree;
+static int junk_work_tree_flags;
 static const char *junk_git_dir;
+static int junk_git_dir_flags;
 static enum {
        JUNK_LEAVE_NONE,
        JUNK_LEAVE_REPO,
@@ -502,12 +507,12 @@ static void remove_junk(void)
 
        if (junk_git_dir) {
                strbuf_addstr(&sb, junk_git_dir);
-               remove_dir_recursively(&sb, 0);
+               remove_dir_recursively(&sb, junk_git_dir_flags);
                strbuf_reset(&sb);
        }
        if (junk_work_tree) {
                strbuf_addstr(&sb, junk_work_tree);
-               remove_dir_recursively(&sb, 0);
+               remove_dir_recursively(&sb, junk_work_tree_flags);
        }
        strbuf_release(&sb);
 }
@@ -863,10 +868,15 @@ static void dissociate_from_references(void)
        free(alternates);
 }
 
+static int dir_exists(const char *path)
+{
+       struct stat sb;
+       return !stat(path, &sb);
+}
+
 int cmd_clone(int argc, const char **argv, const char *prefix)
 {
        int is_bundle = 0, is_local;
-       struct stat buf;
        const char *repo_name, *repo, *work_tree, *git_dir;
        char *path, *dir;
        int dest_exists;
@@ -886,6 +896,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        struct refspec *refspec;
        const char *fetch_pattern;
 
+       fetch_if_missing = 0;
+
        packet_trace_identity("clone");
        argc = parse_options(argc, argv, prefix, builtin_clone_options,
                             builtin_clone_usage, 0);
@@ -938,7 +950,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                dir = guess_dir_name(repo_name, is_bundle, option_bare);
        strip_trailing_slashes(dir);
 
-       dest_exists = !stat(dir, &buf);
+       dest_exists = dir_exists(dir);
        if (dest_exists && !is_empty_dir(dir))
                die(_("destination path '%s' already exists and is not "
                        "an empty directory."), dir);
@@ -949,7 +961,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                work_tree = NULL;
        else {
                work_tree = getenv("GIT_WORK_TREE");
-               if (work_tree && !stat(work_tree, &buf))
+               if (work_tree && dir_exists(work_tree))
                        die(_("working tree '%s' already exists."), work_tree);
        }
 
@@ -967,14 +979,24 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                if (safe_create_leading_directories_const(work_tree) < 0)
                        die_errno(_("could not create leading directories of '%s'"),
                                  work_tree);
-               if (!dest_exists && mkdir(work_tree, 0777))
+               if (dest_exists)
+                       junk_work_tree_flags |= REMOVE_DIR_KEEP_TOPLEVEL;
+               else if (mkdir(work_tree, 0777))
                        die_errno(_("could not create work tree dir '%s'"),
                                  work_tree);
                junk_work_tree = work_tree;
                set_git_work_tree(work_tree);
        }
 
-       junk_git_dir = real_git_dir ? real_git_dir : git_dir;
+       if (real_git_dir) {
+               if (dir_exists(real_git_dir))
+                       junk_git_dir_flags |= REMOVE_DIR_KEEP_TOPLEVEL;
+               junk_git_dir = real_git_dir;
+       } else {
+               if (dest_exists)
+                       junk_git_dir_flags |= REMOVE_DIR_KEEP_TOPLEVEL;
+               junk_git_dir = git_dir;
+       }
        if (safe_create_leading_directories_const(git_dir) < 0)
                die(_("could not create leading directories of '%s'"), git_dir);
 
@@ -1073,6 +1095,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                        warning(_("--shallow-since is ignored in local clones; use file:// instead."));
                if (option_not.nr)
                        warning(_("--shallow-exclude is ignored in local clones; use file:// instead."));
+               if (filter_options.choice)
+                       warning(_("--filter is ignored in local clones; use file:// instead."));
                if (!access(mkpath("%s/shallow", path), F_OK)) {
                        if (option_local > 0)
                                warning(_("source repository is shallow, ignoring --local"));
@@ -1101,7 +1125,13 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                transport_set_option(transport, TRANS_OPT_UPLOADPACK,
                                     option_upload_pack);
 
-       if (transport->smart_options && !deepen)
+       if (filter_options.choice) {
+               transport_set_option(transport, TRANS_OPT_LIST_OBJECTS_FILTER,
+                                    filter_options.filter_spec);
+               transport_set_option(transport, TRANS_OPT_FROM_PROMISOR, "1");
+       }
+
+       if (transport->smart_options && !deepen && !filter_options.choice)
                transport->smart_options->check_self_contained_and_connected = 1;
 
        refs = transport_get_remote_refs(transport);
@@ -1161,13 +1191,17 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        write_refspec_config(src_ref_prefix, our_head_points_at,
                        remote_head_points_at, &branch_top);
 
+       if (filter_options.choice)
+               partial_clone_register("origin", &filter_options);
+
        if (is_local)
                clone_local(path, git_dir);
        else if (refs && complete_refs_before_fetch)
                transport_fetch_refs(transport, mapped_refs);
 
        update_remote_refs(refs, mapped_refs, remote_head_points_at,
-                          branch_top.buf, reflog_msg.buf, transport, !is_local);
+                          branch_top.buf, reflog_msg.buf, transport,
+                          !is_local && !filter_options.choice);
 
        update_head(our_head_points_at, remote_head, reflog_msg.buf);
 
@@ -1188,6 +1222,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        }
 
        junk_mode = JUNK_LEAVE_REPO;
+       fetch_if_missing = 1;
        err = checkout(submodule_progress);
 
        strbuf_release(&reflog_msg);
index 2177251..e5bdf57 100644 (file)
@@ -117,8 +117,8 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
                        die_errno("git commit-tree: failed to read");
        }
 
-       if (commit_tree(buffer.buf, buffer.len, tree_oid.hash, parents,
-                       commit_oid.hash, NULL, sign_commit)) {
+       if (commit_tree(buffer.buf, buffer.len, &tree_oid, parents, &commit_oid,
+                       NULL, sign_commit)) {
                strbuf_release(&buffer);
                return 1;
        }
index 8a87701..e8e8d13 100644 (file)
@@ -31,9 +31,7 @@
 #include "gpg-interface.h"
 #include "column.h"
 #include "sequencer.h"
-#include "notes-utils.h"
 #include "mailmap.h"
-#include "sigchain.h"
 
 static const char * const builtin_commit_usage[] = {
        N_("git commit [<options>] [--] <pathspec>..."),
@@ -45,31 +43,6 @@ static const char * const builtin_status_usage[] = {
        NULL
 };
 
-static const char implicit_ident_advice_noconfig[] =
-N_("Your name and email address were configured automatically based\n"
-"on your username and hostname. Please check that they are accurate.\n"
-"You can suppress this message by setting them explicitly. Run the\n"
-"following command and follow the instructions in your editor to edit\n"
-"your configuration file:\n"
-"\n"
-"    git config --global --edit\n"
-"\n"
-"After doing this, you may fix the identity used for this commit with:\n"
-"\n"
-"    git commit --amend --reset-author\n");
-
-static const char implicit_ident_advice_config[] =
-N_("Your name and email address were configured automatically based\n"
-"on your username and hostname. Please check that they are accurate.\n"
-"You can suppress this message by setting them explicitly:\n"
-"\n"
-"    git config --global user.name \"Your Name\"\n"
-"    git config --global user.email you@example.com\n"
-"\n"
-"After doing this, you may fix the identity used for this commit with:\n"
-"\n"
-"    git commit --amend --reset-author\n");
-
 static const char empty_amend_advice[] =
 N_("You asked to amend the most recent commit, but doing so would make\n"
 "it empty. You can repeat your command with --allow-empty, or you can\n"
@@ -93,8 +66,6 @@ N_("If you wish to skip this commit, use:\n"
 "Then \"git cherry-pick --continue\" will resume cherry-picking\n"
 "the remaining commits.\n");
 
-static GIT_PATH_FUNC(git_path_commit_editmsg, "COMMIT_EDITMSG")
-
 static const char *use_message_buffer;
 static struct lock_file index_lock; /* real index */
 static struct lock_file false_lock; /* used only for partial commits */
@@ -128,12 +99,7 @@ static char *sign_commit;
  * if editor is used, and only the whitespaces if the message
  * is specified explicitly.
  */
-static enum {
-       CLEANUP_SPACE,
-       CLEANUP_NONE,
-       CLEANUP_SCISSORS,
-       CLEANUP_ALL
-} cleanup_mode;
+static enum commit_msg_cleanup_mode cleanup_mode;
 static const char *cleanup_arg;
 
 static enum commit_whence whence;
@@ -673,7 +639,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
        struct strbuf sb = STRBUF_INIT;
        const char *hook_arg1 = NULL;
        const char *hook_arg2 = NULL;
-       int clean_message_contents = (cleanup_mode != CLEANUP_NONE);
+       int clean_message_contents = (cleanup_mode != COMMIT_MSG_CLEANUP_NONE);
        int old_display_comment_prefix;
 
        /* This checks and barfs if author is badly specified */
@@ -701,7 +667,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
                }
        }
 
-       if (have_option_m) {
+       if (have_option_m && !fixup_message) {
                strbuf_addbuf(&sb, &message);
                hook_arg1 = "message";
        } else if (logfile && !strcmp(logfile, "-")) {
@@ -731,6 +697,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
                ctx.output_encoding = get_commit_output_encoding();
                format_commit_message(commit, "fixup! %s\n\n",
                                      &sb, &ctx);
+               if (have_option_m)
+                       strbuf_addbuf(&sb, &message);
                hook_arg1 = "message";
        } else if (!stat(git_path_merge_msg(), &statbuf)) {
                /*
@@ -812,7 +780,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
                struct ident_split ci, ai;
 
                if (whence != FROM_COMMIT) {
-                       if (cleanup_mode == CLEANUP_SCISSORS)
+                       if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
                                wt_status_add_cut_line(s->fp);
                        status_printf_ln(s, GIT_COLOR_NORMAL,
                            whence == FROM_MERGE
@@ -832,14 +800,15 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
                }
 
                fprintf(s->fp, "\n");
-               if (cleanup_mode == CLEANUP_ALL)
+               if (cleanup_mode == COMMIT_MSG_CLEANUP_ALL)
                        status_printf(s, GIT_COLOR_NORMAL,
                                _("Please enter the commit message for your changes."
                                  " Lines starting\nwith '%c' will be ignored, and an empty"
                                  " message aborts the commit.\n"), comment_line_char);
-               else if (cleanup_mode == CLEANUP_SCISSORS && whence == FROM_COMMIT)
+               else if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
+                        whence == FROM_COMMIT)
                        wt_status_add_cut_line(s->fp);
-               else /* CLEANUP_SPACE, that is. */
+               else /* COMMIT_MSG_CLEANUP_SPACE, that is. */
                        status_printf(s, GIT_COLOR_NORMAL,
                                _("Please enter the commit message for your changes."
                                  " Lines starting\n"
@@ -984,65 +953,6 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
        return 1;
 }
 
-static int rest_is_empty(struct strbuf *sb, int start)
-{
-       int i, eol;
-       const char *nl;
-
-       /* Check if the rest is just whitespace and Signed-off-by's. */
-       for (i = start; i < sb->len; i++) {
-               nl = memchr(sb->buf + i, '\n', sb->len - i);
-               if (nl)
-                       eol = nl - sb->buf;
-               else
-                       eol = sb->len;
-
-               if (strlen(sign_off_header) <= eol - i &&
-                   starts_with(sb->buf + i, sign_off_header)) {
-                       i = eol;
-                       continue;
-               }
-               while (i < eol)
-                       if (!isspace(sb->buf[i++]))
-                               return 0;
-       }
-
-       return 1;
-}
-
-/*
- * Find out if the message in the strbuf contains only whitespace and
- * Signed-off-by lines.
- */
-static int message_is_empty(struct strbuf *sb)
-{
-       if (cleanup_mode == CLEANUP_NONE && sb->len)
-               return 0;
-       return rest_is_empty(sb, 0);
-}
-
-/*
- * See if the user edited the message in the editor or left what
- * was in the template intact
- */
-static int template_untouched(struct strbuf *sb)
-{
-       struct strbuf tmpl = STRBUF_INIT;
-       const char *start;
-
-       if (cleanup_mode == CLEANUP_NONE && sb->len)
-               return 0;
-
-       if (!template_file || strbuf_read_file(&tmpl, template_file, 0) <= 0)
-               return 0;
-
-       strbuf_stripspace(&tmpl, cleanup_mode == CLEANUP_ALL);
-       if (!skip_prefix(sb->buf, tmpl.buf, &start))
-               start = sb->buf;
-       strbuf_release(&tmpl);
-       return rest_is_empty(sb, start - sb->buf);
-}
-
 static const char *find_author_by_nickname(const char *name)
 {
        struct rev_info revs;
@@ -1197,8 +1107,8 @@ static int parse_and_validate_options(int argc, const char *argv[],
                f++;
        if (f > 1)
                die(_("Only one of -c/-C/-F/--fixup can be used."));
-       if (have_option_m && f > 0)
-               die((_("Option -m cannot be combined with -c/-C/-F/--fixup.")));
+       if (have_option_m && (edit_message || use_message || logfile))
+               die((_("Option -m cannot be combined with -c/-C/-F.")));
        if (f || have_option_m)
                template_file = NULL;
        if (edit_message)
@@ -1227,15 +1137,17 @@ static int parse_and_validate_options(int argc, const char *argv[],
        if (argc == 0 && (also || (only && !amend && !allow_empty)))
                die(_("No paths with --include/--only does not make sense."));
        if (!cleanup_arg || !strcmp(cleanup_arg, "default"))
-               cleanup_mode = use_editor ? CLEANUP_ALL : CLEANUP_SPACE;
+               cleanup_mode = use_editor ? COMMIT_MSG_CLEANUP_ALL :
+                                           COMMIT_MSG_CLEANUP_SPACE;
        else if (!strcmp(cleanup_arg, "verbatim"))
-               cleanup_mode = CLEANUP_NONE;
+               cleanup_mode = COMMIT_MSG_CLEANUP_NONE;
        else if (!strcmp(cleanup_arg, "whitespace"))
-               cleanup_mode = CLEANUP_SPACE;
+               cleanup_mode = COMMIT_MSG_CLEANUP_SPACE;
        else if (!strcmp(cleanup_arg, "strip"))
-               cleanup_mode = CLEANUP_ALL;
+               cleanup_mode = COMMIT_MSG_CLEANUP_ALL;
        else if (!strcmp(cleanup_arg, "scissors"))
-               cleanup_mode = use_editor ? CLEANUP_SCISSORS : CLEANUP_SPACE;
+               cleanup_mode = use_editor ? COMMIT_MSG_CLEANUP_SCISSORS :
+                                           COMMIT_MSG_CLEANUP_SPACE;
        else
                die(_("Invalid cleanup mode %s"), cleanup_arg);
 
@@ -1437,98 +1349,6 @@ int cmd_status(int argc, const char **argv, const char *prefix)
        return 0;
 }
 
-static const char *implicit_ident_advice(void)
-{
-       char *user_config = expand_user_path("~/.gitconfig", 0);
-       char *xdg_config = xdg_config_home("config");
-       int config_exists = file_exists(user_config) || file_exists(xdg_config);
-
-       free(user_config);
-       free(xdg_config);
-
-       if (config_exists)
-               return _(implicit_ident_advice_config);
-       else
-               return _(implicit_ident_advice_noconfig);
-
-}
-
-static void print_summary(const char *prefix, const struct object_id *oid,
-                         int initial_commit)
-{
-       struct rev_info rev;
-       struct commit *commit;
-       struct strbuf format = STRBUF_INIT;
-       const char *head;
-       struct pretty_print_context pctx = {0};
-       struct strbuf author_ident = STRBUF_INIT;
-       struct strbuf committer_ident = STRBUF_INIT;
-
-       commit = lookup_commit(oid);
-       if (!commit)
-               die(_("couldn't look up newly created commit"));
-       if (parse_commit(commit))
-               die(_("could not parse newly created commit"));
-
-       strbuf_addstr(&format, "format:%h] %s");
-
-       format_commit_message(commit, "%an <%ae>", &author_ident, &pctx);
-       format_commit_message(commit, "%cn <%ce>", &committer_ident, &pctx);
-       if (strbuf_cmp(&author_ident, &committer_ident)) {
-               strbuf_addstr(&format, "\n Author: ");
-               strbuf_addbuf_percentquote(&format, &author_ident);
-       }
-       if (author_date_is_interesting()) {
-               struct strbuf date = STRBUF_INIT;
-               format_commit_message(commit, "%ad", &date, &pctx);
-               strbuf_addstr(&format, "\n Date: ");
-               strbuf_addbuf_percentquote(&format, &date);
-               strbuf_release(&date);
-       }
-       if (!committer_ident_sufficiently_given()) {
-               strbuf_addstr(&format, "\n Committer: ");
-               strbuf_addbuf_percentquote(&format, &committer_ident);
-               if (advice_implicit_identity) {
-                       strbuf_addch(&format, '\n');
-                       strbuf_addstr(&format, implicit_ident_advice());
-               }
-       }
-       strbuf_release(&author_ident);
-       strbuf_release(&committer_ident);
-
-       init_revisions(&rev, prefix);
-       setup_revisions(0, NULL, &rev, NULL);
-
-       rev.diff = 1;
-       rev.diffopt.output_format =
-               DIFF_FORMAT_SHORTSTAT | DIFF_FORMAT_SUMMARY;
-
-       rev.verbose_header = 1;
-       rev.show_root_diff = 1;
-       get_commit_format(format.buf, &rev);
-       rev.always_show_header = 0;
-       rev.diffopt.detect_rename = 1;
-       rev.diffopt.break_opt = 0;
-       diff_setup_done(&rev.diffopt);
-
-       head = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
-       if (!head)
-               die_errno(_("unable to resolve HEAD after creating commit"));
-       if (!strcmp(head, "HEAD"))
-               head = _("detached HEAD");
-       else
-               skip_prefix(head, "refs/heads/", &head);
-       printf("[%s%s ", head, initial_commit ? _(" (root-commit)") : "");
-
-       if (!log_tree_commit(&rev, commit)) {
-               rev.always_show_header = 1;
-               rev.use_terminator = 1;
-               log_tree_commit(&rev, commit);
-       }
-
-       strbuf_release(&format);
-}
-
 static int git_commit_config(const char *k, const char *v, void *cb)
 {
        struct wt_status *s = cb;
@@ -1558,37 +1378,6 @@ static int git_commit_config(const char *k, const char *v, void *cb)
        return git_status_config(k, v, s);
 }
 
-static int run_rewrite_hook(const struct object_id *oldoid,
-                           const struct object_id *newoid)
-{
-       struct child_process proc = CHILD_PROCESS_INIT;
-       const char *argv[3];
-       int code;
-       struct strbuf sb = STRBUF_INIT;
-
-       argv[0] = find_hook("post-rewrite");
-       if (!argv[0])
-               return 0;
-
-       argv[1] = "amend";
-       argv[2] = NULL;
-
-       proc.argv = argv;
-       proc.in = -1;
-       proc.stdout_to_stderr = 1;
-
-       code = start_command(&proc);
-       if (code)
-               return code;
-       strbuf_addf(&sb, "%s %s\n", oid_to_hex(oldoid), oid_to_hex(newoid));
-       sigchain_push(SIGPIPE, SIG_IGN);
-       write_in_full(proc.in, sb.buf, sb.len);
-       close(proc.in);
-       strbuf_release(&sb);
-       sigchain_pop(SIGPIPE);
-       return finish_command(&proc);
-}
-
 int run_commit_hook(int editor_is_used, const char *index_file, const char *name, ...)
 {
        struct argv_array hook_env = ARGV_ARRAY_INIT;
@@ -1671,13 +1460,11 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
        struct strbuf sb = STRBUF_INIT;
        struct strbuf author_ident = STRBUF_INIT;
        const char *index_file, *reflog_msg;
-       char *nl;
        struct object_id oid;
        struct commit_list *parents = NULL;
        struct stat statbuf;
        struct commit *current_head = NULL;
        struct commit_extra_header *extra = NULL;
-       struct ref_transaction *transaction;
        struct strbuf err = STRBUF_INIT;
 
        if (argc == 2 && !strcmp(argv[1], "-h"))
@@ -1768,17 +1555,17 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
        }
 
        if (verbose || /* Truncate the message just before the diff, if any. */
-           cleanup_mode == CLEANUP_SCISSORS)
+           cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
                strbuf_setlen(&sb, wt_status_locate_end(sb.buf, sb.len));
-       if (cleanup_mode != CLEANUP_NONE)
-               strbuf_stripspace(&sb, cleanup_mode == CLEANUP_ALL);
+       if (cleanup_mode != COMMIT_MSG_CLEANUP_NONE)
+               strbuf_stripspace(&sb, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);
 
-       if (message_is_empty(&sb) && !allow_empty_message) {
+       if (message_is_empty(&sb, cleanup_mode) && !allow_empty_message) {
                rollback_index_files();
                fprintf(stderr, _("Aborting commit due to empty commit message.\n"));
                exit(1);
        }
-       if (template_untouched(&sb) && !allow_empty_message) {
+       if (template_untouched(&sb, template_file, cleanup_mode) && !allow_empty_message) {
                rollback_index_files();
                fprintf(stderr, _("Aborting commit; you did not edit the message.\n"));
                exit(1);
@@ -1792,33 +1579,20 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
                append_merge_tag_headers(parents, &tail);
        }
 
-       if (commit_tree_extended(sb.buf, sb.len, active_cache_tree->oid.hash,
-                        parents, oid.hash, author_ident.buf, sign_commit, extra)) {
+       if (commit_tree_extended(sb.buf, sb.len, &active_cache_tree->oid,
+                                parents, &oid, author_ident.buf, sign_commit,
+                                extra)) {
                rollback_index_files();
                die(_("failed to write commit object"));
        }
        strbuf_release(&author_ident);
        free_commit_extra_headers(extra);
 
-       nl = strchr(sb.buf, '\n');
-       if (nl)
-               strbuf_setlen(&sb, nl + 1 - sb.buf);
-       else
-               strbuf_addch(&sb, '\n');
-       strbuf_insert(&sb, 0, reflog_msg, strlen(reflog_msg));
-       strbuf_insert(&sb, strlen(reflog_msg), ": ", 2);
-
-       transaction = ref_transaction_begin(&err);
-       if (!transaction ||
-           ref_transaction_update(transaction, "HEAD", &oid,
-                                  current_head
-                                  ? &current_head->object.oid : &null_oid,
-                                  0, sb.buf, &err) ||
-           ref_transaction_commit(transaction, &err)) {
+       if (update_head_with_reflog(current_head, &oid, reflog_msg, &sb,
+                                   &err)) {
                rollback_index_files();
                die("%s", err.buf);
        }
-       ref_transaction_free(transaction);
 
        unlink(git_path_cherry_pick_head());
        unlink(git_path_revert_head());
@@ -1835,17 +1609,17 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
        rerere(0);
        run_commit_hook(use_editor, get_index_file(), "post-commit", NULL);
        if (amend && !no_post_rewrite) {
-               struct notes_rewrite_cfg *cfg;
-               cfg = init_copy_notes_for_rewrite("amend");
-               if (cfg) {
-                       /* we are amending, so current_head is not NULL */
-                       copy_note_for_rewrite(cfg, &current_head->object.oid, &oid);
-                       finish_copy_notes_for_rewrite(cfg, "Notes added by 'git commit --amend'");
-               }
-               run_rewrite_hook(&current_head->object.oid, &oid);
+               commit_post_rewrite(current_head, &oid);
+       }
+       if (!quiet) {
+               unsigned int flags = 0;
+
+               if (!current_head)
+                       flags |= SUMMARY_INITIAL_COMMIT;
+               if (author_date_is_interesting())
+                       flags |= SUMMARY_SHOW_AUTHOR_DATE;
+               print_commit_summary(prefix, &oid, flags);
        }
-       if (!quiet)
-               print_summary(prefix, &oid, !current_head);
 
        UNLEAK(err);
        UNLEAK(sb);
index 3b0b204..c428984 100644 (file)
@@ -274,10 +274,13 @@ static void append_name(struct commit_name *n, struct strbuf *dst)
                n->name_checked = 1;
        }
 
-       if (n->tag)
+       if (n->tag) {
+               if (all)
+                       strbuf_addstr(dst, "tags/");
                strbuf_addstr(dst, n->tag->tag);
-       else
+       } else {
                strbuf_addstr(dst, n->path);
+       }
 }
 
 static void append_suffix(int depth, const struct object_id *oid, struct strbuf *dst)
@@ -380,7 +383,7 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
        if (!match_cnt) {
                struct object_id *cmit_oid = &cmit->object.oid;
                if (always) {
-                       strbuf_addstr(dst, find_unique_abbrev(cmit_oid->hash, abbrev));
+                       strbuf_add_unique_abbrev(dst, cmit_oid->hash, abbrev);
                        if (suffix)
                                strbuf_addstr(dst, suffix);
                        return;
index 366b9d1..a7bc136 100644 (file)
@@ -53,6 +53,8 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
        struct oid_array shallow = OID_ARRAY_INIT;
        struct string_list deepen_not = STRING_LIST_INIT_DUP;
 
+       fetch_if_missing = 0;
+
        packet_trace_identity("fetch-pack");
 
        memset(&args, 0, sizeof(args));
@@ -143,6 +145,22 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
                        args.update_shallow = 1;
                        continue;
                }
+               if (!strcmp("--from-promisor", arg)) {
+                       args.from_promisor = 1;
+                       continue;
+               }
+               if (!strcmp("--no-dependents", arg)) {
+                       args.no_dependents = 1;
+                       continue;
+               }
+               if (skip_prefix(arg, ("--" CL_ARG__FILTER "="), &arg)) {
+                       parse_list_objects_filter(&args.filter_options, arg);
+                       continue;
+               }
+               if (!strcmp(arg, ("--no-" CL_ARG__FILTER))) {
+                       list_objects_filter_set_no_filter(&args.filter_options);
+                       continue;
+               }
                usage(fetch_pack_usage);
        }
        if (deepen_not.nr)
index 7bbcd26..8ee998e 100644 (file)
@@ -19,6 +19,7 @@
 #include "argv-array.h"
 #include "utf8.h"
 #include "packfile.h"
+#include "list-objects-filter-options.h"
 
 static const char * const builtin_fetch_usage[] = {
        N_("git fetch [<options>] [<repository> [<refspec>...]]"),
@@ -56,6 +57,7 @@ static int recurse_submodules_default = RECURSE_SUBMODULES_ON_DEMAND;
 static int shown_url = 0;
 static int refmap_alloc, refmap_nr;
 static const char **refmap_array;
+static struct list_objects_filter_options filter_options;
 
 static int git_fetch_config(const char *k, const char *v, void *cb)
 {
@@ -161,6 +163,7 @@ static struct option builtin_fetch_options[] = {
                        TRANSPORT_FAMILY_IPV4),
        OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
                        TRANSPORT_FAMILY_IPV6),
+       OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
        OPT_END()
 };
 
@@ -1045,6 +1048,11 @@ static struct transport *prepare_transport(struct remote *remote, int deepen)
                set_option(transport, TRANS_OPT_DEEPEN_RELATIVE, "yes");
        if (update_shallow)
                set_option(transport, TRANS_OPT_UPDATE_SHALLOW, "yes");
+       if (filter_options.choice) {
+               set_option(transport, TRANS_OPT_LIST_OBJECTS_FILTER,
+                          filter_options.filter_spec);
+               set_option(transport, TRANS_OPT_FROM_PROMISOR, "1");
+       }
        return transport;
 }
 
@@ -1265,6 +1273,56 @@ static int fetch_multiple(struct string_list *list)
        return result;
 }
 
+/*
+ * Fetching from the promisor remote should use the given filter-spec
+ * or inherit the default filter-spec from the config.
+ */
+static inline void fetch_one_setup_partial(struct remote *remote)
+{
+       /*
+        * Explicit --no-filter argument overrides everything, regardless
+        * of any prior partial clones and fetches.
+        */
+       if (filter_options.no_filter)
+               return;
+
+       /*
+        * If no prior partial clone/fetch and the current fetch DID NOT
+        * request a partial-fetch, do a normal fetch.
+        */
+       if (!repository_format_partial_clone && !filter_options.choice)
+               return;
+
+       /*
+        * If this is the FIRST partial-fetch request, we enable partial
+        * on this repo and remember the given filter-spec as the default
+        * for subsequent fetches to this remote.
+        */
+       if (!repository_format_partial_clone && filter_options.choice) {
+               partial_clone_register(remote->name, &filter_options);
+               return;
+       }
+
+       /*
+        * We are currently limited to only ONE promisor remote and only
+        * allow partial-fetches from the promisor remote.
+        */
+       if (strcmp(remote->name, repository_format_partial_clone)) {
+               if (filter_options.choice)
+                       die(_("--filter can only be used with the remote configured in core.partialClone"));
+               return;
+       }
+
+       /*
+        * Do a partial-fetch from the promisor remote using either the
+        * explicitly given filter-spec or inherit the filter-spec from
+        * the config.
+        */
+       if (!filter_options.choice)
+               partial_clone_get_default_filter_spec(&filter_options);
+       return;
+}
+
 static int fetch_one(struct remote *remote, int argc, const char **argv)
 {
        static const char **refs = NULL;
@@ -1320,12 +1378,14 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
 {
        int i;
        struct string_list list = STRING_LIST_INIT_DUP;
-       struct remote *remote;
+       struct remote *remote = NULL;
        int result = 0;
        struct argv_array argv_gc_auto = ARGV_ARRAY_INIT;
 
        packet_trace_identity("fetch");
 
+       fetch_if_missing = 0;
+
        /* Record the command line for the reflog */
        strbuf_addstr(&default_rla, "fetch");
        for (i = 1; i < argc; i++)
@@ -1359,23 +1419,23 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
        if (depth || deepen_since || deepen_not.nr)
                deepen = 1;
 
+       if (filter_options.choice && !repository_format_partial_clone)
+               die("--filter can only be used when extensions.partialClone is set");
+
        if (all) {
                if (argc == 1)
                        die(_("fetch --all does not take a repository argument"));
                else if (argc > 1)
                        die(_("fetch --all does not make sense with refspecs"));
                (void) for_each_remote(get_one_remote_for_fetch, &list);
-               result = fetch_multiple(&list);
        } else if (argc == 0) {
                /* No arguments -- use default remote */
                remote = remote_get(NULL);
-               result = fetch_one(remote, argc, argv);
        } else if (multiple) {
                /* All arguments are assumed to be remotes or groups */
                for (i = 0; i < argc; i++)
                        if (!add_remote_or_group(argv[i], &list))
                                die(_("No such remote or remote group: %s"), argv[i]);
-               result = fetch_multiple(&list);
        } else {
                /* Single remote or group */
                (void) add_remote_or_group(argv[0], &list);
@@ -1383,14 +1443,25 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
                        /* More than one remote */
                        if (argc > 1)
                                die(_("Fetching a group and specifying refspecs does not make sense"));
-                       result = fetch_multiple(&list);
                } else {
                        /* Zero or one remotes */
                        remote = remote_get(argv[0]);
-                       result = fetch_one(remote, argc-1, argv+1);
+                       argc--;
+                       argv++;
                }
        }
 
+       if (remote) {
+               if (filter_options.choice || repository_format_partial_clone)
+                       fetch_one_setup_partial(remote);
+               result = fetch_one(remote, argc, argv);
+       } else {
+               if (filter_options.choice)
+                       die(_("--filter can only be used with the remote configured in core.partialClone"));
+               /* TODO should this also die if we have a previous partial-clone? */
+               result = fetch_multiple(&list);
+       }
+
        if (!result && (recurse_submodules != RECURSE_SUBMODULES_OFF)) {
                struct argv_array options = ARGV_ARRAY_INIT;
 
index 04846d4..9981db2 100644 (file)
@@ -149,6 +149,15 @@ static int mark_object(struct object *obj, int type, void *data, struct fsck_opt
        if (obj->flags & REACHABLE)
                return 0;
        obj->flags |= REACHABLE;
+
+       if (is_promisor_object(&obj->oid))
+               /*
+                * Further recursion does not need to be performed on this
+                * object since it is a promisor object (so it does not need to
+                * be added to "pending").
+                */
+               return 0;
+
        if (!(obj->flags & HAS_OBJ)) {
                if (parent && !has_object_file(&obj->oid)) {
                        printf("broken link from %7s %s\n",
@@ -171,7 +180,13 @@ static void mark_object_reachable(struct object *obj)
 
 static int traverse_one_object(struct object *obj)
 {
-       return fsck_walk(obj, obj, &fsck_walk_options);
+       int result = fsck_walk(obj, obj, &fsck_walk_options);
+
+       if (obj->type == OBJ_TREE) {
+               struct tree *tree = (struct tree *)obj;
+               free_tree_buffer(tree);
+       }
+       return result;
 }
 
 static int traverse_reachable(void)
@@ -208,6 +223,8 @@ static void check_reachable_object(struct object *obj)
         * do a full fsck
         */
        if (!(obj->flags & HAS_OBJ)) {
+               if (is_promisor_object(&obj->oid))
+                       return;
                if (has_sha1_pack(obj->oid.hash))
                        return; /* it is in pack - forget about it */
                printf("missing %s %s\n", printable_type(obj),
@@ -398,7 +415,7 @@ static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,
                                        xstrfmt("%s@{%"PRItime"}", refname, timestamp));
                        obj->flags |= USED;
                        mark_object_reachable(obj);
-               } else {
+               } else if (!is_promisor_object(oid)) {
                        error("%s: invalid reflog entry %s", refname, oid_to_hex(oid));
                        errors_found |= ERROR_REACHABLE;
                }
@@ -434,6 +451,14 @@ static int fsck_handle_ref(const char *refname, const struct object_id *oid,
 
        obj = parse_object(oid);
        if (!obj) {
+               if (is_promisor_object(oid)) {
+                       /*
+                        * Increment default_refs anyway, because this is a
+                        * valid ref.
+                        */
+                        default_refs++;
+                        return 0;
+               }
                error("%s: invalid sha1 pointer %s", refname, oid_to_hex(oid));
                errors_found |= ERROR_REACHABLE;
                /* We'll continue with the rest despite the error.. */
@@ -659,6 +684,9 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
        int i;
        struct alternate_object_database *alt;
 
+       /* fsck knows how to handle missing promisor objects */
+       fetch_if_missing = 0;
+
        errors_found = 0;
        check_replace_refs = 0;
 
@@ -731,6 +759,8 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
                        struct object *obj = lookup_object(oid.hash);
 
                        if (!obj || !(obj->flags & HAS_OBJ)) {
+                               if (is_promisor_object(&oid))
+                                       continue;
                                error("%s: object missing", oid_to_hex(&oid));
                                errors_found |= ERROR_OBJECT;
                                continue;
index 3c5eae0..77fa720 100644 (file)
@@ -458,6 +458,9 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
                        argv_array_push(&prune, prune_expire);
                        if (quiet)
                                argv_array_push(&prune, "--no-progress");
+                       if (repository_format_partial_clone)
+                               argv_array_push(&prune,
+                                               "--exclude-promisor-objects");
                        if (run_command_v_opt(prune.argv, RUN_GIT_CMD))
                                return error(FAILED_RUN, prune.argv[0]);
                }
index c532ff9..526da5c 100644 (file)
@@ -24,7 +24,8 @@ static int hash_literally(struct object_id *oid, int fd, const char *type, unsig
        if (strbuf_read(&buf, fd, 4096) < 0)
                ret = -1;
        else
-               ret = hash_sha1_file_literally(buf.buf, buf.len, type, oid, flags);
+               ret = hash_object_file_literally(buf.buf, buf.len, type, oid,
+                                                flags);
        strbuf_release(&buf);
        return ret;
 }
index 4c51aec..7e3e1a4 100644 (file)
@@ -91,7 +91,7 @@ static unsigned int input_offset, input_len;
 static off_t consumed_bytes;
 static off_t max_input_size;
 static unsigned deepest_delta;
-static git_SHA_CTX input_ctx;
+static git_hash_ctx input_ctx;
 static uint32_t input_crc32;
 static int input_fd, output_fd;
 static const char *curr_pack;
@@ -253,7 +253,7 @@ static void flush(void)
        if (input_offset) {
                if (output_fd >= 0)
                        write_or_die(output_fd, input_buffer, input_offset);
-               git_SHA1_Update(&input_ctx, input_buffer, input_offset);
+               the_hash_algo->update_fn(&input_ctx, input_buffer, input_offset);
                memmove(input_buffer, input_buffer + input_offset, input_len);
                input_offset = 0;
        }
@@ -326,7 +326,7 @@ static const char *open_pack_file(const char *pack_name)
                output_fd = -1;
                nothread_data.pack_fd = input_fd;
        }
-       git_SHA1_Init(&input_ctx);
+       the_hash_algo->init_fn(&input_ctx);
        return pack_name;
 }
 
@@ -437,22 +437,22 @@ static int is_delta_type(enum object_type type)
 }
 
 static void *unpack_entry_data(off_t offset, unsigned long size,
-                              enum object_type type, unsigned char *sha1)
+                              enum object_type type, struct object_id *oid)
 {
        static char fixed_buf[8192];
        int status;
        git_zstream stream;
        void *buf;
-       git_SHA_CTX c;
+       git_hash_ctx c;
        char hdr[32];
        int hdrlen;
 
        if (!is_delta_type(type)) {
                hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %lu", typename(type), size) + 1;
-               git_SHA1_Init(&c);
-               git_SHA1_Update(&c, hdr, hdrlen);
+               the_hash_algo->init_fn(&c);
+               the_hash_algo->update_fn(&c, hdr, hdrlen);
        } else
-               sha1 = NULL;
+               oid = NULL;
        if (type == OBJ_BLOB && size > big_file_threshold)
                buf = fixed_buf;
        else
@@ -469,8 +469,8 @@ static void *unpack_entry_data(off_t offset, unsigned long size,
                stream.avail_in = input_len;
                status = git_inflate(&stream, 0);
                use(input_len - stream.avail_in);
-               if (sha1)
-                       git_SHA1_Update(&c, last_out, stream.next_out - last_out);
+               if (oid)
+                       the_hash_algo->update_fn(&c, last_out, stream.next_out - last_out);
                if (buf == fixed_buf) {
                        stream.next_out = buf;
                        stream.avail_out = sizeof(fixed_buf);
@@ -479,15 +479,15 @@ static void *unpack_entry_data(off_t offset, unsigned long size,
        if (stream.total_out != size || status != Z_STREAM_END)
                bad_object(offset, _("inflate returned %d"), status);
        git_inflate_end(&stream);
-       if (sha1)
-               git_SHA1_Final(sha1, &c);
+       if (oid)
+               the_hash_algo->final_fn(oid->hash, &c);
        return buf == fixed_buf ? NULL : buf;
 }
 
 static void *unpack_raw_entry(struct object_entry *obj,
                              off_t *ofs_offset,
-                             unsigned char *ref_sha1,
-                             unsigned char *sha1)
+                             struct object_id *ref_oid,
+                             struct object_id *oid)
 {
        unsigned char *p;
        unsigned long size, c;
@@ -515,8 +515,8 @@ static void *unpack_raw_entry(struct object_entry *obj,
 
        switch (obj->type) {
        case OBJ_REF_DELTA:
-               hashcpy(ref_sha1, fill(20));
-               use(20);
+               hashcpy(ref_oid->hash, fill(the_hash_algo->rawsz));
+               use(the_hash_algo->rawsz);
                break;
        case OBJ_OFS_DELTA:
                p = fill(1);
@@ -546,7 +546,7 @@ static void *unpack_raw_entry(struct object_entry *obj,
        }
        obj->hdr_size = consumed_bytes - obj->idx.offset;
 
-       data = unpack_entry_data(obj->idx.offset, obj->size, obj->type, sha1);
+       data = unpack_entry_data(obj->idx.offset, obj->size, obj->type, oid);
        obj->idx.crc32 = input_crc32;
        return data;
 }
@@ -958,9 +958,8 @@ static void resolve_delta(struct object_entry *delta_obj,
        free(delta_data);
        if (!result->data)
                bad_object(delta_obj->idx.offset, _("failed to apply delta"));
-       hash_sha1_file(result->data, result->size,
-                      typename(delta_obj->real_type),
-                      delta_obj->idx.oid.hash);
+       hash_object_file(result->data, result->size,
+                        typename(delta_obj->real_type), &delta_obj->idx.oid);
        sha1_object(result->data, NULL, result->size, delta_obj->real_type,
                    &delta_obj->idx.oid);
        counter_lock();
@@ -1119,11 +1118,11 @@ static void *threaded_second_pass(void *data)
  * - calculate SHA1 of all non-delta objects;
  * - remember base (SHA1 or offset) for all deltas.
  */
-static void parse_pack_objects(unsigned char *sha1)
+static void parse_pack_objects(unsigned char *hash)
 {
        int i, nr_delays = 0;
        struct ofs_delta_entry *ofs_delta = ofs_deltas;
-       unsigned char ref_delta_sha1[20];
+       struct object_id ref_delta_oid;
        struct stat st;
 
        if (verbose)
@@ -1133,8 +1132,8 @@ static void parse_pack_objects(unsigned char *sha1)
        for (i = 0; i < nr_objects; i++) {
                struct object_entry *obj = &objects[i];
                void *data = unpack_raw_entry(obj, &ofs_delta->offset,
-                                             ref_delta_sha1,
-                                             obj->idx.oid.hash);
+                                             &ref_delta_oid,
+                                             &obj->idx.oid);
                obj->real_type = obj->type;
                if (obj->type == OBJ_OFS_DELTA) {
                        nr_ofs_deltas++;
@@ -1142,7 +1141,7 @@ static void parse_pack_objects(unsigned char *sha1)
                        ofs_delta++;
                } else if (obj->type == OBJ_REF_DELTA) {
                        ALLOC_GROW(ref_deltas, nr_ref_deltas + 1, ref_deltas_alloc);
-                       hashcpy(ref_deltas[nr_ref_deltas].sha1, ref_delta_sha1);
+                       hashcpy(ref_deltas[nr_ref_deltas].sha1, ref_delta_oid.hash);
                        ref_deltas[nr_ref_deltas].obj_no = i;
                        nr_ref_deltas++;
                } else if (!data) {
@@ -1160,10 +1159,10 @@ static void parse_pack_objects(unsigned char *sha1)
 
        /* Check pack integrity */
        flush();
-       git_SHA1_Final(sha1, &input_ctx);
-       if (hashcmp(fill(20), sha1))
+       the_hash_algo->final_fn(hash, &input_ctx);
+       if (hashcmp(fill(the_hash_algo->rawsz), hash))
                die(_("pack is corrupted (SHA1 mismatch)"));
-       use(20);
+       use(the_hash_algo->rawsz);
 
        /* If input_fd is a file, we should have reached its end now. */
        if (fstat(input_fd, &st))
@@ -1239,21 +1238,21 @@ static void resolve_deltas(void)
 /*
  * Third pass:
  * - append objects to convert thin pack to full pack if required
- * - write the final 20-byte SHA-1
+ * - write the final pack hash
  */
-static void fix_unresolved_deltas(struct sha1file *f);
-static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned char *pack_sha1)
+static void fix_unresolved_deltas(struct hashfile *f);
+static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned char *pack_hash)
 {
        if (nr_ref_deltas + nr_ofs_deltas == nr_resolved_deltas) {
                stop_progress(&progress);
-               /* Flush remaining pack final 20-byte SHA1. */
+               /* Flush remaining pack final hash. */
                flush();
                return;
        }
 
        if (fix_thin_pack) {
-               struct sha1file *f;
-               unsigned char read_sha1[20], tail_sha1[20];
+               struct hashfile *f;
+               unsigned char read_hash[GIT_MAX_RAWSZ], tail_hash[GIT_MAX_RAWSZ];
                struct strbuf msg = STRBUF_INIT;
                int nr_unresolved = nr_ofs_deltas + nr_ref_deltas - nr_resolved_deltas;
                int nr_objects_initial = nr_objects;
@@ -1262,7 +1261,7 @@ static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned cha
                REALLOC_ARRAY(objects, nr_objects + nr_unresolved + 1);
                memset(objects + nr_objects + 1, 0,
                       nr_unresolved * sizeof(*objects));
-               f = sha1fd(output_fd, curr_pack);
+               f = hashfd(output_fd, curr_pack);
                fix_unresolved_deltas(f);
                strbuf_addf(&msg, Q_("completed with %d local object",
                                     "completed with %d local objects",
@@ -1270,12 +1269,12 @@ static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned cha
                            nr_objects - nr_objects_initial);
                stop_progress_msg(&progress, msg.buf);
                strbuf_release(&msg);
-               sha1close(f, tail_sha1, 0);
-               hashcpy(read_sha1, pack_sha1);
-               fixup_pack_header_footer(output_fd, pack_sha1,
+               hashclose(f, tail_hash, 0);
+               hashcpy(read_hash, pack_hash);
+               fixup_pack_header_footer(output_fd, pack_hash,
                                         curr_pack, nr_objects,
-                                        read_sha1, consumed_bytes-20);
-               if (hashcmp(read_sha1, tail_sha1) != 0)
+                                        read_hash, consumed_bytes-the_hash_algo->rawsz);
+               if (hashcmp(read_hash, tail_hash) != 0)
                        die(_("Unexpected tail checksum for %s "
                              "(disk corruption?)"), curr_pack);
        }
@@ -1286,7 +1285,7 @@ static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned cha
                    nr_ofs_deltas + nr_ref_deltas - nr_resolved_deltas);
 }
 
-static int write_compressed(struct sha1file *f, void *in, unsigned int size)
+static int write_compressed(struct hashfile *f, void *in, unsigned int size)
 {
        git_zstream stream;
        int status;
@@ -1300,7 +1299,7 @@ static int write_compressed(struct sha1file *f, void *in, unsigned int size)
                stream.next_out = outbuf;
                stream.avail_out = sizeof(outbuf);
                status = git_deflate(&stream, Z_FINISH);
-               sha1write(f, outbuf, sizeof(outbuf) - stream.avail_out);
+               hashwrite(f, outbuf, sizeof(outbuf) - stream.avail_out);
        } while (status == Z_OK);
 
        if (status != Z_STREAM_END)
@@ -1310,7 +1309,7 @@ static int write_compressed(struct sha1file *f, void *in, unsigned int size)
        return size;
 }
 
-static struct object_entry *append_obj_to_pack(struct sha1file *f,
+static struct object_entry *append_obj_to_pack(struct hashfile *f,
                               const unsigned char *sha1, void *buf,
                               unsigned long size, enum object_type type)
 {
@@ -1327,7 +1326,7 @@ static struct object_entry *append_obj_to_pack(struct sha1file *f,
        }
        header[n++] = c;
        crc32_begin(f);
-       sha1write(f, header, n);
+       hashwrite(f, header, n);
        obj[0].size = size;
        obj[0].hdr_size = n;
        obj[0].type = type;
@@ -1335,7 +1334,7 @@ static struct object_entry *append_obj_to_pack(struct sha1file *f,
        obj[1].idx.offset = obj[0].idx.offset + n;
        obj[1].idx.offset += write_compressed(f, buf, size);
        obj[0].idx.crc32 = crc32_end(f);
-       sha1flush(f);
+       hashflush(f);
        hashcpy(obj->idx.oid.hash, sha1);
        return obj;
 }
@@ -1347,7 +1346,7 @@ static int delta_pos_compare(const void *_a, const void *_b)
        return a->obj_no - b->obj_no;
 }
 
-static void fix_unresolved_deltas(struct sha1file *f)
+static void fix_unresolved_deltas(struct hashfile *f)
 {
        struct ref_delta_entry **sorted_by_pos;
        int i;
@@ -1389,15 +1388,60 @@ static void fix_unresolved_deltas(struct sha1file *f)
        free(sorted_by_pos);
 }
 
+static const char *derive_filename(const char *pack_name, const char *suffix,
+                                  struct strbuf *buf)
+{
+       size_t len;
+       if (!strip_suffix(pack_name, ".pack", &len))
+               die(_("packfile name '%s' does not end with '.pack'"),
+                   pack_name);
+       strbuf_add(buf, pack_name, len);
+       strbuf_addch(buf, '.');
+       strbuf_addstr(buf, suffix);
+       return buf->buf;
+}
+
+static void write_special_file(const char *suffix, const char *msg,
+                              const char *pack_name, const unsigned char *hash,
+                              const char **report)
+{
+       struct strbuf name_buf = STRBUF_INIT;
+       const char *filename;
+       int fd;
+       int msg_len = strlen(msg);
+
+       if (pack_name)
+               filename = derive_filename(pack_name, suffix, &name_buf);
+       else
+               filename = odb_pack_name(&name_buf, hash, suffix);
+
+       fd = odb_pack_keep(filename);
+       if (fd < 0) {
+               if (errno != EEXIST)
+                       die_errno(_("cannot write %s file '%s'"),
+                                 suffix, filename);
+       } else {
+               if (msg_len > 0) {
+                       write_or_die(fd, msg, msg_len);
+                       write_or_die(fd, "\n", 1);
+               }
+               if (close(fd) != 0)
+                       die_errno(_("cannot close written %s file '%s'"),
+                                 suffix, filename);
+               if (report)
+                       *report = suffix;
+       }
+       strbuf_release(&name_buf);
+}
+
 static void final(const char *final_pack_name, const char *curr_pack_name,
                  const char *final_index_name, const char *curr_index_name,
-                 const char *keep_name, const char *keep_msg,
-                 unsigned char *sha1)
+                 const char *keep_msg, const char *promisor_msg,
+                 unsigned char *hash)
 {
        const char *report = "pack";
        struct strbuf pack_name = STRBUF_INIT;
        struct strbuf index_name = STRBUF_INIT;
-       struct strbuf keep_name_buf = STRBUF_INIT;
        int err;
 
        if (!from_stdin) {
@@ -1409,32 +1453,16 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
                        die_errno(_("error while closing pack file"));
        }
 
-       if (keep_msg) {
-               int keep_fd, keep_msg_len = strlen(keep_msg);
-
-               if (!keep_name)
-                       keep_name = odb_pack_name(&keep_name_buf, sha1, "keep");
-
-               keep_fd = odb_pack_keep(keep_name);
-               if (keep_fd < 0) {
-                       if (errno != EEXIST)
-                               die_errno(_("cannot write keep file '%s'"),
-                                         keep_name);
-               } else {
-                       if (keep_msg_len > 0) {
-                               write_or_die(keep_fd, keep_msg, keep_msg_len);
-                               write_or_die(keep_fd, "\n", 1);
-                       }
-                       if (close(keep_fd) != 0)
-                               die_errno(_("cannot close written keep file '%s'"),
-                                         keep_name);
-                       report = "keep";
-               }
-       }
+       if (keep_msg)
+               write_special_file("keep", keep_msg, final_pack_name, hash,
+                                  &report);
+       if (promisor_msg)
+               write_special_file("promisor", promisor_msg, final_pack_name,
+                                  hash, NULL);
 
        if (final_pack_name != curr_pack_name) {
                if (!final_pack_name)
-                       final_pack_name = odb_pack_name(&pack_name, sha1, "pack");
+                       final_pack_name = odb_pack_name(&pack_name, hash, "pack");
                if (finalize_object_file(curr_pack_name, final_pack_name))
                        die(_("cannot store pack file"));
        } else if (from_stdin)
@@ -1442,18 +1470,18 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
 
        if (final_index_name != curr_index_name) {
                if (!final_index_name)
-                       final_index_name = odb_pack_name(&index_name, sha1, "idx");
+                       final_index_name = odb_pack_name(&index_name, hash, "idx");
                if (finalize_object_file(curr_index_name, final_index_name))
                        die(_("cannot store index file"));
        } else
                chmod(final_index_name, 0444);
 
        if (!from_stdin) {
-               printf("%s\n", sha1_to_hex(sha1));
+               printf("%s\n", sha1_to_hex(hash));
        } else {
                struct strbuf buf = STRBUF_INIT;
 
-               strbuf_addf(&buf, "%s\t%s\n", report, sha1_to_hex(sha1));
+               strbuf_addf(&buf, "%s\t%s\n", report, sha1_to_hex(hash));
                write_or_die(1, buf.buf, buf.len);
                strbuf_release(&buf);
 
@@ -1472,7 +1500,6 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
 
        strbuf_release(&index_name);
        strbuf_release(&pack_name);
-       strbuf_release(&keep_name_buf);
 }
 
 static int git_index_pack_config(const char *k, const char *v, void *cb)
@@ -1615,32 +1642,26 @@ static void show_pack_info(int stat_only)
        }
 }
 
-static const char *derive_filename(const char *pack_name, const char *suffix,
-                                  struct strbuf *buf)
-{
-       size_t len;
-       if (!strip_suffix(pack_name, ".pack", &len))
-               die(_("packfile name '%s' does not end with '.pack'"),
-                   pack_name);
-       strbuf_add(buf, pack_name, len);
-       strbuf_addstr(buf, suffix);
-       return buf->buf;
-}
-
 int cmd_index_pack(int argc, const char **argv, const char *prefix)
 {
        int i, fix_thin_pack = 0, verify = 0, stat_only = 0;
        const char *curr_index;
        const char *index_name = NULL, *pack_name = NULL;
-       const char *keep_name = NULL, *keep_msg = NULL;
-       struct strbuf index_name_buf = STRBUF_INIT,
-                     keep_name_buf = STRBUF_INIT;
+       const char *keep_msg = NULL;
+       const char *promisor_msg = NULL;
+       struct strbuf index_name_buf = STRBUF_INIT;
        struct pack_idx_entry **idx_objects;
        struct pack_idx_option opts;
-       unsigned char pack_sha1[20];
+       unsigned char pack_hash[GIT_MAX_RAWSZ];
        unsigned foreign_nr = 1;        /* zero is a "good" value, assume bad */
        int report_end_of_input = 0;
 
+       /*
+        * index-pack never needs to fetch missing objects, since it only
+        * accesses the repo to do hash collision checks
+        */
+       fetch_if_missing = 0;
+
        if (argc == 2 && !strcmp(argv[1], "-h"))
                usage(index_pack_usage);
 
@@ -1678,6 +1699,8 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
                                stat_only = 1;
                        } else if (skip_to_optional_arg(arg, "--keep", &keep_msg)) {
                                ; /* nothing to do */
+                       } else if (skip_to_optional_arg(arg, "--promisor", &promisor_msg)) {
+                               ; /* already parsed */
                        } else if (starts_with(arg, "--threads=")) {
                                char *end;
                                nr_threads = strtoul(arg+10, &end, 0);
@@ -1740,9 +1763,7 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
        if (from_stdin && !startup_info->have_repository)
                die(_("--stdin requires a git repository"));
        if (!index_name && pack_name)
-               index_name = derive_filename(pack_name, ".idx", &index_name_buf);
-       if (keep_msg && !keep_name && pack_name)
-               keep_name = derive_filename(pack_name, ".keep", &keep_name_buf);
+               index_name = derive_filename(pack_name, "idx", &index_name_buf);
 
        if (verify) {
                if (!index_name)
@@ -1768,11 +1789,11 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
        if (show_stat)
                obj_stat = xcalloc(st_add(nr_objects, 1), sizeof(struct object_stat));
        ofs_deltas = xcalloc(nr_objects, sizeof(struct ofs_delta_entry));
-       parse_pack_objects(pack_sha1);
+       parse_pack_objects(pack_hash);
        if (report_end_of_input)
                write_in_full(2, "\0", 1);
        resolve_deltas();
-       conclude_pack(fix_thin_pack, curr_pack, pack_sha1);
+       conclude_pack(fix_thin_pack, curr_pack, pack_hash);
        free(ofs_deltas);
        free(ref_deltas);
        if (strict)
@@ -1784,19 +1805,18 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
        ALLOC_ARRAY(idx_objects, nr_objects);
        for (i = 0; i < nr_objects; i++)
                idx_objects[i] = &objects[i].idx;
-       curr_index = write_idx_file(index_name, idx_objects, nr_objects, &opts, pack_sha1);
+       curr_index = write_idx_file(index_name, idx_objects, nr_objects, &opts, pack_hash);
        free(idx_objects);
 
        if (!verify)
                final(pack_name, curr_pack,
                      index_name, curr_index,
-                     keep_name, keep_msg,
-                     pack_sha1);
+                     keep_msg, promisor_msg,
+                     pack_hash);
        else
                close(input_fd);
        free(objects);
        strbuf_release(&index_name_buf);
-       strbuf_release(&keep_name_buf);
        if (pack_name == NULL)
                free((void *) curr_pack);
        if (index_name == NULL)
index 14fdf39..94ee177 100644 (file)
@@ -29,6 +29,8 @@
 #include "gpg-interface.h"
 #include "progress.h"
 
+#define MAIL_DEFAULT_WRAP 72
+
 /* Set a default date-time format for git log ("log.date" config variable) */
 static const char *default_date_mode = NULL;
 
@@ -188,8 +190,8 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
        if (rev->show_notes)
                init_display_notes(&rev->notes_opt);
 
-       if (rev->diffopt.pickaxe || rev->diffopt.filter ||
-           rev->diffopt.flags.follow_renames)
+       if ((rev->diffopt.pickaxe_opts & DIFF_PICKAXE_KINDS_MASK) ||
+           rev->diffopt.filter || rev->diffopt.flags.follow_renames)
                rev->always_show_header = 0;
 
        if (source)
@@ -1044,7 +1046,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
 
        shortlog_init(&log);
        log.wrap_lines = 1;
-       log.wrap = 72;
+       log.wrap = MAIL_DEFAULT_WRAP;
        log.in1 = 2;
        log.in2 = 4;
        log.file = rev->diffopt.file;
@@ -1061,6 +1063,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
 
        memcpy(&opts, &rev->diffopt, sizeof(opts));
        opts.output_format = DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
+       opts.stat_width = MAIL_DEFAULT_WRAP;
 
        diff_setup_done(&opts);
 
@@ -1614,6 +1617,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                (!rev.diffopt.output_format ||
                 rev.diffopt.output_format == DIFF_FORMAT_PATCH))
                rev.diffopt.output_format = DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_SUMMARY;
+       if (!rev.diffopt.stat_width)
+               rev.diffopt.stat_width = MAIL_DEFAULT_WRAP;
 
        /* Always generate a patch */
        rev.diffopt.output_format |= DIFF_FORMAT_PATCH;
index 30264cf..92ba99a 100644 (file)
@@ -820,8 +820,8 @@ static int merge_trivial(struct commit *head, struct commit_list *remoteheads)
        pptr = commit_list_append(head, pptr);
        pptr = commit_list_append(remoteheads->item, pptr);
        prepare_to_commit(remoteheads);
-       if (commit_tree(merge_msg.buf, merge_msg.len, result_tree.hash, parents,
-                       result_commit.hash, NULL, sign_commit))
+       if (commit_tree(merge_msg.buf, merge_msg.len, &result_tree, parents,
+                       &result_commit, NULL, sign_commit))
                die(_("failed to write commit object"));
        finish(head, remoteheads, &result_commit, "In-index merge");
        drop_save();
@@ -845,8 +845,8 @@ static int finish_automerge(struct commit *head,
                commit_list_insert(head, &parents);
        strbuf_addch(&merge_msg, '\n');
        prepare_to_commit(remoteheads);
-       if (commit_tree(merge_msg.buf, merge_msg.len, result_tree->hash, parents,
-                       result_commit.hash, NULL, sign_commit))
+       if (commit_tree(merge_msg.buf, merge_msg.len, result_tree, parents,
+                       &result_commit, NULL, sign_commit))
                die(_("failed to write commit object"));
        strbuf_addf(&buf, "Merge made by the '%s' strategy.", wt_strategy);
        finish(head, remoteheads, &result_commit, buf.buf);
index 031b750..beb5528 100644 (file)
@@ -151,7 +151,7 @@ static int verify_tag(char *buffer, unsigned long size)
 int cmd_mktag(int argc, const char **argv, const char *prefix)
 {
        struct strbuf buf = STRBUF_INIT;
-       unsigned char result_sha1[20];
+       struct object_id result;
 
        if (argc != 1)
                usage("git mktag");
@@ -165,10 +165,10 @@ int cmd_mktag(int argc, const char **argv, const char *prefix)
        if (verify_tag(buf.buf, buf.len) < 0)
                die("invalid tag signature file");
 
-       if (write_sha1_file(buf.buf, buf.len, tag_type, result_sha1) < 0)
+       if (write_object_file(buf.buf, buf.len, tag_type, &result) < 0)
                die("unable to write tag file");
 
        strbuf_release(&buf);
-       printf("%s\n", sha1_to_hex(result_sha1));
+       printf("%s\n", oid_to_hex(&result));
        return 0;
 }
index da0fd8c..8dd9f52 100644 (file)
@@ -40,7 +40,7 @@ static int ent_compare(const void *a_, const void *b_)
                                 b->name, b->len, b->mode);
 }
 
-static void write_tree(unsigned char *sha1)
+static void write_tree(struct object_id *oid)
 {
        struct strbuf buf;
        size_t size;
@@ -57,7 +57,7 @@ static void write_tree(unsigned char *sha1)
                strbuf_add(&buf, ent->sha1, 20);
        }
 
-       write_sha1_file(buf.buf, buf.len, tree_type, sha1);
+       write_object_file(buf.buf, buf.len, tree_type, oid);
        strbuf_release(&buf);
 }
 
@@ -142,7 +142,7 @@ static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_miss
 int cmd_mktree(int ac, const char **av, const char *prefix)
 {
        struct strbuf sb = STRBUF_INIT;
-       unsigned char sha1[20];
+       struct object_id oid;
        int nul_term_line = 0;
        int allow_missing = 0;
        int is_batch_mode = 0;
@@ -181,8 +181,8 @@ int cmd_mktree(int ac, const char **av, const char *prefix)
                         */
                        ; /* skip creating an empty tree */
                } else {
-                       write_tree(sha1);
-                       puts(sha1_to_hex(sha1));
+                       write_tree(&oid);
+                       puts(oid_to_hex(&oid));
                        fflush(stdout);
                }
                used=0; /* reset tree entry buffer for re-use in batch mode */
index 7c81761..39304ba 100644 (file)
@@ -198,9 +198,9 @@ static void prepare_note_data(const struct object_id *object, struct note_data *
        }
 }
 
-static void write_note_data(struct note_data *d, unsigned char *sha1)
+static void write_note_data(struct note_data *d, struct object_id *oid)
 {
-       if (write_sha1_file(d->buf.buf, d->buf.len, blob_type, sha1)) {
+       if (write_object_file(d->buf.buf, d->buf.len, blob_type, oid)) {
                error(_("unable to write note object"));
                if (d->edit_path)
                        error(_("the note contents have been left in %s"),
@@ -459,7 +459,7 @@ static int add(int argc, const char **argv, const char *prefix)
 
        prepare_note_data(&object, &d, note ? note->hash : NULL);
        if (d.buf.len || allow_empty) {
-               write_note_data(&d, new_note.hash);
+               write_note_data(&d, &new_note);
                if (add_note(t, &object, &new_note, combine_notes_overwrite))
                        die("BUG: combine_notes_overwrite failed");
                commit_notes(t, "Notes added by 'git notes add'");
@@ -619,7 +619,7 @@ static int append_edit(int argc, const char **argv, const char *prefix)
        }
 
        if (d.buf.len || allow_empty) {
-               write_note_data(&d, new_note.hash);
+               write_note_data(&d, &new_note);
                if (add_note(t, &object, &new_note, combine_notes_overwrite))
                        die("BUG: combine_notes_overwrite failed");
                logmsg = xstrfmt("Notes added by 'git notes %s'", argv[0]);
index 6b9cfc2..5c674b2 100644 (file)
@@ -26,7 +26,7 @@
 #include "reachable.h"
 #include "sha1-array.h"
 #include "argv-array.h"
-#include "mru.h"
+#include "list.h"
 #include "packfile.h"
 
 static const char *pack_usage[] = {
@@ -75,6 +75,8 @@ static int use_bitmap_index = -1;
 static int write_bitmap_index;
 static uint16_t write_bitmap_options;
 
+static int exclude_promisor_objects;
+
 static unsigned long delta_cache_size = 0;
 static unsigned long max_delta_cache_size = 256 * 1024 * 1024;
 static unsigned long cache_max_small_delta_size = 1000;
@@ -84,8 +86,9 @@ static unsigned long window_memory_limit = 0;
 static struct list_objects_filter_options filter_options;
 
 enum missing_action {
-       MA_ERROR = 0,    /* fail if any missing objects are encountered */
-       MA_ALLOW_ANY,    /* silently allow ALL missing objects */
+       MA_ERROR = 0,      /* fail if any missing objects are encountered */
+       MA_ALLOW_ANY,      /* silently allow ALL missing objects */
+       MA_ALLOW_PROMISOR, /* silently allow all missing PROMISOR objects */
 };
 static enum missing_action arg_missing_action;
 static show_object_fn fn_show_object;
@@ -161,7 +164,7 @@ static unsigned long do_compress(void **pptr, unsigned long size)
        return stream.total_out;
 }
 
-static unsigned long write_large_blob_data(struct git_istream *st, struct sha1file *f,
+static unsigned long write_large_blob_data(struct git_istream *st, struct hashfile *f,
                                           const struct object_id *oid)
 {
        git_zstream stream;
@@ -185,7 +188,7 @@ static unsigned long write_large_blob_data(struct git_istream *st, struct sha1fi
                        stream.next_out = obuf;
                        stream.avail_out = sizeof(obuf);
                        zret = git_deflate(&stream, readlen ? 0 : Z_FINISH);
-                       sha1write(f, obuf, stream.next_out - obuf);
+                       hashwrite(f, obuf, stream.next_out - obuf);
                        olen += stream.next_out - obuf;
                }
                if (stream.avail_in)
@@ -230,7 +233,7 @@ static int check_pack_inflate(struct packed_git *p,
                stream.total_in == len) ? 0 : -1;
 }
 
-static void copy_pack_data(struct sha1file *f,
+static void copy_pack_data(struct hashfile *f,
                struct packed_git *p,
                struct pack_window **w_curs,
                off_t offset,
@@ -243,14 +246,14 @@ static void copy_pack_data(struct sha1file *f,
                in = use_pack(p, w_curs, offset, &avail);
                if (avail > len)
                        avail = (unsigned long)len;
-               sha1write(f, in, avail);
+               hashwrite(f, in, avail);
                offset += avail;
                len -= avail;
        }
 }
 
 /* Return 0 if we will bust the pack-size limit */
-static unsigned long write_no_reuse_object(struct sha1file *f, struct object_entry *entry,
+static unsigned long write_no_reuse_object(struct hashfile *f, struct object_entry *entry,
                                           unsigned long limit, int usable_delta)
 {
        unsigned long size, datalen;
@@ -323,8 +326,8 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent
                        free(buf);
                        return 0;
                }
-               sha1write(f, header, hdrlen);
-               sha1write(f, dheader + pos, sizeof(dheader) - pos);
+               hashwrite(f, header, hdrlen);
+               hashwrite(f, dheader + pos, sizeof(dheader) - pos);
                hdrlen += sizeof(dheader) - pos;
        } else if (type == OBJ_REF_DELTA) {
                /*
@@ -337,8 +340,8 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent
                        free(buf);
                        return 0;
                }
-               sha1write(f, header, hdrlen);
-               sha1write(f, entry->delta->idx.oid.hash, 20);
+               hashwrite(f, header, hdrlen);
+               hashwrite(f, entry->delta->idx.oid.hash, 20);
                hdrlen += 20;
        } else {
                if (limit && hdrlen + datalen + 20 >= limit) {
@@ -347,13 +350,13 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent
                        free(buf);
                        return 0;
                }
-               sha1write(f, header, hdrlen);
+               hashwrite(f, header, hdrlen);
        }
        if (st) {
                datalen = write_large_blob_data(st, f, &entry->idx.oid);
                close_istream(st);
        } else {
-               sha1write(f, buf, datalen);
+               hashwrite(f, buf, datalen);
                free(buf);
        }
 
@@ -361,7 +364,7 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent
 }
 
 /* Return 0 if we will bust the pack-size limit */
-static off_t write_reuse_object(struct sha1file *f, struct object_entry *entry,
+static off_t write_reuse_object(struct hashfile *f, struct object_entry *entry,
                                unsigned long limit, int usable_delta)
 {
        struct packed_git *p = entry->in_pack;
@@ -412,8 +415,8 @@ static off_t write_reuse_object(struct sha1file *f, struct object_entry *entry,
                        unuse_pack(&w_curs);
                        return 0;
                }
-               sha1write(f, header, hdrlen);
-               sha1write(f, dheader + pos, sizeof(dheader) - pos);
+               hashwrite(f, header, hdrlen);
+               hashwrite(f, dheader + pos, sizeof(dheader) - pos);
                hdrlen += sizeof(dheader) - pos;
                reused_delta++;
        } else if (type == OBJ_REF_DELTA) {
@@ -421,8 +424,8 @@ static off_t write_reuse_object(struct sha1file *f, struct object_entry *entry,
                        unuse_pack(&w_curs);
                        return 0;
                }
-               sha1write(f, header, hdrlen);
-               sha1write(f, entry->delta->idx.oid.hash, 20);
+               hashwrite(f, header, hdrlen);
+               hashwrite(f, entry->delta->idx.oid.hash, 20);
                hdrlen += 20;
                reused_delta++;
        } else {
@@ -430,7 +433,7 @@ static off_t write_reuse_object(struct sha1file *f, struct object_entry *entry,
                        unuse_pack(&w_curs);
                        return 0;
                }
-               sha1write(f, header, hdrlen);
+               hashwrite(f, header, hdrlen);
        }
        copy_pack_data(f, p, &w_curs, offset, datalen);
        unuse_pack(&w_curs);
@@ -439,7 +442,7 @@ static off_t write_reuse_object(struct sha1file *f, struct object_entry *entry,
 }
 
 /* Return 0 if we will bust the pack-size limit */
-static off_t write_object(struct sha1file *f,
+static off_t write_object(struct hashfile *f,
                          struct object_entry *entry,
                          off_t write_offset)
 {
@@ -512,7 +515,7 @@ enum write_one_status {
        WRITE_ONE_RECURSIVE = 2 /* already scheduled to be written */
 };
 
-static enum write_one_status write_one(struct sha1file *f,
+static enum write_one_status write_one(struct hashfile *f,
                                       struct object_entry *e,
                                       off_t *offset)
 {
@@ -731,7 +734,7 @@ static struct object_entry **compute_write_order(void)
        return wo;
 }
 
-static off_t write_reused_pack(struct sha1file *f)
+static off_t write_reused_pack(struct hashfile *f)
 {
        unsigned char buffer[8192];
        off_t to_write, total;
@@ -762,7 +765,7 @@ static off_t write_reused_pack(struct sha1file *f)
                if (read_pack > to_write)
                        read_pack = to_write;
 
-               sha1write(f, buffer, read_pack);
+               hashwrite(f, buffer, read_pack);
                to_write -= read_pack;
 
                /*
@@ -791,7 +794,7 @@ static const char no_split_warning[] = N_(
 static void write_pack_file(void)
 {
        uint32_t i = 0, j;
-       struct sha1file *f;
+       struct hashfile *f;
        off_t offset;
        uint32_t nr_remaining = nr_result;
        time_t last_mtime = 0;
@@ -807,7 +810,7 @@ static void write_pack_file(void)
                char *pack_tmp_name = NULL;
 
                if (pack_to_stdout)
-                       f = sha1fd_throughput(1, "<stdout>", progress_state);
+                       f = hashfd_throughput(1, "<stdout>", progress_state);
                else
                        f = create_tmp_packfile(&pack_tmp_name);
 
@@ -834,11 +837,11 @@ static void write_pack_file(void)
                 * If so, rewrite it like in fast-import
                 */
                if (pack_to_stdout) {
-                       sha1close(f, oid.hash, CSUM_CLOSE);
+                       hashclose(f, oid.hash, CSUM_CLOSE);
                } else if (nr_written == nr_remaining) {
-                       sha1close(f, oid.hash, CSUM_FSYNC);
+                       hashclose(f, oid.hash, CSUM_FSYNC);
                } else {
-                       int fd = sha1close(f, oid.hash, 0);
+                       int fd = hashclose(f, oid.hash, 0);
                        fixup_pack_header_footer(fd, oid.hash, pack_tmp_name,
                                                 nr_written, oid.hash, offset);
                        close(fd);
@@ -1006,8 +1009,8 @@ static int want_object_in_pack(const struct object_id *oid,
                               struct packed_git **found_pack,
                               off_t *found_offset)
 {
-       struct mru_entry *entry;
        int want;
+       struct list_head *pos;
 
        if (!exclude && local && has_loose_object_nonlocal(oid->hash))
                return 0;
@@ -1023,8 +1026,8 @@ static int want_object_in_pack(const struct object_id *oid,
                        return want;
        }
 
-       for (entry = packed_git_mru.head; entry; entry = entry->next) {
-               struct packed_git *p = entry->item;
+       list_for_each(pos, &packed_git_mru) {
+               struct packed_git *p = list_entry(pos, struct packed_git, mru);
                off_t offset;
 
                if (p == *found_pack)
@@ -1041,7 +1044,7 @@ static int want_object_in_pack(const struct object_id *oid,
                        }
                        want = want_found_object(exclude, p);
                        if (!exclude && want > 0)
-                               mru_mark(&packed_git_mru, entry);
+                               list_move(&p->mru, &packed_git_mru);
                        if (want != -1)
                                return want;
                }
@@ -2578,6 +2581,20 @@ static void show_object__ma_allow_any(struct object *obj, const char *name, void
        show_object(obj, name, data);
 }
 
+static void show_object__ma_allow_promisor(struct object *obj, const char *name, void *data)
+{
+       assert(arg_missing_action == MA_ALLOW_PROMISOR);
+
+       /*
+        * Quietly ignore EXPECTED missing objects.  This avoids problems with
+        * staging them now and getting an odd error later.
+        */
+       if (!has_object_file(&obj->oid) && is_promisor_object(&obj->oid))
+               return;
+
+       show_object(obj, name, data);
+}
+
 static int option_parse_missing_action(const struct option *opt,
                                       const char *arg, int unset)
 {
@@ -2592,10 +2609,18 @@ static int option_parse_missing_action(const struct option *opt,
 
        if (!strcmp(arg, "allow-any")) {
                arg_missing_action = MA_ALLOW_ANY;
+               fetch_if_missing = 0;
                fn_show_object = show_object__ma_allow_any;
                return 0;
        }
 
+       if (!strcmp(arg, "allow-promisor")) {
+               arg_missing_action = MA_ALLOW_PROMISOR;
+               fetch_if_missing = 0;
+               fn_show_object = show_object__ma_allow_promisor;
+               return 0;
+       }
+
        die(_("invalid value for --missing"));
        return 0;
 }
@@ -2768,7 +2793,7 @@ static void loosen_unused_packed_objects(struct rev_info *revs)
                        if (!packlist_find(&to_pack, oid.hash, NULL) &&
                            !has_sha1_pack_kept_or_nonlocal(&oid) &&
                            !loosened_object_can_be_discarded(&oid, p->mtime))
-                               if (force_object_loose(oid.hash, p->mtime))
+                               if (force_object_loose(&oid, p->mtime))
                                        die("unable to force loose object");
                }
        }
@@ -3009,6 +3034,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
                { OPTION_CALLBACK, 0, "missing", NULL, N_("action"),
                  N_("handling for missing objects"), PARSE_OPT_NONEG,
                  option_parse_missing_action },
+               OPT_BOOL(0, "exclude-promisor-objects", &exclude_promisor_objects,
+                        N_("do not pack objects in promisor packfiles")),
                OPT_END(),
        };
 
@@ -3054,6 +3081,12 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
                argv_array_push(&rp, "--unpacked");
        }
 
+       if (exclude_promisor_objects) {
+               use_internal_rev_list = 1;
+               fetch_if_missing = 0;
+               argv_array_push(&rp, "--exclude-promisor-objects");
+       }
+
        if (!reuse_object)
                reuse_delta = 0;
        if (pack_compression_level == -1)
index d2fdae6..4cfec82 100644 (file)
@@ -101,12 +101,15 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
 {
        struct rev_info revs;
        struct progress *progress = NULL;
+       int exclude_promisor_objects = 0;
        const struct option options[] = {
                OPT__DRY_RUN(&show_only, N_("do not remove, show only")),
                OPT__VERBOSE(&verbose, N_("report pruned objects")),
                OPT_BOOL(0, "progress", &show_progress, N_("show progress")),
                OPT_EXPIRY_DATE(0, "expire", &expire,
                                N_("expire objects older than <time>")),
+               OPT_BOOL(0, "exclude-promisor-objects", &exclude_promisor_objects,
+                        N_("limit traversal to objects outside promisor packfiles")),
                OPT_END()
        };
        char *s;
@@ -139,6 +142,10 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
                show_progress = isatty(2);
        if (show_progress)
                progress = start_delayed_progress(_("Checking connectivity"), 0);
+       if (exclude_promisor_objects) {
+               fetch_if_missing = 0;
+               revs.exclude_promisor_objects = 1;
+       }
 
        mark_reachable_objects(&revs, 1, expire, progress);
        stop_progress(&progress);
index 511dbbe..1876271 100644 (file)
@@ -574,6 +574,7 @@ static int rebase_submodules(void)
        cp.no_stdin = 1;
        argv_array_pushl(&cp.args, "submodule", "update",
                                   "--recursive", "--rebase", NULL);
+       argv_push_verbosity(&cp.args);
 
        return run_command(&cp);
 }
@@ -586,6 +587,7 @@ static int update_submodules(void)
        cp.no_stdin = 1;
        argv_array_pushl(&cp.args, "submodule", "update",
                                   "--recursive", "--checkout", NULL);
+       argv_push_verbosity(&cp.args);
 
        return run_command(&cp);
 }
index 7daee54..ad07470 100644 (file)
@@ -22,6 +22,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)
        struct option options[] = {
                OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")),
                OPT_BOOL(0, "keep-empty", &keep_empty, N_("keep empty commits")),
+               OPT_BOOL(0, "allow-empty-message", &opts.allow_empty_message,
+                       N_("allow commits with empty messages")),
                OPT_CMDMODE(0, "continue", &command, N_("continue rebase"),
                                CONTINUE),
                OPT_CMDMODE(0, "abort", &command, N_("abort rebase"),
@@ -43,7 +45,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)
                OPT_END()
        };
 
-       git_config(git_default_config, NULL);
+       sequencer_init_config(&opts);
        git_config_get_bool("rebase.abbreviatecommands", &abbreviate_commands);
 
        opts.action = REPLAY_INTERACTIVE_REBASE;
index b7ce7c7..75e7f18 100644 (file)
@@ -69,7 +69,7 @@ static int sent_capabilities;
 static int shallow_update;
 static const char *alt_shallow_file;
 static struct strbuf push_cert = STRBUF_INIT;
-static unsigned char push_cert_sha1[20];
+static struct object_id push_cert_oid;
 static struct signature_check sigcheck;
 static const char *push_cert_nonce;
 static const char *cert_nonce_seed;
@@ -633,8 +633,9 @@ static void prepare_push_cert_sha1(struct child_process *proc)
                int bogs /* beginning_of_gpg_sig */;
 
                already_done = 1;
-               if (write_sha1_file(push_cert.buf, push_cert.len, "blob", push_cert_sha1))
-                       hashclr(push_cert_sha1);
+               if (write_object_file(push_cert.buf, push_cert.len, "blob",
+                                     &push_cert_oid))
+                       oidclr(&push_cert_oid);
 
                memset(&sigcheck, '\0', sizeof(sigcheck));
                sigcheck.result = 'N';
@@ -655,9 +656,9 @@ static void prepare_push_cert_sha1(struct child_process *proc)
                strbuf_release(&gpg_status);
                nonce_status = check_nonce(push_cert.buf, bogs);
        }
-       if (!is_null_sha1(push_cert_sha1)) {
+       if (!is_null_oid(&push_cert_oid)) {
                argv_array_pushf(&proc->env_array, "GIT_PUSH_CERT=%s",
-                                sha1_to_hex(push_cert_sha1));
+                                oid_to_hex(&push_cert_oid));
                argv_array_pushf(&proc->env_array, "GIT_PUSH_CERT_SIGNER=%s",
                                 sigcheck.signer ? sigcheck.signer : "");
                argv_array_pushf(&proc->env_array, "GIT_PUSH_CERT_KEY=%s",
index f17a68a..7bdb401 100644 (file)
@@ -83,7 +83,8 @@ static void remove_pack_on_signal(int signo)
 
 /*
  * Adds all packs hex strings to the fname list, which do not
- * have a corresponding .keep file.
+ * have a corresponding .keep or .promisor file. These packs are not to
+ * be kept if we are going to pack everything into one file.
  */
 static void get_non_kept_pack_filenames(struct string_list *fname_list)
 {
@@ -101,7 +102,8 @@ static void get_non_kept_pack_filenames(struct string_list *fname_list)
 
                fname = xmemdupz(e->d_name, len);
 
-               if (!file_exists(mkpath("%s/%s.keep", packdir, fname)))
+               if (!file_exists(mkpath("%s/%s.keep", packdir, fname)) &&
+                   !file_exists(mkpath("%s/%s.promisor", packdir, fname)))
                        string_list_append_nodup(fname_list, fname);
                else
                        free(fname);
@@ -232,6 +234,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
        argv_array_push(&cmd.args, "--all");
        argv_array_push(&cmd.args, "--reflog");
        argv_array_push(&cmd.args, "--indexed-objects");
+       if (repository_format_partial_clone)
+               argv_array_push(&cmd.args, "--exclude-promisor-objects");
        if (window)
                argv_array_pushf(&cmd.args, "--window=%s", window);
        if (window_memory)
index 10078ae..83d3235 100644 (file)
@@ -355,7 +355,7 @@ static void check_one_mergetag(struct commit *commit,
        struct tag *tag;
        int i;
 
-       hash_sha1_file(extra->value, extra->len, typename(OBJ_TAG), tag_oid.hash);
+       hash_object_file(extra->value, extra->len, typename(OBJ_TAG), &tag_oid);
        tag = lookup_tag(&tag_oid);
        if (!tag)
                die(_("bad mergetag in commit '%s'"), ref);
@@ -410,7 +410,7 @@ static int create_graft(int argc, const char **argv, int force)
 
        check_mergetags(commit, argc, argv);
 
-       if (write_sha1_file(buf.buf, buf.len, commit_type, new.hash))
+       if (write_object_file(buf.buf, buf.len, commit_type, &new))
                die(_("could not write replacement commit for: '%s'"), old_ref);
 
        strbuf_release(&buf);
index e15f595..5da0f75 100644 (file)
@@ -106,24 +106,16 @@ out:
 
 static void print_new_head_line(struct commit *commit)
 {
-       const char *hex, *body;
-       const char *msg;
-
-       hex = find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV);
-       printf(_("HEAD is now at %s"), hex);
-       msg = logmsg_reencode(commit, NULL, get_log_output_encoding());
-       body = strstr(msg, "\n\n");
-       if (body) {
-               const char *eol;
-               size_t len;
-               body = skip_blank_lines(body + 2);
-               eol = strchr(body, '\n');
-               len = eol ? eol - body : strlen(body);
-               printf(" %.*s\n", (int) len, body);
-       }
-       else
-               printf("\n");
-       unuse_commit_buffer(commit, msg);
+       struct strbuf buf = STRBUF_INIT;
+
+       printf(_("HEAD is now at %s"),
+               find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV));
+
+       pp_commit_easy(CMIT_FMT_ONELINE, commit, &buf);
+       if (buf.len > 0)
+               printf(" %s", buf.buf);
+       putchar('\n');
+       strbuf_release(&buf);
 }
 
 static void update_index_from_diff(struct diff_queue_struct *q,
index d5345b6..48300d9 100644 (file)
@@ -15,6 +15,7 @@
 #include "progress.h"
 #include "reflog-walk.h"
 #include "oidset.h"
+#include "packfile.h"
 
 static const char rev_list_usage[] =
 "git rev-list [OPTION] <commit-id>... [ -- paths... ]\n"
@@ -67,6 +68,7 @@ enum missing_action {
        MA_ERROR = 0,    /* fail if any missing objects are encountered */
        MA_ALLOW_ANY,    /* silently allow ALL missing objects */
        MA_PRINT,        /* print ALL missing objects in special section */
+       MA_ALLOW_PROMISOR, /* silently allow all missing PROMISOR objects */
 };
 static enum missing_action arg_missing_action;
 
@@ -197,6 +199,12 @@ static void finish_commit(struct commit *commit, void *data)
 
 static inline void finish_object__ma(struct object *obj)
 {
+       /*
+        * Whether or not we try to dynamically fetch missing objects
+        * from the server, we currently DO NOT have the object.  We
+        * can either print, allow (ignore), or conditionally allow
+        * (ignore) them.
+        */
        switch (arg_missing_action) {
        case MA_ERROR:
                die("missing blob object '%s'", oid_to_hex(&obj->oid));
@@ -209,25 +217,36 @@ static inline void finish_object__ma(struct object *obj)
                oidset_insert(&missing_objects, &obj->oid);
                return;
 
+       case MA_ALLOW_PROMISOR:
+               if (is_promisor_object(&obj->oid))
+                       return;
+               die("unexpected missing blob object '%s'",
+                   oid_to_hex(&obj->oid));
+               return;
+
        default:
                BUG("unhandled missing_action");
                return;
        }
 }
 
-static void finish_object(struct object *obj, const char *name, void *cb_data)
+static int finish_object(struct object *obj, const char *name, void *cb_data)
 {
        struct rev_list_info *info = cb_data;
-       if (obj->type == OBJ_BLOB && !has_object_file(&obj->oid))
+       if (obj->type == OBJ_BLOB && !has_object_file(&obj->oid)) {
                finish_object__ma(obj);
+               return 1;
+       }
        if (info->revs->verify_objects && !obj->parsed && obj->type != OBJ_COMMIT)
                parse_object(&obj->oid);
+       return 0;
 }
 
 static void show_object(struct object *obj, const char *name, void *cb_data)
 {
        struct rev_list_info *info = cb_data;
-       finish_object(obj, name, cb_data);
+       if (finish_object(obj, name, cb_data))
+               return;
        display_progress(progress, ++progress_counter);
        if (info->flags & REV_LIST_QUIET)
                return;
@@ -315,11 +334,19 @@ static inline int parse_missing_action_value(const char *value)
 
        if (!strcmp(value, "allow-any")) {
                arg_missing_action = MA_ALLOW_ANY;
+               fetch_if_missing = 0;
                return 1;
        }
 
        if (!strcmp(value, "print")) {
                arg_missing_action = MA_PRINT;
+               fetch_if_missing = 0;
+               return 1;
+       }
+
+       if (!strcmp(value, "allow-promisor")) {
+               arg_missing_action = MA_ALLOW_PROMISOR;
+               fetch_if_missing = 0;
                return 1;
        }
 
@@ -344,6 +371,35 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
        init_revisions(&revs, prefix);
        revs.abbrev = DEFAULT_ABBREV;
        revs.commit_format = CMIT_FMT_UNSPECIFIED;
+
+       /*
+        * Scan the argument list before invoking setup_revisions(), so that we
+        * know if fetch_if_missing needs to be set to 0.
+        *
+        * "--exclude-promisor-objects" acts as a pre-filter on missing objects
+        * by not crossing the boundary from realized objects to promisor
+        * objects.
+        *
+        * Let "--missing" to conditionally set fetch_if_missing.
+        */
+       for (i = 1; i < argc; i++) {
+               const char *arg = argv[i];
+               if (!strcmp(arg, "--exclude-promisor-objects")) {
+                       fetch_if_missing = 0;
+                       revs.exclude_promisor_objects = 1;
+                       break;
+               }
+       }
+       for (i = 1; i < argc; i++) {
+               const char *arg = argv[i];
+               if (skip_prefix(arg, "--missing=", &arg)) {
+                       if (revs.exclude_promisor_objects)
+                               die(_("cannot combine --exclude-promisor-objects and --missing"));
+                       if (parse_missing_action_value(arg))
+                               break;
+               }
+       }
+
        argc = setup_revisions(argc, argv, &revs, NULL);
 
        memset(&info, 0, sizeof(info));
@@ -404,7 +460,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
                        continue;
                }
                if (!strcmp(arg, ("--no-" CL_ARG__FILTER))) {
-                       list_objects_filter_release(&filter_options);
+                       list_objects_filter_set_no_filter(&filter_options);
                        continue;
                }
                if (!strcmp(arg, "--filter-print-omitted")) {
@@ -412,9 +468,10 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
                        continue;
                }
 
-               if (skip_prefix(arg, "--missing=", &arg) &&
-                   parse_missing_action_value(arg))
-                       continue;
+               if (!strcmp(arg, "--exclude-promisor-objects"))
+                       continue; /* already handled above */
+               if (skip_prefix(arg, "--missing=", &arg))
+                       continue; /* already handled above */
 
                usage(rev_list_usage);
 
index 74aa644..96d06a5 100644 (file)
@@ -516,7 +516,7 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
                        PARSE_OPT_SHELL_EVAL);
 
        strbuf_addstr(&parsed, " --");
-       sq_quote_argv(&parsed, argv, 0);
+       sq_quote_argv(&parsed, argv);
        puts(parsed.buf);
        return 0;
 }
@@ -526,7 +526,7 @@ static int cmd_sq_quote(int argc, const char **argv)
        struct strbuf buf = STRBUF_INIT;
 
        if (argc)
-               sq_quote_argv(&buf, argv, 0);
+               sq_quote_argv(&buf, argv);
        printf("%s\n", buf.buf);
        strbuf_release(&buf);
 
index b9d927e..76f0a35 100644 (file)
@@ -208,7 +208,7 @@ int cmd_revert(int argc, const char **argv, const char *prefix)
        if (isatty(0))
                opts.edit = 1;
        opts.action = REPLAY_REVERT;
-       git_config(git_default_config, NULL);
+       sequencer_init_config(&opts);
        res = run_sequencer(argc, argv, &opts);
        if (res < 0)
                die(_("revert failed"));
@@ -221,7 +221,7 @@ int cmd_cherry_pick(int argc, const char **argv, const char *prefix)
        int res;
 
        opts.action = REPLAY_PICK;
-       git_config(git_default_config, NULL);
+       sequencer_init_config(&opts);
        res = run_sequencer(argc, argv, &opts);
        if (res < 0)
                die(_("cherry-pick failed"));
index a5c4a8a..b1daca9 100644 (file)
@@ -20,6 +20,7 @@
 #define OPT_QUIET (1 << 0)
 #define OPT_CACHED (1 << 1)
 #define OPT_RECURSIVE (1 << 2)
+#define OPT_FORCE (1 << 3)
 
 typedef void (*each_submodule_fn)(const struct cache_entry *list_item,
                                  void *cb_data);
@@ -50,6 +51,20 @@ static char *get_default_remote(void)
        return ret;
 }
 
+static int print_default_remote(int argc, const char **argv, const char *prefix)
+{
+       const char *remote;
+
+       if (argc != 1)
+               die(_("submodule--helper print-default-remote takes no arguments"));
+
+       remote = get_default_remote();
+       if (remote)
+               printf("%s\n", remote);
+
+       return 0;
+}
+
 static int starts_with_dot_slash(const char *str)
 {
        return str[0] == '.' && is_dir_sep(str[1]);
@@ -358,6 +373,25 @@ static void module_list_active(struct module_list *list)
        *list = active_modules;
 }
 
+static char *get_up_path(const char *path)
+{
+       int i;
+       struct strbuf sb = STRBUF_INIT;
+
+       for (i = count_slashes(path); i; i--)
+               strbuf_addstr(&sb, "../");
+
+       /*
+        * Check if 'path' ends with slash or not
+        * for having the same output for dir/sub_dir
+        * and dir/sub_dir/
+        */
+       if (!is_dir_sep(path[strlen(path) - 1]))
+               strbuf_addstr(&sb, "../");
+
+       return strbuf_detach(&sb, NULL);
+}
+
 static int module_list(int argc, const char **argv, const char *prefix)
 {
        int i;
@@ -718,6 +752,309 @@ static int module_name(int argc, const char **argv, const char *prefix)
        return 0;
 }
 
+struct sync_cb {
+       const char *prefix;
+       unsigned int flags;
+};
+
+#define SYNC_CB_INIT { NULL, 0 }
+
+static void sync_submodule(const char *path, const char *prefix,
+                          unsigned int flags)
+{
+       const struct submodule *sub;
+       char *remote_key = NULL;
+       char *sub_origin_url, *super_config_url, *displaypath;
+       struct strbuf sb = STRBUF_INIT;
+       struct child_process cp = CHILD_PROCESS_INIT;
+       char *sub_config_path = NULL;
+
+       if (!is_submodule_active(the_repository, path))
+               return;
+
+       sub = submodule_from_path(&null_oid, path);
+
+       if (sub && sub->url) {
+               if (starts_with_dot_dot_slash(sub->url) ||
+                   starts_with_dot_slash(sub->url)) {
+                       char *remote_url, *up_path;
+                       char *remote = get_default_remote();
+                       strbuf_addf(&sb, "remote.%s.url", remote);
+
+                       if (git_config_get_string(sb.buf, &remote_url))
+                               remote_url = xgetcwd();
+
+                       up_path = get_up_path(path);
+                       sub_origin_url = relative_url(remote_url, sub->url, up_path);
+                       super_config_url = relative_url(remote_url, sub->url, NULL);
+
+                       free(remote);
+                       free(up_path);
+                       free(remote_url);
+               } else {
+                       sub_origin_url = xstrdup(sub->url);
+                       super_config_url = xstrdup(sub->url);
+               }
+       } else {
+               sub_origin_url = xstrdup("");
+               super_config_url = xstrdup("");
+       }
+
+       displaypath = get_submodule_displaypath(path, prefix);
+
+       if (!(flags & OPT_QUIET))
+               printf(_("Synchronizing submodule url for '%s'\n"),
+                        displaypath);
+
+       strbuf_reset(&sb);
+       strbuf_addf(&sb, "submodule.%s.url", sub->name);
+       if (git_config_set_gently(sb.buf, super_config_url))
+               die(_("failed to register url for submodule path '%s'"),
+                     displaypath);
+
+       if (!is_submodule_populated_gently(path, NULL))
+               goto cleanup;
+
+       prepare_submodule_repo_env(&cp.env_array);
+       cp.git_cmd = 1;
+       cp.dir = path;
+       argv_array_pushl(&cp.args, "submodule--helper",
+                        "print-default-remote", NULL);
+
+       strbuf_reset(&sb);
+       if (capture_command(&cp, &sb, 0))
+               die(_("failed to get the default remote for submodule '%s'"),
+                     path);
+
+       strbuf_strip_suffix(&sb, "\n");
+       remote_key = xstrfmt("remote.%s.url", sb.buf);
+
+       strbuf_reset(&sb);
+       submodule_to_gitdir(&sb, path);
+       strbuf_addstr(&sb, "/config");
+
+       if (git_config_set_in_file_gently(sb.buf, remote_key, sub_origin_url))
+               die(_("failed to update remote for submodule '%s'"),
+                     path);
+
+       if (flags & OPT_RECURSIVE) {
+               struct child_process cpr = CHILD_PROCESS_INIT;
+
+               cpr.git_cmd = 1;
+               cpr.dir = path;
+               prepare_submodule_repo_env(&cpr.env_array);
+
+               argv_array_push(&cpr.args, "--super-prefix");
+               argv_array_pushf(&cpr.args, "%s/", displaypath);
+               argv_array_pushl(&cpr.args, "submodule--helper", "sync",
+                                "--recursive", NULL);
+
+               if (flags & OPT_QUIET)
+                       argv_array_push(&cpr.args, "--quiet");
+
+               if (run_command(&cpr))
+                       die(_("failed to recurse into submodule '%s'"),
+                             path);
+       }
+
+cleanup:
+       free(super_config_url);
+       free(sub_origin_url);
+       strbuf_release(&sb);
+       free(remote_key);
+       free(displaypath);
+       free(sub_config_path);
+}
+
+static void sync_submodule_cb(const struct cache_entry *list_item, void *cb_data)
+{
+       struct sync_cb *info = cb_data;
+       sync_submodule(list_item->name, info->prefix, info->flags);
+
+}
+
+static int module_sync(int argc, const char **argv, const char *prefix)
+{
+       struct sync_cb info = SYNC_CB_INIT;
+       struct pathspec pathspec;
+       struct module_list list = MODULE_LIST_INIT;
+       int quiet = 0;
+       int recursive = 0;
+
+       struct option module_sync_options[] = {
+               OPT__QUIET(&quiet, N_("Suppress output of synchronizing submodule url")),
+               OPT_BOOL(0, "recursive", &recursive,
+                       N_("Recurse into nested submodules")),
+               OPT_END()
+       };
+
+       const char *const git_submodule_helper_usage[] = {
+               N_("git submodule--helper sync [--quiet] [--recursive] [<path>]"),
+               NULL
+       };
+
+       argc = parse_options(argc, argv, prefix, module_sync_options,
+                            git_submodule_helper_usage, 0);
+
+       if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
+               return 1;
+
+       info.prefix = prefix;
+       if (quiet)
+               info.flags |= OPT_QUIET;
+       if (recursive)
+               info.flags |= OPT_RECURSIVE;
+
+       for_each_listed_submodule(&list, sync_submodule_cb, &info);
+
+       return 0;
+}
+
+struct deinit_cb {
+       const char *prefix;
+       unsigned int flags;
+};
+#define DEINIT_CB_INIT { NULL, 0 }
+
+static void deinit_submodule(const char *path, const char *prefix,
+                            unsigned int flags)
+{
+       const struct submodule *sub;
+       char *displaypath = NULL;
+       struct child_process cp_config = CHILD_PROCESS_INIT;
+       struct strbuf sb_config = STRBUF_INIT;
+       char *sub_git_dir = xstrfmt("%s/.git", path);
+
+       sub = submodule_from_path(&null_oid, path);
+
+       if (!sub || !sub->name)
+               goto cleanup;
+
+       displaypath = get_submodule_displaypath(path, prefix);
+
+       /* remove the submodule work tree (unless the user already did it) */
+       if (is_directory(path)) {
+               struct strbuf sb_rm = STRBUF_INIT;
+               const char *format;
+
+               /*
+                * protect submodules containing a .git directory
+                * NEEDSWORK: instead of dying, automatically call
+                * absorbgitdirs and (possibly) warn.
+                */
+               if (is_directory(sub_git_dir))
+                       die(_("Submodule work tree '%s' contains a .git "
+                             "directory (use 'rm -rf' if you really want "
+                             "to remove it including all of its history)"),
+                           displaypath);
+
+               if (!(flags & OPT_FORCE)) {
+                       struct child_process cp_rm = CHILD_PROCESS_INIT;
+                       cp_rm.git_cmd = 1;
+                       argv_array_pushl(&cp_rm.args, "rm", "-qn",
+                                        path, NULL);
+
+                       if (run_command(&cp_rm))
+                               die(_("Submodule work tree '%s' contains local "
+                                     "modifications; use '-f' to discard them"),
+                                     displaypath);
+               }
+
+               strbuf_addstr(&sb_rm, path);
+
+               if (!remove_dir_recursively(&sb_rm, 0))
+                       format = _("Cleared directory '%s'\n");
+               else
+                       format = _("Could not remove submodule work tree '%s'\n");
+
+               if (!(flags & OPT_QUIET))
+                       printf(format, displaypath);
+
+               strbuf_release(&sb_rm);
+       }
+
+       if (mkdir(path, 0777))
+               printf(_("could not create empty submodule directory %s"),
+                     displaypath);
+
+       cp_config.git_cmd = 1;
+       argv_array_pushl(&cp_config.args, "config", "--get-regexp", NULL);
+       argv_array_pushf(&cp_config.args, "submodule.%s\\.", sub->name);
+
+       /* remove the .git/config entries (unless the user already did it) */
+       if (!capture_command(&cp_config, &sb_config, 0) && sb_config.len) {
+               char *sub_key = xstrfmt("submodule.%s", sub->name);
+               /*
+                * remove the whole section so we have a clean state when
+                * the user later decides to init this submodule again
+                */
+               git_config_rename_section_in_file(NULL, sub_key, NULL);
+               if (!(flags & OPT_QUIET))
+                       printf(_("Submodule '%s' (%s) unregistered for path '%s'\n"),
+                                sub->name, sub->url, displaypath);
+               free(sub_key);
+       }
+
+cleanup:
+       free(displaypath);
+       free(sub_git_dir);
+       strbuf_release(&sb_config);
+}
+
+static void deinit_submodule_cb(const struct cache_entry *list_item,
+                               void *cb_data)
+{
+       struct deinit_cb *info = cb_data;
+       deinit_submodule(list_item->name, info->prefix, info->flags);
+}
+
+static int module_deinit(int argc, const char **argv, const char *prefix)
+{
+       struct deinit_cb info = DEINIT_CB_INIT;
+       struct pathspec pathspec;
+       struct module_list list = MODULE_LIST_INIT;
+       int quiet = 0;
+       int force = 0;
+       int all = 0;
+
+       struct option module_deinit_options[] = {
+               OPT__QUIET(&quiet, N_("Suppress submodule status output")),
+               OPT__FORCE(&force, N_("Remove submodule working trees even if they contain local changes")),
+               OPT_BOOL(0, "all", &all, N_("Unregister all submodules")),
+               OPT_END()
+       };
+
+       const char *const git_submodule_helper_usage[] = {
+               N_("git submodule deinit [--quiet] [-f | --force] [--all | [--] [<path>...]]"),
+               NULL
+       };
+
+       argc = parse_options(argc, argv, prefix, module_deinit_options,
+                            git_submodule_helper_usage, 0);
+
+       if (all && argc) {
+               error("pathspec and --all are incompatible");
+               usage_with_options(git_submodule_helper_usage,
+                                  module_deinit_options);
+       }
+
+       if (!argc && !all)
+               die(_("Use '--all' if you really want to deinitialize all submodules"));
+
+       if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
+               BUG("module_list_compute should not choke on empty pathspec");
+
+       info.prefix = prefix;
+       if (quiet)
+               info.flags |= OPT_QUIET;
+       if (force)
+               info.flags |= OPT_FORCE;
+
+       for_each_listed_submodule(&list, deinit_submodule_cb, &info);
+
+       return 0;
+}
+
 static int clone_submodule(const char *path, const char *gitdir, const char *url,
                           const char *depth, struct string_list *reference,
                           int quiet, int progress)
@@ -1498,6 +1835,9 @@ static struct cmd_struct commands[] = {
        {"resolve-relative-url-test", resolve_relative_url_test, 0},
        {"init", module_init, SUPPORT_SUPER_PREFIX},
        {"status", module_status, SUPPORT_SUPER_PREFIX},
+       {"print-default-remote", print_default_remote, 0},
+       {"sync", module_sync, SUPPORT_SUPER_PREFIX},
+       {"deinit", module_deinit, 0},
        {"remote-branch", resolve_remote_submodule_branch, 0},
        {"push-check", push_check, 0},
        {"absorb-git-dirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX},
index a7e6a5b..8885e21 100644 (file)
@@ -187,7 +187,7 @@ static int build_tag_object(struct strbuf *buf, int sign, struct object_id *resu
 {
        if (sign && do_sign(buf) < 0)
                return error(_("unable to sign the tag"));
-       if (write_sha1_file(buf->buf, buf->len, tag_type, result->hash) < 0)
+       if (write_object_file(buf->buf, buf->len, tag_type, result) < 0)
                return error(_("unable to write tag file"));
        return 0;
 }
index 62ea264..7235d2f 100644 (file)
@@ -21,7 +21,7 @@ static unsigned char buffer[4096];
 static unsigned int offset, len;
 static off_t consumed_bytes;
 static off_t max_input_size;
-static git_SHA_CTX ctx;
+static git_hash_ctx ctx;
 static struct fsck_options fsck_options = FSCK_OPTIONS_STRICT;
 
 /*
@@ -62,7 +62,7 @@ static void *fill(int min)
        if (min > sizeof(buffer))
                die("cannot fill %d bytes", min);
        if (offset) {
-               git_SHA1_Update(&ctx, buffer, offset);
+               the_hash_algo->update_fn(&ctx, buffer, offset);
                memmove(buffer, buffer + offset, len);
                offset = 0;
        }
@@ -172,7 +172,8 @@ static void write_cached_object(struct object *obj, struct obj_buffer *obj_buf)
 {
        struct object_id oid;
 
-       if (write_sha1_file(obj_buf->buffer, obj_buf->size, typename(obj->type), oid.hash) < 0)
+       if (write_object_file(obj_buf->buffer, obj_buf->size,
+                             typename(obj->type), &oid) < 0)
                die("failed to write object %s", oid_to_hex(&obj->oid));
        obj->flags |= FLAG_WRITTEN;
 }
@@ -237,14 +238,16 @@ static void write_object(unsigned nr, enum object_type type,
                         void *buf, unsigned long size)
 {
        if (!strict) {
-               if (write_sha1_file(buf, size, typename(type), obj_list[nr].oid.hash) < 0)
+               if (write_object_file(buf, size, typename(type),
+                                     &obj_list[nr].oid) < 0)
                        die("failed to write object");
                added_object(nr, type, buf, size);
                free(buf);
                obj_list[nr].obj = NULL;
        } else if (type == OBJ_BLOB) {
                struct blob *blob;
-               if (write_sha1_file(buf, size, typename(type), obj_list[nr].oid.hash) < 0)
+               if (write_object_file(buf, size, typename(type),
+                                     &obj_list[nr].oid) < 0)
                        die("failed to write object");
                added_object(nr, type, buf, size);
                free(buf);
@@ -258,7 +261,7 @@ static void write_object(unsigned nr, enum object_type type,
        } else {
                struct object *obj;
                int eaten;
-               hash_sha1_file(buf, size, typename(type), obj_list[nr].oid.hash);
+               hash_object_file(buf, size, typename(type), &obj_list[nr].oid);
                added_object(nr, type, buf, size);
                obj = parse_object_buffer(&obj_list[nr].oid, type, size, buf,
                                          &eaten);
@@ -345,8 +348,8 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
        struct object_id base_oid;
 
        if (type == OBJ_REF_DELTA) {
-               hashcpy(base_oid.hash, fill(GIT_SHA1_RAWSZ));
-               use(GIT_SHA1_RAWSZ);
+               hashcpy(base_oid.hash, fill(the_hash_algo->rawsz));
+               use(the_hash_algo->rawsz);
                delta_data = get_data(delta_size);
                if (dry_run || !delta_data) {
                        free(delta_data);
@@ -564,15 +567,15 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
                /* We don't take any non-flag arguments now.. Maybe some day */
                usage(unpack_usage);
        }
-       git_SHA1_Init(&ctx);
+       the_hash_algo->init_fn(&ctx);
        unpack_all();
-       git_SHA1_Update(&ctx, buffer, offset);
-       git_SHA1_Final(oid.hash, &ctx);
+       the_hash_algo->update_fn(&ctx, buffer, offset);
+       the_hash_algo->final_fn(oid.hash, &ctx);
        if (strict)
                write_rest();
-       if (hashcmp(fill(GIT_SHA1_RAWSZ), oid.hash))
+       if (hashcmp(fill(the_hash_algo->rawsz), oid.hash))
                die("final sha1 did not match");
-       use(GIT_SHA1_RAWSZ);
+       use(the_hash_algo->rawsz);
 
        /* Write the last part of the buffer to stdout */
        while (len) {
index 7cef5b1..9efdc22 100644 (file)
@@ -14,7 +14,7 @@
 #include "worktree.h"
 
 static const char * const worktree_usage[] = {
-       N_("git worktree add [<options>] <path> [<branch>]"),
+       N_("git worktree add [<options>] <path> [<commit-ish>]"),
        N_("git worktree list [<options>]"),
        N_("git worktree lock [<options>] <path>"),
        N_("git worktree prune [<options>]"),
index 3310fd2..8bcd1c8 100644 (file)
@@ -12,7 +12,7 @@ static struct bulk_checkin_state {
        unsigned plugged:1;
 
        char *pack_tmp_name;
-       struct sha1file *f;
+       struct hashfile *f;
        off_t offset;
        struct pack_idx_option pack_idx_opts;
 
@@ -35,9 +35,9 @@ static void finish_bulk_checkin(struct bulk_checkin_state *state)
                unlink(state->pack_tmp_name);
                goto clear_exit;
        } else if (state->nr_written == 1) {
-               sha1close(state->f, oid.hash, CSUM_FSYNC);
+               hashclose(state->f, oid.hash, CSUM_FSYNC);
        } else {
-               int fd = sha1close(state->f, oid.hash, 0);
+               int fd = hashclose(state->f, oid.hash, 0);
                fixup_pack_header_footer(fd, oid.hash, state->pack_tmp_name,
                                         state->nr_written, oid.hash,
                                         state->offset);
@@ -93,7 +93,7 @@ static int already_written(struct bulk_checkin_state *state, unsigned char sha1[
  * with a new pack.
  */
 static int stream_to_pack(struct bulk_checkin_state *state,
-                         git_SHA_CTX *ctx, off_t *already_hashed_to,
+                         git_hash_ctx *ctx, off_t *already_hashed_to,
                          int fd, size_t size, enum object_type type,
                          const char *path, unsigned flags)
 {
@@ -127,7 +127,7 @@ static int stream_to_pack(struct bulk_checkin_state *state,
                                if (rsize < hsize)
                                        hsize = rsize;
                                if (hsize)
-                                       git_SHA1_Update(ctx, ibuf, hsize);
+                                       the_hash_algo->update_fn(ctx, ibuf, hsize);
                                *already_hashed_to = offset;
                        }
                        s.next_in = ibuf;
@@ -149,7 +149,7 @@ static int stream_to_pack(struct bulk_checkin_state *state,
                                        return -1;
                                }
 
-                               sha1write(state->f, obuf, written);
+                               hashwrite(state->f, obuf, written);
                                state->offset += written;
                        }
                        s.next_out = obuf;
@@ -192,10 +192,10 @@ static int deflate_to_pack(struct bulk_checkin_state *state,
                           unsigned flags)
 {
        off_t seekback, already_hashed_to;
-       git_SHA_CTX ctx;
+       git_hash_ctx ctx;
        unsigned char obuf[16384];
        unsigned header_len;
-       struct sha1file_checkpoint checkpoint;
+       struct hashfile_checkpoint checkpoint;
        struct pack_idx_entry *idx = NULL;
 
        seekback = lseek(fd, 0, SEEK_CUR);
@@ -204,8 +204,8 @@ static int deflate_to_pack(struct bulk_checkin_state *state,
 
        header_len = xsnprintf((char *)obuf, sizeof(obuf), "%s %" PRIuMAX,
                               typename(type), (uintmax_t)size) + 1;
-       git_SHA1_Init(&ctx);
-       git_SHA1_Update(&ctx, obuf, header_len);
+       the_hash_algo->init_fn(&ctx);
+       the_hash_algo->update_fn(&ctx, obuf, header_len);
 
        /* Note: idx is non-NULL when we are writing */
        if ((flags & HASH_WRITE_OBJECT) != 0)
@@ -216,7 +216,7 @@ static int deflate_to_pack(struct bulk_checkin_state *state,
        while (1) {
                prepare_to_stream(state, flags);
                if (idx) {
-                       sha1file_checkpoint(state->f, &checkpoint);
+                       hashfile_checkpoint(state->f, &checkpoint);
                        idx->offset = state->offset;
                        crc32_begin(state->f);
                }
@@ -230,19 +230,19 @@ static int deflate_to_pack(struct bulk_checkin_state *state,
                 */
                if (!idx)
                        die("BUG: should not happen");
-               sha1file_truncate(state->f, &checkpoint);
+               hashfile_truncate(state->f, &checkpoint);
                state->offset = checkpoint.offset;
                finish_bulk_checkin(state);
                if (lseek(fd, seekback, SEEK_SET) == (off_t) -1)
                        return error("cannot seek back");
        }
-       git_SHA1_Final(result_sha1, &ctx);
+       the_hash_algo->final_fn(result_sha1, &ctx);
        if (!idx)
                return 0;
 
        idx->crc32 = crc32_end(state->f);
        if (already_written(state, result_sha1)) {
-               sha1file_truncate(state->f, &checkpoint);
+               hashfile_truncate(state->f, &checkpoint);
                state->offset = checkpoint.offset;
                free(idx);
        } else {
index 9329096..efe547e 100644 (file)
--- a/bundle.c
+++ b/bundle.c
@@ -134,7 +134,6 @@ int verify_bundle(struct bundle_header *header, int verbose)
        struct ref_list *p = &header->prerequisites;
        struct rev_info revs;
        const char *argv[] = {NULL, "--all", NULL};
-       struct object_array refs;
        struct commit *commit;
        int i, ret = 0, req_nr;
        const char *message = _("Repository lacks these prerequisite commits:");
@@ -157,14 +156,6 @@ int verify_bundle(struct bundle_header *header, int verbose)
        req_nr = revs.pending.nr;
        setup_revisions(2, argv, &revs, NULL);
 
-       /* Save pending objects, so they can be cleaned up later. */
-       refs = revs.pending;
-       revs.leak_pending = 1;
-
-       /*
-        * prepare_revision_walk (together with .leak_pending = 1) makes us
-        * the sole owner of the list of pending objects.
-        */
        if (prepare_revision_walk(&revs))
                die(_("revision walk setup failed"));
 
@@ -173,18 +164,24 @@ int verify_bundle(struct bundle_header *header, int verbose)
                if (commit->object.flags & PREREQ_MARK)
                        i--;
 
-       for (i = 0; i < req_nr; i++)
-               if (!(refs.objects[i].item->flags & SHOWN)) {
-                       if (++ret == 1)
-                               error("%s", message);
-                       error("%s %s", oid_to_hex(&refs.objects[i].item->oid),
-                               refs.objects[i].name);
-               }
+       for (i = 0; i < p->nr; i++) {
+               struct ref_list_entry *e = p->list + i;
+               struct object *o = parse_object(&e->oid);
+               assert(o); /* otherwise we'd have returned early */
+               if (o->flags & SHOWN)
+                       continue;
+               if (++ret == 1)
+                       error("%s", message);
+               error("%s %s", oid_to_hex(&e->oid), e->name);
+       }
 
        /* Clean up objects used, as they will be reused. */
-       clear_commit_marks_for_object_array(&refs, ALL_REV_FLAGS);
-
-       object_array_clear(&refs);
+       for (i = 0; i < p->nr; i++) {
+               struct ref_list_entry *e = p->list + i;
+               commit = lookup_commit_reference_gently(&e->oid, 1);
+               if (commit)
+                       clear_commit_marks(commit, ALL_REV_FLAGS);
+       }
 
        if (verbose) {
                struct ref_list *r;
index e03e72c..c52e430 100644 (file)
@@ -84,9 +84,8 @@ static struct cache_tree_sub *find_subtree(struct cache_tree *it,
        down->namelen = pathlen;
 
        if (pos < it->subtree_nr)
-               memmove(it->down + pos + 1,
-                       it->down + pos,
-                       sizeof(down) * (it->subtree_nr - pos - 1));
+               MOVE_ARRAY(it->down + pos + 1, it->down + pos,
+                          it->subtree_nr - pos - 1);
        it->down[pos] = down;
        return down;
 }
@@ -400,16 +399,16 @@ static int update_one(struct cache_tree *it,
        }
 
        if (repair) {
-               unsigned char sha1[20];
-               hash_sha1_file(buffer.buf, buffer.len, tree_type, sha1);
-               if (has_sha1_file(sha1))
-                       hashcpy(it->oid.hash, sha1);
+               struct object_id oid;
+               hash_object_file(buffer.buf, buffer.len, tree_type, &oid);
+               if (has_sha1_file(oid.hash))
+                       oidcpy(&it->oid, &oid);
                else
                        to_invalidate = 1;
-       } else if (dryrun)
-               hash_sha1_file(buffer.buf, buffer.len, tree_type,
-                              it->oid.hash);
-       else if (write_sha1_file(buffer.buf, buffer.len, tree_type, it->oid.hash)) {
+       } else if (dryrun) {
+               hash_object_file(buffer.buf, buffer.len, tree_type, &it->oid);
+       } else if (write_object_file(buffer.buf, buffer.len, tree_type,
+                                    &it->oid)) {
                strbuf_release(&buffer);
                return -1;
        }
@@ -608,7 +607,7 @@ int write_index_as_tree(unsigned char *sha1, struct index_state *index_state, co
 
        hold_lock_file_for_update(&lock_file, index_path, LOCK_DIE_ON_ERROR);
 
-       entries = read_index_from(index_state, index_path);
+       entries = read_index_from(index_state, index_path, get_git_dir());
        if (entries < 0) {
                ret = WRITE_TREE_UNREADABLE_INDEX;
                goto out;
diff --git a/cache.h b/cache.h
index d8b975a..21fbcc2 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -4,7 +4,7 @@
 #include "git-compat-util.h"
 #include "strbuf.h"
 #include "hashmap.h"
-#include "mru.h"
+#include "list.h"
 #include "advice.h"
 #include "gettext.h"
 #include "convert.h"
 #include "sha1-array.h"
 #include "repository.h"
 
-#ifndef platform_SHA_CTX
-/*
- * platform's underlying implementation of SHA-1; could be OpenSSL,
- * blk_SHA, Apple CommonCrypto, etc...  Note that including
- * SHA1_HEADER may have already defined platform_SHA_CTX for our
- * own implementations like block-sha1 and ppc-sha1, so we list
- * the default for OpenSSL compatible SHA-1 implementations here.
- */
-#define platform_SHA_CTX       SHA_CTX
-#define platform_SHA1_Init     SHA1_Init
-#define platform_SHA1_Update   SHA1_Update
-#define platform_SHA1_Final            SHA1_Final
-#endif
-
-#define git_SHA_CTX            platform_SHA_CTX
-#define git_SHA1_Init          platform_SHA1_Init
-#define git_SHA1_Update                platform_SHA1_Update
-#define git_SHA1_Final         platform_SHA1_Final
-
-#ifdef SHA1_MAX_BLOCK_SIZE
-#include "compat/sha1-chunked.h"
-#undef git_SHA1_Update
-#define git_SHA1_Update                git_SHA1_Update_Chunked
-#endif
-
 #include <zlib.h>
 typedef struct git_zstream {
        z_stream z;
@@ -345,7 +320,8 @@ struct index_state {
        struct split_index *split_index;
        struct cache_time timestamp;
        unsigned name_hash_initialized : 1,
-                initialized : 1;
+                initialized : 1,
+                drop_cache_tree : 1;
        struct hashmap name_hash;
        struct hashmap dir_hash;
        unsigned char sha1[20];
@@ -371,7 +347,7 @@ extern void free_name_hash(struct index_state *istate);
 #define active_cache_tree (the_index.cache_tree)
 
 #define read_cache() read_index(&the_index)
-#define read_cache_from(path) read_index_from(&the_index, (path))
+#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))
 #define is_cache_unborn() is_index_unborn(&the_index)
 #define read_cache_unmerged() read_index_unmerged(&the_index)
@@ -616,7 +592,8 @@ extern int read_index(struct index_state *);
 extern int read_index_preload(struct index_state *, const struct pathspec *pathspec);
 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);
+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 *);
 
@@ -914,10 +891,13 @@ extern int grafts_replace_parents;
 #define GIT_REPO_VERSION 0
 #define GIT_REPO_VERSION_READ 1
 extern int repository_format_precious_objects;
+extern char *repository_format_partial_clone;
+extern const char *core_partial_clone_filter_default;
 
 struct repository_format {
        int version;
        int precious_objects;
+       char *partial_clone; /* value of extensions.partialclone */
        int is_bare;
        int hash_algo;
        char *work_tree;
@@ -957,12 +937,10 @@ extern void check_repository_format(void);
 #define TYPE_CHANGED    0x0040
 
 /*
- * Return the name of the file in the local object database that would
- * be used to store a loose object with the specified sha1.  The
- * return value is a pointer to a statically allocated buffer that is
- * overwritten each time the function is called.
+ * 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.
  */
-extern const char *sha1_file_name(const unsigned char *sha1);
+extern void sha1_file_name(struct strbuf *buf, const unsigned char *sha1);
 
 /*
  * Return an abbreviated sha1 unique within this repository's object database.
@@ -1029,7 +1007,7 @@ static inline void hashclr(unsigned char *hash)
 
 static inline void oidclr(struct object_id *oid)
 {
-       hashclr(oid->hash);
+       memset(oid->hash, 0, GIT_MAX_RAWSZ);
 }
 
 
@@ -1047,8 +1025,6 @@ extern const struct object_id empty_tree_oid;
        "\xe6\x9d\xe2\x9b\xb2\xd1\xd6\x43\x4b\x8b" \
        "\x29\xae\x77\x5a\xd8\xc2\xe4\x8c\x53\x91"
 extern const struct object_id empty_blob_oid;
-#define EMPTY_BLOB_SHA1_BIN (empty_blob_oid.hash)
-
 
 static inline int is_empty_blob_sha1(const unsigned char *sha1)
 {
@@ -1238,11 +1214,22 @@ static inline const unsigned char *lookup_replace_object(const unsigned char *sh
 
 /* Read and unpack a sha1 file into memory, write memory to a sha1 file */
 extern int sha1_object_info(const unsigned char *, unsigned long *);
-extern int hash_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *sha1);
-extern int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
-extern int hash_sha1_file_literally(const void *buf, unsigned long len, const char *type, struct object_id *oid, unsigned flags);
-extern int pretend_sha1_file(void *, unsigned long, enum object_type, unsigned char *);
-extern int force_object_loose(const unsigned char *sha1, time_t mtime);
+
+extern int hash_object_file(const void *buf, unsigned long len,
+                           const char *type, struct object_id *oid);
+
+extern int write_object_file(const void *buf, unsigned long len,
+                            const char *type, struct object_id *oid);
+
+extern int hash_object_file_literally(const void *buf, unsigned long len,
+                                     const char *type, struct object_id *oid,
+                                     unsigned flags);
+
+extern int pretend_object_file(void *, unsigned long, enum object_type,
+                              struct object_id *oid);
+
+extern int force_object_loose(const struct object_id *oid, time_t mtime);
+
 extern int git_open_cloexec(const char *name, int flags);
 #define git_open(name) git_open_cloexec(name, O_RDONLY)
 extern void *map_sha1_file(const unsigned char *sha1, unsigned long *size);
@@ -1635,6 +1622,7 @@ struct pack_window {
 
 extern struct packed_git {
        struct packed_git *next;
+       struct list_head mru;
        struct pack_window *windows;
        off_t pack_size;
        const void *index_data;
@@ -1648,7 +1636,8 @@ extern struct packed_git {
        unsigned pack_local:1,
                 pack_keep:1,
                 freshened:1,
-                do_not_close:1;
+                do_not_close:1,
+                pack_promisor:1;
        unsigned char sha1[20];
        struct revindex_entry *revindex;
        /* something like ".git/objects/pack/xxxxx.pack" */
@@ -1656,10 +1645,9 @@ extern struct packed_git {
 } *packed_git;
 
 /*
- * A most-recently-used ordered version of the packed_git list, which can
- * be iterated instead of packed_git (and marked via mru_mark).
+ * A most-recently-used ordered version of the packed_git list.
  */
-extern struct mru packed_git_mru;
+extern struct list_head packed_git_mru;
 
 struct pack_entry {
        off_t offset;
@@ -1787,6 +1775,14 @@ struct object_info {
 #define OBJECT_INFO_QUICK 8
 extern int sha1_object_info_extended(const unsigned char *, struct object_info *, unsigned flags);
 
+/*
+ * Set this to 0 to prevent sha1_object_info_extended() from fetching missing
+ * blobs. This has a difference only if extensions.partialClone is set.
+ *
+ * Its default value is 1.
+ */
+extern int fetch_if_missing;
+
 /* Dumb servers support */
 extern int update_server_info(int);
 
index 07f27c7..1efee55 100755 (executable)
@@ -21,8 +21,6 @@ skip_branch_tip_with_tag () {
        fi
 }
 
-good_trees_file="$HOME/travis-cache/good-trees"
-
 # 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.
@@ -83,7 +81,10 @@ check_unignored_build_artifacts ()
 # and installing dependencies.
 set -ex
 
-mkdir -p "$HOME/travis-cache"
+cache_dir="$HOME/travis-cache"
+good_trees_file="$cache_dir/good-trees"
+
+mkdir -p "$cache_dir"
 
 skip_branch_tip_with_tag
 skip_good_tree
index c19c50c..2c60d2e 100755 (executable)
@@ -3,31 +3,58 @@
 # Build and test Git in a 32-bit environment
 #
 # Usage:
-#   run-linux32-build.sh [host-user-id]
+#   run-linux32-build.sh <host-user-id>
 #
 
-set -x
+set -ex
+
+if test $# -ne 1 || test -z "$1"
+then
+       echo >&2 "usage: run-linux32-build.sh <host-user-id>"
+       exit 1
+fi
 
 # Update packages to the latest available versions
 linux32 --32bit i386 sh -c '
     apt update >/dev/null &&
     apt install -y build-essential libcurl4-openssl-dev libssl-dev \
        libexpat-dev gettext python >/dev/null
-' &&
+'
 
 # If this script runs inside a docker container, then all commands are
 # usually executed as root. Consequently, the host user might not be
 # able to access the test output files.
-# If a host user id is given, then create a user "ci" with the host user
-# id to make everything accessible to the host user.
-HOST_UID=$1 &&
-CI_USER=$USER &&
-test -z $HOST_UID || (CI_USER="ci" && useradd -u $HOST_UID $CI_USER) &&
+# If a non 0 host user id is given, then create a user "ci" with that
+# user id to make everything accessible to the host user.
+HOST_UID=$1
+if test $HOST_UID -eq 0
+then
+       # Just in case someone does want to run the test suite as root.
+       CI_USER=root
+else
+       CI_USER=ci
+       if test "$(id -u $CI_USER 2>/dev/null)" = $HOST_UID
+       then
+               echo "user '$CI_USER' already exists with the requested ID $HOST_UID"
+       else
+               useradd -u $HOST_UID $CI_USER
+       fi
+
+       # Due to a bug the test suite was run as root in the past, so
+       # a prove state file created back then is only accessible by
+       # root.  Now that bug is fixed, the test suite is run as a
+       # regular user, but the prove state file coming from Travis
+       # CI's cache might still be owned by root.
+       # Make sure that this user has rights to any cached files,
+       # including an existing prove state file.
+       test -n "$cache_dir" && chown -R $HOST_UID:$HOST_UID "$cache_dir"
+fi
 
 # Build and test
 linux32 --32bit i386 su -m -l $CI_USER -c '
-    cd /usr/src/git &&
-    ln -s /tmp/travis-cache/.prove t/.prove &&
-    make --jobs=2 &&
-    make --quiet test
+       set -ex
+       cd /usr/src/git
+       test -n "$cache_dir" && ln -s "$cache_dir/.prove" t/.prove
+       make --jobs=2
+       make --quiet test
 '
index 4f191c5..2163790 100755 (executable)
@@ -9,7 +9,9 @@ docker pull daald/ubuntu32:xenial
 
 # Use the following command to debug the docker build locally:
 # $ docker run -itv "${PWD}:/usr/src/git" --entrypoint /bin/bash daald/ubuntu32:xenial
-# root@container:/# /usr/src/git/ci/run-linux32-build.sh
+# root@container:/# /usr/src/git/ci/run-linux32-build.sh <host-user-id>
+
+container_cache_dir=/tmp/travis-cache
 
 docker run \
        --interactive \
@@ -18,8 +20,9 @@ docker run \
        --env GIT_PROVE_OPTS \
        --env GIT_TEST_OPTS \
        --env GIT_TEST_CLONE_2GB \
+       --env cache_dir="$container_cache_dir" \
        --volume "${PWD}:/usr/src/git" \
-       --volume "${HOME}/travis-cache:/tmp/travis-cache" \
+       --volume "$cache_dir:$container_cache_dir" \
        daald/ubuntu32:xenial \
        /usr/src/git/ci/run-linux32-build.sh $(id -u $USER)
 
index 22355f0..73e273f 100755 (executable)
@@ -5,8 +5,13 @@
 
 . ${0%/*}/lib-travisci.sh
 
-ln -s $HOME/travis-cache/.prove t/.prove
+ln -s "$cache_dir/.prove" t/.prove
+
 make --quiet test
+if test "$jobname" = "linux-gcc"
+then
+       GIT_TEST_SPLIT_INDEX=YesPlease make --quiet test
+fi
 
 check_unignored_build_artifacts
 
index 2505de1..18c74da 100644 (file)
@@ -1053,7 +1053,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
                        if (is_file) {
                                struct strbuf buf = STRBUF_INIT;
 
-                               if (convert_to_git(&the_index, elem->path, result, len, &buf, safe_crlf)) {
+                               if (convert_to_git(&the_index, elem->path, result, len, &buf, global_conv_flags_eol)) {
                                        free(result);
                                        result = strbuf_detach(&buf, &len);
                                        result_size = len;
@@ -1438,7 +1438,7 @@ void diff_tree_combined(const struct object_id *oid,
                        opt->flags.follow_renames       ||
                        opt->break_opt != -1    ||
                        opt->detect_rename      ||
-                       opt->pickaxe            ||
+                       (opt->pickaxe_opts & DIFF_PICKAXE_KINDS_MASK)   ||
                        opt->filter;
 
 
index cab8d44..e8a49b9 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -126,10 +126,8 @@ int register_commit_graft(struct commit_graft *graft, int ignore_dups)
        ALLOC_GROW(commit_graft, commit_graft_nr + 1, commit_graft_alloc);
        commit_graft_nr++;
        if (pos < commit_graft_nr)
-               memmove(commit_graft + pos + 1,
-                       commit_graft + pos,
-                       (commit_graft_nr - pos - 1) *
-                       sizeof(*commit_graft));
+               MOVE_ARRAY(commit_graft + pos + 1, commit_graft + pos,
+                          commit_graft_nr - pos - 1);
        commit_graft[pos] = graft;
        return 0;
 }
@@ -547,7 +545,7 @@ void clear_commit_marks_many(int nr, struct commit **commit, unsigned int mark)
        struct commit_list *list = NULL;
 
        while (nr--) {
-               commit_list_insert(*commit, &list);
+               clear_commit_marks_1(&list, *commit, mark);
                commit++;
        }
        while (list)
@@ -559,20 +557,6 @@ void clear_commit_marks(struct commit *commit, unsigned int mark)
        clear_commit_marks_many(1, &commit, mark);
 }
 
-void clear_commit_marks_for_object_array(struct object_array *a, unsigned mark)
-{
-       struct object *object;
-       struct commit *commit;
-       unsigned int i;
-
-       for (i = 0; i < a->nr; i++) {
-               object = a->objects[i].item;
-               commit = lookup_commit_reference_gently(&object->oid, 1);
-               if (commit)
-                       clear_commit_marks(commit, mark);
-       }
-}
-
 struct commit *pop_commit(struct commit_list **stack)
 {
        struct commit_list *top = *stack;
@@ -929,8 +913,7 @@ static int remove_redundant(struct commit **array, int cnt)
                        if (work[j]->object.flags & PARENT1)
                                redundant[filled_index[j]] = 1;
                clear_commit_marks(array[i], all_flags);
-               for (j = 0; j < filled; j++)
-                       clear_commit_marks(work[j], all_flags);
+               clear_commit_marks_many(filled, work, all_flags);
                free_commit_list(common);
        }
 
@@ -1395,9 +1378,8 @@ void free_commit_extra_headers(struct commit_extra_header *extra)
        }
 }
 
-int commit_tree(const char *msg, size_t msg_len,
-               const unsigned char *tree,
-               struct commit_list *parents, unsigned char *ret,
+int commit_tree(const char *msg, size_t msg_len, const struct object_id *tree,
+               struct commit_list *parents, struct object_id *ret,
                const char *author, const char *sign_commit)
 {
        struct commit_extra_header *extra = NULL, **tail = &extra;
@@ -1526,8 +1508,8 @@ N_("Warning: commit message did not conform to UTF-8.\n"
    "variable i18n.commitencoding to the encoding your project uses.\n");
 
 int commit_tree_extended(const char *msg, size_t msg_len,
-                        const unsigned char *tree,
-                        struct commit_list *parents, unsigned char *ret,
+                        const struct object_id *tree,
+                        struct commit_list *parents, struct object_id *ret,
                         const char *author, const char *sign_commit,
                         struct commit_extra_header *extra)
 {
@@ -1535,7 +1517,7 @@ int commit_tree_extended(const char *msg, size_t msg_len,
        int encoding_is_utf8;
        struct strbuf buffer;
 
-       assert_sha1_type(tree, OBJ_TREE);
+       assert_sha1_type(tree->hash, OBJ_TREE);
 
        if (memchr(msg, '\0', msg_len))
                return error("a NUL byte in commit log message not allowed.");
@@ -1544,7 +1526,7 @@ int commit_tree_extended(const char *msg, size_t msg_len,
        encoding_is_utf8 = is_encoding_utf8(git_commit_encoding);
 
        strbuf_init(&buffer, 8192); /* should avoid reallocs for the headers */
-       strbuf_addf(&buffer, "tree %s\n", sha1_to_hex(tree));
+       strbuf_addf(&buffer, "tree %s\n", oid_to_hex(tree));
 
        /*
         * NOTE! This ordering means that the same exact tree merged with a
@@ -1583,7 +1565,7 @@ int commit_tree_extended(const char *msg, size_t msg_len,
                goto out;
        }
 
-       result = write_sha1_file(buffer.buf, buffer.len, commit_type, ret);
+       result = write_object_file(buffer.buf, buffer.len, commit_type, ret);
 out:
        strbuf_release(&buffer);
        return result;
index 8c68ca1..0fb8271 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -140,7 +140,6 @@ struct commit *pop_commit(struct commit_list **stack);
 
 void clear_commit_marks(struct commit *commit, unsigned int mark);
 void clear_commit_marks_many(int nr, struct commit **commit, unsigned int mark);
-void clear_commit_marks_for_object_array(struct object_array *a, unsigned mark);
 
 
 enum rev_sort_order {
@@ -263,14 +262,15 @@ extern void append_merge_tag_headers(struct commit_list *parents,
                                     struct commit_extra_header ***tail);
 
 extern int commit_tree(const char *msg, size_t msg_len,
-                      const unsigned char *tree,
-                      struct commit_list *parents, unsigned char *ret,
+                      const struct object_id *tree,
+                      struct commit_list *parents, struct object_id *ret,
                       const char *author, const char *sign_commit);
 
 extern int commit_tree_extended(const char *msg, size_t msg_len,
-                               const unsigned char *tree,
-                               struct commit_list *parents, unsigned char *ret,
-                               const char *author, const char *sign_commit,
+                               const struct object_id *tree,
+                               struct commit_list *parents,
+                               struct object_id *ret, const char *author,
+                               const char *sign_commit,
                                struct commit_extra_header *);
 
 extern struct commit_extra_header *read_commit_extra_headers(struct commit *, const char **);
index e617c20..b0c20e6 100644 (file)
--- a/config.c
+++ b/config.c
@@ -1149,11 +1149,14 @@ static int git_default_core_config(const char *var, const char *value)
        }
 
        if (!strcmp(var, "core.safecrlf")) {
+               int eol_rndtrp_die;
                if (value && !strcasecmp(value, "warn")) {
-                       safe_crlf = SAFE_CRLF_WARN;
+                       global_conv_flags_eol = CONV_EOL_RNDTRP_WARN;
                        return 0;
                }
-               safe_crlf = git_config_bool(var, value);
+               eol_rndtrp_die = git_config_bool(var, value);
+               global_conv_flags_eol = eol_rndtrp_die ?
+                       CONV_EOL_RNDTRP_DIE : CONV_EOL_RNDTRP_WARN;
                return 0;
        }
 
@@ -1251,6 +1254,11 @@ static int git_default_core_config(const char *var, const char *value)
                return 0;
        }
 
+       if (!strcmp(var, "core.partialclonefilter")) {
+               return git_config_string(&core_partial_clone_filter_default,
+                                        var, value);
+       }
+
        /* Add other config variables here and to Documentation/config.txt. */
        return 0;
 }
index 4a47f33..91feb78 100644 (file)
@@ -56,6 +56,8 @@ int check_connected(oid_iterate_fn fn, void *cb_data,
        argv_array_push(&rev_list.args,"rev-list");
        argv_array_push(&rev_list.args, "--objects");
        argv_array_push(&rev_list.args, "--stdin");
+       if (repository_format_partial_clone)
+               argv_array_push(&rev_list.args, "--exclude-promisor-objects");
        argv_array_push(&rev_list.args, "--not");
        argv_array_push(&rev_list.args, "--all");
        argv_array_push(&rev_list.args, "--quiet");
index 1d580e4..e34eada 100644 (file)
@@ -1,21 +1,6 @@
 @ strbuf_addf_with_format_only @
 expression E;
-constant fmt;
-@@
-  strbuf_addf(E,
-(
-  fmt
-|
-  _(fmt)
-)
-  );
-
-@ script:python @
-fmt << strbuf_addf_with_format_only.fmt;
-@@
-cocci.include_match("%" not in fmt)
-
-@ extends strbuf_addf_with_format_only @
+constant fmt !~ "%";
 @@
 - strbuf_addf
 + strbuf_addstr
@@ -29,8 +14,9 @@ cocci.include_match("%" not in fmt)
 
 @@
 expression E1, E2;
+format F =~ "s";
 @@
-- strbuf_addf(E1, "%s", E2);
+- strbuf_addf(E1, "%@F@", E2);
 + strbuf_addstr(E1, E2);
 
 @@
index 3683c77..88813e9 100644 (file)
@@ -594,7 +594,7 @@ __git_is_configured_remote ()
 
 __git_list_merge_strategies ()
 {
-       git merge -s help 2>&1 |
+       LANG=C LC_ALL=C git merge -s help 2>&1 |
        sed -n -e '/[Aa]vailable strategies are: /,/^$/{
                s/\.$//
                s/.*://
index df59bdf..fb0fd0b 100755 (executable)
@@ -13,7 +13,7 @@
 use 5.008;
 use strict;
 use warnings;
-use Error qw(:try);
+use Git::Error qw(:try);
 use File::Basename qw(dirname);
 use File::Copy;
 use File::Find;
index 1a41a48..cc562f6 100644 (file)
--- a/convert.c
+++ b/convert.c
@@ -193,30 +193,30 @@ static enum eol output_eol(enum crlf_action crlf_action)
        return core_eol;
 }
 
-static void check_safe_crlf(const char *path, enum crlf_action crlf_action,
+static void check_global_conv_flags_eol(const char *path, enum crlf_action crlf_action,
                            struct text_stat *old_stats, struct text_stat *new_stats,
-                           enum safe_crlf checksafe)
+                           int conv_flags)
 {
        if (old_stats->crlf && !new_stats->crlf ) {
                /*
                 * CRLFs would not be restored by checkout
                 */
-               if (checksafe == SAFE_CRLF_WARN)
+               if (conv_flags & CONV_EOL_RNDTRP_DIE)
+                       die(_("CRLF would be replaced by LF in %s."), path);
+               else if (conv_flags & CONV_EOL_RNDTRP_WARN)
                        warning(_("CRLF will be replaced by LF in %s.\n"
                                  "The file will have its original line"
                                  " endings in your working directory."), path);
-               else /* i.e. SAFE_CRLF_FAIL */
-                       die(_("CRLF would be replaced by LF in %s."), path);
        } else if (old_stats->lonelf && !new_stats->lonelf ) {
                /*
                 * CRLFs would be added by checkout
                 */
-               if (checksafe == SAFE_CRLF_WARN)
+               if (conv_flags & CONV_EOL_RNDTRP_DIE)
+                       die(_("LF would be replaced by CRLF in %s"), path);
+               else if (conv_flags & CONV_EOL_RNDTRP_WARN)
                        warning(_("LF will be replaced by CRLF in %s.\n"
                                  "The file will have its original line"
                                  " endings in your working directory."), path);
-               else /* i.e. SAFE_CRLF_FAIL */
-                       die(_("LF would be replaced by CRLF in %s"), path);
        }
 }
 
@@ -268,7 +268,7 @@ static int will_convert_lf_to_crlf(size_t len, struct text_stat *stats,
 static int crlf_to_git(const struct index_state *istate,
                       const char *path, const char *src, size_t len,
                       struct strbuf *buf,
-                      enum crlf_action crlf_action, enum safe_crlf checksafe)
+                      enum crlf_action crlf_action, int conv_flags)
 {
        struct text_stat stats;
        char *dst;
@@ -298,12 +298,12 @@ static int crlf_to_git(const struct index_state *istate,
                 * unless we want to renormalize in a merge or
                 * cherry-pick.
                 */
-               if ((checksafe != SAFE_CRLF_RENORMALIZE) &&
+               if ((!(conv_flags & CONV_EOL_RENORMALIZE)) &&
                    has_crlf_in_index(istate, path))
                        convert_crlf_into_lf = 0;
        }
-       if ((checksafe == SAFE_CRLF_WARN ||
-           (checksafe == SAFE_CRLF_FAIL)) && len) {
+       if (((conv_flags & CONV_EOL_RNDTRP_WARN) ||
+            ((conv_flags & CONV_EOL_RNDTRP_DIE) && len))) {
                struct text_stat new_stats;
                memcpy(&new_stats, &stats, sizeof(new_stats));
                /* simulate "git add" */
@@ -316,7 +316,7 @@ static int crlf_to_git(const struct index_state *istate,
                        new_stats.crlf += new_stats.lonelf;
                        new_stats.lonelf = 0;
                }
-               check_safe_crlf(path, crlf_action, &stats, &new_stats, checksafe);
+               check_global_conv_flags_eol(path, crlf_action, &stats, &new_stats, conv_flags);
        }
        if (!convert_crlf_into_lf)
                return 0;
@@ -898,7 +898,7 @@ static int ident_to_git(const char *path, const char *src, size_t len,
 static int ident_to_worktree(const char *path, const char *src, size_t len,
                              struct strbuf *buf, int ident)
 {
-       unsigned char sha1[20];
+       struct object_id oid;
        char *to_free = NULL, *dollar, *spc;
        int cnt;
 
@@ -912,7 +912,7 @@ static int ident_to_worktree(const char *path, const char *src, size_t len,
        /* are we "faking" in place editing ? */
        if (src == buf->buf)
                to_free = strbuf_detach(buf, NULL);
-       hash_sha1_file(src, len, "blob", sha1);
+       hash_object_file(src, len, "blob", &oid);
 
        strbuf_grow(buf, len + cnt * 43);
        for (;;) {
@@ -969,7 +969,7 @@ static int ident_to_worktree(const char *path, const char *src, size_t len,
 
                /* step 4: substitute */
                strbuf_addstr(buf, "Id: ");
-               strbuf_add(buf, sha1_to_hex(sha1), 40);
+               strbuf_addstr(buf, oid_to_hex(&oid));
                strbuf_addstr(buf, " $");
        }
        strbuf_add(buf, src, len);
@@ -1129,7 +1129,7 @@ const char *get_convert_attr_ascii(const char *path)
 
 int convert_to_git(const struct index_state *istate,
                   const char *path, const char *src, size_t len,
-                   struct strbuf *dst, enum safe_crlf checksafe)
+                  struct strbuf *dst, int conv_flags)
 {
        int ret = 0;
        struct conv_attrs ca;
@@ -1144,8 +1144,8 @@ int convert_to_git(const struct index_state *istate,
                src = dst->buf;
                len = dst->len;
        }
-       if (checksafe != SAFE_CRLF_KEEP_CRLF) {
-               ret |= crlf_to_git(istate, path, src, len, dst, ca.crlf_action, checksafe);
+       if (!(conv_flags & CONV_EOL_KEEP_CRLF)) {
+               ret |= crlf_to_git(istate, path, src, len, dst, ca.crlf_action, conv_flags);
                if (ret && dst) {
                        src = dst->buf;
                        len = dst->len;
@@ -1156,7 +1156,7 @@ int convert_to_git(const struct index_state *istate,
 
 void convert_to_git_filter_fd(const struct index_state *istate,
                              const char *path, int fd, struct strbuf *dst,
-                             enum safe_crlf checksafe)
+                             int conv_flags)
 {
        struct conv_attrs ca;
        convert_attrs(&ca, path);
@@ -1167,7 +1167,7 @@ void convert_to_git_filter_fd(const struct index_state *istate,
        if (!apply_filter(path, NULL, 0, fd, dst, ca.drv, CAP_CLEAN, NULL))
                die("%s: clean filter '%s' failed", path, ca.drv->name);
 
-       crlf_to_git(istate, path, dst->buf, dst->len, dst, ca.crlf_action, checksafe);
+       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);
 }
 
@@ -1226,7 +1226,7 @@ int renormalize_buffer(const struct index_state *istate, const char *path,
                src = dst->buf;
                len = dst->len;
        }
-       return ret | convert_to_git(istate, path, src, len, dst, SAFE_CRLF_RENORMALIZE);
+       return ret | convert_to_git(istate, path, src, len, dst, CONV_EOL_RENORMALIZE);
 }
 
 /*****************************************************************
index 4f2da22..65ab3e5 100644 (file)
--- a/convert.h
+++ b/convert.h
@@ -8,15 +8,12 @@
 
 struct index_state;
 
-enum safe_crlf {
-       SAFE_CRLF_FALSE = 0,
-       SAFE_CRLF_FAIL = 1,
-       SAFE_CRLF_WARN = 2,
-       SAFE_CRLF_RENORMALIZE = 3,
-       SAFE_CRLF_KEEP_CRLF = 4
-};
+#define CONV_EOL_RNDTRP_DIE   (1<<0) /* Die if CRLF to LF to CRLF is different */
+#define CONV_EOL_RNDTRP_WARN  (1<<1) /* Warn if CRLF to LF to CRLF is different */
+#define CONV_EOL_RENORMALIZE  (1<<2) /* Convert CRLF to LF */
+#define CONV_EOL_KEEP_CRLF    (1<<3) /* Keep CRLF line endings as is */
 
-extern enum safe_crlf safe_crlf;
+extern int global_conv_flags_eol;
 
 enum auto_crlf {
        AUTO_CRLF_FALSE = 0,
@@ -66,7 +63,7 @@ extern const char *get_convert_attr_ascii(const char *path);
 /* returns 1 if *dst was used */
 extern int convert_to_git(const struct index_state *istate,
                          const char *path, const char *src, size_t len,
-                         struct strbuf *dst, enum safe_crlf checksafe);
+                         struct strbuf *dst, int conv_flags);
 extern int convert_to_working_tree(const char *path, const char *src,
                                   size_t len, struct strbuf *dst);
 extern int async_convert_to_working_tree(const char *path, const char *src,
@@ -85,7 +82,7 @@ static inline int would_convert_to_git(const struct index_state *istate,
 extern void convert_to_git_filter_fd(const struct index_state *istate,
                                     const char *path, int fd,
                                     struct strbuf *dst,
-                                    enum safe_crlf checksafe);
+                                    int conv_flags);
 extern int would_convert_to_git_filter_fd(const char *path);
 
 /*****************************************************************
index 2adae04..5eda7fb 100644 (file)
@@ -11,7 +11,7 @@
 #include "progress.h"
 #include "csum-file.h"
 
-static void flush(struct sha1file *f, const void *buf, unsigned int count)
+static void flush(struct hashfile *f, const void *buf, unsigned int count)
 {
        if (0 <= f->check_fd && count)  {
                unsigned char check_buffer[8192];
@@ -42,28 +42,28 @@ static void flush(struct sha1file *f, const void *buf, unsigned int count)
        }
 }
 
-void sha1flush(struct sha1file *f)
+void hashflush(struct hashfile *f)
 {
        unsigned offset = f->offset;
 
        if (offset) {
-               git_SHA1_Update(&f->ctx, f->buffer, offset);
+               the_hash_algo->update_fn(&f->ctx, f->buffer, offset);
                flush(f, f->buffer, offset);
                f->offset = 0;
        }
 }
 
-int sha1close(struct sha1file *f, unsigned char *result, unsigned int flags)
+int hashclose(struct hashfile *f, unsigned char *result, unsigned int flags)
 {
        int fd;
 
-       sha1flush(f);
-       git_SHA1_Final(f->buffer, &f->ctx);
+       hashflush(f);
+       the_hash_algo->final_fn(f->buffer, &f->ctx);
        if (result)
                hashcpy(result, f->buffer);
        if (flags & (CSUM_CLOSE | CSUM_FSYNC)) {
                /* write checksum and close fd */
-               flush(f, f->buffer, 20);
+               flush(f, f->buffer, the_hash_algo->rawsz);
                if (flags & CSUM_FSYNC)
                        fsync_or_die(f->fd, f->name);
                if (close(f->fd))
@@ -86,7 +86,7 @@ int sha1close(struct sha1file *f, unsigned char *result, unsigned int flags)
        return fd;
 }
 
-void sha1write(struct sha1file *f, const void *buf, unsigned int count)
+void hashwrite(struct hashfile *f, const void *buf, unsigned int count)
 {
        while (count) {
                unsigned offset = f->offset;
@@ -110,7 +110,7 @@ void sha1write(struct sha1file *f, const void *buf, unsigned int count)
                buf = (char *) buf + nr;
                left -= nr;
                if (!left) {
-                       git_SHA1_Update(&f->ctx, data, offset);
+                       the_hash_algo->update_fn(&f->ctx, data, offset);
                        flush(f, data, offset);
                        offset = 0;
                }
@@ -118,15 +118,15 @@ void sha1write(struct sha1file *f, const void *buf, unsigned int count)
        }
 }
 
-struct sha1file *sha1fd(int fd, const char *name)
+struct hashfile *hashfd(int fd, const char *name)
 {
-       return sha1fd_throughput(fd, name, NULL);
+       return hashfd_throughput(fd, name, NULL);
 }
 
-struct sha1file *sha1fd_check(const char *name)
+struct hashfile *hashfd_check(const char *name)
 {
        int sink, check;
-       struct sha1file *f;
+       struct hashfile *f;
 
        sink = open("/dev/null", O_WRONLY);
        if (sink < 0)
@@ -134,14 +134,14 @@ struct sha1file *sha1fd_check(const char *name)
        check = open(name, O_RDONLY);
        if (check < 0)
                die_errno("unable to open '%s'", name);
-       f = sha1fd(sink, name);
+       f = hashfd(sink, name);
        f->check_fd = check;
        return f;
 }
 
-struct sha1file *sha1fd_throughput(int fd, const char *name, struct progress *tp)
+struct hashfile *hashfd_throughput(int fd, const char *name, struct progress *tp)
 {
-       struct sha1file *f = xmalloc(sizeof(*f));
+       struct hashfile *f = xmalloc(sizeof(*f));
        f->fd = fd;
        f->check_fd = -1;
        f->offset = 0;
@@ -149,18 +149,18 @@ struct sha1file *sha1fd_throughput(int fd, const char *name, struct progress *tp
        f->tp = tp;
        f->name = name;
        f->do_crc = 0;
-       git_SHA1_Init(&f->ctx);
+       the_hash_algo->init_fn(&f->ctx);
        return f;
 }
 
-void sha1file_checkpoint(struct sha1file *f, struct sha1file_checkpoint *checkpoint)
+void hashfile_checkpoint(struct hashfile *f, struct hashfile_checkpoint *checkpoint)
 {
-       sha1flush(f);
+       hashflush(f);
        checkpoint->offset = f->total;
        checkpoint->ctx = f->ctx;
 }
 
-int sha1file_truncate(struct sha1file *f, struct sha1file_checkpoint *checkpoint)
+int hashfile_truncate(struct hashfile *f, struct hashfile_checkpoint *checkpoint)
 {
        off_t offset = checkpoint->offset;
 
@@ -169,17 +169,17 @@ int sha1file_truncate(struct sha1file *f, struct sha1file_checkpoint *checkpoint
                return -1;
        f->total = offset;
        f->ctx = checkpoint->ctx;
-       f->offset = 0; /* sha1flush() was called in checkpoint */
+       f->offset = 0; /* hashflush() was called in checkpoint */
        return 0;
 }
 
-void crc32_begin(struct sha1file *f)
+void crc32_begin(struct hashfile *f)
 {
        f->crc32 = crc32(0, NULL, 0);
        f->do_crc = 1;
 }
 
-uint32_t crc32_end(struct sha1file *f)
+uint32_t crc32_end(struct hashfile *f)
 {
        f->do_crc = 0;
        return f->crc32;
index 7530927..992e5c0 100644 (file)
@@ -4,11 +4,11 @@
 struct progress;
 
 /* A SHA1-protected file */
-struct sha1file {
+struct hashfile {
        int fd;
        int check_fd;
        unsigned int offset;
-       git_SHA_CTX ctx;
+       git_hash_ctx ctx;
        off_t total;
        struct progress *tp;
        const char *name;
@@ -18,36 +18,36 @@ struct sha1file {
 };
 
 /* Checkpoint */
-struct sha1file_checkpoint {
+struct hashfile_checkpoint {
        off_t offset;
-       git_SHA_CTX ctx;
+       git_hash_ctx ctx;
 };
 
-extern void sha1file_checkpoint(struct sha1file *, struct sha1file_checkpoint *);
-extern int sha1file_truncate(struct sha1file *, struct sha1file_checkpoint *);
+extern void hashfile_checkpoint(struct hashfile *, struct hashfile_checkpoint *);
+extern int hashfile_truncate(struct hashfile *, struct hashfile_checkpoint *);
 
-/* sha1close flags */
+/* hashclose flags */
 #define CSUM_CLOSE     1
 #define CSUM_FSYNC     2
 
-extern struct sha1file *sha1fd(int fd, const char *name);
-extern struct sha1file *sha1fd_check(const char *name);
-extern struct sha1file *sha1fd_throughput(int fd, const char *name, struct progress *tp);
-extern int sha1close(struct sha1file *, unsigned char *, unsigned int);
-extern void sha1write(struct sha1file *, const void *, unsigned int);
-extern void sha1flush(struct sha1file *f);
-extern void crc32_begin(struct sha1file *);
-extern uint32_t crc32_end(struct sha1file *);
+extern struct hashfile *hashfd(int fd, const char *name);
+extern struct hashfile *hashfd_check(const char *name);
+extern struct hashfile *hashfd_throughput(int fd, const char *name, struct progress *tp);
+extern int hashclose(struct hashfile *, unsigned char *, unsigned int);
+extern void hashwrite(struct hashfile *, const void *, unsigned int);
+extern void hashflush(struct hashfile *f);
+extern void crc32_begin(struct hashfile *);
+extern uint32_t crc32_end(struct hashfile *);
 
-static inline void sha1write_u8(struct sha1file *f, uint8_t data)
+static inline void hashwrite_u8(struct hashfile *f, uint8_t data)
 {
-       sha1write(f, &data, sizeof(data));
+       hashwrite(f, &data, sizeof(data));
 }
 
-static inline void sha1write_be32(struct sha1file *f, uint32_t data)
+static inline void hashwrite_be32(struct hashfile *f, uint32_t data)
 {
        data = htonl(data);
-       sha1write(f, &data, sizeof(data));
+       hashwrite(f, &data, sizeof(data));
 }
 
 #endif
index e37e343..fe833ea 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -9,7 +9,12 @@
 #define initgroups(x, y) (0) /* nothing */
 #endif
 
-static int log_syslog;
+static enum log_destination {
+       LOG_DESTINATION_UNSET = -1,
+       LOG_DESTINATION_NONE = 0,
+       LOG_DESTINATION_STDERR = 1,
+       LOG_DESTINATION_SYSLOG = 2,
+} log_destination = LOG_DESTINATION_UNSET;
 static int verbose;
 static int reuseaddr;
 static int informative_errors;
@@ -25,6 +30,7 @@ static const char daemon_usage[] =
 "           [--access-hook=<path>]\n"
 "           [--inetd | [--listen=<host_or_ipaddr>] [--port=<n>]\n"
 "                      [--detach] [--user=<user> [--group=<group>]]\n"
+"           [--log-destination=(stderr|syslog|none)]\n"
 "           [<directory>...]";
 
 /* List of acceptable pathname prefixes */
@@ -74,11 +80,14 @@ static const char *get_ip_address(struct hostinfo *hi)
 
 static void logreport(int priority, const char *err, va_list params)
 {
-       if (log_syslog) {
+       switch (log_destination) {
+       case LOG_DESTINATION_SYSLOG: {
                char buf[1024];
                vsnprintf(buf, sizeof(buf), err, params);
                syslog(priority, "%s", buf);
-       } else {
+               break;
+       }
+       case LOG_DESTINATION_STDERR:
                /*
                 * Since stderr is set to buffered mode, the
                 * logging of different processes will not overlap
@@ -88,6 +97,11 @@ static void logreport(int priority, const char *err, va_list params)
                vfprintf(stderr, err, params);
                fputc('\n', stderr);
                fflush(stderr);
+               break;
+       case LOG_DESTINATION_NONE:
+               break;
+       case LOG_DESTINATION_UNSET:
+               BUG("log destination not initialized correctly");
        }
 }
 
@@ -597,6 +611,7 @@ static char *parse_host_arg(struct hostinfo *hi, char *extra_args, int buflen)
                if (strncasecmp("host=", extra_args, 5) == 0) {
                        val = extra_args + 5;
                        vallen = strlen(val) + 1;
+                       loginfo("Extended attribute \"host\": %s", val);
                        if (*val) {
                                /* Split <host>:<port> at colon. */
                                char *host;
@@ -647,9 +662,11 @@ static void parse_extra_args(struct hostinfo *hi, struct argv_array *env,
                }
        }
 
-       if (git_protocol.len > 0)
+       if (git_protocol.len > 0) {
+               loginfo("Extended attribute \"protocol\": %s", git_protocol.buf);
                argv_array_pushf(env, GIT_PROTOCOL_ENVIRONMENT "=%s",
                                 git_protocol.buf);
+       }
        strbuf_release(&git_protocol);
 }
 
@@ -757,14 +774,8 @@ static int execute(void)
        alarm(0);
 
        len = strlen(line);
-       if (pktlen != len)
-               loginfo("Extended attributes (%d bytes) exist <%.*s>",
-                       (int) pktlen - len,
-                       (in