summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/RelNotes/2.15.0.txt220
-rw-r--r--Documentation/config.txt10
-rw-r--r--Documentation/git-branch.txt4
-rw-r--r--Documentation/git-for-each-ref.txt9
-rw-r--r--Documentation/git-format-patch.txt4
-rw-r--r--Documentation/git-grep.txt7
-rw-r--r--Documentation/git-push.txt4
-rw-r--r--Documentation/git-send-pack.txt4
-rw-r--r--Documentation/git-tag.txt7
-rw-r--r--Documentation/git.txt3
-rw-r--r--Documentation/githooks.txt4
-rw-r--r--Documentation/technical/api-builtin.txt73
-rw-r--r--Documentation/technical/api-config.txt4
-rwxr-xr-xGIT-VERSION-GEN2
-rw-r--r--Makefile1
l---------RelNotes2
-rw-r--r--apply.c16
-rw-r--r--apply.h1
-rw-r--r--archive.c2
-rw-r--r--attr.c12
-rw-r--r--bisect.c18
-rw-r--r--builtin.h100
-rw-r--r--builtin/add.c6
-rw-r--r--builtin/am.c44
-rw-r--r--builtin/cat-file.c8
-rw-r--r--builtin/clean.c19
-rw-r--r--builtin/clone.c3
-rw-r--r--builtin/commit-tree.c4
-rw-r--r--builtin/commit.c23
-rw-r--r--builtin/describe.c9
-rw-r--r--builtin/difftool.c37
-rw-r--r--builtin/fetch.c26
-rw-r--r--builtin/fsck.c30
-rw-r--r--builtin/grep.c402
-rw-r--r--builtin/log.c24
-rw-r--r--builtin/merge-tree.c6
-rw-r--r--builtin/merge.c8
-rw-r--r--builtin/mv.c2
-rw-r--r--builtin/notes.c2
-rw-r--r--builtin/pull.c4
-rw-r--r--builtin/push.c2
-rw-r--r--builtin/receive-pack.c6
-rw-r--r--builtin/remote.c2
-rw-r--r--builtin/replace.c4
-rw-r--r--builtin/reset.c10
-rw-r--r--builtin/rev-list.c3
-rw-r--r--builtin/rev-parse.c8
-rw-r--r--builtin/revert.c2
-rw-r--r--builtin/rm.c2
-rw-r--r--builtin/send-pack.c2
-rw-r--r--builtin/show-branch.c8
-rw-r--r--builtin/submodule--helper.c74
-rw-r--r--builtin/tag.c5
-rw-r--r--builtin/unpack-file.c12
-rw-r--r--builtin/update-ref.c69
-rw-r--r--builtin/verify-tag.c9
-rw-r--r--cache.h59
-rw-r--r--commit.c10
-rw-r--r--commit.h2
-rw-r--r--compat/win32/syslog.c2
-rw-r--r--config.c54
-rw-r--r--config.h14
-rwxr-xr-xcontrib/contacts/git-contacts2
-rwxr-xr-xcontrib/rerere-train.sh54
-rw-r--r--convert.c3
-rw-r--r--diff.c5
-rw-r--r--fsck.c2
-rwxr-xr-xgit-merge-octopus.sh2
-rwxr-xr-xgit-merge-one-file.sh8
-rwxr-xr-xgit-merge-resolve.sh2
-rw-r--r--git-rebase--am.sh4
-rw-r--r--git-rebase--interactive.sh7
-rwxr-xr-xgit-rebase.sh13
-rwxr-xr-xgit-stash.sh24
-rwxr-xr-xgit-submodule.sh7
-rw-r--r--git.c20
-rw-r--r--grep.c15
-rw-r--r--grep.h1
-rw-r--r--mailmap.c6
-rw-r--r--name-hash.c22
-rw-r--r--notes.c2
-rw-r--r--pager.c2
-rw-r--r--patch-ids.c14
-rw-r--r--perl/Git.pm2
-rw-r--r--perl/Git/SVN.pm2
-rw-r--r--refs.c20
-rw-r--r--refs/files-backend.c639
-rw-r--r--refs/packed-backend.c885
-rw-r--r--refs/packed-backend.h25
-rw-r--r--refs/refs-internal.h10
-rw-r--r--remote.c20
-rw-r--r--remote.h2
-rw-r--r--repository.c8
-rw-r--r--repository.h8
-rw-r--r--revision.c19
-rw-r--r--revision.h7
-rw-r--r--sequencer.c85
-rw-r--r--setup.c12
-rw-r--r--sha1-lookup.c216
-rw-r--r--sha1_file.c62
-rw-r--r--sha1_name.c240
-rw-r--r--shallow.c4
-rw-r--r--strbuf.c1
-rw-r--r--strbuf.h2
-rw-r--r--sub-process.c7
-rw-r--r--sub-process.h4
-rw-r--r--submodule-config.c70
-rw-r--r--submodule-config.h13
-rw-r--r--submodule.c207
-rw-r--r--submodule.h8
-rw-r--r--t/helper/test-hashmap.c34
-rw-r--r--t/helper/test-path-utils.c18
-rw-r--r--t/helper/test-submodule-config.c10
-rwxr-xr-xt/lib-gpg.sh1
-rwxr-xr-xt/t0001-init.sh30
-rwxr-xr-xt/t1002-read-tree-m-u-2way.sh67
-rwxr-xr-xt/t1200-tutorial.sh268
-rwxr-xr-xt/t1408-packed-refs.sh42
-rwxr-xr-xt/t3210-pack-refs.sh42
-rwxr-xr-xt/t3418-rebase-continue.sh85
-rwxr-xr-xt/t3504-cherry-pick-rerere.sh92
-rwxr-xr-xt/t3700-add.sh1
-rwxr-xr-xt/t3905-stash-include-untracked.sh17
-rwxr-xr-xt/t4062-diff-pickaxe.sh4
-rwxr-xr-xt/t4150-am.sh83
-rwxr-xr-xt/t4202-log.sh6
-rwxr-xr-xt/t5308-pack-detect-duplicates.sh11
-rwxr-xr-xt/t5520-pull.sh4
-rwxr-xr-xt/t5526-fetch-submodules.sh8
-rwxr-xr-xt/t5531-deep-submodule-push.sh25
-rwxr-xr-xt/t5534-push-signed.sh7
-rwxr-xr-xt/t6018-rev-list-glob.sh20
-rwxr-xr-xt/t7004-tag.sh2
-rwxr-xr-xt/t7006-pager.sh80
-rwxr-xr-xt/t7301-clean-interactive.sh10
-rwxr-xr-xt/t7400-submodule-basic.sh6
-rwxr-xr-xt/t7810-grep.sh5
-rw-r--r--t/test-lib.sh4
-rw-r--r--tag.c10
-rw-r--r--tag.h2
-rwxr-xr-xtemplates/hooks--prepare-commit-msg.sample32
-rw-r--r--transport-helper.c2
-rw-r--r--tree-diff.c5
-rw-r--r--unpack-trees.c2
144 files changed, 2961 insertions, 2390 deletions
diff --git a/Documentation/RelNotes/2.15.0.txt b/Documentation/RelNotes/2.15.0.txt
new file mode 100644
index 0000000000..2fd49978d7
--- /dev/null
+++ b/Documentation/RelNotes/2.15.0.txt
@@ -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).
diff --git a/Documentation/config.txt b/Documentation/config.txt
index d5c9c4cab6..478b9431e0 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -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::
diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index 81bd0a7b77..d0b3358771 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -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
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index cc42c12832..bb370c9c7b 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -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
diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt
index c890328b02..6cbe462a77 100644
--- a/Documentation/git-format-patch.txt
+++ b/Documentation/git-format-patch.txt
@@ -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,
diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt
index 5033483db4..720c7850e2 100644
--- a/Documentation/git-grep.txt
+++ b/Documentation/git-grep.txt
@@ -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.
diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
index 0a639664fd..3e76e99f38 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.txt
@@ -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
diff --git a/Documentation/git-send-pack.txt b/Documentation/git-send-pack.txt
index 966abb0df8..f51c64939b 100644
--- a/Documentation/git-send-pack.txt
+++ b/Documentation/git-send-pack.txt
@@ -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
diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
index 1eb15afa1c..543fb425ee 100644
--- a/Documentation/git-tag.txt
+++ b/Documentation/git-tag.txt
@@ -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
----------
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 7dd5e03280..6e3a6767e5 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -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.
diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt
index b2514f4d44..623ed1a138 100644
--- a/Documentation/githooks.txt
+++ b/Documentation/githooks.txt
@@ -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
index 22a39b9299..0000000000
--- a/Documentation/technical/api-builtin.txt
+++ /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.
diff --git a/Documentation/technical/api-config.txt b/Documentation/technical/api-config.txt
index 20741f345e..7a83a3a6e2 100644
--- a/Documentation/technical/api-config.txt
+++ b/Documentation/technical/api-config.txt
@@ -187,6 +187,10 @@ Same as `git_config_bool`, except that integers are returned as-is, and
an `is_bool` flag is unset.
`git_config_maybe_bool`::
+Deprecated. Use `git_parse_maybe_bool` instead. They are exactly the
+same, except this function takes an unused argument `name`.
+
+`git_parse_maybe_bool`::
Same as `git_config_bool`, except that it returns -1 on error rather
than dying.
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 1ab52e381e..75beb2e775 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v2.14.2
+DEF_VER=v2.14.GIT
LF='
'
diff --git a/Makefile b/Makefile
index 461c845d33..86ec29202b 100644
--- 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
diff --git a/RelNotes b/RelNotes
index 29ef983310..80ae7a3110 120000
--- 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 40707ca50c..956f56a927 100644
--- 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 b3d6783d55..d9b3957703 100644
--- 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;
diff --git a/archive.c b/archive.c
index 60b3035a7a..557dd2db85 100644
--- 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 56961f0236..2f49151736 100644
--- 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);
}
/*
diff --git a/bisect.c b/bisect.c
index a9fd9fbc61..2549eaf7b1 100644
--- 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. */
diff --git a/builtin.h b/builtin.h
index 498ac80d07..42378f3aa4 100644
--- 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);
diff --git a/builtin/add.c b/builtin/add.c
index e888fb8c5f..5d5773d5cd 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -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);
}
}
diff --git a/builtin/am.c b/builtin/am.c
index c973bd96dc..81095dae02 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -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 {
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 96b786e489..62c8cf0ebf 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -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:
diff --git a/builtin/clean.c b/builtin/clean.c
index c1bafda5b6..21a7a32994 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -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
diff --git a/builtin/clone.c b/builtin/clone.c
index 08b5cc433c..f7e17d2295 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -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);
}
diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c
index a4a923d7c0..19e898fa4e 100644
--- a/builtin/commit-tree.c
+++ b/builtin/commit-tree.c
@@ -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");
diff --git a/builtin/commit.c b/builtin/commit.c
index 1a0da71a43..b79bcfd5b9 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -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");
diff --git a/builtin/describe.c b/builtin/describe.c
index 89ea1cdd60..9c13c6817b 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -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."));
diff --git a/builtin/difftool.c b/builtin/difftool.c
index a1a26ba891..8864d846f8 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -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;
diff --git a/builtin/fetch.c b/builtin/fetch.c
index c87e59f3b1..d84c26391c 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -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);
diff --git a/builtin/fsck.c b/builtin/fsck.c
index 64542ac3de..b0964a8d34 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -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;
}
diff --git a/builtin/grep.c b/builtin/grep.c
index 42ff87065a..a70d8e2fba 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -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)
diff --git a/builtin/log.c b/builtin/log.c
index 5ffc380bd7..25c0808409 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -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);
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index bad6735c76..f12da292cf 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -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;
diff --git a/builtin/merge.c b/builtin/merge.c
index d5797b8fe7..328945d609 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -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
diff --git a/builtin/mv.c b/builtin/mv.c
index dcf6736b5b..94fbaaa5da 100644
--- a/builtin/mv.c
+++ b/builtin/mv.c
@@ -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);
diff --git a/builtin/notes.c b/builtin/notes.c
index 77573cf1ea..4303848e04 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -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))
diff --git a/builtin/pull.c b/builtin/pull.c
index 9b86e519b1..7fe281414e 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -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:
diff --git a/builtin/push.c b/builtin/push.c
index 03846e8379..2ac8104229 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -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;
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index cabdc55e09..14b6e09b42 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -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);
diff --git a/builtin/remote.c b/builtin/remote.c
index 6273c0c23c..a995ea86c1 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -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"))
diff --git a/builtin/replace.c b/builtin/replace.c
index fba336a68a..f4a85a165b 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -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 */
diff --git a/builtin/reset.c b/builtin/reset.c
index 7aeaea2737..046403ed68 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -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)
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index e8f5048903..95b4128250 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -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);
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index c78b7b33d6..2bd28d3c08 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -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
diff --git a/builtin/revert.c b/builtin/revert.c
index 16028b9ea8..b9d927eb09 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -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);
}
diff --git a/builtin/rm.c b/builtin/rm.c
index 52826d1379..4057e73fa0 100644
--- a/builtin/rm.c
+++ b/builtin/rm.c
@@ -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"));
}
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index 633e0c3cdd..fc4f0bb5fb 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -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;
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index 28f245c8cc..84547d6fba 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -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)
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 3a3c9ca72b..0ff9dd0b85 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -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;
}
diff --git a/builtin/tag.c b/builtin/tag.c
index 66e35b823b..c627794181 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -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);
diff --git a/builtin/unpack-file.c b/builtin/unpack-file.c
index 73f1334191..281ca1db6c 100644
--- a/builtin/unpack-file.c
+++ b/builtin/unpack-file.c
@@ -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;
}
diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index 40ccfc193b..6b90c5dead 100644
--- a/builtin/update-ref.c
+++ b/builtin/update-ref.c
@@ -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);
}
diff --git a/builtin/verify-tag.c b/builtin/verify-tag.c
index 87d73e856a..ad7b79fa5c 100644
--- a/builtin/verify-tag.c
+++ b/builtin/verify-tag.c
@@ -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 25c98b6809..ab3b52ff92 100644
--- 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*);
diff --git a/commit.c b/commit.c
index d3150d6270..8b28415939 100644
--- 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);
diff --git a/commit.h b/commit.h
index 4127c298cb..6d857f06c1 100644
--- 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);
diff --git a/compat/win32/syslog.c b/compat/win32/syslog.c
index 6c7c9b6053..161978d720 100644
--- a/compat/win32/syslog.c
+++ b/compat/win32/syslog.c
@@ -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;
}
diff --git a/config.c b/config.c
index acebc85d81..777527daef 100644
--- 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);
diff --git a/config.h b/config.h
index 0352da117b..18b6f3f724 100644
--- 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);
diff --git a/contrib/contacts/git-contacts b/contrib/contacts/git-contacts
index dbe2abf277..85ad732fc0 100755
--- a/contrib/contacts/git-contacts
+++ b/contrib/contacts/git-contacts
@@ -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 {
diff --git a/contrib/rerere-train.sh b/contrib/rerere-train.sh
index 52ad9e41fb..eeee45dd34 100755
--- a/contrib/rerere-train.sh
+++ b/contrib/rerere-train.sh
@@ -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"
diff --git a/convert.c b/convert.c
index 4936fcc26b..1012462e3c 100644
--- 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 9c38258030..9c71201e9c 100644
--- 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 b4204d772b..2d2d2e9432 100644
--- 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)
diff --git a/git-merge-octopus.sh b/git-merge-octopus.sh
index bcf0d92ec2..6c390d6c22 100755
--- a/git-merge-octopus.sh
+++ b/git-merge-octopus.sh
@@ -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
diff --git a/git-merge-one-file.sh b/git-merge-one-file.sh
index 424b034e34..9879c59395 100755
--- a/git-merge-one-file.sh
+++ b/git-merge-one-file.sh
@@ -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
diff --git a/git-merge-resolve.sh b/git-merge-resolve.sh
index c9da747fcf..343fe7bccd 100755
--- a/git-merge-resolve.sh
+++ b/git-merge-resolve.sh
@@ -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
diff --git a/git-rebase--am.sh b/git-rebase--am.sh
index 375239341f..6e64d40d6f 100644
--- a/git-rebase--am.sh
+++ b/git-rebase--am.sh
@@ -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=$?
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 90b1fbe9cf..29b7e8824b 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -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")"
diff --git a/git-rebase.sh b/git-rebase.sh
index 2cf73b88e8..ad8415e3cf 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -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
diff --git a/git-stash.sh b/git-stash.sh
index 9b6c2da7b4..8b2ce9afda 100755
--- a/git-stash.sh
+++ b/git-stash.sh
@@ -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")"
diff --git a/git-submodule.sh b/git-submodule.sh
index e131760eec..66d1ae8ef6 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -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 489aab4d83..f31dca6962 100644
--- 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 2efec0e182..ce6a48e634 100644
--- 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 0c091e5104..52aecfab6e 100644
--- a/grep.h
+++ b/grep.h
@@ -193,7 +193,6 @@ struct grep_source {
GREP_SOURCE_OID,
GREP_SOURCE_FILE,
GREP_SOURCE_BUF,
- GREP_SOURCE_SUBMODULE,
} type;
void *identifier;
diff --git a/mailmap.c b/mailmap.c
index c1a79c100c..cb921b4db6 100644
--- 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)
diff --git a/name-hash.c b/name-hash.c
index 0e10f3eab8..bd8dc7a6a7 100644
--- a/name-hash.c
+++ b/name-hash.c
@@ -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 8f47c202c5..503754d79e 100644
--- 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 4dd9e1b265..92b23e6cd1 100644
--- 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 {
diff --git a/patch-ids.c b/patch-ids.c
index b4166b0f38..7a583b3011 100644
--- a/patch-ids.c
+++ b/patch-ids.c
@@ -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;
}
diff --git a/perl/Git.pm b/perl/Git.pm
index f4b56e6d4d..ffa09ace92 100644
--- a/perl/Git.pm
+++ b/perl/Git.pm
@@ -532,7 +532,7 @@ If TIME is not supplied, the current local time is used.
=cut
sub get_tz_offset {
- # some systmes don't handle or mishandle %z, so be creative.
+ # some systems don't handle or mishandle %z, so be creative.
my $t = shift || time;
my $gm = timegm(localtime($t));
my $sign = qw( + + - )[ $gm <=> $t ];
diff --git a/perl/Git/SVN.pm b/perl/Git/SVN.pm
index 98518f4ddb..bc4eed3d75 100644
--- a/perl/Git/SVN.pm
+++ b/perl/Git/SVN.pm
@@ -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 ea2b9f84f8..3d549a8970 100644
--- 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);
diff --git a/refs/files-backend.c b/refs/files-backend.c
index 0404f2c233..5cca55510b 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -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"
@@ -16,39 +17,6 @@ struct ref_lock {
};
/*
- * 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)
@@ -371,70 +148,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
* directory entry corresponding to dirname.
@@ -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 @@ stat_ref:
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 @@ stat_ref:
* 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 @@ retry:
/*
* 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
index 0000000000..412c85034f
--- /dev/null
+++ b/refs/packed-backend.c
@@ -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
index 0000000000..03b7c1de95
--- /dev/null
+++ b/refs/packed-backend.h
@@ -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 */
diff --git a/refs/refs-internal.h b/refs/refs-internal.h
index 192f9f85c9..4789106fc0 100644
--- a/refs/refs-internal.h
+++ b/refs/refs-internal.h
@@ -77,6 +77,15 @@
*/
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
diff --git a/remote.c b/remote.c
index 60d0043921..43c317e4e9 100644
--- 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;
diff --git a/remote.h b/remote.h
index 6c28cd3e4b..2ecf4c8c74 100644
--- 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;
diff --git a/repository.c b/repository.c
index edca907404..f107af7d76 100644
--- a/repository.c
+++ b/repository.c
@@ -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);
}
diff --git a/repository.h b/repository.h
index 417787f3ef..7f5e24a0a2 100644
--- a/repository.h
+++ b/repository.h
@@ -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 */
diff --git a/revision.c b/revision.c
index 2631b013a5..aa3b946a8d 100644
--- a/revision.c
+++ b/revision.c
@@ -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);
diff --git a/revision.h b/revision.h
index f96e7f7f49..bc18487d6f 100644
--- a/revision.h
+++ b/revision.h
@@ -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;
diff --git a/sequencer.c b/sequencer.c
index 3010faf863..fcceabb80f 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -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 @@ cleanup_head_ref:
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 @@ cleanup_head_ref:
}
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 @@ cleanup_head_ref:
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 860507e1fd..23950173fc 100644
--- 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
diff --git a/sha1-lookup.c b/sha1-lookup.c
index 5f069214d9..2552b7902c 100644
--- a/sha1-lookup.c
+++ b/sha1-lookup.c
@@ -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;
-}
diff --git a/sha1_file.c b/sha1_file.c
index b60ae15f70..189a1c3cdd 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -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;
diff --git a/sha1_name.c b/sha1_name.c
index 74fcb6d788..862b6f1308 100644
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -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);
}
diff --git a/shallow.c b/shallow.c
index 54359d5490..f5591e56da 100644
--- 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;
diff --git a/strbuf.c b/strbuf.c
index 89d22e3b09..323c49ceb3 100644
--- 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) {
diff --git a/strbuf.h b/strbuf.h
index 2075384e0b..e705b94db5 100644
--- 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
diff --git a/sub-process.c b/sub-process.c
index 86de8d7bfb..6edb97c1c6 100644
--- a/sub-process.c
+++ b/sub-process.c
@@ -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);
}
diff --git a/sub-process.h b/sub-process.h
index caa91a9b92..49701998c9 100644
--- a/sub-process.h
+++ b/sub-process.h
@@ -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);
/*
diff --git a/submodule-config.c b/submodule-config.c
index 5fe2d07877..0c839019e1 100644
--- a/submodule-config.c
+++ b/submodule-config.c
@@ -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);
diff --git a/submodule-config.h b/submodule-config.h
index 233bfcb7ff..cccd34b929 100644
--- a/submodule-config.h
+++ b/submodule-config.h
@@ -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 */
diff --git a/submodule.c b/submodule.c
index 6531c5d609..e072036e79 100644
--- a/submodule.c
+++ b/submodule.c
@@ -20,37 +20,53 @@
#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 @@ done:
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 @@ done:
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;
diff --git a/submodule.h b/submodule.h
index e85b144863..e402b004ff 100644
--- a/submodule.h
+++ b/submodule.h
@@ -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
diff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c
index 095d7395f3..6004c81f0b 100644
--- a/t/helper/test-hashmap.c
+++ b/t/helper/test-hashmap.c
@@ -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)) {
diff --git a/t/helper/test-path-utils.c b/t/helper/test-path-utils.c
index 1ebe0f750c..2b3c5092a1 100644
--- a/t/helper/test-path-utils.c
+++ b/t/helper/test-path-utils.c
@@ -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)");
diff --git a/t/helper/test-submodule-config.c b/t/helper/test-submodule-config.c
index c6c57bba0d..e13fbcc1b5 100644
--- a/t/helper/test-submodule-config.c
+++ b/t/helper/test-submodule-config.c
@@ -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.");
diff --git a/t/lib-gpg.sh b/t/lib-gpg.sh
index ec2aa8f687..43679a4c64 100755
--- a/t/lib-gpg.sh
+++ b/t/lib-gpg.sh
@@ -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 \
diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index c4814d248f..86c1a51654 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -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' '
diff --git a/t/t1002-read-tree-m-u-2way.sh b/t/t1002-read-tree-m-u-2way.sh
index e3bf821694..7ca2e65d10 100755
--- a/t/t1002-read-tree-m-u-2way.sh
+++ b/t/t1002-read-tree-m-u-2way.sh
@@ -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
index 397ccb6909..0000000000
--- a/t/t1200-tutorial.sh
+++ /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
index 0000000000..1e44a17eea
--- /dev/null
+++ b/t/t1408-packed-refs.sh
@@ -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
diff --git a/t/t3210-pack-refs.sh b/t/t3210-pack-refs.sh
index 9b182a0c32..afa27ffe2d 100755
--- a/t/t3210-pack-refs.sh
+++ b/t/t3210-pack-refs.sh
@@ -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
diff --git a/t/t3418-rebase-continue.sh b/t/t3418-rebase-continue.sh
index 4428b9086e..fcfdd197bd 100755
--- a/t/t3418-rebase-continue.sh
+++ b/t/t3418-rebase-continue.sh
@@ -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
diff --git a/t/t3504-cherry-pick-rerere.sh b/t/t3504-cherry-pick-rerere.sh
index e6a64816ef..a267b2d144 100755
--- a/t/t3504-cherry-pick-rerere.sh
+++ b/t/t3504-cherry-pick-rerere.sh
@@ -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
'
diff --git a/t/t3700-add.sh b/t/t3700-add.sh
index f3a4b4a913..0aae21d698 100755
--- a/t/t3700-add.sh
+++ b/t/t3700-add.sh
@@ -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 &&
diff --git a/t/t3905-stash-include-untracked.sh b/t/t3905-stash-include-untracked.sh
index 193adc7b68..bfde4057ad 100755
--- a/t/t3905-stash-include-untracked.sh
+++ b/t/t3905-stash-include-untracked.sh
@@ -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
diff --git a/t/t4062-diff-pickaxe.sh b/t/t4062-diff-pickaxe.sh
index 7c4903f497..1130c8019b 100755
--- a/t/t4062-diff-pickaxe.sh
+++ b/t/t4062-diff-pickaxe.sh
@@ -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)"
'
diff --git a/t/t4150-am.sh b/t/t4150-am.sh
index 44807e218d..73b67b4280 100755
--- a/t/t4150-am.sh
+++ b/t/t4150-am.sh
@@ -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
diff --git a/t/t4202-log.sh b/t/t4202-log.sh
index 3f3531f0a4..36d120c969 100755
--- a/t/t4202-log.sh
+++ b/t/t4202-log.sh
@@ -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 &&
diff --git a/t/t5308-pack-detect-duplicates.sh b/t/t5308-pack-detect-duplicates.sh
index 9c5a8766ab..156ae9e9d3 100755
--- a/t/t5308-pack-detect-duplicates.sh
+++ b/t/t5308-pack-detect-duplicates.sh
@@ -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 &&
diff --git a/t/t5520-pull.sh b/t/t5520-pull.sh
index f15f7a3329..59c4b778d3 100755
--- a/t/t5520-pull.sh
+++ b/t/t5520-pull.sh
@@ -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' '
diff --git a/t/t5526-fetch-submodules.sh b/t/t5526-fetch-submodules.sh
index 162baf101f..42251f7f3a 100755
--- a/t/t5526-fetch-submodules.sh
+++ b/t/t5526-fetch-submodules.sh
@@ -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 &&
diff --git a/t/t5531-deep-submodule-push.sh b/t/t5531-deep-submodule-push.sh
index beff65b8ac..0f84a53146 100755
--- a/t/t5531-deep-submodule-push.sh
+++ b/t/t5531-deep-submodule-push.sh
@@ -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
diff --git a/t/t5534-push-signed.sh b/t/t5534-push-signed.sh
index 464ffdd147..1cea758f78 100755
--- a/t/t5534-push-signed.sh
+++ b/t/t5534-push-signed.sh
@@ -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 &&
diff --git a/t/t6018-rev-list-glob.sh b/t/t6018-rev-list-glob.sh
index 381f35ed16..d3453c583c 100755
--- a/t/t6018-rev-list-glob.sh
+++ b/t/t6018-rev-list-glob.sh
@@ -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 &&
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index dd5ba450ee..dbcd6f623c 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -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' '
diff --git a/t/t7006-pager.sh b/t/t7006-pager.sh
index 20b4d83c28..9128ec5acd 100755
--- a/t/t7006-pager.sh
+++ b/t/t7006-pager.sh
@@ -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() {
diff --git a/t/t7301-clean-interactive.sh b/t/t7301-clean-interactive.sh
index 3ae394e934..556e1850e2 100755
--- a/t/t7301-clean-interactive.sh
+++ b/t/t7301-clean-interactive.sh
@@ -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
diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
index dcac364c5f..e9c3335b78 100755
--- a/t/t7400-submodule-basic.sh
+++ b/t/t7400-submodule-basic.sh
@@ -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
diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh
index f106387820..2a6679c2f5 100755
--- a/t/t7810-grep.sh
+++ b/t/t7810-grep.sh
@@ -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
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 1b6e53f78a..5fbd8d4a90 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -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 47f60ae151..7e10acfb6e 100644
--- 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 fdfcb4a84a..d469534e82 100644
--- 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 */
diff --git a/templates/hooks--prepare-commit-msg.sample b/templates/hooks--prepare-commit-msg.sample
index 86b8f227ec..318afe3fd8 100755
--- a/templates/hooks--prepare-commit-msg.sample
+++ b/templates/hooks--prepare-commit-msg.sample
@@ -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
@@ -20,17 +20,23 @@
# 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
diff --git a/transport-helper.c b/transport-helper.c
index 33cff38cc0..8f68d69a86 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -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);
diff --git a/tree-diff.c b/tree-diff.c
index bd6d65a409..2357f72899 100644
--- a/tree-diff.c
+++ b/tree-diff.c
@@ -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);
diff --git a/unpack-trees.c b/unpack-trees.c
index 862cfce661..38000ac8fa 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -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) {