diff options
206 files changed, 8899 insertions, 1683 deletions
@@ -151,7 +151,8 @@ Matthias Kestenholz <matthias@spinlock.ch> <mk@spinlock.ch> Matthias Urlichs <matthias@urlichs.de> <smurf@kiste.(none)> Matthias Urlichs <matthias@urlichs.de> <smurf@smurf.noris.de> Michael Coleman <tutufan@gmail.com> -Michael J Gruber <git@drmicha.warpmail.net> <michaeljgruber+gmane@fastmail.fm> +Michael J Gruber <git@grubix.eu> <michaeljgruber+gmane@fastmail.fm> +Michael J Gruber <git@grubix.eu> <git@drmicha.warpmail.net> Michael S. Tsirkin <mst@kernel.org> <mst@redhat.com> Michael S. Tsirkin <mst@kernel.org> <mst@mellanox.co.il> Michael S. Tsirkin <mst@kernel.org> <mst@dev.mellanox.co.il> diff --git a/.travis.yml b/.travis.yml index 591cc57b80..c757a111ce 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,6 +39,17 @@ env: matrix: include: + - env: Windows + os: linux + compiler: + addons: + before_install: + before_script: + script: + - > + test "$TRAVIS_REPO_SLUG" != "git/git" || + ci/run-windows-build.sh $TRAVIS_BRANCH $(git rev-parse HEAD) + after_failure: - env: Linux32 os: linux services: diff --git a/Documentation/RelNotes/2.12.2.txt b/Documentation/RelNotes/2.12.2.txt new file mode 100644 index 0000000000..441939709c --- /dev/null +++ b/Documentation/RelNotes/2.12.2.txt @@ -0,0 +1,83 @@ +Git v2.12.2 Release Notes +========================= + +Fixes since v2.12.1 +------------------- + + * "git status --porcelain" is supposed to give a stable output, but a + few strings were left as translatable by mistake. + + * "Dumb http" transport used to misparse a nonsense http-alternates + response, which has been fixed. + + * "git diff --quiet" relies on the size field in diff_filespec to be + correctly populated, but diff_populate_filespec() helper function + made an incorrect short-cut when asked only to populate the size + field for paths that need to go through convert_to_git() (e.g. CRLF + conversion). + + * There is no need for Python only to give a few messages to the + standard error stream, but we somehow did. + + * A leak in a codepath to read from a packed object in (rare) cases + has been plugged. + + * "git upload-pack", which is a counter-part of "git fetch", did not + report a request for a ref that was not advertised as invalid. + This is generally not a problem (because "git fetch" will stop + before making such a request), but is the right thing to do. + + * A "gc.log" file left by a backgrounded "gc --auto" disables further + automatic gc; it has been taught to run at least once a day (by + default) by ignoring a stale "gc.log" file that is too old. + + * "git remote rm X", when a branch has remote X configured as the + value of its branch.*.remote, tried to remove branch.*.remote and + branch.*.merge and failed if either is unset. + + * A caller of tempfile API that uses stdio interface to write to + files may ignore errors while writing, which is detected when + tempfile is closed (with a call to ferror()). By that time, the + original errno that may have told us what went wrong is likely to + be long gone and was overwritten by an irrelevant value. + close_tempfile() now resets errno to EIO to make errno at least + predictable. + + * "git show-branch" expected there were only very short branch names + in the repository and used a fixed-length buffer to hold them + without checking for overflow. + + * The code that parses header fields in the commit object has been + updated for (micro)performance and code hygiene. + + * A test that creates a confusing branch whose name is HEAD has been + corrected not to do so. + + * "Cc:" on the trailer part does not have to conform to RFC strictly, + unlike in the e-mail header. "git send-email" has been updated to + ignore anything after '>' when picking addresses, to allow non-address + cruft like " # stable 4.4" after the address. + + * "git push" had a handful of codepaths that could lead to a deadlock + when unexpected error happened, which has been fixed. + + * Code to read submodule.<name>.ignore config did not state the + variable name correctly when giving an error message diagnosing + misconfiguration. + + * "git ls-remote" and "git archive --remote" are designed to work + without being in a directory under Git's control. However, recent + updates revealed that we randomly look into a directory called + .git/ without actually doing necessary set-up when working in a + repository. Stop doing so. + + * The code to parse the command line "git grep <patterns>... <rev> + [[--] <pathspec>...]" has been cleaned up, and a handful of bugs + have been fixed (e.g. we used to check "--" if it is a rev). + + * The code to parse "git -c VAR=VAL cmd" and set configuration + variable for the duration of cmd had two small bugs, which have + been fixed. + This supersedes jc/config-case-cmdline topic that has been discarded. + +Also contains various documentation updates and code clean-ups. diff --git a/Documentation/RelNotes/2.12.3.txt b/Documentation/RelNotes/2.12.3.txt new file mode 100644 index 0000000000..73ce7daa5c --- /dev/null +++ b/Documentation/RelNotes/2.12.3.txt @@ -0,0 +1,57 @@ +Git v2.12.3 Release Notes +========================= + +Fixes since v2.12.2 +------------------- + + * The "parse_config_key()" API function has been cleaned up. + + * An helper function to make it easier to append the result from + real_path() to a strbuf has been added. + + * The t/perf performance test suite was not prepared to test not so + old versions of Git, but now it covers versions of Git that are not + so ancient. + + * Picking two versions of Git and running tests to make sure the + older one and the newer one interoperate happily has now become + possible. + + * Teach the "debug" helper used in the test framework that allows a + command to run under "gdb" to make the session interactive. + + * "git repack --depth=<n>" for a long time busted the specified depth + when reusing delta from existing packs. This has been corrected. + + * user.email that consists of only cruft chars should consistently + error out, but didn't. + + * A few tests were run conditionally under (rare) conditions where + they cannot be run (like running cvs tests under 'root' account). + + * "git branch @" created refs/heads/@ as a branch, and in general the + code that handled @{-1} and @{upstream} was a bit too loose in + disambiguating. + + * "git fetch" that requests a commit by object name, when the other + side does not allow such an request, failed without much + explanation. + + * "git filter-branch --prune-empty" drops a single-parent commit that + becomes a no-op, but did not drop a root commit whose tree is empty. + + * Recent versions of Git treats http alternates (used in dumb http + transport) just like HTTP redirects and requires the client to + enable following it, due to security concerns. But we forgot to + give a warning when we decide not to honor the alternates. + + * NO_PTHREADS build has been broken for some time; now fixed. + + * Fix for potential segv introduced in v2.11.0 and later (also + v2.10.2). + + * A few unterminated here documents in tests were fixed, which in + turn revealed incorrect expectations the tests make. These tests + have been updated. + +Also contains various documentation updates and code clean-ups. diff --git a/Documentation/RelNotes/2.13.0.txt b/Documentation/RelNotes/2.13.0.txt index 0d4a3ef931..4b6e72a7ac 100644 --- a/Documentation/RelNotes/2.13.0.txt +++ b/Documentation/RelNotes/2.13.0.txt @@ -12,8 +12,18 @@ Backward compatibility notes. release (yet). * The historical argument order "git merge <msg> HEAD <commit>..." - has been deprecated for quite some time, and will be removed in a - future release. + has been deprecated for quite some time, and is now removed. + + * The default location "~/.git-credential-cache/socket" for the + socket used to communicate with the credential-cache daemon has + been moved to "~/.cache/git/credential/socket". + + * 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.12 @@ -77,16 +87,13 @@ UI, Workflows & Features unlike in the e-mail header. "git send-email" has been updated to ignore anything after '>' when picking addresses, to allow non-address cruft like " # stable 4.4" after the address. - (merge 9d3343961b jh/send-email-one-cc later to maint). * When "git submodule init" decides that the submodule in the working tree is its upstream, it now gives a warning as it is not a very common setup. - (merge d1b3b81aab sb/submodule-init-url-selection later to maint). - * "git stash save" takes a pathspec so that the local changes can be + * "git stash push" takes a pathspec so that the local changes can be stashed away only partially. - (merge 9e140909f6 tg/stash-push later to maint). * Documentation for "git ls-files" did not refer to core.quotePath. @@ -113,6 +120,62 @@ UI, Workflows & Features repository and was quite messy due to its "chicken-and-egg" nature. The code has been restructured. + * The command line prompt (in contrib/) learned a new 'tag' style + that can be specified with GIT_PS1_DESCRIBE_STYLE, to describe a + detached HEAD with "git describe --tags". + + * The configuration file learned a new "includeIf.<condition>.path" + that includes the contents of the given path only when the + condition holds. This allows you to say "include this work-related + bit only in the repositories under my ~/work/ directory". + + * Recent update to "rebase -i" started showing a message that is not + a warning with "warning:" prefix by mistake. This has been fixed. + + * Recently we started passing the "--push-options" through the + external remote helper interface; now the "smart HTTP" remote + helper understands what to do with the passed information. + + * "git describe --dirty" dies when it cannot be determined if the + state in the working tree matches that of HEAD (e.g. broken + repository or broken submodule). The command learned a new option + "git describe --broken" to give "$name-broken" (where $name is the + description of HEAD) in such a case. + + * "git checkout" is taught the "--recurse-submodules" option. + + * Recent enhancement to "git stash push" command to support pathspec + to allow only a subset of working tree changes to be stashed away + was found to be too chatty and exposed the internal implementation + detail (e.g. when it uses reset to match the index to HEAD before + doing other things, output from reset seeped out). These, and + other chattyness has been fixed. + + * "git merge <message> HEAD <commit>" syntax that has been deprecated + since October 2007 has been removed. + + * The refs completion for large number of refs has been sped up, + partly by giving up disambiguating ambiguous refs and partly by + eliminating most of the shell processing between 'git for-each-ref' + and 'ls-remote' and Bash's completion facility. + + * On many keyboards, typing "@{" involves holding down SHIFT key and + one can easily end up with "@{Up..." when typing "@{upstream}". As + the upstream/push keywords do not appear anywhere else in the syntax, + we can safely accept them case insensitively without introducing + ambiguity or confusion to solve this. + + * "git tag/branch/for-each-ref" family of commands long allowed to + filter the refs by "--contains X" (show only the refs that are + descendants of X), "--merged X" (show only the refs that are + ancestors of X), "--no-merged X" (show only the refs that are not + ancestors of X). One curious omission, "--no-contains X" (show + only the refs that are not descendants of X) has been added to + them. + + * The default behaviour of "git log" in an interactive session has + been changed to enable "--decorate". + Performance, Internal Implementation, Development Support etc. @@ -137,19 +200,15 @@ Performance, Internal Implementation, Development Support etc. errno from failed system calls. * The "parse_config_key()" API function has been cleaned up. - (merge ad8c7cdadd jk/parse-config-key-cleanup later to maint). * A test that creates a confusing branch whose name is HEAD has been corrected not to do so. - (merge f0252ca23c jk/t6300-cleanup later to maint). * The code that parses header fields in the commit object has been updated for (micro)performance and code hygiene. - (merge b072504ce1 rs/commit-parsing-optim later to maint). * An helper function to make it easier to append the result from real_path() to a strbuf has been added. - (merge 33ad9ddd0b rs/strbuf-add-real-path later to maint). * Reduce authentication round-trip over HTTP when the server supports just a single authentication method. This also improves the @@ -164,7 +223,6 @@ Performance, Internal Implementation, Development Support etc. * The t/perf performance test suite was not prepared to test not so old versions of Git, but now it covers versions of Git that are not so ancient. - (merge 28e1fb5466 jt/perf-updates later to maint). * Add 32-bit Linux variant to the set of platforms to be tested with Travis CI. @@ -177,7 +235,6 @@ Performance, Internal Implementation, Development Support etc. * Picking two versions of Git and running tests to make sure the older one and the newer one interoperate happily has now become possible. - (merge bd4d9d993c jk/interop-test later to maint). * "uchar [40]" to "struct object_id" conversion continues. @@ -186,6 +243,34 @@ Performance, Internal Implementation, Development Support etc. use; this has been cleaned up and made to use the newer commit-slab facility. + * The "debug" helper used in the test framework learned to run + a command under "gdb" interactively. + + * The "detect attempt to create collisions" variant of SHA-1 + implementation by Marc Stevens (CWI) and Dan Shumow (Microsoft) + has been integrated and made the default. + + * The test framework learned to detect unterminated here documents. + + * The name-hash used for detecting paths that are different only in + cases (which matter on case insensitive filesystems) has been + optimized to take advantage of multi-threading when it makes sense. + + * An earlier version of sha1dc/sha1.c that was merged to 'master' + compiled incorrectly on Windows, which has been fixed. + + * "what URL do we want to update this submodule?" and "are we + interested in this submodule?" are split into two distinct + concepts, and then the way used to express the latter got extended, + paving a way to make it easier to manage a project with many + submodules and make it possible to later extend use of multiple + worktrees for a project with submodules. + + * Some debugging output from "git describe" were marked for l10n, + but some weren't. Mark missing ones for l10n. + + * Define a new task in .travis.yml that triggers a test session on + Windows run elsewhere. Also contains various documentation updates and code clean-ups. @@ -193,30 +278,26 @@ Also contains various documentation updates and code clean-ups. Fixes since v2.12 ----------------- -Unless otherwise noted, all the fixes since v2.9 in the maintenance +Unless otherwise noted, all the fixes since v2.12 in the maintenance track are contained in this release (see the maintenance releases' notes for details). * "git repack --depth=<n>" for a long time busted the specified depth when reusing delta from existing packs. This has been corrected. - (merge 42b766d765 jk/delta-chain-limit later to maint). * The code to parse the command line "git grep <patterns>... <rev> [[--] <pathspec>...]" has been cleaned up, and a handful of bugs have been fixed (e.g. we used to check "--" if it is a rev). - (merge 131f3c96d2 jk/grep-no-index-fix later to maint). * "git ls-remote" and "git archive --remote" are designed to work without being in a directory under Git's control. However, recent updates revealed that we randomly look into a directory called .git/ without actually doing necessary set-up when working in a repository. Stop doing so. - (merge 4b0c3c7735 jn/remote-helpers-with-git-dir later to maint). * "git show-branch" expected there were only very short branch names in the repository and used a fixed-length buffer to hold them without checking for overflow. - (merge d3cc5f4c44 jk/show-branch-lift-name-len-limit later to maint). * A caller of tempfile API that uses stdio interface to write to files may ignore errors while writing, which is detected when @@ -225,36 +306,29 @@ notes for details). be long gone and was overwritten by an irrelevant value. close_tempfile() now resets errno to EIO to make errno at least predictable. - (merge 7e8c9355b7 jk/tempfile-ferror-fclose-confusion later to maint). * "git remote rm X", when a branch has remote X configured as the value of its branch.*.remote, tried to remove branch.*.remote and branch.*.merge and failed if either is unset. - (merge 20690b2139 rl/remote-allow-missing-branch-name-merge later to maint). * A "gc.log" file left by a backgrounded "gc --auto" disables further automatic gc; it has been taught to run at least once a day (by default) by ignoring a stale "gc.log" file that is too old. - (merge a831c06a2b dt/gc-ignore-old-gc-logs later to maint). * The code to parse "git -c VAR=VAL cmd" and set configuration variable for the duration of cmd had two small bugs, which have been fixed. - (merge 1274a155af jc/config-case-cmdline-take-2 later to maint). * user.email that consists of only cruft chars should consistently error out, but didn't. - (merge 94425552f3 jk/ident-empty later to maint). * "git upload-pack", which is a counter-part of "git fetch", did not report a request for a ref that was not advertised as invalid. This is generally not a problem (because "git fetch" will stop before making such a request), but is the right thing to do. - (merge bdb31eada7 jt/upload-pack-error-report later to maint). * A leak in a codepath to read from a packed object in (rare) cases has been plugged. - (merge 886ddf4777 rs/sha1-file-plug-fallback-base-leak later to maint). * When a redirected http transport gets an error during the redirected request, we ignored the error we got from the server, @@ -272,7 +346,6 @@ notes for details). * There is no need for Python only to give a few messages to the standard error stream, but we somehow did. - (merge b8686c661d ss/remote-bzr-hg-placeholder-wo-python later to maint). * The code to parse "git log -L..." command line was buggy when there are many ranges specified with -L; overrun of the allocated buffer @@ -286,39 +359,31 @@ notes for details). made an incorrect short-cut when asked only to populate the size field for paths that need to go through convert_to_git() (e.g. CRLF conversion). - (merge 12426e114b jc/diff-populate-filespec-size-only-fix later to maint). * A few tests were run conditionally under (rare) conditions where they cannot be run (like running cvs tests under 'root' account). - (merge c6507484a2 ab/cond-skip-tests later to maint). * "git branch @" created refs/heads/@ as a branch, and in general the code that handled @{-1} and @{upstream} was a bit too loose in disambiguating. - (merge fd4692ff70 jk/interpret-branch-name later to maint). * "git fetch" that requests a commit by object name, when the other side does not allow such an request, failed without much explanation. - (merge d56583ded6 mm/fetch-show-error-message-on-unadvertised-object later to maint). * "git filter-branch --prune-empty" drops a single-parent commit that becomes a no-op, but did not drop a root commit whose tree is empty. - (merge 32da7467eb dp/filter-branch-prune-empty later to maint). * Recent versions of Git treats http alternates (used in dumb http transport) just like HTTP redirects and requires the client to enable following it, due to security concerns. But we forgot to give a warning when we decide not to honor the alternates. - (merge 5cae73d5d2 ew/http-alternates-as-redirects-warning later to maint). * "git push" had a handful of codepaths that could lead to a deadlock when unexpected error happened, which has been fixed. - (merge d1a13d3fcb jk/push-deadlock-regression-fix later to maint). * "Dumb http" transport used to misparse a nonsense http-alternates response, which has been fixed. - (merge d61434ae81 jk/http-walker-buffer-underflow-fix later to maint). * "git add -p <pathspec>" unnecessarily expanded the pathspec to a list of individual files that matches the pathspec by running "git @@ -332,11 +397,80 @@ notes for details). * "git status --porcelain" is supposed to give a stable output, but a few strings were left as translatable by mistake. - (merge b9e2bc560a mg/status-porcelain-no-i18n later to maint). + + * "git revert -m 0 $merge_commit" complained that reverting a merge + needs to say relative to which parent the reversion needs to + happen, as if "-m 0" weren't given. The correct diagnosis is that + "-m 0" does not refer to the first parent ("-m 1" does). This has + been fixed. + + * Code to read submodule.<name>.ignore config did not state the + variable name correctly when giving an error message diagnosing + misconfiguration. + + * Fix for NO_PTHREADS build. + + * Fix for potential segv introduced in v2.11.0 and later (also + v2.10.2) to "git log --pickaxe-regex -S". + + * A few unterminated here documents in tests were fixed, which in + turn revealed incorrect expectations the tests make. These tests + have been updated. + + * Fix for NO_PTHREADS option. + (merge 2225e1ea20 bw/grep-recurse-submodules later to maint). + + * 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"). + (merge b1ef400eec jk/no-looking-at-dotgit-outside-repo-final later to maint). + + * A few commands that recently learned the "--recurse-submodule" + option misbehaved when started from a subdirectory of the + superproject. + (merge b2dfeb7c00 bw/recurse-submodules-relative-fix later to maint). + + * FreeBSD implementation of getcwd(3) behaved differently when an + intermediate directory is unreadable/unsearchable depending on the + length of the buffer provided, which our strbuf_getcwd() was not + aware of. strbuf_getcwd() has been taught to cope with it better. + (merge a54e938e5b rs/freebsd-getcwd-workaround later to maint). + + * A recent update to "rebase -i" stopped running hooks for the "git + commit" command during "reword" action, which has been fixed. + + * Removing an entry from a notes tree and then looking another note + entry from the resulting tree using the internal notes API + functions did not work as expected. No in-tree users of the API + has such access pattern, but it still is worth fixing. + + * "git receive-pack" could have been forced to die by attempting + allocate an unreasonably large amount of memory with a crafted push + certificate; this has been fixed. + (merge f2214dede9 bc/push-cert-receive-fix later to maint). + + * Update error handling for codepath that deals with corrupt loose + objects. + (merge 51054177b3 jk/loose-object-info-report-error later to maint). + + * "git diff --submodule=diff" learned to work better in a project + with a submodule that in turn has its own submodules. + (merge 17b254cda6 sb/show-diff-for-submodule-in-diff-fix later to maint). + + * Update the build dependency so that an update to /usr/bin/perl + etc. result in recomputation of perl.mak file. + (merge c59c4939c2 ab/regen-perl-mak-with-different-perl later to maint). * Other minor doc, test and build updates and code cleanups. - (merge b803ae4427 ps/docs-diffcore later to maint). - (merge bcd886d897 ew/markdown-url-in-readme later to maint). - (merge b2d593a779 rj/remove-unused-mktemp later to maint). - (merge 3255e512a8 jk/ewah-use-right-type-in-sizeof later to maint). - (merge dfa3ad3238 rs/blame-code-cleanup later to maint). + (merge df2a6e38b7 jk/pager-in-use later to maint). + (merge 75ec4a6cb0 ab/branch-list-doc later to maint). + (merge 3e5b36c637 sg/skip-prefix-in-prettify-refname later to maint). + (merge 2c5e2865cc jk/fast-import-cleanup later to maint). + (merge 4473060bc2 ab/test-readme-updates later to maint). + (merge 48a96972fd ab/doc-submitting later to maint). + (merge f5c2bc2b96 jk/make-coccicheck-detect-errors later to maint). + (merge c105f563d1 cc/untracked later to maint). + (merge 8668976b53 jc/unused-symbols later to maint). + (merge fba275dc93 jc/bs-t-is-not-a-tab-for-sed later to maint). + (merge be6ed145de mm/ls-files-s-doc later to maint). + (merge 60b091c679 qp/bisect-docfix later to maint). diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index 3faf7eb884..bc8ad00473 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -98,12 +98,17 @@ should skip the full stop. It is also conventional in most cases to prefix the first line with "area: " where the area is a filename or identifier for the general area of the code being modified, e.g. - . archive: ustar header checksum is computed unsigned - . git-cherry-pick.txt: clarify the use of revision range notation + . doc: clarify distinction between sign-off and pgp-signing + . githooks.txt: improve the intro section If in doubt which identifier to use, run "git log --no-merges" on the files you are modifying to see the current conventions. +It's customary to start the remainder of the first line after "area: " +with a lower-case letter. E.g. "doc: clarify...", not "doc: +Clarify...", or "githooks.txt: improve...", not "githooks.txt: +Improve...". + The body should provide a meaningful commit message, which: . explains the problem the change tries to solve, iow, what is wrong @@ -129,8 +134,9 @@ with the subject enclosed in a pair of double-quotes, like this: noticed that ... The "Copy commit summary" command of gitk can be used to obtain this -format. +format, or this invocation of "git show": + git show -s --date=short --pretty='format:%h ("%s", %ad)' <commit> (3) Generate your patch using Git tools out of your commits. diff --git a/Documentation/config.txt b/Documentation/config.txt index eccc012672..475e874d51 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -79,18 +79,69 @@ escape sequences) are invalid. Includes ~~~~~~~~ -You can include one config file from another by setting the special +You can include a config file from another by setting the special `include.path` variable to the name of the file to be included. The variable takes a pathname as its value, and is subject to tilde -expansion. +expansion. `include.path` can be given multiple times. -The -included file is expanded immediately, as if its contents had been +The included file is expanded immediately, as if its contents had been found at the location of the include directive. If the value of the -`include.path` variable is a relative path, the path is considered to be -relative to the configuration file in which the include directive was -found. See below for examples. +`include.path` variable is a relative path, the path is considered to +be relative to the configuration file in which the include directive +was found. See below for examples. +Conditional includes +~~~~~~~~~~~~~~~~~~~~ + +You can include a config file from another conditionally by setting a +`includeIf.<condition>.path` variable to the name of the file to be +included. The variable's value is treated the same way as +`include.path`. `includeIf.<condition>.path` can be given multiple times. + +The condition starts with a keyword followed by a colon and some data +whose format and meaning depends on the keyword. Supported keywords +are: + +`gitdir`:: + + The data that follows the keyword `gitdir:` is used as a glob + pattern. If the location of the .git directory matches the + pattern, the include condition is met. ++ +The .git location may be auto-discovered, or come from `$GIT_DIR` +environment variable. If the repository is auto discovered via a .git +file (e.g. from submodules, or a linked worktree), the .git location +would be the final location where the .git directory is, not where the +.git file is. ++ +The pattern can contain standard globbing wildcards and two additional +ones, `**/` and `/**`, that can match multiple path components. Please +refer to linkgit:gitignore[5] for details. For convenience: + + * If the pattern starts with `~/`, `~` will be substituted with the + content of the environment variable `HOME`. + + * If the pattern starts with `./`, it is replaced with the directory + containing the current config file. + + * If the pattern does not start with either `~/`, `./` or `/`, `**/` + will be automatically prepended. For example, the pattern `foo/bar` + becomes `**/foo/bar` and would match `/any/path/to/foo/bar`. + + * If the pattern ends with `/`, `**` will be automatically added. For + example, the pattern `foo/` becomes `foo/**`. In other words, it + matches "foo" and everything inside, recursively. + +`gitdir/i`:: + This is the same as `gitdir` except that matching is done + case-insensitively (e.g. on case-insensitive file sytems) + +A few more notes on matching via `gitdir` and `gitdir/i`: + + * Symlinks in `$GIT_DIR` are not resolved before matching. + + * Note that "../" is not special and will match literally, which is + unlikely what you want. Example ~~~~~~~ @@ -119,6 +170,17 @@ Example path = foo ; expand "foo" relative to the current file path = ~/foo ; expand "foo" in your `$HOME` directory + ; include if $GIT_DIR is /path/to/foo/.git + [includeIf "gitdir:/path/to/foo/.git"] + path = /path/to/foo.inc + + ; include for all repositories inside /path/to/group + [includeIf "gitdir:/path/to/group/"] + path = /path/to/foo.inc + + ; include for all repositories inside $HOME/to/group + [includeIf "gitdir:~/to/group/"] + path = /path/to/foo.inc Values ~~~~~~ @@ -675,13 +737,13 @@ alternative to having an `init.templateDir` where you've changed default hooks. core.editor:: - Commands such as `commit` and `tag` that lets you edit - messages by launching an editor uses the value of this + Commands such as `commit` and `tag` that let you edit + messages by launching an editor use the value of this variable when it is set, and the environment variable `GIT_EDITOR` is not set. See linkgit:git-var[1]. core.commentChar:: - Commands such as `commit` and `tag` that lets you edit + Commands such as `commit` and `tag` that let you edit messages consider a line that begins with this character commented, and removes them after the editor returns (default '#'). @@ -2459,6 +2521,8 @@ push.default:: pushing to the same repository you would normally pull from (i.e. central workflow). +* `tracking` - This is a deprecated synonym for `upstream`. + * `simple` - in centralized workflow, work like `upstream` with an added safety to refuse to push if the upstream branch's name is different from the local one. @@ -2949,8 +3013,9 @@ submodule.<name>.url:: The URL for a submodule. This variable is copied from the .gitmodules file to the git config via 'git submodule init'. The user can change the configured URL before obtaining the submodule via 'git submodule - update'. After obtaining the submodule, the presence of this variable - is used as a sign whether the submodule is of interest to git commands. + update'. If neither submodule.<name>.active or submodule.active are + set, the presence of this variable is used as a fallback to indicate + whether the submodule is of interest to git commands. See linkgit:git-submodule[1] and linkgit:gitmodules[5] for details. submodule.<name>.update:: @@ -2988,6 +3053,16 @@ submodule.<name>.ignore:: "--ignore-submodules" option. The 'git submodule' commands are not affected by this setting. +submodule.<name>.active:: + Boolean value indicating if the submodule is of interest to git + commands. This config option takes precedence over the + submodule.active config option. + +submodule.active:: + A repeated field which contains a pathspec used to match against a + submodule's path to determine if the submodule is of interest to git + commands. + submodule.fetchJobs:: Specifies how many submodules are fetched/cloned at the same time. A positive integer allows up to that number of submodules fetched diff --git a/Documentation/git-bisect.txt b/Documentation/git-bisect.txt index bdd915a66b..6c42abf070 100644 --- a/Documentation/git-bisect.txt +++ b/Documentation/git-bisect.txt @@ -137,7 +137,7 @@ respectively, in place of "good" and "bad". (But note that you cannot mix "good" and "bad" with "old" and "new" in a single session.) In this more general usage, you provide `git bisect` with a "new" -commit has some property and an "old" commit that doesn't have that +commit that has some property and an "old" commit that doesn't have that property. Each time `git bisect` checks out a commit, you test if that commit has the property. If it does, mark the commit as "new"; otherwise, mark it as "old". When the bisection is done, `git bisect` diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt index 092f1bcf9f..81bd0a7b77 100644 --- a/Documentation/git-branch.txt +++ b/Documentation/git-branch.txt @@ -10,8 +10,9 @@ SYNOPSIS [verse] 'git branch' [--color[=<when>] | --no-color] [-r | -a] [--list] [-v [--abbrev=<length> | --no-abbrev]] - [--column[=<options>] | --no-column] - [(--merged | --no-merged | --contains) [<commit>]] [--sort=<key>] + [--column[=<options>] | --no-column] [--sort=<key>] + [(--merged | --no-merged) [<commit>]] + [--contains [<commit]] [--no-contains [<commit>]] [--points-at <object>] [--format=<format>] [<pattern>...] 'git branch' [--set-upstream | --track | --no-track] [-l] [-f] <branchname> [<start-point>] 'git branch' (--set-upstream-to=<upstream> | -u <upstream>) [<branchname>] @@ -35,11 +36,12 @@ as branch creation. With `--contains`, shows only the branches that contain the named commit (in other words, the branches whose tip commits are descendants of the -named commit). With `--merged`, only branches merged into the named -commit (i.e. the branches whose tip commits are reachable from the named -commit) will be listed. With `--no-merged` only branches not merged into -the named commit will be listed. If the <commit> argument is missing it -defaults to `HEAD` (i.e. the tip of the current branch). +named commit), `--no-contains` inverts it. With `--merged`, only branches +merged into the named commit (i.e. the branches whose tip commits are +reachable from the named commit) will be listed. With `--no-merged` only +branches not merged into the named commit will be listed. If the <commit> +argument is missing it defaults to `HEAD` (i.e. the tip of the current +branch). The command's second form creates a new branch head named <branchname> which points to the current `HEAD`, or <start-point> if given. @@ -142,8 +144,13 @@ This option is only applicable in non-verbose mode. List both remote-tracking branches and local branches. --list:: - Activate the list mode. `git branch <pattern>` would try to create a branch, - use `git branch --list <pattern>` to list matching branches. + List branches. With optional `<pattern>...`, e.g. `git + branch --list 'maint-*'`, list only the branches that match + the pattern(s). ++ +This should not be confused with `git branch -l <branchname>`, +which creates a branch named `<branchname>` with a reflog. +See `--create-reflog` above for details. -v:: -vv:: @@ -213,13 +220,19 @@ start-point is either a local or remote-tracking branch. Only list branches which contain the specified commit (HEAD if not specified). Implies `--list`. +--no-contains [<commit>]:: + Only list branches which don't contain the specified commit + (HEAD if not specified). Implies `--list`. + --merged [<commit>]:: Only list branches whose tips are reachable from the - specified commit (HEAD if not specified). Implies `--list`. + specified commit (HEAD if not specified). Implies `--list`, + incompatible with `--no-merged`. --no-merged [<commit>]:: Only list branches whose tips are not reachable from the - specified commit (HEAD if not specified). Implies `--list`. + specified commit (HEAD if not specified). Implies `--list`, + incompatible with `--merged`. <branchname>:: The name of the branch to create or delete. @@ -296,13 +309,16 @@ If you are creating a branch that you want to checkout immediately, it is easier to use the git checkout command with its `-b` option to create a branch and check it out with a single command. -The options `--contains`, `--merged` and `--no-merged` serve three related -but different purposes: +The options `--contains`, `--no-contains`, `--merged` and `--no-merged` +serve four related but different purposes: - `--contains <commit>` is used to find all branches which will need special attention if <commit> were to be rebased or amended, since those branches contain the specified <commit>. +- `--no-contains <commit>` is the inverse of that, i.e. branches that don't + contain the specified <commit>. + - `--merged` is used to find all branches which can be safely deleted, since those branches are fully contained by HEAD. diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt index 8e2c0662dd..d6399c0af8 100644 --- a/Documentation/git-checkout.txt +++ b/Documentation/git-checkout.txt @@ -256,6 +256,13 @@ section of linkgit:git-add[1] to learn how to operate the `--patch` mode. out anyway. In other words, the ref can be held by more than one worktree. +--[no-]recurse-submodules:: + Using --recurse-submodules will update the content of all initialized + submodules according to the commit recorded in the superproject. If + local modifications in a submodule would be overwritten the checkout + will fail unless `-f` is used. If nothing (or --no-recurse-submodules) + is used, the work trees of submodules will not be updated. + <branch>:: Branch to checkout; if it refers to a branch (i.e., a name that, when prepended with "refs/heads/", is a valid ref), then that diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt index 35cc34b2fb..30052cce49 100644 --- a/Documentation/git-clone.txt +++ b/Documentation/git-clone.txt @@ -14,7 +14,7 @@ SYNOPSIS [-o <name>] [-b <name>] [-u <upload-pack>] [--reference <repository>] [--dissociate] [--separate-git-dir <git dir>] [--depth <depth>] [--[no-]single-branch] - [--recursive | --recurse-submodules] [--[no-]shallow-submodules] + [--recurse-submodules] [--[no-]shallow-submodules] [--jobs <n>] [--] <repository> [<directory>] DESCRIPTION @@ -215,10 +215,14 @@ objects from the source repository into a pack in the cloned repository. branch when `--single-branch` clone was made, no remote-tracking branch is created. ---recursive:: ---recurse-submodules:: - After the clone is created, initialize all submodules within, - using their default settings. This is equivalent to running +--recurse-submodules[=<pathspec]:: + After the clone is created, initialize and clone submodules + within based on the provided pathspec. If no pathspec is + provided, all submodules are initialized and cloned. + Submodules are initialized and cloned using their default + settings. The resulting clone has `submodule.active` set to + the provided pathspec, or "." (meaning all submodules) if no + pathspec is provided. This is equivalent to running `git submodule update --init --recursive` immediately after the clone is finished. This option is ignored if the cloned repository does not have a worktree/checkout (i.e. if any of diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt index 25dcdcc289..ed0f5b94b3 100644 --- a/Documentation/git-commit.txt +++ b/Documentation/git-commit.txt @@ -463,7 +463,7 @@ order). See linkgit:git-var[1] for details. HOOKS ----- This command can run `commit-msg`, `prepare-commit-msg`, `pre-commit`, -and `post-commit` hooks. See linkgit:githooks[5] for more +`post-commit` and `post-rewrite` hooks. See linkgit:githooks[5] for more information. FILES diff --git a/Documentation/git-credential-cache.txt b/Documentation/git-credential-cache.txt index 96208f822e..2b85826393 100644 --- a/Documentation/git-credential-cache.txt +++ b/Documentation/git-credential-cache.txt @@ -33,10 +33,13 @@ OPTIONS --socket <path>:: Use `<path>` to contact a running cache daemon (or start a new - cache daemon if one is not started). Defaults to - `~/.git-credential-cache/socket`. If your home directory is on a - network-mounted filesystem, you may need to change this to a - local filesystem. You must specify an absolute path. + cache daemon if one is not started). + Defaults to `$XDG_CACHE_HOME/git/credential/socket` unless + `~/.git-credential-cache/` exists in which case + `~/.git-credential-cache/socket` is used instead. + If your home directory is on a network-mounted filesystem, you + may need to change this to a local filesystem. You must specify + an absolute path. CONTROLLING THE DAEMON ---------------------- diff --git a/Documentation/git-describe.txt b/Documentation/git-describe.txt index 8755f3af7b..26f19d3b07 100644 --- a/Documentation/git-describe.txt +++ b/Documentation/git-describe.txt @@ -30,9 +30,14 @@ OPTIONS Commit-ish object names to describe. Defaults to HEAD if omitted. --dirty[=<mark>]:: - Describe the working tree. - It means describe HEAD and appends <mark> (`-dirty` by - default) if the working tree is dirty. +--broken[=<mark>]:: + Describe the state of the working tree. When the working + tree matches HEAD, the output is the same as "git describe + HEAD". If the working tree has local modification "-dirty" + is appended to it. If a repository is corrupt and Git + cannot determine if there is local modification, Git will + error out, unless `--broken' is given, which appends + the suffix "-broken" instead. --all:: Instead of using only the annotated tags, use any ref diff --git a/Documentation/git-diff.txt b/Documentation/git-diff.txt index bbab35fcaf..b0c1bb95c8 100644 --- a/Documentation/git-diff.txt +++ b/Documentation/git-diff.txt @@ -97,6 +97,20 @@ OPTIONS :git-diff: 1 include::diff-options.txt[] +-1 --base:: +-2 --ours:: +-3 --theirs:: + Compare the working tree with the "base" version (stage #1), + "our branch" (stage #2) or "their branch" (stage #3). The + index contains these stages only for unmerged entries i.e. + while resolving conflicts. See linkgit:git-read-tree[1] + section "3-Way Merge" for detailed information. + +-0:: + Omit diff output for unmerged entries and just show + "Unmerged". Can be used only when comparing the working tree + with the index. + <path>...:: The <paths> parameters, when given, are used to limit the diff to the named paths (you can give directory diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt index 111e1be6f5..03e187a105 100644 --- a/Documentation/git-for-each-ref.txt +++ b/Documentation/git-for-each-ref.txt @@ -11,7 +11,7 @@ SYNOPSIS 'git for-each-ref' [--count=<count>] [--shell|--perl|--python|--tcl] [(--sort=<key>)...] [--format=<format>] [<pattern>...] [--points-at <object>] [(--merged | --no-merged) [<object>]] - [--contains [<object>]] + [--contains [<object>]] [--no-contains [<object>]] DESCRIPTION ----------- @@ -69,16 +69,22 @@ OPTIONS --merged [<object>]:: Only list refs whose tips are reachable from the - specified commit (HEAD if not specified). + specified commit (HEAD if not specified), + incompatible with `--no-merged`. --no-merged [<object>]:: Only list refs whose tips are not reachable from the - specified commit (HEAD if not specified). + specified commit (HEAD if not specified), + incompatible with `--merged`. --contains [<object>]:: Only list refs which contain the specified commit (HEAD if not specified). +--no-contains [<object>]:: + Only list refs which don't contain the specified commit (HEAD + if not specified). + --ignore-case:: Sorting and filtering refs are case insensitive. diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt index 9b200b379b..f7a069bb92 100644 --- a/Documentation/git-format-patch.txt +++ b/Documentation/git-format-patch.txt @@ -239,7 +239,7 @@ keeping them as Git notes allows them to be maintained between versions of the patch series (but see the discussion of the `notes.rewrite` configuration options in linkgit:git-notes[1] to use this workflow). ---[no]-signature=<signature>:: +--[no-]signature=<signature>:: Add a signature to each message produced. Per RFC 3676 the signature is separated from the body by a line with '-- ' on it. If the signature option is omitted the signature defaults to the Git version diff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt index 1cab703f73..d153c17e06 100644 --- a/Documentation/git-ls-files.txt +++ b/Documentation/git-ls-files.txt @@ -57,7 +57,7 @@ OPTIONS -s:: --stage:: - Show staged contents' object name, mode bits and stage number in the output. + Show staged contents' mode bits, object name and stage number in the output. --directory:: If a whole directory is classified as "other", show just its diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt index ca3c27b88a..04fdd8cf08 100644 --- a/Documentation/git-merge.txt +++ b/Documentation/git-merge.txt @@ -13,7 +13,6 @@ SYNOPSIS [-s <strategy>] [-X <strategy-option>] [-S[<keyid>]] [--[no-]allow-unrelated-histories] [--[no-]rerere-autoupdate] [-m <msg>] [<commit>...] -'git merge' <msg> HEAD <commit>... 'git merge' --abort 'git merge' --continue @@ -46,11 +45,7 @@ a log message from the user describing the changes. D---E---F---G---H master ------------ -The second syntax (<msg> `HEAD` <commit>...) is supported for -historical reasons. Do not use it from the command line or in -new scripts. It is the same as `git merge -m <msg> <commit>...`. - -The third syntax ("`git merge --abort`") can only be run after the +The second syntax ("`git merge --abort`") can only be run after the merge has resulted in conflicts. 'git merge --abort' will abort the merge process and try to reconstruct the pre-merge state. However, if there were uncommitted changes when the merge started (and diff --git a/Documentation/git-read-tree.txt b/Documentation/git-read-tree.txt index fa1d557e5b..ed9d63ef4a 100644 --- a/Documentation/git-read-tree.txt +++ b/Documentation/git-read-tree.txt @@ -115,6 +115,12 @@ OPTIONS directories the index file and index output file are located in. +--[no-]recurse-submodules:: + Using --recurse-submodules will update the content of all initialized + submodules according to the commit recorded in the superproject by + calling read-tree recursively, also setting the submodules HEAD to be + detached at that commit. + --no-sparse-checkout:: Disable sparse checkout support even if `core.sparseCheckout` is true. diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt index 642d0ef199..9d66166f69 100644 --- a/Documentation/git-send-email.txt +++ b/Documentation/git-send-email.txt @@ -89,7 +89,7 @@ See the CONFIGURATION section for `sendemail.multiEdit`. reply to the given Message-Id, which avoids breaking threads to provide a new patch series. The second and subsequent emails will be sent as replies according to - the `--[no]-chain-reply-to` setting. + the `--[no-]chain-reply-to` setting. + So for example when `--thread` and `--no-chain-reply-to` are specified, the second and subsequent patches will be replies to the first one like in the diff --git a/Documentation/git-send-pack.txt b/Documentation/git-send-pack.txt index a831dd0288..966abb0df8 100644 --- a/Documentation/git-send-pack.txt +++ b/Documentation/git-send-pack.txt @@ -81,6 +81,12 @@ be in a separate packet, and the list must end with a flush packet. will also fail if the actual call to `gpg --sign` fails. See linkgit:git-receive-pack[1] for the details on the receiving end. +--push-option=<string>:: + Pass the specified string as a push option for consumption by + hooks on the server side. If the server doesn't support push + options, error out. See linkgit:git-push[1] and + linkgit:githooks[5] for details. + <host>:: A remote host to house the repository. When this part is specified, 'git-receive-pack' is invoked via diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt index ba873657cf..d70abc6afe 100644 --- a/Documentation/git-status.txt +++ b/Documentation/git-status.txt @@ -181,6 +181,17 @@ in which case `XY` are `!!`. ! ! ignored ------------------------------------------------- +Submodules have more state and instead report + M the submodule has a different HEAD than + recorded in the index + m the submodule has modified content + ? the submodule has untracked files +since modified content or untracked files in a submodule cannot be added +via `git add` in the superproject to prepare a commit. + +'m' and '?' are applied recursively. For example if a nested submodule +in a submodule contains an untracked file, this is reported as '?' as well. + If -b is used the short-format status is preceded by a line ## branchname tracking info @@ -210,6 +221,8 @@ field from the first filename). Third, filenames containing special characters are not specially formatted; no quoting or backslash-escaping is performed. +Any submodule changes are reported as modified `M` instead of `m` or single `?`. + Porcelain Format Version 2 ~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt index e05d0cddef..74bc6200d5 100644 --- a/Documentation/git-submodule.txt +++ b/Documentation/git-submodule.txt @@ -129,7 +129,9 @@ init [--] [<path>...]:: repository will be assumed to be upstream. + Optional <path> arguments limit which submodules will be initialized. -If no path is specified, all submodules are initialized. +If no path is specified and submodule.active has been configured, submodules +configured to be active will be initialized, otherwise all submodules are +initialized. + When present, it will also copy the value of `submodule.$name.update`. This command does not alter existing information in .git/config. diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt index 525737a5d8..f8a0b787f4 100644 --- a/Documentation/git-tag.txt +++ b/Documentation/git-tag.txt @@ -12,9 +12,10 @@ SYNOPSIS 'git tag' [-a | -s | -u <keyid>] [-f] [-m <msg> | -F <file>] <tagname> [<commit> | <object>] 'git tag' -d <tagname>... -'git tag' [-n[<num>]] -l [--contains <commit>] [--points-at <object>] - [--column[=<options>] | --no-column] [--create-reflog] [--sort=<key>] - [--format=<format>] [--[no-]merged [<commit>]] [<pattern>...] +'git tag' [-n[<num>]] -l [--contains <commit>] [--contains <commit>] + [--points-at <object>] [--column[=<options>] | --no-column] + [--create-reflog] [--sort=<key>] [--format=<format>] + [--[no-]merged [<commit>]] [<pattern>...] 'git tag' -v [--format=<format>] <tagname>... DESCRIPTION @@ -82,18 +83,24 @@ OPTIONS -n<num>:: <num> specifies how many lines from the annotation, if any, - are printed when using -l. - The default is not to print any annotation lines. - If no number is given to `-n`, only the first line is printed. - If the tag is not annotated, the commit message is displayed instead. - --l <pattern>:: ---list <pattern>:: - List tags with names that match the given pattern (or all if no - pattern is given). Running "git tag" without arguments also - lists all tags. The pattern is a shell wildcard (i.e., matched - using fnmatch(3)). Multiple patterns may be given; if any of - them matches, the tag is shown. + are printed when using -l. Implies `--list`. ++ +The default is not to print any annotation lines. +If no number is given to `-n`, only the first line is printed. +If the tag is not annotated, the commit message is displayed instead. + +-l:: +--list:: + List tags. With optional `<pattern>...`, e.g. `git tag --list + 'v-*'`, list only the tags that match the pattern(s). ++ +Running "git tag" without arguments also lists all tags. The pattern +is a shell wildcard (i.e., matched using fnmatch(3)). Multiple +patterns may be given; if any of them matches, the tag is shown. ++ +This option is implicitly supplied if any other list-like option such +as `--contains` is provided. See the documentation for each of those +options for details. --sort=<key>:: Sort based on the key given. Prefix `-` to sort in @@ -122,10 +129,23 @@ This option is only applicable when listing tags without annotation lines. --contains [<commit>]:: Only list tags which contain the specified commit (HEAD if not - specified). + specified). Implies `--list`. + +--no-contains [<commit>]:: + Only list tags which don't contain the specified commit (HEAD if + not specified). Implies `--list`. + +--merged [<commit>]:: + Only list tags whose commits are reachable from the specified + commit (`HEAD` if not specified), incompatible with `--no-merged`. + +--no-merged [<commit>]:: + Only list tags whose commits are not reachable from the specified + commit (`HEAD` if not specified), incompatible with `--merged`. --points-at <object>:: - Only list tags of the given object. + Only list tags of the given object (HEAD if not + specified). Implies `--list`. -m <msg>:: --message=<msg>:: @@ -173,11 +193,6 @@ This option is only applicable when listing tags without annotation lines. that of linkgit:git-for-each-ref[1]. When unspecified, defaults to `%(refname:strip=2)`. ---[no-]merged [<commit>]:: - Only list tags whose tips are reachable, or not reachable - if `--no-merged` is used, from the specified commit (`HEAD` - if not specified). - CONFIGURATION ------------- By default, 'git tag' in sign-with-default mode (-s) will use your diff --git a/Documentation/git.txt b/Documentation/git.txt index df0941d456..ecc1bb4bd7 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -44,9 +44,11 @@ unreleased) version of Git, that is available from the 'master' branch of the `git.git` repository. Documentation for older releases are available here: -* link:v2.12.0/git.html[documentation for release 2.12.0] +* link:v2.12.2/git.html[documentation for release 2.12.2] * release notes for + link:RelNotes/2.12.2.txt[2.12.2]. + link:RelNotes/2.12.1.txt[2.12.1]. link:RelNotes/2.12.0.txt[2.12]. * link:v2.11.1/git.html[documentation for release 2.11.1] diff --git a/Documentation/revisions.txt b/Documentation/revisions.txt index ba11b9c95e..75d211f1a8 100644 --- a/Documentation/revisions.txt +++ b/Documentation/revisions.txt @@ -96,7 +96,8 @@ some output processing may assume ref names in UTF-8. refers to the branch that the branch specified by branchname is set to build on top of (configured with `branch.<name>.remote` and `branch.<name>.merge`). A missing branchname defaults to the - current one. + current one. These suffixes are also accepted when spelled in uppercase, and + they mean the same thing no matter the case. '<branchname>@\{push\}', e.g. 'master@\{push\}', '@\{push\}':: The suffix '@\{push}' reports the branch "where we would push to" if @@ -122,6 +123,9 @@ refs/remotes/myfork/mybranch Note in the example that we set up a triangular workflow, where we pull from one location and push to another. In a non-triangular workflow, '@\{push}' is the same as '@\{upstream}', and there is no need for it. ++ +This suffix is also accepted when spelled in uppercase, and means the same +thing no matter the case. '<rev>{caret}', e.g. 'HEAD{caret}, v1.5.1{caret}0':: A suffix '{caret}' to a revision parameter means the first parent of diff --git a/Documentation/technical/api-hashmap.txt b/Documentation/technical/api-hashmap.txt index a3f020cd9e..ccc634bbd7 100644 --- a/Documentation/technical/api-hashmap.txt +++ b/Documentation/technical/api-hashmap.txt @@ -21,6 +21,9 @@ that the hashmap is initialized. It may also be useful for statistical purposes `cmpfn` stores the comparison function specified in `hashmap_init()`. In advanced scenarios, it may be useful to change this, e.g. to switch between case-sensitive and case-insensitive lookup. ++ +When `disallow_rehash` is set, automatic rehashes are prevented during inserts +and deletes. `struct hashmap_entry`:: @@ -57,6 +60,7 @@ Functions `unsigned int strihash(const char *buf)`:: `unsigned int memhash(const void *buf, size_t len)`:: `unsigned int memihash(const void *buf, size_t len)`:: +`unsigned int memihash_cont(unsigned int hash_seed, const void *buf, size_t len)`:: Ready-to-use hash functions for strings, using the FNV-1 algorithm (see http://www.isthe.com/chongo/tech/comp/fnv). @@ -65,6 +69,9 @@ Functions `memihash` operate on arbitrary-length memory. + `strihash` and `memihash` are case insensitive versions. ++ +`memihash_cont` is a variant of `memihash` that allows a computation to be +continued with another chunk of data. `unsigned int sha1hash(const unsigned char *sha1)`:: @@ -184,6 +191,21 @@ passed to `hashmap_cmp_fn` to decide whether the entry matches the key. + Returns the removed entry, or NULL if not found. +`void hashmap_disallow_rehash(struct hashmap *map, unsigned value)`:: + + Disallow/allow automatic rehashing of the hashmap during inserts + and deletes. ++ +This is useful if the caller knows that the hashmap will be accessed +by multiple threads. ++ +The caller is still responsible for any necessary locking; this simply +prevents unexpected rehashing. The caller is also responsible for properly +sizing the initial hashmap to ensure good performance. ++ +A call to allow rehashing does not force a rehash; that might happen +with the next insert or delete. + `void hashmap_iter_init(struct hashmap *map, struct hashmap_iter *iter)`:: `void *hashmap_iter_next(struct hashmap_iter *iter)`:: `void *hashmap_iter_first(struct hashmap *map, struct hashmap_iter *iter)`:: diff --git a/Documentation/technical/api-sha1-array.txt b/Documentation/technical/api-oid-array.txt index dcc52943a5..b0c11f868d 100644 --- a/Documentation/technical/api-sha1-array.txt +++ b/Documentation/technical/api-oid-array.txt @@ -1,7 +1,7 @@ -sha1-array API +oid-array API ============== -The sha1-array API provides storage and manipulation of sets of SHA-1 +The oid-array API provides storage and manipulation of sets of object identifiers. The emphasis is on storage and processing efficiency, making them suitable for large lists. Note that the ordering of items is not preserved over some operations. @@ -9,10 +9,10 @@ not preserved over some operations. Data Structures --------------- -`struct sha1_array`:: +`struct oid_array`:: - A single array of SHA-1 hashes. This should be initialized by - assignment from `SHA1_ARRAY_INIT`. The `sha1` member contains + A single array of object IDs. This should be initialized by + assignment from `OID_ARRAY_INIT`. The `oid` member contains the actual data. The `nr` member contains the number of items in the set. The `alloc` and `sorted` members are used internally, and should not be needed by API callers. @@ -20,22 +20,22 @@ Data Structures Functions --------- -`sha1_array_append`:: - Add an item to the set. The sha1 will be placed at the end of +`oid_array_append`:: + Add an item to the set. The object ID will be placed at the end of the array (but note that some operations below may lose this ordering). -`sha1_array_lookup`:: - Perform a binary search of the array for a specific sha1. +`oid_array_lookup`:: + Perform a binary search of the array for a specific object ID. If found, returns the offset (in number of elements) of the - sha1. If not found, returns a negative integer. If the array is - not sorted, this function has the side effect of sorting it. + object ID. If not found, returns a negative integer. If the array + is not sorted, this function has the side effect of sorting it. -`sha1_array_clear`:: +`oid_array_clear`:: Free all memory associated with the array and return it to the initial, empty state. -`sha1_array_for_each_unique`:: +`oid_array_for_each_unique`:: Efficiently iterate over each unique element of the list, executing the callback function for each one. If the array is not sorted, this function has the side effect of sorting it. If @@ -47,25 +47,25 @@ Examples -------- ----------------------------------------- -int print_callback(const unsigned char sha1[20], +int print_callback(const struct object_id *oid, void *data) { - printf("%s\n", sha1_to_hex(sha1)); + printf("%s\n", oid_to_hex(oid)); return 0; /* always continue */ } void some_func(void) { - struct sha1_array hashes = SHA1_ARRAY_INIT; - unsigned char sha1[20]; + struct sha1_array hashes = OID_ARRAY_INIT; + struct object_id oid; /* Read objects into our set */ - while (read_object_from_stdin(sha1)) - sha1_array_append(&hashes, sha1); + while (read_object_from_stdin(oid.hash)) + oid_array_append(&hashes, &oid); /* Check if some objects are in our set */ - while (read_object_from_stdin(sha1)) { - if (sha1_array_lookup(&hashes, sha1) >= 0) + while (read_object_from_stdin(oid.hash)) { + if (oid_array_lookup(&hashes, &oid) >= 0) printf("it's in there!\n"); /* @@ -75,6 +75,6 @@ void some_func(void) * Instead, this will sort once and then skip duplicates * in linear time. */ - sha1_array_for_each_unique(&hashes, print_callback, NULL); + oid_array_for_each_unique(&hashes, print_callback, NULL); } ----------------------------------------- @@ -140,6 +140,13 @@ all:: # Define PPC_SHA1 environment variable when running make to make use of # a bundled SHA1 routine optimized for PowerPC. # +# Define DC_SHA1 to unconditionally enable the collision-detecting sha1 +# algorithm. This is slower, but may detect attempted collision attacks. +# Takes priority over other *_SHA1 knobs. +# +# Define OPENSSL_SHA1 environment variable when running make to link +# with the SHA1 routine from openssl library. +# # Define SHA1_MAX_BLOCK_SIZE to limit the amount of data that will be hashed # in one call to the platform's SHA1_Update(). e.g. APPLE_COMMON_CRYPTO # wants 'SHA1_MAX_BLOCK_SIZE=1024L*1024L*1024L' defined. @@ -614,6 +621,7 @@ TEST_PROGRAMS_NEED_X += test-fake-ssh TEST_PROGRAMS_NEED_X += test-genrandom TEST_PROGRAMS_NEED_X += test-hashmap TEST_PROGRAMS_NEED_X += test-index-version +TEST_PROGRAMS_NEED_X += test-lazy-init-name-hash TEST_PROGRAMS_NEED_X += test-line-buffer TEST_PROGRAMS_NEED_X += test-match-trees TEST_PROGRAMS_NEED_X += test-mergesort @@ -1384,6 +1392,10 @@ ifdef APPLE_COMMON_CRYPTO SHA1_MAX_BLOCK_SIZE = 1024L*1024L*1024L endif +ifdef OPENSSL_SHA1 + EXTLIBS += $(LIB_4_CRYPTO) + BASIC_CFLAGS += -DSHA1_OPENSSL +else ifdef BLK_SHA1 LIB_OBJS += block-sha1/sha1.o BASIC_CFLAGS += -DSHA1_BLK @@ -1396,8 +1408,11 @@ ifdef APPLE_COMMON_CRYPTO COMPAT_CFLAGS += -DCOMMON_DIGEST_FOR_OPENSSL BASIC_CFLAGS += -DSHA1_APPLE else - EXTLIBS += $(LIB_4_CRYPTO) - BASIC_CFLAGS += -DSHA1_OPENSSL + DC_SHA1 := YesPlease + LIB_OBJS += sha1dc/sha1.o + LIB_OBJS += sha1dc/ubc_check.o + BASIC_CFLAGS += -DSHA1_DC +endif endif endif endif @@ -1837,6 +1852,7 @@ perl/perl.mak: perl/PM.stamp perl/PM.stamp: FORCE @$(FIND) perl -type f -name '*.pm' | sort >$@+ && \ + $(PERL_PATH) -V >>$@+ && \ { cmp $@+ $@ >/dev/null 2>/dev/null || mv $@+ $@; } && \ $(RM) $@+ @@ -2224,6 +2240,7 @@ GIT-BUILD-OPTIONS: FORCE @echo NO_PYTHON=\''$(subst ','\'',$(subst ','\'',$(NO_PYTHON)))'\' >>$@+ @echo NO_UNIX_SOCKETS=\''$(subst ','\'',$(subst ','\'',$(NO_UNIX_SOCKETS)))'\' >>$@+ @echo PAGER_ENV=\''$(subst ','\'',$(subst ','\'',$(PAGER_ENV)))'\' >>$@+ + @echo DC_SHA1=\''$(subst ','\'',$(subst ','\'',$(DC_SHA1)))'\' >>$@+ ifdef TEST_OUTPUT_DIRECTORY @echo TEST_OUTPUT_DIRECTORY=\''$(subst ','\'',$(subst ','\'',$(TEST_OUTPUT_DIRECTORY)))'\' >>$@+ endif @@ -2333,9 +2350,17 @@ check: common-cmds.h C_SOURCES = $(patsubst %.o,%.c,$(C_OBJ)) %.cocci.patch: %.cocci $(C_SOURCES) @echo ' ' SPATCH $<; \ + ret=0; \ for f in $(C_SOURCES); do \ - $(SPATCH) --sp-file $< $$f $(SPATCH_FLAGS); \ - done >$@ 2>$@.log; \ + $(SPATCH) --sp-file $< $$f $(SPATCH_FLAGS) || \ + { ret=$$?; break; }; \ + done >$@+ 2>$@.log; \ + if test $$ret != 0; \ + then \ + cat $@.log; \ + exit 1; \ + fi; \ + mv $@+ $@; \ if test -s $@; \ then \ echo ' ' SPATCH result: $@; \ @@ -246,29 +246,21 @@ char *absolute_pathdup(const char *path) return strbuf_detach(&sb, NULL); } -/* - * Unlike prefix_path, this should be used if the named file does - * not have to interact with index entry; i.e. name of a random file - * on the filesystem. - */ -const char *prefix_filename(const char *pfx, int pfx_len, const char *arg) +char *prefix_filename(const char *pfx, const char *arg) { - static struct strbuf path = STRBUF_INIT; -#ifndef GIT_WINDOWS_NATIVE - if (!pfx_len || is_absolute_path(arg)) - return arg; - strbuf_reset(&path); - strbuf_add(&path, pfx, pfx_len); - strbuf_addstr(&path, arg); -#else - /* don't add prefix to absolute paths, but still replace '\' by '/' */ - strbuf_reset(&path); - if (is_absolute_path(arg)) + struct strbuf path = STRBUF_INIT; + size_t pfx_len = pfx ? strlen(pfx) : 0; + + if (!pfx_len) + ; /* nothing to prefix */ + else if (is_absolute_path(arg)) pfx_len = 0; - else if (pfx_len) + else strbuf_add(&path, pfx, pfx_len); + strbuf_addstr(&path, arg); +#ifdef GIT_WINDOWS_NATIVE convert_slashes(path.buf + pfx_len); #endif - return path.buf; + return strbuf_detach(&path, NULL); } @@ -2046,7 +2046,7 @@ static void prefix_one(struct apply_state *state, char **name) char *old_name = *name; if (!old_name) return; - *name = xstrdup(prefix_filename(state->prefix, state->prefix_length, *name)); + *name = prefix_filename(state->prefix, *name); free(old_name); } @@ -4805,6 +4805,7 @@ int apply_all_patches(struct apply_state *state, for (i = 0; i < argc; i++) { const char *arg = argv[i]; + char *to_free = NULL; int fd; if (!strcmp(arg, "-")) { @@ -4814,21 +4815,21 @@ int apply_all_patches(struct apply_state *state, errs |= res; read_stdin = 0; continue; - } else if (0 < state->prefix_length) - arg = prefix_filename(state->prefix, - state->prefix_length, - arg); + } else + arg = to_free = prefix_filename(state->prefix, arg); fd = open(arg, O_RDONLY); if (fd < 0) { error(_("can't open patch '%s': %s"), arg, strerror(errno)); res = -128; + free(to_free); goto end; } read_stdin = 0; set_default_whitespace_mode(state); res = apply_patch(state, fd, arg, options); close(fd); + free(to_free); if (res < 0) goto end; errs |= res; @@ -12,8 +12,8 @@ #include "sha1-array.h" #include "argv-array.h" -static struct sha1_array good_revs; -static struct sha1_array skipped_revs; +static struct oid_array good_revs; +static struct oid_array skipped_revs; static struct object_id *current_bad_oid; @@ -200,6 +200,7 @@ static struct commit_list *best_bisection_sorted(struct commit_list *list, int n { struct commit_list *p; struct commit_dist *array = xcalloc(nr, sizeof(*array)); + struct strbuf buf = STRBUF_INIT; int cnt, i; for (p = list, cnt = 0; p; p = p->next) { @@ -217,17 +218,18 @@ static struct commit_list *best_bisection_sorted(struct commit_list *list, int n } QSORT(array, cnt, compare_commit_dist); for (p = list, i = 0; i < cnt; i++) { - char buf[100]; /* enough for dist=%d */ struct object *obj = &(array[i].commit->object); - snprintf(buf, sizeof(buf), "dist=%d", array[i].distance); - add_name_decoration(DECORATION_NONE, buf, obj); + strbuf_reset(&buf); + strbuf_addf(&buf, "dist=%d", array[i].distance); + add_name_decoration(DECORATION_NONE, buf.buf, obj); p->item = array[i].commit; p = p->next; } if (p) p->next = NULL; + strbuf_release(&buf); free(array); return list; } @@ -413,9 +415,9 @@ static int register_ref(const char *refname, const struct object_id *oid, current_bad_oid = xmalloc(sizeof(*current_bad_oid)); oidcpy(current_bad_oid, oid); } else if (starts_with(refname, good_prefix.buf)) { - sha1_array_append(&good_revs, oid->hash); + oid_array_append(&good_revs, oid); } else if (starts_with(refname, "skip-")) { - sha1_array_append(&skipped_revs, oid->hash); + oid_array_append(&skipped_revs, oid); } strbuf_release(&good_prefix); @@ -451,13 +453,13 @@ static void read_bisect_paths(struct argv_array *array) fclose(fp); } -static char *join_sha1_array_hex(struct sha1_array *array, char delim) +static char *join_sha1_array_hex(struct oid_array *array, char delim) { struct strbuf joined_hexs = STRBUF_INIT; int i; for (i = 0; i < array->nr; i++) { - strbuf_addstr(&joined_hexs, sha1_to_hex(array->sha1[i])); + strbuf_addstr(&joined_hexs, oid_to_hex(array->oid + i)); if (i + 1 < array->nr) strbuf_addch(&joined_hexs, delim); } @@ -499,8 +501,7 @@ struct commit_list *filter_skipped(struct commit_list *list, while (list) { struct commit_list *next = list->next; list->next = NULL; - if (0 <= sha1_array_lookup(&skipped_revs, - list->item->object.oid.hash)) { + if (0 <= oid_array_lookup(&skipped_revs, &list->item->object.oid)) { if (skipped_first && !*skipped_first) *skipped_first = 1; /* Move current to tried list */ @@ -621,7 +622,7 @@ static void bisect_rev_setup(struct rev_info *revs, const char *prefix, argv_array_pushf(&rev_argv, bad_format, oid_to_hex(current_bad_oid)); for (i = 0; i < good_revs.nr; i++) argv_array_pushf(&rev_argv, good_format, - sha1_to_hex(good_revs.sha1[i])); + oid_to_hex(good_revs.oid + i)); argv_array_push(&rev_argv, "--"); if (read_paths) read_bisect_paths(&rev_argv); @@ -682,7 +683,7 @@ static int is_expected_rev(const struct object_id *oid) static int bisect_checkout(const unsigned char *bisect_rev, int no_checkout) { - char bisect_rev_hex[GIT_SHA1_HEXSZ + 1]; + 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); @@ -701,11 +702,11 @@ static int bisect_checkout(const unsigned char *bisect_rev, int no_checkout) return run_command_v_opt(argv_show_branch, RUN_GIT_CMD); } -static struct commit *get_commit_reference(const unsigned char *sha1) +static struct commit *get_commit_reference(const struct object_id *oid) { - struct commit *r = lookup_commit_reference(sha1); + struct commit *r = lookup_commit_reference(oid->hash); if (!r) - die(_("Not a valid commit name %s"), sha1_to_hex(sha1)); + die(_("Not a valid commit name %s"), oid_to_hex(oid)); return r; } @@ -715,9 +716,9 @@ static struct commit **get_bad_and_good_commits(int *rev_nr) int i, n = 0; ALLOC_ARRAY(rev, 1 + good_revs.nr); - rev[n++] = get_commit_reference(current_bad_oid->hash); + rev[n++] = get_commit_reference(current_bad_oid); for (i = 0; i < good_revs.nr; i++) - rev[n++] = get_commit_reference(good_revs.sha1[i]); + rev[n++] = get_commit_reference(good_revs.oid + i); *rev_nr = n; return rev; @@ -754,9 +755,9 @@ static void handle_bad_merge_base(void) exit(1); } -static void handle_skipped_merge_base(const unsigned char *mb) +static void handle_skipped_merge_base(const struct object_id *mb) { - char *mb_hex = sha1_to_hex(mb); + char *mb_hex = oid_to_hex(mb); char *bad_hex = oid_to_hex(current_bad_oid); char *good_hex = join_sha1_array_hex(&good_revs, ' '); @@ -787,16 +788,16 @@ static void check_merge_bases(int no_checkout) result = get_merge_bases_many(rev[0], rev_nr - 1, rev + 1); for (; result; result = result->next) { - const unsigned char *mb = result->item->object.oid.hash; - if (!hashcmp(mb, current_bad_oid->hash)) { + const struct object_id *mb = &result->item->object.oid; + if (!oidcmp(mb, current_bad_oid)) { handle_bad_merge_base(); - } else if (0 <= sha1_array_lookup(&good_revs, mb)) { + } else if (0 <= oid_array_lookup(&good_revs, mb)) { continue; - } else if (0 <= sha1_array_lookup(&skipped_revs, mb)) { + } else if (0 <= oid_array_lookup(&skipped_revs, mb)) { handle_skipped_merge_base(mb); } else { printf(_("Bisecting: a merge base must be tested\n")); - exit(bisect_checkout(mb, no_checkout)); + exit(bisect_checkout(mb->hash, no_checkout)); } } @@ -234,7 +234,7 @@ void create_branch(const char *name, const char *start_name, { struct commit *commit; unsigned char sha1[20]; - char *real_ref, msg[PATH_MAX + 20]; + char *real_ref; struct strbuf ref = STRBUF_INIT; int forcing = 0; int dont_change_ref = 0; @@ -290,19 +290,18 @@ void create_branch(const char *name, const char *start_name, die(_("Not a valid branch point: '%s'."), start_name); hashcpy(sha1, commit->object.oid.hash); - if (forcing) - snprintf(msg, sizeof msg, "branch: Reset to %s", - start_name); - else if (!dont_change_ref) - snprintf(msg, sizeof msg, "branch: Created from %s", - start_name); - if (reflog) log_all_ref_updates = LOG_REFS_NORMAL; if (!dont_change_ref) { struct ref_transaction *transaction; struct strbuf err = STRBUF_INIT; + char *msg; + + if (forcing) + msg = xstrfmt("branch: Reset to %s", start_name); + else + msg = xstrfmt("branch: Created from %s", start_name); transaction = ref_transaction_begin(&err); if (!transaction || @@ -313,6 +312,7 @@ void create_branch(const char *name, const char *start_name, die("%s", err.buf); ref_transaction_free(transaction); strbuf_release(&err); + free(msg); } if (real_ref && track) diff --git a/builtin/blame.c b/builtin/blame.c index f7aa95f4ba..07506a3e45 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -1890,7 +1890,7 @@ static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent, int cnt; const char *cp; struct origin *suspect = ent->suspect; - char hex[GIT_SHA1_HEXSZ + 1]; + char hex[GIT_MAX_HEXSZ + 1]; oid_to_hex_r(hex, &suspect->commit->object.oid); printf("%s %d %d %d\n", @@ -1928,7 +1928,7 @@ static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt) const char *cp; struct origin *suspect = ent->suspect; struct commit_info ci; - char hex[GIT_SHA1_HEXSZ + 1]; + char hex[GIT_MAX_HEXSZ + 1]; int show_raw_time = !!(opt & OUTPUT_RAW_TIMESTAMP); get_commit_info(suspect->commit, &ci, 1); diff --git a/builtin/branch.c b/builtin/branch.c index 52688f2e1b..0552c42ad1 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -562,7 +562,9 @@ int cmd_branch(int argc, const char **argv, const char *prefix) OPT_SET_INT('r', "remotes", &filter.kind, N_("act on remote-tracking branches"), FILTER_REFS_REMOTES), OPT_CONTAINS(&filter.with_commit, N_("print only branches that contain the commit")), + OPT_NO_CONTAINS(&filter.no_commit, N_("print only branches that don't contain the commit")), OPT_WITH(&filter.with_commit, N_("print only branches that contain the commit")), + OPT_WITHOUT(&filter.no_commit, N_("print only branches that don't contain the commit")), OPT__ABBREV(&filter.abbrev), OPT_GROUP(N_("Specific git-branch actions:")), @@ -618,7 +620,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix) if (!delete && !rename && !edit_description && !new_upstream && !unset_upstream && argc == 0) list = 1; - if (filter.with_commit || filter.merge != REF_FILTER_MERGED_NONE || filter.points_at.nr) + if (filter.with_commit || filter.merge != REF_FILTER_MERGED_NONE || filter.points_at.nr || + filter.no_commit) list = 1; if (!!delete + !!rename + !!new_upstream + diff --git a/builtin/bundle.c b/builtin/bundle.c index 4883a435a9..d0de59b94f 100644 --- a/builtin/bundle.c +++ b/builtin/bundle.c @@ -20,21 +20,15 @@ int cmd_bundle(int argc, const char **argv, const char *prefix) struct bundle_header header; const char *cmd, *bundle_file; int bundle_fd = -1; - char buffer[PATH_MAX]; if (argc < 3) usage(builtin_bundle_usage); cmd = argv[1]; - bundle_file = argv[2]; + bundle_file = prefix_filename(prefix, argv[2]); argc -= 2; argv += 2; - if (prefix && bundle_file[0] != '/') { - snprintf(buffer, sizeof(buffer), "%s/%s", prefix, bundle_file); - bundle_file = buffer; - } - memset(&header, 0, sizeof(header)); if (strcmp(cmd, "create") && (bundle_fd = read_bundle_header(bundle_file, &header)) < 0) diff --git a/builtin/cat-file.c b/builtin/cat-file.c index 8b85cb8cf0..1890d7a639 100644 --- a/builtin/cat-file.c +++ b/builtin/cat-file.c @@ -401,10 +401,10 @@ struct object_cb_data { struct expand_data *expand; }; -static int batch_object_cb(const unsigned char sha1[20], void *vdata) +static int batch_object_cb(const struct object_id *oid, void *vdata) { struct object_cb_data *data = vdata; - hashcpy(data->expand->oid.hash, sha1); + oidcpy(&data->expand->oid, oid); batch_object_write(NULL, data->opt, data->expand); return 0; } @@ -413,7 +413,7 @@ static int batch_loose_object(const struct object_id *oid, const char *path, void *data) { - sha1_array_append(data, oid->hash); + oid_array_append(data, oid); return 0; } @@ -422,7 +422,7 @@ static int batch_packed_object(const struct object_id *oid, uint32_t pos, void *data) { - sha1_array_append(data, oid->hash); + oid_array_append(data, oid); return 0; } @@ -462,7 +462,7 @@ static int batch_objects(struct batch_options *opt) data.info.typep = &data.type; if (opt->all_objects) { - struct sha1_array sa = SHA1_ARRAY_INIT; + struct oid_array sa = OID_ARRAY_INIT; struct object_cb_data cb; for_each_loose_object(batch_loose_object, &sa, 0); @@ -470,9 +470,9 @@ static int batch_objects(struct batch_options *opt) cb.opt = opt; cb.expand = &data; - sha1_array_for_each_unique(&sa, batch_object_cb, &cb); + oid_array_for_each_unique(&sa, batch_object_cb, &cb); - sha1_array_clear(&sa); + oid_array_clear(&sa); return 0; } diff --git a/builtin/checkout.c b/builtin/checkout.c index 81f07c3ef2..bfa5419f33 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -21,12 +21,31 @@ #include "submodule-config.h" #include "submodule.h" +static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT; + static const char * const checkout_usage[] = { N_("git checkout [<options>] <branch>"), N_("git checkout [<options>] [<branch>] -- <file>..."), NULL, }; +static int option_parse_recurse_submodules(const struct option *opt, + const char *arg, int unset) +{ + if (unset) { + recurse_submodules = RECURSE_SUBMODULES_OFF; + return 0; + } + if (arg) + recurse_submodules = + parse_update_recurse_submodules_arg(opt->long_name, + arg); + else + recurse_submodules = RECURSE_SUBMODULES_ON; + + return 0; +} + struct checkout_opts { int patch_mode; int quiet; @@ -889,11 +908,10 @@ static int check_tracking_name(struct remote *remote, void *cb_data) static const char *unique_tracking_name(const char *name, struct object_id *oid) { struct tracking_name_data cb_data = { NULL, NULL, NULL, 1 }; - char src_ref[PATH_MAX]; - snprintf(src_ref, PATH_MAX, "refs/heads/%s", name); - cb_data.src_ref = src_ref; + cb_data.src_ref = xstrfmt("refs/heads/%s", name); cb_data.dst_oid = oid; for_each_remote(check_tracking_name, &cb_data); + free(cb_data.src_ref); if (cb_data.unique) return cb_data.dst_ref; free(cb_data.dst_ref); @@ -1163,6 +1181,9 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) N_("second guess 'git checkout <no-such-branch>'")), OPT_BOOL(0, "ignore-other-worktrees", &opts.ignore_other_worktrees, N_("do not check if another worktree is holding the given ref")), + { OPTION_CALLBACK, 0, "recurse-submodules", &recurse_submodules, + "checkout", "control recursive updating of submodules", + PARSE_OPT_OPTARG, option_parse_recurse_submodules }, OPT_BOOL(0, "progress", &opts.show_progress, N_("force progress reporting")), OPT_END(), }; @@ -1193,6 +1214,12 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) git_xmerge_config("merge.conflictstyle", conflict_style, NULL); } + if (recurse_submodules != RECURSE_SUBMODULES_OFF) { + git_config(submodule_config, NULL); + if (recurse_submodules != RECURSE_SUBMODULES_DEFAULT) + set_config_update_recurse_submodules(recurse_submodules); + } + if ((!!opts.new_branch + !!opts.new_branch_force + !!opts.new_orphan_branch) > 1) die(_("-b, -B and --orphan are mutually exclusive")); diff --git a/builtin/clone.c b/builtin/clone.c index b4c929bb8a..de85b85254 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -39,7 +39,7 @@ static const char * const builtin_clone_usage[] = { }; static int option_no_checkout, option_bare, option_mirror, option_single_branch = -1; -static int option_local = -1, option_no_hardlinks, option_shared, option_recursive; +static int option_local = -1, option_no_hardlinks, option_shared; static int option_shallow_submodules; static int deepen; static char *option_template, *option_depth, *option_since; @@ -56,6 +56,21 @@ static struct string_list option_required_reference = STRING_LIST_INIT_NODUP; static struct string_list option_optional_reference = STRING_LIST_INIT_NODUP; static int option_dissociate; static int max_jobs = -1; +static struct string_list option_recurse_submodules = STRING_LIST_INIT_NODUP; + +static int recurse_submodules_cb(const struct option *opt, + const char *arg, int unset) +{ + if (unset) + string_list_clear((struct string_list *)opt->value, 0); + else if (arg) + string_list_append((struct string_list *)opt->value, arg); + else + string_list_append((struct string_list *)opt->value, + (const char *)opt->defval); + + return 0; +} static struct option builtin_clone_options[] = { OPT__VERBOSITY(&option_verbosity), @@ -74,10 +89,13 @@ static struct option builtin_clone_options[] = { N_("don't use local hardlinks, always copy")), OPT_BOOL('s', "shared", &option_shared, N_("setup as shared repository")), - OPT_BOOL(0, "recursive", &option_recursive, - N_("initialize submodules in the clone")), - OPT_BOOL(0, "recurse-submodules", &option_recursive, - N_("initialize submodules in the clone")), + { OPTION_CALLBACK, 0, "recursive", &option_recurse_submodules, + N_("pathspec"), N_("initialize submodules in the clone"), + PARSE_OPT_OPTARG | PARSE_OPT_HIDDEN, recurse_submodules_cb, + (intptr_t)"." }, + { OPTION_CALLBACK, 0, "recurse-submodules", &option_recurse_submodules, + N_("pathspec"), N_("initialize submodules in the clone"), + PARSE_OPT_OPTARG, recurse_submodules_cb, (intptr_t)"." }, OPT_INTEGER('j', "jobs", &max_jobs, N_("number of submodules cloned in parallel")), OPT_STRING(0, "template", &option_template, N_("template-directory"), @@ -733,7 +751,7 @@ static int checkout(int submodule_progress) err |= run_hook_le(NULL, "post-checkout", sha1_to_hex(null_sha1), oid_to_hex(&oid), "1", NULL); - if (!err && option_recursive) { + if (!err && (option_recurse_submodules.nr > 0)) { struct argv_array args = ARGV_ARRAY_INIT; argv_array_pushl(&args, "submodule", "update", "--init", "--recursive", NULL); @@ -957,7 +975,25 @@ int cmd_clone(int argc, const char **argv, const char *prefix) fprintf(stderr, _("Cloning into '%s'...\n"), dir); } - if (option_recursive) { + if (option_recurse_submodules.nr > 0) { + struct string_list_item *item; + struct strbuf sb = STRBUF_INIT; + + /* remove duplicates */ + string_list_sort(&option_recurse_submodules); + string_list_remove_duplicates(&option_recurse_submodules, 0); + + /* + * NEEDSWORK: In a multi-working-tree world, this needs to be + * set in the per-worktree config. + */ + for_each_string_list_item(item, &option_recurse_submodules) { + strbuf_addf(&sb, "submodule.active=%s", + item->string); + string_list_append(&option_config, + strbuf_detach(&sb, NULL)); + } + if (option_required_reference.nr && option_optional_reference.nr) die(_("clone --recursive is not compatible with " diff --git a/builtin/config.c b/builtin/config.c index 05843a0f96..4f49a0edb9 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -527,9 +527,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) else if (given_config_source.file) { if (!is_absolute_path(given_config_source.file) && prefix) given_config_source.file = - xstrdup(prefix_filename(prefix, - strlen(prefix), - given_config_source.file)); + prefix_filename(prefix, given_config_source.file); } if (respect_includes == -1) diff --git a/builtin/describe.c b/builtin/describe.c index 76c18059bf..a5cd8c513f 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -9,6 +9,7 @@ #include "diff.h" #include "hashmap.h" #include "argv-array.h" +#include "run-command.h" #define SEEN (1u << 0) #define MAX_TAGS (FLAG_BITS - 1) @@ -31,7 +32,7 @@ static int have_util; static struct string_list patterns = STRING_LIST_INIT_NODUP; static struct string_list exclude_patterns = STRING_LIST_INIT_NODUP; static int always; -static const char *dirty; +static const char *suffix, *dirty, *broken; /* diff-index command arguments to check if working tree is dirty. */ static const char *diff_index_args[] = { @@ -49,7 +50,7 @@ struct commit_name { }; static const char *prio_names[] = { - "head", "lightweight", "annotated", + N_("head"), N_("lightweight"), N_("annotated"), }; static int commit_name_cmp(const struct commit_name *cn1, @@ -292,8 +293,8 @@ static void describe(const char *arg, int last_one) display_name(n); if (longformat) show_suffix(0, n->tag ? &n->tag->tagged->oid : &oid); - if (dirty) - printf("%s", dirty); + if (suffix) + printf("%s", suffix); printf("\n"); return; } @@ -369,8 +370,8 @@ static void describe(const char *arg, int last_one) struct object_id *oid = &cmit->object.oid; if (always) { printf("%s", find_unique_abbrev(oid->hash, abbrev)); - if (dirty) - printf("%s", dirty); + if (suffix) + printf("%s", suffix); printf("\n"); return; } @@ -394,10 +395,19 @@ static void describe(const char *arg, int last_one) free_commit_list(list); if (debug) { + static int label_width = -1; + if (label_width < 0) { + int i, w; + for (i = 0; i < ARRAY_SIZE(prio_names); i++) { + w = strlen(_(prio_names[i])); + if (label_width < w) + label_width = w; + } + } for (cur_match = 0; cur_match < match_cnt; cur_match++) { struct possible_tag *t = &all_matches[cur_match]; - fprintf(stderr, " %-11s %8d %s\n", - prio_names[t->name->prio], + fprintf(stderr, " %-*s %8d %s\n", + label_width, _(prio_names[t->name->prio]), t->depth, t->name->path); } fprintf(stderr, _("traversed %lu commits\n"), seen_commits); @@ -413,8 +423,8 @@ static void describe(const char *arg, int last_one) display_name(all_matches[0].name); if (abbrev) show_suffix(all_matches[0].depth, &cmit->object.oid); - if (dirty) - printf("%s", dirty); + if (suffix) + printf("%s", suffix); printf("\n"); if (!last_one) @@ -445,6 +455,9 @@ int cmd_describe(int argc, const char **argv, const char *prefix) {OPTION_STRING, 0, "dirty", &dirty, N_("mark"), N_("append <mark> on dirty working tree (default: \"-dirty\")"), PARSE_OPT_OPTARG, NULL, (intptr_t) "-dirty"}, + {OPTION_STRING, 0, "broken", &broken, N_("mark"), + N_("append <mark> on broken working tree (default: \"-broken\")"), + PARSE_OPT_OPTARG, NULL, (intptr_t) "-broken"}, OPT_END(), }; @@ -493,7 +506,28 @@ int cmd_describe(int argc, const char **argv, const char *prefix) die(_("No names found, cannot describe anything.")); if (argc == 0) { - if (dirty) { + if (broken) { + struct child_process cp = CHILD_PROCESS_INIT; + argv_array_pushv(&cp.args, diff_index_args); + cp.git_cmd = 1; + cp.no_stdin = 1; + cp.no_stdout = 1; + + if (!dirty) + dirty = "-dirty"; + + switch (run_command(&cp)) { + case 0: + suffix = NULL; + break; + case 1: + suffix = dirty; + break; + default: + /* diff-index aborted abnormally */ + suffix = broken; + } + } else if (dirty) { static struct lock_file index_lock; int fd; @@ -506,11 +540,15 @@ int cmd_describe(int argc, const char **argv, const char *prefix) if (!cmd_diff_index(ARRAY_SIZE(diff_index_args) - 1, diff_index_args, prefix)) - dirty = NULL; + suffix = NULL; + else + suffix = dirty; } describe("HEAD", 1); } else if (dirty) { die(_("--dirty is incompatible with commit-ishes")); + } else if (broken) { + die(_("--broken is incompatible with commit-ishes")); } else { while (argc-- > 0) describe(*argv++, argc == 0); diff --git a/builtin/diff.c b/builtin/diff.c index 3d64b85337..d184aafab9 100644 --- a/builtin/diff.c +++ b/builtin/diff.c @@ -21,7 +21,7 @@ #define DIFF_NO_INDEX_IMPLICIT 2 struct blobinfo { - unsigned char sha1[20]; + struct object_id oid; const char *name; unsigned mode; }; @@ -31,22 +31,22 @@ static const char builtin_diff_usage[] = static void stuff_change(struct diff_options *opt, unsigned old_mode, unsigned new_mode, - const unsigned char *old_sha1, - const unsigned char *new_sha1, - int old_sha1_valid, - int new_sha1_valid, + const struct object_id *old_oid, + const struct object_id *new_oid, + int old_oid_valid, + int new_oid_valid, const char *old_name, const char *new_name) { struct diff_filespec *one, *two; - if (!is_null_sha1(old_sha1) && !is_null_sha1(new_sha1) && - !hashcmp(old_sha1, new_sha1) && (old_mode == new_mode)) + if (!is_null_oid(old_oid) && !is_null_oid(new_oid) && + !oidcmp(old_oid, new_oid) && (old_mode == new_mode)) return; if (DIFF_OPT_TST(opt, REVERSE_DIFF)) { SWAP(old_mode, new_mode); - SWAP(old_sha1, new_sha1); + SWAP(old_oid, new_oid); SWAP(old_name, new_name); } @@ -57,8 +57,8 @@ static void stuff_change(struct diff_options *opt, one = alloc_filespec(old_name); two = alloc_filespec(new_name); - fill_filespec(one, old_sha1, old_sha1_valid, old_mode); - fill_filespec(two, new_sha1, new_sha1_valid, new_mode); + fill_filespec(one, old_oid->hash, old_oid_valid, old_mode); + fill_filespec(two, new_oid->hash, new_oid_valid, new_mode); diff_queue(&diff_queued_diff, one, two); } @@ -89,7 +89,7 @@ static int builtin_diff_b_f(struct rev_info *revs, stuff_change(&revs->diffopt, blob[0].mode, canon_mode(st.st_mode), - blob[0].sha1, null_sha1, + &blob[0].oid, &null_oid, 1, 0, path, path); diffcore_std(&revs->diffopt); @@ -114,7 +114,7 @@ static int builtin_diff_blobs(struct rev_info *revs, stuff_change(&revs->diffopt, blob[0].mode, blob[1].mode, - blob[0].sha1, blob[1].sha1, + &blob[0].oid, &blob[1].oid, 1, 1, blob[0].name, blob[1].name); diffcore_std(&revs->diffopt); @@ -160,7 +160,7 @@ static int builtin_diff_tree(struct rev_info *revs, struct object_array_entry *ent0, struct object_array_entry *ent1) { - const unsigned char *(sha1[2]); + const struct object_id *(oid[2]); int swap = 0; if (argc > 1) @@ -172,9 +172,9 @@ static int builtin_diff_tree(struct rev_info *revs, */ if (ent1->item->flags & UNINTERESTING) swap = 1; - sha1[swap] = ent0->item->oid.hash; - sha1[1 - swap] = ent1->item->oid.hash; - diff_tree_sha1(sha1[0], sha1[1], "", &revs->diffopt); + oid[swap] = &ent0->item->oid; + oid[1 - swap] = &ent1->item->oid; + diff_tree_sha1(oid[0]->hash, oid[1]->hash, "", &revs->diffopt); log_tree_diff_flush(revs); return 0; } @@ -184,7 +184,7 @@ static int builtin_diff_combined(struct rev_info *revs, struct object_array_entry *ent, int ents) { - struct sha1_array parents = SHA1_ARRAY_INIT; + struct oid_array parents = OID_ARRAY_INIT; int i; if (argc > 1) @@ -193,10 +193,10 @@ static int builtin_diff_combined(struct rev_info *revs, if (!revs->dense_combined_merges && !revs->combine_merges) revs->dense_combined_merges = revs->combine_merges = 1; for (i = 1; i < ents; i++) - sha1_array_append(&parents, ent[i].item->oid.hash); + oid_array_append(&parents, &ent[i].item->oid); diff_tree_combined(ent[0].item->oid.hash, &parents, revs->dense_combined_merges, revs); - sha1_array_clear(&parents); + oid_array_clear(&parents); return 0; } @@ -408,7 +408,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix) } else if (obj->type == OBJ_BLOB) { if (2 <= blobs) die(_("more than two blobs given: '%s'"), name); - hashcpy(blob[blobs].sha1, obj->oid.hash); + hashcpy(blob[blobs].oid.hash, obj->oid.hash); blob[blobs].name = name; blob[blobs].mode = entry->mode; blobs++; diff --git a/builtin/difftool.c b/builtin/difftool.c index d13350ce83..1354d0e462 100644 --- a/builtin/difftool.c +++ b/builtin/difftool.c @@ -254,6 +254,62 @@ static int ensure_leading_directories(char *path) } } +/* + * Unconditional writing of a plain regular file is what + * "git difftool --dir-diff" wants to do for symlinks. We are preparing two + * temporary directories to be fed to a Git-unaware tool that knows how to + * show a diff of two directories (e.g. "diff -r A B"). + * + * Because the tool is Git-unaware, if a symbolic link appears in either of + * these temporary directories, it will try to dereference and show the + * difference of the target of the symbolic link, which is not what we want, + * as the goal of the dir-diff mode is to produce an output that is logically + * equivalent to what "git diff" produces. + * + * Most importantly, we want to get textual comparison of the result of the + * readlink(2). get_symlink() provides that---it returns the contents of + * the symlink that gets written to a regular file to force the external tool + * to compare the readlink(2) result as text, even on a filesystem that is + * capable of doing a symbolic link. + */ +static char *get_symlink(const struct object_id *oid, const char *path) +{ + char *data; + if (is_null_oid(oid)) { + /* The symlink is unknown to Git so read from the filesystem */ + struct strbuf link = STRBUF_INIT; + if (has_symlinks) { + if (strbuf_readlink(&link, path, strlen(path))) + die(_("could not read symlink %s"), path); + } else if (strbuf_read_file(&link, path, 128)) + die(_("could not read symlink file %s"), path); + + data = strbuf_detach(&link, NULL); + } else { + enum object_type type; + unsigned long size; + data = read_sha1_file(oid->hash, &type, &size); + if (!data) + die(_("could not read object %s for symlink %s"), + oid_to_hex(oid), path); + } + + return data; +} + +static int checkout_path(unsigned mode, struct object_id *oid, + const char *path, const struct checkout *state) +{ + struct cache_entry *ce; + int ret; + + ce = make_cache_entry(mode, oid->hash, path, 0, 0); + ret = checkout_entry(ce, state, NULL); + + free(ce); + return ret; +} + static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix, int argc, const char **argv) { @@ -262,16 +318,14 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix, struct strbuf rpath = STRBUF_INIT, buf = STRBUF_INIT; struct strbuf ldir = STRBUF_INIT, rdir = STRBUF_INIT; struct strbuf wtdir = STRBUF_INIT; + char *lbase_dir, *rbase_dir; size_t ldir_len, rdir_len, wtdir_len; - struct cache_entry *ce = xcalloc(1, sizeof(ce) + PATH_MAX + 1); const char *workdir, *tmp; int ret = 0, i; FILE *fp; struct hashmap working_tree_dups, submodules, symlinks2; struct hashmap_iter iter; struct pair_entry *entry; - enum object_type type; - unsigned long size; struct index_state wtindex; struct checkout lstate, rstate; int rc, flags = RUN_GIT_CMD, err = 0; @@ -298,11 +352,11 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix, memset(&wtindex, 0, sizeof(wtindex)); memset(&lstate, 0, sizeof(lstate)); - lstate.base_dir = ldir.buf; + lstate.base_dir = lbase_dir = xstrdup(ldir.buf); lstate.base_dir_len = ldir.len; lstate.force = 1; memset(&rstate, 0, sizeof(rstate)); - rstate.base_dir = rdir.buf; + rstate.base_dir = rbase_dir = xstrdup(rdir.buf); rstate.base_dir_len = rdir.len; rstate.force = 1; @@ -336,7 +390,6 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix, struct object_id loid, roid; char status; const char *src_path, *dst_path; - size_t src_path_len, dst_path_len; if (starts_with(info.buf, "::")) die(N_("combined diff formats('-c' and '--cc') are " @@ -349,17 +402,14 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix, if (strbuf_getline_nul(&lpath, fp)) break; src_path = lpath.buf; - src_path_len = lpath.len; i++; if (status != 'C' && status != 'R') { dst_path = src_path; - dst_path_len = src_path_len; } else { if (strbuf_getline_nul(&rpath, fp)) break; dst_path = rpath.buf; - dst_path_len = rpath.len; } if (S_ISGITLINK(lmode) || S_ISGITLINK(rmode)) { @@ -377,27 +427,23 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix, } if (S_ISLNK(lmode)) { - char *content = read_sha1_file(loid.hash, &type, &size); + char *content = get_symlink(&loid, src_path); add_left_or_right(&symlinks2, src_path, content, 0); free(content); } if (S_ISLNK(rmode)) { - char *content = read_sha1_file(roid.hash, &type, &size); + char *content = get_symlink(&roid, dst_path); add_left_or_right(&symlinks2, dst_path, content, 1); free(content); } if (lmode && status != 'C') { - ce->ce_mode = lmode; - oidcpy(&ce->oid, &loid); - strcpy(ce->name, src_path); - ce->ce_namelen = src_path_len; - if (checkout_entry(ce, &lstate, NULL)) + if (checkout_path(lmode, &loid, src_path, &lstate)) return error("could not write '%s'", src_path); } - if (rmode) { + if (rmode && !S_ISLNK(rmode)) { struct working_tree_entry *entry; /* Avoid duplicate working_tree entries */ @@ -410,11 +456,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix, hashmap_add(&working_tree_dups, entry); if (!use_wt_file(workdir, dst_path, &roid)) { - ce->ce_mode = rmode; - oidcpy(&ce->oid, &roid); - strcpy(ce->name, dst_path); - ce->ce_namelen = dst_path_len; - if (checkout_entry(ce, &rstate, NULL)) + if (checkout_path(rmode, &roid, dst_path, &rstate)) return error("could not write '%s'", dst_path); } else if (!is_null_oid(&roid)) { @@ -584,7 +626,8 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix, exit_cleanup(tmpdir, rc); finish: - free(ce); + free(lbase_dir); + free(rbase_dir); strbuf_release(&ldir); strbuf_release(&rdir); strbuf_release(&wtdir); diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c index 2a1c1c213f..366b9d13f9 100644 --- a/builtin/fetch-pack.c +++ b/builtin/fetch-pack.c @@ -50,7 +50,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix) char **pack_lockfile_ptr = NULL; struct child_process *conn; struct fetch_pack_args args; - struct sha1_array shallow = SHA1_ARRAY_INIT; + struct oid_array shallow = OID_ARRAY_INIT; struct string_list deepen_not = STRING_LIST_INIT_DUP; packet_trace_identity("fetch-pack"); diff --git a/builtin/fetch.c b/builtin/fetch.c index b5ad09d046..5f2c2ab23e 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -421,7 +421,7 @@ static int s_update_ref(const char *action, struct ref *ref, int check_old) { - char msg[1024]; + char *msg; char *rla = getenv("GIT_REFLOG_ACTION"); struct ref_transaction *transaction; struct strbuf err = STRBUF_INIT; @@ -431,7 +431,7 @@ static int s_update_ref(const char *action, return 0; if (!rla) rla = default_rla.buf; - snprintf(msg, sizeof(msg), "%s: %s", rla, action); + msg = xstrfmt("%s: %s", rla, action); transaction = ref_transaction_begin(&err); if (!transaction || @@ -449,11 +449,13 @@ static int s_update_ref(const char *action, ref_transaction_free(transaction); strbuf_release(&err); + free(msg); return 0; fail: ref_transaction_free(transaction); error("%s", err.buf); strbuf_release(&err); + free(msg); return df_conflict ? STORE_REF_ERROR_DF_CONFLICT : STORE_REF_ERROR_OTHER; } @@ -659,7 +661,7 @@ static int update_local_ref(struct ref *ref, if ((recurse_submodules != RECURSE_SUBMODULES_OFF) && (recurse_submodules != RECURSE_SUBMODULES_ON)) - check_for_new_submodule_commits(ref->new_oid.hash); + check_for_new_submodule_commits(&ref->new_oid); r = s_update_ref(msg, ref, 0); format_display(display, r ? '!' : '*', what, r ? _("unable to update local ref") : NULL, @@ -675,7 +677,7 @@ static int update_local_ref(struct ref *ref, strbuf_add_unique_abbrev(&quickref, ref->new_oid.hash, DEFAULT_ABBREV); if ((recurse_submodules != RECURSE_SUBMODULES_OFF) && (recurse_submodules != RECURSE_SUBMODULES_ON)) - check_for_new_submodule_commits(ref->new_oid.hash); + check_for_new_submodule_commits(&ref->new_oid); r = s_update_ref("fast-forward", ref, 1); format_display(display, r ? '!' : ' ', quickref.buf, r ? _("unable to update local ref") : NULL, @@ -690,7 +692,7 @@ static int update_local_ref(struct ref *ref, strbuf_add_unique_abbrev(&quickref, ref->new_oid.hash, DEFAULT_ABBREV); if ((recurse_submodules != RECURSE_SUBMODULES_OFF) && (recurse_submodules != RECURSE_SUBMODULES_ON)) - check_for_new_submodule_commits(ref->new_oid.hash); + check_for_new_submodule_commits(&ref->new_oid); r = s_update_ref("forced-update", ref, 1); format_display(display, r ? '!' : '+', quickref.buf, r ? _("unable to update local ref") : _("forced update"), diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c index df41fa0350..eca365bf89 100644 --- a/builtin/for-each-ref.c +++ b/builtin/for-each-ref.c @@ -8,8 +8,8 @@ static char const * const for_each_ref_usage[] = { N_("git for-each-ref [<options>] [<pattern>]"), N_("git for-each-ref [--points-at <object>]"), - N_("git for-each-ref [(--merged | --no-merged) [<object>]]"), - N_("git for-each-ref [--contains [<object>]]"), + N_("git for-each-ref [(--merged | --no-merged) [<commit>]]"), + N_("git for-each-ref [--contains [<commit>]] [--no-contains [<commit>]]"), NULL }; @@ -43,6 +43,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix) OPT_MERGED(&filter, N_("print only refs that are merged")), OPT_NO_MERGED(&filter, N_("print only refs that are not merged")), OPT_CONTAINS(&filter.with_commit, N_("print only refs which contain the commit")), + OPT_NO_CONTAINS(&filter.no_commit, N_("print only refs which don't contain the commit")), OPT_BOOL(0, "ignore-case", &icase, N_("sorting and filtering are case insensitive")), OPT_END(), }; diff --git a/builtin/gc.c b/builtin/gc.c index c2c61a57bb..2daede7820 100644 --- a/builtin/gc.c +++ b/builtin/gc.c @@ -135,8 +135,6 @@ static int too_many_loose_objects(void) * distributed, we can check only one and get a reasonable * estimate. */ - char path[PATH_MAX]; - const char *objdir = get_object_directory(); DIR *dir; struct dirent *ent; int auto_threshold; @@ -146,11 +144,7 @@ static int too_many_loose_objects(void) if (gc_auto_threshold <= 0) return 0; - if (sizeof(path) <= snprintf(path, sizeof(path), "%s/17", objdir)) { - warning(_("insanely long object directory %.*s"), 50, objdir); - return 0; - } - dir = opendir(path); + dir = opendir(git_path("objects/17")); if (!dir) return 0; diff --git a/builtin/grep.c b/builtin/grep.c index 837836fb3e..65070c52fc 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -310,10 +310,7 @@ static int grep_oid(struct grep_opt *opt, const struct object_id *oid, { struct strbuf pathbuf = STRBUF_INIT; - 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 if (super_prefix) { + if (super_prefix) { strbuf_add(&pathbuf, filename, tree_name_len); strbuf_addstr(&pathbuf, super_prefix); strbuf_addstr(&pathbuf, filename + tree_name_len); @@ -321,6 +318,13 @@ static int grep_oid(struct grep_opt *opt, const struct object_id *oid, 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_SHA1, pathbuf.buf, path, oid); @@ -345,12 +349,14 @@ 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) { - quote_path_relative(filename, opt->prefix, &buf); - } else { - if (super_prefix) - strbuf_addstr(&buf, super_prefix); - strbuf_addstr(&buf, filename); + char *name = strbuf_detach(&buf, NULL); + quote_path_relative(name, opt->prefix, &buf); + free(name); } #ifndef NO_PTHREADS @@ -399,13 +405,12 @@ static void run_pager(struct grep_opt *opt, const char *prefix) } static void compile_submodule_options(const struct grep_opt *opt, - const struct pathspec *pathspec, + const char **argv, int cached, int untracked, int opt_exclude, int use_index, int pattern_type_arg) { struct grep_pat *pattern; - int i; if (recurse_submodules) argv_array_push(&submodule_options, "--recurse-submodules"); @@ -523,9 +528,8 @@ static void compile_submodule_options(const struct grep_opt *opt, /* Add Pathspecs */ argv_array_push(&submodule_options, "--"); - for (i = 0; i < pathspec->nr; i++) - argv_array_push(&submodule_options, - pathspec->items[i].original); + for (; *argv; argv++) + argv_array_push(&submodule_options, *argv); } /* @@ -538,7 +542,7 @@ static int grep_submodule_launch(struct grep_opt *opt, int status, i; const char *end_of_base; const char *name; - struct work_item *w = opt->output_priv; + struct strbuf child_output = STRBUF_INIT; end_of_base = strchr(gs->name, ':'); if (gs->identifier && end_of_base) @@ -549,6 +553,11 @@ static int grep_submodule_launch(struct grep_opt *opt, prepare_submodule_repo_env(&cp.env_array); argv_array_push(&cp.env_array, GIT_DIR_ENVIRONMENT); + if (opt->relative && opt->prefix_length) + argv_array_pushf(&cp.env_array, "%s=%s", + GIT_TOPLEVEL_PREFIX_ENVIRONMENT, + opt->prefix); + /* Add super prefix */ argv_array_pushf(&cp.args, "--super-prefix=%s%s/", super_prefix ? super_prefix : "", @@ -593,14 +602,16 @@ static int grep_submodule_launch(struct grep_opt *opt, * child process. A '0' indicates a hit, a '1' indicates no hit and * anything else is an error. */ - status = capture_command(&cp, &w->out, 0); + status = capture_command(&cp, &child_output, 0); if (status && (status != 1)) { /* flush the buffer */ - write_or_die(1, w->out.buf, w->out.len); + write_or_die(1, child_output.buf, child_output.len); die("process for submodule '%s' failed with exit code: %d", gs->name, status); } + 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; } @@ -616,7 +627,7 @@ static int grep_submodule(struct grep_opt *opt, const unsigned char *sha1, { if (!is_submodule_initialized(path)) return 0; - if (!is_submodule_populated(path)) { + if (!is_submodule_populated_gently(path, NULL)) { /* * If searching history, check for the presense of the * submodule's gitdir before skipping the submodule. @@ -641,19 +652,14 @@ static int grep_submodule(struct grep_opt *opt, const unsigned char *sha1, } else #endif { - struct work_item w; + struct grep_source gs; int hit; - grep_source_init(&w.source, GREP_SOURCE_SUBMODULE, + grep_source_init(&gs, GREP_SOURCE_SUBMODULE, filename, path, sha1); - strbuf_init(&w.out, 0); - opt->output_priv = &w; - hit = grep_submodule_launch(opt, &w.source); - - write_or_die(1, w.out.buf, w.out.len); + hit = grep_submodule_launch(opt, &gs); - grep_source_clear(&w.source); - strbuf_release(&w.out); + grep_source_clear(&gs); return hit; } } @@ -979,7 +985,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) OPT_SET_INT(0, "exclude-standard", &opt_exclude, N_("ignore files specified via '.gitignore'"), 1), OPT_BOOL(0, "recurse-submodules", &recurse_submodules, - N_("recursivley search in each submodule")), + N_("recursively search in each submodule")), OPT_STRING(0, "parent-basename", &parent_basename, N_("basename"), N_("prepend parent project's basename to output")), @@ -1236,7 +1242,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (recurse_submodules) { gitmodules_config(); - compile_submodule_options(&opt, &pathspec, cached, untracked, + compile_submodule_options(&opt, argv + i, cached, untracked, opt_exclude, use_index, pattern_type_arg); } diff --git a/builtin/hash-object.c b/builtin/hash-object.c index 9028e1fdcc..bbeaf20bcc 100644 --- a/builtin/hash-object.c +++ b/builtin/hash-object.c @@ -102,7 +102,6 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix) OPT_END() }; int i; - int prefix_length = -1; const char *errstr = NULL; argc = parse_options(argc, argv, NULL, hash_object_options, @@ -113,9 +112,8 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix) else prefix = setup_git_directory_gently(&nongit); - prefix_length = prefix ? strlen(prefix) : 0; if (vpath && prefix) - vpath = prefix_filename(prefix, prefix_length, vpath); + vpath = xstrdup(prefix_filename(prefix, vpath)); git_config(git_default_config, NULL); @@ -144,11 +142,13 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix) for (i = 0 ; i < argc; i++) { const char *arg = argv[i]; + char *to_free = NULL; - if (0 <= prefix_length) - arg = prefix_filename(prefix, prefix_length, arg); + if (prefix) + arg = to_free = prefix_filename(prefix, arg); hash_object(arg, type, no_filters ? NULL : vpath ? vpath : arg, flags, literally); + free(to_free); } if (stdin_paths) diff --git a/builtin/index-pack.c b/builtin/index-pack.c index f4b87c6c9f..4ff567db47 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -307,14 +307,15 @@ static const char *open_pack_file(const char *pack_name) if (from_stdin) { input_fd = 0; if (!pack_name) { - static char tmp_file[PATH_MAX]; - output_fd = odb_mkstemp(tmp_file, sizeof(tmp_file), + struct strbuf tmp_file = STRBUF_INIT; + output_fd = odb_mkstemp(&tmp_file, "pack/tmp_pack_XXXXXX"); - pack_name = xstrdup(tmp_file); - } else + pack_name = strbuf_detach(&tmp_file, NULL); + } else { output_fd = open(pack_name, O_CREAT|O_EXCL|O_RDWR, 0600); - if (output_fd < 0) - die_errno(_("unable to create '%s'"), pack_name); + if (output_fd < 0) + die_errno(_("unable to create '%s'"), pack_name); + } nothread_data.pack_fd = output_fd; } else { input_fd = open(pack_name, O_RDONLY); @@ -809,6 +810,8 @@ static void sha1_object(const void *data, struct object_entry *obj_entry, unsigned long has_size; read_lock(); has_type = sha1_object_info(sha1, &has_size); + if (has_type < 0) + die(_("cannot read existing object info %s"), sha1_to_hex(sha1)); if (has_type != type || has_size != size) die(_("SHA1 COLLISION FOUND WITH %s !"), sha1_to_hex(sha1)); has_data = read_sha1_file(sha1, &has_type, &has_size); @@ -1386,7 +1389,9 @@ static void final(const char *final_pack_name, const char *curr_pack_name, unsigned char *sha1) { const char *report = "pack"; - char name[PATH_MAX]; + struct strbuf pack_name = STRBUF_INIT; + struct strbuf index_name = STRBUF_INIT; + struct strbuf keep_name_buf = STRBUF_INIT; int err; if (!from_stdin) { @@ -1402,14 +1407,13 @@ static void final(const char *final_pack_name, const char *curr_pack_name, int keep_fd, keep_msg_len = strlen(keep_msg); if (!keep_name) - keep_fd = odb_pack_keep(name, sizeof(name), sha1); - else - keep_fd = open(keep_name, O_RDWR|O_CREAT|O_EXCL, 0600); + keep_name = odb_pack_name(&keep_name_buf, sha1, "keep"); + keep_fd = odb_pack_keep(keep_name); if (keep_fd < 0) { if (errno != EEXIST) die_errno(_("cannot write keep file '%s'"), - keep_name ? keep_name : name); + keep_name); } else { if (keep_msg_len > 0) { write_or_die(keep_fd, keep_msg, keep_msg_len); @@ -1417,28 +1421,22 @@ static void final(const char *final_pack_name, const char *curr_pack_name, } if (close(keep_fd) != 0) die_errno(_("cannot close written keep file '%s'"), - keep_name ? keep_name : name); + keep_name); report = "keep"; } } if (final_pack_name != curr_pack_name) { - if (!final_pack_name) { - snprintf(name, sizeof(name), "%s/pack/pack-%s.pack", - get_object_directory(), sha1_to_hex(sha1)); - final_pack_name = name; - } + if (!final_pack_name) + final_pack_name = odb_pack_name(&pack_name, sha1, "pack"); if (finalize_object_file(curr_pack_name, final_pack_name)) die(_("cannot store pack file")); } else if (from_stdin) chmod(final_pack_name, 0444); if (final_index_name != curr_index_name) { - if (!final_index_name) { - snprintf(name, sizeof(name), "%s/pack/pack-%s.idx", - get_object_directory(), sha1_to_hex(sha1)); - final_index_name = name; - } + if (!final_index_name) + final_index_name = odb_pack_name(&index_name, sha1, "idx"); if (finalize_object_file(curr_index_name, final_index_name)) die(_("cannot store index file")); } else @@ -1447,10 +1445,11 @@ static void final(const char *final_pack_name, const char *curr_pack_name, if (!from_stdin) { printf("%s\n", sha1_to_hex(sha1)); } else { - char buf[48]; - int len = snprintf(buf, sizeof(buf), "%s\t%s\n", - report, sha1_to_hex(sha1)); - write_or_die(1, buf, len); + struct strbuf buf = STRBUF_INIT; + + strbuf_addf(&buf, "%s\t%s\n", report, sha1_to_hex(sha1)); + write_or_die(1, buf.buf, buf.len); + strbuf_release(&buf); /* * Let's just mimic git-unpack-objects here and write @@ -1464,6 +1463,10 @@ static void final(const char *final_pack_name, const char *curr_pack_name, input_offset += err; } } + + strbuf_release(&index_name); + strbuf_release(&pack_name); + strbuf_release(&keep_name_buf); } static int git_index_pack_config(const char *k, const char *v, void *cb) diff --git a/builtin/log.c b/builtin/log.c index 281af8c1ec..b3b10cc1ed 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -52,6 +52,11 @@ struct line_opt_callback_data { struct string_list args; }; +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) { switch (git_config_maybe_bool(var, value)) { @@ -67,7 +72,7 @@ static int parse_decoration_style(const char *var, const char *value) else if (!strcmp(value, "short")) return DECORATE_SHORT_REFS; else if (!strcmp(value, "auto")) - return (isatty(1) || pager_in_use()) ? DECORATE_SHORT_REFS : 0; + return auto_decoration_style(); return -1; } @@ -405,6 +410,8 @@ static int git_log_config(const char *var, const char *value, void *cb) if (decoration_style < 0) decoration_style = 0; /* maybe warn? */ return 0; + } else { + decoration_style = auto_decoration_style(); } if (!strcmp(var, "log.showroot")) { default_show_root = git_config_bool(var, value); @@ -1084,8 +1091,7 @@ static const char *set_outdir(const char *prefix, const char *output_directory) if (!output_directory) return prefix; - return xstrdup(prefix_filename(prefix, outdir_offset, - output_directory)); + return prefix_filename(prefix, output_directory); } static const char * const builtin_format_patch_usage[] = { diff --git a/builtin/ls-files.c b/builtin/ls-files.c index 1c0f057d02..d449e46db5 100644 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@ -30,7 +30,7 @@ static int line_terminator = '\n'; static int debug_mode; static int show_eol; static int recurse_submodules; -static struct argv_array submodules_options = ARGV_ARRAY_INIT; +static struct argv_array submodule_options = ARGV_ARRAY_INIT; static const char *prefix; static const char *super_prefix; @@ -172,20 +172,27 @@ static void show_killed_files(struct dir_struct *dir) /* * Compile an argv_array with all of the options supported by --recurse_submodules */ -static void compile_submodule_options(const struct dir_struct *dir, int show_tag) +static void compile_submodule_options(const char **argv, + const struct dir_struct *dir, + int show_tag) { if (line_terminator == '\0') - argv_array_push(&submodules_options, "-z"); + argv_array_push(&submodule_options, "-z"); if (show_tag) - argv_array_push(&submodules_options, "-t"); + argv_array_push(&submodule_options, "-t"); if (show_valid_bit) - argv_array_push(&submodules_options, "-v"); + argv_array_push(&submodule_options, "-v"); if (show_cached) - argv_array_push(&submodules_options, "--cached"); + argv_array_push(&submodule_options, "--cached"); if (show_eol) - argv_array_push(&submodules_options, "--eol"); + argv_array_push(&submodule_options, "--eol"); if (debug_mode) - argv_array_push(&submodules_options, "--debug"); + argv_array_push(&submodule_options, "--debug"); + + /* Add Pathspecs */ + argv_array_push(&submodule_options, "--"); + for (; *argv; argv++) + argv_array_push(&submodule_options, *argv); } /** @@ -195,8 +202,11 @@ static void show_gitlink(const struct cache_entry *ce) { struct child_process cp = CHILD_PROCESS_INIT; int status; - int i; + if (prefix_len) + argv_array_pushf(&cp.env_array, "%s=%s", + GIT_TOPLEVEL_PREFIX_ENVIRONMENT, + prefix); argv_array_pushf(&cp.args, "--super-prefix=%s%s/", super_prefix ? super_prefix : "", ce->name); @@ -204,16 +214,7 @@ static void show_gitlink(const struct cache_entry *ce) argv_array_push(&cp.args, "--recurse-submodules"); /* add supported options */ - argv_array_pushv(&cp.args, submodules_options.argv); - - /* - * Pass in the original pathspec args. The submodule will be - * responsible for prepending the 'submodule_prefix' prior to comparing - * against the pathspec for matches. - */ - argv_array_push(&cp.args, "--"); - for (i = 0; i < pathspec.nr; i++) - argv_array_push(&cp.args, pathspec.items[i].original); + argv_array_pushv(&cp.args, submodule_options.argv); cp.git_cmd = 1; cp.dir = ce->name; @@ -604,7 +605,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) setup_work_tree(); if (recurse_submodules) - compile_submodule_options(&dir, show_tag); + compile_submodule_options(argv, &dir, show_tag); if (recurse_submodules && (show_stage || show_deleted || show_others || show_unmerged || diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c index 66cdd45cc1..b2d7d5ce68 100644 --- a/builtin/ls-remote.c +++ b/builtin/ls-remote.c @@ -17,17 +17,19 @@ static const char * const ls_remote_usage[] = { static int tail_match(const char **pattern, const char *path) { const char *p; - char pathbuf[PATH_MAX]; + char *pathbuf; if (!pattern) return 1; /* no restriction */ - if (snprintf(pathbuf, sizeof(pathbuf), "/%s", path) > sizeof(pathbuf)) - return error("insanely long ref %.*s...", 20, path); + pathbuf = xstrfmt("/%s", path); while ((p = *(pattern++)) != NULL) { - if (!wildmatch(p, pathbuf, 0, NULL)) + if (!wildmatch(p, pathbuf, 0, NULL)) { + free(pathbuf); return 1; + } } + free(pathbuf); return 0; } diff --git a/builtin/mailinfo.c b/builtin/mailinfo.c index e3b62f2fc7..cfb667a594 100644 --- a/builtin/mailinfo.c +++ b/builtin/mailinfo.c @@ -11,13 +11,6 @@ static const char mailinfo_usage[] = "git mailinfo [-k | -b] [-m | --message-id] [-u | --encoding=<encoding> | -n] [--scissors | --no-scissors] <msg> <patch> < mail >info"; -static char *prefix_copy(const char *prefix, const char *filename) -{ - if (!prefix || is_absolute_path(filename)) - return xstrdup(filename); - return xstrdup(prefix_filename(prefix, strlen(prefix), filename)); -} - int cmd_mailinfo(int argc, const char **argv, const char *prefix) { const char *def_charset; @@ -60,8 +53,8 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix) mi.input = stdin; mi.output = stdout; - msgfile = prefix_copy(prefix, argv[1]); - patchfile = prefix_copy(prefix, argv[2]); + msgfile = prefix_filename(prefix, argv[1]); + patchfile = prefix_filename(prefix, argv[2]); status = !!mailinfo(&mi, msgfile, patchfile); clear_mailinfo(&mi); diff --git a/builtin/merge-file.c b/builtin/merge-file.c index 13e22a2f0b..47dde7c39c 100644 --- a/builtin/merge-file.c +++ b/builtin/merge-file.c @@ -28,7 +28,6 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix) xmparam_t xmp = {{0}}; int ret = 0, i = 0, to_stdout = 0; int quiet = 0; - int prefixlen = 0; struct option options[] = { OPT_BOOL('p', "stdout", &to_stdout, N_("send results to standard output")), OPT_SET_INT(0, "diff3", &xmp.style, N_("use a diff3 based merge"), XDL_MERGE_DIFF3), @@ -65,15 +64,19 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix) return error_errno("failed to redirect stderr to /dev/null"); } - if (prefix) - prefixlen = strlen(prefix); - for (i = 0; i < 3; i++) { - const char *fname = prefix_filename(prefix, prefixlen, argv[i]); + char *fname; + int ret; + if (!names[i]) names[i] = argv[i]; - if (read_mmfile(mmfs + i, fname)) + + fname = prefix_filename(prefix, argv[i]); + ret = read_mmfile(mmfs + i, fname); + free(fname); + if (ret) return -1; + if (mmfs[i].size > MAX_XDIFF_SIZE || buffer_is_binary(mmfs[i].ptr, mmfs[i].size)) return error("Cannot merge binary files: %s", @@ -90,7 +93,7 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix) if (ret >= 0) { const char *filename = argv[0]; - const char *fpath = prefix_filename(prefix, prefixlen, argv[0]); + char *fpath = prefix_filename(prefix, argv[0]); FILE *f = to_stdout ? stdout : fopen(fpath, "wb"); if (!f) @@ -102,6 +105,7 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix) else if (fclose(f)) ret = error_errno("Could not close %s", filename); free(result.ptr); + free(fpath); } if (ret > 127) diff --git a/builtin/merge-index.c b/builtin/merge-index.c index 2d1b6db6bd..c99443b095 100644 --- a/builtin/merge-index.c +++ b/builtin/merge-index.c @@ -9,7 +9,7 @@ static int merge_entry(int pos, const char *path) { int found; const char *arguments[] = { pgm, "", "", "", path, "", "", "", NULL }; - char hexbuf[4][GIT_SHA1_HEXSZ + 1]; + char hexbuf[4][GIT_MAX_HEXSZ + 1]; char ownbuf[4][60]; if (pos >= active_nr) diff --git a/builtin/merge.c b/builtin/merge.c index 7554b8d412..703827f006 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -44,7 +44,6 @@ struct strategy { static const char * const builtin_merge_usage[] = { N_("git merge [<options>] [<commit>...]"), - N_("git merge [<options>] <msg> HEAD <commit>"), N_("git merge --abort"), N_("git merge --continue"), NULL @@ -634,9 +633,10 @@ static void write_tree_trivial(struct object_id *oid) static int try_merge_strategy(const char *strategy, struct commit_list *common, struct commit_list *remoteheads, - struct commit *head, const char *head_arg) + struct commit *head) { static struct lock_file lock; + const char *head_arg = "HEAD"; hold_locked_index(&lock, LOCK_DIE_ON_ERROR); refresh_cache(REFRESH_QUIET); @@ -853,24 +853,6 @@ static int suggest_conflicts(void) return 1; } -static struct commit *is_old_style_invocation(int argc, const char **argv, - const struct object_id *head) -{ - struct commit *second_token = NULL; - if (argc > 2) { - struct object_id second_oid; - - if (get_oid(argv[1], &second_oid)) - return NULL; - second_token = lookup_commit_reference_gently(second_oid.hash, 0); - if (!second_token) - die(_("'%s' is not a commit"), argv[1]); - if (oidcmp(&second_token->object.oid, head)) - return NULL; - } - return second_token; -} - static int evaluate_result(void) { int cnt = 0; @@ -1120,7 +1102,6 @@ int cmd_merge(int argc, const char **argv, const char *prefix) struct object_id result_tree, stash, head_oid; struct commit *head_commit; struct strbuf buf = STRBUF_INIT; - const char *head_arg; int i, ret = 0, head_subsumed; int best_cnt = -1, merge_was_ok = 0, automerge_was_ok = 0; struct commit_list *common = NULL; @@ -1260,34 +1241,12 @@ int cmd_merge(int argc, const char **argv, const char *prefix) } /* - * This could be traditional "merge <msg> HEAD <commit>..." and - * the way we can tell it is to see if the second token is HEAD, - * but some people might have misused the interface and used a - * commit-ish that is the same as HEAD there instead. - * Traditional format never would have "-m" so it is an - * additional safety measure to check for it. + * All the rest are the commits being merged; prepare + * the standard merge summary message to be appended + * to the given message. */ - if (!have_message && - is_old_style_invocation(argc, argv, &head_commit->object.oid)) { - warning("old-style 'git merge <msg> HEAD <commit>' is deprecated."); - strbuf_addstr(&merge_msg, argv[0]); - head_arg = argv[1]; - argv += 2; - argc -= 2; - remoteheads = collect_parents(head_commit, &head_subsumed, - argc, argv, NULL); - } else { - /* We are invoked directly as the first-class UI. */ - head_arg = "HEAD"; - - /* - * All the rest are the commits being merged; prepare - * the standard merge summary message to be appended - * to the given message. - */ - remoteheads = collect_parents(head_commit, &head_subsumed, - argc, argv, &merge_msg); - } + remoteheads = collect_parents(head_commit, &head_subsumed, + argc, argv, &merge_msg); if (!head_commit || !argc) usage_with_options(builtin_merge_usage, @@ -1296,7 +1255,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) if (verify_signatures) { for (p = remoteheads; p; p = p->next) { struct commit *commit = p->item; - char hex[GIT_SHA1_HEXSZ + 1]; + char hex[GIT_MAX_HEXSZ + 1]; struct signature_check signature_check; memset(&signature_check, 0, sizeof(signature_check)); @@ -1513,7 +1472,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) ret = try_merge_strategy(use_strategies[i]->name, common, remoteheads, - head_commit, head_arg); + head_commit); if (!option_commit && !ret) { merge_was_ok = 1; /* @@ -1583,7 +1542,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) printf(_("Using the %s to prepare resolving by hand.\n"), best_strategy); try_merge_strategy(best_strategy, common, remoteheads, - head_commit, head_arg); + head_commit); } if (squash) diff --git a/builtin/name-rev.c b/builtin/name-rev.c index 8bdc3eaa6f..92a5d8a5d2 100644 --- a/builtin/name-rev.c +++ b/builtin/name-rev.c @@ -238,10 +238,9 @@ static const char *get_exact_ref_match(const struct object *o) return NULL; } -/* returns a static buffer */ -static const char *get_rev_name(const struct object *o) +/* may return a constant string or use "buf" as scratch space */ +static const char *get_rev_name(const struct object *o, struct strbuf *buf) { - static char buffer[1024]; struct rev_name *n; struct commit *c; @@ -258,10 +257,9 @@ static const char *get_rev_name(const struct object *o) int len = strlen(n->tip_name); if (len > 2 && !strcmp(n->tip_name + len - 2, "^0")) len -= 2; - snprintf(buffer, sizeof(buffer), "%.*s~%d", len, n->tip_name, - n->generation); - - return buffer; + strbuf_reset(buf); + strbuf_addf(buf, "%.*s~%d", len, n->tip_name, n->generation); + return buf->buf; } } @@ -271,10 +269,11 @@ static void show_name(const struct object *obj, { const char *name; const struct object_id *oid = &obj->oid; + struct strbuf buf = STRBUF_INIT; if (!name_only) printf("%s ", caller_name ? caller_name : oid_to_hex(oid)); - name = get_rev_name(obj); + name = get_rev_name(obj, &buf); if (name) printf("%s\n", name); else if (allow_undefined) @@ -283,6 +282,7 @@ static void show_name(const struct object *obj, printf("%s\n", find_unique_abbrev(oid->hash, DEFAULT_ABBREV)); else die("cannot describe '%s'", oid_to_hex(oid)); + strbuf_release(&buf); } static char const * const name_rev_usage[] = { @@ -294,6 +294,7 @@ static char const * const name_rev_usage[] = { static void name_rev_line(char *p, struct name_ref_data *data) { + struct strbuf buf = STRBUF_INIT; int forty = 0; char *p_start; for (p_start = p; *p; p++) { @@ -314,7 +315,7 @@ static void name_rev_line(char *p, struct name_ref_data *data) struct object *o = lookup_object(sha1); if (o) - name = get_rev_name(o); + name = get_rev_name(o, &buf); } *(p+1) = c; @@ -332,6 +333,8 @@ static void name_rev_line(char *p, struct name_ref_data *data) /* flush */ if (p_start != p) fwrite(p_start, p - p_start, 1, stdout); + + strbuf_release(&buf); } int cmd_name_rev(int argc, const char **argv, const char *prefix) diff --git a/builtin/notes.c b/builtin/notes.c index 0513f7455d..7b891471c4 100644 --- a/builtin/notes.c +++ b/builtin/notes.c @@ -554,7 +554,7 @@ static int append_edit(int argc, const char **argv, const char *prefix) struct notes_tree *t; unsigned char object[20], new_note[20]; const unsigned char *note; - char logmsg[100]; + char *logmsg; const char * const *usage; struct note_data d = { 0, 0, NULL, STRBUF_INIT }; struct option options[] = { @@ -618,17 +618,16 @@ static int append_edit(int argc, const char **argv, const char *prefix) write_note_data(&d, new_note); if (add_note(t, object, new_note, combine_notes_overwrite)) die("BUG: combine_notes_overwrite failed"); - snprintf(logmsg, sizeof(logmsg), "Notes added by 'git notes %s'", - argv[0]); + logmsg = xstrfmt("Notes added by 'git notes %s'", argv[0]); } else { fprintf(stderr, _("Removing note for object %s\n"), sha1_to_hex(object)); remove_note(t, object); - snprintf(logmsg, sizeof(logmsg), "Notes removed by 'git notes %s'", - argv[0]); + logmsg = xstrfmt("Notes removed by 'git notes %s'", argv[0]); } commit_notes(t, logmsg); + free(logmsg); free_note_data(&d); free_notes(t); return 0; diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 16517f2637..0fe35d1b5a 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -239,7 +239,8 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent unsigned long limit, int usable_delta) { unsigned long size, datalen; - unsigned char header[10], dheader[10]; + unsigned char header[MAX_PACK_OBJECT_HEADER], + dheader[MAX_PACK_OBJECT_HEADER]; unsigned hdrlen; enum object_type type; void *buf; @@ -286,7 +287,8 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent * The object header is a byte of 'type' followed by zero or * more bytes of length. */ - hdrlen = encode_in_pack_object_header(type, size, header); + hdrlen = encode_in_pack_object_header(header, sizeof(header), + type, size); if (type == OBJ_OFS_DELTA) { /* @@ -352,13 +354,15 @@ static off_t write_reuse_object(struct sha1file *f, struct object_entry *entry, off_t offset; enum object_type type = entry->type; off_t datalen; - unsigned char header[10], dheader[10]; + unsigned char header[MAX_PACK_OBJECT_HEADER], + dheader[MAX_PACK_OBJECT_HEADER]; unsigned hdrlen; if (entry->delta) type = (allow_ofs_delta && entry->delta->idx.offset) ? OBJ_OFS_DELTA : OBJ_REF_DELTA; - hdrlen = encode_in_pack_object_header(type, entry->size, header); + hdrlen = encode_in_pack_object_header(header, sizeof(header), + type, entry->size); offset = entry->in_pack_offset; revidx = find_pack_revindex(p, offset); @@ -2668,16 +2672,16 @@ static int has_sha1_pack_kept_or_nonlocal(const unsigned char *sha1) * * This is filled by get_object_list. */ -static struct sha1_array recent_objects; +static struct oid_array recent_objects; -static int loosened_object_can_be_discarded(const unsigned char *sha1, +static int loosened_object_can_be_discarded(const struct object_id *oid, unsigned long mtime) { if (!unpack_unreachable_expiration) return 0; if (mtime > unpack_unreachable_expiration) return 0; - if (sha1_array_lookup(&recent_objects, sha1) >= 0) + if (oid_array_lookup(&recent_objects, oid) >= 0) return 0; return 1; } @@ -2686,7 +2690,7 @@ static void loosen_unused_packed_objects(struct rev_info *revs) { struct packed_git *p; uint32_t i; - const unsigned char *sha1; + struct object_id oid; for (p = packed_git; p; p = p->next) { if (!p->pack_local || p->pack_keep) @@ -2696,11 +2700,11 @@ static void loosen_unused_packed_objects(struct rev_info *revs) die("cannot open pack index"); for (i = 0; i < p->num_objects; i++) { - sha1 = nth_packed_object_sha1(p, i); - if (!packlist_find(&to_pack, sha1, NULL) && - !has_sha1_pack_kept_or_nonlocal(sha1) && - !loosened_object_can_be_discarded(sha1, p->mtime)) - if (force_object_loose(sha1, p->mtime)) + nth_packed_object_oid(&oid, p, i); + if (!packlist_find(&to_pack, oid.hash, NULL) && + !has_sha1_pack_kept_or_nonlocal(oid.hash) && + !loosened_object_can_be_discarded(&oid, p->mtime)) + if (force_object_loose(oid.hash, p->mtime)) die("unable to force loose object"); } } @@ -2739,12 +2743,12 @@ static void record_recent_object(struct object *obj, const char *name, void *data) { - sha1_array_append(&recent_objects, obj->oid.hash); + oid_array_append(&recent_objects, &obj->oid); } static void record_recent_commit(struct commit *commit, void *data) { - sha1_array_append(&recent_objects, commit->object.oid.hash); + oid_array_append(&recent_objects, &commit->object.oid); } static void get_object_list(int ac, const char **av) @@ -2812,7 +2816,7 @@ static void get_object_list(int ac, const char **av) if (unpack_unreachable) loosen_unused_packed_objects(&revs); - sha1_array_clear(&recent_objects); + oid_array_clear(&recent_objects); } static int option_parse_index_version(const struct option *opt, diff --git a/builtin/patch-id.c b/builtin/patch-id.c index a84d0003a3..81552e02e4 100644 --- a/builtin/patch-id.c +++ b/builtin/patch-id.c @@ -55,7 +55,7 @@ static int scan_hunk_header(const char *p, int *p_before, int *p_after) static void flush_one_hunk(struct object_id *result, git_SHA_CTX *ctx) { - unsigned char hash[GIT_SHA1_RAWSZ]; + unsigned char hash[GIT_MAX_RAWSZ]; unsigned short carry = 0; int i; diff --git a/builtin/pull.c b/builtin/pull.c index 3ecb881b0b..d8aa26d8ab 100644 --- a/builtin/pull.c +++ b/builtin/pull.c @@ -330,21 +330,21 @@ static int git_pull_config(const char *var, const char *value, void *cb) * Appends merge candidates from FETCH_HEAD that are not marked not-for-merge * into merge_heads. */ -static void get_merge_heads(struct sha1_array *merge_heads) +static void get_merge_heads(struct oid_array *merge_heads) { const char *filename = git_path("FETCH_HEAD"); FILE *fp; struct strbuf sb = STRBUF_INIT; - unsigned char sha1[GIT_SHA1_RAWSZ]; + struct object_id oid; if (!(fp = fopen(filename, "r"))) die_errno(_("could not open '%s' for reading"), filename); while (strbuf_getline_lf(&sb, fp) != EOF) { - if (get_sha1_hex(sb.buf, sha1)) + if (get_oid_hex(sb.buf, &oid)) continue; /* invalid line: does not start with SHA1 */ if (starts_with(sb.buf + GIT_SHA1_HEXSZ, "\tnot-for-merge\t")) continue; /* ref is not-for-merge */ - sha1_array_append(merge_heads, sha1); + oid_array_append(merge_heads, &oid); } fclose(fp); strbuf_release(&sb); @@ -514,8 +514,8 @@ static int run_fetch(const char *repo, const char **refspecs) /** * "Pulls into void" by branching off merge_head. */ -static int pull_into_void(const unsigned char *merge_head, - const unsigned char *curr_head) +static int pull_into_void(const struct object_id *merge_head, + const struct object_id *curr_head) { /* * Two-way merge: we treat the index as based on an empty tree, @@ -523,10 +523,10 @@ static int pull_into_void(const unsigned char *merge_head, * index/worktree changes that the user already made on the unborn * branch. */ - if (checkout_fast_forward(EMPTY_TREE_SHA1_BIN, merge_head, 0)) + if (checkout_fast_forward(EMPTY_TREE_SHA1_BIN, merge_head->hash, 0)) return 1; - if (update_ref("initial pull", "HEAD", merge_head, curr_head, 0, UPDATE_REFS_DIE_ON_ERR)) + if (update_ref("initial pull", "HEAD", merge_head->hash, curr_head->hash, 0, UPDATE_REFS_DIE_ON_ERR)) return 1; return 0; @@ -647,7 +647,7 @@ static const char *get_tracking_branch(const char *remote, const char *refspec) * current branch forked from its remote tracking branch. Returns 0 on success, * -1 on failure. */ -static int get_rebase_fork_point(unsigned char *fork_point, const char *repo, +static int get_rebase_fork_point(struct object_id *fork_point, const char *repo, const char *refspec) { int ret; @@ -678,7 +678,7 @@ static int get_rebase_fork_point(unsigned char *fork_point, const char *repo, if (ret) goto cleanup; - ret = get_sha1_hex(sb.buf, fork_point); + ret = get_oid_hex(sb.buf, fork_point); if (ret) goto cleanup; @@ -691,24 +691,24 @@ cleanup: * Sets merge_base to the octopus merge base of curr_head, merge_head and * fork_point. Returns 0 if a merge base is found, 1 otherwise. */ -static int get_octopus_merge_base(unsigned char *merge_base, - const unsigned char *curr_head, - const unsigned char *merge_head, - const unsigned char *fork_point) +static int get_octopus_merge_base(struct object_id *merge_base, + const struct object_id *curr_head, + const struct object_id *merge_head, + const struct object_id *fork_point) { struct commit_list *revs = NULL, *result; - commit_list_insert(lookup_commit_reference(curr_head), &revs); - commit_list_insert(lookup_commit_reference(merge_head), &revs); - if (!is_null_sha1(fork_point)) - commit_list_insert(lookup_commit_reference(fork_point), &revs); + commit_list_insert(lookup_commit_reference(curr_head->hash), &revs); + commit_list_insert(lookup_commit_reference(merge_head->hash), &revs); + if (!is_null_oid(fork_point)) + commit_list_insert(lookup_commit_reference(fork_point->hash), &revs); result = reduce_heads(get_octopus_merge_bases(revs)); free_commit_list(revs); if (!result) return 1; - hashcpy(merge_base, result->item->object.oid.hash); + oidcpy(merge_base, &result->item->object.oid); return 0; } @@ -717,16 +717,16 @@ static int get_octopus_merge_base(unsigned char *merge_base, * fork point calculated by get_rebase_fork_point(), runs git-rebase with the * appropriate arguments and returns its exit status. */ -static int run_rebase(const unsigned char *curr_head, - const unsigned char *merge_head, - const unsigned char *fork_point) +static int run_rebase(const struct object_id *curr_head, + const struct object_id *merge_head, + const struct object_id *fork_point) { int ret; - unsigned char oct_merge_base[GIT_SHA1_RAWSZ]; + struct object_id oct_merge_base; struct argv_array args = ARGV_ARRAY_INIT; - if (!get_octopus_merge_base(oct_merge_base, curr_head, merge_head, fork_point)) - if (!is_null_sha1(fork_point) && !hashcmp(oct_merge_base, fork_point)) + if (!get_octopus_merge_base(&oct_merge_base, curr_head, merge_head, fork_point)) + if (!is_null_oid(fork_point) && !oidcmp(&oct_merge_base, fork_point)) fork_point = NULL; argv_array_push(&args, "rebase"); @@ -754,12 +754,12 @@ static int run_rebase(const unsigned char *curr_head, warning(_("ignoring --verify-signatures for rebase")); argv_array_push(&args, "--onto"); - argv_array_push(&args, sha1_to_hex(merge_head)); + argv_array_push(&args, oid_to_hex(merge_head)); - if (fork_point && !is_null_sha1(fork_point)) - argv_array_push(&args, sha1_to_hex(fork_point)); + if (fork_point && !is_null_oid(fork_point)) + argv_array_push(&args, oid_to_hex(fork_point)); else - argv_array_push(&args, sha1_to_hex(merge_head)); + argv_array_push(&args, oid_to_hex(merge_head)); ret = run_command_v_opt(args.argv, RUN_GIT_CMD); argv_array_clear(&args); @@ -769,9 +769,9 @@ static int run_rebase(const unsigned char *curr_head, int cmd_pull(int argc, const char **argv, const char *prefix) { const char *repo, **refspecs; - struct sha1_array merge_heads = SHA1_ARRAY_INIT; - unsigned char orig_head[GIT_SHA1_RAWSZ], curr_head[GIT_SHA1_RAWSZ]; - unsigned char rebase_fork_point[GIT_SHA1_RAWSZ]; + struct oid_array merge_heads = OID_ARRAY_INIT; + struct object_id orig_head, curr_head; + struct object_id rebase_fork_point; if (!getenv("GIT_REFLOG_ACTION")) set_reflog_message(argc, argv); @@ -794,8 +794,8 @@ int cmd_pull(int argc, const char **argv, const char *prefix) if (file_exists(git_path("MERGE_HEAD"))) die_conclude_merge(); - if (get_sha1("HEAD", orig_head)) - hashclr(orig_head); + if (get_oid("HEAD", &orig_head)) + oidclr(&orig_head); if (!opt_rebase && opt_autostash != -1) die(_("--[no-]autostash option is only valid with --rebase.")); @@ -805,15 +805,15 @@ int cmd_pull(int argc, const char **argv, const char *prefix) if (opt_autostash != -1) autostash = opt_autostash; - if (is_null_sha1(orig_head) && !is_cache_unborn()) + if (is_null_oid(&orig_head) && !is_cache_unborn()) die(_("Updating an unborn branch with changes added to the index.")); if (!autostash) require_clean_work_tree(N_("pull with rebase"), _("please commit or stash them."), 1, 0); - if (get_rebase_fork_point(rebase_fork_point, repo, *refspecs)) - hashclr(rebase_fork_point); + if (get_rebase_fork_point(&rebase_fork_point, repo, *refspecs)) + oidclr(&rebase_fork_point); } if (run_fetch(repo, refspecs)) @@ -822,11 +822,11 @@ int cmd_pull(int argc, const char **argv, const char *prefix) if (opt_dry_run) return 0; - if (get_sha1("HEAD", curr_head)) - hashclr(curr_head); + if (get_oid("HEAD", &curr_head)) + oidclr(&curr_head); - if (!is_null_sha1(orig_head) && !is_null_sha1(curr_head) && - hashcmp(orig_head, curr_head)) { + if (!is_null_oid(&orig_head) && !is_null_oid(&curr_head) && + oidcmp(&orig_head, &curr_head)) { /* * The fetch involved updating the current branch. * @@ -837,15 +837,15 @@ int cmd_pull(int argc, const char **argv, const char *prefix) warning(_("fetch updated the current branch head.\n" "fast-forwarding your working tree from\n" - "commit %s."), sha1_to_hex(orig_head)); + "commit %s."), oid_to_hex(&orig_head)); - if (checkout_fast_forward(orig_head, curr_head, 0)) + if (checkout_fast_forward(orig_head.hash, curr_head.hash, 0)) die(_("Cannot fast-forward your working tree.\n" "After making sure that you saved anything precious from\n" "$ git diff %s\n" "output, run\n" "$ git reset --hard\n" - "to recover."), sha1_to_hex(orig_head)); + "to recover."), oid_to_hex(&orig_head)); } get_merge_heads(&merge_heads); @@ -853,10 +853,10 @@ int cmd_pull(int argc, const char **argv, const char *prefix) if (!merge_heads.nr) die_no_merge_candidates(repo, refspecs); - if (is_null_sha1(orig_head)) { + if (is_null_oid(&orig_head)) { if (merge_heads.nr > 1) die(_("Cannot merge multiple branches into empty head.")); - return pull_into_void(*merge_heads.sha1, curr_head); + return pull_into_void(merge_heads.oid, &curr_head); } if (opt_rebase && merge_heads.nr > 1) die(_("Cannot rebase onto multiple branches.")); @@ -865,15 +865,15 @@ int cmd_pull(int argc, const char **argv, const char *prefix) struct commit_list *list = NULL; struct commit *merge_head, *head; - head = lookup_commit_reference(orig_head); + head = lookup_commit_reference(orig_head.hash); commit_list_insert(head, &list); - merge_head = lookup_commit_reference(merge_heads.sha1[0]); + merge_head = lookup_commit_reference(merge_heads.oid[0].hash); if (is_descendant_of(merge_head, list)) { /* we can fast-forward this without invoking rebase */ opt_ff = "--ff-only"; return run_merge(); } - return run_rebase(curr_head, *merge_heads.sha1, rebase_fork_point); + return run_rebase(&curr_head, merge_heads.oid, &rebase_fork_point); } else { return run_merge(); } diff --git a/builtin/push.c b/builtin/push.c index 5c22e9f2e5..a597759d8f 100644 --- a/builtin/push.c +++ b/builtin/push.c @@ -510,8 +510,8 @@ int cmd_push(int argc, const char **argv, const char *prefix) int push_cert = -1; int rc; const char *repo = NULL; /* default repository */ - static struct string_list push_options = STRING_LIST_INIT_DUP; - static struct string_list_item *item; + struct string_list push_options = STRING_LIST_INIT_DUP; + const struct string_list_item *item; struct option options[] = { OPT__VERBOSITY(&verbosity), @@ -584,6 +584,7 @@ int cmd_push(int argc, const char **argv, const char *prefix) die(_("push options must not have new line characters")); rc = do_push(repo, flags, &push_options); + string_list_clear(&push_options, 0); if (rc == -1) usage_with_options(push_usage, options); else diff --git a/builtin/read-tree.c b/builtin/read-tree.c index 8ba64bc785..23e212ee8c 100644 --- a/builtin/read-tree.c +++ b/builtin/read-tree.c @@ -15,10 +15,13 @@ #include "builtin.h" #include "parse-options.h" #include "resolve-undo.h" +#include "submodule.h" +#include "submodule-config.h" static int nr_trees; static int read_empty; static struct tree *trees[MAX_UNPACK_TREES]; +static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT; static int list_tree(unsigned char *sha1) { @@ -96,6 +99,23 @@ static int debug_merge(const struct cache_entry * const *stages, return 0; } +static int option_parse_recurse_submodules(const struct option *opt, + const char *arg, int unset) +{ + if (unset) { + recurse_submodules = RECURSE_SUBMODULES_OFF; + return 0; + } + if (arg) + recurse_submodules = + parse_update_recurse_submodules_arg(opt->long_name, + arg); + else + recurse_submodules = RECURSE_SUBMODULES_ON; + + return 0; +} + static struct lock_file lock_file; int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) @@ -137,6 +157,9 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) N_("skip applying sparse checkout filter")), OPT_BOOL(0, "debug-unpack", &opts.debug_unpack, N_("debug unpack-trees")), + { OPTION_CALLBACK, 0, "recurse-submodules", &recurse_submodules, + "checkout", "control recursive updating of submodules", + PARSE_OPT_OPTARG, option_parse_recurse_submodules }, OPT_END() }; @@ -152,6 +175,12 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR); + if (recurse_submodules != RECURSE_SUBMODULES_DEFAULT) { + gitmodules_config(); + git_config(submodule_config, NULL); + set_config_update_recurse_submodules(RECURSE_SUBMODULES_ON); + } + prefix_set = opts.prefix ? 1 : 0; if (1 < opts.merge + opts.reset + prefix_set) die("Which one? -m, --reset, or --prefix?"); diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 83492af05f..3cba3fd278 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -225,10 +225,10 @@ static int receive_pack_config(const char *var, const char *value, void *cb) return git_default_config(var, value, cb); } -static void show_ref(const char *path, const unsigned char *sha1) +static void show_ref(const char *path, const struct object_id *oid) { if (sent_capabilities) { - packet_write_fmt(1, "%s %s\n", sha1_to_hex(sha1), path); + packet_write_fmt(1, "%s %s\n", oid_to_hex(oid), path); } else { struct strbuf cap = STRBUF_INIT; @@ -244,7 +244,7 @@ static void show_ref(const char *path, const unsigned char *sha1) strbuf_addstr(&cap, " push-options"); strbuf_addf(&cap, " agent=%s", git_user_agent_sanitized()); packet_write_fmt(1, "%s %s%c%s\n", - sha1_to_hex(sha1), path, 0, cap.buf); + oid_to_hex(oid), path, 0, cap.buf); strbuf_release(&cap); sent_capabilities = 1; } @@ -271,7 +271,7 @@ static int show_ref_cb(const char *path_full, const struct object_id *oid, } else { oidset_insert(seen, oid); } - show_ref(path, oid->hash); + show_ref(path, oid); return 0; } @@ -284,7 +284,7 @@ static void show_one_alternate_ref(const char *refname, if (oidset_insert(seen, oid)) return; - show_ref(".have", oid->hash); + show_ref(".have", oid); } static void write_head_info(void) @@ -295,7 +295,7 @@ static void write_head_info(void) for_each_alternate_ref(show_one_alternate_ref, &seen); oidset_clear(&seen); if (!sent_capabilities) - show_ref("capabilities^{}", null_sha1); + show_ref("capabilities^{}", &null_oid); advertise_shallow_grafts(1); @@ -309,8 +309,8 @@ struct command { unsigned int skip_update:1, did_not_exist:1; int index; - unsigned char old_sha1[20]; - unsigned char new_sha1[20]; + struct object_id old_oid; + struct object_id new_oid; char ref_name[FLEX_ARRAY]; /* more */ }; @@ -723,7 +723,7 @@ static int feed_receive_hook(void *state_, const char **bufp, size_t *sizep) return -1; /* EOF */ strbuf_reset(&state->buf); strbuf_addf(&state->buf, "%s %s %s\n", - sha1_to_hex(cmd->old_sha1), sha1_to_hex(cmd->new_sha1), + oid_to_hex(&cmd->old_oid), oid_to_hex(&cmd->new_oid), cmd->ref_name); state->cmd = cmd->next; if (bufp) { @@ -764,8 +764,8 @@ static int run_update_hook(struct command *cmd) return 0; argv[1] = cmd->ref_name; - argv[2] = sha1_to_hex(cmd->old_sha1); - argv[3] = sha1_to_hex(cmd->new_sha1); + argv[2] = oid_to_hex(&cmd->old_oid); + argv[3] = oid_to_hex(&cmd->new_oid); argv[4] = NULL; proc.no_stdin = 1; @@ -831,7 +831,7 @@ static int command_singleton_iterator(void *cb_data, unsigned char sha1[20]); static int update_shallow_ref(struct command *cmd, struct shallow_info *si) { static struct lock_file shallow_lock; - struct sha1_array extra = SHA1_ARRAY_INIT; + struct oid_array extra = OID_ARRAY_INIT; struct check_connected_options opt = CHECK_CONNECTED_INIT; uint32_t mask = 1 << (cmd->index % 32); int i; @@ -842,13 +842,13 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si) if (si->used_shallow[i] && (si->used_shallow[i][cmd->index / 32] & mask) && !delayed_reachability_test(si, i)) - sha1_array_append(&extra, si->shallow->sha1[i]); + oid_array_append(&extra, &si->shallow->oid[i]); opt.env = tmp_objdir_env(tmp_objdir); setup_alternate_shallow(&shallow_lock, &opt.shallow_file, &extra); if (check_connected(command_singleton_iterator, cmd, &opt)) { rollback_lock_file(&shallow_lock); - sha1_array_clear(&extra); + oid_array_clear(&extra); return -1; } @@ -859,10 +859,10 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si) * not lose these new roots.. */ for (i = 0; i < extra.nr; i++) - register_shallow(extra.sha1[i]); + register_shallow(extra.oid[i].hash); si->shallow_ref[cmd->index] = 0; - sha1_array_clear(&extra); + oid_array_clear(&extra); return 0; } @@ -988,8 +988,8 @@ static const char *update(struct command *cmd, struct shallow_info *si) const char *name = cmd->ref_name; struct strbuf namespaced_name_buf = STRBUF_INIT; const char *namespaced_name, *ret; - unsigned char *old_sha1 = cmd->old_sha1; - unsigned char *new_sha1 = cmd->new_sha1; + struct object_id *old_oid = &cmd->old_oid; + struct object_id *new_oid = &cmd->new_oid; /* only refs/... are allowed */ if (!starts_with(name, "refs/") || check_refname_format(name + 5, 0)) { @@ -1014,20 +1014,20 @@ static const char *update(struct command *cmd, struct shallow_info *si) refuse_unconfigured_deny(); return "branch is currently checked out"; case DENY_UPDATE_INSTEAD: - ret = update_worktree(new_sha1); + ret = update_worktree(new_oid->hash); if (ret) return ret; break; } } - if (!is_null_sha1(new_sha1) && !has_sha1_file(new_sha1)) { + if (!is_null_oid(new_oid) && !has_object_file(new_oid)) { error("unpack should have generated %s, " - "but I can't find it!", sha1_to_hex(new_sha1)); + "but I can't find it!", oid_to_hex(new_oid)); return "bad pack"; } - if (!is_null_sha1(old_sha1) && is_null_sha1(new_sha1)) { + if (!is_null_oid(old_oid) && is_null_oid(new_oid)) { if (deny_deletes && starts_with(name, "refs/heads/")) { rp_error("denying ref deletion for %s", name); return "deletion prohibited"; @@ -1053,14 +1053,14 @@ static const char *update(struct command *cmd, struct shallow_info *si) } } - if (deny_non_fast_forwards && !is_null_sha1(new_sha1) && - !is_null_sha1(old_sha1) && + if (deny_non_fast_forwards && !is_null_oid(new_oid) && + !is_null_oid(old_oid) && starts_with(name, "refs/heads/")) { struct object *old_object, *new_object; struct commit *old_commit, *new_commit; - old_object = parse_object(old_sha1); - new_object = parse_object(new_sha1); + old_object = parse_object(old_oid->hash); + new_object = parse_object(new_oid->hash); if (!old_object || !new_object || old_object->type != OBJ_COMMIT || @@ -1081,10 +1081,10 @@ static const char *update(struct command *cmd, struct shallow_info *si) return "hook declined"; } - if (is_null_sha1(new_sha1)) { + if (is_null_oid(new_oid)) { struct strbuf err = STRBUF_INIT; - if (!parse_object(old_sha1)) { - old_sha1 = NULL; + if (!parse_object(old_oid->hash)) { + old_oid = NULL; if (ref_exists(name)) { rp_warning("Allowing deletion of corrupt ref."); } else { @@ -1094,7 +1094,7 @@ static const char *update(struct command *cmd, struct shallow_info *si) } if (ref_transaction_delete(transaction, namespaced_name, - old_sha1, + old_oid->hash, 0, "push", &err)) { rp_error("%s", err.buf); strbuf_release(&err); @@ -1111,7 +1111,7 @@ static const char *update(struct command *cmd, struct shallow_info *si) if (ref_transaction_update(transaction, namespaced_name, - new_sha1, old_sha1, + new_oid->hash, old_oid->hash, 0, "push", &err)) { rp_error("%s", err.buf); @@ -1128,25 +1128,22 @@ static const char *update(struct command *cmd, struct shallow_info *si) static void run_update_post_hook(struct command *commands) { struct command *cmd; - int argc; struct child_process proc = CHILD_PROCESS_INIT; const char *hook; hook = find_hook("post-update"); - for (argc = 0, cmd = commands; cmd; cmd = cmd->next) { - if (cmd->error_string || cmd->did_not_exist) - continue; - argc++; - } - if (!argc || !hook) + if (!hook) return; - argv_array_push(&proc.args, hook); for (cmd = commands; cmd; cmd = cmd->next) { if (cmd->error_string || cmd->did_not_exist) continue; + if (!proc.args.argc) + argv_array_push(&proc.args, hook); argv_array_push(&proc.args, cmd->ref_name); } + if (!proc.args.argc) + return; proc.no_stdin = 1; proc.stdout_to_stderr = 1; @@ -1165,7 +1162,7 @@ static void check_aliased_update(struct command *cmd, struct string_list *list) const char *dst_name; struct string_list_item *item; struct command *dst_cmd; - unsigned char sha1[GIT_SHA1_RAWSZ]; + unsigned char sha1[GIT_MAX_RAWSZ]; int flag; strbuf_addf(&buf, "%s%s", get_git_namespace(), cmd->ref_name); @@ -1190,8 +1187,8 @@ static void check_aliased_update(struct command *cmd, struct string_list *list) dst_cmd = (struct command *) item->util; - if (!hashcmp(cmd->old_sha1, dst_cmd->old_sha1) && - !hashcmp(cmd->new_sha1, dst_cmd->new_sha1)) + if (!oidcmp(&cmd->old_oid, &dst_cmd->old_oid) && + !oidcmp(&cmd->new_oid, &dst_cmd->new_oid)) return; dst_cmd->skip_update = 1; @@ -1199,11 +1196,11 @@ static void check_aliased_update(struct command *cmd, struct string_list *list) rp_error("refusing inconsistent update between symref '%s' (%s..%s) and" " its target '%s' (%s..%s)", cmd->ref_name, - find_unique_abbrev(cmd->old_sha1, DEFAULT_ABBREV), - find_unique_abbrev(cmd->new_sha1, DEFAULT_ABBREV), + find_unique_abbrev(cmd->old_oid.hash, DEFAULT_ABBREV), + find_unique_abbrev(cmd->new_oid.hash, DEFAULT_ABBREV), dst_cmd->ref_name, - find_unique_abbrev(dst_cmd->old_sha1, DEFAULT_ABBREV), - find_unique_abbrev(dst_cmd->new_sha1, DEFAULT_ABBREV)); + find_unique_abbrev(dst_cmd->old_oid.hash, DEFAULT_ABBREV), + find_unique_abbrev(dst_cmd->new_oid.hash, DEFAULT_ABBREV)); cmd->error_string = dst_cmd->error_string = "inconsistent aliased update"; @@ -1234,10 +1231,10 @@ static int command_singleton_iterator(void *cb_data, unsigned char sha1[20]) struct command **cmd_list = cb_data; struct command *cmd = *cmd_list; - if (!cmd || is_null_sha1(cmd->new_sha1)) + if (!cmd || is_null_oid(&cmd->new_oid)) return -1; /* end of list */ *cmd_list = NULL; /* this returns only one */ - hashcpy(sha1, cmd->new_sha1); + hashcpy(sha1, cmd->new_oid.hash); return 0; } @@ -1278,8 +1275,8 @@ static int iterate_receive_command_list(void *cb_data, unsigned char sha1[20]) if (shallow_update && data->si->shallow_ref[cmd->index]) /* to be checked in update_shallow_ref() */ continue; - if (!is_null_sha1(cmd->new_sha1) && !cmd->skip_update) { - hashcpy(sha1, cmd->new_sha1); + if (!is_null_oid(&cmd->new_oid) && !cmd->skip_update) { + hashcpy(sha1, cmd->new_oid.hash); *cmd_list = cmd->next; return 0; } @@ -1306,7 +1303,7 @@ static void reject_updates_to_hidden(struct command *commands) if (!ref_is_hidden(cmd->ref_name, refname_full.buf)) continue; - if (is_null_sha1(cmd->new_sha1)) + if (is_null_oid(&cmd->new_oid)) cmd->error_string = "deny deleting a hidden ref"; else cmd->error_string = "deny updating a hidden ref"; @@ -1489,23 +1486,23 @@ static struct command **queue_command(struct command **tail, const char *line, int linelen) { - unsigned char old_sha1[20], new_sha1[20]; + struct object_id old_oid, new_oid; struct command *cmd; const char *refname; int reflen; + const char *p; - if (linelen < 83 || - line[40] != ' ' || - line[81] != ' ' || - get_sha1_hex(line, old_sha1) || - get_sha1_hex(line + 41, new_sha1)) + if (parse_oid_hex(line, &old_oid, &p) || + *p++ != ' ' || + parse_oid_hex(p, &new_oid, &p) || + *p++ != ' ') die("protocol error: expected old/new/ref, got '%s'", line); - refname = line + 82; - reflen = linelen - 82; + refname = p; + reflen = linelen - (p - line); FLEX_ALLOC_MEM(cmd, ref_name, refname, reflen); - hashcpy(cmd->old_sha1, old_sha1); - hashcpy(cmd->new_sha1, new_sha1); + oidcpy(&cmd->old_oid, &old_oid); + oidcpy(&cmd->new_oid, &new_oid); *tail = cmd; return &cmd->next; } @@ -1527,12 +1524,12 @@ static void queue_commands_from_cert(struct command **tail, while (boc < eoc) { const char *eol = memchr(boc, '\n', eoc - boc); - tail = queue_command(tail, boc, eol ? eol - boc : eoc - eol); + tail = queue_command(tail, boc, eol ? eol - boc : eoc - boc); boc = eol ? eol + 1 : eoc; } } -static struct command *read_head_info(struct sha1_array *shallow) +static struct command *read_head_info(struct oid_array *shallow) { struct command *commands = NULL; struct command **p = &commands; @@ -1544,12 +1541,12 @@ static struct command *read_head_info(struct sha1_array *shallow) if (!line) break; - if (len == 48 && starts_with(line, "shallow ")) { - unsigned char sha1[20]; - if (get_sha1_hex(line + 8, sha1)) + if (len > 8 && starts_with(line, "shallow ")) { + struct object_id oid; + if (get_oid_hex(line + 8, &oid)) die("protocol error: expected shallow sha, got '%s'", line + 8); - sha1_array_append(shallow, sha1); + oid_array_append(shallow, &oid); continue; } @@ -1637,12 +1634,17 @@ static const char *parse_pack_header(struct pack_header *hdr) static const char *pack_lockfile; +static void push_header_arg(struct argv_array *args, struct pack_header *hdr) +{ + argv_array_pushf(args, "--pack_header=%"PRIu32",%"PRIu32, + ntohl(hdr->hdr_version), ntohl(hdr->hdr_entries)); +} + static const char *unpack(int err_fd, struct shallow_info *si) { struct pack_header hdr; const char *hdr_err; int status; - char hdr_arg[38]; struct child_process child = CHILD_PROCESS_INIT; int fsck_objects = (receive_fsck_objects >= 0 ? receive_fsck_objects @@ -1656,9 +1658,6 @@ static const char *unpack(int err_fd, struct shallow_info *si) close(err_fd); return hdr_err; } - snprintf(hdr_arg, sizeof(hdr_arg), - "--pack_header=%"PRIu32",%"PRIu32, - ntohl(hdr.hdr_version), ntohl(hdr.hdr_entries)); if (si->nr_ours || si->nr_theirs) { alt_shallow_file = setup_temporary_shallow(si->shallow); @@ -1682,7 +1681,8 @@ static const char *unpack(int err_fd, struct shallow_info *si) tmp_objdir_add_as_alternate(tmp_objdir); if (ntohl(hdr.hdr_entries) < unpack_limit) { - argv_array_pushl(&child.args, "unpack-objects", hdr_arg, NULL); + argv_array_push(&child.args, "unpack-objects"); + push_header_arg(&child.args, &hdr); if (quiet) argv_array_push(&child.args, "-q"); if (fsck_objects) @@ -1700,8 +1700,8 @@ static const char *unpack(int err_fd, struct shallow_info *si) } else { char hostname[256]; - argv_array_pushl(&child.args, "index-pack", - "--stdin", hdr_arg, NULL); + argv_array_pushl(&child.args, "index-pack", "--stdin", NULL); + push_header_arg(&child.args, &hdr); if (gethostname(hostname, sizeof(hostname))) xsnprintf(hostname, sizeof(hostname), "localhost"); @@ -1807,7 +1807,7 @@ static void prepare_shallow_update(struct command *commands, static void update_shallow_info(struct command *commands, struct shallow_info *si, - struct sha1_array *ref) + struct oid_array *ref) { struct command *cmd; int *ref_status; @@ -1818,9 +1818,9 @@ static void update_shallow_info(struct command *commands, } for (cmd = commands; cmd; cmd = cmd->next) { - if (is_null_sha1(cmd->new_sha1)) + if (is_null_oid(&cmd->new_oid)) continue; - sha1_array_append(ref, cmd->new_sha1); + oid_array_append(ref, &cmd->new_oid); cmd->index = ref->nr - 1; } si->ref = ref; @@ -1833,7 +1833,7 @@ static void update_shallow_info(struct command *commands, ALLOC_ARRAY(ref_status, ref->nr); assign_shallow_commits_to_refs(si, NULL, ref_status); for (cmd = commands; cmd; cmd = cmd->next) { - if (is_null_sha1(cmd->new_sha1)) + if (is_null_oid(&cmd->new_oid)) continue; if (ref_status[cmd->index]) { cmd->error_string = "shallow update not allowed"; @@ -1871,7 +1871,7 @@ static int delete_only(struct command *commands) { struct command *cmd; for (cmd = commands; cmd; cmd = cmd->next) { - if (!is_null_sha1(cmd->new_sha1)) + if (!is_null_oid(&cmd->new_oid)) return 0; } return 1; @@ -1881,8 +1881,8 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix) { int advertise_refs = 0; struct command *commands; - struct sha1_array shallow = SHA1_ARRAY_INIT; - struct sha1_array ref = SHA1_ARRAY_INIT; + struct oid_array shallow = OID_ARRAY_INIT; + struct oid_array ref = OID_ARRAY_INIT; struct shallow_info si; struct option options[] = { @@ -1974,8 +1974,8 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix) } if (use_sideband) packet_flush(1); - sha1_array_clear(&shallow); - sha1_array_clear(&ref); + oid_array_clear(&shallow); + oid_array_clear(&ref); free((void *)push_cert_nonce); return 0; } diff --git a/builtin/replace.c b/builtin/replace.c index f83e7b8fc1..065515baba 100644 --- a/builtin/replace.c +++ b/builtin/replace.c @@ -93,26 +93,31 @@ typedef int (*each_replace_name_fn)(const char *name, const char *ref, static int for_each_replace_name(const char **argv, each_replace_name_fn fn) { const char **p, *full_hex; - char ref[PATH_MAX]; + struct strbuf ref = STRBUF_INIT; + size_t base_len; int had_error = 0; struct object_id oid; + strbuf_addstr(&ref, git_replace_ref_base); + base_len = ref.len; + for (p = argv; *p; p++) { if (get_oid(*p, &oid)) { error("Failed to resolve '%s' as a valid ref.", *p); had_error = 1; continue; } - full_hex = oid_to_hex(&oid); - snprintf(ref, sizeof(ref), "%s%s", git_replace_ref_base, full_hex); - /* read_ref() may reuse the buffer */ - full_hex = ref + strlen(git_replace_ref_base); - if (read_ref(ref, oid.hash)) { + + strbuf_setlen(&ref, base_len); + strbuf_addstr(&ref, oid_to_hex(&oid)); + full_hex = ref.buf + base_len; + + if (read_ref(ref.buf, oid.hash)) { error("replace ref '%s' not found.", full_hex); had_error = 1; continue; } - if (fn(full_hex, ref, &oid)) + if (fn(full_hex, ref.buf, &oid)) had_error = 1; } return had_error; @@ -129,21 +134,18 @@ static int delete_replace_ref(const char *name, const char *ref, static void check_ref_valid(struct object_id *object, struct object_id *prev, - char *ref, - int ref_size, + struct strbuf *ref, int force) { - if (snprintf(ref, ref_size, - "%s%s", git_replace_ref_base, - oid_to_hex(object)) > ref_size - 1) - die("replace ref name too long: %.*s...", 50, ref); - if (check_refname_format(ref, 0)) - die("'%s' is not a valid ref name.", ref); - - if (read_ref(ref, prev->hash)) + strbuf_reset(ref); + strbuf_addf(ref, "%s%s", git_replace_ref_base, oid_to_hex(object)); + if (check_refname_format(ref->buf, 0)) + die("'%s' is not a valid ref name.", ref->buf); + + if (read_ref(ref->buf, prev->hash)) oidclr(prev); else if (!force) - die("replace ref '%s' already exists", ref); + die("replace ref '%s' already exists", ref->buf); } static int replace_object_oid(const char *object_ref, @@ -154,7 +156,7 @@ static int replace_object_oid(const char *object_ref, { struct object_id prev; enum object_type obj_type, repl_type; - char ref[PATH_MAX]; + struct strbuf ref = STRBUF_INIT; struct ref_transaction *transaction; struct strbuf err = STRBUF_INIT; @@ -167,16 +169,17 @@ static int replace_object_oid(const char *object_ref, object_ref, typename(obj_type), replace_ref, typename(repl_type)); - check_ref_valid(object, &prev, ref, sizeof(ref), force); + check_ref_valid(object, &prev, &ref, force); transaction = ref_transaction_begin(&err); if (!transaction || - ref_transaction_update(transaction, ref, repl->hash, prev.hash, + ref_transaction_update(transaction, ref.buf, repl->hash, prev.hash, 0, NULL, &err) || ref_transaction_commit(transaction, &err)) die("%s", err.buf); ref_transaction_free(transaction); + strbuf_release(&ref); return 0; } @@ -280,7 +283,7 @@ static int edit_and_replace(const char *object_ref, int force, int raw) char *tmpfile = git_pathdup("REPLACE_EDITOBJ"); enum object_type type; struct object_id old, new, prev; - char ref[PATH_MAX]; + struct strbuf ref = STRBUF_INIT; if (get_oid(object_ref, &old) < 0) die("Not a valid object name: '%s'", object_ref); @@ -289,7 +292,8 @@ static int edit_and_replace(const char *object_ref, int force, int raw) if (type < 0) die("unable to get object type for %s", oid_to_hex(&old)); - check_ref_valid(&old, &prev, ref, sizeof(ref), force); + check_ref_valid(&old, &prev, &ref, force); + strbuf_release(&ref); export_object(&old, type, raw, tmpfile); if (launch_editor(tmpfile, NULL, NULL) < 0) diff --git a/builtin/rev-list.c b/builtin/rev-list.c index 0aa93d5891..bcf77f0b8a 100644 --- a/builtin/rev-list.c +++ b/builtin/rev-list.c @@ -212,7 +212,7 @@ static void print_var_int(const char *var, int val) static int show_bisect_vars(struct rev_list_info *info, int reaches, int all) { int cnt, flags = info->flags; - char hex[GIT_SHA1_HEXSZ + 1] = ""; + char hex[GIT_MAX_HEXSZ + 1] = ""; struct commit_list *tried; struct rev_info *revs = info->revs; diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c index 2549643267..0513330910 100644 --- a/builtin/rev-parse.c +++ b/builtin/rev-parse.c @@ -205,21 +205,22 @@ static int anti_reference(const char *refname, const struct object_id *oid, int return 0; } -static int show_abbrev(const unsigned char *sha1, void *cb_data) +static int show_abbrev(const struct object_id *oid, void *cb_data) { - show_rev(NORMAL, sha1, NULL); + show_rev(NORMAL, oid->hash, NULL); return 0; } static void show_datestring(const char *flag, const char *datestr) { - static char buffer[100]; + char *buffer; /* date handling requires both flags and revs */ if ((filter & (DO_FLAGS | DO_REVS)) != (DO_FLAGS | DO_REVS)) return; - snprintf(buffer, sizeof(buffer), "%s%lu", flag, approxidate(datestr)); + buffer = xstrfmt("%s%lu", flag, approxidate(datestr)); show(buffer); + free(buffer); } static int show_file(const char *arg, int output_prefix) @@ -228,9 +229,9 @@ static int show_file(const char *arg, int output_prefix) if ((filter & (DO_NONFLAGS|DO_NOREV)) == (DO_NONFLAGS|DO_NOREV)) { if (output_prefix) { const char *prefix = startup_info->prefix; - show(prefix_filename(prefix, - prefix ? strlen(prefix) : 0, - arg)); + char *fname = prefix_filename(prefix, arg); + show(fname); + free(fname); } else show(arg); return 1; @@ -536,6 +537,34 @@ N_("git rev-parse --parseopt [<options>] -- [<args>...]\n" "\n" "Run \"git rev-parse --parseopt -h\" for more information on the first usage."); +/* + * Parse "opt" or "opt=<value>", setting value respectively to either + * NULL or the string after "=". + */ +static int opt_with_value(const char *arg, const char *opt, const char **value) +{ + if (skip_prefix(arg, opt, &arg)) { + if (!*arg) { + *value = NULL; + return 1; + } + if (*arg++ == '=') { + *value = arg; + return 1; + } + } + return 0; +} + +static void handle_ref_opt(const char *pattern, const char *prefix) +{ + if (pattern) + for_each_glob_ref_in(show_reference, pattern, prefix, NULL); + else + for_each_ref_in(prefix, show_reference, NULL); + clear_ref_exclusion(&ref_excludes); +} + int cmd_rev_parse(int argc, const char **argv, const char *prefix) { int i, as_is = 0, verify = 0, quiet = 0, revs_count = 0, type = 0; @@ -675,14 +704,13 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) flags |= GET_SHA1_QUIETLY; continue; } - if (!strcmp(arg, "--short") || - starts_with(arg, "--short=")) { + if (opt_with_value(arg, "--short", &arg)) { filter &= ~(DO_FLAGS|DO_NOREV); verify = 1; abbrev = DEFAULT_ABBREV; - if (!arg[7]) + if (!arg) continue; - abbrev = strtoul(arg + 8, NULL, 10); + abbrev = strtoul(arg, NULL, 10); if (abbrev < MINIMUM_ABBREV) abbrev = MINIMUM_ABBREV; else if (40 <= abbrev) @@ -705,17 +733,17 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) symbolic = SHOW_SYMBOLIC_FULL; continue; } - if (starts_with(arg, "--abbrev-ref") && - (!arg[12] || arg[12] == '=')) { + if (opt_with_value(arg, "--abbrev-ref", &arg)) { abbrev_ref = 1; abbrev_ref_strict = warn_ambiguous_refs; - if (arg[12] == '=') { - if (!strcmp(arg + 13, "strict")) + if (arg) { + if (!strcmp(arg, "strict")) abbrev_ref_strict = 1; - else if (!strcmp(arg + 13, "loose")) + else if (!strcmp(arg, "loose")) abbrev_ref_strict = 0; else - die("unknown mode for %s", arg); + die("unknown mode for --abbrev-ref: %s", + arg); } continue; } @@ -723,8 +751,8 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) for_each_ref(show_reference, NULL); continue; } - if (starts_with(arg, "--disambiguate=")) { - for_each_abbrev(arg + 15, show_abbrev, NULL); + if (skip_prefix(arg, "--disambiguate=", &arg)) { + for_each_abbrev(arg, show_abbrev, NULL); continue; } if (!strcmp(arg, "--bisect")) { @@ -732,46 +760,24 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) for_each_ref_in("refs/bisect/good", anti_reference, NULL); continue; } - if (starts_with(arg, "--branches=")) { - for_each_glob_ref_in(show_reference, arg + 11, - "refs/heads/", NULL); - clear_ref_exclusion(&ref_excludes); - continue; - } - if (!strcmp(arg, "--branches")) { - for_each_branch_ref(show_reference, NULL); - clear_ref_exclusion(&ref_excludes); - continue; - } - if (starts_with(arg, "--tags=")) { - for_each_glob_ref_in(show_reference, arg + 7, - "refs/tags/", NULL); - clear_ref_exclusion(&ref_excludes); - continue; - } - if (!strcmp(arg, "--tags")) { - for_each_tag_ref(show_reference, NULL); - clear_ref_exclusion(&ref_excludes); + if (opt_with_value(arg, "--branches", &arg)) { + handle_ref_opt(arg, "refs/heads/"); continue; } - if (starts_with(arg, "--glob=")) { - for_each_glob_ref(show_reference, arg + 7, NULL); - clear_ref_exclusion(&ref_excludes); + if (opt_with_value(arg, "--tags", &arg)) { + handle_ref_opt(arg, "refs/tags/"); continue; } - if (starts_with(arg, "--remotes=")) { - for_each_glob_ref_in(show_reference, arg + 10, - "refs/remotes/", NULL); - clear_ref_exclusion(&ref_excludes); + if (skip_prefix(arg, "--glob=", &arg)) { + handle_ref_opt(arg, NULL); continue; } - if (!strcmp(arg, "--remotes")) { - for_each_remote_ref(show_reference, NULL); - clear_ref_exclusion(&ref_excludes); + if (opt_with_value(arg, "--remotes", &arg)) { + handle_ref_opt(arg, "refs/remotes/"); continue; } - if (starts_with(arg, "--exclude=")) { - add_ref_exclusion(&ref_excludes, arg + 10); + if (skip_prefix(arg, "--exclude=", &arg)) { + add_ref_exclusion(&ref_excludes, arg); continue; } if (!strcmp(arg, "--show-toplevel")) { @@ -872,20 +878,20 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) } continue; } - if (starts_with(arg, "--since=")) { - show_datestring("--max-age=", arg+8); + if (skip_prefix(arg, "--since=", &arg)) { + show_datestring("--max-age=", arg); continue; } - if (starts_with(arg, "--after=")) { - show_datestring("--max-age=", arg+8); + if (skip_prefix(arg, "--after=", &arg)) { + show_datestring("--max-age=", arg); continue; } - if (starts_with(arg, "--before=")) { - show_datestring("--min-age=", arg+9); + if (skip_prefix(arg, "--before=", &arg)) { + show_datestring("--min-age=", arg); continue; } - if (starts_with(arg, "--until=")) { - show_datestring("--min-age=", arg+8); + if (skip_prefix(arg, "--until=", &arg)) { + show_datestring("--min-age=", arg); continue; } if (show_flag(arg) && verify) diff --git a/builtin/send-pack.c b/builtin/send-pack.c index 1ff5a67538..b8e2e74fe0 100644 --- a/builtin/send-pack.c +++ b/builtin/send-pack.c @@ -131,8 +131,8 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) const char *dest = NULL; int fd[2]; struct child_process *conn; - struct sha1_array extra_have = SHA1_ARRAY_INIT; - struct sha1_array shallow = SHA1_ARRAY_INIT; + struct oid_array extra_have = OID_ARRAY_INIT; + struct oid_array shallow = OID_ARRAY_INIT; struct ref *remote_refs, *local_refs; int ret; int helper_status = 0; @@ -144,6 +144,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) unsigned force_update = 0; unsigned quiet = 0; int push_cert = 0; + struct string_list push_options = STRING_LIST_INIT_NODUP; unsigned use_thin_pack = 0; unsigned atomic = 0; unsigned stateless_rpc = 0; @@ -165,6 +166,9 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) { OPTION_CALLBACK, 0, "signed", &push_cert, "yes|no|if-asked", N_("GPG sign the push"), PARSE_OPT_OPTARG, option_parse_push_signed }, + OPT_STRING_LIST(0, "push-option", &push_options, + N_("server-specific"), + N_("option to transmit")), OPT_BOOL(0, "progress", &progress, N_("force progress reporting")), OPT_BOOL(0, "thin", &use_thin_pack, N_("use thin pack")), OPT_BOOL(0, "atomic", &atomic, N_("request atomic transaction on remote side")), @@ -199,6 +203,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) args.use_thin_pack = use_thin_pack; args.atomic = atomic; args.stateless_rpc = stateless_rpc; + args.push_options = push_options.nr ? &push_options : NULL; if (from_stdin) { struct argv_array all_refspecs = ARGV_ARRAY_INIT; diff --git a/builtin/shortlog.c b/builtin/shortlog.c index f78bb4818d..7cff1839fc 100644 --- a/builtin/shortlog.c +++ b/builtin/shortlog.c @@ -149,7 +149,6 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit) ctx.fmt = CMIT_FMT_USERFORMAT; ctx.abbrev = log->abbrev; ctx.print_email_subject = 1; - ctx.after_subject = ""; ctx.date_mode.type = DATE_NORMAL; ctx.output_encoding = get_log_output_encoding(); diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index 15a5430c00..36e4231821 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -270,6 +270,29 @@ static int module_list_compute(int argc, const char **argv, return result; } +static void module_list_active(struct module_list *list) +{ + int i; + struct module_list active_modules = MODULE_LIST_INIT; + + gitmodules_config(); + + for (i = 0; i < list->nr; i++) { + const struct cache_entry *ce = list->entries[i]; + + if (!is_submodule_initialized(ce->name)) + continue; + + ALLOC_GROW(active_modules.entries, + active_modules.nr + 1, + active_modules.alloc); + active_modules.entries[active_modules.nr++] = ce; + } + + free(list->entries); + *list = active_modules; +} + static int module_list(int argc, const char **argv, const char *prefix) { int i; @@ -334,6 +357,18 @@ static void init_submodule(const char *path, const char *prefix, int quiet) displaypath); /* + * NEEDSWORK: In a multi-working-tree world, this needs to be + * set in the per-worktree config. + * + * Set active flag for the submodule being initialized + */ + if (!is_submodule_initialized(path)) { + strbuf_reset(&sb); + strbuf_addf(&sb, "submodule.%s.active", sub->name); + git_config_set_gently(sb.buf, "true"); + } + + /* * Copy url setting when it is not set yet. * To look up the url in .git/config, we must not fall back to * .gitmodules, so look it up directly. @@ -420,6 +455,13 @@ static int module_init(int argc, const char **argv, const char *prefix) if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0) return 1; + /* + * If there are no path args and submodule.active is set then, + * by default, only initialize 'active' modules. + */ + if (!argc && git_config_get_value_multi("submodule.active")) + module_list_active(&list); + for (i = 0; i < list.nr; i++) init_submodule(list.entries[i]->name, prefix, quiet); @@ -577,9 +619,7 @@ static int module_clone(int argc, const char **argv, const char *prefix) const char *name = NULL, *url = NULL, *depth = NULL; int quiet = 0; int progress = 0; - FILE *submodule_dot_git; char *p, *path = NULL, *sm_gitdir; - struct strbuf rel_path = STRBUF_INIT; struct strbuf sb = STRBUF_INIT; struct string_list reference = STRING_LIST_INIT_NODUP; char *sm_alternate = NULL, *error_strategy = NULL; @@ -651,27 +691,12 @@ static int module_clone(int argc, const char **argv, const char *prefix) strbuf_reset(&sb); } - /* Write a .git file in the submodule to redirect to the superproject. */ - strbuf_addf(&sb, "%s/.git", path); - if (safe_create_leading_directories_const(sb.buf) < 0) - die(_("could not create leading directories of '%s'"), sb.buf); - submodule_dot_git = fopen(sb.buf, "w"); - if (!submodule_dot_git) - die_errno(_("cannot open file '%s'"), sb.buf); - - fprintf_or_die(submodule_dot_git, "gitdir: %s\n", - relative_path(sm_gitdir, path, &rel_path)); - if (fclose(submodule_dot_git)) - die(_("could not close file %s"), sb.buf); - strbuf_reset(&sb); - strbuf_reset(&rel_path); + /* Connect module worktree and git dir */ + connect_work_tree_and_git_dir(path, sm_gitdir); - /* Redirect the worktree of the submodule in the superproject's config */ p = git_pathdup_submodule(path, "config"); if (!p) die(_("could not get submodule directory for '%s'"), path); - git_config_set_in_file(p, "core.worktree", - relative_path(path, sm_gitdir, &rel_path)); /* setup alternateLocation and alternateErrorStrategy in the cloned submodule if needed */ git_config_get_string("submodule.alternateLocation", &sm_alternate); @@ -687,7 +712,6 @@ static int module_clone(int argc, const char **argv, const char *prefix) free(error_strategy); strbuf_release(&sb); - strbuf_release(&rel_path); free(sm_gitdir); free(path); free(p); @@ -759,7 +783,6 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce, struct strbuf displaypath_sb = STRBUF_INIT; struct strbuf sb = STRBUF_INIT; const char *displaypath = NULL; - char *url = NULL; int needs_cloning = 0; if (ce_stage(ce)) { @@ -793,15 +816,8 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce, goto cleanup; } - /* - * Looking up the url in .git/config. - * We must not fall back to .gitmodules as we only want - * to process configured submodules. - */ - strbuf_reset(&sb); - strbuf_addf(&sb, "submodule.%s.url", sub->name); - git_config_get_string(sb.buf, &url); - if (!url) { + /* Check if the submodule has been initialized. */ + if (!is_submodule_initialized(ce->name)) { next_submodule_warn_missing(suc, out, displaypath); goto cleanup; } @@ -835,7 +851,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce, argv_array_push(&child->args, "--depth=1"); argv_array_pushl(&child->args, "--path", sub->path, NULL); argv_array_pushl(&child->args, "--name", sub->name, NULL); - argv_array_pushl(&child->args, "--url", url, NULL); + argv_array_pushl(&child->args, "--url", sub->url, NULL); if (suc->references.nr) { struct string_list_item *item; for_each_string_list_item(item, &suc->references) @@ -845,7 +861,6 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce, argv_array_push(&child->args, suc->depth); cleanup: - free(url); strbuf_reset(&displaypath_sb); strbuf_reset(&sb); @@ -1090,6 +1105,50 @@ static int resolve_remote_submodule_branch(int argc, const char **argv, return 0; } +static int push_check(int argc, const char **argv, const char *prefix) +{ + struct remote *remote; + + if (argc < 2) + die("submodule--helper push-check requires at least 1 argument"); + + /* + * The remote must be configured. + * This is to avoid pushing to the exact same URL as the parent. + */ + remote = pushremote_get(argv[1]); + if (!remote || remote->origin == REMOTE_UNCONFIGURED) + die("remote '%s' not configured", argv[1]); + + /* Check the refspec */ + if (argc > 2) { + int i, refspec_nr = argc - 2; + struct ref *local_refs = get_local_heads(); + struct refspec *refspec = parse_push_refspec(refspec_nr, + argv + 2); + + for (i = 0; i < refspec_nr; i++) { + struct refspec *rs = refspec + i; + + 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) + die("src refspec '%s' must name a ref", + rs->src); + } + free_refspec(refspec_nr, refspec); + } + + return 0; +} + static int absorb_git_dirs(int argc, const char **argv, const char *prefix) { int i; @@ -1127,6 +1186,16 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix) return 0; } +static int is_active(int argc, const char **argv, const char *prefix) +{ + if (argc != 2) + die("submodule--helper is-active takes exactly 1 argument"); + + gitmodules_config(); + + return !is_submodule_initialized(argv[1]); +} + #define SUPPORT_SUPER_PREFIX (1<<0) struct cmd_struct { @@ -1145,7 +1214,9 @@ static struct cmd_struct commands[] = { {"resolve-relative-url-test", resolve_relative_url_test, 0}, {"init", module_init, SUPPORT_SUPER_PREFIX}, {"remote-branch", resolve_remote_submodule_branch, 0}, + {"push-check", push_check, 0}, {"absorb-git-dirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX}, + {"is-active", is_active, 0}, }; int cmd_submodule__helper(int argc, const char **argv, const char *prefix) diff --git a/builtin/tag.c b/builtin/tag.c index ad29be6923..222404522f 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -22,7 +22,7 @@ static const char * const git_tag_usage[] = { N_("git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] <tagname> [<head>]"), N_("git tag -d <tagname>..."), - N_("git tag -l [-n[<num>]] [--contains <commit>] [--points-at <object>]" + N_("git tag -l [-n[<num>]] [--contains <commit>] [--no-contains <commit>] [--points-at <object>]" "\n\t\t[--format=<format>] [--[no-]merged [<commit>]] [<pattern>...]"), N_("git tag -v [--format=<format>] <tagname>..."), NULL @@ -72,25 +72,22 @@ static int for_each_tag_name(const char **argv, each_tag_name_fn fn, const void *cb_data) { const char **p; - char ref[PATH_MAX]; + struct strbuf ref = STRBUF_INIT; int had_error = 0; unsigned char sha1[20]; for (p = argv; *p; p++) { - if (snprintf(ref, sizeof(ref), "refs/tags/%s", *p) - >= sizeof(ref)) { - error(_("tag name too long: %.*s..."), 50, *p); - had_error = 1; - continue; - } - if (read_ref(ref, sha1)) { + strbuf_reset(&ref); + strbuf_addf(&ref, "refs/tags/%s", *p); + if (read_ref(ref.buf, sha1)) { error(_("tag '%s' not found."), *p); had_error = 1; continue; } - if (fn(*p, ref, sha1, cb_data)) + if (fn(*p, ref.buf, sha1, cb_data)) had_error = 1; } + strbuf_release(&ref); return had_error; } @@ -231,26 +228,22 @@ static void create_tag(const unsigned char *object, const char *tag, unsigned char *prev, unsigned char *result) { enum object_type type; - char header_buf[1024]; - int header_len; + struct strbuf header = STRBUF_INIT; char *path = NULL; type = sha1_object_info(object, NULL); if (type <= OBJ_NONE) die(_("bad object type.")); - header_len = snprintf(header_buf, sizeof(header_buf), - "object %s\n" - "type %s\n" - "tag %s\n" - "tagger %s\n\n", - sha1_to_hex(object), - typename(type), - tag, - git_committer_info(IDENT_STRICT)); - - if (header_len > sizeof(header_buf) - 1) - die(_("tag header too big.")); + strbuf_addf(&header, + "object %s\n" + "type %s\n" + "tag %s\n" + "tagger %s\n\n", + sha1_to_hex(object), + typename(type), + tag, + git_committer_info(IDENT_STRICT)); if (!opt->message_given) { int fd; @@ -288,7 +281,8 @@ static void create_tag(const unsigned char *object, const char *tag, if (!opt->message_given && !buf->len) die(_("no tag message?")); - strbuf_insert(buf, 0, header_buf, header_len); + strbuf_insert(buf, 0, header.buf, header.len); + strbuf_release(&header); if (build_tag_object(buf, opt->sign, result) < 0) { if (path) @@ -424,14 +418,17 @@ int cmd_tag(int argc, const char **argv, const char *prefix) OPT_GROUP(N_("Tag listing options")), OPT_COLUMN(0, "column", &colopts, N_("show tag list in columns")), OPT_CONTAINS(&filter.with_commit, N_("print only tags that contain the commit")), + OPT_NO_CONTAINS(&filter.no_commit, N_("print only tags that don't contain the commit")), OPT_WITH(&filter.with_commit, N_("print only tags that contain the commit")), + OPT_WITHOUT(&filter.no_commit, N_("print only tags that don't contain the commit")), OPT_MERGED(&filter, N_("print only tags that are merged")), OPT_NO_MERGED(&filter, N_("print only tags that are not merged")), OPT_CALLBACK(0 , "sort", sorting_tail, N_("key"), N_("field name to sort on"), &parse_opt_ref_sorting), { OPTION_CALLBACK, 0, "points-at", &filter.points_at, N_("object"), - N_("print only tags of the object"), 0, parse_opt_object_name + N_("print only tags of the object"), PARSE_OPT_LASTARG_DEFAULT, + parse_opt_object_name, (intptr_t) "HEAD" }, OPT_STRING( 0 , "format", &format, N_("format"), N_("format to use for the output")), OPT_BOOL('i', "ignore-case", &icase, N_("sorting and filtering are case insensitive")), @@ -454,8 +451,14 @@ int cmd_tag(int argc, const char **argv, const char *prefix) } create_tag_object = (opt.sign || annotate || msg.given || msgfile); - if (argc == 0 && !cmdmode) - cmdmode = 'l'; + if (!cmdmode) { + if (argc == 0) + cmdmode = 'l'; + else if (filter.with_commit || filter.no_commit || + filter.points_at.nr || filter.merge_commit || + filter.lines != -1) + cmdmode = 'l'; + } if ((create_tag_object || force) && (cmdmode != 0)) usage_with_options(git_tag_usage, options); @@ -485,13 +488,15 @@ int cmd_tag(int argc, const char **argv, const char *prefix) return ret; } if (filter.lines != -1) - die(_("-n option is only allowed with -l.")); + die(_("-n option is only allowed in list mode")); if (filter.with_commit) - die(_("--contains option is only allowed with -l.")); + die(_("--contains option is only allowed in list mode")); + if (filter.no_commit) + die(_("--no-contains option is only allowed in list mode")); if (filter.points_at.nr) - die(_("--points-at option is only allowed with -l.")); + die(_("--points-at option is only allowed in list mode")); if (filter.merge_commit) - die(_("--merged and --no-merged option are only allowed with -l")); + die(_("--merged and --no-merged options are only allowed in list mode")); if (cmdmode == 'd') return for_each_tag_name(argv, delete_tag, NULL); if (cmdmode == 'v') { diff --git a/builtin/update-index.c b/builtin/update-index.c index d74d72cc7f..ebfc09faa0 100644 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@ -125,12 +125,16 @@ static int test_if_untracked_cache_is_supported(void) struct stat st; struct stat_data base; int fd, ret = 0; + char *cwd; strbuf_addstr(&mtime_dir, "mtime-test-XXXXXX"); if (!mkdtemp(mtime_dir.buf)) die_errno("Could not make temporary directory"); - fprintf(stderr, _("Testing mtime in '%s' "), xgetcwd()); + cwd = xgetcwd(); + fprintf(stderr, _("Testing mtime in '%s' "), cwd); + free(cwd); + atexit(remove_test_directory); xstat_mtime_dir(&st); fill_stat_data(&base, &st); diff --git a/builtin/worktree.c b/builtin/worktree.c index 831fe058a5..9993ded41a 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -318,7 +318,8 @@ static int add(int ac, const char **av, const char *prefix) { struct add_opts opts; const char *new_branch_force = NULL; - const char *path, *branch; + char *path; + const char *branch; struct option options[] = { OPT__FORCE(&opts.force, N_("checkout <branch> even if already checked out in other worktree")), OPT_STRING('b', NULL, &opts.new_branch, N_("branch"), @@ -338,7 +339,7 @@ static int add(int ac, const char **av, const char *prefix) if (ac < 1 || ac > 2) usage_with_options(worktree_usage, options); - path = prefix_filename(prefix, strlen(prefix), av[0]); + path = prefix_filename(prefix, av[0]); branch = ac < 2 ? "HEAD" : av[1]; if (!strcmp(branch, "-")) diff --git a/bulk-checkin.c b/bulk-checkin.c index 991b4a13e2..ddb6070c4c 100644 --- a/bulk-checkin.c +++ b/bulk-checkin.c @@ -105,7 +105,7 @@ static int stream_to_pack(struct bulk_checkin_state *state, git_deflate_init(&s, pack_compression_level); - hdrlen = encode_in_pack_object_header(type, size, obuf); + hdrlen = encode_in_pack_object_header(obuf, sizeof(obuf), type, size); s.next_out = obuf + hdrlen; s.avail_out = sizeof(obuf) - hdrlen; @@ -66,8 +66,12 @@ unsigned long git_deflate_bound(git_zstream *, unsigned long); #define GIT_SHA1_RAWSZ 20 #define GIT_SHA1_HEXSZ (2 * GIT_SHA1_RAWSZ) +/* The length in byte and in hex digits of the largest possible hash value. */ +#define GIT_MAX_RAWSZ GIT_SHA1_RAWSZ +#define GIT_MAX_HEXSZ GIT_SHA1_HEXSZ + struct object_id { - unsigned char hash[GIT_SHA1_RAWSZ]; + unsigned char hash[GIT_MAX_RAWSZ]; }; #if defined(DT_UNKNOWN) && !defined(NO_D_TYPE_IN_DIRENT) @@ -343,6 +347,7 @@ struct index_state { extern struct index_state the_index; /* Name hashing */ +extern int test_lazy_init_name_hash(struct index_state *istate, int try_threaded); extern void add_name_hash(struct index_state *istate, struct cache_entry *ce); extern void remove_name_hash(struct index_state *istate, struct cache_entry *ce); extern void free_name_hash(struct index_state *istate); @@ -410,6 +415,7 @@ 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" @@ -529,7 +535,19 @@ extern const char *setup_git_directory_gently(int *); extern const char *setup_git_directory(void); extern char *prefix_path(const char *prefix, int len, const char *path); extern char *prefix_path_gently(const char *prefix, int len, int *remaining, const char *path); -extern const char *prefix_filename(const char *prefix, int len, const char *path); + +/* + * Concatenate "prefix" (if len is non-zero) and "path", with no + * connecting characters (so "prefix" should end with a "/"). + * Unlike prefix_path, this should be used if the named file does + * not have to interact with index entry; i.e. name of a random file + * on the filesystem. + * + * The return value is always a newly allocated string (even if the + * prefix was empty). + */ +extern char *prefix_filename(const char *prefix, const char *path); + extern int check_filename(const char *prefix, const char *name); extern void verify_filename(const char *prefix, const char *name, @@ -964,7 +982,7 @@ extern char *sha1_pack_index_name(const unsigned char *sha1); extern const char *find_unique_abbrev(const unsigned char *sha1, int len); extern int find_unique_abbrev_r(char *hex, const unsigned char *sha1, int len); -extern const unsigned char null_sha1[GIT_SHA1_RAWSZ]; +extern const unsigned char null_sha1[GIT_MAX_RAWSZ]; extern const struct object_id null_oid; static inline int hashcmp(const unsigned char *sha1, const unsigned char *sha2) @@ -1176,6 +1194,13 @@ extern int is_ntfs_dotgit(const char *name); */ extern char *xdg_config_home(const char *filename); +/** + * Return a newly allocated string with the evaluation of + * "$XDG_CACHE_HOME/git/$filename" if $XDG_CACHE_HOME is non-empty, otherwise + * "$HOME/.cache/git/$filename". Return NULL upon error. + */ +extern char *xdg_cache_home(const char *filename); + /* object replacement */ #define LOOKUP_REPLACE_OBJECT 1 #define LOOKUP_UNKNOWN_OBJECT 2 @@ -1339,7 +1364,7 @@ extern int get_sha1_with_context(const char *str, unsigned flags, unsigned char extern int get_oid(const char *str, struct object_id *oid); -typedef int each_abbrev_fn(const unsigned char *sha1, void *); +typedef int each_abbrev_fn(const struct object_id *oid, void *); extern int for_each_abbrev(const char *prefix, each_abbrev_fn, void *); extern int set_disambiguate_hint_config(const char *var, const char *value); @@ -1654,6 +1679,30 @@ extern struct packed_git *find_sha1_pack(const unsigned char *sha1, extern void pack_report(void); /* + * Create a temporary file rooted in the object database directory, or + * die on failure. The filename is taken from "pattern", which should have the + * usual "XXXXXX" trailer, and the resulting filename is written into the + * "template" buffer. Returns the open descriptor. + */ +extern int odb_mkstemp(struct strbuf *template, const char *pattern); + +/* + * Generate the filename to be used for a pack file with checksum "sha1" and + * extension "ext". The result is written into the strbuf "buf", overwriting + * any existing contents. A pointer to buf->buf is returned as a convenience. + * + * Example: odb_pack_name(out, sha1, "idx") => ".git/objects/pack/pack-1234..idx" + */ +extern char *odb_pack_name(struct strbuf *buf, const unsigned char *sha1, const char *ext); + +/* + * Create a pack .keep file named "name" (which should generally be the output + * of odb_pack_name). Returns a file descriptor opened for writing, or -1 on + * error. + */ +extern int odb_pack_keep(const char *name); + +/* * mmap the index file for the specified packfile (if it is not * already mmapped). Return 0 on success. */ diff --git a/ci/run-windows-build.sh b/ci/run-windows-build.sh new file mode 100755 index 0000000000..4e3a50b60e --- /dev/null +++ b/ci/run-windows-build.sh @@ -0,0 +1,74 @@ +#!/usr/bin/env bash +# +# Script to trigger the a Git for Windows build and test run. +# Set the $GFW_CI_TOKEN as environment variable. +# Pass the branch (only branches on https://github.com/git/git are +# supported) and a commit hash. +# + +test $# -ne 2 && echo "Unexpected number of parameters" && exit 1 +test -z "$GFW_CI_TOKEN" && echo "GFW_CI_TOKEN not defined" && exit + +BRANCH=$1 +COMMIT=$2 + +gfwci () { + local CURL_ERROR_CODE HTTP_CODE + exec 3>&1 + HTTP_CODE=$(curl \ + -H "Authentication: Bearer $GFW_CI_TOKEN" \ + --silent --retry 5 --write-out '%{HTTP_CODE}' \ + --output >(sed "$(printf '1s/^\xef\xbb\xbf//')" >cat >&3) \ + "https://git-for-windows-ci.azurewebsites.net/api/TestNow?$1" \ + ) + CURL_ERROR_CODE=$? + if test $CURL_ERROR_CODE -ne 0 + then + return $CURL_ERROR_CODE + fi + if test "$HTTP_CODE" -ge 400 && test "$HTTP_CODE" -lt 600 + then + return 127 + fi +} + +# Trigger build job +BUILD_ID=$(gfwci "action=trigger&branch=$BRANCH&commit=$COMMIT&skipTests=false") +if test $? -ne 0 +then + echo "Unable to trigger Visual Studio Team Services Build" + echo "$BUILD_ID" + exit 1 +fi + +# Check if the $BUILD_ID contains a number +case $BUILD_ID in +''|*[!0-9]*) echo "Unexpected build number: $BUILD_ID" && exit 1 +esac + +echo "Visual Studio Team Services Build #${BUILD_ID}" + +# Wait until build job finished +STATUS= +RESULT= +while true +do + LAST_STATUS=$STATUS + STATUS=$(gfwci "action=status&buildId=$BUILD_ID") + test "$STATUS" = "$LAST_STATUS" || printf "\nStatus: $STATUS " + printf "." + + case "$STATUS" in + inProgress|postponed|notStarted) sleep 10 ;; # continue + "completed: succeeded") RESULT="success"; break;; # success + *) echo "Unhandled status: $STATUS"; break;; # failure + esac +done + +# Print log +echo "" +echo "" +gfwci "action=log&buildId=$BUILD_ID" | cut -c 30- + +# Set exit code for TravisCI +test "$RESULT" = "success" diff --git a/combine-diff.c b/combine-diff.c index 59501db99a..2848034fe9 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -292,9 +292,10 @@ static char *grab_blob(const struct object_id *oid, unsigned int mode, enum object_type type; if (S_ISGITLINK(mode)) { - blob = xmalloc(100); - *size = snprintf(blob, 100, - "Subproject commit %s\n", oid_to_hex(oid)); + struct strbuf buf = STRBUF_INIT; + strbuf_addf(&buf, "Subproject commit %s\n", oid_to_hex(oid)); + *size = buf.len; + blob = strbuf_detach(&buf, NULL); } else if (is_null_oid(oid)) { /* deleted blob */ *size = 0; @@ -1311,7 +1312,7 @@ static const char *path_path(void *obj) /* find set of paths that every parent touches */ static struct combine_diff_path *find_paths_generic(const unsigned char *sha1, - const struct sha1_array *parents, struct diff_options *opt) + const struct oid_array *parents, struct diff_options *opt) { struct combine_diff_path *paths = NULL; int i, num_parent = parents->nr; @@ -1335,7 +1336,7 @@ static struct combine_diff_path *find_paths_generic(const unsigned char *sha1, opt->output_format = stat_opt; else opt->output_format = DIFF_FORMAT_NO_OUTPUT; - diff_tree_sha1(parents->sha1[i], sha1, "", opt); + diff_tree_sha1(parents->oid[i].hash, sha1, "", opt); diffcore_std(opt); paths = intersect_paths(paths, i, num_parent); @@ -1359,7 +1360,7 @@ static struct combine_diff_path *find_paths_generic(const unsigned char *sha1, * rename/copy detection, etc, comparing all trees simultaneously (= faster). */ static struct combine_diff_path *find_paths_multitree( - const unsigned char *sha1, const struct sha1_array *parents, + const unsigned char *sha1, const struct oid_array *parents, struct diff_options *opt) { int i, nparent = parents->nr; @@ -1369,7 +1370,7 @@ static struct combine_diff_path *find_paths_multitree( ALLOC_ARRAY(parents_sha1, nparent); for (i = 0; i < nparent; i++) - parents_sha1[i] = parents->sha1[i]; + parents_sha1[i] = parents->oid[i].hash; /* fake list head, so worker can assume it is non-NULL */ paths_head.next = NULL; @@ -1384,7 +1385,7 @@ static struct combine_diff_path *find_paths_multitree( void diff_tree_combined(const unsigned char *sha1, - const struct sha1_array *parents, + const struct oid_array *parents, int dense, struct rev_info *rev) { @@ -1462,7 +1463,7 @@ void diff_tree_combined(const unsigned char *sha1, if (stat_opt) { diffopts.output_format = stat_opt; - diff_tree_sha1(parents->sha1[0], sha1, "", &diffopts); + diff_tree_sha1(parents->oid[0].hash, sha1, "", &diffopts); diffcore_std(&diffopts); if (opt->orderfile) diffcore_order(opt->orderfile); @@ -1532,12 +1533,12 @@ void diff_tree_combined_merge(const struct commit *commit, int dense, struct rev_info *rev) { struct commit_list *parent = get_saved_parents(rev, commit); - struct sha1_array parents = SHA1_ARRAY_INIT; + struct oid_array parents = OID_ARRAY_INIT; while (parent) { - sha1_array_append(&parents, parent->item->object.oid.hash); + oid_array_append(&parents, &parent->item->object.oid); parent = parent->next; } diff_tree_combined(commit->object.oid.hash, &parents, dense, rev); - sha1_array_clear(&parents); + oid_array_clear(&parents); } @@ -261,7 +261,7 @@ extern struct commit_list *get_merge_bases_many_dirty(struct commit *one, int n, /* largest positive number a signed 32-bit integer can contain */ #define INFINITE_DEPTH 0x7fffffff -struct sha1_array; +struct oid_array; struct ref; extern int register_shallow(const unsigned char *sha1); extern int unregister_shallow(const unsigned char *sha1); @@ -273,18 +273,18 @@ extern struct commit_list *get_shallow_commits_by_rev_list( int ac, const char **av, int shallow_flag, int not_shallow_flag); extern void set_alternate_shallow_file(const char *path, int override); extern int write_shallow_commits(struct strbuf *out, int use_pack_protocol, - const struct sha1_array *extra); + const struct oid_array *extra); extern void setup_alternate_shallow(struct lock_file *shallow_lock, const char **alternate_shallow_file, - const struct sha1_array *extra); -extern const char *setup_temporary_shallow(const struct sha1_array *extra); + const struct oid_array *extra); +extern const char *setup_temporary_shallow(const struct oid_array *extra); extern void advertise_shallow_grafts(int); struct shallow_info { - struct sha1_array *shallow; + struct oid_array *shallow; int *ours, nr_ours; int *theirs, nr_theirs; - struct sha1_array *ref; + struct oid_array *ref; /* for receive-pack */ uint32_t **used_shallow; @@ -295,7 +295,7 @@ struct shallow_info { int nr_commits; }; -extern void prepare_shallow_info(struct shallow_info *, struct sha1_array *); +extern void prepare_shallow_info(struct shallow_info *, struct oid_array *); extern void clear_shallow_info(struct shallow_info *); extern void remove_nonexistent_theirs_shallow(struct shallow_info *); extern void assign_shallow_commits_to_refs(struct shallow_info *info, @@ -13,6 +13,7 @@ #include "hashmap.h" #include "string-list.h" #include "utf8.h" +#include "dir.h" struct config_source { struct config_source *prev; @@ -170,9 +171,94 @@ static int handle_path_include(const char *path, struct config_include_data *inc return ret; } +static int prepare_include_condition_pattern(struct strbuf *pat) +{ + struct strbuf path = STRBUF_INIT; + char *expanded; + int prefix = 0; + + expanded = expand_user_path(pat->buf); + if (expanded) { + strbuf_reset(pat); + strbuf_addstr(pat, expanded); + free(expanded); + } + + if (pat->buf[0] == '.' && is_dir_sep(pat->buf[1])) { + const char *slash; + + if (!cf || !cf->path) + return error(_("relative config include " + "conditionals must come from files")); + + strbuf_add_absolute_path(&path, cf->path); + slash = find_last_dir_sep(path.buf); + if (!slash) + die("BUG: how is this possible?"); + strbuf_splice(pat, 0, 1, path.buf, slash - path.buf); + prefix = slash - path.buf + 1 /* slash */; + } else if (!is_absolute_path(pat->buf)) + strbuf_insert(pat, 0, "**/", 3); + + if (pat->len && is_dir_sep(pat->buf[pat->len - 1])) + strbuf_addstr(pat, "**"); + + strbuf_release(&path); + return prefix; +} + +static int include_by_gitdir(const char *cond, size_t cond_len, int icase) +{ + struct strbuf text = STRBUF_INIT; + struct strbuf pattern = STRBUF_INIT; + int ret = 0, prefix; + + strbuf_add_absolute_path(&text, get_git_dir()); + strbuf_add(&pattern, cond, cond_len); + prefix = prepare_include_condition_pattern(&pattern); + + if (prefix < 0) + goto done; + + if (prefix > 0) { + /* + * perform literal matching on the prefix part so that + * any wildcard character in it can't create side effects. + */ + if (text.len < prefix) + goto done; + if (!icase && strncmp(pattern.buf, text.buf, prefix)) + goto done; + if (icase && strncasecmp(pattern.buf, text.buf, prefix)) + goto done; + } + + ret = !wildmatch(pattern.buf + prefix, text.buf + prefix, + icase ? WM_CASEFOLD : 0, NULL); + +done: + strbuf_release(&pattern); + strbuf_release(&text); + return ret; +} + +static int include_condition_is_true(const char *cond, size_t cond_len) +{ + + if (skip_prefix_mem(cond, cond_len, "gitdir:", &cond, &cond_len)) + return include_by_gitdir(cond, cond_len, 0); + else if (skip_prefix_mem(cond, cond_len, "gitdir/i:", &cond, &cond_len)) + return include_by_gitdir(cond, cond_len, 1); + + /* unknown conditionals are always false */ + return 0; +} + int git_config_include(const char *var, const char *value, void *data) { struct config_include_data *inc = data; + const char *cond, *key; + int cond_len; int ret; /* @@ -185,6 +271,12 @@ int git_config_include(const char *var, const char *value, void *data) if (!strcmp(var, "include.path")) ret = handle_path_include(value, inc); + + if (!parse_config_key(var, "includeif", &cond, &cond_len, &key) && + (cond && include_condition_is_true(cond, cond_len)) && + !strcmp(key, "path")) + ret = handle_path_include(value, inc); + return ret; } @@ -111,8 +111,8 @@ static void annotate_refs_with_symref_info(struct ref *ref) */ struct ref **get_remote_heads(int in, char *src_buf, size_t src_len, struct ref **list, unsigned int flags, - struct sha1_array *extra_have, - struct sha1_array *shallow_points) + struct oid_array *extra_have, + struct oid_array *shallow_points) { struct ref **orig_list = list; @@ -153,7 +153,7 @@ struct ref **get_remote_heads(int in, char *src_buf, size_t src_len, die("protocol error: expected shallow sha-1, got '%s'", arg); if (!shallow_points) die("repository on the other end cannot be shallow"); - sha1_array_append(shallow_points, old_oid.hash); + oid_array_append(shallow_points, &old_oid); continue; } @@ -169,7 +169,7 @@ struct ref **get_remote_heads(int in, char *src_buf, size_t src_len, } if (extra_have && !strcmp(name, ".have")) { - sha1_array_append(extra_have, old_oid.hash); + oid_array_append(extra_have, &old_oid); continue; } diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index fc32286a43..1150164d5c 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -213,6 +213,20 @@ _get_comp_words_by_ref () } fi +# Fills the COMPREPLY array with prefiltered words without any additional +# processing. +# Callers must take care of providing only words that match the current word +# to be completed and adding any prefix and/or suffix (trailing space!), if +# necessary. +# 1: List of newline-separated matching completion words, complete with +# prefix and suffix. +__gitcomp_direct () +{ + local IFS=$'\n' + + COMPREPLY=($1) +} + __gitcompappend () { local x i=${#COMPREPLY[@]} @@ -338,14 +352,27 @@ __git_index_files () done | sort | uniq } +# Lists branches from the local repository. +# 1: A prefix to be added to each listed branch (optional). +# 2: List only branches matching this word (optional; list all branches if +# unset or empty). +# 3: A suffix to be appended to each listed branch (optional). __git_heads () { - __git for-each-ref --format='%(refname:short)' refs/heads + local pfx="${1-}" cur_="${2-}" sfx="${3-}" + + __git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \ + "refs/heads/$cur_*" "refs/heads/$cur_*/**" } +# Lists tags from the local repository. +# Accepts the same positional parameters as __git_heads() above. __git_tags () { - __git for-each-ref --format='%(refname:short)' refs/tags + local pfx="${1-}" cur_="${2-}" sfx="${3-}" + + __git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \ + "refs/tags/$cur_*" "refs/tags/$cur_*/**" } # Lists refs from the local (by default) or from a remote repository. @@ -354,11 +381,21 @@ __git_tags () # Can be the name of a configured remote, a path, or a URL. # 2: In addition to local refs, list unique branches from refs/remotes/ for # 'git checkout's tracking DWIMery (optional; ignored, if set but empty). +# 3: A prefix to be added to each listed ref (optional). +# 4: List only refs matching this word (optional; list all refs if unset or +# empty). +# 5: A suffix to be appended to each listed ref (optional; ignored, if set +# but empty). +# +# Use __git_complete_refs() instead. __git_refs () { local i hash dir track="${2-}" local list_refs_from=path remote="${1-}" - local format refs pfx + local format refs + local pfx="${3-}" cur_="${4-$cur}" sfx="${5-}" + local match="${4-}" + local fer_pfx="${pfx//\%/%%}" # "escape" for-each-ref format specifiers __git_find_repo_path dir="$__git_repo_path" @@ -382,63 +419,78 @@ __git_refs () fi if [ "$list_refs_from" = path ]; then - case "$cur" in + if [[ "$cur_" == ^* ]]; then + pfx="$pfx^" + fer_pfx="$fer_pfx^" + cur_=${cur_#^} + match=${match#^} + fi + case "$cur_" in refs|refs/*) format="refname" - refs="${cur%/*}" + refs=("$match*" "$match*/**") track="" ;; *) - [[ "$cur" == ^* ]] && pfx="^" for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD; do - if [ -e "$dir/$i" ]; then echo $pfx$i; fi + case "$i" in + $match*) + if [ -e "$dir/$i" ]; then + echo "$pfx$i$sfx" + fi + ;; + esac done - format="refname:short" - refs="refs/tags refs/heads refs/remotes" + format="refname:strip=2" + refs=("refs/tags/$match*" "refs/tags/$match*/**" + "refs/heads/$match*" "refs/heads/$match*/**" + "refs/remotes/$match*" "refs/remotes/$match*/**") ;; esac - __git_dir="$dir" __git for-each-ref --format="$pfx%($format)" \ - $refs + __git_dir="$dir" __git for-each-ref --format="$fer_pfx%($format)$sfx" \ + "${refs[@]}" if [ -n "$track" ]; then # employ the heuristic used by git checkout # Try to find a remote branch that matches the completion word # but only output if the branch name is unique - local ref entry - __git for-each-ref --shell --format="ref=%(refname:short)" \ - "refs/remotes/" | \ - while read -r entry; do - eval "$entry" - ref="${ref#*/}" - if [[ "$ref" == "$cur"* ]]; then - echo "$ref" - fi - done | sort | uniq -u + __git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \ + --sort="refname:strip=3" \ + "refs/remotes/*/$match*" "refs/remotes/*/$match*/**" | \ + uniq -u fi return fi - case "$cur" in + case "$cur_" in refs|refs/*) - __git ls-remote "$remote" "$cur*" | \ + __git ls-remote "$remote" "$match*" | \ while read -r hash i; do case "$i" in *^{}) ;; - *) echo "$i" ;; + *) echo "$pfx$i$sfx" ;; esac done ;; *) if [ "$list_refs_from" = remote ]; then - echo "HEAD" - __git for-each-ref --format="%(refname:short)" \ - "refs/remotes/$remote/" | sed -e "s#^$remote/##" + case "HEAD" in + $match*) echo "${pfx}HEAD$sfx" ;; + esac + __git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \ + "refs/remotes/$remote/$match*" \ + "refs/remotes/$remote/$match*/**" else - __git ls-remote "$remote" HEAD \ - "refs/tags/*" "refs/heads/*" "refs/remotes/*" | + local query_symref + case "HEAD" in + $match*) query_symref="HEAD" ;; + esac + __git ls-remote "$remote" $query_symref \ + "refs/tags/$match*" "refs/heads/$match*" \ + "refs/remotes/$match*" | while read -r hash i; do case "$i" in *^{}) ;; - refs/*) echo "${i#refs/*/}" ;; - *) echo "$i" ;; # symbolic refs + refs/*) echo "$pfx${i#refs/*/}$sfx" ;; + *) echo "$pfx$i$sfx" ;; # symbolic refs esac done fi @@ -446,7 +498,38 @@ __git_refs () esac } +# Completes refs, short and long, local and remote, symbolic and pseudo. +# +# Usage: __git_complete_refs [<option>]... +# --remote=<remote>: The remote to list refs from, can be the name of a +# configured remote, a path, or a URL. +# --track: List unique remote branches for 'git checkout's tracking DWIMery. +# --pfx=<prefix>: A prefix to be added to each ref. +# --cur=<word>: The current ref to be completed. Defaults to the current +# word to be completed. +# --sfx=<suffix>: A suffix to be appended to each ref instead of the default +# space. +__git_complete_refs () +{ + local remote track pfx cur_="$cur" sfx=" " + + while test $# != 0; do + case "$1" in + --remote=*) remote="${1##--remote=}" ;; + --track) track="yes" ;; + --pfx=*) pfx="${1##--pfx=}" ;; + --cur=*) cur_="${1##--cur=}" ;; + --sfx=*) sfx="${1##--sfx=}" ;; + *) return 1 ;; + esac + shift + done + + __gitcomp_direct "$(__git_refs "$remote" "$track" "$pfx" "$cur_" "$sfx")" +} + # __git_refs2 requires 1 argument (to pass to __git_refs) +# Deprecated: use __git_complete_fetch_refspecs() instead. __git_refs2 () { local i @@ -455,6 +538,24 @@ __git_refs2 () done } +# Completes refspecs for fetching from a remote repository. +# 1: The remote repository. +# 2: A prefix to be added to each listed refspec (optional). +# 3: The ref to be completed as a refspec instead of the current word to be +# completed (optional) +# 4: A suffix to be appended to each listed refspec instead of the default +# space (optional). +__git_complete_fetch_refspecs () +{ + local i remote="$1" pfx="${2-}" cur_="${3-$cur}" sfx="${4- }" + + __gitcomp_direct "$( + for i in $(__git_refs "$remote" "" "" "$cur_") ; do + echo "$pfx$i:$i$sfx" + done + )" +} + # __git_refs_remotes requires 1 argument (to pass to ls-remote) __git_refs_remotes () { @@ -554,15 +655,15 @@ __git_complete_revlist_file () *...*) pfx="${cur_%...*}..." cur_="${cur_#*...}" - __gitcomp_nl "$(__git_refs)" "$pfx" "$cur_" + __git_complete_refs --pfx="$pfx" --cur="$cur_" ;; *..*) pfx="${cur_%..*}.." cur_="${cur_#*..}" - __gitcomp_nl "$(__git_refs)" "$pfx" "$cur_" + __git_complete_refs --pfx="$pfx" --cur="$cur_" ;; *) - __gitcomp_nl "$(__git_refs)" + __git_complete_refs ;; esac } @@ -647,23 +748,23 @@ __git_complete_remote_or_refspec () case "$cmd" in fetch) if [ $lhs = 1 ]; then - __gitcomp_nl "$(__git_refs2 "$remote")" "$pfx" "$cur_" + __git_complete_fetch_refspecs "$remote" "$pfx" "$cur_" else - __gitcomp_nl "$(__git_refs)" "$pfx" "$cur_" + __git_complete_refs --pfx="$pfx" --cur="$cur_" fi ;; pull|remote) if [ $lhs = 1 ]; then - __gitcomp_nl "$(__git_refs "$remote")" "$pfx" "$cur_" + __git_complete_refs --remote="$remote" --pfx="$pfx" --cur="$cur_" else - __gitcomp_nl "$(__git_refs)" "$pfx" "$cur_" + __git_complete_refs --pfx="$pfx" --cur="$cur_" fi ;; push) if [ $lhs = 1 ]; then - __gitcomp_nl "$(__git_refs)" "$pfx" "$cur_" + __git_complete_refs --pfx="$pfx" --cur="$cur_" else - __gitcomp_nl "$(__git_refs "$remote")" "$pfx" "$cur_" + __git_complete_refs --remote="$remote" --pfx="$pfx" --cur="$cur_" fi ;; esac @@ -1066,7 +1167,7 @@ _git_bisect () case "$subcommand" in bad|good|reset|skip|start) - __gitcomp_nl "$(__git_refs)" + __git_complete_refs ;; *) ;; @@ -1088,12 +1189,12 @@ _git_branch () case "$cur" in --set-upstream-to=*) - __gitcomp_nl "$(__git_refs)" "" "${cur##--set-upstream-to=}" + __git_complete_refs --cur="${cur##--set-upstream-to=}" ;; --*) __gitcomp " --color --no-color --verbose --abbrev= --no-abbrev - --track --no-track --contains --merged --no-merged + --track --no-track --contains --no-contains --merged --no-merged --set-upstream-to= --edit-description --list --unset-upstream --delete --move --remotes --column --no-column --sort= --points-at @@ -1101,9 +1202,9 @@ _git_branch () ;; *) if [ $only_local_ref = "y" -a $has_r = "n" ]; then - __gitcomp_nl "$(__git_heads)" + __gitcomp_direct "$(__git_heads "" "$cur" " ")" else - __gitcomp_nl "$(__git_refs)" + __git_complete_refs fi ;; esac @@ -1146,18 +1247,18 @@ _git_checkout () *) # check if --track, --no-track, or --no-guess was specified # if so, disable DWIM mode - local flags="--track --no-track --no-guess" track=1 + local flags="--track --no-track --no-guess" track_opt="--track" if [ -n "$(__git_find_on_cmdline "$flags")" ]; then - track='' + track_opt='' fi - __gitcomp_nl "$(__git_refs '' $track)" + __git_complete_refs $track_opt ;; esac } _git_cherry () { - __gitcomp_nl "$(__git_refs)" + __git_complete_refs } _git_cherry_pick () @@ -1172,7 +1273,7 @@ _git_cherry_pick () __gitcomp "--edit --no-commit --signoff --strategy= --mainline" ;; *) - __gitcomp_nl "$(__git_refs)" + __git_complete_refs ;; esac } @@ -1224,7 +1325,7 @@ _git_commit () { case "$prev" in -c|-C) - __gitcomp_nl "$(__git_refs)" "" "${cur}" + __git_complete_refs return ;; esac @@ -1237,7 +1338,7 @@ _git_commit () ;; --reuse-message=*|--reedit-message=*|\ --fixup=*|--squash=*) - __gitcomp_nl "$(__git_refs)" "" "${cur#*=}" + __git_complete_refs --cur="${cur#*=}" return ;; --untracked-files=*) @@ -1277,7 +1378,7 @@ _git_describe () " return esac - __gitcomp_nl "$(__git_refs)" + __git_complete_refs } __git_diff_algorithms="myers minimal patience histogram" @@ -1428,8 +1529,43 @@ _git_gitk () _gitk } -__git_match_ctag() { - awk "/^${1//\//\\/}/ { print \$1 }" "$2" +# Lists matching symbol names from a tag (as in ctags) file. +# 1: List symbol names matching this word. +# 2: The tag file to list symbol names from. +# 3: A prefix to be added to each listed symbol name (optional). +# 4: A suffix to be appended to each listed symbol name (optional). +__git_match_ctag () { + awk -v pfx="${3-}" -v sfx="${4-}" " + /^${1//\//\\/}/ { print pfx \$1 sfx } + " "$2" +} + +# Complete symbol names from a tag file. +# Usage: __git_complete_symbol [<option>]... +# --tags=<file>: The tag file to list symbol names from instead of the +# default "tags". +# --pfx=<prefix>: A prefix to be added to each symbol name. +# --cur=<word>: The current symbol name to be completed. Defaults to +# the current word to be completed. +# --sfx=<suffix>: A suffix to be appended to each symbol name instead +# of the default space. +__git_complete_symbol () { + local tags=tags pfx="" cur_="${cur-}" sfx=" " + + while test $# != 0; do + case "$1" in + --tags=*) tags="${1##--tags=}" ;; + --pfx=*) pfx="${1##--pfx=}" ;; + --cur=*) cur_="${1##--cur=}" ;; + --sfx=*) sfx="${1##--sfx=}" ;; + *) return 1 ;; + esac + shift + done + + if test -r "$tags"; then + __gitcomp_direct "$(__git_match_ctag "$cur_" "$tags" "$pfx" "$sfx")" + fi } _git_grep () @@ -1459,14 +1595,11 @@ _git_grep () case "$cword,$prev" in 2,*|*,-*) - if test -r tags; then - __gitcomp_nl "$(__git_match_ctag "$cur" tags)" - return - fi + __git_complete_symbol && return ;; esac - __gitcomp_nl "$(__git_refs)" + __git_complete_refs } _git_help () @@ -1573,6 +1706,19 @@ _git_log () if [ -f "$__git_repo_path/MERGE_HEAD" ]; then merge="--merge" fi + case "$prev,$cur" in + -L,:*:*) + return # fall back to Bash filename completion + ;; + -L,:*) + __git_complete_symbol --cur="${cur#:}" --sfx=":" + return + ;; + -G,*|-S,*) + __git_complete_symbol + return + ;; + esac case "$cur" in --pretty=*|--format=*) __gitcomp "$__git_log_pretty_formats $(__git_pretty_aliases) @@ -1618,6 +1764,21 @@ _git_log () " return ;; + -L:*:*) + return # fall back to Bash filename completion + ;; + -L:*) + __git_complete_symbol --cur="${cur#-L:}" --sfx=":" + return + ;; + -G*) + __git_complete_symbol --pfx="-G" --cur="${cur#-G}" + return + ;; + -S*) + __git_complete_symbol --pfx="-S" --cur="${cur#-S}" + return + ;; esac __git_complete_revlist } @@ -1640,7 +1801,7 @@ _git_merge () --rerere-autoupdate --no-rerere-autoupdate --abort --continue" return esac - __gitcomp_nl "$(__git_refs)" + __git_complete_refs } _git_mergetool () @@ -1665,7 +1826,7 @@ _git_merge_base () return ;; esac - __gitcomp_nl "$(__git_refs)" + __git_complete_refs } _git_mv () @@ -1703,7 +1864,7 @@ _git_notes () ,*) case "$prev" in --ref) - __gitcomp_nl "$(__git_refs)" + __git_complete_refs ;; *) __gitcomp "$subcommands --ref" @@ -1712,7 +1873,7 @@ _git_notes () ;; add,--reuse-message=*|append,--reuse-message=*|\ add,--reedit-message=*|append,--reedit-message=*) - __gitcomp_nl "$(__git_refs)" "" "${cur#*=}" + __git_complete_refs --cur="${cur#*=}" ;; add,--*|append,--*) __gitcomp '--file= --message= --reedit-message= @@ -1731,7 +1892,7 @@ _git_notes () -m|-F) ;; *) - __gitcomp_nl "$(__git_refs)" + __git_complete_refs ;; esac ;; @@ -1769,10 +1930,10 @@ __git_complete_force_with_lease () --*=) ;; *:*) - __gitcomp_nl "$(__git_refs)" "" "${cur_#*:}" + __git_complete_refs --cur="${cur_#*:}" ;; *) - __gitcomp_nl "$(__git_refs)" "" "$cur_" + __git_complete_refs --cur="$cur_" ;; esac } @@ -1848,7 +2009,7 @@ _git_rebase () return esac - __gitcomp_nl "$(__git_refs)" + __git_complete_refs } _git_reflog () @@ -1859,7 +2020,7 @@ _git_reflog () if [ -z "$subcommand" ]; then __gitcomp "$subcommands" else - __gitcomp_nl "$(__git_refs)" + __git_complete_refs fi } @@ -2005,7 +2166,7 @@ _git_config () return ;; branch.*.merge) - __gitcomp_nl "$(__git_refs)" + __git_complete_refs return ;; branch.*.rebase) @@ -2109,7 +2270,7 @@ _git_config () ;; branch.*) local pfx="${cur%.*}." cur_="${cur#*.}" - __gitcomp_nl "$(__git_heads)" "$pfx" "$cur_" "." + __gitcomp_direct "$(__git_heads "$pfx" "$cur_" ".")" __gitcomp_nl_append $'autosetupmerge\nautosetuprebase\n' "$pfx" "$cur_" return ;; @@ -2516,7 +2677,7 @@ _git_replace () return ;; esac - __gitcomp_nl "$(__git_refs)" + __git_complete_refs } _git_rerere () @@ -2540,7 +2701,7 @@ _git_reset () return ;; esac - __gitcomp_nl "$(__git_refs)" + __git_complete_refs } _git_revert () @@ -2559,7 +2720,7 @@ _git_revert () return ;; esac - __gitcomp_nl "$(__git_refs)" + __git_complete_refs } _git_rm () @@ -2667,7 +2828,7 @@ _git_stash () ;; branch,*) if [ $cword -eq 3 ]; then - __gitcomp_nl "$(__git_refs)"; + __git_complete_refs else __gitcomp_nl "$(__git stash list \ | sed -n -e 's/:.*//p')" @@ -2834,7 +2995,7 @@ _git_tag () i="${words[c]}" case "$i" in -d|-v) - __gitcomp_nl "$(__git_tags)" + __gitcomp_direct "$(__git_tags "" "$cur" " ")" return ;; -f) @@ -2849,11 +3010,11 @@ _git_tag () ;; -*|tag) if [ $f = 1 ]; then - __gitcomp_nl "$(__git_tags)" + __gitcomp_direct "$(__git_tags "" "$cur" " ")" fi ;; *) - __gitcomp_nl "$(__git_refs)" + __git_complete_refs ;; esac @@ -2862,7 +3023,7 @@ _git_tag () __gitcomp " --list --delete --verify --annotate --message --file --sign --cleanup --local-user --force --column --sort= - --contains --points-at --merged --no-merged --create-reflog + --contains --no-contains --points-at --merged --no-merged --create-reflog " ;; esac @@ -3024,6 +3185,15 @@ if [[ -n ${ZSH_VERSION-} ]]; then esac } + __gitcomp_direct () + { + emulate -L zsh + + local IFS=$'\n' + compset -P '*[=:]' + compadd -Q -- ${=1} && _ret=0 + } + __gitcomp_nl () { emulate -L zsh diff --git a/contrib/completion/git-completion.zsh b/contrib/completion/git-completion.zsh index e25541308a..c3521fbfc4 100644 --- a/contrib/completion/git-completion.zsh +++ b/contrib/completion/git-completion.zsh @@ -67,6 +67,15 @@ __gitcomp () esac } +__gitcomp_direct () +{ + emulate -L zsh + + local IFS=$'\n' + compset -P '*[=:]' + compadd -Q -- ${=1} && _ret=0 +} + __gitcomp_nl () { emulate -L zsh diff --git a/contrib/completion/git-prompt.sh b/contrib/completion/git-prompt.sh index 97eacd7832..c6cbef38c2 100644 --- a/contrib/completion/git-prompt.sh +++ b/contrib/completion/git-prompt.sh @@ -82,6 +82,7 @@ # contains relative to newer annotated tag (v1.6.3.2~35) # branch relative to newer tag or branch (master~4) # describe relative to older annotated tag (v1.6.3.1-13-gdd42c2f) +# tag relative to any older tag (v1.6.3.1-13-gdd42c2f) # default exactly matching tag # # If you would like a colored hint about the current dirty state, set @@ -443,6 +444,8 @@ __git_ps1 () git describe --contains HEAD ;; (branch) git describe --contains --all HEAD ;; + (tag) + git describe --tags HEAD ;; (describe) git describe HEAD ;; (* | default) diff --git a/contrib/git-resurrect.sh b/contrib/git-resurrect.sh index d7e97bbc76..8c171dd959 100755 --- a/contrib/git-resurrect.sh +++ b/contrib/git-resurrect.sh @@ -26,13 +26,13 @@ n,dry-run don't recreate the branch" . git-sh-setup search_reflog () { - sed -ne 's~^\([^ ]*\) .*\tcheckout: moving from '"$1"' .*~\1~p' \ + sed -ne 's~^\([^ ]*\) .* checkout: moving from '"$1"' .*~\1~p' \ < "$GIT_DIR"/logs/HEAD } search_reflog_merges () { git rev-parse $( - sed -ne 's~^[^ ]* \([^ ]*\) .*\tmerge '"$1"':.*~\1^2~p' \ + sed -ne 's~^[^ ]* \([^ ]*\) .* merge '"$1"':.*~\1^2~p' \ < "$GIT_DIR"/logs/HEAD ) } diff --git a/credential-cache.c b/credential-cache.c index cc8a6ee192..3cbd420019 100644 --- a/credential-cache.c +++ b/credential-cache.c @@ -83,6 +83,19 @@ static void do_cache(const char *socket, const char *action, int timeout, strbuf_release(&buf); } +static char *get_socket_path(void) +{ + struct stat sb; + char *old_dir, *socket; + old_dir = expand_user_path("~/.git-credential-cache"); + if (old_dir && !stat(old_dir, &sb) && S_ISDIR(sb.st_mode)) + socket = xstrfmt("%s/socket", old_dir); + else + socket = xdg_cache_home("credential/socket"); + free(old_dir); + return socket; +} + int cmd_main(int argc, const char **argv) { char *socket_path = NULL; @@ -106,7 +119,7 @@ int cmd_main(int argc, const char **argv) op = argv[0]; if (!socket_path) - socket_path = expand_user_path("~/.git-credential-cache/socket"); + socket_path = get_socket_path(); if (!socket_path) die("unable to find a suitable socket path; use --socket"); @@ -449,46 +449,42 @@ static void copy_to_log(int fd) fclose(fp); } -static int run_service_command(const char **argv) +static int run_service_command(struct child_process *cld) { - struct child_process cld = CHILD_PROCESS_INIT; - - cld.argv = argv; - cld.git_cmd = 1; - cld.err = -1; - if (start_command(&cld)) + argv_array_push(&cld->args, "."); + cld->git_cmd = 1; + cld->err = -1; + if (start_command(cld)) return -1; close(0); close(1); - copy_to_log(cld.err); + copy_to_log(cld->err); - return finish_command(&cld); + return finish_command(cld); } static int upload_pack(void) { - /* Timeout as string */ - char timeout_buf[64]; - const char *argv[] = { "upload-pack", "--strict", NULL, ".", NULL }; - - argv[2] = timeout_buf; - - snprintf(timeout_buf, sizeof timeout_buf, "--timeout=%u", timeout); - return run_service_command(argv); + struct child_process cld = CHILD_PROCESS_INIT; + argv_array_pushl(&cld.args, "upload-pack", "--strict", NULL); + argv_array_pushf(&cld.args, "--timeout=%u", timeout); + return run_service_command(&cld); } static int upload_archive(void) { - static const char *argv[] = { "upload-archive", ".", NULL }; - return run_service_command(argv); + struct child_process cld = CHILD_PROCESS_INIT; + argv_array_push(&cld.args, "upload-archive"); + return run_service_command(&cld); } static int receive_pack(void) { - static const char *argv[] = { "receive-pack", ".", NULL }; - return run_service_command(argv); + struct child_process cld = CHILD_PROCESS_INIT; + argv_array_push(&cld.args, "receive-pack"); + return run_service_command(&cld); } static struct daemon_service daemon_service[] = { diff --git a/diff-no-index.c b/diff-no-index.c index df762fd0f7..79229382b0 100644 --- a/diff-no-index.c +++ b/diff-no-index.c @@ -236,7 +236,7 @@ static void fixup_paths(const char **path, struct strbuf *replacement) void diff_no_index(struct rev_info *revs, int argc, const char **argv) { - int i, prefixlen; + int i; const char *paths[2]; struct strbuf replacement = STRBUF_INIT; const char *prefix = revs->prefix; @@ -257,7 +257,6 @@ void diff_no_index(struct rev_info *revs, } } - prefixlen = prefix ? strlen(prefix) : 0; for (i = 0; i < 2; i++) { const char *p = argv[argc - 2 + i]; if (!strcmp(p, "-")) @@ -266,8 +265,8 @@ void diff_no_index(struct rev_info *revs, * path that is "-", spell it as "./-". */ p = file_from_standard_input; - else if (prefixlen) - p = xstrdup(prefix_filename(prefix, prefixlen, p)); + else if (prefix) + p = prefix_filename(prefix, p); paths[i] = p; } @@ -398,7 +398,7 @@ static struct diff_tempfile { */ const char *name; - char hex[GIT_SHA1_HEXSZ + 1]; + char hex[GIT_MAX_HEXSZ + 1]; char mode[10]; /* @@ -4023,8 +4023,7 @@ int diff_opt_parse(struct diff_options *options, else if (!strcmp(arg, "--pickaxe-regex")) options->pickaxe_opts |= DIFF_PICKAXE_REGEX; else if ((argcount = short_opt('O', av, &optarg))) { - const char *path = prefix_filename(prefix, strlen(prefix), optarg); - options->orderfile = xstrdup(path); + options->orderfile = prefix_filename(prefix, optarg); return argcount; } else if ((argcount = parse_long_opt("diff-filter", av, &optarg))) { @@ -4071,13 +4070,14 @@ int diff_opt_parse(struct diff_options *options, else if (!strcmp(arg, "--no-function-context")) DIFF_OPT_CLR(options, FUNCCONTEXT); else if ((argcount = parse_long_opt("output", av, &optarg))) { - const char *path = prefix_filename(prefix, strlen(prefix), optarg); + char *path = prefix_filename(prefix, optarg); options->file = fopen(path, "w"); if (!options->file) die_errno("Could not open '%s'", path); options->close_file = 1; if (options->use_color != GIT_COLOR_ALWAYS) options->use_color = GIT_COLOR_NEVER; + free(path); return argcount; } else return 0; @@ -4219,7 +4219,7 @@ const char *diff_aligned_abbrev(const struct object_id *oid, int len) * uniqueness across all objects (statistically speaking). */ if (abblen < GIT_SHA1_HEXSZ - 3) { - static char hex[GIT_SHA1_HEXSZ + 1]; + static char hex[GIT_MAX_HEXSZ + 1]; if (len < abblen && abblen <= len + 2) xsnprintf(hex, sizeof(hex), "%s%.*s", abbrev, len+3-abblen, ".."); else @@ -4570,6 +4570,19 @@ static void patch_id_consume(void *priv, char *line, unsigned long len) data->patchlen += new_len; } +static void patch_id_add_string(git_SHA_CTX *ctx, const char *str) +{ + git_SHA1_Update(ctx, str, strlen(str)); +} + +static void patch_id_add_mode(git_SHA_CTX *ctx, unsigned mode) +{ + /* large enough for 2^32 in octal */ + char buf[12]; + int len = xsnprintf(buf, sizeof(buf), "%06o", mode); + git_SHA1_Update(ctx, buf, len); +} + /* returns 0 upon success, and writes result into sha1 */ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1, int diff_header_only) { @@ -4577,7 +4590,6 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1, int i; git_SHA_CTX ctx; struct patch_id_t data; - char buffer[PATH_MAX * 4 + 20]; git_SHA1_Init(&ctx); memset(&data, 0, sizeof(struct patch_id_t)); @@ -4609,36 +4621,30 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1, len1 = remove_space(p->one->path, strlen(p->one->path)); len2 = remove_space(p->two->path, strlen(p->two->path)); - if (p->one->mode == 0) - len1 = snprintf(buffer, sizeof(buffer), - "diff--gita/%.*sb/%.*s" - "newfilemode%06o" - "---/dev/null" - "+++b/%.*s", - len1, p->one->path, - len2, p->two->path, - p->two->mode, - len2, p->two->path); - else if (p->two->mode == 0) - len1 = snprintf(buffer, sizeof(buffer), - "diff--gita/%.*sb/%.*s" - "deletedfilemode%06o" - "---a/%.*s" - "+++/dev/null", - len1, p->one->path, - len2, p->two->path, - p->one->mode, - len1, p->one->path); - else - len1 = snprintf(buffer, sizeof(buffer), - "diff--gita/%.*sb/%.*s" - "---a/%.*s" - "+++b/%.*s", - len1, p->one->path, - len2, p->two->path, - len1, p->one->path, - len2, p->two->path); - git_SHA1_Update(&ctx, buffer, len1); + patch_id_add_string(&ctx, "diff--git"); + patch_id_add_string(&ctx, "a/"); + git_SHA1_Update(&ctx, p->one->path, len1); + patch_id_add_string(&ctx, "b/"); + git_SHA1_Update(&ctx, p->two->path, len2); + + if (p->one->mode == 0) { + patch_id_add_string(&ctx, "newfilemode"); + patch_id_add_mode(&ctx, p->two->mode); + patch_id_add_string(&ctx, "---/dev/null"); + patch_id_add_string(&ctx, "+++b/"); + git_SHA1_Update(&ctx, p->two->path, len2); + } else if (p->two->mode == 0) { + patch_id_add_string(&ctx, "deletedfilemode"); + patch_id_add_mode(&ctx, p->one->mode); + patch_id_add_string(&ctx, "---a/"); + git_SHA1_Update(&ctx, p->one->path, len1); + patch_id_add_string(&ctx, "+++/dev/null"); + } else { + patch_id_add_string(&ctx, "---a/"); + git_SHA1_Update(&ctx, p->one->path, len1); + patch_id_add_string(&ctx, "+++b/"); + git_SHA1_Update(&ctx, p->two->path, len2); + } if (diff_header_only) continue; @@ -14,7 +14,7 @@ struct diff_queue_struct; struct strbuf; struct diff_filespec; struct userdiff_driver; -struct sha1_array; +struct oid_array; struct commit; struct combine_diff_path; @@ -236,7 +236,7 @@ struct combine_diff_path { extern void show_combined_diff(struct combine_diff_path *elem, int num_parent, int dense, struct rev_info *); -extern void diff_tree_combined(const unsigned char *sha1, const struct sha1_array *parents, int dense, struct rev_info *rev); +extern void diff_tree_combined(const unsigned char *sha1, const struct oid_array *parents, int dense, struct rev_info *rev); extern void diff_tree_combined_merge(const struct commit *commit, int dense, struct rev_info *rev); diff --git a/diffcore-pickaxe.c b/diffcore-pickaxe.c index 9795ca1c15..341529b5a8 100644 --- a/diffcore-pickaxe.c +++ b/diffcore-pickaxe.c @@ -81,12 +81,15 @@ static unsigned int contains(mmfile_t *mf, regex_t *regexp, kwset_t kws) regmatch_t regmatch; int flags = 0; - while (*data && + while (sz && *data && !regexec_buf(regexp, data, sz, 1, ®match, flags)) { flags |= REG_NOTBOL; data += regmatch.rm_eo; - if (*data && regmatch.rm_so == regmatch.rm_eo) + sz -= regmatch.rm_eo; + if (sz && *data && regmatch.rm_so == regmatch.rm_eo) { data++; + sz--; + } cnt++; } @@ -2765,23 +2765,33 @@ void untracked_cache_add_to_index(struct index_state *istate, /* Update gitfile and core.worktree setting to connect work tree and git dir */ void connect_work_tree_and_git_dir(const char *work_tree_, const char *git_dir_) { - struct strbuf file_name = STRBUF_INIT; + struct strbuf gitfile_sb = STRBUF_INIT; + struct strbuf cfg_sb = STRBUF_INIT; struct strbuf rel_path = STRBUF_INIT; - char *git_dir = real_pathdup(git_dir_, 1); - char *work_tree = real_pathdup(work_tree_, 1); + char *git_dir, *work_tree; - /* Update gitfile */ - strbuf_addf(&file_name, "%s/.git", work_tree); - write_file(file_name.buf, "gitdir: %s", - relative_path(git_dir, work_tree, &rel_path)); + /* Prepare .git file */ + strbuf_addf(&gitfile_sb, "%s/.git", work_tree_); + if (safe_create_leading_directories_const(gitfile_sb.buf)) + die(_("could not create directories for %s"), gitfile_sb.buf); + + /* Prepare config file */ + strbuf_addf(&cfg_sb, "%s/config", git_dir_); + if (safe_create_leading_directories_const(cfg_sb.buf)) + die(_("could not create directories for %s"), cfg_sb.buf); + git_dir = real_pathdup(git_dir_, 1); + work_tree = real_pathdup(work_tree_, 1); + + /* Write .git file */ + write_file(gitfile_sb.buf, "gitdir: %s", + relative_path(git_dir, work_tree, &rel_path)); /* Update core.worktree setting */ - strbuf_reset(&file_name); - strbuf_addf(&file_name, "%s/config", git_dir); - git_config_set_in_file(file_name.buf, "core.worktree", + git_config_set_in_file(cfg_sb.buf, "core.worktree", relative_path(work_tree, git_dir, &rel_path)); - strbuf_release(&file_name); + strbuf_release(&gitfile_sb); + strbuf_release(&cfg_sb); strbuf_release(&rel_path); free(work_tree); free(git_dir); @@ -2,6 +2,7 @@ #include "blob.h" #include "dir.h" #include "streaming.h" +#include "submodule.h" static void create_directories(const char *path, int path_len, const struct checkout *state) @@ -146,6 +147,7 @@ static int write_entry(struct cache_entry *ce, unsigned long size; size_t wrote, newsize = 0; struct stat st; + const struct submodule *sub; if (ce_mode_s_ifmt == S_IFREG) { struct stream_filter *filter = get_stream_filter(ce->name, @@ -203,6 +205,10 @@ static int write_entry(struct cache_entry *ce, return error("cannot create temporary submodule %s", path); if (mkdir(path, 0777) < 0) return error("cannot create submodule directory %s", path); + sub = submodule_from_ce(ce); + if (sub) + return submodule_move_head(ce->name, + NULL, oid_to_hex(&ce->oid), SUBMODULE_MOVE_HEAD_FORCE); break; default: return error("unknown file mode for %s in index", path); @@ -259,7 +265,31 @@ int checkout_entry(struct cache_entry *ce, strbuf_add(&path, ce->name, ce_namelen(ce)); if (!check_path(path.buf, path.len, &st, state->base_dir_len)) { + const struct submodule *sub; unsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE); + /* + * Needs to be checked before !changed returns early, + * as the possibly empty directory was not changed + */ + sub = submodule_from_ce(ce); + if (sub) { + int err; + if (!is_submodule_populated_gently(ce->name, &err)) { + struct stat sb; + if (lstat(ce->name, &sb)) + die(_("could not stat file '%s'"), ce->name); + if (!(st.st_mode & S_IFDIR)) + unlink_or_warn(ce->name); + + return submodule_move_head(ce->name, + NULL, oid_to_hex(&ce->oid), + SUBMODULE_MOVE_HEAD_FORCE); + } else + return submodule_move_head(ce->name, + "HEAD", oid_to_hex(&ce->oid), + SUBMODULE_MOVE_HEAD_FORCE); + } + if (!changed) return 0; if (!state->force) { diff --git a/environment.c b/environment.c index 42dc3106d2..ff6e4f06e9 100644 --- a/environment.c +++ b/environment.c @@ -167,8 +167,11 @@ static void setup_git_env(void) const char *replace_ref_base; git_dir = getenv(GIT_DIR_ENVIRONMENT); - if (!git_dir) + if (!git_dir) { + if (!startup_info->have_repository) + die("BUG: setup_git_env called without repository"); git_dir = DEFAULT_GIT_DIR_ENVIRONMENT; + } gitfile = read_gitfile(git_dir); git_dir = xstrdup(gitfile ? gitfile : git_dir); if (get_common_dir(&sb, git_dir)) @@ -274,7 +277,7 @@ char *get_object_directory(void) return git_object_dir; } -int odb_mkstemp(char *template, size_t limit, const char *pattern) +int odb_mkstemp(struct strbuf *template, const char *pattern) { int fd; /* @@ -282,32 +285,28 @@ int odb_mkstemp(char *template, size_t limit, const char *pattern) * restrictive except to remove write permission. */ int mode = 0444; - snprintf(template, limit, "%s/%s", - get_object_directory(), pattern); - fd = git_mkstemp_mode(template, mode); + git_path_buf(template, "objects/%s", pattern); + fd = git_mkstemp_mode(template->buf, mode); if (0 <= fd) return fd; /* slow path */ /* some mkstemp implementations erase template on failure */ - snprintf(template, limit, "%s/%s", - get_object_directory(), pattern); - safe_create_leading_directories(template); - return xmkstemp_mode(template, mode); + git_path_buf(template, "objects/%s", pattern); + safe_create_leading_directories(template->buf); + return xmkstemp_mode(template->buf, mode); } -int odb_pack_keep(char *name, size_t namesz, const unsigned char *sha1) +int odb_pack_keep(const char *name) { int fd; - snprintf(name, namesz, "%s/pack/pack-%s.keep", - get_object_directory(), sha1_to_hex(sha1)); fd = open(name, O_RDWR|O_CREAT|O_EXCL, 0600); if (0 <= fd) return fd; /* slow path */ - safe_create_leading_directories(name); + safe_create_leading_directories_const(name); return open(name, O_RDWR|O_CREAT|O_EXCL, 0600); } diff --git a/fast-import.c b/fast-import.c index 6c13472c42..1ea3a08609 100644 --- a/fast-import.c +++ b/fast-import.c @@ -890,14 +890,15 @@ static struct tree_content *dup_tree_content(struct tree_content *s) static void start_packfile(void) { - static char tmp_file[PATH_MAX]; + struct strbuf tmp_file = STRBUF_INIT; struct packed_git *p; struct pack_header hdr; int pack_fd; - pack_fd = odb_mkstemp(tmp_file, sizeof(tmp_file), - "pack/tmp_pack_XXXXXX"); - FLEX_ALLOC_STR(p, pack_name, tmp_file); + pack_fd = odb_mkstemp(&tmp_file, "pack/tmp_pack_XXXXXX"); + FLEX_ALLOC_STR(p, pack_name, tmp_file.buf); + strbuf_release(&tmp_file); + p->pack_fd = pack_fd; p->do_not_close = 1; pack_file = sha1fd(pack_fd, p->pack_name); @@ -940,41 +941,40 @@ static const char *create_index(void) static char *keep_pack(const char *curr_index_name) { - static char name[PATH_MAX]; static const char *keep_msg = "fast-import"; + struct strbuf name = STRBUF_INIT; int keep_fd; - keep_fd = odb_pack_keep(name, sizeof(name), pack_data->sha1); + odb_pack_name(&name, pack_data->sha1, "keep"); + keep_fd = odb_pack_keep(name.buf); if (keep_fd < 0) die_errno("cannot create keep file"); write_or_die(keep_fd, keep_msg, strlen(keep_msg)); if (close(keep_fd)) die_errno("failed to write keep file"); - snprintf(name, sizeof(name), "%s/pack/pack-%s.pack", - get_object_directory(), sha1_to_hex(pack_data->sha1)); - if (finalize_object_file(pack_data->pack_name, name)) + odb_pack_name(&name, pack_data->sha1, "pack"); + if (finalize_object_file(pack_data->pack_name, name.buf)) die("cannot store pack file"); - snprintf(name, sizeof(name), "%s/pack/pack-%s.idx", - get_object_directory(), sha1_to_hex(pack_data->sha1)); - if (finalize_object_file(curr_index_name, name)) + odb_pack_name(&name, pack_data->sha1, "idx"); + if (finalize_object_file(curr_index_name, name.buf)) die("cannot store index file"); free((void *)curr_index_name); - return name; + return strbuf_detach(&name, NULL); } static void unkeep_all_packs(void) { - static char name[PATH_MAX]; + struct strbuf name = STRBUF_INIT; int k; for (k = 0; k < pack_id; k++) { struct packed_git *p = all_packs[k]; - snprintf(name, sizeof(name), "%s/pack/pack-%s.keep", - get_object_directory(), sha1_to_hex(p->sha1)); - unlink_or_warn(name); + odb_pack_name(&name, p->sha1, "keep"); + unlink_or_warn(name.buf); } + strbuf_release(&name); } static int loosen_small_pack(const struct packed_git *p) @@ -1033,6 +1033,7 @@ static void end_packfile(void) die("core git rejected index %s", idx_name); all_packs[pack_id] = new_p; install_packed_git(new_p); + free(idx_name); /* Print the boundary */ if (pack_edges) { @@ -1173,7 +1174,8 @@ static int store_object( delta_count_by_type[type]++; e->depth = last->depth + 1; - hdrlen = encode_in_pack_object_header(OBJ_OFS_DELTA, deltalen, hdr); + hdrlen = encode_in_pack_object_header(hdr, sizeof(hdr), + OBJ_OFS_DELTA, deltalen); sha1write(pack_file, hdr, hdrlen); pack_size += hdrlen; @@ -1184,7 +1186,8 @@ static int store_object( pack_size += sizeof(hdr) - pos; } else { e->depth = 0; - hdrlen = encode_in_pack_object_header(type, dat->len, hdr); + hdrlen = encode_in_pack_object_header(hdr, sizeof(hdr), + type, dat->len); sha1write(pack_file, hdr, hdrlen); pack_size += hdrlen; } @@ -1237,9 +1240,7 @@ static void stream_blob(uintmax_t len, unsigned char *sha1out, uintmax_t mark) sha1file_checkpoint(pack_file, &checkpoint); offset = checkpoint.offset; - hdrlen = snprintf((char *)out_buf, out_sz, "blob %" PRIuMAX, len) + 1; - if (out_sz <= hdrlen) - die("impossibly large object header"); + hdrlen = xsnprintf((char *)out_buf, out_sz, "blob %" PRIuMAX, len) + 1; git_SHA1_Init(&c); git_SHA1_Update(&c, out_buf, hdrlen); @@ -1248,9 +1249,7 @@ static void stream_blob(uintmax_t len, unsigned char *sha1out, uintmax_t mark) git_deflate_init(&s, pack_compression_level); - hdrlen = encode_in_pack_object_header(OBJ_BLOB, len, out_buf); - if (out_sz <= hdrlen) - die("impossibly large object header"); + hdrlen = encode_in_pack_object_header(out_buf, out_sz, OBJ_BLOB, len); s.next_out = out_buf + hdrlen; s.avail_out = out_sz - hdrlen; @@ -3003,7 +3002,7 @@ static void parse_get_mark(const char *p) if (!oe) die("Unknown mark: %s", command_buf.buf); - snprintf(output, sizeof(output), "%s\n", sha1_to_hex(oe->idx.sha1)); + xsnprintf(output, sizeof(output), "%s\n", sha1_to_hex(oe->idx.sha1)); cat_blob_write(output, 41); } diff --git a/fetch-pack.c b/fetch-pack.c index d07d85ce30..42969353d6 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -1015,7 +1015,7 @@ static void update_shallow(struct fetch_pack_args *args, struct ref **sought, int nr_sought, struct shallow_info *si) { - struct sha1_array ref = SHA1_ARRAY_INIT; + struct oid_array ref = OID_ARRAY_INIT; int *status; int i; @@ -1038,18 +1038,18 @@ static void update_shallow(struct fetch_pack_args *args, * shallow points that exist in the pack (iow in repo * after get_pack() and reprepare_packed_git()) */ - struct sha1_array extra = SHA1_ARRAY_INIT; - unsigned char (*sha1)[20] = si->shallow->sha1; + struct oid_array extra = OID_ARRAY_INIT; + struct object_id *oid = si->shallow->oid; for (i = 0; i < si->shallow->nr; i++) - if (has_sha1_file(sha1[i])) - sha1_array_append(&extra, sha1[i]); + if (has_object_file(&oid[i])) + oid_array_append(&extra, &oid[i]); if (extra.nr) { setup_alternate_shallow(&shallow_lock, &alternate_shallow_file, &extra); commit_lock_file(&shallow_lock); } - sha1_array_clear(&extra); + oid_array_clear(&extra); return; } @@ -1060,7 +1060,7 @@ static void update_shallow(struct fetch_pack_args *args, if (!si->nr_ours && !si->nr_theirs) return; for (i = 0; i < nr_sought; i++) - sha1_array_append(&ref, sought[i]->old_oid.hash); + oid_array_append(&ref, &sought[i]->old_oid); si->ref = &ref; if (args->update_shallow) { @@ -1070,23 +1070,23 @@ static void update_shallow(struct fetch_pack_args *args, * shallow roots that are actually reachable from new * refs. */ - struct sha1_array extra = SHA1_ARRAY_INIT; - unsigned char (*sha1)[20] = si->shallow->sha1; + struct oid_array extra = OID_ARRAY_INIT; + struct object_id *oid = si->shallow->oid; assign_shallow_commits_to_refs(si, NULL, NULL); if (!si->nr_ours && !si->nr_theirs) { - sha1_array_clear(&ref); + oid_array_clear(&ref); return; } for (i = 0; i < si->nr_ours; i++) - sha1_array_append(&extra, sha1[si->ours[i]]); + oid_array_append(&extra, &oid[si->ours[i]]); for (i = 0; i < si->nr_theirs; i++) - sha1_array_append(&extra, sha1[si->theirs[i]]); + oid_array_append(&extra, &oid[si->theirs[i]]); setup_alternate_shallow(&shallow_lock, &alternate_shallow_file, &extra); commit_lock_file(&shallow_lock); - sha1_array_clear(&extra); - sha1_array_clear(&ref); + oid_array_clear(&extra); + oid_array_clear(&ref); return; } @@ -1102,7 +1102,7 @@ static void update_shallow(struct fetch_pack_args *args, sought[i]->status = REF_STATUS_REJECT_SHALLOW; } free(status); - sha1_array_clear(&ref); + oid_array_clear(&ref); } struct ref *fetch_pack(struct fetch_pack_args *args, @@ -1110,7 +1110,7 @@ struct ref *fetch_pack(struct fetch_pack_args *args, const struct ref *ref, const char *dest, struct ref **sought, int nr_sought, - struct sha1_array *shallow, + struct oid_array *shallow, char **pack_lockfile) { struct ref *ref_cpy; diff --git a/fetch-pack.h b/fetch-pack.h index a2d46e6e75..b6aeb43a8e 100644 --- a/fetch-pack.h +++ b/fetch-pack.h @@ -4,7 +4,7 @@ #include "string-list.h" #include "run-command.h" -struct sha1_array; +struct oid_array; struct fetch_pack_args { const char *uploadpack; @@ -42,7 +42,7 @@ struct ref *fetch_pack(struct fetch_pack_args *args, const char *dest, struct ref **sought, int nr_sought, - struct sha1_array *shallow, + struct oid_array *shallow, char **pack_lockfile); /* @@ -132,10 +132,10 @@ static int fsck_msg_type(enum fsck_msg_id msg_id, static void init_skiplist(struct fsck_options *options, const char *path) { - static struct sha1_array skiplist = SHA1_ARRAY_INIT; + static struct oid_array skiplist = OID_ARRAY_INIT; int sorted, fd; - char buffer[41]; - unsigned char sha1[20]; + char buffer[GIT_MAX_HEXSZ + 1]; + struct object_id oid; if (options->skiplist) sorted = options->skiplist->sorted; @@ -148,17 +148,18 @@ static void init_skiplist(struct fsck_options *options, const char *path) if (fd < 0) die("Could not open skip list: %s", path); for (;;) { + const char *p; int result = read_in_full(fd, buffer, sizeof(buffer)); if (result < 0) die_errno("Could not read '%s'", path); if (!result) break; - if (get_sha1_hex(buffer, sha1) || buffer[40] != '\n') + if (parse_oid_hex(buffer, &oid, &p) || *p != '\n') die("Invalid SHA-1: %s", buffer); - sha1_array_append(&skiplist, sha1); + oid_array_append(&skiplist, &oid); if (sorted && skiplist.nr > 1 && - hashcmp(skiplist.sha1[skiplist.nr - 2], - sha1) > 0) + oidcmp(&skiplist.oid[skiplist.nr - 2], + &oid) > 0) sorted = 0; } close(fd); @@ -279,7 +280,7 @@ static int report(struct fsck_options *options, struct object *object, return 0; if (options->skiplist && object && - sha1_array_lookup(options->skiplist, object->oid.hash) >= 0) + oid_array_lookup(options->skiplist, &object->oid) >= 0) return 0; if (msg_type == FSCK_FATAL) @@ -34,7 +34,7 @@ struct fsck_options { fsck_error error_func; unsigned strict:1; int *msg_type; - struct sha1_array *skiplist; + struct oid_array *skiplist; struct decoration *object_names; }; diff --git a/git-add--interactive.perl b/git-add--interactive.perl index 77b4ed53a8..709a5f6ce6 100755 --- a/git-add--interactive.perl +++ b/git-add--interactive.perl @@ -1040,7 +1040,7 @@ marked for unstaging."), marked for applying."), checkout_index => N__( "If the patch applies cleanly, the edited hunk will immediately be -marked for discarding"), +marked for discarding."), checkout_head => N__( "If the patch applies cleanly, the edited hunk will immediately be marked for discarding."), diff --git a/git-compat-util.h b/git-compat-util.h index e626851fe9..8a4a3f85e7 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -798,8 +798,6 @@ extern FILE *xfopen(const char *path, const char *mode); extern FILE *xfdopen(int fd, const char *mode); extern int xmkstemp(char *template); extern int xmkstemp_mode(char *template, int mode); -extern int odb_mkstemp(char *template, size_t limit, const char *pattern); -extern int odb_pack_keep(char *name, size_t namesz, const unsigned char *sha1); extern char *xgetcwd(void); extern FILE *fopen_for_writing(const char *path); diff --git a/git-stash.sh b/git-stash.sh index 9c70662cc8..2fb651b2b8 100755 --- a/git-stash.sh +++ b/git-stash.sh @@ -299,12 +299,12 @@ push_stash () { then if test $# != 0 then - git reset ${GIT_QUIET:+-q} -- "$@" + git reset -q -- "$@" git ls-files -z --modified -- "$@" | git checkout-index -z --force --stdin - git clean --force ${GIT_QUIET:+-q} -d -- "$@" + git clean --force -q -d -- "$@" else - git reset --hard ${GIT_QUIET:+-q} + git reset --hard -q fi test "$untracked" = "all" && CLEAN_X_OPTION=-x || CLEAN_X_OPTION= if test -n "$untracked" @@ -314,7 +314,9 @@ push_stash () { if test "$keep_index" = "t" && test -n "$i_tree" then - git read-tree --reset -u $i_tree + git read-tree --reset $i_tree + git ls-files -z --modified -- "$@" | + git checkout-index -z --force --stdin fi else git apply -R < "$TMP-patch" || @@ -322,7 +324,7 @@ push_stash () { if test "$keep_index" != "t" then - git reset + git reset -q -- "$@" fi fi } diff --git a/git-submodule.sh b/git-submodule.sh index 136e26a2c8..6ec35e5fcd 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -278,6 +278,20 @@ or you are unsure what this means choose another name with the '--name' option." fi && git add --force .gitmodules || die "$(eval_gettext "Failed to register submodule '\$sm_path'")" + + # NEEDSWORK: In a multi-working-tree world, this needs to be + # set in the per-worktree config. + if git config --get submodule.active >/dev/null + then + # If the submodule being adding isn't already covered by the + # current configured pathspec, set the submodule's active flag + if ! git submodule--helper is-active "$sm_path" + then + git config submodule."$sm_name".active "true" + fi + else + git config submodule."$sm_name".active "true" + fi } # @@ -1010,14 +1024,13 @@ cmd_status() do die_if_unmatched "$mode" "$sha1" name=$(git submodule--helper name "$sm_path") || exit - url=$(git config submodule."$name".url) displaypath=$(git submodule--helper relative-path "$prefix$sm_path" "$wt_prefix") if test "$stage" = U then say "U$sha1 $displaypath" continue fi - if test -z "$url" || + if ! git submodule--helper is-active "$sm_path" || { ! test -d "$sm_path"/.git && ! test -f "$sm_path"/.git @@ -1090,6 +1103,13 @@ cmd_sync() while read mode sha1 stage sm_path do die_if_unmatched "$mode" "$sha1" + + # skip inactive submodules + if ! git submodule--helper is-active "$sm_path" + then + continue + fi + name=$(git submodule--helper name "$sm_path") url=$(git config -f .gitmodules --get submodule."$name".url) @@ -1112,27 +1132,24 @@ cmd_sync() ;; esac - if git config "submodule.$name.url" >/dev/null 2>/dev/null + displaypath=$(git submodule--helper relative-path "$prefix$sm_path" "$wt_prefix") + say "$(eval_gettext "Synchronizing submodule url for '\$displaypath'")" + git config submodule."$name".url "$super_config_url" + + if test -e "$sm_path"/.git then - displaypath=$(git submodule--helper relative-path "$prefix$sm_path" "$wt_prefix") - say "$(eval_gettext "Synchronizing submodule url for '\$displaypath'")" - git config submodule."$name".url "$super_config_url" + ( + sanitize_submodule_env + cd "$sm_path" + remote=$(get_default_remote) + git config remote."$remote".url "$sub_origin_url" - if test -e "$sm_path"/.git + if test -n "$recursive" then - ( - sanitize_submodule_env - cd "$sm_path" - remote=$(get_default_remote) - git config remote."$remote".url "$sub_origin_url" - - if test -n "$recursive" - then - prefix="$prefix$sm_path/" - eval cmd_sync - fi - ) + prefix="$prefix$sm_path/" + eval cmd_sync fi + ) fi done } @@ -361,8 +361,6 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv) if (!help && get_super_prefix()) { if (!(p->option & SUPPORT_SUPER_PREFIX)) die("%s doesn't support --super-prefix", p->cmd); - if (prefix) - die("can't use --super-prefix from a subdirectory"); } if (!help && p->option & NEED_WORK_TREE) @@ -12,6 +12,11 @@ static int grep_source_is_binary(struct grep_source *gs); static struct grep_opt grep_defaults; +static void std_output(struct grep_opt *opt, const void *buf, size_t size) +{ + fwrite(buf, size, 1, stdout); +} + /* * Initialize the grep_defaults template with hardcoded defaults. * We could let the compiler do this, but without C99 initializers @@ -42,6 +47,7 @@ void init_grep_defaults(void) color_set(opt->color_selected, ""); color_set(opt->color_sep, GIT_COLOR_CYAN); opt->color = -1; + opt->output = std_output; } static int parse_pattern_type_arg(const char *opt, const char *arg) @@ -152,6 +158,7 @@ void grep_init(struct grep_opt *opt, const char *prefix) opt->pathname = def->pathname; opt->regflags = def->regflags; opt->relative = def->relative; + opt->output = def->output; color_set(opt->color_context, def->color_context); color_set(opt->color_filename, def->color_filename); @@ -1164,7 +1171,7 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol, } if (opt->linenum) { char buf[32]; - snprintf(buf, sizeof(buf), "%d", lno); + xsnprintf(buf, sizeof(buf), "%d", lno); output_color(opt, buf, strlen(buf), opt->color_lineno); output_sep(opt, sign); } @@ -1379,11 +1386,6 @@ static int look_ahead(struct grep_opt *opt, return 0; } -static void std_output(struct grep_opt *opt, const void *buf, size_t size) -{ - fwrite(buf, size, 1, stdout); -} - static int fill_textconv_grep(struct userdiff_driver *driver, struct grep_source *gs) { @@ -1651,7 +1653,7 @@ static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int colle opt->color_filename); output_sep(opt, ':'); } - snprintf(buf, sizeof(buf), "%u\n", count); + xsnprintf(buf, sizeof(buf), "%u\n", count); opt->output(opt, buf, strlen(buf)); return 1; } @@ -7,6 +7,8 @@ #include <CommonCrypto/CommonDigest.h> #elif defined(SHA1_OPENSSL) #include <openssl/sha.h> +#elif defined(SHA1_DC) +#include "sha1dc/sha1.h" #else /* SHA1_BLK */ #include "block-sha1/sha1.h" #endif @@ -50,6 +50,23 @@ unsigned int memihash(const void *buf, size_t len) return hash; } +/* + * Incoporate another chunk of data into a memihash + * computation. + */ +unsigned int memihash_cont(unsigned int hash_seed, const void *buf, size_t len) +{ + unsigned int hash = hash_seed; + unsigned char *ucbuf = (unsigned char *) buf; + while (len--) { + unsigned int c = *ucbuf++; + if (c >= 'a' && c <= 'z') + c -= 'a' - 'A'; + hash = (hash * FNV32_PRIME) ^ c; + } + return hash; +} + #define HASHMAP_INITIAL_SIZE 64 /* grow / shrink by 2^2 */ #define HASHMAP_RESIZE_BITS 2 @@ -87,11 +104,19 @@ static inline unsigned int bucket(const struct hashmap *map, return key->hash & (map->tablesize - 1); } +int hashmap_bucket(const struct hashmap *map, unsigned int hash) +{ + return hash & (map->tablesize - 1); +} + static void rehash(struct hashmap *map, unsigned int newsize) { unsigned int i, oldsize = map->tablesize; struct hashmap_entry **oldtable = map->table; + if (map->disallow_rehash) + return; + alloc_table(map, newsize); for (i = 0; i < oldsize; i++) { struct hashmap_entry *e = oldtable[i]; @@ -124,7 +149,9 @@ void hashmap_init(struct hashmap *map, hashmap_cmp_fn equals_function, size_t initial_size) { unsigned int size = HASHMAP_INITIAL_SIZE; - map->size = 0; + + memset(map, 0, sizeof(*map)); + map->cmpfn = equals_function ? equals_function : always_equal; /* calculate initial table size and allocate the table */ @@ -12,6 +12,7 @@ extern unsigned int strhash(const char *buf); extern unsigned int strihash(const char *buf); extern unsigned int memhash(const void *buf, size_t len); extern unsigned int memihash(const void *buf, size_t len); +extern unsigned int memihash_cont(unsigned int hash_seed, const void *buf, size_t len); static inline unsigned int sha1hash(const unsigned char *sha1) { @@ -38,6 +39,7 @@ struct hashmap { struct hashmap_entry **table; hashmap_cmp_fn cmpfn; unsigned int size, tablesize, grow_at, shrink_at; + unsigned disallow_rehash : 1; }; struct hashmap_iter { @@ -76,6 +78,29 @@ static inline void *hashmap_get_from_hash(const struct hashmap *map, return hashmap_get(map, &key, keydata); } +int hashmap_bucket(const struct hashmap *map, unsigned int hash); + +/* + * Disallow/allow rehashing of the hashmap. + * This is useful if the caller knows that the hashmap + * needs multi-threaded access. The caller is still + * required to guard/lock searches and inserts in a + * manner appropriate to their usage. This simply + * prevents the table from being unexpectedly re-mapped. + * + * If is up to the caller to ensure that the hashmap is + * initialized to a reasonable size to prevent poor + * performance. + * + * When value=1, prevent future rehashes on adds and deleted. + * When value=0, allow future rehahses. This DOES NOT force + * a rehash now. + */ +static inline void hashmap_disallow_rehash(struct hashmap *map, unsigned value) +{ + map->disallow_rehash = value; +} + /* hashmap_iter functions */ extern void hashmap_iter_init(struct hashmap *map, struct hashmap_iter *iter); @@ -85,7 +85,7 @@ char *oid_to_hex_r(char *buffer, const struct object_id *oid) char *sha1_to_hex(const unsigned char *sha1) { static int bufno; - static char hexbuffer[4][GIT_SHA1_HEXSZ + 1]; + static char hexbuffer[4][GIT_MAX_HEXSZ + 1]; bufno = (bufno + 1) % ARRAY_SIZE(hexbuffer); return sha1_to_hex_r(hexbuffer[bufno], sha1); } diff --git a/http-push.c b/http-push.c index 704b1c837c..f0e3108f71 100644 --- a/http-push.c +++ b/http-push.c @@ -1431,11 +1431,9 @@ static void one_remote_ref(const char *refname) */ if (repo->can_update_info_refs && !has_object_file(&ref->old_oid)) { obj = lookup_unknown_object(ref->old_oid.hash); - if (obj) { - fprintf(stderr, " fetch %s for %s\n", - oid_to_hex(&ref->old_oid), refname); - add_fetch_request(obj); - } + fprintf(stderr, " fetch %s for %s\n", + oid_to_hex(&ref->old_oid), refname); + add_fetch_request(obj); } ref->next = remote_refs; @@ -1366,9 +1366,9 @@ static int handle_curl_result(struct slot_results *results) * FAILONERROR it is lost, so we can give only the numeric * status code. */ - snprintf(curl_errorstr, sizeof(curl_errorstr), - "The requested URL returned error: %ld", - results->http_code); + xsnprintf(curl_errorstr, sizeof(curl_errorstr), + "The requested URL returned error: %ld", + results->http_code); } if (results->curl_result == CURLE_OK) { @@ -1410,8 +1410,8 @@ int run_one_slot(struct active_request_slot *slot, { slot->results = results; if (!start_active_slot(slot)) { - snprintf(curl_errorstr, sizeof(curl_errorstr), - "failed to start HTTP request"); + xsnprintf(curl_errorstr, sizeof(curl_errorstr), + "failed to start HTTP request"); return HTTP_START_FAILED; } diff --git a/imap-send.c b/imap-send.c index 5c7e27a894..857591660f 100644 --- a/imap-send.c +++ b/imap-send.c @@ -964,7 +964,7 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc, char *f int gai; char portstr[6]; - snprintf(portstr, sizeof(portstr), "%d", srvc->port); + xsnprintf(portstr, sizeof(portstr), "%d", srvc->port); memset(&hints, 0, sizeof(hints)); hints.ai_socktype = SOCK_STREAM; diff --git a/mailinfo.c b/mailinfo.c index a489d9d0fb..68037758f2 100644 --- a/mailinfo.c +++ b/mailinfo.c @@ -757,8 +757,13 @@ static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line) assert(!mi->filter_stage); if (mi->header_stage) { - if (!line->len || (line->len == 1 && line->buf[0] == '\n')) + if (!line->len || (line->len == 1 && line->buf[0] == '\n')) { + if (mi->inbody_header_accum.len) { + flush_inbody_header_accum(mi); + mi->header_stage = 0; + } return 0; + } } if (mi->use_inbody_headers && mi->header_stage) { diff --git a/name-hash.c b/name-hash.c index 6d9f23e932..cac313c78d 100644 --- a/name-hash.c +++ b/name-hash.c @@ -23,15 +23,21 @@ static int dir_entry_cmp(const struct dir_entry *e1, name ? name : e2->name, e1->namelen); } -static struct dir_entry *find_dir_entry(struct index_state *istate, - const char *name, unsigned int namelen) +static struct dir_entry *find_dir_entry__hash(struct index_state *istate, + const char *name, unsigned int namelen, unsigned int hash) { struct dir_entry key; - hashmap_entry_init(&key, memihash(name, namelen)); + hashmap_entry_init(&key, hash); key.namelen = namelen; return hashmap_get(&istate->dir_hash, &key, name); } +static struct dir_entry *find_dir_entry(struct index_state *istate, + const char *name, unsigned int namelen) +{ + return find_dir_entry__hash(istate, name, namelen, memihash(name, namelen)); +} + static struct dir_entry *hash_dir_entry(struct index_state *istate, struct cache_entry *ce, int namelen) { @@ -112,20 +118,493 @@ static int cache_entry_cmp(const struct cache_entry *ce1, return remove ? !(ce1 == ce2) : 0; } -static void lazy_init_name_hash(struct index_state *istate) +static int lazy_try_threaded = 1; +static int lazy_nr_dir_threads; + +#ifdef NO_PTHREADS + +static inline int lookup_lazy_params(struct index_state *istate) { - int nr; + return 0; +} + +static inline void threaded_lazy_init_name_hash( + struct index_state *istate) +{ +} + +#else + +#include "thread-utils.h" + +/* + * Set a minimum number of cache_entries that we will handle per + * thread and use that to decide how many threads to run (upto + * the number on the system). + * + * For guidance setting the lower per-thread bound, see: + * t/helper/test-lazy-init-name-hash --analyze + */ +#define LAZY_THREAD_COST (2000) + +/* + * We use n mutexes to guard n partitions of the "istate->dir_hash" + * hashtable. Since "find" and "insert" operations will hash to a + * particular bucket and modify/search a single chain, we can say + * that "all chains mod n" are guarded by the same mutex -- rather + * than having a single mutex to guard the entire table. (This does + * require that we disable "rehashing" on the hashtable.) + * + * So, a larger value here decreases the probability of a collision + * and the time that each thread must wait for the mutex. + */ +#define LAZY_MAX_MUTEX (32) + +static pthread_mutex_t *lazy_dir_mutex_array; + +/* + * An array of lazy_entry items is used by the n threads in + * the directory parse (first) phase to (lock-free) store the + * intermediate results. These values are then referenced by + * the 2 threads in the second phase. + */ +struct lazy_entry { + struct dir_entry *dir; + unsigned int hash_dir; + unsigned int hash_name; +}; + +/* + * Decide if we want to use threads (if available) to load + * the hash tables. We set "lazy_nr_dir_threads" to zero when + * it is not worth it. + */ +static int lookup_lazy_params(struct index_state *istate) +{ + int nr_cpus; + + lazy_nr_dir_threads = 0; + + if (!lazy_try_threaded) + return 0; + + /* + * If we are respecting case, just use the original + * code to build the "istate->name_hash". We don't + * need the complexity here. + */ + if (!ignore_case) + return 0; + + nr_cpus = online_cpus(); + if (nr_cpus < 2) + return 0; + + if (istate->cache_nr < 2 * LAZY_THREAD_COST) + return 0; + + if (istate->cache_nr < nr_cpus * LAZY_THREAD_COST) + nr_cpus = istate->cache_nr / LAZY_THREAD_COST; + lazy_nr_dir_threads = nr_cpus; + return lazy_nr_dir_threads; +} + +/* + * Initialize n mutexes for use when searching and inserting + * into "istate->dir_hash". All "dir" threads are trying + * to insert partial pathnames into the hash as they iterate + * over their portions of the index, so lock contention is + * high. + * + * However, the hashmap is going to put items into bucket + * chains based on their hash values. Use that to create n + * mutexes and lock on mutex[bucket(hash) % n]. This will + * decrease the collision rate by (hopefully) by a factor of n. + */ +static void init_dir_mutex(void) +{ + int j; + + lazy_dir_mutex_array = xcalloc(LAZY_MAX_MUTEX, sizeof(pthread_mutex_t)); + + for (j = 0; j < LAZY_MAX_MUTEX; j++) + init_recursive_mutex(&lazy_dir_mutex_array[j]); +} + +static void cleanup_dir_mutex(void) +{ + int j; + + for (j = 0; j < LAZY_MAX_MUTEX; j++) + pthread_mutex_destroy(&lazy_dir_mutex_array[j]); + + free(lazy_dir_mutex_array); +} + +static void lock_dir_mutex(int j) +{ + pthread_mutex_lock(&lazy_dir_mutex_array[j]); +} + +static void unlock_dir_mutex(int j) +{ + pthread_mutex_unlock(&lazy_dir_mutex_array[j]); +} + +static inline int compute_dir_lock_nr( + const struct hashmap *map, + unsigned int hash) +{ + return hashmap_bucket(map, hash) % LAZY_MAX_MUTEX; +} + +static struct dir_entry *hash_dir_entry_with_parent_and_prefix( + struct index_state *istate, + struct dir_entry *parent, + struct strbuf *prefix) +{ + struct dir_entry *dir; + unsigned int hash; + int lock_nr; + + /* + * Either we have a parent directory and path with slash(es) + * or the directory is an immediate child of the root directory. + */ + assert((parent != NULL) ^ (strchr(prefix->buf, '/') == NULL)); + + if (parent) + hash = memihash_cont(parent->ent.hash, + prefix->buf + parent->namelen, + prefix->len - parent->namelen); + else + hash = memihash(prefix->buf, prefix->len); + + lock_nr = compute_dir_lock_nr(&istate->dir_hash, hash); + lock_dir_mutex(lock_nr); + + dir = find_dir_entry__hash(istate, prefix->buf, prefix->len, hash); + if (!dir) { + FLEX_ALLOC_MEM(dir, name, prefix->buf, prefix->len); + hashmap_entry_init(dir, hash); + dir->namelen = prefix->len; + dir->parent = parent; + hashmap_add(&istate->dir_hash, dir); + + if (parent) { + unlock_dir_mutex(lock_nr); + + /* All I really need here is an InterlockedIncrement(&(parent->nr)) */ + lock_nr = compute_dir_lock_nr(&istate->dir_hash, parent->ent.hash); + lock_dir_mutex(lock_nr); + parent->nr++; + } + } + + unlock_dir_mutex(lock_nr); + return dir; +} + +/* + * handle_range_1() and handle_range_dir() are derived from + * clear_ce_flags_1() and clear_ce_flags_dir() in unpack-trees.c + * and handle the iteration over the entire array of index entries. + * They use recursion for adjacent entries in the same parent + * directory. + */ +static int handle_range_1( + struct index_state *istate, + int k_start, + int k_end, + struct dir_entry *parent, + struct strbuf *prefix, + struct lazy_entry *lazy_entries); + +static int handle_range_dir( + struct index_state *istate, + int k_start, + int k_end, + struct dir_entry *parent, + struct strbuf *prefix, + struct lazy_entry *lazy_entries, + struct dir_entry **dir_new_out) +{ + int rc, k; + int input_prefix_len = prefix->len; + struct dir_entry *dir_new; + + dir_new = hash_dir_entry_with_parent_and_prefix(istate, parent, prefix); + + strbuf_addch(prefix, '/'); + + /* + * Scan forward in the index array for index entries having the same + * path prefix (that are also in this directory). + */ + if (strncmp(istate->cache[k_start + 1]->name, prefix->buf, prefix->len) > 0) + k = k_start + 1; + else if (strncmp(istate->cache[k_end - 1]->name, prefix->buf, prefix->len) == 0) + k = k_end; + else { + int begin = k_start; + int end = k_end; + while (begin < end) { + int mid = (begin + end) >> 1; + int cmp = strncmp(istate->cache[mid]->name, prefix->buf, prefix->len); + if (cmp == 0) /* mid has same prefix; look in second part */ + begin = mid + 1; + else if (cmp > 0) /* mid is past group; look in first part */ + end = mid; + else + die("cache entry out of order"); + } + k = begin; + } + + /* + * Recurse and process what we can of this subset [k_start, k). + */ + rc = handle_range_1(istate, k_start, k, dir_new, prefix, lazy_entries); + + strbuf_setlen(prefix, input_prefix_len); + + *dir_new_out = dir_new; + return rc; +} + +static int handle_range_1( + struct index_state *istate, + int k_start, + int k_end, + struct dir_entry *parent, + struct strbuf *prefix, + struct lazy_entry *lazy_entries) +{ + int input_prefix_len = prefix->len; + int k = k_start; + + while (k < k_end) { + struct cache_entry *ce_k = istate->cache[k]; + const char *name, *slash; + + if (prefix->len && strncmp(ce_k->name, prefix->buf, prefix->len)) + break; + + name = ce_k->name + prefix->len; + slash = strchr(name, '/'); + + if (slash) { + int len = slash - name; + int processed; + struct dir_entry *dir_new; + + strbuf_add(prefix, name, len); + processed = handle_range_dir(istate, k, k_end, parent, prefix, lazy_entries, &dir_new); + if (processed) { + k += processed; + strbuf_setlen(prefix, input_prefix_len); + continue; + } + + strbuf_addch(prefix, '/'); + processed = handle_range_1(istate, k, k_end, dir_new, prefix, lazy_entries); + k += processed; + strbuf_setlen(prefix, input_prefix_len); + continue; + } + + /* + * It is too expensive to take a lock to insert "ce_k" + * into "istate->name_hash" and increment the ref-count + * on the "parent" dir. So we defer actually updating + * permanent data structures until phase 2 (where we + * can change the locking requirements) and simply + * accumulate our current results into the lazy_entries + * data array). + * + * We do not need to lock the lazy_entries array because + * we have exclusive access to the cells in the range + * [k_start,k_end) that this thread was given. + */ + lazy_entries[k].dir = parent; + if (parent) { + lazy_entries[k].hash_name = memihash_cont( + parent->ent.hash, + ce_k->name + parent->namelen, + ce_namelen(ce_k) - parent->namelen); + lazy_entries[k].hash_dir = parent->ent.hash; + } else { + lazy_entries[k].hash_name = memihash(ce_k->name, ce_namelen(ce_k)); + } + + k++; + } + + return k - k_start; +} + +struct lazy_dir_thread_data { + pthread_t pthread; + struct index_state *istate; + struct lazy_entry *lazy_entries; + int k_start; + int k_end; +}; + +static void *lazy_dir_thread_proc(void *_data) +{ + struct lazy_dir_thread_data *d = _data; + struct strbuf prefix = STRBUF_INIT; + handle_range_1(d->istate, d->k_start, d->k_end, NULL, &prefix, d->lazy_entries); + strbuf_release(&prefix); + return NULL; +} + +struct lazy_name_thread_data { + pthread_t pthread; + struct index_state *istate; + struct lazy_entry *lazy_entries; +}; + +static void *lazy_name_thread_proc(void *_data) +{ + struct lazy_name_thread_data *d = _data; + int k; + + for (k = 0; k < d->istate->cache_nr; k++) { + struct cache_entry *ce_k = d->istate->cache[k]; + ce_k->ce_flags |= CE_HASHED; + hashmap_entry_init(ce_k, d->lazy_entries[k].hash_name); + hashmap_add(&d->istate->name_hash, ce_k); + } + + return NULL; +} + +static inline void lazy_update_dir_ref_counts( + struct index_state *istate, + struct lazy_entry *lazy_entries) +{ + int k; + + for (k = 0; k < istate->cache_nr; k++) { + if (lazy_entries[k].dir) + lazy_entries[k].dir->nr++; + } +} + +static void threaded_lazy_init_name_hash( + struct index_state *istate) +{ + int nr_each; + int k_start; + int t; + struct lazy_entry *lazy_entries; + struct lazy_dir_thread_data *td_dir; + struct lazy_name_thread_data *td_name; + + k_start = 0; + nr_each = DIV_ROUND_UP(istate->cache_nr, lazy_nr_dir_threads); + + lazy_entries = xcalloc(istate->cache_nr, sizeof(struct lazy_entry)); + td_dir = xcalloc(lazy_nr_dir_threads, sizeof(struct lazy_dir_thread_data)); + td_name = xcalloc(1, sizeof(struct lazy_name_thread_data)); + + init_dir_mutex(); + + /* + * Phase 1: + * Build "istate->dir_hash" using n "dir" threads (and a read-only index). + */ + for (t = 0; t < lazy_nr_dir_threads; t++) { + struct lazy_dir_thread_data *td_dir_t = td_dir + t; + td_dir_t->istate = istate; + td_dir_t->lazy_entries = lazy_entries; + td_dir_t->k_start = k_start; + k_start += nr_each; + if (k_start > istate->cache_nr) + k_start = istate->cache_nr; + td_dir_t->k_end = k_start; + if (pthread_create(&td_dir_t->pthread, NULL, lazy_dir_thread_proc, td_dir_t)) + die("unable to create lazy_dir_thread"); + } + for (t = 0; t < lazy_nr_dir_threads; t++) { + struct lazy_dir_thread_data *td_dir_t = td_dir + t; + if (pthread_join(td_dir_t->pthread, NULL)) + die("unable to join lazy_dir_thread"); + } + + /* + * Phase 2: + * Iterate over all index entries and add them to the "istate->name_hash" + * using a single "name" background thread. + * (Testing showed it wasn't worth running more than 1 thread for this.) + * + * Meanwhile, finish updating the parent directory ref-counts for each + * index entry using the current thread. (This step is very fast and + * doesn't need threading.) + */ + td_name->istate = istate; + td_name->lazy_entries = lazy_entries; + if (pthread_create(&td_name->pthread, NULL, lazy_name_thread_proc, td_name)) + die("unable to create lazy_name_thread"); + + lazy_update_dir_ref_counts(istate, lazy_entries); + + if (pthread_join(td_name->pthread, NULL)) + die("unable to join lazy_name_thread"); + + cleanup_dir_mutex(); + + free(td_name); + free(td_dir); + free(lazy_entries); +} + +#endif + +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, istate->cache_nr); - hashmap_init(&istate->dir_hash, (hashmap_cmp_fn) dir_entry_cmp, 0); - for (nr = 0; nr < istate->cache_nr; nr++) - hash_index_entry(istate, istate->cache[nr]); + hashmap_init(&istate->dir_hash, (hashmap_cmp_fn) dir_entry_cmp, + istate->cache_nr); + + if (lookup_lazy_params(istate)) { + hashmap_disallow_rehash(&istate->dir_hash, 1); + threaded_lazy_init_name_hash(istate); + hashmap_disallow_rehash(&istate->dir_hash, 0); + } else { + int nr; + for (nr = 0; nr < istate->cache_nr; nr++) + hash_index_entry(istate, istate->cache[nr]); + } + istate->name_hash_initialized = 1; } +/* + * A test routine for t/helper/ sources. + * + * Returns the number of threads used or 0 when + * the non-threaded code path was used. + * + * Requesting threading WILL NOT override guards + * in lookup_lazy_params(). + */ +int test_lazy_init_name_hash(struct index_state *istate, int try_threaded) +{ + lazy_nr_dir_threads = 0; + lazy_try_threaded = try_threaded; + + lazy_init_name_hash(istate); + + return lazy_nr_dir_threads; +} + void add_name_hash(struct index_state *istate, struct cache_entry *ce) { if (istate->name_hash_initialized) @@ -153,8 +153,8 @@ static struct leaf_node *note_tree_find(struct notes_tree *t, * How to consolidate an int_node: * If there are > 1 non-NULL entries, give up and return non-zero. * Otherwise replace the int_node at the given index in the given parent node - * with the only entry (or a NULL entry if no entries) from the given tree, - * and return 0. + * with the only NOTE entry (or a NULL entry if no entries) from the given + * tree, and return 0. */ static int note_tree_consolidate(struct int_node *tree, struct int_node *parent, unsigned char index) @@ -173,6 +173,8 @@ static int note_tree_consolidate(struct int_node *tree, } } + if (p && (GET_PTR_TYPE(p) != PTR_TYPE_NOTE)) + return -2; /* replace tree with p in parent[index] */ parent->a[index] = p; free(tree); diff --git a/pack-bitmap-write.c b/pack-bitmap-write.c index 9705596014..e313f4f2bc 100644 --- a/pack-bitmap-write.c +++ b/pack-bitmap-write.c @@ -508,18 +508,16 @@ void bitmap_writer_finish(struct pack_idx_entry **index, const char *filename, uint16_t options) { - static char tmp_file[PATH_MAX]; static uint16_t default_version = 1; static uint16_t flags = BITMAP_OPT_FULL_DAG; + struct strbuf tmp_file = STRBUF_INIT; struct sha1file *f; struct bitmap_disk_header header; - int fd = odb_mkstemp(tmp_file, sizeof(tmp_file), "pack/tmp_bitmap_XXXXXX"); + int fd = odb_mkstemp(&tmp_file, "pack/tmp_bitmap_XXXXXX"); - if (fd < 0) - die_errno("unable to create '%s'", tmp_file); - f = sha1fd(fd, tmp_file); + f = sha1fd(fd, tmp_file.buf); memcpy(header.magic, BITMAP_IDX_SIGNATURE, sizeof(BITMAP_IDX_SIGNATURE)); header.version = htons(default_version); @@ -539,9 +537,11 @@ void bitmap_writer_finish(struct pack_idx_entry **index, sha1close(f, NULL, CSUM_FSYNC); - if (adjust_shared_perm(tmp_file)) + if (adjust_shared_perm(tmp_file.buf)) die_errno("unable to make temporary bitmap file readable"); - if (rename(tmp_file, filename)) + if (rename(tmp_file.buf, filename)) die_errno("unable to rename temporary bitmap file to '%s'", filename); + + strbuf_release(&tmp_file); } diff --git a/pack-write.c b/pack-write.c index 88bc7f9f7d..fa97b72559 100644 --- a/pack-write.c +++ b/pack-write.c @@ -71,15 +71,15 @@ const char *write_idx_file(const char *index_name, struct pack_idx_entry **objec f = sha1fd_check(index_name); } else { if (!index_name) { - static char tmp_file[PATH_MAX]; - fd = odb_mkstemp(tmp_file, sizeof(tmp_file), "pack/tmp_idx_XXXXXX"); - index_name = xstrdup(tmp_file); + struct strbuf tmp_file = STRBUF_INIT; + fd = odb_mkstemp(&tmp_file, "pack/tmp_idx_XXXXXX"); + index_name = strbuf_detach(&tmp_file, NULL); } else { unlink(index_name); fd = open(index_name, O_CREAT|O_EXCL|O_WRONLY, 0600); + if (fd < 0) + die_errno("unable to create '%s'", index_name); } - if (fd < 0) - die_errno("unable to create '%s'", index_name); f = sha1fd(fd, index_name); } @@ -304,7 +304,8 @@ char *index_pack_lockfile(int ip_out) * - each byte afterwards: low seven bits are size continuation, * with the high bit being "size continues" */ -int encode_in_pack_object_header(enum object_type type, uintmax_t size, unsigned char *hdr) +int encode_in_pack_object_header(unsigned char *hdr, int hdr_len, + enum object_type type, uintmax_t size) { int n = 1; unsigned char c; @@ -315,6 +316,8 @@ int encode_in_pack_object_header(enum object_type type, uintmax_t size, unsigned c = (type << 4) | (size & 15); size >>= 4; while (size) { + if (n == hdr_len) + die("object size is too enormous to format"); *hdr++ = c | 0x80; c = size & 0x7f; size >>= 7; @@ -326,11 +329,11 @@ int encode_in_pack_object_header(enum object_type type, uintmax_t size, unsigned struct sha1file *create_tmp_packfile(char **pack_tmp_name) { - char tmpname[PATH_MAX]; + struct strbuf tmpname = STRBUF_INIT; int fd; - fd = odb_mkstemp(tmpname, sizeof(tmpname), "pack/tmp_pack_XXXXXX"); - *pack_tmp_name = xstrdup(tmpname); + fd = odb_mkstemp(&tmpname, "pack/tmp_pack_XXXXXX"); + *pack_tmp_name = strbuf_detach(&tmpname, NULL); return sha1fd(fd, *pack_tmp_name); } @@ -84,7 +84,14 @@ extern int verify_pack(struct packed_git *, verify_fn fn, struct progress *, uin extern off_t write_pack_header(struct sha1file *f, uint32_t); extern void fixup_pack_header_footer(int, unsigned char *, const char *, uint32_t, unsigned char *, off_t); extern char *index_pack_lockfile(int fd); -extern int encode_in_pack_object_header(enum object_type, uintmax_t, unsigned char *); + +/* + * The "hdr" output buffer should be at least this big, which will handle sizes + * up to 2^67. + */ +#define MAX_PACK_OBJECT_HEADER 10 +extern int encode_in_pack_object_header(unsigned char *hdr, int hdr_len, + enum object_type, uintmax_t); #define PH_ERROR_EOF (-1) #define PH_ERROR_PACK_SIGNATURE (-2) @@ -135,9 +135,7 @@ void setup_pager(void) int pager_in_use(void) { - const char *env; - env = getenv("GIT_PAGER_IN_USE"); - return env ? git_config_bool("GIT_PAGER_IN_USE", env) : 0; + return git_env_bool("GIT_PAGER_IN_USE", 0); } /* diff --git a/parse-options-cb.c b/parse-options-cb.c index b7d8f7dcb2..7419780a9b 100644 --- a/parse-options-cb.c +++ b/parse-options-cb.c @@ -96,17 +96,17 @@ int parse_opt_commits(const struct option *opt, const char *arg, int unset) int parse_opt_object_name(const struct option *opt, const char *arg, int unset) { - unsigned char sha1[20]; + struct object_id oid; if (unset) { - sha1_array_clear(opt->value); + oid_array_clear(opt->value); return 0; } if (!arg) return -1; - if (get_sha1(arg, sha1)) + if (get_oid(arg, &oid)) return error(_("malformed object name '%s'"), arg); - sha1_array_append(opt->value, sha1); + oid_array_append(opt->value, &oid); return 0; } diff --git a/parse-options.c b/parse-options.c index 4fbe924a5d..a23a1e67f0 100644 --- a/parse-options.c +++ b/parse-options.c @@ -40,7 +40,7 @@ static void fix_filename(const char *prefix, const char **file) if (!file || !*file || !prefix || is_absolute_path(*file) || !strcmp("-", *file)) return; - *file = xstrdup(prefix_filename(prefix, strlen(prefix), *file)); + *file = prefix_filename(prefix, *file); } static int opt_command_mode_error(const struct option *opt, diff --git a/parse-options.h b/parse-options.h index dcd8a0926c..af711227ae 100644 --- a/parse-options.h +++ b/parse-options.h @@ -258,7 +258,9 @@ extern int parse_opt_passthru_argv(const struct option *, const char *, int); PARSE_OPT_LASTARG_DEFAULT | flag, \ parse_opt_commits, (intptr_t) "HEAD" \ } -#define OPT_CONTAINS(v, h) _OPT_CONTAINS_OR_WITH("contains", v, h, 0) -#define OPT_WITH(v, h) _OPT_CONTAINS_OR_WITH("with", v, h, PARSE_OPT_HIDDEN) +#define OPT_CONTAINS(v, h) _OPT_CONTAINS_OR_WITH("contains", v, h, PARSE_OPT_NONEG) +#define OPT_NO_CONTAINS(v, h) _OPT_CONTAINS_OR_WITH("no-contains", v, h, PARSE_OPT_NONEG) +#define OPT_WITH(v, h) _OPT_CONTAINS_OR_WITH("with", v, h, PARSE_OPT_HIDDEN | PARSE_OPT_NONEG) +#define OPT_WITHOUT(v, h) _OPT_CONTAINS_OR_WITH("without", v, h, PARSE_OPT_HIDDEN | PARSE_OPT_NONEG) #endif diff --git a/patch-ids.c b/patch-ids.c index ce285c2e0c..fa8f11de82 100644 --- a/patch-ids.c +++ b/patch-ids.c @@ -71,7 +71,7 @@ static int init_patch_id_entry(struct patch_id *patch, struct commit *commit, struct patch_ids *ids) { - unsigned char header_only_patch_id[GIT_SHA1_RAWSZ]; + unsigned char header_only_patch_id[GIT_MAX_RAWSZ]; patch->commit = commit; if (commit_patch_id(commit, &ids->diffopts, header_only_patch_id, 1)) diff --git a/patch-ids.h b/patch-ids.h index 0f34ea11ea..b9e5751f8e 100644 --- a/patch-ids.h +++ b/patch-ids.h @@ -3,7 +3,7 @@ struct patch_id { struct hashmap_entry ent; - unsigned char patch_id[GIT_SHA1_RAWSZ]; + unsigned char patch_id[GIT_MAX_RAWSZ]; struct commit *commit; }; @@ -1251,6 +1251,21 @@ char *xdg_config_home(const char *filename) return NULL; } +char *xdg_cache_home(const char *filename) +{ + const char *home, *cache_home; + + assert(filename); + cache_home = getenv("XDG_CACHE_HOME"); + if (cache_home && *cache_home) + return mkpathdup("%s/git/%s", cache_home, filename); + + home = getenv("HOME"); + if (home) + return mkpathdup("%s/.cache/git/%s", home, filename); + return NULL; +} + GIT_PATH_FUNC(git_path_cherry_pick_head, "CHERRY_PICK_HEAD") GIT_PATH_FUNC(git_path_revert_head, "REVERT_HEAD") GIT_PATH_FUNC(git_path_squash_msg, "SQUASH_MSG") @@ -7530,7 +7530,19 @@ msgstr "git describe [<Optionen>] [<Commit-Angabe>...]" msgid "git describe [<options>] --dirty" msgstr "git describe [<Optionen>] --dirty" -#: builtin/describe.c:217 +#: builtin/describe.c:52 +msgid "head" +msgstr "Branch" + +#: builtin/describe.c:52 +msgid "lightweight" +msgstr "nicht-annotiert" + +#: builtin/describe.c:52 +msgid "annotated" +msgstr "annotiert" + +#: builtin/describe.c:249 #, c-format msgid "annotated tag %s not available" msgstr "annotiertes Tag %s ist nicht verfügbar" diff --git a/ref-filter.c b/ref-filter.c index 9c82b5b9d6..3a640448fd 100644 --- a/ref-filter.c +++ b/ref-filter.c @@ -1487,6 +1487,7 @@ struct ref_filter_cbdata { struct ref_array *array; struct ref_filter *filter; struct contains_cache contains_cache; + struct contains_cache no_contains_cache; }; /* @@ -1586,11 +1587,11 @@ static enum contains_result contains_tag_algo(struct commit *candidate, } static int commit_contains(struct ref_filter *filter, struct commit *commit, - struct contains_cache *cache) + struct commit_list *list, struct contains_cache *cache) { if (filter->with_commit_tag_algo) - return contains_tag_algo(commit, filter->with_commit, cache) == CONTAINS_YES; - return is_descendant_of(commit, filter->with_commit); + return contains_tag_algo(commit, list, cache) == CONTAINS_YES; + return is_descendant_of(commit, list); } /* @@ -1677,22 +1678,22 @@ static int filter_pattern_match(struct ref_filter *filter, const char *refname) * the need to parse the object via parse_object(). peel_ref() might be a * more efficient alternative to obtain the pointee. */ -static const unsigned char *match_points_at(struct sha1_array *points_at, - const unsigned char *sha1, - const char *refname) +static const struct object_id *match_points_at(struct oid_array *points_at, + const struct object_id *oid, + const char *refname) { - const unsigned char *tagged_sha1 = NULL; + const struct object_id *tagged_oid = NULL; struct object *obj; - if (sha1_array_lookup(points_at, sha1) >= 0) - return sha1; - obj = parse_object(sha1); + if (oid_array_lookup(points_at, oid) >= 0) + return oid; + obj = parse_object(oid->hash); if (!obj) die(_("malformed object at '%s'"), refname); if (obj->type == OBJ_TAG) - tagged_sha1 = ((struct tag *)obj)->tagged->oid.hash; - if (tagged_sha1 && sha1_array_lookup(points_at, tagged_sha1) >= 0) - return tagged_sha1; + tagged_oid = &((struct tag *)obj)->tagged->oid; + if (tagged_oid && oid_array_lookup(points_at, tagged_oid) >= 0) + return tagged_oid; return NULL; } @@ -1772,7 +1773,7 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid, if (!filter_pattern_match(filter, refname)) return 0; - if (filter->points_at.nr && !match_points_at(&filter->points_at, oid->hash, refname)) + if (filter->points_at.nr && !match_points_at(&filter->points_at, oid, refname)) return 0; /* @@ -1780,13 +1781,17 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid, * obtain the commit using the 'oid' available and discard all * non-commits early. The actual filtering is done later. */ - if (filter->merge_commit || filter->with_commit || filter->verbose) { + if (filter->merge_commit || filter->with_commit || filter->no_commit || filter->verbose) { commit = lookup_commit_reference_gently(oid->hash, 1); if (!commit) return 0; - /* We perform the filtering for the '--contains' option */ + /* We perform the filtering for the '--contains' option... */ if (filter->with_commit && - !commit_contains(filter, commit, &ref_cbdata->contains_cache)) + !commit_contains(filter, commit, filter->with_commit, &ref_cbdata->contains_cache)) + return 0; + /* ...or for the `--no-contains' option */ + if (filter->no_commit && + commit_contains(filter, commit, filter->no_commit, &ref_cbdata->no_contains_cache)) return 0; } @@ -1887,6 +1892,7 @@ int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int filter->kind = type & FILTER_REFS_KIND_MASK; init_contains_cache(&ref_cbdata.contains_cache); + init_contains_cache(&ref_cbdata.no_contains_cache); /* Simple per-ref filtering */ if (!filter->kind) @@ -1911,6 +1917,7 @@ int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int } clear_contains_cache(&ref_cbdata.contains_cache); + clear_contains_cache(&ref_cbdata.no_contains_cache); /* Filters that need revision walking */ if (filter->merge_commit) @@ -2084,8 +2091,17 @@ int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset) { struct ref_filter *rf = opt->value; unsigned char sha1[20]; + int no_merged = starts_with(opt->long_name, "no"); + + if (rf->merge) { + if (no_merged) { + return opterror(opt, "is incompatible with --merged", 0); + } else { + return opterror(opt, "is incompatible with --no-merged", 0); + } + } - rf->merge = starts_with(opt->long_name, "no") + rf->merge = no_merged ? REF_FILTER_MERGED_OMIT : REF_FILTER_MERGED_INCLUDE; diff --git a/ref-filter.h b/ref-filter.h index e738c5dfd3..c20167aa3c 100644 --- a/ref-filter.h +++ b/ref-filter.h @@ -51,8 +51,9 @@ struct ref_array { struct ref_filter { const char **name_patterns; - struct sha1_array points_at; + struct oid_array points_at; struct commit_list *with_commit; + struct commit_list *no_commit; enum { REF_FILTER_MERGED_NONE = 0, @@ -404,11 +404,11 @@ int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data) const char *prettify_refname(const char *name) { - return name + ( - starts_with(name, "refs/heads/") ? 11 : - starts_with(name, "refs/tags/") ? 10 : - starts_with(name, "refs/remotes/") ? 13 : - 0); + if (skip_prefix(name, "refs/heads/", &name) || + skip_prefix(name, "refs/tags/", &name) || + skip_prefix(name, "refs/remotes/", &name)) + ; /* nothing */ + return name; } static const char *ref_rev_parse_rules[] = { @@ -467,29 +467,31 @@ int expand_ref(const char *str, int len, unsigned char *sha1, char **ref) { const char **p, *r; int refs_found = 0; + struct strbuf fullref = STRBUF_INIT; *ref = NULL; for (p = ref_rev_parse_rules; *p; p++) { - char fullref[PATH_MAX]; unsigned char sha1_from_ref[20]; unsigned char *this_result; int flag; this_result = refs_found ? sha1_from_ref : sha1; - mksnpath(fullref, sizeof(fullref), *p, len, str); - r = resolve_ref_unsafe(fullref, RESOLVE_REF_READING, + strbuf_reset(&fullref); + strbuf_addf(&fullref, *p, len, str); + r = resolve_ref_unsafe(fullref.buf, RESOLVE_REF_READING, this_result, &flag); if (r) { if (!refs_found++) *ref = xstrdup(r); if (!warn_ambiguous_refs) break; - } else if ((flag & REF_ISSYMREF) && strcmp(fullref, "HEAD")) { - warning("ignoring dangling symref %s.", fullref); - } else if ((flag & REF_ISBROKEN) && strchr(fullref, '/')) { - warning("ignoring broken ref %s.", fullref); + } else if ((flag & REF_ISSYMREF) && strcmp(fullref.buf, "HEAD")) { + warning("ignoring dangling symref %s.", fullref.buf); + } else if ((flag & REF_ISBROKEN) && strchr(fullref.buf, '/')) { + warning("ignoring broken ref %s.", fullref.buf); } } + strbuf_release(&fullref); return refs_found; } @@ -498,21 +500,22 @@ int dwim_log(const char *str, int len, unsigned char *sha1, char **log) char *last_branch = substitute_branch_name(&str, &len); const char **p; int logs_found = 0; + struct strbuf path = STRBUF_INIT; *log = NULL; for (p = ref_rev_parse_rules; *p; p++) { unsigned char hash[20]; - char path[PATH_MAX]; const char *ref, *it; - mksnpath(path, sizeof(path), *p, len, str); - ref = resolve_ref_unsafe(path, RESOLVE_REF_READING, + strbuf_reset(&path); + strbuf_addf(&path, *p, len, str); + ref = resolve_ref_unsafe(path.buf, RESOLVE_REF_READING, hash, NULL); if (!ref) continue; - if (reflog_exists(path)) - it = path; - else if (strcmp(ref, path) && reflog_exists(ref)) + if (reflog_exists(path.buf)) + it = path.buf; + else if (strcmp(ref, path.buf) && reflog_exists(ref)) it = ref; else continue; @@ -523,6 +526,7 @@ int dwim_log(const char *str, int len, unsigned char *sha1, char **log) if (!warn_ambiguous_refs) break; } + strbuf_release(&path); free(last_branch); return logs_found; } @@ -1013,6 +1017,7 @@ char *shorten_unambiguous_ref(const char *refname, int strict) static char **scanf_fmts; static int nr_rules; char *short_name; + struct strbuf resolved_buf = STRBUF_INIT; if (!nr_rules) { /* @@ -1071,7 +1076,6 @@ char *shorten_unambiguous_ref(const char *refname, int strict) */ for (j = 0; j < rules_to_fail; j++) { const char *rule = ref_rev_parse_rules[j]; - char refname[PATH_MAX]; /* skip matched rule */ if (i == j) @@ -1082,9 +1086,10 @@ char *shorten_unambiguous_ref(const char *refname, int strict) * (with this previous rule) to a valid ref * read_ref() returns 0 on success */ - mksnpath(refname, sizeof(refname), - rule, short_name_len, short_name); - if (ref_exists(refname)) + strbuf_reset(&resolved_buf); + strbuf_addf(&resolved_buf, rule, + short_name_len, short_name); + if (ref_exists(resolved_buf.buf)) break; } @@ -1092,10 +1097,13 @@ char *shorten_unambiguous_ref(const char *refname, int strict) * short name is non-ambiguous if all previous rules * haven't resolved to a valid ref */ - if (j == rules_to_fail) + if (j == rules_to_fail) { + strbuf_release(&resolved_buf); return short_name; + } } + strbuf_release(&resolved_buf); free(short_name); return xstrdup(refname); } diff --git a/remote-curl.c b/remote-curl.c index 34a97e7328..d41fe16ff3 100644 --- a/remote-curl.c +++ b/remote-curl.c @@ -22,6 +22,7 @@ struct options { unsigned long depth; char *deepen_since; struct string_list deepen_not; + struct string_list push_options; unsigned progress : 1, check_self_contained_and_connected : 1, cloning : 1, @@ -139,6 +140,9 @@ static int set_option(const char *name, const char *value) else return -1; return 0; + } else if (!strcmp(name, "push-option")) { + string_list_append(&options.push_options, value); + return 0; #if LIBCURL_VERSION_NUM >= 0x070a08 } else if (!strcmp(name, "family")) { @@ -163,7 +167,7 @@ struct discovery { char *buf; size_t len; struct ref *refs; - struct sha1_array shallow; + struct oid_array shallow; unsigned proto_git : 1; }; static struct discovery *last_discovery; @@ -230,7 +234,7 @@ static void free_discovery(struct discovery *d) if (d) { if (d == last_discovery) last_discovery = NULL; - free(d->shallow.sha1); + free(d->shallow.oid); free(d->buf_alloc); free_refs(d->refs); free(d); @@ -943,6 +947,9 @@ static int push_git(struct discovery *heads, int nr_spec, char **specs) argv_array_push(&args, "--quiet"); else if (options.verbosity > 1) argv_array_push(&args, "--verbose"); + for (i = 0; i < options.push_options.nr; i++) + argv_array_pushf(&args, "--push-option=%s", + options.push_options.items[i].string); argv_array_push(&args, options.progress ? "--progress" : "--no-progress"); for_each_string_list_item(cas_option, &cas_options) argv_array_push(&args, cas_option->string); @@ -1028,6 +1035,7 @@ int cmd_main(int argc, const char **argv) options.progress = !!isatty(2); options.thin = 1; string_list_init(&options.deepen_not, 1); + string_list_init(&options.push_options, 1); remote = remote_get(argv[1]); @@ -630,7 +630,7 @@ struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec) return parse_refspec_internal(nr_refspec, refspec, 1, 0); } -static struct refspec *parse_push_refspec(int nr_refspec, const char **refspec) +struct refspec *parse_push_refspec(int nr_refspec, const char **refspec) { return parse_refspec_internal(nr_refspec, refspec, 0, 0); } @@ -2279,7 +2279,7 @@ static struct push_cas *add_cas_entry(struct push_cas_option *cas, return entry; } -int parse_push_cas_option(struct push_cas_option *cas, const char *arg, int unset) +static int parse_push_cas_option(struct push_cas_option *cas, const char *arg, int unset) { const char *colon; struct push_cas *entry; @@ -149,11 +149,11 @@ int check_ref_type(const struct ref *ref, int flags); */ void free_refs(struct ref *ref); -struct sha1_array; +struct oid_array; extern struct ref **get_remote_heads(int in, char *src_buf, size_t src_len, struct ref **list, unsigned int flags, - struct sha1_array *extra_have, - struct sha1_array *shallow); + struct oid_array *extra_have, + struct oid_array *shallow); int resolve_remote_symref(struct ref *ref, struct ref *list); int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid); @@ -169,6 +169,7 @@ struct ref *ref_remove_duplicates(struct ref *ref_map); int valid_fetch_refspec(const char *refspec); struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec); +extern struct refspec *parse_push_refspec(int nr_refspec, const char **refspec); void free_refspec(int nr_refspec, struct refspec *refspec); @@ -290,7 +291,6 @@ struct push_cas_option { }; extern int parseopt_push_cas_option(const struct option *, const char *arg, int unset); -extern int parse_push_cas_option(struct push_cas_option *, const char *arg, int unset); extern int is_empty_cas(const struct push_cas_option *); void apply_push_cas(struct push_cas_option *, struct remote *, struct ref *); diff --git a/revision.h b/revision.h index 9fac1a607d..14886ec92b 100644 --- a/revision.h +++ b/revision.h @@ -259,8 +259,6 @@ extern void put_revision_mark(const struct rev_info *revs, extern void mark_parents_uninteresting(struct commit *commit); extern void mark_tree_uninteresting(struct tree *tree); -char *path_name(struct strbuf *path, const char *name); - extern void show_object_with_name(FILE *, struct object *, const char *); extern void add_pending_object(struct rev_info *revs, diff --git a/run-command.c b/run-command.c index 5227f78aea..574b81d3e8 100644 --- a/run-command.c +++ b/run-command.c @@ -48,7 +48,7 @@ static void cleanup_children(int sig, int in_signal) kill(p->pid, sig); - if (p->process->wait_after_clean) { + if (p->process && p->process->wait_after_clean) { p->next = children_to_wait_for; children_to_wait_for = p; } else { diff --git a/send-pack.c b/send-pack.c index d2d2a49a02..78bb34ebec 100644 --- a/send-pack.c +++ b/send-pack.c @@ -50,7 +50,7 @@ static void feed_object(const unsigned char *sha1, FILE *fh, int negative) /* * Make a pack stream and spit it out into file descriptor fd */ -static int pack_objects(int fd, struct ref *refs, struct sha1_array *extra, struct send_pack_args *args) +static int pack_objects(int fd, struct ref *refs, struct oid_array *extra, struct send_pack_args *args) { /* * The child becomes pack-objects --revs; we feed @@ -98,7 +98,7 @@ static int pack_objects(int fd, struct ref *refs, struct sha1_array *extra, stru */ po_in = xfdopen(po.in, "w"); for (i = 0; i < extra->nr; i++) - feed_object(extra->sha1[i], po_in, 1); + feed_object(extra->oid[i].hash, po_in, 1); while (refs) { if (!is_null_oid(&refs->old_oid)) @@ -376,7 +376,7 @@ static void reject_invalid_nonce(const char *nonce, int len) int send_pack(struct send_pack_args *args, int fd[], struct child_process *conn, struct ref *remote_refs, - struct sha1_array *extra_have) + struct oid_array *extra_have) { int in = fd[0]; int out = fd[1]; @@ -532,6 +532,14 @@ int send_pack(struct send_pack_args *args, } } + if (use_push_options) { + struct string_list_item *item; + + packet_buf_flush(&req_buf); + for_each_string_list_item(item, args->push_options) + packet_buf_write(&req_buf, "%s", item->string); + } + if (args->stateless_rpc) { if (!args->dry_run && (cmds_sent || is_repository_shallow())) { packet_buf_flush(&req_buf); @@ -544,18 +552,6 @@ int send_pack(struct send_pack_args *args, strbuf_release(&req_buf); strbuf_release(&cap_buf); - if (use_push_options) { - struct string_list_item *item; - struct strbuf sb = STRBUF_INIT; - - for_each_string_list_item(item, args->push_options) - packet_buf_write(&sb, "%s", item->string); - - write_or_die(out, sb.buf, sb.len); - packet_flush(out); - strbuf_release(&sb); - } - if (use_sideband && cmds_sent) { memset(&demux, 0, sizeof(demux)); demux.proc = sideband_demux; diff --git a/send-pack.h b/send-pack.h index 67fc40f4ec..6af71f7008 100644 --- a/send-pack.h +++ b/send-pack.h @@ -32,6 +32,6 @@ int option_parse_push_signed(const struct option *opt, int send_pack(struct send_pack_args *args, int fd[], struct child_process *conn, - struct ref *remote_refs, struct sha1_array *extra_have); + struct ref *remote_refs, struct oid_array *extra_have); #endif diff --git a/sequencer.c b/sequencer.c index 1f729b053b..77afecaebf 100644 --- a/sequencer.c +++ b/sequencer.c @@ -602,6 +602,12 @@ N_("you have staged changes in your working tree\n" "\n" " git rebase --continue\n"); +#define ALLOW_EMPTY (1<<0) +#define EDIT_MSG (1<<1) +#define AMEND_MSG (1<<2) +#define CLEANUP_MSG (1<<3) +#define VERIFY_MSG (1<<4) + /* * If we are cherry-pick, and if the merge did not result in * hand-editing, we will hit this commit and inherit the original @@ -615,8 +621,7 @@ N_("you have staged changes in your working tree\n" * author metadata. */ static int run_git_commit(const char *defmsg, struct replay_opts *opts, - int allow_empty, int edit, int amend, - int cleanup_commit_message) + unsigned int flags) { struct child_process cmd = CHILD_PROCESS_INIT; const char *value; @@ -624,7 +629,7 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts, cmd.git_cmd = 1; if (is_rebase_i(opts)) { - if (!edit) { + if (!(flags & EDIT_MSG)) { cmd.stdout_to_stderr = 1; cmd.err = -1; } @@ -638,9 +643,10 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts, } argv_array_push(&cmd.args, "commit"); - argv_array_push(&cmd.args, "-n"); - if (amend) + if (!(flags & VERIFY_MSG)) + argv_array_push(&cmd.args, "-n"); + if ((flags & AMEND_MSG)) argv_array_push(&cmd.args, "--amend"); if (opts->gpg_sign) argv_array_pushf(&cmd.args, "-S%s", opts->gpg_sign); @@ -648,16 +654,16 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts, argv_array_push(&cmd.args, "-s"); if (defmsg) argv_array_pushl(&cmd.args, "-F", defmsg, NULL); - if (cleanup_commit_message) + if ((flags & CLEANUP_MSG)) argv_array_push(&cmd.args, "--cleanup=strip"); - if (edit) + if ((flags & EDIT_MSG)) argv_array_push(&cmd.args, "-e"); - else if (!cleanup_commit_message && + else if (!(flags & CLEANUP_MSG) && !opts->signoff && !opts->record_origin && git_config_get_value("commit.cleanup", &value)) argv_array_push(&cmd.args, "--cleanup=verbatim"); - if (allow_empty) + if ((flags & ALLOW_EMPTY)) argv_array_push(&cmd.args, "--allow-empty"); if (opts->allow_empty_message) @@ -926,14 +932,14 @@ static void record_in_rewritten(struct object_id *oid, static int do_pick_commit(enum todo_command command, struct commit *commit, struct replay_opts *opts, int final_fixup) { - int edit = opts->edit, cleanup_commit_message = 0; - const char *msg_file = edit ? NULL : git_path_merge_msg(); + unsigned int flags = opts->edit ? EDIT_MSG : 0; + const char *msg_file = opts->edit ? NULL : git_path_merge_msg(); unsigned char head[20]; struct commit *base, *next, *parent; const char *base_label, *next_label; struct commit_message msg = { NULL, NULL, NULL, NULL }; struct strbuf msgbuf = STRBUF_INIT; - int res, unborn = 0, amend = 0, allow = 0; + int res, unborn = 0, allow; if (opts->no_commit) { /* @@ -991,7 +997,9 @@ static int do_pick_commit(enum todo_command command, struct commit *commit, opts); if (res || command != TODO_REWORD) goto leave; - edit = amend = 1; + flags |= EDIT_MSG | AMEND_MSG; + if (command == TODO_REWORD) + flags |= VERIFY_MSG; msg_file = NULL; goto fast_forward_edit; } @@ -1046,15 +1054,15 @@ static int do_pick_commit(enum todo_command command, struct commit *commit, } if (command == TODO_REWORD) - edit = 1; + flags |= EDIT_MSG | VERIFY_MSG; else if (is_fixup(command)) { if (update_squash_messages(command, commit, opts)) return -1; - amend = 1; + flags |= AMEND_MSG; if (!final_fixup) msg_file = rebase_path_squash_msg(); else if (file_exists(rebase_path_fixup_msg())) { - cleanup_commit_message = 1; + flags |= CLEANUP_MSG; msg_file = rebase_path_fixup_msg(); } else { const char *dest = git_path("SQUASH_MSG"); @@ -1064,7 +1072,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit, rebase_path_squash_msg(), dest); unlink(git_path("MERGE_MSG")); msg_file = dest; - edit = 1; + flags |= EDIT_MSG; } } @@ -1123,11 +1131,11 @@ static int do_pick_commit(enum todo_command command, struct commit *commit, if (allow < 0) { res = allow; goto leave; - } + } else if (allow) + flags |= ALLOW_EMPTY; if (!opts->no_commit) fast_forward_edit: - res = run_git_commit(msg_file, opts, allow, edit, amend, - cleanup_commit_message); + res = run_git_commit(msg_file, opts, flags); if (!res && final_fixup) { unlink(rebase_path_fixup_msg()); @@ -1997,7 +2005,8 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts) if (item->command == TODO_EDIT) { struct commit *commit = item->commit; if (!res) - warning(_("stopped at %s... %.*s"), + fprintf(stderr, + _("Stopped at %s... %.*s\n"), short_commit_name(commit), item->arg_len, item->arg); return error_with_patch(commit, @@ -2153,7 +2162,7 @@ static int continue_single_pick(void) static int commit_staged_changes(struct replay_opts *opts) { - int amend = 0; + unsigned int flags = ALLOW_EMPTY | EDIT_MSG; if (has_unstaged_changes(1)) return error(_("cannot rebase: You have unstaged changes.")); @@ -2183,10 +2192,10 @@ static int commit_staged_changes(struct replay_opts *opts) "--continue' again.")); strbuf_release(&rev); - amend = 1; + flags |= AMEND_MSG; } - if (run_git_commit(rebase_path_message(), opts, 1, 1, amend, 0)) + if (run_git_commit(rebase_path_message(), opts, flags)) return error(_("could not commit staged changes.")); unlink(rebase_path_amend()); return 0; @@ -135,6 +135,7 @@ int path_inside_repo(const char *prefix, const char *path) int check_filename(const char *prefix, const char *arg) { const char *name; + char *to_free = NULL; struct stat st; if (starts_with(arg, ":/")) { @@ -142,13 +143,17 @@ int check_filename(const char *prefix, const char *arg) return 1; name = arg + 2; } else if (prefix) - name = prefix_filename(prefix, strlen(prefix), arg); + name = to_free = prefix_filename(prefix, arg); else name = arg; - if (!lstat(name, &st)) + if (!lstat(name, &st)) { + free(to_free); return 1; /* file exists */ - if (errno == ENOENT || errno == ENOTDIR) + } + if (errno == ENOENT || errno == ENOTDIR) { + free(to_free); return 0; /* file does not exist */ + } die_errno("failed to stat '%s'", arg); } @@ -982,7 +987,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; + const char *prefix, *env_prefix; /* * We may have read an incomplete configuration before @@ -1040,6 +1045,10 @@ const char *setup_git_directory_gently(int *nongit_ok) die("BUG: unhandled setup_git_directory_1() result"); } + 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-array.c b/sha1-array.c index c1cc25cd95..7d646ab5b8 100644 --- a/sha1-array.c +++ b/sha1-array.c @@ -2,60 +2,60 @@ #include "sha1-array.h" #include "sha1-lookup.h" -void sha1_array_append(struct sha1_array *array, const unsigned char *sha1) +void oid_array_append(struct oid_array *array, const struct object_id *oid) { - ALLOC_GROW(array->sha1, array->nr + 1, array->alloc); - hashcpy(array->sha1[array->nr++], sha1); + ALLOC_GROW(array->oid, array->nr + 1, array->alloc); + oidcpy(&array->oid[array->nr++], oid); array->sorted = 0; } static int void_hashcmp(const void *a, const void *b) { - return hashcmp(a, b); + return oidcmp(a, b); } -static void sha1_array_sort(struct sha1_array *array) +static void oid_array_sort(struct oid_array *array) { - QSORT(array->sha1, array->nr, void_hashcmp); + QSORT(array->oid, array->nr, void_hashcmp); array->sorted = 1; } static const unsigned char *sha1_access(size_t index, void *table) { - unsigned char (*array)[20] = table; - return array[index]; + struct object_id *array = table; + return array[index].hash; } -int sha1_array_lookup(struct sha1_array *array, const unsigned char *sha1) +int oid_array_lookup(struct oid_array *array, const struct object_id *oid) { if (!array->sorted) - sha1_array_sort(array); - return sha1_pos(sha1, array->sha1, array->nr, sha1_access); + oid_array_sort(array); + return sha1_pos(oid->hash, array->oid, array->nr, sha1_access); } -void sha1_array_clear(struct sha1_array *array) +void oid_array_clear(struct oid_array *array) { - free(array->sha1); - array->sha1 = NULL; + free(array->oid); + array->oid = NULL; array->nr = 0; array->alloc = 0; array->sorted = 0; } -int sha1_array_for_each_unique(struct sha1_array *array, - for_each_sha1_fn fn, +int oid_array_for_each_unique(struct oid_array *array, + for_each_oid_fn fn, void *data) { int i; if (!array->sorted) - sha1_array_sort(array); + oid_array_sort(array); for (i = 0; i < array->nr; i++) { int ret; - if (i > 0 && !hashcmp(array->sha1[i], array->sha1[i-1])) + if (i > 0 && !oidcmp(array->oid + i, array->oid + i - 1)) continue; - ret = fn(array->sha1[i], data); + ret = fn(array->oid + i, data); if (ret) return ret; } diff --git a/sha1-array.h b/sha1-array.h index b3230be0dd..04b0756334 100644 --- a/sha1-array.h +++ b/sha1-array.h @@ -1,23 +1,23 @@ #ifndef SHA1_ARRAY_H #define SHA1_ARRAY_H -struct sha1_array { - unsigned char (*sha1)[20]; +struct oid_array { + struct object_id *oid; int nr; int alloc; int sorted; }; -#define SHA1_ARRAY_INIT { NULL, 0, 0, 0 } +#define OID_ARRAY_INIT { NULL, 0, 0, 0 } -void sha1_array_append(struct sha1_array *array, const unsigned char *sha1); -int sha1_array_lookup(struct sha1_array *array, const unsigned char *sha1); -void sha1_array_clear(struct sha1_array *array); +void oid_array_append(struct oid_array *array, const struct object_id *oid); +int oid_array_lookup(struct oid_array *array, const struct object_id *oid); +void oid_array_clear(struct oid_array *array); -typedef int (*for_each_sha1_fn)(const unsigned char sha1[20], - void *data); -int sha1_array_for_each_unique(struct sha1_array *array, - for_each_sha1_fn fn, +typedef int (*for_each_oid_fn)(const struct object_id *oid, + void *data); +int oid_array_for_each_unique(struct oid_array *array, + for_each_oid_fn fn, void *data); #endif /* SHA1_ARRAY_H */ diff --git a/sha1_file.c b/sha1_file.c index 29bbc5f427..2270f36a2b 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -277,31 +277,26 @@ static const char *alt_sha1_path(struct alternate_object_database *alt, return buf->buf; } -/* - * Return the name of the pack or index file with the specified sha1 - * in its filename. *base and *name are scratch space that must be - * provided by the caller. which should be "pack" or "idx". - */ -static char *sha1_get_pack_name(const unsigned char *sha1, - struct strbuf *buf, - const char *which) + char *odb_pack_name(struct strbuf *buf, + const unsigned char *sha1, + const char *ext) { strbuf_reset(buf); strbuf_addf(buf, "%s/pack/pack-%s.%s", get_object_directory(), - sha1_to_hex(sha1), which); + sha1_to_hex(sha1), ext); return buf->buf; } char *sha1_pack_name(const unsigned char *sha1) { static struct strbuf buf = STRBUF_INIT; - return sha1_get_pack_name(sha1, &buf, "pack"); + return odb_pack_name(&buf, sha1, "pack"); } char *sha1_pack_index_name(const unsigned char *sha1) { static struct strbuf buf = STRBUF_INIT; - return sha1_get_pack_name(sha1, &buf, "idx"); + return odb_pack_name(&buf, sha1, "idx"); } struct alternate_object_database *alt_odb_list; @@ -1611,7 +1606,7 @@ static void mark_bad_packed_object(struct packed_git *p, if (!hashcmp(sha1, p->bad_object_sha1 + GIT_SHA1_RAWSZ * i)) return; p->bad_object_sha1 = xrealloc(p->bad_object_sha1, - st_mult(GIT_SHA1_RAWSZ, + st_mult(GIT_MAX_RAWSZ, st_add(p->num_bad_objects, 1))); hashcpy(p->bad_object_sha1 + GIT_SHA1_RAWSZ * p->num_bad_objects, sha1); p->num_bad_objects++; @@ -2957,7 +2952,7 @@ static int sha1_loose_object_info(const unsigned char *sha1, if (status && oi->typep) *oi->typep = status; strbuf_release(&hdrbuf); - return 0; + return (status < 0) ? status : 0; } int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi, unsigned flags) @@ -3764,11 +3759,11 @@ static int for_each_file_in_obj_subdir(int subdir_nr, strbuf_addf(path, "/%s", de->d_name); if (strlen(de->d_name) == GIT_SHA1_HEXSZ - 2) { - char hex[GIT_SHA1_HEXSZ+1]; + char hex[GIT_MAX_HEXSZ+1]; struct object_id oid; - snprintf(hex, sizeof(hex), "%02x%s", - subdir_nr, de->d_name); + xsnprintf(hex, sizeof(hex), "%02x%s", + subdir_nr, de->d_name); if (!get_oid_hex(hex, &oid)) { if (obj_cb) { r = obj_cb(&oid, path->buf, data); @@ -3918,7 +3913,7 @@ static int check_stream_sha1(git_zstream *stream, const unsigned char *expected_sha1) { git_SHA_CTX c; - unsigned char real_sha1[GIT_SHA1_RAWSZ]; + unsigned char real_sha1[GIT_MAX_RAWSZ]; unsigned char buf[4096]; unsigned long total_read; int status = Z_OK; diff --git a/sha1_name.c b/sha1_name.c index cda9e49b12..8eec9f7c1b 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -11,16 +11,16 @@ static int get_sha1_oneline(const char *, unsigned char *, struct commit_list *); -typedef int (*disambiguate_hint_fn)(const unsigned char *, void *); +typedef int (*disambiguate_hint_fn)(const struct object_id *, void *); struct disambiguate_state { int len; /* length of prefix in hex chars */ - char hex_pfx[GIT_SHA1_HEXSZ + 1]; - unsigned char bin_pfx[GIT_SHA1_RAWSZ]; + char hex_pfx[GIT_MAX_HEXSZ + 1]; + struct object_id bin_pfx; disambiguate_hint_fn fn; void *cb_data; - unsigned char candidate[GIT_SHA1_RAWSZ]; + struct object_id candidate; unsigned candidate_exists:1; unsigned candidate_checked:1; unsigned candidate_ok:1; @@ -29,7 +29,7 @@ struct disambiguate_state { unsigned always_call_fn:1; }; -static void update_candidates(struct disambiguate_state *ds, const unsigned char *current) +static void update_candidates(struct disambiguate_state *ds, const struct object_id *current) { if (ds->always_call_fn) { ds->ambiguous = ds->fn(current, ds->cb_data) ? 1 : 0; @@ -37,10 +37,10 @@ static void update_candidates(struct disambiguate_state *ds, const unsigned char } if (!ds->candidate_exists) { /* this is the first candidate */ - hashcpy(ds->candidate, current); + oidcpy(&ds->candidate, current); ds->candidate_exists = 1; return; - } else if (!hashcmp(ds->candidate, current)) { + } else if (!oidcmp(&ds->candidate, current)) { /* the same as what we already have seen */ return; } @@ -52,14 +52,14 @@ static void update_candidates(struct disambiguate_state *ds, const unsigned char } if (!ds->candidate_checked) { - ds->candidate_ok = ds->fn(ds->candidate, ds->cb_data); + ds->candidate_ok = ds->fn(&ds->candidate, ds->cb_data); ds->disambiguate_fn_used = 1; ds->candidate_checked = 1; } if (!ds->candidate_ok) { /* discard the candidate; we know it does not satisfy fn */ - hashcpy(ds->candidate, current); + oidcpy(&ds->candidate, current); ds->candidate_checked = 0; return; } @@ -80,7 +80,7 @@ static void update_candidates(struct disambiguate_state *ds, const unsigned char static void find_short_object_filename(struct disambiguate_state *ds) { struct alternate_object_database *alt; - char hex[GIT_SHA1_HEXSZ]; + char hex[GIT_MAX_HEXSZ]; static struct alternate_object_database *fakeent; if (!fakeent) { @@ -107,15 +107,15 @@ static void find_short_object_filename(struct disambiguate_state *ds) continue; while (!ds->ambiguous && (de = readdir(dir)) != NULL) { - unsigned char sha1[20]; + struct object_id oid; - if (strlen(de->d_name) != 38) + if (strlen(de->d_name) != GIT_SHA1_HEXSZ - 2) continue; if (memcmp(de->d_name, ds->hex_pfx + 2, ds->len - 2)) continue; - memcpy(hex + 2, de->d_name, 38); - if (!get_sha1_hex(hex, sha1)) - update_candidates(ds, sha1); + memcpy(hex + 2, de->d_name, GIT_SHA1_HEXSZ - 2); + if (!get_oid_hex(hex, &oid)) + update_candidates(ds, &oid); } closedir(dir); } @@ -140,7 +140,7 @@ static void unique_in_pack(struct packed_git *p, struct disambiguate_state *ds) { uint32_t num, last, i, first = 0; - const unsigned char *current = NULL; + const struct object_id *current = NULL; open_pack_index(p); num = p->num_objects; @@ -151,7 +151,7 @@ static void unique_in_pack(struct packed_git *p, int cmp; current = nth_packed_object_sha1(p, mid); - cmp = hashcmp(ds->bin_pfx, current); + cmp = hashcmp(ds->bin_pfx.hash, current); if (!cmp) { first = mid; break; @@ -169,8 +169,9 @@ static void unique_in_pack(struct packed_git *p, * 0, 1 or more objects that actually match(es). */ for (i = first; i < num && !ds->ambiguous; i++) { - current = nth_packed_object_sha1(p, i); - if (!match_sha(ds->len, ds->bin_pfx, current)) + struct object_id oid; + current = nth_packed_object_oid(&oid, p, i); + if (!match_sha(ds->len, ds->bin_pfx.hash, current->hash)) break; update_candidates(ds, current); } @@ -213,66 +214,66 @@ static int finish_object_disambiguation(struct disambiguate_state *ds, * same repository! */ ds->candidate_ok = (!ds->disambiguate_fn_used || - ds->fn(ds->candidate, ds->cb_data)); + ds->fn(&ds->candidate, ds->cb_data)); if (!ds->candidate_ok) return SHORT_NAME_AMBIGUOUS; - hashcpy(sha1, ds->candidate); + hashcpy(sha1, ds->candidate.hash); return 0; } -static int disambiguate_commit_only(const unsigned char *sha1, void *cb_data_unused) +static int disambiguate_commit_only(const struct object_id *oid, void *cb_data_unused) { - int kind = sha1_object_info(sha1, NULL); + int kind = sha1_object_info(oid->hash, NULL); return kind == OBJ_COMMIT; } -static int disambiguate_committish_only(const unsigned char *sha1, void *cb_data_unused) +static int disambiguate_committish_only(const struct object_id *oid, void *cb_data_unused) { struct object *obj; int kind; - kind = sha1_object_info(sha1, NULL); + kind = sha1_object_info(oid->hash, NULL); if (kind == OBJ_COMMIT) return 1; if (kind != OBJ_TAG) return 0; /* We need to do this the hard way... */ - obj = deref_tag(parse_object(sha1), NULL, 0); + obj = deref_tag(parse_object(oid->hash), NULL, 0); if (obj && obj->type == OBJ_COMMIT) return 1; return 0; } -static int disambiguate_tree_only(const unsigned char *sha1, void *cb_data_unused) +static int disambiguate_tree_only(const struct object_id *oid, void *cb_data_unused) { - int kind = sha1_object_info(sha1, NULL); + int kind = sha1_object_info(oid->hash, NULL); return kind == OBJ_TREE; } -static int disambiguate_treeish_only(const unsigned char *sha1, void *cb_data_unused) +static int disambiguate_treeish_only(const struct object_id *oid, void *cb_data_unused) { struct object *obj; int kind; - kind = sha1_object_info(sha1, NULL); + kind = sha1_object_info(oid->hash, NULL); if (kind == OBJ_TREE || kind == OBJ_COMMIT) return 1; if (kind != OBJ_TAG) return 0; /* We need to do this the hard way... */ - obj = deref_tag(parse_object(sha1), NULL, 0); + obj = deref_tag(parse_object(oid->hash), NULL, 0); if (obj && (obj->type == OBJ_TREE || obj->type == OBJ_COMMIT)) return 1; return 0; } -static int disambiguate_blob_only(const unsigned char *sha1, void *cb_data_unused) +static int disambiguate_blob_only(const struct object_id *oid, void *cb_data_unused) { - int kind = sha1_object_info(sha1, NULL); + int kind = sha1_object_info(oid->hash, NULL); return kind == OBJ_BLOB; } @@ -332,7 +333,7 @@ static int init_object_disambiguation(const char *name, int len, ds->hex_pfx[i] = c; if (!(i & 1)) val <<= 4; - ds->bin_pfx[i >> 1] |= val; + ds->bin_pfx.hash[i >> 1] |= val; } ds->len = len; @@ -341,31 +342,32 @@ static int init_object_disambiguation(const char *name, int len, return 0; } -static int show_ambiguous_object(const unsigned char *sha1, void *data) +static int show_ambiguous_object(const struct object_id *oid, void *data) { const struct disambiguate_state *ds = data; struct strbuf desc = STRBUF_INIT; int type; - if (ds->fn && !ds->fn(sha1, ds->cb_data)) + + if (ds->fn && !ds->fn(oid, ds->cb_data)) return 0; - type = sha1_object_info(sha1, NULL); + type = sha1_object_info(oid->hash, NULL); if (type == OBJ_COMMIT) { - struct commit *commit = lookup_commit(sha1); + struct commit *commit = lookup_commit(oid->hash); if (commit) { struct pretty_print_context pp = {0}; pp.date_mode.type = DATE_SHORT; format_commit_message(commit, " %ad - %s", &desc, &pp); } } else if (type == OBJ_TAG) { - struct tag *tag = lookup_tag(sha1); + struct tag *tag = lookup_tag(oid->hash); if (!parse_tag(tag) && tag->tag) strbuf_addf(&desc, " %s", tag->tag); } advise(" %s %s%s", - find_unique_abbrev(sha1, DEFAULT_ABBREV), + find_unique_abbrev(oid->hash, DEFAULT_ABBREV), typename(type) ? typename(type) : "unknown type", desc.buf); @@ -422,15 +424,15 @@ static int get_short_sha1(const char *name, int len, unsigned char *sha1, return status; } -static int collect_ambiguous(const unsigned char *sha1, void *data) +static int collect_ambiguous(const struct object_id *oid, void *data) { - sha1_array_append(data, sha1); + oid_array_append(data, oid); return 0; } int for_each_abbrev(const char *prefix, each_abbrev_fn fn, void *cb_data) { - struct sha1_array collect = SHA1_ARRAY_INIT; + struct oid_array collect = OID_ARRAY_INIT; struct disambiguate_state ds; int ret; @@ -443,8 +445,8 @@ int for_each_abbrev(const char *prefix, each_abbrev_fn fn, void *cb_data) find_short_object_filename(&ds); find_short_packed_object(&ds); - ret = sha1_array_for_each_unique(&collect, fn, cb_data); - sha1_array_clear(&collect); + ret = oid_array_for_each_unique(&collect, fn, cb_data); + oid_array_clear(&collect); return ret; } @@ -509,7 +511,7 @@ int find_unique_abbrev_r(char *hex, const unsigned char *sha1, int len) const char *find_unique_abbrev(const unsigned char *sha1, int len) { static int bufno; - static char hexbuffer[4][GIT_SHA1_HEXSZ + 1]; + static char hexbuffer[4][GIT_MAX_HEXSZ + 1]; char *hex = hexbuffer[bufno]; bufno = (bufno + 1) % ARRAY_SIZE(hexbuffer); find_unique_abbrev_r(hex, sha1, len); @@ -549,7 +551,7 @@ static inline int at_mark(const char *string, int len, for (i = 0; i < nr; i++) { int suffix_len = strlen(suffix[i]); if (suffix_len <= len - && !memcmp(string, suffix[i], suffix_len)) + && !strncasecmp(string, suffix[i], suffix_len)) return suffix_len; } return 0; diff --git a/sha1dc/LICENSE.txt b/sha1dc/LICENSE.txt new file mode 100644 index 0000000000..4a3e6a1b15 --- /dev/null +++ b/sha1dc/LICENSE.txt @@ -0,0 +1,30 @@ +MIT License + +Copyright (c) 2017: + Marc Stevens + Cryptology Group + Centrum Wiskunde & Informatica + P.O. Box 94079, 1090 GB Amsterdam, Netherlands + marc@marc-stevens.nl + + Dan Shumow + Microsoft Research + danshu@microsoft.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/sha1dc/sha1.c b/sha1dc/sha1.c new file mode 100644 index 0000000000..35e9dd5bf4 --- /dev/null +++ b/sha1dc/sha1.c @@ -0,0 +1,1809 @@ +/*** +* Copyright 2017 Marc Stevens <marc@marc-stevens.nl>, Dan Shumow (danshu@microsoft.com) +* Distributed under the MIT Software License. +* See accompanying file LICENSE.txt or copy at +* https://opensource.org/licenses/MIT +***/ + +#include "cache.h" +#include "sha1dc/sha1.h" +#include "sha1dc/ubc_check.h" + + +/* + Because Little-Endian architectures are most common, + we only set SHA1DC_BIGENDIAN if one of these conditions is met. + Note that all MSFT platforms are little endian, + so none of these will be defined under the MSC compiler. + If you are compiling on a big endian platform and your compiler does not define one of these, + you will have to add whatever macros your tool chain defines to indicate Big-Endianness. + */ +#if (defined(__BYTE_ORDER) && (__BYTE_ORDER == __BIG_ENDIAN)) || \ + (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __BIG_ENDIAN__)) || \ + defined(__BIG_ENDIAN__) || defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) || \ + defined(_MIPSEB) || defined(__MIPSEB) || defined(__MIPSEB__) + +#define SHA1DC_BIGENDIAN 1 +#else +#undef SHA1DC_BIGENDIAN +#endif /*ENDIANNESS SELECTION*/ + +#define rotate_right(x,n) (((x)>>(n))|((x)<<(32-(n)))) +#define rotate_left(x,n) (((x)<<(n))|((x)>>(32-(n)))) + +#define sha1_bswap32(x) \ + {x = ((x << 8) & 0xFF00FF00) | ((x >> 8) & 0xFF00FF); x = (x << 16) | (x >> 16);} + +#define sha1_mix(W, t) (rotate_left(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1)) + +#if defined(SHA1DC_BIGENDIAN) + #define sha1_load(m, t, temp) { temp = m[t]; } +#else + #define sha1_load(m, t, temp) { temp = m[t]; sha1_bswap32(temp); } +#endif /* !defined(SHA1DC_BIGENDIAN) */ + +#define sha1_store(W, t, x) *(volatile uint32_t *)&W[t] = x + +#define sha1_f1(b,c,d) ((d)^((b)&((c)^(d)))) +#define sha1_f2(b,c,d) ((b)^(c)^(d)) +#define sha1_f3(b,c,d) (((b)&(c))+((d)&((b)^(c)))) +#define sha1_f4(b,c,d) ((b)^(c)^(d)) + +#define HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, m, t) \ + { e += rotate_left(a, 5) + sha1_f1(b,c,d) + 0x5A827999 + m[t]; b = rotate_left(b, 30); } +#define HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, m, t) \ + { e += rotate_left(a, 5) + sha1_f2(b,c,d) + 0x6ED9EBA1 + m[t]; b = rotate_left(b, 30); } +#define HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, m, t) \ + { e += rotate_left(a, 5) + sha1_f3(b,c,d) + 0x8F1BBCDC + m[t]; b = rotate_left(b, 30); } +#define HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, m, t) \ + { e += rotate_left(a, 5) + sha1_f4(b,c,d) + 0xCA62C1D6 + m[t]; b = rotate_left(b, 30); } + +#define HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(a, b, c, d, e, m, t) \ + { b = rotate_right(b, 30); e -= rotate_left(a, 5) + sha1_f1(b,c,d) + 0x5A827999 + m[t]; } +#define HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(a, b, c, d, e, m, t) \ + { b = rotate_right(b, 30); e -= rotate_left(a, 5) + sha1_f2(b,c,d) + 0x6ED9EBA1 + m[t]; } +#define HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(a, b, c, d, e, m, t) \ + { b = rotate_right(b, 30); e -= rotate_left(a, 5) + sha1_f3(b,c,d) + 0x8F1BBCDC + m[t]; } +#define HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(a, b, c, d, e, m, t) \ + { b = rotate_right(b, 30); e -= rotate_left(a, 5) + sha1_f4(b,c,d) + 0xCA62C1D6 + m[t]; } + +#define SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(a, b, c, d, e, m, W, t, temp) \ + {sha1_load(m, t, temp); sha1_store(W, t, temp); e += temp + rotate_left(a, 5) + sha1_f1(b,c,d) + 0x5A827999; b = rotate_left(b, 30);} + +#define SHA1COMPRESS_FULL_ROUND1_STEP_EXPAND(a, b, c, d, e, W, t, temp) \ + {temp = sha1_mix(W, t); sha1_store(W, t, temp); e += temp + rotate_left(a, 5) + sha1_f1(b,c,d) + 0x5A827999; b = rotate_left(b, 30); } + +#define SHA1COMPRESS_FULL_ROUND2_STEP(a, b, c, d, e, W, t, temp) \ + {temp = sha1_mix(W, t); sha1_store(W, t, temp); e += temp + rotate_left(a, 5) + sha1_f2(b,c,d) + 0x6ED9EBA1; b = rotate_left(b, 30); } + +#define SHA1COMPRESS_FULL_ROUND3_STEP(a, b, c, d, e, W, t, temp) \ + {temp = sha1_mix(W, t); sha1_store(W, t, temp); e += temp + rotate_left(a, 5) + sha1_f3(b,c,d) + 0x8F1BBCDC; b = rotate_left(b, 30); } + +#define SHA1COMPRESS_FULL_ROUND4_STEP(a, b, c, d, e, W, t, temp) \ + {temp = sha1_mix(W, t); sha1_store(W, t, temp); e += temp + rotate_left(a, 5) + sha1_f4(b,c,d) + 0xCA62C1D6; b = rotate_left(b, 30); } + + +#define SHA1_STORE_STATE(i) states[i][0] = a; states[i][1] = b; states[i][2] = c; states[i][3] = d; states[i][4] = e; + +#ifdef BUILDNOCOLLDETECTSHA1COMPRESSION +void sha1_compression(uint32_t ihv[5], const uint32_t m[16]) +{ + uint32_t W[80]; + uint32_t a,b,c,d,e; + unsigned i; + + memcpy(W, m, 16 * 4); + for (i = 16; i < 80; ++i) + W[i] = sha1_mix(W, i); + + a = ihv[0]; b = ihv[1]; c = ihv[2]; d = ihv[3]; e = ihv[4]; + + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 0); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 1); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 2); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 3); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 4); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 5); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 6); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 7); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 8); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 9); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 10); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 11); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 12); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 13); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 14); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 15); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 16); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 17); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 18); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 19); + + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 20); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 21); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 22); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 23); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 24); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 25); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 26); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 27); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 28); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 29); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 30); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 31); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 32); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 33); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 34); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 35); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 36); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 37); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 38); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 39); + + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 40); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 41); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 42); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 43); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 44); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 45); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 46); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 47); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 48); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 49); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 50); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 51); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 52); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 53); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 54); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 55); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 56); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 57); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 58); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 59); + + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 60); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 61); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 62); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 63); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 64); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 65); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 66); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 67); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 68); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 69); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 70); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 71); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 72); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 73); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 74); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 75); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 76); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 77); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 78); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 79); + + ihv[0] += a; ihv[1] += b; ihv[2] += c; ihv[3] += d; ihv[4] += e; +} +#endif /*BUILDNOCOLLDETECTSHA1COMPRESSION*/ + + +static void sha1_compression_W(uint32_t ihv[5], const uint32_t W[80]) +{ + uint32_t a = ihv[0], b = ihv[1], c = ihv[2], d = ihv[3], e = ihv[4]; + + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 0); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 1); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 2); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 3); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 4); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 5); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 6); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 7); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 8); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 9); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 10); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 11); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 12); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 13); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 14); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 15); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 16); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 17); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 18); + HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 19); + + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 20); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 21); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 22); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 23); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 24); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 25); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 26); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 27); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 28); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 29); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 30); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 31); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 32); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 33); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 34); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 35); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 36); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 37); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 38); + HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 39); + + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 40); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 41); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 42); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 43); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 44); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 45); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 46); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 47); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 48); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 49); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 50); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 51); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 52); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 53); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 54); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 55); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 56); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 57); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 58); + HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 59); + + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 60); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 61); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 62); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 63); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 64); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 65); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 66); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 67); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 68); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 69); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 70); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 71); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 72); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 73); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 74); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 75); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 76); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 77); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 78); + HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 79); + + ihv[0] += a; ihv[1] += b; ihv[2] += c; ihv[3] += d; ihv[4] += e; +} + + + +void sha1_compression_states(uint32_t ihv[5], const uint32_t m[16], uint32_t W[80], uint32_t states[80][5]) +{ + uint32_t a = ihv[0], b = ihv[1], c = ihv[2], d = ihv[3], e = ihv[4]; + uint32_t temp; + +#ifdef DOSTORESTATE00 + SHA1_STORE_STATE(0) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(a, b, c, d, e, m, W, 0, temp); + +#ifdef DOSTORESTATE01 + SHA1_STORE_STATE(1) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(e, a, b, c, d, m, W, 1, temp); + +#ifdef DOSTORESTATE02 + SHA1_STORE_STATE(2) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(d, e, a, b, c, m, W, 2, temp); + +#ifdef DOSTORESTATE03 + SHA1_STORE_STATE(3) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(c, d, e, a, b, m, W, 3, temp); + +#ifdef DOSTORESTATE04 + SHA1_STORE_STATE(4) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(b, c, d, e, a, m, W, 4, temp); + +#ifdef DOSTORESTATE05 + SHA1_STORE_STATE(5) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(a, b, c, d, e, m, W, 5, temp); + +#ifdef DOSTORESTATE06 + SHA1_STORE_STATE(6) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(e, a, b, c, d, m, W, 6, temp); + +#ifdef DOSTORESTATE07 + SHA1_STORE_STATE(7) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(d, e, a, b, c, m, W, 7, temp); + +#ifdef DOSTORESTATE08 + SHA1_STORE_STATE(8) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(c, d, e, a, b, m, W, 8, temp); + +#ifdef DOSTORESTATE09 + SHA1_STORE_STATE(9) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(b, c, d, e, a, m, W, 9, temp); + +#ifdef DOSTORESTATE10 + SHA1_STORE_STATE(10) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(a, b, c, d, e, m, W, 10, temp); + +#ifdef DOSTORESTATE11 + SHA1_STORE_STATE(11) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(e, a, b, c, d, m, W, 11, temp); + +#ifdef DOSTORESTATE12 + SHA1_STORE_STATE(12) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(d, e, a, b, c, m, W, 12, temp); + +#ifdef DOSTORESTATE13 + SHA1_STORE_STATE(13) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(c, d, e, a, b, m, W, 13, temp); + +#ifdef DOSTORESTATE14 + SHA1_STORE_STATE(14) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(b, c, d, e, a, m, W, 14, temp); + +#ifdef DOSTORESTATE15 + SHA1_STORE_STATE(15) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(a, b, c, d, e, m, W, 15, temp); + +#ifdef DOSTORESTATE16 + SHA1_STORE_STATE(16) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_EXPAND(e, a, b, c, d, W, 16, temp); + +#ifdef DOSTORESTATE17 + SHA1_STORE_STATE(17) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_EXPAND(d, e, a, b, c, W, 17, temp); + +#ifdef DOSTORESTATE18 + SHA1_STORE_STATE(18) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_EXPAND(c, d, e, a, b, W, 18, temp); + +#ifdef DOSTORESTATE19 + SHA1_STORE_STATE(19) +#endif + SHA1COMPRESS_FULL_ROUND1_STEP_EXPAND(b, c, d, e, a, W, 19, temp); + + + +#ifdef DOSTORESTATE20 + SHA1_STORE_STATE(20) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(a, b, c, d, e, W, 20, temp); + +#ifdef DOSTORESTATE21 + SHA1_STORE_STATE(21) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(e, a, b, c, d, W, 21, temp); + +#ifdef DOSTORESTATE22 + SHA1_STORE_STATE(22) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(d, e, a, b, c, W, 22, temp); + +#ifdef DOSTORESTATE23 + SHA1_STORE_STATE(23) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(c, d, e, a, b, W, 23, temp); + +#ifdef DOSTORESTATE24 + SHA1_STORE_STATE(24) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(b, c, d, e, a, W, 24, temp); + +#ifdef DOSTORESTATE25 + SHA1_STORE_STATE(25) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(a, b, c, d, e, W, 25, temp); + +#ifdef DOSTORESTATE26 + SHA1_STORE_STATE(26) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(e, a, b, c, d, W, 26, temp); + +#ifdef DOSTORESTATE27 + SHA1_STORE_STATE(27) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(d, e, a, b, c, W, 27, temp); + +#ifdef DOSTORESTATE28 + SHA1_STORE_STATE(28) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(c, d, e, a, b, W, 28, temp); + +#ifdef DOSTORESTATE29 + SHA1_STORE_STATE(29) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(b, c, d, e, a, W, 29, temp); + +#ifdef DOSTORESTATE30 + SHA1_STORE_STATE(30) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(a, b, c, d, e, W, 30, temp); + +#ifdef DOSTORESTATE31 + SHA1_STORE_STATE(31) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(e, a, b, c, d, W, 31, temp); + +#ifdef DOSTORESTATE32 + SHA1_STORE_STATE(32) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(d, e, a, b, c, W, 32, temp); + +#ifdef DOSTORESTATE33 + SHA1_STORE_STATE(33) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(c, d, e, a, b, W, 33, temp); + +#ifdef DOSTORESTATE34 + SHA1_STORE_STATE(34) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(b, c, d, e, a, W, 34, temp); + +#ifdef DOSTORESTATE35 + SHA1_STORE_STATE(35) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(a, b, c, d, e, W, 35, temp); + +#ifdef DOSTORESTATE36 + SHA1_STORE_STATE(36) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(e, a, b, c, d, W, 36, temp); + +#ifdef DOSTORESTATE37 + SHA1_STORE_STATE(37) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(d, e, a, b, c, W, 37, temp); + +#ifdef DOSTORESTATE38 + SHA1_STORE_STATE(38) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(c, d, e, a, b, W, 38, temp); + +#ifdef DOSTORESTATE39 + SHA1_STORE_STATE(39) +#endif + SHA1COMPRESS_FULL_ROUND2_STEP(b, c, d, e, a, W, 39, temp); + + + +#ifdef DOSTORESTATE40 + SHA1_STORE_STATE(40) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(a, b, c, d, e, W, 40, temp); + +#ifdef DOSTORESTATE41 + SHA1_STORE_STATE(41) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(e, a, b, c, d, W, 41, temp); + +#ifdef DOSTORESTATE42 + SHA1_STORE_STATE(42) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(d, e, a, b, c, W, 42, temp); + +#ifdef DOSTORESTATE43 + SHA1_STORE_STATE(43) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(c, d, e, a, b, W, 43, temp); + +#ifdef DOSTORESTATE44 + SHA1_STORE_STATE(44) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(b, c, d, e, a, W, 44, temp); + +#ifdef DOSTORESTATE45 + SHA1_STORE_STATE(45) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(a, b, c, d, e, W, 45, temp); + +#ifdef DOSTORESTATE46 + SHA1_STORE_STATE(46) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(e, a, b, c, d, W, 46, temp); + +#ifdef DOSTORESTATE47 + SHA1_STORE_STATE(47) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(d, e, a, b, c, W, 47, temp); + +#ifdef DOSTORESTATE48 + SHA1_STORE_STATE(48) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(c, d, e, a, b, W, 48, temp); + +#ifdef DOSTORESTATE49 + SHA1_STORE_STATE(49) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(b, c, d, e, a, W, 49, temp); + +#ifdef DOSTORESTATE50 + SHA1_STORE_STATE(50) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(a, b, c, d, e, W, 50, temp); + +#ifdef DOSTORESTATE51 + SHA1_STORE_STATE(51) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(e, a, b, c, d, W, 51, temp); + +#ifdef DOSTORESTATE52 + SHA1_STORE_STATE(52) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(d, e, a, b, c, W, 52, temp); + +#ifdef DOSTORESTATE53 + SHA1_STORE_STATE(53) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(c, d, e, a, b, W, 53, temp); + +#ifdef DOSTORESTATE54 + SHA1_STORE_STATE(54) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(b, c, d, e, a, W, 54, temp); + +#ifdef DOSTORESTATE55 + SHA1_STORE_STATE(55) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(a, b, c, d, e, W, 55, temp); + +#ifdef DOSTORESTATE56 + SHA1_STORE_STATE(56) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(e, a, b, c, d, W, 56, temp); + +#ifdef DOSTORESTATE57 + SHA1_STORE_STATE(57) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(d, e, a, b, c, W, 57, temp); + +#ifdef DOSTORESTATE58 + SHA1_STORE_STATE(58) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(c, d, e, a, b, W, 58, temp); + +#ifdef DOSTORESTATE59 + SHA1_STORE_STATE(59) +#endif + SHA1COMPRESS_FULL_ROUND3_STEP(b, c, d, e, a, W, 59, temp); + + + + +#ifdef DOSTORESTATE60 + SHA1_STORE_STATE(60) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(a, b, c, d, e, W, 60, temp); + +#ifdef DOSTORESTATE61 + SHA1_STORE_STATE(61) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(e, a, b, c, d, W, 61, temp); + +#ifdef DOSTORESTATE62 + SHA1_STORE_STATE(62) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(d, e, a, b, c, W, 62, temp); + +#ifdef DOSTORESTATE63 + SHA1_STORE_STATE(63) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(c, d, e, a, b, W, 63, temp); + +#ifdef DOSTORESTATE64 + SHA1_STORE_STATE(64) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(b, c, d, e, a, W, 64, temp); + +#ifdef DOSTORESTATE65 + SHA1_STORE_STATE(65) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(a, b, c, d, e, W, 65, temp); + +#ifdef DOSTORESTATE66 + SHA1_STORE_STATE(66) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(e, a, b, c, d, W, 66, temp); + +#ifdef DOSTORESTATE67 + SHA1_STORE_STATE(67) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(d, e, a, b, c, W, 67, temp); + +#ifdef DOSTORESTATE68 + SHA1_STORE_STATE(68) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(c, d, e, a, b, W, 68, temp); + +#ifdef DOSTORESTATE69 + SHA1_STORE_STATE(69) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(b, c, d, e, a, W, 69, temp); + +#ifdef DOSTORESTATE70 + SHA1_STORE_STATE(70) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(a, b, c, d, e, W, 70, temp); + +#ifdef DOSTORESTATE71 + SHA1_STORE_STATE(71) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(e, a, b, c, d, W, 71, temp); + +#ifdef DOSTORESTATE72 + SHA1_STORE_STATE(72) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(d, e, a, b, c, W, 72, temp); + +#ifdef DOSTORESTATE73 + SHA1_STORE_STATE(73) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(c, d, e, a, b, W, 73, temp); + +#ifdef DOSTORESTATE74 + SHA1_STORE_STATE(74) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(b, c, d, e, a, W, 74, temp); + +#ifdef DOSTORESTATE75 + SHA1_STORE_STATE(75) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(a, b, c, d, e, W, 75, temp); + +#ifdef DOSTORESTATE76 + SHA1_STORE_STATE(76) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(e, a, b, c, d, W, 76, temp); + +#ifdef DOSTORESTATE77 + SHA1_STORE_STATE(77) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(d, e, a, b, c, W, 77, temp); + +#ifdef DOSTORESTATE78 + SHA1_STORE_STATE(78) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(c, d, e, a, b, W, 78, temp); + +#ifdef DOSTORESTATE79 + SHA1_STORE_STATE(79) +#endif + SHA1COMPRESS_FULL_ROUND4_STEP(b, c, d, e, a, W, 79, temp); + + + + ihv[0] += a; ihv[1] += b; ihv[2] += c; ihv[3] += d; ihv[4] += e; +} + + + + +#define SHA1_RECOMPRESS(t) \ +static void sha1recompress_fast_ ## t (uint32_t ihvin[5], uint32_t ihvout[5], const uint32_t me2[80], const uint32_t state[5]) \ +{ \ + uint32_t a = state[0], b = state[1], c = state[2], d = state[3], e = state[4]; \ + if (t > 79) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(b, c, d, e, a, me2, 79); \ + if (t > 78) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(c, d, e, a, b, me2, 78); \ + if (t > 77) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(d, e, a, b, c, me2, 77); \ + if (t > 76) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(e, a, b, c, d, me2, 76); \ + if (t > 75) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(a, b, c, d, e, me2, 75); \ + if (t > 74) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(b, c, d, e, a, me2, 74); \ + if (t > 73) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(c, d, e, a, b, me2, 73); \ + if (t > 72) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(d, e, a, b, c, me2, 72); \ + if (t > 71) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(e, a, b, c, d, me2, 71); \ + if (t > 70) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(a, b, c, d, e, me2, 70); \ + if (t > 69) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(b, c, d, e, a, me2, 69); \ + if (t > 68) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(c, d, e, a, b, me2, 68); \ + if (t > 67) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(d, e, a, b, c, me2, 67); \ + if (t > 66) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(e, a, b, c, d, me2, 66); \ + if (t > 65) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(a, b, c, d, e, me2, 65); \ + if (t > 64) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(b, c, d, e, a, me2, 64); \ + if (t > 63) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(c, d, e, a, b, me2, 63); \ + if (t > 62) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(d, e, a, b, c, me2, 62); \ + if (t > 61) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(e, a, b, c, d, me2, 61); \ + if (t > 60) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(a, b, c, d, e, me2, 60); \ + if (t > 59) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(b, c, d, e, a, me2, 59); \ + if (t > 58) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(c, d, e, a, b, me2, 58); \ + if (t > 57) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(d, e, a, b, c, me2, 57); \ + if (t > 56) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(e, a, b, c, d, me2, 56); \ + if (t > 55) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(a, b, c, d, e, me2, 55); \ + if (t > 54) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(b, c, d, e, a, me2, 54); \ + if (t > 53) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(c, d, e, a, b, me2, 53); \ + if (t > 52) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(d, e, a, b, c, me2, 52); \ + if (t > 51) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(e, a, b, c, d, me2, 51); \ + if (t > 50) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(a, b, c, d, e, me2, 50); \ + if (t > 49) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(b, c, d, e, a, me2, 49); \ + if (t > 48) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(c, d, e, a, b, me2, 48); \ + if (t > 47) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(d, e, a, b, c, me2, 47); \ + if (t > 46) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(e, a, b, c, d, me2, 46); \ + if (t > 45) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(a, b, c, d, e, me2, 45); \ + if (t > 44) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(b, c, d, e, a, me2, 44); \ + if (t > 43) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(c, d, e, a, b, me2, 43); \ + if (t > 42) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(d, e, a, b, c, me2, 42); \ + if (t > 41) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(e, a, b, c, d, me2, 41); \ + if (t > 40) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(a, b, c, d, e, me2, 40); \ + if (t > 39) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(b, c, d, e, a, me2, 39); \ + if (t > 38) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(c, d, e, a, b, me2, 38); \ + if (t > 37) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(d, e, a, b, c, me2, 37); \ + if (t > 36) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(e, a, b, c, d, me2, 36); \ + if (t > 35) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(a, b, c, d, e, me2, 35); \ + if (t > 34) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(b, c, d, e, a, me2, 34); \ + if (t > 33) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(c, d, e, a, b, me2, 33); \ + if (t > 32) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(d, e, a, b, c, me2, 32); \ + if (t > 31) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(e, a, b, c, d, me2, 31); \ + if (t > 30) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(a, b, c, d, e, me2, 30); \ + if (t > 29) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(b, c, d, e, a, me2, 29); \ + if (t > 28) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(c, d, e, a, b, me2, 28); \ + if (t > 27) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(d, e, a, b, c, me2, 27); \ + if (t > 26) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(e, a, b, c, d, me2, 26); \ + if (t > 25) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(a, b, c, d, e, me2, 25); \ + if (t > 24) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(b, c, d, e, a, me2, 24); \ + if (t > 23) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(c, d, e, a, b, me2, 23); \ + if (t > 22) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(d, e, a, b, c, me2, 22); \ + if (t > 21) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(e, a, b, c, d, me2, 21); \ + if (t > 20) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(a, b, c, d, e, me2, 20); \ + if (t > 19) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(b, c, d, e, a, me2, 19); \ + if (t > 18) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(c, d, e, a, b, me2, 18); \ + if (t > 17) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(d, e, a, b, c, me2, 17); \ + if (t > 16) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(e, a, b, c, d, me2, 16); \ + if (t > 15) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(a, b, c, d, e, me2, 15); \ + if (t > 14) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(b, c, d, e, a, me2, 14); \ + if (t > 13) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(c, d, e, a, b, me2, 13); \ + if (t > 12) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(d, e, a, b, c, me2, 12); \ + if (t > 11) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(e, a, b, c, d, me2, 11); \ + if (t > 10) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(a, b, c, d, e, me2, 10); \ + if (t > 9) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(b, c, d, e, a, me2, 9); \ + if (t > 8) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(c, d, e, a, b, me2, 8); \ + if (t > 7) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(d, e, a, b, c, me2, 7); \ + if (t > 6) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(e, a, b, c, d, me2, 6); \ + if (t > 5) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(a, b, c, d, e, me2, 5); \ + if (t > 4) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(b, c, d, e, a, me2, 4); \ + if (t > 3) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(c, d, e, a, b, me2, 3); \ + if (t > 2) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(d, e, a, b, c, me2, 2); \ + if (t > 1) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(e, a, b, c, d, me2, 1); \ + if (t > 0) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(a, b, c, d, e, me2, 0); \ + ihvin[0] = a; ihvin[1] = b; ihvin[2] = c; ihvin[3] = d; ihvin[4] = e; \ + a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; \ + if (t <= 0) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, me2, 0); \ + if (t <= 1) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, me2, 1); \ + if (t <= 2) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, me2, 2); \ + if (t <= 3) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, me2, 3); \ + if (t <= 4) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, me2, 4); \ + if (t <= 5) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, me2, 5); \ + if (t <= 6) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, me2, 6); \ + if (t <= 7) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, me2, 7); \ + if (t <= 8) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, me2, 8); \ + if (t <= 9) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, me2, 9); \ + if (t <= 10) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, me2, 10); \ + if (t <= 11) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, me2, 11); \ + if (t <= 12) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, me2, 12); \ + if (t <= 13) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, me2, 13); \ + if (t <= 14) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, me2, 14); \ + if (t <= 15) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, me2, 15); \ + if (t <= 16) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, me2, 16); \ + if (t <= 17) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, me2, 17); \ + if (t <= 18) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, me2, 18); \ + if (t <= 19) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, me2, 19); \ + if (t <= 20) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, me2, 20); \ + if (t <= 21) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, me2, 21); \ + if (t <= 22) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, me2, 22); \ + if (t <= 23) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, me2, 23); \ + if (t <= 24) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, me2, 24); \ + if (t <= 25) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, me2, 25); \ + if (t <= 26) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, me2, 26); \ + if (t <= 27) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, me2, 27); \ + if (t <= 28) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, me2, 28); \ + if (t <= 29) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, me2, 29); \ + if (t <= 30) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, me2, 30); \ + if (t <= 31) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, me2, 31); \ + if (t <= 32) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, me2, 32); \ + if (t <= 33) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, me2, 33); \ + if (t <= 34) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, me2, 34); \ + if (t <= 35) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, me2, 35); \ + if (t <= 36) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, me2, 36); \ + if (t <= 37) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, me2, 37); \ + if (t <= 38) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, me2, 38); \ + if (t <= 39) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, me2, 39); \ + if (t <= 40) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, me2, 40); \ + if (t <= 41) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, me2, 41); \ + if (t <= 42) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, me2, 42); \ + if (t <= 43) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, me2, 43); \ + if (t <= 44) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, me2, 44); \ + if (t <= 45) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, me2, 45); \ + if (t <= 46) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, me2, 46); \ + if (t <= 47) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, me2, 47); \ + if (t <= 48) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, me2, 48); \ + if (t <= 49) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, me2, 49); \ + if (t <= 50) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, me2, 50); \ + if (t <= 51) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, me2, 51); \ + if (t <= 52) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, me2, 52); \ + if (t <= 53) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, me2, 53); \ + if (t <= 54) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, me2, 54); \ + if (t <= 55) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, me2, 55); \ + if (t <= 56) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, me2, 56); \ + if (t <= 57) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, me2, 57); \ + if (t <= 58) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, me2, 58); \ + if (t <= 59) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, me2, 59); \ + if (t <= 60) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, me2, 60); \ + if (t <= 61) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, me2, 61); \ + if (t <= 62) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, me2, 62); \ + if (t <= 63) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, me2, 63); \ + if (t <= 64) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, me2, 64); \ + if (t <= 65) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, me2, 65); \ + if (t <= 66) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, me2, 66); \ + if (t <= 67) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, me2, 67); \ + if (t <= 68) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, me2, 68); \ + if (t <= 69) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, me2, 69); \ + if (t <= 70) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, me2, 70); \ + if (t <= 71) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, me2, 71); \ + if (t <= 72) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, me2, 72); \ + if (t <= 73) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, me2, 73); \ + if (t <= 74) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, me2, 74); \ + if (t <= 75) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, me2, 75); \ + if (t <= 76) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, me2, 76); \ + if (t <= 77) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, me2, 77); \ + if (t <= 78) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, me2, 78); \ + if (t <= 79) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, me2, 79); \ + ihvout[0] = ihvin[0] + a; ihvout[1] = ihvin[1] + b; ihvout[2] = ihvin[2] + c; ihvout[3] = ihvin[3] + d; ihvout[4] = ihvin[4] + e; \ +} + +#ifdef DOSTORESTATE0 +SHA1_RECOMPRESS(0) +#endif + +#ifdef DOSTORESTATE1 +SHA1_RECOMPRESS(1) +#endif + +#ifdef DOSTORESTATE2 +SHA1_RECOMPRESS(2) +#endif + +#ifdef DOSTORESTATE3 +SHA1_RECOMPRESS(3) +#endif + +#ifdef DOSTORESTATE4 +SHA1_RECOMPRESS(4) +#endif + +#ifdef DOSTORESTATE5 +SHA1_RECOMPRESS(5) +#endif + +#ifdef DOSTORESTATE6 +SHA1_RECOMPRESS(6) +#endif + +#ifdef DOSTORESTATE7 +SHA1_RECOMPRESS(7) +#endif + +#ifdef DOSTORESTATE8 +SHA1_RECOMPRESS(8) +#endif + +#ifdef DOSTORESTATE9 +SHA1_RECOMPRESS(9) +#endif + +#ifdef DOSTORESTATE10 +SHA1_RECOMPRESS(10) +#endif + +#ifdef DOSTORESTATE11 +SHA1_RECOMPRESS(11) +#endif + +#ifdef DOSTORESTATE12 +SHA1_RECOMPRESS(12) +#endif + +#ifdef DOSTORESTATE13 +SHA1_RECOMPRESS(13) +#endif + +#ifdef DOSTORESTATE14 +SHA1_RECOMPRESS(14) +#endif + +#ifdef DOSTORESTATE15 +SHA1_RECOMPRESS(15) +#endif + +#ifdef DOSTORESTATE16 +SHA1_RECOMPRESS(16) +#endif + +#ifdef DOSTORESTATE17 +SHA1_RECOMPRESS(17) +#endif + +#ifdef DOSTORESTATE18 +SHA1_RECOMPRESS(18) +#endif + +#ifdef DOSTORESTATE19 +SHA1_RECOMPRESS(19) +#endif + +#ifdef DOSTORESTATE20 +SHA1_RECOMPRESS(20) +#endif + +#ifdef DOSTORESTATE21 +SHA1_RECOMPRESS(21) +#endif + +#ifdef DOSTORESTATE22 +SHA1_RECOMPRESS(22) +#endif + +#ifdef DOSTORESTATE23 +SHA1_RECOMPRESS(23) +#endif + +#ifdef DOSTORESTATE24 +SHA1_RECOMPRESS(24) +#endif + +#ifdef DOSTORESTATE25 +SHA1_RECOMPRESS(25) +#endif + +#ifdef DOSTORESTATE26 +SHA1_RECOMPRESS(26) +#endif + +#ifdef DOSTORESTATE27 +SHA1_RECOMPRESS(27) +#endif + +#ifdef DOSTORESTATE28 +SHA1_RECOMPRESS(28) +#endif + +#ifdef DOSTORESTATE29 +SHA1_RECOMPRESS(29) +#endif + +#ifdef DOSTORESTATE30 +SHA1_RECOMPRESS(30) +#endif + +#ifdef DOSTORESTATE31 +SHA1_RECOMPRESS(31) +#endif + +#ifdef DOSTORESTATE32 +SHA1_RECOMPRESS(32) +#endif + +#ifdef DOSTORESTATE33 +SHA1_RECOMPRESS(33) +#endif + +#ifdef DOSTORESTATE34 +SHA1_RECOMPRESS(34) +#endif + +#ifdef DOSTORESTATE35 +SHA1_RECOMPRESS(35) +#endif + +#ifdef DOSTORESTATE36 +SHA1_RECOMPRESS(36) +#endif + +#ifdef DOSTORESTATE37 +SHA1_RECOMPRESS(37) +#endif + +#ifdef DOSTORESTATE38 +SHA1_RECOMPRESS(38) +#endif + +#ifdef DOSTORESTATE39 +SHA1_RECOMPRESS(39) +#endif + +#ifdef DOSTORESTATE40 +SHA1_RECOMPRESS(40) +#endif + +#ifdef DOSTORESTATE41 +SHA1_RECOMPRESS(41) +#endif + +#ifdef DOSTORESTATE42 +SHA1_RECOMPRESS(42) +#endif + +#ifdef DOSTORESTATE43 +SHA1_RECOMPRESS(43) +#endif + +#ifdef DOSTORESTATE44 +SHA1_RECOMPRESS(44) +#endif + +#ifdef DOSTORESTATE45 +SHA1_RECOMPRESS(45) +#endif + +#ifdef DOSTORESTATE46 +SHA1_RECOMPRESS(46) +#endif + +#ifdef DOSTORESTATE47 +SHA1_RECOMPRESS(47) +#endif + +#ifdef DOSTORESTATE48 +SHA1_RECOMPRESS(48) +#endif + +#ifdef DOSTORESTATE49 +SHA1_RECOMPRESS(49) +#endif + +#ifdef DOSTORESTATE50 +SHA1_RECOMPRESS(50) +#endif + +#ifdef DOSTORESTATE51 +SHA1_RECOMPRESS(51) +#endif + +#ifdef DOSTORESTATE52 +SHA1_RECOMPRESS(52) +#endif + +#ifdef DOSTORESTATE53 +SHA1_RECOMPRESS(53) +#endif + +#ifdef DOSTORESTATE54 +SHA1_RECOMPRESS(54) +#endif + +#ifdef DOSTORESTATE55 +SHA1_RECOMPRESS(55) +#endif + +#ifdef DOSTORESTATE56 +SHA1_RECOMPRESS(56) +#endif + +#ifdef DOSTORESTATE57 +SHA1_RECOMPRESS(57) +#endif + +#ifdef DOSTORESTATE58 +SHA1_RECOMPRESS(58) +#endif + +#ifdef DOSTORESTATE59 +SHA1_RECOMPRESS(59) +#endif + +#ifdef DOSTORESTATE60 +SHA1_RECOMPRESS(60) +#endif + +#ifdef DOSTORESTATE61 +SHA1_RECOMPRESS(61) +#endif + +#ifdef DOSTORESTATE62 +SHA1_RECOMPRESS(62) +#endif + +#ifdef DOSTORESTATE63 +SHA1_RECOMPRESS(63) +#endif + +#ifdef DOSTORESTATE64 +SHA1_RECOMPRESS(64) +#endif + +#ifdef DOSTORESTATE65 +SHA1_RECOMPRESS(65) +#endif + +#ifdef DOSTORESTATE66 +SHA1_RECOMPRESS(66) +#endif + +#ifdef DOSTORESTATE67 +SHA1_RECOMPRESS(67) +#endif + +#ifdef DOSTORESTATE68 +SHA1_RECOMPRESS(68) +#endif + +#ifdef DOSTORESTATE69 +SHA1_RECOMPRESS(69) +#endif + +#ifdef DOSTORESTATE70 +SHA1_RECOMPRESS(70) +#endif + +#ifdef DOSTORESTATE71 +SHA1_RECOMPRESS(71) +#endif + +#ifdef DOSTORESTATE72 +SHA1_RECOMPRESS(72) +#endif + +#ifdef DOSTORESTATE73 +SHA1_RECOMPRESS(73) +#endif + +#ifdef DOSTORESTATE74 +SHA1_RECOMPRESS(74) +#endif + +#ifdef DOSTORESTATE75 +SHA1_RECOMPRESS(75) +#endif + +#ifdef DOSTORESTATE76 +SHA1_RECOMPRESS(76) +#endif + +#ifdef DOSTORESTATE77 +SHA1_RECOMPRESS(77) +#endif + +#ifdef DOSTORESTATE78 +SHA1_RECOMPRESS(78) +#endif + +#ifdef DOSTORESTATE79 +SHA1_RECOMPRESS(79) +#endif + +static void sha1_recompression_step(uint32_t step, uint32_t ihvin[5], uint32_t ihvout[5], const uint32_t me2[80], const uint32_t state[5]) +{ + switch (step) + { +#ifdef DOSTORESTATE0 + case 0: + sha1recompress_fast_0(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE1 + case 1: + sha1recompress_fast_1(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE2 + case 2: + sha1recompress_fast_2(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE3 + case 3: + sha1recompress_fast_3(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE4 + case 4: + sha1recompress_fast_4(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE5 + case 5: + sha1recompress_fast_5(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE6 + case 6: + sha1recompress_fast_6(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE7 + case 7: + sha1recompress_fast_7(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE8 + case 8: + sha1recompress_fast_8(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE9 + case 9: + sha1recompress_fast_9(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE10 + case 10: + sha1recompress_fast_10(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE11 + case 11: + sha1recompress_fast_11(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE12 + case 12: + sha1recompress_fast_12(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE13 + case 13: + sha1recompress_fast_13(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE14 + case 14: + sha1recompress_fast_14(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE15 + case 15: + sha1recompress_fast_15(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE16 + case 16: + sha1recompress_fast_16(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE17 + case 17: + sha1recompress_fast_17(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE18 + case 18: + sha1recompress_fast_18(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE19 + case 19: + sha1recompress_fast_19(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE20 + case 20: + sha1recompress_fast_20(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE21 + case 21: + sha1recompress_fast_21(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE22 + case 22: + sha1recompress_fast_22(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE23 + case 23: + sha1recompress_fast_23(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE24 + case 24: + sha1recompress_fast_24(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE25 + case 25: + sha1recompress_fast_25(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE26 + case 26: + sha1recompress_fast_26(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE27 + case 27: + sha1recompress_fast_27(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE28 + case 28: + sha1recompress_fast_28(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE29 + case 29: + sha1recompress_fast_29(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE30 + case 30: + sha1recompress_fast_30(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE31 + case 31: + sha1recompress_fast_31(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE32 + case 32: + sha1recompress_fast_32(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE33 + case 33: + sha1recompress_fast_33(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE34 + case 34: + sha1recompress_fast_34(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE35 + case 35: + sha1recompress_fast_35(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE36 + case 36: + sha1recompress_fast_36(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE37 + case 37: + sha1recompress_fast_37(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE38 + case 38: + sha1recompress_fast_38(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE39 + case 39: + sha1recompress_fast_39(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE40 + case 40: + sha1recompress_fast_40(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE41 + case 41: + sha1recompress_fast_41(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE42 + case 42: + sha1recompress_fast_42(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE43 + case 43: + sha1recompress_fast_43(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE44 + case 44: + sha1recompress_fast_44(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE45 + case 45: + sha1recompress_fast_45(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE46 + case 46: + sha1recompress_fast_46(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE47 + case 47: + sha1recompress_fast_47(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE48 + case 48: + sha1recompress_fast_48(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE49 + case 49: + sha1recompress_fast_49(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE50 + case 50: + sha1recompress_fast_50(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE51 + case 51: + sha1recompress_fast_51(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE52 + case 52: + sha1recompress_fast_52(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE53 + case 53: + sha1recompress_fast_53(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE54 + case 54: + sha1recompress_fast_54(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE55 + case 55: + sha1recompress_fast_55(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE56 + case 56: + sha1recompress_fast_56(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE57 + case 57: + sha1recompress_fast_57(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE58 + case 58: + sha1recompress_fast_58(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE59 + case 59: + sha1recompress_fast_59(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE60 + case 60: + sha1recompress_fast_60(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE61 + case 61: + sha1recompress_fast_61(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE62 + case 62: + sha1recompress_fast_62(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE63 + case 63: + sha1recompress_fast_63(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE64 + case 64: + sha1recompress_fast_64(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE65 + case 65: + sha1recompress_fast_65(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE66 + case 66: + sha1recompress_fast_66(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE67 + case 67: + sha1recompress_fast_67(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE68 + case 68: + sha1recompress_fast_68(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE69 + case 69: + sha1recompress_fast_69(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE70 + case 70: + sha1recompress_fast_70(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE71 + case 71: + sha1recompress_fast_71(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE72 + case 72: + sha1recompress_fast_72(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE73 + case 73: + sha1recompress_fast_73(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE74 + case 74: + sha1recompress_fast_74(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE75 + case 75: + sha1recompress_fast_75(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE76 + case 76: + sha1recompress_fast_76(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE77 + case 77: + sha1recompress_fast_77(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE78 + case 78: + sha1recompress_fast_78(ihvin, ihvout, me2, state); + break; +#endif +#ifdef DOSTORESTATE79 + case 79: + sha1recompress_fast_79(ihvin, ihvout, me2, state); + break; +#endif + default: + abort(); + } + +} + + + +static void sha1_process(SHA1_CTX* ctx, const uint32_t block[16]) +{ + unsigned i, j; + uint32_t ubc_dv_mask[DVMASKSIZE] = { 0xFFFFFFFF }; + uint32_t ihvtmp[5]; + + ctx->ihv1[0] = ctx->ihv[0]; + ctx->ihv1[1] = ctx->ihv[1]; + ctx->ihv1[2] = ctx->ihv[2]; + ctx->ihv1[3] = ctx->ihv[3]; + ctx->ihv1[4] = ctx->ihv[4]; + + sha1_compression_states(ctx->ihv, block, ctx->m1, ctx->states); + + if (ctx->detect_coll) + { + if (ctx->ubc_check) + { + ubc_check(ctx->m1, ubc_dv_mask); + } + + if (ubc_dv_mask[0] != 0) + { + for (i = 0; sha1_dvs[i].dvType != 0; ++i) + { + if (ubc_dv_mask[0] & ((uint32_t)(1) << sha1_dvs[i].maskb)) + { + for (j = 0; j < 80; ++j) + ctx->m2[j] = ctx->m1[j] ^ sha1_dvs[i].dm[j]; + + sha1_recompression_step(sha1_dvs[i].testt, ctx->ihv2, ihvtmp, ctx->m2, ctx->states[sha1_dvs[i].testt]); + + /* to verify SHA-1 collision detection code with collisions for reduced-step SHA-1 */ + if ((0 == ((ihvtmp[0] ^ ctx->ihv[0]) | (ihvtmp[1] ^ ctx->ihv[1]) | (ihvtmp[2] ^ ctx->ihv[2]) | (ihvtmp[3] ^ ctx->ihv[3]) | (ihvtmp[4] ^ ctx->ihv[4]))) + || (ctx->reduced_round_coll && 0==((ctx->ihv1[0] ^ ctx->ihv2[0]) | (ctx->ihv1[1] ^ ctx->ihv2[1]) | (ctx->ihv1[2] ^ ctx->ihv2[2]) | (ctx->ihv1[3] ^ ctx->ihv2[3]) | (ctx->ihv1[4] ^ ctx->ihv2[4])))) + { + ctx->found_collision = 1; + + if (ctx->safe_hash) + { + sha1_compression_W(ctx->ihv, ctx->m1); + sha1_compression_W(ctx->ihv, ctx->m1); + } + + break; + } + } + } + } + } +} + +void SHA1DCInit(SHA1_CTX* ctx) +{ + ctx->total = 0; + ctx->ihv[0] = 0x67452301; + ctx->ihv[1] = 0xEFCDAB89; + ctx->ihv[2] = 0x98BADCFE; + ctx->ihv[3] = 0x10325476; + ctx->ihv[4] = 0xC3D2E1F0; + ctx->found_collision = 0; + ctx->safe_hash = 0; + ctx->ubc_check = 1; + ctx->detect_coll = 1; + ctx->reduced_round_coll = 0; + ctx->callback = NULL; +} + +void SHA1DCSetSafeHash(SHA1_CTX* ctx, int safehash) +{ + if (safehash) + ctx->safe_hash = 1; + else + ctx->safe_hash = 0; +} + + +void SHA1DCSetUseUBC(SHA1_CTX* ctx, int ubc_check) +{ + if (ubc_check) + ctx->ubc_check = 1; + else + ctx->ubc_check = 0; +} + +void SHA1DCSetUseDetectColl(SHA1_CTX* ctx, int detect_coll) +{ + if (detect_coll) + ctx->detect_coll = 1; + else + ctx->detect_coll = 0; +} + +void SHA1DCSetDetectReducedRoundCollision(SHA1_CTX* ctx, int reduced_round_coll) +{ + if (reduced_round_coll) + ctx->reduced_round_coll = 1; + else + ctx->reduced_round_coll = 0; +} + +void SHA1DCSetCallback(SHA1_CTX* ctx, collision_block_callback callback) +{ + ctx->callback = callback; +} + +void SHA1DCUpdate(SHA1_CTX* ctx, const char* buf, size_t len) +{ + unsigned left, fill; + if (len == 0) + return; + + left = ctx->total & 63; + fill = 64 - left; + + if (left && len >= fill) + { + ctx->total += fill; + memcpy(ctx->buffer + left, buf, fill); + sha1_process(ctx, (uint32_t*)(ctx->buffer)); + buf += fill; + len -= fill; + left = 0; + } + while (len >= 64) + { + ctx->total += 64; + sha1_process(ctx, (uint32_t*)(buf)); + buf += 64; + len -= 64; + } + if (len > 0) + { + ctx->total += len; + memcpy(ctx->buffer + left, buf, len); + } +} + +static const unsigned char sha1_padding[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +int SHA1DCFinal(unsigned char output[20], SHA1_CTX *ctx) +{ + uint32_t last = ctx->total & 63; + uint32_t padn = (last < 56) ? (56 - last) : (120 - last); + uint64_t total; + SHA1DCUpdate(ctx, (const char*)(sha1_padding), padn); + + total = ctx->total - padn; + total <<= 3; + ctx->buffer[56] = (unsigned char)(total >> 56); + ctx->buffer[57] = (unsigned char)(total >> 48); + ctx->buffer[58] = (unsigned char)(total >> 40); + ctx->buffer[59] = (unsigned char)(total >> 32); + ctx->buffer[60] = (unsigned char)(total >> 24); + ctx->buffer[61] = (unsigned char)(total >> 16); + ctx->buffer[62] = (unsigned char)(total >> 8); + ctx->buffer[63] = (unsigned char)(total); + sha1_process(ctx, (uint32_t*)(ctx->buffer)); + output[0] = (unsigned char)(ctx->ihv[0] >> 24); + output[1] = (unsigned char)(ctx->ihv[0] >> 16); + output[2] = (unsigned char)(ctx->ihv[0] >> 8); + output[3] = (unsigned char)(ctx->ihv[0]); + output[4] = (unsigned char)(ctx->ihv[1] >> 24); + output[5] = (unsigned char)(ctx->ihv[1] >> 16); + output[6] = (unsigned char)(ctx->ihv[1] >> 8); + output[7] = (unsigned char)(ctx->ihv[1]); + output[8] = (unsigned char)(ctx->ihv[2] >> 24); + output[9] = (unsigned char)(ctx->ihv[2] >> 16); + output[10] = (unsigned char)(ctx->ihv[2] >> 8); + output[11] = (unsigned char)(ctx->ihv[2]); + output[12] = (unsigned char)(ctx->ihv[3] >> 24); + output[13] = (unsigned char)(ctx->ihv[3] >> 16); + output[14] = (unsigned char)(ctx->ihv[3] >> 8); + output[15] = (unsigned char)(ctx->ihv[3]); + output[16] = (unsigned char)(ctx->ihv[4] >> 24); + output[17] = (unsigned char)(ctx->ihv[4] >> 16); + output[18] = (unsigned char)(ctx->ihv[4] >> 8); + output[19] = (unsigned char)(ctx->ihv[4]); + return ctx->found_collision; +} + +void git_SHA1DCFinal(unsigned char hash[20], SHA1_CTX *ctx) +{ + if (!SHA1DCFinal(hash, ctx)) + return; + die("SHA-1 appears to be part of a collision attack: %s", + sha1_to_hex(hash)); +} + +void git_SHA1DCUpdate(SHA1_CTX *ctx, const void *vdata, unsigned long len) +{ + const char *data = vdata; + /* We expect an unsigned long, but sha1dc only takes an int */ + while (len > INT_MAX) { + SHA1DCUpdate(ctx, data, INT_MAX); + data += INT_MAX; + len -= INT_MAX; + } + SHA1DCUpdate(ctx, data, len); +} diff --git a/sha1dc/sha1.h b/sha1dc/sha1.h new file mode 100644 index 0000000000..bd8bd928fb --- /dev/null +++ b/sha1dc/sha1.h @@ -0,0 +1,122 @@ +/*** +* Copyright 2017 Marc Stevens <marc@marc-stevens.nl>, Dan Shumow <danshu@microsoft.com> +* Distributed under the MIT Software License. +* See accompanying file LICENSE.txt or copy at +* https://opensource.org/licenses/MIT +***/ +#ifndef SHA1DC_SHA1_H +#define SHA1DC_SHA1_H + +#if defined(__cplusplus) +extern "C" { +#endif + +/* uses SHA-1 message expansion to expand the first 16 words of W[] to 80 words */ +/* void sha1_message_expansion(uint32_t W[80]); */ + +/* sha-1 compression function; first version takes a message block pre-parsed as 16 32-bit integers, second version takes an already expanded message) */ +/* void sha1_compression(uint32_t ihv[5], const uint32_t m[16]); +void sha1_compression_W(uint32_t ihv[5], const uint32_t W[80]); */ + +/* same as sha1_compression_W, but additionally store intermediate states */ +/* only stores states ii (the state between step ii-1 and step ii) when DOSTORESTATEii is defined in ubc_check.h */ +void sha1_compression_states(uint32_t[5], const uint32_t[16], uint32_t[80], uint32_t[80][5]); + +/* +// function type for sha1_recompression_step_T (uint32_t ihvin[5], uint32_t ihvout[5], const uint32_t me2[80], const uint32_t state[5]) +// where 0 <= T < 80 +// me2 is an expanded message (the expansion of an original message block XOR'ed with a disturbance vector's message block difference) +// state is the internal state (a,b,c,d,e) before step T of the SHA-1 compression function while processing the original message block +// the function will return: +// ihvin: the reconstructed input chaining value +// ihvout: the reconstructed output chaining value +*/ +typedef void(*sha1_recompression_type)(uint32_t*, uint32_t*, const uint32_t*, const uint32_t*); + +/* table of sha1_recompression_step_0, ... , sha1_recompression_step_79 */ +/* extern sha1_recompression_type sha1_recompression_step[80];*/ + +/* a callback function type that can be set to be called when a collision block has been found: */ +/* void collision_block_callback(uint64_t byteoffset, const uint32_t ihvin1[5], const uint32_t ihvin2[5], const uint32_t m1[80], const uint32_t m2[80]) */ +typedef void(*collision_block_callback)(uint64_t, const uint32_t*, const uint32_t*, const uint32_t*, const uint32_t*); + +/* the SHA-1 context */ +typedef struct { + uint64_t total; + uint32_t ihv[5]; + unsigned char buffer[64]; + int found_collision; + int safe_hash; + int detect_coll; + int ubc_check; + int reduced_round_coll; + collision_block_callback callback; + + uint32_t ihv1[5]; + uint32_t ihv2[5]; + uint32_t m1[80]; + uint32_t m2[80]; + uint32_t states[80][5]; +} SHA1_CTX; + +/* initialize SHA-1 context */ +void SHA1DCInit(SHA1_CTX*); + +/* +// function to enable safe SHA-1 hashing: +// collision attacks are thwarted by hashing a detected near-collision block 3 times +// think of it as extending SHA-1 from 80-steps to 240-steps for such blocks: +// the best collision attacks against SHA-1 have complexity about 2^60, +// thus for 240-steps an immediate lower-bound for the best cryptanalytic attacks would 2^180 +// an attacker would be better off using a generic birthday search of complexity 2^80 +// +// enabling safe SHA-1 hashing will result in the correct SHA-1 hash for messages where no collision attack was detected +// but it will result in a different SHA-1 hash for messages where a collision attack was detected +// this will automatically invalidate SHA-1 based digital signature forgeries +// enabled by default +*/ +void SHA1DCSetSafeHash(SHA1_CTX*, int); + +/* function to disable or enable the use of Unavoidable Bitconditions (provides a significant speed up) */ +/* enabled by default */ +void SHA1DCSetUseUBC(SHA1_CTX*, int); + +/* function to disable or enable the use of Collision Detection */ +/* enabled by default */ +void SHA1DCSetUseDetectColl(SHA1_CTX*, int); + +/* function to disable or enable the detection of reduced-round SHA-1 collisions */ +/* disabled by default */ +void SHA1DCSetDetectReducedRoundCollision(SHA1_CTX*, int); + +/* function to set a callback function, pass NULL to disable */ +/* by default no callback set */ +void SHA1DCSetCallback(SHA1_CTX*, collision_block_callback); + +/* update SHA-1 context with buffer contents */ +void SHA1DCUpdate(SHA1_CTX*, const char*, size_t); + +/* obtain SHA-1 hash from SHA-1 context */ +/* returns: 0 = no collision detected, otherwise = collision found => warn user for active attack */ +int SHA1DCFinal(unsigned char[20], SHA1_CTX*); + +/* + * Same as SHA1DCFinal, but convert collision attack case into a verbose die(). + */ +void git_SHA1DCFinal(unsigned char [20], SHA1_CTX *); + +/* + * Same as SHA1DCUpdate, but adjust types to match git's usual interface. + */ +void git_SHA1DCUpdate(SHA1_CTX *ctx, const void *data, unsigned long len); + +#define platform_SHA_CTX SHA1_CTX +#define platform_SHA1_Init SHA1DCInit +#define platform_SHA1_Update git_SHA1DCUpdate +#define platform_SHA1_Final git_SHA1DCFinal + +#if defined(__cplusplus) +} +#endif + +#endif /* SHA1DC_SHA1_H */ diff --git a/sha1dc/ubc_check.c b/sha1dc/ubc_check.c new file mode 100644 index 0000000000..089dd4743d --- /dev/null +++ b/sha1dc/ubc_check.c @@ -0,0 +1,363 @@ +/*** +* Copyright 2017 Marc Stevens <marc@marc-stevens.nl>, Dan Shumow <danshu@microsoft.com> +* Distributed under the MIT Software License. +* See accompanying file LICENSE.txt or copy at +* https://opensource.org/licenses/MIT +***/ + +/* +// this file was generated by the 'parse_bitrel' program in the tools section +// using the data files from directory 'tools/data/3565' +// +// sha1_dvs contains a list of SHA-1 Disturbance Vectors (DV) to check +// dvType, dvK and dvB define the DV: I(K,B) or II(K,B) (see the paper) +// dm[80] is the expanded message block XOR-difference defined by the DV +// testt is the step to do the recompression from for collision detection +// maski and maskb define the bit to check for each DV in the dvmask returned by ubc_check +// +// ubc_check takes as input an expanded message block and verifies the unavoidable bitconditions for all listed DVs +// it returns a dvmask where each bit belonging to a DV is set if all unavoidable bitconditions for that DV have been met +// thus one needs to do the recompression check for each DV that has its bit set +// +// ubc_check is programmatically generated and the unavoidable bitconditions have been hardcoded +// a directly verifiable version named ubc_check_verify can be found in ubc_check_verify.c +// ubc_check has been verified against ubc_check_verify using the 'ubc_check_test' program in the tools section +*/ + +#include "git-compat-util.h" +#include "sha1dc/ubc_check.h" + +static const uint32_t DV_I_43_0_bit = (uint32_t)(1) << 0; +static const uint32_t DV_I_44_0_bit = (uint32_t)(1) << 1; +static const uint32_t DV_I_45_0_bit = (uint32_t)(1) << 2; +static const uint32_t DV_I_46_0_bit = (uint32_t)(1) << 3; +static const uint32_t DV_I_46_2_bit = (uint32_t)(1) << 4; +static const uint32_t DV_I_47_0_bit = (uint32_t)(1) << 5; +static const uint32_t DV_I_47_2_bit = (uint32_t)(1) << 6; +static const uint32_t DV_I_48_0_bit = (uint32_t)(1) << 7; +static const uint32_t DV_I_48_2_bit = (uint32_t)(1) << 8; +static const uint32_t DV_I_49_0_bit = (uint32_t)(1) << 9; +static const uint32_t DV_I_49_2_bit = (uint32_t)(1) << 10; +static const uint32_t DV_I_50_0_bit = (uint32_t)(1) << 11; +static const uint32_t DV_I_50_2_bit = (uint32_t)(1) << 12; +static const uint32_t DV_I_51_0_bit = (uint32_t)(1) << 13; +static const uint32_t DV_I_51_2_bit = (uint32_t)(1) << 14; +static const uint32_t DV_I_52_0_bit = (uint32_t)(1) << 15; +static const uint32_t DV_II_45_0_bit = (uint32_t)(1) << 16; +static const uint32_t DV_II_46_0_bit = (uint32_t)(1) << 17; +static const uint32_t DV_II_46_2_bit = (uint32_t)(1) << 18; +static const uint32_t DV_II_47_0_bit = (uint32_t)(1) << 19; +static const uint32_t DV_II_48_0_bit = (uint32_t)(1) << 20; +static const uint32_t DV_II_49_0_bit = (uint32_t)(1) << 21; +static const uint32_t DV_II_49_2_bit = (uint32_t)(1) << 22; +static const uint32_t DV_II_50_0_bit = (uint32_t)(1) << 23; +static const uint32_t DV_II_50_2_bit = (uint32_t)(1) << 24; +static const uint32_t DV_II_51_0_bit = (uint32_t)(1) << 25; +static const uint32_t DV_II_51_2_bit = (uint32_t)(1) << 26; +static const uint32_t DV_II_52_0_bit = (uint32_t)(1) << 27; +static const uint32_t DV_II_53_0_bit = (uint32_t)(1) << 28; +static const uint32_t DV_II_54_0_bit = (uint32_t)(1) << 29; +static const uint32_t DV_II_55_0_bit = (uint32_t)(1) << 30; +static const uint32_t DV_II_56_0_bit = (uint32_t)(1) << 31; + +dv_info_t sha1_dvs[] = +{ + {1,43,0,58,0,0, { 0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018,0x00000164,0x00000408,0x800000e6,0x8000004c,0x00000803,0x80000161,0x80000599 } } +, {1,44,0,58,0,1, { 0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018,0x00000164,0x00000408,0x800000e6,0x8000004c,0x00000803,0x80000161 } } +, {1,45,0,58,0,2, { 0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018,0x00000164,0x00000408,0x800000e6,0x8000004c,0x00000803 } } +, {1,46,0,58,0,3, { 0x2c000010,0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018,0x00000164,0x00000408,0x800000e6,0x8000004c } } +, {1,46,2,58,0,4, { 0xb0000040,0xd0000053,0xd0000022,0x20000000,0x60000032,0x60000043,0x20000040,0xe0000042,0x60000002,0x80000001,0x00000020,0x00000003,0x40000052,0x40000040,0xe0000052,0xa0000000,0x80000040,0x20000001,0x20000060,0x80000001,0x40000042,0xc0000043,0x40000022,0x00000003,0x40000042,0xc0000043,0xc0000022,0x00000001,0x40000002,0xc0000043,0x40000062,0x80000001,0x40000042,0x40000042,0x40000002,0x00000002,0x00000040,0x80000002,0x80000000,0x80000002,0x80000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000000,0x00000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000101,0x00000009,0x00000012,0x00000202,0x0000001a,0x00000124,0x0000040c,0x00000026,0x0000004a,0x0000080a,0x00000060,0x00000590,0x00001020,0x0000039a,0x00000132 } } +, {1,47,0,58,0,5, { 0xc8000010,0x2c000010,0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018,0x00000164,0x00000408,0x800000e6 } } +, {1,47,2,58,0,6, { 0x20000043,0xb0000040,0xd0000053,0xd0000022,0x20000000,0x60000032,0x60000043,0x20000040,0xe0000042,0x60000002,0x80000001,0x00000020,0x00000003,0x40000052,0x40000040,0xe0000052,0xa0000000,0x80000040,0x20000001,0x20000060,0x80000001,0x40000042,0xc0000043,0x40000022,0x00000003,0x40000042,0xc0000043,0xc0000022,0x00000001,0x40000002,0xc0000043,0x40000062,0x80000001,0x40000042,0x40000042,0x40000002,0x00000002,0x00000040,0x80000002,0x80000000,0x80000002,0x80000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000000,0x00000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000101,0x00000009,0x00000012,0x00000202,0x0000001a,0x00000124,0x0000040c,0x00000026,0x0000004a,0x0000080a,0x00000060,0x00000590,0x00001020,0x0000039a } } +, {1,48,0,58,0,7, { 0xb800000a,0xc8000010,0x2c000010,0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018,0x00000164,0x00000408 } } +, {1,48,2,58,0,8, { 0xe000002a,0x20000043,0xb0000040,0xd0000053,0xd0000022,0x20000000,0x60000032,0x60000043,0x20000040,0xe0000042,0x60000002,0x80000001,0x00000020,0x00000003,0x40000052,0x40000040,0xe0000052,0xa0000000,0x80000040,0x20000001,0x20000060,0x80000001,0x40000042,0xc0000043,0x40000022,0x00000003,0x40000042,0xc0000043,0xc0000022,0x00000001,0x40000002,0xc0000043,0x40000062,0x80000001,0x40000042,0x40000042,0x40000002,0x00000002,0x00000040,0x80000002,0x80000000,0x80000002,0x80000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000000,0x00000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000101,0x00000009,0x00000012,0x00000202,0x0000001a,0x00000124,0x0000040c,0x00000026,0x0000004a,0x0000080a,0x00000060,0x00000590,0x00001020 } } +, {1,49,0,58,0,9, { 0x18000000,0xb800000a,0xc8000010,0x2c000010,0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018,0x00000164 } } +, {1,49,2,58,0,10, { 0x60000000,0xe000002a,0x20000043,0xb0000040,0xd0000053,0xd0000022,0x20000000,0x60000032,0x60000043,0x20000040,0xe0000042,0x60000002,0x80000001,0x00000020,0x00000003,0x40000052,0x40000040,0xe0000052,0xa0000000,0x80000040,0x20000001,0x20000060,0x80000001,0x40000042,0xc0000043,0x40000022,0x00000003,0x40000042,0xc0000043,0xc0000022,0x00000001,0x40000002,0xc0000043,0x40000062,0x80000001,0x40000042,0x40000042,0x40000002,0x00000002,0x00000040,0x80000002,0x80000000,0x80000002,0x80000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000000,0x00000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000101,0x00000009,0x00000012,0x00000202,0x0000001a,0x00000124,0x0000040c,0x00000026,0x0000004a,0x0000080a,0x00000060,0x00000590 } } +, {1,50,0,65,0,11, { 0x0800000c,0x18000000,0xb800000a,0xc8000010,0x2c000010,0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018 } } +, {1,50,2,65,0,12, { 0x20000030,0x60000000,0xe000002a,0x20000043,0xb0000040,0xd0000053,0xd0000022,0x20000000,0x60000032,0x60000043,0x20000040,0xe0000042,0x60000002,0x80000001,0x00000020,0x00000003,0x40000052,0x40000040,0xe0000052,0xa0000000,0x80000040,0x20000001,0x20000060,0x80000001,0x40000042,0xc0000043,0x40000022,0x00000003,0x40000042,0xc0000043,0xc0000022,0x00000001,0x40000002,0xc0000043,0x40000062,0x80000001,0x40000042,0x40000042,0x40000002,0x00000002,0x00000040,0x80000002,0x80000000,0x80000002,0x80000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000000,0x00000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000101,0x00000009,0x00000012,0x00000202,0x0000001a,0x00000124,0x0000040c,0x00000026,0x0000004a,0x0000080a,0x00000060 } } +, {1,51,0,65,0,13, { 0xe8000000,0x0800000c,0x18000000,0xb800000a,0xc8000010,0x2c000010,0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202 } } +, {1,51,2,65,0,14, { 0xa0000003,0x20000030,0x60000000,0xe000002a,0x20000043,0xb0000040,0xd0000053,0xd0000022,0x20000000,0x60000032,0x60000043,0x20000040,0xe0000042,0x60000002,0x80000001,0x00000020,0x00000003,0x40000052,0x40000040,0xe0000052,0xa0000000,0x80000040,0x20000001,0x20000060,0x80000001,0x40000042,0xc0000043,0x40000022,0x00000003,0x40000042,0xc0000043,0xc0000022,0x00000001,0x40000002,0xc0000043,0x40000062,0x80000001,0x40000042,0x40000042,0x40000002,0x00000002,0x00000040,0x80000002,0x80000000,0x80000002,0x80000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000000,0x00000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000101,0x00000009,0x00000012,0x00000202,0x0000001a,0x00000124,0x0000040c,0x00000026,0x0000004a,0x0000080a } } +, {1,52,0,65,0,15, { 0x04000010,0xe8000000,0x0800000c,0x18000000,0xb800000a,0xc8000010,0x2c000010,0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012 } } +, {2,45,0,58,0,16, { 0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014,0x8000024b,0x0000011b,0x8000016d,0x8000041a,0x000002e4,0x80000054,0x00000967 } } +, {2,46,0,58,0,17, { 0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014,0x8000024b,0x0000011b,0x8000016d,0x8000041a,0x000002e4,0x80000054 } } +, {2,46,2,58,0,18, { 0x90000070,0xb0000053,0x30000008,0x00000043,0xd0000072,0xb0000010,0xf0000062,0xc0000042,0x00000030,0xe0000042,0x20000060,0xe0000041,0x20000050,0xc0000041,0xe0000072,0xa0000003,0xc0000012,0x60000041,0xc0000032,0x20000001,0xc0000002,0xe0000042,0x60000042,0x80000002,0x00000000,0x00000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000001,0x00000060,0x80000003,0x40000002,0xc0000040,0xc0000002,0x80000000,0x80000000,0x80000002,0x00000040,0x00000002,0x80000000,0x80000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000105,0x00000089,0x00000016,0x0000020b,0x0000011b,0x0000012d,0x0000041e,0x00000224,0x00000050,0x0000092e,0x0000046c,0x000005b6,0x0000106a,0x00000b90,0x00000152 } } +, {2,47,0,58,0,19, { 0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014,0x8000024b,0x0000011b,0x8000016d,0x8000041a,0x000002e4 } } +, {2,48,0,58,0,20, { 0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014,0x8000024b,0x0000011b,0x8000016d,0x8000041a } } +, {2,49,0,58,0,21, { 0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014,0x8000024b,0x0000011b,0x8000016d } } +, {2,49,2,58,0,22, { 0xf0000010,0xf000006a,0x80000040,0x90000070,0xb0000053,0x30000008,0x00000043,0xd0000072,0xb0000010,0xf0000062,0xc0000042,0x00000030,0xe0000042,0x20000060,0xe0000041,0x20000050,0xc0000041,0xe0000072,0xa0000003,0xc0000012,0x60000041,0xc0000032,0x20000001,0xc0000002,0xe0000042,0x60000042,0x80000002,0x00000000,0x00000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000001,0x00000060,0x80000003,0x40000002,0xc0000040,0xc0000002,0x80000000,0x80000000,0x80000002,0x00000040,0x00000002,0x80000000,0x80000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000105,0x00000089,0x00000016,0x0000020b,0x0000011b,0x0000012d,0x0000041e,0x00000224,0x00000050,0x0000092e,0x0000046c,0x000005b6 } } +, {2,50,0,65,0,23, { 0xb400001c,0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014,0x8000024b,0x0000011b } } +, {2,50,2,65,0,24, { 0xd0000072,0xf0000010,0xf000006a,0x80000040,0x90000070,0xb0000053,0x30000008,0x00000043,0xd0000072,0xb0000010,0xf0000062,0xc0000042,0x00000030,0xe0000042,0x20000060,0xe0000041,0x20000050,0xc0000041,0xe0000072,0xa0000003,0xc0000012,0x60000041,0xc0000032,0x20000001,0xc0000002,0xe0000042,0x60000042,0x80000002,0x00000000,0x00000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000001,0x00000060,0x80000003,0x40000002,0xc0000040,0xc0000002,0x80000000,0x80000000,0x80000002,0x00000040,0x00000002,0x80000000,0x80000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000105,0x00000089,0x00000016,0x0000020b,0x0000011b,0x0000012d,0x0000041e,0x00000224,0x00000050,0x0000092e,0x0000046c } } +, {2,51,0,65,0,25, { 0xc0000010,0xb400001c,0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014,0x8000024b } } +, {2,51,2,65,0,26, { 0x00000043,0xd0000072,0xf0000010,0xf000006a,0x80000040,0x90000070,0xb0000053,0x30000008,0x00000043,0xd0000072,0xb0000010,0xf0000062,0xc0000042,0x00000030,0xe0000042,0x20000060,0xe0000041,0x20000050,0xc0000041,0xe0000072,0xa0000003,0xc0000012,0x60000041,0xc0000032,0x20000001,0xc0000002,0xe0000042,0x60000042,0x80000002,0x00000000,0x00000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000001,0x00000060,0x80000003,0x40000002,0xc0000040,0xc0000002,0x80000000,0x80000000,0x80000002,0x00000040,0x00000002,0x80000000,0x80000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000105,0x00000089,0x00000016,0x0000020b,0x0000011b,0x0000012d,0x0000041e,0x00000224,0x00000050,0x0000092e } } +, {2,52,0,65,0,27, { 0x0c000002,0xc0000010,0xb400001c,0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014 } } +, {2,53,0,65,0,28, { 0xcc000014,0x0c000002,0xc0000010,0xb400001c,0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089 } } +, {2,54,0,65,0,29, { 0x0400001c,0xcc000014,0x0c000002,0xc0000010,0xb400001c,0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107 } } +, {2,55,0,65,0,30, { 0x00000010,0x0400001c,0xcc000014,0x0c000002,0xc0000010,0xb400001c,0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b } } +, {2,56,0,65,0,31, { 0x2600001a,0x00000010,0x0400001c,0xcc000014,0x0c000002,0xc0000010,0xb400001c,0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046 } } +, {0,0,0,0,0,0, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}} +}; +void ubc_check(const uint32_t W[80], uint32_t dvmask[1]) +{ + uint32_t mask = ~((uint32_t)(0)); + mask &= (((((W[44]^W[45])>>29)&1)-1) | ~(DV_I_48_0_bit|DV_I_51_0_bit|DV_I_52_0_bit|DV_II_45_0_bit|DV_II_46_0_bit|DV_II_50_0_bit|DV_II_51_0_bit)); + mask &= (((((W[49]^W[50])>>29)&1)-1) | ~(DV_I_46_0_bit|DV_II_45_0_bit|DV_II_50_0_bit|DV_II_51_0_bit|DV_II_55_0_bit|DV_II_56_0_bit)); + mask &= (((((W[48]^W[49])>>29)&1)-1) | ~(DV_I_45_0_bit|DV_I_52_0_bit|DV_II_49_0_bit|DV_II_50_0_bit|DV_II_54_0_bit|DV_II_55_0_bit)); + mask &= ((((W[47]^(W[50]>>25))&(1<<4))-(1<<4)) | ~(DV_I_47_0_bit|DV_I_49_0_bit|DV_I_51_0_bit|DV_II_45_0_bit|DV_II_51_0_bit|DV_II_56_0_bit)); + mask &= (((((W[47]^W[48])>>29)&1)-1) | ~(DV_I_44_0_bit|DV_I_51_0_bit|DV_II_48_0_bit|DV_II_49_0_bit|DV_II_53_0_bit|DV_II_54_0_bit)); + mask &= (((((W[46]>>4)^(W[49]>>29))&1)-1) | ~(DV_I_46_0_bit|DV_I_48_0_bit|DV_I_50_0_bit|DV_I_52_0_bit|DV_II_50_0_bit|DV_II_55_0_bit)); + mask &= (((((W[46]^W[47])>>29)&1)-1) | ~(DV_I_43_0_bit|DV_I_50_0_bit|DV_II_47_0_bit|DV_II_48_0_bit|DV_II_52_0_bit|DV_II_53_0_bit)); + mask &= (((((W[45]>>4)^(W[48]>>29))&1)-1) | ~(DV_I_45_0_bit|DV_I_47_0_bit|DV_I_49_0_bit|DV_I_51_0_bit|DV_II_49_0_bit|DV_II_54_0_bit)); + mask &= (((((W[45]^W[46])>>29)&1)-1) | ~(DV_I_49_0_bit|DV_I_52_0_bit|DV_II_46_0_bit|DV_II_47_0_bit|DV_II_51_0_bit|DV_II_52_0_bit)); + mask &= (((((W[44]>>4)^(W[47]>>29))&1)-1) | ~(DV_I_44_0_bit|DV_I_46_0_bit|DV_I_48_0_bit|DV_I_50_0_bit|DV_II_48_0_bit|DV_II_53_0_bit)); + mask &= (((((W[43]>>4)^(W[46]>>29))&1)-1) | ~(DV_I_43_0_bit|DV_I_45_0_bit|DV_I_47_0_bit|DV_I_49_0_bit|DV_II_47_0_bit|DV_II_52_0_bit)); + mask &= (((((W[43]^W[44])>>29)&1)-1) | ~(DV_I_47_0_bit|DV_I_50_0_bit|DV_I_51_0_bit|DV_II_45_0_bit|DV_II_49_0_bit|DV_II_50_0_bit)); + mask &= (((((W[42]>>4)^(W[45]>>29))&1)-1) | ~(DV_I_44_0_bit|DV_I_46_0_bit|DV_I_48_0_bit|DV_I_52_0_bit|DV_II_46_0_bit|DV_II_51_0_bit)); + mask &= (((((W[41]>>4)^(W[44]>>29))&1)-1) | ~(DV_I_43_0_bit|DV_I_45_0_bit|DV_I_47_0_bit|DV_I_51_0_bit|DV_II_45_0_bit|DV_II_50_0_bit)); + mask &= (((((W[40]^W[41])>>29)&1)-1) | ~(DV_I_44_0_bit|DV_I_47_0_bit|DV_I_48_0_bit|DV_II_46_0_bit|DV_II_47_0_bit|DV_II_56_0_bit)); + mask &= (((((W[54]^W[55])>>29)&1)-1) | ~(DV_I_51_0_bit|DV_II_47_0_bit|DV_II_50_0_bit|DV_II_55_0_bit|DV_II_56_0_bit)); + mask &= (((((W[53]^W[54])>>29)&1)-1) | ~(DV_I_50_0_bit|DV_II_46_0_bit|DV_II_49_0_bit|DV_II_54_0_bit|DV_II_55_0_bit)); + mask &= (((((W[52]^W[53])>>29)&1)-1) | ~(DV_I_49_0_bit|DV_II_45_0_bit|DV_II_48_0_bit|DV_II_53_0_bit|DV_II_54_0_bit)); + mask &= ((((W[50]^(W[53]>>25))&(1<<4))-(1<<4)) | ~(DV_I_50_0_bit|DV_I_52_0_bit|DV_II_46_0_bit|DV_II_48_0_bit|DV_II_54_0_bit)); + mask &= (((((W[50]^W[51])>>29)&1)-1) | ~(DV_I_47_0_bit|DV_II_46_0_bit|DV_II_51_0_bit|DV_II_52_0_bit|DV_II_56_0_bit)); + mask &= ((((W[49]^(W[52]>>25))&(1<<4))-(1<<4)) | ~(DV_I_49_0_bit|DV_I_51_0_bit|DV_II_45_0_bit|DV_II_47_0_bit|DV_II_53_0_bit)); + mask &= ((((W[48]^(W[51]>>25))&(1<<4))-(1<<4)) | ~(DV_I_48_0_bit|DV_I_50_0_bit|DV_I_52_0_bit|DV_II_46_0_bit|DV_II_52_0_bit)); + mask &= (((((W[42]^W[43])>>29)&1)-1) | ~(DV_I_46_0_bit|DV_I_49_0_bit|DV_I_50_0_bit|DV_II_48_0_bit|DV_II_49_0_bit)); + mask &= (((((W[41]^W[42])>>29)&1)-1) | ~(DV_I_45_0_bit|DV_I_48_0_bit|DV_I_49_0_bit|DV_II_47_0_bit|DV_II_48_0_bit)); + mask &= (((((W[40]>>4)^(W[43]>>29))&1)-1) | ~(DV_I_44_0_bit|DV_I_46_0_bit|DV_I_50_0_bit|DV_II_49_0_bit|DV_II_56_0_bit)); + mask &= (((((W[39]>>4)^(W[42]>>29))&1)-1) | ~(DV_I_43_0_bit|DV_I_45_0_bit|DV_I_49_0_bit|DV_II_48_0_bit|DV_II_55_0_bit)); + if (mask & (DV_I_44_0_bit|DV_I_48_0_bit|DV_II_47_0_bit|DV_II_54_0_bit|DV_II_56_0_bit)) + mask &= (((((W[38]>>4)^(W[41]>>29))&1)-1) | ~(DV_I_44_0_bit|DV_I_48_0_bit|DV_II_47_0_bit|DV_II_54_0_bit|DV_II_56_0_bit)); + mask &= (((((W[37]>>4)^(W[40]>>29))&1)-1) | ~(DV_I_43_0_bit|DV_I_47_0_bit|DV_II_46_0_bit|DV_II_53_0_bit|DV_II_55_0_bit)); + if (mask & (DV_I_52_0_bit|DV_II_48_0_bit|DV_II_51_0_bit|DV_II_56_0_bit)) + mask &= (((((W[55]^W[56])>>29)&1)-1) | ~(DV_I_52_0_bit|DV_II_48_0_bit|DV_II_51_0_bit|DV_II_56_0_bit)); + if (mask & (DV_I_52_0_bit|DV_II_48_0_bit|DV_II_50_0_bit|DV_II_56_0_bit)) + mask &= ((((W[52]^(W[55]>>25))&(1<<4))-(1<<4)) | ~(DV_I_52_0_bit|DV_II_48_0_bit|DV_II_50_0_bit|DV_II_56_0_bit)); + if (mask & (DV_I_51_0_bit|DV_II_47_0_bit|DV_II_49_0_bit|DV_II_55_0_bit)) + mask &= ((((W[51]^(W[54]>>25))&(1<<4))-(1<<4)) | ~(DV_I_51_0_bit|DV_II_47_0_bit|DV_II_49_0_bit|DV_II_55_0_bit)); + if (mask & (DV_I_48_0_bit|DV_II_47_0_bit|DV_II_52_0_bit|DV_II_53_0_bit)) + mask &= (((((W[51]^W[52])>>29)&1)-1) | ~(DV_I_48_0_bit|DV_II_47_0_bit|DV_II_52_0_bit|DV_II_53_0_bit)); + if (mask & (DV_I_46_0_bit|DV_I_49_0_bit|DV_II_45_0_bit|DV_II_48_0_bit)) + mask &= (((((W[36]>>4)^(W[40]>>29))&1)-1) | ~(DV_I_46_0_bit|DV_I_49_0_bit|DV_II_45_0_bit|DV_II_48_0_bit)); + if (mask & (DV_I_52_0_bit|DV_II_48_0_bit|DV_II_49_0_bit)) + mask &= ((0-(((W[53]^W[56])>>29)&1)) | ~(DV_I_52_0_bit|DV_II_48_0_bit|DV_II_49_0_bit)); + if (mask & (DV_I_50_0_bit|DV_II_46_0_bit|DV_II_47_0_bit)) + mask &= ((0-(((W[51]^W[54])>>29)&1)) | ~(DV_I_50_0_bit|DV_II_46_0_bit|DV_II_47_0_bit)); + if (mask & (DV_I_49_0_bit|DV_I_51_0_bit|DV_II_45_0_bit)) + mask &= ((0-(((W[50]^W[52])>>29)&1)) | ~(DV_I_49_0_bit|DV_I_51_0_bit|DV_II_45_0_bit)); + if (mask & (DV_I_48_0_bit|DV_I_50_0_bit|DV_I_52_0_bit)) + mask &= ((0-(((W[49]^W[51])>>29)&1)) | ~(DV_I_48_0_bit|DV_I_50_0_bit|DV_I_52_0_bit)); + if (mask & (DV_I_47_0_bit|DV_I_49_0_bit|DV_I_51_0_bit)) + mask &= ((0-(((W[48]^W[50])>>29)&1)) | ~(DV_I_47_0_bit|DV_I_49_0_bit|DV_I_51_0_bit)); + if (mask & (DV_I_46_0_bit|DV_I_48_0_bit|DV_I_50_0_bit)) + mask &= ((0-(((W[47]^W[49])>>29)&1)) | ~(DV_I_46_0_bit|DV_I_48_0_bit|DV_I_50_0_bit)); + if (mask & (DV_I_45_0_bit|DV_I_47_0_bit|DV_I_49_0_bit)) + mask &= ((0-(((W[46]^W[48])>>29)&1)) | ~(DV_I_45_0_bit|DV_I_47_0_bit|DV_I_49_0_bit)); + mask &= ((((W[45]^W[47])&(1<<6))-(1<<6)) | ~(DV_I_47_2_bit|DV_I_49_2_bit|DV_I_51_2_bit)); + if (mask & (DV_I_44_0_bit|DV_I_46_0_bit|DV_I_48_0_bit)) + mask &= ((0-(((W[45]^W[47])>>29)&1)) | ~(DV_I_44_0_bit|DV_I_46_0_bit|DV_I_48_0_bit)); + mask &= (((((W[44]^W[46])>>6)&1)-1) | ~(DV_I_46_2_bit|DV_I_48_2_bit|DV_I_50_2_bit)); + if (mask & (DV_I_43_0_bit|DV_I_45_0_bit|DV_I_47_0_bit)) + mask &= ((0-(((W[44]^W[46])>>29)&1)) | ~(DV_I_43_0_bit|DV_I_45_0_bit|DV_I_47_0_bit)); + mask &= ((0-((W[41]^(W[42]>>5))&(1<<1))) | ~(DV_I_48_2_bit|DV_II_46_2_bit|DV_II_51_2_bit)); + mask &= ((0-((W[40]^(W[41]>>5))&(1<<1))) | ~(DV_I_47_2_bit|DV_I_51_2_bit|DV_II_50_2_bit)); + if (mask & (DV_I_44_0_bit|DV_I_46_0_bit|DV_II_56_0_bit)) + mask &= ((0-(((W[40]^W[42])>>4)&1)) | ~(DV_I_44_0_bit|DV_I_46_0_bit|DV_II_56_0_bit)); + mask &= ((0-((W[39]^(W[40]>>5))&(1<<1))) | ~(DV_I_46_2_bit|DV_I_50_2_bit|DV_II_49_2_bit)); + if (mask & (DV_I_43_0_bit|DV_I_45_0_bit|DV_II_55_0_bit)) + mask &= ((0-(((W[39]^W[41])>>4)&1)) | ~(DV_I_43_0_bit|DV_I_45_0_bit|DV_II_55_0_bit)); + if (mask & (DV_I_44_0_bit|DV_II_54_0_bit|DV_II_56_0_bit)) + mask &= ((0-(((W[38]^W[40])>>4)&1)) | ~(DV_I_44_0_bit|DV_II_54_0_bit|DV_II_56_0_bit)); + if (mask & (DV_I_43_0_bit|DV_II_53_0_bit|DV_II_55_0_bit)) + mask &= ((0-(((W[37]^W[39])>>4)&1)) | ~(DV_I_43_0_bit|DV_II_53_0_bit|DV_II_55_0_bit)); + mask &= ((0-((W[36]^(W[37]>>5))&(1<<1))) | ~(DV_I_47_2_bit|DV_I_50_2_bit|DV_II_46_2_bit)); + if (mask & (DV_I_45_0_bit|DV_I_48_0_bit|DV_II_47_0_bit)) + mask &= (((((W[35]>>4)^(W[39]>>29))&1)-1) | ~(DV_I_45_0_bit|DV_I_48_0_bit|DV_II_47_0_bit)); + if (mask & (DV_I_48_0_bit|DV_II_48_0_bit)) + mask &= ((0-((W[63]^(W[64]>>5))&(1<<0))) | ~(DV_I_48_0_bit|DV_II_48_0_bit)); + if (mask & (DV_I_45_0_bit|DV_II_45_0_bit)) + mask &= ((0-((W[63]^(W[64]>>5))&(1<<1))) | ~(DV_I_45_0_bit|DV_II_45_0_bit)); + if (mask & (DV_I_47_0_bit|DV_II_47_0_bit)) + mask &= ((0-((W[62]^(W[63]>>5))&(1<<0))) | ~(DV_I_47_0_bit|DV_II_47_0_bit)); + if (mask & (DV_I_46_0_bit|DV_II_46_0_bit)) + mask &= ((0-((W[61]^(W[62]>>5))&(1<<0))) | ~(DV_I_46_0_bit|DV_II_46_0_bit)); + mask &= ((0-((W[61]^(W[62]>>5))&(1<<2))) | ~(DV_I_46_2_bit|DV_II_46_2_bit)); + if (mask & (DV_I_45_0_bit|DV_II_45_0_bit)) + mask &= ((0-((W[60]^(W[61]>>5))&(1<<0))) | ~(DV_I_45_0_bit|DV_II_45_0_bit)); + if (mask & (DV_II_51_0_bit|DV_II_54_0_bit)) + mask &= (((((W[58]^W[59])>>29)&1)-1) | ~(DV_II_51_0_bit|DV_II_54_0_bit)); + if (mask & (DV_II_50_0_bit|DV_II_53_0_bit)) + mask &= (((((W[57]^W[58])>>29)&1)-1) | ~(DV_II_50_0_bit|DV_II_53_0_bit)); + if (mask & (DV_II_52_0_bit|DV_II_54_0_bit)) + mask &= ((((W[56]^(W[59]>>25))&(1<<4))-(1<<4)) | ~(DV_II_52_0_bit|DV_II_54_0_bit)); + if (mask & (DV_II_51_0_bit|DV_II_52_0_bit)) + mask &= ((0-(((W[56]^W[59])>>29)&1)) | ~(DV_II_51_0_bit|DV_II_52_0_bit)); + if (mask & (DV_II_49_0_bit|DV_II_52_0_bit)) + mask &= (((((W[56]^W[57])>>29)&1)-1) | ~(DV_II_49_0_bit|DV_II_52_0_bit)); + if (mask & (DV_II_51_0_bit|DV_II_53_0_bit)) + mask &= ((((W[55]^(W[58]>>25))&(1<<4))-(1<<4)) | ~(DV_II_51_0_bit|DV_II_53_0_bit)); + if (mask & (DV_II_50_0_bit|DV_II_52_0_bit)) + mask &= ((((W[54]^(W[57]>>25))&(1<<4))-(1<<4)) | ~(DV_II_50_0_bit|DV_II_52_0_bit)); + if (mask & (DV_II_49_0_bit|DV_II_51_0_bit)) + mask &= ((((W[53]^(W[56]>>25))&(1<<4))-(1<<4)) | ~(DV_II_49_0_bit|DV_II_51_0_bit)); + mask &= ((((W[51]^(W[50]>>5))&(1<<1))-(1<<1)) | ~(DV_I_50_2_bit|DV_II_46_2_bit)); + mask &= ((((W[48]^W[50])&(1<<6))-(1<<6)) | ~(DV_I_50_2_bit|DV_II_46_2_bit)); + if (mask & (DV_I_51_0_bit|DV_I_52_0_bit)) + mask &= ((0-(((W[48]^W[55])>>29)&1)) | ~(DV_I_51_0_bit|DV_I_52_0_bit)); + mask &= ((((W[47]^W[49])&(1<<6))-(1<<6)) | ~(DV_I_49_2_bit|DV_I_51_2_bit)); + mask &= ((((W[48]^(W[47]>>5))&(1<<1))-(1<<1)) | ~(DV_I_47_2_bit|DV_II_51_2_bit)); + mask &= ((((W[46]^W[48])&(1<<6))-(1<<6)) | ~(DV_I_48_2_bit|DV_I_50_2_bit)); + mask &= ((((W[47]^(W[46]>>5))&(1<<1))-(1<<1)) | ~(DV_I_46_2_bit|DV_II_50_2_bit)); + mask &= ((0-((W[44]^(W[45]>>5))&(1<<1))) | ~(DV_I_51_2_bit|DV_II_49_2_bit)); + mask &= ((((W[43]^W[45])&(1<<6))-(1<<6)) | ~(DV_I_47_2_bit|DV_I_49_2_bit)); + mask &= (((((W[42]^W[44])>>6)&1)-1) | ~(DV_I_46_2_bit|DV_I_48_2_bit)); + mask &= ((((W[43]^(W[42]>>5))&(1<<1))-(1<<1)) | ~(DV_II_46_2_bit|DV_II_51_2_bit)); + mask &= ((((W[42]^(W[41]>>5))&(1<<1))-(1<<1)) | ~(DV_I_51_2_bit|DV_II_50_2_bit)); + mask &= ((((W[41]^(W[40]>>5))&(1<<1))-(1<<1)) | ~(DV_I_50_2_bit|DV_II_49_2_bit)); + if (mask & (DV_I_52_0_bit|DV_II_51_0_bit)) + mask &= ((((W[39]^(W[43]>>25))&(1<<4))-(1<<4)) | ~(DV_I_52_0_bit|DV_II_51_0_bit)); + if (mask & (DV_I_51_0_bit|DV_II_50_0_bit)) + mask &= ((((W[38]^(W[42]>>25))&(1<<4))-(1<<4)) | ~(DV_I_51_0_bit|DV_II_50_0_bit)); + if (mask & (DV_I_48_2_bit|DV_I_51_2_bit)) + mask &= ((0-((W[37]^(W[38]>>5))&(1<<1))) | ~(DV_I_48_2_bit|DV_I_51_2_bit)); + if (mask & (DV_I_50_0_bit|DV_II_49_0_bit)) + mask &= ((((W[37]^(W[41]>>25))&(1<<4))-(1<<4)) | ~(DV_I_50_0_bit|DV_II_49_0_bit)); + if (mask & (DV_II_52_0_bit|DV_II_54_0_bit)) + mask &= ((0-((W[36]^W[38])&(1<<4))) | ~(DV_II_52_0_bit|DV_II_54_0_bit)); + mask &= ((0-((W[35]^(W[36]>>5))&(1<<1))) | ~(DV_I_46_2_bit|DV_I_49_2_bit)); + if (mask & (DV_I_51_0_bit|DV_II_47_0_bit)) + mask &= ((((W[35]^(W[39]>>25))&(1<<3))-(1<<3)) | ~(DV_I_51_0_bit|DV_II_47_0_bit)); +if (mask) { + + if (mask & DV_I_43_0_bit) + if ( + !((W[61]^(W[62]>>5)) & (1<<1)) + || !(!((W[59]^(W[63]>>25)) & (1<<5))) + || !((W[58]^(W[63]>>30)) & (1<<0)) + ) mask &= ~DV_I_43_0_bit; + if (mask & DV_I_44_0_bit) + if ( + !((W[62]^(W[63]>>5)) & (1<<1)) + || !(!((W[60]^(W[64]>>25)) & (1<<5))) + || !((W[59]^(W[64]>>30)) & (1<<0)) + ) mask &= ~DV_I_44_0_bit; + if (mask & DV_I_46_2_bit) + mask &= ((~((W[40]^W[42])>>2)) | ~DV_I_46_2_bit); + if (mask & DV_I_47_2_bit) + if ( + !((W[62]^(W[63]>>5)) & (1<<2)) + || !(!((W[41]^W[43]) & (1<<6))) + ) mask &= ~DV_I_47_2_bit; + if (mask & DV_I_48_2_bit) + if ( + !((W[63]^(W[64]>>5)) & (1<<2)) + || !(!((W[48]^(W[49]<<5)) & (1<<6))) + ) mask &= ~DV_I_48_2_bit; + if (mask & DV_I_49_2_bit) + if ( + !(!((W[49]^(W[50]<<5)) & (1<<6))) + || !((W[42]^W[50]) & (1<<1)) + || !(!((W[39]^(W[40]<<5)) & (1<<6))) + || !((W[38]^W[40]) & (1<<1)) + ) mask &= ~DV_I_49_2_bit; + if (mask & DV_I_50_0_bit) + mask &= ((((W[36]^W[37])<<7)) | ~DV_I_50_0_bit); + if (mask & DV_I_50_2_bit) + mask &= ((((W[43]^W[51])<<11)) | ~DV_I_50_2_bit); + if (mask & DV_I_51_0_bit) + mask &= ((((W[37]^W[38])<<9)) | ~DV_I_51_0_bit); + if (mask & DV_I_51_2_bit) + if ( + !(!((W[51]^(W[52]<<5)) & (1<<6))) + || !(!((W[49]^W[51]) & (1<<6))) + || !(!((W[37]^(W[37]>>5)) & (1<<1))) + || !(!((W[35]^(W[39]>>25)) & (1<<5))) + ) mask &= ~DV_I_51_2_bit; + if (mask & DV_I_52_0_bit) + mask &= ((((W[38]^W[39])<<11)) | ~DV_I_52_0_bit); + if (mask & DV_II_46_2_bit) + mask &= ((((W[47]^W[51])<<17)) | ~DV_II_46_2_bit); + if (mask & DV_II_48_0_bit) + if ( + !(!((W[36]^(W[40]>>25)) & (1<<3))) + || !((W[35]^(W[40]<<2)) & (1<<30)) + ) mask &= ~DV_II_48_0_bit; + if (mask & DV_II_49_0_bit) + if ( + !(!((W[37]^(W[41]>>25)) & (1<<3))) + || !((W[36]^(W[41]<<2)) & (1<<30)) + ) mask &= ~DV_II_49_0_bit; + if (mask & DV_II_49_2_bit) + if ( + !(!((W[53]^(W[54]<<5)) & (1<<6))) + || !(!((W[51]^W[53]) & (1<<6))) + || !((W[50]^W[54]) & (1<<1)) + || !(!((W[45]^(W[46]<<5)) & (1<<6))) + || !(!((W[37]^(W[41]>>25)) & (1<<5))) + || !((W[36]^(W[41]>>30)) & (1<<0)) + ) mask &= ~DV_II_49_2_bit; + if (mask & DV_II_50_0_bit) + if ( + !((W[55]^W[58]) & (1<<29)) + || !(!((W[38]^(W[42]>>25)) & (1<<3))) + || !((W[37]^(W[42]<<2)) & (1<<30)) + ) mask &= ~DV_II_50_0_bit; + if (mask & DV_II_50_2_bit) + if ( + !(!((W[54]^(W[55]<<5)) & (1<<6))) + || !(!((W[52]^W[54]) & (1<<6))) + || !((W[51]^W[55]) & (1<<1)) + || !((W[45]^W[47]) & (1<<1)) + || !(!((W[38]^(W[42]>>25)) & (1<<5))) + || !((W[37]^(W[42]>>30)) & (1<<0)) + ) mask &= ~DV_II_50_2_bit; + if (mask & DV_II_51_0_bit) + if ( + !(!((W[39]^(W[43]>>25)) & (1<<3))) + || !((W[38]^(W[43]<<2)) & (1<<30)) + ) mask &= ~DV_II_51_0_bit; + if (mask & DV_II_51_2_bit) + if ( + !(!((W[55]^(W[56]<<5)) & (1<<6))) + || !(!((W[53]^W[55]) & (1<<6))) + || !((W[52]^W[56]) & (1<<1)) + || !((W[46]^W[48]) & (1<<1)) + || !(!((W[39]^(W[43]>>25)) & (1<<5))) + || !((W[38]^(W[43]>>30)) & (1<<0)) + ) mask &= ~DV_II_51_2_bit; + if (mask & DV_II_52_0_bit) + if ( + !(!((W[59]^W[60]) & (1<<29))) + || !(!((W[40]^(W[44]>>25)) & (1<<3))) + || !(!((W[40]^(W[44]>>25)) & (1<<4))) + || !((W[39]^(W[44]<<2)) & (1<<30)) + ) mask &= ~DV_II_52_0_bit; + if (mask & DV_II_53_0_bit) + if ( + !((W[58]^W[61]) & (1<<29)) + || !(!((W[57]^(W[61]>>25)) & (1<<4))) + || !(!((W[41]^(W[45]>>25)) & (1<<3))) + || !(!((W[41]^(W[45]>>25)) & (1<<4))) + ) mask &= ~DV_II_53_0_bit; + if (mask & DV_II_54_0_bit) + if ( + !(!((W[58]^(W[62]>>25)) & (1<<4))) + || !(!((W[42]^(W[46]>>25)) & (1<<3))) + || !(!((W[42]^(W[46]>>25)) & (1<<4))) + ) mask &= ~DV_II_54_0_bit; + if (mask & DV_II_55_0_bit) + if ( + !(!((W[59]^(W[63]>>25)) & (1<<4))) + || !(!((W[57]^(W[59]>>25)) & (1<<4))) + || !(!((W[43]^(W[47]>>25)) & (1<<3))) + || !(!((W[43]^(W[47]>>25)) & (1<<4))) + ) mask &= ~DV_II_55_0_bit; + if (mask & DV_II_56_0_bit) + if ( + !(!((W[60]^(W[64]>>25)) & (1<<4))) + || !(!((W[44]^(W[48]>>25)) & (1<<3))) + || !(!((W[44]^(W[48]>>25)) & (1<<4))) + ) mask &= ~DV_II_56_0_bit; +} + + dvmask[0]=mask; +} diff --git a/sha1dc/ubc_check.h b/sha1dc/ubc_check.h new file mode 100644 index 0000000000..b64c306d77 --- /dev/null +++ b/sha1dc/ubc_check.h @@ -0,0 +1,44 @@ +/*** +* Copyright 2017 Marc Stevens <marc@marc-stevens.nl>, Dan Shumow <danshu@microsoft.com> +* Distributed under the MIT Software License. +* See accompanying file LICENSE.txt or copy at +* https://opensource.org/licenses/MIT +***/ + +/* +// this file was generated by the 'parse_bitrel' program in the tools section +// using the data files from directory 'tools/data/3565' +// +// sha1_dvs contains a list of SHA-1 Disturbance Vectors (DV) to check +// dvType, dvK and dvB define the DV: I(K,B) or II(K,B) (see the paper) +// dm[80] is the expanded message block XOR-difference defined by the DV +// testt is the step to do the recompression from for collision detection +// maski and maskb define the bit to check for each DV in the dvmask returned by ubc_check +// +// ubc_check takes as input an expanded message block and verifies the unavoidable bitconditions for all listed DVs +// it returns a dvmask where each bit belonging to a DV is set if all unavoidable bitconditions for that DV have been met +// thus one needs to do the recompression check for each DV that has its bit set +*/ + +#ifndef UBC_CHECK_H +#define UBC_CHECK_H + +#if defined(__cplusplus) +extern "C" { +#endif + +#define DVMASKSIZE 1 +typedef struct { int dvType; int dvK; int dvB; int testt; int maski; int maskb; uint32_t dm[80]; } dv_info_t; +extern dv_info_t sha1_dvs[]; +void ubc_check(const uint32_t W[80], uint32_t dvmask[DVMASKSIZE]); + +#define DOSTORESTATE58 +#define DOSTORESTATE65 + +#define CHECK_DVMASK(_DVMASK) (0 != _DVMASK[0]) + +#if defined(__cplusplus) +} +#endif + +#endif /* UBC_CHECK_H */ @@ -260,7 +260,7 @@ static int write_one_shallow(const struct commit_graft *graft, void *cb_data) } static int write_shallow_commits_1(struct strbuf *out, int use_pack_protocol, - const struct sha1_array *extra, + const struct oid_array *extra, unsigned flags) { struct write_shallow_data data; @@ -273,7 +273,7 @@ static int write_shallow_commits_1(struct strbuf *out, int use_pack_protocol, if (!extra) return data.count; for (i = 0; i < extra->nr; i++) { - strbuf_addstr(out, sha1_to_hex(extra->sha1[i])); + strbuf_addstr(out, oid_to_hex(extra->oid + i)); strbuf_addch(out, '\n'); data.count++; } @@ -281,14 +281,14 @@ static int write_shallow_commits_1(struct strbuf *out, int use_pack_protocol, } int write_shallow_commits(struct strbuf *out, int use_pack_protocol, - const struct sha1_array *extra) + const struct oid_array *extra) { return write_shallow_commits_1(out, use_pack_protocol, extra, 0); } static struct tempfile temporary_shallow; -const char *setup_temporary_shallow(const struct sha1_array *extra) +const char *setup_temporary_shallow(const struct oid_array *extra) { struct strbuf sb = STRBUF_INIT; int fd; @@ -312,7 +312,7 @@ const char *setup_temporary_shallow(const struct sha1_array *extra) void setup_alternate_shallow(struct lock_file *shallow_lock, const char **alternate_shallow_file, - const struct sha1_array *extra) + const struct oid_array *extra) { struct strbuf sb = STRBUF_INIT; int fd; @@ -385,7 +385,7 @@ struct trace_key trace_shallow = TRACE_KEY_INIT(SHALLOW); * Step 1, split sender shallow commits into "ours" and "theirs" * Step 2, clean "ours" based on .git/shallow */ -void prepare_shallow_info(struct shallow_info *info, struct sha1_array *sa) +void prepare_shallow_info(struct shallow_info *info, struct oid_array *sa) { int i; trace_printf_key(&trace_shallow, "shallow: prepare_shallow_info\n"); @@ -396,9 +396,9 @@ void prepare_shallow_info(struct shallow_info *info, struct sha1_array *sa) ALLOC_ARRAY(info->ours, sa->nr); ALLOC_ARRAY(info->theirs, sa->nr); for (i = 0; i < sa->nr; i++) { - if (has_sha1_file(sa->sha1[i])) { + if (has_object_file(sa->oid + i)) { struct commit_graft *graft; - graft = lookup_commit_graft(sa->sha1[i]); + graft = lookup_commit_graft(sa->oid[i].hash); if (graft && graft->nr_parent < 0) continue; info->ours[info->nr_ours++] = i; @@ -417,13 +417,13 @@ void clear_shallow_info(struct shallow_info *info) void remove_nonexistent_theirs_shallow(struct shallow_info *info) { - unsigned char (*sha1)[20] = info->shallow->sha1; + struct object_id *oid = info->shallow->oid; int i, dst; trace_printf_key(&trace_shallow, "shallow: remove_nonexistent_theirs_shallow\n"); for (i = dst = 0; i < info->nr_theirs; i++) { if (i != dst) info->theirs[dst] = info->theirs[i]; - if (has_sha1_file(sha1[info->theirs[i]])) + if (has_object_file(oid + info->theirs[i])) dst++; } info->nr_theirs = dst; @@ -559,8 +559,8 @@ static void post_assign_shallow(struct shallow_info *info, void assign_shallow_commits_to_refs(struct shallow_info *info, uint32_t **used, int *ref_status) { - unsigned char (*sha1)[20] = info->shallow->sha1; - struct sha1_array *ref = info->ref; + struct object_id *oid = info->shallow->oid; + struct oid_array *ref = info->ref; unsigned int i, nr; int *shallow, nr_shallow = 0; struct paint_info pi; @@ -599,18 +599,18 @@ void assign_shallow_commits_to_refs(struct shallow_info *info, /* Mark potential bottoms so we won't go out of bound */ for (i = 0; i < nr_shallow; i++) { - struct commit *c = lookup_commit(sha1[shallow[i]]); + struct commit *c = lookup_commit(oid[shallow[i]].hash); c->object.flags |= BOTTOM; } for (i = 0; i < ref->nr; i++) - paint_down(&pi, ref->sha1[i], i); + paint_down(&pi, ref->oid[i].hash, i); if (used) { int bitmap_size = ((pi.nr_bits + 31) / 32) * sizeof(uint32_t); memset(used, 0, sizeof(*used) * info->shallow->nr); for (i = 0; i < nr_shallow; i++) { - const struct commit *c = lookup_commit(sha1[shallow[i]]); + const struct commit *c = lookup_commit(oid[shallow[i]].hash); uint32_t **map = ref_bitmap_at(&pi.ref_bitmap, c); if (*map) used[shallow[i]] = xmemdupz(*map, bitmap_size); @@ -664,7 +664,7 @@ static void post_assign_shallow(struct shallow_info *info, struct ref_bitmap *ref_bitmap, int *ref_status) { - unsigned char (*sha1)[20] = info->shallow->sha1; + struct object_id *oid = info->shallow->oid; struct commit *c; uint32_t **bitmap; int dst, i, j; @@ -679,7 +679,7 @@ static void post_assign_shallow(struct shallow_info *info, for (i = dst = 0; i < info->nr_theirs; i++) { if (i != dst) info->theirs[dst] = info->theirs[i]; - c = lookup_commit(sha1[info->theirs[i]]); + c = lookup_commit(oid[info->theirs[i]].hash); bitmap = ref_bitmap_at(ref_bitmap, c); if (!*bitmap) continue; @@ -700,7 +700,7 @@ static void post_assign_shallow(struct shallow_info *info, for (i = dst = 0; i < info->nr_ours; i++) { if (i != dst) info->ours[dst] = info->ours[i]; - c = lookup_commit(sha1[info->ours[i]]); + c = lookup_commit(oid[info->ours[i]].hash); bitmap = ref_bitmap_at(ref_bitmap, c); if (!*bitmap) continue; @@ -722,7 +722,7 @@ static void post_assign_shallow(struct shallow_info *info, int delayed_reachability_test(struct shallow_info *si, int c) { if (si->need_reachability_test[c]) { - struct commit *commit = lookup_commit(si->shallow->sha1[c]); + struct commit *commit = lookup_commit(si->shallow->oid[c].hash); if (!si->commits) { struct commit_array ca; @@ -449,6 +449,17 @@ int strbuf_getcwd(struct strbuf *sb) strbuf_setlen(sb, strlen(sb->buf)); return 0; } + + /* + * If getcwd(3) is implemented as a syscall that falls + * back to a regular lookup using readdir(3) etc. then + * we may be able to avoid EACCES by providing enough + * space to the syscall as it's not necessarily bound + * to the same restrictions as the fallback. + */ + if (errno == EACCES && guessed_len < PATH_MAX) + continue; + if (errno != ERANGE) break; } diff --git a/submodule-config.c b/submodule-config.c index 93453909cf..4f58491ddb 100644 --- a/submodule-config.c +++ b/submodule-config.c @@ -234,6 +234,26 @@ int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg) return parse_fetch_recurse(opt, arg, 1); } +static int parse_update_recurse(const char *opt, const char *arg, + int die_on_error) +{ + switch (git_config_maybe_bool(opt, arg)) { + case 1: + return RECURSE_SUBMODULES_ON; + case 0: + return RECURSE_SUBMODULES_OFF; + default: + if (die_on_error) + die("bad %s argument: %s", opt, arg); + return RECURSE_SUBMODULES_ERROR; + } +} + +int parse_update_recurse_submodules_arg(const char *opt, const char *arg) +{ + return parse_update_recurse(opt, arg, 1); +} + static int parse_push_recurse(const char *opt, const char *arg, int die_on_error) { @@ -333,7 +353,7 @@ static int parse_config(const char *var, const char *value, void *data) strcmp(value, "all") && strcmp(value, "none")) warning("Invalid parameter '%s' for config option " - "'submodule.%s.ignore'", value, var); + "'submodule.%s.ignore'", value, name.buf); else { free((void *) submodule->ignore); submodule->ignore = xstrdup(value); diff --git a/submodule-config.h b/submodule-config.h index 70f19363fd..d434ecdb45 100644 --- a/submodule-config.h +++ b/submodule-config.h @@ -22,16 +22,17 @@ struct submodule { int recommend_shallow; }; -int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg); -int parse_push_recurse_submodules_arg(const char *opt, const char *arg); -int parse_submodule_config_option(const char *var, const char *value); -const struct submodule *submodule_from_name(const unsigned char *commit_or_tree, - const char *name); -const struct submodule *submodule_from_path(const unsigned char *commit_or_tree, - const char *path); +extern int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg); +extern int parse_update_recurse_submodules_arg(const char *opt, const char *arg); +extern int parse_push_recurse_submodules_arg(const char *opt, const char *arg); +extern int parse_submodule_config_option(const char *var, const char *value); +extern const struct submodule *submodule_from_name( + const unsigned char *commit_or_tree, const char *name); +extern const struct submodule *submodule_from_path( + const unsigned char *commit_or_tree, const char *path); extern int gitmodule_sha1_from_commit(const unsigned char *commit_sha1, unsigned char *gitmodules_sha1, struct strbuf *rev); -void submodule_free(void); +extern void submodule_free(void); #endif /* SUBMODULE_CONFIG_H */ diff --git a/submodule.c b/submodule.c index a31f68812c..5615d7392e 100644 --- a/submodule.c +++ b/submodule.c @@ -14,14 +14,16 @@ #include "blob.h" #include "thread-utils.h" #include "quote.h" +#include "remote.h" #include "worktree.h" static int config_fetch_recurse_submodules = RECURSE_SUBMODULES_ON_DEMAND; +static int config_update_recurse_submodules = RECURSE_SUBMODULES_DEFAULT; static int parallel_jobs = 1; static struct string_list changed_submodule_paths = STRING_LIST_INIT_NODUP; static int initialized_fetch_ref_tips; -static struct sha1_array ref_tips_before_fetch; -static struct sha1_array ref_tips_after_fetch; +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 @@ -212,37 +214,68 @@ void gitmodules_config_sha1(const unsigned char *commit_sha1) } /* + * NEEDSWORK: With the addition of different configuration options to determine + * if a submodule is of interests, the validity of this function's name comes + * into question. Once the dust has settled and more concrete terminology is + * decided upon, come up with a more proper name for this function. One + * potential candidate could be 'is_submodule_active()'. + * * Determine if a submodule has been initialized at a given 'path' */ int is_submodule_initialized(const char *path) { int ret = 0; - const struct submodule *module = NULL; + char *key = NULL; + char *value = NULL; + const struct string_list *sl; + const struct submodule *module = submodule_from_path(null_sha1, path); - module = submodule_from_path(null_sha1, path); + /* early return if there isn't a path->module mapping */ + if (!module) + return 0; - if (module) { - char *key = xstrfmt("submodule.%s.url", module->name); - char *value = NULL; + /* submodule.<name>.active is set */ + key = xstrfmt("submodule.%s.active", module->name); + if (!git_config_get_bool(key, &ret)) { + free(key); + return ret; + } + free(key); - ret = !git_config_get_string(key, &value); + /* submodule.active is set */ + sl = git_config_get_value_multi("submodule.active"); + if (sl) { + struct pathspec ps; + struct argv_array args = ARGV_ARRAY_INIT; + const struct string_list_item *item; - free(value); - free(key); + for_each_string_list_item(item, sl) { + argv_array_push(&args, item->string); + } + + parse_pathspec(&ps, 0, 0, NULL, args.argv); + ret = match_pathspec(&ps, path, strlen(path), 0, NULL, 1); + + argv_array_clear(&args); + clear_pathspec(&ps); + return ret; } + /* fallback to checking if the URL is set */ + key = xstrfmt("submodule.%s.url", module->name); + ret = !git_config_get_string(key, &value); + + free(value); + free(key); return ret; } -/* - * Determine if a submodule has been populated at a given 'path' - */ -int is_submodule_populated(const char *path) +int is_submodule_populated_gently(const char *path, int *return_error_code) { int ret = 0; char *gitdir = xstrfmt("%s/.git", path); - if (resolve_gitdir(gitdir)) + if (resolve_gitdir_gently(gitdir, return_error_code)) ret = 1; free(gitdir); @@ -358,6 +391,23 @@ static void print_submodule_summary(struct rev_info *rev, FILE *f, strbuf_release(&sb); } +static void prepare_submodule_repo_env_no_git_dir(struct argv_array *out) +{ + const char * const *var; + + for (var = local_repo_env; *var; var++) { + if (strcmp(*var, CONFIG_DATA_ENVIRONMENT)) + argv_array_push(out, *var); + } +} + +void prepare_submodule_repo_env(struct argv_array *out) +{ + prepare_submodule_repo_env_no_git_dir(out); + argv_array_pushf(out, "%s=%s", GIT_DIR_ENVIRONMENT, + DEFAULT_GIT_DIR_ENVIRONMENT); +} + /* Helper function to display the submodule header line prior to the full * summary output. If it can locate the submodule objects directory it will * attempt to lookup both the left and right commits and put them into the @@ -527,6 +577,7 @@ void show_submodule_inline_diff(FILE *f, const char *path, if (!(dirty_submodule & DIRTY_SUBMODULE_MODIFIED)) argv_array_push(&cp.args, oid_to_hex(new)); + prepare_submodule_repo_env(&cp.env_array); if (run_command(&cp)) fprintf(f, "(diff failed)\n"); @@ -545,41 +596,62 @@ void set_config_fetch_recurse_submodules(int value) config_fetch_recurse_submodules = value; } +void set_config_update_recurse_submodules(int value) +{ + config_update_recurse_submodules = value; +} + +int should_update_submodules(void) +{ + return config_update_recurse_submodules == RECURSE_SUBMODULES_ON; +} + +const struct submodule *submodule_from_ce(const struct cache_entry *ce) +{ + if (!S_ISGITLINK(ce->ce_mode)) + return NULL; + + if (!should_update_submodules()) + return NULL; + + return submodule_from_path(null_sha1, ce->name); +} + static int has_remote(const char *refname, const struct object_id *oid, int flags, void *cb_data) { return 1; } -static int append_sha1_to_argv(const unsigned char sha1[20], void *data) +static int append_oid_to_argv(const struct object_id *oid, void *data) { struct argv_array *argv = data; - argv_array_push(argv, sha1_to_hex(sha1)); + argv_array_push(argv, oid_to_hex(oid)); return 0; } -static int check_has_commit(const unsigned char sha1[20], void *data) +static int check_has_commit(const struct object_id *oid, void *data) { int *has_commit = data; - if (!lookup_commit_reference(sha1)) + if (!lookup_commit_reference(oid->hash)) *has_commit = 0; return 0; } -static int submodule_has_commits(const char *path, struct sha1_array *commits) +static int submodule_has_commits(const char *path, struct oid_array *commits) { int has_commit = 1; if (add_submodule_odb(path)) return 0; - sha1_array_for_each_unique(commits, check_has_commit, &has_commit); + oid_array_for_each_unique(commits, check_has_commit, &has_commit); return has_commit; } -static int submodule_needs_pushing(const char *path, struct sha1_array *commits) +static int submodule_needs_pushing(const char *path, struct oid_array *commits) { if (!submodule_has_commits(path, commits)) /* @@ -601,7 +673,7 @@ static int submodule_needs_pushing(const char *path, struct sha1_array *commits) int needs_pushing = 0; argv_array_push(&cp.args, "rev-list"); - sha1_array_for_each_unique(commits, append_sha1_to_argv, &cp.args); + oid_array_for_each_unique(commits, append_oid_to_argv, &cp.args); argv_array_pushl(&cp.args, "--not", "--remotes", "-n", "1" , NULL); prepare_submodule_repo_env(&cp.env_array); @@ -623,18 +695,18 @@ static int submodule_needs_pushing(const char *path, struct sha1_array *commits) return 0; } -static struct sha1_array *submodule_commits(struct string_list *submodules, +static struct oid_array *submodule_commits(struct string_list *submodules, const char *path) { struct string_list_item *item; item = string_list_insert(submodules, path); if (item->util) - return (struct sha1_array *) item->util; + return (struct oid_array *) item->util; - /* NEEDSWORK: should we have sha1_array_init()? */ - item->util = xcalloc(1, sizeof(struct sha1_array)); - return (struct sha1_array *) item->util; + /* NEEDSWORK: should we have oid_array_init()? */ + item->util = xcalloc(1, sizeof(struct oid_array)); + return (struct oid_array *) item->util; } static void collect_submodules_from_diff(struct diff_queue_struct *q, @@ -646,11 +718,11 @@ static void collect_submodules_from_diff(struct diff_queue_struct *q, for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; - struct sha1_array *commits; + struct oid_array *commits; if (!S_ISGITLINK(p->two->mode)) continue; commits = submodule_commits(submodules, p->two->path); - sha1_array_append(commits, p->two->oid.hash); + oid_array_append(commits, &p->two->oid); } } @@ -670,11 +742,11 @@ static void free_submodules_sha1s(struct string_list *submodules) { struct string_list_item *item; for_each_string_list_item(item, submodules) - sha1_array_clear((struct sha1_array *) item->util); + oid_array_clear((struct oid_array *) item->util); string_list_clear(submodules, 1); } -int find_unpushed_submodules(struct sha1_array *commits, +int find_unpushed_submodules(struct oid_array *commits, const char *remotes_name, struct string_list *needs_pushing) { struct rev_info rev; @@ -687,7 +759,7 @@ int find_unpushed_submodules(struct sha1_array *commits, /* argv.argv[0] will be ignored by setup_revisions */ argv_array_push(&argv, "find_unpushed_submodules"); - sha1_array_for_each_unique(commits, append_sha1_to_argv, &argv); + oid_array_for_each_unique(commits, append_oid_to_argv, &argv); argv_array_push(&argv, "--not"); argv_array_pushf(&argv, "--remotes=%s", remotes_name); @@ -702,7 +774,7 @@ int find_unpushed_submodules(struct sha1_array *commits, argv_array_clear(&argv); for_each_string_list_item(submodule, &submodules) { - struct sha1_array *commits = (struct sha1_array *) submodule->util; + struct oid_array *commits = (struct oid_array *) submodule->util; if (submodule_needs_pushing(submodule->string, commits)) string_list_insert(needs_pushing, submodule->string); @@ -712,7 +784,11 @@ int find_unpushed_submodules(struct sha1_array *commits, return needs_pushing->nr; } -static int push_submodule(const char *path, int dry_run) +static int push_submodule(const char *path, + const struct remote *remote, + const char **refspec, int refspec_nr, + const struct string_list *push_options, + int dry_run) { if (add_submodule_odb(path)) return 1; @@ -723,6 +799,20 @@ static int push_submodule(const char *path, int dry_run) if (dry_run) argv_array_push(&cp.args, "--dry-run"); + if (push_options && push_options->nr) { + const struct string_list_item *item; + for_each_string_list_item(item, push_options) + argv_array_pushf(&cp.args, "--push-option=%s", + item->string); + } + + if (remote->origin != REMOTE_UNCONFIGURED) { + int i; + argv_array_push(&cp.args, remote->name); + for (i = 0; i < refspec_nr; i++) + argv_array_push(&cp.args, refspec[i]); + } + prepare_submodule_repo_env(&cp.env_array); cp.git_cmd = 1; cp.no_stdin = 1; @@ -735,20 +825,67 @@ static int push_submodule(const char *path, int dry_run) return 1; } -int push_unpushed_submodules(struct sha1_array *commits, - const char *remotes_name, +/* + * 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, + const char **refspec, int refspec_nr) +{ + struct child_process cp = CHILD_PROCESS_INIT; + int i; + + argv_array_push(&cp.args, "submodule--helper"); + argv_array_push(&cp.args, "push-check"); + argv_array_push(&cp.args, remote->name); + + for (i = 0; i < refspec_nr; i++) + argv_array_push(&cp.args, refspec[i]); + + prepare_submodule_repo_env(&cp.env_array); + cp.git_cmd = 1; + cp.no_stdin = 1; + cp.no_stdout = 1; + cp.dir = path; + + /* + * Simply indicate if 'submodule--helper push-check' failed. + * More detailed error information will be provided by the + * child process. + */ + if (run_command(&cp)) + die("process for submodule '%s' failed", path); +} + +int push_unpushed_submodules(struct oid_array *commits, + const struct remote *remote, + const char **refspec, int refspec_nr, + const struct string_list *push_options, int dry_run) { int i, ret = 1; struct string_list needs_pushing = STRING_LIST_INIT_DUP; - if (!find_unpushed_submodules(commits, remotes_name, &needs_pushing)) + if (!find_unpushed_submodules(commits, remote->name, &needs_pushing)) return 1; + /* + * Verify that the remote and refspec can be propagated to all + * submodules. This check can be skipped if the remote and refspec + * won't be propagated due to the remote being unconfigured (e.g. a URL + * instead of a remote name). + */ + if (remote->origin != REMOTE_UNCONFIGURED) + for (i = 0; i < needs_pushing.nr; i++) + submodule_push_check(needs_pushing.items[i].string, + remote, refspec, refspec_nr); + + /* Actually push the submodules */ for (i = 0; i < needs_pushing.nr; i++) { const char *path = needs_pushing.items[i].string; fprintf(stderr, "Pushing submodule '%s'\n", path); - if (!push_submodule(path, dry_run)) { + if (!push_submodule(path, remote, refspec, refspec_nr, + push_options, dry_run)) { fprintf(stderr, "Unable to push submodule '%s'\n", path); ret = 0; } @@ -817,23 +954,23 @@ static void submodule_collect_changed_cb(struct diff_queue_struct *q, static int add_sha1_to_array(const char *ref, const struct object_id *oid, int flags, void *data) { - sha1_array_append(data, oid->hash); + oid_array_append(data, oid); return 0; } -void check_for_new_submodule_commits(unsigned char new_sha1[20]) +void check_for_new_submodule_commits(struct object_id *oid) { if (!initialized_fetch_ref_tips) { for_each_ref(add_sha1_to_array, &ref_tips_before_fetch); initialized_fetch_ref_tips = 1; } - sha1_array_append(&ref_tips_after_fetch, new_sha1); + oid_array_append(&ref_tips_after_fetch, oid); } -static int add_sha1_to_argv(const unsigned char sha1[20], void *data) +static int add_oid_to_argv(const struct object_id *oid, void *data) { - argv_array_push(data, sha1_to_hex(sha1)); + argv_array_push(data, oid_to_hex(oid)); return 0; } @@ -849,11 +986,11 @@ static void calculate_changed_submodule_paths(void) init_revisions(&rev, NULL); argv_array_push(&argv, "--"); /* argv[0] program name */ - sha1_array_for_each_unique(&ref_tips_after_fetch, - add_sha1_to_argv, &argv); + oid_array_for_each_unique(&ref_tips_after_fetch, + add_oid_to_argv, &argv); argv_array_push(&argv, "--not"); - sha1_array_for_each_unique(&ref_tips_before_fetch, - add_sha1_to_argv, &argv); + oid_array_for_each_unique(&ref_tips_before_fetch, + add_oid_to_argv, &argv); setup_revisions(argv.argc, argv.argv, &rev, NULL); if (prepare_revision_walk(&rev)) die("revision walk setup failed"); @@ -879,8 +1016,8 @@ static void calculate_changed_submodule_paths(void) } argv_array_clear(&argv); - sha1_array_clear(&ref_tips_before_fetch); - sha1_array_clear(&ref_tips_after_fetch); + oid_array_clear(&ref_tips_before_fetch); + oid_array_clear(&ref_tips_after_fetch); initialized_fetch_ref_tips = 0; } @@ -1041,67 +1178,78 @@ out: unsigned is_submodule_modified(const char *path, int ignore_untracked) { - ssize_t len; struct child_process cp = CHILD_PROCESS_INIT; - const char *argv[] = { - "status", - "--porcelain", - NULL, - NULL, - }; struct strbuf buf = STRBUF_INIT; + FILE *fp; unsigned dirty_submodule = 0; - const char *line, *next_line; const char *git_dir; + int ignore_cp_exit_code = 0; strbuf_addf(&buf, "%s/.git", path); git_dir = read_gitfile(buf.buf); if (!git_dir) git_dir = buf.buf; - if (!is_directory(git_dir)) { + if (!is_git_directory(git_dir)) { + if (is_directory(git_dir)) + die(_("'%s' not recognized as a git repository"), git_dir); strbuf_release(&buf); /* The submodule is not checked out, so it is not modified */ return 0; - } strbuf_reset(&buf); + argv_array_pushl(&cp.args, "status", "--porcelain=2", NULL); if (ignore_untracked) - argv[2] = "-uno"; + argv_array_push(&cp.args, "-uno"); - cp.argv = argv; prepare_submodule_repo_env(&cp.env_array); cp.git_cmd = 1; cp.no_stdin = 1; cp.out = -1; cp.dir = path; if (start_command(&cp)) - die("Could not run 'git status --porcelain' in submodule %s", path); + die("Could not run 'git status --porcelain=2' in submodule %s", path); - len = strbuf_read(&buf, cp.out, 1024); - line = buf.buf; - while (len > 2) { - if ((line[0] == '?') && (line[1] == '?')) { + fp = xfdopen(cp.out, "r"); + while (strbuf_getwholeline(&buf, fp, '\n') != EOF) { + /* regular untracked files */ + if (buf.buf[0] == '?') dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED; - if (dirty_submodule & DIRTY_SUBMODULE_MODIFIED) - break; - } else { - dirty_submodule |= DIRTY_SUBMODULE_MODIFIED; - if (ignore_untracked || - (dirty_submodule & DIRTY_SUBMODULE_UNTRACKED)) - break; + + if (buf.buf[0] == 'u' || + buf.buf[0] == '1' || + buf.buf[0] == '2') { + /* T = line type, XY = status, SSSS = submodule state */ + if (buf.len < strlen("T XY SSSS")) + die("BUG: invalid status --porcelain=2 line %s", + buf.buf); + + if (buf.buf[5] == 'S' && buf.buf[8] == 'U') + /* nested untracked file */ + dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED; + + if (buf.buf[0] == 'u' || + buf.buf[0] == '2' || + memcmp(buf.buf + 5, "S..U", 4)) + /* other change */ + dirty_submodule |= DIRTY_SUBMODULE_MODIFIED; } - next_line = strchr(line, '\n'); - if (!next_line) + + if ((dirty_submodule & DIRTY_SUBMODULE_MODIFIED) && + ((dirty_submodule & DIRTY_SUBMODULE_UNTRACKED) || + ignore_untracked)) { + /* + * We're not interested in any further information from + * the child any more, neither output nor its exit code. + */ + ignore_cp_exit_code = 1; break; - next_line++; - len -= (next_line - line); - line = next_line; + } } - close(cp.out); + fclose(fp); - if (finish_command(&cp)) - die("'git status --porcelain' failed in submodule %s", path); + if (finish_command(&cp) && !ignore_cp_exit_code) + die("'git status --porcelain=2' failed in submodule %s", path); strbuf_release(&buf); return dirty_submodule; @@ -1181,7 +1329,7 @@ int bad_to_remove_submodule(const char *path, unsigned flags) cp.dir = path; if (start_command(&cp)) { if (flags & SUBMODULE_REMOVAL_DIE_ON_ERROR) - die(_("could not start 'git status in submodule '%s'"), + die(_("could not start 'git status' in submodule '%s'"), path); ret = -1; goto out; @@ -1194,7 +1342,7 @@ int bad_to_remove_submodule(const char *path, unsigned flags) if (finish_command(&cp)) { if (flags & SUBMODULE_REMOVAL_DIE_ON_ERROR) - die(_("could not run 'git status in submodule '%s'"), + die(_("could not run 'git status' in submodule '%s'"), path); ret = -1; } @@ -1203,6 +1351,151 @@ out: return ret; } +static const char *get_super_prefix_or_empty(void) +{ + const char *s = get_super_prefix(); + if (!s) + s = ""; + return s; +} + +static int submodule_has_dirty_index(const struct submodule *sub) +{ + struct child_process cp = CHILD_PROCESS_INIT; + + prepare_submodule_repo_env_no_git_dir(&cp.env_array); + + cp.git_cmd = 1; + argv_array_pushl(&cp.args, "diff-index", "--quiet", + "--cached", "HEAD", NULL); + cp.no_stdin = 1; + cp.no_stdout = 1; + cp.dir = sub->path; + if (start_command(&cp)) + die("could not recurse into submodule '%s'", sub->path); + + return finish_command(&cp); +} + +static void submodule_reset_index(const char *path) +{ + struct child_process cp = CHILD_PROCESS_INIT; + prepare_submodule_repo_env_no_git_dir(&cp.env_array); + + cp.git_cmd = 1; + cp.no_stdin = 1; + cp.dir = path; + + argv_array_pushf(&cp.args, "--super-prefix=%s%s/", + get_super_prefix_or_empty(), path); + argv_array_pushl(&cp.args, "read-tree", "-u", "--reset", NULL); + + argv_array_push(&cp.args, EMPTY_TREE_SHA1_HEX); + + if (run_command(&cp)) + die("could not reset submodule index"); +} + +/** + * Moves a submodule at a given path from a given head to another new head. + * For edge cases (a submodule coming into existence or removing a submodule) + * pass NULL for old or new respectively. + */ +int submodule_move_head(const char *path, + const char *old, + const char *new, + unsigned flags) +{ + int ret = 0; + struct child_process cp = CHILD_PROCESS_INIT; + const struct submodule *sub; + + sub = submodule_from_path(null_sha1, path); + + if (!sub) + die("BUG: could not get submodule information for '%s'", path); + + if (old && !(flags & SUBMODULE_MOVE_HEAD_FORCE)) { + /* Check if the submodule has a dirty index. */ + if (submodule_has_dirty_index(sub)) + return error(_("submodule '%s' has dirty index"), path); + } + + if (!(flags & SUBMODULE_MOVE_HEAD_DRY_RUN)) { + if (old) { + if (!submodule_uses_gitfile(path)) + absorb_git_dir_into_superproject("", path, + ABSORB_GITDIR_RECURSE_SUBMODULES); + } else { + struct strbuf sb = STRBUF_INIT; + strbuf_addf(&sb, "%s/modules/%s", + get_git_common_dir(), sub->name); + connect_work_tree_and_git_dir(path, sb.buf); + strbuf_release(&sb); + + /* make sure the index is clean as well */ + submodule_reset_index(path); + } + } + + prepare_submodule_repo_env_no_git_dir(&cp.env_array); + + cp.git_cmd = 1; + cp.no_stdin = 1; + cp.dir = path; + + argv_array_pushf(&cp.args, "--super-prefix=%s%s/", + get_super_prefix_or_empty(), path); + argv_array_pushl(&cp.args, "read-tree", NULL); + + if (flags & SUBMODULE_MOVE_HEAD_DRY_RUN) + argv_array_push(&cp.args, "-n"); + else + argv_array_push(&cp.args, "-u"); + + if (flags & SUBMODULE_MOVE_HEAD_FORCE) + argv_array_push(&cp.args, "--reset"); + else + argv_array_push(&cp.args, "-m"); + + argv_array_push(&cp.args, old ? old : EMPTY_TREE_SHA1_HEX); + argv_array_push(&cp.args, new ? new : EMPTY_TREE_SHA1_HEX); + + if (run_command(&cp)) { + ret = -1; + goto out; + } + + if (!(flags & SUBMODULE_MOVE_HEAD_DRY_RUN)) { + if (new) { + struct child_process cp1 = CHILD_PROCESS_INIT; + /* also set the HEAD accordingly */ + cp1.git_cmd = 1; + cp1.no_stdin = 1; + cp1.dir = path; + + argv_array_pushl(&cp1.args, "update-ref", "HEAD", + new ? new : EMPTY_TREE_SHA1_HEX, NULL); + + if (run_command(&cp1)) { + ret = -1; + goto out; + } + } else { + struct strbuf sb = STRBUF_INIT; + + strbuf_addf(&sb, "%s/.git", path); + unlink_or_warn(sb.buf); + strbuf_release(&sb); + + if (is_empty_dir(path)) + rmdir_or_warn(path); + } + } +out: + return ret; +} + static int find_first_merges(struct object_array *result, const char *path, struct commit *a, struct commit *b) { @@ -1221,7 +1514,7 @@ static int find_first_merges(struct object_array *result, const char *path, memset(&rev_opts, 0, sizeof(rev_opts)); /* get all revisions that merge commit a */ - snprintf(merged_revision, sizeof(merged_revision), "^%s", + xsnprintf(merged_revision, sizeof(merged_revision), "^%s", oid_to_hex(&a->object.oid)); init_revisions(&revs, NULL); rev_opts.submodule = path; @@ -1371,18 +1664,6 @@ int parallel_submodules(void) return parallel_jobs; } -void prepare_submodule_repo_env(struct argv_array *out) -{ - const char * const *var; - - for (var = local_repo_env; *var; var++) { - if (strcmp(*var, CONFIG_DATA_ENVIRONMENT)) - argv_array_push(out, *var); - } - argv_array_pushf(out, "%s=%s", GIT_DIR_ENVIRONMENT, - DEFAULT_GIT_DIR_ENVIRONMENT); -} - /* * Embeds a single submodules git directory into the superprojects git dir, * non recursively. @@ -1414,11 +1695,8 @@ static void relocate_single_git_dir_into_superproject(const char *prefix, die(_("could not create directory '%s'"), new_git_dir); real_new_git_dir = real_pathdup(new_git_dir, 1); - if (!prefix) - prefix = get_super_prefix(); - fprintf(stderr, _("Migrating git directory of '%s%s' from\n'%s' to\n'%s'\n"), - prefix ? prefix : "", path, + get_super_prefix_or_empty(), path, real_old_git_dir, real_new_git_dir); relocate_gitdir(path, real_old_git_dir, real_new_git_dir); @@ -1445,8 +1723,6 @@ void absorb_git_dir_into_superproject(const char *prefix, /* Not populated? */ if (!sub_git_dir) { - char *real_new_git_dir; - const char *new_git_dir; const struct submodule *sub; if (err_code == READ_GITFILE_ERR_STAT_FAILED) { @@ -1469,13 +1745,8 @@ void absorb_git_dir_into_superproject(const char *prefix, sub = submodule_from_path(null_sha1, path); if (!sub) die(_("could not lookup name for submodule '%s'"), path); - new_git_dir = git_path("modules/%s", sub->name); - if (safe_create_leading_directories_const(new_git_dir) < 0) - die(_("could not create directory '%s'"), new_git_dir); - real_new_git_dir = real_pathdup(new_git_dir, 1); - connect_work_tree_and_git_dir(path, real_new_git_dir); - - free(real_new_git_dir); + connect_work_tree_and_git_dir(path, + git_path("modules/%s", sub->name)); } else { /* Is it already absorbed into the superprojects git dir? */ char *real_sub_git_dir = real_pathdup(sub_git_dir, 1); @@ -1496,8 +1767,7 @@ void absorb_git_dir_into_superproject(const char *prefix, if (flags & ~ABSORB_GITDIR_RECURSE_SUBMODULES) die("BUG: we don't know how to pass the flags down?"); - if (get_super_prefix()) - strbuf_addstr(&sb, get_super_prefix()); + strbuf_addstr(&sb, get_super_prefix_or_empty()); strbuf_addstr(&sb, path); strbuf_addch(&sb, '/'); diff --git a/submodule.h b/submodule.h index fce2fb64d2..1277480add 100644 --- a/submodule.h +++ b/submodule.h @@ -3,7 +3,8 @@ struct diff_options; struct argv_array; -struct sha1_array; +struct oid_array; +struct remote; enum { RECURSE_SUBMODULES_ONLY = -5, @@ -41,7 +42,13 @@ extern int submodule_config(const char *var, const char *value, void *cb); extern void gitmodules_config(void); extern void gitmodules_config_sha1(const unsigned char *commit_sha1); extern int is_submodule_initialized(const char *path); -extern int is_submodule_populated(const char *path); +/* + * Determine if a submodule has been populated at a given 'path' by checking if + * the <path>/.git resolves to a valid git repository. + * If return_error_code is NULL, die on error. + * Otherwise the return error code is the same as of resolve_gitdir_gently. + */ +extern int is_submodule_populated_gently(const char *path, int *return_error_code); extern int parse_submodule_update_strategy(const char *value, struct submodule_update_strategy *dst); extern const char *submodule_strategy_to_string(const struct submodule_update_strategy *s); @@ -58,7 +65,15 @@ extern void show_submodule_inline_diff(FILE *f, const char *path, const char *del, const char *add, const char *reset, const struct diff_options *opt); extern void set_config_fetch_recurse_submodules(int value); -extern void check_for_new_submodule_commits(unsigned char new_sha1[20]); +extern void set_config_update_recurse_submodules(int value); +/* Check if we want to update any submodule.*/ +extern int should_update_submodules(void); +/* + * Returns the submodule struct if the given ce entry is a submodule + * and it should be updated. Returns NULL otherwise. + */ +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 quiet, int max_parallel_jobs); @@ -73,11 +88,13 @@ extern int merge_submodule(unsigned char result[20], const char *path, const unsigned char base[20], const unsigned char a[20], const unsigned char b[20], int search); -extern int find_unpushed_submodules(struct sha1_array *commits, +extern int find_unpushed_submodules(struct oid_array *commits, const char *remotes_name, struct string_list *needs_pushing); -extern int push_unpushed_submodules(struct sha1_array *commits, - const char *remotes_name, +extern int push_unpushed_submodules(struct oid_array *commits, + const struct remote *remote, + const char **refspec, int refspec_nr, + 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); @@ -88,6 +105,13 @@ extern int parallel_submodules(void); */ int submodule_to_gitdir(struct strbuf *buf, const char *submodule); +#define SUBMODULE_MOVE_HEAD_DRY_RUN (1<<0) +#define SUBMODULE_MOVE_HEAD_FORCE (1<<1) +extern int submodule_move_head(const char *path, + const char *old, + const char *new, + unsigned flags); + /* * Prepare the "env_array" parameter of a "struct child_process" for executing * a submodule by clearing any repo-specific envirionment variables, but @@ -471,13 +471,13 @@ Don't: their output. You can glean some further possible issues from the TAP grammar - (see http://search.cpan.org/perldoc?TAP::Parser::Grammar#TAP_Grammar) + (see https://metacpan.org/pod/TAP::Parser::Grammar#TAP-GRAMMAR) but the best indication is to just run the tests with prove(1), it'll complain if anything is amiss. Keep in mind: - - Inside <script> part, the standard output and standard error + - Inside the <script> part, the standard output and standard error streams are discarded, and the test harness only reports "ok" or "not ok" to the end user running the tests. Under --verbose, they are shown to help debugging the tests. @@ -611,9 +611,11 @@ library for your script to use. - test_have_prereq <prereq> - Check if we have a prerequisite previously set with - test_set_prereq. The most common use of this directly is to skip - all the tests if we don't have some essential prerequisite: + Check if we have a prerequisite previously set with test_set_prereq. + The most common way to use this explicitly (as opposed to the + implicit use when an argument is passed to test_expect_*) is to skip + all the tests at the start of the test script if we don't have some + essential prerequisite: if ! test_have_prereq PERL then diff --git a/t/helper/.gitignore b/t/helper/.gitignore index 5f68aa8f8a..d1fa751cf9 100644 --- a/t/helper/.gitignore +++ b/t/helper/.gitignore @@ -11,6 +11,7 @@ /test-genrandom /test-hashmap /test-index-version +/test-lazy-init-name-hash /test-line-buffer /test-match-trees /test-mergesort diff --git a/t/helper/test-lazy-init-name-hash.c b/t/helper/test-lazy-init-name-hash.c new file mode 100644 index 0000000000..6368a89345 --- /dev/null +++ b/t/helper/test-lazy-init-name-hash.c @@ -0,0 +1,264 @@ +#include "cache.h" +#include "parse-options.h" + +static int single; +static int multi; +static int count = 1; +static int dump; +static int perf; +static int analyze; +static int analyze_step; + +/* + * Dump the contents of the "dir" and "name" hash tables to stdout. + * If you sort the result, you can compare it with the other type + * mode and verify that both single and multi produce the same set. + */ +static void dump_run(void) +{ + struct hashmap_iter iter_dir; + struct hashmap_iter iter_cache; + + /* Stolen from name-hash.c */ + struct dir_entry { + struct hashmap_entry ent; + struct dir_entry *parent; + int nr; + unsigned int namelen; + char name[FLEX_ARRAY]; + }; + + struct dir_entry *dir; + struct cache_entry *ce; + + read_cache(); + if (single) { + test_lazy_init_name_hash(&the_index, 0); + } else { + int nr_threads_used = test_lazy_init_name_hash(&the_index, 1); + if (!nr_threads_used) + die("non-threaded code path used"); + } + + dir = hashmap_iter_first(&the_index.dir_hash, &iter_dir); + while (dir) { + printf("dir %08x %7d %s\n", dir->ent.hash, dir->nr, dir->name); + dir = hashmap_iter_next(&iter_dir); + } + + ce = hashmap_iter_first(&the_index.name_hash, &iter_cache); + while (ce) { + printf("name %08x %s\n", ce->ent.hash, ce->name); + ce = hashmap_iter_next(&iter_cache); + } + + discard_cache(); +} + +/* + * Run the single or multi threaded version "count" times and + * report on the time taken. + */ +static uint64_t time_runs(int try_threaded) +{ + uint64_t t0, t1, t2; + uint64_t sum = 0; + uint64_t avg; + int nr_threads_used; + int i; + + for (i = 0; i < count; i++) { + t0 = getnanotime(); + read_cache(); + t1 = getnanotime(); + nr_threads_used = test_lazy_init_name_hash(&the_index, try_threaded); + t2 = getnanotime(); + + sum += (t2 - t1); + + if (try_threaded && !nr_threads_used) + die("non-threaded code path used"); + + if (nr_threads_used) + printf("%f %f %d multi %d\n", + ((double)(t1 - t0))/1000000000, + ((double)(t2 - t1))/1000000000, + the_index.cache_nr, + nr_threads_used); + else + printf("%f %f %d single\n", + ((double)(t1 - t0))/1000000000, + ((double)(t2 - t1))/1000000000, + the_index.cache_nr); + fflush(stdout); + + discard_cache(); + } + + avg = sum / count; + if (count > 1) + printf("avg %f %s\n", + (double)avg/1000000000, + (try_threaded) ? "multi" : "single"); + + return avg; +} + +/* + * Try a series of runs varying the "istate->cache_nr" and + * try to find a good value for the multi-threaded criteria. + */ +static void analyze_run(void) +{ + uint64_t t1s, t1m, t2s, t2m; + int cache_nr_limit; + int nr_threads_used; + int i; + int nr; + + read_cache(); + cache_nr_limit = the_index.cache_nr; + discard_cache(); + + nr = analyze; + while (1) { + uint64_t sum_single = 0; + uint64_t sum_multi = 0; + uint64_t avg_single; + uint64_t avg_multi; + + if (nr > cache_nr_limit) + nr = cache_nr_limit; + + for (i = 0; i < count; i++) { + read_cache(); + the_index.cache_nr = nr; /* cheap truncate of index */ + t1s = getnanotime(); + test_lazy_init_name_hash(&the_index, 0); + t2s = getnanotime(); + sum_single += (t2s - t1s); + the_index.cache_nr = cache_nr_limit; + discard_cache(); + + read_cache(); + the_index.cache_nr = nr; /* cheap truncate of index */ + t1m = getnanotime(); + nr_threads_used = test_lazy_init_name_hash(&the_index, 1); + t2m = getnanotime(); + sum_multi += (t2m - t1m); + the_index.cache_nr = cache_nr_limit; + discard_cache(); + + if (!nr_threads_used) + printf(" [size %8d] [single %f] non-threaded code path used\n", + nr, ((double)(t2s - t1s))/1000000000); + else + printf(" [size %8d] [single %f] %c [multi %f %d]\n", + nr, + ((double)(t2s - t1s))/1000000000, + (((t2s - t1s) < (t2m - t1m)) ? '<' : '>'), + ((double)(t2m - t1m))/1000000000, + nr_threads_used); + fflush(stdout); + } + if (count > 1) { + avg_single = sum_single / count; + avg_multi = sum_multi / count; + if (!nr_threads_used) + printf("avg [size %8d] [single %f]\n", + nr, + (double)avg_single/1000000000); + else + printf("avg [size %8d] [single %f] %c [multi %f %d]\n", + nr, + (double)avg_single/1000000000, + (avg_single < avg_multi ? '<' : '>'), + (double)avg_multi/1000000000, + nr_threads_used); + fflush(stdout); + } + + if (nr >= cache_nr_limit) + return; + nr += analyze_step; + } +} + +int cmd_main(int argc, const char **argv) +{ + const char *usage[] = { + "test-lazy-init-name-hash -d (-s | -m)", + "test-lazy-init-name-hash -p [-c c]", + "test-lazy-init-name-hash -a a [--step s] [-c c]", + "test-lazy-init-name-hash (-s | -m) [-c c]", + "test-lazy-init-name-hash -s -m [-c c]", + NULL + }; + struct option options[] = { + OPT_BOOL('s', "single", &single, "run single-threaded code"), + OPT_BOOL('m', "multi", &multi, "run multi-threaded code"), + OPT_INTEGER('c', "count", &count, "number of passes"), + OPT_BOOL('d', "dump", &dump, "dump hash tables"), + OPT_BOOL('p', "perf", &perf, "compare single vs multi"), + OPT_INTEGER('a', "analyze", &analyze, "analyze different multi sizes"), + OPT_INTEGER(0, "step", &analyze_step, "analyze step factor"), + OPT_END(), + }; + const char *prefix; + uint64_t avg_single, avg_multi; + + prefix = setup_git_directory(); + + argc = parse_options(argc, argv, prefix, options, usage, 0); + + /* + * istate->dir_hash is only created when ignore_case is set. + */ + ignore_case = 1; + + if (dump) { + if (perf || analyze > 0) + die("cannot combine dump, perf, or analyze"); + if (count > 1) + die("count not valid with dump"); + if (single && multi) + die("cannot use both single and multi with dump"); + if (!single && !multi) + die("dump requires either single or multi"); + dump_run(); + return 0; + } + + if (perf) { + if (analyze > 0) + die("cannot combine dump, perf, or analyze"); + if (single || multi) + die("cannot use single or multi with perf"); + avg_single = time_runs(0); + avg_multi = time_runs(1); + if (avg_multi > avg_single) + die("multi is slower"); + return 0; + } + + if (analyze) { + if (analyze < 500) + die("analyze must be at least 500"); + if (!analyze_step) + analyze_step = analyze; + if (single || multi) + die("cannot use single or multi with analyze"); + analyze_run(); + return 0; + } + + if (!single && !multi) + die("require either -s or -m or both"); + + if (single) + time_runs(0); + if (multi) + time_runs(1); + + return 0; +} diff --git a/t/helper/test-sha1-array.c b/t/helper/test-sha1-array.c index f7a53c4ad6..edfd52d82a 100644 --- a/t/helper/test-sha1-array.c +++ b/t/helper/test-sha1-array.c @@ -1,33 +1,33 @@ #include "cache.h" #include "sha1-array.h" -static int print_sha1(const unsigned char sha1[20], void *data) +static int print_oid(const struct object_id *oid, void *data) { - puts(sha1_to_hex(sha1)); + puts(oid_to_hex(oid)); return 0; } int cmd_main(int argc, const char **argv) { - struct sha1_array array = SHA1_ARRAY_INIT; + struct oid_array array = OID_ARRAY_INIT; struct strbuf line = STRBUF_INIT; while (strbuf_getline(&line, stdin) != EOF) { const char *arg; - unsigned char sha1[20]; + struct object_id oid; if (skip_prefix(line.buf, "append ", &arg)) { - if (get_sha1_hex(arg, sha1)) + if (get_oid_hex(arg, &oid)) die("not a hexadecimal SHA1: %s", arg); - sha1_array_append(&array, sha1); + oid_array_append(&array, &oid); } else if (skip_prefix(line.buf, "lookup ", &arg)) { - if (get_sha1_hex(arg, sha1)) + if (get_oid_hex(arg, &oid)) die("not a hexadecimal SHA1: %s", arg); - printf("%d\n", sha1_array_lookup(&array, sha1)); + printf("%d\n", oid_array_lookup(&array, &oid)); } else if (!strcmp(line.buf, "clear")) - sha1_array_clear(&array); + oid_array_clear(&array); else if (!strcmp(line.buf, "for_each_unique")) - sha1_array_for_each_unique(&array, print_sha1, NULL); + oid_array_for_each_unique(&array, print_oid, NULL); else die("unknown command: %s", line.buf); } diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh index 915eb4a7c6..fb4f7b014e 100755 --- a/t/lib-submodule-update.sh +++ b/t/lib-submodule-update.sh @@ -4,6 +4,7 @@ # - New submodule (no_submodule => add_sub1) # - Removed submodule (add_sub1 => remove_sub1) # - Updated submodule (add_sub1 => modify_sub1) +# - Updated submodule recursively (add_nested_sub => modify_sub1_recursively) # - Submodule updated to invalid commit (add_sub1 => invalid_sub1) # - Submodule updated from invalid commit (invalid_sub1 => valid_sub1) # - Submodule replaced by tracked files in directory (add_sub1 => @@ -15,23 +16,50 @@ # - Tracked file replaced by submodule (replace_sub1_with_file => # replace_file_with_sub1) # -# --O-----O -# / ^ replace_directory_with_sub1 -# / replace_sub1_with_directory -# /----O -# / ^ -# / modify_sub1 -# O------O-------O -# ^ ^\ ^ -# | | \ remove_sub1 -# | | -----O-----O -# | | \ ^ replace_file_with_sub1 -# | | \ replace_sub1_with_file -# | add_sub1 --O-----O -# no_submodule ^ valid_sub1 -# invalid_sub1 +# ----O +# / ^ +# / remove_sub1 +# / +# add_sub1 /-------O---------O--------O modify_sub1_recursively +# | / ^ add_nested_sub +# | / modify_sub1 +# v/ +# O------O-----------O---------O +# ^ \ ^ replace_directory_with_sub1 +# | \ replace_sub1_with_directory +# no_submodule \ +# --------O---------O +# \ ^ replace_file_with_sub1 +# \ replace_sub1_with_file +# \ +# ----O---------O +# ^ valid_sub1 +# invalid_sub1 # + create_lib_submodule_repo () { + git init submodule_update_sub1 && + ( + cd submodule_update_sub1 && + echo "expect" >>.gitignore && + echo "actual" >>.gitignore && + echo "x" >file1 && + echo "y" >file2 && + git add .gitignore file1 file2 && + git commit -m "Base inside first submodule" && + git branch "no_submodule" + ) && + git init submodule_update_sub2 && + ( + cd submodule_update_sub2 + echo "expect" >>.gitignore && + echo "actual" >>.gitignore && + echo "x" >file1 && + echo "y" >file2 && + git add .gitignore file1 file2 && + git commit -m "nested submodule base" && + git branch "no_submodule" + ) && git init submodule_update_repo && ( cd submodule_update_repo && @@ -44,15 +72,16 @@ create_lib_submodule_repo () { git branch "no_submodule" && git checkout -b "add_sub1" && - git submodule add ./. sub1 && + git submodule add ../submodule_update_sub1 sub1 && git config -f .gitmodules submodule.sub1.ignore all && git config submodule.sub1.ignore all && git add .gitmodules && git commit -m "Add sub1" && - git checkout -b remove_sub1 && + + git checkout -b remove_sub1 add_sub1 && git revert HEAD && - git checkout -b "modify_sub1" "add_sub1" && + git checkout -b modify_sub1 add_sub1 && git submodule update && ( cd sub1 && @@ -67,7 +96,27 @@ create_lib_submodule_repo () { git add sub1 && git commit -m "Modify sub1" && - git checkout -b "replace_sub1_with_directory" "add_sub1" && + git checkout -b add_nested_sub modify_sub1 && + git -C sub1 checkout -b "add_nested_sub" && + git -C sub1 submodule add --branch no_submodule ../submodule_update_sub2 sub2 && + git -C sub1 commit -a -m "add a nested submodule" && + git add sub1 && + git commit -a -m "update submodule, that updates a nested submodule" && + git checkout -b modify_sub1_recursively && + git -C sub1 checkout -b modify_sub1_recursively && + git -C sub1/sub2 checkout -b modify_sub1_recursively && + echo change >sub1/sub2/file3 && + git -C sub1/sub2 add file3 && + git -C sub1/sub2 commit -m "make a change in nested sub" && + git -C sub1 add sub2 && + git -C sub1 commit -m "update nested sub" && + git add sub1 && + git commit -m "update sub1, that updates nested sub" && + git -C sub1 push origin modify_sub1_recursively && + git -C sub1/sub2 push origin modify_sub1_recursively && + git -C sub1 submodule deinit -f --all && + + git checkout -b replace_sub1_with_directory add_sub1 && git submodule update && git -C sub1 checkout modifications && git rm --cached sub1 && @@ -75,22 +124,25 @@ create_lib_submodule_repo () { git config -f .gitmodules --remove-section "submodule.sub1" && git add .gitmodules sub1/* && git commit -m "Replace sub1 with directory" && + git checkout -b replace_directory_with_sub1 && git revert HEAD && - git checkout -b "replace_sub1_with_file" "add_sub1" && + git checkout -b replace_sub1_with_file add_sub1 && git rm sub1 && echo "content" >sub1 && git add sub1 && git commit -m "Replace sub1 with file" && + git checkout -b replace_file_with_sub1 && git revert HEAD && - git checkout -b "invalid_sub1" "add_sub1" && + git checkout -b invalid_sub1 add_sub1 && git update-index --cacheinfo 160000 0123456789012345678901234567890123456789 sub1 && git commit -m "Invalid sub1 commit" && git checkout -b valid_sub1 && git revert HEAD && + git checkout master ) } @@ -130,6 +182,15 @@ test_git_directory_is_unchanged () { ) } +test_git_directory_exists() { + test -e ".git/modules/$1" && + if test -f sub1/.git + then + # does core.worktree point at the right place? + test "$(git -C .git/modules/$1 config core.worktree)" = "../../../$1" + fi +} + # Helper function to be executed at the start of every test below, it sets up # the submodule repo if it doesn't exist and configures the most problematic # settings for diff.ignoreSubmodules. @@ -151,15 +212,36 @@ reset_work_tree_to () { git checkout -f "$1" && git status -u -s >actual && test_must_be_empty actual && - sha1=$(git rev-parse --revs-only HEAD:sub1) && - if test -n "$sha1" && - test $(cd "sub1" && git rev-parse --verify "$sha1^{commit}") + hash=$(git rev-parse --revs-only HEAD:sub1) && + if test -n "$hash" && + test $(cd "../submodule_update_sub1" && git rev-parse --verify "$hash^{commit}") then git submodule update --init --recursive "sub1" fi ) } +reset_work_tree_to_interested () { + reset_work_tree_to $1 && + # make the submodule git dirs available + if ! test -d submodule_update/.git/modules/sub1 + then + mkdir -p submodule_update/.git/modules && + cp -r submodule_update_repo/.git/modules/sub1 submodule_update/.git/modules/sub1 + GIT_WORK_TREE=. git -C submodule_update/.git/modules/sub1 config --unset core.worktree + fi && + if ! test -d submodule_update/.git/modules/sub1/modules/sub2 + then + mkdir -p submodule_update/.git/modules/sub1/modules && + cp -r submodule_update_repo/.git/modules/sub1/modules/sub2 submodule_update/.git/modules/sub1/modules/sub2 + GIT_WORK_TREE=. git -C submodule_update/.git/modules/sub1/modules/sub2 config --unset core.worktree + fi && + # indicate we are interested in the submodule: + git -C submodule_update config submodule.sub1.url "bogus" && + # sub1 might not be checked out, so use the git dir + git -C submodule_update/.git/modules/sub1 config submodule.sub2.url "bogus" +} + # Test that the superproject contains the content according to commit "$1" # (the work tree must match the index for everything but submodules but the # index must exactly match the given commit including any submodule SHA-1s). @@ -173,6 +255,11 @@ test_superproject_content () { # Test that the given submodule at path "$1" contains the content according # to the submodule commit recorded in the superproject's commit "$2" test_submodule_content () { + if test x"$1" = "x-C" + then + cd "$2" + shift; shift; + fi if test $# != 2 then echo "test_submodule_content needs two arguments" @@ -675,3 +762,464 @@ test_submodule_forced_switch () { ) ' } + +# Test that submodule contents are correctly updated when switching +# between commits that change a submodule. +# Test that the following transitions are correctly handled: +# (These tests are also above in the case where we expect no change +# in the submodule) +# - Updated submodule +# - New submodule +# - Removed submodule +# - Directory containing tracked files replaced by submodule +# - Submodule replaced by tracked files in directory +# - Submodule replaced by tracked file with the same name +# - tracked file replaced by submodule +# +# New test cases +# - Removing a submodule with a git directory absorbs the submodules +# git directory first into the superproject. + +test_submodule_switch_recursing () { + command="$1" + RESULTDS=success + if test "$KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS" = 1 + then + RESULTDS=failure + fi + RESULTR=success + if test "$KNOWN_FAILURE_SUBMODULE_RECURSIVE_NESTED" = 1 + then + RESULTR=failure + fi + RESULTOI=success + if test "$KNOWN_FAILURE_SUBMODULE_OVERWRITE_IGNORED_UNTRACKED" = 1 + then + RESULTOI=failure + fi + ######################### Appearing submodule ######################### + # Switching to a commit letting a submodule appear checks it out ... + test_expect_success "$command: added submodule is checked out" ' + prolog && + reset_work_tree_to_interested no_submodule && + ( + cd submodule_update && + git branch -t add_sub1 origin/add_sub1 && + $command add_sub1 && + test_superproject_content origin/add_sub1 && + test_submodule_content sub1 origin/add_sub1 + ) + ' + # ... ignoring an empty existing directory ... + test_expect_success "$command: added submodule is checked out in empty dir" ' + prolog && + reset_work_tree_to_interested no_submodule && + ( + cd submodule_update && + mkdir sub1 && + git branch -t add_sub1 origin/add_sub1 && + $command add_sub1 && + test_superproject_content origin/add_sub1 && + test_submodule_content sub1 origin/add_sub1 + ) + ' + # ... unless there is an untracked file in its place. + test_expect_success "$command: added submodule doesn't remove untracked file with same name" ' + prolog && + reset_work_tree_to_interested no_submodule && + ( + cd submodule_update && + git branch -t add_sub1 origin/add_sub1 && + : >sub1 && + test_must_fail $command add_sub1 && + test_superproject_content origin/no_submodule && + test_must_be_empty sub1 + ) + ' + # ... but an ignored file is fine. + test_expect_$RESULTOI "$command: added submodule removes an untracked ignored file" ' + test_when_finished "rm submodule_update/.git/info/exclude" && + prolog && + reset_work_tree_to_interested no_submodule && + ( + cd submodule_update && + git branch -t add_sub1 origin/add_sub1 && + : >sub1 && + echo sub1 >.git/info/exclude + $command add_sub1 && + test_superproject_content origin/add_sub1 && + test_submodule_content sub1 origin/add_sub1 + ) + ' + # Replacing a tracked file with a submodule produces a checked out submodule + test_expect_success "$command: replace tracked file with submodule checks out submodule" ' + prolog && + reset_work_tree_to_interested replace_sub1_with_file && + ( + cd submodule_update && + git branch -t replace_file_with_sub1 origin/replace_file_with_sub1 && + $command replace_file_with_sub1 && + test_superproject_content origin/replace_file_with_sub1 && + test_submodule_content sub1 origin/replace_file_with_sub1 + ) + ' + # ... as does removing a directory with tracked files with a submodule. + test_expect_success "$command: replace directory with submodule" ' + prolog && + reset_work_tree_to_interested replace_sub1_with_directory && + ( + cd submodule_update && + git branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 && + $command replace_directory_with_sub1 && + test_superproject_content origin/replace_directory_with_sub1 && + test_submodule_content sub1 origin/replace_directory_with_sub1 + ) + ' + + ######################## Disappearing submodule ####################### + # Removing a submodule removes its work tree ... + test_expect_success "$command: removed submodule removes submodules working tree" ' + prolog && + reset_work_tree_to_interested add_sub1 && + ( + cd submodule_update && + git branch -t remove_sub1 origin/remove_sub1 && + $command remove_sub1 && + test_superproject_content origin/remove_sub1 && + ! test -e sub1 + ) + ' + # ... absorbing a .git directory along the way. + test_expect_success "$command: removed submodule absorbs submodules .git directory" ' + prolog && + reset_work_tree_to_interested add_sub1 && + ( + cd submodule_update && + git branch -t remove_sub1 origin/remove_sub1 && + replace_gitfile_with_git_dir sub1 && + rm -rf .git/modules && + $command remove_sub1 && + test_superproject_content origin/remove_sub1 && + ! test -e sub1 && + test_git_directory_exists sub1 + ) + ' + # Replacing a submodule with files in a directory must succeeds + # when the submodule is clean + test_expect_$RESULTDS "$command: replace submodule with a directory" ' + prolog && + reset_work_tree_to_interested add_sub1 && + ( + cd submodule_update && + git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory && + $command replace_sub1_with_directory && + test_superproject_content origin/replace_sub1_with_directory && + test_submodule_content sub1 origin/replace_sub1_with_directory + ) + ' + # ... absorbing a .git directory. + test_expect_$RESULTDS "$command: replace submodule containing a .git directory with a directory must absorb the git dir" ' + prolog && + reset_work_tree_to_interested add_sub1 && + ( + cd submodule_update && + git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory && + replace_gitfile_with_git_dir sub1 && + rm -rf .git/modules && + $command replace_sub1_with_directory && + test_superproject_content origin/replace_sub1_with_directory && + test_git_directory_exists sub1 + ) + ' + + # Replacing it with a file ... + test_expect_success "$command: replace submodule with a file" ' + prolog && + reset_work_tree_to_interested add_sub1 && + ( + cd submodule_update && + git branch -t replace_sub1_with_file origin/replace_sub1_with_file && + $command replace_sub1_with_file && + test_superproject_content origin/replace_sub1_with_file && + test -f sub1 + ) + ' + + # ... must check its local work tree for untracked files + test_expect_$RESULTDS "$command: replace submodule with a file must fail with untracked files" ' + prolog && + reset_work_tree_to_interested add_sub1 && + ( + cd submodule_update && + git branch -t replace_sub1_with_file origin/replace_sub1_with_file && + : >sub1/untrackedfile && + test_must_fail $command replace_sub1_with_file && + test_superproject_content origin/add_sub1 && + test_submodule_content sub1 origin/add_sub1 + ) + ' + + # ... and ignored files are ignored + test_expect_success "$command: replace submodule with a file works ignores ignored files in submodule" ' + test_when_finished "rm submodule_update/.git/modules/sub1/info/exclude" && + prolog && + reset_work_tree_to_interested add_sub1 && + ( + cd submodule_update && + git branch -t replace_sub1_with_file origin/replace_sub1_with_file && + : >sub1/ignored && + $command replace_sub1_with_file && + test_superproject_content origin/replace_sub1_with_file && + test -f sub1 + ) + ' + + ########################## Modified submodule ######################### + # Updating a submodule sha1 updates the submodule's work tree + test_expect_success "$command: modified submodule updates submodule work tree" ' + prolog && + reset_work_tree_to_interested add_sub1 && + ( + cd submodule_update && + git branch -t modify_sub1 origin/modify_sub1 && + $command modify_sub1 && + test_superproject_content origin/modify_sub1 && + test_submodule_content sub1 origin/modify_sub1 + ) + ' + + # Updating a submodule to an invalid sha1 doesn't update the + # superproject nor the submodule's work tree. + test_expect_success "$command: updating to a missing submodule commit fails" ' + prolog && + reset_work_tree_to_interested add_sub1 && + ( + cd submodule_update && + git branch -t invalid_sub1 origin/invalid_sub1 && + test_must_fail $command invalid_sub1 && + test_superproject_content origin/add_sub1 && + test_submodule_content sub1 origin/add_sub1 + ) + ' + + # recursing deeper than one level doesn't work yet. + test_expect_$RESULTR "$command: modified submodule updates submodule recursively" ' + prolog && + reset_work_tree_to_interested add_nested_sub && + ( + cd submodule_update && + git branch -t modify_sub1_recursively origin/modify_sub1_recursively && + $command modify_sub1_recursively && + test_superproject_content origin/modify_sub1_recursively && + test_submodule_content sub1 origin/modify_sub1_recursively && + test_submodule_content -C sub1 sub2 origin/modify_sub1_recursively + ) + ' +} + +# Test that submodule contents are updated when switching between commits +# that change a submodule, but throwing away local changes in +# the superproject as well as the submodule is allowed. +test_submodule_forced_switch_recursing () { + command="$1" + RESULT=success + if test "$KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS" = 1 + then + RESULT=failure + fi + ######################### Appearing submodule ######################### + # Switching to a commit letting a submodule appear creates empty dir ... + test_expect_success "$command: added submodule is checked out" ' + prolog && + reset_work_tree_to_interested no_submodule && + ( + cd submodule_update && + git branch -t add_sub1 origin/add_sub1 && + $command add_sub1 && + test_superproject_content origin/add_sub1 && + test_submodule_content sub1 origin/add_sub1 + ) + ' + # ... and doesn't care if it already exists ... + test_expect_success "$command: added submodule ignores empty directory" ' + prolog && + reset_work_tree_to_interested no_submodule && + ( + cd submodule_update && + git branch -t add_sub1 origin/add_sub1 && + mkdir sub1 && + $command add_sub1 && + test_superproject_content origin/add_sub1 && + test_submodule_content sub1 origin/add_sub1 + ) + ' + # ... not caring about an untracked file either + test_expect_success "$command: added submodule does remove untracked unignored file with same name when forced" ' + prolog && + reset_work_tree_to_interested no_submodule && + ( + cd submodule_update && + git branch -t add_sub1 origin/add_sub1 && + >sub1 && + $command add_sub1 && + test_superproject_content origin/add_sub1 && + test_submodule_content sub1 origin/add_sub1 + ) + ' + # Replacing a tracked file with a submodule checks out the submodule + test_expect_success "$command: replace tracked file with submodule populates the submodule" ' + prolog && + reset_work_tree_to_interested replace_sub1_with_file && + ( + cd submodule_update && + git branch -t replace_file_with_sub1 origin/replace_file_with_sub1 && + $command replace_file_with_sub1 && + test_superproject_content origin/replace_file_with_sub1 && + test_submodule_content sub1 origin/replace_file_with_sub1 + ) + ' + # ... as does removing a directory with tracked files with a + # submodule. + test_expect_success "$command: replace directory with submodule" ' + prolog && + reset_work_tree_to_interested replace_sub1_with_directory && + ( + cd submodule_update && + git branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 && + $command replace_directory_with_sub1 && + test_superproject_content origin/replace_directory_with_sub1 && + test_submodule_content sub1 origin/replace_directory_with_sub1 + ) + ' + + ######################## Disappearing submodule ####################### + # Removing a submodule doesn't remove its work tree ... + test_expect_success "$command: removed submodule leaves submodule directory and its contents in place" ' + prolog && + reset_work_tree_to_interested add_sub1 && + ( + cd submodule_update && + git branch -t remove_sub1 origin/remove_sub1 && + $command remove_sub1 && + test_superproject_content origin/remove_sub1 && + ! test -e sub1 + ) + ' + # ... especially when it contains a .git directory. + test_expect_success "$command: removed submodule leaves submodule containing a .git directory alone" ' + prolog && + reset_work_tree_to_interested add_sub1 && + ( + cd submodule_update && + git branch -t remove_sub1 origin/remove_sub1 && + replace_gitfile_with_git_dir sub1 && + rm -rf .git/modules/sub1 && + $command remove_sub1 && + test_superproject_content origin/remove_sub1 && + test_git_directory_exists sub1 && + ! test -e sub1 + ) + ' + # Replacing a submodule with files in a directory ... + test_expect_success "$command: replace submodule with a directory" ' + prolog && + reset_work_tree_to_interested add_sub1 && + ( + cd submodule_update && + git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory && + $command replace_sub1_with_directory && + test_superproject_content origin/replace_sub1_with_directory + ) + ' + # ... absorbing a .git directory. + test_expect_success "$command: replace submodule containing a .git directory with a directory must fail" ' + prolog && + reset_work_tree_to_interested add_sub1 && + ( + cd submodule_update && + git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory && + replace_gitfile_with_git_dir sub1 && + rm -rf .git/modules/sub1 && + $command replace_sub1_with_directory && + test_superproject_content origin/replace_sub1_with_directory && + test_submodule_content sub1 origin/modify_sub1 + test_git_directory_exists sub1 + ) + ' + # Replacing it with a file + test_expect_success "$command: replace submodule with a file" ' + prolog && + reset_work_tree_to_interested add_sub1 && + ( + cd submodule_update && + git branch -t replace_sub1_with_file origin/replace_sub1_with_file && + $command replace_sub1_with_file && + test_superproject_content origin/replace_sub1_with_file + ) + ' + + # ... even if the submodule contains ignored files + test_expect_success "$command: replace submodule with a file ignoring ignored files" ' + prolog && + reset_work_tree_to_interested add_sub1 && + ( + cd submodule_update && + git branch -t replace_sub1_with_file origin/replace_sub1_with_file && + : >sub1/expect && + $command replace_sub1_with_file && + test_superproject_content origin/replace_sub1_with_file + ) + ' + + # ... but stops for untracked files that would be lost + test_expect_$RESULT "$command: replace submodule with a file stops for untracked files" ' + prolog && + reset_work_tree_to_interested add_sub1 && + ( + cd submodule_update && + git branch -t replace_sub1_with_file origin/replace_sub1_with_file && + : >sub1/untracked_file && + test_must_fail $command replace_sub1_with_file && + test_superproject_content origin/add_sub1 && + test -f sub1/untracked_file + ) + ' + + ########################## Modified submodule ######################### + # Updating a submodule sha1 updates the submodule's work tree + test_expect_success "$command: modified submodule updates submodule work tree" ' + prolog && + reset_work_tree_to_interested add_sub1 && + ( + cd submodule_update && + git branch -t modify_sub1 origin/modify_sub1 && + $command modify_sub1 && + test_superproject_content origin/modify_sub1 && + test_submodule_content sub1 origin/modify_sub1 + ) + ' + # Updating a submodule to an invalid sha1 doesn't update the + # submodule's work tree, subsequent update will fail + test_expect_success "$command: modified submodule does not update submodule work tree to invalid commit" ' + prolog && + reset_work_tree_to_interested add_sub1 && + ( + cd submodule_update && + git branch -t invalid_sub1 origin/invalid_sub1 && + test_must_fail $command invalid_sub1 && + test_superproject_content origin/add_sub1 && + test_submodule_content sub1 origin/add_sub1 + ) + ' + # Updating a submodule from an invalid sha1 updates + test_expect_success "$command: modified submodule does not update submodule work tree from invalid commit" ' + prolog && + reset_work_tree_to_interested invalid_sub1 && + ( + cd submodule_update && + git branch -t valid_sub1 origin/valid_sub1 && + test_must_fail $command valid_sub1 && + test_superproject_content origin/invalid_sub1 + ) + ' +} diff --git a/t/perf/p0004-lazy-init-name-hash.sh b/t/perf/p0004-lazy-init-name-hash.sh new file mode 100644 index 0000000000..5afa8c8df3 --- /dev/null +++ b/t/perf/p0004-lazy-init-name-hash.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +test_description='Tests multi-threaded lazy_init_name_hash' +. ./perf-lib.sh + +test_perf_large_repo +test_checkout_worktree + +test_expect_success 'verify both methods build the same hashmaps' ' + $GIT_BUILD_DIR/t/helper/test-lazy-init-name-hash$X --dump --single | sort >out.single && + $GIT_BUILD_DIR/t/helper/test-lazy-init-name-hash$X --dump --multi | sort >out.multi && + test_cmp out.single out.multi +' + +test_expect_success 'multithreaded should be faster' ' + $GIT_BUILD_DIR/t/helper/test-lazy-init-name-hash$X --perf >out.perf +' + +test_done diff --git a/t/t0001-init.sh b/t/t0001-init.sh index e424de5363..c4814d248f 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -315,6 +315,20 @@ test_expect_success 'init with separate gitdir' ' test_path_is_dir realgitdir/refs ' +test_expect_success 'init in 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 && + ( + cd $p127 && + git init newdir + ) +' + test_expect_success 're-init on .git file' ' ( cd newdir && git init ) ' diff --git a/t/t0013-sha1dc.sh b/t/t0013-sha1dc.sh new file mode 100755 index 0000000000..6d655cb161 --- /dev/null +++ b/t/t0013-sha1dc.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +test_description='test sha1 collision detection' +. ./test-lib.sh +TEST_DATA="$TEST_DIRECTORY/t0013" + +if test -z "$DC_SHA1" +then + skip_all='skipping sha1 collision tests, DC_SHA1 not set' + test_done +fi + +test_expect_success 'test-sha1 detects shattered pdf' ' + test_must_fail test-sha1 <"$TEST_DATA/shattered-1.pdf" 2>err && + test_i18ngrep collision err && + grep 38762cf7f55934b34d179ae6a4c80cadccbb7f0a err +' + +test_done diff --git a/t/t0013/shattered-1.pdf b/t/t0013/shattered-1.pdf Binary files differnew file mode 100644 index 0000000000..ba9aaa145c --- /dev/null +++ b/t/t0013/shattered-1.pdf diff --git a/t/t0301-credential-cache.sh b/t/t0301-credential-cache.sh index 82c8411210..fd92533acf 100755 --- a/t/t0301-credential-cache.sh +++ b/t/t0301-credential-cache.sh @@ -12,7 +12,100 @@ test -z "$NO_UNIX_SOCKETS" || { # don't leave a stale daemon running trap 'code=$?; git credential-cache exit; (exit $code); die' EXIT +# test that the daemon works with no special setup helper_test cache + +test_expect_success 'socket defaults to ~/.cache/git/credential/socket' ' + test_when_finished " + git credential-cache exit && + rmdir -p .cache/git/credential/ + " && + test_path_is_missing "$HOME/.git-credential-cache" && + test -S "$HOME/.cache/git/credential/socket" +' + +XDG_CACHE_HOME="$HOME/xdg" +export XDG_CACHE_HOME +# test behavior when XDG_CACHE_HOME is set +helper_test cache + +test_expect_success "use custom XDG_CACHE_HOME if set and default sockets are not created" ' + test_when_finished "git credential-cache exit" && + test -S "$XDG_CACHE_HOME/git/credential/socket" && + test_path_is_missing "$HOME/.git-credential-cache/socket" && + test_path_is_missing "$HOME/.cache/git/credential/socket" +' +unset XDG_CACHE_HOME + +test_expect_success 'credential-cache --socket option overrides default location' ' + test_when_finished " + git credential-cache exit --socket \"\$HOME/dir/socket\" && + rmdir \"\$HOME/dir\" + " && + check approve "cache --socket \"\$HOME/dir/socket\"" <<-\EOF && + protocol=https + host=example.com + username=store-user + password=store-pass + EOF + test -S "$HOME/dir/socket" +' + +test_expect_success "use custom XDG_CACHE_HOME even if xdg socket exists" ' + test_when_finished " + git credential-cache exit && + sane_unset XDG_CACHE_HOME + " && + check approve cache <<-\EOF && + protocol=https + host=example.com + username=store-user + password=store-pass + EOF + test -S "$HOME/.cache/git/credential/socket" && + XDG_CACHE_HOME="$HOME/xdg" && + export XDG_CACHE_HOME && + check approve cache <<-\EOF && + protocol=https + host=example.com + username=store-user + password=store-pass + EOF + test -S "$XDG_CACHE_HOME/git/credential/socket" +' + +test_expect_success 'use user socket if user directory exists' ' + test_when_finished " + git credential-cache exit && + rmdir \"\$HOME/.git-credential-cache/\" + " && + mkdir -p -m 700 "$HOME/.git-credential-cache/" && + check approve cache <<-\EOF && + protocol=https + host=example.com + username=store-user + password=store-pass + EOF + test -S "$HOME/.git-credential-cache/socket" +' + +test_expect_success SYMLINKS 'use user socket if user directory is a symlink to a directory' ' + test_when_finished " + git credential-cache exit && + rmdir \"\$HOME/dir/\" && + rm \"\$HOME/.git-credential-cache\" + " && + mkdir -p -m 700 "$HOME/dir/" && + ln -s "$HOME/dir" "$HOME/.git-credential-cache" && + check approve cache <<-\EOF && + protocol=https + host=example.com + username=store-user + password=store-pass + EOF + test -S "$HOME/.git-credential-cache/socket" +' + helper_test_timeout cache --timeout=1 # we can't rely on our "trap" above working after test_done, diff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh index c5245c5cb4..532682f51c 100755 --- a/t/t1007-hash-object.sh +++ b/t/t1007-hash-object.sh @@ -134,6 +134,16 @@ test_expect_success 'gitattributes also work in a subdirectory' ' ) ' +test_expect_success '--path works in a subdirectory' ' + ( + cd subdir && + path1_sha=$(git hash-object --path=../file1 ../file0) && + path0_sha=$(git hash-object --path=../file0 ../file1) && + test "$file0_sha" = "$path0_sha" && + test "$file1_sha" = "$path1_sha" + ) +' + test_expect_success 'check that --no-filters option works' ' nofilters_file1=$(git hash-object --no-filters file1) && test "$file0_sha" = "$nofilters_file1" && diff --git a/t/t1013-read-tree-submodule.sh b/t/t1013-read-tree-submodule.sh index 20526aed34..de1ba02dc5 100755 --- a/t/t1013-read-tree-submodule.sh +++ b/t/t1013-read-tree-submodule.sh @@ -5,6 +5,14 @@ test_description='read-tree can handle submodules' . ./test-lib.sh . "$TEST_DIRECTORY"/lib-submodule-update.sh +KNOWN_FAILURE_SUBMODULE_RECURSIVE_NESTED=1 +KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS=1 +KNOWN_FAILURE_SUBMODULE_OVERWRITE_IGNORED_UNTRACKED=1 + +test_submodule_switch_recursing "git read-tree --recurse-submodules -u -m" + +test_submodule_forced_switch_recursing "git read-tree --recurse-submodules -u --reset" + test_submodule_switch "git read-tree -u -m" test_submodule_forced_switch "git read-tree -u --reset" diff --git a/t/t1060-object-corruption.sh b/t/t1060-object-corruption.sh index 3f8705139d..ac1f189fd2 100755 --- a/t/t1060-object-corruption.sh +++ b/t/t1060-object-corruption.sh @@ -21,6 +21,14 @@ test_expect_success 'setup corrupt repo' ' cd bit-error && test_commit content && corrupt_byte HEAD:content.t 10 + ) && + git init no-bit-error && + ( + # distinct commit from bit-error, but containing a + # non-corrupted version of the same blob + cd no-bit-error && + test_tick && + test_commit content ) ' @@ -53,6 +61,13 @@ test_expect_success 'streaming a corrupt blob fails' ' ) ' +test_expect_success 'getting type of a corrupt blob fails' ' + ( + cd bit-error && + test_must_fail git cat-file -s HEAD:content.t + ) +' + test_expect_success 'read-tree -u detects bit-errors in blobs' ' ( cd bit-error && @@ -101,4 +116,13 @@ test_expect_failure 'clone --local detects misnamed objects' ' test_must_fail git clone --local misnamed misnamed-checkout ' +test_expect_success 'fetch into corrupted repo with index-pack' ' + ( + cd bit-error && + test_must_fail git -c transfer.unpackLimit=1 \ + fetch ../no-bit-error 2>stderr && + test_i18ngrep ! -i collision stderr + ) +' + test_done diff --git a/t/t1305-config-include.sh b/t/t1305-config-include.sh index 9ba2ba11c3..e833939320 100755 --- a/t/t1305-config-include.sh +++ b/t/t1305-config-include.sh @@ -102,7 +102,7 @@ test_expect_success 'config modification does not affect includes' ' test_expect_success 'missing include files are ignored' ' cat >.gitconfig <<-\EOF && - [include]path = foo + [include]path = non-existent [test]value = yes EOF echo yes >expect && @@ -152,6 +152,62 @@ test_expect_success 'relative includes from stdin line fail' ' test_must_fail git config --file - test.one ' +test_expect_success 'conditional include, both unanchored' ' + git init foo && + ( + cd foo && + echo "[includeIf \"gitdir:foo/\"]path=bar" >>.git/config && + echo "[test]one=1" >.git/bar && + echo 1 >expect && + git config test.one >actual && + test_cmp expect actual + ) +' + +test_expect_success 'conditional include, $HOME expansion' ' + ( + cd foo && + echo "[includeIf \"gitdir:~/foo/\"]path=bar2" >>.git/config && + echo "[test]two=2" >.git/bar2 && + echo 2 >expect && + git config test.two >actual && + test_cmp expect actual + ) +' + +test_expect_success 'conditional include, full pattern' ' + ( + cd foo && + echo "[includeIf \"gitdir:**/foo/**\"]path=bar3" >>.git/config && + echo "[test]three=3" >.git/bar3 && + echo 3 >expect && + git config test.three >actual && + test_cmp expect actual + ) +' + +test_expect_success 'conditional include, relative path' ' + echo "[includeIf \"gitdir:./foo/.git\"]path=bar4" >>.gitconfig && + echo "[test]four=4" >bar4 && + ( + cd foo && + echo 4 >expect && + git config test.four >actual && + test_cmp expect actual + ) +' + +test_expect_success 'conditional include, both unanchored, icase' ' + ( + cd foo && + echo "[includeIf \"gitdir/i:FOO/\"]path=bar5" >>.git/config && + echo "[test]five=5" >.git/bar5 && + echo 5 >expect && + git config test.five >actual && + test_cmp expect actual + ) +' + test_expect_success 'include cycles are detected' ' cat >.gitconfig <<-\EOF && [test]value = gitconfig diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh index 825422341d..a23cd7b576 100755 --- a/t/t1400-update-ref.sh +++ b/t/t1400-update-ref.sh @@ -40,7 +40,7 @@ test_expect_success \ "git update-ref $m $A && test $A"' = $(cat .git/'"$m"')' test_expect_success \ - "create $m" \ + "create $m with oldvalue verification" \ "git update-ref $m $B $A && test $B"' = $(cat .git/'"$m"')' test_expect_success "fail to delete $m with stale ref" ' @@ -48,31 +48,31 @@ test_expect_success "fail to delete $m with stale ref" ' test $B = "$(cat .git/$m)" ' test_expect_success "delete $m" ' + test_when_finished "rm -f .git/$m" && git update-ref -d $m $B && - ! test -f .git/$m + test_path_is_missing .git/$m ' -rm -f .git/$m -test_expect_success "delete $m without oldvalue verification" " +test_expect_success "delete $m without oldvalue verification" ' + test_when_finished "rm -f .git/$m" && git update-ref $m $A && - test $A = \$(cat .git/$m) && + test $A = $(cat .git/$m) && git update-ref -d $m && - ! test -f .git/$m -" -rm -f .git/$m + test_path_is_missing .git/$m +' -test_expect_success \ - "fail to create $n" \ - "touch .git/$n_dir && - test_must_fail git update-ref $n $A >out 2>err" -rm -f .git/$n_dir out err +test_expect_success "fail to create $n" ' + test_when_finished "rm -f .git/$n_dir" && + touch .git/$n_dir && + test_must_fail git update-ref $n $A +' test_expect_success \ "create $m (by HEAD)" \ "git update-ref HEAD $A && test $A"' = $(cat .git/'"$m"')' test_expect_success \ - "create $m (by HEAD)" \ + "create $m (by HEAD) with oldvalue verification" \ "git update-ref HEAD $B $A && test $B"' = $(cat .git/'"$m"')' test_expect_success "fail to delete $m (by HEAD) with stale ref" ' @@ -80,28 +80,28 @@ test_expect_success "fail to delete $m (by HEAD) with stale ref" ' test $B = $(cat .git/$m) ' test_expect_success "delete $m (by HEAD)" ' + test_when_finished "rm -f .git/$m" && git update-ref -d HEAD $B && - ! test -f .git/$m + test_path_is_missing .git/$m ' -rm -f .git/$m test_expect_success "deleting current branch adds message to HEAD's log" ' + test_when_finished "rm -f .git/$m" && git update-ref $m $A && git symbolic-ref HEAD $m && git update-ref -m delete-$m -d $m && - ! test -f .git/$m && + test_path_is_missing .git/$m && grep "delete-$m$" .git/logs/HEAD ' -rm -f .git/$m test_expect_success "deleting by HEAD adds message to HEAD's log" ' + test_when_finished "rm -f .git/$m" && git update-ref $m $A && git symbolic-ref HEAD $m && git update-ref -m delete-by-head -d HEAD && - ! test -f .git/$m && + test_path_is_missing .git/$m && grep "delete-by-head$" .git/logs/HEAD ' -rm -f .git/$m test_expect_success 'update-ref does not create reflogs by default' ' test_when_finished "git update-ref -d $outside" && @@ -188,28 +188,29 @@ test_expect_success \ "git update-ref HEAD $B $A && test $B"' = $(cat .git/'"$m"')' test_expect_success "delete $m (by HEAD) should remove both packed and loose $m" ' + test_when_finished "rm -f .git/$m" && git update-ref -d HEAD $B && ! grep "$m" .git/packed-refs && - ! test -f .git/$m + test_path_is_missing .git/$m ' -rm -f .git/$m cp -f .git/HEAD .git/HEAD.orig test_expect_success "delete symref without dereference" ' + test_when_finished "cp -f .git/HEAD.orig .git/HEAD" && git update-ref --no-deref -d HEAD && - ! test -f .git/HEAD + test_path_is_missing .git/HEAD ' -cp -f .git/HEAD.orig .git/HEAD test_expect_success "delete symref without dereference when the referred ref is packed" ' + test_when_finished "cp -f .git/HEAD.orig .git/HEAD" && echo foo >foo.c && git add foo.c && git commit -m foo && git pack-refs --all && git update-ref --no-deref -d HEAD && - ! test -f .git/HEAD + test_path_is_missing .git/HEAD ' -cp -f .git/HEAD.orig .git/HEAD + git update-ref -d $m test_expect_success 'update-ref -d is not confused by self-reference' ' @@ -241,10 +242,10 @@ test_expect_success 'update-ref --no-deref -d can delete reference to bad ref' ' test_expect_success '(not) create HEAD with old sha1' " test_must_fail git update-ref HEAD $A $B " -test_expect_success "(not) prior created .git/$m" " - ! test -f .git/$m -" -rm -f .git/$m +test_expect_success "(not) prior created .git/$m" ' + test_when_finished "rm -f .git/$m" && + test_path_is_missing .git/$m +' test_expect_success \ "create HEAD" \ @@ -252,38 +253,41 @@ test_expect_success \ test_expect_success '(not) change HEAD with wrong SHA1' " test_must_fail git update-ref HEAD $B $Z " -test_expect_success "(not) changed .git/$m" " - ! test $B"' = $(cat .git/'"$m"') +test_expect_success "(not) changed .git/$m" ' + test_when_finished "rm -f .git/$m" && + ! test $B = $(cat .git/$m) ' -rm -f .git/$m rm -f .git/logs/refs/heads/master test_expect_success \ "create $m (logged by touch)" \ - 'GIT_COMMITTER_DATE="2005-05-26 23:30" \ + 'test_config core.logAllRefUpdates false && + GIT_COMMITTER_DATE="2005-05-26 23:30" \ git update-ref --create-reflog HEAD '"$A"' -m "Initial Creation" && test '"$A"' = $(cat .git/'"$m"')' test_expect_success \ "update $m (logged by touch)" \ - 'GIT_COMMITTER_DATE="2005-05-26 23:31" \ + 'test_config core.logAllRefUpdates false && + GIT_COMMITTER_DATE="2005-05-26 23:31" \ git update-ref HEAD'" $B $A "'-m "Switch" && test '"$B"' = $(cat .git/'"$m"')' test_expect_success \ "set $m (logged by touch)" \ - 'GIT_COMMITTER_DATE="2005-05-26 23:41" \ + 'test_config core.logAllRefUpdates false && + GIT_COMMITTER_DATE="2005-05-26 23:41" \ git update-ref HEAD'" $A && test $A"' = $(cat .git/'"$m"')' test_expect_success "empty directory removal" ' git branch d1/d2/r1 HEAD && git branch d1/r2 HEAD && - test -f .git/refs/heads/d1/d2/r1 && - test -f .git/logs/refs/heads/d1/d2/r1 && + test_path_is_file .git/refs/heads/d1/d2/r1 && + test_path_is_file .git/logs/refs/heads/d1/d2/r1 && git branch -d d1/d2/r1 && - ! test -e .git/refs/heads/d1/d2 && - ! test -e .git/logs/refs/heads/d1/d2 && - test -f .git/refs/heads/d1/r2 && - test -f .git/logs/refs/heads/d1/r2 + test_path_is_missing .git/refs/heads/d1/d2 && + test_path_is_missing .git/logs/refs/heads/d1/d2 && + test_path_is_file .git/refs/heads/d1/r2 && + test_path_is_file .git/logs/refs/heads/d1/r2 ' test_expect_success "symref empty directory removal" ' @@ -291,14 +295,14 @@ test_expect_success "symref empty directory removal" ' git branch e1/r2 HEAD && git checkout e1/e2/r1 && test_when_finished "git checkout master" && - test -f .git/refs/heads/e1/e2/r1 && - test -f .git/logs/refs/heads/e1/e2/r1 && + test_path_is_file .git/refs/heads/e1/e2/r1 && + test_path_is_file .git/logs/refs/heads/e1/e2/r1 && git update-ref -d HEAD && - ! test -e .git/refs/heads/e1/e2 && - ! test -e .git/logs/refs/heads/e1/e2 && - test -f .git/refs/heads/e1/r2 && - test -f .git/logs/refs/heads/e1/r2 && - test -f .git/logs/HEAD + test_path_is_missing .git/refs/heads/e1/e2 && + test_path_is_missing .git/logs/refs/heads/e1/e2 && + test_path_is_file .git/refs/heads/e1/r2 && + test_path_is_file .git/logs/refs/heads/e1/r2 && + test_path_is_file .git/logs/HEAD ' cat >expect <<EOF @@ -306,29 +310,27 @@ $Z $A $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 Initial Creati $A $B $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150260 +0000 Switch $B $A $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150860 +0000 EOF -test_expect_success \ - "verifying $m's log" \ - "test_cmp expect .git/logs/$m" -rm -rf .git/$m .git/logs expect - -test_expect_success \ - 'enable core.logAllRefUpdates' \ - 'git config core.logAllRefUpdates true && - test true = $(git config --bool --get core.logAllRefUpdates)' +test_expect_success "verifying $m's log (logged by touch)" ' + test_when_finished "rm -rf .git/$m .git/logs expect" && + test_cmp expect .git/logs/$m +' test_expect_success \ "create $m (logged by config)" \ - 'GIT_COMMITTER_DATE="2005-05-26 23:32" \ + 'test_config core.logAllRefUpdates true && + GIT_COMMITTER_DATE="2005-05-26 23:32" \ git update-ref HEAD'" $A "'-m "Initial Creation" && test '"$A"' = $(cat .git/'"$m"')' test_expect_success \ "update $m (logged by config)" \ - 'GIT_COMMITTER_DATE="2005-05-26 23:33" \ + 'test_config core.logAllRefUpdates true && + GIT_COMMITTER_DATE="2005-05-26 23:33" \ git update-ref HEAD'" $B $A "'-m "Switch" && test '"$B"' = $(cat .git/'"$m"')' test_expect_success \ "set $m (logged by config)" \ - 'GIT_COMMITTER_DATE="2005-05-26 23:43" \ + 'test_config core.logAllRefUpdates true && + GIT_COMMITTER_DATE="2005-05-26 23:43" \ git update-ref HEAD '"$A && test $A"' = $(cat .git/'"$m"')' @@ -338,9 +340,9 @@ $A $B $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150380 +0000 Switch $B $A $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150980 +0000 EOF test_expect_success \ - "verifying $m's log" \ - 'test_cmp expect .git/logs/$m' -rm -f .git/$m .git/logs/$m expect + "verifying $m's log (logged by config)" \ + 'test_when_finished "rm -f .git/$m .git/logs/$m expect" && + test_cmp expect .git/logs/$m' git update-ref $m $D cat >.git/logs/$m <<EOF @@ -356,55 +358,55 @@ gd="Thu, 26 May 2005 18:33:00 -0500" ld="Thu, 26 May 2005 18:43:00 -0500" test_expect_success \ 'Query "master@{May 25 2005}" (before history)' \ - 'rm -f o e && + 'test_when_finished "rm -f o e" && git rev-parse --verify "master@{May 25 2005}" >o 2>e && test '"$C"' = $(cat o) && test "warning: Log for '\'master\'' only goes back to $ed." = "$(cat e)"' test_expect_success \ "Query master@{2005-05-25} (before history)" \ - 'rm -f o e && + 'test_when_finished "rm -f o e" && git rev-parse --verify master@{2005-05-25} >o 2>e && test '"$C"' = $(cat o) && echo test "warning: Log for '\'master\'' only goes back to $ed." = "$(cat e)"' test_expect_success \ 'Query "master@{May 26 2005 23:31:59}" (1 second before history)' \ - 'rm -f o e && + 'test_when_finished "rm -f o e" && git rev-parse --verify "master@{May 26 2005 23:31:59}" >o 2>e && test '"$C"' = $(cat o) && test "warning: Log for '\''master'\'' only goes back to $ed." = "$(cat e)"' test_expect_success \ 'Query "master@{May 26 2005 23:32:00}" (exactly history start)' \ - 'rm -f o e && + 'test_when_finished "rm -f o e" && git rev-parse --verify "master@{May 26 2005 23:32:00}" >o 2>e && test '"$C"' = $(cat o) && test "" = "$(cat e)"' test_expect_success \ 'Query "master@{May 26 2005 23:32:30}" (first non-creation change)' \ - 'rm -f o e && + 'test_when_finished "rm -f o e" && git rev-parse --verify "master@{May 26 2005 23:32:30}" >o 2>e && test '"$A"' = $(cat o) && test "" = "$(cat e)"' test_expect_success \ 'Query "master@{2005-05-26 23:33:01}" (middle of history with gap)' \ - 'rm -f o e && + 'test_when_finished "rm -f o e" && git rev-parse --verify "master@{2005-05-26 23:33:01}" >o 2>e && test '"$B"' = $(cat o) && test "warning: Log for ref '"$m has gap after $gd"'." = "$(cat e)"' test_expect_success \ 'Query "master@{2005-05-26 23:38:00}" (middle of history)' \ - 'rm -f o e && + 'test_when_finished "rm -f o e" && git rev-parse --verify "master@{2005-05-26 23:38:00}" >o 2>e && test '"$Z"' = $(cat o) && test "" = "$(cat e)"' test_expect_success \ 'Query "master@{2005-05-26 23:43:00}" (exact end of history)' \ - 'rm -f o e && + 'test_when_finished "rm -f o e" && git rev-parse --verify "master@{2005-05-26 23:43:00}" >o 2>e && test '"$E"' = $(cat o) && test "" = "$(cat e)"' test_expect_success \ 'Query "master@{2005-05-28}" (past end of history)' \ - 'rm -f o e && + 'test_when_finished "rm -f o e" && git rev-parse --verify "master@{2005-05-28}" >o 2>e && test '"$D"' = $(cat o) && test "warning: Log for ref '"$m unexpectedly ended on $ld"'." = "$(cat e)"' @@ -414,7 +416,8 @@ rm -f .git/$m .git/logs/$m expect test_expect_success \ 'creating initial files' \ - 'echo TEST >F && + 'test_when_finished rm -f M && + echo TEST >F && git add F && GIT_AUTHOR_DATE="2005-05-26 23:30" \ GIT_COMMITTER_DATE="2005-05-26 23:30" git commit -m add -a && @@ -432,8 +435,7 @@ test_expect_success \ echo $h_TEST >.git/MERGE_HEAD && GIT_AUTHOR_DATE="2005-05-26 23:45" \ GIT_COMMITTER_DATE="2005-05-26 23:45" git commit -F M && - h_MERGED=$(git rev-parse --verify HEAD) && - rm -f M' + h_MERGED=$(git rev-parse --verify HEAD)' cat >expect <<EOF $Z $h_TEST $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 commit (initial): add diff --git a/t/t1507-rev-parse-upstream.sh b/t/t1507-rev-parse-upstream.sh index 46ef1f22dc..b23c4e3fab 100755 --- a/t/t1507-rev-parse-upstream.sh +++ b/t/t1507-rev-parse-upstream.sh @@ -46,11 +46,14 @@ error_message () { } test_expect_success '@{upstream} resolves to correct full name' ' - test refs/remotes/origin/master = "$(full_name @{upstream})" + test refs/remotes/origin/master = "$(full_name @{upstream})" && + test refs/remotes/origin/master = "$(full_name @{UPSTREAM})" && + test refs/remotes/origin/master = "$(full_name @{UpSTReam})" ' test_expect_success '@{u} resolves to correct full name' ' - test refs/remotes/origin/master = "$(full_name @{u})" + test refs/remotes/origin/master = "$(full_name @{u})" && + test refs/remotes/origin/master = "$(full_name @{U})" ' test_expect_success 'my-side@{upstream} resolves to correct full name' ' @@ -60,6 +63,8 @@ test_expect_success 'my-side@{upstream} resolves to correct full name' ' test_expect_success 'upstream of branch with @ in middle' ' full_name fun@ny@{u} >actual && echo refs/remotes/origin/side >expect && + test_cmp expect actual && + full_name fun@ny@{U} >actual && test_cmp expect actual ' @@ -96,12 +101,14 @@ test_expect_success 'not-tracking@{u} fails' ' test_expect_success '<branch>@{u}@{1} resolves correctly' ' test_commit 6 && (cd clone && git fetch) && - test 5 = $(commit_subject my-side@{u}@{1}) + test 5 = $(commit_subject my-side@{u}@{1}) && + test 5 = $(commit_subject my-side@{U}@{1}) ' test_expect_success '@{u} without specifying branch fails on a detached HEAD' ' git checkout HEAD^0 && - test_must_fail git rev-parse @{u} + test_must_fail git rev-parse @{u} && + test_must_fail git rev-parse @{U} ' test_expect_success 'checkout -b new my-side@{u} forks from the same' ' diff --git a/t/t1514-rev-parse-push.sh b/t/t1514-rev-parse-push.sh index 623a32aa6e..788cc91e45 100755 --- a/t/t1514-rev-parse-push.sh +++ b/t/t1514-rev-parse-push.sh @@ -24,12 +24,16 @@ test_expect_success 'setup' ' test_expect_success '@{push} with default=nothing' ' test_config push.default nothing && - test_must_fail git rev-parse master@{push} + test_must_fail git rev-parse master@{push} && + test_must_fail git rev-parse master@{PUSH} && + test_must_fail git rev-parse master@{PuSH} ' test_expect_success '@{push} with default=simple' ' test_config push.default simple && - resolve master@{push} refs/remotes/origin/master + resolve master@{push} refs/remotes/origin/master && + resolve master@{PUSH} refs/remotes/origin/master && + resolve master@{pUSh} refs/remotes/origin/master ' test_expect_success 'triangular @{push} fails with default=simple' ' diff --git a/t/t2013-checkout-submodule.sh b/t/t2013-checkout-submodule.sh index 6847f75822..e8f70b806f 100755 --- a/t/t2013-checkout-submodule.sh +++ b/t/t2013-checkout-submodule.sh @@ -63,6 +63,12 @@ test_expect_success '"checkout <submodule>" honors submodule.*.ignore from .git/ ! test -s actual ' +KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS=1 +KNOWN_FAILURE_SUBMODULE_RECURSIVE_NESTED=1 +test_submodule_switch_recursing "git checkout --recurse-submodules" + +test_submodule_forced_switch_recursing "git checkout -f --recurse-submodules" + test_submodule_switch "git checkout" test_submodule_forced_switch "git checkout -f" diff --git a/t/t3007-ls-files-recurse-submodules.sh b/t/t3007-ls-files-recurse-submodules.sh index a5426171d3..4cf6ccf5a8 100755 --- a/t/t3007-ls-files-recurse-submodules.sh +++ b/t/t3007-ls-files-recurse-submodules.sh @@ -188,6 +188,45 @@ test_expect_success '--recurse-submodules and pathspecs' ' test_cmp expect actual ' +test_expect_success '--recurse-submodules and relative paths' ' + # From subdir + cat >expect <<-\EOF && + b + EOF + git -C b ls-files --recurse-submodules >actual && + test_cmp expect actual && + + # Relative path to top + cat >expect <<-\EOF && + ../.gitmodules + ../a + b + ../h.txt + ../sib/file + ../sub/file + ../submodule/.gitmodules + ../submodule/c + ../submodule/f.TXT + ../submodule/g.txt + ../submodule/subsub/d + ../submodule/subsub/e.txt + EOF + git -C b ls-files --recurse-submodules -- .. >actual && + test_cmp expect actual && + + # Relative path to submodule + cat >expect <<-\EOF && + ../submodule/.gitmodules + ../submodule/c + ../submodule/f.TXT + ../submodule/g.txt + ../submodule/subsub/d + ../submodule/subsub/e.txt + EOF + git -C b ls-files --recurse-submodules -- ../submodule >actual && + test_cmp expect actual +' + test_expect_success '--recurse-submodules does not support --error-unmatch' ' test_must_fail git ls-files --recurse-submodules --error-unmatch 2>actual && test_i18ngrep "does not support --error-unmatch" actual diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index 9f353c0efc..fe62e7c775 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -978,6 +978,10 @@ test_expect_success '--merged catches invalid object names' ' test_must_fail git branch --merged 0000000000000000000000000000000000000000 ' +test_expect_success '--merged is incompatible with --no-merged' ' + test_must_fail git branch --merged HEAD --no-merged HEAD +' + test_expect_success 'tracking with unexpected .fetch refspec' ' rm -rf a b c d && git init a && diff --git a/t/t3201-branch-contains.sh b/t/t3201-branch-contains.sh index 7f3ec47241..0ef1b6fdcc 100755 --- a/t/t3201-branch-contains.sh +++ b/t/t3201-branch-contains.sh @@ -1,6 +1,6 @@ #!/bin/sh -test_description='branch --contains <commit>, --merged, and --no-merged' +test_description='branch --contains <commit>, --no-contains <commit> --merged, and --no-merged' . ./test-lib.sh @@ -45,6 +45,22 @@ test_expect_success 'branch --contains master' ' ' +test_expect_success 'branch --no-contains=master' ' + + git branch --no-contains=master >actual && + >expect && + test_cmp expect actual + +' + +test_expect_success 'branch --no-contains master' ' + + git branch --no-contains master >actual && + >expect && + test_cmp expect actual + +' + test_expect_success 'branch --contains=side' ' git branch --contains=side >actual && @@ -55,6 +71,16 @@ test_expect_success 'branch --contains=side' ' ' +test_expect_success 'branch --no-contains=side' ' + + git branch --no-contains=side >actual && + { + echo " master" + } >expect && + test_cmp expect actual + +' + test_expect_success 'branch --contains with pattern implies --list' ' git branch --contains=master master >actual && @@ -65,6 +91,14 @@ test_expect_success 'branch --contains with pattern implies --list' ' ' +test_expect_success 'branch --no-contains with pattern implies --list' ' + + git branch --no-contains=master master >actual && + >expect && + test_cmp expect actual + +' + test_expect_success 'side: branch --merged' ' git branch --merged >actual && @@ -126,8 +160,20 @@ test_expect_success 'branch --no-merged with pattern implies --list' ' test_expect_success 'implicit --list conflicts with modification options' ' test_must_fail git branch --contains=master -d && - test_must_fail git branch --contains=master -m foo + test_must_fail git branch --contains=master -m foo && + test_must_fail git branch --no-contains=master -d && + test_must_fail git branch --no-contains=master -m foo + +' +test_expect_success 'Assert that --contains only works on commits, not trees & blobs' ' + test_must_fail git branch --contains master^{tree} && + blob=$(git hash-object -w --stdin <<-\EOF + Some blob + EOF + ) && + test_must_fail git branch --contains $blob && + test_must_fail git branch --no-contains $blob ' # We want to set up a case where the walk for the tracking info @@ -159,4 +205,15 @@ test_expect_success 'branch --merged with --verbose' ' test_i18ncmp expect actual ' +test_expect_success 'branch --contains combined with --no-contains' ' + git branch --contains zzz --no-contains topic >actual && + cat >expect <<-\EOF && + master + side + zzz + EOF + test_cmp expect actual + +' + test_done diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh index 5aa6db584c..5f9913ba33 100755 --- a/t/t3600-rm.sh +++ b/t/t3600-rm.sh @@ -268,6 +268,14 @@ cat >expect.modified <<EOF M submod EOF +cat >expect.modified_inside <<EOF + m submod +EOF + +cat >expect.modified_untracked <<EOF + ? submod +EOF + cat >expect.cached <<EOF D submod EOF @@ -421,7 +429,7 @@ test_expect_success 'rm of a populated submodule with modifications fails unless test -d submod && test -f submod/.git && git status -s -uno --ignore-submodules=none >actual && - test_cmp expect.modified actual && + test_cmp expect.modified_inside actual && git rm -f submod && test ! -d submod && git status -s -uno --ignore-submodules=none >actual && @@ -436,7 +444,7 @@ test_expect_success 'rm of a populated submodule with untracked files fails unle test -d submod && test -f submod/.git && git status -s -uno --ignore-submodules=none >actual && - test_cmp expect.modified actual && + test_cmp expect.modified_untracked actual && git rm -f submod && test ! -d submod && git status -s -uno --ignore-submodules=none >actual && @@ -621,7 +629,7 @@ test_expect_success 'rm of a populated nested submodule with different nested HE test -d submod && test -f submod/.git && git status -s -uno --ignore-submodules=none >actual && - test_cmp expect.modified actual && + test_cmp expect.modified_inside actual && git rm -f submod && test ! -d submod && git status -s -uno --ignore-submodules=none >actual && @@ -636,7 +644,7 @@ test_expect_success 'rm of a populated nested submodule with nested modification test -d submod && test -f submod/.git && git status -s -uno --ignore-submodules=none >actual && - test_cmp expect.modified actual && + test_cmp expect.modified_inside actual && git rm -f submod && test ! -d submod && git status -s -uno --ignore-submodules=none >actual && @@ -651,14 +659,14 @@ test_expect_success 'rm of a populated nested submodule with nested untracked fi test -d submod && test -f submod/.git && git status -s -uno --ignore-submodules=none >actual && - test_cmp expect.modified actual && + test_cmp expect.modified_untracked actual && git rm -f submod && test ! -d submod && git status -s -uno --ignore-submodules=none >actual && test_cmp expect actual ' -test_expect_success 'rm of a populated nested submodule with a nested .git directory fails even when forced' ' +test_expect_success "rm absorbs submodule's nested .git directory" ' git reset --hard && git submodule update --recursive && (cd submod/subsubmod && diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh index 89877e4b52..b71d1e659e 100755 --- a/t/t3903-stash.sh +++ b/t/t3903-stash.sh @@ -663,7 +663,7 @@ test_expect_success 'stash apply shows status same as git status (relative to cu sane_unset GIT_MERGE_VERBOSITY && git stash apply ) | - sed -e 1,2d >actual && # drop "Saved..." and "HEAD is now..." + sed -e 1d >actual && # drop "Saved..." test_i18ncmp expect actual ' @@ -907,4 +907,18 @@ test_expect_success 'stash without verb with pathspec' ' test_path_is_file bar ' +test_expect_success 'stash -k -- <pathspec> leaves unstaged files intact' ' + git reset && + >foo && + >bar && + git add foo bar && + git commit -m "test" && + echo "foo" >foo && + echo "bar" >bar && + git stash -k -- foo && + test "",bar = $(cat foo),$(cat bar) && + git stash pop && + test foo,bar = $(cat foo),$(cat bar) +' + test_done diff --git a/t/t3904-stash-patch.sh b/t/t3904-stash-patch.sh index 38e730090f..83744f8c93 100755 --- a/t/t3904-stash-patch.sh +++ b/t/t3904-stash-patch.sh @@ -77,6 +77,14 @@ test_expect_success 'git stash --no-keep-index -p' ' verify_state dir/foo work index ' +test_expect_success 'stash -p --no-keep-index -- <pathspec> does not unstage other files' ' + set_state HEAD HEADfile_work HEADfile_index && + set_state dir/foo work index && + echo y | git stash push -p --no-keep-index -- HEAD && + verify_state HEAD committed committed && + verify_state dir/foo work index +' + test_expect_success 'none of this moved HEAD' ' verify_saved_head ' diff --git a/t/t4060-diff-submodule-option-diff-format.sh b/t/t4060-diff-submodule-option-diff-format.sh index 7e23b55ea4..d4a3ffa69c 100755 --- a/t/t4060-diff-submodule-option-diff-format.sh +++ b/t/t4060-diff-submodule-option-diff-format.sh @@ -746,4 +746,33 @@ test_expect_success 'diff --submodule=diff with .git file' ' test_cmp expected actual ' +test_expect_success 'setup nested submodule' ' + git submodule add -f ./sm2 && + git commit -a -m "add sm2" && + git -C sm2 submodule add ../sm2 nested && + git -C sm2 commit -a -m "nested sub" +' + +test_expect_success 'move nested submodule HEAD' ' + echo "nested content" >sm2/nested/file && + git -C sm2/nested add file && + git -C sm2/nested commit --allow-empty -m "new HEAD" +' + +test_expect_success 'diff --submodule=diff with moved nested submodule HEAD' ' + cat >expected <<-EOF && + Submodule nested a5a65c9..b55928c: + diff --git a/nested/file b/nested/file + new file mode 100644 + index 0000000..ca281f5 + --- /dev/null + +++ b/nested/file + @@ -0,0 +1 @@ + +nested content + EOF + git -C sm2 diff --submodule=diff >actual 2>err && + test_must_be_empty err && + test_cmp expected actual +' + test_done diff --git a/t/t4062-diff-pickaxe.sh b/t/t4062-diff-pickaxe.sh index f0bf50bda7..7c4903f497 100755 --- a/t/t4062-diff-pickaxe.sh +++ b/t/t4062-diff-pickaxe.sh @@ -19,4 +19,9 @@ test_expect_success '-G matches' ' test 4096-zeroes.txt = "$(cat out)" ' +test_expect_success '-S --pickaxe-regex' ' + git diff --name-only -S0 --pickaxe-regex HEAD^ >out && + verbose test 4096-zeroes.txt = "$(cat out)" +' + test_done diff --git a/t/t4150-am.sh b/t/t4150-am.sh index 89a5bacac5..44807e218d 100755 --- a/t/t4150-am.sh +++ b/t/t4150-am.sh @@ -983,7 +983,9 @@ test_expect_success 'am works with multi-line in-body headers' ' rm -fr .git/rebase-apply && git checkout -f first && echo one >> file && - git commit -am "$LONG" --author="$LONG <long@example.com>" && + git commit -am "$LONG + + Body test" --author="$LONG <long@example.com>" && git format-patch --stdout -1 >patch && # bump from, date, and subject down to in-body header perl -lpe " @@ -997,7 +999,7 @@ test_expect_success 'am works with multi-line in-body headers' ' git am msg && # Ensure that the author and full message are present git cat-file commit HEAD | grep "^author.*long@example.com" && - git cat-file commit HEAD | grep "^$LONG" + git cat-file commit HEAD | grep "^$LONG$" ' test_done diff --git a/t/t4202-log.sh b/t/t4202-log.sh index 48b55bfd27..f577990716 100755 --- a/t/t4202-log.sh +++ b/t/t4202-log.sh @@ -4,6 +4,7 @@ test_description='git log' . ./test-lib.sh . "$TEST_DIRECTORY/lib-gpg.sh" +. "$TEST_DIRECTORY/lib-terminal.sh" test_expect_success setup ' @@ -520,7 +521,7 @@ test_expect_success 'log --graph with merge' ' ' test_expect_success 'log.decorate configuration' ' - git log --oneline >expect.none && + git log --oneline --no-decorate >expect.none && git log --oneline --decorate >expect.short && git log --oneline --decorate=full >expect.full && @@ -576,6 +577,13 @@ test_expect_success 'log.decorate configuration' ' ' +test_expect_success TTY 'log output on a TTY' ' + git log --oneline --decorate >expect.short && + + test_terminal git log --oneline >actual && + test_cmp expect.short actual +' + test_expect_success 'reflog is expected format' ' git log -g --abbrev-commit --pretty=oneline >expect && git reflog >actual && diff --git a/t/t5531-deep-submodule-push.sh b/t/t5531-deep-submodule-push.sh index f55137f76f..57ba322628 100755 --- a/t/t5531-deep-submodule-push.sh +++ b/t/t5531-deep-submodule-push.sh @@ -475,4 +475,56 @@ test_expect_success 'push only unpushed submodules recursively' ' test_cmp expected_pub actual_pub ' +test_expect_success 'push propagating the remotes name to a submodule' ' + git -C work remote add origin ../pub.git && + git -C work remote add pub ../pub.git && + + > work/gar/bage/junk10 && + git -C work/gar/bage add junk10 && + git -C work/gar/bage commit -m "Tenth junk" && + git -C work add gar/bage && + git -C work commit -m "Tenth junk added to gar/bage" && + + # Fails when submodule does not have a matching remote + test_must_fail git -C work push --recurse-submodules=on-demand pub master && + # Succeeds when submodules has matching remote and refspec + git -C work push --recurse-submodules=on-demand origin master && + + git -C submodule.git rev-parse master >actual_submodule && + git -C pub.git rev-parse master >actual_pub && + git -C work/gar/bage rev-parse master >expected_submodule && + git -C work rev-parse master >expected_pub && + test_cmp expected_submodule actual_submodule && + test_cmp expected_pub actual_pub +' + +test_expect_success 'push propagating refspec to a submodule' ' + > work/gar/bage/junk11 && + git -C work/gar/bage add junk11 && + git -C work/gar/bage commit -m "Eleventh junk" && + + git -C work checkout branch2 && + git -C work add gar/bage && + git -C work commit -m "updating gar/bage in branch2" && + + # Fails when submodule does not have a matching branch + test_must_fail git -C work push --recurse-submodules=on-demand origin branch2 && + # 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 + test_must_fail git -C work push --recurse-submodules=on-demand origin \ + HEAD:refs/heads/branch2 && + + git -C work/gar/bage branch branch2 master && + git -C work push --recurse-submodules=on-demand origin 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/t5545-push-options.sh b/t/t5545-push-options.sh index 9a57a7d8f2..f9232f5d0f 100755 --- a/t/t5545-push-options.sh +++ b/t/t5545-push-options.sh @@ -102,17 +102,86 @@ test_expect_success 'two push options work' ' test_cmp expect upstream/.git/hooks/post-receive.push_options ' -test_expect_success 'push option denied properly by http remote helper' '\ +test_expect_success 'push option denied properly by http server' ' + test_when_finished "rm -rf test_http_clone" && + test_when_finished "rm -rf \"$HTTPD_DOCUMENT_ROOT_PATH\"/upstream.git" && mk_repo_pair && git -C upstream config receive.advertisePushOptions false && git -C upstream config http.receivepack true && cp -R upstream/.git "$HTTPD_DOCUMENT_ROOT_PATH"/upstream.git && git clone "$HTTPD_URL"/smart/upstream test_http_clone && test_commit -C test_http_clone one && - test_must_fail git -C test_http_clone push --push-option=asdf origin master && + test_must_fail git -C test_http_clone push --push-option=asdf origin master 2>actual && + test_i18ngrep "the receiving end does not support push options" actual && git -C test_http_clone push origin master ' +test_expect_success 'push options work properly across http' ' + test_when_finished "rm -rf test_http_clone" && + test_when_finished "rm -rf \"$HTTPD_DOCUMENT_ROOT_PATH\"/upstream.git" && + mk_repo_pair && + git -C upstream config receive.advertisePushOptions true && + git -C upstream config http.receivepack true && + cp -R upstream/.git "$HTTPD_DOCUMENT_ROOT_PATH"/upstream.git && + git clone "$HTTPD_URL"/smart/upstream test_http_clone && + + test_commit -C test_http_clone one && + git -C test_http_clone push origin master && + git -C "$HTTPD_DOCUMENT_ROOT_PATH"/upstream.git rev-parse --verify master >expect && + git -C test_http_clone rev-parse --verify master >actual && + test_cmp expect actual && + + test_commit -C test_http_clone two && + git -C test_http_clone push --push-option=asdf --push-option="more structured text" origin master && + printf "asdf\nmore structured text\n" >expect && + test_cmp expect "$HTTPD_DOCUMENT_ROOT_PATH"/upstream.git/hooks/pre-receive.push_options && + test_cmp expect "$HTTPD_DOCUMENT_ROOT_PATH"/upstream.git/hooks/post-receive.push_options && + + git -C "$HTTPD_DOCUMENT_ROOT_PATH"/upstream.git rev-parse --verify master >expect && + git -C test_http_clone rev-parse --verify master >actual && + test_cmp expect actual +' + +test_expect_success 'push options and submodules' ' + test_when_finished "rm -rf parent" && + test_when_finished "rm -rf parent_upstream" && + mk_repo_pair && + git -C upstream config receive.advertisePushOptions true && + cp -r upstream parent_upstream && + test_commit -C upstream one && + + test_create_repo parent && + git -C parent remote add up ../parent_upstream && + test_commit -C parent one && + git -C parent push --mirror up && + + git -C parent submodule add ../upstream workbench && + git -C parent/workbench remote add up ../../upstream && + git -C parent commit -m "add submoule" && + + test_commit -C parent/workbench two && + git -C parent add workbench && + git -C parent commit -m "update workbench" && + + git -C parent push \ + --push-option=asdf --push-option="more structured text" \ + --recurse-submodules=on-demand up master && + + git -C upstream rev-parse --verify master >expect && + git -C parent/workbench rev-parse --verify master >actual && + test_cmp expect actual && + + git -C parent_upstream rev-parse --verify master >expect && + git -C parent rev-parse --verify master >actual && + test_cmp expect actual && + + printf "asdf\nmore structured text\n" >expect && + test_cmp expect upstream/.git/hooks/pre-receive.push_options && + test_cmp expect upstream/.git/hooks/post-receive.push_options && + test_cmp expect parent_upstream/.git/hooks/pre-receive.push_options && + test_cmp expect parent_upstream/.git/hooks/post-receive.push_options +' + stop_httpd test_done diff --git a/t/t5615-alternate-env.sh b/t/t5615-alternate-env.sh index 26ebb0375d..d2d883f3a1 100755 --- a/t/t5615-alternate-env.sh +++ b/t/t5615-alternate-env.sh @@ -77,6 +77,7 @@ test_expect_success 'mix of quoted and unquoted alternates' ' check_obj "$quoted:$unquoted" <<-EOF $one blob $two blob + EOF ' test_expect_success !MINGW 'broken quoting falls back to interpreting raw' ' diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh index 167491fd5b..16952e44fc 100755 --- a/t/t6120-describe.sh +++ b/t/t6120-describe.sh @@ -233,4 +233,24 @@ test_expect_success 'describe --contains and --no-match' ' test_cmp expect actual ' +test_expect_success 'setup and absorb a submodule' ' + test_create_repo sub1 && + test_commit -C sub1 initial && + git submodule add ./sub1 && + git submodule absorbgitdirs && + git commit -a -m "add submodule" && + git describe --dirty >expect && + git describe --broken >out && + test_cmp expect out +' + +test_expect_success 'describe chokes on severly broken submodules' ' + mv .git/modules/sub1/ .git/modules/sub_moved && + test_must_fail git describe --dirty +' +test_expect_success 'describe ignoring a borken submodule' ' + git describe --broken >out && + grep broken out +' + test_done diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh index a09a1a46ef..fc067ed672 100755 --- a/t/t6302-for-each-ref-filter.sh +++ b/t/t6302-for-each-ref-filter.sh @@ -93,6 +93,22 @@ test_expect_success 'filtering with --contains' ' test_cmp expect actual ' +test_expect_success 'filtering with --no-contains' ' + cat >expect <<-\EOF && + refs/tags/one + EOF + git for-each-ref --format="%(refname)" --no-contains=two >actual && + test_cmp expect actual +' + +test_expect_success 'filtering with --contains and --no-contains' ' + cat >expect <<-\EOF && + refs/tags/two + EOF + git for-each-ref --format="%(refname)" --contains=two --no-contains=three >actual && + test_cmp expect actual +' + test_expect_success '%(color) must fail' ' test_must_fail git for-each-ref --format="%(color)%(refname)" ' @@ -421,4 +437,8 @@ test_expect_success 'check %(if:notequals=<string>)' ' test_cmp expect actual ' +test_expect_success '--merged is incompatible with --no-merged' ' + test_must_fail git for-each-ref --merged HEAD --no-merged HEAD +' + test_done diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index b4698ab5f5..bb2e4d704d 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -16,7 +16,6 @@ tag_exists () { git show-ref --quiet --verify refs/tags/"$1" } -# todo: git tag -l now returns always zero, when fixed, change this test test_expect_success 'listing all tags in an empty tree should succeed' ' git tag -l && git tag @@ -119,6 +118,18 @@ test_expect_success 'listing all tags if one exists should succeed' ' git tag ' +cat >expect <<EOF +mytag +EOF +test_expect_success 'Multiple -l or --list options are equivalent to one -l option' ' + git tag -l -l >actual && + test_cmp expect actual && + git tag --list --list >actual && + test_cmp expect actual && + git tag --list -l --list >actual && + test_cmp expect actual +' + test_expect_success 'listing all tags if one exists should output that tag' ' test $(git tag -l) = mytag && test $(git tag) = mytag @@ -136,9 +147,8 @@ test_expect_success \ 'listing a tag using a matching pattern should output that tag' \ 'test $(git tag -l mytag) = mytag' -# todo: git tag -l now returns always zero, when fixed, change this test test_expect_success \ - 'listing tags using a non-matching pattern should suceed' \ + 'listing tags using a non-matching pattern should succeed' \ 'git tag -l xxx' test_expect_success \ @@ -338,6 +348,19 @@ test_expect_success 'tag -l can accept multiple patterns' ' test_cmp expect actual ' +# Between v1.7.7 & v2.13.0 a fair reading of the git-tag documentation +# could leave you with the impression that "-l <pattern> -l <pattern>" +# was how we wanted to accept multiple patterns. +# +# This test should not imply that this is a sane thing to support. but +# since the documentation was worded like it was let's at least find +# out if we're going to break this long-documented form of taking +# multiple patterns. +test_expect_success 'tag -l <pattern> -l <pattern> works, as our buggy documentation previously suggested' ' + git tag -l "v1*" -l "v0*" >actual && + test_cmp expect actual +' + test_expect_success 'listing tags in column' ' COLUMNS=40 git tag -l --column=row >actual && cat >expected <<\EOF && @@ -620,6 +643,11 @@ test_expect_success \ git tag -n0 -l tag-one-line >actual && test_cmp expect actual && + git tag -n0 | grep "^tag-one-line" >actual && + test_cmp expect actual && + git tag -n0 tag-one-line >actual && + test_cmp expect actual && + echo "tag-one-line A msg" >expect && git tag -n1 -l | grep "^tag-one-line" >actual && test_cmp expect actual && @@ -633,6 +661,17 @@ test_expect_success \ test_cmp expect actual ' +test_expect_success 'The -n 100 invocation means -n --list 100, not -n100' ' + >expect && + git tag -n 100 >actual && + test_cmp expect actual && + + git tag -m "A msg" 100 && + echo "100 A msg" >expect && + git tag -n 100 >actual && + test_cmp expect actual +' + test_expect_success \ 'listing the zero-lines message of a non-signed tag should succeed' ' git tag -m "" tag-zero-lines && @@ -895,18 +934,16 @@ test_expect_success GPG 'verifying a forged tag should fail' ' test_must_fail git tag -v forged-tag ' -test_expect_success 'verifying a proper tag with --format pass and format accordingly' ' - cat >expect <<-\EOF +test_expect_success GPG 'verifying a proper tag with --format pass and format accordingly' ' + cat >expect <<-\EOF && tagname : signed-tag - EOF && + EOF git tag -v --format="tagname : %(tag)" "signed-tag" >actual && test_cmp expect actual ' -test_expect_success 'verifying a forged tag with --format fail and format accordingly' ' - cat >expect <<-\EOF - tagname : forged-tag - EOF && +test_expect_success GPG 'verifying a forged tag with --format should fail silently' ' + >expect && test_must_fail git tag -v --format="tagname : %(tag)" "forged-tag" >actual && test_cmp expect actual ' @@ -1385,6 +1422,23 @@ test_expect_success 'checking that first commit is in all tags (relative)' " test_cmp expected actual " +# All the --contains tests above, but with --no-contains +test_expect_success 'checking that first commit is not listed in any tag with --no-contains (hash)' " + >expected && + git tag -l --no-contains $hash1 v* >actual && + test_cmp expected actual +" + +test_expect_success 'checking that first commit is in all tags (tag)' " + git tag -l --no-contains v1.0 v* >actual && + test_cmp expected actual +" + +test_expect_success 'checking that first commit is in all tags (relative)' " + git tag -l --no-contains HEAD~2 v* >actual && + test_cmp expected actual +" + cat > expected <<EOF v2.0 EOF @@ -1394,6 +1448,17 @@ test_expect_success 'checking that second commit only has one tag' " test_cmp expected actual " +cat > expected <<EOF +v0.2.1 +v1.0 +v1.0.1 +v1.1.3 +EOF + +test_expect_success 'inverse of the last test, with --no-contains' " + git tag -l --no-contains $hash2 v* >actual && + test_cmp expected actual +" cat > expected <<EOF EOF @@ -1403,6 +1468,19 @@ test_expect_success 'checking that third commit has no tags' " test_cmp expected actual " +cat > expected <<EOF +v0.2.1 +v1.0 +v1.0.1 +v1.1.3 +v2.0 +EOF + +test_expect_success 'conversely --no-contains on the third commit lists all tags' " + git tag -l --no-contains $hash3 v* >actual && + test_cmp expected actual +" + # how about a simple merge? test_expect_success 'creating simple branch' ' @@ -1424,6 +1502,19 @@ test_expect_success 'checking that branch head only has one tag' " test_cmp expected actual " +cat > expected <<EOF +v0.2.1 +v1.0 +v1.0.1 +v1.1.3 +v2.0 +EOF + +test_expect_success 'checking that branch head with --no-contains lists all but one tag' " + git tag -l --no-contains $hash4 v* >actual && + test_cmp expected actual +" + test_expect_success 'merging original branch into this branch' ' git merge --strategy=ours master && git tag v4.0 @@ -1445,6 +1536,20 @@ v1.0.1 v1.1.3 v2.0 v3.0 +EOF + +test_expect_success 'checking that original branch head with --no-contains lists all but one tag now' " + git tag -l --no-contains $hash3 v* >actual && + test_cmp expected actual +" + +cat > expected <<EOF +v0.2.1 +v1.0 +v1.0.1 +v1.1.3 +v2.0 +v3.0 v4.0 EOF @@ -1453,21 +1558,76 @@ test_expect_success 'checking that initial commit is in all tags' " test_cmp expected actual " +test_expect_success 'checking that --contains can be used in non-list mode' ' + git tag --contains $hash1 v* >actual && + test_cmp expected actual +' + +test_expect_success 'checking that initial commit is in all tags with --no-contains' " + >expected && + git tag -l --no-contains $hash1 v* >actual && + test_cmp expected actual +" + # mixing modes and options: test_expect_success 'mixing incompatibles modes and options is forbidden' ' test_must_fail git tag -a && + test_must_fail git tag -a -l && + test_must_fail git tag -s && + test_must_fail git tag -s -l && + test_must_fail git tag -m && + test_must_fail git tag -m -l && + test_must_fail git tag -m "hlagh" && + test_must_fail git tag -m "hlagh" -l && + test_must_fail git tag -F && + test_must_fail git tag -F -l && + test_must_fail git tag -f && + test_must_fail git tag -f -l && + test_must_fail git tag -a -s -m -F && + test_must_fail git tag -a -s -m -F -l && test_must_fail git tag -l -v && - test_must_fail git tag -n 100 && + test_must_fail git tag -l -d && + test_must_fail git tag -l -v -d && + test_must_fail git tag -n 100 -v && test_must_fail git tag -l -m msg && test_must_fail git tag -l -F some file && - test_must_fail git tag -v -s -' + test_must_fail git tag -v -s && + test_must_fail git tag --contains tag-tree && + test_must_fail git tag --contains tag-blob && + test_must_fail git tag --no-contains tag-tree && + test_must_fail git tag --no-contains tag-blob && + test_must_fail git tag --contains --no-contains && + test_must_fail git tag --no-with HEAD && + test_must_fail git tag --no-without HEAD +' + +for option in --contains --with --no-contains --without --merged --no-merged --points-at +do + test_expect_success "mixing incompatible modes with $option is forbidden" " + test_must_fail git tag -d $option HEAD && + test_must_fail git tag -d $option HEAD some-tag && + test_must_fail git tag -v $option HEAD + " + test_expect_success "Doing 'git tag --list-like $option <commit> <pattern> is permitted" " + git tag -n $option HEAD HEAD && + git tag $option HEAD HEAD && + git tag $option + " +done # check points-at -test_expect_success '--points-at cannot be used in non-list mode' ' - test_must_fail git tag --points-at=v4.0 foo +test_expect_success '--points-at can be used in non-list mode' ' + echo v4.0 >expect && + git tag --points-at=v4.0 "v*" >actual && + test_cmp expect actual +' + +test_expect_success '--points-at is a synonym for --points-at HEAD' ' + echo v4.0 >expect && + git tag --points-at >actual && + test_cmp expect actual ' test_expect_success '--points-at finds lightweight tags' ' @@ -1709,7 +1869,7 @@ run_with_limited_stack () { test_lazy_prereq ULIMIT_STACK_SIZE 'run_with_limited_stack true' # we require ulimit, this excludes Windows -test_expect_success ULIMIT_STACK_SIZE '--contains works in a deep repo' ' +test_expect_success ULIMIT_STACK_SIZE '--contains and --no-contains work in a deep repo' ' >expect && i=1 && while test $i -lt 8000 @@ -1725,7 +1885,9 @@ EOF" git checkout master && git tag far-far-away HEAD^ && run_with_limited_stack git tag --contains HEAD >actual && - test_cmp expect actual + test_cmp expect actual && + run_with_limited_stack git tag --no-contains HEAD >actual && + test_line_count ">" 10 actual ' test_expect_success '--format should list tags as per format given' ' @@ -1744,8 +1906,17 @@ test_expect_success 'setup --merged test tags' ' git tag mergetest-3 HEAD ' -test_expect_success '--merged cannot be used in non-list mode' ' - test_must_fail git tag --merged=mergetest-2 foo +test_expect_success '--merged can be used in non-list mode' ' + cat >expect <<-\EOF && + mergetest-1 + mergetest-2 + EOF + git tag --merged=mergetest-2 "mergetest*" >actual && + test_cmp expect actual +' + +test_expect_success '--merged is incompatible with --no-merged' ' + test_must_fail git tag --merged HEAD --no-merged HEAD ' test_expect_success '--merged shows merged tags' ' @@ -1765,6 +1936,11 @@ test_expect_success '--no-merged show unmerged tags' ' test_cmp expect actual ' +test_expect_success '--no-merged can be used in non-list mode' ' + git tag --no-merged=mergetest-2 mergetest-* >actual && + test_cmp expect actual +' + test_expect_success 'ambiguous branch/tags not marked' ' git tag ambiguous && git branch ambiguous && @@ -1773,4 +1949,47 @@ test_expect_success 'ambiguous branch/tags not marked' ' test_cmp expect actual ' +test_expect_success '--contains combined with --no-contains' ' + ( + git init no-contains && + cd no-contains && + test_commit v0.1 && + test_commit v0.2 && + test_commit v0.3 && + test_commit v0.4 && + test_commit v0.5 && + cat >expected <<-\EOF && + v0.2 + v0.3 + v0.4 + EOF + git tag --contains v0.2 --no-contains v0.5 >actual && + test_cmp expected actual + ) +' + +# As the docs say, list tags which contain a specified *commit*. We +# don't recurse down to tags for trees or blobs pointed to by *those* +# commits. +test_expect_success 'Does --[no-]contains stop at commits? Yes!' ' + cd no-contains && + blob=$(git rev-parse v0.3:v0.3.t) && + tree=$(git rev-parse v0.3^{tree}) && + git tag tag-blob $blob && + git tag tag-tree $tree && + git tag --contains v0.3 >actual && + cat >expected <<-\EOF && + v0.3 + v0.4 + v0.5 + EOF + test_cmp expected actual && + git tag --no-contains v0.3 >actual && + cat >expected <<-\EOF && + v0.1 + v0.2 + EOF + test_cmp expected actual +' + test_done diff --git a/t/t7030-verify-tag.sh b/t/t7030-verify-tag.sh index d62ccbb98e..b4b49eeb08 100755 --- a/t/t7030-verify-tag.sh +++ b/t/t7030-verify-tag.sh @@ -125,18 +125,16 @@ test_expect_success GPG 'verify multiple tags' ' test_cmp expect.stderr actual.stderr ' -test_expect_success 'verifying tag with --format' ' - cat >expect <<-\EOF +test_expect_success GPG 'verifying tag with --format' ' + cat >expect <<-\EOF && tagname : fourth-signed - EOF && + EOF git verify-tag --format="tagname : %(tag)" "fourth-signed" >actual && test_cmp expect actual ' -test_expect_success 'verifying a forged tag with --format fail and format accordingly' ' - cat >expect <<-\EOF - tagname : 7th forged-signed - EOF && +test_expect_success GPG 'verifying a forged tag with --format should fail silently' ' + >expect && test_must_fail git verify-tag --format="tagname : %(tag)" $(cat forged1.tag) >actual-forged && test_cmp expect actual-forged ' diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh index c09ce0d4c1..cf77a3a357 100755 --- a/t/t7400-submodule-basic.sh +++ b/t/t7400-submodule-basic.sh @@ -1130,5 +1130,141 @@ test_expect_success 'submodule helper list is not confused by common prefixes' ' test_cmp expect actual ' +test_expect_success 'setup superproject with submodules' ' + git init sub1 && + test_commit -C sub1 test && + test_commit -C sub1 test2 && + git init multisuper && + git -C multisuper submodule add ../sub1 sub0 && + git -C multisuper submodule add ../sub1 sub1 && + git -C multisuper submodule add ../sub1 sub2 && + git -C multisuper submodule add ../sub1 sub3 && + git -C multisuper commit -m "add some submodules" +' + +cat >expect <<-EOF +-sub0 + sub1 (test2) + sub2 (test2) + sub3 (test2) +EOF + +test_expect_success 'submodule update --init with a specification' ' + test_when_finished "rm -rf multisuper_clone" && + pwd=$(pwd) && + git clone file://"$pwd"/multisuper multisuper_clone && + git -C multisuper_clone submodule update --init . ":(exclude)sub0" && + git -C multisuper_clone submodule status |cut -c 1,43- >actual && + test_cmp expect actual +' + +test_expect_success 'submodule update --init with submodule.active set' ' + test_when_finished "rm -rf multisuper_clone" && + pwd=$(pwd) && + git clone file://"$pwd"/multisuper multisuper_clone && + git -C multisuper_clone config submodule.active "." && + git -C multisuper_clone config --add submodule.active ":(exclude)sub0" && + git -C multisuper_clone submodule update --init && + git -C multisuper_clone submodule status |cut -c 1,43- >actual && + test_cmp expect actual +' + +test_expect_success 'submodule update and setting submodule.<name>.active' ' + test_when_finished "rm -rf multisuper_clone" && + pwd=$(pwd) && + git clone file://"$pwd"/multisuper multisuper_clone && + git -C multisuper_clone config --bool submodule.sub0.active "true" && + git -C multisuper_clone config --bool submodule.sub1.active "false" && + git -C multisuper_clone config --bool submodule.sub2.active "true" && + + cat >expect <<-\EOF && + sub0 (test2) + -sub1 + sub2 (test2) + -sub3 + EOF + git -C multisuper_clone submodule update && + git -C multisuper_clone submodule status |cut -c 1,43- >actual && + test_cmp expect actual +' + +test_expect_success 'clone --recurse-submodules with a pathspec works' ' + test_when_finished "rm -rf multisuper_clone" && + cat >expected <<-\EOF && + sub0 (test2) + -sub1 + -sub2 + -sub3 + EOF + + git clone --recurse-submodules="sub0" multisuper multisuper_clone && + git -C multisuper_clone submodule status |cut -c1,43- >actual && + test_cmp actual expected +' + +test_expect_success 'clone with multiple --recurse-submodules options' ' + test_when_finished "rm -rf multisuper_clone" && + cat >expect <<-\EOF && + -sub0 + sub1 (test2) + -sub2 + sub3 (test2) + EOF + + git clone --recurse-submodules="." \ + --recurse-submodules=":(exclude)sub0" \ + --recurse-submodules=":(exclude)sub2" \ + multisuper multisuper_clone && + git -C multisuper_clone submodule status |cut -c1,43- >actual && + test_cmp expect actual +' + +test_expect_success 'clone and subsequent updates correctly auto-initialize submodules' ' + test_when_finished "rm -rf multisuper_clone" && + cat <<-\EOF >expect && + -sub0 + sub1 (test2) + -sub2 + sub3 (test2) + EOF + + cat <<-\EOF >expect2 && + -sub0 + sub1 (test2) + -sub2 + sub3 (test2) + -sub4 + sub5 (test2) + EOF + + git clone --recurse-submodules="." \ + --recurse-submodules=":(exclude)sub0" \ + --recurse-submodules=":(exclude)sub2" \ + --recurse-submodules=":(exclude)sub4" \ + multisuper multisuper_clone && + + git -C multisuper_clone submodule status |cut -c1,43- >actual && + test_cmp expect actual && + + git -C multisuper submodule add ../sub1 sub4 && + git -C multisuper submodule add ../sub1 sub5 && + git -C multisuper commit -m "add more submodules" && + # obtain the new superproject + git -C multisuper_clone pull && + git -C multisuper_clone submodule update --init && + git -C multisuper_clone submodule status |cut -c1,43- >actual && + test_cmp expect2 actual +' + +test_expect_success 'init properly sets the config' ' + test_when_finished "rm -rf multisuper_clone" && + git clone --recurse-submodules="." \ + --recurse-submodules=":(exclude)sub0" \ + multisuper multisuper_clone && + + git -C multisuper_clone submodule init -- sub0 sub1 && + git -C multisuper_clone config --get submodule.sub0.active && + test_must_fail git -C multisuper_clone config --get submodule.sub1.active +' test_done diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh index 347857fa7c..4ac386d98b 100755 --- a/t/t7406-submodule-update.sh +++ b/t/t7406-submodule-update.sh @@ -442,11 +442,11 @@ test_expect_success 'submodule update - command in .git/config catches failure - ' test_expect_success 'submodule update - command run for initial population of submodule' ' - cat <<-\ EOF >expect + cat >expect <<-EOF && Execution of '\''false $submodulesha1'\'' failed in submodule path '\''submodule'\'' - EOF && + EOF rm -rf super/submodule && - test_must_fail git -C super submodule update >../actual && + test_must_fail git -C super submodule update 2>actual && test_cmp expect actual && git -C super submodule update --checkout ' diff --git a/t/t7413-submodule-is-active.sh b/t/t7413-submodule-is-active.sh new file mode 100755 index 0000000000..9c785b07ec --- /dev/null +++ b/t/t7413-submodule-is-active.sh @@ -0,0 +1,107 @@ +#!/bin/sh + +test_description='Test submodule--helper is-active + +This test verifies that `git submodue--helper is-active` correclty identifies +submodules which are "active" and interesting to the user. +' + +. ./test-lib.sh + +test_expect_success 'setup' ' + git init sub && + test_commit -C sub initial && + git init super && + test_commit -C super initial && + git -C super submodule add ../sub sub1 && + git -C super submodule add ../sub sub2 && + + # Remove submodule.<name>.active entries in order to test in an + # environment where only URLs are present in the conifg + git -C super config --unset submodule.sub1.active && + git -C super config --unset submodule.sub2.active && + + git -C super commit -a -m "add 2 submodules at sub{1,2}" +' + +test_expect_success 'is-active works with urls' ' + git -C super submodule--helper is-active sub1 && + git -C super submodule--helper is-active sub2 && + + git -C super config --unset submodule.sub1.URL && + test_must_fail git -C super submodule--helper is-active sub1 && + git -C super config submodule.sub1.URL ../sub && + git -C super submodule--helper is-active sub1 +' + +test_expect_success 'is-active works with submodule.<name>.active config' ' + test_when_finished "git -C super config --unset submodule.sub1.active" && + test_when_finished "git -C super config submodule.sub1.URL ../sub" && + + git -C super config --bool submodule.sub1.active "false" && + test_must_fail git -C super submodule--helper is-active sub1 && + + git -C super config --bool submodule.sub1.active "true" && + git -C super config --unset submodule.sub1.URL && + git -C super submodule--helper is-active sub1 +' + +test_expect_success 'is-active works with basic submodule.active config' ' + test_when_finished "git -C super config submodule.sub1.URL ../sub" && + test_when_finished "git -C super config --unset-all submodule.active" && + + git -C super config --add submodule.active "." && + git -C super config --unset submodule.sub1.URL && + + git -C super submodule--helper is-active sub1 && + git -C super submodule--helper is-active sub2 +' + +test_expect_success 'is-active correctly works with paths that are not submodules' ' + test_when_finished "git -C super config --unset-all submodule.active" && + + test_must_fail git -C super submodule--helper is-active not-a-submodule && + + git -C super config --add submodule.active "." && + test_must_fail git -C super submodule--helper is-active not-a-submodule +' + +test_expect_success 'is-active works with exclusions in submodule.active config' ' + test_when_finished "git -C super config --unset-all submodule.active" && + + git -C super config --add submodule.active "." && + git -C super config --add submodule.active ":(exclude)sub1" && + + test_must_fail git -C super submodule--helper is-active sub1 && + git -C super submodule--helper is-active sub2 +' + +test_expect_success 'is-active with submodule.active and submodule.<name>.active' ' + test_when_finished "git -C super config --unset-all submodule.active" && + test_when_finished "git -C super config --unset submodule.sub1.active" && + test_when_finished "git -C super config --unset submodule.sub2.active" && + + git -C super config --add submodule.active "sub1" && + git -C super config --bool submodule.sub1.active "false" && + git -C super config --bool submodule.sub2.active "true" && + + test_must_fail git -C super submodule--helper is-active sub1 && + git -C super submodule--helper is-active sub2 +' + +test_expect_success 'is-active, submodule.active and submodule add' ' + test_when_finished "rm -rf super2" && + git init super2 && + test_commit -C super2 initial && + git -C super2 config --add submodule.active "sub*" && + + # submodule add should only add submodule.<name>.active + # to the config if not matched by the pathspec + git -C super2 submodule add ../sub sub1 && + test_must_fail git -C super2 config --get submodule.sub1.active && + + git -C super2 submodule add ../sub mod && + git -C super2 config --get submodule.mod.active +' + +test_done diff --git a/t/t7504-commit-msg-hook.sh b/t/t7504-commit-msg-hook.sh index 8728db61d3..88d4cda299 100755 --- a/t/t7504-commit-msg-hook.sh +++ b/t/t7504-commit-msg-hook.sh @@ -220,4 +220,21 @@ test_expect_success "hook doesn't edit commit message (editor)" ' ' +# set up fake editor to replace `pick` by `reword` +cat > reword-editor <<'EOF' +#!/bin/sh +mv "$1" "$1".bup && +sed 's/^pick/reword/' <"$1".bup >"$1" +EOF +chmod +x reword-editor +REWORD_EDITOR="$(pwd)/reword-editor" +export REWORD_EDITOR + +test_expect_success 'hook is called for reword during `rebase -i`' ' + + GIT_SEQUENCE_EDITOR="\"$REWORD_EDITOR\"" git rebase -i HEAD^ && + commit_msg_is "new message" + +' + test_done diff --git a/t/t7506-status-submodule.sh b/t/t7506-status-submodule.sh index d31b34da83..055c90736e 100755 --- a/t/t7506-status-submodule.sh +++ b/t/t7506-status-submodule.sh @@ -17,6 +17,12 @@ test_create_repo_with_commit () { ) } +sanitize_output () { + sed -e "s/$_x40/HASH/" -e "s/$_x40/HASH/" output >output2 && + mv output2 output +} + + test_expect_success 'setup' ' test_create_repo_with_commit sub && echo output > .gitignore && @@ -50,6 +56,15 @@ test_expect_success 'status with modified file in submodule (porcelain)' ' EOF ' +test_expect_success 'status with modified file in submodule (short)' ' + (cd sub && git reset --hard) && + echo "changed" >sub/foo && + git status --short >output && + diff output - <<-\EOF + m sub + EOF +' + test_expect_success 'status with added file in submodule' ' (cd sub && git reset --hard && echo >foo && git add foo) && git status >output && @@ -64,6 +79,14 @@ test_expect_success 'status with added file in submodule (porcelain)' ' EOF ' +test_expect_success 'status with added file in submodule (short)' ' + (cd sub && git reset --hard && echo >foo && git add foo) && + git status --short >output && + diff output - <<-\EOF + m sub + EOF +' + test_expect_success 'status with untracked file in submodule' ' (cd sub && git reset --hard) && echo "content" >sub/new-file && @@ -83,6 +106,13 @@ test_expect_success 'status with untracked file in submodule (porcelain)' ' EOF ' +test_expect_success 'status with untracked file in submodule (short)' ' + git status --short >output && + diff output - <<-\EOF + ? sub + EOF +' + test_expect_success 'status with added and untracked file in submodule' ' (cd sub && git reset --hard && echo >foo && git add foo) && echo "content" >sub/new-file && @@ -177,8 +207,24 @@ test_expect_success 'status with added file in modified submodule with .git file test_i18ngrep "modified: sub (new commits, modified content)" output ' +test_expect_success 'status with a lot of untracked files in the submodule' ' + ( + cd sub + i=0 && + while test $i -lt 1024 + do + >some-file-$i + i=$(( $i + 1 )) + done + ) && + git status --porcelain sub 2>err.actual && + test_must_be_empty err.actual && + rm err.actual +' + test_expect_success 'rm submodule contents' ' - rm -rf sub/* sub/.git + rm -rf sub && + mkdir sub ' test_expect_success 'status clean (empty submodule dir)' ' @@ -271,4 +317,91 @@ test_expect_success 'diff --submodule with merge conflict in .gitmodules' ' test_cmp diff_submodule_actual diff_submodule_expect ' +# We'll setup different cases for further testing: +# sub1 will contain a nested submodule, +# sub2 will have an untracked file +# sub3 will have an untracked repository +test_expect_success 'setup superproject with untracked file in nested submodule' ' + ( + cd super && + git clean -dfx && + rm .gitmodules && + git submodule add -f ./sub1 && + git submodule add -f ./sub2 && + git submodule add -f ./sub1 sub3 && + git commit -a -m "messy merge in superproject" && + ( + cd sub1 && + git submodule add ../sub2 && + git commit -a -m "add sub2 to sub1" + ) && + git add sub1 && + git commit -a -m "update sub1 to contain nested sub" + ) && + echo content >super/sub1/sub2/file && + echo content >super/sub2/file && + git -C super/sub3 clone ../../sub2 untracked_repository +' + +test_expect_success 'status with untracked file in nested submodule (porcelain)' ' + git -C super status --porcelain >output && + diff output - <<-\EOF + M sub1 + M sub2 + M sub3 + EOF +' + +test_expect_success 'status with untracked file in nested submodule (porcelain=2)' ' + git -C super status --porcelain=2 >output && + sanitize_output output && + diff output - <<-\EOF + 1 .M S..U 160000 160000 160000 HASH HASH sub1 + 1 .M S..U 160000 160000 160000 HASH HASH sub2 + 1 .M S..U 160000 160000 160000 HASH HASH sub3 + EOF +' + +test_expect_success 'status with untracked file in nested submodule (short)' ' + git -C super status --short >output && + diff output - <<-\EOF + ? sub1 + ? sub2 + ? sub3 + EOF +' + +test_expect_success 'setup superproject with modified file in nested submodule' ' + git -C super/sub1/sub2 add file && + git -C super/sub2 add file +' + +test_expect_success 'status with added file in nested submodule (porcelain)' ' + git -C super status --porcelain >output && + diff output - <<-\EOF + M sub1 + M sub2 + M sub3 + EOF +' + +test_expect_success 'status with added file in nested submodule (porcelain=2)' ' + git -C super status --porcelain=2 >output && + sanitize_output output && + diff output - <<-\EOF + 1 .M S.M. 160000 160000 160000 HASH HASH sub1 + 1 .M S.M. 160000 160000 160000 HASH HASH sub2 + 1 .M S..U 160000 160000 160000 HASH HASH sub3 + EOF +' + +test_expect_success 'status with added file in nested submodule (short)' ' + git -C super status --short >output && + diff output - <<-\EOF + m sub1 + m sub2 + ? sub3 + EOF +' + test_done diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh index 25241f4096..7f09867478 100755 --- a/t/t7800-difftool.sh +++ b/t/t7800-difftool.sh @@ -393,6 +393,25 @@ test_expect_success 'setup change in subdirectory' ' git commit -m "modified both" ' +test_expect_success 'difftool -d with growing paths' ' + a=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa && + git init growing && + ( + cd growing && + echo "test -f \"\$2/b\"" | write_script .git/test-for-b.sh && + one=$(printf 1 | git hash-object -w --stdin) && + two=$(printf 2 | git hash-object -w --stdin) && + git update-index --add \ + --cacheinfo 100644,$one,$a --cacheinfo 100644,$two,b && + tree1=$(git write-tree) && + git update-index --add \ + --cacheinfo 100644,$two,$a --cacheinfo 100644,$one,b && + tree2=$(git write-tree) && + git checkout -- $a && + git difftool -d --extcmd .git/test-for-b.sh $tree1 $tree2 + ) +' + run_dir_diff_test () { test_expect_success "$1 --no-symlinks" " symlinks=--no-symlinks && @@ -428,7 +447,7 @@ run_dir_diff_test 'difftool --dir-diff branch from subdirectory' ' git difftool --dir-diff $symlinks --extcmd ls branch >output && # "sub" must only exist in "right" # "file" and "file2" must be listed in both "left" and "right" - grep sub output > sub-output && + grep sub output >sub-output && test_line_count = 1 sub-output && grep file"$" output >file-output && test_line_count = 2 file-output && @@ -591,6 +610,7 @@ test_expect_success 'difftool --no-symlinks detects conflict ' ' ' test_expect_success 'difftool properly honors gitlink and core.worktree' ' + test_when_finished rm -rf submod/ule && git submodule add ./. submod/ule && test_config -C submod/ule diff.tool checktrees && test_config -C submod/ule difftool.checktrees.cmd '\'' @@ -600,11 +620,13 @@ test_expect_success 'difftool properly honors gitlink and core.worktree' ' cd submod/ule && echo good >expect && git difftool --tool=checktrees --dir-diff HEAD~ >actual && - test_cmp expect actual + test_cmp expect actual && + rm -f expect actual ) ' test_expect_success SYMLINKS 'difftool --dir-diff symlinked directories' ' + test_when_finished git reset --hard && git init dirlinks && ( cd dirlinks && @@ -623,4 +645,64 @@ test_expect_success SYMLINKS 'difftool --dir-diff symlinked directories' ' ) ' +test_expect_success SYMLINKS 'difftool --dir-diff handles modified symlinks' ' + test_when_finished git reset --hard && + touch b && + ln -s b c && + git add b c && + test_tick && + git commit -m initial && + touch d && + rm c && + ln -s d c && + cat >expect <<-EOF && + b + c + + c + EOF + git difftool --symlinks --dir-diff --extcmd ls >output && + grep -v ^/ output >actual && + test_cmp expect actual && + + git difftool --no-symlinks --dir-diff --extcmd ls >output && + grep -v ^/ output >actual && + test_cmp expect actual && + + # The left side contains symlink "c" that points to "b" + test_config difftool.cat.cmd "cat \$LOCAL/c" && + printf "%s\n" b >expect && + + git difftool --symlinks --dir-diff --tool cat >actual && + test_cmp expect actual && + + git difftool --symlinks --no-symlinks --dir-diff --tool cat >actual && + test_cmp expect actual && + + # The right side contains symlink "c" that points to "d" + test_config difftool.cat.cmd "cat \$REMOTE/c" && + printf "%s\n" d >expect && + + git difftool --symlinks --dir-diff --tool cat >actual && + test_cmp expect actual && + + git difftool --no-symlinks --dir-diff --tool cat >actual && + test_cmp expect actual && + + # Deleted symlinks + rm -f c && + cat >expect <<-EOF && + b + c + + EOF + git difftool --symlinks --dir-diff --extcmd ls >output && + grep -v ^/ output >actual && + test_cmp expect actual && + + git difftool --no-symlinks --dir-diff --extcmd ls >output && + grep -v ^/ output >actual && + test_cmp expect actual +' + test_done diff --git a/t/t7814-grep-recurse-submodules.sh b/t/t7814-grep-recurse-submodules.sh index 67247a01d6..5b6eb3a65e 100755 --- a/t/t7814-grep-recurse-submodules.sh +++ b/t/t7814-grep-recurse-submodules.sh @@ -227,6 +227,81 @@ test_expect_success 'grep history with moved submoules' ' test_cmp expect actual ' +test_expect_success 'grep using relative path' ' + test_when_finished "rm -rf parent sub" && + git init sub && + echo "foobar" >sub/file && + git -C sub add file && + git -C sub commit -m "add file" && + + git init parent && + echo "foobar" >parent/file && + git -C parent add file && + mkdir parent/src && + echo "foobar" >parent/src/file2 && + git -C parent add src/file2 && + git -C parent submodule add ../sub && + git -C parent commit -m "add files and submodule" && + + # From top works + cat >expect <<-\EOF && + file:foobar + src/file2:foobar + sub/file:foobar + EOF + git -C parent grep --recurse-submodules -e "foobar" >actual && + test_cmp expect actual && + + # Relative path to top + cat >expect <<-\EOF && + ../file:foobar + file2:foobar + ../sub/file:foobar + EOF + git -C parent/src grep --recurse-submodules -e "foobar" -- .. >actual && + test_cmp expect actual && + + # Relative path to submodule + cat >expect <<-\EOF && + ../sub/file:foobar + EOF + git -C parent/src grep --recurse-submodules -e "foobar" -- ../sub >actual && + test_cmp expect actual +' + +test_expect_success 'grep from a subdir' ' + test_when_finished "rm -rf parent sub" && + git init sub && + echo "foobar" >sub/file && + git -C sub add file && + git -C sub commit -m "add file" && + + git init parent && + mkdir parent/src && + echo "foobar" >parent/src/file && + git -C parent add src/file && + git -C parent submodule add ../sub src/sub && + git -C parent submodule add ../sub sub && + git -C parent commit -m "add files and submodules" && + + # Verify grep from root works + cat >expect <<-\EOF && + src/file:foobar + src/sub/file:foobar + sub/file:foobar + EOF + git -C parent grep --recurse-submodules -e "foobar" >actual && + test_cmp expect actual && + + # Verify grep from a subdir works + cat >expect <<-\EOF && + file:foobar + sub/file:foobar + EOF + git -C parent/src grep --recurse-submodules -e "foobar" >actual && + test_cmp expect actual +' + test_incompatible_with_recurse_submodules () { test_expect_success "--recurse-submodules and $1 are incompatible" " diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index d711bef240..5ed28135be 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -400,6 +400,22 @@ test_expect_success '__gitdir - remote as argument' ' test_cmp expected "$actual" ' +test_expect_success '__gitcomp_direct - puts everything into COMPREPLY as-is' ' + sed -e "s/Z$//g" >expected <<-EOF && + with-trailing-space Z + without-trailing-spaceZ + --option Z + --option=Z + $invalid_variable_name Z + EOF + ( + cur=should_be_ignored && + __gitcomp_direct "$(cat expected)" && + print_comp + ) && + test_cmp expected out +' + test_expect_success '__gitcomp - trailing space - options' ' test_gitcomp "--re" "--dry-run --reuse-message= --reedit-message= --reset-author" <<-EOF @@ -555,6 +571,9 @@ test_expect_success '__git_refs - full refs' ' cat >expected <<-EOF && refs/heads/master refs/heads/matching-branch + refs/remotes/other/branch-in-other + refs/remotes/other/master-in-other + refs/tags/matching-tag EOF ( cur=refs/heads/ && @@ -620,6 +639,7 @@ test_expect_success '__git_refs - configured remote' ' test_expect_success '__git_refs - configured remote - full refs' ' cat >expected <<-EOF && + HEAD refs/heads/branch-in-other refs/heads/master-in-other refs/tags/tag-in-other @@ -648,6 +668,7 @@ test_expect_success '__git_refs - configured remote - repo given on the command test_expect_success '__git_refs - configured remote - full refs - repo given on the command line' ' cat >expected <<-EOF && + HEAD refs/heads/branch-in-other refs/heads/master-in-other refs/tags/tag-in-other @@ -692,6 +713,7 @@ test_expect_success '__git_refs - URL remote' ' test_expect_success '__git_refs - URL remote - full refs' ' cat >expected <<-EOF && + HEAD refs/heads/branch-in-other refs/heads/master-in-other refs/tags/tag-in-other @@ -775,6 +797,371 @@ test_expect_success '__git_refs - unique remote branches for git checkout DWIMer test_cmp expected "$actual" ' +test_expect_success '__git_refs - after --opt=' ' + cat >expected <<-EOF && + HEAD + master + matching-branch + other/branch-in-other + other/master-in-other + matching-tag + EOF + ( + cur="--opt=" && + __git_refs "" "" "" "" >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success '__git_refs - after --opt= - full refs' ' + cat >expected <<-EOF && + refs/heads/master + refs/heads/matching-branch + refs/remotes/other/branch-in-other + refs/remotes/other/master-in-other + refs/tags/matching-tag + EOF + ( + cur="--opt=refs/" && + __git_refs "" "" "" refs/ >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success '__git refs - exluding refs' ' + cat >expected <<-EOF && + ^HEAD + ^master + ^matching-branch + ^other/branch-in-other + ^other/master-in-other + ^matching-tag + EOF + ( + cur=^ && + __git_refs >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success '__git refs - exluding full refs' ' + cat >expected <<-EOF && + ^refs/heads/master + ^refs/heads/matching-branch + ^refs/remotes/other/branch-in-other + ^refs/remotes/other/master-in-other + ^refs/tags/matching-tag + EOF + ( + cur=^refs/ && + __git_refs >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'setup for filtering matching refs' ' + git branch matching/branch && + git tag matching/tag && + git -C otherrepo branch matching/branch-in-other && + git fetch --no-tags other && + rm -f .git/FETCH_HEAD +' + +test_expect_success '__git_refs - dont filter refs unless told so' ' + cat >expected <<-EOF && + HEAD + master + matching-branch + matching/branch + other/branch-in-other + other/master-in-other + other/matching/branch-in-other + matching-tag + matching/tag + EOF + ( + cur=master && + __git_refs >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success '__git_refs - only matching refs' ' + cat >expected <<-EOF && + matching-branch + matching/branch + matching-tag + matching/tag + EOF + ( + cur=mat && + __git_refs "" "" "" "$cur" >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success '__git_refs - only matching refs - full refs' ' + cat >expected <<-EOF && + refs/heads/matching-branch + refs/heads/matching/branch + EOF + ( + cur=refs/heads/mat && + __git_refs "" "" "" "$cur" >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success '__git_refs - only matching refs - remote on local file system' ' + cat >expected <<-EOF && + master-in-other + matching/branch-in-other + EOF + ( + cur=ma && + __git_refs otherrepo "" "" "$cur" >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success '__git_refs - only matching refs - configured remote' ' + cat >expected <<-EOF && + master-in-other + matching/branch-in-other + EOF + ( + cur=ma && + __git_refs other "" "" "$cur" >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success '__git_refs - only matching refs - remote - full refs' ' + cat >expected <<-EOF && + refs/heads/master-in-other + refs/heads/matching/branch-in-other + EOF + ( + cur=refs/heads/ma && + __git_refs other "" "" "$cur" >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success '__git_refs - only matching refs - checkout DWIMery' ' + cat >expected <<-EOF && + matching-branch + matching/branch + matching-tag + matching/tag + matching/branch-in-other + EOF + for remote_ref in refs/remotes/other/ambiguous \ + refs/remotes/remote/ambiguous \ + refs/remotes/remote/branch-in-remote + do + git update-ref $remote_ref master && + test_when_finished "git update-ref -d $remote_ref" + done && + ( + cur=mat && + __git_refs "" 1 "" "$cur" >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'teardown after filtering matching refs' ' + git branch -d matching/branch && + git tag -d matching/tag && + git update-ref -d refs/remotes/other/matching/branch-in-other && + git -C otherrepo branch -D matching/branch-in-other +' + +test_expect_success '__git_refs - for-each-ref format specifiers in prefix' ' + cat >expected <<-EOF && + evil-%%-%42-%(refname)..master + EOF + ( + cur="evil-%%-%42-%(refname)..mas" && + __git_refs "" "" "evil-%%-%42-%(refname).." mas >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success '__git_complete_refs - simple' ' + sed -e "s/Z$//" >expected <<-EOF && + HEAD Z + master Z + matching-branch Z + other/branch-in-other Z + other/master-in-other Z + matching-tag Z + EOF + ( + cur= && + __git_complete_refs && + print_comp + ) && + test_cmp expected out +' + +test_expect_success '__git_complete_refs - matching' ' + sed -e "s/Z$//" >expected <<-EOF && + matching-branch Z + matching-tag Z + EOF + ( + cur=mat && + __git_complete_refs && + print_comp + ) && + test_cmp expected out +' + +test_expect_success '__git_complete_refs - remote' ' + sed -e "s/Z$//" >expected <<-EOF && + HEAD Z + branch-in-other Z + master-in-other Z + EOF + ( + cur= + __git_complete_refs --remote=other && + print_comp + ) && + test_cmp expected out +' + +test_expect_success '__git_complete_refs - track' ' + sed -e "s/Z$//" >expected <<-EOF && + HEAD Z + master Z + matching-branch Z + other/branch-in-other Z + other/master-in-other Z + matching-tag Z + branch-in-other Z + master-in-other Z + EOF + ( + cur= + __git_complete_refs --track && + print_comp + ) && + test_cmp expected out +' + +test_expect_success '__git_complete_refs - current word' ' + sed -e "s/Z$//" >expected <<-EOF && + matching-branch Z + matching-tag Z + EOF + ( + cur="--option=mat" && + __git_complete_refs --cur="${cur#*=}" && + print_comp + ) && + test_cmp expected out +' + +test_expect_success '__git_complete_refs - prefix' ' + sed -e "s/Z$//" >expected <<-EOF && + v1.0..matching-branch Z + v1.0..matching-tag Z + EOF + ( + cur=v1.0..mat && + __git_complete_refs --pfx=v1.0.. --cur=mat && + print_comp + ) && + test_cmp expected out +' + +test_expect_success '__git_complete_refs - suffix' ' + cat >expected <<-EOF && + HEAD. + master. + matching-branch. + other/branch-in-other. + other/master-in-other. + matching-tag. + EOF + ( + cur= && + __git_complete_refs --sfx=. && + print_comp + ) && + test_cmp expected out +' + +test_expect_success '__git_complete_fetch_refspecs - simple' ' + sed -e "s/Z$//" >expected <<-EOF && + HEAD:HEAD Z + branch-in-other:branch-in-other Z + master-in-other:master-in-other Z + EOF + ( + cur= && + __git_complete_fetch_refspecs other && + print_comp + ) && + test_cmp expected out +' + +test_expect_success '__git_complete_fetch_refspecs - matching' ' + sed -e "s/Z$//" >expected <<-EOF && + branch-in-other:branch-in-other Z + EOF + ( + cur=br && + __git_complete_fetch_refspecs other "" br && + print_comp + ) && + test_cmp expected out +' + +test_expect_success '__git_complete_fetch_refspecs - prefix' ' + sed -e "s/Z$//" >expected <<-EOF && + +HEAD:HEAD Z + +branch-in-other:branch-in-other Z + +master-in-other:master-in-other Z + EOF + ( + cur="+" && + __git_complete_fetch_refspecs other "+" "" && + print_comp + ) && + test_cmp expected out +' + +test_expect_success '__git_complete_fetch_refspecs - fully qualified' ' + sed -e "s/Z$//" >expected <<-EOF && + refs/heads/branch-in-other:refs/heads/branch-in-other Z + refs/heads/master-in-other:refs/heads/master-in-other Z + refs/tags/tag-in-other:refs/tags/tag-in-other Z + EOF + ( + cur=refs/ && + __git_complete_fetch_refspecs other "" refs/ && + print_comp + ) && + test_cmp expected out +' + +test_expect_success '__git_complete_fetch_refspecs - fully qualified & prefix' ' + sed -e "s/Z$//" >expected <<-EOF && + +refs/heads/branch-in-other:refs/heads/branch-in-other Z + +refs/heads/master-in-other:refs/heads/master-in-other Z + +refs/tags/tag-in-other:refs/tags/tag-in-other Z + EOF + ( + cur=+refs/ && + __git_complete_fetch_refspecs other + refs/ && + print_comp + ) && + test_cmp expected out +' + test_expect_success 'teardown after ref completion' ' git branch -d matching-branch && git tag -d matching-tag && diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh index bd357704cc..5ee124332a 100644 --- a/t/test-lib-functions.sh +++ b/t/test-lib-functions.sh @@ -136,17 +136,12 @@ test_tick () { export GIT_COMMITTER_DATE GIT_AUTHOR_DATE } -# Stop execution and start a shell. This is useful for debugging tests and -# only makes sense together with "-v". +# Stop execution and start a shell. This is useful for debugging tests. # # Be sure to remove all invocations of this command before submitting. test_pause () { - if test "$verbose" = t; then - "$SHELL_PATH" <&6 >&3 2>&4 - else - error >&5 "test_pause requires --verbose" - fi + "$SHELL_PATH" <&6 >&5 2>&7 } # Wrap git in gdb. Adding this to a command can make it easier to @@ -154,7 +149,7 @@ test_pause () { # # Example: "debug git checkout master". debug () { - GIT_TEST_GDB=1 "$@" + GIT_TEST_GDB=1 "$@" <&6 >&5 2>&7 } # Call test_commit with the arguments diff --git a/t/test-lib.sh b/t/test-lib.sh index 86d77c16dd..13b5696822 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -342,6 +342,7 @@ fi exec 5>&1 exec 6<&0 +exec 7>&2 if test "$verbose_log" = "t" then exec 3>>"$GIT_TEST_TEE_OUTPUT_FILE" 4>&3 @@ -624,9 +625,9 @@ test_run_ () { trace= # 117 is magic because it is unlikely to match the exit # code of other programs - test_eval_ "(exit 117) && $1" - if test "$?" != 117; then - error "bug in the test script: broken &&-chain: $1" + if test "OK-117" != "$(test_eval_ "(exit 117) && $1${LF}${LF}echo OK-\$?" 3>&1)" + then + error "bug in the test script: broken &&-chain or run-away HERE-DOC: $1" fi trace=$trace_tmp fi diff --git a/transport-helper.c b/transport-helper.c index dc90a1fb76..36408046eb 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -347,14 +347,11 @@ static int set_helper_option(struct transport *transport, static void standard_options(struct transport *t) { char buf[16]; - int n; int v = t->verbose; set_helper_option(t, "progress", t->progress ? "true" : "false"); - n = snprintf(buf, sizeof(buf), "%d", v + 1); - if (n >= sizeof(buf)) - die("impossibly large verbosity value"); + xsnprintf(buf, sizeof(buf), "%d", v + 1); set_helper_option(t, "verbosity", buf); switch (t->family) { diff --git a/transport.c b/transport.c index 417ed7f19f..4d33138a75 100644 --- a/transport.c +++ b/transport.c @@ -116,8 +116,8 @@ struct git_transport_data { struct child_process *conn; int fd[2]; unsigned got_remote_heads : 1; - struct sha1_array extra_have; - struct sha1_array shallow; + struct oid_array extra_have; + struct oid_array shallow; }; static int set_git_option(struct git_transport_options *opts, @@ -447,7 +447,7 @@ static int print_one_push_status(struct ref *ref, const char *dest, int count, static int measure_abbrev(const struct object_id *oid, int sofar) { - char hex[GIT_SHA1_HEXSZ + 1]; + char hex[GIT_MAX_HEXSZ + 1]; int w = find_unique_abbrev_r(hex, oid->hash, DEFAULT_ABBREV); return (w < sofar) ? sofar : w; @@ -1023,19 +1023,22 @@ int transport_push(struct transport *transport, TRANSPORT_RECURSE_SUBMODULES_ONLY)) && !is_bare_repository()) { struct ref *ref = remote_refs; - struct sha1_array commits = SHA1_ARRAY_INIT; + struct oid_array commits = OID_ARRAY_INIT; for (; ref; ref = ref->next) if (!is_null_oid(&ref->new_oid)) - sha1_array_append(&commits, ref->new_oid.hash); + oid_array_append(&commits, + &ref->new_oid); if (!push_unpushed_submodules(&commits, - transport->remote->name, + transport->remote, + refspec, refspec_nr, + transport->push_options, pretend)) { - sha1_array_clear(&commits); + oid_array_clear(&commits); die("Failed to push all needed submodules!"); } - sha1_array_clear(&commits); + oid_array_clear(&commits); } if (((flags & TRANSPORT_RECURSE_SUBMODULES_CHECK) || @@ -1044,19 +1047,20 @@ int transport_push(struct transport *transport, !pretend)) && !is_bare_repository()) { struct ref *ref = remote_refs; struct string_list needs_pushing = STRING_LIST_INIT_DUP; - struct sha1_array commits = SHA1_ARRAY_INIT; + struct oid_array commits = OID_ARRAY_INIT; for (; ref; ref = ref->next) if (!is_null_oid(&ref->new_oid)) - sha1_array_append(&commits, ref->new_oid.hash); + oid_array_append(&commits, + &ref->new_oid); if (find_unpushed_submodules(&commits, transport->remote->name, &needs_pushing)) { - sha1_array_clear(&commits); + oid_array_clear(&commits); die_with_unpushed_submodules(&needs_pushing); } string_list_clear(&needs_pushing, 0); - sha1_array_clear(&commits); + oid_array_clear(&commits); } if (!(flags & TRANSPORT_RECURSE_SUBMODULES_ONLY)) diff --git a/unpack-trees.c b/unpack-trees.c index 3a8ee19fe8..6b7356dab2 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -10,6 +10,8 @@ #include "attr.h" #include "split-index.h" #include "dir.h" +#include "submodule.h" +#include "submodule-config.h" /* * Error messages expected by scripts out of plumbing commands such as @@ -45,6 +47,9 @@ static const char *unpack_plumbing_errors[NB_UNPACK_TREES_ERROR_TYPES] = { /* ERROR_WOULD_LOSE_ORPHANED_REMOVED */ "Working tree file '%s' would be removed by sparse checkout update.", + + /* ERROR_WOULD_LOSE_SUBMODULE */ + "Submodule '%s' cannot checkout new HEAD.", }; #define ERRORMSG(o,type) \ @@ -161,6 +166,8 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts, _("The following working tree files would be overwritten by sparse checkout update:\n%s"); msgs[ERROR_WOULD_LOSE_ORPHANED_REMOVED] = _("The following working tree files would be removed by sparse checkout update:\n%s"); + msgs[ERROR_WOULD_LOSE_SUBMODULE] = + _("Cannot update submodule:\n%s"); opts->show_all_errors = 1; /* rejected paths may not have a static buffer */ @@ -240,12 +247,75 @@ static void display_error_msgs(struct unpack_trees_options *o) fprintf(stderr, _("Aborting\n")); } +static int check_submodule_move_head(const struct cache_entry *ce, + const char *old_id, + const char *new_id, + struct unpack_trees_options *o) +{ + const struct submodule *sub = submodule_from_ce(ce); + if (!sub) + return 0; + + switch (sub->update_strategy.type) { + case SM_UPDATE_UNSPECIFIED: + case SM_UPDATE_CHECKOUT: + if (submodule_move_head(ce->name, old_id, new_id, SUBMODULE_MOVE_HEAD_DRY_RUN)) + return o->gently ? -1 : + add_rejected_path(o, ERROR_WOULD_LOSE_SUBMODULE, ce->name); + return 0; + case SM_UPDATE_NONE: + return 0; + case SM_UPDATE_REBASE: + case SM_UPDATE_MERGE: + case SM_UPDATE_COMMAND: + default: + warning(_("submodule update strategy not supported for submodule '%s'"), ce->name); + return -1; + } +} + +static void reload_gitmodules_file(struct index_state *index, + struct checkout *state) +{ + int i; + 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"); + if (r < 0) + continue; + else if (r == 0) { + submodule_free(); + checkout_entry(ce, state, NULL); + gitmodules_config(); + git_config(submodule_config, NULL); + } else + break; + } + } +} + /* * Unlink the last component and schedule the leading directories for * removal, such that empty directories get removed. */ static void unlink_entry(const struct cache_entry *ce) { + const struct submodule *sub = submodule_from_ce(ce); + if (sub) { + switch (sub->update_strategy.type) { + case SM_UPDATE_UNSPECIFIED: + case SM_UPDATE_CHECKOUT: + case SM_UPDATE_REBASE: + case SM_UPDATE_MERGE: + submodule_move_head(ce->name, "HEAD", NULL, + SUBMODULE_MOVE_HEAD_FORCE); + break; + case SM_UPDATE_NONE: + case SM_UPDATE_COMMAND: + return; /* Do not touch the submodule. */ + } + } if (!check_leading_path(ce->name, ce_namelen(ce))) return; if (remove_or_warn(ce->ce_mode, ce->name)) @@ -301,6 +371,9 @@ static int check_updates(struct unpack_trees_options *o) remove_marked_cache_entries(index); remove_scheduled_dirs(); + if (should_update_submodules() && o->update && !o->dry_run) + reload_gitmodules_file(index, &state); + for (i = 0; i < index->cache_nr; i++) { struct cache_entry *ce = index->cache[i]; @@ -1358,17 +1431,26 @@ static int verify_uptodate_1(const struct cache_entry *ce, if (!lstat(ce->name, &st)) { int flags = CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE; unsigned changed = ie_match_stat(o->src_index, ce, &st, flags); + + if (submodule_from_ce(ce)) { + int r = check_submodule_move_head(ce, + "HEAD", oid_to_hex(&ce->oid), o); + if (r) + return o->gently ? -1 : + add_rejected_path(o, error_type, ce->name); + return 0; + } + if (!changed) return 0; /* - * NEEDSWORK: the current default policy is to allow - * submodule to be out of sync wrt the superproject - * index. This needs to be tightened later for - * submodules that are marked to be automatically - * checked out. + * Historic default policy was to allow submodule to be out + * of sync wrt the superproject index. If the submodule was + * not considered interesting above, we don't care here. */ if (S_ISGITLINK(ce->ce_mode)) return 0; + errno = 0; } if (errno == ENOENT) @@ -1407,11 +1489,16 @@ static void invalidate_ce_path(const struct cache_entry *ce, * Currently, git does not checkout subprojects during a superproject * checkout, so it is not going to overwrite anything. */ -static int verify_clean_submodule(const struct cache_entry *ce, +static int verify_clean_submodule(const char *old_sha1, + const struct cache_entry *ce, enum unpack_trees_error_types error_type, struct unpack_trees_options *o) { - return 0; + if (!submodule_from_ce(ce)) + return 0; + + return check_submodule_move_head(ce, old_sha1, + oid_to_hex(&ce->oid), o); } static int verify_clean_subdirectory(const struct cache_entry *ce, @@ -1427,16 +1514,18 @@ static int verify_clean_subdirectory(const struct cache_entry *ce, struct dir_struct d; char *pathbuf; int cnt = 0; - unsigned char sha1[20]; - if (S_ISGITLINK(ce->ce_mode) && - resolve_gitlink_ref(ce->name, "HEAD", sha1) == 0) { - /* If we are not going to update the submodule, then + if (S_ISGITLINK(ce->ce_mode)) { + unsigned char sha1[20]; + int sub_head = resolve_gitlink_ref(ce->name, "HEAD", sha1); + /* + * If we are not going to update the submodule, then * we don't care. */ - if (!hashcmp(sha1, ce->oid.hash)) + if (!sub_head && !hashcmp(sha1, ce->oid.hash)) return 0; - return verify_clean_submodule(ce, error_type, o); + return verify_clean_submodule(sub_head ? NULL : sha1_to_hex(sha1), + ce, error_type, o); } /* @@ -1575,9 +1664,15 @@ static int verify_absent_1(const struct cache_entry *ce, path = xmemdupz(ce->name, len); if (lstat(path, &st)) ret = error_errno("cannot stat '%s'", path); - else - ret = check_ok_to_remove(path, len, DT_UNKNOWN, NULL, - &st, error_type, o); + else { + if (submodule_from_ce(ce)) + ret = check_submodule_move_head(ce, + oid_to_hex(&ce->oid), + NULL, o); + else + ret = check_ok_to_remove(path, len, DT_UNKNOWN, NULL, + &st, error_type, o); + } free(path); return ret; } else if (lstat(ce->name, &st)) { @@ -1585,6 +1680,10 @@ static int verify_absent_1(const struct cache_entry *ce, return error_errno("cannot stat '%s'", ce->name); return 0; } else { + if (submodule_from_ce(ce)) + return check_submodule_move_head(ce, oid_to_hex(&ce->oid), + NULL, o); + return check_ok_to_remove(ce->name, ce_namelen(ce), ce_to_dtype(ce), ce, &st, error_type, o); @@ -1640,6 +1739,15 @@ static int merged_entry(const struct cache_entry *ce, return -1; } invalidate_ce_path(merge, o); + + if (submodule_from_ce(ce)) { + int ret = check_submodule_move_head(ce, NULL, + oid_to_hex(&ce->oid), + o); + if (ret) + return ret; + } + } else if (!(old->ce_flags & CE_CONFLICTED)) { /* * See if we can re-use the old CE directly? @@ -1660,6 +1768,14 @@ static int merged_entry(const struct cache_entry *ce, update |= old->ce_flags & (CE_SKIP_WORKTREE | CE_NEW_SKIP_WORKTREE); invalidate_ce_path(old, o); } + + if (submodule_from_ce(ce)) { + int ret = check_submodule_move_head(ce, oid_to_hex(&old->oid), + oid_to_hex(&ce->oid), + o); + if (ret) + return ret; + } } else { /* * Previously unmerged entry left as an existence diff --git a/unpack-trees.h b/unpack-trees.h index 36a73a6d00..6c48117b84 100644 --- a/unpack-trees.h +++ b/unpack-trees.h @@ -21,6 +21,7 @@ enum unpack_trees_error_types { ERROR_SPARSE_NOT_UPTODATE_FILE, ERROR_WOULD_LOSE_ORPHANED_OVERWRITTEN, ERROR_WOULD_LOSE_ORPHANED_REMOVED, + ERROR_WOULD_LOSE_SUBMODULE, NB_UNPACK_TREES_ERROR_TYPES }; diff --git a/worktree.c b/worktree.c index fa7bc67a50..bae787cf8d 100644 --- a/worktree.c +++ b/worktree.c @@ -250,16 +250,19 @@ struct worktree *find_worktree(struct worktree **list, { struct worktree *wt; char *path; + char *to_free = NULL; if ((wt = find_worktree_by_suffix(list, arg))) return wt; - arg = prefix_filename(prefix, strlen(prefix), arg); + if (prefix) + arg = to_free = prefix_filename(prefix, arg); path = real_pathdup(arg, 1); for (; *list; list++) if (!fspathcmp(path, real_path((*list)->path))) break; free(path); + free(to_free); return *list; } diff --git a/wt-status.c b/wt-status.c index cc446f26ba..0375484962 100644 --- a/wt-status.c +++ b/wt-status.c @@ -407,6 +407,16 @@ static void wt_longstatus_print_change_data(struct wt_status *s, strbuf_release(&twobuf); } +static char short_submodule_status(struct wt_status_change_data *d) { + if (d->new_submodule_commits) + return 'M'; + if (d->dirty_submodule & DIRTY_SUBMODULE_MODIFIED) + return 'm'; + if (d->dirty_submodule & DIRTY_SUBMODULE_UNTRACKED) + return '?'; + return d->worktree_status; +} + static void wt_status_collect_changed_cb(struct diff_queue_struct *q, struct diff_options *options, void *data) @@ -431,10 +441,13 @@ static void wt_status_collect_changed_cb(struct diff_queue_struct *q, } if (!d->worktree_status) d->worktree_status = p->status; - d->dirty_submodule = p->two->dirty_submodule; - if (S_ISGITLINK(p->two->mode)) + if (S_ISGITLINK(p->two->mode)) { + d->dirty_submodule = p->two->dirty_submodule; d->new_submodule_commits = !!oidcmp(&p->one->oid, &p->two->oid); + if (s->status_format == STATUS_FORMAT_SHORT) + d->worktree_status = short_submodule_status(d); + } switch (p->status) { case DIFF_STATUS_ADDED: @@ -1785,34 +1798,24 @@ static void wt_shortstatus_print_tracking(struct wt_status *s) static void wt_shortstatus_print(struct wt_status *s) { - int i; + struct string_list_item *it; if (s->show_branch) wt_shortstatus_print_tracking(s); - for (i = 0; i < s->change.nr; i++) { - struct wt_status_change_data *d; - struct string_list_item *it; + for_each_string_list_item(it, &s->change) { + struct wt_status_change_data *d = it->util; - it = &(s->change.items[i]); - d = it->util; if (d->stagemask) wt_shortstatus_unmerged(it, s); else wt_shortstatus_status(it, s); } - for (i = 0; i < s->untracked.nr; i++) { - struct string_list_item *it; - - it = &(s->untracked.items[i]); + for_each_string_list_item(it, &s->untracked) wt_shortstatus_other(it, s, "??"); - } - for (i = 0; i < s->ignored.nr; i++) { - struct string_list_item *it; - it = &(s->ignored.items[i]); + for_each_string_list_item(it, &s->ignored) wt_shortstatus_other(it, s, "!!"); - } } static void wt_porcelain_print(struct wt_status *s) diff --git a/wt-status.h b/wt-status.h index 54fec77032..6018c627b1 100644 --- a/wt-status.h +++ b/wt-status.h @@ -80,7 +80,7 @@ struct wt_status { int hints; enum wt_status_format status_format; - unsigned char sha1_commit[GIT_SHA1_RAWSZ]; /* when not Initial */ + unsigned char sha1_commit[GIT_MAX_RAWSZ]; /* when not Initial */ /* These are computed during processing of the individual sections */ int commitable; |