diff options
134 files changed, 2095 insertions, 1016 deletions
diff --git a/.gitattributes b/.gitattributes index 49b3051641..acf853e029 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,7 +5,7 @@ *.pl eof=lf diff=perl *.pm eol=lf diff=perl *.py eol=lf diff=python -/Documentation/git-*.txt eol=lf +/Documentation/**/*.txt eol=lf /command-list.txt eol=lf /GIT-VERSION-GEN eol=lf /mergetools/* eol=lf @@ -21,6 +21,8 @@ Anders Kaseorg <andersk@MIT.EDU> <andersk@mit.edu> Aneesh Kumar K.V <aneesh.kumar@gmail.com> Amos Waterland <apw@debian.org> <apw@rossby.metr.ou.edu> Amos Waterland <apw@debian.org> <apw@us.ibm.com> +Ben Peart <benpeart@microsoft.com> <Ben.Peart@microsoft.com> +Ben Peart <benpeart@microsoft.com> <peartben@gmail.com> Ben Walton <bdwalton@gmail.com> <bwalton@artsci.utoronto.ca> Benoit Sigoure <tsunanet@gmail.com> <tsuna@lrde.epita.fr> Bernt Hansen <bernt@norang.ca> <bernt@alumni.uwaterloo.ca> @@ -32,6 +34,7 @@ Bryan Larsen <bryan@larsen.st> <bryanlarsen@yahoo.com> Cheng Renquan <crquan@gmail.com> Chris Shoemaker <c.shoemaker@cox.net> Chris Wright <chrisw@sous-sol.org> <chrisw@osdl.org> +Christian Ludwig <chrissicool@gmail.com> <chrissicool@googlemail.com> Cord Seele <cowose@gmail.com> <cowose@googlemail.com> Christian Couder <chriscool@tuxfamily.org> <christian.couder@gmail.com> Christian Stimming <stimming@tuhh.de> <chs@ckiste.goetheallee> @@ -51,6 +54,7 @@ David Reiss <dreiss@facebook.com> <dreiss@dreiss-vmware.(none)> David S. Miller <davem@davemloft.net> David Turner <novalis@novalis.org> <dturner@twopensource.com> David Turner <novalis@novalis.org> <dturner@twosigma.com> +Derrick Stolee <dstolee@microsoft.com> <stolee@gmail.com> Deskin Miller <deskinm@umich.edu> Dirk Süsserott <newsletter@dirk.my1.cc> Eric Blake <eblake@redhat.com> <ebb9@byu.net> @@ -98,6 +102,7 @@ Jens Axboe <axboe@kernel.dk> <jens.axboe@oracle.com> Jens Lindström <jl@opera.com> Jens Lindstrom <jl@opera.com> Jim Meyering <jim@meyering.net> <meyering@redhat.com> Joachim Berdal Haga <cjhaga@fys.uio.no> +Joachim Jablon <joachim.jablon@people-doc.com> <ewjoachim@gmail.com> Johannes Schindelin <Johannes.Schindelin@gmx.de> <johannes.schindelin@gmx.de> Johannes Sixt <j6t@kdbg.org> <J.Sixt@eudaptics.com> Johannes Sixt <j6t@kdbg.org> <j.sixt@viscovery.net> @@ -150,6 +155,7 @@ Mark Levedahl <mdl123@verizon.net> <mlevedahl@gmail.com> Mark Rada <marada@uwaterloo.ca> Martin Langhoff <martin@laptop.org> <martin@catalyst.net.nz> Martin von Zweigbergk <martinvonz@gmail.com> <martin.von.zweigbergk@gmail.com> +Masaya Suzuki <masayasuzuki@google.com> <draftcode@gmail.com> Matt Draisey <matt@draisey.ca> <mattdraisey@sympatico.ca> Matt Kraai <kraai@ftbfs.org> <matt.kraai@amo.abbott.com> Matt McCutchen <matt@mattmccutchen.net> <hashproduct@gmail.com> @@ -157,6 +163,7 @@ Matthias Kestenholz <matthias@spinlock.ch> <mk@spinlock.ch> Matthias Rüster <matthias.ruester@gmail.com> Matthias Ruester Matthias Urlichs <matthias@urlichs.de> <smurf@kiste.(none)> Matthias Urlichs <matthias@urlichs.de> <smurf@smurf.noris.de> +Matthieu Moy <git@matthieu-moy.fr> <Matthieu.Moy@imag.fr> Michael Coleman <tutufan@gmail.com> Michael J Gruber <git@grubix.eu> <michaeljgruber+gmane@fastmail.fm> Michael J Gruber <git@grubix.eu> <git@drmicha.warpmail.net> @@ -180,7 +187,11 @@ Nick Stokoe <nick@noodlefactory.co.uk> Nick Woolley <nick@noodlefactory.co.uk> Nick Stokoe <nick@noodlefactory.co.uk> Nick Woolley <nickwoolley@yahoo.co.uk> Nicolas Morey-Chaisemartin <devel-git@morey-chaisemartin.com> <nicolas.morey@free.fr> Nicolas Morey-Chaisemartin <devel-git@morey-chaisemartin.com> <nmorey@kalray.eu> +Nicolas Morey-Chaisemartin <devel-git@morey-chaisemartin.com> <nicolas@morey-chaisemartin.com> +Nicolas Morey-Chaisemartin <devel-git@morey-chaisemartin.com> <NMoreyChaisemartin@suse.com> +Nicolas Morey-Chaisemartin <devel-git@morey-chaisemartin.com> <nmoreychaisemartin@suse.com> Nicolas Sebrecht <nicolas.s.dev@gmx.fr> <ni.s@laposte.net> +Orgad Shaneh <orgads@gmail.com> <orgad.shaneh@audiocodes.com> Paolo Bonzini <bonzini@gnu.org> <paolo.bonzini@lu.unisi.ch> Pascal Obry <pascal@obry.net> <pascal.obry@gmail.com> Pascal Obry <pascal@obry.net> <pascal.obry@wanadoo.fr> @@ -200,6 +211,7 @@ Philipp A. Hartmann <pah@qo.cx> <ph@sorgh.de> Philippe Bruhat <book@cpan.org> Ralf Thielow <ralf.thielow@gmail.com> <ralf.thielow@googlemail.com> Ramsay Jones <ramsay@ramsayjones.plus.com> <ramsay@ramsay1.demon.co.uk> +Randall S. Becker <randall.becker@nexbridge.ca> <rsbecker@nexbridge.com> René Scharfe <l.s.r@web.de> <rene.scharfe@lsrfire.ath.cx> René Scharfe <l.s.r@web.de> Rene Scharfe Richard Hansen <rhansen@rhansen.org> <hansenr@google.com> @@ -238,6 +250,7 @@ Steven Walter <stevenrwalter@gmail.com> <swalter@lpdev.prtdev.lexmark.com> Sven Verdoolaege <skimo@kotnet.org> <Sven.Verdoolaege@cs.kuleuven.ac.be> Sven Verdoolaege <skimo@kotnet.org> <skimo@liacs.nl> SZEDER Gábor <szeder.dev@gmail.com> <szeder@ira.uka.de> +Tao Qingyun <taoqy@ls-a.me> <845767657@qq.com> Tay Ray Chuan <rctay89@gmail.com> Ted Percival <ted@midg3t.net> <ted.percival@quest.com> Theodore Ts'o <tytso@mit.edu> diff --git a/.travis.yml b/.travis.yml index a5a82d6832..03c8e4c613 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,7 @@ compiler: matrix: include: - - env: jobname=GETTEXT_POISON + - env: jobname=GIT_TEST_GETTEXT_POISON os: linux compiler: addons: diff --git a/Documentation/Makefile b/Documentation/Makefile index 48d261dc2c..d5d936e6a7 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -73,6 +73,7 @@ TECH_DOCS += technical/hash-function-transition TECH_DOCS += technical/http-protocol TECH_DOCS += technical/index-format TECH_DOCS += technical/long-running-process-protocol +TECH_DOCS += technical/multi-pack-index TECH_DOCS += technical/pack-format TECH_DOCS += technical/pack-heuristics TECH_DOCS += technical/pack-protocol diff --git a/Documentation/RelNotes/2.19.2.txt b/Documentation/RelNotes/2.19.2.txt new file mode 100644 index 0000000000..759e6ca957 --- /dev/null +++ b/Documentation/RelNotes/2.19.2.txt @@ -0,0 +1,108 @@ +Git v2.19.2 Release Notes +========================= + +Fixes since v2.19.1 +------------------- + + * "git interpret-trailers" and its underlying machinery had a buggy + code that attempted to ignore patch text after commit log message, + which triggered in various codepaths that will always get the log + message alone and never get such an input. + + * "git rebase -i" did not clear the state files correctly when a run + of "squash/fixup" is aborted and then the user manually amended the + commit instead, which has been corrected. + + * When fsmonitor is in use, after operation on submodules updates + .gitmodules, we lost track of the fact that we did so and relied on + stale fsmonitor data. + + * Fix for a long-standing bug that leaves the index file corrupt when + it shrinks during a partial commit. + + * Further fix for O_APPEND emulation on Windows + + * A corner case bugfix in "git rerere" code. + + * "git add ':(attr:foo)'" is not supported and is supposed to be + rejected while the command line arguments are parsed, but we fail + to reject such a command line upfront. + + * "git rebase" etc. in Git 2.19 fails to abort when given an empty + commit log message as result of editing, which has been corrected. + + * The code to backfill objects in lazily cloned repository did not + work correctly, which has been corrected. + + * Update error messages given by "git remote" and make them consistent. + + * "git update-ref" learned to make both "--no-deref" and "--stdin" + work at the same time. + + * Recently added "range-diff" had a corner-case bug to cause it + segfault, which has been corrected. + + * The recently introduced commit-graph auxiliary data is incompatible + with mechanisms such as replace & grafts that "breaks" immutable + nature of the object reference relationship. Disable optimizations + based on its use (and updating existing commit-graph) when these + incompatible features are in use in the repository. + + * The mailmap file update. + + * The code in "git status" sometimes hit an assertion failure. This + was caused by a structure that was reused without cleaning the data + used for the first run, which has been corrected. + + * A corner-case bugfix. + + * A partial clone that is configured to lazily fetch missing objects + will on-demand issue a "git fetch" request to the originating + repository to fill not-yet-obtained objects. The request has been + optimized for requesting a tree object (and not the leaf blob + objects contained in it) by telling the originating repository that + no blobs are needed. + + * The codepath to support the experimental split-index mode had + remaining "racily clean" issues fixed. + + * "git log --graph" showing an octopus merge sometimes miscounted the + number of display columns it is consuming to show the merge and its + parent commits, which has been corrected. + + * The implementation of run_command() API on the UNIX platforms had a + bug that caused a command not on $PATH to be found in the current + directory. + + * A mutex used in "git pack-objects" were not correctly initialized + and this caused "git repack" to dump core on Windows. + + * Under certain circumstances, "git diff D:/a/b/c D:/a/b/d" on + Windows would strip initial parts from the paths because they + were not recognized as absolute, which has been corrected. + + * The receive.denyCurrentBranch=updateInstead codepath kicked in even + when the push should have been rejected due to other reasons, such + as it does not fast-forward or the update-hook rejects it, which + has been corrected. + + * "git repack" in a shallow clone did not correctly update the + shallow points in the repository, leading to a repository that + does not pass fsck. + + * Operations on promisor objects make sense in the context of only a + small subset of the commands that internally use the revisions + machinery, but the "--exclude-promisor-objects" option were taken + and led to nonsense results by commands like "log", to which it + didn't make much sense. This has been corrected. + + * The "container" mode of TravisCI is going away. Our .travis.yml + file is getting prepared for the transition. + + * Our test scripts can now take the '-V' option as a synonym for the + '--verbose-log' option. + + * A regression in Git 2.12 era made "git fsck" fall into an infinite + loop while processing truncated loose objects. + +Also contains various documentation updates and code clean-ups. diff --git a/Documentation/RelNotes/2.20.0.txt b/Documentation/RelNotes/2.20.0.txt index 519c89407c..8e266647f0 100644 --- a/Documentation/RelNotes/2.20.0.txt +++ b/Documentation/RelNotes/2.20.0.txt @@ -1,5 +1,5 @@ -Git Release Notes -================= +Git 2.20 Release Notes +====================== Backward Compatibility Notes ---------------------------- @@ -173,6 +173,15 @@ UI, Workflows & Features each other. (merge e5bbe09e88 nd/wildmatch-double-asterisk later to maint). + * The "--no-patch" option, which can be used to get a high-level + overview without the actual line-by-line patch difference shown, of + the "range-diff" command was earlier broken, which has been + corrected. + + * The recently merged "rebase in C" has an escape hatch to use the + scripted version when necessary, but it hasn't been documented, + which has been corrected. + Performance, Internal Implementation, Development Support etc. @@ -249,8 +258,8 @@ Performance, Internal Implementation, Development Support etc. used during tests are getting renamed for consistency. (merge 4231d1ba99 bp/rename-test-env-var later to maint). - * A new extension to the index file has been introduced, which allows - the index file to be read in parallel for performance. + * A pair of new extensions to the index file have been introduced. + They allow the index file to be read in parallel for performance. * The oidset API was built on top of the oidmap API which in turn is on the hashmap API. Replace the implementation to build on top of @@ -332,6 +341,52 @@ Performance, Internal Implementation, Development Support etc. * The support for format-patch (and send-email) by the command-line completion script (in contrib/) has been simplified a bit. + * The revision walker machinery learned to take advantage of the + commit generation numbers stored in the commit-graph file. + + * The codebase has been cleaned up to reduce "#ifndef NO_PTHREADS". + + * The way -lcurl library gets linked has been simplified by taking + advantage of the fact that we can just ask curl-config command how. + + * Various functions have been audited for "-Wunused-parameter" warnings + and bugs in them got fixed. + + * A sanity check for start-up sequence has been added in the config + API codepath. + + * The build procedure to link for fuzzing test has been made + customizable with a new Makefile variable. + + * The way "git rebase" parses and forwards the command line options + meant for underlying "git am" has been revamped, which fixed for + options with parameters that were not passed correctly. + + * Our testing framework uses a special i18n "poisoned localization" + feature to find messages that ought to stay constant but are + incorrectly marked to be translated. This feature has been made + into a runtime option (it used to be a compile-time option). + + * "git push" used to check ambiguities between object-names and + refnames while processing the list of refs' old and new values, + which was unnecessary (as it knew that it is feeding raw object + names). This has been optimized out. + + * The xcurl_off_t() helper function is used to cast size_t to + curl_off_t, but some compilers gave warnings against the code to + ensure the casting is done without wraparound, when size_t is + narrower than curl_off_t. This warning has been squelched. + + * Code preparation to replace ulong vars with size_t vars where + appropriate continues. + + * The "test installed Git" mode of our test suite has been updated to + work better. + + * A coding convention around the Coccinelle semantic patches to have + two classes to ease code migration process has been proposed and + its support has been added to the Makefile. + Fixes since v2.19 ----------------- @@ -544,6 +599,46 @@ Fixes since v2.19 pathspec elements were involved, which has been fixed. (merge b7845cebc0 nd/tree-walk-path-exclusion later to maint). + * "git merge" and "git pull" that merges into an unborn branch used + to completely ignore "--verify-signatures", which has been + corrected. + (merge 01a31f3bca jk/verify-sig-merge-into-void later to maint). + + * "git rebase --autostash" did not correctly re-attach the HEAD at times. + + * "rev-parse --exclude=<pattern> --branches=<pattern>" etc. did not + quite work, which has been corrected. + (merge 9ab9b5df0e ra/rev-parse-exclude-glob later to maint). + + * When editing a patch in a "git add -i" session, a hunk could be + made to no-op. The "git apply" program used to reject a patch with + such a no-op hunk to catch user mistakes, but it is now updated to + explicitly allow a no-op hunk in an edited patch. + (merge 22cb3835b9 js/apply-recount-allow-noop later to maint). + + * The URL to an MSDN page in a comment has been updated. + (merge 2ef2ae2917 js/mingw-msdn-url later to maint). + + * "git ls-remote --sort=<thing>" can feed an object that is not yet + available into the comparison machinery and segfault, which has + been corrected to check such a request upfront and reject it. + + * When "git bundle" aborts due to an empty commit ranges + (i.e. resulting in an empty pack), it left a file descriptor to an + lockfile open, which resulted in leftover lockfile on Windows where + you cannot remove a file with an open file descriptor. This has + been corrected. + (merge 2c8ee1f53c jk/close-duped-fd-before-unlock-for-bundle later to maint). + + * "git format-patch --stat=<width>" can be used to specify the width + used by the diffstat (shown in the cover letter). + (merge 284aeb7e60 nd/format-patch-cover-letter-stat-width later to maint). + + * The way .git/index and .git/sharedindex* files were initially + created gave these files different perm bits until they were + adjusted for shared repository settings. This was made consistent. + (merge c9d6c78870 cc/shared-index-permbits later to maint). + * Code cleanup, docfix, build fix, etc. (merge 96a7501aad ts/doc-build-manpage-xsl-quietly later to maint). (merge b9b07efdb2 tg/conflict-marker-size later to maint). @@ -583,3 +678,4 @@ Fixes since v2.19 (merge 3063477445 tb/char-may-be-unsigned later to maint). (merge 8c64bc9420 sg/test-rebase-editor-fix later to maint). (merge 71571cd7d6 ma/sequencer-do-reset-saner-loop-termination later to maint). + (merge 9a4cb8781e cb/notes-freeing-always-null-fix later to maint). diff --git a/Documentation/config.txt b/Documentation/config.txt index 3e735f1a9a..d87846faa6 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -292,13 +292,6 @@ include::config/advice.txt[] include::config/core.txt[] -extensions.worktreeConfig:: - If set, by default "git config" reads from both "config" and - "config.worktree" file from GIT_DIR in that order. In - multiple working directory mode, "config" file is shared while - "config.worktree" is per-working directory (i.e., it's in - GIT_COMMON_DIR/worktrees/<id>/config.worktree) - include::config/add.txt[] include::config/alias.txt[] diff --git a/Documentation/config/index.txt b/Documentation/config/index.txt index 4b94b6bedc..f181503041 100644 --- a/Documentation/config/index.txt +++ b/Documentation/config/index.txt @@ -1,3 +1,19 @@ +index.recordEndOfIndexEntries:: + Specifies whether the index file should include an "End Of Index + Entry" section. This reduces index load time on multiprocessor + machines but produces a message "ignoring EOIE extension" when + reading the index using Git versions before 2.20. Defaults to + 'true' if index.threads has been explicitly enabled, 'false' + otherwise. + +index.recordOffsetTable:: + Specifies whether the index file should include an "Index Entry + Offset Table" section. This reduces index load time on + multiprocessor machines but produces a message "ignoring IEOT + extension" when reading the index using Git versions before 2.20. + Defaults to 'true' if index.threads has been explicitly enabled, + 'false' otherwise. + index.threads:: Specifies the number of threads to spawn when loading the index. This is meant to reduce index load time on multiprocessor machines. diff --git a/Documentation/config/rebase.txt b/Documentation/config/rebase.txt index 42e1ba7575..f079bf6b7e 100644 --- a/Documentation/config/rebase.txt +++ b/Documentation/config/rebase.txt @@ -1,3 +1,17 @@ +rebase.useBuiltin:: + Set to `false` to use the legacy shellscript implementation of + linkgit:git-rebase[1]. Is `true` by default, which means use + the built-in rewrite of it in C. ++ +The C rewrite is first included with Git version 2.20. This option +serves an an escape hatch to re-enable the legacy version in case any +bugs are found in the rewrite. This option and the shellscript version +of linkgit:git-rebase[1] will be removed in some future release. ++ +If you find some reason to set this option to `false` other than +one-off testing you should report the behavior difference as a bug in +git. + rebase.stat:: Whether to show a diffstat of what changed upstream since the last rebase. False by default. diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt index aba4c5febe..27304428a1 100644 --- a/Documentation/git-format-patch.txt +++ b/Documentation/git-format-patch.txt @@ -250,6 +250,11 @@ feeding the result to `git send-email`. feature/v2`), or a revision range if the two versions of the series are disjoint (for example `git format-patch --cover-letter --range-diff=feature/v1~3..feature/v1 -3 feature/v2`). ++ +Note that diff options passed to the command affect how the primary +product of `format-patch` is generated, and they are not passed to +the underlying `range-diff` machinery used to generate the cover-letter +material (this may change in the future). --creation-factor=<percent>:: Used with `--range-diff`, tweak the heuristic which matches up commits diff --git a/Documentation/git-range-diff.txt b/Documentation/git-range-diff.txt index f693930fdb..8a6ea2c6c5 100644 --- a/Documentation/git-range-diff.txt +++ b/Documentation/git-range-diff.txt @@ -78,6 +78,23 @@ between patches", i.e. to compare the author, commit message and diff of corresponding old/new commits. There is currently no means to tweak the diff options passed to `git log` when generating those patches. +OUTPUT STABILITY +---------------- + +The output of the `range-diff` command is subject to change. It is +intended to be human-readable porcelain output, not something that can +be used across versions of Git to get a textually stable `range-diff` +(as opposed to something like the `--stable` option to +linkgit:git-patch-id[1]). There's also no equivalent of +linkgit:git-apply[1] for `range-diff`, the output is not intended to +be machine-readable. + +This is particularly true when passing in diff options. Currently some +options like `--stat` can, as an emergent effect, produce output +that's quite useless in the context of `range-diff`. Future versions +of `range-diff` may learn to interpret such options in a manner +specific to `range-diff` (e.g. for `--stat` producing human-readable +output which summarizes how the diffstat changed). CONFIGURATION ------------- diff --git a/Documentation/git-reset.txt b/Documentation/git-reset.txt index 2dac95c71a..9f69ae8b69 100644 --- a/Documentation/git-reset.txt +++ b/Documentation/git-reset.txt @@ -14,14 +14,14 @@ SYNOPSIS DESCRIPTION ----------- -In the first and second form, copy entries from <tree-ish> to the index. -In the third form, set the current branch head (HEAD) to <commit>, optionally -modifying index and working tree to match. The <tree-ish>/<commit> defaults -to HEAD in all forms. +In the first and second form, copy entries from `<tree-ish>` to the index. +In the third form, set the current branch head (`HEAD`) to `<commit>`, +optionally modifying index and working tree to match. +The `<tree-ish>`/`<commit>` defaults to `HEAD` in all forms. 'git reset' [-q] [<tree-ish>] [--] <paths>...:: - This form resets the index entries for all <paths> to their - state at <tree-ish>. (It does not affect the working tree or + This form resets the index entries for all `<paths>` to their + state at `<tree-ish>`. (It does not affect the working tree or the current branch.) + This means that `git reset <paths>` is the opposite of `git add @@ -36,7 +36,7 @@ working tree in one go. 'git reset' (--patch | -p) [<tree-ish>] [--] [<paths>...]:: Interactively select hunks in the difference between the index - and <tree-ish> (defaults to HEAD). The chosen hunks are applied + and `<tree-ish>` (defaults to `HEAD`). The chosen hunks are applied in reverse to the index. + This means that `git reset -p` is the opposite of `git add -p`, i.e. @@ -44,16 +44,16 @@ you can use it to selectively reset hunks. See the ``Interactive Mode'' section of linkgit:git-add[1] to learn how to operate the `--patch` mode. 'git reset' [<mode>] [<commit>]:: - This form resets the current branch head to <commit> and - possibly updates the index (resetting it to the tree of <commit>) and - the working tree depending on <mode>. If <mode> is omitted, - defaults to "--mixed". The <mode> must be one of the following: + This form resets the current branch head to `<commit>` and + possibly updates the index (resetting it to the tree of `<commit>`) and + the working tree depending on `<mode>`. If `<mode>` is omitted, + defaults to `--mixed`. The `<mode>` must be one of the following: + -- --soft:: Does not touch the index file or the working tree at all (but - resets the head to <commit>, just like all modes do). This leaves - all your changed files "Changes to be committed", as 'git status' + resets the head to `<commit>`, just like all modes do). This leaves + all your changed files "Changes to be committed", as `git status` would put it. --mixed:: @@ -66,24 +66,24 @@ linkgit:git-add[1]). --hard:: Resets the index and working tree. Any changes to tracked files in the - working tree since <commit> are discarded. + working tree since `<commit>` are discarded. --merge:: Resets the index and updates the files in the working tree that are - different between <commit> and HEAD, but keeps those which are + different between `<commit>` and `HEAD`, but keeps those which are different between the index and working tree (i.e. which have changes which have not been added). - If a file that is different between <commit> and the index has unstaged - changes, reset is aborted. + If a file that is different between `<commit>` and the index has + unstaged changes, reset is aborted. + -In other words, --merge does something like a 'git read-tree -u -m <commit>', +In other words, `--merge` does something like a `git read-tree -u -m <commit>`, but carries forward unmerged index entries. --keep:: Resets index entries and updates files in the working tree that are - different between <commit> and HEAD. - If a file that is different between <commit> and HEAD has local changes, - reset is aborted. + different between `<commit>` and `HEAD`. + If a file that is different between `<commit>` and `HEAD` has local + changes, reset is aborted. -- If you want to undo a commit other than the latest on a branch, @@ -116,15 +116,15 @@ $ git pull git://info.example.com/ nitfol <4> + <1> You are happily working on something, and find the changes in these files are in good order. You do not want to see them -when you run "git diff", because you plan to work on other files +when you run `git diff`, because you plan to work on other files and changes with these files are distracting. <2> Somebody asks you to pull, and the changes sound worthy of merging. <3> However, you already dirtied the index (i.e. your index does -not match the HEAD commit). But you know the pull you are going -to make does not affect frotz.c or filfre.c, so you revert the +not match the `HEAD` commit). But you know the pull you are going +to make does not affect `frotz.c` or `filfre.c`, so you revert the index changes for these two files. Your changes in working tree remain there. -<4> Then you can pull and merge, leaving frotz.c and filfre.c +<4> Then you can pull and merge, leaving `frotz.c` and `filfre.c` changes still in the working tree. Undo a commit and redo:: @@ -140,11 +140,11 @@ $ git commit -a -c ORIG_HEAD <3> just committed is incomplete, or you misspelled your commit message, or both. Leaves working tree as it was before "reset". <2> Make corrections to working tree files. -<3> "reset" copies the old head to .git/ORIG_HEAD; redo the +<3> "reset" copies the old head to `.git/ORIG_HEAD`; redo the commit by starting with its log message. If you do not need to -edit the message further, you can give -C option instead. +edit the message further, you can give `-C` option instead. + -See also the --amend option to linkgit:git-commit[1]. +See also the `--amend` option to linkgit:git-commit[1]. Undo a commit, making it a topic branch:: + @@ -155,11 +155,11 @@ $ git checkout topic/wip <3> ------------ + <1> You have made some commits, but realize they were premature -to be in the "master" branch. You want to continue polishing -them in a topic branch, so create "topic/wip" branch off of the -current HEAD. +to be in the `master` branch. You want to continue polishing +them in a topic branch, so create `topic/wip` branch off of the +current `HEAD`. <2> Rewind the master branch to get rid of those three commits. -<3> Switch to "topic/wip" branch and keep working. +<3> Switch to `topic/wip` branch and keep working. Undo commits permanently:: + @@ -168,7 +168,7 @@ $ git commit ... $ git reset --hard HEAD~3 <1> ------------ + -<1> The last three commits (HEAD, HEAD^, and HEAD~2) were bad +<1> The last three commits (`HEAD`, `HEAD^`, and `HEAD~2`) were bad and you do not want to ever see them again. Do *not* do this if you have already given these commits to somebody else. (See the "RECOVERING FROM UPSTREAM REBASE" section in linkgit:git-rebase[1] for @@ -191,14 +191,14 @@ $ git reset --hard ORIG_HEAD <4> <1> Try to update from the upstream resulted in a lot of conflicts; you were not ready to spend a lot of time merging right now, so you decide to do that later. -<2> "pull" has not made merge commit, so "git reset --hard" -which is a synonym for "git reset --hard HEAD" clears the mess +<2> "pull" has not made merge commit, so `git reset --hard` +which is a synonym for `git reset --hard HEAD` clears the mess from the index file and the working tree. <3> Merge a topic branch into the current branch, which resulted in a fast-forward. <4> But you decided that the topic branch is not ready for public consumption yet. "pull" or "merge" always leaves the original -tip of the current branch in ORIG_HEAD, so resetting hard to it +tip of the current branch in `ORIG_HEAD`, so resetting hard to it brings your index file and the working tree back to that state, and resets the tip of the branch to that commit. @@ -214,14 +214,14 @@ $ git reset --merge ORIG_HEAD <2> ------------ + <1> Even if you may have local modifications in your -working tree, you can safely say "git pull" when you know +working tree, you can safely say `git pull` when you know that the change in the other branch does not overlap with them. <2> After inspecting the result of the merge, you may find that the change in the other branch is unsatisfactory. Running -"git reset --hard ORIG_HEAD" will let you go back to where you +`git reset --hard ORIG_HEAD` will let you go back to where you were, but it will discard your local changes, which you do not -want. "git reset --merge" keeps your local changes. +want. `git reset --merge` keeps your local changes. Interrupted workflow:: @@ -287,13 +287,13 @@ $ git checkout -b branch2 <2> $ git reset --keep start <3> ------------ + -<1> This commits your first edits in branch1. +<1> This commits your first edits in `branch1`. <2> In the ideal world, you could have realized that the earlier commit did not belong to the new topic when you created and switched - to branch2 (i.e. "git checkout -b branch2 start"), but nobody is + to `branch2` (i.e. `git checkout -b branch2 start`), but nobody is perfect. -<3> But you can use "reset --keep" to remove the unwanted commit after - you switched to "branch2". +<3> But you can use `reset --keep` to remove the unwanted commit after + you switched to `branch2`. Split a commit apart into a sequence of commits:: + @@ -317,26 +317,27 @@ $ git commit ... <8> + <1> First, reset the history back one commit so that we remove the original commit, but leave the working tree with all the changes. The -N ensures - that any new files added with HEAD are still marked so that git add -p + that any new files added with `HEAD` are still marked so that `git add -p` will find them. -<2> Next, we interactively select diff hunks to add using the git add -p +<2> Next, we interactively select diff hunks to add using the `git add -p` facility. This will ask you about each diff hunk in sequence and you can use simple commands such as "yes, include this", "No don't include this" or even the very powerful "edit" facility. <3> Once satisfied with the hunks you want to include, you should verify what - has been prepared for the first commit by using git diff --cached. This + has been prepared for the first commit by using `git diff --cached`. This shows all the changes that have been moved into the index and are about to be committed. -<4> Next, commit the changes stored in the index. The -c option specifies to +<4> Next, commit the changes stored in the index. The `-c` option specifies to pre-populate the commit message from the original message that you started - with in the first commit. This is helpful to avoid retyping it. The HEAD@{1} - is a special notation for the commit that HEAD used to be at prior to the - original reset commit (1 change ago). See linkgit:git-reflog[1] for more - details. You may also use any other valid commit reference. + with in the first commit. This is helpful to avoid retyping it. The + `HEAD@{1}` is a special notation for the commit that `HEAD` used to be at + prior to the original reset commit (1 change ago). + See linkgit:git-reflog[1] for more details. You may also use any other + valid commit reference. <5> You can repeat steps 2-4 multiple times to break the original code into any number of commits. <6> Now you've split out many of the changes into their own commits, and might - no longer use the patch mode of git add, in order to select all remaining + no longer use the patch mode of `git add`, in order to select all remaining uncommitted changes. <7> Once again, check to verify that you've included what you want to. You may also wish to verify that git diff doesn't show any remaining changes to be @@ -353,104 +354,120 @@ The tables below show what happens when running: git reset --option target ---------- -to reset the HEAD to another commit (`target`) with the different +to reset the `HEAD` to another commit (`target`) with the different reset options depending on the state of the files. -In these tables, A, B, C and D are some different states of a +In these tables, `A`, `B`, `C` and `D` are some different states of a file. For example, the first line of the first table means that if a -file is in state A in the working tree, in state B in the index, in -state C in HEAD and in state D in the target, then "git reset --soft -target" will leave the file in the working tree in state A and in the -index in state B. It resets (i.e. moves) the HEAD (i.e. the tip of -the current branch, if you are on one) to "target" (which has the file -in state D). - - working index HEAD target working index HEAD - ---------------------------------------------------- - A B C D --soft A B D - --mixed A D D - --hard D D D - --merge (disallowed) - --keep (disallowed) - - working index HEAD target working index HEAD - ---------------------------------------------------- - A B C C --soft A B C - --mixed A C C - --hard C C C - --merge (disallowed) - --keep A C C - - working index HEAD target working index HEAD - ---------------------------------------------------- - B B C D --soft B B D - --mixed B D D - --hard D D D - --merge D D D - --keep (disallowed) - - working index HEAD target working index HEAD - ---------------------------------------------------- - B B C C --soft B B C - --mixed B C C - --hard C C C - --merge C C C - --keep B C C - - working index HEAD target working index HEAD - ---------------------------------------------------- - B C C D --soft B C D - --mixed B D D - --hard D D D - --merge (disallowed) - --keep (disallowed) - - working index HEAD target working index HEAD - ---------------------------------------------------- - B C C C --soft B C C - --mixed B C C - --hard C C C - --merge B C C - --keep B C C - -"reset --merge" is meant to be used when resetting out of a conflicted +file is in state `A` in the working tree, in state `B` in the index, in +state `C` in `HEAD` and in state `D` in the target, then `git reset --soft +target` will leave the file in the working tree in state `A` and in the +index in state `B`. It resets (i.e. moves) the `HEAD` (i.e. the tip of +the current branch, if you are on one) to `target` (which has the file +in state `D`). + +.... +working index HEAD target working index HEAD +---------------------------------------------------- + A B C D --soft A B D + --mixed A D D + --hard D D D + --merge (disallowed) + --keep (disallowed) +.... + +.... +working index HEAD target working index HEAD +---------------------------------------------------- + A B C C --soft A B C + --mixed A C C + --hard C C C + --merge (disallowed) + --keep A C C +.... + +.... +working index HEAD target working index HEAD +---------------------------------------------------- + B B C D --soft B B D + --mixed B D D + --hard D D D + --merge D D D + --keep (disallowed) +.... + +.... +working index HEAD target working index HEAD +---------------------------------------------------- + B B C C --soft B B C + --mixed B C C + --hard C C C + --merge C C C + --keep B C C +.... + +.... +working index HEAD target working index HEAD +---------------------------------------------------- + B C C D --soft B C D + --mixed B D D + --hard D D D + --merge (disallowed) + --keep (disallowed) +.... + +.... +working index HEAD target working index HEAD +---------------------------------------------------- + B C C C --soft B C C + --mixed B C C + --hard C C C + --merge B C C + --keep B C C +.... + +`reset --merge` is meant to be used when resetting out of a conflicted merge. Any mergy operation guarantees that the working tree file that is involved in the merge does not have local change wrt the index before it starts, and that it writes the result out to the working tree. So if we see some difference between the index and the target and also between the index and the working tree, then it means that we are not resetting out from a state that a mergy operation left after failing -with a conflict. That is why we disallow --merge option in this case. +with a conflict. That is why we disallow `--merge` option in this case. -"reset --keep" is meant to be used when removing some of the last +`reset --keep` is meant to be used when removing some of the last commits in the current branch while keeping changes in the working tree. If there could be conflicts between the changes in the commit we want to remove and the changes in the working tree we want to keep, the reset is disallowed. That's why it is disallowed if there are both -changes between the working tree and HEAD, and between HEAD and the +changes between the working tree and `HEAD`, and between `HEAD` and the target. To be safe, it is also disallowed when there are unmerged entries. The following tables show what happens when there are unmerged entries: - working index HEAD target working index HEAD - ---------------------------------------------------- - X U A B --soft (disallowed) - --mixed X B B - --hard B B B - --merge B B B - --keep (disallowed) - - working index HEAD target working index HEAD - ---------------------------------------------------- - X U A A --soft (disallowed) - --mixed X A A - --hard A A A - --merge A A A - --keep (disallowed) - -X means any state and U means an unmerged index. +.... +working index HEAD target working index HEAD +---------------------------------------------------- + X U A B --soft (disallowed) + --mixed X B B + --hard B B B + --merge B B B + --keep (disallowed) +.... + +.... +working index HEAD target working index HEAD +---------------------------------------------------- + X U A A --soft (disallowed) + --mixed X A A + --hard A A A + --merge A A A + --keep (disallowed) +.... + +`X` means any state and `U` means an unmerged index. GIT --- diff --git a/Documentation/gitrepository-layout.txt b/Documentation/gitrepository-layout.txt index d501af9d77..366dee238c 100644 --- a/Documentation/gitrepository-layout.txt +++ b/Documentation/gitrepository-layout.txt @@ -290,6 +290,8 @@ worktrees/<id>/locked:: worktrees/<id>/config.worktree:: Working directory specific configuration file. +include::technical/repository-version.txt[] + SEE ALSO -------- linkgit:git-init[1], diff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt index 829b558110..2b036d7838 100644 --- a/Documentation/technical/api-parse-options.txt +++ b/Documentation/technical/api-parse-options.txt @@ -183,10 +183,6 @@ There are some macros to easily define options: scale the provided value by 1024, 1024^2 or 1024^3 respectively. The scaled value is put into `unsigned_long_var`. -`OPT_DATE(short, long, ×tamp_t_var, description)`:: - Introduce an option with date argument, see `approxidate()`. - The timestamp is put into `timestamp_t_var`. - `OPT_EXPIRY_DATE(short, long, ×tamp_t_var, description)`:: Introduce an option with expiry date argument, see `parse_expiry_date()`. The timestamp is put into `timestamp_t_var`. diff --git a/Documentation/technical/repository-version.txt b/Documentation/technical/repository-version.txt index e03eaccebc..7844ef30ff 100644 --- a/Documentation/technical/repository-version.txt +++ b/Documentation/technical/repository-version.txt @@ -1,5 +1,4 @@ -Git Repository Format Versions -============================== +== Git Repository Format Versions Every git repository is marked with a numeric version in the `core.repositoryformatversion` key of its `config` file. This version @@ -40,16 +39,14 @@ format by default. The currently defined format versions are: -Version `0` ------------ +=== Version `0` This is the format defined by the initial version of git, including but not limited to the format of the repository directory, the repository configuration file, and the object and ref storage. Specifying the complete behavior of git is beyond the scope of this document. -Version `1` ------------ +=== Version `1` This format is identical to version `0`, with the following exceptions: @@ -74,21 +71,18 @@ it here, in order to claim the name. The defined extensions are: -`noop` -~~~~~~ +==== `noop` This extension does not change git's behavior at all. It is useful only for testing format-1 compatibility. -`preciousObjects` -~~~~~~~~~~~~~~~~~ +==== `preciousObjects` When the config key `extensions.preciousObjects` is set to `true`, objects in the repository MUST NOT be deleted (e.g., by `git-prune` or `git repack -d`). -`partialclone` -~~~~~~~~~~~~~~ +==== `partialclone` When the config key `extensions.partialclone` is set, it indicates that the repo was created with a partial clone (or later performed @@ -98,3 +92,11 @@ and it promises that all such omitted objects can be fetched from it in the future. The value of this key is the name of the promisor remote. + +==== `worktreeConfig` + +If set, by default "git config" reads from both "config" and +"config.worktree" file from GIT_DIR in that order. In +multiple working directory mode, "config" file is shared while +"config.worktree" is per-working directory (i.e., it's in +GIT_COMMON_DIR/worktrees/<id>/config.worktree) diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 498fce8b64..bc15874422 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v2.19.GIT +DEF_VER=v2.20.0-rc1 LF=' ' @@ -59,6 +59,13 @@ all:: # Define CURL_CONFIG to curl's configuration program that prints information # about the library (e.g., its version number). The default is 'curl-config'. # +# Define CURL_LDFLAGS to specify flags that you need to link when using libcurl, +# if you do not want to rely on the libraries provided by CURL_CONFIG. The +# default value is a result of `curl-config --libs`. An example value for +# CURL_LDFLAGS is as follows: +# +# CURL_LDFLAGS=-lcurl +# # Define NO_EXPAT if you do not have expat installed. git-http-push is # not built, and you cannot push using http:// and https:// transports (dumb). # @@ -183,10 +190,6 @@ all:: # # Define NEEDS_SSL_WITH_CRYPTO if you need -lssl when using -lcrypto (Darwin). # -# Define NEEDS_SSL_WITH_CURL if you need -lssl with -lcurl (Minix). -# -# Define NEEDS_IDN_WITH_CURL if you need -lidn when using -lcurl (Minix). -# # Define NEEDS_LIBICONV if linking with libc is not enough (Darwin). # # Define NEEDS_LIBINTL_BEFORE_LIBICONV if you need libintl before libiconv. @@ -207,10 +210,12 @@ all:: # Define MMAP_PREVENTS_DELETE if a file that is currently mmapped cannot be # deleted or cannot be replaced using rename(). # +# Define NO_POLL_H if you don't have poll.h. +# # Define NO_SYS_POLL_H if you don't have sys/poll.h. # # Define NO_POLL if you do not have or don't want to use poll(). -# This also implies NO_SYS_POLL_H. +# This also implies NO_POLL_H and NO_SYS_POLL_H. # # Define NEEDS_SYS_PARAM_H if you need to include sys/param.h to compile, # *PLEASE* REPORT to git@vger.kernel.org if your platform needs this; @@ -362,11 +367,6 @@ all:: # Define HAVE_DEV_TTY if your system can open /dev/tty to interact with the # user. # -# Define GETTEXT_POISON if you are debugging the choice of strings marked -# for translation. In a GETTEXT_POISON build, you can turn all strings marked -# for translation into gibberish by setting the GIT_GETTEXT_POISON variable -# (to any value) in your environment. -# # Define JSMIN to point to JavaScript minifier that functions as # a filter to have gitweb.js minified. # @@ -993,6 +993,7 @@ LIB_OBJS += sub-process.o LIB_OBJS += symlinks.o LIB_OBJS += tag.o LIB_OBJS += tempfile.o +LIB_OBJS += thread-utils.o LIB_OBJS += tmp-objdir.o LIB_OBJS += trace.o LIB_OBJS += trailer.o @@ -1308,20 +1309,17 @@ else ifdef CURLDIR # Try "-Wl,-rpath=$(CURLDIR)/$(lib)" in such a case. BASIC_CFLAGS += -I$(CURLDIR)/include - CURL_LIBCURL = -L$(CURLDIR)/$(lib) $(CC_LD_DYNPATH)$(CURLDIR)/$(lib) -lcurl + CURL_LIBCURL = -L$(CURLDIR)/$(lib) $(CC_LD_DYNPATH)$(CURLDIR)/$(lib) else - CURL_LIBCURL = -lcurl - endif - ifdef NEEDS_SSL_WITH_CURL - CURL_LIBCURL += -lssl - ifdef NEEDS_CRYPTO_WITH_SSL - CURL_LIBCURL += -lcrypto - endif - endif - ifdef NEEDS_IDN_WITH_CURL - CURL_LIBCURL += -lidn + CURL_LIBCURL = endif +ifdef CURL_LDFLAGS + CURL_LIBCURL += $(CURL_LDFLAGS) +else + CURL_LIBCURL += $(shell $(CURL_CONFIG) --libs) +endif + REMOTE_CURL_PRIMARY = git-remote-http$X REMOTE_CURL_ALIASES = git-remote-https$X git-remote-ftp$X git-remote-ftps$X REMOTE_CURL_NAMES = $(REMOTE_CURL_PRIMARY) $(REMOTE_CURL_ALIASES) @@ -1453,13 +1451,14 @@ ifdef NO_SYMLINK_HEAD BASIC_CFLAGS += -DNO_SYMLINK_HEAD endif ifdef GETTEXT_POISON - BASIC_CFLAGS += -DGETTEXT_POISON +$(warning The GETTEXT_POISON option has been removed in favor of runtime GIT_TEST_GETTEXT_POISON. See t/README!) endif ifdef NO_GETTEXT BASIC_CFLAGS += -DNO_GETTEXT USE_GETTEXT_SCHEME ?= fallthrough endif ifdef NO_POLL + NO_POLL_H = YesPlease NO_SYS_POLL_H = YesPlease COMPAT_CFLAGS += -DNO_POLL -Icompat/poll COMPAT_OBJS += compat/poll/poll.o @@ -1498,6 +1497,9 @@ endif ifdef NO_SYS_SELECT_H BASIC_CFLAGS += -DNO_SYS_SELECT_H endif +ifdef NO_POLL_H + BASIC_CFLAGS += -DNO_POLL_H +endif ifdef NO_SYS_POLL_H BASIC_CFLAGS += -DNO_SYS_POLL_H endif @@ -1677,7 +1679,6 @@ ifdef NO_PTHREADS else BASIC_CFLAGS += $(PTHREAD_CFLAGS) EXTLIBS += $(PTHREAD_LIBS) - LIB_OBJS += thread-utils.o endif ifdef HAVE_PATHS_H @@ -2111,7 +2112,7 @@ $(SCRIPT_LIB) : % : %.sh GIT-SCRIPT-DEFINES $(QUIET_GEN)$(cmd_munge_script) && \ mv $@+ $@ -git.res: git.rc GIT-VERSION-FILE +git.res: git.rc GIT-VERSION-FILE GIT-PREFIX $(QUIET_RC)$(RC) \ $(join -DMAJOR= -DMINOR= -DMICRO= -DPATCHLEVEL=, $(wordlist 1, 4, \ $(shell echo $(GIT_VERSION) 0 0 0 0 | tr '.a-zA-Z-' ' '))) \ @@ -2591,6 +2592,7 @@ GIT-BUILD-OPTIONS: FORCE @echo NO_UNIX_SOCKETS=\''$(subst ','\'',$(subst ','\'',$(NO_UNIX_SOCKETS)))'\' >>$@+ @echo PAGER_ENV=\''$(subst ','\'',$(subst ','\'',$(PAGER_ENV)))'\' >>$@+ @echo DC_SHA1=\''$(subst ','\'',$(subst ','\'',$(DC_SHA1)))'\' >>$@+ + @echo X=\'$(X)\' >>$@+ ifdef TEST_OUTPUT_DIRECTORY @echo TEST_OUTPUT_DIRECTORY=\''$(subst ','\'',$(subst ','\'',$(TEST_OUTPUT_DIRECTORY)))'\' >>$@+ endif @@ -2604,7 +2606,6 @@ ifdef GIT_TEST_CMP_USE_COPIED_CONTEXT @echo GIT_TEST_CMP_USE_COPIED_CONTEXT=YesPlease >>$@+ endif @echo NO_GETTEXT=\''$(subst ','\'',$(subst ','\'',$(NO_GETTEXT)))'\' >>$@+ - @echo GETTEXT_POISON=\''$(subst ','\'',$(subst ','\'',$(GETTEXT_POISON)))'\' >>$@+ ifdef GIT_PERF_REPEAT_COUNT @echo GIT_PERF_REPEAT_COUNT=\''$(subst ','\'',$(subst ','\'',$(GIT_PERF_REPEAT_COUNT)))'\' >>$@+ endif @@ -2741,9 +2742,12 @@ endif then \ echo ' ' SPATCH result: $@; \ fi -coccicheck: $(addsuffix .patch,$(wildcard contrib/coccinelle/*.cocci)) +coccicheck: $(addsuffix .patch,$(filter-out %.pending.cocci,$(wildcard contrib/coccinelle/*.cocci))) + +# See contrib/coccinelle/README +coccicheck-pending: $(addsuffix .patch,$(wildcard contrib/coccinelle/*.pending.cocci)) -.PHONY: coccicheck +.PHONY: coccicheck coccicheck-pending ### Installation rules @@ -3099,14 +3103,16 @@ cover_db_html: cover_db # An example command to build against libFuzzer from LLVM 4.0.0: # # make CC=clang CXX=clang++ \ -# CFLAGS="-fsanitize-coverage=trace-pc-guard -fsanitize=address" \ +# FUZZ_CXXFLAGS="-fsanitize-coverage=trace-pc-guard -fsanitize=address" \ # LIB_FUZZING_ENGINE=/usr/lib/llvm-4.0/lib/libFuzzer.a \ # fuzz-all # +FUZZ_CXXFLAGS ?= $(CFLAGS) + .PHONY: fuzz-all $(FUZZ_PROGRAMS): all - $(QUIET_LINK)$(CXX) $(CFLAGS) $(LIB_OBJS) $(BUILTIN_OBJS) \ + $(QUIET_LINK)$(CXX) $(FUZZ_CXXFLAGS) $(LIB_OBJS) $(BUILTIN_OBJS) \ $(XDIFF_OBJS) $(EXTLIBS) git.o $@.o $(LIB_FUZZING_ENGINE) -o $@ fuzz-all: $(FUZZ_PROGRAMS) @@ -1748,7 +1748,7 @@ static int parse_fragment(struct apply_state *state, } if (oldlines || newlines) return -1; - if (!deleted && !added) + if (!patch->recount && !deleted && !added) return -1; fragment->leading = leading; @@ -4772,6 +4772,9 @@ static int apply_option_parse_exclude(const struct option *opt, const char *arg, int unset) { struct apply_state *state = opt->value; + + BUG_ON_OPT_NEG(unset); + add_name_limit(state, arg, 1); return 0; } @@ -4780,6 +4783,9 @@ static int apply_option_parse_include(const struct option *opt, const char *arg, int unset) { struct apply_state *state = opt->value; + + BUG_ON_OPT_NEG(unset); + add_name_limit(state, arg, 0); state->has_include = 1; return 0; @@ -4790,6 +4796,9 @@ static int apply_option_parse_p(const struct option *opt, int unset) { struct apply_state *state = opt->value; + + BUG_ON_OPT_NEG(unset); + state->p_value = atoi(arg); state->p_value_known = 1; return 0; @@ -4799,6 +4808,9 @@ static int apply_option_parse_space_change(const struct option *opt, const char *arg, int unset) { struct apply_state *state = opt->value; + + BUG_ON_OPT_ARG(arg); + if (unset) state->ws_ignore_action = ignore_ws_none; else @@ -4810,9 +4822,12 @@ static int apply_option_parse_whitespace(const struct option *opt, const char *arg, int unset) { struct apply_state *state = opt->value; + + BUG_ON_OPT_NEG(unset); + state->whitespace_option = arg; if (parse_whitespace_option(state, arg)) - exit(1); + return -1; return 0; } @@ -4820,6 +4835,9 @@ static int apply_option_parse_directory(const struct option *opt, const char *arg, int unset) { struct apply_state *state = opt->value; + + BUG_ON_OPT_NEG(unset); + strbuf_reset(&state->root); strbuf_addstr(&state->root, arg); strbuf_complete(&state->root, '/'); @@ -4939,10 +4957,10 @@ int apply_parse_options(int argc, const char **argv, struct option builtin_apply_options[] = { { OPTION_CALLBACK, 0, "exclude", state, N_("path"), N_("don't apply changes matching the given path"), - 0, apply_option_parse_exclude }, + PARSE_OPT_NONEG, apply_option_parse_exclude }, { OPTION_CALLBACK, 0, "include", state, N_("path"), N_("apply changes matching the given path"), - 0, apply_option_parse_include }, + PARSE_OPT_NONEG, apply_option_parse_include }, { OPTION_CALLBACK, 'p', NULL, state, N_("num"), N_("remove <num> leading slashes from traditional diff paths"), 0, apply_option_parse_p }, diff --git a/archive-tar.c b/archive-tar.c index 7a535cba24..a58e1a8ebf 100644 --- a/archive-tar.c +++ b/archive-tar.c @@ -202,7 +202,7 @@ static void prepare_header(struct archiver_args *args, unsigned int mode, unsigned long size) { xsnprintf(header->mode, sizeof(header->mode), "%07o", mode & 07777); - xsnprintf(header->size, sizeof(header->size), "%011lo", S_ISREG(mode) ? size : 0); + xsnprintf(header->size, sizeof(header->size), "%011"PRIoMAX , S_ISREG(mode) ? (uintmax_t)size : (uintmax_t)0); xsnprintf(header->mtime, sizeof(header->mtime), "%011lo", (unsigned long) args->time); xsnprintf(header->uid, sizeof(header->uid), "%07o", 0); @@ -41,23 +41,17 @@ const char *git_attr_name(const struct git_attr *attr) struct attr_hashmap { struct hashmap map; -#ifndef NO_PTHREADS pthread_mutex_t mutex; -#endif }; static inline void hashmap_lock(struct attr_hashmap *map) { -#ifndef NO_PTHREADS pthread_mutex_lock(&map->mutex); -#endif } static inline void hashmap_unlock(struct attr_hashmap *map) { -#ifndef NO_PTHREADS pthread_mutex_unlock(&map->mutex); -#endif } /* @@ -498,23 +492,17 @@ static struct check_vector { size_t nr; size_t alloc; struct attr_check **checks; -#ifndef NO_PTHREADS pthread_mutex_t mutex; -#endif } check_vector; static inline void vector_lock(void) { -#ifndef NO_PTHREADS pthread_mutex_lock(&check_vector.mutex); -#endif } static inline void vector_unlock(void) { -#ifndef NO_PTHREADS pthread_mutex_unlock(&check_vector.mutex); -#endif } static void check_vector_add(struct attr_check *c) @@ -1181,8 +1169,6 @@ void git_all_attrs(const struct index_state *istate, void attr_start(void) { -#ifndef NO_PTHREADS pthread_mutex_init(&g_attr_hashmap.mutex, NULL); pthread_mutex_init(&check_vector.mutex, NULL); -#endif } diff --git a/builtin/am.c b/builtin/am.c index dc576a3372..8f27f3375b 100644 --- a/builtin/am.c +++ b/builtin/am.c @@ -2113,7 +2113,9 @@ static int parse_opt_patchformat(const struct option *opt, const char *arg, int { int *opt_value = opt->value; - if (!strcmp(arg, "mbox")) + if (unset) + *opt_value = PATCH_FORMAT_UNKNOWN; + else if (!strcmp(arg, "mbox")) *opt_value = PATCH_FORMAT_MBOX; else if (!strcmp(arg, "stgit")) *opt_value = PATCH_FORMAT_STGIT; diff --git a/builtin/blame.c b/builtin/blame.c index a443af9ee9..06a7163ffe 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -732,6 +732,8 @@ static int blame_copy_callback(const struct option *option, const char *arg, int { int *opt = option->value; + BUG_ON_OPT_NEG(unset); + /* * -C enables copy from removed files; * -C -C enables copy from existing files, but only @@ -754,6 +756,8 @@ static int blame_move_callback(const struct option *option, const char *arg, int { int *opt = option->value; + BUG_ON_OPT_NEG(unset); + *opt |= PICKAXE_BLAME_MOVE; if (arg) diff --git a/builtin/cat-file.c b/builtin/cat-file.c index 0d403eb77d..2ca56fd086 100644 --- a/builtin/cat-file.c +++ b/builtin/cat-file.c @@ -99,7 +99,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name, oi.sizep = &size; if (oid_object_info_extended(the_repository, &oid, &oi, flags) < 0) die("git cat-file: could not get object info"); - printf("%lu\n", size); + printf("%"PRIuMAX"\n", (uintmax_t)size); return 0; case 'e': @@ -245,7 +245,7 @@ static void expand_atom(struct strbuf *sb, const char *atom, int len, if (data->mark_query) data->info.sizep = &data->size; else - strbuf_addf(sb, "%lu", data->size); + strbuf_addf(sb, "%"PRIuMAX , (uintmax_t)data->size); } else if (is_atom("objectsize:disk", atom, len)) { if (data->mark_query) data->info.disk_sizep = &data->disk_size; @@ -603,8 +603,10 @@ static int batch_option_callback(const struct option *opt, { struct batch_options *bo = opt->value; + BUG_ON_OPT_NEG(unset); + if (bo->enabled) { - return 1; + return error(_("only one batch option may be specified")); } bo->enabled = 1; @@ -639,10 +641,12 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "buffer", &batch.buffer_output, N_("buffer --batch output")), { OPTION_CALLBACK, 0, "batch", &batch, "format", N_("show info and content of objects fed from the standard input"), - PARSE_OPT_OPTARG, batch_option_callback }, + PARSE_OPT_OPTARG | PARSE_OPT_NONEG, + batch_option_callback }, { OPTION_CALLBACK, 0, "batch-check", &batch, "format", N_("show info about objects fed from the standard input"), - PARSE_OPT_OPTARG, batch_option_callback }, + PARSE_OPT_OPTARG | PARSE_OPT_NONEG, + batch_option_callback }, OPT_BOOL(0, "follow-symlinks", &batch.follow_symlinks, N_("follow in-tree symlinks (used with --batch or --batch-check)")), OPT_BOOL(0, "batch-all-objects", &batch.all_objects, diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c index 88b86c8d9f..eb74774cbc 100644 --- a/builtin/checkout-index.c +++ b/builtin/checkout-index.c @@ -132,6 +132,8 @@ static const char * const builtin_checkout_index_usage[] = { static int option_parse_stage(const struct option *opt, const char *arg, int unset) { + BUG_ON_OPT_NEG(unset); + if (!strcmp(arg, "all")) { to_tempfile = 1; checkout_stage = CHECKOUT_ALL; diff --git a/builtin/clean.c b/builtin/clean.c index 8d9a7dc206..bbcdeb2d9e 100644 --- a/builtin/clean.c +++ b/builtin/clean.c @@ -140,6 +140,7 @@ static void clean_print_color(enum color_clean ix) static int exclude_cb(const struct option *opt, const char *arg, int unset) { struct string_list *exclude_list = opt->value; + BUG_ON_OPT_NEG(unset); string_list_append(exclude_list, arg); return 0; } diff --git a/builtin/commit.c b/builtin/commit.c index 96d336ec3d..c021b119bb 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -161,6 +161,9 @@ static int opt_parse_m(const struct option *opt, const char *arg, int unset) static int opt_parse_rename_score(const struct option *opt, const char *arg, int unset) { const char **value = opt->value; + + BUG_ON_OPT_NEG(unset); + if (arg != NULL && *arg == '=') arg = arg + 1; @@ -1335,7 +1338,7 @@ int cmd_status(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "no-renames", &no_renames, N_("do not detect renames")), { OPTION_CALLBACK, 'M', "find-renames", &rename_score_arg, N_("n"), N_("detect renames, optionally set similarity index"), - PARSE_OPT_OPTARG, opt_parse_rename_score }, + PARSE_OPT_OPTARG | PARSE_OPT_NONEG, opt_parse_rename_score }, OPT_END(), }; diff --git a/builtin/fast-export.c b/builtin/fast-export.c index 456797c12a..5790f0d554 100644 --- a/builtin/fast-export.c +++ b/builtin/fast-export.c @@ -253,7 +253,7 @@ static void export_blob(const struct object_id *oid) mark_next_object(object); - printf("blob\nmark :%"PRIu32"\ndata %lu\n", last_idnum, size); + printf("blob\nmark :%"PRIu32"\ndata %"PRIuMAX"\n", last_idnum, (uintmax_t)size); if (size && fwrite(buf, size, 1, stdout) != 1) die_errno("could not write blob '%s'", oid_to_hex(oid)); printf("\n"); diff --git a/builtin/fetch.c b/builtin/fetch.c index 6ec7c07d1d..e0140327aa 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -98,6 +98,8 @@ static int git_fetch_config(const char *k, const char *v, void *cb) static int parse_refmap_arg(const struct option *opt, const char *arg, int unset) { + BUG_ON_OPT_NEG(unset); + /* * "git fetch --refmap='' origin foo" * can be used to tell the command not to store anywhere diff --git a/builtin/grep.c b/builtin/grep.c index 56e4a11052..71df52a333 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -34,7 +34,6 @@ static int recurse_submodules; #define GREP_NUM_THREADS_DEFAULT 8 static int num_threads; -#ifndef NO_PTHREADS static pthread_t *threads; /* We use one producer thread and THREADS consumer @@ -70,13 +69,11 @@ static pthread_mutex_t grep_mutex; static inline void grep_lock(void) { - assert(num_threads); pthread_mutex_lock(&grep_mutex); } static inline void grep_unlock(void) { - assert(num_threads); pthread_mutex_unlock(&grep_mutex); } @@ -234,6 +231,9 @@ static int wait_all(void) int hit = 0; int i; + if (!HAVE_THREADS) + BUG("Never call this function unless you have started threads"); + grep_lock(); all_work_added = 1; @@ -265,13 +265,6 @@ static int wait_all(void) return hit; } -#else /* !NO_PTHREADS */ - -static int wait_all(void) -{ - return 0; -} -#endif static int grep_cmd_config(const char *var, const char *value, void *cb) { @@ -284,17 +277,15 @@ static int grep_cmd_config(const char *var, const char *value, void *cb) if (num_threads < 0) die(_("invalid number of threads specified (%d) for %s"), num_threads, var); -#ifdef NO_PTHREADS - else if (num_threads && num_threads != 1) { + else if (!HAVE_THREADS && num_threads > 1) { /* * TRANSLATORS: %s is the configuration * variable for tweaking threads, currently * grep.threads */ warning(_("no threads support, ignoring %s"), var); - num_threads = 0; + num_threads = 1; } -#endif } if (!strcmp(var, "submodule.recurse")) @@ -330,17 +321,14 @@ static int grep_oid(struct grep_opt *opt, const struct object_id *oid, grep_source_init(&gs, GREP_SOURCE_OID, pathbuf.buf, path, oid); strbuf_release(&pathbuf); -#ifndef NO_PTHREADS - if (num_threads) { + if (num_threads > 1) { /* * add_work() copies gs and thus assumes ownership of * its fields, so do not call grep_source_clear() */ add_work(opt, &gs); return 0; - } else -#endif - { + } else { int hit; hit = grep_source(opt, &gs); @@ -363,17 +351,14 @@ static int grep_file(struct grep_opt *opt, const char *filename) grep_source_init(&gs, GREP_SOURCE_FILE, buf.buf, filename, filename); strbuf_release(&buf); -#ifndef NO_PTHREADS - if (num_threads) { + if (num_threads > 1) { /* * add_work() copies gs and thus assumes ownership of * its fields, so do not call grep_source_clear() */ add_work(opt, &gs); return 0; - } else -#endif - { + } else { int hit; hit = grep_source(opt, &gs); @@ -723,11 +708,14 @@ static int context_callback(const struct option *opt, const char *arg, static int file_callback(const struct option *opt, const char *arg, int unset) { struct grep_opt *grep_opt = opt->value; - int from_stdin = !strcmp(arg, "-"); + int from_stdin; FILE *patterns; int lno = 0; struct strbuf sb = STRBUF_INIT; + BUG_ON_OPT_NEG(unset); + + from_stdin = !strcmp(arg, "-"); patterns = from_stdin ? stdin : fopen(arg, "r"); if (!patterns) die_errno(_("cannot open '%s'"), arg); @@ -748,6 +736,8 @@ static int file_callback(const struct option *opt, const char *arg, int unset) static int not_callback(const struct option *opt, const char *arg, int unset) { struct grep_opt *grep_opt = opt->value; + BUG_ON_OPT_NEG(unset); + BUG_ON_OPT_ARG(arg); append_grep_pattern(grep_opt, "--not", "command line", 0, GREP_NOT); return 0; } @@ -755,6 +745,8 @@ static int not_callback(const struct option *opt, const char *arg, int unset) static int and_callback(const struct option *opt, const char *arg, int unset) { struct grep_opt *grep_opt = opt->value; + BUG_ON_OPT_NEG(unset); + BUG_ON_OPT_ARG(arg); append_grep_pattern(grep_opt, "--and", "command line", 0, GREP_AND); return 0; } @@ -762,6 +754,8 @@ static int and_callback(const struct option *opt, const char *arg, int unset) static int open_callback(const struct option *opt, const char *arg, int unset) { struct grep_opt *grep_opt = opt->value; + BUG_ON_OPT_NEG(unset); + BUG_ON_OPT_ARG(arg); append_grep_pattern(grep_opt, "(", "command line", 0, GREP_OPEN_PAREN); return 0; } @@ -769,6 +763,8 @@ static int open_callback(const struct option *opt, const char *arg, int unset) static int close_callback(const struct option *opt, const char *arg, int unset) { struct grep_opt *grep_opt = opt->value; + BUG_ON_OPT_NEG(unset); + BUG_ON_OPT_ARG(arg); append_grep_pattern(grep_opt, ")", "command line", 0, GREP_CLOSE_PAREN); return 0; } @@ -777,6 +773,7 @@ static int pattern_callback(const struct option *opt, const char *arg, int unset) { struct grep_opt *grep_opt = opt->value; + BUG_ON_OPT_NEG(unset); append_grep_pattern(grep_opt, arg, "-e option", 0, GREP_PATTERN); return 0; } @@ -1049,39 +1046,35 @@ int cmd_grep(int argc, const char **argv, const char *prefix) pathspec.recursive = 1; pathspec.recurse_submodules = !!recurse_submodules; -#ifndef NO_PTHREADS - if (list.nr || cached || show_in_pager) - num_threads = 0; - else if (num_threads == 0) - num_threads = GREP_NUM_THREADS_DEFAULT; - else if (num_threads < 0) - die(_("invalid number of threads specified (%d)"), num_threads); - if (num_threads == 1) - num_threads = 0; -#else - if (num_threads) + if (list.nr || cached || show_in_pager) { + if (num_threads > 1) + warning(_("invalid option combination, ignoring --threads")); + num_threads = 1; + } else if (!HAVE_THREADS && num_threads > 1) { warning(_("no threads support, ignoring --threads")); - num_threads = 0; -#endif + num_threads = 1; + } else if (num_threads < 0) + die(_("invalid number of threads specified (%d)"), num_threads); + else if (num_threads == 0) + num_threads = HAVE_THREADS ? GREP_NUM_THREADS_DEFAULT : 1; - if (!num_threads) + if (num_threads > 1) { + if (!HAVE_THREADS) + BUG("Somebody got num_threads calculation wrong!"); + if (!(opt.name_only || opt.unmatch_name_only || opt.count) + && (opt.pre_context || opt.post_context || + opt.file_break || opt.funcbody)) + skip_first_line = 1; + start_threads(&opt); + } else { /* * The compiled patterns on the main path are only * used when not using threading. Otherwise - * start_threads() below calls compile_grep_patterns() + * start_threads() above calls compile_grep_patterns() * for each thread. */ compile_grep_patterns(&opt); - -#ifndef NO_PTHREADS - if (num_threads) { - if (!(opt.name_only || opt.unmatch_name_only || opt.count) - && (opt.pre_context || opt.post_context || - opt.file_break || opt.funcbody)) - skip_first_line = 1; - start_threads(&opt); } -#endif if (show_in_pager && (cached || list.nr)) die(_("--open-files-in-pager only works on the worktree")); @@ -1132,7 +1125,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) hit = grep_objects(&opt, &pathspec, &list); } - if (num_threads) + if (num_threads > 1) hit |= wait_all(); if (hit && show_in_pager) run_pager(&opt, prefix); diff --git a/builtin/index-pack.c b/builtin/index-pack.c index 2004e25da2..ac1f4ea9a7 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -42,9 +42,7 @@ struct base_data { }; struct thread_local { -#ifndef NO_PTHREADS pthread_t thread; -#endif struct base_data *base_cache; size_t base_cache_used; int pack_fd; @@ -98,8 +96,6 @@ static uint32_t input_crc32; static int input_fd, output_fd; static const char *curr_pack; -#ifndef NO_PTHREADS - static struct thread_local *thread_data; static int nr_dispatched; static int threads_active; @@ -179,26 +175,6 @@ static void cleanup_thread(void) free(thread_data); } -#else - -#define read_lock() -#define read_unlock() - -#define counter_lock() -#define counter_unlock() - -#define work_lock() -#define work_unlock() - -#define deepest_delta_lock() -#define deepest_delta_unlock() - -#define type_cas_lock() -#define type_cas_unlock() - -#endif - - static int mark_link(struct object *obj, int type, void *data, struct fsck_options *options) { if (!obj) @@ -364,22 +340,20 @@ static NORETURN void bad_object(off_t offset, const char *format, ...) static inline struct thread_local *get_thread_data(void) { -#ifndef NO_PTHREADS - if (threads_active) - return pthread_getspecific(key); - assert(!threads_active && - "This should only be reached when all threads are gone"); -#endif + if (HAVE_THREADS) { + if (threads_active) + return pthread_getspecific(key); + assert(!threads_active && + "This should only be reached when all threads are gone"); + } return ¬hread_data; } -#ifndef NO_PTHREADS static void set_thread_data(struct thread_local *data) { if (threads_active) pthread_setspecific(key, data); } -#endif static struct base_data *alloc_base_data(void) { @@ -450,7 +424,8 @@ static void *unpack_entry_data(off_t offset, unsigned long size, int hdrlen; if (!is_delta_type(type)) { - hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %lu", type_name(type), size) + 1; + hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %"PRIuMAX, + type_name(type),(uintmax_t)size) + 1; the_hash_algo->init_fn(&c); the_hash_algo->update_fn(&c, hdr, hdrlen); } else @@ -1092,7 +1067,6 @@ static void resolve_base(struct object_entry *obj) find_unresolved_deltas(base_obj); } -#ifndef NO_PTHREADS static void *threaded_second_pass(void *data) { set_thread_data(data); @@ -1116,7 +1090,6 @@ static void *threaded_second_pass(void *data) } return NULL; } -#endif /* * First pass: @@ -1213,7 +1186,6 @@ static void resolve_deltas(void) progress = start_progress(_("Resolving deltas"), nr_ref_deltas + nr_ofs_deltas); -#ifndef NO_PTHREADS nr_dispatched = 0; if (nr_threads > 1 || getenv("GIT_FORCE_THREADS")) { init_thread(); @@ -1229,7 +1201,6 @@ static void resolve_deltas(void) cleanup_thread(); return; } -#endif for (i = 0; i < nr_objects; i++) { struct object_entry *obj = &objects[i]; @@ -1531,11 +1502,10 @@ static int git_index_pack_config(const char *k, const char *v, void *cb) if (nr_threads < 0) die(_("invalid number of threads specified (%d)"), nr_threads); -#ifdef NO_PTHREADS - if (nr_threads != 1) + if (!HAVE_THREADS && nr_threads != 1) { warning(_("no threads support, ignoring %s"), k); - nr_threads = 1; -#endif + nr_threads = 1; + } return 0; } return git_default_config(k, v, cb); @@ -1628,10 +1598,10 @@ static void show_pack_info(int stat_only) chain_histogram[obj_stat[i].delta_depth - 1]++; if (stat_only) continue; - printf("%s %-6s %lu %lu %"PRIuMAX, + printf("%s %-6s %"PRIuMAX" %"PRIuMAX" %"PRIuMAX, oid_to_hex(&obj->idx.oid), - type_name(obj->real_type), obj->size, - (unsigned long)(obj[1].idx.offset - obj->idx.offset), + type_name(obj->real_type), (uintmax_t)obj->size, + (uintmax_t)(obj[1].idx.offset - obj->idx.offset), (uintmax_t)obj->idx.offset); if (is_delta_type(obj->type)) { struct object_entry *bobj = &objects[obj_stat[i].base_object_no]; @@ -1723,12 +1693,10 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix) nr_threads = strtoul(arg+10, &end, 0); if (!arg[10] || *end || nr_threads < 0) usage(index_pack_usage); -#ifdef NO_PTHREADS - if (nr_threads != 1) - warning(_("no threads support, " - "ignoring %s"), arg); - nr_threads = 1; -#endif + if (!HAVE_THREADS && nr_threads != 1) { + warning(_("no threads support, ignoring %s"), arg); + nr_threads = 1; + } } else if (starts_with(arg, "--pack_header=")) { struct pack_header *hdr; char *c; @@ -1791,14 +1759,12 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix) if (strict) opts.flags |= WRITE_IDX_STRICT; -#ifndef NO_PTHREADS - if (!nr_threads) { + if (HAVE_THREADS && !nr_threads) { nr_threads = online_cpus(); /* An experiment showed that more threads does not mean faster */ if (nr_threads > 3) nr_threads = 3; } -#endif curr_pack = open_pack_file(pack_name); parse_pack_header(); diff --git a/builtin/init-db.c b/builtin/init-db.c index 12ddda7e7b..41faffd28d 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -451,6 +451,7 @@ static int guess_repository_type(const char *git_dir) static int shared_callback(const struct option *opt, const char *arg, int unset) { + BUG_ON_OPT_NEG(unset); *((int *) opt->value) = (arg) ? git_config_perm("arg", arg) : PERM_GROUP; return 0; } diff --git a/builtin/interpret-trailers.c b/builtin/interpret-trailers.c index 4b87e0dd2e..8ae40dec47 100644 --- a/builtin/interpret-trailers.c +++ b/builtin/interpret-trailers.c @@ -80,6 +80,8 @@ static int parse_opt_parse(const struct option *opt, const char *arg, v->only_trailers = 1; v->only_input = 1; v->unfold = 1; + BUG_ON_OPT_NEG(unset); + BUG_ON_OPT_ARG(arg); return 0; } diff --git a/builtin/log.c b/builtin/log.c index 061d4fd864..5ac18e2848 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -107,6 +107,8 @@ static int log_line_range_callback(const struct option *option, const char *arg, { struct line_opt_callback_data *data = option->value; + BUG_ON_OPT_NEG(unset); + if (!arg) return -1; @@ -1009,8 +1011,6 @@ static void show_diffstat(struct rev_info *rev, memcpy(&opts, &rev->diffopt, sizeof(opts)); opts.output_format = DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT; - opts.stat_width = MAIL_DEFAULT_WRAP; - diff_setup_done(&opts); diff_tree_oid(get_commit_tree_oid(origin), @@ -1096,7 +1096,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout, if (rev->rdiff1) { fprintf_ln(rev->diffopt.file, "%s", rev->rdiff_title); show_range_diff(rev->rdiff1, rev->rdiff2, - rev->creation_factor, 1, &rev->diffopt); + rev->creation_factor, 1, NULL); } } @@ -1151,6 +1151,8 @@ static int keep_subject = 0; static int keep_callback(const struct option *opt, const char *arg, int unset) { + BUG_ON_OPT_NEG(unset); + BUG_ON_OPT_ARG(arg); ((struct rev_info *)opt->value)->total = -1; keep_subject = 1; return 0; @@ -1161,6 +1163,7 @@ static int subject_prefix = 0; static int subject_prefix_callback(const struct option *opt, const char *arg, int unset) { + BUG_ON_OPT_NEG(unset); subject_prefix = 1; ((struct rev_info *)opt->value)->subject_prefix = arg; return 0; @@ -1168,6 +1171,8 @@ static int subject_prefix_callback(const struct option *opt, const char *arg, static int rfc_callback(const struct option *opt, const char *arg, int unset) { + BUG_ON_OPT_NEG(unset); + BUG_ON_OPT_ARG(arg); return subject_prefix_callback(opt, "RFC PATCH", unset); } @@ -1176,6 +1181,7 @@ static int numbered_cmdline_opt = 0; static int numbered_callback(const struct option *opt, const char *arg, int unset) { + BUG_ON_OPT_ARG(arg); *(int *)opt->value = numbered_cmdline_opt = unset ? 0 : 1; if (unset) auto_number = 0; @@ -1185,6 +1191,7 @@ static int numbered_callback(const struct option *opt, const char *arg, static int no_numbered_callback(const struct option *opt, const char *arg, int unset) { + BUG_ON_OPT_NEG(unset); return numbered_callback(opt, arg, 1); } @@ -1192,6 +1199,7 @@ static int output_directory_callback(const struct option *opt, const char *arg, int unset) { const char **dir = (const char **)opt->value; + BUG_ON_OPT_NEG(unset); if (*dir) die(_("Two output directories?")); *dir = arg; @@ -1508,7 +1516,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) PARSE_OPT_NOARG, numbered_callback }, { OPTION_CALLBACK, 'N', "no-numbered", &numbered, NULL, N_("use [PATCH] even with multiple patches"), - PARSE_OPT_NOARG, no_numbered_callback }, + PARSE_OPT_NOARG | PARSE_OPT_NONEG, no_numbered_callback }, OPT_BOOL('s', "signoff", &do_signoff, N_("add Signed-off-by:")), OPT_BOOL(0, "stdout", &use_stdout, N_("print patches to standard out")), diff --git a/builtin/ls-files.c b/builtin/ls-files.c index 7f9919a362..c70a9c7158 100644 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@ -475,6 +475,8 @@ static int option_parse_exclude(const struct option *opt, { struct string_list *exclude_list = opt->value; + BUG_ON_OPT_NEG(unset); + exc_given = 1; string_list_append(exclude_list, arg); @@ -486,6 +488,8 @@ static int option_parse_exclude_from(const struct option *opt, { struct dir_struct *dir = opt->value; + BUG_ON_OPT_NEG(unset); + exc_given = 1; add_excludes_from_file(dir, arg); @@ -497,6 +501,9 @@ static int option_parse_exclude_standard(const struct option *opt, { struct dir_struct *dir = opt->value; + BUG_ON_OPT_NEG(unset); + BUG_ON_OPT_ARG(arg); + exc_given = 1; setup_standard_excludes(dir); @@ -548,15 +555,16 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) N_("show resolve-undo information")), { OPTION_CALLBACK, 'x', "exclude", &exclude_list, N_("pattern"), N_("skip files matching pattern"), - 0, option_parse_exclude }, + PARSE_OPT_NONEG, option_parse_exclude }, { OPTION_CALLBACK, 'X', "exclude-from", &dir, N_("file"), N_("exclude patterns are read from <file>"), - 0, option_parse_exclude_from }, + PARSE_OPT_NONEG, option_parse_exclude_from }, OPT_STRING(0, "exclude-per-directory", &dir.exclude_per_dir, N_("file"), N_("read additional per-directory exclude patterns in <file>")), { OPTION_CALLBACK, 0, "exclude-standard", &dir, NULL, N_("add the standard git exclusions"), - PARSE_OPT_NOARG, option_parse_exclude_standard }, + PARSE_OPT_NOARG | PARSE_OPT_NONEG, + option_parse_exclude_standard }, OPT_SET_INT_F(0, "full-name", &prefix_len, N_("make the output relative to the project top directory"), 0, PARSE_OPT_NONEG), diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c index fe3b952cb3..7d581d6463 100644 --- a/builtin/ls-tree.c +++ b/builtin/ls-tree.c @@ -100,7 +100,7 @@ static int show_tree(const struct object_id *oid, struct strbuf *base, "BAD"); else xsnprintf(size_text, sizeof(size_text), - "%lu", size); + "%"PRIuMAX, (uintmax_t)size); } else xsnprintf(size_text, sizeof(size_text), "-"); printf("%06o %s %s %7s\t", mode, type, diff --git a/builtin/merge-file.c b/builtin/merge-file.c index b08803e611..06a2f90c48 100644 --- a/builtin/merge-file.c +++ b/builtin/merge-file.c @@ -15,6 +15,8 @@ static int label_cb(const struct option *opt, const char *arg, int unset) static int label_count = 0; const char **names = (const char **)opt->value; + BUG_ON_OPT_NEG(unset); + if (label_count >= 3) return error("too many labels on the command line"); names[label_count++] = arg; diff --git a/builtin/merge.c b/builtin/merge.c index 4aa6071598..c3c976d471 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -224,6 +224,7 @@ static int option_parse_x(const struct option *opt, static int option_parse_n(const struct option *opt, const char *arg, int unset) { + BUG_ON_OPT_ARG(arg); show_diffstat = unset; return 0; } @@ -1336,6 +1337,10 @@ int cmd_merge(int argc, const char **argv, const char *prefix) die(_("%s - not something we can merge"), argv[0]); if (remoteheads->next) die(_("Can merge only exactly one commit into empty head")); + + if (verify_signatures) + verify_merge_signature(remoteheads->item, verbosity); + remote_head_oid = &remoteheads->item->object.oid; read_empty(remote_head_oid, 0); update_ref("initial pull", "HEAD", remote_head_oid, NULL, 0, @@ -1357,31 +1362,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_MAX_HEXSZ + 1]; - struct signature_check signature_check; - memset(&signature_check, 0, sizeof(signature_check)); - - check_commit_signature(commit, &signature_check); - - find_unique_abbrev_r(hex, &commit->object.oid, DEFAULT_ABBREV); - switch (signature_check.result) { - case 'G': - break; - case 'U': - die(_("Commit %s has an untrusted GPG signature, " - "allegedly by %s."), hex, signature_check.signer); - case 'B': - die(_("Commit %s has a bad GPG signature " - "allegedly by %s."), hex, signature_check.signer); - default: /* 'N' */ - die(_("Commit %s does not have a GPG signature."), hex); - } - if (verbosity >= 0 && signature_check.result == 'G') - printf(_("Commit %s has a good GPG signature by %s\n"), - hex, signature_check.signer); - - signature_check_clear(&signature_check); + verify_merge_signature(p->item, verbosity); } } diff --git a/builtin/notes.c b/builtin/notes.c index c05cd004ab..c78b7a0c5b 100644 --- a/builtin/notes.c +++ b/builtin/notes.c @@ -215,6 +215,8 @@ static int parse_msg_arg(const struct option *opt, const char *arg, int unset) { struct note_data *d = opt->value; + BUG_ON_OPT_NEG(unset); + strbuf_grow(&d->buf, strlen(arg) + 2); if (d->buf.len) strbuf_addch(&d->buf, '\n'); @@ -229,6 +231,8 @@ static int parse_file_arg(const struct option *opt, const char *arg, int unset) { struct note_data *d = opt->value; + BUG_ON_OPT_NEG(unset); + if (d->buf.len) strbuf_addch(&d->buf, '\n'); if (!strcmp(arg, "-")) { @@ -250,15 +254,15 @@ static int parse_reuse_arg(const struct option *opt, const char *arg, int unset) enum object_type type; unsigned long len; + BUG_ON_OPT_NEG(unset); + if (d->buf.len) strbuf_addch(&d->buf, '\n'); if (get_oid(arg, &object)) die(_("failed to resolve '%s' as a valid ref."), arg); - if (!(buf = read_object_file(&object, &type, &len))) { - free(buf); + if (!(buf = read_object_file(&object, &type, &len))) die(_("failed to read object '%s'."), arg); - } if (type != OBJ_BLOB) { free(buf); die(_("cannot read note data from non-blob object '%s'."), arg); @@ -273,6 +277,7 @@ static int parse_reuse_arg(const struct option *opt, const char *arg, int unset) static int parse_reedit_arg(const struct option *opt, const char *arg, int unset) { struct note_data *d = opt->value; + BUG_ON_OPT_NEG(unset); d->use_editor = 1; return parse_reuse_arg(opt, arg, unset); } diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index c99ee79c31..411aefd687 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -1953,8 +1953,6 @@ static int delta_cacheable(unsigned long src_size, unsigned long trg_size, return 0; } -#ifndef NO_PTHREADS - /* Protect access to object database */ static pthread_mutex_t read_mutex; #define read_lock() pthread_mutex_lock(&read_mutex) @@ -1979,16 +1977,6 @@ static pthread_mutex_t progress_mutex; * ahead in the list because they can be stolen and would need * progress_mutex for protection. */ -#else - -#define read_lock() (void)0 -#define read_unlock() (void)0 -#define cache_lock() (void)0 -#define cache_unlock() (void)0 -#define progress_lock() (void)0 -#define progress_unlock() (void)0 - -#endif /* * Return the size of the object without doing any delta @@ -2095,9 +2083,9 @@ static int try_delta(struct unpacked *trg, struct unpacked *src, die(_("object %s cannot be read"), oid_to_hex(&trg_entry->idx.oid)); if (sz != trg_size) - die(_("object %s inconsistent object length (%lu vs %lu)"), - oid_to_hex(&trg_entry->idx.oid), sz, - trg_size); + die(_("object %s inconsistent object length (%"PRIuMAX" vs %"PRIuMAX")"), + oid_to_hex(&trg_entry->idx.oid), (uintmax_t)sz, + (uintmax_t)trg_size); *mem_usage += sz; } if (!src->data) { @@ -2122,9 +2110,9 @@ static int try_delta(struct unpacked *trg, struct unpacked *src, oid_to_hex(&src_entry->idx.oid)); } if (sz != src_size) - die(_("object %s inconsistent object length (%lu vs %lu)"), - oid_to_hex(&src_entry->idx.oid), sz, - src_size); + die(_("object %s inconsistent object length (%"PRIuMAX" vs %"PRIuMAX")"), + oid_to_hex(&src_entry->idx.oid), (uintmax_t)sz, + (uintmax_t)src_size); *mem_usage += sz; } if (!src->index) { @@ -2347,8 +2335,6 @@ static void find_deltas(struct object_entry **list, unsigned *list_size, free(array); } -#ifndef NO_PTHREADS - static void try_to_free_from_threads(size_t size) { read_lock(); @@ -2577,10 +2563,6 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size, free(p); } -#else -#define ll_find_deltas(l, s, w, d, p) find_deltas(l, &s, w, d, p) -#endif - static void add_tag_chain(const struct object_id *oid) { struct tag *tag; @@ -2733,12 +2715,10 @@ static int git_pack_config(const char *k, const char *v, void *cb) if (delta_search_threads < 0) die(_("invalid number of threads specified (%d)"), delta_search_threads); -#ifdef NO_PTHREADS - if (delta_search_threads != 1) { + if (!HAVE_THREADS && delta_search_threads != 1) { warning(_("no threads support, ignoring %s"), k); delta_search_threads = 0; } -#endif return 0; } if (!strcmp(k, "pack.indexversion")) { @@ -2806,9 +2786,11 @@ static void show_object(struct object *obj, const char *name, void *data) if (use_delta_islands) { const char *p; - unsigned depth = 0; + unsigned depth; struct object_entry *ent; + /* the empty string is a root tree, which is depth 0 */ + depth = *name ? 1 : 0; for (p = strchr(name, '/'); p; p = strchr(p + 1, '/')) depth++; @@ -3104,6 +3086,7 @@ static void get_object_list(int ac, const char **av) struct rev_info revs; char line[1000]; int flags = 0; + int save_warning; repo_init_revisions(the_repository, &revs, NULL); save_commit_buffer = 0; @@ -3113,6 +3096,9 @@ static void get_object_list(int ac, const char **av) /* make sure shallows are read */ is_repository_shallow(the_repository); + save_warning = warn_on_object_refname_ambiguity; + warn_on_object_refname_ambiguity = 0; + while (fgets(line, sizeof(line), stdin) != NULL) { int len = strlen(line); if (len && line[len - 1] == '\n') @@ -3139,6 +3125,8 @@ static void get_object_list(int ac, const char **av) die(_("bad revision '%s'"), line); } + warn_on_object_refname_ambiguity = save_warning; + if (use_bitmap_index && !get_object_list_from_bitmap(&revs)) return; @@ -3207,6 +3195,9 @@ static int option_parse_index_version(const struct option *opt, { char *c; const char *val = arg; + + BUG_ON_OPT_NEG(unset); + pack_idx_opts.version = strtoul(val, &c, 10); if (pack_idx_opts.version > 2) die(_("unsupported index version %s"), val); @@ -3253,7 +3244,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) N_("similar to --all-progress when progress meter is shown")), { OPTION_CALLBACK, 0, "index-version", NULL, N_("<version>[,<offset>]"), N_("write the pack index file in the specified idx format version"), - 0, option_parse_index_version }, + PARSE_OPT_NONEG, option_parse_index_version }, OPT_MAGNITUDE(0, "max-pack-size", &pack_size_limit, N_("maximum size of each output pack file")), OPT_BOOL(0, "local", &local, @@ -3402,10 +3393,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) if (!delta_search_threads) /* --threads=0 means autodetect */ delta_search_threads = online_cpus(); -#ifdef NO_PTHREADS - if (delta_search_threads != 1) + if (!HAVE_THREADS && delta_search_threads != 1) warning(_("no threads support, ignoring --threads")); -#endif if (!pack_to_stdout && !pack_size_limit) pack_size_limit = pack_size_limit_cfg; if (pack_to_stdout && pack_size_limit) diff --git a/builtin/pull.c b/builtin/pull.c index c21aa276f1..1b90622b13 100644 --- a/builtin/pull.c +++ b/builtin/pull.c @@ -557,6 +557,17 @@ static int run_fetch(const char *repo, const char **refspecs) static int pull_into_void(const struct object_id *merge_head, const struct object_id *curr_head) { + if (opt_verify_signatures) { + struct commit *commit; + + commit = lookup_commit(the_repository, merge_head); + if (!commit) + die(_("unable to access commit %s"), + oid_to_hex(merge_head)); + + verify_merge_signature(commit, opt_verbosity); + } + /* * Two-way merge: we treat the index as based on an empty tree, * and try to fast-forward to HEAD. This ensures we will not lose diff --git a/builtin/read-tree.c b/builtin/read-tree.c index fbbc98e516..183ee8c1e5 100644 --- a/builtin/read-tree.c +++ b/builtin/read-tree.c @@ -44,6 +44,7 @@ static const char * const read_tree_usage[] = { static int index_output_cb(const struct option *opt, const char *arg, int unset) { + BUG_ON_OPT_NEG(unset); set_alternate_index_output(arg); return 0; } @@ -54,6 +55,8 @@ static int exclude_per_directory_cb(const struct option *opt, const char *arg, struct dir_struct *dir; struct unpack_trees_options *opts; + BUG_ON_OPT_NEG(unset); + opts = (struct unpack_trees_options *)opt->value; if (opts->dir) diff --git a/builtin/rebase.c b/builtin/rebase.c index 0ee06aa363..b5c99ec10c 100644 --- a/builtin/rebase.c +++ b/builtin/rebase.c @@ -23,6 +23,7 @@ #include "revision.h" #include "commit-reach.h" #include "rerere.h" +#include "branch.h" static char const * const builtin_rebase_usage[] = { N_("git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] " @@ -48,7 +49,10 @@ static int use_builtin_rebase(void) { struct child_process cp = CHILD_PROCESS_INIT; struct strbuf out = STRBUF_INIT; - int ret; + int ret, env = git_env_bool("GIT_TEST_REBASE_USE_BUILTIN", -1); + + if (env != -1) + return env; argv_array_pushl(&cp.args, "config", "--bool", "rebase.usebuiltin", NULL); @@ -87,7 +91,7 @@ struct rebase_options { REBASE_FORCE = 1<<3, REBASE_INTERACTIVE_EXPLICIT = 1<<4, } flags; - struct strbuf git_am_opt; + struct argv_array git_am_opts; const char *action; int signoff; int allow_rerere_autoupdate; @@ -339,7 +343,7 @@ N_("Resolve all conflicts manually, mark them as resolved with\n" static int run_specific_rebase(struct rebase_options *opts) { const char *argv[] = { NULL, NULL }; - struct strbuf script_snippet = STRBUF_INIT; + struct strbuf script_snippet = STRBUF_INIT, buf = STRBUF_INIT; int status; const char *backend, *backend_func; @@ -433,7 +437,9 @@ static int run_specific_rebase(struct rebase_options *opts) oid_to_hex(&opts->restrict_revision->object.oid) : NULL); add_var(&script_snippet, "GIT_QUIET", opts->flags & REBASE_NO_QUIET ? "" : "t"); - add_var(&script_snippet, "git_am_opt", opts->git_am_opt.buf); + sq_quote_argv_pretty(&buf, opts->git_am_opts.argv); + add_var(&script_snippet, "git_am_opt", buf.buf); + strbuf_release(&buf); add_var(&script_snippet, "verbose", opts->flags & REBASE_VERBOSE ? "t" : ""); add_var(&script_snippet, "diffstat", @@ -522,12 +528,17 @@ finished_rebase: #define GIT_REFLOG_ACTION_ENVIRONMENT "GIT_REFLOG_ACTION" +#define RESET_HEAD_DETACH (1<<0) +#define RESET_HEAD_HARD (1<<1) + static int reset_head(struct object_id *oid, const char *action, - const char *switch_to_branch, int detach_head, + const char *switch_to_branch, unsigned flags, const char *reflog_orig_head, const char *reflog_head) { + unsigned detach_head = flags & RESET_HEAD_DETACH; + unsigned reset_hard = flags & RESET_HEAD_HARD; struct object_id head_oid; - struct tree_desc desc; + struct tree_desc desc[2] = { { NULL }, { NULL } }; struct lock_file lock = LOCK_INIT; struct unpack_trees_options unpack_tree_opts; struct tree *tree; @@ -536,60 +547,63 @@ static int reset_head(struct object_id *oid, const char *action, size_t prefix_len; struct object_id *orig = NULL, oid_orig, *old_orig = NULL, oid_old_orig; - int ret = 0; + int ret = 0, nr = 0; if (switch_to_branch && !starts_with(switch_to_branch, "refs/")) BUG("Not a fully qualified branch: '%s'", switch_to_branch); - if (hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0) - return -1; + if (hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0) { + ret = -1; + goto leave_reset_head; + } - if (!oid) { - if (get_oid("HEAD", &head_oid)) { - rollback_lock_file(&lock); - return error(_("could not determine HEAD revision")); - } - oid = &head_oid; + if ((!oid || !reset_hard) && get_oid("HEAD", &head_oid)) { + ret = error(_("could not determine HEAD revision")); + goto leave_reset_head; } + if (!oid) + oid = &head_oid; + memset(&unpack_tree_opts, 0, sizeof(unpack_tree_opts)); setup_unpack_trees_porcelain(&unpack_tree_opts, action); unpack_tree_opts.head_idx = 1; unpack_tree_opts.src_index = the_repository->index; unpack_tree_opts.dst_index = the_repository->index; - unpack_tree_opts.fn = oneway_merge; + unpack_tree_opts.fn = reset_hard ? oneway_merge : twoway_merge; unpack_tree_opts.update = 1; unpack_tree_opts.merge = 1; if (!detach_head) unpack_tree_opts.reset = 1; if (read_index_unmerged(the_repository->index) < 0) { - rollback_lock_file(&lock); - return error(_("could not read index")); + ret = error(_("could not read index")); + goto leave_reset_head; } - if (!fill_tree_descriptor(&desc, oid)) { - error(_("failed to find tree of %s"), oid_to_hex(oid)); - rollback_lock_file(&lock); - free((void *)desc.buffer); - return -1; + if (!reset_hard && !fill_tree_descriptor(&desc[nr++], &head_oid)) { + ret = error(_("failed to find tree of %s"), + oid_to_hex(&head_oid)); + goto leave_reset_head; } - if (unpack_trees(1, &desc, &unpack_tree_opts)) { - rollback_lock_file(&lock); - free((void *)desc.buffer); - return -1; + if (!fill_tree_descriptor(&desc[nr++], oid)) { + ret = error(_("failed to find tree of %s"), oid_to_hex(oid)); + goto leave_reset_head; + } + + if (unpack_trees(nr, desc, &unpack_tree_opts)) { + ret = -1; + goto leave_reset_head; } tree = parse_tree_indirect(oid); prime_cache_tree(the_repository->index, tree); - if (write_locked_index(the_repository->index, &lock, COMMIT_LOCK) < 0) + if (write_locked_index(the_repository->index, &lock, COMMIT_LOCK) < 0) { ret = error(_("could not write index")); - free((void *)desc.buffer); - - if (ret) - return ret; + goto leave_reset_head; + } reflog_action = getenv(GIT_REFLOG_ACTION_ENVIRONMENT); strbuf_addf(&msg, "%s: ", reflog_action ? reflog_action : "rebase"); @@ -613,7 +627,8 @@ static int reset_head(struct object_id *oid, const char *action, reflog_head = msg.buf; } if (!switch_to_branch) - ret = update_ref(reflog_head, "HEAD", oid, orig, REF_NO_DEREF, + ret = update_ref(reflog_head, "HEAD", oid, orig, + detach_head ? REF_NO_DEREF : 0, UPDATE_REFS_MSG_ON_ERR); else { ret = create_symref("HEAD", switch_to_branch, msg.buf); @@ -622,7 +637,11 @@ static int reset_head(struct object_id *oid, const char *action, UPDATE_REFS_MSG_ON_ERR); } +leave_reset_head: strbuf_release(&msg); + rollback_lock_file(&lock); + while (nr) + free((void *)desc[--nr].buffer); return ret; } @@ -703,6 +722,9 @@ static int parse_opt_merge(const struct option *opt, const char *arg, int unset) { struct rebase_options *opts = opt->value; + BUG_ON_OPT_NEG(unset); + BUG_ON_OPT_ARG(arg); + if (!is_interactive(opts)) opts->type = REBASE_MERGE; @@ -715,6 +737,9 @@ static int parse_opt_interactive(const struct option *opt, const char *arg, { struct rebase_options *opts = opt->value; + BUG_ON_OPT_NEG(unset); + BUG_ON_OPT_ARG(arg); + opts->type = REBASE_INTERACTIVE; opts->flags |= REBASE_INTERACTIVE_EXPLICIT; @@ -751,12 +776,29 @@ static void NORETURN error_on_missing_default_upstream(void) exit(1); } +static void set_reflog_action(struct rebase_options *options) +{ + const char *env; + struct strbuf buf = STRBUF_INIT; + + if (!is_interactive(options)) + return; + + env = getenv(GIT_REFLOG_ACTION_ENVIRONMENT); + if (env && strcmp("rebase", env)) + return; /* only override it if it is "rebase" */ + + strbuf_addf(&buf, "rebase -i (%s)", options->action); + setenv(GIT_REFLOG_ACTION_ENVIRONMENT, buf.buf, 1); + strbuf_release(&buf); +} + int cmd_rebase(int argc, const char **argv, const char *prefix) { struct rebase_options options = { .type = REBASE_UNSPECIFIED, .flags = REBASE_NO_QUIET, - .git_am_opt = STRBUF_INIT, + .git_am_opts = ARGV_ARRAY_INIT, .allow_rerere_autoupdate = -1, .allow_empty_message = 1, .git_format_patch_opt = STRBUF_INIT, @@ -777,12 +819,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) ACTION_EDIT_TODO, ACTION_SHOW_CURRENT_PATCH, } action = NO_ACTION; - int committer_date_is_author_date = 0; - int ignore_date = 0; - int ignore_whitespace = 0; const char *gpg_sign = NULL; - int opt_c = -1; - struct string_list whitespace = STRING_LIST_INIT_NODUP; struct string_list exec = STRING_LIST_INIT_NODUP; const char *rebase_merges = NULL; int fork_point = -1; @@ -804,15 +841,20 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) {OPTION_NEGBIT, 'n', "no-stat", &options.flags, NULL, N_("do not show diffstat of what changed upstream"), PARSE_OPT_NOARG, NULL, REBASE_DIFFSTAT }, - OPT_BOOL(0, "ignore-whitespace", &ignore_whitespace, - N_("passed to 'git apply'")), OPT_BOOL(0, "signoff", &options.signoff, N_("add a Signed-off-by: line to each commit")), - OPT_BOOL(0, "committer-date-is-author-date", - &committer_date_is_author_date, - N_("passed to 'git am'")), - OPT_BOOL(0, "ignore-date", &ignore_date, - N_("passed to 'git am'")), + OPT_PASSTHRU_ARGV(0, "ignore-whitespace", &options.git_am_opts, + NULL, N_("passed to 'git am'"), + PARSE_OPT_NOARG), + OPT_PASSTHRU_ARGV(0, "committer-date-is-author-date", + &options.git_am_opts, NULL, + N_("passed to 'git am'"), PARSE_OPT_NOARG), + OPT_PASSTHRU_ARGV(0, "ignore-date", &options.git_am_opts, NULL, + N_("passed to 'git am'"), PARSE_OPT_NOARG), + OPT_PASSTHRU_ARGV('C', NULL, &options.git_am_opts, N_("n"), + N_("passed to 'git apply'"), 0), + OPT_PASSTHRU_ARGV(0, "whitespace", &options.git_am_opts, + N_("action"), N_("passed to 'git apply'"), 0), OPT_BIT('f', "force-rebase", &options.flags, N_("cherry-pick all commits, even if unchanged"), REBASE_FORCE), @@ -846,7 +888,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) "them"), REBASE_PRESERVE_MERGES), OPT_BOOL(0, "rerere-autoupdate", &options.allow_rerere_autoupdate, - N_("allow rerere to update index with resolved " + N_("allow rerere to update index with resolved " "conflict")), OPT_BOOL('k', "keep-empty", &options.keep_empty, N_("preserve empty commits during rebase")), @@ -856,10 +898,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) { OPTION_STRING, 'S', "gpg-sign", &gpg_sign, N_("key-id"), N_("GPG-sign commits"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" }, - OPT_STRING_LIST(0, "whitespace", &whitespace, - N_("whitespace"), N_("passed to 'git apply'")), - OPT_SET_INT('C', NULL, &opt_c, N_("passed to 'git apply'"), - REBASE_AM), OPT_BOOL(0, "autostash", &options.autostash, N_("automatically stash/stash pop before and after")), OPT_STRING_LIST('x', "exec", &exec, N_("exec"), @@ -884,6 +922,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) N_("rebase all reachable commits up to the root(s)")), OPT_END(), }; + int i; /* * NEEDSWORK: Once the builtin rebase has been tested enough @@ -956,6 +995,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) if (action != NO_ACTION && !in_progress) die(_("No rebase in progress?")); + setenv(GIT_REFLOG_ACTION_ENVIRONMENT, "rebase", 0); if (action == ACTION_EDIT_TODO && !is_interactive(&options)) die(_("The --edit-todo action can only be used during " @@ -968,6 +1008,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) int fd; options.action = "continue"; + set_reflog_action(&options); /* Sanity check */ if (get_oid("HEAD", &head)) @@ -996,12 +1037,15 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) struct string_list merge_rr = STRING_LIST_INIT_DUP; options.action = "skip"; + set_reflog_action(&options); rerere_clear(&merge_rr); string_list_clear(&merge_rr, 1); - if (reset_head(NULL, "reset", NULL, 0, NULL, NULL) < 0) + if (reset_head(NULL, "reset", NULL, RESET_HEAD_HARD, + NULL, NULL) < 0) die(_("could not discard worktree changes")); + remove_branch_state(); if (read_basic_state(&options)) exit(1); goto run_rebase; @@ -1009,6 +1053,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) case ACTION_ABORT: { struct string_list merge_rr = STRING_LIST_INIT_DUP; options.action = "abort"; + set_reflog_action(&options); rerere_clear(&merge_rr); string_list_clear(&merge_rr, 1); @@ -1016,9 +1061,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) if (read_basic_state(&options)) exit(1); if (reset_head(&options.orig_head, "reset", - options.head_name, 0, NULL, NULL) < 0) + options.head_name, RESET_HEAD_HARD, + NULL, NULL) < 0) die(_("could not move back to %s"), oid_to_hex(&options.orig_head)); + remove_branch_state(); ret = finish_rebase(&options); goto cleanup; } @@ -1064,22 +1111,27 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) state_dir_base, cmd_live_rebase, buf.buf); } - if (!(options.flags & REBASE_NO_QUIET)) - strbuf_addstr(&options.git_am_opt, " -q"); - - if (committer_date_is_author_date) { - strbuf_addstr(&options.git_am_opt, - " --committer-date-is-author-date"); - options.flags |= REBASE_FORCE; + for (i = 0; i < options.git_am_opts.argc; i++) { + const char *option = options.git_am_opts.argv[i], *p; + if (!strcmp(option, "--committer-date-is-author-date") || + !strcmp(option, "--ignore-date") || + !strcmp(option, "--whitespace=fix") || + !strcmp(option, "--whitespace=strip")) + options.flags |= REBASE_FORCE; + else if (skip_prefix(option, "-C", &p)) { + while (*p) + if (!isdigit(*(p++))) + die(_("switch `C' expects a " + "numerical value")); + } else if (skip_prefix(option, "--whitespace=", &p)) { + if (*p && strcmp(p, "warn") && strcmp(p, "nowarn") && + strcmp(p, "error") && strcmp(p, "error-all")) + die("Invalid whitespace option: '%s'", p); + } } - if (ignore_whitespace) - strbuf_addstr(&options.git_am_opt, " --ignore-whitespace"); - - if (ignore_date) { - strbuf_addstr(&options.git_am_opt, " --ignore-date"); - options.flags |= REBASE_FORCE; - } + if (!(options.flags & REBASE_NO_QUIET)) + argv_array_push(&options.git_am_opts, "-q"); if (options.keep_empty) imply_interactive(&options, "--keep-empty"); @@ -1089,23 +1141,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) options.gpg_sign_opt = xstrfmt("-S%s", gpg_sign); } - if (opt_c >= 0) - strbuf_addf(&options.git_am_opt, " -C%d", opt_c); - - if (whitespace.nr) { - int i; - - for (i = 0; i < whitespace.nr; i++) { - const char *item = whitespace.items[i].string; - - strbuf_addf(&options.git_am_opt, " --whitespace=%s", - item); - - if ((!strcmp(item, "fix")) || (!strcmp(item, "strip"))) - options.flags |= REBASE_FORCE; - } - } - if (exec.nr) { int i; @@ -1181,23 +1216,18 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) break; } - if (options.git_am_opt.len) { - const char *p; - + if (options.git_am_opts.argc) { /* all am options except -q are compatible only with --am */ - strbuf_reset(&buf); - strbuf_addbuf(&buf, &options.git_am_opt); - strbuf_addch(&buf, ' '); - while ((p = strstr(buf.buf, " -q "))) - strbuf_splice(&buf, p - buf.buf, 4, " ", 1); - strbuf_trim(&buf); + for (i = options.git_am_opts.argc - 1; i >= 0; i--) + if (strcmp(options.git_am_opts.argv[i], "-q")) + break; - if (is_interactive(&options) && buf.len) + if (is_interactive(&options) && i >= 0) die(_("error: cannot combine interactive options " "(--interactive, --exec, --rebase-merges, " "--preserve-merges, --keep-empty, --root + " "--onto) with am options (%s)"), buf.buf); - if (options.type == REBASE_MERGE && buf.len) + if (options.type == REBASE_MERGE && i >= 0) die(_("error: cannot combine merge options (--merge, " "--strategy, --strategy-option) with am options " "(%s)"), buf.buf); @@ -1207,7 +1237,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) if (options.type == REBASE_PRESERVE_MERGES) die("cannot combine '--signoff' with " "'--preserve-merges'"); - strbuf_addstr(&options.git_am_opt, " --signoff"); + argv_array_push(&options.git_am_opts, "--signoff"); options.flags |= REBASE_FORCE; } @@ -1380,7 +1410,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) write_file(autostash, "%s", oid_to_hex(&oid)); printf(_("Created autostash: %s\n"), buf.buf); if (reset_head(&head->object.oid, "reset --hard", - NULL, 0, NULL, NULL) < 0) + NULL, RESET_HEAD_HARD, NULL, NULL) < 0) die(_("could not reset --hard")); printf(_("HEAD is now at %s"), find_unique_abbrev(&head->object.oid, @@ -1431,11 +1461,12 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) } strbuf_reset(&buf); - strbuf_addf(&buf, "rebase: checkout %s", + strbuf_addf(&buf, "%s: checkout %s", + getenv(GIT_REFLOG_ACTION_ENVIRONMENT), options.switch_to); if (reset_head(&oid, "checkout", options.head_name, 0, - NULL, NULL) < 0) { + NULL, buf.buf) < 0) { ret = !!error(_("could not switch to " "%s"), options.switch_to); @@ -1472,10 +1503,15 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) if (options.flags & REBASE_DIFFSTAT) { struct diff_options opts; - if (options.flags & REBASE_VERBOSE) - printf(_("Changes from %s to %s:\n"), - oid_to_hex(&merge_base), - oid_to_hex(&options.onto->object.oid)); + if (options.flags & REBASE_VERBOSE) { + if (is_null_oid(&merge_base)) + printf(_("Changes to %s:\n"), + oid_to_hex(&options.onto->object.oid)); + else + printf(_("Changes from %s to %s:\n"), + oid_to_hex(&merge_base), + oid_to_hex(&options.onto->object.oid)); + } /* We want color (if set), but no pager */ diff_setup(&opts); @@ -1485,8 +1521,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT; opts.detect_rename = DIFF_DETECT_RENAME; diff_setup_done(&opts); - diff_tree_oid(&merge_base, &options.onto->object.oid, - "", &opts); + diff_tree_oid(is_null_oid(&merge_base) ? + the_hash_algo->empty_tree : &merge_base, + &options.onto->object.oid, "", &opts); diffcore_std(&opts); diff_flush(&opts); } @@ -1499,9 +1536,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) printf(_("First, rewinding head to replay your work on top of " "it...\n")); - strbuf_addf(&msg, "rebase: checkout %s", options.onto_name); - if (reset_head(&options.onto->object.oid, "checkout", NULL, 1, - NULL, msg.buf)) + strbuf_addf(&msg, "%s: checkout %s", + getenv(GIT_REFLOG_ACTION_ENVIRONMENT), options.onto_name); + if (reset_head(&options.onto->object.oid, "checkout", NULL, + RESET_HEAD_DETACH, NULL, msg.buf)) die(_("Could not detach HEAD")); strbuf_release(&msg); @@ -1511,7 +1549,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) */ strbuf_reset(&msg); if (!oidcmp(&merge_base, &options.orig_head)) { - printf(_("Fast-forwarded %s to %s. \n"), + printf(_("Fast-forwarded %s to %s.\n"), branch_name, options.onto_name); strbuf_addf(&msg, "rebase finished: %s onto %s", options.head_name ? options.head_name : "detached HEAD", diff --git a/builtin/replace.c b/builtin/replace.c index a58b9c6d13..affcdfb416 100644 --- a/builtin/replace.c +++ b/builtin/replace.c @@ -495,6 +495,7 @@ static int convert_graft_file(int force) if (!fp) return -1; + advice_graft_file_deprecated = 0; while (strbuf_getline(&buf, fp) != EOF) { if (*buf.buf == '#') continue; diff --git a/builtin/show-branch.c b/builtin/show-branch.c index 65f4a4c83c..934e514944 100644 --- a/builtin/show-branch.c +++ b/builtin/show-branch.c @@ -604,6 +604,7 @@ static int parse_reflog_param(const struct option *opt, const char *arg, { char *ep; const char **base = (const char **)opt->value; + BUG_ON_OPT_NEG(unset); if (!arg) arg = ""; reflog = strtoul(arg, &ep, 10); @@ -674,7 +675,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) { OPTION_CALLBACK, 'g', "reflog", &reflog_base, N_("<n>[,<base>]"), N_("show <n> most recent ref-log entries starting at " "base"), - PARSE_OPT_OPTARG, + PARSE_OPT_OPTARG | PARSE_OPT_NONEG, parse_reflog_param }, OPT_END() }; diff --git a/builtin/show-ref.c b/builtin/show-ref.c index 2f13f1316f..ed888ffa48 100644 --- a/builtin/show-ref.c +++ b/builtin/show-ref.c @@ -151,6 +151,7 @@ static int hash_callback(const struct option *opt, const char *arg, int unset) static int exclude_existing_callback(const struct option *opt, const char *arg, int unset) { + BUG_ON_OPT_NEG(unset); exclude_arg = 1; *(const char **)opt->value = arg; return 0; diff --git a/builtin/tag.c b/builtin/tag.c index f623632186..02f6bd1279 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -338,6 +338,8 @@ static int parse_msg_arg(const struct option *opt, const char *arg, int unset) { struct msg_arg *msg = opt->value; + BUG_ON_OPT_NEG(unset); + if (!arg) return -1; if (msg->buf.len) @@ -390,8 +392,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix) OPT_GROUP(N_("Tag creation options")), OPT_BOOL('a', "annotate", &annotate, N_("annotated tag, needs a message")), - OPT_CALLBACK('m', "message", &msg, N_("message"), - N_("tag message"), parse_msg_arg), + { OPTION_CALLBACK, 'm', "message", &msg, N_("message"), + N_("tag message"), PARSE_OPT_NONEG, parse_msg_arg }, OPT_FILENAME('F', "file", &msgfile, N_("read message from file")), OPT_BOOL('e', "edit", &edit_flag, N_("force edit of tag message")), OPT_BOOL('s', "sign", &opt.sign, N_("annotated and GPG-signed tag")), diff --git a/builtin/update-index.c b/builtin/update-index.c index 0e1dcf0438..31e7cce301 100644 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@ -790,12 +790,16 @@ static int refresh(struct refresh_params *o, unsigned int flag) static int refresh_callback(const struct option *opt, const char *arg, int unset) { + BUG_ON_OPT_NEG(unset); + BUG_ON_OPT_ARG(arg); return refresh(opt->value, 0); } static int really_refresh_callback(const struct option *opt, const char *arg, int unset) { + BUG_ON_OPT_NEG(unset); + BUG_ON_OPT_ARG(arg); return refresh(opt->value, REFRESH_REALLY); } @@ -803,6 +807,7 @@ static int chmod_callback(const struct option *opt, const char *arg, int unset) { char *flip = opt->value; + BUG_ON_OPT_NEG(unset); if ((arg[0] != '-' && arg[0] != '+') || arg[1] != 'x' || arg[2]) return error("option 'chmod' expects \"+x\" or \"-x\""); *flip = arg[0]; @@ -812,6 +817,8 @@ static int chmod_callback(const struct option *opt, static int resolve_undo_clear_callback(const struct option *opt, const char *arg, int unset) { + BUG_ON_OPT_NEG(unset); + BUG_ON_OPT_ARG(arg); resolve_undo_clear(); return 0; } @@ -847,6 +854,8 @@ static int cacheinfo_callback(struct parse_opt_ctx_t *ctx, unsigned int mode; const char *path; + BUG_ON_OPT_NEG(unset); + if (!parse_new_style_cacheinfo(ctx->argv[1], &mode, &oid, &path)) { if (add_cacheinfo(mode, &oid, path, 0)) die("git update-index: --cacheinfo cannot add %s", path); @@ -869,6 +878,8 @@ static int stdin_cacheinfo_callback(struct parse_opt_ctx_t *ctx, { int *nul_term_line = opt->value; + BUG_ON_OPT_NEG(unset); + if (ctx->argc != 1) return error("option '%s' must be the last argument", opt->long_name); allow_add = allow_replace = allow_remove = 1; @@ -881,6 +892,8 @@ static int stdin_callback(struct parse_opt_ctx_t *ctx, { int *read_from_stdin = opt->value; + BUG_ON_OPT_NEG(unset); + if (ctx->argc != 1) return error("option '%s' must be the last argument", opt->long_name); *read_from_stdin = 1; @@ -888,11 +901,13 @@ static int stdin_callback(struct parse_opt_ctx_t *ctx, } static int unresolve_callback(struct parse_opt_ctx_t *ctx, - const struct option *opt, int flags) + const struct option *opt, int unset) { int *has_errors = opt->value; const char *prefix = startup_info->prefix; + BUG_ON_OPT_NEG(unset); + /* consume remaining arguments. */ *has_errors = do_unresolve(ctx->argc, ctx->argv, prefix, prefix ? strlen(prefix) : 0); @@ -905,11 +920,13 @@ static int unresolve_callback(struct parse_opt_ctx_t *ctx, } static int reupdate_callback(struct parse_opt_ctx_t *ctx, - const struct option *opt, int flags) + const struct option *opt, int unset) { int *has_errors = opt->value; const char *prefix = startup_info->prefix; + BUG_ON_OPT_NEG(unset); + /* consume remaining arguments. */ setup_work_tree(); *has_errors = do_reupdate(ctx->argc, ctx->argv, @@ -243,7 +243,7 @@ out: } -/* Write the pack data to bundle_fd, then close it if it is > 1. */ +/* Write the pack data to bundle_fd */ static int write_pack_data(int bundle_fd, struct rev_info *revs) { struct child_process pack_objects = CHILD_PROCESS_INIT; @@ -256,6 +256,20 @@ static int write_pack_data(int bundle_fd, struct rev_info *revs) pack_objects.in = -1; pack_objects.out = bundle_fd; pack_objects.git_cmd = 1; + + /* + * start_command() will close our descriptor if it's >1. Duplicate it + * to avoid surprising the caller. + */ + if (pack_objects.out > 1) { + pack_objects.out = dup(pack_objects.out); + if (pack_objects.out < 0) { + error_errno(_("unable to dup bundle descriptor")); + child_process_clear(&pack_objects); + return -1; + } + } + if (start_command(&pack_objects)) return error(_("Could not spawn pack-objects")); @@ -421,21 +435,10 @@ int create_bundle(struct bundle_header *header, const char *path, bundle_to_stdout = !strcmp(path, "-"); if (bundle_to_stdout) bundle_fd = 1; - else { + else bundle_fd = hold_lock_file_for_update(&lock, path, LOCK_DIE_ON_ERROR); - /* - * write_pack_data() will close the fd passed to it, - * but commit_lock_file() will also try to close the - * lockfile's fd. So make a copy of the file - * descriptor to avoid trying to close it twice. - */ - bundle_fd = dup(bundle_fd); - if (bundle_fd < 0) - die_errno("unable to dup file descriptor"); - } - /* write signature */ write_or_die(bundle_fd, bundle_signature, strlen(bundle_signature)); @@ -463,10 +466,8 @@ int create_bundle(struct bundle_header *header, const char *path, goto err; /* write pack */ - if (write_pack_data(bundle_fd, &revs)) { - bundle_fd = -1; /* already closed by the above call */ + if (write_pack_data(bundle_fd, &revs)) goto err; - } if (!bundle_to_stdout) { if (commit_lock_file(&lock)) @@ -474,11 +475,7 @@ int create_bundle(struct bundle_header *header, const char *path, } return 0; err: - if (!bundle_to_stdout) { - if (0 <= bundle_fd) - close(bundle_fd); - rollback_lock_file(&lock); - } + rollback_lock_file(&lock); return -1; } diff --git a/ci/lib-travisci.sh b/ci/lib-travisci.sh index 06970f7213..69dff4d1ec 100755 --- a/ci/lib-travisci.sh +++ b/ci/lib-travisci.sh @@ -123,7 +123,7 @@ osx-clang|osx-gcc) # Travis CI OS X export GIT_SKIP_TESTS="t9810 t9816" ;; -GETTEXT_POISON) - export GETTEXT_POISON=YesPlease +GIT_TEST_GETTEXT_POISON) + export GIT_TEST_GETTEXT_POISON=YesPlease ;; esac @@ -657,11 +657,10 @@ struct commit *pop_commit(struct commit_list **stack) /* count number of children that have not been emitted */ define_commit_slab(indegree_slab, int); -/* record author-date for each commit object */ define_commit_slab(author_date_slab, timestamp_t); -static void record_author_date(struct author_date_slab *author_date, - struct commit *commit) +void record_author_date(struct author_date_slab *author_date, + struct commit *commit) { const char *buffer = get_commit_buffer(commit, NULL); struct ident_split ident; @@ -686,8 +685,8 @@ fail_exit: unuse_commit_buffer(commit, buffer); } -static int compare_commits_by_author_date(const void *a_, const void *b_, - void *cb_data) +int compare_commits_by_author_date(const void *a_, const void *b_, + void *cb_data) { const struct commit *a = a_, *b = b_; struct author_date_slab *author_date = cb_data; @@ -1100,7 +1099,33 @@ int check_commit_signature(const struct commit *commit, struct signature_check * return ret; } +void verify_merge_signature(struct commit *commit, int verbosity) +{ + char hex[GIT_MAX_HEXSZ + 1]; + struct signature_check signature_check; + memset(&signature_check, 0, sizeof(signature_check)); + + check_commit_signature(commit, &signature_check); + + find_unique_abbrev_r(hex, &commit->object.oid, DEFAULT_ABBREV); + switch (signature_check.result) { + case 'G': + break; + case 'U': + die(_("Commit %s has an untrusted GPG signature, " + "allegedly by %s."), hex, signature_check.signer); + case 'B': + die(_("Commit %s has a bad GPG signature " + "allegedly by %s."), hex, signature_check.signer); + default: /* 'N' */ + die(_("Commit %s does not have a GPG signature."), hex); + } + if (verbosity >= 0 && signature_check.result == 'G') + printf(_("Commit %s has a good GPG signature by %s\n"), + hex, signature_check.signer); + signature_check_clear(&signature_check); +} void append_merge_tag_headers(struct commit_list *parents, struct commit_extra_header ***tail) @@ -8,6 +8,7 @@ #include "gpg-interface.h" #include "string-list.h" #include "pretty.h" +#include "commit-slab.h" #define COMMIT_NOT_FROM_GRAPH 0xFFFFFFFF #define GENERATION_NUMBER_INFINITY 0xFFFFFFFF @@ -333,6 +334,20 @@ extern int remove_signature(struct strbuf *buf); */ extern int check_commit_signature(const struct commit *commit, struct signature_check *sigc); +/* record author-date for each commit object */ +struct author_date_slab; +void record_author_date(struct author_date_slab *author_date, + struct commit *commit); + +int compare_commits_by_author_date(const void *a_, const void *b_, void *unused); + +/* + * Verify a single commit with check_commit_signature() and die() if it is not + * a good signature. This isn't really suitable for general use, but is a + * helper to implement consistent logic for pull/merge --verify-signatures. + */ +void verify_merge_signature(struct commit *commit, int verbose); + int compare_commits_by_commit_date(const void *a_, const void *b_, void *unused); int compare_commits_by_gen_then_commit_date(const void *a_, const void *b_, void *unused); diff --git a/compat/mingw.c b/compat/mingw.c index d2f4fabb44..34b3880b29 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1028,8 +1028,8 @@ char *mingw_getcwd(char *pointer, int len) } /* - * See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx - * (Parsing C++ Command-Line Arguments) + * See "Parsing C++ Command-Line Arguments" at Microsoft's Docs: + * https://docs.microsoft.com/en-us/cpp/cpp/parsing-cpp-command-line-arguments */ static const char *quote_arg(const char *arg) { @@ -2211,24 +2211,12 @@ int mingw_raise(int sig) int link(const char *oldpath, const char *newpath) { - typedef BOOL (WINAPI *T)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES); - static T create_hard_link = NULL; wchar_t woldpath[MAX_PATH], wnewpath[MAX_PATH]; if (xutftowcs_path(woldpath, oldpath) < 0 || xutftowcs_path(wnewpath, newpath) < 0) return -1; - if (!create_hard_link) { - create_hard_link = (T) GetProcAddress( - GetModuleHandle("kernel32.dll"), "CreateHardLinkW"); - if (!create_hard_link) - create_hard_link = (T)-1; - } - if (create_hard_link == (T)-1) { - errno = ENOSYS; - return -1; - } - if (!create_hard_link(wnewpath, woldpath, NULL)) { + if (!CreateHardLinkW(wnewpath, woldpath, NULL)) { errno = err_win_to_posix(GetLastError()); return -1; } diff --git a/compat/win32/pthread.c b/compat/win32/pthread.c index e18f5c6e2e..2e7eead42c 100644 --- a/compat/win32/pthread.c +++ b/compat/win32/pthread.c @@ -56,141 +56,3 @@ pthread_t pthread_self(void) t.tid = GetCurrentThreadId(); return t; } - -int pthread_cond_init(pthread_cond_t *cond, const void *unused) -{ - cond->waiters = 0; - cond->was_broadcast = 0; - InitializeCriticalSection(&cond->waiters_lock); - - cond->sema = CreateSemaphore(NULL, 0, LONG_MAX, NULL); - if (!cond->sema) - die("CreateSemaphore() failed"); - - cond->continue_broadcast = CreateEvent(NULL, /* security */ - FALSE, /* auto-reset */ - FALSE, /* not signaled */ - NULL); /* name */ - if (!cond->continue_broadcast) - die("CreateEvent() failed"); - - return 0; -} - -int pthread_cond_destroy(pthread_cond_t *cond) -{ - CloseHandle(cond->sema); - CloseHandle(cond->continue_broadcast); - DeleteCriticalSection(&cond->waiters_lock); - return 0; -} - -int pthread_cond_wait(pthread_cond_t *cond, CRITICAL_SECTION *mutex) -{ - int last_waiter; - - EnterCriticalSection(&cond->waiters_lock); - cond->waiters++; - LeaveCriticalSection(&cond->waiters_lock); - - /* - * Unlock external mutex and wait for signal. - * NOTE: we've held mutex locked long enough to increment - * waiters count above, so there's no problem with - * leaving mutex unlocked before we wait on semaphore. - */ - LeaveCriticalSection(mutex); - - /* let's wait - ignore return value */ - WaitForSingleObject(cond->sema, INFINITE); - - /* - * Decrease waiters count. If we are the last waiter, then we must - * notify the broadcasting thread that it can continue. - * But if we continued due to cond_signal, we do not have to do that - * because the signaling thread knows that only one waiter continued. - */ - EnterCriticalSection(&cond->waiters_lock); - cond->waiters--; - last_waiter = cond->was_broadcast && cond->waiters == 0; - LeaveCriticalSection(&cond->waiters_lock); - - if (last_waiter) { - /* - * cond_broadcast was issued while mutex was held. This means - * that all other waiters have continued, but are contending - * for the mutex at the end of this function because the - * broadcasting thread did not leave cond_broadcast, yet. - * (This is so that it can be sure that each waiter has - * consumed exactly one slice of the semaphor.) - * The last waiter must tell the broadcasting thread that it - * can go on. - */ - SetEvent(cond->continue_broadcast); - /* - * Now we go on to contend with all other waiters for - * the mutex. Auf in den Kampf! - */ - } - /* lock external mutex again */ - EnterCriticalSection(mutex); - - return 0; -} - -/* - * IMPORTANT: This implementation requires that pthread_cond_signal - * is called while the mutex is held that is used in the corresponding - * pthread_cond_wait calls! - */ -int pthread_cond_signal(pthread_cond_t *cond) -{ - int have_waiters; - - EnterCriticalSection(&cond->waiters_lock); - have_waiters = cond->waiters > 0; - LeaveCriticalSection(&cond->waiters_lock); - - /* - * Signal only when there are waiters - */ - if (have_waiters) - return ReleaseSemaphore(cond->sema, 1, NULL) ? - 0 : err_win_to_posix(GetLastError()); - else - return 0; -} - -/* - * DOUBLY IMPORTANT: This implementation requires that pthread_cond_broadcast - * is called while the mutex is held that is used in the corresponding - * pthread_cond_wait calls! - */ -int pthread_cond_broadcast(pthread_cond_t *cond) -{ - EnterCriticalSection(&cond->waiters_lock); - - if ((cond->was_broadcast = cond->waiters > 0)) { - /* wake up all waiters */ - ReleaseSemaphore(cond->sema, cond->waiters, NULL); - LeaveCriticalSection(&cond->waiters_lock); - /* - * At this point all waiters continue. Each one takes its - * slice of the semaphor. Now it's our turn to wait: Since - * the external mutex is held, no thread can leave cond_wait, - * yet. For this reason, we can be sure that no thread gets - * a chance to eat *more* than one slice. OTOH, it means - * that the last waiter must send us a wake-up. - */ - WaitForSingleObject(cond->continue_broadcast, INFINITE); - /* - * Since the external mutex is held, no thread can enter - * cond_wait, and, hence, it is safe to reset this flag - * without cond->waiters_lock held. - */ - cond->was_broadcast = 0; - } else { - LeaveCriticalSection(&cond->waiters_lock); - } - return 0; -} diff --git a/compat/win32/pthread.h b/compat/win32/pthread.h index 1c164088fb..c6cb8dd219 100644 --- a/compat/win32/pthread.h +++ b/compat/win32/pthread.h @@ -32,27 +32,13 @@ typedef int pthread_mutexattr_t; #define pthread_mutexattr_settype(a, t) 0 #define PTHREAD_MUTEX_RECURSIVE 0 -/* - * Implement simple condition variable for Windows threads, based on ACE - * implementation. - * - * See original implementation: http://bit.ly/1vkDjo - * ACE homepage: http://www.cse.wustl.edu/~schmidt/ACE.html - * See also: http://www.cse.wustl.edu/~schmidt/win32-cv-1.html - */ -typedef struct { - LONG waiters; - int was_broadcast; - CRITICAL_SECTION waiters_lock; - HANDLE sema; - HANDLE continue_broadcast; -} pthread_cond_t; - -extern int pthread_cond_init(pthread_cond_t *cond, const void *unused); -extern int pthread_cond_destroy(pthread_cond_t *cond); -extern int pthread_cond_wait(pthread_cond_t *cond, CRITICAL_SECTION *mutex); -extern int pthread_cond_signal(pthread_cond_t *cond); -extern int pthread_cond_broadcast(pthread_cond_t *cond); +#define pthread_cond_t CONDITION_VARIABLE + +#define pthread_cond_init(a,b) InitializeConditionVariable((a)) +#define pthread_cond_destroy(a) do {} while (0) +#define pthread_cond_wait(a,b) return_0(SleepConditionVariableCS((a), (b), INFINITE)) +#define pthread_cond_signal WakeConditionVariable +#define pthread_cond_broadcast WakeAllConditionVariable /* * Simple thread creation implementation using pthread API @@ -1668,6 +1668,8 @@ static int do_git_config_sequence(const struct config_options *opts, if (opts->commondir) repo_config = mkpathdup("%s/config", opts->commondir); + else if (opts->git_dir) + BUG("git_dir without commondir"); else repo_config = NULL; @@ -2292,22 +2294,25 @@ int git_config_get_fsmonitor(void) return 0; } -int git_config_get_index_threads(void) +int git_config_get_index_threads(int *dest) { - int is_bool, val = 0; + int is_bool, val; val = git_env_ulong("GIT_TEST_INDEX_THREADS", 0); - if (val) - return val; + if (val) { + *dest = val; + return 0; + } if (!git_config_get_bool_or_int("index.threads", &is_bool, &val)) { if (is_bool) - return val ? 0 : 1; + *dest = val ? 0 : 1; else - return val; + *dest = val; + return 0; } - return 0; /* auto */ + return 1; } NORETURN @@ -246,11 +246,11 @@ extern int git_config_get_bool(const char *key, int *dest); extern int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest); extern int git_config_get_maybe_bool(const char *key, int *dest); extern int git_config_get_pathname(const char *key, const char **dest); +extern int git_config_get_index_threads(int *dest); extern int git_config_get_untracked_cache(void); extern int git_config_get_split_index(void); extern int git_config_get_max_percent_split_change(void); extern int git_config_get_fsmonitor(void); -extern int git_config_get_index_threads(void); /* This dies if the configured or default date is in the future */ extern int git_config_get_expiry(const char *key, const char **output); diff --git a/config.mak.uname b/config.mak.uname index f179d7a1dc..3ee7da0e23 100644 --- a/config.mak.uname +++ b/config.mak.uname @@ -430,8 +430,6 @@ ifeq ($(uname_S),Minix) NO_NSEC = YesPlease NEEDS_LIBGEN = NEEDS_CRYPTO_WITH_SSL = YesPlease - NEEDS_IDN_WITH_CURL = YesPlease - NEEDS_SSL_WITH_CURL = YesPlease NEEDS_RESOLV = NO_HSTRERROR = YesPlease NO_MMAP = YesPlease @@ -457,7 +455,6 @@ ifeq ($(uname_S),NONSTOP_KERNEL) # Missdetected, hence commented out, see below. #NO_CURL = YesPlease # Added manually, see above. - NEEDS_SSL_WITH_CURL = YesPlease HAVE_LIBCHARSET_H = YesPlease HAVE_STRINGS_H = YesPlease NEEDS_LIBICONV = YesPlease diff --git a/configure.ac b/configure.ac index e11b7976ab..e0d0da3c0c 100644 --- a/configure.ac +++ b/configure.ac @@ -600,17 +600,14 @@ AC_CHECK_PROG([CURL_CONFIG], [curl-config], if test $CURL_CONFIG != no; then GIT_CONF_SUBST([CURL_CONFIG]) - if test -z "${NO_OPENSSL}"; then - AC_MSG_CHECKING([if Curl supports SSL]) - if test $(curl-config --features|grep SSL) = SSL; then - NEEDS_SSL_WITH_CURL=YesPlease - AC_MSG_RESULT([yes]) - else - NEEDS_SSL_WITH_CURL= - AC_MSG_RESULT([no]) - fi - GIT_CONF_SUBST([NEEDS_SSL_WITH_CURL]) + + if test -z "$CURL_CONFIG_OPTS"; then + CURL_CONFIG_OPTS="--libs" fi + + CURL_LDFLAGS=$($CURL_CONFIG $CURL_CONFIG_OPTS) + AC_MSG_NOTICE([Setting CURL_LDFLAGS to '$CURL_LDFLAGS']) + GIT_CONF_SUBST([CURL_LDFLAGS], [$CURL_LDFLAGS]) fi fi @@ -792,6 +789,12 @@ AC_CHECK_HEADER([sys/select.h], [NO_SYS_SELECT_H=UnfortunatelyYes]) GIT_CONF_SUBST([NO_SYS_SELECT_H]) # +# Define NO_POLL_H if you don't have poll.h +AC_CHECK_HEADER([poll.h], +[NO_POLL_H=], +[NO_POLL_H=UnfortunatelyYes]) +GIT_CONF_SUBST([NO_POLL_H]) +# # Define NO_SYS_POLL_H if you don't have sys/poll.h AC_CHECK_HEADER([sys/poll.h], [NO_SYS_POLL_H=], diff --git a/contrib/coccinelle/README b/contrib/coccinelle/README index 9c2f8879c2..f0e80bd7f0 100644 --- a/contrib/coccinelle/README +++ b/contrib/coccinelle/README @@ -1,2 +1,43 @@ This directory provides examples of Coccinelle (http://coccinelle.lip6.fr/) semantic patches that might be useful to developers. + +There are two types of semantic patches: + + * Using the semantic transformation to check for bad patterns in the code; + The target 'make coccicheck' is designed to check for these patterns and + it is expected that any resulting patch indicates a regression. + The patches resulting from 'make coccicheck' are small and infrequent, + so once they are found, they can be sent to the mailing list as per usual. + + Example for introducing new patterns: + 67947c34ae (convert "hashcmp() != 0" to "!hasheq()", 2018-08-28) + b84c783882 (fsck: s/++i > 1/i++/, 2018-10-24) + + Example of fixes using this approach: + 248f66ed8e (run-command: use strbuf_addstr() for adding a string to + a strbuf, 2018-03-25) + f919ffebed (Use MOVE_ARRAY, 2018-01-22) + + These types of semantic patches are usually part of testing, c.f. + 0860a7641b (travis-ci: fail if Coccinelle static analysis found something + to transform, 2018-07-23) + + * Using semantic transformations in large scale refactorings throughout + the code base. + + When applying the semantic patch into a real patch, sending it to the + mailing list in the usual way, such a patch would be expected to have a + lot of textual and semantic conflicts as such large scale refactorings + change function signatures that are used widely in the code base. + A textual conflict would arise if surrounding code near any call of such + function changes. A semantic conflict arises when other patch series in + flight introduce calls to such functions. + + So to aid these large scale refactorings, semantic patches can be used. + However we do not want to store them in the same place as the checks for + bad patterns, as then automated builds would fail. + That is why semantic patches 'contrib/coccinelle/*.pending.cocci' + are ignored for checks, and can be applied using 'make coccicheck-pending'. + + This allows to expose plans of pending large scale refactorings without + impacting the bad pattern checks. @@ -3228,7 +3228,7 @@ static void emit_binary_diff_body(struct diff_options *o, } if (delta && delta_size < deflate_size) { - char *s = xstrfmt("%lu", orig_size); + char *s = xstrfmt("%"PRIuMAX , (uintmax_t)orig_size); emit_diff_symbol(o, DIFF_SYMBOL_BINARY_DIFF_HEADER_DELTA, s, strlen(s), 0); free(s); @@ -404,7 +404,7 @@ static void mark_colliding_entries(const struct checkout *state, { int i, trust_ino = check_stat; -#if defined(GIT_WINDOWS_NATIVE) +#if defined(GIT_WINDOWS_NATIVE) || defined(__CYGWIN__) trust_ino = 0; #endif @@ -419,7 +419,7 @@ static void mark_colliding_entries(const struct checkout *state, if (dup->ce_flags & (CE_MATCHED | CE_VALID | CE_SKIP_WORKTREE)) continue; - if ((trust_ino && dup->ce_stat_data.sd_ino == st->st_ino) || + if ((trust_ino && !match_stat_data(&dup->ce_stat_data, st)) || (!trust_ino && !fspathcmp(ce->name, dup->name))) { dup->ce_flags |= CE_MATCHED; break; diff --git a/fast-import.c b/fast-import.c index 95600c78e0..69886687ce 100644 --- a/fast-import.c +++ b/fast-import.c @@ -2955,8 +2955,8 @@ static void cat_blob(struct object_entry *oe, struct object_id *oid) die("Object %s is a %s but a blob was expected.", oid_to_hex(oid), type_name(type)); strbuf_reset(&line); - strbuf_addf(&line, "%s %s %lu\n", oid_to_hex(oid), - type_name(type), size); + strbuf_addf(&line, "%s %s %"PRIuMAX"\n", oid_to_hex(oid), + type_name(type), (uintmax_t)size); cat_blob_write(line.buf, line.len); strbuf_release(&line); cat_blob_write(buf, size); @@ -7,6 +7,7 @@ #include "gettext.h" #include "strbuf.h" #include "utf8.h" +#include "config.h" #ifndef NO_GETTEXT # include <locale.h> @@ -46,15 +47,15 @@ const char *get_preferred_languages(void) return NULL; } -#ifdef GETTEXT_POISON int use_gettext_poison(void) { static int poison_requested = -1; - if (poison_requested == -1) - poison_requested = getenv("GIT_GETTEXT_POISON") ? 1 : 0; + if (poison_requested == -1) { + const char *v = getenv("GIT_TEST_GETTEXT_POISON"); + poison_requested = v && strlen(v) ? 1 : 0; + } return poison_requested; } -#endif #ifndef NO_GETTEXT static int test_vsnprintf(const char *fmt, ...) @@ -164,6 +165,8 @@ void git_setup_gettext(void) if (!podir) podir = p = system_path(GIT_LOCALE_PATH); + use_gettext_poison(); /* getenv() reentrancy paranoia */ + if (!is_directory(podir)) { free(p); return; @@ -28,12 +28,15 @@ #define FORMAT_PRESERVING(n) __attribute__((format_arg(n))) +extern int use_gettext_poison(void); + #ifndef NO_GETTEXT extern void git_setup_gettext(void); extern int gettext_width(const char *s); #else static inline void git_setup_gettext(void) { + use_gettext_poison(); /* getenv() reentrancy paranoia */ } static inline int gettext_width(const char *s) { @@ -41,12 +44,6 @@ static inline int gettext_width(const char *s) } #endif -#ifdef GETTEXT_POISON -extern int use_gettext_poison(void); -#else -#define use_gettext_poison() 0 -#endif - static inline FORMAT_PRESERVING(1) const char *_(const char *msgid) { if (!*msgid) diff --git a/git-compat-util.h b/git-compat-util.h index 3a08d9916f..09b0102cae 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -180,9 +180,12 @@ #include <regex.h> #include <utime.h> #include <syslog.h> -#ifndef NO_SYS_POLL_H +#if !defined(NO_POLL_H) +#include <poll.h> +#elif !defined(NO_SYS_POLL_H) #include <sys/poll.h> #else +/* Pull the compat stuff */ #include <poll.h> #endif #ifdef HAVE_BSD_SYSCTL @@ -858,6 +861,7 @@ extern FILE *fopen_or_warn(const char *path, const char *mode); #define FREE_AND_NULL(p) do { free(p); (p) = NULL; } while (0) #define ALLOC_ARRAY(x, alloc) (x) = xmalloc(st_mult(sizeof(*(x)), (alloc))) +#define CALLOC_ARRAY(x, alloc) (x) = xcalloc((alloc), sizeof(*(x))); #define REALLOC_ARRAY(x, alloc) (x) = xrealloc((x), st_mult(sizeof(*(x)), (alloc))) #define COPY_ARRAY(dst, src, n) copy_array((dst), (src), (n), sizeof(*(dst)) + \ diff --git a/git-legacy-rebase.sh b/git-legacy-rebase.sh index 75a08b2683..b4c7dbfa57 100755 --- a/git-legacy-rebase.sh +++ b/git-legacy-rebase.sh @@ -337,6 +337,11 @@ do fix|strip) force_rebase=t ;; + warn|nowarn|error|error-all) + ;; # okay, known whitespace option + *) + die "fatal: Invalid whitespace option: '${1#*=}'" + ;; esac ;; --ignore-whitespace) @@ -352,6 +357,9 @@ do git_am_opt="$git_am_opt $1" force_rebase=t ;; + -C*[!0-9]*) + die "fatal: switch \`C' expects a numerical value" + ;; -C*) git_am_opt="$git_am_opt $1" ;; @@ -710,10 +718,16 @@ if test -n "$diffstat" then if test -n "$verbose" then - echo "$(eval_gettext "Changes from \$mb to \$onto:")" + if test -z "$mb" + then + echo "$(eval_gettext "Changes to \$onto:")" + else + echo "$(eval_gettext "Changes from \$mb to \$onto:")" + fi fi + mb_tree="${mb:-$(git hash-object -t tree /dev/null)}" # We want color (if set), but no pager - GIT_PAGER='' git diff --stat --summary "$mb" "$onto" + GIT_PAGER='' git diff --stat --summary "$mb_tree" "$onto" fi test -n "$interactive_rebase" && run_specific_rebase diff --git a/git-sh-i18n.sh b/git-sh-i18n.sh index 9d065fb4bf..e1d917fd27 100644 --- a/git-sh-i18n.sh +++ b/git-sh-i18n.sh @@ -17,7 +17,7 @@ export TEXTDOMAINDIR # First decide what scheme to use... GIT_INTERNAL_GETTEXT_SH_SCHEME=fallthrough -if test -n "$GIT_GETTEXT_POISON" +if test -n "$GIT_TEST_GETTEXT_POISON" then GIT_INTERNAL_GETTEXT_SH_SCHEME=poison elif test -n "@@USE_GETTEXT_SCHEME@@" @@ -1513,7 +1513,6 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol, } } -#ifndef NO_PTHREADS int grep_use_locks; /* @@ -1539,11 +1538,6 @@ static inline void grep_attr_unlock(void) */ pthread_mutex_t grep_read_mutex; -#else -#define grep_attr_lock() -#define grep_attr_unlock() -#endif - static int match_funcname(struct grep_opt *opt, struct grep_source *gs, char *bol, char *eol) { xdemitconf_t *xecfg = opt->priv; @@ -229,7 +229,6 @@ int grep_source(struct grep_opt *opt, struct grep_source *gs); extern struct grep_opt *grep_opt_dup(const struct grep_opt *opt); extern int grep_threads_ok(const struct grep_opt *opt); -#ifndef NO_PTHREADS /* * Mutex used around access to the attributes machinery if * opt->use_threads. Must be initialized/destroyed by callers! @@ -250,9 +249,4 @@ static inline void grep_read_unlock(void) pthread_mutex_unlock(&grep_read_mutex); } -#else -#define grep_read_lock() -#define grep_read_unlock() -#endif - #endif diff --git a/http-push.c b/http-push.c index d1f52cbdf6..cd48590912 100644 --- a/http-push.c +++ b/http-push.c @@ -365,7 +365,7 @@ static void start_put(struct transfer_request *request) git_zstream stream; unpacked = read_object_file(&request->obj->oid, &type, &len); - hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %lu", type_name(type), len) + 1; + hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %"PRIuMAX , type_name(type), (uintmax_t)len) + 1; /* Set it up */ git_deflate_init(&stream, zlib_compression_level); @@ -834,7 +834,7 @@ static CURL *get_curl_handle(void) #if LIBCURL_VERSION_NUM >= 0x072c00 curl_easy_setopt(result, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NO_REVOKE); #else - warning(_("CURLSSLOPT_NO_REVOKE not suported with cURL < 7.44.0")); + warning(_("CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0")); #endif } diff --git a/log-tree.c b/log-tree.c index 7a83e99250..b243779a0b 100644 --- a/log-tree.c +++ b/log-tree.c @@ -762,7 +762,7 @@ void show_log(struct rev_info *opt) next_commentary_block(opt, NULL); fprintf_ln(opt->diffopt.file, "%s", opt->rdiff_title); show_range_diff(opt->rdiff1, opt->rdiff2, - opt->creation_factor, 1, &opt->diffopt); + opt->creation_factor, 1, NULL); memcpy(&diff_queued_diff, &dq, sizeof(diff_queued_diff)); } @@ -202,7 +202,7 @@ int prepare_midx_pack(struct multi_pack_index *m, uint32_t pack_int_id) struct strbuf pack_name = STRBUF_INIT; if (pack_int_id >= m->num_packs) - die(_("bad pack-int-id: %u (%u total packs"), + die(_("bad pack-int-id: %u (%u total packs)"), pack_int_id, m->num_packs); if (m->packs[pack_int_id]) @@ -721,12 +721,18 @@ static size_t write_midx_object_offsets(struct hashfile *f, int large_offset_nee static size_t write_midx_large_offsets(struct hashfile *f, uint32_t nr_large_offset, struct pack_midx_entry *objects, uint32_t nr_objects) { - struct pack_midx_entry *list = objects; + struct pack_midx_entry *list = objects, *end = objects + nr_objects; size_t written = 0; while (nr_large_offset) { - struct pack_midx_entry *obj = list++; - uint64_t offset = obj->offset; + struct pack_midx_entry *obj; + uint64_t offset; + + if (list >= end) + BUG("too many large-offset objects"); + + obj = list++; + offset = obj->offset; if (!(offset >> 31)) continue; diff --git a/name-hash.c b/name-hash.c index 1fcda73cb3..623ca6923a 100644 --- a/name-hash.c +++ b/name-hash.c @@ -7,6 +7,7 @@ */ #define NO_THE_INDEX_COMPATIBILITY_MACROS #include "cache.h" +#include "thread-utils.h" struct dir_entry { struct hashmap_entry ent; @@ -131,22 +132,6 @@ static int cache_entry_cmp(const void *unused_cmp_data, 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) -{ - 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 @@ -509,6 +494,7 @@ static inline void lazy_update_dir_ref_counts( static void threaded_lazy_init_name_hash( struct index_state *istate) { + int err; int nr_each; int k_start; int t; @@ -516,6 +502,9 @@ static void threaded_lazy_init_name_hash( struct lazy_dir_thread_data *td_dir; struct lazy_name_thread_data *td_name; + if (!HAVE_THREADS) + return; + k_start = 0; nr_each = DIV_ROUND_UP(istate->cache_nr, lazy_nr_dir_threads); @@ -538,8 +527,9 @@ static void threaded_lazy_init_name_hash( 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"); + err = pthread_create(&td_dir_t->pthread, NULL, lazy_dir_thread_proc, td_dir_t); + if (err) + die(_("unable to create lazy_dir thread: %s"), strerror(err)); } for (t = 0; t < lazy_nr_dir_threads; t++) { struct lazy_dir_thread_data *td_dir_t = td_dir + t; @@ -559,13 +549,15 @@ static void threaded_lazy_init_name_hash( */ 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"); + err = pthread_create(&td_name->pthread, NULL, lazy_name_thread_proc, td_name); + if (err) + die(_("unable to create lazy_name thread: %s"), strerror(err)); lazy_update_dir_ref_counts(istate, lazy_entries); - if (pthread_join(td_name->pthread, NULL)) - die("unable to join lazy_name_thread"); + err = pthread_join(td_name->pthread, NULL); + if (err) + die(_("unable to join lazy_name thread: %s"), strerror(err)); cleanup_dir_mutex(); @@ -574,8 +566,6 @@ static void threaded_lazy_init_name_hash( free(lazy_entries); } -#endif - static void lazy_init_name_hash(struct index_state *istate) { @@ -59,7 +59,7 @@ struct object_array { /* * object flag allocation: - * revision.h: 0---------10 2526 + * revision.h: 0---------10 25----28 * fetch-pack.c: 01 * negotiator/default.c: 2--5 * walker.c: 0-2 @@ -78,7 +78,7 @@ struct object_array { * builtin/show-branch.c: 0-------------------------------------------26 * builtin/unpack-objects.c: 2021 */ -#define FLAG_BITS 27 +#define FLAG_BITS 29 /* * The object type is stored in 3 bits. diff --git a/pack-objects.h b/pack-objects.h index 86ee93feb4..dc869f26c2 100644 --- a/pack-objects.h +++ b/pack-objects.h @@ -145,9 +145,7 @@ struct packing_data { struct packed_git **in_pack_by_idx; struct packed_git **in_pack; -#ifndef NO_PTHREADS pthread_mutex_t lock; -#endif /* * This list contains entries for bases which we know the other side @@ -169,15 +167,11 @@ void prepare_packing_data(struct packing_data *pdata); static inline void packing_data_lock(struct packing_data *pdata) { -#ifndef NO_PTHREADS pthread_mutex_lock(&pdata->lock); -#endif } static inline void packing_data_unlock(struct packing_data *pdata) { -#ifndef NO_PTHREADS pthread_mutex_unlock(&pdata->lock); -#endif } struct object_entry *packlist_alloc(struct packing_data *pdata, @@ -418,7 +412,7 @@ static inline void oe_set_tree_depth(struct packing_data *pack, unsigned int tree_depth) { if (!pack->tree_depth) - ALLOC_ARRAY(pack->tree_depth, pack->nr_objects); + CALLOC_ARRAY(pack->tree_depth, pack->nr_alloc); pack->tree_depth[e - pack->objects] = tree_depth; } @@ -435,7 +429,7 @@ static inline void oe_set_layer(struct packing_data *pack, unsigned char layer) { if (!pack->layer) - ALLOC_ARRAY(pack->layer, pack->nr_objects); + CALLOC_ARRAY(pack->layer, pack->nr_alloc); pack->layer[e - pack->objects] = layer; } diff --git a/parse-options-cb.c b/parse-options-cb.c index e8236534ac..8c9edce52f 100644 --- a/parse-options-cb.c +++ b/parse-options-cb.c @@ -28,13 +28,6 @@ int parse_opt_abbrev_cb(const struct option *opt, const char *arg, int unset) return 0; } -int parse_opt_approxidate_cb(const struct option *opt, const char *arg, - int unset) -{ - *(timestamp_t *)(opt->value) = approxidate(arg); - return 0; -} - int parse_opt_expiry_date_cb(const struct option *opt, const char *arg, int unset) { @@ -65,6 +58,8 @@ int parse_opt_verbosity_cb(const struct option *opt, const char *arg, { int *target = opt->value; + BUG_ON_OPT_ARG(arg); + if (unset) /* --no-quiet, --no-verbose */ *target = 0; @@ -87,6 +82,8 @@ int parse_opt_commits(const struct option *opt, const char *arg, int unset) struct object_id oid; struct commit *commit; + BUG_ON_OPT_NEG(unset); + if (!arg) return -1; if (get_oid(arg, &oid)) @@ -117,6 +114,9 @@ int parse_opt_object_name(const struct option *opt, const char *arg, int unset) int parse_opt_tertiary(const struct option *opt, const char *arg, int unset) { int *target = opt->value; + + BUG_ON_OPT_ARG(arg); + *target = unset ? 2 : 1; return 0; } diff --git a/parse-options.h b/parse-options.h index dd14911a29..6c4fe2016d 100644 --- a/parse-options.h +++ b/parse-options.h @@ -150,9 +150,6 @@ struct option { (h), 0, &parse_opt_string_list } #define OPT_UYN(s, l, v, h) { OPTION_CALLBACK, (s), (l), (v), NULL, \ (h), PARSE_OPT_NOARG, &parse_opt_tertiary } -#define OPT_DATE(s, l, v, h) \ - { OPTION_CALLBACK, (s), (l), (v), N_("time"),(h), 0, \ - parse_opt_approxidate_cb } #define OPT_EXPIRY_DATE(s, l, v, h) \ { OPTION_CALLBACK, (s), (l), (v), N_("expiry-date"),(h), 0, \ parse_opt_expiry_date_cb } @@ -194,6 +191,20 @@ extern int opterror(const struct option *opt, const char *reason, int flags); #define opterror(o,r,f) (opterror((o),(r),(f)), const_error()) #endif +/* + * Use these assertions for callbacks that expect to be called with NONEG and + * NOARG respectively, and do not otherwise handle the "unset" and "arg" + * parameters. + */ +#define BUG_ON_OPT_NEG(unset) do { \ + if ((unset)) \ + BUG("option callback does not expect negation"); \ +} while (0) +#define BUG_ON_OPT_ARG(arg) do { \ + if ((arg)) \ + BUG("option callback does not expect an argument"); \ +} while (0) + /*----- incremental advanced APIs -----*/ enum { @@ -232,7 +243,6 @@ extern struct option *parse_options_concat(struct option *a, struct option *b); /*----- some often used options -----*/ extern int parse_opt_abbrev_cb(const struct option *, const char *, int); -extern int parse_opt_approxidate_cb(const struct option *, const char *, int); extern int parse_opt_expiry_date_cb(const struct option *, const char *, int); extern int parse_opt_color_flag_cb(const struct option *, const char *, int); extern int parse_opt_verbosity_cb(const struct option *, const char *, int); @@ -289,16 +289,11 @@ something in the test suite might still depend on the US English version of the strings, e.g. to grep some error message or other output. -To smoke out issues like these Git can be compiled with gettext poison -support, at the top-level: +To smoke out issues like these, Git tested with a translation mode that +emits gibberish on every call to gettext. To use it run the test suite +with it, e.g.: - make GETTEXT_POISON=YesPlease - -That'll give you a git which emits gibberish on every call to -gettext. It's obviously not meant to be installed, but you should run -the test suite with it: - - cd t && prove -j 9 ./t[0-9]*.sh + cd t && GIT_TEST_GETTEXT_POISON=YesPlease prove -j 9 ./t[0-9]*.sh If tests break with it you should inspect them manually and see if what you're translating is sane, i.e. that you're not translating diff --git a/preload-index.c b/preload-index.c index 222792ccbc..c7dc3f2b9f 100644 --- a/preload-index.c +++ b/preload-index.c @@ -7,17 +7,7 @@ #include "fsmonitor.h" #include "config.h" #include "progress.h" - -#ifdef NO_PTHREADS -void preload_index(struct index_state *index, - const struct pathspec *pathspec, - unsigned int refresh_flags) -{ - ; /* nothing */ -} -#else - -#include <pthread.h> +#include "thread-utils.h" /* * Mostly randomly chosen maximum thread counts: we @@ -108,7 +98,7 @@ void preload_index(struct index_state *index, struct thread_data data[MAX_PARALLEL]; struct progress_data pd; - if (!core_preload_index) + if (!HAVE_THREADS || !core_preload_index) return; threads = index->cache_nr / THREAD_COST; @@ -131,6 +121,8 @@ void preload_index(struct index_state *index, for (i = 0; i < threads; i++) { struct thread_data *p = data+i; + int err; + p->index = index; if (pathspec) copy_pathspec(&p->pathspec, pathspec); @@ -139,8 +131,10 @@ void preload_index(struct index_state *index, if (pd.progress) p->progress = &pd; offset += work; - if (pthread_create(&p->pthread, NULL, preload_thread, p)) - die("unable to create threaded lstat"); + err = pthread_create(&p->pthread, NULL, preload_thread, p); + + if (err) + die(_("unable to create threaded lstat: %s"), strerror(err)); } for (i = 0; i < threads; i++) { struct thread_data *p = data+i; @@ -151,7 +145,6 @@ void preload_index(struct index_state *index, trace_performance_leave("preload index"); } -#endif int read_index_preload(struct index_state *index, const struct pathspec *pathspec, diff --git a/prio-queue.c b/prio-queue.c index a078451872..d3f488cb05 100644 --- a/prio-queue.c +++ b/prio-queue.c @@ -85,3 +85,12 @@ void *prio_queue_get(struct prio_queue *queue) } return result; } + +void *prio_queue_peek(struct prio_queue *queue) +{ + if (!queue->nr) + return NULL; + if (!queue->compare) + return queue->array[queue->nr - 1].data; + return queue->array[0].data; +} diff --git a/prio-queue.h b/prio-queue.h index d030ec9dd6..682e51867a 100644 --- a/prio-queue.h +++ b/prio-queue.h @@ -46,6 +46,12 @@ extern void prio_queue_put(struct prio_queue *, void *thing); */ extern void *prio_queue_get(struct prio_queue *); +/* + * Gain access to the "thing" that would be returned by + * prio_queue_get, but do not remove it from the queue. + */ +extern void *prio_queue_peek(struct prio_queue *); + extern void clear_prio_queue(struct prio_queue *); /* Reverse the LIFO elements */ diff --git a/range-diff.c b/range-diff.c index 3958720f00..48b0e1b4ce 100644 --- a/range-diff.c +++ b/range-diff.c @@ -460,8 +460,13 @@ int show_range_diff(const char *range1, const char *range2, struct diff_options opts; struct strbuf indent = STRBUF_INIT; - memcpy(&opts, diffopt, sizeof(opts)); - opts.output_format = DIFF_FORMAT_PATCH; + if (diffopt) + memcpy(&opts, diffopt, sizeof(opts)); + else + diff_setup(&opts); + + if (!opts.output_format) + opts.output_format = DIFF_FORMAT_PATCH; opts.flags.suppress_diff_headers = 1; opts.flags.dual_color_diffed_diffs = dual_color; opts.output_prefix = output_prefix_cb; diff --git a/range-diff.h b/range-diff.h index 190593f0c7..08a50b6e98 100644 --- a/range-diff.h +++ b/range-diff.h @@ -5,6 +5,11 @@ #define RANGE_DIFF_CREATION_FACTOR_DEFAULT 60 +/* + * Compare series of commmits in RANGE1 and RANGE2, and emit to the + * standard output. NULL can be passed to DIFFOPT to use the built-in + * default. + */ int show_range_diff(const char *range1, const char *range2, int creation_factor, int dual_color, struct diff_options *diffopt); diff --git a/read-cache.c b/read-cache.c index 8c924506dd..bd45dc3e24 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1752,7 +1752,7 @@ static struct cache_entry *create_from_disk(struct mem_pool *ce_mem_pool, size_t len; const char *name; unsigned int flags; - size_t copy_len; + size_t copy_len = 0; /* * Adjacent cache entries tend to share the leading paths, so it makes * sense to only store the differences in later entries. In the v4 @@ -1792,8 +1792,6 @@ static struct cache_entry *create_from_disk(struct mem_pool *ce_mem_pool, die(_("malformed name field in the index, near path '%s'"), previous_ce->name); copy_len = previous_len - strip_len; - } else { - copy_len = 0; } name = (const char *)cp; } @@ -1926,19 +1924,15 @@ struct index_entry_offset_table struct index_entry_offset entries[FLEX_ARRAY]; }; -#ifndef NO_PTHREADS static struct index_entry_offset_table *read_ieot_extension(const char *mmap, size_t mmap_size, size_t offset); static void write_ieot_extension(struct strbuf *sb, struct index_entry_offset_table *ieot); -#endif static size_t read_eoie_extension(const char *mmap, size_t mmap_size); static void write_eoie_extension(struct strbuf *sb, git_hash_ctx *eoie_context, size_t offset); struct load_index_extensions { -#ifndef NO_PTHREADS pthread_t pthread; -#endif struct index_state *istate; const char *mmap; size_t mmap_size; @@ -2016,8 +2010,6 @@ static unsigned long load_all_cache_entries(struct index_state *istate, return consumed; } -#ifndef NO_PTHREADS - /* * Mostly randomly chosen maximum thread counts: we * cap the parallelism to online_cpus() threads, and we want @@ -2128,7 +2120,6 @@ static unsigned long load_cache_entries_threaded(struct index_state *istate, con return consumed; } -#endif /* remember to discard_cache() before reading a different cache! */ int do_read_index(struct index_state *istate, const char *path, int must_exist) @@ -2141,10 +2132,8 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist) size_t mmap_size; struct load_index_extensions p; size_t extension_offset = 0; -#ifndef NO_PTHREADS int nr_threads, cpus; struct index_entry_offset_table *ieot = NULL; -#endif if (istate->initialized) return istate->cache_nr; @@ -2187,8 +2176,8 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist) src_offset = sizeof(*hdr); -#ifndef NO_PTHREADS - nr_threads = git_config_get_index_threads(); + if (git_config_get_index_threads(&nr_threads)) + nr_threads = 1; /* TODO: does creating more threads than cores help? */ if (!nr_threads) { @@ -2198,6 +2187,9 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist) nr_threads = cpus; } + if (!HAVE_THREADS) + nr_threads = 1; + if (nr_threads > 1) { extension_offset = read_eoie_extension(mmap, mmap_size); if (extension_offset) { @@ -2225,22 +2217,16 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist) } else { src_offset += load_all_cache_entries(istate, mmap, mmap_size, src_offset); } -#else - src_offset += load_all_cache_entries(istate, mmap, mmap_size, src_offset); -#endif istate->timestamp.sec = st.st_mtime; istate->timestamp.nsec = ST_MTIME_NSEC(st); /* if we created a thread, join it otherwise load the extensions on the primary thread */ -#ifndef NO_PTHREADS if (extension_offset) { int ret = pthread_join(p.pthread, NULL); if (ret) die(_("unable to join load_index_extensions thread: %s"), strerror(ret)); - } -#endif - if (!extension_offset) { + } else { p.src_offset = src_offset; load_index_extensions(&p); } @@ -2704,6 +2690,36 @@ void update_index_if_able(struct index_state *istate, struct lock_file *lockfile rollback_lock_file(lockfile); } +static int record_eoie(void) +{ + int val; + + if (!git_config_get_bool("index.recordendofindexentries", &val)) + return val; + + /* + * As a convenience, the end of index entries extension + * used for threading is written by default if the user + * explicitly requested threaded index reads. + */ + return !git_config_get_index_threads(&val) && val != 1; +} + +static int record_ieot(void) +{ + int val; + + if (!git_config_get_bool("index.recordoffsettable", &val)) + return val; + + /* + * As a convenience, the offset table used for threading is + * written by default if the user explicitly requested + * threaded index reads. + */ + return !git_config_get_index_threads(&val) && val != 1; +} + /* * On success, `tempfile` is closed. If it is the temporary file * of a `struct lock_file`, we will therefore effectively perform @@ -2762,9 +2778,10 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile, if (ce_write(&c, newfd, &hdr, sizeof(hdr)) < 0) return -1; -#ifndef NO_PTHREADS - nr_threads = git_config_get_index_threads(); - if (nr_threads != 1) { + if (!HAVE_THREADS || git_config_get_index_threads(&nr_threads)) + nr_threads = 1; + + if (nr_threads != 1 && record_ieot()) { int ieot_blocks, cpus; /* @@ -2793,7 +2810,6 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile, ieot_entries = DIV_ROUND_UP(entries, ieot_blocks); } } -#endif offset = lseek(newfd, 0, SEEK_CUR); if (offset < 0) { @@ -2877,7 +2893,6 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile, * strip_extensions parameter as we need it when loading the shared * index. */ -#ifndef NO_PTHREADS if (ieot) { struct strbuf sb = STRBUF_INIT; @@ -2889,7 +2904,6 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile, if (err) return -1; } -#endif if (!strip_extensions && istate->split_index) { struct strbuf sb = STRBUF_INIT; @@ -2951,7 +2965,7 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile, * read. Write it out regardless of the strip_extensions parameter as we need it * when loading the shared index. */ - if (offset) { + if (offset && record_eoie()) { struct strbuf sb = STRBUF_INIT; write_eoie_extension(&sb, &eoie_c, offset); @@ -3165,7 +3179,8 @@ int write_locked_index(struct index_state *istate, struct lock_file *lock, struct tempfile *temp; int saved_errno; - temp = mks_tempfile(git_path("sharedindex_XXXXXX")); + /* Same initial permissions as the main .git/index file */ + temp = mks_tempfile_sm(git_path("sharedindex_XXXXXX"), 0, 0666); if (!temp) { oidclr(&si->base_oid); ret = do_write_locked_index(istate, lock, flags); @@ -3475,7 +3490,6 @@ static void write_eoie_extension(struct strbuf *sb, git_hash_ctx *eoie_context, strbuf_add(sb, hash, the_hash_algo->rawsz); } -#ifndef NO_PTHREADS #define IEOT_VERSION (1) static struct index_entry_offset_table *read_ieot_extension(const char *mmap, size_t mmap_size, size_t offset) @@ -3548,4 +3562,3 @@ static void write_ieot_extension(struct strbuf *sb, struct index_entry_offset_ta strbuf_add(sb, &buffer, sizeof(uint32_t)); } } -#endif diff --git a/ref-filter.c b/ref-filter.c index 0c45ed9d94..5de616befe 100644 --- a/ref-filter.c +++ b/ref-filter.c @@ -534,6 +534,10 @@ static int parse_ref_filter_atom(const struct ref_format *format, if (ARRAY_SIZE(valid_atom) <= i) return strbuf_addf_ret(err, -1, _("unknown field name: %.*s"), (int)(ep-atom), atom); + if (valid_atom[i].source != SOURCE_NONE && !have_git_dir()) + return strbuf_addf_ret(err, -1, + _("not a git repository, but the field '%.*s' requires access to object data"), + (int)(ep-atom), atom); /* Add it in, including the deref prefix */ at = used_atom_cnt; @@ -878,7 +882,7 @@ static void grab_common_values(struct atom_value *val, int deref, struct expand_ v->s = xstrdup(type_name(oi->type)); else if (!strcmp(name, "objectsize")) { v->value = oi->size; - v->s = xstrfmt("%lu", oi->size); + v->s = xstrfmt("%"PRIuMAX , (uintmax_t)oi->size); } else if (deref) grab_objectname(name, &oi->oid, v, &used_atom[i]); @@ -2316,6 +2320,8 @@ int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset) struct object_id oid; int no_merged = starts_with(opt->long_name, "no"); + BUG_ON_OPT_NEG(unset); + if (rf->merge) { if (no_merged) { return opterror(opt, "is incompatible with --merged", 0); @@ -217,6 +217,7 @@ char *resolve_refdup(const char *refname, int resolve_flags, /* The argument to filter_refs */ struct ref_filter { const char *pattern; + const char *prefix; each_ref_fn *fn; void *cb_data; }; @@ -296,6 +297,8 @@ static int filter_refs(const char *refname, const struct object_id *oid, if (wildmatch(filter->pattern, refname, 0)) return 0; + if (filter->prefix) + skip_prefix(refname, filter->prefix, &refname); return filter->fn(refname, oid, flags, filter->cb_data); } @@ -458,6 +461,7 @@ int for_each_glob_ref_in(each_ref_fn fn, const char *pattern, } filter.pattern = real_pattern.buf; + filter.prefix = prefix; filter.fn = fn; filter.cb_data = cb_data; ret = for_each_ref(filter_refs, &filter); diff --git a/refs/files-backend.c b/refs/files-backend.c index 9183875dad..dd8abe9185 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -180,7 +180,8 @@ static void files_reflog_path(struct files_ref_store *refs, break; case REF_TYPE_OTHER_PSEUDOREF: case REF_TYPE_MAIN_PSEUDOREF: - return files_reflog_path_other_worktrees(refs, sb, refname); + files_reflog_path_other_worktrees(refs, sb, refname); + break; case REF_TYPE_NORMAL: strbuf_addf(sb, "%s/logs/%s", refs->gitcommondir, refname); break; diff --git a/remote-curl.c b/remote-curl.c index 762a55a75f..1220dffcdc 100644 --- a/remote-curl.c +++ b/remote-curl.c @@ -617,10 +617,11 @@ static int probe_rpc(struct rpc_state *rpc, struct slot_results *results) return err; } -static curl_off_t xcurl_off_t(ssize_t len) { - if (len > maximum_signed_value_of_type(curl_off_t)) +static curl_off_t xcurl_off_t(size_t len) { + uintmax_t size = len; + if (size > maximum_signed_value_of_type(curl_off_t)) die("cannot handle pushes this big"); - return (curl_off_t) len; + return (curl_off_t)size; } static int post_rpc(struct rpc_state *rpc) diff --git a/revision.c b/revision.c index bdd3e7c9f1..13e0519c02 100644 --- a/revision.c +++ b/revision.c @@ -25,6 +25,8 @@ #include "worktree.h" #include "argv-array.h" #include "commit-reach.h" +#include "commit-graph.h" +#include "prio-queue.h" volatile show_early_output_fn_t show_early_output; @@ -767,8 +769,8 @@ static void commit_list_insert_by_date_cached(struct commit *p, struct commit_li *cache = new_entry; } -static int add_parents_to_list(struct rev_info *revs, struct commit *commit, - struct commit_list **list, struct commit_list **cache_ptr) +static int process_parents(struct rev_info *revs, struct commit *commit, + struct commit_list **list, struct commit_list **cache_ptr) { struct commit_list *parent = commit->parents; unsigned left_flag; @@ -807,7 +809,8 @@ static int add_parents_to_list(struct rev_info *revs, struct commit *commit, if (p->object.flags & SEEN) continue; p->object.flags |= SEEN; - commit_list_insert_by_date_cached(p, list, cached_base, cache_ptr); + if (list) + commit_list_insert_by_date_cached(p, list, cached_base, cache_ptr); } return 0; } @@ -846,7 +849,8 @@ static int add_parents_to_list(struct rev_info *revs, struct commit *commit, p->object.flags |= left_flag; if (!(p->object.flags & SEEN)) { p->object.flags |= SEEN; - commit_list_insert_by_date_cached(p, list, cached_base, cache_ptr); + if (list) + commit_list_insert_by_date_cached(p, list, cached_base, cache_ptr); } if (revs->first_parent_only) break; @@ -1090,7 +1094,7 @@ static int limit_list(struct rev_info *revs) if (revs->max_age != -1 && (commit->date < revs->max_age)) obj->flags |= UNINTERESTING; - if (add_parents_to_list(revs, commit, &list, NULL) < 0) + if (process_parents(revs, commit, &list, NULL) < 0) return -1; if (obj->flags & UNINTERESTING) { mark_parents_uninteresting(commit); @@ -2468,7 +2472,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s if (revs->diffopt.objfind) revs->simplify_history = 0; - if (revs->topo_order) + if (revs->topo_order && !generation_numbers_enabled(the_repository)) revs->limited = 1; if (revs->prune_data.nr) { @@ -2907,6 +2911,217 @@ static int mark_uninteresting(const struct object_id *oid, return 0; } +define_commit_slab(indegree_slab, int); +define_commit_slab(author_date_slab, timestamp_t); + +struct topo_walk_info { + uint32_t min_generation; + struct prio_queue explore_queue; + struct prio_queue indegree_queue; + struct prio_queue topo_queue; + struct indegree_slab indegree; + struct author_date_slab author_date; +}; + +static inline void test_flag_and_insert(struct prio_queue *q, struct commit *c, int flag) +{ + if (c->object.flags & flag) + return; + + c->object.flags |= flag; + prio_queue_put(q, c); +} + +static void explore_walk_step(struct rev_info *revs) +{ + struct topo_walk_info *info = revs->topo_walk_info; + struct commit_list *p; + struct commit *c = prio_queue_get(&info->explore_queue); + + if (!c) + return; + + if (parse_commit_gently(c, 1) < 0) + return; + + if (revs->sort_order == REV_SORT_BY_AUTHOR_DATE) + record_author_date(&info->author_date, c); + + if (revs->max_age != -1 && (c->date < revs->max_age)) + c->object.flags |= UNINTERESTING; + + if (process_parents(revs, c, NULL, NULL) < 0) + return; + + if (c->object.flags & UNINTERESTING) + mark_parents_uninteresting(c); + + for (p = c->parents; p; p = p->next) + test_flag_and_insert(&info->explore_queue, p->item, TOPO_WALK_EXPLORED); +} + +static void explore_to_depth(struct rev_info *revs, + uint32_t gen_cutoff) +{ + struct topo_walk_info *info = revs->topo_walk_info; + struct commit *c; + while ((c = prio_queue_peek(&info->explore_queue)) && + c->generation >= gen_cutoff) + explore_walk_step(revs); +} + +static void indegree_walk_step(struct rev_info *revs) +{ + struct commit_list *p; + struct topo_walk_info *info = revs->topo_walk_info; + struct commit *c = prio_queue_get(&info->indegree_queue); + + if (!c) + return; + + if (parse_commit_gently(c, 1) < 0) + return; + + explore_to_depth(revs, c->generation); + + for (p = c->parents; p; p = p->next) { + struct commit *parent = p->item; + int *pi = indegree_slab_at(&info->indegree, parent); + + if (*pi) + (*pi)++; + else + *pi = 2; + + test_flag_and_insert(&info->indegree_queue, parent, TOPO_WALK_INDEGREE); + + if (revs->first_parent_only) + return; + } +} + +static void compute_indegrees_to_depth(struct rev_info *revs, + uint32_t gen_cutoff) +{ + struct topo_walk_info *info = revs->topo_walk_info; + struct commit *c; + while ((c = prio_queue_peek(&info->indegree_queue)) && + c->generation >= gen_cutoff) + indegree_walk_step(revs); +} + +static void init_topo_walk(struct rev_info *revs) +{ + struct topo_walk_info *info; + struct commit_list *list; + revs->topo_walk_info = xmalloc(sizeof(struct topo_walk_info)); + info = revs->topo_walk_info; + memset(info, 0, sizeof(struct topo_walk_info)); + + init_indegree_slab(&info->indegree); + memset(&info->explore_queue, 0, sizeof(info->explore_queue)); + memset(&info->indegree_queue, 0, sizeof(info->indegree_queue)); + memset(&info->topo_queue, 0, sizeof(info->topo_queue)); + + switch (revs->sort_order) { + default: /* REV_SORT_IN_GRAPH_ORDER */ + info->topo_queue.compare = NULL; + break; + case REV_SORT_BY_COMMIT_DATE: + info->topo_queue.compare = compare_commits_by_commit_date; + break; + case REV_SORT_BY_AUTHOR_DATE: + init_author_date_slab(&info->author_date); + info->topo_queue.compare = compare_commits_by_author_date; + info->topo_queue.cb_data = &info->author_date; + break; + } + + info->explore_queue.compare = compare_commits_by_gen_then_commit_date; + info->indegree_queue.compare = compare_commits_by_gen_then_commit_date; + + info->min_generation = GENERATION_NUMBER_INFINITY; + for (list = revs->commits; list; list = list->next) { + struct commit *c = list->item; + + if (parse_commit_gently(c, 1)) + continue; + + test_flag_and_insert(&info->explore_queue, c, TOPO_WALK_EXPLORED); + test_flag_and_insert(&info->indegree_queue, c, TOPO_WALK_INDEGREE); + + if (c->generation < info->min_generation) + info->min_generation = c->generation; + + *(indegree_slab_at(&info->indegree, c)) = 1; + + if (revs->sort_order == REV_SORT_BY_AUTHOR_DATE) + record_author_date(&info->author_date, c); + } + compute_indegrees_to_depth(revs, info->min_generation); + + for (list = revs->commits; list; list = list->next) { + struct commit *c = list->item; + + if (*(indegree_slab_at(&info->indegree, c)) == 1) + prio_queue_put(&info->topo_queue, c); + } + + /* + * This is unfortunate; the initial tips need to be shown + * in the order given from the revision traversal machinery. + */ + if (revs->sort_order == REV_SORT_IN_GRAPH_ORDER) + prio_queue_reverse(&info->topo_queue); +} + +static struct commit *next_topo_commit(struct rev_info *revs) +{ + struct commit *c; + struct topo_walk_info *info = revs->topo_walk_info; + + /* pop next off of topo_queue */ + c = prio_queue_get(&info->topo_queue); + + if (c) + *(indegree_slab_at(&info->indegree, c)) = 0; + + return c; +} + +static void expand_topo_walk(struct rev_info *revs, struct commit *commit) +{ + struct commit_list *p; + struct topo_walk_info *info = revs->topo_walk_info; + if (process_parents(revs, commit, NULL, NULL) < 0) { + if (!revs->ignore_missing_links) + die("Failed to traverse parents of commit %s", + oid_to_hex(&commit->object.oid)); + } + + for (p = commit->parents; p; p = p->next) { + struct commit *parent = p->item; + int *pi; + + if (parse_commit_gently(parent, 1) < 0) + continue; + + if (parent->generation < info->min_generation) { + info->min_generation = parent->generation; + compute_indegrees_to_depth(revs, info->min_generation); + } + + pi = indegree_slab_at(&info->indegree, parent); + + (*pi)--; + if (*pi == 1) + prio_queue_put(&info->topo_queue, parent); + + if (revs->first_parent_only) + return; + } +} + int prepare_revision_walk(struct rev_info *revs) { int i; @@ -2943,11 +3158,13 @@ int prepare_revision_walk(struct rev_info *revs) commit_list_sort_by_date(&revs->commits); if (revs->no_walk) return 0; - if (revs->limited) + if (revs->limited) { if (limit_list(revs) < 0) return -1; - if (revs->topo_order) - sort_in_topological_order(&revs->commits, revs->sort_order); + if (revs->topo_order) + sort_in_topological_order(&revs->commits, revs->sort_order); + } else if (revs->topo_order) + init_topo_walk(revs); if (revs->line_level_traverse) line_log_filter(revs); if (revs->simplify_merges) @@ -2964,7 +3181,7 @@ static enum rewrite_result rewrite_one(struct rev_info *revs, struct commit **pp for (;;) { struct commit *p = *pp; if (!revs->limited) - if (add_parents_to_list(revs, p, &revs->commits, &cache) < 0) + if (process_parents(revs, p, &revs->commits, &cache) < 0) return rewrite_one_error; if (p->object.flags & UNINTERESTING) return rewrite_one_ok; @@ -3272,6 +3489,8 @@ static struct commit *get_revision_1(struct rev_info *revs) if (revs->reflog_info) commit = next_reflog_entry(revs->reflog_info); + else if (revs->topo_walk_info) + commit = next_topo_commit(revs); else commit = pop_commit(&revs->commits); @@ -3293,7 +3512,9 @@ static struct commit *get_revision_1(struct rev_info *revs) if (revs->reflog_info) try_to_simplify_commit(revs, commit); - else if (add_parents_to_list(revs, commit, &revs->commits, NULL) < 0) { + else if (revs->topo_walk_info) + expand_topo_walk(revs, commit); + else if (process_parents(revs, commit, &revs->commits, NULL) < 0) { if (!revs->ignore_missing_links) die("Failed to traverse parents of commit %s", oid_to_hex(&commit->object.oid)); diff --git a/revision.h b/revision.h index 0d2abc2d36..7987bfcd2e 100644 --- a/revision.h +++ b/revision.h @@ -32,6 +32,9 @@ #define TRACK_LINEAR (1u<<26) #define ALL_REV_FLAGS (((1u<<11)-1) | NOT_USER_GIVEN | TRACK_LINEAR) +#define TOPO_WALK_EXPLORED (1u<<27) +#define TOPO_WALK_INDEGREE (1u<<28) + #define DECORATE_SHORT_REFS 1 #define DECORATE_FULL_REFS 2 @@ -64,6 +67,8 @@ struct rev_cmdline_info { #define REVISION_WALK_NO_WALK_SORTED 1 #define REVISION_WALK_NO_WALK_UNSORTED 2 +struct topo_walk_info; + struct rev_info { /* Starting list */ struct commit_list *commits; @@ -270,6 +275,8 @@ struct rev_info { const char *break_bar; struct revision_sources *sources; + + struct topo_walk_info *topo_walk_info; }; int ref_excluded(struct string_list *, const char *path); diff --git a/run-command.c b/run-command.c index d679cc267c..c11ff80674 100644 --- a/run-command.c +++ b/run-command.c @@ -1226,7 +1226,7 @@ int start_async(struct async *async) { int err = pthread_create(&async->tid, NULL, run_thread, async); if (err) { - error_errno("cannot create thread"); + error(_("cannot create async thread: %s"), strerror(err)); goto error; } } @@ -1259,6 +1259,15 @@ int finish_async(struct async *async) #endif } +int async_with_fork(void) +{ +#ifdef NO_PTHREADS + return 1; +#else + return 0; +#endif +} + const char *find_hook(const char *name) { static struct strbuf path = STRBUF_INIT; diff --git a/run-command.h b/run-command.h index 3932420ec8..68f5369fc2 100644 --- a/run-command.h +++ b/run-command.h @@ -1,9 +1,7 @@ #ifndef RUN_COMMAND_H #define RUN_COMMAND_H -#ifndef NO_PTHREADS -#include <pthread.h> -#endif +#include "thread-utils.h" #include "argv-array.h" @@ -143,6 +141,7 @@ struct async { int start_async(struct async *async); int finish_async(struct async *async); int in_async(void); +int async_with_fork(void); void check_pipe(int err); /** diff --git a/send-pack.c b/send-pack.c index e920ca57df..f692686770 100644 --- a/send-pack.c +++ b/send-pack.c @@ -203,9 +203,8 @@ static int receive_status(int in, struct ref *refs) static int sideband_demux(int in, int out, void *data) { int *fd = data, ret; -#ifdef NO_PTHREADS - close(fd[1]); -#endif + if (async_with_fork()) + close(fd[1]); ret = recv_sideband("send-pack", fd[0], out); close(out); return ret; diff --git a/sequencer.c b/sequencer.c index 0d87b0739b..e1a4dd15f1 100644 --- a/sequencer.c +++ b/sequencer.c @@ -3244,10 +3244,6 @@ static int do_merge(struct commit *commit, const char *arg, int arg_len, } merge_commit = to_merge->item; - write_message(oid_to_hex(&merge_commit->object.oid), GIT_SHA1_HEXSZ, - git_path_merge_head(the_repository), 0); - write_message("no-ff", 5, git_path_merge_mode(the_repository), 0); - bases = get_merge_bases(head_commit, merge_commit); if (bases && oideq(&merge_commit->object.oid, &bases->item->object.oid)) { @@ -3256,6 +3252,10 @@ static int do_merge(struct commit *commit, const char *arg, int arg_len, goto leave_merge; } + write_message(oid_to_hex(&merge_commit->object.oid), GIT_SHA1_HEXSZ, + git_path_merge_head(the_repository), 0); + write_message("no-ff", 5, git_path_merge_mode(the_repository), 0); + for (j = bases; j; j = j->next) commit_list_insert(j->item, &reversed); free_commit_list(bases); @@ -3512,6 +3512,7 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts) unlink(rebase_path_author_script()); unlink(rebase_path_stopped_sha()); unlink(rebase_path_amend()); + unlink(git_path_merge_head(the_repository)); delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF); if (item->command == TODO_BREAK) @@ -3882,6 +3883,7 @@ static int commit_staged_changes(struct replay_opts *opts, opts, flags)) return error(_("could not commit staged changes.")); unlink(rebase_path_amend()); + unlink(git_path_merge_head(the_repository)); if (final_fixup) { unlink(rebase_path_fixup_msg()); unlink(rebase_path_squash_msg()); diff --git a/sha1-file.c b/sha1-file.c index 2daf7d9935..5bd11c85bc 100644 --- a/sha1-file.c +++ b/sha1-file.c @@ -833,7 +833,7 @@ int check_object_signature(const struct object_id *oid, void *map, return -1; /* Generate the header */ - hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %lu", type_name(obj_type), size) + 1; + hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %"PRIuMAX , type_name(obj_type), (uintmax_t)size) + 1; /* Sha1.. */ the_hash_algo->init_fn(&c); @@ -1492,7 +1492,7 @@ static void write_object_file_prepare(const void *buf, unsigned long len, git_hash_ctx c; /* Generate the header */ - *hdrlen = xsnprintf(hdr, *hdrlen, "%s %lu", type, len)+1; + *hdrlen = xsnprintf(hdr, *hdrlen, "%s %"PRIuMAX , type, (uintmax_t)len)+1; /* Sha1.. */ the_hash_algo->init_fn(&c); @@ -1758,7 +1758,7 @@ int force_object_loose(const struct object_id *oid, time_t mtime) buf = read_object(oid->hash, &type, &len); if (!buf) return error(_("cannot read sha1_file for %s"), oid_to_hex(oid)); - hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %lu", type_name(type), len) + 1; + hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %"PRIuMAX , type_name(type), (uintmax_t)len) + 1; ret = write_loose_object(oid, hdr, hdrlen, buf, len, mtime); free(buf); @@ -302,6 +302,12 @@ that cannot be easily covered by a few specific test cases. These could be enabled by running the test suite with correct GIT_TEST_ environment set. +GIT_TEST_GETTEXT_POISON=<non-empty?> turns all strings marked for +translation into gibberish if non-empty (think "test -n"). Used for +spotting those tests that need to be marked with a C_LOCALE_OUTPUT +prerequisite when adding more strings for translation. See "Testing +marked strings" in po/README for details. + GIT_TEST_SPLIT_INDEX=<boolean> forces split-index mode on the whole test suite. Accept any boolean values that are accepted by git-config. @@ -339,6 +345,10 @@ for the index version specified. Can be set to any valid version GIT_TEST_PRELOAD_INDEX=<boolean> exercises the preload-index code path by overriding the minimum number of cache entries required per thread. +GIT_TEST_REBASE_USE_BUILTIN=<boolean>, when false, disables the +builtin version of git-rebase. See 'rebase.useBuiltin' in +git-config(1). + GIT_TEST_INDEX_THREADS=<n> enables exercising the multi-threaded loading of the index for the whole test suite by bypassing the default number of cache entries and thread minimums. Setting this to 1 will make the diff --git a/t/helper/test-parse-options.c b/t/helper/test-parse-options.c index 9cb8a0ea0f..47fee660b8 100644 --- a/t/helper/test-parse-options.c +++ b/t/helper/test-parse-options.c @@ -36,6 +36,7 @@ static int length_callback(const struct option *opt, const char *arg, int unset) static int number_callback(const struct option *opt, const char *arg, int unset) { + BUG_ON_OPT_NEG(unset); *(int *)opt->value = strtol(arg, NULL, 10); return 0; } @@ -119,7 +120,6 @@ int cmd__parse_options(int argc, const char **argv) OPT_INTEGER('j', NULL, &integer, "get a integer, too"), OPT_MAGNITUDE('m', "magnitude", &magnitude, "get a magnitude"), OPT_SET_INT(0, "set23", &integer, "set integer to 23", 23), - OPT_DATE('t', NULL, ×tamp, "get timestamp of <time>"), OPT_CALLBACK('L', "length", &integer, "str", "get length of <str>", length_callback), OPT_FILENAME('F', "file", &file, "set file to <file>"), diff --git a/t/helper/test-prio-queue.c b/t/helper/test-prio-queue.c index 9807b649b1..5bc9c46ea5 100644 --- a/t/helper/test-prio-queue.c +++ b/t/helper/test-prio-queue.c @@ -22,14 +22,24 @@ int cmd__prio_queue(int argc, const char **argv) struct prio_queue pq = { intcmp }; while (*++argv) { - if (!strcmp(*argv, "get")) - show(prio_queue_get(&pq)); - else if (!strcmp(*argv, "dump")) { - int *v; - while ((v = prio_queue_get(&pq))) - show(v); - } - else { + if (!strcmp(*argv, "get")) { + void *peek = prio_queue_peek(&pq); + void *get = prio_queue_get(&pq); + if (peek != get) + BUG("peek and get results do not match"); + show(get); + } else if (!strcmp(*argv, "dump")) { + void *peek; + void *get; + while ((peek = prio_queue_peek(&pq))) { + get = prio_queue_get(&pq); + if (peek != get) + BUG("peek and get results do not match"); + show(get); + } + } else if (!strcmp(*argv, "stack")) { + pq.compare = NULL; + } else { int *v = malloc(sizeof(*v)); *v = atoi(*argv); prio_queue_put(&pq, v); diff --git a/t/lib-gettext.sh b/t/lib-gettext.sh index eec757f104..2139b427ca 100644 --- a/t/lib-gettext.sh +++ b/t/lib-gettext.sh @@ -10,9 +10,14 @@ GIT_TEXTDOMAINDIR="$GIT_BUILD_DIR/po/build/locale" GIT_PO_PATH="$GIT_BUILD_DIR/po" export GIT_TEXTDOMAINDIR GIT_PO_PATH -. "$GIT_BUILD_DIR"/git-sh-i18n +if test -n "$GIT_TEST_INSTALLED" +then + . "$(git --exec-path)"/git-sh-i18n +else + . "$GIT_BUILD_DIR"/git-sh-i18n +fi -if test_have_prereq GETTEXT && ! test_have_prereq GETTEXT_POISON +if test_have_prereq GETTEXT && test_have_prereq C_LOCALE_OUTPUT then # is_IS.UTF-8 on Solaris and FreeBSD, is_IS.utf8 on Debian is_IS_locale=$(locale -a 2>/dev/null | diff --git a/t/lib-git-daemon.sh b/t/lib-git-daemon.sh index edbea2d986..f98de95c15 100644 --- a/t/lib-git-daemon.sh +++ b/t/lib-git-daemon.sh @@ -92,7 +92,7 @@ stop_git_daemon() { kill "$GIT_DAEMON_PID" wait "$GIT_DAEMON_PID" >&3 2>&4 ret=$? - if test_match_signal 15 $? + if ! test_match_signal 15 $ret then error "git daemon exited with status: $ret" fi diff --git a/t/lib-gpg/keyring.gpg b/t/lib-gpg/keyring.gpg index d4754a1f19..918dfce332 100644 --- a/t/lib-gpg/keyring.gpg +++ b/t/lib-gpg/keyring.gpg @@ -30,7 +30,6 @@ Cezx4Q2khACcCs+/LtE8Lb9hC+2cvr3uH5p82AI= =aEiU -----END PGP PRIVATE KEY BLOCK----- -----BEGIN PGP PRIVATE KEY BLOCK----- -Version: GnuPG v1 lQOYBFFMlkcBCADJi/xnAF8yI34PHilSCbM7VtOFO17oFMkpu4cgN2QpPuM5MVjy cvrzKSguZFvPCDLzeAFJW1uPxL4SHaHSkisCrFhijH7OJWcOPNPSFCwu+inAoAsv @@ -83,11 +82,43 @@ fn1sY/IG5atoKK+ypmV/TlBlMZqFQzuPIJQT8VLbmxtLlDhJG04LbI6c8axIZxOO ZKLy5nTTSy16ztqEeS7eifHLPZg1UFFyEEIQ1XW0CNDAeuWKh90ERjyl4Cg7PnWS Z9Ei+zj6JD5Pcdi3BJhQo9WOLOVEJ0NHmewTYqk9QVXH/0v1Hdl4LMJtgcbdbDWk 4UTkXbg9pn3umCgkNJ3Vs8fWnIWO9Izdr2/wrFY2JvUT7Yvl+wsNIWatvOEzGy7n -BOW78WUxzhu0YJTLKy+iKCjg5HS5dx6OC+e4aEEgfhNPCMkbvDsJjtQ= -=hieJ +BOW78WUxzhu0YJTLKy+iKCjg5HS5dx6OC+e4aEEgfhNPCMkbvDsJjtSdA5gEW967 +3AEIAKjseT0sTQjyN39fOn0fzxWp89REMUUKgLigb01MKuuNI3cedBZsz3hpFOKV +cii5rldw8uf3yS3Okht2DfHPSD4NrGzLGEzSTpQ10S8N2q0DUYwyLU6C0U8HnMZm +/n+lCGBbUoxvnruohAvKAjpHO3rmJ8D4De9hlWg/fwdAxQQ0Sve0kN8Vwk2p1GuO +OWQKV1SU9c+kBiou7dewQmbilPRanKmP5ZSU4emhpTOMlJFXF+kmYSODQk1cMvWW +Ob3ttll2llX0Gul7Sjf+haq/FcRyRk7Tw5MHwZjr5aWiCny0/0+byvfF6SBIfzyE +qlyWURQ2gHZUqSiG3QPMZiYr04cAEQEAAQAH/Am4rv/oQF6wodgz5y4zc6JJiTDA +4+nKdIuR7OKqUxk1oo7eZjJML/xvMumygNyUvJ9nodl1SlMKilOhdAswfkKj9gJY +BdDJLm1OufhW3pJwy6ahbjeqEgwJFVENtSPF0zkuyED9kElrpbD2ZTGfzwdM0e9D +10ZDFWtODCw8rzOFcijujgI8oilLtxSNrkkTKW+25WJFRNPSHgIkMIm8UlPAG+rj +3Yj9UqodeXTSvXwG2zceOxjFJadV77sOFJDgwWslN6J8El4+GcgwFVepJxoZEj7e +cKkmVr0Dc9/Q04D5dWATc1FYcIhZbTu3oImCAh45ep4u9WYLUV5PGyeMviEEAMwo +mJbYBxWuPjpNa722HQcbvMUiZWWDwHfLCib/SaP0AgfDahid8/PcZwxOPHPByBrm +GDi0z7ibn/pgJr07kpp1Cic9ntfc2FvkI0QMzG0EuiekzQyPEnzjoDHF+V4nJIj2 +GWVjLYYqlZWEmhsfKt1CnlPXBunKoDJ30ABPcHJ/BADT0WxAIVKF4lO2HlrDVP44 +bufBEG9Ct7dl/G08Qve4Ag3VEZpT82vEFp0LzX0mTCDIUKJUYAYLxAIPhP7IvIfc +EZXrwyDUxU7YSgKTHMKo9nFC6fIc1GeGPRalIF1gmTY32qlYJC6y5BTDhZNV5ydG +u8QL2P/orP7XuRrJyeyK+QP/XTekr/DS6Jkct826MPA52ciIkWVgYLatH5fO4HCq +ssDU8vz7FbbvGs0G1Xn7GA4m9dNYVOZtKwX++3nf2IEOpgPiZVTn/nP2u3HutpJb +/HMLlcfZGiGdxS6n/vdz6wsEobJoi6STkHkA+VFNOSZmdsw6eKl3X911tpCTYfOG +2U47/IkCbAQYAQgAIBYhBNS+IjEa0xMeXtoppGEJLoW3InGJBQJb3rvcAhsCAUAJ +EGEJLoW3InGJwHQgBBkBCAAdFiEE+DZKWeB//p9NYwBaZaDuoC4wytcFAlveu9wA +CgkQZaDuoC4wytcD9gf/WigtHl7lFyl8RaE/uqROFEelZyM00v1h55fd/IGRG88E +tN0Lr4FaqBqPkMZjU/LN9UMBaTd+748vHlHaweZqljXJu99CO9Id7Y4w7WzF3C3Y +yQsGZ92EGxthsPK0+rhHV0MbaINupI1oO9gATFglSxq17o83FJatGRjaXCZau8jr +57/By1MGtjk+Iq1NkzGkrX778LdRQGLKDw2Qa7lsdHY8d3lUPAH8mbb97ELmIc9t +PG2aM7ATJL7nBmFuTHo6hmEcIw32Ei9KK1zxM0ZylEYkjBjHAlklWmKb9MiayMC5 +uHW7Iyhjl+NbgbIEr2JTamW/9tL6UrIIxiDEdqaHNfCaB/9D+V31Upcohc9azwB4 +AF8diQwt5nfiVpnVeF/W8+eS1By2W6QrwLNthNRabYFnuSf9USHAY6atDWe+egId +MLIv4ce0i3ykoczSu0oMoUCMxdl9kQrsNHZCqWX/OiDDLSb05u/P/3he900y6tSB +15MbIPA6i5Bw/693nHguqxS1ASbBB/LiIu3vCXdFEs9RMvIJ+qkP3xQA96oImQiK +R3U6OGv593eONKijUINNqHRq6+UxIyJ+OCAi+L2QTidAhJLRCp6EZD96u02cthYq +8KA8j1+rx9BcbeacVVHepeG1JsgxsXX8BTJ7ZuS5VVndZOjag8URW/9nJMf01w/h +el64 +=Iv7W -----END PGP PRIVATE KEY BLOCK----- -----BEGIN PGP PUBLIC KEY BLOCK----- -Version: GnuPG v1 mQGiBEZnyykRBACzCPjIpTYNL7Y2tQqlEGTTDlvZcWNLjF5f7ZzuyOqNOidLUgFD 36qch1LZLSZkShdR3Gae+bsolyjxrlFuFP0eXRPMtqK20aLw7WZvPFpEV1ThMne+ @@ -137,6 +168,25 @@ bGPyBuWraCivsqZlf05QZTGahUM7jyCUE/FS25sbS5Q4SRtOC2yOnPGsSGcTjmSi 8uZ000stes7ahHku3onxyz2YNVBRchBCENV1tAjQwHrliofdBEY8peAoOz51kmfR Ivs4+iQ+T3HYtwSYUKPVjizlRCdDR5nsE2KpPUFVx/9L9R3ZeCzCbYHG3Ww1pOFE 5F24PaZ97pgoJDSd1bPH1pyFjvSM3a9v8KxWNib1E+2L5fsLDSFmrbzhMxsu5wTl -u/FlMc4btGCUyysvoigo4OR0uXcejgvnuGhBIH4TTwjJG7w7CY7U -=iYv/ +u/FlMc4btGCUyysvoigo4OR0uXcejgvnuGhBIH4TTwjJG7w7CY7UuQENBFveu9wB +CACo7Hk9LE0I8jd/Xzp9H88VqfPURDFFCoC4oG9NTCrrjSN3HnQWbM94aRTilXIo +ua5XcPLn98ktzpIbdg3xz0g+DaxsyxhM0k6UNdEvDdqtA1GMMi1OgtFPB5zGZv5/ +pQhgW1KMb567qIQLygI6Rzt65ifA+A3vYZVoP38HQMUENEr3tJDfFcJNqdRrjjlk +CldUlPXPpAYqLu3XsEJm4pT0Wpypj+WUlOHpoaUzjJSRVxfpJmEjg0JNXDL1ljm9 +7bZZdpZV9Brpe0o3/oWqvxXEckZO08OTB8GY6+Wlogp8tP9Pm8r3xekgSH88hKpc +llEUNoB2VKkoht0DzGYmK9OHABEBAAGJAmwEGAEIACAWIQTUviIxGtMTHl7aKaRh +CS6FtyJxiQUCW9673AIbAgFACRBhCS6FtyJxicB0IAQZAQgAHRYhBPg2Slngf/6f +TWMAWmWg7qAuMMrXBQJb3rvcAAoJEGWg7qAuMMrXA/YH/1ooLR5e5RcpfEWhP7qk +ThRHpWcjNNL9YeeX3fyBkRvPBLTdC6+BWqgaj5DGY1PyzfVDAWk3fu+PLx5R2sHm +apY1ybvfQjvSHe2OMO1sxdwt2MkLBmfdhBsbYbDytPq4R1dDG2iDbqSNaDvYAExY +JUsate6PNxSWrRkY2lwmWrvI6+e/wctTBrY5PiKtTZMxpK1++/C3UUBiyg8NkGu5 +bHR2PHd5VDwB/Jm2/exC5iHPbTxtmjOwEyS+5wZhbkx6OoZhHCMN9hIvSitc8TNG +cpRGJIwYxwJZJVpim/TImsjAubh1uyMoY5fjW4GyBK9iU2plv/bS+lKyCMYgxHam +hzXwmgf/Q/ld9VKXKIXPWs8AeABfHYkMLeZ34laZ1Xhf1vPnktQctlukK8CzbYTU +Wm2BZ7kn/VEhwGOmrQ1nvnoCHTCyL+HHtIt8pKHM0rtKDKFAjMXZfZEK7DR2Qqll +/zogwy0m9Obvz/94XvdNMurUgdeTGyDwOouQcP+vd5x4LqsUtQEmwQfy4iLt7wl3 +RRLPUTLyCfqpD98UAPeqCJkIikd1Ojhr+fd3jjSoo1CDTah0auvlMSMifjggIvi9 +kE4nQISS0QqehGQ/ertNnLYWKvCgPI9fq8fQXG3mnFVR3qXhtSbIMbF1/AUye2bk +uVVZ3WTo2oPFEVv/ZyTH9NcP4XpeuA== +=KRyT -----END PGP PUBLIC KEY BLOCK----- diff --git a/t/perf/p3400-rebase.sh b/t/perf/p3400-rebase.sh index ce271ca4c1..d202aaed06 100755 --- a/t/perf/p3400-rebase.sh +++ b/t/perf/p3400-rebase.sh @@ -6,9 +6,9 @@ test_description='Tests rebase performance' test_perf_default_repo test_expect_success 'setup rebasing on top of a lot of changes' ' - git checkout -f -b base && - git checkout -b to-rebase && - git checkout -b upstream && + git checkout -f -B base && + git checkout -B to-rebase && + git checkout -B upstream && for i in $(seq 100) do # simulate huge diffs @@ -35,8 +35,8 @@ test_perf 'rebase on top of a lot of unrelated changes' ' test_expect_success 'setup rebasing many changes without split-index' ' git config core.splitIndex false && - git checkout -b upstream2 to-rebase && - git checkout -b to-rebase2 upstream + git checkout -B upstream2 to-rebase && + git checkout -B to-rebase2 upstream ' test_perf 'rebase a lot of unrelated changes without split-index' ' diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh index 4d23373526..b6566003dd 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -274,7 +274,7 @@ test_expect_success 'pretend we have a mix of all possible results' " EOF " -test_expect_success 'test --verbose' ' +test_expect_success C_LOCALE_OUTPUT 'test --verbose' ' test_must_fail run_sub_test_lib_test \ test-verbose "test verbose" --verbose <<-\EOF && test_expect_success "passing test" true diff --git a/t/t0009-prio-queue.sh b/t/t0009-prio-queue.sh index e56dfce668..3941ad2528 100755 --- a/t/t0009-prio-queue.sh +++ b/t/t0009-prio-queue.sh @@ -47,4 +47,18 @@ test_expect_success 'notice empty queue' ' test_cmp expect actual ' +cat >expect <<'EOF' +3 +2 +6 +4 +5 +1 +8 +EOF +test_expect_success 'stack order' ' + test-tool prio-queue stack 8 1 5 4 6 2 3 dump >actual && + test_cmp expect actual +' + test_done diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh index 17d0c18feb..f5b10861c4 100755 --- a/t/t0040-parse-options.sh +++ b/t/t0040-parse-options.sh @@ -23,7 +23,6 @@ usage: test-tool parse-options <options> -j <n> get a integer, too -m, --magnitude <n> get a magnitude --set23 set integer to 23 - -t <time> get timestamp of <time> -L, --length <str> get length of <str> -F, --file <file> set file to <file> @@ -246,27 +245,6 @@ test_expect_success 'keep some options as arguments' ' ' cat >expect <<\EOF -boolean: 0 -integer: 0 -magnitude: 0 -timestamp: 1 -string: (not set) -abbrev: 7 -verbose: -1 -quiet: 1 -dry run: no -file: (not set) -arg 00: foo -EOF - -test_expect_success 'OPT_DATE() works' ' - test-tool parse-options -t "1970-01-01 00:00:01 +0000" \ - foo -q >output 2>output.err && - test_must_be_empty output.err && - test_cmp expect output -' - -cat >expect <<\EOF Callback: "four", 0 boolean: 5 integer: 4 diff --git a/t/t0205-gettext-poison.sh b/t/t0205-gettext-poison.sh index 438e778d6a..a06269f38a 100755 --- a/t/t0205-gettext-poison.sh +++ b/t/t0205-gettext-poison.sh @@ -5,13 +5,15 @@ test_description='Gettext Shell poison' +GIT_TEST_GETTEXT_POISON=YesPlease +export GIT_TEST_GETTEXT_POISON . ./lib-gettext.sh -test_expect_success GETTEXT_POISON 'sanity: $GIT_INTERNAL_GETTEXT_SH_SCHEME" is poison' ' +test_expect_success 'sanity: $GIT_INTERNAL_GETTEXT_SH_SCHEME" is poison' ' test "$GIT_INTERNAL_GETTEXT_SH_SCHEME" = "poison" ' -test_expect_success GETTEXT_POISON 'gettext: our gettext() fallback has poison semantics' ' +test_expect_success 'gettext: our gettext() fallback has poison semantics' ' printf "# GETTEXT POISON #" >expect && gettext "test" >actual && test_cmp expect actual && @@ -20,7 +22,7 @@ test_expect_success GETTEXT_POISON 'gettext: our gettext() fallback has poison s test_cmp expect actual ' -test_expect_success GETTEXT_POISON 'eval_gettext: our eval_gettext() fallback has poison semantics' ' +test_expect_success 'eval_gettext: our eval_gettext() fallback has poison semantics' ' printf "# GETTEXT POISON #" >expect && eval_gettext "test" >actual && test_cmp expect actual && diff --git a/t/t1700-split-index.sh b/t/t1700-split-index.sh index 2ac47aa0e4..4667e1a190 100755 --- a/t/t1700-split-index.sh +++ b/t/t1700-split-index.sh @@ -25,14 +25,17 @@ test_expect_success 'enable split index' ' git update-index --split-index && test-tool dump-split-index .git/index >actual && indexversion=$(test-tool index-version <.git/index) && + + # NEEDSWORK: Stop hard-coding checksums. if test "$indexversion" = "4" then - own=3527df833c6c100d3d1d921a9a782d62a8be4b58 - base=746f7ab2ed44fb839efdfbffcf399d0b113fb4cb + own=432ef4b63f32193984f339431fd50ca796493569 + base=508851a7f0dfa8691e9f69c7f055865389012491 else - own=5e9b60117ece18da410ddecc8b8d43766a0e4204 - base=4370042739b31cd17a5c5cd6043a77c9a00df113 + own=8299b0bcd1ac364e5f1d7768efb62fa2da79a339 + base=39d890139ee5356c7ef572216cebcd27aa41f9df fi && + cat >expect <<-EOF && own $own base $base @@ -381,6 +384,26 @@ test_expect_success 'check splitIndex.sharedIndexExpire set to "never" and "now" test $(ls .git/sharedindex.* | wc -l) -le 2 ' +test_expect_success POSIXPERM 'same mode for index & split index' ' + git init same-mode && + ( + cd same-mode && + test_commit A && + test_modebits .git/index >index_mode && + test_must_fail git config core.sharedRepository && + git -c core.splitIndex=true status && + shared=$(ls .git/sharedindex.*) && + case "$shared" in + *" "*) + # we have more than one??? + false ;; + *) + test_modebits "$shared" >split_index_mode && + test_cmp index_mode split_index_mode ;; + esac + ) +' + while read -r mode modebits do test_expect_success POSIXPERM "split index respects core.sharedrepository $mode" ' diff --git a/t/t3206-range-diff.sh b/t/t3206-range-diff.sh index 6aae364171..e497c1358f 100755 --- a/t/t3206-range-diff.sh +++ b/t/t3206-range-diff.sh @@ -122,6 +122,36 @@ test_expect_success 'changed commit' ' test_cmp expected actual ' +test_expect_success 'changed commit with --no-patch diff option' ' + git range-diff --no-color --no-patch topic...changed >actual && + cat >expected <<-EOF && + 1: 4de457d = 1: a4b3333 s/5/A/ + 2: fccce22 = 2: f51d370 s/4/A/ + 3: 147e64e ! 3: 0559556 s/11/B/ + 4: a63e992 ! 4: d966c5c s/12/B/ + EOF + test_cmp expected actual +' + +test_expect_success 'changed commit with --stat diff option' ' + git range-diff --no-color --stat topic...changed >actual && + cat >expected <<-EOF && + 1: 4de457d = 1: a4b3333 s/5/A/ + a => b | 0 + 1 file changed, 0 insertions(+), 0 deletions(-) + 2: fccce22 = 2: f51d370 s/4/A/ + a => b | 0 + 1 file changed, 0 insertions(+), 0 deletions(-) + 3: 147e64e ! 3: 0559556 s/11/B/ + a => b | 0 + 1 file changed, 0 insertions(+), 0 deletions(-) + 4: a63e992 ! 4: d966c5c s/12/B/ + a => b | 0 + 1 file changed, 0 insertions(+), 0 deletions(-) + EOF + test_cmp expected actual +' + test_expect_success 'changed commit with sm config' ' git range-diff --no-color --submodule=log topic...changed >actual && cat >expected <<-EOF && diff --git a/t/t3406-rebase-message.sh b/t/t3406-rebase-message.sh index 0392e36d23..f64b130cb8 100755 --- a/t/t3406-rebase-message.sh +++ b/t/t3406-rebase-message.sh @@ -77,11 +77,54 @@ test_expect_success 'rebase -n overrides config rebase.stat config' ' # "Does not point to a valid commit: invalid-ref" # # NEEDSWORK: This "grep" is fine in real non-C locales, but -# GETTEXT_POISON poisons the refname along with the enclosing +# GIT_TEST_GETTEXT_POISON poisons the refname along with the enclosing # error message. test_expect_success 'rebase --onto outputs the invalid ref' ' test_must_fail git rebase --onto invalid-ref HEAD HEAD 2>err && test_i18ngrep "invalid-ref" err ' +test_expect_success 'error out early upon -C<n> or --whitespace=<bad>' ' + test_must_fail git rebase -Cnot-a-number HEAD 2>err && + test_i18ngrep "numerical value" err && + test_must_fail git rebase --whitespace=bad HEAD 2>err && + test_i18ngrep "Invalid whitespace option" err +' + +test_expect_success 'GIT_REFLOG_ACTION' ' + git checkout start && + test_commit reflog-onto && + git checkout -b reflog-topic start && + test_commit reflog-to-rebase && + + git rebase reflog-onto && + git log -g --format=%gs -3 >actual && + cat >expect <<-\EOF && + rebase finished: returning to refs/heads/reflog-topic + rebase: reflog-to-rebase + rebase: checkout reflog-onto + EOF + test_cmp expect actual && + + git checkout -b reflog-prefix reflog-to-rebase && + GIT_REFLOG_ACTION=change-the-reflog git rebase reflog-onto && + git log -g --format=%gs -3 >actual && + cat >expect <<-\EOF && + rebase finished: returning to refs/heads/reflog-prefix + change-the-reflog: reflog-to-rebase + change-the-reflog: checkout reflog-onto + EOF + test_cmp expect actual +' + +test_expect_success 'rebase -i onto unrelated history' ' + git init unrelated && + test_commit -C unrelated 1 && + git -C unrelated remote add -f origin "$PWD" && + git -C unrelated branch --set-upstream-to=origin/master && + git -C unrelated -c core.editor=true rebase -i -v --stat >actual && + test_i18ngrep "Changes to " actual && + test_i18ngrep "5 files changed" actual +' + test_done diff --git a/t/t3420-rebase-autostash.sh b/t/t3420-rebase-autostash.sh index f355c6825a..4c7494cc8f 100755 --- a/t/t3420-rebase-autostash.sh +++ b/t/t3420-rebase-autostash.sh @@ -361,4 +361,12 @@ test_expect_success 'autostash with dirty submodules' ' git rebase -i --autostash HEAD ' +test_expect_success 'branch is left alone when possible' ' + git checkout -b unchanged-branch && + echo changed >file0 && + git rebase --autostash unchanged-branch && + test changed = "$(cat file0)" && + test unchanged-branch = "$(git rev-parse --abbrev-ref HEAD)" +' + test_done diff --git a/t/t3430-rebase-merges.sh b/t/t3430-rebase-merges.sh index aa7bfc88ec..cc5646836f 100755 --- a/t/t3430-rebase-merges.sh +++ b/t/t3430-rebase-merges.sh @@ -396,4 +396,20 @@ test_expect_success 'with --autosquash and --exec' ' grep "G: +G" actual ' +test_expect_success '--continue after resolving conflicts after a merge' ' + git checkout -b already-has-g E && + git cherry-pick E..G && + test_commit H2 && + + git checkout -b conflicts-in-merge H && + test_commit H2 H2.t conflicts H2-conflict && + test_must_fail git rebase -r already-has-g && + grep conflicts H2.t && + echo resolved >H2.t && + git add -u && + git rebase --continue && + test_must_fail git rev-parse --verify HEAD^2 && + test_path_is_missing .git/MERGE_HEAD +' + test_done diff --git a/t/t4052-stat-output.sh b/t/t4052-stat-output.sh index 6e2cf933f7..28c053849a 100755 --- a/t/t4052-stat-output.sh +++ b/t/t4052-stat-output.sh @@ -44,42 +44,50 @@ show --stat log -1 --stat EOF -while read cmd args +cat >expect.60 <<-'EOF' + ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 + +EOF +cat >expect.6030 <<-'EOF' + ...aaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 + +EOF +cat >expect2.60 <<-'EOF' + ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 + + ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 + +EOF +cat >expect2.6030 <<-'EOF' + ...aaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 + + ...aaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 + +EOF +while read expect cmd args do - cat >expect <<-'EOF' - ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 + - EOF test_expect_success "$cmd --stat=width: a long name is given more room when the bar is short" ' git $cmd $args --stat=40 >output && grep " | " output >actual && - test_cmp expect actual + test_cmp $expect.60 actual ' test_expect_success "$cmd --stat-width=width with long name" ' git $cmd $args --stat-width=40 >output && grep " | " output >actual && - test_cmp expect actual + test_cmp $expect.60 actual ' - cat >expect <<-'EOF' - ...aaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 + - EOF test_expect_success "$cmd --stat=...,name-width with long name" ' git $cmd $args --stat=60,30 >output && grep " | " output >actual && - test_cmp expect actual + test_cmp $expect.6030 actual ' test_expect_success "$cmd --stat-name-width with long name" ' git $cmd $args --stat-name-width=30 >output && grep " | " output >actual && - test_cmp expect actual + test_cmp $expect.6030 actual ' done <<\EOF -format-patch -1 --stdout -diff HEAD^ HEAD --stat -show --stat -log -1 --stat +expect2 format-patch --cover-letter -1 --stdout +expect diff HEAD^ HEAD --stat +expect show --stat +expect log -1 --stat EOF @@ -97,6 +105,16 @@ test_expect_success 'preparation for big change tests' ' cat >expect72 <<'EOF' abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +EOF +test_expect_success "format-patch --cover-letter ignores COLUMNS (big change)" ' + COLUMNS=200 git format-patch -1 --stdout --cover-letter >output && + grep " | " output >actual && + test_cmp expect72 actual +' + +cat >expect72 <<'EOF' + abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ EOF cat >expect72-graph <<'EOF' | abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/t/t4136-apply-check.sh b/t/t4136-apply-check.sh index 6d92872318..4c3f264a63 100755 --- a/t/t4136-apply-check.sh +++ b/t/t4136-apply-check.sh @@ -29,6 +29,18 @@ test_expect_success 'apply exits non-zero with no-op patch' ' test_must_fail git apply --check input ' +test_expect_success '`apply --recount` allows no-op patch' ' + echo 1 >1 && + git apply --recount --check <<-\EOF + diff --get a/1 b/1 + index 6696ea4..606eddd 100644 + --- a/1 + +++ b/1 + @@ -1,1 +1,1 @@ + 1 + EOF +' + test_expect_success 'invalid combination: create and copy' ' test_must_fail git apply --check - <<-\EOF diff --git a/1 b/2 diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh index 91ee6841c1..32e722db2e 100755 --- a/t/t5512-ls-remote.sh +++ b/t/t5512-ls-remote.sh @@ -302,6 +302,12 @@ test_expect_success 'ls-remote works outside repository' ' nongit git ls-remote dst.git ' +test_expect_success 'ls-remote --sort fails gracefully outside repository' ' + # Use a sort key that requires access to the referenced objects. + nongit test_must_fail git ls-remote --sort=authordate "$TRASH_DIRECTORY" 2>err && + test_i18ngrep "^fatal: not a git repository, but the field '\''authordate'\'' requires access to object data" err +' + test_expect_success 'ls-remote patterns work with all protocol versions' ' git for-each-ref --format="%(objectname) %(refname)" \ refs/heads/master refs/remotes/origin/master >expect && diff --git a/t/t5562-http-backend-content-length.sh b/t/t5562-http-backend-content-length.sh index b24d8b05a4..90d890d02f 100755 --- a/t/t5562-http-backend-content-length.sh +++ b/t/t5562-http-backend-content-length.sh @@ -31,6 +31,7 @@ test_http_env() { PATH_TRANSLATED="$PWD/.git/git-$handler_type-pack" \ GIT_HTTP_EXPORT_ALL=TRUE \ REQUEST_METHOD=POST \ + "$PERL_PATH" \ "$TEST_DIRECTORY"/t5562/invoke-with-content-length.pl \ "$request_body" git http-backend >act.out 2>act.err } diff --git a/t/t5562/invoke-with-content-length.pl b/t/t5562/invoke-with-content-length.pl index 6c2aae7692..0943474af2 100755..100644 --- a/t/t5562/invoke-with-content-length.pl +++ b/t/t5562/invoke-with-content-length.pl @@ -1,4 +1,3 @@ -#!/usr/bin/perl use 5.008; use strict; use warnings; diff --git a/t/t5573-pull-verify-signatures.sh b/t/t5573-pull-verify-signatures.sh index 747775c147..3e9876e197 100755 --- a/t/t5573-pull-verify-signatures.sh +++ b/t/t5573-pull-verify-signatures.sh @@ -78,4 +78,11 @@ test_expect_success GPG 'pull commit with bad signature with --no-verify-signatu git pull --ff-only --no-verify-signatures bad 2>pullerror ' +test_expect_success GPG 'pull unsigned commit into unborn branch' ' + git init empty-repo && + test_must_fail \ + git -C empty-repo pull --verify-signatures .. 2>pullerror && + test_i18ngrep "does not have a GPG signature" pullerror +' + test_done diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh index f1a49e94f5..8bbc7068ac 100755 --- a/t/t5601-clone.sh +++ b/t/t5601-clone.sh @@ -628,7 +628,7 @@ test_expect_success 'clone on case-insensitive fs' ' ) ' -test_expect_success !MINGW,!CYGWIN,CASE_INSENSITIVE_FS 'colliding file detection' ' +test_expect_success CASE_INSENSITIVE_FS 'colliding file detection' ' grep X icasefs/warning && grep x icasefs/warning && test_i18ngrep "the following paths have collided" icasefs/warning diff --git a/t/t5607-clone-bundle.sh b/t/t5607-clone-bundle.sh index 348d9b3bc7..cf39e9e243 100755 --- a/t/t5607-clone-bundle.sh +++ b/t/t5607-clone-bundle.sh @@ -71,4 +71,10 @@ test_expect_success 'prerequisites with an empty commit message' ' git bundle verify bundle ' +test_expect_success 'failed bundle creation does not leave cruft' ' + # This fails because the bundle would be empty. + test_must_fail git bundle create fail.bundle master..master && + test_path_is_missing fail.bundle.lock +' + test_done diff --git a/t/t6012-rev-list-simplify.sh b/t/t6012-rev-list-simplify.sh index b5a1190ffe..a10f0df02b 100755 --- a/t/t6012-rev-list-simplify.sh +++ b/t/t6012-rev-list-simplify.sh @@ -12,6 +12,22 @@ unnote () { git name-rev --tags --stdin | sed -e "s|$OID_REGEX (tags/\([^)]*\)) |\1 |g" } +# +# Create a test repo with interesting commit graph: +# +# A--B----------G--H--I--K--L +# \ \ / / +# \ \ / / +# C------E---F J +# \_/ +# +# The commits are laid out from left-to-right starting with +# the root commit A and terminating at the tip commit L. +# +# There are a few places where we adjust the commit date or +# author date to make the --topo-order, --date-order, and +# --author-date-order flags produce different output. + test_expect_success setup ' echo "Hi there" >file && echo "initial" >lost && @@ -21,10 +37,18 @@ test_expect_success setup ' git branch other-branch && + git symbolic-ref HEAD refs/heads/unrelated && + git rm -f "*" && + echo "Unrelated branch" >side && + git add side && + test_tick && git commit -m "Side root" && + note J && + git checkout master && + echo "Hello" >file && echo "second" >lost && git add file lost && - test_tick && git commit -m "Modified file and lost" && + test_tick && GIT_AUTHOR_DATE=$(($test_tick + 120)) git commit -m "Modified file and lost" && note B && git checkout other-branch && @@ -63,13 +87,6 @@ test_expect_success setup ' test_tick && git commit -a -m "Final change" && note I && - git symbolic-ref HEAD refs/heads/unrelated && - git rm -f "*" && - echo "Unrelated branch" >side && - git add side && - test_tick && git commit -m "Side root" && - note J && - git checkout master && test_tick && git merge --allow-unrelated-histories -m "Coolest" unrelated && note K && @@ -103,14 +120,24 @@ check_result () { check_outcome success "$@" } -check_result 'L K J I H G F E D C B A' --full-history +check_result 'L K J I H F E D C G B A' --full-history --topo-order +check_result 'L K I H G F E D C B J A' --full-history +check_result 'L K I H G F E D C B J A' --full-history --date-order +check_result 'L K I H G F E D B C J A' --full-history --author-date-order check_result 'K I H E C B A' --full-history -- file check_result 'K I H E C B A' --full-history --topo-order -- file check_result 'K I H E C B A' --full-history --date-order -- file +check_result 'K I H E B C A' --full-history --author-date-order -- file check_result 'I E C B A' --simplify-merges -- file +check_result 'I E C B A' --simplify-merges --topo-order -- file +check_result 'I E C B A' --simplify-merges --date-order -- file +check_result 'I E B C A' --simplify-merges --author-date-order -- file check_result 'I B A' -- file check_result 'I B A' --topo-order -- file +check_result 'I B A' --date-order -- file +check_result 'I B A' --author-date-order -- file check_result 'H' --first-parent -- another-file +check_result 'H' --first-parent --topo-order -- another-file check_result 'E C B A' --full-history E -- lost test_expect_success 'full history simplification without parent' ' diff --git a/t/t6018-rev-list-glob.sh b/t/t6018-rev-list-glob.sh index 270e579c2d..bb5aeac07f 100755 --- a/t/t6018-rev-list-glob.sh +++ b/t/t6018-rev-list-glob.sh @@ -36,7 +36,13 @@ test_expect_success 'setup' ' git tag foo/bar master && commit master3 && git update-ref refs/remotes/foo/baz master && - commit master4 + commit master4 && + git update-ref refs/remotes/upstream/one subspace/one && + git update-ref refs/remotes/upstream/two subspace/two && + git update-ref refs/remotes/upstream/x subspace-x && + git tag qux/one subspace/one && + git tag qux/two subspace/two && + git tag qux/x subspace-x ' test_expect_success 'rev-parse --glob=refs/heads/subspace/*' ' @@ -153,6 +159,54 @@ test_expect_success 'rev-parse --all clears --exclude' ' compare rev-parse "--exclude=* --all --all" "--all" ' +test_expect_success 'rev-parse --exclude=glob with --branches=glob' ' + compare rev-parse "--exclude=subspace-* --branches=sub*" "subspace/one subspace/two" +' + +test_expect_success 'rev-parse --exclude=glob with --tags=glob' ' + compare rev-parse "--exclude=qux/? --tags=qux/*" "qux/one qux/two" +' + +test_expect_success 'rev-parse --exclude=glob with --remotes=glob' ' + compare rev-parse "--exclude=upstream/? --remotes=upstream/*" "upstream/one upstream/two" +' + +test_expect_success 'rev-parse --exclude=ref with --branches=glob' ' + compare rev-parse "--exclude=subspace-x --branches=sub*" "subspace/one subspace/two" +' + +test_expect_success 'rev-parse --exclude=ref with --tags=glob' ' + compare rev-parse "--exclude=qux/x --tags=qux/*" "qux/one qux/two" +' + +test_expect_success 'rev-parse --exclude=ref with --remotes=glob' ' + compare rev-parse "--exclude=upstream/x --remotes=upstream/*" "upstream/one upstream/two" +' + +test_expect_success 'rev-list --exclude=glob with --branches=glob' ' + compare rev-list "--exclude=subspace-* --branches=sub*" "subspace/one subspace/two" +' + +test_expect_success 'rev-list --exclude=glob with --tags=glob' ' + compare rev-list "--exclude=qux/? --tags=qux/*" "qux/one qux/two" +' + +test_expect_success 'rev-list --exclude=glob with --remotes=glob' ' + compare rev-list "--exclude=upstream/? --remotes=upstream/*" "upstream/one upstream/two" +' + +test_expect_success 'rev-list --exclude=ref with --branches=glob' ' + compare rev-list "--exclude=subspace-x --branches=sub*" "subspace/one subspace/two" +' + +test_expect_success 'rev-list --exclude=ref with --tags=glob' ' + compare rev-list "--exclude=qux/x --tags=qux/*" "qux/one qux/two" +' + +test_expect_success 'rev-list --exclude=ref with --remotes=glob' ' + compare rev-list "--exclude=upstream/x --remotes=upstream/*" "upstream/one upstream/two" +' + test_expect_success 'rev-list --glob=refs/heads/subspace/*' ' compare rev-list "subspace/one subspace/two" "--glob=refs/heads/subspace/*" @@ -245,7 +299,7 @@ test_expect_success 'rev-list --tags=foo' ' test_expect_success 'rev-list --tags' ' - compare rev-list "foo/bar" "--tags" + compare rev-list "foo/bar qux/x qux/two qux/one" "--tags" ' @@ -304,7 +358,7 @@ test_expect_success 'shortlog accepts --glob/--tags/--remotes' ' "master other/three someref subspace-x subspace/one subspace/two" \ "--glob=heads/*" && compare shortlog foo/bar --tags=foo && - compare shortlog foo/bar --tags && + compare shortlog "foo/bar qux/one qux/two qux/x" --tags && compare shortlog foo/baz --remotes=foo ' diff --git a/t/t6050-replace.sh b/t/t6050-replace.sh index 86374a9c52..5d6d3184ac 100755 --- a/t/t6050-replace.sh +++ b/t/t6050-replace.sh @@ -461,7 +461,10 @@ test_expect_success '--convert-graft-file' ' printf "%s\n%s %s\n\n# comment\n%s\n" \ $(git rev-parse HEAD^^ HEAD^ HEAD^^ HEAD^2) \ >.git/info/grafts && - git replace --convert-graft-file && + git status 2>stderr && + test_i18ngrep "hint:.*grafts is deprecated" stderr && + git replace --convert-graft-file 2>stderr && + test_i18ngrep ! "hint:.*grafts is deprecated" stderr && test_path_is_missing .git/info/grafts && : verify that the history is now "grafted" && diff --git a/t/t6600-test-reach.sh b/t/t6600-test-reach.sh index a0c64e617a..b24d850036 100755 --- a/t/t6600-test-reach.sh +++ b/t/t6600-test-reach.sh @@ -56,18 +56,22 @@ test_expect_success 'setup' ' git config core.commitGraph true ' -test_three_modes () { +run_three_modes () { test_when_finished rm -rf .git/objects/info/commit-graph && - test-tool reach $1 <input >actual && + "$@" <input >actual && test_cmp expect actual && cp commit-graph-full .git/objects/info/commit-graph && - test-tool reach $1 <input >actual && + "$@" <input >actual && test_cmp expect actual && cp commit-graph-half .git/objects/info/commit-graph && - test-tool reach $1 <input >actual && + "$@" <input >actual && test_cmp expect actual } +test_three_modes () { + run_three_modes test-tool reach "$@" +} + test_expect_success 'ref_newer:miss' ' cat >input <<-\EOF && A:commit-5-7 @@ -265,6 +269,90 @@ test_expect_success 'commit_contains:miss' ' test_three_modes commit_contains --tag ' +test_expect_success 'rev-list: basic topo-order' ' + git rev-parse \ + commit-6-6 commit-5-6 commit-4-6 commit-3-6 commit-2-6 commit-1-6 \ + commit-6-5 commit-5-5 commit-4-5 commit-3-5 commit-2-5 commit-1-5 \ + commit-6-4 commit-5-4 commit-4-4 commit-3-4 commit-2-4 commit-1-4 \ + commit-6-3 commit-5-3 commit-4-3 commit-3-3 commit-2-3 commit-1-3 \ + commit-6-2 commit-5-2 commit-4-2 commit-3-2 commit-2-2 commit-1-2 \ + commit-6-1 commit-5-1 commit-4-1 commit-3-1 commit-2-1 commit-1-1 \ + >expect && + run_three_modes git rev-list --topo-order commit-6-6 +' + +test_expect_success 'rev-list: first-parent topo-order' ' + git rev-parse \ + commit-6-6 \ + commit-6-5 \ + commit-6-4 \ + commit-6-3 \ + commit-6-2 \ + commit-6-1 commit-5-1 commit-4-1 commit-3-1 commit-2-1 commit-1-1 \ + >expect && + run_three_modes git rev-list --first-parent --topo-order commit-6-6 +' + +test_expect_success 'rev-list: range topo-order' ' + git rev-parse \ + commit-6-6 commit-5-6 commit-4-6 commit-3-6 commit-2-6 commit-1-6 \ + commit-6-5 commit-5-5 commit-4-5 commit-3-5 commit-2-5 commit-1-5 \ + commit-6-4 commit-5-4 commit-4-4 commit-3-4 commit-2-4 commit-1-4 \ + commit-6-3 commit-5-3 commit-4-3 \ + commit-6-2 commit-5-2 commit-4-2 \ + commit-6-1 commit-5-1 commit-4-1 \ + >expect && + run_three_modes git rev-list --topo-order commit-3-3..commit-6-6 +' + +test_expect_success 'rev-list: range topo-order' ' + git rev-parse \ + commit-6-6 commit-5-6 commit-4-6 \ + commit-6-5 commit-5-5 commit-4-5 \ + commit-6-4 commit-5-4 commit-4-4 \ + commit-6-3 commit-5-3 commit-4-3 \ + commit-6-2 commit-5-2 commit-4-2 \ + commit-6-1 commit-5-1 commit-4-1 \ + >expect && + run_three_modes git rev-list --topo-order commit-3-8..commit-6-6 +' + +test_expect_success 'rev-list: first-parent range topo-order' ' + git rev-parse \ + commit-6-6 \ + commit-6-5 \ + commit-6-4 \ + commit-6-3 \ + commit-6-2 \ + commit-6-1 commit-5-1 commit-4-1 \ + >expect && + run_three_modes git rev-list --first-parent --topo-order commit-3-8..commit-6-6 +' + +test_expect_success 'rev-list: ancestry-path topo-order' ' + git rev-parse \ + commit-6-6 commit-5-6 commit-4-6 commit-3-6 \ + commit-6-5 commit-5-5 commit-4-5 commit-3-5 \ + commit-6-4 commit-5-4 commit-4-4 commit-3-4 \ + commit-6-3 commit-5-3 commit-4-3 \ + >expect && + run_three_modes git rev-list --topo-order --ancestry-path commit-3-3..commit-6-6 +' + +test_expect_success 'rev-list: symmetric difference topo-order' ' + git rev-parse \ + commit-6-6 commit-5-6 commit-4-6 \ + commit-6-5 commit-5-5 commit-4-5 \ + commit-6-4 commit-5-4 commit-4-4 \ + commit-6-3 commit-5-3 commit-4-3 \ + commit-6-2 commit-5-2 commit-4-2 \ + commit-6-1 commit-5-1 commit-4-1 \ + commit-3-8 commit-2-8 commit-1-8 \ + commit-3-7 commit-2-7 commit-1-7 \ + >expect && + run_three_modes git rev-list --topo-order commit-3-8...commit-6-6 +' + test_expect_success 'get_reachable_subset:all' ' cat >input <<-\EOF && X:commit-9-1 diff --git a/t/t7201-co.sh b/t/t7201-co.sh index 826987ca80..72b9b375ba 100755 --- a/t/t7201-co.sh +++ b/t/t7201-co.sh @@ -254,9 +254,9 @@ test_expect_success 'checkout to detach HEAD (with advice declined)' ' test_expect_success 'checkout to detach HEAD' ' git config advice.detachedHead true && git checkout -f renamer && git clean -f && - git checkout renamer^ 2>messages && - test_i18ngrep "HEAD is now at 7329388" messages && - (test_line_count -gt 1 messages || test -n "$GETTEXT_POISON") && + GIT_TEST_GETTEXT_POISON= git checkout renamer^ 2>messages && + grep "HEAD is now at 7329388" messages && + test_line_count -gt 1 messages && H=$(git rev-parse --verify HEAD) && M=$(git show-ref -s --verify refs/heads/master) && test "z$H" = "z$M" && diff --git a/t/t7510-signed-commit.sh b/t/t7510-signed-commit.sh index 19ccae2869..86d3f93fa2 100755 --- a/t/t7510-signed-commit.sh +++ b/t/t7510-signed-commit.sh @@ -176,8 +176,9 @@ test_expect_success GPG 'show good signature with custom format' ' 13B6F51ECDDE430D C O Mitter <committer@example.com> 73D758744BE721698EC54E8713B6F51ECDDE430D + 73D758744BE721698EC54E8713B6F51ECDDE430D EOF - git log -1 --format="%G?%n%GK%n%GS%n%GF" sixth-signed >actual && + git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" sixth-signed >actual && test_cmp expect actual ' @@ -187,30 +188,33 @@ test_expect_success GPG 'show bad signature with custom format' ' 13B6F51ECDDE430D C O Mitter <committer@example.com> + EOF - git log -1 --format="%G?%n%GK%n%GS%n%GF" $(cat forged1.commit) >actual && + git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" $(cat forged1.commit) >actual && test_cmp expect actual ' test_expect_success GPG 'show untrusted signature with custom format' ' cat >expect <<-\EOF && U - 61092E85B7227189 + 65A0EEA02E30CAD7 Eris Discordia <discord@example.net> + F8364A59E07FFE9F4D63005A65A0EEA02E30CAD7 D4BE22311AD3131E5EDA29A461092E85B7227189 EOF - git log -1 --format="%G?%n%GK%n%GS%n%GF" eighth-signed-alt >actual && + git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" eighth-signed-alt >actual && test_cmp expect actual ' test_expect_success GPG 'show unknown signature with custom format' ' cat >expect <<-\EOF && E - 61092E85B7227189 + 65A0EEA02E30CAD7 + EOF - GNUPGHOME="$GNUPGHOME_NOT_USED" git log -1 --format="%G?%n%GK%n%GS%n%GF" eighth-signed-alt >actual && + GNUPGHOME="$GNUPGHOME_NOT_USED" git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" eighth-signed-alt >actual && test_cmp expect actual ' @@ -220,8 +224,9 @@ test_expect_success GPG 'show lack of signature with custom format' ' + EOF - git log -1 --format="%G?%n%GK%n%GS%n%GF" seventh-unsigned >actual && + git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" seventh-unsigned >actual && test_cmp expect actual ' @@ -261,8 +266,9 @@ test_expect_success GPG 'show double signature with custom format' ' + EOF - git log -1 --format="%G?%n%GK%n%GS%n%GF" $(cat double-commit.commit) >actual && + git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" $(cat double-commit.commit) >actual && test_cmp expect actual ' diff --git a/t/t7612-merge-verify-signatures.sh b/t/t7612-merge-verify-signatures.sh index e2b1df817a..d99218a725 100755 --- a/t/t7612-merge-verify-signatures.sh +++ b/t/t7612-merge-verify-signatures.sh @@ -103,4 +103,11 @@ test_expect_success GPG 'merge commit with bad signature with merge.verifySignat git merge --no-verify-signatures $(cat forged.commit) ' +test_expect_success GPG 'merge unsigned commit into unborn branch' ' + test_when_finished "git checkout initial" && + git checkout --orphan unborn && + test_must_fail git merge --verify-signatures side-unsigned 2>mergeerror && + test_i18ngrep "does not have a GPG signature" mergeerror +' + test_done diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index 175f83d704..3c6b185b60 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -1697,7 +1697,8 @@ test_expect_success 'sourcing the completion script clears cached commands' ' verbose test -z "$__git_all_commands" ' -test_expect_success !GETTEXT_POISON 'sourcing the completion script clears cached merge strategies' ' +test_expect_success 'sourcing the completion script clears cached merge strategies' ' + GIT_TEST_GETTEXT_POISON= && __git_compute_merge_strategies && verbose test -n "$__git_merge_strategies" && . "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" && diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh index d158c8d0bf..b4e391526a 100644 --- a/t/test-lib-functions.sh +++ b/t/test-lib-functions.sh @@ -778,16 +778,16 @@ test_cmp_bin() { # Use this instead of test_cmp to compare files that contain expected and # actual output from git commands that can be translated. When running -# under GETTEXT_POISON this pretends that the command produced expected +# under GIT_TEST_GETTEXT_POISON this pretends that the command produced expected # results. test_i18ncmp () { - test -n "$GETTEXT_POISON" || test_cmp "$@" + ! test_have_prereq C_LOCALE_OUTPUT || test_cmp "$@" } # Use this instead of "grep expected-string actual" to see if the # output from a git command that can be translated either contains an # expected string, or does not contain an unwanted one. When running -# under GETTEXT_POISON this pretends that the command produced expected +# under GIT_TEST_GETTEXT_POISON this pretends that the command produced expected # results. test_i18ngrep () { eval "last_arg=\${$#}" @@ -802,7 +802,7 @@ test_i18ngrep () { error "bug in the test script: too few parameters to test_i18ngrep" fi - if test -n "$GETTEXT_POISON" + if test_have_prereq !C_LOCALE_OUTPUT then # pretend success return 0 @@ -923,7 +923,8 @@ test_create_repo () { mkdir -p "$repo" ( cd "$repo" || error "Cannot setup test environment" - "$GIT_EXEC_PATH/git-init" "--template=$GIT_BUILD_DIR/templates/blt/" >&3 2>&4 || + "${GIT_TEST_INSTALLED:-$GIT_EXEC_PATH}/git$X" init \ + "--template=$GIT_BUILD_DIR/templates/blt/" >&3 2>&4 || error "cannot run git init -- have you built things yet?" mv .git/hooks .git/hooks-disabled ) || exit diff --git a/t/test-lib.sh b/t/test-lib.sh index aba66cafa2..6c6c0af7a1 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -49,18 +49,28 @@ export ASAN_OPTIONS : ${LSAN_OPTIONS=abort_on_error=1} export LSAN_OPTIONS +if test ! -f "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS +then + echo >&2 'error: GIT-BUILD-OPTIONS missing (has Git been built?).' + exit 1 +fi +. "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS +export PERL_PATH SHELL_PATH + ################################################################ # It appears that people try to run tests without building... -"$GIT_BUILD_DIR/git" >/dev/null +"${GIT_TEST_INSTALLED:-$GIT_BUILD_DIR}/git$X" >/dev/null if test $? != 1 then - echo >&2 'error: you do not seem to have built git yet.' + if test -n "$GIT_TEST_INSTALLED" + then + echo >&2 "error: there is no working Git at '$GIT_TEST_INSTALLED'" + else + echo >&2 'error: you do not seem to have built git yet.' + fi exit 1 fi -. "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS -export PERL_PATH SHELL_PATH - # if --tee was passed, write the output not only to the terminal, but # additionally to the file test-results/$BASENAME.out, too. case "$GIT_TEST_TEE_STARTED, $* " in @@ -95,6 +105,16 @@ PAGER=cat TZ=UTC export LANG LC_ALL PAGER TZ EDITOR=: + +# GIT_TEST_GETTEXT_POISON should not influence git commands executed +# during initialization of test-lib and the test repo. Back it up, +# unset and then restore after initialization is finished. +if test -n "$GIT_TEST_GETTEXT_POISON" +then + GIT_TEST_GETTEXT_POISON_ORIG=$GIT_TEST_GETTEXT_POISON + unset GIT_TEST_GETTEXT_POISON +fi + # A call to "unset" with no arguments causes at least Solaris 10 # /usr/xpg4/bin/sh and /bin/ksh to bail out. So keep the unsets # deriving from the command substitution clustered with the other @@ -957,7 +977,7 @@ elif test -n "$GIT_TEST_INSTALLED" then GIT_EXEC_PATH=$($GIT_TEST_INSTALLED/git --exec-path) || error "Cannot run git from $GIT_TEST_INSTALLED." - PATH=$GIT_TEST_INSTALLED:$GIT_BUILD_DIR:$PATH + PATH=$GIT_TEST_INSTALLED:$GIT_BUILD_DIR/t/helper:$PATH GIT_EXEC_PATH=${GIT_TEST_EXEC_PATH:-$GIT_EXEC_PATH} else # normal case, use ../bin-wrappers only unless $with_dashes: git_bin_dir="$GIT_BUILD_DIR/bin-wrappers" @@ -1104,13 +1124,15 @@ test -n "$USE_LIBPCRE1" && test_set_prereq LIBPCRE1 test -n "$USE_LIBPCRE2" && test_set_prereq LIBPCRE2 test -z "$NO_GETTEXT" && test_set_prereq GETTEXT +if test -n "$GIT_TEST_GETTEXT_POISON_ORIG" +then + GIT_TEST_GETTEXT_POISON=$GIT_TEST_GETTEXT_POISON_ORIG + unset GIT_TEST_GETTEXT_POISON_ORIG +fi + # Can we rely on git's output in the C locale? -if test -n "$GETTEXT_POISON" +if test -z "$GIT_TEST_GETTEXT_POISON" then - GIT_GETTEXT_POISON=YesPlease - export GIT_GETTEXT_POISON - test_set_prereq GETTEXT_POISON -else test_set_prereq C_LOCALE_OUTPUT fi diff --git a/thread-utils.c b/thread-utils.c index a2135e0743..5329845691 100644 --- a/thread-utils.c +++ b/thread-utils.c @@ -20,6 +20,9 @@ int online_cpus(void) { +#ifdef NO_PTHREADS + return 1; +#else #ifdef _SC_NPROCESSORS_ONLN long ncpus; #endif @@ -59,10 +62,12 @@ int online_cpus(void) #endif return 1; +#endif } int init_recursive_mutex(pthread_mutex_t *m) { +#ifndef NO_PTHREADS pthread_mutexattr_t a; int ret; @@ -74,4 +79,47 @@ int init_recursive_mutex(pthread_mutex_t *m) pthread_mutexattr_destroy(&a); } return ret; +#else + return 0; +#endif +} + +#ifdef NO_PTHREADS +int dummy_pthread_create(pthread_t *pthread, const void *attr, + void *(*fn)(void *), void *data) +{ + /* + * Do nothing. + * + * The main purpose of this function is to break compiler's + * flow analysis and avoid -Wunused-variable false warnings. + */ + return ENOSYS; +} + +int dummy_pthread_init(void *data) +{ + /* + * Do nothing. + * + * The main purpose of this function is to break compiler's + * flow analysis or it may realize that functions like + * pthread_mutex_init() is no-op, which means the (static) + * variable is not used/initialized at all and trigger + * -Wunused-variable + */ + return ENOSYS; } + +int dummy_pthread_join(pthread_t pthread, void **retval) +{ + /* + * Do nothing. + * + * The main purpose of this function is to break compiler's + * flow analysis and avoid -Wunused-variable false warnings. + */ + return ENOSYS; +} + +#endif diff --git a/thread-utils.h b/thread-utils.h index d9a769d190..4961487ed9 100644 --- a/thread-utils.h +++ b/thread-utils.h @@ -4,12 +4,54 @@ #ifndef NO_PTHREADS #include <pthread.h> -extern int online_cpus(void); -extern int init_recursive_mutex(pthread_mutex_t*); +#define HAVE_THREADS 1 #else -#define online_cpus() 1 +#define HAVE_THREADS 0 + +/* + * macros instead of typedefs because pthread definitions may have + * been pulled in by some system dependencies even though the user + * wants to disable pthread. + */ +#define pthread_t int +#define pthread_mutex_t int +#define pthread_cond_t int +#define pthread_key_t int + +#define pthread_mutex_init(mutex, attr) dummy_pthread_init(mutex) +#define pthread_mutex_lock(mutex) +#define pthread_mutex_unlock(mutex) +#define pthread_mutex_destroy(mutex) + +#define pthread_cond_init(cond, attr) dummy_pthread_init(cond) +#define pthread_cond_wait(cond, mutex) +#define pthread_cond_signal(cond) +#define pthread_cond_broadcast(cond) +#define pthread_cond_destroy(cond) + +#define pthread_key_create(key, attr) dummy_pthread_init(key) +#define pthread_key_delete(key) + +#define pthread_create(thread, attr, fn, data) \ + dummy_pthread_create(thread, attr, fn, data) +#define pthread_join(thread, retval) \ + dummy_pthread_join(thread, retval) + +#define pthread_setspecific(key, data) +#define pthread_getspecific(key) NULL + +int dummy_pthread_create(pthread_t *pthread, const void *attr, + void *(*fn)(void *), void *data); +int dummy_pthread_join(pthread_t pthread, void **retval); + +int dummy_pthread_init(void *); #endif + +int online_cpus(void); +int init_recursive_mutex(pthread_mutex_t*); + + #endif /* THREAD_COMPAT_H */ diff --git a/transport-helper.c b/transport-helper.c index 7213fa0d32..bf225c698f 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -573,7 +573,7 @@ static int run_connect(struct transport *transport, struct strbuf *cmdbuf) fprintf(stderr, "Debug: Falling back to dumb " "transport.\n"); } else { - die(_(_("unknown response to connect: %s")), + die(_("unknown response to connect: %s"), cmdbuf->buf); } diff --git a/wt-status.c b/wt-status.c index 187568a112..a24711374c 100644 --- a/wt-status.c +++ b/wt-status.c @@ -1559,6 +1559,7 @@ void wt_status_get_state(struct wt_status_state *state, struct object_id oid; if (!stat(git_path_merge_head(the_repository), &st)) { + wt_status_check_rebase(NULL, state); state->merge_in_progress = 1; } else if (wt_status_check_rebase(NULL, state)) { ; /* all set */ @@ -1583,9 +1584,13 @@ static void wt_longstatus_print_state(struct wt_status *s) const char *state_color = color(WT_STATUS_HEADER, s); struct wt_status_state *state = &s->state; - if (state->merge_in_progress) + if (state->merge_in_progress) { + if (state->rebase_interactive_in_progress) { + show_rebase_information(s, state_color); + fputs("\n", s->fp); + } show_merge_in_progress(s, state_color); - else if (state->am_in_progress) + } else if (state->am_in_progress) show_am_in_progress(s, state_color); else if (state->rebase_in_progress || state->rebase_interactive_in_progress) show_rebase_in_progress(s, state_color); |