Merge branch 'jt/sha1-file-cleanup'
authorJunio C Hamano <gitster@pobox.com>
Wed, 23 Aug 2017 21:13:07 +0000 (14:13 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 23 Aug 2017 21:13:07 +0000 (14:13 -0700)
Preparatory code clean-up.

* jt/sha1-file-cleanup:
  sha1_file: remove read_packed_sha1()
  sha1_file: set whence in storage-specific info fn

184 files changed:
Documentation/RelNotes/2.15.0.txt [new file with mode: 0644]
Documentation/diff-config.txt
Documentation/diff-options.txt
Documentation/git-for-each-ref.txt
Documentation/git-grep.txt
Documentation/git-push.txt
Documentation/git-send-pack.txt
Documentation/git-tag.txt
Documentation/gitattributes.txt
Documentation/githooks.txt
Documentation/pretty-formats.txt
Documentation/technical/api-builtin.txt [deleted file]
Documentation/technical/api-config.txt
Documentation/technical/api-sub-process.txt [deleted file]
Makefile
RelNotes
apply.c
apply.h
archive.c
attr.c
bisect.c
builtin.h
builtin/add.c
builtin/am.c
builtin/branch.c
builtin/cat-file.c
builtin/checkout.c
builtin/clean.c
builtin/clone.c
builtin/commit-tree.c
builtin/commit.c
builtin/describe.c
builtin/difftool.c
builtin/fetch.c
builtin/fmt-merge-msg.c
builtin/for-each-ref.c
builtin/fsck.c
builtin/grep.c
builtin/log.c
builtin/ls-files.c
builtin/merge-tree.c
builtin/merge.c
builtin/mv.c
builtin/notes.c
builtin/pack-objects.c
builtin/pull.c
builtin/push.c
builtin/receive-pack.c
builtin/remote.c
builtin/replace.c
builtin/reset.c
builtin/rev-list.c
builtin/rev-parse.c
builtin/revert.c
builtin/rm.c
builtin/send-pack.c
builtin/show-branch.c
builtin/submodule--helper.c
builtin/tag.c
builtin/unpack-file.c
builtin/update-ref.c
builtin/verify-tag.c
cache-tree.c
cache.h
color.c
commit.c
commit.h
compat/bswap.h
compat/win32/syslog.c
config.c
config.h
contrib/coccinelle/array.cocci
contrib/contacts/git-contacts
contrib/rerere-train.sh
convert.c
convert.h
credential-cache.c
diff.c
dir.c
entry.c
fsck.c
git-compat-util.h
git-gui/Makefile
git-gui/lib/choose_repository.tcl
git-merge-octopus.sh
git-merge-one-file.sh
git-merge-resolve.sh
git-rebase--am.sh
git-rebase--interactive.sh
git-rebase.sh
git-stash.sh
git-submodule.sh
git.c
gitweb/gitweb.perl
grep.c
grep.h
http.c
mailmap.c
name-hash.c
notes-merge.c
notes.c
object.c
object.h
pager.c
patch-ids.c
perl/Git.pm
perl/Git/SVN.pm
pkt-line.c
pkt-line.h
pretty.c
read-cache.c
ref-filter.c
ref-filter.h
reflog-walk.c
reflog-walk.h
refs.c
refs/files-backend.c
refs/packed-backend.c [new file with mode: 0644]
refs/packed-backend.h [new file with mode: 0644]
refs/refs-internal.h
remote.c
remote.h
repository.c
repository.h
revision.c
revision.h
run-command.c
sequencer.c
setup.c
sha1-lookup.c
sha1_file.c
sha1_name.c
shallow.c
strbuf.c
strbuf.h
string-list.c
sub-process.c
sub-process.h
submodule-config.c
submodule-config.h
submodule.c
submodule.h
t/helper/test-hashmap.c
t/helper/test-path-utils.c
t/helper/test-submodule-config.c
t/lib-gpg.sh
t/t0001-init.sh
t/t0021-conversion.sh
t/t0021/rot13-filter.pl
t/t1200-tutorial.sh [deleted file]
t/t1408-packed-refs.sh [new file with mode: 0755]
t/t1411-reflog-show.sh
t/t1414-reflog-walk.sh [new file with mode: 0755]
t/t1450-fsck.sh
t/t3200-branch.sh
t/t3203-branch-output.sh
t/t3210-pack-refs.sh
t/t3418-rebase-continue.sh
t/t3504-cherry-pick-rerere.sh
t/t3700-add.sh
t/t4062-diff-pickaxe.sh
t/t4150-am.sh
t/t4202-log.sh
t/t4207-log-decoration-colors.sh
t/t5308-pack-detect-duplicates.sh
t/t5520-pull.sh
t/t5531-deep-submodule-push.sh
t/t5534-push-signed.sh
t/t6006-rev-list-format.sh
t/t6018-rev-list-glob.sh
t/t6300-for-each-ref.sh
t/t7004-tag.sh
t/t7006-pager.sh
t/t7301-clean-interactive.sh
t/t7400-submodule-basic.sh
t/t8008-blame-formats.sh
t/test-lib-functions.sh
t/test-lib.sh
tag.c
tag.h
templates/hooks--prepare-commit-msg.sample
transport-helper.c
tree-diff.c
unpack-trees.c

diff --git a/Documentation/RelNotes/2.15.0.txt b/Documentation/RelNotes/2.15.0.txt
new file mode 100644 (file)
index 0000000..001f006
--- /dev/null
@@ -0,0 +1,190 @@
+Git 2.15 Release Notes
+======================
+
+Backward compatibility notes and other notable changes.
+
+ * Use of an empty string as a pathspec element that is used for
+   'everything matches' is still warned and Git asks users to use a
+   more explicit '.' for that instead.  The hope is that existing
+   users will not mind this change, and eventually the warning can be
+   turned into a hard error, upgrading the deprecation into removal of
+   this (mis)feature.  That is now scheduled to happen in the upcoming
+   release.
+
+ * Git now avoids blindly falling back to ".git" when the setup
+   sequence said we are _not_ in Git repository.  A corner case that
+   happens to work right now may be broken by a call to die("BUG").
+   We've tried hard to locate such cases and fixed them, but there
+   might still be cases that need to be addressed--bug reports are
+   greatly appreciated.
+
+
+Updates since v2.14
+-------------------
+
+UI, Workflows & Features
+
+ * An example that is now obsolete has been removed from a sample hook,
+   and an old example in it that added a sign-off manually has been
+   improved to use the interpret-trailers command.
+
+ * The advice message given when "git rebase" stops for conflicting
+   changes has been improved.
+
+ * The "rerere-train" script (in contrib/) learned the "--overwrite"
+   option to allow overwriting existing recorded resolutions.
+   (merge ad53bf79aa rg/rerere-train-overwrite later to maint).
+
+ * "git contacts" (in contrib/) now lists the address on the
+   "Reported-by:" trailer to its output, in addition to those on
+   S-o-b: and other trailers, to make it easier to notify (and thank)
+   the original bug reporter.
+   (merge 09ac673788 eb/contacts-reported-by later to maint).
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * Conversion from uchar[20] to struct object_id continues.
+
+ * Start using selected c99 constructs in small, stable and
+   essentialpart of the system to catch people who care about
+   older compilers that do not grok them.
+
+ * The filter-process interface learned to allow a process with long
+   latency give a "delayed" response.
+
+ * Many uses of comparision callback function the hashmap API uses
+   cast the callback function type when registering it to
+   hashmap_init(), which defeats the compile time type checking when
+   the callback interface changes (e.g. gaining more parameters).
+   The callback implementations have been updated to take "void *"
+   pointers and cast them to the type they expect instead.
+
+ * Because recent Git for Windows do come with a real msgfmt, the
+   build procedure for git-gui has been updated to use it instead of a
+   hand-rolled substitute.
+   (merge 90dbf226ba js/git-gui-msgfmt-on-windows later to maint).
+
+ * "git grep --recurse-submodules" has been reworked to give a more
+   consistent output across submodule boundary (and do its thing
+   without having to fork a separate process).
+
+ * A helper function to read a single whole line into strbuf
+   mistakenly triggered OOM error at EOF under certain conditions,
+   which has been fixed.
+   (merge 642956cf45 rs/strbuf-getwholeline-fix later to maint).
+
+ * The "ref-store" code reorganization continues.
+
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v2.14
+-----------------
+
+ * "%C(color name)" in the pretty print format always produced ANSI
+   color escape codes, which was an early design mistake.  They now
+   honor the configuration (e.g. "color.ui = never") and also tty-ness
+   of the output medium.
+   (merge 11b087adfd jk/ref-filter-colors later to maint).
+
+ * The http.{sslkey,sslCert} configuration variables are to be
+   interpreted as a pathname that honors "~[username]/" prefix, but
+   weren't, which has been fixed.
+   (merge 8d1549643e jc/http-sslkey-and-ssl-cert-are-paths later to maint).
+
+ * Numerous bugs in walking of reflogs via "log -g" and friends have
+   been fixed.
+   (merge de239446b6 jk/reflog-walk later to maint).
+
+ * "git commit" when seeing an totally empty message said "you did not
+   edit the message", which is clearly wrong.  The message has been
+   corrected.
+   (merge bc17f35f8c ks/commit-abort-on-empty-message-fix later to maint).
+
+ * When a directory is not readable, "gitweb" fails to build the
+   project list.  Work this around by skipping such a directory.
+   (merge 46a13857fc hb/gitweb-project-list later to maint).
+
+ * Some versions of GnuPG fails to kill gpg-agent it auto-spawned
+   and such a left-over agent can interfere with a test.  Work it
+   around by attempting to kill one before starting a new test.
+   (merge 29ff1f8f74 st/lib-gpg-kill-stray-agent later to maint).
+
+ * A recently added test for the "credential-cache" helper revealed
+   that EOF detection done around the time the connection to the cache
+   daemon is torn down were flaky.  This was fixed by reacting to
+   ECONNRESET and behaving as if we got an EOF.
+   (merge 1f180e5eb9 dl/credential-cache-socket-in-xdg-cache later to maint).
+
+ * "git log --tag=no-such-tag" showed log starting from HEAD, which
+   has been fixed---it now shows nothing.
+   (merge 5d34d1ac06 jk/rev-list-empty-input later to maint).
+
+ * The "tag.pager" configuration variable was useless for those who
+   actually create tag objects, as it interfered with the use of an
+   editor.  A new mechanism has been introduced for commands to enable
+   pager depending on what operation is being carried out to fix this,
+   and then "git tag -l" is made to run pager by default.
+   (merge 595d59e2b5 ma/pager-per-subcommand-action later to maint).
+
+ * "git push --recurse-submodules $there HEAD:$target" was not
+   propagated down to the submodules, but now it is.
+   (merge c7be7201a7 bw/push-options-recursively-to-submodules later to maint).
+
+ * Commands like "git rebase" accepted the --rerere-autoupdate option
+   from the command line, but did not always use it.  This has been
+   fixed.
+   (merge f826fb799e pw/sequence-rerere-autoupdate later to maint).
+
+ * "git clone --recurse-submodules --quiet" did not pass the quiet
+   option down to submodules.
+   (merge 03c004c581 bw/clone-recursive-quiet later to maint).
+
+ * Test portability fix for OBSD.
+   (merge bed67874e2 rs/obsd-getcwd-workaround later to maint).
+   (merge 4c7fda8fc1 rs/t4062-obsd later to maint).
+
+ * Portability fix for OBSD.
+   (merge 29c2eda80b rs/in-obsd-basename-dirname-take-const later to maint).
+
+ * "git am -s" has been taught that some input may end with a trailer
+   block that is not Signed-off-by: and it should refrain from adding
+   an extra blank line before adding a new sign-off in such a case.
+   (merge 735285b403 pw/am-signoff later to maint).
+
+ * "git svn" used with "--localtime" option did not compute the tz
+   offset for the timestamp in question and instead always used the
+   current time, which has been corrected.
+   (merge 1adc4b9a58 ur/svn-local-zone later to maint).
+
+ * Memory leak in an error codepath has been plugged.
+   (merge 83cd6f9017 rs/fsck-obj-leakfix later to maint).
+   (merge 896dca3ab7 rs/unpack-entry-leakfix later to maint).
+   (merge 149d8cbb2e rs/win32-syslog-leakfix later to maint).
+
+ * Other minor doc, test and build updates and code cleanups.
+   (merge 5b114f3bb0 rs/bswap-ubsan-fix later to maint).
+   (merge 168e63554c rs/move-array later to maint).
+   (merge 268ba20110 rs/stat-data-unaligned-reads-fix later to maint).
+   (merge 78e7b98f45 jt/fsck-code-cleanup later to maint).
+   (merge c7b0780545 rs/pack-objects-pbase-cleanup later to maint).
+   (merge c1e860f1dc js/run-process-parallel-api-fix later to maint).
+   (merge 7a40a95eb4 cc/ref-is-hidden-microcleanup later to maint).
+   (merge c0bb6d9cef ah/doc-wserrorhighlight later to maint).
+   (merge edd64ef4f7 dc/fmt-merge-msg-microcleanup later to maint).
+   (merge fa64a2fdbe jt/subprocess-handshake later to maint).
+   (merge 0ba9c9a0fb jb/t8008-cleanup later to maint).
+   (merge a7c28a2161 jt/t1450-fsck-corrupt-packfile later to maint).
+   (merge dff2813391 ab/ref-filter-no-contains later to maint).
+   (merge f094b89a4d ma/parse-maybe-bool later to maint).
+   (merge 974ce8078c mf/no-dashed-subcommands later to maint).
+   (merge f81935cc4d jc/perl-git-comment-typofix later to maint).
+   (merge 57ea241ef0 rs/t3700-clean-leftover later to maint).
+   (merge f1068efefe jk/drop-sha1-entry-pos later to maint).
+   (merge 0b006014c8 jk/hashcmp-memcmp later to maint).
+   (merge 1e22a9917b rj/add-chmod-error-message later to maint).
+   (merge 881529c846 rs/apply-lose-prefix-length later to maint).
+   (merge 6355a76802 rs/find-pack-entry-bisection later to maint).
+   (merge de3ce210ed rs/merge-microcleanup later to maint).
index cbce8ec..5ca942a 100644 (file)
@@ -200,7 +200,10 @@ diff.algorithm::
 +
 
 diff.wsErrorHighlight::
-       A comma separated list of `old`, `new`, `context`, that
-       specifies how whitespace errors on lines are highlighted
-       with `color.diff.whitespace`.  Can be overridden by the
-       command line option `--ws-error-highlight=<kind>`
+       Highlight whitespace errors in the `context`, `old` or `new`
+       lines of the diff.  Multiple values are separated by comma,
+       `none` resets previous values, `default` reset the list to
+       `new` and `all` is a shorthand for `old,new,context`.  The
+       whitespace errors are colored with `color.diff.whitespace`.
+       The command line option `--ws-error-highlight=<kind>`
+       overrides this setting.
index 43d18a4..56dedaf 100644 (file)
@@ -300,15 +300,14 @@ ifndef::git-format-patch[]
        with --exit-code.
 
 --ws-error-highlight=<kind>::
-       Highlight whitespace errors on lines specified by <kind>
-       in the color specified by `color.diff.whitespace`.  <kind>
-       is a comma separated list of `old`, `new`, `context`.  When
-       this option is not given, only whitespace errors in `new`
-       lines are highlighted.  E.g. `--ws-error-highlight=new,old`
-       highlights whitespace errors on both deleted and added lines.
-       `all` can be used as a short-hand for `old,new,context`.
-       The `diff.wsErrorHighlight` configuration variable can be
-       used to specify the default behaviour.
+       Highlight whitespace errors in the `context`, `old` or `new`
+       lines of the diff.  Multiple values are separated by comma,
+       `none` resets previous values, `default` reset the list to
+       `new` and `all` is a shorthand for `old,new,context`.  When
+       this option is not given, and the configuration variable
+       `diff.wsErrorHighlight` is not set, only whitespace errors in
+       `new` lines are highlighted. The whitespace errors are colored
+       whith `color.diff.whitespace`.
 
 endif::git-format-patch[]
 
index 03e187a..cc42c12 100644 (file)
@@ -156,8 +156,10 @@ HEAD::
        otherwise.
 
 color::
-       Change output color.  Followed by `:<colorname>`, where names
-       are described in `color.branch.*`.
+       Change output color. Followed by `:<colorname>`, where color
+       names are described under Values in the "CONFIGURATION FILE"
+       section of linkgit:git-config[1].  For example,
+       `%(color:bold red)`.
 
 align::
        Left-, middle-, or right-align the content between
index 5033483..720c785 100644 (file)
@@ -95,13 +95,6 @@ OPTIONS
        <tree> option the prefix of all submodule output will be the name of
        the parent project's <tree> object.
 
---parent-basename <basename>::
-       For internal use only.  In order to produce uniform output with the
-       --recurse-submodules option, this option can be used to provide the
-       basename of a parent's <tree> object to a submodule so the submodule
-       can prefix its output with the parent's name rather than the SHA1 of
-       the submodule.
-
 -a::
 --text::
        Process binary files as if they were text.
index 0a63966..3e76e99 100644 (file)
@@ -12,7 +12,7 @@ SYNOPSIS
 'git push' [--all | --mirror | --tags] [--follow-tags] [--atomic] [-n | --dry-run] [--receive-pack=<git-receive-pack>]
           [--repo=<repository>] [-f | --force] [-d | --delete] [--prune] [-v | --verbose]
           [-u | --set-upstream] [--push-option=<string>]
-          [--[no-]signed|--sign=(true|false|if-asked)]
+          [--[no-]signed|--signed=(true|false|if-asked)]
           [--force-with-lease[=<refname>[:<expect>]]]
           [--no-verify] [<repository> [<refspec>...]]
 
@@ -141,7 +141,7 @@ already exists on the remote side.
        information, see `push.followTags` in linkgit:git-config[1].
 
 --[no-]signed::
---sign=(true|false|if-asked)::
+--signed=(true|false|if-asked)::
        GPG-sign the push request to update refs on the receiving
        side, to allow it to be checked by the hooks and/or be
        logged.  If `false` or `--no-signed`, no signing will be
index 966abb0..f51c649 100644 (file)
@@ -11,7 +11,7 @@ SYNOPSIS
 [verse]
 'git send-pack' [--all] [--dry-run] [--force] [--receive-pack=<git-receive-pack>]
                [--verbose] [--thin] [--atomic]
-               [--[no-]signed|--sign=(true|false|if-asked)]
+               [--[no-]signed|--signed=(true|false|if-asked)]
                [<host>:]<directory> [<ref>...]
 
 DESCRIPTION
@@ -71,7 +71,7 @@ be in a separate packet, and the list must end with a flush packet.
        refs.
 
 --[no-]signed::
---sign=(true|false|if-asked)::
+--signed=(true|false|if-asked)::
        GPG-sign the push request to update refs on the receiving
        side, to allow it to be checked by the hooks and/or be
        logged.  If `false` or `--no-signed`, no signing will be
index 1eb15af..d97aad3 100644 (file)
@@ -205,6 +205,9 @@ it in the repository configuration as follows:
     signingKey = <gpg-keyid>
 -------------------------------------
 
+`pager.tag` is only respected when listing tags, i.e., when `-l` is
+used or implied. The default is to use a pager.
+See linkgit:git-config[1].
 
 DISCUSSION
 ----------
index 2a2d7e2..c4f2be2 100644 (file)
@@ -425,8 +425,8 @@ packet:          git< capability=clean
 packet:          git< capability=smudge
 packet:          git< 0000
 ------------------------
-Supported filter capabilities in version 2 are "clean" and
-"smudge".
+Supported filter capabilities in version 2 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
@@ -512,12 +512,73 @@ 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 blob it is expected to wait for
-the next "key=value" list containing a command. Git will close
+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
+^^^^^
+
+If the filter supports the "delay" capability, then Git can send the
+flag "can-delay" after the filter command and pathname. This flag
+denotes that the filter can delay filtering the current blob (e.g. to
+compensate network latencies) by responding with no content but with
+the status "delayed" and a flush packet.
+------------------------
+packet:          git> command=smudge
+packet:          git> pathname=path/testfile.dat
+packet:          git> can-delay=1
+packet:          git> 0000
+packet:          git> CONTENT
+packet:          git> 0000
+packet:          git< status=delayed
+packet:          git< 0000
+------------------------
+
+If the filter supports the "delay" capability then it must support the
+"list_available_blobs" command. If Git sends this command, then the
+filter is expected to return a list of pathnames representing blobs
+that have been delayed earlier and are now available.
+The list must be terminated with a flush packet followed
+by a "success" status that is also terminated with a flush packet. If
+no blobs for the delayed paths are available, yet, then the filter is
+expected to block the response until at least one blob becomes
+available. The filter can tell Git that it has no more delayed blobs
+by sending an empty list. As soon as the filter responds with an empty
+list, Git stops asking. All blobs that Git has not received at this
+point are considered missing and will result in an error.
+
+------------------------
+packet:          git> command=list_available_blobs
+packet:          git> 0000
+packet:          git< pathname=path/testfile.dat
+packet:          git< pathname=path/otherfile.dat
+packet:          git< 0000
+packet:          git< status=success
+packet:          git< 0000
+------------------------
+
+After Git received the pathnames, it will request the corresponding
+blobs again. These requests contain a pathname and an empty content
+section. The filter is expected to respond with the smudged content
+in the usual way as explained above.
+------------------------
+packet:          git> command=smudge
+packet:          git> pathname=path/testfile.dat
+packet:          git> 0000
+packet:          git> 0000  # empty content!
+packet:          git< status=success
+packet:          git< 0000
+packet:          git< SMUDGED_CONTENT
+packet:          git< 0000
+packet:          git< 0000  # empty list, keep "status=success" unchanged!
+------------------------
+
+Example
+^^^^^^^
+
 A long running filter demo implementation can be found in
 `contrib/long-running-filter/example.pl` located in the Git
 core repository. If you develop your own long running filter
index b2514f4..623ed1a 100644 (file)
@@ -121,8 +121,8 @@ it is not suppressed by the `--no-verify` option.  A non-zero exit
 means a failure of the hook and aborts the commit.  It should not
 be used as replacement for pre-commit hook.
 
-The sample `prepare-commit-msg` hook that comes with Git comments
-out the `Conflicts:` part of a merge's commit message.
+The sample `prepare-commit-msg` hook that comes with Git removes the
+help message found in the commented portion of the commit template.
 
 commit-msg
 ~~~~~~~~~~
index 4d6dac5..973d196 100644 (file)
@@ -173,13 +173,17 @@ endif::git-rev-list[]
 - '%Cblue': switch color to blue
 - '%Creset': reset color
 - '%C(...)': color specification, as described under Values in the
-  "CONFIGURATION FILE" section of linkgit:git-config[1];
-  adding `auto,` at the beginning (e.g. `%C(auto,red)`) will emit
-  color only when colors are enabled for log output (by `color.diff`,
-  `color.ui`, or `--color`, and respecting the `auto` settings of the
-  former if we are going to a terminal). `auto` alone (i.e.
-  `%C(auto)`) will turn on auto coloring on the next placeholders
-  until the color is switched again.
+  "CONFIGURATION FILE" section of linkgit:git-config[1].
+  By default, colors are shown only when enabled for log output (by
+  `color.diff`, `color.ui`, or `--color`, and respecting the `auto`
+  settings of the former if we are going to a terminal). `%C(auto,...)`
+  is accepted as a historical synonym for the default (e.g.,
+  `%C(auto,red)`). Specifying `%C(always,...) will show the colors
+  even when color is not otherwise enabled (though consider
+  just using `--color=always` to enable color for the whole output,
+  including this format and anything else git might color).  `auto`
+  alone (i.e. `%C(auto)`) will turn on auto coloring on the next
+  placeholders until the color is switched again.
 - '%m': left (`<`), right (`>`) or boundary (`-`) mark
 - '%n': newline
 - '%%': a raw '%'
diff --git a/Documentation/technical/api-builtin.txt b/Documentation/technical/api-builtin.txt
deleted file mode 100644 (file)
index 22a39b9..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-builtin API
-===========
-
-Adding a new built-in
----------------------
-
-There are 4 things to do to add a built-in command implementation to
-Git:
-
-. Define the implementation of the built-in command `foo` with
-  signature:
-
-       int cmd_foo(int argc, const char **argv, const char *prefix);
-
-. Add the external declaration for the function to `builtin.h`.
-
-. Add the command to the `commands[]` table defined in `git.c`.
-  The entry should look like:
-
-       { "foo", cmd_foo, <options> },
-+
-where options is the bitwise-or of:
-
-`RUN_SETUP`::
-       If there is not a Git directory to work on, abort.  If there
-       is a work tree, chdir to the top of it if the command was
-       invoked in a subdirectory.  If there is no work tree, no
-       chdir() is done.
-
-`RUN_SETUP_GENTLY`::
-       If there is a Git directory, chdir as per RUN_SETUP, otherwise,
-       don't chdir anywhere.
-
-`USE_PAGER`::
-
-       If the standard output is connected to a tty, spawn a pager and
-       feed our output to it.
-
-`NEED_WORK_TREE`::
-
-       Make sure there is a work tree, i.e. the command cannot act
-       on bare repositories.
-       This only makes sense when `RUN_SETUP` is also set.
-
-. Add `builtin/foo.o` to `BUILTIN_OBJS` in `Makefile`.
-
-Additionally, if `foo` is a new command, there are 3 more things to do:
-
-. Add tests to `t/` directory.
-
-. Write documentation in `Documentation/git-foo.txt`.
-
-. Add an entry for `git-foo` to `command-list.txt`.
-
-. Add an entry for `/git-foo` to `.gitignore`.
-
-
-How a built-in is called
-------------------------
-
-The implementation `cmd_foo()` takes three parameters, `argc`, `argv,
-and `prefix`.  The first two are similar to what `main()` of a
-standalone command would be called with.
-
-When `RUN_SETUP` is specified in the `commands[]` table, and when you
-were started from a subdirectory of the work tree, `cmd_foo()` is called
-after chdir(2) to the top of the work tree, and `prefix` gets the path
-to the subdirectory the command started from.  This allows you to
-convert a user-supplied pathname (typically relative to that directory)
-to a pathname relative to the top of the work tree.
-
-The return value from `cmd_foo()` becomes the exit status of the
-command.
index 20741f3..7a83a3a 100644 (file)
@@ -187,6 +187,10 @@ Same as `git_config_bool`, except that integers are returned as-is, and
 an `is_bool` flag is unset.
 
 `git_config_maybe_bool`::
+Deprecated. Use `git_parse_maybe_bool` instead. They are exactly the
+same, except this function takes an unused argument `name`.
+
+`git_parse_maybe_bool`::
 Same as `git_config_bool`, except that it returns -1 on error rather
 than dying.
 
diff --git a/Documentation/technical/api-sub-process.txt b/Documentation/technical/api-sub-process.txt
deleted file mode 100644 (file)
index 793508c..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-sub-process API
-===============
-
-The sub-process API makes it possible to run background sub-processes
-for the entire lifetime of a Git invocation. If Git needs to communicate
-with an external process multiple times, then this can reduces the process
-invocation overhead. Git and the sub-process communicate through stdin and
-stdout.
-
-The sub-processes are kept in a hashmap by command name and looked up
-via the subprocess_find_entry function.  If an existing instance can not
-be found then a new process should be created and started.  When the
-parent git command terminates, all sub-processes are also terminated.
-
-This API is based on the run-command API.
-
-Data structures
----------------
-
-* `struct subprocess_entry`
-
-The sub-process structure.  Members should not be accessed directly.
-
-Types
------
-
-'int(*subprocess_start_fn)(struct subprocess_entry *entry)'::
-
-       User-supplied function to initialize the sub-process.  This is
-       typically used to negotiate the interface version and capabilities.
-
-
-Functions
----------
-
-`cmd2process_cmp`::
-
-       Function to test two subprocess hashmap entries for equality.
-
-`subprocess_start`::
-
-       Start a subprocess and add it to the subprocess hashmap.
-
-`subprocess_stop`::
-
-       Kill a subprocess and remove it from the subprocess hashmap.
-
-`subprocess_find_entry`::
-
-       Find a subprocess in the subprocess hashmap.
-
-`subprocess_get_child_process`::
-
-       Get the underlying `struct child_process` from a subprocess.
-
-`subprocess_read_status`::
-
-       Helper function to read packets looking for the last "status=<foo>"
-       key/value pair.
index 461c845..86ec292 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -842,6 +842,7 @@ LIB_OBJS += reflog-walk.o
 LIB_OBJS += refs.o
 LIB_OBJS += refs/files-backend.o
 LIB_OBJS += refs/iterator.o
+LIB_OBJS += refs/packed-backend.o
 LIB_OBJS += refs/ref-cache.o
 LIB_OBJS += ref-filter.o
 LIB_OBJS += remote.o
index 86e33ed..80ae7a3 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.14.1.txt
\ No newline at end of file
+Documentation/RelNotes/2.15.0.txt
\ No newline at end of file
diff --git a/apply.c b/apply.c
index f2d5991..956f56a 100644 (file)
--- a/apply.c
+++ b/apply.c
@@ -80,7 +80,6 @@ int init_apply_state(struct apply_state *state,
 {
        memset(state, 0, sizeof(*state));
        state->prefix = prefix;
-       state->prefix_length = state->prefix ? strlen(state->prefix) : 0;
        state->lock_file = lock_file;
        state->newfd = -1;
        state->apply = 1;
@@ -786,11 +785,11 @@ static int guess_p_value(struct apply_state *state, const char *nameline)
                 * Does it begin with "a/$our-prefix" and such?  Then this is
                 * very likely to apply to our directory.
                 */
-               if (!strncmp(name, state->prefix, state->prefix_length))
+               if (starts_with(name, state->prefix))
                        val = count_slashes(state->prefix);
                else {
                        cp++;
-                       if (!strncmp(cp, state->prefix, state->prefix_length))
+                       if (starts_with(cp, state->prefix))
                                val = count_slashes(state->prefix) + 1;
                }
        }
@@ -2089,10 +2088,9 @@ static int use_patch(struct apply_state *state, struct patch *p)
        int i;
 
        /* Paths outside are not touched regardless of "--include" */
-       if (0 < state->prefix_length) {
-               int pathlen = strlen(pathname);
-               if (pathlen <= state->prefix_length ||
-                   memcmp(state->prefix, pathname, state->prefix_length))
+       if (state->prefix && *state->prefix) {
+               const char *rest;
+               if (!skip_prefix(pathname, state->prefix, &rest) || !*rest)
                        return 0;
        }
 
@@ -2809,13 +2807,10 @@ static void update_image(struct apply_state *state,
                img->line_allocated = img->line;
        }
        if (preimage_limit != postimage->nr)
-               memmove(img->line + applied_pos + postimage->nr,
-                       img->line + applied_pos + preimage_limit,
-                       (img->nr - (applied_pos + preimage_limit)) *
-                       sizeof(*img->line));
-       memcpy(img->line + applied_pos,
-              postimage->line,
-              postimage->nr * sizeof(*img->line));
+               MOVE_ARRAY(img->line + applied_pos + postimage->nr,
+                          img->line + applied_pos + preimage_limit,
+                          img->nr - (applied_pos + preimage_limit));
+       COPY_ARRAY(img->line + applied_pos, postimage->line, postimage->nr);
        if (!state->allow_overlap)
                for (i = 0; i < postimage->nr; i++)
                        img->line[applied_pos + i].flag |= LINE_PATCHED;
@@ -3551,7 +3546,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);
-       else if (get_sha1(patch->old_sha1_prefix, pre_oid.hash) ||
+       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."));
 
@@ -4075,7 +4070,7 @@ static int build_fake_ancestor(struct apply_state *state, struct patch *list)
                        else
                                return error(_("sha1 information is lacking or "
                                               "useless for submodule %s"), name);
-               } else if (!get_sha1_blob(patch->old_sha1_prefix, oid.hash)) {
+               } else if (!get_oid_blob(patch->old_sha1_prefix, &oid)) {
                        ; /* ok */
                } else if (!patch->lines_added && !patch->lines_deleted) {
                        /* mode-only change: update the current */
diff --git a/apply.h b/apply.h
index b3d6783..d9b3957 100644 (file)
--- a/apply.h
+++ b/apply.h
@@ -35,7 +35,6 @@ enum apply_verbosity {
 
 struct apply_state {
        const char *prefix;
-       int prefix_length;
 
        /* These are lock_file related */
        struct lock_file *lock_file;
index 60b3035..557dd2d 100644 (file)
--- a/archive.c
+++ b/archive.c
@@ -358,7 +358,7 @@ static void parse_treeish_arg(const char **argv,
                free(ref);
        }
 
-       if (get_sha1(name, oid.hash))
+       if (get_oid(name, &oid))
                die("Not a valid object name");
 
        commit = lookup_commit_reference_gently(&oid, 1);
diff --git a/attr.c b/attr.c
index 56961f0..2f49151 100644 (file)
--- a/attr.c
+++ b/attr.c
@@ -76,18 +76,20 @@ struct attr_hash_entry {
 };
 
 /* attr_hashmap comparison function */
-static int attr_hash_entry_cmp(void *unused_cmp_data,
-                              const struct attr_hash_entry *a,
-                              const struct attr_hash_entry *b,
-                              void *unused_keydata)
+static int attr_hash_entry_cmp(const void *unused_cmp_data,
+                              const void *entry,
+                              const void *entry_or_key,
+                              const void *unused_keydata)
 {
+       const struct attr_hash_entry *a = entry;
+       const struct attr_hash_entry *b = entry_or_key;
        return (a->keylen != b->keylen) || strncmp(a->key, b->key, a->keylen);
 }
 
 /* Initialize an 'attr_hashmap' object */
 static void attr_hashmap_init(struct attr_hashmap *map)
 {
-       hashmap_init(&map->map, (hashmap_cmp_fn) attr_hash_entry_cmp, NULL, 0);
+       hashmap_init(&map->map, attr_hash_entry_cmp, NULL, 0);
 }
 
 /*
index a9fd9fb..2549eaf 100644 (file)
--- a/bisect.c
+++ b/bisect.c
@@ -680,16 +680,16 @@ static int is_expected_rev(const struct object_id *oid)
        return res;
 }
 
-static int bisect_checkout(const unsigned char *bisect_rev, int no_checkout)
+static int bisect_checkout(const struct object_id *bisect_rev, int no_checkout)
 {
        char bisect_rev_hex[GIT_MAX_HEXSZ + 1];
 
-       memcpy(bisect_rev_hex, sha1_to_hex(bisect_rev), GIT_SHA1_HEXSZ + 1);
-       update_ref(NULL, "BISECT_EXPECTED_REV", bisect_rev, NULL, 0, UPDATE_REFS_DIE_ON_ERR);
+       memcpy(bisect_rev_hex, oid_to_hex(bisect_rev), GIT_SHA1_HEXSZ + 1);
+       update_ref(NULL, "BISECT_EXPECTED_REV", bisect_rev->hash, NULL, 0, UPDATE_REFS_DIE_ON_ERR);
 
        argv_checkout[2] = bisect_rev_hex;
        if (no_checkout) {
-               update_ref(NULL, "BISECT_HEAD", bisect_rev, NULL, 0, UPDATE_REFS_DIE_ON_ERR);
+               update_ref(NULL, "BISECT_HEAD", bisect_rev->hash, NULL, 0, UPDATE_REFS_DIE_ON_ERR);
        } else {
                int res;
                res = run_command_v_opt(argv_checkout, RUN_GIT_CMD);
@@ -796,7 +796,7 @@ static void check_merge_bases(int no_checkout)
                        handle_skipped_merge_base(mb);
                } else {
                        printf(_("Bisecting: a merge base must be tested\n"));
-                       exit(bisect_checkout(mb->hash, no_checkout));
+                       exit(bisect_checkout(mb, no_checkout));
                }
        }
 
@@ -939,7 +939,7 @@ int bisect_next_all(const char *prefix, int no_checkout)
        struct rev_info revs;
        struct commit_list *tried;
        int reaches = 0, all = 0, nr, steps;
-       const unsigned char *bisect_rev;
+       struct object_id *bisect_rev;
        char *steps_msg;
 
        read_bisect_terms(&term_bad, &term_good);
@@ -977,11 +977,11 @@ int bisect_next_all(const char *prefix, int no_checkout)
                exit(4);
        }
 
-       bisect_rev = revs.commits->item->object.oid.hash;
+       bisect_rev = &revs.commits->item->object.oid;
 
-       if (!hashcmp(bisect_rev, current_bad_oid->hash)) {
+       if (!oidcmp(bisect_rev, current_bad_oid)) {
                exit_if_skipped_commits(tried, current_bad_oid);
-               printf("%s is the first %s commit\n", sha1_to_hex(bisect_rev),
+               printf("%s is the first %s commit\n", oid_to_hex(bisect_rev),
                        term_bad);
                show_diff_tree(prefix, revs.commits->item);
                /* This means the bisection process succeeded. */
index 498ac80..42378f3 100644 (file)
--- a/builtin.h
+++ b/builtin.h
@@ -6,6 +6,94 @@
 #include "cache.h"
 #include "commit.h"
 
+/*
+ * builtin API
+ * ===========
+ *
+ * Adding a new built-in
+ * ---------------------
+ *
+ * There are 4 things to do to add a built-in command implementation to
+ * Git:
+ *
+ * . Define the implementation of the built-in command `foo` with
+ *   signature:
+ *
+ *     int cmd_foo(int argc, const char **argv, const char *prefix);
+ *
+ * . Add the external declaration for the function to `builtin.h`.
+ *
+ * . Add the command to the `commands[]` table defined in `git.c`.
+ *   The entry should look like:
+ *
+ *     { "foo", cmd_foo, <options> },
+ *
+ * where options is the bitwise-or of:
+ *
+ * `RUN_SETUP`:
+ *     If there is not a Git directory to work on, abort.  If there
+ *     is a work tree, chdir to the top of it if the command was
+ *     invoked in a subdirectory.  If there is no work tree, no
+ *     chdir() is done.
+ *
+ * `RUN_SETUP_GENTLY`:
+ *     If there is a Git directory, chdir as per RUN_SETUP, otherwise,
+ *     don't chdir anywhere.
+ *
+ * `USE_PAGER`:
+ *
+ *     If the standard output is connected to a tty, spawn a pager and
+ *     feed our output to it.
+ *
+ * `NEED_WORK_TREE`:
+ *
+ *     Make sure there is a work tree, i.e. the command cannot act
+ *     on bare repositories.
+ *     This only makes sense when `RUN_SETUP` is also set.
+ *
+ * `SUPPORT_SUPER_PREFIX`:
+ *
+ *     The built-in supports `--super-prefix`.
+ *
+ * `DELAY_PAGER_CONFIG`:
+ *
+ *     If RUN_SETUP or RUN_SETUP_GENTLY is set, git.c normally handles
+ *     the `pager.<cmd>`-configuration. If this flag is used, git.c
+ *     will skip that step, instead allowing the built-in to make a
+ *     more informed decision, e.g., by ignoring `pager.<cmd>` for
+ *     certain subcommands.
+ *
+ * . Add `builtin/foo.o` to `BUILTIN_OBJS` in `Makefile`.
+ *
+ * Additionally, if `foo` is a new command, there are 4 more things to do:
+ *
+ * . Add tests to `t/` directory.
+ *
+ * . Write documentation in `Documentation/git-foo.txt`.
+ *
+ * . Add an entry for `git-foo` to `command-list.txt`.
+ *
+ * . Add an entry for `/git-foo` to `.gitignore`.
+ *
+ *
+ * How a built-in is called
+ * ------------------------
+ *
+ * The implementation `cmd_foo()` takes three parameters, `argc`, `argv,
+ * and `prefix`.  The first two are similar to what `main()` of a
+ * standalone command would be called with.
+ *
+ * When `RUN_SETUP` is specified in the `commands[]` table, and when you
+ * were started from a subdirectory of the work tree, `cmd_foo()` is called
+ * after chdir(2) to the top of the work tree, and `prefix` gets the path
+ * to the subdirectory the command started from.  This allows you to
+ * convert a user-supplied pathname (typically relative to that directory)
+ * to a pathname relative to the top of the work tree.
+ *
+ * The return value from `cmd_foo()` becomes the exit status of the
+ * command.
+ */
+
 #define DEFAULT_MERGE_LOG_LEN 20
 
 extern const char git_usage_string[];
@@ -25,6 +113,18 @@ struct fmt_merge_msg_opts {
 extern int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
                         struct fmt_merge_msg_opts *);
 
+/**
+ * If a built-in has DELAY_PAGER_CONFIG set, the built-in should call this early
+ * when it wishes to respect the `pager.foo`-config. The `cmd` is the name of
+ * the built-in, e.g., "foo". If a paging-choice has already been setup, this
+ * does nothing. The default in `def` should be 0 for "pager off", 1 for "pager
+ * on" or -1 for "punt".
+ *
+ * You should most likely use a default of 0 or 1. "Punt" (-1) could be useful
+ * to be able to fall back to some historical compatibility name.
+ */
+extern void setup_auto_pager(const char *cmd, int def);
+
 extern int is_builtin(const char *s);
 
 extern int cmd_add(int argc, const char **argv, const char *prefix);
index e888fb8..5d5773d 100644 (file)
@@ -32,7 +32,7 @@ struct update_callback_data {
        int add_errors;
 };
 
-static void chmod_pathspec(struct pathspec *pathspec, int force_mode)
+static void chmod_pathspec(struct pathspec *pathspec, char flip)
 {
        int i;
 
@@ -42,8 +42,8 @@ static void chmod_pathspec(struct pathspec *pathspec, int force_mode)
                if (pathspec && !ce_path_match(ce, pathspec, NULL))
                        continue;
 
-               if (chmod_cache_entry(ce, force_mode) < 0)
-                       fprintf(stderr, "cannot chmod '%s'", ce->name);
+               if (chmod_cache_entry(ce, flip) < 0)
+                       fprintf(stderr, "cannot chmod %cx '%s'\n", flip, ce->name);
        }
 }
 
index c973bd9..81095da 100644 (file)
@@ -431,6 +431,14 @@ static void am_load(struct am_state *state)
        read_state_file(&sb, state, "utf8", 1);
        state->utf8 = !strcmp(sb.buf, "t");
 
+       if (file_exists(am_path(state, "rerere-autoupdate"))) {
+               read_state_file(&sb, state, "rerere-autoupdate", 1);
+               state->allow_rerere_autoupdate = strcmp(sb.buf, "t") ?
+                       RERERE_NOAUTOUPDATE : RERERE_AUTOUPDATE;
+       } else {
+               state->allow_rerere_autoupdate = 0;
+       }
+
        read_state_file(&sb, state, "keep", 1);
        if (!strcmp(sb.buf, "t"))
                state->keep = KEEP_TRUE;
@@ -1003,6 +1011,10 @@ static void am_setup(struct am_state *state, enum patch_format patch_format,
        write_state_bool(state, "sign", state->signoff);
        write_state_bool(state, "utf8", state->utf8);
 
+       if (state->allow_rerere_autoupdate)
+               write_state_bool(state, "rerere-autoupdate",
+                        state->allow_rerere_autoupdate == RERERE_AUTOUPDATE);
+
        switch (state->keep) {
        case KEEP_FALSE:
                str = "f";
@@ -1131,7 +1143,7 @@ static int index_has_changes(struct strbuf *sb)
        struct object_id head;
        int i;
 
-       if (!get_sha1_tree("HEAD", head.hash)) {
+       if (!get_oid_tree("HEAD", &head)) {
                struct diff_options opt;
 
                diff_setup(&opt);
@@ -1181,34 +1193,10 @@ static void NORETURN die_user_resolve(const struct am_state *state)
  */
 static void am_append_signoff(struct am_state *state)
 {
-       char *cp;
-       struct strbuf mine = STRBUF_INIT;
        struct strbuf sb = STRBUF_INIT;
 
        strbuf_attach(&sb, state->msg, state->msg_len, state->msg_len);
-
-       /* our sign-off */
-       strbuf_addf(&mine, "\n%s%s\n",
-                   sign_off_header,
-                   fmt_name(getenv("GIT_COMMITTER_NAME"),
-                            getenv("GIT_COMMITTER_EMAIL")));
-
-       /* Does sb end with it already? */
-       if (mine.len < sb.len &&
-           !strcmp(mine.buf, sb.buf + sb.len - mine.len))
-               goto exit; /* no need to duplicate */
-
-       /* Does it have any Signed-off-by: in the text */
-       for (cp = sb.buf;
-            cp && *cp && (cp = strstr(cp, sign_off_header)) != NULL;
-            cp = strchr(cp, '\n')) {
-               if (sb.buf == cp || cp[-1] == '\n')
-                       break;
-       }
-
-       strbuf_addstr(&sb, mine.buf + !!cp);
-exit:
-       strbuf_release(&mine);
+       append_signoff(&sb, 0, 0);
        state->msg = strbuf_detach(&sb, &state->msg_len);
 }
 
@@ -1432,7 +1420,7 @@ static void write_index_patch(const struct am_state *state)
        struct rev_info rev_info;
        FILE *fp;
 
-       if (!get_sha1_tree("HEAD", head.hash))
+       if (!get_oid_tree("HEAD", &head))
                tree = lookup_tree(&head);
        else
                tree = lookup_tree(&empty_tree_oid);
@@ -1661,7 +1649,7 @@ static void do_commit(const struct am_state *state)
        if (write_cache_as_tree(tree.hash, 0, NULL))
                die(_("git write-tree failed to write a tree"));
 
-       if (!get_sha1_commit("HEAD", parent.hash)) {
+       if (!get_oid_commit("HEAD", &parent)) {
                old_oid = &parent;
                commit_list_insert(lookup_commit(&parent), &parents);
        } else {
index 8a0595e..16d391b 100644 (file)
@@ -92,7 +92,7 @@ static int git_branch_config(const char *var, const char *value, void *cb)
                        return config_error_nonbool(var);
                return color_parse(value, branch_colors[slot]);
        }
-       return git_color_default_config(var, value, cb);
+       return git_default_config(var, value, cb);
 }
 
 static const char *branch_get_color(enum color_branch ix)
@@ -383,7 +383,7 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r
        return strbuf_detach(&fmt, NULL);
 }
 
-static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sorting, const char *format)
+static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sorting, struct ref_format *format)
 {
        int i;
        struct ref_array array;
@@ -407,14 +407,17 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin
        if (filter->verbose)
                maxwidth = calc_maxwidth(&array, strlen(remote_prefix));
 
-       if (!format)
-               format = to_free = build_format(filter, maxwidth, remote_prefix);
-       verify_ref_format(format);
+       if (!format->format)
+               format->format = to_free = build_format(filter, maxwidth, remote_prefix);
+       format->use_color = branch_use_color;
+
+       if (verify_ref_format(format))
+               die(_("unable to parse format string"));
 
        ref_array_sort(sorting, &array);
 
        for (i = 0; i < array.nr; i++) {
-               format_ref_array_item(array.items[i], format, 0, &out);
+               format_ref_array_item(array.items[i], format, &out);
                if (column_active(colopts)) {
                        assert(!filter->verbose && "--column and --verbose are incompatible");
                         /* format to a string_list to let print_columns() do its job */
@@ -549,7 +552,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
        struct ref_filter filter;
        int icase = 0;
        static struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;
-       const char *format = NULL;
+       struct ref_format format = REF_FORMAT_INIT;
 
        struct option options[] = {
                OPT_GROUP(N_("Generic options")),
@@ -593,7 +596,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                        N_("print only branches of the object"), 0, parse_opt_object_name
                },
                OPT_BOOL('i', "ignore-case", &icase, N_("sorting and filtering are case insensitive")),
-               OPT_STRING(  0 , "format", &format, N_("format"), N_("format to use for the output")),
+               OPT_STRING(  0 , "format", &format.format, N_("format"), N_("format to use for the output")),
                OPT_END(),
        };
 
@@ -667,7 +670,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                if (!sorting)
                        sorting = ref_default_sorting();
                sorting->ignore_case = icase;
-               print_ref_list(&filter, sorting, format);
+               print_ref_list(&filter, sorting, &format);
                print_columns(&output, colopts, NULL);
                string_list_clear(&output, 0);
                return 0;
index 96b786e..62c8cf0 100644 (file)
@@ -63,8 +63,8 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
        if (unknown_type)
                flags |= OBJECT_INFO_ALLOW_UNKNOWN_TYPE;
 
-       if (get_sha1_with_context(obj_name, GET_SHA1_RECORD_PATH,
-                                 oid.hash, &obj_context))
+       if (get_oid_with_context(obj_name, GET_OID_RECORD_PATH,
+                                &oid, &obj_context))
                die("Not a valid object name %s", obj_name);
 
        if (!path)
@@ -361,10 +361,10 @@ static void batch_one_object(const char *obj_name, struct batch_options *opt,
                             struct expand_data *data)
 {
        struct object_context ctx;
-       int flags = opt->follow_symlinks ? GET_SHA1_FOLLOW_SYMLINKS : 0;
+       int flags = opt->follow_symlinks ? GET_OID_FOLLOW_SYMLINKS : 0;
        enum follow_symlinks_result result;
 
-       result = get_sha1_with_context(obj_name, flags, data->oid.hash, &ctx);
+       result = get_oid_with_context(obj_name, flags, &data->oid, &ctx);
        if (result != FOUND) {
                switch (result) {
                case MISSING_OBJECT:
index 9661e1b..2d75ac6 100644 (file)
@@ -358,6 +358,8 @@ static int checkout_paths(const struct checkout_opts *opts,
        state.force = 1;
        state.refresh_cache = 1;
        state.istate = &the_index;
+
+       enable_delayed_checkout(&state);
        for (pos = 0; pos < active_nr; pos++) {
                struct cache_entry *ce = active_cache[pos];
                if (ce->ce_flags & CE_MATCHED) {
@@ -372,6 +374,7 @@ static int checkout_paths(const struct checkout_opts *opts,
                        pos = skip_same_name(ce, pos) - 1;
                }
        }
+       errs |= finish_delayed_checkout(&state);
 
        if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
                die(_("unable to write new index file"));
index 057fc97..21a7a32 100644 (file)
@@ -33,15 +33,6 @@ static const char *msg_skip_git_dir = N_("Skipping repository %s\n");
 static const char *msg_would_skip_git_dir = N_("Would skip repository %s\n");
 static const char *msg_warn_remove_failed = N_("failed to remove %s");
 
-static int clean_use_color = -1;
-static char clean_colors[][COLOR_MAXLEN] = {
-       GIT_COLOR_RESET,
-       GIT_COLOR_NORMAL,       /* PLAIN */
-       GIT_COLOR_BOLD_BLUE,    /* PROMPT */
-       GIT_COLOR_BOLD,         /* HEADER */
-       GIT_COLOR_BOLD_RED,     /* HELP */
-       GIT_COLOR_BOLD_RED,     /* ERROR */
-};
 enum color_clean {
        CLEAN_COLOR_RESET = 0,
        CLEAN_COLOR_PLAIN = 1,
@@ -51,6 +42,16 @@ enum color_clean {
        CLEAN_COLOR_ERROR = 5
 };
 
+static int clean_use_color = -1;
+static char clean_colors[][COLOR_MAXLEN] = {
+       [CLEAN_COLOR_ERROR] = GIT_COLOR_BOLD_RED,
+       [CLEAN_COLOR_HEADER] = GIT_COLOR_BOLD,
+       [CLEAN_COLOR_HELP] = GIT_COLOR_BOLD_RED,
+       [CLEAN_COLOR_PLAIN] = GIT_COLOR_NORMAL,
+       [CLEAN_COLOR_PROMPT] = GIT_COLOR_BOLD_BLUE,
+       [CLEAN_COLOR_RESET] = GIT_COLOR_RESET,
+};
+
 #define MENU_OPTS_SINGLETON            01
 #define MENU_OPTS_IMMEDIATE            02
 #define MENU_OPTS_LIST_ONLY            04
@@ -125,8 +126,7 @@ static int git_clean_config(const char *var, const char *value, void *cb)
                return 0;
        }
 
-       /* inspect the color.ui config variable and others */
-       return git_color_default_config(var, value, cb);
+       return git_default_config(var, value, cb);
 }
 
 static const char *clean_get_color(enum color_clean ix)
index 08b5cc4..f7e17d2 100644 (file)
@@ -768,6 +768,9 @@ static int checkout(int submodule_progress)
                if (submodule_progress)
                        argv_array_push(&args, "--progress");
 
+               if (option_verbosity < 0)
+                       argv_array_push(&args, "--quiet");
+
                err = run_command_v_opt(args.argv, RUN_GIT_CMD);
                argv_array_clear(&args);
        }
index a4a923d..19e898f 100644 (file)
@@ -56,7 +56,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
                        struct object_id oid;
                        if (argc <= ++i)
                                usage(commit_tree_usage);
-                       if (get_sha1_commit(argv[i], oid.hash))
+                       if (get_oid_commit(argv[i], &oid))
                                die("Not a valid object name %s", argv[i]);
                        assert_sha1_type(oid.hash, OBJ_COMMIT);
                        new_parent(lookup_commit(&oid), &parents);
@@ -106,7 +106,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
                        continue;
                }
 
-               if (get_sha1_tree(arg, tree_oid.hash))
+               if (get_oid_tree(arg, &tree_oid))
                        die("Not a valid object name %s", arg);
                if (got_tree)
                        die("Cannot give more than one trees");
index 8e93802..e7a2cb6 100644 (file)
@@ -510,7 +510,7 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int
        s->index_file = index_file;
        s->fp = fp;
        s->nowarn = nowarn;
-       s->is_initial = get_sha1(s->reference, oid.hash) ? 1 : 0;
+       s->is_initial = get_oid(s->reference, &oid) ? 1 : 0;
        if (!s->is_initial)
                hashcpy(s->sha1_commit, oid.hash);
        s->status_format = status_format;
@@ -891,7 +891,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
                if (amend)
                        parent = "HEAD^1";
 
-               if (get_sha1(parent, oid.hash)) {
+               if (get_oid(parent, &oid)) {
                        int i, ita_nr = 0;
 
                        for (i = 0; i < active_nr; i++)
@@ -1387,7 +1387,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
 
        fd = hold_locked_index(&index_lock, 0);
 
-       s.is_initial = get_sha1(s.reference, oid.hash) ? 1 : 0;
+       s.is_initial = get_oid(s.reference, &oid) ? 1 : 0;
        if (!s.is_initial)
                hashcpy(s.sha1_commit, oid.hash);
 
@@ -1657,7 +1657,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
        status_format = STATUS_FORMAT_NONE; /* Ignore status.short */
        s.colopts = 0;
 
-       if (get_sha1("HEAD", oid.hash))
+       if (get_oid("HEAD", &oid))
                current_head = NULL;
        else {
                current_head = lookup_commit_or_die(&oid, "HEAD");
@@ -1739,17 +1739,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)
                strbuf_setlen(&sb, wt_status_locate_end(sb.buf, sb.len));
-
        if (cleanup_mode != CLEANUP_NONE)
                strbuf_stripspace(&sb, cleanup_mode == CLEANUP_ALL);
-       if (template_untouched(&sb) && !allow_empty_message) {
+
+       if (message_is_empty(&sb) && !allow_empty_message) {
                rollback_index_files();
-               fprintf(stderr, _("Aborting commit; you did not edit the message.\n"));
+               fprintf(stderr, _("Aborting commit due to empty commit message.\n"));
                exit(1);
        }
-       if (message_is_empty(&sb) && !allow_empty_message) {
+       if (template_untouched(&sb) && !allow_empty_message) {
                rollback_index_files();
-               fprintf(stderr, _("Aborting commit due to empty commit message.\n"));
+               fprintf(stderr, _("Aborting commit; you did not edit the message.\n"));
                exit(1);
        }
 
index 89ea1cd..9c13c68 100644 (file)
@@ -55,10 +55,13 @@ static const char *prio_names[] = {
 };
 
 static int commit_name_cmp(const void *unused_cmp_data,
-                          const struct commit_name *cn1,
-                          const struct commit_name *cn2,
+                          const void *entry,
+                          const void *entry_or_key,
                           const void *peeled)
 {
+       const struct commit_name *cn1 = entry;
+       const struct commit_name *cn2 = entry_or_key;
+
        return oidcmp(&cn1->peeled, peeled ? peeled : &cn2->peeled);
 }
 
@@ -503,7 +506,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
                return cmd_name_rev(args.argc, args.argv, prefix);
        }
 
-       hashmap_init(&names, (hashmap_cmp_fn) commit_name_cmp, NULL, 0);
+       hashmap_init(&names, commit_name_cmp, NULL, 0);
        for_each_rawref(get_name, NULL);
        if (!names.size && !always)
                die(_("No names found, cannot describe anything."));
index a1a26ba..8864d84 100644 (file)
@@ -131,10 +131,12 @@ struct working_tree_entry {
 };
 
 static int working_tree_entry_cmp(const void *unused_cmp_data,
-                                 struct working_tree_entry *a,
-                                 struct working_tree_entry *b,
-                                 void *unused_keydata)
+                                 const void *entry,
+                                 const void *entry_or_key,
+                                 const void *unused_keydata)
 {
+       const struct working_tree_entry *a = entry;
+       const struct working_tree_entry *b = entry_or_key;
        return strcmp(a->path, b->path);
 }
 
@@ -149,9 +151,13 @@ struct pair_entry {
 };
 
 static int pair_cmp(const void *unused_cmp_data,
-                   struct pair_entry *a, struct pair_entry *b,
-                   void *unused_keydata)
+                   const void *entry,
+                   const void *entry_or_key,
+                   const void *unused_keydata)
 {
+       const struct pair_entry *a = entry;
+       const struct pair_entry *b = entry_or_key;
+
        return strcmp(a->path, b->path);
 }
 
@@ -179,9 +185,13 @@ struct path_entry {
 };
 
 static int path_entry_cmp(const void *unused_cmp_data,
-                         struct path_entry *a, struct path_entry *b,
-                         void *key)
+                         const void *entry,
+                         const void *entry_or_key,
+                         const void *key)
 {
+       const struct path_entry *a = entry;
+       const struct path_entry *b = entry_or_key;
+
        return strcmp(a->path, key ? key : b->path);
 }
 
@@ -372,10 +382,9 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
        rdir_len = rdir.len;
        wtdir_len = wtdir.len;
 
-       hashmap_init(&working_tree_dups,
-                    (hashmap_cmp_fn)working_tree_entry_cmp, NULL, 0);
-       hashmap_init(&submodules, (hashmap_cmp_fn)pair_cmp, NULL, 0);
-       hashmap_init(&symlinks2, (hashmap_cmp_fn)pair_cmp, NULL, 0);
+       hashmap_init(&working_tree_dups, working_tree_entry_cmp, NULL, 0);
+       hashmap_init(&submodules, pair_cmp, NULL, 0);
+       hashmap_init(&symlinks2, pair_cmp, NULL, 0);
 
        child.no_stdin = 1;
        child.git_cmd = 1;
@@ -585,10 +594,8 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
         * in the common case of --symlinks and the difftool updating
         * files through the symlink.
         */
-       hashmap_init(&wt_modified, (hashmap_cmp_fn)path_entry_cmp,
-                    NULL, wtindex.cache_nr);
-       hashmap_init(&tmp_modified, (hashmap_cmp_fn)path_entry_cmp,
-                    NULL, wtindex.cache_nr);
+       hashmap_init(&wt_modified, path_entry_cmp, NULL, wtindex.cache_nr);
+       hashmap_init(&tmp_modified, path_entry_cmp, NULL, wtindex.cache_nr);
 
        for (i = 0; i < wtindex.cache_nr; i++) {
                struct hashmap_entry dummy;
index c87e59f..d84c263 100644 (file)
@@ -39,7 +39,7 @@ static int prune = -1; /* unspecified */
 static int all, append, dry_run, force, keep, multiple, update_head_ok, verbosity, deepen_relative;
 static int progress = -1;
 static int tags = TAGS_DEFAULT, unshallow, update_shallow, deepen;
-static int max_children = -1;
+static int max_children = 1;
 static enum transport_family family;
 static const char *depth;
 static const char *deepen_since;
@@ -68,9 +68,30 @@ static int git_fetch_config(const char *k, const char *v, void *cb)
                recurse_submodules = r;
        }
 
+       if (!strcmp(k, "submodule.fetchjobs")) {
+               max_children = parse_submodule_fetchjobs(k, v);
+               return 0;
+       } else if (!strcmp(k, "fetch.recursesubmodules")) {
+               recurse_submodules = parse_fetch_recurse_submodules_arg(k, v);
+               return 0;
+       }
+
        return git_default_config(k, v, cb);
 }
 
+static int gitmodules_fetch_config(const char *var, const char *value, void *cb)
+{
+       if (!strcmp(var, "submodule.fetchjobs")) {
+               max_children = parse_submodule_fetchjobs(var, value);
+               return 0;
+       } else if (!strcmp(var, "fetch.recursesubmodules")) {
+               recurse_submodules = parse_fetch_recurse_submodules_arg(var, value);
+               return 0;
+       }
+
+       return 0;
+}
+
 static int parse_refmap_arg(const struct option *opt, const char *arg, int unset)
 {
        ALLOC_GROW(refmap_array, refmap_nr + 1, refmap_alloc);
@@ -1311,6 +1332,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
        for (i = 1; i < argc; i++)
                strbuf_addf(&default_rla, " %s", argv[i]);
 
+       config_from_gitmodules(gitmodules_fetch_config, NULL);
        git_config(git_fetch_config, NULL);
 
        argc = parse_options(argc, argv, prefix,
@@ -1339,7 +1361,6 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
                deepen = 1;
 
        if (recurse_submodules != RECURSE_SUBMODULES_OFF) {
-               set_config_fetch_recurse_submodules(recurse_submodules_default);
                gitmodules_config();
                git_config(submodule_config, NULL);
        }
@@ -1383,6 +1404,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
                result = fetch_populated_submodules(&options,
                                                    submodule_prefix,
                                                    recurse_submodules,
+                                                   recurse_submodules_default,
                                                    verbosity < 0,
                                                    max_children);
                argv_array_clear(&options);
index 10cbb43..e99b5dd 100644 (file)
@@ -408,7 +408,8 @@ static void shortlog(const char *name,
 }
 
 static void fmt_merge_msg_title(struct strbuf *out,
-       const char *current_branch) {
+                               const char *current_branch)
+{
        int i = 0;
        char *sep = "";
 
index 52be99c..5d7c921 100644 (file)
@@ -17,25 +17,25 @@ static char const * const for_each_ref_usage[] = {
 int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
 {
        int i;
-       const char *format = "%(objectname) %(objecttype)\t%(refname)";
        struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;
-       int maxcount = 0, quote_style = 0, icase = 0;
+       int maxcount = 0, icase = 0;
        struct ref_array array;
        struct ref_filter filter;
+       struct ref_format format = REF_FORMAT_INIT;
 
        struct option opts[] = {
-               OPT_BIT('s', "shell", &quote_style,
+               OPT_BIT('s', "shell", &format.quote_style,
                        N_("quote placeholders suitably for shells"), QUOTE_SHELL),
-               OPT_BIT('p', "perl",  &quote_style,
+               OPT_BIT('p', "perl",  &format.quote_style,
                        N_("quote placeholders suitably for perl"), QUOTE_PERL),
-               OPT_BIT(0 , "python", &quote_style,
+               OPT_BIT(0 , "python", &format.quote_style,
                        N_("quote placeholders suitably for python"), QUOTE_PYTHON),
-               OPT_BIT(0 , "tcl",  &quote_style,
+               OPT_BIT(0 , "tcl",  &format.quote_style,
                        N_("quote placeholders suitably for Tcl"), QUOTE_TCL),
 
                OPT_GROUP(""),
                OPT_INTEGER( 0 , "count", &maxcount, N_("show only <n> matched refs")),
-               OPT_STRING(  0 , "format", &format, N_("format"), N_("format to use for the output")),
+               OPT_STRING(  0 , "format", &format.format, N_("format"), N_("format to use for the output")),
                OPT_CALLBACK(0 , "sort", sorting_tail, N_("key"),
                            N_("field name to sort on"), &parse_opt_ref_sorting),
                OPT_CALLBACK(0, "points-at", &filter.points_at,
@@ -52,16 +52,20 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
        memset(&array, 0, sizeof(array));
        memset(&filter, 0, sizeof(filter));
 
+       format.format = "%(objectname) %(objecttype)\t%(refname)";
+
+       git_config(git_default_config, NULL);
+
        parse_options(argc, argv, prefix, opts, for_each_ref_usage, 0);
        if (maxcount < 0) {
                error("invalid --count argument: `%d'", maxcount);
                usage_with_options(for_each_ref_usage, opts);
        }
-       if (HAS_MULTI_BITS(quote_style)) {
+       if (HAS_MULTI_BITS(format.quote_style)) {
                error("more than one quoting style?");
                usage_with_options(for_each_ref_usage, opts);
        }
-       if (verify_ref_format(format))
+       if (verify_ref_format(&format))
                usage_with_options(for_each_ref_usage, opts);
 
        if (!sorting)
@@ -69,9 +73,6 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
        sorting->ignore_case = icase;
        filter.ignore_case = icase;
 
-       /* for warn_ambiguous_refs */
-       git_config(git_default_config, NULL);
-
        filter.name_patterns = argv;
        filter.match_as_path = 1;
        filter_refs(&array, &filter, FILTER_REFS_ALL | FILTER_REFS_INCLUDE_BROKEN);
@@ -80,7 +81,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
        if (!maxcount || array.nr < maxcount)
                maxcount = array.nr;
        for (i = 0; i < maxcount; i++)
-               show_ref_array_item(array.items[i], format, quote_style);
+               show_ref_array_item(array.items[i], &format);
        ref_array_clear(&array);
        return 0;
 }
index 99dea7a..b0964a8 100644 (file)
@@ -19,6 +19,8 @@
 #define REACHABLE 0x0001
 #define SEEN      0x0002
 #define HAS_OBJ   0x0004
+/* This flag is set if something points to this object. */
+#define USED      0x0008
 
 static int show_root;
 static int show_tags;
@@ -168,18 +170,7 @@ static void mark_object_reachable(struct object *obj)
 
 static int traverse_one_object(struct object *obj)
 {
-       int result;
-       struct tree *tree = NULL;
-
-       if (obj->type == OBJ_TREE) {
-               tree = (struct tree *)obj;
-               if (parse_tree(tree) < 0)
-                       return 1; /* error already displayed */
-       }
-       result = fsck_walk(obj, obj, &fsck_walk_options);
-       if (tree)
-               free_tree_buffer(tree);
-       return result;
+       return fsck_walk(obj, obj, &fsck_walk_options);
 }
 
 static int traverse_reachable(void)
@@ -206,7 +197,7 @@ static int mark_used(struct object *obj, int type, void *data, struct fsck_optio
 {
        if (!obj)
                return 1;
-       obj->used = 1;
+       obj->flags |= USED;
        return 0;
 }
 
@@ -255,7 +246,7 @@ static void check_unreachable_object(struct object *obj)
        }
 
        /*
-        * "!used" means that nothing at all points to it, including
+        * "!USED" means that nothing at all points to it, including
         * other unreachable objects. In other words, it's the "tip"
         * of some set of unreachable objects, usually a commit that
         * got dropped.
@@ -266,7 +257,7 @@ static void check_unreachable_object(struct object *obj)
         * deleted a branch by mistake, this is a prime candidate to
         * start looking at, for example.
         */
-       if (!obj->used) {
+       if (!(obj->flags & USED)) {
                if (show_dangling)
                        printf("dangling %s %s\n", printable_type(obj),
                               describe_object(obj));
@@ -335,6 +326,8 @@ static void check_connectivity(void)
 
 static int fsck_obj(struct object *obj)
 {
+       int err;
+
        if (obj->flags & SEEN)
                return 0;
        obj->flags |= SEEN;
@@ -345,20 +338,13 @@ static int fsck_obj(struct object *obj)
 
        if (fsck_walk(obj, NULL, &fsck_obj_options))
                objerror(obj, "broken links");
-       if (fsck_object(obj, NULL, 0, &fsck_obj_options))
-               return -1;
-
-       if (obj->type == OBJ_TREE) {
-               struct tree *item = (struct tree *) obj;
-
-               free_tree_buffer(item);
-       }
+       err = fsck_object(obj, NULL, 0, &fsck_obj_options);
+       if (err)
+               goto out;
 
        if (obj->type == OBJ_COMMIT) {
                struct commit *commit = (struct commit *) obj;
 
-               free_commit_buffer(commit);
-
                if (!commit->parents && show_root)
                        printf("root %s\n", describe_object(&commit->object));
        }
@@ -374,7 +360,12 @@ static int fsck_obj(struct object *obj)
                }
        }
 
-       return 0;
+out:
+       if (obj->type == OBJ_TREE)
+               free_tree_buffer((struct tree *)obj);
+       if (obj->type == OBJ_COMMIT)
+               free_commit_buffer((struct commit *)obj);
+       return err;
 }
 
 static int fsck_obj_buffer(const struct object_id *oid, enum object_type type,
@@ -390,7 +381,8 @@ static int fsck_obj_buffer(const struct object_id *oid, enum object_type type,
                errors_found |= ERROR_OBJECT;
                return error("%s: object corrupt or missing", oid_to_hex(oid));
        }
-       obj->flags = HAS_OBJ;
+       obj->flags &= ~(REACHABLE | SEEN);
+       obj->flags |= HAS_OBJ;
        return fsck_obj(obj);
 }
 
@@ -408,7 +400,7 @@ static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,
                                add_decoration(fsck_walk_options.object_names,
                                        obj,
                                        xstrfmt("%s@{%"PRItime"}", refname, timestamp));
-                       obj->used = 1;
+                       obj->flags |= USED;
                        mark_object_reachable(obj);
                } else {
                        error("%s: invalid reflog entry %s", refname, oid_to_hex(oid));
@@ -456,7 +448,7 @@ static int fsck_handle_ref(const char *refname, const struct object_id *oid,
                errors_found |= ERROR_REFS;
        }
        default_refs++;
-       obj->used = 1;
+       obj->flags |= USED;
        if (name_objects)
                add_decoration(fsck_walk_options.object_names,
                        obj, xstrdup(refname));
@@ -524,7 +516,8 @@ static int fsck_loose(const struct object_id *oid, const char *path, void *data)
                return 0; /* keep checking other objects */
        }
 
-       obj->flags = HAS_OBJ;
+       obj->flags &= ~(REACHABLE | SEEN);
+       obj->flags |= HAS_OBJ;
        if (fsck_obj(obj))
                errors_found |= ERROR_OBJECT;
        return 0;
@@ -606,7 +599,7 @@ static int fsck_cache_tree(struct cache_tree *it)
                        errors_found |= ERROR_REFS;
                        return 1;
                }
-               obj->used = 1;
+               obj->flags |= USED;
                if (name_objects)
                        add_decoration(fsck_walk_options.object_names,
                                obj, xstrdup(":"));
@@ -667,7 +660,7 @@ static struct option fsck_opts[] = {
 
 int cmd_fsck(int argc, const char **argv, const char *prefix)
 {
-       int i, heads;
+       int i;
        struct alternate_object_database *alt;
 
        errors_found = 0;
@@ -735,25 +728,23 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
                }
        }
 
-       heads = 0;
        for (i = 0; i < argc; i++) {
                const char *arg = argv[i];
-               unsigned char sha1[20];
-               if (!get_sha1(arg, sha1)) {
-                       struct object *obj = lookup_object(sha1);
+               struct object_id oid;
+               if (!get_oid(arg, &oid)) {
+                       struct object *obj = lookup_object(oid.hash);
 
                        if (!obj || !(obj->flags & HAS_OBJ)) {
-                               error("%s: object missing", sha1_to_hex(sha1));
+                               error("%s: object missing", oid_to_hex(&oid));
                                errors_found |= ERROR_OBJECT;
                                continue;
                        }
 
-                       obj->used = 1;
+                       obj->flags |= USED;
                        if (name_objects)
                                add_decoration(fsck_walk_options.object_names,
                                        obj, xstrdup(arg));
                        mark_object_reachable(obj);
-                       heads++;
                        continue;
                }
                error("invalid parameter: expected sha1, got '%s'", arg);
@@ -785,7 +776,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
                        if (!blob)
                                continue;
                        obj = &blob->object;
-                       obj->used = 1;
+                       obj->flags |= USED;
                        if (name_objects)
                                add_decoration(fsck_walk_options.object_names,
                                        obj,
index 7e79eb1..a70d8e2 100644 (file)
@@ -28,13 +28,7 @@ static char const * const grep_usage[] = {
        NULL
 };
 
-static const char *super_prefix;
 static int recurse_submodules;
-static struct argv_array submodule_options = ARGV_ARRAY_INIT;
-static const char *parent_basename;
-
-static int grep_submodule_launch(struct grep_opt *opt,
-                                const struct grep_source *gs);
 
 #define GREP_NUM_THREADS_DEFAULT 8
 static int num_threads;
@@ -186,10 +180,7 @@ static void *run(void *arg)
                        break;
 
                opt->output_priv = w;
-               if (w->source.type == GREP_SOURCE_SUBMODULE)
-                       hit |= grep_submodule_launch(opt, &w->source);
-               else
-                       hit |= grep_source(opt, &w->source);
+               hit |= grep_source(opt, &w->source);
                grep_source_clear_data(&w->source);
                work_done(w);
        }
@@ -284,7 +275,7 @@ static int wait_all(void)
 static int grep_cmd_config(const char *var, const char *value, void *cb)
 {
        int st = grep_config(var, value, cb);
-       if (git_color_default_config(var, value, cb) < 0)
+       if (git_default_config(var, value, cb) < 0)
                st = -1;
 
        if (!strcmp(var, "grep.threads")) {
@@ -327,21 +318,13 @@ static int grep_oid(struct grep_opt *opt, const struct object_id *oid,
 {
        struct strbuf pathbuf = STRBUF_INIT;
 
-       if (super_prefix) {
-               strbuf_add(&pathbuf, filename, tree_name_len);
-               strbuf_addstr(&pathbuf, super_prefix);
-               strbuf_addstr(&pathbuf, filename + tree_name_len);
+       if (opt->relative && opt->prefix_length) {
+               quote_path_relative(filename + tree_name_len, opt->prefix, &pathbuf);
+               strbuf_insert(&pathbuf, 0, filename, tree_name_len);
        } else {
                strbuf_addstr(&pathbuf, filename);
        }
 
-       if (opt->relative && opt->prefix_length) {
-               char *name = strbuf_detach(&pathbuf, NULL);
-               quote_path_relative(name + tree_name_len, opt->prefix, &pathbuf);
-               strbuf_insert(&pathbuf, 0, name, tree_name_len);
-               free(name);
-       }
-
 #ifndef NO_PTHREADS
        if (num_threads) {
                add_work(opt, GREP_SOURCE_OID, pathbuf.buf, path, oid);
@@ -366,15 +349,10 @@ static int grep_file(struct grep_opt *opt, const char *filename)
 {
        struct strbuf buf = STRBUF_INIT;
 
-       if (super_prefix)
-               strbuf_addstr(&buf, super_prefix);
-       strbuf_addstr(&buf, filename);
-
-       if (opt->relative && opt->prefix_length) {
-               char *name = strbuf_detach(&buf, NULL);
-               quote_path_relative(name, opt->prefix, &buf);
-               free(name);
-       }
+       if (opt->relative && opt->prefix_length)
+               quote_path_relative(filename, opt->prefix, &buf);
+       else
+               strbuf_addstr(&buf, filename);
 
 #ifndef NO_PTHREADS
        if (num_threads) {
@@ -421,284 +399,89 @@ static void run_pager(struct grep_opt *opt, const char *prefix)
                exit(status);
 }
 
-static void compile_submodule_options(const struct grep_opt *opt,
-                                     const char **argv,
-                                     int cached, int untracked,
-                                     int opt_exclude, int use_index,
-                                     int pattern_type_arg)
-{
-       struct grep_pat *pattern;
-
-       if (recurse_submodules)
-               argv_array_push(&submodule_options, "--recurse-submodules");
-
-       if (cached)
-               argv_array_push(&submodule_options, "--cached");
-       if (!use_index)
-               argv_array_push(&submodule_options, "--no-index");
-       if (untracked)
-               argv_array_push(&submodule_options, "--untracked");
-       if (opt_exclude > 0)
-               argv_array_push(&submodule_options, "--exclude-standard");
-
-       if (opt->invert)
-               argv_array_push(&submodule_options, "-v");
-       if (opt->ignore_case)
-               argv_array_push(&submodule_options, "-i");
-       if (opt->word_regexp)
-               argv_array_push(&submodule_options, "-w");
-       switch (opt->binary) {
-       case GREP_BINARY_NOMATCH:
-               argv_array_push(&submodule_options, "-I");
-               break;
-       case GREP_BINARY_TEXT:
-               argv_array_push(&submodule_options, "-a");
-               break;
-       default:
-               break;
-       }
-       if (opt->allow_textconv)
-               argv_array_push(&submodule_options, "--textconv");
-       if (opt->max_depth != -1)
-               argv_array_pushf(&submodule_options, "--max-depth=%d",
-                                opt->max_depth);
-       if (opt->linenum)
-               argv_array_push(&submodule_options, "-n");
-       if (!opt->pathname)
-               argv_array_push(&submodule_options, "-h");
-       if (!opt->relative)
-               argv_array_push(&submodule_options, "--full-name");
-       if (opt->name_only)
-               argv_array_push(&submodule_options, "-l");
-       if (opt->unmatch_name_only)
-               argv_array_push(&submodule_options, "-L");
-       if (opt->null_following_name)
-               argv_array_push(&submodule_options, "-z");
-       if (opt->count)
-               argv_array_push(&submodule_options, "-c");
-       if (opt->file_break)
-               argv_array_push(&submodule_options, "--break");
-       if (opt->heading)
-               argv_array_push(&submodule_options, "--heading");
-       if (opt->pre_context)
-               argv_array_pushf(&submodule_options, "--before-context=%d",
-                                opt->pre_context);
-       if (opt->post_context)
-               argv_array_pushf(&submodule_options, "--after-context=%d",
-                                opt->post_context);
-       if (opt->funcname)
-               argv_array_push(&submodule_options, "-p");
-       if (opt->funcbody)
-               argv_array_push(&submodule_options, "-W");
-       if (opt->all_match)
-               argv_array_push(&submodule_options, "--all-match");
-       if (opt->debug)
-               argv_array_push(&submodule_options, "--debug");
-       if (opt->status_only)
-               argv_array_push(&submodule_options, "-q");
-
-       switch (pattern_type_arg) {
-       case GREP_PATTERN_TYPE_BRE:
-               argv_array_push(&submodule_options, "-G");
-               break;
-       case GREP_PATTERN_TYPE_ERE:
-               argv_array_push(&submodule_options, "-E");
-               break;
-       case GREP_PATTERN_TYPE_FIXED:
-               argv_array_push(&submodule_options, "-F");
-               break;
-       case GREP_PATTERN_TYPE_PCRE:
-               argv_array_push(&submodule_options, "-P");
-               break;
-       case GREP_PATTERN_TYPE_UNSPECIFIED:
-               break;
-       default:
-               die("BUG: Added a new grep pattern type without updating switch statement");
-       }
-
-       for (pattern = opt->pattern_list; pattern != NULL;
-            pattern = pattern->next) {
-               switch (pattern->token) {
-               case GREP_PATTERN:
-                       argv_array_pushf(&submodule_options, "-e%s",
-                                        pattern->pattern);
-                       break;
-               case GREP_AND:
-               case GREP_OPEN_PAREN:
-               case GREP_CLOSE_PAREN:
-               case GREP_NOT:
-               case GREP_OR:
-                       argv_array_push(&submodule_options, pattern->pattern);
-                       break;
-               /* BODY and HEAD are not used by git-grep */
-               case GREP_PATTERN_BODY:
-               case GREP_PATTERN_HEAD:
-                       break;
-               }
-       }
-
-       /*
-        * Limit number of threads for child process to use.
-        * This is to prevent potential fork-bomb behavior of git-grep as each
-        * submodule process has its own thread pool.
-        */
-       argv_array_pushf(&submodule_options, "--threads=%d",
-                        DIV_ROUND_UP(num_threads, 2));
-
-       /* Add Pathspecs */
-       argv_array_push(&submodule_options, "--");
-       for (; *argv; argv++)
-               argv_array_push(&submodule_options, *argv);
-}
+static int grep_cache(struct grep_opt *opt, struct repository *repo,
+                     const struct pathspec *pathspec, int cached);
+static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
+                    struct tree_desc *tree, struct strbuf *base, int tn_len,
+                    int check_attr, struct repository *repo);
 
-/*
- * Launch child process to grep contents of a submodule
- */
-static int grep_submodule_launch(struct grep_opt *opt,
-                                const struct grep_source *gs)
+static int grep_submodule(struct grep_opt *opt, struct repository *superproject,
+                         const struct pathspec *pathspec,
+                         const struct object_id *oid,
+                         const char *filename, const char *path)
 {
-       struct child_process cp = CHILD_PROCESS_INIT;
-       int status, i;
-       const char *end_of_base;
-       const char *name;
-       struct strbuf child_output = STRBUF_INIT;
-
-       end_of_base = strchr(gs->name, ':');
-       if (gs->identifier && end_of_base)
-               name = end_of_base + 1;
-       else
-               name = gs->name;
+       struct repository submodule;
+       int hit;
 
-       prepare_submodule_repo_env(&cp.env_array);
-       argv_array_push(&cp.env_array, GIT_DIR_ENVIRONMENT);
+       if (!is_submodule_active(superproject, path))
+               return 0;
 
-       if (opt->relative && opt->prefix_length)
-               argv_array_pushf(&cp.env_array, "%s=%s",
-                                GIT_TOPLEVEL_PREFIX_ENVIRONMENT,
-                                opt->prefix);
+       if (repo_submodule_init(&submodule, superproject, path))
+               return 0;
 
-       /* Add super prefix */
-       argv_array_pushf(&cp.args, "--super-prefix=%s%s/",
-                        super_prefix ? super_prefix : "",
-                        name);
-       argv_array_push(&cp.args, "grep");
+       repo_read_gitmodules(&submodule);
 
        /*
-        * Add basename of parent project
-        * When performing grep on a tree object the filename is prefixed
-        * with the object's name: 'tree-name:filename'.  In order to
-        * provide uniformity of output we want to pass the name of the
-        * parent project's object name to the submodule so the submodule can
-        * prefix its output with the parent's name and not its own OID.
+        * NEEDSWORK: This adds the submodule's object directory to the list of
+        * alternates for the single in-memory object store.  This has some bad
+        * consequences for memory (processed objects will never be freed) and
+        * performance (this increases the number of pack files git has to pay
+        * attention to, to the sum of the number of pack files in all the
+        * repositories processed so far).  This can be removed once the object
+        * store is no longer global and instead is a member of the repository
+        * object.
         */
-       if (gs->identifier && end_of_base)
-               argv_array_pushf(&cp.args, "--parent-basename=%.*s",
-                                (int) (end_of_base - gs->name),
-                                gs->name);
+       add_to_alternates_memory(submodule.objectdir);
 
-       /* Add options */
-       for (i = 0; i < submodule_options.argc; i++) {
-               /*
-                * If there is a tree identifier for the submodule, add the
-                * rev after adding the submodule options but before the
-                * pathspecs.  To do this we listen for the '--' and insert the
-                * oid before pushing the '--' onto the child process argv
-                * array.
-                */
-               if (gs->identifier &&
-                   !strcmp("--", submodule_options.argv[i])) {
-                       argv_array_push(&cp.args, oid_to_hex(gs->identifier));
-               }
+       if (oid) {
+               struct object *object;
+               struct tree_desc tree;
+               void *data;
+               unsigned long size;
+               struct strbuf base = STRBUF_INIT;
 
-               argv_array_push(&cp.args, submodule_options.argv[i]);
-       }
+               object = parse_object_or_die(oid, oid_to_hex(oid));
 
-       cp.git_cmd = 1;
-       cp.dir = gs->path;
+               grep_read_lock();
+               data = read_object_with_reference(object->oid.hash, tree_type,
+                                                 &size, NULL);
+               grep_read_unlock();
 
-       /*
-        * Capture output to output buffer and check the return code from the
-        * child process.  A '0' indicates a hit, a '1' indicates no hit and
-        * anything else is an error.
-        */
-       status = capture_command(&cp, &child_output, 0);
-       if (status && (status != 1)) {
-               /* flush the buffer */
-               write_or_die(1, child_output.buf, child_output.len);
-               die("process for submodule '%s' failed with exit code: %d",
-                   gs->name, status);
-       }
+               if (!data)
+                       die(_("unable to read tree (%s)"), oid_to_hex(&object->oid));
 
-       opt->output(opt, child_output.buf, child_output.len);
-       strbuf_release(&child_output);
-       /* invert the return code to make a hit equal to 1 */
-       return !status;
-}
+               strbuf_addstr(&base, filename);
+               strbuf_addch(&base, '/');
 
-/*
- * Prep grep structures for a submodule grep
- * oid: the oid of the submodule or NULL if using the working tree
- * filename: name of the submodule including tree name of parent
- * path: location of the submodule
- */
-static int grep_submodule(struct grep_opt *opt, const struct object_id *oid,
-                         const char *filename, const char *path)
-{
-       if (!is_submodule_active(the_repository, path))
-               return 0;
-       if (!is_submodule_populated_gently(path, NULL)) {
-               /*
-                * If searching history, check for the presence of the
-                * submodule's gitdir before skipping the submodule.
-                */
-               if (oid) {
-                       const struct submodule *sub =
-                                       submodule_from_path(null_sha1, path);
-                       if (sub)
-                               path = git_path("modules/%s", sub->name);
-
-                       if (!(is_directory(path) && is_git_directory(path)))
-                               return 0;
-               } else {
-                       return 0;
-               }
+               init_tree_desc(&tree, data, size);
+               hit = grep_tree(opt, pathspec, &tree, &base, base.len,
+                               object->type == OBJ_COMMIT, &submodule);
+               strbuf_release(&base);
+               free(data);
+       } else {
+               hit = grep_cache(opt, &submodule, pathspec, 1);
        }
 
-#ifndef NO_PTHREADS
-       if (num_threads) {
-               add_work(opt, GREP_SOURCE_SUBMODULE, filename, path, oid);
-               return 0;
-       } else
-#endif
-       {
-               struct grep_source gs;
-               int hit;
-
-               grep_source_init(&gs, GREP_SOURCE_SUBMODULE,
-                                filename, path, oid);
-               hit = grep_submodule_launch(opt, &gs);
-
-               grep_source_clear(&gs);
-               return hit;
-       }
+       repo_clear(&submodule);
+       return hit;
 }
 
-static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec,
-                     int cached)
+static int grep_cache(struct grep_opt *opt, struct repository *repo,
+                     const struct pathspec *pathspec, int cached)
 {
        int hit = 0;
        int nr;
        struct strbuf name = STRBUF_INIT;
        int name_base_len = 0;
-       if (super_prefix) {
-               name_base_len = strlen(super_prefix);
-               strbuf_addstr(&name, super_prefix);
+       if (repo->submodule_prefix) {
+               name_base_len = strlen(repo->submodule_prefix);
+               strbuf_addstr(&name, repo->submodule_prefix);
        }
 
-       read_cache();
+       repo_read_index(repo);
 
-       for (nr = 0; nr < active_nr; nr++) {
-               const struct cache_entry *ce = active_cache[nr];
+       for (nr = 0; nr < repo->index->cache_nr; nr++) {
+               const struct cache_entry *ce = repo->index->cache[nr];
                strbuf_setlen(&name, name_base_len);
                strbuf_addstr(&name, ce->name);
 
@@ -715,14 +498,14 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec,
                            ce_skip_worktree(ce)) {
                                if (ce_stage(ce) || ce_intent_to_add(ce))
                                        continue;
-                               hit |= grep_oid(opt, &ce->oid, ce->name,
-                                                0, ce->name);
+                               hit |= grep_oid(opt, &ce->oid, name.buf,
+                                                0, name.buf);
                        } else {
-                               hit |= grep_file(opt, ce->name);
+                               hit |= grep_file(opt, name.buf);
                        }
                } else if (recurse_submodules && S_ISGITLINK(ce->ce_mode) &&
                           submodule_path_match(pathspec, name.buf, NULL)) {
-                       hit |= grep_submodule(opt, NULL, ce->name, ce->name);
+                       hit |= grep_submodule(opt, repo, pathspec, NULL, ce->name, ce->name);
                } else {
                        continue;
                }
@@ -730,8 +513,8 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec,
                if (ce_stage(ce)) {
                        do {
                                nr++;
-                       } while (nr < active_nr &&
-                                !strcmp(ce->name, active_cache[nr]->name));
+                       } while (nr < repo->index->cache_nr &&
+                                !strcmp(ce->name, repo->index->cache[nr]->name));
                        nr--; /* compensate for loop control */
                }
                if (hit && opt->status_only)
@@ -744,7 +527,7 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec,
 
 static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
                     struct tree_desc *tree, struct strbuf *base, int tn_len,
-                    int check_attr)
+                    int check_attr, struct repository *repo)
 {
        int hit = 0;
        enum interesting match = entry_not_interesting;
@@ -752,8 +535,8 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
        int old_baselen = base->len;
        struct strbuf name = STRBUF_INIT;
        int name_base_len = 0;
-       if (super_prefix) {
-               strbuf_addstr(&name, super_prefix);
+       if (repo->submodule_prefix) {
+               strbuf_addstr(&name, repo->submodule_prefix);
                name_base_len = name.len;
        }
 
@@ -791,11 +574,11 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
                        strbuf_addch(base, '/');
                        init_tree_desc(&sub, data, size);
                        hit |= grep_tree(opt, pathspec, &sub, base, tn_len,
-                                        check_attr);
+                                        check_attr, repo);
                        free(data);
                } else if (recurse_submodules && S_ISGITLINK(entry.mode)) {
-                       hit |= grep_submodule(opt, entry.oid, base->buf,
-                                             base->buf + tn_len);
+                       hit |= grep_submodule(opt, repo, pathspec, entry.oid,
+                                             base->buf, base->buf + tn_len);
                }
 
                strbuf_setlen(base, old_baselen);
@@ -809,7 +592,8 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
 }
 
 static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
-                      struct object *obj, const char *name, const char *path)
+                      struct object *obj, const char *name, const char *path,
+                      struct repository *repo)
 {
        if (obj->type == OBJ_BLOB)
                return grep_oid(opt, &obj->oid, name, 0, path);
@@ -828,10 +612,6 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
                if (!data)
                        die(_("unable to read tree (%s)"), oid_to_hex(&obj->oid));
 
-               /* Use parent's name as base when recursing submodules */
-               if (recurse_submodules && parent_basename)
-                       name = parent_basename;
-
                len = name ? strlen(name) : 0;
                strbuf_init(&base, PATH_MAX + len + 1);
                if (len) {
@@ -840,7 +620,7 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
                }
                init_tree_desc(&tree, data, size);
                hit = grep_tree(opt, pathspec, &tree, &base, base.len,
-                               obj->type == OBJ_COMMIT);
+                               obj->type == OBJ_COMMIT, repo);
                strbuf_release(&base);
                free(data);
                return hit;
@@ -849,6 +629,7 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
 }
 
 static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec,
+                       struct repository *repo,
                        const struct object_array *list)
 {
        unsigned int i;
@@ -862,9 +643,10 @@ static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec,
                /* load the gitmodules file for this rev */
                if (recurse_submodules) {
                        submodule_free();
-                       gitmodules_config_sha1(real_obj->oid.hash);
+                       gitmodules_config_oid(&real_obj->oid);
                }
-               if (grep_object(opt, pathspec, real_obj, list->objects[i].name, list->objects[i].path)) {
+               if (grep_object(opt, pathspec, real_obj, list->objects[i].name, list->objects[i].path,
+                               repo)) {
                        hit = 1;
                        if (opt->status_only)
                                break;
@@ -1005,9 +787,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                            N_("ignore files specified via '.gitignore'"), 1),
                OPT_BOOL(0, "recurse-submodules", &recurse_submodules,
                         N_("recursively search in each submodule")),
-               OPT_STRING(0, "parent-basename", &parent_basename,
-                          N_("basename"),
-                          N_("prepend parent project's basename to output")),
                OPT_GROUP(""),
                OPT_BOOL('v', "invert-match", &opt.invert,
                        N_("show non-matching lines")),
@@ -1112,7 +891,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
        init_grep_defaults();
        git_config(grep_cmd_config, NULL);
        grep_init(&opt, prefix);
-       super_prefix = get_super_prefix();
 
        /*
         * If there is no -- then the paths must exist in the working
@@ -1205,8 +983,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                        break;
                }
 
-               if (get_sha1_with_context(arg, GET_SHA1_RECORD_PATH,
-                                         oid.hash, &oc)) {
+               if (get_oid_with_context(arg, GET_OID_RECORD_PATH,
+                                        &oid, &oc)) {
                        if (seen_dashdash)
                                die(_("unable to resolve revision: %s"), arg);
                        break;
@@ -1272,9 +1050,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 
        if (recurse_submodules) {
                gitmodules_config();
-               compile_submodule_options(&opt, argv + i, cached, untracked,
-                                         opt_exclude, use_index,
-                                         pattern_type_arg);
        }
 
        if (show_in_pager && (cached || list.nr))
@@ -1318,11 +1093,12 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                if (!cached)
                        setup_work_tree();
 
-               hit = grep_cache(&opt, &pathspec, cached);
+               hit = grep_cache(&opt, the_repository, &pathspec, cached);
        } else {
                if (cached)
                        die(_("both --cached and trees are given."));
-               hit = grep_objects(&opt, &pathspec, &list);
+
+               hit = grep_objects(&opt, &pathspec, the_repository, &list);
        }
 
        if (num_threads)
index c6362cf..25c8241 100644 (file)
@@ -58,9 +58,9 @@ static int auto_decoration_style(void)
        return (isatty(1) || pager_in_use()) ? DECORATE_SHORT_REFS : 0;
 }
 
-static int parse_decoration_style(const char *var, const char *value)
+static int parse_decoration_style(const char *value)
 {
-       switch (git_config_maybe_bool(var, value)) {
+       switch (git_parse_maybe_bool(value)) {
        case 1:
                return DECORATE_SHORT_REFS;
        case 0:
@@ -82,7 +82,7 @@ static int decorate_callback(const struct option *opt, const char *arg, int unse
        if (unset)
                decoration_style = 0;
        else if (arg)
-               decoration_style = parse_decoration_style("command line", arg);
+               decoration_style = parse_decoration_style(arg);
        else
                decoration_style = DECORATE_SHORT_REFS;
 
@@ -372,11 +372,14 @@ static int cmd_log_walk(struct rev_info *rev)
                         */
                        rev->max_count++;
                if (!rev->reflog_info) {
-                       /* we allow cycles in reflog ancestry */
+                       /*
+                        * We may show a given commit multiple times when
+                        * walking the reflogs.
+                        */
                        free_commit_buffer(commit);
+                       free_commit_list(commit->parents);
+                       commit->parents = NULL;
                }
-               free_commit_list(commit->parents);
-               commit->parents = NULL;
                if (saved_nrl < rev->diffopt.needed_rename_limit)
                        saved_nrl = rev->diffopt.needed_rename_limit;
                if (rev->diffopt.degraded_cc_to_c)
@@ -409,7 +412,7 @@ static int git_log_config(const char *var, const char *value, void *cb)
        if (!strcmp(var, "log.date"))
                return git_config_string(&default_date_mode, var, value);
        if (!strcmp(var, "log.decorate")) {
-               decoration_style = parse_decoration_style(var, value);
+               decoration_style = parse_decoration_style(value);
                if (decoration_style < 0)
                        decoration_style = 0; /* maybe warn? */
                return 0;
@@ -484,8 +487,8 @@ static int show_blob_object(const struct object_id *oid, struct rev_info *rev, c
            !DIFF_OPT_TST(&rev->diffopt, ALLOW_TEXTCONV))
                return stream_blob_to_fd(1, oid, NULL, 0);
 
-       if (get_sha1_with_context(obj_name, GET_SHA1_RECORD_PATH,
-                                 oidc.hash, &obj_context))
+       if (get_oid_with_context(obj_name, GET_OID_RECORD_PATH,
+                                &oidc, &obj_context))
                die(_("Not a valid object name %s"), obj_name);
        if (!obj_context.path ||
            !textconv_object(obj_context.path, obj_context.mode, &oidc, 1, &buf, &size)) {
@@ -821,7 +824,7 @@ static int git_format_config(const char *var, const char *value, void *cb)
                return 0;
        }
        if (!strcmp(var, "format.from")) {
-               int b = git_config_maybe_bool(var, value);
+               int b = git_parse_maybe_bool(value);
                free(from);
                if (b < 0)
                        from = xstrdup(value);
index b8514a0..c6126ea 100644 (file)
@@ -362,7 +362,7 @@ static void prune_index(struct index_state *istate,
        int pos;
        unsigned int first, last;
 
-       if (!prefix)
+       if (!prefix || !istate->cache_nr)
                return;
        pos = index_name_pos(istate, prefix, prefixlen);
        if (pos < 0)
@@ -378,8 +378,7 @@ static void prune_index(struct index_state *istate,
                }
                last = next;
        }
-       memmove(istate->cache, istate->cache + pos,
-               (last - pos) * sizeof(struct cache_entry *));
+       MOVE_ARRAY(istate->cache, istate->cache + pos, last - pos);
        istate->cache_nr = last - pos;
 }
 
index bad6735..f12da29 100644 (file)
@@ -347,12 +347,12 @@ static void merge_trees(struct tree_desc t[3], const char *base)
 
 static void *get_tree_descriptor(struct tree_desc *desc, const char *rev)
 {
-       unsigned char sha1[20];
+       struct object_id oid;
        void *buf;
 
-       if (get_sha1(rev, sha1))
+       if (get_oid(rev, &oid))
                die("unknown rev %s", rev);
-       buf = fill_tree_descriptor(desc, sha1);
+       buf = fill_tree_descriptor(desc, oid.hash);
        if (!buf)
                die("%s is not a tree", rev);
        return buf;
index 900bafd..328945d 100644 (file)
@@ -537,7 +537,7 @@ static void parse_branch_merge_options(char *bmo)
                die(_("Bad branch.%s.mergeoptions string: %s"), branch,
                    split_cmdline_strerror(argc));
        REALLOC_ARRAY(argv, argc + 2);
-       memmove(argv + 1, argv, sizeof(*argv) * (argc + 1));
+       MOVE_ARRAY(argv + 1, argv, argc + 1);
        argc++;
        argv[0] = "branch.*.mergeoptions";
        parse_options(argc, argv, NULL, builtin_merge_options,
@@ -566,7 +566,7 @@ static int git_merge_config(const char *k, const char *v, void *cb)
        else if (!strcmp(k, "merge.renormalize"))
                option_renormalize = git_config_bool(k, v);
        else if (!strcmp(k, "merge.ff")) {
-               int boolval = git_config_maybe_bool(k, v);
+               int boolval = git_parse_maybe_bool(v);
                if (0 <= boolval) {
                        fast_forward = boolval ? FF_ALLOW : FF_NO;
                } else if (v && !strcmp(v, "only")) {
@@ -940,7 +940,7 @@ static int default_edit_option(void)
                return 0;
 
        if (e) {
-               int v = git_config_maybe_bool(name, e);
+               int v = git_parse_maybe_bool(e);
                if (v < 0)
                        die(_("Bad value '%s' in environment '%s'"), e, name);
                return v;
@@ -1117,8 +1117,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
         * current branch.
         */
        branch = branch_to_free = resolve_refdup("HEAD", 0, head_oid.hash, NULL);
-       if (branch && starts_with(branch, "refs/heads/"))
-               branch += 11;
+       if (branch)
+               skip_prefix(branch, "refs/heads/", &branch);
        if (!branch || is_null_oid(&head_oid))
                head_commit = NULL;
        else
index dcf6736..94fbaaa 100644 (file)
@@ -81,7 +81,7 @@ static void prepare_move_submodule(const char *src, int first,
        struct strbuf submodule_dotgit = STRBUF_INIT;
        if (!S_ISGITLINK(active_cache[first]->ce_mode))
                die(_("Directory %s is in index and no submodule?"), src);
-       if (!is_staging_gitmodules_ok())
+       if (!is_staging_gitmodules_ok(&the_index))
                die(_("Please stage your changes to .gitmodules or stash them to proceed"));
        strbuf_addf(&submodule_dotgit, "%s/.git", src);
        *submodule_gitfile = read_gitfile(submodule_dotgit.buf);
index 77573cf..4303848 100644 (file)
@@ -456,7 +456,7 @@ static int add(int argc, const char **argv, const char *prefix)
                        oid_to_hex(&object));
        }
 
-       prepare_note_data(&object, &d, note->hash);
+       prepare_note_data(&object, &d, note ? note->hash : NULL);
        if (d.buf.len || allow_empty) {
                write_note_data(&d, new_note.hash);
                if (add_note(t, &object, &new_note, combine_notes_overwrite))
index f4a8441..c753e92 100644 (file)
@@ -1289,7 +1289,7 @@ static int done_pbase_path_pos(unsigned hash)
 
 static int check_pbase_path(unsigned hash)
 {
-       int pos = (!done_pbase_paths) ? -1 : done_pbase_path_pos(hash);
+       int pos = done_pbase_path_pos(hash);
        if (0 <= pos)
                return 1;
        pos = -pos - 1;
@@ -1298,9 +1298,8 @@ static int check_pbase_path(unsigned hash)
                   done_pbase_paths_alloc);
        done_pbase_paths_num++;
        if (pos < done_pbase_paths_num)
-               memmove(done_pbase_paths + pos + 1,
-                       done_pbase_paths + pos,
-                       (done_pbase_paths_num - pos - 1) * sizeof(unsigned));
+               MOVE_ARRAY(done_pbase_paths + pos + 1, done_pbase_paths + pos,
+                          done_pbase_paths_num - pos - 1);
        done_pbase_paths[pos] = hash;
        return 0;
 }
index 9b86e51..7fe2814 100644 (file)
@@ -39,7 +39,7 @@ enum rebase_type {
 static enum rebase_type parse_config_rebase(const char *key, const char *value,
                int fatal)
 {
-       int v = git_config_maybe_bool("pull.rebase", value);
+       int v = git_parse_maybe_bool(value);
 
        if (!v)
                return REBASE_FALSE;
@@ -274,7 +274,7 @@ static const char *config_get_ff(void)
        if (git_config_get_value("pull.ff", &value))
                return NULL;
 
-       switch (git_config_maybe_bool("pull.ff", value)) {
+       switch (git_parse_maybe_bool(value)) {
        case 0:
                return "--no-ff";
        case 1:
index 03846e8..2ac8104 100644 (file)
@@ -481,7 +481,7 @@ static int git_push_config(const char *k, const char *v, void *cb)
        } else if (!strcmp(k, "push.gpgsign")) {
                const char *value;
                if (!git_config_get_value("push.gpgsign", &value)) {
-                       switch (git_config_maybe_bool("push.gpgsign", value)) {
+                       switch (git_parse_maybe_bool(value)) {
                        case 0:
                                set_push_cert_flags(flags, SEND_PACK_PUSH_CERT_NEVER);
                                break;
index cabdc55..14b6e09 100644 (file)
@@ -919,9 +919,9 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
  */
 static int head_has_history(void)
 {
-       unsigned char sha1[20];
+       struct object_id oid;
 
-       return !get_sha1("HEAD", sha1);
+       return !get_oid("HEAD", &oid);
 }
 
 static const char *push_to_deploy(unsigned char *sha1,
@@ -1138,7 +1138,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
                }
                if (ref_transaction_delete(transaction,
                                           namespaced_name,
-                                          old_oid->hash,
+                                          old_oid ? old_oid->hash : NULL,
                                           0, "push", &err)) {
                        rp_error("%s", err.buf);
                        strbuf_release(&err);
index 6273c0c..a995ea8 100644 (file)
@@ -301,7 +301,7 @@ static int config_read_branches(const char *key, const char *value, void *cb)
                        }
                        string_list_append(&info->merge, xstrdup(value));
                } else {
-                       int v = git_config_maybe_bool(orig_key, value);
+                       int v = git_parse_maybe_bool(value);
                        if (v >= 0)
                                info->rebase = v;
                        else if (!strcmp(value, "preserve"))
index fba336a..f4a85a1 100644 (file)
@@ -50,7 +50,7 @@ static int show_reference(const char *refname, const struct object_id *oid,
                        struct object_id object;
                        enum object_type obj_type, repl_type;
 
-                       if (get_sha1(refname, object.hash))
+                       if (get_oid(refname, &object))
                                return error("Failed to resolve '%s' as a valid ref.", refname);
 
                        obj_type = sha1_object_info(object.hash, NULL);
@@ -365,7 +365,7 @@ static void check_one_mergetag(struct commit *commit,
        /* iterate over new parents */
        for (i = 1; i < mergetag_data->argc; i++) {
                struct object_id oid;
-               if (get_sha1(mergetag_data->argv[i], oid.hash) < 0)
+               if (get_oid(mergetag_data->argv[i], &oid) < 0)
                        die(_("Not a valid object name: '%s'"), mergetag_data->argv[i]);
                if (!oidcmp(&tag->tagged->oid, &oid))
                        return; /* found */
index 7aeaea2..046403e 100644 (file)
@@ -219,8 +219,8 @@ static void parse_args(struct pathspec *pathspec,
                 * has to be unambiguous. If there is a single argument, it
                 * can not be a tree
                 */
-               else if ((!argv[1] && !get_sha1_committish(argv[0], unused.hash)) ||
-                        (argv[1] && !get_sha1_treeish(argv[0], unused.hash))) {
+               else if ((!argv[1] && !get_oid_committish(argv[0], &unused)) ||
+                        (argv[1] && !get_oid_treeish(argv[0], &unused))) {
                        /*
                         * Ok, argv[0] looks like a commit/tree; it should not
                         * be a filename.
@@ -310,13 +310,13 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
 
        load_submodule_cache();
 
-       unborn = !strcmp(rev, "HEAD") && get_sha1("HEAD", oid.hash);
+       unborn = !strcmp(rev, "HEAD") && get_oid("HEAD", &oid);
        if (unborn) {
                /* reset on unborn branch: treat as reset to empty tree */
                hashcpy(oid.hash, EMPTY_TREE_SHA1_BIN);
        } else if (!pathspec.nr) {
                struct commit *commit;
-               if (get_sha1_committish(rev, oid.hash))
+               if (get_oid_committish(rev, &oid))
                        die(_("Failed to resolve '%s' as a valid revision."), rev);
                commit = lookup_commit_reference(&oid);
                if (!commit)
@@ -324,7 +324,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
                oidcpy(&oid, &commit->object.oid);
        } else {
                struct tree *tree;
-               if (get_sha1_treeish(rev, oid.hash))
+               if (get_oid_treeish(rev, &oid))
                        die(_("Failed to resolve '%s' as a valid tree."), rev);
                tree = parse_tree_indirect(&oid);
                if (!tree)
index 95d84d5..95b4128 100644 (file)
@@ -11,6 +11,7 @@
 #include "graph.h"
 #include "bisect.h"
 #include "progress.h"
+#include "reflog-walk.h"
 
 static const char rev_list_usage[] =
 "git rev-list [OPTION] <commit-id>... [ -- paths... ]\n"
@@ -122,6 +123,7 @@ static void show_commit(struct commit *commit, void *data)
                ctx.date_mode_explicit = revs->date_mode_explicit;
                ctx.fmt = revs->commit_format;
                ctx.output_encoding = get_log_output_encoding();
+               ctx.color = revs->diffopt.use_color;
                pretty_print_commit(&ctx, commit, &buf);
                if (buf.len) {
                        if (revs->commit_format != CMIT_FMT_ONELINE)
@@ -348,9 +350,10 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
                /* Only --header was specified */
                revs.commit_format = CMIT_FMT_RAW;
 
-       if ((!revs.commits &&
+       if ((!revs.commits && reflog_walk_empty(revs.reflog_info) &&
             (!(revs.tag_objects || revs.tree_objects || revs.blob_objects) &&
-             !revs.pending.nr)) ||
+             !revs.pending.nr) &&
+            !revs.rev_input_given) ||
            revs.diff)
                usage(rev_list_usage);
 
index c78b7b3..2bd28d3 100644 (file)
@@ -274,7 +274,7 @@ static int try_difference(const char *arg)
                return 0;
        }
 
-       if (!get_sha1_committish(this, oid.hash) && !get_sha1_committish(next, end.hash)) {
+       if (!get_oid_committish(this, &oid) && !get_oid_committish(next, &end)) {
                show_rev(NORMAL, &end, next);
                show_rev(symmetric ? NORMAL : REVERSED, &oid, this);
                if (symmetric) {
@@ -328,7 +328,7 @@ static int try_parent_shorthands(const char *arg)
                return 0;
 
        *dotdot = 0;
-       if (get_sha1_committish(arg, oid.hash)) {
+       if (get_oid_committish(arg, &oid)) {
                *dotdot = '^';
                return 0;
        }
@@ -702,7 +702,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
                        }
                        if (!strcmp(arg, "--quiet") || !strcmp(arg, "-q")) {
                                quiet = 1;
-                               flags |= GET_SHA1_QUIETLY;
+                               flags |= GET_OID_QUIETLY;
                                continue;
                        }
                        if (opt_with_value(arg, "--short", &arg)) {
@@ -911,7 +911,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
                        name++;
                        type = REVERSED;
                }
-               if (!get_sha1_with_context(name, flags, oid.hash, &unused)) {
+               if (!get_oid_with_context(name, flags, &oid, &unused)) {
                        if (verify)
                                revs_count++;
                        else
index 16028b9..b9d927e 100644 (file)
@@ -155,6 +155,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
                                "--strategy-option", opts->xopts ? 1 : 0,
                                "-x", opts->record_origin,
                                "--ff", opts->allow_ff,
+                               "--rerere-autoupdate", opts->allow_rerere_auto == RERERE_AUTOUPDATE,
+                               "--no-rerere-autoupdate", opts->allow_rerere_auto == RERERE_NOAUTOUPDATE,
                                NULL);
        }
 
index 52826d1..4057e73 100644 (file)
@@ -286,7 +286,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
                list.entry[list.nr].name = xstrdup(ce->name);
                list.entry[list.nr].is_submodule = S_ISGITLINK(ce->ce_mode);
                if (list.entry[list.nr++].is_submodule &&
-                   !is_staging_gitmodules_ok())
+                   !is_staging_gitmodules_ok(&the_index))
                        die (_("Please stage your changes to .gitmodules or stash them to proceed"));
        }
 
index 633e0c3..fc4f0bb 100644 (file)
@@ -105,7 +105,7 @@ static int send_pack_config(const char *k, const char *v, void *cb)
        if (!strcmp(k, "push.gpgsign")) {
                const char *value;
                if (!git_config_get_value("push.gpgsign", &value)) {
-                       switch (git_config_maybe_bool("push.gpgsign", value)) {
+                       switch (git_parse_maybe_bool(value)) {
                        case 0:
                                args.push_cert = SEND_PACK_PUSH_CERT_NEVER;
                                break;
index 7073a3e..84547d6 100644 (file)
@@ -393,7 +393,7 @@ static int append_head_ref(const char *refname, const struct object_id *oid,
        /* If both heads/foo and tags/foo exists, get_sha1 would
         * get confused.
         */
-       if (get_sha1(refname + ofs, tmp.hash) || oidcmp(&tmp, oid))
+       if (get_oid(refname + ofs, &tmp) || oidcmp(&tmp, oid))
                ofs = 5;
        return append_ref(refname + ofs, oid, 0);
 }
@@ -408,7 +408,7 @@ static int append_remote_ref(const char *refname, const struct object_id *oid,
        /* If both heads/foo and tags/foo exists, get_sha1 would
         * get confused.
         */
-       if (get_sha1(refname + ofs, tmp.hash) || oidcmp(&tmp, oid))
+       if (get_oid(refname + ofs, &tmp) || oidcmp(&tmp, oid))
                ofs = 5;
        return append_ref(refname + ofs, oid, 0);
 }
@@ -514,7 +514,7 @@ static int show_independent(struct commit **rev,
 static void append_one_rev(const char *av)
 {
        struct object_id revkey;
-       if (!get_sha1(av, revkey.hash)) {
+       if (!get_oid(av, &revkey)) {
                append_ref(av, &revkey, 0);
                return;
        }
@@ -554,7 +554,7 @@ static int git_show_branch_config(const char *var, const char *value, void *cb)
                return 0;
        }
 
-       return git_color_default_config(var, value, cb);
+       return git_default_config(var, value, cb);
 }
 
 static int omit_in_dense(struct commit *commit, struct commit **rev, int n)
@@ -808,7 +808,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
                        die(Q_("cannot handle more than %d rev.",
                               "cannot handle more than %d revs.",
                               MAX_REVS), MAX_REVS);
-               if (get_sha1(ref_name[num_rev], revkey.hash))
+               if (get_oid(ref_name[num_rev], &revkey))
                        die(_("'%s' is not a valid ref."), ref_name[num_rev]);
                commit = lookup_commit_reference(&revkey);
                if (!commit)
index 6abdad3..0ff9dd0 100644 (file)
@@ -350,7 +350,7 @@ static void init_submodule(const char *path, const char *prefix, int quiet)
        } else
                displaypath = xstrdup(path);
 
-       sub = submodule_from_path(null_sha1, path);
+       sub = submodule_from_path(&null_oid, path);
 
        if (!sub)
                die(_("No url found for submodule path '%s' in .gitmodules"),
@@ -476,7 +476,7 @@ static int module_name(int argc, const char **argv, const char *prefix)
                usage(_("git submodule--helper name <path>"));
 
        gitmodules_config();
-       sub = submodule_from_path(null_sha1, argv[1]);
+       sub = submodule_from_path(&null_oid, argv[1]);
 
        if (!sub)
                die(_("no submodule mapping found in .gitmodules for path '%s'"),
@@ -795,7 +795,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
                goto cleanup;
        }
 
-       sub = submodule_from_path(null_sha1, ce->name);
+       sub = submodule_from_path(&null_oid, ce->name);
 
        if (suc->recursive_prefix)
                displaypath = relative_path(suc->recursive_prefix,
@@ -930,7 +930,7 @@ static int update_clone_task_finished(int result,
        const struct cache_entry *ce;
        struct submodule_update_clone *suc = suc_cb;
 
-       int *idxP = *(int**)idx_task_cb;
+       int *idxP = idx_task_cb;
        int idx = *idxP;
        free(idxP);
 
@@ -960,10 +960,19 @@ static int update_clone_task_finished(int result,
        return 0;
 }
 
+static int gitmodules_update_clone_config(const char *var, const char *value,
+                                         void *cb)
+{
+       int *max_jobs = cb;
+       if (!strcmp(var, "submodule.fetchjobs"))
+               *max_jobs = parse_submodule_fetchjobs(var, value);
+       return 0;
+}
+
 static int update_clone(int argc, const char **argv, const char *prefix)
 {
        const char *update = NULL;
-       int max_jobs = -1;
+       int max_jobs = 1;
        struct string_list_item *item;
        struct pathspec pathspec;
        struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;
@@ -1000,6 +1009,9 @@ static int update_clone(int argc, const char **argv, const char *prefix)
        };
        suc.prefix = prefix;
 
+       config_from_gitmodules(gitmodules_update_clone_config, &max_jobs);
+       git_config(gitmodules_update_clone_config, &max_jobs);
+
        argc = parse_options(argc, argv, prefix, module_update_clone_options,
                             git_submodule_helper_usage, 0);
 
@@ -1017,9 +1029,6 @@ static int update_clone(int argc, const char **argv, const char *prefix)
        gitmodules_config();
        git_config(submodule_config, NULL);
 
-       if (max_jobs < 0)
-               max_jobs = parallel_submodules();
-
        run_processes_parallel(max_jobs,
                               update_clone_get_next_task,
                               update_clone_start_failure,
@@ -1060,7 +1069,7 @@ static const char *remote_submodule_branch(const char *path)
        gitmodules_config();
        git_config(submodule_config, NULL);
 
-       sub = submodule_from_path(null_sha1, path);
+       sub = submodule_from_path(&null_oid, path);
        if (!sub)
                return NULL;
 
@@ -1108,9 +1117,28 @@ static int resolve_remote_submodule_branch(int argc, const char **argv,
 static int push_check(int argc, const char **argv, const char *prefix)
 {
        struct remote *remote;
+       const char *superproject_head;
+       char *head;
+       int detached_head = 0;
+       struct object_id head_oid;
 
-       if (argc < 2)
-               die("submodule--helper push-check requires at least 1 argument");
+       if (argc < 3)
+               die("submodule--helper push-check requires at least 2 arguments");
+
+       /*
+        * superproject's resolved head ref.
+        * if HEAD then the superproject is in a detached head state, otherwise
+        * it will be the resolved head ref.
+        */
+       superproject_head = argv[1];
+       argv++;
+       argc--;
+       /* Get the submodule's head ref and determine if it is detached */
+       head = resolve_refdup("HEAD", 0, head_oid.hash, NULL);
+       if (!head)
+               die(_("Failed to resolve HEAD as a valid ref."));
+       if (!strcmp(head, "HEAD"))
+               detached_head = 1;
 
        /*
         * The remote must be configured.
@@ -1133,18 +1161,30 @@ static int push_check(int argc, const char **argv, const char *prefix)
                        if (rs->pattern || rs->matching)
                                continue;
 
-                       /*
-                        * LHS must match a single ref
-                        * NEEDSWORK: add logic to special case 'HEAD' once
-                        * working with submodules in a detached head state
-                        * ceases to be the norm.
-                        */
-                       if (count_refspec_match(rs->src, local_refs, NULL) != 1)
+                       /* LHS must match a single ref */
+                       switch (count_refspec_match(rs->src, local_refs, NULL)) {
+                       case 1:
+                               break;
+                       case 0:
+                               /*
+                                * If LHS matches 'HEAD' then we need to ensure
+                                * that it matches the same named branch
+                                * checked out in the superproject.
+                                */
+                               if (!strcmp(rs->src, "HEAD")) {
+                                       if (!detached_head &&
+                                           !strcmp(head, superproject_head))
+                                               break;
+                                       die("HEAD does not match the named branch in the superproject");
+                               }
+                       default:
                                die("src refspec '%s' must name a ref",
                                    rs->src);
+                       }
                }
                free_refspec(refspec_nr, refspec);
        }
+       free(head);
 
        return 0;
 }
index 01154ea..c627794 100644 (file)
@@ -32,7 +32,8 @@ static const char * const git_tag_usage[] = {
 static unsigned int colopts;
 static int force_sign_annotate;
 
-static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting, const char *format)
+static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting,
+                    struct ref_format *format)
 {
        struct ref_array array;
        char *to_free = NULL;
@@ -43,23 +44,24 @@ static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting, con
        if (filter->lines == -1)
                filter->lines = 0;
 
-       if (!format) {
+       if (!format->format) {
                if (filter->lines) {
                        to_free = xstrfmt("%s %%(contents:lines=%d)",
                                          "%(align:15)%(refname:lstrip=2)%(end)",
                                          filter->lines);
-                       format = to_free;
+                       format->format = to_free;
                } else
-                       format = "%(refname:lstrip=2)";
+                       format->format = "%(refname:lstrip=2)";
        }
 
-       verify_ref_format(format);
+       if (verify_ref_format(format))
+               die(_("unable to parse format string"));
        filter->with_commit_tag_algo = 1;
        filter_refs(&array, filter, FILTER_REFS_TAGS);
        ref_array_sort(sorting, &array);
 
        for (i = 0; i < array.nr; i++)
-               show_ref_array_item(array.items[i], format, 0);
+               show_ref_array_item(array.items[i], format);
        ref_array_clear(&array);
        free(to_free);
 
@@ -105,17 +107,17 @@ static int verify_tag(const char *name, const char *ref,
                      const struct object_id *oid, const void *cb_data)
 {
        int flags;
-       const char *fmt_pretty = cb_data;
+       const struct ref_format *format = cb_data;
        flags = GPG_VERIFY_VERBOSE;
 
-       if (fmt_pretty)
+       if (format->format)
                flags = GPG_VERIFY_OMIT_STATUS;
 
-       if (gpg_verify_tag(oid->hash, name, flags))
+       if (gpg_verify_tag(oid, name, flags))
                return -1;
 
-       if (fmt_pretty)
-               pretty_print_ref(name, oid->hash, fmt_pretty);
+       if (format->format)
+               pretty_print_ref(name, oid->hash, format);
 
        return 0;
 }
@@ -134,30 +136,6 @@ static const char tag_template_nocleanup[] =
        "Lines starting with '%c' will be kept; you may remove them"
        " yourself if you want to.\n");
 
-/* Parse arg given and add it the ref_sorting array */
-static int parse_sorting_string(const char *arg, struct ref_sorting **sorting_tail)
-{
-       struct ref_sorting *s;
-       int len;
-
-       s = xcalloc(1, sizeof(*s));
-       s->next = *sorting_tail;
-       *sorting_tail = s;
-
-       if (*arg == '-') {
-               s->reverse = 1;
-               arg++;
-       }
-       if (skip_prefix(arg, "version:", &arg) ||
-           skip_prefix(arg, "v:", &arg))
-               s->version = 1;
-
-       len = strlen(arg);
-       s->atom = parse_ref_filter_atom(arg, arg+len);
-
-       return 0;
-}
-
 static int git_tag_config(const char *var, const char *value, void *cb)
 {
        int status;
@@ -166,7 +144,7 @@ static int git_tag_config(const char *var, const char *value, void *cb)
        if (!strcmp(var, "tag.sort")) {
                if (!value)
                        return config_error_nonbool(var);
-               parse_sorting_string(value, sorting_tail);
+               parse_ref_sorting(sorting_tail, value);
                return 0;
        }
 
@@ -392,7 +370,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
        struct strbuf err = STRBUF_INIT;
        struct ref_filter filter;
        static struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;
-       const char *format = NULL;
+       struct ref_format format = REF_FORMAT_INIT;
        int icase = 0;
        struct option options[] = {
                OPT_CMDMODE('l', "list", &cmdmode, N_("list tag names"), 'l'),
@@ -431,7 +409,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
                        N_("print only tags of the object"), PARSE_OPT_LASTARG_DEFAULT,
                        parse_opt_object_name, (intptr_t) "HEAD"
                },
-               OPT_STRING(  0 , "format", &format, N_("format"), N_("format to use for the output")),
+               OPT_STRING(  0 , "format", &format.format, N_("format"),
+                          N_("format to use for the output")),
                OPT_BOOL('i', "ignore-case", &icase, N_("sorting and filtering are case insensitive")),
                OPT_END()
        };
@@ -461,6 +440,9 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
                        cmdmode = 'l';
        }
 
+       if (cmdmode == 'l')
+               setup_auto_pager("tag", 1);
+
        if ((create_tag_object || force) && (cmdmode != 0))
                usage_with_options(git_tag_usage, options);
 
@@ -483,7 +465,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
                        run_column_filter(colopts, &copts);
                }
                filter.name_patterns = argv;
-               ret = list_tags(&filter, sorting, format);
+               ret = list_tags(&filter, sorting, &format);
                if (column_active(colopts))
                        stop_column_filter();
                return ret;
@@ -501,9 +483,9 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
        if (cmdmode == 'd')
                return for_each_tag_name(argv, delete_tag, NULL);
        if (cmdmode == 'v') {
-               if (format)
-                       verify_ref_format(format);
-               return for_each_tag_name(argv, verify_tag, format);
+               if (format.format && verify_ref_format(&format))
+                       usage_with_options(git_tag_usage, options);
+               return for_each_tag_name(argv, verify_tag, &format);
        }
 
        if (msg.given || msgfile) {
index 73f1334..281ca1d 100644 (file)
@@ -1,7 +1,7 @@
 #include "builtin.h"
 #include "config.h"
 
-static char *create_temp_file(unsigned char *sha1)
+static char *create_temp_file(struct object_id *oid)
 {
        static char path[50];
        void *buf;
@@ -9,9 +9,9 @@ static char *create_temp_file(unsigned char *sha1)
        unsigned long size;
        int fd;
 
-       buf = read_sha1_file(sha1, &type, &size);
+       buf = read_sha1_file(oid->hash, &type, &size);
        if (!buf || type != OBJ_BLOB)
-               die("unable to read blob object %s", sha1_to_hex(sha1));
+               die("unable to read blob object %s", oid_to_hex(oid));
 
        xsnprintf(path, sizeof(path), ".merge_file_XXXXXX");
        fd = xmkstemp(path);
@@ -23,15 +23,15 @@ static char *create_temp_file(unsigned char *sha1)
 
 int cmd_unpack_file(int argc, const char **argv, const char *prefix)
 {
-       unsigned char sha1[20];
+       struct object_id oid;
 
        if (argc != 2 || !strcmp(argv[1], "-h"))
                usage("git unpack-file <sha1>");
-       if (get_sha1(argv[1], sha1))
+       if (get_oid(argv[1], &oid))
                die("Not a valid object name %s", argv[1]);
 
        git_config(git_default_config, NULL);
 
-       puts(create_temp_file(sha1));
+       puts(create_temp_file(&oid));
        return 0;
 }
index 40ccfc1..6b90c5d 100644 (file)
@@ -94,10 +94,10 @@ static char *parse_refname(struct strbuf *input, const char **next)
  * provided but cannot be converted to a SHA-1, die.  flags can
  * include PARSE_SHA1_OLD and/or PARSE_SHA1_ALLOW_EMPTY.
  */
-static int parse_next_sha1(struct strbuf *input, const char **next,
-                          unsigned char *sha1,
-                          const char *command, const char *refname,
-                          int flags)
+static int parse_next_oid(struct strbuf *input, const char **next,
+                         struct object_id *oid,
+                         const char *command, const char *refname,
+                         int flags)
 {
        struct strbuf arg = STRBUF_INIT;
        int ret = 0;
@@ -115,11 +115,11 @@ static int parse_next_sha1(struct strbuf *input, const char **next,
                (*next)++;
                *next = parse_arg(*next, &arg);
                if (arg.len) {
-                       if (get_sha1(arg.buf, sha1))
+                       if (get_oid(arg.buf, oid))
                                goto invalid;
                } else {
                        /* Without -z, an empty value means all zeros: */
-                       hashclr(sha1);
+                       oidclr(oid);
                }
        } else {
                /* With -z, read the next NUL-terminated line */
@@ -133,13 +133,13 @@ static int parse_next_sha1(struct strbuf *input, const char **next,
                *next += arg.len;
 
                if (arg.len) {
-                       if (get_sha1(arg.buf, sha1))
+                       if (get_oid(arg.buf, oid))
                                goto invalid;
                } else if (flags & PARSE_SHA1_ALLOW_EMPTY) {
                        /* With -z, treat an empty value as all zeros: */
                        warning("%s %s: missing <newvalue>, treating as zero",
                                command, refname);
-                       hashclr(sha1);
+                       oidclr(oid);
                } else {
                        /*
                         * With -z, an empty non-required value means
@@ -182,26 +182,25 @@ static const char *parse_cmd_update(struct ref_transaction *transaction,
 {
        struct strbuf err = STRBUF_INIT;
        char *refname;
-       unsigned char new_sha1[20];
-       unsigned char old_sha1[20];
+       struct object_id new_oid, old_oid;
        int have_old;
 
        refname = parse_refname(input, &next);
        if (!refname)
                die("update: missing <ref>");
 
-       if (parse_next_sha1(input, &next, new_sha1, "update", refname,
-                           PARSE_SHA1_ALLOW_EMPTY))
+       if (parse_next_oid(input, &next, &new_oid, "update", refname,
+                          PARSE_SHA1_ALLOW_EMPTY))
                die("update %s: missing <newvalue>", refname);
 
-       have_old = !parse_next_sha1(input, &next, old_sha1, "update", refname,
-                                   PARSE_SHA1_OLD);
+       have_old = !parse_next_oid(input, &next, &old_oid, "update", refname,
+                                  PARSE_SHA1_OLD);
 
        if (*next != line_termination)
                die("update %s: extra input: %s", refname, next);
 
        if (ref_transaction_update(transaction, refname,
-                                  new_sha1, have_old ? old_sha1 : NULL,
+                                  new_oid.hash, have_old ? old_oid.hash : NULL,
                                   update_flags | create_reflog_flag,
                                   msg, &err))
                die("%s", err.buf);
@@ -218,22 +217,22 @@ static const char *parse_cmd_create(struct ref_transaction *transaction,
 {
        struct strbuf err = STRBUF_INIT;
        char *refname;
-       unsigned char new_sha1[20];
+       struct object_id new_oid;
 
        refname = parse_refname(input, &next);
        if (!refname)
                die("create: missing <ref>");
 
-       if (parse_next_sha1(input, &next, new_sha1, "create", refname, 0))
+       if (parse_next_oid(input, &next, &new_oid, "create", refname, 0))
                die("create %s: missing <newvalue>", refname);
 
-       if (is_null_sha1(new_sha1))
+       if (is_null_oid(&new_oid))
                die("create %s: zero <newvalue>", refname);
 
        if (*next != line_termination)
                die("create %s: extra input: %s", refname, next);
 
-       if (ref_transaction_create(transaction, refname, new_sha1,
+       if (ref_transaction_create(transaction, refname, new_oid.hash,
                                   update_flags | create_reflog_flag,
                                   msg, &err))
                die("%s", err.buf);
@@ -250,18 +249,18 @@ static const char *parse_cmd_delete(struct ref_transaction *transaction,
 {
        struct strbuf err = STRBUF_INIT;
        char *refname;
-       unsigned char old_sha1[20];
+       struct object_id old_oid;
        int have_old;
 
        refname = parse_refname(input, &next);
        if (!refname)
                die("delete: missing <ref>");
 
-       if (parse_next_sha1(input, &next, old_sha1, "delete", refname,
-                           PARSE_SHA1_OLD)) {
+       if (parse_next_oid(input, &next, &old_oid, "delete", refname,
+                          PARSE_SHA1_OLD)) {
                have_old = 0;
        } else {
-               if (is_null_sha1(old_sha1))
+               if (is_null_oid(&old_oid))
                        die("delete %s: zero <oldvalue>", refname);
                have_old = 1;
        }
@@ -270,7 +269,7 @@ static const char *parse_cmd_delete(struct ref_transaction *transaction,
                die("delete %s: extra input: %s", refname, next);
 
        if (ref_transaction_delete(transaction, refname,
-                                  have_old ? old_sha1 : NULL,
+                                  have_old ? old_oid.hash : NULL,
                                   update_flags, msg, &err))
                die("%s", err.buf);
 
@@ -286,20 +285,20 @@ static const char *parse_cmd_verify(struct ref_transaction *transaction,
 {
        struct strbuf err = STRBUF_INIT;
        char *refname;
-       unsigned char old_sha1[20];
+       struct object_id old_oid;
 
        refname = parse_refname(input, &next);
        if (!refname)
                die("verify: missing <ref>");
 
-       if (parse_next_sha1(input, &next, old_sha1, "verify", refname,
-                           PARSE_SHA1_OLD))
-               hashclr(old_sha1);
+       if (parse_next_oid(input, &next, &old_oid, "verify", refname,
+                          PARSE_SHA1_OLD))
+               oidclr(&old_oid);
 
        if (*next != line_termination)
                die("verify %s: extra input: %s", refname, next);
 
-       if (ref_transaction_verify(transaction, refname, old_sha1,
+       if (ref_transaction_verify(transaction, refname, old_oid.hash,
                                   update_flags, &err))
                die("%s", err.buf);
 
@@ -355,7 +354,7 @@ static void update_refs_stdin(struct ref_transaction *transaction)
 int cmd_update_ref(int argc, const char **argv, const char *prefix)
 {
        const char *refname, *oldval;
-       unsigned char sha1[20], oldsha1[20];
+       struct object_id oid, oldoid;
        int delete = 0, no_deref = 0, read_stdin = 0, end_null = 0;
        unsigned int flags = 0;
        int create_reflog = 0;
@@ -412,7 +411,7 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
                refname = argv[0];
                value = argv[1];
                oldval = argv[2];
-               if (get_sha1(value, sha1))
+               if (get_oid(value, &oid))
                        die("%s: not a valid SHA1", value);
        }
 
@@ -422,8 +421,8 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
                         * The empty string implies that the reference
                         * must not already exist:
                         */
-                       hashclr(oldsha1);
-               else if (get_sha1(oldval, oldsha1))
+                       oidclr(&oldoid);
+               else if (get_oid(oldval, &oldoid))
                        die("%s: not a valid old SHA1", oldval);
        }
 
@@ -435,10 +434,10 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
                 * NULL_SHA1 as "don't care" here:
                 */
                return delete_ref(msg, refname,
-                                 (oldval && !is_null_sha1(oldsha1)) ? oldsha1 : NULL,
+                                 (oldval && !is_null_oid(&oldoid)) ? oldoid.hash : NULL,
                                  flags);
        else
-               return update_ref(msg, refname, sha1, oldval ? oldsha1 : NULL,
+               return update_ref(msg, refname, oid.hash, oldval ? oldoid.hash : NULL,
                                  flags | create_reflog_flag,
                                  UPDATE_REFS_DIE_ON_ERR);
 }
index f9a5f75..ad7b79f 100644 (file)
@@ -32,11 +32,11 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix)
 {
        int i = 1, verbose = 0, had_error = 0;
        unsigned flags = 0;
-       char *fmt_pretty = NULL;
+       struct ref_format format = REF_FORMAT_INIT;
        const struct option verify_tag_options[] = {
                OPT__VERBOSE(&verbose, N_("print tag contents")),
                OPT_BIT(0, "raw", &flags, N_("print raw gpg status output"), GPG_VERIFY_RAW),
-               OPT_STRING(  0 , "format", &fmt_pretty, N_("format"), N_("format to use for the output")),
+               OPT_STRING(0, "format", &format.format, N_("format"), N_("format to use for the output")),
                OPT_END()
        };
 
@@ -50,26 +50,29 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix)
        if (verbose)
                flags |= GPG_VERIFY_VERBOSE;
 
-       if (fmt_pretty) {
-               verify_ref_format(fmt_pretty);
+       if (format.format) {
+               if (verify_ref_format(&format))
+                       usage_with_options(verify_tag_usage,
+                                          verify_tag_options);
                flags |= GPG_VERIFY_OMIT_STATUS;
        }
 
        while (i < argc) {
-               unsigned char sha1[20];
+               struct object_id oid;
                const char *name = argv[i++];
-               if (get_sha1(name, sha1)) {
+
+               if (get_oid(name, &oid)) {
                        had_error = !!error("tag '%s' not found.", name);
                        continue;
                }
 
-               if (gpg_verify_tag(sha1, name, flags)) {
+               if (gpg_verify_tag(&oid, name, flags)) {
                        had_error = 1;
                        continue;
                }
 
-               if (fmt_pretty)
-                       pretty_print_ref(name, sha1, fmt_pretty);
+               if (format.format)
+                       pretty_print_ref(name, oid.hash, &format);
        }
        return had_error;
 }
index ec23d8c..2440d1d 100644 (file)
@@ -131,9 +131,8 @@ static int do_invalidate_path(struct cache_tree *it, const char *path)
                         * move 4 and 5 up one place (2 entries)
                         * 2 = 6 - 3 - 1 = subtree_nr - pos - 1
                         */
-                       memmove(it->down+pos, it->down+pos+1,
-                               sizeof(struct cache_tree_sub *) *
-                               (it->subtree_nr - pos - 1));
+                       MOVE_ARRAY(it->down + pos, it->down + pos + 1,
+                                  it->subtree_nr - pos - 1);
                        it->subtree_nr--;
                }
                return 1;
diff --git a/cache.h b/cache.h
index a09a501..f99404f 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -417,7 +417,6 @@ static inline enum object_type object_type(unsigned int mode)
 #define GIT_WORK_TREE_ENVIRONMENT "GIT_WORK_TREE"
 #define GIT_PREFIX_ENVIRONMENT "GIT_PREFIX"
 #define GIT_SUPER_PREFIX_ENVIRONMENT "GIT_INTERNAL_SUPER_PREFIX"
-#define GIT_TOPLEVEL_PREFIX_ENVIRONMENT "GIT_INTERNAL_TOPLEVEL_PREFIX"
 #define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
 #define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
 #define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
@@ -433,6 +432,7 @@ static inline enum object_type object_type(unsigned int mode)
 #define GITATTRIBUTES_FILE ".gitattributes"
 #define INFOATTRIBUTES_FILE "info/attributes"
 #define ATTRIBUTE_MACRO_PREFIX "[attr]"
+#define GITMODULES_FILE ".gitmodules"
 #define GIT_NOTES_REF_ENVIRONMENT "GIT_NOTES_REF"
 #define GIT_NOTES_DEFAULT_REF "refs/notes/commits"
 #define GIT_NOTES_DISPLAY_REF_ENVIRONMENT "GIT_NOTES_DISPLAY_REF"
@@ -939,14 +939,7 @@ extern const struct object_id null_oid;
 
 static inline int hashcmp(const unsigned char *sha1, const unsigned char *sha2)
 {
-       int i;
-
-       for (i = 0; i < GIT_SHA1_RAWSZ; i++, sha1++, sha2++) {
-               if (*sha1 != *sha2)
-                       return *sha1 - *sha2;
-       }
-
-       return 0;
+       return memcmp(sha1, sha2, GIT_SHA1_RAWSZ);
 }
 
 static inline int oidcmp(const struct object_id *oid1, const struct object_id *oid2)
@@ -1291,38 +1284,37 @@ struct object_context {
         */
        struct strbuf symlink_path;
        /*
-        * If GET_SHA1_RECORD_PATH is set, this will record path (if any)
+        * If GET_OID_RECORD_PATH is set, this will record path (if any)
         * found when resolving the name. The caller is responsible for
         * releasing the memory.
         */
        char *path;
 };
 
-#define GET_SHA1_QUIETLY           01
-#define GET_SHA1_COMMIT            02
-#define GET_SHA1_COMMITTISH        04
-#define GET_SHA1_TREE             010
-#define GET_SHA1_TREEISH          020
-#define GET_SHA1_BLOB             040
-#define GET_SHA1_FOLLOW_SYMLINKS 0100
-#define GET_SHA1_RECORD_PATH     0200
-#define GET_SHA1_ONLY_TO_DIE    04000
-
-#define GET_SHA1_DISAMBIGUATORS \
-       (GET_SHA1_COMMIT | GET_SHA1_COMMITTISH | \
-       GET_SHA1_TREE | GET_SHA1_TREEISH | \
-       GET_SHA1_BLOB)
-
-extern int get_sha1(const char *str, unsigned char *sha1);
-extern int get_sha1_commit(const char *str, unsigned char *sha1);
-extern int get_sha1_committish(const char *str, unsigned char *sha1);
-extern int get_sha1_tree(const char *str, unsigned char *sha1);
-extern int get_sha1_treeish(const char *str, unsigned char *sha1);
-extern int get_sha1_blob(const char *str, unsigned char *sha1);
-extern void maybe_die_on_misspelt_object_name(const char *name, const char *prefix);
-extern int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *oc);
+#define GET_OID_QUIETLY           01
+#define GET_OID_COMMIT            02
+#define GET_OID_COMMITTISH        04
+#define GET_OID_TREE             010
+#define GET_OID_TREEISH          020
+#define GET_OID_BLOB             040
+#define GET_OID_FOLLOW_SYMLINKS 0100
+#define GET_OID_RECORD_PATH     0200
+#define GET_OID_ONLY_TO_DIE    04000
+
+#define GET_OID_DISAMBIGUATORS \
+       (GET_OID_COMMIT | GET_OID_COMMITTISH | \
+       GET_OID_TREE | GET_OID_TREEISH | \
+       GET_OID_BLOB)
 
 extern int get_oid(const char *str, struct object_id *oid);
+extern int get_oid_commit(const char *str, struct object_id *oid);
+extern int get_oid_committish(const char *str, struct object_id *oid);
+extern int get_oid_tree(const char *str, struct object_id *oid);
+extern int get_oid_treeish(const char *str, struct object_id *oid);
+extern int get_oid_blob(const char *str, struct object_id *oid);
+extern void maybe_die_on_misspelt_object_name(const char *name, const char *prefix);
+extern int get_oid_with_context(const char *str, unsigned flags, struct object_id *oid, struct object_context *oc);
+
 
 typedef int each_abbrev_fn(const struct object_id *oid, void *);
 extern int for_each_abbrev(const char *prefix, each_abbrev_fn, void *);
@@ -1500,6 +1492,7 @@ struct checkout {
        struct index_state *istate;
        const char *base_dir;
        int base_dir_len;
+       struct delayed_checkout *delayed_checkout;
        unsigned force:1,
                 quiet:1,
                 not_new:1,
@@ -1509,6 +1502,8 @@ struct checkout {
 
 #define TEMPORARY_FILENAME_LENGTH 25
 extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath);
+extern void enable_delayed_checkout(struct checkout *state);
+extern int finish_delayed_checkout(struct checkout *state);
 
 struct cache_def {
        struct strbuf path;
diff --git a/color.c b/color.c
index 31b6207..7aa8b07 100644 (file)
--- a/color.c
+++ b/color.c
@@ -361,14 +361,6 @@ int git_color_config(const char *var, const char *value, void *cb)
        return 0;
 }
 
-int git_color_default_config(const char *var, const char *value, void *cb)
-{
-       if (git_color_config(var, value, cb) < 0)
-               return -1;
-
-       return git_default_config(var, value, cb);
-}
-
 void color_print_strbuf(FILE *fp, const char *color, const struct strbuf *sb)
 {
        if (*color)
index cbfd689..8b28415 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -59,7 +59,7 @@ struct commit *lookup_commit_reference_by_name(const char *name)
        struct object_id oid;
        struct commit *commit;
 
-       if (get_sha1_committish(name, oid.hash))
+       if (get_oid_committish(name, &oid))
                return NULL;
        commit = lookup_commit_reference(&oid);
        if (parse_commit(commit))
@@ -199,11 +199,11 @@ static void prepare_commit_graft(void)
        commit_graft_prepared = 1;
 }
 
-struct commit_graft *lookup_commit_graft(const unsigned char *sha1)
+struct commit_graft *lookup_commit_graft(const struct object_id *oid)
 {
        int pos;
        prepare_commit_graft();
-       pos = commit_graft_pos(sha1);
+       pos = commit_graft_pos(oid->hash);
        if (pos < 0)
                return NULL;
        return commit_graft[pos];
@@ -223,9 +223,8 @@ int unregister_shallow(const struct object_id *oid)
        if (pos < 0)
                return -1;
        if (pos + 1 < commit_graft_nr)
-               memmove(commit_graft + pos, commit_graft + pos + 1,
-                               sizeof(struct commit_graft *)
-                               * (commit_graft_nr - pos - 1));
+               MOVE_ARRAY(commit_graft + pos, commit_graft + pos + 1,
+                          commit_graft_nr - pos - 1);
        commit_graft_nr--;
        return 0;
 }
@@ -335,7 +334,7 @@ int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long s
        bufptr += tree_entry_len + 1; /* "tree " + "hex sha1" + "\n" */
        pptr = &item->parents;
 
-       graft = lookup_commit_graft(item->object.oid.hash);
+       graft = lookup_commit_graft(&item->object.oid);
        while (bufptr + parent_entry_len < tail && !memcmp(bufptr, "parent ", 7)) {
                struct commit *new_parent;
 
@@ -1587,7 +1586,7 @@ struct commit *get_merge_parent(const char *name)
        struct object *obj;
        struct commit *commit;
        struct object_id oid;
-       if (get_sha1(name, oid.hash))
+       if (get_oid(name, &oid))
                return NULL;
        obj = parse_object(&oid);
        commit = (struct commit *)peel_to_type(name, 0, obj, OBJ_COMMIT);
index 4127c29..6d857f0 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -249,7 +249,7 @@ typedef int (*each_commit_graft_fn)(const struct commit_graft *, void *);
 
 struct commit_graft *read_graft_line(char *buf, int len);
 int register_commit_graft(struct commit_graft *, int);
-struct commit_graft *lookup_commit_graft(const unsigned char *sha1);
+struct commit_graft *lookup_commit_graft(const struct object_id *oid);
 
 extern struct commit_list *get_merge_bases(struct commit *rev1, struct commit *rev2);
 extern struct commit_list *get_merge_bases_many(struct commit *one, int n, struct commit **twos);
index d47c003..7d063e9 100644 (file)
@@ -162,19 +162,29 @@ static inline uint64_t git_bswap64(uint64_t x)
 
 #else
 
-#define get_be16(p)    ( \
-       (*((unsigned char *)(p) + 0) << 8) | \
-       (*((unsigned char *)(p) + 1) << 0) )
-#define get_be32(p)    ( \
-       (*((unsigned char *)(p) + 0) << 24) | \
-       (*((unsigned char *)(p) + 1) << 16) | \
-       (*((unsigned char *)(p) + 2) <<  8) | \
-       (*((unsigned char *)(p) + 3) <<  0) )
-#define put_be32(p, v) do { \
-       unsigned int __v = (v); \
-       *((unsigned char *)(p) + 0) = __v >> 24; \
-       *((unsigned char *)(p) + 1) = __v >> 16; \
-       *((unsigned char *)(p) + 2) = __v >>  8; \
-       *((unsigned char *)(p) + 3) = __v >>  0; } while (0)
+static inline uint16_t get_be16(const void *ptr)
+{
+       const unsigned char *p = ptr;
+       return  (uint16_t)p[0] << 8 |
+               (uint16_t)p[1] << 0;
+}
+
+static inline uint32_t get_be32(const void *ptr)
+{
+       const unsigned char *p = ptr;
+       return  (uint32_t)p[0] << 24 |
+               (uint32_t)p[1] << 16 |
+               (uint32_t)p[2] <<  8 |
+               (uint32_t)p[3] <<  0;
+}
+
+static inline void put_be32(void *ptr, uint32_t value)
+{
+       unsigned char *p = ptr;
+       p[0] = value >> 24;
+       p[1] = value >> 16;
+       p[2] = value >>  8;
+       p[3] = value >>  0;
+}
 
 #endif
index 6c7c9b6..161978d 100644 (file)
@@ -43,8 +43,10 @@ void syslog(int priority, const char *fmt, ...)
        va_end(ap);
 
        while ((pos = strstr(str, "%1")) != NULL) {
+               char *oldstr = str;
                str = realloc(str, st_add(++str_len, 1));
                if (!str) {
+                       free(oldstr);
                        warning_errno("realloc failed");
                        return;
                }
index 231f9a7..777527d 100644 (file)
--- a/config.c
+++ b/config.c
@@ -16,6 +16,7 @@
 #include "string-list.h"
 #include "utf8.h"
 #include "dir.h"
+#include "color.h"
 
 struct config_source {
        struct config_source *prev;
@@ -928,7 +929,7 @@ ssize_t git_config_ssize_t(const char *name, const char *value)
        return ret;
 }
 
-int git_parse_maybe_bool(const char *value)
+static int git_parse_maybe_bool_text(const char *value)
 {
        if (!value)
                return 1;
@@ -945,9 +946,9 @@ int git_parse_maybe_bool(const char *value)
        return -1;
 }
 
-int git_config_maybe_bool(const char *name, const char *value)
+int git_parse_maybe_bool(const char *value)
 {
-       int v = git_parse_maybe_bool(value);
+       int v = git_parse_maybe_bool_text(value);
        if (0 <= v)
                return v;
        if (git_parse_int(value, &v))
@@ -955,9 +956,14 @@ int git_config_maybe_bool(const char *name, const char *value)
        return -1;
 }
 
+int git_config_maybe_bool(const char *name, const char *value)
+{
+       return git_parse_maybe_bool(value);
+}
+
 int git_config_bool_or_int(const char *name, const char *value, int *is_bool)
 {
-       int v = git_parse_maybe_bool(value);
+       int v = git_parse_maybe_bool_text(value);
        if (0 <= v) {
                *is_bool = 1;
                return v;
@@ -1350,6 +1356,9 @@ int git_default_config(const char *var, const char *value, void *dummy)
        if (starts_with(var, "advice."))
                return git_default_advice_config(var, value);
 
+       if (git_color_config(var, value, dummy) < 0)
+               return -1;
+
        if (!strcmp(var, "pager.color") || !strcmp(var, "color.pager")) {
                pager_use_color = git_config_bool(var,value);
                return 0;
@@ -1460,9 +1469,9 @@ int git_config_from_mem(config_fn_t fn, const enum config_origin_type origin_typ
        return do_config_from(&top, fn, data);
 }
 
-int git_config_from_blob_sha1(config_fn_t fn,
+int git_config_from_blob_oid(config_fn_t fn,
                              const char *name,
-                             const unsigned char *sha1,
+                             const struct object_id *oid,
                              void *data)
 {
        enum object_type type;
@@ -1470,7 +1479,7 @@ int git_config_from_blob_sha1(config_fn_t fn,
        unsigned long size;
        int ret;
 
-       buf = read_sha1_file(sha1, &type, &size);
+       buf = read_sha1_file(oid->hash, &type, &size);
        if (!buf)
                return error("unable to load config blob object '%s'", name);
        if (type != OBJ_BLOB) {
@@ -1488,11 +1497,11 @@ static int git_config_from_blob_ref(config_fn_t fn,
                                    const char *name,
                                    void *data)
 {
-       unsigned char sha1[20];
+       struct object_id oid;
 
-       if (get_sha1(name, sha1) < 0)
+       if (get_oid(name, &oid) < 0)
                return error("unable to resolve config blob '%s'", name);
-       return git_config_from_blob_sha1(fn, name, sha1, data);
+       return git_config_from_blob_oid(fn, name, &oid, data);
 }
 
 const char *git_etc_gitconfig(void)
@@ -1715,17 +1724,19 @@ static int configset_add_value(struct config_set *cs, const char *key, const cha
 }
 
 static int config_set_element_cmp(const void *unused_cmp_data,
-                                 const struct config_set_element *e1,
-                                 const struct config_set_element *e2,
+                                 const void *entry,
+                                 const void *entry_or_key,
                                  const void *unused_keydata)
 {
+       const struct config_set_element *e1 = entry;
+       const struct config_set_element *e2 = entry_or_key;
+
        return strcmp(e1->key, e2->key);
 }
 
 void git_configset_init(struct config_set *cs)
 {
-       hashmap_init(&cs->config_hash, (hashmap_cmp_fn)config_set_element_cmp,
-                    NULL, 0);
+       hashmap_init(&cs->config_hash, config_set_element_cmp, NULL, 0);
        cs->hash_initialized = 1;
        cs->list.nr = 0;
        cs->list.alloc = 0;
@@ -1846,7 +1857,7 @@ int git_configset_get_maybe_bool(struct config_set *cs, const char *key, int *de
 {
        const char *value;
        if (!git_configset_get_value(cs, key, &value)) {
-               *dest = git_config_maybe_bool(key, value);
+               *dest = git_parse_maybe_bool(value);
                if (*dest == -1)
                        return -1;
                return 0;
@@ -2053,6 +2064,23 @@ int git_config_get_pathname(const char *key, const char **dest)
        return repo_config_get_pathname(the_repository, key, dest);
 }
 
+/*
+ * Note: This function exists solely to maintain backward compatibility with
+ * 'fetch' and 'update_clone' storing configuration in '.gitmodules' and should
+ * NOT be used anywhere else.
+ *
+ * Runs the provided config function on the '.gitmodules' file found in the
+ * working directory.
+ */
+void config_from_gitmodules(config_fn_t fn, void *data)
+{
+       if (the_repository->worktree) {
+               char *file = repo_worktree_path(the_repository, GITMODULES_FILE);
+               git_config_from_file(fn, file, data);
+               free(file);
+       }
+}
+
 int git_config_get_expiry(const char *key, const char **output)
 {
        int ret = git_config_get_string_const(key, output);
index 0352da1..18b6f3f 100644 (file)
--- a/config.h
+++ b/config.h
@@ -39,8 +39,8 @@ extern int git_default_config(const char *, const char *, void *);
 extern int git_config_from_file(config_fn_t fn, const char *, void *);
 extern int git_config_from_mem(config_fn_t fn, const enum config_origin_type,
                                        const char *name, const char *buf, size_t len, void *data);
-extern int git_config_from_blob_sha1(config_fn_t fn, const char *name,
-                                    const unsigned char *sha1, void *data);
+extern int git_config_from_blob_oid(config_fn_t fn, const char *name,
+                                   const struct object_id *oid, void *data);
 extern void git_config_push_parameter(const char *text);
 extern int git_config_from_parameters(config_fn_t fn, void *data);
 extern void read_early_config(config_fn_t cb, void *data);
@@ -187,6 +187,16 @@ extern int repo_config_get_maybe_bool(struct repository *repo,
 extern int repo_config_get_pathname(struct repository *repo,
                                    const char *key, const char **dest);
 
+/*
+ * Note: This function exists solely to maintain backward compatibility with
+ * 'fetch' and 'update_clone' storing configuration in '.gitmodules' and should
+ * NOT be used anywhere else.
+ *
+ * Runs the provided config function on the '.gitmodules' file found in the
+ * working directory.
+ */
+extern void config_from_gitmodules(config_fn_t fn, void *data);
+
 extern int git_config_get_value(const char *key, const char **value);
 extern const struct string_list *git_config_get_value_multi(const char *key);
 extern void git_config_clear(void);
index 4ba98b7..c61d1ca 100644 (file)
@@ -25,6 +25,23 @@ expression n;
 - memcpy(dst, src, n * sizeof(T));
 + COPY_ARRAY(dst, src, n);
 
+@@
+type T;
+T *dst;
+T *src;
+expression n;
+@@
+(
+- memmove(dst, src, (n) * sizeof(*dst));
++ MOVE_ARRAY(dst, src, n);
+|
+- memmove(dst, src, (n) * sizeof(*src));
++ MOVE_ARRAY(dst, src, n);
+|
+- memmove(dst, src, (n) * sizeof(T));
++ MOVE_ARRAY(dst, src, n);
+)
+
 @@
 type T;
 T *ptr;
index dbe2abf..85ad732 100755 (executable)
@@ -11,7 +11,7 @@ use IPC::Open2;
 
 my $since = '5-years-ago';
 my $min_percent = 10;
-my $labels_rx = qr/Signed-off-by|Reviewed-by|Acked-by|Cc/i;
+my $labels_rx = qr/Signed-off-by|Reviewed-by|Acked-by|Cc|Reported-by/i;
 my %seen;
 
 sub format_contact {
index 52ad9e4..eeee45d 100755 (executable)
@@ -3,10 +3,56 @@
 # Prime rerere database from existing merge commits
 
 me=rerere-train
-USAGE="$me rev-list-args"
+USAGE=$(cat <<-EOF
+usage: $me [--overwrite] <rev-list-args>
+
+    -h, --help            show the help
+    -o, --overwrite       overwrite any existing rerere cache
+EOF
+)
 
 SUBDIRECTORY_OK=Yes
-OPTIONS_SPEC=
+
+overwrite=0
+
+while test $# -gt 0
+do
+       opt="$1"
+       case "$opt" in
+       -h|--help)
+               echo "$USAGE"
+               exit 0
+               ;;
+       -o|--overwrite)
+               overwrite=1
+               shift
+               break
+               ;;
+       --)
+               shift
+               break
+               ;;
+       *)
+               break
+               ;;
+       esac
+done
+
+# Overwrite or help options are not valid except as first arg
+for opt in "$@"
+do
+       case "$opt" in
+       -h|--help)
+               echo "$USAGE"
+               exit 0
+               ;;
+       -o|--overwrite)
+               echo "$USAGE"
+               exit 0
+               ;;
+       esac
+done
+
 . "$(git --exec-path)/git-sh-setup"
 require_work_tree
 cd_to_toplevel
@@ -34,6 +80,10 @@ do
                # Cleanly merges
                continue
        fi
+       if test $overwrite = 1
+       then
+               git rerere forget .
+       fi
        if test -s "$GIT_DIR/MERGE_RR"
        then
                git show -s --pretty=format:"Learning from %h %s" "$commit"
index deaf0ba..1012462 100644 (file)
--- a/convert.c
+++ b/convert.c
@@ -501,6 +501,7 @@ static int apply_single_file_filter(const char *path, const char *src, size_t le
 
 #define CAP_CLEAN    (1u<<0)
 #define CAP_SMUDGE   (1u<<1)
+#define CAP_DELAY    (1u<<2)
 
 struct cmd2process {
        struct subprocess_entry subprocess; /* must be the first member! */
@@ -512,69 +513,49 @@ static struct hashmap subprocess_map;
 
 static int start_multi_file_filter_fn(struct subprocess_entry *subprocess)
 {
-       int err;
+       static int versions[] = {2, 0};
+       static struct subprocess_capability capabilities[] = {
+               { "clean",  CAP_CLEAN  },
+               { "smudge", CAP_SMUDGE },
+               { "delay",  CAP_DELAY  },
+               { NULL, 0 }
+       };
        struct cmd2process *entry = (struct cmd2process *)subprocess;
-       struct string_list cap_list = STRING_LIST_INIT_NODUP;
-       char *cap_buf;
-       const char *cap_name;
-       struct child_process *process = &subprocess->process;
-       const char *cmd = subprocess->cmd;
-
-       sigchain_push(SIGPIPE, SIG_IGN);
-
-       err = packet_writel(process->in, "git-filter-client", "version=2", NULL);
-       if (err)
-               goto done;
-
-       err = strcmp(packet_read_line(process->out, NULL), "git-filter-server");
-       if (err) {
-               error("external filter '%s' does not support filter protocol version 2", cmd);
-               goto done;
-       }
-       err = strcmp(packet_read_line(process->out, NULL), "version=2");
-       if (err)
-               goto done;
-       err = packet_read_line(process->out, NULL) != NULL;
-       if (err)
-               goto done;
-
-       err = packet_writel(process->in, "capability=clean", "capability=smudge", NULL);
-
-       for (;;) {
-               cap_buf = packet_read_line(process->out, NULL);
-               if (!cap_buf)
-                       break;
-               string_list_split_in_place(&cap_list, cap_buf, '=', 1);
-
-               if (cap_list.nr != 2 || strcmp(cap_list.items[0].string, "capability"))
-                       continue;
-
-               cap_name = cap_list.items[1].string;
-               if (!strcmp(cap_name, "clean")) {
-                       entry->supported_capabilities |= CAP_CLEAN;
-               } else if (!strcmp(cap_name, "smudge")) {
-                       entry->supported_capabilities |= CAP_SMUDGE;
-               } else {
-                       warning(
-                               "external filter '%s' requested unsupported filter capability '%s'",
-                               cmd, cap_name
-                       );
-               }
+       return subprocess_handshake(subprocess, "git-filter", versions, NULL,
+                                   capabilities,
+                                   &entry->supported_capabilities);
+}
 
-               string_list_clear(&cap_list, 0);
+static void handle_filter_error(const struct strbuf *filter_status,
+                               struct cmd2process *entry,
+                               const unsigned int wanted_capability) {
+       if (!strcmp(filter_status->buf, "error"))
+               ; /* The filter signaled a problem with the file. */
+       else if (!strcmp(filter_status->buf, "abort") && wanted_capability) {
+               /*
+                * The filter signaled a permanent problem. Don't try to filter
+                * files with the same command for the lifetime of the current
+                * Git process.
+                */
+                entry->supported_capabilities &= ~wanted_capability;
+       } else {
+               /*
+                * Something went wrong with the protocol filter.
+                * Force shutdown and restart if another blob requires filtering.
+                */
+               error("external filter '%s' failed", entry->subprocess.cmd);
+               subprocess_stop(&subprocess_map, &entry->subprocess);
+               free(entry);
        }
-
-done:
-       sigchain_pop(SIGPIPE);
-
-       return err;
 }
 
 static int apply_multi_file_filter(const char *path, const char *src, size_t len,
                                   int fd, struct strbuf *dst, const char *cmd,
-                                  const unsigned int wanted_capability)
+                                  const unsigned int wanted_capability,
+                                  struct delayed_checkout *dco)
 {
        int err;
+       int can_delay = 0;
        struct cmd2process *entry;
        struct child_process *process;
        struct strbuf nbuf = STRBUF_INIT;
@@ -583,8 +564,7 @@ static int apply_multi_file_filter(const char *path, const char *src, size_t len
 
        if (!subprocess_map_initialized) {
                subprocess_map_initialized = 1;
-               hashmap_init(&subprocess_map, (hashmap_cmp_fn) cmd2process_cmp,
-                            NULL, 0);
+               hashmap_init(&subprocess_map, cmd2process_cmp, NULL, 0);
                entry = NULL;
        } else {
                entry = (struct cmd2process *)subprocess_find_entry(&subprocess_map, cmd);
@@ -603,12 +583,12 @@ static int apply_multi_file_filter(const char *path, const char *src, size_t len
        }
        process = &entry->subprocess.process;
 
-       if (!(wanted_capability & entry->supported_capabilities))
+       if (!(entry->supported_capabilities & wanted_capability))
                return 0;
 
-       if (CAP_CLEAN & wanted_capability)
+       if (wanted_capability & CAP_CLEAN)
                filter_type = "clean";
-       else if (CAP_SMUDGE & wanted_capability)
+       else if (wanted_capability & CAP_SMUDGE)
                filter_type = "smudge";
        else
                die("unexpected filter type");
@@ -630,6 +610,14 @@ static int apply_multi_file_filter(const char *path, const char *src, size_t len
        if (err)
                goto done;
 
+       if ((entry->supported_capabilities & CAP_DELAY) &&
+           dco && dco->state == CE_CAN_DELAY) {
+               can_delay = 1;
+               err = packet_write_fmt_gently(process->in, "can-delay=1\n");
+               if (err)
+                       goto done;
+       }
+
        err = packet_flush_gently(process->in);
        if (err)
                goto done;
@@ -645,14 +633,73 @@ static int apply_multi_file_filter(const char *path, const char *src, size_t len
        if (err)
                goto done;
 
-       err = strcmp(filter_status.buf, "success");
+       if (can_delay && !strcmp(filter_status.buf, "delayed")) {
+               string_list_insert(&dco->filters, cmd);
+               string_list_insert(&dco->paths, path);
+       } else {
+               /* The filter got the blob and wants to send us a response. */
+               err = strcmp(filter_status.buf, "success");
+               if (err)
+                       goto done;
+
+               err = read_packetized_to_strbuf(process->out, &nbuf) < 0;
+               if (err)
+                       goto done;
+
+               err = subprocess_read_status(process->out, &filter_status);
+               if (err)
+                       goto done;
+
+               err = strcmp(filter_status.buf, "success");
+       }
+
+done:
+       sigchain_pop(SIGPIPE);
+
+       if (err)
+               handle_filter_error(&filter_status, entry, wanted_capability);
+       else
+               strbuf_swap(dst, &nbuf);
+       strbuf_release(&nbuf);
+       return !err;
+}
+
+
+int async_query_available_blobs(const char *cmd, struct string_list *available_paths)
+{
+       int err;
+       char *line;
+       struct cmd2process *entry;
+       struct child_process *process;
+       struct strbuf filter_status = STRBUF_INIT;
+
+       assert(subprocess_map_initialized);
+       entry = (struct cmd2process *)subprocess_find_entry(&subprocess_map, cmd);
+       if (!entry) {
+               error("external filter '%s' is not available anymore although "
+                     "not all paths have been filtered", cmd);
+               return 0;
+       }
+       process = &entry->subprocess.process;
+       sigchain_push(SIGPIPE, SIG_IGN);
+
+       err = packet_write_fmt_gently(
+               process->in, "command=list_available_blobs\n");
        if (err)
                goto done;
 
-       err = read_packetized_to_strbuf(process->out, &nbuf) < 0;
+       err = packet_flush_gently(process->in);
        if (err)
                goto done;
 
+       while ((line = packet_read_line(process->out, NULL))) {
+               const char *path;
+               if (skip_prefix(line, "pathname=", &path))
+                       string_list_insert(available_paths, xstrdup(path));
+               else
+                       ; /* ignore unknown keys */
+       }
+
        err = subprocess_read_status(process->out, &filter_status);
        if (err)
                goto done;
@@ -662,29 +709,8 @@ static int apply_multi_file_filter(const char *path, const char *src, size_t len
 done:
        sigchain_pop(SIGPIPE);
 
-       if (err) {
-               if (!strcmp(filter_status.buf, "error")) {
-                       /* The filter signaled a problem with the file. */
-               } else if (!strcmp(filter_status.buf, "abort")) {
-                       /*
-                        * The filter signaled a permanent problem. Don't try to filter
-                        * files with the same command for the lifetime of the current
-                        * Git process.
-                        */
-                        entry->supported_capabilities &= ~wanted_capability;
-               } else {
-                       /*
-                        * Something went wrong with the protocol filter.
-                        * Force shutdown and restart if another blob requires filtering.
-                        */
-                       error("external filter '%s' failed", cmd);
-                       subprocess_stop(&subprocess_map, &entry->subprocess);
-                       free(entry);
-               }
-       } else {
-               strbuf_swap(dst, &nbuf);
-       }
-       strbuf_release(&nbuf);
+       if (err)
+               handle_filter_error(&filter_status, entry, 0);
        return !err;
 }
 
@@ -699,7 +725,8 @@ static struct convert_driver {
 
 static int apply_filter(const char *path, const char *src, size_t len,
                        int fd, struct strbuf *dst, struct convert_driver *drv,
-                       const unsigned int wanted_capability)
+                       const unsigned int wanted_capability,
+                       struct delayed_checkout *dco)
 {
        const char *cmd = NULL;
 
@@ -709,15 +736,16 @@ static int apply_filter(const char *path, const char *src, size_t len,
        if (!dst)
                return 1;
 
-       if ((CAP_CLEAN & wanted_capability) && !drv->process && drv->clean)
+       if ((wanted_capability & CAP_CLEAN) && !drv->process && drv->clean)
                cmd = drv->clean;
-       else if ((CAP_SMUDGE & wanted_capability) && !drv->process && drv->smudge)
+       else if ((wanted_capability & CAP_SMUDGE) && !drv->process && drv->smudge)
                cmd = drv->smudge;
 
        if (cmd && *cmd)
                return apply_single_file_filter(path, src, len, fd, dst, cmd);
        else if (drv->process && *drv->process)
-               return apply_multi_file_filter(path, src, len, fd, dst, drv->process, wanted_capability);
+               return apply_multi_file_filter(path, src, len, fd, dst,
+                       drv->process, wanted_capability, dco);
 
        return 0;
 }
@@ -1058,7 +1086,7 @@ int would_convert_to_git_filter_fd(const char *path)
        if (!ca.drv->required)
                return 0;
 
-       return apply_filter(path, NULL, 0, -1, NULL, ca.drv, CAP_CLEAN);
+       return apply_filter(path, NULL, 0, -1, NULL, ca.drv, CAP_CLEAN, NULL);
 }
 
 const char *get_convert_attr_ascii(const char *path)
@@ -1096,7 +1124,7 @@ int convert_to_git(const struct index_state *istate,
 
        convert_attrs(&ca, path);
 
-       ret |= apply_filter(path, src, len, -1, dst, ca.drv, CAP_CLEAN);
+       ret |= apply_filter(path, src, len, -1, dst, ca.drv, CAP_CLEAN, NULL);
        if (!ret && ca.drv && ca.drv->required)
                die("%s: clean filter '%s' failed", path, ca.drv->name);
 
@@ -1122,7 +1150,7 @@ void convert_to_git_filter_fd(const struct index_state *istate,
        assert(ca.drv);
        assert(ca.drv->clean || ca.drv->process);
 
-       if (!apply_filter(path, NULL, 0, fd, dst, ca.drv, CAP_CLEAN))
+       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);
@@ -1131,7 +1159,7 @@ void convert_to_git_filter_fd(const struct index_state *istate,
 
 static int convert_to_working_tree_internal(const char *path, const char *src,
                                            size_t len, struct strbuf *dst,
-                                           int normalizing)
+                                           int normalizing, struct delayed_checkout *dco)
 {
        int ret = 0, ret_filter = 0;
        struct conv_attrs ca;
@@ -1156,22 +1184,30 @@ static int convert_to_working_tree_internal(const char *path, const char *src,
                }
        }
 
-       ret_filter = apply_filter(path, src, len, -1, dst, ca.drv, CAP_SMUDGE);
+       ret_filter = apply_filter(
+               path, src, len, -1, dst, ca.drv, CAP_SMUDGE, dco);
        if (!ret_filter && ca.drv && ca.drv->required)
                die("%s: smudge filter %s failed", path, ca.drv->name);
 
        return ret | ret_filter;
 }
 
+int async_convert_to_working_tree(const char *path, const char *src,
+                                 size_t len, struct strbuf *dst,
+                                 void *dco)
+{
+       return convert_to_working_tree_internal(path, src, len, dst, 0, dco);
+}
+
 int convert_to_working_tree(const char *path, const char *src, size_t len, struct strbuf *dst)
 {
-       return convert_to_working_tree_internal(path, src, len, dst, 0);
+       return convert_to_working_tree_internal(path, src, len, dst, 0, NULL);
 }
 
 int renormalize_buffer(const struct index_state *istate, const char *path,
                       const char *src, size_t len, struct strbuf *dst)
 {
-       int ret = convert_to_working_tree_internal(path, src, len, dst, 1);
+       int ret = convert_to_working_tree_internal(path, src, len, dst, 1, NULL);
        if (ret) {
                src = dst->buf;
                len = dst->len;
index cecf59d..6b06144 100644 (file)
--- a/convert.h
+++ b/convert.h
@@ -4,6 +4,8 @@
 #ifndef CONVERT_H
 #define CONVERT_H
 
+#include "string-list.h"
+
 struct index_state;
 
 enum safe_crlf {
@@ -34,6 +36,26 @@ enum eol {
 #endif
 };
 
+enum ce_delay_state {
+       CE_NO_DELAY = 0,
+       CE_CAN_DELAY = 1,
+       CE_RETRY = 2
+};
+
+struct delayed_checkout {
+       /*
+        * State of the currently processed cache entry. If the state is
+        * CE_CAN_DELAY, then the filter can delay the current cache entry.
+        * If the state is CE_RETRY, then this signals the filter that the
+        * cache entry was requested before.
+        */
+       enum ce_delay_state state;
+       /* List of filter drivers that signaled delayed blobs. */
+       struct string_list filters;
+       /* List of delayed blobs identified by their path. */
+       struct string_list paths;
+};
+
 extern enum eol core_eol;
 extern const char *get_cached_convert_stats_ascii(const struct index_state *istate,
                                                  const char *path);
@@ -46,6 +68,10 @@ extern int convert_to_git(const struct index_state *istate,
                          struct strbuf *dst, enum safe_crlf checksafe);
 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,
+                                        size_t len, struct strbuf *dst,
+                                        void *dco);
+extern int async_query_available_blobs(const char *cmd, struct string_list *available_paths);
 extern int renormalize_buffer(const struct index_state *istate,
                              const char *path, const char *src, size_t len,
                              struct strbuf *dst);
index 91550bf..1cccc3a 100644 (file)
@@ -25,7 +25,7 @@ static int send_request(const char *socket, const struct strbuf *out)
                int r;
 
                r = read_in_full(fd, in, sizeof(in));
-               if (r == 0)
+               if (r == 0 || (r < 0 && errno == ECONNRESET))
                        break;
                if (r < 0)
                        die_errno("read error from cache daemon");
diff --git a/diff.c b/diff.c
index 85e714f..9c38258 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -299,9 +299,6 @@ int git_diff_ui_config(const char *var, const char *value, void *cb)
                return 0;
        }
 
-       if (git_color_config(var, value, cb) < 0)
-               return -1;
-
        return git_diff_basic_config(var, value, cb);
 }
 
diff --git a/dir.c b/dir.c
index ae6f5c9..1c55dc3 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -2398,7 +2398,8 @@ struct ondisk_untracked_cache {
        char exclude_per_dir[FLEX_ARRAY];
 };
 
-#define ouc_size(len) (offsetof(struct ondisk_untracked_cache, exclude_per_dir) + len + 1)
+#define ouc_offset(x) offsetof(struct ondisk_untracked_cache, x)
+#define ouc_size(len) (ouc_offset(exclude_per_dir) + len + 1)
 
 struct write_data {
        int index;         /* number of written untracked_cache_dir */
@@ -2560,17 +2561,18 @@ struct read_data {
        const unsigned char *end;
 };
 
-static void stat_data_from_disk(struct stat_data *to, const struct stat_data *from)
+static void stat_data_from_disk(struct stat_data *to, const unsigned char *data)
 {
-       to->sd_ctime.sec  = get_be32(&from->sd_ctime.sec);
-       to->sd_ctime.nsec = get_be32(&from->sd_ctime.nsec);
-       to->sd_mtime.sec  = get_be32(&from->sd_mtime.sec);
-       to->sd_mtime.nsec = get_be32(&from->sd_mtime.nsec);
-       to->sd_dev        = get_be32(&from->sd_dev);
-       to->sd_ino        = get_be32(&from->sd_ino);
-       to->sd_uid        = get_be32(&from->sd_uid);
-       to->sd_gid        = get_be32(&from->sd_gid);
-       to->sd_size       = get_be32(&from->sd_size);
+       memcpy(to, data, sizeof(*to));
+       to->sd_ctime.sec  = ntohl(to->sd_ctime.sec);
+       to->sd_ctime.nsec = ntohl(to->sd_ctime.nsec);
+       to->sd_mtime.sec  = ntohl(to->sd_mtime.sec);
+       to->sd_mtime.nsec = ntohl(to->sd_mtime.nsec);
+       to->sd_dev        = ntohl(to->sd_dev);
+       to->sd_ino        = ntohl(to->sd_ino);
+       to->sd_uid        = ntohl(to->sd_uid);
+       to->sd_gid        = ntohl(to->sd_gid);
+       to->sd_size       = ntohl(to->sd_size);
 }
 
 static int read_one_dir(struct untracked_cache_dir **untracked_,
@@ -2645,7 +2647,7 @@ static void read_stat(size_t pos, void *cb)
                rd->data = rd->end + 1;
                return;
        }
-       stat_data_from_disk(&ud->stat_data, (struct stat_data *)rd->data);
+       stat_data_from_disk(&ud->stat_data, rd->data);
        rd->data += sizeof(struct stat_data);
        ud->valid = 1;
 }
@@ -2663,22 +2665,22 @@ static void read_sha1(size_t pos, void *cb)
 }
 
 static void load_sha1_stat(struct sha1_stat *sha1_stat,
-                          const struct stat_data *stat,
+                          const unsigned char *data,
                           const unsigned char *sha1)
 {
-       stat_data_from_disk(&sha1_stat->stat, stat);
+       stat_data_from_disk(&sha1_stat->stat, data);
        hashcpy(sha1_stat->sha1, sha1);
        sha1_stat->valid = 1;
 }
 
 struct untracked_cache *read_untracked_extension(const void *data, unsigned long sz)
 {
-       const struct ondisk_untracked_cache *ouc;
        struct untracked_cache *uc;
        struct read_data rd;
        const unsigned char *next = data, *end = (const unsigned char *)data + sz;
        const char *ident;
        int ident_len, len;
+       const char *exclude_per_dir;
 
        if (sz <= 1 || end[-1] != '\0')
                return NULL;
@@ -2690,21 +2692,23 @@ struct untracked_cache *read_untracked_extension(const void *data, unsigned long
        ident = (const char *)next;
        next += ident_len;
 
-       ouc = (const struct ondisk_untracked_cache *)next;
        if (next + ouc_size(0) > end)
                return NULL;
 
        uc = xcalloc(1, sizeof(*uc));
        strbuf_init(&uc->ident, ident_len);
        strbuf_add(&uc->ident, ident, ident_len);
-       load_sha1_stat(&uc->ss_info_exclude, &ouc->info_exclude_stat,
-                      ouc->info_exclude_sha1);
-       load_sha1_stat(&uc->ss_excludes_file, &ouc->excludes_file_stat,
-                      ouc->excludes_file_sha1);
-       uc->dir_flags = get_be32(&ouc->dir_flags);
-       uc->exclude_per_dir = xstrdup(ouc->exclude_per_dir);
+       load_sha1_stat(&uc->ss_info_exclude,
+                      next + ouc_offset(info_exclude_stat),
+                      next + ouc_offset(info_exclude_sha1));
+       load_sha1_stat(&uc->ss_excludes_file,
+                      next + ouc_offset(excludes_file_stat),
+                      next + ouc_offset(excludes_file_sha1));
+       uc->dir_flags = get_be32(next + ouc_offset(dir_flags));
+       exclude_per_dir = (const char *)next + ouc_offset(exclude_per_dir);
+       uc->exclude_per_dir = xstrdup(exclude_per_dir);
        /* NUL after exclude_per_dir is covered by sizeof(*ouc) */
-       next += ouc_size(strlen(ouc->exclude_per_dir));
+       next += ouc_size(strlen(exclude_per_dir));
        if (next >= end)
                goto done2;
 
diff --git a/entry.c b/entry.c
index d6b263f..65458f0 100644 (file)
--- a/entry.c
+++ b/entry.c
@@ -137,6 +137,105 @@ static int streaming_write_entry(const struct cache_entry *ce, char *path,
        return result;
 }
 
+void enable_delayed_checkout(struct checkout *state)
+{
+       if (!state->delayed_checkout) {
+               state->delayed_checkout = xmalloc(sizeof(*state->delayed_checkout));
+               state->delayed_checkout->state = CE_CAN_DELAY;
+               string_list_init(&state->delayed_checkout->filters, 0);
+               string_list_init(&state->delayed_checkout->paths, 0);
+       }
+}
+
+static int remove_available_paths(struct string_list_item *item, void *cb_data)
+{
+       struct string_list *available_paths = cb_data;
+       struct string_list_item *available;
+
+       available = string_list_lookup(available_paths, item->string);
+       if (available)
+               available->util = (void *)item->string;
+       return !available;
+}
+
+int finish_delayed_checkout(struct checkout *state)
+{
+       int errs = 0;
+       struct string_list_item *filter, *path;
+       struct delayed_checkout *dco = state->delayed_checkout;
+
+       if (!state->delayed_checkout)
+               return errs;
+
+       dco->state = CE_RETRY;
+       while (dco->filters.nr > 0) {
+               for_each_string_list_item(filter, &dco->filters) {
+                       struct string_list available_paths = STRING_LIST_INIT_NODUP;
+
+                       if (!async_query_available_blobs(filter->string, &available_paths)) {
+                               /* Filter reported an error */
+                               errs = 1;
+                               filter->string = "";
+                               continue;
+                       }
+                       if (available_paths.nr <= 0) {
+                               /*
+                                * Filter responded with no entries. That means
+                                * the filter is done and we can remove the
+                                * filter from the list (see
+                                * "string_list_remove_empty_items" call below).
+                                */
+                               filter->string = "";
+                               continue;
+                       }
+
+                       /*
+                        * In dco->paths we store a list of all delayed paths.
+                        * The filter just send us a list of available paths.
+                        * Remove them from the list.
+                        */
+                       filter_string_list(&dco->paths, 0,
+                               &remove_available_paths, &available_paths);
+
+                       for_each_string_list_item(path, &available_paths) {
+                               struct cache_entry* ce;
+
+                               if (!path->util) {
+                                       error("external filter '%s' signaled that '%s' "
+                                             "is now available although it has not been "
+                                             "delayed earlier",
+                                             filter->string, path->string);
+                                       errs |= 1;
+
+                                       /*
+                                        * Do not ask the filter for available blobs,
+                                        * again, as the filter is likely buggy.
+                                        */
+                                       filter->string = "";
+                                       continue;
+                               }
+                               ce = index_file_exists(state->istate, path->string,
+                                                      strlen(path->string), 0);
+                               errs |= (ce ? checkout_entry(ce, state, NULL) : 1);
+                       }
+               }
+               string_list_remove_empty_items(&dco->filters, 0);
+       }
+       string_list_clear(&dco->filters, 0);
+
+       /* At this point we should not have any delayed paths anymore. */
+       errs |= dco->paths.nr;
+       for_each_string_list_item(path, &dco->paths) {
+               error("'%s' was not filtered properly", path->string);
+       }
+       string_list_clear(&dco->paths, 0);
+
+       free(dco);
+       state->delayed_checkout = NULL;
+
+       return errs;
+}
+
 static int write_entry(struct cache_entry *ce,
                       char *path, const struct checkout *state, int to_tempfile)
 {
@@ -179,11 +278,34 @@ static int write_entry(struct cache_entry *ce,
                /*
                 * Convert from git internal format to working tree format
                 */
-               if (ce_mode_s_ifmt == S_IFREG &&
-                   convert_to_working_tree(ce->name, new, size, &buf)) {
-                       free(new);
-                       new = strbuf_detach(&buf, &newsize);
-                       size = newsize;
+               if (ce_mode_s_ifmt == S_IFREG) {
+                       struct delayed_checkout *dco = state->delayed_checkout;
+                       if (dco && dco->state != CE_NO_DELAY) {
+                               /* Do not send the blob in case of a retry. */
+                               if (dco->state == CE_RETRY) {
+                                       new = NULL;
+                                       size = 0;
+                               }
+                               ret = async_convert_to_working_tree(
+                                       ce->name, new, size, &buf, dco);
+                               if (ret && string_list_has_string(&dco->paths, ce->name)) {
+                                       free(new);
+                                       goto finish;
+                               }
+                       } else
+                               ret = convert_to_working_tree(
+                                       ce->name, new, size, &buf);
+
+                       if (ret) {
+                               free(new);
+                               new = strbuf_detach(&buf, &newsize);
+                               size = newsize;
+                       }
+                       /*
+                        * No "else" here as errors from convert are OK at this
+                        * point. If the error would have been fatal (e.g.
+                        * filter is required), then we would have died already.
+                        */
                }
 
                fd = open_output_fd(path, ce, to_tempfile);
diff --git a/fsck.c b/fsck.c
index b4204d7..2d2d2e9 100644 (file)
--- a/fsck.c
+++ b/fsck.c
@@ -736,7 +736,7 @@ static int fsck_commit_buffer(struct commit *commit, const char *buffer,
                buffer += 41;
                parent_line_count++;
        }
-       graft = lookup_commit_graft(commit->object.oid.hash);
+       graft = lookup_commit_graft(&commit->object.oid);
        parent_count = commit_list_count(commit->parents);
        if (graft) {
                if (graft->nr_parent == -1 && !parent_count)
index db9c22d..7d2c0ca 100644 (file)
@@ -828,6 +828,14 @@ static inline void copy_array(void *dst, const void *src, size_t n, size_t size)
                memcpy(dst, src, st_mult(size, n));
 }
 
+#define MOVE_ARRAY(dst, src, n) move_array((dst), (src), (n), sizeof(*(dst)) + \
+       BUILD_ASSERT_OR_ZERO(sizeof(*(dst)) == sizeof(*(src))))
+static inline void move_array(void *dst, const void *src, size_t n, size_t size)
+{
+       if (n)
+               memmove(dst, src, st_mult(size, n));
+}
+
 /*
  * These functions help you allocate structs with flex arrays, and copy
  * the data directly into the array. For example, if you had:
index fe30be3..918a8de 100644 (file)
@@ -161,7 +161,9 @@ ifeq ($(uname_S),Darwin)
        endif
 endif
 ifneq (,$(findstring MINGW,$(uname_S)))
+ifeq ($(shell expr "$(uname_R)" : '1\.'),2)
        NO_MSGFMT=1
+endif
        GITGUI_WINDOWS_WRAPPER := YesPlease
        GITGUI_RELATIVE := 1
 endif
index 75d1da8..80f5a59 100644 (file)
@@ -142,6 +142,10 @@ constructor pick {} {
                                -label [mc "Recent Repositories"]
                }
 
+       if {[set lenrecent [llength $sorted_recent]] < $maxrecent} {
+               set lenrecent $maxrecent
+       }
+
                ${NS}::label $w_body.space
                ${NS}::label $w_body.recentlabel \
                        -anchor w \
@@ -153,7 +157,7 @@ constructor pick {} {
                        -background [get_bg_color $w_body.recentlabel] \
                        -wrap none \
                        -width 50 \
-                       -height $maxrecent
+                       -height $lenrecent
                $w_recentlist tag conf link \
                        -foreground blue \
                        -underline 1
@@ -235,19 +239,19 @@ method _invoke_next {} {
 
 proc _get_recentrepos {} {
        set recent [list]
-       foreach p [get_config gui.recentrepo] {
+       foreach p [lsort -unique [get_config gui.recentrepo]] {
                if {[_is_git [file join $p .git]]} {
                        lappend recent $p
                } else {
                        _unset_recentrepo $p
                }
        }
-       return [lsort $recent]
+       return $recent
 }
 
 proc _unset_recentrepo {p} {
        regsub -all -- {([()\[\]{}\.^$+*?\\])} $p {\\\1} p
-       git config --global --unset gui.recentrepo "^$p\$"
+       catch {git config --global --unset-all gui.recentrepo "^$p\$"}
        load_config 1
 }
 
@@ -262,12 +266,11 @@ proc _append_recentrepos {path} {
        set i [lsearch $recent $path]
        if {$i >= 0} {
                _unset_recentrepo $path
-               set recent [lreplace $recent $i $i]
        }
 
-       lappend recent $path
        git config --global --add gui.recentrepo $path
        load_config 1
+       set recent [get_config gui.recentrepo]
 
        if {[set maxrecent [get_config gui.maxrecentrepo]] eq {}} {
                set maxrecent 10
@@ -275,7 +278,7 @@ proc _append_recentrepos {path} {
 
        while {[llength $recent] > $maxrecent} {
                _unset_recentrepo [lindex $recent 0]
-               set recent [lrange $recent 1 end]
+               set recent [get_config gui.recentrepo]
        }
 }
 
index bcf0d92..6c390d6 100755 (executable)
@@ -100,7 +100,7 @@ do
        if test $? -ne 0
        then
                gettextln "Simple merge did not work, trying automatic merge."
-               git-merge-index -o git-merge-one-file -a ||
+               git merge-index -o git-merge-one-file -a ||
                OCTOPUS_FAILURE=1
                next=$(git write-tree 2>/dev/null)
        fi
index 424b034..9879c59 100755 (executable)
@@ -115,16 +115,16 @@ case "${1:-.}${2:-.}${3:-.}" in
                ;;
        esac
 
-       src1=$(git-unpack-file $2)
-       src2=$(git-unpack-file $3)
+       src1=$(git unpack-file $2)
+       src2=$(git unpack-file $3)
        case "$1" in
        '')
                echo "Added $4 in both, but differently."
-               orig=$(git-unpack-file e69de29bb2d1d6434b8b29ae775ad8c2e48c5391)
+               orig=$(git unpack-file e69de29bb2d1d6434b8b29ae775ad8c2e48c5391)
                ;;
        *)
                echo "Auto-merging $4"
-               orig=$(git-unpack-file $1)
+               orig=$(git unpack-file $1)
                ;;
        esac
 
index c9da747..343fe7b 100755 (executable)
@@ -45,7 +45,7 @@ then
        exit 0
 else
        echo "Simple merge failed, trying Automatic merge."
-       if git-merge-index -o git-merge-one-file -a
+       if git merge-index -o git-merge-one-file -a
        then
                exit 0
        else
index 3752393..319933e 100644 (file)
@@ -45,7 +45,7 @@ then
        # itself well to recording empty patches.  fortunately, cherry-pick
        # makes this easy
        git cherry-pick ${gpg_sign_opt:+"$gpg_sign_opt"} --allow-empty \
-               --right-only "$revisions" \
+               $allow_rerere_autoupdate --right-only "$revisions" \
                ${restrict_revision+^$restrict_revision}
        ret=$?
 else
@@ -82,6 +82,7 @@ else
        fi
 
        git am $git_am_opt --rebasing --resolvemsg="$resolvemsg" \
+               $allow_rerere_autoupdate \
                ${gpg_sign_opt:+"$gpg_sign_opt"} <"$GIT_DIR/rebased-patches"
        ret=$?
 
index 90b1fbe..29b7e88 100644 (file)
@@ -281,7 +281,7 @@ pick_one () {
 
        test -d "$rewritten" &&
                pick_one_preserving_merges "$@" && return
-       output eval git cherry-pick \
+       output eval git cherry-pick $allow_rerere_autoupdate \
                        ${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")} \
                        "$strategy_args" $empty_args $ff "$@"
 
@@ -393,7 +393,8 @@ pick_one_preserving_merges () {
                        merge_args="--no-log --no-ff"
                        if ! do_with_author output eval \
                        'git merge ${gpg_sign_opt:+"$gpg_sign_opt"} \
-                               $merge_args $strategy_args -m "$msg_content" $new_parents'
+                               $allow_rerere_autoupdate $merge_args \
+                               $strategy_args -m "$msg_content" $new_parents'
                        then
                                printf "%s\n" "$msg_content" > "$GIT_DIR"/MERGE_MSG
                                die_with_patch $sha1 "$(eval_gettext "Error redoing merge \$sha1")"
@@ -401,7 +402,7 @@ pick_one_preserving_merges () {
                        echo "$sha1 $(git rev-parse HEAD^0)" >> "$rewritten_list"
                        ;;
                *)
-                       output eval git cherry-pick \
+                       output eval git cherry-pick $allow_rerere_autoupdate \
                                ${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")} \
                                "$strategy_args" "$@" ||
                                die_with_patch $sha1 "$(eval_gettext "Could not pick \$sha1")"
index 2cf73b8..f8b3d1f 100755 (executable)
@@ -55,9 +55,10 @@ LF='
 '
 ok_to_skip_pre_rebase=
 resolvemsg="
-$(gettext 'When you have resolved this problem, run "git rebase --continue".
-If you prefer to skip this patch, run "git rebase --skip" instead.
-To check out the original branch and stop rebasing, run "git rebase --abort".')
+$(gettext 'Resolve all conflicts manually, mark them as resolved with
+"git add/rm <conflicted_files>", then run "git rebase --continue".
+You can instead skip this commit: run "git rebase --skip".
+To abort and get back to the state before "git rebase", run "git rebase --abort".')
 "
 unset onto
 unset restrict_revision
index 9b6c2da..9aa09c3 100755 (executable)
@@ -573,7 +573,7 @@ apply_stash () {
 
        if test -n "$u_tree"
        then
-               GIT_INDEX_FILE="$TMPindex" git-read-tree "$u_tree" &&
+               GIT_INDEX_FILE="$TMPindex" git read-tree "$u_tree" &&
                GIT_INDEX_FILE="$TMPindex" git checkout-index --all &&
                rm -f "$TMPindex" ||
                die "$(gettext "Could not restore untracked files from stash entry")"
index e131760..ffa2d66 100755 (executable)
@@ -864,7 +864,7 @@ cmd_summary() {
                                test $status != A && test $ignore_config = all && continue
                        fi
                        # Also show added or modified modules which are checked out
-                       GIT_DIR="$sm_path/.git" git-rev-parse --git-dir >/dev/null 2>&1 &&
+                       GIT_DIR="$sm_path/.git" git rev-parse --git-dir >/dev/null 2>&1 &&
                        printf '%s\n' "$sm_path"
                done
        )
@@ -898,11 +898,11 @@ cmd_summary() {
                missing_dst=
 
                test $mod_src = 160000 &&
-               ! GIT_DIR="$name/.git" git-rev-parse -q --verify $sha1_src^0 >/dev/null &&
+               ! GIT_DIR="$name/.git" git rev-parse -q --verify $sha1_src^0 >/dev/null &&
                missing_src=t
 
                test $mod_dst = 160000 &&
-               ! GIT_DIR="$name/.git" git-rev-parse -q --verify $sha1_dst^0 >/dev/null &&
+               ! GIT_DIR="$name/.git" git rev-parse -q --verify $sha1_dst^0 >/dev/null &&
                missing_dst=t
 
                display_name=$(git submodule--helper relative-path "$name" "$wt_prefix")
diff --git a/git.c b/git.c
index 489aab4..f31dca6 100644 (file)
--- a/git.c
+++ b/git.c
@@ -33,6 +33,16 @@ static void commit_pager_choice(void) {
        }
 }
 
+void setup_auto_pager(const char *cmd, int def)
+{
+       if (use_pager != -1 || pager_in_use())
+               return;
+       use_pager = check_pager_config(cmd);
+       if (use_pager == -1)
+               use_pager = def;
+       commit_pager_choice();
+}
+
 static int handle_options(const char ***argv, int *argc, int *envchanged)
 {
        const char **orig_argv = *argv;
@@ -283,6 +293,7 @@ static int handle_alias(int *argcp, const char ***argv)
  */
 #define NEED_WORK_TREE         (1<<3)
 #define SUPPORT_SUPER_PREFIX   (1<<4)
+#define DELAY_PAGER_CONFIG     (1<<5)
 
 struct cmd_struct {
        const char *cmd;
@@ -306,7 +317,8 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
                        prefix = setup_git_directory_gently(&nongit_ok);
                }
 
-               if (use_pager == -1 && p->option & (RUN_SETUP | RUN_SETUP_GENTLY))
+               if (use_pager == -1 && p->option & (RUN_SETUP | RUN_SETUP_GENTLY) &&
+                   !(p->option & DELAY_PAGER_CONFIG))
                        use_pager = check_pager_config(p->cmd);
                if (use_pager == -1 && p->option & USE_PAGER)
                        use_pager = 1;
@@ -392,7 +404,7 @@ static struct cmd_struct commands[] = {
        { "fsck-objects", cmd_fsck, RUN_SETUP },
        { "gc", cmd_gc, RUN_SETUP },
        { "get-tar-commit-id", cmd_get_tar_commit_id },
-       { "grep", cmd_grep, RUN_SETUP_GENTLY | SUPPORT_SUPER_PREFIX },
+       { "grep", cmd_grep, RUN_SETUP_GENTLY },
        { "hash-object", cmd_hash_object },
        { "help", cmd_help },
        { "index-pack", cmd_index_pack, RUN_SETUP_GENTLY },
@@ -454,7 +466,7 @@ static struct cmd_struct commands[] = {
        { "stripspace", cmd_stripspace },
        { "submodule--helper", cmd_submodule__helper, RUN_SETUP | SUPPORT_SUPER_PREFIX},
        { "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
-       { "tag", cmd_tag, RUN_SETUP },
+       { "tag", cmd_tag, RUN_SETUP | DELAY_PAGER_CONFIG },
        { "unpack-file", cmd_unpack_file, RUN_SETUP },
        { "unpack-objects", cmd_unpack_objects, RUN_SETUP },
        { "update-index", cmd_update_index, RUN_SETUP },
@@ -547,7 +559,7 @@ static void execv_dashed_external(const char **argv)
        if (get_super_prefix())
                die("%s doesn't support --super-prefix", argv[0]);
 
-       if (use_pager == -1)
+       if (use_pager == -1 && !is_builtin(argv[0]))
                use_pager = check_pager_config(argv[0]);
        commit_pager_choice();
 
index 3d4a8ee..9208f42 100755 (executable)
@@ -3071,6 +3071,8 @@ sub git_get_projects_list {
                                return if (m!^[/.]$!);
                                # only directories can be git repositories
                                return unless (-d $_);
+                               # need search permission
+                               return unless (-x $_);
                                # don't traverse too deep (Find is super slow on os x)
                                # $project_maxdepth excludes depth of $projectroot
                                if (($File::Find::name =~ tr!/!!) - $pfxdepth > $project_maxdepth) {
diff --git a/grep.c b/grep.c
index 2efec0e..45acd33 100644 (file)
--- a/grep.c
+++ b/grep.c
@@ -1927,16 +1927,6 @@ void grep_source_init(struct grep_source *gs, enum grep_source_type type,
        case GREP_SOURCE_FILE:
                gs->identifier = xstrdup(identifier);
                break;
-       case GREP_SOURCE_SUBMODULE:
-               if (!identifier) {
-                       gs->identifier = NULL;
-                       break;
-               }
-               /*
-                * FALL THROUGH
-                * If the identifier is non-NULL (in the submodule case) it
-                * will be a SHA1 that needs to be copied.
-                */
        case GREP_SOURCE_OID:
                gs->identifier = oiddup(identifier);
                break;
@@ -1959,7 +1949,6 @@ void grep_source_clear_data(struct grep_source *gs)
        switch (gs->type) {
        case GREP_SOURCE_FILE:
        case GREP_SOURCE_OID:
-       case GREP_SOURCE_SUBMODULE:
                FREE_AND_NULL(gs->buf);
                gs->size = 0;
                break;
@@ -2030,8 +2019,6 @@ static int grep_source_load(struct grep_source *gs)
                return grep_source_load_oid(gs);
        case GREP_SOURCE_BUF:
                return gs->buf ? 0 : -1;
-       case GREP_SOURCE_SUBMODULE:
-               break;
        }
        die("BUG: invalid grep_source type to load");
 }
diff --git a/grep.h b/grep.h
index 0c091e5..52aecfa 100644 (file)
--- a/grep.h
+++ b/grep.h
@@ -193,7 +193,6 @@ struct grep_source {
                GREP_SOURCE_OID,
                GREP_SOURCE_FILE,
                GREP_SOURCE_BUF,
-               GREP_SOURCE_SUBMODULE,
        } type;
        void *identifier;
 
diff --git a/http.c b/http.c
index c6c010f..76ff63c 100644 (file)
--- a/http.c
+++ b/http.c
@@ -272,10 +272,10 @@ static int http_options(const char *var, const char *value, void *cb)
        if (!strcmp("http.sslversion", var))
                return git_config_string(&ssl_version, var, value);
        if (!strcmp("http.sslcert", var))
-               return git_config_string(&ssl_cert, var, value);
+               return git_config_pathname(&ssl_cert, var, value);
 #if LIBCURL_VERSION_NUM >= 0x070903
        if (!strcmp("http.sslkey", var))
-               return git_config_string(&ssl_key, var, value);
+               return git_config_pathname(&ssl_key, var, value);
 #endif
 #if LIBCURL_VERSION_NUM >= 0x070908
        if (!strcmp("http.sslcapath", var))
index c1a79c1..cb921b4 100644 (file)
--- a/mailmap.c
+++ b/mailmap.c
@@ -214,17 +214,17 @@ static int read_mailmap_blob(struct string_list *map,
                             const char *name,
                             char **repo_abbrev)
 {
-       unsigned char sha1[20];
+       struct object_id oid;
        char *buf;
        unsigned long size;
        enum object_type type;
 
        if (!name)
                return 0;
-       if (get_sha1(name, sha1) < 0)
+       if (get_oid(name, &oid) < 0)
                return 0;
 
-       buf = read_sha1_file(sha1, &type, &size);
+       buf = read_sha1_file(oid.hash, &type, &size);
        if (!buf)
                return error("unable to read mailmap object at %s", name);
        if (type != OBJ_BLOB)
index 0e10f3e..bd8dc7a 100644 (file)
@@ -17,10 +17,14 @@ struct dir_entry {
 };
 
 static int dir_entry_cmp(const void *unused_cmp_data,
-                        const struct dir_entry *e1,
-                        const struct dir_entry *e2,
-                        const char *name)
+                        const void *entry,
+                        const void *entry_or_key,
+                        const void *keydata)
 {
+       const struct dir_entry *e1 = entry;
+       const struct dir_entry *e2 = entry_or_key;
+       const char *name = keydata;
+
        return e1->namelen != e2->namelen || strncasecmp(e1->name,
                        name ? name : e2->name, e1->namelen);
 }
@@ -110,10 +114,12 @@ static void hash_index_entry(struct index_state *istate, struct cache_entry *ce)
 }
 
 static int cache_entry_cmp(const void *unused_cmp_data,
-                          const struct cache_entry *ce1,
-                          const struct cache_entry *ce2,
+                          const void *entry,
+                          const void *entry_or_key,
                           const void *remove)
 {
+       const struct cache_entry *ce1 = entry;
+       const struct cache_entry *ce2 = entry_or_key;
        /*
         * For remove_name_hash, find the exact entry (pointer equality); for
         * index_file_exists, find all entries with matching hash code and
@@ -574,10 +580,8 @@ static void lazy_init_name_hash(struct index_state *istate)
 {
        if (istate->name_hash_initialized)
                return;
-       hashmap_init(&istate->name_hash, (hashmap_cmp_fn) cache_entry_cmp,
-                       NULL, istate->cache_nr);
-       hashmap_init(&istate->dir_hash, (hashmap_cmp_fn) dir_entry_cmp,
-                       NULL, istate->cache_nr);
+       hashmap_init(&istate->name_hash, cache_entry_cmp, NULL, istate->cache_nr);
+       hashmap_init(&istate->dir_hash, dir_entry_cmp, NULL, istate->cache_nr);
 
        if (lookup_lazy_params(istate)) {
                hashmap_disallow_rehash(&istate->dir_hash, 1);
index 70e3fbe..c12b354 100644 (file)
@@ -99,8 +99,7 @@ static struct notes_merge_pair *find_notes_merge_pair_pos(
        else {
                *occupied = 0;
                if (insert_new && i < len) {
-                       memmove(list + i + 1, list + i,
-                               (len - i) * sizeof(struct notes_merge_pair));
+                       MOVE_ARRAY(list + i + 1, list + i, len - i);
                        memset(list + i, 0, sizeof(struct notes_merge_pair));
                }
        }
diff --git a/notes.c b/notes.c
index 8f47c20..503754d 100644 (file)
--- a/notes.c
+++ b/notes.c
@@ -1026,7 +1026,7 @@ void init_notes(struct notes_tree *t, const char *notes_ref,
        t->dirty = 0;
 
        if (flags & NOTES_INIT_EMPTY || !notes_ref ||
-           get_sha1_treeish(notes_ref, object_oid.hash))
+           get_oid_treeish(notes_ref, &object_oid))
                return;
        if (flags & NOTES_INIT_WRITABLE && read_ref(notes_ref, object_oid.hash))
                die("Cannot use notes ref %s", notes_ref);
index f818777..321d7e9 100644 (file)
--- a/object.c
+++ b/object.c
@@ -141,7 +141,6 @@ void *create_object(const unsigned char *sha1, void *o)
        struct object *obj = o;
 
        obj->parsed = 0;
-       obj->used = 0;
        obj->flags = 0;
        hashcpy(obj->oid.hash, sha1);
 
index 33e5cc9..0a419ba 100644 (file)
--- a/object.h
+++ b/object.h
@@ -38,6 +38,7 @@ struct object_array {
  * http-push.c:                            16-----19
  * commit.c:                               16-----19
  * sha1_name.c:                                     20
+ * builtin/fsck.c:  0--3
  */
 #define FLAG_BITS  27
 
@@ -46,7 +47,6 @@ struct object_array {
  */
 struct object {
        unsigned parsed : 1;
-       unsigned used : 1;
        unsigned type : TYPE_BITS;
        unsigned flags : FLAG_BITS;
        struct object_id oid;
diff --git a/pager.c b/pager.c
index 4dd9e1b..92b23e6 100644 (file)
--- a/pager.c
+++ b/pager.c
@@ -194,7 +194,7 @@ static int pager_command_config(const char *var, const char *value, void *vdata)
        const char *cmd;
 
        if (skip_prefix(var, "pager.", &cmd) && !strcmp(cmd, data->cmd)) {
-               int b = git_config_maybe_bool(var, value);
+               int b = git_parse_maybe_bool(value);
                if (b >= 0)
                        data->want = b;
                else {
index b4166b0..7a583b3 100644 (file)
@@ -35,11 +35,16 @@ int commit_patch_id(struct commit *commit, struct diff_options *options,
  * the side of safety.  The actual value being negative does not have
  * any significance; only that it is non-zero matters.
  */
-static int patch_id_cmp(struct diff_options *opt,
-                       struct patch_id *a,
-                       struct patch_id *b,
+static int patch_id_cmp(const void *cmpfn_data,
+                       const void *entry,
+                       const void *entry_or_key,
                        const void *unused_keydata)
 {
+       /* NEEDSWORK: const correctness? */
+       struct diff_options *opt = (void *)cmpfn_data;
+       struct patch_id *a = (void *)entry;
+       struct patch_id *b = (void *)entry_or_key;
+
        if (is_null_oid(&a->patch_id) &&
            commit_patch_id(a->commit, opt, &a->patch_id, 0))
                return error("Could not get patch ID for %s",
@@ -58,8 +63,7 @@ int init_patch_ids(struct patch_ids *ids)
        ids->diffopts.detect_rename = 0;
        DIFF_OPT_SET(&ids->diffopts, RECURSIVE);
        diff_setup_done(&ids->diffopts);
-       hashmap_init(&ids->patches, (hashmap_cmp_fn)patch_id_cmp,
-                    &ids->diffopts, 256);
+       hashmap_init(&ids->patches, patch_id_cmp, &ids->diffopts, 256);
        return 0;
 }
 
index f4b56e6..ffa09ac 100644 (file)
@@ -532,7 +532,7 @@ If TIME is not supplied, the current local time is used.
 =cut
 
 sub get_tz_offset {
-       # some systmes don't handle or mishandle %z, so be creative.
+       # some systems don't handle or mishandle %z, so be creative.
        my $t = shift || time;
        my $gm = timegm(localtime($t));
        my $sign = qw( + + - )[ $gm <=> $t ];
index 98518f4..bc4eed3 100644 (file)
@@ -1416,7 +1416,7 @@ sub parse_svn_date {
                        delete $ENV{TZ};
                }
 
-               my $our_TZ = get_tz_offset();
+               my $our_TZ = get_tz_offset($epoch_in_UTC);
 
                # This converts $epoch_in_UTC into our local timezone.
                my ($sec, $min, $hour, $mday, $mon, $year,
index 9d845ec..7db9119 100644 (file)
@@ -171,25 +171,6 @@ int packet_write_fmt_gently(int fd, const char *fmt, ...)
        return status;
 }
 
-int packet_writel(int fd, const char *line, ...)
-{
-       va_list args;
-       int err;
-       va_start(args, line);
-       for (;;) {
-               if (!line)
-                       break;
-               if (strlen(line) > LARGE_PACKET_DATA_MAX)
-                       return -1;
-               err = packet_write_fmt_gently(fd, "%s\n", line);
-               if (err)
-                       return err;
-               line = va_arg(args, const char*);
-       }
-       va_end(args);
-       return packet_flush_gently(fd);
-}
-
 static int packet_write_gently(const int fd_out, const char *buf, size_t size)
 {
        static char packet_write_buffer[LARGE_PACKET_MAX];
index 450183b..66ef610 100644 (file)
@@ -25,8 +25,6 @@ void packet_buf_flush(struct strbuf *buf);
 void packet_buf_write(struct strbuf *buf, const char *fmt, ...) __attribute__((format (printf, 2, 3)));
 int packet_flush_gently(int fd);
 int packet_write_fmt_gently(int fd, const char *fmt, ...) __attribute__((format (printf, 2, 3)));
-LAST_ARG_MUST_BE_NULL
-int packet_writel(int fd, const char *line, ...);
 int write_packetized_from_fd(int fd_in, int fd_out);
 int write_packetized_from_buf(const char *src_in, size_t len, int fd_out);
 
index e4b561c..39cad51 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -947,6 +947,7 @@ static size_t parse_color(struct strbuf *sb, /* in UTF-8 */
                          struct format_commit_context *c)
 {
        const char *rest = placeholder;
+       const char *basic_color = NULL;
 
        if (placeholder[1] == '(') {
                const char *begin = placeholder + 2;
@@ -955,23 +956,41 @@ static size_t parse_color(struct strbuf *sb, /* in UTF-8 */
 
                if (!end)
                        return 0;
+
                if (skip_prefix(begin, "auto,", &begin)) {
                        if (!want_color(c->pretty_ctx->color))
                                return end - placeholder + 1;
+               } else if (skip_prefix(begin, "always,", &begin)) {
+                       /* nothing to do; we do not respect want_color at all */
+               } else {
+                       /* the default is the same as "auto" */
+                       if (!want_color(c->pretty_ctx->color))
+                               return end - placeholder + 1;
                }
+
                if (color_parse_mem(begin, end - begin, color) < 0)
                        die(_("unable to parse --pretty format"));
                strbuf_addstr(sb, color);
                return end - placeholder + 1;
        }
+
+       /*
+        * We handle things like "%C(red)" above; for historical reasons, there
+        * are a few colors that can be specified without parentheses (and
+        * they cannot support things like "auto" or "always" at all).
+        */
        if (skip_prefix(placeholder + 1, "red", &rest))
-               strbuf_addstr(sb, GIT_COLOR_RED);
+               basic_color = GIT_COLOR_RED;
        else if (skip_prefix(placeholder + 1, "green", &rest))
-               strbuf_addstr(sb, GIT_COLOR_GREEN);
+               basic_color = GIT_COLOR_GREEN;
        else if (skip_prefix(placeholder + 1, "blue", &rest))
-               strbuf_addstr(sb, GIT_COLOR_BLUE);
+               basic_color = GIT_COLOR_BLUE;
        else if (skip_prefix(placeholder + 1, "reset", &rest))
-               strbuf_addstr(sb, GIT_COLOR_RESET);
+               basic_color = GIT_COLOR_RESET;
+
+       if (basic_color && want_color(c->pretty_ctx->color))
+               strbuf_addstr(sb, basic_color);
+
        return rest - placeholder;
 }
 
index 2121b6e..acfb028 100644 (file)
@@ -515,9 +515,8 @@ int remove_index_entry_at(struct index_state *istate, int pos)
        istate->cache_nr--;
        if (pos >= istate->cache_nr)
                return 0;
-       memmove(istate->cache + pos,
-               istate->cache + pos + 1,
-               (istate->cache_nr - pos) * sizeof(struct cache_entry *));
+       MOVE_ARRAY(istate->cache + pos, istate->cache + pos + 1,
+                  istate->cache_nr - pos);
        return 1;
 }
 
index ae6ecbd..bc591f4 100644 (file)
@@ -97,14 +97,19 @@ static struct used_atom {
        } u;
 } *used_atom;
 static int used_atom_cnt, need_tagged, need_symref;
-static int need_color_reset_at_eol;
 
-static void color_atom_parser(struct used_atom *atom, const char *color_value)
+static void color_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *color_value)
 {
        if (!color_value)
                die(_("expected format: %%(color:<color>)"));
        if (color_parse(color_value, atom->u.color) < 0)
                die(_("unrecognized color: %%(color:%s)"), color_value);
+       /*
+        * We check this after we've parsed the color, which lets us complain
+        * about syntactically bogus color names even if they won't be used.
+        */
+       if (!want_color(format->use_color))
+               color_parse("", atom->u.color);
 }
 
 static void refname_atom_parser_internal(struct refname_atom *atom,
@@ -127,7 +132,7 @@ static void refname_atom_parser_internal(struct refname_atom *atom,
                die(_("unrecognized %%(%s) argument: %s"), name, arg);
 }
 
-static void remote_ref_atom_parser(struct used_atom *atom, const char *arg)
+static void remote_ref_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
 {
        struct string_list params = STRING_LIST_INIT_DUP;
        int i;
@@ -161,28 +166,28 @@ static void remote_ref_atom_parser(struct used_atom *atom, const char *arg)
        string_list_clear(&params, 0);
 }
 
-static void body_atom_parser(struct used_atom *atom, const char *arg)
+static void body_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
 {
        if (arg)
                die(_("%%(body) does not take arguments"));
        atom->u.contents.option = C_BODY_DEP;
 }
 
-static void subject_atom_parser(struct used_atom *atom, const char *arg)
+static void subject_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
 {
        if (arg)
                die(_("%%(subject) does not take arguments"));
        atom->u.contents.option = C_SUB;
 }
 
-static void trailers_atom_parser(struct used_atom *atom, const char *arg)
+static void trailers_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
 {
        if (arg)
                die(_("%%(trailers) does not take arguments"));
        atom->u.contents.option = C_TRAILERS;
 }
 
-static void contents_atom_parser(struct used_atom *atom, const char *arg)
+static void contents_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
 {
        if (!arg)
                atom->u.contents.option = C_BARE;
@@ -202,7 +207,7 @@ static void contents_atom_parser(struct used_atom *atom, const char *arg)
                die(_("unrecognized %%(contents) argument: %s"), arg);
 }
 
-static void objectname_atom_parser(struct used_atom *atom, const char *arg)
+static void objectname_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
 {
        if (!arg)
                atom->u.objectname.option = O_FULL;
@@ -219,7 +224,7 @@ static void objectname_atom_parser(struct used_atom *atom, const char *arg)
                die(_("unrecognized %%(objectname) argument: %s"), arg);
 }
 
-static void refname_atom_parser(struct used_atom *atom, const char *arg)
+static void refname_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
 {
        refname_atom_parser_internal(&atom->u.refname, arg, atom->name);
 }
@@ -235,7 +240,7 @@ static align_type parse_align_position(const char *s)
        return -1;
 }
 
-static void align_atom_parser(struct used_atom *atom, const char *arg)
+static void align_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
 {
        struct align *align = &atom->u.align;
        struct string_list params = STRING_LIST_INIT_DUP;
@@ -274,7 +279,7 @@ static void align_atom_parser(struct used_atom *atom, const char *arg)
        string_list_clear(&params, 0);
 }
 
-static void if_atom_parser(struct used_atom *atom, const char *arg)
+static void if_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
 {
        if (!arg) {
                atom->u.if_then_else.cmp_status = COMPARE_NONE;
@@ -288,7 +293,7 @@ static void if_atom_parser(struct used_atom *atom, const char *arg)
        }
 }
 
-static void head_atom_parser(struct used_atom *atom, const char *arg)
+static void head_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
 {
        struct object_id unused;
 
@@ -298,7 +303,7 @@ static void head_atom_parser(struct used_atom *atom, const char *arg)
 static struct {
        const char *name;
        cmp_type cmp_type;
-       void (*parser)(struct used_atom *atom, const char *arg);
+       void (*parser)(const struct ref_format *format, struct used_atom *atom, const char *arg);
 } valid_atom[] = {
        { "refname" , FIELD_STR, refname_atom_parser },
        { "objecttype" },
@@ -365,7 +370,8 @@ struct atom_value {
 /*
  * Used to parse format string and sort specifiers
  */
-int parse_ref_filter_atom(const char *atom, const char *ep)
+static int parse_ref_filter_atom(const struct ref_format *format,
+                                const char *atom, const char *ep)
 {
        const char *sp;
        const char *arg;
@@ -413,7 +419,7 @@ int parse_ref_filter_atom(const char *atom, const char *ep)
                arg = used_atom[at].name + (arg - atom) + 1;
        memset(&used_atom[at].u, 0, sizeof(used_atom[at].u));
        if (valid_atom[i].parser)
-               valid_atom[i].parser(&used_atom[at], arg);
+               valid_atom[i].parser(format, &used_atom[at], arg);
        if (*atom == '*')
                need_tagged = 1;
        if (!strcmp(valid_atom[i].name, "symref"))
@@ -657,24 +663,26 @@ static const char *find_next(const char *cp)
  * Make sure the format string is well formed, and parse out
  * the used atoms.
  */
-int verify_ref_format(const char *format)
+int verify_ref_format(struct ref_format *format)
 {
        const char *cp, *sp;
 
-       need_color_reset_at_eol = 0;
-       for (cp = format; *cp && (sp = find_next(cp)); ) {
+       format->need_color_reset_at_eol = 0;
+       for (cp = format->format; *cp && (sp = find_next(cp)); ) {
                const char *color, *ep = strchr(sp, ')');
                int at;
 
                if (!ep)
                        return error(_("malformed format string %s"), sp);
                /* sp points at "%(" and ep points at the closing ")" */
-               at = parse_ref_filter_atom(sp + 2, ep);
+               at = parse_ref_filter_atom(format, sp + 2, ep);
                cp = ep + 1;
 
                if (skip_prefix(used_atom[at].name, "color:", &color))
-                       need_color_reset_at_eol = !!strcmp(color, "reset");
+                       format->need_color_reset_at_eol = !!strcmp(color, "reset");
        }
+       if (format->need_color_reset_at_eol && !want_color(format->use_color))
+               format->need_color_reset_at_eol = 0;
        return 0;
 }
 
@@ -2060,35 +2068,34 @@ static void append_literal(const char *cp, const char *ep, struct ref_formatting
        }
 }
 
-void format_ref_array_item(struct ref_array_item *info, const char *format,
-                          int quote_style, struct strbuf *final_buf)
+void format_ref_array_item(struct ref_array_item *info,
+                          const struct ref_format *format,
+                          struct strbuf *final_buf)
 {
        const char *cp, *sp, *ep;
        struct ref_formatting_state state = REF_FORMATTING_STATE_INIT;
 
-   &n