diff options
133 files changed, 2849 insertions, 1366 deletions
diff --git a/Documentation/RelNotes/2.14.5.txt b/Documentation/RelNotes/2.14.5.txt new file mode 100644 index 0000000000..130645fb29 --- /dev/null +++ b/Documentation/RelNotes/2.14.5.txt @@ -0,0 +1,16 @@ +Git v2.14.5 Release Notes +========================= + +This release is to address the recently reported CVE-2018-17456. + +Fixes since v2.14.4 +------------------- + + * Submodules' "URL"s come from the untrusted .gitmodules file, but + we blindly gave it to "git clone" to clone submodules when "git + clone --recurse-submodules" was used to clone a project that has + such a submodule. The code has been hardened to reject such + malformed URLs (e.g. one that begins with a dash). + +Credit for finding and fixing this vulnerability goes to joernchen +and Jeff King, respectively. diff --git a/Documentation/RelNotes/2.15.3.txt b/Documentation/RelNotes/2.15.3.txt new file mode 100644 index 0000000000..fd2e6f8df7 --- /dev/null +++ b/Documentation/RelNotes/2.15.3.txt @@ -0,0 +1,6 @@ +Git v2.15.3 Release Notes +========================= + +This release merges up the fixes that appear in v2.14.5 to address +the recently reported CVE-2018-17456; see the release notes for that +version for details. diff --git a/Documentation/RelNotes/2.16.5.txt b/Documentation/RelNotes/2.16.5.txt new file mode 100644 index 0000000000..cb8ee02a9a --- /dev/null +++ b/Documentation/RelNotes/2.16.5.txt @@ -0,0 +1,6 @@ +Git v2.16.5 Release Notes +========================= + +This release merges up the fixes that appear in v2.14.5 to address +the recently reported CVE-2018-17456; see the release notes for that +version for details. diff --git a/Documentation/RelNotes/2.17.2.txt b/Documentation/RelNotes/2.17.2.txt new file mode 100644 index 0000000000..ef021be870 --- /dev/null +++ b/Documentation/RelNotes/2.17.2.txt @@ -0,0 +1,12 @@ +Git v2.17.2 Release Notes +========================= + +This release merges up the fixes that appear in v2.14.5 to address +the recently reported CVE-2018-17456; see the release notes for that +version for details. + +In addition, this release also teaches "fsck" and the server side +logic to reject pushes to repositories that attempt to create such a +problematic ".gitmodules" file as tracked contents, to help hosting +sites protect their customers by preventing malicious contents from +spreading. diff --git a/Documentation/RelNotes/2.18.1.txt b/Documentation/RelNotes/2.18.1.txt new file mode 100644 index 0000000000..2098cdd776 --- /dev/null +++ b/Documentation/RelNotes/2.18.1.txt @@ -0,0 +1,6 @@ +Git v2.18.1 Release Notes +========================= + +This release merges up the fixes that appear in v2.14.5 and in +v2.17.2 to address the recently reported CVE-2018-17456; see the +release notes for those versions for details. diff --git a/Documentation/RelNotes/2.19.1.txt b/Documentation/RelNotes/2.19.1.txt new file mode 100644 index 0000000000..da7672674e --- /dev/null +++ b/Documentation/RelNotes/2.19.1.txt @@ -0,0 +1,6 @@ +Git v2.19.1 Release Notes +========================= + +This release merges up the fixes that appear in v2.14.5 and in +v2.17.2 to address the recently reported CVE-2018-17456; see the +release notes for those versions for details. diff --git a/Documentation/RelNotes/2.20.0.txt b/Documentation/RelNotes/2.20.0.txt new file mode 100644 index 0000000000..2cc5fd7a9f --- /dev/null +++ b/Documentation/RelNotes/2.20.0.txt @@ -0,0 +1,183 @@ +Git Release Notes +================= + +Backward Compatibility Notes +---------------------------- + + * "git branch -l <foo>" used to be a way to ask a reflog to be + created while creating a new branch, but that is no longer the + case. It is a short-hand for "git branch --list <foo>" now. + + * "git push" into refs/tags/* hierarchy is rejected without getting + forced, but "git fetch" (misguidedly) used the "fast forwarding" + rule used for the refs/heads/* hierarchy; this has been corrected, + which means some fetches of tags that did not fail with older + version of Git will fail without "--force" with this version. + + +Updates since v2.19 +------------------- + +UI, Workflows & Features + + * Running "git clone" against a project that contain two files with + pathnames that differ only in cases on a case insensitive + filesystem would result in one of the files lost because the + underlying filesystem is incapable of holding both at the same + time. An attempt is made to detect such a case and warn. + + * "git checkout -b newbranch [HEAD]" should not have to do as much as + checking out a commit different from HEAD. An attempt is made to + optimize this special case. + + * "git rev-list --stdin </dev/null" used to be an error; it now shows + no output without an error. "git rev-list --stdin --default HEAD" + still falls back to the given default when nothing is given on the + standard input. + + * Lift code from GitHub to restrict delta computation so that an + object that exists in one fork is not made into a delta against + another object that does not appear in the same forked repository. + + * "git format-patch" learned new "--interdiff" and "--range-diff" + options to explain the difference between this version and the + previous attempt in the cover letter (or after the tree-dashes as + a comment). + + * "git mailinfo" used in "git am" learned to make a best-effort + recovery of a patch corrupted by MUA that sends text/plain with + format=flawed option. + (merge 3aa4d81f88 rs/mailinfo-format-flowed later to maint). + + * The rules used by "git push" and "git fetch" to determine if a ref + can or cannot be updated were inconsistent; specifically, fetching + to update existing tags were allowed even though tags are supposed + to be unmoving anchoring points. "git fetch" was taught to forbid + updates to existing tags without the "--force" option. + + * "git multi-pack-index" learned to detect corruption in the .midx + file it uses, and this feature has been integrated into "git fsck". + + +Performance, Internal Implementation, Development Support etc. + + * When there are too many packfiles in a repository (which is not + recommended), looking up an object in these would require + consulting many pack .idx files; a new mechanism to have a single + file that consolidates all of these .idx files is introduced. + + * "git submodule update" is getting rewritten piece-by-piece into C. + + * The code for computing history reachability has been shuffled, + obtained a bunch of new tests to cover them, and then being + improved. + + * The unpack_trees() API used in checking out a branch and merging + walks one or more trees along with the index. When the cache-tree + in the index tells us that we are walking a tree whose flattened + contents is known (i.e. matches a span in the index), as linearly + scanning a span in the index is much more efficient than having to + open tree objects recursively and listing their entries, the walk + can be optimized, which has been done. + + * When creating a thin pack, which allows objects to be made into a + delta against another object that is not in the resulting pack but + is known to be present on the receiving end, the code learned to + take advantage of the reachability bitmap; this allows the server + to send a delta against a base beyond the "boundary" commit. + + * spatch transformation to replace boolean uses of !hashcmp() to + newly introduced oideq() is added, and applied, to regain + performance lost due to support of multiple hash algorithms. + + * Fix a bug in which the same path could be registered under multiple + worktree entries if the path was missing (for instance, was removed + manually). Also, as a convenience, expand the number of cases in + which --force is applicable. + + * Split Documentation/config.txt for easier maintenance. + (merge 6014363f0b nd/config-split later to maint). + + * Test helper binaries clean-up. + (merge c9a1f4161f nd/test-tool later to maint). + + * Various tests have been updated to make it easier to swap the + hash function used for object identification. + (merge ae0c89d41b bc/hash-independent-tests later to maint). + + * Update fsck.skipList implementation and documentation. + (merge 371a655074 ab/fsck-skiplist later to maint). + + +Fixes since v2.19 +----------------- + + * "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. + (merge 66e83d9b41 jk/trailer-fixes later to maint). + + * Malformed or crafted data in packstream can make our code attempt + to read or write past the allocated buffer and abort, instead of + reporting an error, which has been fixed. + + * "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. + (merge 10d2f35436 js/rebase-i-autosquash-fix later to maint). + + * 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. + (merge 43f1180814 bp/mv-submodules-with-fsmonitor later to maint). + + * Fix for a long-standing bug that leaves the index file corrupt when + it shrinks during a partial commit. + (merge 6c003d6ffb jk/reopen-tempfile-truncate later to maint). + + * Further fix for O_APPEND emulation on Windows + (merge eeaf7ddac7 js/mingw-o-append later to maint). + + * A corner case bugfix in "git rerere" code. + (merge ad2bf0d9b4 en/rerere-multi-stage-1-fix later to maint). + + * "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. + (merge 84d938b732 nd/attr-pathspec-fix later to maint). + + * Recent update broke the reachability algorithm when refs (e.g. + tags) that point at objects that are not commit were involved, + which has been fixed. + + * "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. + (merge a3ec9eaf38 en/sequencer-empty-edit-result-aborts later to maint). + + * The code to backfill objects in lazily cloned repository did not + work correctly, which has been corrected. + (merge e68302011c jt/lazy-object-fetch-fix later to maint). + + * Update error messages given by "git remote" and make them consistent. + (merge 5025425dff ms/remote-error-message-update later to maint). + + * "git update-ref" learned to make both "--no-deref" and "--stdin" + work at the same time. + (merge d345e9fbe7 en/update-ref-no-deref-stdin later to maint). + + * Recently added "range-diff" had a corner-case bug to cause it + segfault, which has been corrected. + (merge e467a90c7a tg/range-diff-corner-case-fix 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). + (merge fa0aeea770 sg/doc-trace-appends later to maint). + (merge d64324cb60 tb/void-check-attr later to maint). + (merge c3b9bc94b9 en/double-semicolon-fix later to maint). + (merge 79336116f5 sg/t3701-tighten-trace later to maint). + (merge 801fa63a90 jk/dev-build-format-security later to maint). + (merge 0597dd62ba sb/string-list-remove-unused later to maint). + (merge db2d36fad8 bw/protocol-v2 later to maint). + (merge 456d7cd3a9 sg/split-index-test later to maint). diff --git a/Documentation/config.txt b/Documentation/config.txt index 112041f407..c9f8b72df7 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -225,7 +225,7 @@ boolean:: false;; Boolean false literals are `no`, `off`, `false`, `0` and the empty string. + -When converting value to the canonical form using `--bool` type +When converting a value to its canonical form using the `--type=bool` type specifier, 'git config' will ensure that the output is "true" or "false" (spelled in lowercase). @@ -832,12 +832,6 @@ core.packedRefsTimeout:: all; -1 means to try indefinitely. Default is 1000 (i.e., retry for 1 second). -sequence.editor:: - Text editor used by `git rebase -i` for editing the rebase instruction file. - The value is meant to be interpreted by the shell when it is used. - It can be overridden by the `GIT_SEQUENCE_EDITOR` environment variable. - When not configured the default commit message editor is used instead. - core.pager:: Text viewer for use by Git commands (e.g., 'less'). The value is meant to be interpreted by the shell. The order of preference @@ -1159,7 +1153,7 @@ and by linkgit:git-worktree[1] when 'git worktree add' refers to a remote branch. This setting might be used for other checkout-like commands or functionality in the future. -checkout.optimizeNewBranch +checkout.optimizeNewBranch:: Optimizes the performance of "git checkout -b <new_branch>" when using sparse-checkout. When set to true, git will not update the repo based on the current sparse-checkout settings. This means it @@ -1520,159 +1514,9 @@ fastimport.unpackLimit:: operation complete faster, especially on slow filesystems. If not set, the value of `transfer.unpackLimit` is used instead. -fetch.recurseSubmodules:: - This option can be either set to a boolean value or to 'on-demand'. - Setting it to a boolean changes the behavior of fetch and pull to - unconditionally recurse into submodules when set to true or to not - recurse at all when set to false. When set to 'on-demand' (the default - value), fetch and pull will only recurse into a populated submodule - when its superproject retrieves a commit that updates the submodule's - reference. - -fetch.fsckObjects:: - If it is set to true, git-fetch-pack will check all fetched - objects. See `transfer.fsckObjects` for what's - checked. Defaults to false. If not set, the value of - `transfer.fsckObjects` is used instead. - -fetch.fsck.<msg-id>:: - Acts like `fsck.<msg-id>`, but is used by - linkgit:git-fetch-pack[1] instead of linkgit:git-fsck[1]. See - the `fsck.<msg-id>` documentation for details. - -fetch.fsck.skipList:: - Acts like `fsck.skipList`, but is used by - linkgit:git-fetch-pack[1] instead of linkgit:git-fsck[1]. See - the `fsck.skipList` documentation for details. - -fetch.unpackLimit:: - If the number of objects fetched over the Git native - transfer is below this - limit, then the objects will be unpacked into loose object - files. However if the number of received objects equals or - exceeds this limit then the received pack will be stored as - a pack, after adding any missing delta bases. Storing the - pack from a push can make the push operation complete faster, - especially on slow filesystems. If not set, the value of - `transfer.unpackLimit` is used instead. - -fetch.prune:: - If true, fetch will automatically behave as if the `--prune` - option was given on the command line. See also `remote.<name>.prune` - and the PRUNING section of linkgit:git-fetch[1]. - -fetch.pruneTags:: - If true, fetch will automatically behave as if the - `refs/tags/*:refs/tags/*` refspec was provided when pruning, - if not set already. This allows for setting both this option - and `fetch.prune` to maintain a 1=1 mapping to upstream - refs. See also `remote.<name>.pruneTags` and the PRUNING - section of linkgit:git-fetch[1]. - -fetch.output:: - Control how ref update status is printed. Valid values are - `full` and `compact`. Default value is `full`. See section - OUTPUT in linkgit:git-fetch[1] for detail. - -fetch.negotiationAlgorithm:: - Control how information about the commits in the local repository is - sent when negotiating the contents of the packfile to be sent by the - server. Set to "skipping" to use an algorithm that skips commits in an - effort to converge faster, but may result in a larger-than-necessary - packfile; The default is "default" which instructs Git to use the default algorithm - that never skips commits (unless the server has acknowledged it or one - of its descendants). - Unknown values will cause 'git fetch' to error out. -+ -See also the `--negotiation-tip` option for linkgit:git-fetch[1]. - -format.attach:: - Enable multipart/mixed attachments as the default for - 'format-patch'. The value can also be a double quoted string - which will enable attachments as the default and set the - value as the boundary. See the --attach option in - linkgit:git-format-patch[1]. - -format.from:: - Provides the default value for the `--from` option to format-patch. - Accepts a boolean value, or a name and email address. If false, - format-patch defaults to `--no-from`, using commit authors directly in - the "From:" field of patch mails. If true, format-patch defaults to - `--from`, using your committer identity in the "From:" field of patch - mails and including a "From:" field in the body of the patch mail if - different. If set to a non-boolean value, format-patch uses that - value instead of your committer identity. Defaults to false. - -format.numbered:: - A boolean which can enable or disable sequence numbers in patch - subjects. It defaults to "auto" which enables it only if there - is more than one patch. It can be enabled or disabled for all - messages by setting it to "true" or "false". See --numbered - option in linkgit:git-format-patch[1]. - -format.headers:: - Additional email headers to include in a patch to be submitted - by mail. See linkgit:git-format-patch[1]. - -format.to:: -format.cc:: - Additional recipients to include in a patch to be submitted - by mail. See the --to and --cc options in - linkgit:git-format-patch[1]. - -format.subjectPrefix:: - The default for format-patch is to output files with the '[PATCH]' - subject prefix. Use this variable to change that prefix. - -format.signature:: - The default for format-patch is to output a signature containing - the Git version number. Use this variable to change that default. - Set this variable to the empty string ("") to suppress - signature generation. - -format.signatureFile:: - Works just like format.signature except the contents of the - file specified by this variable will be used as the signature. - -format.suffix:: - The default for format-patch is to output files with the suffix - `.patch`. Use this variable to change that suffix (make sure to - include the dot if you want it). - -format.pretty:: - The default pretty format for log/show/whatchanged command, - See linkgit:git-log[1], linkgit:git-show[1], - linkgit:git-whatchanged[1]. - -format.thread:: - The default threading style for 'git format-patch'. Can be - a boolean value, or `shallow` or `deep`. `shallow` threading - makes every mail a reply to the head of the series, - where the head is chosen from the cover letter, the - `--in-reply-to`, and the first patch mail, in this order. - `deep` threading makes every mail a reply to the previous one. - A true boolean value is the same as `shallow`, and a false - value disables threading. - -format.signOff:: - A boolean value which lets you enable the `-s/--signoff` option of - format-patch by default. *Note:* Adding the Signed-off-by: line to a - patch should be a conscious act and means that you certify you have - the rights to submit this work under the same open source license. - Please see the 'SubmittingPatches' document for further discussion. - -format.coverLetter:: - A boolean that controls whether to generate a cover-letter when - format-patch is invoked, but in addition can be set to "auto", to - generate a cover-letter only when there's more than one patch. - -format.outputDirectory:: - Set a custom directory to store the resulting files instead of the - current working directory. - -format.useAutoBase:: - A boolean value which lets you enable the `--base=auto` option of - format-patch by default. +include::fetch-config.txt[] + +include::format-config.txt[] filter.<driver>.clean:: The command which is used to convert the content of a worktree @@ -1723,12 +1567,16 @@ doing the same for `receive.fsck.<msg-id>` and `fetch.fsck.<msg-id>` will only cause git to warn. fsck.skipList:: - The path to a sorted list of object names (i.e. one SHA-1 per + The path to a list of object names (i.e. one unabbreviated SHA-1 per line) that are known to be broken in a non-fatal way and should - be ignored. This feature is useful when an established project - should be accepted despite early commits containing errors that - can be safely ignored such as invalid committer email addresses. - Note: corrupt objects cannot be skipped with this setting. + be ignored. On versions of Git 2.20 and later comments ('#'), empty + lines, and any leading and trailing whitespace is ignored. Everything + but a SHA-1 per line will error out on older versions. ++ +This feature is useful when an established project should be accepted +despite early commits containing errors that can be safely ignored +such as invalid committer email addresses. Note: corrupt objects +cannot be skipped with this setting. + Like `fsck.<msg-id>` this variable has corresponding `receive.fsck.skipList` and `fetch.fsck.skipList` variants. @@ -1738,6 +1586,15 @@ Unlike variables like `color.ui` and `core.editor` the fall back on the `fsck.skipList` configuration if they aren't set. To uniformly configure the same fsck settings in different circumstances all three of them they must all set to the same values. ++ +Older versions of Git (before 2.20) documented that the object names +list should be sorted. This was never a requirement, the object names +could appear in any order, but when reading the list we tracked whether +the list was sorted for the purposes of an internal binary search +implementation, which could save itself some work with an already sorted +list. Unless you had a humongous list there was no reason to go out of +your way to pre-sort the list. After Git version 2.20 a hash implementation +is used instead, so there's now no reason to pre-sort the list. gc.aggressiveDepth:: The depth parameter used in the delta compression @@ -1847,73 +1704,7 @@ gc.rerereUnresolved:: You can also use more human-readable "1.month.ago", etc. The default is 15 days. See linkgit:git-rerere[1]. -gitcvs.commitMsgAnnotation:: - Append this string to each commit message. Set to empty string - to disable this feature. Defaults to "via git-CVS emulator". - -gitcvs.enabled:: - Whether the CVS server interface is enabled for this repository. - See linkgit:git-cvsserver[1]. - -gitcvs.logFile:: - Path to a log file where the CVS server interface well... logs - various stuff. See linkgit:git-cvsserver[1]. - -gitcvs.usecrlfattr:: - If true, the server will look up the end-of-line conversion - attributes for files to determine the `-k` modes to use. If - the attributes force Git to treat a file as text, - the `-k` mode will be left blank so CVS clients will - treat it as text. If they suppress text conversion, the file - will be set with '-kb' mode, which suppresses any newline munging - the client might otherwise do. If the attributes do not allow - the file type to be determined, then `gitcvs.allBinary` is - used. See linkgit:gitattributes[5]. - -gitcvs.allBinary:: - This is used if `gitcvs.usecrlfattr` does not resolve - the correct '-kb' mode to use. If true, all - unresolved files are sent to the client in - mode '-kb'. This causes the client to treat them - as binary files, which suppresses any newline munging it - otherwise might do. Alternatively, if it is set to "guess", - then the contents of the file are examined to decide if - it is binary, similar to `core.autocrlf`. - -gitcvs.dbName:: - Database used by git-cvsserver to cache revision information - derived from the Git repository. The exact meaning depends on the - used database driver, for SQLite (which is the default driver) this - is a filename. Supports variable substitution (see - linkgit:git-cvsserver[1] for details). May not contain semicolons (`;`). - Default: '%Ggitcvs.%m.sqlite' - -gitcvs.dbDriver:: - Used Perl DBI driver. You can specify any available driver - for this here, but it might not work. git-cvsserver is tested - with 'DBD::SQLite', reported to work with 'DBD::Pg', and - reported *not* to work with 'DBD::mysql'. Experimental feature. - May not contain double colons (`:`). Default: 'SQLite'. - See linkgit:git-cvsserver[1]. - -gitcvs.dbUser, gitcvs.dbPass:: - Database user and password. Only useful if setting `gitcvs.dbDriver`, - since SQLite has no concept of database users and/or passwords. - 'gitcvs.dbUser' supports variable substitution (see - linkgit:git-cvsserver[1] for details). - -gitcvs.dbTableNamePrefix:: - Database table name prefix. Prepended to the names of any - database tables used, allowing a single database to be used - for several repositories. Supports variable substitution (see - linkgit:git-cvsserver[1] for details). Any non-alphabetic - characters will be replaced with underscores. - -All gitcvs variables except for `gitcvs.usecrlfattr` and -`gitcvs.allBinary` can also be specified as -'gitcvs.<access_method>.<varname>' (where 'access_method' -is one of "ext" and "pserver") to make them apply only for the given -access method. +include::gitcvs-config.txt[] gitweb.category:: gitweb.description:: @@ -1978,63 +1769,7 @@ gpg.<format>.program:: be used as a legacy synonym for `gpg.openpgp.program`. The default value for `gpg.x509.program` is "gpgsm". -gui.commitMsgWidth:: - Defines how wide the commit message window is in the - linkgit:git-gui[1]. "75" is the default. - -gui.diffContext:: - Specifies how many context lines should be used in calls to diff - made by the linkgit:git-gui[1]. The default is "5". - -gui.displayUntracked:: - Determines if linkgit:git-gui[1] shows untracked files - in the file list. The default is "true". - -gui.encoding:: - Specifies the default encoding to use for displaying of - file contents in linkgit:git-gui[1] and linkgit:gitk[1]. - It can be overridden by setting the 'encoding' attribute - for relevant files (see linkgit:gitattributes[5]). - If this option is not set, the tools default to the - locale encoding. - -gui.matchTrackingBranch:: - Determines if new branches created with linkgit:git-gui[1] should - default to tracking remote branches with matching names or - not. Default: "false". - -gui.newBranchTemplate:: - Is used as suggested name when creating new branches using the - linkgit:git-gui[1]. - -gui.pruneDuringFetch:: - "true" if linkgit:git-gui[1] should prune remote-tracking branches when - performing a fetch. The default value is "false". - -gui.trustmtime:: - Determines if linkgit:git-gui[1] should trust the file modification - timestamp or not. By default the timestamps are not trusted. - -gui.spellingDictionary:: - Specifies the dictionary used for spell checking commit messages in - the linkgit:git-gui[1]. When set to "none" spell checking is turned - off. - -gui.fastCopyBlame:: - If true, 'git gui blame' uses `-C` instead of `-C -C` for original - location detection. It makes blame significantly faster on huge - repositories at the expense of less thorough copy detection. - -gui.copyBlameThreshold:: - Specifies the threshold to use in 'git gui blame' original location - detection, measured in alphanumeric characters. See the - linkgit:git-blame[1] manual for more information on copy detection. - -gui.blamehistoryctx:: - Specifies the radius of history context in days to show in - linkgit:gitk[1] for the selected commit, when the `Show History - Context` menu item is invoked from 'git gui blame'. If this - variable is set to zero, the whole history is shown. +include::gui-config.txt[] guitool.<name>.cmd:: Specifies the shell command line to execute when the corresponding item @@ -2856,284 +2591,17 @@ protocol.version:: * `1` - the original wire protocol with the addition of a version string in the initial response from the server. --- - -pull.ff:: - By default, Git does not create an extra merge commit when merging - a commit that is a descendant of the current commit. Instead, the - tip of the current branch is fast-forwarded. When set to `false`, - this variable tells Git to create an extra merge commit in such - a case (equivalent to giving the `--no-ff` option from the command - line). When set to `only`, only such fast-forward merges are - allowed (equivalent to giving the `--ff-only` option from the - command line). This setting overrides `merge.ff` when pulling. - -pull.rebase:: - When true, rebase branches on top of the fetched branch, instead - of merging the default branch from the default remote when "git - pull" is run. See "branch.<name>.rebase" for setting this on a - per-branch basis. -+ -When `merges`, pass the `--rebase-merges` option to 'git rebase' -so that the local merge commits are included in the rebase (see -linkgit:git-rebase[1] for details). -+ -When preserve, also pass `--preserve-merges` along to 'git rebase' -so that locally committed merge commits will not be flattened -by running 'git pull'. -+ -When the value is `interactive`, the rebase is run in interactive mode. -+ -*NOTE*: this is a possibly dangerous operation; do *not* use -it unless you understand the implications (see linkgit:git-rebase[1] -for details). - -pull.octopus:: - The default merge strategy to use when pulling multiple branches - at once. - -pull.twohead:: - The default merge strategy to use when pulling a single branch. - -push.default:: - Defines the action `git push` should take if no refspec is - explicitly given. Different values are well-suited for - specific workflows; for instance, in a purely central workflow - (i.e. the fetch source is equal to the push destination), - `upstream` is probably what you want. Possible values are: -+ --- - -* `nothing` - do not push anything (error out) unless a refspec is - explicitly given. This is primarily meant for people who want to - avoid mistakes by always being explicit. - -* `current` - push the current branch to update a branch with the same - name on the receiving end. Works in both central and non-central - workflows. - -* `upstream` - push the current branch back to the branch whose - changes are usually integrated into the current branch (which is - called `@{upstream}`). This mode only makes sense if you are - pushing to the same repository you would normally pull from - (i.e. central workflow). - -* `tracking` - This is a deprecated synonym for `upstream`. +* `2` - link:technical/protocol-v2.html[wire protocol version 2]. -* `simple` - in centralized workflow, work like `upstream` with an - added safety to refuse to push if the upstream branch's name is - different from the local one. -+ -When pushing to a remote that is different from the remote you normally -pull from, work as `current`. This is the safest option and is suited -for beginners. -+ -This mode has become the default in Git 2.0. - -* `matching` - push all branches having the same name on both ends. - This makes the repository you are pushing to remember the set of - branches that will be pushed out (e.g. if you always push 'maint' - and 'master' there and no other branches, the repository you push - to will have these two branches, and your local 'maint' and - 'master' will be pushed there). -+ -To use this mode effectively, you have to make sure _all_ the -branches you would push out are ready to be pushed out before -running 'git push', as the whole point of this mode is to allow you -to push all of the branches in one go. If you usually finish work -on only one branch and push out the result, while other branches are -unfinished, this mode is not for you. Also this mode is not -suitable for pushing into a shared central repository, as other -people may add new branches there, or update the tip of existing -branches outside your control. -+ -This used to be the default, but not since Git 2.0 (`simple` is the -new default). - --- - -push.followTags:: - If set to true enable `--follow-tags` option by default. You - may override this configuration at time of push by specifying - `--no-follow-tags`. - -push.gpgSign:: - May be set to a boolean value, or the string 'if-asked'. A true - value causes all pushes to be GPG signed, as if `--signed` is - passed to linkgit:git-push[1]. The string 'if-asked' causes - pushes to be signed if the server supports it, as if - `--signed=if-asked` is passed to 'git push'. A false value may - override a value from a lower-priority config file. An explicit - command-line flag always overrides this config option. - -push.pushOption:: - When no `--push-option=<option>` argument is given from the - command line, `git push` behaves as if each <value> of - this variable is given as `--push-option=<value>`. -+ -This is a multi-valued variable, and an empty value can be used in a -higher priority configuration file (e.g. `.git/config` in a -repository) to clear the values inherited from a lower priority -configuration files (e.g. `$HOME/.gitconfig`). -+ -- -Example: +include::pull-config.txt[] -/etc/gitconfig - push.pushoption = a - push.pushoption = b - -~/.gitconfig - push.pushoption = c - -repo/.git/config - push.pushoption = - push.pushoption = b - -This will result in only b (a and c are cleared). - --- - -push.recurseSubmodules:: - Make sure all submodule commits used by the revisions to be pushed - are available on a remote-tracking branch. If the value is 'check' - then Git will verify that all submodule commits that changed in the - revisions to be pushed are available on at least one remote of the - submodule. If any commits are missing, the push will be aborted and - exit with non-zero status. If the value is 'on-demand' then all - submodules that changed in the revisions to be pushed will be - pushed. If on-demand was not able to push all necessary revisions - it will also be aborted and exit with non-zero status. If the value - is 'no' then default behavior of ignoring submodules when pushing - is retained. You may override this configuration at time of push by - specifying '--recurse-submodules=check|on-demand|no'. +include::push-config.txt[] include::rebase-config.txt[] -receive.advertiseAtomic:: - By default, git-receive-pack will advertise the atomic push - capability to its clients. If you don't want to advertise this - capability, set this variable to false. - -receive.advertisePushOptions:: - When set to true, git-receive-pack will advertise the push options - capability to its clients. False by default. - -receive.autogc:: - By default, git-receive-pack will run "git-gc --auto" after - receiving data from git-push and updating refs. You can stop - it by setting this variable to false. - -receive.certNonceSeed:: - By setting this variable to a string, `git receive-pack` - will accept a `git push --signed` and verifies it by using - a "nonce" protected by HMAC using this string as a secret - key. - -receive.certNonceSlop:: - When a `git push --signed` sent a push certificate with a - "nonce" that was issued by a receive-pack serving the same - repository within this many seconds, export the "nonce" - found in the certificate to `GIT_PUSH_CERT_NONCE` to the - hooks (instead of what the receive-pack asked the sending - side to include). This may allow writing checks in - `pre-receive` and `post-receive` a bit easier. Instead of - checking `GIT_PUSH_CERT_NONCE_SLOP` environment variable - that records by how many seconds the nonce is stale to - decide if they want to accept the certificate, they only - can check `GIT_PUSH_CERT_NONCE_STATUS` is `OK`. - -receive.fsckObjects:: - If it is set to true, git-receive-pack will check all received - objects. See `transfer.fsckObjects` for what's checked. - Defaults to false. If not set, the value of - `transfer.fsckObjects` is used instead. - -receive.fsck.<msg-id>:: - Acts like `fsck.<msg-id>`, but is used by - linkgit:git-receive-pack[1] instead of - linkgit:git-fsck[1]. See the `fsck.<msg-id>` documentation for - details. - -receive.fsck.skipList:: - Acts like `fsck.skipList`, but is used by - linkgit:git-receive-pack[1] instead of - linkgit:git-fsck[1]. See the `fsck.skipList` documentation for - details. - -receive.keepAlive:: - After receiving the pack from the client, `receive-pack` may - produce no output (if `--quiet` was specified) while processing - the pack, causing some networks to drop the TCP connection. - With this option set, if `receive-pack` does not transmit - any data in this phase for `receive.keepAlive` seconds, it will - send a short keepalive packet. The default is 5 seconds; set - to 0 to disable keepalives entirely. - -receive.unpackLimit:: - If the number of objects received in a push is below this - limit then the objects will be unpacked into loose object - files. However if the number of received objects equals or - exceeds this limit then the received pack will be stored as - a pack, after adding any missing delta bases. Storing the - pack from a push can make the push operation complete faster, - especially on slow filesystems. If not set, the value of - `transfer.unpackLimit` is used instead. - -receive.maxInputSize:: - If the size of the incoming pack stream is larger than this - limit, then git-receive-pack will error out, instead of - accepting the pack file. If not set or set to 0, then the size - is unlimited. - -receive.denyDeletes:: - If set to true, git-receive-pack will deny a ref update that deletes - the ref. Use this to prevent such a ref deletion via a push. - -receive.denyDeleteCurrent:: - If set to true, git-receive-pack will deny a ref update that - deletes the currently checked out branch of a non-bare repository. - -receive.denyCurrentBranch:: - If set to true or "refuse", git-receive-pack will deny a ref update - to the currently checked out branch of a non-bare repository. - Such a push is potentially dangerous because it brings the HEAD - out of sync with the index and working tree. If set to "warn", - print a warning of such a push to stderr, but allow the push to - proceed. If set to false or "ignore", allow such pushes with no - message. Defaults to "refuse". -+ -Another option is "updateInstead" which will update the working -tree if pushing into the current branch. This option is -intended for synchronizing working directories when one side is not easily -accessible via interactive ssh (e.g. a live web site, hence the requirement -that the working directory be clean). This mode also comes in handy when -developing inside a VM to test and fix code on different Operating Systems. -+ -By default, "updateInstead" will refuse the push if the working tree or -the index have any difference from the HEAD, but the `push-to-checkout` -hook can be used to customize this. See linkgit:githooks[5]. - -receive.denyNonFastForwards:: - If set to true, git-receive-pack will deny a ref update which is - not a fast-forward. Use this to prevent such an update via a push, - even if that push is forced. This configuration variable is - set when initializing a shared repository. - -receive.hideRefs:: - This variable is the same as `transfer.hideRefs`, but applies - only to `receive-pack` (and so affects pushes, but not fetches). - An attempt to update or delete a hidden ref by `git push` is - rejected. - -receive.updateServerInfo:: - If set to true, git-receive-pack will run git-update-server-info - after receiving data from git-push and updating refs. - -receive.shallowUpdate:: - If set to true, .git/shallow can be updated when new refs - require new shallow roots. Otherwise those refs are rejected. +include::receive-config.txt[] remote.pushDefault:: The remote to push to by default. Overrides @@ -3259,71 +2727,15 @@ rerere.enabled:: `$GIT_DIR`, e.g. if "rerere" was previously used in the repository. -sendemail.identity:: - A configuration identity. When given, causes values in the - 'sendemail.<identity>' subsection to take precedence over - values in the 'sendemail' section. The default identity is - the value of `sendemail.identity`. - -sendemail.smtpEncryption:: - See linkgit:git-send-email[1] for description. Note that this - setting is not subject to the 'identity' mechanism. - -sendemail.smtpssl (deprecated):: - Deprecated alias for 'sendemail.smtpEncryption = ssl'. - -sendemail.smtpsslcertpath:: - Path to ca-certificates (either a directory or a single file). - Set it to an empty string to disable certificate verification. - -sendemail.<identity>.*:: - Identity-specific versions of the 'sendemail.*' parameters - found below, taking precedence over those when this - identity is selected, through either the command-line or - `sendemail.identity`. - -sendemail.aliasesFile:: -sendemail.aliasFileType:: -sendemail.annotate:: -sendemail.bcc:: -sendemail.cc:: -sendemail.ccCmd:: -sendemail.chainReplyTo:: -sendemail.confirm:: -sendemail.envelopeSender:: -sendemail.from:: -sendemail.multiEdit:: -sendemail.signedoffbycc:: -sendemail.smtpPass:: -sendemail.suppresscc:: -sendemail.suppressFrom:: -sendemail.to:: -sendemail.tocmd:: -sendemail.smtpDomain:: -sendemail.smtpServer:: -sendemail.smtpServerPort:: -sendemail.smtpServerOption:: -sendemail.smtpUser:: -sendemail.thread:: -sendemail.transferEncoding:: -sendemail.validate:: -sendemail.xmailer:: - See linkgit:git-send-email[1] for description. - -sendemail.signedoffcc (deprecated):: - Deprecated alias for `sendemail.signedoffbycc`. - -sendemail.smtpBatchSize:: - Number of messages to be sent per connection, after that a relogin - will happen. If the value is 0 or undefined, send all messages in - one connection. - See also the `--batch-size` option of linkgit:git-send-email[1]. - -sendemail.smtpReloginDelay:: - Seconds wait before reconnecting to smtp server. - See also the `--relogin-delay` option of linkgit:git-send-email[1]. - -showbranch.default:: +include::sendemail-config.txt[] + +sequence.editor:: + Text editor used by `git rebase -i` for editing the rebase instruction file. + The value is meant to be interpreted by the shell when it is used. + It can be overridden by the `GIT_SEQUENCE_EDITOR` environment variable. + When not configured the default commit message editor is used instead. + +showBranch.default:: The default set of branches for linkgit:git-show-branch[1]. See linkgit:git-show-branch[1]. @@ -3435,88 +2847,7 @@ stash.showStat:: option will show diffstat of the stash entry. Defaults to true. See description of 'show' command in linkgit:git-stash[1]. -submodule.<name>.url:: - The URL for a submodule. This variable is copied from the .gitmodules - file to the git config via 'git submodule init'. The user can change - the configured URL before obtaining the submodule via 'git submodule - update'. If neither submodule.<name>.active or submodule.active are - set, the presence of this variable is used as a fallback to indicate - whether the submodule is of interest to git commands. - See linkgit:git-submodule[1] and linkgit:gitmodules[5] for details. - -submodule.<name>.update:: - The method by which a submodule is updated by 'git submodule update', - which is the only affected command, others such as - 'git checkout --recurse-submodules' are unaffected. It exists for - historical reasons, when 'git submodule' was the only command to - interact with submodules; settings like `submodule.active` - and `pull.rebase` are more specific. It is populated by - `git submodule init` from the linkgit:gitmodules[5] file. - See description of 'update' command in linkgit:git-submodule[1]. - -submodule.<name>.branch:: - The remote branch name for a submodule, used by `git submodule - update --remote`. Set this option to override the value found in - the `.gitmodules` file. See linkgit:git-submodule[1] and - linkgit:gitmodules[5] for details. - -submodule.<name>.fetchRecurseSubmodules:: - This option can be used to control recursive fetching of this - submodule. It can be overridden by using the --[no-]recurse-submodules - command-line option to "git fetch" and "git pull". - This setting will override that from in the linkgit:gitmodules[5] - file. - -submodule.<name>.ignore:: - Defines under what circumstances "git status" and the diff family show - a submodule as modified. When set to "all", it will never be considered - modified (but it will nonetheless show up in the output of status and - commit when it has been staged), "dirty" will ignore all changes - to the submodules work tree and - takes only differences between the HEAD of the submodule and the commit - recorded in the superproject into account. "untracked" will additionally - let submodules with modified tracked files in their work tree show up. - Using "none" (the default when this option is not set) also shows - submodules that have untracked files in their work tree as changed. - This setting overrides any setting made in .gitmodules for this submodule, - both settings can be overridden on the command line by using the - "--ignore-submodules" option. The 'git submodule' commands are not - affected by this setting. - -submodule.<name>.active:: - Boolean value indicating if the submodule is of interest to git - commands. This config option takes precedence over the - submodule.active config option. See linkgit:gitsubmodules[7] for - details. - -submodule.active:: - A repeated field which contains a pathspec used to match against a - submodule's path to determine if the submodule is of interest to git - commands. See linkgit:gitsubmodules[7] for details. - -submodule.recurse:: - Specifies if commands recurse into submodules by default. This - applies to all commands that have a `--recurse-submodules` option, - except `clone`. - Defaults to false. - -submodule.fetchJobs:: - Specifies how many submodules are fetched/cloned at the same time. - A positive integer allows up to that number of submodules fetched - in parallel. A value of 0 will give some reasonable default. - If unset, it defaults to 1. - -submodule.alternateLocation:: - Specifies how the submodules obtain alternates when submodules are - cloned. Possible values are `no`, `superproject`. - By default `no` is assumed, which doesn't add references. When the - value is set to `superproject` the submodule to be cloned computes - its alternates location relative to the superprojects alternate. - -submodule.alternateErrorStrategy:: - Specifies how to treat errors with the alternates for a submodule - as computed via `submodule.alternateLocation`. Possible values are - `ignore`, `info`, `die`. Default is `die`. +include::submodule-config.txt[] tag.forceSignAnnotated:: A boolean to specify whether annotated tags created should be GPG signed. diff --git a/Documentation/fetch-config.txt b/Documentation/fetch-config.txt new file mode 100644 index 0000000000..cbfad6cdbb --- /dev/null +++ b/Documentation/fetch-config.txt @@ -0,0 +1,65 @@ +fetch.recurseSubmodules:: + This option can be either set to a boolean value or to 'on-demand'. + Setting it to a boolean changes the behavior of fetch and pull to + unconditionally recurse into submodules when set to true or to not + recurse at all when set to false. When set to 'on-demand' (the default + value), fetch and pull will only recurse into a populated submodule + when its superproject retrieves a commit that updates the submodule's + reference. + +fetch.fsckObjects:: + If it is set to true, git-fetch-pack will check all fetched + objects. See `transfer.fsckObjects` for what's + checked. Defaults to false. If not set, the value of + `transfer.fsckObjects` is used instead. + +fetch.fsck.<msg-id>:: + Acts like `fsck.<msg-id>`, but is used by + linkgit:git-fetch-pack[1] instead of linkgit:git-fsck[1]. See + the `fsck.<msg-id>` documentation for details. + +fetch.fsck.skipList:: + Acts like `fsck.skipList`, but is used by + linkgit:git-fetch-pack[1] instead of linkgit:git-fsck[1]. See + the `fsck.skipList` documentation for details. + +fetch.unpackLimit:: + If the number of objects fetched over the Git native + transfer is below this + limit, then the objects will be unpacked into loose object + files. However if the number of received objects equals or + exceeds this limit then the received pack will be stored as + a pack, after adding any missing delta bases. Storing the + pack from a push can make the push operation complete faster, + especially on slow filesystems. If not set, the value of + `transfer.unpackLimit` is used instead. + +fetch.prune:: + If true, fetch will automatically behave as if the `--prune` + option was given on the command line. See also `remote.<name>.prune` + and the PRUNING section of linkgit:git-fetch[1]. + +fetch.pruneTags:: + If true, fetch will automatically behave as if the + `refs/tags/*:refs/tags/*` refspec was provided when pruning, + if not set already. This allows for setting both this option + and `fetch.prune` to maintain a 1=1 mapping to upstream + refs. See also `remote.<name>.pruneTags` and the PRUNING + section of linkgit:git-fetch[1]. + +fetch.output:: + Control how ref update status is printed. Valid values are + `full` and `compact`. Default value is `full`. See section + OUTPUT in linkgit:git-fetch[1] for detail. + +fetch.negotiationAlgorithm:: + Control how information about the commits in the local repository is + sent when negotiating the contents of the packfile to be sent by the + server. Set to "skipping" to use an algorithm that skips commits in an + effort to converge faster, but may result in a larger-than-necessary + packfile; The default is "default" which instructs Git to use the default algorithm + that never skips commits (unless the server has acknowledged it or one + of its descendants). + Unknown values will cause 'git fetch' to error out. ++ +See also the `--negotiation-tip` option for linkgit:git-fetch[1]. diff --git a/Documentation/format-config.txt b/Documentation/format-config.txt new file mode 100644 index 0000000000..dc77941c48 --- /dev/null +++ b/Documentation/format-config.txt @@ -0,0 +1,87 @@ +format.attach:: + Enable multipart/mixed attachments as the default for + 'format-patch'. The value can also be a double quoted string + which will enable attachments as the default and set the + value as the boundary. See the --attach option in + linkgit:git-format-patch[1]. + +format.from:: + Provides the default value for the `--from` option to format-patch. + Accepts a boolean value, or a name and email address. If false, + format-patch defaults to `--no-from`, using commit authors directly in + the "From:" field of patch mails. If true, format-patch defaults to + `--from`, using your committer identity in the "From:" field of patch + mails and including a "From:" field in the body of the patch mail if + different. If set to a non-boolean value, format-patch uses that + value instead of your committer identity. Defaults to false. + +format.numbered:: + A boolean which can enable or disable sequence numbers in patch + subjects. It defaults to "auto" which enables it only if there + is more than one patch. It can be enabled or disabled for all + messages by setting it to "true" or "false". See --numbered + option in linkgit:git-format-patch[1]. + +format.headers:: + Additional email headers to include in a patch to be submitted + by mail. See linkgit:git-format-patch[1]. + +format.to:: +format.cc:: + Additional recipients to include in a patch to be submitted + by mail. See the --to and --cc options in + linkgit:git-format-patch[1]. + +format.subjectPrefix:: + The default for format-patch is to output files with the '[PATCH]' + subject prefix. Use this variable to change that prefix. + +format.signature:: + The default for format-patch is to output a signature containing + the Git version number. Use this variable to change that default. + Set this variable to the empty string ("") to suppress + signature generation. + +format.signatureFile:: + Works just like format.signature except the contents of the + file specified by this variable will be used as the signature. + +format.suffix:: + The default for format-patch is to output files with the suffix + `.patch`. Use this variable to change that suffix (make sure to + include the dot if you want it). + +format.pretty:: + The default pretty format for log/show/whatchanged command, + See linkgit:git-log[1], linkgit:git-show[1], + linkgit:git-whatchanged[1]. + +format.thread:: + The default threading style for 'git format-patch'. Can be + a boolean value, or `shallow` or `deep`. `shallow` threading + makes every mail a reply to the head of the series, + where the head is chosen from the cover letter, the + `--in-reply-to`, and the first patch mail, in this order. + `deep` threading makes every mail a reply to the previous one. + A true boolean value is the same as `shallow`, and a false + value disables threading. + +format.signOff:: + A boolean value which lets you enable the `-s/--signoff` option of + format-patch by default. *Note:* Adding the Signed-off-by: line to a + patch should be a conscious act and means that you certify you have + the rights to submit this work under the same open source license. + Please see the 'SubmittingPatches' document for further discussion. + +format.coverLetter:: + A boolean that controls whether to generate a cover-letter when + format-patch is invoked, but in addition can be set to "auto", to + generate a cover-letter only when there's more than one patch. + +format.outputDirectory:: + Set a custom directory to store the resulting files instead of the + current working directory. + +format.useAutoBase:: + A boolean value which lets you enable the `--base=auto` option of + format-patch by default. diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt index 8e240435be..5e87d82933 100644 --- a/Documentation/git-config.txt +++ b/Documentation/git-config.txt @@ -188,8 +188,8 @@ Valid `<type>`'s include: --bool-or-int:: --path:: --expiry-date:: - Historical options for selecting a type specifier. Prefer instead `--type`, - (see: above). + Historical options for selecting a type specifier. Prefer instead `--type` + (see above). --no-type:: Un-sets the previously set type specifier (if one was previously set). This @@ -442,9 +442,9 @@ For URLs in `https://weak.example.com`, `http.sslVerify` is set to false, while it is set to `true` for all others: ------------ -% git config --bool --get-urlmatch http.sslverify https://good.example.com +% git config --type=bool --get-urlmatch http.sslverify https://good.example.com true -% git config --bool --get-urlmatch http.sslverify https://weak.example.com +% git config --type=bool --get-urlmatch http.sslverify https://weak.example.com false % git config --get-urlmatch http https://weak.example.com http.cookieFile /tmp/cookie.txt diff --git a/Documentation/git-multi-pack-index.txt b/Documentation/git-multi-pack-index.txt index 1f97e79912..f7778a2c85 100644 --- a/Documentation/git-multi-pack-index.txt +++ b/Documentation/git-multi-pack-index.txt @@ -27,6 +27,10 @@ write:: When given as the verb, write a new MIDX file to `<dir>/packs/multi-pack-index`. +verify:: + When given as the verb, verify the contents of the MIDX file + at `<dir>/packs/multi-pack-index`. + EXAMPLES -------- @@ -43,6 +47,12 @@ $ git multi-pack-index write $ git multi-pack-index --object-dir <alt> write ----------------------------------------------- +* Verify the MIDX file for the packfiles in the current .git folder. ++ +----------------------------------------------- +$ git multi-pack-index verify +----------------------------------------------- + SEE ALSO -------- diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt index f345bd30fc..a5fc54aeab 100644 --- a/Documentation/git-push.txt +++ b/Documentation/git-push.txt @@ -110,7 +110,7 @@ can be overridden by adding an the optional leading `+` to a refspec is that no amount of forcing will make the `refs/heads/*` namespace accept a non-commit object. Hooks and configuration can also override or amend these rules, see e.g. `receive.denyNonFastForwards` in -linkgit:git-config[1] and`pre-receive` and `update` in +linkgit:git-config[1] and `pre-receive` and `update` in linkgit:githooks[5]. + Pushing an empty <src> allows you to delete the <dst> ref from the diff --git a/Documentation/git-update-ref.txt b/Documentation/git-update-ref.txt index bc8fdfd469..fda8516677 100644 --- a/Documentation/git-update-ref.txt +++ b/Documentation/git-update-ref.txt @@ -8,7 +8,7 @@ git-update-ref - Update the object name stored in a ref safely SYNOPSIS -------- [verse] -'git update-ref' [-m <reason>] (-d <ref> [<oldvalue>] | [--no-deref] [--create-reflog] <ref> <newvalue> [<oldvalue>] | --stdin [-z]) +'git update-ref' [-m <reason>] [--no-deref] (-d <ref> [<oldvalue>] | [--create-reflog] <ref> <newvalue> [<oldvalue>] | --stdin [-z]) DESCRIPTION ----------- diff --git a/Documentation/git.txt b/Documentation/git.txt index 74a9d7edb4..08e533d62b 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -76,7 +76,7 @@ Note that omitting the `=` in `git -c foo.bar ...` is allowed and sets `foo.bar` to the boolean true value (just like `[foo]bar` would in a config file). Including the equals but with an empty value (like `git -c foo.bar= ...`) sets `foo.bar` to the empty string which `git config ---bool` will convert to `false`. +--type=bool` will convert to `false`. --exec-path[=<path>]:: Path to wherever your core Git programs are installed. diff --git a/Documentation/gitcvs-config.txt b/Documentation/gitcvs-config.txt new file mode 100644 index 0000000000..02da427fd9 --- /dev/null +++ b/Documentation/gitcvs-config.txt @@ -0,0 +1,67 @@ +gitcvs.commitMsgAnnotation:: + Append this string to each commit message. Set to empty string + to disable this feature. Defaults to "via git-CVS emulator". + +gitcvs.enabled:: + Whether the CVS server interface is enabled for this repository. + See linkgit:git-cvsserver[1]. + +gitcvs.logFile:: + Path to a log file where the CVS server interface well... logs + various stuff. See linkgit:git-cvsserver[1]. + +gitcvs.usecrlfattr:: + If true, the server will look up the end-of-line conversion + attributes for files to determine the `-k` modes to use. If + the attributes force Git to treat a file as text, + the `-k` mode will be left blank so CVS clients will + treat it as text. If they suppress text conversion, the file + will be set with '-kb' mode, which suppresses any newline munging + the client might otherwise do. If the attributes do not allow + the file type to be determined, then `gitcvs.allBinary` is + used. See linkgit:gitattributes[5]. + +gitcvs.allBinary:: + This is used if `gitcvs.usecrlfattr` does not resolve + the correct '-kb' mode to use. If true, all + unresolved files are sent to the client in + mode '-kb'. This causes the client to treat them + as binary files, which suppresses any newline munging it + otherwise might do. Alternatively, if it is set to "guess", + then the contents of the file are examined to decide if + it is binary, similar to `core.autocrlf`. + +gitcvs.dbName:: + Database used by git-cvsserver to cache revision information + derived from the Git repository. The exact meaning depends on the + used database driver, for SQLite (which is the default driver) this + is a filename. Supports variable substitution (see + linkgit:git-cvsserver[1] for details). May not contain semicolons (`;`). + Default: '%Ggitcvs.%m.sqlite' + +gitcvs.dbDriver:: + Used Perl DBI driver. You can specify any available driver + for this here, but it might not work. git-cvsserver is tested + with 'DBD::SQLite', reported to work with 'DBD::Pg', and + reported *not* to work with 'DBD::mysql'. Experimental feature. + May not contain double colons (`:`). Default: 'SQLite'. + See linkgit:git-cvsserver[1]. + +gitcvs.dbUser, gitcvs.dbPass:: + Database user and password. Only useful if setting `gitcvs.dbDriver`, + since SQLite has no concept of database users and/or passwords. + 'gitcvs.dbUser' supports variable substitution (see + linkgit:git-cvsserver[1] for details). + +gitcvs.dbTableNamePrefix:: + Database table name prefix. Prepended to the names of any + database tables used, allowing a single database to be used + for several repositories. Supports variable substitution (see + linkgit:git-cvsserver[1] for details). Any non-alphabetic + characters will be replaced with underscores. + +All gitcvs variables except for `gitcvs.usecrlfattr` and +`gitcvs.allBinary` can also be specified as +'gitcvs.<access_method>.<varname>' (where 'access_method' +is one of "ext" and "pserver") to make them apply only for the given +access method. diff --git a/Documentation/gui-config.txt b/Documentation/gui-config.txt new file mode 100644 index 0000000000..d30831a130 --- /dev/null +++ b/Documentation/gui-config.txt @@ -0,0 +1,57 @@ +gui.commitMsgWidth:: + Defines how wide the commit message window is in the + linkgit:git-gui[1]. "75" is the default. + +gui.diffContext:: + Specifies how many context lines should be used in calls to diff + made by the linkgit:git-gui[1]. The default is "5". + +gui.displayUntracked:: + Determines if linkgit:git-gui[1] shows untracked files + in the file list. The default is "true". + +gui.encoding:: + Specifies the default encoding to use for displaying of + file contents in linkgit:git-gui[1] and linkgit:gitk[1]. + It can be overridden by setting the 'encoding' attribute + for relevant files (see linkgit:gitattributes[5]). + If this option is not set, the tools default to the + locale encoding. + +gui.matchTrackingBranch:: + Determines if new branches created with linkgit:git-gui[1] should + default to tracking remote branches with matching names or + not. Default: "false". + +gui.newBranchTemplate:: + Is used as suggested name when creating new branches using the + linkgit:git-gui[1]. + +gui.pruneDuringFetch:: + "true" if linkgit:git-gui[1] should prune remote-tracking branches when + performing a fetch. The default value is "false". + +gui.trustmtime:: + Determines if linkgit:git-gui[1] should trust the file modification + timestamp or not. By default the timestamps are not trusted. + +gui.spellingDictionary:: + Specifies the dictionary used for spell checking commit messages in + the linkgit:git-gui[1]. When set to "none" spell checking is turned + off. + +gui.fastCopyBlame:: + If true, 'git gui blame' uses `-C` instead of `-C -C` for original + location detection. It makes blame significantly faster on huge + repositories at the expense of less thorough copy detection. + +gui.copyBlameThreshold:: + Specifies the threshold to use in 'git gui blame' original location + detection, measured in alphanumeric characters. See the + linkgit:git-blame[1] manual for more information on copy detection. + +gui.blamehistoryctx:: + Specifies the radius of history context in days to show in + linkgit:gitk[1] for the selected commit, when the `Show History + Context` menu item is invoked from 'git gui blame'. If this + variable is set to zero, the whole history is shown. diff --git a/Documentation/pull-config.txt b/Documentation/pull-config.txt new file mode 100644 index 0000000000..bb23a9947d --- /dev/null +++ b/Documentation/pull-config.txt @@ -0,0 +1,36 @@ +pull.ff:: + By default, Git does not create an extra merge commit when merging + a commit that is a descendant of the current commit. Instead, the + tip of the current branch is fast-forwarded. When set to `false`, + this variable tells Git to create an extra merge commit in such + a case (equivalent to giving the `--no-ff` option from the command + line). When set to `only`, only such fast-forward merges are + allowed (equivalent to giving the `--ff-only` option from the + command line). This setting overrides `merge.ff` when pulling. + +pull.rebase:: + When true, rebase branches on top of the fetched branch, instead + of merging the default branch from the default remote when "git + pull" is run. See "branch.<name>.rebase" for setting this on a + per-branch basis. ++ +When `merges`, pass the `--rebase-merges` option to 'git rebase' +so that the local merge commits are included in the rebase (see +linkgit:git-rebase[1] for details). ++ +When preserve, also pass `--preserve-merges` along to 'git rebase' +so that locally committed merge commits will not be flattened +by running 'git pull'. ++ +When the value is `interactive`, the rebase is run in interactive mode. ++ +*NOTE*: this is a possibly dangerous operation; do *not* use +it unless you understand the implications (see linkgit:git-rebase[1] +for details). + +pull.octopus:: + The default merge strategy to use when pulling multiple branches + at once. + +pull.twohead:: + The default merge strategy to use when pulling a single branch. diff --git a/Documentation/pull-fetch-param.txt b/Documentation/pull-fetch-param.txt index 293c6b967d..7d3a60f5b9 100644 --- a/Documentation/pull-fetch-param.txt +++ b/Documentation/pull-fetch-param.txt @@ -45,9 +45,9 @@ rules particular to 'git fetch' are noted below. + Until Git version 2.20, and unlike when pushing with linkgit:git-push[1], any updates to `refs/tags/*` would be accepted -without `+` in the refspec (or `--force`). The receiving promiscuously +without `+` in the refspec (or `--force`). When fetching, we promiscuously considered all tag updates from a remote to be forced fetches. Since -Git version 2.20, fetching to update `refs/tags/*` work the same way +Git version 2.20, fetching to update `refs/tags/*` works the same way as when pushing. I.e. any updates will be rejected without `+` in the refspec (or `--force`). + diff --git a/Documentation/push-config.txt b/Documentation/push-config.txt new file mode 100644 index 0000000000..0a0e000569 --- /dev/null +++ b/Documentation/push-config.txt @@ -0,0 +1,113 @@ +push.default:: + Defines the action `git push` should take if no refspec is + explicitly given. Different values are well-suited for + specific workflows; for instance, in a purely central workflow + (i.e. the fetch source is equal to the push destination), + `upstream` is probably what you want. Possible values are: ++ +-- + +* `nothing` - do not push anything (error out) unless a refspec is + explicitly given. This is primarily meant for people who want to + avoid mistakes by always being explicit. + +* `current` - push the current branch to update a branch with the same + name on the receiving end. Works in both central and non-central + workflows. + +* `upstream` - push the current branch back to the branch whose + changes are usually integrated into the current branch (which is + called `@{upstream}`). This mode only makes sense if you are + pushing to the same repository you would normally pull from + (i.e. central workflow). + +* `tracking` - This is a deprecated synonym for `upstream`. + +* `simple` - in centralized workflow, work like `upstream` with an + added safety to refuse to push if the upstream branch's name is + different from the local one. ++ +When pushing to a remote that is different from the remote you normally +pull from, work as `current`. This is the safest option and is suited +for beginners. ++ +This mode has become the default in Git 2.0. + +* `matching` - push all branches having the same name on both ends. + This makes the repository you are pushing to remember the set of + branches that will be pushed out (e.g. if you always push 'maint' + and 'master' there and no other branches, the repository you push + to will have these two branches, and your local 'maint' and + 'master' will be pushed there). ++ +To use this mode effectively, you have to make sure _all_ the +branches you would push out are ready to be pushed out before +running 'git push', as the whole point of this mode is to allow you +to push all of the branches in one go. If you usually finish work +on only one branch and push out the result, while other branches are +unfinished, this mode is not for you. Also this mode is not +suitable for pushing into a shared central repository, as other +people may add new branches there, or update the tip of existing +branches outside your control. ++ +This used to be the default, but not since Git 2.0 (`simple` is the +new default). + +-- + +push.followTags:: + If set to true enable `--follow-tags` option by default. You + may override this configuration at time of push by specifying + `--no-follow-tags`. + +push.gpgSign:: + May be set to a boolean value, or the string 'if-asked'. A true + value causes all pushes to be GPG signed, as if `--signed` is + passed to linkgit:git-push[1]. The string 'if-asked' causes + pushes to be signed if the server supports it, as if + `--signed=if-asked` is passed to 'git push'. A false value may + override a value from a lower-priority config file. An explicit + command-line flag always overrides this config option. + +push.pushOption:: + When no `--push-option=<option>` argument is given from the + command line, `git push` behaves as if each <value> of + this variable is given as `--push-option=<value>`. ++ +This is a multi-valued variable, and an empty value can be used in a +higher priority configuration file (e.g. `.git/config` in a +repository) to clear the values inherited from a lower priority +configuration files (e.g. `$HOME/.gitconfig`). ++ +-- + +Example: + +/etc/gitconfig + push.pushoption = a + push.pushoption = b + +~/.gitconfig + push.pushoption = c + +repo/.git/config + push.pushoption = + push.pushoption = b + +This will result in only b (a and c are cleared). + +-- + +push.recurseSubmodules:: + Make sure all submodule commits used by the revisions to be pushed + are available on a remote-tracking branch. If the value is 'check' + then Git will verify that all submodule commits that changed in the + revisions to be pushed are available on at least one remote of the + submodule. If any commits are missing, the push will be aborted and + exit with non-zero status. If the value is 'on-demand' then all + submodules that changed in the revisions to be pushed will be + pushed. If on-demand was not able to push all necessary revisions + it will also be aborted and exit with non-zero status. If the value + is 'no' then default behavior of ignoring submodules when pushing + is retained. You may override this configuration at time of push by + specifying '--recurse-submodules=check|on-demand|no'. diff --git a/Documentation/receive-config.txt b/Documentation/receive-config.txt new file mode 100644 index 0000000000..65f78aac37 --- /dev/null +++ b/Documentation/receive-config.txt @@ -0,0 +1,123 @@ +receive.advertiseAtomic:: + By default, git-receive-pack will advertise the atomic push + capability to its clients. If you don't want to advertise this + capability, set this variable to false. + +receive.advertisePushOptions:: + When set to true, git-receive-pack will advertise the push options + capability to its clients. False by default. + +receive.autogc:: + By default, git-receive-pack will run "git-gc --auto" after + receiving data from git-push and updating refs. You can stop + it by setting this variable to false. + +receive.certNonceSeed:: + By setting this variable to a string, `git receive-pack` + will accept a `git push --signed` and verifies it by using + a "nonce" protected by HMAC using this string as a secret + key. + +receive.certNonceSlop:: + When a `git push --signed` sent a push certificate with a + "nonce" that was issued by a receive-pack serving the same + repository within this many seconds, export the "nonce" + found in the certificate to `GIT_PUSH_CERT_NONCE` to the + hooks (instead of what the receive-pack asked the sending + side to include). This may allow writing checks in + `pre-receive` and `post-receive` a bit easier. Instead of + checking `GIT_PUSH_CERT_NONCE_SLOP` environment variable + that records by how many seconds the nonce is stale to + decide if they want to accept the certificate, they only + can check `GIT_PUSH_CERT_NONCE_STATUS` is `OK`. + +receive.fsckObjects:: + If it is set to true, git-receive-pack will check all received + objects. See `transfer.fsckObjects` for what's checked. + Defaults to false. If not set, the value of + `transfer.fsckObjects` is used instead. + +receive.fsck.<msg-id>:: + Acts like `fsck.<msg-id>`, but is used by + linkgit:git-receive-pack[1] instead of + linkgit:git-fsck[1]. See the `fsck.<msg-id>` documentation for + details. + +receive.fsck.skipList:: + Acts like `fsck.skipList`, but is used by + linkgit:git-receive-pack[1] instead of + linkgit:git-fsck[1]. See the `fsck.skipList` documentation for + details. + +receive.keepAlive:: + After receiving the pack from the client, `receive-pack` may + produce no output (if `--quiet` was specified) while processing + the pack, causing some networks to drop the TCP connection. + With this option set, if `receive-pack` does not transmit + any data in this phase for `receive.keepAlive` seconds, it will + send a short keepalive packet. The default is 5 seconds; set + to 0 to disable keepalives entirely. + +receive.unpackLimit:: + If the number of objects received in a push is below this + limit then the objects will be unpacked into loose object + files. However if the number of received objects equals or + exceeds this limit then the received pack will be stored as + a pack, after adding any missing delta bases. Storing the + pack from a push can make the push operation complete faster, + especially on slow filesystems. If not set, the value of + `transfer.unpackLimit` is used instead. + +receive.maxInputSize:: + If the size of the incoming pack stream is larger than this + limit, then git-receive-pack will error out, instead of + accepting the pack file. If not set or set to 0, then the size + is unlimited. + +receive.denyDeletes:: + If set to true, git-receive-pack will deny a ref update that deletes + the ref. Use this to prevent such a ref deletion via a push. + +receive.denyDeleteCurrent:: + If set to true, git-receive-pack will deny a ref update that + deletes the currently checked out branch of a non-bare repository. + +receive.denyCurrentBranch:: + If set to true or "refuse", git-receive-pack will deny a ref update + to the currently checked out branch of a non-bare repository. + Such a push is potentially dangerous because it brings the HEAD + out of sync with the index and working tree. If set to "warn", + print a warning of such a push to stderr, but allow the push to + proceed. If set to false or "ignore", allow such pushes with no + message. Defaults to "refuse". ++ +Another option is "updateInstead" which will update the working +tree if pushing into the current branch. This option is +intended for synchronizing working directories when one side is not easily +accessible via interactive ssh (e.g. a live web site, hence the requirement +that the working directory be clean). This mode also comes in handy when +developing inside a VM to test and fix code on different Operating Systems. ++ +By default, "updateInstead" will refuse the push if the working tree or +the index have any difference from the HEAD, but the `push-to-checkout` +hook can be used to customize this. See linkgit:githooks[5]. + +receive.denyNonFastForwards:: + If set to true, git-receive-pack will deny a ref update which is + not a fast-forward. Use this to prevent such an update via a push, + even if that push is forced. This configuration variable is + set when initializing a shared repository. + +receive.hideRefs:: + This variable is the same as `transfer.hideRefs`, but applies + only to `receive-pack` (and so affects pushes, but not fetches). + An attempt to update or delete a hidden ref by `git push` is + rejected. + +receive.updateServerInfo:: + If set to true, git-receive-pack will run git-update-server-info + after receiving data from git-push and updating refs. + +receive.shallowUpdate:: + If set to true, .git/shallow can be updated when new refs + require new shallow roots. Otherwise those refs are rejected. diff --git a/Documentation/sendemail-config.txt b/Documentation/sendemail-config.txt new file mode 100644 index 0000000000..0006faf800 --- /dev/null +++ b/Documentation/sendemail-config.txt @@ -0,0 +1,63 @@ +sendemail.identity:: + A configuration identity. When given, causes values in the + 'sendemail.<identity>' subsection to take precedence over + values in the 'sendemail' section. The default identity is + the value of `sendemail.identity`. + +sendemail.smtpEncryption:: + See linkgit:git-send-email[1] for description. Note that this + setting is not subject to the 'identity' mechanism. + +sendemail.smtpssl (deprecated):: + Deprecated alias for 'sendemail.smtpEncryption = ssl'. + +sendemail.smtpsslcertpath:: + Path to ca-certificates (either a directory or a single file). + Set it to an empty string to disable certificate verification. + +sendemail.<identity>.*:: + Identity-specific versions of the 'sendemail.*' parameters + found below, taking precedence over those when this + identity is selected, through either the command-line or + `sendemail.identity`. + +sendemail.aliasesFile:: +sendemail.aliasFileType:: +sendemail.annotate:: +sendemail.bcc:: +sendemail.cc:: +sendemail.ccCmd:: +sendemail.chainReplyTo:: +sendemail.confirm:: +sendemail.envelopeSender:: +sendemail.from:: +sendemail.multiEdit:: +sendemail.signedoffbycc:: +sendemail.smtpPass:: +sendemail.suppresscc:: +sendemail.suppressFrom:: +sendemail.to:: +sendemail.tocmd:: +sendemail.smtpDomain:: +sendemail.smtpServer:: +sendemail.smtpServerPort:: +sendemail.smtpServerOption:: +sendemail.smtpUser:: +sendemail.thread:: +sendemail.transferEncoding:: +sendemail.validate:: +sendemail.xmailer:: + See linkgit:git-send-email[1] for description. + +sendemail.signedoffcc (deprecated):: + Deprecated alias for `sendemail.signedoffbycc`. + +sendemail.smtpBatchSize:: + Number of messages to be sent per connection, after that a relogin + will happen. If the value is 0 or undefined, send all messages in + one connection. + See also the `--batch-size` option of linkgit:git-send-email[1]. + +sendemail.smtpReloginDelay:: + Seconds wait before reconnecting to smtp server. + See also the `--relogin-delay` option of linkgit:git-send-email[1]. diff --git a/Documentation/submodule-config.txt b/Documentation/submodule-config.txt new file mode 100644 index 0000000000..0a1293b051 --- /dev/null +++ b/Documentation/submodule-config.txt @@ -0,0 +1,82 @@ +submodule.<name>.url:: + The URL for a submodule. This variable is copied from the .gitmodules + file to the git config via 'git submodule init'. The user can change + the configured URL before obtaining the submodule via 'git submodule + update'. If neither submodule.<name>.active or submodule.active are + set, the presence of this variable is used as a fallback to indicate + whether the submodule is of interest to git commands. + See linkgit:git-submodule[1] and linkgit:gitmodules[5] for details. + +submodule.<name>.update:: + The method by which a submodule is updated by 'git submodule update', + which is the only affected command, others such as + 'git checkout --recurse-submodules' are unaffected. It exists for + historical reasons, when 'git submodule' was the only command to + interact with submodules; settings like `submodule.active` + and `pull.rebase` are more specific. It is populated by + `git submodule init` from the linkgit:gitmodules[5] file. + See description of 'update' command in linkgit:git-submodule[1]. + +submodule.<name>.branch:: + The remote branch name for a submodule, used by `git submodule + update --remote`. Set this option to override the value found in + the `.gitmodules` file. See linkgit:git-submodule[1] and + linkgit:gitmodules[5] for details. + +submodule.<name>.fetchRecurseSubmodules:: + This option can be used to control recursive fetching of this + submodule. It can be overridden by using the --[no-]recurse-submodules + command-line option to "git fetch" and "git pull". + This setting will override that from in the linkgit:gitmodules[5] + file. + +submodule.<name>.ignore:: + Defines under what circumstances "git status" and the diff family show + a submodule as modified. When set to "all", it will never be considered + modified (but it will nonetheless show up in the output of status and + commit when it has been staged), "dirty" will ignore all changes + to the submodules work tree and + takes only differences between the HEAD of the submodule and the commit + recorded in the superproject into account. "untracked" will additionally + let submodules with modified tracked files in their work tree show up. + Using "none" (the default when this option is not set) also shows + submodules that have untracked files in their work tree as changed. + This setting overrides any setting made in .gitmodules for this submodule, + both settings can be overridden on the command line by using the + "--ignore-submodules" option. The 'git submodule' commands are not + affected by this setting. + +submodule.<name>.active:: + Boolean value indicating if the submodule is of interest to git + commands. This config option takes precedence over the + submodule.active config option. See linkgit:gitsubmodules[7] for + details. + +submodule.active:: + A repeated field which contains a pathspec used to match against a + submodule's path to determine if the submodule is of interest to git + commands. See linkgit:gitsubmodules[7] for details. + +submodule.recurse:: + Specifies if commands recurse into submodules by default. This + applies to all commands that have a `--recurse-submodules` option, + except `clone`. + Defaults to false. + +submodule.fetchJobs:: + Specifies how many submodules are fetched/cloned at the same time. + A positive integer allows up to that number of submodules fetched + in parallel. A value of 0 will give some reasonable default. + If unset, it defaults to 1. + +submodule.alternateLocation:: + Specifies how the submodules obtain alternates when submodules are + cloned. Possible values are `no`, `superproject`. + By default `no` is assumed, which doesn't add references. When the + value is set to `superproject` the submodule to be cloned computes + its alternates location relative to the superprojects alternate. + +submodule.alternateErrorStrategy:: + Specifies how to treat errors with the alternates for a submodule + as computed via `submodule.alternateLocation`. Possible values are + `ignore`, `info`, `die`. Default is `die`. diff --git a/Documentation/technical/commit-graph.txt b/Documentation/technical/commit-graph.txt index c664acbd76..001395e950 100644 --- a/Documentation/technical/commit-graph.txt +++ b/Documentation/technical/commit-graph.txt @@ -112,12 +112,24 @@ Design Details - The file format includes parameters for the object ID hash function, so a future change of hash algorithm does not require a change in format. +- Commit grafts and replace objects can change the shape of the commit + history. The latter can also be enabled/disabled on the fly using + `--no-replace-objects`. This leads to difficultly storing both possible + interpretations of a commit id, especially when computing generation + numbers. The commit-graph will not be read or written when + replace-objects or grafts are present. + +- Shallow clones create grafts of commits by dropping their parents. This + leads the commit-graph to think those commits have generation number 1. + If and when those commits are made unshallow, those generation numbers + become invalid. Since shallow clones are intended to restrict the commit + history to a very small set of commits, the commit-graph feature is less + helpful for these clones, anyway. The commit-graph will not be read or + written when shallow commits are present. + Future Work ----------- -- The commit graph feature currently does not honor commit grafts. This can - be remedied by duplicating or refactoring the current graft logic. - - After computing and storing generation numbers, we must make graph walks aware of generation numbers to gain the performance benefits they enable. This will mostly be accomplished by swapping a commit-date-ordered @@ -709,7 +709,9 @@ TEST_BUILTINS_OBJS += test-date.o TEST_BUILTINS_OBJS += test-delta.o TEST_BUILTINS_OBJS += test-drop-caches.o TEST_BUILTINS_OBJS += test-dump-cache-tree.o +TEST_BUILTINS_OBJS += test-dump-fsmonitor.o TEST_BUILTINS_OBJS += test-dump-split-index.o +TEST_BUILTINS_OBJS += test-dump-untracked-cache.o TEST_BUILTINS_OBJS += test-example-decorate.o TEST_BUILTINS_OBJS += test-genrandom.o TEST_BUILTINS_OBJS += test-hashmap.o @@ -720,7 +722,9 @@ TEST_BUILTINS_OBJS += test-match-trees.o TEST_BUILTINS_OBJS += test-mergesort.o TEST_BUILTINS_OBJS += test-mktemp.o TEST_BUILTINS_OBJS += test-online-cpus.o +TEST_BUILTINS_OBJS += test-parse-options.o TEST_BUILTINS_OBJS += test-path-utils.o +TEST_BUILTINS_OBJS += test-pkt-line.o TEST_BUILTINS_OBJS += test-prio-queue.o TEST_BUILTINS_OBJS += test-reach.o TEST_BUILTINS_OBJS += test-read-cache.o @@ -731,8 +735,8 @@ TEST_BUILTINS_OBJS += test-repository.o TEST_BUILTINS_OBJS += test-revision-walking.o TEST_BUILTINS_OBJS += test-run-command.o TEST_BUILTINS_OBJS += test-scrap-cache-tree.o -TEST_BUILTINS_OBJS += test-sha1-array.o TEST_BUILTINS_OBJS += test-sha1.o +TEST_BUILTINS_OBJS += test-sha1-array.o TEST_BUILTINS_OBJS += test-sigchain.o TEST_BUILTINS_OBJS += test-strcmp-offset.o TEST_BUILTINS_OBJS += test-string-list.o @@ -740,14 +744,13 @@ TEST_BUILTINS_OBJS += test-submodule-config.o TEST_BUILTINS_OBJS += test-subprocess.o TEST_BUILTINS_OBJS += test-urlmatch-normalization.o TEST_BUILTINS_OBJS += test-wildmatch.o +TEST_BUILTINS_OBJS += test-windows-named-pipe.o TEST_BUILTINS_OBJS += test-write-cache.o -TEST_PROGRAMS_NEED_X += test-dump-fsmonitor -TEST_PROGRAMS_NEED_X += test-dump-untracked-cache +# Do not add more tests here unless they have extra dependencies. Add +# them in TEST_BUILTINS_OBJS above. TEST_PROGRAMS_NEED_X += test-fake-ssh TEST_PROGRAMS_NEED_X += test-line-buffer -TEST_PROGRAMS_NEED_X += test-parse-options -TEST_PROGRAMS_NEED_X += test-pkt-line TEST_PROGRAMS_NEED_X += test-svn-fe TEST_PROGRAMS_NEED_X += test-tool diff --git a/RelNotes b/RelNotes index 46e159c68d..8d0b1654d2 100644..120000 --- a/RelNotes +++ b/RelNotes @@ -1,112 +1 @@ -Git Release Notes -================= - -Backward Compatibility Notes ----------------------------- - - * "git branch -l <foo>" used to be a way to ask a reflog to be - created while creating a new branch, but that is no longer the - case. It is a short-hand for "git branch --list <foo>" now. - - * "git push" into refs/tags/* hierarchy is rejected without getting - forced, but "git fetch" (misguidedly) used the "fast forwarding" - rule used for the refs/heads/* hierarchy; this has been corrected, - which means some fetches of tags that did not fail with older - version of Git will fail without "--force" with this version. - - -Updates since v2.19 -------------------- - -UI, Workflows & Features - - * Running "git clone" against a project that contain two files with - pathnames that differ only in cases on a case insensitive - filesystem would result in one of the files lost because the - underlying filesystem is incapable of holding both at the same - time. An attempt is made to detect such a case and warn. - - * "git checkout -b newbranch [HEAD]" should not have to do as much as - checking out a commit different from HEAD. An attempt is made to - optimize this special case. - - * "git rev-list --stdin </dev/null" used to be an error; it now shows - no output without an error. "git rev-list --stdin --default HEAD" - still falls back to the given default when nothing is given on the - standard input. - - * Lift code from GitHub to restrict delta computation so that an - object that exists in one fork is not made into a delta against - another object that does not appear in the same forked repository. - - * "git format-patch" learned new "--interdiff" and "--range-diff" - options to explain the difference between this version and the - previous attempt in the cover letter (or after the tree-dashes as - a comment). - - * "git mailinfo" used in "git am" learned to make a best-effort - recovery of a patch corrupted by MUA that sends text/plain with - format=flawed option. - (merge 3aa4d81f88 rs/mailinfo-format-flowed later to maint). - - * The rules used by "git push" and "git fetch" to determine if a ref - can or cannot be updated were inconsistent; specifically, fetching - to update existing tags were allowed even though tags are supposed - to be unmoving anchoring points. "git fetch" was taught to forbid - updates to existing tags without the "--force" option. - - -Performance, Internal Implementation, Development Support etc. - - * When there are too many packfiles in a repository (which is not - recommended), looking up an object in these would require - consulting many pack .idx files; a new mechanism to have a single - file that consolidates all of these .idx files is introduced. - - * "git submodule update" is getting rewritten piece-by-piece into C. - - * The code for computing history reachability has been shuffled, - obtained a bunch of new tests to cover them, and then being - improved. - - * The unpack_trees() API used in checking out a branch and merging - walks one or more trees along with the index. When the cache-tree - in the index tells us that we are walking a tree whose flattened - contents is known (i.e. matches a span in the index), as linearly - scanning a span in the index is much more efficient than having to - open tree objects recursively and listing their entries, the walk - can be optimized, which has been done. - - * When creating a thin pack, which allows objects to be made into a - delta against another object that is not in the resulting pack but - is known to be present on the receiving end, the code learned to - take advantage of the reachability bitmap; this allows the server - to send a delta against a base beyond the "boundary" commit. - - * spatch transformation to replace boolean uses of !hashcmp() to - newly introduced oideq() is added, and applied, to regain - performance lost due to support of multiple hash algorithms. - - * Fix a bug in which the same path could be registered under multiple - worktree entries if the path was missing (for instance, was removed - manually). Also, as a convenience, expand the number of cases in - which --force is applicable. - - -Fixes since v2.19 ------------------ - - * "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. - (merge 66e83d9b41 jk/trailer-fixes later to maint). - - * Malformed or crafted data in packstream can make our code attempt - to read or write past the allocated buffer and abort, instead of - reporting an error, which has been fixed. - - * 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). - (merge fa0aeea770 sg/doc-trace-appends later to maint). +Documentation/RelNotes/2.20.0.txt
\ No newline at end of file @@ -110,7 +110,8 @@ static const struct attr_check *get_archive_attrs(struct index_state *istate, static struct attr_check *check; if (!check) check = attr_check_initl("export-ignore", "export-subst", NULL); - return git_check_attr(istate, path, check) ? NULL : check; + git_check_attr(istate, path, check); + return check; } static int check_attr_export_ignore(const struct attr_check *check) @@ -1143,9 +1143,9 @@ static void collect_some_attrs(const struct index_state *istate, fill(path, pathlen, basename_offset, check->stack, check->all_attrs, rem); } -int git_check_attr(const struct index_state *istate, - const char *path, - struct attr_check *check) +void git_check_attr(const struct index_state *istate, + const char *path, + struct attr_check *check) { int i; @@ -1158,8 +1158,6 @@ int git_check_attr(const struct index_state *istate, value = ATTR__UNSET; check->items[i].value = value; } - - return 0; } void git_all_attrs(const struct index_state *istate, @@ -63,8 +63,8 @@ void attr_check_free(struct attr_check *check); */ const char *git_attr_name(const struct git_attr *); -int git_check_attr(const struct index_state *istate, - const char *path, struct attr_check *check); +void git_check_attr(const struct index_state *istate, + const char *path, struct attr_check *check); /* * Retrieve all attributes that apply to the specified path. diff --git a/builtin/add.c b/builtin/add.c index 9916498a29..0b64bcdebe 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -454,7 +454,7 @@ int cmd_add(int argc, const char **argv, const char *prefix) * Check the "pathspec '%s' did not match any files" block * below before enabling new magic. */ - parse_pathspec(&pathspec, 0, + parse_pathspec(&pathspec, PATHSPEC_ATTR, PATHSPEC_PREFER_FULL | PATHSPEC_SYMLINK_LEADING_PATH, prefix, argv); diff --git a/builtin/check-attr.c b/builtin/check-attr.c index c05573ff9c..30a2f84274 100644 --- a/builtin/check-attr.c +++ b/builtin/check-attr.c @@ -65,8 +65,7 @@ static void check_attr(const char *prefix, if (collect_all) { git_all_attrs(&the_index, full_path, check); } else { - if (git_check_attr(&the_index, full_path, check)) - die("git_check_attr died"); + git_check_attr(&the_index, full_path, check); } output_attr(check, file); diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c index 0bf0c48657..22b974f4b4 100644 --- a/builtin/commit-graph.c +++ b/builtin/commit-graph.c @@ -120,6 +120,8 @@ static int graph_read(int argc, const char **argv) return 0; } +extern int read_replace_refs; + static int graph_write(int argc, const char **argv) { struct string_list *pack_indexes = NULL; @@ -150,8 +152,10 @@ static int graph_write(int argc, const char **argv) if (!opts.obj_dir) opts.obj_dir = get_object_directory(); + read_replace_refs = 0; + if (opts.reachable) { - write_commit_graph_reachable(opts.obj_dir, opts.append); + write_commit_graph_reachable(opts.obj_dir, opts.append, 1); return 0; } @@ -171,7 +175,8 @@ static int graph_write(int argc, const char **argv) write_commit_graph(opts.obj_dir, pack_indexes, commit_hex, - opts.append); + opts.append, + 1); string_list_clear(&lines, 0); return 0; diff --git a/builtin/commit.c b/builtin/commit.c index b57d8e4b82..3f33ae6043 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -1654,7 +1654,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) "not exceeded, and then \"git reset HEAD\" to recover.")); if (git_env_bool(GIT_TEST_COMMIT_GRAPH, 0)) - write_commit_graph_reachable(get_object_directory(), 0); + write_commit_graph_reachable(get_object_directory(), 0, 0); rerere(0); run_command_v_opt(argv_gc_auto, RUN_GIT_CMD); diff --git a/builtin/fsck.c b/builtin/fsck.c index 63c8578cc1..06eb421720 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -848,5 +848,23 @@ int cmd_fsck(int argc, const char **argv, const char *prefix) } } + if (!git_config_get_bool("core.multipackindex", &i) && i) { + struct child_process midx_verify = CHILD_PROCESS_INIT; + const char *midx_argv[] = { "multi-pack-index", "verify", NULL, NULL, NULL }; + + midx_verify.argv = midx_argv; + midx_verify.git_cmd = 1; + if (run_command(&midx_verify)) + errors_found |= ERROR_COMMIT_GRAPH; + + prepare_alt_odb(the_repository); + for (alt = the_repository->objects->alt_odb_list; alt; alt = alt->next) { + midx_argv[2] = "--object-dir"; + midx_argv[3] = alt->path; + if (run_command(&midx_verify)) + errors_found |= ERROR_COMMIT_GRAPH; + } + } + return errors_found; } diff --git a/builtin/gc.c b/builtin/gc.c index 2b592260e9..6591ddbe83 100644 --- a/builtin/gc.c +++ b/builtin/gc.c @@ -646,7 +646,8 @@ int cmd_gc(int argc, const char **argv, const char *prefix) clean_pack_garbage(); if (gc_write_commit_graph) - write_commit_graph_reachable(get_object_directory(), 0); + write_commit_graph_reachable(get_object_directory(), 0, + !quiet && !daemonized); if (auto_gc && too_many_loose_objects()) warning(_("There are too many unreachable loose objects; " diff --git a/builtin/multi-pack-index.c b/builtin/multi-pack-index.c index 2633efd95d..fca70f8e4f 100644 --- a/builtin/multi-pack-index.c +++ b/builtin/multi-pack-index.c @@ -5,7 +5,7 @@ #include "midx.h" static char const * const builtin_multi_pack_index_usage[] = { - N_("git multi-pack-index [--object-dir=<dir>] write"), + N_("git multi-pack-index [--object-dir=<dir>] (write|verify)"), NULL }; @@ -42,6 +42,8 @@ int cmd_multi_pack_index(int argc, const char **argv, if (!strcmp(argv[0], "write")) return write_midx_file(opts.object_dir); + if (!strcmp(argv[0], "verify")) + return verify_midx_file(opts.object_dir); die(_("unrecognized verb: %s"), argv[0]); } diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 5041818ddf..c6370f2716 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -970,8 +970,7 @@ static int no_try_delta(const char *path) if (!check) check = attr_check_initl("delta", NULL); - if (git_check_attr(&the_index, path, check)) - return 0; + git_check_attr(&the_index, path, check); if (ATTR_FALSE(check->items[0].value)) return 1; return 0; @@ -1470,6 +1469,57 @@ static void cleanup_preferred_base(void) done_pbase_paths_num = done_pbase_paths_alloc = 0; } +/* + * Return 1 iff the object specified by "delta" can be sent + * literally as a delta against the base in "base_sha1". If + * so, then *base_out will point to the entry in our packing + * list, or NULL if we must use the external-base list. + * + * Depth value does not matter - find_deltas() will + * never consider reused delta as the base object to + * deltify other objects against, in order to avoid + * circular deltas. + */ +static int can_reuse_delta(const unsigned char *base_sha1, + struct object_entry *delta, + struct object_entry **base_out) +{ + struct object_entry *base; + + if (!base_sha1) + return 0; + + /* + * First see if we're already sending the base (or it's explicitly in + * our "excluded" list). + */ + base = packlist_find(&to_pack, base_sha1, NULL); + if (base) { + if (!in_same_island(&delta->idx.oid, &base->idx.oid)) + return 0; + *base_out = base; + return 1; + } + + /* + * Otherwise, reachability bitmaps may tell us if the receiver has it, + * even if it was buried too deep in history to make it into the + * packing list. + */ + if (thin && bitmap_has_sha1_in_uninteresting(bitmap_git, base_sha1)) { + if (use_delta_islands) { + struct object_id base_oid; + hashcpy(base_oid.hash, base_sha1); + if (!in_same_island(&delta->idx.oid, &base_oid)) + return 0; + } + *base_out = NULL; + return 1; + } + + return 0; +} + static void check_object(struct object_entry *entry) { unsigned long canonical_size; @@ -1556,22 +1606,7 @@ static void check_object(struct object_entry *entry) break; } - if (base_ref && ( - (base_entry = packlist_find(&to_pack, base_ref, NULL)) || - (thin && - bitmap_has_sha1_in_uninteresting(bitmap_git, base_ref))) && - in_same_island(&entry->idx.oid, &base_entry->idx.oid)) { - /* - * If base_ref was set above that means we wish to - * reuse delta data, and either we found that object in - * the list of objects we want to pack, or it's one we - * know the receiver has. - * - * Depth value does not matter - find_deltas() will - * never consider reused delta as the base object to - * deltify other objects against, in order to avoid - * circular deltas. - */ + if (can_reuse_delta(base_ref, entry, &base_entry)) { oe_set_type(entry, entry->in_pack_type); SET_SIZE(entry, in_pack_size); /* delta size */ SET_DELTA_SIZE(entry, in_pack_size); diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index a3bb13af10..4d30001950 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -466,7 +466,7 @@ static char *prepare_push_cert_nonce(const char *path, timestamp_t stamp) unsigned char sha1[GIT_SHA1_RAWSZ]; strbuf_addf(&buf, "%s:%"PRItime, path, stamp); - hmac_sha1(sha1, buf.buf, buf.len, cert_nonce_seed, strlen(cert_nonce_seed));; + hmac_sha1(sha1, buf.buf, buf.len, cert_nonce_seed, strlen(cert_nonce_seed)); strbuf_release(&buf); /* RFC 2104 5. HMAC-SHA1-80 */ diff --git a/builtin/remote.c b/builtin/remote.c index 40c6f8a1bd..f7edf7f2cb 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -626,7 +626,7 @@ static int mv(int argc, const char **argv) oldremote = remote_get(rename.old_name); if (!remote_is_configured(oldremote, 1)) - die(_("No such remote: %s"), rename.old_name); + die(_("No such remote: '%s'"), rename.old_name); if (!strcmp(rename.old_name, rename.new_name) && oldremote->origin != REMOTE_CONFIG) return migrate_file(oldremote); @@ -762,7 +762,7 @@ static int rm(int argc, const char **argv) remote = remote_get(argv[1]); if (!remote_is_configured(remote, 1)) - die(_("No such remote: %s"), argv[1]); + die(_("No such remote: '%s'"), argv[1]); known_remotes.to_delete = remote; for_each_remote(add_known_remote, &known_remotes); @@ -861,7 +861,7 @@ static int get_remote_ref_states(const char *name, states->remote = remote_get(name); if (!states->remote) - return error(_("No such remote: %s"), name); + return error(_("No such remote: '%s'"), name); read_branches(); diff --git a/builtin/replace.c b/builtin/replace.c index 8e67e09819..30a661ea0c 100644 --- a/builtin/replace.c +++ b/builtin/replace.c @@ -39,7 +39,8 @@ struct show_data { enum replace_format format; }; -static int show_reference(const char *refname, const struct object_id *oid, +static int show_reference(struct repository *r, const char *refname, + const struct object_id *oid, int flag, void *cb_data) { struct show_data *data = cb_data; @@ -56,9 +57,8 @@ static int show_reference(const char *refname, const struct object_id *oid, if (get_oid(refname, &object)) return error(_("failed to resolve '%s' as a valid ref"), refname); - obj_type = oid_object_info(the_repository, &object, - NULL); - repl_type = oid_object_info(the_repository, oid, NULL); + obj_type = oid_object_info(r, &object, NULL); + repl_type = oid_object_info(r, oid, NULL); printf("%s (%s) -> %s (%s)\n", refname, type_name(obj_type), oid_to_hex(oid), type_name(repl_type)); diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index 40844870cf..247881189f 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -1233,6 +1233,7 @@ static int clone_submodule(const char *path, const char *gitdir, const char *url if (gitdir && *gitdir) argv_array_pushl(&cp.args, "--separate-git-dir", gitdir, NULL); + argv_array_push(&cp.args, "--"); argv_array_push(&cp.args, url); argv_array_push(&cp.args, path); diff --git a/builtin/update-ref.c b/builtin/update-ref.c index 4fa3c0a86f..2d8f7f0578 100644 --- a/builtin/update-ref.c +++ b/builtin/update-ref.c @@ -14,7 +14,8 @@ static const char * const git_update_ref_usage[] = { }; static char line_termination = '\n'; -static int update_flags; +static unsigned int update_flags; +static unsigned int default_flags; static unsigned create_reflog_flag; static const char *msg; @@ -205,7 +206,7 @@ static const char *parse_cmd_update(struct ref_transaction *transaction, msg, &err)) die("%s", err.buf); - update_flags = 0; + update_flags = default_flags; free(refname); strbuf_release(&err); @@ -237,7 +238,7 @@ static const char *parse_cmd_create(struct ref_transaction *transaction, msg, &err)) die("%s", err.buf); - update_flags = 0; + update_flags = default_flags; free(refname); strbuf_release(&err); @@ -273,7 +274,7 @@ static const char *parse_cmd_delete(struct ref_transaction *transaction, update_flags, msg, &err)) die("%s", err.buf); - update_flags = 0; + update_flags = default_flags; free(refname); strbuf_release(&err); @@ -302,7 +303,7 @@ static const char *parse_cmd_verify(struct ref_transaction *transaction, update_flags, &err)) die("%s", err.buf); - update_flags = 0; + update_flags = default_flags; free(refname); strbuf_release(&err); @@ -357,7 +358,6 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix) const char *refname, *oldval; struct object_id oid, oldoid; int delete = 0, no_deref = 0, read_stdin = 0, end_null = 0; - unsigned int flags = 0; int create_reflog = 0; struct option options[] = { OPT_STRING( 'm', NULL, &msg, N_("reason"), N_("reason of the update")), @@ -378,6 +378,11 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix) create_reflog_flag = create_reflog ? REF_FORCE_CREATE_REFLOG : 0; + if (no_deref) { + default_flags = REF_NO_DEREF; + update_flags = default_flags; + } + if (read_stdin) { struct strbuf err = STRBUF_INIT; struct ref_transaction *transaction; @@ -385,7 +390,7 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix) transaction = ref_transaction_begin(&err); if (!transaction) die("%s", err.buf); - if (delete || no_deref || argc > 0) + if (delete || argc > 0) usage_with_options(git_update_ref_usage, options); if (end_null) line_termination = '\0'; @@ -427,8 +432,6 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix) die("%s: not a valid old SHA1", oldval); } - if (no_deref) - flags = REF_NO_DEREF; if (delete) /* * For purposes of backwards compatibility, we treat @@ -436,9 +439,9 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix) */ return delete_ref(msg, refname, (oldval && !is_null_oid(&oldoid)) ? &oldoid : NULL, - flags); + default_flags); else return update_ref(msg, refname, &oid, oldval ? &oldoid : NULL, - flags | create_reflog_flag, + default_flags | create_reflog_flag, UPDATE_REFS_DIE_ON_ERR); } diff --git a/commit-graph.c b/commit-graph.c index 7f4519ec3b..a686758603 100644 --- a/commit-graph.c +++ b/commit-graph.c @@ -13,6 +13,9 @@ #include "commit-graph.h" #include "object-store.h" #include "alloc.h" +#include "hashmap.h" +#include "replace-object.h" +#include "progress.h" #define GRAPH_SIGNATURE 0x43475048 /* "CGPH" */ #define GRAPH_CHUNKID_OIDFANOUT 0x4f494446 /* "OIDF" */ @@ -56,6 +59,28 @@ static struct commit_graph *alloc_commit_graph(void) return g; } +extern int read_replace_refs; + +static int commit_graph_compatible(struct repository *r) +{ + if (!r->gitdir) + return 0; + + if (read_replace_refs) { + prepare_replace_object(r); + if (hashmap_get_size(&r->objects->replace_map->map)) + return 0; + } + + prepare_commit_graft(r); + if (r->parsed_objects && r->parsed_objects->grafts_nr) + return 0; + if (is_repository_shallow(r)) + return 0; + + return 1; +} + struct commit_graph *load_commit_graph_one(const char *graph_file) { void *graph_map; @@ -224,6 +249,9 @@ static int prepare_commit_graph(struct repository *r) */ return 0; + if (!commit_graph_compatible(r)) + return 0; + obj_dir = r->objects->objectdir; prepare_commit_graph_one(r, obj_dir); prepare_alt_odb(r); @@ -252,10 +280,10 @@ int generation_numbers_enabled(struct repository *r) return !!first_generation; } -static void close_commit_graph(void) +void close_commit_graph(struct repository *r) { - free_commit_graph(the_repository->objects->commit_graph); - the_repository->objects->commit_graph = NULL; + free_commit_graph(r->objects->commit_graph); + r->objects->commit_graph = NULL; } static int bsearch_graph(struct commit_graph *g, struct object_id *oid, uint32_t *pos) @@ -567,6 +595,8 @@ struct packed_oid_list { struct object_id *list; int nr; int alloc; + struct progress *progress; + int progress_done; }; static int add_packed_commits(const struct object_id *oid, @@ -579,6 +609,9 @@ static int add_packed_commits(const struct object_id *oid, off_t offset = nth_packed_object_offset(pack, pos); struct object_info oi = OBJECT_INFO_INIT; + if (list->progress) + display_progress(list->progress, ++list->progress_done); + oi.typep = &type; if (packed_object_info(the_repository, pack, offset, &oi) < 0) die(_("unable to get type of object %s"), oid_to_hex(oid)); @@ -606,12 +639,18 @@ static void add_missing_parents(struct packed_oid_list *oids, struct commit *com } } -static void close_reachable(struct packed_oid_list *oids) +static void close_reachable(struct packed_oid_list *oids, int report_progress) { int i; struct commit *commit; + struct progress *progress = NULL; + int j = 0; + if (report_progress) + progress = start_delayed_progress( + _("Annotating commits in commit graph"), 0); for (i = 0; i < oids->nr; i++) { + display_progress(progress, ++j); commit = lookup_commit(the_repository, &oids->list[i]); if (commit) commit->object.flags |= UNINTERESTING; @@ -623,6 +662,7 @@ static void close_reachable(struct packed_oid_list *oids) * closure. */ for (i = 0; i < oids->nr; i++) { + display_progress(progress, ++j); commit = lookup_commit(the_repository, &oids->list[i]); if (commit && !parse_commit(commit)) @@ -630,19 +670,28 @@ static void close_reachable(struct packed_oid_list *oids) } for (i = 0; i < oids->nr; i++) { + display_progress(progress, ++j); commit = lookup_commit(the_repository, &oids->list[i]); if (commit) commit->object.flags &= ~UNINTERESTING; } + stop_progress(&progress); } -static void compute_generation_numbers(struct packed_commit_list* commits) +static void compute_generation_numbers(struct packed_commit_list* commits, + int report_progress) { int i; struct commit_list *list = NULL; + struct progress *progress = NULL; + if (report_progress) + progress = start_progress( + _("Computing commit graph generation numbers"), + commits->nr); for (i = 0; i < commits->nr; i++) { + display_progress(progress, i + 1); if (commits->list[i]->generation != GENERATION_NUMBER_INFINITY && commits->list[i]->generation != GENERATION_NUMBER_ZERO) continue; @@ -674,6 +723,7 @@ static void compute_generation_numbers(struct packed_commit_list* commits) } } } + stop_progress(&progress); } static int add_ref_to_list(const char *refname, @@ -686,19 +736,20 @@ static int add_ref_to_list(const char *refname, return 0; } -void write_commit_graph_reachable(const char *obj_dir, int append) +void write_commit_graph_reachable(const char *obj_dir, int append, + int report_progress) { struct string_list list; string_list_init(&list, 1); for_each_ref(add_ref_to_list, &list); - write_commit_graph(obj_dir, NULL, &list, append); + write_commit_graph(obj_dir, NULL, &list, append, report_progress); } void write_commit_graph(const char *obj_dir, struct string_list *pack_indexes, struct string_list *commit_hex, - int append) + int append, int report_progress) { struct packed_oid_list oids; struct packed_commit_list commits; @@ -711,9 +762,15 @@ void write_commit_graph(const char *obj_dir, int num_chunks; int num_extra_edges; struct commit_list *parent; + struct progress *progress = NULL; + + if (!commit_graph_compatible(the_repository)) + return; oids.nr = 0; oids.alloc = approximate_object_count() / 4; + oids.progress = NULL; + oids.progress_done = 0; if (append) { prepare_commit_graph_one(the_repository, obj_dir); @@ -740,6 +797,11 @@ void write_commit_graph(const char *obj_dir, int dirlen; strbuf_addf(&packname, "%s/pack/", obj_dir); dirlen = packname.len; + if (report_progress) { + oids.progress = start_delayed_progress( + _("Finding commits for commit graph"), 0); + oids.progress_done = 0; + } for (i = 0; i < pack_indexes->nr; i++) { struct packed_git *p; strbuf_setlen(&packname, dirlen); @@ -752,15 +814,21 @@ void write_commit_graph(const char *obj_dir, for_each_object_in_pack(p, add_packed_commits, &oids, 0); close_pack(p); } + stop_progress(&oids.progress); strbuf_release(&packname); } if (commit_hex) { + if (report_progress) + progress = start_delayed_progress( + _("Finding commits for commit graph"), + commit_hex->nr); for (i = 0; i < commit_hex->nr; i++) { const char *end; struct object_id oid; struct commit *result; + display_progress(progress, i + 1); if (commit_hex->items[i].string && parse_oid_hex(commit_hex->items[i].string, &oid, &end)) continue; @@ -773,12 +841,18 @@ void write_commit_graph(const char *obj_dir, oids.nr++; } } + stop_progress(&progress); } - if (!pack_indexes && !commit_hex) + if (!pack_indexes && !commit_hex) { + if (report_progress) + oids.progress = start_delayed_progress( + _("Finding commits for commit graph"), 0); for_each_packed_object(add_packed_commits, &oids, 0); + stop_progress(&oids.progress); + } - close_reachable(&oids); + close_reachable(&oids, report_progress); QSORT(oids.list, oids.nr, commit_compare); @@ -818,7 +892,7 @@ void write_commit_graph(const char *obj_dir, if (commits.nr >= GRAPH_PARENT_MISSING) die(_("too many commits to write graph")); - compute_generation_numbers(&commits); + compute_generation_numbers(&commits, report_progress); graph_name = get_commit_graph_filename(obj_dir); if (safe_create_leading_directories(graph_name)) @@ -864,7 +938,7 @@ void write_commit_graph(const char *obj_dir, write_graph_chunk_data(f, GRAPH_OID_LEN, commits.list, commits.nr); write_graph_chunk_large_edges(f, commits.list, commits.nr); - close_commit_graph(); + close_commit_graph(the_repository); finalize_hashfile(f, NULL, CSUM_HASH_IN_STREAM | CSUM_FSYNC); commit_lock_file(&lk); @@ -897,6 +971,7 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g) int generation_zero = 0; struct hashfile *f; int devnull; + struct progress *progress = NULL; if (!g) { graph_report("no commit-graph file loaded"); @@ -964,11 +1039,14 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g) if (verify_commit_graph_error & ~VERIFY_COMMIT_GRAPH_ERROR_HASH) return verify_commit_graph_error; + progress = start_progress(_("Verifying commits in commit graph"), + g->num_commits); for (i = 0; i < g->num_commits; i++) { struct commit *graph_commit, *odb_commit; struct commit_list *graph_parents, *odb_parents; uint32_t max_generation = 0; + display_progress(progress, i + 1); hashcpy(cur_oid.hash, g->chunk_oid_lookup + g->hash_len * i); graph_commit = lookup_commit(r, &cur_oid); @@ -1045,6 +1123,7 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g) graph_commit->date, odb_commit->date); } + stop_progress(&progress); return verify_commit_graph_error; } diff --git a/commit-graph.h b/commit-graph.h index b050476765..9db40b4d3a 100644 --- a/commit-graph.h +++ b/commit-graph.h @@ -60,14 +60,16 @@ struct commit_graph *load_commit_graph_one(const char *graph_file); */ int generation_numbers_enabled(struct repository *r); -void write_commit_graph_reachable(const char *obj_dir, int append); +void write_commit_graph_reachable(const char *obj_dir, int append, + int report_progress); void write_commit_graph(const char *obj_dir, struct string_list *pack_indexes, struct string_list *commit_hex, - int append); + int append, int report_progress); int verify_commit_graph(struct repository *r, struct commit_graph *g); +void close_commit_graph(struct repository *); void free_commit_graph(struct commit_graph *); #endif diff --git a/commit-reach.c b/commit-reach.c index 622eeb313d..00e5ceee6f 100644 --- a/commit-reach.c +++ b/commit-reach.c @@ -547,20 +547,42 @@ int can_all_from_reach_with_flag(struct object_array *from, { struct commit **list = NULL; int i; + int nr_commits; int result = 1; ALLOC_ARRAY(list, from->nr); + nr_commits = 0; for (i = 0; i < from->nr; i++) { - list[i] = (struct commit *)from->objects[i].item; + struct object *from_one = from->objects[i].item; - if (parse_commit(list[i]) || - list[i]->generation < min_generation) - return 0; + if (!from_one || from_one->flags & assign_flag) + continue; + + from_one = deref_tag(the_repository, from_one, + "a from object", 0); + if (!from_one || from_one->type != OBJ_COMMIT) { + /* no way to tell if this is reachable by + * looking at the ancestry chain alone, so + * leave a note to ourselves not to worry about + * this object anymore. + */ + from->objects[i].item->flags |= assign_flag; + continue; + } + + list[nr_commits] = (struct commit *)from_one; + if (parse_commit(list[nr_commits]) || + list[nr_commits]->generation < min_generation) { + result = 0; + goto cleanup; + } + + nr_commits++; } - QSORT(list, from->nr, compare_commits_by_gen); + QSORT(list, nr_commits, compare_commits_by_gen); - for (i = 0; i < from->nr; i++) { + for (i = 0; i < nr_commits; i++) { /* DFS from list[i] */ struct commit_list *stack = NULL; @@ -603,10 +625,15 @@ int can_all_from_reach_with_flag(struct object_array *from, } cleanup: - for (i = 0; i < from->nr; i++) { + for (i = 0; i < nr_commits; i++) { clear_commit_marks(list[i], RESULT); clear_commit_marks(list[i], assign_flag); } + free(list); + + for (i = 0; i < from->nr; i++) + from->objects[i].item->flags &= ~assign_flag; + return result; } @@ -209,7 +209,7 @@ static int read_graft_file(struct repository *r, const char *graft_file) return 0; } -static void prepare_commit_graft(struct repository *r) +void prepare_commit_graft(struct repository *r) { char *graft_file; @@ -202,6 +202,7 @@ typedef int (*each_commit_graft_fn)(const struct commit_graft *, void *); struct commit_graft *read_graft_line(struct strbuf *line); int register_commit_graft(struct repository *r, struct commit_graft *, int); +void prepare_commit_graft(struct repository *r); struct commit_graft *lookup_commit_graft(struct repository *r, const struct object_id *oid); /* largest positive number a signed 32-bit integer can contain */ diff --git a/compat/mingw.c b/compat/mingw.c index 858ca14a57..18caf21969 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -341,6 +341,19 @@ int mingw_mkdir(const char *path, int mode) return ret; } +/* + * Calling CreateFile() using FILE_APPEND_DATA and without FILE_WRITE_DATA + * is documented in [1] as opening a writable file handle in append mode. + * (It is believed that) this is atomic since it is maintained by the + * kernel unlike the O_APPEND flag which is racily maintained by the CRT. + * + * [1] https://docs.microsoft.com/en-us/windows/desktop/fileio/file-access-rights-constants + * + * This trick does not appear to work for named pipes. Instead it creates + * a named pipe client handle that cannot be written to. Callers should + * just use the regular _wopen() for them. (And since client handle gets + * bound to a unique server handle, it isn't really an issue.) + */ static int mingw_open_append(wchar_t const *wfilename, int oflags, ...) { HANDLE handle; @@ -360,10 +373,12 @@ static int mingw_open_append(wchar_t const *wfilename, int oflags, ...) NULL, create, FILE_ATTRIBUTE_NORMAL, NULL); if (handle == INVALID_HANDLE_VALUE) return errno = err_win_to_posix(GetLastError()), -1; + /* * No O_APPEND here, because the CRT uses it only to reset the - * file pointer to EOF on write(); but that is not necessary - * for a file created with FILE_APPEND_DATA. + * file pointer to EOF before each write(); but that is not + * necessary (and may lead to races) for a file created with + * FILE_APPEND_DATA. */ fd = _open_osfhandle((intptr_t)handle, O_BINARY); if (fd < 0) @@ -371,6 +386,21 @@ static int mingw_open_append(wchar_t const *wfilename, int oflags, ...) return fd; } +/* + * Does the pathname map to the local named pipe filesystem? + * That is, does it have a "//./pipe/" prefix? + */ +static int is_local_named_pipe_path(const char *filename) +{ + return (is_dir_sep(filename[0]) && + is_dir_sep(filename[1]) && + filename[2] == '.' && + is_dir_sep(filename[3]) && + !strncasecmp(filename+4, "pipe", 4) && + is_dir_sep(filename[8]) && + filename[9]); +} + int mingw_open (const char *filename, int oflags, ...) { typedef int (*open_fn_t)(wchar_t const *wfilename, int oflags, ...); @@ -387,7 +417,7 @@ int mingw_open (const char *filename, int oflags, ...) if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - if (oflags & O_APPEND) + if ((oflags & O_APPEND) && !is_local_named_pipe_path(filename)) open_fn = mingw_open_append; else open_fn = _wopen; diff --git a/config.mak.dev b/config.mak.dev index 9a998149d9..92d268137f 100644 --- a/config.mak.dev +++ b/config.mak.dev @@ -7,6 +7,7 @@ CFLAGS += -pedantic CFLAGS += -DUSE_PARENS_AROUND_GETTEXT_N=0 endif CFLAGS += -Wdeclaration-after-statement +CFLAGS += -Wformat-security CFLAGS += -Wno-format-zero-length CFLAGS += -Wold-style-definition CFLAGS += -Woverflow @@ -1297,6 +1297,7 @@ static void convert_attrs(const struct index_state *istate, struct conv_attrs *ca, const char *path) { static struct attr_check *check; + struct attr_check_item *ccheck = NULL; if (!check) { check = attr_check_initl("crlf", "ident", "filter", @@ -1306,30 +1307,25 @@ static void convert_attrs(const struct index_state *istate, git_config(read_convert_config, NULL); } - if (!git_check_attr(istate, path, check)) { - struct attr_check_item *ccheck = check->items; - ca->crlf_action = git_path_check_crlf(ccheck + 4); - if (ca->crlf_action == CRLF_UNDEFINED) - ca->crlf_action = git_path_check_crlf(ccheck + 0); - ca->ident = git_path_check_ident(ccheck + 1); - ca->drv = git_path_check_convert(ccheck + 2); - if (ca->crlf_action != CRLF_BINARY) { - enum eol eol_attr = git_path_check_eol(ccheck + 3); - if (ca->crlf_action == CRLF_AUTO && eol_attr == EOL_LF) - ca->crlf_action = CRLF_AUTO_INPUT; - else if (ca->crlf_action == CRLF_AUTO && eol_attr == EOL_CRLF) - ca->crlf_action = CRLF_AUTO_CRLF; - else if (eol_attr == EOL_LF) - ca->crlf_action = CRLF_TEXT_INPUT; - else if (eol_attr == EOL_CRLF) - ca->crlf_action = CRLF_TEXT_CRLF; - } - ca->working_tree_encoding = git_path_check_encoding(ccheck + 5); - } else { - ca->drv = NULL; - ca->crlf_action = CRLF_UNDEFINED; - ca->ident = 0; + git_check_attr(istate, path, check); + ccheck = check->items; + ca->crlf_action = git_path_check_crlf(ccheck + 4); + if (ca->crlf_action == CRLF_UNDEFINED) + ca->crlf_action = git_path_check_crlf(ccheck + 0); + ca->ident = git_path_check_ident(ccheck + 1); + ca->drv = git_path_check_convert(ccheck + 2); + if (ca->crlf_action != CRLF_BINARY) { + enum eol eol_attr = git_path_check_eol(ccheck + 3); + if (ca->crlf_action == CRLF_AUTO && eol_attr == EOL_LF) + ca->crlf_action = CRLF_AUTO_INPUT; + else if (ca->crlf_action == CRLF_AUTO && eol_attr == EOL_CRLF) + ca->crlf_action = CRLF_AUTO_CRLF; + else if (eol_attr == EOL_LF) + ca->crlf_action = CRLF_TEXT_INPUT; + else if (eol_attr == EOL_CRLF) + ca->crlf_action = CRLF_TEXT_CRLF; } + ca->working_tree_encoding = git_path_check_encoding(ccheck + 5); /* Save attr and make a decision for action */ ca->attr_action = ca->crlf_action; @@ -980,8 +980,13 @@ static void pmb_advance_or_null_multi_match(struct diff_options *o, /* Carry the white space delta forward */ pmb[i]->next_line->wsd = pmb[i]->wsd; pmb[i] = pmb[i]->next_line; - } else + } else { + if (pmb[i]->wsd) { + free(pmb[i]->wsd->string); + FREE_AND_NULL(pmb[i]->wsd); + } pmb[i] = NULL; + } } } @@ -1002,10 +1007,6 @@ static int shrink_potential_moved_blocks(struct moved_entry **pmb, if (lp < pmb_nr && rp > -1 && lp < rp) { pmb[lp] = pmb[rp]; - if (pmb[rp]->wsd) { - free(pmb[rp]->wsd->string); - FREE_AND_NULL(pmb[rp]->wsd); - } pmb[rp] = NULL; rp--; lp++; diff --git a/fetch-object.c b/fetch-object.c index 853624f811..4266548800 100644 --- a/fetch-object.c +++ b/fetch-object.c @@ -23,21 +23,16 @@ static void fetch_refs(const char *remote_name, struct ref *ref) fetch_if_missing = original_fetch_if_missing; } -void fetch_object(const char *remote_name, const unsigned char *sha1) -{ - struct ref *ref = alloc_ref(sha1_to_hex(sha1)); - hashcpy(ref->old_oid.hash, sha1); - fetch_refs(remote_name, ref); -} - -void fetch_objects(const char *remote_name, const struct oid_array *to_fetch) +void fetch_objects(const char *remote_name, const struct object_id *oids, + int oid_nr) { struct ref *ref = NULL; int i; - for (i = 0; i < to_fetch->nr; i++) { - struct ref *new_ref = alloc_ref(oid_to_hex(&to_fetch->oid[i])); - oidcpy(&new_ref->old_oid, &to_fetch->oid[i]); + for (i = 0; i < oid_nr; i++) { + struct ref *new_ref = alloc_ref(oid_to_hex(&oids[i])); + oidcpy(&new_ref->old_oid, &oids[i]); + new_ref->exact_oid = 1; new_ref->next = ref; ref = new_ref; } diff --git a/fetch-object.h b/fetch-object.h index 4b269d07ed..d2f996d4e8 100644 --- a/fetch-object.h +++ b/fetch-object.h @@ -1,11 +1,7 @@ #ifndef FETCH_OBJECT_H #define FETCH_OBJECT_H -#include "sha1-array.h" - -extern void fetch_object(const char *remote_name, const unsigned char *sha1); - -extern void fetch_objects(const char *remote_name, - const struct oid_array *to_fetch); +void fetch_objects(const char *remote_name, const struct object_id *oids, + int oid_nr); #endif @@ -10,7 +10,6 @@ #include "fsck.h" #include "refs.h" #include "utf8.h" -#include "sha1-array.h" #include "decorate.h" #include "oidset.h" #include "packfile.h" @@ -67,6 +66,8 @@ static struct oidset gitmodules_done = OIDSET_INIT; FUNC(GITMODULES_LARGE, ERROR) \ FUNC(GITMODULES_NAME, ERROR) \ FUNC(GITMODULES_SYMLINK, ERROR) \ + FUNC(GITMODULES_URL, ERROR) \ + FUNC(GITMODULES_PATH, ERROR) \ /* warnings */ \ FUNC(BAD_FILEMODE, WARN) \ FUNC(EMPTY_NAME, WARN) \ @@ -182,40 +183,37 @@ static int fsck_msg_type(enum fsck_msg_id msg_id, static void init_skiplist(struct fsck_options *options, const char *path) { - static struct oid_array skiplist = OID_ARRAY_INIT; - int sorted, fd; - char buffer[GIT_MAX_HEXSZ + 1]; + FILE *fp; + struct strbuf sb = STRBUF_INIT; struct object_id oid; - if (options->skiplist) - sorted = options->skiplist->sorted; - else { - sorted = 1; - options->skiplist = &skiplist; - } - - fd = open(path, O_RDONLY); - if (fd < 0) + fp = fopen(path, "r"); + if (!fp) die("Could not open skip list: %s", path); - for (;;) { + while (!strbuf_getline(&sb, fp)) { const char *p; - int result = read_in_full(fd, buffer, sizeof(buffer)); - if (result < 0) - die_errno("Could not read '%s'", path); - if (!result) - break; - if (parse_oid_hex(buffer, &oid, &p) || *p != '\n') - die("Invalid SHA-1: %s", buffer); - oid_array_append(&skiplist, &oid); - if (sorted && skiplist.nr > 1 && - oidcmp(&skiplist.oid[skiplist.nr - 2], - &oid) > 0) - sorted = 0; - } - close(fd); + const char *hash; - if (sorted) - skiplist.sorted = 1; + /* + * Allow trailing comments, leading whitespace + * (including before commits), and empty or whitespace + * only lines. + */ + hash = strchr(sb.buf, '#'); + if (hash) + strbuf_setlen(&sb, hash - sb.buf); + strbuf_trim(&sb); + if (!sb.len) + continue; + + if (parse_oid_hex(sb.buf, &oid, &p) || *p != '\0') + die("Invalid SHA-1: %s", sb.buf); + oidset_insert(&options->skiplist, &oid); + } + if (ferror(fp)) + die_errno("Could not read '%s'", path); + fclose(fp); + strbuf_release(&sb); } static int parse_msg_type(const char *str) @@ -320,9 +318,7 @@ static void append_msg_id(struct strbuf *sb, const char *msg_id) static int object_on_skiplist(struct fsck_options *opts, struct object *obj) { - if (opts && opts->skiplist && obj) - return oid_array_lookup(opts->skiplist, &obj->oid) >= 0; - return 0; + return opts && obj && oidset_contains(&opts->skiplist, &obj->oid); } __attribute__((format (printf, 4, 5))) @@ -992,6 +988,18 @@ static int fsck_gitmodules_fn(const char *var, const char *value, void *vdata) FSCK_MSG_GITMODULES_NAME, "disallowed submodule name: %s", name); + if (!strcmp(key, "url") && value && + looks_like_command_line_option(value)) + data->ret |= report(data->options, data->obj, + FSCK_MSG_GITMODULES_URL, + "disallowed submodule url: %s", + value); + if (!strcmp(key, "path") && value && + looks_like_command_line_option(value)) + data->ret |= report(data->options, data->obj, + FSCK_MSG_GITMODULES_PATH, + "disallowed submodule path: %s", + value); free(name); return 0; @@ -1,6 +1,8 @@ #ifndef GIT_FSCK_H #define GIT_FSCK_H +#include "oidset.h" + #define FSCK_ERROR 1 #define FSCK_WARN 2 #define FSCK_IGNORE 3 @@ -35,12 +37,12 @@ struct fsck_options { fsck_error error_func; unsigned strict:1; int *msg_type; - struct oid_array *skiplist; + struct oidset skiplist; struct decoration *object_names; }; -#define FSCK_OPTIONS_DEFAULT { NULL, fsck_error_function, 0, NULL } -#define FSCK_OPTIONS_STRICT { NULL, fsck_error_function, 1, NULL } +#define FSCK_OPTIONS_DEFAULT { NULL, fsck_error_function, 0, NULL, OIDSET_INIT } +#define FSCK_OPTIONS_STRICT { NULL, fsck_error_function, 1, NULL, OIDSET_INIT } /* descend in all linked child objects * the return value is: @@ -675,6 +675,8 @@ static void execv_dashed_external(const char **argv) static int run_argv(int *argcp, const char ***argv) { int done_alias = 0; + struct string_list cmd_list = STRING_LIST_INIT_NODUP; + struct string_list_item *seen; while (1) { /* @@ -692,17 +694,37 @@ static int run_argv(int *argcp, const char ***argv) /* .. then try the external ones */ execv_dashed_external(*argv); - /* It could be an alias -- this works around the insanity + seen = unsorted_string_list_lookup(&cmd_list, *argv[0]); + if (seen) { + int i; + struct strbuf sb = STRBUF_INIT; + for (i = 0; i < cmd_list.nr; i++) { + struct string_list_item *item = &cmd_list.items[i]; + + strbuf_addf(&sb, "\n %s", item->string); + if (item == seen) + strbuf_addstr(&sb, " <=="); + else if (i == cmd_list.nr - 1) + strbuf_addstr(&sb, " ==>"); + } + die(_("alias loop detected: expansion of '%s' does" + " not terminate:%s"), cmd_list.items[0].string, sb.buf); + } + + string_list_append(&cmd_list, *argv[0]); + + /* + * It could be an alias -- this works around the insanity * of overriding "git log" with "git show" by having * alias.log = show */ - if (done_alias) - break; if (!handle_alias(argcp, argv)) break; done_alias = 1; } + string_list_clear(&cmd_list, 0); + return done_alias; } diff --git a/linear-assignment.c b/linear-assignment.c index 9b3e56e283..ecffc09be6 100644 --- a/linear-assignment.c +++ b/linear-assignment.c @@ -19,6 +19,12 @@ void compute_assignment(int column_count, int row_count, int *cost, int *free_row, free_count = 0, saved_free_count, *pred, *col; int i, j, phase; + if (column_count < 2) { + memset(column2row, 0, sizeof(int) * column_count); + memset(row2column, 0, sizeof(int) * row_count); + return; + } + memset(column2row, -1, sizeof(int) * column_count); memset(row2column, -1, sizeof(int) * row_count); ALLOC_ARRAY(v, column_count); diff --git a/ll-merge.c b/ll-merge.c index 0e2800f7bb..1936fee9e1 100644 --- a/ll-merge.c +++ b/ll-merge.c @@ -371,13 +371,12 @@ int ll_merge(mmbuffer_t *result_buf, if (!check) check = attr_check_initl("merge", "conflict-marker-size", NULL); - if (!git_check_attr(&the_index, path, check)) { - ll_driver_name = check->items[0].value; - if (check->items[1].value) { - marker_size = atoi(check->items[1].value); - if (marker_size <= 0) - marker_size = DEFAULT_CONFLICT_MARKER_SIZE; - } + git_check_attr(&the_index, path, check); + ll_driver_name = check->items[0].value; + if (check->items[1].value) { + marker_size = atoi(check->items[1].value); + if (marker_size <= 0) + marker_size = DEFAULT_CONFLICT_MARKER_SIZE; } driver = find_ll_merge_driver(ll_driver_name); @@ -398,7 +397,8 @@ int ll_merge_marker_size(const char *path) if (!check) check = attr_check_initl("conflict-marker-size", NULL); - if (!git_check_attr(&the_index, path, check) && check->items[0].value) { + git_check_attr(&the_index, path, check); + if (check->items[0].value) { marker_size = atoi(check->items[0].value); if (marker_size <= 0) marker_size = DEFAULT_CONFLICT_MARKER_SIZE; diff --git a/lockfile.h b/lockfile.h index f401c979f0..35403ccc0d 100644 --- a/lockfile.h +++ b/lockfile.h @@ -263,8 +263,8 @@ static inline int close_lock_file_gently(struct lock_file *lk) * nobody else) to inspect the contents you wrote, while still * holding the lock yourself. * - * * `reopen_lock_file()` to reopen the lockfile. Make further updates - * to the contents. + * * `reopen_lock_file()` to reopen the lockfile, truncating the existing + * contents. Write out the new contents. * * * `commit_lock_file()` to make the final version permanent. */ diff --git a/merge-recursive.c b/merge-recursive.c index 45a163c555..fa87341e67 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -2240,7 +2240,7 @@ static struct dir_rename_entry *check_dir_renamed(const char *path, { char *temp = xstrdup(path); char *end; - struct dir_rename_entry *entry = NULL;; + struct dir_rename_entry *entry = NULL; while ((end = strrchr(temp, '/'))) { *end = '\0'; @@ -7,6 +7,7 @@ #include "object-store.h" #include "sha1-lookup.h" #include "midx.h" +#include "progress.h" #define MIDX_SIGNATURE 0x4d494458 /* "MIDX" */ #define MIDX_VERSION 1 @@ -76,24 +77,18 @@ struct multi_pack_index *load_multi_pack_index(const char *object_dir, int local m->local = local; m->signature = get_be32(m->data); - if (m->signature != MIDX_SIGNATURE) { - error(_("multi-pack-index signature 0x%08x does not match signature 0x%08x"), + if (m->signature != MIDX_SIGNATURE) + die(_("multi-pack-index signature 0x%08x does not match signature 0x%08x"), m->signature, MIDX_SIGNATURE); - goto cleanup_fail; - } m->version = m->data[MIDX_BYTE_FILE_VERSION]; - if (m->version != MIDX_VERSION) { - error(_("multi-pack-index version %d not recognized"), + if (m->version != MIDX_VERSION) + die(_("multi-pack-index version %d not recognized"), m->version); - goto cleanup_fail; - } hash_version = m->data[MIDX_BYTE_HASH_VERSION]; - if (hash_version != MIDX_HASH_VERSION) { - error(_("hash version %u does not match"), hash_version); - goto cleanup_fail; - } + if (hash_version != MIDX_HASH_VERSION) + die(_("hash version %u does not match"), hash_version); m->hash_len = MIDX_HASH_LEN; m->num_chunks = m->data[MIDX_BYTE_NUM_CHUNKS]; @@ -106,6 +101,9 @@ struct multi_pack_index *load_multi_pack_index(const char *object_dir, int local uint64_t chunk_offset = get_be64(m->data + MIDX_HEADER_SIZE + 4 + MIDX_CHUNKLOOKUP_WIDTH * i); + if (chunk_offset >= m->data_len) + die(_("invalid chunk offset (too large)")); + switch (chunk_id) { case MIDX_CHUNKID_PACKNAMES: m->chunk_pack_names = m->data + chunk_offset; @@ -160,12 +158,10 @@ struct multi_pack_index *load_multi_pack_index(const char *object_dir, int local cur_pack_name += strlen(cur_pack_name) + 1; - if (i && strcmp(m->pack_names[i], m->pack_names[i - 1]) <= 0) { - error(_("multi-pack-index pack names out of order: '%s' before '%s'"), + if (i && strcmp(m->pack_names[i], m->pack_names[i - 1]) <= 0) + die(_("multi-pack-index pack names out of order: '%s' before '%s'"), m->pack_names[i - 1], m->pack_names[i]); - goto cleanup_fail; - } } return m; @@ -202,7 +198,8 @@ 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) - BUG("bad pack-int-id"); + die(_("bad pack-int-id: %u (%u total packs"), + pack_int_id, m->num_packs); if (m->packs[pack_int_id]) return 0; @@ -241,7 +238,7 @@ static off_t nth_midxed_offset(struct multi_pack_index *m, uint32_t pos) offset32 = get_be32(offset_data + sizeof(uint32_t)); if (m->chunk_large_offsets && offset32 & MIDX_LARGE_OFFSET_NEEDED) { - if (sizeof(offset32) < sizeof(uint64_t)) + if (sizeof(off_t) < sizeof(uint64_t)) die(_("multi-pack-index stores a 64-bit offset, but off_t is too small")); offset32 ^= MIDX_LARGE_OFFSET_NEEDED; @@ -928,3 +925,83 @@ void clear_midx_file(const char *object_dir) free(midx); } + +static int verify_midx_error; + +static void midx_report(const char *fmt, ...) +{ + va_list ap; + verify_midx_error = 1; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); +} + +int verify_midx_file(const char *object_dir) +{ + uint32_t i; + struct progress *progress = NULL; + struct multi_pack_index *m = load_multi_pack_index(object_dir, 1); + verify_midx_error = 0; + + if (!m) + return 0; + + for (i = 0; i < m->num_packs; i++) { + if (prepare_midx_pack(m, i)) + midx_report("failed to load pack in position %d", i); + } + + for (i = 0; i < 255; i++) { + uint32_t oid_fanout1 = ntohl(m->chunk_oid_fanout[i]); + uint32_t oid_fanout2 = ntohl(m->chunk_oid_fanout[i + 1]); + + if (oid_fanout1 > oid_fanout2) + midx_report(_("oid fanout out of order: fanout[%d] = %"PRIx32" > %"PRIx32" = fanout[%d]"), + i, oid_fanout1, oid_fanout2, i + 1); + } + + for (i = 0; i < m->num_objects - 1; i++) { + struct object_id oid1, oid2; + + nth_midxed_object_oid(&oid1, m, i); + nth_midxed_object_oid(&oid2, m, i + 1); + + if (oidcmp(&oid1, &oid2) >= 0) + midx_report(_("oid lookup out of order: oid[%d] = %s >= %s = oid[%d]"), + i, oid_to_hex(&oid1), oid_to_hex(&oid2), i + 1); + } + + progress = start_progress(_("Verifying object offsets"), m->num_objects); + for (i = 0; i < m->num_objects; i++) { + struct object_id oid; + struct pack_entry e; + off_t m_offset, p_offset; + + nth_midxed_object_oid(&oid, m, i); + if (!fill_midx_entry(&oid, &e, m)) { + midx_report(_("failed to load pack entry for oid[%d] = %s"), + i, oid_to_hex(&oid)); + continue; + } + + if (open_pack_index(e.p)) { + midx_report(_("failed to load pack-index for packfile %s"), + e.p->pack_name); + break; + } + + m_offset = e.offset; + p_offset = find_pack_entry_one(oid.hash, e.p); + + if (m_offset != p_offset) + midx_report(_("incorrect object offset for oid[%d] = %s: %"PRIx64" != %"PRIx64), + i, oid_to_hex(&oid), m_offset, p_offset); + + display_progress(progress, i + 1); + } + stop_progress(&progress); + + return verify_midx_error; +} @@ -46,5 +46,6 @@ int prepare_multi_pack_index_one(struct repository *r, const char *object_dir, i int write_midx_file(const char *object_dir); void clear_midx_file(const char *object_dir); +int verify_midx_file(const char *object_dir); #endif @@ -1394,17 +1394,50 @@ struct ref_iterator *refs_ref_iterator_begin( * non-zero value, stop the iteration and return that value; * otherwise, return 0. */ +static int do_for_each_repo_ref(struct repository *r, const char *prefix, + each_repo_ref_fn fn, int trim, int flags, + void *cb_data) +{ + struct ref_iterator *iter; + struct ref_store *refs = get_main_ref_store(r); + + if (!refs) + return 0; + + iter = refs_ref_iterator_begin(refs, prefix, trim, flags); + + return do_for_each_repo_ref_iterator(r, iter, fn, cb_data); +} + +struct do_for_each_ref_help { + each_ref_fn *fn; + void *cb_data; +}; + +static int do_for_each_ref_helper(struct repository *r, + const char *refname, + const struct object_id *oid, + int flags, + void *cb_data) +{ + struct do_for_each_ref_help *hp = cb_data; + + return hp->fn(refname, oid, flags, hp->cb_data); +} + static int do_for_each_ref(struct ref_store *refs, const char *prefix, each_ref_fn fn, int trim, int flags, void *cb_data) { struct ref_iterator *iter; + struct do_for_each_ref_help hp = { fn, cb_data }; if (!refs) return 0; iter = refs_ref_iterator_begin(refs, prefix, trim, flags); - return do_for_each_ref_iterator(iter, fn, cb_data); + return do_for_each_repo_ref_iterator(the_repository, iter, + do_for_each_ref_helper, &hp); } int refs_for_each_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data) @@ -1449,12 +1482,11 @@ int refs_for_each_fullref_in(struct ref_store *refs, const char *prefix, return do_for_each_ref(refs, prefix, fn, 0, flag, cb_data); } -int for_each_replace_ref(struct repository *r, each_ref_fn fn, void *cb_data) +int for_each_replace_ref(struct repository *r, each_repo_ref_fn fn, void *cb_data) { - return do_for_each_ref(get_main_ref_store(r), - git_replace_ref_base, fn, - strlen(git_replace_ref_base), - DO_FOR_EACH_INCLUDE_BROKEN, cb_data); + return do_for_each_repo_ref(r, git_replace_ref_base, fn, + strlen(git_replace_ref_base), + DO_FOR_EACH_INCLUDE_BROKEN, cb_data); } int for_each_namespaced_ref(each_ref_fn fn, void *cb_data) @@ -2033,10 +2065,12 @@ cleanup: int refs_for_each_reflog(struct ref_store *refs, each_ref_fn fn, void *cb_data) { struct ref_iterator *iter; + struct do_for_each_ref_help hp = { fn, cb_data }; iter = refs->be->reflog_iterator_begin(refs); - return do_for_each_ref_iterator(iter, fn, cb_data); + return do_for_each_repo_ref_iterator(the_repository, iter, + do_for_each_ref_helper, &hp); } int for_each_reflog(each_ref_fn fn, void *cb_data) @@ -277,6 +277,16 @@ typedef int each_ref_fn(const char *refname, const struct object_id *oid, int flags, void *cb_data); /* + * The same as each_ref_fn, but also with a repository argument that + * contains the repository associated with the callback. + */ +typedef int each_repo_ref_fn(struct repository *r, + const char *refname, + const struct object_id *oid, + int flags, + void *cb_data); + +/* * The following functions invoke the specified callback function for * each reference indicated. If the function ever returns a nonzero * value, stop the iteration and return that value. Please note that @@ -309,7 +319,7 @@ int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data, int for_each_tag_ref(each_ref_fn fn, void *cb_data); int for_each_branch_ref(each_ref_fn fn, void *cb_data); int for_each_remote_ref(each_ref_fn fn, void *cb_data); -int for_each_replace_ref(struct repository *r, each_ref_fn fn, void *cb_data); +int for_each_replace_ref(struct repository *r, each_repo_ref_fn fn, void *cb_data); int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data); int for_each_glob_ref_in(each_ref_fn fn, const char *pattern, const char *prefix, void *cb_data); diff --git a/refs/iterator.c b/refs/iterator.c index 2ac91ac340..629e00a122 100644 --- a/refs/iterator.c +++ b/refs/iterator.c @@ -407,15 +407,15 @@ struct ref_iterator *prefix_ref_iterator_begin(struct ref_iterator *iter0, struct ref_iterator *current_ref_iter = NULL; -int do_for_each_ref_iterator(struct ref_iterator *iter, - each_ref_fn fn, void *cb_data) +int do_for_each_repo_ref_iterator(struct repository *r, struct ref_iterator *iter, + each_repo_ref_fn fn, void *cb_data) { int retval = 0, ok; struct ref_iterator *old_ref_iter = current_ref_iter; current_ref_iter = iter; while ((ok = ref_iterator_advance(iter)) == ITER_OK) { - retval = fn(iter->refname, iter->oid, iter->flags, cb_data); + retval = fn(r, iter->refname, iter->oid, iter->flags, cb_data); if (retval) { /* * If ref_iterator_abort() returns ITER_ERROR, diff --git a/refs/refs-internal.h b/refs/refs-internal.h index 44d53672c7..f2d8c0123a 100644 --- a/refs/refs-internal.h +++ b/refs/refs-internal.h @@ -286,7 +286,7 @@ int refs_rename_ref_available(struct ref_store *refs, * * // Access information about the current reference: * if (!(iter->flags & REF_ISSYMREF)) - * printf("%s is %s\n", iter->refname, oid_to_hex(&iter->oid)); + * printf("%s is %s\n", iter->refname, oid_to_hex(iter->oid)); * * // If you need to peel the reference: * ref_iterator_peel(iter, &oid); @@ -478,8 +478,9 @@ extern struct ref_iterator *current_ref_iter; * adapter between the callback style of reference iteration and the * iterator style. */ -int do_for_each_ref_iterator(struct ref_iterator *iter, - each_ref_fn fn, void *cb_data); +int do_for_each_repo_ref_iterator(struct repository *r, + struct ref_iterator *iter, + each_repo_ref_fn fn, void *cb_data); /* * Only include per-worktree refs in a do_for_each_ref*() iteration. diff --git a/remote-curl.c b/remote-curl.c index fb28309e85..762a55a75f 100644 --- a/remote-curl.c +++ b/remote-curl.c @@ -178,7 +178,7 @@ static int set_option(const char *name, const char *value) options.no_dependents = 1; return 0; } else if (!strcmp(name, "filter")) { - options.filter = xstrdup(value);; + options.filter = xstrdup(value); return 0; } else { return 1 /* unsupported */; diff --git a/replace-object.c b/replace-object.c index 4ec77ce418..e295e87943 100644 --- a/replace-object.c +++ b/replace-object.c @@ -6,7 +6,8 @@ #include "repository.h" #include "commit.h" -static int register_replace_ref(const char *refname, +static int register_replace_ref(struct repository *r, + const char *refname, const struct object_id *oid, int flag, void *cb_data) { @@ -25,13 +26,13 @@ static int register_replace_ref(const char *refname, oidcpy(&repl_obj->replacement, oid); /* Register new object */ - if (oidmap_put(the_repository->objects->replace_map, repl_obj)) + if (oidmap_put(r->objects->replace_map, repl_obj)) die(_("duplicate replace ref: %s"), refname); return 0; } -static void prepare_replace_object(struct repository *r) +void prepare_replace_object(struct repository *r) { if (r->objects->replace_map) return; diff --git a/replace-object.h b/replace-object.h index 9345e105dd..16528df942 100644 --- a/replace-object.h +++ b/replace-object.h @@ -10,6 +10,8 @@ struct replace_object { struct object_id replacement; }; +void prepare_replace_object(struct repository *r); + /* * This internal function is only declared here for the benefit of * lookup_replace_object(). Please do not call it directly. @@ -521,7 +521,7 @@ static int check_one_conflict(int i, int *type) } *type = PUNTED; - while (ce_stage(active_cache[i]) == 1) + while (i < active_nr && ce_stage(active_cache[i]) == 1) i++; /* Only handle regular files with both stages #2 and #3 */ diff --git a/sequencer.c b/sequencer.c index 00cefd129e..ddb41a62d9 100644 --- a/sequencer.c +++ b/sequencer.c @@ -903,7 +903,7 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts, if ((flags & ALLOW_EMPTY)) argv_array_push(&cmd.args, "--allow-empty"); - if (opts->allow_empty_message) + if (!(flags & EDIT_MSG)) argv_array_push(&cmd.args, "--allow-empty-message"); if (cmd.err == -1) { @@ -1317,7 +1317,7 @@ static int try_to_commit(struct strbuf *msg, const char *author, if (cleanup != COMMIT_MSG_CLEANUP_NONE) strbuf_stripspace(msg, cleanup == COMMIT_MSG_CLEANUP_ALL); - if (!opts->allow_empty_message && message_is_empty(msg, cleanup)) { + if ((flags & EDIT_MSG) && message_is_empty(msg, cleanup)) { res = 1; /* run 'git commit' to display error message */ goto out; } @@ -3611,9 +3611,20 @@ static int commit_staged_changes(struct replay_opts *opts, * the commit message and if there was a squash, let the user * edit it. */ - if (is_clean && oideq(&head, &to_amend) && - opts->current_fixup_count > 0 && - file_exists(rebase_path_stopped_sha())) { + if (!is_clean || !opts->current_fixup_count) + ; /* this is not the final fixup */ + else if (!oideq(&head, &to_amend) || + !file_exists(rebase_path_stopped_sha())) { + /* was a final fixup or squash done manually? */ + if (!is_fixup(peek_command(todo_list, 0))) { + unlink(rebase_path_fixup_msg()); + unlink(rebase_path_squash_msg()); + unlink(rebase_path_current_fixups()); + strbuf_reset(&opts->current_fixups); + opts->current_fixup_count = 0; + } + } else { + /* we are in a fixup/squash chain */ const char *p = opts->current_fixups.buf; int len = opts->current_fixups.len; diff --git a/sha1-file.c b/sha1-file.c index d85f4e93e1..a4367b8f04 100644 --- a/sha1-file.c +++ b/sha1-file.c @@ -1317,7 +1317,7 @@ int oid_object_info_extended(struct repository *r, const struct object_id *oid, * TODO Pass a repository struct through fetch_object, * such that arbitrary repositories work. */ - fetch_object(repository_format_partial_clone, real->hash); + fetch_objects(repository_format_partial_clone, real, 1); already_retried = 1; continue; } diff --git a/string-list.c b/string-list.c index 771c455098..1f6063f2a2 100644 --- a/string-list.c +++ b/string-list.c @@ -195,16 +195,6 @@ void string_list_clear_func(struct string_list *list, string_list_clear_func_t c list->nr = list->alloc = 0; } - -void print_string_list(const struct string_list *p, const char *text) -{ - int i; - if ( text ) - printf("%s\n", text); - for (i = 0; i < p->nr; i++) - printf("%s:%p\n", p->items[i].string, p->items[i].util); -} - struct string_list_item *string_list_append_nodup(struct string_list *list, char *string) { diff --git a/string-list.h b/string-list.h index ff8f6094a3..18c718c12c 100644 --- a/string-list.h +++ b/string-list.h @@ -114,14 +114,6 @@ void filter_string_list(struct string_list *list, int free_util, string_list_each_func_t want, void *cb_data); /** - * Dump a string_list to stdout, useful mainly for debugging - * purposes. It can take an optional header argument and it writes out - * the string-pointer pairs of the string_list, each one in its own - * line. - */ -void print_string_list(const struct string_list *p, const char *text); - -/** * Free a string_list. The `string` pointer of the items will be freed * in case the `strdup_strings` member of the string_list is set. The * second parameter controls if the `util` pointer of the items should diff --git a/submodule-config.c b/submodule-config.c index e04ba756d9..b132f7a80b 100644 --- a/submodule-config.c +++ b/submodule-config.c @@ -384,6 +384,12 @@ static void warn_multiple_config(const struct object_id *treeish_name, commit_string, name, option); } +static void warn_command_line_option(const char *var, const char *value) +{ + warning(_("ignoring '%s' which may be interpreted as" + " a command-line option: %s"), var, value); +} + struct parse_config_parameter { struct submodule_cache *cache; const struct object_id *treeish_name; @@ -409,6 +415,8 @@ static int parse_config(const char *var, const char *value, void *data) if (!strcmp(item.buf, "path")) { if (!value) ret = config_error_nonbool(var); + else if (looks_like_command_line_option(value)) + warn_command_line_option(var, value); else if (!me->overwrite && submodule->path) warn_multiple_config(me->treeish_name, submodule->name, "path"); @@ -449,6 +457,8 @@ static int parse_config(const char *var, const char *value, void *data) } else if (!strcmp(item.buf, "url")) { if (!value) { ret = config_error_nonbool(var); + } else if (looks_like_command_line_option(value)) { + warn_command_line_option(var, value); } else if (!me->overwrite && submodule->url) { warn_multiple_config(me->treeish_name, submodule->name, "url"); diff --git a/submodule.c b/submodule.c index ed05339b58..b53cb6e9c4 100644 --- a/submodule.c +++ b/submodule.c @@ -66,8 +66,7 @@ int is_staging_gitmodules_ok(struct index_state *istate) if ((pos >= 0) && (pos < istate->cache_nr)) { struct stat st; if (lstat(GITMODULES_FILE, &st) == 0 && - ie_match_stat(istate, istate->cache[pos], &st, - CE_MATCH_IGNORE_FSMONITOR) & DATA_CHANGED) + ie_match_stat(istate, istate->cache[pos], &st, 0) & DATA_CHANGED) return 0; } @@ -814,6 +814,28 @@ library for your script to use. the symbolic link in the file system and a part that does; then only the latter part need be protected by a SYMLINKS prerequisite (see below). + - test_oid_init + + This function loads facts and useful object IDs related to the hash + algorithm(s) in use from the files in t/oid-info. + + - test_oid_cache + + This function reads per-hash algorithm information from standard + input (usually a heredoc) in the format described in + t/oid-info/README. This is useful for test-specific values, such as + object IDs, which must vary based on the hash algorithm. + + Certain fixed values, such as hash sizes and common placeholder + object IDs, can be loaded with test_oid_init (described above). + + - test_oid <key> + + This function looks up a value for the hash algorithm in use, based + on the key given. The value must have been loaded using + test_oid_init or test_oid_cache. Providing an unknown key is an + error. + Prerequisites ------------- diff --git a/t/helper/test-dump-fsmonitor.c b/t/helper/test-dump-fsmonitor.c index ad452707e8..08e3684aff 100644 --- a/t/helper/test-dump-fsmonitor.c +++ b/t/helper/test-dump-fsmonitor.c @@ -1,6 +1,7 @@ +#include "test-tool.h" #include "cache.h" -int cmd_main(int ac, const char **av) +int cmd__dump_fsmonitor(int ac, const char **av) { struct index_state *istate = &the_index; int i; diff --git a/t/helper/test-dump-untracked-cache.c b/t/helper/test-dump-untracked-cache.c index bd92fb305a..52870ebbb3 100644 --- a/t/helper/test-dump-untracked-cache.c +++ b/t/helper/test-dump-untracked-cache.c @@ -1,3 +1,4 @@ +#include "test-tool.h" #include "cache.h" #include "dir.h" @@ -38,7 +39,7 @@ static void dump(struct untracked_cache_dir *ucd, struct strbuf *base) strbuf_setlen(base, len); } -int cmd_main(int ac, const char **av) +int cmd__dump_untracked_cache(int ac, const char **av) { struct untracked_cache *uc; struct strbuf base = STRBUF_INIT; diff --git a/t/helper/test-parse-options.c b/t/helper/test-parse-options.c index 630c76d127..9cb8a0ea0f 100644 --- a/t/helper/test-parse-options.c +++ b/t/helper/test-parse-options.c @@ -1,3 +1,4 @@ +#include "test-tool.h" #include "cache.h" #include "parse-options.h" #include "string-list.h" @@ -94,11 +95,11 @@ static void show(struct string_list *expect, int *status, const char *fmt, ...) strbuf_release(&buf); } -int cmd_main(int argc, const char **argv) +int cmd__parse_options(int argc, const char **argv) { const char *prefix = "prefix/"; const char *usage[] = { - "test-parse-options <options>", + "test-tool parse-options <options>", "", "A helper function for the parse-options API.", NULL diff --git a/t/helper/test-pkt-line.c b/t/helper/test-pkt-line.c index 30775f986f..282d536384 100644 --- a/t/helper/test-pkt-line.c +++ b/t/helper/test-pkt-line.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "test-tool.h" #include "pkt-line.h" static void pack_line(const char *line) @@ -79,7 +80,7 @@ static void unpack_sideband(void) } } -int cmd_main(int argc, const char **argv) +int cmd__pkt_line(int argc, const char **argv) { if (argc < 2) die("too few arguments"); diff --git a/t/helper/test-reach.c b/t/helper/test-reach.c index eb21103998..08d2ea68e8 100644 --- a/t/helper/test-reach.c +++ b/t/helper/test-reach.c @@ -31,6 +31,7 @@ int cmd__reach(int ac, const char **av) struct object_id oid_A, oid_B; struct commit *A, *B; struct commit_list *X, *Y; + struct object_array X_obj = OBJECT_ARRAY_INIT; struct commit **X_array; int X_nr, X_alloc; struct strbuf buf = STRBUF_INIT; @@ -49,7 +50,8 @@ int cmd__reach(int ac, const char **av) while (strbuf_getline(&buf, stdin) != EOF) { struct object_id oid; - struct object *o; + struct object *orig; + struct object *peeled; struct commit *c; if (buf.len < 3) continue; @@ -57,14 +59,14 @@ int cmd__reach(int ac, const char **av) if (get_oid_committish(buf.buf + 2, &oid)) die("failed to resolve %s", buf.buf + 2); - o = parse_object(r, &oid); - o = deref_tag_noverify(o); + orig = parse_object(r, &oid); + peeled = deref_tag_noverify(orig); - if (!o) + if (!peeled) die("failed to load commit for input %s resulting in oid %s\n", buf.buf, oid_to_hex(&oid)); - c = object_as_type(r, o, OBJ_COMMIT, 0); + c = object_as_type(r, peeled, OBJ_COMMIT, 0); if (!c) die("failed to load commit for input %s resulting in oid %s\n", @@ -85,6 +87,7 @@ int cmd__reach(int ac, const char **av) commit_list_insert(c, &X); ALLOC_GROW(X_array, X_nr + 1, X_alloc); X_array[X_nr++] = c; + add_object_array(orig, NULL, &X_obj); break; case 'Y': @@ -113,6 +116,15 @@ int cmd__reach(int ac, const char **av) print_sorted_commit_ids(list); } else if (!strcmp(av[1], "can_all_from_reach")) { printf("%s(X,Y):%d\n", av[1], can_all_from_reach(X, Y, 1)); + } else if (!strcmp(av[1], "can_all_from_reach_with_flag")) { + struct commit_list *iter = Y; + + while (iter) { + iter->item->object.flags |= 2; + iter = iter->next; + } + + printf("%s(X,_,_,0,0):%d\n", av[1], can_all_from_reach_with_flag(&X_obj, 2, 4, 0, 0)); } else if (!strcmp(av[1], "commit_contains")) { struct ref_filter filter; struct contains_cache cache; diff --git a/t/helper/test-repository.c b/t/helper/test-repository.c index 2762ca6562..6a84a53efb 100644 --- a/t/helper/test-repository.c +++ b/t/helper/test-repository.c @@ -15,7 +15,10 @@ static void test_parse_commit_in_graph(const char *gitdir, const char *worktree, struct commit *c; struct commit_list *parent; - repo_init(&r, gitdir, worktree); + setup_git_env(gitdir); + + if (repo_init(&r, gitdir, worktree)) + die("Couldn't init repo"); c = lookup_commit(&r, commit_oid); @@ -38,7 +41,10 @@ static void test_get_commit_tree_in_graph(const char *gitdir, struct commit *c; struct tree *tree; - repo_init(&r, gitdir, worktree); + setup_git_env(gitdir); + + if (repo_init(&r, gitdir, worktree)) + die("Couldn't init repo"); c = lookup_commit(&r, commit_oid); diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c index bef50c4dcc..6b5836dc1b 100644 --- a/t/helper/test-tool.c +++ b/t/helper/test-tool.c @@ -14,7 +14,9 @@ static struct test_cmd cmds[] = { { "delta", cmd__delta }, { "drop-caches", cmd__drop_caches }, { "dump-cache-tree", cmd__dump_cache_tree }, + { "dump-fsmonitor", cmd__dump_fsmonitor }, { "dump-split-index", cmd__dump_split_index }, + { "dump-untracked-cache", cmd__dump_untracked_cache }, { "example-decorate", cmd__example_decorate }, { "genrandom", cmd__genrandom }, { "hashmap", cmd__hashmap }, @@ -25,7 +27,9 @@ static struct test_cmd cmds[] = { { "mergesort", cmd__mergesort }, { "mktemp", cmd__mktemp }, { "online-cpus", cmd__online_cpus }, + { "parse-options", cmd__parse_options }, { "path-utils", cmd__path_utils }, + { "pkt-line", cmd__pkt_line }, { "prio-queue", cmd__prio_queue }, { "reach", cmd__reach }, { "read-cache", cmd__read_cache }, @@ -36,8 +40,8 @@ static struct test_cmd cmds[] = { { "revision-walking", cmd__revision_walking }, { "run-command", cmd__run_command }, { "scrap-cache-tree", cmd__scrap_cache_tree }, - { "sha1-array", cmd__sha1_array }, { "sha1", cmd__sha1 }, + { "sha1-array", cmd__sha1_array }, { "sigchain", cmd__sigchain }, { "strcmp-offset", cmd__strcmp_offset }, { "string-list", cmd__string_list }, @@ -45,6 +49,9 @@ static struct test_cmd cmds[] = { { "subprocess", cmd__subprocess }, { "urlmatch-normalization", cmd__urlmatch_normalization }, { "wildmatch", cmd__wildmatch }, +#ifdef GIT_WINDOWS_NATIVE + { "windows-named-pipe", cmd__windows_named_pipe }, +#endif { "write-cache", cmd__write_cache }, }; diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h index 321982e4bc..e4890566da 100644 --- a/t/helper/test-tool.h +++ b/t/helper/test-tool.h @@ -10,7 +10,9 @@ int cmd__date(int argc, const char **argv); int cmd__delta(int argc, const char **argv); int cmd__drop_caches(int argc, const char **argv); int cmd__dump_cache_tree(int argc, const char **argv); +int cmd__dump_fsmonitor(int argc, const char **argv); int cmd__dump_split_index(int argc, const char **argv); +int cmd__dump_untracked_cache(int argc, const char **argv); int cmd__example_decorate(int argc, const char **argv); int cmd__genrandom(int argc, const char **argv); int cmd__hashmap(int argc, const char **argv); @@ -21,7 +23,9 @@ int cmd__match_trees(int argc, const char **argv); int cmd__mergesort(int argc, const char **argv); int cmd__mktemp(int argc, const char **argv); int cmd__online_cpus(int argc, const char **argv); +int cmd__parse_options(int argc, const char **argv); int cmd__path_utils(int argc, const char **argv); +int cmd__pkt_line(int argc, const char **argv); int cmd__prio_queue(int argc, const char **argv); int cmd__reach(int argc, const char **argv); int cmd__read_cache(int argc, const char **argv); @@ -32,8 +36,8 @@ int cmd__repository(int argc, const char **argv); int cmd__revision_walking(int argc, const char **argv); int cmd__run_command(int argc, const char **argv); int cmd__scrap_cache_tree(int argc, const char **argv); -int cmd__sha1_array(int argc, const char **argv); int cmd__sha1(int argc, const char **argv); +int cmd__sha1_array(int argc, const char **argv); int cmd__sigchain(int argc, const char **argv); int cmd__strcmp_offset(int argc, const char **argv); int cmd__string_list(int argc, const char **argv); @@ -41,6 +45,9 @@ int cmd__submodule_config(int argc, const char **argv); int cmd__subprocess(int argc, const char **argv); int cmd__urlmatch_normalization(int argc, const char **argv); int cmd__wildmatch(int argc, const char **argv); +#ifdef GIT_WINDOWS_NATIVE +int cmd__windows_named_pipe(int argc, const char **argv); +#endif int cmd__write_cache(int argc, const char **argv); #endif diff --git a/t/helper/test-windows-named-pipe.c b/t/helper/test-windows-named-pipe.c new file mode 100644 index 0000000000..b4b752b01a --- /dev/null +++ b/t/helper/test-windows-named-pipe.c @@ -0,0 +1,72 @@ +#include "test-tool.h" +#include "git-compat-util.h" +#include "strbuf.h" + +#ifdef GIT_WINDOWS_NATIVE +static const char *usage_string = "<pipe-filename>"; + +#define TEST_BUFSIZE (4096) + +int cmd__windows_named_pipe(int argc, const char **argv) +{ + const char *filename; + struct strbuf pathname = STRBUF_INIT; + int err; + HANDLE h; + BOOL connected; + char buf[TEST_BUFSIZE + 1]; + + if (argc < 2) + goto print_usage; + filename = argv[1]; + if (strchr(filename, '/') || strchr(filename, '\\')) + goto print_usage; + strbuf_addf(&pathname, "//./pipe/%s", filename); + + /* + * Create a single instance of the server side of the named pipe. + * This will allow exactly one client instance to connect to it. + */ + h = CreateNamedPipeA( + pathname.buf, + PIPE_ACCESS_INBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, + TEST_BUFSIZE, TEST_BUFSIZE, 0, NULL); + if (h == INVALID_HANDLE_VALUE) { + err = err_win_to_posix(GetLastError()); + fprintf(stderr, "CreateNamedPipe failed: %s\n", + strerror(err)); + return err; + } + + connected = ConnectNamedPipe(h, NULL) + ? TRUE + : (GetLastError() == ERROR_PIPE_CONNECTED); + if (!connected) { + err = err_win_to_posix(GetLastError()); + fprintf(stderr, "ConnectNamedPipe failed: %s\n", + strerror(err)); + CloseHandle(h); + return err; + } + + while (1) { + DWORD nbr; + BOOL success = ReadFile(h, buf, TEST_BUFSIZE, &nbr, NULL); + if (!success || nbr == 0) + break; + buf[nbr] = 0; + + write(1, buf, nbr); + } + + DisconnectNamedPipe(h); + CloseHandle(h); + return 0; + +print_usage: + fprintf(stderr, "usage: %s %s\n", argv[0], usage_string); + return 1; +} +#endif diff --git a/t/oid-info/README b/t/oid-info/README new file mode 100644 index 0000000000..27f843fc00 --- /dev/null +++ b/t/oid-info/README @@ -0,0 +1,19 @@ +This directory contains various per-hash values that are used in the testsuite. + +Each file contains lines containing a key-value pair; blank lines and lines +starting with `#` are ignored. The key and value are separated by whitespace +(specifically, those whitespace in the default `$IFS`). The key consists only +of shell identifier characters, and the value consists of a hash algorithm, +colon, and value. The hash algorithm also consists only of shell identifier +characters; it should match the value in sha1-file.c. + +For example, the following lines map the key "rawsz" to "20" if SHA-1 is in use +and to "32" if SHA-256 is in use: + +---- +rawsz sha1:20 +rawsz sha256:32 +---- + +The keys and values used here are loaded by `test_oid_init` (see the README file +in the "t" directory) and are used by calling `test_oid`. diff --git a/t/oid-info/hash-info b/t/oid-info/hash-info new file mode 100644 index 0000000000..ccdbfdf974 --- /dev/null +++ b/t/oid-info/hash-info @@ -0,0 +1,8 @@ +rawsz sha1:20 +rawsz sha256:32 + +hexsz sha1:40 +hexsz sha256:64 + +zero sha1:0000000000000000000000000000000000000000 +zero sha256:0000000000000000000000000000000000000000000000000000000000000000 diff --git a/t/oid-info/oid b/t/oid-info/oid new file mode 100644 index 0000000000..a754970523 --- /dev/null +++ b/t/oid-info/oid @@ -0,0 +1,29 @@ +# These are some common invalid and partial object IDs used in tests. +001 sha1:0000000000000000000000000000000000000001 +001 sha256:0000000000000000000000000000000000000000000000000000000000000001 +002 sha1:0000000000000000000000000000000000000002 +002 sha256:0000000000000000000000000000000000000000000000000000000000000002 +003 sha1:0000000000000000000000000000000000000003 +003 sha256:0000000000000000000000000000000000000000000000000000000000000003 +004 sha1:0000000000000000000000000000000000000004 +004 sha256:0000000000000000000000000000000000000000000000000000000000000004 +005 sha1:0000000000000000000000000000000000000005 +005 sha256:0000000000000000000000000000000000000000000000000000000000000005 +006 sha1:0000000000000000000000000000000000000006 +006 sha256:0000000000000000000000000000000000000000000000000000000000000006 +007 sha1:0000000000000000000000000000000000000007 +007 sha256:0000000000000000000000000000000000000000000000000000000000000007 +# All zeros or Fs missing one or two hex segments. +zero_1 sha1:000000000000000000000000000000000000000 +zero_1 sha256:000000000000000000000000000000000000000000000000000000000000000 +zero_2 sha1:00000000000000000000000000000000000000 +zero_2 sha256:00000000000000000000000000000000000000000000000000000000000000 +ff_1 sha1:fffffffffffffffffffffffffffffffffffffff +ff_1 sha256:fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ff_2 sha1:ffffffffffffffffffffffffffffffffffffff +ff_2 sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +# More various invalid OIDs. +numeric sha1:0123456789012345678901234567890123456789 +numeric sha256:0123456789012345678901234567890123456789012345678901234567890123 +deadbeef sha1:deadbeefdeadbeefdeadbeefdeadbeefdeadbeef +deadbeef sha256:deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef diff --git a/t/perf/p1450-fsck.sh b/t/perf/p1450-fsck.sh new file mode 100755 index 0000000000..ae1b84198b --- /dev/null +++ b/t/perf/p1450-fsck.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +test_description='Test fsck performance' + +. ./perf-lib.sh + +test_perf_large_repo + +test_perf 'fsck' ' + git fsck +' + +test_done diff --git a/t/perf/p1451-fsck-skip-list.sh b/t/perf/p1451-fsck-skip-list.sh new file mode 100755 index 0000000000..c2b97d2487 --- /dev/null +++ b/t/perf/p1451-fsck-skip-list.sh @@ -0,0 +1,40 @@ +#!/bin/sh + +test_description='Test fsck skipList performance' + +. ./perf-lib.sh + +test_perf_fresh_repo + +n=1000000 + +test_expect_success "setup $n bad commits" ' + for i in $(test_seq 1 $n) + do + echo "commit refs/heads/master" && + echo "committer C <c@example.com> 1234567890 +0000" && + echo "data <<EOF" && + echo "$i.Q." && + echo "EOF" + done | q_to_nul | git fast-import +' + +skip=0 +while test $skip -le $n +do + test_expect_success "create skipList for $skip bad commits" ' + git log --format=%H --max-count=$skip | + sort >skiplist + ' + + test_perf "fsck with $skip skipped bad commits" ' + git -c fsck.skipList=skiplist fsck + ' + + case $skip in + 0) skip=1 ;; + *) skip=${skip}0 ;; + esac +done + +test_done diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh index 850f651e4e..391f910c6a 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -821,9 +821,87 @@ test_expect_success 'tests clean up even on failures' " EOF " +test_expect_success 'test_oid setup' ' + test_oid_init +' + +test_expect_success 'test_oid provides sane info by default' ' + test_oid zero >actual && + grep "^00*\$" actual && + rawsz="$(test_oid rawsz)" && + hexsz="$(test_oid hexsz)" && + test "$hexsz" -eq $(wc -c <actual) && + test $(( $rawsz * 2)) -eq "$hexsz" +' + +test_expect_success 'test_oid can look up data for SHA-1' ' + test_when_finished "test_detect_hash" && + test_set_hash sha1 && + test_oid zero >actual && + grep "^00*\$" actual && + rawsz="$(test_oid rawsz)" && + hexsz="$(test_oid hexsz)" && + test $(wc -c <actual) -eq 40 && + test "$rawsz" -eq 20 && + test "$hexsz" -eq 40 +' + +test_expect_success 'test_oid can look up data for SHA-256' ' + test_when_finished "test_detect_hash" && + test_set_hash sha256 && + test_oid zero >actual && + grep "^00*\$" actual && + rawsz="$(test_oid rawsz)" && + hexsz="$(test_oid hexsz)" && + test $(wc -c <actual) -eq 64 && + test "$rawsz" -eq 32 && + test "$hexsz" -eq 64 +' + ################################################################ # Basics of the basics +test_oid_cache <<\EOF +path0f sha1:f87290f8eb2cbbea7857214459a0739927eab154 +path0f sha256:638106af7c38be056f3212cbd7ac65bc1bac74f420ca5a436ff006a9d025d17d + +path0s sha1:15a98433ae33114b085f3eb3bb03b832b3180a01 +path0s sha256:3a24cc53cf68edddac490bbf94a418a52932130541361f685df685e41dd6c363 + +path2f sha1:3feff949ed00a62d9f7af97c15cd8a30595e7ac7 +path2f sha256:2a7f36571c6fdbaf0e3f62751a0b25a3f4c54d2d1137b3f4af9cb794bb498e5f + +path2s sha1:d8ce161addc5173867a3c3c730924388daedbc38 +path2s sha256:18fd611b787c2e938ddcc248fabe4d66a150f9364763e9ec133dd01d5bb7c65a + +path2d sha1:58a09c23e2ca152193f2786e06986b7b6712bdbe +path2d sha256:00e4b32b96e7e3d65d79112dcbea53238a22715f896933a62b811377e2650c17 + +path3f sha1:0aa34cae68d0878578ad119c86ca2b5ed5b28376 +path3f sha256:09f58616b951bd571b8cb9dc76d372fbb09ab99db2393f5ab3189d26c45099ad + +path3s sha1:8599103969b43aff7e430efea79ca4636466794f +path3s sha256:fce1aed087c053306f3f74c32c1a838c662bbc4551a7ac2420f5d6eb061374d0 + +path3d sha1:21ae8269cacbe57ae09138dcc3a2887f904d02b3 +path3d sha256:9b60497be959cb830bf3f0dc82bcc9ad9e925a24e480837ade46b2295e47efe1 + +subp3f sha1:00fb5908cb97c2564a9783c0c64087333b3b464f +subp3f sha256:a1a9e16998c988453f18313d10375ee1d0ddefe757e710dcae0d66aa1e0c58b3 + +subp3s sha1:6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c +subp3s sha256:81759d9f5e93c6546ecfcadb560c1ff057314b09f93fe8ec06e2d8610d34ef10 + +subp3d sha1:3c5e5399f3a333eddecce7a9b9465b63f65f51e2 +subp3d sha256:76b4ef482d4fa1c754390344cf3851c7f883b27cf9bc999c6547928c46aeafb7 + +root sha1:087704a96baf1c2d1c869a8b084481e121c88b5b +root sha256:9481b52abab1b2ffeedbf9de63ce422b929f179c1b98ff7bee5f8f1bc0710751 + +simpletree sha1:7bb943559a305bdd6bdee2cef6e5df2413c3d30a +simpletree sha256:1710c07a6c86f9a3c7376364df04c47ee39e5a5e221fcdd84b743bc9bb7e2bc5 +EOF + # updating a new file without --add should fail. test_expect_success 'git update-index without --add should fail adding' ' test_must_fail git update-index should-be-empty @@ -839,8 +917,8 @@ test_expect_success 'writing tree out with git write-tree' ' ' # we know the shape and contents of the tree and know the object ID for it. -test_expect_success SHA1 'validate object ID of a known tree' ' - test "$tree" = 7bb943559a305bdd6bdee2cef6e5df2413c3d30a +test_expect_success 'validate object ID of a known tree' ' + test "$tree" = "$(test_oid simpletree)" ' # Removing paths. @@ -882,16 +960,16 @@ test_expect_success 'showing stage with git ls-files --stage' ' git ls-files --stage >current ' -test_expect_success SHA1 'validate git ls-files output for a known tree' ' - cat >expected <<-\EOF && - 100644 f87290f8eb2cbbea7857214459a0739927eab154 0 path0 - 120000 15a98433ae33114b085f3eb3bb03b832b3180a01 0 path0sym - 100644 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 0 path2/file2 - 120000 d8ce161addc5173867a3c3c730924388daedbc38 0 path2/file2sym - 100644 0aa34cae68d0878578ad119c86ca2b5ed5b28376 0 path3/file3 - 120000 8599103969b43aff7e430efea79ca4636466794f 0 path3/file3sym - 100644 00fb5908cb97c2564a9783c0c64087333b3b464f 0 path3/subp3/file3 - 120000 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c 0 path3/subp3/file3sym +test_expect_success 'validate git ls-files output for a known tree' ' + cat >expected <<-EOF && + 100644 $(test_oid path0f) 0 path0 + 120000 $(test_oid path0s) 0 path0sym + 100644 $(test_oid path2f) 0 path2/file2 + 120000 $(test_oid path2s) 0 path2/file2sym + 100644 $(test_oid path3f) 0 path3/file3 + 120000 $(test_oid path3s) 0 path3/file3sym + 100644 $(test_oid subp3f) 0 path3/subp3/file3 + 120000 $(test_oid subp3s) 0 path3/subp3/file3sym EOF test_cmp expected current ' @@ -900,20 +978,20 @@ test_expect_success 'writing tree out with git write-tree' ' tree=$(git write-tree) ' -test_expect_success SHA1 'validate object ID for a known tree' ' - test "$tree" = 087704a96baf1c2d1c869a8b084481e121c88b5b +test_expect_success 'validate object ID for a known tree' ' + test "$tree" = "$(test_oid root)" ' test_expect_success 'showing tree with git ls-tree' ' git ls-tree $tree >current ' -test_expect_success SHA1 'git ls-tree output for a known tree' ' - cat >expected <<-\EOF && - 100644 blob f87290f8eb2cbbea7857214459a0739927eab154 path0 - 120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01 path0sym - 040000 tree 58a09c23e2ca152193f2786e06986b7b6712bdbe path2 - 040000 tree 21ae8269cacbe57ae09138dcc3a2887f904d02b3 path3 +test_expect_success 'git ls-tree output for a known tree' ' + cat >expected <<-EOF && + 100644 blob $(test_oid path0f) path0 + 120000 blob $(test_oid path0s) path0sym + 040000 tree $(test_oid path2d) path2 + 040000 tree $(test_oid path3d) path3 EOF test_cmp expected current ' @@ -924,16 +1002,16 @@ test_expect_success 'showing tree with git ls-tree -r' ' git ls-tree -r $tree >current ' -test_expect_success SHA1 'git ls-tree -r output for a known tree' ' - cat >expected <<-\EOF && - 100644 blob f87290f8eb2cbbea7857214459a0739927eab154 path0 - 120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01 path0sym - 100644 blob 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 path2/file2 - 120000 blob d8ce161addc5173867a3c3c730924388daedbc38 path2/file2sym - 100644 blob 0aa34cae68d0878578ad119c86ca2b5ed5b28376 path3/file3 - 120000 blob 8599103969b43aff7e430efea79ca4636466794f path3/file3sym - 100644 blob 00fb5908cb97c2564a9783c0c64087333b3b464f path3/subp3/file3 - 120000 blob 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c path3/subp3/file3sym +test_expect_success 'git ls-tree -r output for a known tree' ' + cat >expected <<-EOF && + 100644 blob $(test_oid path0f) path0 + 120000 blob $(test_oid path0s) path0sym + 100644 blob $(test_oid path2f) path2/file2 + 120000 blob $(test_oid path2s) path2/file2sym + 100644 blob $(test_oid path3f) path3/file3 + 120000 blob $(test_oid path3s) path3/file3sym + 100644 blob $(test_oid subp3f) path3/subp3/file3 + 120000 blob $(test_oid subp3s) path3/subp3/file3sym EOF test_cmp expected current ' @@ -943,19 +1021,19 @@ test_expect_success 'showing tree with git ls-tree -r -t' ' git ls-tree -r -t $tree >current ' -test_expect_success SHA1 'git ls-tree -r output for a known tree' ' - cat >expected <<-\EOF && - 100644 blob f87290f8eb2cbbea7857214459a0739927eab154 path0 - 120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01 path0sym - 040000 tree 58a09c23e2ca152193f2786e06986b7b6712bdbe path2 - 100644 blob 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 path2/file2 - 120000 blob d8ce161addc5173867a3c3c730924388daedbc38 path2/file2sym - 040000 tree 21ae8269cacbe57ae09138dcc3a2887f904d02b3 path3 - 100644 blob 0aa34cae68d0878578ad119c86ca2b5ed5b28376 path3/file3 - 120000 blob 8599103969b43aff7e430efea79ca4636466794f path3/file3sym - 040000 tree 3c5e5399f3a333eddecce7a9b9465b63f65f51e2 path3/subp3 - 100644 blob 00fb5908cb97c2564a9783c0c64087333b3b464f path3/subp3/file3 - 120000 blob 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c path3/subp3/file3sym +test_expect_success 'git ls-tree -r output for a known tree' ' + cat >expected <<-EOF && + 100644 blob $(test_oid path0f) path0 + 120000 blob $(test_oid path0s) path0sym + 040000 tree $(test_oid path2d) path2 + 100644 blob $(test_oid path2f) path2/file2 + 120000 blob $(test_oid path2s) path2/file2sym + 040000 tree $(test_oid path3d) path3 + 100644 blob $(test_oid path3f) path3/file3 + 120000 blob $(test_oid path3s) path3/file3sym + 040000 tree $(test_oid subp3d) path3/subp3 + 100644 blob $(test_oid subp3f) path3/subp3/file3 + 120000 blob $(test_oid subp3s) path3/subp3/file3sym EOF test_cmp expected current ' @@ -964,26 +1042,27 @@ test_expect_success 'writing partial tree out with git write-tree --prefix' ' ptree=$(git write-tree --prefix=path3) ' -test_expect_success SHA1 'validate object ID for a known tree' ' - test "$ptree" = 21ae8269cacbe57ae09138dcc3a2887f904d02b3 +test_expect_success 'validate object ID for a known tree' ' + test "$ptree" = $(test_oid path3d) ' test_expect_success 'writing partial tree out with git write-tree --prefix' ' ptree=$(git write-tree --prefix=path3/subp3) ' -test_expect_success SHA1 'validate object ID for a known tree' ' - test "$ptree" = 3c5e5399f3a333eddecce7a9b9465b63f65f51e2 +test_expect_success 'validate object ID for a known tree' ' + test "$ptree" = $(test_oid subp3d) ' test_expect_success 'put invalid objects into the index' ' rm -f .git/index && - cat >badobjects <<-\EOF && - 100644 blob 1000000000000000000000000000000000000000 dir/file1 - 100644 blob 2000000000000000000000000000000000000000 dir/file2 - 100644 blob 3000000000000000000000000000000000000000 dir/file3 - 100644 blob 4000000000000000000000000000000000000000 dir/file4 - 100644 blob 5000000000000000000000000000000000000000 dir/file5 + suffix=$(echo $ZERO_OID | sed -e "s/^.//") && + cat >badobjects <<-EOF && + 100644 blob $(test_oid 001) dir/file1 + 100644 blob $(test_oid 002) dir/file2 + 100644 blob $(test_oid 003) dir/file3 + 100644 blob $(test_oid 004) dir/file4 + 100644 blob $(test_oid 005) dir/file5 EOF git update-index --index-info <badobjects ' @@ -1006,16 +1085,16 @@ test_expect_success 'git read-tree followed by write-tree should be idempotent' test "$newtree" = "$tree" ' -test_expect_success SHA1 'validate git diff-files output for a know cache/work tree state' ' - cat >expected <<\EOF && -:100644 100644 f87290f8eb2cbbea7857214459a0739927eab154 0000000000000000000000000000000000000000 M path0 -:120000 120000 15a98433ae33114b085f3eb3bb03b832b3180a01 0000000000000000000000000000000000000000 M path0sym -:100644 100644 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 0000000000000000000000000000000000000000 M path2/file2 -:120000 120000 d8ce161addc5173867a3c3c730924388daedbc38 0000000000000000000000000000000000000000 M path2/file2sym -:100644 100644 0aa34cae68d0878578ad119c86ca2b5ed5b28376 0000000000000000000000000000000000000000 M path3/file3 -:120000 120000 8599103969b43aff7e430efea79ca4636466794f 0000000000000000000000000000000000000000 M path3/file3sym -:100644 100644 00fb5908cb97c2564a9783c0c64087333b3b464f 0000000000000000000000000000000000000000 M path3/subp3/file3 -:120000 120000 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c 0000000000000000000000000000000000000000 M path3/subp3/file3sym +test_expect_success 'validate git diff-files output for a know cache/work tree state' ' + cat >expected <<EOF && +:100644 100644 $(test_oid path0f) $ZERO_OID M path0 +:120000 120000 $(test_oid path0s) $ZERO_OID M path0sym +:100644 100644 $(test_oid path2f) $ZERO_OID M path2/file2 +:120000 120000 $(test_oid path2s) $ZERO_OID M path2/file2sym +:100644 100644 $(test_oid path3f) $ZERO_OID M path3/file3 +:120000 120000 $(test_oid path3s) $ZERO_OID M path3/file3sym +:100644 100644 $(test_oid subp3f) $ZERO_OID M path3/subp3/file3 +:120000 120000 $(test_oid subp3s) $ZERO_OID M path3/subp3/file3sym EOF git diff-files >current && test_cmp current expected @@ -1031,23 +1110,23 @@ test_expect_success 'no diff after checkout and git update-index --refresh' ' ' ################################################################ -P=087704a96baf1c2d1c869a8b084481e121c88b5b +P=$(test_oid root) -test_expect_success SHA1 'git commit-tree records the correct tree in a commit' ' +test_expect_success 'git commit-tree records the correct tree in a commit' ' commit0=$(echo NO | git commit-tree $P) && tree=$(git show --pretty=raw $commit0 | sed -n -e "s/^tree //p" -e "/^author /q") && test "z$tree" = "z$P" ' -test_expect_success SHA1 'git commit-tree records the correct parent in a commit' ' +test_expect_success 'git commit-tree records the correct parent in a commit' ' commit1=$(echo NO | git commit-tree $P -p $commit0) && parent=$(git show --pretty=raw $commit1 | sed -n -e "s/^parent //p" -e "/^author /q") && test "z$commit0" = "z$parent" ' -test_expect_success SHA1 'git commit-tree omits duplicated parent in a commit' ' +test_expect_success 'git commit-tree omits duplicated parent in a commit' ' commit2=$(echo NO | git commit-tree $P -p $commit0 -p $commit0) && parent=$(git show --pretty=raw $commit2 | sed -n -e "s/^parent //p" -e "/^author /q" | diff --git a/t/t0002-gitfile.sh b/t/t0002-gitfile.sh index 3691023d51..0aa9908ea1 100755 --- a/t/t0002-gitfile.sh +++ b/t/t0002-gitfile.sh @@ -92,11 +92,12 @@ test_expect_success 'enter_repo non-strict mode' ' mv .git .realgit && echo "gitdir: .realgit" >.git ) && + head=$(git -C enter_repo rev-parse HEAD) && git ls-remote enter_repo >actual && - cat >expected <<-\EOF && - 946e985ab20de757ca5b872b16d64e92ff3803a9 HEAD - 946e985ab20de757ca5b872b16d64e92ff3803a9 refs/heads/master - 946e985ab20de757ca5b872b16d64e92ff3803a9 refs/tags/foo + cat >expected <<-EOF && + $head HEAD + $head refs/heads/master + $head refs/tags/foo EOF test_cmp expected actual ' @@ -106,21 +107,23 @@ test_expect_success 'enter_repo linked checkout' ' cd enter_repo && git worktree add ../foo refs/tags/foo ) && + head=$(git -C enter_repo rev-parse HEAD) && git ls-remote foo >actual && - cat >expected <<-\EOF && - 946e985ab20de757ca5b872b16d64e92ff3803a9 HEAD - 946e985ab20de757ca5b872b16d64e92ff3803a9 refs/heads/master - 946e985ab20de757ca5b872b16d64e92ff3803a9 refs/tags/foo + cat >expected <<-EOF && + $head HEAD + $head refs/heads/master + $head refs/tags/foo EOF test_cmp expected actual ' test_expect_success 'enter_repo strict mode' ' + head=$(git -C enter_repo rev-parse HEAD) && git ls-remote --upload-pack="git upload-pack --strict" foo/.git >actual && - cat >expected <<-\EOF && - 946e985ab20de757ca5b872b16d64e92ff3803a9 HEAD - 946e985ab20de757ca5b872b16d64e92ff3803a9 refs/heads/master - 946e985ab20de757ca5b872b16d64e92ff3803a9 refs/tags/foo + cat >expected <<-EOF && + $head HEAD + $head refs/heads/master + $head refs/tags/foo EOF test_cmp expected actual ' diff --git a/t/t0014-alias.sh b/t/t0014-alias.sh new file mode 100755 index 0000000000..a070e645d7 --- /dev/null +++ b/t/t0014-alias.sh @@ -0,0 +1,40 @@ +#!/bin/sh + +test_description='git command aliasing' + +. ./test-lib.sh + +test_expect_success 'nested aliases - internal execution' ' + git config alias.nested-internal-1 nested-internal-2 && + git config alias.nested-internal-2 status && + git nested-internal-1 >output && + test_i18ngrep "^On branch " output +' + +test_expect_success 'nested aliases - mixed execution' ' + git config alias.nested-external-1 nested-external-2 && + git config alias.nested-external-2 "!git nested-external-3" && + git config alias.nested-external-3 status && + git nested-external-1 >output && + test_i18ngrep "^On branch " output +' + +test_expect_success 'looping aliases - internal execution' ' + git config alias.loop-internal-1 loop-internal-2 && + git config alias.loop-internal-2 loop-internal-3 && + git config alias.loop-internal-3 loop-internal-2 && + test_must_fail git loop-internal-1 2>output && + test_i18ngrep "^fatal: alias loop detected: expansion of" output +' + +# This test is disabled until external loops are fixed, because would block +# the test suite for a full minute. +# +#test_expect_failure 'looping aliases - mixed execution' ' +# git config alias.loop-mixed-1 loop-mixed-2 && +# git config alias.loop-mixed-2 "!git loop-mixed-1" && +# test_must_fail git loop-mixed-1 2>output && +# test_i18ngrep "^fatal: alias loop detected: expansion of" output +#' + +test_done diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh index 5b0560fa20..17d0c18feb 100755 --- a/t/t0040-parse-options.sh +++ b/t/t0040-parse-options.sh @@ -8,7 +8,7 @@ test_description='our own option parser' . ./test-lib.sh cat >expect <<\EOF -usage: test-parse-options <options> +usage: test-tool parse-options <options> A helper function for the parse-options API. @@ -52,7 +52,7 @@ Standard options EOF test_expect_success 'test help' ' - test_must_fail test-parse-options -h >output 2>output.err && + test_must_fail test-tool parse-options -h >output 2>output.err && test_must_be_empty output.err && test_i18ncmp expect output ' @@ -64,7 +64,7 @@ check () { shift && expect="$1" && shift && - test-parse-options --expect="$what $expect" "$@" + test-tool parse-options --expect="$what $expect" "$@" } check_unknown_i18n() { @@ -75,7 +75,7 @@ check_unknown_i18n() { echo error: unknown switch \`${1#-}\' >expect ;; esac && cat expect.err >>expect && - test_must_fail test-parse-options $* >output 2>output.err && + test_must_fail test-tool parse-options $* >output 2>output.err && test_must_be_empty output && test_i18ncmp expect output.err } @@ -133,7 +133,7 @@ file: prefix/my.file EOF test_expect_success 'short options' ' - test-parse-options -s123 -b -i 1729 -m 16k -b -vv -n -F my.file \ + test-tool parse-options -s123 -b -i 1729 -m 16k -b -vv -n -F my.file \ >output 2>output.err && test_cmp expect output && test_must_be_empty output.err @@ -153,7 +153,7 @@ file: prefix/fi.le EOF test_expect_success 'long options' ' - test-parse-options --boolean --integer 1729 --magnitude 16k \ + test-tool parse-options --boolean --integer 1729 --magnitude 16k \ --boolean --string2=321 --verbose --verbose --no-dry-run \ --abbrev=10 --file fi.le --obsolete \ >output 2>output.err && @@ -162,9 +162,9 @@ test_expect_success 'long options' ' ' test_expect_success 'missing required value' ' - test_expect_code 129 test-parse-options -s && - test_expect_code 129 test-parse-options --string && - test_expect_code 129 test-parse-options --file + test_expect_code 129 test-tool parse-options -s && + test_expect_code 129 test-tool parse-options --string && + test_expect_code 129 test-tool parse-options --file ' cat >expect <<\EOF @@ -184,7 +184,7 @@ arg 02: --boolean EOF test_expect_success 'intermingled arguments' ' - test-parse-options a1 --string 123 b1 --boolean -j 13 -- --boolean \ + test-tool parse-options a1 --string 123 b1 --boolean -j 13 -- --boolean \ >output 2>output.err && test_must_be_empty output.err && test_cmp expect output @@ -204,21 +204,21 @@ file: (not set) EOF test_expect_success 'unambiguously abbreviated option' ' - test-parse-options --int 2 --boolean --no-bo >output 2>output.err && + test-tool parse-options --int 2 --boolean --no-bo >output 2>output.err && test_must_be_empty output.err && test_cmp expect output ' test_expect_success 'unambiguously abbreviated option with "="' ' - test-parse-options --expect="integer: 2" --int=2 + test-tool parse-options --expect="integer: 2" --int=2 ' test_expect_success 'ambiguously abbreviated option' ' - test_expect_code 129 test-parse-options --strin 123 + test_expect_code 129 test-tool parse-options --strin 123 ' test_expect_success 'non ambiguous option (after two options it abbreviates)' ' - test-parse-options --expect="string: 123" --st 123 + test-tool parse-options --expect="string: 123" --st 123 ' cat >typo.err <<\EOF @@ -226,7 +226,7 @@ error: did you mean `--boolean` (with two dashes ?) EOF test_expect_success 'detect possible typos' ' - test_must_fail test-parse-options -boolean >output 2>output.err && + test_must_fail test-tool parse-options -boolean >output 2>output.err && test_must_be_empty output && test_cmp typo.err output.err ' @@ -236,13 +236,13 @@ error: did you mean `--ambiguous` (with two dashes ?) EOF test_expect_success 'detect possible typos' ' - test_must_fail test-parse-options -ambiguous >output 2>output.err && + test_must_fail test-tool parse-options -ambiguous >output 2>output.err && test_must_be_empty output && test_cmp typo.err output.err ' test_expect_success 'keep some options as arguments' ' - test-parse-options --expect="arg 00: --quux" --quux + test-tool parse-options --expect="arg 00: --quux" --quux ' cat >expect <<\EOF @@ -260,7 +260,7 @@ arg 00: foo EOF test_expect_success 'OPT_DATE() works' ' - test-parse-options -t "1970-01-01 00:00:01 +0000" \ + 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 @@ -281,13 +281,13 @@ file: (not set) EOF test_expect_success 'OPT_CALLBACK() and OPT_BIT() work' ' - test-parse-options --length=four -b -4 >output 2>output.err && + test-tool parse-options --length=four -b -4 >output 2>output.err && test_must_be_empty output.err && test_cmp expect output ' test_expect_success 'OPT_CALLBACK() and callback errors work' ' - test_must_fail test-parse-options --no-length >output 2>output.err && + test_must_fail test-tool parse-options --no-length >output 2>output.err && test_must_be_empty output && test_must_be_empty output.err ' @@ -306,31 +306,31 @@ file: (not set) EOF test_expect_success 'OPT_BIT() and OPT_SET_INT() work' ' - test-parse-options --set23 -bbbbb --no-or4 >output 2>output.err && + test-tool parse-options --set23 -bbbbb --no-or4 >output 2>output.err && test_must_be_empty output.err && test_cmp expect output ' test_expect_success 'OPT_NEGBIT() and OPT_SET_INT() work' ' - test-parse-options --set23 -bbbbb --neg-or4 >output 2>output.err && + test-tool parse-options --set23 -bbbbb --neg-or4 >output 2>output.err && test_must_be_empty output.err && test_cmp expect output ' test_expect_success 'OPT_BIT() works' ' - test-parse-options --expect="boolean: 6" -bb --or4 + test-tool parse-options --expect="boolean: 6" -bb --or4 ' test_expect_success 'OPT_NEGBIT() works' ' - test-parse-options --expect="boolean: 6" -bb --no-neg-or4 + test-tool parse-options --expect="boolean: 6" -bb --no-neg-or4 ' test_expect_success 'OPT_COUNTUP() with PARSE_OPT_NODASH works' ' - test-parse-options --expect="boolean: 6" + + + + + + + test-tool parse-options --expect="boolean: 6" + + + + + + ' test_expect_success 'OPT_NUMBER_CALLBACK() works' ' - test-parse-options --expect="integer: 12345" -12345 + test-tool parse-options --expect="integer: 12345" -12345 ' cat >expect <<\EOF @@ -347,7 +347,7 @@ file: (not set) EOF test_expect_success 'negation of OPT_NONEG flags is not ambiguous' ' - test-parse-options --no-ambig >output 2>output.err && + test-tool parse-options --no-ambig >output 2>output.err && test_must_be_empty output.err && test_cmp expect output ' @@ -358,38 +358,38 @@ list: bar list: baz EOF test_expect_success '--list keeps list of strings' ' - test-parse-options --list foo --list=bar --list=baz >output && + test-tool parse-options --list foo --list=bar --list=baz >output && test_cmp expect output ' test_expect_success '--no-list resets list' ' - test-parse-options --list=other --list=irrelevant --list=options \ + test-tool parse-options --list=other --list=irrelevant --list=options \ --no-list --list=foo --list=bar --list=baz >output && test_cmp expect output ' test_expect_success 'multiple quiet levels' ' - test-parse-options --expect="quiet: 3" -q -q -q + test-tool parse-options --expect="quiet: 3" -q -q -q ' test_expect_success 'multiple verbose levels' ' - test-parse-options --expect="verbose: 3" -v -v -v + test-tool parse-options --expect="verbose: 3" -v -v -v ' test_expect_success '--no-quiet sets --quiet to 0' ' - test-parse-options --expect="quiet: 0" --no-quiet + test-tool parse-options --expect="quiet: 0" --no-quiet ' test_expect_success '--no-quiet resets multiple -q to 0' ' - test-parse-options --expect="quiet: 0" -q -q -q --no-quiet + test-tool parse-options --expect="quiet: 0" -q -q -q --no-quiet ' test_expect_success '--no-verbose sets verbose to 0' ' - test-parse-options --expect="verbose: 0" --no-verbose + test-tool parse-options --expect="verbose: 0" --no-verbose ' test_expect_success '--no-verbose resets multiple verbose to 0' ' - test-parse-options --expect="verbose: 0" -v -v -v --no-verbose + test-tool parse-options --expect="verbose: 0" -v -v -v --no-verbose ' test_done diff --git a/t/t0051-windows-named-pipe.sh b/t/t0051-windows-named-pipe.sh new file mode 100755 index 0000000000..10ac92d225 --- /dev/null +++ b/t/t0051-windows-named-pipe.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +test_description='Windows named pipes' + +. ./test-lib.sh + +test_expect_success MINGW 'o_append write to named pipe' ' + GIT_TRACE="$(pwd)/expect" git status >/dev/null 2>&1 && + { test-tool windows-named-pipe t0051 >actual 2>&1 & } && + pid=$! && + sleep 1 && + GIT_TRACE=//./pipe/t0051 git status >/dev/null 2>warning && + wait $pid && + test_cmp expect actual +' + +test_done diff --git a/t/t0064-sha1-array.sh b/t/t0064-sha1-array.sh index 67484502a0..5dda570b9a 100755 --- a/t/t0064-sha1-array.sh +++ b/t/t0064-sha1-array.sh @@ -3,30 +3,30 @@ test_description='basic tests for the SHA1 array implementation' . ./test-lib.sh -echo20 () { +echoid () { prefix="${1:+$1 }" shift while test $# -gt 0 do - echo "$prefix$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1" + echo "$prefix$ZERO_OID" | sed -e "s/00/$1/g" shift done } test_expect_success 'ordered enumeration' ' - echo20 "" 44 55 88 aa >expect && + echoid "" 44 55 88 aa >expect && { - echo20 append 88 44 aa 55 && + echoid append 88 44 aa 55 && echo for_each_unique } | test-tool sha1-array >actual && test_cmp expect actual ' test_expect_success 'ordered enumeration with duplicate suppression' ' - echo20 "" 44 55 88 aa >expect && + echoid "" 44 55 88 aa >expect && { - echo20 append 88 44 aa 55 && - echo20 append 88 44 aa 55 && + echoid append 88 44 aa 55 && + echoid append 88 44 aa 55 && echo for_each_unique } | test-tool sha1-array >actual && test_cmp expect actual @@ -34,8 +34,8 @@ test_expect_success 'ordered enumeration with duplicate suppression' ' test_expect_success 'lookup' ' { - echo20 append 88 44 aa 55 && - echo20 lookup 55 + echoid append 88 44 aa 55 && + echoid lookup 55 } | test-tool sha1-array >actual && n=$(cat actual) && test "$n" -eq 1 @@ -43,8 +43,8 @@ test_expect_success 'lookup' ' test_expect_success 'lookup non-existing entry' ' { - echo20 append 88 44 aa 55 && - echo20 lookup 33 + echoid append 88 44 aa 55 && + echoid lookup 33 } | test-tool sha1-array >actual && n=$(cat actual) && test "$n" -lt 0 @@ -52,9 +52,9 @@ test_expect_success 'lookup non-existing entry' ' test_expect_success 'lookup with duplicates' ' { - echo20 append 88 44 aa 55 && - echo20 append 88 44 aa 55 && - echo20 lookup 55 + echoid append 88 44 aa 55 && + echoid append 88 44 aa 55 && + echoid lookup 55 } | test-tool sha1-array >actual && n=$(cat actual) && test "$n" -ge 2 && @@ -63,19 +63,24 @@ test_expect_success 'lookup with duplicates' ' test_expect_success 'lookup non-existing entry with duplicates' ' { - echo20 append 88 44 aa 55 && - echo20 append 88 44 aa 55 && - echo20 lookup 66 + echoid append 88 44 aa 55 && + echoid append 88 44 aa 55 && + echoid lookup 66 } | test-tool sha1-array >actual && n=$(cat actual) && test "$n" -lt 0 ' test_expect_success 'lookup with almost duplicate values' ' + # n-1 5s + root=$(echoid "" 55) && + root=${root%5} && { - echo "append 5555555555555555555555555555555555555555" && - echo "append 555555555555555555555555555555555555555f" && - echo20 lookup 55 + id1="${root}5" && + id2="${root}f" && + echo "append $id1" && + echo "append $id2" && + echoid lookup 55 } | test-tool sha1-array >actual && n=$(cat actual) && test "$n" -eq 0 @@ -83,8 +88,8 @@ test_expect_success 'lookup with almost duplicate values' ' test_expect_success 'lookup with single duplicate value' ' { - echo20 append 55 55 && - echo20 lookup 55 + echoid append 55 55 && + echoid lookup 55 } | test-tool sha1-array >actual && n=$(cat actual) && test "$n" -ge 0 && diff --git a/t/t0090-cache-tree.sh b/t/t0090-cache-tree.sh index 7de40141ca..504334e552 100755 --- a/t/t0090-cache-tree.sh +++ b/t/t0090-cache-tree.sh @@ -161,6 +161,24 @@ test_expect_success PERL 'commit --interactive gives cache-tree on partial commi test_cache_tree ' +test_expect_success PERL 'commit -p with shrinking cache-tree' ' + mkdir -p deep/subdir && + echo content >deep/subdir/file && + git add deep && + git commit -m add && + git rm -r deep && + + before=$(wc -c <.git/index) && + git commit -m delete -p && + after=$(wc -c <.git/index) && + + # double check that the index shrank + test $before -gt $after && + + # and that our index was not corrupted + git fsck +' + test_expect_success 'commit in child dir has cache-tree' ' mkdir dir && >dir/child.t && @@ -243,13 +261,16 @@ test_expect_success 'no phantom error when switching trees' ' ' test_expect_success 'switching trees does not invalidate shared index' ' - git update-index --split-index && - >split && - git add split && - test-tool dump-split-index .git/index | grep -v ^own >before && - git commit -m "as-is" && - test-tool dump-split-index .git/index | grep -v ^own >after && - test_cmp before after + ( + sane_unset GIT_TEST_SPLIT_INDEX && + git update-index --split-index && + >split && + git add split && + test-tool dump-split-index .git/index | grep -v ^own >before && + git commit -m "as-is" && + test-tool dump-split-index .git/index | grep -v ^own >after && + test_cmp before after + ) ' test_done diff --git a/t/t0410-partial-clone.sh b/t/t0410-partial-clone.sh index b35bc89f1e..cfd0655ea1 100755 --- a/t/t0410-partial-clone.sh +++ b/t/t0410-partial-clone.sh @@ -170,6 +170,18 @@ test_expect_success 'fetching of missing objects' ' git verify-pack --verbose "$IDX" | grep "$HASH" ' +test_expect_success 'fetching of missing objects works with ref-in-want enabled' ' + # ref-in-want requires protocol version 2 + git -C server config protocol.version 2 && + git -C server config uploadpack.allowrefinwant 1 && + git -C repo config protocol.version 2 && + + rm -rf repo/.git/objects/* && + rm -f trace && + GIT_TRACE_PACKET="$(pwd)/trace" git -C repo cat-file -p "$HASH" && + grep "git< fetch=.*ref-in-want" trace +' + test_expect_success 'rev-list stops traversal at missing and promised commit' ' rm -rf repo && test_create_repo repo && diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh index 7f19d591f2..a7c95bb785 100755 --- a/t/t1006-cat-file.sh +++ b/t/t1006-cat-file.sh @@ -140,15 +140,17 @@ test_expect_success '--batch-check without %(rest) considers whole line' ' test_cmp expect actual ' +test_oid_init + tree_sha1=$(git write-tree) -tree_size=33 +tree_size=$(($(test_oid rawsz) + 13)) tree_pretty_content="100644 blob $hello_sha1 hello" run_tests 'tree' $tree_sha1 $tree_size "" "$tree_pretty_content" commit_message="Initial commit" commit_sha1=$(echo_without_newline "$commit_message" | git commit-tree $tree_sha1) -commit_size=177 +commit_size=$(($(test_oid hexsz) + 137)) commit_content="tree $tree_sha1 author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> 0000000000 +0000 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 0000000000 +0000 diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh index 7c8df20955..663f17c5fe 100755 --- a/t/t1400-update-ref.sh +++ b/t/t1400-update-ref.sh @@ -346,7 +346,7 @@ test_expect_success "verifying $m's log (logged by config)" ' git update-ref $m $D cat >.git/logs/$m <<EOF -0000000000000000000000000000000000000000 $C $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150320 -0500 +$Z $C $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150320 -0500 $C $A $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150350 -0500 $A $B $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150380 -0500 $F $Z $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150680 -0500 @@ -807,6 +807,37 @@ test_expect_success 'stdin delete symref works option no-deref' ' test_cmp expect actual ' +test_expect_success 'stdin update symref works flag --no-deref' ' + git symbolic-ref TESTSYMREFONE $b && + git symbolic-ref TESTSYMREFTWO $b && + cat >stdin <<-EOF && + update TESTSYMREFONE $a $b + update TESTSYMREFTWO $a $b + EOF + git update-ref --no-deref --stdin <stdin && + git rev-parse TESTSYMREFONE TESTSYMREFTWO >expect && + git rev-parse $a $a >actual && + test_cmp expect actual && + git rev-parse $m~1 >expect && + git rev-parse $b >actual && + test_cmp expect actual +' + +test_expect_success 'stdin delete symref works flag --no-deref' ' + git symbolic-ref TESTSYMREFONE $b && + git symbolic-ref TESTSYMREFTWO $b && + cat >stdin <<-EOF && + delete TESTSYMREFONE $b + delete TESTSYMREFTWO $b + EOF + git update-ref --no-deref --stdin <stdin && + test_must_fail git rev-parse --verify -q TESTSYMREFONE && + test_must_fail git rev-parse --verify -q TESTSYMREFTWO && + git rev-parse $m~1 >expect && + git rev-parse $b >actual && + test_cmp expect actual +' + test_expect_success 'stdin delete ref works with right old value' ' echo "delete $b $m~1" >stdin && git update-ref --stdin <stdin && diff --git a/t/t1405-main-ref-store.sh b/t/t1405-main-ref-store.sh index a74c38b5fb..331899ddc4 100755 --- a/t/t1405-main-ref-store.sh +++ b/t/t1405-main-ref-store.sh @@ -54,7 +54,7 @@ test_expect_success 'for_each_ref(refs/heads/)' ' ' test_expect_success 'for_each_ref() is sorted' ' - $RUN for-each-ref refs/heads/ | cut -c 42- >actual && + $RUN for-each-ref refs/heads/ | cut -d" " -f 2- >actual && sort actual > expected && test_cmp expected actual ' @@ -71,7 +71,7 @@ test_expect_success 'verify_ref(new-master)' ' ' test_expect_success 'for_each_reflog()' ' - $RUN for-each-reflog | sort -k2 | cut -c 42- >actual && + $RUN for-each-reflog | sort -k2 | cut -d" " -f 2- >actual && cat >expected <<-\EOF && HEAD 0x1 refs/heads/master 0x0 diff --git a/t/t1406-submodule-ref-store.sh b/t/t1406-submodule-ref-store.sh index e093782cc3..d199d872fb 100755 --- a/t/t1406-submodule-ref-store.sh +++ b/t/t1406-submodule-ref-store.sh @@ -39,7 +39,7 @@ test_expect_success 'rename_refs() not allowed' ' ' test_expect_success 'for_each_ref(refs/heads/)' ' - $RUN for-each-ref refs/heads/ | cut -c 42- >actual && + $RUN for-each-ref refs/heads/ | cut -d" " -f 2- >actual && cat >expected <<-\EOF && master 0x0 new-master 0x0 @@ -48,7 +48,7 @@ test_expect_success 'for_each_ref(refs/heads/)' ' ' test_expect_success 'for_each_ref() is sorted' ' - $RUN for-each-ref refs/heads/ | cut -c 42- >actual && + $RUN for-each-ref refs/heads/ | cut -d" " -f 2- >actual && sort actual > expected && test_cmp expected actual ' @@ -65,7 +65,7 @@ test_expect_success 'verify_ref(new-master)' ' ' test_expect_success 'for_each_reflog()' ' - $RUN for-each-reflog | sort | cut -c 42- >actual && + $RUN for-each-reflog | sort | cut -d" " -f 2- >actual && cat >expected <<-\EOF && HEAD 0x1 refs/heads/master 0x0 diff --git a/t/t1407-worktree-ref-store.sh b/t/t1407-worktree-ref-store.sh index 4623ae15c4..9a84858118 100755 --- a/t/t1407-worktree-ref-store.sh +++ b/t/t1407-worktree-ref-store.sh @@ -58,7 +58,7 @@ test_expect_success 'for_each_reflog()' ' mkdir -p .git/worktrees/wt/logs/refs/bisect && echo $ZERO_OID > .git/worktrees/wt/logs/refs/bisect/wt-random && - $RWT for-each-reflog | cut -c 42- | sort >actual && + $RWT for-each-reflog | cut -d" " -f 2- | sort >actual && cat >expected <<-\EOF && HEAD 0x1 PSEUDO-WT 0x0 @@ -68,7 +68,7 @@ test_expect_success 'for_each_reflog()' ' EOF test_cmp expected actual && - $RMAIN for-each-reflog | cut -c 42- | sort >actual && + $RMAIN for-each-reflog | cut -d" " -f 2- | sort >actual && cat >expected <<-\EOF && HEAD 0x1 PSEUDO-MAIN 0x0 diff --git a/t/t1700-split-index.sh b/t/t1700-split-index.sh index b3b4d83eaf..be22398a85 100755 --- a/t/t1700-split-index.sh +++ b/t/t1700-split-index.sh @@ -57,7 +57,7 @@ test_expect_success 'disable split index' ' EOF test_cmp ls-files.expect ls-files.actual && - BASE=$(test-tool dump-split-index .git/index | grep "^own" | sed "s/own/base/") && + BASE=$(test-tool dump-split-index .git/index | sed -n "s/^own/base/p") && test-tool dump-split-index .git/index | sed "/^own/d" >actual && cat >expect <<-EOF && not a split index diff --git a/t/t3206-range-diff.sh b/t/t3206-range-diff.sh index 88ebed1dfa..045aca1c18 100755 --- a/t/t3206-range-diff.sh +++ b/t/t3206-range-diff.sh @@ -122,6 +122,11 @@ test_expect_success 'changed commit' ' test_cmp expected actual ' +test_expect_success 'no commits on one side' ' + git commit --amend -m "new message" && + git range-diff master HEAD@{1} HEAD +' + test_expect_success 'changed message' ' git range-diff --no-color topic...changed-message >actual && sed s/Z/\ /g >expected <<-EOF && @@ -193,4 +198,9 @@ do ' done +test_expect_success 'format-patch --range-diff as commentary' ' + git format-patch --stdout --range-diff=HEAD~1 HEAD~1 >actual && + test_i18ngrep "^Range-diff:$" actual +' + test_done diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index 86bba5ed7c..ff89b6341a 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -569,16 +569,15 @@ test_expect_success '--continue tries to commit, even for "edit"' ' ' test_expect_success 'aborted --continue does not squash commits after "edit"' ' - test_when_finished "git rebase --abort" && old=$(git rev-parse HEAD) && test_tick && set_fake_editor && FAKE_LINES="edit 1" git rebase -i HEAD^ && echo "edited again" > file7 && git add file7 && - echo all the things >>conflict && - test_must_fail git rebase --continue && - test $old = $(git rev-parse HEAD) + test_must_fail env FAKE_COMMIT_MESSAGE=" " git rebase --continue && + test $old = $(git rev-parse HEAD) && + git rebase --abort ' test_expect_success 'auto-amend only edited commits after "edit"' ' diff --git a/t/t3405-rebase-malformed.sh b/t/t3405-rebase-malformed.sh index da94dddc86..860e63e444 100755 --- a/t/t3405-rebase-malformed.sh +++ b/t/t3405-rebase-malformed.sh @@ -83,7 +83,7 @@ test_expect_success 'rebase -m commit with empty message' ' test_expect_success 'rebase -i commit with empty message' ' git checkout diff-in-message && set_fake_editor && - env FAKE_COMMIT_MESSAGE=" " FAKE_LINES="reword 1" \ + test_must_fail env FAKE_COMMIT_MESSAGE=" " FAKE_LINES="reword 1" \ git rebase -i HEAD^ ' diff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh index e364c12622..13f5688135 100755 --- a/t/t3415-rebase-autosquash.sh +++ b/t/t3415-rebase-autosquash.sh @@ -330,4 +330,23 @@ test_expect_success 'wrapped original subject' ' test $base = $parent ' +test_expect_success 'abort last squash' ' + test_when_finished "test_might_fail git rebase --abort" && + test_when_finished "git checkout master" && + + git checkout -b some-squashes && + git commit --allow-empty -m first && + git commit --allow-empty --squash HEAD && + git commit --allow-empty -m second && + git commit --allow-empty --squash HEAD && + + test_must_fail git -c core.editor="grep -q ^pick" \ + rebase -ki --autosquash HEAD~4 && + : do not finish the squash, but resolve it manually && + git commit --allow-empty --amend -m edited-first && + git rebase --skip && + git show >actual && + ! grep first actual +' + test_done diff --git a/t/t3505-cherry-pick-empty.sh b/t/t3505-cherry-pick-empty.sh index fbdc47cfbd..5f911bb529 100755 --- a/t/t3505-cherry-pick-empty.sh +++ b/t/t3505-cherry-pick-empty.sh @@ -11,17 +11,14 @@ test_expect_success setup ' test_tick && git commit -m "first" && - git checkout -b empty-branch && - test_tick && - git commit --allow-empty -m "empty" && - + git checkout -b empty-message-branch && echo third >> file1 && git add file1 && test_tick && git commit --allow-empty-message -m "" && git checkout master && - git checkout -b empty-branch2 && + git checkout -b empty-change-branch && test_tick && git commit --allow-empty -m "empty" @@ -29,7 +26,7 @@ test_expect_success setup ' test_expect_success 'cherry-pick an empty commit' ' git checkout master && - test_expect_code 1 git cherry-pick empty-branch^ + test_expect_code 1 git cherry-pick empty-change-branch ' test_expect_success 'index lockfile was removed' ' @@ -37,8 +34,9 @@ test_expect_success 'index lockfile was removed' ' ' test_expect_success 'cherry-pick a commit with an empty message' ' + test_when_finished "git reset --hard empty-message-branch~1" && git checkout master && - test_expect_code 1 git cherry-pick empty-branch + git cherry-pick empty-message-branch ' test_expect_success 'index lockfile was removed' ' @@ -47,7 +45,7 @@ test_expect_success 'index lockfile was removed' ' test_expect_success 'cherry-pick a commit with an empty message with --allow-empty-message' ' git checkout -f master && - git cherry-pick --allow-empty-message empty-branch + git cherry-pick --allow-empty-message empty-message-branch ' test_expect_success 'cherry pick an empty non-ff commit without --allow-empty' ' @@ -55,12 +53,12 @@ test_expect_success 'cherry pick an empty non-ff commit without --allow-empty' ' echo fourth >>file2 && git add file2 && git commit -m "fourth" && - test_must_fail git cherry-pick empty-branch2 + test_must_fail git cherry-pick empty-change-branch ' test_expect_success 'cherry pick an empty non-ff commit with --allow-empty' ' git checkout master && - git cherry-pick --allow-empty empty-branch2 + git cherry-pick --allow-empty empty-change-branch ' test_expect_success 'cherry pick with --keep-redundant-commits' ' diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh index 609fbfdc31..65dfbc033a 100755 --- a/t/t3701-add-interactive.sh +++ b/t/t3701-add-interactive.sh @@ -540,7 +540,7 @@ test_expect_success 'add -p does not expand argument lists' ' # update it, but we want to be sure that our "." pathspec # was not expanded into the argument list of any command. # So look only for "not-changed". - ! grep not-changed trace.out + ! grep -E "^trace: (built-in|exec|run_command): .*not-changed" trace.out ' test_expect_success 'hunk-editing handles custom comment char' ' diff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh index 428b3c1e9e..55b7750ade 100755 --- a/t/t4200-rerere.sh +++ b/t/t4200-rerere.sh @@ -642,4 +642,33 @@ test_expect_success 'rerere with inner conflict markers' ' test_cmp expect actual ' +test_expect_success 'setup simple stage 1 handling' ' + test_create_repo stage_1_handling && + ( + cd stage_1_handling && + + test_seq 1 10 >original && + git add original && + git commit -m original && + + git checkout -b A master && + git mv original A && + git commit -m "rename to A" && + + git checkout -b B master && + git mv original B && + git commit -m "rename to B" + ) +' + +test_expect_success 'test simple stage 1 handling' ' + ( + cd stage_1_handling && + + git config rerere.enabled true && + git checkout A^0 && + test_must_fail git merge B^0 + ) +' + test_done diff --git a/t/t5318-commit-graph.sh b/t/t5318-commit-graph.sh index 0c500f7ca2..db8dcafca3 100755 --- a/t/t5318-commit-graph.sh +++ b/t/t5318-commit-graph.sh @@ -8,7 +8,8 @@ test_expect_success 'setup full repo' ' cd "$TRASH_DIRECTORY/full" && git init && git config core.commitGraph true && - objdir=".git/objects" + objdir=".git/objects" && + test_oid_init ' test_expect_success 'verify graph with no graph file' ' @@ -259,6 +260,66 @@ test_expect_success 'check that gc computes commit-graph' ' test_cmp_bin commit-graph-after-gc $objdir/info/commit-graph ' +test_expect_success 'replace-objects invalidates commit-graph' ' + cd "$TRASH_DIRECTORY" && + test_when_finished rm -rf replace && + git clone full replace && + ( + cd replace && + git commit-graph write --reachable && + test_path_is_file .git/objects/info/commit-graph && + git replace HEAD~1 HEAD~2 && + git -c core.commitGraph=false log >expect && + git -c core.commitGraph=true log >actual && + test_cmp expect actual && + git commit-graph write --reachable && + git -c core.commitGraph=false --no-replace-objects log >expect && + git -c core.commitGraph=true --no-replace-objects log >actual && + test_cmp expect actual && + rm -rf .git/objects/info/commit-graph && + git commit-graph write --reachable && + test_path_is_file .git/objects/info/commit-graph + ) +' + +test_expect_success 'commit grafts invalidate commit-graph' ' + cd "$TRASH_DIRECTORY" && + test_when_finished rm -rf graft && + git clone full graft && + ( + cd graft && + git commit-graph write --reachable && + test_path_is_file .git/objects/info/commit-graph && + H1=$(git rev-parse --verify HEAD~1) && + H3=$(git rev-parse --verify HEAD~3) && + echo "$H1 $H3" >.git/info/grafts && + git -c core.commitGraph=false log >expect && + git -c core.commitGraph=true log >actual && + test_cmp expect actual && + git commit-graph write --reachable && + git -c core.commitGraph=false --no-replace-objects log >expect && + git -c core.commitGraph=true --no-replace-objects log >actual && + test_cmp expect actual && + rm -rf .git/objects/info/commit-graph && + git commit-graph write --reachable && + test_path_is_missing .git/objects/info/commit-graph + ) +' + +test_expect_success 'replace-objects invalidates commit-graph' ' + cd "$TRASH_DIRECTORY" && + test_when_finished rm -rf shallow && + git clone --depth 2 "file://$TRASH_DIRECTORY/full" shallow && + ( + cd shallow && + git commit-graph write --reachable && + test_path_is_missing .git/objects/info/commit-graph && + git fetch origin --unshallow && + git commit-graph write --reachable && + test_path_is_file .git/objects/info/commit-graph + ) +' + # the verify tests below expect the commit-graph to contain # exactly the commits reachable from the commits/8 branch. # If the file changes the set of commits in the list, then the @@ -273,7 +334,7 @@ test_expect_success 'git commit-graph verify' ' NUM_COMMITS=9 NUM_OCTOPUS_EDGES=2 -HASH_LEN=20 +HASH_LEN="$(test_oid rawsz)" GRAPH_BYTE_VERSION=4 GRAPH_BYTE_HASH=5 GRAPH_BYTE_CHUNK_COUNT=6 diff --git a/t/t5319-multi-pack-index.sh b/t/t5319-multi-pack-index.sh index 6f56b38674..bd8e841b81 100755 --- a/t/t5319-multi-pack-index.sh +++ b/t/t5319-multi-pack-index.sh @@ -150,6 +150,125 @@ test_expect_success 'write midx with twelve packs' ' compare_results_with_midx "twelve packs" +test_expect_success 'verify multi-pack-index success' ' + git multi-pack-index verify --object-dir=$objdir +' + +# usage: corrupt_midx_and_verify <pos> <data> <objdir> <string> +corrupt_midx_and_verify() { + POS=$1 && + DATA="${2:-\0}" && + OBJDIR=$3 && + GREPSTR="$4" && + COMMAND="$5" && + if test -z "$COMMAND" + then + COMMAND="git multi-pack-index verify --object-dir=$OBJDIR" + fi && + FILE=$OBJDIR/pack/multi-pack-index && + chmod a+w $FILE && + test_when_finished mv midx-backup $FILE && + cp $FILE midx-backup && + printf "$DATA" | dd of="$FILE" bs=1 seek="$POS" conv=notrunc && + test_must_fail $COMMAND 2>test_err && + grep -v "^+" test_err >err && + test_i18ngrep "$GREPSTR" err +} + +test_expect_success 'verify bad signature' ' + corrupt_midx_and_verify 0 "\00" $objdir \ + "multi-pack-index signature" +' + +HASH_LEN=20 +NUM_OBJECTS=74 +MIDX_BYTE_VERSION=4 +MIDX_BYTE_OID_VERSION=5 +MIDX_BYTE_CHUNK_COUNT=6 +MIDX_HEADER_SIZE=12 +MIDX_BYTE_CHUNK_ID=$MIDX_HEADER_SIZE +MIDX_BYTE_CHUNK_OFFSET=$(($MIDX_HEADER_SIZE + 4)) +MIDX_NUM_CHUNKS=5 +MIDX_CHUNK_LOOKUP_WIDTH=12 +MIDX_OFFSET_PACKNAMES=$(($MIDX_HEADER_SIZE + \ + $MIDX_NUM_CHUNKS * $MIDX_CHUNK_LOOKUP_WIDTH)) +MIDX_BYTE_PACKNAME_ORDER=$(($MIDX_OFFSET_PACKNAMES + 2)) +MIDX_OFFSET_OID_FANOUT=$(($MIDX_OFFSET_PACKNAMES + 652)) +MIDX_OID_FANOUT_WIDTH=4 +MIDX_BYTE_OID_FANOUT_ORDER=$((MIDX_OFFSET_OID_FANOUT + 250 * $MIDX_OID_FANOUT_WIDTH + 1)) +MIDX_OFFSET_OID_LOOKUP=$(($MIDX_OFFSET_OID_FANOUT + 256 * $MIDX_OID_FANOUT_WIDTH)) +MIDX_BYTE_OID_LOOKUP=$(($MIDX_OFFSET_OID_LOOKUP + 16 * $HASH_LEN)) +MIDX_OFFSET_OBJECT_OFFSETS=$(($MIDX_OFFSET_OID_LOOKUP + $NUM_OBJECTS * $HASH_LEN)) +MIDX_OFFSET_WIDTH=8 +MIDX_BYTE_PACK_INT_ID=$(($MIDX_OFFSET_OBJECT_OFFSETS + 16 * $MIDX_OFFSET_WIDTH + 2)) +MIDX_BYTE_OFFSET=$(($MIDX_OFFSET_OBJECT_OFFSETS + 16 * $MIDX_OFFSET_WIDTH + 6)) + +test_expect_success 'verify bad version' ' + corrupt_midx_and_verify $MIDX_BYTE_VERSION "\00" $objdir \ + "multi-pack-index version" +' + +test_expect_success 'verify bad OID version' ' + corrupt_midx_and_verify $MIDX_BYTE_OID_VERSION "\02" $objdir \ + "hash version" +' + +test_expect_success 'verify truncated chunk count' ' + corrupt_midx_and_verify $MIDX_BYTE_CHUNK_COUNT "\01" $objdir \ + "missing required" +' + +test_expect_success 'verify extended chunk count' ' + corrupt_midx_and_verify $MIDX_BYTE_CHUNK_COUNT "\07" $objdir \ + "terminating multi-pack-index chunk id appears earlier than expected" +' + +test_expect_success 'verify missing required chunk' ' + corrupt_midx_and_verify $MIDX_BYTE_CHUNK_ID "\01" $objdir \ + "missing required" +' + +test_expect_success 'verify invalid chunk offset' ' + corrupt_midx_and_verify $MIDX_BYTE_CHUNK_OFFSET "\01" $objdir \ + "invalid chunk offset (too large)" +' + +test_expect_success 'verify packnames out of order' ' + corrupt_midx_and_verify $MIDX_BYTE_PACKNAME_ORDER "z" $objdir \ + "pack names out of order" +' + +test_expect_success 'verify packnames out of order' ' + corrupt_midx_and_verify $MIDX_BYTE_PACKNAME_ORDER "a" $objdir \ + "failed to load pack" +' + +test_expect_success 'verify oid fanout out of order' ' + corrupt_midx_and_verify $MIDX_BYTE_OID_FANOUT_ORDER "\01" $objdir \ + "oid fanout out of order" +' + +test_expect_success 'verify oid lookup out of order' ' + corrupt_midx_and_verify $MIDX_BYTE_OID_LOOKUP "\00" $objdir \ + "oid lookup out of order" +' + +test_expect_success 'verify incorrect pack-int-id' ' + corrupt_midx_and_verify $MIDX_BYTE_PACK_INT_ID "\07" $objdir \ + "bad pack-int-id" +' + +test_expect_success 'verify incorrect offset' ' + corrupt_midx_and_verify $MIDX_BYTE_OFFSET "\07" $objdir \ + "incorrect object offset" +' + +test_expect_success 'git-fsck incorrect offset' ' + corrupt_midx_and_verify $MIDX_BYTE_OFFSET "\07" $objdir \ + "incorrect object offset" \ + "git -c core.multipackindex=true fsck" +' + test_expect_success 'repack removes multi-pack-index' ' test_path_is_file $objdir/pack/multi-pack-index && git repack -adf && @@ -187,7 +306,6 @@ test_expect_success 'multi-pack-index in an alternate' ' compare_results_with_midx "with alternate (remote midx)" - # usage: corrupt_data <file> <pos> [<data>] corrupt_data () { file=$1 @@ -214,4 +332,20 @@ test_expect_success 'force some 64-bit offsets with pack-objects' ' midx_read_expect 1 63 5 objects64 " large-offsets" ' +test_expect_success 'verify multi-pack-index with 64-bit offsets' ' + git multi-pack-index verify --object-dir=objects64 +' + +NUM_OBJECTS=63 +MIDX_OFFSET_OID_FANOUT=$((MIDX_OFFSET_PACKNAMES + 54)) +MIDX_OFFSET_OID_LOOKUP=$((MIDX_OFFSET_OID_FANOUT + 256 * $MIDX_OID_FANOUT_WIDTH)) +MIDX_OFFSET_OBJECT_OFFSETS=$(($MIDX_OFFSET_OID_LOOKUP + $NUM_OBJECTS * $HASH_LEN)) +MIDX_OFFSET_LARGE_OFFSETS=$(($MIDX_OFFSET_OBJECT_OFFSETS + $NUM_OBJECTS * $MIDX_OFFSET_WIDTH)) +MIDX_BYTE_LARGE_OFFSET=$(($MIDX_OFFSET_LARGE_OFFSETS + 3)) + +test_expect_success 'verify incorrect 64-bit offset' ' + corrupt_midx_and_verify $MIDX_BYTE_LARGE_OFFSET "\07" objects64 \ + "incorrect object offset" +' + test_done diff --git a/t/t5504-fetch-receive-strict.sh b/t/t5504-fetch-receive-strict.sh index 62f3569891..7bc706873c 100755 --- a/t/t5504-fetch-receive-strict.sh +++ b/t/t5504-fetch-receive-strict.sh @@ -133,6 +133,34 @@ committer Bugs Bunny <bugs@bun.ni> 1234567890 +0000 This commit object intentionally broken EOF +test_expect_success 'setup bogus commit' ' + commit="$(git hash-object -t commit -w --stdin <bogus-commit)" +' + +test_expect_success 'fsck with no skipList input' ' + test_must_fail git fsck 2>err && + test_i18ngrep "missingEmail" err +' + +test_expect_success 'setup sorted and unsorted skipLists' ' + cat >SKIP.unsorted <<-EOF && + 0000000000000000000000000000000000000004 + 0000000000000000000000000000000000000002 + $commit + 0000000000000000000000000000000000000001 + 0000000000000000000000000000000000000003 + EOF + sort SKIP.unsorted >SKIP.sorted +' + +test_expect_success 'fsck with sorted skipList' ' + git -c fsck.skipList=SKIP.sorted fsck +' + +test_expect_success 'fsck with unsorted skipList' ' + git -c fsck.skipList=SKIP.unsorted fsck +' + test_expect_success 'fsck with invalid or bogus skipList input' ' git -c fsck.skipList=/dev/null -c fsck.missingEmail=ignore fsck && test_must_fail git -c fsck.skipList=does-not-exist -c fsck.missingEmail=ignore fsck 2>err && @@ -141,8 +169,47 @@ test_expect_success 'fsck with invalid or bogus skipList input' ' test_i18ngrep "Invalid SHA-1: \[core\]" err ' +test_expect_success 'fsck with other accepted skipList input (comments & empty lines)' ' + cat >SKIP.with-comment <<-EOF && + # Some bad commit + 0000000000000000000000000000000000000001 + EOF + test_must_fail git -c fsck.skipList=SKIP.with-comment fsck 2>err-with-comment && + test_i18ngrep "missingEmail" err-with-comment && + cat >SKIP.with-empty-line <<-EOF && + 0000000000000000000000000000000000000001 + + 0000000000000000000000000000000000000002 + EOF + test_must_fail git -c fsck.skipList=SKIP.with-empty-line fsck 2>err-with-empty-line && + test_i18ngrep "missingEmail" err-with-empty-line +' + +test_expect_success 'fsck no garbage output from comments & empty lines errors' ' + test_line_count = 1 err-with-comment && + test_line_count = 1 err-with-empty-line +' + +test_expect_success 'fsck with invalid abbreviated skipList input' ' + echo $commit | test_copy_bytes 20 >SKIP.abbreviated && + test_must_fail git -c fsck.skipList=SKIP.abbreviated fsck 2>err-abbreviated && + test_i18ngrep "^fatal: Invalid SHA-1: " err-abbreviated +' + +test_expect_success 'fsck with exhaustive accepted skipList input (various types of comments etc.)' ' + >SKIP.exhaustive && + echo "# A commented line" >>SKIP.exhaustive && + echo "" >>SKIP.exhaustive && + echo " " >>SKIP.exhaustive && + echo " # Comment after whitespace" >>SKIP.exhaustive && + echo "$commit # Our bad commit (with leading whitespace and trailing comment)" >>SKIP.exhaustive && + echo "# Some bad commit (leading whitespace)" >>SKIP.exhaustive && + echo " 0000000000000000000000000000000000000001" >>SKIP.exhaustive && + git -c fsck.skipList=SKIP.exhaustive fsck 2>err && + test_must_be_empty err +' + test_expect_success 'push with receive.fsck.skipList' ' - commit="$(git hash-object -t commit -w --stdin <bogus-commit)" && git push . $commit:refs/heads/bogus && rm -rf dst && git init dst && @@ -169,7 +236,6 @@ test_expect_success 'push with receive.fsck.skipList' ' ' test_expect_success 'fetch with fetch.fsck.skipList' ' - commit="$(git hash-object -t commit -w --stdin <bogus-commit)" && refspec=refs/heads/bogus:refs/heads/bogus && git push . $commit:refs/heads/bogus && rm -rf dst && @@ -204,7 +270,6 @@ test_expect_success 'fsck.<unknownmsg-id> dies' ' ' test_expect_success 'push with receive.fsck.missingEmail=warn' ' - commit="$(git hash-object -t commit -w --stdin <bogus-commit)" && git push . $commit:refs/heads/bogus && rm -rf dst && git init dst && @@ -232,7 +297,6 @@ test_expect_success 'push with receive.fsck.missingEmail=warn' ' ' test_expect_success 'fetch with fetch.fsck.missingEmail=warn' ' - commit="$(git hash-object -t commit -w --stdin <bogus-commit)" && refspec=refs/heads/bogus:refs/heads/bogus && git push . $commit:refs/heads/bogus && rm -rf dst && diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index 241e6a319d..d2a2cdd453 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -145,7 +145,7 @@ test_expect_success 'remove remote protects local branches' ' test_expect_success 'remove errors out early when deleting non-existent branch' ' ( cd test && - echo "fatal: No such remote: foo" >expect && + echo "fatal: No such remote: '\''foo'\''" >expect && test_must_fail git remote rm foo 2>actual && test_i18ncmp expect actual ) @@ -173,7 +173,7 @@ test_expect_success 'remove remote with a branch without configured merge' ' test_expect_success 'rename errors out early when deleting non-existent branch' ' ( cd test && - echo "fatal: No such remote: foo" >expect && + echo "fatal: No such remote: '\''foo'\''" >expect && test_must_fail git remote rename foo bar 2>actual && test_i18ncmp expect actual ) diff --git a/t/t5701-git-serve.sh b/t/t5701-git-serve.sh index 75ec79e6cb..29a54fbfff 100755 --- a/t/t5701-git-serve.sh +++ b/t/t5701-git-serve.sh @@ -15,13 +15,13 @@ test_expect_success 'test capability advertisement' ' EOF git serve --advertise-capabilities >out && - test-pkt-line unpack <out >actual && + test-tool pkt-line unpack <out >actual && test_cmp actual expect ' test_expect_success 'stateless-rpc flag does not list capabilities' ' # Empty request - test-pkt-line pack >in <<-EOF && + test-tool pkt-line pack >in <<-EOF && 0000 EOF git serve --stateless-rpc >out <in && @@ -33,7 +33,7 @@ test_expect_success 'stateless-rpc flag does not list capabilities' ' ' test_expect_success 'request invalid capability' ' - test-pkt-line pack >in <<-EOF && + test-tool pkt-line pack >in <<-EOF && foobar 0000 EOF @@ -42,7 +42,7 @@ test_expect_success 'request invalid capability' ' ' test_expect_success 'request with no command' ' - test-pkt-line pack >in <<-EOF && + test-tool pkt-line pack >in <<-EOF && agent=git/test 0000 EOF @@ -51,7 +51,7 @@ test_expect_success 'request with no command' ' ' test_expect_success 'request invalid command' ' - test-pkt-line pack >in <<-EOF && + test-tool pkt-line pack >in <<-EOF && command=foo agent=git/test 0000 @@ -71,7 +71,7 @@ test_expect_success 'setup some refs and tags' ' ' test_expect_success 'basics of ls-refs' ' - test-pkt-line pack >in <<-EOF && + test-tool pkt-line pack >in <<-EOF && command=ls-refs 0000 EOF @@ -88,12 +88,12 @@ test_expect_success 'basics of ls-refs' ' EOF git serve --stateless-rpc <in >out && - test-pkt-line unpack <out >actual && + test-tool pkt-line unpack <out >actual && test_cmp actual expect ' test_expect_success 'basic ref-prefixes' ' - test-pkt-line pack >in <<-EOF && + test-tool pkt-line pack >in <<-EOF && command=ls-refs 0001 ref-prefix refs/heads/master @@ -108,12 +108,12 @@ test_expect_success 'basic ref-prefixes' ' EOF git serve --stateless-rpc <in >out && - test-pkt-line unpack <out >actual && + test-tool pkt-line unpack <out >actual && test_cmp actual expect ' test_expect_success 'refs/heads prefix' ' - test-pkt-line pack >in <<-EOF && + test-tool pkt-line pack >in <<-EOF && command=ls-refs 0001 ref-prefix refs/heads/ @@ -128,12 +128,12 @@ test_expect_success 'refs/heads prefix' ' EOF git serve --stateless-rpc <in >out && - test-pkt-line unpack <out >actual && + test-tool pkt-line unpack <out >actual && test_cmp actual expect ' test_expect_success 'peel parameter' ' - test-pkt-line pack >in <<-EOF && + test-tool pkt-line pack >in <<-EOF && command=ls-refs 0001 peel @@ -149,12 +149,12 @@ test_expect_success 'peel parameter' ' EOF git serve --stateless-rpc <in >out && - test-pkt-line unpack <out >actual && + test-tool pkt-line unpack <out >actual && test_cmp actual expect ' test_expect_success 'symrefs parameter' ' - test-pkt-line pack >in <<-EOF && + test-tool pkt-line pack >in <<-EOF && command=ls-refs 0001 symrefs @@ -170,12 +170,12 @@ test_expect_success 'symrefs parameter' ' EOF git serve --stateless-rpc <in >out && - test-pkt-line unpack <out >actual && + test-tool pkt-line unpack <out >actual && test_cmp actual expect ' test_expect_success 'sending server-options' ' - test-pkt-line pack >in <<-EOF && + test-tool pkt-line pack >in <<-EOF && command=ls-refs server-option=hello server-option=world @@ -190,14 +190,14 @@ test_expect_success 'sending server-options' ' EOF git serve --stateless-rpc <in >out && - test-pkt-line unpack <out >actual && + test-tool pkt-line unpack <out >actual && test_cmp actual expect ' test_expect_success 'unexpected lines are not allowed in fetch request' ' git init server && - test-pkt-line pack >in <<-EOF && + test-tool pkt-line pack >in <<-EOF && command=fetch 0001 this-is-not-a-command diff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh index 3beeed4546..88a886975d 100755 --- a/t/t5702-protocol-v2.sh +++ b/t/t5702-protocol-v2.sh @@ -334,7 +334,7 @@ test_expect_success 'even with handcrafted request, filter does not work if not git -C server config uploadpack.allowfilter 0 && # Custom request that tries to filter even though it is not advertised. - test-pkt-line pack >in <<-EOF && + test-tool pkt-line pack >in <<-EOF && command=fetch 0001 want $(git -C server rev-parse master) diff --git a/t/t5703-upload-pack-ref-in-want.sh b/t/t5703-upload-pack-ref-in-want.sh index d1ccc22331..3f58f05cbb 100755 --- a/t/t5703-upload-pack-ref-in-want.sh +++ b/t/t5703-upload-pack-ref-in-want.sh @@ -9,14 +9,14 @@ get_actual_refs () { /wanted-refs/d /0001/d p - }' <out | test-pkt-line unpack >actual_refs + }' <out | test-tool pkt-line unpack >actual_refs } get_actual_commits () { sed -n -e '/packfile/,/0000/{ /packfile/d p - }' <out | test-pkt-line unpack-sideband >o.pack && + }' <out | test-tool pkt-line unpack-sideband >o.pack && git index-pack o.pack && git verify-pack -v o.idx | grep commit | cut -c-40 | sort >actual_commits } @@ -61,7 +61,7 @@ test_expect_success 'config controls ref-in-want advertisement' ' ' test_expect_success 'invalid want-ref line' ' - test-pkt-line pack >in <<-EOF && + test-tool pkt-line pack >in <<-EOF && command=fetch 0001 no-progress @@ -80,7 +80,7 @@ test_expect_success 'basic want-ref' ' EOF git rev-parse f | sort >expected_commits && - test-pkt-line pack >in <<-EOF && + test-tool pkt-line pack >in <<-EOF && command=fetch 0001 no-progress @@ -101,7 +101,7 @@ test_expect_success 'multiple want-ref lines' ' EOF git rev-parse c d | sort >expected_commits && - test-pkt-line pack >in <<-EOF && + test-tool pkt-line pack >in <<-EOF && command=fetch 0001 no-progress @@ -122,7 +122,7 @@ test_expect_success 'mix want and want-ref' ' EOF git rev-parse e f | sort >expected_commits && - test-pkt-line pack >in <<-EOF && + test-tool pkt-line pack >in <<-EOF && command=fetch 0001 no-progress @@ -143,7 +143,7 @@ test_expect_success 'want-ref with ref we already have commit for' ' EOF >expected_commits && - test-pkt-line pack >in <<-EOF && + test-tool pkt-line pack >in <<-EOF && command=fetch 0001 no-progress diff --git a/t/t6135-pathspec-with-attrs.sh b/t/t6135-pathspec-with-attrs.sh index 77b8cef661..e436a73962 100755 --- a/t/t6135-pathspec-with-attrs.sh +++ b/t/t6135-pathspec-with-attrs.sh @@ -166,7 +166,7 @@ test_expect_success 'fail if attr magic is used places not implemented' ' # though, but git-add is convenient as it has its own internal pathspec # parsing. test_must_fail git add ":(attr:labelB)" 2>actual && - test_i18ngrep "unsupported magic" actual + test_i18ngrep "magic not supported" actual ' test_expect_success 'abort on giving invalid label on the command line' ' diff --git a/t/t6500-gc.sh b/t/t6500-gc.sh index 818435f04e..b3fbd87ee7 100755 --- a/t/t6500-gc.sh +++ b/t/t6500-gc.sh @@ -4,6 +4,7 @@ test_description='basic git gc tests ' . ./test-lib.sh +. "$TEST_DIRECTORY"/lib-terminal.sh test_expect_success 'setup' ' # do not let the amount of physical memory affects gc @@ -99,6 +100,26 @@ test_expect_success 'auto gc with too many loose objects does not attempt to cre test_line_count = 2 new # There is one new pack and its .idx ' +test_expect_success 'gc --no-quiet' ' + git -c gc.writeCommitGraph=true gc --no-quiet >stdout 2>stderr && + test_must_be_empty stdout && + test_line_count = 1 stderr && + test_i18ngrep "Computing commit graph generation numbers" stderr +' + +test_expect_success TTY 'with TTY: gc --no-quiet' ' + test_terminal git -c gc.writeCommitGraph=true gc --no-quiet >stdout 2>stderr && + test_must_be_empty stdout && + test_i18ngrep "Enumerating objects" stderr && + test_i18ngrep "Computing commit graph generation numbers" stderr +' + +test_expect_success 'gc --quiet' ' + git -c gc.writeCommitGraph=true gc --quiet >stdout 2>stderr && + test_must_be_empty stdout && + test_must_be_empty stderr +' + run_and_wait_for_auto_gc () { # We read stdout from gc for the side effect of waiting until the # background gc process exits, closing its fd 9. Furthermore, the diff --git a/t/t6600-test-reach.sh b/t/t6600-test-reach.sh index d139a00d1d..ae94b27f70 100755 --- a/t/t6600-test-reach.sh +++ b/t/t6600-test-reach.sh @@ -31,7 +31,8 @@ test_expect_success 'setup' ' for i in $(test_seq 1 10) do test_commit "1-$i" && - git branch -f commit-1-$i + git branch -f commit-1-$i && + git tag -a -m "1-$i" tag-1-$i commit-1-$i done && for j in $(test_seq 1 9) do @@ -39,11 +40,13 @@ test_expect_success 'setup' ' x=$(($j + 1)) && test_commit "$x-1" && git branch -f commit-$x-1 && + git tag -a -m "$x-1" tag-$x-1 commit-$x-1 && for i in $(test_seq 2 10) do git merge commit-$j-$i -m "$x-$i" && - git branch -f commit-$x-$i + git branch -f commit-$x-$i && + git tag -a -m "$x-$i" tag-$x-$i commit-$x-$i done done && git commit-graph write --reachable && @@ -205,6 +208,29 @@ test_expect_success 'can_all_from_reach:miss' ' test_three_modes can_all_from_reach ' +test_expect_success 'can_all_from_reach_with_flag: tags case' ' + cat >input <<-\EOF && + X:tag-2-10 + X:tag-3-9 + X:tag-4-8 + X:commit-5-7 + X:commit-6-6 + X:commit-7-5 + X:commit-8-4 + X:commit-9-3 + Y:tag-1-9 + Y:tag-2-8 + Y:tag-3-7 + Y:commit-4-6 + Y:commit-5-5 + Y:commit-6-4 + Y:commit-7-3 + Y:commit-8-1 + EOF + echo "can_all_from_reach_with_flag(X,_,_,0,0):1" >expect && + test_three_modes can_all_from_reach_with_flag +' + test_expect_success 'commit_contains:hit' ' cat >input <<-\EOF && A:commit-7-7 diff --git a/t/t7063-status-untracked-cache.sh b/t/t7063-status-untracked-cache.sh index 2da57fce7b..190ae149cf 100755 --- a/t/t7063-status-untracked-cache.sh +++ b/t/t7063-status-untracked-cache.sh @@ -55,7 +55,7 @@ test_expect_success 'setup' ' ' test_expect_success 'untracked cache is empty' ' - test-dump-untracked-cache >../actual && + test-tool dump-untracked-cache >../actual && cat >../expect-empty <<EOF && info/exclude 0000000000000000000000000000000000000000 core.excludesfile 0000000000000000000000000000000000000000 @@ -106,7 +106,7 @@ EOF ' test_expect_success 'untracked cache after first status' ' - test-dump-untracked-cache >../actual && + test-tool dump-untracked-cache >../actual && test_cmp ../dump.expect ../actual ' @@ -126,7 +126,7 @@ EOF ' test_expect_success 'untracked cache after second status' ' - test-dump-untracked-cache >../actual && + test-tool dump-untracked-cache >../actual && test_cmp ../dump.expect ../actual ' @@ -157,7 +157,7 @@ EOF ' test_expect_success 'verify untracked cache dump' ' - test-dump-untracked-cache >../actual && + test-tool dump-untracked-cache >../actual && cat >../expect <<EOF && info/exclude $EMPTY_BLOB core.excludesfile 0000000000000000000000000000000000000000 @@ -204,7 +204,7 @@ EOF ' test_expect_success 'verify untracked cache dump' ' - test-dump-untracked-cache >../actual && + test-tool dump-untracked-cache >../actual && cat >../expect <<EOF && info/exclude $EMPTY_BLOB core.excludesfile 0000000000000000000000000000000000000000 @@ -248,7 +248,7 @@ EOF ' test_expect_success 'verify untracked cache dump' ' - test-dump-untracked-cache >../actual && + test-tool dump-untracked-cache >../actual && cat >../expect <<EOF && info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0 core.excludesfile 0000000000000000000000000000000000000000 @@ -267,7 +267,7 @@ EOF test_expect_success 'move two from tracked to untracked' ' git rm --cached two && - test-dump-untracked-cache >../actual && + test-tool dump-untracked-cache >../actual && cat >../expect <<EOF && info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0 core.excludesfile 0000000000000000000000000000000000000000 @@ -304,7 +304,7 @@ EOF ' test_expect_success 'verify untracked cache dump' ' - test-dump-untracked-cache >../actual && + test-tool dump-untracked-cache >../actual && cat >../expect <<EOF && info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0 core.excludesfile 0000000000000000000000000000000000000000 @@ -324,7 +324,7 @@ EOF test_expect_success 'move two from untracked to tracked' ' git add two && - test-dump-untracked-cache >../actual && + test-tool dump-untracked-cache >../actual && cat >../expect <<EOF && info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0 core.excludesfile 0000000000000000000000000000000000000000 @@ -361,7 +361,7 @@ EOF ' test_expect_success 'verify untracked cache dump' ' - test-dump-untracked-cache >../actual && + test-tool dump-untracked-cache >../actual && cat >../expect <<EOF && info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0 core.excludesfile 0000000000000000000000000000000000000000 @@ -405,7 +405,7 @@ EOF ' test_expect_success 'untracked cache correct after commit' ' - test-dump-untracked-cache >../actual && + test-tool dump-untracked-cache >../actual && cat >../expect <<EOF && info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0 core.excludesfile 0000000000000000000000000000000000000000 @@ -464,7 +464,7 @@ EOF ' test_expect_success 'untracked cache correct after status' ' - test-dump-untracked-cache >../actual && + test-tool dump-untracked-cache >../actual && cat >../expect <<EOF && info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0 core.excludesfile 0000000000000000000000000000000000000000 @@ -532,7 +532,7 @@ EOF ' test_expect_success 'verify untracked cache dump (sparse/subdirs)' ' - test-dump-untracked-cache >../actual && + test-tool dump-untracked-cache >../actual && cat >../expect-from-test-dump <<EOF && info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0 core.excludesfile 0000000000000000000000000000000000000000 @@ -598,66 +598,66 @@ EOF test_expect_success '--no-untracked-cache removes the cache' ' git update-index --no-untracked-cache && - test-dump-untracked-cache >../actual && + test-tool dump-untracked-cache >../actual && echo "no untracked cache" >../expect-no-uc && test_cmp ../expect-no-uc ../actual ' test_expect_success 'git status does not change anything' ' git status && - test-dump-untracked-cache >../actual && + test-tool dump-untracked-cache >../actual && test_cmp ../expect-no-uc ../actual ' test_expect_success 'setting core.untrackedCache to true and using git status creates the cache' ' git config core.untrackedCache true && - test-dump-untracked-cache >../actual && + test-tool dump-untracked-cache >../actual && test_cmp ../expect-no-uc ../actual && git status && - test-dump-untracked-cache >../actual && + test-tool dump-untracked-cache >../actual && test_cmp ../expect-from-test-dump ../actual ' test_expect_success 'using --no-untracked-cache does not fail when core.untrackedCache is true' ' git update-index --no-untracked-cache && - test-dump-untracked-cache >../actual && + test-tool dump-untracked-cache >../actual && test_cmp ../expect-no-uc ../actual && git update-index --untracked-cache && - test-dump-untracked-cache >../actual && + test-tool dump-untracked-cache >../actual && test_cmp ../expect-empty ../actual ' test_expect_success 'setting core.untrackedCache to false and using git status removes the cache' ' git config core.untrackedCache false && - test-dump-untracked-cache >../actual && + test-tool dump-untracked-cache >../actual && test_cmp ../expect-empty ../actual && git status && - test-dump-untracked-cache >../actual && + test-tool dump-untracked-cache >../actual && test_cmp ../expect-no-uc ../actual ' test_expect_success 'using --untracked-cache does not fail when core.untrackedCache is false' ' git update-index --untracked-cache && - test-dump-untracked-cache >../actual && + test-tool dump-untracked-cache >../actual && test_cmp ../expect-empty ../actual ' test_expect_success 'setting core.untrackedCache to keep' ' git config core.untrackedCache keep && git update-index --untracked-cache && - test-dump-untracked-cache >../actual && + test-tool dump-untracked-cache >../actual && test_cmp ../expect-empty ../actual && git status && - test-dump-untracked-cache >../actual && + test-tool dump-untracked-cache >../actual && test_cmp ../expect-from-test-dump ../actual && git update-index --no-untracked-cache && - test-dump-untracked-cache >../actual && + test-tool dump-untracked-cache >../actual && test_cmp ../expect-no-uc ../actual && git update-index --force-untracked-cache && - test-dump-untracked-cache >../actual && + test-tool dump-untracked-cache >../actual && test_cmp ../expect-empty ../actual && git status && - test-dump-untracked-cache >../actual && + test-tool dump-untracked-cache >../actual && test_cmp ../expect-from-test-dump ../actual ' @@ -671,23 +671,23 @@ test_expect_success 'test ident field is working' ' test_expect_success 'untracked cache survives a checkout' ' git commit --allow-empty -m empty && - test-dump-untracked-cache >../before && + test-tool dump-untracked-cache >../before && test_when_finished "git checkout master" && git checkout -b other_branch && - test-dump-untracked-cache >../after && + test-tool dump-untracked-cache >../after && test_cmp ../before ../after && test_commit test && - test-dump-untracked-cache >../before && + test-tool dump-untracked-cache >../before && git checkout master && - test-dump-untracked-cache >../after && + test-tool dump-untracked-cache >../after && test_cmp ../before ../after ' test_expect_success 'untracked cache survives a commit' ' - test-dump-untracked-cache >../before && + test-tool dump-untracked-cache >../before && git add done/two && git commit -m commit && - test-dump-untracked-cache >../after && + test-tool dump-untracked-cache >../after && test_cmp ../before ../after ' @@ -751,7 +751,7 @@ test_expect_success '"status" after file replacement should be clean with UC=tru git checkout master && avoid_racy && status_is_clean && - test-dump-untracked-cache >../actual && + test-tool dump-untracked-cache >../actual && grep -F "recurse valid" ../actual >../actual.grep && cat >../expect.grep <<EOF && / 0000000000000000000000000000000000000000 recurse valid diff --git a/t/t7416-submodule-dash-url.sh b/t/t7416-submodule-dash-url.sh new file mode 100755 index 0000000000..1cd2c1c1ea --- /dev/null +++ b/t/t7416-submodule-dash-url.sh @@ -0,0 +1,49 @@ +#!/bin/sh + +test_description='check handling of .gitmodule url with dash' +. ./test-lib.sh + +test_expect_success 'create submodule with protected dash in url' ' + git init upstream && + git -C upstream commit --allow-empty -m base && + mv upstream ./-upstream && + git submodule add ./-upstream sub && + git add sub .gitmodules && + git commit -m submodule +' + +test_expect_success 'clone can recurse submodule' ' + test_when_finished "rm -rf dst" && + git clone --recurse-submodules . dst && + echo base >expect && + git -C dst/sub log -1 --format=%s >actual && + test_cmp expect actual +' + +test_expect_success 'fsck accepts protected dash' ' + test_when_finished "rm -rf dst" && + git init --bare dst && + git -C dst config transfer.fsckObjects true && + git push dst HEAD +' + +test_expect_success 'remove ./ protection from .gitmodules url' ' + perl -i -pe "s{\./}{}" .gitmodules && + git commit -am "drop protection" +' + +test_expect_success 'clone rejects unprotected dash' ' + test_when_finished "rm -rf dst" && + test_must_fail git clone --recurse-submodules . dst 2>err && + test_i18ngrep ignoring err +' + +test_expect_success 'fsck rejects unprotected dash' ' + test_when_finished "rm -rf dst" && + git init --bare dst && + git -C dst config transfer.fsckObjects true && + test_must_fail git push dst HEAD 2>err && + grep gitmodulesUrl err +' + +test_done diff --git a/t/t7417-submodule-path-url.sh b/t/t7417-submodule-path-url.sh new file mode 100755 index 0000000000..756af8c4d6 --- /dev/null +++ b/t/t7417-submodule-path-url.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +test_description='check handling of .gitmodule path with dash' +. ./test-lib.sh + +test_expect_success 'create submodule with dash in path' ' + git init upstream && + git -C upstream commit --allow-empty -m base && + git submodule add ./upstream sub && + git mv sub ./-sub && + git commit -m submodule +' + +test_expect_success 'clone rejects unprotected dash' ' + test_when_finished "rm -rf dst" && + git clone --recurse-submodules . dst 2>err && + test_i18ngrep ignoring err +' + +test_expect_success 'fsck rejects unprotected dash' ' + test_when_finished "rm -rf dst" && + git init --bare dst && + git -C dst config transfer.fsckObjects true && + test_must_fail git push dst HEAD 2>err && + grep gitmodulesPath err +' + +test_done diff --git a/t/t7519-status-fsmonitor.sh b/t/t7519-status-fsmonitor.sh index 756beb0d8e..8384ad258c 100755 --- a/t/t7519-status-fsmonitor.sh +++ b/t/t7519-status-fsmonitor.sh @@ -84,21 +84,21 @@ test_expect_success 'setup' ' # test that the fsmonitor extension is off by default test_expect_success 'fsmonitor extension is off by default' ' - test-dump-fsmonitor >actual && + test-tool dump-fsmonitor >actual && grep "^no fsmonitor" actual ' # test that "update-index --fsmonitor" adds the fsmonitor extension test_expect_success 'update-index --fsmonitor" adds the fsmonitor extension' ' git update-index --fsmonitor && - test-dump-fsmonitor >actual && + test-tool dump-fsmonitor >actual && grep "^fsmonitor last update" actual ' # test that "update-index --no-fsmonitor" removes the fsmonitor extension test_expect_success 'update-index --no-fsmonitor" removes the fsmonitor extension' ' git update-index --no-fsmonitor && - test-dump-fsmonitor >actual && + test-tool dump-fsmonitor >actual && grep "^no fsmonitor" actual ' @@ -307,9 +307,9 @@ test_expect_success 'splitting the index results in the same state' ' dirty_repo && git update-index --fsmonitor && git ls-files -f >expect && - test-dump-fsmonitor >&2 && echo && + test-tool dump-fsmonitor >&2 && echo && git update-index --fsmonitor --split-index && - test-dump-fsmonitor >&2 && echo && + test-tool dump-fsmonitor >&2 && echo && git ls-files -f >actual && test_cmp expect actual ' @@ -333,7 +333,7 @@ test_expect_success UNTRACKED_CACHE 'ignore .git changes when invalidating UNTR' git update-index --fsmonitor && GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace-before" \ git status && - test-dump-untracked-cache >../before + test-tool dump-untracked-cache >../before ) && cat >>dot-git/.git/hooks/fsmonitor-test <<-\EOF && printf ".git\0" @@ -345,7 +345,7 @@ test_expect_success UNTRACKED_CACHE 'ignore .git changes when invalidating UNTR' cd dot-git && GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace-after" \ git status && - test-dump-untracked-cache >../after + test-tool dump-untracked-cache >../after ) && grep "directory invalidation" trace-before >>before && grep "directory invalidation" trace-after >>after && diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh index d82fac9d79..78d8c3783b 100644 --- a/t/test-lib-functions.sh +++ b/t/test-lib-functions.sh @@ -1157,3 +1157,72 @@ depacketize () { } ' } + +# Set the hash algorithm in use to $1. Only useful when testing the testsuite. +test_set_hash () { + test_hash_algo="$1" +} + +# Detect the hash algorithm in use. +test_detect_hash () { + # Currently we only support SHA-1, but in the future this function will + # actually detect the algorithm in use. + test_hash_algo='sha1' +} + +# Load common hash metadata and common placeholder object IDs for use with +# test_oid. +test_oid_init () { + test -n "$test_hash_algo" || test_detect_hash && + test_oid_cache <"$TEST_DIRECTORY/oid-info/hash-info" && + test_oid_cache <"$TEST_DIRECTORY/oid-info/oid" +} + +# Load key-value pairs from stdin suitable for use with test_oid. Blank lines +# and lines starting with "#" are ignored. Keys must be shell identifier +# characters. +# +# Examples: +# rawsz sha1:20 +# rawsz sha256:32 +test_oid_cache () { + local tag rest k v && + + { test -n "$test_hash_algo" || test_detect_hash; } && + while read tag rest + do + case $tag in + \#*) + continue;; + ?*) + # non-empty + ;; + *) + # blank line + continue;; + esac && + + k="${rest%:*}" && + v="${rest#*:}" && + + if ! expr "$k" : '[a-z0-9][a-z0-9]*$' >/dev/null + then + error 'bug in the test script: bad hash algorithm' + fi && + eval "test_oid_${k}_$tag=\"\$v\"" + done +} + +# Look up a per-hash value based on a key ($1). The value must have been loaded +# by test_oid_init or test_oid_cache. +test_oid () { + local var="test_oid_${test_hash_algo}_$1" && + + # If the variable is unset, we must be missing an entry for this + # key-hash pair, so exit with an error. + if eval "test -z \"\${$var+set}\"" + then + error "bug in the test script: undefined key '$1'" >&2 + fi && + eval "printf '%s' \"\${$var}\"" +} diff --git a/tempfile.c b/tempfile.c index 139ecd97f8..d43ad8c191 100644 --- a/tempfile.c +++ b/tempfile.c @@ -279,7 +279,7 @@ int reopen_tempfile(struct tempfile *tempfile) BUG("reopen_tempfile called for an inactive object"); if (0 <= tempfile->fd) BUG("reopen_tempfile called for an open object"); - tempfile->fd = open(tempfile->filename.buf, O_WRONLY); + tempfile->fd = open(tempfile->filename.buf, O_WRONLY|O_TRUNC); return tempfile->fd; } diff --git a/tempfile.h b/tempfile.h index 36434eb6fa..61d8dc4d1b 100644 --- a/tempfile.h +++ b/tempfile.h @@ -236,8 +236,8 @@ extern int close_tempfile_gently(struct tempfile *tempfile); * it (and nobody else) to inspect or even modify the file's * contents. * - * * `reopen_tempfile()` to reopen the temporary file. Make further - * updates to the contents. + * * `reopen_tempfile()` to reopen the temporary file, truncating the existing + * contents. Write out the new contents. * * * `rename_tempfile()` to move the file to its permanent location. */ diff --git a/unpack-trees.c b/unpack-trees.c index 65f157b9de..51bfac6aa0 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -436,7 +436,7 @@ static int check_updates(struct unpack_trees_options *o) } if (to_fetch.nr) fetch_objects(repository_format_partial_clone, - &to_fetch); + to_fetch.oid, to_fetch.nr); fetch_if_missing = fetch_if_missing_store; oid_array_clear(&to_fetch); } diff --git a/upload-pack.c b/upload-pack.c index 62a1000f44..540778d1dd 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -24,6 +24,7 @@ #include "quote.h" #include "upload-pack.h" #include "serve.h" +#include "commit-graph.h" #include "commit-reach.h" /* Remember to update object flag allocation in object.h */ @@ -692,6 +693,7 @@ static void deepen_by_rev_list(int ac, const char **av, { struct commit_list *result; + close_commit_graph(the_repository); result = get_shallow_commits_by_rev_list(ac, av, SHALLOW, NOT_SHALLOW); send_shallow(result); free_commit_list(result); diff --git a/userdiff.c b/userdiff.c index f3f4be579c..f565f6731d 100644 --- a/userdiff.c +++ b/userdiff.c @@ -278,8 +278,7 @@ struct userdiff_driver *userdiff_find_by_path(const char *path) check = attr_check_initl("diff", NULL); if (!path) return NULL; - if (git_check_attr(&the_index, path, check)) - return NULL; + git_check_attr(&the_index, path, check); if (ATTR_TRUE(check->items[0].value)) return &driver_true; @@ -74,35 +74,31 @@ unsigned parse_whitespace_rule(const char *string) unsigned whitespace_rule(const char *pathname) { static struct attr_check *attr_whitespace_rule; + const char *value; if (!attr_whitespace_rule) attr_whitespace_rule = attr_check_initl("whitespace", NULL); - if (!git_check_attr(&the_index, pathname, attr_whitespace_rule)) { - const char *value; - - value = attr_whitespace_rule->items[0].value; - if (ATTR_TRUE(value)) { - /* true (whitespace) */ - unsigned all_rule = ws_tab_width(whitespace_rule_cfg); - int i; - for (i = 0; i < ARRAY_SIZE(whitespace_rule_names); i++) - if (!whitespace_rule_names[i].loosens_error && - !whitespace_rule_names[i].exclude_default) - all_rule |= whitespace_rule_names[i].rule_bits; - return all_rule; - } else if (ATTR_FALSE(value)) { - /* false (-whitespace) */ - return ws_tab_width(whitespace_rule_cfg); - } else if (ATTR_UNSET(value)) { - /* reset to default (!whitespace) */ - return whitespace_rule_cfg; - } else { - /* string */ - return parse_whitespace_rule(value); - } - } else { + git_check_attr(&the_index, pathname, attr_whitespace_rule); + value = attr_whitespace_rule->items[0].value; + if (ATTR_TRUE(value)) { + /* true (whitespace) */ + unsigned all_rule = ws_tab_width(whitespace_rule_cfg); + int i; + for (i = 0; i < ARRAY_SIZE(whitespace_rule_names); i++) + if (!whitespace_rule_names[i].loosens_error && + !whitespace_rule_names[i].exclude_default) + all_rule |= whitespace_rule_names[i].rule_bits; + return all_rule; + } else if (ATTR_FALSE(value)) { + /* false (-whitespace) */ + return ws_tab_width(whitespace_rule_cfg); + } else if (ATTR_UNSET(value)) { + /* reset to default (!whitespace) */ return whitespace_rule_cfg; + } else { + /* string */ + return parse_whitespace_rule(value); } } |