summaryrefslogtreecommitdiff
AgeCommit message (Collapse)AuthorFilesLines
2020-06-05dir: fix treatment of negated pathspecsLibravatar Elijah Newren2-17/+66
do_match_pathspec() started life as match_pathspec_depth_1() and for correctness was only supposed to be called from match_pathspec_depth(). match_pathspec_depth() was later renamed to match_pathspec(), so the invariant we expect today is that do_match_pathspec() has no direct callers outside of match_pathspec(). Unfortunately, this intention was lost with the renames of the two functions, and additional calls to do_match_pathspec() were added in commits 75a6315f74 ("ls-files: add pathspec matching for submodules", 2016-10-07) and 89a1f4aaf7 ("dir: if our pathspec might match files under a dir, recurse into it", 2019-09-17). Of course, do_match_pathspec() had an important advantge over match_pathspec() -- match_pathspec() would hardcode flags to one of two values, and these new callers needed to pass some other value for flags. Also, although calling do_match_pathspec() directly was incorrect, there likely wasn't any difference in the observable end output, because the bug just meant that fill_diretory() would recurse into unneeded directories. Since subsequent does-this-path-match checks on individual paths under the directory would cause those extra paths to be filtered out, the only difference from using the wrong function was unnecessary computation. The second of those bad calls to do_match_pathspec() was involved -- via either direct movement or via copying+editing -- into a number of later refactors. See commits 777b420347 ("dir: synchronize treat_leading_path() and read_directory_recursive()", 2019-12-19), 8d92fb2927 ("dir: replace exponential algorithm with a linear one", 2020-04-01), and 95c11ecc73 ("Fix error-prone fill_directory() API; make it only return matches", 2020-04-01). The last of those introduced the usage of do_match_pathspec() on an individual file, and thus resulted in individual paths being returned that shouldn't be. The problem with calling do_match_pathspec() instead of match_pathspec() is that any negated patterns such as ':!unwanted_path` will be ignored. Add a new match_pathspec_with_flags() function to fulfill the needs of specifying special flags while still correctly checking negated patterns, add a big comment above do_match_pathspec() to prevent others from misusing it, and correct current callers of do_match_pathspec() to instead use either match_pathspec() or match_pathspec_with_flags(). One final note is that DO_MATCH_LEADING_PATHSPEC needs special consideration when working with DO_MATCH_EXCLUDE. The point of DO_MATCH_LEADING_PATHSPEC is that if we have a pathspec like */Makefile and we are checking a directory path like src/module/component that we want to consider it a match so that we recurse into the directory because it _might_ have a file named Makefile somewhere below. However, when we are using an exclusion pattern, i.e. we have a pathspec like :(exclude)*/Makefile we do NOT want to say that a directory path like src/module/component is a (negative) match. While there *might* be a file named 'Makefile' somewhere below that directory, there could also be other files and we cannot pre-emptively rule all the files under that directory out; we need to recurse and then check individual files. Adjust the DO_MATCH_LEADING_PATHSPEC logic to only get activated for positive pathspecs. Reported-by: John Millikin <jmillikin@stripe.com> Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-04-01completion: fix 'git add' on paths under an untracked directoryLibravatar Elijah Newren2-1/+6
As reported on the git mailing list, since git-2.25, git add untracked-dir/ has been tab completing to git add untracked-dir/./ The cause for this was that with commit b9670c1f5e (dir: fix checks on common prefix directory, 2019-12-19), git ls-files -o --directory untracked-dir/ (or the equivalent `git -C untracked-dir ls-files -o --directory`) began reporting untracked-dir/ instead of listing paths underneath that directory. It may also be worth noting that the real command in question was git -C untracked-dir ls-files -o --directory '*' which is equivalent to git ls-files -o --directory 'untracked-dir/*' which behaves the same for the purposes of this issue (the '*' can match the empty string), but becomes relevant for the proposed fix. At first, based on the report, I decided to try to view this as a regression and tried to find a way to recover the old behavior without breaking other stuff, or at least breaking as little as possible. However, in the end, I couldn't figure out a way to do it that wouldn't just cause lots more problems than it solved. The old behavior was a bug: * Although older git would avoid cleaning anything with `git clean -f .git`, it would wipe out everything under that direcotry with `git clean -f .git/`. Despite the difference in command used, this is relevant because the exact same change that fixed clean changed the behavior of ls-files. * Older git would report different results based solely on presence or absence of a trailing slash for $SUBDIR in the command `git ls-files -o --directory $SUBDIR`. * Older git violated the documented behavior of not recursing into directories that matched the pathspec when --directory was specified. * And, after all, commit b9670c1f5e (dir: fix checks on common prefix directory, 2019-12-19) didn't overlook this issue; it explicitly stated that the behavior of the command was being changed to bring it inline with the docs. (Also, if it helps, despite that commit being merged during the 2.25 series, this bug was not reported during the 2.25 cycle, nor even during most of the 2.26 cycle -- it was reported a day before 2.26 was released. So the impact of the change is at least somewhat small.) Instead of relying on a bug of ls-files in reporting the wrong content, change the invocation of ls-files used by git-completion to make it grab paths one depth deeper. Do this by changing '$DIR/*' (match $DIR/ plus 0 or more characters) into '$DIR/?*' (match $DIR/ plus 1 or more characters). Note that the '?' character should not be added when trying to complete a filename (e.g. 'git ls-files -o --directory "merge.c?*"' would not correctly return "merge.c" when such a file exists), so we have to make sure to add the '?' character only in cases where the path specified so far is a directory. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-04-01Fix error-prone fill_directory() API; make it only return matchesLibravatar Elijah Newren6-27/+18
Traditionally, the expected calling convention for the dir.c API was: fill_directory(&dir, ..., pathspec) foreach entry in dir->entries: if (dir_path_match(entry, pathspec)) process_or_display(entry) This may have made sense once upon a time, because the fill_directory() call could use cheap checks to avoid doing full pathspec matching, and an external caller may have wanted to do other post-processing of the results anyway. However: * this structure makes it easy for users of the API to get it wrong * this structure actually makes it harder to understand fill_directory() and the functions it uses internally. It has tripped me up several times while trying to fix bugs and restructure things. * relying on post-filtering was already found to produce wrong results; pathspec matching had to be added internally for multiple cases in order to get the right results (see commits 404ebceda01c (dir: also check directories for matching pathspecs, 2019-09-17) and 89a1f4aaf765 (dir: if our pathspec might match files under a dir, recurse into it, 2019-09-17)) * it's bad for performance: fill_directory() already has to do lots of checks and knows the subset of cases where it still needs to do more checks. Forcing external callers to do full pathspec matching means they must re-check _every_ path. So, add the pathspec matching within the fill_directory() internals, and remove it from external callers. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-04-01dir: replace double pathspec matching with single in treat_directory()Libravatar Elijah Newren1-19/+19
treat_directory() had a call to both do_match_pathspec() and match_pathspec(). These calls have migrated through the code somewhat since their introduction, but we don't actually need both. Replace the two calls with one, and while at it, move the check earlier in order to reduce the need for callers of fill_directory() to do post-filtering of results. The next patch will address post-filtering more forcefully and provide more relevant history and context. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-04-01dir: include DIR_KEEP_UNTRACKED_CONTENTS handling in treat_directory()Libravatar Elijah Newren1-24/+19
Handling DIR_KEEP_UNTRACKED_CONTENTS within treat_directory() instead of as a post-processing step in read_directory(): * allows us to directly access and remove the relevant entries instead of needing to calculate which ones need to be removed * keeps the logic for directory handling in one location (and puts it closer the the logic for stripping out extra ignored entries, which seems logical). Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-04-01dir: replace exponential algorithm with a linear oneLibravatar Elijah Newren1-63/+147
dir's read_directory_recursive() naturally operates recursively in order to walk the directory tree. Treating of directories is sometimes weird because there are so many different permutations about how to handle directories. Some examples: * 'git ls-files -o --directory' only needs to know that a directory itself is untracked; it doesn't need to recurse into it to see what is underneath. * 'git status' needs to recurse into an untracked directory, but only to determine whether or not it is empty. If there are no files underneath, the directory itself will be omitted from the output. If it is not empty, only the directory will be listed. * 'git status --ignored' needs to recurse into untracked directories and report all the ignored entries and then report the directory as untracked -- UNLESS all the entries under the directory are ignored, in which case we don't print any of the entries under the directory and just report the directory itself as ignored. (Note that although this forces us to walk all untracked files underneath the directory as well, we strip them from the output, except for users like 'git clean' who also set DIR_KEEP_TRACKED_CONTENTS.) * For 'git clean', we may need to recurse into a directory that doesn't match any specified pathspecs, if it's possible that there is an entry underneath the directory that can match one of the pathspecs. In such a case, we need to be careful to omit the directory itself from the list of paths (see commit 404ebceda01c ("dir: also check directories for matching pathspecs", 2019-09-17)) Part of the tension noted above is that the treatment of a directory can change based on the files within it, and based on the various settings in dir->flags. Trying to keep this in mind while reading over the code, it is easy to think in terms of "treat_directory() tells us what to do with a directory, and read_directory_recursive() is the thing that recurses". Since we need to look into a directory to know how to treat it, though, it is quite easy to decide to (also) recurse into the directory from treat_directory() by adding a read_directory_recursive() call. Adding such a call is actually fine, IF we make sure that read_directory_recursive() does not also recurse into that same directory. Unfortunately, commit df5bcdf83aeb ("dir: recurse into untracked dirs for ignored files", 2017-05-18), added exactly such a case to the code, meaning we'd have two calls to read_directory_recursive() for an untracked directory. So, if we had a file named one/two/three/four/five/somefile.txt and nothing in one/ was tracked, then 'git status --ignored' would call read_directory_recursive() twice on the directory 'one/', and each of those would call read_directory_recursive() twice on the directory 'one/two/', and so on until read_directory_recursive() was called 2^5 times for 'one/two/three/four/five/'. Avoid calling read_directory_recursive() twice per level by moving a lot of the special logic into treat_directory(). Since dir.c is somewhat complex, extra cruft built up around this over time. While trying to unravel it, I noticed several instances where the first call to read_directory_recursive() would return e.g. path_untracked for some directory and a later one would return e.g. path_none, despite the fact that the directory clearly should have been considered untracked. The code happened to work due to the side-effect from the first invocation of adding untracked entries to dir->entries; this allowed it to get the correct output despite the supposed override in return value by the later call. I am somewhat concerned that there are still bugs and maybe even testcases with the wrong expectation. I have tried to carefully document treat_directory() since it becomes more complex after this change (though much of this complexity came from elsewhere that probably deserved better comments to begin with). However, much of my work felt more like a game of whackamole while attempting to make the code match the existing regression tests than an attempt to create an implementation that matched some clear design. That seems wrong to me, but the rules of existing behavior had so many special cases that I had a hard time coming up with some overarching rules about what correct behavior is for all cases, forcing me to hope that the regression tests are correct and sufficient. Such a hope seems likely to be ill-founded, given my experience with dir.c-related testcases in the last few months: Examples where the documentation was hard to parse or even just wrong: * 3aca58045f4f (git-clean.txt: do not claim we will delete files with -n/--dry-run, 2019-09-17) * 09487f2cbad3 (clean: avoid removing untracked files in a nested git repository, 2019-09-17) * e86bbcf987fa (clean: disambiguate the definition of -d, 2019-09-17) Examples where testcases were declared wrong and changed: * 09487f2cbad3 (clean: avoid removing untracked files in a nested git repository, 2019-09-17) * e86bbcf987fa (clean: disambiguate the definition of -d, 2019-09-17) * a2b13367fe55 (Revert "dir.c: make 'git-status --ignored' work within leading directories", 2019-12-10) Examples where testcases were clearly inadequate: * 502c386ff944 (t7300-clean: demonstrate deleting nested repo with an ignored file breakage, 2019-08-25) * 7541cc530239 (t7300: add testcases showing failure to clean specified pathspecs, 2019-09-17) * a5e916c7453b (dir: fix off-by-one error in match_pathspec_item, 2019-09-17) * 404ebceda01c (dir: also check directories for matching pathspecs, 2019-09-17) * 09487f2cbad3 (clean: avoid removing untracked files in a nested git repository, 2019-09-17) * e86bbcf987fa (clean: disambiguate the definition of -d, 2019-09-17) * 452efd11fbf6 (t3011: demonstrate directory traversal failures, 2019-12-10) * b9670c1f5e6b (dir: fix checks on common prefix directory, 2019-12-19) Examples where "correct behavior" was unclear to everyone: https://lore.kernel.org/git/20190905154735.29784-1-newren@gmail.com/ Other commits of note: * 902b90cf42bc (clean: fix theoretical path corruption, 2019-09-17) However, on the positive side, it does make the code much faster. For the following simple shell loop in an empty repository: for depth in $(seq 10 25) do dirs=$(for i in $(seq 1 $depth) ; do printf 'dir/' ; done) rm -rf dir mkdir -p $dirs >$dirs/untracked-file /usr/bin/time --format="$depth: %e" git status --ignored >/dev/null done I saw the following timings, in seconds (note that the numbers are a little noisy from run-to-run, but the trend is very clear with every run): 10: 0.03 11: 0.05 12: 0.08 13: 0.19 14: 0.29 15: 0.50 16: 1.05 17: 2.11 18: 4.11 19: 8.60 20: 17.55 21: 33.87 22: 68.71 23: 140.05 24: 274.45 25: 551.15 For the above run, using strace I can look for the number of untracked directories opened and can verify that it matches the expected 2^($depth+1)-2 (the sum of 2^1 + 2^2 + 2^3 + ... + 2^$depth). After this fix, with strace I can verify that the number of untracked directories that are opened drops to just $depth, and the timings all drop to 0.00. In fact, it isn't until a depth of 190 nested directories that it sometimes starts reporting a time of 0.01 seconds and doesn't consistently report 0.01 seconds until there are 240 nested directories. The previous code would have taken 17.55 * 2^220 / (60*60*24*365) = 9.4 * 10^59 YEARS to have completed the 240 nested directories case. It's not often that you get to speed something up by a factor of 3*10^69. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-04-01dir: refactor treat_directory to clarify control flowLibravatar Derrick Stolee1-18/+17
The logic in treat_directory() is handled by a multi-case switch statement, but this switch is very asymmetrical, as the first two cases are simple but the third is more complicated than the rest of the method. In fact, the third case includes a "break" statement that leads to the block of code outside the switch statement. That is the only way to reach that block, as the switch handles all possible values from directory_exists_in_index(); Extract the switch statement into a series of "if" statements. This simplifies the trivial cases, while clarifying how to reach the "show_other_directories" case. This is particularly important as the "show_other_directories" case will expand in a later change. Helped-by: Elijah Newren <newren@gmail.com> Signed-off-by: Derrick Stolee <dstolee@microsoft.com> Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-04-01dir: fix confusion based on variable tenseLibravatar Elijah Newren1-13/+13
Despite having contributed several fixes in this area, I have for months (years?) assumed that the "exclude" variable was a directive; this caused me to think of it as a different mode we operate in and left me confused as I tried to build up a mental model around why we'd need such a directive. I mostly tried to ignore it while focusing on the pieces I was trying to understand. Then I finally traced this variable all back to a call to is_excluded(), meaning it was actually functioning as an adjective. In particular, it was a checked property ("Does this path match a rule in .gitignore?"), rather than a mode passed in from the caller. Change the variable name to match the part of speech used by the function called to define it, which will hopefully make these bits of code slightly clearer to the next reader. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-04-01dir: fix broken commentLibravatar Elijah Newren1-1/+1
Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-04-01dir: consolidate treat_path() and treat_one_path()Libravatar Elijah Newren1-66/+55
Commit 16e2cfa90993 ("read_directory(): further split treat_path()", 2010-01-08) split treat_one_path() out of treat_path(), because treat_leading_path() would not have access to a dirent but wanted to re-use as much of treat_path() as possible. Not re-using all of treat_path() caused other bugs, as noted in commit b9670c1f5e6b ("dir: fix checks on common prefix directory", 2019-12-19). Finally, in commit ad6f2157f951 ("dir: restructure in a way to avoid passing around a struct dirent", 2020-01-16), dirents were removed from treat_path() and other functions entirely. Since the only reason for splitting these functions was the lack of a dirent -- which no longer applies to either function -- and since the split caused problems in the past resulting in us not using treat_one_path() separately anymore, just undo the split. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-04-01dir: fix simple typo in commentLibravatar Elijah Newren1-1/+1
Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-04-01t3000: add more testcases testing a variety of ls-files issuesLibravatar Elijah Newren1-0/+121
This adds seven new ls-files tests. While currently all seven test pass, my earlier rounds of restructuring dir.c to replace an exponential algorithm with a linear one passed all the tests in the testsuite but failed six of these seven new tests. Add these tests to increase our case coverage. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-04-01t7063: more thorough status checkingLibravatar Elijah Newren1-0/+52
It turns out the t7063 has some testcases that even without using the untracked cache cover situations that nothing else in the testsuite handles. Checking the results of git status --porcelain both with and without the untracked cache, and comparing both against our expected results helped uncover a critical bug in some dir.c restructuring. Unfortunately, it's not easy to run status and tell it to ignore the untracked cache; the only knob we have is core.untrackedCache=false, which is used to instruct git to *delete* the untracked cache (which might also ignore the untracked cache when it operates, but that isn't specified in the docs). Create a simple helper that will create a clone of the index that is missing the untracked cache bits, and use it to compare that the results with the untracked cache match the results we get without the untracked cache. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-03-17Git 2.25.2Libravatar Junio C Hamano3-2/+62
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-03-17unicode: update the width tables to Unicode 13.0Libravatar Beat Bolli1-16/+27
Now that Unicode 13.0 has been announced[0], update the character width tables to the new version. [0] https://home.unicode.org/announcing-the-unicode-standard-version-13-0/ Signed-off-by: Beat Bolli <dev+git@drbeat.li> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-03-17Merge branch 'js/ci-windows-update' into maintLibravatar Junio C Hamano10-73/+93
Updates to the CI settings. * js/ci-windows-update: Azure Pipeline: switch to the latest agent pools ci: prevent `perforce` from being quarantined t/lib-httpd: avoid using macOS' sed
2020-03-17Merge branch 'jk/run-command-formatfix' into maintLibravatar Junio C Hamano1-1/+1
Code style cleanup. * jk/run-command-formatfix: run-command.h: fix mis-indented struct member
2020-03-17Merge branch 'jk/doc-credential-helper' into maintLibravatar Junio C Hamano2-91/+88
Docfix. * jk/doc-credential-helper: doc: move credential helper info into gitcredentials(7)
2020-03-17Merge branch 'js/mingw-open-in-gdb' into maintLibravatar Junio C Hamano2-0/+23
Dev support. * js/mingw-open-in-gdb: mingw: add a helper function to attach GDB to the current process
2020-03-17Merge branch 'js/test-unc-fetch' into maintLibravatar Junio C Hamano1-0/+12
Test updates. * js/test-unc-fetch: t5580: test cloning without file://, test fetching via UNC paths
2020-03-17Merge branch 'js/test-write-junit-xml-fix' into maintLibravatar Junio C Hamano1-1/+2
Testfix. * js/test-write-junit-xml-fix: tests: fix --write-junit-xml with subshells
2020-03-17Merge branch 'en/simplify-check-updates-in-unpack-trees' into maintLibravatar Junio C Hamano1-12/+14
Code simplification. * en/simplify-check-updates-in-unpack-trees: unpack-trees: exit check_updates() early if updates are not wanted
2020-03-17Merge branch 'jc/doc-single-h-is-for-help' into maintLibravatar Junio C Hamano2-1/+8
Both "git ls-remote -h" and "git grep -h" give short usage help, like any other Git subcommand, but it is not unreasonable to expect that the former would behave the same as "git ls-remote --head" (there is no other sensible behaviour for the latter). The documentation has been updated in an attempt to clarify this. * jc/doc-single-h-is-for-help: Documentation: clarify that `-h` alone stands for `help`
2020-03-17Merge branch 'hd/show-one-mergetag-fix' into maintLibravatar Junio C Hamano2-1/+21
"git show" and others gave an object name in raw format in its error output, which has been corrected to give it in hex. * hd/show-one-mergetag-fix: show_one_mergetag: print non-parent in hex form.
2020-03-17Merge branch 'am/mingw-poll-fix' into maintLibravatar Junio C Hamano1-28/+3
MinGW's poll() emulation has been improved. * am/mingw-poll-fix: mingw: workaround for hangs when sending STDIN
2020-03-17Merge branch 'hi/gpg-use-check-signature' into maintLibravatar Junio C Hamano4-72/+75
"git merge signed-tag" while lacking the public key started to say "No signature", which was utterly wrong. This regression has been reverted. * hi/gpg-use-check-signature: Revert "gpg-interface: prefer check_signature() for GPG verification"
2020-03-17Merge branch 'ds/partial-clone-fixes' into maintLibravatar Junio C Hamano2-5/+36
Fix for a bug revealed by a recent change to make the protocol v2 the default. * ds/partial-clone-fixes: partial-clone: avoid fetching when looking for objects partial-clone: demonstrate bugs in partial fetch
2020-03-17Merge branch 'en/t3433-rebase-stat-dirty-failure' into maintLibravatar Junio C Hamano2-2/+53
The merge-recursive machinery failed to refresh the cache entry for a merge result in a couple of places, resulting in an unnecessary merge failure, which has been fixed. * en/t3433-rebase-stat-dirty-failure: merge-recursive: fix the refresh logic in update_file_flags t3433: new rebase testcase documenting a stat-dirty-like failure
2020-03-17Merge branch 'en/check-ignore' into maintLibravatar Junio C Hamano3-19/+35
"git check-ignore" did not work when the given path is explicitly marked as not ignored with a negative entry in the .gitignore file. * en/check-ignore: check-ignore: fix documentation and implementation to match
2020-03-17Merge branch 'jk/push-option-doc-markup-fix' into maintLibravatar Junio C Hamano1-2/+2
Doc markup fix. * jk/push-option-doc-markup-fix: doc/config/push: use longer "--" line for preformatted example
2020-03-17Merge branch 'jk/doc-diff-parallel' into maintLibravatar Junio C Hamano1-1/+1
Update to doc-diff. * jk/doc-diff-parallel: doc-diff: use single-colon rule in rendering Makefile
2020-03-17Merge branch 'jh/notes-fanout-fix' into maintLibravatar Junio C Hamano2-33/+94
The code to automatically shrink the fan-out in the notes tree had an off-by-one bug, which has been killed. * jh/notes-fanout-fix: notes.c: fix off-by-one error when decreasing notes fanout t3305: check notes fanout more carefully and robustly
2020-03-17Merge branch 'jk/index-pack-dupfix' into maintLibravatar Junio C Hamano2-5/+7
The index-pack code now diagnoses a bad input packstream that records the same object twice when it is used as delta base; the code used to declare a software bug when encountering such an input, but it is an input error. * jk/index-pack-dupfix: index-pack: downgrade twice-resolved REF_DELTA to die()
2020-03-17Merge branch 'js/rebase-i-with-colliding-hash' into maintLibravatar Junio C Hamano3-9/+34
"git rebase -i" identifies existing commits in its todo file with their abbreviated object name, which could become ambigous as it goes to create new commits, and has a mechanism to avoid ambiguity in the main part of its execution. A few other cases however were not covered by the protection against ambiguity, which has been corrected. * js/rebase-i-with-colliding-hash: rebase -i: also avoid SHA-1 collisions with missingCommitsCheck rebase -i: re-fix short SHA-1 collision parse_insn_line(): improve error message when parsing failed
2020-03-17Merge branch 'jk/clang-sanitizer-fixes' into maintLibravatar Junio C Hamano5-15/+29
C pedantry ;-) fix. * jk/clang-sanitizer-fixes: obstack: avoid computing offsets from NULL pointer xdiff: avoid computing non-zero offset from NULL pointer avoid computing zero offsets from NULL pointer merge-recursive: use subtraction to flip stage merge-recursive: silence -Wxor-used-as-pow warning
2020-03-17Merge branch 'dt/submodule-rm-with-stale-cache' into maintLibravatar Junio C Hamano2-1/+8
Running "git rm" on a submodule failed unnecessarily when .gitmodules is only cache-dirty, which has been corrected. * dt/submodule-rm-with-stale-cache: git rm submodule: succeed if .gitmodules index stat info is zero
2020-03-17Merge branch 'pb/recurse-submodule-in-worktree-fix' into maintLibravatar Junio C Hamano3-80/+93
The "--recurse-submodules" option of various subcommands did not work well when run in an alternate worktree, which has been corrected. * pb/recurse-submodule-in-worktree-fix: submodule.c: use get_git_dir() instead of get_git_common_dir() t2405: clarify test descriptions and simplify test t2405: use git -C and test_commit -C instead of subshells t7410: rename to t2405-worktree-submodule.sh
2020-03-17Merge branch 'es/outside-repo-errmsg-hints' into maintLibravatar Junio C Hamano3-4/+52
An earlier update to show the location of working tree in the error message did not consider the possibility that a git command may be run in a bare repository, which has been corrected. * es/outside-repo-errmsg-hints: prefix_path: show gitdir if worktree unavailable prefix_path: show gitdir when arg is outside repo
2020-03-17Merge branch 'js/builtin-add-i-cmds' into maintLibravatar Junio C Hamano2-3/+15
Minor bugfixes to "git add -i" that has recently been rewritten in C. * js/builtin-add-i-cmds: built-in add -i: accept open-ended ranges again built-in add -i: do not try to `patch`/`diff` an empty list of files
2020-03-15prefix_path: show gitdir if worktree unavailableLibravatar Emily Shaffer3-4/+50
If there is no worktree at present, we can still hint the user about Git's current directory by showing them the absolute path to the Git directory. Even though the Git directory doesn't make it as easy to locate the worktree in question, it can still help a user figure out what's going on while developing a script. This fixes a segmentation fault introduced in e0020b2f ("prefix_path: show gitdir when arg is outside repo", 2020-02-14). Signed-off-by: Emily Shaffer <emilyshaffer@google.com> [jc: added minimum tests, with help from Szeder Gábor] Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-03-02show_one_mergetag: print non-parent in hex form.Libravatar Harald van Dijk2-1/+21
When a mergetag names a non-parent, which can occur after a shallow clone, its hash was previously printed as raw data. Print it in hex form instead. Signed-off-by: Harald van Dijk <harald@gigawatt.nl> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-02-28Revert "gpg-interface: prefer check_signature() for GPG verification"Libravatar Junio C Hamano4-72/+75
This reverts commit 72b006f4bfd30b7c5037c163efaf279ab65bea9c, which breaks the end-user experience when merging a signed tag without having the public key. We should report "can't check because we have no public key", but the code with this change claimed that there was no signature.
2020-02-27mingw: workaround for hangs when sending STDINLibravatar Alexandr Miloslavskiy1-28/+3
Explanation ----------- The problem here is flawed `poll()` implementation. When it tries to see if pipe can be written without blocking, it eventually calls `NtQueryInformationFile()` and tests `WriteQuotaAvailable`. However, the meaning of quota was misunderstood. The value of quota is reduced when either some data was written to a pipe, *or* there is a pending read on the pipe. Therefore, if there is a pending read of size >= than the pipe's buffer size, poll() will think that pipe is not writable and will hang forever, usually that means deadlocking both pipe users. I have studied the problem and found that Windows pipes track two values: `QuotaUsed` and `BytesInQueue`. The code in `poll()` apparently wants to know `BytesInQueue` instead of quota. Unfortunately, `BytesInQueue` can only be requested from read end of the pipe, while `poll()` receives write end. The git's implementation of `poll()` was copied from gnulib, which also contains a flawed implementation up to today. I also had a look at implementation in cygwin, which is also broken in a subtle way. It uses this code in `pipe_data_available()`: fpli.WriteQuotaAvailable = (fpli.OutboundQuota - fpli.ReadDataAvailable) However, `ReadDataAvailable` always returns 0 for the write end of the pipe, turning the code into an obfuscated version of returning pipe's total buffer size, which I guess will in turn have `poll()` always say that pipe is writable. The commit that introduced the code doesn't say anything about this change, so it could be some debugging code that slipped in. These are the typical sizes used in git: 0x2000 - default read size in `strbuf_read()` 0x1000 - default read size in CRT, used by `strbuf_getwholeline()` 0x2000 - pipe buffer size in compat\mingw.c As a consequence, as soon as child process uses `strbuf_read()`, `poll()` in parent process will hang forever, deadlocking both processes. This results in two observable behaviors: 1) If parent process begins sending STDIN quickly (and usually that's the case), then first `poll()` will succeed and first block will go through. MAX_IO_SIZE_DEFAULT is 8MB, so if STDIN exceeds 8MB, then it will deadlock. 2) If parent process waits a little bit for any reason (including OS scheduler) and child is first to issue `strbuf_read()`, then it will deadlock immediately even on small STDINs. The problem is illustrated by `git stash push`, which will currently read the entire patch into memory and then send it to `git apply` via STDIN. If patch exceeds 8MB, git hangs on Windows. Possible solutions ------------------ 1) Somehow obtain `BytesInQueue` instead of `QuotaUsed` I did a pretty thorough search and didn't find any ways to obtain the value from write end of the pipe. 2) Also give read end of the pipe to `poll()` That can be done, but it will probably invite some dirty code, because `poll()` * can accept multiple pipes at once * can accept things that are not pipes * is expected to have a well known signature. 3) Make `poll()` always reply "writable" for write end of the pipe Afterall it seems that cygwin (accidentally?) does that for years. Also, it should be noted that `pump_io_round()` writes 8MB blocks, completely ignoring the fact that pipe's buffer size is only 8KB, which means that pipe gets clogged many times during that single write. This may invite a deadlock, if child's STDERR/STDOUT gets clogged while it's trying to deal with 8MB of STDIN. Such deadlocks could be defeated with writing less than pipe's buffer size per round, and always reading everything from STDOUT/STDERR before starting next round. Therefore, making `poll()` always reply "writable" shouldn't cause any new issues or block any future solutions. 4) Increase the size of the pipe's buffer The difference between `BytesInQueue` and `QuotaUsed` is the size of pending reads. Therefore, if buffer is bigger than size of reads, `poll()` won't hang so easily. However, I found that for example `strbuf_read()` will get more and more hungry as it reads large inputs, eventually surpassing any reasonable pipe buffer size. Chosen solution --------------- Make `poll()` always reply "writable" for write end of the pipe. Hopefully one day someone will find a way to implement it properly. Reproduction ------------ printf "%8388608s" X >large_file.txt git stash push --include-untracked -- large_file.txt I have decided not to include this as test to avoid slowing down the test suite. I don't expect the specific problem to come back, and chances are that `git stash push` will be reworked to avoid sending the entire patch via STDIN. Signed-off-by: Alexandr Miloslavskiy <alexandr.miloslavskiy@syntevo.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-02-27Documentation: clarify that `-h` alone stands for `help`Libravatar Junio C Hamano2-1/+8
We seem to be getting new users who get confused every 20 months or so with this "-h consistently wants to give help, but the commands to which `-h` may feel like a good short-form option want it to mean something else." compromise. Let's make sure that the readers know that `git cmd -h` (with no other arguments) is a way to get usage text, even for commands like ls-remote and grep. Also extend the description that is already in gitcli.txt, as it is clear that users still get confused with the current text. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-02-27Azure Pipeline: switch to the latest agent poolsLibravatar Johannes Schindelin1-12/+25
It would seem that at least the `vs2015-win2012r2` pool (which we use via its old name, `Hosted`) is about to be phased out. Let's switch before that. While at it, use the newer pool names as suggested at https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/hosted?view=azure-devops#use-a-microsoft-hosted-agent Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-02-27ci: prevent `perforce` from being quarantinedLibravatar Johannes Schindelin1-2/+2
The most recent Azure Pipelines macOS agents enable what Apple calls "System Integrity Protection". This makes `p4d -V` hang: there is some sort of GUI dialog waiting for the user to acknowledge that the copied binaries are legit and may be executed, but on build agents, there is no user who could acknowledge that. Let's ask Homebrew specifically to _not_ quarantine the Perforce binaries. Helped-by: Aleksandr Chebotov Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-02-27t/lib-httpd: avoid using macOS' sedLibravatar Johannes Schindelin8-59/+66
Among other differences relative to GNU sed, macOS' sed always ends its output with a trailing newline, even if the input did not have such a trailing newline. Surprisingly, this makes three httpd-based tests fail on macOS: t5616, t5702 and t5703. ("Surprisingly" because those tests have been around for some time, but apparently nobody runs them on macOS with a working Apache2 setup.) The reason is that we use `sed` in those tests to filter the response of the web server. Apart from the fact that we use GNU constructs (such as using a space after the `c` command instead of a backslash and a newline), we have another problem: macOS' sed LF-only newlines while webservers are supposed to use CR/LF ones. Even worse, t5616 uses `sed` to replace a binary part of the response with a new binary part (kind of hoping that the replaced binary part does not contain a 0x0a byte which would be interpreted as a newline). To that end, it calls on Perl to read the binary pack file and hex-encode it, then calls on `sed` to prefix every hex digit pair with a `\x` in order to construct the text that the `c` statement of the `sed` invocation is supposed to insert. So we call Perl and sed to construct a sed statement. The final nail in the coffin is that macOS' sed does not even interpret those `\x<hex>` constructs. Let's just replace all of that by Perl snippets. With Perl, at least, we do not have to deal with GNU vs macOS semantics, we do not have to worry about unwanted trailing newlines, and we do not have to spawn commands to construct arguments for other commands to be spawned (i.e. we can avoid a whole lot of shell scripting complexity). The upshot is that this fixes t5616, t5702 and t5703 on macOS with Apache2. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-02-22partial-clone: avoid fetching when looking for objectsLibravatar Derrick Stolee2-6/+6
When using partial clone, find_non_local_tags() in builtin/fetch.c checks each remote tag to see if its object also exists locally. There is no expectation that the object exist locally, but this function nevertheless triggers a lazy fetch if the object does not exist. This can be extremely expensive when asking for a commit, as we are completely removed from the context of the non-existent object and thus supply no "haves" in the request. 6462d5eb9a (fetch: remove fetch_if_missing=0, 2019-11-05) removed a global variable that prevented these fetches in favor of a bitflag. However, some object existence checks were not updated to use this flag. Update find_non_local_tags() to use OBJECT_INFO_SKIP_FETCH_OBJECT in addition to OBJECT_INFO_QUICK. The _QUICK option only prevents repreparing the pack-file structures. We need to be extremely careful about supplying _SKIP_FETCH_OBJECT when we expect an object to not exist due to updated refs. This resolves a broken test in t5616-partial-clone.sh. Signed-off-by: Derrick Stolee <dstolee@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-02-22partial-clone: demonstrate bugs in partial fetchLibravatar Derrick Stolee1-0/+31
While testing partial clone, I noticed some odd behavior. I was testing a way of running 'git init', followed by manually configuring the remote for partial clone, and then running 'git fetch'. Astonishingly, I saw the 'git fetch' process start asking the server for multiple rounds of pack-file downloads! When tweaking the situation a little more, I discovered that I could cause the remote to hang up with an error. Add two tests that demonstrate these two issues. In the first test, we find that when fetching with blob filters from a repository that previously did not have any tags, the 'git fetch --tags origin' command fails because the server sends "multiple filter-specs cannot be combined". This only happens when using protocol v2. In the second test, we see that a 'git fetch origin' request with several ref updates results in multiple pack-file downloads. This must be due to Git trying to fault-in the objects pointed by the refs. What makes this matter particularly nasty is that this goes through the do_oid_object_info_extended() method, so there are no "haves" in the negotiation. This leads the remote to send every reachable commit and tree from each new ref, providing a quadratic amount of data transfer! This test is fixed if we revert 6462d5eb9a (fetch: remove fetch_if_missing=0, 2019-11-05), but that revert causes other test failures. The real fix will need more care. The tests are ordered in this way because if I swap the test order the tag test will succeed instead of fail. I believe this is because somehow we need the srv.bare repo to not have any tags when we clone, but then have tags in our next fetch. Signed-off-by: Derrick Stolee <dstolee@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-02-22run-command.h: fix mis-indented struct memberLibravatar Jeff King1-1/+1
An accidental conversion of a tab to 4 spaces snuck into 4c4066d95d (run-command: move doc to run-command.h, 2019-11-17), messing up the alignment when you have the project-recommended 8-width tabstops. Let's revert that line. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>