Sync with maint
authorJunio C Hamano <gitster@pobox.com>
Wed, 23 Aug 2017 21:36:38 +0000 (14:36 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 23 Aug 2017 21:36:38 +0000 (14:36 -0700)
* maint:
Prepare for 2.14.2

144 files changed:
Documentation/RelNotes/2.15.0.txt [new file with mode: 0644]
Documentation/config.txt
Documentation/git-branch.txt
Documentation/git-for-each-ref.txt
Documentation/git-format-patch.txt
Documentation/git-grep.txt
Documentation/git-push.txt
Documentation/git-send-pack.txt
Documentation/git-tag.txt
Documentation/git.txt
Documentation/githooks.txt
Documentation/technical/api-builtin.txt [deleted file]
Documentation/technical/api-config.txt
GIT-VERSION-GEN
Makefile
RelNotes
apply.c
apply.h
archive.c
attr.c
bisect.c
builtin.h
builtin/add.c
builtin/am.c
builtin/cat-file.c
builtin/clean.c
builtin/clone.c
builtin/commit-tree.c
builtin/commit.c
builtin/describe.c
builtin/difftool.c
builtin/fetch.c
builtin/fsck.c
builtin/grep.c
builtin/log.c
builtin/merge-tree.c
builtin/merge.c
builtin/mv.c
builtin/notes.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.h
commit.c
commit.h
compat/win32/syslog.c
config.c
config.h
contrib/contacts/git-contacts
contrib/rerere-train.sh
convert.c
diff.c
fsck.c
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
grep.c
grep.h
mailmap.c
name-hash.c
notes.c
pager.c
patch-ids.c
perl/Git.pm
perl/Git/SVN.pm
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
sequencer.c
setup.c
sha1-lookup.c
sha1_file.c
sha1_name.c
shallow.c
strbuf.c
strbuf.h
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/t1002-read-tree-m-u-2way.sh
t/t1200-tutorial.sh [deleted file]
t/t1408-packed-refs.sh [new file with mode: 0755]
t/t3210-pack-refs.sh
t/t3418-rebase-continue.sh
t/t3504-cherry-pick-rerere.sh
t/t3700-add.sh
t/t3905-stash-include-untracked.sh
t/t4062-diff-pickaxe.sh
t/t4150-am.sh
t/t4202-log.sh
t/t5308-pack-detect-duplicates.sh
t/t5520-pull.sh
t/t5526-fetch-submodules.sh
t/t5531-deep-submodule-push.sh
t/t5534-push-signed.sh
t/t6018-rev-list-glob.sh
t/t7004-tag.sh
t/t7006-pager.sh
t/t7301-clean-interactive.sh
t/t7400-submodule-basic.sh
t/t7810-grep.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..2fd4997
--- /dev/null
@@ -0,0 +1,220 @@
+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).
+
+ * "git rebase", especially when it is run by mistake and ends up
+   trying to replay many changes, spent long time in silence.  The
+   command has been taught to show progress report when it spends
+   long time preparing these many changes to replay (which would give
+   the user a chance to abort with ^C).
+
+
+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.
+
+ * "git commit" used to discard the index and re-read from the filesystem
+   just in case the pre-commit hook has updated it in the middle; this
+   has been optimized out when we know we do not run the pre-commit hook.
+   (merge 680ee550d7 kw/commit-keep-index-when-pre-commit-is-not-run later to maint).
+
+
+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).
+
+ * "git stash -u" used the contents of the committed version of the
+   ".gitignore" file to decide which paths are ignored, even when the
+   file has local changes.  The command has been taught to instead use
+   the locally modified contents.
+
+ * bash 4.4 or newer gave a warning on NUL byte in command
+   substitution done in "git stash"; this has been squelched.
+   (merge 5fc92f8828 kd/stash-with-bash-4.4 later to maint).
+
+ * "git grep -L" and "git grep --quiet -L" reported different exit
+   codes; this has been corrected.
+   (merge e1f68c66d5 as/grep-quiet-no-match-exit-code-fix 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).
+   (merge 7f0a02be2f ah/doc-empty-string-is-false later to maint).
+   (merge 70ec6bd63b rs/t1002-do-not-use-sum later to maint).
+   (merge 2456990dfd sb/sha1-file-cleanup later to maint).
+   (merge 2aac933c62 hv/t5526-andand-chain-fix later to maint).
+   (merge c8d0c4fe9b sb/submodule-parallel-update later to maint).
+   (merge 794b7e1674 mg/format-ref-doc-fix later to maint).
index d5c9c4cab60531d178d5c11d623a5c3f1036a0d0..478b9431e0933cc2031e1be01aeab98faa9f55c0 100644 (file)
@@ -216,15 +216,15 @@ boolean::
        synonyms are accepted for 'true' and 'false'; these are all
        case-insensitive.
 
-       true;; Boolean true can be spelled as `yes`, `on`, `true`,
-               or `1`.  Also, a variable defined without `= <value>`
+       true;; Boolean true literals are `yes`, `on`, `true`,
+               and `1`.  Also, a variable defined without `= <value>`
                is taken as true.
 
-       false;; Boolean false can be spelled as `no`, `off`,
-               `false`, or `0`.
+       false;; Boolean false literals are `no`, `off`, `false`,
+               `0` and the empty string.
 +
 When converting value to the canonical form using `--bool` type
-specifier; 'git config' will ensure that the output is "true" or
+specifier, 'git config' will ensure that the output is "true" or
 "false" (spelled in lowercase).
 
 integer::
index 81bd0a7b7741f175cf7a99e2aa9cbcacf42da78e..d0b33587717a198655164f5dd5e35e116a8a30e0 100644 (file)
@@ -267,8 +267,8 @@ start-point is either a local or remote-tracking branch.
        Only list branches of the given object.
 
 --format <format>::
-       A string that interpolates `%(fieldname)` from the object
-       pointed at by a ref being shown.  The format is the same as
+       A string that interpolates `%(fieldname)` from a branch ref being shown
+       and the object it points at.  The format is the same as
        that of linkgit:git-for-each-ref[1].
 
 Examples
index cc42c128323d32bd1a9bf47688722321857a5d65..bb370c9c7b91425ad939383d8b28c5fbbb73cbac 100644 (file)
@@ -38,11 +38,12 @@ OPTIONS
        key.
 
 <format>::
-       A string that interpolates `%(fieldname)` from the
-       object pointed at by a ref being shown.  If `fieldname`
+       A string that interpolates `%(fieldname)` from a ref being shown
+       and the object it points at.  If `fieldname`
        is prefixed with an asterisk (`*`) and the ref points
-       at a tag object, the value for the field in the object
-       tag refers is used.  When unspecified, defaults to
+       at a tag object, use the value for the field in the object
+       which the tag object refers to (instead of the field in the tag object).
+       When unspecified, `<format>` defaults to
        `%(objectname) SPC %(objecttype) TAB %(refname)`.
        It also interpolates `%%` to `%`, and `%xx` where `xx`
        are hex digits interpolates to character with hex code
index c890328b02ec4c3a28aaeb8aa057d327c75b9967..6cbe462a77467b05561938ff9cf8e9dcebd42efe 100644 (file)
@@ -23,6 +23,7 @@ SYNOPSIS
                   [(--reroll-count|-v) <n>]
                   [--to=<email>] [--cc=<email>]
                   [--[no-]cover-letter] [--quiet] [--notes[=<ref>]]
+                  [--progress]
                   [<common diff options>]
                   [ <since> | <revision range> ]
 
@@ -283,6 +284,9 @@ you can use `--suffix=-patch` to get `0001-description-of-my-change-patch`.
        range are always formatted as creation patches, independently
        of this flag.
 
+--progress::
+       Show progress reports on stderr as patches are generated.
+
 CONFIGURATION
 -------------
 You can specify extra mail header lines to be added to each message,
index 5033483db496286910dd24507f3374e18ff6c2b5..720c7850e2790bf18a3c493977a2703cbeab048a 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 0a639664fd67f497b1597cf903015a284947509d..3e76e99f38f67a530d43e2da3b3129c2a99e3366 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 966abb0df807c79714a18d8b106390caae45cf89..f51c64939b48b7b082752a294b17aee6d92c4fa0 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 1eb15afa1ce8a533d65c5f5ace0bcd694d7f6ffd..543fb425ee7c1d4c09a5ad4afbd00b9b812e4871 100644 (file)
@@ -188,8 +188,8 @@ This option is only applicable when listing tags without annotation lines.
        Defaults to HEAD.
 
 <format>::
-       A string that interpolates `%(fieldname)` from the object
-       pointed at by a ref being shown.  The format is the same as
+       A string that interpolates `%(fieldname)` from a tag ref being shown
+       and the object it points at.  The format is the same as
        that of linkgit:git-for-each-ref[1].  When unspecified,
        defaults to `%(refname:strip=2)`.
 
@@ -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 7dd5e03280b09f21f59289b0b00cd6fdee0ca3cb..6e3a6767e5f0ce347b2363cc7829d8eab042ae0a 100644 (file)
@@ -75,7 +75,8 @@ example the following invocations are equivalent:
 Note that omitting the `=` in `git -c foo.bar ...` is allowed and sets
 `foo.bar` to the boolean true value (just like `[foo]bar` would in a
 config file). Including the equals but with an empty value (like `git -c
-foo.bar= ...`) sets `foo.bar` to the empty string.
+foo.bar= ...`) sets `foo.bar` to the empty string which ` git config
+--bool` will convert to `false`.
 
 --exec-path[=<path>]::
        Path to wherever your core Git programs are installed.
index b2514f4d4426a730e65bcae264a6364eb50bcd60..623ed1a13829188971531aa62c6e109e9d29ec44 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
 ~~~~~~~~~~
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 20741f345e459f41d357039496f7d6be30edab06..7a83a3a6e2c8fde8754fa9be4e1b218beca6bc89 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.
 
index 1ab52e381e2f4e6bfb0e4d08fd339aee9b891c8d..75beb2e7750f82db233c8365f0ba2223ca4e2486 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v2.14.2
+DEF_VER=v2.14.GIT
 
 LF='
 '
index 461c845d33cbc5f201096ea4b3e1048492cb0a6a..86ec29202b5c88f5a7636d7d167eb4d8c892a2a1 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 29ef98331028ae5b1cdc10be75626e48b173a961..80ae7a3110de6bd298cfa9d8481808d0af5e7d2d 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.14.2.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 40707ca50c50331c392ab51375a83f4fb97edee1..956f56a9272c901ebd9087fcb6f1f9bea09b0782 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;
        }
 
@@ -3548,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."));
 
@@ -4072,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 b3d6783d55344de5aaa3d4b81a22abed0b6972fb..d9b395770364b5495fc1136248efd64bd3a5e66d 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 60b3035a7a6a9e7c2e69b4ba7de00ebdf8bfdbb8..557dd2db85ff261ee00ec50ea0bfe286bff7bda3 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 56961f02361129b5cb49e6ffb7ab185655f09c41..2f49151736095cf2e2a76ea91d72743df3778a5d 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 a9fd9fbc61a661ab19e18713b115f868daab2f98..2549eaf7b15152a9c130e63e44c8d8f4fc865233 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 498ac80d07bc5b00a9c66e9e62449d7700bc7550..42378f3aa471eb79594d96736ad2410b54d6c4dd 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 e888fb8c5f2a1fa2be33e834724460dec8072726..5d5773d5cd2fc9e713498a72da7b57b84fd25d19 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 c973bd96dcb5d630d56e935733bfa4530ccd2872..81095dae029836febd8bfb5504fdb39866ed5cf6 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 96b786e4892aec0ed7e5d07ac8d3261c7b765f33..62c8cf0ebf3f2ba063945fc44714a9da29b599ef 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 c1bafda5b63324b0aba7400535cc0ba745e46004..21a7a3299408ac507917ac13f9342e3148ac53ec 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
index 08b5cc433c6fcad5eea2dfc3321aea28a599d51f..f7e17d22951cfd8e498143c009fa0303d0ff8319 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 a4a923d7c0b688e162c8e4d0411ff9b72748fb5c..19e898fa4e46da9271de950ad9add75af2051ed6 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 1a0da71a43cfef8818b52a3d27131e340725cef2..b79bcfd5b9331f79b660940bb4029aa96041d80e 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++)
@@ -940,13 +940,16 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
                return 0;
        }
 
-       /*
-        * Re-read the index as pre-commit hook could have updated it,
-        * and write it out as a tree.  We must do this before we invoke
-        * the editor and after we invoke run_status above.
-        */
-       discard_cache();
+       if (!no_verify && find_hook("pre-commit")) {
+               /*
+                * Re-read the index as pre-commit hook could have updated it,
+                * and write it out as a tree.  We must do this before we invoke
+                * the editor and after we invoke run_status above.
+                */
+               discard_cache();
+       }
        read_cache_from(index_file);
+
        if (update_main_cache_tree(0)) {
                error(_("Error building trees"));
                return 0;
@@ -1387,7 +1390,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 +1660,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");
index 89ea1cdd60a215473ecb52ff2a4ce51932e1cf6d..9c13c6817bd784fb9c0e3eff781911577ef7ef8c 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 a1a26ba8912f4ee49527b287657826440fd92e9e..8864d846f89846669a5403d3a9436aa784d47be2 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 c87e59f3b1def1f064e0dae54a14e310c06df1fa..d84c26391c59cddb57d278b81f69ddf72af01fa8 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 64542ac3dea48e3a92901319233aa3a1e0c4cb9a..b0964a8d3499a6a288985f92ade5568356bd6a56 100644 (file)
@@ -326,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;
@@ -336,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));
        }
@@ -365,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,
@@ -730,12 +730,12 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
 
        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;
                        }
index 42ff87065a0e72c999488d2844463f901fd73a5c..a70d8e2fba9f4e371a069bd801d20dcfe195f485 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);
        }
@@ -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 5ffc380bd71f0ab8b5bec06f864e9cdcffda1e2f..25c0808409abce661d89896ceef490f15bb0b57e 100644 (file)
@@ -27,6 +27,7 @@
 #include "version.h"
 #include "mailmap.h"
 #include "gpg-interface.h"
+#include "progress.h"
 
 /* Set a default date-time format for git log ("log.date" config variable) */
 static const char *default_date_mode = NULL;
@@ -58,9 +59,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 +83,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;
 
@@ -412,7 +413,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;
@@ -487,8 +488,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)) {
@@ -824,7 +825,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);
@@ -1422,6 +1423,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
        char *branch_name = NULL;
        char *base_commit = NULL;
        struct base_tree_info bases;
+       int show_progress = 0;
+       struct progress *progress = NULL;
 
        const struct option builtin_format_patch_options[] = {
                { OPTION_CALLBACK, 'n', "numbered", &numbered, NULL,
@@ -1493,6 +1496,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                OPT_FILENAME(0, "signature-file", &signature_file,
                                N_("add a signature from a file")),
                OPT__QUIET(&quiet, N_("don't print the patch filenames")),
+               OPT_BOOL(0, "progress", &show_progress,
+                        N_("show progress while generating patches")),
                OPT_END()
        };
 
@@ -1752,8 +1757,12 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                start_number--;
        }
        rev.add_signoff = do_signoff;
+
+       if (show_progress)
+               progress = start_progress_delay(_("Generating patches"), total, 0, 2);
        while (0 <= --nr) {
                int shown;
+               display_progress(progress, total - nr);
                commit = list[nr];
                rev.nr = total - nr + (start_number - 1);
                /* Make the second and subsequent mails replies to the first */
@@ -1818,6 +1827,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                if (!use_stdout)
                        fclose(rev.diffopt.file);
        }
+       stop_progress(&progress);
        free(list);
        free(branch_name);
        string_list_clear(&extra_to, 0);
index bad6735c76fd0647547edfd1201d91c3c86dfc8f..f12da292cf91b1ecb9fc785fd50bd1ef83b361e9 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 d5797b8fe77c99c89323348f3a0bd1d68ae9b453..328945d6093aae40410b0c437a21c588ac6d6692 100644 (file)
@@ -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 dcf6736b5b4c53989ee1fb3c5240e04f5dbb337d..94fbaaa5dac65cc062429225e22a3586f9997156 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 77573cf1ea8cb4d998597e265263487e22fde592..4303848e044c9f9c6a12236d887a521316b4fc05 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 9b86e519b19a6180e52fda3342dec4f080e1f9e9..7fe281414eceaae64926caca2b6194c9fcfef299 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 03846e83795c477c8e802d078c5a5ed77140d550..2ac81042292ef1852ec9a31dea34ec91a1b796e3 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 cabdc55e0933adb09d459a5a0747c718fd2c7d1e..14b6e09b42f1d423307c98275f5b203078b82445 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 6273c0c23c904d5f789ff794458cf0c3f2661d94..a995ea86c17474be248a974469f7d535c942fc70 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 fba336a68a375e20e9b40d332eb58a3f302249fa..f4a85a165bbff187f331a0a4675066fc5f7b4316 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 7aeaea2737991f021eb788708c1710305abb4b08..046403ed6881f452271c636e935ad3ab05da0b78 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 e8f50489038644ef7a6dc0d217563c65fa9d6083..95b4128250c850eb130fbdfea2407bad819a85b8 100644 (file)
@@ -352,7 +352,8 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
 
        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 c78b7b33d6604bb38a16e30d64cfabee0fd67f40..2bd28d3c085c9f7f86072bb7e1aae443aee745e6 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 16028b9ea82edee9cf41044c69a47e8994d78fc6..b9d927eb09c9ed87c84681df1396f4e6d9b13c97 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 52826d137935ca6698006258ebdb8b207f7161df..4057e73fa04bee9fce10911955c8a43d118ef573 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 633e0c3cdd3171e6e51944c5b68e4a4afa48862e..fc4f0bb5fbc033604a13a147094c0d1bc661db17 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 28f245c8cccbc20c96a189516e9df77d238c7e96..84547d6fba07cb7770d94e80cda170c391d04a21 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;
        }
@@ -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 3a3c9ca72b678f1a446013cc17cc36caa3e47355..0ff9dd0b85074dfe6e04b6fc56c04f2c1789f7eb 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,
@@ -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 66e35b823b6e0a3e732fb84e402dd0af6830a471..c627794181f55d293719e5369d74bb9b598f5450 100644 (file)
@@ -113,7 +113,7 @@ static int verify_tag(const char *name, const char *ref,
        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 (format->format)
@@ -440,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);
 
index 73f133419167840d150300faa696bc32027cd02f..281ca1db6ce13ddb4cc227ebb7ea454176e8e9e1 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 40ccfc193bf785cfae0f83526c561eedf0d310bc..6b90c5deadb62600aa08166f500bde24cb800fbf 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 87d73e856a13e4abaa67ee8cad3e520f1bd9f779..ad7b79fa5cd718daf3be5f1a46a1fbb2bed41ad5 100644 (file)
@@ -58,20 +58,21 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix)
        }
 
        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 (format.format)
-                       pretty_print_ref(name, sha1, &format);
+                       pretty_print_ref(name, oid.hash, &format);
        }
        return had_error;
 }
diff --git a/cache.h b/cache.h
index 25c98b68093858e5ffc37fd33cf2efb0b2561ba7..ab3b52ff926083cad9edab1c4cd90cbfdcaeae9c 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 *);
@@ -1552,7 +1544,6 @@ extern struct alternate_object_database {
        char path[FLEX_ARRAY];
 } *alt_odb_list;
 extern void prepare_alt_odb(void);
-extern void read_info_alternates(const char * relative_base, int depth);
 extern char *compute_alternate_path(const char *path, struct strbuf *err);
 typedef int alt_odb_fn(struct alternate_object_database *, void *);
 extern int foreach_alt_odb(alt_odb_fn, void*);
index d3150d627071316accafb7d9c69b5988050f4a8e..8b28415939035e2b40153013e6f8805422094d84 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];
@@ -334,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;
 
@@ -1586,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 4127c298cb1370a9ab56ca9d003e853b3e26b67e..6d857f06c16c0dfc3a447355d9a185b416e4e664 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 6c7c9b60538d932d6dbc2d32774a6f64f8687c69..161978d720aed9db5a00c77d1c6bd9a073544f15 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 acebc85d81372f15d3d490d84dc751f59bde26c4..777527daef8a292ec6a3589319c5d84593b3d487 100644 (file)
--- a/config.c
+++ b/config.c
@@ -929,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;
@@ -946,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))
@@ -956,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;
@@ -1464,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;
@@ -1474,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) {
@@ -1492,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)
@@ -1719,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;
@@ -1850,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;
@@ -2057,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 0352da117b9a61498311da5a5b5fdf5e14af8b58..18b6f3f724bd823bf98f039e4699b0c2c5dc5393 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 dbe2abf27730e20fcbd692012e9dd07a2e70404f..85ad732fc0636062634453a58be69454dd745b80 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 52ad9e41fb7aba37abf71dad2bf5a0015b01dca7..eeee45dd341b25d51b7497c4def555c4133c4267 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 4936fcc26b907ca6338ef74bcadc03079b3a3075..1012462e3c9c114ad1b2374a2ae27568ace57bac 100644 (file)
--- a/convert.c
+++ b/convert.c
@@ -564,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);
diff --git a/diff.c b/diff.c
index 9c382580306e340ed6333f96bc4919c4c507a7b9..9c71201e9cbaed28a1f990114484ac75425ee19f 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -406,8 +406,6 @@ static struct diff_tempfile {
        struct tempfile tempfile;
 } diff_temp[2];
 
-typedef unsigned long (*sane_truncate_fn)(char *line, unsigned long len);
-
 struct emit_callback {
        int color_diff;
        unsigned ws_rule;
@@ -415,7 +413,6 @@ struct emit_callback {
        int blank_at_eof_in_postimage;
        int lno_in_preimage;
        int lno_in_postimage;
-       sane_truncate_fn truncate;
        const char **label_path;
        struct diff_words_data *diff_words;
        struct diff_options *opt;
@@ -1243,8 +1240,6 @@ static unsigned long sane_truncate_line(struct emit_callback *ecb, char *line, u
        unsigned long allot;
        size_t l = len;
 
-       if (ecb->truncate)
-               return ecb->truncate(line, len);
        cp = line;
        allot = l;
        while (0 < l) {
diff --git a/fsck.c b/fsck.c
index b4204d772b39335c5feb5c85a11c517bcedcd562..2d2d2e9432b96e5ff2ad893bd8661c0157d42eee 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 bcf0d92ec223bf9e1f0995c5acef6376d1299502..6c390d6c229d7ef8cca8ae01d33b42b57e29c3b3 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 424b034e34b4b40e7c44da16ddf83a31dee6f6a0..9879c59395edff1a02e390397fc623bc60724c57 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 c9da747fcfe504b1fd233c68d91e549def0f3571..343fe7bccd0d64f0caff1ad5d3f981729a8e5fc9 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 375239341fbfe885e51a25e9e0dc2d4fee791345..6e64d40d6fb8fe1566dd26c3df534afe2278390c 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
@@ -53,6 +53,7 @@ else
 
        git format-patch -k --stdout --full-index --cherry-pick --right-only \
                --src-prefix=a/ --dst-prefix=b/ --no-renames --no-cover-letter \
+               $git_format_patch_opt \
                "$revisions" ${restrict_revision+^$restrict_revision} \
                >"$GIT_DIR/rebased-patches"
        ret=$?
@@ -82,6 +83,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 90b1fbe9cf6e8dfb2f4331916809fa40bf9050d2..29b7e8824b53abeaa68780b95d5954f67f734098 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 2cf73b88e8e83ca34b9eb319dbc2b0a220139b0f..ad8415e3cf6907044b0730b59fc2e6ff30ab7174 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
@@ -73,6 +74,7 @@ test "$(git config --bool rebase.stat)" = true && diffstat=t
 autostash="$(git config --bool rebase.autostash || echo false)"
 fork_point=auto
 git_am_opt=
+git_format_patch_opt=
 rebase_root=
 force_rebase=
 allow_rerere_autoupdate=
@@ -444,6 +446,11 @@ else
        state_dir="$apply_dir"
 fi
 
+if test -t 2 && test -z "$GIT_QUIET"
+then
+       git_format_patch_opt="$git_format_patch_opt --progress"
+fi
+
 if test -z "$rebase_root"
 then
        case "$#" in
index 9b6c2da7b4b75980403d836f6fa1fc516bdc3639..8b2ce9afdab6d67e8b9af5fc97a30dc6941323f2 100755 (executable)
@@ -43,9 +43,16 @@ no_changes () {
 }
 
 untracked_files () {
+       if test "$1" = "-z"
+       then
+               shift
+               z=-z
+       else
+               z=
+       fi
        excl_opt=--exclude-standard
        test "$untracked" = "all" && excl_opt=
-       git ls-files -o -z $excl_opt -- "$@"
+       git ls-files -o $z $excl_opt -- "$@"
 }
 
 clear_stash () {
@@ -114,7 +121,7 @@ create_stash () {
                # Untracked files are stored by themselves in a parentless commit, for
                # ease of unpacking later.
                u_commit=$(
-                       untracked_files "$@" | (
+                       untracked_files -z "$@" | (
                                GIT_INDEX_FILE="$TMPindex" &&
                                export GIT_INDEX_FILE &&
                                rm -f "$TMPindex" &&
@@ -300,6 +307,12 @@ push_stash () {
 
        if test -z "$patch_mode"
        then
+               test "$untracked" = "all" && CLEAN_X_OPTION=-x || CLEAN_X_OPTION=
+               if test -n "$untracked"
+               then
+                       git clean --force --quiet -d $CLEAN_X_OPTION -- "$@"
+               fi
+
                if test $# != 0
                then
                        git reset -q -- "$@"
@@ -309,11 +322,6 @@ push_stash () {
                else
                        git reset --hard -q
                fi
-               test "$untracked" = "all" && CLEAN_X_OPTION=-x || CLEAN_X_OPTION=
-               if test -n "$untracked"
-               then
-                       git clean --force --quiet -d $CLEAN_X_OPTION -- "$@"
-               fi
 
                if test "$keep_index" = "t" && test -n "$i_tree"
                then
@@ -573,7 +581,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 e131760eecf944aee97e18a68ab1f171fc0e1d1b..66d1ae8ef6c5f12c856a2f88eabce515dcafd489 100755 (executable)
@@ -611,7 +611,6 @@ cmd_update()
                die_if_unmatched "$mode" "$sha1"
 
                name=$(git submodule--helper name "$sm_path") || exit
-               url=$(git config submodule."$name".url)
                if ! test -z "$update"
                then
                        update_module=$update
@@ -864,7 +863,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 +897,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 489aab4d83a1e222c3e5f3b3bd812b4f29ecd34f..f31dca69620ac244e87e04f1d508ee23cf2f92cf 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();
 
diff --git a/grep.c b/grep.c
index 2efec0e182d5c20fb77903fc61dedd09a8ee7ba3..ce6a48e634105154ca4bb267b4eb744c74d4d803 100644 (file)
--- a/grep.c
+++ b/grep.c
@@ -1821,7 +1821,7 @@ static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int colle
                return 0;
 
        if (opt->status_only)
-               return 0;
+               return opt->unmatch_name_only;
        if (opt->unmatch_name_only) {
                /* We did not see any hit, so we want to show this */
                show_name(opt, gs->name);
@@ -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 0c091e5104a83c0f83c65fd0bef9f39caf8f644d..52aecfab6ebdd6c5565e79db6062b7d7a99cf3df 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;
 
index c1a79c100c9a71083a58401081fb2929420ce361..cb921b4db676e3db918ee16f419cd2b78e0bf57e 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 0e10f3eab804cdc08d3a2f97021e8b18edcb552a..bd8dc7a6a7498d42f2576eb866e97dd55797194d 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);
diff --git a/notes.c b/notes.c
index 8f47c202c58752b6d9d56852ae9c315e2f144769..503754d79ebdca94fb102ccff7886ccef30f31e5 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);
diff --git a/pager.c b/pager.c
index 4dd9e1b26592bd3e7a7ddb52182ea79971557db0..92b23e6cd1d44a26c86afeeb748ddc0aee3f9154 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 b4166b0f384691ada862ff0b1e37387b018587b1..7a583b3011390c1a3cb1c0885e420e76b7751d26 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 f4b56e6d4d38cbc4365ecfc9073f5caf3a05377a..ffa09ace924e0a7b079d039e905363435b08cf9b 100644 (file)
@@ -532,7 +532,7 @@ sub version {
 =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 98518f4ddb4c031417e313dcf4daaa68e9955be0..bc4eed3d75461444f8af0e27e2930ccb25663312 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,
diff --git a/refs.c b/refs.c
index ea2b9f84f8d3fab5452105f10f4492d672cd1d90..3d549a89701ab77c973835cd7c556b5a8c6ddd6f 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -174,6 +174,24 @@ int refname_is_safe(const char *refname)
        return 1;
 }
 
+/*
+ * Return true if refname, which has the specified oid and flags, can
+ * be resolved to an object in the database. If the referred-to object
+ * does not exist, emit a warning and return false.
+ */
+int ref_resolves_to_object(const char *refname,
+                          const struct object_id *oid,
+                          unsigned int flags)
+{
+       if (flags & REF_ISBROKEN)
+               return 0;
+       if (!has_sha1_file(oid->hash)) {
+               error("%s does not point to a valid object!", refname);
+               return 0;
+       }
+       return 1;
+}
+
 char *refs_resolve_refdup(struct ref_store *refs,
                          const char *refname, int resolve_flags,
                          unsigned char *sha1, int *flags)
@@ -818,7 +836,7 @@ int read_ref_at(const char *refname, unsigned int flags, timestamp_t at_time, in
        for_each_reflog_ent_reverse(refname, read_ref_at_ent, &cb);
 
        if (!cb.reccnt) {
-               if (flags & GET_SHA1_QUIETLY)
+               if (flags & GET_OID_QUIETLY)
                        exit(128);
                else
                        die("Log for %s is empty.", refname);
index 0404f2c2333c0fadeb57d225deedc6f0d4afadad..5cca55510b6a0683f16937215f6056d896c622e0 100644 (file)
@@ -3,6 +3,7 @@
 #include "../refs.h"
 #include "refs-internal.h"
 #include "ref-cache.h"
+#include "packed-backend.h"
 #include "../iterator.h"
 #include "../dir-iterator.h"
 #include "../lockfile.h"
@@ -15,39 +16,6 @@ struct ref_lock {
        struct object_id old_oid;
 };
 
-/*
- * Return true if refname, which has the specified oid and flags, can
- * be resolved to an object in the database. If the referred-to object
- * does not exist, emit a warning and return false.
- */
-static int ref_resolves_to_object(const char *refname,
-                                 const struct object_id *oid,
-                                 unsigned int flags)
-{
-       if (flags & REF_ISBROKEN)
-               return 0;
-       if (!has_sha1_file(oid->hash)) {
-               error("%s does not point to a valid object!", refname);
-               return 0;
-       }
-       return 1;
-}
-
-struct packed_ref_cache {
-       struct ref_cache *cache;
-
-       /*
-        * Count of references to the data structure in this instance,
-        * including the pointer from files_ref_store::packed if any.
-        * The data will not be freed as long as the reference count
-        * is nonzero.
-        */
-       unsigned int referrers;
-
-       /* The metadata from when this packed-refs cache was read */
-       struct stat_validity validity;
-};
-
 /*
  * Future: need to be in "struct repository"
  * when doing a full libification.
@@ -58,54 +26,12 @@ struct files_ref_store {
 
        char *gitdir;
        char *gitcommondir;
-       char *packed_refs_path;
 
        struct ref_cache *loose;
-       struct packed_ref_cache *packed;
 
-       /*
-        * Lock used for the "packed-refs" file. Note that this (and
-        * thus the enclosing `files_ref_store`) must not be freed.
-        */
-       struct lock_file packed_refs_lock;
+       struct ref_store *packed_ref_store;
 };
 
-/*
- * Increment the reference count of *packed_refs.
- */
-static void acquire_packed_ref_cache(struct packed_ref_cache *packed_refs)
-{
-       packed_refs->referrers++;
-}
-
-/*
- * Decrease the reference count of *packed_refs.  If it goes to zero,
- * free *packed_refs and return true; otherwise return false.
- */
-static int release_packed_ref_cache(struct packed_ref_cache *packed_refs)
-{
-       if (!--packed_refs->referrers) {
-               free_ref_cache(packed_refs->cache);
-               stat_validity_clear(&packed_refs->validity);
-               free(packed_refs);
-               return 1;
-       } else {
-               return 0;
-       }
-}
-
-static void clear_packed_ref_cache(struct files_ref_store *refs)
-{
-       if (refs->packed) {
-               struct packed_ref_cache *packed_refs = refs->packed;
-
-               if (is_lock_file_locked(&refs->packed_refs_lock))
-                       die("BUG: packed-ref cache cleared while locked");
-               refs->packed = NULL;
-               release_packed_ref_cache(packed_refs);
-       }
-}
-
 static void clear_loose_ref_cache(struct files_ref_store *refs)
 {
        if (refs->loose) {
@@ -132,7 +58,8 @@ static struct ref_store *files_ref_store_create(const char *gitdir,
        get_common_dir_noenv(&sb, gitdir);
        refs->gitcommondir = strbuf_detach(&sb, NULL);
        strbuf_addf(&sb, "%s/packed-refs", refs->gitcommondir);
-       refs->packed_refs_path = strbuf_detach(&sb, NULL);
+       refs->packed_ref_store = packed_ref_store_create(sb.buf, flags);
+       strbuf_release(&sb);
 
        return ref_store;
 }
@@ -175,156 +102,6 @@ static struct files_ref_store *files_downcast(struct ref_store *ref_store,
        return refs;
 }
 
-/* The length of a peeled reference line in packed-refs, including EOL: */
-#define PEELED_LINE_LENGTH 42
-
-/*
- * The packed-refs header line that we write out.  Perhaps other
- * traits will be added later.  The trailing space is required.
- */
-static const char PACKED_REFS_HEADER[] =
-       "# pack-refs with: peeled fully-peeled \n";
-
-/*
- * Parse one line from a packed-refs file.  Write the SHA1 to sha1.
- * Return a pointer to the refname within the line (null-terminated),
- * or NULL if there was a problem.
- */
-static const char *parse_ref_line(struct strbuf *line, struct object_id *oid)
-{
-       const char *ref;
-
-       if (parse_oid_hex(line->buf, oid, &ref) < 0)
-               return NULL;
-       if (!isspace(*ref++))
-               return NULL;
-
-       if (isspace(*ref))
-               return NULL;
-
-       if (line->buf[line->len - 1] != '\n')
-               return NULL;
-       line->buf[--line->len] = 0;
-
-       return ref;
-}
-
-/*
- * Read from `packed_refs_file` into a newly-allocated
- * `packed_ref_cache` and return it. The return value will already
- * have its reference count incremented.
- *
- * A comment line of the form "# pack-refs with: " may contain zero or
- * more traits. We interpret the traits as follows:
- *
- *   No traits:
- *
- *      Probably no references are peeled. But if the file contains a
- *      peeled value for a reference, we will use it.
- *
- *   peeled:
- *
- *      References under "refs/tags/", if they *can* be peeled, *are*
- *      peeled in this file. References outside of "refs/tags/" are
- *      probably not peeled even if they could have been, but if we find
- *      a peeled value for such a reference we will use it.
- *
- *   fully-peeled:
- *
- *      All references in the file that can be peeled are peeled.
- *      Inversely (and this is more important), any references in the
- *      file for which no peeled value is recorded is not peelable. This
- *      trait should typically be written alongside "peeled" for
- *      compatibility with older clients, but we do not require it
- *      (i.e., "peeled" is a no-op if "fully-peeled" is set).
- */
-static struct packed_ref_cache *read_packed_refs(const char *packed_refs_file)
-{
-       FILE *f;
-       struct packed_ref_cache *packed_refs = xcalloc(1, sizeof(*packed_refs));
-       struct ref_entry *last = NULL;
-       struct strbuf line = STRBUF_INIT;
-       enum { PEELED_NONE, PEELED_TAGS, PEELED_FULLY } peeled = PEELED_NONE;
-       struct ref_dir *dir;
-
-       acquire_packed_ref_cache(packed_refs);
-       packed_refs->cache = create_ref_cache(NULL, NULL);
-       packed_refs->cache->root->flag &= ~REF_INCOMPLETE;
-
-       f = fopen(packed_refs_file, "r");
-       if (!f) {
-               if (errno == ENOENT) {
-                       /*
-                        * This is OK; it just means that no
-                        * "packed-refs" file has been written yet,
-                        * which is equivalent to it being empty.
-                        */
-                       return packed_refs;
-               } else {
-                       die_errno("couldn't read %s", packed_refs_file);
-               }
-       }
-
-       stat_validity_update(&packed_refs->validity, fileno(f));
-
-       dir = get_ref_dir(packed_refs->cache->root);
-       while (strbuf_getwholeline(&line, f, '\n') != EOF) {
-               struct object_id oid;
-               const char *refname;
-               const char *traits;
-
-               if (skip_prefix(line.buf, "# pack-refs with:", &traits)) {
-                       if (strstr(traits, " fully-peeled "))
-                               peeled = PEELED_FULLY;
-                       else if (strstr(traits, " peeled "))
-                               peeled = PEELED_TAGS;
-                       /* perhaps other traits later as well */
-                       continue;
-               }
-
-               refname = parse_ref_line(&line, &oid);
-               if (refname) {
-                       int flag = REF_ISPACKED;
-
-                       if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {
-                               if (!refname_is_safe(refname))
-                                       die("packed refname is dangerous: %s", refname);
-                               oidclr(&oid);
-                               flag |= REF_BAD_NAME | REF_ISBROKEN;
-                       }
-                       last = create_ref_entry(refname, &oid, flag);
-                       if (peeled == PEELED_FULLY ||
-                           (peeled == PEELED_TAGS && starts_with(refname, "refs/tags/")))
-                               last->flag |= REF_KNOWS_PEELED;
-                       add_ref_entry(dir, last);
-                       continue;
-               }
-               if (last &&
-                   line.buf[0] == '^' &&
-                   line.len == PEELED_LINE_LENGTH &&
-                   line.buf[PEELED_LINE_LENGTH - 1] == '\n' &&
-                   !get_oid_hex(line.buf + 1, &oid)) {
-                       oidcpy(&last->u.value.peeled, &oid);
-                       /*
-                        * Regardless of what the file header said,
-                        * we definitely know the value of *this*
-                        * reference:
-                        */
-                       last->flag |= REF_KNOWS_PEELED;
-               }
-       }
-
-       fclose(f);
-       strbuf_release(&line);
-
-       return packed_refs;
-}
-
-static const char *files_packed_refs_path(struct files_ref_store *refs)
-{
-       return refs->packed_refs_path;
-}
-
 static void files_reflog_path(struct files_ref_store *refs,
                              struct strbuf *sb,
                              const char *refname)
@@ -370,70 +147,6 @@ static void files_ref_path(struct files_ref_store *refs,
        }
 }
 
-/*
- * Check that the packed refs cache (if any) still reflects the
- * contents of the file. If not, clear the cache.
- */
-static void validate_packed_ref_cache(struct files_ref_store *refs)
-{
-       if (refs->packed &&
-           !stat_validity_check(&refs->packed->validity,
-                                files_packed_refs_path(refs)))
-               clear_packed_ref_cache(refs);
-}
-
-/*
- * Get the packed_ref_cache for the specified files_ref_store,
- * creating and populating it if it hasn't been read before or if the
- * file has been changed (according to its `validity` field) since it
- * was last read. On the other hand, if we hold the lock, then assume
- * that the file hasn't been changed out from under us, so skip the
- * extra `stat()` call in `stat_validity_check()`.
- */
-static struct packed_ref_cache *get_packed_ref_cache(struct files_ref_store *refs)
-{
-       const char *packed_refs_file = files_packed_refs_path(refs);
-
-       if (!is_lock_file_locked(&refs->packed_refs_lock))
-               validate_packed_ref_cache(refs);
-
-       if (!refs->packed)
-               refs->packed = read_packed_refs(packed_refs_file);
-
-       return refs->packed;
-}
-
-static struct ref_dir *get_packed_ref_dir(struct packed_ref_cache *packed_ref_cache)
-{
-       return get_ref_dir(packed_ref_cache->cache->root);
-}
-
-static struct ref_dir *get_packed_refs(struct files_ref_store *refs)
-{
-       return get_packed_ref_dir(get_packed_ref_cache(refs));
-}
-
-/*
- * Add a reference to the in-memory packed reference cache.  This may
- * only be called while the packed-refs file is locked (see
- * lock_packed_refs()).  To actually write the packed-refs file, call
- * commit_packed_refs().
- */
-static void add_packed_ref(struct files_ref_store *refs,
-                          const char *refname, const struct object_id *oid)
-{
-       struct packed_ref_cache *packed_ref_cache = get_packed_ref_cache(refs);
-
-       if (!is_lock_file_locked(&refs->packed_refs_lock))
-               die("BUG: packed refs not locked");
-
-       if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL))
-               die("Reference has invalid format: '%s'", refname);
-
-       add_ref_entry(get_packed_ref_dir(packed_ref_cache),
-                     create_ref_entry(refname, oid, REF_ISPACKED));
-}
-
 /*
  * Read the loose references from the namespace dirname into dir
  * (without recursing).  dirname must end with '/'.  dir must be the
@@ -556,39 +269,6 @@ static struct ref_cache *get_loose_ref_cache(struct files_ref_store *refs)
        return refs->loose;
 }
 
-/*
- * Return the ref_entry for the given refname from the packed
- * references.  If it does not exist, return NULL.
- */
-static struct ref_entry *get_packed_ref(struct files_ref_store *refs,
-                                       const char *refname)
-{
-       return find_ref_entry(get_packed_refs(refs), refname);
-}
-
-/*
- * A loose ref file doesn't exist; check for a packed ref.
- */
-static int resolve_packed_ref(struct files_ref_store *refs,
-                             const char *refname,
-                             unsigned char *sha1, unsigned int *flags)
-{
-       struct ref_entry *entry;
-
-       /*
-        * The loose reference file does not exist; check for a packed
-        * reference.
-        */
-       entry = get_packed_ref(refs, refname);
-       if (entry) {
-               hashcpy(sha1, entry->u.value.oid.hash);
-               *flags |= REF_ISPACKED;
-               return 0;
-       }
-       /* refname is not a packed reference. */
-       return -1;
-}
-
 static int files_read_raw_ref(struct ref_store *ref_store,
                              const char *refname, unsigned char *sha1,
                              struct strbuf *referent, unsigned int *type)
@@ -632,7 +312,8 @@ static int files_read_raw_ref(struct ref_store *ref_store,
        if (lstat(path, &st) < 0) {
                if (errno != ENOENT)
                        goto out;
-               if (resolve_packed_ref(refs, refname, sha1, type)) {
+               if (refs_read_raw_ref(refs->packed_ref_store, refname,
+                                     sha1, referent, type)) {
                        errno = ENOENT;
                        goto out;
                }
@@ -671,7 +352,8 @@ static int files_read_raw_ref(struct ref_store *ref_store,
                 * ref is supposed to be, there could still be a
                 * packed ref:
                 */
-               if (resolve_packed_ref(refs, refname, sha1, type)) {
+               if (refs_read_raw_ref(refs->packed_ref_store, refname,
+                                     sha1, referent, type)) {
                        errno = EISDIR;
                        goto out;
                }
@@ -950,11 +632,11 @@ static int lock_raw_ref(struct files_ref_store *refs,
 
                /*
                 * If the ref did not exist and we are creating it,
-                * make sure there is no existing ref that conflicts
-                * with refname:
+                * make sure there is no existing packed ref that
+                * conflicts with refname:
                 */
                if (refs_verify_refname_available(
-                                   &refs->base, refname,
+                                   refs->packed_ref_store, refname,
                                    extras, skip, err))
                        goto error_return;
        }
@@ -1001,15 +683,9 @@ static int files_peel_ref(struct ref_store *ref_store,
         * be expensive and (b) loose references anyway usually do not
         * have REF_KNOWS_PEELED.
         */
-       if (flag & REF_ISPACKED) {
-               struct ref_entry *r = get_packed_ref(refs, refname);
-               if (r) {
-                       if (peel_entry(r, 0))
-                               return -1;
-                       hashcpy(sha1, r->u.value.peeled.hash);
-                       return 0;
-               }
-       }
+       if (flag & REF_ISPACKED &&
+           !refs_peel_ref(refs->packed_ref_store, refname, sha1))
+               return 0;
 
        return peel_object(base, sha1);
 }
@@ -1017,7 +693,6 @@ static int files_peel_ref(struct ref_store *ref_store,
 struct files_ref_iterator {
        struct ref_iterator base;
 
-       struct packed_ref_cache *packed_ref_cache;
        struct ref_iterator *iter0;
        unsigned int flags;
 };
@@ -1070,7 +745,6 @@ static int files_ref_iterator_abort(struct ref_iterator *ref_iterator)
        if (iter->iter0)
                ok = ref_iterator_abort(iter->iter0);
 
-       release_packed_ref_cache(iter->packed_ref_cache);
        base_ref_iterator_free(ref_iterator);
        return ok;
 }
@@ -1112,18 +786,28 @@ static struct ref_iterator *files_ref_iterator_begin(
         * (If they've already been read, that's OK; we only need to
         * guarantee that they're read before the packed refs, not
         * *how much* before.) After that, we call
-        * get_packed_ref_cache(), which internally checks whether the
-        * packed-ref cache is up to date with what is on disk, and
-        * re-reads it if not.
+        * packed_ref_iterator_begin(), which internally checks
+        * whether the packed-ref cache is up to date with what is on
+        * disk, and re-reads it if not.
         */
 
        loose_iter = cache_ref_iterator_begin(get_loose_ref_cache(refs),
                                              prefix, 1);
 
-       iter->packed_ref_cache = get_packed_ref_cache(refs);
-       acquire_packed_ref_cache(iter->packed_ref_cache);
-       packed_iter = cache_ref_iterator_begin(iter->packed_ref_cache->cache,
-                                              prefix, 0);
+       /*
+        * The packed-refs file might contain broken references, for
+        * example an old version of a reference that points at an
+        * object that has since been garbage-collected. This is OK as
+        * long as there is a corresponding loose reference that
+        * overrides it, and we don't want to emit an error message in
+        * this case. So ask the packed_ref_store for all of its
+        * references, and (if needed) do our own check for broken
+        * ones in files_ref_iterator_advance(), after we have merged
+        * the packed and loose references.
+        */
+       packed_iter = refs_ref_iterator_begin(
+                       refs->packed_ref_store, prefix, 0,
+                       DO_FOR_EACH_INCLUDE_BROKEN);
 
        iter->iter0 = overlay_ref_iterator_begin(loose_iter, packed_iter);
        iter->flags = flags;
@@ -1255,7 +939,7 @@ static struct ref_lock *lock_ref_sha1_basic(struct files_ref_store *refs,
         * our refname.
         */
        if (is_null_oid(&lock->old_oid) &&
-           refs_verify_refname_available(&refs->base, refname,
+           refs_verify_refname_available(refs->packed_ref_store, refname,
                                          extras, skip, err)) {
                last_errno = ENOTDIR;
                goto error_return;
@@ -1287,124 +971,6 @@ static struct ref_lock *lock_ref_sha1_basic(struct files_ref_store *refs,
        return lock;
 }
 
-/*
- * Write an entry to the packed-refs file for the specified refname.
- * If peeled is non-NULL, write it as the entry's peeled value.
- */
-static void write_packed_entry(FILE *fh, const char *refname,
-                              const unsigned char *sha1,
-                              const unsigned char *peeled)
-{
-       fprintf_or_die(fh, "%s %s\n", sha1_to_hex(sha1), refname);
-       if (peeled)
-               fprintf_or_die(fh, "^%s\n", sha1_to_hex(peeled));
-}
-
-/*
- * Lock the packed-refs file for writing. Flags is passed to
- * hold_lock_file_for_update(). Return 0 on success. On errors, set
- * errno appropriately and return a nonzero value.
- */
-static int lock_packed_refs(struct files_ref_store *refs, int flags)
-{
-       static int timeout_configured = 0;
-       static int timeout_value = 1000;
-       struct packed_ref_cache *packed_ref_cache;
-
-       files_assert_main_repository(refs, "lock_packed_refs");
-
-       if (!timeout_configured) {
-               git_config_get_int("core.packedrefstimeout", &timeout_value);
-               timeout_configured = 1;
-       }
-
-       if (hold_lock_file_for_update_timeout(
-                           &refs->packed_refs_lock, files_packed_refs_path(refs),
-                           flags, timeout_value) < 0)
-               return -1;
-
-       /*
-        * Now that we hold the `packed-refs` lock, make sure that our
-        * cache matches the current version of the file. Normally
-        * `get_packed_ref_cache()` does that for us, but that
-        * function assumes that when the file is locked, any existing
-        * cache is still valid. We've just locked the file, but it
-        * might have changed the moment *before* we locked it.
-        */
-       validate_packed_ref_cache(refs);
-
-       packed_ref_cache = get_packed_ref_cache(refs);
-       /* Increment the reference count to prevent it from being freed: */
-       acquire_packed_ref_cache(packed_ref_cache);
-       return 0;
-}
-
-/*
- * Write the current version of the packed refs cache from memory to
- * disk. The packed-refs file must already be locked for writing (see
- * lock_packed_refs()). Return zero on success. On errors, set errno
- * and return a nonzero value
- */
-static int commit_packed_refs(struct files_ref_store *refs)
-{
-       struct packed_ref_cache *packed_ref_cache =
-               get_packed_ref_cache(refs);
-       int ok, error = 0;
-       int save_errno = 0;
-       FILE *out;
-       struct ref_iterator *iter;
-
-       files_assert_main_repository(refs, "commit_packed_refs");
-
-       if (!is_lock_file_locked(&refs->packed_refs_lock))
-               die("BUG: packed-refs not locked");
-
-       out = fdopen_lock_file(&refs->packed_refs_lock, "w");
-       if (!out)
-               die_errno("unable to fdopen packed-refs descriptor");
-
-       fprintf_or_die(out, "%s", PACKED_REFS_HEADER);
-
-       iter = cache_ref_iterator_begin(packed_ref_cache->cache, NULL, 0);
-       while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
-               struct object_id peeled;
-               int peel_error = ref_iterator_peel(iter, &peeled);
-
-               write_packed_entry(out, iter->refname, iter->oid->hash,
-                                  peel_error ? NULL : peeled.hash);
-       }
-
-       if (ok != ITER_DONE)
-               die("error while iterating over references");
-
-       if (commit_lock_file(&refs->packed_refs_lock)) {
-               save_errno = errno;
-               error = -1;
-       }
-       release_packed_ref_cache(packed_ref_cache);
-       errno = save_errno;
-       return error;
-}
-
-/*
- * Rollback the lockfile for the packed-refs file, and discard the
- * in-memory packed reference cache.  (The packed-refs file will be
- * read anew if it is needed again after this function is called.)
- */
-static void rollback_packed_refs(struct files_ref_store *refs)
-{
-       struct packed_ref_cache *packed_ref_cache =
-               get_packed_ref_cache(refs);
-
-       files_assert_main_repository(refs, "rollback_packed_refs");
-
-       if (!is_lock_file_locked(&refs->packed_refs_lock))
-               die("BUG: packed-refs not locked");
-       rollback_lock_file(&refs->packed_refs_lock);
-       release_packed_ref_cache(packed_ref_cache);
-       clear_packed_ref_cache(refs);
-}
-
 struct ref_to_prune {
        struct ref_to_prune *next;
        unsigned char sha1[20];
@@ -1527,12 +1093,11 @@ static int files_pack_refs(struct ref_store *ref_store, unsigned int flags)
                files_downcast(ref_store, REF_STORE_WRITE | REF_STORE_ODB,
                               "pack_refs");
        struct ref_iterator *iter;
-       struct ref_dir *packed_refs;
        int ok;
        struct ref_to_prune *refs_to_prune = NULL;
+       struct strbuf err = STRBUF_INIT;
 
-       lock_packed_refs(refs, LOCK_DIE_ON_ERROR);
-       packed_refs = get_packed_refs(refs);
+       packed_refs_lock(refs->packed_ref_store, LOCK_DIE_ON_ERROR, &err);
 
        iter = cache_ref_iterator_begin(get_loose_ref_cache(refs), NULL, 0);
        while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
@@ -1541,8 +1106,6 @@ static int files_pack_refs(struct ref_store *ref_store, unsigned int flags)
                 * in the packed ref cache. If the reference should be
                 * pruned, also add it to refs_to_prune.
                 */
-               struct ref_entry *packed_entry;
-
                if (!should_pack_ref(iter->refname, iter->oid, iter->flags,
                                     flags))
                        continue;
@@ -1553,17 +1116,7 @@ static int files_pack_refs(struct ref_store *ref_store, unsigned int flags)
                 * we don't copy the peeled status, because we want it
                 * to be re-peeled.
                 */
-               packed_entry = find_ref_entry(packed_refs, iter->refname);
-               if (packed_entry) {
-                       /* Overwrite existing packed entry with info from loose entry */
-                       packed_entry->flag = REF_ISPACKED;
-                       oidcpy(&packed_entry->u.value.oid, iter->oid);
-               } else {
-                       packed_entry = create_ref_entry(iter->refname, iter->oid,
-                                                       REF_ISPACKED);
-                       add_ref_entry(packed_refs, packed_entry);
-               }
-               oidclr(&packed_entry->u.value.peeled);
+               add_packed_ref(refs->packed_ref_store, iter->refname, iter->oid);
 
                /* Schedule the loose reference for pruning if requested. */
                if ((flags & PACK_REFS_PRUNE)) {
@@ -1577,69 +1130,15 @@ static int files_pack_refs(struct ref_store *ref_store, unsigned int flags)
        if (ok != ITER_DONE)
                die("error while iterating over references");
 
-       if (commit_packed_refs(refs))
-               die_errno("unable to overwrite old ref-pack file");
+       if (commit_packed_refs(refs->packed_ref_store, &err))
+               die("unable to overwrite old ref-pack file: %s", err.buf);
+       packed_refs_unlock(refs->packed_ref_store);
 
        prune_refs(refs, refs_to_prune);
+       strbuf_release(&err);
        return 0;
 }
 
-/*
- * Rewrite the packed-refs file, omitting any refs listed in
- * 'refnames'. On error, leave packed-refs unchanged, write an error
- * message to 'err', and return a nonzero value.
- *
- * The refs in 'refnames' needn't be sorted. `err` must not be NULL.
- */
-static int repack_without_refs(struct files_ref_store *refs,
-                              struct string_list *refnames, struct strbuf *err)
-{
-       struct ref_dir *packed;
-       struct string_list_item *refname;
-       int ret, needs_repacking = 0, removed = 0;
-
-       files_assert_main_repository(refs, "repack_without_refs");
-       assert(err);
-
-       /* Look for a packed ref */
-       for_each_string_list_item(refname, refnames) {
-               if (get_packed_ref(refs, refname->string)) {
-                       needs_repacking = 1;
-                       break;
-               }
-       }
-
-       /* Avoid locking if we have nothing to do */
-       if (!needs_repacking)
-               return 0; /* no refname exists in packed refs */
-
-       if (lock_packed_refs(refs, 0)) {
-               unable_to_lock_message(files_packed_refs_path(refs), errno, err);
-               return -1;
-       }
-       packed = get_packed_refs(refs);
-
-       /* Remove refnames from the cache */
-       for_each_string_list_item(refname, refnames)
-               if (remove_entry_from_dir(packed, refname->string) != -1)
-                       removed = 1;
-       if (!removed) {
-               /*
-                * All packed entries disappeared while we were
-                * acquiring the lock.
-                */
-               rollback_packed_refs(refs);
-               return 0;
-       }
-
-       /* Write what remains */
-       ret = commit_packed_refs(refs);
-       if (ret)
-               strbuf_addf(err, "unable to overwrite old ref-pack file: %s",
-                           strerror(errno));
-       return ret;
-}
-
 static int files_delete_refs(struct ref_store *ref_store, const char *msg,
                             struct string_list *refnames, unsigned int flags)
 {
@@ -1651,24 +1150,16 @@ static int files_delete_refs(struct ref_store *ref_store, const char *msg,
        if (!refnames->nr)
                return 0;
 
-       result = repack_without_refs(refs, refnames, &err);
-       if (result) {
-               /*
-                * If we failed to rewrite the packed-refs file, then
-                * it is unsafe to try to remove loose refs, because
-                * doing so might expose an obsolete packed value for
-                * a reference that might even point at an object that
-                * has been garbage collected.
-                */
-               if (refnames->nr == 1)
-                       error(_("could not delete reference %s: %s"),
-                             refnames->items[0].string, err.buf);
-               else
-                       error(_("could not delete references: %s"), err.buf);
+       if (packed_refs_lock(refs->packed_ref_store, 0, &err))
+               goto error;
 
-               goto out;
+       if (repack_without_refs(refs->packed_ref_store, refnames, &err)) {
+               packed_refs_unlock(refs->packed_ref_store);
+               goto error;
        }
 
+       packed_refs_unlock(refs->packed_ref_store);
+
        for (i = 0; i < refnames->nr; i++) {
                const char *refname = refnames->items[i].string;
 
@@ -1676,9 +1167,24 @@ static int files_delete_refs(struct ref_store *ref_store, const char *msg,
                        result |= error(_("could not remove reference %s"), refname);
        }
 
-out:
        strbuf_release(&err);
        return result;
+
+error:
+       /*
+        * If we failed to rewrite the packed-refs file, then it is
+        * unsafe to try to remove loose refs, because doing so might
+        * expose an obsolete packed value for a reference that might
+        * even point at an object that has been garbage collected.
+        */
+       if (refnames->nr == 1)
+               error(_("could not delete reference %s: %s"),
+                     refnames->items[0].string, err.buf);
+       else
+               error(_("could not delete references: %s"), err.buf);
+
+       strbuf_release(&err);
+       return -1;
 }
 
 /*
@@ -3070,11 +2576,19 @@ static int files_transaction_finish(struct ref_store *ref_store,
                }
        }
 
-       if (repack_without_refs(refs, &refs_to_delete, err)) {
+       if (packed_refs_lock(refs->packed_ref_store, 0, err)) {
                ret = TRANSACTION_GENERIC_ERROR;
                goto cleanup;
        }
 
+       if (repack_without_refs(refs->packed_ref_store, &refs_to_delete, err)) {
+               ret = TRANSACTION_GENERIC_ERROR;
+               packed_refs_unlock(refs->packed_ref_store);
+               goto cleanup;
+       }
+
+       packed_refs_unlock(refs->packed_ref_store);
+
        /* Delete the reflogs of any references that were deleted: */
        for_each_string_list_item(ref_to_delete, &refs_to_delete) {
                strbuf_reset(&sb);
@@ -3181,9 +2695,7 @@ static int files_initial_transaction_commit(struct ref_store *ref_store,
                }
        }
 
-       if (lock_packed_refs(refs, 0)) {
-               strbuf_addf(err, "unable to lock packed-refs file: %s",
-                           strerror(errno));
+       if (packed_refs_lock(refs->packed_ref_store, 0, err)) {
                ret = TRANSACTION_GENERIC_ERROR;
                goto cleanup;
        }
@@ -3193,18 +2705,17 @@ static int files_initial_transaction_commit(struct ref_store *ref_store,
 
                if ((update->flags & REF_HAVE_NEW) &&
                    !is_null_oid(&update->new_oid))
-                       add_packed_ref(refs, update->refname,
+                       add_packed_ref(refs->packed_ref_store, update->refname,
                                       &update->new_oid);
        }
 
-       if (commit_packed_refs(refs)) {
-               strbuf_addf(err, "unable to commit packed-refs file: %s",
-                           strerror(errno));
+       if (commit_packed_refs(refs->packed_ref_store, err)) {
                ret = TRANSACTION_GENERIC_ERROR;
                goto cleanup;
        }
 
 cleanup:
+       packed_refs_unlock(refs->packed_ref_store);
        transaction->state = REF_TRANSACTION_CLOSED;
        string_list_clear(&affected_refnames, 0);
        return ret;
diff --git a/refs/packed-backend.c b/refs/packed-backend.c
new file mode 100644 (file)
index 0000000..412c850
--- /dev/null
@@ -0,0 +1,885 @@
+#include "../cache.h"
+#include "../config.h"
+#include "../refs.h"
+#include "refs-internal.h"
+#include "ref-cache.h"
+#include "packed-backend.h"
+#include "../iterator.h"
+#include "../lockfile.h"
+
+struct packed_ref_cache {
+       struct ref_cache *cache;
+
+       /*
+        * Count of references to the data structure in this instance,
+        * including the pointer from files_ref_store::packed if any.
+        * The data will not be freed as long as the reference count
+        * is nonzero.
+        */
+       unsigned int referrers;
+
+       /* The metadata from when this packed-refs cache was read */
+       struct stat_validity validity;
+};
+
+/*
+ * Increment the reference count of *packed_refs.
+ */
+static void acquire_packed_ref_cache(struct packed_ref_cache *packed_refs)
+{
+       packed_refs->referrers++;
+}
+
+/*
+ * Decrease the reference count of *packed_refs.  If it goes to zero,
+ * free *packed_refs and return true; otherwise return false.
+ */
+static int release_packed_ref_cache(struct packed_ref_cache *packed_refs)
+{
+       if (!--packed_refs->referrers) {
+               free_ref_cache(packed_refs->cache);
+               stat_validity_clear(&packed_refs->validity);
+               free(packed_refs);
+               return 1;
+       } else {
+               return 0;
+       }
+}
+
+/*
+ * A container for `packed-refs`-related data. It is not (yet) a
+ * `ref_store`.
+ */
+struct packed_ref_store {
+       struct ref_store base;
+
+       unsigned int store_flags;
+
+       /* The path of the "packed-refs" file: */
+       char *path;
+
+       /*
+        * A cache of the values read from the `packed-refs` file, if
+        * it might still be current; otherwise, NULL.
+        */
+       struct packed_ref_cache *cache;
+
+       /*
+        * Lock used for the "packed-refs" file. Note that this (and
+        * thus the enclosing `packed_ref_store`) must not be freed.
+        */
+       struct lock_file lock;
+
+       /*
+        * Temporary file used when rewriting new contents to the
+        * "packed-refs" file. Note that this (and thus the enclosing
+        * `packed_ref_store`) must not be freed.
+        */
+       struct tempfile tempfile;
+};
+
+struct ref_store *packed_ref_store_create(const char *path,
+                                         unsigned int store_flags)
+{
+       struct packed_ref_store *refs = xcalloc(1, sizeof(*refs));
+       struct ref_store *ref_store = (struct ref_store *)refs;
+
+       base_ref_store_init(ref_store, &refs_be_packed);
+       refs->store_flags = store_flags;
+
+       refs->path = xstrdup(path);
+       return ref_store;
+}
+
+/*
+ * Die if refs is not the main ref store. caller is used in any
+ * necessary error messages.
+ */
+static void packed_assert_main_repository(struct packed_ref_store *refs,
+                                         const char *caller)
+{
+       if (refs->store_flags & REF_STORE_MAIN)
+               return;
+
+       die("BUG: operation %s only allowed for main ref store", caller);
+}
+
+/*
+ * Downcast `ref_store` to `packed_ref_store`. Die if `ref_store` is
+ * not a `packed_ref_store`. Also die if `packed_ref_store` doesn't
+ * support at least the flags specified in `required_flags`. `caller`
+ * is used in any necessary error messages.
+ */
+static struct packed_ref_store *packed_downcast(struct ref_store *ref_store,
+                                               unsigned int required_flags,
+                                               const char *caller)
+{
+       struct packed_ref_store *refs;
+
+       if (ref_store->be != &refs_be_packed)
+               die("BUG: ref_store is type \"%s\" not \"packed\" in %s",
+                   ref_store->be->name, caller);
+
+       refs = (struct packed_ref_store *)ref_store;
+
+       if ((refs->store_flags & required_flags) != required_flags)
+               die("BUG: unallowed operation (%s), requires %x, has %x\n",
+                   caller, required_flags, refs->store_flags);
+
+       return refs;
+}
+
+static void clear_packed_ref_cache(struct packed_ref_store *refs)
+{
+       if (refs->cache) {
+               struct packed_ref_cache *cache = refs->cache;
+
+               refs->cache = NULL;
+               release_packed_ref_cache(cache);
+       }
+}
+
+/* The length of a peeled reference line in packed-refs, including EOL: */
+#define PEELED_LINE_LENGTH 42
+
+/*
+ * Parse one line from a packed-refs file.  Write the SHA1 to sha1.
+ * Return a pointer to the refname within the line (null-terminated),
+ * or NULL if there was a problem.
+ */
+static const char *parse_ref_line(struct strbuf *line, struct object_id *oid)
+{
+       const char *ref;
+
+       if (parse_oid_hex(line->buf, oid, &ref) < 0)
+               return NULL;
+       if (!isspace(*ref++))
+               return NULL;
+
+       if (isspace(*ref))
+               return NULL;
+
+       if (line->buf[line->len - 1] != '\n')
+               return NULL;
+       line->buf[--line->len] = 0;
+
+       return ref;
+}
+
+/*
+ * Read from `packed_refs_file` into a newly-allocated
+ * `packed_ref_cache` and return it. The return value will already
+ * have its reference count incremented.
+ *
+ * A comment line of the form "# pack-refs with: " may contain zero or
+ * more traits. We interpret the traits as follows:
+ *
+ *   No traits:
+ *
+ *      Probably no references are peeled. But if the file contains a
+ *      peeled value for a reference, we will use it.
+ *
+ *   peeled:
+ *
+ *      References under "refs/tags/", if they *can* be peeled, *are*
+ *      peeled in this file. References outside of "refs/tags/" are
+ *      probably not peeled even if they could have been, but if we find
+ *      a peeled value for such a reference we will use it.
+ *
+ *   fully-peeled:
+ *
+ *      All references in the file that can be peeled are peeled.
+ *      Inversely (and this is more important), any references in the
+ *      file for which no peeled value is recorded is not peelable. This
+ *      trait should typically be written alongside "peeled" for
+ *      compatibility with older clients, but we do not require it
+ *      (i.e., "peeled" is a no-op if "fully-peeled" is set).
+ */
+static struct packed_ref_cache *read_packed_refs(const char *packed_refs_file)
+{
+       FILE *f;
+       struct packed_ref_cache *packed_refs = xcalloc(1, sizeof(*packed_refs));
+       struct ref_entry *last = NULL;
+       struct strbuf line = STRBUF_INIT;
+       enum { PEELED_NONE, PEELED_TAGS, PEELED_FULLY } peeled = PEELED_NONE;
+       struct ref_dir *dir;
+
+       acquire_packed_ref_cache(packed_refs);
+       packed_refs->cache = create_ref_cache(NULL, NULL);
+       packed_refs->cache->root->flag &= ~REF_INCOMPLETE;
+
+       f = fopen(packed_refs_file, "r");
+       if (!f) {
+               if (errno == ENOENT) {
+                       /*
+                        * This is OK; it just means that no
+                        * "packed-refs" file has been written yet,
+                        * which is equivalent to it being empty.
+                        */
+                       return packed_refs;
+               } else {
+                       die_errno("couldn't read %s", packed_refs_file);
+               }
+       }
+
+       stat_validity_update(&packed_refs->validity, fileno(f));
+
+       dir = get_ref_dir(packed_refs->cache->root);
+       while (strbuf_getwholeline(&line, f, '\n') != EOF) {
+               struct object_id oid;
+               const char *refname;
+               const char *traits;
+
+               if (!line.len || line.buf[line.len - 1] != '\n')
+                       die("unterminated line in %s: %s", packed_refs_file, line.buf);
+
+               if (skip_prefix(line.buf, "# pack-refs with:", &traits)) {
+                       if (strstr(traits, " fully-peeled "))
+                               peeled = PEELED_FULLY;
+                       else if (strstr(traits, " peeled "))
+                               peeled = PEELED_TAGS;
+                       /* perhaps other traits later as well */
+                       continue;
+               }
+
+               refname = parse_ref_line(&line, &oid);
+               if (refname) {
+                       int flag = REF_ISPACKED;
+
+                       if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {
+                               if (!refname_is_safe(refname))
+                                       die("packed refname is dangerous: %s", refname);
+                               oidclr(&oid);
+                               flag |= REF_BAD_NAME | REF_ISBROKEN;
+                       }
+                       last = create_ref_entry(refname, &oid, flag);
+                       if (peeled == PEELED_FULLY ||
+                           (peeled == PEELED_TAGS && starts_with(refname, "refs/tags/")))
+                               last->flag |= REF_KNOWS_PEELED;
+                       add_ref_entry(dir, last);
+               } else if (last &&
+                   line.buf[0] == '^' &&
+                   line.len == PEELED_LINE_LENGTH &&
+                   line.buf[PEELED_LINE_LENGTH - 1] == '\n' &&
+                   !get_oid_hex(line.buf + 1, &oid)) {
+                       oidcpy(&last->u.value.peeled, &oid);
+                       /*
+                        * Regardless of what the file header said,
+                        * we definitely know the value of *this*
+                        * reference:
+                        */
+                       last->flag |= REF_KNOWS_PEELED;
+               } else {
+                       strbuf_setlen(&line, line.len - 1);
+                       die("unexpected line in %s: %s", packed_refs_file, line.buf);
+               }
+       }
+
+       fclose(f);
+       strbuf_release(&line);
+
+       return packed_refs;
+}
+
+/*
+ * Check that the packed refs cache (if any) still reflects the
+ * contents of the file. If not, clear the cache.
+ */
+static void validate_packed_ref_cache(struct packed_ref_store *refs)
+{
+       if (refs->cache &&
+           !stat_validity_check(&refs->cache->validity, refs->path))
+               clear_packed_ref_cache(refs);
+}
+
+/*
+ * Get the packed_ref_cache for the specified packed_ref_store,
+ * creating and populating it if it hasn't been read before or if the
+ * file has been changed (according to its `validity` field) since it
+ * was last read. On the other hand, if we hold the lock, then assume
+ * that the file hasn't been changed out from under us, so skip the
+ * extra `stat()` call in `stat_validity_check()`.
+ */
+static struct packed_ref_cache *get_packed_ref_cache(struct packed_ref_store *refs)
+{
+       if (!is_lock_file_locked(&refs->lock))
+               validate_packed_ref_cache(refs);
+
+       if (!refs->cache)
+               refs->cache = read_packed_refs(refs->path);
+
+       return refs->cache;
+}
+
+static struct ref_dir *get_packed_ref_dir(struct packed_ref_cache *packed_ref_cache)
+{
+       return get_ref_dir(packed_ref_cache->cache->root);
+}
+
+static struct ref_dir *get_packed_refs(struct packed_ref_store *refs)
+{
+       return get_packed_ref_dir(get_packed_ref_cache(refs));
+}
+
+/*
+ * Add or overwrite a reference in the in-memory packed reference
+ * cache. This may only be called while the packed-refs file is locked
+ * (see packed_refs_lock()). To actually write the packed-refs file,
+ * call commit_packed_refs().
+ */
+void add_packed_ref(struct ref_store *ref_store,
+                   const char *refname, const struct object_id *oid)
+{
+       struct packed_ref_store *refs =
+               packed_downcast(ref_store, REF_STORE_WRITE,
+                               "add_packed_ref");
+       struct ref_dir *packed_refs;
+       struct ref_entry *packed_entry;
+
+       if (!is_lock_file_locked(&refs->lock))
+               die("BUG: packed refs not locked");
+
+       if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL))
+               die("Reference has invalid format: '%s'", refname);
+
+       packed_refs = get_packed_refs(refs);
+       packed_entry = find_ref_entry(packed_refs, refname);
+       if (packed_entry) {
+               /* Overwrite the existing entry: */
+               oidcpy(&packed_entry->u.value.oid, oid);
+               packed_entry->flag = REF_ISPACKED;
+               oidclr(&packed_entry->u.value.peeled);
+       } else {
+               packed_entry = create_ref_entry(refname, oid, REF_ISPACKED);
+               add_ref_entry(packed_refs, packed_entry);
+       }
+}
+
+/*
+ * Return the ref_entry for the given refname from the packed
+ * references.  If it does not exist, return NULL.
+ */
+static struct ref_entry *get_packed_ref(struct packed_ref_store *refs,
+                                       const char *refname)
+{
+       return find_ref_entry(get_packed_refs(refs), refname);
+}
+
+static int packed_read_raw_ref(struct ref_store *ref_store,
+                              const char *refname, unsigned char *sha1,
+                              struct strbuf *referent, unsigned int *type)
+{
+       struct packed_ref_store *refs =
+               packed_downcast(ref_store, REF_STORE_READ, "read_raw_ref");
+
+       struct ref_entry *entry;
+
+       *type = 0;
+
+       entry = get_packed_ref(refs, refname);
+       if (!entry) {
+               errno = ENOENT;
+               return -1;
+       }
+
+       hashcpy(sha1, entry->u.value.oid.hash);
+       *type = REF_ISPACKED;
+       return 0;
+}
+
+static int packed_peel_ref(struct ref_store *ref_store,
+                          const char *refname, unsigned char *sha1)
+{
+       struct packed_ref_store *refs =
+               packed_downcast(ref_store, REF_STORE_READ | REF_STORE_ODB,
+                               "peel_ref");
+       struct ref_entry *r = get_packed_ref(refs, refname);
+
+       if (!r || peel_entry(r, 0))
+               return -1;
+
+       hashcpy(sha1, r->u.value.peeled.hash);
+       return 0;
+}
+
+struct packed_ref_iterator {
+       struct ref_iterator base;
+
+       struct packed_ref_cache *cache;
+       struct ref_iterator *iter0;
+       unsigned int flags;
+};
+
+static int packed_ref_iterator_advance(struct ref_iterator *ref_iterator)
+{
+       struct packed_ref_iterator *iter =
+               (struct packed_ref_iterator *)ref_iterator;
+       int ok;
+
+       while ((ok = ref_iterator_advance(iter->iter0)) == ITER_OK) {
+               if (iter->flags & DO_FOR_EACH_PER_WORKTREE_ONLY &&
+                   ref_type(iter->iter0->refname) != REF_TYPE_PER_WORKTREE)
+                       continue;
+
+               if (!(iter->flags & DO_FOR_EACH_INCLUDE_BROKEN) &&
+                   !ref_resolves_to_object(iter->iter0->refname,
+                                           iter->iter0->oid,
+                                           iter->iter0->flags))
+                       continue;
+
+               iter->base.refname = iter->iter0->refname;
+               iter->base.oid = iter->iter0->oid;
+               iter->base.flags = iter->iter0->flags;
+               return ITER_OK;
+       }
+
+       iter->iter0 = NULL;
+       if (ref_iterator_abort(ref_iterator) != ITER_DONE)
+               ok = ITER_ERROR;
+
+       return ok;
+}
+
+static int packed_ref_iterator_peel(struct ref_iterator *ref_iterator,
+                                  struct object_id *peeled)
+{
+       struct packed_ref_iterator *iter =
+               (struct packed_ref_iterator *)ref_iterator;
+
+       return ref_iterator_peel(iter->iter0, peeled);
+}
+
+static int packed_ref_iterator_abort(struct ref_iterator *ref_iterator)
+{
+       struct packed_ref_iterator *iter =
+               (struct packed_ref_iterator *)ref_iterator;
+       int ok = ITER_DONE;
+
+       if (iter->iter0)
+               ok = ref_iterator_abort(iter->iter0);
+
+       release_packed_ref_cache(iter->cache);
+       base_ref_iterator_free(ref_iterator);
+       return ok;
+}
+
+static struct ref_iterator_vtable packed_ref_iterator_vtable = {
+       packed_ref_iterator_advance,
+       packed_ref_iterator_peel,
+       packed_ref_iterator_abort
+};
+
+static struct ref_iterator *packed_ref_iterator_begin(
+               struct ref_store *ref_store,
+               const char *prefix, unsigned int flags)
+{
+       struct packed_ref_store *refs;
+       struct packed_ref_iterator *iter;
+       struct ref_iterator *ref_iterator;
+       unsigned int required_flags = REF_STORE_READ;
+
+       if (!(flags & DO_FOR_EACH_INCLUDE_BROKEN))
+               required_flags |= REF_STORE_ODB;
+       refs = packed_downcast(ref_store, required_flags, "ref_iterator_begin");
+
+       iter = xcalloc(1, sizeof(*iter));
+       ref_iterator = &iter->base;
+       base_ref_iterator_init(ref_iterator, &packed_ref_iterator_vtable);
+
+       /*
+        * Note that get_packed_ref_cache() internally checks whether
+        * the packed-ref cache is up to date with what is on disk,
+        * and re-reads it if not.
+        */
+
+       iter->cache = get_packed_ref_cache(refs);
+       acquire_packed_ref_cache(iter->cache);
+       iter->iter0 = cache_ref_iterator_begin(iter->cache->cache, prefix, 0);
+
+       iter->flags = flags;
+
+       return ref_iterator;
+}
+
+/*
+ * Write an entry to the packed-refs file for the specified refname.
+ * If peeled is non-NULL, write it as the entry's peeled value. On
+ * error, return a nonzero value and leave errno set at the value left
+ * by the failing call to `fprintf()`.
+ */
+static int write_packed_entry(FILE *fh, const char *refname,
+                             const unsigned char *sha1,
+                             const unsigned char *peeled)
+{
+       if (fprintf(fh, "%s %s\n", sha1_to_hex(sha1), refname) < 0 ||
+           (peeled && fprintf(fh, "^%s\n", sha1_to_hex(peeled)) < 0))
+               return -1;
+
+       return 0;
+}
+
+int packed_refs_lock(struct ref_store *ref_store, int flags, struct strbuf *err)
+{
+       struct packed_ref_store *refs =
+               packed_downcast(ref_store, REF_STORE_WRITE | REF_STORE_MAIN,
+                               "packed_refs_lock");
+       static int timeout_configured = 0;
+       static int timeout_value = 1000;
+       struct packed_ref_cache *packed_ref_cache;
+
+       if (!timeout_configured) {
+               git_config_get_int("core.packedrefstimeout", &timeout_value);
+               timeout_configured = 1;
+       }
+
+       /*
+        * Note that we close the lockfile immediately because we
+        * don't write new content to it, but rather to a separate
+        * tempfile.
+        */
+       if (hold_lock_file_for_update_timeout(
+                           &refs->lock,
+                           refs->path,
+                           flags, timeout_value) < 0) {
+               unable_to_lock_message(refs->path, errno, err);
+               return -1;
+       }
+
+       if (close_lock_file(&refs->lock)) {
+               strbuf_addf(err, "unable to close %s: %s", refs->path, strerror(errno));
+               return -1;
+       }
+
+       /*
+        * Now that we hold the `packed-refs` lock, make sure that our
+        * cache matches the current version of the file. Normally
+        * `get_packed_ref_cache()` does that for us, but that
+        * function assumes that when the file is locked, any existing
+        * cache is still valid. We've just locked the file, but it
+        * might have changed the moment *before* we locked it.
+        */
+       validate_packed_ref_cache(refs);
+
+       packed_ref_cache = get_packed_ref_cache(refs);
+       /* Increment the reference count to prevent it from being freed: */
+       acquire_packed_ref_cache(packed_ref_cache);
+       return 0;
+}
+
+void packed_refs_unlock(struct ref_store *ref_store)
+{
+       struct packed_ref_store *refs = packed_downcast(
+                       ref_store,
+                       REF_STORE_READ | REF_STORE_WRITE,
+                       "packed_refs_unlock");
+
+       if (!is_lock_file_locked(&refs->lock))
+               die("BUG: packed_refs_unlock() called when not locked");
+       rollback_lock_file(&refs->lock);
+       release_packed_ref_cache(refs->cache);
+}
+
+int packed_refs_is_locked(struct ref_store *ref_store)
+{
+       struct packed_ref_store *refs = packed_downcast(
+                       ref_store,
+                       REF_STORE_READ | REF_STORE_WRITE,
+                       "packed_refs_is_locked");
+
+       return is_lock_file_locked(&refs->lock);
+}
+
+/*
+ * The packed-refs header line that we write out.  Perhaps other
+ * traits will be added later.  The trailing space is required.
+ */
+static const char PACKED_REFS_HEADER[] =
+       "# pack-refs with: peeled fully-peeled \n";
+
+/*
+ * Write the current version of the packed refs cache from memory to
+ * disk. The packed-refs file must already be locked for writing (see
+ * packed_refs_lock()). Return zero on success. On errors, rollback
+ * the lockfile, write an error message to `err`, and return a nonzero
+ * value.
+ */
+int commit_packed_refs(struct ref_store *ref_store, struct strbuf *err)
+{
+       struct packed_ref_store *refs =
+               packed_downcast(ref_store, REF_STORE_WRITE | REF_STORE_MAIN,
+                               "commit_packed_refs");
+       struct packed_ref_cache *packed_ref_cache =
+               get_packed_ref_cache(refs);
+       int ok;
+       int ret = -1;
+       struct strbuf sb = STRBUF_INIT;
+       FILE *out;
+       struct ref_iterator *iter;
+       char *packed_refs_path;
+
+       if (!is_lock_file_locked(&refs->lock))
+               die("BUG: commit_packed_refs() called when unlocked");
+
+       /*
+        * If packed-refs is a symlink, we want to overwrite the
+        * symlinked-to file, not the symlink itself. Also, put the
+        * staging file next to it:
+        */
+       packed_refs_path = get_locked_file_path(&refs->lock);
+       strbuf_addf(&sb, "%s.new", packed_refs_path);
+       if (create_tempfile(&refs->tempfile, sb.buf) < 0) {
+               strbuf_addf(err, "unable to create file %s: %s",
+                           sb.buf, strerror(errno));
+               strbuf_release(&sb);
+               goto out;
+       }
+       strbuf_release(&sb);
+
+       out = fdopen_tempfile(&refs->tempfile, "w");
+       if (!out) {
+               strbuf_addf(err, "unable to fdopen packed-refs tempfile: %s",
+                           strerror(errno));
+               goto error;
+       }
+
+       if (fprintf(out, "%s", PACKED_REFS_HEADER) < 0) {
+               strbuf_addf(err, "error writing to %s: %s",
+                           get_tempfile_path(&refs->tempfile), strerror(errno));
+               goto error;
+       }
+
+       iter = cache_ref_iterator_begin(packed_ref_cache->cache, NULL, 0);
+       while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
+               struct object_id peeled;
+               int peel_error = ref_iterator_peel(iter, &peeled);
+
+               if (write_packed_entry(out, iter->refname, iter->oid->hash,
+                                      peel_error ? NULL : peeled.hash)) {
+                       strbuf_addf(err, "error writing to %s: %s",
+                                   get_tempfile_path(&refs->tempfile),
+                                   strerror(errno));
+                       ref_iterator_abort(iter);
+                       goto error;
+               }
+       }
+
+       if (ok != ITER_DONE) {
+               strbuf_addf(err, "unable to rewrite packed-refs file: "
+                           "error iterating over old contents");
+               goto error;
+       }
+
+       if (rename_tempfile(&refs->tempfile, packed_refs_path)) {
+               strbuf_addf(err, "error replacing %s: %s",
+                           refs->path, strerror(errno));
+               goto out;
+       }
+
+       ret = 0;
+       goto out;
+
+error:
+       delete_tempfile(&refs->tempfile);
+
+out:
+       free(packed_refs_path);
+       return ret;
+}
+
+/*
+ * Rewrite the packed-refs file, omitting any refs listed in
+ * 'refnames'. On error, leave packed-refs unchanged, write an error
+ * message to 'err', and return a nonzero value. The packed refs lock
+ * must be held when calling this function; it will still be held when
+ * the function returns.
+ *
+ * The refs in 'refnames' needn't be sorted. `err` must not be NULL.
+ */
+int repack_without_refs(struct ref_store *ref_store,
+                       struct string_list *refnames, struct strbuf *err)
+{
+       struct packed_ref_store *refs =
+               packed_downcast(ref_store, REF_STORE_WRITE | REF_STORE_MAIN,
+                               "repack_without_refs");
+       struct ref_dir *packed;
+       struct string_list_item *refname;
+       int needs_repacking = 0, removed = 0;
+
+       packed_assert_main_repository(refs, "repack_without_refs");
+       assert(err);
+
+       if (!is_lock_file_locked(&refs->lock))
+               die("BUG: repack_without_refs called without holding lock");
+
+       /* Look for a packed ref */
+       for_each_string_list_item(refname, refnames) {
+               if (get_packed_ref(refs, refname->string)) {
+                       needs_repacking = 1;
+                       break;
+               }
+       }
+
+       /* Avoid locking if we have nothing to do */
+       if (!needs_repacking)
+               return 0; /* no refname exists in packed refs */
+
+       packed = get_packed_refs(refs);
+
+       /* Remove refnames from the cache */
+       for_each_string_list_item(refname, refnames)
+               if (remove_entry_from_dir(packed, refname->string) != -1)
+                       removed = 1;
+       if (!removed) {
+               /*
+                * All packed entries disappeared while we were
+                * acquiring the lock.
+                */
+               clear_packed_ref_cache(refs);
+               return 0;
+       }
+
+       /* Write what remains */
+       return commit_packed_refs(&refs->base, err);
+}
+
+static int packed_init_db(struct ref_store *ref_store, struct strbuf *err)
+{
+       /* Nothing to do. */
+       return 0;
+}
+
+static int packed_transaction_prepare(struct ref_store *ref_store,
+                                     struct ref_transaction *transaction,
+                                     struct strbuf *err)
+{
+       die("BUG: not implemented yet");
+}
+
+static int packed_transaction_abort(struct ref_store *ref_store,
+                                   struct ref_transaction *transaction,
+                                   struct strbuf *err)
+{
+       die("BUG: not implemented yet");
+}
+
+static int packed_transaction_finish(struct ref_store *ref_store,
+                                    struct ref_transaction *transaction,
+                                    struct strbuf *err)
+{
+       die("BUG: not implemented yet");
+}
+
+static int packed_initial_transaction_commit(struct ref_store *ref_store,
+                                           struct ref_transaction *transaction,
+                                           struct strbuf *err)
+{
+       return ref_transaction_commit(transaction, err);
+}
+
+static int packed_delete_refs(struct ref_store *ref_store, const char *msg,
+                            struct string_list *refnames, unsigned int flags)
+{
+       die("BUG: not implemented yet");
+}
+
+static int packed_pack_refs(struct ref_store *ref_store, unsigned int flags)
+{
+       /*
+        * Packed refs are already packed. It might be that loose refs
+        * are packed *into* a packed refs store, but that is done by
+        * updating the packed references via a transaction.
+        */
+       return 0;
+}
+
+static int packed_create_symref(struct ref_store *ref_store,
+                              const char *refname, const char *target,
+                              const char *logmsg)
+{
+       die("BUG: packed reference store does not support symrefs");
+}
+
+static int packed_rename_ref(struct ref_store *ref_store,
+                           const char *oldrefname, const char *newrefname,
+                           const char *logmsg)
+{
+       die("BUG: packed reference store does not support renaming references");
+}
+
+static struct ref_iterator *packed_reflog_iterator_begin(struct ref_store *ref_store)
+{
+       return empty_ref_iterator_begin();
+}
+
+static int packed_for_each_reflog_ent(struct ref_store *ref_store,
+                                     const char *refname,
+                                     each_reflog_ent_fn fn, void *cb_data)
+{
+       return 0;
+}
+
+static int packed_for_each_reflog_ent_reverse(struct ref_store *ref_store,
+                                             const char *refname,
+                                             each_reflog_ent_fn fn,
+                                             void *cb_data)
+{
+       return 0;
+}
+
+static int packed_reflog_exists(struct ref_store *ref_store,
+                              const char *refname)
+{
+       return 0;
+}
+
+static int packed_create_reflog(struct ref_store *ref_store,
+                              const char *refname, int force_create,
+                              struct strbuf *err)
+{
+       die("BUG: packed reference store does not support reflogs");
+}
+
+static int packed_delete_reflog(struct ref_store *ref_store,
+                              const char *refname)
+{
+       return 0;
+}
+
+static int packed_reflog_expire(struct ref_store *ref_store,
+                               const char *refname, const unsigned char *sha1,
+                               unsigned int flags,
+                               reflog_expiry_prepare_fn prepare_fn,
+                               reflog_expiry_should_prune_fn should_prune_fn,
+                               reflog_expiry_cleanup_fn cleanup_fn,
+                               void *policy_cb_data)
+{
+       return 0;
+}
+
+struct ref_storage_be refs_be_packed = {
+       NULL,
+       "packed",
+       packed_ref_store_create,
+       packed_init_db,
+       packed_transaction_prepare,
+       packed_transaction_finish,
+       packed_transaction_abort,
+       packed_initial_transaction_commit,
+
+       packed_pack_refs,
+       packed_peel_ref,
+       packed_create_symref,
+       packed_delete_refs,
+       packed_rename_ref,
+
+       packed_ref_iterator_begin,
+       packed_read_raw_ref,
+
+       packed_reflog_iterator_begin,
+       packed_for_each_reflog_ent,
+       packed_for_each_reflog_ent_reverse,
+       packed_reflog_exists,
+       packed_create_reflog,
+       packed_delete_reflog,
+       packed_reflog_expire
+};
diff --git a/refs/packed-backend.h b/refs/packed-backend.h
new file mode 100644 (file)
index 0000000..03b7c1d
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef REFS_PACKED_BACKEND_H
+#define REFS_PACKED_BACKEND_H
+
+struct ref_store *packed_ref_store_create(const char *path,
+                                         unsigned int store_flags);
+
+/*
+ * Lock the packed-refs file for writing. Flags is passed to
+ * hold_lock_file_for_update(). Return 0 on success. On errors, write
+ * an error message to `err` and return a nonzero value.
+ */
+int packed_refs_lock(struct ref_store *ref_store, int flags, struct strbuf *err);
+
+void packed_refs_unlock(struct ref_store *ref_store);
+int packed_refs_is_locked(struct ref_store *ref_store);
+
+void add_packed_ref(struct ref_store *ref_store,
+                   const char *refname, const struct object_id *oid);
+
+int commit_packed_refs(struct ref_store *ref_store, struct strbuf *err);
+
+int repack_without_refs(struct ref_store *ref_store,
+                       struct string_list *refnames, struct strbuf *err);
+
+#endif /* REFS_PACKED_BACKEND_H */
index 192f9f85c97c0d7ca4e9c933e27ba0686da31dbe..4789106fc093391f1c3e67d0fe46c8ece47fde34 100644 (file)
  */
 int refname_is_safe(const char *refname);
 
+/*
+ * Helper function: return true if refname, which has the specified
+ * oid and flags, can be resolved to an object in the database. If the
+ * referred-to object does not exist, emit a warning and return false.
+ */
+int ref_resolves_to_object(const char *refname,
+                          const struct object_id *oid,
+                          unsigned int flags);
+
 enum peel_status {
        /* object was peeled successfully: */
        PEEL_PEELED = 0,
@@ -655,6 +664,7 @@ struct ref_storage_be {
 };
 
 extern struct ref_storage_be refs_be_files;
+extern struct ref_storage_be refs_be_packed;
 
 /*
  * A representation of the reference store for the main repository or
index 60d004392109f1e39f0bf34578e195cdf3af1639..43c317e4e9f6e67aa3e1d0ae245d097bdba664db 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -134,10 +134,14 @@ struct remotes_hash_key {
 };
 
 static int remotes_hash_cmp(const void *unused_cmp_data,
-                           const struct remote *a,
-                           const struct remote *b,
-                           const struct remotes_hash_key *key)
+                           const void *entry,
+                           const void *entry_or_key,
+                           const void *keydata)
 {
+       const struct remote *a = entry;
+       const struct remote *b = entry_or_key;
+       const struct remotes_hash_key *key = keydata;
+
        if (key)
                return strncmp(a->name, key->str, key->len) || a->name[key->len];
        else
@@ -147,7 +151,7 @@ static int remotes_hash_cmp(const void *unused_cmp_data,
 static inline void init_remotes_hash(void)
 {
        if (!remotes_hash.cmpfn)
-               hashmap_init(&remotes_hash, (hashmap_cmp_fn)remotes_hash_cmp, NULL, 0);
+               hashmap_init(&remotes_hash, remotes_hash_cmp, NULL, 0);
 }
 
 static struct remote *make_remote(const char *name, int len)
@@ -1081,7 +1085,7 @@ static int try_explicit_object_name(const char *name,
                return 0;
        }
 
-       if (get_sha1(name, oid.hash))
+       if (get_oid(name, &oid))
                return -1;
 
        if (match) {
@@ -2297,8 +2301,8 @@ static int parse_push_cas_option(struct push_cas_option *cas, const char *arg, i
        if (!*colon)
                entry->use_tracking = 1;
        else if (!colon[1])
-               hashclr(entry->expect);
-       else if (get_sha1(colon + 1, entry->expect))
+               oidclr(&entry->expect);
+       else if (get_oid(colon + 1, &entry->expect))
                return error("cannot parse expected object name '%s'", colon + 1);
        return 0;
 }
@@ -2345,7 +2349,7 @@ static void apply_cas(struct push_cas_option *cas,
                        continue;
                ref->expect_old_sha1 = 1;
                if (!entry->use_tracking)
-                       hashcpy(ref->old_oid_expect.hash, cas->entry[i].expect);
+                       oidcpy(&ref->old_oid_expect, &entry->expect);
                else if (remote_tracking(remote, ref->name, &ref->old_oid_expect))
                        oidclr(&ref->old_oid_expect);
                return;
index 6c28cd3e4bfe2e8be058485d0b963b23622b999f..2ecf4c8c74ce590c9bcc917d997b3c7acf9c07c1 100644 (file)
--- a/remote.h
+++ b/remote.h
@@ -282,7 +282,7 @@ struct ref *get_stale_heads(struct refspec *refs, int ref_count, struct ref *fet
 struct push_cas_option {
        unsigned use_tracking_for_rest:1;
        struct push_cas {
-               unsigned char expect[20];
+               struct object_id expect;
                unsigned use_tracking:1;
                char *refname;
        } *entry;
index edca9074046ab1ca9826d2479bcca11018ba1873..f107af7d763e848648ace5da0010be4df2e0d4dc 100644 (file)
@@ -4,7 +4,9 @@
 #include "submodule-config.h"
 
 /* The main repository */
-static struct repository the_repo;
+static struct repository the_repo = {
+       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &the_index, 0, 0
+};
 struct repository *the_repository = &the_repo;
 
 static char *git_path_from_env(const char *envvar, const char *git_dir,
@@ -158,7 +160,7 @@ int repo_submodule_init(struct repository *submodule,
        struct strbuf worktree = STRBUF_INIT;
        int ret = 0;
 
-       sub = submodule_from_cache(superproject, null_sha1, path);
+       sub = submodule_from_cache(superproject, &null_oid, path);
        if (!sub) {
                ret = -1;
                goto out;
@@ -235,8 +237,6 @@ int repo_read_index(struct repository *repo)
 {
        if (!repo->index)
                repo->index = xcalloc(1, sizeof(*repo->index));
-       else
-               discard_index(repo->index);
 
        return read_index_from(repo->index, repo->index_file);
 }
index 417787f3ef02e871406fa81d1a1bebcdac6e5f13..7f5e24a0a24011393e9b1b9986895ebe8b3f10ab 100644 (file)
@@ -92,6 +92,14 @@ extern int repo_submodule_init(struct repository *submodule,
                               const char *path);
 extern void repo_clear(struct repository *repo);
 
+/*
+ * Populates the repository's index from its index_file, an index struct will
+ * be allocated if needed.
+ *
+ * Return the number of index entries in the populated index or a value less
+ * than zero if an error occured.  If the repository's index has already been
+ * populated then the number of entries will simply be returned.
+ */
 extern int repo_read_index(struct repository *repo);
 
 #endif /* REPOSITORY_H */
index 2631b013a52980f1c338ba1cd539da50784475f4..aa3b946a8d831702f503f3b91d6866d190aef885 100644 (file)
@@ -1166,6 +1166,7 @@ static void init_all_refs_cb(struct all_refs_cb *cb, struct rev_info *revs,
 {
        cb->all_revs = revs;
        cb->all_flags = flags;
+       revs->rev_input_given = 1;
 }
 
 void clear_ref_exclusion(struct string_list **ref_excludes_p)
@@ -1301,7 +1302,7 @@ static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,
                flags ^= UNINTERESTING | BOTTOM;
                arg++;
        }
-       if (get_sha1_committish(arg, oid.hash))
+       if (get_oid_committish(arg, &oid))
                return 0;
        while (1) {
                it = get_reference(revs, arg, &oid, 0);
@@ -1450,7 +1451,7 @@ static int handle_dotdot_1(const char *arg, char *dotdot,
        unsigned int a_flags, b_flags;
        int symmetric = 0;
        unsigned int flags_exclude = flags ^ (UNINTERESTING | BOTTOM);
-       unsigned int oc_flags = GET_SHA1_COMMITTISH | GET_SHA1_RECORD_PATH;
+       unsigned int oc_flags = GET_OID_COMMITTISH | GET_OID_RECORD_PATH;
 
        a_name = arg;
        if (!*a_name)
@@ -1464,8 +1465,8 @@ static int handle_dotdot_1(const char *arg, char *dotdot,
        if (!*b_name)
                b_name = "HEAD";
 
-       if (get_sha1_with_context(a_name, oc_flags, a_oid.hash, a_oc) ||
-           get_sha1_with_context(b_name, oc_flags, b_oid.hash, b_oc))
+       if (get_oid_with_context(a_name, oc_flags, &a_oid, a_oc) ||
+           get_oid_with_context(b_name, oc_flags, &b_oid, b_oc))
                return -1;
 
        if (!cant_be_filename) {
@@ -1546,7 +1547,7 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsi
        int local_flags;
        const char *arg = arg_;
        int cant_be_filename = revarg_opt & REVARG_CANNOT_BE_FILENAME;
-       unsigned get_sha1_flags = GET_SHA1_RECORD_PATH;
+       unsigned get_sha1_flags = GET_OID_RECORD_PATH;
 
        flags = flags & UNINTERESTING ? flags | BOTTOM : flags & ~BOTTOM;
 
@@ -1597,9 +1598,9 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsi
        }
 
        if (revarg_opt & REVARG_COMMITTISH)
-               get_sha1_flags |= GET_SHA1_COMMITTISH;
+               get_sha1_flags |= GET_OID_COMMITTISH;
 
-       if (get_sha1_with_context(arg, get_sha1_flags, oid.hash, &oc))
+       if (get_oid_with_context(arg, get_sha1_flags, &oid, &oc))
                return revs->ignore_missing ? 0 : -1;
        if (!cant_be_filename)
                verify_non_filename(revs->prefix, arg);
@@ -2313,11 +2314,11 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
                opt->tweak(revs, opt);
        if (revs->show_merge)
                prepare_show_merge(revs);
-       if (revs->def && !revs->pending.nr && !got_rev_arg) {
+       if (revs->def && !revs->pending.nr && !revs->rev_input_given && !got_rev_arg) {
                struct object_id oid;
                struct object *object;
                struct object_context oc;
-               if (get_sha1_with_context(revs->def, 0, oid.hash, &oc))
+               if (get_oid_with_context(revs->def, 0, &oid, &oc))
                        diagnose_missing_default(revs->def);
                object = get_reference(revs, revs->def, &oid, 0);
                add_pending_object_with_mode(revs, object, revs->def, oc.mode);
index f96e7f7f49debccac9f85e7c4f0fc06c0be16ca8..bc18487d6fff5e86dff60748c084995a77d2b588 100644 (file)
@@ -71,6 +71,13 @@ struct rev_info {
        const char *def;
        struct pathspec prune_data;
 
+       /*
+        * Whether the arguments parsed by setup_revisions() included any
+        * "input" revisions that might still have yielded an empty pending
+        * list (e.g., patterns like "--all" or "--glob").
+        */
+       int rev_input_given;
+
        /* topo-sort */
        enum rev_sort_order sort_order;
 
index 3010faf86398697469e903318a35421d911acb23..fcceabb80f4261006cdd65bc0ec95ac54ea42e7c 100644 (file)
@@ -127,6 +127,7 @@ static GIT_PATH_FUNC(rebase_path_onto, "rebase-merge/onto")
 static GIT_PATH_FUNC(rebase_path_autostash, "rebase-merge/autostash")
 static GIT_PATH_FUNC(rebase_path_strategy, "rebase-merge/strategy")
 static GIT_PATH_FUNC(rebase_path_strategy_opts, "rebase-merge/strategy_opts")
+static GIT_PATH_FUNC(rebase_path_allow_rerere_autoupdate, "rebase-merge/allow_rerere_autoupdate")
 
 static inline int is_rebase_i(const struct replay_opts *opts)
 {
@@ -691,7 +692,7 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,
 
 static int is_original_commit_empty(struct commit *commit)
 {
-       const unsigned char *ptree_sha1;
+       const struct object_id *ptree_oid;
 
        if (parse_commit(commit))
                return error(_("could not parse commit %s\n"),
@@ -701,12 +702,12 @@ static int is_original_commit_empty(struct commit *commit)
                if (parse_commit(parent))
                        return error(_("could not parse parent commit %s\n"),
                                oid_to_hex(&parent->object.oid));
-               ptree_sha1 = parent->tree->object.oid.hash;
+               ptree_oid = &parent->tree->object.oid;
        } else {
-               ptree_sha1 = EMPTY_TREE_SHA1_BIN; /* commit is root */
+               ptree_oid = &empty_tree_oid; /* commit is root */
        }
 
-       return !hashcmp(ptree_sha1, commit->tree->object.oid.hash);
+       return !oidcmp(ptree_oid, &commit->tree->object.oid);
 }
 
 /*
@@ -896,18 +897,18 @@ static int update_squash_messages(enum todo_command command,
 
 static void flush_rewritten_pending(void) {
        struct strbuf buf = STRBUF_INIT;
-       unsigned char newsha1[20];
+       struct object_id newoid;
        FILE *out;
 
-       if (strbuf_read_file(&buf, rebase_path_rewritten_pending(), 82) > 0 &&
-           !get_sha1("HEAD", newsha1) &&
+       if (strbuf_read_file(&buf, rebase_path_rewritten_pending(), (GIT_MAX_HEXSZ + 1) * 2) > 0 &&
+           !get_oid("HEAD", &newoid) &&
            (out = fopen_or_warn(rebase_path_rewritten_list(), "a"))) {
                char *bol = buf.buf, *eol;
 
                while (*bol) {
                        eol = strchrnul(bol, '\n');
                        fprintf(out, "%.*s %s\n", (int)(eol - bol),
-                                       bol, sha1_to_hex(newsha1));
+                                       bol, oid_to_hex(&newoid));
                        if (!*eol)
                                break;
                        bol = eol + 1;
@@ -1438,7 +1439,11 @@ static int populate_opts_cb(const char *key, const char *value, void *data)
        else if (!strcmp(key, "options.strategy-option")) {
                ALLOC_GROW(opts->xopts, opts->xopts_nr + 1, opts->xopts_alloc);
                opts->xopts[opts->xopts_nr++] = xstrdup(value);
-       } else
+       } else if (!strcmp(key, "options.allow-rerere-auto"))
+               opts->allow_rerere_auto =
+                       git_config_bool_or_int(key, value, &error_flag) ?
+                               RERERE_AUTOUPDATE : RERERE_NOAUTOUPDATE;
+       else
                return error(_("invalid key: %s"), key);
 
        if (!error_flag)
@@ -1479,6 +1484,15 @@ static int read_populate_opts(struct replay_opts *opts)
                                free(opts->gpg_sign);
                                opts->gpg_sign = xstrdup(buf.buf + 2);
                        }
+                       strbuf_reset(&buf);
+               }
+
+               if (read_oneliner(&buf, rebase_path_allow_rerere_autoupdate(), 1)) {
+                       if (!strcmp(buf.buf, "--rerere-autoupdate"))
+                               opts->allow_rerere_auto = RERERE_AUTOUPDATE;
+                       else if (!strcmp(buf.buf, "--no-rerere-autoupdate"))
+                               opts->allow_rerere_auto = RERERE_NOAUTOUPDATE;
+                       strbuf_reset(&buf);
                }
 
                if (file_exists(rebase_path_verbose()))
@@ -1594,36 +1608,37 @@ static int rollback_is_safe(void)
        return !oidcmp(&actual_head, &expected_head);
 }
 
-static int reset_for_rollback(const unsigned char *sha1)
+static int reset_for_rollback(const struct object_id *oid)
 {
        const char *argv[4];    /* reset --merge <arg> + NULL */
 
        argv[0] = "reset";
        argv[1] = "--merge";
-       argv[2] = sha1_to_hex(sha1);
+       argv[2] = oid_to_hex(oid);
        argv[3] = NULL;
        return run_command_v_opt(argv, RUN_GIT_CMD);
 }
 
 static int rollback_single_pick(void)
 {
-       unsigned char head_sha1[20];
+       struct object_id head_oid;
 
        if (!file_exists(git_path_cherry_pick_head()) &&
            !file_exists(git_path_revert_head()))
                return error(_("no cherry-pick or revert in progress"));
-       if (read_ref_full("HEAD", 0, head_sha1, NULL))
+       if (read_ref_full("HEAD", 0, head_oid.hash, NULL))
                return error(_("cannot resolve HEAD"));
-       if (is_null_sha1(head_sha1))
+       if (is_null_oid(&head_oid))
                return error(_("cannot abort from a branch yet to be born"));
-       return reset_for_rollback(head_sha1);
+       return reset_for_rollback(&head_oid);
 }
 
 int sequencer_rollback(struct replay_opts *opts)
 {
        FILE *f;
-       unsigned char sha1[20];
+       struct object_id oid;
        struct strbuf buf = STRBUF_INIT;
+       const char *p;
 
        f = fopen(git_path_head_file(), "r");
        if (!f && errno == ENOENT) {
@@ -1643,12 +1658,12 @@ int sequencer_rollback(struct replay_opts *opts)
                goto fail;
        }
        fclose(f);
-       if (get_sha1_hex(buf.buf, sha1) || buf.buf[40] != '\0') {
+       if (parse_oid_hex(buf.buf, &oid, &p) || *p != '\0') {
                error(_("stored pre-cherry-pick HEAD file '%s' is corrupt"),
                        git_path_head_file());
                goto fail;
        }
-       if (is_null_sha1(sha1)) {
+       if (is_null_oid(&oid)) {
                error(_("cannot abort from a branch yet to be born"));
                goto fail;
        }
@@ -1658,7 +1673,7 @@ int sequencer_rollback(struct replay_opts *opts)
                warning(_("You seem to have moved HEAD. "
                          "Not rewinding, check your HEAD!"));
        } else
-       if (reset_for_rollback(sha1))
+       if (reset_for_rollback(&oid))
                goto fail;
        strbuf_release(&buf);
        return sequencer_remove_state(opts);
@@ -1742,6 +1757,10 @@ static int save_opts(struct replay_opts *opts)
                                                        "options.strategy-option",
                                                        opts->xopts[i], "^$", 0);
        }
+       if (opts->allow_rerere_auto)
+               res |= git_config_set_in_file_gently(opts_file, "options.allow-rerere-auto",
+                                                    opts->allow_rerere_auto == RERERE_AUTOUPDATE ?
+                                                    "true" : "false");
        return res;
 }
 
@@ -1788,13 +1807,13 @@ static int make_patch(struct commit *commit, struct replay_opts *opts)
 
 static int intend_to_amend(void)
 {
-       unsigned char head[20];
+       struct object_id head;
        char *p;
 
-       if (get_sha1("HEAD", head))
+       if (get_oid("HEAD", &head))
                return error(_("cannot read HEAD"));
 
-       p = sha1_to_hex(head);
+       p = oid_to_hex(&head);
        return write_message(p, strlen(p), rebase_path_amend(), 1);
 }
 
@@ -2079,10 +2098,10 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
                if (read_oneliner(&head_ref, rebase_path_head_name(), 0) &&
                                starts_with(head_ref.buf, "refs/")) {
                        const char *msg;
-                       unsigned char head[20], orig[20];
+                       struct object_id head, orig;
                        int res;
 
-                       if (get_sha1("HEAD", head)) {
+                       if (get_oid("HEAD", &head)) {
                                res = error(_("cannot read HEAD"));
 cleanup_head_ref:
                                strbuf_release(&head_ref);
@@ -2090,7 +2109,7 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
                                return res;
                        }
                        if (!read_oneliner(&buf, rebase_path_orig_head(), 0) ||
-                                       get_sha1_hex(buf.buf, orig)) {
+                                       get_oid_hex(buf.buf, &orig)) {
                                res = error(_("could not read orig-head"));
                                goto cleanup_head_ref;
                        }
@@ -2101,7 +2120,7 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
                        }
                        msg = reflog_message(opts, "finish", "%s onto %s",
                                head_ref.buf, buf.buf);
-                       if (update_ref(msg, head_ref.buf, head, orig,
+                       if (update_ref(msg, head_ref.buf, head.hash, orig.hash,
                                        REF_NODEREF, UPDATE_REFS_MSG_ON_ERR)) {
                                res = error(_("could not update %s"),
                                        head_ref.buf);
@@ -2129,8 +2148,8 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
                        log_tree_opt.disable_stdin = 1;
 
                        if (read_oneliner(&buf, rebase_path_orig_head(), 0) &&
-                           !get_sha1(buf.buf, orig.hash) &&
-                           !get_sha1("HEAD", head.hash)) {
+                           !get_oid(buf.buf, &orig) &&
+                           !get_oid("HEAD", &head)) {
                                diff_tree_oid(&orig, &head, "",
                                              &log_tree_opt.diffopt);
                                log_tree_diff_flush(&log_tree_opt);
@@ -2205,16 +2224,16 @@ static int commit_staged_changes(struct replay_opts *opts)
 
        if (file_exists(rebase_path_amend())) {
                struct strbuf rev = STRBUF_INIT;
-               unsigned char head[20], to_amend[20];
+               struct object_id head, to_amend;
 
-               if (get_sha1("HEAD", head))
+               if (get_oid("HEAD", &head))
                        return error(_("cannot amend non-existing commit"));
                if (!read_oneliner(&rev, rebase_path_amend(), 0))
                        return error(_("invalid file: '%s'"), rebase_path_amend());
-               if (get_sha1_hex(rev.buf, to_amend))
+               if (get_oid_hex(rev.buf, &to_amend))
                        return error(_("invalid contents: '%s'"),
                                rebase_path_amend());
-               if (hashcmp(head, to_amend))
+               if (oidcmp(&head, &to_amend))
                        return error(_("\nYou have uncommitted changes in your "
                                       "working tree. Please, commit them\n"
                                       "first and then run 'git rebase "
@@ -2266,7 +2285,7 @@ int sequencer_continue(struct replay_opts *opts)
                struct object_id oid;
 
                if (read_oneliner(&buf, rebase_path_stopped_sha(), 1) &&
-                   !get_sha1_committish(buf.buf, oid.hash))
+                   !get_oid_committish(buf.buf, &oid))
                        record_in_rewritten(&oid, peek_command(&todo_list, 0));
                strbuf_release(&buf);
        }
diff --git a/setup.c b/setup.c
index 860507e1fdb2d61da71b27eb00d8413f2fabcfa9..23950173fc01268320d2e23c36ef80a1b1231a5e 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -1027,7 +1027,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
 {
        static struct strbuf cwd = STRBUF_INIT;
        struct strbuf dir = STRBUF_INIT, gitdir = STRBUF_INIT;
-       const char *prefix, *env_prefix;
+       const char *prefix;
 
        /*
         * We may have read an incomplete configuration before
@@ -1085,16 +1085,6 @@ const char *setup_git_directory_gently(int *nongit_ok)
                die("BUG: unhandled setup_git_directory_1() result");
        }
 
-       /*
-        * NEEDSWORK: This was a hack in order to get ls-files and grep to have
-        * properly formated output when recursing submodules.  Once ls-files
-        * and grep have been changed to perform this recursing in-process this
-        * needs to be removed.
-        */
-       env_prefix = getenv(GIT_TOPLEVEL_PREFIX_ENVIRONMENT);
-       if (env_prefix)
-               prefix = env_prefix;
-
        if (prefix)
                setenv(GIT_PREFIX_ENVIRONMENT, prefix, 1);
        else
index 5f069214d9060da8ceb001e6c037607c1d0096bf..2552b7902c70154282eb278ffed7e21b2d618514 100644 (file)
@@ -99,219 +99,3 @@ int sha1_pos(const unsigned char *sha1, void *table, size_t nr,
        } while (lo < hi);
        return -lo-1;
 }
-
-/*
- * Conventional binary search loop looks like this:
- *
- *     unsigned lo, hi;
- *      do {
- *              unsigned mi = (lo + hi) / 2;
- *              int cmp = "entry pointed at by mi" minus "target";
- *              if (!cmp)
- *                      return (mi is the wanted one)
- *              if (cmp > 0)
- *                      hi = mi; "mi is larger than target"
- *              else
- *                      lo = mi+1; "mi is smaller than target"
- *      } while (lo < hi);
- *
- * The invariants are:
- *
- * - When entering the loop, lo points at a slot that is never
- *   above the target (it could be at the target), hi points at a
- *   slot that is guaranteed to be above the target (it can never
- *   be at the target).
- *
- * - We find a point 'mi' between lo and hi (mi could be the same
- *   as lo, but never can be as same as hi), and check if it hits
- *   the target.  There are three cases:
- *
- *    - if it is a hit, we are happy.
- *
- *    - if it is strictly higher than the target, we set it to hi,
- *      and repeat the search.
- *
- *    - if it is strictly lower than the target, we update lo to
- *      one slot after it, because we allow lo to be at the target.
- *
- *   If the loop exits, there is no matching entry.
- *
- * When choosing 'mi', we do not have to take the "middle" but
- * anywhere in between lo and hi, as long as lo <= mi < hi is
- * satisfied.  When we somehow know that the distance between the
- * target and lo is much shorter than the target and hi, we could
- * pick mi that is much closer to lo than the midway.
- *
- * Now, we can take advantage of the fact that SHA-1 is a good hash
- * function, and as long as there are enough entries in the table, we
- * can expect uniform distribution.  An entry that begins with for
- * example "deadbeef..." is much likely to appear much later than in
- * the midway of the table.  It can reasonably be expected to be near
- * 87% (222/256) from the top of the table.
- *
- * However, we do not want to pick "mi" too precisely.  If the entry at
- * the 87% in the above example turns out to be higher than the target
- * we are looking for, we would end up narrowing the search space down
- * only by 13%, instead of 50% we would get if we did a simple binary
- * search.  So we would want to hedge our bets by being less aggressive.
- *
- * The table at "table" holds at least "nr" entries of "elem_size"
- * bytes each.  Each entry has the SHA-1 key at "key_offset".  The
- * table is sorted by the SHA-1 key of the entries.  The caller wants
- * to find the entry with "key", and knows that the entry at "lo" is
- * not higher than the entry it is looking for, and that the entry at
- * "hi" is higher than the entry it is looking for.
- */
-int sha1_entry_pos(const void *table,
-                  size_t elem_size,
-                  size_t key_offset,
-                  unsigned lo, unsigned hi, unsigned nr,
-                  const unsigned char *key)
-{
-       const unsigned char *base = table;
-       const unsigned char *hi_key, *lo_key;
-       unsigned ofs_0;
-       static int debug_lookup = -1;
-
-       if (debug_lookup < 0)
-               debug_lookup = !!getenv("GIT_DEBUG_LOOKUP");
-
-       if (!nr || lo >= hi)
-               return -1;
-
-       if (nr == hi)
-               hi_key = NULL;
-       else
-               hi_key = base + elem_size * hi + key_offset;
-       lo_key = base + elem_size * lo + key_offset;
-
-       ofs_0 = 0;
-       do {
-               int cmp;
-               unsigned ofs, mi, range;
-               unsigned lov, hiv, kyv;
-               const unsigned char *mi_key;
-
-               range = hi - lo;
-               if (hi_key) {
-                       for (ofs = ofs_0; ofs < 20; ofs++)
-                               if (lo_key[ofs] != hi_key[ofs])
-                                       break;
-                       ofs_0 = ofs;
-                       /*
-                        * byte 0 thru (ofs-1) are the same between
-                        * lo and hi; ofs is the first byte that is
-                        * different.
-                        *
-                        * If ofs==20, then no bytes are different,
-                        * meaning we have entries with duplicate
-                        * keys. We know that we are in a solid run
-                        * of this entry (because the entries are
-                        * sorted, and our lo and hi are the same,
-                        * there can be nothing but this single key
-                        * in between). So we can stop the search.
-                        * Either one of these entries is it (and
-                        * we do not care which), or we do not have
-                        * it.
-                        *
-                        * Furthermore, we know that one of our
-                        * endpoints must be the edge of the run of
-                        * duplicates. For example, given this
-                        * sequence:
-                        *
-                        *     idx 0 1 2 3 4 5
-                        *     key A C C C C D
-                        *
-                        * If we are searching for "B", we might
-                        * hit the duplicate run at lo=1, hi=3
-                        * (e.g., by first mi=3, then mi=0). But we
-                        * can never have lo > 1, because B < C.
-                        * That is, if our key is less than the
-                        * run, we know that "lo" is the edge, but
-                        * we can say nothing of "hi". Similarly,
-                        * if our key is greater than the run, we
-                        * know that "hi" is the edge, but we can
-                        * say nothing of "lo".
-                        *
-                        * Therefore if we do not find it, we also
-                        * know where it would go if it did exist:
-                        * just on the far side of the edge that we
-                        * know about.
-                        */
-                       if (ofs == 20) {
-                               mi = lo;
-                               mi_key = base + elem_size * mi + key_offset;
-                               cmp = memcmp(mi_key, key, 20);
-                               if (!cmp)
-                                       return mi;
-                               if (cmp < 0)
-                                       return -1 - hi;
-                               else
-                                       return -1 - lo;
-                       }
-
-                       hiv = hi_key[ofs_0];
-                       if (ofs_0 < 19)
-                               hiv = (hiv << 8) | hi_key[ofs_0+1];
-               } else {
-                       hiv = 256;
-                       if (ofs_0 < 19)
-                               hiv <<= 8;
-               }
-               lov = lo_key[ofs_0];
-               kyv = key[ofs_0];
-               if (ofs_0 < 19) {
-                       lov = (lov << 8) | lo_key[ofs_0+1];
-                       kyv = (kyv << 8) | key[ofs_0+1];
-               }
-               assert(lov < hiv);
-
-               if (kyv < lov)
-                       return -1 - lo;
-               if (hiv < kyv)
-                       return -1 - hi;
-
-               /*
-                * Even if we know the target is much closer to 'hi'
-                * than 'lo', if we pick too precisely and overshoot
-                * (e.g. when we know 'mi' is closer to 'hi' than to
-                * 'lo', pick 'mi' that is higher than the target), we
-                * end up narrowing the search space by a smaller
-                * amount (i.e. the distance between 'mi' and 'hi')
-                * than what we would have (i.e. about half of 'lo'
-                * and 'hi').  Hedge our bets to pick 'mi' less
-                * aggressively, i.e. make 'mi' a bit closer to the
-                * middle than we would otherwise pick.
-                */
-               kyv = (kyv * 6 + lov + hiv) / 8;
-               if (lov < hiv - 1) {
-                       if (kyv == lov)
-                               kyv++;
-                       else if (kyv == hiv)
-                               kyv--;
-               }
-               mi = (range - 1) * (kyv - lov) / (hiv - lov) + lo;
-
-               if (debug_lookup) {
-                       printf("lo %u hi %u rg %u mi %u ", lo, hi, range, mi);
-                       printf("ofs %u lov %x, hiv %x, kyv %x\n",
-                              ofs_0, lov, hiv, kyv);
-               }
-               if (!(lo <= mi && mi < hi))
-                       die("assertion failure lo %u mi %u hi %u %s",
-                           lo, mi, hi, sha1_to_hex(key));
-
-               mi_key = base + elem_size * mi + key_offset;
-               cmp = memcmp(mi_key + ofs_0, key + ofs_0, 20 - ofs_0);
-               if (!cmp)
-                       return mi;
-               if (cmp > 0) {
-                       hi = mi;
-                       hi_key = mi_key;
-               } else {
-                       lo = mi + 1;
-                       lo_key = mi_key + elem_size;
-               }
-       } while (lo < hi);
-       return -lo-1;
-}
index b60ae15f7068c157df6407933ea7ee94a53f0640..189a1c3cdd14ad7a9d7e72a4577f47449e2ed5f6 100644 (file)
@@ -347,6 +347,7 @@ static int alt_odb_usable(struct strbuf *path, const char *normalized_objdir)
  * SHA1, an extra slash for the first level indirection, and the
  * terminating NUL.
  */
+static void read_info_alternates(const char * relative_base, int depth);
 static int link_alt_odb_entry(const char *entry, const char *relative_base,
        int depth, const char *normalized_objdir)
 {
@@ -448,7 +449,7 @@ static void link_alt_odb_entries(const char *alt, int len, int sep,
        strbuf_release(&objdirbuf);
 }
 
-void read_info_alternates(const char * relative_base, int depth)
+static void read_info_alternates(const char * relative_base, int depth)
 {
        char *map;
        size_t mapsz;
@@ -2444,6 +2445,9 @@ int packed_object_info(struct packed_git *p, off_t obj_offset,
                        hashclr(oi->delta_base_sha1);
        }
 
+       oi->whence = in_delta_base_cache(p, obj_offset) ? OI_DBCACHED :
+                                                         OI_PACKED;
+
 out:
        unuse_pack(&w_curs);
        return type;
@@ -2542,8 +2546,8 @@ void *unpack_entry(struct packed_git *p, off_t obj_offset,
                                error("bad packed object CRC for %s",
                                      sha1_to_hex(sha1));
                                mark_bad_packed_object(p, sha1);
-                               unuse_pack(&w_curs);
-                               return NULL;
+                               data = NULL;
+                               goto out;
                        }
                }
 
@@ -2681,6 +2685,7 @@ void *unpack_entry(struct packed_git *p, off_t obj_offset,
        if (final_size)
                *final_size = size;
 
+out:
        unuse_pack(&w_curs);
 
        if (delta_stack != small_delta_stack)
@@ -2759,7 +2764,6 @@ off_t find_pack_entry_one(const unsigned char *sha1,
        const uint32_t *level1_ofs = p->index_data;
        const unsigned char *index = p->index_data;
        unsigned hi, lo, stride;
-       static int use_lookup = -1;
        static int debug_lookup = -1;
 
        if (debug_lookup < 0)
@@ -2789,17 +2793,7 @@ off_t find_pack_entry_one(const unsigned char *sha1,
                printf("%02x%02x%02x... lo %u hi %u nr %"PRIu32"\n",
                       sha1[0], sha1[1], sha1[2], lo, hi, p->num_objects);
 
-       if (use_lookup < 0)
-               use_lookup = !!getenv("GIT_USE_LOOKUP");
-       if (use_lookup) {
-               int pos = sha1_entry_pos(index, stride, 0,
-                                        lo, hi, p->num_objects, sha1);
-               if (pos < 0)
-                       return 0;
-               return nth_packed_object_offset(p, pos);
-       }
-
-       do {
+       while (lo < hi) {
                unsigned mi = (lo + hi) / 2;
                int cmp = hashcmp(index + mi * stride, sha1);
 
@@ -2812,7 +2806,7 @@ off_t find_pack_entry_one(const unsigned char *sha1,
                        hi = mi;
                else
                        lo = mi+1;
-       } while (lo < hi);
+       }
        return 0;
 }
 
@@ -2973,6 +2967,7 @@ static int sha1_loose_object_info(const unsigned char *sha1,
        if (oi->sizep == &size_scratch)
                oi->sizep = NULL;
        strbuf_release(&hdrbuf);
+       oi->whence = OI_LOOSE;
        return (status < 0) ? status : 0;
 }
 
@@ -3010,10 +3005,8 @@ int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi,
 
        if (!find_pack_entry(real, &e)) {
                /* Most likely it's a loose object. */
-               if (!sha1_loose_object_info(real, oi, flags)) {
-                       oi->whence = OI_LOOSE;
+               if (!sha1_loose_object_info(real, oi, flags))
                        return 0;
-               }
 
                /* Not a loose object; someone else may have just packed it. */
                if (flags & OBJECT_INFO_QUICK) {
@@ -3036,10 +3029,7 @@ int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi,
        if (rtype < 0) {
                mark_bad_packed_object(e.p, real);
                return sha1_object_info_extended(real, oi, 0);
-       } else if (in_delta_base_cache(e.p, e.offset)) {
-               oi->whence = OI_DBCACHED;
-       } else {
-               oi->whence = OI_PACKED;
+       } else if (oi->whence == OI_PACKED) {
                oi->u.packed.offset = e.offset;
                oi->u.packed.pack = e.p;
                oi->u.packed.is_delta = (rtype == OBJ_REF_DELTA ||
@@ -3063,30 +3053,6 @@ int sha1_object_info(const unsigned char *sha1, unsigned long *sizep)
        return type;
 }
 
-static void *read_packed_sha1(const unsigned char *sha1,
-                             enum object_type *type, unsigned long *size)
-{
-       struct pack_entry e;
-       void *data;
-
-       if (!find_pack_entry(sha1, &e))
-               return NULL;
-       data = cache_or_unpack_entry(e.p, e.offset, size, type);
-       if (!data) {
-               /*
-                * We're probably in deep shit, but let's try to fetch
-                * the required object anyway from another pack or loose.
-                * This should happen only in the presence of a corrupted
-                * pack, and is better than failing outright.
-                */
-               error("failed to read object %s at offset %"PRIuMAX" from %s",
-                     sha1_to_hex(sha1), (uintmax_t)e.offset, e.p->pack_name);
-               mark_bad_packed_object(e.p, sha1);
-               data = read_object(sha1, type, size);
-       }
-       return data;
-}
-
 int pretend_sha1_file(void *buf, unsigned long len, enum object_type type,
                      unsigned char *sha1)
 {
@@ -3469,7 +3435,7 @@ int force_object_loose(const unsigned char *sha1, time_t mtime)
 
        if (has_loose_object(sha1))
                return 0;
-       buf = read_packed_sha1(sha1, &type, &len);
+       buf = read_object(sha1, &type, &len);
        if (!buf)
                return error("cannot read sha1_file for %s", sha1_to_hex(sha1));
        hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %lu", typename(type), len) + 1;
index 74fcb6d788f4cb591a9f7d3c6a2692f5c6d84022..862b6f1308e7031317ab6eb6d181652a6fc644ad 100644 (file)
@@ -10,7 +10,7 @@
 #include "dir.h"
 #include "sha1-array.h"
 
-static int get_sha1_oneline(const char *, unsigned char *, struct commit_list *);
+static int get_oid_oneline(const char *, struct object_id *, struct commit_list *);
 
 typedef int (*disambiguate_hint_fn)(const struct object_id *, void *);
 
@@ -200,7 +200,7 @@ static void find_short_packed_object(struct disambiguate_state *ds)
 #define SHORT_NAME_AMBIGUOUS (-2)
 
 static int finish_object_disambiguation(struct disambiguate_state *ds,
-                                       unsigned char *sha1)
+                                       struct object_id *oid)
 {
        if (ds->ambiguous)
                return SHORT_NAME_AMBIGUOUS;
@@ -229,7 +229,7 @@ static int finish_object_disambiguation(struct disambiguate_state *ds,
        if (!ds->candidate_ok)
                return SHORT_NAME_AMBIGUOUS;
 
-       hashcpy(sha1, ds->candidate.hash);
+       oidcpy(oid, &ds->candidate);
        return 0;
 }
 
@@ -385,35 +385,35 @@ static int show_ambiguous_object(const struct object_id *oid, void *data)
        return 0;
 }
 
-static int get_short_sha1(const char *name, int len, unsigned char *sha1,
+static int get_short_oid(const char *name, int len, struct object_id *oid,
                          unsigned flags)
 {
        int status;
        struct disambiguate_state ds;
-       int quietly = !!(flags & GET_SHA1_QUIETLY);
+       int quietly = !!(flags & GET_OID_QUIETLY);
 
        if (init_object_disambiguation(name, len, &ds) < 0)
                return -1;
 
-       if (HAS_MULTI_BITS(flags & GET_SHA1_DISAMBIGUATORS))
-               die("BUG: multiple get_short_sha1 disambiguator flags");
+       if (HAS_MULTI_BITS(flags & GET_OID_DISAMBIGUATORS))
+               die("BUG: multiple get_short_oid disambiguator flags");
 
-       if (flags & GET_SHA1_COMMIT)
+       if (flags & GET_OID_COMMIT)
                ds.fn = disambiguate_commit_only;
-       else if (flags & GET_SHA1_COMMITTISH)
+       else if (flags & GET_OID_COMMITTISH)
                ds.fn = disambiguate_committish_only;
-       else if (flags & GET_SHA1_TREE)
+       else if (flags & GET_OID_TREE)
                ds.fn = disambiguate_tree_only;
-       else if (flags & GET_SHA1_TREEISH)
+       else if (flags & GET_OID_TREEISH)
                ds.fn = disambiguate_treeish_only;
-       else if (flags & GET_SHA1_BLOB)
+       else if (flags & GET_OID_BLOB)
                ds.fn = disambiguate_blob_only;
        else
                ds.fn = default_disambiguate_hint;
 
        find_short_object_filename(&ds);
        find_short_packed_object(&ds);
-       status = finish_object_disambiguation(&ds, sha1);
+       status = finish_object_disambiguation(&ds, oid);
 
        if (!quietly && (status == SHORT_NAME_AMBIGUOUS)) {
                error(_("short SHA1 %s is ambiguous"), ds.hex_pfx);
@@ -500,12 +500,12 @@ int find_unique_abbrev_r(char *hex, const unsigned char *sha1, int len)
        }
 
        sha1_to_hex_r(hex, sha1);
-       if (len == 40 || !len)
-               return 40;
+       if (len == GIT_SHA1_HEXSZ || !len)
+               return GIT_SHA1_HEXSZ;
        exists = has_sha1_file(sha1);
-       while (len < 40) {
-               unsigned char sha1_ret[20];
-               status = get_short_sha1(hex, len, sha1_ret, GET_SHA1_QUIETLY);
+       while (len < GIT_SHA1_HEXSZ) {
+               struct object_id oid_ret;
+               status = get_short_oid(hex, len, &oid_ret, GET_OID_QUIETLY);
                if (exists
                    ? !status
                    : status == SHORT_NAME_NOT_FOUND) {
@@ -578,10 +578,10 @@ static inline int push_mark(const char *string, int len)
        return at_mark(string, len, suffix, ARRAY_SIZE(suffix));
 }
 
-static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned lookup_flags);
+static int get_oid_1(const char *name, int len, struct object_id *oid, unsigned lookup_flags);
 static int interpret_nth_prior_checkout(const char *name, int namelen, struct strbuf *buf);
 
-static int get_sha1_basic(const char *str, int len, unsigned char *sha1,
+static int get_oid_basic(const char *str, int len, struct object_id *oid,
                          unsigned int flags)
 {
        static const char *warn_msg = "refname '%.*s' is ambiguous.";
@@ -595,14 +595,14 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1,
        "where \"$br\" is somehow empty and a 40-hex ref is created. Please\n"
        "examine these refs and maybe delete them. Turn this message off by\n"
        "running \"git config advice.objectNameWarning false\"");
-       unsigned char tmp_sha1[20];
+       struct object_id tmp_oid;
        char *real_ref = NULL;
        int refs_found = 0;
        int at, reflog_len, nth_prior = 0;
 
-       if (len == 40 && !get_sha1_hex(str, sha1)) {
+       if (len == GIT_SHA1_HEXSZ && !get_oid_hex(str, oid)) {
                if (warn_ambiguous_refs && warn_on_object_refname_ambiguity) {
-                       refs_found = dwim_ref(str, len, tmp_sha1, &real_ref);
+                       refs_found = dwim_ref(str, len, tmp_oid.hash, &real_ref);
                        if (refs_found > 0) {
                                warning(warn_msg, len, str);
                                if (advice_object_name_warning)
@@ -644,7 +644,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1,
                int detached;
 
                if (interpret_nth_prior_checkout(str, len, &buf) > 0) {
-                       detached = (buf.len == 40 && !get_sha1_hex(buf.buf, sha1));
+                       detached = (buf.len == GIT_SHA1_HEXSZ && !get_oid_hex(buf.buf, oid));
                        strbuf_release(&buf);
                        if (detached)
                                return 0;
@@ -653,18 +653,18 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1,
 
        if (!len && reflog_len)
                /* allow "@{...}" to mean the current branch reflog */
-               refs_found = dwim_ref("HEAD", 4, sha1, &real_ref);
+               refs_found = dwim_ref("HEAD", 4, oid->hash, &real_ref);
        else if (reflog_len)
-               refs_found = dwim_log(str, len, sha1, &real_ref);
+               refs_found = dwim_log(str, len, oid->hash, &real_ref);
        else
-               refs_found = dwim_ref(str, len, sha1, &real_ref);
+               refs_found = dwim_ref(str, len, oid->hash, &real_ref);
 
        if (!refs_found)
                return -1;
 
-       if (warn_ambiguous_refs && !(flags & GET_SHA1_QUIETLY) &&
+       if (warn_ambiguous_refs && !(flags & GET_OID_QUIETLY) &&
            (refs_found > 1 ||
-            !get_short_sha1(str, len, tmp_sha1, GET_SHA1_QUIETLY)))
+            !get_short_oid(str, len, &tmp_oid, GET_OID_QUIETLY)))
                warning(warn_msg, len, str);
 
        if (reflog_len) {
@@ -696,7 +696,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1,
                                return -1;
                        }
                }
-               if (read_ref_at(real_ref, flags, at_time, nth, sha1, NULL,
+               if (read_ref_at(real_ref, flags, at_time, nth, oid->hash, NULL,
                                &co_time, &co_tz, &co_cnt)) {
                        if (!len) {
                                if (starts_with(real_ref, "refs/heads/")) {
@@ -709,13 +709,13 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1,
                                }
                        }
                        if (at_time) {
-                               if (!(flags & GET_SHA1_QUIETLY)) {
+                               if (!(flags & GET_OID_QUIETLY)) {
                                        warning("Log for '%.*s' only goes "
                                                "back to %s.", len, str,
                                                show_date(co_time, co_tz, DATE_MODE(RFC2822)));
                                }
                        } else {
-                               if (flags & GET_SHA1_QUIETLY) {
+                               if (flags & GET_OID_QUIETLY) {
                                        exit(128);
                                }
                                die("Log for '%.*s' only has %d entries.",
@@ -729,10 +729,10 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1,
 }
 
 static int get_parent(const char *name, int len,
-                     unsigned char *result, int idx)
+                     struct object_id *result, int idx)
 {
        struct object_id oid;
-       int ret = get_sha1_1(name, len, oid.hash, GET_SHA1_COMMITTISH);
+       int ret = get_oid_1(name, len, &oid, GET_OID_COMMITTISH);
        struct commit *commit;
        struct commit_list *p;
 
@@ -742,13 +742,13 @@ static int get_parent(const char *name, int len,
        if (parse_commit(commit))
                return -1;
        if (!idx) {
-               hashcpy(result, commit->object.oid.hash);
+               oidcpy(result, &commit->object.oid);
                return 0;
        }
        p = commit->parents;
        while (p) {
                if (!--idx) {
-                       hashcpy(result, p->item->object.oid.hash);
+                       oidcpy(result, &p->item->object.oid);
                        return 0;
                }
                p = p->next;
@@ -757,13 +757,13 @@ static int get_parent(const char *name, int len,
 }
 
 static int get_nth_ancestor(const char *name, int len,
-                           unsigned char *result, int generation)
+                           struct object_id *result, int generation)
 {
        struct object_id oid;
        struct commit *commit;
        int ret;
 
-       ret = get_sha1_1(name, len, oid.hash, GET_SHA1_COMMITTISH);
+       ret = get_oid_1(name, len, &oid, GET_OID_COMMITTISH);
        if (ret)
                return ret;
        commit = lookup_commit_reference(&oid);
@@ -775,7 +775,7 @@ static int get_nth_ancestor(const char *name, int len,
                        return -1;
                commit = commit->parents->item;
        }
-       hashcpy(result, commit->object.oid.hash);
+       oidcpy(result, &commit->object.oid);
        return 0;
 }
 
@@ -804,7 +804,7 @@ struct object *peel_to_type(const char *name, int namelen,
        }
 }
 
-static int peel_onion(const char *name, int len, unsigned char *sha1,
+static int peel_onion(const char *name, int len, struct object_id *oid,
                      unsigned lookup_flags)
 {
        struct object_id outer;
@@ -849,13 +849,13 @@ static int peel_onion(const char *name, int len, unsigned char *sha1,
        else
                return -1;
 
-       lookup_flags &= ~GET_SHA1_DISAMBIGUATORS;
+       lookup_flags &= ~GET_OID_DISAMBIGUATORS;
        if (expected_type == OBJ_COMMIT)
-               lookup_flags |= GET_SHA1_COMMITTISH;
+               lookup_flags |= GET_OID_COMMITTISH;
        else if (expected_type == OBJ_TREE)
-               lookup_flags |= GET_SHA1_TREEISH;
+               lookup_flags |= GET_OID_TREEISH;
 
-       if (get_sha1_1(name, sp - name - 2, outer.hash, lookup_flags))
+       if (get_oid_1(name, sp - name - 2, &outer, lookup_flags))
                return -1;
 
        o = parse_object(&outer);
@@ -865,7 +865,7 @@ static int peel_onion(const char *name, int len, unsigned char *sha1,
                o = deref_tag(o, name, sp - name - 2);
                if (!o || (!o->parsed && !parse_object(&o->oid)))
                        return -1;
-               hashcpy(sha1, o->oid.hash);
+               oidcpy(oid, &o->oid);
                return 0;
        }
 
@@ -878,7 +878,7 @@ static int peel_onion(const char *name, int len, unsigned char *sha1,
        if (!o)
                return -1;
 
-       hashcpy(sha1, o->oid.hash);
+       oidcpy(oid, &o->oid);
        if (sp[0] == '/') {
                /* "$commit^{/foo}" */
                char *prefix;
@@ -894,17 +894,17 @@ static int peel_onion(const char *name, int len, unsigned char *sha1,
 
                prefix = xstrndup(sp + 1, name + len - 1 - (sp + 1));
                commit_list_insert((struct commit *)o, &list);
-               ret = get_sha1_oneline(prefix, sha1, list);
+               ret = get_oid_oneline(prefix, oid, list);
                free(prefix);
                return ret;
        }
        return 0;
 }
 
-static int get_describe_name(const char *name, int len, unsigned char *sha1)
+static int get_describe_name(const char *name, int len, struct object_id *oid)
 {
        const char *cp;
-       unsigned flags = GET_SHA1_QUIETLY | GET_SHA1_COMMIT;
+       unsigned flags = GET_OID_QUIETLY | GET_OID_COMMIT;
 
        for (cp = name + len - 1; name + 2 <= cp; cp--) {
                char ch = *cp;
@@ -915,14 +915,14 @@ static int get_describe_name(const char *name, int len, unsigned char *sha1)
                        if (ch == 'g' && cp[-1] == '-') {
                                cp++;
                                len -= cp - name;
-                               return get_short_sha1(cp, len, sha1, flags);
+                               return get_short_oid(cp, len, oid, flags);
                        }
                }
        }
        return -1;
 }
 
-static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned lookup_flags)
+static int get_oid_1(const char *name, int len, struct object_id *oid, unsigned lookup_flags)
 {
        int ret, has_suffix;
        const char *cp;
@@ -949,25 +949,25 @@ static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned l
                if (!num && len1 == len - 1)
                        num = 1;
                if (has_suffix == '^')
-                       return get_parent(name, len1, sha1, num);
+                       return get_parent(name, len1, oid, num);
                /* else if (has_suffix == '~') -- goes without saying */
-               return get_nth_ancestor(name, len1, sha1, num);
+               return get_nth_ancestor(name, len1, oid, num);
        }
 
-       ret = peel_onion(name, len, sha1, lookup_flags);
+       ret = peel_onion(name, len, oid, lookup_flags);
        if (!ret)
                return 0;
 
-       ret = get_sha1_basic(name, len, sha1, lookup_flags);
+       ret = get_oid_basic(name, len, oid, lookup_flags);
        if (!ret)
                return 0;
 
        /* It could be describe output that is "SOMETHING-gXXXX" */
-       ret = get_describe_name(name, len, sha1);
+       ret = get_describe_name(name, len, oid);
        if (!ret)
                return 0;
 
-       return get_short_sha1(name, len, sha1, lookup_flags);
+       return get_short_oid(name, len, oid, lookup_flags);
 }
 
 /*
@@ -1004,7 +1004,7 @@ static int handle_one_ref(const char *path, const struct object_id *oid,
        return 0;
 }
 
-static int get_sha1_oneline(const char *prefix, unsigned char *sha1,
+static int get_oid_oneline(const char *prefix, struct object_id *oid,
                            struct commit_list *list)
 {
        struct commit_list *backup = NULL, *l;
@@ -1044,7 +1044,7 @@ static int get_sha1_oneline(const char *prefix, unsigned char *sha1,
                unuse_commit_buffer(commit, buf);
 
                if (matches) {
-                       hashcpy(sha1, commit->object.oid.hash);
+                       oidcpy(oid, &commit->object.oid);
                        found = 1;
                        break;
                }
@@ -1140,7 +1140,7 @@ int get_oid_mb(const char *name, struct object_id *oid)
                struct strbuf sb;
                strbuf_init(&sb, dots - name);
                strbuf_add(&sb, name, dots - name);
-               st = get_sha1_committish(sb.buf, oid_tmp.hash);
+               st = get_oid_committish(sb.buf, &oid_tmp);
                strbuf_release(&sb);
        }
        if (st)
@@ -1149,7 +1149,7 @@ int get_oid_mb(const char *name, struct object_id *oid)
        if (!one)
                return -1;
 
-       if (get_sha1_committish(dots[3] ? (dots + 3) : "HEAD", oid_tmp.hash))
+       if (get_oid_committish(dots[3] ? (dots + 3) : "HEAD", &oid_tmp))
                return -1;
        two = lookup_commit_reference_gently(&oid_tmp, 0);
        if (!two)
@@ -1338,21 +1338,13 @@ int strbuf_check_branch_ref(struct strbuf *sb, const char *name)
 }
 
 /*
- * This is like "get_sha1_basic()", except it allows "sha1 expressions",
+ * This is like "get_oid_basic()", except it allows "object ID expressions",
  * notably "xyz^" for "parent of xyz"
  */
-int get_sha1(const char *name, unsigned char *sha1)
-{
-       struct object_context unused;
-       return get_sha1_with_context(name, 0, sha1, &unused);
-}
-
-/*
- * This is like "get_sha1()", but for struct object_id.
- */
 int get_oid(const char *name, struct object_id *oid)
 {
-       return get_sha1(name, oid->hash);
+       struct object_context unused;
+       return get_oid_with_context(name, 0, oid, &unused);
 }
 
 
@@ -1366,49 +1358,49 @@ int get_oid(const char *name, struct object_id *oid)
  * commit-ish. It is merely to give a hint to the disambiguation
  * machinery.
  */
-int get_sha1_committish(const char *name, unsigned char *sha1)
+int get_oid_committish(const char *name, struct object_id *oid)
 {
        struct object_context unused;
-       return get_sha1_with_context(name, GET_SHA1_COMMITTISH,
-                                    sha1, &unused);
+       return get_oid_with_context(name, GET_OID_COMMITTISH,
+                                   oid, &unused);
 }
 
-int get_sha1_treeish(const char *name, unsigned char *sha1)
+int get_oid_treeish(const char *name, struct object_id *oid)
 {
        struct object_context unused;
-       return get_sha1_with_context(name, GET_SHA1_TREEISH,
-                                    sha1, &unused);
+       return get_oid_with_context(name, GET_OID_TREEISH,
+                                   oid, &unused);
 }
 
-int get_sha1_commit(const char *name, unsigned char *sha1)
+int get_oid_commit(const char *name, struct object_id *oid)
 {
        struct object_context unused;
-       return get_sha1_with_context(name, GET_SHA1_COMMIT,
-                                    sha1, &unused);
+       return get_oid_with_context(name, GET_OID_COMMIT,
+                                   oid, &unused);
 }
 
-int get_sha1_tree(const char *name, unsigned char *sha1)
+int get_oid_tree(const char *name, struct object_id *oid)
 {
        struct object_context unused;
-       return get_sha1_with_context(name, GET_SHA1_TREE,
-                                    sha1, &unused);
+       return get_oid_with_context(name, GET_OID_TREE,
+                                   oid, &unused);
 }
 
-int get_sha1_blob(const char *name, unsigned char *sha1)
+int get_oid_blob(const char *name, struct object_id *oid)
 {
        struct object_context unused;
-       return get_sha1_with_context(name, GET_SHA1_BLOB,
-                                    sha1, &unused);
+       return get_oid_with_context(name, GET_OID_BLOB,
+                                   oid, &unused);
 }
 
 /* Must be called only when object_name:filename doesn't exist. */
-static void diagnose_invalid_sha1_path(const char *prefix,
-                                      const char *filename,
-                                      const unsigned char *tree_sha1,
-                                      const char *object_name,
-                                      int object_name_len)
+static void diagnose_invalid_oid_path(const char *prefix,
+                                     const char *filename,
+                                     const struct object_id *tree_oid,
+                                     const char *object_name,
+                                     int object_name_len)
 {
-       unsigned char sha1[20];
+       struct object_id oid;
        unsigned mode;
 
        if (!prefix)
@@ -1420,8 +1412,8 @@ static void diagnose_invalid_sha1_path(const char *prefix,
        if (is_missing_file_error(errno)) {
                char *fullname = xstrfmt("%s%s", prefix, filename);
 
-               if (!get_tree_entry(tree_sha1, fullname,
-                                   sha1, &mode)) {
+               if (!get_tree_entry(tree_oid->hash, fullname,
+                                   oid.hash, &mode)) {
                        die("Path '%s' exists, but not '%s'.\n"
                            "Did you mean '%.*s:%s' aka '%.*s:./%s'?",
                            fullname,
@@ -1504,24 +1496,24 @@ static char *resolve_relative_path(const char *rel)
                           rel);
 }
 
-static int get_sha1_with_context_1(const char *name,
-                                  unsigned flags,
-                                  const char *prefix,
-                                  unsigned char *sha1,
-                                  struct object_context *oc)
+static int get_oid_with_context_1(const char *name,
+                                 unsigned flags,
+                                 const char *prefix,
+                                 struct object_id *oid,
+                                 struct object_context *oc)
 {
        int ret, bracket_depth;
        int namelen = strlen(name);
        const char *cp;
-       int only_to_die = flags & GET_SHA1_ONLY_TO_DIE;
+       int only_to_die = flags & GET_OID_ONLY_TO_DIE;
 
        if (only_to_die)
-               flags |= GET_SHA1_QUIETLY;
+               flags |= GET_OID_QUIETLY;
 
        memset(oc, 0, sizeof(*oc));
        oc->mode = S_IFINVALID;
        strbuf_init(&oc->symlink_path, 0);
-       ret = get_sha1_1(name, namelen, sha1, flags);
+       ret = get_oid_1(name, namelen, oid, flags);
        if (!ret)
                return ret;
        /*
@@ -1541,7 +1533,7 @@ static int get_sha1_with_context_1(const char *name,
 
                        for_each_ref(handle_one_ref, &list);
                        commit_list_sort_by_date(&list);
-                       return get_sha1_oneline(name + 2, sha1, list);
+                       return get_oid_oneline(name + 2, oid, list);
                }
                if (namelen < 3 ||
                    name[2] != ':' ||
@@ -1559,7 +1551,7 @@ static int get_sha1_with_context_1(const char *name,
                        namelen = strlen(cp);
                }
 
-               if (flags & GET_SHA1_RECORD_PATH)
+               if (flags & GET_OID_RECORD_PATH)
                        oc->path = xstrdup(cp);
 
                if (!active_cache)
@@ -1573,7 +1565,7 @@ static int get_sha1_with_context_1(const char *name,
                            memcmp(ce->name, cp, namelen))
                                break;
                        if (ce_stage(ce) == stage) {
-                               hashcpy(sha1, ce->oid.hash);
+                               oidcpy(oid, &ce->oid);
                                oc->mode = ce->ce_mode;
                                free(new_path);
                                return 0;
@@ -1594,36 +1586,36 @@ static int get_sha1_with_context_1(const char *name,
                        break;
        }
        if (*cp == ':') {
-               unsigned char tree_sha1[20];
+               struct object_id tree_oid;
                int len = cp - name;
                unsigned sub_flags = flags;
 
-               sub_flags &= ~GET_SHA1_DISAMBIGUATORS;
-               sub_flags |= GET_SHA1_TREEISH;
+               sub_flags &= ~GET_OID_DISAMBIGUATORS;
+               sub_flags |= GET_OID_TREEISH;
 
-               if (!get_sha1_1(name, len, tree_sha1, sub_flags)) {
+               if (!get_oid_1(name, len, &tree_oid, sub_flags)) {
                        const char *filename = cp+1;
                        char *new_filename = NULL;
 
                        new_filename = resolve_relative_path(filename);
                        if (new_filename)
                                filename = new_filename;
-                       if (flags & GET_SHA1_FOLLOW_SYMLINKS) {
-                               ret = get_tree_entry_follow_symlinks(tree_sha1,
-                                       filename, sha1, &oc->symlink_path,
+                       if (flags & GET_OID_FOLLOW_SYMLINKS) {
+                               ret = get_tree_entry_follow_symlinks(tree_oid.hash,
+                                       filename, oid->hash, &oc->symlink_path,
                                        &oc->mode);
                        } else {
-                               ret = get_tree_entry(tree_sha1, filename,
-                                                    sha1, &oc->mode);
+                               ret = get_tree_entry(tree_oid.hash, filename,
+                                                    oid->hash, &oc->mode);
                                if (ret && only_to_die) {
-                                       diagnose_invalid_sha1_path(prefix,
+                                       diagnose_invalid_oid_path(prefix,
                                                                   filename,
-                                                                  tree_sha1,
+                                                                  &tree_oid,
                                                                   name, len);
                                }
                        }
-                       hashcpy(oc->tree, tree_sha1);
-                       if (flags & GET_SHA1_RECORD_PATH)
+                       hashcpy(oc->tree, tree_oid.hash);
+                       if (flags & GET_OID_RECORD_PATH)
                                oc->path = xstrdup(filename);
 
                        free(new_filename);
@@ -1646,13 +1638,13 @@ static int get_sha1_with_context_1(const char *name,
 void maybe_die_on_misspelt_object_name(const char *name, const char *prefix)
 {
        struct object_context oc;
-       unsigned char sha1[20];
-       get_sha1_with_context_1(name, GET_SHA1_ONLY_TO_DIE, prefix, sha1, &oc);
+       struct object_id oid;
+       get_oid_with_context_1(name, GET_OID_ONLY_TO_DIE, prefix, &oid, &oc);
 }
 
-int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *oc)
+int get_oid_with_context(const char *str, unsigned flags, struct object_id *oid, struct object_context *oc)
 {
-       if (flags & GET_SHA1_FOLLOW_SYMLINKS && flags & GET_SHA1_ONLY_TO_DIE)
+       if (flags & GET_OID_FOLLOW_SYMLINKS && flags & GET_OID_ONLY_TO_DIE)
                die("BUG: incompatible flags for get_sha1_with_context");
-       return get_sha1_with_context_1(str, flags, NULL, sha1, oc);
+       return get_oid_with_context_1(str, flags, NULL, oid, oc);
 }
index 54359d549075b5cfe1670ca979ff3cf5eeedc9d1..f5591e56dab67d6113deb8196c4a68c8af3f2ee0 100644 (file)
--- a/shallow.c
+++ b/shallow.c
@@ -107,7 +107,7 @@ struct commit_list *get_shallow_commits(struct object_array *heads, int depth,
                cur_depth++;
                if ((depth != INFINITE_DEPTH && cur_depth >= depth) ||
                    (is_repository_shallow() && !commit->parents &&
-                    (graft = lookup_commit_graft(commit->object.oid.hash)) != NULL &&
+                    (graft = lookup_commit_graft(&commit->object.oid)) != NULL &&
                     graft->nr_parent < 0)) {
                        commit_list_insert(commit, &result);
                        commit->object.flags |= shallow_flag;
@@ -398,7 +398,7 @@ void prepare_shallow_info(struct shallow_info *info, struct oid_array *sa)
        for (i = 0; i < sa->nr; i++) {
                if (has_object_file(sa->oid + i)) {
                        struct commit_graft *graft;
-                       graft = lookup_commit_graft(sa->oid[i].hash);
+                       graft = lookup_commit_graft(&sa->oid[i]);
                        if (graft && graft->nr_parent < 0)
                                continue;
                        info->ours[info->nr_ours++] = i;
index 89d22e3b0903a220fa958b8d912607828ab2a9ba..323c49ceb35cb053434248df869578e649ccadc0 100644 (file)
--- a/strbuf.c
+++ b/strbuf.c
@@ -476,6 +476,7 @@ int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term)
        /* Translate slopbuf to NULL, as we cannot call realloc on it */
        if (!sb->alloc)
                sb->buf = NULL;
+       errno = 0;
        r = getdelim(&sb->buf, &sb->alloc, term, fp);
 
        if (r > 0) {
index 2075384e0b2df97a6d113acebcbcdcc853237166..e705b94db55578aabb2063f7364220978cea5a40 100644 (file)
--- a/strbuf.h
+++ b/strbuf.h
@@ -68,7 +68,7 @@ struct strbuf {
 };
 
 extern char strbuf_slopbuf[];
-#define STRBUF_INIT  { 0, 0, strbuf_slopbuf }
+#define STRBUF_INIT  { .alloc = 0, .len = 0, .buf = strbuf_slopbuf }
 
 /**
  * Life Cycle Functions
index 86de8d7bfbcd781b50571f867f0669c84093eca3..6edb97c1c68c063216bda710d5880b1d08de27da 100644 (file)
@@ -6,10 +6,13 @@
 #include "pkt-line.h"
 
 int cmd2process_cmp(const void *unused_cmp_data,
-                   const struct subprocess_entry *e1,
-                   const struct subprocess_entry *e2,
+                   const void *entry,
+                   const void *entry_or_key,
                    const void *unused_keydata)
 {
+       const struct subprocess_entry *e1 = entry;
+       const struct subprocess_entry *e2 = entry_or_key;
+
        return strcmp(e1->cmd, e2->cmd);
 }
 
index caa91a9b92f2256a33d3330b1084a205bef98632..49701998c9bd663073244e64c4edd7e80991a3ef 100644 (file)
@@ -43,8 +43,8 @@ struct subprocess_capability {
 
 /* Function to test two subprocess hashmap entries for equality. */
 extern int cmd2process_cmp(const void *unused_cmp_data,
-                          const struct subprocess_entry *e1,
-                          const struct subprocess_entry *e2,
+                          const void *e1,
+                          const void *e2,
                           const void *unused_keydata);
 
 /*
index 5fe2d0787745de4d97218c738b808667dc8348d3..0c839019e1dca2e30ac0113303d55b4387bbe96d 100644 (file)
@@ -35,19 +35,25 @@ enum lookup_type {
 };
 
 static int config_path_cmp(const void *unused_cmp_data,
-                          const struct submodule_entry *a,
-                          const struct submodule_entry *b,
+                          const void *entry,
+                          const void *entry_or_key,
                           const void *unused_keydata)
 {
+       const struct submodule_entry *a = entry;
+       const struct submodule_entry *b = entry_or_key;
+
        return strcmp(a->config->path, b->config->path) ||
               hashcmp(a->config->gitmodules_sha1, b->config->gitmodules_sha1);
 }
 
 static int config_name_cmp(const void *unused_cmp_data,
-                          const struct submodule_entry *a,
-                          const struct submodule_entry *b,
+                          const void *entry,
+                          const void *entry_or_key,
                           const void *unused_keydata)
 {
+       const struct submodule_entry *a = entry;
+       const struct submodule_entry *b = entry_or_key;
+
        return strcmp(a->config->name, b->config->name) ||
               hashcmp(a->config->gitmodules_sha1, b->config->gitmodules_sha1);
 }
@@ -59,8 +65,8 @@ static struct submodule_cache *submodule_cache_alloc(void)
 
 static void submodule_cache_init(struct submodule_cache *cache)
 {
-       hashmap_init(&cache->for_path, (hashmap_cmp_fn) config_path_cmp, NULL, 0);
-       hashmap_init(&cache->for_name, (hashmap_cmp_fn) config_name_cmp, NULL, 0);
+       hashmap_init(&cache->for_path, config_path_cmp, NULL, 0);
+       hashmap_init(&cache->for_name, config_name_cmp, NULL, 0);
        cache->initialized = 1;
 }
 
@@ -232,7 +238,7 @@ static struct submodule *lookup_or_create_by_name(struct submodule_cache *cache,
 static int parse_fetch_recurse(const char *opt, const char *arg,
                               int die_on_error)
 {
-       switch (git_config_maybe_bool(opt, arg)) {
+       switch (git_parse_maybe_bool(arg)) {
        case 1:
                return RECURSE_SUBMODULES_ON;
        case 0:
@@ -248,6 +254,14 @@ static int parse_fetch_recurse(const char *opt, const char *arg,
        }
 }
 
+int parse_submodule_fetchjobs(const char *var, const char *value)
+{
+       int fetchjobs = git_config_int(var, value);
+       if (fetchjobs < 0)
+               die(_("negative values not allowed for submodule.fetchjobs"));
+       return fetchjobs;
+}
+
 int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg)
 {
        return parse_fetch_recurse(opt, arg, 1);
@@ -277,7 +291,7 @@ int option_fetch_parse_recurse_submodules(const struct option *opt,
 static int parse_update_recurse(const char *opt, const char *arg,
                                int die_on_error)
 {
-       switch (git_config_maybe_bool(opt, arg)) {
+       switch (git_parse_maybe_bool(arg)) {
        case 1:
                return RECURSE_SUBMODULES_ON;
        case 0:
@@ -297,7 +311,7 @@ int parse_update_recurse_submodules_arg(const char *opt, const char *arg)
 static int parse_push_recurse(const char *opt, const char *arg,
                               int die_on_error)
 {
-       switch (git_config_maybe_bool(opt, arg)) {
+       switch (git_parse_maybe_bool(arg)) {
        case 1:
                /* There's no simple "on" value when pushing */
                if (die_on_error)
@@ -441,19 +455,19 @@ static int parse_config(const char *var, const char *value, void *data)
        return ret;
 }
 
-int gitmodule_sha1_from_commit(const unsigned char *treeish_name,
-                                     unsigned char *gitmodules_sha1,
+int gitmodule_oid_from_commit(const struct object_id *treeish_name,
+                                     struct object_id *gitmodules_oid,
                                      struct strbuf *rev)
 {
        int ret = 0;
 
-       if (is_null_sha1(treeish_name)) {
-               hashclr(gitmodules_sha1);
+       if (is_null_oid(treeish_name)) {
+               oidclr(gitmodules_oid);
                return 1;
        }
 
-       strbuf_addf(rev, "%s:.gitmodules", sha1_to_hex(treeish_name));
-       if (get_sha1(rev->buf, gitmodules_sha1) >= 0)
+       strbuf_addf(rev, "%s:.gitmodules", oid_to_hex(treeish_name));
+       if (get_oid(rev->buf, gitmodules_oid) >= 0)
                ret = 1;
 
        return ret;
@@ -464,13 +478,13 @@ int gitmodule_sha1_from_commit(const unsigned char *treeish_name,
  * revisions.
  */
 static const struct submodule *config_from(struct submodule_cache *cache,
-               const unsigned char *treeish_name, const char *key,
+               const struct object_id *treeish_name, const char *key,
                enum lookup_type lookup_type)
 {
        struct strbuf rev = STRBUF_INIT;
        unsigned long config_size;
        char *config = NULL;
-       unsigned char sha1[20];
+       struct object_id oid;
        enum object_type type;
        const struct submodule *submodule = NULL;
        struct parse_config_parameter parameter;
@@ -490,28 +504,28 @@ static const struct submodule *config_from(struct submodule_cache *cache,
                return entry->config;
        }
 
-       if (!gitmodule_sha1_from_commit(treeish_name, sha1, &rev))
+       if (!gitmodule_oid_from_commit(treeish_name, &oid, &rev))
                goto out;
 
        switch (lookup_type) {
        case lookup_name:
-               submodule = cache_lookup_name(cache, sha1, key);
+               submodule = cache_lookup_name(cache, oid.hash, key);
                break;
        case lookup_path:
-               submodule = cache_lookup_path(cache, sha1, key);
+               submodule = cache_lookup_path(cache, oid.hash, key);
                break;
        }
        if (submodule)
                goto out;
 
-       config = read_sha1_file(sha1, &type, &config_size);
+       config = read_sha1_file(oid.hash, &type, &config_size);
        if (!config || type != OBJ_BLOB)
                goto out;
 
        /* fill the submodule config into the cache */
        parameter.cache = cache;
-       parameter.treeish_name = treeish_name;
-       parameter.gitmodules_sha1 = sha1;
+       parameter.treeish_name = treeish_name->hash;
+       parameter.gitmodules_sha1 = oid.hash;
        parameter.overwrite = 0;
        git_config_from_mem(parse_config, CONFIG_ORIGIN_SUBMODULE_BLOB, rev.buf,
                        config, config_size, &parameter);
@@ -520,9 +534,9 @@ static const struct submodule *config_from(struct submodule_cache *cache,
 
        switch (lookup_type) {
        case lookup_name:
-               return cache_lookup_name(cache, sha1, key);
+               return cache_lookup_name(cache, oid.hash, key);
        case lookup_path:
-               return cache_lookup_path(cache, sha1, key);
+               return cache_lookup_path(cache, oid.hash, key);
        default:
                return NULL;
        }
@@ -564,14 +578,14 @@ int parse_submodule_config_option(const char *var, const char *value)
        return submodule_config_option(the_repository, var, value);
 }
 
-const struct submodule *submodule_from_name(const unsigned char *treeish_name,
+const struct submodule *submodule_from_name(const struct object_id *treeish_name,
                const char *name)
 {
        submodule_cache_check_init(the_repository);
        return config_from(the_repository->submodule_cache, treeish_name, name, lookup_name);
 }
 
-const struct submodule *submodule_from_path(const unsigned char *treeish_name,
+const struct submodule *submodule_from_path(const struct object_id *treeish_name,
                const char *path)
 {
        submodule_cache_check_init(the_repository);
@@ -579,7 +593,7 @@ const struct submodule *submodule_from_path(const unsigned char *treeish_name,
 }
 
 const struct submodule *submodule_from_cache(struct repository *repo,
-                                            const unsigned char *treeish_name,
+                                            const struct object_id *treeish_name,
                                             const char *key)
 {
        submodule_cache_check_init(repo);
index 233bfcb7fff0b2dedc64fbb11d167734bf0fad7e..cccd34b929f5299fbba6f43c74daeb96773aebdf 100644 (file)
@@ -27,6 +27,7 @@ struct repository;
 
 extern void submodule_cache_free(struct submodule_cache *cache);
 
+extern int parse_submodule_fetchjobs(const char *var, const char *value);
 extern int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg);
 struct option;
 extern int option_fetch_parse_recurse_submodules(const struct option *opt,
@@ -37,15 +38,15 @@ extern int parse_submodule_config_option(const char *var, const char *value);
 extern int submodule_config_option(struct repository *repo,
                                   const char *var, const char *value);
 extern const struct submodule *submodule_from_name(
-               const unsigned char *commit_or_tree, const char *name);
+               const struct object_id *commit_or_tree, const char *name);
 extern const struct submodule *submodule_from_path(
-               const unsigned char *commit_or_tree, const char *path);
+               const struct object_id *commit_or_tree, const char *path);
 extern const struct submodule *submodule_from_cache(struct repository *repo,
-                                                   const unsigned char *treeish_name,
+                                                   const struct object_id *treeish_name,
                                                    const char *key);
-extern int gitmodule_sha1_from_commit(const unsigned char *commit_sha1,
-                                     unsigned char *gitmodules_sha1,
-                                     struct strbuf *rev);
+extern int gitmodule_oid_from_commit(const struct object_id *commit_oid,
+                                    struct object_id *gitmodules_oid,
+                                    struct strbuf *rev);
 extern void submodule_free(void);
 
 #endif /* SUBMODULE_CONFIG_H */
index 6531c5d6094e47b251e69ce741699abfee7a64df..e072036e7965ca82a665ac1eeb88bfb44fa4569a 100644 (file)
 #include "worktree.h"
 #include "parse-options.h"
 
-static int config_fetch_recurse_submodules = RECURSE_SUBMODULES_ON_DEMAND;
 static int config_update_recurse_submodules = RECURSE_SUBMODULES_OFF;
-static int parallel_jobs = 1;
 static struct string_list changed_submodule_paths = STRING_LIST_INIT_DUP;
 static int initialized_fetch_ref_tips;
 static struct oid_array ref_tips_before_fetch;
 static struct oid_array ref_tips_after_fetch;
 
 /*
- * The following flag is set if the .gitmodules file is unmerged. We then
- * disable recursion for all submodules where .git/config doesn't have a
- * matching config entry because we can't guess what might be configured in
- * .gitmodules unless the user resolves the conflict. When a command line
- * option is given (which always overrides configuration) this flag will be
- * ignored.
+ * Check if the .gitmodules file is unmerged. Parsing of the .gitmodules file
+ * will be disabled because we can't guess what might be configured in
+ * .gitmodules unless the user resolves the conflict.
  */
-static int gitmodules_is_unmerged;
+int is_gitmodules_unmerged(const struct index_state *istate)
+{
+       int pos = index_name_pos(istate, GITMODULES_FILE, strlen(GITMODULES_FILE));
+       if (pos < 0) { /* .gitmodules not found or isn't merged */
+               pos = -1 - pos;
+               if (istate->cache_nr > pos) {  /* there is a .gitmodules */
+                       const struct cache_entry *ce = istate->cache[pos];
+                       if (ce_namelen(ce) == strlen(GITMODULES_FILE) &&
+                           !strcmp(ce->name, GITMODULES_FILE))
+                               return 1;
+               }
+       }
+
+       return 0;
+}
 
 /*
- * This flag is set if the .gitmodules file had unstaged modifications on
- * startup. This must be checked before allowing modifications to the
- * .gitmodules file with the intention to stage them later, because when
- * continuing we would stage the modifications the user didn't stage herself
- * too. That might change in a future version when we learn to stage the
- * changes we do ourselves without staging any previous modifications.
+ * Check if the .gitmodules file has unstaged modifications.  This must be
+ * checked before allowing modifications to the .gitmodules file with the
+ * intention to stage them later, because when continuing we would stage the
+ * modifications the user didn't stage herself too. That might change in a
+ * future version when we learn to stage the changes we do ourselves without
+ * staging any previous modifications.
  */
-static int gitmodules_is_modified;
-
-int is_staging_gitmodules_ok(void)
+int is_staging_gitmodules_ok(const struct index_state *istate)
 {
-       return !gitmodules_is_modified;
+       int pos = index_name_pos(istate, GITMODULES_FILE, strlen(GITMODULES_FILE));
+
+       if ((pos >= 0) && (pos < istate->cache_nr)) {
+               struct stat st;
+               if (lstat(GITMODULES_FILE, &st) == 0 &&
+                   ce_match_stat(istate->cache[pos], &st, 0) & DATA_CHANGED)
+                       return 0;
+       }
+
+       return 1;
 }
 
 /*
@@ -63,13 +79,13 @@ int update_path_in_gitmodules(const char *oldpath, const char *newpath)
        struct strbuf entry = STRBUF_INIT;
        const struct submodule *submodule;
 
-       if (!file_exists(".gitmodules")) /* Do nothing without .gitmodules */
+       if (!file_exists(GITMODULES_FILE)) /* Do nothing without .gitmodules */
                return -1;
 
-       if (gitmodules_is_unmerged)
+       if (is_gitmodules_unmerged(&the_index))
                die(_("Cannot change unmerged .gitmodules, resolve merge conflicts first"));
 
-       submodule = submodule_from_path(null_sha1, oldpath);
+       submodule = submodule_from_path(&null_oid, oldpath);
        if (!submodule || !submodule->name) {
                warning(_("Could not find section in .gitmodules where path=%s"), oldpath);
                return -1;
@@ -77,7 +93,7 @@ int update_path_in_gitmodules(const char *oldpath, const char *newpath)
        strbuf_addstr(&entry, "submodule.");
        strbuf_addstr(&entry, submodule->name);
        strbuf_addstr(&entry, ".path");
-       if (git_config_set_in_file_gently(".gitmodules", entry.buf, newpath) < 0) {
+       if (git_config_set_in_file_gently(GITMODULES_FILE, entry.buf, newpath) < 0) {
                /* Maybe the user already did that, don't error out here */
                warning(_("Could not update .gitmodules entry %s"), entry.buf);
                strbuf_release(&entry);
@@ -97,20 +113,20 @@ int remove_path_from_gitmodules(const char *path)
        struct strbuf sect = STRBUF_INIT;
        const struct submodule *submodule;
 
-       if (!file_exists(".gitmodules")) /* Do nothing without .gitmodules */
+       if (!file_exists(GITMODULES_FILE)) /* Do nothing without .gitmodules */
                return -1;
 
-       if (gitmodules_is_unmerged)
+       if (is_gitmodules_unmerged(&the_index))
                die(_("Cannot change unmerged .gitmodules, resolve merge conflicts first"));
 
-       submodule = submodule_from_path(null_sha1, path);
+       submodule = submodule_from_path(&null_oid, path);
        if (!submodule || !submodule->name) {
                warning(_("Could not find section in .gitmodules where path=%s"), path);
                return -1;
        }
        strbuf_addstr(&sect, "submodule.");
        strbuf_addstr(&sect, submodule->name);
-       if (git_config_rename_section_in_file(".gitmodules", sect.buf, NULL) < 0) {
+       if (git_config_rename_section_in_file(GITMODULES_FILE, sect.buf, NULL) < 0) {
                /* Maybe the user already did that, don't error out here */
                warning(_("Could not remove .gitmodules entry for %s"), path);
                strbuf_release(&sect);
@@ -122,7 +138,7 @@ int remove_path_from_gitmodules(const char *path)
 
 void stage_updated_gitmodules(void)
 {
-       if (add_file_to_cache(".gitmodules", 0))
+       if (add_file_to_cache(GITMODULES_FILE, 0))
                die(_("staging updated .gitmodules failed"));
 }
 
@@ -147,11 +163,11 @@ static int add_submodule_odb(const char *path)
 void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,
                                             const char *path)
 {
-       const struct submodule *submodule = submodule_from_path(null_sha1, path);
+       const struct submodule *submodule = submodule_from_path(&null_oid, path);
        if (submodule) {
                if (submodule->ignore)
                        handle_ignore_submodules_arg(diffopt, submodule->ignore);
-               else if (gitmodules_is_unmerged)
+               else if (is_gitmodules_unmerged(&the_index))
                        DIFF_OPT_SET(diffopt, IGNORE_SUBMODULES);
        }
 }
@@ -159,17 +175,8 @@ void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,
 /* For loading from the .gitmodules file. */
 static int git_modules_config(const char *var, const char *value, void *cb)
 {
-       if (!strcmp(var, "submodule.fetchjobs")) {
-               parallel_jobs = git_config_int(var, value);
-               if (parallel_jobs < 0)
-                       die(_("negative values not allowed for submodule.fetchJobs"));
-               return 0;
-       } else if (starts_with(var, "submodule."))
+       if (starts_with(var, "submodule."))
                return parse_submodule_config_option(var, value);
-       else if (!strcmp(var, "fetch.recursesubmodules")) {
-               config_fetch_recurse_submodules = parse_fetch_recurse_submodules_arg(var, value);
-               return 0;
-       }
        return 0;
 }
 
@@ -223,39 +230,6 @@ void load_submodule_cache(void)
        git_config(submodule_config, NULL);
 }
 
-void gitmodules_config(void)
-{
-       const char *work_tree = get_git_work_tree();
-       if (work_tree) {
-               struct strbuf gitmodules_path = STRBUF_INIT;
-               int pos;
-               strbuf_addstr(&gitmodules_path, work_tree);
-               strbuf_addstr(&gitmodules_path, "/.gitmodules");
-               if (read_cache() < 0)
-                       die("index file corrupt");
-               pos = cache_name_pos(".gitmodules", 11);
-               if (pos < 0) { /* .gitmodules not found or isn't merged */
-                       pos = -1 - pos;
-                       if (active_nr > pos) {  /* there is a .gitmodules */
-                               const struct cache_entry *ce = active_cache[pos];
-                               if (ce_namelen(ce) == 11 &&
-                                   !memcmp(ce->name, ".gitmodules", 11))
-                                       gitmodules_is_unmerged = 1;
-                       }
-               } else if (pos < active_nr) {
-                       struct stat st;
-                       if (lstat(".gitmodules", &st) == 0 &&
-                           ce_match_stat(active_cache[pos], &st, 0) & DATA_CHANGED)
-                               gitmodules_is_modified = 1;
-               }
-
-               if (!gitmodules_is_unmerged)
-                       git_config_from_file(git_modules_config,
-                               gitmodules_path.buf, NULL);
-               strbuf_release(&gitmodules_path);
-       }
-}
-
 static int gitmodules_cb(const char *var, const char *value, void *data)
 {
        struct repository *repo = data;
@@ -264,20 +238,34 @@ static int gitmodules_cb(const char *var, const char *value, void *data)
 
 void repo_read_gitmodules(struct repository *repo)
 {
-       char *gitmodules_path = repo_worktree_path(repo, ".gitmodules");
+       if (repo->worktree) {
+               char *gitmodules;
+
+               if (repo_read_index(repo) < 0)
+                       return;
+
+               gitmodules = repo_worktree_path(repo, GITMODULES_FILE);
+
+               if (!is_gitmodules_unmerged(repo->index))
+                       git_config_from_file(gitmodules_cb, gitmodules, repo);
 
-       git_config_from_file(gitmodules_cb, gitmodules_path, repo);
-       free(gitmodules_path);
+               free(gitmodules);
+       }
+}
+
+void gitmodules_config(void)
+{
+       repo_read_gitmodules(the_repository);
 }
 
-void gitmodules_config_sha1(const unsigned char *commit_sha1)
+void gitmodules_config_oid(const struct object_id *commit_oid)
 {
        struct strbuf rev = STRBUF_INIT;
-       unsigned char sha1[20];
+       struct object_id oid;
 
-       if (gitmodule_sha1_from_commit(commit_sha1, sha1, &rev)) {
-               git_config_from_blob_sha1(git_modules_config, rev.buf,
-                                         sha1, NULL);
+       if (gitmodule_oid_from_commit(commit_oid, &oid, &rev)) {
+               git_config_from_blob_oid(submodule_config, rev.buf,
+                                        &oid, NULL);
        }
        strbuf_release(&rev);
 }
@@ -293,7 +281,7 @@ int is_submodule_active(struct repository *repo, const char *path)
        const struct string_list *sl;
        const struct submodule *module;
 
-       module = submodule_from_cache(repo, null_sha1, path);
+       module = submodule_from_cache(repo, &null_oid, path);
 
        /* early return if there isn't a path->module mapping */
        if (!module)
@@ -720,11 +708,6 @@ void show_submodule_inline_diff(FILE *f, const char *path,
                clear_commit_marks(right, ~0);
 }
 
-void set_config_fetch_recurse_submodules(int value)
-{
-       config_fetch_recurse_submodules = value;
-}
-
 int should_update_submodules(void)
 {
        return config_update_recurse_submodules == RECURSE_SUBMODULES_ON;
@@ -738,7 +721,7 @@ const struct submodule *submodule_from_ce(const struct cache_entry *ce)
        if (!should_update_submodules())
                return NULL;
 
-       return submodule_from_path(null_sha1, ce->name);
+       return submodule_from_path(&null_oid, ce->name);
 }
 
 static struct oid_array *submodule_commits(struct string_list *submodules,
@@ -1015,7 +998,8 @@ static int push_submodule(const char *path,
  * Perform a check in the submodule to see if the remote and refspec work.
  * Die if the submodule can't be pushed.
  */
-static void submodule_push_check(const char *path, const struct remote *remote,
+static void submodule_push_check(const char *path, const char *head,
+                                const struct remote *remote,
                                 const char **refspec, int refspec_nr)
 {
        struct child_process cp = CHILD_PROCESS_INIT;
@@ -1023,6 +1007,7 @@ static void submodule_push_check(const char *path, const struct remote *remote,
 
        argv_array_push(&cp.args, "submodule--helper");
        argv_array_push(&cp.args, "push-check");
+       argv_array_push(&cp.args, head);
        argv_array_push(&cp.args, remote->name);
 
        for (i = 0; i < refspec_nr; i++)
@@ -1061,10 +1046,20 @@ int push_unpushed_submodules(struct oid_array *commits,
         * won't be propagated due to the remote being unconfigured (e.g. a URL
         * instead of a remote name).
         */
-       if (remote->origin != REMOTE_UNCONFIGURED)
+       if (remote->origin != REMOTE_UNCONFIGURED) {
+               char *head;
+               struct object_id head_oid;
+
+               head = resolve_refdup("HEAD", 0, head_oid.hash, NULL);
+               if (!head)
+                       die(_("Failed to resolve HEAD as a valid ref."));
+
                for (i = 0; i < needs_pushing.nr; i++)
                        submodule_push_check(needs_pushing.items[i].string,
-                                            remote, refspec, refspec_nr);
+                                            head, remote,
+                                            refspec, refspec_nr);
+               free(head);
+       }
 
        /* Actually push the submodules */
        for (i = 0; i < needs_pushing.nr; i++) {
@@ -1170,10 +1165,11 @@ struct submodule_parallel_fetch {
        const char *work_tree;
        const char *prefix;
        int command_line_option;
+       int default_option;
        int quiet;
        int result;
 };
-#define SPF_INIT {0, ARGV_ARRAY_INIT, NULL, NULL, 0, 0, 0}
+#define SPF_INIT {0, ARGV_ARRAY_INIT, NULL, NULL, 0, 0, 0, 0}
 
 static int get_next_submodule(struct child_process *cp,
                              struct strbuf *err, void *data, void **task_cb)
@@ -1192,9 +1188,9 @@ static int get_next_submodule(struct child_process *cp,
                if (!S_ISGITLINK(ce->ce_mode))
                        continue;
 
-               submodule = submodule_from_path(null_sha1, ce->name);
+               submodule = submodule_from_path(&null_oid, ce->name);
                if (!submodule)
-                       submodule = submodule_from_name(null_sha1, ce->name);
+                       submodule = submodule_from_name(&null_oid, ce->name);
 
                default_argv = "yes";
                if (spf->command_line_option == RECURSE_SUBMODULES_DEFAULT) {
@@ -1211,10 +1207,9 @@ static int get_next_submodule(struct child_process *cp,
                                        default_argv = "on-demand";
                                }
                        } else {
-                               if ((config_fetch_recurse_submodules == RECURSE_SUBMODULES_OFF) ||
-                                   gitmodules_is_unmerged)
+                               if (spf->default_option == RECURSE_SUBMODULES_OFF)
                                        continue;
-                               if (config_fetch_recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND) {
+                               if (spf->default_option == RECURSE_SUBMODULES_ON_DEMAND) {
                                        if (!unsorted_string_list_lookup(&changed_submodule_paths, ce->name))
                                                continue;
                                        default_argv = "on-demand";
@@ -1281,6 +1276,7 @@ static int fetch_finish(int retvalue, struct strbuf *err,
 
 int fetch_populated_submodules(const struct argv_array *options,
                               const char *prefix, int command_line_option,
+                              int default_option,
                               int quiet, int max_parallel_jobs)
 {
        int i;
@@ -1288,6 +1284,7 @@ int fetch_populated_submodules(const struct argv_array *options,
 
        spf.work_tree = get_git_work_tree();
        spf.command_line_option = command_line_option;
+       spf.default_option = default_option;
        spf.quiet = quiet;
        spf.prefix = prefix;
 
@@ -1303,9 +1300,6 @@ int fetch_populated_submodules(const struct argv_array *options,
        argv_array_push(&spf.args, "--recurse-submodules-default");
        /* default value, "--submodule-prefix" and its value are added later */
 
-       if (max_parallel_jobs < 0)
-               max_parallel_jobs = parallel_jobs;
-
        calculate_changed_submodule_paths();
        run_processes_parallel(max_parallel_jobs,
                               get_next_submodule,
@@ -1570,7 +1564,7 @@ int submodule_move_head(const char *path,
        if (old && !is_submodule_populated_gently(path, error_code_ptr))
                return 0;
 
-       sub = submodule_from_path(null_sha1, path);
+       sub = submodule_from_path(&null_oid, path);
 
        if (!sub)
                die("BUG: could not get submodule information for '%s'", path);
@@ -1825,11 +1819,6 @@ int merge_submodule(struct object_id *result, const char *path,
        return 0;
 }
 
-int parallel_submodules(void)
-{
-       return parallel_jobs;
-}
-
 /*
  * Embeds a single submodules git directory into the superprojects git dir,
  * non recursively.
@@ -1852,7 +1841,7 @@ static void relocate_single_git_dir_into_superproject(const char *prefix,
 
        real_old_git_dir = real_pathdup(old_git_dir, 1);
 
-       sub = submodule_from_path(null_sha1, path);
+       sub = submodule_from_path(&null_oid, path);
        if (!sub)
                die(_("could not lookup name for submodule '%s'"), path);
 
@@ -1908,7 +1897,7 @@ void absorb_git_dir_into_superproject(const char *prefix,
                * superproject did not rewrite the git file links yet,
                * fix it now.
                */
-               sub = submodule_from_path(null_sha1, path);
+               sub = submodule_from_path(&null_oid, path);
                if (!sub)
                        die(_("could not lookup name for submodule '%s'"), path);
                connect_work_tree_and_git_dir(path,
@@ -2051,7 +2040,7 @@ int submodule_to_gitdir(struct strbuf *buf, const char *submodule)
        }
        if (!is_git_directory(buf->buf)) {
                gitmodules_config();
-               sub = submodule_from_path(null_sha1, submodule);
+               sub = submodule_from_path(&null_oid, submodule);
                if (!sub) {
                        ret = -1;
                        goto cleanup;
index e85b1448638ac7255a48a1bc1e2d6409c3a85ba6..e402b004ff0a7d983d196eb1fc0e34bdd2bacb93 100644 (file)
@@ -33,7 +33,8 @@ struct submodule_update_strategy {
 };
 #define SUBMODULE_UPDATE_STRATEGY_INIT {SM_UPDATE_UNSPECIFIED, NULL}
 
-extern int is_staging_gitmodules_ok(void);
+extern int is_gitmodules_unmerged(const struct index_state *istate);
+extern int is_staging_gitmodules_ok(const struct index_state *istate);
 extern int update_path_in_gitmodules(const char *oldpath, const char *newpath);
 extern int remove_path_from_gitmodules(const char *path);
 extern void stage_updated_gitmodules(void);
@@ -48,7 +49,7 @@ int option_parse_recurse_submodules_worktree_updater(const struct option *opt,
 void load_submodule_cache(void);
 extern void gitmodules_config(void);
 extern void repo_read_gitmodules(struct repository *repo);
-extern void gitmodules_config_sha1(const unsigned char *commit_sha1);
+extern void gitmodules_config_oid(const struct object_id *commit_oid);
 extern int is_submodule_active(struct repository *repo, const char *path);
 /*
  * Determine if a submodule has been populated at a given 'path' by checking if
@@ -76,7 +77,6 @@ extern void show_submodule_inline_diff(FILE *f, const char *path,
                unsigned dirty_submodule, const char *meta,
                const char *del, const char *add, const char *reset,
                const struct diff_options *opt);
-extern void set_config_fetch_recurse_submodules(int value);
 /* Check if we want to update any submodule.*/
 extern int should_update_submodules(void);
 /*
@@ -87,6 +87,7 @@ extern const struct submodule *submodule_from_ce(const struct cache_entry *ce);
 extern void check_for_new_submodule_commits(struct object_id *oid);
 extern int fetch_populated_submodules(const struct argv_array *options,
                               const char *prefix, int command_line_option,
+                              int default_option,
                               int quiet, int max_parallel_jobs);
 extern unsigned is_submodule_modified(const char *path, int ignore_untracked);
 extern int submodule_uses_gitfile(const char *path);
@@ -112,7 +113,6 @@ extern int push_unpushed_submodules(struct oid_array *commits,
                                    const struct string_list *push_options,
                                    int dry_run);
 extern void connect_work_tree_and_git_dir(const char *work_tree, const char *git_dir);
-extern int parallel_submodules(void);
 /*
  * Given a submodule path (as in the index), return the repository
  * path of that submodule in 'buf'. Return -1 on error or when the
index 095d7395f3c25d042c60095e8c56d8a22a9a0ba6..6004c81f0bce4d701a341c963f56caca425da067 100644 (file)
@@ -13,20 +13,20 @@ static const char *get_value(const struct test_entry *e)
        return e->key + strlen(e->key) + 1;
 }
 
-static int test_entry_cmp(const void *unused_cmp_data,
-                         const struct test_entry *e1,
-                         const struct test_entry *e2,
-                         const char* key)
+static int test_entry_cmp(const void *cmp_data,
+                         const void *entry,
+                         const void *entry_or_key,
+                         const void *keydata)
 {
-       return strcmp(e1->key, key ? key : e2->key);
-}
-
-static int test_entry_cmp_icase(const void *unused_cmp_data,
-                               const struct test_entry *e1,
-                               const struct test_entry *e2,
-                               const char* key)
-{
-       return strcasecmp(e1->key, key ? key : e2->key);
+       const int ignore_case = cmp_data ? *((int *)cmp_data) : 0;
+       const struct test_entry *e1 = entry;
+       const struct test_entry *e2 = entry_or_key;
+       const char *key = keydata;
+
+       if (ignore_case)
+               return strcasecmp(e1->key, key ? key : e2->key);
+       else
+               return strcmp(e1->key, key ? key : e2->key);
 }
 
 static struct test_entry *alloc_test_entry(int hash, char *key, int klen,
@@ -96,8 +96,7 @@ static void perf_hashmap(unsigned int method, unsigned int rounds)
        if (method & TEST_ADD) {
                /* test adding to the map */
                for (j = 0; j < rounds; j++) {
-                       hashmap_init(&map, (hashmap_cmp_fn) test_entry_cmp,
-                                    NULL, 0);
+                       hashmap_init(&map, test_entry_cmp, NULL, 0);
 
                        /* add entries */
                        for (i = 0; i < TEST_SIZE; i++) {
@@ -109,7 +108,7 @@ static void perf_hashmap(unsigned int method, unsigned int rounds)
                }
        } else {
                /* test map lookups */
-               hashmap_init(&map, (hashmap_cmp_fn) test_entry_cmp, NULL, 0);
+               hashmap_init(&map, test_entry_cmp, NULL, 0);
 
                /* fill the map (sparsely if specified) */
                j = (method & TEST_SPARSE) ? TEST_SIZE / 10 : TEST_SIZE;
@@ -151,8 +150,7 @@ int cmd_main(int argc, const char **argv)
 
        /* init hash map */
        icase = argc > 1 && !strcmp("ignorecase", argv[1]);
-       hashmap_init(&map, (hashmap_cmp_fn) (icase ? test_entry_cmp_icase
-                       : test_entry_cmp), NULL, 0);
+       hashmap_init(&map, test_entry_cmp, &icase, 0);
 
        /* process commands from stdin */
        while (fgets(line, sizeof(line), stdin)) {
index 1ebe0f750c648cd4d92983c11ace9e8a86327dd1..2b3c5092a199835ea2e84339b473a9e29778178d 100644 (file)
@@ -38,6 +38,20 @@ struct test_data {
        const char *alternative; /* output: ... or this.      */
 };
 
+/*
+ * Compatibility wrappers for OpenBSD, whose basename(3) and dirname(3)
+ * have const parameters.
+ */
+static char *posix_basename(char *path)
+{
+       return basename(path);
+}
+
+static char *posix_dirname(char *path)
+{
+       return dirname(path);
+}
+
 static int test_function(struct test_data *data, char *(*func)(char *input),
        const char *funcname)
 {
@@ -251,10 +265,10 @@ int cmd_main(int argc, const char **argv)
        }
 
        if (argc == 2 && !strcmp(argv[1], "basename"))
-               return test_function(basename_data, basename, argv[1]);
+               return test_function(basename_data, posix_basename, argv[1]);
 
        if (argc == 2 && !strcmp(argv[1], "dirname"))
-               return test_function(dirname_data, dirname, argv[1]);
+               return test_function(dirname_data, posix_dirname, argv[1]);
 
        fprintf(stderr, "%s: unknown function name: %s\n", argv[0],
                argv[1] ? argv[1] : "(there was none)");
index c6c57bba0d397e44e8897b05d479a30b53311517..e13fbcc1b5c271c1b2a4a2b3449544e844282358 100644 (file)
@@ -41,7 +41,7 @@ int cmd_main(int argc, const char **argv)
        git_config(git_test_config, NULL);
 
        while (*arg) {
-               unsigned char commit_sha1[20];
+               struct object_id commit_oid;
                const struct submodule *submodule;
                const char *commit;
                const char *path_or_name;
@@ -50,14 +50,14 @@ int cmd_main(int argc, const char **argv)
                path_or_name = arg[1];
 
                if (commit[0] == '\0')
-                       hashclr(commit_sha1);
-               else if (get_sha1(commit, commit_sha1) < 0)
+                       oidclr(&commit_oid);
+               else if (get_oid(commit, &commit_oid) < 0)
                        die_usage(argc, argv, "Commit not found.");
 
                if (lookup_name) {
-                       submodule = submodule_from_name(commit_sha1, path_or_name);
+                       submodule = submodule_from_name(&commit_oid, path_or_name);
                } else
-                       submodule = submodule_from_path(commit_sha1, path_or_name);
+                       submodule = submodule_from_path(&commit_oid, path_or_name);
                if (!submodule)
                        die_usage(argc, argv, "Submodule not found.");
 
index ec2aa8f6879d68078caeccaff25d89178b9fb902..43679a4c640e874aed8d3a378a378b1a6080fc1c 100755 (executable)
@@ -31,6 +31,7 @@ then
                chmod 0700 ./gpghome &&
                GNUPGHOME="$(pwd)/gpghome" &&
                export GNUPGHOME &&
+               (gpgconf --kill gpg-agent 2>&1 >/dev/null || : ) &&
                gpg --homedir "${GNUPGHOME}" 2>/dev/null --import \
                        "$TEST_DIRECTORY"/lib-gpg/keyring.gpg &&
                gpg --homedir "${GNUPGHOME}" 2>/dev/null --import-ownertrust \
index c4814d248fc96e7dc0177b6987baa18853c6213c..86c1a51654fa6c1b049a313fe8d880c6a266ee62 100755 (executable)
@@ -315,18 +315,44 @@ test_expect_success 'init with separate gitdir' '
        test_path_is_dir realgitdir/refs
 '
 
-test_expect_success 'init in long base path' '
+test_lazy_prereq GETCWD_IGNORES_PERMS '
+       base=GETCWD_TEST_BASE_DIR &&
+       mkdir -p $base/dir &&
+       chmod 100 $base ||
+       error "bug in test script: cannot prepare $base"
+
+       (cd $base/dir && /bin/pwd -P)
+       status=$?
+
+       chmod 700 $base &&
+       rm -rf $base ||
+       error "bug in test script: cannot clean $base"
+       return $status
+'
+
+check_long_base_path () {
        # exceed initial buffer size of strbuf_getcwd()
        component=123456789abcdef &&
        test_when_finished "chmod 0700 $component; rm -rf $component" &&
        p31=$component/$component &&
        p127=$p31/$p31/$p31/$p31 &&
        mkdir -p $p127 &&
-       chmod 0111 $component &&
+       if test $# = 1
+       then
+               chmod $1 $component
+       fi &&
        (
                cd $p127 &&
                git init newdir
        )
+}
+
+test_expect_success 'init in long base path' '
+       check_long_base_path
+'
+
+test_expect_success GETCWD_IGNORES_PERMS 'init in long restricted base path' '
+       check_long_base_path 0111
 '
 
 test_expect_success 're-init on .git file' '
index e3bf821694553354a0be2e93b71038bddb1d689d..7ca2e65d102afd76dc4136a9f12c53a5ba0fce25 100755 (executable)
@@ -51,7 +51,9 @@ test_expect_success \
      treeM=$(git write-tree) &&
      echo treeM $treeM &&
      git ls-tree $treeM &&
-     sum bozbar frotz nitfol >M.sum &&
+     cp bozbar bozbar.M &&
+     cp frotz frotz.M &&
+     cp nitfol nitfol.M &&
      git diff-tree $treeH $treeM'
 
 test_expect_success \
@@ -61,8 +63,9 @@ test_expect_success \
      read_tree_u_must_succeed -m -u $treeH $treeM &&
      git ls-files --stage >1-3.out &&
      cmp M.out 1-3.out &&
-     sum bozbar frotz nitfol >actual3.sum &&
-     cmp M.sum actual3.sum &&
+     test_cmp bozbar.M bozbar &&
+     test_cmp frotz.M frotz &&
+     test_cmp nitfol.M nitfol &&
      check_cache_at bozbar clean &&
      check_cache_at frotz clean &&
      check_cache_at nitfol clean'
@@ -79,8 +82,9 @@ test_expect_success \
      test_might_fail git diff -U0 --no-index M.out 4.out >4diff.out &&
      compare_change 4diff.out expected &&
      check_cache_at yomin clean &&
-     sum bozbar frotz nitfol >actual4.sum &&
-     cmp M.sum actual4.sum &&
+     test_cmp bozbar.M bozbar &&
+     test_cmp frotz.M frotz &&
+     test_cmp nitfol.M nitfol &&
      echo yomin >yomin1 &&
      diff yomin yomin1 &&
      rm -f yomin1'
@@ -98,8 +102,9 @@ test_expect_success \
      test_might_fail git diff -U0 --no-index M.out 5.out >5diff.out &&
      compare_change 5diff.out expected &&
      check_cache_at yomin dirty &&
-     sum bozbar frotz nitfol >actual5.sum &&
-     cmp M.sum actual5.sum &&
+     test_cmp bozbar.M bozbar &&
+     test_cmp frotz.M frotz &&
+     test_cmp nitfol.M nitfol &&
      : dirty index should have prevented -u from checking it out. &&
      echo yomin yomin >yomin1 &&
      diff yomin yomin1 &&
@@ -115,8 +120,9 @@ test_expect_success \
      git ls-files --stage >6.out &&
      test_cmp M.out 6.out &&
      check_cache_at frotz clean &&
-     sum bozbar frotz nitfol >actual3.sum &&
-     cmp M.sum actual3.sum &&
+     test_cmp bozbar.M bozbar &&
+     test_cmp frotz.M frotz &&
+     test_cmp nitfol.M nitfol &&
      echo frotz >frotz1 &&
      diff frotz frotz1 &&
      rm -f frotz1'
@@ -132,8 +138,8 @@ test_expect_success \
      git ls-files --stage >7.out &&
      test_cmp M.out 7.out &&
      check_cache_at frotz dirty &&
-     sum bozbar frotz nitfol >actual7.sum &&
-     if cmp M.sum actual7.sum; then false; else :; fi &&
+     test_cmp bozbar.M bozbar &&
+     test_cmp nitfol.M nitfol &&
      : dirty index should have prevented -u from checking it out. &&
      echo frotz frotz >frotz1 &&
      diff frotz frotz1 &&
@@ -165,8 +171,10 @@ test_expect_success \
      read_tree_u_must_succeed -m -u $treeH $treeM &&
      git ls-files --stage >10.out &&
      cmp M.out 10.out &&
-     sum bozbar frotz nitfol >actual10.sum &&
-     cmp M.sum actual10.sum'
+     test_cmp bozbar.M bozbar &&
+     test_cmp frotz.M frotz &&
+     test_cmp nitfol.M nitfol
+'
 
 test_expect_success \
     '11 - dirty path removed.' \
@@ -209,11 +217,8 @@ test_expect_success \
      git ls-files --stage >14.out &&
      test_must_fail git diff -U0 --no-index M.out 14.out >14diff.out &&
      compare_change 14diff.out expected &&
-     sum bozbar frotz >actual14.sum &&
-     grep -v nitfol M.sum > expected14.sum &&
-     cmp expected14.sum actual14.sum &&
-     sum bozbar frotz nitfol >actual14a.sum &&
-     if cmp M.sum actual14a.sum; then false; else :; fi &&
+     test_cmp bozbar.M bozbar &&
+     test_cmp frotz.M frotz &&
      check_cache_at nitfol clean &&
      echo nitfol nitfol >nitfol1 &&
      diff nitfol nitfol1 &&
@@ -231,11 +236,8 @@ test_expect_success \
      test_must_fail git diff -U0 --no-index M.out 15.out >15diff.out &&
      compare_change 15diff.out expected &&
      check_cache_at nitfol dirty &&
-     sum bozbar frotz >actual15.sum &&
-     grep -v nitfol M.sum > expected15.sum &&
-     cmp expected15.sum actual15.sum &&
-     sum bozbar frotz nitfol >actual15a.sum &&
-     if cmp M.sum actual15a.sum; then false; else :; fi &&
+     test_cmp bozbar.M bozbar &&
+     test_cmp frotz.M frotz &&
      echo nitfol nitfol nitfol >nitfol1 &&
      diff nitfol nitfol1 &&
      rm -f nitfol1'
@@ -267,8 +269,10 @@ test_expect_success \
      git ls-files --stage >18.out &&
      test_cmp M.out 18.out &&
      check_cache_at bozbar clean &&
-     sum bozbar frotz nitfol >actual18.sum &&
-     cmp M.sum actual18.sum'
+     test_cmp bozbar.M bozbar &&
+     test_cmp frotz.M frotz &&
+     test_cmp nitfol.M nitfol
+'
 
 test_expect_success \
     '19 - local change already having a good result, further modified.' \
@@ -281,11 +285,8 @@ test_expect_success \
      git ls-files --stage >19.out &&
      test_cmp M.out 19.out &&
      check_cache_at bozbar dirty &&
-     sum frotz nitfol >actual19.sum &&
-     grep -v bozbar  M.sum > expected19.sum &&
-     cmp expected19.sum actual19.sum &&
-     sum bozbar frotz nitfol >actual19a.sum &&
-     if cmp M.sum actual19a.sum; then false; else :; fi &&
+     test_cmp frotz.M frotz &&
+     test_cmp nitfol.M nitfol &&
      echo gnusto gnusto >bozbar1 &&
      diff bozbar bozbar1 &&
      rm -f bozbar1'
@@ -300,8 +301,10 @@ test_expect_success \
      git ls-files --stage >20.out &&
      test_cmp M.out 20.out &&
      check_cache_at bozbar clean &&
-     sum bozbar frotz nitfol >actual20.sum &&
-     cmp M.sum actual20.sum'
+     test_cmp bozbar.M bozbar &&
+     test_cmp frotz.M frotz &&
+     test_cmp nitfol.M nitfol
+'
 
 test_expect_success \
     '21 - no local change, dirty cache.' \
diff --git a/t/t1200-tutorial.sh b/t/t1200-tutorial.sh
deleted file mode 100755 (executable)
index 397ccb6..0000000
+++ /dev/null
@@ -1,268 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) 2005 Johannes Schindelin
-#
-
-test_description='A simple turial in the form of a test case'
-
-. ./test-lib.sh
-
-test_expect_success 'blob'  '
-       echo "Hello World" > hello &&
-       echo "Silly example" > example &&
-
-       git update-index --add hello example &&
-
-       test blob = "$(git cat-file -t 557db03)"
-'
-
-test_expect_success 'blob 557db03' '
-       test "Hello World" = "$(git cat-file blob 557db03)"
-'
-
-echo "It's a new day for git" >>hello
-cat > diff.expect << EOF
-diff --git a/hello b/hello
-index 557db03..263414f 100644
---- a/hello
-+++ b/hello
-@@ -1 +1,2 @@
- Hello World
-+It's a new day for git
-EOF
-
-test_expect_success 'git diff-files -p' '
-       git diff-files -p > diff.output &&
-       test_cmp diff.expect diff.output
-'
-
-test_expect_success 'git diff' '
-       git diff > diff.output &&
-       test_cmp diff.expect diff.output
-'
-
-test_expect_success 'tree' '
-       tree=$(git write-tree 2>/dev/null) &&
-       test 8988da15d077d4829fc51d8544c097def6644dbb = $tree
-'
-
-test_expect_success 'git diff-index -p HEAD' '
-       test_tick &&
-       tree=$(git write-tree) &&
-       commit=$(echo "Initial commit" | git commit-tree $tree) &&
-       git update-ref HEAD $commit &&
-       git diff-index -p HEAD > diff.output &&
-       test_cmp diff.expect diff.output
-'
-
-test_expect_success 'git diff HEAD' '
-       git diff HEAD > diff.output &&
-       test_cmp diff.expect diff.output
-'
-
-cat > whatchanged.expect << EOF
-commit VARIABLE
-Author: VARIABLE
-Date:   VARIABLE
-
-    Initial commit
-
-diff --git a/example b/example
-new file mode 100644
-index 0000000..f24c74a
---- /dev/null
-+++ b/example
-@@ -0,0 +1 @@
-+Silly example
-diff --git a/hello b/hello
-new file mode 100644
-index 0000000..557db03
---- /dev/null
-+++ b/hello
-@@ -0,0 +1 @@
-+Hello World
-EOF
-
-test_expect_success 'git whatchanged -p --root' '
-       git whatchanged -p --root |
-               sed -e "1s/^\(.\{7\}\).\{40\}/\1VARIABLE/" \
-               -e "2,3s/^\(.\{8\}\).*$/\1VARIABLE/" \
-       > whatchanged.output &&
-       test_cmp whatchanged.expect whatchanged.output
-'
-
-test_expect_success 'git tag my-first-tag' '
-       git tag my-first-tag &&
-       test_cmp .git/refs/heads/master .git/refs/tags/my-first-tag
-'
-
-test_expect_success 'git checkout -b mybranch' '
-       git checkout -b mybranch &&
-       test_cmp .git/refs/heads/master .git/refs/heads/mybranch
-'
-
-cat > branch.expect <<EOF
-  master
-* mybranch
-EOF
-
-test_expect_success 'git branch' '
-       git branch > branch.output &&
-       test_cmp branch.expect branch.output
-'
-
-test_expect_success 'git resolve now fails' '
-       git checkout mybranch &&
-       echo "Work, work, work" >>hello &&
-       test_tick &&
-       git commit -m "Some work." -i hello &&
-
-       git checkout master &&
-
-       echo "Play, play, play" >>hello &&
-       echo "Lots of fun" >>example &&
-       test_tick &&
-       git commit -m "Some fun." -i hello example &&
-
-       test_must_fail git merge -m "Merge work in mybranch" mybranch
-'
-
-cat > hello << EOF
-Hello World
-It's a new day for git
-Play, play, play
-Work, work, work
-EOF
-
-cat > show-branch.expect << EOF
-* [master] Merge work in mybranch
- ! [mybranch] Some work.
---
--  [master] Merge work in mybranch
-*+ [mybranch] Some work.
-*  [master^] Some fun.
-EOF
-
-test_expect_success 'git show-branch' '
-       test_tick &&
-       git commit -m "Merge work in mybranch" -i hello &&
-       git show-branch --topo-order --more=1 master mybranch \
-               > show-branch.output &&
-       test_cmp show-branch.expect show-branch.output
-'
-
-cat > resolve.expect << EOF
-Updating VARIABLE..VARIABLE
-FASTFORWARD (no commit created; -m option ignored)
- example | 1 +
- hello   | 1 +
- 2 files changed, 2 insertions(+)
-EOF
-
-test_expect_success 'git resolve' '
-       git checkout mybranch &&
-       git merge -m "Merge upstream changes." master |
-               sed -e "1s/[0-9a-f]\{7\}/VARIABLE/g" \
-               -e "s/^Fast[- ]forward /FASTFORWARD /" >resolve.output
-'
-
-test_expect_success 'git resolve output' '
-       test_i18ncmp resolve.expect resolve.output
-'
-
-cat > show-branch2.expect << EOF
-! [master] Merge work in mybranch
- * [mybranch] Merge work in mybranch
---
--- [master] Merge work in mybranch
-EOF
-
-test_expect_success 'git show-branch (part 2)' '
-       git show-branch --topo-order master mybranch > show-branch2.output &&
-       test_cmp show-branch2.expect show-branch2.output
-'
-
-cat > show-branch3.expect << EOF
-! [master] Merge work in mybranch
- * [mybranch] Merge work in mybranch
---
--- [master] Merge work in mybranch
-+* [master^2] Some work.
-+* [master^] Some fun.
-EOF
-
-test_expect_success 'git show-branch (part 3)' '
-       git show-branch --topo-order --more=2 master mybranch \
-               > show-branch3.output &&
-       test_cmp show-branch3.expect show-branch3.output
-'
-
-test_expect_success 'rewind to "Some fun." and "Some work."' '
-       git checkout mybranch &&
-       git reset --hard master^2 &&
-       git checkout master &&
-       git reset --hard master^
-'
-
-cat > show-branch4.expect << EOF
-* [master] Some fun.
- ! [mybranch] Some work.
---
-*  [master] Some fun.
- + [mybranch] Some work.
-*+ [master^] Initial commit
-EOF
-
-test_expect_success 'git show-branch (part 4)' '
-       git show-branch --topo-order > show-branch4.output &&
-       test_cmp show-branch4.expect show-branch4.output
-'
-
-test_expect_success 'manual merge' '
-       mb=$(git merge-base HEAD mybranch) &&
-       git name-rev --name-only --tags $mb > name-rev.output &&
-       test "my-first-tag" = $(cat name-rev.output) &&
-
-       git read-tree -m -u $mb HEAD mybranch
-'
-
-cat > ls-files.expect << EOF
-100644 7f8b141b65fdcee47321e399a2598a235a032422 0      example
-100644 557db03de997c86a4a028e1ebd3a1ceb225be238 1      hello
-100644 ba42a2a96e3027f3333e13ede4ccf4498c3ae942 2      hello
-100644 cc44c73eb783565da5831b4d820c962954019b69 3      hello
-EOF
-
-test_expect_success 'git ls-files --stage' '
-       git ls-files --stage > ls-files.output &&
-       test_cmp ls-files.expect ls-files.output
-'
-
-cat > ls-files-unmerged.expect << EOF
-100644 557db03de997c86a4a028e1ebd3a1ceb225be238 1      hello
-100644 ba42a2a96e3027f3333e13ede4ccf4498c3ae942 2      hello
-100644 cc44c73eb783565da5831b4d820c962954019b69 3      hello
-EOF
-
-test_expect_success 'git ls-files --unmerged' '
-       git ls-files --unmerged > ls-files-unmerged.output &&
-       test_cmp ls-files-unmerged.expect ls-files-unmerged.output
-'
-
-test_expect_success 'git-merge-index' '
-       test_must_fail git merge-index git-merge-one-file hello
-'
-
-test_expect_success 'git ls-files --stage (part 2)' '
-       git ls-files --stage > ls-files.output2 &&
-       test_cmp ls-files.expect ls-files.output2
-'
-
-test_expect_success 'git repack' 'git repack'
-test_expect_success 'git prune-packed' 'git prune-packed'
-test_expect_success '-> only packed objects' '
-       git prune && # Remove conflict marked blobs
-       test $(find .git/objects/[0-9a-f][0-9a-f] -type f -print 2>/dev/null | wc -l) = 0
-'
-
-test_done
diff --git a/t/t1408-packed-refs.sh b/t/t1408-packed-refs.sh
new file mode 100755 (executable)
index 0000000..1e44a17
--- /dev/null
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+test_description='packed-refs entries are covered by loose refs'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+       test_tick &&
+       git commit --allow-empty -m one &&
+       one=$(git rev-parse HEAD) &&
+       git for-each-ref >actual &&
+       echo "$one commit       refs/heads/master" >expect &&
+       test_cmp expect actual &&
+
+       git pack-refs --all &&
+       git for-each-ref >actual &&
+       echo "$one commit       refs/heads/master" >expect &&
+       test_cmp expect actual &&
+
+       git checkout --orphan another &&
+       test_tick &&
+       git commit --allow-empty -m two &&
+       two=$(git rev-parse HEAD) &&
+       git checkout -B master &&
+       git branch -D another &&
+
+       git for-each-ref >actual &&
+       echo "$two commit       refs/heads/master" >expect &&
+       test_cmp expect actual &&
+
+       git reflog expire --expire=now --all &&
+       git prune &&
+       git tag -m v1.0 v1.0 master
+'
+
+test_expect_success 'no error from stale entry in packed-refs' '
+       git describe master >actual 2>&1 &&
+       echo "v1.0" >expect &&
+       test_cmp expect actual
+'
+
+test_done
index 9b182a0c328e9bc6eb1e24a0cbaec47d9fa36b24..afa27ffe2d869a5e7fdf8318d5b9957208a96c52 100755 (executable)
@@ -194,6 +194,33 @@ test_expect_success 'notice d/f conflict with existing ref' '
        test_must_fail git branch foo/bar/baz/lots/of/extra/components
 '
 
+test_expect_success 'reject packed-refs with unterminated line' '
+       cp .git/packed-refs .git/packed-refs.bak &&
+       test_when_finished "mv .git/packed-refs.bak .git/packed-refs" &&
+       printf "%s" "$HEAD refs/zzzzz" >>.git/packed-refs &&
+       echo "fatal: unterminated line in .git/packed-refs: $HEAD refs/zzzzz" >expected_err &&
+       test_must_fail git for-each-ref >out 2>err &&
+       test_cmp expected_err err
+'
+
+test_expect_success 'reject packed-refs containing junk' '
+       cp .git/packed-refs .git/packed-refs.bak &&
+       test_when_finished "mv .git/packed-refs.bak .git/packed-refs" &&
+       printf "%s\n" "bogus content" >>.git/packed-refs &&
+       echo "fatal: unexpected line in .git/packed-refs: bogus content" >expected_err &&
+       test_must_fail git for-each-ref >out 2>err &&
+       test_cmp expected_err err
+'
+
+test_expect_success 'reject packed-refs with a short SHA-1' '
+       cp .git/packed-refs .git/packed-refs.bak &&
+       test_when_finished "mv .git/packed-refs.bak .git/packed-refs" &&
+       printf "%.7s %s\n" $HEAD refs/zzzzz >>.git/packed-refs &&
+       printf "fatal: unexpected line in .git/packed-refs: %.7s %s\n" $HEAD refs/zzzzz >expected_err &&
+       test_must_fail git for-each-ref >out 2>err &&
+       test_cmp expected_err err
+'
+
 test_expect_success 'timeout if packed-refs.lock exists' '
        LOCK=.git/packed-refs.lock &&
        >"$LOCK" &&
@@ -211,4 +238,19 @@ test_expect_success 'retry acquiring packed-refs.lock' '
        git -c core.packedrefstimeout=3000 pack-refs --all --prune
 '
 
+test_expect_success SYMLINKS 'pack symlinked packed-refs' '
+       # First make sure that symlinking works when reading:
+       git update-ref refs/heads/loosy refs/heads/master &&
+       git for-each-ref >all-refs-before &&
+       mv .git/packed-refs .git/my-deviant-packed-refs &&
+       ln -s my-deviant-packed-refs .git/packed-refs &&
+       git for-each-ref >all-refs-linked &&
+       test_cmp all-refs-before all-refs-linked &&
+       git pack-refs --all --prune &&
+       git for-each-ref >all-refs-packed &&
+       test_cmp all-refs-before all-refs-packed &&
+       test -h .git/packed-refs &&
+       test "$(readlink .git/packed-refs)" = "my-deviant-packed-refs"
+'
+
 test_done
index 4428b9086e8bcb383df801834d0de323f316f4fa..fcfdd197bd352a9dca10233c2ba6d2aa4a66149e 100755 (executable)
@@ -40,25 +40,6 @@ test_expect_success 'non-interactive rebase --continue works with touched file'
        git rebase --continue
 '
 
-test_expect_success 'non-interactive rebase --continue with rerere enabled' '
-       test_config rerere.enabled true &&
-       test_when_finished "test_might_fail git rebase --abort" &&
-       git reset --hard commit-new-file-F2-on-topic-branch &&
-       git checkout master &&
-       rm -fr .git/rebase-* &&
-
-       test_must_fail git rebase --onto master master topic &&
-       echo "Resolved" >F2 &&
-       git add F2 &&
-       cp F2 F2.expected &&
-       git rebase --continue &&
-
-       git reset --hard commit-new-file-F2-on-topic-branch &&
-       git checkout master &&
-       test_must_fail git rebase --onto master master topic &&
-       test_cmp F2.expected F2
-'
-
 test_expect_success 'rebase --continue can not be used with other options' '
        test_must_fail git rebase -v --continue &&
        test_must_fail git rebase --continue -v
@@ -93,25 +74,75 @@ test_expect_success 'rebase --continue remembers merge strategy and options' '
        test -f funny.was.run
 '
 
-test_expect_success 'rebase --continue remembers --rerere-autoupdate' '
+test_expect_success 'setup rerere database' '
        rm -fr .git/rebase-* &&
        git reset --hard commit-new-file-F3-on-topic-branch &&
        git checkout master &&
        test_commit "commit-new-file-F3" F3 3 &&
-       git config rerere.enabled true &&
+       test_config rerere.enabled true &&
        test_must_fail git rebase -m master topic &&
        echo "Resolved" >F2 &&
+       cp F2 expected-F2 &&
        git add F2 &&
        test_must_fail git rebase --continue &&
        echo "Resolved" >F3 &&
+       cp F3 expected-F3 &&
        git add F3 &&
        git rebase --continue &&
-       git reset --hard topic@{1} &&
-       test_must_fail git rebase -m --rerere-autoupdate master &&
-       test "$(cat F2)" = "Resolved" &&
-       test_must_fail git rebase --continue &&
-       test "$(cat F3)" = "Resolved" &&
-       git rebase --continue
+       git reset --hard topic@{1}
 '
 
+prepare () {
+       rm -fr .git/rebase-* &&
+       git reset --hard commit-new-file-F3-on-topic-branch &&
+       git checkout master &&
+       test_config rerere.enabled true
+}
+
+test_rerere_autoupdate () {
+       action=$1 &&
+       test_expect_success "rebase $action --continue remembers --rerere-autoupdate" '
+               prepare &&
+               test_must_fail git rebase $action --rerere-autoupdate master topic &&
+               test_cmp expected-F2 F2 &&
+               git diff-files --quiet &&
+               test_must_fail git rebase --continue &&
+               test_cmp expected-F3 F3 &&
+               git diff-files --quiet &&
+               git rebase --continue
+       '
+
+       test_expect_success "rebase $action --continue honors rerere.autoUpdate" '
+               prepare &&
+               test_config rerere.autoupdate true &&
+               test_must_fail git rebase $action master topic &&
+               test_cmp expected-F2 F2 &&
+               git diff-files --quiet &&
+               test_must_fail git rebase --continue &&
+               test_cmp expected-F3 F3 &&
+               git diff-files --quiet &&
+               git rebase --continue
+       '
+
+       test_expect_success "rebase $action --continue remembers --no-rerere-autoupdate" '
+               prepare &&
+               test_config rerere.autoupdate true &&
+               test_must_fail git rebase $action --no-rerere-autoupdate master topic &&
+               test_cmp expected-F2 F2 &&
+               test_must_fail git diff-files --quiet &&
+               git add F2 &&
+               test_must_fail git rebase --continue &&
+               test_cmp expected-F3 F3 &&
+               test_must_fail git diff-files --quiet &&
+               git add F3 &&
+               git rebase --continue
+       '
+}
+
+test_rerere_autoupdate
+test_rerere_autoupdate -m
+GIT_SEQUENCE_EDITOR=: && export GIT_SEQUENCE_EDITOR
+test_rerere_autoupdate -i
+test_rerere_autoupdate --preserve-merges
+
 test_done
index e6a64816efef0e53018c7a56784d1af62602e9d3..a267b2d144df4a84f18ba4907b317e757ba98f16 100755 (executable)
@@ -5,14 +5,13 @@ test_description='cherry-pick should rerere for conflicts'
 . ./test-lib.sh
 
 test_expect_success setup '
-       echo foo >foo &&
-       git add foo && test_tick && git commit -q -m 1 &&
-       echo foo-master >foo &&
-       git add foo && test_tick && git commit -q -m 2 &&
-
-       git checkout -b dev HEAD^ &&
-       echo foo-dev >foo &&
-       git add foo && test_tick && git commit -q -m 3 &&
+       test_commit foo &&
+       test_commit foo-master foo &&
+       test_commit bar-master bar &&
+
+       git checkout -b dev foo &&
+       test_commit foo-dev foo &&
+       test_commit bar-dev bar &&
        git config rerere.enabled true
 '
 
@@ -21,23 +20,80 @@ test_expect_success 'conflicting merge' '
 '
 
 test_expect_success 'fixup' '
-       echo foo-dev >foo &&
-       git add foo && test_tick && git commit -q -m 4 &&
-       git reset --hard HEAD^ &&
-       echo foo-dev >expect
+       echo foo-resolved >foo &&
+       echo bar-resolved >bar &&
+       git commit -am resolved &&
+       cp foo foo-expect &&
+       cp bar bar-expect &&
+       git reset --hard HEAD^
 '
 
-test_expect_success 'cherry-pick conflict' '
-       test_must_fail git cherry-pick master &&
-       test_cmp expect foo
+test_expect_success 'cherry-pick conflict with --rerere-autoupdate' '
+       test_must_fail git cherry-pick --rerere-autoupdate foo..bar-master &&
+       test_cmp foo-expect foo &&
+       git diff-files --quiet &&
+       test_must_fail git cherry-pick --continue &&
+       test_cmp bar-expect bar &&
+       git diff-files --quiet &&
+       git cherry-pick --continue &&
+       git reset --hard bar-dev
+'
+
+test_expect_success 'cherry-pick conflict repsects rerere.autoUpdate' '
+       test_config rerere.autoUpdate true &&
+       test_must_fail git cherry-pick foo..bar-master &&
+       test_cmp foo-expect foo &&
+       git diff-files --quiet &&
+       test_must_fail git cherry-pick --continue &&
+       test_cmp bar-expect bar &&
+       git diff-files --quiet &&
+       git cherry-pick --continue &&
+       git reset --hard bar-dev
+'
+
+test_expect_success 'cherry-pick conflict with --no-rerere-autoupdate' '
+       test_config rerere.autoUpdate true &&
+       test_must_fail git cherry-pick --no-rerere-autoupdate foo..bar-master &&
+       test_cmp foo-expect foo &&
+       test_must_fail git diff-files --quiet &&
+       git add foo &&
+       test_must_fail git cherry-pick --continue &&
+       test_cmp bar-expect bar &&
+       test_must_fail git diff-files --quiet &&
+       git add bar &&
+       git cherry-pick --continue &&
+       git reset --hard bar-dev
+'
+
+test_expect_success 'cherry-pick --continue rejects --rerere-autoupdate' '
+       test_must_fail git cherry-pick --rerere-autoupdate foo..bar-master &&
+       test_cmp foo-expect foo &&
+       git diff-files --quiet &&
+       test_must_fail git cherry-pick --continue --rerere-autoupdate >actual 2>&1 &&
+       echo "fatal: cherry-pick: --rerere-autoupdate cannot be used with --continue" >expect &&
+       test_i18ncmp expect actual &&
+       test_must_fail git cherry-pick --continue --no-rerere-autoupdate >actual 2>&1 &&
+       echo "fatal: cherry-pick: --no-rerere-autoupdate cannot be used with --continue" >expect &&
+       test_i18ncmp expect actual &&
+       git cherry-pick --abort
 '
 
-test_expect_success 'reconfigure' '
-       git config rerere.enabled false &&
-       git reset --hard
+test_expect_success 'cherry-pick --rerere-autoupdate more than once' '
+       test_must_fail git cherry-pick --rerere-autoupdate --rerere-autoupdate foo..bar-master &&
+       test_cmp foo-expect foo &&
+       git diff-files --quiet &&
+       git cherry-pick --abort &&
+       test_must_fail git cherry-pick --rerere-autoupdate --no-rerere-autoupdate --rerere-autoupdate foo..bar-master &&
+       test_cmp foo-expect foo &&
+       git diff-files --quiet &&
+       git cherry-pick --abort &&
+       test_must_fail git cherry-pick --rerere-autoupdate --no-rerere-autoupdate foo..bar-master &&
+       test_must_fail git diff-files --quiet &&
+       git cherry-pick --abort
 '
 
 test_expect_success 'cherry-pick conflict without rerere' '
+       test_config rerere.enabled false &&
        test_must_fail git cherry-pick master &&
        test_must_fail test_cmp expect foo
 '
index f3a4b4a913f344ce140344ec7b70482a6d36bcbe..0aae21d6984bf0bd5c7c7de425a021da6122beee 100755 (executable)
@@ -356,6 +356,7 @@ test_expect_success POSIXPERM,SYMLINKS 'git add --chmod=+x with symlinks' '
 
 test_expect_success 'git add --chmod=[+-]x changes index with already added file' '
        rm -f foo3 xfoo3 &&
+       git reset --hard &&
        echo foo >foo3 &&
        git add foo3 &&
        git add --chmod=+x foo3 &&
index 193adc7b68d691526b804fa7ce02e1f42f21b8a4..bfde4057ad2afcdd3bd38cbb43ffa2ce241aaa67 100755 (executable)
@@ -211,4 +211,21 @@ test_expect_success 'stash push with $IFS character' '
        test_path_is_file bar
 '
 
+cat > .gitignore <<EOF
+ignored
+ignored.d/*
+EOF
+
+test_expect_success 'stash previously ignored file' '
+       git reset HEAD &&
+       git add .gitignore &&
+       git commit -m "Add .gitignore" &&
+       >ignored.d/foo &&
+       echo "!ignored.d/foo" >> .gitignore &&
+       git stash save --include-untracked &&
+       test_path_is_missing ignored.d/foo &&
+       git stash pop &&
+       test_path_is_file ignored.d/foo
+'
+
 test_done
index 7c4903f49713a22d7fba28a608acf07f1330110b..1130c8019b4c14975744f31f360886ffb4c3f14c 100755 (executable)
@@ -14,8 +14,10 @@ test_expect_success setup '
        test_tick &&
        git commit -m "A 4k file"
 '
+
+# OpenBSD only supports up to 255 repetitions, so repeat twice for 64*64=4096.
 test_expect_success '-G matches' '
-       git diff --name-only -G "^0{4096}$" HEAD^ >out &&
+       git diff --name-only -G "^(0{64}){64}$" HEAD^ >out &&
        test 4096-zeroes.txt = "$(cat out)"
 '
 
index 44807e218d7016f58bd41b89af71104a37f31a8b..73b67b4280b99e0328e201e6b69c3d88b766ea84 100755 (executable)
@@ -40,6 +40,8 @@ test_expect_success 'setup: messages' '
        dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio
        dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te
        feugait nulla facilisi.
+
+       Reported-by: A N Other <a.n.other@example.com>
        EOF
 
        cat >failmail <<-\EOF &&
@@ -93,7 +95,7 @@ test_expect_success setup '
        echo world >>file &&
        git add file &&
        test_tick &&
-       git commit -s -F msg &&
+       git commit -F msg &&
        git tag second &&
 
        git format-patch --stdout first >patch1 &&
@@ -124,8 +126,6 @@ test_expect_success setup '
                echo "Date: $GIT_AUTHOR_DATE" &&
                echo &&
                sed -e "1,2d" msg &&
-               echo &&
-               echo "Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" &&
                echo "---" &&
                git diff-tree --no-commit-id --stat -p second
        } >patch1-stgit.eml &&
@@ -144,8 +144,6 @@ test_expect_success setup '
                echo "# Parent  $_z40" &&
                cat msg &&
                echo &&
-               echo "Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" &&
-               echo &&
                git diff-tree --no-commit-id -p second
        } >patch1-hg.eml &&
 
@@ -470,13 +468,15 @@ test_expect_success 'am --signoff adds Signed-off-by: line' '
        git reset --hard &&
        git checkout -b master2 first &&
        git am --signoff <patch2 &&
-       printf "%s\n" "$signoff" >expected &&
-       echo "Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" >>expected &&
-       git cat-file commit HEAD^ | grep "Signed-off-by:" >actual &&
-       test_cmp expected actual &&
-       echo "Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" >expected &&
-       git cat-file commit HEAD | grep "Signed-off-by:" >actual &&
-       test_cmp expected actual
+       {
+               printf "third\n\nSigned-off-by: %s <%s>\n\n" \
+                       "$GIT_COMMITTER_NAME" "$GIT_COMMITTER_EMAIL" &&
+               cat msg &&
+               printf "Signed-off-by: %s <%s>\n\n" \
+                       "$GIT_COMMITTER_NAME" "$GIT_COMMITTER_EMAIL"
+       } >expected-log &&
+       git log --pretty=%B -2 HEAD >actual &&
+       test_cmp expected-log actual
 '
 
 test_expect_success 'am stays in branch' '
@@ -486,17 +486,60 @@ test_expect_success 'am stays in branch' '
 '
 
 test_expect_success 'am --signoff does not add Signed-off-by: line if already there' '
-       git format-patch --stdout HEAD^ >patch3 &&
-       sed -e "/^Subject/ s,\[PATCH,Re: Re: Re: & 1/5 v2] [foo," patch3 >patch4 &&
-       rm -fr .git/rebase-apply &&
-       git reset --hard &&
-       git checkout HEAD^ &&
-       git am --signoff patch4 &&
-       git cat-file commit HEAD >actual &&
-       test $(grep -c "^Signed-off-by:" actual) -eq 1
+       git format-patch --stdout first >patch3 &&
+       git reset --hard first &&
+       git am --signoff <patch3 &&
+       git log --pretty=%B -2 HEAD >actual &&
+       test_cmp expected-log actual
+'
+
+test_expect_success 'am --signoff adds Signed-off-by: if another author is preset' '
+       NAME="A N Other" &&
+       EMAIL="a.n.other@example.com" &&
+       {
+               printf "third\n\nSigned-off-by: %s <%s>\nSigned-off-by: %s <%s>\n\n" \
+                       "$GIT_COMMITTER_NAME" "$GIT_COMMITTER_EMAIL" \
+                       "$NAME" "$EMAIL" &&
+               cat msg &&
+               printf "Signed-off-by: %s <%s>\nSigned-off-by: %s <%s>\n\n" \
+                       "$GIT_COMMITTER_NAME" "$GIT_COMMITTER_EMAIL" \
+                       "$NAME" "$EMAIL"
+       } >expected-log &&
+       git reset --hard first &&
+       GIT_COMMITTER_NAME="$NAME" GIT_COMMITTER_EMAIL="$EMAIL" \
+               git am --signoff <patch3 &&
+       git log --pretty=%B -2 HEAD >actual &&
+       test_cmp expected-log actual
+'
+
+test_expect_success 'am --signoff duplicates Signed-off-by: if it is not the last one' '
+       NAME="A N Other" &&
+       EMAIL="a.n.other@example.com" &&
+       {
+               printf "third\n\nSigned-off-by: %s <%s>\n\
+Signed-off-by: %s <%s>\nSigned-off-by: %s <%s>\n\n" \
+                       "$GIT_COMMITTER_NAME" "$GIT_COMMITTER_EMAIL" \
+                       "$NAME" "$EMAIL" \
+                       "$GIT_COMMITTER_NAME" "$GIT_COMMITTER_EMAIL" &&
+               cat msg &&
+               printf "Signed-off-by: %s <%s>\nSigned-off-by: %s <%s>\n\
+Signed-off-by: %s <%s>\n\n" \
+                       "$GIT_COMMITTER_NAME" "$GIT_COMMITTER_EMAIL" \
+                       "$NAME" "$EMAIL" \
+                       "$GIT_COMMITTER_NAME" "$GIT_COMMITTER_EMAIL"
+       } >expected-log &&
+       git format-patch --stdout first >patch3 &&
+       git reset --hard first &&
+       git am --signoff <patch3 &&
+       git log --pretty=%B -2 HEAD >actual &&
+       test_cmp expected-log actual
 '
 
 test_expect_success 'am without --keep removes Re: and [PATCH] stuff' '
+       git format-patch --stdout HEAD^ >tmp &&
+       sed -e "/^Subject/ s,\[PATCH,Re: Re: Re: & 1/5 v2] [foo," tmp >patch4 &&
+       git reset --hard HEAD^ &&
+       git am <patch4 &&
        git rev-parse HEAD >expected &&
        git rev-parse master2 >actual &&
        test_cmp expected actual
index 3f3531f0a49be39e29b20a36a55f0d27f04b4fc8..36d120c969f6c116c2bed19c8bb0c027919d66a9 100755 (executable)
@@ -1523,6 +1523,12 @@ test_expect_success 'log diagnoses bogus HEAD' '
        test_i18ngrep broken stderr
 '
 
+test_expect_success 'log does not default to HEAD when rev input is given' '
+       >expect &&
+       git log --branches=does-not-exist >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'set up --source tests' '
        git checkout --orphan source-a &&
        test_commit one &&
index 9c5a8766ab0af40382b83cf3340b13a32f7f0c8e..156ae9e9d335029e63430a6cc7d0ec2fd0d68dd3 100755 (executable)
@@ -56,20 +56,11 @@ test_expect_success 'create batch-check test vectors' '
        EOF
 '
 
-test_expect_success 'lookup in duplicated pack (binary search)' '
+test_expect_success 'lookup in duplicated pack' '
        git cat-file --batch-check <input >actual &&
        test_cmp expect actual
 '
 
-test_expect_success 'lookup in duplicated pack (GIT_USE_LOOKUP)' '
-       (
-               GIT_USE_LOOKUP=1 &&
-               export GIT_USE_LOOKUP &&
-               git cat-file --batch-check <input >actual
-       ) &&
-       test_cmp expect actual
-'
-
 test_expect_success 'index-pack can reject packs with duplicates' '
        clear_packs &&
        create_pack dups.pack 2 &&
index f15f7a332960f15c7af32a3c1e7a66f5a8a68989..59c4b778d3a455b6ef4575a4b07b860d1e84720d 100755 (executable)
@@ -305,7 +305,7 @@ test_expect_success '--rebase with conflicts shows advice' '
        test_tick &&
        git commit -m "Create conflict" seq.txt &&
        test_must_fail git pull --rebase . seq 2>err >out &&
-       test_i18ngrep "When you have resolved this problem" out
+       test_i18ngrep "Resolve all conflicts manually" out
 '
 
 test_expect_success 'failed --rebase shows advice' '
@@ -319,7 +319,7 @@ test_expect_success 'failed --rebase shows advice' '
        git checkout -f -b fails-to-rebase HEAD^ &&
        test_commit v2-without-cr file "2" file2-lf &&
        test_must_fail git pull --rebase . diverging 2>err >out &&
-       test_i18ngrep "When you have resolved this problem" out
+       test_i18ngrep "Resolve all conflicts manually" out
 '
 
 test_expect_success '--rebase fails with multiple branches' '
index 162baf101f340885619e0a1e67b0b14cf37a2347..42251f7f3af0865a31fd38722fbf7433d81fe3f0 100755 (executable)
@@ -193,7 +193,7 @@ test_expect_success "recurseSubmodules=true propagates into submodules" '
        add_upstream_commit &&
        (
                cd downstream &&
-               git config fetch.recurseSubmodules true
+               git config fetch.recurseSubmodules true &&
                git fetch >../actual.out 2>../actual.err
        ) &&
        test_must_be_empty actual.out &&
@@ -218,7 +218,7 @@ test_expect_success "--no-recurse-submodules overrides config setting" '
        add_upstream_commit &&
        (
                cd downstream &&
-               git config fetch.recurseSubmodules true
+               git config fetch.recurseSubmodules true &&
                git fetch --no-recurse-submodules >../actual.out 2>../actual.err
        ) &&
        ! test -s actual.out &&
@@ -232,7 +232,7 @@ test_expect_success "Recursion doesn't happen when no new commits are fetched in
                        cd submodule &&
                        git config --unset fetch.recurseSubmodules
                ) &&
-               git config --unset fetch.recurseSubmodules
+               git config --unset fetch.recurseSubmodules &&
                git fetch >../actual.out 2>../actual.err
        ) &&
        ! test -s actual.out &&
@@ -312,7 +312,7 @@ test_expect_success "Recursion picks up all submodules when necessary" '
                ) &&
                head1=$(git rev-parse --short HEAD^) &&
                git add subdir/deepsubmodule &&
-               git commit -m "new deepsubmodule"
+               git commit -m "new deepsubmodule" &&
                head2=$(git rev-parse --short HEAD) &&
                echo "Fetching submodule submodule" > ../expect.err.sub &&
                echo "From $pwd/submodule" >> ../expect.err.sub &&
index beff65b8ace505d78c3997a737711ee7fc6383b5..0f84a53146f3bac1bded4d2b11212b8ddef1bf2c 100755 (executable)
@@ -533,7 +533,8 @@ test_expect_success 'push propagating refspec to a submodule' '
        # Fails when refspec includes an object id
        test_must_fail git -C work push --recurse-submodules=on-demand origin \
                "$(git -C work rev-parse branch2):refs/heads/branch2" &&
-       # Fails when refspec includes 'HEAD' as it is unsupported at this time
+       # Fails when refspec includes HEAD and parent and submodule do not
+       # have the same named branch checked out
        test_must_fail git -C work push --recurse-submodules=on-demand origin \
                HEAD:refs/heads/branch2 &&
 
@@ -548,4 +549,26 @@ test_expect_success 'push propagating refspec to a submodule' '
        test_cmp expected_pub actual_pub
 '
 
+test_expect_success 'push propagating HEAD refspec to a submodule' '
+       git -C work/gar/bage checkout branch2 &&
+       > work/gar/bage/junk12 &&
+       git -C work/gar/bage add junk12 &&
+       git -C work/gar/bage commit -m "Twelfth junk" &&
+
+       git -C work checkout branch2 &&
+       git -C work add gar/bage &&
+       git -C work commit -m "updating gar/bage in branch2" &&
+
+       # Passes since the superproject and submodules HEAD are both on branch2
+       git -C work push --recurse-submodules=on-demand origin \
+               HEAD:refs/heads/branch2 &&
+
+       git -C submodule.git rev-parse branch2 >actual_submodule &&
+       git -C pub.git rev-parse branch2 >actual_pub &&
+       git -C work/gar/bage rev-parse branch2 >expected_submodule &&
+       git -C work rev-parse branch2 >expected_pub &&
+       test_cmp expected_submodule actual_submodule &&
+       test_cmp expected_pub actual_pub
+'
+
 test_done
index 464ffdd147abbae354ae3adfe593b89a37d5c726..1cea758f789edef35a61ce1a9bc11d9fda7bd7ac 100755 (executable)
@@ -71,6 +71,13 @@ test_expect_success 'push --signed fails with a receiver without push certificat
        test_i18ngrep "the receiving end does not support" err
 '
 
+test_expect_success 'push --signed=1 is accepted' '
+       prepare_dst &&
+       mkdir -p dst/.git/hooks &&
+       test_must_fail git push --signed=1 dst noop ff +noff 2>err &&
+       test_i18ngrep "the receiving end does not support" err
+'
+
 test_expect_success GPG 'no certificate for a signed push with no update' '
        prepare_dst &&
        mkdir -p dst/.git/hooks &&
index 381f35ed16d152e7926774587c1c0a006a600ee6..d3453c583c1921a10409c16b5e2cf949edde6cd2 100755 (executable)
@@ -255,27 +255,19 @@ test_expect_success 'rev-list accumulates multiple --exclude' '
        compare rev-list "--exclude=refs/remotes/* --exclude=refs/tags/* --all" --branches
 '
 
-
-# "git rev-list<ENTER>" is likely to be a bug in the calling script and may
-# deserve an error message, but do cases where set of refs programmatically
-# given using globbing and/or --stdin need to fail with the same error, or
-# are we better off reporting a success with no output?  The following few
-# tests document the current behaviour to remind us that we might want to
-# think about this issue.
-
-test_expect_failure 'rev-list may want to succeed with empty output on no input (1)' '
+test_expect_failure 'rev-list should succeed with empty output on empty stdin' '
        >expect &&
        git rev-list --stdin <expect >actual &&
        test_cmp expect actual
 '
 
-test_expect_failure 'rev-list may want to succeed with empty output on no input (2)' '
+test_expect_success 'rev-list should succeed with empty output with all refs excluded' '
        >expect &&
        git rev-list --exclude=* --all >actual &&
        test_cmp expect actual
 '
 
-test_expect_failure 'rev-list may want to succeed with empty output on no input (3)' '
+test_expect_success 'rev-list should succeed with empty output with empty --all' '
        (
                test_create_repo empty &&
                cd empty &&
@@ -285,6 +277,12 @@ test_expect_failure 'rev-list may want to succeed with empty output on no input
        )
 '
 
+test_expect_success 'rev-list should succeed with empty output with empty glob' '
+       >expect &&
+       git rev-list --glob=does-not-match-anything >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'shortlog accepts --glob/--tags/--remotes' '
 
        compare shortlog "subspace/one subspace/two" --branches=subspace &&
index dd5ba450ee4b33801dc39d0b57e4c4b08c1dfd62..dbcd6f623c7e233b487d4d0c1dd7d71cb34059b0 100755 (executable)
@@ -1888,7 +1888,7 @@ EOF"
        run_with_limited_stack git tag --contains HEAD >actual &&
        test_cmp expect actual &&
        run_with_limited_stack git tag --no-contains HEAD >actual &&
-       test_line_count ">" 10 actual
+       test_line_count "-gt" 10 actual
 '
 
 test_expect_success '--format should list tags as per format given' '
index 20b4d83c281e2fde8812f309bdebef012c6ecb74..9128ec5acda3b4b2f568dee50169046a333c4527 100755 (executable)
@@ -134,6 +134,86 @@ test_expect_success TTY 'configuration can enable pager (from subdir)' '
        }
 '
 
+test_expect_success TTY 'git tag -l defaults to paging' '
+       rm -f paginated.out &&
+       test_terminal git tag -l &&
+       test -e paginated.out
+'
+
+test_expect_success TTY 'git tag -l respects pager.tag' '
+       rm -f paginated.out &&
+       test_terminal git -c pager.tag=false tag -l &&
+       ! test -e paginated.out
+'
+
+test_expect_success TTY 'git tag -l respects --no-pager' '
+       rm -f paginated.out &&
+       test_terminal git -c pager.tag --no-pager tag -l &&
+       ! test -e paginated.out
+'
+
+test_expect_success TTY 'git tag with no args defaults to paging' '
+       # no args implies -l so this should page like -l
+       rm -f paginated.out &&
+       test_terminal git tag &&
+       test -e paginated.out
+'
+
+test_expect_success TTY 'git tag with no args respects pager.tag' '
+       # no args implies -l so this should page like -l
+       rm -f paginated.out &&
+       test_terminal git -c pager.tag=false tag &&
+       ! test -e paginated.out
+'
+
+test_expect_success TTY 'git tag --contains defaults to paging' '
+       # --contains implies -l so this should page like -l
+       rm -f paginated.out &&
+       test_terminal git tag --contains &&
+       test -e paginated.out
+'
+
+test_expect_success TTY 'git tag --contains respects pager.tag' '
+       # --contains implies -l so this should page like -l
+       rm -f paginated.out &&
+       test_terminal git -c pager.tag=false tag --contains &&
+       ! test -e paginated.out
+'
+
+test_expect_success TTY 'git tag -a defaults to not paging' '
+       test_when_finished "git tag -d newtag" &&
+       rm -f paginated.out &&
+       test_terminal git tag -am message newtag &&
+       ! test -e paginated.out
+'
+
+test_expect_success TTY 'git tag -a ignores pager.tag' '
+       test_when_finished "git tag -d newtag" &&
+       rm -f paginated.out &&
+       test_terminal git -c pager.tag tag -am message newtag &&
+       ! test -e paginated.out
+'
+
+test_expect_success TTY 'git tag -a respects --paginate' '
+       test_when_finished "git tag -d newtag" &&
+       rm -f paginated.out &&
+       test_terminal git --paginate tag -am message newtag &&
+       test -e paginated.out
+'
+
+test_expect_success TTY 'git tag as alias ignores pager.tag with -a' '
+       test_when_finished "git tag -d newtag" &&
+       rm -f paginated.out &&
+       test_terminal git -c pager.tag -c alias.t=tag t -am message newtag &&
+       ! test -e paginated.out
+'
+
+test_expect_success TTY 'git tag as alias respects pager.tag with -l' '
+       rm -f paginated.out &&
+       test_terminal git -c pager.tag=false -c alias.t=tag t -l &&
+       ! test -e paginated.out
+'
+
 # A colored commit log will begin with an appropriate ANSI escape
 # for the first color; the text "commit" comes later.
 colorful() {
index 3ae394e934d972d29286ecd25596eedd45bee902..556e1850e2b20c3f484ee43a975e5dcca8eac99e 100755 (executable)
@@ -472,4 +472,14 @@ test_expect_success 'git clean -id with prefix and path (ask)' '
 
 '
 
+test_expect_success 'git clean -i paints the header in HEADER color' '
+       >a.out &&
+       echo q |
+       git -c color.ui=always clean -i |
+       test_decode_color |
+       head -n 1 >header &&
+       # not i18ngrep
+       grep "^<BOLD>" header
+'
+
 test_done
index dcac364c5fa2a8ff7fe264a21fb9682ec934a874..e9c3335b78bb6f78c640cf496f7b055462c1e275 100755 (executable)
@@ -1289,4 +1289,10 @@ test_expect_success 'init properly sets the config' '
        test_must_fail git -C multisuper_clone config --get submodule.sub1.active
 '
 
+test_expect_success 'recursive clone respects -q' '
+       test_when_finished "rm -rf multisuper_clone" &&
+       git clone -q --recurse-submodules multisuper multisuper_clone >actual &&
+       test_must_be_empty actual
+'
+
 test_done
index f1063878205cfb9b0af8e54d997040ddb65bc27e..2a6679c2f596fb13a34786a4aa4b954e61c61113 100755 (executable)
@@ -374,6 +374,11 @@ test_expect_success 'grep -L -C' '
        test_cmp expected actual
 '
 
+test_expect_success 'grep --files-without-match --quiet' '
+       git grep --files-without-match --quiet nonexistent_string >actual &&
+       test_cmp /dev/null actual
+'
+
 cat >expected <<EOF
 file:foo mmap bar_mmap
 EOF
index 1b6e53f78aef40673354e5f1911d78808ae8ef4d..5fbd8d4a90b3b88cf57ca53c6b1fe99d5a957460 100644 (file)
@@ -99,7 +99,6 @@ unset VISUAL EMAIL LANGUAGE COLUMNS $("$PERL_PATH" -e '
        my $ok = join("|", qw(
                TRACE
                DEBUG
-               USE_LOOKUP
                TEST
                .*_TEST
                PROVE
@@ -991,9 +990,6 @@ case $uname_s in
        find () {
                /usr/bin/find "$@"
        }
-       sum () {
-               md5sum "$@"
-       }
        # git sees Windows-style pwd
        pwd () {
                builtin pwd -W
diff --git a/tag.c b/tag.c
index 47f60ae151c2cfd9855d1b6f1660ec2ba178bec3..7e10acfb6ef1673e783e0a42e1b8810a6e2eff06 100644 (file)
--- a/tag.c
+++ b/tag.c
@@ -33,7 +33,7 @@ static int run_gpg_verify(const char *buf, unsigned long size, unsigned flags)
        return ret;
 }
 
-int gpg_verify_tag(const unsigned char *sha1, const char *name_to_report,
+int gpg_verify_tag(const struct object_id *oid, const char *name_to_report,
                unsigned flags)
 {
        enum object_type type;
@@ -41,20 +41,20 @@ int gpg_verify_tag(const unsigned char *sha1, const char *name_to_report,
        unsigned long size;
        int ret;
 
-       type = sha1_object_info(sha1, NULL);
+       type = sha1_object_info(oid->hash, NULL);
        if (type != OBJ_TAG)
                return error("%s: cannot verify a non-tag object of type %s.",
                                name_to_report ?
                                name_to_report :
-                               find_unique_abbrev(sha1, DEFAULT_ABBREV),
+                               find_unique_abbrev(oid->hash, DEFAULT_ABBREV),
                                typename(type));
 
-       buf = read_sha1_file(sha1, &type, &size);
+       buf = read_sha1_file(oid->hash, &type, &size);
        if (!buf)
                return error("%s: unable to read file.",
                                name_to_report ?
                                name_to_report :
-                               find_unique_abbrev(sha1, DEFAULT_ABBREV));
+                               find_unique_abbrev(oid->hash, DEFAULT_ABBREV));
 
        ret = run_gpg_verify(buf, size, flags);
 
diff --git a/tag.h b/tag.h
index fdfcb4a84aa16b8173f8f308f7faecf8e9f000c7..d469534e82a87b651abe752469d0547c2b560e10 100644 (file)
--- a/tag.h
+++ b/tag.h
@@ -17,7 +17,7 @@ extern int parse_tag_buffer(struct tag *item, const void *data, unsigned long si
 extern int parse_tag(struct tag *item);
 extern struct object *deref_tag(struct object *, const char *, int);
 extern struct object *deref_tag_noverify(struct object *);
-extern int gpg_verify_tag(const unsigned char *sha1,
+extern int gpg_verify_tag(const struct object_id *oid,
                const char *name_to_report, unsigned flags);
 
 #endif /* TAG_H */
index 86b8f227ecab874a4af98bc5ba3164d370e5e4b5..318afe3fd865013e668fcd8a2213bc5567b46579 100755 (executable)
@@ -9,8 +9,8 @@
 #
 # To enable this hook, rename this file to "prepare-commit-msg".
 
-# This hook includes three examples.  The first comments out the
-# "Conflicts:" part of a merge commit.
+# This hook includes three examples. The first one removes the
+# "# Please enter the commit message..." help message.
 #
 # The second includes the output of "git diff --name-status -r"
 # into the message, just before the "git status" output.  It is
 # The third example adds a Signed-off-by line to the message, that can
 # still be edited.  This is rarely a good idea.
 
-case "$2,$3" in
-  merge,)
-    @PERL_PATH@ -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;;
+COMMIT_MSG_FILE=$1
+COMMIT_SOURCE=$2
+SHA1=$3
 
-# ,|template,)
-#   @PERL_PATH@ -i.bak -pe '
-#      print "\n" . `git diff --cached --name-status -r`
-#       if /^#/ && $first++ == 0' "$1" ;;
+@PERL_PATH@ -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE"
 
-  *) ;;
-esac
+# case "$COMMIT_SOURCE,$SHA1" in
+#  ,|template,)
+#    @PERL_PATH@ -i.bak -pe '
+#       print "\n" . `git diff --cached --name-status -r`
+#       if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;;
+#  *) ;;
+# esac
 
-# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
-# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
+# SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
+# git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE"
+# if test -z "$COMMIT_SOURCE"
+# then
+#   @PERL_PATH@ -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE"
+# fi
index 33cff38cc0b9b4a2d05b26544c9edda9caa33e9a..8f68d69a86bd919162b62514af0b1d1d55e204a1 100644 (file)
@@ -927,7 +927,7 @@ static int push_refs_with_export(struct transport *transport,
                struct object_id oid;
 
                private = apply_refspecs(data->refspecs, data->refspec_nr, ref->name);
-               if (private && !get_sha1(private, oid.hash)) {
+               if (private && !get_oid(private, &oid)) {
                        strbuf_addf(&buf, "^%s", private);
                        string_list_append(&revlist_args, strbuf_detach(&buf, NULL));
                        oidcpy(&ref->old_oid, &oid);
index bd6d65a40920a547b9f27512e31341231273fa75..2357f72899f8f47e497ffd1bb66a0d76d7dbe012 100644 (file)
@@ -421,8 +421,9 @@ static struct combine_diff_path *ll_diff_tree_paths(
         *   diff_tree_oid(parent, commit) )
         */
        for (i = 0; i < nparent; ++i)
-               tptree[i] = fill_tree_descriptor(&tp[i], parents_oid[i]->hash);
-       ttree = fill_tree_descriptor(&t, oid->hash);
+               tptree[i] = fill_tree_descriptor(&tp[i],
+                               parents_oid[i] ? parents_oid[i]->hash : NULL);
+       ttree = fill_tree_descriptor(&t, oid ? oid->hash : NULL);
 
        /* Enable recursion indefinitely */
        opt->pathspec.recursive = DIFF_OPT_TST(opt, RECURSIVE);
index 862cfce661e57e50f7c6030dd5a8eda0add0cca5..38000ac8fad4e8cb626b74bf80197e070084246e 100644 (file)
@@ -286,7 +286,7 @@ static void reload_gitmodules_file(struct index_state *index,
        for (i = 0; i < index->cache_nr; i++) {
                struct cache_entry *ce = index->cache[i];
                if (ce->ce_flags & CE_UPDATE) {
-                       int r = strcmp(ce->name, ".gitmodules");
+                       int r = strcmp(ce->name, GITMODULES_FILE);
                        if (r < 0)
                                continue;
                        else if (r == 0) {