diff options
Diffstat (limited to 't')
392 files changed, 24093 insertions, 6193 deletions
diff --git a/t/Makefile b/t/Makefile index 8fd1a72357..43b15e36ae 100644 --- a/t/Makefile +++ b/t/Makefile @@ -13,7 +13,7 @@ TAR ?= $(TAR) RM ?= rm -f PROVE ?= prove DEFAULT_TEST_TARGET ?= test -TEST_LINT ?= test-lint-duplicates test-lint-executable +TEST_LINT ?= test-lint ifdef TEST_OUTPUT_DIRECTORY TEST_RESULTS_DIRECTORY = $(TEST_OUTPUT_DIRECTORY)/test-results @@ -29,6 +29,7 @@ TEST_RESULTS_DIRECTORY_SQ = $(subst ','\'',$(TEST_RESULTS_DIRECTORY)) T = $(sort $(wildcard t[0-9][0-9][0-9][0-9]-*.sh)) TSVN = $(sort $(wildcard t91[0-9][0-9]-*.sh)) TGITWEB = $(sort $(wildcard t95[0-9][0-9]-*.sh)) +THELPERS = $(sort $(filter-out $(T),$(wildcard *.sh))) all: $(DEFAULT_TEST_TARGET) @@ -65,7 +66,7 @@ test-lint-executable: echo >&2 "non-executable tests:" $$bad; exit 1; } test-lint-shell-syntax: - @'$(PERL_PATH_SQ)' check-non-portable-shell.pl $(T) + @'$(PERL_PATH_SQ)' check-non-portable-shell.pl $(T) $(THELPERS) aggregate-results-and-cleanup: $(T) $(MAKE) aggregate-results @@ -71,6 +71,7 @@ You can pass --verbose (or -v), --debug (or -d), and --immediate (or -i) command line argument to the test, or by setting GIT_TEST_OPTS appropriately before running "make". +-v:: --verbose:: This makes the test more verbose. Specifically, the command being run and their output if any are also @@ -81,6 +82,13 @@ appropriately before running "make". numbers matching <pattern>. The number matched against is simply the running count of the test within the file. +-x:: + Turn on shell tracing (i.e., `set -x`) during the tests + themselves. Implies `--verbose`. Note that this can cause + failures in some tests which redirect and test the + output of shell functions. Use with caution. + +-d:: --debug:: This may help the person who is developing a new test. It causes the command defined with test_debug to run. @@ -89,6 +97,7 @@ appropriately before running "make". failed tests so that you can inspect its contents after the test finished. +-i:: --immediate:: This causes the test to immediately exit upon the first failed test. Cleanup commands requested with @@ -96,10 +105,17 @@ appropriately before running "make". in order to keep the state for inspection by the tester to diagnose the bug. +-l:: --long-tests:: This causes additional long-running tests to be run (where available), for more exhaustive testing. +-r:: +--run=<test-selector>:: + Run only the subset of tests indicated by + <test-selector>. See section "Skipping Tests" below for + <test-selector> syntax. + --valgrind=<tool>:: Execute all Git binaries under valgrind tool <tool> and exit with status 126 on errors (just like regular tests, this will @@ -152,6 +168,16 @@ appropriately before running "make". Using this option with a RAM-based filesystem (such as tmpfs) can massively speed up the test suite. +--chain-lint:: +--no-chain-lint:: + If --chain-lint is enabled, the test harness will check each + test to make sure that it properly "&&-chains" all commands (so + that a failure in the middle does not go unnoticed by the final + exit code of the test). This check is performed in addition to + running the tests themselves. You may also enable or disable + this feature by setting the GIT_TEST_CHAIN_LINT environment + variable to "1" or "0", respectively. + You can also set the GIT_TEST_INSTALLED environment variable to the bindir of an existing git installation to test that installation. You still need to have built this git sandbox, from which various @@ -187,10 +213,77 @@ and either can match the "t[0-9]{4}" part to skip the whole test, or t[0-9]{4} followed by ".$number" to say which particular test to skip. -Note that some tests in the existing test suite rely on previous -test item, so you cannot arbitrarily disable one and expect the -remainder of test to check what the test originally was intended -to check. +For an individual test suite --run could be used to specify that +only some tests should be run or that some tests should be +excluded from a run. + +The argument for --run is a list of individual test numbers or +ranges with an optional negation prefix that define what tests in +a test suite to include in the run. A range is two numbers +separated with a dash and matches a range of tests with both ends +been included. You may omit the first or the second number to +mean "from the first test" or "up to the very last test" +respectively. + +Optional prefix of '!' means that the test or a range of tests +should be excluded from the run. + +If --run starts with an unprefixed number or range the initial +set of tests to run is empty. If the first item starts with '!' +all the tests are added to the initial set. After initial set is +determined every test number or range is added or excluded from +the set one by one, from left to right. + +Individual numbers or ranges could be separated either by a space +or a comma. + +For example, to run only tests up to a specific test (21), one +could do this: + + $ sh ./t9200-git-cvsexport-commit.sh --run='1-21' + +or this: + + $ sh ./t9200-git-cvsexport-commit.sh --run='-21' + +Common case is to run several setup tests (1, 2, 3) and then a +specific test (21) that relies on that setup: + + $ sh ./t9200-git-cvsexport-commit.sh --run='1 2 3 21' + +or: + + $ sh ./t9200-git-cvsexport-commit.sh --run=1,2,3,21 + +or: + + $ sh ./t9200-git-cvsexport-commit.sh --run='-3 21' + +As noted above, the test set is built going though items left to +right, so this: + + $ sh ./t9200-git-cvsexport-commit.sh --run='1-4 !3' + +will run tests 1, 2, and 4. Items that comes later have higher +precendence. It means that this: + + $ sh ./t9200-git-cvsexport-commit.sh --run='!3 1-4' + +would just run tests from 1 to 4, including 3. + +You may use negation with ranges. The following will run all +test in the test suite except from 7 up to 11: + + $ sh ./t9200-git-cvsexport-commit.sh --run='!7-11' + +Some tests in a test suite rely on the previous tests performing +certain actions, specifically some tests are designated as +"setup" test, so you cannot _arbitrarily_ disable one test and +expect the rest to function correctly. + +--run is mostly useful when you want to focus on a specific test +and know what setup is needed for it. Or when you want to run +everything up to a certain test. Naming Tests @@ -335,7 +428,8 @@ Don't: dies in an unexpected way (e.g. segfault). On the other hand, don't use test_must_fail for running regular - platform commands; just use '! cmd'. + platform commands; just use '! cmd'. We are not in the business + of verifying that the world given to us sanely works. - use perl without spelling it as "$PERL_PATH". This is to help our friends on Windows where the platform Perl often adds CR before @@ -469,6 +563,11 @@ library for your script to use. argument. This is primarily meant for use during the development of a new test script. + - debug <git-command> + + Run a git command inside a debugger. This is primarily meant for + use when debugging a failing test script. + - test_done Your test script must have test_done at the end. Its purpose @@ -596,6 +695,27 @@ library for your script to use. ... ' + - test_write_lines <lines> + + Write <lines> on standard output, one line per argument. + Useful to prepare multi-line files in a compact form. + + Example: + + test_write_lines a b c d e f g >foo + + Is a more compact equivalent of: + cat >foo <<-EOF + a + b + c + d + e + f + g + EOF + + - test_pause This command is useful for writing and debugging tests and must be diff --git a/t/annotate-tests.sh b/t/annotate-tests.sh index 304c7b7d87..093832fef1 100644 --- a/t/annotate-tests.sh +++ b/t/annotate-tests.sh @@ -1,6 +1,17 @@ # This file isn't used as a test script directly, instead it is # sourced from t8001-annotate.sh and t8002-blame.sh. +if test_have_prereq MINGW +then + sanitize_L () { + echo "$1" | sed 'sX\(^-L\|,\)\^\?/X&\\;*Xg' + } +else + sanitize_L () { + echo "$1" + } +fi + check_count () { head= && file='file' && @@ -10,6 +21,7 @@ check_count () { case "$1" in -h) head="$2"; shift; shift ;; -f) file="$2"; shift; shift ;; + -L*) options="$options $(sanitize_L "$1")"; shift ;; -*) options="$options $1"; shift ;; *) break ;; esac @@ -56,6 +68,13 @@ test_expect_success 'blame 1 author' ' check_count A 2 ' +test_expect_success 'blame by tag objects' ' + git tag -m "test tag" testTag && + git tag -m "test tag #2" testTag2 testTag && + check_count -h testTag A 2 && + check_count -h testTag2 A 2 +' + test_expect_success 'setup B lines' ' echo "2A quick brown fox jumps over the" >>file && echo "lazy dog" >>file && @@ -99,6 +118,10 @@ test_expect_success 'blame 2 authors + 2 merged-in authors' ' check_count A 2 B 1 B1 2 B2 1 ' +test_expect_success 'blame --first-parent blames merge for branch1' ' + check_count --first-parent A 2 B 1 "A U Thor" 2 B2 1 +' + test_expect_success 'blame ancestor' ' check_count -h master A 2 B 2 ' @@ -393,7 +416,7 @@ test_expect_success 'setup -L :regex' ' mv hello.c hello.orig && echo "#include <stdio.h>" >hello.c && cat hello.orig >>hello.c && - tr Q "\\t" >>hello.c <<-\EOF + tr Q "\\t" >>hello.c <<-\EOF && void mail() { Qputs("mail"); diff --git a/t/check-non-portable-shell.pl b/t/check-non-portable-shell.pl index 45971f43b7..b170cbc045 100755 --- a/t/check-non-portable-shell.pl +++ b/t/check-non-portable-shell.pl @@ -16,12 +16,12 @@ sub err { while (<>) { chomp; - /^\s*sed\s+-i/ and err 'sed -i is not portable'; - /^\s*echo\s+-n/ and err 'echo -n is not portable (please use printf)'; + /\bsed\s+-i/ and err 'sed -i is not portable'; + /\becho\s+-n/ and err 'echo -n is not portable (please use printf)'; /^\s*declare\s+/ and err 'arrays/declare not portable'; /^\s*[^#]\s*which\s/ and err 'which is not portable (please use type)'; - /test\s+[^=]*==/ and err '"test a == b" is not portable (please use =)'; - /^\s*export\s+[^=]*=/ and err '"export FOO=bar" is not portable (please use FOO=bar && export FOO)'; + /\btest\s+[^=]*==/ and err '"test a == b" is not portable (please use =)'; + /\bexport\s+[A-Za-z0-9_]*=/ and err '"export FOO=bar" is not portable (please use FOO=bar && export FOO)'; # this resets our $. for each file close ARGV if eof; } diff --git a/t/diff-lib.sh b/t/diff-lib.sh index 75a35fcd06..c211dc40ee 100644 --- a/t/diff-lib.sh +++ b/t/diff-lib.sh @@ -1,6 +1,6 @@ : -sanitize_diff_raw='/^:/s/ '"$_x40"' '"$_x40"' \([A-Z]\)[0-9]* / X X \1# /' +sanitize_diff_raw='/^:/s/ '"\($_x40\)"' '"\($_x40\)"' \([A-Z]\)[0-9]* / \1 \2 \3# /' compare_diff_raw () { # When heuristics are improved, the score numbers would change. # Ignore them while comparing. diff --git a/t/diff-lib/COPYING b/t/diff-lib/COPYING new file mode 100644 index 0000000000..6ff87c4664 --- /dev/null +++ b/t/diff-lib/COPYING @@ -0,0 +1,361 @@ + + Note that the only valid version of the GPL as far as this project + is concerned is _this_ particular version of the license (ie v2, not + v2.2 or v3.x or whatever), unless explicitly otherwise stated. + + HOWEVER, in order to allow a migration to GPLv3 if that seems like + a good idea, I also ask that people involved with the project make + their preferences known. In particular, if you trust me to make that + decision, you might note so in your copyright message, ie something + like + + This file is licensed under the GPL v2, or a later version + at the discretion of Linus. + + might avoid issues. But we can also just decide to synchronize and + contact all copyright holders on record if/when the occasion arises. + + Linus Torvalds + +---------------------------------------- + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/t/diff-lib/README b/t/diff-lib/README new file mode 100644 index 0000000000..548142c327 --- /dev/null +++ b/t/diff-lib/README @@ -0,0 +1,46 @@ +//////////////////////////////////////////////////////////////// + + GIT - the stupid content tracker + +//////////////////////////////////////////////////////////////// + +"git" can mean anything, depending on your mood. + + - random three-letter combination that is pronounceable, and not + actually used by any common UNIX command. The fact that it is a + mispronunciation of "get" may or may not be relevant. + - stupid. contemptible and despicable. simple. Take your pick from the + dictionary of slang. + - "global information tracker": you're in a good mood, and it actually + works for you. Angels sing, and a light suddenly fills the room. + - "goddamn idiotic truckload of sh*t": when it breaks + +Git is a fast, scalable, distributed revision control system with an +unusually rich command set that provides both high-level operations +and full access to internals. + +Git is an Open Source project covered by the GNU General Public License. +It was originally written by Linus Torvalds with help of a group of +hackers around the net. It is currently maintained by Junio C Hamano. + +Please read the file INSTALL for installation instructions. +See Documentation/tutorial.txt to get started, then see +Documentation/everyday.txt for a useful minimum set of commands, +and "man git-commandname" for documentation of each command. +CVS users may also want to read Documentation/cvs-migration.txt. + +Many Git online resources are accessible from http://git.or.cz/ +including full documentation and Git related tools. + +The user discussion and development of Git take place on the Git +mailing list -- everyone is welcome to post bug reports, feature +requests, comments and patches to git@vger.kernel.org. To subscribe +to the list, send an email with just "subscribe git" in the body to +majordomo@vger.kernel.org. The mailing list archives are available at +http://marc.theaimsgroup.com/?l=git and other archival sites. + +The messages titled "A note from the maintainer", "What's in +git.git (stable)" and "What's cooking in git.git (topics)" and +the discussion following them on the mailing list give a good +reference for project status, development direction and +remaining tasks. diff --git a/t/lib-credential.sh b/t/lib-credential.sh index 957ae936e8..d8e41f7ddd 100755 --- a/t/lib-credential.sh +++ b/t/lib-credential.sh @@ -278,12 +278,10 @@ helper_test_timeout() { ' } -cat >askpass <<\EOF -#!/bin/sh +write_script askpass <<\EOF echo >&2 askpass: $* -what=`echo $1 | cut -d" " -f1 | tr A-Z a-z | tr -cd a-z` +what=$(echo $1 | cut -d" " -f1 | tr A-Z a-z | tr -cd a-z) echo "askpass-$what" EOF -chmod +x askpass GIT_ASKPASS="$PWD/askpass" export GIT_ASKPASS diff --git a/t/lib-cvs.sh b/t/lib-cvs.sh index 5076718916..9b2bcfb1b0 100644 --- a/t/lib-cvs.sh +++ b/t/lib-cvs.sh @@ -13,7 +13,7 @@ fi CVS="cvs -f" export CVS -cvsps_version=`cvsps -h 2>&1 | sed -ne 's/cvsps version //p'` +cvsps_version=$(cvsps -h 2>&1 | sed -ne 's/cvsps version //p') case "$cvsps_version" in 2.1 | 2.2*) ;; diff --git a/t/lib-git-p4.sh b/t/lib-git-p4.sh index 5aa8adcf9c..f9ae1d780d 100644 --- a/t/lib-git-p4.sh +++ b/t/lib-git-p4.sh @@ -6,6 +6,14 @@ # a subdirectory called "$git" TEST_NO_CREATE_REPO=NoThanks +# Some operations require multiple attempts to be successful. Define +# here the maximal retry timeout in seconds. +RETRY_TIMEOUT=60 + +# Sometimes p4d seems to hang. Terminate the p4d process automatically after +# the defined timeout in seconds. +P4D_TIMEOUT=300 + . ./test-lib.sh if ! test_have_prereq PYTHON @@ -36,6 +44,15 @@ native_path() { echo "$path" } +# On Solaris the 'date +%s' function is not supported and therefore we +# need this replacement. +# Attention: This function is not safe again against time offset updates +# at runtime (e.g. via NTP). The 'clock_gettime(CLOCK_MONOTONIC)' +# function could fix that but it is not in Python until 3.3. +time_in_seconds() { + python -c 'import time; print int(time.time())' +} + # Try to pick a unique port: guess a large number, then hope # no more than one of each test is running. # @@ -57,6 +74,15 @@ cli="$TRASH_DIRECTORY/cli" git="$TRASH_DIRECTORY/git" pidfile="$TRASH_DIRECTORY/p4d.pid" +# Sometimes "prove" seems to hang on exit because p4d is still running +cleanup() { + if test -f "$pidfile" + then + kill -9 $(cat "$pidfile") 2>/dev/null && exit 255 + fi +} +trap cleanup EXIT + # git p4 submit generates a temp file, which will # not get cleaned up if the submission fails. Don't # clutter up /tmp on the test machine. @@ -69,7 +95,7 @@ start_p4d() { ( cd "$db" && { - p4d -q -p $P4DPORT & + p4d -q -p $P4DPORT "$@" & echo $! >"$pidfile" } ) && @@ -81,6 +107,19 @@ start_p4d() { # will be caught with the "kill -0" check below. i=${P4D_START_PATIENCE:-300} pid=$(cat "$pidfile") + + timeout=$(($(time_in_seconds) + $P4D_TIMEOUT)) + while true + do + if test $(time_in_seconds) -gt $timeout + then + kill -9 $pid + exit 1 + fi + sleep 1 + done & + watchdog_pid=$! + ready= while test $i -gt 0 do @@ -121,22 +160,36 @@ p4_add_user() { EOF } +retry_until_success() { + timeout=$(($(time_in_seconds) + $RETRY_TIMEOUT)) + until "$@" 2>/dev/null || test $(time_in_seconds) -gt $timeout + do + sleep 1 + done +} + +retry_until_fail() { + timeout=$(($(time_in_seconds) + $RETRY_TIMEOUT)) + until ! "$@" 2>/dev/null || test $(time_in_seconds) -gt $timeout + do + sleep 1 + done +} + kill_p4d() { pid=$(cat "$pidfile") - # it had better exist for the first kill - kill $pid && - for i in 1 2 3 4 5 ; do - kill $pid >/dev/null 2>&1 || break - sleep 1 - done && + retry_until_fail kill $pid + retry_until_fail kill -9 $pid # complain if it would not die test_must_fail kill $pid >/dev/null 2>&1 && - rm -rf "$db" "$cli" "$pidfile" + rm -rf "$db" "$cli" "$pidfile" && + retry_until_fail kill -9 $watchdog_pid } cleanup_git() { - rm -rf "$git" && - mkdir "$git" + retry_until_success rm -r "$git" + test_must_fail test -d "$git" && + retry_until_success mkdir "$git" } marshal_dump() { diff --git a/t/lib-gpg.sh b/t/lib-gpg.sh index 05824fa8e4..db2ef22e8f 100755 --- a/t/lib-gpg.sh +++ b/t/lib-gpg.sh @@ -1,6 +1,6 @@ #!/bin/sh -gpg_version=`gpg --version 2>&1` +gpg_version=$(gpg --version 2>&1) if test $? = 127; then say "You do not seem to have gpg installed" else @@ -12,19 +12,43 @@ else say "Your version of gpg (1.0.6) is too buggy for testing" ;; *) - # key generation info: gpg --homedir t/lib-gpg --gen-key - # Type DSA and Elgamal, size 2048 bits, no expiration date. - # Name and email: C O Mitter <committer@example.com> + # Available key info: + # * Type DSA and Elgamal, size 2048 bits, no expiration date, + # name and email: C O Mitter <committer@example.com> + # * Type RSA, size 2048 bits, no expiration date, + # name and email: Eris Discordia <discord@example.net> # No password given, to enable non-interactive operation. - cp -R "$TEST_DIRECTORY"/lib-gpg ./gpghome - chmod 0700 gpghome - GNUPGHOME="$(pwd)/gpghome" - export GNUPGHOME + # To generate new key: + # gpg --homedir /tmp/gpghome --gen-key + # To write armored exported key to keyring: + # gpg --homedir /tmp/gpghome --export-secret-keys \ + # --armor 0xDEADBEEF >> lib-gpg/keyring.gpg + # gpg --homedir /tmp/gpghome --export \ + # --armor 0xDEADBEEF >> lib-gpg/keyring.gpg + # To export ownertrust: + # gpg --homedir /tmp/gpghome --export-ownertrust \ + # > lib-gpg/ownertrust + mkdir ./gpghome && + chmod 0700 ./gpghome && + GNUPGHOME="$(pwd)/gpghome" && + export GNUPGHOME && + gpg --homedir "${GNUPGHOME}" 2>/dev/null --import \ + "$TEST_DIRECTORY"/lib-gpg/keyring.gpg && + gpg --homedir "${GNUPGHOME}" 2>/dev/null --import-ownertrust \ + "$TEST_DIRECTORY"/lib-gpg/ownertrust && + gpg --homedir "${GNUPGHOME}" </dev/null >/dev/null 2>&1 \ + --sign -u committer@example.com && test_set_prereq GPG ;; esac fi +if test_have_prereq GPG && + echo | gpg --homedir "${GNUPGHOME}" -b --rfc1991 >/dev/null 2>&1 +then + test_set_prereq RFC1991 +fi + sanitize_pgp() { perl -ne ' /^-----END PGP/ and $in_pgp = 0; diff --git a/t/lib-gpg/keyring.gpg b/t/lib-gpg/keyring.gpg new file mode 100644 index 0000000000..d4754a1f19 --- /dev/null +++ b/t/lib-gpg/keyring.gpg @@ -0,0 +1,142 @@ +-----BEGIN PGP PRIVATE KEY BLOCK----- +Version: GnuPG v1 + +lQG7BEZnyykRBACzCPjIpTYNL7Y2tQqlEGTTDlvZcWNLjF5f7ZzuyOqNOidLUgFD +36qch1LZLSZkShdR3Gae+bsolyjxrlFuFP0eXRPMtqK20aLw7WZvPFpEV1ThMne+ +PRJjYrvghWw3L0VVIAIZ8GXwrVBuU99uEjHEI0ojYloOvFc2jVPgSaoBvwCg48Tj +fol2foSoJa7XUu9yAL8szg8D/RUsTzNF+I9hSRHl7MYKFMYoKEY9BDgrgAujp7YY +8qdGsiUb0Ggyzp2kRjZFt4lpcvKhGfHn5GEjmtk+fRbD5qPfMqKFW+T0NPfYlYmL +JJ4fs4qZ8Lx7x6iG6X51u+YNwsQuIGjMCC3CeNi3F7or651kkNYASbaQ1NROkCIN +NudyA/0aasvoZUoNJAc2cP5Ifs6WhXMWLfMR2p2XbfKwKNYneec60usnSComcKqh +sJVk0Gytvr3FOYVhRkXnKAbx+0W2urFP8OFVBTEKO6Ts2VygWGgneQYoHnqzwlUE +yjOjlr+lyf7u2s/KAxpKA6jnttEdRZAmzWkhuox1wwAUkr27/QAAn3TEzKR1pxxR ++R3dHuFpnnfatMIDC5O0IkMgTyBNaXR0ZXIgPGNvbW1pdHRlckBleGFtcGxlLmNv +bT6IXgQTEQIAHgUCRmfLKQIbAwYLCQgHAwIDFQIDAxYCAQIeAQIXgAAKCRATtvUe +zd5DDXQdAKC92f+wOrTkbmPEf+u+qA/Gv6BxQwCfQ128JXCi3MpMB8tI2Kmo15tY +gnmdAj0ERmfLThAIAM65eT9T6+gg0fJn+Qxhs3FFDPjxK6AOBS3SieWWmXO6stZZ +plvb7r2+sXYp8HMHntnOX3TRPolIx1dsdkv3W3w8yUzf9Lmo2XMPsZ3/isWdEbOI +A0rO3B1xwbQO7vEoWHeB7uyYIF6YsIH0pMqxkImciwB1tnJPB9OxqPHlD/HyyHr2 +voj6nmEGaPQWj8/dkfyenXm6XmNZUZL/slk6tRhNwv4cW3QQLh39nbiz9rqvZMKF +XX8wkY4FdQkJjCGwqzG+7yJcyHvem29/iq//jRLZgdiN8BwV3MCTJyDp8/Wb/d9y +jZcUm1RdtwRiwfhfQ+zmpyspm7OxINfH65rf7f8ABA0IALRiMRs/eOD59jrYXmPS +ZQUbiALlbJJtuP2c9N3WZ5OgrhDiAW+SDIN+hgDynJ9b7C2dE3xNaud4zaXAAF44 +J4J0bAo2ZtZoJajw+GXwaZfh4Z7nPNHwEcbFD4/uXPCj9jPkcLOJqGmUY1aXdygo +t3Hn5U/zo8JxPQ83YbJQhkzAOZ/HGowLNqKgGkLLHn1X9qay0CxlfTQeEN5RZyl3 +b4qRzGgGALFvoheyZIUw1TbjRpbn3kqlJooEQY02VwXFXfLI/LwzglilH6sSckvs +0WHKLZ+0L6b3CgJHN2RsZ7QxwCBi1aemsvr65FeEXp/AYxaG5duUbsugG8PgoJ06 +bsEAAVQNQO3cXWpuiJ/nNLLnWuPunBKJUlurkBdf2GD+m+muF0VpwDchhqqbTO4e +FqOISQQYEQIACQUCRmfLTgIbDAAKCRATtvUezd5DDcHsAKDQcoAtDWJFupVRqleB +Cezx4Q2khACcCs+/LtE8Lb9hC+2cvr3uH5p82AI= +=aEiU +-----END PGP PRIVATE KEY BLOCK----- +-----BEGIN PGP PRIVATE KEY BLOCK----- +Version: GnuPG v1 + +lQOYBFFMlkcBCADJi/xnAF8yI34PHilSCbM7VtOFO17oFMkpu4cgN2QpPuM5MVjy +cvrzKSguZFvPCDLzeAFJW1uPxL4SHaHSkisCrFhijH7OJWcOPNPSFCwu+inAoAsv +Hm4ns6pfDZyRjVTHSY4rdMISqKFRozaXu8vHeBRzIhFnubBCepKZW07oKPnrnELV +TVUSUVI+6el8JFmJIWxxLNLhfRRSPF0v4MDXPF//iCWiZDI+J1pLvQ5V/f7YtfsD +GV0oPY66J72BFJG555eKBttnNY901LmI3ocn5P5iVnXDaqMElw7FKpnANXucgY3H +4kLyNkI3s3J0CGbXI7b3MBWtjctuhWv1q2G5ABEBAAEAB/wLiuza/qEfv1Cfj7FQ +ytAXpz1YoAcrcM/53TeRQhrbvIee5ZNGhLdCkyot81QeuJrSaXO0E9CxRynrjQQ7 +ibYqN7Hy0uu1kAbQQJjmVdQXTKnKJ7Wm7oM4hYhNsVCKNXc+1+5AfDYGg4nZob36 +qqgHtc+Ardl5VfUg7uF+eZrnSMynjZANgikKbPtE09DKVtVOtUE4xTD9ijkpgn65 +glsZDqb7J4QVgTeEiCDKJsQvin3SwrPBqBxBRULF2TIaMbOwe6dHiiaI85rsvAWS +VGzonUB3IU1470P2SDIVczbXYUK/nDSGx6ZZ0wLu9ZcCyUPvxVEykuh2P4UWHla+ +nHLRBADMLavcfjsCI5CRUsdurYpgE8Y3bEbcDpvzAu5jT5D25p3YPDODOXD3AKTt +PzVMARVtv8twkbgAyWaoDevJz8OtmoSwsWjdFo4YvsYw9jV7Yf3GwzD3Ya1ZnW32 +JWQr6cX8qcK0AukAD7UZkVyhU2KBvB02t8lKHLbScHXTYVqrywQA/LNUXwmHji+6 +osnSQAC8X9ggMOEs9dGo7Qlk4JgfGAH17CFI3S3ubsaVEdxz3YwzOkD8SNmEbLyW +a7CZ/RnpdAZU0nB7kSfbfZl7ajhPbgKBMsaV2yvaDdJeor4m5eKdXffRk0SksxjL +Z/4P1tTIuL8WzetGB/aDcWDFgseSAAsEALzmf579ptlSmDyGRAKQqub+mj4V3EUZ +1GVGcfBY86w3BZVDsaRiCtcNjk/lcP4AZ1Vbb42RM6jk8nLsENRc7rf2xa7ZPf0T +6n5F6W+vk7EG76RoFhKVtGZngGKiDGVavxk3FT/yf8lKrT3wYiT03SZDuZ0pWvku +FiJGEyesAC8WRz60JEVyaXMgRGlzY29yZGlhIDxkaXNjb3JkQGV4YW1wbGUubmV0 +PokBOAQTAQIAIgUCUUyWRwIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQ +YQkuhbcicYlYowf7B+f+FDcLVfw8XzGlKku1F6PI1yGCt7AMO2/JkmO4LlgHuIgF +pqe5b/XjKl0IsRcbVLitqiIokc8u+7H8yYU67DDliq7t1gqBy+qThSHcgn6WMKTa +qCqOE2jzHyqulIAzQsJQ+c5SRofEZAKT4Qa2Dy+nsqWDpIE78aJd0Vnkk9U6H2Vu +ABvUeN/IMgvxPr525o+rBD7LU4J3CtOzfV+sO6+33da+Bm9UhkR4tC4H/n1dDN1J +YuxBQbgxTq/h8mKe4/7/Yvy+5WsYd96ZRLE2ZFWeWXtKkwmYbQ42G3SZUXaZ8R8O +tbTyUrjbFKipO4wvXwhyju1l9cxAsrca6xbSCJ0DmARRTJZHAQgAqTtPFcTXqM+U +o7bOoo+dcHi8XDf/8XSEmZfMKc/U5pSTBk7h1gSKuGzjF2n3wQm6A8+101vTLaQ6 +PoFDFW8uQB00mjymGrRDYFgz8bjhnaekZnA4XThr1ROjffgMhs3uTpCebdV+lL8K +0oJTHc39TPLTg23DFcRSDN+3ARJJS7+CRBIbt9L5gObpgA4HUap/o6N7O04rQOPU +83MAqnwo2JTO/Ded0zoad0Vo31Nmk4F+KvEE52ftGHbd7yqIUGKBt2SeTAh850ac +LeNZP+V1Y7atBCr7/zm+JpHWq9OH7/NomlEIkxL8WDt8GfAKoqZgqefL+ACEnLbA +t1du3f0FswARAQABAAf8DclaIQDfPM5kYo3y+YVPoykC11RskmQWpVibdlCLHJm/ +/ISSm1fVYT7lpTOpzl0XfVX/jw9s/cviPtNS/r0G/Iwki+gi9Av5bTDiUm/oWWqd +1waPYPDGwB4QdKOviY/fOSFI9tOsszt5Czs4wDXWy90AZDWd7fkHYisbgofV1sjK +Q8bYQPabcepcZ2JyET+EpZBEmUHHqQ76bTiqjN+Vz6k1OFlsEBzGkE+WIakAhkQ2 +57oUrRgFe+h6Ch7meB/v6vVfIRSsLpZe183uc4SigqtfsgjbG9PqOcAJOqovDncB +Scg3qvpWFOAkTA3Re+yBPUd2HHl9WF/TPa2kBDCT2QQAxcJZeUCuUgDgCizqEgfs +Kzm6dy4G/OJdW0q9m9psHqD1XWLd7ZLE4+eTS1cxktJiGcGNdGoZD0EtgxkV09uM +12QYCOBErFJzv4/4oledHeEhTaRR/mFFGRp+kWTz2Ai/zNqUd3D++DYUe8g4mVQJ +6JP014XhvoRnaCfT8cH9Zd0EANsSL70WGdifcVoWKA9jFJhahc0sSG6IZvMOc7bs +cSbhBqLEnheObkarBP+A+zgllqIf+sbCassMXjcV52mnl9th3J5RWr7scrQLJ9ZX +Ivz3uoP85vwlUI98dI9roYK0OpKmG4hNFppAcgiCVNVjnQlhuQ/HoexRHxRmnmcb +38jPA/sEHPCFbLCGOSB+HQNKx/5Wf6VpFX/4oBNbIUiYoxcRl0jpYT7Lc0zbc8So +HthjPfWhXhKzYvEDC5YgASEy1cNbGMUJcGyuAInwIQjq44FSwRMkI3ISSHnbv1iH +0wBVJUzpluMebEAesdZUz1DcZWVf6eVJD0dhZxD6DoG7Xj1m9ThUiQEfBBgBAgAJ +BQJRTJZHAhsMAAoJEGEJLoW3InGJ7HEIAMXkMf4cOWmnAuvvcSm3KpLghuWik9dy +fn1sY/IG5atoKK+ypmV/TlBlMZqFQzuPIJQT8VLbmxtLlDhJG04LbI6c8axIZxOO +ZKLy5nTTSy16ztqEeS7eifHLPZg1UFFyEEIQ1XW0CNDAeuWKh90ERjyl4Cg7PnWS +Z9Ei+zj6JD5Pcdi3BJhQo9WOLOVEJ0NHmewTYqk9QVXH/0v1Hdl4LMJtgcbdbDWk +4UTkXbg9pn3umCgkNJ3Vs8fWnIWO9Izdr2/wrFY2JvUT7Yvl+wsNIWatvOEzGy7n +BOW78WUxzhu0YJTLKy+iKCjg5HS5dx6OC+e4aEEgfhNPCMkbvDsJjtQ= +=hieJ +-----END PGP PRIVATE KEY BLOCK----- +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1 + +mQGiBEZnyykRBACzCPjIpTYNL7Y2tQqlEGTTDlvZcWNLjF5f7ZzuyOqNOidLUgFD +36qch1LZLSZkShdR3Gae+bsolyjxrlFuFP0eXRPMtqK20aLw7WZvPFpEV1ThMne+ +PRJjYrvghWw3L0VVIAIZ8GXwrVBuU99uEjHEI0ojYloOvFc2jVPgSaoBvwCg48Tj +fol2foSoJa7XUu9yAL8szg8D/RUsTzNF+I9hSRHl7MYKFMYoKEY9BDgrgAujp7YY +8qdGsiUb0Ggyzp2kRjZFt4lpcvKhGfHn5GEjmtk+fRbD5qPfMqKFW+T0NPfYlYmL +JJ4fs4qZ8Lx7x6iG6X51u+YNwsQuIGjMCC3CeNi3F7or651kkNYASbaQ1NROkCIN +NudyA/0aasvoZUoNJAc2cP5Ifs6WhXMWLfMR2p2XbfKwKNYneec60usnSComcKqh +sJVk0Gytvr3FOYVhRkXnKAbx+0W2urFP8OFVBTEKO6Ts2VygWGgneQYoHnqzwlUE +yjOjlr+lyf7u2s/KAxpKA6jnttEdRZAmzWkhuox1wwAUkr27/bQiQyBPIE1pdHRl +ciA8Y29tbWl0dGVyQGV4YW1wbGUuY29tPoheBBMRAgAeBQJGZ8spAhsDBgsJCAcD +AgMVAgMDFgIBAh4BAheAAAoJEBO29R7N3kMNdB0AoL3Z/7A6tORuY8R/676oD8a/ +oHFDAJ9DXbwlcKLcykwHy0jYqajXm1iCebkCDQRGZ8tOEAgAzrl5P1Pr6CDR8mf5 +DGGzcUUM+PEroA4FLdKJ5ZaZc7qy1lmmW9vuvb6xdinwcwee2c5fdNE+iUjHV2x2 +S/dbfDzJTN/0uajZcw+xnf+KxZ0Rs4gDSs7cHXHBtA7u8ShYd4Hu7JggXpiwgfSk +yrGQiZyLAHW2ck8H07Go8eUP8fLIeva+iPqeYQZo9BaPz92R/J6debpeY1lRkv+y +WTq1GE3C/hxbdBAuHf2duLP2uq9kwoVdfzCRjgV1CQmMIbCrMb7vIlzIe96bb3+K +r/+NEtmB2I3wHBXcwJMnIOnz9Zv933KNlxSbVF23BGLB+F9D7OanKymbs7Eg18fr +mt/t/wAEDQgAtGIxGz944Pn2OtheY9JlBRuIAuVskm24/Zz03dZnk6CuEOIBb5IM +g36GAPKcn1vsLZ0TfE1q53jNpcAAXjgngnRsCjZm1mglqPD4ZfBpl+Hhnuc80fAR +xsUPj+5c8KP2M+Rws4moaZRjVpd3KCi3ceflT/OjwnE9DzdhslCGTMA5n8cajAs2 +oqAaQssefVf2prLQLGV9NB4Q3lFnKXdvipHMaAYAsW+iF7JkhTDVNuNGlufeSqUm +igRBjTZXBcVd8sj8vDOCWKUfqxJyS+zRYcotn7QvpvcKAkc3ZGxntDHAIGLVp6ay ++vrkV4Ren8BjFobl25Ruy6Abw+CgnTpuwYhJBBgRAgAJBQJGZ8tOAhsMAAoJEBO2 +9R7N3kMNwewAoNBygC0NYkW6lVGqV4EJ7PHhDaSEAJwKz78u0Twtv2EL7Zy+ve4f +mnzYApkBDQRRTJZHAQgAyYv8ZwBfMiN+Dx4pUgmzO1bThTte6BTJKbuHIDdkKT7j +OTFY8nL68ykoLmRbzwgy83gBSVtbj8S+Eh2h0pIrAqxYYox+ziVnDjzT0hQsLvop +wKALLx5uJ7OqXw2ckY1Ux0mOK3TCEqihUaM2l7vLx3gUcyIRZ7mwQnqSmVtO6Cj5 +65xC1U1VElFSPunpfCRZiSFscSzS4X0UUjxdL+DA1zxf/4glomQyPidaS70OVf3+ +2LX7AxldKD2Ouie9gRSRueeXigbbZzWPdNS5iN6HJ+T+YlZ1w2qjBJcOxSqZwDV7 +nIGNx+JC8jZCN7NydAhm1yO29zAVrY3LboVr9athuQARAQABtCRFcmlzIERpc2Nv +cmRpYSA8ZGlzY29yZEBleGFtcGxlLm5ldD6JATgEEwECACIFAlFMlkcCGwMGCwkI +BwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEGEJLoW3InGJWKMH+wfn/hQ3C1X8PF8x +pSpLtRejyNchgrewDDtvyZJjuC5YB7iIBaanuW/14ypdCLEXG1S4raoiKJHPLvux +/MmFOuww5Yqu7dYKgcvqk4Uh3IJ+ljCk2qgqjhNo8x8qrpSAM0LCUPnOUkaHxGQC +k+EGtg8vp7Klg6SBO/GiXdFZ5JPVOh9lbgAb1HjfyDIL8T6+duaPqwQ+y1OCdwrT +s31frDuvt93WvgZvVIZEeLQuB/59XQzdSWLsQUG4MU6v4fJinuP+/2L8vuVrGHfe +mUSxNmRVnll7SpMJmG0ONht0mVF2mfEfDrW08lK42xSoqTuML18Ico7tZfXMQLK3 +GusW0gi5AQ0EUUyWRwEIAKk7TxXE16jPlKO2zqKPnXB4vFw3//F0hJmXzCnP1OaU +kwZO4dYEirhs4xdp98EJugPPtdNb0y2kOj6BQxVvLkAdNJo8phq0Q2BYM/G44Z2n +pGZwOF04a9UTo334DIbN7k6Qnm3VfpS/CtKCUx3N/Uzy04NtwxXEUgzftwESSUu/ +gkQSG7fS+YDm6YAOB1Gqf6OjeztOK0Dj1PNzAKp8KNiUzvw3ndM6GndFaN9TZpOB +firxBOdn7Rh23e8qiFBigbdknkwIfOdGnC3jWT/ldWO2rQQq+/85viaR1qvTh+/z +aJpRCJMS/Fg7fBnwCqKmYKnny/gAhJy2wLdXbt39BbMAEQEAAYkBHwQYAQIACQUC +UUyWRwIbDAAKCRBhCS6FtyJxiexxCADF5DH+HDlppwLr73EptyqS4IblopPXcn59 +bGPyBuWraCivsqZlf05QZTGahUM7jyCUE/FS25sbS5Q4SRtOC2yOnPGsSGcTjmSi +8uZ000stes7ahHku3onxyz2YNVBRchBCENV1tAjQwHrliofdBEY8peAoOz51kmfR +Ivs4+iQ+T3HYtwSYUKPVjizlRCdDR5nsE2KpPUFVx/9L9R3ZeCzCbYHG3Ww1pOFE +5F24PaZ97pgoJDSd1bPH1pyFjvSM3a9v8KxWNib1E+2L5fsLDSFmrbzhMxsu5wTl +u/FlMc4btGCUyysvoigo4OR0uXcejgvnuGhBIH4TTwjJG7w7CY7U +=iYv/ +-----END PGP PUBLIC KEY BLOCK----- diff --git a/t/lib-gpg/ownertrust b/t/lib-gpg/ownertrust new file mode 100644 index 0000000000..b3e3c4f1cd --- /dev/null +++ b/t/lib-gpg/ownertrust @@ -0,0 +1,4 @@ +# List of assigned trustvalues, created Thu 11 Dec 2014 01:26:28 PM CET +# (Use "gpg --import-ownertrust" to restore them) +73D758744BE721698EC54E8713B6F51ECDDE430D:6: +D4BE22311AD3131E5EDA29A461092E85B7227189:3: diff --git a/t/lib-gpg/pubring.gpg b/t/lib-gpg/pubring.gpg Binary files differdeleted file mode 100644 index 1a3c2d487c..0000000000 --- a/t/lib-gpg/pubring.gpg +++ /dev/null diff --git a/t/lib-gpg/random_seed b/t/lib-gpg/random_seed Binary files differdeleted file mode 100644 index 95d249f15f..0000000000 --- a/t/lib-gpg/random_seed +++ /dev/null diff --git a/t/lib-gpg/secring.gpg b/t/lib-gpg/secring.gpg Binary files differdeleted file mode 100644 index 82dca8f80b..0000000000 --- a/t/lib-gpg/secring.gpg +++ /dev/null diff --git a/t/lib-gpg/trustdb.gpg b/t/lib-gpg/trustdb.gpg Binary files differdeleted file mode 100644 index 4879ae9a84..0000000000 --- a/t/lib-gpg/trustdb.gpg +++ /dev/null diff --git a/t/lib-httpd.sh b/t/lib-httpd.sh index 252cbf163b..e9714467d0 100644 --- a/t/lib-httpd.sh +++ b/t/lib-httpd.sh @@ -30,6 +30,18 @@ # Copyright (c) 2008 Clemens Buchacher <drizzd@aon.at> # +if test -n "$NO_CURL" +then + skip_all='skipping test, git built without http support' + test_done +fi + +if test -n "$NO_EXPAT" && test -n "$LIB_HTTPD_DAV" +then + skip_all='skipping test, git built without expat support' + test_done +fi + test_tristate GIT_TEST_HTTPD if test "$GIT_TEST_HTTPD" = false then @@ -37,6 +49,11 @@ then test_done fi +if ! test_have_prereq NOT_ROOT; then + test_skip_or_die $GIT_TEST_HTTPD \ + "Cannot run httpd tests as root" +fi + HTTPD_PARA="" for DEFAULT_HTTPD_PATH in '/usr/sbin/httpd' '/usr/sbin/apache2' @@ -74,6 +91,7 @@ HTTPD_DOCUMENT_ROOT_PATH=$HTTPD_ROOT_PATH/www # hack to suppress apache PassEnv warnings GIT_VALGRIND=$GIT_VALGRIND; export GIT_VALGRIND GIT_VALGRIND_OPTIONS=$GIT_VALGRIND_OPTIONS; export GIT_VALGRIND_OPTIONS +GIT_TRACE=$GIT_TRACE; export GIT_TRACE if ! test -x "$LIB_HTTPD_PATH" then @@ -105,10 +123,15 @@ else "Could not identify web server at '$LIB_HTTPD_PATH'" fi +install_script () { + write_script "$HTTPD_ROOT_PATH/$1" <"$TEST_PATH/$1" +} + prepare_httpd() { mkdir -p "$HTTPD_DOCUMENT_ROOT_PATH" cp "$TEST_PATH"/passwd "$HTTPD_ROOT_PATH" - cp "$TEST_PATH"/broken-smart-http.sh "$HTTPD_ROOT_PATH" + install_script broken-smart-http.sh + install_script error.sh ln -s "$LIB_HTTPD_MODULE_PATH" "$HTTPD_ROOT_PATH/modules" @@ -132,7 +155,7 @@ prepare_httpd() { HTTPD_URL_USER=$HTTPD_PROTO://user%40host@$HTTPD_DEST HTTPD_URL_USER_PASS=$HTTPD_PROTO://user%40host:pass%40host@$HTTPD_DEST - if test -n "$LIB_HTTPD_DAV" -o -n "$LIB_HTTPD_SVN" + if test -n "$LIB_HTTPD_DAV" || test -n "$LIB_HTTPD_SVN" then HTTPD_PARA="$HTTPD_PARA -DDAV" diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf index 3a03e8263d..7d15e6d44c 100644 --- a/t/lib-httpd/apache.conf +++ b/t/lib-httpd/apache.conf @@ -68,6 +68,9 @@ LockFile accept.lock PassEnv GIT_VALGRIND PassEnv GIT_VALGRIND_OPTIONS +PassEnv GNUPGHOME +PassEnv ASAN_OPTIONS +PassEnv GIT_TRACE Alias /dumb/ www/ Alias /auth/dumb/ www/auth/dumb/ @@ -97,12 +100,16 @@ Alias /auth/dumb/ www/auth/dumb/ </LocationMatch> ScriptAliasMatch /smart_*[^/]*/(.*) ${GIT_EXEC_PATH}/git-http-backend/$1 ScriptAlias /broken_smart/ broken-smart-http.sh/ +ScriptAlias /error/ error.sh/ <Directory ${GIT_EXEC_PATH}> Options FollowSymlinks </Directory> <Files broken-smart-http.sh> Options ExecCGI </Files> +<Files error.sh> + Options ExecCGI +</Files> <Files ${GIT_EXEC_PATH}/git-http-backend> Options ExecCGI </Files> @@ -112,6 +119,10 @@ RewriteRule ^/smart-redir-perm/(.*)$ /smart/$1 [R=301] RewriteRule ^/smart-redir-temp/(.*)$ /smart/$1 [R=302] RewriteRule ^/smart-redir-auth/(.*)$ /auth/smart/$1 [R=301] RewriteRule ^/smart-redir-limited/(.*)/info/refs$ /smart/$1/info/refs [R=301] +RewriteRule ^/ftp-redir/(.*)$ ftp://localhost:1000/$1 [R=302] + +RewriteRule ^/loop-redir/x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-(.*) /$1 [R=302] +RewriteRule ^/loop-redir/(.*)$ /loop-redir/x-$1 [R=302] <IfDefine SSL> LoadModule ssl_module modules/mod_ssl.so diff --git a/t/lib-httpd/broken-smart-http.sh b/t/lib-httpd/broken-smart-http.sh index f7ebfffa80..82cc610b0a 100755..100644 --- a/t/lib-httpd/broken-smart-http.sh +++ b/t/lib-httpd/broken-smart-http.sh @@ -1,4 +1,3 @@ -#!/bin/sh printf "Content-Type: text/%s\n" "html" echo printf "%s\n" "001e# service=git-upload-pack" diff --git a/t/lib-httpd/error.sh b/t/lib-httpd/error.sh new file mode 100755 index 0000000000..a77b8e5469 --- /dev/null +++ b/t/lib-httpd/error.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +printf "Status: 500 Intentional Breakage\n" + +printf "Content-Type: " +charset=iso-8859-1 +case "$PATH_INFO" in +*html*) + printf "text/html" + ;; +*text*) + printf "text/plain" + ;; +*charset*) + printf "text/plain; charset=utf-8" + charset=utf-8 + ;; +*utf16*) + printf "text/plain; charset=utf-16" + charset=utf-16 + ;; +*odd-spacing*) + printf "text/plain; foo=bar ;charset=utf-16; other=nonsense" + charset=utf-16 + ;; +esac +printf "\n" + +printf "\n" +printf "this is the error message\n" | +iconv -f us-ascii -t $charset diff --git a/t/lib-proto-disable.sh b/t/lib-proto-disable.sh new file mode 100644 index 0000000000..b0917d93e6 --- /dev/null +++ b/t/lib-proto-disable.sh @@ -0,0 +1,96 @@ +# Test routines for checking protocol disabling. + +# test cloning a particular protocol +# $1 - description of the protocol +# $2 - machine-readable name of the protocol +# $3 - the URL to try cloning +test_proto () { + desc=$1 + proto=$2 + url=$3 + + test_expect_success "clone $1 (enabled)" ' + rm -rf tmp.git && + ( + GIT_ALLOW_PROTOCOL=$proto && + export GIT_ALLOW_PROTOCOL && + git clone --bare "$url" tmp.git + ) + ' + + test_expect_success "fetch $1 (enabled)" ' + ( + cd tmp.git && + GIT_ALLOW_PROTOCOL=$proto && + export GIT_ALLOW_PROTOCOL && + git fetch + ) + ' + + test_expect_success "push $1 (enabled)" ' + ( + cd tmp.git && + GIT_ALLOW_PROTOCOL=$proto && + export GIT_ALLOW_PROTOCOL && + git push origin HEAD:pushed + ) + ' + + test_expect_success "push $1 (disabled)" ' + ( + cd tmp.git && + GIT_ALLOW_PROTOCOL=none && + export GIT_ALLOW_PROTOCOL && + test_must_fail git push origin HEAD:pushed + ) + ' + + test_expect_success "fetch $1 (disabled)" ' + ( + cd tmp.git && + GIT_ALLOW_PROTOCOL=none && + export GIT_ALLOW_PROTOCOL && + test_must_fail git fetch + ) + ' + + test_expect_success "clone $1 (disabled)" ' + rm -rf tmp.git && + ( + GIT_ALLOW_PROTOCOL=none && + export GIT_ALLOW_PROTOCOL && + test_must_fail git clone --bare "$url" tmp.git + ) + ' +} + +# set up an ssh wrapper that will access $host/$repo in the +# trash directory, and enable it for subsequent tests. +setup_ssh_wrapper () { + test_expect_success 'setup ssh wrapper' ' + write_script ssh-wrapper <<-\EOF && + echo >&2 "ssh: $*" + host=$1; shift + cd "$TRASH_DIRECTORY/$host" && + eval "$*" + EOF + GIT_SSH="$PWD/ssh-wrapper" && + export GIT_SSH && + export TRASH_DIRECTORY + ' +} + +# set up a wrapper that can be used with remote-ext to +# access repositories in the "remote" directory of trash-dir, +# like "ext::fake-remote %S repo.git" +setup_ext_wrapper () { + test_expect_success 'setup ext wrapper' ' + write_script fake-remote <<-\EOF && + echo >&2 "fake-remote: $*" + cd "$TRASH_DIRECTORY/remote" && + eval "$*" + EOF + PATH=$TRASH_DIRECTORY:$PATH && + export TRASH_DIRECTORY + ' +} diff --git a/t/lib-rebase.sh b/t/lib-rebase.sh index 6bd252212a..9a96e1566d 100644 --- a/t/lib-rebase.sh +++ b/t/lib-rebase.sh @@ -14,7 +14,7 @@ # specified line. # # "<cmd> <lineno>" -- add a line with the specified command -# ("squash", "fixup", "edit", or "reword") and the SHA1 taken +# ("squash", "fixup", "edit", "reword" or "drop") and the SHA1 taken # from the specified line. # # "exec_cmd_with_args" -- add an "exec cmd with args" line. @@ -46,7 +46,7 @@ set_fake_editor () { action=pick for line in $FAKE_LINES; do case $line in - squash|fixup|edit|reword) + squash|fixup|edit|reword|drop) action="$line";; exec*) echo "$line" | sed 's/_/ /g' >> "$1";; @@ -54,6 +54,11 @@ set_fake_editor () { echo '# comment' >> "$1";; ">") echo >> "$1";; + bad) + action="badcmd";; + fakesha) + echo "$action XXXXXXX False commit" >> "$1" + action=pick;; *) sed -n "${line}s/^pick/$action/p" < "$1".tmp >> "$1" action=pick;; diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh new file mode 100755 index 0000000000..79cdd34a54 --- /dev/null +++ b/t/lib-submodule-update.sh @@ -0,0 +1,680 @@ +# Create a submodule layout used for all tests below. +# +# The following use cases are covered: +# - New submodule (no_submodule => add_sub1) +# - Removed submodule (add_sub1 => remove_sub1) +# - Updated submodule (add_sub1 => modify_sub1) +# - Submodule updated to invalid commit (add_sub1 => invalid_sub1) +# - Submodule updated from invalid commit (invalid_sub1 => valid_sub1) +# - Submodule replaced by tracked files in directory (add_sub1 => +# replace_sub1_with_directory) +# - Directory containing tracked files replaced by submodule +# (replace_sub1_with_directory => replace_directory_with_sub1) +# - Submodule replaced by tracked file with the same name (add_sub1 => +# replace_sub1_with_file) +# - Tracked file replaced by submodule (replace_sub1_with_file => +# replace_file_with_sub1) +# +# --O-----O +# / ^ replace_directory_with_sub1 +# / replace_sub1_with_directory +# /----O +# / ^ +# / modify_sub1 +# O------O-------O +# ^ ^\ ^ +# | | \ remove_sub1 +# | | -----O-----O +# | | \ ^ replace_file_with_sub1 +# | | \ replace_sub1_with_file +# | add_sub1 --O-----O +# no_submodule ^ valid_sub1 +# invalid_sub1 +# +create_lib_submodule_repo () { + git init submodule_update_repo && + ( + cd submodule_update_repo && + echo "expect" >>.gitignore && + echo "actual" >>.gitignore && + echo "x" >file1 && + echo "y" >file2 && + git add .gitignore file1 file2 && + git commit -m "Base" && + git branch "no_submodule" && + + git checkout -b "add_sub1" && + git submodule add ./. sub1 && + git config -f .gitmodules submodule.sub1.ignore all && + git config submodule.sub1.ignore all && + git add .gitmodules && + git commit -m "Add sub1" && + git checkout -b remove_sub1 && + git revert HEAD && + + git checkout -b "modify_sub1" "add_sub1" && + git submodule update && + ( + cd sub1 && + git fetch && + git checkout -b "modifications" && + echo "z" >file2 && + echo "x" >file3 && + git add file2 file3 && + git commit -m "modified file2 and added file3" && + git push origin modifications + ) && + git add sub1 && + git commit -m "Modify sub1" && + + git checkout -b "replace_sub1_with_directory" "add_sub1" && + git submodule update && + ( + cd sub1 && + git checkout modifications + ) && + git rm --cached sub1 && + rm sub1/.git* && + git config -f .gitmodules --remove-section "submodule.sub1" && + git add .gitmodules sub1/* && + git commit -m "Replace sub1 with directory" && + git checkout -b replace_directory_with_sub1 && + git revert HEAD && + + git checkout -b "replace_sub1_with_file" "add_sub1" && + git rm sub1 && + echo "content" >sub1 && + git add sub1 && + git commit -m "Replace sub1 with file" && + git checkout -b replace_file_with_sub1 && + git revert HEAD && + + git checkout -b "invalid_sub1" "add_sub1" && + git update-index --cacheinfo 160000 0123456789012345678901234567890123456789 sub1 && + git commit -m "Invalid sub1 commit" && + git checkout -b valid_sub1 && + git revert HEAD && + git checkout master + ) +} + +# Helper function to replace gitfile with .git directory +replace_gitfile_with_git_dir () { + ( + cd "$1" && + git_dir="$(git rev-parse --git-dir)" && + rm -f .git && + cp -R "$git_dir" .git && + GIT_WORK_TREE=. git config --unset core.worktree + ) +} + +# Test that the .git directory in the submodule is unchanged (except for the +# core.worktree setting, which appears only in $GIT_DIR/modules/$1/config). +# Call this function before test_submodule_content as the latter might +# write the index file leading to false positive index differences. +# +# Note that this only supports submodules at the root level of the +# superproject, with the default name, i.e. same as its path. +test_git_directory_is_unchanged () { + ( + cd ".git/modules/$1" && + # does core.worktree point at the right place? + test "$(git config core.worktree)" = "../../../$1" && + # remove it temporarily before comparing, as + # "$1/.git/config" lacks it... + git config --unset core.worktree + ) && + diff -r ".git/modules/$1" "$1/.git" && + ( + # ... and then restore. + cd ".git/modules/$1" && + git config core.worktree "../../../$1" + ) +} + +# Helper function to be executed at the start of every test below, it sets up +# the submodule repo if it doesn't exist and configures the most problematic +# settings for diff.ignoreSubmodules. +prolog () { + (test -d submodule_update_repo || create_lib_submodule_repo) && + test_config_global diff.ignoreSubmodules all && + test_config diff.ignoreSubmodules all +} + +# Helper function to bring work tree back into the state given by the +# commit. This includes trying to populate sub1 accordingly if it exists and +# should be updated to an existing commit. +reset_work_tree_to () { + rm -rf submodule_update && + git clone submodule_update_repo submodule_update && + ( + cd submodule_update && + rm -rf sub1 && + git checkout -f "$1" && + git status -u -s >actual && + test_must_be_empty actual && + sha1=$(git rev-parse --revs-only HEAD:sub1) && + if test -n "$sha1" && + test $(cd "sub1" && git rev-parse --verify "$sha1^{commit}") + then + git submodule update --init --recursive "sub1" + fi + ) +} + +# Test that the superproject contains the content according to commit "$1" +# (the work tree must match the index for everything but submodules but the +# index must exactly match the given commit including any submodule SHA-1s). +test_superproject_content () { + git diff-index --cached "$1" >actual && + test_must_be_empty actual && + git diff-files --ignore-submodules >actual && + test_must_be_empty actual +} + +# Test that the given submodule at path "$1" contains the content according +# to the submodule commit recorded in the superproject's commit "$2" +test_submodule_content () { + if test $# != 2 + then + echo "test_submodule_content needs two arguments" + return 1 + fi && + submodule="$1" && + commit="$2" && + test -d "$submodule"/ && + if ! test -f "$submodule"/.git && ! test -d "$submodule"/.git + then + echo "Submodule $submodule is not populated" + return 1 + fi && + sha1=$(git rev-parse --verify "$commit:$submodule") && + if test -z "$sha1" + then + echo "Couldn't retrieve SHA-1 of $submodule for $commit" + return 1 + fi && + ( + cd "$submodule" && + git status -u -s >actual && + test_must_be_empty actual && + git diff "$sha1" >actual && + test_must_be_empty actual + ) +} + +# Test that the following transitions are correctly handled: +# - Updated submodule +# - New submodule +# - Removed submodule +# - Directory containing tracked files replaced by submodule +# - Submodule replaced by tracked files in directory +# - Submodule replaced by tracked file with the same name +# - tracked file replaced by submodule +# +# The default is that submodule contents aren't changed until "git submodule +# update" is run. And even then that command doesn't delete the work tree of +# a removed submodule. +# +# Removing a submodule containing a .git directory must fail even when forced +# to protect the history! +# + +# Test that submodule contents are currently not updated when switching +# between commits that change a submodule. +test_submodule_switch () { + command="$1" + ######################### Appearing submodule ######################### + # Switching to a commit letting a submodule appear creates empty dir ... + if test "$KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES" = 1 + then + # Restoring stash fails to restore submodule index entry + RESULT="failure" + else + RESULT="success" + fi + test_expect_$RESULT "$command: added submodule creates empty directory" ' + prolog && + reset_work_tree_to no_submodule && + ( + cd submodule_update && + git branch -t add_sub1 origin/add_sub1 && + $command add_sub1 && + test_superproject_content origin/add_sub1 && + test_dir_is_empty sub1 && + git submodule update --init --recursive && + test_submodule_content sub1 origin/add_sub1 + ) + ' + # ... and doesn't care if it already exists ... + test_expect_$RESULT "$command: added submodule leaves existing empty directory alone" ' + prolog && + reset_work_tree_to no_submodule && + ( + cd submodule_update && + mkdir sub1 && + git branch -t add_sub1 origin/add_sub1 && + $command add_sub1 && + test_superproject_content origin/add_sub1 && + test_dir_is_empty sub1 && + git submodule update --init --recursive && + test_submodule_content sub1 origin/add_sub1 + ) + ' + # ... unless there is an untracked file in its place. + test_expect_success "$command: added submodule doesn't remove untracked unignored file with same name" ' + prolog && + reset_work_tree_to no_submodule && + ( + cd submodule_update && + git branch -t add_sub1 origin/add_sub1 && + >sub1 && + test_must_fail $command add_sub1 && + test_superproject_content origin/no_submodule && + test_must_be_empty sub1 + ) + ' + # Replacing a tracked file with a submodule produces an empty + # directory ... + test_expect_$RESULT "$command: replace tracked file with submodule creates empty directory" ' + prolog && + reset_work_tree_to replace_sub1_with_file && + ( + cd submodule_update && + git branch -t replace_file_with_sub1 origin/replace_file_with_sub1 && + $command replace_file_with_sub1 && + test_superproject_content origin/replace_file_with_sub1 && + test_dir_is_empty sub1 && + git submodule update --init --recursive && + test_submodule_content sub1 origin/replace_file_with_sub1 + ) + ' + # ... as does removing a directory with tracked files with a + # submodule. + if test "$KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR" = 1 + then + # Non fast-forward merges fail with "Directory sub1 doesn't + # exist. sub1" because the empty submodule directory is not + # created + RESULT="failure" + else + RESULT="success" + fi + test_expect_$RESULT "$command: replace directory with submodule" ' + prolog && + reset_work_tree_to replace_sub1_with_directory && + ( + cd submodule_update && + git branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 && + $command replace_directory_with_sub1 && + test_superproject_content origin/replace_directory_with_sub1 && + test_dir_is_empty sub1 && + git submodule update --init --recursive && + test_submodule_content sub1 origin/replace_directory_with_sub1 + ) + ' + + ######################## Disappearing submodule ####################### + # Removing a submodule doesn't remove its work tree ... + if test "$KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES" = 1 + then + RESULT="failure" + else + RESULT="success" + fi + test_expect_$RESULT "$command: removed submodule leaves submodule directory and its contents in place" ' + prolog && + reset_work_tree_to add_sub1 && + ( + cd submodule_update && + git branch -t remove_sub1 origin/remove_sub1 && + $command remove_sub1 && + test_superproject_content origin/remove_sub1 && + test_submodule_content sub1 origin/add_sub1 + ) + ' + # ... especially when it contains a .git directory. + test_expect_$RESULT "$command: removed submodule leaves submodule containing a .git directory alone" ' + prolog && + reset_work_tree_to add_sub1 && + ( + cd submodule_update && + git branch -t remove_sub1 origin/remove_sub1 && + replace_gitfile_with_git_dir sub1 && + $command remove_sub1 && + test_superproject_content origin/remove_sub1 && + test_git_directory_is_unchanged sub1 && + test_submodule_content sub1 origin/add_sub1 + ) + ' + # Replacing a submodule with files in a directory must fail as the + # submodule work tree isn't removed ... + if test "$KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES" = 1 + then + # Non fast-forward merges attempt to merge the former + # submodule files with the newly checked out ones in the + # directory of the same name while it shouldn't. + RESULT="failure" + else + RESULT="success" + fi + test_expect_$RESULT "$command: replace submodule with a directory must fail" ' + prolog && + reset_work_tree_to add_sub1 && + ( + cd submodule_update && + git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory && + test_must_fail $command replace_sub1_with_directory && + test_superproject_content origin/add_sub1 && + test_submodule_content sub1 origin/add_sub1 + ) + ' + # ... especially when it contains a .git directory. + test_expect_$RESULT "$command: replace submodule containing a .git directory with a directory must fail" ' + prolog && + reset_work_tree_to add_sub1 && + ( + cd submodule_update && + git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory && + replace_gitfile_with_git_dir sub1 && + test_must_fail $command replace_sub1_with_directory && + test_superproject_content origin/add_sub1 && + test_git_directory_is_unchanged sub1 && + test_submodule_content sub1 origin/add_sub1 + ) + ' + # Replacing it with a file must fail as it could throw away any local + # work tree changes ... + test_expect_failure "$command: replace submodule with a file must fail" ' + prolog && + reset_work_tree_to add_sub1 && + ( + cd submodule_update && + git branch -t replace_sub1_with_file origin/replace_sub1_with_file && + test_must_fail $command replace_sub1_with_file && + test_superproject_content origin/add_sub1 && + test_submodule_content sub1 origin/add_sub1 + ) + ' + # ... or even destroy unpushed parts of submodule history if that + # still uses a .git directory. + test_expect_failure "$command: replace submodule containing a .git directory with a file must fail" ' + prolog && + reset_work_tree_to add_sub1 && + ( + cd submodule_update && + git branch -t replace_sub1_with_file origin/replace_sub1_with_file && + replace_gitfile_with_git_dir sub1 && + test_must_fail $command replace_sub1_with_file && + test_superproject_content origin/add_sub1 && + test_git_directory_is_unchanged sub1 && + test_submodule_content sub1 origin/add_sub1 + ) + ' + + ########################## Modified submodule ######################### + # Updating a submodule sha1 doesn't update the submodule's work tree + if test "$KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT" = 1 + then + # When cherry picking a SHA-1 update for an ignored submodule + # the commit incorrectly fails with "The previous cherry-pick + # is now empty, possibly due to conflict resolution." + RESULT="failure" + else + RESULT="success" + fi + test_expect_$RESULT "$command: modified submodule does not update submodule work tree" ' + prolog && + reset_work_tree_to add_sub1 && + ( + cd submodule_update && + git branch -t modify_sub1 origin/modify_sub1 && + $command modify_sub1 && + test_superproject_content origin/modify_sub1 && + test_submodule_content sub1 origin/add_sub1 && + git submodule update && + test_submodule_content sub1 origin/modify_sub1 + ) + ' + + # Updating a submodule to an invalid sha1 doesn't update the + # submodule's work tree, subsequent update will fail + test_expect_$RESULT "$command: modified submodule does not update submodule work tree to invalid commit" ' + prolog && + reset_work_tree_to add_sub1 && + ( + cd submodule_update && + git branch -t invalid_sub1 origin/invalid_sub1 && + $command invalid_sub1 && + test_superproject_content origin/invalid_sub1 && + test_submodule_content sub1 origin/add_sub1 && + test_must_fail git submodule update && + test_submodule_content sub1 origin/add_sub1 + ) + ' + # Updating a submodule from an invalid sha1 doesn't update the + # submodule's work tree, subsequent update will succeed + test_expect_$RESULT "$command: modified submodule does not update submodule work tree from invalid commit" ' + prolog && + reset_work_tree_to invalid_sub1 && + ( + cd submodule_update && + git branch -t valid_sub1 origin/valid_sub1 && + $command valid_sub1 && + test_superproject_content origin/valid_sub1 && + test_dir_is_empty sub1 && + git submodule update --init --recursive && + test_submodule_content sub1 origin/valid_sub1 + ) + ' +} + +# Test that submodule contents are currently not updated when switching +# between commits that change a submodule, but throwing away local changes in +# the superproject is allowed. +test_submodule_forced_switch () { + command="$1" + ######################### Appearing submodule ######################### + # Switching to a commit letting a submodule appear creates empty dir ... + test_expect_success "$command: added submodule creates empty directory" ' + prolog && + reset_work_tree_to no_submodule && + ( + cd submodule_update && + git branch -t add_sub1 origin/add_sub1 && + $command add_sub1 && + test_superproject_content origin/add_sub1 && + test_dir_is_empty sub1 && + git submodule update --init --recursive && + test_submodule_content sub1 origin/add_sub1 + ) + ' + # ... and doesn't care if it already exists ... + test_expect_success "$command: added submodule leaves existing empty directory alone" ' + prolog && + reset_work_tree_to no_submodule && + ( + cd submodule_update && + git branch -t add_sub1 origin/add_sub1 && + mkdir sub1 && + $command add_sub1 && + test_superproject_content origin/add_sub1 && + test_dir_is_empty sub1 && + git submodule update --init --recursive && + test_submodule_content sub1 origin/add_sub1 + ) + ' + # ... unless there is an untracked file in its place. + test_expect_success "$command: added submodule does remove untracked unignored file with same name when forced" ' + prolog && + reset_work_tree_to no_submodule && + ( + cd submodule_update && + git branch -t add_sub1 origin/add_sub1 && + >sub1 && + $command add_sub1 && + test_superproject_content origin/add_sub1 && + test_dir_is_empty sub1 + ) + ' + # Replacing a tracked file with a submodule produces an empty + # directory ... + test_expect_success "$command: replace tracked file with submodule creates empty directory" ' + prolog && + reset_work_tree_to replace_sub1_with_file && + ( + cd submodule_update && + git branch -t replace_file_with_sub1 origin/replace_file_with_sub1 && + $command replace_file_with_sub1 && + test_superproject_content origin/replace_file_with_sub1 && + test_dir_is_empty sub1 && + git submodule update --init --recursive && + test_submodule_content sub1 origin/replace_file_with_sub1 + ) + ' + # ... as does removing a directory with tracked files with a + # submodule. + test_expect_success "$command: replace directory with submodule" ' + prolog && + reset_work_tree_to replace_sub1_with_directory && + ( + cd submodule_update && + git branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 && + $command replace_directory_with_sub1 && + test_superproject_content origin/replace_directory_with_sub1 && + test_dir_is_empty sub1 && + git submodule update --init --recursive && + test_submodule_content sub1 origin/replace_directory_with_sub1 + ) + ' + + ######################## Disappearing submodule ####################### + # Removing a submodule doesn't remove its work tree ... + test_expect_success "$command: removed submodule leaves submodule directory and its contents in place" ' + prolog && + reset_work_tree_to add_sub1 && + ( + cd submodule_update && + git branch -t remove_sub1 origin/remove_sub1 && + $command remove_sub1 && + test_superproject_content origin/remove_sub1 && + test_submodule_content sub1 origin/add_sub1 + ) + ' + # ... especially when it contains a .git directory. + test_expect_success "$command: removed submodule leaves submodule containing a .git directory alone" ' + prolog && + reset_work_tree_to add_sub1 && + ( + cd submodule_update && + git branch -t remove_sub1 origin/remove_sub1 && + replace_gitfile_with_git_dir sub1 && + $command remove_sub1 && + test_superproject_content origin/remove_sub1 && + test_git_directory_is_unchanged sub1 && + test_submodule_content sub1 origin/add_sub1 + ) + ' + # Replacing a submodule with files in a directory must fail as the + # submodule work tree isn't removed ... + test_expect_failure "$command: replace submodule with a directory must fail" ' + prolog && + reset_work_tree_to add_sub1 && + ( + cd submodule_update && + git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory && + test_must_fail $command replace_sub1_with_directory && + test_superproject_content origin/add_sub1 && + test_submodule_content sub1 origin/add_sub1 + ) + ' + # ... especially when it contains a .git directory. + test_expect_failure "$command: replace submodule containing a .git directory with a directory must fail" ' + prolog && + reset_work_tree_to add_sub1 && + ( + cd submodule_update && + git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory && + replace_gitfile_with_git_dir sub1 && + test_must_fail $command replace_sub1_with_directory && + test_superproject_content origin/add_sub1 && + test_git_directory_is_unchanged sub1 && + test_submodule_content sub1 origin/add_sub1 + ) + ' + # Replacing it with a file must fail as it could throw away any local + # work tree changes ... + test_expect_failure "$command: replace submodule with a file must fail" ' + prolog && + reset_work_tree_to add_sub1 && + ( + cd submodule_update && + git branch -t replace_sub1_with_file origin/replace_sub1_with_file && + test_must_fail $command replace_sub1_with_file && + test_superproject_content origin/add_sub1 && + test_submodule_content sub1 origin/add_sub1 + ) + ' + # ... or even destroy unpushed parts of submodule history if that + # still uses a .git directory. + test_expect_failure "$command: replace submodule containing a .git directory with a file must fail" ' + prolog && + reset_work_tree_to add_sub1 && + ( + cd submodule_update && + git branch -t replace_sub1_with_file origin/replace_sub1_with_file && + replace_gitfile_with_git_dir sub1 && + test_must_fail $command replace_sub1_with_file && + test_superproject_content origin/add_sub1 && + test_git_directory_is_unchanged sub1 && + test_submodule_content sub1 origin/add_sub1 + ) + ' + + ########################## Modified submodule ######################### + # Updating a submodule sha1 doesn't update the submodule's work tree + test_expect_success "$command: modified submodule does not update submodule work tree" ' + prolog && + reset_work_tree_to add_sub1 && + ( + cd submodule_update && + git branch -t modify_sub1 origin/modify_sub1 && + $command modify_sub1 && + test_superproject_content origin/modify_sub1 && + test_submodule_content sub1 origin/add_sub1 && + git submodule update && + test_submodule_content sub1 origin/modify_sub1 + ) + ' + # Updating a submodule to an invalid sha1 doesn't update the + # submodule's work tree, subsequent update will fail + test_expect_success "$command: modified submodule does not update submodule work tree to invalid commit" ' + prolog && + reset_work_tree_to add_sub1 && + ( + cd submodule_update && + git branch -t invalid_sub1 origin/invalid_sub1 && + $command invalid_sub1 && + test_superproject_content origin/invalid_sub1 && + test_submodule_content sub1 origin/add_sub1 && + test_must_fail git submodule update && + test_submodule_content sub1 origin/add_sub1 + ) + ' + # Updating a submodule from an invalid sha1 doesn't update the + # submodule's work tree, subsequent update will succeed + test_expect_success "$command: modified submodule does not update submodule work tree from invalid commit" ' + prolog && + reset_work_tree_to invalid_sub1 && + ( + cd submodule_update && + git branch -t valid_sub1 origin/valid_sub1 && + $command valid_sub1 && + test_superproject_content origin/valid_sub1 && + test_dir_is_empty sub1 && + git submodule update --init --recursive && + test_submodule_content sub1 origin/valid_sub1 + ) + ' +} diff --git a/t/lib-terminal.sh b/t/lib-terminal.sh index 51845491bb..cd220e378e 100644 --- a/t/lib-terminal.sh +++ b/t/lib-terminal.sh @@ -1,7 +1,7 @@ # Helpers for terminal output tests. # Catch tests which should depend on TTY but forgot to. There's no need -# to aditionally check that the TTY prereq is set here. If the test declared +# to additionally check that the TTY prereq is set here. If the test declared # it and we are running the test, then it must have been set. test_terminal () { if ! test_declared_prereq TTY diff --git a/t/perf/aggregate.perl b/t/perf/aggregate.perl index 15f7fc1b80..924b19dab4 100755 --- a/t/perf/aggregate.perl +++ b/t/perf/aggregate.perl @@ -1,5 +1,6 @@ #!/usr/bin/perl +use lib '../../perl/blib/lib'; use strict; use warnings; use Git; diff --git a/t/perf/p5302-pack-index.sh b/t/perf/p5302-pack-index.sh index 6cb5b0d55b..5ee9211f98 100755 --- a/t/perf/p5302-pack-index.sh +++ b/t/perf/p5302-pack-index.sh @@ -8,7 +8,7 @@ test_perf_large_repo test_expect_success 'repack' ' git repack -ad && - PACK=`ls .git/objects/pack/*.pack | head -n1` && + PACK=$(ls .git/objects/pack/*.pack | head -n1) && test -f "$PACK" && export PACK ' diff --git a/t/perf/p5310-pack-bitmaps.sh b/t/perf/p5310-pack-bitmaps.sh index 685d46f8b7..de2a224a36 100755 --- a/t/perf/p5310-pack-bitmaps.sh +++ b/t/perf/p5310-pack-bitmaps.sh @@ -8,6 +8,9 @@ test_perf_large_repo # note that we do everything through config, # since we want to be able to compare bitmap-aware # git versus non-bitmap git +# +# We intentionally use the deprecated pack.writebitmaps +# config so that we can test against older versions of git. test_expect_success 'setup bitmap config' ' git config pack.writebitmaps true && git config pack.writebitmaphashcache true @@ -36,14 +39,14 @@ test_expect_success 'create partial bitmap state' ' # now kill off all of the refs and pretend we had # just the one tip - rm -rf .git/logs .git/refs/* .git/packed-refs - git update-ref HEAD $cutoff + rm -rf .git/logs .git/refs/* .git/packed-refs && + git update-ref HEAD $cutoff && # and then repack, which will leave us with a nice # big bitmap pack of the "old" history, and all of # the new history will be loose, as if it had been pushed # up incrementally and exploded via unpack-objects - git repack -Ad + git repack -Ad && # and now restore our original tip, as if the pushes # had happened diff --git a/t/perf/p7000-filter-branch.sh b/t/perf/p7000-filter-branch.sh new file mode 100755 index 0000000000..15ee5d1d53 --- /dev/null +++ b/t/perf/p7000-filter-branch.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +test_description='performance of filter-branch' +. ./perf-lib.sh + +test_perf_default_repo +test_checkout_worktree + +test_expect_success 'mark bases for tests' ' + git tag -f tip && + git tag -f base HEAD~100 +' + +test_perf 'noop filter' ' + git checkout --detach tip && + git filter-branch -f base..HEAD +' + +test_done diff --git a/t/perf/p7300-clean.sh b/t/perf/p7300-clean.sh new file mode 100755 index 0000000000..7c1888a27e --- /dev/null +++ b/t/perf/p7300-clean.sh @@ -0,0 +1,35 @@ +#!/bin/sh + +test_description="Test git-clean performance" + +. ./perf-lib.sh + +test_perf_default_repo +test_checkout_worktree + +test_expect_success 'setup untracked directory with many sub dirs' ' + rm -rf 500_sub_dirs 100000_sub_dirs clean_test_dir && + mkdir 500_sub_dirs 100000_sub_dirs clean_test_dir && + for i in $(test_seq 1 500) + do + mkdir 500_sub_dirs/dir$i || return $? + done && + for i in $(test_seq 1 200) + do + cp -r 500_sub_dirs 100000_sub_dirs/dir$i || return $? + done +' + +test_perf 'clean many untracked sub dirs, check for nested git' ' + git clean -n -q -f -d 100000_sub_dirs/ +' + +test_perf 'clean many untracked sub dirs, ignore nested git' ' + git clean -n -q -f -f -d 100000_sub_dirs/ +' + +test_perf 'ls-files -o' ' + git ls-files -o +' + +test_done diff --git a/t/perf/perf-lib.sh b/t/perf/perf-lib.sh index a8c9574291..5cf74eddec 100644 --- a/t/perf/perf-lib.sh +++ b/t/perf/perf-lib.sh @@ -91,7 +91,7 @@ test_perf_create_repo_from () { */objects|*/hooks|*/config) ;; *) - cp -R "$stuff" . || break + cp -R "$stuff" . || exit 1 ;; esac done && diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh index a2bb63ce8e..79b9074172 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -42,9 +42,9 @@ test_expect_success 'success is reported like this' ' : ' -run_sub_test_lib_test () { - name="$1" descr="$2" # stdin is the body of the test code - shift 2 +_run_sub_test_lib_test_common () { + neg="$1" name="$2" descr="$3" # stdin is the body of the test code + shift 3 mkdir "$name" && ( # Pretend we're not running under a test harness, whether we @@ -70,10 +70,23 @@ run_sub_test_lib_test () { export TEST_DIRECTORY && TEST_OUTPUT_DIRECTORY=$(pwd) && export TEST_OUTPUT_DIRECTORY && - ./"$name.sh" "$@" >out 2>err + if test -z "$neg" + then + ./"$name.sh" "$@" >out 2>err + else + ! ./"$name.sh" "$@" >out 2>err + fi ) } +run_sub_test_lib_test () { + _run_sub_test_lib_test_common '' "$@" +} + +run_sub_test_lib_test_err () { + _run_sub_test_lib_test_common '!' "$@" +} + check_sub_test_lib_test () { name="$1" # stdin is the expected output from the test ( @@ -84,6 +97,18 @@ check_sub_test_lib_test () { ) } +check_sub_test_lib_test_err () { + name="$1" # stdin is the expected output output from the test + # expected error output is in descriptior 3 + ( + cd "$name" && + sed -e 's/^> //' -e 's/Z$//' >expect.out && + test_cmp expect.out out && + sed -e 's/^> //' -e 's/Z$//' <&3 >expect.err && + test_cmp expect.err err + ) +} + test_expect_success 'pretend we have a fully passing test suite' " run_sub_test_lib_test full-pass '3 passing tests' <<-\\EOF && for i in 1 2 3 @@ -228,7 +253,7 @@ test_expect_success 'test --verbose' ' test_expect_success "failing test" false test_done EOF - mv test-verbose/out test-verbose/out+ + mv test-verbose/out test-verbose/out+ && grep -v "^Initialized empty" test-verbose/out+ >test-verbose/out && check_sub_test_lib_test test-verbose <<-\EOF > expecting success: true @@ -270,6 +295,398 @@ test_expect_success 'test --verbose-only' ' EOF ' +test_expect_success 'GIT_SKIP_TESTS' " + ( + GIT_SKIP_TESTS='git.2' && export GIT_SKIP_TESTS && + run_sub_test_lib_test git-skip-tests-basic \ + 'GIT_SKIP_TESTS' <<-\\EOF && + for i in 1 2 3 + do + test_expect_success \"passing test #\$i\" 'true' + done + test_done + EOF + check_sub_test_lib_test git-skip-tests-basic <<-\\EOF + > ok 1 - passing test #1 + > ok 2 # skip passing test #2 (GIT_SKIP_TESTS) + > ok 3 - passing test #3 + > # passed all 3 test(s) + > 1..3 + EOF + ) +" + +test_expect_success 'GIT_SKIP_TESTS several tests' " + ( + GIT_SKIP_TESTS='git.2 git.5' && export GIT_SKIP_TESTS && + run_sub_test_lib_test git-skip-tests-several \ + 'GIT_SKIP_TESTS several tests' <<-\\EOF && + for i in 1 2 3 4 5 6 + do + test_expect_success \"passing test #\$i\" 'true' + done + test_done + EOF + check_sub_test_lib_test git-skip-tests-several <<-\\EOF + > ok 1 - passing test #1 + > ok 2 # skip passing test #2 (GIT_SKIP_TESTS) + > ok 3 - passing test #3 + > ok 4 - passing test #4 + > ok 5 # skip passing test #5 (GIT_SKIP_TESTS) + > ok 6 - passing test #6 + > # passed all 6 test(s) + > 1..6 + EOF + ) +" + +test_expect_success 'GIT_SKIP_TESTS sh pattern' " + ( + GIT_SKIP_TESTS='git.[2-5]' && export GIT_SKIP_TESTS && + run_sub_test_lib_test git-skip-tests-sh-pattern \ + 'GIT_SKIP_TESTS sh pattern' <<-\\EOF && + for i in 1 2 3 4 5 6 + do + test_expect_success \"passing test #\$i\" 'true' + done + test_done + EOF + check_sub_test_lib_test git-skip-tests-sh-pattern <<-\\EOF + > ok 1 - passing test #1 + > ok 2 # skip passing test #2 (GIT_SKIP_TESTS) + > ok 3 # skip passing test #3 (GIT_SKIP_TESTS) + > ok 4 # skip passing test #4 (GIT_SKIP_TESTS) + > ok 5 # skip passing test #5 (GIT_SKIP_TESTS) + > ok 6 - passing test #6 + > # passed all 6 test(s) + > 1..6 + EOF + ) +" + +test_expect_success '--run basic' " + run_sub_test_lib_test run-basic \ + '--run basic' --run='1 3 5' <<-\\EOF && + for i in 1 2 3 4 5 6 + do + test_expect_success \"passing test #\$i\" 'true' + done + test_done + EOF + check_sub_test_lib_test run-basic <<-\\EOF + > ok 1 - passing test #1 + > ok 2 # skip passing test #2 (--run) + > ok 3 - passing test #3 + > ok 4 # skip passing test #4 (--run) + > ok 5 - passing test #5 + > ok 6 # skip passing test #6 (--run) + > # passed all 6 test(s) + > 1..6 + EOF +" + +test_expect_success '--run with a range' " + run_sub_test_lib_test run-range \ + '--run with a range' --run='1-3' <<-\\EOF && + for i in 1 2 3 4 5 6 + do + test_expect_success \"passing test #\$i\" 'true' + done + test_done + EOF + check_sub_test_lib_test run-range <<-\\EOF + > ok 1 - passing test #1 + > ok 2 - passing test #2 + > ok 3 - passing test #3 + > ok 4 # skip passing test #4 (--run) + > ok 5 # skip passing test #5 (--run) + > ok 6 # skip passing test #6 (--run) + > # passed all 6 test(s) + > 1..6 + EOF +" + +test_expect_success '--run with two ranges' " + run_sub_test_lib_test run-two-ranges \ + '--run with two ranges' --run='1-2 5-6' <<-\\EOF && + for i in 1 2 3 4 5 6 + do + test_expect_success \"passing test #\$i\" 'true' + done + test_done + EOF + check_sub_test_lib_test run-two-ranges <<-\\EOF + > ok 1 - passing test #1 + > ok 2 - passing test #2 + > ok 3 # skip passing test #3 (--run) + > ok 4 # skip passing test #4 (--run) + > ok 5 - passing test #5 + > ok 6 - passing test #6 + > # passed all 6 test(s) + > 1..6 + EOF +" + +test_expect_success '--run with a left open range' " + run_sub_test_lib_test run-left-open-range \ + '--run with a left open range' --run='-3' <<-\\EOF && + for i in 1 2 3 4 5 6 + do + test_expect_success \"passing test #\$i\" 'true' + done + test_done + EOF + check_sub_test_lib_test run-left-open-range <<-\\EOF + > ok 1 - passing test #1 + > ok 2 - passing test #2 + > ok 3 - passing test #3 + > ok 4 # skip passing test #4 (--run) + > ok 5 # skip passing test #5 (--run) + > ok 6 # skip passing test #6 (--run) + > # passed all 6 test(s) + > 1..6 + EOF +" + +test_expect_success '--run with a right open range' " + run_sub_test_lib_test run-right-open-range \ + '--run with a right open range' --run='4-' <<-\\EOF && + for i in 1 2 3 4 5 6 + do + test_expect_success \"passing test #\$i\" 'true' + done + test_done + EOF + check_sub_test_lib_test run-right-open-range <<-\\EOF + > ok 1 # skip passing test #1 (--run) + > ok 2 # skip passing test #2 (--run) + > ok 3 # skip passing test #3 (--run) + > ok 4 - passing test #4 + > ok 5 - passing test #5 + > ok 6 - passing test #6 + > # passed all 6 test(s) + > 1..6 + EOF +" + +test_expect_success '--run with basic negation' " + run_sub_test_lib_test run-basic-neg \ + '--run with basic negation' --run='"'!3'"' <<-\\EOF && + for i in 1 2 3 4 5 6 + do + test_expect_success \"passing test #\$i\" 'true' + done + test_done + EOF + check_sub_test_lib_test run-basic-neg <<-\\EOF + > ok 1 - passing test #1 + > ok 2 - passing test #2 + > ok 3 # skip passing test #3 (--run) + > ok 4 - passing test #4 + > ok 5 - passing test #5 + > ok 6 - passing test #6 + > # passed all 6 test(s) + > 1..6 + EOF +" + +test_expect_success '--run with two negations' " + run_sub_test_lib_test run-two-neg \ + '--run with two negations' --run='"'!3 !6'"' <<-\\EOF && + for i in 1 2 3 4 5 6 + do + test_expect_success \"passing test #\$i\" 'true' + done + test_done + EOF + check_sub_test_lib_test run-two-neg <<-\\EOF + > ok 1 - passing test #1 + > ok 2 - passing test #2 + > ok 3 # skip passing test #3 (--run) + > ok 4 - passing test #4 + > ok 5 - passing test #5 + > ok 6 # skip passing test #6 (--run) + > # passed all 6 test(s) + > 1..6 + EOF +" + +test_expect_success '--run a range and negation' " + run_sub_test_lib_test run-range-and-neg \ + '--run a range and negation' --run='"'-4 !2'"' <<-\\EOF && + for i in 1 2 3 4 5 6 + do + test_expect_success \"passing test #\$i\" 'true' + done + test_done + EOF + check_sub_test_lib_test run-range-and-neg <<-\\EOF + > ok 1 - passing test #1 + > ok 2 # skip passing test #2 (--run) + > ok 3 - passing test #3 + > ok 4 - passing test #4 + > ok 5 # skip passing test #5 (--run) + > ok 6 # skip passing test #6 (--run) + > # passed all 6 test(s) + > 1..6 + EOF +" + +test_expect_success '--run range negation' " + run_sub_test_lib_test run-range-neg \ + '--run range negation' --run='"'!1-3'"' <<-\\EOF && + for i in 1 2 3 4 5 6 + do + test_expect_success \"passing test #\$i\" 'true' + done + test_done + EOF + check_sub_test_lib_test run-range-neg <<-\\EOF + > ok 1 # skip passing test #1 (--run) + > ok 2 # skip passing test #2 (--run) + > ok 3 # skip passing test #3 (--run) + > ok 4 - passing test #4 + > ok 5 - passing test #5 + > ok 6 - passing test #6 + > # passed all 6 test(s) + > 1..6 + EOF +" + +test_expect_success '--run include, exclude and include' " + run_sub_test_lib_test run-inc-neg-inc \ + '--run include, exclude and include' \ + --run='"'1-5 !1-3 2'"' <<-\\EOF && + for i in 1 2 3 4 5 6 + do + test_expect_success \"passing test #\$i\" 'true' + done + test_done + EOF + check_sub_test_lib_test run-inc-neg-inc <<-\\EOF + > ok 1 # skip passing test #1 (--run) + > ok 2 - passing test #2 + > ok 3 # skip passing test #3 (--run) + > ok 4 - passing test #4 + > ok 5 - passing test #5 + > ok 6 # skip passing test #6 (--run) + > # passed all 6 test(s) + > 1..6 + EOF +" + +test_expect_success '--run include, exclude and include, comma separated' " + run_sub_test_lib_test run-inc-neg-inc-comma \ + '--run include, exclude and include, comma separated' \ + --run=1-5,\!1-3,2 <<-\\EOF && + for i in 1 2 3 4 5 6 + do + test_expect_success \"passing test #\$i\" 'true' + done + test_done + EOF + check_sub_test_lib_test run-inc-neg-inc-comma <<-\\EOF + > ok 1 # skip passing test #1 (--run) + > ok 2 - passing test #2 + > ok 3 # skip passing test #3 (--run) + > ok 4 - passing test #4 + > ok 5 - passing test #5 + > ok 6 # skip passing test #6 (--run) + > # passed all 6 test(s) + > 1..6 + EOF +" + +test_expect_success '--run exclude and include' " + run_sub_test_lib_test run-neg-inc \ + '--run exclude and include' \ + --run='"'!3- 5'"' <<-\\EOF && + for i in 1 2 3 4 5 6 + do + test_expect_success \"passing test #\$i\" 'true' + done + test_done + EOF + check_sub_test_lib_test run-neg-inc <<-\\EOF + > ok 1 - passing test #1 + > ok 2 - passing test #2 + > ok 3 # skip passing test #3 (--run) + > ok 4 # skip passing test #4 (--run) + > ok 5 - passing test #5 + > ok 6 # skip passing test #6 (--run) + > # passed all 6 test(s) + > 1..6 + EOF +" + +test_expect_success '--run empty selectors' " + run_sub_test_lib_test run-empty-sel \ + '--run empty selectors' \ + --run='1,,3,,,5' <<-\\EOF && + for i in 1 2 3 4 5 6 + do + test_expect_success \"passing test #\$i\" 'true' + done + test_done + EOF + check_sub_test_lib_test run-empty-sel <<-\\EOF + > ok 1 - passing test #1 + > ok 2 # skip passing test #2 (--run) + > ok 3 - passing test #3 + > ok 4 # skip passing test #4 (--run) + > ok 5 - passing test #5 + > ok 6 # skip passing test #6 (--run) + > # passed all 6 test(s) + > 1..6 + EOF +" + +test_expect_success '--run invalid range start' " + run_sub_test_lib_test_err run-inv-range-start \ + '--run invalid range start' \ + --run='a-5' <<-\\EOF && + test_expect_success \"passing test #1\" 'true' + test_done + EOF + check_sub_test_lib_test_err run-inv-range-start \ + <<-\\EOF_OUT 3<<-\\EOF_ERR + > FATAL: Unexpected exit with code 1 + EOF_OUT + > error: --run: invalid non-numeric in range start: 'a-5' + EOF_ERR +" + +test_expect_success '--run invalid range end' " + run_sub_test_lib_test_err run-inv-range-end \ + '--run invalid range end' \ + --run='1-z' <<-\\EOF && + test_expect_success \"passing test #1\" 'true' + test_done + EOF + check_sub_test_lib_test_err run-inv-range-end \ + <<-\\EOF_OUT 3<<-\\EOF_ERR + > FATAL: Unexpected exit with code 1 + EOF_OUT + > error: --run: invalid non-numeric in range end: '1-z' + EOF_ERR +" + +test_expect_success '--run invalid selector' " + run_sub_test_lib_test_err run-inv-selector \ + '--run invalid selector' \ + --run='1?' <<-\\EOF && + test_expect_success \"passing test #1\" 'true' + test_done + EOF + check_sub_test_lib_test_err run-inv-selector \ + <<-\\EOF_OUT 3<<-\\EOF_ERR + > FATAL: Unexpected exit with code 1 + EOF_OUT + > error: --run: invalid non-numeric in test selector: '1?' + EOF_ERR +" + + test_set_prereq HAVEIT haveit=no test_expect_success HAVEIT 'test runs if prerequisite is satisfied' ' @@ -557,7 +974,7 @@ test_expect_success 'writing this tree with --missing-ok' ' ################################################################ test_expect_success 'git read-tree followed by write-tree should be idempotent' ' - rm -f .git/index + rm -f .git/index && git read-tree $tree && test -f .git/index && newtree=$(git write-tree) && diff --git a/t/t0001-init.sh b/t/t0001-init.sh index bbc9cb60dd..f91bbcfc85 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -12,6 +12,13 @@ check_config () { echo "expected a directory $1, a file $1/config and $1/refs" return 1 fi + + if test_have_prereq POSIXPERM && test -x "$1/config" + then + echo "$1/config is executable?" + return 1 + fi + bare=$(cd "$1" && git config --bool core.bare) worktree=$(cd "$1" && git config core.worktree) || worktree=unset @@ -56,7 +63,7 @@ test_expect_success 'plain through aliased command, outside any git repo' ' check_config plain-aliased/.git false unset ' -test_expect_failure 'plain nested through aliased command' ' +test_expect_success 'plain nested through aliased command' ' ( git init plain-ancestor-aliased && cd plain-ancestor-aliased && @@ -68,7 +75,7 @@ test_expect_failure 'plain nested through aliased command' ' check_config plain-ancestor-aliased/plain-nested/.git false unset ' -test_expect_failure 'plain nested in bare through aliased command' ' +test_expect_success 'plain nested in bare through aliased command' ' ( git init --bare bare-ancestor-aliased.git && cd bare-ancestor-aliased.git && @@ -185,18 +192,18 @@ test_expect_success 'init --bare/--shared overrides system/global config' ' git init --bare --shared=0666 init-bare-shared-override && check_config init-bare-shared-override true unset && test x0666 = \ - x`git config -f init-bare-shared-override/config core.sharedRepository` + x$(git config -f init-bare-shared-override/config core.sharedRepository) ' test_expect_success 'init honors global core.sharedRepository' ' test_config_global core.sharedRepository 0666 && git init shared-honor-global && test x0666 = \ - x`git config -f shared-honor-global/.git/config core.sharedRepository` + x$(git config -f shared-honor-global/.git/config core.sharedRepository) ' -test_expect_success 'init rejects insanely long --template' ' - test_must_fail git init --template=$(printf "x%09999dx" 1) test +test_expect_success 'init allows insanely long --template' ' + git init --template=$(printf "x%09999dx" 1) test ' test_expect_success 'init creates a new directory' ' @@ -285,7 +292,7 @@ test_expect_success 'init prefers command line to GIT_DIR' ' test_expect_success 'init with separate gitdir' ' rm -rf newdir && git init --separate-git-dir realgitdir newdir && - echo "gitdir: `pwd`/realgitdir" >expected && + echo "gitdir: $(pwd)/realgitdir" >expected && test_cmp expected newdir/.git && test_path_is_dir realgitdir/refs ' @@ -299,7 +306,7 @@ test_expect_success 're-init to update git link' ' cd newdir && git init --separate-git-dir ../surrealgitdir ) && - echo "gitdir: `pwd`/surrealgitdir" >expected && + echo "gitdir: $(pwd)/surrealgitdir" >expected && test_cmp expected newdir/.git && test_path_is_dir surrealgitdir/refs && test_path_is_missing realgitdir/refs @@ -312,7 +319,7 @@ test_expect_success 're-init to move gitdir' ' cd newdir && git init --separate-git-dir ../realgitdir ) && - echo "gitdir: `pwd`/realgitdir" >expected && + echo "gitdir: $(pwd)/realgitdir" >expected && test_cmp expected newdir/.git && test_path_is_dir realgitdir/refs ' @@ -326,7 +333,7 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' ' ln -s here .git && git init --separate-git-dir ../realgitdir ) && - echo "gitdir: `pwd`/realgitdir" >expected && + echo "gitdir: $(pwd)/realgitdir" >expected && test_cmp expected newdir/.git && test_cmp expected newdir/here && test_path_is_dir realgitdir/refs diff --git a/t/t0002-gitfile.sh b/t/t0002-gitfile.sh index 37e9396e5d..3afe0125c9 100755 --- a/t/t0002-gitfile.sh +++ b/t/t0002-gitfile.sh @@ -99,4 +99,63 @@ test_expect_success 'check rev-list' ' test "$SHA" = "$(git rev-list HEAD)" ' +test_expect_failure 'setup_git_dir twice in subdir' ' + git init sgd && + ( + cd sgd && + git config alias.lsfi ls-files && + mv .git .realgit && + echo "gitdir: .realgit" >.git && + mkdir subdir && + cd subdir && + >foo && + git add foo && + git lsfi >actual && + echo foo >expected && + test_cmp expected actual + ) +' + +test_expect_success 'enter_repo non-strict mode' ' + test_create_repo enter_repo && + ( + cd enter_repo && + test_tick && + test_commit foo && + mv .git .realgit && + echo "gitdir: .realgit" >.git + ) && + git ls-remote enter_repo >actual && + cat >expected <<-\EOF && + 946e985ab20de757ca5b872b16d64e92ff3803a9 HEAD + 946e985ab20de757ca5b872b16d64e92ff3803a9 refs/heads/master + 946e985ab20de757ca5b872b16d64e92ff3803a9 refs/tags/foo + EOF + test_cmp expected actual +' + +test_expect_success 'enter_repo linked checkout' ' + ( + cd enter_repo && + git worktree add ../foo refs/tags/foo + ) && + git ls-remote foo >actual && + cat >expected <<-\EOF && + 946e985ab20de757ca5b872b16d64e92ff3803a9 HEAD + 946e985ab20de757ca5b872b16d64e92ff3803a9 refs/heads/master + 946e985ab20de757ca5b872b16d64e92ff3803a9 refs/tags/foo + EOF + test_cmp expected actual +' + +test_expect_success 'enter_repo strict mode' ' + 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 + EOF + test_cmp expected actual +' + test_done diff --git a/t/t0005-signals.sh b/t/t0005-signals.sh index 981437b3a8..e7f27ebbc1 100755 --- a/t/t0005-signals.sh +++ b/t/t0005-signals.sh @@ -10,8 +10,8 @@ one EOF test_expect_success 'sigchain works' ' - test-sigchain >actual - case "$?" in + { test-sigchain >actual; ret=$?; } && + case "$ret" in 143) true ;; # POSIX w/ SIGTERM=15 271) true ;; # ksh w/ SIGTERM=15 3) true ;; # Windows @@ -27,4 +27,26 @@ test_expect_success !MINGW 'signals are propagated using shell convention' ' test_expect_code 143 git sigterm ' +large_git () { + for i in $(test_seq 1 100) + do + git diff --cached --binary || return + done +} + +test_expect_success 'create blob' ' + test-genrandom foo 16384 >file && + git add file +' + +test_expect_success !MINGW 'a constipated git dies with SIGPIPE' ' + OUT=$( ((large_git; echo $? 1>&3) | :) 3>&1 ) && + test "$OUT" -eq 141 +' + +test_expect_success !MINGW 'a constipated git dies with SIGPIPE even if parent ignores it' ' + OUT=$( ((trap "" PIPE; large_git; echo $? 1>&3) | :) 3>&1 ) && + test "$OUT" -eq 141 +' + test_done diff --git a/t/t0006-date.sh b/t/t0006-date.sh index e53cf6d36d..fac0986134 100755 --- a/t/t0006-date.sh +++ b/t/t0006-date.sh @@ -82,4 +82,7 @@ check_approxidate 'Jun 6, 5AM' '2009-06-06 05:00:00' check_approxidate '5AM Jun 6' '2009-06-06 05:00:00' check_approxidate '6AM, June 7, 2009' '2009-06-07 06:00:00' +check_approxidate '2008-12-01' '2008-12-01 19:20:00' +check_approxidate '2009-12-01' '2009-12-01 19:20:00' + test_done diff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh index 39e55a13c8..4ef5ed484c 100755 --- a/t/t0008-ignores.sh +++ b/t/t0008-ignores.sh @@ -806,7 +806,7 @@ test_expect_success !MINGW 'quoting allows trailing whitespace' ' test_cmp err.expect err ' -test_expect_success NOT_MINGW,NOT_CYGWIN 'correct handling of backslashes' ' +test_expect_success !MINGW,!CYGWIN 'correct handling of backslashes' ' rm -rf whitespace && mkdir whitespace && >"whitespace/trailing 1 " && @@ -831,4 +831,14 @@ test_expect_success NOT_MINGW,NOT_CYGWIN 'correct handling of backslashes' ' test_cmp err.expect err ' +test_expect_success 'info/exclude trumps core.excludesfile' ' + echo >>global-excludes usually-ignored && + echo >>.git/info/exclude "!usually-ignored" && + >usually-ignored && + echo "?? usually-ignored" >expect && + + git status --porcelain usually-ignored >actual && + test_cmp expect actual +' + test_done diff --git a/t/t0010-racy-git.sh b/t/t0010-racy-git.sh index e45a9e40e4..5657c5a87b 100755 --- a/t/t0010-racy-git.sh +++ b/t/t0010-racy-git.sh @@ -14,7 +14,7 @@ do git update-index --add infocom echo xyzzy >infocom - files=`git diff-files -p` + files=$(git diff-files -p) test_expect_success \ "Racy GIT trial #$trial part A" \ 'test "" != "$files"' @@ -23,7 +23,7 @@ do echo xyzzy >cornerstone git update-index --add cornerstone - files=`git diff-files -p` + files=$(git diff-files -p) test_expect_success \ "Racy GIT trial #$trial part B" \ 'test "" != "$files"' diff --git a/t/t0011-hashmap.sh b/t/t0011-hashmap.sh index 391e2b6492..9c217d948c 100755 --- a/t/t0011-hashmap.sh +++ b/t/t0011-hashmap.sh @@ -218,7 +218,7 @@ test_expect_success 'grow / shrink' ' echo size >> in && echo 64 51 >> expect && echo put key52 value52 >> in && - echo NULL >> expect + echo NULL >> expect && echo size >> in && echo 256 52 >> expect && for n in $(test_seq 12) @@ -237,4 +237,17 @@ test_expect_success 'grow / shrink' ' ' +test_expect_success 'string interning' ' + +test_hashmap "intern value1 +intern Value1 +intern value2 +intern value2 +" "value1 +Value1 +value2 +value2" + +' + test_done diff --git a/t/t0020-crlf.sh b/t/t0020-crlf.sh index e526184a0b..f94120a894 100755 --- a/t/t0020-crlf.sh +++ b/t/t0020-crlf.sh @@ -8,6 +8,13 @@ has_cr() { tr '\015' Q <"$1" | grep Q >/dev/null } +# add or remove CRs to disk file in-place +# usage: munge_cr <append|remove> <file> +munge_cr () { + "${1}_cr" <"$2" >tmp && + mv tmp "$2" +} + test_expect_success setup ' git config core.autocrlf false && @@ -20,17 +27,15 @@ test_expect_success setup ' git commit -m initial && - one=`git rev-parse HEAD:one` && - dir=`git rev-parse HEAD:dir` && - two=`git rev-parse HEAD:dir/two` && - three=`git rev-parse HEAD:three` && + one=$(git rev-parse HEAD:one) && + dir=$(git rev-parse HEAD:dir) && + two=$(git rev-parse HEAD:dir/two) && + three=$(git rev-parse HEAD:three) && for w in Some extra lines here; do echo $w; done >>one && git diff >patch.file && - patched=`git hash-object --stdin <one` && - git read-tree --reset -u HEAD && - - echo happy. + patched=$(git hash-object --stdin <one) && + git read-tree --reset -u HEAD ' test_expect_success 'safecrlf: autocrlf=input, all CRLF' ' @@ -100,22 +105,11 @@ test_expect_success 'update with autocrlf=input' ' rm -f tmp one dir/two three && git read-tree --reset -u HEAD && git config core.autocrlf input && - - for f in one dir/two - do - append_cr <$f >tmp && mv -f tmp $f && - git update-index -- $f || { - echo Oops - false - break - } - done && - - differs=`git diff-index --cached HEAD` && - test -z "$differs" || { - echo Oops "$differs" - false - } + munge_cr append one && + munge_cr append dir/two && + git update-index -- one dir/two && + differs=$(git diff-index --cached HEAD) && + verbose test -z "$differs" ' @@ -124,22 +118,11 @@ test_expect_success 'update with autocrlf=true' ' rm -f tmp one dir/two three && git read-tree --reset -u HEAD && git config core.autocrlf true && - - for f in one dir/two - do - append_cr <$f >tmp && mv -f tmp $f && - git update-index -- $f || { - echo "Oops $f" - false - break - } - done && - - differs=`git diff-index --cached HEAD` && - test -z "$differs" || { - echo Oops "$differs" - false - } + munge_cr append one && + munge_cr append dir/two && + git update-index -- one dir/two && + differs=$(git diff-index --cached HEAD) && + verbose test -z "$differs" ' @@ -148,23 +131,13 @@ test_expect_success 'checkout with autocrlf=true' ' rm -f tmp one dir/two three && git config core.autocrlf true && git read-tree --reset -u HEAD && - - for f in one dir/two - do - remove_cr <"$f" >tmp && mv -f tmp $f && - git update-index -- $f || { - echo "Eh? $f" - false - break - } - done && - test "$one" = `git hash-object --stdin <one` && - test "$two" = `git hash-object --stdin <dir/two` && - differs=`git diff-index --cached HEAD` && - test -z "$differs" || { - echo Oops "$differs" - false - } + munge_cr remove one && + munge_cr remove dir/two && + git update-index -- one dir/two && + test "$one" = $(git hash-object --stdin <one) && + test "$two" = $(git hash-object --stdin <dir/two) && + differs=$(git diff-index --cached HEAD) && + verbose test -z "$differs" ' test_expect_success 'checkout with autocrlf=input' ' @@ -172,25 +145,13 @@ test_expect_success 'checkout with autocrlf=input' ' rm -f tmp one dir/two three && git config core.autocrlf input && git read-tree --reset -u HEAD && - - for f in one dir/two - do - if has_cr "$f" - then - echo "Eh? $f" - false - break - else - git update-index -- $f - fi - done && - test "$one" = `git hash-object --stdin <one` && - test "$two" = `git hash-object --stdin <dir/two` && - differs=`git diff-index --cached HEAD` && - test -z "$differs" || { - echo Oops "$differs" - false - } + test_must_fail has_cr one && + test_must_fail has_cr two && + git update-index -- one dir/two && + test "$one" = $(git hash-object --stdin <one) && + test "$two" = $(git hash-object --stdin <dir/two) && + differs=$(git diff-index --cached HEAD) && + verbose test -z "$differs" ' test_expect_success 'apply patch (autocrlf=input)' ' @@ -200,10 +161,7 @@ test_expect_success 'apply patch (autocrlf=input)' ' git read-tree --reset -u HEAD && git apply patch.file && - test "$patched" = "`git hash-object --stdin <one`" || { - echo "Eh? apply without index" - false - } + verbose test "$patched" = "$(git hash-object --stdin <one)" ' test_expect_success 'apply patch --cached (autocrlf=input)' ' @@ -213,10 +171,7 @@ test_expect_success 'apply patch --cached (autocrlf=input)' ' git read-tree --reset -u HEAD && git apply --cached patch.file && - test "$patched" = `git rev-parse :one` || { - echo "Eh? apply with --cached" - false - } + verbose test "$patched" = $(git rev-parse :one) ' test_expect_success 'apply patch --index (autocrlf=input)' ' @@ -226,11 +181,8 @@ test_expect_success 'apply patch --index (autocrlf=input)' ' git read-tree --reset -u HEAD && git apply --index patch.file && - test "$patched" = `git rev-parse :one` && - test "$patched" = `git hash-object --stdin <one` || { - echo "Eh? apply with --index" - false - } + verbose test "$patched" = $(git rev-parse :one) && + verbose test "$patched" = $(git hash-object --stdin <one) ' test_expect_success 'apply patch (autocrlf=true)' ' @@ -240,10 +192,7 @@ test_expect_success 'apply patch (autocrlf=true)' ' git read-tree --reset -u HEAD && git apply patch.file && - test "$patched" = "`remove_cr <one | git hash-object --stdin`" || { - echo "Eh? apply without index" - false - } + verbose test "$patched" = "$(remove_cr <one | git hash-object --stdin)" ' test_expect_success 'apply patch --cached (autocrlf=true)' ' @@ -253,10 +202,7 @@ test_expect_success 'apply patch --cached (autocrlf=true)' ' git read-tree --reset -u HEAD && git apply --cached patch.file && - test "$patched" = `git rev-parse :one` || { - echo "Eh? apply without index" - false - } + verbose test "$patched" = $(git rev-parse :one) ' test_expect_success 'apply patch --index (autocrlf=true)' ' @@ -266,11 +212,8 @@ test_expect_success 'apply patch --index (autocrlf=true)' ' git read-tree --reset -u HEAD && git apply --index patch.file && - test "$patched" = `git rev-parse :one` && - test "$patched" = "`remove_cr <one | git hash-object --stdin`" || { - echo "Eh? apply with --index" - false - } + verbose test "$patched" = $(git rev-parse :one) && + verbose test "$patched" = "$(remove_cr <one | git hash-object --stdin)" ' test_expect_success '.gitattributes says two is binary' ' @@ -280,29 +223,9 @@ test_expect_success '.gitattributes says two is binary' ' git config core.autocrlf true && git read-tree --reset -u HEAD && - if has_cr dir/two - then - echo "Huh?" - false - else - : happy - fi && - - if has_cr one - then - : happy - else - echo "Huh?" - false - fi && - - if has_cr three - then - echo "Huh?" - false - else - : happy - fi + test_must_fail has_cr dir/two && + verbose has_cr one && + test_must_fail has_cr three ' test_expect_success '.gitattributes says two is input' ' @@ -311,13 +234,7 @@ test_expect_success '.gitattributes says two is input' ' echo "two crlf=input" >.gitattributes && git read-tree --reset -u HEAD && - if has_cr dir/two - then - echo "Huh?" - false - else - : happy - fi + test_must_fail has_cr dir/two ' test_expect_success '.gitattributes says two and three are text' ' @@ -326,21 +243,8 @@ test_expect_success '.gitattributes says two and three are text' ' echo "t* crlf" >.gitattributes && git read-tree --reset -u HEAD && - if has_cr dir/two - then - : happy - else - echo "Huh?" - false - fi && - - if has_cr three - then - : happy - else - echo "Huh?" - false - fi + verbose has_cr dir/two && + verbose has_cr three ' test_expect_success 'in-tree .gitattributes (1)' ' @@ -352,17 +256,8 @@ test_expect_success 'in-tree .gitattributes (1)' ' rm -rf tmp one dir .gitattributes patch.file three && git read-tree --reset -u HEAD && - if has_cr one - then - echo "Eh? one should not have CRLF" - false - else - : happy - fi && - has_cr three || { - echo "Eh? three should still have CRLF" - false - } + test_must_fail has_cr one && + verbose has_cr three ' test_expect_success 'in-tree .gitattributes (2)' ' @@ -371,17 +266,8 @@ test_expect_success 'in-tree .gitattributes (2)' ' git read-tree --reset HEAD && git checkout-index -f -q -u -a && - if has_cr one - then - echo "Eh? one should not have CRLF" - false - else - : happy - fi && - has_cr three || { - echo "Eh? three should still have CRLF" - false - } + test_must_fail has_cr one && + verbose has_cr three ' test_expect_success 'in-tree .gitattributes (3)' ' @@ -391,17 +277,8 @@ test_expect_success 'in-tree .gitattributes (3)' ' git checkout-index -u .gitattributes && git checkout-index -u one dir/two three && - if has_cr one - then - echo "Eh? one should not have CRLF" - false - else - : happy - fi && - has_cr three || { - echo "Eh? three should still have CRLF" - false - } + test_must_fail has_cr one && + verbose has_cr three ' test_expect_success 'in-tree .gitattributes (4)' ' @@ -411,17 +288,8 @@ test_expect_success 'in-tree .gitattributes (4)' ' git checkout-index -u one dir/two three && git checkout-index -u .gitattributes && - if has_cr one - then - echo "Eh? one should not have CRLF" - false - else - : happy - fi && - has_cr three || { - echo "Eh? three should still have CRLF" - false - } + test_must_fail has_cr one && + verbose has_cr three ' test_expect_success 'checkout with existing .gitattributes' ' diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh index b92e6cb046..718efa04d3 100755 --- a/t/t0021-conversion.sh +++ b/t/t0021-conversion.sh @@ -153,17 +153,23 @@ test_expect_success 'filter shell-escaped filenames' ' : ' -test_expect_success 'required filter success' ' - git config filter.required.smudge cat && - git config filter.required.clean cat && +test_expect_success 'required filter should filter data' ' + git config filter.required.smudge ./rot13.sh && + git config filter.required.clean ./rot13.sh && git config filter.required.required true && echo "*.r filter=required" >.gitattributes && - echo test >test.r && + cat test.o >test.r && git add test.r && + rm -f test.r && - git checkout -- test.r + git checkout -- test.r && + cmp test.o test.r && + + ./rot13.sh <test.o >expected && + git cat-file blob :test.r >actual && + cmp expected actual ' test_expect_success 'required filter smudge failure' ' @@ -190,7 +196,23 @@ test_expect_success 'required filter clean failure' ' test_must_fail git add test.fc ' -test -n "$GIT_TEST_LONG" && test_set_prereq EXPENSIVE +test_expect_success 'filtering large input to small output should use little memory' ' + git config filter.devnull.clean "cat >/dev/null" && + git config filter.devnull.required true && + for i in $(test_seq 1 30); do printf "%1048576d" 1; done >30MB && + echo "30MB filter=devnull" >.gitattributes && + GIT_MMAP_LIMIT=1m GIT_ALLOC_LIMIT=1m git add 30MB +' + +test_expect_success 'filter that does not read is fine' ' + test-genrandom foo $((128 * 1024 + 1)) >big && + echo "big filter=epipe" >.gitattributes && + git config filter.epipe.clean "echo xyzzy" && + git add big && + git cat-file blob :big >actual && + echo xyzzy >expect && + test_cmp expect actual +' test_expect_success EXPENSIVE 'filter large file' ' git config filter.largefile.smudge cat && @@ -204,4 +226,30 @@ test_expect_success EXPENSIVE 'filter large file' ' ! test -s err ' +test_expect_success "filter: clean empty file" ' + git config filter.in-repo-header.clean "echo cleaned && cat" && + git config filter.in-repo-header.smudge "sed 1d" && + + echo "empty-in-worktree filter=in-repo-header" >>.gitattributes && + >empty-in-worktree && + + echo cleaned >expected && + git add empty-in-worktree && + git show :empty-in-worktree >actual && + test_cmp expected actual +' + +test_expect_success "filter: smudge empty file" ' + git config filter.empty-in-repo.clean "cat >/dev/null" && + git config filter.empty-in-repo.smudge "echo smudged && cat" && + + echo "empty-in-repo filter=empty-in-repo" >>.gitattributes && + echo dead data walking >empty-in-repo && + git add empty-in-repo && + + echo smudged >expected && + git checkout-index --prefix=filtered- empty-in-repo && + test_cmp expected filtered-empty-in-repo +' + test_done diff --git a/t/t0025-crlf-auto.sh b/t/t0025-crlf-auto.sh index f5f67a6337..c164b4662a 100755 --- a/t/t0025-crlf-auto.sh +++ b/t/t0025-crlf-auto.sh @@ -12,144 +12,144 @@ test_expect_success setup ' git config core.autocrlf false && - for w in Hello world how are you; do echo $w; done >one && - for w in I am very very fine thank you; do echo ${w}Q; done | q_to_cr >two && - for w in Oh here is a QNUL byte how alarming; do echo ${w}; done | q_to_nul >three && + for w in Hello world how are you; do echo $w; done >LFonly && + for w in I am very very fine thank you; do echo ${w}Q; done | q_to_cr >CRLFonly && + for w in Oh here is a QNUL byte how alarming; do echo ${w}; done | q_to_nul >LFwithNUL && git add . && git commit -m initial && - one=`git rev-parse HEAD:one` && - two=`git rev-parse HEAD:two` && - three=`git rev-parse HEAD:three` && + LFonly=$(git rev-parse HEAD:LFonly) && + CRLFonly=$(git rev-parse HEAD:CRLFonly) && + LFwithNUL=$(git rev-parse HEAD:LFwithNUL) && echo happy. ' test_expect_success 'default settings cause no changes' ' - rm -f .gitattributes tmp one two three && + rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL && git read-tree --reset -u HEAD && - ! has_cr one && - has_cr two && - onediff=`git diff one` && - twodiff=`git diff two` && - threediff=`git diff three` && - test -z "$onediff" -a -z "$twodiff" -a -z "$threediff" + ! has_cr LFonly && + has_cr CRLFonly && + LFonlydiff=$(git diff LFonly) && + CRLFonlydiff=$(git diff CRLFonly) && + LFwithNULdiff=$(git diff LFwithNUL) && + test -z "$LFonlydiff" -a -z "$CRLFonlydiff" -a -z "$LFwithNULdiff" ' test_expect_success 'crlf=true causes a CRLF file to be normalized' ' # Backwards compatibility check - rm -f .gitattributes tmp one two three && - echo "two crlf" > .gitattributes && + rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL && + echo "CRLFonly crlf" > .gitattributes && git read-tree --reset -u HEAD && # Note, "normalized" means that git will normalize it if added - has_cr two && - twodiff=`git diff two` && - test -n "$twodiff" + has_cr CRLFonly && + CRLFonlydiff=$(git diff CRLFonly) && + test -n "$CRLFonlydiff" ' test_expect_success 'text=true causes a CRLF file to be normalized' ' - rm -f .gitattributes tmp one two three && - echo "two text" > .gitattributes && + rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL && + echo "CRLFonly text" > .gitattributes && git read-tree --reset -u HEAD && # Note, "normalized" means that git will normalize it if added - has_cr two && - twodiff=`git diff two` && - test -n "$twodiff" + has_cr CRLFonly && + CRLFonlydiff=$(git diff CRLFonly) && + test -n "$CRLFonlydiff" ' test_expect_success 'eol=crlf gives a normalized file CRLFs with autocrlf=false' ' - rm -f .gitattributes tmp one two three && + rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL && git config core.autocrlf false && - echo "one eol=crlf" > .gitattributes && + echo "LFonly eol=crlf" > .gitattributes && git read-tree --reset -u HEAD && - has_cr one && - onediff=`git diff one` && - test -z "$onediff" + has_cr LFonly && + LFonlydiff=$(git diff LFonly) && + test -z "$LFonlydiff" ' test_expect_success 'eol=crlf gives a normalized file CRLFs with autocrlf=input' ' - rm -f .gitattributes tmp one two three && + rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL && git config core.autocrlf input && - echo "one eol=crlf" > .gitattributes && + echo "LFonly eol=crlf" > .gitattributes && git read-tree --reset -u HEAD && - has_cr one && - onediff=`git diff one` && - test -z "$onediff" + has_cr LFonly && + LFonlydiff=$(git diff LFonly) && + test -z "$LFonlydiff" ' test_expect_success 'eol=lf gives a normalized file LFs with autocrlf=true' ' - rm -f .gitattributes tmp one two three && + rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL && git config core.autocrlf true && - echo "one eol=lf" > .gitattributes && + echo "LFonly eol=lf" > .gitattributes && git read-tree --reset -u HEAD && - ! has_cr one && - onediff=`git diff one` && - test -z "$onediff" + ! has_cr LFonly && + LFonlydiff=$(git diff LFonly) && + test -z "$LFonlydiff" ' test_expect_success 'autocrlf=true does not normalize CRLF files' ' - rm -f .gitattributes tmp one two three && + rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL && git config core.autocrlf true && git read-tree --reset -u HEAD && - has_cr one && - has_cr two && - onediff=`git diff one` && - twodiff=`git diff two` && - threediff=`git diff three` && - test -z "$onediff" -a -z "$twodiff" -a -z "$threediff" + has_cr LFonly && + has_cr CRLFonly && + LFonlydiff=$(git diff LFonly) && + CRLFonlydiff=$(git diff CRLFonly) && + LFwithNULdiff=$(git diff LFwithNUL) && + test -z "$LFonlydiff" -a -z "$CRLFonlydiff" -a -z "$LFwithNULdiff" ' test_expect_success 'text=auto, autocrlf=true _does_ normalize CRLF files' ' - rm -f .gitattributes tmp one two three && + rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL && git config core.autocrlf true && echo "* text=auto" > .gitattributes && git read-tree --reset -u HEAD && - has_cr one && - has_cr two && - onediff=`git diff one` && - twodiff=`git diff two` && - threediff=`git diff three` && - test -z "$onediff" -a -n "$twodiff" -a -z "$threediff" + has_cr LFonly && + has_cr CRLFonly && + LFonlydiff=$(git diff LFonly) && + CRLFonlydiff=$(git diff CRLFonly) && + LFwithNULdiff=$(git diff LFwithNUL) && + test -z "$LFonlydiff" -a -n "$CRLFonlydiff" -a -z "$LFwithNULdiff" ' test_expect_success 'text=auto, autocrlf=true does not normalize binary files' ' - rm -f .gitattributes tmp one two three && + rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL && git config core.autocrlf true && echo "* text=auto" > .gitattributes && git read-tree --reset -u HEAD && - ! has_cr three && - threediff=`git diff three` && - test -z "$threediff" + ! has_cr LFwithNUL && + LFwithNULdiff=$(git diff LFwithNUL) && + test -z "$LFwithNULdiff" ' test_expect_success 'eol=crlf _does_ normalize binary files' ' - rm -f .gitattributes tmp one two three && - echo "three eol=crlf" > .gitattributes && + rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL && + echo "LFwithNUL eol=crlf" > .gitattributes && git read-tree --reset -u HEAD && - has_cr three && - threediff=`git diff three` && - test -z "$threediff" + has_cr LFwithNUL && + LFwithNULdiff=$(git diff LFwithNUL) && + test -z "$LFwithNULdiff" ' test_done diff --git a/t/t0026-eol-config.sh b/t/t0026-eol-config.sh index fe0164be62..c5203e232c 100755 --- a/t/t0026-eol-config.sh +++ b/t/t0026-eol-config.sh @@ -20,8 +20,8 @@ test_expect_success setup ' git commit -m initial && - one=`git rev-parse HEAD:one` && - two=`git rev-parse HEAD:two` && + one=$(git rev-parse HEAD:one) && + two=$(git rev-parse HEAD:two) && echo happy. ' @@ -34,9 +34,9 @@ test_expect_success 'eol=lf puts LFs in normalized file' ' ! has_cr one && ! has_cr two && - onediff=`git diff one` && - twodiff=`git diff two` && - test -z "$onediff" -a -z "$twodiff" + onediff=$(git diff one) && + twodiff=$(git diff two) && + test -z "$onediff" && test -z "$twodiff" ' test_expect_success 'eol=crlf puts CRLFs in normalized file' ' @@ -47,9 +47,9 @@ test_expect_success 'eol=crlf puts CRLFs in normalized file' ' has_cr one && ! has_cr two && - onediff=`git diff one` && - twodiff=`git diff two` && - test -z "$onediff" -a -z "$twodiff" + onediff=$(git diff one) && + twodiff=$(git diff two) && + test -z "$onediff" && test -z "$twodiff" ' test_expect_success 'autocrlf=true overrides eol=lf' ' @@ -61,9 +61,9 @@ test_expect_success 'autocrlf=true overrides eol=lf' ' has_cr one && has_cr two && - onediff=`git diff one` && - twodiff=`git diff two` && - test -z "$onediff" -a -z "$twodiff" + onediff=$(git diff one) && + twodiff=$(git diff two) && + test -z "$onediff" && test -z "$twodiff" ' test_expect_success 'autocrlf=true overrides unset eol' ' @@ -75,9 +75,29 @@ test_expect_success 'autocrlf=true overrides unset eol' ' has_cr one && has_cr two && - onediff=`git diff one` && - twodiff=`git diff two` && - test -z "$onediff" -a -z "$twodiff" + onediff=$(git diff one) && + twodiff=$(git diff two) && + test -z "$onediff" && test -z "$twodiff" +' + +test_expect_success NATIVE_CRLF 'eol native is crlf' ' + + rm -rf native_eol && mkdir native_eol && + ( + cd native_eol && + printf "*.txt text\n" >.gitattributes && + printf "one\r\ntwo\r\nthree\r\n" >filedos.txt && + printf "one\ntwo\nthree\n" >fileunix.txt && + git init && + git config core.autocrlf false && + git config core.eol native && + git add filedos.txt fileunix.txt && + git commit -m "first" && + rm file*.txt && + git reset --hard HEAD && + has_cr filedos.txt && + has_cr fileunix.txt + ) ' test_done diff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh new file mode 100755 index 0000000000..b343651504 --- /dev/null +++ b/t/t0027-auto-crlf.sh @@ -0,0 +1,483 @@ +#!/bin/sh + +test_description='CRLF conversion all combinations' + +. ./test-lib.sh + +if ! test_have_prereq EXPENSIVE +then + skip_all="EXPENSIVE not set" + test_done +fi + +compare_files () { + tr '\015\000' QN <"$1" >"$1".expect && + tr '\015\000' QN <"$2" >"$2".actual && + test_cmp "$1".expect "$2".actual && + rm "$1".expect "$2".actual +} + +compare_ws_file () { + pfx=$1 + exp=$2.expect + act=$pfx.actual.$3 + tr '\015\000' QN <"$2" >"$exp" && + tr '\015\000' QN <"$3" >"$act" && + test_cmp $exp $act && + rm $exp $act +} + +create_gitattributes () { + attr=$1 + case "$attr" in + auto) + echo "*.txt text=auto" >.gitattributes + ;; + text) + echo "*.txt text" >.gitattributes + ;; + -text) + echo "*.txt -text" >.gitattributes + ;; + crlf) + echo "*.txt eol=crlf" >.gitattributes + ;; + lf) + echo "*.txt eol=lf" >.gitattributes + ;; + "") + echo >.gitattributes + ;; + *) + echo >&2 invalid attribute: $attr + exit 1 + ;; + esac +} + +create_NNO_files () { + lfname=$1 + crlfname=$2 + lfmixcrlf=$3 + lfmixcr=$4 + crlfnul=$5 + for crlf in false true input + do + for attr in "" auto text -text lf crlf + do + pfx=NNO_${crlf}_attr_${attr} && + cp $lfname ${pfx}_LF.txt && + cp $crlfname ${pfx}_CRLF.txt && + cp $lfmixcrlf ${pfx}_CRLF_mix_LF.txt && + cp $lfmixcr ${pfx}_LF_mix_CR.txt && + cp $crlfnul ${pfx}_CRLF_nul.txt + done + done +} + +check_warning () { + case "$1" in + LF_CRLF) echo "warning: LF will be replaced by CRLF" >"$2".expect ;; + CRLF_LF) echo "warning: CRLF will be replaced by LF" >"$2".expect ;; + '') >"$2".expect ;; + *) echo >&2 "Illegal 1": "$1" ; return false ;; + esac + grep "will be replaced by" "$2" | sed -e "s/\(.*\) in [^ ]*$/\1/" | uniq >"$2".actual + test_cmp "$2".expect "$2".actual +} + +commit_check_warn () { + crlf=$1 + attr=$2 + lfname=$3 + crlfname=$4 + lfmixcrlf=$5 + lfmixcr=$6 + crlfnul=$7 + pfx=crlf_${crlf}_attr_${attr} + create_gitattributes "$attr" && + for f in LF CRLF repoMIX LF_mix_CR CRLF_mix_LF LF_nul CRLF_nul + do + fname=${pfx}_$f.txt && + cp $f $fname && + git -c core.autocrlf=$crlf add $fname 2>"${pfx}_$f.err" + done && + git commit -m "core.autocrlf $crlf" && + check_warning "$lfname" ${pfx}_LF.err && + check_warning "$crlfname" ${pfx}_CRLF.err && + check_warning "$lfmixcrlf" ${pfx}_CRLF_mix_LF.err && + check_warning "$lfmixcr" ${pfx}_LF_mix_CR.err && + check_warning "$crlfnul" ${pfx}_CRLF_nul.err +} + +commit_chk_wrnNNO () { + crlf=$1 + attr=$2 + lfwarn=$3 + crlfwarn=$4 + lfmixcrlf=$5 + lfmixcr=$6 + crlfnul=$7 + pfx=NNO_${crlf}_attr_${attr} + #Commit files on top of existing file + create_gitattributes "$attr" && + for f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul + do + fname=${pfx}_$f.txt && + cp $f $fname && + git -c core.autocrlf=$crlf add $fname 2>/dev/null && + git -c core.autocrlf=$crlf commit -m "commit_$fname" $fname >"${pfx}_$f.err" 2>&1 + done + + test_expect_success "commit NNO files crlf=$crlf attr=$attr LF" ' + check_warning "$lfwarn" ${pfx}_LF.err + ' + test_expect_success "commit NNO files crlf=$crlf attr=$attr CRLF" ' + check_warning "$crlfwarn" ${pfx}_CRLF.err + ' + + test_expect_success "commit NNO files crlf=$crlf attr=$attr CRLF_mix_LF" ' + check_warning "$lfmixcrlf" ${pfx}_CRLF_mix_LF.err + ' + + test_expect_success "commit NNO files crlf=$crlf attr=$attr LF_mix_cr" ' + check_warning "$lfmixcr" ${pfx}_LF_mix_CR.err + ' + + test_expect_success "commit NNO files crlf=$crlf attr=$attr CRLF_nul" ' + check_warning "$crlfnul" ${pfx}_CRLF_nul.err + ' +} + +check_files_in_repo () { + crlf=$1 + attr=$2 + lfname=$3 + crlfname=$4 + lfmixcrlf=$5 + lfmixcr=$6 + crlfnul=$7 + pfx=crlf_${crlf}_attr_${attr}_ && + compare_files $lfname ${pfx}LF.txt && + compare_files $crlfname ${pfx}CRLF.txt && + compare_files $lfmixcrlf ${pfx}CRLF_mix_LF.txt && + compare_files $lfmixcr ${pfx}LF_mix_CR.txt && + compare_files $crlfnul ${pfx}CRLF_nul.txt +} + +check_in_repo_NNO () { + crlf=$1 + attr=$2 + lfname=$3 + crlfname=$4 + lfmixcrlf=$5 + lfmixcr=$6 + crlfnul=$7 + pfx=NNO_${crlf}_attr_${attr}_ + test_expect_success "compare_files $lfname ${pfx}LF.txt" ' + compare_files $lfname ${pfx}LF.txt + ' + test_expect_success "compare_files $crlfname ${pfx}CRLF.txt" ' + compare_files $crlfname ${pfx}CRLF.txt + ' + test_expect_success "compare_files $lfmixcrlf ${pfx}CRLF_mix_LF.txt" ' + compare_files $lfmixcrlf ${pfx}CRLF_mix_LF.txt + ' + test_expect_success "compare_files $lfmixcr ${pfx}LF_mix_CR.txt" ' + compare_files $lfmixcr ${pfx}LF_mix_CR.txt + ' + test_expect_success "compare_files $crlfnul ${pfx}CRLF_nul.txt" ' + compare_files $crlfnul ${pfx}CRLF_nul.txt + ' +} + +checkout_files () { + eol=$1 + crlf=$2 + attr=$3 + lfname=$4 + crlfname=$5 + lfmixcrlf=$6 + lfmixcr=$7 + crlfnul=$8 + create_gitattributes $attr && + git config core.autocrlf $crlf && + pfx=eol_${eol}_crlf_${crlf}_attr_${attr}_ && + src=crlf_false_attr__ && + for f in LF CRLF LF_mix_CR CRLF_mix_LF LF_nul + do + rm $src$f.txt && + if test -z "$eol"; then + git checkout $src$f.txt + else + git -c core.eol=$eol checkout $src$f.txt + fi + done + + test_expect_success "checkout core.eol=$eol core.autocrlf=$crlf gitattributes=$attr file=LF" " + compare_ws_file $pfx $lfname ${src}LF.txt + " + test_expect_success "checkout core.eol=$eol core.autocrlf=$crlf gitattributes=$attr file=CRLF" " + compare_ws_file $pfx $crlfname ${src}CRLF.txt + " + test_expect_success "checkout core.eol=$eol core.autocrlf=$crlf gitattributes=$attr file=CRLF_mix_LF" " + compare_ws_file $pfx $lfmixcrlf ${src}CRLF_mix_LF.txt + " + test_expect_success "checkout core.eol=$eol core.autocrlf=$crlf gitattributes=$attr file=LF_mix_CR" " + compare_ws_file $pfx $lfmixcr ${src}LF_mix_CR.txt + " + test_expect_success "checkout core.eol=$eol core.autocrlf=$crlf gitattributes=$attr file=LF_nul" " + compare_ws_file $pfx $crlfnul ${src}LF_nul.txt + " +} + +####### +test_expect_success 'setup master' ' + echo >.gitattributes && + git checkout -b master && + git add .gitattributes && + git commit -m "add .gitattributes" "" && + printf "line1\nline2\nline3" >LF && + printf "line1\r\nline2\r\nline3" >CRLF && + printf "line1\r\nline2\nline3" >repoMIX && + printf "line1\r\nline2\nline3" >CRLF_mix_LF && + printf "line1\nline2\rline3" >LF_mix_CR && + printf "line1\r\nline2\rline3" >CRLF_mix_CR && + printf "line1Q\r\nline2\r\nline3" | q_to_nul >CRLF_nul && + printf "line1Q\nline2\nline3" | q_to_nul >LF_nul && + create_NNO_files CRLF_mix_LF CRLF_mix_LF CRLF_mix_LF CRLF_mix_LF CRLF_mix_LF && + git -c core.autocrlf=false add NNO_*.txt && + git commit -m "mixed line endings" && + test_tick +' + + + +warn_LF_CRLF="LF will be replaced by CRLF" +warn_CRLF_LF="CRLF will be replaced by LF" + +# WILC stands for "Warn if (this OS) converts LF into CRLF". +# WICL: Warn if CRLF becomes LF +# WAMIX: Mixed line endings: either CRLF->LF or LF->CRLF +if test_have_prereq NATIVE_CRLF +then + WILC=LF_CRLF + WICL= + WAMIX=LF_CRLF +else + WILC= + WICL=CRLF_LF + WAMIX=CRLF_LF +fi + +# attr LF CRLF CRLFmixLF LFmixCR CRLFNUL +test_expect_success 'commit files empty attr' ' + commit_check_warn false "" "" "" "" "" "" && + commit_check_warn true "" "LF_CRLF" "" "LF_CRLF" "" "" && + commit_check_warn input "" "" "CRLF_LF" "CRLF_LF" "" "" +' + +test_expect_success 'commit files attr=auto' ' + commit_check_warn false "auto" "$WILC" "$WICL" "$WAMIX" "" "" && + commit_check_warn true "auto" "LF_CRLF" "" "LF_CRLF" "" "" && + commit_check_warn input "auto" "" "CRLF_LF" "CRLF_LF" "" "" +' + +test_expect_success 'commit files attr=text' ' + commit_check_warn false "text" "$WILC" "$WICL" "$WAMIX" "$WILC" "$WICL" && + commit_check_warn true "text" "LF_CRLF" "" "LF_CRLF" "LF_CRLF" "" && + commit_check_warn input "text" "" "CRLF_LF" "CRLF_LF" "" "CRLF_LF" +' + +test_expect_success 'commit files attr=-text' ' + commit_check_warn false "-text" "" "" "" "" "" && + commit_check_warn true "-text" "" "" "" "" "" && + commit_check_warn input "-text" "" "" "" "" "" +' + +test_expect_success 'commit files attr=lf' ' + commit_check_warn false "lf" "" "CRLF_LF" "CRLF_LF" "" "CRLF_LF" && + commit_check_warn true "lf" "" "CRLF_LF" "CRLF_LF" "" "CRLF_LF" && + commit_check_warn input "lf" "" "CRLF_LF" "CRLF_LF" "" "CRLF_LF" +' + +test_expect_success 'commit files attr=crlf' ' + commit_check_warn false "crlf" "LF_CRLF" "" "LF_CRLF" "LF_CRLF" "" && + commit_check_warn true "crlf" "LF_CRLF" "" "LF_CRLF" "LF_CRLF" "" && + commit_check_warn input "crlf" "LF_CRLF" "" "LF_CRLF" "LF_CRLF" "" +' + +# attr LF CRLF CRLFmixLF LF_mix_CR CRLFNUL +commit_chk_wrnNNO false "" "" "" "" "" "" +commit_chk_wrnNNO true "" "LF_CRLF" "" "" "" "" +commit_chk_wrnNNO input "" "" "" "" "" "" + + +commit_chk_wrnNNO false "auto" "$WILC" "$WICL" "$WAMIX" "" "" +commit_chk_wrnNNO true "auto" "LF_CRLF" "" "LF_CRLF" "" "" +commit_chk_wrnNNO input "auto" "" "CRLF_LF" "CRLF_LF" "" "" + +commit_chk_wrnNNO false "text" "$WILC" "$WICL" "$WAMIX" "$WILC" "$WICL" +commit_chk_wrnNNO true "text" "LF_CRLF" "" "LF_CRLF" "LF_CRLF" "" +commit_chk_wrnNNO input "text" "" "CRLF_LF" "CRLF_LF" "" "CRLF_LF" + +commit_chk_wrnNNO false "-text" "" "" "" "" "" +commit_chk_wrnNNO true "-text" "" "" "" "" "" +commit_chk_wrnNNO input "-text" "" "" "" "" "" + +commit_chk_wrnNNO false "lf" "" "CRLF_LF" "CRLF_LF" "" "CRLF_LF" +commit_chk_wrnNNO true "lf" "" "CRLF_LF" "CRLF_LF" "" "CRLF_LF" +commit_chk_wrnNNO input "lf" "" "CRLF_LF" "CRLF_LF" "" "CRLF_LF" + +commit_chk_wrnNNO false "crlf" "LF_CRLF" "" "LF_CRLF" "LF_CRLF" "" +commit_chk_wrnNNO true "crlf" "LF_CRLF" "" "LF_CRLF" "LF_CRLF" "" +commit_chk_wrnNNO input "crlf" "LF_CRLF" "" "LF_CRLF" "LF_CRLF" "" + +test_expect_success 'create files cleanup' ' + rm -f *.txt && + git -c core.autocrlf=false reset --hard +' + +test_expect_success 'commit empty gitattribues' ' + check_files_in_repo false "" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul && + check_files_in_repo true "" LF LF LF LF_mix_CR CRLF_nul && + check_files_in_repo input "" LF LF LF LF_mix_CR CRLF_nul +' + +test_expect_success 'commit text=auto' ' + check_files_in_repo false "auto" LF LF LF LF_mix_CR CRLF_nul && + check_files_in_repo true "auto" LF LF LF LF_mix_CR CRLF_nul && + check_files_in_repo input "auto" LF LF LF LF_mix_CR CRLF_nul +' + +test_expect_success 'commit text' ' + check_files_in_repo false "text" LF LF LF LF_mix_CR LF_nul && + check_files_in_repo true "text" LF LF LF LF_mix_CR LF_nul && + check_files_in_repo input "text" LF LF LF LF_mix_CR LF_nul +' + +test_expect_success 'commit -text' ' + check_files_in_repo false "-text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul && + check_files_in_repo true "-text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul && + check_files_in_repo input "-text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul +' + +# attr LF CRLF CRLF_mix_LF LF_mix_CR CRLFNUL +check_in_repo_NNO false "" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul +check_in_repo_NNO true "" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul +check_in_repo_NNO input "" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul + +check_in_repo_NNO false "auto" LF LF LF LF_mix_CR CRLF_nul +check_in_repo_NNO true "auto" LF LF LF LF_mix_CR CRLF_nul +check_in_repo_NNO input "auto" LF LF LF LF_mix_CR CRLF_nul + +check_in_repo_NNO false "text" LF LF LF LF_mix_CR LF_nul +check_in_repo_NNO true "text" LF LF LF LF_mix_CR LF_nul +check_in_repo_NNO input "text" LF LF LF LF_mix_CR LF_nul + +check_in_repo_NNO false "-text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul +check_in_repo_NNO true "-text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul +check_in_repo_NNO input "-text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul + + +################################################################################ +# Check how files in the repo are changed when they are checked out +# How to read the table below: +# - checkout_files will check multiple files with a combination of settings +# and attributes (core.autocrlf=input is forbidden with core.eol=crlf) +# - parameter $1 : core.eol lf | crlf +# - parameter $2 : core.autocrlf false | true | input +# - parameter $3 : text in .gitattributs "" (empty) | auto | text | -text +# - parameter $4 : reference for a file with only LF in the repo +# - parameter $5 : reference for a file with only CRLF in the repo +# - parameter $6 : reference for a file with mixed LF and CRLF in the repo +# - parameter $7 : reference for a file with LF and CR in the repo (does somebody uses this ?) +# - parameter $8 : reference for a file with CRLF and a NUL (should be handled as binary when auto) + +# What we have in the repo: +# ----------------- EOL in repo ---------------- +# LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul +# settings with checkout: +# core. core. .gitattr +# eol acrlf +# ---------------------------------------------- +# What we want to have in the working tree: +if test_have_prereq NATIVE_CRLF +then +MIX_CRLF_LF=CRLF +MIX_LF_CR=CRLF_mix_CR +NL=CRLF +LFNUL=CRLF_nul +else +MIX_CRLF_LF=CRLF_mix_LF +MIX_LF_CR=LF_mix_CR +NL=LF +LFNUL=LF_nul +fi +export CRLF_MIX_LF_CR MIX NL + +checkout_files lf false "" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files lf true "" CRLF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files lf input "" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files lf false "auto" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files lf true "auto" CRLF CRLF CRLF LF_mix_CR LF_nul +checkout_files lf input "auto" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files lf false "text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files lf true "text" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul +checkout_files lf input "text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files lf false "-text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files lf true "-text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files lf input "-text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files lf false "lf" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files lf true "lf" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files lf input "lf" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files lf false "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul +checkout_files lf true "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul +checkout_files lf input "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul + +checkout_files crlf false "" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files crlf true "" CRLF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files crlf false "auto" CRLF CRLF CRLF LF_mix_CR LF_nul +checkout_files crlf true "auto" CRLF CRLF CRLF LF_mix_CR LF_nul +checkout_files crlf false "text" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul +checkout_files crlf true "text" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul +checkout_files crlf false "-text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files crlf true "-text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files crlf false "lf" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files crlf true "lf" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files crlf false "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul +checkout_files crlf true "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul + +checkout_files "" false "" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" true "" CRLF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" input "" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" false "auto" $NL CRLF $MIX_CRLF_LF LF_mix_CR LF_nul +checkout_files "" true "auto" CRLF CRLF CRLF LF_mix_CR LF_nul +checkout_files "" input "auto" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" false "text" $NL CRLF $MIX_CRLF_LF $MIX_LF_CR $LFNUL +checkout_files "" true "text" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul +checkout_files "" input "text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" false "-text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" true "-text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" input "-text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" false "lf" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" true "lf" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" input "lf" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files "" false "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul +checkout_files "" true "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul +checkout_files "" input "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul + +checkout_files native false "" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files native true "" CRLF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files native false "auto" $NL CRLF $MIX_CRLF_LF LF_mix_CR LF_nul +checkout_files native true "auto" CRLF CRLF CRLF LF_mix_CR LF_nul +checkout_files native false "text" $NL CRLF $MIX_CRLF_LF $MIX_LF_CR $LFNUL +checkout_files native true "text" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul +checkout_files native false "-text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files native true "-text" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files native false "lf" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files native true "lf" LF CRLF CRLF_mix_LF LF_mix_CR LF_nul +checkout_files native false "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul +checkout_files native true "crlf" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul + +test_done diff --git a/t/t0030-stripspace.sh b/t/t0030-stripspace.sh index a8e84d8546..29e91d861c 100755 --- a/t/t0030-stripspace.sh +++ b/t/t0030-stripspace.sh @@ -225,22 +225,22 @@ test_expect_success \ test_expect_success \ 'text without newline at end should end with newline' ' - test `printf "$ttt" | git stripspace | wc -l` -gt 0 && - test `printf "$ttt$ttt" | git stripspace | wc -l` -gt 0 && - test `printf "$ttt$ttt$ttt" | git stripspace | wc -l` -gt 0 && - test `printf "$ttt$ttt$ttt$ttt" | git stripspace | wc -l` -gt 0 + test $(printf "$ttt" | git stripspace | wc -l) -gt 0 && + test $(printf "$ttt$ttt" | git stripspace | wc -l) -gt 0 && + test $(printf "$ttt$ttt$ttt" | git stripspace | wc -l) -gt 0 && + test $(printf "$ttt$ttt$ttt$ttt" | git stripspace | wc -l) -gt 0 ' # text plus spaces at the end: test_expect_success \ 'text plus spaces without newline at end should end with newline' ' - test `printf "$ttt$sss" | git stripspace | wc -l` -gt 0 && - test `printf "$ttt$ttt$sss" | git stripspace | wc -l` -gt 0 && - test `printf "$ttt$ttt$ttt$sss" | git stripspace | wc -l` -gt 0 && - test `printf "$ttt$sss$sss" | git stripspace | wc -l` -gt 0 && - test `printf "$ttt$ttt$sss$sss" | git stripspace | wc -l` -gt 0 && - test `printf "$ttt$sss$sss$sss" | git stripspace | wc -l` -gt 0 + test $(printf "$ttt$sss" | git stripspace | wc -l) -gt 0 && + test $(printf "$ttt$ttt$sss" | git stripspace | wc -l) -gt 0 && + test $(printf "$ttt$ttt$ttt$sss" | git stripspace | wc -l) -gt 0 && + test $(printf "$ttt$sss$sss" | git stripspace | wc -l) -gt 0 && + test $(printf "$ttt$ttt$sss$sss" | git stripspace | wc -l) -gt 0 && + test $(printf "$ttt$sss$sss$sss" | git stripspace | wc -l) -gt 0 ' test_expect_success \ @@ -432,4 +432,10 @@ test_expect_success '-c with changed comment char' ' test_cmp expect actual ' +test_expect_success 'avoid SP-HT sequence in commented line' ' + printf "#\tone\n#\n# two\n" >expect && + printf "\tone\n\ntwo\n" | git stripspace -c >actual && + test_cmp expect actual +' + test_done diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh index a90c86bfa3..9be6411104 100755 --- a/t/t0040-parse-options.sh +++ b/t/t0040-parse-options.sh @@ -19,6 +19,7 @@ usage: test-parse-options <options> -i, --integer <n> get a integer -j <n> get a integer, too + -m, --magnitude <n> get a magnitude --set23 set integer to 23 -t <time> get timestamp of <time> -L, --length <str> get length of <str> @@ -58,6 +59,7 @@ mv expect expect.err cat >expect.template <<EOF boolean: 0 integer: 0 +magnitude: 0 timestamp: 0 string: (not set) abbrev: 7 @@ -132,9 +134,32 @@ test_expect_success 'OPT_BOOL() no negation #2' 'check_unknown_i18n --no-no-fear test_expect_success 'OPT_BOOL() positivation' 'check boolean: 0 -D --doubt' +test_expect_success 'OPT_INT() negative' 'check integer: -2345 -i -2345' + +test_expect_success 'OPT_MAGNITUDE() simple' ' + check magnitude: 2345678 -m 2345678 +' + +test_expect_success 'OPT_MAGNITUDE() kilo' ' + check magnitude: 239616 -m 234k +' + +test_expect_success 'OPT_MAGNITUDE() mega' ' + check magnitude: 104857600 -m 100m +' + +test_expect_success 'OPT_MAGNITUDE() giga' ' + check magnitude: 1073741824 -m 1g +' + +test_expect_success 'OPT_MAGNITUDE() 3giga' ' + check magnitude: 3221225472 -m 3g +' + cat > expect << EOF boolean: 2 integer: 1729 +magnitude: 16384 timestamp: 0 string: 123 abbrev: 7 @@ -145,8 +170,8 @@ file: prefix/my.file EOF test_expect_success 'short options' ' - test-parse-options -s123 -b -i 1729 -b -vv -n -F my.file \ - > output 2> output.err && + test-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 ' @@ -154,6 +179,7 @@ test_expect_success 'short options' ' cat > expect << EOF boolean: 2 integer: 1729 +magnitude: 16384 timestamp: 0 string: 321 abbrev: 10 @@ -164,25 +190,24 @@ file: prefix/fi.le EOF test_expect_success 'long options' ' - test-parse-options --boolean --integer 1729 --boolean --string2=321 \ - --verbose --verbose --no-dry-run --abbrev=10 --file fi.le\ - --obsolete > output 2> output.err && + test-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 && test_must_be_empty output.err && test_cmp expect output ' test_expect_success 'missing required value' ' - test-parse-options -s; - test $? = 129 && - test-parse-options --string; - test $? = 129 && - test-parse-options --file; - test $? = 129 + test_expect_code 129 test-parse-options -s && + test_expect_code 129 test-parse-options --string && + test_expect_code 129 test-parse-options --file ' cat > expect << EOF boolean: 1 integer: 13 +magnitude: 0 timestamp: 0 string: 123 abbrev: 7 @@ -205,6 +230,7 @@ test_expect_success 'intermingled arguments' ' cat > expect << EOF boolean: 0 integer: 2 +magnitude: 0 timestamp: 0 string: (not set) abbrev: 7 @@ -227,13 +253,13 @@ test_expect_success 'unambiguously abbreviated option with "="' ' ' test_expect_success 'ambiguously abbreviated option' ' - test-parse-options --strin 123; - test $? = 129 + test_expect_code 129 test-parse-options --strin 123 ' cat > expect << EOF boolean: 0 integer: 0 +magnitude: 0 timestamp: 0 string: 123 abbrev: 7 @@ -272,6 +298,7 @@ test_expect_success 'detect possible typos' ' cat > expect <<EOF boolean: 0 integer: 0 +magnitude: 0 timestamp: 0 string: (not set) abbrev: 7 @@ -291,6 +318,7 @@ test_expect_success 'keep some options as arguments' ' cat > expect <<EOF boolean: 0 integer: 0 +magnitude: 0 timestamp: 1 string: (not set) abbrev: 7 @@ -312,6 +340,7 @@ cat > expect <<EOF Callback: "four", 0 boolean: 5 integer: 4 +magnitude: 0 timestamp: 0 string: (not set) abbrev: 7 @@ -340,6 +369,7 @@ test_expect_success 'OPT_CALLBACK() and callback errors work' ' cat > expect <<EOF boolean: 1 integer: 23 +magnitude: 0 timestamp: 0 string: (not set) abbrev: 7 @@ -364,6 +394,7 @@ test_expect_success 'OPT_NEGBIT() and OPT_SET_INT() work' ' cat > expect <<EOF boolean: 6 integer: 0 +magnitude: 0 timestamp: 0 string: (not set) abbrev: 7 @@ -394,6 +425,7 @@ test_expect_success 'OPT_COUNTUP() with PARSE_OPT_NODASH works' ' cat > expect <<EOF boolean: 0 integer: 12345 +magnitude: 0 timestamp: 0 string: (not set) abbrev: 7 @@ -412,6 +444,7 @@ test_expect_success 'OPT_NUMBER_CALLBACK() works' ' cat >expect <<EOF boolean: 0 integer: 0 +magnitude: 0 timestamp: 0 string: (not set) abbrev: 7 diff --git a/t/t0050-filesystem.sh b/t/t0050-filesystem.sh index 6b3cedcf24..b29d749bb7 100755 --- a/t/t0050-filesystem.sh +++ b/t/t0050-filesystem.sh @@ -33,16 +33,20 @@ test_expect_success "detection of case insensitive filesystem during repo init" ' else test_expect_success "detection of case insensitive filesystem during repo init" ' - test_must_fail git config --bool core.ignorecase >/dev/null || - test $(git config --bool core.ignorecase) = false + { + test_must_fail git config --bool core.ignorecase >/dev/null || + test $(git config --bool core.ignorecase) = false + } ' fi if test_have_prereq SYMLINKS then test_expect_success "detection of filesystem w/o symlink support during repo init" ' - test_must_fail git config --bool core.symlinks || - test "$(git config --bool core.symlinks)" = true + { + test_must_fail git config --bool core.symlinks || + test "$(git config --bool core.symlinks)" = true + } ' else test_expect_success "detection of filesystem w/o symlink support during repo init" ' @@ -64,7 +68,7 @@ test_expect_success "setup case tests" ' git checkout -f master ' -$test_case 'rename (case change)' ' +test_expect_success 'rename (case change)' ' git mv camelcase CamelCase && git commit -m "rename" ' diff --git a/t/t0056-git-C.sh b/t/t0056-git-C.sh index 99c037703a..2630e756da 100755 --- a/t/t0056-git-C.sh +++ b/t/t0056-git-C.sh @@ -14,6 +14,16 @@ test_expect_success '"git -C <path>" runs git from the directory <path>' ' test_cmp expected actual ' +test_expect_success '"git -C <path>" with an empty <path> is a no-op' ' + ( + mkdir -p dir1/subdir && + cd dir1/subdir && + git -C "" rev-parse --show-prefix >actual && + echo subdir/ >expect && + test_cmp expect actual + ) +' + test_expect_success 'Multiple -C options: "-C dir1 -C dir2" is equivalent to "-C dir1/dir2"' ' test_create_repo dir1/dir2 && echo 1 >dir1/dir2/b.txt && diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh index c0143a0a70..f0152a7ab4 100755 --- a/t/t0060-path-utils.sh +++ b/t/t0060-path-utils.sh @@ -19,6 +19,14 @@ relative_path() { "test \"\$(test-path-utils relative_path '$1' '$2')\" = '$expected'" } +test_git_path() { + test_expect_success "git-path $1 $2 => $3" " + $1 git rev-parse --git-path $2 >actual && + echo $3 >expect && + test_cmp expect actual + " +} + # On Windows, we are using MSYS's bash, which mangles the paths. # Absolute paths are anchored at the MSYS installation directory, # which means that the path / accounts for this many characters: @@ -51,6 +59,9 @@ case $(uname -s) in ;; esac +test_expect_success basename 'test-path-utils basename' +test_expect_success dirname 'test-path-utils dirname' + norm_path "" "" norm_path . "" norm_path ./ "" @@ -244,4 +255,38 @@ relative_path "<null>" "<empty>" ./ relative_path "<null>" "<null>" ./ relative_path "<null>" /foo/a/b ./ +test_git_path A=B info/grafts .git/info/grafts +test_git_path GIT_GRAFT_FILE=foo info/grafts foo +test_git_path GIT_GRAFT_FILE=foo info/////grafts foo +test_git_path GIT_INDEX_FILE=foo index foo +test_git_path GIT_INDEX_FILE=foo index/foo .git/index/foo +test_git_path GIT_INDEX_FILE=foo index2 .git/index2 +test_expect_success 'setup fake objects directory foo' 'mkdir foo' +test_git_path GIT_OBJECT_DIRECTORY=foo objects foo +test_git_path GIT_OBJECT_DIRECTORY=foo objects/foo foo/foo +test_git_path GIT_OBJECT_DIRECTORY=foo objects2 .git/objects2 +test_expect_success 'setup common repository' 'git --git-dir=bar init' +test_git_path GIT_COMMON_DIR=bar index .git/index +test_git_path GIT_COMMON_DIR=bar HEAD .git/HEAD +test_git_path GIT_COMMON_DIR=bar logs/HEAD .git/logs/HEAD +test_git_path GIT_COMMON_DIR=bar logs/refs/bisect/foo .git/logs/refs/bisect/foo +test_git_path GIT_COMMON_DIR=bar logs/refs/bisec/foo bar/logs/refs/bisec/foo +test_git_path GIT_COMMON_DIR=bar logs/refs/bisec bar/logs/refs/bisec +test_git_path GIT_COMMON_DIR=bar logs/refs/bisectfoo bar/logs/refs/bisectfoo +test_git_path GIT_COMMON_DIR=bar objects bar/objects +test_git_path GIT_COMMON_DIR=bar objects/bar bar/objects/bar +test_git_path GIT_COMMON_DIR=bar info/exclude bar/info/exclude +test_git_path GIT_COMMON_DIR=bar info/grafts bar/info/grafts +test_git_path GIT_COMMON_DIR=bar info/sparse-checkout .git/info/sparse-checkout +test_git_path GIT_COMMON_DIR=bar info//sparse-checkout .git/info//sparse-checkout +test_git_path GIT_COMMON_DIR=bar remotes/bar bar/remotes/bar +test_git_path GIT_COMMON_DIR=bar branches/bar bar/branches/bar +test_git_path GIT_COMMON_DIR=bar logs/refs/heads/master bar/logs/refs/heads/master +test_git_path GIT_COMMON_DIR=bar refs/heads/master bar/refs/heads/master +test_git_path GIT_COMMON_DIR=bar refs/bisect/foo .git/refs/bisect/foo +test_git_path GIT_COMMON_DIR=bar hooks/me bar/hooks/me +test_git_path GIT_COMMON_DIR=bar config bar/config +test_git_path GIT_COMMON_DIR=bar packed-refs bar/packed-refs +test_git_path GIT_COMMON_DIR=bar shallow bar/shallow + test_done diff --git a/t/t0061-run-command.sh b/t/t0061-run-command.sh index 17e969df60..9acf628726 100755 --- a/t/t0061-run-command.sh +++ b/t/t0061-run-command.sh @@ -34,7 +34,7 @@ test_expect_success POSIXPERM 'run_command reports EACCES' ' grep "fatal: cannot exec.*hello.sh" err ' -test_expect_success POSIXPERM 'unreadable directory in PATH' ' +test_expect_success POSIXPERM,SANITY 'unreadable directory in PATH' ' mkdir local-command && test_when_finished "chmod u+rwx local-command && rm -fr local-command" && git config alias.nitfol "!echo frotz" && diff --git a/t/t0062-revision-walking.sh b/t/t0062-revision-walking.sh index 3d98eb847f..113c728e67 100755 --- a/t/t0062-revision-walking.sh +++ b/t/t0062-revision-walking.sh @@ -26,7 +26,7 @@ test_expect_success 'setup' ' ' test_expect_success 'revision walking can be done twice' ' - test-revision-walking run-twice > run_twice_actual + test-revision-walking run-twice >run_twice_actual && test_cmp run_twice_expected run_twice_actual ' diff --git a/t/t0064-sha1-array.sh b/t/t0064-sha1-array.sh new file mode 100755 index 0000000000..50b31ffe75 --- /dev/null +++ b/t/t0064-sha1-array.sh @@ -0,0 +1,94 @@ +#!/bin/sh + +test_description='basic tests for the SHA1 array implementation' +. ./test-lib.sh + +echo20 () { + 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" + shift + done +} + +test_expect_success 'ordered enumeration' ' + echo20 "" 44 55 88 aa >expect && + { + echo20 append 88 44 aa 55 && + echo for_each_unique + } | test-sha1-array >actual && + test_cmp expect actual +' + +test_expect_success 'ordered enumeration with duplicate suppression' ' + echo20 "" 44 55 88 aa >expect && + { + echo20 append 88 44 aa 55 && + echo20 append 88 44 aa 55 && + echo for_each_unique + } | test-sha1-array >actual && + test_cmp expect actual +' + +test_expect_success 'lookup' ' + { + echo20 append 88 44 aa 55 && + echo20 lookup 55 + } | test-sha1-array >actual && + n=$(cat actual) && + test "$n" -eq 1 +' + +test_expect_success 'lookup non-existing entry' ' + { + echo20 append 88 44 aa 55 && + echo20 lookup 33 + } | test-sha1-array >actual && + n=$(cat actual) && + test "$n" -lt 0 +' + +test_expect_success 'lookup with duplicates' ' + { + echo20 append 88 44 aa 55 && + echo20 append 88 44 aa 55 && + echo20 lookup 55 + } | test-sha1-array >actual && + n=$(cat actual) && + test "$n" -ge 2 && + test "$n" -le 3 +' + +test_expect_success 'lookup non-existing entry with duplicates' ' + { + echo20 append 88 44 aa 55 && + echo20 append 88 44 aa 55 && + echo20 lookup 66 + } | test-sha1-array >actual && + n=$(cat actual) && + test "$n" -lt 0 +' + +test_expect_success 'lookup with almost duplicate values' ' + { + echo "append 5555555555555555555555555555555555555555" && + echo "append 555555555555555555555555555555555555555f" && + echo20 lookup 55 + } | test-sha1-array >actual && + n=$(cat actual) && + test "$n" -eq 0 +' + +test_expect_success 'lookup with single duplicate value' ' + { + echo20 append 55 55 && + echo20 lookup 55 + } | test-sha1-array >actual && + n=$(cat actual) && + test "$n" -ge 0 && + test "$n" -le 1 +' + +test_done diff --git a/t/t0081-line-buffer.sh b/t/t0081-line-buffer.sh index bd83ed371a..ce92e6acad 100755 --- a/t/t0081-line-buffer.sh +++ b/t/t0081-line-buffer.sh @@ -29,7 +29,7 @@ test_expect_success '0-length read, send along greeting' ' test_cmp expect actual ' -test_expect_success 'read from file descriptor' ' +test_expect_success !MINGW 'read from file descriptor' ' rm -f input && echo hello >expect && echo hello >input && diff --git a/t/t0090-cache-tree.sh b/t/t0090-cache-tree.sh index 6c33e28ee8..adfd4f0b5e 100755 --- a/t/t0090-cache-tree.sh +++ b/t/t0090-cache-tree.sh @@ -8,7 +8,7 @@ cache-tree extension. . ./test-lib.sh cmp_cache_tree () { - test-dump-cache-tree >actual && + test-dump-cache-tree | sed -e '/#(ref)/d' >actual && sed "s/$_x40/SHA/" <actual >filtered && test_cmp "$1" filtered } @@ -16,15 +16,40 @@ cmp_cache_tree () { # We don't bother with actually checking the SHA1: # test-dump-cache-tree already verifies that all existing data is # correct. -test_shallow_cache_tree () { - printf "SHA (%d entries, 0 subtrees)\n" $(git ls-files|wc -l) >expect && +generate_expected_cache_tree_rec () { + dir="$1${1:+/}" && + parent="$2" && + # ls-files might have foo/bar, foo/bar/baz, and foo/bar/quux + # We want to count only foo because it's the only direct child + subtrees=$(git ls-files|grep /|cut -d / -f 1|uniq) && + subtree_count=$(echo "$subtrees"|awk -v c=0 '$1 != "" {++c} END {print c}') && + entries=$(git ls-files|wc -l) && + printf "SHA $dir (%d entries, %d subtrees)\n" "$entries" "$subtree_count" && + for subtree in $subtrees + do + cd "$subtree" + generate_expected_cache_tree_rec "$dir$subtree" "$dir" || return 1 + cd .. + done && + dir=$parent +} + +generate_expected_cache_tree () { + ( + generate_expected_cache_tree_rec + ) +} + +test_cache_tree () { + generate_expected_cache_tree >expect && cmp_cache_tree expect } test_invalid_cache_tree () { - echo "invalid (0 subtrees)" >expect && - printf "SHA #(ref) (%d entries, 0 subtrees)\n" $(git ls-files|wc -l) >>expect && - cmp_cache_tree expect + printf "invalid %s ()\n" "" "$@" >expect && + test-dump-cache-tree | + sed -n -e "s/[0-9]* subtrees//" -e '/#(ref)/d' -e '/^invalid /p' >actual && + test_cmp expect actual } test_no_cache_tree () { @@ -32,26 +57,59 @@ test_no_cache_tree () { cmp_cache_tree expect } -test_expect_failure 'initial commit has cache-tree' ' +test_expect_success 'initial commit has cache-tree' ' test_commit foo && - test_shallow_cache_tree + test_cache_tree ' test_expect_success 'read-tree HEAD establishes cache-tree' ' git read-tree HEAD && - test_shallow_cache_tree + test_cache_tree ' test_expect_success 'git-add invalidates cache-tree' ' test_when_finished "git reset --hard; git read-tree HEAD" && - echo "I changed this file" > foo && + echo "I changed this file" >foo && git add foo && test_invalid_cache_tree ' +test_expect_success 'git-add in subdir invalidates cache-tree' ' + test_when_finished "git reset --hard; git read-tree HEAD" && + mkdir dirx && + echo "I changed this file" >dirx/foo && + git add dirx/foo && + test_invalid_cache_tree +' + +cat >before <<\EOF +SHA (3 entries, 2 subtrees) +SHA dir1/ (1 entries, 0 subtrees) +SHA dir2/ (1 entries, 0 subtrees) +EOF + +cat >expect <<\EOF +invalid (2 subtrees) +invalid dir1/ (0 subtrees) +SHA dir2/ (1 entries, 0 subtrees) +EOF + +test_expect_success 'git-add in subdir does not invalidate sibling cache-tree' ' + git tag no-children && + test_when_finished "git reset --hard no-children; git read-tree HEAD" && + mkdir dir1 dir2 && + test_commit dir1/a && + test_commit dir2/b && + echo "I changed this file" >dir1/a && + cmp_cache_tree before && + echo "I changed this file" >dir1/a && + git add dir1/a && + cmp_cache_tree expect +' + test_expect_success 'update-index invalidates cache-tree' ' test_when_finished "git reset --hard; git read-tree HEAD" && - echo "I changed this file" > foo && + echo "I changed this file" >foo && git update-index --add foo && test_invalid_cache_tree ' @@ -59,7 +117,7 @@ test_expect_success 'update-index invalidates cache-tree' ' test_expect_success 'write-tree establishes cache-tree' ' test-scrap-cache-tree && git write-tree && - test_shallow_cache_tree + test_cache_tree ' test_expect_success 'test-scrap-cache-tree works' ' @@ -70,24 +128,128 @@ test_expect_success 'test-scrap-cache-tree works' ' test_expect_success 'second commit has cache-tree' ' test_commit bar && - test_shallow_cache_tree + test_cache_tree +' + +test_expect_success PERL 'commit --interactive gives cache-tree on partial commit' ' + cat <<-\EOT >foo.c && + int foo() + { + return 42; + } + int bar() + { + return 42; + } + EOT + git add foo.c && + test_invalid_cache_tree && + git commit -m "add a file" && + test_cache_tree && + cat <<-\EOT >foo.c && + int foo() + { + return 43; + } + int bar() + { + return 44; + } + EOT + (echo p; echo 1; echo; echo s; echo n; echo y; echo q) | + git commit --interactive -m foo && + test_cache_tree +' + +test_expect_success 'commit in child dir has cache-tree' ' + mkdir dir && + >dir/child.t && + git add dir/child.t && + git commit -m dir/child.t && + test_cache_tree ' test_expect_success 'reset --hard gives cache-tree' ' test-scrap-cache-tree && git reset --hard && - test_shallow_cache_tree + test_cache_tree ' test_expect_success 'reset --hard without index gives cache-tree' ' rm -f .git/index && git reset --hard && - test_shallow_cache_tree + test_cache_tree ' -test_expect_failure 'checkout gives cache-tree' ' +test_expect_success 'checkout gives cache-tree' ' + git tag current && git checkout HEAD^ && - test_shallow_cache_tree + test_cache_tree +' + +test_expect_success 'checkout -b gives cache-tree' ' + git checkout current && + git checkout -b prev HEAD^ && + test_cache_tree +' + +test_expect_success 'checkout -B gives cache-tree' ' + git checkout current && + git checkout -B prev HEAD^ && + test_cache_tree +' + +test_expect_success 'merge --ff-only maintains cache-tree' ' + git checkout current && + git checkout -b changes && + test_commit llamas && + test_commit pachyderm && + test_cache_tree && + git checkout current && + test_cache_tree && + git merge --ff-only changes && + test_cache_tree +' + +test_expect_success 'merge maintains cache-tree' ' + git checkout current && + git checkout -b changes2 && + test_commit alpacas && + test_cache_tree && + git checkout current && + test_commit struthio && + test_cache_tree && + git merge changes2 && + test_cache_tree +' + +test_expect_success 'partial commit gives cache-tree' ' + git checkout -b partial no-children && + test_commit one && + test_commit two && + echo "some change" >one.t && + git add one.t && + echo "some other change" >two.t && + git commit two.t -m partial && + test_cache_tree +' + +test_expect_success 'no phantom error when switching trees' ' + mkdir newdir && + >newdir/one && + git add newdir/one && + git checkout 2>errors && + ! test -s errors +' + +test_expect_success 'switching trees does not invalidate shared index' ' + git update-index --split-index && + >split && + git add split && + test-dump-split-index .git/index | grep -v ^own >before && + git commit -m "as-is" && + test-dump-split-index .git/index | grep -v ^own >after && + test_cmp before after ' test_done diff --git a/t/t0110-urlmatch-normalization.sh b/t/t0110-urlmatch-normalization.sh index 8d6096d4d1..410d5768ca 100755 --- a/t/t0110-urlmatch-normalization.sh +++ b/t/t0110-urlmatch-normalization.sh @@ -117,7 +117,7 @@ test_expect_success 'url general escapes' ' test "$(test-urlmatch-normalization -p "X://W?'\!'")" = "x://w/?'\!'" ' -test_expect_success 'url high-bit escapes' ' +test_expect_success !MINGW 'url high-bit escapes' ' test "$(test-urlmatch-normalization -p "$(cat "$tu-1")")" = "x://q/%01%02%03%04%05%06%07%08%0E%0F%10%11%12" && test "$(test-urlmatch-normalization -p "$(cat "$tu-2")")" = "x://q/%13%14%15%16%17%18%19%1B%1C%1D%1E%1F%7F" && test "$(test-urlmatch-normalization -p "$(cat "$tu-3")")" = "x://q/%80%81%82%83%84%85%86%87%88%89%8A%8B%8C%8D%8E%8F" && @@ -127,7 +127,10 @@ test_expect_success 'url high-bit escapes' ' test "$(test-urlmatch-normalization -p "$(cat "$tu-7")")" = "x://q/%C0%C1%C2%C3%C4%C5%C6%C7%C8%C9%CA%CB%CC%CD%CE%CF" && test "$(test-urlmatch-normalization -p "$(cat "$tu-8")")" = "x://q/%D0%D1%D2%D3%D4%D5%D6%D7%D8%D9%DA%DB%DC%DD%DE%DF" && test "$(test-urlmatch-normalization -p "$(cat "$tu-9")")" = "x://q/%E0%E1%E2%E3%E4%E5%E6%E7%E8%E9%EA%EB%EC%ED%EE%EF" && - test "$(test-urlmatch-normalization -p "$(cat "$tu-10")")" = "x://q/%F0%F1%F2%F3%F4%F5%F6%F7%F8%F9%FA%FB%FC%FD%FE%FF" && + test "$(test-urlmatch-normalization -p "$(cat "$tu-10")")" = "x://q/%F0%F1%F2%F3%F4%F5%F6%F7%F8%F9%FA%FB%FC%FD%FE%FF" +' + +test_expect_success 'url utf-8 escapes' ' test "$(test-urlmatch-normalization -p "$(cat "$tu-11")")" = "x://q/%C2%80%DF%BF%E0%A0%80%EF%BF%BD%F0%90%80%80%F0%AF%BF%BD" ' diff --git a/t/t0201-gettext-fallbacks.sh b/t/t0201-gettext-fallbacks.sh index 5d80a985fb..90da1c7ddc 100755 --- a/t/t0201-gettext-fallbacks.sh +++ b/t/t0201-gettext-fallbacks.sh @@ -50,17 +50,17 @@ test_expect_success 'eval_gettext: our eval_gettext() fallback can interpolate v test_expect_success 'eval_gettext: our eval_gettext() fallback can interpolate variables with spaces' ' cmdline="git am" && - export cmdline; + export cmdline && printf "When you have resolved this problem, run git am --resolved." >expect && - eval_gettext "When you have resolved this problem, run \$cmdline --resolved." >actual + eval_gettext "When you have resolved this problem, run \$cmdline --resolved." >actual && test_i18ncmp expect actual ' test_expect_success 'eval_gettext: our eval_gettext() fallback can interpolate variables with spaces and quotes' ' cmdline="git am" && - export cmdline; + export cmdline && printf "When you have resolved this problem, run \"git am --resolved\"." >expect && - eval_gettext "When you have resolved this problem, run \"\$cmdline --resolved\"." >actual + eval_gettext "When you have resolved this problem, run \"\$cmdline --resolved\"." >actual && test_i18ncmp expect actual ' diff --git a/t/t0300-credentials.sh b/t/t0300-credentials.sh index 538ea5fb1c..d7ef44b4a2 100755 --- a/t/t0300-credentials.sh +++ b/t/t0300-credentials.sh @@ -6,7 +6,7 @@ test_description='basic credential helper tests' test_expect_success 'setup helper scripts' ' cat >dump <<-\EOF && - whoami=`echo $0 | sed s/.*git-credential-//` + whoami=$(echo $0 | sed s/.*git-credential-//) echo >&2 "$whoami: $*" OIFS=$IFS IFS== @@ -289,4 +289,13 @@ test_expect_success 'http paths can be part of context' ' EOF ' +test_expect_success 'helpers can abort the process' ' + test_must_fail git \ + -c credential.helper="!f() { echo quit=1; }; f" \ + -c credential.helper="verbatim foo bar" \ + credential fill >stdout && + >expect && + test_cmp expect stdout +' + test_done diff --git a/t/t0302-credential-store.sh b/t/t0302-credential-store.sh index f61b40c69b..1d8d1f210b 100755 --- a/t/t0302-credential-store.sh +++ b/t/t0302-credential-store.sh @@ -6,4 +6,118 @@ test_description='credential-store tests' helper_test store +test_expect_success 'when xdg file does not exist, xdg file not created' ' + test_path_is_missing "$HOME/.config/git/credentials" && + test -s "$HOME/.git-credentials" +' + +test_expect_success 'setup xdg file' ' + rm -f "$HOME/.git-credentials" && + mkdir -p "$HOME/.config/git" && + >"$HOME/.config/git/credentials" +' + +helper_test store + +test_expect_success 'when xdg file exists, home file not created' ' + test -s "$HOME/.config/git/credentials" && + test_path_is_missing "$HOME/.git-credentials" +' + +test_expect_success 'setup custom xdg file' ' + rm -f "$HOME/.git-credentials" && + rm -f "$HOME/.config/git/credentials" && + mkdir -p "$HOME/xdg/git" && + >"$HOME/xdg/git/credentials" +' + +XDG_CONFIG_HOME="$HOME/xdg" +export XDG_CONFIG_HOME +helper_test store +unset XDG_CONFIG_HOME + +test_expect_success 'if custom xdg file exists, home and xdg files not created' ' + test_when_finished "rm -f $HOME/xdg/git/credentials" && + test -s "$HOME/xdg/git/credentials" && + test_path_is_missing "$HOME/.git-credentials" && + test_path_is_missing "$HOME/.config/git/credentials" +' + +test_expect_success 'get: use home file if both home and xdg files have matches' ' + echo "https://home-user:home-pass@example.com" >"$HOME/.git-credentials" && + mkdir -p "$HOME/.config/git" && + echo "https://xdg-user:xdg-pass@example.com" >"$HOME/.config/git/credentials" && + check fill store <<-\EOF + protocol=https + host=example.com + -- + protocol=https + host=example.com + username=home-user + password=home-pass + -- + EOF +' + +test_expect_success 'get: use xdg file if home file has no matches' ' + >"$HOME/.git-credentials" && + mkdir -p "$HOME/.config/git" && + echo "https://xdg-user:xdg-pass@example.com" >"$HOME/.config/git/credentials" && + check fill store <<-\EOF + protocol=https + host=example.com + -- + protocol=https + host=example.com + username=xdg-user + password=xdg-pass + -- + EOF +' + +test_expect_success POSIXPERM,SANITY 'get: use xdg file if home file is unreadable' ' + echo "https://home-user:home-pass@example.com" >"$HOME/.git-credentials" && + chmod -r "$HOME/.git-credentials" && + mkdir -p "$HOME/.config/git" && + echo "https://xdg-user:xdg-pass@example.com" >"$HOME/.config/git/credentials" && + check fill store <<-\EOF + protocol=https + host=example.com + -- + protocol=https + host=example.com + username=xdg-user + password=xdg-pass + -- + EOF +' + +test_expect_success 'store: if both xdg and home files exist, only store in home file' ' + >"$HOME/.git-credentials" && + mkdir -p "$HOME/.config/git" && + >"$HOME/.config/git/credentials" && + check approve store <<-\EOF && + protocol=https + host=example.com + username=store-user + password=store-pass + EOF + echo "https://store-user:store-pass@example.com" >expected && + test_cmp expected "$HOME/.git-credentials" && + test_must_be_empty "$HOME/.config/git/credentials" +' + + +test_expect_success 'erase: erase matching credentials from both xdg and home files' ' + echo "https://home-user:home-pass@example.com" >"$HOME/.git-credentials" && + mkdir -p "$HOME/.config/git" && + echo "https://xdg-user:xdg-pass@example.com" >"$HOME/.config/git/credentials" && + check reject store <<-\EOF && + protocol=https + host=example.com + EOF + test_must_be_empty "$HOME/.git-credentials" && + test_must_be_empty "$HOME/.config/git/credentials" +' + test_done diff --git a/t/t1000-read-tree-m-3way.sh b/t/t1000-read-tree-m-3way.sh index babcdd2343..a0b79b4839 100755 --- a/t/t1000-read-tree-m-3way.sh +++ b/t/t1000-read-tree-m-3way.sh @@ -519,10 +519,10 @@ test_expect_success \ 'rm -f .git/index F16 && echo F16 >F16 && git update-index --add F16 && - tree0=`git write-tree` && + tree0=$(git write-tree) && echo E16 >F16 && git update-index F16 && - tree1=`git write-tree` && + tree1=$(git write-tree) && read_tree_must_succeed -m $tree0 $tree1 $tree1 $tree0 && git ls-files --stage' diff --git a/t/t1001-read-tree-m-2way.sh b/t/t1001-read-tree-m-2way.sh index 3a24abf549..db1b6f5cf4 100755 --- a/t/t1001-read-tree-m-2way.sh +++ b/t/t1001-read-tree-m-2way.sh @@ -36,7 +36,7 @@ compare_change () { } check_cache_at () { - clean_if_empty=`git diff-files -- "$1"` + clean_if_empty=$(git diff-files -- "$1") case "$clean_if_empty" in '') echo "$1: clean" ;; ?*) echo "$1: dirty" ;; @@ -68,14 +68,14 @@ test_expect_success \ echo rezrov >rezrov && echo yomin >yomin && git update-index --add nitfol bozbar rezrov && - treeH=`git write-tree` && + treeH=$(git write-tree) && echo treeH $treeH && git ls-tree $treeH && cat bozbar-new >bozbar && git update-index --add frotz bozbar --force-remove rezrov && git ls-files --stage >M.out && - treeM=`git write-tree` && + treeM=$(git write-tree) && echo treeM $treeM && git ls-tree $treeM && git diff-tree $treeH $treeM' @@ -315,7 +315,7 @@ test_expect_success \ 'rm -f .git/index && echo DF >DF && git update-index --add DF && - treeDF=`git write-tree` && + treeDF=$(git write-tree) && echo treeDF $treeDF && git ls-tree $treeDF && @@ -323,7 +323,7 @@ test_expect_success \ mkdir DF && echo DF/DF >DF/DF && git update-index --add --remove DF DF/DF && - treeDFDF=`git write-tree` && + treeDFDF=$(git write-tree) && echo treeDFDF $treeDFDF && git ls-tree $treeDFDF && git ls-files --stage >DFDF.out' @@ -345,7 +345,7 @@ test_expect_success \ 'rm -f .git/index && : >a && git update-index --add a && - treeM=`git write-tree` && + treeM=$(git write-tree) && echo treeM $treeM && git ls-tree $treeM && git ls-files --stage >treeM.out && @@ -354,7 +354,7 @@ test_expect_success \ git update-index --remove a && mkdir a && : >a/b && - treeH=`git write-tree` && + treeH=$(git write-tree) && echo treeH $treeH && git ls-tree $treeH' @@ -372,7 +372,7 @@ test_expect_success \ mkdir c && : >c/d && git update-index --add a c/d && - treeM=`git write-tree` && + treeM=$(git write-tree) && echo treeM $treeM && git ls-tree $treeM && git ls-files --stage >treeM.out && @@ -381,7 +381,7 @@ test_expect_success \ mkdir a && : >a/b && git update-index --add --remove a a/b && - treeH=`git write-tree` && + treeH=$(git write-tree) && echo treeH $treeH && git ls-tree $treeH' diff --git a/t/t1002-read-tree-m-u-2way.sh b/t/t1002-read-tree-m-u-2way.sh index a847709a13..e3bf821694 100755 --- a/t/t1002-read-tree-m-u-2way.sh +++ b/t/t1002-read-tree-m-u-2way.sh @@ -21,7 +21,7 @@ compare_change () { } check_cache_at () { - clean_if_empty=`git diff-files -- "$1"` + clean_if_empty=$(git diff-files -- "$1") case "$clean_if_empty" in '') echo "$1: clean" ;; ?*) echo "$1: dirty" ;; @@ -41,14 +41,14 @@ test_expect_success \ echo bozbar >bozbar && echo rezrov >rezrov && git update-index --add nitfol bozbar rezrov && - treeH=`git write-tree` && + treeH=$(git write-tree) && echo treeH $treeH && git ls-tree $treeH && echo gnusto >bozbar && git update-index --add frotz bozbar --force-remove rezrov && git ls-files --stage >M.out && - treeM=`git write-tree` && + treeM=$(git write-tree) && echo treeM $treeM && git ls-tree $treeM && sum bozbar frotz nitfol >M.sum && @@ -75,8 +75,8 @@ test_expect_success \ echo yomin >yomin && git update-index --add yomin && read_tree_u_must_succeed -m -u $treeH $treeM && - git ls-files --stage >4.out || return 1 - git diff -U0 --no-index M.out 4.out >4diff.out + git ls-files --stage >4.out && + test_might_fail git diff -U0 --no-index M.out 4.out >4diff.out && compare_change 4diff.out expected && check_cache_at yomin clean && sum bozbar frotz nitfol >actual4.sum && @@ -94,8 +94,8 @@ test_expect_success \ git update-index --add yomin && echo yomin yomin >yomin && read_tree_u_must_succeed -m -u $treeH $treeM && - git ls-files --stage >5.out || return 1 - git diff -U0 --no-index M.out 5.out >5diff.out + git ls-files --stage >5.out && + test_might_fail git diff -U0 --no-index M.out 5.out >5diff.out && compare_change 5diff.out expected && check_cache_at yomin dirty && sum bozbar frotz nitfol >actual5.sum && @@ -318,7 +318,7 @@ test_expect_success \ 'rm -f .git/index && echo DF >DF && git update-index --add DF && - treeDF=`git write-tree` && + treeDF=$(git write-tree) && echo treeDF $treeDF && git ls-tree $treeDF && @@ -326,7 +326,7 @@ test_expect_success \ mkdir DF && echo DF/DF >DF/DF && git update-index --add --remove DF DF/DF && - treeDFDF=`git write-tree` && + treeDFDF=$(git write-tree) && echo treeDFDF $treeDFDF && git ls-tree $treeDFDF && git ls-files --stage >DFDF.out' diff --git a/t/t1003-read-tree-prefix.sh b/t/t1003-read-tree-prefix.sh index 8c6d67edda..b6111cd150 100755 --- a/t/t1003-read-tree-prefix.sh +++ b/t/t1003-read-tree-prefix.sh @@ -11,7 +11,7 @@ test_description='git read-tree --prefix test. test_expect_success setup ' echo hello >one && git update-index --add one && - tree=`git write-tree` && + tree=$(git write-tree) && echo tree is $tree ' diff --git a/t/t1004-read-tree-m-u-wf.sh b/t/t1004-read-tree-m-u-wf.sh index 3e72aff470..c70cf42300 100755 --- a/t/t1004-read-tree-m-u-wf.sh +++ b/t/t1004-read-tree-m-u-wf.sh @@ -30,7 +30,7 @@ test_expect_success 'two-way not clobbering' ' echo >file2 master creates untracked file2 && echo >subdir/file2 master creates untracked subdir/file2 && - if err=`read_tree_u_must_succeed -m -u master side 2>&1` + if err=$(read_tree_u_must_succeed -m -u master side 2>&1) then echo should have complained false @@ -43,7 +43,7 @@ echo file2 >.gitignore test_expect_success 'two-way with incorrect --exclude-per-directory (1)' ' - if err=`read_tree_u_must_succeed -m --exclude-per-directory=.gitignore master side 2>&1` + if err=$(read_tree_u_must_succeed -m --exclude-per-directory=.gitignore master side 2>&1) then echo should have complained false @@ -54,7 +54,7 @@ test_expect_success 'two-way with incorrect --exclude-per-directory (1)' ' test_expect_success 'two-way with incorrect --exclude-per-directory (2)' ' - if err=`read_tree_u_must_succeed -m -u --exclude-per-directory=foo --exclude-per-directory=.gitignore master side 2>&1` + if err=$(read_tree_u_must_succeed -m -u --exclude-per-directory=foo --exclude-per-directory=.gitignore master side 2>&1) then echo should have complained false @@ -95,7 +95,7 @@ test_expect_success 'three-way not clobbering a working tree file' ' git checkout master && echo >file3 file three created in master, untracked && echo >subdir/file3 file three created in master, untracked && - if err=`read_tree_u_must_succeed -m -u branch-point master side 2>&1` + if err=$(read_tree_u_must_succeed -m -u branch-point master side 2>&1) then echo should have complained false diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh index a72e700ae4..4f38078ff3 100755 --- a/t/t1006-cat-file.sh +++ b/t/t1006-cat-file.sh @@ -47,6 +47,18 @@ $content" test_cmp expect actual ' + test_expect_success "Type of $type is correct using --allow-unknown-type" ' + echo $type >expect && + git cat-file -t --allow-unknown-type $sha1 >actual && + test_cmp expect actual + ' + + test_expect_success "Size of $type is correct using --allow-unknown-type" ' + echo $size >expect && + git cat-file -s --allow-unknown-type $sha1 >actual && + test_cmp expect actual + ' + test -z "$content" || test_expect_success "Content of $type is correct" ' maybe_remove_timestamp "$content" $no_ts >expect && @@ -189,6 +201,13 @@ do ' done +for opt in t s e p +do + test_expect_success "Passing -$opt with --follow-symlinks fails" ' + test_must_fail git cat-file --follow-symlinks -$opt $hello_sha1 + ' +done + test_expect_success "--batch-check for a non-existent named object" ' test "foobar42 missing foobar84 missing" = \ @@ -274,7 +293,7 @@ test_expect_success 'setup blobs which are likely to delta' ' ' test_expect_success 'confirm that neither loose blob is a delta' ' - cat >expect <<-EOF + cat >expect <<-EOF && $_z40 $_z40 EOF @@ -296,4 +315,262 @@ test_expect_success '%(deltabase) reports packed delta bases' ' } ' +bogus_type="bogus" +bogus_content="bogus" +bogus_size=$(strlen "$bogus_content") +bogus_sha1=$(echo_without_newline "$bogus_content" | git hash-object -t $bogus_type --literally -w --stdin) + +test_expect_success "Type of broken object is correct" ' + echo $bogus_type >expect && + git cat-file -t --allow-unknown-type $bogus_sha1 >actual && + test_cmp expect actual +' + +test_expect_success "Size of broken object is correct" ' + echo $bogus_size >expect && + git cat-file -s --allow-unknown-type $bogus_sha1 >actual && + test_cmp expect actual +' +bogus_type="abcdefghijklmnopqrstuvwxyz1234679" +bogus_content="bogus" +bogus_size=$(strlen "$bogus_content") +bogus_sha1=$(echo_without_newline "$bogus_content" | git hash-object -t $bogus_type --literally -w --stdin) + +test_expect_success "Type of broken object is correct when type is large" ' + echo $bogus_type >expect && + git cat-file -t --allow-unknown-type $bogus_sha1 >actual && + test_cmp expect actual +' + +test_expect_success "Size of large broken object is correct when type is large" ' + echo $bogus_size >expect && + git cat-file -s --allow-unknown-type $bogus_sha1 >actual && + test_cmp expect actual +' + +# Tests for git cat-file --follow-symlinks +test_expect_success 'prep for symlink tests' ' + echo_without_newline "$hello_content" >morx && + test_ln_s_add morx same-dir-link && + test_ln_s_add dir link-to-dir && + test_ln_s_add ../fleem out-of-repo-link && + test_ln_s_add .. out-of-repo-link-dir && + test_ln_s_add same-dir-link link-to-link && + test_ln_s_add nope broken-same-dir-link && + mkdir dir && + test_ln_s_add ../morx dir/parent-dir-link && + test_ln_s_add .. dir/link-dir && + test_ln_s_add ../../escape dir/out-of-repo-link && + test_ln_s_add ../.. dir/out-of-repo-link-dir && + test_ln_s_add nope dir/broken-link-in-dir && + mkdir dir/subdir && + test_ln_s_add ../../morx dir/subdir/grandparent-dir-link && + test_ln_s_add ../../../great-escape dir/subdir/out-of-repo-link && + test_ln_s_add ../../.. dir/subdir/out-of-repo-link-dir && + test_ln_s_add ../../../ dir/subdir/out-of-repo-link-dir-trailing && + test_ln_s_add ../parent-dir-link dir/subdir/parent-dir-link-to-link && + echo_without_newline "$hello_content" >dir/subdir/ind2 && + echo_without_newline "$hello_content" >dir/ind1 && + test_ln_s_add dir dirlink && + test_ln_s_add dir/subdir subdirlink && + test_ln_s_add subdir/ind2 dir/link-to-child && + test_ln_s_add dir/link-to-child link-to-down-link && + test_ln_s_add dir/.. up-down && + test_ln_s_add dir/../ up-down-trailing && + test_ln_s_add dir/../morx up-down-file && + test_ln_s_add dir/../../morx up-up-down-file && + test_ln_s_add subdirlink/../../morx up-two-down-file && + test_ln_s_add loop1 loop2 && + test_ln_s_add loop2 loop1 && + git add morx dir/subdir/ind2 dir/ind1 && + git commit -am "test" && + echo $hello_sha1 blob $hello_size >found +' + +test_expect_success 'git cat-file --batch-check --follow-symlinks works for non-links' ' + echo HEAD:morx | git cat-file --batch-check --follow-symlinks >actual && + test_cmp found actual && + echo HEAD:nope missing >expect && + echo HEAD:nope | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual +' + +test_expect_success 'git cat-file --batch-check --follow-symlinks works for in-repo, same-dir links' ' + echo HEAD:same-dir-link | git cat-file --batch-check --follow-symlinks >actual && + test_cmp found actual +' + +test_expect_success 'git cat-file --batch-check --follow-symlinks works for in-repo, links to dirs' ' + echo HEAD:link-to-dir/ind1 | git cat-file --batch-check --follow-symlinks >actual && + test_cmp found actual +' + + +test_expect_success 'git cat-file --batch-check --follow-symlinks works for broken in-repo, same-dir links' ' + echo dangling 25 >expect && + echo HEAD:broken-same-dir-link >>expect && + echo HEAD:broken-same-dir-link | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual +' + +test_expect_success 'git cat-file --batch-check --follow-symlinks works for same-dir links-to-links' ' + echo HEAD:link-to-link | git cat-file --batch-check --follow-symlinks >actual && + test_cmp found actual +' + +test_expect_success 'git cat-file --batch-check --follow-symlinks works for parent-dir links' ' + echo HEAD:dir/parent-dir-link | git cat-file --batch-check --follow-symlinks >actual && + test_cmp found actual && + echo notdir 29 >expect && + echo HEAD:dir/parent-dir-link/nope >>expect && + echo HEAD:dir/parent-dir-link/nope | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual +' + +test_expect_success 'git cat-file --batch-check --follow-symlinks works for .. links' ' + echo dangling 22 >expect && + echo HEAD:dir/link-dir/nope >>expect && + echo HEAD:dir/link-dir/nope | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual && + echo HEAD:dir/link-dir/morx | git cat-file --batch-check --follow-symlinks >actual && + test_cmp found actual && + echo dangling 27 >expect && + echo HEAD:dir/broken-link-in-dir >>expect && + echo HEAD:dir/broken-link-in-dir | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual +' + +test_expect_success 'git cat-file --batch-check --follow-symlinks works for ../.. links' ' + echo notdir 41 >expect && + echo HEAD:dir/subdir/grandparent-dir-link/nope >>expect && + echo HEAD:dir/subdir/grandparent-dir-link/nope | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual && + echo HEAD:dir/subdir/grandparent-dir-link | git cat-file --batch-check --follow-symlinks >actual && + test_cmp found actual && + echo HEAD:dir/subdir/parent-dir-link-to-link | git cat-file --batch-check --follow-symlinks >actual && + test_cmp found actual +' + +test_expect_success 'git cat-file --batch-check --follow-symlinks works for dir/ links' ' + echo dangling 17 >expect && + echo HEAD:dirlink/morx >>expect && + echo HEAD:dirlink/morx | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual && + echo $hello_sha1 blob $hello_size >expect && + echo HEAD:dirlink/ind1 | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual +' + +test_expect_success 'git cat-file --batch-check --follow-symlinks works for dir/subdir links' ' + echo dangling 20 >expect && + echo HEAD:subdirlink/morx >>expect && + echo HEAD:subdirlink/morx | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual && + echo HEAD:subdirlink/ind2 | git cat-file --batch-check --follow-symlinks >actual && + test_cmp found actual +' + +test_expect_success 'git cat-file --batch-check --follow-symlinks works for dir ->subdir links' ' + echo notdir 27 >expect && + echo HEAD:dir/link-to-child/morx >>expect && + echo HEAD:dir/link-to-child/morx | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual && + echo HEAD:dir/link-to-child | git cat-file --batch-check --follow-symlinks >actual && + test_cmp found actual && + echo HEAD:link-to-down-link | git cat-file --batch-check --follow-symlinks >actual && + test_cmp found actual +' + +test_expect_success 'git cat-file --batch-check --follow-symlinks works for out-of-repo symlinks' ' + echo symlink 8 >expect && + echo ../fleem >>expect && + echo HEAD:out-of-repo-link | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual && + echo symlink 2 >expect && + echo .. >>expect && + echo HEAD:out-of-repo-link-dir | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual +' + +test_expect_success 'git cat-file --batch-check --follow-symlinks works for out-of-repo symlinks in dirs' ' + echo symlink 9 >expect && + echo ../escape >>expect && + echo HEAD:dir/out-of-repo-link | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual && + echo symlink 2 >expect && + echo .. >>expect && + echo HEAD:dir/out-of-repo-link-dir | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual +' + +test_expect_success 'git cat-file --batch-check --follow-symlinks works for out-of-repo symlinks in subdirs' ' + echo symlink 15 >expect && + echo ../great-escape >>expect && + echo HEAD:dir/subdir/out-of-repo-link | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual && + echo symlink 2 >expect && + echo .. >>expect && + echo HEAD:dir/subdir/out-of-repo-link-dir | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual && + echo symlink 3 >expect && + echo ../ >>expect && + echo HEAD:dir/subdir/out-of-repo-link-dir-trailing | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual +' + +test_expect_success 'git cat-file --batch-check --follow-symlinks works for symlinks with internal ..' ' + echo HEAD: | git cat-file --batch-check >expect && + echo HEAD:up-down | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual && + echo HEAD:up-down-trailing | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual && + echo HEAD:up-down-file | git cat-file --batch-check --follow-symlinks >actual && + test_cmp found actual && + echo symlink 7 >expect && + echo ../morx >>expect && + echo HEAD:up-up-down-file | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual && + echo HEAD:up-two-down-file | git cat-file --batch-check --follow-symlinks >actual && + test_cmp found actual +' + +test_expect_success 'git cat-file --batch-check --follow-symlink breaks loops' ' + echo loop 10 >expect && + echo HEAD:loop1 >>expect && + echo HEAD:loop1 | git cat-file --batch-check --follow-symlinks >actual && + test_cmp expect actual +' + +test_expect_success 'git cat-file --batch --follow-symlink returns correct sha and mode' ' + echo HEAD:morx | git cat-file --batch >expect && + echo HEAD:morx | git cat-file --batch --follow-symlinks >actual && + test_cmp expect actual +' + +test_expect_success 'cat-file --batch-all-objects shows all objects' ' + # make new repos so we know the full set of objects; we will + # also make sure that there are some packed and some loose + # objects, some referenced and some not, and that there are + # some available only via alternates. + git init all-one && + ( + cd all-one && + echo content >file && + git add file && + git commit -qm base && + git rev-parse HEAD HEAD^{tree} HEAD:file && + git repack -ad && + echo not-cloned | git hash-object -w --stdin + ) >expect.unsorted && + git clone -s all-one all-two && + ( + cd all-two && + echo local-unref | git hash-object -w --stdin + ) >>expect.unsorted && + sort <expect.unsorted >expect && + git -C all-two cat-file --batch-all-objects \ + --batch-check="%(objectname)" >actual && + test_cmp expect actual +' + test_done diff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh index f83df8eb8b..7d2baa15bb 100755 --- a/t/t1007-hash-object.sh +++ b/t/t1007-hash-object.sh @@ -201,4 +201,23 @@ test_expect_success 'corrupt tag' ' test_must_fail git hash-object -t tag --stdin </dev/null ' +test_expect_success 'hash-object complains about bogus type name' ' + test_must_fail git hash-object -t bogus --stdin </dev/null +' + +test_expect_success 'hash-object complains about truncated type name' ' + test_must_fail git hash-object -t bl --stdin </dev/null +' + +test_expect_success '--literally' ' + t=1234567890 && + echo example | git hash-object -t $t --literally --stdin +' + +test_expect_success '--literally with extra-long type' ' + t=12345678901234567890123456789012345678901234567890 && + t="$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t" && + echo example | git hash-object -t $t --literally --stdin +' + test_done diff --git a/t/t1013-read-tree-submodule.sh b/t/t1013-read-tree-submodule.sh new file mode 100755 index 0000000000..20526aed34 --- /dev/null +++ b/t/t1013-read-tree-submodule.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +test_description='read-tree can handle submodules' + +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-submodule-update.sh + +test_submodule_switch "git read-tree -u -m" + +test_submodule_forced_switch "git read-tree -u --reset" + +test_done diff --git a/t/t1020-subdirectory.sh b/t/t1020-subdirectory.sh index 6902320e81..8e22b03cdd 100755 --- a/t/t1020-subdirectory.sh +++ b/t/t1020-subdirectory.sh @@ -20,27 +20,27 @@ test_expect_success setup ' test_expect_success 'update-index and ls-files' ' git update-index --add one && - case "`git ls-files`" in + case "$(git ls-files)" in one) echo pass one ;; *) echo bad one; exit 1 ;; esac && ( cd dir && git update-index --add two && - case "`git ls-files`" in + case "$(git ls-files)" in two) echo pass two ;; *) echo bad two; exit 1 ;; esac ) && - case "`git ls-files`" in + case "$(git ls-files)" in dir/two"$LF"one) echo pass both ;; *) echo bad; exit 1 ;; esac ' test_expect_success 'cat-file' ' - two=`git ls-files -s dir/two` && - two=`expr "$two" : "[0-7]* \\([0-9a-f]*\\)"` && + two=$(git ls-files -s dir/two) && + two=$(expr "$two" : "[0-7]* \\([0-9a-f]*\\)") && echo "$two" && git cat-file -p "$two" >actual && cmp dir/two actual && @@ -55,18 +55,18 @@ rm -f actual dir/actual test_expect_success 'diff-files' ' echo a >>one && echo d >>dir/two && - case "`git diff-files --name-only`" in + case "$(git diff-files --name-only)" in dir/two"$LF"one) echo pass top ;; *) echo bad top; exit 1 ;; esac && # diff should not omit leading paths ( cd dir && - case "`git diff-files --name-only`" in + case "$(git diff-files --name-only)" in dir/two"$LF"one) echo pass subdir ;; *) echo bad subdir; exit 1 ;; esac && - case "`git diff-files --name-only .`" in + case "$(git diff-files --name-only .)" in dir/two) echo pass subdir limited ;; *) echo bad subdir limited; exit 1 ;; esac @@ -74,11 +74,11 @@ test_expect_success 'diff-files' ' ' test_expect_success 'write-tree' ' - top=`git write-tree` && + top=$(git write-tree) && echo $top && ( cd dir && - sub=`git write-tree` && + sub=$(git write-tree) && echo $sub && test "z$top" = "z$sub" ) @@ -96,7 +96,7 @@ test_expect_success 'checkout-index' ' test_expect_success 'read-tree' ' rm -f one dir/two && - tree=`git write-tree` && + tree=$(git write-tree) && read_tree_u_must_succeed --reset -u "$tree" && cmp one original.one && cmp dir/two original.two && @@ -118,7 +118,7 @@ test_expect_success 'alias expansion' ' ) ' -test_expect_success NOT_MINGW '!alias expansion' ' +test_expect_success !MINGW '!alias expansion' ' pwd >expect && ( git config alias.test-alias-directory !pwd && @@ -162,16 +162,20 @@ test_expect_success 'no file/rev ambiguity check inside .git' ' ) ' -test_expect_success 'no file/rev ambiguity check inside a bare repo' ' +test_expect_success 'no file/rev ambiguity check inside a bare repo (explicit GIT_DIR)' ' + test_when_finished "rm -fr foo.git" && git clone -s --bare .git foo.git && ( cd foo.git && + # older Git needed help by exporting GIT_DIR=. + # to realize that it is inside a bare repository. + # We keep this test around for regression testing. GIT_DIR=. git show -s HEAD ) ' -# This still does not work as it should... -: test_expect_success 'no file/rev ambiguity check inside a bare repo' ' +test_expect_success 'no file/rev ambiguity check inside a bare repo' ' + test_when_finished "rm -fr foo.git" && git clone -s --bare .git foo.git && ( cd foo.git && @@ -180,7 +184,6 @@ test_expect_success 'no file/rev ambiguity check inside a bare repo' ' ' test_expect_success SYMLINKS 'detection should not be fooled by a symlink' ' - rm -fr foo.git && git clone -s .git another && ln -s another yetanother && ( diff --git a/t/t1050-large.sh b/t/t1050-large.sh index fd10528009..f9f3d1391f 100755 --- a/t/t1050-large.sh +++ b/t/t1050-large.sh @@ -9,11 +9,11 @@ test_expect_success setup ' # clone does not allow us to pass core.bigfilethreshold to # new repos, so set core.bigfilethreshold globally git config --global core.bigfilethreshold 200k && - echo X | dd of=large1 bs=1k seek=2000 && - echo X | dd of=large2 bs=1k seek=2000 && - echo X | dd of=large3 bs=1k seek=2000 && - echo Y | dd of=huge bs=1k seek=2500 && - GIT_ALLOC_LIMIT=1500 && + printf "%2000000s" X >large1 && + cp large1 large2 && + cp large1 large3 && + printf "%2500000s" Y >huge && + GIT_ALLOC_LIMIT=1500k && export GIT_ALLOC_LIMIT ' @@ -61,7 +61,7 @@ test_expect_success 'checkout a large file' ' large1=$(git rev-parse :large1) && git update-index --add --cacheinfo 100644 $large1 another && git checkout another && - cmp large1 another ;# this must not be test_cmp + test_cmp large1 another ' test_expect_success 'packsize limit' ' @@ -112,6 +112,20 @@ test_expect_success 'diff --raw' ' git diff --raw HEAD^ ' +test_expect_success 'diff --stat' ' + git diff --stat HEAD^ HEAD +' + +test_expect_success 'diff' ' + git diff HEAD^ HEAD >actual && + grep "Binary files.*differ" actual +' + +test_expect_success 'diff --cached' ' + git diff --cached HEAD^ >actual && + grep "Binary files.*differ" actual +' + test_expect_success 'hash-object' ' git hash-object large1 ' @@ -131,7 +145,7 @@ test_expect_success 'git-show a large file' ' ' test_expect_success 'index-pack' ' - git clone file://"`pwd`"/.git foo && + git clone file://"$(pwd)"/.git foo && GIT_DIR=non-existent git index-pack --strict --verify foo/.git/objects/pack/*.pack ' @@ -140,7 +154,7 @@ test_expect_success 'repack' ' ' test_expect_success 'pack-objects with large loose object' ' - SHA1=`git hash-object huge` && + SHA1=$(git hash-object huge) && test_create_repo loose && echo $SHA1 | git pack-objects --stdout | GIT_ALLOC_LIMIT=0 GIT_DIR=loose/.git git unpack-objects && @@ -148,7 +162,7 @@ test_expect_success 'pack-objects with large loose object' ' test_create_repo packed && mv pack-* packed/.git/objects/pack && GIT_DIR=packed/.git git cat-file blob $SHA1 >actual && - cmp huge actual + test_cmp huge actual ' test_expect_success 'tar achiving' ' @@ -163,4 +177,10 @@ test_expect_success 'zip achiving, deflate' ' git archive --format=zip HEAD >/dev/null ' +test_expect_success 'fsck' ' + test_must_fail git fsck 2>err && + n=$(grep "error: attempting to allocate .* over limit" err | wc -l) && + test "$n" -gt 1 +' + test_done diff --git a/t/t1090-sparse-checkout-scope.sh b/t/t1090-sparse-checkout-scope.sh new file mode 100755 index 0000000000..1f61eb3e88 --- /dev/null +++ b/t/t1090-sparse-checkout-scope.sh @@ -0,0 +1,52 @@ +#!/bin/sh + +test_description='sparse checkout scope tests' + +. ./test-lib.sh + +test_expect_success 'setup' ' + echo "initial" >a && + echo "initial" >b && + echo "initial" >c && + git add a b c && + git commit -m "initial commit" +' + +test_expect_success 'create feature branch' ' + git checkout -b feature && + echo "modified" >b && + echo "modified" >c && + git add b c && + git commit -m "modification" +' + +test_expect_success 'perform sparse checkout of master' ' + git config --local --bool core.sparsecheckout true && + echo "!/*" >.git/info/sparse-checkout && + echo "/a" >>.git/info/sparse-checkout && + echo "/c" >>.git/info/sparse-checkout && + git checkout master && + test_path_is_file a && + test_path_is_missing b && + test_path_is_file c +' + +test_expect_success 'merge feature branch into sparse checkout of master' ' + git merge feature && + test_path_is_file a && + test_path_is_missing b && + test_path_is_file c && + test "$(cat c)" = "modified" +' + +test_expect_success 'return to full checkout of master' ' + git checkout feature && + echo "/*" >.git/info/sparse-checkout && + git checkout master && + test_path_is_file a && + test_path_is_file b && + test_path_is_file c && + test "$(cat b)" = "modified" +' + +test_done diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 58cd5435be..52678e7d0a 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -353,6 +353,18 @@ test_expect_success '--list without repo produces empty output' ' ' cat > expect << EOF +beta.noindent +nextsection.nonewline +123456.a123 +version.1.2.3eX.alpha +EOF + +test_expect_success '--name-only --list' ' + git config --name-only --list >output && + test_cmp expect output +' + +cat > expect << EOF beta.noindent sillyValue nextsection.nonewline wow2 for me EOF @@ -363,6 +375,16 @@ test_expect_success '--get-regexp' ' ' cat > expect << EOF +beta.noindent +nextsection.nonewline +EOF + +test_expect_success '--name-only --get-regexp' ' + git config --name-only --get-regexp in >output && + test_cmp expect output +' + +cat > expect << EOF wow2 for me wow4 for you EOF @@ -677,7 +699,7 @@ test_expect_success 'invalid unit' ' echo 1auto >expect && git config aninvalid.unit >actual && test_cmp expect actual && - cat >expect <<-\EOF + cat >expect <<-\EOF && fatal: bad numeric config value '\''1auto'\'' for '\''aninvalid.unit'\'' in .git/config: invalid unit EOF test_must_fail git config --int --get aninvalid.unit 2>actual && @@ -824,14 +846,14 @@ cat >expect <<\EOF trailingtilde = foo~ EOF -test_expect_success NOT_MINGW 'set --path' ' +test_expect_success !MINGW 'set --path' ' rm -f .git/config && git config --path path.home "~/" && git config --path path.normal "/dev/null" && git config --path path.trailingtilde "foo~" && test_cmp expect .git/config' -if test_have_prereq NOT_MINGW && test "${HOME+set}" +if test_have_prereq !MINGW && test "${HOME+set}" then test_set_prereq HOMEVAR fi @@ -854,7 +876,7 @@ cat >expect <<\EOF foo~ EOF -test_expect_success NOT_MINGW 'get --path copes with unset $HOME' ' +test_expect_success !MINGW 'get --path copes with unset $HOME' ' ( unset HOME; test_must_fail git config --get --path path.home \ @@ -1010,6 +1032,17 @@ test_expect_success 'git -c "key=value" support' ' test_must_fail git -c name=value config core.name ' +# We just need a type-specifier here that cares about the +# distinction internally between a NULL boolean and a real +# string (because most of git's internal parsers do care). +# Using "--path" works, but we do not otherwise care about +# its semantics. +test_expect_success 'git -c can represent empty string' ' + echo >expect && + git -c foo.empty= config --path foo.empty >actual && + test_cmp expect actual +' + test_expect_success 'key sanity-checking' ' test_must_fail git config foo=bar && test_must_fail git config foo=.bar && @@ -1154,8 +1187,18 @@ test_expect_failure 'adding a key into an empty section reuses header' ' Qkey = value EOF - git config section.key value + git config section.key value && test_cmp expect .git/config ' +test_expect_success POSIXPERM,PERL 'preserves existing permissions' ' + chmod 0600 .git/config && + git config imap.pass Hunter2 && + perl -e \ + "die q(badset) if ((stat(q(.git/config)))[2] & 07777) != 0600" && + git config --rename-section imap pop && + perl -e \ + "die q(badrename) if ((stat(q(.git/config)))[2] & 07777) != 0600" +' + test_done diff --git a/t/t1301-shared-repo.sh b/t/t1301-shared-repo.sh index de42d21c92..ac10875408 100755 --- a/t/t1301-shared-repo.sh +++ b/t/t1301-shared-repo.sh @@ -12,12 +12,11 @@ setfacl -k . 2>/dev/null # User must have read permissions to the repo -> failure on --shared=0400 test_expect_success 'shared = 0400 (faulty permission u-w)' ' + test_when_finished "rm -rf sub" && mkdir sub && ( - cd sub && git init --shared=0400 + cd sub && + test_must_fail git init --shared=0400 ) - ret="$?" - rm -rf sub - test $ret != "0" ' modebits () { @@ -33,7 +32,7 @@ do git init --shared=1 && test 1 = "$(git config core.sharedrepository)" ) && - actual=$(ls -l sub/.git/HEAD) + actual=$(ls -l sub/.git/HEAD) && case "$actual" in -rw-rw-r--*) : happy @@ -90,10 +89,8 @@ do rm -f .git/info/refs && git update-server-info && actual="$(modebits .git/info/refs)" && - test "x$actual" = "x-$y" || { - ls -lt .git/info - false - } + verbose test "x$actual" = "x-$y" + ' umask 077 && @@ -102,16 +99,24 @@ do rm -f .git/info/refs && git update-server-info && actual="$(modebits .git/info/refs)" && - test "x$actual" = "x-$x" || { - ls -lt .git/info - false - } + verbose test "x$actual" = "x-$x" ' done +test_expect_success POSIXPERM 'info/refs respects umask in unshared repo' ' + rm -f .git/info/refs && + test_unconfig core.sharedrepository && + umask 002 && + git update-server-info && + echo "-rw-rw-r--" >expect && + modebits .git/info/refs >actual && + test_cmp expect actual +' + test_expect_success POSIXPERM 'git reflog expire honors core.sharedRepository' ' + umask 077 && git config core.sharedRepository group && git reflog expire --all && actual="$(ls -l .git/logs/refs/heads/master)" && diff --git a/t/t1302-repo-version.sh b/t/t1302-repo-version.sh index 0d9388afc4..9bcd34969f 100755 --- a/t/t1302-repo-version.sh +++ b/t/t1302-repo-version.sh @@ -67,4 +67,64 @@ test_expect_success 'gitdir required mode' ' ) ' +check_allow () { + git rev-parse --git-dir >actual && + echo .git >expect && + test_cmp expect actual +} + +check_abort () { + test_must_fail git rev-parse --git-dir +} + +# avoid git-config, since it cannot be trusted to run +# in a repository with a broken version +mkconfig () { + echo '[core]' && + echo "repositoryformatversion = $1" && + shift && + + if test $# -gt 0; then + echo '[extensions]' && + for i in "$@"; do + echo "$i" + done + fi +} + +while read outcome version extensions; do + test_expect_success "$outcome version=$version $extensions" " + mkconfig $version $extensions >.git/config && + check_${outcome} + " +done <<\EOF +allow 0 +allow 1 +allow 1 noop +abort 1 no-such-extension +allow 0 no-such-extension +EOF + +test_expect_success 'precious-objects allowed' ' + mkconfig 1 preciousObjects >.git/config && + check_allow +' + +test_expect_success 'precious-objects blocks destructive repack' ' + test_must_fail git repack -ad +' + +test_expect_success 'other repacks are OK' ' + test_commit foo && + git repack +' + +test_expect_success 'precious-objects blocks prune' ' + test_must_fail git prune +' + +test_expect_success 'gc runs without complaint' ' + git gc +' + test_done diff --git a/t/t1303-wacky-config.sh b/t/t1303-wacky-config.sh index 3a2c81968c..3b92083e19 100755 --- a/t/t1303-wacky-config.sh +++ b/t/t1303-wacky-config.sh @@ -111,4 +111,24 @@ test_expect_success 'unset many entries' ' test_must_fail git config section.key ' +test_expect_success '--add appends new value after existing empty value' ' + cat >expect <<-\EOF && + + + fool + roll + EOF + cp .git/config .git/config.old && + test_when_finished "mv .git/config.old .git/config" && + cat >.git/config <<-\EOF && + [foo] + baz + baz = + baz = fool + EOF + git config --add foo.baz roll && + git config --get-all foo.baz >output && + test_cmp expect output +' + test_done diff --git a/t/t1304-default-acl.sh b/t/t1304-default-acl.sh index 79045abb51..f5422f1d33 100755 --- a/t/t1304-default-acl.sh +++ b/t/t1304-default-acl.sh @@ -26,7 +26,7 @@ test_expect_success 'checking for a working acl setup' ' if test -z "$LOGNAME" then - LOGNAME=$USER + LOGNAME="${USER:-$(id -u -n)}" fi check_perms_and_acl () { diff --git a/t/t1307-config-blob.sh b/t/t1307-config-blob.sh index fdc257e66f..3c6791e6be 100755 --- a/t/t1307-config-blob.sh +++ b/t/t1307-config-blob.sh @@ -67,4 +67,13 @@ test_expect_success 'parse errors in blobs are properly attributed' ' grep "HEAD:config" err ' +test_expect_success 'can parse blob ending with CR' ' + printf "[some]key = value\\r" >config && + git add config && + git commit -m CR && + echo value >expect && + git config --blob=HEAD:config some.key >actual && + test_cmp expect actual +' + test_done diff --git a/t/t1308-config-set.sh b/t/t1308-config-set.sh new file mode 100755 index 0000000000..91235b76ba --- /dev/null +++ b/t/t1308-config-set.sh @@ -0,0 +1,221 @@ +#!/bin/sh + +test_description='Test git config-set API in different settings' + +. ./test-lib.sh + +# 'check_config get_* section.key value' verifies that the entry for +# section.key is 'value' +check_config () { + if test "$1" = expect_code + then + expect_code="$2" && shift && shift + else + expect_code=0 + fi && + op=$1 key=$2 && shift && shift && + if test $# != 0 + then + printf "%s\n" "$@" + fi >expect && + test_expect_code $expect_code test-config "$op" "$key" >actual && + test_cmp expect actual +} + +test_expect_success 'setup default config' ' + cat >.git/config <<-\EOF + [case] + penguin = very blue + Movie = BadPhysics + UPPERCASE = true + MixedCase = true + my = + foo + baz = sam + [Cores] + WhatEver = Second + baz = bar + [cores] + baz = bat + [CORES] + baz = ball + [my "Foo bAr"] + hi = mixed-case + [my "FOO BAR"] + hi = upper-case + [my "foo bar"] + hi = lower-case + [case] + baz = bat + baz = hask + [lamb] + chop = 65 + head = none + [goat] + legs = 4 + head = true + skin = false + nose = 1 + horns + EOF +' + +test_expect_success 'get value for a simple key' ' + check_config get_value case.penguin "very blue" +' + +test_expect_success 'get value for a key with value as an empty string' ' + check_config get_value case.my "" +' + +test_expect_success 'get value for a key with value as NULL' ' + check_config get_value case.foo "(NULL)" +' + +test_expect_success 'upper case key' ' + check_config get_value case.UPPERCASE "true" && + check_config get_value case.uppercase "true" +' + +test_expect_success 'mixed case key' ' + check_config get_value case.MixedCase "true" && + check_config get_value case.MIXEDCASE "true" && + check_config get_value case.mixedcase "true" +' + +test_expect_success 'key and value with mixed case' ' + check_config get_value case.Movie "BadPhysics" +' + +test_expect_success 'key with case sensitive subsection' ' + check_config get_value "my.Foo bAr.hi" "mixed-case" && + check_config get_value "my.FOO BAR.hi" "upper-case" && + check_config get_value "my.foo bar.hi" "lower-case" +' + +test_expect_success 'key with case insensitive section header' ' + check_config get_value cores.baz "ball" && + check_config get_value Cores.baz "ball" && + check_config get_value CORES.baz "ball" && + check_config get_value coreS.baz "ball" +' + +test_expect_success 'key with case insensitive section header & variable' ' + check_config get_value CORES.BAZ "ball" && + check_config get_value cores.baz "ball" && + check_config get_value cores.BaZ "ball" && + check_config get_value cOreS.bAz "ball" +' + +test_expect_success 'find value with misspelled key' ' + check_config expect_code 1 get_value "my.fOo Bar.hi" "Value not found for \"my.fOo Bar.hi\"" +' + +test_expect_success 'find value with the highest priority' ' + check_config get_value case.baz "hask" +' + +test_expect_success 'find integer value for a key' ' + check_config get_int lamb.chop 65 +' + +test_expect_success 'find string value for a key' ' + check_config get_string case.baz hask && + check_config expect_code 1 get_string case.ba "Value not found for \"case.ba\"" +' + +test_expect_success 'check line error when NULL string is queried' ' + test_expect_code 128 test-config get_string case.foo 2>result && + test_i18ngrep "fatal: .*case\.foo.*\.git/config.*line 7" result +' + +test_expect_success 'find integer if value is non parse-able' ' + check_config expect_code 128 get_int lamb.head +' + +test_expect_success 'find bool value for the entered key' ' + check_config get_bool goat.head 1 && + check_config get_bool goat.skin 0 && + check_config get_bool goat.nose 1 && + check_config get_bool goat.horns 1 && + check_config get_bool goat.legs 1 +' + +test_expect_success 'find multiple values' ' + check_config get_value_multi case.baz sam bat hask +' + +test_expect_success 'find value from a configset' ' + cat >config2 <<-\EOF && + [case] + baz = lama + [my] + new = silk + [case] + baz = ball + EOF + echo silk >expect && + test-config configset_get_value my.new config2 .git/config >actual && + test_cmp expect actual +' + +test_expect_success 'find value with highest priority from a configset' ' + echo hask >expect && + test-config configset_get_value case.baz config2 .git/config >actual && + test_cmp expect actual +' + +test_expect_success 'find value_list for a key from a configset' ' + cat >except <<-\EOF && + sam + bat + hask + lama + ball + EOF + test-config configset_get_value case.baz config2 .git/config >actual && + test_cmp expect actual +' + +test_expect_success 'proper error on non-existent files' ' + echo "Error (-1) reading configuration file non-existent-file." >expect && + test_expect_code 2 test-config configset_get_value foo.bar non-existent-file 2>actual && + test_cmp expect actual +' + +test_expect_success POSIXPERM,SANITY 'proper error on non-accessible files' ' + chmod -r .git/config && + test_when_finished "chmod +r .git/config" && + echo "Error (-1) reading configuration file .git/config." >expect && + test_expect_code 2 test-config configset_get_value foo.bar .git/config 2>actual && + test_cmp expect actual +' + +test_expect_success 'proper error on error in default config files' ' + cp .git/config .git/config.old && + test_when_finished "mv .git/config.old .git/config" && + echo "[" >>.git/config && + echo "fatal: bad config file line 34 in .git/config" >expect && + test_expect_code 128 test-config get_value foo.bar 2>actual && + test_cmp expect actual +' + +test_expect_success 'proper error on error in custom config files' ' + echo "[" >>syntax-error && + echo "fatal: bad config file line 1 in syntax-error" >expect && + test_expect_code 128 test-config configset_get_value foo.bar syntax-error 2>actual && + test_cmp expect actual +' + +test_expect_success 'check line errors for malformed values' ' + mv .git/config .git/config.old && + test_when_finished "mv .git/config.old .git/config" && + cat >.git/config <<-\EOF && + [alias] + br + EOF + test_expect_code 128 git br 2>result && + test_i18ngrep "fatal: .*alias\.br.*\.git/config.*line 2" result +' + +test_done diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh index e130c528fe..af1b20dd5c 100755 --- a/t/t1400-update-ref.sh +++ b/t/t1400-update-ref.sh @@ -23,6 +23,7 @@ test_expect_success setup ' m=refs/heads/master n_dir=refs/heads/gu n=$n_dir/fixes +outside=foo test_expect_success \ "create $m" \ @@ -74,6 +75,24 @@ test_expect_success "delete $m (by HEAD)" ' ' rm -f .git/$m +test_expect_success 'update-ref does not create reflogs by default' ' + test_when_finished "git update-ref -d $outside" && + git update-ref $outside $A && + git rev-parse $A >expect && + git rev-parse $outside >actual && + test_cmp expect actual && + test_must_fail git reflog exists $outside +' + +test_expect_success 'update-ref creates reflogs with --create-reflog' ' + test_when_finished "git update-ref -d $outside" && + git update-ref --create-reflog $outside $A && + git rev-parse $A >expect && + git rev-parse $outside >actual && + test_cmp expect actual && + git reflog exists $outside +' + test_expect_success \ "create $m (by HEAD)" \ "git update-ref HEAD $A && @@ -110,6 +129,32 @@ test_expect_success "delete symref without dereference when the referred ref is cp -f .git/HEAD.orig .git/HEAD git update-ref -d $m +test_expect_success 'update-ref -d is not confused by self-reference' ' + git symbolic-ref refs/heads/self refs/heads/self && + test_when_finished "rm -f .git/refs/heads/self" && + test_path_is_file .git/refs/heads/self && + test_must_fail git update-ref -d refs/heads/self && + test_path_is_file .git/refs/heads/self +' + +test_expect_success 'update-ref --no-deref -d can delete self-reference' ' + git symbolic-ref refs/heads/self refs/heads/self && + test_when_finished "rm -f .git/refs/heads/self" && + test_path_is_file .git/refs/heads/self && + git update-ref --no-deref -d refs/heads/self && + test_path_is_missing .git/refs/heads/self +' + +test_expect_success 'update-ref --no-deref -d can delete reference to bad ref' ' + >.git/refs/heads/bad && + test_when_finished "rm -f .git/refs/heads/bad" && + git symbolic-ref refs/heads/ref-to-bad refs/heads/bad && + test_when_finished "rm -f .git/refs/heads/ref-to-bad" && + test_path_is_file .git/refs/heads/ref-to-bad && + git update-ref --no-deref -d refs/heads/ref-to-bad && + test_path_is_missing .git/refs/heads/ref-to-bad +' + test_expect_success '(not) create HEAD with old sha1' " test_must_fail git update-ref HEAD $A $B " @@ -129,12 +174,11 @@ test_expect_success "(not) changed .git/$m" " ' rm -f .git/$m -: a repository with working tree always has reflog these days... -: >.git/logs/refs/heads/master +rm -f .git/logs/refs/heads/master test_expect_success \ "create $m (logged by touch)" \ 'GIT_COMMITTER_DATE="2005-05-26 23:30" \ - git update-ref HEAD '"$A"' -m "Initial Creation" && + git update-ref --create-reflog HEAD '"$A"' -m "Initial Creation" && test '"$A"' = $(cat .git/'"$m"')' test_expect_success \ "update $m (logged by touch)" \ @@ -235,7 +279,7 @@ test_expect_success \ 'rm -f o e && git rev-parse --verify "master@{2005-05-26 23:33:01}" >o 2>e && test '"$B"' = $(cat o) && - test "warning: Log .git/logs/'"$m has gap after $gd"'." = "$(cat e)"' + test "warning: Log for ref '"$m has gap after $gd"'." = "$(cat e)"' test_expect_success \ 'Query "master@{2005-05-26 23:38:00}" (middle of history)' \ 'rm -f o e && @@ -253,7 +297,7 @@ test_expect_success \ 'rm -f o e && git rev-parse --verify "master@{2005-05-28}" >o 2>e && test '"$D"' = $(cat o) && - test "warning: Log .git/logs/'"$m unexpectedly ended on $ld"'." = "$(cat e)"' + test "warning: Log for ref '"$m unexpectedly ended on $ld"'." = "$(cat e)"' rm -f .git/$m .git/logs/$m expect @@ -350,88 +394,76 @@ test_expect_success 'stdin fails on unknown command' ' grep "fatal: unknown command: unknown $a" err ' -test_expect_success 'stdin fails on badly quoted input' ' +test_expect_success 'stdin fails on unbalanced quotes' ' echo "create $a \"master" >stdin && test_must_fail git update-ref --stdin <stdin 2>err && grep "fatal: badly quoted argument: \\\"master" err ' -test_expect_success 'stdin fails on arguments not separated by space' ' - echo "create \"$a\"master" >stdin && +test_expect_success 'stdin fails on invalid escape' ' + echo "create $a \"ma\zter\"" >stdin && test_must_fail git update-ref --stdin <stdin 2>err && - grep "fatal: expected SP but got: master" err + grep "fatal: badly quoted argument: \\\"ma\\\\zter\\\"" err ' -test_expect_success 'stdin fails create with no ref' ' - echo "create " >stdin && +test_expect_success 'stdin fails on junk after quoted argument' ' + echo "create \"$a\"master" >stdin && test_must_fail git update-ref --stdin <stdin 2>err && - grep "fatal: create line missing <ref>" err + grep "fatal: unexpected character after quoted argument: \\\"$a\\\"master" err ' -test_expect_success 'stdin fails create with bad ref name' ' - echo "create ~a $m" >stdin && +test_expect_success 'stdin fails create with no ref' ' + echo "create " >stdin && test_must_fail git update-ref --stdin <stdin 2>err && - grep "fatal: invalid ref format: ~a" err + grep "fatal: create: missing <ref>" err ' test_expect_success 'stdin fails create with no new value' ' echo "create $a" >stdin && test_must_fail git update-ref --stdin <stdin 2>err && - grep "fatal: create $a missing <newvalue>" err + grep "fatal: create $a: missing <newvalue>" err ' test_expect_success 'stdin fails create with too many arguments' ' echo "create $a $m $m" >stdin && test_must_fail git update-ref --stdin <stdin 2>err && - grep "fatal: create $a has extra input: $m" err + grep "fatal: create $a: extra input: $m" err ' test_expect_success 'stdin fails update with no ref' ' echo "update " >stdin && test_must_fail git update-ref --stdin <stdin 2>err && - grep "fatal: update line missing <ref>" err -' - -test_expect_success 'stdin fails update with bad ref name' ' - echo "update ~a $m" >stdin && - test_must_fail git update-ref --stdin <stdin 2>err && - grep "fatal: invalid ref format: ~a" err + grep "fatal: update: missing <ref>" err ' test_expect_success 'stdin fails update with no new value' ' echo "update $a" >stdin && test_must_fail git update-ref --stdin <stdin 2>err && - grep "fatal: update $a missing <newvalue>" err + grep "fatal: update $a: missing <newvalue>" err ' test_expect_success 'stdin fails update with too many arguments' ' echo "update $a $m $m $m" >stdin && test_must_fail git update-ref --stdin <stdin 2>err && - grep "fatal: update $a has extra input: $m" err + grep "fatal: update $a: extra input: $m" err ' test_expect_success 'stdin fails delete with no ref' ' echo "delete " >stdin && test_must_fail git update-ref --stdin <stdin 2>err && - grep "fatal: delete line missing <ref>" err -' - -test_expect_success 'stdin fails delete with bad ref name' ' - echo "delete ~a $m" >stdin && - test_must_fail git update-ref --stdin <stdin 2>err && - grep "fatal: invalid ref format: ~a" err + grep "fatal: delete: missing <ref>" err ' test_expect_success 'stdin fails delete with too many arguments' ' echo "delete $a $m $m" >stdin && test_must_fail git update-ref --stdin <stdin 2>err && - grep "fatal: delete $a has extra input: $m" err + grep "fatal: delete $a: extra input: $m" err ' test_expect_success 'stdin fails verify with too many arguments' ' echo "verify $a $m $m" >stdin && test_must_fail git update-ref --stdin <stdin 2>err && - grep "fatal: verify $a has extra input: $m" err + grep "fatal: verify $a: extra input: $m" err ' test_expect_success 'stdin fails option with unknown name' ' @@ -458,6 +490,43 @@ test_expect_success 'stdin create ref works' ' test_cmp expect actual ' +test_expect_success 'stdin does not create reflogs by default' ' + test_when_finished "git update-ref -d $outside" && + echo "create $outside $m" >stdin && + git update-ref --stdin <stdin && + git rev-parse $m >expect && + git rev-parse $outside >actual && + test_cmp expect actual && + test_must_fail git reflog exists $outside +' + +test_expect_success 'stdin creates reflogs with --create-reflog' ' + echo "create $outside $m" >stdin && + git update-ref --create-reflog --stdin <stdin && + git rev-parse $m >expect && + git rev-parse $outside >actual && + test_cmp expect actual && + git reflog exists $outside +' + +test_expect_success 'stdin succeeds with quoted argument' ' + git update-ref -d $a && + echo "create $a \"$m\"" >stdin && + git update-ref --stdin <stdin && + git rev-parse $m >expect && + git rev-parse $a >actual && + test_cmp expect actual +' + +test_expect_success 'stdin succeeds with escaped character' ' + git update-ref -d $a && + echo "create $a \"ma\\163ter\"" >stdin && + git update-ref --stdin <stdin && + git rev-parse $m >expect && + git rev-parse $a >actual && + test_cmp expect actual +' + test_expect_success 'stdin update ref creates with zero old value' ' echo "update $b $m $Z" >stdin && git update-ref --stdin <stdin && @@ -487,28 +556,28 @@ test_expect_success 'stdin create ref works with path with space to blob' ' test_expect_success 'stdin update ref fails with wrong old value' ' echo "update $c $m $m~1" >stdin && test_must_fail git update-ref --stdin <stdin 2>err && - grep "fatal: Cannot lock the ref '"'"'$c'"'"'" err && + grep "fatal: cannot lock ref '"'"'$c'"'"'" err && test_must_fail git rev-parse --verify -q $c ' test_expect_success 'stdin update ref fails with bad old value' ' echo "update $c $m does-not-exist" >stdin && test_must_fail git update-ref --stdin <stdin 2>err && - grep "fatal: invalid old value for ref $c: does-not-exist" err && + grep "fatal: update $c: invalid <oldvalue>: does-not-exist" err && test_must_fail git rev-parse --verify -q $c ' test_expect_success 'stdin create ref fails with bad new value' ' echo "create $c does-not-exist" >stdin && test_must_fail git update-ref --stdin <stdin 2>err && - grep "fatal: invalid new value for ref $c: does-not-exist" err && + grep "fatal: create $c: invalid <newvalue>: does-not-exist" err && test_must_fail git rev-parse --verify -q $c ' test_expect_success 'stdin create ref fails with zero new value' ' echo "create $c " >stdin && test_must_fail git update-ref --stdin <stdin 2>err && - grep "fatal: create $c given zero new value" err && + grep "fatal: create $c: zero <newvalue>" err && test_must_fail git rev-parse --verify -q $c ' @@ -523,7 +592,7 @@ test_expect_success 'stdin update ref works with right old value' ' test_expect_success 'stdin delete ref fails with wrong old value' ' echo "delete $a $m~1" >stdin && test_must_fail git update-ref --stdin <stdin 2>err && - grep "fatal: Cannot lock the ref '"'"'$a'"'"'" err && + grep "fatal: cannot lock ref '"'"'$a'"'"'" err && git rev-parse $m >expect && git rev-parse $a >actual && test_cmp expect actual @@ -532,7 +601,7 @@ test_expect_success 'stdin delete ref fails with wrong old value' ' test_expect_success 'stdin delete ref fails with zero old value' ' echo "delete $a " >stdin && test_must_fail git update-ref --stdin <stdin 2>err && - grep "fatal: delete $a given zero old value" err && + grep "fatal: delete $a: zero <oldvalue>" err && git rev-parse $m >expect && git rev-parse $a >actual && test_cmp expect actual @@ -587,6 +656,52 @@ test_expect_success 'stdin update/create/verify combination works' ' test_must_fail git rev-parse --verify -q $c ' +test_expect_success 'stdin verify succeeds for correct value' ' + git rev-parse $m >expect && + echo "verify $m $m" >stdin && + git update-ref --stdin <stdin && + git rev-parse $m >actual && + test_cmp expect actual +' + +test_expect_success 'stdin verify succeeds for missing reference' ' + echo "verify refs/heads/missing $Z" >stdin && + git update-ref --stdin <stdin && + test_must_fail git rev-parse --verify -q refs/heads/missing +' + +test_expect_success 'stdin verify treats no value as missing' ' + echo "verify refs/heads/missing" >stdin && + git update-ref --stdin <stdin && + test_must_fail git rev-parse --verify -q refs/heads/missing +' + +test_expect_success 'stdin verify fails for wrong value' ' + git rev-parse $m >expect && + echo "verify $m $m~1" >stdin && + test_must_fail git update-ref --stdin <stdin && + git rev-parse $m >actual && + test_cmp expect actual +' + +test_expect_success 'stdin verify fails for mistaken null value' ' + git rev-parse $m >expect && + echo "verify $m $Z" >stdin && + test_must_fail git update-ref --stdin <stdin && + git rev-parse $m >actual && + test_cmp expect actual +' + +test_expect_success 'stdin verify fails for mistaken empty value' ' + M=$(git rev-parse $m) && + test_when_finished "git update-ref $m $M" && + git rev-parse $m >expect && + echo "verify $m" >stdin && + test_must_fail git update-ref --stdin <stdin && + git rev-parse $m >actual && + test_cmp expect actual +' + test_expect_success 'stdin update refs works with identity updates' ' cat >stdin <<-EOF && update $a $m $m @@ -610,7 +725,7 @@ test_expect_success 'stdin update refs fails with wrong old value' ' update $c '' EOF test_must_fail git update-ref --stdin <stdin 2>err && - grep "fatal: Cannot lock the ref '"'"'$c'"'"'" err && + grep "fatal: cannot lock ref '"'"'$c'"'"'" err && git rev-parse $m >expect && git rev-parse $a >actual && test_cmp expect actual && @@ -673,19 +788,13 @@ test_expect_success 'stdin -z fails on unknown command' ' test_expect_success 'stdin -z fails create with no ref' ' printf $F "create " >stdin && test_must_fail git update-ref -z --stdin <stdin 2>err && - grep "fatal: create line missing <ref>" err -' - -test_expect_success 'stdin -z fails create with bad ref name' ' - printf $F "create ~a " "$m" >stdin && - test_must_fail git update-ref -z --stdin <stdin 2>err && - grep "fatal: invalid ref format: ~a " err + grep "fatal: create: missing <ref>" err ' test_expect_success 'stdin -z fails create with no new value' ' printf $F "create $a" >stdin && test_must_fail git update-ref -z --stdin <stdin 2>err && - grep "fatal: create $a missing <newvalue>" err + grep "fatal: create $a: unexpected end of input when reading <newvalue>" err ' test_expect_success 'stdin -z fails create with too many arguments' ' @@ -697,25 +806,33 @@ test_expect_success 'stdin -z fails create with too many arguments' ' test_expect_success 'stdin -z fails update with no ref' ' printf $F "update " >stdin && test_must_fail git update-ref -z --stdin <stdin 2>err && - grep "fatal: update line missing <ref>" err + grep "fatal: update: missing <ref>" err ' -test_expect_success 'stdin -z fails update with bad ref name' ' - printf $F "update ~a" "$m" >stdin && +test_expect_success 'stdin -z fails update with too few args' ' + printf $F "update $a" "$m" >stdin && test_must_fail git update-ref -z --stdin <stdin 2>err && - grep "fatal: invalid ref format: ~a" err + grep "fatal: update $a: unexpected end of input when reading <oldvalue>" err +' + +test_expect_success 'stdin -z emits warning with empty new value' ' + git update-ref $a $m && + printf $F "update $a" "" "" >stdin && + git update-ref -z --stdin <stdin 2>err && + grep "warning: update $a: missing <newvalue>, treating as zero" err && + test_must_fail git rev-parse --verify -q $a ' test_expect_success 'stdin -z fails update with no new value' ' printf $F "update $a" >stdin && test_must_fail git update-ref -z --stdin <stdin 2>err && - grep "fatal: update $a missing <newvalue>" err + grep "fatal: update $a: unexpected end of input when reading <newvalue>" err ' test_expect_success 'stdin -z fails update with no old value' ' printf $F "update $a" "$m" >stdin && test_must_fail git update-ref -z --stdin <stdin 2>err && - grep "fatal: update $a missing \\[<oldvalue>\\] NUL" err + grep "fatal: update $a: unexpected end of input when reading <oldvalue>" err ' test_expect_success 'stdin -z fails update with too many arguments' ' @@ -727,19 +844,13 @@ test_expect_success 'stdin -z fails update with too many arguments' ' test_expect_success 'stdin -z fails delete with no ref' ' printf $F "delete " >stdin && test_must_fail git update-ref -z --stdin <stdin 2>err && - grep "fatal: delete line missing <ref>" err -' - -test_expect_success 'stdin -z fails delete with bad ref name' ' - printf $F "delete ~a" "$m" >stdin && - test_must_fail git update-ref -z --stdin <stdin 2>err && - grep "fatal: invalid ref format: ~a" err + grep "fatal: delete: missing <ref>" err ' test_expect_success 'stdin -z fails delete with no old value' ' printf $F "delete $a" >stdin && test_must_fail git update-ref -z --stdin <stdin 2>err && - grep "fatal: delete $a missing \\[<oldvalue>\\] NUL" err + grep "fatal: delete $a: unexpected end of input when reading <oldvalue>" err ' test_expect_success 'stdin -z fails delete with too many arguments' ' @@ -757,7 +868,7 @@ test_expect_success 'stdin -z fails verify with too many arguments' ' test_expect_success 'stdin -z fails verify with no old value' ' printf $F "verify $a" >stdin && test_must_fail git update-ref -z --stdin <stdin 2>err && - grep "fatal: verify $a missing \\[<oldvalue>\\] NUL" err + grep "fatal: verify $a: unexpected end of input when reading <oldvalue>" err ' test_expect_success 'stdin -z fails option with unknown name' ' @@ -809,14 +920,14 @@ test_expect_success 'stdin -z create ref works with path with space to blob' ' test_expect_success 'stdin -z update ref fails with wrong old value' ' printf $F "update $c" "$m" "$m~1" >stdin && test_must_fail git update-ref -z --stdin <stdin 2>err && - grep "fatal: Cannot lock the ref '"'"'$c'"'"'" err && + grep "fatal: cannot lock ref '"'"'$c'"'"'" err && test_must_fail git rev-parse --verify -q $c ' test_expect_success 'stdin -z update ref fails with bad old value' ' printf $F "update $c" "$m" "does-not-exist" >stdin && test_must_fail git update-ref -z --stdin <stdin 2>err && - grep "fatal: invalid old value for ref $c: does-not-exist" err && + grep "fatal: update $c: invalid <oldvalue>: does-not-exist" err && test_must_fail git rev-parse --verify -q $c ' @@ -825,7 +936,7 @@ test_expect_success 'stdin -z create ref fails when ref exists' ' git rev-parse "$c" >expect && printf $F "create $c" "$m~1" >stdin && test_must_fail git update-ref -z --stdin <stdin 2>err && - grep "fatal: Cannot lock the ref '"'"'$c'"'"'" err && + grep "fatal: cannot lock ref '"'"'$c'"'"'" err && git rev-parse "$c" >actual && test_cmp expect actual ' @@ -834,14 +945,14 @@ test_expect_success 'stdin -z create ref fails with bad new value' ' git update-ref -d "$c" && printf $F "create $c" "does-not-exist" >stdin && test_must_fail git update-ref -z --stdin <stdin 2>err && - grep "fatal: invalid new value for ref $c: does-not-exist" err && + grep "fatal: create $c: invalid <newvalue>: does-not-exist" err && test_must_fail git rev-parse --verify -q $c ' -test_expect_success 'stdin -z create ref fails with zero new value' ' +test_expect_success 'stdin -z create ref fails with empty new value' ' printf $F "create $c" "" >stdin && test_must_fail git update-ref -z --stdin <stdin 2>err && - grep "fatal: create $c given zero new value" err && + grep "fatal: create $c: missing <newvalue>" err && test_must_fail git rev-parse --verify -q $c ' @@ -856,7 +967,7 @@ test_expect_success 'stdin -z update ref works with right old value' ' test_expect_success 'stdin -z delete ref fails with wrong old value' ' printf $F "delete $a" "$m~1" >stdin && test_must_fail git update-ref -z --stdin <stdin 2>err && - grep "fatal: Cannot lock the ref '"'"'$a'"'"'" err && + grep "fatal: cannot lock ref '"'"'$a'"'"'" err && git rev-parse $m >expect && git rev-parse $a >actual && test_cmp expect actual @@ -865,7 +976,7 @@ test_expect_success 'stdin -z delete ref fails with wrong old value' ' test_expect_success 'stdin -z delete ref fails with zero old value' ' printf $F "delete $a" "$Z" >stdin && test_must_fail git update-ref -z --stdin <stdin 2>err && - grep "fatal: delete $a given zero old value" err && + grep "fatal: delete $a: zero <oldvalue>" err && git rev-parse $m >expect && git rev-parse $a >actual && test_cmp expect actual @@ -910,6 +1021,52 @@ test_expect_success 'stdin -z update/create/verify combination works' ' test_must_fail git rev-parse --verify -q $c ' +test_expect_success 'stdin -z verify succeeds for correct value' ' + git rev-parse $m >expect && + printf $F "verify $m" "$m" >stdin && + git update-ref -z --stdin <stdin && + git rev-parse $m >actual && + test_cmp expect actual +' + +test_expect_success 'stdin -z verify succeeds for missing reference' ' + printf $F "verify refs/heads/missing" "$Z" >stdin && + git update-ref -z --stdin <stdin && + test_must_fail git rev-parse --verify -q refs/heads/missing +' + +test_expect_success 'stdin -z verify treats no value as missing' ' + printf $F "verify refs/heads/missing" "" >stdin && + git update-ref -z --stdin <stdin && + test_must_fail git rev-parse --verify -q refs/heads/missing +' + +test_expect_success 'stdin -z verify fails for wrong value' ' + git rev-parse $m >expect && + printf $F "verify $m" "$m~1" >stdin && + test_must_fail git update-ref -z --stdin <stdin && + git rev-parse $m >actual && + test_cmp expect actual +' + +test_expect_success 'stdin -z verify fails for mistaken null value' ' + git rev-parse $m >expect && + printf $F "verify $m" "$Z" >stdin && + test_must_fail git update-ref -z --stdin <stdin && + git rev-parse $m >actual && + test_cmp expect actual +' + +test_expect_success 'stdin -z verify fails for mistaken empty value' ' + M=$(git rev-parse $m) && + test_when_finished "git update-ref $m $M" && + git rev-parse $m >expect && + printf $F "verify $m" "" >stdin && + test_must_fail git update-ref -z --stdin <stdin && + git rev-parse $m >actual && + test_cmp expect actual +' + test_expect_success 'stdin -z update refs works with identity updates' ' printf $F "update $a" "$m" "$m" "update $b" "$m" "$m" "update $c" "$Z" "" >stdin && git update-ref -z --stdin <stdin && @@ -923,9 +1080,9 @@ test_expect_success 'stdin -z update refs works with identity updates' ' test_expect_success 'stdin -z update refs fails with wrong old value' ' git update-ref $c $m && - printf $F "update $a" "$m" "$m" "update $b" "$m" "$m" "update $c" "" "$Z" >stdin && + printf $F "update $a" "$m" "$m" "update $b" "$m" "$m" "update $c" "$m" "$Z" >stdin && test_must_fail git update-ref -z --stdin <stdin 2>err && - grep "fatal: Cannot lock the ref '"'"'$c'"'"'" err && + grep "fatal: cannot lock ref '"'"'$c'"'"'" err && git rev-parse $m >expect && git rev-parse $a >actual && test_cmp expect actual && @@ -945,4 +1102,51 @@ test_expect_success 'stdin -z delete refs works with packed and loose refs' ' test_must_fail git rev-parse --verify -q $c ' +run_with_limited_open_files () { + (ulimit -n 32 && "$@") +} + +test_lazy_prereq ULIMIT_FILE_DESCRIPTORS 'run_with_limited_open_files true' + +test_expect_success ULIMIT_FILE_DESCRIPTORS 'large transaction creating branches does not burst open file limit' ' +( + for i in $(test_seq 33) + do + echo "create refs/heads/$i HEAD" + done >large_input && + run_with_limited_open_files git update-ref --stdin <large_input && + git rev-parse --verify -q refs/heads/33 +) +' + +test_expect_success ULIMIT_FILE_DESCRIPTORS 'large transaction deleting branches does not burst open file limit' ' +( + for i in $(test_seq 33) + do + echo "delete refs/heads/$i HEAD" + done >large_input && + run_with_limited_open_files git update-ref --stdin <large_input && + test_must_fail git rev-parse --verify -q refs/heads/33 +) +' + +test_expect_success 'handle per-worktree refs in refs/bisect' ' + git commit --allow-empty -m "initial commit" && + git worktree add -b branch worktree && + ( + cd worktree && + git commit --allow-empty -m "test commit" && + git for-each-ref >for-each-ref.out && + ! grep refs/bisect for-each-ref.out && + git update-ref refs/bisect/something HEAD && + git rev-parse refs/bisect/something >../worktree-head && + git for-each-ref | grep refs/bisect/something + ) && + test_path_is_missing .git/refs/bisect && + test_must_fail git rev-parse refs/bisect/something && + git update-ref refs/bisect/something HEAD && + git rev-parse refs/bisect/something >main-head && + ! test_cmp main-head worktree-head +' + test_done diff --git a/t/t1401-symbolic-ref.sh b/t/t1401-symbolic-ref.sh index 36378b0e3f..1f0dff3a0b 100755 --- a/t/t1401-symbolic-ref.sh +++ b/t/t1401-symbolic-ref.sh @@ -63,4 +63,55 @@ test_expect_success 'symbolic-ref fails to delete real ref' ' ' reset_to_sane +test_expect_success 'create large ref name' ' + # make 256+ character ref; some systems may not handle that, + # so be gentle + long=0123456789abcdef && + long=$long/$long/$long/$long && + long=$long/$long/$long/$long && + long_ref=refs/heads/$long && + tree=$(git write-tree) && + commit=$(echo foo | git commit-tree $tree) && + if git update-ref $long_ref $commit; then + test_set_prereq LONG_REF + else + echo >&2 "long refs not supported" + fi +' + +test_expect_success LONG_REF 'symbolic-ref can point to large ref name' ' + git symbolic-ref HEAD $long_ref && + echo $long_ref >expect && + git symbolic-ref HEAD >actual && + test_cmp expect actual +' + +test_expect_success LONG_REF 'we can parse long symbolic ref' ' + echo $commit >expect && + git rev-parse --verify HEAD >actual && + test_cmp expect actual +' + +test_expect_success 'symbolic-ref reports failure in exit code' ' + test_when_finished "rm -f .git/HEAD.lock" && + >.git/HEAD.lock && + test_must_fail git symbolic-ref HEAD refs/heads/whatever +' + +test_expect_success 'symbolic-ref writes reflog entry' ' + git checkout -b log1 && + test_commit one && + git checkout -b log2 && + test_commit two && + git checkout --orphan orphan && + git symbolic-ref -m create HEAD refs/heads/log1 && + git symbolic-ref -m update HEAD refs/heads/log2 && + cat >expect <<-\EOF && + update + create + EOF + git log --format=%gs -g >actual && + test_cmp expect actual +' + test_done diff --git a/t/t1402-check-ref-format.sh b/t/t1402-check-ref-format.sh index 1a5a5f39fd..0790edf60d 100755 --- a/t/t1402-check-ref-format.sh +++ b/t/t1402-check-ref-format.sh @@ -7,7 +7,7 @@ test_description='Test git check-ref-format' valid_ref() { prereq= case $1 in - [A-Z]*) + [A-Z!]*) prereq=$1 shift esac @@ -19,7 +19,7 @@ valid_ref() { invalid_ref() { prereq= case $1 in - [A-Z]*) + [A-Z!]*) prereq=$1 shift esac @@ -30,17 +30,17 @@ invalid_ref() { } invalid_ref '' -invalid_ref NOT_MINGW '/' -invalid_ref NOT_MINGW '/' --allow-onelevel -invalid_ref NOT_MINGW '/' --normalize -invalid_ref NOT_MINGW '/' '--allow-onelevel --normalize' +invalid_ref !MINGW '/' +invalid_ref !MINGW '/' --allow-onelevel +invalid_ref !MINGW '/' --normalize +invalid_ref !MINGW '/' '--allow-onelevel --normalize' valid_ref 'foo/bar/baz' valid_ref 'foo/bar/baz' --normalize invalid_ref 'refs///heads/foo' valid_ref 'refs///heads/foo' --normalize invalid_ref 'heads/foo/' -invalid_ref NOT_MINGW '/heads/foo' -valid_ref NOT_MINGW '/heads/foo' --normalize +invalid_ref !MINGW '/heads/foo' +valid_ref !MINGW '/heads/foo' --normalize invalid_ref '///heads/foo' valid_ref '///heads/foo' --normalize invalid_ref './foo' @@ -48,6 +48,7 @@ invalid_ref './foo/bar' invalid_ref 'foo/./bar' invalid_ref 'foo/bar/.' invalid_ref '.refs/foo' +invalid_ref 'refs/heads/foo.' invalid_ref 'heads/foo..bar' invalid_ref 'heads/foo?bar' valid_ref 'foo./bar' @@ -61,9 +62,11 @@ invalid_ref 'heads/foo\bar' invalid_ref "$(printf 'heads/foo\t')" invalid_ref "$(printf 'heads/foo\177')" valid_ref "$(printf 'heads/fu\303\237')" -invalid_ref 'heads/*foo/bar' --refspec-pattern -invalid_ref 'heads/foo*/bar' --refspec-pattern -invalid_ref 'heads/f*o/bar' --refspec-pattern +valid_ref 'heads/*foo/bar' --refspec-pattern +valid_ref 'heads/foo*/bar' --refspec-pattern +valid_ref 'heads/f*o/bar' --refspec-pattern +invalid_ref 'heads/f*o*/bar' --refspec-pattern +invalid_ref 'heads/foo*/bar*' --refspec-pattern ref='foo' invalid_ref "$ref" @@ -119,14 +122,14 @@ invalid_ref "$ref" --refspec-pattern invalid_ref "$ref" '--refspec-pattern --allow-onelevel' ref='/foo' -invalid_ref NOT_MINGW "$ref" -invalid_ref NOT_MINGW "$ref" --allow-onelevel -invalid_ref NOT_MINGW "$ref" --refspec-pattern -invalid_ref NOT_MINGW "$ref" '--refspec-pattern --allow-onelevel' -invalid_ref NOT_MINGW "$ref" --normalize -valid_ref NOT_MINGW "$ref" '--allow-onelevel --normalize' -invalid_ref NOT_MINGW "$ref" '--refspec-pattern --normalize' -valid_ref NOT_MINGW "$ref" '--refspec-pattern --allow-onelevel --normalize' +invalid_ref !MINGW "$ref" +invalid_ref !MINGW "$ref" --allow-onelevel +invalid_ref !MINGW "$ref" --refspec-pattern +invalid_ref !MINGW "$ref" '--refspec-pattern --allow-onelevel' +invalid_ref !MINGW "$ref" --normalize +valid_ref !MINGW "$ref" '--allow-onelevel --normalize' +invalid_ref !MINGW "$ref" '--refspec-pattern --normalize' +valid_ref !MINGW "$ref" '--refspec-pattern --allow-onelevel --normalize' test_expect_success "check-ref-format --branch @{-1}" ' T=$(git write-tree) && @@ -161,7 +164,7 @@ test_expect_success 'check-ref-format --branch from subdir' ' valid_ref_normalized() { prereq= case $1 in - [A-Z]*) + [A-Z!]*) prereq=$1 shift esac @@ -173,7 +176,7 @@ valid_ref_normalized() { invalid_ref_normalized() { prereq= case $1 in - [A-Z]*) + [A-Z!]*) prereq=$1 shift esac @@ -184,10 +187,10 @@ invalid_ref_normalized() { valid_ref_normalized 'heads/foo' 'heads/foo' valid_ref_normalized 'refs///heads/foo' 'refs/heads/foo' -valid_ref_normalized NOT_MINGW '/heads/foo' 'heads/foo' +valid_ref_normalized !MINGW '/heads/foo' 'heads/foo' valid_ref_normalized '///heads/foo' 'heads/foo' invalid_ref_normalized 'foo' -invalid_ref_normalized NOT_MINGW '/foo' +invalid_ref_normalized !MINGW '/foo' invalid_ref_normalized 'heads/foo/../bar' invalid_ref_normalized 'heads/./foo' invalid_ref_normalized 'heads\foo' diff --git a/t/t1403-show-ref.sh b/t/t1403-show-ref.sh index 3e500ed7da..7e10bcfe39 100755 --- a/t/t1403-show-ref.sh +++ b/t/t1403-show-ref.sh @@ -28,7 +28,7 @@ test_expect_success 'show-ref' ' >expect && - test_must_fail git show-ref D >actual + test_must_fail git show-ref D >actual && test_cmp expect actual ' @@ -62,7 +62,7 @@ test_expect_success 'show-ref --verify' ' test_must_fail git show-ref --verify tags/A >actual && test_cmp expect actual && - test_must_fail git show-ref --verify D >actual + test_must_fail git show-ref --verify D >actual && test_cmp expect actual ' @@ -78,7 +78,7 @@ test_expect_success 'show-ref --verify -q' ' test_must_fail git show-ref --verify -q tags/A >actual && test_cmp expect actual && - test_must_fail git show-ref --verify -q D >actual + test_must_fail git show-ref --verify -q D >actual && test_cmp expect actual ' @@ -105,10 +105,10 @@ test_expect_success 'show-ref -d' ' test_cmp expect actual && git show-ref -d refs/heads/master >actual && - test_cmp expect actual + test_cmp expect actual && git show-ref -d --verify refs/heads/master >actual && - test_cmp expect actual + test_cmp expect actual && >expect && diff --git a/t/t1404-update-ref-df-conflicts.sh b/t/t1404-update-ref-df-conflicts.sh new file mode 100755 index 0000000000..66bafb5cf4 --- /dev/null +++ b/t/t1404-update-ref-df-conflicts.sh @@ -0,0 +1,107 @@ +#!/bin/sh + +test_description='Test git update-ref with D/F conflicts' +. ./test-lib.sh + +test_update_rejected () { + prefix="$1" && + before="$2" && + pack="$3" && + create="$4" && + error="$5" && + printf "create $prefix/%s $C\n" $before | + git update-ref --stdin && + git for-each-ref $prefix >unchanged && + if $pack + then + git pack-refs --all + fi && + printf "create $prefix/%s $C\n" $create >input && + test_must_fail git update-ref --stdin <input 2>output.err && + grep -F "$error" output.err && + git for-each-ref $prefix >actual && + test_cmp unchanged actual +} + +Q="'" + +test_expect_success 'setup' ' + + git commit --allow-empty -m Initial && + C=$(git rev-parse HEAD) + +' + +test_expect_success 'existing loose ref is a simple prefix of new' ' + + prefix=refs/1l && + test_update_rejected $prefix "a c e" false "b c/x d" \ + "$Q$prefix/c$Q exists; cannot create $Q$prefix/c/x$Q" + +' + +test_expect_success 'existing packed ref is a simple prefix of new' ' + + prefix=refs/1p && + test_update_rejected $prefix "a c e" true "b c/x d" \ + "$Q$prefix/c$Q exists; cannot create $Q$prefix/c/x$Q" + +' + +test_expect_success 'existing loose ref is a deeper prefix of new' ' + + prefix=refs/2l && + test_update_rejected $prefix "a c e" false "b c/x/y d" \ + "$Q$prefix/c$Q exists; cannot create $Q$prefix/c/x/y$Q" + +' + +test_expect_success 'existing packed ref is a deeper prefix of new' ' + + prefix=refs/2p && + test_update_rejected $prefix "a c e" true "b c/x/y d" \ + "$Q$prefix/c$Q exists; cannot create $Q$prefix/c/x/y$Q" + +' + +test_expect_success 'new ref is a simple prefix of existing loose' ' + + prefix=refs/3l && + test_update_rejected $prefix "a c/x e" false "b c d" \ + "$Q$prefix/c/x$Q exists; cannot create $Q$prefix/c$Q" + +' + +test_expect_success 'new ref is a simple prefix of existing packed' ' + + prefix=refs/3p && + test_update_rejected $prefix "a c/x e" true "b c d" \ + "$Q$prefix/c/x$Q exists; cannot create $Q$prefix/c$Q" + +' + +test_expect_success 'new ref is a deeper prefix of existing loose' ' + + prefix=refs/4l && + test_update_rejected $prefix "a c/x/y e" false "b c d" \ + "$Q$prefix/c/x/y$Q exists; cannot create $Q$prefix/c$Q" + +' + +test_expect_success 'new ref is a deeper prefix of existing packed' ' + + prefix=refs/4p && + test_update_rejected $prefix "a c/x/y e" true "b c d" \ + "$Q$prefix/c/x/y$Q exists; cannot create $Q$prefix/c$Q" + +' + +test_expect_success 'one new ref is a simple prefix of another' ' + + prefix=refs/5 && + test_update_rejected $prefix "a e" false "b c c/x d" \ + "cannot process $Q$prefix/c$Q and $Q$prefix/c/x$Q at the same time" + +' + +test_done diff --git a/t/t1410-reflog.sh b/t/t1410-reflog.sh index 236b13a3ab..17a194bfa6 100755 --- a/t/t1410-reflog.sh +++ b/t/t1410-reflog.sh @@ -100,7 +100,8 @@ test_expect_success setup ' check_fsck && - test_line_count = 4 .git/logs/refs/heads/master + git reflog refs/heads/master >output && + test_line_count = 4 output ' test_expect_success rewind ' @@ -116,7 +117,8 @@ test_expect_success rewind ' check_have A B C D E F G H I J K L && - test_line_count = 5 .git/logs/refs/heads/master + git reflog refs/heads/master >output && + test_line_count = 5 output ' test_expect_success 'corrupt and check' ' @@ -134,7 +136,8 @@ test_expect_success 'reflog expire --dry-run should not touch reflog' ' --stale-fix \ --all && - test_line_count = 5 .git/logs/refs/heads/master && + git reflog refs/heads/master >output && + test_line_count = 5 output && check_fsck "missing blob $F" ' @@ -147,7 +150,8 @@ test_expect_success 'reflog expire' ' --stale-fix \ --all && - test_line_count = 2 .git/logs/refs/heads/master && + git reflog refs/heads/master >output && + test_line_count = 2 output && check_fsck "dangling commit $K" ' @@ -213,7 +217,8 @@ test_expect_success 'delete' ' test_expect_success 'rewind2' ' test_tick && git reset --hard HEAD~2 && - test_line_count = 4 .git/logs/refs/heads/master + git reflog refs/heads/master >output && + test_line_count = 4 output ' test_expect_success '--expire=never' ' @@ -222,7 +227,8 @@ test_expect_success '--expire=never' ' --expire=never \ --expire-unreachable=never \ --all && - test_line_count = 4 .git/logs/refs/heads/master + git reflog refs/heads/master >output && + test_line_count = 4 output ' test_expect_success 'gc.reflogexpire=never' ' @@ -230,7 +236,8 @@ test_expect_success 'gc.reflogexpire=never' ' git config gc.reflogexpire never && git config gc.reflogexpireunreachable never && git reflog expire --verbose --all && - test_line_count = 4 .git/logs/refs/heads/master + git reflog refs/heads/master >output && + test_line_count = 4 output ' test_expect_success 'gc.reflogexpire=false' ' @@ -238,11 +245,97 @@ test_expect_success 'gc.reflogexpire=false' ' git config gc.reflogexpire false && git config gc.reflogexpireunreachable false && git reflog expire --verbose --all && - test_line_count = 4 .git/logs/refs/heads/master && + git reflog refs/heads/master >output && + test_line_count = 4 output && git config --unset gc.reflogexpire && git config --unset gc.reflogexpireunreachable ' +test_expect_success 'checkout should not delete log for packed ref' ' + test $(git reflog master | wc -l) = 4 && + git branch foo && + git pack-refs --all && + git checkout foo && + test $(git reflog master | wc -l) = 4 +' + +test_expect_success 'stale dirs do not cause d/f conflicts (reflogs on)' ' + test_when_finished "git branch -d one || git branch -d one/two" && + + git branch one/two master && + echo "one/two@{0} branch: Created from master" >expect && + git log -g --format="%gd %gs" one/two >actual && + test_cmp expect actual && + git branch -d one/two && + + # now logs/refs/heads/one is a stale directory, but + # we should move it out of the way to create "one" reflog + git branch one master && + echo "one@{0} branch: Created from master" >expect && + git log -g --format="%gd %gs" one >actual && + test_cmp expect actual +' + +test_expect_success 'stale dirs do not cause d/f conflicts (reflogs off)' ' + test_when_finished "git branch -d one || git branch -d one/two" && + + git branch one/two master && + echo "one/two@{0} branch: Created from master" >expect && + git log -g --format="%gd %gs" one/two >actual && + test_cmp expect actual && + git branch -d one/two && + + # same as before, but we only create a reflog for "one" if + # it already exists, which it does not + git -c core.logallrefupdates=false branch one master && + : >expect && + git log -g --format="%gd %gs" one >actual && + test_cmp expect actual +' + +# Triggering the bug detected by this test requires a newline to fall +# exactly BUFSIZ-1 bytes from the end of the file. We don't know +# what that value is, since it's platform dependent. However, if +# we choose some value N, we also catch any D which divides N evenly +# (since we will read backwards in chunks of D). So we choose 8K, +# which catches glibc (with an 8K BUFSIZ) and *BSD (1K). +# +# Each line is 114 characters, so we need 75 to still have a few before the +# last 8K. The 89-character padding on the final entry lines up our +# newline exactly. +test_expect_success 'parsing reverse reflogs at BUFSIZ boundaries' ' + git checkout -b reflogskip && + z38=00000000000000000000000000000000000000 && + ident="abc <xyz> 0000000001 +0000" && + for i in $(test_seq 1 75); do + printf "$z38%02d $z38%02d %s\t" $i $(($i+1)) "$ident" && + if test $i = 75; then + for j in $(test_seq 1 89); do + printf X + done + else + printf X + fi && + printf "\n" + done >.git/logs/refs/heads/reflogskip && + git rev-parse reflogskip@{73} >actual && + echo ${z38}03 >expect && + test_cmp expect actual +' + +test_expect_success 'no segfaults for reflog containing non-commit sha1s' ' + git update-ref --create-reflog -m "Creating ref" \ + refs/tests/tree-in-reflog HEAD && + git update-ref -m "Forcing tree" refs/tests/tree-in-reflog HEAD^{tree} && + git update-ref -m "Restoring to commit" refs/tests/tree-in-reflog HEAD && + git reflog refs/tests/tree-in-reflog +' + +test_expect_failure 'reflog with non-commit entries displays all entries' ' + git reflog refs/tests/tree-in-reflog >actual && + test_line_count = 3 actual +' + test_done diff --git a/t/t1411-reflog-show.sh b/t/t1411-reflog-show.sh index 6f47c0dd0e..6ac7734d79 100755 --- a/t/t1411-reflog-show.sh +++ b/t/t1411-reflog-show.sh @@ -138,7 +138,7 @@ test_expect_success '--date magic does not override explicit @{0} syntax' ' : >expect test_expect_success 'empty reflog file' ' git branch empty && - : >.git/logs/refs/heads/empty && + git reflog expire --expire=all refs/heads/empty && git log -g empty >actual && test_cmp expect actual @@ -166,4 +166,9 @@ test_expect_success 'git log -g -p shows diffs vs. parents' ' test_cmp expect actual ' +test_expect_success 'reflog exists works' ' + git reflog exists refs/heads/master && + ! git reflog exists refs/heads/nonexistent +' + test_done diff --git a/t/t1413-reflog-detach.sh b/t/t1413-reflog-detach.sh new file mode 100755 index 0000000000..c730600d8a --- /dev/null +++ b/t/t1413-reflog-detach.sh @@ -0,0 +1,70 @@ +#!/bin/sh + +test_description='Test reflog interaction with detached HEAD' +. ./test-lib.sh + +reset_state () { + git checkout master && + cp saved_reflog .git/logs/HEAD +} + +test_expect_success setup ' + test_tick && + git commit --allow-empty -m initial && + git branch side && + test_tick && + git commit --allow-empty -m second && + cat .git/logs/HEAD >saved_reflog +' + +test_expect_success baseline ' + reset_state && + git rev-parse master master^ >expect && + git log -g --format=%H >actual && + test_cmp expect actual +' + +test_expect_success 'switch to branch' ' + reset_state && + git rev-parse side master master^ >expect && + git checkout side && + git log -g --format=%H >actual && + test_cmp expect actual +' + +test_expect_success 'detach to other' ' + reset_state && + git rev-parse master side master master^ >expect && + git checkout side && + git checkout master^0 && + git log -g --format=%H >actual && + test_cmp expect actual +' + +test_expect_success 'detach to self' ' + reset_state && + git rev-parse master master master^ >expect && + git checkout master^0 && + git log -g --format=%H >actual && + test_cmp expect actual +' + +test_expect_success 'attach to self' ' + reset_state && + git rev-parse master master master master^ >expect && + git checkout master^0 && + git checkout master && + git log -g --format=%H >actual && + test_cmp expect actual +' + +test_expect_success 'attach to other' ' + reset_state && + git rev-parse side master master master^ >expect && + git checkout master^0 && + git checkout side && + git log -g --format=%H >actual && + test_cmp expect actual +' + +test_done diff --git a/t/t1430-bad-ref-name.sh b/t/t1430-bad-ref-name.sh new file mode 100755 index 0000000000..c465abe8e3 --- /dev/null +++ b/t/t1430-bad-ref-name.sh @@ -0,0 +1,224 @@ +#!/bin/sh + +test_description='Test handling of ref names that check-ref-format rejects' +. ./test-lib.sh + +test_expect_success setup ' + test_commit one && + test_commit two +' + +test_expect_success 'fast-import: fail on invalid branch name ".badbranchname"' ' + test_when_finished "rm -f .git/objects/pack_* .git/objects/index_*" && + cat >input <<-INPUT_END && + commit .badbranchname + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + corrupt + COMMIT + + from refs/heads/master + + INPUT_END + test_must_fail git fast-import <input +' + +test_expect_success 'fast-import: fail on invalid branch name "bad[branch]name"' ' + test_when_finished "rm -f .git/objects/pack_* .git/objects/index_*" && + cat >input <<-INPUT_END && + commit bad[branch]name + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + corrupt + COMMIT + + from refs/heads/master + + INPUT_END + test_must_fail git fast-import <input +' + +test_expect_success 'git branch shows badly named ref as warning' ' + cp .git/refs/heads/master .git/refs/heads/broken...ref && + test_when_finished "rm -f .git/refs/heads/broken...ref" && + git branch >output 2>error && + grep -e "broken\.\.\.ref" error && + ! grep -e "broken\.\.\.ref" output +' + +test_expect_success 'branch -d can delete badly named ref' ' + cp .git/refs/heads/master .git/refs/heads/broken...ref && + test_when_finished "rm -f .git/refs/heads/broken...ref" && + git branch -d broken...ref && + git branch >output 2>error && + ! grep -e "broken\.\.\.ref" error && + ! grep -e "broken\.\.\.ref" output +' + +test_expect_success 'branch -D can delete badly named ref' ' + cp .git/refs/heads/master .git/refs/heads/broken...ref && + test_when_finished "rm -f .git/refs/heads/broken...ref" && + git branch -D broken...ref && + git branch >output 2>error && + ! grep -e "broken\.\.\.ref" error && + ! grep -e "broken\.\.\.ref" output +' + +test_expect_success 'branch -D cannot delete non-ref in .git dir' ' + echo precious >.git/my-private-file && + echo precious >expect && + test_must_fail git branch -D ../../my-private-file && + test_cmp expect .git/my-private-file +' + +test_expect_success 'branch -D cannot delete ref in .git dir' ' + git rev-parse HEAD >.git/my-private-file && + git rev-parse HEAD >expect && + git branch foo/legit && + test_must_fail git branch -D foo////./././../../../my-private-file && + test_cmp expect .git/my-private-file +' + +test_expect_success 'branch -D cannot delete absolute path' ' + git branch -f extra && + test_must_fail git branch -D "$(pwd)/.git/refs/heads/extra" && + test_cmp_rev HEAD extra +' + +test_expect_success 'git branch cannot create a badly named ref' ' + test_when_finished "rm -f .git/refs/heads/broken...ref" && + test_must_fail git branch broken...ref && + git branch >output 2>error && + ! grep -e "broken\.\.\.ref" error && + ! grep -e "broken\.\.\.ref" output +' + +test_expect_success 'branch -m cannot rename to a bad ref name' ' + test_when_finished "rm -f .git/refs/heads/broken...ref" && + test_might_fail git branch -D goodref && + git branch goodref && + test_must_fail git branch -m goodref broken...ref && + test_cmp_rev master goodref && + git branch >output 2>error && + ! grep -e "broken\.\.\.ref" error && + ! grep -e "broken\.\.\.ref" output +' + +test_expect_failure 'branch -m can rename from a bad ref name' ' + cp .git/refs/heads/master .git/refs/heads/broken...ref && + test_when_finished "rm -f .git/refs/heads/broken...ref" && + git branch -m broken...ref renamed && + test_cmp_rev master renamed && + git branch >output 2>error && + ! grep -e "broken\.\.\.ref" error && + ! grep -e "broken\.\.\.ref" output +' + +test_expect_success 'push cannot create a badly named ref' ' + test_when_finished "rm -f .git/refs/heads/broken...ref" && + test_must_fail git push "file://$(pwd)" HEAD:refs/heads/broken...ref && + git branch >output 2>error && + ! grep -e "broken\.\.\.ref" error && + ! grep -e "broken\.\.\.ref" output +' + +test_expect_failure 'push --mirror can delete badly named ref' ' + top=$(pwd) && + git init src && + git init dest && + + ( + cd src && + test_commit one + ) && + ( + cd dest && + test_commit two && + git checkout --detach && + cp .git/refs/heads/master .git/refs/heads/broken...ref + ) && + git -C src push --mirror "file://$top/dest" && + git -C dest branch >output 2>error && + ! grep -e "broken\.\.\.ref" error && + ! grep -e "broken\.\.\.ref" output +' + +test_expect_success 'rev-parse skips symref pointing to broken name' ' + test_when_finished "rm -f .git/refs/heads/broken...ref" && + git branch shadow one && + cp .git/refs/heads/master .git/refs/heads/broken...ref && + git symbolic-ref refs/tags/shadow refs/heads/broken...ref && + + git rev-parse --verify one >expect && + git rev-parse --verify shadow >actual 2>err && + test_cmp expect actual && + test_i18ngrep "ignoring.*refs/tags/shadow" err +' + +test_expect_success 'update-ref --no-deref -d can delete reference to broken name' ' + git symbolic-ref refs/heads/badname refs/heads/broken...ref && + test_when_finished "rm -f .git/refs/heads/badname" && + test_path_is_file .git/refs/heads/badname && + git update-ref --no-deref -d refs/heads/badname && + test_path_is_missing .git/refs/heads/badname +' + +test_expect_success 'update-ref -d can delete broken name' ' + cp .git/refs/heads/master .git/refs/heads/broken...ref && + test_when_finished "rm -f .git/refs/heads/broken...ref" && + git update-ref -d refs/heads/broken...ref && + git branch >output 2>error && + ! grep -e "broken\.\.\.ref" error && + ! grep -e "broken\.\.\.ref" output +' + +test_expect_success 'update-ref -d cannot delete non-ref in .git dir' ' + echo precious >.git/my-private-file && + echo precious >expect && + test_must_fail git update-ref -d my-private-file && + test_cmp expect .git/my-private-file +' + +test_expect_success 'update-ref -d cannot delete absolute path' ' + git branch -f extra && + test_must_fail git update-ref -d "$(pwd)/.git/refs/heads/extra" && + test_cmp_rev HEAD extra +' + +test_expect_success 'update-ref --stdin fails create with bad ref name' ' + echo "create ~a refs/heads/master" >stdin && + test_must_fail git update-ref --stdin <stdin 2>err && + grep "fatal: invalid ref format: ~a" err +' + +test_expect_success 'update-ref --stdin fails update with bad ref name' ' + echo "update ~a refs/heads/master" >stdin && + test_must_fail git update-ref --stdin <stdin 2>err && + grep "fatal: invalid ref format: ~a" err +' + +test_expect_success 'update-ref --stdin fails delete with bad ref name' ' + echo "delete ~a refs/heads/master" >stdin && + test_must_fail git update-ref --stdin <stdin 2>err && + grep "fatal: invalid ref format: ~a" err +' + +test_expect_success 'update-ref --stdin -z fails create with bad ref name' ' + printf "%s\0" "create ~a " refs/heads/master >stdin && + test_must_fail git update-ref -z --stdin <stdin 2>err && + grep "fatal: invalid ref format: ~a " err +' + +test_expect_success 'update-ref --stdin -z fails update with bad ref name' ' + printf "%s\0" "update ~a" refs/heads/master "" >stdin && + test_must_fail git update-ref -z --stdin <stdin 2>err && + grep "fatal: invalid ref format: ~a" err +' + +test_expect_success 'update-ref --stdin -z fails delete with bad ref name' ' + printf "%s\0" "delete ~a" refs/heads/master >stdin && + test_must_fail git update-ref -z --stdin <stdin 2>err && + grep "fatal: invalid ref format: ~a" err +' + +test_done diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh index a5589e2da7..e66b7cb697 100755 --- a/t/t1450-fsck.sh +++ b/t/t1450-fsck.sh @@ -69,7 +69,7 @@ test_expect_success 'object with bad sha1' ' git update-ref refs/heads/bogus $cmt && test_when_finished "git update-ref -d refs/heads/bogus" && - test_might_fail git fsck 2>out && + test_must_fail git fsck 2>out && cat out && grep "$sha.*corrupt" out ' @@ -77,11 +77,31 @@ test_expect_success 'object with bad sha1' ' test_expect_success 'branch pointing to non-commit' ' git rev-parse HEAD^{tree} >.git/refs/heads/invalid && test_when_finished "git update-ref -d refs/heads/invalid" && - git fsck 2>out && + test_must_fail git fsck 2>out && cat out && grep "not a commit" out ' +test_expect_success 'HEAD link pointing at a funny object' ' + test_when_finished "mv .git/SAVED_HEAD .git/HEAD" && + mv .git/HEAD .git/SAVED_HEAD && + echo 0000000000000000000000000000000000000000 >.git/HEAD && + # avoid corrupt/broken HEAD from interfering with repo discovery + test_must_fail env GIT_DIR=.git git fsck 2>out && + cat out && + grep "detached HEAD points" out +' + +test_expect_success 'HEAD link pointing at a funny place' ' + test_when_finished "mv .git/SAVED_HEAD .git/HEAD" && + mv .git/HEAD .git/SAVED_HEAD && + echo "ref: refs/funny/place" >.git/HEAD && + # avoid corrupt/broken HEAD from interfering with repo discovery + test_must_fail env GIT_DIR=.git git fsck 2>out && + cat out && + grep "HEAD points to something strange" out +' + test_expect_success 'email without @ is okay' ' git cat-file commit HEAD >basis && sed "s/@/AT/" basis >okay && @@ -101,7 +121,7 @@ test_expect_success 'email with embedded > is not okay' ' test_when_finished "remove_object $new" && git update-ref refs/heads/bogus "$new" && test_when_finished "git update-ref -d refs/heads/bogus" && - git fsck 2>out && + test_must_fail git fsck 2>out && cat out && grep "error in commit $new" out ' @@ -113,7 +133,7 @@ test_expect_success 'missing < email delimiter is reported nicely' ' test_when_finished "remove_object $new" && git update-ref refs/heads/bogus "$new" && test_when_finished "git update-ref -d refs/heads/bogus" && - git fsck 2>out && + test_must_fail git fsck 2>out && cat out && grep "error in commit $new.* - bad name" out ' @@ -125,7 +145,7 @@ test_expect_success 'missing email is reported nicely' ' test_when_finished "remove_object $new" && git update-ref refs/heads/bogus "$new" && test_when_finished "git update-ref -d refs/heads/bogus" && - git fsck 2>out && + test_must_fail git fsck 2>out && cat out && grep "error in commit $new.* - missing email" out ' @@ -137,7 +157,7 @@ test_expect_success '> in name is reported' ' test_when_finished "remove_object $new" && git update-ref refs/heads/bogus "$new" && test_when_finished "git update-ref -d refs/heads/bogus" && - git fsck 2>out && + test_must_fail git fsck 2>out && cat out && grep "error in commit $new" out ' @@ -151,11 +171,43 @@ test_expect_success 'integer overflow in timestamps is reported' ' test_when_finished "remove_object $new" && git update-ref refs/heads/bogus "$new" && test_when_finished "git update-ref -d refs/heads/bogus" && - git fsck 2>out && + test_must_fail git fsck 2>out && cat out && grep "error in commit $new.*integer overflow" out ' +test_expect_success 'commit with NUL in header' ' + git cat-file commit HEAD >basis && + sed "s/author ./author Q/" <basis | q_to_nul >commit-NUL-header && + new=$(git hash-object -t commit -w --stdin <commit-NUL-header) && + test_when_finished "remove_object $new" && + git update-ref refs/heads/bogus "$new" && + test_when_finished "git update-ref -d refs/heads/bogus" && + test_must_fail git fsck 2>out && + cat out && + grep "error in commit $new.*unterminated header: NUL at offset" out +' + +test_expect_success 'malformatted tree object' ' + test_when_finished "git update-ref -d refs/tags/wrong" && + test_when_finished "remove_object \$T" && + T=$( + GIT_INDEX_FILE=test-index && + export GIT_INDEX_FILE && + rm -f test-index && + >x && + git add x && + T=$(git write-tree) && + ( + git cat-file tree $T && + git cat-file tree $T + ) | + git hash-object -w -t tree --stdin + ) && + test_must_fail git fsck 2>out && + grep "error in tree .*contains duplicate file entries" out +' + test_expect_success 'tag pointing to nonexistent' ' cat >invalid-tag <<-\EOF && object ffffffffffffffffffffffffffffffffffffffff @@ -194,6 +246,68 @@ test_expect_success 'tag pointing to something else than its type' ' test_must_fail git fsck --tags ' +test_expect_success 'tag with incorrect tag name & missing tagger' ' + sha=$(git rev-parse HEAD) && + cat >wrong-tag <<-EOF && + object $sha + type commit + tag wrong name format + + This is an invalid tag. + EOF + + tag=$(git hash-object -t tag -w --stdin <wrong-tag) && + test_when_finished "remove_object $tag" && + echo $tag >.git/refs/tags/wrong && + test_when_finished "git update-ref -d refs/tags/wrong" && + git fsck --tags 2>out && + + cat >expect <<-EOF && + warning in tag $tag: badTagName: invalid '\''tag'\'' name: wrong name format + warning in tag $tag: missingTaggerEntry: invalid format - expected '\''tagger'\'' line + EOF + test_cmp expect out +' + +test_expect_success 'tag with bad tagger' ' + sha=$(git rev-parse HEAD) && + cat >wrong-tag <<-EOF && + object $sha + type commit + tag not-quite-wrong + tagger Bad Tagger Name + + This is an invalid tag. + EOF + + tag=$(git hash-object --literally -t tag -w --stdin <wrong-tag) && + test_when_finished "remove_object $tag" && + echo $tag >.git/refs/tags/wrong && + test_when_finished "git update-ref -d refs/tags/wrong" && + test_must_fail git fsck --tags 2>out && + grep "error in tag .*: invalid author/committer" out +' + +test_expect_success 'tag with NUL in header' ' + sha=$(git rev-parse HEAD) && + q_to_nul >tag-NUL-header <<-EOF && + object $sha + type commit + tag contains-Q-in-header + tagger T A Gger <tagger@example.com> 1234567890 -0000 + + This is an invalid tag. + EOF + + tag=$(git hash-object --literally -t tag -w --stdin <tag-NUL-header) && + test_when_finished "remove_object $tag" && + echo $tag >.git/refs/tags/wrong && + test_when_finished "git update-ref -d refs/tags/wrong" && + test_must_fail git fsck --tags 2>out && + cat out && + grep "error in tag $tag.*unterminated header: NUL at offset" out +' + test_expect_success 'cleaned up' ' git fsck >actual 2>&1 && test_cmp empty actual @@ -225,6 +339,17 @@ test_expect_success 'rev-list --verify-objects with bad sha1' ' grep -q "error: sha1 mismatch 63ffffffffffffffffffffffffffffffffffffff" out ' +test_expect_success 'force fsck to ignore double author' ' + git cat-file commit HEAD >basis && + sed "s/^author .*/&,&/" <basis | tr , \\n >multiple-authors && + new=$(git hash-object -t commit -w --stdin <multiple-authors) && + test_when_finished "remove_object $new" && + git update-ref refs/heads/bogus "$new" && + test_when_finished "git update-ref -d refs/heads/bogus" && + test_must_fail git fsck && + git -c fsck.multipleAuthors=ignore fsck +' + _bz='\0' _bz5="$_bz$_bz$_bz$_bz$_bz" _bz20="$_bz5$_bz5$_bz5$_bz5" @@ -302,4 +427,82 @@ test_expect_success 'fsck allows .Ňit' ' ) ' +# create a static test repo which is broken by omitting +# one particular object ($1, which is looked up via rev-parse +# in the new repository). +create_repo_missing () { + rm -rf missing && + git init missing && + ( + cd missing && + git commit -m one --allow-empty && + mkdir subdir && + echo content >subdir/file && + git add subdir/file && + git commit -m two && + unrelated=$(echo unrelated | git hash-object --stdin -w) && + git tag -m foo tag $unrelated && + sha1=$(git rev-parse --verify "$1") && + path=$(echo $sha1 | sed 's|..|&/|') && + rm .git/objects/$path + ) +} + +test_expect_success 'fsck notices missing blob' ' + create_repo_missing HEAD:subdir/file && + test_must_fail git -C missing fsck +' + +test_expect_success 'fsck notices missing subtree' ' + create_repo_missing HEAD:subdir && + test_must_fail git -C missing fsck +' + +test_expect_success 'fsck notices missing root tree' ' + create_repo_missing HEAD^{tree} && + test_must_fail git -C missing fsck +' + +test_expect_success 'fsck notices missing parent' ' + create_repo_missing HEAD^ && + test_must_fail git -C missing fsck +' + +test_expect_success 'fsck notices missing tagged object' ' + create_repo_missing tag^{blob} && + test_must_fail git -C missing fsck +' + +test_expect_success 'fsck notices ref pointing to missing commit' ' + create_repo_missing HEAD && + test_must_fail git -C missing fsck +' + +test_expect_success 'fsck notices ref pointing to missing tag' ' + create_repo_missing tag && + test_must_fail git -C missing fsck +' + +test_expect_success 'fsck --connectivity-only' ' + rm -rf connectivity-only && + git init connectivity-only && + ( + cd connectivity-only && + touch empty && + git add empty && + test_commit empty && + empty=.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 && + rm -f $empty && + echo invalid >$empty && + test_must_fail git fsck --strict && + git fsck --strict --connectivity-only && + tree=$(git rev-parse HEAD:) && + suffix=${tree#??} && + tree=.git/objects/${tree%$suffix}/$suffix && + rm -f $tree && + echo invalid >$tree && + test_must_fail git fsck --strict --connectivity-only + ) +' + test_done diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh index 8f36aa9fc4..cc5b870e58 100755 --- a/t/t1501-worktree.sh +++ b/t/t1501-worktree.sh @@ -346,4 +346,81 @@ test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' ' test_cmp expected actual ' +test_expect_success 'Multi-worktree setup' ' + mkdir work && + mkdir -p repo.git/repos/foo && + cp repo.git/HEAD repo.git/index repo.git/repos/foo && + test_might_fail cp repo.git/sharedindex.* repo.git/repos/foo && + sane_unset GIT_DIR GIT_CONFIG GIT_WORK_TREE +' + +test_expect_success 'GIT_DIR set (1)' ' + echo "gitdir: repo.git/repos/foo" >gitfile && + echo ../.. >repo.git/repos/foo/commondir && + ( + cd work && + GIT_DIR=../gitfile git rev-parse --git-common-dir >actual && + test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect && + test_cmp expect actual + ) +' + +test_expect_success 'GIT_DIR set (2)' ' + echo "gitdir: repo.git/repos/foo" >gitfile && + echo "$(pwd)/repo.git" >repo.git/repos/foo/commondir && + ( + cd work && + GIT_DIR=../gitfile git rev-parse --git-common-dir >actual && + test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect && + test_cmp expect actual + ) +' + +test_expect_success 'Auto discovery' ' + echo "gitdir: repo.git/repos/foo" >.git && + echo ../.. >repo.git/repos/foo/commondir && + ( + cd work && + git rev-parse --git-common-dir >actual && + test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect && + test_cmp expect actual && + echo haha >data1 && + git add data1 && + git ls-files --full-name :/ | grep data1 >actual && + echo work/data1 >expect && + test_cmp expect actual + ) +' + +test_expect_success '$GIT_DIR/common overrides core.worktree' ' + mkdir elsewhere && + git --git-dir=repo.git config core.worktree "$TRASH_DIRECTORY/elsewhere" && + echo "gitdir: repo.git/repos/foo" >.git && + echo ../.. >repo.git/repos/foo/commondir && + ( + cd work && + git rev-parse --git-common-dir >actual && + test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect && + test_cmp expect actual && + echo haha >data2 && + git add data2 && + git ls-files --full-name :/ | grep data2 >actual && + echo work/data2 >expect && + test_cmp expect actual + ) +' + +test_expect_success '$GIT_WORK_TREE overrides $GIT_DIR/common' ' + echo "gitdir: repo.git/repos/foo" >.git && + echo ../.. >repo.git/repos/foo/commondir && + ( + cd work && + echo haha >data3 && + git --git-dir=../.git --work-tree=. add data3 && + git ls-files --full-name -- :/ | grep data3 >actual && + echo data3 >expect && + test_cmp expect actual + ) +' + test_done diff --git a/t/t1502-rev-parse-parseopt.sh b/t/t1502-rev-parse-parseopt.sh index 922423e7d0..310f93fd30 100755 --- a/t/t1502-rev-parse-parseopt.sh +++ b/t/t1502-rev-parse-parseopt.sh @@ -3,7 +3,40 @@ test_description='test git rev-parse --parseopt' . ./test-lib.sh -sed -e 's/^|//' >expect <<\END_EXPECT +test_expect_success 'setup optionspec' ' + sed -e "s/^|//" >optionspec <<\EOF +|some-command [options] <args>... +| +|some-command does foo and bar! +|-- +|h,help show the help +| +|foo some nifty option --foo +|bar= some cool option --bar with an argument +|b,baz a short and long option +| +| An option group Header +|C? option C with an optional argument +|d,data? short and long option with an optional argument +| +| Argument hints +|B=arg short option required argument +|bar2=arg long option required argument +|e,fuz=with-space short and long option required argument +|s?some short option optional argument +|long?data long option optional argument +|g,fluf?path short and long option optional argument +|longest=very-long-argument-hint a very long argument hint +|pair=key=value with an equals sign in the hint +|short-hint=a with a one symbol hint +| +|Extras +|extra1 line above used to cause a segfault but no longer does +EOF +' + +test_expect_success 'test --parseopt help output' ' + sed -e "s/^|//" >expect <<\END_EXPECT && |cat <<\EOF |usage: some-command [options] <args>... | @@ -19,7 +52,7 @@ sed -e 's/^|//' >expect <<\END_EXPECT | -d, --data[=...] short and long option with an optional argument | |Argument hints -| -b <arg> short option required argument +| -B <arg> short option required argument | --bar2 <arg> long option required argument | -e, --fuz <with-space> | short and long option required argument @@ -28,49 +61,23 @@ sed -e 's/^|//' >expect <<\END_EXPECT | -g, --fluf[=<path>] short and long option optional argument | --longest <very-long-argument-hint> | a very long argument hint +| --pair <key=value> with an equals sign in the hint +| --short-hint <a> with a one symbol hint | |Extras | --extra1 line above used to cause a segfault but no longer does | |EOF END_EXPECT - -sed -e 's/^|//' >optionspec <<\EOF -|some-command [options] <args>... -| -|some-command does foo and bar! -|-- -|h,help show the help -| -|foo some nifty option --foo -|bar= some cool option --bar with an argument -|b,baz a short and long option -| -| An option group Header -|C? option C with an optional argument -|d,data? short and long option with an optional argument -| -| Argument hints -|b=arg short option required argument -|bar2=arg long option required argument -|e,fuz=with-space short and long option required argument -|s?some short option optional argument -|long?data long option optional argument -|g,fluf?path short and long option optional argument -|longest=very-long-argument-hint a very long argument hint -| -|Extras -|extra1 line above used to cause a segfault but no longer does -EOF - -test_expect_success 'test --parseopt help output' ' test_expect_code 129 git rev-parse --parseopt -- -h > output < optionspec && test_i18ncmp expect output ' -cat > expect <<EOF +test_expect_success 'setup expect.1' " + cat > expect <<EOF set -- --foo --bar 'ham' -b -- 'arg' EOF +" test_expect_success 'test --parseopt' ' git rev-parse --parseopt -- --foo --bar=ham --baz arg < optionspec > output && @@ -82,9 +89,11 @@ test_expect_success 'test --parseopt with mixed options and arguments' ' test_cmp expect output ' -cat > expect <<EOF +test_expect_success 'setup expect.2' " + cat > expect <<EOF set -- --foo -- 'arg' '--bar=ham' EOF +" test_expect_success 'test --parseopt with --' ' git rev-parse --parseopt -- --foo -- arg --bar=ham < optionspec > output && @@ -96,54 +105,66 @@ test_expect_success 'test --parseopt --stop-at-non-option' ' test_cmp expect output ' -cat > expect <<EOF +test_expect_success 'setup expect.3' " + cat > expect <<EOF set -- --foo -- '--' 'arg' '--bar=ham' EOF +" test_expect_success 'test --parseopt --keep-dashdash' ' git rev-parse --parseopt --keep-dashdash -- --foo -- arg --bar=ham < optionspec > output && test_cmp expect output ' -cat >expect <<EOF +test_expect_success 'setup expect.4' " + cat >expect <<EOF set -- --foo -- '--' 'arg' '--spam=ham' EOF +" test_expect_success 'test --parseopt --keep-dashdash --stop-at-non-option with --' ' git rev-parse --parseopt --keep-dashdash --stop-at-non-option -- --foo -- arg --spam=ham <optionspec >output && test_cmp expect output ' -cat > expect <<EOF +test_expect_success 'setup expect.5' " + cat > expect <<EOF set -- --foo -- 'arg' '--spam=ham' EOF +" test_expect_success 'test --parseopt --keep-dashdash --stop-at-non-option without --' ' git rev-parse --parseopt --keep-dashdash --stop-at-non-option -- --foo arg --spam=ham <optionspec >output && test_cmp expect output ' -cat > expect <<EOF +test_expect_success 'setup expect.6' " + cat > expect <<EOF set -- --foo --bar='z' --baz -C'Z' --data='A' -- 'arg' EOF +" test_expect_success 'test --parseopt --stuck-long' ' git rev-parse --parseopt --stuck-long -- --foo --bar=z -b arg -CZ -dA <optionspec >output && test_cmp expect output ' -cat > expect <<EOF +test_expect_success 'setup expect.7' " + cat > expect <<EOF set -- --data='' -C --baz -- 'arg' EOF +" test_expect_success 'test --parseopt --stuck-long and empty optional argument' ' git rev-parse --parseopt --stuck-long -- --data= arg -C -b <optionspec >output && test_cmp expect output ' -cat > expect <<EOF +test_expect_success 'setup expect.8' " + cat > expect <<EOF set -- --data --baz -- 'arg' EOF +" test_expect_success 'test --parseopt --stuck-long and long option with unset optional argument' ' git rev-parse --parseopt --stuck-long -- --data arg -b <optionspec >output && diff --git a/t/t1503-rev-parse-verify.sh b/t/t1503-rev-parse-verify.sh index 813cc1b3e2..ab27d0db5c 100755 --- a/t/t1503-rev-parse-verify.sh +++ b/t/t1503-rev-parse-verify.sh @@ -72,15 +72,39 @@ test_expect_success 'fails with any bad rev or many good revs' ' test_expect_success 'fails silently when using -q' ' test_must_fail git rev-parse --verify --quiet 2>error && - test -z "$(cat error)" && + test_must_be_empty error && test_must_fail git rev-parse -q --verify foo 2>error && - test -z "$(cat error)" && + test_must_be_empty error && test_must_fail git rev-parse --verify -q HEAD bar 2>error && - test -z "$(cat error)" && + test_must_be_empty error && test_must_fail git rev-parse --quiet --verify baz HEAD 2>error && - test -z "$(cat error)" && + test_must_be_empty error && test_must_fail git rev-parse -q --verify $HASH2 HEAD 2>error && - test -z "$(cat error)" + test_must_be_empty error +' + +test_expect_success 'fails silently when using -q with deleted reflogs' ' + ref=$(git rev-parse HEAD) && + git update-ref --create-reflog -m "message for refs/test" refs/test "$ref" && + git reflog delete --updateref --rewrite refs/test@{0} && + test_must_fail git rev-parse -q --verify refs/test@{0} >error 2>&1 && + test_must_be_empty error +' + +test_expect_success 'fails silently when using -q with not enough reflogs' ' + ref=$(git rev-parse HEAD) && + git update-ref --create-reflog -m "message for refs/test2" refs/test2 "$ref" && + test_must_fail git rev-parse -q --verify refs/test2@{999} >error 2>&1 && + test_must_be_empty error +' + +test_expect_success 'succeeds silently with -q and reflogs that do not go far back enough in time' ' + ref=$(git rev-parse HEAD) && + git update-ref --create-reflog -m "message for refs/test3" refs/test3 "$ref" && + git rev-parse -q --verify refs/test3@{1.year.ago} >actual 2>error && + test_must_be_empty error && + echo "$ref" >expect && + test_cmp expect actual ' test_expect_success 'no stdout output on error' ' diff --git a/t/t1507-rev-parse-upstream.sh b/t/t1507-rev-parse-upstream.sh index 1978947c41..46ef1f22dc 100755 --- a/t/t1507-rev-parse-upstream.sh +++ b/t/t1507-rev-parse-upstream.sh @@ -150,7 +150,7 @@ test_expect_success 'branch@{u} works when tracking a local branch' ' test_expect_success 'branch@{u} error message when no upstream' ' cat >expect <<-EOF && - fatal: No upstream configured for branch ${sq}non-tracking${sq} + fatal: no upstream configured for branch ${sq}non-tracking${sq} EOF error_message non-tracking@{u} 2>actual && test_i18ncmp expect actual @@ -158,7 +158,7 @@ test_expect_success 'branch@{u} error message when no upstream' ' test_expect_success '@{u} error message when no upstream' ' cat >expect <<-EOF && - fatal: No upstream configured for branch ${sq}master${sq} + fatal: no upstream configured for branch ${sq}master${sq} EOF test_must_fail git rev-parse --verify @{u} 2>actual && test_i18ncmp expect actual @@ -166,7 +166,7 @@ test_expect_success '@{u} error message when no upstream' ' test_expect_success 'branch@{u} error message with misspelt branch' ' cat >expect <<-EOF && - fatal: No such branch: ${sq}no-such-branch${sq} + fatal: no such branch: ${sq}no-such-branch${sq} EOF error_message no-such-branch@{u} 2>actual && test_i18ncmp expect actual @@ -183,7 +183,7 @@ test_expect_success '@{u} error message when not on a branch' ' test_expect_success 'branch@{u} error message if upstream branch not fetched' ' cat >expect <<-EOF && - fatal: Upstream branch ${sq}refs/heads/side${sq} not stored as a remote-tracking branch + fatal: upstream branch ${sq}refs/heads/side${sq} not stored as a remote-tracking branch EOF error_message bad-upstream@{u} 2>actual && test_i18ncmp expect actual diff --git a/t/t1509-root-worktree.sh b/t/t1509-root-worktree.sh index 335420fd87..553a3f601b 100755 --- a/t/t1509-root-worktree.sh +++ b/t/t1509-root-worktree.sh @@ -98,8 +98,16 @@ test_foobar_foobar() { ' } -if ! test_have_prereq POSIXPERM || ! [ -w / ]; then - skip_all="Dangerous test skipped. Read this test if you want to execute it" +if ! test -w / +then + skip_all="Test requiring writable / skipped. Read this test if you want to run it" + test_done +fi + +if test -e /refs || test -e /objects || test -e /info || test -e /hooks || + test -e /.git || test -e /foo || test -e /me +then + skip_all="Skip test that clobbers existing files in /" test_done fi @@ -108,15 +116,16 @@ if [ "$IKNOWWHATIAMDOING" != "YES" ]; then test_done fi -if [ "$UID" = 0 ]; then - skip_all="No you can't run this with root" +if ! test_have_prereq NOT_ROOT +then + skip_all="No you can't run this as root" test_done fi ONE_SHA1=d00491fd7e5bb6fa28c517a0bb32b8b506539d4d test_expect_success 'setup' ' - rm -rf /foo + rm -rf /foo && mkdir /foo && mkdir /foo/bar && echo 1 > /foo/foome && @@ -209,7 +218,7 @@ unset GIT_WORK_TREE test_expect_success 'go to /' 'cd /' test_expect_success 'setup' ' - rm -rf /.git + rm -rf /.git && echo "Initialized empty Git repository in /.git/" > expected && git init > result && test_cmp expected result @@ -232,8 +241,8 @@ say "auto bare gitdir" # DESTROYYYYY!!!!! test_expect_success 'setup' ' - rm -rf /refs /objects /info /hooks - rm /* + rm -rf /refs /objects /info /hooks && + rm -f /expected /ls.expected /me /result && cd / && echo "Initialized empty Git repository in /" > expected && git init --bare > result && diff --git a/t/t1509/prepare-chroot.sh b/t/t1509/prepare-chroot.sh index 62691172e3..6d47e2c725 100755 --- a/t/t1509/prepare-chroot.sh +++ b/t/t1509/prepare-chroot.sh @@ -14,25 +14,45 @@ xmkdir() { R="$1" +[ "$(id -u)" -eq 0 ] && die "This script should not be run as root, what if it does rm -rf /?" [ -n "$R" ] || die "usage: prepare-chroot.sh <root>" [ -x git ] || die "This script needs to be executed at git source code's top directory" -[ -x /bin/busybox ] || die "You need busybox" +if [ -x /bin/busybox ]; then + BB=/bin/busybox +elif [ -x /usr/bin/busybox ]; then + BB=/usr/bin/busybox +else + die "You need busybox" +fi xmkdir "$R" "$R/bin" "$R/etc" "$R/lib" "$R/dev" -[ -c "$R/dev/null" ] || die "/dev/null is missing. Do mknod $R/dev/null c 1 3 && chmod 666 $R/dev/null" +touch "$R/dev/null" echo "root:x:0:0:root:/:/bin/sh" > "$R/etc/passwd" echo "$(id -nu):x:$(id -u):$(id -g)::$(pwd)/t:/bin/sh" >> "$R/etc/passwd" echo "root::0:root" > "$R/etc/group" echo "$(id -ng)::$(id -g):$(id -nu)" >> "$R/etc/group" -[ -x "$R/bin/busybox" ] || cp /bin/busybox "$R/bin/busybox" -[ -x "$R/bin/sh" ] || ln -s /bin/busybox "$R/bin/sh" -[ -x "$R/bin/su" ] || ln -s /bin/busybox "$R/bin/su" +[ -x "$R$BB" ] || cp $BB "$R/bin/busybox" +for cmd in sh su ls expr tr basename rm mkdir mv id uname dirname cat true sed diff; do + ln -f -s /bin/busybox "$R/bin/$cmd" +done mkdir -p "$R$(pwd)" rsync --exclude-from t/t1509/excludes -Ha . "$R$(pwd)" -ldd git | grep '/' | sed 's,.*\s\(/[^ ]*\).*,\1,' | while read i; do - mkdir -p "$R$(dirname $i)" - cp "$i" "$R/$i" +# Fake perl to reduce dependency, t1509 does not use perl, but some +# env might slip through, see test-lib.sh, unset.*PERL_PATH +sed 's|^PERL_PATH=.*|PERL_PATH=/bin/true|' GIT-BUILD-OPTIONS > "$R$(pwd)/GIT-BUILD-OPTIONS" +for cmd in git $BB;do + ldd $cmd | grep '/' | sed 's,.*\s\(/[^ ]*\).*,\1,' | while read i; do + mkdir -p "$R$(dirname $i)" + cp "$i" "$R/$i" + done done -echo "Execute this in root: 'chroot $R /bin/su - $(id -nu)'" +cat <<EOF +All is set up in $R, execute t1509 with the following commands: + +sudo chroot $R /bin/su - $(id -nu) +IKNOWWHATIAMDOING=YES ./t1509-root-worktree.sh -v -i + +When you are done, simply delete $R to clean up +EOF diff --git a/t/t1510-repo-setup.sh b/t/t1510-repo-setup.sh index e1b2a99f10..13ae12dfa7 100755 --- a/t/t1510-repo-setup.sh +++ b/t/t1510-repo-setup.sh @@ -106,6 +106,7 @@ setup_env () { expect () { cat >"$1/expected" <<-EOF setup: git_dir: $2 + setup: git_common_dir: $2 setup: worktree: $3 setup: cwd: $4 setup: prefix: $5 @@ -598,11 +599,20 @@ test_expect_success '#20b/c: core.worktree and core.bare conflict' ' mkdir -p 20b/.git/wt/sub && ( cd 20b/.git && - test_must_fail git symbolic-ref HEAD >/dev/null + test_must_fail git status >/dev/null ) 2>message && grep "core.bare and core.worktree" message ' +test_expect_success '#20d: core.worktree and core.bare OK when working tree not needed' ' + setup_repo 20d non-existent "" true && + mkdir -p 20d/.git/wt/sub && + ( + cd 20d/.git && + git config foo.bar value + ) +' + # Case #21: core.worktree/GIT_WORK_TREE overrides core.bare' ' test_expect_success '#21: setup, core.worktree warns before overriding core.bare' ' setup_repo 21 non-existent "" unset && @@ -611,7 +621,7 @@ test_expect_success '#21: setup, core.worktree warns before overriding core.bare cd 21/.git && GIT_WORK_TREE="$here/21" && export GIT_WORK_TREE && - git symbolic-ref HEAD >/dev/null + git status >/dev/null ) 2>message && ! test -s message @@ -700,13 +710,13 @@ test_expect_success '#22.2: core.worktree and core.bare conflict' ' cd 22/.git && GIT_DIR=. && export GIT_DIR && - test_must_fail git symbolic-ref HEAD 2>result + test_must_fail git status 2>result ) && ( cd 22 && GIT_DIR=.git && export GIT_DIR && - test_must_fail git symbolic-ref HEAD 2>result + test_must_fail git status 2>result ) && grep "core.bare and core.worktree" 22/.git/result && grep "core.bare and core.worktree" 22/result @@ -752,9 +762,8 @@ test_expect_success '#28: core.worktree and core.bare conflict (gitfile case)' ' setup_repo 28 "$here/28" gitfile true && ( cd 28 && - test_must_fail git symbolic-ref HEAD + test_must_fail git status ) 2>message && - ! grep "^warning:" message && grep "core.bare and core.worktree" message ' @@ -766,7 +775,7 @@ test_expect_success '#29: setup' ' cd 29 && GIT_WORK_TREE="$here/29" && export GIT_WORK_TREE && - git symbolic-ref HEAD >/dev/null + git status ) 2>message && ! test -s message ' @@ -777,7 +786,7 @@ test_expect_success '#30: core.worktree and core.bare conflict (gitfile version) setup_repo 30 "$here/30" gitfile true && ( cd 30 && - test_must_fail env GIT_DIR=.git git symbolic-ref HEAD 2>result + test_must_fail env GIT_DIR=.git git status 2>result ) && grep "core.bare and core.worktree" 30/result ' diff --git a/t/t1514-rev-parse-push.sh b/t/t1514-rev-parse-push.sh new file mode 100755 index 0000000000..7214f5b33f --- /dev/null +++ b/t/t1514-rev-parse-push.sh @@ -0,0 +1,63 @@ +#!/bin/sh + +test_description='test <branch>@{push} syntax' +. ./test-lib.sh + +resolve () { + echo "$2" >expect && + git rev-parse --symbolic-full-name "$1" >actual && + test_cmp expect actual +} + +test_expect_success 'setup' ' + git init --bare parent.git && + git init --bare other.git && + git remote add origin parent.git && + git remote add other other.git && + test_commit base && + git push origin HEAD && + git branch --set-upstream-to=origin/master master && + git branch --track topic origin/master && + git push origin topic && + git push other topic +' + +test_expect_success '@{push} with default=nothing' ' + test_config push.default nothing && + test_must_fail git rev-parse master@{push} +' + +test_expect_success '@{push} with default=simple' ' + test_config push.default simple && + resolve master@{push} refs/remotes/origin/master +' + +test_expect_success 'triangular @{push} fails with default=simple' ' + test_config push.default simple && + test_must_fail git rev-parse topic@{push} +' + +test_expect_success '@{push} with default=current' ' + test_config push.default current && + resolve topic@{push} refs/remotes/origin/topic +' + +test_expect_success '@{push} with default=matching' ' + test_config push.default matching && + resolve topic@{push} refs/remotes/origin/topic +' + +test_expect_success '@{push} with pushremote defined' ' + test_config push.default current && + test_config branch.topic.pushremote other && + resolve topic@{push} refs/remotes/other/topic +' + +test_expect_success '@{push} with push refspecs' ' + test_config push.default nothing && + test_config remote.origin.push refs/heads/*:refs/heads/magic/* && + git push && + resolve topic@{push} refs/remotes/origin/magic/topic +' + +test_done diff --git a/t/t1700-split-index.sh b/t/t1700-split-index.sh new file mode 100755 index 0000000000..193d55c3f4 --- /dev/null +++ b/t/t1700-split-index.sh @@ -0,0 +1,203 @@ +#!/bin/sh + +test_description='split index mode tests' + +. ./test-lib.sh + +# We need total control of index splitting here +sane_unset GIT_TEST_SPLIT_INDEX + +test_expect_success 'enable split index' ' + git update-index --split-index && + test-dump-split-index .git/index >actual && + indexversion=$(test-index-version <.git/index) && + if test "$indexversion" = "4" + then + own=432ef4b63f32193984f339431fd50ca796493569 + base=508851a7f0dfa8691e9f69c7f055865389012491 + else + own=8299b0bcd1ac364e5f1d7768efb62fa2da79a339 + base=39d890139ee5356c7ef572216cebcd27aa41f9df + fi && + cat >expect <<EOF && +own $own +base $base +replacements: +deletions: +EOF + test_cmp expect actual +' + +test_expect_success 'add one file' ' + : >one && + git update-index --add one && + git ls-files --stage >ls-files.actual && + cat >ls-files.expect <<EOF && +100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 one +EOF + test_cmp ls-files.expect ls-files.actual && + + test-dump-split-index .git/index | sed "/^own/d" >actual && + cat >expect <<EOF && +base $base +100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 one +replacements: +deletions: +EOF + test_cmp expect actual +' + +test_expect_success 'disable split index' ' + git update-index --no-split-index && + git ls-files --stage >ls-files.actual && + cat >ls-files.expect <<EOF && +100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 one +EOF + test_cmp ls-files.expect ls-files.actual && + + BASE=`test-dump-split-index .git/index | grep "^own" | sed "s/own/base/"` && + test-dump-split-index .git/index | sed "/^own/d" >actual && + cat >expect <<EOF && +not a split index +EOF + test_cmp expect actual +' + +test_expect_success 'enable split index again, "one" now belongs to base index"' ' + git update-index --split-index && + git ls-files --stage >ls-files.actual && + cat >ls-files.expect <<EOF && +100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 one +EOF + test_cmp ls-files.expect ls-files.actual && + + test-dump-split-index .git/index | sed "/^own/d" >actual && + cat >expect <<EOF && +$BASE +replacements: +deletions: +EOF + test_cmp expect actual +' + +test_expect_success 'modify original file, base index untouched' ' + echo modified >one && + git update-index one && + git ls-files --stage >ls-files.actual && + cat >ls-files.expect <<EOF && +100644 2e0996000b7e9019eabcad29391bf0f5c7702f0b 0 one +EOF + test_cmp ls-files.expect ls-files.actual && + + test-dump-split-index .git/index | sed "/^own/d" >actual && + q_to_tab >expect <<EOF && +$BASE +100644 2e0996000b7e9019eabcad29391bf0f5c7702f0b 0Q +replacements: 0 +deletions: +EOF + test_cmp expect actual +' + +test_expect_success 'add another file, which stays index' ' + : >two && + git update-index --add two && + git ls-files --stage >ls-files.actual && + cat >ls-files.expect <<EOF && +100644 2e0996000b7e9019eabcad29391bf0f5c7702f0b 0 one +100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 two +EOF + test_cmp ls-files.expect ls-files.actual && + + test-dump-split-index .git/index | sed "/^own/d" >actual && + q_to_tab >expect <<EOF && +$BASE +100644 2e0996000b7e9019eabcad29391bf0f5c7702f0b 0Q +100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 two +replacements: 0 +deletions: +EOF + test_cmp expect actual +' + +test_expect_success 'remove file not in base index' ' + git update-index --force-remove two && + git ls-files --stage >ls-files.actual && + cat >ls-files.expect <<EOF && +100644 2e0996000b7e9019eabcad29391bf0f5c7702f0b 0 one +EOF + test_cmp ls-files.expect ls-files.actual && + + test-dump-split-index .git/index | sed "/^own/d" >actual && + q_to_tab >expect <<EOF && +$BASE +100644 2e0996000b7e9019eabcad29391bf0f5c7702f0b 0Q +replacements: 0 +deletions: +EOF + test_cmp expect actual +' + +test_expect_success 'remove file in base index' ' + git update-index --force-remove one && + git ls-files --stage >ls-files.actual && + cat >ls-files.expect <<EOF && +EOF + test_cmp ls-files.expect ls-files.actual && + + test-dump-split-index .git/index | sed "/^own/d" >actual && + cat >expect <<EOF && +$BASE +replacements: +deletions: 0 +EOF + test_cmp expect actual +' + +test_expect_success 'add original file back' ' + : >one && + git update-index --add one && + git ls-files --stage >ls-files.actual && + cat >ls-files.expect <<EOF && +100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 one +EOF + test_cmp ls-files.expect ls-files.actual && + + test-dump-split-index .git/index | sed "/^own/d" >actual && + cat >expect <<EOF && +$BASE +100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 one +replacements: +deletions: 0 +EOF + test_cmp expect actual +' + +test_expect_success 'add new file' ' + : >two && + git update-index --add two && + git ls-files --stage >actual && + cat >expect <<EOF && +100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 one +100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 two +EOF + test_cmp expect actual +' + +test_expect_success 'unify index, two files remain' ' + git update-index --no-split-index && + git ls-files --stage >ls-files.actual && + cat >ls-files.expect <<EOF && +100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 one +100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 two +EOF + test_cmp ls-files.expect ls-files.actual && + + test-dump-split-index .git/index | sed "/^own/d" >actual && + cat >expect <<EOF && +not a split index +EOF + test_cmp expect actual +' + +test_done diff --git a/t/t2004-checkout-cache-temp.sh b/t/t2004-checkout-cache-temp.sh index f171a5578b..a12afe93f3 100755 --- a/t/t2004-checkout-cache-temp.sh +++ b/t/t2004-checkout-cache-temp.sh @@ -10,202 +10,212 @@ rather than the tracked path.' . ./test-lib.sh -test_expect_success \ -'preparation' ' -mkdir asubdir && -echo tree1path0 >path0 && -echo tree1path1 >path1 && -echo tree1path3 >path3 && -echo tree1path4 >path4 && -echo tree1asubdir/path5 >asubdir/path5 && -git update-index --add path0 path1 path3 path4 asubdir/path5 && -t1=$(git write-tree) && -rm -f path* .merge_* out .git/index && -echo tree2path0 >path0 && -echo tree2path1 >path1 && -echo tree2path2 >path2 && -echo tree2path4 >path4 && -git update-index --add path0 path1 path2 path4 && -t2=$(git write-tree) && -rm -f path* .merge_* out .git/index && -echo tree2path0 >path0 && -echo tree3path1 >path1 && -echo tree3path2 >path2 && -echo tree3path3 >path3 && -git update-index --add path0 path1 path2 path3 && -t3=$(git write-tree)' - -test_expect_success \ -'checkout one stage 0 to temporary file' ' -rm -f path* .merge_* out .git/index && -git read-tree $t1 && -git checkout-index --temp -- path1 >out && -test_line_count = 1 out && -test $(cut "-d " -f2 out) = path1 && -p=$(cut "-d " -f1 out) && -test -f $p && -test $(cat $p) = tree1path1' - -test_expect_success \ -'checkout all stage 0 to temporary files' ' -rm -f path* .merge_* out .git/index && -git read-tree $t1 && -git checkout-index -a --temp >out && -test_line_count = 5 out && -for f in path0 path1 path3 path4 asubdir/path5 -do - test $(grep $f out | cut "-d " -f2) = $f && - p=$(grep $f out | cut "-d " -f1) && +test_expect_success 'setup' ' + mkdir asubdir && + echo tree1path0 >path0 && + echo tree1path1 >path1 && + echo tree1path3 >path3 && + echo tree1path4 >path4 && + echo tree1asubdir/path5 >asubdir/path5 && + git update-index --add path0 path1 path3 path4 asubdir/path5 && + t1=$(git write-tree) && + rm -f path* .merge_* actual .git/index && + echo tree2path0 >path0 && + echo tree2path1 >path1 && + echo tree2path2 >path2 && + echo tree2path4 >path4 && + git update-index --add path0 path1 path2 path4 && + t2=$(git write-tree) && + rm -f path* .merge_* actual .git/index && + echo tree2path0 >path0 && + echo tree3path1 >path1 && + echo tree3path2 >path2 && + echo tree3path3 >path3 && + git update-index --add path0 path1 path2 path3 && + t3=$(git write-tree) +' + +test_expect_success 'checkout one stage 0 to temporary file' ' + rm -f path* .merge_* actual .git/index && + git read-tree $t1 && + git checkout-index --temp -- path1 >actual && + test_line_count = 1 actual && + test $(cut "-d " -f2 actual) = path1 && + p=$(cut "-d " -f1 actual) && test -f $p && - test $(cat $p) = tree1$f -done' - -test_expect_success \ -'prepare 3-way merge' ' -rm -f path* .merge_* out .git/index && -git read-tree -m $t1 $t2 $t3' - -test_expect_success \ -'checkout one stage 2 to temporary file' ' -rm -f path* .merge_* out && -git checkout-index --stage=2 --temp -- path1 >out && -test_line_count = 1 out && -test $(cut "-d " -f2 out) = path1 && -p=$(cut "-d " -f1 out) && -test -f $p && -test $(cat $p) = tree2path1' - -test_expect_success \ -'checkout all stage 2 to temporary files' ' -rm -f path* .merge_* out && -git checkout-index --all --stage=2 --temp >out && -test_line_count = 3 out && -for f in path1 path2 path4 -do - test $(grep $f out | cut "-d " -f2) = $f && - p=$(grep $f out | cut "-d " -f1) && + test $(cat $p) = tree1path1 +' + +test_expect_success 'checkout all stage 0 to temporary files' ' + rm -f path* .merge_* actual .git/index && + git read-tree $t1 && + git checkout-index -a --temp >actual && + test_line_count = 5 actual && + for f in path0 path1 path3 path4 asubdir/path5 + do + test $(grep $f actual | cut "-d " -f2) = $f && + p=$(grep $f actual | cut "-d " -f1) && + test -f $p && + test $(cat $p) = tree1$f + done +' + +test_expect_success 'setup 3-way merge' ' + rm -f path* .merge_* actual .git/index && + git read-tree -m $t1 $t2 $t3 +' + +test_expect_success 'checkout one stage 2 to temporary file' ' + rm -f path* .merge_* actual && + git checkout-index --stage=2 --temp -- path1 >actual && + test_line_count = 1 actual && + test $(cut "-d " -f2 actual) = path1 && + p=$(cut "-d " -f1 actual) && test -f $p && - test $(cat $p) = tree2$f -done' - -test_expect_success \ -'checkout all stages/one file to nothing' ' -rm -f path* .merge_* out && -git checkout-index --stage=all --temp -- path0 >out && -test_line_count = 0 out' - -test_expect_success \ -'checkout all stages/one file to temporary files' ' -rm -f path* .merge_* out && -git checkout-index --stage=all --temp -- path1 >out && -test_line_count = 1 out && -test $(cut "-d " -f2 out) = path1 && -cut "-d " -f1 out | (read s1 s2 s3 && -test -f $s1 && -test -f $s2 && -test -f $s3 && -test $(cat $s1) = tree1path1 && -test $(cat $s2) = tree2path1 && -test $(cat $s3) = tree3path1)' - -test_expect_success \ -'checkout some stages/one file to temporary files' ' -rm -f path* .merge_* out && -git checkout-index --stage=all --temp -- path2 >out && -test_line_count = 1 out && -test $(cut "-d " -f2 out) = path2 && -cut "-d " -f1 out | (read s1 s2 s3 && -test $s1 = . && -test -f $s2 && -test -f $s3 && -test $(cat $s2) = tree2path2 && -test $(cat $s3) = tree3path2)' - -test_expect_success \ -'checkout all stages/all files to temporary files' ' -rm -f path* .merge_* out && -git checkout-index -a --stage=all --temp >out && -test_line_count = 5 out' - -test_expect_success \ -'-- path0: no entry' ' -test x$(grep path0 out | cut "-d " -f2) = x' - -test_expect_success \ -'-- path1: all 3 stages' ' -test $(grep path1 out | cut "-d " -f2) = path1 && -grep path1 out | cut "-d " -f1 | (read s1 s2 s3 && -test -f $s1 && -test -f $s2 && -test -f $s3 && -test $(cat $s1) = tree1path1 && -test $(cat $s2) = tree2path1 && -test $(cat $s3) = tree3path1)' - -test_expect_success \ -'-- path2: no stage 1, have stage 2 and 3' ' -test $(grep path2 out | cut "-d " -f2) = path2 && -grep path2 out | cut "-d " -f1 | (read s1 s2 s3 && -test $s1 = . && -test -f $s2 && -test -f $s3 && -test $(cat $s2) = tree2path2 && -test $(cat $s3) = tree3path2)' - -test_expect_success \ -'-- path3: no stage 2, have stage 1 and 3' ' -test $(grep path3 out | cut "-d " -f2) = path3 && -grep path3 out | cut "-d " -f1 | (read s1 s2 s3 && -test -f $s1 && -test $s2 = . && -test -f $s3 && -test $(cat $s1) = tree1path3 && -test $(cat $s3) = tree3path3)' - -test_expect_success \ -'-- path4: no stage 3, have stage 1 and 3' ' -test $(grep path4 out | cut "-d " -f2) = path4 && -grep path4 out | cut "-d " -f1 | (read s1 s2 s3 && -test -f $s1 && -test -f $s2 && -test $s3 = . && -test $(cat $s1) = tree1path4 && -test $(cat $s2) = tree2path4)' - -test_expect_success \ -'-- asubdir/path5: no stage 2 and 3 have stage 1' ' -test $(grep asubdir/path5 out | cut "-d " -f2) = asubdir/path5 && -grep asubdir/path5 out | cut "-d " -f1 | (read s1 s2 s3 && -test -f $s1 && -test $s2 = . && -test $s3 = . && -test $(cat $s1) = tree1asubdir/path5)' - -test_expect_success \ -'checkout --temp within subdir' ' -(cd asubdir && - git checkout-index -a --stage=all >out && - test_line_count = 1 out && - test $(grep path5 out | cut "-d " -f2) = path5 && - grep path5 out | cut "-d " -f1 | (read s1 s2 s3 && - test -f ../$s1 && - test $s2 = . && - test $s3 = . && - test $(cat ../$s1) = tree1asubdir/path5) -)' - -test_expect_success \ -'checkout --temp symlink' ' -rm -f path* .merge_* out .git/index && -test_ln_s_add b a && -t4=$(git write-tree) && -rm -f .git/index && -git read-tree $t4 && -git checkout-index --temp -a >out && -test_line_count = 1 out && -test $(cut "-d " -f2 out) = a && -p=$(cut "-d " -f1 out) && -test -f $p && -test $(cat $p) = b' + test $(cat $p) = tree2path1 +' + +test_expect_success 'checkout all stage 2 to temporary files' ' + rm -f path* .merge_* actual && + git checkout-index --all --stage=2 --temp >actual && + test_line_count = 3 actual && + for f in path1 path2 path4 + do + test $(grep $f actual | cut "-d " -f2) = $f && + p=$(grep $f actual | cut "-d " -f1) && + test -f $p && + test $(cat $p) = tree2$f + done +' + +test_expect_success 'checkout all stages/one file to nothing' ' + rm -f path* .merge_* actual && + git checkout-index --stage=all --temp -- path0 >actual && + test_line_count = 0 actual +' + +test_expect_success 'checkout all stages/one file to temporary files' ' + rm -f path* .merge_* actual && + git checkout-index --stage=all --temp -- path1 >actual && + test_line_count = 1 actual && + test $(cut "-d " -f2 actual) = path1 && + cut "-d " -f1 actual | (read s1 s2 s3 && + test -f $s1 && + test -f $s2 && + test -f $s3 && + test $(cat $s1) = tree1path1 && + test $(cat $s2) = tree2path1 && + test $(cat $s3) = tree3path1) +' + +test_expect_success 'checkout some stages/one file to temporary files' ' + rm -f path* .merge_* actual && + git checkout-index --stage=all --temp -- path2 >actual && + test_line_count = 1 actual && + test $(cut "-d " -f2 actual) = path2 && + cut "-d " -f1 actual | (read s1 s2 s3 && + test $s1 = . && + test -f $s2 && + test -f $s3 && + test $(cat $s2) = tree2path2 && + test $(cat $s3) = tree3path2) +' + +test_expect_success 'checkout all stages/all files to temporary files' ' + rm -f path* .merge_* actual && + git checkout-index -a --stage=all --temp >actual && + test_line_count = 5 actual +' + +test_expect_success '-- path0: no entry' ' + test x$(grep path0 actual | cut "-d " -f2) = x +' + +test_expect_success '-- path1: all 3 stages' ' + test $(grep path1 actual | cut "-d " -f2) = path1 && + grep path1 actual | cut "-d " -f1 | (read s1 s2 s3 && + test -f $s1 && + test -f $s2 && + test -f $s3 && + test $(cat $s1) = tree1path1 && + test $(cat $s2) = tree2path1 && + test $(cat $s3) = tree3path1) +' + +test_expect_success '-- path2: no stage 1, have stage 2 and 3' ' + test $(grep path2 actual | cut "-d " -f2) = path2 && + grep path2 actual | cut "-d " -f1 | (read s1 s2 s3 && + test $s1 = . && + test -f $s2 && + test -f $s3 && + test $(cat $s2) = tree2path2 && + test $(cat $s3) = tree3path2) +' + +test_expect_success '-- path3: no stage 2, have stage 1 and 3' ' + test $(grep path3 actual | cut "-d " -f2) = path3 && + grep path3 actual | cut "-d " -f1 | (read s1 s2 s3 && + test -f $s1 && + test $s2 = . && + test -f $s3 && + test $(cat $s1) = tree1path3 && + test $(cat $s3) = tree3path3) +' + +test_expect_success '-- path4: no stage 3, have stage 1 and 3' ' + test $(grep path4 actual | cut "-d " -f2) = path4 && + grep path4 actual | cut "-d " -f1 | (read s1 s2 s3 && + test -f $s1 && + test -f $s2 && + test $s3 = . && + test $(cat $s1) = tree1path4 && + test $(cat $s2) = tree2path4) +' + +test_expect_success '-- asubdir/path5: no stage 2 and 3 have stage 1' ' + test $(grep asubdir/path5 actual | cut "-d " -f2) = asubdir/path5 && + grep asubdir/path5 actual | cut "-d " -f1 | (read s1 s2 s3 && + test -f $s1 && + test $s2 = . && + test $s3 = . && + test $(cat $s1) = tree1asubdir/path5) +' + +test_expect_success 'checkout --temp within subdir' ' + ( + cd asubdir && + git checkout-index -a --stage=all >actual && + test_line_count = 1 actual && + test $(grep path5 actual | cut "-d " -f2) = path5 && + grep path5 actual | cut "-d " -f1 | (read s1 s2 s3 && + test -f ../$s1 && + test $s2 = . && + test $s3 = . && + test $(cat ../$s1) = tree1asubdir/path5) + ) +' + +test_expect_success 'checkout --temp symlink' ' + rm -f path* .merge_* actual .git/index && + test_ln_s_add path7 path6 && + git checkout-index --temp -a >actual && + test_line_count = 1 actual && + test $(cut "-d " -f2 actual) = path6 && + p=$(cut "-d " -f1 actual) && + test -f $p && + test $(cat $p) = path7 +' + +test_expect_success 'emit well-formed relative path' ' + rm -f path* .merge_* actual .git/index && + >path0123456789 && + git update-index --add path0123456789 && + ( + cd asubdir && + git checkout-index --temp -- ../path0123456789 >actual && + test_line_count = 1 actual && + test $(cut "-d " -f2 actual) = ../path0123456789 + ) +' test_done diff --git a/t/t2013-checkout-submodule.sh b/t/t2013-checkout-submodule.sh index 06b18f8bc1..6847f75822 100755 --- a/t/t2013-checkout-submodule.sh +++ b/t/t2013-checkout-submodule.sh @@ -3,6 +3,7 @@ test_description='checkout can handle submodules' . ./test-lib.sh +. "$TEST_DIRECTORY"/lib-submodule-update.sh test_expect_success 'setup' ' mkdir submodule && @@ -62,4 +63,8 @@ test_expect_success '"checkout <submodule>" honors submodule.*.ignore from .git/ ! test -s actual ' +test_submodule_switch "git checkout" + +test_submodule_forced_switch "git checkout -f" + test_done diff --git a/t/t2019-checkout-ambiguous-ref.sh b/t/t2019-checkout-ambiguous-ref.sh index b99d5192a9..199b22d85e 100755 --- a/t/t2019-checkout-ambiguous-ref.sh +++ b/t/t2019-checkout-ambiguous-ref.sh @@ -56,4 +56,30 @@ test_expect_success VAGUENESS_SUCCESS 'checkout reports switch to branch' ' test_i18ngrep ! "^HEAD is now at" stderr ' +test_expect_success 'wildcard ambiguation, paths win' ' + git init ambi && + ( + cd ambi && + echo a >a.c && + git add a.c && + echo b >a.c && + git checkout "*.c" && + echo a >expect && + test_cmp expect a.c + ) +' + +test_expect_success !MINGW 'wildcard ambiguation, refs lose' ' + git init ambi2 && + ( + cd ambi2 && + echo a >"*.c" && + git add . && + test_must_fail git show :"*.c" && + git show :"*.c" -- >actual && + echo a >expect && + test_cmp expect actual + ) +' + test_done diff --git a/t/t2022-checkout-paths.sh b/t/t2022-checkout-paths.sh index 8e3545d868..f46d0499bc 100755 --- a/t/t2022-checkout-paths.sh +++ b/t/t2022-checkout-paths.sh @@ -61,4 +61,21 @@ test_expect_success 'do not touch unmerged entries matching $path but not in $tr test_cmp expect.next0 actual.next0 ' +test_expect_success 'do not touch files that are already up-to-date' ' + git reset --hard && + echo one >file1 && + echo two >file2 && + git add file1 file2 && + git commit -m base && + echo modified >file1 && + test-chmtime =1000000000 file2 && + git update-index -q --refresh && + git checkout HEAD -- file1 file2 && + echo one >expect && + test_cmp expect file1 && + echo "1000000000 file2" >expect && + test-chmtime -v +0 file2 >actual && + test_cmp expect actual +' + test_done diff --git a/t/t2024-checkout-dwim.sh b/t/t2024-checkout-dwim.sh index 6ecb559465..468a000e4b 100755 --- a/t/t2024-checkout-dwim.sh +++ b/t/t2024-checkout-dwim.sh @@ -185,4 +185,22 @@ test_expect_success 'checkout <branch> -- succeeds, even if a file with the same test_branch_upstream spam repo_c spam ' +test_expect_success 'loosely defined local base branch is reported correctly' ' + + git checkout master && + git branch strict && + git branch loose && + git commit --allow-empty -m "a bit more" && + + test_config branch.strict.remote . && + test_config branch.loose.remote . && + test_config branch.strict.merge refs/heads/master && + test_config branch.loose.merge master && + + git checkout strict | sed -e "s/strict/BRANCHNAME/g" >expect && + git checkout loose | sed -e "s/loose/BRANCHNAME/g" >actual && + + test_cmp expect actual +' + test_done diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh new file mode 100755 index 0000000000..3694174989 --- /dev/null +++ b/t/t2025-worktree-add.sh @@ -0,0 +1,201 @@ +#!/bin/sh + +test_description='test git worktree add' + +. ./test-lib.sh + +test_expect_success 'setup' ' + test_commit init +' + +test_expect_success '"add" an existing worktree' ' + mkdir -p existing/subtree && + test_must_fail git worktree add --detach existing master +' + +test_expect_success '"add" an existing empty worktree' ' + mkdir existing_empty && + git worktree add --detach existing_empty master +' + +test_expect_success '"add" refuses to checkout locked branch' ' + test_must_fail git worktree add zere master && + ! test -d zere && + ! test -d .git/worktrees/zere +' + +test_expect_success 'checking out paths not complaining about linked checkouts' ' + ( + cd existing_empty && + echo dirty >>init.t && + git checkout master -- init.t + ) +' + +test_expect_success '"add" worktree' ' + git rev-parse HEAD >expect && + git worktree add --detach here master && + ( + cd here && + test_cmp ../init.t init.t && + test_must_fail git symbolic-ref HEAD && + git rev-parse HEAD >actual && + test_cmp ../expect actual && + git fsck + ) +' + +test_expect_success '"add" worktree from a subdir' ' + ( + mkdir sub && + cd sub && + git worktree add --detach here master && + cd here && + test_cmp ../../init.t init.t + ) +' + +test_expect_success '"add" from a linked checkout' ' + ( + cd here && + git worktree add --detach nested-here master && + cd nested-here && + git fsck + ) +' + +test_expect_success '"add" worktree creating new branch' ' + git worktree add -b newmaster there master && + ( + cd there && + test_cmp ../init.t init.t && + git symbolic-ref HEAD >actual && + echo refs/heads/newmaster >expect && + test_cmp expect actual && + git fsck + ) +' + +test_expect_success 'die the same branch is already checked out' ' + ( + cd here && + test_must_fail git checkout newmaster + ) +' + +test_expect_success SYMLINKS 'die the same branch is already checked out (symlink)' ' + head=$(git -C there rev-parse --git-path HEAD) && + ref=$(git -C there symbolic-ref HEAD) && + rm "$head" && + ln -s "$ref" "$head" && + test_must_fail git -C here checkout newmaster +' + +test_expect_success 'not die the same branch is already checked out' ' + ( + cd here && + git worktree add --force anothernewmaster newmaster + ) +' + +test_expect_success 'not die on re-checking out current branch' ' + ( + cd there && + git checkout newmaster + ) +' + +test_expect_success '"add" from a bare repo' ' + ( + git clone --bare . bare && + cd bare && + git worktree add -b bare-master ../there2 master + ) +' + +test_expect_success 'checkout from a bare repo without "add"' ' + ( + cd bare && + test_must_fail git checkout master + ) +' + +test_expect_success 'checkout with grafts' ' + test_when_finished rm .git/info/grafts && + test_commit abc && + SHA1=`git rev-parse HEAD` && + test_commit def && + test_commit xyz && + echo "`git rev-parse HEAD` $SHA1" >.git/info/grafts && + cat >expected <<-\EOF && + xyz + abc + EOF + git log --format=%s -2 >actual && + test_cmp expected actual && + git worktree add --detach grafted master && + git --git-dir=grafted/.git log --format=%s -2 >actual && + test_cmp expected actual +' + +test_expect_success '"add" from relative HEAD' ' + test_commit a && + test_commit b && + test_commit c && + git rev-parse HEAD~1 >expected && + git worktree add relhead HEAD~1 && + git -C relhead rev-parse HEAD >actual && + test_cmp expected actual +' + +test_expect_success '"add -b" with <branch> omitted' ' + git worktree add -b burble flornk && + test_cmp_rev HEAD burble +' + +test_expect_success '"add --detach" with <branch> omitted' ' + git worktree add --detach fishhook && + git rev-parse HEAD >expected && + git -C fishhook rev-parse HEAD >actual && + test_cmp expected actual && + test_must_fail git -C fishhook symbolic-ref HEAD +' + +test_expect_success '"add" with <branch> omitted' ' + git worktree add wiffle/bat && + test_cmp_rev HEAD bat +' + +test_expect_success '"add" auto-vivify does not clobber existing branch' ' + test_commit c1 && + test_commit c2 && + git branch precious HEAD~1 && + test_must_fail git worktree add precious && + test_cmp_rev HEAD~1 precious && + test_path_is_missing precious +' + +test_expect_success '"add" no auto-vivify with --detach and <branch> omitted' ' + git worktree add --detach mish/mash && + test_must_fail git rev-parse mash -- && + test_must_fail git -C mish/mash symbolic-ref HEAD +' + +test_expect_success '"add" -b/-B mutually exclusive' ' + test_must_fail git worktree add -b poodle -B poodle bamboo master +' + +test_expect_success '"add" -b/--detach mutually exclusive' ' + test_must_fail git worktree add -b poodle --detach bamboo master +' + +test_expect_success '"add" -B/--detach mutually exclusive' ' + test_must_fail git worktree add -B poodle --detach bamboo master +' + +test_expect_success 'local clone from linked checkout' ' + git clone --local here here-clone && + ( cd here-clone && git fsck ) +' + +test_done diff --git a/t/t2026-worktree-prune.sh b/t/t2026-worktree-prune.sh new file mode 100755 index 0000000000..a0f1e3bb80 --- /dev/null +++ b/t/t2026-worktree-prune.sh @@ -0,0 +1,96 @@ +#!/bin/sh + +test_description='prune $GIT_DIR/worktrees' + +. ./test-lib.sh + +test_expect_success initialize ' + git commit --allow-empty -m init +' + +test_expect_success 'worktree prune on normal repo' ' + git worktree prune && + test_must_fail git worktree prune abc +' + +test_expect_success 'prune files inside $GIT_DIR/worktrees' ' + mkdir .git/worktrees && + : >.git/worktrees/abc && + git worktree prune --verbose >actual && + cat >expect <<EOF && +Removing worktrees/abc: not a valid directory +EOF + test_i18ncmp expect actual && + ! test -f .git/worktrees/abc && + ! test -d .git/worktrees +' + +test_expect_success 'prune directories without gitdir' ' + mkdir -p .git/worktrees/def/abc && + : >.git/worktrees/def/def && + cat >expect <<EOF && +Removing worktrees/def: gitdir file does not exist +EOF + git worktree prune --verbose >actual && + test_i18ncmp expect actual && + ! test -d .git/worktrees/def && + ! test -d .git/worktrees +' + +test_expect_success SANITY 'prune directories with unreadable gitdir' ' + mkdir -p .git/worktrees/def/abc && + : >.git/worktrees/def/def && + : >.git/worktrees/def/gitdir && + chmod u-r .git/worktrees/def/gitdir && + git worktree prune --verbose >actual && + test_i18ngrep "Removing worktrees/def: unable to read gitdir file" actual && + ! test -d .git/worktrees/def && + ! test -d .git/worktrees +' + +test_expect_success 'prune directories with invalid gitdir' ' + mkdir -p .git/worktrees/def/abc && + : >.git/worktrees/def/def && + : >.git/worktrees/def/gitdir && + git worktree prune --verbose >actual && + test_i18ngrep "Removing worktrees/def: invalid gitdir file" actual && + ! test -d .git/worktrees/def && + ! test -d .git/worktrees +' + +test_expect_success 'prune directories with gitdir pointing to nowhere' ' + mkdir -p .git/worktrees/def/abc && + : >.git/worktrees/def/def && + echo "$(pwd)"/nowhere >.git/worktrees/def/gitdir && + git worktree prune --verbose >actual && + test_i18ngrep "Removing worktrees/def: gitdir file points to non-existent location" actual && + ! test -d .git/worktrees/def && + ! test -d .git/worktrees +' + +test_expect_success 'not prune locked checkout' ' + test_when_finished rm -r .git/worktrees && + mkdir -p .git/worktrees/ghi && + : >.git/worktrees/ghi/locked && + git worktree prune && + test -d .git/worktrees/ghi +' + +test_expect_success 'not prune recent checkouts' ' + test_when_finished rm -r .git/worktrees && + mkdir zz && + mkdir -p .git/worktrees/jlm && + echo "$(pwd)"/zz >.git/worktrees/jlm/gitdir && + rmdir zz && + git worktree prune --verbose --expire=2.days.ago && + test -d .git/worktrees/jlm +' + +test_expect_success 'not prune proper checkouts' ' + test_when_finished rm -r .git/worktrees && + git worktree add --detach "$PWD/nop" master && + git worktree prune && + test -d .git/worktrees/nop +' + +test_done diff --git a/t/t2027-worktree-list.sh b/t/t2027-worktree-list.sh new file mode 100755 index 0000000000..75ebb1b4a0 --- /dev/null +++ b/t/t2027-worktree-list.sh @@ -0,0 +1,89 @@ +#!/bin/sh + +test_description='test git worktree list' + +. ./test-lib.sh + +test_expect_success 'setup' ' + test_commit init +' + +test_expect_success '"list" all worktrees from main' ' + echo "$(git rev-parse --show-toplevel) $(git rev-parse --short HEAD) [$(git symbolic-ref --short HEAD)]" >expect && + test_when_finished "rm -rf here && git worktree prune" && + git worktree add --detach here master && + echo "$(git -C here rev-parse --show-toplevel) $(git rev-parse --short HEAD) (detached HEAD)" >>expect && + git worktree list | sed "s/ */ /g" >actual && + test_cmp expect actual +' + +test_expect_success '"list" all worktrees from linked' ' + echo "$(git rev-parse --show-toplevel) $(git rev-parse --short HEAD) [$(git symbolic-ref --short HEAD)]" >expect && + test_when_finished "rm -rf here && git worktree prune" && + git worktree add --detach here master && + echo "$(git -C here rev-parse --show-toplevel) $(git rev-parse --short HEAD) (detached HEAD)" >>expect && + git -C here worktree list | sed "s/ */ /g" >actual && + test_cmp expect actual +' + +test_expect_success '"list" all worktrees --porcelain' ' + echo "worktree $(git rev-parse --show-toplevel)" >expect && + echo "HEAD $(git rev-parse HEAD)" >>expect && + echo "branch $(git symbolic-ref HEAD)" >>expect && + echo >>expect && + test_when_finished "rm -rf here && git worktree prune" && + git worktree add --detach here master && + echo "worktree $(git -C here rev-parse --show-toplevel)" >>expect && + echo "HEAD $(git rev-parse HEAD)" >>expect && + echo "detached" >>expect && + echo >>expect && + git worktree list --porcelain >actual && + test_cmp expect actual +' + +test_expect_success 'bare repo setup' ' + git init --bare bare1 && + echo "data" >file1 && + git add file1 && + git commit -m"File1: add data" && + git push bare1 master && + git reset --hard HEAD^ +' + +test_expect_success '"list" all worktrees from bare main' ' + test_when_finished "rm -rf there && git -C bare1 worktree prune" && + git -C bare1 worktree add --detach ../there master && + echo "$(pwd)/bare1 (bare)" >expect && + echo "$(git -C there rev-parse --show-toplevel) $(git -C there rev-parse --short HEAD) (detached HEAD)" >>expect && + git -C bare1 worktree list | sed "s/ */ /g" >actual && + test_cmp expect actual +' + +test_expect_success '"list" all worktrees --porcelain from bare main' ' + test_when_finished "rm -rf there && git -C bare1 worktree prune" && + git -C bare1 worktree add --detach ../there master && + echo "worktree $(pwd)/bare1" >expect && + echo "bare" >>expect && + echo >>expect && + echo "worktree $(git -C there rev-parse --show-toplevel)" >>expect && + echo "HEAD $(git -C there rev-parse HEAD)" >>expect && + echo "detached" >>expect && + echo >>expect && + git -C bare1 worktree list --porcelain >actual && + test_cmp expect actual +' + +test_expect_success '"list" all worktrees from linked with a bare main' ' + test_when_finished "rm -rf there && git -C bare1 worktree prune" && + git -C bare1 worktree add --detach ../there master && + echo "$(pwd)/bare1 (bare)" >expect && + echo "$(git -C there rev-parse --show-toplevel) $(git -C there rev-parse --short HEAD) (detached HEAD)" >>expect && + git -C there worktree list | sed "s/ */ /g" >actual && + test_cmp expect actual +' + +test_expect_success 'bare repo cleanup' ' + rm -rf bare1 +' + +test_done diff --git a/t/t2104-update-index-skip-worktree.sh b/t/t2104-update-index-skip-worktree.sh index 29c1fb10ca..cc830da58d 100755 --- a/t/t2104-update-index-skip-worktree.sh +++ b/t/t2104-update-index-skip-worktree.sh @@ -7,6 +7,8 @@ test_description='skip-worktree bit test' . ./test-lib.sh +sane_unset GIT_TEST_SPLIT_INDEX + test_set_index_version 3 cat >expect.full <<EOF diff --git a/t/t2107-update-index-basic.sh b/t/t2107-update-index-basic.sh index 1bafb9098c..dfe02f4818 100755 --- a/t/t2107-update-index-basic.sh +++ b/t/t2107-update-index-basic.sh @@ -65,4 +65,19 @@ test_expect_success '--cacheinfo mode,sha1,path (new syntax)' ' test_cmp expect actual ' +test_expect_success '.lock files cleaned up' ' + mkdir cleanup && + ( + cd cleanup && + mkdir worktree && + git init repo && + cd repo && + git config core.worktree ../../worktree && + # --refresh triggers late setup_work_tree, + # active_cache_changed is zero, rollback_lock_file fails + git update-index --refresh && + ! test -f .git/index.lock + ) +' + test_done diff --git a/t/t2200-add-update.sh b/t/t2200-add-update.sh index e16b15d3e5..314c73c5a7 100755 --- a/t/t2200-add-update.sh +++ b/t/t2200-add-update.sh @@ -84,6 +84,8 @@ test_expect_success 'non-qualified update in subdir updates from the root' ' ( cd dir1 && echo even more >>sub2 && + git --literal-pathspecs add -u && + echo even more >>sub2 && git add -u ) && : >expect && diff --git a/t/t2202-add-addremove.sh b/t/t2202-add-addremove.sh index fc8b59e7f7..6a5a3166b1 100755 --- a/t/t2202-add-addremove.sh +++ b/t/t2202-add-addremove.sh @@ -14,6 +14,7 @@ test_expect_success setup ' echo expect echo ignored ) >.gitignore && + git --literal-pathspecs add --all && >will-remove && git add --all && test_tick && diff --git a/t/t3000-ls-files-others.sh b/t/t3000-ls-files-others.sh index 88be904c09..c525656b2c 100755 --- a/t/t3000-ls-files-others.sh +++ b/t/t3000-ls-files-others.sh @@ -65,6 +65,13 @@ test_expect_success '--no-empty-directory hides empty directory' ' test_cmp expected3 output ' +test_expect_success 'ls-files --others handles non-submodule .git' ' + mkdir not-a-submodule && + echo foo >not-a-submodule/.git && + git ls-files -o >output && + test_cmp expected1 output +' + test_expect_success SYMLINKS 'ls-files --others with symlinked submodule' ' git init super && git init sub && diff --git a/t/t3001-ls-files-others-exclude.sh b/t/t3001-ls-files-others-exclude.sh index b2798feef7..3fc484e8c3 100755 --- a/t/t3001-ls-files-others-exclude.sh +++ b/t/t3001-ls-files-others-exclude.sh @@ -294,7 +294,7 @@ one/a.1 one/two/a.1 three/a.1 EOF - git ls-files -o -i --exclude "**/a.1" >actual + git ls-files -o -i --exclude "**/a.1" >actual && test_cmp expect actual ' diff --git a/t/t3010-ls-files-killed-modified.sh b/t/t3010-ls-files-killed-modified.sh index 6d3b828a95..580e158f99 100755 --- a/t/t3010-ls-files-killed-modified.sh +++ b/t/t3010-ls-files-killed-modified.sh @@ -55,14 +55,11 @@ test_expect_success 'git update-index --add to add various paths.' ' : >path9 && date >path10 && git update-index --add -- path0 path?/file? pathx/ju path7 path8 path9 path10 && - for i in 1 2 - do - git init submod$i && - ( - cd submod$i && git commit --allow-empty -m "empty $i" - ) || break - done && - git update-index --add submod[12] + git init submod1 && + git -C submod1 commit --allow-empty -m "empty 1" && + git init submod2 && + git -C submod2 commit --allow-empty -m "empty 2" && + git update-index --add submod[12] && ( cd submod1 && git commit --allow-empty -m "empty 1 (updated)" @@ -99,12 +96,12 @@ test_expect_success 'git ls-files -k to show killed files.' ' ' test_expect_success 'git ls-files -k output (w/o icase)' ' - git ls-files -k >.output + git ls-files -k >.output && test_cmp .expected .output ' test_expect_success 'git ls-files -k output (w/ icase)' ' - git -c core.ignorecase=true ls-files -k >.output + git -c core.ignorecase=true ls-files -k >.output && test_cmp .expected .output ' diff --git a/t/t3020-ls-files-error-unmatch.sh b/t/t3020-ls-files-error-unmatch.sh index ca01053bcc..124e73b8e6 100755 --- a/t/t3020-ls-files-error-unmatch.sh +++ b/t/t3020-ls-files-error-unmatch.sh @@ -22,7 +22,7 @@ test_expect_success \ 'test_must_fail git ls-files --error-unmatch foo bar-does-not-match' test_expect_success \ - 'git ls-files --error-unmatch should succeed eith matched paths.' \ + 'git ls-files --error-unmatch should succeed with matched paths.' \ 'git ls-files --error-unmatch foo bar' test_done diff --git a/t/t3030-merge-recursive.sh b/t/t3030-merge-recursive.sh index 82e18548c3..6224187632 100755 --- a/t/t3030-merge-recursive.sh +++ b/t/t3030-merge-recursive.sh @@ -629,5 +629,35 @@ test_expect_failure 'merge-recursive rename vs. rename/symlink' ' test_cmp expected actual ' +test_expect_success 'merging with triple rename across D/F conflict' ' + git reset --hard HEAD && + git checkout -b main && + git rm -rf . && + + echo "just a file" >sub1 && + mkdir -p sub2 && + echo content1 >sub2/file1 && + echo content2 >sub2/file2 && + echo content3 >sub2/file3 && + mkdir simple && + echo base >simple/bar && + git add -A && + test_tick && + git commit -m base && + + git checkout -b other && + echo more >>simple/bar && + test_tick && + git commit -a -m changesimplefile && + + git checkout main && + git rm sub1 && + git mv sub2 sub1 && + test_tick && + git commit -m changefiletodir && + + test_tick && + git merge other +' test_done diff --git a/t/t3031-merge-criscross.sh b/t/t3031-merge-criscross.sh index 7f41607c56..e59b0a32d6 100755 --- a/t/t3031-merge-criscross.sh +++ b/t/t3031-merge-criscross.sh @@ -32,7 +32,7 @@ test_expect_success 'setup repo with criss-cross history' ' do echo $n > data/$n && n=$(($n+1)) || - break + return 1 done && # check them in diff --git a/t/t3033-merge-toplevel.sh b/t/t3033-merge-toplevel.sh new file mode 100755 index 0000000000..46aadc410b --- /dev/null +++ b/t/t3033-merge-toplevel.sh @@ -0,0 +1,136 @@ +#!/bin/sh + +test_description='"git merge" top-level frontend' + +. ./test-lib.sh + +t3033_reset () { + git checkout -B master two && + git branch -f left three && + git branch -f right four +} + +test_expect_success setup ' + test_commit one && + git branch left && + git branch right && + test_commit two && + git checkout left && + test_commit three && + git checkout right && + test_commit four && + git checkout master +' + +# Local branches + +test_expect_success 'merge an octopus into void' ' + t3033_reset && + git checkout --orphan test && + git rm -fr . && + test_must_fail git merge left right && + test_must_fail git rev-parse --verify HEAD && + git diff --quiet && + test_must_fail git rev-parse HEAD +' + +test_expect_success 'merge an octopus, fast-forward (ff)' ' + t3033_reset && + git reset --hard one && + git merge left right && + # one is ancestor of three (left) and four (right) + test_must_fail git rev-parse --verify HEAD^3 && + git rev-parse HEAD^1 HEAD^2 | sort >actual && + git rev-parse three four | sort >expect && + test_cmp expect actual +' + +test_expect_success 'merge octopus, non-fast-forward (ff)' ' + t3033_reset && + git reset --hard one && + git merge --no-ff left right && + # one is ancestor of three (left) and four (right) + test_must_fail git rev-parse --verify HEAD^4 && + git rev-parse HEAD^1 HEAD^2 HEAD^3 | sort >actual && + git rev-parse one three four | sort >expect && + test_cmp expect actual +' + +test_expect_success 'merge octopus, fast-forward (does not ff)' ' + t3033_reset && + git merge left right && + # two (master) is not an ancestor of three (left) and four (right) + test_must_fail git rev-parse --verify HEAD^4 && + git rev-parse HEAD^1 HEAD^2 HEAD^3 | sort >actual && + git rev-parse two three four | sort >expect && + test_cmp expect actual +' + +test_expect_success 'merge octopus, non-fast-forward' ' + t3033_reset && + git merge --no-ff left right && + test_must_fail git rev-parse --verify HEAD^4 && + git rev-parse HEAD^1 HEAD^2 HEAD^3 | sort >actual && + git rev-parse two three four | sort >expect && + test_cmp expect actual +' + +# The same set with FETCH_HEAD + +test_expect_success 'merge FETCH_HEAD octopus into void' ' + t3033_reset && + git checkout --orphan test && + git rm -fr . && + git fetch . left right && + test_must_fail git merge FETCH_HEAD && + test_must_fail git rev-parse --verify HEAD && + git diff --quiet && + test_must_fail git rev-parse HEAD +' + +test_expect_success 'merge FETCH_HEAD octopus fast-forward (ff)' ' + t3033_reset && + git reset --hard one && + git fetch . left right && + git merge FETCH_HEAD && + # one is ancestor of three (left) and four (right) + test_must_fail git rev-parse --verify HEAD^3 && + git rev-parse HEAD^1 HEAD^2 | sort >actual && + git rev-parse three four | sort >expect && + test_cmp expect actual +' + +test_expect_success 'merge FETCH_HEAD octopus non-fast-forward (ff)' ' + t3033_reset && + git reset --hard one && + git fetch . left right && + git merge --no-ff FETCH_HEAD && + # one is ancestor of three (left) and four (right) + test_must_fail git rev-parse --verify HEAD^4 && + git rev-parse HEAD^1 HEAD^2 HEAD^3 | sort >actual && + git rev-parse one three four | sort >expect && + test_cmp expect actual +' + +test_expect_success 'merge FETCH_HEAD octopus fast-forward (does not ff)' ' + t3033_reset && + git fetch . left right && + git merge FETCH_HEAD && + # two (master) is not an ancestor of three (left) and four (right) + test_must_fail git rev-parse --verify HEAD^4 && + git rev-parse HEAD^1 HEAD^2 HEAD^3 | sort >actual && + git rev-parse two three four | sort >expect && + test_cmp expect actual +' + +test_expect_success 'merge FETCH_HEAD octopus non-fast-forward' ' + t3033_reset && + git fetch . left right && + git merge --no-ff FETCH_HEAD && + test_must_fail git rev-parse --verify HEAD^4 && + git rev-parse HEAD^1 HEAD^2 HEAD^3 | sort >actual && + git rev-parse two three four | sort >expect && + test_cmp expect actual +' + +test_done diff --git a/t/t3060-ls-files-with-tree.sh b/t/t3060-ls-files-with-tree.sh index 61c1f53d1b..44f378ce41 100755 --- a/t/t3060-ls-files-with-tree.sh +++ b/t/t3060-ls-files-with-tree.sh @@ -18,22 +18,16 @@ test_expect_success setup ' echo file >expected && mkdir sub && - bad= && for n in 0 1 2 3 4 5 do for m in 0 1 2 3 4 5 6 7 8 9 do num=00$n$m && >sub/file-$num && - echo file-$num >>expected || { - bad=t - break - } - done && test -z "$bad" || { - bad=t - break - } - done && test -z "$bad" && + echo file-$num >>expected || + return 1 + done + done && git add . && git commit -m "add a bunch of files" && diff --git a/t/t3102-ls-tree-wildcards.sh b/t/t3102-ls-tree-wildcards.sh index c286854485..4d4b02e760 100755 --- a/t/t3102-ls-tree-wildcards.sh +++ b/t/t3102-ls-tree-wildcards.sh @@ -12,11 +12,25 @@ test_expect_success 'setup' ' ' test_expect_success 'ls-tree a[a] matches literally' ' - cat >expected <<EOF && -100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 a[a]/three -EOF + cat >expect <<-\EOF && + 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 a[a]/three + EOF git ls-tree -r HEAD "a[a]" >actual && - test_cmp expected actual + test_cmp expect actual +' + +test_expect_success 'ls-tree outside prefix' ' + cat >expect <<-\EOF && + 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 ../a[a]/three + EOF + ( cd aa && git ls-tree -r HEAD "../a[a]"; ) >actual && + test_cmp expect actual +' + +test_expect_failure 'ls-tree does not yet support negated pathspec' ' + git ls-files ":(exclude)a" "a*" >expect && + git ls-tree --name-only -r HEAD ":(exclude)a" "a*" >actual && + test_cmp expect actual ' test_done diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index ac31b711f2..cdaf6f64ec 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -59,7 +59,7 @@ test_expect_success 'git branch -l d/e/f should create a branch and a log' ' test_expect_success 'git branch -d d/e/f should delete a branch and a log' ' git branch -d d/e/f && test_path_is_missing .git/refs/heads/d/e/f && - test_path_is_missing .git/logs/refs/heads/d/e/f + test_must_fail git reflog exists refs/heads/d/e/f ' test_expect_success 'git branch j/k should work after branch j has been deleted' ' @@ -82,13 +82,13 @@ test_expect_success 'git branch -m dumps usage' ' test_expect_success 'git branch -m m m/m should work' ' git branch -l m && git branch -m m m/m && - test_path_is_file .git/logs/refs/heads/m/m + git reflog exists refs/heads/m/m ' test_expect_success 'git branch -m n/n n should work' ' git branch -l n/n && git branch -m n/n n && - test_path_is_file .git/logs/refs/heads/n + git reflog exists refs/heads/n ' test_expect_success 'git branch -m o/o o should fail when o/p exists' ' @@ -97,6 +97,20 @@ test_expect_success 'git branch -m o/o o should fail when o/p exists' ' test_must_fail git branch -m o/o o ' +test_expect_success 'git branch -m o/q o/p should fail when o/p exists' ' + git branch o/q && + test_must_fail git branch -m o/q o/p +' + +test_expect_success 'git branch -M o/q o/p should work when o/p exists' ' + git branch -M o/q o/p +' + +test_expect_success 'git branch -m -f o/q o/p should work when o/p exists' ' + git branch o/q && + git branch -m -f o/q o/p +' + test_expect_success 'git branch -m q r/q should fail when r exists' ' git branch q && git branch r && @@ -253,12 +267,12 @@ git config branch.s/s.dummy Hello test_expect_success 'git branch -m s/s s should work when s/t is deleted' ' git branch -l s/s && - test_path_is_file .git/logs/refs/heads/s/s && + git reflog exists refs/heads/s/s && git branch -l s/t && - test_path_is_file .git/logs/refs/heads/s/t && + git reflog exists refs/heads/s/t && git branch -d s/t && git branch -m s/s s && - test_path_is_file .git/logs/refs/heads/s + git reflog exists refs/heads/s ' test_expect_success 'config information was renamed, too' ' @@ -285,6 +299,15 @@ test_expect_success 'deleting a dangling symref' ' test_i18ncmp expect actual ' +test_expect_success 'deleting a self-referential symref' ' + git symbolic-ref refs/heads/self-reference refs/heads/self-reference && + test_path_is_file .git/refs/heads/self-reference && + echo "Deleted branch self-reference (was refs/heads/self-reference)." >expect && + git branch -d self-reference >actual && + test_path_is_missing .git/refs/heads/self-reference && + test_i18ncmp expect actual +' + test_expect_success 'renaming a symref is not allowed' ' git symbolic-ref refs/heads/master2 refs/heads/master && test_must_fail git branch -m master2 master3 && diff --git a/t/t3201-branch-contains.sh b/t/t3201-branch-contains.sh index 141b0611ea..912a6635a8 100755 --- a/t/t3201-branch-contains.sh +++ b/t/t3201-branch-contains.sh @@ -130,4 +130,33 @@ test_expect_success 'implicit --list conflicts with modification options' ' ' +# We want to set up a case where the walk for the tracking info +# of one branch crosses the tip of another branch (and make sure +# that the latter walk does not mess up our flag to see if it was +# merged). +# +# Here "topic" tracks "master" with one extra commit, and "zzz" points to the +# same tip as master The name "zzz" must come alphabetically after "topic" +# as we process them in that order. +test_expect_success 'branch --merged with --verbose' ' + git branch --track topic master && + git branch zzz topic && + git checkout topic && + test_commit foo && + git branch --merged topic >actual && + cat >expect <<-\EOF && + master + * topic + zzz + EOF + test_cmp expect actual && + git branch --verbose --merged topic >actual && + cat >expect <<-\EOF && + master c77a0a9 second on master + * topic 2c939f4 [ahead 1] foo + zzz c77a0a9 second on master + EOF + test_cmp expect actual +' + test_done diff --git a/t/t3202-show-branch-octopus.sh b/t/t3202-show-branch-octopus.sh index 0a5d5e669f..6adf47869c 100755 --- a/t/t3202-show-branch-octopus.sh +++ b/t/t3202-show-branch-octopus.sh @@ -19,7 +19,7 @@ test_expect_success 'setup' ' > file$i && git add file$i && test_tick && - git commit -m branch$i || break + git commit -m branch$i || return 1 done ' diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh index ba4f98e800..4261403cf6 100755 --- a/t/t3203-branch-output.sh +++ b/t/t3203-branch-output.sh @@ -96,7 +96,7 @@ test_expect_success 'git branch -v pattern does not show branch summaries' ' test_expect_success 'git branch shows detached HEAD properly' ' cat >expect <<EOF && -* (detached from $(git rev-parse --short HEAD^0)) +* (HEAD detached at $(git rev-parse --short HEAD^0)) branch-one branch-two master @@ -106,4 +106,82 @@ EOF test_i18ncmp expect actual ' +test_expect_success 'git branch shows detached HEAD properly after checkout --detach' ' + git checkout master && + cat >expect <<EOF && +* (HEAD detached at $(git rev-parse --short HEAD^0)) + branch-one + branch-two + master +EOF + git checkout --detach && + git branch >actual && + test_i18ncmp expect actual +' + +test_expect_success 'git branch shows detached HEAD properly after moving' ' + cat >expect <<EOF && +* (HEAD detached from $(git rev-parse --short HEAD)) + branch-one + branch-two + master +EOF + git reset --hard HEAD^1 && + git branch >actual && + test_i18ncmp expect actual +' + +test_expect_success 'git branch shows detached HEAD properly from tag' ' + cat >expect <<EOF && +* (HEAD detached at fromtag) + branch-one + branch-two + master +EOF + git tag fromtag master && + git checkout fromtag && + git branch >actual && + test_i18ncmp expect actual +' + +test_expect_success 'git branch shows detached HEAD properly after moving from tag' ' + cat >expect <<EOF && +* (HEAD detached from fromtag) + branch-one + branch-two + master +EOF + git reset --hard HEAD^1 && + git branch >actual && + test_i18ncmp expect actual +' + +test_expect_success 'git branch `--sort` option' ' + cat >expect <<-\EOF && + * (HEAD detached from fromtag) + branch-two + branch-one + master + EOF + git branch --sort=objectsize >actual && + test_i18ncmp expect actual +' + +test_expect_success 'git branch --points-at option' ' + cat >expect <<-\EOF && + branch-one + master + EOF + git branch --points-at=branch-one >actual && + test_cmp expect actual +' + +test_expect_success 'ambiguous branch/tag not marked' ' + git tag ambiguous && + git branch ambiguous && + echo " ambiguous" >expect && + git branch --list ambiguous >actual && + test_cmp expect actual +' + test_done diff --git a/t/t3210-pack-refs.sh b/t/t3210-pack-refs.sh index 1a2080e3dc..db244d2f88 100755 --- a/t/t3210-pack-refs.sh +++ b/t/t3210-pack-refs.sh @@ -11,7 +11,9 @@ semantic is still the same. ' . ./test-lib.sh -echo '[core] logallrefupdates = true' >>.git/config +test_expect_success 'enable reflogs' ' + git config core.logallrefupdates true +' test_expect_success \ 'prepare a trivial repository' \ @@ -151,4 +153,62 @@ test_expect_success 'delete ref while another dangling packed ref' ' test_cmp /dev/null result ' +test_expect_success 'pack ref directly below refs/' ' + git update-ref refs/top HEAD && + git pack-refs --all --prune && + grep refs/top .git/packed-refs && + test_path_is_missing .git/refs/top +' + +test_expect_success 'do not pack ref in refs/bisect' ' + git update-ref refs/bisect/local HEAD && + git pack-refs --all --prune && + ! grep refs/bisect/local .git/packed-refs >/dev/null && + test_path_is_file .git/refs/bisect/local +' + +test_expect_success 'disable reflogs' ' + git config core.logallrefupdates false && + rm -rf .git/logs +' + +test_expect_success 'create packed foo/bar/baz branch' ' + git branch foo/bar/baz && + git pack-refs --all --prune && + test_path_is_missing .git/refs/heads/foo/bar/baz && + test_must_fail git reflog exists refs/heads/foo/bar/baz +' + +test_expect_success 'notice d/f conflict with existing directory' ' + test_must_fail git branch foo && + test_must_fail git branch foo/bar +' + +test_expect_success 'existing directory reports concrete ref' ' + test_must_fail git branch foo 2>stderr && + grep refs/heads/foo/bar/baz stderr +' + +test_expect_success 'notice d/f conflict with existing ref' ' + test_must_fail git branch foo/bar/baz/extra && + test_must_fail git branch foo/bar/baz/lots/of/extra/components +' + +test_expect_success 'timeout if packed-refs.lock exists' ' + LOCK=.git/packed-refs.lock && + >"$LOCK" && + test_when_finished "rm -f $LOCK" && + test_must_fail git pack-refs --all --prune +' + +test_expect_success 'retry acquiring packed-refs.lock' ' + LOCK=.git/packed-refs.lock && + >"$LOCK" && + test_when_finished "wait; rm -f $LOCK" && + { + ( sleep 1 ; rm -f $LOCK ) & + } && + git -c core.packedrefstimeout=3000 pack-refs --all --prune +' + test_done diff --git a/t/t3301-notes.sh b/t/t3301-notes.sh index cfd67ff3df..cd70274ea5 100755 --- a/t/t3301-notes.sh +++ b/t/t3301-notes.sh @@ -7,28 +7,22 @@ test_description='Test commit notes' . ./test-lib.sh -cat > fake_editor.sh << \EOF -#!/bin/sh -echo "$MSG" > "$1" -echo "$MSG" >& 2 +write_script fake_editor <<\EOF +echo "$MSG" >"$1" +echo "$MSG" >&2 EOF -chmod a+x fake_editor.sh -GIT_EDITOR=./fake_editor.sh +GIT_EDITOR=./fake_editor export GIT_EDITOR +indent=" " + test_expect_success 'cannot annotate non-existing HEAD' ' test_must_fail env MSG=3 git notes add ' -test_expect_success setup ' - : > a1 && - git add a1 && - test_tick && - git commit -m 1st && - : > a2 && - git add a2 && - test_tick && - git commit -m 2nd +test_expect_success 'setup' ' + test_commit 1st && + test_commit 2nd ' test_expect_success 'need valid notes ref' ' @@ -50,206 +44,186 @@ test_expect_success 'handle empty notes gracefully' ' ' test_expect_success 'show non-existent notes entry with %N' ' - for l in A B - do - echo "$l" - done >expect && - git show -s --format='A%n%NB' >output && - test_cmp expect output + test_write_lines A B >expect && + git show -s --format="A%n%NB" >actual && + test_cmp expect actual ' test_expect_success 'create notes' ' - git config core.notesRef refs/notes/commits && MSG=b4 git notes add && - test ! -f .git/NOTES_EDITMSG && - test 1 = $(git ls-tree refs/notes/commits | wc -l) && - test b4 = $(git notes show) && + test_path_is_missing .git/NOTES_EDITMSG && + git ls-tree -r refs/notes/commits >actual && + test_line_count = 1 actual && + test "b4" = "$(git notes show)" && git show HEAD^ && test_must_fail git notes show HEAD^ ' test_expect_success 'show notes entry with %N' ' - for l in A b4 B - do - echo "$l" - done >expect && - git show -s --format='A%n%NB' >output && - test_cmp expect output + test_write_lines A b4 B >expect && + git show -s --format="A%n%NB" >actual && + test_cmp expect actual ' -cat >expect <<EOF -d423f8c refs/notes/commits@{0}: notes: Notes added by 'git notes add' -EOF - test_expect_success 'create reflog entry' ' - git reflog show refs/notes/commits >output && - test_cmp expect output + cat <<-EOF >expect && + a1d8fa6 refs/notes/commits@{0}: notes: Notes added by '\''git notes add'\'' + EOF + git reflog show refs/notes/commits >actual && + test_cmp expect actual ' test_expect_success 'edit existing notes' ' MSG=b3 git notes edit && - test ! -f .git/NOTES_EDITMSG && - test 1 = $(git ls-tree refs/notes/commits | wc -l) && - test b3 = $(git notes show) && + test_path_is_missing .git/NOTES_EDITMSG && + git ls-tree -r refs/notes/commits >actual && + test_line_count = 1 actual && + test "b3" = "$(git notes show)" && git show HEAD^ && test_must_fail git notes show HEAD^ ' test_expect_success 'cannot "git notes add -m" where notes already exists' ' test_must_fail git notes add -m "b2" && - test ! -f .git/NOTES_EDITMSG && - test 1 = $(git ls-tree refs/notes/commits | wc -l) && - test b3 = $(git notes show) && + test_path_is_missing .git/NOTES_EDITMSG && + git ls-tree -r refs/notes/commits >actual && + test_line_count = 1 actual && + test "b3" = "$(git notes show)" && git show HEAD^ && test_must_fail git notes show HEAD^ ' test_expect_success 'can overwrite existing note with "git notes add -f -m"' ' git notes add -f -m "b1" && - test ! -f .git/NOTES_EDITMSG && - test 1 = $(git ls-tree refs/notes/commits | wc -l) && - test b1 = $(git notes show) && + test_path_is_missing .git/NOTES_EDITMSG && + git ls-tree -r refs/notes/commits >actual && + test_line_count = 1 actual && + test "b1" = "$(git notes show)" && git show HEAD^ && test_must_fail git notes show HEAD^ ' test_expect_success 'add w/no options on existing note morphs into edit' ' MSG=b2 git notes add && - test ! -f .git/NOTES_EDITMSG && - test 1 = $(git ls-tree refs/notes/commits | wc -l) && - test b2 = $(git notes show) && + test_path_is_missing .git/NOTES_EDITMSG && + git ls-tree -r refs/notes/commits >actual && + test_line_count = 1 actual && + test "b2" = "$(git notes show)" && git show HEAD^ && test_must_fail git notes show HEAD^ ' test_expect_success 'can overwrite existing note with "git notes add -f"' ' MSG=b1 git notes add -f && - test ! -f .git/NOTES_EDITMSG && - test 1 = $(git ls-tree refs/notes/commits | wc -l) && - test b1 = $(git notes show) && + test_path_is_missing .git/NOTES_EDITMSG && + git ls-tree -r refs/notes/commits >actual && + test_line_count = 1 actual && + test "b1" = "$(git notes show)" && git show HEAD^ && test_must_fail git notes show HEAD^ ' -cat > expect << EOF -commit 268048bfb8a1fb38e703baceb8ab235421bf80c5 -Author: A U Thor <author@example.com> -Date: Thu Apr 7 15:14:13 2005 -0700 - - 2nd +test_expect_success 'show notes' ' + cat >expect <<-EOF && + commit 7a4ca6ee52a974a66cbaa78e33214535dff1d691 + Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:14:13 2005 -0700 -Notes: - b1 -EOF + ${indent}2nd -test_expect_success 'show notes' ' + Notes: + ${indent}b1 + EOF ! (git cat-file commit HEAD | grep b1) && - git log -1 > output && - test_cmp expect output -' - -test_expect_success 'create multi-line notes (setup)' ' - : > a3 && - git add a3 && - test_tick && - git commit -m 3rd && - MSG="b3 -c3c3c3c3 -d3d3d3" git notes add + git log -1 >actual && + test_cmp expect actual ' -cat > expect-multiline << EOF -commit 1584215f1d29c65e99c6c6848626553fdd07fd75 -Author: A U Thor <author@example.com> -Date: Thu Apr 7 15:15:13 2005 -0700 - - 3rd +test_expect_success 'show multi-line notes' ' + test_commit 3rd && + MSG="b3${LF}c3c3c3c3${LF}d3d3d3" git notes add && + cat >expect-multiline <<-EOF && + commit d07d62e5208f22eb5695e7eb47667dc8b9860290 + Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:15:13 2005 -0700 -Notes: - b3 - c3c3c3c3 - d3d3d3 -EOF + ${indent}3rd -printf "\n" >> expect-multiline -cat expect >> expect-multiline + Notes: + ${indent}b3 + ${indent}c3c3c3c3 + ${indent}d3d3d3 -test_expect_success 'show multi-line notes' ' - git log -2 > output && - test_cmp expect-multiline output + EOF + cat expect >>expect-multiline && + git log -2 >actual && + test_cmp expect-multiline actual ' -test_expect_success 'create -F notes (setup)' ' - : > a4 && - git add a4 && - test_tick && - git commit -m 4th && - echo "xyzzy" > note5 && - git notes add -F note5 -' - -cat > expect-F << EOF -commit 15023535574ded8b1a89052b32673f84cf9582b8 -Author: A U Thor <author@example.com> -Date: Thu Apr 7 15:16:13 2005 -0700 - 4th +test_expect_success 'show -F notes' ' + test_commit 4th && + echo "xyzzy" >note5 && + git notes add -F note5 && + cat >expect-F <<-EOF && + commit 0f7aa3ec6325aeb88b910453bb3eb37c49d75c11 + Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:16:13 2005 -0700 -Notes: - xyzzy -EOF + ${indent}4th -printf "\n" >> expect-F -cat expect-multiline >> expect-F + Notes: + ${indent}xyzzy -test_expect_success 'show -F notes' ' - git log -3 > output && - test_cmp expect-F output + EOF + cat expect-multiline >>expect-F && + git log -3 >actual && + test_cmp expect-F actual ' test_expect_success 'Re-adding -F notes without -f fails' ' - echo "zyxxy" > note5 && + echo "zyxxy" >note5 && test_must_fail git notes add -F note5 && - git log -3 > output && - test_cmp expect-F output + git log -3 >actual && + test_cmp expect-F actual ' -cat >expect << EOF -commit 15023535574ded8b1a89052b32673f84cf9582b8 -tree e070e3af51011e47b183c33adf9736736a525709 -parent 1584215f1d29c65e99c6c6848626553fdd07fd75 -author A U Thor <author@example.com> 1112912173 -0700 -committer C O Mitter <committer@example.com> 1112912173 -0700 - - 4th -EOF test_expect_success 'git log --pretty=raw does not show notes' ' - git log -1 --pretty=raw >output && - test_cmp expect output + cat >expect <<-EOF && + commit 0f7aa3ec6325aeb88b910453bb3eb37c49d75c11 + tree 05ac65288c4c4b3b709a020ae94b2ece2f2201ae + parent d07d62e5208f22eb5695e7eb47667dc8b9860290 + author A U Thor <author@example.com> 1112912173 -0700 + committer C O Mitter <committer@example.com> 1112912173 -0700 + + ${indent}4th + EOF + git log -1 --pretty=raw >actual && + test_cmp expect actual ' -cat >>expect <<EOF - -Notes: - xyzzy -EOF test_expect_success 'git log --show-notes' ' - git log -1 --pretty=raw --show-notes >output && - test_cmp expect output + cat >>expect <<-EOF && + + Notes: + ${indent}xyzzy + EOF + git log -1 --pretty=raw --show-notes >actual && + test_cmp expect actual ' test_expect_success 'git log --no-notes' ' - git log -1 --no-notes >output && - ! grep xyzzy output + git log -1 --no-notes >actual && + ! grep xyzzy actual ' test_expect_success 'git format-patch does not show notes' ' - git format-patch -1 --stdout >output && - ! grep xyzzy output + git format-patch -1 --stdout >actual && + ! grep xyzzy actual ' test_expect_success 'git format-patch --show-notes does show notes' ' - git format-patch --show-notes -1 --stdout >output && - grep xyzzy output + git format-patch --show-notes -1 --stdout >actual && + grep xyzzy actual ' for pretty in \ @@ -261,8 +235,8 @@ do ?*) p="$pretty" not=" not" negate="!" ;; esac test_expect_success "git show $pretty does$not show notes" ' - git show $p >output && - eval "$negate grep xyzzy output" + git show $p >actual && + eval "$negate grep xyzzy actual" ' done @@ -271,161 +245,131 @@ test_expect_success 'setup alternate notes ref' ' ' test_expect_success 'git log --notes shows default notes' ' - git log -1 --notes >output && - grep xyzzy output && - ! grep alternate output + git log -1 --notes >actual && + grep xyzzy actual && + ! grep alternate actual ' test_expect_success 'git log --notes=X shows only X' ' - git log -1 --notes=alternate >output && - ! grep xyzzy output && - grep alternate output + git log -1 --notes=alternate >actual && + ! grep xyzzy actual && + grep alternate actual ' test_expect_success 'git log --notes --notes=X shows both' ' - git log -1 --notes --notes=alternate >output && - grep xyzzy output && - grep alternate output + git log -1 --notes --notes=alternate >actual && + grep xyzzy actual && + grep alternate actual ' test_expect_success 'git log --no-notes resets default state' ' git log -1 --notes --notes=alternate \ --no-notes --notes=alternate \ - >output && - ! grep xyzzy output && - grep alternate output + >actual && + ! grep xyzzy actual && + grep alternate actual ' test_expect_success 'git log --no-notes resets ref list' ' git log -1 --notes --notes=alternate \ --no-notes --notes \ - >output && - grep xyzzy output && - ! grep alternate output -' - -test_expect_success 'create -m notes (setup)' ' - : > a5 && - git add a5 && - test_tick && - git commit -m 5th && - git notes add -m spam -m "foo -bar -baz" -' - -whitespace=" " -cat > expect-m << EOF -commit bd1753200303d0a0344be813e504253b3d98e74d -Author: A U Thor <author@example.com> -Date: Thu Apr 7 15:17:13 2005 -0700 - - 5th - -Notes: - spam -$whitespace - foo - bar - baz -EOF - -printf "\n" >> expect-m -cat expect-F >> expect-m - -test_expect_success 'show -m notes' ' - git log -4 > output && - test_cmp expect-m output -' - -test_expect_success 'remove note with add -f -F /dev/null (setup)' ' - git notes add -f -F /dev/null + >actual && + grep xyzzy actual && + ! grep alternate actual ' -cat > expect-rm-F << EOF -commit bd1753200303d0a0344be813e504253b3d98e74d -Author: A U Thor <author@example.com> -Date: Thu Apr 7 15:17:13 2005 -0700 - - 5th -EOF - -printf "\n" >> expect-rm-F -cat expect-F >> expect-rm-F - -test_expect_success 'verify note removal with -F /dev/null' ' - git log -4 > output && - test_cmp expect-rm-F output && +test_expect_success 'show -m notes' ' + test_commit 5th && + git notes add -m spam -m "foo${LF}bar${LF}baz" && + cat >expect-m <<-EOF && + commit 7f9ad8836c775acb134c0a055fc55fb4cd1ba361 + Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:17:13 2005 -0700 + + ${indent}5th + + Notes: + ${indent}spam + ${indent} + ${indent}foo + ${indent}bar + ${indent}baz + + EOF + cat expect-F >>expect-m && + git log -4 >actual && + test_cmp expect-m actual +' + +test_expect_success 'remove note with add -f -F /dev/null' ' + git notes add -f -F /dev/null && + cat >expect-rm-F <<-EOF && + commit 7f9ad8836c775acb134c0a055fc55fb4cd1ba361 + Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:17:13 2005 -0700 + + ${indent}5th + + EOF + cat expect-F >>expect-rm-F && + git log -4 >actual && + test_cmp expect-rm-F actual && test_must_fail git notes show ' -test_expect_success 'do not create empty note with -m "" (setup)' ' - git notes add -m "" -' - -test_expect_success 'verify non-creation of note with -m ""' ' - git log -4 > output && - test_cmp expect-rm-F output && +test_expect_success 'do not create empty note with -m ""' ' + git notes add -m "" && + git log -4 >actual && + test_cmp expect-rm-F actual && test_must_fail git notes show ' -cat > expect-combine_m_and_F << EOF -foo +test_expect_success 'create note with combination of -m and -F' ' + cat >expect-combine_m_and_F <<-EOF && + foo -xyzzy + xyzzy -bar + bar -zyxxy + zyxxy -baz -EOF - -test_expect_success 'create note with combination of -m and -F' ' - echo "xyzzy" > note_a && - echo "zyxxy" > note_b && + baz + EOF + echo "xyzzy" >note_a && + echo "zyxxy" >note_b && git notes add -m "foo" -F note_a -m "bar" -F note_b -m "baz" && - git notes show > output && - test_cmp expect-combine_m_and_F output + git notes show >actual && + test_cmp expect-combine_m_and_F actual ' -test_expect_success 'remove note with "git notes remove" (setup)' ' +test_expect_success 'remove note with "git notes remove"' ' git notes remove HEAD^ && - git notes remove -' - -cat > expect-rm-remove << EOF -commit bd1753200303d0a0344be813e504253b3d98e74d -Author: A U Thor <author@example.com> -Date: Thu Apr 7 15:17:13 2005 -0700 - - 5th + git notes remove && + cat >expect-rm-remove <<-EOF && + commit 7f9ad8836c775acb134c0a055fc55fb4cd1ba361 + Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:17:13 2005 -0700 -commit 15023535574ded8b1a89052b32673f84cf9582b8 -Author: A U Thor <author@example.com> -Date: Thu Apr 7 15:16:13 2005 -0700 + ${indent}5th - 4th -EOF + commit 0f7aa3ec6325aeb88b910453bb3eb37c49d75c11 + Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:16:13 2005 -0700 -printf "\n" >> expect-rm-remove -cat expect-multiline >> expect-rm-remove + ${indent}4th -test_expect_success 'verify note removal with "git notes remove"' ' - git log -4 > output && - test_cmp expect-rm-remove output && + EOF + cat expect-multiline >>expect-rm-remove && + git log -4 >actual && + test_cmp expect-rm-remove actual && test_must_fail git notes show HEAD^ ' -cat > expect << EOF -c18dc024e14f08d18d14eea0d747ff692d66d6a3 1584215f1d29c65e99c6c6848626553fdd07fd75 -c9c6af7f78bc47490dbf3e822cf2f3c24d4b9061 268048bfb8a1fb38e703baceb8ab235421bf80c5 -EOF - test_expect_success 'removing non-existing note should not create new commit' ' - git rev-parse --verify refs/notes/commits > before_commit && + git rev-parse --verify refs/notes/commits >before_commit && test_must_fail git notes remove HEAD^ && - git rev-parse --verify refs/notes/commits > after_commit && + git rev-parse --verify refs/notes/commits >after_commit && test_cmp before_commit after_commit ' @@ -505,70 +449,68 @@ test_expect_success 'removing with --stdin --ignore-missing' ' ' test_expect_success 'list notes with "git notes list"' ' - git notes list > output && - test_cmp expect output + cat >expect <<-EOF && + c9c6af7f78bc47490dbf3e822cf2f3c24d4b9061 7a4ca6ee52a974a66cbaa78e33214535dff1d691 + c18dc024e14f08d18d14eea0d747ff692d66d6a3 d07d62e5208f22eb5695e7eb47667dc8b9860290 + EOF + git notes list >actual && + test_cmp expect actual ' test_expect_success 'list notes with "git notes"' ' - git notes > output && - test_cmp expect output + git notes >actual && + test_cmp expect actual ' -cat > expect << EOF -c18dc024e14f08d18d14eea0d747ff692d66d6a3 -EOF - test_expect_success 'list specific note with "git notes list <object>"' ' - git notes list HEAD^^ > output && - test_cmp expect output + cat >expect <<-EOF && + c18dc024e14f08d18d14eea0d747ff692d66d6a3 + EOF + git notes list HEAD^^ >actual && + test_cmp expect actual ' -cat > expect << EOF -EOF - test_expect_success 'listing non-existing notes fails' ' - test_must_fail git notes list HEAD > output && - test_cmp expect output + cat >expect <<-EOF && + EOF + test_must_fail git notes list HEAD >actual && + test_cmp expect actual ' -cat > expect << EOF -Initial set of notes - -More notes appended with git notes append -EOF - test_expect_success 'append to existing note with "git notes append"' ' + cat >expect <<-EOF && + Initial set of notes + + More notes appended with git notes append + EOF git notes add -m "Initial set of notes" && git notes append -m "More notes appended with git notes append" && - git notes show > output && - test_cmp expect output + git notes show >actual && + test_cmp expect actual ' -cat > expect_list << EOF -c18dc024e14f08d18d14eea0d747ff692d66d6a3 1584215f1d29c65e99c6c6848626553fdd07fd75 -c9c6af7f78bc47490dbf3e822cf2f3c24d4b9061 268048bfb8a1fb38e703baceb8ab235421bf80c5 -4b6ad22357cc8a1296720574b8d2fbc22fab0671 bd1753200303d0a0344be813e504253b3d98e74d -EOF - test_expect_success '"git notes list" does not expand to "git notes list HEAD"' ' - git notes list > output && - test_cmp expect_list output + cat >expect_list <<-EOF && + c9c6af7f78bc47490dbf3e822cf2f3c24d4b9061 7a4ca6ee52a974a66cbaa78e33214535dff1d691 + 4b6ad22357cc8a1296720574b8d2fbc22fab0671 7f9ad8836c775acb134c0a055fc55fb4cd1ba361 + c18dc024e14f08d18d14eea0d747ff692d66d6a3 d07d62e5208f22eb5695e7eb47667dc8b9860290 + EOF + git notes list >actual && + test_cmp expect_list actual ' test_expect_success 'appending empty string does not change existing note' ' git notes append -m "" && - git notes show > output && - test_cmp expect output + git notes show >actual && + test_cmp expect actual ' test_expect_success 'git notes append == add when there is no existing note' ' git notes remove HEAD && test_must_fail git notes list HEAD && - git notes append -m "Initial set of notes - -More notes appended with git notes append" && - git notes show > output && - test_cmp expect output + git notes append -m "Initial set of notes${LF}${LF}More notes appended with git notes append" && + git notes show >actual && + test_cmp expect actual ' test_expect_success 'appending empty string to non-existing note does not create note' ' @@ -579,229 +521,208 @@ test_expect_success 'appending empty string to non-existing note does not create ' test_expect_success 'create other note on a different notes ref (setup)' ' - : > a6 && - git add a6 && - test_tick && - git commit -m 6th && - GIT_NOTES_REF="refs/notes/other" git notes add -m "other note" -' - -cat > expect-other << EOF -commit 387a89921c73d7ed72cd94d179c1c7048ca47756 -Author: A U Thor <author@example.com> -Date: Thu Apr 7 15:18:13 2005 -0700 - - 6th - -Notes (other): - other note -EOF + test_commit 6th && + GIT_NOTES_REF="refs/notes/other" git notes add -m "other note" && + cat >expect-not-other <<-EOF && + commit 2c125331118caba0ff8238b7f4958ac6e93fe39c + Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:18:13 2005 -0700 -cat > expect-not-other << EOF -commit 387a89921c73d7ed72cd94d179c1c7048ca47756 -Author: A U Thor <author@example.com> -Date: Thu Apr 7 15:18:13 2005 -0700 + ${indent}6th + EOF + cp expect-not-other expect-other && + cat >>expect-other <<-EOF - 6th -EOF + Notes (other): + ${indent}other note + EOF +' test_expect_success 'Do not show note on other ref by default' ' - git log -1 > output && - test_cmp expect-not-other output + git log -1 >actual && + test_cmp expect-not-other actual ' test_expect_success 'Do show note when ref is given in GIT_NOTES_REF' ' - GIT_NOTES_REF="refs/notes/other" git log -1 > output && - test_cmp expect-other output + GIT_NOTES_REF="refs/notes/other" git log -1 >actual && + test_cmp expect-other actual ' test_expect_success 'Do show note when ref is given in core.notesRef config' ' - git config core.notesRef "refs/notes/other" && - git log -1 > output && - test_cmp expect-other output + test_config core.notesRef "refs/notes/other" && + git log -1 >actual && + test_cmp expect-other actual ' test_expect_success 'Do not show note when core.notesRef is overridden' ' - GIT_NOTES_REF="refs/notes/wrong" git log -1 > output && - test_cmp expect-not-other output + test_config core.notesRef "refs/notes/other" && + GIT_NOTES_REF="refs/notes/wrong" git log -1 >actual && + test_cmp expect-not-other actual ' -cat > expect-both << EOF -commit 387a89921c73d7ed72cd94d179c1c7048ca47756 -Author: A U Thor <author@example.com> -Date: Thu Apr 7 15:18:13 2005 -0700 - - 6th +test_expect_success 'Show all notes when notes.displayRef=refs/notes/*' ' + cat >expect-both <<-EOF && + commit 2c125331118caba0ff8238b7f4958ac6e93fe39c + Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:18:13 2005 -0700 -Notes: - order test + ${indent}6th -Notes (other): - other note + Notes: + ${indent}order test -commit bd1753200303d0a0344be813e504253b3d98e74d -Author: A U Thor <author@example.com> -Date: Thu Apr 7 15:17:13 2005 -0700 + Notes (other): + ${indent}other note - 5th + commit 7f9ad8836c775acb134c0a055fc55fb4cd1ba361 + Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:17:13 2005 -0700 -Notes: - replacement for deleted note -EOF + ${indent}5th -test_expect_success 'Show all notes when notes.displayRef=refs/notes/*' ' + Notes: + ${indent}replacement for deleted note + EOF GIT_NOTES_REF=refs/notes/commits git notes add \ -m"replacement for deleted note" HEAD^ && GIT_NOTES_REF=refs/notes/commits git notes add -m"order test" && - git config --unset core.notesRef && - git config notes.displayRef "refs/notes/*" && - git log -2 > output && - test_cmp expect-both output + test_unconfig core.notesRef && + test_config notes.displayRef "refs/notes/*" && + git log -2 >actual && + test_cmp expect-both actual ' test_expect_success 'core.notesRef is implicitly in notes.displayRef' ' - git config core.notesRef refs/notes/commits && - git config notes.displayRef refs/notes/other && - git log -2 > output && - test_cmp expect-both output + test_config core.notesRef refs/notes/commits && + test_config notes.displayRef refs/notes/other && + git log -2 >actual && + test_cmp expect-both actual ' test_expect_success 'notes.displayRef can be given more than once' ' - git config --unset core.notesRef && - git config notes.displayRef refs/notes/commits && + test_unconfig core.notesRef && + test_config notes.displayRef refs/notes/commits && git config --add notes.displayRef refs/notes/other && - git log -2 > output && - test_cmp expect-both output + git log -2 >actual && + test_cmp expect-both actual ' -cat > expect-both-reversed << EOF -commit 387a89921c73d7ed72cd94d179c1c7048ca47756 -Author: A U Thor <author@example.com> -Date: Thu Apr 7 15:18:13 2005 -0700 - - 6th +test_expect_success 'notes.displayRef respects order' ' + cat >expect-both-reversed <<-EOF && + commit 2c125331118caba0ff8238b7f4958ac6e93fe39c + Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:18:13 2005 -0700 -Notes (other): - other note + ${indent}6th -Notes: - order test -EOF + Notes (other): + ${indent}other note -test_expect_success 'notes.displayRef respects order' ' - git config core.notesRef refs/notes/other && - git config --unset-all notes.displayRef && - git config notes.displayRef refs/notes/commits && - git log -1 > output && - test_cmp expect-both-reversed output + Notes: + ${indent}order test + EOF + test_config core.notesRef refs/notes/other && + test_config notes.displayRef refs/notes/commits && + git log -1 >actual && + test_cmp expect-both-reversed actual ' test_expect_success 'GIT_NOTES_DISPLAY_REF works' ' - git config --unset-all core.notesRef && - git config --unset-all notes.displayRef && GIT_NOTES_DISPLAY_REF=refs/notes/commits:refs/notes/other \ - git log -2 > output && - test_cmp expect-both output + git log -2 >actual && + test_cmp expect-both actual ' -cat > expect-none << EOF -commit 387a89921c73d7ed72cd94d179c1c7048ca47756 -Author: A U Thor <author@example.com> -Date: Thu Apr 7 15:18:13 2005 -0700 +test_expect_success 'GIT_NOTES_DISPLAY_REF overrides config' ' + cat >expect-none <<-EOF && + commit 2c125331118caba0ff8238b7f4958ac6e93fe39c + Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:18:13 2005 -0700 - 6th + ${indent}6th -commit bd1753200303d0a0344be813e504253b3d98e74d -Author: A U Thor <author@example.com> -Date: Thu Apr 7 15:17:13 2005 -0700 + commit 7f9ad8836c775acb134c0a055fc55fb4cd1ba361 + Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:17:13 2005 -0700 - 5th -EOF - -test_expect_success 'GIT_NOTES_DISPLAY_REF overrides config' ' - git config notes.displayRef "refs/notes/*" && - GIT_NOTES_REF= GIT_NOTES_DISPLAY_REF= git log -2 > output && - test_cmp expect-none output + ${indent}5th + EOF + test_config notes.displayRef "refs/notes/*" && + GIT_NOTES_REF= GIT_NOTES_DISPLAY_REF= git log -2 >actual && + test_cmp expect-none actual ' test_expect_success '--show-notes=* adds to GIT_NOTES_DISPLAY_REF' ' - GIT_NOTES_REF= GIT_NOTES_DISPLAY_REF= git log --show-notes=* -2 > output && - test_cmp expect-both output + GIT_NOTES_REF= GIT_NOTES_DISPLAY_REF= git log --show-notes=* -2 >actual && + test_cmp expect-both actual ' -cat > expect-commits << EOF -commit 387a89921c73d7ed72cd94d179c1c7048ca47756 -Author: A U Thor <author@example.com> -Date: Thu Apr 7 15:18:13 2005 -0700 - - 6th +test_expect_success '--no-standard-notes' ' + cat >expect-commits <<-EOF && + commit 2c125331118caba0ff8238b7f4958ac6e93fe39c + Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:18:13 2005 -0700 -Notes: - order test -EOF + ${indent}6th -test_expect_success '--no-standard-notes' ' - git log --no-standard-notes --show-notes=commits -1 > output && - test_cmp expect-commits output + Notes: + ${indent}order test + EOF + git log --no-standard-notes --show-notes=commits -1 >actual && + test_cmp expect-commits actual ' test_expect_success '--standard-notes' ' + test_config notes.displayRef "refs/notes/*" && git log --no-standard-notes --show-notes=commits \ - --standard-notes -2 > output && - test_cmp expect-both output + --standard-notes -2 >actual && + test_cmp expect-both actual ' test_expect_success '--show-notes=ref accumulates' ' git log --show-notes=other --show-notes=commits \ - --no-standard-notes -1 > output && - test_cmp expect-both-reversed output + --no-standard-notes -1 >actual && + test_cmp expect-both-reversed actual ' test_expect_success 'Allow notes on non-commits (trees, blobs, tags)' ' - git config core.notesRef refs/notes/other && - echo "Note on a tree" > expect && + test_config core.notesRef refs/notes/other && + echo "Note on a tree" >expect && git notes add -m "Note on a tree" HEAD: && - git notes show HEAD: > actual && + git notes show HEAD: >actual && test_cmp expect actual && - echo "Note on a blob" > expect && + echo "Note on a blob" >expect && filename=$(git ls-tree --name-only HEAD | head -n1) && git notes add -m "Note on a blob" HEAD:$filename && - git notes show HEAD:$filename > actual && + git notes show HEAD:$filename >actual && test_cmp expect actual && - echo "Note on a tag" > expect && + echo "Note on a tag" >expect && git tag -a -m "This is an annotated tag" foobar HEAD^ && git notes add -m "Note on a tag" foobar && - git notes show foobar > actual && + git notes show foobar >actual && test_cmp expect actual ' -cat > expect << EOF -commit 2ede89468182a62d0bde2583c736089bcf7d7e92 -Author: A U Thor <author@example.com> -Date: Thu Apr 7 15:19:13 2005 -0700 - - 7th +test_expect_success 'create note from other note with "git notes add -C"' ' + cat >expect <<-EOF && + commit fb01e0ca8c33b6cc0c6451dde747f97df567cb5c + Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:19:13 2005 -0700 -Notes (other): - other note -EOF + ${indent}7th -test_expect_success 'create note from other note with "git notes add -C"' ' - : > a7 && - git add a7 && - test_tick && - git commit -m 7th && + Notes: + ${indent}order test + EOF + test_commit 7th && git notes add -C $(git notes list HEAD^) && - git log -1 > actual && + git log -1 >actual && test_cmp expect actual && test "$(git notes list HEAD)" = "$(git notes list HEAD^)" ' test_expect_success 'create note from non-existing note with "git notes add -C" fails' ' - : > a8 && - git add a8 && - test_tick && - git commit -m 8th && + test_commit 8th && test_must_fail git notes add -C deadbeef && test_must_fail git notes list HEAD ' @@ -814,405 +735,386 @@ test_expect_success 'create note from non-blob with "git notes add -C" fails' ' test_must_fail git notes list HEAD ' -cat > expect << EOF -commit 80d796defacd5db327b7a4e50099663902fbdc5c -Author: A U Thor <author@example.com> -Date: Thu Apr 7 15:20:13 2005 -0700 - - 8th +test_expect_success 'create note from blob with "git notes add -C" reuses blob id' ' + cat >expect <<-EOF && + commit 9a4c31c7f722b5d517e92c64e932dd751e1413bf + Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:20:13 2005 -0700 -Notes (other): - This is a blob object -EOF + ${indent}8th -test_expect_success 'create note from blob with "git notes add -C" reuses blob id' ' + Notes: + ${indent}This is a blob object + EOF blob=$(echo "This is a blob object" | git hash-object -w --stdin) && git notes add -C $blob && - git log -1 > actual && + git log -1 >actual && test_cmp expect actual && test "$(git notes list HEAD)" = "$blob" ' -cat > expect << EOF -commit 016e982bad97eacdbda0fcbd7ce5b0ba87c81f1b -Author: A U Thor <author@example.com> -Date: Thu Apr 7 15:21:13 2005 -0700 - - 9th +test_expect_success 'create note from other note with "git notes add -c"' ' + cat >expect <<-EOF && + commit 2e0db4bc649e174d667a1cde19e725cf897a5bd2 + Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:21:13 2005 -0700 -Notes (other): - yet another note -EOF + ${indent}9th -test_expect_success 'create note from other note with "git notes add -c"' ' - : > a9 && - git add a9 && - test_tick && - git commit -m 9th && + Notes: + ${indent}yet another note + EOF + test_commit 9th && MSG="yet another note" git notes add -c $(git notes list HEAD^^) && - git log -1 > actual && + git log -1 >actual && test_cmp expect actual ' test_expect_success 'create note from non-existing note with "git notes add -c" fails' ' - : > a10 && - git add a10 && - test_tick && - git commit -m 10th && + test_commit 10th && test_must_fail env MSG="yet another note" git notes add -c deadbeef && test_must_fail git notes list HEAD ' -cat > expect << EOF -commit 016e982bad97eacdbda0fcbd7ce5b0ba87c81f1b -Author: A U Thor <author@example.com> -Date: Thu Apr 7 15:21:13 2005 -0700 - - 9th - -Notes (other): - yet another note -$whitespace - yet another note -EOF - test_expect_success 'append to note from other note with "git notes append -C"' ' + cat >expect <<-EOF && + commit 2e0db4bc649e174d667a1cde19e725cf897a5bd2 + Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:21:13 2005 -0700 + + ${indent}9th + + Notes: + ${indent}yet another note + ${indent} + ${indent}yet another note + EOF git notes append -C $(git notes list HEAD^) HEAD^ && - git log -1 HEAD^ > actual && + git log -1 HEAD^ >actual && test_cmp expect actual ' -cat > expect << EOF -commit ffed603236bfa3891c49644257a83598afe8ae5a -Author: A U Thor <author@example.com> -Date: Thu Apr 7 15:22:13 2005 -0700 - - 10th +test_expect_success 'create note from other note with "git notes append -c"' ' + cat >expect <<-EOF && + commit 7c3b87ab368f81e11b1ea87b2ab99a71ccd25406 + Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:22:13 2005 -0700 -Notes (other): - other note -EOF + ${indent}10th -test_expect_success 'create note from other note with "git notes append -c"' ' + Notes: + ${indent}other note + EOF MSG="other note" git notes append -c $(git notes list HEAD^) && - git log -1 > actual && + git log -1 >actual && test_cmp expect actual ' -cat > expect << EOF -commit ffed603236bfa3891c49644257a83598afe8ae5a -Author: A U Thor <author@example.com> -Date: Thu Apr 7 15:22:13 2005 -0700 - - 10th - -Notes (other): - other note -$whitespace - yet another note -EOF - test_expect_success 'append to note from other note with "git notes append -c"' ' + cat >expect <<-EOF && + commit 7c3b87ab368f81e11b1ea87b2ab99a71ccd25406 + Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:22:13 2005 -0700 + + ${indent}10th + + Notes: + ${indent}other note + ${indent} + ${indent}yet another note + EOF MSG="yet another note" git notes append -c $(git notes list HEAD) && - git log -1 > actual && + git log -1 >actual && test_cmp expect actual ' -cat > expect << EOF -commit 6352c5e33dbcab725fe0579be16aa2ba8eb369be -Author: A U Thor <author@example.com> -Date: Thu Apr 7 15:23:13 2005 -0700 - - 11th - -Notes (other): - other note -$whitespace - yet another note -EOF - test_expect_success 'copy note with "git notes copy"' ' - : > a11 && - git add a11 && - test_tick && - git commit -m 11th && + cat >expect <<-EOF && + commit a446fff8777efdc6eb8f4b7c8a5ff699484df0d5 + Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:23:13 2005 -0700 + + ${indent}11th + + Notes: + ${indent}other note + ${indent} + ${indent}yet another note + EOF + test_commit 11th && git notes copy HEAD^ HEAD && - git log -1 > actual && + git log -1 >actual && test_cmp expect actual && test "$(git notes list HEAD)" = "$(git notes list HEAD^)" ' test_expect_success 'prevent overwrite with "git notes copy"' ' test_must_fail git notes copy HEAD~2 HEAD && - git log -1 > actual && + git log -1 >actual && test_cmp expect actual && test "$(git notes list HEAD)" = "$(git notes list HEAD^)" ' -cat > expect << EOF -commit 6352c5e33dbcab725fe0579be16aa2ba8eb369be -Author: A U Thor <author@example.com> -Date: Thu Apr 7 15:23:13 2005 -0700 - - 11th - -Notes (other): - yet another note -$whitespace - yet another note -EOF - test_expect_success 'allow overwrite with "git notes copy -f"' ' + cat >expect <<-EOF && + commit a446fff8777efdc6eb8f4b7c8a5ff699484df0d5 + Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:23:13 2005 -0700 + + ${indent}11th + + Notes: + ${indent}yet another note + ${indent} + ${indent}yet another note + EOF git notes copy -f HEAD~2 HEAD && - git log -1 > actual && + git log -1 >actual && test_cmp expect actual && test "$(git notes list HEAD)" = "$(git notes list HEAD~2)" ' test_expect_success 'cannot copy note from object without notes' ' - : > a12 && - git add a12 && - test_tick && - git commit -m 12th && - : > a13 && - git add a13 && - test_tick && - git commit -m 13th && + test_commit 12th && + test_commit 13th && test_must_fail git notes copy HEAD^ HEAD ' -cat > expect << EOF -commit e5d4fb5698d564ab8c73551538ecaf2b0c666185 -Author: A U Thor <author@example.com> -Date: Thu Apr 7 15:25:13 2005 -0700 +test_expect_success 'git notes copy --stdin' ' + cat >expect <<-EOF && + commit e871aa61182b1d95d0a6fb75445d891722863b6b + Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:25:13 2005 -0700 - 13th + ${indent}13th -Notes (other): - yet another note -$whitespace - yet another note + Notes: + ${indent}yet another note + ${indent} + ${indent}yet another note -commit 7038787dfe22a14c3867ce816dbba39845359719 -Author: A U Thor <author@example.com> -Date: Thu Apr 7 15:24:13 2005 -0700 + commit 65e263ded02ae4e8839bc151095113737579dc12 + Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:24:13 2005 -0700 - 12th + ${indent}12th -Notes (other): - other note -$whitespace - yet another note -EOF - -test_expect_success 'git notes copy --stdin' ' + Notes: + ${indent}other note + ${indent} + ${indent}yet another note + EOF (echo $(git rev-parse HEAD~3) $(git rev-parse HEAD^); \ echo $(git rev-parse HEAD~2) $(git rev-parse HEAD)) | git notes copy --stdin && - git log -2 > output && - test_cmp expect output && + git log -2 >actual && + test_cmp expect actual && test "$(git notes list HEAD)" = "$(git notes list HEAD~2)" && test "$(git notes list HEAD^)" = "$(git notes list HEAD~3)" ' -cat > expect << EOF -commit 37a0d4cba38afef96ba54a3ea567e6dac575700b -Author: A U Thor <author@example.com> -Date: Thu Apr 7 15:27:13 2005 -0700 - - 15th +test_expect_success 'git notes copy --for-rewrite (unconfigured)' ' + cat >expect <<-EOF && + commit 4acf42e847e7fffbbf89ee365c20ac7caf40de89 + Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:27:13 2005 -0700 -commit be28d8b4d9951ad940d229ee3b0b9ee3b1ec273d -Author: A U Thor <author@example.com> -Date: Thu Apr 7 15:26:13 2005 -0700 + ${indent}15th - 14th -EOF + commit 07c85d77059393ed0154b8c96906547a59dfcddd + Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:26:13 2005 -0700 -test_expect_success 'git notes copy --for-rewrite (unconfigured)' ' + ${indent}14th + EOF test_commit 14th && test_commit 15th && (echo $(git rev-parse HEAD~3) $(git rev-parse HEAD^); \ echo $(git rev-parse HEAD~2) $(git rev-parse HEAD)) | git notes copy --for-rewrite=foo && - git log -2 > output && - test_cmp expect output + git log -2 >actual && + test_cmp expect actual ' -cat > expect << EOF -commit 37a0d4cba38afef96ba54a3ea567e6dac575700b -Author: A U Thor <author@example.com> -Date: Thu Apr 7 15:27:13 2005 -0700 - - 15th - -Notes (other): - yet another note -$whitespace - yet another note - -commit be28d8b4d9951ad940d229ee3b0b9ee3b1ec273d -Author: A U Thor <author@example.com> -Date: Thu Apr 7 15:26:13 2005 -0700 - - 14th - -Notes (other): - other note -$whitespace - yet another note -EOF - test_expect_success 'git notes copy --for-rewrite (enabled)' ' - git config notes.rewriteMode overwrite && - git config notes.rewriteRef "refs/notes/*" && + cat >expect <<-EOF && + commit 4acf42e847e7fffbbf89ee365c20ac7caf40de89 + Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:27:13 2005 -0700 + + ${indent}15th + + Notes: + ${indent}yet another note + ${indent} + ${indent}yet another note + + commit 07c85d77059393ed0154b8c96906547a59dfcddd + Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:26:13 2005 -0700 + + ${indent}14th + + Notes: + ${indent}other note + ${indent} + ${indent}yet another note + EOF + test_config notes.rewriteMode overwrite && + test_config notes.rewriteRef "refs/notes/*" && (echo $(git rev-parse HEAD~3) $(git rev-parse HEAD^); \ echo $(git rev-parse HEAD~2) $(git rev-parse HEAD)) | git notes copy --for-rewrite=foo && - git log -2 > output && - test_cmp expect output + git log -2 >actual && + test_cmp expect actual ' test_expect_success 'git notes copy --for-rewrite (disabled)' ' - git config notes.rewrite.bar false && + test_config notes.rewrite.bar false && echo $(git rev-parse HEAD~3) $(git rev-parse HEAD) | git notes copy --for-rewrite=bar && - git log -2 > output && - test_cmp expect output + git log -2 >actual && + test_cmp expect actual ' -cat > expect << EOF -commit 37a0d4cba38afef96ba54a3ea567e6dac575700b -Author: A U Thor <author@example.com> -Date: Thu Apr 7 15:27:13 2005 -0700 - - 15th +test_expect_success 'git notes copy --for-rewrite (overwrite)' ' + cat >expect <<-EOF && + commit 4acf42e847e7fffbbf89ee365c20ac7caf40de89 + Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:27:13 2005 -0700 -Notes (other): - a fresh note -EOF + ${indent}15th -test_expect_success 'git notes copy --for-rewrite (overwrite)' ' + Notes: + ${indent}a fresh note + EOF git notes add -f -m"a fresh note" HEAD^ && + test_config notes.rewriteMode overwrite && + test_config notes.rewriteRef "refs/notes/*" && echo $(git rev-parse HEAD^) $(git rev-parse HEAD) | git notes copy --for-rewrite=foo && - git log -1 > output && - test_cmp expect output + git log -1 >actual && + test_cmp expect actual ' test_expect_success 'git notes copy --for-rewrite (ignore)' ' - git config notes.rewriteMode ignore && + test_config notes.rewriteMode ignore && + test_config notes.rewriteRef "refs/notes/*" && echo $(git rev-parse HEAD^) $(git rev-parse HEAD) | git notes copy --for-rewrite=foo && - git log -1 > output && - test_cmp expect output + git log -1 >actual && + test_cmp expect actual ' -cat > expect << EOF -commit 37a0d4cba38afef96ba54a3ea567e6dac575700b -Author: A U Thor <author@example.com> -Date: Thu Apr 7 15:27:13 2005 -0700 - - 15th - -Notes (other): - a fresh note -$whitespace - another fresh note -EOF - test_expect_success 'git notes copy --for-rewrite (append)' ' + cat >expect <<-EOF && + commit 4acf42e847e7fffbbf89ee365c20ac7caf40de89 + Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:27:13 2005 -0700 + + ${indent}15th + + Notes: + ${indent}a fresh note + ${indent} + ${indent}another fresh note + EOF git notes add -f -m"another fresh note" HEAD^ && - git config notes.rewriteMode concatenate && + test_config notes.rewriteMode concatenate && + test_config notes.rewriteRef "refs/notes/*" && echo $(git rev-parse HEAD^) $(git rev-parse HEAD) | git notes copy --for-rewrite=foo && - git log -1 > output && - test_cmp expect output + git log -1 >actual && + test_cmp expect actual ' -cat > expect << EOF -commit 37a0d4cba38afef96ba54a3ea567e6dac575700b -Author: A U Thor <author@example.com> -Date: Thu Apr 7 15:27:13 2005 -0700 - - 15th - -Notes (other): - a fresh note -$whitespace - another fresh note -$whitespace - append 1 -$whitespace - append 2 -EOF - test_expect_success 'git notes copy --for-rewrite (append two to one)' ' + cat >expect <<-EOF && + commit 4acf42e847e7fffbbf89ee365c20ac7caf40de89 + Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:27:13 2005 -0700 + + ${indent}15th + + Notes: + ${indent}a fresh note + ${indent} + ${indent}another fresh note + ${indent} + ${indent}append 1 + ${indent} + ${indent}append 2 + EOF git notes add -f -m"append 1" HEAD^ && git notes add -f -m"append 2" HEAD^^ && + test_config notes.rewriteMode concatenate && + test_config notes.rewriteRef "refs/notes/*" && (echo $(git rev-parse HEAD^) $(git rev-parse HEAD); echo $(git rev-parse HEAD^^) $(git rev-parse HEAD)) | git notes copy --for-rewrite=foo && - git log -1 > output && - test_cmp expect output + git log -1 >actual && + test_cmp expect actual ' test_expect_success 'git notes copy --for-rewrite (append empty)' ' git notes remove HEAD^ && + test_config notes.rewriteMode concatenate && + test_config notes.rewriteRef "refs/notes/*" && echo $(git rev-parse HEAD^) $(git rev-parse HEAD) | git notes copy --for-rewrite=foo && - git log -1 > output && - test_cmp expect output + git log -1 >actual && + test_cmp expect actual ' -cat > expect << EOF -commit 37a0d4cba38afef96ba54a3ea567e6dac575700b -Author: A U Thor <author@example.com> -Date: Thu Apr 7 15:27:13 2005 -0700 - - 15th - -Notes (other): - replacement note 1 -EOF - test_expect_success 'GIT_NOTES_REWRITE_MODE works' ' + cat >expect <<-EOF && + commit 4acf42e847e7fffbbf89ee365c20ac7caf40de89 + Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:27:13 2005 -0700 + + ${indent}15th + + Notes: + ${indent}replacement note 1 + EOF + test_config notes.rewriteMode concatenate && + test_config notes.rewriteRef "refs/notes/*" && git notes add -f -m"replacement note 1" HEAD^ && echo $(git rev-parse HEAD^) $(git rev-parse HEAD) | GIT_NOTES_REWRITE_MODE=overwrite git notes copy --for-rewrite=foo && - git log -1 > output && - test_cmp expect output + git log -1 >actual && + test_cmp expect actual ' -cat > expect << EOF -commit 37a0d4cba38afef96ba54a3ea567e6dac575700b -Author: A U Thor <author@example.com> -Date: Thu Apr 7 15:27:13 2005 -0700 - - 15th +test_expect_success 'GIT_NOTES_REWRITE_REF works' ' + cat >expect <<-EOF && + commit 4acf42e847e7fffbbf89ee365c20ac7caf40de89 + Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:27:13 2005 -0700 -Notes (other): - replacement note 2 -EOF + ${indent}15th -test_expect_success 'GIT_NOTES_REWRITE_REF works' ' - git config notes.rewriteMode overwrite && + Notes: + ${indent}replacement note 2 + EOF git notes add -f -m"replacement note 2" HEAD^ && - git config --unset-all notes.rewriteRef && + test_config notes.rewriteMode overwrite && + test_unconfig notes.rewriteRef && echo $(git rev-parse HEAD^) $(git rev-parse HEAD) | GIT_NOTES_REWRITE_REF=refs/notes/commits:refs/notes/other \ git notes copy --for-rewrite=foo && - git log -1 > output && - test_cmp expect output + git log -1 >actual && + test_cmp expect actual ' test_expect_success 'GIT_NOTES_REWRITE_REF overrides config' ' - git config notes.rewriteRef refs/notes/other && git notes add -f -m"replacement note 3" HEAD^ && + test_config notes.rewriteMode overwrite && + test_config notes.rewriteRef refs/notes/other && echo $(git rev-parse HEAD^) $(git rev-parse HEAD) | GIT_NOTES_REWRITE_REF= git notes copy --for-rewrite=foo && - git log -1 > output && - test_cmp expect output + git log -1 >actual && + test_cmp expect actual ' test_expect_success 'git notes copy diagnoses too many or too few parameters' ' @@ -1220,14 +1122,20 @@ test_expect_success 'git notes copy diagnoses too many or too few parameters' ' test_must_fail git notes copy one two three ' +test_expect_success 'git notes get-ref expands refs/heads/master to refs/notes/refs/heads/master' ' + test_unconfig core.notesRef && + sane_unset GIT_NOTES_REF && + test "$(git notes --ref=refs/heads/master get-ref)" = "refs/notes/refs/heads/master" +' + test_expect_success 'git notes get-ref (no overrides)' ' - git config --unset core.notesRef && + test_unconfig core.notesRef && sane_unset GIT_NOTES_REF && test "$(git notes get-ref)" = "refs/notes/commits" ' test_expect_success 'git notes get-ref (core.notesRef)' ' - git config core.notesRef refs/notes/foo && + test_config core.notesRef refs/notes/foo && test "$(git notes get-ref)" = "refs/notes/foo" ' @@ -1239,4 +1147,51 @@ test_expect_success 'git notes get-ref (--ref)' ' test "$(GIT_NOTES_REF=refs/notes/bar git notes --ref=baz get-ref)" = "refs/notes/baz" ' +test_expect_success 'setup testing of empty notes' ' + test_unconfig core.notesRef && + test_commit 16th && + empty_blob=$(git hash-object -w /dev/null) && + echo "$empty_blob" >expect_empty +' + +while read cmd +do + test_expect_success "'git notes $cmd' removes empty note" " + test_might_fail git notes remove HEAD && + MSG= git notes $cmd && + test_must_fail git notes list HEAD + " + + test_expect_success "'git notes $cmd --allow-empty' stores empty note" " + test_might_fail git notes remove HEAD && + MSG= git notes $cmd --allow-empty && + git notes list HEAD >actual && + test_cmp expect_empty actual + " +done <<\EOF +add +add -F /dev/null +add -m "" +add -c "$empty_blob" +add -C "$empty_blob" +append +append -F /dev/null +append -m "" +append -c "$empty_blob" +append -C "$empty_blob" +edit +EOF + +test_expect_success 'empty notes are displayed by git log' ' + test_commit 17th && + git log -1 >expect && + cat >>expect <<-EOF && + + Notes: + EOF + git notes add -C "$empty_blob" --allow-empty && + git log -1 >actual && + test_cmp expect actual +' + test_done diff --git a/t/t3302-notes-index-expensive.sh b/t/t3302-notes-index-expensive.sh index e35d7811ac..7217c5e222 100755 --- a/t/t3302-notes-index-expensive.sh +++ b/t/t3302-notes-index-expensive.sh @@ -7,53 +7,49 @@ test_description='Test commit notes index (expensive!)' . ./test-lib.sh -test_set_prereq NOT_EXPENSIVE -test -n "$GIT_NOTES_TIMING_TESTS" && test_set_prereq EXPENSIVE -test -x /usr/bin/time && test_set_prereq USR_BIN_TIME - create_repo () { number_of_commits=$1 nr=0 test -d .git || { git init && ( - while [ $nr -lt $number_of_commits ]; do + while test $nr -lt $number_of_commits + do nr=$(($nr+1)) mark=$(($nr+$nr)) notemark=$(($mark+1)) test_tick && - cat <<INPUT_END && -commit refs/heads/master -mark :$mark -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -commit #$nr -COMMIT - -M 644 inline file -data <<EOF -file in commit #$nr -EOF - -blob -mark :$notemark -data <<EOF -note for commit #$nr -EOF - -INPUT_END - - echo "N :$notemark :$mark" >> note_commit + cat <<-INPUT_END && + commit refs/heads/master + mark :$mark + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + commit #$nr + COMMIT + + M 644 inline file + data <<EOF + file in commit #$nr + EOF + + blob + mark :$notemark + data <<EOF + note for commit #$nr + EOF + + INPUT_END + echo "N :$notemark :$mark" >>note_commit done && test_tick && - cat <<INPUT_END && -commit refs/notes/commits -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -notes -COMMIT + cat <<-INPUT_END && + commit refs/notes/commits + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + notes + COMMIT -INPUT_END + INPUT_END cat note_commit ) | @@ -65,62 +61,74 @@ INPUT_END test_notes () { count=$1 && git config core.notesRef refs/notes/commits && - git log | grep "^ " > output && + git log | grep "^ " >output && i=$count && - while [ $i -gt 0 ]; do + while test $i -gt 0 + do echo " commit #$i" && echo " note for commit #$i" && - i=$(($i-1)); - done > expect && + i=$(($i-1)) + done >expect && test_cmp expect output } -cat > time_notes << \EOF +write_script time_notes <<\EOF mode=$1 i=1 - while [ $i -lt $2 ]; do + while test $i -lt $2 + do case $1 in no-notes) - GIT_NOTES_REF=non-existing; export GIT_NOTES_REF - ;; + GIT_NOTES_REF=non-existing + export GIT_NOTES_REF + ;; notes) unset GIT_NOTES_REF - ;; + ;; esac - git log >/dev/null + git log i=$(($i+1)) - done + done >/dev/null EOF time_notes () { for mode in no-notes notes do echo $mode - /usr/bin/time "$SHELL_PATH" ../time_notes $mode $1 + /usr/bin/time ../time_notes $mode $1 done } do_tests () { - pr=$1 - count=$2 - - test_expect_success $pr 'setup / mkdir' ' - mkdir $count && - cd $count + count=$1 pr=${2-} + + test_expect_success $pr "setup $count" ' + mkdir "$count" && + ( + cd "$count" && + create_repo "$count" + ) ' - test_expect_success $pr "setup $count" "create_repo $count" - - test_expect_success $pr 'notes work' "test_notes $count" - - test_expect_success USR_BIN_TIME,$pr 'notes timing with /usr/bin/time' "time_notes 100" + test_expect_success $pr 'notes work' ' + ( + cd "$count" && + test_notes "$count" + ) + ' - test_expect_success $pr 'teardown / cd ..' 'cd ..' + test_expect_success "USR_BIN_TIME${pr:+,$pr}" 'notes timing with /usr/bin/time' ' + ( + cd "$count" && + time_notes 100 + ) + ' } -do_tests NOT_EXPENSIVE 10 -for count in 100 1000 10000; do - do_tests EXPENSIVE $count +do_tests 10 +for count in 100 1000 10000 +do + do_tests "$count" EXPENSIVE done test_done diff --git a/t/t3305-notes-fanout.sh b/t/t3305-notes-fanout.sh index b1ea64b213..54460beec4 100755 --- a/t/t3305-notes-fanout.sh +++ b/t/t3305-notes-fanout.sh @@ -51,15 +51,12 @@ test_expect_success 'deleting most notes with git-notes' ' num_notes=250 && i=0 && git rev-list HEAD | - while read sha1 + while test $i -lt $num_notes && read sha1 do i=$(($i + 1)) && - if test $i -gt $num_notes - then - break - fi && test_tick && - git notes remove "$sha1" + git notes remove "$sha1" || + exit 1 done ' diff --git a/t/t3309-notes-merge-auto-resolve.sh b/t/t3309-notes-merge-auto-resolve.sh index 461fd84755..14c2adf970 100755 --- a/t/t3309-notes-merge-auto-resolve.sh +++ b/t/t3309-notes-merge-auto-resolve.sh @@ -298,6 +298,13 @@ test_expect_success 'merge z into y with invalid strategy => Fail/No changes' ' verify_notes y y ' +test_expect_success 'merge z into y with invalid configuration option => Fail/No changes' ' + git config core.notesRef refs/notes/y && + test_must_fail git -c notes.mergeStrategy="foo" notes merge z && + # Verify no changes (y) + verify_notes y y +' + cat <<EOF | sort >expect_notes_ours 68b8630d25516028bed862719855b3d6768d7833 $commit_sha15 5de7ea7ad4f47e7ff91989fb82234634730f75df $commit_sha14 @@ -365,6 +372,28 @@ test_expect_success 'reset to pre-merge state (y)' ' verify_notes y y ' +test_expect_success 'merge z into y with "ours" configuration option => Non-conflicting 3-way merge' ' + git -c notes.mergeStrategy="ours" notes merge z && + verify_notes y ours +' + +test_expect_success 'reset to pre-merge state (y)' ' + git update-ref refs/notes/y refs/notes/y^1 && + # Verify pre-merge state + verify_notes y y +' + +test_expect_success 'merge z into y with "ours" per-ref configuration option => Non-conflicting 3-way merge' ' + git -c notes.y.mergeStrategy="ours" notes merge z && + verify_notes y ours +' + +test_expect_success 'reset to pre-merge state (y)' ' + git update-ref refs/notes/y refs/notes/y^1 && + # Verify pre-merge state + verify_notes y y +' + cat <<EOF | sort >expect_notes_theirs 9b4b2c61f0615412da3c10f98ff85b57c04ec765 $commit_sha15 5de7ea7ad4f47e7ff91989fb82234634730f75df $commit_sha14 @@ -432,6 +461,17 @@ test_expect_success 'reset to pre-merge state (y)' ' verify_notes y y ' +test_expect_success 'merge z into y with "theirs" strategy overriding configuration option "ours" => Non-conflicting 3-way merge' ' + git -c notes.mergeStrategy="ours" notes merge --strategy=theirs z && + verify_notes y theirs +' + +test_expect_success 'reset to pre-merge state (y)' ' + git update-ref refs/notes/y refs/notes/y^1 && + # Verify pre-merge state + verify_notes y y +' + cat <<EOF | sort >expect_notes_union 7c4e546efd0fe939f876beb262ece02797880b54 $commit_sha15 5de7ea7ad4f47e7ff91989fb82234634730f75df $commit_sha14 @@ -505,6 +545,34 @@ test_expect_success 'reset to pre-merge state (y)' ' verify_notes y y ' +test_expect_success 'merge z into y with "union" strategy overriding per-ref configuration => Non-conflicting 3-way merge' ' + git -c notes.y.mergeStrategy="theirs" notes merge --strategy=union z && + verify_notes y union +' + +test_expect_success 'reset to pre-merge state (y)' ' + git update-ref refs/notes/y refs/notes/y^1 && + # Verify pre-merge state + verify_notes y y +' + +test_expect_success 'merge z into y with "union" per-ref overriding general configuration => Non-conflicting 3-way merge' ' + git -c notes.y.mergeStrategy="union" -c notes.mergeStrategy="theirs" notes merge z && + verify_notes y union +' + +test_expect_success 'reset to pre-merge state (y)' ' + git update-ref refs/notes/y refs/notes/y^1 && + # Verify pre-merge state + verify_notes y y +' + +test_expect_success 'merge z into y with "manual" per-ref only checks specific ref configuration => Conflicting 3-way merge' ' + test_must_fail git -c notes.z.mergeStrategy="union" notes merge z && + git notes merge --abort && + verify_notes y y +' + cat <<EOF | sort >expect_notes_union2 d682107b8bf7a7aea1e537a8d5cb6a12b60135f1 $commit_sha15 5de7ea7ad4f47e7ff91989fb82234634730f75df $commit_sha14 @@ -644,4 +712,15 @@ test_expect_success 'merge y into z with "cat_sort_uniq" strategy => Non-conflic verify_notes z cat_sort_uniq ' +test_expect_success 'reset to pre-merge state (z)' ' + git update-ref refs/notes/z refs/notes/z^1 && + # Verify pre-merge state + verify_notes z z +' + +test_expect_success 'merge y into z with "cat_sort_uniq" strategy configuration option => Non-conflicting 3-way merge' ' + git -c notes.mergeStrategy="cat_sort_uniq" notes merge y && + verify_notes z cat_sort_uniq +' + test_done diff --git a/t/t3310-notes-merge-manual-resolve.sh b/t/t3310-notes-merge-manual-resolve.sh index 195bb97f85..d5572121da 100755 --- a/t/t3310-notes-merge-manual-resolve.sh +++ b/t/t3310-notes-merge-manual-resolve.sh @@ -314,6 +314,18 @@ y and z notes on 1st commit EOF +test_expect_success 'do not allow mixing --commit and --abort' ' + test_must_fail git notes merge --commit --abort +' + +test_expect_success 'do not allow mixing --commit and --strategy' ' + test_must_fail git notes merge --commit --strategy theirs +' + +test_expect_success 'do not allow mixing --abort and --strategy' ' + test_must_fail git notes merge --abort --strategy theirs +' + test_expect_success 'finalize conflicting merge (z => m)' ' # Resolve conflicts and finalize merge cat >.git/NOTES_MERGE_WORKTREE/$commit_sha1 <<EOF && diff --git a/t/t3320-notes-merge-worktrees.sh b/t/t3320-notes-merge-worktrees.sh new file mode 100755 index 0000000000..1f71d589f5 --- /dev/null +++ b/t/t3320-notes-merge-worktrees.sh @@ -0,0 +1,72 @@ +#!/bin/sh +# +# Copyright (c) 2015 Twitter, Inc +# + +test_description='Test merging of notes trees in multiple worktrees' + +. ./test-lib.sh + +test_expect_success 'setup commit' ' + test_commit tantrum +' + +commit_tantrum=$(git rev-parse tantrum^{commit}) + +test_expect_success 'setup notes ref (x)' ' + git config core.notesRef refs/notes/x && + git notes add -m "x notes on tantrum" tantrum +' + +test_expect_success 'setup local branch (y)' ' + git update-ref refs/notes/y refs/notes/x && + git config core.notesRef refs/notes/y && + git notes remove tantrum +' + +test_expect_success 'setup remote branch (z)' ' + git update-ref refs/notes/z refs/notes/x && + git config core.notesRef refs/notes/z && + git notes add -f -m "conflicting notes on tantrum" tantrum +' + +test_expect_success 'modify notes ref ourselves (x)' ' + git config core.notesRef refs/notes/x && + git notes add -f -m "more conflicting notes on tantrum" tantrum +' + +test_expect_success 'create some new worktrees' ' + git worktree add -b newbranch worktree master && + git worktree add -b newbranch2 worktree2 master +' + +test_expect_success 'merge z into y fails and sets NOTES_MERGE_REF' ' + git config core.notesRef refs/notes/y && + test_must_fail git notes merge z && + echo "ref: refs/notes/y" >expect && + test_cmp .git/NOTES_MERGE_REF expect +' + +test_expect_success 'merge z into y while mid-merge in another workdir fails' ' + ( + cd worktree && + git config core.notesRef refs/notes/y && + test_must_fail git notes merge z 2>err && + grep "A notes merge into refs/notes/y is already in-progress at" err + ) && + test_path_is_missing .git/worktrees/worktree/NOTES_MERGE_REF +' + +test_expect_success 'merge z into x while mid-merge on y succeeds' ' + ( + cd worktree2 && + git config core.notesRef refs/notes/x && + test_must_fail git notes merge z 2>&1 >out && + grep "Automatic notes merge failed" out && + grep -v "A notes merge into refs/notes/x is already in-progress in" out + ) && + echo "ref: refs/notes/x" >expect && + test_cmp .git/worktrees/worktree2/NOTES_MERGE_REF expect +' + +test_done diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh index 80e0a951ea..47b5682662 100755 --- a/t/t3400-rebase.sh +++ b/t/t3400-rebase.sh @@ -169,6 +169,29 @@ test_expect_success 'default to common base in @{upstream}s reflog if no upstrea test_cmp expect actual ' +test_expect_success 'cherry-picked commits and fork-point work together' ' + git checkout default-base && + echo Amended >A && + git commit -a --no-edit --amend && + test_commit B B && + test_commit new_B B "New B" && + test_commit C C && + git checkout default && + git reset --hard default-base@{4} && + test_commit D D && + git cherry-pick -2 default-base^ && + test_commit final_B B "Final B" && + git rebase && + echo Amended >expect && + test_cmp A expect && + echo "Final B" >expect && + test_cmp B expect && + echo C >expect && + test_cmp C expect && + echo D >expect && + test_cmp D expect +' + test_expect_success 'rebase -q is quiet' ' git checkout -b quiet topic && git rebase -q master >output.out 2>&1 && diff --git a/t/t3402-rebase-merge.sh b/t/t3402-rebase-merge.sh index 5a27ec9b5e..8f64505e4f 100755 --- a/t/t3402-rebase-merge.sh +++ b/t/t3402-rebase-merge.sh @@ -47,7 +47,7 @@ test_expect_success setup ' ' test_expect_success 'reference merge' ' - git merge -s recursive "reference merge" HEAD master + git merge -s recursive -m "reference merge" master ' PRE_REBASE=$(git rev-parse test-rebase) diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index c0023a5b4f..544f9ad508 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -67,6 +67,14 @@ test_expect_success 'setup' ' SHELL= export SHELL +test_expect_success 'rebase --keep-empty' ' + git checkout -b emptybranch master && + git commit --allow-empty -m "empty" && + git rebase --keep-empty -i HEAD~2 && + git log --oneline >actual && + test_line_count = 6 actual +' + test_expect_success 'rebase -i with the exec command' ' git checkout master && ( @@ -942,7 +950,7 @@ test_expect_success 'rebase --edit-todo can be used to modify todo' ' set_fake_editor && FAKE_LINES="edit 1 2 3" git rebase -i HEAD~3 && FAKE_LINES="2 1" git rebase --edit-todo && - git rebase --continue + git rebase --continue && test M = $(git cat-file commit HEAD^ | sed -ne \$p) && test L = $(git cat-file commit HEAD | sed -ne \$p) ' @@ -953,13 +961,13 @@ test_expect_success 'rebase -i produces readable reflog' ' set_fake_editor && git rebase -i --onto I F branch-reflog-test && cat >expect <<-\EOF && - rebase -i (start): checkout I - rebase -i (pick): G - rebase -i (pick): H rebase -i (finish): returning to refs/heads/branch-reflog-test + rebase -i (pick): H + rebase -i (pick): G + rebase -i (start): checkout I EOF - tail -n 4 .git/logs/HEAD | - sed -e "s/.* //" >actual && + git reflog -n4 HEAD | + sed "s/[^:]*: //" >actual && test_cmp expect actual ' @@ -998,8 +1006,24 @@ test_expect_success 'rebase -i with --strategy and -X' ' test $(cat file1) = Z ' +test_expect_success 'interrupted rebase -i with --strategy and -X' ' + git checkout -b conflict-merge-use-theirs-interrupted conflict-branch && + git reset --hard HEAD^ && + >breakpoint && + git add breakpoint && + git commit -m "breakpoint for interactive mode" && + echo five >conflict && + echo Z >file1 && + git commit -a -m "one file conflict" && + set_fake_editor && + FAKE_LINES="edit 1 2" git rebase -i --strategy=recursive -Xours conflict-branch && + git rebase --continue && + test $(git show conflict-branch:conflict) = $(cat conflict) && + test $(cat file1) = Z +' + test_expect_success 'rebase -i error on commits with \ in message' ' - current_head=$(git rev-parse HEAD) + current_head=$(git rev-parse HEAD) && test_when_finished "git rebase --abort; git reset --hard $current_head; rm -f error" && test_commit TO-REMOVE will-conflict old-content && test_commit "\temp" will-conflict new-content dummy && @@ -1031,4 +1055,238 @@ test_expect_success 'short SHA-1 collide' ' ) ' +test_expect_success 'respect core.abbrev' ' + git config core.abbrev 12 && + set_cat_todo_editor && + test_must_fail git rebase -i HEAD~4 >todo-list && + test 4 = $(grep -c "pick [0-9a-f]\{12,\}" todo-list) +' + +test_expect_success 'todo count' ' + write_script dump-raw.sh <<-\EOF && + cat "$1" + EOF + test_set_editor "$(pwd)/dump-raw.sh" && + git rebase -i HEAD~4 >actual && + grep "^# Rebase ..* onto ..* ([0-9]" actual +' + +test_expect_success 'rebase -i commits that overwrite untracked files (pick)' ' + git checkout --force branch2 && + git clean -f && + set_fake_editor && + FAKE_LINES="edit 1 2" git rebase -i A && + test_cmp_rev HEAD F && + test_path_is_missing file6 && + >file6 && + test_must_fail git rebase --continue && + test_cmp_rev HEAD F && + rm file6 && + git rebase --continue && + test_cmp_rev HEAD I +' + +test_expect_success 'rebase -i commits that overwrite untracked files (squash)' ' + git checkout --force branch2 && + git clean -f && + git tag original-branch2 && + set_fake_editor && + FAKE_LINES="edit 1 squash 2" git rebase -i A && + test_cmp_rev HEAD F && + test_path_is_missing file6 && + >file6 && + test_must_fail git rebase --continue && + test_cmp_rev HEAD F && + rm file6 && + git rebase --continue && + test $(git cat-file commit HEAD | sed -ne \$p) = I && + git reset --hard original-branch2 +' + +test_expect_success 'rebase -i commits that overwrite untracked files (no ff)' ' + git checkout --force branch2 && + git clean -f && + set_fake_editor && + FAKE_LINES="edit 1 2" git rebase -i --no-ff A && + test $(git cat-file commit HEAD | sed -ne \$p) = F && + test_path_is_missing file6 && + >file6 && + test_must_fail git rebase --continue && + test $(git cat-file commit HEAD | sed -ne \$p) = F && + rm file6 && + git rebase --continue && + test $(git cat-file commit HEAD | sed -ne \$p) = I +' + +test_expect_success 'rebase --continue removes CHERRY_PICK_HEAD' ' + git checkout -b commit-to-skip && + for double in X 3 1 + do + test_seq 5 | sed "s/$double/&&/" >seq && + git add seq && + test_tick && + git commit -m seq-$double + done && + git tag seq-onto && + git reset --hard HEAD~2 && + git cherry-pick seq-onto && + set_fake_editor && + test_must_fail env FAKE_LINES= git rebase -i seq-onto && + test -d .git/rebase-merge && + git rebase --continue && + git diff --exit-code seq-onto && + test ! -d .git/rebase-merge && + test ! -f .git/CHERRY_PICK_HEAD +' + +rebase_setup_and_clean () { + test_when_finished " + git checkout master && + test_might_fail git branch -D $1 && + test_might_fail git rebase --abort + " && + git checkout -b $1 master +} + +test_expect_success 'drop' ' + rebase_setup_and_clean drop-test && + set_fake_editor && + FAKE_LINES="1 drop 2 3 drop 4 5" git rebase -i --root && + test E = $(git cat-file commit HEAD | sed -ne \$p) && + test C = $(git cat-file commit HEAD^ | sed -ne \$p) && + test A = $(git cat-file commit HEAD^^ | sed -ne \$p) +' + +cat >expect <<EOF +Successfully rebased and updated refs/heads/missing-commit. +EOF + +test_expect_success 'rebase -i respects rebase.missingCommitsCheck = ignore' ' + test_config rebase.missingCommitsCheck ignore && + rebase_setup_and_clean missing-commit && + set_fake_editor && + FAKE_LINES="1 2 3 4" \ + git rebase -i --root 2>actual && + test D = $(git cat-file commit HEAD | sed -ne \$p) && + test_cmp expect actual +' + +cat >expect <<EOF +Warning: some commits may have been dropped accidentally. +Dropped commits (newer to older): + - $(git rev-list --pretty=oneline --abbrev-commit -1 master) +To avoid this message, use "drop" to explicitly remove a commit. + +Use 'git config rebase.missingCommitsCheck' to change the level of warnings. +The possible behaviours are: ignore, warn, error. + +Successfully rebased and updated refs/heads/missing-commit. +EOF + +test_expect_success 'rebase -i respects rebase.missingCommitsCheck = warn' ' + test_config rebase.missingCommitsCheck warn && + rebase_setup_and_clean missing-commit && + set_fake_editor && + FAKE_LINES="1 2 3 4" \ + git rebase -i --root 2>actual && + test_cmp expect actual && + test D = $(git cat-file commit HEAD | sed -ne \$p) +' + +cat >expect <<EOF +Warning: some commits may have been dropped accidentally. +Dropped commits (newer to older): + - $(git rev-list --pretty=oneline --abbrev-commit -1 master) + - $(git rev-list --pretty=oneline --abbrev-commit -1 master~2) +To avoid this message, use "drop" to explicitly remove a commit. + +Use 'git config rebase.missingCommitsCheck' to change the level of warnings. +The possible behaviours are: ignore, warn, error. + +You can fix this with 'git rebase --edit-todo'. +Or you can abort the rebase with 'git rebase --abort'. +EOF + +test_expect_success 'rebase -i respects rebase.missingCommitsCheck = error' ' + test_config rebase.missingCommitsCheck error && + rebase_setup_and_clean missing-commit && + set_fake_editor && + test_must_fail env FAKE_LINES="1 2 4" \ + git rebase -i --root 2>actual && + test_cmp expect actual && + cp .git/rebase-merge/git-rebase-todo.backup \ + .git/rebase-merge/git-rebase-todo && + FAKE_LINES="1 2 drop 3 4 drop 5" \ + git rebase --edit-todo && + git rebase --continue && + test D = $(git cat-file commit HEAD | sed -ne \$p) && + test B = $(git cat-file commit HEAD^ | sed -ne \$p) +' + +cat >expect <<EOF +Warning: the command isn't recognized in the following line: + - badcmd $(git rev-list --oneline -1 master~1) + +You can fix this with 'git rebase --edit-todo'. +Or you can abort the rebase with 'git rebase --abort'. +EOF + +test_expect_success 'static check of bad command' ' + rebase_setup_and_clean bad-cmd && + set_fake_editor && + test_must_fail env FAKE_LINES="1 2 3 bad 4 5" \ + git rebase -i --root 2>actual && + test_cmp expect actual && + FAKE_LINES="1 2 3 drop 4 5" git rebase --edit-todo && + git rebase --continue && + test E = $(git cat-file commit HEAD | sed -ne \$p) && + test C = $(git cat-file commit HEAD^ | sed -ne \$p) +' + +test_expect_success 'tabs and spaces are accepted in the todolist' ' + rebase_setup_and_clean indented-comment && + write_script add-indent.sh <<-\EOF && + ( + # Turn single spaces into space/tab mix + sed "1s/ / /g; 2s/ / /g; 3s/ / /g" "$1" + printf "\n\t# comment\n #more\n\t # comment\n" + ) >"$1.new" + mv "$1.new" "$1" + EOF + test_set_editor "$(pwd)/add-indent.sh" && + git rebase -i HEAD^^^ && + test E = $(git cat-file commit HEAD | sed -ne \$p) +' + +cat >expect <<EOF +Warning: the SHA-1 is missing or isn't a commit in the following line: + - edit XXXXXXX False commit + +You can fix this with 'git rebase --edit-todo'. +Or you can abort the rebase with 'git rebase --abort'. +EOF + +test_expect_success 'static check of bad SHA-1' ' + rebase_setup_and_clean bad-sha && + set_fake_editor && + test_must_fail env FAKE_LINES="1 2 edit fakesha 3 4 5 #" \ + git rebase -i --root 2>actual && + test_cmp expect actual && + FAKE_LINES="1 2 4 5 6" git rebase --edit-todo && + git rebase --continue && + test E = $(git cat-file commit HEAD | sed -ne \$p) +' + +test_expect_success 'editor saves as CR/LF' ' + git checkout -b with-crlf && + write_script add-crs.sh <<-\EOF && + sed -e "s/\$/Q/" <"$1" | tr Q "\\015" >"$1".new && + mv -f "$1".new "$1" + EOF + ( + test_set_editor "$(pwd)/add-crs.sh" && + git rebase -i HEAD^ + ) +' + test_done diff --git a/t/t3405-rebase-malformed.sh b/t/t3405-rebase-malformed.sh index 19eddadcf7..ff8c360cd5 100755 --- a/t/t3405-rebase-malformed.sh +++ b/t/t3405-rebase-malformed.sh @@ -24,7 +24,7 @@ test_expect_success setup ' git add file1 file2 && test_tick && git commit -m "Initial commit" && - git branch diff-in-message + git branch diff-in-message && git checkout -b multi-line-subject && cat F >file2 && @@ -36,7 +36,7 @@ test_expect_success setup ' git checkout diff-in-message && echo "commit log message containing a diff" >G && - echo "" >>G + echo "" >>G && cat G >file2 && git add file2 && git diff --cached >>G && diff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh index 41370ab998..8f53e54ce4 100755 --- a/t/t3415-rebase-autosquash.sh +++ b/t/t3415-rebase-autosquash.sh @@ -250,4 +250,25 @@ test_expect_success 'squash! fixup!' ' test_auto_fixup_fixup squash fixup ' +test_expect_success 'autosquash with custom inst format' ' + git reset --hard base && + git config --add rebase.instructionFormat "[%an @ %ar] %s" && + echo 2 >file1 && + git add -u && + test_tick && + git commit -m "squash! $(git rev-parse --short HEAD^)" && + echo 1 >file1 && + git add -u && + test_tick && + git commit -m "squash! $(git log -n 1 --format=%s HEAD~2)" && + git tag final-squash-instFmt && + test_tick && + git rebase --autosquash -i HEAD~4 && + git log --oneline >actual && + test_line_count = 3 actual && + git diff --exit-code final-squash-instFmt && + test 1 = "$(git cat-file blob HEAD^:file1)" && + test 2 = $(git cat-file commit HEAD^ | grep squash | wc -l) +' + test_done diff --git a/t/t3418-rebase-continue.sh b/t/t3418-rebase-continue.sh index 2680375628..4428b9086e 100755 --- a/t/t3418-rebase-continue.sh +++ b/t/t3418-rebase-continue.sh @@ -40,6 +40,25 @@ test_expect_success 'non-interactive rebase --continue works with touched file' git rebase --continue ' +test_expect_success 'non-interactive rebase --continue with rerere enabled' ' + test_config rerere.enabled true && + test_when_finished "test_might_fail git rebase --abort" && + git reset --hard commit-new-file-F2-on-topic-branch && + git checkout master && + rm -fr .git/rebase-* && + + test_must_fail git rebase --onto master master topic && + echo "Resolved" >F2 && + git add F2 && + cp F2 F2.expected && + git rebase --continue && + + git reset --hard commit-new-file-F2-on-topic-branch && + git checkout master && + test_must_fail git rebase --onto master master topic && + test_cmp F2.expected F2 +' + test_expect_success 'rebase --continue can not be used with other options' ' test_must_fail git rebase -v --continue && test_must_fail git rebase --continue -v diff --git a/t/t3419-rebase-patch-id.sh b/t/t3419-rebase-patch-id.sh index e70ac10a0c..217dd79b2e 100755 --- a/t/t3419-rebase-patch-id.sh +++ b/t/t3419-rebase-patch-id.sh @@ -4,12 +4,7 @@ test_description='git rebase - test patch id computation' . ./test-lib.sh -test_set_prereq NOT_EXPENSIVE -test -n "$GIT_PATCHID_TIMING_TESTS" && test_set_prereq EXPENSIVE -test -x /usr/bin/time && test_set_prereq USR_BIN_TIME - -count() -{ +count () { i=0 while test $i -lt $1 do @@ -18,8 +13,7 @@ count() done } -scramble() -{ +scramble () { i=0 while read x do @@ -28,12 +22,11 @@ scramble() echo "$x" fi i=$((($i+1) % 10)) - done < "$1" > "$1.new" + done <"$1" >"$1.new" mv -f "$1.new" "$1" } -run() -{ +run () { echo \$ "$@" /usr/bin/time "$@" >/dev/null } @@ -43,10 +36,8 @@ test_expect_success 'setup' ' git tag root ' -do_tests() -{ - pr=$1 - nlines=$2 +do_tests () { + nlines=$1 pr=${2-} test_expect_success $pr "setup: $nlines lines" " rm -f .gitattributes && @@ -103,7 +94,7 @@ do_tests() " } -do_tests NOT_EXPENSIVE 500 -do_tests EXPENSIVE 50000 +do_tests 500 +do_tests 50000 EXPENSIVE test_done diff --git a/t/t3420-rebase-autostash.sh b/t/t3420-rebase-autostash.sh index d783f03d3f..944154b2e0 100755 --- a/t/t3420-rebase-autostash.sh +++ b/t/t3420-rebase-autostash.sh @@ -37,6 +37,16 @@ testrebase() { type=$1 dotest=$2 + test_expect_success "rebase$type: dirty worktree, --no-autostash" ' + test_config rebase.autostash true && + git reset --hard && + git checkout -b rebased-feature-branch feature-branch && + test_when_finished git branch -D rebased-feature-branch && + test_when_finished git checkout feature-branch && + echo dirty >>file3 && + test_must_fail git rebase$type --no-autostash unrelated-onto-branch + ' + test_expect_success "rebase$type: dirty worktree, non-conflicting rebase" ' test_config rebase.autostash true && git reset --hard && diff --git a/t/t3425-rebase-topology-merges.sh b/t/t3425-rebase-topology-merges.sh index 1d195fbd64..846f85c27e 100755 --- a/t/t3425-rebase-topology-merges.sh +++ b/t/t3425-rebase-topology-merges.sh @@ -24,7 +24,7 @@ test_expect_success 'setup of non-linear-history' ' test_commit c && git checkout b && test_commit d && - test_commit e + test_commit e && git checkout c && test_commit g && @@ -33,7 +33,7 @@ test_expect_success 'setup of non-linear-history' ' cherry_pick gp g && test_commit i && git checkout b && - test_commit f + test_commit f && git checkout d && test_commit n && diff --git a/t/t3426-rebase-submodule.sh b/t/t3426-rebase-submodule.sh new file mode 100755 index 0000000000..d5b896d445 --- /dev/null +++ b/t/t3426-rebase-submodule.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +test_description='rebase can handle submodules' + +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-submodule-update.sh +. "$TEST_DIRECTORY"/lib-rebase.sh + +git_rebase () { + git status -su >expect && + ls -1pR * >>expect && + git checkout -b ours HEAD && + echo x >>file1 && + git add file1 && + git commit -m add_x && + git revert HEAD && + git status -su >actual && + ls -1pR * >>actual && + test_cmp expect actual && + git rebase "$1" +} + +test_submodule_switch "git_rebase" + +git_rebase_interactive () { + git status -su >expect && + ls -1pR * >>expect && + git checkout -b ours HEAD && + echo x >>file1 && + git add file1 && + git commit -m add_x && + git revert HEAD && + git status -su >actual && + ls -1pR * >>actual && + test_cmp expect actual && + set_fake_editor && + echo "fake-editor.sh" >.git/info/exclude && + git rebase -i "$1" +} + +KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1 +# The real reason "replace directory with submodule" fails is because a +# directory "sub1" exists, but we reuse the suppression added for merge here +test_submodule_switch "git_rebase_interactive" + +test_done diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh index 223b98433c..7c5ad08626 100755 --- a/t/t3507-cherry-pick-conflict.sh +++ b/t/t3507-cherry-pick-conflict.sh @@ -351,19 +351,45 @@ test_expect_success 'commit after failed cherry-pick does not add duplicated -s' test_expect_success 'commit after failed cherry-pick adds -s at the right place' ' pristine_detach initial && test_must_fail git cherry-pick picked && + git commit -a -s && - pwd && - cat <<EOF > expected && -picked -Signed-off-by: C O Mitter <committer@example.com> + # Do S-o-b and Conflicts appear in the right order? + cat <<-\EOF >expect && + Signed-off-by: C O Mitter <committer@example.com> + # Conflicts: + EOF + grep -e "^# Conflicts:" -e '^Signed-off-by' <.git/COMMIT_EDITMSG >actual && + test_cmp expect actual && + + cat <<-\EOF >expected && + picked -Conflicts: - foo -EOF + Signed-off-by: C O Mitter <committer@example.com> + EOF - git show -s --pretty=format:%B > actual && + git show -s --pretty=format:%B >actual && test_cmp expected actual ' +test_expect_success 'commit --amend -s places the sign-off at the right place' ' + pristine_detach initial && + test_must_fail git cherry-pick picked && + + # emulate old-style conflicts block + mv .git/MERGE_MSG .git/MERGE_MSG+ && + sed -e "/^# Conflicts:/,\$s/^# *//" <.git/MERGE_MSG+ >.git/MERGE_MSG && + + git commit -a && + git commit --amend -s && + + # Do S-o-b and Conflicts appear in the right order? + cat <<-\EOF >expect && + Signed-off-by: C O Mitter <committer@example.com> + Conflicts: + EOF + grep -e "^Conflicts:" -e '^Signed-off-by' <.git/COMMIT_EDITMSG >actual && + test_cmp expect actual +' + test_done diff --git a/t/t3508-cherry-pick-many-commits.sh b/t/t3508-cherry-pick-many-commits.sh index 19c99d7ef1..b457333e18 100755 --- a/t/t3508-cherry-pick-many-commits.sh +++ b/t/t3508-cherry-pick-many-commits.sh @@ -65,12 +65,15 @@ test_expect_success 'output to keep user entertained during multi-pick' ' cat <<-\EOF >expected && [master OBJID] second Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:14:13 2005 -0700 1 file changed, 1 insertion(+) [master OBJID] third Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:15:13 2005 -0700 1 file changed, 1 insertion(+) [master OBJID] fourth Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:16:13 2005 -0700 1 file changed, 1 insertion(+) EOF @@ -98,14 +101,17 @@ test_expect_success 'output during multi-pick indicates merge strategy' ' Trying simple merge. [master OBJID] second Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:14:13 2005 -0700 1 file changed, 1 insertion(+) Trying simple merge. [master OBJID] third Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:15:13 2005 -0700 1 file changed, 1 insertion(+) Trying simple merge. [master OBJID] fourth Author: A U Thor <author@example.com> + Date: Thu Apr 7 15:16:13 2005 -0700 1 file changed, 1 insertion(+) EOF diff --git a/t/t3511-cherry-pick-x.sh b/t/t3511-cherry-pick-x.sh index f97727975b..b7dff09d06 100755 --- a/t/t3511-cherry-pick-x.sh +++ b/t/t3511-cherry-pick-x.sh @@ -36,6 +36,20 @@ mesg_with_cherry_footer="$mesg_with_footer_sob (cherry picked from commit da39a3ee5e6b4b0d3255bfef95601890afd80709) Tested-by: C.U. Thor <cuthor@example.com>" +mesg_unclean="$mesg_one_line + + +leading empty lines + + +consecutive empty lines + +# hash tag comment + +trailing empty lines + + +" test_expect_success setup ' git config advice.detachedhead false && @@ -53,6 +67,10 @@ test_expect_success setup ' test_commit "$mesg_with_footer_sob" foo b mesg-with-footer-sob && git reset --hard initial && test_commit "$mesg_with_cherry_footer" foo b mesg-with-cherry-footer && + git reset --hard initial && + test_config commit.cleanup verbatim && + test_commit "$mesg_unclean" foo b mesg-unclean && + test_unconfig commit.cleanup && pristine_detach initial && test_commit conflicting unrelated ' @@ -216,4 +234,14 @@ test_expect_success 'cherry-pick -x -s treats "(cherry picked from..." line as p test_cmp expect actual ' +test_expect_success 'cherry-pick preserves commit message' ' + pristine_detach initial && + printf "$mesg_unclean" >expect && + git log -1 --pretty=format:%B mesg-unclean >actual && + test_cmp expect actual && + git cherry-pick mesg-unclean && + git log -1 --pretty=format:%B >actual && + test_cmp expect actual +' + test_done diff --git a/t/t3512-cherry-pick-submodule.sh b/t/t3512-cherry-pick-submodule.sh new file mode 100755 index 0000000000..6863b7bb6f --- /dev/null +++ b/t/t3512-cherry-pick-submodule.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +test_description='cherry-pick can handle submodules' + +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-submodule-update.sh + +KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT=1 +KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1 +KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1 +test_submodule_switch "git cherry-pick" + +test_done diff --git a/t/t3513-revert-submodule.sh b/t/t3513-revert-submodule.sh new file mode 100755 index 0000000000..a1c4e0216f --- /dev/null +++ b/t/t3513-revert-submodule.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +test_description='revert can handle submodules' + +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-submodule-update.sh + +# Create a revert that moves from HEAD (including any test modifications to +# the work tree) to $1 by first checking out $1 and reverting it. Reverting +# the revert is the transition we test for. We tar the current work tree +# first so we can restore the work tree test setup after doing the checkout +# and revert. We test here that the restored work tree content is identical +# to that at the beginning. The last revert is then tested by the framework. +git_revert () { + git status -su >expect && + ls -1pR * >>expect && + tar czf "$TRASH_DIRECTORY/tmp.tgz" * && + git checkout "$1" && + git revert HEAD && + rm -rf * && + tar xzf "$TRASH_DIRECTORY/tmp.tgz" && + git status -su >actual && + ls -1pR * >>actual && + test_cmp expect actual && + git revert HEAD +} + +KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT=1 +KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1 +test_submodule_switch "git_revert" + +test_done diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh index e00d7d2b61..9d90d2c935 100755 --- a/t/t3600-rm.sh +++ b/t/t3600-rm.sh @@ -38,37 +38,37 @@ test_expect_success \ test_expect_success \ 'Test that git rm --cached foo succeeds if the index matches the file' \ - 'echo content > foo - git add foo + 'echo content >foo && + git add foo && git rm --cached foo' test_expect_success \ 'Test that git rm --cached foo succeeds if the index matches the file' \ - 'echo content > foo - git add foo - git commit -m foo - echo "other content" > foo + 'echo content >foo && + git add foo && + git commit -m foo && + echo "other content" >foo && git rm --cached foo' test_expect_success \ 'Test that git rm --cached foo fails if the index matches neither the file nor HEAD' ' - echo content > foo - git add foo - git commit -m foo - echo "other content" > foo - git add foo - echo "yet another content" > foo + echo content >foo && + git add foo && + git commit -m foo --allow-empty && + echo "other content" >foo && + git add foo && + echo "yet another content" >foo && test_must_fail git rm --cached foo ' test_expect_success \ 'Test that git rm --cached -f foo works in case where --cached only did not' \ - 'echo content > foo - git add foo - git commit -m foo - echo "other content" > foo - git add foo - echo "yet another content" > foo + 'echo content >foo && + git add foo && + git commit -m foo --allow-empty && + echo "other content" >foo && + git add foo && + echo "yet another content" >foo && git rm --cached -f foo' test_expect_success \ @@ -170,7 +170,7 @@ test_expect_success 'but with -f it should work.' ' git rm -f foo baz && test ! -f foo && test ! -f baz && - test_must_fail git ls-files --error-unmatch foo + test_must_fail git ls-files --error-unmatch foo && test_must_fail git ls-files --error-unmatch baz ' @@ -183,7 +183,7 @@ test_expect_success 'refuse to remove cached empty file with modifications' ' test_expect_success 'remove intent-to-add file without --force' ' echo content >intent-to-add && - git add -N intent-to-add + git add -N intent-to-add && git rm --cached intent-to-add ' @@ -201,7 +201,7 @@ test_expect_success 'Recursive without -r fails' ' ' test_expect_success 'Recursive with -r but dirty' ' - echo qfwfq >>frotz/nitfol + echo qfwfq >>frotz/nitfol && test_must_fail git rm -r frotz && test -d frotz && test -f frotz/nitfol diff --git a/t/t3700-add.sh b/t/t3700-add.sh index fe274e2fb1..f7ff1f555d 100755 --- a/t/t3700-add.sh +++ b/t/t3700-add.sh @@ -91,6 +91,13 @@ test_expect_success 'error out when attempting to add ignored ones without -f' ' ! (git ls-files | grep "\\.ig") ' +test_expect_success 'error out when attempting to add ignored ones but add others' ' + touch a.if && + test_must_fail git add a.?? && + ! (git ls-files | grep "\\.ig") && + (git ls-files | grep a.if) +' + test_expect_success 'add ignored ones with -f' ' git add -f a.?? && git ls-files --error-unmatch a.ig @@ -311,7 +318,6 @@ cat >expect.err <<\EOF The following paths are ignored by one of your .gitignore files: ignored-file Use -f if you really want to add them. -fatal: no files added EOF cat >expect.out <<\EOF add 'track-this' diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh index 24ddd8a704..deae948c76 100755 --- a/t/t3701-add-interactive.sh +++ b/t/t3701-add-interactive.sh @@ -326,15 +326,34 @@ test_expect_success 'split hunk "add -p (edit)"' ' # 2. Correct version applies the (not)edited version, and asks # about the next hunk, against which we say q and program # exits. - for a in s e q n q q - do - echo $a - done | + printf "%s\n" s e q n q q | EDITOR=: git add -p && git diff >actual && ! grep "^+15" actual ' +test_expect_failure 'split hunk "add -p (no, yes, edit)"' ' + cat >test <<-\EOF && + 5 + 10 + 20 + 21 + 30 + 31 + 40 + 50 + 60 + EOF + git reset && + # test sequence is s(plit), n(o), y(es), e(dit) + # q n q q is there to make sure we exit at the end. + printf "%s\n" s n y e q n q q | + EDITOR=: git add -p 2>error && + test_must_be_empty error && + git diff >actual && + ! grep "^+31" actual +' + test_expect_success 'patch mode ignores unmerged entries' ' git reset --hard && test_commit conflict && diff --git a/t/t3702-add-edit.sh b/t/t3702-add-edit.sh index 4ee47cc9a8..3cb74ca296 100755 --- a/t/t3702-add-edit.sh +++ b/t/t3702-add-edit.sh @@ -118,4 +118,11 @@ test_expect_success 'add -e' ' ' +test_expect_success 'add -e notices editor failure' ' + git reset --hard && + echo change >>file && + test_must_fail env GIT_EDITOR=false git add -e && + test_expect_code 1 git diff --exit-code +' + test_done diff --git a/t/t3901-i18n-patch.sh b/t/t3901-i18n-patch.sh index 31a5770b34..509084e1a7 100755 --- a/t/t3901-i18n-patch.sh +++ b/t/t3901-i18n-patch.sh @@ -9,7 +9,7 @@ test_description='i18n settings and format-patch | am pipe' check_encoding () { # Make sure characters are not corrupted - cnt="$1" header="$2" i=1 j=0 bad=0 + cnt="$1" header="$2" i=1 j=0 while test "$i" -le $cnt do git format-patch --encoding=UTF-8 --stdout HEAD~$i..HEAD~$j | @@ -20,14 +20,10 @@ check_encoding () { grep "^encoding ISO8859-1" ;; *) grep "^encoding ISO8859-1"; test "$?" != 0 ;; - esac || { - bad=1 - break - } + esac || return 1 j=$i i=$(($i+1)) done - (exit $bad) } test_expect_success setup ' @@ -54,10 +50,13 @@ test_expect_success setup ' git add yours && git commit -s -m "Second on side" && - # the second one on the side branch is ISO-8859-1 - git config i18n.commitencoding ISO8859-1 && - # use author and committer name in ISO-8859-1 to match it. - . "$TEST_DIRECTORY"/t3901-8859-1.txt && + if test_have_prereq !MINGW + then + # the second one on the side branch is ISO-8859-1 + git config i18n.commitencoding ISO8859-1 && + # use author and committer name in ISO-8859-1 to match it. + . "$TEST_DIRECTORY"/t3901-8859-1.txt + fi && test_tick && echo Yet another >theirs && git add theirs && @@ -119,7 +118,7 @@ test_expect_success 'rebase (U/L)' ' check_encoding 2 ' -test_expect_success 'rebase (L/L)' ' +test_expect_success !MINGW 'rebase (L/L)' ' # In this test we want ISO-8859-1 encoded commits as the result git config i18n.commitencoding ISO8859-1 && git config i18n.logoutputencoding ISO8859-1 && @@ -131,7 +130,7 @@ test_expect_success 'rebase (L/L)' ' check_encoding 2 8859 ' -test_expect_success 'rebase (L/U)' ' +test_expect_success !MINGW 'rebase (L/U)' ' # This is pathological -- use UTF-8 as intermediate form # to get ISO-8859-1 results. git config i18n.commitencoding ISO8859-1 && @@ -159,7 +158,7 @@ test_expect_success 'cherry-pick(U/U)' ' check_encoding 3 ' -test_expect_success 'cherry-pick(L/L)' ' +test_expect_success !MINGW 'cherry-pick(L/L)' ' # Both the commitencoding and logoutputencoding is set to ISO-8859-1 git config i18n.commitencoding ISO8859-1 && @@ -189,7 +188,7 @@ test_expect_success 'cherry-pick(U/L)' ' check_encoding 3 ' -test_expect_success 'cherry-pick(L/U)' ' +test_expect_success !MINGW 'cherry-pick(L/U)' ' # Again, the commitencoding is set to ISO-8859-1 but # logoutputencoding is set to UTF-8. @@ -252,4 +251,66 @@ test_expect_success 'rebase --merge (L/U)' ' check_encoding 2 8859 ' +test_expect_success 'am (U/U)' ' + # Apply UTF-8 patches with UTF-8 commitencoding + git config i18n.commitencoding UTF-8 && + . "$TEST_DIRECTORY"/t3901-utf8.txt && + + git reset --hard master && + git am out-u1 out-u2 && + + check_encoding 2 +' + +test_expect_success !MINGW 'am (L/L)' ' + # Apply ISO-8859-1 patches with ISO-8859-1 commitencoding + git config i18n.commitencoding ISO8859-1 && + . "$TEST_DIRECTORY"/t3901-8859-1.txt && + + git reset --hard master && + git am out-l1 out-l2 && + + check_encoding 2 8859 +' + +test_expect_success 'am (U/L)' ' + # Apply ISO-8859-1 patches with UTF-8 commitencoding + git config i18n.commitencoding UTF-8 && + . "$TEST_DIRECTORY"/t3901-utf8.txt && + git reset --hard master && + + # am specifies --utf8 by default. + git am out-l1 out-l2 && + + check_encoding 2 +' + +test_expect_success 'am --no-utf8 (U/L)' ' + # Apply ISO-8859-1 patches with UTF-8 commitencoding + git config i18n.commitencoding UTF-8 && + . "$TEST_DIRECTORY"/t3901-utf8.txt && + + git reset --hard master && + git am --no-utf8 out-l1 out-l2 2>err && + + # commit-tree will warn that the commit message does not contain valid UTF-8 + # as mailinfo did not convert it + grep "did not conform" err && + + check_encoding 2 +' + +test_expect_success !MINGW 'am (L/U)' ' + # Apply UTF-8 patches with ISO-8859-1 commitencoding + git config i18n.commitencoding ISO8859-1 && + . "$TEST_DIRECTORY"/t3901-8859-1.txt && + + git reset --hard master && + # mailinfo will re-code the commit message to the charset specified by + # i18n.commitencoding + git am out-u1 out-u2 && + + check_encoding 2 8859 +' + test_done diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh index 5b79b216e2..2142c1fa92 100755 --- a/t/t3903-stash.sh +++ b/t/t3903-stash.sh @@ -10,6 +10,8 @@ test_description='Test git stash' test_expect_success 'stash some dirty working directory' ' echo 1 > file && git add file && + echo unrelated >other-file && + git add other-file && test_tick && git commit -m initial && echo 2 > file && @@ -45,8 +47,6 @@ test_expect_success 'applying bogus stash does nothing' ' test_expect_success 'apply does not need clean working directory' ' echo 4 >other-file && - git add other-file && - echo 5 >other-file && git stash apply && echo 3 >expect && test_cmp expect file @@ -93,6 +93,10 @@ test_expect_success 'unstashing in a subdirectory' ' ) ' +test_expect_success 'stash drop complains of extra options' ' + test_must_fail git stash drop --foo +' + test_expect_success 'drop top stash' ' git reset --hard && git stash list > stashlist1 && @@ -668,7 +672,7 @@ test_expect_success 'store updates stash ref and reflog' ' ! grep quux bazzy && git stash store -m quuxery $STASH_ID && test $(cat .git/refs/stash) = $STASH_ID && - grep $STASH_ID .git/logs/refs/stash && + git reflog --format=%H stash| grep $STASH_ID && git stash pop && grep quux bazzy ' @@ -685,4 +689,46 @@ test_expect_success 'handle stash specification with spaces' ' grep pig file ' +test_expect_success 'setup stash with index and worktree changes' ' + git stash clear && + git reset --hard && + echo index >file && + git add file && + echo working >file && + git stash +' + +test_expect_success 'stash list implies --first-parent -m' ' + cat >expect <<-EOF && + stash@{0} + + diff --git a/file b/file + index 257cc56..d26b33d 100644 + --- a/file + +++ b/file + @@ -1 +1 @@ + -foo + +working + EOF + git stash list --format=%gd -p >actual && + test_cmp expect actual +' + +test_expect_success 'stash list --cc shows combined diff' ' + cat >expect <<-\EOF && + stash@{0} + + diff --cc file + index 257cc56,9015a7a..d26b33d + --- a/file + +++ b/file + @@@ -1,1 -1,1 +1,1 @@@ + - foo + -index + ++working + EOF + git stash list --format=%gd -p --cc >actual && + test_cmp expect actual +' + test_done diff --git a/t/t3904-stash-patch.sh b/t/t3904-stash-patch.sh index 70655c1848..38e730090f 100755 --- a/t/t3904-stash-patch.sh +++ b/t/t3904-stash-patch.sh @@ -1,9 +1,15 @@ #!/bin/sh -test_description='git checkout --patch' +test_description='stash -p' . ./lib-patch-mode.sh -test_expect_success PERL 'setup' ' +if ! test_have_prereq PERL +then + skip_all='skipping stash -p tests, perl not available' + test_done +fi + +test_expect_success 'setup' ' mkdir dir && echo parent > dir/foo && echo dummy > bar && @@ -20,7 +26,7 @@ test_expect_success PERL 'setup' ' # note: order of files with unstaged changes: HEAD bar dir/foo -test_expect_success PERL 'saying "n" does nothing' ' +test_expect_success 'saying "n" does nothing' ' set_state HEAD HEADfile_work HEADfile_index && set_state dir/foo work index && (echo n; echo n; echo n) | test_must_fail git stash save -p && @@ -29,7 +35,7 @@ test_expect_success PERL 'saying "n" does nothing' ' verify_state dir/foo work index ' -test_expect_success PERL 'git stash -p' ' +test_expect_success 'git stash -p' ' (echo y; echo n; echo y) | git stash save -p && verify_state HEAD committed HEADfile_index && verify_saved_state bar && @@ -41,7 +47,7 @@ test_expect_success PERL 'git stash -p' ' verify_state dir/foo work head ' -test_expect_success PERL 'git stash -p --no-keep-index' ' +test_expect_success 'git stash -p --no-keep-index' ' set_state HEAD HEADfile_work HEADfile_index && set_state bar bar_work bar_index && set_state dir/foo work index && @@ -56,7 +62,7 @@ test_expect_success PERL 'git stash -p --no-keep-index' ' verify_state dir/foo work index ' -test_expect_success PERL 'git stash --no-keep-index -p' ' +test_expect_success 'git stash --no-keep-index -p' ' set_state HEAD HEADfile_work HEADfile_index && set_state bar bar_work bar_index && set_state dir/foo work index && @@ -71,8 +77,31 @@ test_expect_success PERL 'git stash --no-keep-index -p' ' verify_state dir/foo work index ' -test_expect_success PERL 'none of this moved HEAD' ' +test_expect_success 'none of this moved HEAD' ' verify_saved_head ' +test_expect_failure 'stash -p with split hunk' ' + git reset --hard && + cat >test <<-\EOF && + aaa + bbb + ccc + EOF + git add test && + git commit -m "initial" && + cat >test <<-\EOF && + aaa + added line 1 + bbb + added line 2 + ccc + EOF + printf "%s\n" s n y q | + test_might_fail git stash -p 2>error && + ! test_must_be_empty error && + grep "added line 1" test && + ! grep "added line 2" test +' + test_done diff --git a/t/t3905-stash-include-untracked.sh b/t/t3905-stash-include-untracked.sh index a5e7e6b2ba..f372fc8ca8 100755 --- a/t/t3905-stash-include-untracked.sh +++ b/t/t3905-stash-include-untracked.sh @@ -96,8 +96,8 @@ test_expect_success 'stash pop after save --include-untracked leaves files untra git stash pop && git status --porcelain >actual && test_cmp expect actual && - test "1" = "`cat file2`" && - test untracked = "`cat untracked/untracked`" + test "1" = "$(cat file2)" && + test untracked = "$(cat untracked/untracked)" ' git clean --force --quiet -d diff --git a/t/t3906-stash-submodule.sh b/t/t3906-stash-submodule.sh new file mode 100755 index 0000000000..d7219d6f8f --- /dev/null +++ b/t/t3906-stash-submodule.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +test_description='stash apply can handle submodules' + +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-submodule-update.sh + +git_stash () { + git status -su >expect && + ls -1pR * >>expect && + git read-tree -u -m "$1" && + git stash && + git status -su >actual && + ls -1pR * >>actual && + test_cmp expect actual && + git stash apply +} + +KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES=1 +KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT=1 +KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1 +test_submodule_switch "git_stash" + +test_done diff --git a/t/t3910-mac-os-precompose.sh b/t/t3910-mac-os-precompose.sh index e4ba6013e4..831935665e 100755 --- a/t/t3910-mac-os-precompose.sh +++ b/t/t3910-mac-os-precompose.sh @@ -14,13 +14,13 @@ then fi # create utf-8 variables -Adiarnfc=`printf '\303\204'` -Adiarnfd=`printf 'A\314\210'` +Adiarnfc=$(printf '\303\204') +Adiarnfd=$(printf 'A\314\210') -Odiarnfc=`printf '\303\226'` -Odiarnfd=`printf 'O\314\210'` -AEligatu=`printf '\303\206'` -Invalidu=`printf '\303\377'` +Odiarnfc=$(printf '\303\226') +Odiarnfd=$(printf 'O\314\210') +AEligatu=$(printf '\303\206') +Invalidu=$(printf '\303\377') #Create a string with 255 bytes (decomposed) @@ -35,7 +35,7 @@ Alongc=$Alongc$Alongc$Alongc$Alongc$Alongc #250 Byte Alongc=$Alongc$AEligatu$AEligatu #254 Byte test_expect_success "detect if nfd needed" ' - precomposeunicode=`git config core.precomposeunicode` && + precomposeunicode=$(git config core.precomposeunicode) && test "$precomposeunicode" = true && git config core.precomposeunicode true ' @@ -140,13 +140,23 @@ test_expect_success "Add long precomposed filename" ' git add * && git commit -m "Long filename" ' + +test_expect_failure 'handle existing decomposed filenames' ' + echo content >"verbatim.$Adiarnfd" && + git -c core.precomposeunicode=false add "verbatim.$Adiarnfd" && + git commit -m "existing decomposed file" && + >expect && + git ls-files --exclude-standard -o "verbatim*" >untracked && + test_cmp expect untracked +' + # Test if the global core.precomposeunicode stops autosensing # Must be the last test case test_expect_success "respect git config --global core.precomposeunicode" ' git config --global core.precomposeunicode true && rm -rf .git && git init && - precomposeunicode=`git config core.precomposeunicode` && + precomposeunicode=$(git config core.precomposeunicode) && test "$precomposeunicode" = "true" ' diff --git a/t/t4003-diff-rename-1.sh b/t/t4003-diff-rename-1.sh index bfa8835638..df2accb655 100755 --- a/t/t4003-diff-rename-1.sh +++ b/t/t4003-diff-rename-1.sh @@ -11,7 +11,7 @@ test_description='More rename detection test_expect_success \ 'prepare reference tree' \ - 'cat "$TEST_DIRECTORY"/../COPYING >COPYING && + 'cat "$TEST_DIRECTORY"/diff-lib/COPYING >COPYING && echo frotz >rezrov && git update-index --add COPYING rezrov && tree=$(git write-tree) && @@ -99,7 +99,7 @@ test_expect_success \ test_expect_success \ 'prepare work tree once again' \ - 'cat "$TEST_DIRECTORY"/../COPYING >COPYING && + 'cat "$TEST_DIRECTORY"/diff-lib/COPYING >COPYING && git update-index --add --remove COPYING COPYING.1' # tree has COPYING and rezrov. work tree has COPYING and COPYING.1, diff --git a/t/t4005-diff-rename-2.sh b/t/t4005-diff-rename-2.sh index 7d2c6e13a2..135addbfbd 100755 --- a/t/t4005-diff-rename-2.sh +++ b/t/t4005-diff-rename-2.sh @@ -11,7 +11,7 @@ test_description='Same rename detection as t4003 but testing diff-raw. test_expect_success \ 'prepare reference tree' \ - 'cat "$TEST_DIRECTORY"/../COPYING >COPYING && + 'cat "$TEST_DIRECTORY"/diff-lib/COPYING >COPYING && echo frotz >rezrov && git update-index --add COPYING rezrov && tree=$(git write-tree) && @@ -71,7 +71,7 @@ test_expect_success \ test_expect_success \ 'prepare work tree once again' \ - 'cat "$TEST_DIRECTORY"/../COPYING >COPYING && + 'cat "$TEST_DIRECTORY"/diff-lib/COPYING >COPYING && git update-index --add --remove COPYING COPYING.1' git diff-index -C --find-copies-harder $tree >current diff --git a/t/t4006-diff-mode.sh b/t/t4006-diff-mode.sh index 05911492ca..76f643b2c2 100755 --- a/t/t4006-diff-mode.sh +++ b/t/t4006-diff-mode.sh @@ -13,7 +13,7 @@ sed_script='s/\(:100644 100755\) \('"$_x40"'\) \2 /\1 X X /' test_expect_success 'setup' ' echo frotz >rezrov && git update-index --add rezrov && - tree=`git write-tree` && + tree=$(git write-tree) && echo $tree ' diff --git a/t/t4007-rename-3.sh b/t/t4007-rename-3.sh index 11502b7509..dae327fabb 100755 --- a/t/t4007-rename-3.sh +++ b/t/t4007-rename-3.sh @@ -11,7 +11,7 @@ test_description='Rename interaction with pathspec. test_expect_success 'prepare reference tree' ' mkdir path0 path1 && - cp "$TEST_DIRECTORY"/../COPYING path0/COPYING && + cp "$TEST_DIRECTORY"/diff-lib/COPYING path0/COPYING && git update-index --add path0/COPYING && tree=$(git write-tree) && echo $tree diff --git a/t/t4008-diff-break-rewrite.sh b/t/t4008-diff-break-rewrite.sh index 27e98a8f9d..9dd1bc5e16 100755 --- a/t/t4008-diff-break-rewrite.sh +++ b/t/t4008-diff-break-rewrite.sh @@ -10,179 +10,145 @@ We have two very different files, file0 and file1, registered in a tree. We update file1 so drastically that it is more similar to file0, and then remove file0. With -B, changes to file1 should be broken into separate delete and create, resulting in removal of file0, removal of -original file1 and creation of completely rewritten file1. +original file1 and creation of completely rewritten file1. The latter +two are then merged back into a single "complete rewrite". Further, with -B and -M together, these three modifications should turn into rename-edit of file0 into file1. Starting from the same two files in the tree, we swap file0 and file1. -With -B, this should be detected as two complete rewrites, resulting in -four changes in total. +With -B, this should be detected as two complete rewrites. Further, with -B and -M together, these should turn into two renames. ' . ./test-lib.sh . "$TEST_DIRECTORY"/diff-lib.sh ;# test-lib chdir's into trash -test_expect_success \ - setup \ - 'cat "$TEST_DIRECTORY"/../README >file0 && - cat "$TEST_DIRECTORY"/../COPYING >file1 && - git update-index --add file0 file1 && - tree=$(git write-tree) && - echo "$tree"' - -test_expect_success \ - 'change file1 with copy-edit of file0 and remove file0' \ - 'sed -e "s/git/GIT/" file0 >file1 && - rm -f file0 && - git update-index --remove file0 file1' - -test_expect_success \ - 'run diff with -B' \ - 'git diff-index -B --cached "$tree" >current' - -cat >expected <<\EOF -:100644 000000 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 0000000000000000000000000000000000000000 D file0 -:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 11e331465a89c394dc25c780de230043750c1ec8 M100 file1 -EOF - -test_expect_success \ - 'validate result of -B (#1)' \ - 'compare_diff_raw expected current' - -test_expect_success \ - 'run diff with -B and -M' \ - 'git diff-index -B -M "$tree" >current' - -cat >expected <<\EOF -:100644 100644 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 08bb2fb671deff4c03a4d4a0a1315dff98d5732c R100 file0 file1 -EOF - -test_expect_success \ - 'validate result of -B -M (#2)' \ - 'compare_diff_raw expected current' - -test_expect_success \ - 'swap file0 and file1' \ - 'rm -f file0 file1 && - git read-tree -m $tree && - git checkout-index -f -u -a && - mv file0 tmp && - mv file1 file0 && - mv tmp file1 && - git update-index file0 file1' - -test_expect_success \ - 'run diff with -B' \ - 'git diff-index -B "$tree" >current' - -cat >expected <<\EOF -:100644 100644 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 6ff87c4664981e4397625791c8ea3bbb5f2279a3 M100 file0 -:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 M100 file1 -EOF - -test_expect_success \ - 'validate result of -B (#3)' \ - 'compare_diff_raw expected current' - -test_expect_success \ - 'run diff with -B and -M' \ - 'git diff-index -B -M "$tree" >current' - -cat >expected <<\EOF -:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 6ff87c4664981e4397625791c8ea3bbb5f2279a3 R100 file1 file0 -:100644 100644 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 R100 file0 file1 -EOF - -test_expect_success \ - 'validate result of -B -M (#4)' \ - 'compare_diff_raw expected current' - -test_expect_success \ - 'make file0 into something completely different' \ - 'rm -f file0 && - test_ln_s_add frotz file0 && - git update-index file1' - -test_expect_success \ - 'run diff with -B' \ - 'git diff-index -B "$tree" >current' - -cat >expected <<\EOF -:100644 120000 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 67be421f88824578857624f7b3dc75e99a8a1481 T file0 -:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 M100 file1 -EOF - -test_expect_success \ - 'validate result of -B (#5)' \ - 'compare_diff_raw expected current' - -test_expect_success \ - 'run diff with -B -M' \ - 'git diff-index -B -M "$tree" >current' - -# file0 changed from regular to symlink. file1 is very close to the preimage of file0. -# because we break file0, file1 can become a rename of it. -cat >expected <<\EOF -:100644 120000 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 67be421f88824578857624f7b3dc75e99a8a1481 T file0 -:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 R file0 file1 -EOF - -test_expect_success \ - 'validate result of -B -M (#6)' \ - 'compare_diff_raw expected current' - -test_expect_success \ - 'run diff with -M' \ - 'git diff-index -M "$tree" >current' - -# This should not mistake file0 as the copy source of new file1 -# due to type differences. -cat >expected <<\EOF -:100644 120000 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 67be421f88824578857624f7b3dc75e99a8a1481 T file0 -:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 M file1 -EOF - -test_expect_success \ - 'validate result of -M (#7)' \ - 'compare_diff_raw expected current' - -test_expect_success \ - 'file1 edited to look like file0 and file0 rename-edited to file2' \ - 'rm -f file0 file1 && - git read-tree -m $tree && - git checkout-index -f -u -a && - sed -e "s/git/GIT/" file0 >file1 && - sed -e "s/git/GET/" file0 >file2 && - rm -f file0 && - git update-index --add --remove file0 file1 file2' - -test_expect_success \ - 'run diff with -B' \ - 'git diff-index -B "$tree" >current' - -cat >expected <<\EOF -:100644 000000 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 0000000000000000000000000000000000000000 D file0 -:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 08bb2fb671deff4c03a4d4a0a1315dff98d5732c M100 file1 -:000000 100644 0000000000000000000000000000000000000000 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 A file2 -EOF - -test_expect_success \ - 'validate result of -B (#8)' \ - 'compare_diff_raw expected current' - -test_expect_success \ - 'run diff with -B -C' \ - 'git diff-index -B -C "$tree" >current' - -cat >expected <<\EOF -:100644 100644 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 08bb2fb671deff4c03a4d4a0a1315dff98d5732c C095 file0 file1 -:100644 100644 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 59f832e5c8b3f7e486be15ad0cd3e95ba9af8998 R095 file0 file2 -EOF - -test_expect_success \ - 'validate result of -B -M (#9)' \ - 'compare_diff_raw expected current' +test_expect_success setup ' + cat "$TEST_DIRECTORY"/diff-lib/README >file0 && + cat "$TEST_DIRECTORY"/diff-lib/COPYING >file1 && + git update-index --add file0 file1 && + git tag reference $(git write-tree) +' + +test_expect_success 'change file1 with copy-edit of file0 and remove file0' ' + sed -e "s/git/GIT/" file0 >file1 && + rm -f file0 && + git update-index --remove file0 file1 +' + +test_expect_success 'run diff with -B (#1)' ' + git diff-index -B --cached reference >current && + cat >expect <<-\EOF && + :100644 000000 548142c327a6790ff8821d67c2ee1eff7a656b52 0000000000000000000000000000000000000000 D file0 + :100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 2fbedd0b5d4b8126e4750c3bee305e8ff79f80ec M100 file1 + EOF + compare_diff_raw expect current +' + +test_expect_success 'run diff with -B and -M (#2)' ' + git diff-index -B -M reference >current && + cat >expect <<-\EOF && + :100644 100644 548142c327a6790ff8821d67c2ee1eff7a656b52 2fbedd0b5d4b8126e4750c3bee305e8ff79f80ec R100 file0 file1 + EOF + compare_diff_raw expect current +' + +test_expect_success 'swap file0 and file1' ' + rm -f file0 file1 && + git read-tree -m reference && + git checkout-index -f -u -a && + mv file0 tmp && + mv file1 file0 && + mv tmp file1 && + git update-index file0 file1 +' + +test_expect_success 'run diff with -B (#3)' ' + git diff-index -B reference >current && + cat >expect <<-\EOF && + :100644 100644 548142c327a6790ff8821d67c2ee1eff7a656b52 6ff87c4664981e4397625791c8ea3bbb5f2279a3 M100 file0 + :100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 548142c327a6790ff8821d67c2ee1eff7a656b52 M100 file1 + EOF + compare_diff_raw expect current +' + +test_expect_success 'run diff with -B and -M (#4)' ' + git diff-index -B -M reference >current && + cat >expect <<-\EOF && + :100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 6ff87c4664981e4397625791c8ea3bbb5f2279a3 R100 file1 file0 + :100644 100644 548142c327a6790ff8821d67c2ee1eff7a656b52 548142c327a6790ff8821d67c2ee1eff7a656b52 R100 file0 file1 + EOF + compare_diff_raw expect current +' + +test_expect_success 'make file0 into something completely different' ' + rm -f file0 && + test_ln_s_add frotz file0 && + git update-index file1 +' + +test_expect_success 'run diff with -B (#5)' ' + git diff-index -B reference >current && + cat >expect <<-\EOF && + :100644 120000 548142c327a6790ff8821d67c2ee1eff7a656b52 67be421f88824578857624f7b3dc75e99a8a1481 T file0 + :100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 548142c327a6790ff8821d67c2ee1eff7a656b52 M100 file1 + EOF + compare_diff_raw expect current +' + +test_expect_success 'run diff with -B -M (#6)' ' + git diff-index -B -M reference >current && + + # file0 changed from regular to symlink. file1 is the same as the preimage + # of file0. Because the change does not make file0 disappear, file1 is + # denoted as a copy of file0 + cat >expect <<-\EOF && + :100644 120000 548142c327a6790ff8821d67c2ee1eff7a656b52 67be421f88824578857624f7b3dc75e99a8a1481 T file0 + :100644 100644 548142c327a6790ff8821d67c2ee1eff7a656b52 548142c327a6790ff8821d67c2ee1eff7a656b52 C file0 file1 + EOF + compare_diff_raw expect current +' + +test_expect_success 'run diff with -M (#7)' ' + git diff-index -M reference >current && + + # This should not mistake file0 as the copy source of new file1 + # due to type differences. + cat >expect <<-\EOF && + :100644 120000 548142c327a6790ff8821d67c2ee1eff7a656b52 67be421f88824578857624f7b3dc75e99a8a1481 T file0 + :100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 548142c327a6790ff8821d67c2ee1eff7a656b52 M file1 + EOF + compare_diff_raw expect current +' + +test_expect_success 'file1 edited to look like file0 and file0 rename-edited to file2' ' + rm -f file0 file1 && + git read-tree -m reference && + git checkout-index -f -u -a && + sed -e "s/git/GIT/" file0 >file1 && + sed -e "s/git/GET/" file0 >file2 && + rm -f file0 && + git update-index --add --remove file0 file1 file2 +' + +test_expect_success 'run diff with -B (#8)' ' + git diff-index -B reference >current && + cat >expect <<-\EOF && + :100644 000000 548142c327a6790ff8821d67c2ee1eff7a656b52 0000000000000000000000000000000000000000 D file0 + :100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 2fbedd0b5d4b8126e4750c3bee305e8ff79f80ec M100 file1 + :000000 100644 0000000000000000000000000000000000000000 69a939f651686f56322566e2fd76715947a24162 A file2 + EOF + compare_diff_raw expect current +' + +test_expect_success 'run diff with -B -C (#9)' ' + git diff-index -B -C reference >current && + cat >expect <<-\EOF && + :100644 100644 548142c327a6790ff8821d67c2ee1eff7a656b52 2fbedd0b5d4b8126e4750c3bee305e8ff79f80ec C095 file0 file1 + :100644 100644 548142c327a6790ff8821d67c2ee1eff7a656b52 69a939f651686f56322566e2fd76715947a24162 R095 file0 file2 + EOF + compare_diff_raw expect current +' test_done diff --git a/t/t4009-diff-rename-4.sh b/t/t4009-diff-rename-4.sh index 57c094fdce..3641fd84d6 100755 --- a/t/t4009-diff-rename-4.sh +++ b/t/t4009-diff-rename-4.sh @@ -11,7 +11,7 @@ test_description='Same rename detection as t4003 but testing diff-raw -z. test_expect_success \ 'prepare reference tree' \ - 'cat "$TEST_DIRECTORY"/../COPYING >COPYING && + 'cat "$TEST_DIRECTORY"/diff-lib/COPYING >COPYING && echo frotz >rezrov && git update-index --add COPYING rezrov && tree=$(git write-tree) && @@ -78,7 +78,7 @@ test_expect_success \ test_expect_success \ 'prepare work tree once again' \ - 'cat "$TEST_DIRECTORY"/../COPYING >COPYING && + 'cat "$TEST_DIRECTORY"/diff-lib/COPYING >COPYING && git update-index --add --remove COPYING COPYING.1' git diff-index -z -C --find-copies-harder $tree >current diff --git a/t/t4010-diff-pathspec.sh b/t/t4010-diff-pathspec.sh index 2bb973655b..43c488b545 100755 --- a/t/t4010-diff-pathspec.sh +++ b/t/t4010-diff-pathspec.sh @@ -18,7 +18,7 @@ test_expect_success \ mkdir path1 && echo rezrov >path1/file1 && git update-index --add file0 path1/file1 && - tree=`git write-tree` && + tree=$(git write-tree) && echo "$tree" && echo nitfol >file0 && echo yomin >path1/file1 && @@ -56,7 +56,7 @@ test_expect_success \ compare_diff_raw current expected' cat >expected <<\EOF -:100644 100644 766498d93a4b06057a8e49d23f4068f1170ff38f 0a41e115ab61be0328a19b29f18cdcb49338d516 M file0 +:100644 100644 8e4020bb5a8d8c873b25de15933e75cc0fc275df dca6b92303befc93086aa025d90a5facd7eb2812 M file0 EOF test_expect_success \ 'limit to file0 should show file0' \ @@ -131,7 +131,7 @@ test_expect_success 'diff multiple wildcard pathspecs' ' mkdir path2 && echo rezrov >path2/file1 && git update-index --add path2/file1 && - tree3=`git write-tree` && + tree3=$(git write-tree) && git diff --name-only $tree $tree3 -- "path2*1" "path1*1" >actual && cat <<-\EOF >expect && path1/file1 diff --git a/t/t4012-diff-binary.sh b/t/t4012-diff-binary.sh index 1215ae544b..643d729157 100755 --- a/t/t4012-diff-binary.sh +++ b/t/t4012-diff-binary.sh @@ -67,18 +67,18 @@ test_expect_success C_LOCALE_OUTPUT 'apply detecting corrupt patch correctly' ' git diff >output && sed -e "s/-CIT/xCIT/" <output >broken && test_must_fail git apply --stat --summary broken 2>detected && - detected=`cat detected` && - detected=`expr "$detected" : "fatal.*at line \\([0-9]*\\)\$"` && - detected=`sed -ne "${detected}p" broken` && + detected=$(cat detected) && + detected=$(expr "$detected" : "fatal.*at line \\([0-9]*\\)\$") && + detected=$(sed -ne "${detected}p" broken) && test "$detected" = xCIT ' test_expect_success C_LOCALE_OUTPUT 'apply detecting corrupt patch correctly' ' git diff --binary | sed -e "s/-CIT/xCIT/" >broken && test_must_fail git apply --stat --summary broken 2>detected && - detected=`cat detected` && - detected=`expr "$detected" : "fatal.*at line \\([0-9]*\\)\$"` && - detected=`sed -ne "${detected}p" broken` && + detected=$(cat detected) && + detected=$(expr "$detected" : "fatal.*at line \\([0-9]*\\)\$") && + detected=$(sed -ne "${detected}p" broken) && test "$detected" = xCIT ' @@ -88,7 +88,7 @@ test_expect_success 'initial commit' 'git commit -a -m initial' test_expect_success 'diff-index with --binary' ' echo AIT >a && mv b e && echo CIT >c && cat e >d && git update-index --add --remove a b c d e && - tree0=`git write-tree` && + tree0=$(git write-tree) && git diff --cached --binary >current && git apply --stat --summary current ' @@ -96,7 +96,7 @@ test_expect_success 'diff-index with --binary' ' test_expect_success 'apply binary patch' ' git reset --hard && git apply --binary --index <current && - tree1=`git write-tree` && + tree1=$(git write-tree) && test "$tree1" = "$tree0" ' diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh index f7a9af893b..6ec6072118 100755 --- a/t/t4013-diff-various.sh +++ b/t/t4013-diff-various.sh @@ -107,14 +107,14 @@ test_expect_success setup ' +*++ [initial] Initial EOF -V=`git version | sed -e 's/^git version //' -e 's/\./\\./g'` +V=$(git version | sed -e 's/^git version //' -e 's/\./\\./g') while read cmd do case "$cmd" in '' | '#'*) continue ;; esac - test=`echo "$cmd" | sed -e 's|[/ ][/ ]*|_|g'` - pfx=`printf "%04d" $test_count` + test=$(echo "$cmd" | sed -e 's|[/ ][/ ]*|_|g') + pfx=$(printf "%04d" $test_count) expect="$TEST_DIRECTORY/t4013/diff.$test" actual="$pfx-diff.$test" diff --git a/t/t4013/diff.log_--decorate=full_--all b/t/t4013/diff.log_--decorate=full_--all index 44d45257da..b345b2ebfa 100644 --- a/t/t4013/diff.log_--decorate=full_--all +++ b/t/t4013/diff.log_--decorate=full_--all @@ -5,7 +5,7 @@ Date: Mon Jun 26 00:06:00 2006 +0000 Rearranged lines in dir/sub -commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD, refs/heads/master) +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD -> refs/heads/master) Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:04:00 2006 +0000 diff --git a/t/t4013/diff.log_--decorate_--all b/t/t4013/diff.log_--decorate_--all index 27d3eabc26..3aa16a9e42 100644 --- a/t/t4013/diff.log_--decorate_--all +++ b/t/t4013/diff.log_--decorate_--all @@ -5,7 +5,7 @@ Date: Mon Jun 26 00:06:00 2006 +0000 Rearranged lines in dir/sub -commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD, master) +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD -> master) Merge: 9a6d494 c7a2ab9 Author: A U Thor <author@example.com> Date: Mon Jun 26 00:04:00 2006 +0000 diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh index 9c80633146..646c4750ec 100755 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@ -43,7 +43,7 @@ test_expect_success setup ' test_expect_success "format-patch --ignore-if-in-upstream" ' git format-patch --stdout master..side >patch0 && - cnt=`grep "^From " patch0 | wc -l` && + cnt=$(grep "^From " patch0 | wc -l) && test $cnt = 3 ' @@ -52,11 +52,19 @@ test_expect_success "format-patch --ignore-if-in-upstream" ' git format-patch --stdout \ --ignore-if-in-upstream master..side >patch1 && - cnt=`grep "^From " patch1 | wc -l` && + cnt=$(grep "^From " patch1 | wc -l) && test $cnt = 2 ' +test_expect_success "format-patch --ignore-if-in-upstream handles tags" ' + git tag -a v1 -m tag side && + git tag -a v2 -m tag master && + git format-patch --stdout --ignore-if-in-upstream v2..v1 >patch1 && + cnt=$(grep "^From " patch1 | wc -l) && + test $cnt = 2 +' + test_expect_success "format-patch doesn't consider merge commits" ' git checkout -b slave master && @@ -69,7 +77,7 @@ test_expect_success "format-patch doesn't consider merge commits" ' git checkout -b merger master && test_tick && git merge --no-ff slave && - cnt=`git format-patch -3 --stdout | grep "^From " | wc -l` && + cnt=$(git format-patch -3 --stdout | grep "^From " | wc -l) && test $cnt = 3 ' @@ -77,7 +85,7 @@ test_expect_success "format-patch result applies" ' git checkout -b rebuild-0 master && git am -3 patch0 && - cnt=`git rev-list master.. | wc -l` && + cnt=$(git rev-list master.. | wc -l) && test $cnt = 2 ' @@ -85,7 +93,7 @@ test_expect_success "format-patch --ignore-if-in-upstream result applies" ' git checkout -b rebuild-1 master && git am -3 patch1 && - cnt=`git rev-list master.. | wc -l` && + cnt=$(git rev-list master.. | wc -l) && test $cnt = 2 ' @@ -762,6 +770,67 @@ test_expect_success 'format-patch --signature="" suppresses signatures' ' ! grep "^-- \$" output ' +test_expect_success 'prepare mail-signature input' ' + cat >mail-signature <<-\EOF + + Test User <test.email@kernel.org> + http://git.kernel.org/cgit/git/git.git + + git.kernel.org/?p=git/git.git;a=summary + + EOF +' + +test_expect_success '--signature-file=file works' ' + git format-patch --stdout --signature-file=mail-signature -1 >output && + check_patch output && + sed -e "1,/^-- \$/d" <output >actual && + { + cat mail-signature && echo + } >expect && + test_cmp expect actual +' + +test_expect_success 'format.signaturefile works' ' + test_config format.signaturefile mail-signature && + git format-patch --stdout -1 >output && + check_patch output && + sed -e "1,/^-- \$/d" <output >actual && + { + cat mail-signature && echo + } >expect && + test_cmp expect actual +' + +test_expect_success '--no-signature suppresses format.signaturefile ' ' + test_config format.signaturefile mail-signature && + git format-patch --stdout --no-signature -1 >output && + check_patch output && + ! grep "^-- \$" output +' + +test_expect_success '--signature-file overrides format.signaturefile' ' + cat >other-mail-signature <<-\EOF && + Use this other signature instead of mail-signature. + EOF + test_config format.signaturefile mail-signature && + git format-patch --stdout \ + --signature-file=other-mail-signature -1 >output && + check_patch output && + sed -e "1,/^-- \$/d" <output >actual && + { + cat other-mail-signature && echo + } >expect && + test_cmp expect actual +' + +test_expect_success '--signature overrides format.signaturefile' ' + test_config format.signaturefile mail-signature && + git format-patch --stdout --signature="my sig" -1 >output && + check_patch output && + grep "my sig" output +' + test_expect_success TTY 'format-patch --stdout paginates' ' rm -f pager_used && test_terminal env GIT_PAGER="wc >pager_used" git format-patch --stdout --all && @@ -1362,4 +1431,18 @@ test_expect_success 'cover letter auto user override' ' test_line_count = 2 list ' +test_expect_success 'format-patch --zero-commit' ' + git format-patch --zero-commit --stdout v2..v1 >patch2 && + grep "^From " patch2 | sort | uniq >actual && + echo "From $_z40 Mon Sep 17 00:00:00 2001" >expect && + test_cmp expect actual +' + +test_expect_success 'From line has expected format' ' + git format-patch --stdout v2..v1 >patch2 && + grep "^From " patch2 >from && + grep "^From $_x40 Mon Sep 17 00:00:00 2001$" patch2 >filtered && + test_cmp from filtered +' + test_done diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh index 604a838c1a..2434157aa7 100755 --- a/t/t4015-diff-whitespace.sh +++ b/t/t4015-diff-whitespace.sh @@ -9,138 +9,144 @@ test_description='Test special whitespace in diff engine. . ./test-lib.sh . "$TEST_DIRECTORY"/diff-lib.sh -# Ray Lehtiniemi's example +test_expect_success "Ray Lehtiniemi's example" ' + cat <<-\EOF >x && + do { + nothing; + } while (0); + EOF + git update-index --add x && -cat << EOF > x -do { - nothing; -} while (0); -EOF + cat <<-\EOF >x && + do + { + nothing; + } + while (0); + EOF + + cat <<-\EOF >expect && + diff --git a/x b/x + index adf3937..6edc172 100644 + --- a/x + +++ b/x + @@ -1,3 +1,5 @@ + -do { + +do + +{ + nothing; + -} while (0); + +} + +while (0); + EOF -git update-index --add x + git diff >out && + test_cmp expect out && -cat << EOF > x -do -{ - nothing; -} -while (0); -EOF + git diff -w >out && + test_cmp expect out && -cat << EOF > expect -diff --git a/x b/x -index adf3937..6edc172 100644 ---- a/x -+++ b/x -@@ -1,3 +1,5 @@ --do { -+do -+{ - nothing; --} while (0); -+} -+while (0); -EOF + git diff -b >out && + test_cmp expect out +' -git diff > out -test_expect_success "Ray's example without options" 'test_cmp expect out' +test_expect_success 'another test, without options' ' + tr Q "\015" <<-\EOF >x && + whitespace at beginning + whitespace change + whitespace in the middle + whitespace at end + unchanged line + CR at endQ + EOF -git diff -w > out -test_expect_success "Ray's example with -w" 'test_cmp expect out' + git update-index x && -git diff -b > out -test_expect_success "Ray's example with -b" 'test_cmp expect out' + tr "_" " " <<-\EOF >x && + _ whitespace at beginning + whitespace change + white space in the middle + whitespace at end__ + unchanged line + CR at end + EOF -tr 'Q' '\015' << EOF > x -whitespace at beginning -whitespace change -whitespace in the middle -whitespace at end -unchanged line -CR at endQ -EOF + tr "Q_" "\015 " <<-\EOF >expect && + diff --git a/x b/x + index d99af23..22d9f73 100644 + --- a/x + +++ b/x + @@ -1,6 +1,6 @@ + -whitespace at beginning + -whitespace change + -whitespace in the middle + -whitespace at end + + whitespace at beginning + +whitespace change + +white space in the middle + +whitespace at end__ + unchanged line + -CR at endQ + +CR at end + EOF -git update-index x + git diff >out && + test_cmp expect out && -tr '_' ' ' << EOF > x - whitespace at beginning -whitespace change -white space in the middle -whitespace at end__ -unchanged line -CR at end -EOF + >expect && + git diff -w >out && + test_cmp expect out && -tr 'Q_' '\015 ' << EOF > expect -diff --git a/x b/x -index d99af23..8b32fb5 100644 ---- a/x -+++ b/x -@@ -1,6 +1,6 @@ --whitespace at beginning --whitespace change --whitespace in the middle --whitespace at end -+ whitespace at beginning -+whitespace change -+white space in the middle -+whitespace at end__ - unchanged line --CR at endQ -+CR at end -EOF -git diff > out -test_expect_success 'another test, without options' 'test_cmp expect out' + git diff -w -b >out && + test_cmp expect out && -cat << EOF > expect -EOF -git diff -w > out -test_expect_success 'another test, with -w' 'test_cmp expect out' -git diff -w -b > out -test_expect_success 'another test, with -w -b' 'test_cmp expect out' -git diff -w --ignore-space-at-eol > out -test_expect_success 'another test, with -w --ignore-space-at-eol' 'test_cmp expect out' -git diff -w -b --ignore-space-at-eol > out -test_expect_success 'another test, with -w -b --ignore-space-at-eol' 'test_cmp expect out' - -tr 'Q_' '\015 ' << EOF > expect -diff --git a/x b/x -index d99af23..8b32fb5 100644 ---- a/x -+++ b/x -@@ -1,6 +1,6 @@ --whitespace at beginning -+ whitespace at beginning - whitespace change --whitespace in the middle -+white space in the middle - whitespace at end__ - unchanged line - CR at end -EOF -git diff -b > out -test_expect_success 'another test, with -b' 'test_cmp expect out' -git diff -b --ignore-space-at-eol > out -test_expect_success 'another test, with -b --ignore-space-at-eol' 'test_cmp expect out' - -tr 'Q_' '\015 ' << EOF > expect -diff --git a/x b/x -index d99af23..8b32fb5 100644 ---- a/x -+++ b/x -@@ -1,6 +1,6 @@ --whitespace at beginning --whitespace change --whitespace in the middle -+ whitespace at beginning -+whitespace change -+white space in the middle - whitespace at end__ - unchanged line - CR at end -EOF -git diff --ignore-space-at-eol > out -test_expect_success 'another test, with --ignore-space-at-eol' 'test_cmp expect out' + git diff -w --ignore-space-at-eol >out && + test_cmp expect out && + + git diff -w -b --ignore-space-at-eol >out && + test_cmp expect out && + + + tr "Q_" "\015 " <<-\EOF >expect && + diff --git a/x b/x + index d99af23..22d9f73 100644 + --- a/x + +++ b/x + @@ -1,6 +1,6 @@ + -whitespace at beginning + +_ whitespace at beginning + whitespace change + -whitespace in the middle + +white space in the middle + whitespace at end__ + unchanged line + CR at end + EOF + git diff -b >out && + test_cmp expect out && + + git diff -b --ignore-space-at-eol >out && + test_cmp expect out && + + tr "Q_" "\015 " <<-\EOF >expect && + diff --git a/x b/x + index d99af23..22d9f73 100644 + --- a/x + +++ b/x + @@ -1,6 +1,6 @@ + -whitespace at beginning + -whitespace change + -whitespace in the middle + +_ whitespace at beginning + +whitespace change + +white space in the middle + whitespace at end__ + unchanged line + CR at end + EOF + git diff --ignore-space-at-eol >out && + test_cmp expect out +' test_expect_success 'ignore-blank-lines: only new lines' ' test_seq 5 >x && @@ -489,291 +495,219 @@ test_expect_success 'ignore-blank-lines: mix changes and blank lines' ' ' test_expect_success 'check mixed spaces and tabs in indent' ' - # This is indented with SP HT SP. - echo " foo();" > x && + echo " foo();" >x && git diff --check | grep "space before tab in indent" - ' test_expect_success 'check mixed tabs and spaces in indent' ' - # This is indented with HT SP HT. - echo " foo();" > x && + echo " foo();" >x && git diff --check | grep "space before tab in indent" - ' test_expect_success 'check with no whitespace errors' ' - git commit -m "snapshot" && - echo "foo();" > x && + echo "foo();" >x && git diff --check - ' test_expect_success 'check with trailing whitespace' ' - - echo "foo(); " > x && + echo "foo(); " >x && test_must_fail git diff --check - ' test_expect_success 'check with space before tab in indent' ' - # indent has space followed by hard tab - echo " foo();" > x && + echo " foo();" >x && test_must_fail git diff --check - ' test_expect_success '--check and --exit-code are not exclusive' ' - git checkout x && git diff --check --exit-code - ' test_expect_success '--check and --quiet are not exclusive' ' - git diff --check --quiet - ' test_expect_success 'check staged with no whitespace errors' ' - - echo "foo();" > x && + echo "foo();" >x && git add x && git diff --cached --check - ' test_expect_success 'check staged with trailing whitespace' ' - - echo "foo(); " > x && + echo "foo(); " >x && git add x && test_must_fail git diff --cached --check - ' test_expect_success 'check staged with space before tab in indent' ' - # indent has space followed by hard tab - echo " foo();" > x && + echo " foo();" >x && git add x && test_must_fail git diff --cached --check - ' test_expect_success 'check with no whitespace errors (diff-index)' ' - - echo "foo();" > x && + echo "foo();" >x && git add x && git diff-index --check HEAD - ' test_expect_success 'check with trailing whitespace (diff-index)' ' - - echo "foo(); " > x && + echo "foo(); " >x && git add x && test_must_fail git diff-index --check HEAD - ' test_expect_success 'check with space before tab in indent (diff-index)' ' - # indent has space followed by hard tab - echo " foo();" > x && + echo " foo();" >x && git add x && test_must_fail git diff-index --check HEAD - ' test_expect_success 'check staged with no whitespace errors (diff-index)' ' - - echo "foo();" > x && + echo "foo();" >x && git add x && git diff-index --cached --check HEAD - ' test_expect_success 'check staged with trailing whitespace (diff-index)' ' - - echo "foo(); " > x && + echo "foo(); " >x && git add x && test_must_fail git diff-index --cached --check HEAD - ' test_expect_success 'check staged with space before tab in indent (diff-index)' ' - # indent has space followed by hard tab - echo " foo();" > x && + echo " foo();" >x && git add x && test_must_fail git diff-index --cached --check HEAD - ' test_expect_success 'check with no whitespace errors (diff-tree)' ' - - echo "foo();" > x && + echo "foo();" >x && git commit -m "new commit" x && git diff-tree --check HEAD^ HEAD - ' test_expect_success 'check with trailing whitespace (diff-tree)' ' - - echo "foo(); " > x && + echo "foo(); " >x && git commit -m "another commit" x && test_must_fail git diff-tree --check HEAD^ HEAD - ' test_expect_success 'check with space before tab in indent (diff-tree)' ' - # indent has space followed by hard tab - echo " foo();" > x && + echo " foo();" >x && git commit -m "yet another" x && test_must_fail git diff-tree --check HEAD^ HEAD - ' test_expect_success 'check trailing whitespace (trailing-space: off)' ' - git config core.whitespace "-trailing-space" && - echo "foo (); " > x && + echo "foo (); " >x && git diff --check - ' test_expect_success 'check trailing whitespace (trailing-space: on)' ' - git config core.whitespace "trailing-space" && - echo "foo (); " > x && + echo "foo (); " >x && test_must_fail git diff --check - ' test_expect_success 'check space before tab in indent (space-before-tab: off)' ' - # indent contains space followed by HT git config core.whitespace "-space-before-tab" && - echo " foo ();" > x && + echo " foo ();" >x && git diff --check - ' test_expect_success 'check space before tab in indent (space-before-tab: on)' ' - # indent contains space followed by HT git config core.whitespace "space-before-tab" && - echo " foo (); " > x && + echo " foo (); " >x && test_must_fail git diff --check - ' test_expect_success 'check spaces as indentation (indent-with-non-tab: off)' ' - git config core.whitespace "-indent-with-non-tab" && - echo " foo ();" > x && + echo " foo ();" >x && git diff --check - ' test_expect_success 'check spaces as indentation (indent-with-non-tab: on)' ' - git config core.whitespace "indent-with-non-tab" && - echo " foo ();" > x && + echo " foo ();" >x && test_must_fail git diff --check - ' test_expect_success 'ditto, but tabwidth=9' ' - git config core.whitespace "indent-with-non-tab,tabwidth=9" && git diff --check - ' test_expect_success 'check tabs and spaces as indentation (indent-with-non-tab: on)' ' - git config core.whitespace "indent-with-non-tab" && - echo " foo ();" > x && + echo " foo ();" >x && test_must_fail git diff --check - ' test_expect_success 'ditto, but tabwidth=10' ' - git config core.whitespace "indent-with-non-tab,tabwidth=10" && test_must_fail git diff --check - ' test_expect_success 'ditto, but tabwidth=20' ' - git config core.whitespace "indent-with-non-tab,tabwidth=20" && git diff --check - ' test_expect_success 'check tabs as indentation (tab-in-indent: off)' ' - git config core.whitespace "-tab-in-indent" && - echo " foo ();" > x && + echo " foo ();" >x && git diff --check - ' test_expect_success 'check tabs as indentation (tab-in-indent: on)' ' - git config core.whitespace "tab-in-indent" && - echo " foo ();" > x && + echo " foo ();" >x && test_must_fail git diff --check - ' test_expect_success 'check tabs and spaces as indentation (tab-in-indent: on)' ' - git config core.whitespace "tab-in-indent" && - echo " foo ();" > x && + echo " foo ();" >x && test_must_fail git diff --check - ' test_expect_success 'ditto, but tabwidth=1 (must be irrelevant)' ' - git config core.whitespace "tab-in-indent,tabwidth=1" && test_must_fail git diff --check - ' test_expect_success 'check tab-in-indent and indent-with-non-tab conflict' ' - git config core.whitespace "tab-in-indent,indent-with-non-tab" && - echo "foo ();" > x && + echo "foo ();" >x && test_must_fail git diff --check - ' test_expect_success 'check tab-in-indent excluded from wildcard whitespace attribute' ' - git config --unset core.whitespace && - echo "x whitespace" > .gitattributes && - echo " foo ();" > x && + echo "x whitespace" >.gitattributes && + echo " foo ();" >x && git diff --check && rm -f .gitattributes - ' test_expect_success 'line numbers in --check output are correct' ' - - echo "" > x && - echo "foo(); " >> x && + echo "" >x && + echo "foo(); " >>x && git diff --check | grep "x:2:" - ' test_expect_success 'checkdiff detects new trailing blank lines (1)' ' @@ -876,29 +810,127 @@ test_expect_success 'setup diff colors' ' git config color.diff.old red && git config color.diff.new green && git config color.diff.commit yellow && - git config color.diff.whitespace "normal red" && + git config color.diff.whitespace blue && git config core.autocrlf false ' -cat >expected <<\EOF -<BOLD>diff --git a/x b/x<RESET> -<BOLD>index 9daeafb..2874b91 100644<RESET> -<BOLD>--- a/x<RESET> -<BOLD>+++ b/x<RESET> -<CYAN>@@ -1 +1,4 @@<RESET> - test<RESET> -<GREEN>+<RESET><GREEN>{<RESET> -<GREEN>+<RESET><BRED> <RESET> -<GREEN>+<RESET><GREEN>}<RESET> -EOF test_expect_success 'diff that introduces a line with only tabs' ' git config core.whitespace blank-at-eol && git reset --hard && - echo "test" > x && + echo "test" >x && git commit -m "initial" x && - echo "{NTN}" | tr "NT" "\n\t" >> x && + echo "{NTN}" | tr "NT" "\n\t" >>x && git -c color.diff=always diff | test_decode_color >current && + + cat >expected <<-\EOF && + <BOLD>diff --git a/x b/x<RESET> + <BOLD>index 9daeafb..2874b91 100644<RESET> + <BOLD>--- a/x<RESET> + <BOLD>+++ b/x<RESET> + <CYAN>@@ -1 +1,4 @@<RESET> + test<RESET> + <GREEN>+<RESET><GREEN>{<RESET> + <GREEN>+<RESET><BLUE> <RESET> + <GREEN>+<RESET><GREEN>}<RESET> + EOF + + test_cmp expected current +' + +test_expect_success 'diff that introduces and removes ws breakages' ' + git reset --hard && + { + echo "0. blank-at-eol " && + echo "1. blank-at-eol " + } >x && + git commit -a --allow-empty -m preimage && + { + echo "0. blank-at-eol " && + echo "1. still-blank-at-eol " && + echo "2. and a new line " + } >x && + + git -c color.diff=always diff | + test_decode_color >current && + + cat >expected <<-\EOF && + <BOLD>diff --git a/x b/x<RESET> + <BOLD>index d0233a2..700886e 100644<RESET> + <BOLD>--- a/x<RESET> + <BOLD>+++ b/x<RESET> + <CYAN>@@ -1,2 +1,3 @@<RESET> + 0. blank-at-eol <RESET> + <RED>-1. blank-at-eol <RESET> + <GREEN>+<RESET><GREEN>1. still-blank-at-eol<RESET><BLUE> <RESET> + <GREEN>+<RESET><GREEN>2. and a new line<RESET><BLUE> <RESET> + EOF + + test_cmp expected current +' + +test_expect_success 'the same with --ws-error-highlight' ' + git reset --hard && + { + echo "0. blank-at-eol " && + echo "1. blank-at-eol " + } >x && + git commit -a --allow-empty -m preimage && + { + echo "0. blank-at-eol " && + echo "1. still-blank-at-eol " && + echo "2. and a new line " + } >x && + + git -c color.diff=always diff --ws-error-highlight=default,old | + test_decode_color >current && + + cat >expected <<-\EOF && + <BOLD>diff --git a/x b/x<RESET> + <BOLD>index d0233a2..700886e 100644<RESET> + <BOLD>--- a/x<RESET> + <BOLD>+++ b/x<RESET> + <CYAN>@@ -1,2 +1,3 @@<RESET> + 0. blank-at-eol <RESET> + <RED>-<RESET><RED>1. blank-at-eol<RESET><BLUE> <RESET> + <GREEN>+<RESET><GREEN>1. still-blank-at-eol<RESET><BLUE> <RESET> + <GREEN>+<RESET><GREEN>2. and a new line<RESET><BLUE> <RESET> + EOF + + test_cmp expected current && + + git -c color.diff=always diff --ws-error-highlight=all | + test_decode_color >current && + + cat >expected <<-\EOF && + <BOLD>diff --git a/x b/x<RESET> + <BOLD>index d0233a2..700886e 100644<RESET> + <BOLD>--- a/x<RESET> + <BOLD>+++ b/x<RESET> + <CYAN>@@ -1,2 +1,3 @@<RESET> + <RESET>0. blank-at-eol<RESET><BLUE> <RESET> + <RED>-<RESET><RED>1. blank-at-eol<RESET><BLUE> <RESET> + <GREEN>+<RESET><GREEN>1. still-blank-at-eol<RESET><BLUE> <RESET> + <GREEN>+<RESET><GREEN>2. and a new line<RESET><BLUE> <RESET> + EOF + + test_cmp expected current && + + git -c color.diff=always diff --ws-error-highlight=none | + test_decode_color >current && + + cat >expected <<-\EOF && + <BOLD>diff --git a/x b/x<RESET> + <BOLD>index d0233a2..700886e 100644<RESET> + <BOLD>--- a/x<RESET> + <BOLD>+++ b/x<RESET> + <CYAN>@@ -1,2 +1,3 @@<RESET> + 0. blank-at-eol <RESET> + <RED>-1. blank-at-eol <RESET> + <GREEN>+1. still-blank-at-eol <RESET> + <GREEN>+2. and a new line <RESET> + EOF + test_cmp expected current ' diff --git a/t/t4018-diff-funcname.sh b/t/t4018-diff-funcname.sh index 34591c23da..67373dc44e 100755 --- a/t/t4018-diff-funcname.sh +++ b/t/t4018-diff-funcname.sh @@ -31,6 +31,7 @@ diffpatterns=" cpp csharp fortran + fountain html java matlab @@ -52,15 +53,15 @@ do echo "*.java diff=$p" >.gitattributes && test_expect_code 1 git diff --no-index \ A.java B.java 2>msg && - ! test_i18ngrep fatal msg && - ! test_i18ngrep error msg + test_i18ngrep ! fatal msg && + test_i18ngrep ! error msg ' test_expect_success "builtin $p wordRegex pattern compiles" ' echo "*.java diff=$p" >.gitattributes && test_expect_code 1 git diff --no-index --word-diff \ A.java B.java 2>msg && - ! test_i18ngrep fatal msg && - ! test_i18ngrep error msg + test_i18ngrep ! fatal msg && + test_i18ngrep ! error msg ' done diff --git a/t/t4018/fountain-scene b/t/t4018/fountain-scene new file mode 100644 index 0000000000..6b3257d680 --- /dev/null +++ b/t/t4018/fountain-scene @@ -0,0 +1,4 @@ +EXT. STREET RIGHT OUTSIDE - DAY + +CHARACTER +You didn't say the magic phrase, "ChangeMe". diff --git a/t/t4022-diff-rewrite.sh b/t/t4022-diff-rewrite.sh index 2d030a4ec3..cb51d9f9d4 100755 --- a/t/t4022-diff-rewrite.sh +++ b/t/t4022-diff-rewrite.sh @@ -20,10 +20,7 @@ test_expect_success setup ' test_expect_success 'detect rewrite' ' actual=$(git diff-files -B --summary test) && - expr "$actual" : " rewrite test ([0-9]*%)$" || { - echo "Eh? <<$actual>>" - false - } + verbose expr "$actual" : " rewrite test ([0-9]*%)$" ' diff --git a/t/t4023-diff-rename-typechange.sh b/t/t4023-diff-rename-typechange.sh index 55d549fcf4..8c9823765e 100755 --- a/t/t4023-diff-rename-typechange.sh +++ b/t/t4023-diff-rename-typechange.sh @@ -76,7 +76,8 @@ test_expect_success 'moves and renames' ' git diff-tree three four -r --name-status -B -M | sort >actual && { - echo "R100 foo bar" + # see -B -M (#6) in t4008 + echo "C100 foo bar" echo "T100 foo" } | sort >expect && test_cmp expect actual diff --git a/t/t4024-diff-optimize-common.sh b/t/t4024-diff-optimize-common.sh index c4d733f5db..7e76018296 100755 --- a/t/t4024-diff-optimize-common.sh +++ b/t/t4024-diff-optimize-common.sh @@ -139,7 +139,7 @@ test_expect_success setup ' ( printf C; zs $n ) >file-c$n && ( echo D; zs $n ) >file-d$n && - expect_pattern $n || break + expect_pattern $n || return 1 done >expect ' diff --git a/t/t4026-color.sh b/t/t4026-color.sh index 3726a0e201..2b32c4fbe6 100755 --- a/t/t4026-color.sh +++ b/t/t4026-color.sh @@ -45,14 +45,41 @@ test_expect_success 'fg bg attr...' ' color "blue bold dim ul blink reverse" "[1;2;4;5;7;34m" ' +# note that nobold and nodim are the same code (22) +test_expect_success 'attr negation' ' + color "nobold nodim noul noblink noreverse" "[22;24;25;27m" +' + test_expect_success 'long color specification' ' color "254 255 bold dim ul blink reverse" "[1;2;4;5;7;38;5;254;48;5;255m" ' +test_expect_success 'absurdly long color specification' ' + color \ + "#ffffff #ffffff bold nobold dim nodim ul noul blink noblink reverse noreverse" \ + "[1;2;4;5;7;22;24;25;27;38;2;255;255;255;48;2;255;255;255m" +' + +test_expect_success '0-7 are aliases for basic ANSI color names' ' + color "0 7" "[30;47m" +' + test_expect_success '256 colors' ' color "254 bold 255" "[1;38;5;254;48;5;255m" ' +test_expect_success '24-bit colors' ' + color "#ff00ff black" "[38;2;255;0;255;40m" +' + +test_expect_success '"normal" yields no color at all"' ' + color "normal black" "[40m" +' + +test_expect_success '-1 is a synonym for "normal"' ' + color "-1 black" "[40m" +' + test_expect_success 'color too small' ' invalid_color "-2" ' @@ -84,9 +111,9 @@ test_expect_success 'unknown color slots are ignored (branch)' ' ' test_expect_success 'unknown color slots are ignored (status)' ' - git config color.status.nosuchslotwilleverbedefined white || exit - git status - case $? in 0|1) : ok ;; *) false ;; esac + git config color.status.nosuchslotwilleverbedefined white && + { git status; ret=$?; } && + case $ret in 0|1) : ok ;; *) false ;; esac ' test_done diff --git a/t/t4035-diff-quiet.sh b/t/t4035-diff-quiet.sh index e8ae2a03fd..461f4bb583 100755 --- a/t/t4035-diff-quiet.sh +++ b/t/t4035-diff-quiet.sh @@ -29,67 +29,65 @@ test_expect_success 'setup' ' ' test_expect_success 'git diff-tree HEAD^ HEAD' ' - git diff-tree --quiet HEAD^ HEAD >cnt - test $? = 1 && test_line_count = 0 cnt + test_expect_code 1 git diff-tree --quiet HEAD^ HEAD >cnt && + test_line_count = 0 cnt ' test_expect_success 'git diff-tree HEAD^ HEAD -- a' ' - git diff-tree --quiet HEAD^ HEAD -- a >cnt - test $? = 0 && test_line_count = 0 cnt + test_expect_code 0 git diff-tree --quiet HEAD^ HEAD -- a >cnt && + test_line_count = 0 cnt ' test_expect_success 'git diff-tree HEAD^ HEAD -- b' ' - git diff-tree --quiet HEAD^ HEAD -- b >cnt - test $? = 1 && test_line_count = 0 cnt + test_expect_code 1 git diff-tree --quiet HEAD^ HEAD -- b >cnt && + test_line_count = 0 cnt ' # this diff outputs one line: sha1 of the given head test_expect_success 'echo HEAD | git diff-tree --stdin' ' - echo $(git rev-parse HEAD) | git diff-tree --quiet --stdin >cnt - test $? = 1 && test_line_count = 1 cnt + echo $(git rev-parse HEAD) | + test_expect_code 1 git diff-tree --quiet --stdin >cnt && + test_line_count = 1 cnt ' test_expect_success 'git diff-tree HEAD HEAD' ' - git diff-tree --quiet HEAD HEAD >cnt - test $? = 0 && test_line_count = 0 cnt + test_expect_code 0 git diff-tree --quiet HEAD HEAD >cnt && + test_line_count = 0 cnt ' test_expect_success 'git diff-files' ' - git diff-files --quiet >cnt - test $? = 0 && test_line_count = 0 cnt + test_expect_code 0 git diff-files --quiet >cnt && + test_line_count = 0 cnt ' test_expect_success 'git diff-index --cached HEAD' ' - git diff-index --quiet --cached HEAD >cnt - test $? = 0 && test_line_count = 0 cnt + test_expect_code 0 git diff-index --quiet --cached HEAD >cnt && + test_line_count = 0 cnt ' test_expect_success 'git diff-index --cached HEAD^' ' - git diff-index --quiet --cached HEAD^ >cnt - test $? = 1 && test_line_count = 0 cnt + test_expect_code 1 git diff-index --quiet --cached HEAD^ >cnt && + test_line_count = 0 cnt ' test_expect_success 'git diff-index --cached HEAD^' ' echo text >>b && echo 3 >c && - git add . && { - git diff-index --quiet --cached HEAD^ >cnt - test $? = 1 && test_line_count = 0 cnt - } + git add . && + test_expect_code 1 git diff-index --quiet --cached HEAD^ >cnt && + test_line_count = 0 cnt ' test_expect_success 'git diff-tree -Stext HEAD^ HEAD -- b' ' - git commit -m "text in b" && { - git diff-tree --quiet -Stext HEAD^ HEAD -- b >cnt - test $? = 1 && test_line_count = 0 cnt - } + git commit -m "text in b" && + test_expect_code 1 git diff-tree --quiet -Stext HEAD^ HEAD -- b >cnt && + test_line_count = 0 cnt ' test_expect_success 'git diff-tree -Snot-found HEAD^ HEAD -- b' ' - git diff-tree --quiet -Snot-found HEAD^ HEAD -- b >cnt - test $? = 0 && test_line_count = 0 cnt + test_expect_code 0 git diff-tree --quiet -Snot-found HEAD^ HEAD -- b >cnt && + test_line_count = 0 cnt ' test_expect_success 'git diff-files' ' - echo 3 >>c && { - git diff-files --quiet >cnt - test $? = 1 && test_line_count = 0 cnt - } + echo 3 >>c && + test_expect_code 1 git diff-files --quiet >cnt && + test_line_count = 0 cnt ' + test_expect_success 'git diff-index --cached HEAD' ' - git update-index c && { - git diff-index --quiet --cached HEAD >cnt - test $? = 1 && test_line_count = 0 cnt - } + git update-index c && + test_expect_code 1 git diff-index --quiet --cached HEAD >cnt && + test_line_count = 0 cnt ' test_expect_success 'git diff, one file outside repo' ' diff --git a/t/t4036-format-patch-signer-mime.sh b/t/t4036-format-patch-signer-mime.sh index ba43f18549..98d9713d8b 100755 --- a/t/t4036-format-patch-signer-mime.sh +++ b/t/t4036-format-patch-signer-mime.sh @@ -42,7 +42,7 @@ test_expect_success 'attach and signoff do not duplicate mime headers' ' GIT_COMMITTER_NAME="はまの ふにおう" \ git format-patch -s --stdout -1 --attach >output && - test `grep -ci ^MIME-Version: output` = 1 + test $(grep -ci ^MIME-Version: output) = 1 ' diff --git a/t/t4038-diff-combined.sh b/t/t4038-diff-combined.sh index 1019d7b35f..0b4f7dfdc6 100755 --- a/t/t4038-diff-combined.sh +++ b/t/t4038-diff-combined.sh @@ -94,7 +94,7 @@ test_expect_success 'setup for --cc --raw' ' blob=$(echo file | git hash-object --stdin -w) && base_tree=$(echo "100644 blob $blob file" | git mktree) && trees= && - for i in `test_seq 1 40` + for i in $(test_seq 1 40) do blob=$(echo file$i | git hash-object --stdin -w) && trees="$trees$(echo "100644 blob $blob file" | git mktree)$LF" @@ -401,4 +401,38 @@ test_expect_success 'combine diff missing delete bug' ' compare_diff_patch expected actual ' +test_expect_success 'combine diff gets tree sorting right' ' + # create a directory and a file that sort differently in trees + # versus byte-wise (implied "/" sorts after ".") + git checkout -f master && + mkdir foo && + echo base >foo/one && + echo base >foo/two && + echo base >foo.ext && + git add foo foo.ext && + git commit -m base && + + # one side modifies a file in the directory, along with the root + # file... + echo master >foo/one && + echo master >foo.ext && + git commit -a -m master && + + # the other side modifies the other file in the directory + git checkout -b other HEAD^ && + echo other >foo/two && + git commit -a -m other && + + # And now we merge. The files in the subdirectory will resolve cleanly, + # meaning that a combined diff will not find them interesting. But it + # will find the tree itself interesting, because it had to be merged. + git checkout master && + git merge other && + + printf "MM\tfoo\n" >expect && + git diff-tree -c --name-status -t HEAD >actual.tmp && + sed 1d <actual.tmp >actual && + test_cmp expect actual +' + test_done diff --git a/t/t4041-diff-submodule-option.sh b/t/t4041-diff-submodule-option.sh index 463d63bde0..2d9731b52d 100755 --- a/t/t4041-diff-submodule-option.sh +++ b/t/t4041-diff-submodule-option.sh @@ -26,8 +26,10 @@ add_file () { echo "$name" >"$name" && git add "$name" && test_tick && - msg_added_iso88591=$(echo "Add $name ($added $name)" | iconv -f utf-8 -t $test_encoding) && - git -c "i18n.commitEncoding=$test_encoding" commit -m "$msg_added_iso88591" + # "git commit -m" would break MinGW, as Windows refuse to pass + # $test_encoding encoded parameter to git. + echo "Add $name ($added $name)" | iconv -f utf-8 -t $test_encoding | + git -c "i18n.commitEncoding=$test_encoding" commit -F - done >/dev/null && git rev-parse --short --verify HEAD ) @@ -526,10 +528,12 @@ test_expect_success 'diff --submodule with objects referenced by alternates' ' sha1_before=$(git rev-parse --short HEAD) echo b >b && git add b && - git commit -m b - sha1_after=$(git rev-parse --short HEAD) - echo "Submodule sub $sha1_before..$sha1_after: - > b" >../expected + git commit -m b && + sha1_after=$(git rev-parse --short HEAD) && + { + echo "Submodule sub $sha1_before..$sha1_after:" && + echo " > b" + } >../expected ) && (cd super && (cd sub && @@ -537,7 +541,7 @@ test_expect_success 'diff --submodule with objects referenced by alternates' ' git checkout origin/master ) && git diff --submodule > ../actual - ) + ) && test_cmp expected actual ' diff --git a/t/t4046-diff-unmerged.sh b/t/t4046-diff-unmerged.sh index 25d50a654a..d0f14475ca 100755 --- a/t/t4046-diff-unmerged.sh +++ b/t/t4046-diff-unmerged.sh @@ -8,7 +8,7 @@ test_expect_success setup ' do blob=$(echo $i | git hash-object --stdin) && eval "blob$i=$blob" && - eval "m$i=\"100644 \$blob$i $i\"" || break + eval "m$i=\"100644 \$blob$i $i\"" || return 1 done && paths= && for b in o x @@ -24,9 +24,9 @@ test_expect_success setup ' case "$b" in x) echo "$m1$p" ;; esac && case "$o" in x) echo "$m2$p" ;; esac && case "$t" in x) echo "$m3$p" ;; esac || - break - done || break - done || break + return 1 + done + done done >ls-files-s.expect && git update-index --index-info <ls-files-s.expect && git ls-files -s >ls-files-s.actual && diff --git a/t/t4047-diff-dirstat.sh b/t/t4047-diff-dirstat.sh index ed7e093366..3b8b7921d6 100755 --- a/t/t4047-diff-dirstat.sh +++ b/t/t4047-diff-dirstat.sh @@ -374,7 +374,7 @@ test_expect_success 'later options override earlier options:' ' git diff --dirstat=files,10,cumulative,changes,noncumulative,3 -M HEAD^..HEAD >actual_diff_dirstat_M && test_cmp expect_diff_dirstat_M actual_diff_dirstat_M && git diff --dirstat=files,10,cumulative,changes,noncumulative,3 -C -C HEAD^..HEAD >actual_diff_dirstat_CC && - test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC + test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC && git diff --dirstat=files --dirstat=10 --dirstat=cumulative --dirstat=changes --dirstat=noncumulative -X3 HEAD^..HEAD >actual_diff_dirstat && test_cmp expect_diff_dirstat actual_diff_dirstat && git diff --dirstat=files --dirstat=10 --dirstat=cumulative --dirstat=changes --dirstat=noncumulative -X3 -M HEAD^..HEAD >actual_diff_dirstat_M && @@ -973,4 +973,18 @@ test_expect_success 'diff.dirstat=future_param,0,lines should warn, but still wo test_i18ngrep -q "diff\\.dirstat" actual_error ' +test_expect_success '--shortstat --dirstat should output only one dirstat' ' + git diff --shortstat --dirstat=changes HEAD^..HEAD >out && + grep " dst/copy/changed/$" out >actual_diff_shortstat_dirstat_changes && + test_line_count = 1 actual_diff_shortstat_dirstat_changes && + + git diff --shortstat --dirstat=lines HEAD^..HEAD >out && + grep " dst/copy/changed/$" out >actual_diff_shortstat_dirstat_lines && + test_line_count = 1 actual_diff_shortstat_dirstat_lines && + + git diff --shortstat --dirstat=files HEAD^..HEAD >out && + grep " dst/copy/changed/$" out >actual_diff_shortstat_dirstat_files && + test_line_count = 1 actual_diff_shortstat_dirstat_files +' + test_done diff --git a/t/t4049-diff-stat-count.sh b/t/t4049-diff-stat-count.sh index 5b594e878f..a34121740a 100755 --- a/t/t4049-diff-stat-count.sh +++ b/t/t4049-diff-stat-count.sh @@ -18,7 +18,7 @@ test_expect_success 'mode-only change show as a 0-line change' ' test_chmod +x b d && echo a >a && echo c >c && - cat >expect <<-\EOF + cat >expect <<-\EOF && a | 1 + b | 0 ... @@ -33,7 +33,7 @@ test_expect_success 'binary changes do not count in lines' ' echo a >a && echo c >c && cat "$TEST_DIRECTORY"/test-binary-1.png >d && - cat >expect <<-\EOF + cat >expect <<-\EOF && a | 1 + c | 1 + ... @@ -55,7 +55,7 @@ test_expect_success 'exclude unmerged entries from total file count' ' done | git update-index --index-info && echo d >d && - cat >expect <<-\EOF + cat >expect <<-\EOF && a | 1 + b | 1 + ... diff --git a/t/t4052-stat-output.sh b/t/t4052-stat-output.sh index b68afefa3c..9f563db20a 100755 --- a/t/t4052-stat-output.sh +++ b/t/t4052-stat-output.sh @@ -94,15 +94,15 @@ EOF while read verb expect cmd args do test_expect_success "$cmd $verb COLUMNS (big change)" ' - COLUMNS=200 git $cmd $args >output + COLUMNS=200 git $cmd $args >output && grep " | " output >actual && test_cmp "$expect" actual ' - test "$cmd" != diff || continue + case "$cmd" in diff|show) continue;; esac test_expect_success "$cmd --graph $verb COLUMNS (big change)" ' - COLUMNS=200 git $cmd $args --graph >output + COLUMNS=200 git $cmd $args --graph >output && grep " | " output >actual && test_cmp "$expect-graph" actual ' @@ -122,15 +122,15 @@ EOF while read verb expect cmd args do test_expect_success "$cmd $verb not enough COLUMNS (big change)" ' - COLUMNS=40 git $cmd $args >output + COLUMNS=40 git $cmd $args >output && grep " | " output >actual && test_cmp "$expect" actual ' - test "$cmd" != diff || continue + case "$cmd" in diff|show) continue;; esac test_expect_success "$cmd --graph $verb not enough COLUMNS (big change)" ' - COLUMNS=40 git $cmd $args --graph >output + COLUMNS=40 git $cmd $args --graph >output && grep " | " output >actual && test_cmp "$expect-graph" actual ' @@ -150,15 +150,15 @@ EOF while read verb expect cmd args do test_expect_success "$cmd $verb statGraphWidth config" ' - git -c diff.statGraphWidth=26 $cmd $args >output + git -c diff.statGraphWidth=26 $cmd $args >output && grep " | " output >actual && test_cmp "$expect" actual ' - test "$cmd" != diff || continue + case "$cmd" in diff|show) continue;; esac test_expect_success "$cmd --graph $verb statGraphWidth config" ' - git -c diff.statGraphWidth=26 $cmd $args --graph >output + git -c diff.statGraphWidth=26 $cmd $args --graph >output && grep " | " output >actual && test_cmp "$expect-graph" actual ' @@ -179,33 +179,33 @@ EOF while read cmd args do test_expect_success "$cmd --stat=width with big change" ' - git $cmd $args --stat=40 >output + git $cmd $args --stat=40 >output && grep " | " output >actual && test_cmp expect actual ' test_expect_success "$cmd --stat-width=width with big change" ' - git $cmd $args --stat-width=40 >output + git $cmd $args --stat-width=40 >output && grep " | " output >actual && test_cmp expect actual ' test_expect_success "$cmd --stat-graph-width with big change" ' - git $cmd $args --stat-graph-width=26 >output + git $cmd $args --stat-graph-width=26 >output && grep " | " output >actual && test_cmp expect actual ' - test "$cmd" != diff || continue + case "$cmd" in diff|show) continue;; esac test_expect_success "$cmd --stat-width=width --graph with big change" ' - git $cmd $args --stat-width=40 --graph >output + git $cmd $args --stat-width=40 --graph >output && grep " | " output >actual && test_cmp expect-graph actual ' test_expect_success "$cmd --stat-graph-width --graph with big change" ' - git $cmd $args --stat-graph-width=26 --graph >output + git $cmd $args --stat-graph-width=26 --graph >output && grep " | " output >actual && test_cmp expect-graph actual ' @@ -236,7 +236,7 @@ do test_cmp expect actual ' - test "$cmd" != diff || continue + case "$cmd" in diff|show) continue;; esac test_expect_success "$cmd --stat=width --graph with big change is balanced" ' git $cmd $args --stat-width=60 --graph >output && @@ -265,15 +265,15 @@ EOF while read verb expect cmd args do test_expect_success "$cmd $verb COLUMNS (long filename)" ' - COLUMNS=200 git $cmd $args >output + COLUMNS=200 git $cmd $args >output && grep " | " output >actual && test_cmp "$expect" actual ' - test "$cmd" != diff || continue + case "$cmd" in diff|show) continue;; esac test_expect_success "$cmd --graph $verb COLUMNS (long filename)" ' - COLUMNS=200 git $cmd $args --graph >output + COLUMNS=200 git $cmd $args --graph >output && grep " | " output >actual && test_cmp "$expect-graph" actual ' @@ -294,16 +294,16 @@ while read verb expect cmd args do test_expect_success COLUMNS_CAN_BE_1 \ "$cmd $verb prefix greater than COLUMNS (big change)" ' - COLUMNS=1 git $cmd $args >output + COLUMNS=1 git $cmd $args >output && grep " | " output >actual && test_cmp "$expect" actual ' - test "$cmd" != diff || continue + case "$cmd" in diff|show) continue;; esac test_expect_success COLUMNS_CAN_BE_1 \ "$cmd --graph $verb prefix greater than COLUMNS (big change)" ' - COLUMNS=1 git $cmd $args --graph >output + COLUMNS=1 git $cmd $args --graph >output && grep " | " output >actual && test_cmp "$expect-graph" actual ' @@ -320,7 +320,7 @@ EOF test_expect_success 'merge --stat respects COLUMNS (big change)' ' git checkout -b branch HEAD^^ && COLUMNS=100 git merge --stat --no-ff master^ >output && - grep " | " output >actual + grep " | " output >actual && test_cmp expect actual ' @@ -329,7 +329,7 @@ cat >expect <<'EOF' EOF test_expect_success 'merge --stat respects COLUMNS (long filename)' ' COLUMNS=100 git merge --stat --no-ff master >output && - grep " | " output >actual + grep " | " output >actual && test_cmp expect actual ' diff --git a/t/t4053-diff-no-index.sh b/t/t4053-diff-no-index.sh index 2ab3c48734..6eb83211b5 100755 --- a/t/t4053-diff-no-index.sh +++ b/t/t4053-diff-no-index.sh @@ -17,8 +17,8 @@ test_expect_success 'setup' ' ' test_expect_success 'git diff --no-index directories' ' - git diff --no-index a b >cnt - test $? = 1 && test_line_count = 14 cnt + test_expect_code 1 git diff --no-index a b >cnt && + test_line_count = 14 cnt ' test_expect_success 'git diff --no-index relative path outside repo' ' @@ -55,4 +55,38 @@ test_expect_success 'git diff --no-index executed outside repo gives correct err ) ' +test_expect_success 'diff D F and diff F D' ' + ( + cd repo && + echo in-repo >a && + echo non-repo >../non/git/a && + mkdir sub && + echo sub-repo >sub/a && + + test_must_fail git diff --no-index sub/a ../non/git/a >expect && + test_must_fail git diff --no-index sub/a ../non/git/ >actual && + test_cmp expect actual && + + test_must_fail git diff --no-index a ../non/git/a >expect && + test_must_fail git diff --no-index a ../non/git/ >actual && + test_cmp expect actual && + + test_must_fail git diff --no-index ../non/git/a a >expect && + test_must_fail git diff --no-index ../non/git a >actual && + test_cmp expect actual + ) +' + +test_expect_success 'turning a file into a directory' ' + ( + cd non/git && + mkdir d e e/sub && + echo 1 >d/sub && + echo 2 >e/sub/file && + printf "D\td/sub\nA\te/sub/file\n" >expect && + test_must_fail git diff --no-index --name-status d e >actual && + test_cmp expect actual + ) +' + test_done diff --git a/t/t4054-diff-bogus-tree.sh b/t/t4054-diff-bogus-tree.sh index 0843c87890..1d6efab3c5 100755 --- a/t/t4054-diff-bogus-tree.sh +++ b/t/t4054-diff-bogus-tree.sh @@ -16,7 +16,7 @@ test_expect_success 'create bogus tree' ' test_expect_success 'create tree with matching file' ' echo bar >foo && git add foo && - good_tree=$(git write-tree) + good_tree=$(git write-tree) && blob=$(git rev-parse :foo) ' diff --git a/t/t4055-diff-context.sh b/t/t4055-diff-context.sh index cd0454356a..741e0803c1 100755 --- a/t/t4055-diff-context.sh +++ b/t/t4055-diff-context.sh @@ -79,7 +79,7 @@ test_expect_success 'non-integer config parsing' ' test_expect_success 'negative integer config parsing' ' git config diff.context -1 && test_must_fail git diff 2>output && - test_i18ngrep "bad config file" output + test_i18ngrep "bad config variable" output ' test_expect_success '-U0 is valid, so is diff.context=0' ' diff --git a/t/t4056-diff-order.sh b/t/t4056-diff-order.sh index c0460bb0e5..43dd474a12 100755 --- a/t/t4056-diff-order.sh +++ b/t/t4056-diff-order.sh @@ -68,6 +68,12 @@ test_expect_success POSIXPERM,SANITY 'unreadable orderfile' ' test_must_fail git diff -Ounreadable_file --name-only HEAD^..HEAD ' +test_expect_success "orderfile using option from subdir with --output" ' + mkdir subdir && + git -C subdir diff -O../order_file_1 --output ../actual --name-only HEAD^..HEAD && + test_cmp expect_1 actual +' + for i in 1 2 do test_expect_success "orderfile using option ($i)" ' diff --git a/t/t4057-diff-combined-paths.sh b/t/t4057-diff-combined-paths.sh index 097e63215e..dff36b77ec 100755 --- a/t/t4057-diff-combined-paths.sh +++ b/t/t4057-diff-combined-paths.sh @@ -5,7 +5,7 @@ test_description='combined diff show only paths that are different to all parent . ./test-lib.sh # verify that diffc.expect matches output of -# `git diff -c --name-only HEAD HEAD^ HEAD^2` +# $(git diff -c --name-only HEAD HEAD^ HEAD^2) diffc_verify () { git diff -c --name-only HEAD HEAD^ HEAD^2 >diffc.actual && test_cmp diffc.expect diffc.actual diff --git a/t/t4058-diff-duplicates.sh b/t/t4058-diff-duplicates.sh new file mode 100755 index 0000000000..0a23242cb6 --- /dev/null +++ b/t/t4058-diff-duplicates.sh @@ -0,0 +1,79 @@ +#!/bin/sh + +test_description='test tree diff when trees have duplicate entries' +. ./test-lib.sh + +# make_tree_entry <mode> <mode> <sha1> +# +# We have to rely on perl here because not all printfs understand +# hex escapes (only octal), and xxd is not portable. +make_tree_entry () { + printf '%s %s\0' "$1" "$2" && + perl -e 'print chr(hex($_)) for ($ARGV[0] =~ /../g)' "$3" +} + +# Like git-mktree, but without all of the pesky sanity checking. +# Arguments come in groups of three, each group specifying a single +# tree entry (see make_tree_entry above). +make_tree () { + while test $# -gt 2; do + make_tree_entry "$1" "$2" "$3" + shift; shift; shift + done | + git hash-object -w -t tree --stdin +} + +# this is kind of a convoluted setup, but matches +# a real-world case. Each tree contains four entries +# for the given path, one with one sha1, and three with +# the other. The first tree has them split across +# two subtrees (which are themselves duplicate entries in +# the root tree), and the second has them all in a single subtree. +test_expect_success 'create trees with duplicate entries' ' + blob_one=$(echo one | git hash-object -w --stdin) && + blob_two=$(echo two | git hash-object -w --stdin) && + inner_one_a=$(make_tree \ + 100644 inner $blob_one + ) && + inner_one_b=$(make_tree \ + 100644 inner $blob_two \ + 100644 inner $blob_two \ + 100644 inner $blob_two + ) && + outer_one=$(make_tree \ + 040000 outer $inner_one_a \ + 040000 outer $inner_one_b + ) && + inner_two=$(make_tree \ + 100644 inner $blob_one \ + 100644 inner $blob_two \ + 100644 inner $blob_two \ + 100644 inner $blob_two + ) && + outer_two=$(make_tree \ + 040000 outer $inner_two + ) && + git tag one $outer_one && + git tag two $outer_two +' + +test_expect_success 'diff-tree between trees' ' + { + printf ":000000 100644 $_z40 $blob_two A\touter/inner\n" && + printf ":000000 100644 $_z40 $blob_two A\touter/inner\n" && + printf ":000000 100644 $_z40 $blob_two A\touter/inner\n" && + printf ":100644 000000 $blob_two $_z40 D\touter/inner\n" && + printf ":100644 000000 $blob_two $_z40 D\touter/inner\n" && + printf ":100644 000000 $blob_two $_z40 D\touter/inner\n" + } >expect && + git diff-tree -r --no-abbrev one two >actual && + test_cmp expect actual +' + +test_expect_success 'diff-tree with renames' ' + # same expectation as above, since we disable rename detection + git diff-tree -M -r --no-abbrev one two >actual && + test_cmp expect actual +' + +test_done diff --git a/t/t4102-apply-rename.sh b/t/t4102-apply-rename.sh index 49e2d6c349..fae305979a 100755 --- a/t/t4102-apply-rename.sh +++ b/t/t4102-apply-rename.sh @@ -52,6 +52,6 @@ EOF test_expect_success 'apply copy' \ 'git apply --index --stat --summary --apply test-patch && - test "$(cat bar)" = "This is bar" -a "$(cat foo)" = "This is foo"' + test "$(cat bar)" = "This is bar" && test "$(cat foo)" = "This is foo"' test_done diff --git a/t/t4104-apply-boundary.sh b/t/t4104-apply-boundary.sh index c617c2a33d..32e3b0ee0b 100755 --- a/t/t4104-apply-boundary.sh +++ b/t/t4104-apply-boundary.sh @@ -18,7 +18,7 @@ test_expect_success setup ' cat victim >original && git update-index --add victim && - : add to the head + # add to the head for i in a b '"$L"' y do echo $i @@ -27,7 +27,7 @@ test_expect_success setup ' git diff victim >add-a-patch.with && git diff --unified=0 >add-a-patch.without && - : insert at line two + # insert at line two for i in b a '"$L"' y do echo $i @@ -36,7 +36,7 @@ test_expect_success setup ' git diff victim >insert-a-patch.with && git diff --unified=0 >insert-a-patch.without && - : modify at the head + # modify at the head for i in a '"$L"' y do echo $i @@ -45,16 +45,16 @@ test_expect_success setup ' git diff victim >mod-a-patch.with && git diff --unified=0 >mod-a-patch.without && - : remove from the head + # remove from the head for i in '"$L"' y do echo $i done >victim && cat victim >del-a-expect && - git diff victim >del-a-patch.with + git diff victim >del-a-patch.with && git diff --unified=0 >del-a-patch.without && - : add to the tail + # add to the tail for i in b '"$L"' y z do echo $i @@ -63,7 +63,7 @@ test_expect_success setup ' git diff victim >add-z-patch.with && git diff --unified=0 >add-z-patch.without && - : modify at the tail + # modify at the tail for i in b '"$L"' z do echo $i @@ -72,16 +72,16 @@ test_expect_success setup ' git diff victim >mod-z-patch.with && git diff --unified=0 >mod-z-patch.without && - : remove from the tail + # remove from the tail for i in b '"$L"' do echo $i done >victim && cat victim >del-z-expect && - git diff victim >del-z-patch.with - git diff --unified=0 >del-z-patch.without && + git diff victim >del-z-patch.with && + git diff --unified=0 >del-z-patch.without - : done + # done ' for with in with without @@ -95,10 +95,7 @@ do test_expect_success "apply $kind-patch $with context" ' cat original >victim && git update-index victim && - git apply --index '"$u$kind-patch.$with"' || { - cat '"$kind-patch.$with"' - (exit 1) - } && + git apply --index '"$u$kind-patch.$with"' && test_cmp '"$kind"'-expect victim ' done @@ -113,10 +110,7 @@ do test_expect_success "apply non-git $kind-patch without context" ' cat original >victim && git update-index victim && - git apply --unidiff-zero --index '"$kind-ng.without"' || { - cat '"$kind-ng.without"' - (exit 1) - } && + git apply --unidiff-zero --index '"$kind-ng.without"' && test_cmp '"$kind"'-expect victim ' done diff --git a/t/t4116-apply-reverse.sh b/t/t4116-apply-reverse.sh index 1e4d4380bf..ce8567f496 100755 --- a/t/t4116-apply-reverse.sh +++ b/t/t4116-apply-reverse.sh @@ -30,10 +30,10 @@ test_expect_success setup ' test_expect_success 'apply in forward' ' - T0=`git rev-parse "second^{tree}"` && + T0=$(git rev-parse "second^{tree}") && git reset --hard initial && git apply --index --binary patch && - T1=`git write-tree` && + T1=$(git write-tree) && test "$T0" = "$T1" ' @@ -62,22 +62,22 @@ test_expect_success 'setup separate repository lacking postimage' ' test_expect_success 'apply in forward without postimage' ' - T0=`git rev-parse "second^{tree}"` && + T0=$(git rev-parse "second^{tree}") && ( cd initial && git apply --index --binary ../patch && - T1=`git write-tree` && + T1=$(git write-tree) && test "$T0" = "$T1" ) ' test_expect_success 'apply in reverse without postimage' ' - T0=`git rev-parse "initial^{tree}"` && + T0=$(git rev-parse "initial^{tree}") && ( cd second && git apply --index --binary --reverse ../patch && - T1=`git write-tree` && + T1=$(git write-tree) && test "$T0" = "$T1" ) ' diff --git a/t/t4117-apply-reject.sh b/t/t4117-apply-reject.sh index 8e15ecbdfd..d80187de94 100755 --- a/t/t4117-apply-reject.sh +++ b/t/t4117-apply-reject.sh @@ -56,23 +56,13 @@ test_expect_success 'apply --reject is incompatible with --3way' ' test_expect_success 'apply without --reject should fail' ' - if git apply patch.1 - then - echo "Eh? Why?" - exit 1 - fi - + test_must_fail git apply patch.1 && test_cmp file1 saved.file1 ' test_expect_success 'apply without --reject should fail' ' - if git apply --verbose patch.1 - then - echo "Eh? Why?" - exit 1 - fi - + test_must_fail git apply --verbose patch.1 && test_cmp file1 saved.file1 ' @@ -81,21 +71,11 @@ test_expect_success 'apply with --reject should fail but update the file' ' cat saved.file1 >file1 && rm -f file1.rej file2.rej && - if git apply --reject patch.1 - then - echo "succeeds with --reject?" - exit 1 - fi - + test_must_fail git apply --reject patch.1 && test_cmp file1 expected && cat file1.rej && - - if test -f file2.rej - then - echo "file2 should not have been touched" - exit 1 - fi + test_path_is_missing file2.rej ' test_expect_success 'apply with --reject should fail but update the file' ' @@ -103,25 +83,12 @@ test_expect_success 'apply with --reject should fail but update the file' ' cat saved.file1 >file1 && rm -f file1.rej file2.rej file2 && - if git apply --reject patch.2 >rejects - then - echo "succeeds with --reject?" - exit 1 - fi - - test -f file1 && { - echo "file1 still exists?" - exit 1 - } + test_must_fail git apply --reject patch.2 >rejects && + test_path_is_missing file1 && test_cmp file2 expected && cat file2.rej && - - if test -f file1.rej - then - echo "file2 should not have been touched" - exit 1 - fi + test_path_is_missing file1.rej ' @@ -130,25 +97,12 @@ test_expect_success 'the same test with --verbose' ' cat saved.file1 >file1 && rm -f file1.rej file2.rej file2 && - if git apply --reject --verbose patch.2 >rejects - then - echo "succeeds with --reject?" - exit 1 - fi - - test -f file1 && { - echo "file1 still exists?" - exit 1 - } + test_must_fail git apply --reject --verbose patch.2 >rejects && + test_path_is_missing file1 && test_cmp file2 expected && cat file2.rej && - - if test -f file1.rej - then - echo "file2 should not have been touched" - exit 1 - fi + test_path_is_missing file1.rej ' diff --git a/t/t4119-apply-config.sh b/t/t4119-apply-config.sh index 3d0384daa8..a9a0583811 100755 --- a/t/t4119-apply-config.sh +++ b/t/t4119-apply-config.sh @@ -68,7 +68,7 @@ test_expect_success 'apply --whitespace=strip from config' ' check_result sub/file1 ' -D=`pwd` +D=$(pwd) test_expect_success 'apply --whitespace=strip in subdir' ' @@ -159,4 +159,21 @@ test_expect_success 'same but with traditional patch input of depth 2' ' check_result sub/file1 ' +test_expect_success 'in subdir with traditional patch input' ' + cd "$D" && + git config apply.whitespace strip && + cat >.gitattributes <<-EOF && + /* whitespace=blank-at-eol + sub/* whitespace=-blank-at-eol + EOF + rm -f sub/file1 && + cp saved sub/file1 && + git update-index --refresh && + + cd sub && + git apply ../gpatch.file && + echo "B " >expect && + test_cmp expect file1 +' + test_done diff --git a/t/t4122-apply-symlink-inside.sh b/t/t4122-apply-symlink-inside.sh index 70b3a06e1d..4acb3f336e 100755 --- a/t/t4122-apply-symlink-inside.sh +++ b/t/t4122-apply-symlink-inside.sh @@ -3,17 +3,10 @@ test_description='apply to deeper directory without getting fooled with symlink' . ./test-lib.sh -lecho () { - for l_ - do - echo "$l_" - done -} - test_expect_success setup ' mkdir -p arch/i386/boot arch/x86_64 && - lecho 1 2 3 4 5 >arch/i386/boot/Makefile && + test_write_lines 1 2 3 4 5 >arch/i386/boot/Makefile && test_ln_s_add ../i386/boot arch/x86_64/boot && git add . && test_tick && @@ -22,7 +15,7 @@ test_expect_success setup ' rm arch/x86_64/boot && mkdir arch/x86_64/boot && - lecho 2 3 4 5 6 >arch/x86_64/boot/Makefile && + test_write_lines 2 3 4 5 6 >arch/x86_64/boot/Makefile && git add . && test_tick && git commit -a -m second && @@ -52,4 +45,110 @@ test_expect_success 'check result' ' ' +test_expect_success SYMLINKS 'do not read from beyond symbolic link' ' + git reset --hard && + mkdir -p arch/x86_64/dir && + >arch/x86_64/dir/file && + git add arch/x86_64/dir/file && + echo line >arch/x86_64/dir/file && + git diff >patch && + git reset --hard && + + mkdir arch/i386/dir && + >arch/i386/dir/file && + ln -s ../i386/dir arch/x86_64/dir && + + test_must_fail git apply patch && + test_must_fail git apply --cached patch && + test_must_fail git apply --index patch + +' + +test_expect_success SYMLINKS 'do not follow symbolic link (setup)' ' + + rm -rf arch/i386/dir arch/x86_64/dir && + git reset --hard && + ln -s ../i386/dir arch/x86_64/dir && + git add arch/x86_64/dir && + git diff HEAD >add_symlink.patch && + git reset --hard && + + mkdir arch/x86_64/dir && + >arch/x86_64/dir/file && + git add arch/x86_64/dir/file && + git diff HEAD >add_file.patch && + git diff -R HEAD >del_file.patch && + git reset --hard && + rm -fr arch/x86_64/dir && + + cat add_symlink.patch add_file.patch >patch && + cat add_symlink.patch del_file.patch >tricky_del && + + mkdir arch/i386/dir +' + +test_expect_success SYMLINKS 'do not follow symbolic link (same input)' ' + + # same input creates a confusing symbolic link + test_must_fail git apply patch 2>error-wt && + test_i18ngrep "beyond a symbolic link" error-wt && + test_path_is_missing arch/x86_64/dir && + test_path_is_missing arch/i386/dir/file && + + test_must_fail git apply --index patch 2>error-ix && + test_i18ngrep "beyond a symbolic link" error-ix && + test_path_is_missing arch/x86_64/dir && + test_path_is_missing arch/i386/dir/file && + test_must_fail git ls-files --error-unmatch arch/x86_64/dir && + test_must_fail git ls-files --error-unmatch arch/i386/dir && + + test_must_fail git apply --cached patch 2>error-ct && + test_i18ngrep "beyond a symbolic link" error-ct && + test_must_fail git ls-files --error-unmatch arch/x86_64/dir && + test_must_fail git ls-files --error-unmatch arch/i386/dir && + + >arch/i386/dir/file && + git add arch/i386/dir/file && + + test_must_fail git apply tricky_del && + test_path_is_file arch/i386/dir/file && + + test_must_fail git apply --index tricky_del && + test_path_is_file arch/i386/dir/file && + test_must_fail git ls-files --error-unmatch arch/x86_64/dir && + git ls-files --error-unmatch arch/i386/dir && + + test_must_fail git apply --cached tricky_del && + test_must_fail git ls-files --error-unmatch arch/x86_64/dir && + git ls-files --error-unmatch arch/i386/dir +' + +test_expect_success SYMLINKS 'do not follow symbolic link (existing)' ' + + # existing symbolic link + git reset --hard && + ln -s ../i386/dir arch/x86_64/dir && + git add arch/x86_64/dir && + + test_must_fail git apply add_file.patch 2>error-wt-add && + test_i18ngrep "beyond a symbolic link" error-wt-add && + test_path_is_missing arch/i386/dir/file && + + mkdir arch/i386/dir && + >arch/i386/dir/file && + test_must_fail git apply del_file.patch 2>error-wt-del && + test_i18ngrep "beyond a symbolic link" error-wt-del && + test_path_is_file arch/i386/dir/file && + rm arch/i386/dir/file && + + test_must_fail git apply --index add_file.patch 2>error-ix-add && + test_i18ngrep "beyond a symbolic link" error-ix-add && + test_path_is_missing arch/i386/dir/file && + test_must_fail git ls-files --error-unmatch arch/i386/dir && + + test_must_fail git apply --cached add_file.patch 2>error-ct-file && + test_i18ngrep "beyond a symbolic link" error-ct-file && + test_must_fail git ls-files --error-unmatch arch/i386/dir +' + test_done diff --git a/t/t4124-apply-ws-rule.sh b/t/t4124-apply-ws-rule.sh index 5d0c598338..d350065f25 100755 --- a/t/t4124-apply-ws-rule.sh +++ b/t/t4124-apply-ws-rule.sh @@ -99,9 +99,8 @@ test_expect_success 'whitespace=warn, default rule' ' test_expect_success 'whitespace=error-all, default rule' ' - apply_patch --whitespace=error-all && return 1 - test -s target && return 1 - : happy + test_must_fail apply_patch --whitespace=error-all && + ! test -s target ' @@ -512,4 +511,15 @@ test_expect_success 'whitespace=fix to expand' ' git -c core.whitespace=tab-in-indent apply --whitespace=fix patch ' +test_expect_success 'whitespace check skipped for excluded paths' ' + git config core.whitespace blank-at-eol && + >used && + >unused && + git add used unused && + echo "used" >used && + echo "unused " >unused && + git diff-files -p used unused >patch && + git apply --include=used --stat --whitespace=error <patch +' + test_done diff --git a/t/t4136-apply-check.sh b/t/t4136-apply-check.sh index a321f7c245..4b0a374b63 100755 --- a/t/t4136-apply-check.sh +++ b/t/t4136-apply-check.sh @@ -16,4 +16,17 @@ test_expect_success 'apply --check exits non-zero with unrecognized input' ' EOF ' +test_expect_success 'apply exits non-zero with no-op patch' ' + cat >input <<-\EOF && + diff --get a/1 b/1 + index 6696ea4..606eddd 100644 + --- a/1 + +++ b/1 + @@ -1,1 +1,1 @@ + 1 + EOF + test_must_fail git apply --stat input && + test_must_fail git apply --check input +' + test_done diff --git a/t/t4137-apply-submodule.sh b/t/t4137-apply-submodule.sh new file mode 100755 index 0000000000..a9bd40a6d0 --- /dev/null +++ b/t/t4137-apply-submodule.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +test_description='git apply handling submodules' + +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-submodule-update.sh + +apply_index () { + git diff --ignore-submodules=dirty "..$1" | git apply --index - +} + +test_submodule_switch "apply_index" + +apply_3way () { + git diff --ignore-submodules=dirty "..$1" | git apply --3way - +} + +test_submodule_switch "apply_3way" + +test_done diff --git a/t/t4138-apply-ws-expansion.sh b/t/t4138-apply-ws-expansion.sh new file mode 100755 index 0000000000..0ffe33fbef --- /dev/null +++ b/t/t4138-apply-ws-expansion.sh @@ -0,0 +1,121 @@ +#!/bin/sh +# +# Copyright (C) 2015 Kyle J. McKay +# + +test_description='git apply test patches with whitespace expansion.' + +. ./test-lib.sh + +test_expect_success setup ' + # + ## create test-N, patchN.patch, expect-N files + # + + # test 1 + printf "\t%s\n" 1 2 3 4 5 6 >before && + printf "\t%s\n" 1 2 3 >after && + printf "%64s\n" a b c >>after && + printf "\t%s\n" 4 5 6 >>after && + git diff --no-index before after | + sed -e "s/before/test-1/" -e "s/after/test-1/" >patch1.patch && + printf "%64s\n" 1 2 3 4 5 6 >test-1 && + printf "%64s\n" 1 2 3 a b c 4 5 6 >expect-1 && + + # test 2 + printf "\t%s\n" a b c d e f >before && + printf "\t%s\n" a b c >after && + n=10 && + x=1 && + while test $x -lt $n + do + printf "%63s%d\n" "" $x >>after + x=$(( $x + 1 )) + done && + printf "\t%s\n" d e f >>after && + git diff --no-index before after | + sed -e "s/before/test-2/" -e "s/after/test-2/" >patch2.patch && + printf "%64s\n" a b c d e f >test-2 && + printf "%64s\n" a b c >expect-2 && + x=1 && + while test $x -lt $n + do + printf "%63s%d\n" "" $x >>expect-2 + x=$(( $x + 1 )) + done && + printf "%64s\n" d e f >>expect-2 && + + # test 3 + printf "\t%s\n" a b c d e f >before && + printf "\t%s\n" a b c >after && + n=100 && + x=0 && + while test $x -lt $n + do + printf "%63s%02d\n" "" $x >>after + x=$(( $x + 1 )) + done && + printf "\t%s\n" d e f >>after && + git diff --no-index before after | + sed -e "s/before/test-3/" -e "s/after/test-3/" >patch3.patch && + printf "%64s\n" a b c d e f >test-3 && + printf "%64s\n" a b c >expect-3 && + x=0 && + while test $x -lt $n + do + printf "%63s%02d\n" "" $x >>expect-3 + x=$(( $x + 1 )) + done && + printf "%64s\n" d e f >>expect-3 && + + # test 4 + >before && + x=0 && + while test $x -lt 50 + do + printf "\t%02d\n" $x >>before + x=$(( $x + 1 )) + done && + cat before >after && + printf "%64s\n" a b c >>after && + while test $x -lt 100 + do + printf "\t%02d\n" $x >>before + printf "\t%02d\n" $x >>after + x=$(( $x + 1 )) + done && + git diff --no-index before after | + sed -e "s/before/test-4/" -e "s/after/test-4/" >patch4.patch && + >test-4 && + x=0 && + while test $x -lt 50 + do + printf "%63s%02d\n" "" $x >>test-4 + x=$(( $x + 1 )) + done && + cat test-4 >expect-4 && + printf "%64s\n" a b c >>expect-4 && + while test $x -lt 100 + do + printf "%63s%02d\n" "" $x >>test-4 + printf "%63s%02d\n" "" $x >>expect-4 + x=$(( $x + 1 )) + done && + + git config core.whitespace tab-in-indent,tabwidth=63 && + git config apply.whitespace fix + +' + +# Note that `patch` can successfully apply all patches when run +# with the --ignore-whitespace option. + +for t in 1 2 3 4 +do + test_expect_success 'apply with ws expansion (t=$t)' ' + git apply patch$t.patch && + test_cmp test-$t expect-$t + ' +done + +test_done diff --git a/t/t4139-apply-escape.sh b/t/t4139-apply-escape.sh new file mode 100755 index 0000000000..45b5660a47 --- /dev/null +++ b/t/t4139-apply-escape.sh @@ -0,0 +1,141 @@ +#!/bin/sh + +test_description='paths written by git-apply cannot escape the working tree' +. ./test-lib.sh + +# tests will try to write to ../foo, and we do not +# want them to escape the trash directory when they +# fail +test_expect_success 'bump git repo one level down' ' + mkdir inside && + mv .git inside/ && + cd inside +' + +# $1 = name of file +# $2 = current path to file (if different) +mkpatch_add () { + rm -f "${2:-$1}" && + cat <<-EOF + diff --git a/$1 b/$1 + new file mode 100644 + index 0000000..53c74cd + --- /dev/null + +++ b/$1 + @@ -0,0 +1 @@ + +evil + EOF +} + +mkpatch_del () { + echo evil >"${2:-$1}" && + cat <<-EOF + diff --git a/$1 b/$1 + deleted file mode 100644 + index 53c74cd..0000000 + --- a/$1 + +++ /dev/null + @@ -1 +0,0 @@ + -evil + EOF +} + +# $1 = name of file +# $2 = content of symlink +mkpatch_symlink () { + rm -f "$1" && + cat <<-EOF + diff --git a/$1 b/$1 + new file mode 120000 + index 0000000..$(printf "%s" "$2" | git hash-object --stdin) + --- /dev/null + +++ b/$1 + @@ -0,0 +1 @@ + +$2 + \ No newline at end of file + EOF +} + +test_expect_success 'cannot create file containing ..' ' + mkpatch_add ../foo >patch && + test_must_fail git apply patch && + test_path_is_missing ../foo +' + +test_expect_success 'can create file containing .. with --unsafe-paths' ' + mkpatch_add ../foo >patch && + git apply --unsafe-paths patch && + test_path_is_file ../foo +' + +test_expect_success 'cannot create file containing .. (index)' ' + mkpatch_add ../foo >patch && + test_must_fail git apply --index patch && + test_path_is_missing ../foo +' + +test_expect_success 'cannot create file containing .. with --unsafe-paths (index)' ' + mkpatch_add ../foo >patch && + test_must_fail git apply --index --unsafe-paths patch && + test_path_is_missing ../foo +' + +test_expect_success 'cannot delete file containing ..' ' + mkpatch_del ../foo >patch && + test_must_fail git apply patch && + test_path_is_file ../foo +' + +test_expect_success 'can delete file containing .. with --unsafe-paths' ' + mkpatch_del ../foo >patch && + git apply --unsafe-paths patch && + test_path_is_missing ../foo +' + +test_expect_success 'cannot delete file containing .. (index)' ' + mkpatch_del ../foo >patch && + test_must_fail git apply --index patch && + test_path_is_file ../foo +' + +test_expect_success SYMLINKS 'symlink escape via ..' ' + { + mkpatch_symlink tmp .. && + mkpatch_add tmp/foo ../foo + } >patch && + test_must_fail git apply patch && + test_path_is_missing tmp && + test_path_is_missing ../foo +' + +test_expect_success SYMLINKS 'symlink escape via .. (index)' ' + { + mkpatch_symlink tmp .. && + mkpatch_add tmp/foo ../foo + } >patch && + test_must_fail git apply --index patch && + test_path_is_missing tmp && + test_path_is_missing ../foo +' + +test_expect_success SYMLINKS 'symlink escape via absolute path' ' + { + mkpatch_symlink tmp "$(pwd)" && + mkpatch_add tmp/foo ../foo + } >patch && + test_must_fail git apply patch && + test_path_is_missing tmp && + test_path_is_missing ../foo +' + +test_expect_success SYMLINKS 'symlink escape via absolute path (index)' ' + { + mkpatch_symlink tmp "$(pwd)" && + mkpatch_add tmp/foo ../foo + } >patch && + test_must_fail git apply --index patch && + test_path_is_missing tmp && + test_path_is_missing ../foo +' + +test_done diff --git a/t/t4150-am.sh b/t/t4150-am.sh index 5edb79a058..b41bd17264 100755 --- a/t/t4150-am.sh +++ b/t/t4150-am.sh @@ -67,6 +67,19 @@ test_expect_success 'setup: messages' ' EOF + cat >scissors-msg <<-\EOF && + Test git-am with scissors line + + This line should be included in the commit message. + EOF + + cat - scissors-msg >no-scissors-msg <<-\EOF && + This line should not be included in the commit message with --scissors enabled. + + - - >8 - - remove everything above this line - - >8 - - + + EOF + signoff="Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" ' @@ -85,6 +98,7 @@ test_expect_success setup ' git format-patch --stdout first >patch1 && { + echo "Message-Id: <1226501681-24923-1-git-send-email-bda@mnsspb.ru>" && echo "X-Fake-Field: Line One" && echo "X-Fake-Field: Line Two" && echo "X-Fake-Field: Line Three" && @@ -103,6 +117,52 @@ test_expect_success setup ' echo "X-Fake-Field: Line Three" && git format-patch --stdout first | sed -e "1d" } > patch1-ws.eml && + { + sed -ne "1p" msg && + echo && + echo "From: $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL>" && + echo "Date: $GIT_AUTHOR_DATE" && + echo && + sed -e "1,2d" msg && + echo && + echo "Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" && + echo "---" && + git diff-tree --no-commit-id --stat -p second + } >patch1-stgit.eml && + mkdir stgit-series && + cp patch1-stgit.eml stgit-series/patch && + { + echo "# This series applies on GIT commit $(git rev-parse first)" && + echo "patch" + } >stgit-series/series && + { + echo "# HG changeset patch" && + echo "# User $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL>" && + echo "# Date $test_tick 25200" && + echo "# $(git show --pretty="%aD" -s second)" && + echo "# Node ID $_z40" && + echo "# Parent $_z40" && + cat msg && + echo && + echo "Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" && + echo && + git diff-tree --no-commit-id -p second + } >patch1-hg.eml && + + + echo scissors-file >scissors-file && + git add scissors-file && + git commit -F scissors-msg && + git tag scissors && + git format-patch --stdout scissors^ >scissors-patch.eml && + git reset --hard HEAD^ && + + echo no-scissors-file >no-scissors-file && + git add no-scissors-file && + git commit -F no-scissors-msg && + git tag no-scissors && + git format-patch --stdout no-scissors^ >no-scissors-patch.eml && + git reset --hard HEAD^ && sed -n -e "3,\$p" msg >file && git add file && @@ -153,6 +213,18 @@ test_expect_success 'am applies patch correctly' ' test "$(git rev-parse second^)" = "$(git rev-parse HEAD^)" ' +test_expect_success 'am fails if index is dirty' ' + test_when_finished "rm -f dirtyfile" && + rm -fr .git/rebase-apply && + git reset --hard && + git checkout first && + echo dirtyfile >dirtyfile && + git add dirtyfile && + test_must_fail git am patch1 && + test_path_is_dir .git/rebase-apply && + test_cmp_rev first HEAD +' + test_expect_success 'am applies patch e-mail not in a mbox' ' rm -fr .git/rebase-apply && git reset --hard && @@ -186,6 +258,183 @@ test_expect_success 'am applies patch e-mail with preceding whitespace' ' test "$(git rev-parse second^)" = "$(git rev-parse HEAD^)" ' +test_expect_success 'am applies stgit patch' ' + rm -fr .git/rebase-apply && + git checkout -f first && + git am patch1-stgit.eml && + test_path_is_missing .git/rebase-apply && + git diff --exit-code second && + test_cmp_rev second HEAD && + test_cmp_rev second^ HEAD^ +' + +test_expect_success 'am --patch-format=stgit applies stgit patch' ' + rm -fr .git/rebase-apply && + git checkout -f first && + git am --patch-format=stgit <patch1-stgit.eml && + test_path_is_missing .git/rebase-apply && + git diff --exit-code second && + test_cmp_rev second HEAD && + test_cmp_rev second^ HEAD^ +' + +test_expect_success 'am applies stgit series' ' + rm -fr .git/rebase-apply && + git checkout -f first && + git am stgit-series/series && + test_path_is_missing .git/rebase-apply && + git diff --exit-code second && + test_cmp_rev second HEAD && + test_cmp_rev second^ HEAD^ +' + +test_expect_success 'am applies hg patch' ' + rm -fr .git/rebase-apply && + git checkout -f first && + git am patch1-hg.eml && + test_path_is_missing .git/rebase-apply && + git diff --exit-code second && + test_cmp_rev second HEAD && + test_cmp_rev second^ HEAD^ +' + +test_expect_success 'am --patch-format=hg applies hg patch' ' + rm -fr .git/rebase-apply && + git checkout -f first && + git am --patch-format=hg <patch1-hg.eml && + test_path_is_missing .git/rebase-apply && + git diff --exit-code second && + test_cmp_rev second HEAD && + test_cmp_rev second^ HEAD^ +' + +test_expect_success 'am with applypatch-msg hook' ' + test_when_finished "rm -f .git/hooks/applypatch-msg" && + rm -fr .git/rebase-apply && + git reset --hard && + git checkout first && + mkdir -p .git/hooks && + write_script .git/hooks/applypatch-msg <<-\EOF && + cat "$1" >actual-msg && + echo hook-message >"$1" + EOF + git am patch1 && + test_path_is_missing .git/rebase-apply && + git diff --exit-code second && + echo hook-message >expected && + git log -1 --format=format:%B >actual && + test_cmp expected actual && + git log -1 --format=format:%B second >expected && + test_cmp expected actual-msg +' + +test_expect_success 'am with failing applypatch-msg hook' ' + test_when_finished "rm -f .git/hooks/applypatch-msg" && + rm -fr .git/rebase-apply && + git reset --hard && + git checkout first && + mkdir -p .git/hooks && + write_script .git/hooks/applypatch-msg <<-\EOF && + exit 1 + EOF + test_must_fail git am patch1 && + test_path_is_dir .git/rebase-apply && + git diff --exit-code first && + test_cmp_rev first HEAD +' + +test_expect_success 'am with pre-applypatch hook' ' + test_when_finished "rm -f .git/hooks/pre-applypatch" && + rm -fr .git/rebase-apply && + git reset --hard && + git checkout first && + mkdir -p .git/hooks && + write_script .git/hooks/pre-applypatch <<-\EOF && + git diff first >diff.actual + exit 0 + EOF + git am patch1 && + test_path_is_missing .git/rebase-apply && + git diff --exit-code second && + test_cmp_rev second HEAD && + git diff first..second >diff.expected && + test_cmp diff.expected diff.actual +' + +test_expect_success 'am with failing pre-applypatch hook' ' + test_when_finished "rm -f .git/hooks/pre-applypatch" && + rm -fr .git/rebase-apply && + git reset --hard && + git checkout first && + mkdir -p .git/hooks && + write_script .git/hooks/pre-applypatch <<-\EOF && + exit 1 + EOF + test_must_fail git am patch1 && + test_path_is_dir .git/rebase-apply && + git diff --exit-code second && + test_cmp_rev first HEAD +' + +test_expect_success 'am with post-applypatch hook' ' + test_when_finished "rm -f .git/hooks/post-applypatch" && + rm -fr .git/rebase-apply && + git reset --hard && + git checkout first && + mkdir -p .git/hooks && + write_script .git/hooks/post-applypatch <<-\EOF && + git rev-parse HEAD >head.actual + git diff second >diff.actual + exit 0 + EOF + git am patch1 && + test_path_is_missing .git/rebase-apply && + test_cmp_rev second HEAD && + git rev-parse second >head.expected && + test_cmp head.expected head.actual && + git diff second >diff.expected && + test_cmp diff.expected diff.actual +' + +test_expect_success 'am with failing post-applypatch hook' ' + test_when_finished "rm -f .git/hooks/post-applypatch" && + rm -fr .git/rebase-apply && + git reset --hard && + git checkout first && + mkdir -p .git/hooks && + write_script .git/hooks/post-applypatch <<-\EOF && + git rev-parse HEAD >head.actual + exit 1 + EOF + git am patch1 && + test_path_is_missing .git/rebase-apply && + git diff --exit-code second && + test_cmp_rev second HEAD && + git rev-parse second >head.expected && + test_cmp head.expected head.actual +' + +test_expect_success 'am --scissors cuts the message at the scissors line' ' + rm -fr .git/rebase-apply && + git reset --hard && + git checkout second && + git am --scissors scissors-patch.eml && + test_path_is_missing .git/rebase-apply && + git diff --exit-code scissors && + test_cmp_rev scissors HEAD +' + +test_expect_success 'am --no-scissors overrides mailinfo.scissors' ' + rm -fr .git/rebase-apply && + git reset --hard && + git checkout second && + test_config mailinfo.scissors true && + git am --no-scissors no-scissors-patch.eml && + test_path_is_missing .git/rebase-apply && + git diff --exit-code no-scissors && + test_cmp_rev no-scissors HEAD +' + test_expect_success 'setup: new author and committer' ' GIT_AUTHOR_NAME="Another Thor" && GIT_AUTHOR_EMAIL="a.thor@example.com" && @@ -273,15 +522,21 @@ test_expect_success 'am --keep-non-patch really keeps the non-patch part' ' grep "^\[foo\] third" actual ' -test_expect_success 'am -3 falls back to 3-way merge' ' +test_expect_success 'setup am -3' ' rm -fr .git/rebase-apply && git reset --hard && - git checkout -b lorem2 master2 && + git checkout -b base3way master2 && sed -n -e "3,\$p" msg >file && head -n 9 msg >>file && git add file && test_tick && - git commit -m "copied stuff" && + git commit -m "copied stuff" +' + +test_expect_success 'am -3 falls back to 3-way merge' ' + rm -fr .git/rebase-apply && + git reset --hard && + git checkout -b lorem2 base3way && git am -3 lorem-move.patch && test_path_is_missing .git/rebase-apply && git diff --exit-code lorem @@ -290,17 +545,31 @@ test_expect_success 'am -3 falls back to 3-way merge' ' test_expect_success 'am -3 -p0 can read --no-prefix patch' ' rm -fr .git/rebase-apply && git reset --hard && - git checkout -b lorem3 master2 && - sed -n -e "3,\$p" msg >file && - head -n 9 msg >>file && - git add file && - test_tick && - git commit -m "copied stuff" && + git checkout -b lorem3 base3way && git am -3 -p0 lorem-zero.patch && test_path_is_missing .git/rebase-apply && git diff --exit-code lorem ' +test_expect_success 'am with config am.threeWay falls back to 3-way merge' ' + rm -fr .git/rebase-apply && + git reset --hard && + git checkout -b lorem4 base3way && + test_config am.threeWay 1 && + git am lorem-move.patch && + test_path_is_missing .git/rebase-apply && + git diff --exit-code lorem +' + +test_expect_success 'am with config am.threeWay overridden by --no-3way' ' + rm -fr .git/rebase-apply && + git reset --hard && + git checkout -b lorem5 base3way && + test_config am.threeWay 1 && + test_must_fail git am --no-3way lorem-move.patch && + test_path_is_dir .git/rebase-apply +' + test_expect_success 'am can rename a file' ' grep "^rename from" rename.patch && rm -fr .git/rebase-apply && @@ -337,12 +606,7 @@ test_expect_success 'am -3 can rename a file after falling back to 3-way merge' test_expect_success 'am -3 -q is quiet' ' rm -fr .git/rebase-apply && git checkout -f lorem2 && - git reset master2 --hard && - sed -n -e "3,\$p" msg >file && - head -n 9 msg >>file && - git add file && - test_tick && - git commit -m "copied stuff" && + git reset base3way --hard && git am -3 -q lorem-move.patch >output.out 2>&1 && ! test -s output.out ' @@ -369,6 +633,20 @@ test_expect_success 'am --abort removes a stray directory' ' test_path_is_missing .git/rebase-apply ' +test_expect_success 'am refuses patches when paused' ' + rm -fr .git/rebase-apply && + git reset --hard && + git checkout lorem2^^ && + + test_must_fail git am lorem-move.patch && + test_path_is_dir .git/rebase-apply && + test_cmp_rev lorem2^^ HEAD && + + test_must_fail git am <lorem-move.patch && + test_path_is_dir .git/rebase-apply && + test_cmp_rev lorem2^^ HEAD +' + test_expect_success 'am --resolved works' ' echo goodbye >expected && rm -fr .git/rebase-apply && @@ -383,6 +661,31 @@ test_expect_success 'am --resolved works' ' test_cmp expected another ' +test_expect_success 'am --resolved fails if index has no changes' ' + rm -fr .git/rebase-apply && + git reset --hard && + git checkout lorem2^^ && + test_must_fail git am lorem-move.patch && + test_path_is_dir .git/rebase-apply && + test_cmp_rev lorem2^^ HEAD && + test_must_fail git am --resolved && + test_path_is_dir .git/rebase-apply && + test_cmp_rev lorem2^^ HEAD +' + +test_expect_success 'am --resolved fails if index has unmerged entries' ' + rm -fr .git/rebase-apply && + git reset --hard && + git checkout second && + test_must_fail git am -3 lorem-move.patch && + test_path_is_dir .git/rebase-apply && + test_cmp_rev second HEAD && + test_must_fail git am --resolved >err && + test_path_is_dir .git/rebase-apply && + test_cmp_rev second HEAD && + test_i18ngrep "still have unmerged paths" err +' + test_expect_success 'am takes patches from a Pine mailbox' ' rm -fr .git/rebase-apply && git reset --hard && @@ -536,4 +839,122 @@ test_expect_success 'am empty-file does not infloop' ' test_i18ncmp expected actual ' +test_expect_success 'am --message-id really adds the message id' ' + rm -fr .git/rebase-apply && + git reset --hard && + git checkout HEAD^ && + git am --message-id patch1.eml && + test_path_is_missing .git/rebase-apply && + git cat-file commit HEAD | tail -n1 >actual && + grep Message-Id patch1.eml >expected && + test_cmp expected actual +' + +test_expect_success 'am.messageid really adds the message id' ' + rm -fr .git/rebase-apply && + git reset --hard && + git checkout HEAD^ && + test_config am.messageid true && + git am patch1.eml && + test_path_is_missing .git/rebase-apply && + git cat-file commit HEAD | tail -n1 >actual && + grep Message-Id patch1.eml >expected && + test_cmp expected actual +' + +test_expect_success 'am --message-id -s signs off after the message id' ' + rm -fr .git/rebase-apply && + git reset --hard && + git checkout HEAD^ && + git am -s --message-id patch1.eml && + test_path_is_missing .git/rebase-apply && + git cat-file commit HEAD | tail -n2 | head -n1 >actual && + grep Message-Id patch1.eml >expected && + test_cmp expected actual +' + +test_expect_success 'am -3 works with rerere' ' + rm -fr .git/rebase-apply && + git reset --hard && + + # make patches one->two and two->three... + test_commit one file && + test_commit two file && + test_commit three file && + git format-patch -2 --stdout >seq.patch && + + # and create a situation that conflicts... + git reset --hard one && + test_commit other file && + + # enable rerere... + test_config rerere.enabled true && + test_when_finished "rm -rf .git/rr-cache" && + + # ...and apply. Our resolution is to skip the first + # patch, and the rerere the second one. + test_must_fail git am -3 seq.patch && + test_must_fail git am --skip && + echo resolved >file && + git add file && + git am --resolved && + + # now apply again, and confirm that rerere engaged (we still + # expect failure from am because rerere does not auto-commit + # for us). + git reset --hard other && + test_must_fail git am -3 seq.patch && + test_must_fail git am --skip && + echo resolved >expect && + test_cmp expect file +' + +test_expect_success 'am -s unexpected trailer block' ' + rm -fr .git/rebase-apply && + git reset --hard && + echo signed >file && + git add file && + cat >msg <<-EOF && + subject here + + Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> + [jc: tweaked log message] + Signed-off-by: J C H <j@c.h> + EOF + git commit -F msg && + git cat-file commit HEAD | sed -e '1,/^$/d' >original && + git format-patch --stdout -1 >patch && + + git reset --hard HEAD^ && + git am -s patch && + ( + cat original && + echo "Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" + ) >expect && + git cat-file commit HEAD | sed -e '1,/^$/d' >actual && + test_cmp expect actual && + + cat >msg <<-\EOF && + subject here + + We make sure that there is a blank line between the log + message proper and Signed-off-by: line added. + EOF + git reset HEAD^ && + git commit -F msg file && + git cat-file commit HEAD | sed -e '1,/^$/d' >original && + git format-patch --stdout -1 >patch && + + git reset --hard HEAD^ && + git am -s patch && + + ( + cat original && + echo && + echo "Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" + ) >expect && + git cat-file commit HEAD | sed -e '1,/^$/d' >actual && + test_cmp expect actual +' + test_done diff --git a/t/t4151-am-abort.sh b/t/t4151-am-abort.sh index 1176bcccf3..ea5ace99a1 100755 --- a/t/t4151-am-abort.sh +++ b/t/t4151-am-abort.sh @@ -14,13 +14,14 @@ test_expect_success setup ' git add file-1 file-2 && git commit -m initial && git tag initial && + git format-patch --stdout --root initial >initial.patch && for i in 2 3 4 5 6 do echo $i >>file-1 && echo $i >otherfile-$i && git add otherfile-$i && test_tick && - git commit -a -m $i || break + git commit -a -m $i || return 1 done && git format-patch --no-numbered initial && git checkout -b side initial && @@ -63,6 +64,28 @@ do done +test_expect_success 'am -3 --skip removes otherfile-4' ' + git reset --hard initial && + test_must_fail git am -3 0003-*.patch && + test 3 -eq $(git ls-files -u | wc -l) && + test 4 = "$(cat otherfile-4)" && + git am --skip && + test_cmp_rev initial HEAD && + test -z "$(git ls-files -u)" && + test_path_is_missing otherfile-4 +' + +test_expect_success 'am -3 --abort removes otherfile-4' ' + git reset --hard initial && + test_must_fail git am -3 0003-*.patch && + test 3 -eq $(git ls-files -u | wc -l) && + test 4 = "$(cat otherfile-4)" && + git am --abort && + test_cmp_rev initial HEAD && + test -z $(git ls-files -u) && + test_path_is_missing otherfile-4 +' + test_expect_success 'am --abort will keep the local commits intact' ' test_must_fail git am 0004-*.patch && test_commit unrelated && @@ -72,4 +95,101 @@ test_expect_success 'am --abort will keep the local commits intact' ' test_cmp expect actual ' +test_expect_success 'am --abort will keep dirty index intact' ' + git reset --hard initial && + echo dirtyfile >dirtyfile && + cp dirtyfile dirtyfile.expected && + git add dirtyfile && + test_must_fail git am 0001-*.patch && + test_cmp_rev initial HEAD && + test_path_is_file dirtyfile && + test_cmp dirtyfile.expected dirtyfile && + git am --abort && + test_cmp_rev initial HEAD && + test_path_is_file dirtyfile && + test_cmp dirtyfile.expected dirtyfile +' + +test_expect_success 'am -3 stops on conflict on unborn branch' ' + git checkout -f --orphan orphan && + git reset && + rm -f otherfile-4 && + test_must_fail git am -3 0003-*.patch && + test 2 -eq $(git ls-files -u | wc -l) && + test 4 = "$(cat otherfile-4)" +' + +test_expect_success 'am -3 --skip clears index on unborn branch' ' + test_path_is_dir .git/rebase-apply && + echo tmpfile >tmpfile && + git add tmpfile && + git am --skip && + test -z "$(git ls-files)" && + test_path_is_missing otherfile-4 && + test_path_is_missing tmpfile +' + +test_expect_success 'am -3 --abort removes otherfile-4 on unborn branch' ' + git checkout -f --orphan orphan && + git reset && + rm -f otherfile-4 file-1 && + test_must_fail git am -3 0003-*.patch && + test 2 -eq $(git ls-files -u | wc -l) && + test 4 = "$(cat otherfile-4)" && + git am --abort && + test -z "$(git ls-files -u)" && + test_path_is_missing otherfile-4 +' + +test_expect_success 'am -3 --abort on unborn branch removes applied commits' ' + git checkout -f --orphan orphan && + git reset && + rm -f otherfile-4 otherfile-2 file-1 file-2 && + test_must_fail git am -3 initial.patch 0003-*.patch && + test 3 -eq $(git ls-files -u | wc -l) && + test 4 = "$(cat otherfile-4)" && + git am --abort && + test -z "$(git ls-files -u)" && + test_path_is_missing otherfile-4 && + test_path_is_missing file-1 && + test_path_is_missing file-2 && + test 0 -eq $(git log --oneline 2>/dev/null | wc -l) && + test refs/heads/orphan = "$(git symbolic-ref HEAD)" +' + +test_expect_success 'am --abort on unborn branch will keep local commits intact' ' + git checkout -f --orphan orphan && + git reset && + test_must_fail git am 0004-*.patch && + test_commit unrelated2 && + git rev-parse HEAD >expect && + git am --abort && + git rev-parse HEAD >actual && + test_cmp expect actual +' + +test_expect_success 'am --skip leaves index stat info alone' ' + git checkout -f --orphan skip-stat-info && + git reset && + test_commit skip-should-be-untouched && + test-chmtime =0 skip-should-be-untouched.t && + git update-index --refresh && + git diff-files --exit-code --quiet && + test_must_fail git am 0001-*.patch && + git am --skip && + git diff-files --exit-code --quiet +' + +test_expect_success 'am --abort leaves index stat info alone' ' + git checkout -f --orphan abort-stat-info && + git reset && + test_commit abort-should-be-untouched && + test-chmtime =0 abort-should-be-untouched.t && + git update-index --refresh && + git diff-files --exit-code --quiet && + test_must_fail git am 0001-*.patch && + git am --abort && + git diff-files --exit-code --quiet +' + test_done diff --git a/t/t4153-am-resume-override-opts.sh b/t/t4153-am-resume-override-opts.sh new file mode 100755 index 0000000000..7c013d84d5 --- /dev/null +++ b/t/t4153-am-resume-override-opts.sh @@ -0,0 +1,102 @@ +#!/bin/sh + +test_description='git-am command-line options override saved options' + +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-terminal.sh + +format_patch () { + git format-patch --stdout -1 "$1" >"$1".eml +} + +test_expect_success 'setup' ' + test_commit initial file && + test_commit first file && + + git checkout initial && + git mv file file2 && + test_tick && + git commit -m renamed-file && + git tag renamed-file && + + git checkout -b side initial && + test_commit side1 file && + test_commit side2 file && + + format_patch side1 && + format_patch side2 +' + +test_expect_success TTY '--3way overrides --no-3way' ' + rm -fr .git/rebase-apply && + git reset --hard && + git checkout renamed-file && + + # Applying side1 will fail as the file has been renamed. + test_must_fail git am --no-3way side[12].eml && + test_path_is_dir .git/rebase-apply && + test_cmp_rev renamed-file HEAD && + test -z "$(git ls-files -u)" && + + # Applying side1 with am --3way will succeed due to the threeway-merge. + # Applying side2 will fail as --3way does not apply to it. + test_must_fail test_terminal git am --3way </dev/zero && + test_path_is_dir .git/rebase-apply && + test side1 = "$(cat file2)" +' + +test_expect_success '--no-quiet overrides --quiet' ' + rm -fr .git/rebase-apply && + git reset --hard && + git checkout first && + + # Applying side1 will be quiet. + test_must_fail git am --quiet side[123].eml >out && + test_path_is_dir .git/rebase-apply && + ! test_i18ngrep "^Applying: " out && + echo side1 >file && + git add file && + + # Applying side1 will not be quiet. + # Applying side2 will be quiet. + git am --no-quiet --continue >out && + echo "Applying: side1" >expected && + test_i18ncmp expected out +' + +test_expect_success '--signoff overrides --no-signoff' ' + rm -fr .git/rebase-apply && + git reset --hard && + git checkout first && + + test_must_fail git am --no-signoff side[12].eml && + test_path_is_dir .git/rebase-apply && + echo side1 >file && + git add file && + git am --signoff --continue && + + # Applied side1 will be signed off + echo "Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" >expected && + git cat-file commit HEAD^ | grep "Signed-off-by:" >actual && + test_cmp expected actual && + + # Applied side2 will not be signed off + test $(git cat-file commit HEAD | grep -c "Signed-off-by:") -eq 0 +' + +test_expect_success TTY '--reject overrides --no-reject' ' + rm -fr .git/rebase-apply && + git reset --hard && + git checkout first && + rm -f file.rej && + + test_must_fail git am --no-reject side1.eml && + test_path_is_dir .git/rebase-apply && + test_path_is_missing file.rej && + + test_must_fail test_terminal git am --reject </dev/zero && + test_path_is_dir .git/rebase-apply && + test_path_is_file file.rej +' + +test_done diff --git a/t/t4201-shortlog.sh b/t/t4201-shortlog.sh index 97fcb31d6e..7600a3e3e8 100755 --- a/t/t4201-shortlog.sh +++ b/t/t4201-shortlog.sh @@ -93,7 +93,7 @@ test_expect_success 'output from user-defined format is re-wrapped' ' test_cmp expect log.predictable ' -test_expect_success 'shortlog wrapping' ' +test_expect_success !MINGW 'shortlog wrapping' ' cat >expect <<\EOF && A U Thor (5): Test @@ -114,7 +114,7 @@ EOF test_cmp expect out ' -test_expect_success 'shortlog from non-git directory' ' +test_expect_success !MINGW 'shortlog from non-git directory' ' git log HEAD >log && GIT_DIR=non-existing git shortlog -w <log >out && test_cmp expect out @@ -159,7 +159,7 @@ $DSCHO (2): EOF -test_expect_success 'shortlog encoding' ' +test_expect_success !MINGW 'shortlog encoding' ' git reset --hard "$commit" && git config --unset i18n.commitencoding && echo 2 > a1 && diff --git a/t/t4202-log.sh b/t/t4202-log.sh index 99ab7ca21f..cb82eb7e66 100755 --- a/t/t4202-log.sh +++ b/t/t4202-log.sh @@ -113,11 +113,7 @@ test_expect_success 'diff-filter=M' ' actual=$(git log --pretty="format:%s" --diff-filter=M HEAD) && expect=$(echo second) && - test "$actual" = "$expect" || { - echo Oops - echo "Actual: $actual" - false - } + verbose test "$actual" = "$expect" ' @@ -125,11 +121,7 @@ test_expect_success 'diff-filter=D' ' actual=$(git log --pretty="format:%s" --diff-filter=D HEAD) && expect=$(echo sixth ; echo third) && - test "$actual" = "$expect" || { - echo Oops - echo "Actual: $actual" - false - } + verbose test "$actual" = "$expect" ' @@ -137,11 +129,7 @@ test_expect_success 'diff-filter=R' ' actual=$(git log -M --pretty="format:%s" --diff-filter=R HEAD) && expect=$(echo third) && - test "$actual" = "$expect" || { - echo Oops - echo "Actual: $actual" - false - } + verbose test "$actual" = "$expect" ' @@ -149,11 +137,7 @@ test_expect_success 'diff-filter=C' ' actual=$(git log -C -C --pretty="format:%s" --diff-filter=C HEAD) && expect=$(echo fourth) && - test "$actual" = "$expect" || { - echo Oops - echo "Actual: $actual" - false - } + verbose test "$actual" = "$expect" ' @@ -161,12 +145,31 @@ test_expect_success 'git log --follow' ' actual=$(git log --follow --pretty="format:%s" ichi) && expect=$(echo third ; echo second ; echo initial) && - test "$actual" = "$expect" || { - echo Oops - echo "Actual: $actual" - false - } + verbose test "$actual" = "$expect" +' + +test_expect_success 'git config log.follow works like --follow' ' + test_config log.follow true && + actual=$(git log --pretty="format:%s" ichi) && + expect=$(echo third ; echo second ; echo initial) && + verbose test "$actual" = "$expect" +' + +test_expect_success 'git config log.follow does not die with multiple paths' ' + test_config log.follow true && + git log --pretty="format:%s" ichi ein +' + +test_expect_success 'git config log.follow does not die with no paths' ' + test_config log.follow true && + git log -- +' +test_expect_success 'git config log.follow is overridden by --no-follow' ' + test_config log.follow true && + actual=$(git log --no-follow --pretty="format:%s" ichi) && + expect="third" && + verbose test "$actual" = "$expect" ' cat > expect << EOF @@ -212,6 +215,21 @@ test_expect_success 'log --grep' ' test_cmp expect actual ' +cat > expect << EOF +second +initial +EOF +test_expect_success 'log --invert-grep --grep' ' + git log --pretty="tformat:%s" --invert-grep --grep=th --grep=Sec >actual && + test_cmp expect actual +' + +test_expect_success 'log --invert-grep --grep -i' ' + echo initial >expect && + git log --pretty="tformat:%s" --invert-grep -i --grep=th --grep=Sec >actual && + test_cmp expect actual +' + test_expect_success 'log --grep option parsing' ' echo second >expect && git log -1 --pretty="tformat:%s" --grep sec >actual && @@ -466,7 +484,7 @@ test_expect_success 'log.decorate configuration' ' git log --oneline --no-decorate >actual && test_cmp expect.none actual && git log --oneline --decorate >actual && - test_cmp expect.short actual + test_cmp expect.short actual && test_unconfig log.decorate && git log --pretty=raw >expect.raw && @@ -872,4 +890,51 @@ test_expect_success GPG 'log --graph --show-signature for merged tag' ' grep "^| | gpg: Good signature" actual ' +test_expect_success 'log --graph --no-walk is forbidden' ' + test_must_fail git log --graph --no-walk +' + +test_expect_success 'log diagnoses bogus HEAD' ' + git init empty && + test_must_fail git -C empty log 2>stderr && + test_i18ngrep does.not.have.any.commits stderr && + echo 1234abcd >empty/.git/refs/heads/master && + test_must_fail git -C empty log 2>stderr && + test_i18ngrep broken stderr && + echo "ref: refs/heads/invalid.lock" >empty/.git/HEAD && + test_must_fail git -C empty log 2>stderr && + test_i18ngrep broken stderr && + test_must_fail git -C empty log --default totally-bogus 2>stderr && + test_i18ngrep broken stderr +' + +test_expect_success 'set up --source tests' ' + git checkout --orphan source-a && + test_commit one && + test_commit two && + git checkout -b source-b HEAD^ && + test_commit three +' + +test_expect_success 'log --source paints branch names' ' + cat >expect <<-\EOF && + 09e12a9 source-b three + 8e393e1 source-a two + 1ac6c77 source-b one + EOF + git log --oneline --source source-a source-b >actual && + test_cmp expect actual +' + +test_expect_success 'log --source paints tag names' ' + git tag -m tagged source-tag && + cat >expect <<-\EOF && + 09e12a9 source-tag three + 8e393e1 source-a two + 1ac6c77 source-tag one + EOF + git log --oneline --source source-tag source-a >actual && + test_cmp expect actual +' + test_done diff --git a/t/t4204-patch-id.sh b/t/t4204-patch-id.sh index d2c930de87..baa9d3c82e 100755 --- a/t/t4204-patch-id.sh +++ b/t/t4204-patch-id.sh @@ -5,27 +5,44 @@ test_description='git patch-id' . ./test-lib.sh test_expect_success 'setup' ' - test_commit initial foo a && - test_commit first foo b && - git checkout -b same HEAD^ && - test_commit same-msg foo b && - git checkout -b notsame HEAD^ && - test_commit notsame-msg foo c + as="a a a a a a a a" && # eight a + test_write_lines $as >foo && + test_write_lines $as >bar && + git add foo bar && + git commit -a -m initial && + test_write_lines $as b >foo && + test_write_lines $as b >bar && + git commit -a -m first && + git checkout -b same master && + git commit --amend -m same-msg && + git checkout -b notsame master && + echo c >foo && + echo c >bar && + git commit --amend -a -m notsame-msg && + test_write_lines bar foo >bar-then-foo && + test_write_lines foo bar >foo-then-bar ' test_expect_success 'patch-id output is well-formed' ' - git log -p -1 | git patch-id > output && + git log -p -1 | git patch-id >output && grep "^[a-f0-9]\{40\} $(git rev-parse HEAD)$" output ' +#calculate patch id. Make sure output is not empty. calc_patch_id () { - git patch-id | - sed "s# .*##" > patch-id_"$1" + name="$1" + shift + git patch-id "$@" | + sed "s/ .*//" >patch-id_"$name" && + test_line_count -gt 0 patch-id_"$name" +} + +get_top_diff () { + git log -p -1 "$@" -O bar-then-foo -- } get_patch_id () { - git log -p -1 "$1" | git patch-id | - sed "s# .*##" > patch-id_"$1" + get_top_diff "$1" | calc_patch_id "$@" } test_expect_success 'patch-id detects equality' ' @@ -45,8 +62,8 @@ test_expect_success 'patch-id supports git-format-patch output' ' git checkout same && git format-patch -1 --stdout | calc_patch_id same && test_cmp patch-id_master patch-id_same && - set `git format-patch -1 --stdout | git patch-id` && - test "$2" = `git rev-parse HEAD` + set $(git format-patch -1 --stdout | git patch-id) && + test "$2" = $(git rev-parse HEAD) ' test_expect_success 'whitespace is irrelevant in footer' ' @@ -56,6 +73,69 @@ test_expect_success 'whitespace is irrelevant in footer' ' test_cmp patch-id_master patch-id_same ' +cmp_patch_id () { + if + test "$1" = "relevant" + then + ! test_cmp patch-id_"$2" patch-id_"$3" + else + test_cmp patch-id_"$2" patch-id_"$3" + fi +} + +test_patch_id_file_order () { + relevant="$1" + shift + name="order-${1}-$relevant" + shift + get_top_diff "master" | calc_patch_id "$name" "$@" && + git checkout same && + git format-patch -1 --stdout -O foo-then-bar | + calc_patch_id "ordered-$name" "$@" && + cmp_patch_id $relevant "$name" "ordered-$name" + +} + +# combined test for options: add more tests here to make them +# run with all options +test_patch_id () { + test_patch_id_file_order "$@" +} + +# small tests with detailed diagnostic for basic options. +test_expect_success 'file order is irrelevant with --stable' ' + test_patch_id_file_order irrelevant --stable --stable +' + +test_expect_success 'file order is relevant with --unstable' ' + test_patch_id_file_order relevant --unstable --unstable +' + +#Now test various option combinations. +test_expect_success 'default is unstable' ' + test_patch_id relevant default +' + +test_expect_success 'patchid.stable = true is stable' ' + test_config patchid.stable true && + test_patch_id irrelevant patchid.stable=true +' + +test_expect_success 'patchid.stable = false is unstable' ' + test_config patchid.stable false && + test_patch_id relevant patchid.stable=false +' + +test_expect_success '--unstable overrides patchid.stable = true' ' + test_config patchid.stable true && + test_patch_id relevant patchid.stable=true--unstable --unstable +' + +test_expect_success '--stable overrides patchid.stable = false' ' + test_config patchid.stable false && + test_patch_id irrelevant patchid.stable=false--stable --stable +' + test_expect_success 'patch-id supports git-format-patch MIME output' ' get_patch_id master && git checkout same && diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh index c84ec9ae61..7398605e7b 100755 --- a/t/t4205-log-pretty-formats.sh +++ b/t/t4205-log-pretty-formats.sh @@ -31,7 +31,7 @@ test_expect_success 'set up basic repos' ' git add foo && test_tick && git config i18n.commitEncoding $test_encoding && - git commit -m "$(commit_msg $test_encoding)" && + commit_msg $test_encoding | git commit -F - && git add bar && test_tick && git commit -m "add bar" && @@ -431,6 +431,21 @@ EOF test_cmp expected actual ' +test_expect_success 'strbuf_utf8_replace() not producing NUL' ' + git log --color --pretty="tformat:%<(10,trunc)%s%>>(10,ltrunc)%C(auto)%d" | + test_decode_color | + nul_to_q >actual && + ! grep Q actual +' + +# ISO strict date format +test_expect_success 'ISO and ISO-strict date formats display the same values' ' + git log --format=%ai%n%ci | + sed -e "s/ /T/; s/ //; s/..\$/:&/" >expected && + git log --format=%aI%n%cI >actual && + test_cmp expected actual +' + # get new digests (with no abbreviations) head1=$(git rev-parse --verify HEAD~0) && head2=$(git rev-parse --verify HEAD~1) && @@ -450,4 +465,15 @@ EOF test_cmp expected actual1 ' +test_expect_success 'clean log decoration' ' + git log --no-walk --tags --pretty="%H %D" --decorate=full >actual && + cat >expected <<EOF && +$head1 tag: refs/tags/tag2 +$head2 tag: refs/tags/message-one +$old_head1 tag: refs/tags/message-two +EOF + sort actual >actual1 && + test_cmp expected actual1 +' + test_done diff --git a/t/t4207-log-decoration-colors.sh b/t/t4207-log-decoration-colors.sh index 925f577a3c..f8008b6a3d 100755 --- a/t/t4207-log-decoration-colors.sh +++ b/t/t4207-log-decoration-colors.sh @@ -44,15 +44,15 @@ test_expect_success setup ' ' cat >expected <<EOF -${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_HEAD}HEAD${c_reset}${c_commit},\ - ${c_tag}tag: v1.0${c_reset}${c_commit},\ - ${c_tag}tag: B${c_reset}${c_commit},\ - ${c_branch}master${c_reset}${c_commit})${c_reset} B -${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_tag}tag: A1${c_reset}${c_commit},\ - ${c_remoteBranch}other/master${c_reset}${c_commit})${c_reset} A1 -${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_stash}refs/stash${c_reset}${c_commit})${c_reset}\ +${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD${c_reset}${c_commit} ->\ + ${c_reset}${c_branch}master${c_reset}${c_commit},\ + ${c_reset}${c_tag}tag: v1.0${c_reset}${c_commit},\ + ${c_reset}${c_tag}tag: B${c_reset}${c_commit})${c_reset} B +${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: A1${c_reset}${c_commit},\ + ${c_reset}${c_remoteBranch}other/master${c_reset}${c_commit})${c_reset} A1 +${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_stash}refs/stash${c_reset}${c_commit})${c_reset}\ On master: Changes to A.t -${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_tag}tag: A${c_reset}${c_commit})${c_reset} A +${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: A${c_reset}${c_commit})${c_reset} A EOF # We want log to show all, but the second parent to refs/stash is irrelevant diff --git a/t/t4210-log-i18n.sh b/t/t4210-log-i18n.sh index 52a74729ba..e585fe6129 100755 --- a/t/t4210-log-i18n.sh +++ b/t/t4210-log-i18n.sh @@ -34,7 +34,7 @@ test_expect_success 'log --grep searches in log output encoding (utf8)' ' test_cmp expect actual ' -test_expect_success 'log --grep searches in log output encoding (latin1)' ' +test_expect_success !MINGW 'log --grep searches in log output encoding (latin1)' ' cat >expect <<-\EOF && latin1 utf8 @@ -43,7 +43,7 @@ test_expect_success 'log --grep searches in log output encoding (latin1)' ' test_cmp expect actual ' -test_expect_success 'log --grep does not find non-reencoded values (utf8)' ' +test_expect_success !MINGW 'log --grep does not find non-reencoded values (utf8)' ' >expect && git log --encoding=utf8 --format=%s --grep=$latin1_e >actual && test_cmp expect actual diff --git a/t/t4211-line-log.sh b/t/t4211-line-log.sh index 7369d3c517..4451127eb2 100755 --- a/t/t4211-line-log.sh +++ b/t/t4211-line-log.sh @@ -54,14 +54,14 @@ canned_test "-L 4:a.c -L 8,12:a.c simple" multiple-superset canned_test "-L 8,12:a.c -L 4:a.c simple" multiple-superset test_bad_opts "-L" "switch.*requires a value" -test_bad_opts "-L b.c" "argument.*not of the form" -test_bad_opts "-L 1:" "argument.*not of the form" +test_bad_opts "-L b.c" "argument not .start,end:file" +test_bad_opts "-L 1:" "argument not .start,end:file" test_bad_opts "-L 1:nonexistent" "There is no path" test_bad_opts "-L 1:simple" "There is no path" -test_bad_opts "-L '/foo:b.c'" "argument.*not of the form" +test_bad_opts "-L '/foo:b.c'" "argument not .start,end:file" test_bad_opts "-L 1000:b.c" "has only.*lines" test_bad_opts "-L 1,1000:b.c" "has only.*lines" -test_bad_opts "-L :b.c" "argument.*not of the form" +test_bad_opts "-L :b.c" "argument not .start,end:file" test_bad_opts "-L :foo:b.c" "no match" test_expect_success '-L X (X == nlines)' ' @@ -94,4 +94,9 @@ test_expect_success '-L ,Y (Y == nlines + 2)' ' test_must_fail git log -L ,$n:b.c ' +test_expect_success '-L with --first-parent and a merge' ' + git checkout parallel-change && + git log --first-parent -L 1,1:b.c +' + test_done diff --git a/t/t4212-log-corrupt.sh b/t/t4212-log-corrupt.sh index 58b792bf20..22aa8b7c0e 100755 --- a/t/t4212-log-corrupt.sh +++ b/t/t4212-log-corrupt.sh @@ -14,7 +14,7 @@ test_expect_success 'setup' ' ' test_expect_success 'fsck notices broken commit' ' - git fsck 2>actual && + test_must_fail git fsck 2>actual && test_i18ngrep invalid.author actual ' @@ -61,7 +61,7 @@ test_expect_success 'unparsable dates produce sentinel value' ' test_expect_success 'unparsable dates produce sentinel value (%ad)' ' commit=$(munge_author_date HEAD totally_bogus) && echo >expect && - git log -1 --format=%ad $commit >actual + git log -1 --format=%ad $commit >actual && test_cmp expect actual ' diff --git a/t/t4255-am-submodule.sh b/t/t4255-am-submodule.sh new file mode 100755 index 0000000000..0ba8194403 --- /dev/null +++ b/t/t4255-am-submodule.sh @@ -0,0 +1,93 @@ +#!/bin/sh + +test_description='git am handling submodules' + +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-submodule-update.sh + +am () { + git format-patch --stdout --ignore-submodules=dirty "..$1" | git am - +} + +test_submodule_switch "am" + +am_3way () { + git format-patch --stdout --ignore-submodules=dirty "..$1" | git am --3way - +} + +KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1 +test_submodule_switch "am_3way" + +test_expect_success 'setup diff.submodule' ' + test_commit one && + INITIAL=$(git rev-parse HEAD) && + + git init submodule && + ( + cd submodule && + test_commit two && + git rev-parse HEAD >../initial-submodule + ) && + git submodule add ./submodule && + git commit -m first && + + ( + cd submodule && + test_commit three && + git rev-parse HEAD >../first-submodule + ) && + git add submodule && + git commit -m second && + SECOND=$(git rev-parse HEAD) && + + ( + cd submodule && + git mv two.t four.t && + git commit -m "second submodule" && + git rev-parse HEAD >../second-submodule + ) && + test_commit four && + git add submodule && + git commit --amend --no-edit && + THIRD=$(git rev-parse HEAD) && + git submodule update --init +' + +run_test() { + START_COMMIT=$1 && + EXPECT=$2 && + # Abort any merges in progress: the previous + # test may have failed, and we should clean up. + test_might_fail git am --abort && + git reset --hard $START_COMMIT && + rm -f *.patch && + git format-patch -1 && + git reset --hard $START_COMMIT^ && + git submodule update && + git am *.patch && + git submodule update && + git -C submodule rev-parse HEAD >actual && + test_cmp $EXPECT actual +} + +test_expect_success 'diff.submodule unset' ' + test_unconfig diff.submodule && + run_test $SECOND first-submodule +' + +test_expect_success 'diff.submodule unset with extra file' ' + test_unconfig diff.submodule && + run_test $THIRD second-submodule +' + +test_expect_success 'diff.submodule=log' ' + test_config diff.submodule log && + run_test $SECOND first-submodule +' + +test_expect_success 'diff.submodule=log with extra file' ' + test_config diff.submodule log && + run_test $THIRD second-submodule +' + +test_done diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index 4efaf8c58e..4b68bbafbe 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -72,7 +72,7 @@ check_tar() { for header in *.paxheader do data=${header%.paxheader}.data && - if test -h $data -o -e $data + if test -h $data || test -e $data then path=$(get_pax_header $header path) && if test -n "$path" @@ -101,7 +101,7 @@ test_expect_success \ ten=0123456789 && hundred=$ten$ten$ten$ten$ten$ten$ten$ten$ten$ten && echo long filename >a/four$hundred && mkdir a/bin && - cp /bin/sh a/bin && + test-genrandom "frotz" 500000 >a/bin/sh && printf "A\$Format:%s\$O" "$SUBSTFORMAT" >a/substfile1 && printf "A not substituted O" >a/substfile2 && if test_have_prereq SYMLINKS; then @@ -119,14 +119,10 @@ test_expect_success \ 'echo ignore me >a/ignored && echo ignored export-ignore >.git/info/attributes' -test_expect_success \ - 'add files to repository' \ - 'find a -type f | xargs git update-index --add && - find a -type l | xargs git update-index --add && - treeid=`git write-tree` && - echo $treeid >treeid && - git update-ref HEAD $(TZ=GMT GIT_COMMITTER_DATE="2005-05-27 22:00:00" \ - git commit-tree $treeid </dev/null)' +test_expect_success 'add files to repository' ' + git add a && + GIT_COMMITTER_DATE="2005-05-27 22:00" git commit -m initial +' test_expect_success 'setup export-subst' ' echo "substfile?" export-subst >>.git/info/attributes && @@ -207,7 +203,7 @@ test_expect_success \ test_expect_success 'clients cannot access unreachable commits' ' test_commit unreachable && - sha1=`git rev-parse HEAD` && + sha1=$(git rev-parse HEAD) && git reset --hard HEAD^ && git archive $sha1 >remote.tar && test_must_fail git archive --remote=. $sha1 >remote.tar @@ -215,7 +211,7 @@ test_expect_success 'clients cannot access unreachable commits' ' test_expect_success 'upload-archive can allow unreachable commits' ' test_commit unreachable1 && - sha1=`git rev-parse HEAD` && + sha1=$(git rev-parse HEAD) && git reset --hard HEAD^ && git archive $sha1 >remote.tar && test_config uploadarchive.allowUnreachable true && @@ -309,4 +305,18 @@ test_expect_success GZIP 'remote tar.gz can be disabled' ' >remote.tar.gz ' +test_expect_success 'archive and :(glob)' ' + git archive -v HEAD -- ":(glob)**/sh" >/dev/null 2>actual && + cat >expect <<EOF && +a/ +a/bin/ +a/bin/sh +EOF + test_cmp expect actual +' + +test_expect_success 'catch non-matching pathspec' ' + test_must_fail git archive -v HEAD -- "*.abc" >/dev/null +' + test_done diff --git a/t/t5003-archive-zip.sh b/t/t5003-archive-zip.sh index 21a5c93f41..14744b2a4b 100755 --- a/t/t5003-archive-zip.sh +++ b/t/t5003-archive-zip.sh @@ -33,6 +33,37 @@ check_zip() { test_expect_success UNZIP " validate file contents" " diff -r a ${dir_with_prefix}a " + + dir=eol_$1 + dir_with_prefix=$dir/$2 + extracted=${dir_with_prefix}a + original=a + + test_expect_success UNZIP " extract ZIP archive with EOL conversion" ' + (mkdir $dir && cd $dir && "$GIT_UNZIP" -a ../$zipfile) + ' + + test_expect_success UNZIP " validate that text files are converted" " + test_cmp_bin $extracted/text.cr $extracted/text.crlf && + test_cmp_bin $extracted/text.cr $extracted/text.lf + " + + test_expect_success UNZIP " validate that binary files are unchanged" " + test_cmp_bin $original/binary.cr $extracted/binary.cr && + test_cmp_bin $original/binary.crlf $extracted/binary.crlf && + test_cmp_bin $original/binary.lf $extracted/binary.lf + " + + test_expect_success UNZIP " validate that diff files are converted" " + test_cmp_bin $extracted/diff.cr $extracted/diff.crlf && + test_cmp_bin $extracted/diff.cr $extracted/diff.lf + " + + test_expect_success UNZIP " validate that -diff files are unchanged" " + test_cmp_bin $original/nodiff.cr $extracted/nodiff.cr && + test_cmp_bin $original/nodiff.crlf $extracted/nodiff.crlf && + test_cmp_bin $original/nodiff.lf $extracted/nodiff.lf + " } test_expect_success \ @@ -41,6 +72,18 @@ test_expect_success \ echo simple textfile >a/a && mkdir a/bin && cp /bin/sh a/bin && + printf "text\r" >a/text.cr && + printf "text\r\n" >a/text.crlf && + printf "text\n" >a/text.lf && + printf "text\r" >a/nodiff.cr && + printf "text\r\n" >a/nodiff.crlf && + printf "text\n" >a/nodiff.lf && + printf "\0\r" >a/binary.cr && + printf "\0\r\n" >a/binary.crlf && + printf "\0\n" >a/binary.lf && + printf "\0\r" >a/diff.cr && + printf "\0\r\n" >a/diff.crlf && + printf "\0\n" >a/diff.lf && printf "A\$Format:%s\$O" "$SUBSTFORMAT" >a/substfile1 && printf "A not substituted O" >a/substfile2 && (p=long_path_to_a_file && cd a && @@ -61,16 +104,14 @@ test_expect_success \ 'echo ignore me >a/ignored && echo ignored export-ignore >.git/info/attributes' -test_expect_success \ - 'add files to repository' \ - 'find a -type f | xargs git update-index --add && - find a -type l | xargs git update-index --add && - treeid=`git write-tree` && - echo $treeid >treeid && - git update-ref HEAD $(TZ=GMT GIT_COMMITTER_DATE="2005-05-27 22:00:00" \ - git commit-tree $treeid </dev/null)' - -test_expect_success 'setup export-subst' ' +test_expect_success 'add files to repository' ' + git add a && + GIT_COMMITTER_DATE="2005-05-27 22:00" git commit -m initial +' + +test_expect_success 'setup export-subst and diff attributes' ' + echo "a/nodiff.* -diff" >>.git/info/attributes && + echo "a/diff.* diff" >>.git/info/attributes && echo "substfile?" export-subst >>.git/info/attributes && git log --max-count=1 "--pretty=format:A${SUBSTFORMAT}O" HEAD \ >a/substfile1 diff --git a/t/t5004-archive-corner-cases.sh b/t/t5004-archive-corner-cases.sh index 305bcac6b7..cca23383c5 100755 --- a/t/t5004-archive-corner-cases.sh +++ b/t/t5004-archive-corner-cases.sh @@ -66,8 +66,10 @@ test_expect_success UNZIP 'zip archive of empty tree is empty' ' # handle the empty repo at all, making our later check of its exit code # a no-op). But we cannot do anything reasonable except skip the test # on such platforms anyway, and this is the moral equivalent. - "$GIT_UNZIP" "$TEST_DIRECTORY"/t5004/empty.zip - expect_code=$? + { + "$GIT_UNZIP" "$TEST_DIRECTORY"/t5004/empty.zip + expect_code=$? + } && git archive --format=zip HEAD >empty.zip && make_dir extract && @@ -113,4 +115,44 @@ test_expect_success 'archive empty subtree by direct pathspec' ' check_dir extract sub ' +ZIPINFO=zipinfo + +test_lazy_prereq ZIPINFO ' + n=$("$ZIPINFO" "$TEST_DIRECTORY"/t5004/empty.zip | sed -n "2s/.* //p") + test "x$n" = "x0" +' + +test_expect_success ZIPINFO 'zip archive with many entries' ' + # add a directory with 256 files + mkdir 00 && + for a in 0 1 2 3 4 5 6 7 8 9 a b c d e f + do + for b in 0 1 2 3 4 5 6 7 8 9 a b c d e f + do + : >00/$a$b + done + done && + git add 00 && + git commit -m "256 files in 1 directory" && + + # duplicate it to get 65536 files in 256 directories + subtree=$(git write-tree --prefix=00/) && + for c in 0 1 2 3 4 5 6 7 8 9 a b c d e f + do + for d in 0 1 2 3 4 5 6 7 8 9 a b c d e f + do + echo "040000 tree $subtree $c$d" + done + done >tree && + tree=$(git mktree <tree) && + + # zip them + git archive -o many.zip $tree && + + # check the number of entries in the ZIP file directory + expr 65536 + 256 >expect && + "$ZIPINFO" many.zip | head -2 | sed -n "2s/.* //p" >actual && + test_cmp expect actual +' + test_done diff --git a/t/t5100-mailinfo.sh b/t/t5100-mailinfo.sh index 3e64a7a65d..e97cfb2ab8 100755 --- a/t/t5100-mailinfo.sh +++ b/t/t5100-mailinfo.sh @@ -34,6 +34,10 @@ do if test -f "$TEST_DIRECTORY"/t5100/msg$mail--no-inbody-headers then check_mailinfo $mail --no-inbody-headers + fi && + if test -f "$TEST_DIRECTORY"/t5100/msg$mail--message-id + then + check_mailinfo $mail --message-id fi ' done @@ -89,4 +93,22 @@ test_expect_success 'mailinfo on from header without name works' ' ' +test_expect_success 'mailinfo finds headers after embedded From line' ' + mkdir embed-from && + git mailsplit -oembed-from "$TEST_DIRECTORY"/t5100/embed-from.in && + test_cmp "$TEST_DIRECTORY"/t5100/embed-from.in embed-from/0001 && + git mailinfo embed-from/msg embed-from/patch \ + <embed-from/0001 >embed-from/out && + test_cmp "$TEST_DIRECTORY"/t5100/embed-from.expect embed-from/out +' + +test_expect_success 'mailinfo on message with quoted >From' ' + mkdir quoted-from && + git mailsplit -oquoted-from "$TEST_DIRECTORY"/t5100/quoted-from.in && + test_cmp "$TEST_DIRECTORY"/t5100/quoted-from.in quoted-from/0001 && + git mailinfo quoted-from/msg quoted-from/patch \ + <quoted-from/0001 >quoted-from/out && + test_cmp "$TEST_DIRECTORY"/t5100/quoted-from.expect quoted-from/msg +' + test_done diff --git a/t/t5100/embed-from.expect b/t/t5100/embed-from.expect new file mode 100644 index 0000000000..06a3a3859a --- /dev/null +++ b/t/t5100/embed-from.expect @@ -0,0 +1,5 @@ +Author: Commit Author +Email: commit@example.com +Subject: patch subject +Date: Sat, 13 Sep 2014 21:13:23 -0400 + diff --git a/t/t5100/embed-from.in b/t/t5100/embed-from.in new file mode 100644 index 0000000000..5f3f84e508 --- /dev/null +++ b/t/t5100/embed-from.in @@ -0,0 +1,13 @@ +From 1234567890123456789012345678901234567890 Mon Sep 17 00:00:00 2001 +From: Email Author <email@example.com> +Date: Sun, 25 May 2008 00:38:18 -0700 +Subject: [PATCH] email subject + +>From 1234567890123456789012345678901234567890 Mon Sep 17 00:00:00 2001 +From: Commit Author <commit@example.com> +Date: Sat, 13 Sep 2014 21:13:23 -0400 +Subject: patch subject + +patch body +--- +patch diff --git a/t/t5100/info0012--message-id b/t/t5100/info0012--message-id new file mode 100644 index 0000000000..ac1216ff75 --- /dev/null +++ b/t/t5100/info0012--message-id @@ -0,0 +1,5 @@ +Author: Dmitriy Blinov +Email: bda@mnsspb.ru +Subject: Изменён список пакетов необходимых для сборки +Date: Wed, 12 Nov 2008 17:54:41 +0300 + diff --git a/t/t5100/msg0012--message-id b/t/t5100/msg0012--message-id new file mode 100644 index 0000000000..376e26e9ae --- /dev/null +++ b/t/t5100/msg0012--message-id @@ -0,0 +1,8 @@ +textlive-* исправлены на texlive-* +docutils заменён на python-docutils + +Действительно, оказалось, что rest2web вытягивает за собой +python-docutils. В то время как сам rest2web не нужен. + +Signed-off-by: Dmitriy Blinov <bda@mnsspb.ru> +Message-Id: <1226501681-24923-1-git-send-email-bda@mnsspb.ru> diff --git a/t/t5100/patch0012--message-id b/t/t5100/patch0012--message-id new file mode 100644 index 0000000000..36a0b68161 --- /dev/null +++ b/t/t5100/patch0012--message-id @@ -0,0 +1,30 @@ +--- + howto/build_navy.txt | 6 +++--- + 1 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/howto/build_navy.txt b/howto/build_navy.txt +index 3fd3afb..0ee807e 100644 +--- a/howto/build_navy.txt ++++ b/howto/build_navy.txt +@@ -119,8 +119,8 @@ + - libxv-dev + - libusplash-dev + - latex-make +- - textlive-lang-cyrillic +- - textlive-latex-extra ++ - texlive-lang-cyrillic ++ - texlive-latex-extra + - dia + - python-pyrex + - libtool +@@ -128,7 +128,7 @@ + - sox + - cython + - imagemagick +- - docutils ++ - python-docutils + + #. на машине dinar: добавить свой открытый ssh-ключ в authorized_keys2 пользователя ddev + #. на своей машине: отредактировать /etc/sudoers (команда ``visudo``) примерно следующим образом:: +-- +1.5.6.5 diff --git a/t/t5100/quoted-from.expect b/t/t5100/quoted-from.expect new file mode 100644 index 0000000000..8c9d48c852 --- /dev/null +++ b/t/t5100/quoted-from.expect @@ -0,0 +1,3 @@ +>From the depths of history, we are stuck with the +flaky mbox format. + diff --git a/t/t5100/quoted-from.in b/t/t5100/quoted-from.in new file mode 100644 index 0000000000..847e1c4d3e --- /dev/null +++ b/t/t5100/quoted-from.in @@ -0,0 +1,10 @@ +From 1234567890123456789012345678901234567890 Mon Sep 17 00:00:00 2001 +From: Author Name <somebody@example.com> +Date: Sun, 25 May 2008 00:38:18 -0700 +Subject: [PATCH] testing quoted >From + +>From the depths of history, we are stuck with the +flaky mbox format. + +--- +patch diff --git a/t/t5302-pack-index.sh b/t/t5302-pack-index.sh index 4bbb718751..3dc5ec4dd3 100755 --- a/t/t5302-pack-index.sh +++ b/t/t5302-pack-index.sh @@ -243,4 +243,23 @@ test_expect_success 'running index-pack in the object store' ' test -f .git/objects/pack/pack-${pack1}.idx ' +test_expect_success 'index-pack --strict warns upon missing tagger in tag' ' + sha=$(git rev-parse HEAD) && + cat >wrong-tag <<EOF && +object $sha +type commit +tag guten tag + +This is an invalid tag. +EOF + + tag=$(git hash-object -t tag -w --stdin <wrong-tag) && + pack1=$(echo $tag $sha | git pack-objects tag-test) && + echo remove tag object && + thirtyeight=${tag#??} && + rm -f .git/objects/${tag%$thirtyeight}/$thirtyeight && + git index-pack --strict tag-test-${pack1}.pack 2>err && + grep "^warning:.* expected .tagger. line" err +' + test_done diff --git a/t/t5304-prune.sh b/t/t5304-prune.sh index 377d3d3899..def203c724 100755 --- a/t/t5304-prune.sh +++ b/t/t5304-prune.sh @@ -13,8 +13,8 @@ add_blob() { before=$(git count-objects | sed "s/ .*//") && BLOB=$(echo aleph_0 | git hash-object -w --stdin) && BLOB_FILE=.git/objects/$(echo $BLOB | sed "s/^../&\//") && - test $((1 + $before)) = $(git count-objects | sed "s/ .*//") && - test -f $BLOB_FILE && + verbose test $((1 + $before)) = $(git count-objects | sed "s/ .*//") && + test_path_is_file $BLOB_FILE && test-chmtime =+0 $BLOB_FILE } @@ -35,9 +35,9 @@ test_expect_success 'prune stale packs' ' : > .git/objects/tmp_2.pack && test-chmtime =-86501 .git/objects/tmp_1.pack && git prune --expire 1.day && - test -f $orig_pack && - test -f .git/objects/tmp_2.pack && - ! test -f .git/objects/tmp_1.pack + test_path_is_file $orig_pack && + test_path_is_file .git/objects/tmp_2.pack && + test_path_is_missing .git/objects/tmp_1.pack ' @@ -45,12 +45,12 @@ test_expect_success 'prune --expire' ' add_blob && git prune --expire=1.hour.ago && - test $((1 + $before)) = $(git count-objects | sed "s/ .*//") && - test -f $BLOB_FILE && + verbose test $((1 + $before)) = $(git count-objects | sed "s/ .*//") && + test_path_is_file $BLOB_FILE && test-chmtime =-86500 $BLOB_FILE && git prune --expire 1.day && - test $before = $(git count-objects | sed "s/ .*//") && - ! test -f $BLOB_FILE + verbose test $before = $(git count-objects | sed "s/ .*//") && + test_path_is_missing $BLOB_FILE ' @@ -59,12 +59,12 @@ test_expect_success 'gc: implicit prune --expire' ' add_blob && test-chmtime =-$((2*$week-30)) $BLOB_FILE && git gc && - test $((1 + $before)) = $(git count-objects | sed "s/ .*//") && - test -f $BLOB_FILE && + verbose test $((1 + $before)) = $(git count-objects | sed "s/ .*//") && + test_path_is_file $BLOB_FILE && test-chmtime =-$((2*$week+1)) $BLOB_FILE && git gc && - test $before = $(git count-objects | sed "s/ .*//") && - ! test -f $BLOB_FILE + verbose test $before = $(git count-objects | sed "s/ .*//") && + test_path_is_missing $BLOB_FILE ' @@ -104,6 +104,28 @@ test_expect_success 'prune: prune unreachable heads' ' ' +test_expect_success 'prune: do not prune detached HEAD with no reflog' ' + + git checkout --detach --quiet && + git commit --allow-empty -m "detached commit" && + # verify that there is no reflogs + # (should be removed and disabled by previous test) + test_path_is_missing .git/logs && + git prune -n >prune_actual && + : >prune_expected && + test_cmp prune_actual prune_expected + +' + +test_expect_success 'prune: prune former HEAD after checking out branch' ' + + head_sha1=$(git rev-parse HEAD) && + git checkout --quiet master && + git prune -v >prune_actual && + grep "$head_sha1" prune_actual + +' + test_expect_success 'prune: do not prune heads listed as an argument' ' : > file2 && @@ -122,8 +144,8 @@ test_expect_success 'gc --no-prune' ' test-chmtime =-$((5001*$day)) $BLOB_FILE && git config gc.pruneExpire 2.days.ago && git gc --no-prune && - test 1 = $(git count-objects | sed "s/ .*//") && - test -f $BLOB_FILE + verbose test 1 = $(git count-objects | sed "s/ .*//") && + test_path_is_file $BLOB_FILE ' @@ -131,10 +153,10 @@ test_expect_success 'gc respects gc.pruneExpire' ' git config gc.pruneExpire 5002.days.ago && git gc && - test -f $BLOB_FILE && + test_path_is_file $BLOB_FILE && git config gc.pruneExpire 5000.days.ago && git gc && - test ! -f $BLOB_FILE + test_path_is_missing $BLOB_FILE ' @@ -143,9 +165,9 @@ test_expect_success 'gc --prune=<date>' ' add_blob && test-chmtime =-$((5001*$day)) $BLOB_FILE && git gc --prune=5002.days.ago && - test -f $BLOB_FILE && + test_path_is_file $BLOB_FILE && git gc --prune=5000.days.ago && - test ! -f $BLOB_FILE + test_path_is_missing $BLOB_FILE ' @@ -153,9 +175,9 @@ test_expect_success 'gc --prune=never' ' add_blob && git gc --prune=never && - test -f $BLOB_FILE && + test_path_is_file $BLOB_FILE && git gc --prune=now && - test ! -f $BLOB_FILE + test_path_is_missing $BLOB_FILE ' @@ -164,10 +186,10 @@ test_expect_success 'gc respects gc.pruneExpire=never' ' git config gc.pruneExpire never && add_blob && git gc && - test -f $BLOB_FILE && + test_path_is_file $BLOB_FILE && git config gc.pruneExpire now && git gc && - test ! -f $BLOB_FILE + test_path_is_missing $BLOB_FILE ' @@ -175,9 +197,9 @@ test_expect_success 'prune --expire=never' ' add_blob && git prune --expire=never && - test -f $BLOB_FILE && + test_path_is_file $BLOB_FILE && git prune && - test ! -f $BLOB_FILE + test_path_is_missing $BLOB_FILE ' @@ -187,15 +209,17 @@ test_expect_success 'gc: prune old objects after local clone' ' git clone --no-hardlinks . aclone && ( cd aclone && - test 1 = $(git count-objects | sed "s/ .*//") && - test -f $BLOB_FILE && + verbose test 1 = $(git count-objects | sed "s/ .*//") && + test_path_is_file $BLOB_FILE && git gc --prune && - test 0 = $(git count-objects | sed "s/ .*//") && - ! test -f $BLOB_FILE + verbose test 0 = $(git count-objects | sed "s/ .*//") && + test_path_is_missing $BLOB_FILE ) ' test_expect_success 'garbage report in count-objects -v' ' + test_when_finished "rm -f .git/objects/pack/fake*" && + test_when_finished "rm -f .git/objects/pack/foo*" && : >.git/objects/pack/foo && : >.git/objects/pack/foo.bar && : >.git/objects/pack/foo.keep && @@ -221,6 +245,26 @@ EOF test_cmp expected actual ' +test_expect_success 'clean pack garbage with gc' ' + test_when_finished "rm -f .git/objects/pack/fake*" && + test_when_finished "rm -f .git/objects/pack/foo*" && + : >.git/objects/pack/foo.keep && + : >.git/objects/pack/foo.pack && + : >.git/objects/pack/fake.idx && + : >.git/objects/pack/fake2.keep && + : >.git/objects/pack/fake2.idx && + : >.git/objects/pack/fake3.keep && + git gc && + git count-objects -v 2>stderr && + grep "^warning:" stderr | sort >actual && + cat >expected <<\EOF && +warning: no corresponding .idx or .pack: .git/objects/pack/fake3.keep +warning: no corresponding .idx: .git/objects/pack/foo.keep +warning: no corresponding .idx: .git/objects/pack/foo.pack +EOF + test_cmp expected actual +' + test_expect_success 'prune .git/shallow' ' SHA1=`echo hi|git commit-tree HEAD^{tree}` && echo $SHA1 >.git/shallow && @@ -228,7 +272,15 @@ test_expect_success 'prune .git/shallow' ' grep $SHA1 .git/shallow && grep $SHA1 out && git prune && - ! test -f .git/shallow + test_path_is_missing .git/shallow +' + +test_expect_success 'prune: handle alternate object database' ' + test_create_repo A && + git -C A commit --allow-empty -m "initial commit" && + git clone --shared A B && + git -C B commit --allow-empty -m "next commit" && + git -C B prune ' test_done diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh index f4f02ba918..d446706e94 100755 --- a/t/t5310-pack-bitmaps.sh +++ b/t/t5310-pack-bitmaps.sh @@ -18,7 +18,7 @@ test_expect_success 'setup repo with moderate-sized history' ' git checkout master && blob=$(echo tagged-blob | git hash-object -w --stdin) && git tag tagged-blob $blob && - git config pack.writebitmaps true && + git config repack.writebitmaps true && git config pack.writebitmaphashcache true ' @@ -53,6 +53,12 @@ rev_list_tests() { test_cmp expect actual ' + test_expect_success "counting commits with limiting ($state)" ' + git rev-list --count HEAD -- 1.t >expect && + git rev-list --use-bitmap-index --count HEAD -- 1.t >actual && + test_cmp expect actual + ' + test_expect_success "enumerate --objects ($state)" ' git rev-list --objects --use-bitmap-index HEAD >tmp && cut -d" " -f1 <tmp >tmp2 && @@ -170,4 +176,13 @@ test_expect_success JGIT 'jgit can read our bitmaps' ' ) ' +test_expect_success 'splitting packs does not generate bogus bitmaps' ' + test-genrandom foo $((1024 * 1024)) >rand && + git add rand && + git commit -m "commit with big file" && + git -c pack.packSizeLimit=500k repack -adb && + git init --bare no-bitmaps.git && + git -C no-bitmaps.git fetch .. HEAD +' + test_done diff --git a/t/t5311-pack-bitmaps-shallow.sh b/t/t5311-pack-bitmaps-shallow.sh new file mode 100755 index 0000000000..872a95df33 --- /dev/null +++ b/t/t5311-pack-bitmaps-shallow.sh @@ -0,0 +1,39 @@ +#!/bin/sh + +test_description='check bitmap operation with shallow repositories' +. ./test-lib.sh + +# We want to create a situation where the shallow, grafted +# view of reachability does not match reality in a way that +# might cause us to send insufficient objects. +# +# We do this with a history that repeats a state, like: +# +# A -- B -- C +# file=1 file=2 file=1 +# +# and then create a shallow clone to the second commit, B. +# In a non-shallow clone, that would mean we already have +# the tree for A. But in a shallow one, we've grafted away +# A, and fetching A to B requires that the other side send +# us the tree for file=1. +test_expect_success 'setup shallow repo' ' + echo 1 >file && + git add file && + git commit -m orig && + echo 2 >file && + git commit -a -m update && + git clone --no-local --bare --depth=1 . shallow.git && + echo 1 >file && + git commit -a -m repeat +' + +test_expect_success 'turn on bitmaps in the parent' ' + git repack -adb +' + +test_expect_success 'shallow fetch from bitmapped repo' ' + (cd shallow.git && git fetch) +' + +test_done diff --git a/t/t5312-prune-corruption.sh b/t/t5312-prune-corruption.sh new file mode 100755 index 0000000000..da9d59940d --- /dev/null +++ b/t/t5312-prune-corruption.sh @@ -0,0 +1,114 @@ +#!/bin/sh + +test_description=' +Test pruning of repositories with minor corruptions. The goal +here is that we should always be erring on the side of safety. So +if we see, for example, a ref with a bogus name, it is OK either to +bail out or to proceed using it as a reachable tip, but it is _not_ +OK to proceed as if it did not exist. Otherwise we might silently +delete objects that cannot be recovered. +' +. ./test-lib.sh + +test_expect_success 'disable reflogs' ' + git config core.logallrefupdates false && + git reflog expire --expire=all --all +' + +test_expect_success 'create history reachable only from a bogus-named ref' ' + test_tick && git commit --allow-empty -m master && + base=$(git rev-parse HEAD) && + test_tick && git commit --allow-empty -m bogus && + bogus=$(git rev-parse HEAD) && + git cat-file commit $bogus >saved && + echo $bogus >.git/refs/heads/bogus..name && + git reset --hard HEAD^ +' + +test_expect_success 'pruning does not drop bogus object' ' + test_when_finished "git hash-object -w -t commit saved" && + test_might_fail git prune --expire=now && + verbose git cat-file -e $bogus +' + +test_expect_success 'put bogus object into pack' ' + git tag reachable $bogus && + git repack -ad && + git tag -d reachable && + verbose git cat-file -e $bogus +' + +test_expect_success 'destructive repack keeps packed object' ' + test_might_fail git repack -Ad --unpack-unreachable=now && + verbose git cat-file -e $bogus && + test_might_fail git repack -ad && + verbose git cat-file -e $bogus +' + +# subsequent tests will have different corruptions +test_expect_success 'clean up bogus ref' ' + rm .git/refs/heads/bogus..name +' + +# We create two new objects here, "one" and "two". Our +# master branch points to "two", which is deleted, +# corrupting the repository. But we'd like to make sure +# that the otherwise unreachable "one" is not pruned +# (since it is the user's best bet for recovering +# from the corruption). +# +# Note that we also point HEAD somewhere besides "two", +# as we want to make sure we test the case where we +# pick up the reference to "two" by iterating the refs, +# not by resolving HEAD. +test_expect_success 'create history with missing tip commit' ' + test_tick && git commit --allow-empty -m one && + recoverable=$(git rev-parse HEAD) && + git cat-file commit $recoverable >saved && + test_tick && git commit --allow-empty -m two && + missing=$(git rev-parse HEAD) && + git checkout --detach $base && + rm .git/objects/$(echo $missing | sed "s,..,&/,") && + test_must_fail git cat-file -e $missing +' + +test_expect_success 'pruning with a corrupted tip does not drop history' ' + test_when_finished "git hash-object -w -t commit saved" && + test_might_fail git prune --expire=now && + verbose git cat-file -e $recoverable +' + +test_expect_success 'pack-refs does not silently delete broken loose ref' ' + git pack-refs --all --prune && + echo $missing >expect && + git rev-parse refs/heads/master >actual && + test_cmp expect actual +' + +# we do not want to count on running pack-refs to +# actually pack it, as it is perfectly reasonable to +# skip processing a broken ref +test_expect_success 'create packed-refs file with broken ref' ' + rm -f .git/refs/heads/master && + cat >.git/packed-refs <<-EOF && + $missing refs/heads/master + $recoverable refs/heads/other + EOF + echo $missing >expect && + git rev-parse refs/heads/master >actual && + test_cmp expect actual +' + +test_expect_success 'pack-refs does not silently delete broken packed ref' ' + git pack-refs --all --prune && + git rev-parse refs/heads/master >actual && + test_cmp expect actual +' + +test_expect_success 'pack-refs does not drop broken refs during deletion' ' + git update-ref -d refs/heads/other && + git rev-parse refs/heads/master >actual && + test_cmp expect actual +' + +test_done diff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh index 0736bcbcd5..04cea97f87 100755 --- a/t/t5400-send-pack.sh +++ b/t/t5400-send-pack.sh @@ -76,8 +76,7 @@ test_expect_success 'refuse pushing rewound head without --force' ' test "$victim_head" = "$pushed_head" ' -test_expect_success \ - 'push can be used to delete a ref' ' +test_expect_success 'push can be used to delete a ref' ' ( cd victim && git branch extra master ) && git send-pack ./victim :extra master && ( cd victim && @@ -196,19 +195,6 @@ rewound_push_setup() { ) } -rewound_push_succeeded() { - cmp ../parent/.git/refs/heads/master .git/refs/heads/master -} - -rewound_push_failed() { - if rewound_push_succeeded - then - false - else - true - fi -} - test_expect_success 'pushing explicit refspecs respects forcing' ' rewound_push_setup && parent_orig=$(cd parent && git rev-parse --verify master) && diff --git a/t/t5401-update-hooks.sh b/t/t5401-update-hooks.sh index 17bcb0b040..7f278d8ce9 100755 --- a/t/t5401-update-hooks.sh +++ b/t/t5401-update-hooks.sh @@ -135,4 +135,17 @@ test_expect_success 'send-pack stderr contains hook messages' ' test_cmp expect actual ' +test_expect_success 'pre-receive hook that forgets to read its input' ' + write_script victim.git/hooks/pre-receive <<-\EOF && + exit 0 + EOF + rm -f victim.git/hooks/update victim.git/hooks/post-update && + + for v in $(test_seq 100 999) + do + git branch branch_$v master || return + done && + git push ./victim.git "+refs/heads/*:refs/heads/*" +' + test_done diff --git a/t/t5403-post-checkout-hook.sh b/t/t5403-post-checkout-hook.sh index 1753ef2b91..fc898c9eac 100755 --- a/t/t5403-post-checkout-hook.sh +++ b/t/t5403-post-checkout-hook.sh @@ -39,7 +39,7 @@ test_expect_success 'post-checkout receives the right arguments with HEAD unchan old=$(awk "{print \$1}" clone1/.git/post-checkout.args) && new=$(awk "{print \$2}" clone1/.git/post-checkout.args) && flag=$(awk "{print \$3}" clone1/.git/post-checkout.args) && - test $old = $new -a $flag = 1 + test $old = $new && test $flag = 1 ' test_expect_success 'post-checkout runs as expected ' ' @@ -52,7 +52,7 @@ test_expect_success 'post-checkout args are correct with git checkout -b ' ' old=$(awk "{print \$1}" clone1/.git/post-checkout.args) && new=$(awk "{print \$2}" clone1/.git/post-checkout.args) && flag=$(awk "{print \$3}" clone1/.git/post-checkout.args) && - test $old = $new -a $flag = 1 + test $old = $new && test $flag = 1 ' test_expect_success 'post-checkout receives the right args with HEAD changed ' ' @@ -60,7 +60,7 @@ test_expect_success 'post-checkout receives the right args with HEAD changed ' ' old=$(awk "{print \$1}" clone2/.git/post-checkout.args) && new=$(awk "{print \$2}" clone2/.git/post-checkout.args) && flag=$(awk "{print \$3}" clone2/.git/post-checkout.args) && - test $old != $new -a $flag = 1 + test $old != $new && test $flag = 1 ' test_expect_success 'post-checkout receives the right args when not switching branches ' ' @@ -68,7 +68,7 @@ test_expect_success 'post-checkout receives the right args when not switching br old=$(awk "{print \$1}" clone2/.git/post-checkout.args) && new=$(awk "{print \$2}" clone2/.git/post-checkout.args) && flag=$(awk "{print \$3}" clone2/.git/post-checkout.args) && - test $old = $new -a $flag = 0 + test $old = $new && test $flag = 0 ' if test "$(git config --bool core.filemode)" = true; then diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh index ea2e0d4b48..7a48236e87 100755 --- a/t/t5407-post-rewrite-hook.sh +++ b/t/t5407-post-rewrite-hook.sh @@ -61,10 +61,10 @@ test_expect_success 'git rebase' ' git add foo && git rebase --continue && echo rebase >expected.args && - cat >expected.data <<EOF && -$(git rev-parse C) $(git rev-parse HEAD^) -$(git rev-parse D) $(git rev-parse HEAD) -EOF + cat >expected.data <<-EOF && + $(git rev-parse C) $(git rev-parse HEAD^) + $(git rev-parse D) $(git rev-parse HEAD) + EOF verify_hook_input ' @@ -77,9 +77,9 @@ test_expect_success 'git rebase --skip' ' git add foo && git rebase --continue && echo rebase >expected.args && - cat >expected.data <<EOF && -$(git rev-parse D) $(git rev-parse HEAD) -EOF + cat >expected.data <<-EOF && + $(git rev-parse D) $(git rev-parse HEAD) + EOF verify_hook_input ' @@ -89,9 +89,9 @@ test_expect_success 'git rebase --skip the last one' ' test_must_fail git rebase --onto D A && git rebase --skip && echo rebase >expected.args && - cat >expected.data <<EOF && -$(git rev-parse E) $(git rev-parse HEAD) -EOF + cat >expected.data <<-EOF && + $(git rev-parse E) $(git rev-parse HEAD) + EOF verify_hook_input ' @@ -103,10 +103,10 @@ test_expect_success 'git rebase -m' ' git add foo && git rebase --continue && echo rebase >expected.args && - cat >expected.data <<EOF && -$(git rev-parse C) $(git rev-parse HEAD^) -$(git rev-parse D) $(git rev-parse HEAD) -EOF + cat >expected.data <<-EOF && + $(git rev-parse C) $(git rev-parse HEAD^) + $(git rev-parse D) $(git rev-parse HEAD) + EOF verify_hook_input ' @@ -119,9 +119,9 @@ test_expect_success 'git rebase -m --skip' ' git add foo && git rebase --continue && echo rebase >expected.args && - cat >expected.data <<EOF && -$(git rev-parse D) $(git rev-parse HEAD) -EOF + cat >expected.data <<-EOF && + $(git rev-parse D) $(git rev-parse HEAD) + EOF verify_hook_input ' @@ -148,10 +148,10 @@ test_expect_success 'git rebase -i (unchanged)' ' git add foo && git rebase --continue && echo rebase >expected.args && - cat >expected.data <<EOF && -$(git rev-parse C) $(git rev-parse HEAD^) -$(git rev-parse D) $(git rev-parse HEAD) -EOF + cat >expected.data <<-EOF && + $(git rev-parse C) $(git rev-parse HEAD^) + $(git rev-parse D) $(git rev-parse HEAD) + EOF verify_hook_input ' @@ -163,9 +163,9 @@ test_expect_success 'git rebase -i (skip)' ' git add foo && git rebase --continue && echo rebase >expected.args && - cat >expected.data <<EOF && -$(git rev-parse D) $(git rev-parse HEAD) -EOF + cat >expected.data <<-EOF && + $(git rev-parse D) $(git rev-parse HEAD) + EOF verify_hook_input ' @@ -177,10 +177,10 @@ test_expect_success 'git rebase -i (squash)' ' git add foo && git rebase --continue && echo rebase >expected.args && - cat >expected.data <<EOF && -$(git rev-parse C) $(git rev-parse HEAD) -$(git rev-parse D) $(git rev-parse HEAD) -EOF + cat >expected.data <<-EOF && + $(git rev-parse C) $(git rev-parse HEAD) + $(git rev-parse D) $(git rev-parse HEAD) + EOF verify_hook_input ' @@ -189,10 +189,10 @@ test_expect_success 'git rebase -i (fixup without conflict)' ' clear_hook_input && FAKE_LINES="1 fixup 2" git rebase -i B && echo rebase >expected.args && - cat >expected.data <<EOF && -$(git rev-parse C) $(git rev-parse HEAD) -$(git rev-parse D) $(git rev-parse HEAD) -EOF + cat >expected.data <<-EOF && + $(git rev-parse C) $(git rev-parse HEAD) + $(git rev-parse D) $(git rev-parse HEAD) + EOF verify_hook_input ' @@ -205,10 +205,27 @@ test_expect_success 'git rebase -i (double edit)' ' git add foo && git rebase --continue && echo rebase >expected.args && - cat >expected.data <<EOF && -$(git rev-parse C) $(git rev-parse HEAD^) -$(git rev-parse D) $(git rev-parse HEAD) -EOF + cat >expected.data <<-EOF && + $(git rev-parse C) $(git rev-parse HEAD^) + $(git rev-parse D) $(git rev-parse HEAD) + EOF + verify_hook_input +' + +test_expect_success 'git rebase -i (exec)' ' + git reset --hard D && + clear_hook_input && + FAKE_LINES="edit 1 exec_false 2" git rebase -i B && + echo something >bar && + git add bar && + # Fails because of exec false + test_must_fail git rebase --continue && + git rebase --continue && + echo rebase >expected.args && + cat >expected.data <<-EOF && + $(git rev-parse C) $(git rev-parse HEAD^) + $(git rev-parse D) $(git rev-parse HEAD) + EOF verify_hook_input ' diff --git a/t/t5408-send-pack-stdin.sh b/t/t5408-send-pack-stdin.sh new file mode 100755 index 0000000000..e8737df6f9 --- /dev/null +++ b/t/t5408-send-pack-stdin.sh @@ -0,0 +1,92 @@ +#!/bin/sh + +test_description='send-pack --stdin tests' +. ./test-lib.sh + +create_ref () { + tree=$(git write-tree) && + test_tick && + commit=$(echo "$1" | git commit-tree $tree) && + git update-ref "$1" $commit +} + +clear_remote () { + rm -rf remote.git && + git init --bare remote.git +} + +verify_push () { + git rev-parse "$1" >expect && + git --git-dir=remote.git rev-parse "${2:-$1}" >actual && + test_cmp expect actual +} + +test_expect_success 'setup refs' ' + cat >refs <<-\EOF && + refs/heads/A + refs/heads/C + refs/tags/D + refs/heads/B + refs/tags/E + EOF + for i in $(cat refs); do + create_ref $i || return 1 + done +' + +# sanity check our setup +test_expect_success 'refs on cmdline' ' + clear_remote && + git send-pack remote.git $(cat refs) && + for i in $(cat refs); do + verify_push $i || return 1 + done +' + +test_expect_success 'refs over stdin' ' + clear_remote && + git send-pack remote.git --stdin <refs && + for i in $(cat refs); do + verify_push $i || return 1 + done +' + +test_expect_success 'stdin lines are full refspecs' ' + clear_remote && + echo "A:other" >input && + git send-pack remote.git --stdin <input && + verify_push refs/heads/A refs/heads/other +' + +test_expect_success 'stdin mixed with cmdline' ' + clear_remote && + echo A >input && + git send-pack remote.git --stdin B <input && + verify_push A && + verify_push B +' + +test_expect_success 'cmdline refs written in order' ' + clear_remote && + test_must_fail git send-pack remote.git A:foo B:foo && + verify_push A foo +' + +test_expect_success '--stdin refs come after cmdline' ' + clear_remote && + echo A:foo >input && + test_must_fail git send-pack remote.git --stdin B:foo <input && + verify_push B foo +' + +test_expect_success 'refspecs and --mirror do not mix (cmdline)' ' + clear_remote && + test_must_fail git send-pack remote.git --mirror $(cat refs) +' + +test_expect_success 'refspecs and --mirror do not mix (stdin)' ' + clear_remote && + test_must_fail git send-pack remote.git --mirror --stdin <refs +' + +test_done diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh index 5b2b1c2c13..3a9b77576f 100755 --- a/t/t5500-fetch-pack.sh +++ b/t/t5500-fetch-pack.sh @@ -414,7 +414,7 @@ test_expect_success 'setup tests for the --stdin parameter' ' do git tag $head $head done && - cat >input <<-\EOF + cat >input <<-\EOF && refs/heads/C refs/heads/A refs/heads/D @@ -541,13 +541,30 @@ check_prot_path () { test_cmp expected actual } -check_prot_host_path () { - cat >expected <<-EOF && +check_prot_host_port_path () { + local diagport + case "$2" in + *ssh*) + pp=ssh + uah=userandhost + ehost=$(echo $3 | tr -d "[]") + diagport="Diag: port=$4" + ;; + *) + pp=$p + uah=hostandport + ehost=$(echo $3$4 | sed -e "s/22$/:22/" -e "s/NONE//") + diagport="" + ;; + esac + cat >exp <<-EOF && Diag: url=$1 - Diag: protocol=$2 - Diag: hostandport=$3 - Diag: path=$4 + Diag: protocol=$pp + Diag: $uah=$ehost + $diagport + Diag: path=$5 EOF + grep -v "^$" exp >expected git fetch-pack --diag-url "$1" >actual && test_cmp expected actual } @@ -557,22 +574,23 @@ do # git or ssh with scheme for p in "ssh+git" "git+ssh" git ssh do - for h in host host:12 [::1] [::1]:23 + for h in host user@host user@[::1] user@::1 do - case "$p" in - *ssh*) - pp=ssh - ;; - *) - pp=$p - ;; - esac - test_expect_success "fetch-pack --diag-url $p://$h/$r" ' - check_prot_host_path $p://$h/$r $pp "$h" "/$r" - ' - # "/~" -> "~" conversion - test_expect_success "fetch-pack --diag-url $p://$h/~$r" ' - check_prot_host_path $p://$h/~$r $pp "$h" "~$r" + for c in "" : + do + test_expect_success "fetch-pack --diag-url $p://$h$c/$r" ' + check_prot_host_port_path $p://$h/$r $p "$h" NONE "/$r" + ' + # "/~" -> "~" conversion + test_expect_success "fetch-pack --diag-url $p://$h$c/~$r" ' + check_prot_host_port_path $p://$h/~$r $p "$h" NONE "~$r" + ' + done + done + for h in host User@host User@[::1] + do + test_expect_success "fetch-pack --diag-url $p://$h:22/$r" ' + check_prot_host_port_path $p://$h:22/$r $p "$h" 22 "/$r" ' done done @@ -603,11 +621,11 @@ do for h in host [::1] do test_expect_success "fetch-pack --diag-url $h:$r" ' - check_prot_path $h:$r $p "$r" + check_prot_host_port_path $h:$r $p "$h" NONE "$r" ' # Do "/~" -> "~" conversion test_expect_success "fetch-pack --diag-url $h:/~$r" ' - check_prot_host_path $h:/~$r $p "$h" "~$r" + check_prot_host_port_path $h:/~$r $p "$h" NONE "~$r" ' done done diff --git a/t/t5503-tagfollow.sh b/t/t5503-tagfollow.sh index f30c03885c..4ca48f0276 100755 --- a/t/t5503-tagfollow.sh +++ b/t/t5503-tagfollow.sh @@ -139,8 +139,8 @@ EOF ' test_expect_success 'new clone fetch master and tags' ' - git branch -D cat - rm -f $U + test_might_fail git branch -D cat && + rm -f $U && ( mkdir clone2 && cd clone2 && diff --git a/t/t5504-fetch-receive-strict.sh b/t/t5504-fetch-receive-strict.sh index 69ee13c8be..89224edcc5 100755 --- a/t/t5504-fetch-receive-strict.sh +++ b/t/t5504-fetch-receive-strict.sh @@ -100,7 +100,7 @@ test_expect_success 'push with receive.fsckobjects' ' git config receive.fsckobjects true && git config transfer.fsckobjects false ) && - test_must_fail git push --porcelain dst master:refs/heads/test >act && + test_must_fail ok=sigpipe git push --porcelain dst master:refs/heads/test >act && test_cmp exp act ' @@ -111,8 +111,58 @@ test_expect_success 'push with transfer.fsckobjects' ' cd dst && git config transfer.fsckobjects true ) && - test_must_fail git push --porcelain dst master:refs/heads/test >act && - test_cmp exp act + test_must_fail ok=sigpipe git push --porcelain dst master:refs/heads/test >act +' + +cat >bogus-commit <<\EOF +tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904 +author Bugs Bunny 1234567890 +0000 +committer Bugs Bunny <bugs@bun.ni> 1234567890 +0000 + +This commit object intentionally broken +EOF + +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 && + git --git-dir=dst/.git config receive.fsckObjects true && + test_must_fail git push --porcelain dst bogus && + git --git-dir=dst/.git config receive.fsck.skipList SKIP && + echo $commit >dst/.git/SKIP && + git push --porcelain dst bogus +' + +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 && + git --git-dir=dst/.git config receive.fsckobjects true && + test_must_fail git push --porcelain dst bogus && + git --git-dir=dst/.git config \ + receive.fsck.missingEmail warn && + git push --porcelain dst bogus >act 2>&1 && + grep "missingEmail" act && + git --git-dir=dst/.git branch -D bogus && + git --git-dir=dst/.git config --add \ + receive.fsck.missingEmail ignore && + git --git-dir=dst/.git config --add \ + receive.fsck.badDate warn && + git push --porcelain dst bogus >act 2>&1 && + test_must_fail grep "missingEmail" act +' + +test_expect_success \ + 'receive.fsck.unterminatedHeader=warn triggers error' ' + rm -rf dst && + git init dst && + git --git-dir=dst/.git config receive.fsckobjects true && + git --git-dir=dst/.git config \ + receive.fsck.unterminatedheader warn && + test_must_fail git push --porcelain dst HEAD >act 2>&1 && + grep "Cannot demote unterminatedheader" act ' test_done diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index ac79dd915d..dfaf9d9f68 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -579,7 +579,7 @@ test_expect_success 'update with arguments' ' cd one && for b in $(git branch -r) do - git branch -r -d $b || break + git branch -r -d $b || exit 1 done && git remote add manduca ../mirror && git remote add megaloprepus ../mirror && @@ -622,7 +622,7 @@ test_expect_success 'update default' ' cd one && for b in $(git branch -r) do - git branch -r -d $b || break + git branch -r -d $b || exit 1 done && git config remote.drosophila.skipDefaultUpdate true && git remote update default && @@ -642,7 +642,7 @@ test_expect_success 'update default (overridden, with funny whitespace)' ' cd one && for b in $(git branch -r) do - git branch -r -d $b || break + git branch -r -d $b || exit 1 done && git config remotes.default "$(printf "\t drosophila \n")" && git remote update default && @@ -656,7 +656,7 @@ test_expect_success 'update (with remotes.default defined)' ' cd one && for b in $(git branch -r) do - git branch -r -d $b || break + git branch -r -d $b || exit 1 done && git config remotes.default "drosophila" && git remote update && @@ -919,6 +919,19 @@ test_expect_success 'new remote' ' cmp expect actual ' +get_url_test () { + cat >expect && + git remote get-url "$@" >actual && + test_cmp expect actual +} + +test_expect_success 'get-url on new remote' ' + echo foo | get_url_test someremote && + echo foo | get_url_test --all someremote && + echo foo | get_url_test --push someremote && + echo foo | get_url_test --push --all someremote +' + test_expect_success 'remote set-url bar' ' git remote set-url someremote bar && echo bar >expect && @@ -961,6 +974,13 @@ test_expect_success 'remote set-url --push zot' ' cmp expect actual ' +test_expect_success 'get-url with different urls' ' + echo baz | get_url_test someremote && + echo baz | get_url_test --all someremote && + echo zot | get_url_test --push someremote && + echo zot | get_url_test --push --all someremote +' + test_expect_success 'remote set-url --push qux zot' ' git remote set-url --push someremote qux zot && echo qux >expect && @@ -995,6 +1015,14 @@ test_expect_success 'remote set-url --push --add aaa' ' cmp expect actual ' +test_expect_success 'get-url on multi push remote' ' + echo foo | get_url_test --push someremote && + get_url_test --push --all someremote <<-\EOF + foo + aaa + EOF +' + test_expect_success 'remote set-url --push bar aaa' ' git remote set-url --push someremote bar aaa && echo foo >expect && @@ -1039,6 +1067,14 @@ test_expect_success 'remote set-url --add bbb' ' cmp expect actual ' +test_expect_success 'get-url on multi fetch remote' ' + echo baz | get_url_test someremote && + get_url_test --all someremote <<-\EOF + baz + bbb + EOF +' + test_expect_success 'remote set-url --delete .*' ' test_must_fail git remote set-url --delete someremote .\* && echo "YYY" >expect && @@ -1108,9 +1144,15 @@ test_extra_arg rename origin newname test_extra_arg remove origin test_extra_arg set-head origin master # set-branches takes any number of args +test_extra_arg get-url origin newurl test_extra_arg set-url origin newurl oldurl # show takes any number of args # prune takes any number of args # update takes any number of args +test_expect_success 'add remote matching the "insteadOf" URL' ' + git config url.xyz@example.com.insteadOf backup && + git remote add backup xyz@example.com +' + test_done diff --git a/t/t5507-remote-environment.sh b/t/t5507-remote-environment.sh new file mode 100755 index 0000000000..e6149295b1 --- /dev/null +++ b/t/t5507-remote-environment.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +test_description='check environment showed to remote side of transports' +. ./test-lib.sh + +test_expect_success 'set up "remote" push situation' ' + test_commit one && + git config push.default current && + git init remote +' + +test_expect_success 'set up fake ssh' ' + GIT_SSH_COMMAND="f() { + cd \"\$TRASH_DIRECTORY\" && + eval \"\$2\" + }; f" && + export GIT_SSH_COMMAND && + export TRASH_DIRECTORY +' + +# due to receive.denyCurrentBranch=true +test_expect_success 'confirm default push fails' ' + test_must_fail git push remote +' + +test_expect_success 'config does not travel over same-machine push' ' + test_must_fail git -c receive.denyCurrentBranch=false push remote +' + +test_expect_success 'config does not travel over ssh push' ' + test_must_fail git -c receive.denyCurrentBranch=false push host:remote +' + +test_done diff --git a/t/t5509-fetch-push-namespaces.sh b/t/t5509-fetch-push-namespaces.sh index cc0b31f6b0..bc44ac36d5 100755 --- a/t/t5509-fetch-push-namespaces.sh +++ b/t/t5509-fetch-push-namespaces.sh @@ -82,4 +82,45 @@ test_expect_success 'mirroring a repository using a ref namespace' ' ) ' +test_expect_success 'hide namespaced refs with transfer.hideRefs' ' + GIT_NAMESPACE=namespace \ + git -C pushee -c transfer.hideRefs=refs/tags \ + ls-remote "ext::git %s ." >actual && + printf "$commit1\trefs/heads/master\n" >expected && + test_cmp expected actual +' + +test_expect_success 'check that transfer.hideRefs does not match unstripped refs' ' + GIT_NAMESPACE=namespace \ + git -C pushee -c transfer.hideRefs=refs/namespaces/namespace/refs/tags \ + ls-remote "ext::git %s ." >actual && + printf "$commit1\trefs/heads/master\n" >expected && + printf "$commit0\trefs/tags/0\n" >>expected && + printf "$commit1\trefs/tags/1\n" >>expected && + test_cmp expected actual +' + +test_expect_success 'hide full refs with transfer.hideRefs' ' + GIT_NAMESPACE=namespace \ + git -C pushee -c transfer.hideRefs="^refs/namespaces/namespace/refs/tags" \ + ls-remote "ext::git %s ." >actual && + printf "$commit1\trefs/heads/master\n" >expected && + test_cmp expected actual +' + +test_expect_success 'try to update a hidden ref' ' + test_config -C pushee transfer.hideRefs refs/heads/master && + test_must_fail git -C original push pushee-namespaced master +' + +test_expect_success 'try to update a ref that is not hidden' ' + test_config -C pushee transfer.hideRefs refs/namespaces/namespace/refs/heads/master && + git -C original push pushee-namespaced master +' + +test_expect_success 'try to update a hidden full ref' ' + test_config -C pushee transfer.hideRefs "^refs/namespaces/namespace/refs/heads/master" && + test_must_fail git -C original push pushee-namespaced master +' + test_done diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index 29d59ef9fa..e3ee4bd700 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -124,7 +124,7 @@ test_expect_success 'fetch --prune handles overlapping refspecs' ' git rev-parse origin/master && git rev-parse origin/pr/42 && - git config --unset-all remote.origin.fetch + git config --unset-all remote.origin.fetch && git config remote.origin.fetch refs/pull/*/head:refs/remotes/origin/pr/* && git config --add remote.origin.fetch refs/heads/*:refs/remotes/origin/* && @@ -447,6 +447,43 @@ test_expect_success 'explicit pull should update tracking' ' ) ' +test_expect_success 'explicit --refmap is allowed only with command-line refspec' ' + cd "$D" && + ( + cd three && + test_must_fail git fetch --refmap="*:refs/remotes/none/*" + ) +' + +test_expect_success 'explicit --refmap option overrides remote.*.fetch' ' + cd "$D" && + git branch -f side && + ( + cd three && + git update-ref refs/remotes/origin/master base-origin-master && + o=$(git rev-parse --verify refs/remotes/origin/master) && + git fetch --refmap="refs/heads/*:refs/remotes/other/*" origin master && + n=$(git rev-parse --verify refs/remotes/origin/master) && + test "$o" = "$n" && + test_must_fail git rev-parse --verify refs/remotes/origin/side && + git rev-parse --verify refs/remotes/other/master + ) +' + +test_expect_success 'explicitly empty --refmap option disables remote.*.fetch' ' + cd "$D" && + git branch -f side && + ( + cd three && + git update-ref refs/remotes/origin/master base-origin-master && + o=$(git rev-parse --verify refs/remotes/origin/master) && + git fetch --refmap="" origin master && + n=$(git rev-parse --verify refs/remotes/origin/master) && + test "$o" = "$n" && + test_must_fail git rev-parse --verify refs/remotes/origin/side + ) +' + test_expect_success 'configured fetch updates tracking' ' cd "$D" && @@ -559,7 +596,7 @@ test_configured_prune () { test_unconfig remote.origin.prune && git fetch && git rev-parse --verify refs/remotes/origin/newbranch - ) + ) && # now remove it git branch -d newbranch && @@ -671,4 +708,17 @@ test_expect_success 'fetching a one-level ref works' ' ) ' +test_expect_success 'fetching with auto-gc does not lock up' ' + write_script askyesno <<-\EOF && + echo "$*" && + false + EOF + git clone "file://$D" auto-gc && + test_commit test2 && + cd auto-gc && + git config gc.autoPackLimit 1 && + GIT_ASK_YESNO="$D/askyesno" git fetch >fetch.out 2>&1 && + ! grep "Should I try again" fetch.out +' + test_done diff --git a/t/t5511-refspec.sh b/t/t5511-refspec.sh index c28932216b..f541f30bc2 100755 --- a/t/t5511-refspec.sh +++ b/t/t5511-refspec.sh @@ -5,7 +5,6 @@ test_description='refspec parsing' . ./test-lib.sh test_refspec () { - kind=$1 refspec=$2 expect=$3 git config remote.frotz.url "." && git config --remove-section remote.frotz && @@ -72,16 +71,24 @@ test_refspec fetch ':refs/remotes/frotz/HEAD-to-me' test_refspec push ':refs/remotes/frotz/delete me' invalid test_refspec fetch ':refs/remotes/frotz/HEAD to me' invalid -test_refspec fetch 'refs/heads/*/for-linus:refs/remotes/mine/*-blah' invalid -test_refspec push 'refs/heads/*/for-linus:refs/remotes/mine/*-blah' invalid +test_refspec fetch 'refs/heads/*/for-linus:refs/remotes/mine/*-blah' +test_refspec push 'refs/heads/*/for-linus:refs/remotes/mine/*-blah' -test_refspec fetch 'refs/heads*/for-linus:refs/remotes/mine/*' invalid -test_refspec push 'refs/heads*/for-linus:refs/remotes/mine/*' invalid +test_refspec fetch 'refs/heads*/for-linus:refs/remotes/mine/*' +test_refspec push 'refs/heads*/for-linus:refs/remotes/mine/*' test_refspec fetch 'refs/heads/*/*/for-linus:refs/remotes/mine/*' invalid test_refspec push 'refs/heads/*/*/for-linus:refs/remotes/mine/*' invalid +test_refspec fetch 'refs/heads/*g*/for-linus:refs/remotes/mine/*' invalid +test_refspec push 'refs/heads/*g*/for-linus:refs/remotes/mine/*' invalid + test_refspec fetch 'refs/heads/*/for-linus:refs/remotes/mine/*' test_refspec push 'refs/heads/*/for-linus:refs/remotes/mine/*' +good=$(printf '\303\204') +test_refspec fetch "refs/heads/${good}" +bad=$(printf '\011tab') +test_refspec fetch "refs/heads/${bad}" invalid + test_done diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh index 321c3e5234..aadaac515e 100755 --- a/t/t5512-ls-remote.sh +++ b/t/t5512-ls-remote.sh @@ -103,8 +103,10 @@ test_expect_success 'confuses pattern as remote when no remote specified' ' ' test_expect_success 'die with non-2 for wrong repository even with --exit-code' ' - git ls-remote --exit-code ./no-such-repository ;# not && - status=$? && + { + git ls-remote --exit-code ./no-such-repository + status=$? + } && test $status != 2 && test $status != 0 ' @@ -126,6 +128,11 @@ test_expect_success 'Report match with --exit-code' ' test_cmp expect actual ' +test_expect_success 'set up some extra tags for ref hiding' ' + git tag magic/one && + git tag magic/two +' + for configsection in transfer uploadpack do test_expect_success "Hide some refs with $configsection.hiderefs" ' @@ -136,6 +143,24 @@ do sed -e "/ refs\/tags\//d" >expect && test_cmp expect actual ' + + test_expect_success "Override hiding of $configsection.hiderefs" ' + test_when_finished "test_unconfig $configsection.hiderefs" && + git config --add $configsection.hiderefs refs/tags && + git config --add $configsection.hiderefs "!refs/tags/magic" && + git config --add $configsection.hiderefs refs/tags/magic/one && + git ls-remote . >actual && + grep refs/tags/magic/two actual && + ! grep refs/tags/magic/one actual + ' + done +test_expect_success 'overrides work between mixed transfer/upload-pack hideRefs' ' + test_config uploadpack.hiderefs refs/tags && + test_config transfer.hiderefs "!refs/tags/magic" && + git ls-remote . >actual && + grep refs/tags/magic actual +' + test_done diff --git a/t/t5514-fetch-multiple.sh b/t/t5514-fetch-multiple.sh index 0f8140957f..4b4b6673b8 100755 --- a/t/t5514-fetch-multiple.sh +++ b/t/t5514-fetch-multiple.sh @@ -120,7 +120,7 @@ test_expect_success 'git fetch --all (skipFetchAll)' ' (cd test4 && for b in $(git branch -r) do - git branch -r -d $b || break + git branch -r -d $b || exit 1 done && git remote add three ../three && git config remote.three.skipFetchAll true && @@ -144,7 +144,7 @@ test_expect_success 'git fetch --multiple (ignoring skipFetchAll)' ' (cd test4 && for b in $(git branch -r) do - git branch -r -d $b || break + git branch -r -d $b || exit 1 done && git fetch --multiple one two three && git branch -r > output && diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index 67e0ab3462..0a87e195ea 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -11,6 +11,7 @@ This test checks the following functionality: * hooks * --porcelain output format * hiderefs +* reflogs ' . ./test-lib.sh @@ -237,7 +238,7 @@ test_expect_success 'push with pushInsteadOf' ' test_expect_success 'push with pushInsteadOf and explicit pushurl (pushInsteadOf should not rewrite)' ' mk_empty testrepo && test_config "url.trash2/.pushInsteadOf" testrepo/ && - test_config "url.trash3/.pusnInsteadOf" trash/wrong && + test_config "url.trash3/.pushInsteadOf" trash/wrong && test_config remote.r.url trash/wrong && test_config remote.r.pushurl "testrepo/" && git push r refs/heads/master:refs/remotes/origin/master && @@ -1106,12 +1107,74 @@ test_expect_success 'fetch exact SHA1' ' git config uploadpack.allowtipsha1inwant true ) && - git fetch -v ../testrepo $the_commit:refs/heads/copy && - result=$(git rev-parse --verify refs/heads/copy) && - test "$the_commit" = "$result" + git fetch -v ../testrepo $the_commit:refs/heads/copy master:refs/heads/extra && + cat >expect <<-EOF && + $the_commit + $the_first_commit + EOF + { + git rev-parse --verify refs/heads/copy && + git rev-parse --verify refs/heads/extra + } >actual && + test_cmp expect actual ) ' +for configallowtipsha1inwant in true false +do + test_expect_success "shallow fetch reachable SHA1 (but not a ref), allowtipsha1inwant=$configallowtipsha1inwant" ' + mk_empty testrepo && + ( + cd testrepo && + git config uploadpack.allowtipsha1inwant $configallowtipsha1inwant && + git commit --allow-empty -m foo && + git commit --allow-empty -m bar + ) && + SHA1=$(git --git-dir=testrepo/.git rev-parse HEAD^) && + mk_empty shallow && + ( + cd shallow && + test_must_fail git fetch --depth=1 ../testrepo/.git $SHA1 && + git --git-dir=../testrepo/.git config uploadpack.allowreachablesha1inwant true && + git fetch --depth=1 ../testrepo/.git $SHA1 && + git cat-file commit $SHA1 + ) + ' + + test_expect_success "deny fetch unreachable SHA1, allowtipsha1inwant=$configallowtipsha1inwant" ' + mk_empty testrepo && + ( + cd testrepo && + git config uploadpack.allowtipsha1inwant $configallowtipsha1inwant && + git commit --allow-empty -m foo && + git commit --allow-empty -m bar && + git commit --allow-empty -m xyz + ) && + SHA1_1=$(git --git-dir=testrepo/.git rev-parse HEAD^^) && + SHA1_2=$(git --git-dir=testrepo/.git rev-parse HEAD^) && + SHA1_3=$(git --git-dir=testrepo/.git rev-parse HEAD) && + ( + cd testrepo && + git reset --hard $SHA1_2 && + git cat-file commit $SHA1_1 && + git cat-file commit $SHA1_3 + ) && + mk_empty shallow && + ( + cd shallow && + test_must_fail ok=sigpipe git fetch ../testrepo/.git $SHA1_3 && + test_must_fail ok=sigpipe git fetch ../testrepo/.git $SHA1_1 && + git --git-dir=../testrepo/.git config uploadpack.allowreachablesha1inwant true && + git fetch ../testrepo/.git $SHA1_1 && + git cat-file commit $SHA1_1 && + test_must_fail git cat-file commit $SHA1_2 && + git fetch ../testrepo/.git $SHA1_2 && + git cat-file commit $SHA1_2 && + test_must_fail ok=sigpipe git fetch ../testrepo/.git $SHA1_3 + ) + ' +done + test_expect_success 'fetch follows tags by default' ' mk_test testrepo heads/master && rm -fr src dst && @@ -1277,4 +1340,276 @@ EOF git push --no-thin --receive-pack="$rcvpck" no-thin/.git refs/heads/master:refs/heads/foo ' +test_expect_success 'pushing a tag pushes the tagged object' ' + rm -rf dst.git && + blob=$(echo unreferenced | git hash-object -w --stdin) && + git tag -m foo tag-of-blob $blob && + git init --bare dst.git && + git push dst.git tag-of-blob && + # the receiving index-pack should have noticed + # any problems, but we double check + echo unreferenced >expect && + git --git-dir=dst.git cat-file blob tag-of-blob >actual && + test_cmp expect actual +' + +test_expect_success 'push into bare respects core.logallrefupdates' ' + rm -rf dst.git && + git init --bare dst.git && + git -C dst.git config core.logallrefupdates true && + + # double push to test both with and without + # the actual pack transfer + git push dst.git master:one && + echo "one@{0} push" >expect && + git -C dst.git log -g --format="%gd %gs" one >actual && + test_cmp expect actual && + + git push dst.git master:two && + echo "two@{0} push" >expect && + git -C dst.git log -g --format="%gd %gs" two >actual && + test_cmp expect actual +' + +test_expect_success 'fetch into bare respects core.logallrefupdates' ' + rm -rf dst.git && + git init --bare dst.git && + ( + cd dst.git && + git config core.logallrefupdates true && + + # as above, we double-fetch to test both + # with and without pack transfer + git fetch .. master:one && + echo "one@{0} fetch .. master:one: storing head" >expect && + git log -g --format="%gd %gs" one >actual && + test_cmp expect actual && + + git fetch .. master:two && + echo "two@{0} fetch .. master:two: storing head" >expect && + git log -g --format="%gd %gs" two >actual && + test_cmp expect actual + ) +' + +test_expect_success 'receive.denyCurrentBranch = updateInstead' ' + git push testrepo master && + ( + cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch updateInstead + ) && + test_commit third path2 && + + # Try pushing into a repository with pristine working tree + git push testrepo master && + ( + cd testrepo && + git update-index -q --refresh && + git diff-files --quiet -- && + git diff-index --quiet --cached HEAD -- && + test third = "$(cat path2)" && + test $(git -C .. rev-parse HEAD) = $(git rev-parse HEAD) + ) && + + # Try pushing into a repository with working tree needing a refresh + ( + cd testrepo && + git reset --hard HEAD^ && + test $(git -C .. rev-parse HEAD^) = $(git rev-parse HEAD) && + test-chmtime +100 path1 + ) && + git push testrepo master && + ( + cd testrepo && + git update-index -q --refresh && + git diff-files --quiet -- && + git diff-index --quiet --cached HEAD -- && + test_cmp ../path1 path1 && + test third = "$(cat path2)" && + test $(git -C .. rev-parse HEAD) = $(git rev-parse HEAD) + ) && + + # Update what is to be pushed + test_commit fourth path2 && + + # Try pushing into a repository with a dirty working tree + # (1) the working tree updated + ( + cd testrepo && + echo changed >path1 + ) && + test_must_fail git push testrepo master && + ( + cd testrepo && + test $(git -C .. rev-parse HEAD^) = $(git rev-parse HEAD) && + git diff --quiet --cached && + test changed = "$(cat path1)" + ) && + + # (2) the index updated + ( + cd testrepo && + echo changed >path1 && + git add path1 + ) && + test_must_fail git push testrepo master && + ( + cd testrepo && + test $(git -C .. rev-parse HEAD^) = $(git rev-parse HEAD) && + git diff --quiet && + test changed = "$(cat path1)" + ) && + + # Introduce a new file in the update + test_commit fifth path3 && + + # (3) the working tree has an untracked file that would interfere + ( + cd testrepo && + git reset --hard && + echo changed >path3 + ) && + test_must_fail git push testrepo master && + ( + cd testrepo && + test $(git -C .. rev-parse HEAD^^) = $(git rev-parse HEAD) && + git diff --quiet && + git diff --quiet --cached && + test changed = "$(cat path3)" + ) && + + # (4) the target changes to what gets pushed but it still is a change + ( + cd testrepo && + git reset --hard && + echo fifth >path3 && + git add path3 + ) && + test_must_fail git push testrepo master && + ( + cd testrepo && + test $(git -C .. rev-parse HEAD^^) = $(git rev-parse HEAD) && + git diff --quiet && + test fifth = "$(cat path3)" + ) && + + # (5) push into void + rm -fr void && + git init void && + ( + cd void && + git config receive.denyCurrentBranch updateInstead + ) && + git push void master && + ( + cd void && + test $(git -C .. rev-parse master) = $(git rev-parse HEAD) && + git diff --quiet && + git diff --cached --quiet + ) +' + +test_expect_success 'updateInstead with push-to-checkout hook' ' + rm -fr testrepo && + git init testrepo && + ( + cd testrepo && + git pull .. master && + git reset --hard HEAD^^ && + git tag initial && + git config receive.denyCurrentBranch updateInstead && + write_script .git/hooks/push-to-checkout <<-\EOF + echo >&2 updating from $(git rev-parse HEAD) + echo >&2 updating to "$1" + + git update-index -q --refresh && + git read-tree -u -m HEAD "$1" || { + status=$? + echo >&2 read-tree failed + exit $status + } + EOF + ) && + + # Try pushing into a pristine + git push testrepo master && + ( + cd testrepo && + git diff --quiet && + git diff HEAD --quiet && + test $(git -C .. rev-parse HEAD) = $(git rev-parse HEAD) + ) && + + # Try pushing into a repository with conflicting change + ( + cd testrepo && + git reset --hard initial && + echo conflicting >path2 + ) && + test_must_fail git push testrepo master && + ( + cd testrepo && + test $(git rev-parse initial) = $(git rev-parse HEAD) && + test conflicting = "$(cat path2)" && + git diff-index --quiet --cached HEAD + ) && + + # Try pushing into a repository with unrelated change + ( + cd testrepo && + git reset --hard initial && + echo unrelated >path1 && + echo irrelevant >path5 && + git add path5 + ) && + git push testrepo master && + ( + cd testrepo && + test "$(cat path1)" = unrelated && + test "$(cat path5)" = irrelevant && + test "$(git diff --name-only --cached HEAD)" = path5 && + test $(git -C .. rev-parse HEAD) = $(git rev-parse HEAD) + ) && + + # push into void + rm -fr void && + git init void && + ( + cd void && + git config receive.denyCurrentBranch updateInstead && + write_script .git/hooks/push-to-checkout <<-\EOF + if git rev-parse --quiet --verify HEAD + then + has_head=yes + echo >&2 updating from $(git rev-parse HEAD) + else + has_head=no + echo >&2 pushing into void + fi + echo >&2 updating to "$1" + + git update-index -q --refresh && + case "$has_head" in + yes) + git read-tree -u -m HEAD "$1" ;; + no) + git read-tree -u -m "$1" ;; + esac || { + status=$? + echo >&2 read-tree failed + exit $status + } + EOF + ) && + + git push void master && + ( + cd void && + git diff --quiet && + git diff --cached --quiet && + test $(git -C .. rev-parse HEAD) = $(git rev-parse HEAD) + ) +' + test_done diff --git a/t/t5520-pull.sh b/t/t5520-pull.sh index 227d293350..a0013ee32f 100755 --- a/t/t5520-pull.sh +++ b/t/t5520-pull.sh @@ -9,36 +9,27 @@ modify () { mv "$2.x" "$2" } -D=`pwd` - test_expect_success setup ' - echo file >file && git add file && git commit -a -m original - ' test_expect_success 'pulling into void' ' - mkdir cloned && - cd cloned && - git init && - git pull .. -' - -cd "$D" - -test_expect_success 'checking the results' ' + git init cloned && + ( + cd cloned && + git pull .. + ) && test -f file && test -f cloned/file && test_cmp file cloned/file ' test_expect_success 'pulling into void using master:master' ' - mkdir cloned-uho && + git init cloned-uho && ( cd cloned-uho && - git init && git pull .. master:master ) && test -f file && @@ -71,7 +62,6 @@ test_expect_success 'pulling into void does not overwrite staged files' ' ) ' - test_expect_success 'pulling into void does not remove new staged files' ' git init cloned-staged-new && ( @@ -86,17 +76,29 @@ test_expect_success 'pulling into void does not remove new staged files' ' ) ' -test_expect_success 'test . as a remote' ' +test_expect_success 'pulling into void must not create an octopus' ' + git init cloned-octopus && + ( + cd cloned-octopus && + test_must_fail git pull .. master master && + ! test -f file + ) +' +test_expect_success 'test . as a remote' ' git branch copy master && git config branch.copy.remote . && git config branch.copy.merge refs/heads/master && echo updated >file && git commit -a -m updated && git checkout copy && - test `cat file` = file && + test "$(cat file)" = file && git pull && - test `cat file` = updated + test "$(cat file)" = updated && + git reflog -1 >reflog.actual && + sed "s/^[0-9a-f][0-9a-f]*/OBJID/" reflog.actual >reflog.fuzzy && + echo "OBJID HEAD@{0}: pull: Fast-forward" >reflog.expected && + test_cmp reflog.expected reflog.fuzzy ' test_expect_success 'the default remote . should not break explicit pull' ' @@ -105,9 +107,120 @@ test_expect_success 'the default remote . should not break explicit pull' ' git commit -a -m modified && git checkout copy && git reset --hard HEAD^ && - test `cat file` = file && + test "$(cat file)" = file && git pull . second && - test `cat file` = modified + test "$(cat file)" = modified && + git reflog -1 >reflog.actual && + sed "s/^[0-9a-f][0-9a-f]*/OBJID/" reflog.actual >reflog.fuzzy && + echo "OBJID HEAD@{0}: pull . second: Fast-forward" >reflog.expected && + test_cmp reflog.expected reflog.fuzzy +' + +test_expect_success 'fail if wildcard spec does not match any refs' ' + git checkout -b test copy^ && + test_when_finished "git checkout -f copy && git branch -D test" && + test "$(cat file)" = file && + test_must_fail git pull . "refs/nonexisting1/*:refs/nonexisting2/*" 2>err && + test_i18ngrep "no candidates for merging" err && + test "$(cat file)" = file +' + +test_expect_success 'fail if no branches specified with non-default remote' ' + git remote add test_remote . && + test_when_finished "git remote remove test_remote" && + git checkout -b test copy^ && + test_when_finished "git checkout -f copy && git branch -D test" && + test "$(cat file)" = file && + test_config branch.test.remote origin && + test_must_fail git pull test_remote 2>err && + test_i18ngrep "specify a branch on the command line" err && + test "$(cat file)" = file +' + +test_expect_success 'fail if not on a branch' ' + git remote add origin . && + test_when_finished "git remote remove origin" && + git checkout HEAD^ && + test_when_finished "git checkout -f copy" && + test "$(cat file)" = file && + test_must_fail git pull 2>err && + test_i18ngrep "not currently on a branch" err && + test "$(cat file)" = file +' + +test_expect_success 'fail if no configuration for current branch' ' + git remote add test_remote . && + test_when_finished "git remote remove test_remote" && + git checkout -b test copy^ && + test_when_finished "git checkout -f copy && git branch -D test" && + test_config branch.test.remote test_remote && + test "$(cat file)" = file && + test_must_fail git pull 2>err && + test_i18ngrep "no tracking information" err && + test "$(cat file)" = file +' + +test_expect_success 'pull --all: fail if no configuration for current branch' ' + git remote add test_remote . && + test_when_finished "git remote remove test_remote" && + git checkout -b test copy^ && + test_when_finished "git checkout -f copy && git branch -D test" && + test_config branch.test.remote test_remote && + test "$(cat file)" = file && + test_must_fail git pull --all 2>err && + test_i18ngrep "There is no tracking information" err && + test "$(cat file)" = file +' + +test_expect_success 'fail if upstream branch does not exist' ' + git checkout -b test copy^ && + test_when_finished "git checkout -f copy && git branch -D test" && + test_config branch.test.remote . && + test_config branch.test.merge refs/heads/nonexisting && + test "$(cat file)" = file && + test_must_fail git pull 2>err && + test_i18ngrep "no such ref was fetched" err && + test "$(cat file)" = file +' + +test_expect_success 'fail if the index has unresolved entries' ' + git checkout -b third second^ && + test_when_finished "git checkout -f copy && git branch -D third" && + test "$(cat file)" = file && + test_commit modified2 file && + test -z "$(git ls-files -u)" && + test_must_fail git pull . second && + test -n "$(git ls-files -u)" && + cp file expected && + test_must_fail git pull . second 2>err && + test_i18ngrep "Pull is not possible because you have unmerged files" err && + test_cmp expected file && + git add file && + test -z "$(git ls-files -u)" && + test_must_fail git pull . second 2>err && + test_i18ngrep "You have not concluded your merge" err && + test_cmp expected file +' + +test_expect_success 'fast-forwards working tree if branch head is updated' ' + git checkout -b third second^ && + test_when_finished "git checkout -f copy && git branch -D third" && + test "$(cat file)" = file && + git pull . second:third 2>err && + test_i18ngrep "fetch updated the current branch head" err && + test "$(cat file)" = modified && + test "$(git rev-parse third)" = "$(git rev-parse second)" +' + +test_expect_success 'fast-forward fails with conflicting work tree' ' + git checkout -b third second^ && + test_when_finished "git checkout -f copy && git branch -D third" && + test "$(cat file)" = file && + echo conflict >file && + test_must_fail git pull . second:third 2>err && + test_i18ngrep "Cannot fast-forward your working tree" err && + test "$(cat file)" = conflict && + test "$(git rev-parse third)" = "$(git rev-parse second)" ' test_expect_success '--rebase' ' @@ -120,23 +233,43 @@ test_expect_success '--rebase' ' git commit -m "new file" && git tag before-rebase && git pull --rebase . copy && - test $(git rev-parse HEAD^) = $(git rev-parse copy) && - test new = $(git show HEAD:file2) + test "$(git rev-parse HEAD^)" = "$(git rev-parse copy)" && + test new = "$(git show HEAD:file2)" ' + +test_expect_success '--rebase fails with multiple branches' ' + git reset --hard before-rebase && + test_must_fail git pull --rebase . copy master 2>err && + test "$(git rev-parse HEAD)" = "$(git rev-parse before-rebase)" && + test_i18ngrep "Cannot rebase onto multiple branches" err && + test modified = "$(git show HEAD:file)" +' + +test_expect_success 'pull --rebase succeeds with dirty working directory and rebase.autostash set' ' + test_config rebase.autostash true && + git reset --hard before-rebase && + echo dirty >new_file && + git add new_file && + git pull --rebase . copy && + test_cmp_rev HEAD^ copy && + test "$(cat new_file)" = dirty && + test "$(cat file)" = "modified again" +' + test_expect_success 'pull.rebase' ' git reset --hard before-rebase && test_config pull.rebase true && git pull . copy && - test $(git rev-parse HEAD^) = $(git rev-parse copy) && - test new = $(git show HEAD:file2) + test "$(git rev-parse HEAD^)" = "$(git rev-parse copy)" && + test new = "$(git show HEAD:file2)" ' test_expect_success 'branch.to-rebase.rebase' ' git reset --hard before-rebase && test_config branch.to-rebase.rebase true && git pull . copy && - test $(git rev-parse HEAD^) = $(git rev-parse copy) && - test new = $(git show HEAD:file2) + test "$(git rev-parse HEAD^)" = "$(git rev-parse copy)" && + test new = "$(git show HEAD:file2)" ' test_expect_success 'branch.to-rebase.rebase should override pull.rebase' ' @@ -144,8 +277,8 @@ test_expect_success 'branch.to-rebase.rebase should override pull.rebase' ' test_config pull.rebase true && test_config branch.to-rebase.rebase false && git pull . copy && - test $(git rev-parse HEAD^) != $(git rev-parse copy) && - test new = $(git show HEAD:file2) + test "$(git rev-parse HEAD^)" != "$(git rev-parse copy)" && + test new = "$(git show HEAD:file2)" ' # add a feature branch, keep-merge, that is merged into master, so the @@ -164,33 +297,33 @@ test_expect_success 'pull.rebase=false create a new merge commit' ' git reset --hard before-preserve-rebase && test_config pull.rebase false && git pull . copy && - test $(git rev-parse HEAD^1) = $(git rev-parse before-preserve-rebase) && - test $(git rev-parse HEAD^2) = $(git rev-parse copy) && - test file3 = $(git show HEAD:file3.t) + test "$(git rev-parse HEAD^1)" = "$(git rev-parse before-preserve-rebase)" && + test "$(git rev-parse HEAD^2)" = "$(git rev-parse copy)" && + test file3 = "$(git show HEAD:file3.t)" ' test_expect_success 'pull.rebase=true flattens keep-merge' ' git reset --hard before-preserve-rebase && test_config pull.rebase true && git pull . copy && - test $(git rev-parse HEAD^^) = $(git rev-parse copy) && - test file3 = $(git show HEAD:file3.t) + test "$(git rev-parse HEAD^^)" = "$(git rev-parse copy)" && + test file3 = "$(git show HEAD:file3.t)" ' test_expect_success 'pull.rebase=1 is treated as true and flattens keep-merge' ' git reset --hard before-preserve-rebase && test_config pull.rebase 1 && git pull . copy && - test $(git rev-parse HEAD^^) = $(git rev-parse copy) && - test file3 = $(git show HEAD:file3.t) + test "$(git rev-parse HEAD^^)" = "$(git rev-parse copy)" && + test file3 = "$(git show HEAD:file3.t)" ' test_expect_success 'pull.rebase=preserve rebases and merges keep-merge' ' git reset --hard before-preserve-rebase && test_config pull.rebase preserve && git pull . copy && - test $(git rev-parse HEAD^^) = $(git rev-parse copy) && - test $(git rev-parse HEAD^2) = $(git rev-parse keep-merge) + test "$(git rev-parse HEAD^^)" = "$(git rev-parse copy)" && + test "$(git rev-parse HEAD^2)" = "$(git rev-parse keep-merge)" ' test_expect_success 'pull.rebase=invalid fails' ' @@ -203,25 +336,25 @@ test_expect_success '--rebase=false create a new merge commit' ' git reset --hard before-preserve-rebase && test_config pull.rebase true && git pull --rebase=false . copy && - test $(git rev-parse HEAD^1) = $(git rev-parse before-preserve-rebase) && - test $(git rev-parse HEAD^2) = $(git rev-parse copy) && - test file3 = $(git show HEAD:file3.t) + test "$(git rev-parse HEAD^1)" = "$(git rev-parse before-preserve-rebase)" && + test "$(git rev-parse HEAD^2)" = "$(git rev-parse copy)" && + test file3 = "$(git show HEAD:file3.t)" ' test_expect_success '--rebase=true rebases and flattens keep-merge' ' git reset --hard before-preserve-rebase && test_config pull.rebase preserve && git pull --rebase=true . copy && - test $(git rev-parse HEAD^^) = $(git rev-parse copy) && - test file3 = $(git show HEAD:file3.t) + test "$(git rev-parse HEAD^^)" = "$(git rev-parse copy)" && + test file3 = "$(git show HEAD:file3.t)" ' test_expect_success '--rebase=preserve rebases and merges keep-merge' ' git reset --hard before-preserve-rebase && test_config pull.rebase true && git pull --rebase=preserve . copy && - test $(git rev-parse HEAD^^) = $(git rev-parse copy) && - test $(git rev-parse HEAD^2) = $(git rev-parse keep-merge) + test "$(git rev-parse HEAD^^)" = "$(git rev-parse copy)" && + test "$(git rev-parse HEAD^2)" = "$(git rev-parse keep-merge)" ' test_expect_success '--rebase=invalid fails' ' @@ -233,8 +366,8 @@ test_expect_success '--rebase overrides pull.rebase=preserve and flattens keep-m git reset --hard before-preserve-rebase && test_config pull.rebase preserve && git pull --rebase . copy && - test $(git rev-parse HEAD^^) = $(git rev-parse copy) && - test file3 = $(git show HEAD:file3.t) + test "$(git rev-parse HEAD^^)" = "$(git rev-parse copy)" && + test file3 = "$(git show HEAD:file3.t)" ' test_expect_success '--rebase with rebased upstream' ' @@ -251,10 +384,18 @@ test_expect_success '--rebase with rebased upstream' ' git tag to-rebase-orig && git pull --rebase me copy && test "conflicting modification" = "$(cat file)" && - test file = $(cat file2) + test file = "$(cat file2)" ' +test_expect_success '--rebase -f with rebased upstream' ' + test_when_finished "test_might_fail git rebase --abort" && + git reset --hard to-rebase-orig && + git pull --rebase -f me copy && + test "conflicting modification" = "$(cat file)" && + test file = "$(cat file2)" +' + test_expect_success '--rebase with rebased default upstream' ' git update-ref refs/remotes/me/copy copy-orig && @@ -262,7 +403,7 @@ test_expect_success '--rebase with rebased default upstream' ' git reset --hard to-rebase-orig && git pull --rebase && test "conflicting modification" = "$(cat file)" && - test file = $(cat file2) + test file = "$(cat file2)" ' @@ -283,7 +424,7 @@ test_expect_success 'pull --rebase dies early with dirty working directory' ' git checkout to-rebase && git update-ref refs/remotes/me/copy copy^ && - COPY=$(git rev-parse --verify me/copy) && + COPY="$(git rev-parse --verify me/copy)" && git rebase --onto $COPY copy && test_config branch.to-rebase.remote me && test_config branch.to-rebase.merge refs/heads/copy && @@ -291,10 +432,10 @@ test_expect_success 'pull --rebase dies early with dirty working directory' ' echo dirty >> file && git add file && test_must_fail git pull && - test $COPY = $(git rev-parse --verify me/copy) && + test "$COPY" = "$(git rev-parse --verify me/copy)" && git checkout HEAD -- file && git pull && - test $COPY != $(git rev-parse --verify me/copy) + test "$COPY" != "$(git rev-parse --verify me/copy)" ' @@ -309,6 +450,21 @@ test_expect_success 'pull --rebase works on branch yet to be born' ' test_cmp expect actual ' +test_expect_success 'pull --rebase fails on unborn branch with staged changes' ' + test_when_finished "rm -rf empty_repo2" && + git init empty_repo2 && + ( + cd empty_repo2 && + echo staged-file >staged-file && + git add staged-file && + test "$(git ls-files)" = staged-file && + test_must_fail git pull --rebase .. master 2>err && + test "$(git ls-files)" = staged-file && + test "$(git show :staged-file)" = staged-file && + test_i18ngrep "unborn branch with changes added to the index" err + ) +' + test_expect_success 'setup for detecting upstreamed changes' ' mkdir src && (cd src && diff --git a/t/t5521-pull-options.sh b/t/t5521-pull-options.sh index 453aba53f4..18372caa15 100755 --- a/t/t5521-pull-options.sh +++ b/t/t5521-pull-options.sh @@ -117,4 +117,31 @@ test_expect_success 'git pull --all' ' ) ' +test_expect_success 'git pull --dry-run' ' + test_when_finished "rm -rf clonedry" && + git init clonedry && + ( + cd clonedry && + git pull --dry-run ../parent && + test_path_is_missing .git/FETCH_HEAD && + test_path_is_missing .git/refs/heads/master && + test_path_is_missing .git/index && + test_path_is_missing file + ) +' + +test_expect_success 'git pull --all --dry-run' ' + test_when_finished "rm -rf cloneddry" && + git init clonedry && + ( + cd clonedry && + git remote add origin ../parent && + git pull --all --dry-run && + test_path_is_missing .git/FETCH_HEAD && + test_path_is_missing .git/refs/remotes/origin/master && + test_path_is_missing .git/index && + test_path_is_missing file + ) +' + test_done diff --git a/t/t5524-pull-msg.sh b/t/t5524-pull-msg.sh index 8cccecc2fc..c278adaa5a 100755 --- a/t/t5524-pull-msg.sh +++ b/t/t5524-pull-msg.sh @@ -17,6 +17,9 @@ test_expect_success setup ' git commit -m "add bfile" ) && test_tick && test_tick && + echo "second" >afile && + git add afile && + git commit -m "second commit" && echo "original $dollar" >afile && git add afile && git commit -m "do not clobber $dollar signs" @@ -32,4 +35,18 @@ test_expect_success pull ' ) ' +test_expect_success '--log=1 limits shortlog length' ' +( + cd cloned && + git reset --hard HEAD^ && + test "$(cat afile)" = original && + test "$(cat bfile)" = added && + git pull --log=1 && + git log -3 && + git cat-file commit HEAD >result && + grep Dollar result && + ! grep "second commit" result +) +' + test_done diff --git a/t/t5526-fetch-submodules.sh b/t/t5526-fetch-submodules.sh index ca5b027c55..a4532b00d6 100755 --- a/t/t5526-fetch-submodules.sh +++ b/t/t5526-fetch-submodules.sh @@ -216,7 +216,7 @@ test_expect_success "Recursion stops when no new submodule commits are fetched" head2=$(git rev-parse --short HEAD) && echo "Fetching submodule submodule" > expect.out.sub && echo "From $pwd/." > expect.err.sub && - echo " $head1..$head2 master -> origin/master" >> expect.err.sub + echo " $head1..$head2 master -> origin/master" >>expect.err.sub && head -2 expect.err >> expect.err.sub && ( cd downstream && @@ -315,7 +315,7 @@ test_expect_success "'--recurse-submodules=on-demand' doesn't recurse when no ne ) && head1=$(git rev-parse --short HEAD^) && git add subdir/deepsubmodule && - git commit -m "new deepsubmodule" + git commit -m "new deepsubmodule" && head2=$(git rev-parse --short HEAD) && echo "From $pwd/submodule" > ../expect.err.sub && echo " $head1..$head2 master -> origin/master" >> ../expect.err.sub @@ -337,7 +337,7 @@ test_expect_success "'--recurse-submodules=on-demand' recurses as deep as necess head2=$(git rev-parse --short HEAD) && tail -2 expect.err > expect.err.deepsub && echo "From $pwd/." > expect.err && - echo " $head1..$head2 master -> origin/master" >> expect.err + echo " $head1..$head2 master -> origin/master" >>expect.err && cat expect.err.sub >> expect.err && cat expect.err.deepsub >> expect.err && ( @@ -387,7 +387,7 @@ test_expect_success "'fetch.recurseSubmodules=on-demand' overrides global config git commit -m "new submodule" && head2=$(git rev-parse --short HEAD) && echo "From $pwd/." > expect.err.2 && - echo " $head1..$head2 master -> origin/master" >> expect.err.2 + echo " $head1..$head2 master -> origin/master" >>expect.err.2 && head -2 expect.err >> expect.err.2 && ( cd downstream && @@ -415,7 +415,7 @@ test_expect_success "'submodule.<sub>.fetchRecurseSubmodules=on-demand' override git commit -m "new submodule" && head2=$(git rev-parse --short HEAD) && echo "From $pwd/." > expect.err.2 && - echo " $head1..$head2 master -> origin/master" >> expect.err.2 + echo " $head1..$head2 master -> origin/master" >>expect.err.2 && head -2 expect.err >> expect.err.2 && ( cd downstream && diff --git a/t/t5527-fetch-odd-refs.sh b/t/t5527-fetch-odd-refs.sh index edea9f957e..207899a99f 100755 --- a/t/t5527-fetch-odd-refs.sh +++ b/t/t5527-fetch-odd-refs.sh @@ -26,4 +26,37 @@ test_expect_success 'suffix ref is ignored during fetch' ' test_cmp expect actual ' +test_expect_success 'try to create repo with absurdly long refname' ' + ref240=$_z40/$_z40/$_z40/$_z40/$_z40/$_z40 && + ref1440=$ref240/$ref240/$ref240/$ref240/$ref240/$ref240 && + git init long && + ( + cd long && + test_commit long && + test_commit master + ) && + if git -C long update-ref refs/heads/$ref1440 long; then + test_set_prereq LONG_REF + else + echo >&2 "long refs not supported" + fi +' + +test_expect_success LONG_REF 'fetch handles extremely long refname' ' + git fetch long refs/heads/*:refs/remotes/long/* && + cat >expect <<-\EOF && + long + master + EOF + git for-each-ref --format="%(subject)" refs/remotes/long >actual && + test_cmp expect actual +' + +test_expect_success LONG_REF 'push handles extremely long refname' ' + git push long :refs/heads/$ref1440 && + git -C long for-each-ref --format="%(subject)" refs/heads >actual && + echo master >expect && + test_cmp expect actual +' + test_done diff --git a/t/t5528-push-default.sh b/t/t5528-push-default.sh index 6a5ac3add4..73f4bb6346 100755 --- a/t/t5528-push-default.sh +++ b/t/t5528-push-default.sh @@ -26,7 +26,7 @@ check_pushed_commit () { # $2 = expected target branch for the push # $3 = [optional] repo to check for actual output (repo1 by default) test_push_success () { - git -c push.default="$1" push && + git ${1:+-c} ${1:+push.default="$1"} push && check_pushed_commit HEAD "$2" "$3" } @@ -34,7 +34,7 @@ test_push_success () { # check that push fails and does not modify any remote branch test_push_failure () { git --git-dir=repo1 log --no-walk --format='%h %s' --all >expect && - test_must_fail git -c push.default="$1" push && + test_must_fail git ${1:+-c} ${1:+push.default="$1"} push && git --git-dir=repo1 log --no-walk --format='%h %s' --all >actual && test_cmp expect actual } @@ -172,4 +172,32 @@ test_pushdefault_workflow success simple master triangular # master is updated (parent2 does not have foo) test_pushdefault_workflow success matching master triangular +# default tests, when no push-default is specified. This +# should behave the same as "simple" in non-triangular +# settings, and as "current" otherwise. + +test_expect_success 'default behavior allows "simple" push' ' + test_config branch.master.remote parent1 && + test_config branch.master.merge refs/heads/master && + test_config remote.pushdefault parent1 && + test_commit default-master-master && + test_push_success "" master +' + +test_expect_success 'default behavior rejects non-simple push' ' + test_config branch.master.remote parent1 && + test_config branch.master.merge refs/heads/foo && + test_config remote.pushdefault parent1 && + test_commit default-master-foo && + test_push_failure "" +' + +test_expect_success 'default triangular behavior acts like "current"' ' + test_config branch.master.remote parent1 && + test_config branch.master.merge refs/heads/foo && + test_config remote.pushdefault parent2 && + test_commit default-triangular && + test_push_success "" master repo2 +' + test_done diff --git a/t/t5531-deep-submodule-push.sh b/t/t5531-deep-submodule-push.sh index 445bb5fe26..198ce84754 100755 --- a/t/t5531-deep-submodule-push.sh +++ b/t/t5531-deep-submodule-push.sh @@ -64,7 +64,12 @@ test_expect_success 'push fails if submodule commit not on remote' ' cd work && git add gar/bage && git commit -m "Third commit for gar/bage" && - test_must_fail git push --recurse-submodules=check ../pub.git master + # the push should fail with --recurse-submodules=check + # on the command line... + test_must_fail git push --recurse-submodules=check ../pub.git master && + + # ...or if specified in the configuration.. + test_must_fail git -c push.recurseSubmodules=check push ../pub.git master ) ' @@ -79,6 +84,216 @@ test_expect_success 'push succeeds after commit was pushed to remote' ' ) ' +test_expect_success 'push succeeds if submodule commit not on remote but using on-demand on command line' ' + ( + cd work/gar/bage && + >recurse-on-demand-on-command-line && + git add recurse-on-demand-on-command-line && + git commit -m "Recurse on-demand on command line junk" + ) && + ( + cd work && + git add gar/bage && + git commit -m "Recurse on-demand on command line for gar/bage" && + git push --recurse-submodules=on-demand ../pub.git master && + # Check that the supermodule commit got there + git fetch ../pub.git && + git diff --quiet FETCH_HEAD master && + # Check that the submodule commit got there too + cd gar/bage && + git diff --quiet origin/master master + ) +' + +test_expect_success 'push succeeds if submodule commit not on remote but using on-demand from config' ' + ( + cd work/gar/bage && + >recurse-on-demand-from-config && + git add recurse-on-demand-from-config && + git commit -m "Recurse on-demand from config junk" + ) && + ( + cd work && + git add gar/bage && + git commit -m "Recurse on-demand from config for gar/bage" && + git -c push.recurseSubmodules=on-demand push ../pub.git master && + # Check that the supermodule commit got there + git fetch ../pub.git && + git diff --quiet FETCH_HEAD master && + # Check that the submodule commit got there too + cd gar/bage && + git diff --quiet origin/master master + ) +' + +test_expect_success 'push recurse-submodules on command line overrides config' ' + ( + cd work/gar/bage && + >recurse-check-on-command-line-overriding-config && + git add recurse-check-on-command-line-overriding-config && + git commit -m "Recurse on command-line overriding config junk" + ) && + ( + cd work && + git add gar/bage && + git commit -m "Recurse on command-line overriding config for gar/bage" && + + # Ensure that we can override on-demand in the config + # to just check submodules + test_must_fail git -c push.recurseSubmodules=on-demand push --recurse-submodules=check ../pub.git master && + # Check that the supermodule commit did not get there + git fetch ../pub.git && + git diff --quiet FETCH_HEAD master^ && + # Check that the submodule commit did not get there + (cd gar/bage && git diff --quiet origin/master master^) && + + # Ensure that we can override check in the config to + # disable submodule recursion entirely + (cd gar/bage && git diff --quiet origin/master master^) && + git -c push.recurseSubmodules=on-demand push --recurse-submodules=no ../pub.git master && + git fetch ../pub.git && + git diff --quiet FETCH_HEAD master && + (cd gar/bage && git diff --quiet origin/master master^) && + + # Ensure that we can override check in the config to + # disable submodule recursion entirely (alternative form) + git -c push.recurseSubmodules=on-demand push --no-recurse-submodules ../pub.git master && + git fetch ../pub.git && + git diff --quiet FETCH_HEAD master && + (cd gar/bage && git diff --quiet origin/master master^) && + + # Ensure that we can override check in the config to + # push the submodule too + git -c push.recurseSubmodules=check push --recurse-submodules=on-demand ../pub.git master && + git fetch ../pub.git && + git diff --quiet FETCH_HEAD master && + (cd gar/bage && git diff --quiet origin/master master) + ) +' + +test_expect_success 'push recurse-submodules last one wins on command line' ' + ( + cd work/gar/bage && + >recurse-check-on-command-line-overriding-earlier-command-line && + git add recurse-check-on-command-line-overriding-earlier-command-line && + git commit -m "Recurse on command-line overridiing earlier command-line junk" + ) && + ( + cd work && + git add gar/bage && + git commit -m "Recurse on command-line overriding earlier command-line for gar/bage" && + + # should result in "check" + test_must_fail git push --recurse-submodules=on-demand --recurse-submodules=check ../pub.git master && + # Check that the supermodule commit did not get there + git fetch ../pub.git && + git diff --quiet FETCH_HEAD master^ && + # Check that the submodule commit did not get there + (cd gar/bage && git diff --quiet origin/master master^) && + + # should result in "no" + git push --recurse-submodules=on-demand --recurse-submodules=no ../pub.git master && + # Check that the supermodule commit did get there + git fetch ../pub.git && + git diff --quiet FETCH_HEAD master && + # Check that the submodule commit did not get there + (cd gar/bage && git diff --quiet origin/master master^) && + + # should result in "no" + git push --recurse-submodules=on-demand --no-recurse-submodules ../pub.git master && + # Check that the submodule commit did not get there + (cd gar/bage && git diff --quiet origin/master master^) && + + # But the options in the other order should push the submodule + git push --recurse-submodules=check --recurse-submodules=on-demand ../pub.git master && + # Check that the submodule commit did get there + git fetch ../pub.git && + (cd gar/bage && git diff --quiet origin/master master) + ) +' + +test_expect_success 'push succeeds if submodule commit not on remote using on-demand from cmdline overriding config' ' + ( + cd work/gar/bage && + >recurse-on-demand-on-command-line-overriding-config && + git add recurse-on-demand-on-command-line-overriding-config && + git commit -m "Recurse on-demand on command-line overriding config junk" + ) && + ( + cd work && + git add gar/bage && + git commit -m "Recurse on-demand on command-line overriding config for gar/bage" && + git -c push.recurseSubmodules=check push --recurse-submodules=on-demand ../pub.git master && + # Check that the supermodule commit got there + git fetch ../pub.git && + git diff --quiet FETCH_HEAD master && + # Check that the submodule commit got there + cd gar/bage && + git diff --quiet origin/master master + ) +' + +test_expect_success 'push succeeds if submodule commit disabling recursion from cmdline overriding config' ' + ( + cd work/gar/bage && + >recurse-disable-on-command-line-overriding-config && + git add recurse-disable-on-command-line-overriding-config && + git commit -m "Recurse disable on command-line overriding config junk" + ) && + ( + cd work && + git add gar/bage && + git commit -m "Recurse disable on command-line overriding config for gar/bage" && + git -c push.recurseSubmodules=check push --recurse-submodules=no ../pub.git master && + # Check that the supermodule commit got there + git fetch ../pub.git && + git diff --quiet FETCH_HEAD master && + # But that the submodule commit did not + ( cd gar/bage && git diff --quiet origin/master master^ ) && + # Now push it to avoid confusing future tests + git push --recurse-submodules=on-demand ../pub.git master + ) +' + +test_expect_success 'push succeeds if submodule commit disabling recursion from cmdline (alternative form) overriding config' ' + ( + cd work/gar/bage && + >recurse-disable-on-command-line-alt-overriding-config && + git add recurse-disable-on-command-line-alt-overriding-config && + git commit -m "Recurse disable on command-line alternative overriding config junk" + ) && + ( + cd work && + git add gar/bage && + git commit -m "Recurse disable on command-line alternative overriding config for gar/bage" && + git -c push.recurseSubmodules=check push --no-recurse-submodules ../pub.git master && + # Check that the supermodule commit got there + git fetch ../pub.git && + git diff --quiet FETCH_HEAD master && + # But that the submodule commit did not + ( cd gar/bage && git diff --quiet origin/master master^ ) && + # Now push it to avoid confusing future tests + git push --recurse-submodules=on-demand ../pub.git master + ) +' + +test_expect_success 'push fails if recurse submodules option passed as yes' ' + ( + cd work/gar/bage && + >recurse-push-fails-if-recurse-submodules-passed-as-yes && + git add recurse-push-fails-if-recurse-submodules-passed-as-yes && + git commit -m "Recurse push fails if recurse submodules option passed as yes" + ) && + ( + cd work && + git add gar/bage && + git commit -m "Recurse push fails if recurse submodules option passed as yes for gar/bage" && + test_must_fail git push --recurse-submodules=yes ../pub.git master && + test_must_fail git -c push.recurseSubmodules=yes push ../pub.git master && + git push --recurse-submodules=on-demand ../pub.git master + ) +' + test_expect_success 'push fails when commit on multiple branches if one branch has no remote' ' ( cd work/gar/bage && @@ -104,7 +319,7 @@ test_expect_success 'push fails when commit on multiple branches if one branch h ' test_expect_success 'push succeeds if submodule has no remote and is on the first superproject commit' ' - git init --bare a + git init --bare a && git clone a a1 && ( cd a1 && diff --git a/t/t5533-push-cas.sh b/t/t5533-push-cas.sh index ba20d83333..c402d8d3d7 100755 --- a/t/t5533-push-cas.sh +++ b/t/t5533-push-cas.sh @@ -14,7 +14,7 @@ setup_srcdst_basic () { } test_expect_success setup ' - : create template repository + # create template repository test_commit A && test_commit B && test_commit C @@ -159,7 +159,7 @@ test_expect_success 'cover everything with default force-with-lease (protected)' ( cd src && git branch naster master^ - ) + ) && git ls-remote src refs/heads/\* >expect && ( cd dst && @@ -174,7 +174,7 @@ test_expect_success 'cover everything with default force-with-lease (allowed)' ' ( cd src && git branch naster master^ - ) + ) && ( cd dst && git fetch && diff --git a/t/t5534-push-signed.sh b/t/t5534-push-signed.sh new file mode 100755 index 0000000000..ecb8d446a5 --- /dev/null +++ b/t/t5534-push-signed.sh @@ -0,0 +1,171 @@ +#!/bin/sh + +test_description='signed push' + +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-gpg.sh + +prepare_dst () { + rm -fr dst && + test_create_repo dst && + + git push dst master:noop master:ff master:noff +} + +test_expect_success setup ' + # master, ff and noff branches pointing at the same commit + test_tick && + git commit --allow-empty -m initial && + + git checkout -b noop && + git checkout -b ff && + git checkout -b noff && + + # noop stays the same, ff advances, noff rewrites + test_tick && + git commit --allow-empty --amend -m rewritten && + git checkout ff && + + test_tick && + git commit --allow-empty -m second +' + +test_expect_success 'unsigned push does not send push certificate' ' + prepare_dst && + mkdir -p dst/.git/hooks && + write_script dst/.git/hooks/post-receive <<-\EOF && + # discard the update list + cat >/dev/null + # record the push certificate + if test -n "${GIT_PUSH_CERT-}" + then + git cat-file blob $GIT_PUSH_CERT >../push-cert + fi + EOF + + git push dst noop ff +noff && + ! test -f dst/push-cert +' + +test_expect_success 'talking with a receiver without push certificate support' ' + prepare_dst && + mkdir -p dst/.git/hooks && + write_script dst/.git/hooks/post-receive <<-\EOF && + # discard the update list + cat >/dev/null + # record the push certificate + if test -n "${GIT_PUSH_CERT-}" + then + git cat-file blob $GIT_PUSH_CERT >../push-cert + fi + EOF + + git push dst noop ff +noff && + ! test -f dst/push-cert +' + +test_expect_success 'push --signed fails with a receiver without push certificate support' ' + prepare_dst && + mkdir -p dst/.git/hooks && + test_must_fail git push --signed dst noop ff +noff 2>err && + test_i18ngrep "the receiving end does not support" err +' + +test_expect_success GPG 'no certificate for a signed push with no update' ' + prepare_dst && + mkdir -p dst/.git/hooks && + write_script dst/.git/hooks/post-receive <<-\EOF && + if test -n "${GIT_PUSH_CERT-}" + then + git cat-file blob $GIT_PUSH_CERT >../push-cert + fi + EOF + git push dst noop && + ! test -f dst/push-cert +' + +test_expect_success GPG 'signed push sends push certificate' ' + prepare_dst && + mkdir -p dst/.git/hooks && + git -C dst config receive.certnonceseed sekrit && + write_script dst/.git/hooks/post-receive <<-\EOF && + # discard the update list + cat >/dev/null + # record the push certificate + if test -n "${GIT_PUSH_CERT-}" + then + git cat-file blob $GIT_PUSH_CERT >../push-cert + fi && + + cat >../push-cert-status <<E_O_F + SIGNER=${GIT_PUSH_CERT_SIGNER-nobody} + KEY=${GIT_PUSH_CERT_KEY-nokey} + STATUS=${GIT_PUSH_CERT_STATUS-nostatus} + NONCE_STATUS=${GIT_PUSH_CERT_NONCE_STATUS-nononcestatus} + NONCE=${GIT_PUSH_CERT_NONCE-nononce} + E_O_F + + EOF + + git push --signed dst noop ff +noff && + + ( + cat <<-\EOF && + SIGNER=C O Mitter <committer@example.com> + KEY=13B6F51ECDDE430D + STATUS=G + NONCE_STATUS=OK + EOF + sed -n -e "s/^nonce /NONCE=/p" -e "/^$/q" dst/push-cert + ) >expect && + + grep "$(git rev-parse noop ff) refs/heads/ff" dst/push-cert && + grep "$(git rev-parse noop noff) refs/heads/noff" dst/push-cert && + test_cmp expect dst/push-cert-status +' + +test_expect_success GPG 'fail without key and heed user.signingkey' ' + prepare_dst && + mkdir -p dst/.git/hooks && + git -C dst config receive.certnonceseed sekrit && + write_script dst/.git/hooks/post-receive <<-\EOF && + # discard the update list + cat >/dev/null + # record the push certificate + if test -n "${GIT_PUSH_CERT-}" + then + git cat-file blob $GIT_PUSH_CERT >../push-cert + fi && + + cat >../push-cert-status <<E_O_F + SIGNER=${GIT_PUSH_CERT_SIGNER-nobody} + KEY=${GIT_PUSH_CERT_KEY-nokey} + STATUS=${GIT_PUSH_CERT_STATUS-nostatus} + NONCE_STATUS=${GIT_PUSH_CERT_NONCE_STATUS-nononcestatus} + NONCE=${GIT_PUSH_CERT_NONCE-nononce} + E_O_F + + EOF + + unset GIT_COMMITTER_EMAIL && + git config user.email hasnokey@nowhere.com && + test_must_fail git push --signed dst noop ff +noff && + git config user.signingkey committer@example.com && + git push --signed dst noop ff +noff && + + ( + cat <<-\EOF && + SIGNER=C O Mitter <committer@example.com> + KEY=13B6F51ECDDE430D + STATUS=G + NONCE_STATUS=OK + EOF + sed -n -e "s/^nonce /NONCE=/p" -e "/^$/q" dst/push-cert + ) >expect && + + grep "$(git rev-parse noop ff) refs/heads/ff" dst/push-cert && + grep "$(git rev-parse noop noff) refs/heads/noff" dst/push-cert && + test_cmp expect dst/push-cert-status +' + +test_done diff --git a/t/t5539-fetch-http-shallow.sh b/t/t5539-fetch-http-shallow.sh index 94553e1039..37a433504e 100755 --- a/t/t5539-fetch-http-shallow.sh +++ b/t/t5539-fetch-http-shallow.sh @@ -3,12 +3,6 @@ test_description='fetch/clone from a shallow clone over http' . ./test-lib.sh - -if test -n "$NO_CURL"; then - skip_all='skipping test, git built without http support' - test_done -fi - . "$TEST_DIRECTORY"/lib-httpd.sh start_httpd @@ -54,6 +48,7 @@ EOF test_expect_success 'no shallow lines after receiving ACK ready' ' ( cd shallow && + test_tick && for i in $(test_seq 15) do git checkout --orphan unrelated$i && diff --git a/t/t5540-http-push-webdav.sh b/t/t5540-http-push-webdav.sh index 8d7b3c57e3..88ff5a49e4 100755 --- a/t/t5540-http-push-webdav.sh +++ b/t/t5540-http-push-webdav.sh @@ -169,7 +169,7 @@ test_expect_failure 'push to password-protected repository (no user in URL)' ' test_commit pw-nouser && set_askpass user@host pass@host && git push "$HTTPD_URL/auth/dumb/test_repo.git" HEAD && - expect_askpass both user@host + expect_askpass both user@host && git rev-parse --verify HEAD >expect && git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/auth/dumb/test_repo.git" \ rev-parse --verify HEAD >actual && diff --git a/t/t5541-http-push-smart.sh b/t/t5541-http-push-smart.sh index 73af16f481..fd7d06b9a2 100755 --- a/t/t5541-http-push-smart.sh +++ b/t/t5541-http-push-smart.sh @@ -6,12 +6,8 @@ test_description='test smart pushing over http via http-backend' . ./test-lib.sh -if test -n "$NO_CURL"; then - skip_all='skipping test, git built without http support' - test_done -fi - ROOT_PATH="$PWD" +. "$TEST_DIRECTORY"/lib-gpg.sh . "$TEST_DIRECTORY"/lib-httpd.sh . "$TEST_DIRECTORY"/lib-terminal.sh start_httpd @@ -157,7 +153,7 @@ test_http_push_nonff "$HTTPD_DOCUMENT_ROOT_PATH"/test_repo.git \ test_expect_success 'push fails for non-fast-forward refs unmatched by remote helper' ' # create a dissimilarly-named remote ref so that git is unable to match the # two refs (viz. local, remote) unless an explicit refspec is provided. - git push origin master:retsam + git push origin master:retsam && echo "change changed" > path2 && git commit -a -m path2 --amend && @@ -323,5 +319,54 @@ test_expect_success 'push into half-auth-complete requires password' ' test_cmp expect actual ' +test_expect_success CMDLINE_LIMIT 'push 2000 tags over http' ' + sha1=$(git rev-parse HEAD) && + test_seq 2000 | + sort | + sed "s|.*|$sha1 refs/tags/really-long-tag-name-&|" \ + >.git/packed-refs && + run_with_limited_cmdline git push --mirror +' + +test_expect_success GPG 'push with post-receive to inspect certificate' ' + ( + cd "$HTTPD_DOCUMENT_ROOT_PATH"/test_repo.git && + mkdir -p hooks && + write_script hooks/post-receive <<-\EOF && + # discard the update list + cat >/dev/null + # record the push certificate + if test -n "${GIT_PUSH_CERT-}" + then + git cat-file blob $GIT_PUSH_CERT >../push-cert + fi && + cat >../push-cert-status <<E_O_F + SIGNER=${GIT_PUSH_CERT_SIGNER-nobody} + KEY=${GIT_PUSH_CERT_KEY-nokey} + STATUS=${GIT_PUSH_CERT_STATUS-nostatus} + NONCE_STATUS=${GIT_PUSH_CERT_NONCE_STATUS-nononcestatus} + NONCE=${GIT_PUSH_CERT_NONCE-nononce} + E_O_F + EOF + + git config receive.certnonceseed sekrit && + git config receive.certnonceslop 30 + ) && + cd "$ROOT_PATH/test_repo_clone" && + test_commit cert-test && + git push --signed "$HTTPD_URL/smart/test_repo.git" && + ( + cd "$HTTPD_DOCUMENT_ROOT_PATH" && + cat <<-\EOF && + SIGNER=C O Mitter <committer@example.com> + KEY=13B6F51ECDDE430D + STATUS=G + NONCE_STATUS=OK + EOF + sed -n -e "s/^nonce /NONCE=/p" -e "/^$/q" push-cert + ) >expect && + test_cmp expect "$HTTPD_DOCUMENT_ROOT_PATH/push-cert-status" +' + stop_httpd test_done diff --git a/t/t5542-push-http-shallow.sh b/t/t5542-push-http-shallow.sh index 2a691e09eb..5165833157 100755 --- a/t/t5542-push-http-shallow.sh +++ b/t/t5542-push-http-shallow.sh @@ -3,12 +3,6 @@ test_description='push from/to a shallow clone over http' . ./test-lib.sh - -if test -n "$NO_CURL"; then - say 'skipping test, git built without http support' - test_done -fi - . "$TEST_DIRECTORY"/lib-httpd.sh start_httpd diff --git a/t/t5543-atomic-push.sh b/t/t5543-atomic-push.sh new file mode 100755 index 0000000000..3480b33007 --- /dev/null +++ b/t/t5543-atomic-push.sh @@ -0,0 +1,194 @@ +#!/bin/sh + +test_description='pushing to a repository using the atomic push option' + +. ./test-lib.sh + +mk_repo_pair () { + rm -rf workbench upstream && + test_create_repo upstream && + test_create_repo workbench && + ( + cd upstream && + git config receive.denyCurrentBranch warn + ) && + ( + cd workbench && + git remote add up ../upstream + ) +} + +# Compare the ref ($1) in upstream with a ref value from workbench ($2) +# i.e. test_refs second HEAD@{2} +test_refs () { + test $# = 2 && + git -C upstream rev-parse --verify "$1" >expect && + git -C workbench rev-parse --verify "$2" >actual && + test_cmp expect actual +} + +test_expect_success 'atomic push works for a single branch' ' + mk_repo_pair && + ( + cd workbench && + test_commit one && + git push --mirror up && + test_commit two && + git push --atomic up master + ) && + test_refs master master +' + +test_expect_success 'atomic push works for two branches' ' + mk_repo_pair && + ( + cd workbench && + test_commit one && + git branch second && + git push --mirror up && + test_commit two && + git checkout second && + test_commit three && + git push --atomic up master second + ) && + test_refs master master && + test_refs second second +' + +test_expect_success 'atomic push works in combination with --mirror' ' + mk_repo_pair && + ( + cd workbench && + test_commit one && + git checkout -b second && + test_commit two && + git push --atomic --mirror up + ) && + test_refs master master && + test_refs second second +' + +test_expect_success 'atomic push works in combination with --force' ' + mk_repo_pair && + ( + cd workbench && + test_commit one && + git branch second master && + test_commit two_a && + git checkout second && + test_commit two_b && + test_commit three_b && + test_commit four && + git push --mirror up && + # The actual test is below + git checkout master && + test_commit three_a && + git checkout second && + git reset --hard HEAD^ && + git push --force --atomic up master second + ) && + test_refs master master && + test_refs second second +' + +# set up two branches where master can be pushed but second can not +# (non-fast-forward). Since second can not be pushed the whole operation +# will fail and leave master untouched. +test_expect_success 'atomic push fails if one branch fails' ' + mk_repo_pair && + ( + cd workbench && + test_commit one && + git checkout -b second master && + test_commit two && + test_commit three && + test_commit four && + git push --mirror up && + git reset --hard HEAD~2 && + test_commit five && + git checkout master && + test_commit six && + test_must_fail git push --atomic --all up + ) && + test_refs master HEAD@{7} && + test_refs second HEAD@{4} +' + +test_expect_success 'atomic push fails if one tag fails remotely' ' + # prepare the repo + mk_repo_pair && + ( + cd workbench && + test_commit one && + git checkout -b second master && + test_commit two && + git push --mirror up + ) && + # a third party modifies the server side: + ( + cd upstream && + git checkout second && + git tag test_tag second + ) && + # see if we can now push both branches. + ( + cd workbench && + git checkout master && + test_commit three && + git checkout second && + test_commit four && + git tag test_tag && + test_must_fail git push --tags --atomic up master second + ) && + test_refs master HEAD@{3} && + test_refs second HEAD@{1} +' + +test_expect_success 'atomic push obeys update hook preventing a branch to be pushed' ' + mk_repo_pair && + ( + cd workbench && + test_commit one && + git checkout -b second master && + test_commit two && + git push --mirror up + ) && + ( + cd upstream && + HOOKDIR="$(git rev-parse --git-dir)/hooks" && + HOOK="$HOOKDIR/update" && + mkdir -p "$HOOKDIR" && + write_script "$HOOK" <<-\EOF + # only allow update to master from now on + test "$1" = "refs/heads/master" + EOF + ) && + ( + cd workbench && + git checkout master && + test_commit three && + git checkout second && + test_commit four && + test_must_fail git push --atomic up master second + ) && + test_refs master HEAD@{3} && + test_refs second HEAD@{1} +' + +test_expect_success 'atomic push is not advertised if configured' ' + mk_repo_pair && + ( + cd upstream + git config receive.advertiseatomic 0 + ) && + ( + cd workbench && + test_commit one && + git push --mirror up && + test_commit two && + test_must_fail git push --atomic up master + ) && + test_refs master HEAD@{1} +' + +test_done diff --git a/t/t5550-http-fetch-dumb.sh b/t/t5550-http-fetch-dumb.sh index 1a3a2b6c1a..87a7aa04ae 100755 --- a/t/t5550-http-fetch-dumb.sh +++ b/t/t5550-http-fetch-dumb.sh @@ -2,12 +2,6 @@ test_description='test dumb fetching over http via static file' . ./test-lib.sh - -if test -n "$NO_CURL"; then - skip_all='skipping test, git built without http support' - test_done -fi - . "$TEST_DIRECTORY"/lib-httpd.sh start_httpd @@ -15,7 +9,7 @@ test_expect_success 'setup repository' ' git config push.default matching && echo content1 >file && git add file && - git commit -m one + git commit -m one && echo content2 >file && git add file && git commit -m two @@ -165,11 +159,96 @@ test_expect_success 'fetch notices corrupt idx' ' ) ' +test_expect_success 'fetch can handle previously-fetched .idx files' ' + git checkout --orphan branch1 && + echo base >file && + git add file && + git commit -m base && + git --bare init "$HTTPD_DOCUMENT_ROOT_PATH"/repo_packed_branches.git && + git push "$HTTPD_DOCUMENT_ROOT_PATH"/repo_packed_branches.git branch1 && + git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH"/repo_packed_branches.git repack -d && + git checkout -b branch2 branch1 && + echo b2 >>file && + git commit -a -m b2 && + git push "$HTTPD_DOCUMENT_ROOT_PATH"/repo_packed_branches.git branch2 && + git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH"/repo_packed_branches.git repack -d && + git --bare init clone_packed_branches.git && + git --git-dir=clone_packed_branches.git fetch "$HTTPD_URL"/dumb/repo_packed_branches.git branch1:branch1 && + git --git-dir=clone_packed_branches.git fetch "$HTTPD_URL"/dumb/repo_packed_branches.git branch2:branch2 +' + test_expect_success 'did not use upload-pack service' ' - grep '/git-upload-pack' <"$HTTPD_ROOT_PATH"/access.log >act - : >exp + test_might_fail grep '/git-upload-pack' <"$HTTPD_ROOT_PATH"/access.log >act && + : >exp && test_cmp exp act ' +test_expect_success 'git client shows text/plain errors' ' + test_must_fail git clone "$HTTPD_URL/error/text" 2>stderr && + grep "this is the error message" stderr +' + +test_expect_success 'git client does not show html errors' ' + test_must_fail git clone "$HTTPD_URL/error/html" 2>stderr && + ! grep "this is the error message" stderr +' + +test_expect_success 'git client shows text/plain with a charset' ' + test_must_fail git clone "$HTTPD_URL/error/charset" 2>stderr && + grep "this is the error message" stderr +' + +test_expect_success 'http error messages are reencoded' ' + test_must_fail git clone "$HTTPD_URL/error/utf16" 2>stderr && + grep "this is the error message" stderr +' + +test_expect_success 'reencoding is robust to whitespace oddities' ' + test_must_fail git clone "$HTTPD_URL/error/odd-spacing" 2>stderr && + grep "this is the error message" stderr +' + +check_language () { + case "$2" in + '') + >expect + ;; + ?*) + echo "Accept-Language: $1" >expect + ;; + esac && + GIT_CURL_VERBOSE=1 \ + LANGUAGE=$2 \ + git ls-remote "$HTTPD_URL/dumb/repo.git" >output 2>&1 && + tr -d '\015' <output | + sort -u | + sed -ne '/^Accept-Language:/ p' >actual && + test_cmp expect actual +} + +test_expect_success 'git client sends Accept-Language based on LANGUAGE' ' + check_language "ko-KR, *;q=0.9" ko_KR.UTF-8' + +test_expect_success 'git client sends Accept-Language correctly with unordinary LANGUAGE' ' + check_language "ko-KR, *;q=0.9" "ko_KR:" && + check_language "ko-KR, en-US;q=0.9, *;q=0.8" "ko_KR::en_US" && + check_language "ko-KR, *;q=0.9" ":::ko_KR" && + check_language "ko-KR, en-US;q=0.9, *;q=0.8" "ko_KR!!:en_US" && + check_language "ko-KR, ja-JP;q=0.9, *;q=0.8" "ko_KR en_US:ja_JP"' + +test_expect_success 'git client sends Accept-Language with many preferred languages' ' + check_language "ko-KR, en-US;q=0.9, fr-CA;q=0.8, de;q=0.7, sr;q=0.6, \ +ja;q=0.5, zh;q=0.4, sv;q=0.3, pt;q=0.2, *;q=0.1" \ + ko_KR.EUC-KR:en_US.UTF-8:fr_CA:de.UTF-8@euro:sr@latin:ja:zh:sv:pt && + check_language "ko-KR, en-US;q=0.99, fr-CA;q=0.98, de;q=0.97, sr;q=0.96, \ +ja;q=0.95, zh;q=0.94, sv;q=0.93, pt;q=0.92, nb;q=0.91, *;q=0.90" \ + ko_KR.EUC-KR:en_US.UTF-8:fr_CA:de.UTF-8@euro:sr@latin:ja:zh:sv:pt:nb +' + +test_expect_success 'git client does not send an empty Accept-Language' ' + GIT_CURL_VERBOSE=1 LANGUAGE= git ls-remote "$HTTPD_URL/dumb/repo.git" 2>stderr && + ! grep "^Accept-Language:" stderr +' + stop_httpd test_done diff --git a/t/t5551-http-fetch-smart.sh b/t/t5551-http-fetch-smart.sh index e07eaf35f1..58207d8825 100755 --- a/t/t5551-http-fetch-smart.sh +++ b/t/t5551-http-fetch-smart.sh @@ -2,12 +2,6 @@ test_description='test smart fetching over http via http-backend' . ./test-lib.sh - -if test -n "$NO_CURL"; then - skip_all='skipping test, git built without http support' - test_done -fi - . "$TEST_DIRECTORY"/lib-httpd.sh start_httpd @@ -83,7 +77,7 @@ test_expect_success 'clone http repository' ' test_expect_success 'fetch changes via http' ' echo content >>file && git commit -a -m two && - git push public + git push public && (cd clone && git pull) && test_cmp file clone/file ' @@ -169,7 +163,7 @@ test_expect_success 'GIT_SMART_HTTP can disable smart http' ' ' test_expect_success 'invalid Content-Type rejected' ' - test_must_fail git clone $HTTPD_URL/broken_smart/repo.git 2>actual + test_must_fail git clone $HTTPD_URL/broken_smart/repo.git 2>actual && grep "not valid:" actual ' @@ -209,44 +203,84 @@ test_expect_success 'cookies stored in http.cookiefile when http.savecookies set git config http.cookiefile cookies.txt && git config http.savecookies true && git ls-remote $HTTPD_URL/smart_cookies/repo.git master && - tail -3 cookies.txt > cookies_tail.txt + tail -3 cookies.txt >cookies_tail.txt && test_cmp expect_cookies.txt cookies_tail.txt ' -test -n "$GIT_TEST_LONG" && test_set_prereq EXPENSIVE +test_expect_success 'transfer.hiderefs works over smart-http' ' + test_commit hidden && + test_commit visible && + git push public HEAD^:refs/heads/a HEAD:refs/heads/b && + git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \ + config transfer.hiderefs refs/heads/a && + git clone --bare "$HTTPD_URL/smart/repo.git" hidden.git && + test_must_fail git -C hidden.git rev-parse --verify a && + git -C hidden.git rev-parse --verify b +' -test_expect_success EXPENSIVE 'create 50,000 tags in the repo' ' - ( - cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && - for i in `test_seq 50000` +# create an arbitrary number of tags, numbered from tag-$1 to tag-$2 +create_tags () { + rm -f marks && + for i in $(test_seq "$1" "$2") do - echo "commit refs/heads/too-many-refs" - echo "mark :$i" - echo "committer git <git@example.com> $i +0000" - echo "data 0" - echo "M 644 inline bla.txt" - echo "data 4" - echo "bla" + # don't use here-doc, because it requires a process + # per loop iteration + echo "commit refs/heads/too-many-refs-$1" && + echo "mark :$i" && + echo "committer git <git@example.com> $i +0000" && + echo "data 0" && + echo "M 644 inline bla.txt" && + echo "data 4" && + echo "bla" && # make every commit dangling by always # rewinding the branch after each commit - echo "reset refs/heads/too-many-refs" - echo "from :1" + echo "reset refs/heads/too-many-refs-$1" && + echo "from :$1" done | git fast-import --export-marks=marks && # now assign tags to all the dangling commits we created above tag=$(perl -e "print \"bla\" x 30") && sed -e "s|^:\([^ ]*\) \(.*\)$|\2 refs/tags/$tag-\1|" <marks >>packed-refs +} + +test_expect_success 'create 2,000 tags in the repo' ' + ( + cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && + create_tags 1 2000 ) ' -test_expect_success EXPENSIVE 'clone the 50,000 tag repo to check OS command line overflow' ' - git clone $HTTPD_URL/smart/repo.git too-many-refs 2>err && - test_line_count = 0 err && +test_expect_success CMDLINE_LIMIT \ + 'clone the 2,000 tag repo to check OS command line overflow' ' + run_with_limited_cmdline git clone $HTTPD_URL/smart/repo.git too-many-refs && ( cd too-many-refs && - test $(git for-each-ref refs/tags | wc -l) = 50000 + git for-each-ref refs/tags >actual && + test_line_count = 2000 actual ) ' +test_expect_success 'large fetch-pack requests can be split across POSTs' ' + GIT_CURL_VERBOSE=1 git -c http.postbuffer=65536 \ + clone --bare "$HTTPD_URL/smart/repo.git" split.git 2>err && + grep "^> POST" err >posts && + test_line_count = 2 posts +' + +test_expect_success EXPENSIVE 'http can handle enormous ref negotiation' ' + ( + cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && + create_tags 2001 50000 + ) && + git -C too-many-refs fetch -q --tags && + ( + cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && + create_tags 50001 100000 + ) && + git -C too-many-refs fetch -q --tags && + git -C too-many-refs for-each-ref refs/tags >tags && + test_line_count = 100000 tags +' + stop_httpd test_done diff --git a/t/t5560-http-backend-noserver.sh b/t/t5560-http-backend-noserver.sh index aa73eeaef8..9fafcf1945 100755 --- a/t/t5560-http-backend-noserver.sh +++ b/t/t5560-http-backend-noserver.sh @@ -44,10 +44,6 @@ POST() { test_cmp exp act } -log_div() { - return 0 -} - . "$TEST_DIRECTORY"/t556x_common expect_aliased() { diff --git a/t/t5561-http-backend.sh b/t/t5561-http-backend.sh index d23fb02384..90e0d6f0fe 100755 --- a/t/t5561-http-backend.sh +++ b/t/t5561-http-backend.sh @@ -2,12 +2,6 @@ test_description='test git-http-backend' . ./test-lib.sh - -if test -n "$NO_CURL"; then - skip_all='skipping test, git built without http support' - test_done -fi - . "$TEST_DIRECTORY"/lib-httpd.sh start_httpd @@ -35,15 +29,9 @@ POST() { test_cmp exp act } -log_div() { - echo >>"$HTTPD_ROOT_PATH"/access.log - echo "### $1" >>"$HTTPD_ROOT_PATH"/access.log - echo "###" >>"$HTTPD_ROOT_PATH"/access.log -} - . "$TEST_DIRECTORY"/t556x_common -cat >exp <<EOF +grep '^[^#]' >exp <<EOF ### refs/heads/master ### diff --git a/t/t556x_common b/t/t556x_common index 82926cfdb7..359fcfe32b 100755 --- a/t/t556x_common +++ b/t/t556x_common @@ -52,21 +52,17 @@ get_static_files() { SMART=smart GIT_HTTP_EXPORT_ALL=1 && export GIT_HTTP_EXPORT_ALL test_expect_success 'direct refs/heads/master not found' ' - log_div "refs/heads/master" && GET refs/heads/master "404 Not Found" ' test_expect_success 'static file is ok' ' - log_div "getanyfile default" && get_static_files "200 OK" ' SMART=smart_noexport unset GIT_HTTP_EXPORT_ALL test_expect_success 'no export by default' ' - log_div "no git-daemon-export-ok" && get_static_files "404 Not Found" ' test_expect_success 'export if git-daemon-export-ok' ' - log_div "git-daemon-export-ok" && (cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && touch git-daemon-export-ok ) && @@ -75,47 +71,39 @@ test_expect_success 'export if git-daemon-export-ok' ' SMART=smart GIT_HTTP_EXPORT_ALL=1 && export GIT_HTTP_EXPORT_ALL test_expect_success 'static file if http.getanyfile true is ok' ' - log_div "getanyfile true" && config http.getanyfile true && get_static_files "200 OK" ' test_expect_success 'static file if http.getanyfile false fails' ' - log_div "getanyfile false" && config http.getanyfile false && get_static_files "403 Forbidden" ' test_expect_success 'http.uploadpack default enabled' ' - log_div "uploadpack default" && GET info/refs?service=git-upload-pack "200 OK" && POST git-upload-pack 0000 "200 OK" ' test_expect_success 'http.uploadpack true' ' - log_div "uploadpack true" && config http.uploadpack true && GET info/refs?service=git-upload-pack "200 OK" && POST git-upload-pack 0000 "200 OK" ' test_expect_success 'http.uploadpack false' ' - log_div "uploadpack false" && config http.uploadpack false && GET info/refs?service=git-upload-pack "403 Forbidden" && POST git-upload-pack 0000 "403 Forbidden" ' test_expect_success 'http.receivepack default disabled' ' - log_div "receivepack default" && GET info/refs?service=git-receive-pack "403 Forbidden" && POST git-receive-pack 0000 "403 Forbidden" ' test_expect_success 'http.receivepack true' ' - log_div "receivepack true" && config http.receivepack true && GET info/refs?service=git-receive-pack "200 OK" && POST git-receive-pack 0000 "200 OK" ' test_expect_success 'http.receivepack false' ' - log_div "receivepack false" && config http.receivepack false && GET info/refs?service=git-receive-pack "403 Forbidden" && POST git-receive-pack 0000 "403 Forbidden" diff --git a/t/t5570-git-daemon.sh b/t/t5570-git-daemon.sh index 6b16379951..b7e283252d 100755 --- a/t/t5570-git-daemon.sh +++ b/t/t5570-git-daemon.sh @@ -142,4 +142,31 @@ test_expect_success 'read access denied' "test_remote_error -x 'no such reposito test_expect_success 'not exported' "test_remote_error -n 'repository not exported' fetch repo.git " stop_git_daemon +start_git_daemon --interpolated-path="$GIT_DAEMON_DOCUMENT_ROOT_PATH/%H%D" + +test_expect_success 'access repo via interpolated hostname' ' + repo="$GIT_DAEMON_DOCUMENT_ROOT_PATH/localhost/interp.git" && + git init --bare "$repo" && + git push "$repo" HEAD && + >"$repo"/git-daemon-export-ok && + rm -rf tmp.git && + GIT_OVERRIDE_VIRTUAL_HOST=localhost \ + git clone --bare "$GIT_DAEMON_URL/interp.git" tmp.git && + rm -rf tmp.git && + GIT_OVERRIDE_VIRTUAL_HOST=LOCALHOST \ + git clone --bare "$GIT_DAEMON_URL/interp.git" tmp.git +' + +test_expect_success 'hostname cannot break out of directory' ' + rm -rf tmp.git && + repo="$GIT_DAEMON_DOCUMENT_ROOT_PATH/../escape.git" && + git init --bare "$repo" && + git push "$repo" HEAD && + >"$repo"/git-daemon-export-ok && + test_must_fail \ + env GIT_OVERRIDE_VIRTUAL_HOST=.. \ + git clone --bare "$GIT_DAEMON_URL/escape.git" tmp.git +' + +stop_git_daemon test_done diff --git a/t/t5571-pre-push-hook.sh b/t/t5571-pre-push-hook.sh index 6f9916a390..ba975bb355 100755 --- a/t/t5571-pre-push-hook.sh +++ b/t/t5571-pre-push-hook.sh @@ -109,23 +109,20 @@ test_expect_success 'push to URL' ' diff expected actual ' -# Test that filling pipe buffers doesn't cause failure -# Too slow to leave enabled for general use -if false -then - printf 'parent1\nrepo1\n' >expected - nr=1000 - while test $nr -lt 2000 - do - nr=$(( $nr + 1 )) - git branch b/$nr $COMMIT3 - echo "refs/heads/b/$nr $COMMIT3 refs/heads/b/$nr $_z40" >>expected - done - - test_expect_success 'push many refs' ' - git push parent1 "refs/heads/b/*:refs/heads/b/*" && - diff expected actual - ' -fi +test_expect_success 'set up many-ref tests' ' + { + nr=1000 + while test $nr -lt 2000 + do + nr=$(( $nr + 1 )) + echo "create refs/heads/b/$nr $COMMIT3" + done + } | git update-ref --stdin +' + +test_expect_success 'sigpipe does not cause pre-push hook failure' ' + echo "exit 0" | write_script "$HOOK" && + git push parent1 "refs/heads/b/*:refs/heads/b/*" +' test_done diff --git a/t/t5572-pull-submodule.sh b/t/t5572-pull-submodule.sh new file mode 100755 index 0000000000..accfa5cc0c --- /dev/null +++ b/t/t5572-pull-submodule.sh @@ -0,0 +1,45 @@ +#!/bin/sh + +test_description='pull can handle submodules' + +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-submodule-update.sh + +reset_branch_to_HEAD () { + git branch -D "$1" && + git checkout -b "$1" HEAD && + git branch --set-upstream-to="origin/$1" "$1" +} + +git_pull () { + reset_branch_to_HEAD "$1" && + git pull +} + +# pulls without conflicts +test_submodule_switch "git_pull" + +git_pull_ff () { + reset_branch_to_HEAD "$1" && + git pull --ff +} + +test_submodule_switch "git_pull_ff" + +git_pull_ff_only () { + reset_branch_to_HEAD "$1" && + git pull --ff-only +} + +test_submodule_switch "git_pull_ff_only" + +git_pull_noff () { + reset_branch_to_HEAD "$1" && + git pull --no-ff +} + +KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1 +KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1 +test_submodule_switch "git_pull_noff" + +test_done diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh index 5e67035be8..9b34f3c615 100755 --- a/t/t5601-clone.sh +++ b/t/t5601-clone.sh @@ -296,16 +296,28 @@ setup_ssh_wrapper () { ' } +copy_ssh_wrapper_as () { + cp "$TRASH_DIRECTORY/ssh-wrapper" "$1" && + GIT_SSH="$1" && + export GIT_SSH +} + expect_ssh () { test_when_finished ' (cd "$TRASH_DIRECTORY" && rm -f ssh-expect && >ssh-output) ' && { - case "$1" in - none) + case "$#" in + 1) ;; - *) + 2) echo "ssh: $1 git-upload-pack '$2'" + ;; + 3) + echo "ssh: $1 $2 git-upload-pack '$3'" + ;; + *) + echo "ssh: $1 $2 git-upload-pack '$3' $4" esac } >"$TRASH_DIRECTORY/ssh-expect" && (cd "$TRASH_DIRECTORY" && test_cmp ssh-expect ssh-output) @@ -318,7 +330,7 @@ test_expect_success 'clone myhost:src uses ssh' ' expect_ssh myhost src ' -test_expect_success NOT_MINGW,NOT_CYGWIN 'clone local path foo:bar' ' +test_expect_success !MINGW,!CYGWIN 'clone local path foo:bar' ' cp -R src "foo:bar" && git clone "foo:bar" foobar && expect_ssh none @@ -326,9 +338,36 @@ test_expect_success NOT_MINGW,NOT_CYGWIN 'clone local path foo:bar' ' test_expect_success 'bracketed hostnames are still ssh' ' git clone "[myhost:123]:src" ssh-bracket-clone && - expect_ssh myhost:123 src + expect_ssh "-p 123" myhost src +' + +test_expect_success 'uplink is not treated as putty' ' + copy_ssh_wrapper_as "$TRASH_DIRECTORY/uplink" && + git clone "[myhost:123]:src" ssh-bracket-clone-uplink && + expect_ssh "-p 123" myhost src +' + +test_expect_success 'plink is treated specially (as putty)' ' + copy_ssh_wrapper_as "$TRASH_DIRECTORY/plink" && + git clone "[myhost:123]:src" ssh-bracket-clone-plink-0 && + expect_ssh "-P 123" myhost src +' + +test_expect_success 'plink.exe is treated specially (as putty)' ' + copy_ssh_wrapper_as "$TRASH_DIRECTORY/plink.exe" && + git clone "[myhost:123]:src" ssh-bracket-clone-plink-1 && + expect_ssh "-P 123" myhost src +' + +test_expect_success 'tortoiseplink is like putty, with extra arguments' ' + copy_ssh_wrapper_as "$TRASH_DIRECTORY/tortoiseplink" && + git clone "[myhost:123]:src" ssh-bracket-clone-plink-2 && + expect_ssh "-batch -P 123" myhost src ' +# Reset the GIT_SSH environment variable for clone tests. +setup_ssh_wrapper + counter=0 # $1 url # $2 none|host @@ -336,10 +375,11 @@ counter=0 test_clone_url () { counter=$(($counter + 1)) test_might_fail git clone "$1" tmp$counter && - expect_ssh "$2" "$3" + shift && + expect_ssh "$@" } -test_expect_success NOT_MINGW 'clone c:temp is ssl' ' +test_expect_success !MINGW 'clone c:temp is ssl' ' test_clone_url c:temp c temp ' @@ -359,7 +399,7 @@ done for repo in rep rep/home/project 123 do test_expect_success "clone [::1]:$repo" ' - test_clone_url [::1]:$repo ::1 $repo + test_clone_url [::1]:$repo ::1 "$repo" ' done #home directory @@ -380,14 +420,17 @@ do done #with ssh:// scheme -test_expect_success 'clone ssh://host.xz/home/user/repo' ' - test_clone_url "ssh://host.xz/home/user/repo" host.xz "/home/user/repo" -' - -# from home directory -test_expect_success 'clone ssh://host.xz/~repo' ' - test_clone_url "ssh://host.xz/~repo" host.xz "~repo" +#ignore trailing colon +for tcol in "" : +do + test_expect_success "clone ssh://host.xz$tcol/home/user/repo" ' + test_clone_url "ssh://host.xz$tcol/home/user/repo" host.xz /home/user/repo + ' + # from home directory + test_expect_success "clone ssh://host.xz$tcol/~repo" ' + test_clone_url "ssh://host.xz$tcol/~repo" host.xz "~repo" ' +done # with port number test_expect_success 'clone ssh://host.xz:22/home/user/repo' ' @@ -400,24 +443,40 @@ test_expect_success 'clone ssh://host.xz:22/~repo' ' ' #IPv6 -test_expect_success 'clone ssh://[::1]/home/user/repo' ' - test_clone_url "ssh://[::1]/home/user/repo" "::1" "/home/user/repo" -' +for tuah in ::1 [::1] [::1]: user@::1 user@[::1] user@[::1]: [user@::1] [user@::1]: +do + ehost=$(echo $tuah | sed -e "s/1]:/1]/ "| tr -d "[]") + test_expect_success "clone ssh://$tuah/home/user/repo" " + test_clone_url ssh://$tuah/home/user/repo $ehost /home/user/repo + " +done #IPv6 from home directory -test_expect_success 'clone ssh://[::1]/~repo' ' - test_clone_url "ssh://[::1]/~repo" "::1" "~repo" -' +for tuah in ::1 [::1] user@::1 user@[::1] [user@::1] +do + euah=$(echo $tuah | tr -d "[]") + test_expect_success "clone ssh://$tuah/~repo" " + test_clone_url ssh://$tuah/~repo $euah '~repo' + " +done #IPv6 with port number -test_expect_success 'clone ssh://[::1]:22/home/user/repo' ' - test_clone_url "ssh://[::1]:22/home/user/repo" "-p 22 ::1" "/home/user/repo" -' +for tuah in [::1] user@[::1] [user@::1] +do + euah=$(echo $tuah | tr -d "[]") + test_expect_success "clone ssh://$tuah:22/home/user/repo" " + test_clone_url ssh://$tuah:22/home/user/repo '-p 22' $euah /home/user/repo + " +done #IPv6 from home directory with port number -test_expect_success 'clone ssh://[::1]:22/~repo' ' - test_clone_url "ssh://[::1]:22/~repo" "-p 22 ::1" "~repo" -' +for tuah in [::1] user@[::1] [user@::1] +do + euah=$(echo $tuah | tr -d "[]") + test_expect_success "clone ssh://$tuah:22/~repo" " + test_clone_url ssh://$tuah:22/~repo '-p 22' $euah '~repo' + " +done test_expect_success 'clone from a repository with two identical branches' ' @@ -437,4 +496,11 @@ test_expect_success 'shallow clone locally' ' ( cd ddsstt && git fsck ) ' +test_expect_success 'GIT_TRACE_PACKFILE produces a usable pack' ' + rm -rf dst.git && + GIT_TRACE_PACKFILE=$PWD/tmp.pack git clone --no-local --bare src dst.git && + git init --bare replay.git && + git -C replay.git index-pack -v --stdin <tmp.pack +' + test_done diff --git a/t/t5603-clone-dirname.sh b/t/t5603-clone-dirname.sh new file mode 100755 index 0000000000..d5af758129 --- /dev/null +++ b/t/t5603-clone-dirname.sh @@ -0,0 +1,106 @@ +#!/bin/sh + +test_description='check output directory names used by git-clone' +. ./test-lib.sh + +# we use a fake ssh wrapper that ignores the arguments +# entirely; we really only care that we get _some_ repo, +# as the real test is what clone does on the local side +test_expect_success 'setup ssh wrapper' ' + write_script "$TRASH_DIRECTORY/ssh-wrapper" <<-\EOF && + git upload-pack "$TRASH_DIRECTORY" + EOF + GIT_SSH="$TRASH_DIRECTORY/ssh-wrapper" && + export GIT_SSH && + export TRASH_DIRECTORY +' + +# make sure that cloning $1 results in local directory $2 +test_clone_dir () { + url=$1; shift + dir=$1; shift + expect=success + bare=non-bare + clone_opts= + for i in "$@" + do + case "$i" in + fail) + expect=failure + ;; + bare) + bare=bare + clone_opts=--bare + ;; + esac + done + test_expect_$expect "clone of $url goes to $dir ($bare)" " + rm -rf $dir && + git clone $clone_opts $url && + test_path_is_dir $dir + " +} + +# basic syntax with bare and non-bare variants +test_clone_dir host:foo foo +test_clone_dir host:foo foo.git bare +test_clone_dir host:foo.git foo +test_clone_dir host:foo.git foo.git bare +test_clone_dir host:foo/.git foo +test_clone_dir host:foo/.git foo.git bare + +# similar, but using ssh URL rather than host:path syntax +test_clone_dir ssh://host/foo foo +test_clone_dir ssh://host/foo foo.git bare +test_clone_dir ssh://host/foo.git foo +test_clone_dir ssh://host/foo.git foo.git bare +test_clone_dir ssh://host/foo/.git foo +test_clone_dir ssh://host/foo/.git foo.git bare + +# we should remove trailing slashes and .git suffixes +test_clone_dir ssh://host/foo/ foo +test_clone_dir ssh://host/foo/// foo +test_clone_dir ssh://host/foo/.git/ foo +test_clone_dir ssh://host/foo.git/ foo +test_clone_dir ssh://host/foo.git/// foo +test_clone_dir ssh://host/foo///.git/ foo +test_clone_dir ssh://host/foo/.git/// foo + +test_clone_dir host:foo/ foo +test_clone_dir host:foo/// foo +test_clone_dir host:foo.git/ foo +test_clone_dir host:foo/.git/ foo +test_clone_dir host:foo.git/// foo +test_clone_dir host:foo///.git/ foo +test_clone_dir host:foo/.git/// foo + +# omitting the path should default to the hostname +test_clone_dir ssh://host/ host +test_clone_dir ssh://host:1234/ host +test_clone_dir ssh://user@host/ host +test_clone_dir host:/ host + +# auth materials should be redacted +test_clone_dir ssh://user:password@host/ host +test_clone_dir ssh://user:password@host:1234/ host +test_clone_dir ssh://user:passw@rd@host:1234/ host +test_clone_dir user@host:/ host +test_clone_dir user:password@host:/ host +test_clone_dir user:passw@rd@host:/ host + +# auth-like material should not be dropped +test_clone_dir ssh://host/foo@bar foo@bar +test_clone_dir ssh://host/foo@bar.git foo@bar +test_clone_dir ssh://user:password@host/foo@bar foo@bar +test_clone_dir ssh://user:passw@rd@host/foo@bar.git foo@bar + +test_clone_dir host:/foo@bar foo@bar +test_clone_dir host:/foo@bar.git foo@bar +test_clone_dir user:password@host:/foo@bar foo@bar +test_clone_dir user:passw@rd@host:/foo@bar.git foo@bar + +# trailing port-like numbers should not be stripped for paths +test_clone_dir ssh://user:password@host/test:1234 1234 +test_clone_dir ssh://user:password@host/test:1234.git 1234 + +test_done diff --git a/t/t5700-clone-reference.sh b/t/t5700-clone-reference.sh index 6537911a43..dfa1bf79c5 100755 --- a/t/t5700-clone-reference.sh +++ b/t/t5700-clone-reference.sh @@ -10,49 +10,51 @@ base_dir=`pwd` U=$base_dir/UPLOAD_LOG -test_expect_success 'preparing first repository' \ -'test_create_repo A && cd A && -echo first > file1 && -git add file1 && -git commit -m initial' - -cd "$base_dir" - -test_expect_success 'preparing second repository' \ -'git clone A B && cd B && -echo second > file2 && -git add file2 && -git commit -m addition && -git repack -a -d && -git prune' - -cd "$base_dir" - -test_expect_success 'cloning with reference (-l -s)' \ -'git clone -l -s --reference B A C' - -cd "$base_dir" - -test_expect_success 'existence of info/alternates' \ -'test_line_count = 2 C/.git/objects/info/alternates' - -cd "$base_dir" +# create a commit in repo $1 with name $2 +commit_in () { + ( + cd "$1" && + echo "$2" >"$2" && + git add "$2" && + git commit -m "$2" + ) +} + +# check that there are $2 loose objects in repo $1 +test_objcount () { + echo "$2" >expect && + git -C "$1" count-objects >actual.raw && + cut -d' ' -f1 <actual.raw >actual && + test_cmp expect actual +} + +test_expect_success 'preparing first repository' ' + test_create_repo A && + commit_in A file1 +' -test_expect_success 'pulling from reference' \ -'cd C && -git pull ../B master' +test_expect_success 'preparing second repository' ' + git clone A B && + commit_in B file2 && + git -C B repack -ad && + git -C B prune +' -cd "$base_dir" +test_expect_success 'cloning with reference (-l -s)' ' + git clone -l -s --reference B A C +' -test_expect_success 'that reference gets used' \ -'cd C && -echo "0 objects, 0 kilobytes" > expected && -git count-objects > current && -test_cmp expected current' +test_expect_success 'existence of info/alternates' ' + test_line_count = 2 C/.git/objects/info/alternates +' -cd "$base_dir" +test_expect_success 'pulling from reference' ' + git -C C pull ../B master +' -rm -f "$U.D" +test_expect_success 'that reference gets used' ' + test_objcount C 0 +' test_expect_success 'cloning with reference (no -l -s)' ' GIT_TRACE_PACKET=$U.D git clone --reference B "file://$(pwd)/A" D @@ -63,95 +65,69 @@ test_expect_success 'fetched no objects' ' ! grep " want" "$U.D" ' -cd "$base_dir" - -test_expect_success 'existence of info/alternates' \ -'test_line_count = 1 D/.git/objects/info/alternates' - -cd "$base_dir" - -test_expect_success 'pulling from reference' \ -'cd D && git pull ../B master' - -cd "$base_dir" - -test_expect_success 'that reference gets used' \ -'cd D && echo "0 objects, 0 kilobytes" > expected && -git count-objects > current && -test_cmp expected current' - -cd "$base_dir" +test_expect_success 'existence of info/alternates' ' + test_line_count = 1 D/.git/objects/info/alternates +' -test_expect_success 'updating origin' \ -'cd A && -echo third > file3 && -git add file3 && -git commit -m update && -git repack -a -d && -git prune' +test_expect_success 'pulling from reference' ' + git -C D pull ../B master +' -cd "$base_dir" +test_expect_success 'that reference gets used' ' + test_objcount D 0 +' -test_expect_success 'pulling changes from origin' \ -'cd C && -git pull origin' +test_expect_success 'updating origin' ' + commit_in A file3 && + git -C A repack -ad && + git -C A prune +' -cd "$base_dir" +test_expect_success 'pulling changes from origin' ' + git -C C pull origin +' # the 2 local objects are commit and tree from the merge -test_expect_success 'that alternate to origin gets used' \ -'cd C && -echo "2 objects" > expected && -git count-objects | cut -d, -f1 > current && -test_cmp expected current' - -cd "$base_dir" - -test_expect_success 'pulling changes from origin' \ -'cd D && -git pull origin' +test_expect_success 'that alternate to origin gets used' ' + test_objcount C 2 +' -cd "$base_dir" +test_expect_success 'pulling changes from origin' ' + git -C D pull origin +' # the 5 local objects are expected; file3 blob, commit in A to add it # and its tree, and 2 are our tree and the merge commit. -test_expect_success 'check objects expected to exist locally' \ -'cd D && -echo "5 objects" > expected && -git count-objects | cut -d, -f1 > current && -test_cmp expected current' - -cd "$base_dir" - -test_expect_success 'preparing alternate repository #1' \ -'test_create_repo F && cd F && -echo first > file1 && -git add file1 && -git commit -m initial' - -cd "$base_dir" - -test_expect_success 'cloning alternate repo #2 and adding changes to repo #1' \ -'git clone F G && cd F && -echo second > file2 && -git add file2 && -git commit -m addition' +test_expect_success 'check objects expected to exist locally' ' + test_objcount D 5 +' -cd "$base_dir" +test_expect_success 'preparing alternate repository #1' ' + test_create_repo F && + commit_in F file1 +' -test_expect_success 'cloning alternate repo #1, using #2 as reference' \ -'git clone --reference G F H' +test_expect_success 'cloning alternate repo #2 and adding changes to repo #1' ' + git clone F G && + commit_in F file2 +' -cd "$base_dir" +test_expect_success 'cloning alternate repo #1, using #2 as reference' ' + git clone --reference G F H +' -test_expect_success 'cloning with reference being subset of source (-l -s)' \ -'git clone -l -s --reference A B E' +test_expect_success 'cloning with reference being subset of source (-l -s)' ' + git clone -l -s --reference A B E +' -cd "$base_dir" +test_expect_success 'cloning with multiple references drops duplicates' ' + git clone -s --reference B --reference A --reference B A dups && + test_line_count = 2 dups/.git/objects/info/alternates +' test_expect_success 'clone with reference from a tagged repository' ' ( - cd A && git tag -a -m 'tagged' HEAD + cd A && git tag -a -m tagged HEAD ) && git clone --reference=A A I ' @@ -168,8 +144,6 @@ test_expect_success 'prepare branched repository' ' ) ' -rm -f "$U.K" - test_expect_success 'fetch with incomplete alternates' ' git init K && echo "$base_dir/A/.git/objects" >K/.git/objects/info/alternates && @@ -198,4 +172,53 @@ test_expect_success 'clone using repo pointed at by gitfile as reference' ' test_cmp expected "$base_dir/O/.git/objects/info/alternates" ' +test_expect_success 'clone and dissociate from reference' ' + git init P && + ( + cd P && test_commit one + ) && + git clone P Q && + ( + cd Q && test_commit two + ) && + git clone --no-local --reference=P Q R && + git clone --no-local --reference=P --dissociate Q S && + # removing the reference P would corrupt R but not S + rm -fr P && + test_must_fail git -C R fsck && + git -C S fsck +' +test_expect_success 'clone, dissociate from partial reference and repack' ' + rm -fr P Q R && + git init P && + ( + cd P && + test_commit one && + git repack && + test_commit two && + git repack + ) && + git clone --bare P Q && + ( + cd P && + git checkout -b second && + test_commit three && + git repack + ) && + git clone --bare --dissociate --reference=P Q R && + ls R/objects/pack/*.pack >packs.txt && + test_line_count = 1 packs.txt +' + +test_expect_success 'clone, dissociate from alternates' ' + rm -fr A B C && + test_create_repo A && + commit_in A file1 && + git clone --reference=A A B && + test_line_count = 1 B/.git/objects/info/alternates && + git clone --local --dissociate B C && + ! test -f C/.git/objects/info/alternates && + ( cd C && git fsck ) +' + test_done diff --git a/t/t5704-bundle.sh b/t/t5704-bundle.sh index a45c31692e..348d9b3bc7 100755 --- a/t/t5704-bundle.sh +++ b/t/t5704-bundle.sh @@ -14,7 +14,10 @@ test_expect_success 'setup' ' git tag -d third ' -test_expect_success 'tags can be excluded by rev-list options' ' +test_expect_success 'annotated tags can be excluded by rev-list options' ' + git bundle create bundle --all --since=7.Apr.2005.15:14:00.-0700 && + git ls-remote bundle > output && + grep tag output && git bundle create bundle --all --since=7.Apr.2005.15:16:00.-0700 && git ls-remote bundle > output && ! grep tag output diff --git a/t/t5705-clone-2gb.sh b/t/t5705-clone-2gb.sh index e9783c341a..191d6d3a78 100755 --- a/t/t5705-clone-2gb.sh +++ b/t/t5705-clone-2gb.sh @@ -46,7 +46,7 @@ test_expect_success CLONE_2GB 'clone - bare' ' test_expect_success CLONE_2GB 'clone - with worktree, file:// protocol' ' - git clone file://. clone-wt + git clone "file://$(pwd)" clone-wt ' diff --git a/t/t5709-clone-refspec.sh b/t/t5709-clone-refspec.sh index 6f1ea984d4..7ace2535c8 100755 --- a/t/t5709-clone-refspec.sh +++ b/t/t5709-clone-refspec.sh @@ -147,7 +147,7 @@ test_expect_success '--single-branch with detached' ' git for-each-ref refs/remotes/origin | sed -e "/HEAD$/d" \ -e "s|/remotes/origin/|/heads/|" >../actual - ) + ) && # nothing >expect && test_cmp expect actual diff --git a/t/t5801-remote-helpers.sh b/t/t5801-remote-helpers.sh index a00a660763..362b1581e0 100755 --- a/t/t5801-remote-helpers.sh +++ b/t/t5801-remote-helpers.sh @@ -87,13 +87,29 @@ test_expect_success 'push new branch by name' ' compare_refs local HEAD server refs/heads/new-name ' -test_expect_failure 'push new branch with old:new refspec' ' +test_expect_success 'push new branch with old:new refspec' ' (cd local && git push origin new-name:new-refspec ) && compare_refs local HEAD server refs/heads/new-refspec ' +test_expect_success 'push new branch with HEAD:new refspec' ' + (cd local && + git checkout new-name + git push origin HEAD:new-refspec-2 + ) && + compare_refs local HEAD server refs/heads/new-refspec-2 +' + +test_expect_success 'push delete branch' ' + (cd local && + git push origin :new-name + ) && + test_must_fail git --git-dir="server/.git" \ + rev-parse --verify refs/heads/new-name +' + test_expect_success 'forced push' ' (cd local && git checkout -b force-test && @@ -226,13 +242,6 @@ clean_mark () { sort >$(basename "$1") } -cmp_marks () { - test_when_finished "rm -rf git.marks testgit.marks" && - clean_mark ".git/testgit/$1/git.marks" && - clean_mark ".git/testgit/$1/testgit.marks" && - test_cmp git.marks testgit.marks -} - test_expect_success 'proper failure checks for fetching' ' (cd local && test_must_fail env GIT_REMOTE_TESTGIT_FAILURE=1 git fetch 2>error && @@ -242,12 +251,15 @@ test_expect_success 'proper failure checks for fetching' ' ' test_expect_success 'proper failure checks for pushing' ' + test_when_finished "rm -rf local/git.marks local/testgit.marks" && (cd local && git checkout -b crash master && echo crash >>file && git commit -a -m crash && test_must_fail env GIT_REMOTE_TESTGIT_FAILURE=1 git push --all && - cmp_marks origin + clean_mark ".git/testgit/origin/git.marks" && + clean_mark ".git/testgit/origin/testgit.marks" && + test_cmp git.marks testgit.marks ) ' @@ -265,4 +277,28 @@ test_expect_success 'push messages' ' ) ' +test_expect_success 'fetch HEAD' ' + (cd server && + git checkout master && + echo more >>file && + git commit -a -m more + ) && + (cd local && + git fetch origin HEAD + ) && + compare_refs server HEAD local FETCH_HEAD +' + +test_expect_success 'fetch url' ' + (cd server && + git checkout master && + echo more >>file && + git commit -a -m more + ) && + (cd local && + git fetch "testgit::${PWD}/../server" + ) && + compare_refs server HEAD local FETCH_HEAD +' + test_done diff --git a/t/t5802-connect-helper.sh b/t/t5802-connect-helper.sh index 878faf2b63..b7a7f9d588 100755 --- a/t/t5802-connect-helper.sh +++ b/t/t5802-connect-helper.sh @@ -69,4 +69,32 @@ test_expect_success 'update backfilled tag without primary transfer' ' test_cmp expect actual ' + +test_expect_success 'set up fake git-daemon' ' + mkdir remote && + git init --bare remote/one.git && + mkdir remote/host && + git init --bare remote/host/two.git && + write_script fake-daemon <<-\EOF && + git daemon --inetd \ + --informative-errors \ + --export-all \ + --base-path="$TRASH_DIRECTORY/remote" \ + --interpolated-path="$TRASH_DIRECTORY/remote/%H%D" \ + "$TRASH_DIRECTORY/remote" + EOF + export TRASH_DIRECTORY && + PATH=$TRASH_DIRECTORY:$PATH +' + +test_expect_success 'ext command can connect to git daemon (no vhost)' ' + rm -rf dst && + git clone "ext::fake-daemon %G/one.git" dst +' + +test_expect_success 'ext command can connect to git daemon (vhost)' ' + rm -rf dst && + git clone "ext::fake-daemon %G/two.git %Vhost" dst +' + test_done diff --git a/t/t5810-proto-disable-local.sh b/t/t5810-proto-disable-local.sh new file mode 100755 index 0000000000..563592d8a8 --- /dev/null +++ b/t/t5810-proto-disable-local.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +test_description='test disabling of local paths in clone/fetch' +. ./test-lib.sh +. "$TEST_DIRECTORY/lib-proto-disable.sh" + +test_expect_success 'setup repository to clone' ' + test_commit one +' + +test_proto "file://" file "file://$PWD" +test_proto "path" file . + +test_done diff --git a/t/t5811-proto-disable-git.sh b/t/t5811-proto-disable-git.sh new file mode 100755 index 0000000000..8ac6b2a1d0 --- /dev/null +++ b/t/t5811-proto-disable-git.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +test_description='test disabling of git-over-tcp in clone/fetch' +. ./test-lib.sh +. "$TEST_DIRECTORY/lib-proto-disable.sh" +. "$TEST_DIRECTORY/lib-git-daemon.sh" +start_git_daemon + +test_expect_success 'create git-accessible repo' ' + bare="$GIT_DAEMON_DOCUMENT_ROOT_PATH/repo.git" && + test_commit one && + git --bare init "$bare" && + git push "$bare" HEAD && + >"$bare/git-daemon-export-ok" && + git -C "$bare" config daemon.receivepack true +' + +test_proto "git://" git "$GIT_DAEMON_URL/repo.git" + +test_done diff --git a/t/t5812-proto-disable-http.sh b/t/t5812-proto-disable-http.sh new file mode 100755 index 0000000000..0d105d5417 --- /dev/null +++ b/t/t5812-proto-disable-http.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +test_description='test disabling of git-over-http in clone/fetch' +. ./test-lib.sh +. "$TEST_DIRECTORY/lib-proto-disable.sh" +. "$TEST_DIRECTORY/lib-httpd.sh" +start_httpd + +test_expect_success 'create git-accessible repo' ' + bare="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && + test_commit one && + git --bare init "$bare" && + git push "$bare" HEAD && + git -C "$bare" config http.receivepack true +' + +test_proto "smart http" http "$HTTPD_URL/smart/repo.git" + +test_expect_success 'curl redirects respect whitelist' ' + test_must_fail env GIT_ALLOW_PROTOCOL=http:https \ + git clone "$HTTPD_URL/ftp-redir/repo.git" 2>stderr && + { + test_i18ngrep "ftp.*disabled" stderr || + test_i18ngrep "your curl version is too old" + } +' + +test_expect_success 'curl limits redirects' ' + test_must_fail git clone "$HTTPD_URL/loop-redir/smart/repo.git" +' + +stop_httpd +test_done diff --git a/t/t5813-proto-disable-ssh.sh b/t/t5813-proto-disable-ssh.sh new file mode 100755 index 0000000000..a954ead8af --- /dev/null +++ b/t/t5813-proto-disable-ssh.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +test_description='test disabling of git-over-ssh in clone/fetch' +. ./test-lib.sh +. "$TEST_DIRECTORY/lib-proto-disable.sh" + +setup_ssh_wrapper + +test_expect_success 'setup repository to clone' ' + test_commit one && + mkdir remote && + git init --bare remote/repo.git && + git push remote/repo.git HEAD +' + +test_proto "host:path" ssh "remote:repo.git" +test_proto "ssh://" ssh "ssh://remote$PWD/remote/repo.git" +test_proto "git+ssh://" ssh "git+ssh://remote$PWD/remote/repo.git" + +test_done diff --git a/t/t5814-proto-disable-ext.sh b/t/t5814-proto-disable-ext.sh new file mode 100755 index 0000000000..9d6f7dfa2c --- /dev/null +++ b/t/t5814-proto-disable-ext.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +test_description='test disabling of remote-helper paths in clone/fetch' +. ./test-lib.sh +. "$TEST_DIRECTORY/lib-proto-disable.sh" + +setup_ext_wrapper + +test_expect_success 'setup repository to clone' ' + test_commit one && + mkdir remote && + git init --bare remote/repo.git && + git push remote/repo.git HEAD +' + +test_proto "remote-helper" ext "ext::fake-remote %S repo.git" + +test_done diff --git a/t/t5815-submodule-protos.sh b/t/t5815-submodule-protos.sh new file mode 100755 index 0000000000..06f55a1b8a --- /dev/null +++ b/t/t5815-submodule-protos.sh @@ -0,0 +1,43 @@ +#!/bin/sh + +test_description='test protocol whitelisting with submodules' +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-proto-disable.sh + +setup_ext_wrapper +setup_ssh_wrapper + +test_expect_success 'setup repository with submodules' ' + mkdir remote && + git init remote/repo.git && + (cd remote/repo.git && test_commit one) && + # submodule-add should probably trust what we feed it on the cmdline, + # but its implementation is overly conservative. + GIT_ALLOW_PROTOCOL=ssh git submodule add remote:repo.git ssh-module && + GIT_ALLOW_PROTOCOL=ext git submodule add "ext::fake-remote %S repo.git" ext-module && + git commit -m "add submodules" +' + +test_expect_success 'clone with recurse-submodules fails' ' + test_must_fail git clone --recurse-submodules . dst +' + +test_expect_success 'setup individual updates' ' + rm -rf dst && + git clone . dst && + git -C dst submodule init +' + +test_expect_success 'update of ssh allowed' ' + git -C dst submodule update ssh-module +' + +test_expect_success 'update of ext not allowed' ' + test_must_fail git -C dst submodule update ext-module +' + +test_expect_success 'user can override whitelist' ' + GIT_ALLOW_PROTOCOL=ext git -C dst submodule update ext-module +' + +test_done diff --git a/t/t6000-rev-list-misc.sh b/t/t6000-rev-list-misc.sh index 3794e4ceaf..3e752ce032 100755 --- a/t/t6000-rev-list-misc.sh +++ b/t/t6000-rev-list-misc.sh @@ -42,7 +42,7 @@ test_expect_success 'rev-list --objects with pathspecs and copied files' ' test_tick && git commit -m that && - ONE=$(git rev-parse HEAD:one) + ONE=$(git rev-parse HEAD:one) && git rev-list --objects HEAD two >output && grep "$ONE two/three" output && ! grep one output @@ -73,4 +73,31 @@ test_expect_success 'symleft flag bit is propagated down from tag' ' test_cmp expect actual ' +test_expect_success 'rev-list can show index objects' ' + # Of the blobs and trees in the index, note: + # + # - we do not show two/three, because it is the + # same blob as "one", and we show objects only once + # + # - we do show the tree "two", because it has a valid cache tree + # from the last commit + # + # - we do not show the root tree; since we updated the index, it + # does not have a valid cache tree + # + cat >expect <<-\EOF && + 8e4020bb5a8d8c873b25de15933e75cc0fc275df one + d9d3a7417b9605cfd88ee6306b28dadc29e6ab08 only-in-index + 9200b628cf9dc883a85a7abc8d6e6730baee589c two + EOF + echo only-in-index >only-in-index && + git add only-in-index && + git rev-list --objects --indexed-objects >actual && + test_cmp expect actual +' + +test_expect_success '--bisect and --first-parent can not be combined' ' + test_must_fail git rev-list --bisect --first-parent HEAD +' + test_done diff --git a/t/t6006-rev-list-format.sh b/t/t6006-rev-list-format.sh index 88ed3191e8..b77d4c97c1 100755 --- a/t/t6006-rev-list-format.sh +++ b/t/t6006-rev-list-format.sh @@ -35,17 +35,17 @@ test_expect_success 'setup' ' : >foo && git add foo && git config i18n.commitEncoding $test_encoding && - git commit -m "$added_iso88591" && + echo "$added_iso88591" | git commit -F - && head1=$(git rev-parse --verify HEAD) && head1_short=$(git rev-parse --verify --short $head1) && tree1=$(git rev-parse --verify HEAD:) && tree1_short=$(git rev-parse --verify --short $tree1) && echo "$changed" > foo && - git commit -a -m "$changed_iso88591" && + echo "$changed_iso88591" | git commit -a -F - && head2=$(git rev-parse --verify HEAD) && head2_short=$(git rev-parse --verify --short $head2) && tree2=$(git rev-parse --verify HEAD:) && - tree2_short=$(git rev-parse --verify --short $tree2) + tree2_short=$(git rev-parse --verify --short $tree2) && git config --unset i18n.commitEncoding ' @@ -358,10 +358,7 @@ test_expect_success 'empty email' ' test_tick && C=$(GIT_AUTHOR_EMAIL= git commit-tree HEAD^{tree} </dev/null) && A=$(git show --pretty=format:%an,%ae,%ad%n -s $C) && - test "$A" = "A U Thor,,Thu Apr 7 15:14:13 2005 -0700" || { - echo "Eh? $A" >failure - false - } + verbose test "$A" = "A U Thor,,Thu Apr 7 15:14:13 2005 -0700" ' test_expect_success 'del LF before empty (1)' ' diff --git a/t/t6012-rev-list-simplify.sh b/t/t6012-rev-list-simplify.sh index fde5e712eb..b89cd6b07a 100755 --- a/t/t6012-rev-list-simplify.sh +++ b/t/t6012-rev-list-simplify.sh @@ -95,10 +95,7 @@ check_outcome () { git log --pretty="$FMT" --parents $param | unnote >actual && sed -e "s/^.* \([^ ]*\) .*/\1/" >check <actual && - test_cmp expect check || { - cat actual - false - } + test_cmp expect check ' } @@ -121,10 +118,7 @@ test_expect_success 'full history simplification without parent' ' git log --pretty="$FMT" --full-history E -- lost | unnote >actual && sed -e "s/^.* \([^ ]*\) .*/\1/" >check <actual && - test_cmp expect check || { - cat actual - false - } + test_cmp expect check ' test_expect_success '--full-diff is not affected by --parents' ' diff --git a/t/t6014-rev-list-all.sh b/t/t6014-rev-list-all.sh index 991ab4a65b..c9bedd29cb 100755 --- a/t/t6014-rev-list-all.sh +++ b/t/t6014-rev-list-all.sh @@ -35,4 +35,8 @@ test_expect_success 'repack does not lose detached HEAD' ' ' +test_expect_success 'rev-list --graph --no-walk is forbidden' ' + test_must_fail git rev-list --graph --no-walk HEAD +' + test_done diff --git a/t/t6020-merge-df.sh b/t/t6020-merge-df.sh index 27c3d73961..2af1beec5f 100755 --- a/t/t6020-merge-df.sh +++ b/t/t6020-merge-df.sh @@ -24,7 +24,7 @@ test_expect_success 'prepare repository' ' ' test_expect_success 'Merge with d/f conflicts' ' - test_expect_code 1 git merge "merge msg" B master + test_expect_code 1 git merge -m "merge msg" master ' test_expect_success 'F/D conflict' ' diff --git a/t/t6021-merge-criss-cross.sh b/t/t6021-merge-criss-cross.sh index d15b313d4b..213deecab1 100755 --- a/t/t6021-merge-criss-cross.sh +++ b/t/t6021-merge-criss-cross.sh @@ -48,7 +48,7 @@ echo "1 " > file && git commit -m "C3" file && git branch C3 && -git merge "pre E3 merge" B A && +git merge -m "pre E3 merge" A && echo "1 2 3 changed in E3, branch B. New file size @@ -61,7 +61,7 @@ echo "1 " > file && git commit -m "E3" file && git checkout A && -git merge "pre D8 merge" A C3 && +git merge -m "pre D8 merge" C3 && echo "1 2 3 changed in C3, branch B @@ -73,7 +73,7 @@ echo "1 9" > file && git commit -m D8 file' -test_expect_success 'Criss-cross merge' 'git merge "final merge" A B' +test_expect_success 'Criss-cross merge' 'git merge -m "final merge" B' cat > file-expect <<EOF 1 diff --git a/t/t6022-merge-rename.sh b/t/t6022-merge-rename.sh index a89dfbef08..05ebba7afa 100755 --- a/t/t6022-merge-rename.sh +++ b/t/t6022-merge-rename.sh @@ -685,7 +685,7 @@ test_expect_success 'setup avoid unnecessary update, dir->(file,nothing)' ' git add -A && git commit -mA && - git checkout -b side + git checkout -b side && git rm -rf df && git commit -mB && @@ -716,7 +716,7 @@ test_expect_success 'setup avoid unnecessary update, modify/delete' ' git add -A && git commit -mA && - git checkout -b side + git checkout -b side && git rm -f file && git commit -m "Delete file" && @@ -745,7 +745,7 @@ test_expect_success 'setup avoid unnecessary update, rename/add-dest' ' git add -A && git commit -mA && - git checkout -b side + git checkout -b side && cp file newfile && git add -A && git commit -m "Add file copy" && diff --git a/t/t6023-merge-file.sh b/t/t6023-merge-file.sh index 432f086c06..190ee903cf 100755 --- a/t/t6023-merge-file.sh +++ b/t/t6023-merge-file.sh @@ -69,7 +69,8 @@ test_expect_success 'works in subdirectory' ' cp new1.txt dir/a.txt && cp orig.txt dir/o.txt && cp new2.txt dir/b.txt && - ( cd dir && git merge-file a.txt o.txt b.txt ) + ( cd dir && git merge-file a.txt o.txt b.txt ) && + test_path_is_missing a.txt ' cp new1.txt test.txt @@ -77,12 +78,29 @@ test_expect_success "merge without conflict (--quiet)" \ "git merge-file --quiet test.txt orig.txt new2.txt" cp new1.txt test2.txt -test_expect_success "merge without conflict (missing LF at EOF)" \ - "git merge-file test2.txt orig.txt new2.txt" +test_expect_failure "merge without conflict (missing LF at EOF)" \ + "git merge-file test2.txt orig.txt new4.txt" -test_expect_success "merge result added missing LF" \ +test_expect_failure "merge result added missing LF" \ "test_cmp test.txt test2.txt" +cp new4.txt test3.txt +test_expect_success "merge without conflict (missing LF at EOF, away from change in the other file)" \ + "git merge-file --quiet test3.txt new2.txt new3.txt" + +cat > expect.txt << EOF +DOMINUS regit me, +et nihil mihi deerit. +In loco pascuae ibi me collocavit, +super aquam refectionis educavit me; +animam meam convertit, +deduxit me super semitas jusitiae, +EOF +printf "propter nomen suum." >> expect.txt + +test_expect_success "merge does not add LF away of change" \ + "test_cmp test3.txt expect.txt" + cp test.txt backup.txt test_expect_success "merge with conflicts" \ "test_must_fail git merge-file test.txt orig.txt new3.txt" @@ -107,6 +125,55 @@ EOF test_expect_success "expected conflict markers" "test_cmp test.txt expect.txt" cp backup.txt test.txt + +cat > expect.txt << EOF +Dominus regit me, et nihil mihi deerit. +In loco pascuae ibi me collocavit, +super aquam refectionis educavit me; +animam meam convertit, +deduxit me super semitas jusitiae, +propter nomen suum. +Nam et si ambulavero in medio umbrae mortis, +non timebo mala, quoniam tu mecum es: +virga tua et baculus tuus ipsa me consolata sunt. +EOF +test_expect_success "merge conflicting with --ours" \ + "git merge-file --ours test.txt orig.txt new3.txt && test_cmp test.txt expect.txt" +cp backup.txt test.txt + +cat > expect.txt << EOF +DOMINUS regit me, +et nihil mihi deerit. +In loco pascuae ibi me collocavit, +super aquam refectionis educavit me; +animam meam convertit, +deduxit me super semitas jusitiae, +propter nomen suum. +Nam et si ambulavero in medio umbrae mortis, +non timebo mala, quoniam tu mecum es: +virga tua et baculus tuus ipsa me consolata sunt. +EOF +test_expect_success "merge conflicting with --theirs" \ + "git merge-file --theirs test.txt orig.txt new3.txt && test_cmp test.txt expect.txt" +cp backup.txt test.txt + +cat > expect.txt << EOF +Dominus regit me, et nihil mihi deerit. +DOMINUS regit me, +et nihil mihi deerit. +In loco pascuae ibi me collocavit, +super aquam refectionis educavit me; +animam meam convertit, +deduxit me super semitas jusitiae, +propter nomen suum. +Nam et si ambulavero in medio umbrae mortis, +non timebo mala, quoniam tu mecum es: +virga tua et baculus tuus ipsa me consolata sunt. +EOF +test_expect_success "merge conflicting with --union" \ + "git merge-file --union test.txt orig.txt new3.txt && test_cmp test.txt expect.txt" +cp backup.txt test.txt + test_expect_success "merge with conflicts, using -L" \ "test_must_fail git merge-file -L 1 -L 2 test.txt orig.txt new3.txt" @@ -260,4 +327,23 @@ test_expect_success 'marker size' ' test_cmp expect actual ' +printf "line1\nline2\nline3" >nolf-orig.txt +printf "line1\nline2\nline3x" >nolf-diff1.txt +printf "line1\nline2\nline3y" >nolf-diff2.txt + +test_expect_success 'conflict at EOF without LF resolved by --ours' \ + 'git merge-file -p --ours nolf-diff1.txt nolf-orig.txt nolf-diff2.txt >output.txt && + printf "line1\nline2\nline3x" >expect.txt && + test_cmp expect.txt output.txt' + +test_expect_success 'conflict at EOF without LF resolved by --theirs' \ + 'git merge-file -p --theirs nolf-diff1.txt nolf-orig.txt nolf-diff2.txt >output.txt && + printf "line1\nline2\nline3y" >expect.txt && + test_cmp expect.txt output.txt' + +test_expect_success 'conflict at EOF without LF resolved by --union' \ + 'git merge-file -p --union nolf-diff1.txt nolf-orig.txt nolf-diff2.txt >output.txt && + printf "line1\nline2\nline3x\nline3y" >expect.txt && + test_cmp expect.txt output.txt' + test_done diff --git a/t/t6026-merge-attr.sh b/t/t6026-merge-attr.sh index 5e439972be..04c0509c47 100755 --- a/t/t6026-merge-attr.sh +++ b/t/t6026-merge-attr.sh @@ -11,7 +11,7 @@ test_expect_success setup ' for f in text binary union do - echo Initial >$f && git add $f || break + echo Initial >$f && git add $f || return 1 done && test_tick && git commit -m Initial && @@ -19,7 +19,7 @@ test_expect_success setup ' git branch side && for f in text binary union do - echo Master >>$f && git add $f || break + echo Master >>$f && git add $f || return 1 done && test_tick && git commit -m Master && @@ -27,7 +27,7 @@ test_expect_success setup ' git checkout side && for f in text binary union do - echo Side >>$f && git add $f || break + echo Side >>$f && git add $f || return 1 done && test_tick && git commit -m Side && @@ -85,11 +85,12 @@ test_expect_success 'retry the merge with longer context' ' cat >./custom-merge <<\EOF #!/bin/sh -orig="$1" ours="$2" theirs="$3" exit="$4" +orig="$1" ours="$2" theirs="$3" exit="$4" path=$5 ( echo "orig is $orig" echo "ours is $ours" echo "theirs is $theirs" + echo "path is $path" echo "=== orig ===" cat "$orig" echo "=== ours ===" @@ -110,7 +111,7 @@ test_expect_success 'custom merge backend' ' git reset --hard anchor && git config --replace-all \ - merge.custom.driver "./custom-merge %O %A %B 0" && + merge.custom.driver "./custom-merge %O %A %B 0 %P" && git config --replace-all \ merge.custom.name "custom merge driver for testing" && @@ -121,7 +122,7 @@ test_expect_success 'custom merge backend' ' o=$(git unpack-file master^:text) && a=$(git unpack-file side^:text) && b=$(git unpack-file master:text) && - sh -c "./custom-merge $o $a $b 0" && + sh -c "./custom-merge $o $a $b 0 'text'" && sed -e 1,3d $a >check-2 && cmp check-1 check-2 && rm -f $o $a $b @@ -131,7 +132,7 @@ test_expect_success 'custom merge backend' ' git reset --hard anchor && git config --replace-all \ - merge.custom.driver "./custom-merge %O %A %B 1" && + merge.custom.driver "./custom-merge %O %A %B 1 %P" && git config --replace-all \ merge.custom.name "custom merge driver for testing" && @@ -148,9 +149,12 @@ test_expect_success 'custom merge backend' ' o=$(git unpack-file master^:text) && a=$(git unpack-file anchor:text) && b=$(git unpack-file master:text) && - sh -c "./custom-merge $o $a $b 0" && + sh -c "./custom-merge $o $a $b 0 'text'" && sed -e 1,3d $a >check-2 && cmp check-1 check-2 && + sed -e 1,3d -e 4q $a >check-3 && + echo "path is text" >expect && + cmp expect check-3 && rm -f $o $a $b ' diff --git a/t/t6028-merge-up-to-date.sh b/t/t6028-merge-up-to-date.sh index c518e9c30c..7763c1ba98 100755 --- a/t/t6028-merge-up-to-date.sh +++ b/t/t6028-merge-up-to-date.sh @@ -83,7 +83,7 @@ test_expect_success 'merge fast-forward octopus' ' git reset --hard c0 && test_tick && - git merge c1 c2 + git merge c1 c2 && expect=$(git rev-parse c2) && current=$(git rev-parse HEAD) && test "$expect" = "$current" diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh index 064f5cefeb..e74662ba5c 100755 --- a/t/t6030-bisect-porcelain.sh +++ b/t/t6030-bisect-porcelain.sh @@ -52,15 +52,8 @@ test_expect_success 'bisect starts with only one bad' ' test_expect_success 'bisect does not start with only one good' ' git bisect reset && git bisect start && - git bisect good $HASH1 || return 1 - - if git bisect next - then - echo Oops, should have failed. - false - else - : - fi + git bisect good $HASH1 && + test_must_fail git bisect next ' test_expect_success 'bisect start with one bad and good' ' @@ -191,34 +184,27 @@ test_expect_success 'bisect start: no ".git/BISECT_START" if checkout error' ' # but $HASH2 is bad, # so we should find $HASH2 as the first bad commit test_expect_success 'bisect skip: successful result' ' + test_when_finished git bisect reset && git bisect reset && git bisect start $HASH4 $HASH1 && git bisect skip && git bisect bad > my_bisect_log.txt && - grep "$HASH2 is the first bad commit" my_bisect_log.txt && - git bisect reset + grep "$HASH2 is the first bad commit" my_bisect_log.txt ' # $HASH1 is good, $HASH4 is bad, we skip $HASH3 and $HASH2 # so we should not be able to tell the first bad commit # among $HASH2, $HASH3 and $HASH4 test_expect_success 'bisect skip: cannot tell between 3 commits' ' + test_when_finished git bisect reset && git bisect start $HASH4 $HASH1 && - git bisect skip || return 1 - - if git bisect skip > my_bisect_log.txt - then - echo Oops, should have failed. - false - else - test $? -eq 2 && - grep "first bad commit could be any of" my_bisect_log.txt && - ! grep $HASH1 my_bisect_log.txt && - grep $HASH2 my_bisect_log.txt && - grep $HASH3 my_bisect_log.txt && - grep $HASH4 my_bisect_log.txt && - git bisect reset - fi + git bisect skip && + test_expect_code 2 git bisect skip >my_bisect_log.txt && + grep "first bad commit could be any of" my_bisect_log.txt && + ! grep $HASH1 my_bisect_log.txt && + grep $HASH2 my_bisect_log.txt && + grep $HASH3 my_bisect_log.txt && + grep $HASH4 my_bisect_log.txt ' # $HASH1 is good, $HASH4 is bad, we skip $HASH3 @@ -226,22 +212,15 @@ test_expect_success 'bisect skip: cannot tell between 3 commits' ' # so we should not be able to tell the first bad commit # among $HASH3 and $HASH4 test_expect_success 'bisect skip: cannot tell between 2 commits' ' + test_when_finished git bisect reset && git bisect start $HASH4 $HASH1 && - git bisect skip || return 1 - - if git bisect good > my_bisect_log.txt - then - echo Oops, should have failed. - false - else - test $? -eq 2 && - grep "first bad commit could be any of" my_bisect_log.txt && - ! grep $HASH1 my_bisect_log.txt && - ! grep $HASH2 my_bisect_log.txt && - grep $HASH3 my_bisect_log.txt && - grep $HASH4 my_bisect_log.txt && - git bisect reset - fi + git bisect skip && + test_expect_code 2 git bisect good >my_bisect_log.txt && + grep "first bad commit could be any of" my_bisect_log.txt && + ! grep $HASH1 my_bisect_log.txt && + ! grep $HASH2 my_bisect_log.txt && + grep $HASH3 my_bisect_log.txt && + grep $HASH4 my_bisect_log.txt ' # $HASH1 is good, $HASH4 is both skipped and bad, we skip $HASH3 @@ -249,24 +228,18 @@ test_expect_success 'bisect skip: cannot tell between 2 commits' ' # so we should not be able to tell the first bad commit # among $HASH3 and $HASH4 test_expect_success 'bisect skip: with commit both bad and skipped' ' + test_when_finished git bisect reset && git bisect start && git bisect skip && git bisect bad && git bisect good $HASH1 && git bisect skip && - if git bisect good > my_bisect_log.txt - then - echo Oops, should have failed. - false - else - test $? -eq 2 && - grep "first bad commit could be any of" my_bisect_log.txt && - ! grep $HASH1 my_bisect_log.txt && - ! grep $HASH2 my_bisect_log.txt && - grep $HASH3 my_bisect_log.txt && - grep $HASH4 my_bisect_log.txt && - git bisect reset - fi + test_expect_code 2 git bisect good >my_bisect_log.txt && + grep "first bad commit could be any of" my_bisect_log.txt && + ! grep $HASH1 my_bisect_log.txt && + ! grep $HASH2 my_bisect_log.txt && + grep $HASH3 my_bisect_log.txt && + grep $HASH4 my_bisect_log.txt ' # We want to automatically find the commit that @@ -389,7 +362,7 @@ test_expect_success 'bisect starting with a detached HEAD' ' test_expect_success 'bisect errors out if bad and good are mistaken' ' git bisect reset && test_must_fail git bisect start $HASH2 $HASH4 2> rev_list_error && - grep "mistake good and bad" rev_list_error && + grep "mistook good and bad" rev_list_error && git bisect reset ' @@ -601,8 +574,7 @@ test_expect_success 'test bisection on bare repo - --no-checkout specified' ' git bisect bad $HASH4 && git bisect run eval \ "test \$(git rev-list BISECT_HEAD ^$HASH2 --max-count=1 | wc -l) = 0" \ - >../nocheckout.log && - git bisect reset + >../nocheckout.log ) && grep "$HASH3 is the first bad commit" nocheckout.log ' @@ -617,8 +589,7 @@ test_expect_success 'test bisection on bare repo - --no-checkout defaulted' ' git bisect bad $HASH4 && git bisect run eval \ "test \$(git rev-list BISECT_HEAD ^$HASH2 --max-count=1 | wc -l) = 0" \ - >../defaulted.log && - git bisect reset + >../defaulted.log ) && grep "$HASH3 is the first bad commit" defaulted.log ' @@ -642,14 +613,14 @@ test_expect_success 'broken branch creation' ' mkdir missing && :> missing/MISSING && git add missing/MISSING && - git commit -m "6(broken): Added file that will be deleted" + git commit -m "6(broken): Added file that will be deleted" && git tag BROKEN_HASH6 && add_line_into_file "7(broken): second line on a broken branch" hello2 && git tag BROKEN_HASH7 && add_line_into_file "8(broken): third line on a broken branch" hello2 && git tag BROKEN_HASH8 && git rm missing/MISSING && - git commit -m "9(broken): Remove missing file" + git commit -m "9(broken): Remove missing file" && git tag BROKEN_HASH9 && rm .git/objects/39/f7e61a724187ab767d2e08442d9b6b9dab587d ' @@ -779,4 +750,148 @@ test_expect_success 'bisect log: only skip commits left' ' git bisect reset ' +test_expect_success '"git bisect bad HEAD" behaves as "git bisect bad"' ' + git checkout parallel && + git bisect start HEAD $HASH1 && + git bisect good HEAD && + git bisect bad HEAD && + test "$HASH6" = $(git rev-parse --verify HEAD) && + git bisect reset +' + +test_expect_success 'bisect starts with only one new' ' + git bisect reset && + git bisect start && + git bisect new $HASH4 && + git bisect next +' + +test_expect_success 'bisect does not start with only one old' ' + git bisect reset && + git bisect start && + git bisect old $HASH1 && + test_must_fail git bisect next +' + +test_expect_success 'bisect start with one new and old' ' + git bisect reset && + git bisect start && + git bisect old $HASH1 && + git bisect new $HASH4 && + git bisect new && + git bisect new >bisect_result && + grep "$HASH2 is the first new commit" bisect_result && + git bisect log >log_to_replay.txt && + git bisect reset +' + +test_expect_success 'bisect replay with old and new' ' + git bisect replay log_to_replay.txt >bisect_result && + grep "$HASH2 is the first new commit" bisect_result && + git bisect reset +' + +test_expect_success 'bisect cannot mix old/new and good/bad' ' + git bisect start && + git bisect bad $HASH4 && + test_must_fail git bisect old $HASH1 +' + +test_expect_success 'bisect terms needs 0 or 1 argument' ' + git bisect reset && + test_must_fail git bisect terms only-one && + test_must_fail git bisect terms 1 2 && + test_must_fail git bisect terms 2>actual && + echo "no terms defined" >expected && + test_cmp expected actual +' + +test_expect_success 'bisect terms shows good/bad after start' ' + git bisect reset && + git bisect start HEAD $HASH1 && + git bisect terms --term-good >actual && + echo good >expected && + test_cmp expected actual && + git bisect terms --term-bad >actual && + echo bad >expected && + test_cmp expected actual +' + +test_expect_success 'bisect start with one term1 and term2' ' + git bisect reset && + git bisect start --term-old term2 --term-new term1 && + git bisect term2 $HASH1 && + git bisect term1 $HASH4 && + git bisect term1 && + git bisect term1 >bisect_result && + grep "$HASH2 is the first term1 commit" bisect_result && + git bisect log >log_to_replay.txt && + git bisect reset +' + +test_expect_success 'bisect replay with term1 and term2' ' + git bisect replay log_to_replay.txt >bisect_result && + grep "$HASH2 is the first term1 commit" bisect_result && + git bisect reset +' + +test_expect_success 'bisect start term1 term2' ' + git bisect reset && + git bisect start --term-new term1 --term-old term2 $HASH4 $HASH1 && + git bisect term1 && + git bisect term1 >bisect_result && + grep "$HASH2 is the first term1 commit" bisect_result && + git bisect log >log_to_replay.txt && + git bisect reset +' + +test_expect_success 'bisect cannot mix terms' ' + git bisect reset && + git bisect start --term-good term1 --term-bad term2 $HASH4 $HASH1 && + test_must_fail git bisect a && + test_must_fail git bisect b && + test_must_fail git bisect bad && + test_must_fail git bisect good && + test_must_fail git bisect new && + test_must_fail git bisect old +' + +test_expect_success 'bisect terms rejects invalid terms' ' + git bisect reset && + test_must_fail git bisect start --term-good invalid..term && + test_must_fail git bisect terms --term-bad invalid..term && + test_must_fail git bisect terms --term-good bad && + test_must_fail git bisect terms --term-good old && + test_must_fail git bisect terms --term-good skip && + test_must_fail git bisect terms --term-good reset && + test_path_is_missing .git/BISECT_TERMS +' + +test_expect_success 'bisect start --term-* does store terms' ' + git bisect reset && + git bisect start --term-bad=one --term-good=two && + git bisect terms >actual && + cat <<-EOF >expected && + Your current terms are two for the old state + and one for the new state. + EOF + test_cmp expected actual && + git bisect terms --term-bad >actual && + echo one >expected && + test_cmp expected actual && + git bisect terms --term-good >actual && + echo two >expected && + test_cmp expected actual +' + +test_expect_success 'bisect start takes options and revs in any order' ' + git bisect reset && + git bisect start --term-good one $HASH4 \ + --term-good two --term-bad bad-term \ + $HASH1 --term-good three -- && + (git bisect terms --term-bad && git bisect terms --term-good) >actual && + printf "%s\n%s\n" bad-term three >expected && + test_cmp expected actual +' + test_done diff --git a/t/t6031-merge-filemode.sh b/t/t6031-merge-filemode.sh new file mode 100755 index 0000000000..7d06461f13 --- /dev/null +++ b/t/t6031-merge-filemode.sh @@ -0,0 +1,100 @@ +#!/bin/sh + +test_description='merge: handle file mode' +. ./test-lib.sh + +test_expect_success 'set up mode change in one branch' ' + : >file1 && + git add file1 && + git commit -m initial && + git checkout -b a1 master && + : >dummy && + git add dummy && + git commit -m a && + git checkout -b b1 master && + test_chmod +x file1 && + git add file1 && + git commit -m b1 +' + +do_one_mode () { + strategy=$1 + us=$2 + them=$3 + test_expect_success "resolve single mode change ($strategy, $us)" ' + git checkout -f $us && + git merge -s $strategy $them && + git ls-files -s file1 | grep ^100755 + ' + + test_expect_success FILEMODE "verify executable bit on file ($strategy, $us)" ' + test -x file1 + ' +} + +do_one_mode recursive a1 b1 +do_one_mode recursive b1 a1 +do_one_mode resolve a1 b1 +do_one_mode resolve b1 a1 + +test_expect_success 'set up mode change in both branches' ' + git reset --hard HEAD && + git checkout -b a2 master && + : >file2 && + H=$(git hash-object file2) && + test_chmod +x file2 && + git commit -m a2 && + git checkout -b b2 master && + : >file2 && + git add file2 && + git commit -m b2 && + { + echo "100755 $H 2 file2" + echo "100644 $H 3 file2" + } >expect +' + +do_both_modes () { + strategy=$1 + test_expect_success "detect conflict on double mode change ($strategy)" ' + git reset --hard && + git checkout -f a2 && + test_must_fail git merge -s $strategy b2 && + git ls-files -u >actual && + test_cmp actual expect && + git ls-files -s file2 | grep ^100755 + ' + + test_expect_success FILEMODE "verify executable bit on file ($strategy)" ' + test -x file2 + ' +} + +# both sides are equivalent, so no need to run both ways +do_both_modes recursive +do_both_modes resolve + +test_expect_success 'set up delete/modechange scenario' ' + git reset --hard && + git checkout -b deletion master && + git rm file1 && + git commit -m deletion +' + +do_delete_modechange () { + strategy=$1 + us=$2 + them=$3 + test_expect_success "detect delete/modechange conflict ($strategy, $us)" ' + git reset --hard && + git checkout $us && + test_must_fail git merge -s $strategy $them + ' +} + +do_delete_modechange recursive b1 deletion +do_delete_modechange recursive deletion b1 +do_delete_modechange resolve b1 deletion +do_delete_modechange resolve deletion b1 + +test_done diff --git a/t/t6031-merge-recursive.sh b/t/t6031-merge-recursive.sh deleted file mode 100755 index a953f1b55c..0000000000 --- a/t/t6031-merge-recursive.sh +++ /dev/null @@ -1,86 +0,0 @@ -#!/bin/sh - -test_description='merge-recursive: handle file mode' -. ./test-lib.sh - -test_expect_success 'mode change in one branch: keep changed version' ' - : >file1 && - git add file1 && - git commit -m initial && - git checkout -b a1 master && - : >dummy && - git add dummy && - git commit -m a && - git checkout -b b1 master && - test_chmod +x file1 && - git commit -m b1 && - git checkout a1 && - git merge-recursive master -- a1 b1 && - git ls-files -s file1 | grep ^100755 -' - -test_expect_success FILEMODE 'verify executable bit on file' ' - test -x file1 -' - -test_expect_success 'mode change in both branches: expect conflict' ' - git reset --hard HEAD && - git checkout -b a2 master && - : >file2 && - H=$(git hash-object file2) && - test_chmod +x file2 && - git commit -m a2 && - git checkout -b b2 master && - : >file2 && - git add file2 && - git commit -m b2 && - git checkout a2 && - ( - git merge-recursive master -- a2 b2 - test $? = 1 - ) && - git ls-files -u >actual && - ( - echo "100755 $H 2 file2" - echo "100644 $H 3 file2" - ) >expect && - test_cmp actual expect && - git ls-files -s file2 | grep ^100755 -' - -test_expect_success FILEMODE 'verify executable bit on file' ' - test -x file2 -' - -test_expect_success 'merging with triple rename across D/F conflict' ' - git reset --hard HEAD && - git checkout -b main && - git rm -rf . && - - echo "just a file" >sub1 && - mkdir -p sub2 && - echo content1 >sub2/file1 && - echo content2 >sub2/file2 && - echo content3 >sub2/file3 && - mkdir simple && - echo base >simple/bar && - git add -A && - test_tick && - git commit -m base && - - git checkout -b other && - echo more >>simple/bar && - test_tick && - git commit -a -m changesimplefile && - - git checkout main && - git rm sub1 && - git mv sub2 sub1 && - test_tick && - git commit -m changefiletodir && - - test_tick && - git merge other -' - -test_done diff --git a/t/t6032-merge-large-rename.sh b/t/t6032-merge-large-rename.sh index 15beecc3c6..0f79268917 100755 --- a/t/t6032-merge-large-rename.sh +++ b/t/t6032-merge-large-rename.sh @@ -28,10 +28,10 @@ make_text() { test_rename() { test_expect_success "rename ($1, $2)" ' - n='$1' - expect='$2' + n='$1' && + expect='$2' && git checkout -f master && - git branch -D test$n || true && + test_might_fail git branch -D test$n && git reset --hard initial && for i in $(count $n); do make_text $i initial initial >$i diff --git a/t/t6034-merge-rename-nocruft.sh b/t/t6034-merge-rename-nocruft.sh index 65be95fbaa..89871aa5b0 100755 --- a/t/t6034-merge-rename-nocruft.sh +++ b/t/t6034-merge-rename-nocruft.sh @@ -73,33 +73,12 @@ test_expect_success 'merge white into red (A->B,M->N)' \ ' git checkout -b red-white red && git merge white && - git write-tree >/dev/null || { - echo "BAD: merge did not complete" - return 1 - } - - test -f B || { - echo "BAD: B does not exist in working directory" - return 1 - } - test -f N || { - echo "BAD: N does not exist in working directory" - return 1 - } - test -f R || { - echo "BAD: R does not exist in working directory" - return 1 - } - - test -f A && { - echo "BAD: A still exists in working directory" - return 1 - } - test -f M && { - echo "BAD: M still exists in working directory" - return 1 - } - return 0 + git write-tree && + test_path_is_file B && + test_path_is_file N && + test_path_is_file R && + test_path_is_missing A && + test_path_is_missing M ' # This test broke in 8371234ecaaf6e14fe3f2082a855eff1bbd79ae9 @@ -108,32 +87,13 @@ test_expect_success 'merge blue into white (A->B, mod A, A untracked)' \ git checkout -b white-blue white && echo dirty >A && git merge blue && - git write-tree >/dev/null || { - echo "BAD: merge did not complete" - return 1 - } - - test -f A || { - echo "BAD: A does not exist in working directory" - return 1 - } - test `cat A` = dirty || { - echo "BAD: A content is wrong" - return 1 - } - test -f B || { - echo "BAD: B does not exist in working directory" - return 1 - } - test -f N || { - echo "BAD: N does not exist in working directory" - return 1 - } - test -f M && { - echo "BAD: M still exists in working directory" - return 1 - } - return 0 + git write-tree && + test_path_is_file A && + echo dirty >expect && + test_cmp expect A && + test_path_is_file B && + test_path_is_file N && + test_path_is_missing M ' test_done diff --git a/t/t6036-recursive-corner-cases.sh b/t/t6036-recursive-corner-cases.sh index a86087be95..9d6621c056 100755 --- a/t/t6036-recursive-corner-cases.sh +++ b/t/t6036-recursive-corner-cases.sh @@ -86,7 +86,7 @@ test_expect_success 'setup criss-cross + rename merges with basic modification' rm -rf .git && git init && - ten="0 1 2 3 4 5 6 7 8 9" + ten="0 1 2 3 4 5 6 7 8 9" && for i in $ten do echo line $i in a sample file @@ -195,12 +195,7 @@ test_expect_success 'git detects differently handled merges conflict' ' git reset --hard && git checkout D^0 && - git merge -s recursive E^0 && { - echo "BAD: should have conflicted" - test "Incorrectly merged content" = "$(cat new_a)" && - echo "BAD: Silently accepted wrong content" - return 1 - } + test_must_fail git merge -s recursive E^0 && test 3 = $(git ls-files -s | wc -l) && test 3 = $(git ls-files -u | wc -l) && @@ -533,7 +528,7 @@ test_expect_success 'merge of E2 & D fails but has appropriate contents' ' test $(git rev-parse :3:a) = $(git rev-parse B:a) && test $(git rev-parse :2:a/file) = $(git rev-parse E2:a/file) && - test $(git rev-parse :1:a/file) = $(git rev-parse C:a/file) + test $(git rev-parse :1:a/file) = $(git rev-parse C:a/file) && test $(git rev-parse :0:ignore-me) = $(git rev-parse A:ignore-me) && test -f a~D^0 diff --git a/t/t6038-merge-text-auto.sh b/t/t6038-merge-text-auto.sh index d9c2d386dd..85c10b0940 100755 --- a/t/t6038-merge-text-auto.sh +++ b/t/t6038-merge-text-auto.sh @@ -72,6 +72,10 @@ test_expect_success 'Merge after setting text=auto' ' same line EOF + if test_have_prereq NATIVE_CRLF; then + append_cr <expected >expected.temp && + mv expected.temp expected + fi && git config merge.renormalize true && git rm -fr . && rm -f .gitattributes && @@ -86,6 +90,10 @@ test_expect_success 'Merge addition of text=auto' ' same line EOF + if test_have_prereq NATIVE_CRLF; then + append_cr <expected >expected.temp && + mv expected.temp expected + fi && git config merge.renormalize true && git rm -fr . && rm -f .gitattributes && @@ -95,16 +103,19 @@ test_expect_success 'Merge addition of text=auto' ' ' test_expect_success 'Detect CRLF/LF conflict after setting text=auto' ' - q_to_cr <<-\EOF >expected && - <<<<<<< - first line - same line - ======= - first lineQ - same lineQ - >>>>>>> - EOF - + echo "<<<<<<<" >expected && + if test_have_prereq NATIVE_CRLF; then + echo first line | append_cr >>expected && + echo same line | append_cr >>expected && + echo ======= | append_cr >>expected + else + echo first line >>expected && + echo same line >>expected && + echo ======= >>expected + fi && + echo first line | append_cr >>expected && + echo same line | append_cr >>expected && + echo ">>>>>>>" >>expected && git config merge.renormalize false && rm -f .gitattributes && git reset --hard a && @@ -114,16 +125,19 @@ test_expect_success 'Detect CRLF/LF conflict after setting text=auto' ' ' test_expect_success 'Detect LF/CRLF conflict from addition of text=auto' ' - q_to_cr <<-\EOF >expected && - <<<<<<< - first lineQ - same lineQ - ======= - first line - same line - >>>>>>> - EOF - + echo "<<<<<<<" >expected && + echo first line | append_cr >>expected && + echo same line | append_cr >>expected && + if test_have_prereq NATIVE_CRLF; then + echo ======= | append_cr >>expected && + echo first line | append_cr >>expected && + echo same line | append_cr >>expected + else + echo ======= >>expected && + echo first line >>expected && + echo same line >>expected + fi && + echo ">>>>>>>" >>expected && git config merge.renormalize false && rm -f .gitattributes && git reset --hard b && diff --git a/t/t6039-merge-ignorecase.sh b/t/t6039-merge-ignorecase.sh index a977653147..531850d834 100755 --- a/t/t6039-merge-ignorecase.sh +++ b/t/t6039-merge-ignorecase.sh @@ -15,7 +15,7 @@ test_expect_success 'merge with case-changing rename' ' >TestCase && git add TestCase && git commit -m "add TestCase" && - git tag baseline + git tag baseline && git checkout -b with-camel && >foo && git add foo && diff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh index 7ac8fd06c3..3d5c238c81 100755 --- a/t/t6040-tracking-info.sh +++ b/t/t6040-tracking-info.sh @@ -12,10 +12,9 @@ advance () { } test_expect_success setup ' - for i in a b c; - do - advance $i || break - done && + advance a && + advance b && + advance c && git clone . test && ( cd test && diff --git a/t/t6041-bisect-submodule.sh b/t/t6041-bisect-submodule.sh new file mode 100755 index 0000000000..c6b7aa6977 --- /dev/null +++ b/t/t6041-bisect-submodule.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +test_description='bisect can handle submodules' + +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-submodule-update.sh + +git_bisect () { + git status -su >expect && + ls -1pR * >>expect && + tar czf "$TRASH_DIRECTORY/tmp.tgz" * && + GOOD=$(git rev-parse --verify HEAD) && + git checkout "$1" && + echo "foo" >bar && + git add bar && + git commit -m "bisect bad" && + BAD=$(git rev-parse --verify HEAD) && + git reset --hard HEAD^^ && + git submodule update && + git bisect start && + git bisect good $GOOD && + rm -rf * && + tar xzf "$TRASH_DIRECTORY/tmp.tgz" && + git status -su >actual && + ls -1pR * >>actual && + test_cmp expect actual && + git bisect bad $BAD +} + +test_submodule_switch "git_bisect" + +test_done diff --git a/t/t6050-replace.sh b/t/t6050-replace.sh index 719a11673b..c630aba657 100755 --- a/t/t6050-replace.sh +++ b/t/t6050-replace.sh @@ -7,8 +7,9 @@ test_description='Tests replace refs functionality' exec </dev/null . ./test-lib.sh +. "$TEST_DIRECTORY/lib-gpg.sh" -add_and_commit_file() +add_and_commit_file () { _file="$1" _msg="$2" @@ -18,6 +19,38 @@ add_and_commit_file() git commit --quiet -m "$_file: $_msg" } +commit_buffer_contains_parents () +{ + git cat-file commit "$1" >payload && + sed -n -e '/^$/q' -e '/^parent /p' <payload >actual && + shift && + for _parent + do + echo "parent $_parent" + done >expected && + test_cmp expected actual +} + +commit_peeling_shows_parents () +{ + _parent_number=1 + _commit="$1" + shift && + for _parent + do + _found=$(git rev-parse --verify $_commit^$_parent_number) || return 1 + test "$_found" = "$_parent" || return 1 + _parent_number=$(( $_parent_number + 1 )) + done && + test_must_fail git rev-parse --verify $_commit^$_parent_number +} + +commit_has_parents () +{ + commit_buffer_contains_parents "$@" && + commit_peeling_shows_parents "$@" +} + HASH1= HASH2= HASH3= @@ -27,36 +60,36 @@ HASH6= HASH7= test_expect_success 'set up buggy branch' ' - echo "line 1" >> hello && - echo "line 2" >> hello && - echo "line 3" >> hello && - echo "line 4" >> hello && + echo "line 1" >>hello && + echo "line 2" >>hello && + echo "line 3" >>hello && + echo "line 4" >>hello && add_and_commit_file hello "4 lines" && HASH1=$(git rev-parse --verify HEAD) && - echo "line BUG" >> hello && - echo "line 6" >> hello && - echo "line 7" >> hello && - echo "line 8" >> hello && + echo "line BUG" >>hello && + echo "line 6" >>hello && + echo "line 7" >>hello && + echo "line 8" >>hello && add_and_commit_file hello "4 more lines with a BUG" && HASH2=$(git rev-parse --verify HEAD) && - echo "line 9" >> hello && - echo "line 10" >> hello && + echo "line 9" >>hello && + echo "line 10" >>hello && add_and_commit_file hello "2 more lines" && HASH3=$(git rev-parse --verify HEAD) && - echo "line 11" >> hello && + echo "line 11" >>hello && add_and_commit_file hello "1 more line" && HASH4=$(git rev-parse --verify HEAD) && - sed -e "s/BUG/5/" hello > hello.new && + sed -e "s/BUG/5/" hello >hello.new && mv hello.new hello && add_and_commit_file hello "BUG fixed" && HASH5=$(git rev-parse --verify HEAD) && - echo "line 12" >> hello && - echo "line 13" >> hello && + echo "line 12" >>hello && + echo "line 13" >>hello && add_and_commit_file hello "2 more lines" && HASH6=$(git rev-parse --verify HEAD) && - echo "line 14" >> hello && - echo "line 15" >> hello && - echo "line 16" >> hello && + echo "line 14" >>hello && + echo "line 15" >>hello && + echo "line 16" >>hello && add_and_commit_file hello "again 3 more lines" && HASH7=$(git rev-parse --verify HEAD) ' @@ -95,7 +128,7 @@ test_expect_success 'tag replaced commit' ' ' test_expect_success '"git fsck" works' ' - git fsck master > fsck_master.out && + git fsck master >fsck_master.out && grep "dangling commit $R" fsck_master.out && grep "dangling tag $(cat .git/refs/tags/mytag)" fsck_master.out && test -z "$(git fsck)" @@ -217,14 +250,14 @@ test_expect_success 'fetch branch with replacement' ' ( cd clone_dir && git fetch origin refs/heads/tofetch:refs/heads/parallel3 && - git log --pretty=oneline parallel3 > output.txt && + git log --pretty=oneline parallel3 >output.txt && ! grep $PARA3 output.txt && - git show $PARA3 > para3.txt && + git show $PARA3 >para3.txt && grep "A U Thor" para3.txt && git fetch origin "refs/replace/*:refs/replace/*" && - git log --pretty=oneline parallel3 > output.txt && + git log --pretty=oneline parallel3 >output.txt && grep $PARA3 output.txt && - git show $PARA3 > para3.txt && + git show $PARA3 >para3.txt && grep "O Thor" para3.txt ) ' @@ -302,7 +335,7 @@ test_expect_success 'test --format medium' ' echo "$PARA3 -> $S" && echo "$MYTAG -> $HASH1" } | sort >expected && - git replace -l --format medium | sort > actual && + git replace -l --format medium | sort >actual && test_cmp expected actual ' @@ -314,14 +347,101 @@ test_expect_success 'test --format long' ' echo "$PARA3 (commit) -> $S (commit)" && echo "$MYTAG (tag) -> $HASH1 (commit)" } | sort >expected && - git replace --format=long | sort > actual && + git replace --format=long | sort >actual && test_cmp expected actual ' +test_expect_success 'setup fake editors' ' + write_script fakeeditor <<-\EOF && + sed -e "s/A U Thor/A fake Thor/" "$1" >"$1.new" + mv "$1.new" "$1" + EOF + write_script failingfakeeditor <<-\EOF + ./fakeeditor "$@" + false + EOF +' + +test_expect_success '--edit with and without already replaced object' ' + test_must_fail env GIT_EDITOR=./fakeeditor git replace --edit "$PARA3" && + GIT_EDITOR=./fakeeditor git replace --force --edit "$PARA3" && + git replace -l | grep "$PARA3" && + git cat-file commit "$PARA3" | grep "A fake Thor" && + git replace -d "$PARA3" && + GIT_EDITOR=./fakeeditor git replace --edit "$PARA3" && + git replace -l | grep "$PARA3" && + git cat-file commit "$PARA3" | grep "A fake Thor" +' + +test_expect_success '--edit and change nothing or command failed' ' + git replace -d "$PARA3" && + test_must_fail env GIT_EDITOR=true git replace --edit "$PARA3" && + test_must_fail env GIT_EDITOR="./failingfakeeditor" git replace --edit "$PARA3" && + GIT_EDITOR=./fakeeditor git replace --edit "$PARA3" && + git replace -l | grep "$PARA3" && + git cat-file commit "$PARA3" | grep "A fake Thor" +' + test_expect_success 'replace ref cleanup' ' test -n "$(git replace)" && git replace -d $(git replace) && test -z "$(git replace)" ' +test_expect_success '--graft with and without already replaced object' ' + test $(git log --oneline | wc -l) = 7 && + git replace --graft $HASH5 && + test $(git log --oneline | wc -l) = 3 && + commit_has_parents $HASH5 && + test_must_fail git replace --graft $HASH5 $HASH4 $HASH3 && + git replace --force -g $HASH5 $HASH4 $HASH3 && + commit_has_parents $HASH5 $HASH4 $HASH3 && + git replace -d $HASH5 +' + +test_expect_success GPG 'set up a signed commit' ' + echo "line 17" >>hello && + echo "line 18" >>hello && + git add hello && + test_tick && + git commit --quiet -S -m "hello: 2 more lines in a signed commit" && + HASH8=$(git rev-parse --verify HEAD) && + git verify-commit $HASH8 +' + +test_expect_success GPG '--graft with a signed commit' ' + git cat-file commit $HASH8 >orig && + git replace --graft $HASH8 && + git cat-file commit $HASH8 >repl && + commit_has_parents $HASH8 && + test_must_fail git verify-commit $HASH8 && + sed -n -e "/^tree /p" -e "/^author /p" -e "/^committer /p" orig >expected && + echo >>expected && + sed -e "/^$/q" repl >actual && + test_cmp expected actual && + git replace -d $HASH8 +' + +test_expect_success GPG 'set up a merge commit with a mergetag' ' + git reset --hard HEAD && + git checkout -b test_branch HEAD~2 && + echo "line 1 from test branch" >>hello && + echo "line 2 from test branch" >>hello && + git add hello && + test_tick && + git commit -m "hello: 2 more lines from a test branch" && + HASH9=$(git rev-parse --verify HEAD) && + git tag -s -m "tag for testing with a mergetag" test_tag HEAD && + git checkout master && + git merge -s ours test_tag && + HASH10=$(git rev-parse --verify HEAD) && + git cat-file commit $HASH10 | grep "^mergetag object" +' + +test_expect_success GPG '--graft on a commit with a mergetag' ' + test_must_fail git replace --graft $HASH10 $HASH8^1 && + git replace --graft $HASH10 $HASH8^1 $HASH9 && + git replace -d $HASH10 +' + test_done diff --git a/t/t6111-rev-list-treesame.sh b/t/t6111-rev-list-treesame.sh index 88b84dfa73..32474c23d3 100755 --- a/t/t6111-rev-list-treesame.sh +++ b/t/t6111-rev-list-treesame.sh @@ -58,7 +58,7 @@ test_expect_success setup ' git checkout master && test_tick && git merge --no-ff fiddler-branch && - note K + note K && test_commit "file=Part 1" file "Part 1" L && @@ -92,10 +92,7 @@ check_outcome () { git log --format="$FMT" $param | unnote >actual && sed -e "$munge_actual" <actual >check && - test_cmp expect check || { - cat actual - false - } + test_cmp expect check ' } diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh index c0e5b2a627..85f269411c 100755 --- a/t/t6120-describe.sh +++ b/t/t6120-describe.sh @@ -113,6 +113,14 @@ check_describe A-3-* --long HEAD^^2 check_describe c-7-* --tags check_describe e-3-* --first-parent --tags +test_expect_success 'describe --contains defaults to HEAD without commit-ish' ' + echo "A^0" >expect && + git checkout A && + test_when_finished "git checkout -" && + git describe --contains >actual && + test_cmp expect actual +' + : >err.expect check_describe A --all A^0 test_expect_success 'no warning was displayed for A' ' diff --git a/t/t6132-pathspec-exclude.sh b/t/t6132-pathspec-exclude.sh index 62049be0c7..e1e1b1fa38 100755 --- a/t/t6132-pathspec-exclude.sh +++ b/t/t6132-pathspec-exclude.sh @@ -30,7 +30,7 @@ test_expect_success 'exclude only should error out' ' ' test_expect_success 't_e_i() exclude sub' ' - git log --oneline --format=%s -- . ":(exclude)sub" >actual + git log --oneline --format=%s -- . ":(exclude)sub" >actual && cat <<EOF >expect && sub2/file file @@ -39,7 +39,7 @@ EOF ' test_expect_success 't_e_i() exclude sub/sub/file' ' - git log --oneline --format=%s -- . ":(exclude)sub/sub/file" >actual + git log --oneline --format=%s -- . ":(exclude)sub/sub/file" >actual && cat <<EOF >expect && sub2/file sub/sub/sub/file @@ -51,7 +51,7 @@ EOF ' test_expect_success 't_e_i() exclude sub using mnemonic' ' - git log --oneline --format=%s -- . ":!sub" >actual + git log --oneline --format=%s -- . ":!sub" >actual && cat <<EOF >expect && sub2/file file @@ -60,7 +60,7 @@ EOF ' test_expect_success 't_e_i() exclude :(icase)SUB' ' - git log --oneline --format=%s -- . ":(exclude,icase)SUB" >actual + git log --oneline --format=%s -- . ":(exclude,icase)SUB" >actual && cat <<EOF >expect && sub2/file file @@ -71,7 +71,7 @@ EOF test_expect_success 't_e_i() exclude sub2 from sub' ' ( cd sub && - git log --oneline --format=%s -- :/ ":/!sub2" >actual + git log --oneline --format=%s -- :/ ":/!sub2" >actual && cat <<EOF >expect && sub/sub/sub/file sub/file2 @@ -84,7 +84,7 @@ EOF ' test_expect_success 't_e_i() exclude sub/*file' ' - git log --oneline --format=%s -- . ":(exclude)sub/*file" >actual + git log --oneline --format=%s -- . ":(exclude)sub/*file" >actual && cat <<EOF >expect && sub2/file sub/file2 @@ -94,7 +94,7 @@ EOF ' test_expect_success 't_e_i() exclude :(glob)sub/*/file' ' - git log --oneline --format=%s -- . ":(exclude,glob)sub/*/file" >actual + git log --oneline --format=%s -- . ":(exclude,glob)sub/*/file" >actual && cat <<EOF >expect && sub2/file sub/sub/sub/file @@ -106,7 +106,7 @@ EOF ' test_expect_success 'm_p_d() exclude sub' ' - git ls-files -- . ":(exclude)sub" >actual + git ls-files -- . ":(exclude)sub" >actual && cat <<EOF >expect && file sub2/file @@ -115,7 +115,7 @@ EOF ' test_expect_success 'm_p_d() exclude sub/sub/file' ' - git ls-files -- . ":(exclude)sub/sub/file" >actual + git ls-files -- . ":(exclude)sub/sub/file" >actual && cat <<EOF >expect && file sub/file @@ -127,7 +127,7 @@ EOF ' test_expect_success 'm_p_d() exclude sub using mnemonic' ' - git ls-files -- . ":!sub" >actual + git ls-files -- . ":!sub" >actual && cat <<EOF >expect && file sub2/file @@ -136,7 +136,7 @@ EOF ' test_expect_success 'm_p_d() exclude :(icase)SUB' ' - git ls-files -- . ":(exclude,icase)SUB" >actual + git ls-files -- . ":(exclude,icase)SUB" >actual && cat <<EOF >expect && file sub2/file @@ -147,7 +147,7 @@ EOF test_expect_success 'm_p_d() exclude sub2 from sub' ' ( cd sub && - git ls-files -- :/ ":/!sub2" >actual + git ls-files -- :/ ":/!sub2" >actual && cat <<EOF >expect && ../file file @@ -160,7 +160,7 @@ EOF ' test_expect_success 'm_p_d() exclude sub/*file' ' - git ls-files -- . ":(exclude)sub/*file" >actual + git ls-files -- . ":(exclude)sub/*file" >actual && cat <<EOF >expect && file sub/file2 @@ -170,7 +170,7 @@ EOF ' test_expect_success 'm_p_d() exclude :(glob)sub/*/file' ' - git ls-files -- . ":(exclude,glob)sub/*/file" >actual + git ls-files -- . ":(exclude,glob)sub/*/file" >actual && cat <<EOF >expect && file sub/file diff --git a/t/t6200-fmt-merge-msg.sh b/t/t6200-fmt-merge-msg.sh index 54b5744cc5..2e2fb0e957 100755 --- a/t/t6200-fmt-merge-msg.sh +++ b/t/t6200-fmt-merge-msg.sh @@ -194,7 +194,7 @@ test_expect_success '--log=5 with custom comment character' ' ' test_expect_success 'merge.log=0 disables shortlog' ' - echo "Merge branch ${apos}left${apos}" >expected + echo "Merge branch ${apos}left${apos}" >expected && git -c merge.log=0 fmt-merge-msg <.git/FETCH_HEAD >actual && test_cmp expected actual ' diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh index bda354c1c4..19a2823025 100755 --- a/t/t6300-for-each-ref.sh +++ b/t/t6300-for-each-ref.sh @@ -8,8 +8,8 @@ test_description='for-each-ref test' . ./test-lib.sh . "$TEST_DIRECTORY"/lib-gpg.sh -# Mon Jul 3 15:18:43 2006 +0000 -datestamp=1151939923 +# Mon Jul 3 23:18:43 2006 +0000 +datestamp=1151968723 setdate_and_increment () { GIT_COMMITTER_DATE="$datestamp +0200" datestamp=$(expr "$datestamp" + 1) @@ -28,7 +28,10 @@ test_expect_success setup ' git update-ref refs/remotes/origin/master master && git remote add origin nowhere && git config branch.master.remote origin && - git config branch.master.merge refs/heads/master + git config branch.master.merge refs/heads/master && + git remote add myfork elsewhere && + git config remote.pushdefault myfork && + git config push.default current ' test_atom() { @@ -46,10 +49,17 @@ test_atom() { } test_atom head refname refs/heads/master +test_atom head refname:short master +test_atom head refname:strip=1 heads/master +test_atom head refname:strip=2 master test_atom head upstream refs/remotes/origin/master +test_atom head upstream:short origin/master +test_atom head push refs/remotes/myfork/master +test_atom head push:short myfork/master test_atom head objecttype commit test_atom head objectsize 171 test_atom head objectname $(git rev-parse refs/heads/master) +test_atom head objectname:short $(git rev-parse --short refs/heads/master) test_atom head tree $(git rev-parse refs/heads/master^{tree}) test_atom head parent '' test_atom head numparent 0 @@ -57,21 +67,21 @@ test_atom head object '' test_atom head type '' test_atom head '*objectname' '' test_atom head '*objecttype' '' -test_atom head author 'A U Thor <author@example.com> 1151939924 +0200' +test_atom head author 'A U Thor <author@example.com> 1151968724 +0200' test_atom head authorname 'A U Thor' test_atom head authoremail '<author@example.com>' -test_atom head authordate 'Mon Jul 3 17:18:44 2006 +0200' -test_atom head committer 'C O Mitter <committer@example.com> 1151939923 +0200' +test_atom head authordate 'Tue Jul 4 01:18:44 2006 +0200' +test_atom head committer 'C O Mitter <committer@example.com> 1151968723 +0200' test_atom head committername 'C O Mitter' test_atom head committeremail '<committer@example.com>' -test_atom head committerdate 'Mon Jul 3 17:18:43 2006 +0200' +test_atom head committerdate 'Tue Jul 4 01:18:43 2006 +0200' test_atom head tag '' test_atom head tagger '' test_atom head taggername '' test_atom head taggeremail '' test_atom head taggerdate '' -test_atom head creator 'C O Mitter <committer@example.com> 1151939923 +0200' -test_atom head creatordate 'Mon Jul 3 17:18:43 2006 +0200' +test_atom head creator 'C O Mitter <committer@example.com> 1151968723 +0200' +test_atom head creatordate 'Tue Jul 4 01:18:43 2006 +0200' test_atom head subject 'Initial' test_atom head contents:subject 'Initial' test_atom head body '' @@ -82,16 +92,19 @@ test_atom head contents 'Initial test_atom head HEAD '*' test_atom tag refname refs/tags/testtag +test_atom tag refname:short testtag test_atom tag upstream '' +test_atom tag push '' test_atom tag objecttype tag test_atom tag objectsize 154 test_atom tag objectname $(git rev-parse refs/tags/testtag) +test_atom tag objectname:short $(git rev-parse --short refs/tags/testtag) test_atom tag tree '' test_atom tag parent '' test_atom tag numparent '' test_atom tag object $(git rev-parse refs/tags/testtag^0) test_atom tag type 'commit' -test_atom tag '*objectname' '67a36f10722846e891fbada1ba48ed035de75581' +test_atom tag '*objectname' 'ea122842f48be4afb2d1fc6a4b96c05885ab7463' test_atom tag '*objecttype' 'commit' test_atom tag author '' test_atom tag authorname '' @@ -102,18 +115,18 @@ test_atom tag committername '' test_atom tag committeremail '' test_atom tag committerdate '' test_atom tag tag 'testtag' -test_atom tag tagger 'C O Mitter <committer@example.com> 1151939925 +0200' +test_atom tag tagger 'C O Mitter <committer@example.com> 1151968725 +0200' test_atom tag taggername 'C O Mitter' test_atom tag taggeremail '<committer@example.com>' -test_atom tag taggerdate 'Mon Jul 3 17:18:45 2006 +0200' -test_atom tag creator 'C O Mitter <committer@example.com> 1151939925 +0200' -test_atom tag creatordate 'Mon Jul 3 17:18:45 2006 +0200' -test_atom tag subject 'Tagging at 1151939927' -test_atom tag contents:subject 'Tagging at 1151939927' +test_atom tag taggerdate 'Tue Jul 4 01:18:45 2006 +0200' +test_atom tag creator 'C O Mitter <committer@example.com> 1151968725 +0200' +test_atom tag creatordate 'Tue Jul 4 01:18:45 2006 +0200' +test_atom tag subject 'Tagging at 1151968727' +test_atom tag contents:subject 'Tagging at 1151968727' test_atom tag body '' test_atom tag contents:body '' test_atom tag contents:signature '' -test_atom tag contents 'Tagging at 1151939927 +test_atom tag contents 'Tagging at 1151968727 ' test_atom tag HEAD ' ' @@ -121,6 +134,16 @@ test_expect_success 'Check invalid atoms names are errors' ' test_must_fail git for-each-ref --format="%(INVALID)" refs/heads ' +test_expect_success 'arguments to :strip must be positive integers' ' + test_must_fail git for-each-ref --format="%(refname:strip=0)" && + test_must_fail git for-each-ref --format="%(refname:strip=-1)" && + test_must_fail git for-each-ref --format="%(refname:strip=foo)" +' + +test_expect_success 'stripping refnames too far gives an error' ' + test_must_fail git for-each-ref --format="%(refname:strip=3)" +' + test_expect_success 'Check format specifiers are ignored in naming date atoms' ' git for-each-ref --format="%(authordate)" refs/heads && git for-each-ref --format="%(authordate:default) %(authordate)" refs/heads && @@ -141,84 +164,130 @@ test_expect_success 'Check invalid format specifiers are errors' ' test_must_fail git for-each-ref --format="%(authordate:INVALID)" refs/heads ' -cat >expected <<\EOF -'refs/heads/master' 'Mon Jul 3 17:18:43 2006 +0200' 'Mon Jul 3 17:18:44 2006 +0200' -'refs/tags/testtag' 'Mon Jul 3 17:18:45 2006 +0200' -EOF +test_date () { + f=$1 && + committer_date=$2 && + author_date=$3 && + tagger_date=$4 && + cat >expected <<-EOF && + 'refs/heads/master' '$committer_date' '$author_date' + 'refs/tags/testtag' '$tagger_date' + EOF + ( + git for-each-ref --shell \ + --format="%(refname) %(committerdate${f:+:$f}) %(authordate${f:+:$f})" \ + refs/heads && + git for-each-ref --shell \ + --format="%(refname) %(taggerdate${f:+:$f})" \ + refs/tags + ) >actual && + test_cmp expected actual +} test_expect_success 'Check unformatted date fields output' ' - (git for-each-ref --shell --format="%(refname) %(committerdate) %(authordate)" refs/heads && - git for-each-ref --shell --format="%(refname) %(taggerdate)" refs/tags) >actual && - test_cmp expected actual + test_date "" \ + "Tue Jul 4 01:18:43 2006 +0200" \ + "Tue Jul 4 01:18:44 2006 +0200" \ + "Tue Jul 4 01:18:45 2006 +0200" ' test_expect_success 'Check format "default" formatted date fields output' ' - f=default && - (git for-each-ref --shell --format="%(refname) %(committerdate:$f) %(authordate:$f)" refs/heads && - git for-each-ref --shell --format="%(refname) %(taggerdate:$f)" refs/tags) >actual && - test_cmp expected actual + test_date default \ + "Tue Jul 4 01:18:43 2006 +0200" \ + "Tue Jul 4 01:18:44 2006 +0200" \ + "Tue Jul 4 01:18:45 2006 +0200" +' + +test_expect_success 'Check format "default-local" date fields output' ' + test_date default-local "Mon Jul 3 23:18:43 2006" "Mon Jul 3 23:18:44 2006" "Mon Jul 3 23:18:45 2006" ' # Don't know how to do relative check because I can't know when this script # is going to be run and can't fake the current time to git, and hence can't # provide expected output. Instead, I'll just make sure that "relative" # doesn't exit in error -# -#cat >expected <<\EOF -# -#EOF -# test_expect_success 'Check format "relative" date fields output' ' f=relative && (git for-each-ref --shell --format="%(refname) %(committerdate:$f) %(authordate:$f)" refs/heads && git for-each-ref --shell --format="%(refname) %(taggerdate:$f)" refs/tags) >actual ' -cat >expected <<\EOF -'refs/heads/master' '2006-07-03' '2006-07-03' -'refs/tags/testtag' '2006-07-03' -EOF +# We just check that this is the same as "relative" for now. +test_expect_success 'Check format "relative-local" date fields output' ' + test_date relative-local \ + "$(git for-each-ref --format="%(committerdate:relative)" refs/heads)" \ + "$(git for-each-ref --format="%(authordate:relative)" refs/heads)" \ + "$(git for-each-ref --format="%(taggerdate:relative)" refs/tags)" +' test_expect_success 'Check format "short" date fields output' ' - f=short && - (git for-each-ref --shell --format="%(refname) %(committerdate:$f) %(authordate:$f)" refs/heads && - git for-each-ref --shell --format="%(refname) %(taggerdate:$f)" refs/tags) >actual && - test_cmp expected actual + test_date short 2006-07-04 2006-07-04 2006-07-04 ' -cat >expected <<\EOF -'refs/heads/master' 'Mon Jul 3 15:18:43 2006' 'Mon Jul 3 15:18:44 2006' -'refs/tags/testtag' 'Mon Jul 3 15:18:45 2006' -EOF +test_expect_success 'Check format "short-local" date fields output' ' + test_date short-local 2006-07-03 2006-07-03 2006-07-03 +' test_expect_success 'Check format "local" date fields output' ' - f=local && - (git for-each-ref --shell --format="%(refname) %(committerdate:$f) %(authordate:$f)" refs/heads && - git for-each-ref --shell --format="%(refname) %(taggerdate:$f)" refs/tags) >actual && - test_cmp expected actual + test_date local \ + "Mon Jul 3 23:18:43 2006" \ + "Mon Jul 3 23:18:44 2006" \ + "Mon Jul 3 23:18:45 2006" ' -cat >expected <<\EOF -'refs/heads/master' '2006-07-03 17:18:43 +0200' '2006-07-03 17:18:44 +0200' -'refs/tags/testtag' '2006-07-03 17:18:45 +0200' -EOF - test_expect_success 'Check format "iso8601" date fields output' ' - f=iso8601 && - (git for-each-ref --shell --format="%(refname) %(committerdate:$f) %(authordate:$f)" refs/heads && - git for-each-ref --shell --format="%(refname) %(taggerdate:$f)" refs/tags) >actual && - test_cmp expected actual + test_date iso8601 \ + "2006-07-04 01:18:43 +0200" \ + "2006-07-04 01:18:44 +0200" \ + "2006-07-04 01:18:45 +0200" ' -cat >expected <<\EOF -'refs/heads/master' 'Mon, 3 Jul 2006 17:18:43 +0200' 'Mon, 3 Jul 2006 17:18:44 +0200' -'refs/tags/testtag' 'Mon, 3 Jul 2006 17:18:45 +0200' -EOF +test_expect_success 'Check format "iso8601-local" date fields output' ' + test_date iso8601-local "2006-07-03 23:18:43 +0000" "2006-07-03 23:18:44 +0000" "2006-07-03 23:18:45 +0000" +' test_expect_success 'Check format "rfc2822" date fields output' ' - f=rfc2822 && - (git for-each-ref --shell --format="%(refname) %(committerdate:$f) %(authordate:$f)" refs/heads && - git for-each-ref --shell --format="%(refname) %(taggerdate:$f)" refs/tags) >actual && + test_date rfc2822 \ + "Tue, 4 Jul 2006 01:18:43 +0200" \ + "Tue, 4 Jul 2006 01:18:44 +0200" \ + "Tue, 4 Jul 2006 01:18:45 +0200" +' + +test_expect_success 'Check format "rfc2822-local" date fields output' ' + test_date rfc2822-local "Mon, 3 Jul 2006 23:18:43 +0000" "Mon, 3 Jul 2006 23:18:44 +0000" "Mon, 3 Jul 2006 23:18:45 +0000" +' + +test_expect_success 'Check format "raw" date fields output' ' + test_date raw "1151968723 +0200" "1151968724 +0200" "1151968725 +0200" +' + +test_expect_success 'Check format "raw-local" date fields output' ' + test_date raw-local "1151968723 +0000" "1151968724 +0000" "1151968725 +0000" +' + +test_expect_success 'Check format of strftime date fields' ' + echo "my date is 2006-07-04" >expected && + git for-each-ref \ + --format="%(authordate:format:my date is %Y-%m-%d)" \ + refs/heads >actual && + test_cmp expected actual +' + +test_expect_success 'Check format of strftime-local date fields' ' + echo "my date is 2006-07-03" >expected && + git for-each-ref \ + --format="%(authordate:format-local:my date is %Y-%m-%d)" \ + refs/heads >actual && + test_cmp expected actual +' + +test_expect_success 'exercise strftime with odd fields' ' + echo >expected && + git for-each-ref --format="%(authordate:format:)" refs/heads >actual && + test_cmp expected actual && + long="long format -- $_z40$_z40$_z40$_z40$_z40$_z40$_z40" && + echo $long >expected && + git for-each-ref --format="%(authordate:format:$long)" refs/heads >actual && test_cmp expected actual ' @@ -287,59 +356,30 @@ for i in "--perl --shell" "-s --python" "--python --tcl" "--tcl --perl"; do " done -cat >expected <<\EOF -master -testtag -EOF - -test_expect_success 'Check short refname format' ' - (git for-each-ref --format="%(refname:short)" refs/heads && - git for-each-ref --format="%(refname:short)" refs/tags) >actual && - test_cmp expected actual -' - -cat >expected <<EOF -origin/master -EOF - -test_expect_success 'Check short upstream format' ' - git for-each-ref --format="%(upstream:short)" refs/heads >actual && - test_cmp expected actual -' - test_expect_success 'setup for upstream:track[short]' ' test_commit two ' -cat >expected <<EOF -[ahead 1] -EOF - -test_expect_success 'Check upstream:track format' ' - git for-each-ref --format="%(upstream:track)" refs/heads >actual && - test_cmp expected actual -' - -cat >expected <<EOF -> -EOF - -test_expect_success 'Check upstream:trackshort format' ' - git for-each-ref --format="%(upstream:trackshort)" refs/heads >actual && - test_cmp expected actual -' +test_atom head upstream:track '[ahead 1]' +test_atom head upstream:trackshort '>' +test_atom head push:track '[ahead 1]' +test_atom head push:trackshort '>' test_expect_success 'Check that :track[short] cannot be used with other atoms' ' test_must_fail git for-each-ref --format="%(refname:track)" 2>/dev/null && test_must_fail git for-each-ref --format="%(refname:trackshort)" 2>/dev/null ' -cat >expected <<EOF -$(git rev-parse --short HEAD) -EOF +test_expect_success 'Check that :track[short] works when upstream is invalid' ' + cat >expected <<-\EOF && + -test_expect_success 'Check short objectname format' ' - git for-each-ref --format="%(objectname:short)" refs/heads >actual && + EOF + test_when_finished "git config branch.master.merge refs/heads/master" && + git config branch.master.merge refs/heads/does-not-exist && + git for-each-ref \ + --format="%(upstream:track)$LF%(upstream:trackshort)" \ + refs/heads >actual && test_cmp expected actual ' @@ -504,8 +544,8 @@ body contents $sig" cat >expected <<EOF -$(git rev-parse refs/tags/master) <committer@example.com> refs/tags/master $(git rev-parse refs/tags/bogo) <committer@example.com> refs/tags/bogo +$(git rev-parse refs/tags/master) <committer@example.com> refs/tags/master EOF test_expect_success 'Verify sort with multiple keys' ' diff --git a/t/t6301-for-each-ref-errors.sh b/t/t6301-for-each-ref-errors.sh new file mode 100755 index 0000000000..cdb67a03b7 --- /dev/null +++ b/t/t6301-for-each-ref-errors.sh @@ -0,0 +1,56 @@ +#!/bin/sh + +test_description='for-each-ref errors for broken refs' + +. ./test-lib.sh + +ZEROS=$_z40 +MISSING=abababababababababababababababababababab + +test_expect_success setup ' + git commit --allow-empty -m "Initial" && + git tag testtag && + git for-each-ref >full-list && + git for-each-ref --format="%(objectname) %(refname)" >brief-list +' + +test_expect_success 'Broken refs are reported correctly' ' + r=refs/heads/bogus && + : >.git/$r && + test_when_finished "rm -f .git/$r" && + echo "warning: ignoring broken ref $r" >broken-err && + git for-each-ref >out 2>err && + test_cmp full-list out && + test_cmp broken-err err +' + +test_expect_success 'NULL_SHA1 refs are reported correctly' ' + r=refs/heads/zeros && + echo $ZEROS >.git/$r && + test_when_finished "rm -f .git/$r" && + echo "warning: ignoring broken ref $r" >zeros-err && + git for-each-ref >out 2>err && + test_cmp full-list out && + test_cmp zeros-err err && + git for-each-ref --format="%(objectname) %(refname)" >brief-out 2>brief-err && + test_cmp brief-list brief-out && + test_cmp zeros-err brief-err +' + +test_expect_success 'Missing objects are reported correctly' ' + r=refs/heads/missing && + echo $MISSING >.git/$r && + test_when_finished "rm -f .git/$r" && + echo "fatal: missing object $MISSING for $r" >missing-err && + test_must_fail git for-each-ref 2>err && + test_cmp missing-err err && + ( + cat brief-list && + echo "$MISSING $r" + ) | sort -k 2 >missing-brief-expected && + git for-each-ref --format="%(objectname) %(refname)" >brief-out 2>brief-err && + test_cmp missing-brief-expected brief-out && + test_must_be_empty brief-err +' + +test_done diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh new file mode 100755 index 0000000000..fe4796cc9c --- /dev/null +++ b/t/t6302-for-each-ref-filter.sh @@ -0,0 +1,258 @@ +#!/bin/sh + +test_description='test for-each-refs usage of ref-filter APIs' + +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-gpg.sh + +if ! test_have_prereq GPG +then + skip_all="skipping for-each-ref tests, GPG not available" + test_done +fi + +test_expect_success 'setup some history and refs' ' + test_commit one && + test_commit two && + test_commit three && + git checkout -b side && + test_commit four && + git tag -s -m "A signed tag message" signed-tag && + git tag -s -m "Annonated doubly" double-tag signed-tag && + git checkout master && + git update-ref refs/odd/spot master +' + +test_expect_success 'filtering with --points-at' ' + cat >expect <<-\EOF && + refs/heads/master + refs/odd/spot + refs/tags/three + EOF + git for-each-ref --format="%(refname)" --points-at=master >actual && + test_cmp expect actual +' + +test_expect_success 'check signed tags with --points-at' ' + sed -e "s/Z$//" >expect <<-\EOF && + refs/heads/side Z + refs/tags/four Z + refs/tags/signed-tag four + EOF + git for-each-ref --format="%(refname) %(*subject)" --points-at=side >actual && + test_cmp expect actual +' + +test_expect_success 'filtering with --merged' ' + cat >expect <<-\EOF && + refs/heads/master + refs/odd/spot + refs/tags/one + refs/tags/three + refs/tags/two + EOF + git for-each-ref --format="%(refname)" --merged=master >actual && + test_cmp expect actual +' + +test_expect_success 'filtering with --no-merged' ' + cat >expect <<-\EOF && + refs/heads/side + refs/tags/double-tag + refs/tags/four + refs/tags/signed-tag + EOF + git for-each-ref --format="%(refname)" --no-merged=master >actual && + test_cmp expect actual +' + +test_expect_success 'filtering with --contains' ' + cat >expect <<-\EOF && + refs/heads/master + refs/heads/side + refs/odd/spot + refs/tags/double-tag + refs/tags/four + refs/tags/signed-tag + refs/tags/three + refs/tags/two + EOF + git for-each-ref --format="%(refname)" --contains=two >actual && + test_cmp expect actual +' + +test_expect_success '%(color) must fail' ' + test_must_fail git for-each-ref --format="%(color)%(refname)" +' + +test_expect_success 'left alignment is default' ' + cat >expect <<-\EOF && + refname is refs/heads/master |refs/heads/master + refname is refs/heads/side |refs/heads/side + refname is refs/odd/spot |refs/odd/spot + refname is refs/tags/double-tag|refs/tags/double-tag + refname is refs/tags/four |refs/tags/four + refname is refs/tags/one |refs/tags/one + refname is refs/tags/signed-tag|refs/tags/signed-tag + refname is refs/tags/three |refs/tags/three + refname is refs/tags/two |refs/tags/two + EOF + git for-each-ref --format="%(align:30)refname is %(refname)%(end)|%(refname)" >actual && + test_cmp expect actual +' + +test_expect_success 'middle alignment' ' + cat >expect <<-\EOF && + | refname is refs/heads/master |refs/heads/master + | refname is refs/heads/side |refs/heads/side + | refname is refs/odd/spot |refs/odd/spot + |refname is refs/tags/double-tag|refs/tags/double-tag + | refname is refs/tags/four |refs/tags/four + | refname is refs/tags/one |refs/tags/one + |refname is refs/tags/signed-tag|refs/tags/signed-tag + | refname is refs/tags/three |refs/tags/three + | refname is refs/tags/two |refs/tags/two + EOF + git for-each-ref --format="|%(align:middle,30)refname is %(refname)%(end)|%(refname)" >actual && + test_cmp expect actual +' + +test_expect_success 'right alignment' ' + cat >expect <<-\EOF && + | refname is refs/heads/master|refs/heads/master + | refname is refs/heads/side|refs/heads/side + | refname is refs/odd/spot|refs/odd/spot + |refname is refs/tags/double-tag|refs/tags/double-tag + | refname is refs/tags/four|refs/tags/four + | refname is refs/tags/one|refs/tags/one + |refname is refs/tags/signed-tag|refs/tags/signed-tag + | refname is refs/tags/three|refs/tags/three + | refname is refs/tags/two|refs/tags/two + EOF + git for-each-ref --format="|%(align:30,right)refname is %(refname)%(end)|%(refname)" >actual && + test_cmp expect actual +' + +# Individual atoms inside %(align:...) and %(end) must not be quoted. + +test_expect_success 'alignment with format quote' " + cat >expect <<-\EOF && + |' '\''master| A U Thor'\'' '| + |' '\''side| A U Thor'\'' '| + |' '\''odd/spot| A U Thor'\'' '| + |' '\''double-tag| '\'' '| + |' '\''four| A U Thor'\'' '| + |' '\''one| A U Thor'\'' '| + |' '\''signed-tag| '\'' '| + |' '\''three| A U Thor'\'' '| + |' '\''two| A U Thor'\'' '| + EOF + git for-each-ref --shell --format=\"|%(align:30,middle)'%(refname:short)| %(authorname)'%(end)|\" >actual && + test_cmp expect actual +" + +test_expect_success 'nested alignment with quote formatting' " + cat >expect <<-\EOF && + |' master '| + |' side '| + |' odd/spot '| + |' double-tag '| + |' four '| + |' one '| + |' signed-tag '| + |' three '| + |' two '| + EOF + git for-each-ref --shell --format='|%(align:30,left)%(align:15,right)%(refname:short)%(end)%(end)|' >actual && + test_cmp expect actual +" + +test_expect_success 'check `%(contents:lines=1)`' ' + cat >expect <<-\EOF && + master |three + side |four + odd/spot |three + double-tag |Annonated doubly + four |four + one |one + signed-tag |A signed tag message + three |three + two |two + EOF + git for-each-ref --format="%(refname:short) |%(contents:lines=1)" >actual && + test_cmp expect actual +' + +test_expect_success 'check `%(contents:lines=0)`' ' + cat >expect <<-\EOF && + master | + side | + odd/spot | + double-tag | + four | + one | + signed-tag | + three | + two | + EOF + git for-each-ref --format="%(refname:short) |%(contents:lines=0)" >actual && + test_cmp expect actual +' + +test_expect_success 'check `%(contents:lines=99999)`' ' + cat >expect <<-\EOF && + master |three + side |four + odd/spot |three + double-tag |Annonated doubly + four |four + one |one + signed-tag |A signed tag message + three |three + two |two + EOF + git for-each-ref --format="%(refname:short) |%(contents:lines=99999)" >actual && + test_cmp expect actual +' + +test_expect_success '`%(contents:lines=-1)` should fail' ' + test_must_fail git for-each-ref --format="%(refname:short) |%(contents:lines=-1)" +' + +test_expect_success 'setup for version sort' ' + test_commit foo1.3 && + test_commit foo1.6 && + test_commit foo1.10 +' + +test_expect_success 'version sort' ' + git for-each-ref --sort=version:refname --format="%(refname:short)" refs/tags/ | grep "foo" >actual && + cat >expect <<-\EOF && + foo1.3 + foo1.6 + foo1.10 + EOF + test_cmp expect actual +' + +test_expect_success 'version sort (shortened)' ' + git for-each-ref --sort=v:refname --format="%(refname:short)" refs/tags/ | grep "foo" >actual && + cat >expect <<-\EOF && + foo1.3 + foo1.6 + foo1.10 + EOF + test_cmp expect actual +' + +test_expect_success 'reverse version sort' ' + git for-each-ref --sort=-version:refname --format="%(refname:short)" refs/tags/ | grep "foo" >actual && + cat >expect <<-\EOF && + foo1.10 + foo1.6 + foo1.3 + EOF + test_cmp expect actual +' + +test_done diff --git a/t/t6500-gc.sh b/t/t6500-gc.sh index 63194d819e..5d7d414617 100755 --- a/t/t6500-gc.sh +++ b/t/t6500-gc.sh @@ -30,4 +30,17 @@ test_expect_success 'gc -h with invalid configuration' ' test_i18ngrep "[Uu]sage" broken/usage ' +test_expect_success 'gc is not aborted due to a stale symref' ' + git init remote && + ( + cd remote && + test_commit initial && + git clone . ../client && + git branch -m develop && + cd ../client && + git fetch --prune && + git gc + ) +' + test_done diff --git a/t/t6501-freshen-objects.sh b/t/t6501-freshen-objects.sh new file mode 100755 index 0000000000..cf076dcd94 --- /dev/null +++ b/t/t6501-freshen-objects.sh @@ -0,0 +1,147 @@ +#!/bin/sh +# +# This test covers the handling of objects which might have old +# mtimes in the filesystem (because they were used previously) +# and are just now becoming referenced again. +# +# We're going to do two things that are a little bit "fake" to +# help make our simulation easier: +# +# 1. We'll turn off reflogs. You can still run into +# problems with reflogs on, but your objects +# don't get pruned until both the reflog expiration +# has passed on their references, _and_ they are out +# of prune's expiration period. Dropping reflogs +# means we only have to deal with one variable in our tests, +# but the results generalize. +# +# 2. We'll use a temporary index file to create our +# works-in-progress. Most workflows would mention +# referenced objects in the index, which prune takes +# into account. However, many operations don't. For +# example, a partial commit with "git commit foo" +# will use a temporary index. Or they may not need +# an index at all (e.g., creating a new commit +# to refer to an existing tree). + +test_description='check pruning of dependent objects' +. ./test-lib.sh + +# We care about reachability, so we do not want to use +# the normal test_commit, which creates extra tags. +add () { + echo "$1" >"$1" && + git add "$1" +} +commit () { + test_tick && + add "$1" && + git commit -m "$1" +} + +maybe_repack () { + if test -n "$repack"; then + git repack -ad + fi +} + +for repack in '' true; do + title=${repack:+repack} + title=${title:-loose} + + test_expect_success "make repo completely empty ($title)" ' + rm -rf .git && + git init + ' + + test_expect_success "disable reflogs ($title)" ' + git config core.logallrefupdates false && + git reflog expire --expire=all --all + ' + + test_expect_success "setup basic history ($title)" ' + commit base + ' + + test_expect_success "create and abandon some objects ($title)" ' + git checkout -b experiment && + commit abandon && + maybe_repack && + git checkout master && + git branch -D experiment + ' + + test_expect_success "simulate time passing ($title)" ' + find .git/objects -type f | + xargs test-chmtime -v -86400 + ' + + test_expect_success "start writing new commit with old blob ($title)" ' + tree=$( + GIT_INDEX_FILE=index.tmp && + export GIT_INDEX_FILE && + git read-tree HEAD && + add unrelated && + add abandon && + git write-tree + ) + ' + + test_expect_success "simultaneous gc ($title)" ' + git gc --prune=12.hours.ago + ' + + test_expect_success "finish writing out commit ($title)" ' + commit=$(echo foo | git commit-tree -p HEAD $tree) && + git update-ref HEAD $commit + ' + + # "abandon" blob should have been rescued by reference from new tree + test_expect_success "repository passes fsck ($title)" ' + git fsck + ' + + test_expect_success "abandon objects again ($title)" ' + git reset --hard HEAD^ && + find .git/objects -type f | + xargs test-chmtime -v -86400 + ' + + test_expect_success "start writing new commit with same tree ($title)" ' + tree=$( + GIT_INDEX_FILE=index.tmp && + export GIT_INDEX_FILE && + git read-tree HEAD && + add abandon && + add unrelated && + git write-tree + ) + ' + + test_expect_success "simultaneous gc ($title)" ' + git gc --prune=12.hours.ago + ' + + # tree should have been refreshed by write-tree + test_expect_success "finish writing out commit ($title)" ' + commit=$(echo foo | git commit-tree -p HEAD $tree) && + git update-ref HEAD $commit + ' +done + +test_expect_success 'do not complain about existing broken links' ' + cat >broken-commit <<-\EOF && + tree 0000000000000000000000000000000000000001 + parent 0000000000000000000000000000000000000002 + author whatever <whatever@example.com> 1234 -0000 + committer whatever <whatever@example.com> 1234 -0000 + + some message + EOF + commit=$(git hash-object -t commit -w broken-commit) && + git gc 2>stderr && + verbose git cat-file -e $commit && + test_must_be_empty stderr +' + +test_done diff --git a/t/t7001-mv.sh b/t/t7001-mv.sh index 54d78079e8..7b56081137 100755 --- a/t/t7001-mv.sh +++ b/t/t7001-mv.sh @@ -161,10 +161,7 @@ test_expect_success "Michael Cassar's test case" ' git mv papers/unsorted/Thesis.pdf papers/all-papers/moo-blah.pdf && T=`git write-tree` && - git ls-tree -r $T | grep partA/outline.txt || { - git ls-tree -r $T - (exit 1) - } + git ls-tree -r $T | verbose grep partA/outline.txt ' rm -fr papers partA path? @@ -350,10 +347,11 @@ test_expect_success 'git mv moves a submodule with a .git directory and .gitmodu ' test_expect_success 'git mv moves a submodule with gitfile' ' - rm -rf mod/sub && + rm -rf mod && git reset --hard && git submodule update && entry="$(git ls-files --stage sub | cut -f 1)" && + mkdir mod && ( cd mod && git mv ../sub/ . @@ -372,11 +370,12 @@ test_expect_success 'git mv moves a submodule with gitfile' ' ' test_expect_success 'mv does not complain when no .gitmodules file is found' ' - rm -rf mod/sub && + rm -rf mod && git reset --hard && git submodule update && git rm .gitmodules && entry="$(git ls-files --stage sub | cut -f 1)" && + mkdir mod && git mv sub mod/sub 2>actual.err && ! test -s actual.err && ! test -e sub && @@ -390,11 +389,12 @@ test_expect_success 'mv does not complain when no .gitmodules file is found' ' ' test_expect_success 'mv will error out on a modified .gitmodules file unless staged' ' - rm -rf mod/sub && + rm -rf mod && git reset --hard && git submodule update && git config -f .gitmodules foo.bar true && entry="$(git ls-files --stage sub | cut -f 1)" && + mkdir mod && test_must_fail git mv sub mod/sub 2>actual.err && test -s actual.err && test -e sub && @@ -413,13 +413,14 @@ test_expect_success 'mv will error out on a modified .gitmodules file unless sta ' test_expect_success 'mv issues a warning when section is not found in .gitmodules' ' - rm -rf mod/sub && + rm -rf mod && git reset --hard && git submodule update && git config -f .gitmodules --remove-section submodule.sub && git add .gitmodules && entry="$(git ls-files --stage sub | cut -f 1)" && echo "warning: Could not find section in .gitmodules where path=sub" >expect.err && + mkdir mod && git mv sub mod/sub 2>actual.err && test_i18ncmp expect.err actual.err && ! test -e sub && @@ -433,9 +434,10 @@ test_expect_success 'mv issues a warning when section is not found in .gitmodule ' test_expect_success 'mv --dry-run does not touch the submodule or .gitmodules' ' - rm -rf mod/sub && + rm -rf mod && git reset --hard && git submodule update && + mkdir mod && git mv -n sub mod/sub 2>actual.err && test -f sub/.git && git diff-index --exit-code HEAD && diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh index 66643e4bd7..edb834187a 100755 --- a/t/t7003-filter-branch.sh +++ b/t/t7003-filter-branch.sh @@ -2,6 +2,7 @@ test_description='git filter-branch' . ./test-lib.sh +. "$TEST_DIRECTORY/lib-gpg.sh" test_expect_success 'setup' ' test_commit A && @@ -292,6 +293,19 @@ test_expect_success 'Tag name filtering strips gpg signature' ' test_cmp expect actual ' +test_expect_success GPG 'Filtering retains message of gpg signed commit' ' + mkdir gpg && + touch gpg/foo && + git add gpg && + test_tick && + git commit -S -m "Adding gpg" && + + git log -1 --format="%s" > expect && + git filter-branch -f --msg-filter "cat" && + git log -1 --format="%s" > actual && + test_cmp expect actual +' + test_expect_success 'Tag name filtering allows slashes in tag names' ' git tag -m tag-with-slash X/1 && git cat-file tag X/1 | sed -e s,X/1,X/2, > expect && @@ -319,6 +333,14 @@ test_expect_success 'prune empty collapsed merges' ' test_cmp expect actual ' +test_expect_success 'prune empty works even without index/tree filters' ' + git rev-list HEAD >expect && + git commit --allow-empty -m empty && + git filter-branch -f --prune-empty HEAD && + git rev-list HEAD >actual && + test_cmp expect actual +' + test_expect_success '--remap-to-ancestor with filename filters' ' git checkout master && git reset --hard A && @@ -394,4 +416,21 @@ test_expect_success 'replace submodule revision' ' test $orig_head != `git show-ref --hash --head HEAD` ' +test_expect_success 'filter commit message without trailing newline' ' + git reset --hard original && + commit=$(printf "no newline" | git commit-tree HEAD^{tree}) && + git update-ref refs/heads/no-newline $commit && + git filter-branch -f refs/heads/no-newline && + echo $commit >expect && + git rev-parse refs/heads/no-newline >actual && + test_cmp expect actual +' + +test_expect_success 'tree-filter deals with object name vs pathname ambiguity' ' + test_when_finished "git reset --hard original" && + ambiguous=$(git rev-list -1 HEAD) && + git filter-branch --tree-filter "mv file.t $ambiguous" HEAD^.. && + git show HEAD:$ambiguous +' + test_done diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index 143a8ea605..c64579fe15 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -51,7 +51,19 @@ test_expect_success 'creating a tag using default HEAD should succeed' ' echo foo >foo && git add foo && git commit -m Foo && - git tag mytag + git tag mytag && + test_must_fail git reflog exists refs/tags/mytag +' + +test_expect_success 'creating a tag with --create-reflog should create reflog' ' + test_when_finished "git tag -d tag_with_reflog" && + git tag --create-reflog tag_with_reflog && + git reflog exists refs/tags/tag_with_reflog +' + +test_expect_success '--create-reflog does not create reflog on failure' ' + test_must_fail git tag --create-reflog mytag && + test_must_fail git reflog exists refs/tags/mytag ' test_expect_success 'listing all tags if one exists should succeed' ' @@ -1081,7 +1093,7 @@ test_expect_success GPG \ get_tag_header rfc1991-signed-tag $commit commit $time >expect echo "RFC1991 signed tag" >>expect echo '-----BEGIN PGP MESSAGE-----' >>expect -test_expect_success GPG \ +test_expect_success GPG,RFC1991 \ 'creating a signed tag with rfc1991' ' echo "rfc1991" >gpghome/gpg.conf && git tag -s -m "RFC1991 signed tag" rfc1991-signed-tag $commit && @@ -1095,7 +1107,7 @@ cp "$1" actual EOF chmod +x fakeeditor -test_expect_success GPG \ +test_expect_success GPG,RFC1991 \ 'reediting a signed tag body omits signature' ' echo "rfc1991" >gpghome/gpg.conf && echo "RFC1991 signed tag" >expect && @@ -1103,13 +1115,13 @@ test_expect_success GPG \ test_cmp expect actual ' -test_expect_success GPG \ +test_expect_success GPG,RFC1991 \ 'verifying rfc1991 signature' ' echo "rfc1991" >gpghome/gpg.conf && git tag -v rfc1991-signed-tag ' -test_expect_success GPG \ +test_expect_success GPG,RFC1991 \ 'list tag with rfc1991 signature' ' echo "rfc1991" >gpghome/gpg.conf && echo "rfc1991-signed-tag RFC1991 signed tag" >expect && @@ -1123,12 +1135,12 @@ test_expect_success GPG \ rm -f gpghome/gpg.conf -test_expect_success GPG \ +test_expect_success GPG,RFC1991 \ 'verifying rfc1991 signature without --rfc1991' ' git tag -v rfc1991-signed-tag ' -test_expect_success GPG \ +test_expect_success GPG,RFC1991 \ 'list tag with rfc1991 signature without --rfc1991' ' echo "rfc1991-signed-tag RFC1991 signed tag" >expect && git tag -l -n1 rfc1991-signed-tag >actual && @@ -1139,7 +1151,7 @@ test_expect_success GPG \ test_cmp expect actual ' -test_expect_success GPG \ +test_expect_success GPG,RFC1991 \ 'reediting a signed tag body omits signature' ' echo "RFC1991 signed tag" >expect && GIT_EDITOR=./fakeeditor git tag -f -s rfc1991-signed-tag $commit && @@ -1180,8 +1192,8 @@ test_expect_success 'message in editor has initial comment: first line' ' test_expect_success \ 'message in editor has initial comment: remainder' ' # remove commented lines from the remainder -- should be empty - >rest.expect - sed -e 1d -e '/^#/d' <actual >rest.actual && + >rest.expect && + sed -e 1d -e "/^#/d" <actual >rest.actual && test_cmp rest.expect rest.actual ' @@ -1385,41 +1397,172 @@ test_expect_success 'lexical sort' ' git tag foo1.6 && git tag foo1.10 && git tag -l --sort=refname "foo*" >actual && - cat >expect <<EOF && -foo1.10 -foo1.3 -foo1.6 -EOF + cat >expect <<-\EOF && + foo1.10 + foo1.3 + foo1.6 + EOF test_cmp expect actual ' test_expect_success 'version sort' ' git tag -l --sort=version:refname "foo*" >actual && - cat >expect <<EOF && -foo1.3 -foo1.6 -foo1.10 -EOF + cat >expect <<-\EOF && + foo1.3 + foo1.6 + foo1.10 + EOF test_cmp expect actual ' test_expect_success 'reverse version sort' ' git tag -l --sort=-version:refname "foo*" >actual && - cat >expect <<EOF && -foo1.10 -foo1.6 -foo1.3 -EOF + cat >expect <<-\EOF && + foo1.10 + foo1.6 + foo1.3 + EOF test_cmp expect actual ' test_expect_success 'reverse lexical sort' ' git tag -l --sort=-refname "foo*" >actual && - cat >expect <<EOF && -foo1.6 -foo1.3 -foo1.10 -EOF + cat >expect <<-\EOF && + foo1.6 + foo1.3 + foo1.10 + EOF + test_cmp expect actual +' + +test_expect_success 'configured lexical sort' ' + git config tag.sort "v:refname" && + git tag -l "foo*" >actual && + cat >expect <<-\EOF && + foo1.3 + foo1.6 + foo1.10 + EOF + test_cmp expect actual +' + +test_expect_success 'option override configured sort' ' + git tag -l --sort=-refname "foo*" >actual && + cat >expect <<-\EOF && + foo1.6 + foo1.3 + foo1.10 + EOF + test_cmp expect actual +' + +test_expect_success 'invalid sort parameter on command line' ' + test_must_fail git tag -l --sort=notvalid "foo*" >actual +' + +test_expect_success 'invalid sort parameter in configuratoin' ' + git config tag.sort "v:notvalid" && + test_must_fail git tag -l "foo*" +' + +test_expect_success 'version sort with prerelease reordering' ' + git config --unset tag.sort && + git config versionsort.prereleaseSuffix -rc && + git tag foo1.6-rc1 && + git tag foo1.6-rc2 && + git tag -l --sort=version:refname "foo*" >actual && + cat >expect <<-\EOF && + foo1.3 + foo1.6-rc1 + foo1.6-rc2 + foo1.6 + foo1.10 + EOF + test_cmp expect actual +' + +test_expect_success 'reverse version sort with prerelease reordering' ' + git tag -l --sort=-version:refname "foo*" >actual && + cat >expect <<-\EOF && + foo1.10 + foo1.6 + foo1.6-rc2 + foo1.6-rc1 + foo1.3 + EOF + test_cmp expect actual +' + +run_with_limited_stack () { + (ulimit -s 128 && "$@") +} + +test_lazy_prereq ULIMIT_STACK_SIZE 'run_with_limited_stack true' + +# we require ulimit, this excludes Windows +test_expect_success ULIMIT_STACK_SIZE '--contains works in a deep repo' ' + >expect && + i=1 && + while test $i -lt 8000 + do + echo "commit refs/heads/master +committer A U Thor <author@example.com> $((1000000000 + $i * 100)) +0200 +data <<EOF +commit #$i +EOF" + test $i = 1 && echo "from refs/heads/master^0" + i=$(($i + 1)) + done | git fast-import && + git checkout master && + git tag far-far-away HEAD^ && + run_with_limited_stack git tag --contains HEAD >actual && + test_cmp expect actual +' + +test_expect_success '--format should list tags as per format given' ' + cat >expect <<-\EOF && + refname : refs/tags/foo1.10 + refname : refs/tags/foo1.3 + refname : refs/tags/foo1.6 + refname : refs/tags/foo1.6-rc1 + refname : refs/tags/foo1.6-rc2 + EOF + git tag -l --format="refname : %(refname)" "foo*" >actual && + test_cmp expect actual +' + +test_expect_success 'setup --merged test tags' ' + git tag mergetest-1 HEAD~2 && + git tag mergetest-2 HEAD~1 && + git tag mergetest-3 HEAD +' + +test_expect_success '--merged cannot be used in non-list mode' ' + test_must_fail git tag --merged=mergetest-2 foo +' + +test_expect_success '--merged shows merged tags' ' + cat >expect <<-\EOF && + mergetest-1 + mergetest-2 + EOF + git tag -l --merged=mergetest-2 mergetest-* >actual && + test_cmp expect actual +' + +test_expect_success '--no-merged show unmerged tags' ' + cat >expect <<-\EOF && + mergetest-3 + EOF + git tag -l --no-merged=mergetest-2 mergetest-* >actual && + test_cmp expect actual +' + +test_expect_success 'ambiguous branch/tags not marked' ' + git tag ambiguous && + git branch ambiguous && + echo ambiguous >expect && + git tag -l ambiguous >actual && test_cmp expect actual ' diff --git a/t/t7006-pager.sh b/t/t7006-pager.sh index da958a8b56..6ea7ac4c41 100755 --- a/t/t7006-pager.sh +++ b/t/t7006-pager.sh @@ -396,7 +396,7 @@ test_expect_success TTY 'command-specific pager overrides core.pager' ' sane_unset PAGER GIT_PAGER && echo "foo:initial" >expect && >actual && - test_config core.pager "exit 1" + test_config core.pager "exit 1" && test_config pager.log "sed s/^/foo:/ >actual" && test_terminal git log --format=%s -1 && test_cmp expect actual @@ -447,4 +447,13 @@ test_expect_success TTY 'external command pagers override sub-commands' ' test_cmp expect actual ' +test_expect_success 'command with underscores does not complain' ' + write_script git-under_score <<-\EOF && + echo ok + EOF + git --exec-path=. under_score >actual 2>&1 && + echo ok >expect && + test_cmp expect actual +' + test_done diff --git a/t/t7007-show.sh b/t/t7007-show.sh index 1b824fe5ed..42d3db6246 100755 --- a/t/t7007-show.sh +++ b/t/t7007-show.sh @@ -124,4 +124,8 @@ test_expect_success '--quiet suppresses diff' ' test_cmp expect actual ' +test_expect_success 'show --graph is forbidden' ' + test_must_fail git show --graph HEAD +' + test_done diff --git a/t/t7009-filter-branch-null-sha1.sh b/t/t7009-filter-branch-null-sha1.sh index a997f7ac3a..c27f90f285 100755 --- a/t/t7009-filter-branch-null-sha1.sh +++ b/t/t7009-filter-branch-null-sha1.sh @@ -13,7 +13,7 @@ test_expect_success 'setup: a commit with a bogus null sha1 in the tree' ' { git ls-tree HEAD && printf "160000 commit $_z40\\tbroken\\n" - } >broken-tree + } >broken-tree && echo "add broken entry" >msg && tree=$(git mktree <broken-tree) && diff --git a/t/t7030-verify-tag.sh b/t/t7030-verify-tag.sh new file mode 100755 index 0000000000..4608e71343 --- /dev/null +++ b/t/t7030-verify-tag.sh @@ -0,0 +1,115 @@ +#!/bin/sh + +test_description='signed tag tests' +. ./test-lib.sh +. "$TEST_DIRECTORY/lib-gpg.sh" + +test_expect_success GPG 'create signed tags' ' + echo 1 >file && git add file && + test_tick && git commit -m initial && + git tag -s -m initial initial && + git branch side && + + echo 2 >file && test_tick && git commit -a -m second && + git tag -s -m second second && + + git checkout side && + echo 3 >elif && git add elif && + test_tick && git commit -m "third on side" && + + git checkout master && + test_tick && git merge -S side && + git tag -s -m merge merge && + + echo 4 >file && test_tick && git commit -a -S -m "fourth unsigned" && + git tag -a -m fourth-unsigned fourth-unsigned && + + test_tick && git commit --amend -S -m "fourth signed" && + git tag -s -m fourth fourth-signed && + + echo 5 >file && test_tick && git commit -a -m "fifth" && + git tag fifth-unsigned && + + git config commit.gpgsign true && + echo 6 >file && test_tick && git commit -a -m "sixth" && + git tag -a -m sixth sixth-unsigned && + + test_tick && git rebase -f HEAD^^ && git tag -s -m 6th sixth-signed HEAD^ && + git tag -m seventh -s seventh-signed && + + echo 8 >file && test_tick && git commit -a -m eighth && + git tag -uB7227189 -m eighth eighth-signed-alt +' + +test_expect_success GPG 'verify and show signatures' ' + ( + for tag in initial second merge fourth-signed sixth-signed seventh-signed + do + git verify-tag $tag 2>actual && + grep "Good signature from" actual && + ! grep "BAD signature from" actual && + echo $tag OK || exit 1 + done + ) && + ( + for tag in fourth-unsigned fifth-unsigned sixth-unsigned + do + test_must_fail git verify-tag $tag 2>actual && + ! grep "Good signature from" actual && + ! grep "BAD signature from" actual && + echo $tag OK || exit 1 + done + ) && + ( + for tag in eighth-signed-alt + do + git verify-tag $tag 2>actual && + grep "Good signature from" actual && + ! grep "BAD signature from" actual && + grep "not certified" actual && + echo $tag OK || exit 1 + done + ) +' + +test_expect_success GPG 'detect fudged signature' ' + git cat-file tag seventh-signed >raw && + sed -e "s/seventh/7th forged/" raw >forged1 && + git hash-object -w -t tag forged1 >forged1.tag && + test_must_fail git verify-tag $(cat forged1.tag) 2>actual1 && + grep "BAD signature from" actual1 && + ! grep "Good signature from" actual1 +' + +test_expect_success GPG 'verify signatures with --raw' ' + ( + for tag in initial second merge fourth-signed sixth-signed seventh-signed + do + git verify-tag --raw $tag 2>actual && + grep "GOODSIG" actual && + ! grep "BADSIG" actual && + echo $tag OK || exit 1 + done + ) && + ( + for tag in fourth-unsigned fifth-unsigned sixth-unsigned + do + test_must_fail git verify-tag --raw $tag 2>actual && + ! grep "GOODSIG" actual && + ! grep "BADSIG" actual && + echo $tag OK || exit 1 + done + ) && + ( + for tag in eighth-signed-alt + do + git verify-tag --raw $tag 2>actual && + grep "GOODSIG" actual && + ! grep "BADSIG" actual && + grep "TRUST_UNDEFINED" actual && + echo $tag OK || exit 1 + done + ) +' + +test_done diff --git a/t/t7060-wtstatus.sh b/t/t7060-wtstatus.sh index 741ec08576..44bf1d84af 100755 --- a/t/t7060-wtstatus.sh +++ b/t/t7060-wtstatus.sh @@ -106,7 +106,7 @@ test_expect_success 'git diff-index --cached -M shows 2 added + 1 unmerged' ' A THREE A TWO EOF - git diff-index --cached --name-status HEAD >actual && + git diff-index --cached -M --name-status HEAD >actual && test_cmp expected actual ' @@ -213,5 +213,19 @@ EOF git checkout master ' +test_expect_success 'status --branch with detached HEAD' ' + git reset --hard && + git checkout master^0 && + git status --branch --porcelain >actual && + cat >expected <<-EOF && + ## HEAD (no branch) + ?? .gitconfig + ?? actual + ?? expect + ?? expected + ?? mdconflict/ + EOF + test_i18ncmp expected actual +' test_done diff --git a/t/t7061-wtstatus-ignore.sh b/t/t7061-wtstatus-ignore.sh index 460789b4d8..cdc0747bf0 100755 --- a/t/t7061-wtstatus-ignore.sh +++ b/t/t7061-wtstatus-ignore.sh @@ -20,6 +20,15 @@ test_expect_success 'status untracked directory with --ignored' ' test_cmp expected actual ' +test_expect_success 'same with gitignore starting with BOM' ' + printf "\357\273\277ignored\n" >.gitignore && + mkdir -p untracked && + : >untracked/ignored && + : >untracked/uncommitted && + git status --porcelain --ignored >actual && + test_cmp expected actual +' + cat >expected <<\EOF ?? .gitignore ?? actual diff --git a/t/t7063-status-untracked-cache.sh b/t/t7063-status-untracked-cache.sh new file mode 100755 index 0000000000..0e8d0d42f2 --- /dev/null +++ b/t/t7063-status-untracked-cache.sh @@ -0,0 +1,574 @@ +#!/bin/sh + +test_description='test untracked cache' + +. ./test-lib.sh + +avoid_racy() { + sleep 1 +} + +# It's fine if git update-index returns an error code other than one, +# it'll be caught in the first test. +test_lazy_prereq UNTRACKED_CACHE ' + { git update-index --untracked-cache; ret=$?; } && + test $ret -ne 1 +' + +if ! test_have_prereq UNTRACKED_CACHE; then + skip_all='This system does not support untracked cache' + test_done +fi + +test_expect_success 'setup' ' + git init worktree && + cd worktree && + mkdir done dtwo dthree && + touch one two three done/one dtwo/two dthree/three && + git add one two done/one && + : >.git/info/exclude && + git update-index --untracked-cache +' + +test_expect_success 'untracked cache is empty' ' + test-dump-untracked-cache >../actual && + cat >../expect <<EOF && +info/exclude 0000000000000000000000000000000000000000 +core.excludesfile 0000000000000000000000000000000000000000 +exclude_per_dir .gitignore +flags 00000006 +EOF + test_cmp ../expect ../actual +' + +cat >../status.expect <<EOF && +A done/one +A one +A two +?? dthree/ +?? dtwo/ +?? three +EOF + +cat >../dump.expect <<EOF && +info/exclude e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 +core.excludesfile 0000000000000000000000000000000000000000 +exclude_per_dir .gitignore +flags 00000006 +/ 0000000000000000000000000000000000000000 recurse valid +dthree/ +dtwo/ +three +/done/ 0000000000000000000000000000000000000000 recurse valid +/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid +three +/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid +two +EOF + +test_expect_success 'status first time (empty cache)' ' + avoid_racy && + : >../trace && + GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \ + git status --porcelain >../actual && + test_cmp ../status.expect ../actual && + cat >../trace.expect <<EOF && +node creation: 3 +gitignore invalidation: 1 +directory invalidation: 0 +opendir: 4 +EOF + test_cmp ../trace.expect ../trace +' + +test_expect_success 'untracked cache after first status' ' + test-dump-untracked-cache >../actual && + test_cmp ../dump.expect ../actual +' + +test_expect_success 'status second time (fully populated cache)' ' + avoid_racy && + : >../trace && + GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \ + git status --porcelain >../actual && + test_cmp ../status.expect ../actual && + cat >../trace.expect <<EOF && +node creation: 0 +gitignore invalidation: 0 +directory invalidation: 0 +opendir: 0 +EOF + test_cmp ../trace.expect ../trace +' + +test_expect_success 'untracked cache after second status' ' + test-dump-untracked-cache >../actual && + test_cmp ../dump.expect ../actual +' + +test_expect_success 'modify in root directory, one dir invalidation' ' + avoid_racy && + : >four && + : >../trace && + GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \ + git status --porcelain >../actual && + cat >../status.expect <<EOF && +A done/one +A one +A two +?? dthree/ +?? dtwo/ +?? four +?? three +EOF + test_cmp ../status.expect ../actual && + cat >../trace.expect <<EOF && +node creation: 0 +gitignore invalidation: 0 +directory invalidation: 1 +opendir: 1 +EOF + test_cmp ../trace.expect ../trace + +' + +test_expect_success 'verify untracked cache dump' ' + test-dump-untracked-cache >../actual && + cat >../expect <<EOF && +info/exclude e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 +core.excludesfile 0000000000000000000000000000000000000000 +exclude_per_dir .gitignore +flags 00000006 +/ 0000000000000000000000000000000000000000 recurse valid +dthree/ +dtwo/ +four +three +/done/ 0000000000000000000000000000000000000000 recurse valid +/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid +three +/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid +two +EOF + test_cmp ../expect ../actual +' + +test_expect_success 'new .gitignore invalidates recursively' ' + avoid_racy && + echo four >.gitignore && + : >../trace && + GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \ + git status --porcelain >../actual && + cat >../status.expect <<EOF && +A done/one +A one +A two +?? .gitignore +?? dthree/ +?? dtwo/ +?? three +EOF + test_cmp ../status.expect ../actual && + cat >../trace.expect <<EOF && +node creation: 0 +gitignore invalidation: 1 +directory invalidation: 1 +opendir: 4 +EOF + test_cmp ../trace.expect ../trace + +' + +test_expect_success 'verify untracked cache dump' ' + test-dump-untracked-cache >../actual && + cat >../expect <<EOF && +info/exclude e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 +core.excludesfile 0000000000000000000000000000000000000000 +exclude_per_dir .gitignore +flags 00000006 +/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid +.gitignore +dthree/ +dtwo/ +three +/done/ 0000000000000000000000000000000000000000 recurse valid +/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid +three +/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid +two +EOF + test_cmp ../expect ../actual +' + +test_expect_success 'new info/exclude invalidates everything' ' + avoid_racy && + echo three >>.git/info/exclude && + : >../trace && + GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \ + git status --porcelain >../actual && + cat >../status.expect <<EOF && +A done/one +A one +A two +?? .gitignore +?? dtwo/ +EOF + test_cmp ../status.expect ../actual && + cat >../trace.expect <<EOF && +node creation: 0 +gitignore invalidation: 1 +directory invalidation: 0 +opendir: 4 +EOF + test_cmp ../trace.expect ../trace +' + +test_expect_success 'verify untracked cache dump' ' + test-dump-untracked-cache >../actual && + cat >../expect <<EOF && +info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0 +core.excludesfile 0000000000000000000000000000000000000000 +exclude_per_dir .gitignore +flags 00000006 +/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid +.gitignore +dtwo/ +/done/ 0000000000000000000000000000000000000000 recurse valid +/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid +/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid +two +EOF + test_cmp ../expect ../actual +' + +test_expect_success 'move two from tracked to untracked' ' + git rm --cached two && + test-dump-untracked-cache >../actual && + cat >../expect <<EOF && +info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0 +core.excludesfile 0000000000000000000000000000000000000000 +exclude_per_dir .gitignore +flags 00000006 +/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse +/done/ 0000000000000000000000000000000000000000 recurse valid +/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid +/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid +two +EOF + test_cmp ../expect ../actual +' + +test_expect_success 'status after the move' ' + : >../trace && + GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \ + git status --porcelain >../actual && + cat >../status.expect <<EOF && +A done/one +A one +?? .gitignore +?? dtwo/ +?? two +EOF + test_cmp ../status.expect ../actual && + cat >../trace.expect <<EOF && +node creation: 0 +gitignore invalidation: 0 +directory invalidation: 0 +opendir: 1 +EOF + test_cmp ../trace.expect ../trace +' + +test_expect_success 'verify untracked cache dump' ' + test-dump-untracked-cache >../actual && + cat >../expect <<EOF && +info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0 +core.excludesfile 0000000000000000000000000000000000000000 +exclude_per_dir .gitignore +flags 00000006 +/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid +.gitignore +dtwo/ +two +/done/ 0000000000000000000000000000000000000000 recurse valid +/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid +/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid +two +EOF + test_cmp ../expect ../actual +' + +test_expect_success 'move two from untracked to tracked' ' + git add two && + test-dump-untracked-cache >../actual && + cat >../expect <<EOF && +info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0 +core.excludesfile 0000000000000000000000000000000000000000 +exclude_per_dir .gitignore +flags 00000006 +/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse +/done/ 0000000000000000000000000000000000000000 recurse valid +/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid +/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid +two +EOF + test_cmp ../expect ../actual +' + +test_expect_success 'status after the move' ' + : >../trace && + GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \ + git status --porcelain >../actual && + cat >../status.expect <<EOF && +A done/one +A one +A two +?? .gitignore +?? dtwo/ +EOF + test_cmp ../status.expect ../actual && + cat >../trace.expect <<EOF && +node creation: 0 +gitignore invalidation: 0 +directory invalidation: 0 +opendir: 1 +EOF + test_cmp ../trace.expect ../trace +' + +test_expect_success 'verify untracked cache dump' ' + test-dump-untracked-cache >../actual && + cat >../expect <<EOF && +info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0 +core.excludesfile 0000000000000000000000000000000000000000 +exclude_per_dir .gitignore +flags 00000006 +/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid +.gitignore +dtwo/ +/done/ 0000000000000000000000000000000000000000 recurse valid +/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid +/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid +two +EOF + test_cmp ../expect ../actual +' + +test_expect_success 'set up for sparse checkout testing' ' + echo two >done/.gitignore && + echo three >>done/.gitignore && + echo two >done/two && + git add -f done/two done/.gitignore && + git commit -m "first commit" +' + +test_expect_success 'status after commit' ' + : >../trace && + GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \ + git status --porcelain >../actual && + cat >../status.expect <<EOF && +?? .gitignore +?? dtwo/ +EOF + test_cmp ../status.expect ../actual && + cat >../trace.expect <<EOF && +node creation: 0 +gitignore invalidation: 0 +directory invalidation: 0 +opendir: 2 +EOF + test_cmp ../trace.expect ../trace +' + +test_expect_success 'untracked cache correct after commit' ' + test-dump-untracked-cache >../actual && + cat >../expect <<EOF && +info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0 +core.excludesfile 0000000000000000000000000000000000000000 +exclude_per_dir .gitignore +flags 00000006 +/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid +.gitignore +dtwo/ +/done/ 0000000000000000000000000000000000000000 recurse valid +/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid +/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid +two +EOF + test_cmp ../expect ../actual +' + +test_expect_success 'set up sparse checkout' ' + echo "done/[a-z]*" >.git/info/sparse-checkout && + test_config core.sparsecheckout true && + git checkout master && + git update-index --force-untracked-cache && + git status --porcelain >/dev/null && # prime the cache + test_path_is_missing done/.gitignore && + test_path_is_file done/one +' + +test_expect_success 'create/modify files, some of which are gitignored' ' + echo two bis >done/two && + echo three >done/three && # three is gitignored + echo four >done/four && # four is gitignored at a higher level + echo five >done/five && # five is not gitignored + echo test >base && #we need to ensure that the root dir is touched + rm base +' + +test_expect_success 'test sparse status with untracked cache' ' + : >../trace && + avoid_racy && + GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \ + git status --porcelain >../status.actual && + cat >../status.expect <<EOF && + M done/two +?? .gitignore +?? done/five +?? dtwo/ +EOF + test_cmp ../status.expect ../status.actual && + cat >../trace.expect <<EOF && +node creation: 0 +gitignore invalidation: 1 +directory invalidation: 2 +opendir: 2 +EOF + test_cmp ../trace.expect ../trace +' + +test_expect_success 'untracked cache correct after status' ' + test-dump-untracked-cache >../actual && + cat >../expect <<EOF && +info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0 +core.excludesfile 0000000000000000000000000000000000000000 +exclude_per_dir .gitignore +flags 00000006 +/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid +.gitignore +dtwo/ +/done/ 1946f0437f90c5005533cbe1736a6451ca301714 recurse valid +five +/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid +/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid +two +EOF + test_cmp ../expect ../actual +' + +test_expect_success 'test sparse status again with untracked cache' ' + avoid_racy && + : >../trace && + GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \ + git status --porcelain >../status.actual && + cat >../status.expect <<EOF && + M done/two +?? .gitignore +?? done/five +?? dtwo/ +EOF + test_cmp ../status.expect ../status.actual && + cat >../trace.expect <<EOF && +node creation: 0 +gitignore invalidation: 0 +directory invalidation: 0 +opendir: 0 +EOF + test_cmp ../trace.expect ../trace +' + +test_expect_success 'set up for test of subdir and sparse checkouts' ' + mkdir done/sub && + mkdir done/sub/sub && + echo "sub" > done/sub/sub/file +' + +test_expect_success 'test sparse status with untracked cache and subdir' ' + avoid_racy && + : >../trace && + GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \ + git status --porcelain >../status.actual && + cat >../status.expect <<EOF && + M done/two +?? .gitignore +?? done/five +?? done/sub/ +?? dtwo/ +EOF + test_cmp ../status.expect ../status.actual && + cat >../trace.expect <<EOF && +node creation: 2 +gitignore invalidation: 0 +directory invalidation: 1 +opendir: 3 +EOF + test_cmp ../trace.expect ../trace +' + +test_expect_success 'verify untracked cache dump (sparse/subdirs)' ' + test-dump-untracked-cache >../actual && + cat >../expect <<EOF && +info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0 +core.excludesfile 0000000000000000000000000000000000000000 +exclude_per_dir .gitignore +flags 00000006 +/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid +.gitignore +dtwo/ +/done/ 1946f0437f90c5005533cbe1736a6451ca301714 recurse valid +five +sub/ +/done/sub/ 0000000000000000000000000000000000000000 recurse check_only valid +sub/ +/done/sub/sub/ 0000000000000000000000000000000000000000 recurse check_only valid +file +/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid +/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid +two +EOF + test_cmp ../expect ../actual +' + +test_expect_success 'test sparse status again with untracked cache and subdir' ' + avoid_racy && + : >../trace && + GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \ + git status --porcelain >../status.actual && + test_cmp ../status.expect ../status.actual && + cat >../trace.expect <<EOF && +node creation: 0 +gitignore invalidation: 0 +directory invalidation: 0 +opendir: 0 +EOF + test_cmp ../trace.expect ../trace +' + +test_expect_success 'move entry in subdir from untracked to cached' ' + git add dtwo/two && + git status --porcelain >../status.actual && + cat >../status.expect <<EOF && + M done/two +A dtwo/two +?? .gitignore +?? done/five +?? done/sub/ +EOF + test_cmp ../status.expect ../status.actual +' + +test_expect_success 'move entry in subdir from cached to untracked' ' + git rm --cached dtwo/two && + git status --porcelain >../status.actual && + cat >../status.expect <<EOF && + M done/two +?? .gitignore +?? done/five +?? done/sub/ +?? dtwo/ +EOF + test_cmp ../status.expect ../status.actual +' + +test_done diff --git a/t/t7102-reset.sh b/t/t7102-reset.sh index ee703bed64..98bcfe21aa 100755 --- a/t/t7102-reset.sh +++ b/t/t7102-reset.sh @@ -44,7 +44,9 @@ test_expect_success 'creating initial files and commits' ' echo "1st line 2nd file" >secondfile && echo "2nd line 2nd file" >>secondfile && - git -c "i18n.commitEncoding=$test_encoding" commit -a -m "$(commit_msg $test_encoding)" && + # "git commit -m" would break MinGW, as Windows refuse to pass + # $test_encoding encoded parameter to git. + commit_msg $test_encoding | git -c "i18n.commitEncoding=$test_encoding" commit -a -F - && head5=$(git rev-parse --verify HEAD) ' # git log --pretty=oneline # to see those SHA1 involved @@ -334,7 +336,9 @@ test_expect_success 'redoing the last two commits should succeed' ' echo "1st line 2nd file" >secondfile && echo "2nd line 2nd file" >>secondfile && - git -c "i18n.commitEncoding=$test_encoding" commit -a -m "$(commit_msg $test_encoding)" && + # "git commit -m" would break MinGW, as Windows refuse to pass + # $test_encoding encoded parameter to git. + commit_msg $test_encoding | git -c "i18n.commitEncoding=$test_encoding" commit -a -F - && check_changes $head5 ' diff --git a/t/t7112-reset-submodule.sh b/t/t7112-reset-submodule.sh new file mode 100755 index 0000000000..2eda6adeb1 --- /dev/null +++ b/t/t7112-reset-submodule.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +test_description='reset can handle submodules' + +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-submodule-update.sh + +test_submodule_switch "git reset --keep" + +test_submodule_switch "git reset --merge" + +test_submodule_forced_switch "git reset --hard" + +test_done diff --git a/t/t7201-co.sh b/t/t7201-co.sh index 0c9ec0ad44..885923610a 100755 --- a/t/t7201-co.sh +++ b/t/t7201-co.sh @@ -88,14 +88,10 @@ test_expect_success "checkout with unrelated dirty tree without -m" ' git checkout -f master && fill 0 1 2 3 4 5 6 7 8 >same && - cp same kept + cp same kept && git checkout side >messages && - test_cmp same kept - (cat > messages.expect <<EOF -M same -EOF -) && - touch messages.expect && + test_cmp same kept && + printf "M\t%s\n" same >messages.expect && test_cmp messages.expect messages ' @@ -109,10 +105,7 @@ test_expect_success "checkout -m with dirty tree" ' test "$(git symbolic-ref HEAD)" = "refs/heads/side" && - (cat >expect.messages <<EOF -M one -EOF -) && + printf "M\t%s\n" one >expect.messages && test_cmp expect.messages messages && fill "M one" "A three" "D two" >expect.master && @@ -223,6 +216,23 @@ test_expect_success 'checkout --merge --conflict=diff3 <branch>' ' test_cmp two expect ' +test_expect_success 'switch to another branch while carrying a deletion' ' + + git checkout -f master && git reset --hard && git clean -f && + git rm two && + + test_must_fail git checkout simple 2>errs && + test_i18ngrep overwritten errs && + + git checkout --merge simple 2>errs && + test_i18ngrep ! overwritten errs && + git ls-files -u && + test_must_fail git cat-file -t :0:two && + test "$(git cat-file -t :1:two)" = blob && + test "$(git cat-file -t :2:two)" = blob && + test_must_fail git cat-file -t :3:two +' + test_expect_success 'checkout to detach HEAD (with advice declined)' ' git config advice.detachedHead false && @@ -392,12 +402,12 @@ test_expect_success \ test_expect_success \ 'checkout w/autosetupmerge=always sets up tracking' ' + test_when_finished git config branch.autosetupmerge false && git config branch.autosetupmerge always && git checkout master && git checkout -b track2 && test "$(git config branch.track2.remote)" && - test "$(git config branch.track2.merge)" - git config branch.autosetupmerge false' + test "$(git config branch.track2.merge)"' test_expect_success 'checkout w/--track from non-branch HEAD fails' ' git checkout master^0 && @@ -574,7 +584,7 @@ test_expect_success 'checkout --conflict=merge, overriding config' ' ' test_expect_success 'checkout --conflict=diff3' ' - git config --unset merge.conflictstyle + test_unconfig merge.conflictstyle && setup_conflicting_index && echo "none of the above" >sample && echo ourside >expect && diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh index 04118ad75b..86ceb38b01 100755 --- a/t/t7300-clean.sh +++ b/t/t7300-clean.sh @@ -119,10 +119,7 @@ test_expect_success C_LOCALE_OUTPUT 'git clean with relative prefix' ' git clean -n ../src | sed -n -e "s|^Would remove ||p" ) && - test "$would_clean" = ../src/part3.c || { - echo "OOps <$would_clean>" - false - } + verbose test "$would_clean" = ../src/part3.c ' test_expect_success C_LOCALE_OUTPUT 'git clean with absolute path' ' @@ -134,10 +131,7 @@ test_expect_success C_LOCALE_OUTPUT 'git clean with absolute path' ' git clean -n "$(pwd)/../src" | sed -n -e "s|^Would remove ||p" ) && - test "$would_clean" = ../src/part3.c || { - echo "OOps <$would_clean>" - false - } + verbose test "$would_clean" = ../src/part3.c ' test_expect_success 'git clean with out of work tree relative path' ' @@ -438,9 +432,7 @@ test_expect_success 'nested git work tree' ' ( cd foo && git init && - >hello.world - git add . && - git commit -a -m nested + test_commit nested hello.world ) && ( cd bar && @@ -449,9 +441,7 @@ test_expect_success 'nested git work tree' ' ( cd baz/boo && git init && - >deeper.world - git add . && - git commit -a -m deeply.nested + test_commit deeply.nested deeper.world ) && git clean -f -d && test -f foo/.git/index && @@ -461,15 +451,153 @@ test_expect_success 'nested git work tree' ' ! test -d bar ' +test_expect_success 'should clean things that almost look like git but are not' ' + rm -fr almost_git almost_bare_git almost_submodule && + mkdir -p almost_git/.git/objects && + mkdir -p almost_git/.git/refs && + cat >almost_git/.git/HEAD <<-\EOF && + garbage + EOF + cp -r almost_git/.git/ almost_bare_git && + mkdir almost_submodule/ && + cat >almost_submodule/.git <<-\EOF && + garbage + EOF + test_when_finished "rm -rf almost_*" && + git clean -f -d && + test_path_is_missing almost_git && + test_path_is_missing almost_bare_git && + test_path_is_missing almost_submodule +' + +test_expect_success 'should not clean submodules' ' + rm -fr repo to_clean sub1 sub2 && + mkdir repo to_clean && + ( + cd repo && + git init && + test_commit msg hello.world + ) && + git submodule add ./repo/.git sub1 && + git commit -m "sub1" && + git branch before_sub2 && + git submodule add ./repo/.git sub2 && + git commit -m "sub2" && + git checkout before_sub2 && + >to_clean/should_clean.this && + git clean -f -d && + test_path_is_file repo/.git/index && + test_path_is_file repo/hello.world && + test_path_is_file sub1/.git && + test_path_is_file sub1/hello.world && + test_path_is_file sub2/.git && + test_path_is_file sub2/hello.world && + test_path_is_missing to_clean +' + +test_expect_success POSIXPERM 'should avoid cleaning possible submodules' ' + rm -fr to_clean possible_sub1 && + mkdir to_clean possible_sub1 && + test_when_finished "rm -rf possible_sub*" && + echo "gitdir: foo" >possible_sub1/.git && + >possible_sub1/hello.world && + chmod 0 possible_sub1/.git && + >to_clean/should_clean.this && + git clean -f -d && + test_path_is_file possible_sub1/.git && + test_path_is_file possible_sub1/hello.world && + test_path_is_missing to_clean +' + +test_expect_success 'nested (empty) git should be kept' ' + rm -fr empty_repo to_clean && + git init empty_repo && + mkdir to_clean && + >to_clean/should_clean.this && + git clean -f -d && + test_path_is_file empty_repo/.git/HEAD && + test_path_is_missing to_clean +' + +test_expect_success 'nested bare repositories should be cleaned' ' + rm -fr bare1 bare2 subdir && + git init --bare bare1 && + git clone --local --bare . bare2 && + mkdir subdir && + cp -r bare2 subdir/bare3 && + git clean -f -d && + test_path_is_missing bare1 && + test_path_is_missing bare2 && + test_path_is_missing subdir +' + +test_expect_failure 'nested (empty) bare repositories should be cleaned even when in .git' ' + rm -fr strange_bare && + mkdir strange_bare && + git init --bare strange_bare/.git && + git clean -f -d && + test_path_is_missing strange_bare +' + +test_expect_failure 'nested (non-empty) bare repositories should be cleaned even when in .git' ' + rm -fr strange_bare && + mkdir strange_bare && + git clone --local --bare . strange_bare/.git && + git clean -f -d && + test_path_is_missing strange_bare +' + +test_expect_success 'giving path in nested git work tree will remove it' ' + rm -fr repo && + mkdir repo && + ( + cd repo && + git init && + mkdir -p bar/baz && + test_commit msg bar/baz/hello.world + ) && + git clean -f -d repo/bar/baz && + test_path_is_file repo/.git/HEAD && + test_path_is_dir repo/bar/ && + test_path_is_missing repo/bar/baz +' + +test_expect_success 'giving path to nested .git will not remove it' ' + rm -fr repo && + mkdir repo untracked && + ( + cd repo && + git init && + test_commit msg hello.world + ) && + git clean -f -d repo/.git && + test_path_is_file repo/.git/HEAD && + test_path_is_dir repo/.git/refs && + test_path_is_dir repo/.git/objects && + test_path_is_dir untracked/ +' + +test_expect_success 'giving path to nested .git/ will remove contents' ' + rm -fr repo untracked && + mkdir repo untracked && + ( + cd repo && + git init && + test_commit msg hello.world + ) && + git clean -f -d repo/.git/ && + test_path_is_dir repo/.git && + test_dir_is_empty repo/.git && + test_path_is_dir untracked/ +' + test_expect_success 'force removal of nested git work tree' ' rm -fr foo bar baz && mkdir -p foo bar baz/boo && ( cd foo && git init && - >hello.world - git add . && - git commit -a -m nested + test_commit nested hello.world ) && ( cd bar && @@ -478,9 +606,7 @@ test_expect_success 'force removal of nested git work tree' ' ( cd baz/boo && git init && - >deeper.world - git add . && - git commit -a -m deeply.nested + test_commit deeply.nested deeper.world ) && git clean -f -f -d && ! test -d foo && diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh index 7c88245031..540771ca41 100755 --- a/t/t7400-submodule-basic.sh +++ b/t/t7400-submodule-basic.sh @@ -171,6 +171,23 @@ test_expect_success 'submodule add with ./ in path' ' test_cmp empty untracked ' +test_expect_success 'submodule add with /././ in path' ' + echo "refs/heads/master" >expect && + >empty && + + ( + cd addtest && + git submodule add "$submodurl" dotslashdotsubmod/././frotz/./ && + git submodule init + ) && + + rm -f heads head untracked && + inspect addtest/dotslashdotsubmod/frotz ../../.. && + test_cmp expect heads && + test_cmp expect head && + test_cmp empty untracked +' + test_expect_success 'submodule add with // in path' ' echo "refs/heads/master" >expect && >empty && @@ -749,7 +766,7 @@ test_expect_success 'moving the superproject does not break submodules' ' ( cd addtest && git submodule status >expect - ) + ) && mv addtest addtest2 && ( cd addtest2 && @@ -970,7 +987,7 @@ test_expect_success 'submodule with UTF-8 name' ' test_expect_success 'submodule add clone shallow submodule' ' mkdir super && - pwd=$(pwd) + pwd=$(pwd) && ( cd super && git init && diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh index 29d3d2cca0..dda3929d99 100755 --- a/t/t7406-submodule-update.sh +++ b/t/t7406-submodule-update.sh @@ -754,7 +754,7 @@ test_expect_success SYMLINKS 'submodule update can handle symbolic links in pwd' test_expect_success 'submodule update clone shallow submodule' ' git clone cloned super3 && - pwd=$(pwd) + pwd=$(pwd) && (cd super3 && sed -e "s#url = ../#url = file://$pwd/#" <.gitmodules >.gitmodules.tmp && mv -f .gitmodules.tmp .gitmodules && diff --git a/t/t7410-submodule-checkout-to.sh b/t/t7410-submodule-checkout-to.sh new file mode 100755 index 0000000000..1acef32647 --- /dev/null +++ b/t/t7410-submodule-checkout-to.sh @@ -0,0 +1,60 @@ +#!/bin/sh + +test_description='Combination of submodules and multiple workdirs' + +. ./test-lib.sh + +base_path=$(pwd -P) + +test_expect_success 'setup: make origin' \ + 'mkdir -p origin/sub && ( cd origin/sub && git init && + echo file1 >file1 && + git add file1 && + git commit -m file1 ) && + mkdir -p origin/main && ( cd origin/main && git init && + git submodule add ../sub && + git commit -m "add sub" ) && + ( cd origin/sub && + echo file1updated >file1 && + git add file1 && + git commit -m "file1 updated" ) && + ( cd origin/main/sub && git pull ) && + ( cd origin/main && + git add sub && + git commit -m "sub updated" )' + +test_expect_success 'setup: clone' \ + 'mkdir clone && ( cd clone && + git clone --recursive "$base_path/origin/main")' + +rev1_hash_main=$(git --git-dir=origin/main/.git show --pretty=format:%h -q "HEAD~1") +rev1_hash_sub=$(git --git-dir=origin/sub/.git show --pretty=format:%h -q "HEAD~1") + +test_expect_success 'checkout main' \ + 'mkdir default_checkout && + (cd clone/main && + git worktree add "$base_path/default_checkout/main" "$rev1_hash_main")' + +test_expect_failure 'can see submodule diffs just after checkout' \ + '(cd default_checkout/main && git diff --submodule master"^!" | grep "file1 updated")' + +test_expect_success 'checkout main and initialize independed clones' \ + 'mkdir fully_cloned_submodule && + (cd clone/main && + git worktree add "$base_path/fully_cloned_submodule/main" "$rev1_hash_main") && + (cd fully_cloned_submodule/main && git submodule update)' + +test_expect_success 'can see submodule diffs after independed cloning' \ + '(cd fully_cloned_submodule/main && git diff --submodule master"^!" | grep "file1 updated")' + +test_expect_success 'checkout sub manually' \ + 'mkdir linked_submodule && + (cd clone/main && + git worktree add "$base_path/linked_submodule/main" "$rev1_hash_main") && + (cd clone/main/sub && + git worktree add "$base_path/linked_submodule/main/sub" "$rev1_hash_sub")' + +test_expect_success 'can see submodule diffs after manual checkout of linked submodule' \ + '(cd linked_submodule/main && git diff --submodule master"^!" | grep "file1 updated")' + +test_done diff --git a/t/t7411-submodule-config.sh b/t/t7411-submodule-config.sh new file mode 100755 index 0000000000..fc97c3314e --- /dev/null +++ b/t/t7411-submodule-config.sh @@ -0,0 +1,153 @@ +#!/bin/sh +# +# Copyright (c) 2014 Heiko Voigt +# + +test_description='Test submodules config cache infrastructure + +This test verifies that parsing .gitmodules configurations directly +from the database and from the worktree works. +' + +TEST_NO_CREATE_REPO=1 +. ./test-lib.sh + +test_expect_success 'submodule config cache setup' ' + mkdir submodule && + (cd submodule && + git init && + echo a >a && + git add . && + git commit -ma + ) && + mkdir super && + (cd super && + git init && + git submodule add ../submodule && + git submodule add ../submodule a && + git commit -m "add as submodule and as a" && + git mv a b && + git commit -m "move a to b" + ) +' + +cat >super/expect <<EOF +Submodule name: 'a' for path 'a' +Submodule name: 'a' for path 'b' +Submodule name: 'submodule' for path 'submodule' +Submodule name: 'submodule' for path 'submodule' +EOF + +test_expect_success 'test parsing and lookup of submodule config by path' ' + (cd super && + test-submodule-config \ + HEAD^ a \ + HEAD b \ + HEAD^ submodule \ + HEAD submodule \ + >actual && + test_cmp expect actual + ) +' + +test_expect_success 'test parsing and lookup of submodule config by name' ' + (cd super && + test-submodule-config --name \ + HEAD^ a \ + HEAD a \ + HEAD^ submodule \ + HEAD submodule \ + >actual && + test_cmp expect actual + ) +' + +cat >super/expect_error <<EOF +Submodule name: 'a' for path 'b' +Submodule name: 'submodule' for path 'submodule' +EOF + +test_expect_success 'error in one submodule config lets continue' ' + (cd super && + cp .gitmodules .gitmodules.bak && + echo " value = \"" >>.gitmodules && + git add .gitmodules && + mv .gitmodules.bak .gitmodules && + git commit -m "add error" && + test-submodule-config \ + HEAD b \ + HEAD submodule \ + >actual && + test_cmp expect_error actual + ) +' + +cat >super/expect_url <<EOF +Submodule url: 'git@somewhere.else.net:a.git' for path 'b' +Submodule url: 'git@somewhere.else.net:submodule.git' for path 'submodule' +EOF + +cat >super/expect_local_path <<EOF +Submodule name: 'a' for path 'c' +Submodule name: 'submodule' for path 'submodule' +EOF + +test_expect_success 'reading of local configuration' ' + (cd super && + old_a=$(git config submodule.a.url) && + old_submodule=$(git config submodule.submodule.url) && + git config submodule.a.url git@somewhere.else.net:a.git && + git config submodule.submodule.url git@somewhere.else.net:submodule.git && + test-submodule-config --url \ + "" b \ + "" submodule \ + >actual && + test_cmp expect_url actual && + git config submodule.a.path c && + test-submodule-config \ + "" c \ + "" submodule \ + >actual && + test_cmp expect_local_path actual && + git config submodule.a.url $old_a && + git config submodule.submodule.url $old_submodule && + git config --unset submodule.a.path c + ) +' + +cat >super/expect_fetchrecurse_die.err <<EOF +fatal: bad submodule.submodule.fetchrecursesubmodules argument: blabla +EOF + +test_expect_success 'local error in fetchrecursesubmodule dies early' ' + (cd super && + git config submodule.submodule.fetchrecursesubmodules blabla && + test_must_fail test-submodule-config \ + "" b \ + "" submodule \ + >actual.out 2>actual.err && + touch expect_fetchrecurse_die.out && + test_cmp expect_fetchrecurse_die.out actual.out && + test_cmp expect_fetchrecurse_die.err actual.err && + git config --unset submodule.submodule.fetchrecursesubmodules + ) +' + +test_expect_success 'error in history in fetchrecursesubmodule lets continue' ' + (cd super && + git config -f .gitmodules \ + submodule.submodule.fetchrecursesubmodules blabla && + git add .gitmodules && + git config --unset -f .gitmodules \ + submodule.submodule.fetchrecursesubmodules && + git commit -m "add error in fetchrecursesubmodules" && + test-submodule-config \ + HEAD b \ + HEAD submodule \ + >actual && + test_cmp expect_error actual && + git reset --hard HEAD^ + ) +' + +test_done diff --git a/t/t7501-commit.sh b/t/t7501-commit.sh index d58b097ff3..63e04277f9 100755 --- a/t/t7501-commit.sh +++ b/t/t7501-commit.sh @@ -346,8 +346,21 @@ test_expect_success 'amend commit to fix date' ' ' -test_expect_success 'commit complains about bogus date' ' - test_must_fail git commit --amend --date=10.11.2010 +test_expect_success 'commit mentions forced date in output' ' + git commit --amend --date=2010-01-02T03:04:05 >output && + grep "Date: *Sat Jan 2 03:04:05 2010" output +' + +test_expect_success 'commit complains about completely bogus dates' ' + test_must_fail git commit --amend --date=seventeen +' + +test_expect_success 'commit --date allows approxidate' ' + git commit --amend \ + --date="midnight the 12th of october, anno domini 1979" && + echo "Fri Oct 12 00:00:00 1979 +0000" >expect && + git log -1 --format=%ad >actual && + test_cmp expect actual ' test_expect_success 'sign off (1)' ' diff --git a/t/t7502-commit.sh b/t/t7502-commit.sh index 9a3f3a1b41..b39e313ac2 100755 --- a/t/t7502-commit.sh +++ b/t/t7502-commit.sh @@ -229,14 +229,36 @@ test_expect_success 'cleanup commit messages (scissors option,-F,-e)' ' cat >text <<EOF && # to be kept + + # ------------------------ >8 ------------------------ +# to be kept, too # ------------------------ >8 ------------------------ to be removed +# ------------------------ >8 ------------------------ +to be removed, too +EOF + + cat >expect <<EOF && +# to be kept + + # ------------------------ >8 ------------------------ +# to be kept, too EOF - echo "# to be kept" >expect && git commit --cleanup=scissors -e -F text -a && git cat-file -p HEAD |sed -e "1,/^\$/d">actual && test_cmp expect actual +' +test_expect_success 'cleanup commit messages (scissors option,-F,-e, scissors on first line)' ' + + echo >>negative && + cat >text <<EOF && +# ------------------------ >8 ------------------------ +to be removed +EOF + git commit --cleanup=scissors -e -F text -a --allow-empty-message && + git cat-file -p HEAD |sed -e "1,/^\$/d">actual && + test_must_be_empty actual ' test_expect_success 'cleanup commit messages (strip option,-F)' ' @@ -344,6 +366,13 @@ test_expect_success 'message shows author when it is not equal to committer' ' .git/COMMIT_EDITMSG ' +test_expect_success 'message shows date when it is explicitly set' ' + git commit --allow-empty -e -m foo --date="2010-01-02T03:04:05" && + test_i18ngrep \ + "^# Date: *Sat Jan 2 03:04:05 2010 +0000" \ + .git/COMMIT_EDITMSG +' + test_expect_success AUTOIDENT 'message shows committer when it is automatic' ' echo >>negative && @@ -363,7 +392,7 @@ exit 0 EOF test_expect_success !AUTOIDENT 'do not fire editor when committer is bogus' ' - >.git/result + >.git/result && >expect && echo >>negative && @@ -563,4 +592,30 @@ test_expect_success 'commit --status with custom comment character' ' test_i18ngrep "^; Changes to be committed:" .git/COMMIT_EDITMSG ' +test_expect_success 'switch core.commentchar' ' + test_commit "#foo" foo && + GIT_EDITOR=.git/FAKE_EDITOR git -c core.commentChar=auto commit --amend && + test_i18ngrep "^; Changes to be committed:" .git/COMMIT_EDITMSG +' + +test_expect_success 'switch core.commentchar but out of options' ' + cat >text <<\EOF && +# 1 +; 2 +@ 3 +! 4 +$ 5 +% 6 +^ 7 +& 8 +| 9 +: 10 +EOF + git commit --amend -F text && + ( + test_set_editor .git/FAKE_EDITOR && + test_must_fail git -c core.commentChar=auto commit --amend + ) +' + test_done diff --git a/t/t7508-status.sh b/t/t7508-status.sh index d48006960e..c3ed7cb51c 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -66,6 +66,12 @@ strip_comments () { rm "$1" && mv "$1".tmp "$1" } +cat >.gitignore <<\EOF +.gitignore +expect* +output* +EOF + test_expect_success 'status --column' ' cat >expect <<\EOF && # On branch master @@ -83,8 +89,8 @@ test_expect_success 'status --column' ' # Untracked files: # (use "git add <file>..." to include in what will be committed) # -# dir1/untracked dir2/untracked output -# dir2/modified expect untracked +# dir1/untracked dir2/untracked +# dir2/modified untracked # EOF COLUMNS=50 git -c status.displayCommentPrefix=true status --column="column dense" >output && @@ -116,8 +122,6 @@ cat >expect <<\EOF # dir1/untracked # dir2/modified # dir2/untracked -# expect -# output # untracked # EOF @@ -133,6 +137,23 @@ test_expect_success 'status with status.displayCommentPrefix=false' ' test_i18ncmp expect output ' +test_expect_success 'status -v' ' + (cat expect && git diff --cached) >expect-with-v && + git status -v >output && + test_i18ncmp expect-with-v output +' + +test_expect_success 'status -v -v' ' + (cat expect && + echo "Changes to be committed:" && + git -c diff.mnemonicprefix=true diff --cached && + echo "--------------------------------------------------" && + echo "Changes not staged for commit:" && + git -c diff.mnemonicprefix=true diff) >expect-with-v && + git status -v -v >output && + test_i18ncmp expect-with-v output +' + test_expect_success 'setup fake editor' ' cat >.git/editor <<-\EOF && #! /bin/sh @@ -167,8 +188,6 @@ Untracked files: dir1/untracked dir2/modified dir2/untracked - expect - output untracked EOF @@ -186,8 +205,6 @@ A dir2/added ?? dir1/untracked ?? dir2/modified ?? dir2/untracked -?? expect -?? output ?? untracked EOF @@ -201,7 +218,7 @@ test_expect_success 'status -s' ' test_expect_success 'status with gitignore' ' { echo ".gitignore" && - echo "expect" && + echo "expect*" && echo "output" && echo "untracked" } >.gitignore && @@ -222,6 +239,7 @@ test_expect_success 'status with gitignore' ' !! dir1/untracked !! dir2/untracked !! expect + !! expect-with-v !! output !! untracked EOF @@ -253,6 +271,7 @@ Ignored files: dir1/untracked dir2/untracked expect + expect-with-v output untracked @@ -264,7 +283,7 @@ EOF test_expect_success 'status with gitignore (nothing untracked)' ' { echo ".gitignore" && - echo "expect" && + echo "expect*" && echo "dir2/modified" && echo "output" && echo "untracked" @@ -285,6 +304,7 @@ test_expect_success 'status with gitignore (nothing untracked)' ' !! dir2/modified !! dir2/untracked !! expect + !! expect-with-v !! output !! untracked EOF @@ -312,6 +332,7 @@ Ignored files: dir2/modified dir2/untracked expect + expect-with-v output untracked @@ -320,7 +341,11 @@ EOF test_i18ncmp expect output ' -rm -f .gitignore +cat >.gitignore <<\EOF +.gitignore +expect* +output* +EOF cat >expect <<\EOF ## master @@ -329,8 +354,6 @@ A dir2/added ?? dir1/untracked ?? dir2/modified ?? dir2/untracked -?? expect -?? output ?? untracked EOF @@ -408,7 +431,7 @@ test_expect_success 'status -s -uno' ' ' test_expect_success 'status -s (status.showUntrackedFiles no)' ' - git config status.showuntrackedfiles no + git config status.showuntrackedfiles no && git status -s >output && test_cmp expect output ' @@ -434,8 +457,6 @@ Untracked files: dir2/modified dir2/untracked dir3/ - expect - output untracked EOF @@ -444,7 +465,7 @@ EOF ' test_expect_success 'status (status.showUntrackedFiles normal)' ' - test_config status.showuntrackedfiles normal + test_config status.showuntrackedfiles normal && git status >output && test_i18ncmp expect output ' @@ -456,8 +477,6 @@ A dir2/added ?? dir2/modified ?? dir2/untracked ?? dir3/ -?? expect -?? output ?? untracked EOF test_expect_success 'status -s -unormal' ' @@ -466,7 +485,7 @@ test_expect_success 'status -s -unormal' ' ' test_expect_success 'status -s (status.showUntrackedFiles normal)' ' - git config status.showuntrackedfiles normal + git config status.showuntrackedfiles normal && git status -s >output && test_cmp expect output ' @@ -493,8 +512,6 @@ Untracked files: dir2/untracked dir3/untracked1 dir3/untracked2 - expect - output untracked EOF @@ -503,7 +520,7 @@ EOF ' test_expect_success 'status (status.showUntrackedFiles all)' ' - test_config status.showuntrackedfiles all + test_config status.showuntrackedfiles all && git status >output && test_i18ncmp expect output ' @@ -518,12 +535,10 @@ A dir2/added ?? dir1/untracked ?? dir2/modified ?? dir2/untracked -?? expect -?? output ?? untracked EOF test_expect_success 'status -s -uall' ' - git config --unset status.showuntrackedfiles + test_unconfig status.showuntrackedfiles && git status -s -uall >output && test_cmp expect output ' @@ -554,8 +569,6 @@ Untracked files: untracked ../dir2/modified ../dir2/untracked - ../expect - ../output ../untracked EOF @@ -569,8 +582,6 @@ A ../dir2/added ?? untracked ?? ../dir2/modified ?? ../dir2/untracked -?? ../expect -?? ../output ?? ../untracked EOF test_expect_success 'status -s with relative paths' ' @@ -586,8 +597,6 @@ A dir2/added ?? dir1/untracked ?? dir2/modified ?? dir2/untracked -?? expect -?? output ?? untracked EOF @@ -625,8 +634,6 @@ Untracked files: <BLUE>dir1/untracked<RESET> <BLUE>dir2/modified<RESET> <BLUE>dir2/untracked<RESET> - <BLUE>expect<RESET> - <BLUE>output<RESET> <BLUE>untracked<RESET> EOF @@ -647,8 +654,6 @@ cat >expect <<\EOF <BLUE>??<RESET> dir1/untracked <BLUE>??<RESET> dir2/modified <BLUE>??<RESET> dir2/untracked -<BLUE>??<RESET> expect -<BLUE>??<RESET> output <BLUE>??<RESET> untracked EOF @@ -676,8 +681,6 @@ cat >expect <<\EOF <BLUE>??<RESET> dir1/untracked <BLUE>??<RESET> dir2/modified <BLUE>??<RESET> dir2/untracked -<BLUE>??<RESET> expect -<BLUE>??<RESET> output <BLUE>??<RESET> untracked EOF @@ -694,8 +697,6 @@ A dir2/added ?? dir1/untracked ?? dir2/modified ?? dir2/untracked -?? expect -?? output ?? untracked EOF @@ -755,8 +756,6 @@ Untracked files: dir1/untracked dir2/modified dir2/untracked - expect - output untracked EOF @@ -772,8 +771,6 @@ A dir2/added ?? dir1/untracked ?? dir2/modified ?? dir2/untracked -?? expect -?? output ?? untracked EOF @@ -798,8 +795,6 @@ Untracked files: dir1/untracked dir2/ - expect - output untracked EOF @@ -848,8 +843,6 @@ Untracked files: dir1/untracked dir2/modified dir2/untracked - expect - output untracked EOF @@ -870,8 +863,6 @@ A sm ?? dir1/untracked ?? dir2/modified ?? dir2/untracked -?? expect -?? output ?? untracked EOF test_expect_success 'status -s submodule summary is disabled by default' ' @@ -913,8 +904,6 @@ Untracked files: dir1/untracked dir2/modified dir2/untracked - expect - output untracked EOF @@ -940,8 +929,6 @@ A sm ?? dir1/untracked ?? dir2/modified ?? dir2/untracked -?? expect -?? output ?? untracked EOF test_expect_success 'status -s submodule summary' ' @@ -964,8 +951,6 @@ Untracked files: dir1/untracked dir2/modified dir2/untracked - expect - output untracked no changes added to commit (use "git add" and/or "git commit -a") @@ -983,8 +968,6 @@ cat >expect <<EOF ?? dir1/untracked ?? dir2/modified ?? dir2/untracked -?? expect -?? output ?? untracked EOF test_expect_success 'status -s submodule summary (clean submodule)' ' @@ -1025,8 +1008,6 @@ Untracked files: dir1/untracked dir2/modified dir2/untracked - expect - output untracked EOF @@ -1080,8 +1061,6 @@ Untracked files: dir1/untracked dir2/modified dir2/untracked - expect - output untracked EOF @@ -1192,8 +1171,6 @@ Untracked files: dir1/untracked dir2/modified dir2/untracked - expect - output untracked EOF @@ -1254,8 +1231,6 @@ Untracked files: dir1/untracked dir2/modified dir2/untracked - expect - output untracked EOF @@ -1336,8 +1311,6 @@ cat > expect << EOF ; dir1/untracked ; dir2/modified ; dir2/untracked -; expect -; output ; untracked ; EOF @@ -1350,8 +1323,7 @@ test_expect_success "status (core.commentchar with submodule summary)" ' test_expect_success "status (core.commentchar with two chars with submodule summary)" ' test_config core.commentchar ";;" && - git -c status.displayCommentPrefix=true status >output && - test_i18ncmp expect output + test_must_fail git -c status.displayCommentPrefix=true status ' test_expect_success "--ignore-submodules=all suppresses submodule summary" ' @@ -1370,8 +1342,6 @@ Untracked files: dir1/untracked dir2/modified dir2/untracked - expect - output untracked no changes added to commit (use "git add" and/or "git commit -a") @@ -1401,8 +1371,6 @@ Untracked files: dir1/untracked dir2/modified dir2/untracked - expect - output untracked EOF diff --git a/t/t7509-commit.sh b/t/t7509-commit.sh index 9ac794052d..db9774e345 100755 --- a/t/t7509-commit.sh +++ b/t/t7509-commit.sh @@ -90,22 +90,10 @@ sha1_file() { remove_object() { rm -f $(sha1_file "$*") } -no_reflog() { - cp .git/config .git/config.saved && - echo "[core] logallrefupdates = false" >>.git/config && - test_when_finished "mv -f .git/config.saved .git/config" && - - if test -e .git/logs - then - mv .git/logs . && - test_when_finished "mv logs .git/" - fi -} test_expect_success '--amend option with empty author' ' git cat-file commit Initial >tmp && sed "s/author [^<]* </author </" tmp >empty-author && - no_reflog && sha=$(git hash-object -t commit -w empty-author) && test_when_finished "remove_object $sha" && git checkout $sha && @@ -119,7 +107,6 @@ test_expect_success '--amend option with empty author' ' test_expect_success '--amend option with missing author' ' git cat-file commit Initial >tmp && sed "s/author [^<]* </author </" tmp >malformed && - no_reflog && sha=$(git hash-object -t commit -w malformed) && test_when_finished "remove_object $sha" && git checkout $sha && diff --git a/t/t7510-signed-commit.sh b/t/t7510-signed-commit.sh index e97477a3b9..18e5cf0663 100755 --- a/t/t7510-signed-commit.sh +++ b/t/t7510-signed-commit.sh @@ -42,16 +42,17 @@ test_expect_success GPG 'create signed commits' ' git tag seventh-unsigned && test_tick && git rebase -f HEAD^^ && git tag sixth-signed HEAD^ && - git tag seventh-signed + git tag seventh-signed && echo 8 >file && test_tick && git commit -a -m eighth -SB7227189 && git tag eighth-signed-alt ' -test_expect_success GPG 'show signatures' ' +test_expect_success GPG 'verify and show signatures' ' ( for commit in initial second merge fourth-signed fifth-signed sixth-signed seventh-signed do + git verify-commit $commit && git show --pretty=short --show-signature $commit >actual && grep "Good signature from" actual && ! grep "BAD signature from" actual && @@ -61,6 +62,7 @@ test_expect_success GPG 'show signatures' ' ( for commit in merge^2 fourth-unsigned sixth-unsigned seventh-unsigned do + test_must_fail git verify-commit $commit && git show --pretty=short --show-signature $commit >actual && ! grep "Good signature from" actual && ! grep "BAD signature from" actual && @@ -79,11 +81,63 @@ test_expect_success GPG 'show signatures' ' ) ' +test_expect_success GPG 'verify-commit exits success on untrusted signature' ' + git verify-commit eighth-signed-alt 2>actual && + grep "Good signature from" actual && + ! grep "BAD signature from" actual && + grep "not certified" actual +' + +test_expect_success GPG 'verify signatures with --raw' ' + ( + for commit in initial second merge fourth-signed fifth-signed sixth-signed seventh-signed + do + git verify-commit --raw $commit 2>actual && + grep "GOODSIG" actual && + ! grep "BADSIG" actual && + echo $commit OK || exit 1 + done + ) && + ( + for commit in merge^2 fourth-unsigned sixth-unsigned seventh-unsigned + do + test_must_fail git verify-commit --raw $commit 2>actual && + ! grep "GOODSIG" actual && + ! grep "BADSIG" actual && + echo $commit OK || exit 1 + done + ) && + ( + for commit in eighth-signed-alt + do + git verify-commit --raw $commit 2>actual && + grep "GOODSIG" actual && + ! grep "BADSIG" actual && + grep "TRUST_UNDEFINED" actual && + echo $commit OK || exit 1 + done + ) +' + +test_expect_success GPG 'show signed commit with signature' ' + git show -s initial >commit && + git show -s --show-signature initial >show && + git verify-commit -v initial >verify.1 2>verify.2 && + git cat-file commit initial >cat && + grep -v -e "gpg: " -e "Warning: " show >show.commit && + grep -e "gpg: " -e "Warning: " show >show.gpg && + grep -v "^ " cat | grep -v "^gpgsig " >cat.commit && + test_cmp show.commit commit && + test_cmp show.gpg verify.2 && + test_cmp cat.commit verify.1 +' + test_expect_success GPG 'detect fudged signature' ' git cat-file commit seventh-signed >raw && sed -e "s/seventh/7th forged/" raw >forged1 && git hash-object -w -t commit forged1 >forged1.commit && + ! git verify-commit $(cat forged1.commit) && git show --pretty=short --show-signature $(cat forged1.commit) >actual1 && grep "BAD signature from" actual1 && ! grep "Good signature from" actual1 @@ -94,6 +148,7 @@ test_expect_success GPG 'detect fudged signature with NUL' ' cat raw >forged2 && echo Qwik | tr "Q" "\000" >>forged2 && git hash-object -w -t commit forged2 >forged2.commit && + ! git verify-commit $(cat forged2.commit) && git show --pretty=short --show-signature $(cat forged2.commit) >actual2 && grep "BAD signature from" actual2 && ! grep "Good signature from" actual2 @@ -102,6 +157,7 @@ test_expect_success GPG 'detect fudged signature with NUL' ' test_expect_success GPG 'amending already signed commit' ' git checkout fourth-signed^0 && git commit --amend -S --no-edit && + git verify-commit HEAD && git show -s --show-signature HEAD >actual && grep "Good signature from" actual && ! grep "BAD signature from" actual diff --git a/t/t7512-status-help.sh b/t/t7512-status-help.sh index 68ad2d7454..49d19a3b36 100755 --- a/t/t7512-status-help.sh +++ b/t/t7512-status-help.sh @@ -134,9 +134,13 @@ test_expect_success 'prepare for rebase_i_conflicts' ' test_expect_success 'status during rebase -i when conflicts unresolved' ' test_when_finished "git rebase --abort" && ONTO=$(git rev-parse --short rebase_i_conflicts) && + LAST_COMMIT=$(git rev-parse --short rebase_i_conflicts_second) && test_must_fail git rebase -i rebase_i_conflicts && cat >expected <<EOF && -rebase in progress; onto $ONTO +interactive rebase in progress; onto $ONTO +Last command done (1 command done): + pick $LAST_COMMIT one_second +No commands remaining. You are currently rebasing branch '\''rebase_i_conflicts_second'\'' on '\''$ONTO'\''. (fix conflicts and then run "git rebase --continue") (use "git rebase --skip" to skip this patch) @@ -159,10 +163,14 @@ test_expect_success 'status during rebase -i after resolving conflicts' ' git reset --hard rebase_i_conflicts_second && test_when_finished "git rebase --abort" && ONTO=$(git rev-parse --short rebase_i_conflicts) && + LAST_COMMIT=$(git rev-parse --short rebase_i_conflicts_second) && test_must_fail git rebase -i rebase_i_conflicts && git add main.txt && cat >expected <<EOF && -rebase in progress; onto $ONTO +interactive rebase in progress; onto $ONTO +Last command done (1 command done): + pick $LAST_COMMIT one_second +No commands remaining. You are currently rebasing branch '\''rebase_i_conflicts_second'\'' on '\''$ONTO'\''. (all conflicts fixed: run "git rebase --continue") @@ -183,14 +191,20 @@ test_expect_success 'status when rebasing -i in edit mode' ' git checkout -b rebase_i_edit && test_commit one_rebase_i main.txt one && test_commit two_rebase_i main.txt two && + COMMIT2=$(git rev-parse --short rebase_i_edit) && test_commit three_rebase_i main.txt three && + COMMIT3=$(git rev-parse --short rebase_i_edit) && FAKE_LINES="1 edit 2" && export FAKE_LINES && test_when_finished "git rebase --abort" && ONTO=$(git rev-parse --short HEAD~2) && git rebase -i HEAD~2 && cat >expected <<EOF && -rebase in progress; onto $ONTO +interactive rebase in progress; onto $ONTO +Last commands done (2 commands done): + pick $COMMIT2 two_rebase_i + edit $COMMIT3 three_rebase_i +No commands remaining. You are currently editing a commit while rebasing branch '\''rebase_i_edit'\'' on '\''$ONTO'\''. (use "git commit --amend" to amend the current commit) (use "git rebase --continue" once you are satisfied with your changes) @@ -207,8 +221,11 @@ test_expect_success 'status when splitting a commit' ' git checkout -b split_commit && test_commit one_split main.txt one && test_commit two_split main.txt two && + COMMIT2=$(git rev-parse --short split_commit) && test_commit three_split main.txt three && + COMMIT3=$(git rev-parse --short split_commit) && test_commit four_split main.txt four && + COMMIT4=$(git rev-parse --short split_commit) && FAKE_LINES="1 edit 2 3" && export FAKE_LINES && test_when_finished "git rebase --abort" && @@ -216,7 +233,13 @@ test_expect_success 'status when splitting a commit' ' git rebase -i HEAD~3 && git reset HEAD^ && cat >expected <<EOF && -rebase in progress; onto $ONTO +interactive rebase in progress; onto $ONTO +Last commands done (2 commands done): + pick $COMMIT2 two_split + edit $COMMIT3 three_split +Next command to do (1 remaining command): + pick $COMMIT4 four_split + (use "git rebase --edit-todo" to view and edit) You are currently splitting a commit while rebasing branch '\''split_commit'\'' on '\''$ONTO'\''. (Once your working directory is clean, run "git rebase --continue") @@ -239,7 +262,9 @@ test_expect_success 'status after editing the last commit with --amend during a test_commit one_amend main.txt one && test_commit two_amend main.txt two && test_commit three_amend main.txt three && + COMMIT3=$(git rev-parse --short amend_last) && test_commit four_amend main.txt four && + COMMIT4=$(git rev-parse --short amend_last) && FAKE_LINES="1 2 edit 3" && export FAKE_LINES && test_when_finished "git rebase --abort" && @@ -247,7 +272,12 @@ test_expect_success 'status after editing the last commit with --amend during a git rebase -i HEAD~3 && git commit --amend -m "foo" && cat >expected <<EOF && -rebase in progress; onto $ONTO +interactive rebase in progress; onto $ONTO +Last commands done (3 commands done): + pick $COMMIT3 three_amend + edit $COMMIT4 four_amend + (see more in file .git/rebase-merge/done) +No commands remaining. You are currently editing a commit while rebasing branch '\''amend_last'\'' on '\''$ONTO'\''. (use "git commit --amend" to amend the current commit) (use "git rebase --continue" once you are satisfied with your changes) @@ -273,11 +303,20 @@ test_expect_success 'status: (continue first edit) second edit' ' FAKE_LINES="edit 1 edit 2 3" && export FAKE_LINES && test_when_finished "git rebase --abort" && + COMMIT2=$(git rev-parse --short several_edits^^) && + COMMIT3=$(git rev-parse --short several_edits^) && + COMMIT4=$(git rev-parse --short several_edits) && ONTO=$(git rev-parse --short HEAD~3) && git rebase -i HEAD~3 && git rebase --continue && cat >expected <<EOF && -rebase in progress; onto $ONTO +interactive rebase in progress; onto $ONTO +Last commands done (2 commands done): + edit $COMMIT2 two_edits + edit $COMMIT3 three_edits +Next command to do (1 remaining command): + pick $COMMIT4 four_edits + (use "git rebase --edit-todo" to view and edit) You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''. (use "git commit --amend" to amend the current commit) (use "git rebase --continue" once you are satisfied with your changes) @@ -294,12 +333,21 @@ test_expect_success 'status: (continue first edit) second edit and split' ' FAKE_LINES="edit 1 edit 2 3" && export FAKE_LINES && test_when_finished "git rebase --abort" && + COMMIT2=$(git rev-parse --short several_edits^^) && + COMMIT3=$(git rev-parse --short several_edits^) && + COMMIT4=$(git rev-parse --short several_edits) && ONTO=$(git rev-parse --short HEAD~3) && git rebase -i HEAD~3 && git rebase --continue && git reset HEAD^ && cat >expected <<EOF && -rebase in progress; onto $ONTO +interactive rebase in progress; onto $ONTO +Last commands done (2 commands done): + edit $COMMIT2 two_edits + edit $COMMIT3 three_edits +Next command to do (1 remaining command): + pick $COMMIT4 four_edits + (use "git rebase --edit-todo" to view and edit) You are currently splitting a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''. (Once your working directory is clean, run "git rebase --continue") @@ -321,12 +369,21 @@ test_expect_success 'status: (continue first edit) second edit and amend' ' FAKE_LINES="edit 1 edit 2 3" && export FAKE_LINES && test_when_finished "git rebase --abort" && + COMMIT2=$(git rev-parse --short several_edits^^) && + COMMIT3=$(git rev-parse --short several_edits^) && + COMMIT4=$(git rev-parse --short several_edits) && ONTO=$(git rev-parse --short HEAD~3) && git rebase -i HEAD~3 && git rebase --continue && git commit --amend -m "foo" && cat >expected <<EOF && -rebase in progress; onto $ONTO +interactive rebase in progress; onto $ONTO +Last commands done (2 commands done): + edit $COMMIT2 two_edits + edit $COMMIT3 three_edits +Next command to do (1 remaining command): + pick $COMMIT4 four_edits + (use "git rebase --edit-todo" to view and edit) You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''. (use "git commit --amend" to amend the current commit) (use "git rebase --continue" once you are satisfied with your changes) @@ -343,12 +400,21 @@ test_expect_success 'status: (amend first edit) second edit' ' FAKE_LINES="edit 1 edit 2 3" && export FAKE_LINES && test_when_finished "git rebase --abort" && + COMMIT2=$(git rev-parse --short several_edits^^) && + COMMIT3=$(git rev-parse --short several_edits^) && + COMMIT4=$(git rev-parse --short several_edits) && ONTO=$(git rev-parse --short HEAD~3) && git rebase -i HEAD~3 && git commit --amend -m "a" && git rebase --continue && cat >expected <<EOF && -rebase in progress; onto $ONTO +interactive rebase in progress; onto $ONTO +Last commands done (2 commands done): + edit $COMMIT2 two_edits + edit $COMMIT3 three_edits +Next command to do (1 remaining command): + pick $COMMIT4 four_edits + (use "git rebase --edit-todo" to view and edit) You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''. (use "git commit --amend" to amend the current commit) (use "git rebase --continue" once you are satisfied with your changes) @@ -366,12 +432,21 @@ test_expect_success 'status: (amend first edit) second edit and split' ' export FAKE_LINES && test_when_finished "git rebase --abort" && ONTO=$(git rev-parse --short HEAD~3) && + COMMIT2=$(git rev-parse --short several_edits^^) && + COMMIT3=$(git rev-parse --short several_edits^) && + COMMIT4=$(git rev-parse --short several_edits) && git rebase -i HEAD~3 && git commit --amend -m "b" && git rebase --continue && git reset HEAD^ && cat >expected <<EOF && -rebase in progress; onto $ONTO +interactive rebase in progress; onto $ONTO +Last commands done (2 commands done): + edit $COMMIT2 two_edits + edit $COMMIT3 three_edits +Next command to do (1 remaining command): + pick $COMMIT4 four_edits + (use "git rebase --edit-todo" to view and edit) You are currently splitting a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''. (Once your working directory is clean, run "git rebase --continue") @@ -393,13 +468,22 @@ test_expect_success 'status: (amend first edit) second edit and amend' ' FAKE_LINES="edit 1 edit 2 3" && export FAKE_LINES && test_when_finished "git rebase --abort" && + COMMIT2=$(git rev-parse --short several_edits^^) && + COMMIT3=$(git rev-parse --short several_edits^) && + COMMIT4=$(git rev-parse --short several_edits) && ONTO=$(git rev-parse --short HEAD~3) && git rebase -i HEAD~3 && git commit --amend -m "c" && git rebase --continue && git commit --amend -m "d" && cat >expected <<EOF && -rebase in progress; onto $ONTO +interactive rebase in progress; onto $ONTO +Last commands done (2 commands done): + edit $COMMIT2 two_edits + edit $COMMIT3 three_edits +Next command to do (1 remaining command): + pick $COMMIT4 four_edits + (use "git rebase --edit-todo" to view and edit) You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''. (use "git commit --amend" to amend the current commit) (use "git rebase --continue" once you are satisfied with your changes) @@ -416,6 +500,9 @@ test_expect_success 'status: (split first edit) second edit' ' FAKE_LINES="edit 1 edit 2 3" && export FAKE_LINES && test_when_finished "git rebase --abort" && + COMMIT2=$(git rev-parse --short several_edits^^) && + COMMIT3=$(git rev-parse --short several_edits^) && + COMMIT4=$(git rev-parse --short several_edits) && ONTO=$(git rev-parse --short HEAD~3) && git rebase -i HEAD~3 && git reset HEAD^ && @@ -423,7 +510,13 @@ test_expect_success 'status: (split first edit) second edit' ' git commit -m "e" && git rebase --continue && cat >expected <<EOF && -rebase in progress; onto $ONTO +interactive rebase in progress; onto $ONTO +Last commands done (2 commands done): + edit $COMMIT2 two_edits + edit $COMMIT3 three_edits +Next command to do (1 remaining command): + pick $COMMIT4 four_edits + (use "git rebase --edit-todo" to view and edit) You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''. (use "git commit --amend" to amend the current commit) (use "git rebase --continue" once you are satisfied with your changes) @@ -440,6 +533,9 @@ test_expect_success 'status: (split first edit) second edit and split' ' FAKE_LINES="edit 1 edit 2 3" && export FAKE_LINES && test_when_finished "git rebase --abort" && + COMMIT2=$(git rev-parse --short several_edits^^) && + COMMIT3=$(git rev-parse --short several_edits^) && + COMMIT4=$(git rev-parse --short several_edits) && ONTO=$(git rev-parse --short HEAD~3) && git rebase -i HEAD~3 && git reset HEAD^ && @@ -448,7 +544,13 @@ test_expect_success 'status: (split first edit) second edit and split' ' git rebase --continue && git reset HEAD^ && cat >expected <<EOF && -rebase in progress; onto $ONTO +interactive rebase in progress; onto $ONTO +Last commands done (2 commands done): + edit $COMMIT2 two_edits + edit $COMMIT3 three_edits +Next command to do (1 remaining command): + pick $COMMIT4 four_edits + (use "git rebase --edit-todo" to view and edit) You are currently splitting a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''. (Once your working directory is clean, run "git rebase --continue") @@ -470,6 +572,9 @@ test_expect_success 'status: (split first edit) second edit and amend' ' FAKE_LINES="edit 1 edit 2 3" && export FAKE_LINES && test_when_finished "git rebase --abort" && + COMMIT2=$(git rev-parse --short several_edits^^) && + COMMIT3=$(git rev-parse --short several_edits^) && + COMMIT4=$(git rev-parse --short several_edits) && ONTO=$(git rev-parse --short HEAD~3) && git rebase -i HEAD~3 && git reset HEAD^ && @@ -478,7 +583,13 @@ test_expect_success 'status: (split first edit) second edit and amend' ' git rebase --continue && git commit --amend -m "h" && cat >expected <<EOF && -rebase in progress; onto $ONTO +interactive rebase in progress; onto $ONTO +Last commands done (2 commands done): + edit $COMMIT2 two_edits + edit $COMMIT3 three_edits +Next command to do (1 remaining command): + pick $COMMIT4 four_edits + (use "git rebase --edit-todo" to view and edit) You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''. (use "git commit --amend" to amend the current commit) (use "git rebase --continue" once you are satisfied with your changes) @@ -745,4 +856,91 @@ EOF test_i18ncmp expected actual ' +test_expect_success 'prepare for different number of commits rebased' ' + git reset --hard master && + git checkout -b several_commits && + test_commit one_commit main.txt one && + test_commit two_commit main.txt two && + test_commit three_commit main.txt three && + test_commit four_commit main.txt four +' + +test_expect_success 'status: one command done nothing remaining' ' + FAKE_LINES="exec_exit_15" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + ONTO=$(git rev-parse --short HEAD~3) && + test_must_fail git rebase -i HEAD~3 && + cat >expected <<EOF && +interactive rebase in progress; onto $ONTO +Last command done (1 command done): + exec exit 15 +No commands remaining. +You are currently editing a commit while rebasing branch '\''several_commits'\'' on '\''$ONTO'\''. + (use "git commit --amend" to amend the current commit) + (use "git rebase --continue" once you are satisfied with your changes) + +nothing to commit (use -u to show untracked files) +EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + +test_expect_success 'status: two commands done with some white lines in done file' ' + FAKE_LINES="1 > exec_exit_15 2 3" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + ONTO=$(git rev-parse --short HEAD~3) && + COMMIT4=$(git rev-parse --short HEAD) && + COMMIT3=$(git rev-parse --short HEAD^) && + COMMIT2=$(git rev-parse --short HEAD^^) && + test_must_fail git rebase -i HEAD~3 && + cat >expected <<EOF && +interactive rebase in progress; onto $ONTO +Last commands done (2 commands done): + pick $COMMIT2 two_commit + exec exit 15 +Next commands to do (2 remaining commands): + pick $COMMIT3 three_commit + pick $COMMIT4 four_commit + (use "git rebase --edit-todo" to view and edit) +You are currently editing a commit while rebasing branch '\''several_commits'\'' on '\''$ONTO'\''. + (use "git commit --amend" to amend the current commit) + (use "git rebase --continue" once you are satisfied with your changes) + +nothing to commit (use -u to show untracked files) +EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + +test_expect_success 'status: two remaining commands with some white lines in todo file' ' + FAKE_LINES="1 2 exec_exit_15 3 > 4" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + ONTO=$(git rev-parse --short HEAD~4) && + COMMIT4=$(git rev-parse --short HEAD) && + COMMIT3=$(git rev-parse --short HEAD^) && + COMMIT2=$(git rev-parse --short HEAD^^) && + test_must_fail git rebase -i HEAD~4 && + cat >expected <<EOF && +interactive rebase in progress; onto $ONTO +Last commands done (3 commands done): + pick $COMMIT2 two_commit + exec exit 15 + (see more in file .git/rebase-merge/done) +Next commands to do (2 remaining commands): + pick $COMMIT3 three_commit + pick $COMMIT4 four_commit + (use "git rebase --edit-todo" to view and edit) +You are currently editing a commit while rebasing branch '\''several_commits'\'' on '\''$ONTO'\''. + (use "git commit --amend" to amend the current commit) + (use "git rebase --continue" once you are satisfied with your changes) + +nothing to commit (use -u to show untracked files) +EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + test_done diff --git a/t/t7513-interpret-trailers.sh b/t/t7513-interpret-trailers.sh new file mode 100755 index 0000000000..322c436a49 --- /dev/null +++ b/t/t7513-interpret-trailers.sh @@ -0,0 +1,922 @@ +#!/bin/sh +# +# Copyright (c) 2013, 2014 Christian Couder +# + +test_description='git interpret-trailers' + +. ./test-lib.sh + +# When we want one trailing space at the end of each line, let's use sed +# to make sure that these spaces are not removed by any automatic tool. + +test_expect_success 'setup' ' + : >empty && + cat >basic_message <<-\EOF && + subject + + body + EOF + cat >complex_message_body <<-\EOF && + my subject + + my body which is long + and contains some special + chars like : = ? ! + + EOF + sed -e "s/ Z\$/ /" >complex_message_trailers <<-\EOF && + Fixes: Z + Acked-by: Z + Reviewed-by: Z + Signed-off-by: Z + EOF + cat >basic_patch <<-\EOF + --- + foo.txt | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + + diff --git a/foo.txt b/foo.txt + index 0353767..1d91aa1 100644 + --- a/foo.txt + +++ b/foo.txt + @@ -1,3 +1,3 @@ + + -bar + +baz + + -- + 1.9.rc0.11.ga562ddc + + EOF +' + +test_expect_success 'without config' ' + sed -e "s/ Z\$/ /" >expected <<-\EOF && + + ack: Peff + Reviewed-by: Z + Acked-by: Johan + EOF + git interpret-trailers --trailer "ack = Peff" --trailer "Reviewed-by" \ + --trailer "Acked-by: Johan" empty >actual && + test_cmp expected actual +' + +test_expect_success 'without config in another order' ' + sed -e "s/ Z\$/ /" >expected <<-\EOF && + + Acked-by: Johan + Reviewed-by: Z + ack: Peff + EOF + git interpret-trailers --trailer "Acked-by: Johan" --trailer "Reviewed-by" \ + --trailer "ack = Peff" empty >actual && + test_cmp expected actual +' + +test_expect_success '--trim-empty without config' ' + cat >expected <<-\EOF && + + ack: Peff + Acked-by: Johan + EOF + git interpret-trailers --trim-empty --trailer ack=Peff \ + --trailer "Reviewed-by" --trailer "Acked-by: Johan" \ + --trailer "sob:" empty >actual && + test_cmp expected actual +' + +test_expect_success 'with config option on the command line' ' + cat >expected <<-\EOF && + + Acked-by: Johan + Reviewed-by: Peff + EOF + { echo; echo "Acked-by: Johan"; } | + git -c "trailer.Acked-by.ifexists=addifdifferent" interpret-trailers \ + --trailer "Reviewed-by: Peff" --trailer "Acked-by: Johan" >actual && + test_cmp expected actual +' + +test_expect_success 'with only a title in the message' ' + cat >expected <<-\EOF && + area: change + + Reviewed-by: Peff + Acked-by: Johan + EOF + echo "area: change" | + git interpret-trailers --trailer "Reviewed-by: Peff" \ + --trailer "Acked-by: Johan" >actual && + test_cmp expected actual +' + +test_expect_success 'with multiline title in the message' ' + cat >expected <<-\EOF && + place of + code: change + + Reviewed-by: Peff + Acked-by: Johan + EOF + printf "%s\n" "place of" "code: change" | + git interpret-trailers --trailer "Reviewed-by: Peff" \ + --trailer "Acked-by: Johan" >actual && + test_cmp expected actual +' + +test_expect_success 'with config setup' ' + git config trailer.ack.key "Acked-by: " && + cat >expected <<-\EOF && + + Acked-by: Peff + EOF + git interpret-trailers --trim-empty --trailer "ack = Peff" empty >actual && + test_cmp expected actual && + git interpret-trailers --trim-empty --trailer "Acked-by = Peff" empty >actual && + test_cmp expected actual && + git interpret-trailers --trim-empty --trailer "Acked-by :Peff" empty >actual && + test_cmp expected actual +' + +test_expect_success 'with config setup and ":=" as separators' ' + git config trailer.separators ":=" && + git config trailer.ack.key "Acked-by= " && + cat >expected <<-\EOF && + + Acked-by= Peff + EOF + git interpret-trailers --trim-empty --trailer "ack = Peff" empty >actual && + test_cmp expected actual && + git interpret-trailers --trim-empty --trailer "Acked-by= Peff" empty >actual && + test_cmp expected actual && + git interpret-trailers --trim-empty --trailer "Acked-by : Peff" empty >actual && + test_cmp expected actual +' + +test_expect_success 'with config setup and "%" as separators' ' + git config trailer.separators "%" && + cat >expected <<-\EOF && + + bug% 42 + count% 10 + bug% 422 + EOF + git interpret-trailers --trim-empty --trailer "bug = 42" \ + --trailer count%10 --trailer "test: stuff" \ + --trailer "bug % 422" empty >actual && + test_cmp expected actual +' + +test_expect_success 'with "%" as separators and a message with trailers' ' + cat >special_message <<-\EOF && + Special Message + + bug% 42 + count% 10 + bug% 422 + EOF + cat >expected <<-\EOF && + Special Message + + bug% 42 + count% 10 + bug% 422 + count% 100 + EOF + git interpret-trailers --trailer count%100 \ + special_message >actual && + test_cmp expected actual +' + +test_expect_success 'with config setup and ":=#" as separators' ' + git config trailer.separators ":=#" && + git config trailer.bug.key "Bug #" && + cat >expected <<-\EOF && + + Bug #42 + EOF + git interpret-trailers --trim-empty --trailer "bug = 42" empty >actual && + test_cmp expected actual +' + +test_expect_success 'with commit basic message' ' + cat basic_message >expected && + echo >>expected && + git interpret-trailers <basic_message >actual && + test_cmp expected actual +' + +test_expect_success 'with basic patch' ' + cat basic_message >input && + cat basic_patch >>input && + cat basic_message >expected && + echo >>expected && + cat basic_patch >>expected && + git interpret-trailers <input >actual && + test_cmp expected actual +' + +test_expect_success 'with commit complex message as argument' ' + cat complex_message_body complex_message_trailers >complex_message && + cat complex_message_body >expected && + sed -e "s/ Z\$/ /" >>expected <<-\EOF && + Fixes: Z + Acked-by= Z + Reviewed-by: Z + Signed-off-by: Z + EOF + git interpret-trailers complex_message >actual && + test_cmp expected actual +' + +test_expect_success 'with 2 files arguments' ' + cat basic_message >>expected && + echo >>expected && + cat basic_patch >>expected && + git interpret-trailers complex_message input >actual && + test_cmp expected actual +' + +test_expect_success 'with message that has comments' ' + cat basic_message >message_with_comments && + sed -e "s/ Z\$/ /" >>message_with_comments <<-\EOF && + # comment + + # other comment + Cc: Z + # yet another comment + Reviewed-by: Johan + Reviewed-by: Z + # last comment + + EOF + cat basic_patch >>message_with_comments && + cat basic_message >expected && + cat >>expected <<-\EOF && + # comment + + Reviewed-by: Johan + Cc: Peff + # last comment + + EOF + cat basic_patch >>expected && + git interpret-trailers --trim-empty --trailer "Cc: Peff" message_with_comments >actual && + test_cmp expected actual +' + +test_expect_success 'with message that has an old style conflict block' ' + cat basic_message >message_with_comments && + sed -e "s/ Z\$/ /" >>message_with_comments <<-\EOF && + # comment + + # other comment + Cc: Z + # yet another comment + Reviewed-by: Johan + Reviewed-by: Z + # last comment + + Conflicts: + + EOF + cat basic_message >expected && + cat >>expected <<-\EOF && + # comment + + Reviewed-by: Johan + Cc: Peff + # last comment + + Conflicts: + + EOF + git interpret-trailers --trim-empty --trailer "Cc: Peff" message_with_comments >actual && + test_cmp expected actual +' + +test_expect_success 'with commit complex message and trailer args' ' + cat complex_message_body >expected && + sed -e "s/ Z\$/ /" >>expected <<-\EOF && + Fixes: Z + Acked-by= Z + Reviewed-by: Z + Signed-off-by: Z + Acked-by= Peff + Bug #42 + EOF + git interpret-trailers --trailer "ack: Peff" \ + --trailer "bug: 42" <complex_message >actual && + test_cmp expected actual +' + +test_expect_success 'with complex patch, args and --trim-empty' ' + cat complex_message >complex_patch && + cat basic_patch >>complex_patch && + cat complex_message_body >expected && + cat >>expected <<-\EOF && + Acked-by= Peff + Bug #42 + EOF + cat basic_patch >>expected && + git interpret-trailers --trim-empty --trailer "ack: Peff" \ + --trailer "bug: 42" <complex_patch >actual && + test_cmp expected actual +' + +test_expect_success 'using "where = before"' ' + git config trailer.bug.where "before" && + cat complex_message_body >expected && + sed -e "s/ Z\$/ /" >>expected <<-\EOF && + Bug #42 + Fixes: Z + Acked-by= Z + Reviewed-by: Z + Signed-off-by: Z + Acked-by= Peff + EOF + git interpret-trailers --trailer "ack: Peff" \ + --trailer "bug: 42" complex_message >actual && + test_cmp expected actual +' + +test_expect_success 'using "where = after"' ' + git config trailer.ack.where "after" && + cat complex_message_body >expected && + sed -e "s/ Z\$/ /" >>expected <<-\EOF && + Bug #42 + Fixes: Z + Acked-by= Z + Acked-by= Peff + Reviewed-by: Z + Signed-off-by: Z + EOF + git interpret-trailers --trailer "ack: Peff" \ + --trailer "bug: 42" complex_message >actual && + test_cmp expected actual +' + +test_expect_success 'using "where = end"' ' + git config trailer.review.key "Reviewed-by" && + git config trailer.review.where "end" && + cat complex_message_body >expected && + sed -e "s/ Z\$/ /" >>expected <<-\EOF && + Fixes: Z + Acked-by= Z + Acked-by= Peff + Reviewed-by: Z + Signed-off-by: Z + Reviewed-by: Junio + Reviewed-by: Johannes + EOF + git interpret-trailers --trailer "ack: Peff" \ + --trailer "Reviewed-by: Junio" --trailer "Reviewed-by: Johannes" \ + complex_message >actual && + test_cmp expected actual +' + +test_expect_success 'using "where = start"' ' + git config trailer.review.key "Reviewed-by" && + git config trailer.review.where "start" && + cat complex_message_body >expected && + sed -e "s/ Z\$/ /" >>expected <<-\EOF && + Reviewed-by: Johannes + Reviewed-by: Junio + Fixes: Z + Acked-by= Z + Acked-by= Peff + Reviewed-by: Z + Signed-off-by: Z + EOF + git interpret-trailers --trailer "ack: Peff" \ + --trailer "Reviewed-by: Junio" --trailer "Reviewed-by: Johannes" \ + complex_message >actual && + test_cmp expected actual +' + +test_expect_success 'using "where = before" for a token in the middle of the message' ' + git config trailer.review.key "Reviewed-by:" && + git config trailer.review.where "before" && + cat complex_message_body >expected && + sed -e "s/ Z\$/ /" >>expected <<-\EOF && + Bug #42 + Fixes: Z + Acked-by= Z + Acked-by= Peff + Reviewed-by:Johan + Reviewed-by: + Signed-off-by: Z + EOF + git interpret-trailers --trailer "ack: Peff" --trailer "bug: 42" \ + --trailer "review: Johan" <complex_message >actual && + test_cmp expected actual +' + +test_expect_success 'using "where = before" and --trim-empty' ' + cat complex_message_body >expected && + cat >>expected <<-\EOF && + Bug #46 + Bug #42 + Acked-by= Peff + Reviewed-by:Johan + EOF + git interpret-trailers --trim-empty --trailer "ack: Peff" \ + --trailer "bug: 42" --trailer "review: Johan" \ + --trailer "Bug: 46" <complex_message >actual && + test_cmp expected actual +' + +test_expect_success 'the default is "ifExists = addIfDifferentNeighbor"' ' + cat complex_message_body >expected && + sed -e "s/ Z\$/ /" >>expected <<-\EOF && + Bug #42 + Fixes: Z + Acked-by= Z + Acked-by= Peff + Acked-by= Junio + Acked-by= Peff + Reviewed-by: + Signed-off-by: Z + EOF + git interpret-trailers --trailer "ack: Peff" --trailer "review:" \ + --trailer "ack: Junio" --trailer "bug: 42" --trailer "ack: Peff" \ + --trailer "ack: Peff" <complex_message >actual && + test_cmp expected actual +' + +test_expect_success 'default "ifExists" is now "addIfDifferent"' ' + git config trailer.ifexists "addIfDifferent" && + cat complex_message_body >expected && + sed -e "s/ Z\$/ /" >>expected <<-\EOF && + Bug #42 + Fixes: Z + Acked-by= Z + Acked-by= Peff + Acked-by= Junio + Reviewed-by: + Signed-off-by: Z + EOF + git interpret-trailers --trailer "ack: Peff" --trailer "review:" \ + --trailer "ack: Junio" --trailer "bug: 42" --trailer "ack: Peff" \ + --trailer "ack: Peff" <complex_message >actual && + test_cmp expected actual +' + +test_expect_success 'using "ifExists = addIfDifferent" with "where = end"' ' + git config trailer.ack.ifExists "addIfDifferent" && + git config trailer.ack.where "end" && + cat complex_message_body >expected && + sed -e "s/ Z\$/ /" >>expected <<-\EOF && + Bug #42 + Fixes: Z + Acked-by= Z + Reviewed-by: + Signed-off-by: Z + Acked-by= Peff + EOF + git interpret-trailers --trailer "ack: Peff" --trailer "review:" \ + --trailer "bug: 42" --trailer "ack: Peff" \ + <complex_message >actual && + test_cmp expected actual +' + +test_expect_success 'using "ifExists = addIfDifferent" with "where = before"' ' + git config trailer.ack.ifExists "addIfDifferent" && + git config trailer.ack.where "before" && + cat complex_message_body >expected && + sed -e "s/ Z\$/ /" >>expected <<-\EOF && + Bug #42 + Fixes: Z + Acked-by= Peff + Acked-by= Z + Reviewed-by: + Signed-off-by: Z + EOF + git interpret-trailers --trailer "ack: Peff" --trailer "review:" \ + --trailer "bug: 42" --trailer "ack: Peff" \ + <complex_message >actual && + test_cmp expected actual +' + +test_expect_success 'using "ifExists = addIfDifferentNeighbor" with "where = end"' ' + git config trailer.ack.ifExists "addIfDifferentNeighbor" && + git config trailer.ack.where "end" && + cat complex_message_body >expected && + sed -e "s/ Z\$/ /" >>expected <<-\EOF && + Bug #42 + Fixes: Z + Acked-by= Z + Reviewed-by: + Signed-off-by: Z + Acked-by= Peff + Acked-by= Junio + Tested-by: Jakub + Acked-by= Junio + Acked-by= Peff + EOF + git interpret-trailers --trailer "ack: Peff" --trailer "review:" \ + --trailer "ack: Junio" --trailer "bug: 42" \ + --trailer "Tested-by: Jakub" --trailer "ack: Junio" \ + --trailer "ack: Junio" --trailer "ack: Peff" <complex_message >actual && + test_cmp expected actual +' + +test_expect_success 'using "ifExists = addIfDifferentNeighbor" with "where = after"' ' + git config trailer.ack.ifExists "addIfDifferentNeighbor" && + git config trailer.ack.where "after" && + cat complex_message_body >expected && + sed -e "s/ Z\$/ /" >>expected <<-\EOF && + Bug #42 + Fixes: Z + Acked-by= Z + Acked-by= Peff + Acked-by= Junio + Acked-by= Peff + Reviewed-by: + Signed-off-by: Z + Tested-by: Jakub + EOF + git interpret-trailers --trailer "ack: Peff" --trailer "review:" \ + --trailer "ack: Junio" --trailer "bug: 42" \ + --trailer "Tested-by: Jakub" --trailer "ack: Junio" \ + --trailer "ack: Junio" --trailer "ack: Peff" <complex_message >actual && + test_cmp expected actual +' + +test_expect_success 'using "ifExists = addIfDifferentNeighbor" and --trim-empty' ' + git config trailer.ack.ifExists "addIfDifferentNeighbor" && + cat complex_message_body >expected && + cat >>expected <<-\EOF && + Bug #42 + Acked-by= Peff + Acked-by= Junio + Acked-by= Peff + EOF + git interpret-trailers --trim-empty --trailer "ack: Peff" \ + --trailer "Acked-by= Peff" --trailer "review:" \ + --trailer "ack: Junio" --trailer "bug: 42" \ + --trailer "ack: Peff" <complex_message >actual && + test_cmp expected actual +' + +test_expect_success 'using "ifExists = add" with "where = end"' ' + git config trailer.ack.ifExists "add" && + git config trailer.ack.where "end" && + cat complex_message_body >expected && + sed -e "s/ Z\$/ /" >>expected <<-\EOF && + Bug #42 + Fixes: Z + Acked-by= Z + Reviewed-by: + Signed-off-by: Z + Acked-by= Peff + Acked-by= Peff + Tested-by: Jakub + Acked-by= Junio + Tested-by: Johannes + Acked-by= Peff + EOF + git interpret-trailers --trailer "ack: Peff" \ + --trailer "Acked-by= Peff" --trailer "review:" \ + --trailer "Tested-by: Jakub" --trailer "ack: Junio" \ + --trailer "bug: 42" --trailer "Tested-by: Johannes" \ + --trailer "ack: Peff" <complex_message >actual && + test_cmp expected actual +' + +test_expect_success 'using "ifExists = add" with "where = after"' ' + git config trailer.ack.ifExists "add" && + git config trailer.ack.where "after" && + cat complex_message_body >expected && + sed -e "s/ Z\$/ /" >>expected <<-\EOF && + Bug #42 + Fixes: Z + Acked-by= Z + Acked-by= Peff + Acked-by= Peff + Acked-by= Junio + Acked-by= Peff + Reviewed-by: + Signed-off-by: Z + EOF + git interpret-trailers --trailer "ack: Peff" \ + --trailer "Acked-by= Peff" --trailer "review:" \ + --trailer "ack: Junio" --trailer "bug: 42" \ + --trailer "ack: Peff" <complex_message >actual && + test_cmp expected actual +' + +test_expect_success 'using "ifExists = replace"' ' + git config trailer.fix.key "Fixes: " && + git config trailer.fix.ifExists "replace" && + cat complex_message_body >expected && + sed -e "s/ Z\$/ /" >>expected <<-\EOF && + Bug #42 + Acked-by= Z + Acked-by= Junio + Acked-by= Peff + Reviewed-by: + Signed-off-by: Z + Fixes: 22 + EOF + git interpret-trailers --trailer "review:" \ + --trailer "fix=53" --trailer "ack: Junio" --trailer "fix=22" \ + --trailer "bug: 42" --trailer "ack: Peff" \ + <complex_message >actual && + test_cmp expected actual +' + +test_expect_success 'using "ifExists = replace" with "where = after"' ' + git config trailer.fix.where "after" && + cat complex_message_body >expected && + sed -e "s/ Z\$/ /" >>expected <<-\EOF && + Bug #42 + Fixes: 22 + Acked-by= Z + Acked-by= Junio + Acked-by= Peff + Reviewed-by: + Signed-off-by: Z + EOF + git interpret-trailers --trailer "review:" \ + --trailer "fix=53" --trailer "ack: Junio" --trailer "fix=22" \ + --trailer "bug: 42" --trailer "ack: Peff" \ + <complex_message >actual && + test_cmp expected actual +' + +test_expect_success 'using "ifExists = doNothing"' ' + git config trailer.fix.ifExists "doNothing" && + cat complex_message_body >expected && + sed -e "s/ Z\$/ /" >>expected <<-\EOF && + Bug #42 + Fixes: Z + Acked-by= Z + Acked-by= Junio + Acked-by= Peff + Reviewed-by: + Signed-off-by: Z + EOF + git interpret-trailers --trailer "review:" --trailer "fix=53" \ + --trailer "ack: Junio" --trailer "fix=22" \ + --trailer "bug: 42" --trailer "ack: Peff" \ + <complex_message >actual && + test_cmp expected actual +' + +test_expect_success 'the default is "ifMissing = add"' ' + git config trailer.cc.key "Cc: " && + git config trailer.cc.where "before" && + cat complex_message_body >expected && + sed -e "s/ Z\$/ /" >>expected <<-\EOF && + Bug #42 + Cc: Linus + Fixes: Z + Acked-by= Z + Acked-by= Junio + Acked-by= Peff + Reviewed-by: + Signed-off-by: Z + EOF + git interpret-trailers --trailer "review:" --trailer "fix=53" \ + --trailer "cc=Linus" --trailer "ack: Junio" \ + --trailer "fix=22" --trailer "bug: 42" --trailer "ack: Peff" \ + <complex_message >actual && + test_cmp expected actual +' + +test_expect_success 'when default "ifMissing" is "doNothing"' ' + git config trailer.ifmissing "doNothing" && + cat complex_message_body >expected && + sed -e "s/ Z\$/ /" >>expected <<-\EOF && + Fixes: Z + Acked-by= Z + Acked-by= Junio + Acked-by= Peff + Reviewed-by: + Signed-off-by: Z + EOF + git interpret-trailers --trailer "review:" --trailer "fix=53" \ + --trailer "cc=Linus" --trailer "ack: Junio" \ + --trailer "fix=22" --trailer "bug: 42" --trailer "ack: Peff" \ + <complex_message >actual && + test_cmp expected actual && + git config trailer.ifmissing "add" +' + +test_expect_success 'using "ifMissing = add" with "where = end"' ' + git config trailer.cc.key "Cc: " && + git config trailer.cc.where "end" && + git config trailer.cc.ifMissing "add" && + cat complex_message_body >expected && + sed -e "s/ Z\$/ /" >>expected <<-\EOF && + Bug #42 + Fixes: Z + Acked-by= Z + Acked-by= Junio + Acked-by= Peff + Reviewed-by: + Signed-off-by: Z + Cc: Linus + EOF + git interpret-trailers --trailer "review:" --trailer "fix=53" \ + --trailer "ack: Junio" --trailer "fix=22" \ + --trailer "bug: 42" --trailer "cc=Linus" --trailer "ack: Peff" \ + <complex_message >actual && + test_cmp expected actual +' + +test_expect_success 'using "ifMissing = add" with "where = before"' ' + git config trailer.cc.key "Cc: " && + git config trailer.cc.where "before" && + git config trailer.cc.ifMissing "add" && + cat complex_message_body >expected && + sed -e "s/ Z\$/ /" >>expected <<-\EOF && + Cc: Linus + Bug #42 + Fixes: Z + Acked-by= Z + Acked-by= Junio + Acked-by= Peff + Reviewed-by: + Signed-off-by: Z + EOF + git interpret-trailers --trailer "review:" --trailer "fix=53" \ + --trailer "ack: Junio" --trailer "fix=22" \ + --trailer "bug: 42" --trailer "cc=Linus" --trailer "ack: Peff" \ + <complex_message >actual && + test_cmp expected actual +' + +test_expect_success 'using "ifMissing = doNothing"' ' + git config trailer.cc.ifMissing "doNothing" && + cat complex_message_body >expected && + sed -e "s/ Z\$/ /" >>expected <<-\EOF && + Bug #42 + Fixes: Z + Acked-by= Z + Acked-by= Junio + Acked-by= Peff + Reviewed-by: + Signed-off-by: Z + EOF + git interpret-trailers --trailer "review:" --trailer "fix=53" \ + --trailer "cc=Linus" --trailer "ack: Junio" \ + --trailer "fix=22" --trailer "bug: 42" --trailer "ack: Peff" \ + <complex_message >actual && + test_cmp expected actual +' + +test_expect_success 'default "where" is now "after"' ' + git config trailer.where "after" && + git config --unset trailer.ack.where && + cat complex_message_body >expected && + sed -e "s/ Z\$/ /" >>expected <<-\EOF && + Bug #42 + Fixes: Z + Acked-by= Z + Acked-by= Peff + Acked-by= Peff + Acked-by= Junio + Acked-by= Peff + Reviewed-by: + Signed-off-by: Z + Tested-by: Jakub + Tested-by: Johannes + EOF + git interpret-trailers --trailer "ack: Peff" \ + --trailer "Acked-by= Peff" --trailer "review:" \ + --trailer "Tested-by: Jakub" --trailer "ack: Junio" \ + --trailer "bug: 42" --trailer "Tested-by: Johannes" \ + --trailer "ack: Peff" <complex_message >actual && + test_cmp expected actual +' + +test_expect_success 'with simple command' ' + git config trailer.sign.key "Signed-off-by: " && + git config trailer.sign.where "after" && + git config trailer.sign.ifExists "addIfDifferentNeighbor" && + git config trailer.sign.command "echo \"A U Thor <author@example.com>\"" && + cat complex_message_body >expected && + sed -e "s/ Z\$/ /" >>expected <<-\EOF && + Fixes: Z + Acked-by= Z + Reviewed-by: + Signed-off-by: Z + Signed-off-by: A U Thor <author@example.com> + EOF + git interpret-trailers --trailer "review:" --trailer "fix=22" \ + <complex_message >actual && + test_cmp expected actual +' + +test_expect_success 'with command using commiter information' ' + git config trailer.sign.ifExists "addIfDifferent" && + git config trailer.sign.command "echo \"\$GIT_COMMITTER_NAME <\$GIT_COMMITTER_EMAIL>\"" && + cat complex_message_body >expected && + sed -e "s/ Z\$/ /" >>expected <<-\EOF && + Fixes: Z + Acked-by= Z + Reviewed-by: + Signed-off-by: Z + Signed-off-by: C O Mitter <committer@example.com> + EOF + git interpret-trailers --trailer "review:" --trailer "fix=22" \ + <complex_message >actual && + test_cmp expected actual +' + +test_expect_success 'with command using author information' ' + git config trailer.sign.key "Signed-off-by: " && + git config trailer.sign.where "after" && + git config trailer.sign.ifExists "addIfDifferentNeighbor" && + git config trailer.sign.command "echo \"\$GIT_AUTHOR_NAME <\$GIT_AUTHOR_EMAIL>\"" && + cat complex_message_body >expected && + sed -e "s/ Z\$/ /" >>expected <<-\EOF && + Fixes: Z + Acked-by= Z + Reviewed-by: + Signed-off-by: Z + Signed-off-by: A U Thor <author@example.com> + EOF + git interpret-trailers --trailer "review:" --trailer "fix=22" \ + <complex_message >actual && + test_cmp expected actual +' + +test_expect_success 'setup a commit' ' + echo "Content of the first commit." > a.txt && + git add a.txt && + git commit -m "Add file a.txt" +' + +test_expect_success 'with command using $ARG' ' + git config trailer.fix.ifExists "replace" && + git config trailer.fix.command "git log -1 --oneline --format=\"%h (%s)\" --abbrev-commit --abbrev=14 \$ARG" && + FIXED=$(git log -1 --oneline --format="%h (%s)" --abbrev-commit --abbrev=14 HEAD) && + cat complex_message_body >expected && + sed -e "s/ Z\$/ /" >>expected <<-EOF && + Fixes: $FIXED + Acked-by= Z + Reviewed-by: + Signed-off-by: Z + Signed-off-by: A U Thor <author@example.com> + EOF + git interpret-trailers --trailer "review:" --trailer "fix=HEAD" \ + <complex_message >actual && + test_cmp expected actual +' + +test_expect_success 'with failing command using $ARG' ' + git config trailer.fix.ifExists "replace" && + git config trailer.fix.command "false \$ARG" && + cat complex_message_body >expected && + sed -e "s/ Z\$/ /" >>expected <<-EOF && + Fixes: Z + Acked-by= Z + Reviewed-by: + Signed-off-by: Z + Signed-off-by: A U Thor <author@example.com> + EOF + git interpret-trailers --trailer "review:" --trailer "fix=HEAD" \ + <complex_message >actual && + test_cmp expected actual +' + +test_expect_success 'with empty tokens' ' + git config --unset trailer.fix.command && + cat >expected <<-EOF && + + Signed-off-by: A U Thor <author@example.com> + EOF + git interpret-trailers --trailer ":" --trailer ":test" >actual <<-EOF && + EOF + test_cmp expected actual +' + +test_expect_success 'with command but no key' ' + git config --unset trailer.sign.key && + cat >expected <<-EOF && + + sign: A U Thor <author@example.com> + EOF + git interpret-trailers >actual <<-EOF && + EOF + test_cmp expected actual +' + +test_expect_success 'with no command and no key' ' + git config --unset trailer.review.key && + cat >expected <<-EOF && + + review: Junio + sign: A U Thor <author@example.com> + EOF + git interpret-trailers --trailer "review:Junio" >actual <<-EOF && + EOF + test_cmp expected actual +' + +test_done diff --git a/t/t7515-status-symlinks.sh b/t/t7515-status-symlinks.sh new file mode 100755 index 0000000000..9f989be01b --- /dev/null +++ b/t/t7515-status-symlinks.sh @@ -0,0 +1,43 @@ +#!/bin/sh + +test_description='git status and symlinks' + +. ./test-lib.sh + +test_expect_success 'setup' ' + echo .gitignore >.gitignore && + echo actual >>.gitignore && + echo expect >>.gitignore && + mkdir dir && + echo x >dir/file1 && + echo y >dir/file2 && + git add dir && + git commit -m initial && + git tag initial +' + +test_expect_success SYMLINKS 'symlink to a directory' ' + test_when_finished "rm symlink" && + ln -s dir symlink && + echo "?? symlink" >expect && + git status --porcelain >actual && + test_cmp expect actual +' + +test_expect_success SYMLINKS 'symlink replacing a directory' ' + test_when_finished "rm -rf copy && git reset --hard initial" && + mkdir copy && + cp dir/file1 copy/file1 && + echo "changed in copy" >copy/file2 && + git add copy && + git commit -m second && + rm -rf copy && + ln -s dir copy && + echo " D copy/file1" >expect && + echo " D copy/file2" >>expect && + echo "?? copy" >>expect && + git status --porcelain >actual && + test_cmp expect actual +' + +test_done diff --git a/t/t7516-commit-races.sh b/t/t7516-commit-races.sh new file mode 100755 index 0000000000..f2ce14e907 --- /dev/null +++ b/t/t7516-commit-races.sh @@ -0,0 +1,30 @@ +#!/bin/sh + +test_description='git commit races' +. ./test-lib.sh + +test_expect_success 'race to create orphan commit' ' + write_script hare-editor <<-\EOF && + git commit --allow-empty -m hare + EOF + test_must_fail env EDITOR=./hare-editor git commit --allow-empty -m tortoise -e && + git show -s --pretty=format:%s >subject && + grep hare subject && + test -z "$(git show -s --pretty=format:%P)" +' + +test_expect_success 'race to create non-orphan commit' ' + write_script airplane-editor <<-\EOF && + git commit --allow-empty -m airplane + EOF + git checkout --orphan branch && + git commit --allow-empty -m base && + git rev-parse HEAD >base && + test_must_fail env EDITOR=./airplane-editor git commit --allow-empty -m ship -e && + git show -s --pretty=format:%s >subject && + grep airplane subject && + git rev-parse HEAD^ >parent && + test_cmp base parent +' + +test_done diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh index b16462132f..302e238263 100755 --- a/t/t7600-merge.sh +++ b/t/t7600-merge.sh @@ -133,7 +133,7 @@ test_expect_success 'setup' ' test_tick && git commit -m "commit 3" && git tag c3 && - c3=$(git rev-parse HEAD) + c3=$(git rev-parse HEAD) && git reset --hard "$c0" && create_merge_msgs ' @@ -692,4 +692,37 @@ test_expect_success GPG 'merge --no-edit tag should skip editor' ' test_cmp actual expect ' +test_expect_success 'set up mod-256 conflict scenario' ' + # 256 near-identical stanzas... + for i in $(test_seq 1 256); do + for j in 1 2 3 4 5; do + echo $i-$j + done + done >file && + git add file && + git commit -m base && + + # one side changes the first line of each to "master" + sed s/-1/-master/ <file >tmp && + mv tmp file && + git commit -am master && + + # and the other to "side"; merging the two will + # yield 256 separate conflicts + git checkout -b side HEAD^ && + sed s/-1/-side/ <file >tmp && + mv tmp file && + git commit -am side +' + +test_expect_success 'merge detects mod-256 conflicts (recursive)' ' + git reset --hard && + test_must_fail git merge -s recursive master +' + +test_expect_success 'merge detects mod-256 conflicts (resolve)' ' + git reset --hard && + test_must_fail git merge -s resolve master +' + test_done diff --git a/t/t7601-merge-pull-config.sh b/t/t7601-merge-pull-config.sh index f768c900ab..c6c44ec570 100755 --- a/t/t7601-merge-pull-config.sh +++ b/t/t7601-merge-pull-config.sh @@ -45,6 +45,14 @@ test_expect_success 'fast-forward pull succeeds with "true" in pull.ff' ' test "$(git rev-parse HEAD)" = "$(git rev-parse c1)" ' +test_expect_success 'pull.ff=true overrides merge.ff=false' ' + git reset --hard c0 && + test_config merge.ff false && + test_config pull.ff true && + git pull . c1 && + test "$(git rev-parse HEAD)" = "$(git rev-parse c1)" +' + test_expect_success 'fast-forward pull creates merge with "false" in pull.ff' ' git reset --hard c0 && test_config pull.ff false && diff --git a/t/t7610-mergetool.sh b/t/t7610-mergetool.sh index 05d9db090d..6f12b235b3 100755 --- a/t/t7610-mergetool.sh +++ b/t/t7610-mergetool.sh @@ -14,512 +14,527 @@ Testing basic merge tool invocation' # running mergetool test_expect_success 'setup' ' - git config rerere.enabled true && - echo master >file1 && - echo master spaced >"spaced name" && - echo master file11 >file11 && - echo master file12 >file12 && - echo master file13 >file13 && - echo master file14 >file14 && - mkdir subdir && - echo master sub >subdir/file3 && - test_create_repo submod && - ( - cd submod && - : >foo && - git add foo && - git commit -m "Add foo" - ) && - git submodule add git://example.com/submod submod && - git add file1 "spaced name" file1[1-4] subdir/file3 .gitmodules submod && - git commit -m "add initial versions" && - - git checkout -b branch1 master && - git submodule update -N && - echo branch1 change >file1 && - echo branch1 newfile >file2 && - echo branch1 spaced >"spaced name" && - echo branch1 both added >both && - echo branch1 change file11 >file11 && - echo branch1 change file13 >file13 && - echo branch1 sub >subdir/file3 && - ( - cd submod && - echo branch1 submodule >bar && - git add bar && - git commit -m "Add bar on branch1" && - git checkout -b submod-branch1 - ) && - git add file1 "spaced name" file11 file13 file2 subdir/file3 submod && - git add both && - git rm file12 && - git commit -m "branch1 changes" && - - git checkout -b stash1 master && - echo stash1 change file11 >file11 && - git add file11 && - git commit -m "stash1 changes" && - - git checkout -b stash2 master && - echo stash2 change file11 >file11 && - git add file11 && - git commit -m "stash2 changes" && - - git checkout master && - git submodule update -N && - echo master updated >file1 && - echo master new >file2 && - echo master updated spaced >"spaced name" && - echo master both added >both && - echo master updated file12 >file12 && - echo master updated file14 >file14 && - echo master new sub >subdir/file3 && - ( - cd submod && - echo master submodule >bar && - git add bar && - git commit -m "Add bar on master" && - git checkout -b submod-master - ) && - git add file1 "spaced name" file12 file14 file2 subdir/file3 submod && - git add both && - git rm file11 && - git commit -m "master updates" && - - git config merge.tool mytool && - git config mergetool.mytool.cmd "cat \"\$REMOTE\" >\"\$MERGED\"" && - git config mergetool.mytool.trustExitCode true && - git config mergetool.mybase.cmd "cat \"\$BASE\" >\"\$MERGED\"" && - git config mergetool.mybase.trustExitCode true + test_config rerere.enabled true && + echo master >file1 && + echo master spaced >"spaced name" && + echo master file11 >file11 && + echo master file12 >file12 && + echo master file13 >file13 && + echo master file14 >file14 && + mkdir subdir && + echo master sub >subdir/file3 && + test_create_repo submod && + ( + cd submod && + : >foo && + git add foo && + git commit -m "Add foo" + ) && + git submodule add git://example.com/submod submod && + git add file1 "spaced name" file1[1-4] subdir/file3 .gitmodules submod && + git commit -m "add initial versions" && + + git checkout -b branch1 master && + git submodule update -N && + echo branch1 change >file1 && + echo branch1 newfile >file2 && + echo branch1 spaced >"spaced name" && + echo branch1 both added >both && + echo branch1 change file11 >file11 && + echo branch1 change file13 >file13 && + echo branch1 sub >subdir/file3 && + ( + cd submod && + echo branch1 submodule >bar && + git add bar && + git commit -m "Add bar on branch1" && + git checkout -b submod-branch1 + ) && + git add file1 "spaced name" file11 file13 file2 subdir/file3 submod && + git add both && + git rm file12 && + git commit -m "branch1 changes" && + + git checkout -b stash1 master && + echo stash1 change file11 >file11 && + git add file11 && + git commit -m "stash1 changes" && + + git checkout -b stash2 master && + echo stash2 change file11 >file11 && + git add file11 && + git commit -m "stash2 changes" && + + git checkout master && + git submodule update -N && + echo master updated >file1 && + echo master new >file2 && + echo master updated spaced >"spaced name" && + echo master both added >both && + echo master updated file12 >file12 && + echo master updated file14 >file14 && + echo master new sub >subdir/file3 && + ( + cd submod && + echo master submodule >bar && + git add bar && + git commit -m "Add bar on master" && + git checkout -b submod-master + ) && + git add file1 "spaced name" file12 file14 file2 subdir/file3 submod && + git add both && + git rm file11 && + git commit -m "master updates" && + + git config merge.tool mytool && + git config mergetool.mytool.cmd "cat \"\$REMOTE\" >\"\$MERGED\"" && + git config mergetool.mytool.trustExitCode true && + git config mergetool.mybase.cmd "cat \"\$BASE\" >\"\$MERGED\"" && + git config mergetool.mybase.trustExitCode true ' test_expect_success 'custom mergetool' ' - git checkout -b test1 branch1 && - git submodule update -N && - test_must_fail git merge master >/dev/null 2>&1 && - ( yes "" | git mergetool both >/dev/null 2>&1 ) && - ( yes "" | git mergetool file1 file1 ) && - ( yes "" | git mergetool file2 "spaced name" >/dev/null 2>&1 ) && - ( yes "" | git mergetool subdir/file3 >/dev/null 2>&1 ) && - ( yes "d" | git mergetool file11 >/dev/null 2>&1 ) && - ( yes "d" | git mergetool file12 >/dev/null 2>&1 ) && - ( yes "l" | git mergetool submod >/dev/null 2>&1 ) && - test "$(cat file1)" = "master updated" && - test "$(cat file2)" = "master new" && - test "$(cat subdir/file3)" = "master new sub" && - test "$(cat submod/bar)" = "branch1 submodule" && - git commit -m "branch1 resolved with mergetool" + git checkout -b test1 branch1 && + git submodule update -N && + test_must_fail git merge master >/dev/null 2>&1 && + ( yes "" | git mergetool both >/dev/null 2>&1 ) && + ( yes "" | git mergetool file1 file1 ) && + ( yes "" | git mergetool file2 "spaced name" >/dev/null 2>&1 ) && + ( yes "" | git mergetool subdir/file3 >/dev/null 2>&1 ) && + ( yes "d" | git mergetool file11 >/dev/null 2>&1 ) && + ( yes "d" | git mergetool file12 >/dev/null 2>&1 ) && + ( yes "l" | git mergetool submod >/dev/null 2>&1 ) && + test "$(cat file1)" = "master updated" && + test "$(cat file2)" = "master new" && + test "$(cat subdir/file3)" = "master new sub" && + test "$(cat submod/bar)" = "branch1 submodule" && + git commit -m "branch1 resolved with mergetool" ' test_expect_success 'mergetool crlf' ' - git config core.autocrlf true && - git checkout -b test2 branch1 && - test_must_fail git merge master >/dev/null 2>&1 && - ( yes "" | git mergetool file1 >/dev/null 2>&1 ) && - ( yes "" | git mergetool file2 >/dev/null 2>&1 ) && - ( yes "" | git mergetool "spaced name" >/dev/null 2>&1 ) && - ( yes "" | git mergetool both >/dev/null 2>&1 ) && - ( yes "" | git mergetool subdir/file3 >/dev/null 2>&1 ) && - ( yes "d" | git mergetool file11 >/dev/null 2>&1 ) && - ( yes "d" | git mergetool file12 >/dev/null 2>&1 ) && - ( yes "r" | git mergetool submod >/dev/null 2>&1 ) && - test "$(printf x | cat file1 -)" = "$(printf "master updated\r\nx")" && - test "$(printf x | cat file2 -)" = "$(printf "master new\r\nx")" && - test "$(printf x | cat subdir/file3 -)" = "$(printf "master new sub\r\nx")" && - git submodule update -N && - test "$(cat submod/bar)" = "master submodule" && - git commit -m "branch1 resolved with mergetool - autocrlf" && - git config core.autocrlf false && - git reset --hard + test_config core.autocrlf true && + git checkout -b test2 branch1 && + test_must_fail git merge master >/dev/null 2>&1 && + ( yes "" | git mergetool file1 >/dev/null 2>&1 ) && + ( yes "" | git mergetool file2 >/dev/null 2>&1 ) && + ( yes "" | git mergetool "spaced name" >/dev/null 2>&1 ) && + ( yes "" | git mergetool both >/dev/null 2>&1 ) && + ( yes "" | git mergetool subdir/file3 >/dev/null 2>&1 ) && + ( yes "d" | git mergetool file11 >/dev/null 2>&1 ) && + ( yes "d" | git mergetool file12 >/dev/null 2>&1 ) && + ( yes "r" | git mergetool submod >/dev/null 2>&1 ) && + test "$(printf x | cat file1 -)" = "$(printf "master updated\r\nx")" && + test "$(printf x | cat file2 -)" = "$(printf "master new\r\nx")" && + test "$(printf x | cat subdir/file3 -)" = "$(printf "master new sub\r\nx")" && + git submodule update -N && + test "$(cat submod/bar)" = "master submodule" && + git commit -m "branch1 resolved with mergetool - autocrlf" && + test_config core.autocrlf false && + git reset --hard ' test_expect_success 'mergetool in subdir' ' - git checkout -b test3 branch1 && - git submodule update -N && - ( - cd subdir && - test_must_fail git merge master >/dev/null 2>&1 && - ( yes "" | git mergetool file3 >/dev/null 2>&1 ) && - test "$(cat file3)" = "master new sub" - ) + git checkout -b test3 branch1 && + git submodule update -N && + ( + cd subdir && + test_must_fail git merge master >/dev/null 2>&1 && + ( yes "" | git mergetool file3 >/dev/null 2>&1 ) && + test "$(cat file3)" = "master new sub" + ) ' test_expect_success 'mergetool on file in parent dir' ' - ( - cd subdir && - ( yes "" | git mergetool ../file1 >/dev/null 2>&1 ) && - ( yes "" | git mergetool ../file2 ../spaced\ name >/dev/null 2>&1 ) && - ( yes "" | git mergetool ../both >/dev/null 2>&1 ) && - ( yes "d" | git mergetool ../file11 >/dev/null 2>&1 ) && - ( yes "d" | git mergetool ../file12 >/dev/null 2>&1 ) && - ( yes "l" | git mergetool ../submod >/dev/null 2>&1 ) && - test "$(cat ../file1)" = "master updated" && - test "$(cat ../file2)" = "master new" && - test "$(cat ../submod/bar)" = "branch1 submodule" && - git commit -m "branch1 resolved with mergetool - subdir" - ) + ( + cd subdir && + ( yes "" | git mergetool ../file1 >/dev/null 2>&1 ) && + ( yes "" | git mergetool ../file2 ../spaced\ name >/dev/null 2>&1 ) && + ( yes "" | git mergetool ../both >/dev/null 2>&1 ) && + ( yes "d" | git mergetool ../file11 >/dev/null 2>&1 ) && + ( yes "d" | git mergetool ../file12 >/dev/null 2>&1 ) && + ( yes "l" | git mergetool ../submod >/dev/null 2>&1 ) && + test "$(cat ../file1)" = "master updated" && + test "$(cat ../file2)" = "master new" && + test "$(cat ../submod/bar)" = "branch1 submodule" && + git commit -m "branch1 resolved with mergetool - subdir" + ) ' test_expect_success 'mergetool skips autoresolved' ' - git checkout -b test4 branch1 && - git submodule update -N && - test_must_fail git merge master && - test -n "$(git ls-files -u)" && - ( yes "d" | git mergetool file11 >/dev/null 2>&1 ) && - ( yes "d" | git mergetool file12 >/dev/null 2>&1 ) && - ( yes "l" | git mergetool submod >/dev/null 2>&1 ) && - output="$(git mergetool --no-prompt)" && - test "$output" = "No files need merging" && - git reset --hard + git checkout -b test4 branch1 && + git submodule update -N && + test_must_fail git merge master && + test -n "$(git ls-files -u)" && + ( yes "d" | git mergetool file11 >/dev/null 2>&1 ) && + ( yes "d" | git mergetool file12 >/dev/null 2>&1 ) && + ( yes "l" | git mergetool submod >/dev/null 2>&1 ) && + output="$(git mergetool --no-prompt)" && + test "$output" = "No files need merging" && + git reset --hard ' test_expect_success 'mergetool merges all from subdir' ' - ( - cd subdir && - git config rerere.enabled false && - test_must_fail git merge master && - ( yes "r" | git mergetool ../submod ) && - ( yes "d" "d" | git mergetool --no-prompt ) && - test "$(cat ../file1)" = "master updated" && - test "$(cat ../file2)" = "master new" && - test "$(cat file3)" = "master new sub" && - ( cd .. && git submodule update -N ) && - test "$(cat ../submod/bar)" = "master submodule" && - git commit -m "branch2 resolved by mergetool from subdir" - ) + test_config rerere.enabled false && + ( + cd subdir && + test_must_fail git merge master && + ( yes "r" | git mergetool ../submod ) && + ( yes "d" "d" | git mergetool --no-prompt ) && + test "$(cat ../file1)" = "master updated" && + test "$(cat ../file2)" = "master new" && + test "$(cat file3)" = "master new sub" && + ( cd .. && git submodule update -N ) && + test "$(cat ../submod/bar)" = "master submodule" && + git commit -m "branch2 resolved by mergetool from subdir" + ) ' test_expect_success 'mergetool skips resolved paths when rerere is active' ' - git config rerere.enabled true && - rm -rf .git/rr-cache && - git checkout -b test5 branch1 - git submodule update -N && - test_must_fail git merge master >/dev/null 2>&1 && - ( yes "l" | git mergetool --no-prompt submod >/dev/null 2>&1 ) && - ( yes "d" "d" | git mergetool --no-prompt >/dev/null 2>&1 ) && - git submodule update -N && - output="$(yes "n" | git mergetool --no-prompt)" && - test "$output" = "No files need merging" && - git reset --hard + test_config rerere.enabled true && + rm -rf .git/rr-cache && + git checkout -b test5 branch1 && + git submodule update -N && + test_must_fail git merge master >/dev/null 2>&1 && + ( yes "l" | git mergetool --no-prompt submod >/dev/null 2>&1 ) && + ( yes "d" "d" | git mergetool --no-prompt >/dev/null 2>&1 ) && + git submodule update -N && + output="$(yes "n" | git mergetool --no-prompt)" && + test "$output" = "No files need merging" && + git reset --hard ' test_expect_success 'conflicted stash sets up rerere' ' - git config rerere.enabled true && - git checkout stash1 && - echo "Conflicting stash content" >file11 && - git stash && - - git checkout --detach stash2 && - test_must_fail git stash apply && - - test -n "$(git ls-files -u)" && - conflicts="$(git rerere remaining)" && - test "$conflicts" = "file11" && - output="$(git mergetool --no-prompt)" && - test "$output" != "No files need merging" && - - git commit -am "save the stash resolution" && - - git reset --hard stash2 && - test_must_fail git stash apply && - - test -n "$(git ls-files -u)" && - conflicts="$(git rerere remaining)" && - test -z "$conflicts" && - output="$(git mergetool --no-prompt)" && - test "$output" = "No files need merging" + test_config rerere.enabled true && + git checkout stash1 && + echo "Conflicting stash content" >file11 && + git stash && + + git checkout --detach stash2 && + test_must_fail git stash apply && + + test -n "$(git ls-files -u)" && + conflicts="$(git rerere remaining)" && + test "$conflicts" = "file11" && + output="$(git mergetool --no-prompt)" && + test "$output" != "No files need merging" && + + git commit -am "save the stash resolution" && + + git reset --hard stash2 && + test_must_fail git stash apply && + + test -n "$(git ls-files -u)" && + conflicts="$(git rerere remaining)" && + test -z "$conflicts" && + output="$(git mergetool --no-prompt)" && + test "$output" = "No files need merging" ' test_expect_success 'mergetool takes partial path' ' - git reset --hard - git config rerere.enabled false && - git checkout -b test12 branch1 && - git submodule update -N && - test_must_fail git merge master && - - #should not need these lines - #( yes "d" | git mergetool file11 >/dev/null 2>&1 ) && - #( yes "d" | git mergetool file12 >/dev/null 2>&1 ) && - #( yes "l" | git mergetool submod >/dev/null 2>&1 ) && - #( yes "" | git mergetool file1 file2 >/dev/null 2>&1 ) && - - ( yes "" | git mergetool subdir ) && - - test "$(cat subdir/file3)" = "master new sub" && - git reset --hard + git reset --hard && + test_config rerere.enabled false && + git checkout -b test12 branch1 && + git submodule update -N && + test_must_fail git merge master && + + ( yes "" | git mergetool subdir ) && + + test "$(cat subdir/file3)" = "master new sub" && + git reset --hard ' test_expect_success 'deleted vs modified submodule' ' - git checkout -b test6 branch1 && - git submodule update -N && - mv submod submod-movedaside && - git rm --cached submod && - git commit -m "Submodule deleted from branch" && - git checkout -b test6.a test6 && - test_must_fail git merge master && - test -n "$(git ls-files -u)" && - ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) && - ( yes "" | git mergetool both >/dev/null 2>&1 ) && - ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) && - ( yes "r" | git mergetool submod ) && - rmdir submod && mv submod-movedaside submod && - test "$(cat submod/bar)" = "branch1 submodule" && - git submodule update -N && - test "$(cat submod/bar)" = "master submodule" && - output="$(git mergetool --no-prompt)" && - test "$output" = "No files need merging" && - git commit -m "Merge resolved by keeping module" && - - mv submod submod-movedaside && - git checkout -b test6.b test6 && - git submodule update -N && - test_must_fail git merge master && - test -n "$(git ls-files -u)" && - ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) && - ( yes "" | git mergetool both >/dev/null 2>&1 ) && - ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) && - ( yes "l" | git mergetool submod ) && - test ! -e submod && - output="$(git mergetool --no-prompt)" && - test "$output" = "No files need merging" && - git commit -m "Merge resolved by deleting module" && - - mv submod-movedaside submod && - git checkout -b test6.c master && - git submodule update -N && - test_must_fail git merge test6 && - test -n "$(git ls-files -u)" && - ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) && - ( yes "" | git mergetool both >/dev/null 2>&1 ) && - ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) && - ( yes "r" | git mergetool submod ) && - test ! -e submod && - test -d submod.orig && - git submodule update -N && - output="$(git mergetool --no-prompt)" && - test "$output" = "No files need merging" && - git commit -m "Merge resolved by deleting module" && - mv submod.orig submod && - - git checkout -b test6.d master && - git submodule update -N && - test_must_fail git merge test6 && - test -n "$(git ls-files -u)" && - ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) && - ( yes "" | git mergetool both >/dev/null 2>&1 ) && - ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) && - ( yes "l" | git mergetool submod ) && - test "$(cat submod/bar)" = "master submodule" && - git submodule update -N && - test "$(cat submod/bar)" = "master submodule" && - output="$(git mergetool --no-prompt)" && - test "$output" = "No files need merging" && - git commit -m "Merge resolved by keeping module" && - git reset --hard HEAD + git checkout -b test6 branch1 && + git submodule update -N && + mv submod submod-movedaside && + git rm --cached submod && + git commit -m "Submodule deleted from branch" && + git checkout -b test6.a test6 && + test_must_fail git merge master && + test -n "$(git ls-files -u)" && + ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) && + ( yes "" | git mergetool both >/dev/null 2>&1 ) && + ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) && + ( yes "r" | git mergetool submod ) && + rmdir submod && mv submod-movedaside submod && + test "$(cat submod/bar)" = "branch1 submodule" && + git submodule update -N && + test "$(cat submod/bar)" = "master submodule" && + output="$(git mergetool --no-prompt)" && + test "$output" = "No files need merging" && + git commit -m "Merge resolved by keeping module" && + + mv submod submod-movedaside && + git checkout -b test6.b test6 && + git submodule update -N && + test_must_fail git merge master && + test -n "$(git ls-files -u)" && + ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) && + ( yes "" | git mergetool both >/dev/null 2>&1 ) && + ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) && + ( yes "l" | git mergetool submod ) && + test ! -e submod && + output="$(git mergetool --no-prompt)" && + test "$output" = "No files need merging" && + git commit -m "Merge resolved by deleting module" && + + mv submod-movedaside submod && + git checkout -b test6.c master && + git submodule update -N && + test_must_fail git merge test6 && + test -n "$(git ls-files -u)" && + ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) && + ( yes "" | git mergetool both >/dev/null 2>&1 ) && + ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) && + ( yes "r" | git mergetool submod ) && + test ! -e submod && + test -d submod.orig && + git submodule update -N && + output="$(git mergetool --no-prompt)" && + test "$output" = "No files need merging" && + git commit -m "Merge resolved by deleting module" && + mv submod.orig submod && + + git checkout -b test6.d master && + git submodule update -N && + test_must_fail git merge test6 && + test -n "$(git ls-files -u)" && + ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) && + ( yes "" | git mergetool both >/dev/null 2>&1 ) && + ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) && + ( yes "l" | git mergetool submod ) && + test "$(cat submod/bar)" = "master submodule" && + git submodule update -N && + test "$(cat submod/bar)" = "master submodule" && + output="$(git mergetool --no-prompt)" && + test "$output" = "No files need merging" && + git commit -m "Merge resolved by keeping module" && + git reset --hard HEAD ' test_expect_success 'file vs modified submodule' ' - git checkout -b test7 branch1 && - git submodule update -N && - mv submod submod-movedaside && - git rm --cached submod && - echo not a submodule >submod && - git add submod && - git commit -m "Submodule path becomes file" && - git checkout -b test7.a branch1 && - test_must_fail git merge master && - test -n "$(git ls-files -u)" && - ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) && - ( yes "" | git mergetool both >/dev/null 2>&1 ) && - ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) && - ( yes "r" | git mergetool submod ) && - rmdir submod && mv submod-movedaside submod && - test "$(cat submod/bar)" = "branch1 submodule" && - git submodule update -N && - test "$(cat submod/bar)" = "master submodule" && - output="$(git mergetool --no-prompt)" && - test "$output" = "No files need merging" && - git commit -m "Merge resolved by keeping module" && - - mv submod submod-movedaside && - git checkout -b test7.b test7 && - test_must_fail git merge master && - test -n "$(git ls-files -u)" && - ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) && - ( yes "" | git mergetool both >/dev/null 2>&1 ) && - ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) && - ( yes "l" | git mergetool submod ) && - git submodule update -N && - test "$(cat submod)" = "not a submodule" && - output="$(git mergetool --no-prompt)" && - test "$output" = "No files need merging" && - git commit -m "Merge resolved by keeping file" && - - git checkout -b test7.c master && - rmdir submod && mv submod-movedaside submod && - test ! -e submod.orig && - git submodule update -N && - test_must_fail git merge test7 && - test -n "$(git ls-files -u)" && - ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) && - ( yes "" | git mergetool both >/dev/null 2>&1 ) && - ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) && - ( yes "r" | git mergetool submod ) && - test -d submod.orig && - git submodule update -N && - test "$(cat submod)" = "not a submodule" && - output="$(git mergetool --no-prompt)" && - test "$output" = "No files need merging" && - git commit -m "Merge resolved by keeping file" && - - git checkout -b test7.d master && - rmdir submod && mv submod.orig submod && - git submodule update -N && - test_must_fail git merge test7 && - test -n "$(git ls-files -u)" && - ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) && - ( yes "" | git mergetool both>/dev/null 2>&1 ) && - ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) && - ( yes "l" | git mergetool submod ) && - test "$(cat submod/bar)" = "master submodule" && - git submodule update -N && - test "$(cat submod/bar)" = "master submodule" && - output="$(git mergetool --no-prompt)" && - test "$output" = "No files need merging" && - git commit -m "Merge resolved by keeping module" + git checkout -b test7 branch1 && + git submodule update -N && + mv submod submod-movedaside && + git rm --cached submod && + echo not a submodule >submod && + git add submod && + git commit -m "Submodule path becomes file" && + git checkout -b test7.a branch1 && + test_must_fail git merge master && + test -n "$(git ls-files -u)" && + ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) && + ( yes "" | git mergetool both >/dev/null 2>&1 ) && + ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) && + ( yes "r" | git mergetool submod ) && + rmdir submod && mv submod-movedaside submod && + test "$(cat submod/bar)" = "branch1 submodule" && + git submodule update -N && + test "$(cat submod/bar)" = "master submodule" && + output="$(git mergetool --no-prompt)" && + test "$output" = "No files need merging" && + git commit -m "Merge resolved by keeping module" && + + mv submod submod-movedaside && + git checkout -b test7.b test7 && + test_must_fail git merge master && + test -n "$(git ls-files -u)" && + ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) && + ( yes "" | git mergetool both >/dev/null 2>&1 ) && + ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) && + ( yes "l" | git mergetool submod ) && + git submodule update -N && + test "$(cat submod)" = "not a submodule" && + output="$(git mergetool --no-prompt)" && + test "$output" = "No files need merging" && + git commit -m "Merge resolved by keeping file" && + + git checkout -b test7.c master && + rmdir submod && mv submod-movedaside submod && + test ! -e submod.orig && + git submodule update -N && + test_must_fail git merge test7 && + test -n "$(git ls-files -u)" && + ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) && + ( yes "" | git mergetool both >/dev/null 2>&1 ) && + ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) && + ( yes "r" | git mergetool submod ) && + test -d submod.orig && + git submodule update -N && + test "$(cat submod)" = "not a submodule" && + output="$(git mergetool --no-prompt)" && + test "$output" = "No files need merging" && + git commit -m "Merge resolved by keeping file" && + + git checkout -b test7.d master && + rmdir submod && mv submod.orig submod && + git submodule update -N && + test_must_fail git merge test7 && + test -n "$(git ls-files -u)" && + ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) && + ( yes "" | git mergetool both>/dev/null 2>&1 ) && + ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) && + ( yes "l" | git mergetool submod ) && + test "$(cat submod/bar)" = "master submodule" && + git submodule update -N && + test "$(cat submod/bar)" = "master submodule" && + output="$(git mergetool --no-prompt)" && + test "$output" = "No files need merging" && + git commit -m "Merge resolved by keeping module" ' test_expect_success 'submodule in subdirectory' ' - git checkout -b test10 branch1 && - git submodule update -N && - ( - cd subdir && - test_create_repo subdir_module && + git checkout -b test10 branch1 && + git submodule update -N && + ( + cd subdir && + test_create_repo subdir_module && + ( + cd subdir_module && + : >file15 && + git add file15 && + git commit -m "add initial versions" + ) + ) && + git submodule add git://example.com/subsubmodule subdir/subdir_module && + git add subdir/subdir_module && + git commit -m "add submodule in subdirectory" && + + git checkout -b test10.a test10 && + git submodule update -N && ( - cd subdir_module && - : >file15 && - git add file15 && - git commit -m "add initial versions" - ) - ) && - git submodule add git://example.com/subsubmodule subdir/subdir_module && - git add subdir/subdir_module && - git commit -m "add submodule in subdirectory" && - - git checkout -b test10.a test10 && - git submodule update -N && - ( - cd subdir/subdir_module && - git checkout -b super10.a && - echo test10.a >file15 && - git add file15 && - git commit -m "on branch 10.a" - ) && - git add subdir/subdir_module && - git commit -m "change submodule in subdirectory on test10.a" && - - git checkout -b test10.b test10 && - git submodule update -N && - ( cd subdir/subdir_module && - git checkout -b super10.b && - echo test10.b >file15 && - git add file15 && - git commit -m "on branch 10.b" - ) && - git add subdir/subdir_module && - git commit -m "change submodule in subdirectory on test10.b" && - - test_must_fail git merge test10.a >/dev/null 2>&1 && - ( - cd subdir && - ( yes "l" | git mergetool subdir_module ) - ) && - test "$(cat subdir/subdir_module/file15)" = "test10.b" && - git submodule update -N && - test "$(cat subdir/subdir_module/file15)" = "test10.b" && - git reset --hard && - git submodule update -N && - - test_must_fail git merge test10.a >/dev/null 2>&1 && - ( yes "r" | git mergetool subdir/subdir_module ) && - test "$(cat subdir/subdir_module/file15)" = "test10.b" && - git submodule update -N && - test "$(cat subdir/subdir_module/file15)" = "test10.a" && - git commit -m "branch1 resolved with mergetool" && - rm -rf subdir/subdir_module + git checkout -b super10.a && + echo test10.a >file15 && + git add file15 && + git commit -m "on branch 10.a" + ) && + git add subdir/subdir_module && + git commit -m "change submodule in subdirectory on test10.a" && + + git checkout -b test10.b test10 && + git submodule update -N && + ( + cd subdir/subdir_module && + git checkout -b super10.b && + echo test10.b >file15 && + git add file15 && + git commit -m "on branch 10.b" + ) && + git add subdir/subdir_module && + git commit -m "change submodule in subdirectory on test10.b" && + + test_must_fail git merge test10.a >/dev/null 2>&1 && + ( + cd subdir && + ( yes "l" | git mergetool subdir_module ) + ) && + test "$(cat subdir/subdir_module/file15)" = "test10.b" && + git submodule update -N && + test "$(cat subdir/subdir_module/file15)" = "test10.b" && + git reset --hard && + git submodule update -N && + + test_must_fail git merge test10.a >/dev/null 2>&1 && + ( yes "r" | git mergetool subdir/subdir_module ) && + test "$(cat subdir/subdir_module/file15)" = "test10.b" && + git submodule update -N && + test "$(cat subdir/subdir_module/file15)" = "test10.a" && + git commit -m "branch1 resolved with mergetool" && + rm -rf subdir/subdir_module ' test_expect_success 'directory vs modified submodule' ' - git checkout -b test11 branch1 && - mv submod submod-movedaside && - git rm --cached submod && - mkdir submod && - echo not a submodule >submod/file16 && - git add submod/file16 && - git commit -m "Submodule path becomes directory" && - - test_must_fail git merge master && - test -n "$(git ls-files -u)" && - ( yes "l" | git mergetool submod ) && - test "$(cat submod/file16)" = "not a submodule" && - rm -rf submod.orig && - - git reset --hard >/dev/null 2>&1 && - test_must_fail git merge master && - test -n "$(git ls-files -u)" && - test ! -e submod.orig && - ( yes "r" | git mergetool submod ) && - test -d submod.orig && - test "$(cat submod.orig/file16)" = "not a submodule" && - rm -r submod.orig && - mv submod-movedaside/.git submod && - ( cd submod && git clean -f && git reset --hard ) && - git submodule update -N && - test "$(cat submod/bar)" = "master submodule" && - git reset --hard >/dev/null 2>&1 && rm -rf submod-movedaside && - - git checkout -b test11.c master && - git submodule update -N && - test_must_fail git merge test11 && - test -n "$(git ls-files -u)" && - ( yes "l" | git mergetool submod ) && - git submodule update -N && - test "$(cat submod/bar)" = "master submodule" && - - git reset --hard >/dev/null 2>&1 && - git submodule update -N && - test_must_fail git merge test11 && - test -n "$(git ls-files -u)" && - test ! -e submod.orig && - ( yes "r" | git mergetool submod ) && - test "$(cat submod/file16)" = "not a submodule" && - - git reset --hard master >/dev/null 2>&1 && - ( cd submod && git clean -f && git reset --hard ) && - git submodule update -N + git checkout -b test11 branch1 && + mv submod submod-movedaside && + git rm --cached submod && + mkdir submod && + echo not a submodule >submod/file16 && + git add submod/file16 && + git commit -m "Submodule path becomes directory" && + + test_must_fail git merge master && + test -n "$(git ls-files -u)" && + ( yes "l" | git mergetool submod ) && + test "$(cat submod/file16)" = "not a submodule" && + rm -rf submod.orig && + + git reset --hard >/dev/null 2>&1 && + test_must_fail git merge master && + test -n "$(git ls-files -u)" && + test ! -e submod.orig && + ( yes "r" | git mergetool submod ) && + test -d submod.orig && + test "$(cat submod.orig/file16)" = "not a submodule" && + rm -r submod.orig && + mv submod-movedaside/.git submod && + ( cd submod && git clean -f && git reset --hard ) && + git submodule update -N && + test "$(cat submod/bar)" = "master submodule" && + git reset --hard >/dev/null 2>&1 && rm -rf submod-movedaside && + + git checkout -b test11.c master && + git submodule update -N && + test_must_fail git merge test11 && + test -n "$(git ls-files -u)" && + ( yes "l" | git mergetool submod ) && + git submodule update -N && + test "$(cat submod/bar)" = "master submodule" && + + git reset --hard >/dev/null 2>&1 && + git submodule update -N && + test_must_fail git merge test11 && + test -n "$(git ls-files -u)" && + test ! -e submod.orig && + ( yes "r" | git mergetool submod ) && + test "$(cat submod/file16)" = "not a submodule" && + + git reset --hard master >/dev/null 2>&1 && + ( cd submod && git clean -f && git reset --hard ) && + git submodule update -N ' test_expect_success 'file with no base' ' - git checkout -b test13 branch1 && - test_must_fail git merge master && - git mergetool --no-prompt --tool mybase -- both && - >expected && - test_cmp both expected && - git reset --hard master >/dev/null 2>&1 + git checkout -b test13 branch1 && + test_must_fail git merge master && + git mergetool --no-prompt --tool mybase -- both && + >expected && + test_cmp both expected && + git reset --hard master >/dev/null 2>&1 ' test_expect_success 'custom commands override built-ins' ' - git checkout -b test14 branch1 && - git config mergetool.defaults.cmd "cat \"\$REMOTE\" >\"\$MERGED\"" && - git config mergetool.defaults.trustExitCode true && - test_must_fail git merge master && - git mergetool --no-prompt --tool defaults -- both && - echo master both added >expected && - test_cmp both expected && - git config --unset mergetool.defaults.cmd && - git config --unset mergetool.defaults.trustExitCode && - git reset --hard master >/dev/null 2>&1 + git checkout -b test14 branch1 && + test_config mergetool.defaults.cmd "cat \"\$REMOTE\" >\"\$MERGED\"" && + test_config mergetool.defaults.trustExitCode true && + test_must_fail git merge master && + git mergetool --no-prompt --tool defaults -- both && + echo master both added >expected && + test_cmp both expected && + git reset --hard master >/dev/null 2>&1 +' + +test_expect_success 'filenames seen by tools start with ./' ' + git checkout -b test15 branch1 && + test_config mergetool.writeToTemp false && + test_config mergetool.myecho.cmd "echo \"\$LOCAL\"" && + test_config mergetool.myecho.trustExitCode true && + test_must_fail git merge master && + git mergetool --no-prompt --tool myecho -- both >actual && + grep ^\./both_LOCAL_ actual >/dev/null && + git reset --hard master >/dev/null 2>&1 +' + +test_expect_success 'temporary filenames are used with mergetool.writeToTemp' ' + git checkout -b test16 branch1 && + test_config mergetool.writeToTemp true && + test_config mergetool.myecho.cmd "echo \"\$LOCAL\"" && + test_config mergetool.myecho.trustExitCode true && + test_must_fail git merge master && + git mergetool --no-prompt --tool myecho -- both >actual && + test_must_fail grep ^\./both_LOCAL_ actual >/dev/null && + grep /both_LOCAL_ actual >/dev/null && + git reset --hard master >/dev/null 2>&1 ' test_done diff --git a/t/t7612-merge-verify-signatures.sh b/t/t7612-merge-verify-signatures.sh index 21a0bf8fb8..8ae69a61c3 100755 --- a/t/t7612-merge-verify-signatures.sh +++ b/t/t7612-merge-verify-signatures.sh @@ -29,7 +29,7 @@ test_expect_success GPG 'create signed commits' ' git checkout -b side-untrusted && echo 3 >baz && git add baz && - test_tick && git commit -SB7227189 -m "untrusted on side" + test_tick && git commit -SB7227189 -m "untrusted on side" && git checkout master ' diff --git a/t/t7613-merge-submodule.sh b/t/t7613-merge-submodule.sh new file mode 100755 index 0000000000..d1e9fcc781 --- /dev/null +++ b/t/t7613-merge-submodule.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +test_description='merge can handle submodules' + +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-submodule-update.sh + +# merges without conflicts +test_submodule_switch "git merge" + +test_submodule_switch "git merge --ff" + +test_submodule_switch "git merge --ff-only" + +KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1 +KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1 +test_submodule_switch "git merge --no-ff" + +test_done diff --git a/t/t7700-repack.sh b/t/t7700-repack.sh index 61e6ed37aa..021c5479bd 100755 --- a/t/t7700-repack.sh +++ b/t/t7700-repack.sh @@ -21,7 +21,7 @@ test_expect_success 'objects in packs marked .keep are not repacked' ' objsha1=$(git verify-pack -v pack-$packsha1.idx | head -n 1 | sed -e "s/^\([0-9a-f]\{40\}\).*/\1/") && mv pack-* .git/objects/pack/ && - git repack --no-pack-kept-objects -A -d -l && + git repack -A -d -l && git prune-packed && for p in .git/objects/pack/*.idx; do idx=$(basename $p) @@ -53,7 +53,7 @@ test_expect_success 'writing bitmaps via command-line can duplicate .keep object test_expect_success 'writing bitmaps via config can duplicate .keep objects' ' # build on $objsha1, $packsha1, and .keep state from previous - git -c pack.writebitmaps=true repack -Adl && + git -c repack.writebitmaps=true repack -Adl && test_when_finished "found_duplicate_object=" && for p in .git/objects/pack/*.idx; do idx=$(basename $p) diff --git a/t/t7701-repack-unpack-unreachable.sh b/t/t7701-repack-unpack-unreachable.sh index b8d4cdea8c..b66e383866 100755 --- a/t/t7701-repack-unpack-unreachable.sh +++ b/t/t7701-repack-unpack-unreachable.sh @@ -57,7 +57,7 @@ compare_mtimes () { read tref rest && while read t rest; do - test "$tref" = "$t" || break + test "$tref" = "$t" || return 1 done } @@ -109,4 +109,17 @@ test_expect_success 'do not bother loosening old objects' ' test_must_fail git cat-file -p $obj2 ' +test_expect_success 'keep packed objects found only in index' ' + echo my-unique-content >file && + git add file && + git commit -m "make it reachable" && + git gc && + git reset HEAD^ && + git reflog expire --expire=now --all && + git add file && + test-chmtime =-86400 .git/objects/pack/* && + git gc --prune=1.hour.ago && + git cat-file blob :file +' + test_done diff --git a/t/t7702-repack-cyclic-alternate.sh b/t/t7702-repack-cyclic-alternate.sh new file mode 100755 index 0000000000..93b74867ac --- /dev/null +++ b/t/t7702-repack-cyclic-alternate.sh @@ -0,0 +1,24 @@ +#!/bin/sh +# +# Copyright (c) 2014 Ephrim Khong +# + +test_description='repack involving cyclic alternate' +. ./test-lib.sh + +test_expect_success setup ' + GIT_OBJECT_DIRECTORY=.git//../.git/objects && + export GIT_OBJECT_DIRECTORY && + touch a && + git add a && + git commit -m 1 && + git repack -adl && + echo "$(pwd)"/.git/objects/../objects >.git/objects/info/alternates +' + +test_expect_success 're-packing repository with itsself as alternate' ' + git repack -adl && + git fsck +' + +test_done diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh index 5a193c500d..ec8bc8c765 100755 --- a/t/t7800-difftool.sh +++ b/t/t7800-difftool.sh @@ -58,7 +58,7 @@ test_expect_success PERL 'custom tool commands override built-ins' ' test_expect_success PERL 'difftool ignores bad --tool values' ' : >expect && - test_expect_code 1 \ + test_must_fail \ git difftool --no-prompt --tool=bad-tool branch >actual && test_cmp expect actual ' @@ -76,6 +76,54 @@ test_expect_success PERL 'difftool forwards arguments to diff' ' rm for-diff ' +test_expect_success PERL 'difftool ignores exit code' ' + test_config difftool.error.cmd false && + git difftool -y -t error branch +' + +test_expect_success PERL 'difftool forwards exit code with --trust-exit-code' ' + test_config difftool.error.cmd false && + test_must_fail git difftool -y --trust-exit-code -t error branch +' + +test_expect_success PERL 'difftool forwards exit code with --trust-exit-code for built-ins' ' + test_config difftool.vimdiff.path false && + test_must_fail git difftool -y --trust-exit-code -t vimdiff branch +' + +test_expect_success PERL 'difftool honors difftool.trustExitCode = true' ' + test_config difftool.error.cmd false && + test_config difftool.trustExitCode true && + test_must_fail git difftool -y -t error branch +' + +test_expect_success PERL 'difftool honors difftool.trustExitCode = false' ' + test_config difftool.error.cmd false && + test_config difftool.trustExitCode false && + git difftool -y -t error branch +' + +test_expect_success PERL 'difftool ignores exit code with --no-trust-exit-code' ' + test_config difftool.error.cmd false && + test_config difftool.trustExitCode true && + git difftool -y --no-trust-exit-code -t error branch +' + +test_expect_success PERL 'difftool stops on error with --trust-exit-code' ' + test_when_finished "rm -f for-diff .git/fail-right-file" && + test_when_finished "git reset -- for-diff" && + write_script .git/fail-right-file <<-\EOF && + echo "$2" + exit 1 + EOF + >for-diff && + git add for-diff && + echo file >expect && + test_must_fail git difftool -y --trust-exit-code \ + --extcmd .git/fail-right-file branch >actual && + test_cmp expect actual +' + test_expect_success PERL 'difftool honors --gui' ' difftool_test_setup && test_config merge.tool bogus-tool && @@ -301,6 +349,14 @@ test_expect_success PERL 'say no to the second file' ' ! grep br2 output ' +test_expect_success PERL 'ending prompt input with EOF' ' + git difftool -x cat branch </dev/null >output && + ! grep master output && + ! grep branch output && + ! grep m2 output && + ! grep br2 output +' + test_expect_success PERL 'difftool --tool-help' ' git difftool --tool-help >output && grep tool output @@ -436,12 +492,31 @@ test_expect_success PERL 'difftool --no-symlinks detects conflict ' ' test_expect_success PERL 'difftool properly honors gitlink and core.worktree' ' git submodule add ./. submod/ule && + test_config -C submod/ule diff.tool checktrees && + test_config -C submod/ule difftool.checktrees.cmd '\'' + test -d "$LOCAL" && test -d "$REMOTE" && echo good + '\'' && ( cd submod/ule && - test_config diff.tool checktrees && - test_config difftool.checktrees.cmd '\'' - test -d "$LOCAL" && test -d "$REMOTE" && echo good - '\'' && + echo good >expect && + git difftool --tool=checktrees --dir-diff HEAD~ >actual && + test_cmp expect actual + ) +' + +test_expect_success PERL,SYMLINKS 'difftool --dir-diff symlinked directories' ' + git init dirlinks && + ( + cd dirlinks && + git config diff.tool checktrees && + git config difftool.checktrees.cmd "echo good" && + mkdir foo && + : >foo/bar && + git add foo/bar && + test_commit symlink-one && + ln -s foo link && + git add link && + test_commit symlink-two && echo good >expect && git difftool --tool=checktrees --dir-diff HEAD~ >actual && test_cmp expect actual diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh index 40615debc4..028ffe4a05 100755 --- a/t/t7810-grep.sh +++ b/t/t7810-grep.sh @@ -1202,4 +1202,98 @@ test_expect_success LIBPCRE 'grep -P "^ "' ' test_cmp expected actual ' +cat >expected <<EOF +space-line without leading space1 +space: line <RED>with <RESET>leading space1 +space: line <RED>with <RESET>leading <RED>space2<RESET> +space: line <RED>with <RESET>leading space3 +space:line without leading <RED>space2<RESET> +EOF + +test_expect_success 'grep --color -e A -e B with context' ' + test_config color.grep.context normal && + test_config color.grep.filename normal && + test_config color.grep.function normal && + test_config color.grep.linenumber normal && + test_config color.grep.matchContext normal && + test_config color.grep.matchSelected red && + test_config color.grep.selected normal && + test_config color.grep.separator normal && + + git grep --color=always -C2 -e "with " -e space2 space | + test_decode_color >actual && + test_cmp expected actual +' + +cat >expected <<EOF +space-line without leading space1 +space- line with leading space1 +space: line <RED>with <RESET>leading <RED>space2<RESET> +space- line with leading space3 +space-line without leading space2 +EOF + +test_expect_success 'grep --color -e A --and -e B with context' ' + test_config color.grep.context normal && + test_config color.grep.filename normal && + test_config color.grep.function normal && + test_config color.grep.linenumber normal && + test_config color.grep.matchContext normal && + test_config color.grep.matchSelected red && + test_config color.grep.selected normal && + test_config color.grep.separator normal && + + git grep --color=always -C2 -e "with " --and -e space2 space | + test_decode_color >actual && + test_cmp expected actual +' + +cat >expected <<EOF +space-line without leading space1 +space: line <RED>with <RESET>leading space1 +space- line with leading space2 +space: line <RED>with <RESET>leading space3 +space-line without leading space2 +EOF + +test_expect_success 'grep --color -e A --and --not -e B with context' ' + test_config color.grep.context normal && + test_config color.grep.filename normal && + test_config color.grep.function normal && + test_config color.grep.linenumber normal && + test_config color.grep.matchContext normal && + test_config color.grep.matchSelected red && + test_config color.grep.selected normal && + test_config color.grep.separator normal && + + git grep --color=always -C2 -e "with " --and --not -e space2 space | + test_decode_color >actual && + test_cmp expected actual +' + +cat >expected <<EOF +hello.c-#include <stdio.h> +hello.c=int main(int argc, const char **argv) +hello.c-{ +hello.c: pr<RED>int<RESET>f("<RED>Hello<RESET> world.\n"); +hello.c- return 0; +hello.c- /* char ?? */ +hello.c-} +EOF + +test_expect_success 'grep --color -e A --and -e B -p with context' ' + test_config color.grep.context normal && + test_config color.grep.filename normal && + test_config color.grep.function normal && + test_config color.grep.linenumber normal && + test_config color.grep.matchContext normal && + test_config color.grep.matchSelected red && + test_config color.grep.selected normal && + test_config color.grep.separator normal && + + git grep --color=always -p -C3 -e int --and -e Hello --no-index hello.c | + test_decode_color >actual && + test_cmp expected actual +' + test_done diff --git a/t/t8002-blame.sh b/t/t8002-blame.sh index 5cdf3f178e..ff09aced68 100755 --- a/t/t8002-blame.sh +++ b/t/t8002-blame.sh @@ -19,4 +19,66 @@ test_expect_success 'blame --show-email' ' "<E at test dot git>" 1 ' +test_expect_success 'setup showEmail tests' ' + echo "bin: test number 1" >one && + git add one && + GIT_AUTHOR_NAME=name1 \ + GIT_AUTHOR_EMAIL=email1@test.git \ + git commit -m First --date="2010-01-01 01:00:00" && + cat >expected_n <<-\EOF && + (name1 2010-01-01 01:00:00 +0000 1) bin: test number 1 + EOF + cat >expected_e <<-\EOF + (<email1@test.git> 2010-01-01 01:00:00 +0000 1) bin: test number 1 + EOF +' + +find_blame () { + sed -e 's/^[^(]*//' +} + +test_expect_success 'blame with no options and no config' ' + git blame one >blame && + find_blame <blame >result && + test_cmp expected_n result +' + +test_expect_success 'blame with showemail options' ' + git blame --show-email one >blame1 && + find_blame <blame1 >result && + test_cmp expected_e result && + git blame -e one >blame2 && + find_blame <blame2 >result && + test_cmp expected_e result && + git blame --no-show-email one >blame3 && + find_blame <blame3 >result && + test_cmp expected_n result +' + +test_expect_success 'blame with showEmail config false' ' + git config blame.showEmail false && + git blame one >blame1 && + find_blame <blame1 >result && + test_cmp expected_n result && + git blame --show-email one >blame2 && + find_blame <blame2 >result && + test_cmp expected_e result && + git blame -e one >blame3 && + find_blame <blame3 >result && + test_cmp expected_e result && + git blame --no-show-email one >blame4 && + find_blame <blame4 >result && + test_cmp expected_n result +' + +test_expect_success 'blame with showEmail config true' ' + git config blame.showEmail true && + git blame one >blame1 && + find_blame <blame1 >result && + test_cmp expected_e result && + git blame --no-show-email one >blame2 && + find_blame <blame2 >result && + test_cmp expected_n result +' + test_done diff --git a/t/t8003-blame-corner-cases.sh b/t/t8003-blame-corner-cases.sh index 2a3469bcbe..16f1442c1e 100755 --- a/t/t8003-blame-corner-cases.sh +++ b/t/t8003-blame-corner-cases.sh @@ -26,7 +26,7 @@ test_expect_success setup ' cat one >uno && mv two dos && cat one >>tres && - echo DEF >>mouse + echo DEF >>mouse && git add uno dos tres mouse && test_tick && GIT_AUTHOR_NAME=Second git commit -a -m Second && @@ -153,15 +153,15 @@ test_expect_success 'blame path that used to be a directory' ' ' test_expect_success 'blame to a commit with no author name' ' - TREE=`git rev-parse HEAD:` - cat >badcommit <<EOF + TREE=`git rev-parse HEAD:` && + cat >badcommit <<EOF && tree $TREE author <noname> 1234567890 +0000 committer David Reiss <dreiss@facebook.com> 1234567890 +0000 some message EOF - COMMIT=`git hash-object -t commit -w badcommit` + COMMIT=`git hash-object -t commit -w badcommit` && git --no-pager blame $COMMIT -- uno >/dev/null ' @@ -191,12 +191,24 @@ test_expect_success 'indent of line numbers, ten lines' ' test $(grep -c " " actual) = 9 ' -test_expect_success 'blaming files with CRLF newlines' ' +test_expect_success 'setup file with CRLF newlines' ' git config core.autocrlf false && - printf "testcase\r\n" >crlffile && + printf "testcase\n" >crlffile && git add crlffile && git commit -m testcase && - git -c core.autocrlf=input blame crlffile >actual && + printf "testcase\r\n" >crlffile +' + +test_expect_success 'blame file with CRLF core.autocrlf true' ' + git config core.autocrlf true && + git blame crlffile >actual && + grep "A U Thor" actual +' + +test_expect_success 'blame file with CRLF attributes text' ' + git config core.autocrlf false && + echo "crlffile text" >.gitattributes && + git blame crlffile >actual && grep "A U Thor" actual ' diff --git a/t/t8005-blame-i18n.sh b/t/t8005-blame-i18n.sh index cb390559f9..847d098c09 100755 --- a/t/t8005-blame-i18n.sh +++ b/t/t8005-blame-i18n.sh @@ -33,7 +33,7 @@ author $SJIS_NAME summary $SJIS_MSG EOF -test_expect_success \ +test_expect_success !MINGW \ 'blame respects i18n.commitencoding' ' git blame --incremental file | \ egrep "^(author|summary) " > actual && @@ -49,7 +49,7 @@ author $EUC_JAPAN_NAME summary $EUC_JAPAN_MSG EOF -test_expect_success \ +test_expect_success !MINGW \ 'blame respects i18n.logoutputencoding' ' git config i18n.logoutputencoding eucJP && git blame --incremental file | \ @@ -66,7 +66,7 @@ author $UTF8_NAME summary $UTF8_MSG EOF -test_expect_success \ +test_expect_success !MINGW \ 'blame respects --encoding=UTF-8' ' git blame --incremental --encoding=UTF-8 file | \ egrep "^(author|summary) " > actual && @@ -82,7 +82,7 @@ author $UTF8_NAME summary $UTF8_MSG EOF -test_expect_success \ +test_expect_success !MINGW \ 'blame respects --encoding=none' ' git blame --incremental --encoding=none file | \ egrep "^(author|summary) " > actual && diff --git a/t/t8008-blame-formats.sh b/t/t8008-blame-formats.sh index d15f8b3d47..29f84a6dd1 100755 --- a/t/t8008-blame-formats.sh +++ b/t/t8008-blame-formats.sh @@ -5,7 +5,7 @@ test_description='blame output in various formats on a simple case' test_expect_success 'setup' ' echo a >file && - git add file + git add file && test_tick && git commit -m one && echo b >>file && diff --git a/t/t8009-blame-vs-topicbranches.sh b/t/t8009-blame-vs-topicbranches.sh new file mode 100755 index 0000000000..72596e38b2 --- /dev/null +++ b/t/t8009-blame-vs-topicbranches.sh @@ -0,0 +1,36 @@ +#!/bin/sh + +test_description='blaming trough history with topic branches' +. ./test-lib.sh + +# Creates the history shown below. '*'s mark the first parent in the merges. +# The only line of file.t is changed in commit B2 +# +# +---C1 +# / \ +# A0--A1--*A2--*A3 +# \ / +# B1-B2 +# +test_expect_success setup ' + test_commit A0 file.t line0 && + test_commit A1 && + git reset --hard A0 && + test_commit B1 && + test_commit B2 file.t line0changed && + git reset --hard A1 && + test_merge A2 B2 && + git reset --hard A1 && + test_commit C1 && + git reset --hard A2 && + test_merge A3 C1 + ' + +test_expect_success 'blame --reverse --first-parent finds A1' ' + git blame --porcelain --reverse --first-parent A0..A3 -- file.t >actual_full && + head -n 1 <actual_full | sed -e "s/ .*//" >actual && + git rev-parse A1 >expect && + test_cmp expect actual + ' + +test_done diff --git a/t/t9000-addresses.sh b/t/t9000-addresses.sh new file mode 100755 index 0000000000..a1ebef6de2 --- /dev/null +++ b/t/t9000-addresses.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +test_description='compare address parsing with and without Mail::Address' +. ./test-lib.sh + +if ! test_have_prereq PERL; then + skip_all='skipping perl interface tests, perl not available' + test_done +fi + +perl -MTest::More -e 0 2>/dev/null || { + skip_all="Perl Test::More unavailable, skipping test" + test_done +} + +perl -MMail::Address -e 0 2>/dev/null || { + skip_all="Perl Mail::Address unavailable, skipping test" + test_done +} + +test_external_has_tap=1 + +test_external_without_stderr \ + 'Perl address parsing function' \ + perl "$TEST_DIRECTORY"/t9000/test.pl + +test_done diff --git a/t/t9000/test.pl b/t/t9000/test.pl new file mode 100755 index 0000000000..2d05d3eeab --- /dev/null +++ b/t/t9000/test.pl @@ -0,0 +1,67 @@ +#!/usr/bin/perl +use lib (split(/:/, $ENV{GITPERLLIB})); + +use 5.008; +use warnings; +use strict; + +use Test::More qw(no_plan); +use Mail::Address; + +BEGIN { use_ok('Git') } + +my @success_list = (q[Jane], + q[jdoe@example.com], + q[<jdoe@example.com>], + q[Jane <jdoe@example.com>], + q[Jane Doe <jdoe@example.com>], + q["Jane" <jdoe@example.com>], + q["Doe, Jane" <jdoe@example.com>], + q["Jane@:;\>.,()<Doe" <jdoe@example.com>], + q[Jane!#$%&'*+-/=?^_{|}~Doe' <jdoe@example.com>], + q["<jdoe@example.com>"], + q["Jane jdoe@example.com"], + q[Jane Doe <jdoe @ example.com >], + q[Jane Doe < jdoe@example.com >], + q[Jane @ Doe @ Jane @ Doe], + q["Jane, 'Doe'" <jdoe@example.com>], + q['Doe, "Jane' <jdoe@example.com>], + q["Jane" "Do"e <jdoe@example.com>], + q["Jane' Doe" <jdoe@example.com>], + q["Jane Doe <jdoe@example.com>" <jdoe@example.com>], + q["Jane\" Doe" <jdoe@example.com>], + q[Doe, jane <jdoe@example.com>], + q["Jane Doe <jdoe@example.com>], + q['Jane 'Doe' <jdoe@example.com>]); + +my @known_failure_list = (q[Jane\ Doe <jdoe@example.com>], + q["Doe, Ja"ne <jdoe@example.com>], + q["Doe, Katarina" Jane <jdoe@example.com>], + q[Jane@:;\.,()<>Doe <jdoe@example.com>], + q[Jane jdoe@example.com], + q[<jdoe@example.com> Jane Doe], + q[Jane <jdoe@example.com> Doe], + q["Jane "Kat"a" ri"na" ",Doe" <jdoe@example.com>], + q[Jane Doe], + q[Jane "Doe <jdoe@example.com>"], + q[\"Jane Doe <jdoe@example.com>], + q[Jane\"\" Doe <jdoe@example.com>], + q['Jane "Katarina\" \' Doe' <jdoe@example.com>]); + +foreach my $str (@success_list) { + my @expected = map { $_->format } Mail::Address->parse("$str"); + my @actual = Git::parse_mailboxes("$str"); + is_deeply(\@expected, \@actual, qq[same output : $str]); +} + +TODO: { + local $TODO = "known breakage"; + foreach my $str (@known_failure_list) { + my @expected = map { $_->format } Mail::Address->parse("$str"); + my @actual = Git::parse_mailboxes("$str"); + is_deeply(\@expected, \@actual, qq[same output : $str]); + } +} + +my $is_passing = eval { Test::More->is_passing }; +exit($is_passing ? 0 : 1) unless $@ =~ /Can't locate object method/; diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index 1ecdacb6fd..834d91a691 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -6,35 +6,37 @@ test_description='git send-email' # May be altered later in the test PREREQ="PERL" -test_expect_success $PREREQ \ - 'prepare reference tree' \ - 'echo "1A quick brown fox jumps over the" >file && - echo "lazy dog" >>file && - git add file && - GIT_AUTHOR_NAME="A" git commit -a -m "Initial."' - -test_expect_success $PREREQ \ - 'Setup helper tool' \ - '(echo "#!$SHELL_PATH" - echo shift - echo output=1 - echo "while test -f commandline\$output; do output=\$((\$output+1)); done" - echo for a - echo do - echo " echo \"!\$a!\"" - echo "done >commandline\$output" - echo "cat > msgtxt\$output" - ) >fake.sendmail && - chmod +x ./fake.sendmail && - git add fake.sendmail && - GIT_AUTHOR_NAME="A" git commit -a -m "Second."' - -clean_fake_sendmail() { +test_expect_success $PREREQ 'prepare reference tree' ' + echo "1A quick brown fox jumps over the" >file && + echo "lazy dog" >>file && + git add file && + GIT_AUTHOR_NAME="A" git commit -a -m "Initial." +' + +test_expect_success $PREREQ 'Setup helper tool' ' + write_script fake.sendmail <<-\EOF && + shift + output=1 + while test -f commandline$output + do + output=$(($output+1)) + done + for a + do + echo "!$a!" + done >commandline$output + cat >"msgtxt$output" + EOF + git add fake.sendmail && + GIT_AUTHOR_NAME="A" git commit -a -m "Second." +' + +clean_fake_sendmail () { rm -f commandline* msgtxt* } test_expect_success $PREREQ 'Extract patches' ' - patches=`git format-patch -s --cc="One <one@example.com>" --cc=two@example.com -n HEAD^1` + patches=`git format-patch -s --cc="One <one@example.com>" --cc=two@example.com -n HEAD^1` ' # Test no confirm early to ensure remaining tests will not hang @@ -47,9 +49,9 @@ test_no_confirm () { --to=nobody@example.com \ --smtp-server="$(pwd)/fake.sendmail" \ $@ \ - $patches > stdout && + $patches >stdout && test_must_fail grep "Send this email" stdout && - > no_confirm_okay + >no_confirm_okay } # Exit immediately to prevent hang if a no-confirm test fails @@ -82,61 +84,61 @@ test_expect_success $PREREQ 'No confirm with sendemail.confirm=never' ' ' test_expect_success $PREREQ 'Send patches' ' - git send-email --suppress-cc=sob --from="Example <nobody@example.com>" --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors + git send-email --suppress-cc=sob --from="Example <nobody@example.com>" --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors ' test_expect_success $PREREQ 'setup expect' ' -cat >expected <<\EOF -!nobody@example.com! -!author@example.com! -!one@example.com! -!two@example.com! -EOF + cat >expected <<-\EOF + !nobody@example.com! + !author@example.com! + !one@example.com! + !two@example.com! + EOF ' -test_expect_success $PREREQ \ - 'Verify commandline' \ - 'test_cmp expected commandline1' +test_expect_success $PREREQ 'Verify commandline' ' + test_cmp expected commandline1 +' test_expect_success $PREREQ 'Send patches with --envelope-sender' ' - clean_fake_sendmail && - git send-email --envelope-sender="Patch Contributor <patch@example.com>" --suppress-cc=sob --from="Example <nobody@example.com>" --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors + clean_fake_sendmail && + git send-email --envelope-sender="Patch Contributor <patch@example.com>" --suppress-cc=sob --from="Example <nobody@example.com>" --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors ' test_expect_success $PREREQ 'setup expect' ' -cat >expected <<\EOF -!patch@example.com! -!-i! -!nobody@example.com! -!author@example.com! -!one@example.com! -!two@example.com! -EOF + cat >expected <<-\EOF + !patch@example.com! + !-i! + !nobody@example.com! + !author@example.com! + !one@example.com! + !two@example.com! + EOF ' -test_expect_success $PREREQ \ - 'Verify commandline' \ - 'test_cmp expected commandline1' +test_expect_success $PREREQ 'Verify commandline' ' + test_cmp expected commandline1 +' test_expect_success $PREREQ 'Send patches with --envelope-sender=auto' ' - clean_fake_sendmail && - git send-email --envelope-sender=auto --suppress-cc=sob --from="Example <nobody@example.com>" --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors + clean_fake_sendmail && + git send-email --envelope-sender=auto --suppress-cc=sob --from="Example <nobody@example.com>" --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors ' test_expect_success $PREREQ 'setup expect' ' -cat >expected <<\EOF -!nobody@example.com! -!-i! -!nobody@example.com! -!author@example.com! -!one@example.com! -!two@example.com! -EOF + cat >expected <<-\EOF + !nobody@example.com! + !-i! + !nobody@example.com! + !author@example.com! + !one@example.com! + !two@example.com! + EOF ' -test_expect_success $PREREQ \ - 'Verify commandline' \ - 'test_cmp expected commandline1' +test_expect_success $PREREQ 'Verify commandline' ' + test_cmp expected commandline1 +' test_expect_success $PREREQ 'setup expect' " cat >expected-show-all-headers <<\EOF @@ -240,6 +242,13 @@ test_expect_success $PREREQ 'non-ascii self name is suppressed' " 'non_ascii_self_suppressed' " +# This name is long enough to force format-patch to split it into multiple +# encoded-words, assuming it uses UTF-8 with the "Q" encoding. +test_expect_success $PREREQ 'long non-ascii self name is suppressed' " + test_suppress_self_quoted 'Ƒüñníęř €. Nâṁé' 'odd_?=mail@example.com' \ + 'long_non_ascii_self_suppressed' +" + test_expect_success $PREREQ 'sanitized self name is suppressed' " test_suppress_self_unquoted '\"A U. Thor\"' 'author@example.com' \ 'self_name_sanitized_suppressed' @@ -303,15 +312,19 @@ test_expect_success $PREREQ,!AUTOIDENT 'broken implicit ident aborts send-email' ) ' +test_expect_success $PREREQ 'setup tocmd and cccmd scripts' ' + write_script tocmd-sed <<-\EOF && + sed -n -e "s/^tocmd--//p" "$1" + EOF + write_script cccmd-sed <<-\EOF + sed -n -e "s/^cccmd--//p" "$1" + EOF +' + test_expect_success $PREREQ 'tocmd works' ' clean_fake_sendmail && cp $patches tocmd.patch && echo tocmd--tocmd@example.com >>tocmd.patch && - { - echo "#!$SHELL_PATH" - echo sed -n -e s/^tocmd--//p \"\$1\" - } > tocmd-sed && - chmod +x tocmd-sed && git send-email \ --from="Example <nobody@example.com>" \ --to-cmd=./tocmd-sed \ @@ -325,11 +338,6 @@ test_expect_success $PREREQ 'cccmd works' ' clean_fake_sendmail && cp $patches cccmd.patch && echo "cccmd-- cccmd@example.com" >>cccmd.patch && - { - echo "#!$SHELL_PATH" - echo sed -n -e s/^cccmd--//p \"\$1\" - } > cccmd-sed && - chmod +x cccmd-sed && git send-email \ --from="Example <nobody@example.com>" \ --to=nobody@example.com \ @@ -367,7 +375,7 @@ test_expect_success $PREREQ 'Author From: in message body' ' --to=nobody@example.com \ --smtp-server="$(pwd)/fake.sendmail" \ $patches && - sed "1,/^\$/d" < msgtxt1 > msgbody1 && + sed "1,/^\$/d" <msgtxt1 >msgbody1 && grep "From: A <author@example.com>" msgbody1 ' @@ -378,7 +386,7 @@ test_expect_success $PREREQ 'Author From: not in message body' ' --to=nobody@example.com \ --smtp-server="$(pwd)/fake.sendmail" \ $patches && - sed "1,/^\$/d" < msgtxt1 > msgbody1 && + sed "1,/^\$/d" <msgtxt1 >msgbody1 && ! grep "From: A <author@example.com>" msgbody1 ' @@ -387,7 +395,7 @@ test_expect_success $PREREQ 'allow long lines with --no-validate' ' --from="Example <nobody@example.com>" \ --to=nobody@example.com \ --smtp-server="$(pwd)/fake.sendmail" \ - --novalidate \ + --no-validate \ $patches longline.patch \ 2>errors ' @@ -421,7 +429,7 @@ test_expect_success $PREREQ 'In-Reply-To without --chain-reply-to' ' git send-email \ --from="Example <nobody@example.com>" \ --to=nobody@example.com \ - --nochain-reply-to \ + --no-chain-reply-to \ --in-reply-to="$(cat expect)" \ --smtp-server="$(pwd)/fake.sendmail" \ $patches $patches $patches \ @@ -459,10 +467,9 @@ test_expect_success $PREREQ 'In-Reply-To with --chain-reply-to' ' ' test_expect_success $PREREQ 'setup fake editor' ' - (echo "#!$SHELL_PATH" && - echo "echo fake edit >>\"\$1\"" - ) >fake-editor && - chmod +x fake-editor + write_script fake-editor <<-\EOF + echo fake edit >>"$1" + EOF ' test_set_editor "$(pwd)/fake-editor" @@ -515,6 +522,12 @@ Result: OK EOF " +replace_variable_fields () { + sed -e "s/^\(Date:\).*/\1 DATE-STRING/" \ + -e "s/^\(Message-Id:\).*/\1 MESSAGE-ID-STRING/" \ + -e "s/^\(X-Mailer:\).*/\1 X-MAILER-STRING/" +} + test_suppression () { git send-email \ --dry-run \ @@ -522,10 +535,7 @@ test_suppression () { --from="Example <from@example.com>" \ --to=to@example.com \ --smtp-server relay.example.com \ - $patches | - sed -e "s/^\(Date:\).*/\1 DATE-STRING/" \ - -e "s/^\(Message-Id:\).*/\1 MESSAGE-ID-STRING/" \ - -e "s/^\(X-Mailer:\).*/\1 X-MAILER-STRING/" \ + $patches | replace_variable_fields \ >actual-suppress-$1${2+"-$2"} && test_cmp expected-suppress-$1${2+"-$2"} actual-suppress-$1${2+"-$2"} } @@ -598,8 +608,9 @@ EOF " test_expect_success $PREREQ 'sendemail.cccmd' ' - echo echo cc-cmd@example.com > cccmd && - chmod +x cccmd && + write_script cccmd <<-\EOF && + echo cc-cmd@example.com + EOF git config sendemail.cccmd ./cccmd && test_suppression cccmd ' @@ -792,7 +803,7 @@ test_confirm () { --from="Example <nobody@example.com>" \ --to=nobody@example.com \ --smtp-server="$(pwd)/fake.sendmail" \ - $@ $patches > stdout && + $@ $patches >stdout && grep "Send this email" stdout } @@ -813,25 +824,19 @@ test_expect_success $PREREQ '--confirm=compose' ' ' test_expect_success $PREREQ 'confirm by default (due to cc)' ' - CONFIRM=$(git config --get sendemail.confirm) && + test_when_finished git config sendemail.confirm never && git config --unset sendemail.confirm && test_confirm - ret="$?" - git config sendemail.confirm ${CONFIRM:-never} - test $ret = "0" ' test_expect_success $PREREQ 'confirm by default (due to --compose)' ' - CONFIRM=$(git config --get sendemail.confirm) && + test_when_finished git config sendemail.confirm never && git config --unset sendemail.confirm && test_confirm --suppress-cc=all --compose - ret="$?" - git config sendemail.confirm ${CONFIRM:-never} - test $ret = "0" ' test_expect_success $PREREQ 'confirm detects EOF (inform assumes y)' ' - CONFIRM=$(git config --get sendemail.confirm) && + test_when_finished git config sendemail.confirm never && git config --unset sendemail.confirm && rm -fr outdir && git format-patch -2 -o outdir && @@ -840,14 +845,11 @@ test_expect_success $PREREQ 'confirm detects EOF (inform assumes y)' ' --from="Example <nobody@example.com>" \ --to=nobody@example.com \ --smtp-server="$(pwd)/fake.sendmail" \ - outdir/*.patch < /dev/null - ret="$?" - git config sendemail.confirm ${CONFIRM:-never} - test $ret = "0" + outdir/*.patch </dev/null ' test_expect_success $PREREQ 'confirm detects EOF (auto causes failure)' ' - CONFIRM=$(git config --get sendemail.confirm) && + test_when_finished git config sendemail.confirm never && git config sendemail.confirm auto && GIT_SEND_EMAIL_NOTTY=1 && export GIT_SEND_EMAIL_NOTTY && @@ -855,14 +857,11 @@ test_expect_success $PREREQ 'confirm detects EOF (auto causes failure)' ' --from="Example <nobody@example.com>" \ --to=nobody@example.com \ --smtp-server="$(pwd)/fake.sendmail" \ - $patches < /dev/null - ret="$?" - git config sendemail.confirm ${CONFIRM:-never} - test $ret = "0" + $patches </dev/null ' test_expect_success $PREREQ 'confirm does not loop forever' ' - CONFIRM=$(git config --get sendemail.confirm) && + test_when_finished git config sendemail.confirm never && git config sendemail.confirm auto && GIT_SEND_EMAIL_NOTTY=1 && export GIT_SEND_EMAIL_NOTTY && @@ -871,9 +870,6 @@ test_expect_success $PREREQ 'confirm does not loop forever' ' --to=nobody@example.com \ --smtp-server="$(pwd)/fake.sendmail" \ $patches - ret="$?" - git config sendemail.confirm ${CONFIRM:-never} - test $ret = "0" ' test_expect_success $PREREQ 'utf8 Cc is rfc2047 encoded' ' @@ -891,39 +887,39 @@ test_expect_success $PREREQ 'utf8 Cc is rfc2047 encoded' ' test_expect_success $PREREQ '--compose adds MIME for utf8 body' ' clean_fake_sendmail && - (echo "#!$SHELL_PATH" && - echo "echo utf8 body: àéìöú >>\"\$1\"" - ) >fake-editor-utf8 && - chmod +x fake-editor-utf8 && - GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \ - git send-email \ - --compose --subject foo \ - --from="Example <nobody@example.com>" \ - --to=nobody@example.com \ - --smtp-server="$(pwd)/fake.sendmail" \ - $patches && + write_script fake-editor-utf8 <<-\EOF && + echo "utf8 body: àéìöú" >>"$1" + EOF + GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \ + git send-email \ + --compose --subject foo \ + --from="Example <nobody@example.com>" \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + $patches && grep "^utf8 body" msgtxt1 && grep "^Content-Type: text/plain; charset=UTF-8" msgtxt1 ' test_expect_success $PREREQ '--compose respects user mime type' ' clean_fake_sendmail && - (echo "#!$SHELL_PATH" && - echo "(echo MIME-Version: 1.0" - echo " echo Content-Type: text/plain\\; charset=iso-8859-1" - echo " echo Content-Transfer-Encoding: 8bit" - echo " echo Subject: foo" - echo " echo " - echo " echo utf8 body: àéìöú) >\"\$1\"" - ) >fake-editor-utf8-mime && - chmod +x fake-editor-utf8-mime && - GIT_EDITOR="\"$(pwd)/fake-editor-utf8-mime\"" \ - git send-email \ - --compose --subject foo \ - --from="Example <nobody@example.com>" \ - --to=nobody@example.com \ - --smtp-server="$(pwd)/fake.sendmail" \ - $patches && + write_script fake-editor-utf8-mime <<-\EOF && + cat >"$1" <<-\EOM + MIME-Version: 1.0 + Content-Type: text/plain; charset=iso-8859-1 + Content-Transfer-Encoding: 8bit + Subject: foo + + utf8 body: àéìöú + EOM + EOF + GIT_EDITOR="\"$(pwd)/fake-editor-utf8-mime\"" \ + git send-email \ + --compose --subject foo \ + --from="Example <nobody@example.com>" \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + $patches && grep "^utf8 body" msgtxt1 && grep "^Content-Type: text/plain; charset=iso-8859-1" msgtxt1 && ! grep "^Content-Type: text/plain; charset=UTF-8" msgtxt1 @@ -931,13 +927,13 @@ test_expect_success $PREREQ '--compose respects user mime type' ' test_expect_success $PREREQ '--compose adds MIME for utf8 subject' ' clean_fake_sendmail && - GIT_EDITOR="\"$(pwd)/fake-editor\"" \ - git send-email \ - --compose --subject utf8-sübjëct \ - --from="Example <nobody@example.com>" \ - --to=nobody@example.com \ - --smtp-server="$(pwd)/fake.sendmail" \ - $patches && + GIT_EDITOR="\"$(pwd)/fake-editor\"" \ + git send-email \ + --compose --subject utf8-sübjëct \ + --from="Example <nobody@example.com>" \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + $patches && grep "^fake edit" msgtxt1 && grep "^Subject: =?UTF-8?q?utf8-s=C3=BCbj=C3=ABct?=" msgtxt1 ' @@ -949,9 +945,9 @@ test_expect_success $PREREQ 'utf8 author is correctly passed on' ' git commit --amend --author "Füñný Nâmé <odd_?=mail@example.com>" && git format-patch --stdout -1 >funny_name.patch && git send-email --from="Example <nobody@example.com>" \ - --to=nobody@example.com \ - --smtp-server="$(pwd)/fake.sendmail" \ - funny_name.patch && + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + funny_name.patch && grep "^From: Füñný Nâmé <odd_?=mail@example.com>" msgtxt1 ' @@ -962,9 +958,9 @@ test_expect_success $PREREQ 'utf8 sender is not duplicated' ' git commit --amend --author "Füñný Nâmé <odd_?=mail@example.com>" && git format-patch --stdout -1 >funny_name.patch && git send-email --from="Füñný Nâmé <odd_?=mail@example.com>" \ - --to=nobody@example.com \ - --smtp-server="$(pwd)/fake.sendmail" \ - funny_name.patch && + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + funny_name.patch && grep "^From: " msgtxt1 >msgfrom && test_line_count = 1 msgfrom ' @@ -972,35 +968,33 @@ test_expect_success $PREREQ 'utf8 sender is not duplicated' ' test_expect_success $PREREQ 'sendemail.composeencoding works' ' clean_fake_sendmail && git config sendemail.composeencoding iso-8859-1 && - (echo "#!$SHELL_PATH" && - echo "echo utf8 body: àéìöú >>\"\$1\"" - ) >fake-editor-utf8 && - chmod +x fake-editor-utf8 && - GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \ - git send-email \ - --compose --subject foo \ - --from="Example <nobody@example.com>" \ - --to=nobody@example.com \ - --smtp-server="$(pwd)/fake.sendmail" \ - $patches && + write_script fake-editor-utf8 <<-\EOF && + echo "utf8 body: àéìöú" >>"$1" + EOF + GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \ + git send-email \ + --compose --subject foo \ + --from="Example <nobody@example.com>" \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + $patches && grep "^utf8 body" msgtxt1 && grep "^Content-Type: text/plain; charset=iso-8859-1" msgtxt1 ' test_expect_success $PREREQ '--compose-encoding works' ' clean_fake_sendmail && - (echo "#!$SHELL_PATH" && - echo "echo utf8 body: àéìöú >>\"\$1\"" - ) >fake-editor-utf8 && - chmod +x fake-editor-utf8 && - GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \ - git send-email \ - --compose-encoding iso-8859-1 \ - --compose --subject foo \ - --from="Example <nobody@example.com>" \ - --to=nobody@example.com \ - --smtp-server="$(pwd)/fake.sendmail" \ - $patches && + write_script fake-editor-utf8 <<-\EOF && + echo "utf8 body: àéìöú" >>"$1" + EOF + GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \ + git send-email \ + --compose-encoding iso-8859-1 \ + --compose --subject foo \ + --from="Example <nobody@example.com>" \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + $patches && grep "^utf8 body" msgtxt1 && grep "^Content-Type: text/plain; charset=iso-8859-1" msgtxt1 ' @@ -1008,38 +1002,37 @@ test_expect_success $PREREQ '--compose-encoding works' ' test_expect_success $PREREQ '--compose-encoding overrides sendemail.composeencoding' ' clean_fake_sendmail && git config sendemail.composeencoding iso-8859-1 && - (echo "#!$SHELL_PATH" && - echo "echo utf8 body: àéìöú >>\"\$1\"" - ) >fake-editor-utf8 && - chmod +x fake-editor-utf8 && - GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \ - git send-email \ - --compose-encoding iso-8859-2 \ - --compose --subject foo \ - --from="Example <nobody@example.com>" \ - --to=nobody@example.com \ - --smtp-server="$(pwd)/fake.sendmail" \ - $patches && + write_script fake-editor-utf8 <<-\EOF && + echo "utf8 body: àéìöú" >>"$1" + EOF + GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \ + git send-email \ + --compose-encoding iso-8859-2 \ + --compose --subject foo \ + --from="Example <nobody@example.com>" \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + $patches && grep "^utf8 body" msgtxt1 && grep "^Content-Type: text/plain; charset=iso-8859-2" msgtxt1 ' test_expect_success $PREREQ '--compose-encoding adds correct MIME for subject' ' clean_fake_sendmail && - GIT_EDITOR="\"$(pwd)/fake-editor\"" \ - git send-email \ - --compose-encoding iso-8859-2 \ - --compose --subject utf8-sübjëct \ - --from="Example <nobody@example.com>" \ - --to=nobody@example.com \ - --smtp-server="$(pwd)/fake.sendmail" \ - $patches && + GIT_EDITOR="\"$(pwd)/fake-editor\"" \ + git send-email \ + --compose-encoding iso-8859-2 \ + --compose --subject utf8-sübjëct \ + --from="Example <nobody@example.com>" \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + $patches && grep "^fake edit" msgtxt1 && grep "^Subject: =?iso-8859-2?q?utf8-s=C3=BCbj=C3=ABct?=" msgtxt1 ' test_expect_success $PREREQ 'detects ambiguous reference/file conflict' ' - echo master > master && + echo master >master && git add master && git commit -m"add master" && test_must_fail git send-email --dry-run master 2>errors && @@ -1050,10 +1043,10 @@ test_expect_success $PREREQ 'feed two files' ' rm -fr outdir && git format-patch -2 -o outdir && git send-email \ - --dry-run \ - --from="Example <nobody@example.com>" \ - --to=nobody@example.com \ - outdir/000?-*.patch 2>errors >out && + --dry-run \ + --from="Example <nobody@example.com>" \ + --to=nobody@example.com \ + outdir/000?-*.patch 2>errors >out && grep "^Subject: " out >subjects && test "z$(sed -n -e 1p subjects)" = "zSubject: [PATCH 1/2] Second." && test "z$(sed -n -e 2p subjects)" = "zSubject: [PATCH 2/2] add master" @@ -1065,7 +1058,7 @@ test_expect_success $PREREQ 'in-reply-to but no threading' ' --from="Example <nobody@example.com>" \ --to=nobody@example.com \ --in-reply-to="<in-reply-id@example.com>" \ - --nothread \ + --no-thread \ $patches | grep "In-Reply-To: <in-reply-id@example.com>" ' @@ -1075,7 +1068,7 @@ test_expect_success $PREREQ 'no in-reply-to and no threading' ' --dry-run \ --from="Example <nobody@example.com>" \ --to=nobody@example.com \ - --nothread \ + --no-thread \ $patches $patches >stdout && ! grep "In-Reply-To: " stdout ' @@ -1086,7 +1079,7 @@ test_expect_success $PREREQ 'threading but no chain-reply-to' ' --from="Example <nobody@example.com>" \ --to=nobody@example.com \ --thread \ - --nochain-reply-to \ + --no-chain-reply-to \ $patches $patches >stdout && grep "In-Reply-To: " stdout ' @@ -1197,7 +1190,7 @@ test_expect_success $PREREQ 'To headers from files reset each patch' ' ' test_expect_success $PREREQ 'setup expect' ' -cat >email-using-8bit <<EOF +cat >email-using-8bit <<\EOF From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001 Message-Id: <bogus-message-id@example.com> From: author@example.com @@ -1209,9 +1202,7 @@ EOF ' test_expect_success $PREREQ 'setup expect' ' -cat >expected <<EOF -Subject: subject goes here -EOF + echo "Subject: subject goes here" >expected ' test_expect_success $PREREQ 'ASCII subject is not RFC2047 quoted' ' @@ -1226,11 +1217,11 @@ test_expect_success $PREREQ 'ASCII subject is not RFC2047 quoted' ' ' test_expect_success $PREREQ 'setup expect' ' -cat >content-type-decl <<EOF -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit -EOF + cat >content-type-decl <<-\EOF + MIME-Version: 1.0 + Content-Type: text/plain; charset=UTF-8 + Content-Transfer-Encoding: 8bit + EOF ' test_expect_success $PREREQ 'asks about and fixes 8bit encodings' ' @@ -1270,21 +1261,21 @@ test_expect_success $PREREQ '--8bit-encoding overrides sendemail.8bitEncoding' ' ' test_expect_success $PREREQ 'setup expect' ' -cat >email-using-8bit <<EOF -From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001 -Message-Id: <bogus-message-id@example.com> -From: author@example.com -Date: Sat, 12 Jun 2010 15:53:58 +0200 -Subject: Dieser Betreff enthält auch einen Umlaut! - -Nothing to see here. -EOF + cat >email-using-8bit <<-\EOF + From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001 + Message-Id: <bogus-message-id@example.com> + From: author@example.com + Date: Sat, 12 Jun 2010 15:53:58 +0200 + Subject: Dieser Betreff enthält auch einen Umlaut! + + Nothing to see here. + EOF ' test_expect_success $PREREQ 'setup expect' ' -cat >expected <<EOF -Subject: =?UTF-8?q?Dieser=20Betreff=20enth=C3=A4lt=20auch=20einen=20Umlaut!?= -EOF + cat >expected <<-\EOF + Subject: =?UTF-8?q?Dieser=20Betreff=20enth=C3=A4lt=20auch=20einen=20Umlaut!?= + EOF ' test_expect_success $PREREQ '--8bit-encoding also treats subject' ' @@ -1298,6 +1289,163 @@ test_expect_success $PREREQ '--8bit-encoding also treats subject' ' test_cmp expected actual ' +test_expect_success $PREREQ 'setup expect' ' + cat >email-using-8bit <<-\EOF + From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001 + Message-Id: <bogus-message-id@example.com> + From: A U Thor <author@example.com> + Date: Sat, 12 Jun 2010 15:53:58 +0200 + Content-Type: text/plain; charset=UTF-8 + Subject: Nothing to see here. + + Dieser Betreff enthält auch einen Umlaut! + EOF +' + +test_expect_success $PREREQ 'sendemail.transferencoding=7bit fails on 8bit data' ' + clean_fake_sendmail && + git config sendemail.transferEncoding 7bit && + test_must_fail git send-email \ + --transfer-encoding=7bit \ + --smtp-server="$(pwd)/fake.sendmail" \ + email-using-8bit \ + 2>errors >out && + grep "cannot send message as 7bit" errors && + test -z "$(ls msgtxt*)" +' + +test_expect_success $PREREQ '--transfer-encoding overrides sendemail.transferEncoding' ' + clean_fake_sendmail && + git config sendemail.transferEncoding 8bit && + test_must_fail git send-email \ + --transfer-encoding=7bit \ + --smtp-server="$(pwd)/fake.sendmail" \ + email-using-8bit \ + 2>errors >out && + grep "cannot send message as 7bit" errors && + test -z "$(ls msgtxt*)" +' + +test_expect_success $PREREQ 'sendemail.transferencoding=8bit' ' + clean_fake_sendmail && + git send-email \ + --transfer-encoding=8bit \ + --smtp-server="$(pwd)/fake.sendmail" \ + email-using-8bit \ + 2>errors >out && + sed '1,/^$/d' msgtxt1 >actual && + sed '1,/^$/d' email-using-8bit >expected && + test_cmp expected actual +' + +test_expect_success $PREREQ 'setup expect' ' + cat >expected <<-\EOF + Dieser Betreff enth=C3=A4lt auch einen Umlaut! + EOF +' + +test_expect_success $PREREQ '8-bit and sendemail.transferencoding=quoted-printable' ' + clean_fake_sendmail && + git send-email \ + --transfer-encoding=quoted-printable \ + --smtp-server="$(pwd)/fake.sendmail" \ + email-using-8bit \ + 2>errors >out && + sed '1,/^$/d' msgtxt1 >actual && + test_cmp expected actual +' + +test_expect_success $PREREQ 'setup expect' ' + cat >expected <<-\EOF + RGllc2VyIEJldHJlZmYgZW50aMOkbHQgYXVjaCBlaW5lbiBVbWxhdXQhCg== + EOF +' + +test_expect_success $PREREQ '8-bit and sendemail.transferencoding=base64' ' + clean_fake_sendmail && + git send-email \ + --transfer-encoding=base64 \ + --smtp-server="$(pwd)/fake.sendmail" \ + email-using-8bit \ + 2>errors >out && + sed '1,/^$/d' msgtxt1 >actual && + test_cmp expected actual +' + +test_expect_success $PREREQ 'setup expect' ' + cat >email-using-qp <<-\EOF + From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001 + Message-Id: <bogus-message-id@example.com> + From: A U Thor <author@example.com> + Date: Sat, 12 Jun 2010 15:53:58 +0200 + MIME-Version: 1.0 + Content-Transfer-Encoding: quoted-printable + Content-Type: text/plain; charset=UTF-8 + Subject: Nothing to see here. + + Dieser Betreff enth=C3=A4lt auch einen Umlaut! + EOF +' + +test_expect_success $PREREQ 'convert from quoted-printable to base64' ' + clean_fake_sendmail && + git send-email \ + --transfer-encoding=base64 \ + --smtp-server="$(pwd)/fake.sendmail" \ + email-using-qp \ + 2>errors >out && + sed '1,/^$/d' msgtxt1 >actual && + test_cmp expected actual +' + +test_expect_success $PREREQ 'setup expect' " +tr -d '\\015' | tr '%' '\\015' >email-using-crlf <<EOF +From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001 +Message-Id: <bogus-message-id@example.com> +From: A U Thor <author@example.com> +Date: Sat, 12 Jun 2010 15:53:58 +0200 +Content-Type: text/plain; charset=UTF-8 +Subject: Nothing to see here. + +Look, I have a CRLF and an = sign!% +EOF +" + +test_expect_success $PREREQ 'setup expect' ' + cat >expected <<-\EOF + Look, I have a CRLF and an =3D sign!=0D + EOF +' + +test_expect_success $PREREQ 'CRLF and sendemail.transferencoding=quoted-printable' ' + clean_fake_sendmail && + git send-email \ + --transfer-encoding=quoted-printable \ + --smtp-server="$(pwd)/fake.sendmail" \ + email-using-crlf \ + 2>errors >out && + sed '1,/^$/d' msgtxt1 >actual && + test_cmp expected actual +' + +test_expect_success $PREREQ 'setup expect' ' + cat >expected <<-\EOF + TG9vaywgSSBoYXZlIGEgQ1JMRiBhbmQgYW4gPSBzaWduIQ0K + EOF +' + +test_expect_success $PREREQ 'CRLF and sendemail.transferencoding=base64' ' + clean_fake_sendmail && + git send-email \ + --transfer-encoding=base64 \ + --smtp-server="$(pwd)/fake.sendmail" \ + email-using-crlf \ + 2>errors >out && + sed '1,/^$/d' msgtxt1 >actual && + test_cmp expected actual +' + + # Note that the patches in this test are deliberately out of order; we # want to make sure it works even if the cover-letter is not in the # first mail. @@ -1306,13 +1454,13 @@ test_expect_success $PREREQ 'refusing to send cover letter template' ' rm -fr outdir && git format-patch --cover-letter -2 -o outdir && test_must_fail git send-email \ - --from="Example <nobody@example.com>" \ - --to=nobody@example.com \ - --smtp-server="$(pwd)/fake.sendmail" \ - outdir/0002-*.patch \ - outdir/0000-*.patch \ - outdir/0001-*.patch \ - 2>errors >out && + --from="Example <nobody@example.com>" \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + outdir/0002-*.patch \ + outdir/0000-*.patch \ + outdir/0001-*.patch \ + 2>errors >out && grep "SUBJECT HERE" errors && test -z "$(ls msgtxt*)" ' @@ -1322,44 +1470,419 @@ test_expect_success $PREREQ '--force sends cover letter template anyway' ' rm -fr outdir && git format-patch --cover-letter -2 -o outdir && git send-email \ - --force \ - --from="Example <nobody@example.com>" \ - --to=nobody@example.com \ - --smtp-server="$(pwd)/fake.sendmail" \ - outdir/0002-*.patch \ - outdir/0000-*.patch \ - outdir/0001-*.patch \ - 2>errors >out && + --force \ + --from="Example <nobody@example.com>" \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + outdir/0002-*.patch \ + outdir/0000-*.patch \ + outdir/0001-*.patch \ + 2>errors >out && ! grep "SUBJECT HERE" errors && test -n "$(ls msgtxt*)" ' +test_cover_addresses () { + header="$1" + shift + clean_fake_sendmail && + rm -fr outdir && + git format-patch --cover-letter -2 -o outdir && + cover=`echo outdir/0000-*.patch` && + mv $cover cover-to-edit.patch && + perl -pe "s/^From:/$header: extra\@address.com\nFrom:/" cover-to-edit.patch >"$cover" && + git send-email \ + --force \ + --from="Example <nobody@example.com>" \ + --no-to --no-cc \ + "$@" \ + --smtp-server="$(pwd)/fake.sendmail" \ + outdir/0000-*.patch \ + outdir/0001-*.patch \ + outdir/0002-*.patch \ + 2>errors >out && + grep "^$header: extra@address.com" msgtxt1 >to1 && + grep "^$header: extra@address.com" msgtxt2 >to2 && + grep "^$header: extra@address.com" msgtxt3 >to3 && + test_line_count = 1 to1 && + test_line_count = 1 to2 && + test_line_count = 1 to3 +} + +test_expect_success $PREREQ 'to-cover adds To to all mail' ' + test_cover_addresses "To" --to-cover +' + +test_expect_success $PREREQ 'cc-cover adds Cc to all mail' ' + test_cover_addresses "Cc" --cc-cover +' + +test_expect_success $PREREQ 'tocover adds To to all mail' ' + test_config sendemail.tocover true && + test_cover_addresses "To" +' + +test_expect_success $PREREQ 'cccover adds Cc to all mail' ' + test_config sendemail.cccover true && + test_cover_addresses "Cc" +' + +test_expect_success $PREREQ 'escaped quotes in sendemail.aliasfiletype=mutt' ' + clean_fake_sendmail && + echo "alias sbd \\\"Dot U. Sir\\\" <somebody@example.org>" >.mutt && + git config --replace-all sendemail.aliasesfile "$(pwd)/.mutt" && + git config sendemail.aliasfiletype mutt && + git send-email \ + --from="Example <nobody@example.com>" \ + --to=sbd \ + --smtp-server="$(pwd)/fake.sendmail" \ + outdir/0001-*.patch \ + 2>errors >out && + grep "^!somebody@example\.org!$" commandline1 && + grep -F "To: \"Dot U. Sir\" <somebody@example.org>" out +' + test_expect_success $PREREQ 'sendemail.aliasfiletype=mailrc' ' clean_fake_sendmail && echo "alias sbd somebody@example.org" >.mailrc && git config --replace-all sendemail.aliasesfile "$(pwd)/.mailrc" && git config sendemail.aliasfiletype mailrc && git send-email \ - --from="Example <nobody@example.com>" \ - --to=sbd \ - --smtp-server="$(pwd)/fake.sendmail" \ - outdir/0001-*.patch \ - 2>errors >out && + --from="Example <nobody@example.com>" \ + --to=sbd \ + --smtp-server="$(pwd)/fake.sendmail" \ + outdir/0001-*.patch \ + 2>errors >out && grep "^!somebody@example\.org!$" commandline1 ' test_expect_success $PREREQ 'sendemail.aliasfile=~/.mailrc' ' clean_fake_sendmail && - echo "alias sbd someone@example.org" >~/.mailrc && + echo "alias sbd someone@example.org" >"$HOME/.mailrc" && git config --replace-all sendemail.aliasesfile "~/.mailrc" && git config sendemail.aliasfiletype mailrc && git send-email \ - --from="Example <nobody@example.com>" \ - --to=sbd \ - --smtp-server="$(pwd)/fake.sendmail" \ - outdir/0001-*.patch \ - 2>errors >out && + --from="Example <nobody@example.com>" \ + --to=sbd \ + --smtp-server="$(pwd)/fake.sendmail" \ + outdir/0001-*.patch \ + 2>errors >out && + grep "^!someone@example\.org!$" commandline1 +' + +test_dump_aliases () { + msg="$1" && shift && + filetype="$1" && shift && + printf '%s\n' "$@" >expect && + cat >.tmp-email-aliases && + + test_expect_success $PREREQ "$msg" ' + clean_fake_sendmail && rm -fr outdir && + git config --replace-all sendemail.aliasesfile \ + "$(pwd)/.tmp-email-aliases" && + git config sendemail.aliasfiletype "$filetype" && + git send-email --dump-aliases 2>errors >actual && + test_cmp expect actual + ' +} + +test_dump_aliases '--dump-aliases sendmail format' \ + 'sendmail' \ + 'abgroup' \ + 'alice' \ + 'bcgrp' \ + 'bob' \ + 'chloe' <<-\EOF + alice: Alice W Land <awol@example.com> + bob: Robert Bobbyton <bob@example.com> + chloe: chloe@example.com + abgroup: alice, bob + bcgrp: bob, chloe, Other <o@example.com> + EOF + +test_dump_aliases '--dump-aliases mutt format' \ + 'mutt' \ + 'alice' \ + 'bob' \ + 'chloe' \ + 'donald' <<-\EOF + alias alice Alice W Land <awol@example.com> + alias donald Donald C Carlton <donc@example.com> + alias bob Robert Bobbyton <bob@example.com> + alias chloe chloe@example.com + EOF + +test_dump_aliases '--dump-aliases mailrc format' \ + 'mailrc' \ + 'alice' \ + 'bob' \ + 'chloe' \ + 'eve' <<-\EOF + alias alice Alice W Land <awol@example.com> + alias eve Eve <eve@example.com> + alias bob Robert Bobbyton <bob@example.com> + alias chloe chloe@example.com + EOF + +test_dump_aliases '--dump-aliases pine format' \ + 'pine' \ + 'alice' \ + 'bob' \ + 'chloe' \ + 'eve' <<-\EOF + alice Alice W Land <awol@example.com> + eve Eve <eve@example.com> + bob Robert Bobbyton <bob@example.com> + chloe chloe@example.com + EOF + +test_dump_aliases '--dump-aliases gnus format' \ + 'gnus' \ + 'alice' \ + 'bob' \ + 'chloe' \ + 'eve' <<-\EOF + (define-mail-alias "alice" "awol@example.com") + (define-mail-alias "eve" "eve@example.com") + (define-mail-alias "bob" "bob@example.com") + (define-mail-alias "chloe" "chloe@example.com") + EOF + +test_expect_success '--dump-aliases must be used alone' ' + test_must_fail git send-email --dump-aliases --to=janice@example.com -1 refs/heads/accounting +' + +test_sendmail_aliases () { + msg="$1" && shift && + expect="$@" && + cat >.tmp-email-aliases && + + test_expect_success $PREREQ "$msg" ' + clean_fake_sendmail && rm -fr outdir && + git format-patch -1 -o outdir && + git config --replace-all sendemail.aliasesfile \ + "$(pwd)/.tmp-email-aliases" && + git config sendemail.aliasfiletype sendmail && + git send-email \ + --from="Example <nobody@example.com>" \ + --to=alice --to=bcgrp \ + --smtp-server="$(pwd)/fake.sendmail" \ + outdir/0001-*.patch \ + 2>errors >out && + for i in $expect + do + grep "^!$i!$" commandline1 || return 1 + done + ' +} + +test_sendmail_aliases 'sendemail.aliasfiletype=sendmail' \ + 'awol@example\.com' \ + 'bob@example\.com' \ + 'chloe@example\.com' \ + 'o@example\.com' <<-\EOF + alice: Alice W Land <awol@example.com> + bob: Robert Bobbyton <bob@example.com> + # this is a comment + # this is also a comment + chloe: chloe@example.com + abgroup: alice, bob + bcgrp: bob, chloe, Other <o@example.com> + EOF + +test_sendmail_aliases 'sendmail aliases line folding' \ + alice1 \ + bob1 bob2 \ + chuck1 chuck2 \ + darla1 darla2 darla3 \ + elton1 elton2 elton3 \ + fred1 fred2 \ + greg1 <<-\EOF + alice: alice1 + bob: bob1,\ + bob2 + chuck: chuck1, + chuck2 + darla: darla1,\ + darla2, + darla3 + elton: elton1, + elton2,\ + elton3 + fred: fred1,\ + fred2 + greg: greg1 + bcgrp: bob, chuck, darla, elton, fred, greg + EOF + +test_sendmail_aliases 'sendmail aliases tolerate bogus line folding' \ + alice1 bob1 <<-\EOF + alice: alice1 + bcgrp: bob1\ + EOF + +test_sendmail_aliases 'sendmail aliases empty' alice bcgrp <<-\EOF + EOF + +test_expect_success $PREREQ 'alias support in To header' ' + clean_fake_sendmail && + echo "alias sbd someone@example.org" >.mailrc && + test_config sendemail.aliasesfile ".mailrc" && + test_config sendemail.aliasfiletype mailrc && + git format-patch --stdout -1 --to=sbd >aliased.patch && + git send-email \ + --from="Example <nobody@example.com>" \ + --smtp-server="$(pwd)/fake.sendmail" \ + aliased.patch \ + 2>errors >out && + grep "^!someone@example\.org!$" commandline1 +' + +test_expect_success $PREREQ 'alias support in Cc header' ' + clean_fake_sendmail && + echo "alias sbd someone@example.org" >.mailrc && + test_config sendemail.aliasesfile ".mailrc" && + test_config sendemail.aliasfiletype mailrc && + git format-patch --stdout -1 --cc=sbd >aliased.patch && + git send-email \ + --from="Example <nobody@example.com>" \ + --smtp-server="$(pwd)/fake.sendmail" \ + aliased.patch \ + 2>errors >out && + grep "^!someone@example\.org!$" commandline1 +' + +test_expect_success $PREREQ 'tocmd works with aliases' ' + clean_fake_sendmail && + echo "alias sbd someone@example.org" >.mailrc && + test_config sendemail.aliasesfile ".mailrc" && + test_config sendemail.aliasfiletype mailrc && + git format-patch --stdout -1 >tocmd.patch && + echo tocmd--sbd >>tocmd.patch && + git send-email \ + --from="Example <nobody@example.com>" \ + --to-cmd=./tocmd-sed \ + --smtp-server="$(pwd)/fake.sendmail" \ + tocmd.patch \ + 2>errors >out && + grep "^!someone@example\.org!$" commandline1 +' + +test_expect_success $PREREQ 'cccmd works with aliases' ' + clean_fake_sendmail && + echo "alias sbd someone@example.org" >.mailrc && + test_config sendemail.aliasesfile ".mailrc" && + test_config sendemail.aliasfiletype mailrc && + git format-patch --stdout -1 >cccmd.patch && + echo cccmd--sbd >>cccmd.patch && + git send-email \ + --from="Example <nobody@example.com>" \ + --cc-cmd=./cccmd-sed \ + --smtp-server="$(pwd)/fake.sendmail" \ + cccmd.patch \ + 2>errors >out && grep "^!someone@example\.org!$" commandline1 ' +do_xmailer_test () { + expected=$1 params=$2 && + git format-patch -1 && + git send-email \ + --from="Example <nobody@example.com>" \ + --to=someone@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + $params \ + 0001-*.patch \ + 2>errors >out && + { grep '^X-Mailer:' out || :; } >mailer && + test_line_count = $expected mailer +} + +test_expect_success $PREREQ '--[no-]xmailer without any configuration' ' + do_xmailer_test 1 "--xmailer" && + do_xmailer_test 0 "--no-xmailer" +' + +test_expect_success $PREREQ '--[no-]xmailer with sendemail.xmailer=true' ' + test_config sendemail.xmailer true && + do_xmailer_test 1 "" && + do_xmailer_test 0 "--no-xmailer" && + do_xmailer_test 1 "--xmailer" +' + +test_expect_success $PREREQ '--[no-]xmailer with sendemail.xmailer=false' ' + test_config sendemail.xmailer false && + do_xmailer_test 0 "" && + do_xmailer_test 0 "--no-xmailer" && + do_xmailer_test 1 "--xmailer" +' + +test_expect_success $PREREQ 'setup expected-list' ' + git send-email \ + --dry-run \ + --from="Example <from@example.com>" \ + --to="To 1 <to1@example.com>" \ + --to="to2@example.com" \ + --to="to3@example.com" \ + --cc="Cc 1 <cc1@example.com>" \ + --cc="Cc2 <cc2@example.com>" \ + --bcc="bcc1@example.com" \ + --bcc="bcc2@example.com" \ + 0001-add-master.patch | replace_variable_fields \ + >expected-list +' + +test_expect_success $PREREQ 'use email list in --cc --to and --bcc' ' + git send-email \ + --dry-run \ + --from="Example <from@example.com>" \ + --to="To 1 <to1@example.com>, to2@example.com" \ + --to="to3@example.com" \ + --cc="Cc 1 <cc1@example.com>, Cc2 <cc2@example.com>" \ + --bcc="bcc1@example.com, bcc2@example.com" \ + 0001-add-master.patch | replace_variable_fields \ + >actual-list && + test_cmp expected-list actual-list +' + +test_expect_success $PREREQ 'aliases work with email list' ' + echo "alias to2 to2@example.com" >.mutt && + echo "alias cc1 Cc 1 <cc1@example.com>" >>.mutt && + test_config sendemail.aliasesfile ".mutt" && + test_config sendemail.aliasfiletype mutt && + git send-email \ + --dry-run \ + --from="Example <from@example.com>" \ + --to="To 1 <to1@example.com>, to2, to3@example.com" \ + --cc="cc1, Cc2 <cc2@example.com>" \ + --bcc="bcc1@example.com, bcc2@example.com" \ + 0001-add-master.patch | replace_variable_fields \ + >actual-list && + test_cmp expected-list actual-list +' + +test_expect_success $PREREQ 'leading and trailing whitespaces are removed' ' + echo "alias to2 to2@example.com" >.mutt && + echo "alias cc1 Cc 1 <cc1@example.com>" >>.mutt && + test_config sendemail.aliasesfile ".mutt" && + test_config sendemail.aliasfiletype mutt && + TO1=$(echo "QTo 1 <to1@example.com>" | q_to_tab) && + TO2=$(echo "QZto2" | qz_to_tab_space) && + CC1=$(echo "cc1" | append_cr) && + BCC1=$(echo "Q bcc1@example.com Q" | q_to_nul) && + git send-email \ + --dry-run \ + --from=" Example <from@example.com>" \ + --to="$TO1" \ + --to="$TO2" \ + --to=" to3@example.com " \ + --cc="$CC1" \ + --cc="Cc2 <cc2@example.com>" \ + --bcc="$BCC1" \ + --bcc="bcc2@example.com" \ + 0001-add-master.patch | replace_variable_fields \ + >actual-list && + test_cmp expected-list actual-list +' + test_done diff --git a/t/t9104-git-svn-follow-parent.sh b/t/t9104-git-svn-follow-parent.sh index 13b179e721..83f17e13e8 100755 --- a/t/t9104-git-svn-follow-parent.sh +++ b/t/t9104-git-svn-follow-parent.sh @@ -72,16 +72,18 @@ test_expect_success 'follow larger parent' ' svn import -m "import a larger parent" import "$svnrepo"/larger-parent && svn cp -m "hi" "$svnrepo"/larger-parent "$svnrepo"/another-larger && git svn init --minimize-url -i larger \ - "$svnrepo"/another-larger/trunk/thunk/bump/thud && + "$svnrepo"/larger-parent/trunk/thunk/bump/thud && git svn fetch -i larger && + git svn init --minimize-url -i larger-parent \ + "$svnrepo"/another-larger/trunk/thunk/bump/thud && + git svn fetch -i larger-parent && git rev-parse --verify refs/remotes/larger && git rev-parse --verify \ - refs/remotes/larger-parent/trunk/thunk/bump/thud && + refs/remotes/larger-parent && test "`git merge-base \ - refs/remotes/larger-parent/trunk/thunk/bump/thud \ + refs/remotes/larger-parent \ refs/remotes/larger`" = \ "`git rev-parse refs/remotes/larger`" - true ' test_expect_success 'follow higher-level parent' ' diff --git a/t/t9119-git-svn-info.sh b/t/t9119-git-svn-info.sh index ff19695e77..f16f3234a1 100755 --- a/t/t9119-git-svn-info.sh +++ b/t/t9119-git-svn-info.sh @@ -74,6 +74,36 @@ test_expect_success 'info .' " test_cmp_info expected.info-dot actual.info-dot " +test_expect_success 'info $(pwd)' ' + (cd svnwc; svn info "$(pwd)") >expected.info-pwd && + (cd gitwc; git svn info "$(pwd)") >actual.info-pwd && + grep -v ^Path: <expected.info-pwd >expected.info-np && + grep -v ^Path: <actual.info-pwd >actual.info-np && + test_cmp_info expected.info-np actual.info-np && + test "$(sed -ne \"/^Path:/ s!/svnwc!!\" <expected.info-pwd)" = \ + "$(sed -ne \"/^Path:/ s!/gitwc!!\" <actual.info-pwd)" + ' + +test_expect_success 'info $(pwd)/../___wc' ' + (cd svnwc; svn info "$(pwd)/../svnwc") >expected.info-pwd && + (cd gitwc; git svn info "$(pwd)/../gitwc") >actual.info-pwd && + grep -v ^Path: <expected.info-pwd >expected.info-np && + grep -v ^Path: <actual.info-pwd >actual.info-np && + test_cmp_info expected.info-np actual.info-np && + test "$(sed -ne \"/^Path:/ s!/svnwc!!\" <expected.info-pwd)" = \ + "$(sed -ne \"/^Path:/ s!/gitwc!!\" <actual.info-pwd)" + ' + +test_expect_success 'info $(pwd)/../___wc//file' ' + (cd svnwc; svn info "$(pwd)/../svnwc//file") >expected.info-pwd && + (cd gitwc; git svn info "$(pwd)/../gitwc//file") >actual.info-pwd && + grep -v ^Path: <expected.info-pwd >expected.info-np && + grep -v ^Path: <actual.info-pwd >actual.info-np && + test_cmp_info expected.info-np actual.info-np && + test "$(sed -ne \"/^Path:/ s!/svnwc!!\" <expected.info-pwd)" = \ + "$(sed -ne \"/^Path:/ s!/gitwc!!\" <actual.info-pwd)" + ' + test_expect_success 'info --url .' ' test "$(cd gitwc; git svn info --url .)" = "$quoted_svnrepo" ' diff --git a/t/t9138-git-svn-authors-prog.sh b/t/t9138-git-svn-authors-prog.sh index 83cc5fc9d1..2937f4c265 100755 --- a/t/t9138-git-svn-authors-prog.sh +++ b/t/t9138-git-svn-authors-prog.sh @@ -7,40 +7,39 @@ test_description='git svn authors prog tests' . ./lib-git-svn.sh -cat > svn-authors-prog <<'EOF' -#!/usr/bin/perl -$_ = shift; -if (s/-sub$//) { - print "$_ <$_\@sub.example.com>\n"; -} -else { - print "$_ <$_\@example.com>\n"; -} +write_script svn-authors-prog "$PERL_PATH" <<-\EOF + $_ = shift; + if (s/-sub$//) { + print "$_ <$_\@sub.example.com>\n"; + } else { + print "$_ <$_\@example.com>\n"; + } EOF -chmod +x svn-authors-prog -cat > svn-authors <<'EOF' -ff = FFFFFFF FFFFFFF <fFf@other.example.com> -EOF +test_expect_success 'svn-authors setup' ' + cat >svn-authors <<-\EOF + ff = FFFFFFF FFFFFFF <fFf@other.example.com> + EOF +' test_expect_success 'setup svnrepo' ' for i in aa bb cc-sub dd-sub ee-foo ff do svn mkdir -m $i --username $i "$svnrepo"/$i done - ' +' test_expect_success 'import authors with prog and file' ' git svn clone --authors-prog=./svn-authors-prog \ --authors-file=svn-authors "$svnrepo" x - ' +' test_expect_success 'imported 6 revisions successfully' ' ( cd x test "`git rev-list refs/remotes/git-svn | wc -l`" -eq 6 ) - ' +' test_expect_success 'authors-prog ran correctly' ' ( @@ -56,7 +55,7 @@ test_expect_success 'authors-prog ran correctly' ' git rev-list -1 --pretty=raw refs/remotes/git-svn~5 | \ grep "^author aa <aa@example\.com> " ) - ' +' test_expect_success 'authors-file overrode authors-prog' ' ( @@ -64,7 +63,7 @@ test_expect_success 'authors-file overrode authors-prog' ' git rev-list -1 --pretty=raw refs/remotes/git-svn | \ grep "^author FFFFFFF FFFFFFF <fFf@other\.example\.com> " ) - ' +' git --git-dir=x/.git config --unset svn.authorsfile git --git-dir=x/.git config --unset svn.authorsprog diff --git a/t/t9148-git-svn-propset.sh b/t/t9148-git-svn-propset.sh new file mode 100755 index 0000000000..102639090c --- /dev/null +++ b/t/t9148-git-svn-propset.sh @@ -0,0 +1,95 @@ +#!/bin/sh +# +# Copyright (c) 2014 Alfred Perlstein +# + +test_description='git svn propset tests' + +. ./lib-git-svn.sh + +foo_subdir2="subdir/subdir2/foo_subdir2" + +set -e +mkdir import && +(set -e ; cd import + mkdir subdir + mkdir subdir/subdir2 + touch foo # for 'add props top level' + touch subdir/foo_subdir # for 'add props relative' + touch "$foo_subdir2" # for 'add props subdir' + svn_cmd import -m 'import for git svn' . "$svnrepo" >/dev/null +) +rm -rf import + +test_expect_success 'initialize git svn' ' + git svn init "$svnrepo" + ' + +test_expect_success 'fetch revisions from svn' ' + git svn fetch + ' + +set_props () { + subdir="$1" + file="$2" + shift;shift; + (cd "$subdir" && + while [ $# -gt 0 ] ; do + git svn propset "$1" "$2" "$file" || exit 1 + shift;shift; + done && + echo hello >> "$file" && + git commit -m "testing propset" "$file") +} + +confirm_props () { + subdir="$1" + file="$2" + shift;shift; + (set -e ; cd "svn_project/$subdir" && + while [ $# -gt 0 ] ; do + test "$(svn_cmd propget "$1" "$file")" = "$2" || exit 1 + shift;shift; + done) +} + + +#The current implementation has a restriction: +#svn propset will be taken as a delta for svn dcommit only +#if the file content is also modified +test_expect_success 'add props top level' ' + set_props "." "foo" "svn:keywords" "FreeBSD=%H" && + git svn dcommit && + svn_cmd co "$svnrepo" svn_project && + confirm_props "." "foo" "svn:keywords" "FreeBSD=%H" && + rm -rf svn_project + ' + +test_expect_success 'add multiple props' ' + set_props "." "foo" \ + "svn:keywords" "FreeBSD=%H" fbsd:nokeywords yes && + git svn dcommit && + svn_cmd co "$svnrepo" svn_project && + confirm_props "." "foo" \ + "svn:keywords" "FreeBSD=%H" fbsd:nokeywords yes && + rm -rf svn_project + ' + +test_expect_success 'add props subdir' ' + set_props "." "$foo_subdir2" svn:keywords "FreeBSD=%H" && + git svn dcommit && + svn_cmd co "$svnrepo" svn_project && + confirm_props "." "$foo_subdir2" "svn:keywords" "FreeBSD=%H" && + rm -rf svn_project + ' + +test_expect_success 'add props relative' ' + set_props "subdir/subdir2" "../foo_subdir" \ + svn:keywords "FreeBSD=%H" && + git svn dcommit && + svn_cmd co "$svnrepo" svn_project && + confirm_props "subdir/subdir2" "../foo_subdir" \ + svn:keywords "FreeBSD=%H" && + rm -rf svn_project + ' +test_done diff --git a/t/t9158-git-svn-mergeinfo.sh b/t/t9158-git-svn-mergeinfo.sh index 8c9539e1b4..13f78f2682 100755 --- a/t/t9158-git-svn-mergeinfo.sh +++ b/t/t9158-git-svn-mergeinfo.sh @@ -34,7 +34,7 @@ test_expect_success 'change svn:mergeinfo' ' ' test_expect_success 'verify svn:mergeinfo' ' - mergeinfo=$(svn_cmd propget svn:mergeinfo "$svnrepo"/trunk) + mergeinfo=$(svn_cmd propget svn:mergeinfo "$svnrepo"/trunk) && test "$mergeinfo" = "/branches/foo:1-10" ' @@ -46,7 +46,7 @@ test_expect_success 'change svn:mergeinfo multiline' ' ' test_expect_success 'verify svn:mergeinfo multiline' ' - mergeinfo=$(svn_cmd propget svn:mergeinfo "$svnrepo"/trunk) + mergeinfo=$(svn_cmd propget svn:mergeinfo "$svnrepo"/trunk) && test "$mergeinfo" = "/branches/bar:1-10 /branches/other:3-5,8,10-11" ' diff --git a/t/t9161-git-svn-mergeinfo-push.sh b/t/t9161-git-svn-mergeinfo-push.sh index 6cb0909afe..f113acaa6c 100755 --- a/t/t9161-git-svn-mergeinfo-push.sh +++ b/t/t9161-git-svn-mergeinfo-push.sh @@ -24,7 +24,7 @@ test_expect_success 'propagate merge information' ' ' test_expect_success 'check svn:mergeinfo' ' - mergeinfo=$(svn_cmd propget svn:mergeinfo "$svnrepo"/branches/svnb1) + mergeinfo=$(svn_cmd propget svn:mergeinfo "$svnrepo"/branches/svnb1) && test "$mergeinfo" = "/branches/svnb2:3,8" ' @@ -34,7 +34,7 @@ test_expect_success 'merge another branch' ' ' test_expect_success 'check primary parent mergeinfo respected' ' - mergeinfo=$(svn_cmd propget svn:mergeinfo "$svnrepo"/branches/svnb1) + mergeinfo=$(svn_cmd propget svn:mergeinfo "$svnrepo"/branches/svnb1) && test "$mergeinfo" = "/branches/svnb2:3,8 /branches/svnb3:4,9" ' @@ -45,7 +45,7 @@ test_expect_success 'merge existing merge' ' ' test_expect_success "check both parents' mergeinfo respected" ' - mergeinfo=$(svn_cmd propget svn:mergeinfo "$svnrepo"/branches/svnb1) + mergeinfo=$(svn_cmd propget svn:mergeinfo "$svnrepo"/branches/svnb1) && test "$mergeinfo" = "/branches/svnb2:3,8 /branches/svnb3:4,9 /branches/svnb4:5-6,10-12 @@ -70,7 +70,7 @@ test_expect_success 'second forward merge' ' ' test_expect_success 'check new mergeinfo added' ' - mergeinfo=$(svn_cmd propget svn:mergeinfo "$svnrepo"/branches/svnb1) + mergeinfo=$(svn_cmd propget svn:mergeinfo "$svnrepo"/branches/svnb1) && test "$mergeinfo" = "/branches/svnb2:3,8,16-17 /branches/svnb3:4,9 /branches/svnb4:5-6,10-12 @@ -84,7 +84,7 @@ test_expect_success 'reintegration merge' ' ' test_expect_success 'check reintegration mergeinfo' ' - mergeinfo=$(svn_cmd propget svn:mergeinfo "$svnrepo"/branches/svnb4) + mergeinfo=$(svn_cmd propget svn:mergeinfo "$svnrepo"/branches/svnb4) && test "$mergeinfo" = "/branches/svnb1:2-4,7-9,13-18 /branches/svnb2:3,8,16-17 /branches/svnb3:4,9 diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index 27263dfb80..14a938402e 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -47,1107 +47,1075 @@ file5_data='an inline file. file6_data='#!/bin/sh echo "$@"' ->empty - ### ### series A ### -test_tick - test_expect_success 'empty stream succeeds' ' git fast-import </dev/null ' -cat >input <<INPUT_END -blob -mark :2 -data <<EOF -$file2_data -EOF - -blob -mark :3 -data <<END -$file3_data -END - -blob -mark :4 -data $file4_len -$file4_data -commit refs/heads/master -mark :5 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -initial -COMMIT - -M 644 :2 file2 -M 644 :3 file3 -M 755 :4 file4 - -tag series-A -from :5 -data <<EOF -An annotated tag without a tagger -EOF - -tag series-A-blob -from :3 -data <<EOF -An annotated tag that annotates a blob. -EOF - -INPUT_END -test_expect_success \ - 'A: create pack from stdin' \ - 'git fast-import --export-marks=marks.out <input && - git whatchanged master' +test_expect_success 'A: create pack from stdin' ' + test_tick && + cat >input <<-INPUT_END && + blob + mark :2 + data <<EOF + $file2_data + EOF + + blob + mark :3 + data <<END + $file3_data + END + + blob + mark :4 + data $file4_len + $file4_data + commit refs/heads/master + mark :5 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + initial + COMMIT + + M 644 :2 file2 + M 644 :3 file3 + M 755 :4 file4 + + tag series-A + from :5 + data <<EOF + An annotated tag without a tagger + EOF + + tag series-A-blob + from :3 + data <<EOF + An annotated tag that annotates a blob. + EOF + + INPUT_END + git fast-import --export-marks=marks.out <input && + git whatchanged master +' test_expect_success 'A: verify pack' ' verify_packs ' -cat >expect <<EOF -author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE - -initial -EOF -test_expect_success \ - 'A: verify commit' \ - 'git cat-file commit master | sed 1d >actual && - test_cmp expect actual' - -cat >expect <<EOF -100644 blob file2 -100644 blob file3 -100755 blob file4 -EOF -test_expect_success \ - 'A: verify tree' \ - 'git cat-file -p master^{tree} | sed "s/ [0-9a-f]* / /" >actual && - test_cmp expect actual' - -echo "$file2_data" >expect -test_expect_success \ - 'A: verify file2' \ - 'git cat-file blob master:file2 >actual && test_cmp expect actual' - -echo "$file3_data" >expect -test_expect_success \ - 'A: verify file3' \ - 'git cat-file blob master:file3 >actual && test_cmp expect actual' - -printf "$file4_data" >expect -test_expect_success \ - 'A: verify file4' \ - 'git cat-file blob master:file4 >actual && test_cmp expect actual' - -cat >expect <<EOF -object $(git rev-parse refs/heads/master) -type commit -tag series-A - -An annotated tag without a tagger -EOF +test_expect_success 'A: verify commit' ' + cat >expect <<-EOF && + author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + + initial + EOF + git cat-file commit master | sed 1d >actual && + test_cmp expect actual +' + +test_expect_success 'A: verify tree' ' + cat >expect <<-EOF && + 100644 blob file2 + 100644 blob file3 + 100755 blob file4 + EOF + git cat-file -p master^{tree} | sed "s/ [0-9a-f]* / /" >actual && + test_cmp expect actual +' + +test_expect_success 'A: verify file2' ' + echo "$file2_data" >expect && + git cat-file blob master:file2 >actual && + test_cmp expect actual +' + +test_expect_success 'A: verify file3' ' + echo "$file3_data" >expect && + git cat-file blob master:file3 >actual && + test_cmp expect actual +' + +test_expect_success 'A: verify file4' ' + printf "$file4_data" >expect && + git cat-file blob master:file4 >actual && + test_cmp expect actual +' + test_expect_success 'A: verify tag/series-A' ' + cat >expect <<-EOF && + object $(git rev-parse refs/heads/master) + type commit + tag series-A + + An annotated tag without a tagger + EOF git cat-file tag tags/series-A >actual && test_cmp expect actual ' -cat >expect <<EOF -object $(git rev-parse refs/heads/master:file3) -type blob -tag series-A-blob - -An annotated tag that annotates a blob. -EOF test_expect_success 'A: verify tag/series-A-blob' ' + cat >expect <<-EOF && + object $(git rev-parse refs/heads/master:file3) + type blob + tag series-A-blob + + An annotated tag that annotates a blob. + EOF git cat-file tag tags/series-A-blob >actual && test_cmp expect actual ' -cat >expect <<EOF -:2 `git rev-parse --verify master:file2` -:3 `git rev-parse --verify master:file3` -:4 `git rev-parse --verify master:file4` -:5 `git rev-parse --verify master^0` -EOF -test_expect_success \ - 'A: verify marks output' \ - 'test_cmp expect marks.out' +test_expect_success 'A: verify marks output' ' + cat >expect <<-EOF && + :2 `git rev-parse --verify master:file2` + :3 `git rev-parse --verify master:file3` + :4 `git rev-parse --verify master:file4` + :5 `git rev-parse --verify master^0` + EOF + test_cmp expect marks.out +' -test_expect_success \ - 'A: verify marks import' \ - 'git fast-import \ +test_expect_success 'A: verify marks import' ' + git fast-import \ --import-marks=marks.out \ --export-marks=marks.new \ </dev/null && - test_cmp expect marks.new' - -test_tick -new_blob=$(echo testing | git hash-object --stdin) -cat >input <<INPUT_END -tag series-A-blob-2 -from $(git rev-parse refs/heads/master:file3) -data <<EOF -Tag blob by sha1. -EOF - -blob -mark :6 -data <<EOF -testing -EOF - -commit refs/heads/new_blob -committer <> 0 +0000 -data 0 -M 644 :6 new_blob -#pretend we got sha1 from fast-import -ls "new_blob" - -tag series-A-blob-3 -from $new_blob -data <<EOF -Tag new_blob. -EOF -INPUT_END - -cat >expect <<EOF -object $(git rev-parse refs/heads/master:file3) -type blob -tag series-A-blob-2 - -Tag blob by sha1. -object $new_blob -type blob -tag series-A-blob-3 - -Tag new_blob. -EOF - -test_expect_success \ - 'A: tag blob by sha1' \ - 'git fast-import <input && + test_cmp expect marks.new +' + +test_expect_success 'A: tag blob by sha1' ' + test_tick && + new_blob=$(echo testing | git hash-object --stdin) && + cat >input <<-INPUT_END && + tag series-A-blob-2 + from $(git rev-parse refs/heads/master:file3) + data <<EOF + Tag blob by sha1. + EOF + + blob + mark :6 + data <<EOF + testing + EOF + + commit refs/heads/new_blob + committer <> 0 +0000 + data 0 + M 644 :6 new_blob + #pretend we got sha1 from fast-import + ls "new_blob" + + tag series-A-blob-3 + from $new_blob + data <<EOF + Tag new_blob. + EOF + INPUT_END + + cat >expect <<-EOF && + object $(git rev-parse refs/heads/master:file3) + type blob + tag series-A-blob-2 + + Tag blob by sha1. + object $new_blob + type blob + tag series-A-blob-3 + + Tag new_blob. + EOF + + git fast-import <input && git cat-file tag tags/series-A-blob-2 >actual && git cat-file tag tags/series-A-blob-3 >>actual && - test_cmp expect actual' + test_cmp expect actual +' + +test_expect_success 'A: verify marks import does not crash' ' + test_tick && + cat >input <<-INPUT_END && + commit refs/heads/verify--import-marks + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + recreate from :5 + COMMIT -test_tick -cat >input <<INPUT_END -commit refs/heads/verify--import-marks -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -recreate from :5 -COMMIT + from :5 + M 755 :2 copy-of-file2 -from :5 -M 755 :2 copy-of-file2 + INPUT_END -INPUT_END -test_expect_success \ - 'A: verify marks import does not crash' \ - 'git fast-import --import-marks=marks.out <input && - git whatchanged verify--import-marks' + git fast-import --import-marks=marks.out <input && + git whatchanged verify--import-marks +' test_expect_success 'A: verify pack' ' verify_packs ' -cat >expect <<EOF -:000000 100755 0000000000000000000000000000000000000000 7123f7f44e39be127c5eb701e5968176ee9d78b1 A copy-of-file2 -EOF -git diff-tree -M -r master verify--import-marks >actual -test_expect_success \ - 'A: verify diff' \ - 'compare_diff_raw expect actual && - test `git rev-parse --verify master:file2` \ - = `git rev-parse --verify verify--import-marks:copy-of-file2`' - -test_tick -mt=$(git hash-object --stdin < /dev/null) -: >input.blob -: >marks.exp -: >tree.exp - -cat >input.commit <<EOF -commit refs/heads/verify--dump-marks -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -test the sparse array dumping routines with exponentially growing marks -COMMIT -EOF - -i=0 -l=4 -m=6 -n=7 -while test "$i" -lt 27; do - cat >>input.blob <<EOF -blob -mark :$l -data 0 -blob -mark :$m -data 0 -blob -mark :$n -data 0 -EOF - echo "M 100644 :$l l$i" >>input.commit - echo "M 100644 :$m m$i" >>input.commit - echo "M 100644 :$n n$i" >>input.commit - - echo ":$l $mt" >>marks.exp - echo ":$m $mt" >>marks.exp - echo ":$n $mt" >>marks.exp - - printf "100644 blob $mt\tl$i\n" >>tree.exp - printf "100644 blob $mt\tm$i\n" >>tree.exp - printf "100644 blob $mt\tn$i\n" >>tree.exp - - l=$(($l + $l)) - m=$(($m + $m)) - n=$(($l + $n)) - - i=$((1 + $i)) -done - -sort tree.exp > tree.exp_s +test_expect_success 'A: verify diff' ' + cat >expect <<-EOF && + :000000 100755 0000000000000000000000000000000000000000 7123f7f44e39be127c5eb701e5968176ee9d78b1 A copy-of-file2 + EOF + git diff-tree -M -r master verify--import-marks >actual && + compare_diff_raw expect actual && + test `git rev-parse --verify master:file2` \ + = `git rev-parse --verify verify--import-marks:copy-of-file2` +' test_expect_success 'A: export marks with large values' ' + test_tick && + mt=$(git hash-object --stdin < /dev/null) && + >input.blob && + >marks.exp && + >tree.exp && + + cat >input.commit <<-EOF && + commit refs/heads/verify--dump-marks + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + test the sparse array dumping routines with exponentially growing marks + COMMIT + EOF + + i=0 l=4 m=6 n=7 && + while test "$i" -lt 27 + do + cat >>input.blob <<-EOF && + blob + mark :$l + data 0 + blob + mark :$m + data 0 + blob + mark :$n + data 0 + EOF + echo "M 100644 :$l l$i" >>input.commit && + echo "M 100644 :$m m$i" >>input.commit && + echo "M 100644 :$n n$i" >>input.commit && + + echo ":$l $mt" >>marks.exp && + echo ":$m $mt" >>marks.exp && + echo ":$n $mt" >>marks.exp && + + printf "100644 blob $mt\tl$i\n" >>tree.exp && + printf "100644 blob $mt\tm$i\n" >>tree.exp && + printf "100644 blob $mt\tn$i\n" >>tree.exp && + + l=$(($l + $l)) && + m=$(($m + $m)) && + n=$(($l + $n)) && + + i=$((1 + $i)) || return 1 + done && + + sort tree.exp > tree.exp_s && + cat input.blob input.commit | git fast-import --export-marks=marks.large && git ls-tree refs/heads/verify--dump-marks >tree.out && test_cmp tree.exp_s tree.out && - test_cmp marks.exp marks.large' + test_cmp marks.exp marks.large +' ### ### series B ### -test_tick -cat >input <<INPUT_END -commit refs/heads/branch -mark :1 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -corrupt -COMMIT +test_expect_success 'B: fail on invalid blob sha1' ' + test_tick && + cat >input <<-INPUT_END && + commit refs/heads/branch + mark :1 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + corrupt + COMMIT -from refs/heads/master -M 755 0000000000000000000000000000000000000001 zero1 + from refs/heads/master + M 755 0000000000000000000000000000000000000001 zero1 + + INPUT_END + + test_when_finished "rm -f .git/objects/pack_* .git/objects/index_*" && + test_must_fail git fast-import <input +' + +test_expect_success 'B: accept branch name "TEMP_TAG"' ' + cat >input <<-INPUT_END && + commit TEMP_TAG + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + tag base + COMMIT + + from refs/heads/master + + INPUT_END + + test_when_finished "rm -f .git/TEMP_TAG + git gc + git prune" && + git fast-import <input && + test -f .git/TEMP_TAG && + test `git rev-parse master` = `git rev-parse TEMP_TAG^` +' -INPUT_END -test_expect_success 'B: fail on invalid blob sha1' ' - test_must_fail git fast-import <input -' -rm -f .git/objects/pack_* .git/objects/index_* - -cat >input <<INPUT_END -commit .badbranchname -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -corrupt -COMMIT - -from refs/heads/master - -INPUT_END -test_expect_success 'B: fail on invalid branch name ".badbranchname"' ' - test_must_fail git fast-import <input -' -rm -f .git/objects/pack_* .git/objects/index_* - -cat >input <<INPUT_END -commit bad[branch]name -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -corrupt -COMMIT - -from refs/heads/master - -INPUT_END -test_expect_success 'B: fail on invalid branch name "bad[branch]name"' ' - test_must_fail git fast-import <input -' -rm -f .git/objects/pack_* .git/objects/index_* - -cat >input <<INPUT_END -commit TEMP_TAG -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -tag base -COMMIT - -from refs/heads/master - -INPUT_END -test_expect_success \ - 'B: accept branch name "TEMP_TAG"' \ - 'git fast-import <input && - test -f .git/TEMP_TAG && - test `git rev-parse master` = `git rev-parse TEMP_TAG^`' -rm -f .git/TEMP_TAG - -git gc 2>/dev/null >/dev/null -git prune 2>/dev/null >/dev/null - -cat >input <<INPUT_END -commit refs/heads/empty-committer-1 -committer <> $GIT_COMMITTER_DATE -data <<COMMIT -empty commit -COMMIT -INPUT_END test_expect_success 'B: accept empty committer' ' + cat >input <<-INPUT_END && + commit refs/heads/empty-committer-1 + committer <> $GIT_COMMITTER_DATE + data <<COMMIT + empty commit + COMMIT + INPUT_END + + test_when_finished "git update-ref -d refs/heads/empty-committer-1 + git gc + git prune" && git fast-import <input && out=$(git fsck) && echo "$out" && test -z "$out" ' -git update-ref -d refs/heads/empty-committer-1 || true - -git gc 2>/dev/null >/dev/null -git prune 2>/dev/null >/dev/null -cat >input <<INPUT_END -commit refs/heads/empty-committer-2 -committer <a@b.com> $GIT_COMMITTER_DATE -data <<COMMIT -empty commit -COMMIT -INPUT_END test_expect_success 'B: accept and fixup committer with no name' ' + cat >input <<-INPUT_END && + commit refs/heads/empty-committer-2 + committer <a@b.com> $GIT_COMMITTER_DATE + data <<COMMIT + empty commit + COMMIT + INPUT_END + + test_when_finished "git update-ref -d refs/heads/empty-committer-2 + git gc + git prune" && git fast-import <input && out=$(git fsck) && echo "$out" && test -z "$out" ' -git update-ref -d refs/heads/empty-committer-2 || true - -git gc 2>/dev/null >/dev/null -git prune 2>/dev/null >/dev/null -cat >input <<INPUT_END -commit refs/heads/invalid-committer -committer Name email> $GIT_COMMITTER_DATE -data <<COMMIT -empty commit -COMMIT -INPUT_END test_expect_success 'B: fail on invalid committer (1)' ' + cat >input <<-INPUT_END && + commit refs/heads/invalid-committer + committer Name email> $GIT_COMMITTER_DATE + data <<COMMIT + empty commit + COMMIT + INPUT_END + + test_when_finished "git update-ref -d refs/heads/invalid-committer" && test_must_fail git fast-import <input ' -git update-ref -d refs/heads/invalid-committer || true -cat >input <<INPUT_END -commit refs/heads/invalid-committer -committer Name <e<mail> $GIT_COMMITTER_DATE -data <<COMMIT -empty commit -COMMIT -INPUT_END test_expect_success 'B: fail on invalid committer (2)' ' + cat >input <<-INPUT_END && + commit refs/heads/invalid-committer + committer Name <e<mail> $GIT_COMMITTER_DATE + data <<COMMIT + empty commit + COMMIT + INPUT_END + + test_when_finished "git update-ref -d refs/heads/invalid-committer" && test_must_fail git fast-import <input ' -git update-ref -d refs/heads/invalid-committer || true -cat >input <<INPUT_END -commit refs/heads/invalid-committer -committer Name <email>> $GIT_COMMITTER_DATE -data <<COMMIT -empty commit -COMMIT -INPUT_END test_expect_success 'B: fail on invalid committer (3)' ' + cat >input <<-INPUT_END && + commit refs/heads/invalid-committer + committer Name <email>> $GIT_COMMITTER_DATE + data <<COMMIT + empty commit + COMMIT + INPUT_END + + test_when_finished "git update-ref -d refs/heads/invalid-committer" && test_must_fail git fast-import <input ' -git update-ref -d refs/heads/invalid-committer || true -cat >input <<INPUT_END -commit refs/heads/invalid-committer -committer Name <email $GIT_COMMITTER_DATE -data <<COMMIT -empty commit -COMMIT -INPUT_END test_expect_success 'B: fail on invalid committer (4)' ' + cat >input <<-INPUT_END && + commit refs/heads/invalid-committer + committer Name <email $GIT_COMMITTER_DATE + data <<COMMIT + empty commit + COMMIT + INPUT_END + + test_when_finished "git update-ref -d refs/heads/invalid-committer" && test_must_fail git fast-import <input ' -git update-ref -d refs/heads/invalid-committer || true -cat >input <<INPUT_END -commit refs/heads/invalid-committer -committer Name<email> $GIT_COMMITTER_DATE -data <<COMMIT -empty commit -COMMIT -INPUT_END test_expect_success 'B: fail on invalid committer (5)' ' + cat >input <<-INPUT_END && + commit refs/heads/invalid-committer + committer Name<email> $GIT_COMMITTER_DATE + data <<COMMIT + empty commit + COMMIT + INPUT_END + + test_when_finished "git update-ref -d refs/heads/invalid-committer" && test_must_fail git fast-import <input ' -git update-ref -d refs/heads/invalid-committer || true ### ### series C ### -newf=`echo hi newf | git hash-object -w --stdin` -oldf=`git rev-parse --verify master:file2` -test_tick -cat >input <<INPUT_END -commit refs/heads/branch -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -second -COMMIT - -from refs/heads/master -M 644 $oldf file2/oldf -M 755 $newf file2/newf -D file3 - -INPUT_END -test_expect_success \ - 'C: incremental import create pack from stdin' \ - 'git fast-import <input && - git whatchanged branch' +test_expect_success 'C: incremental import create pack from stdin' ' + newf=`echo hi newf | git hash-object -w --stdin` && + oldf=`git rev-parse --verify master:file2` && + test_tick && + cat >input <<-INPUT_END && + commit refs/heads/branch + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + second + COMMIT + + from refs/heads/master + M 644 $oldf file2/oldf + M 755 $newf file2/newf + D file3 + + INPUT_END + + git fast-import <input && + git whatchanged branch +' test_expect_success 'C: verify pack' ' verify_packs ' -test_expect_success \ - 'C: validate reuse existing blob' \ - 'test $newf = `git rev-parse --verify branch:file2/newf` && - test $oldf = `git rev-parse --verify branch:file2/oldf`' - -cat >expect <<EOF -parent `git rev-parse --verify master^0` -author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE - -second -EOF -test_expect_success \ - 'C: verify commit' \ - 'git cat-file commit branch | sed 1d >actual && - test_cmp expect actual' - -cat >expect <<EOF -:000000 100755 0000000000000000000000000000000000000000 f1fb5da718392694d0076d677d6d0e364c79b0bc A file2/newf -:100644 100644 7123f7f44e39be127c5eb701e5968176ee9d78b1 7123f7f44e39be127c5eb701e5968176ee9d78b1 R100 file2 file2/oldf -:100644 000000 0d92e9f3374ae2947c23aa477cbc68ce598135f1 0000000000000000000000000000000000000000 D file3 -EOF -git diff-tree -M -r master branch >actual -test_expect_success \ - 'C: validate rename result' \ - 'compare_diff_raw expect actual' +test_expect_success 'C: validate reuse existing blob' ' + test $newf = `git rev-parse --verify branch:file2/newf` && + test $oldf = `git rev-parse --verify branch:file2/oldf` +' + +test_expect_success 'C: verify commit' ' + cat >expect <<-EOF && + parent `git rev-parse --verify master^0` + author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + + second + EOF + + git cat-file commit branch | sed 1d >actual && + test_cmp expect actual +' + +test_expect_success 'C: validate rename result' ' + cat >expect <<-EOF && + :000000 100755 0000000000000000000000000000000000000000 f1fb5da718392694d0076d677d6d0e364c79b0bc A file2/newf + :100644 100644 7123f7f44e39be127c5eb701e5968176ee9d78b1 7123f7f44e39be127c5eb701e5968176ee9d78b1 R100 file2 file2/oldf + :100644 000000 0d92e9f3374ae2947c23aa477cbc68ce598135f1 0000000000000000000000000000000000000000 D file3 + EOF + git diff-tree -M -r master branch >actual && + compare_diff_raw expect actual +' ### ### series D ### -test_tick -cat >input <<INPUT_END -commit refs/heads/branch -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -third -COMMIT - -from refs/heads/branch^0 -M 644 inline newdir/interesting -data <<EOF -$file5_data -EOF - -M 755 inline newdir/exec.sh -data <<EOF -$file6_data -EOF - -INPUT_END -test_expect_success \ - 'D: inline data in commit' \ - 'git fast-import <input && - git whatchanged branch' +test_expect_success 'D: inline data in commit' ' + test_tick && + cat >input <<-INPUT_END && + commit refs/heads/branch + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + third + COMMIT + + from refs/heads/branch^0 + M 644 inline newdir/interesting + data <<EOF + $file5_data + EOF + + M 755 inline newdir/exec.sh + data <<EOF + $file6_data + EOF + + INPUT_END + + git fast-import <input && + git whatchanged branch +' test_expect_success 'D: verify pack' ' verify_packs ' -cat >expect <<EOF -:000000 100755 0000000000000000000000000000000000000000 35a59026a33beac1569b1c7f66f3090ce9c09afc A newdir/exec.sh -:000000 100644 0000000000000000000000000000000000000000 046d0371e9220107917db0d0e030628de8a1de9b A newdir/interesting -EOF -git diff-tree -M -r branch^ branch >actual -test_expect_success \ - 'D: validate new files added' \ - 'compare_diff_raw expect actual' +test_expect_success 'D: validate new files added' ' + cat >expect <<-EOF && + :000000 100755 0000000000000000000000000000000000000000 e74b7d465e52746be2b4bae983670711e6e66657 A newdir/exec.sh + :000000 100644 0000000000000000000000000000000000000000 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 A newdir/interesting + EOF + git diff-tree -M -r branch^ branch >actual && + compare_diff_raw expect actual +' -echo "$file5_data" >expect -test_expect_success \ - 'D: verify file5' \ - 'git cat-file blob branch:newdir/interesting >actual && - test_cmp expect actual' +test_expect_success 'D: verify file5' ' + echo "$file5_data" >expect && + git cat-file blob branch:newdir/interesting >actual && + test_cmp expect actual +' -echo "$file6_data" >expect -test_expect_success \ - 'D: verify file6' \ - 'git cat-file blob branch:newdir/exec.sh >actual && - test_cmp expect actual' +test_expect_success 'D: verify file6' ' + echo "$file6_data" >expect && + git cat-file blob branch:newdir/exec.sh >actual && + test_cmp expect actual +' ### ### series E ### -cat >input <<INPUT_END -commit refs/heads/branch -author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> Tue Feb 6 11:22:18 2007 -0500 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> Tue Feb 6 12:35:02 2007 -0500 -data <<COMMIT -RFC 2822 type date -COMMIT +test_expect_success 'E: rfc2822 date, --date-format=raw' ' + cat >input <<-INPUT_END && + commit refs/heads/branch + author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> Tue Feb 6 11:22:18 2007 -0500 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> Tue Feb 6 12:35:02 2007 -0500 + data <<COMMIT + RFC 2822 type date + COMMIT -from refs/heads/branch^0 + from refs/heads/branch^0 -INPUT_END -test_expect_success 'E: rfc2822 date, --date-format=raw' ' - test_must_fail git fast-import --date-format=raw <input + INPUT_END + + test_must_fail git fast-import --date-format=raw <input +' +test_expect_success 'E: rfc2822 date, --date-format=rfc2822' ' + git fast-import --date-format=rfc2822 <input ' -test_expect_success \ - 'E: rfc2822 date, --date-format=rfc2822' \ - 'git fast-import --date-format=rfc2822 <input' test_expect_success 'E: verify pack' ' verify_packs ' -cat >expect <<EOF -author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> 1170778938 -0500 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1170783302 -0500 +test_expect_success 'E: verify commit' ' + cat >expect <<-EOF && + author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> 1170778938 -0500 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1170783302 -0500 -RFC 2822 type date -EOF -test_expect_success \ - 'E: verify commit' \ - 'git cat-file commit branch | sed 1,2d >actual && - test_cmp expect actual' + RFC 2822 type date + EOF + git cat-file commit branch | sed 1,2d >actual && + test_cmp expect actual +' ### ### series F ### -old_branch=`git rev-parse --verify branch^0` -test_tick -cat >input <<INPUT_END -commit refs/heads/branch -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -losing things already? -COMMIT - -from refs/heads/branch~1 - -reset refs/heads/other -from refs/heads/branch - -INPUT_END -test_expect_success \ - 'F: non-fast-forward update skips' \ - 'if git fast-import <input - then - echo BAD gfi did not fail - return 1 - else - if test $old_branch = `git rev-parse --verify branch^0` - then - : branch unaffected and failure returned - return 0 - else - echo BAD gfi changed branch $old_branch - return 1 - fi - fi - ' +test_expect_success 'F: non-fast-forward update skips' ' + old_branch=`git rev-parse --verify branch^0` && + test_tick && + cat >input <<-INPUT_END && + commit refs/heads/branch + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + losing things already? + COMMIT + + from refs/heads/branch~1 + + reset refs/heads/other + from refs/heads/branch + + INPUT_END + + test_must_fail git fast-import <input && + # branch must remain unaffected + test $old_branch = `git rev-parse --verify branch^0` +' test_expect_success 'F: verify pack' ' verify_packs ' -cat >expect <<EOF -tree `git rev-parse branch~1^{tree}` -parent `git rev-parse branch~1` -author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE +test_expect_success 'F: verify other commit' ' + cat >expect <<-EOF && + tree `git rev-parse branch~1^{tree}` + parent `git rev-parse branch~1` + author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -losing things already? -EOF -test_expect_success \ - 'F: verify other commit' \ - 'git cat-file commit other >actual && - test_cmp expect actual' + losing things already? + EOF + git cat-file commit other >actual && + test_cmp expect actual +' ### ### series G ### -old_branch=`git rev-parse --verify branch^0` -test_tick -cat >input <<INPUT_END -commit refs/heads/branch -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -losing things already? -COMMIT +test_expect_success 'G: non-fast-forward update forced' ' + old_branch=`git rev-parse --verify branch^0` && + test_tick && + cat >input <<-INPUT_END && + commit refs/heads/branch + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + losing things already? + COMMIT -from refs/heads/branch~1 + from refs/heads/branch~1 -INPUT_END -test_expect_success \ - 'G: non-fast-forward update forced' \ - 'git fast-import --force <input' + INPUT_END + git fast-import --force <input +' test_expect_success 'G: verify pack' ' verify_packs ' -test_expect_success \ - 'G: branch changed, but logged' \ - 'test $old_branch != `git rev-parse --verify branch^0` && - test $old_branch = `git rev-parse --verify branch@{1}`' +test_expect_success 'G: branch changed, but logged' ' + test $old_branch != `git rev-parse --verify branch^0` && + test $old_branch = `git rev-parse --verify branch@{1}` +' ### ### series H ### -test_tick -cat >input <<INPUT_END -commit refs/heads/H -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -third -COMMIT - -from refs/heads/branch^0 -M 644 inline i-will-die -data <<EOF -this file will never exist. -EOF - -deleteall -M 644 inline h/e/l/lo -data <<EOF -$file5_data -EOF - -INPUT_END -test_expect_success \ - 'H: deletall, add 1' \ - 'git fast-import <input && - git whatchanged H' +test_expect_success 'H: deletall, add 1' ' + test_tick && + cat >input <<-INPUT_END && + commit refs/heads/H + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + third + COMMIT + + from refs/heads/branch^0 + M 644 inline i-will-die + data <<EOF + this file will never exist. + EOF + + deleteall + M 644 inline h/e/l/lo + data <<EOF + $file5_data + EOF + + INPUT_END + git fast-import <input && + git whatchanged H +' test_expect_success 'H: verify pack' ' verify_packs ' -cat >expect <<EOF -:100755 000000 f1fb5da718392694d0076d677d6d0e364c79b0bc 0000000000000000000000000000000000000000 D file2/newf -:100644 000000 7123f7f44e39be127c5eb701e5968176ee9d78b1 0000000000000000000000000000000000000000 D file2/oldf -:100755 000000 85df50785d62d3b05ab03d9cbf7e4a0b49449730 0000000000000000000000000000000000000000 D file4 -:100644 100644 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 R100 newdir/interesting h/e/l/lo -:100755 000000 e74b7d465e52746be2b4bae983670711e6e66657 0000000000000000000000000000000000000000 D newdir/exec.sh -EOF -git diff-tree -M -r H^ H >actual -test_expect_success \ - 'H: validate old files removed, new files added' \ - 'compare_diff_raw expect actual' - -echo "$file5_data" >expect -test_expect_success \ - 'H: verify file' \ - 'git cat-file blob H:h/e/l/lo >actual && - test_cmp expect actual' +test_expect_success 'H: validate old files removed, new files added' ' + cat >expect <<-EOF && + :100755 000000 f1fb5da718392694d0076d677d6d0e364c79b0bc 0000000000000000000000000000000000000000 D file2/newf + :100644 000000 7123f7f44e39be127c5eb701e5968176ee9d78b1 0000000000000000000000000000000000000000 D file2/oldf + :100755 000000 85df50785d62d3b05ab03d9cbf7e4a0b49449730 0000000000000000000000000000000000000000 D file4 + :100644 100644 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 R100 newdir/interesting h/e/l/lo + :100755 000000 e74b7d465e52746be2b4bae983670711e6e66657 0000000000000000000000000000000000000000 D newdir/exec.sh + EOF + git diff-tree -M -r H^ H >actual && + compare_diff_raw expect actual +' + +test_expect_success 'H: verify file' ' + echo "$file5_data" >expect && + git cat-file blob H:h/e/l/lo >actual && + test_cmp expect actual +' ### ### series I ### -cat >input <<INPUT_END -commit refs/heads/export-boundary -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -we have a border. its only 40 characters wide. -COMMIT +test_expect_success 'I: export-pack-edges' ' + cat >input <<-INPUT_END && + commit refs/heads/export-boundary + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + we have a border. its only 40 characters wide. + COMMIT -from refs/heads/branch + from refs/heads/branch -INPUT_END -test_expect_success \ - 'I: export-pack-edges' \ - 'git fast-import --export-pack-edges=edges.list <input' + INPUT_END + git fast-import --export-pack-edges=edges.list <input +' -cat >expect <<EOF -.git/objects/pack/pack-.pack: `git rev-parse --verify export-boundary` -EOF -test_expect_success \ - 'I: verify edge list' \ - 'sed -e s/pack-.*pack/pack-.pack/ edges.list >actual && - test_cmp expect actual' +test_expect_success 'I: verify edge list' ' + cat >expect <<-EOF && + .git/objects/pack/pack-.pack: `git rev-parse --verify export-boundary` + EOF + sed -e s/pack-.*pack/pack-.pack/ edges.list >actual && + test_cmp expect actual +' ### ### series J ### -cat >input <<INPUT_END -commit refs/heads/J -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -create J -COMMIT - -from refs/heads/branch - -reset refs/heads/J - -commit refs/heads/J -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -initialize J -COMMIT - -INPUT_END -test_expect_success \ - 'J: reset existing branch creates empty commit' \ - 'git fast-import <input' -test_expect_success \ - 'J: branch has 1 commit, empty tree' \ - 'test 1 = `git rev-list J | wc -l` && - test 0 = `git ls-tree J | wc -l`' - -cat >input <<INPUT_END -reset refs/heads/J2 - -tag wrong_tag -from refs/heads/J2 -data <<EOF -Tag branch that was reset. -EOF -INPUT_END -test_expect_success \ - 'J: tag must fail on empty branch' \ - 'test_must_fail git fast-import <input' +test_expect_success 'J: reset existing branch creates empty commit' ' + cat >input <<-INPUT_END && + commit refs/heads/J + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + create J + COMMIT + + from refs/heads/branch + + reset refs/heads/J + + commit refs/heads/J + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + initialize J + COMMIT + + INPUT_END + git fast-import <input +' +test_expect_success 'J: branch has 1 commit, empty tree' ' + test 1 = `git rev-list J | wc -l` && + test 0 = `git ls-tree J | wc -l` +' + +test_expect_success 'J: tag must fail on empty branch' ' + cat >input <<-INPUT_END && + reset refs/heads/J2 + + tag wrong_tag + from refs/heads/J2 + data <<EOF + Tag branch that was reset. + EOF + INPUT_END + test_must_fail git fast-import <input +' + ### ### series K ### -cat >input <<INPUT_END -commit refs/heads/K -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -create K -COMMIT +test_expect_success 'K: reinit branch with from' ' + cat >input <<-INPUT_END && + commit refs/heads/K + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + create K + COMMIT -from refs/heads/branch + from refs/heads/branch -commit refs/heads/K -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -redo K -COMMIT + commit refs/heads/K + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + redo K + COMMIT -from refs/heads/branch^1 + from refs/heads/branch^1 -INPUT_END -test_expect_success \ - 'K: reinit branch with from' \ - 'git fast-import <input' -test_expect_success \ - 'K: verify K^1 = branch^1' \ - 'test `git rev-parse --verify branch^1` \ - = `git rev-parse --verify K^1`' + INPUT_END + git fast-import <input +' +test_expect_success 'K: verify K^1 = branch^1' ' + test `git rev-parse --verify branch^1` \ + = `git rev-parse --verify K^1` +' ### ### series L ### -cat >input <<INPUT_END -blob -mark :1 -data <<EOF -some data -EOF - -blob -mark :2 -data <<EOF -other data -EOF - -commit refs/heads/L -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -create L -COMMIT - -M 644 :1 b. -M 644 :1 b/other -M 644 :1 ba - -commit refs/heads/L -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -update L -COMMIT - -M 644 :2 b. -M 644 :2 b/other -M 644 :2 ba -INPUT_END - -cat >expect <<EXPECT_END -:100644 100644 4268632... 55d3a52... M b. -:040000 040000 0ae5cac... 443c768... M b -:100644 100644 4268632... 55d3a52... M ba -EXPECT_END - -test_expect_success \ - 'L: verify internal tree sorting' \ - 'git fast-import <input && - git diff-tree --abbrev --raw L^ L >output && - test_cmp expect output' - -cat >input <<INPUT_END -blob -mark :1 -data <<EOF -the data -EOF - -commit refs/heads/L2 -committer C O Mitter <committer@example.com> 1112912473 -0700 -data <<COMMIT -init L2 -COMMIT -M 644 :1 a/b/c -M 644 :1 a/b/d -M 644 :1 a/e/f - -commit refs/heads/L2 -committer C O Mitter <committer@example.com> 1112912473 -0700 -data <<COMMIT -update L2 -COMMIT -C a g -C a/e g/b -M 644 :1 g/b/h -INPUT_END - -cat <<EOF >expect -g/b/f -g/b/h -EOF - -test_expect_success \ - 'L: nested tree copy does not corrupt deltas' \ - 'git fast-import <input && +test_expect_success 'L: verify internal tree sorting' ' + cat >input <<-INPUT_END && + blob + mark :1 + data <<EOF + some data + EOF + + blob + mark :2 + data <<EOF + other data + EOF + + commit refs/heads/L + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + create L + COMMIT + + M 644 :1 b. + M 644 :1 b/other + M 644 :1 ba + + commit refs/heads/L + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + update L + COMMIT + + M 644 :2 b. + M 644 :2 b/other + M 644 :2 ba + INPUT_END + + cat >expect <<-EXPECT_END && + :100644 100644 4268632... 55d3a52... M b. + :040000 040000 0ae5cac... 443c768... M b + :100644 100644 4268632... 55d3a52... M ba + EXPECT_END + + git fast-import <input && + git diff-tree --abbrev --raw L^ L >output && + test_cmp expect output +' + +test_expect_success 'L: nested tree copy does not corrupt deltas' ' + cat >input <<-INPUT_END && + blob + mark :1 + data <<EOF + the data + EOF + + commit refs/heads/L2 + committer C O Mitter <committer@example.com> 1112912473 -0700 + data <<COMMIT + init L2 + COMMIT + M 644 :1 a/b/c + M 644 :1 a/b/d + M 644 :1 a/e/f + + commit refs/heads/L2 + committer C O Mitter <committer@example.com> 1112912473 -0700 + data <<COMMIT + update L2 + COMMIT + C a g + C a/e g/b + M 644 :1 g/b/h + INPUT_END + + cat >expect <<-\EOF && + g/b/f + g/b/h + EOF + + test_when_finished "git update-ref -d refs/heads/L2" && + git fast-import <input && git ls-tree L2 g/b/ >tmp && cat tmp | cut -f 2 >actual && test_cmp expect actual && - git fsck `git rev-parse L2`' - -git update-ref -d refs/heads/L2 + git fsck `git rev-parse L2` +' ### ### series M ### -test_tick -cat >input <<INPUT_END -commit refs/heads/M1 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -file rename -COMMIT - -from refs/heads/branch^0 -R file2/newf file2/n.e.w.f - -INPUT_END - -cat >expect <<EOF -:100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc R100 file2/newf file2/n.e.w.f -EOF -test_expect_success \ - 'M: rename file in same subdirectory' \ - 'git fast-import <input && - git diff-tree -M -r M1^ M1 >actual && - compare_diff_raw expect actual' - -cat >input <<INPUT_END -commit refs/heads/M2 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -file rename -COMMIT - -from refs/heads/branch^0 -R file2/newf i/am/new/to/you - -INPUT_END - -cat >expect <<EOF -:100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc R100 file2/newf i/am/new/to/you -EOF -test_expect_success \ - 'M: rename file to new subdirectory' \ - 'git fast-import <input && - git diff-tree -M -r M2^ M2 >actual && - compare_diff_raw expect actual' - -cat >input <<INPUT_END -commit refs/heads/M3 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -file rename -COMMIT - -from refs/heads/M2^0 -R i other/sub - -INPUT_END - -cat >expect <<EOF -:100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc R100 i/am/new/to/you other/sub/am/new/to/you -EOF -test_expect_success \ - 'M: rename subdirectory to new subdirectory' \ - 'git fast-import <input && - git diff-tree -M -r M3^ M3 >actual && - compare_diff_raw expect actual' - -cat >input <<INPUT_END -commit refs/heads/M4 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -rename root -COMMIT - -from refs/heads/M2^0 -R "" sub - -INPUT_END - -cat >expect <<EOF -:100644 100644 7123f7f44e39be127c5eb701e5968176ee9d78b1 7123f7f44e39be127c5eb701e5968176ee9d78b1 R100 file2/oldf sub/file2/oldf -:100755 100755 85df50785d62d3b05ab03d9cbf7e4a0b49449730 85df50785d62d3b05ab03d9cbf7e4a0b49449730 R100 file4 sub/file4 -:100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc R100 i/am/new/to/you sub/i/am/new/to/you -:100755 100755 e74b7d465e52746be2b4bae983670711e6e66657 e74b7d465e52746be2b4bae983670711e6e66657 R100 newdir/exec.sh sub/newdir/exec.sh -:100644 100644 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 R100 newdir/interesting sub/newdir/interesting -EOF -test_expect_success \ - 'M: rename root to subdirectory' \ - 'git fast-import <input && - git diff-tree -M -r M4^ M4 >actual && - cat actual && - compare_diff_raw expect actual' +test_expect_success 'M: rename file in same subdirectory' ' + test_tick && + cat >input <<-INPUT_END && + commit refs/heads/M1 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + file rename + COMMIT + + from refs/heads/branch^0 + R file2/newf file2/n.e.w.f + + INPUT_END + + cat >expect <<-EOF && + :100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc R100 file2/newf file2/n.e.w.f + EOF + git fast-import <input && + git diff-tree -M -r M1^ M1 >actual && + compare_diff_raw expect actual +' + +test_expect_success 'M: rename file to new subdirectory' ' + cat >input <<-INPUT_END && + commit refs/heads/M2 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + file rename + COMMIT + + from refs/heads/branch^0 + R file2/newf i/am/new/to/you + + INPUT_END + + cat >expect <<-EOF && + :100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc R100 file2/newf i/am/new/to/you + EOF + git fast-import <input && + git diff-tree -M -r M2^ M2 >actual && + compare_diff_raw expect actual +' + +test_expect_success 'M: rename subdirectory to new subdirectory' ' + cat >input <<-INPUT_END && + commit refs/heads/M3 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + file rename + COMMIT + + from refs/heads/M2^0 + R i other/sub + + INPUT_END + + cat >expect <<-EOF && + :100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc R100 i/am/new/to/you other/sub/am/new/to/you + EOF + git fast-import <input && + git diff-tree -M -r M3^ M3 >actual && + compare_diff_raw expect actual +' + +test_expect_success 'M: rename root to subdirectory' ' + cat >input <<-INPUT_END && + commit refs/heads/M4 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + rename root + COMMIT + + from refs/heads/M2^0 + R "" sub + + INPUT_END + + cat >expect <<-EOF && + :100644 100644 7123f7f44e39be127c5eb701e5968176ee9d78b1 7123f7f44e39be127c5eb701e5968176ee9d78b1 R100 file2/oldf sub/file2/oldf + :100755 100755 85df50785d62d3b05ab03d9cbf7e4a0b49449730 85df50785d62d3b05ab03d9cbf7e4a0b49449730 R100 file4 sub/file4 + :100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc R100 i/am/new/to/you sub/i/am/new/to/you + :100755 100755 e74b7d465e52746be2b4bae983670711e6e66657 e74b7d465e52746be2b4bae983670711e6e66657 R100 newdir/exec.sh sub/newdir/exec.sh + :100644 100644 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 R100 newdir/interesting sub/newdir/interesting + EOF + git fast-import <input && + git diff-tree -M -r M4^ M4 >actual && + cat actual && + compare_diff_raw expect actual +' ### ### series N ### -test_tick -cat >input <<INPUT_END -commit refs/heads/N1 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -file copy -COMMIT - -from refs/heads/branch^0 -C file2/newf file2/n.e.w.f - -INPUT_END - -cat >expect <<EOF -:100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc C100 file2/newf file2/n.e.w.f -EOF -test_expect_success \ - 'N: copy file in same subdirectory' \ - 'git fast-import <input && - git diff-tree -C --find-copies-harder -r N1^ N1 >actual && - compare_diff_raw expect actual' - -cat >input <<INPUT_END -commit refs/heads/N2 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -clean directory copy -COMMIT - -from refs/heads/branch^0 -C file2 file3 - -commit refs/heads/N2 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -modify directory copy -COMMIT - -M 644 inline file3/file5 -data <<EOF -$file5_data -EOF - -INPUT_END - -cat >expect <<EOF -:100644 100644 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 C100 newdir/interesting file3/file5 -:100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc C100 file2/newf file3/newf -:100644 100644 7123f7f44e39be127c5eb701e5968176ee9d78b1 7123f7f44e39be127c5eb701e5968176ee9d78b1 C100 file2/oldf file3/oldf -EOF -test_expect_success \ - 'N: copy then modify subdirectory' \ - 'git fast-import <input && - git diff-tree -C --find-copies-harder -r N2^^ N2 >actual && - compare_diff_raw expect actual' - -cat >input <<INPUT_END -commit refs/heads/N3 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -dirty directory copy -COMMIT - -from refs/heads/branch^0 -M 644 inline file2/file5 -data <<EOF -$file5_data -EOF - -C file2 file3 -D file2/file5 - -INPUT_END - -test_expect_success \ - 'N: copy dirty subdirectory' \ - 'git fast-import <input && - test `git rev-parse N2^{tree}` = `git rev-parse N3^{tree}`' - -test_expect_success \ - 'N: copy directory by id' \ - 'cat >expect <<-\EOF && +test_expect_success 'N: copy file in same subdirectory' ' + test_tick && + cat >input <<-INPUT_END && + commit refs/heads/N1 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + file copy + COMMIT + + from refs/heads/branch^0 + C file2/newf file2/n.e.w.f + + INPUT_END + + cat >expect <<-EOF && + :100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc C100 file2/newf file2/n.e.w.f + EOF + git fast-import <input && + git diff-tree -C --find-copies-harder -r N1^ N1 >actual && + compare_diff_raw expect actual +' + +test_expect_success 'N: copy then modify subdirectory' ' + cat >input <<-INPUT_END && + commit refs/heads/N2 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + clean directory copy + COMMIT + + from refs/heads/branch^0 + C file2 file3 + + commit refs/heads/N2 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + modify directory copy + COMMIT + + M 644 inline file3/file5 + data <<EOF + $file5_data + EOF + + INPUT_END + + cat >expect <<-EOF && + :100644 100644 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 C100 newdir/interesting file3/file5 :100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc C100 file2/newf file3/newf :100644 100644 7123f7f44e39be127c5eb701e5968176ee9d78b1 7123f7f44e39be127c5eb701e5968176ee9d78b1 C100 file2/oldf file3/oldf EOF - subdir=$(git rev-parse refs/heads/branch^0:file2) && - cat >input <<-INPUT_END && + git fast-import <input && + git diff-tree -C --find-copies-harder -r N2^^ N2 >actual && + compare_diff_raw expect actual +' + +test_expect_success 'N: copy dirty subdirectory' ' + cat >input <<-INPUT_END && + commit refs/heads/N3 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + dirty directory copy + COMMIT + + from refs/heads/branch^0 + M 644 inline file2/file5 + data <<EOF + $file5_data + EOF + + C file2 file3 + D file2/file5 + + INPUT_END + + git fast-import <input && + test `git rev-parse N2^{tree}` = `git rev-parse N3^{tree}` +' + +test_expect_success 'N: copy directory by id' ' + cat >expect <<-\EOF && + :100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc C100 file2/newf file3/newf + :100644 100644 7123f7f44e39be127c5eb701e5968176ee9d78b1 7123f7f44e39be127c5eb701e5968176ee9d78b1 C100 file2/oldf file3/oldf + EOF + subdir=$(git rev-parse refs/heads/branch^0:file2) && + cat >input <<-INPUT_END && commit refs/heads/N4 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE data <<COMMIT @@ -1157,12 +1125,13 @@ test_expect_success \ from refs/heads/branch^0 M 040000 $subdir file3 INPUT_END - git fast-import <input && - git diff-tree -C --find-copies-harder -r N4^ N4 >actual && - compare_diff_raw expect actual' + git fast-import <input && + git diff-tree -C --find-copies-harder -r N4^ N4 >actual && + compare_diff_raw expect actual +' test_expect_success PIPE 'N: read and copy directory' ' - cat >expect <<-\EOF + cat >expect <<-\EOF && :100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc C100 file2/newf file3/newf :100644 100644 7123f7f44e39be127c5eb701e5968176ee9d78b1 7123f7f44e39be127c5eb701e5968176ee9d78b1 C100 file2/oldf file3/oldf EOF @@ -1232,14 +1201,13 @@ test_expect_success PIPE 'N: empty directory reads as missing' ' test_cmp expect actual ' -test_expect_success \ - 'N: copy root directory by tree hash' \ - 'cat >expect <<-\EOF && +test_expect_success 'N: copy root directory by tree hash' ' + cat >expect <<-\EOF && :100755 000000 f1fb5da718392694d0076d677d6d0e364c79b0bc 0000000000000000000000000000000000000000 D file3/newf :100644 000000 7123f7f44e39be127c5eb701e5968176ee9d78b1 0000000000000000000000000000000000000000 D file3/oldf EOF - root=$(git rev-parse refs/heads/branch^0^{tree}) && - cat >input <<-INPUT_END && + root=$(git rev-parse refs/heads/branch^0^{tree}) && + cat >input <<-INPUT_END && commit refs/heads/N6 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE data <<COMMIT @@ -1249,20 +1217,20 @@ test_expect_success \ from refs/heads/branch^0 M 040000 $root "" INPUT_END - git fast-import <input && - git diff-tree -C --find-copies-harder -r N4 N6 >actual && - compare_diff_raw expect actual' + git fast-import <input && + git diff-tree -C --find-copies-harder -r N4 N6 >actual && + compare_diff_raw expect actual +' -test_expect_success \ - 'N: copy root by path' \ - 'cat >expect <<-\EOF && +test_expect_success 'N: copy root by path' ' + cat >expect <<-\EOF && :100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc C100 file2/newf oldroot/file2/newf :100644 100644 7123f7f44e39be127c5eb701e5968176ee9d78b1 7123f7f44e39be127c5eb701e5968176ee9d78b1 C100 file2/oldf oldroot/file2/oldf :100755 100755 85df50785d62d3b05ab03d9cbf7e4a0b49449730 85df50785d62d3b05ab03d9cbf7e4a0b49449730 C100 file4 oldroot/file4 :100755 100755 e74b7d465e52746be2b4bae983670711e6e66657 e74b7d465e52746be2b4bae983670711e6e66657 C100 newdir/exec.sh oldroot/newdir/exec.sh :100644 100644 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 C100 newdir/interesting oldroot/newdir/interesting EOF - cat >input <<-INPUT_END && + cat >input <<-INPUT_END && commit refs/heads/N-copy-root-path committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE data <<COMMIT @@ -1272,21 +1240,21 @@ test_expect_success \ from refs/heads/branch^0 C "" oldroot INPUT_END - git fast-import <input && - git diff-tree -C --find-copies-harder -r branch N-copy-root-path >actual && - compare_diff_raw expect actual' + git fast-import <input && + git diff-tree -C --find-copies-harder -r branch N-copy-root-path >actual && + compare_diff_raw expect actual +' -test_expect_success \ - 'N: delete directory by copying' \ - 'cat >expect <<-\EOF && +test_expect_success 'N: delete directory by copying' ' + cat >expect <<-\EOF && OBJID :100644 000000 OBJID OBJID D foo/bar/qux OBJID :000000 100644 OBJID OBJID A foo/bar/baz :000000 100644 OBJID OBJID A foo/bar/qux EOF - empty_tree=$(git mktree </dev/null) && - cat >input <<-INPUT_END && + empty_tree=$(git mktree </dev/null) && + cat >input <<-INPUT_END && commit refs/heads/N-delete committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE data <<COMMIT @@ -1312,21 +1280,21 @@ test_expect_success \ M 040000 $empty_tree foo/bar/qux INPUT_END - git fast-import <input && - git rev-list N-delete | + git fast-import <input && + git rev-list N-delete | git diff-tree -r --stdin --root --always | sed -e "s/$_x40/OBJID/g" >actual && - test_cmp expect actual' + test_cmp expect actual +' -test_expect_success \ - 'N: modify copied tree' \ - 'cat >expect <<-\EOF && +test_expect_success 'N: modify copied tree' ' + cat >expect <<-\EOF && :100644 100644 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 C100 newdir/interesting file3/file5 :100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc C100 file2/newf file3/newf :100644 100644 7123f7f44e39be127c5eb701e5968176ee9d78b1 7123f7f44e39be127c5eb701e5968176ee9d78b1 C100 file2/oldf file3/oldf EOF - subdir=$(git rev-parse refs/heads/branch^0:file2) && - cat >input <<-INPUT_END && + subdir=$(git rev-parse refs/heads/branch^0:file2) && + cat >input <<-INPUT_END && commit refs/heads/N5 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE data <<COMMIT @@ -1347,14 +1315,14 @@ test_expect_success \ $file5_data EOF INPUT_END - git fast-import <input && - git diff-tree -C --find-copies-harder -r N5^^ N5 >actual && - compare_diff_raw expect actual' - -test_expect_success \ - 'N: reject foo/ syntax' \ - 'subdir=$(git rev-parse refs/heads/branch^0:file2) && - test_must_fail git fast-import <<-INPUT_END + git fast-import <input && + git diff-tree -C --find-copies-harder -r N5^^ N5 >actual && + compare_diff_raw expect actual +' + +test_expect_success 'N: reject foo/ syntax' ' + subdir=$(git rev-parse refs/heads/branch^0:file2) && + test_must_fail git fast-import <<-INPUT_END commit refs/heads/N5B committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE data <<COMMIT @@ -1363,11 +1331,11 @@ test_expect_success \ from refs/heads/branch^0 M 040000 $subdir file3/ - INPUT_END' + INPUT_END +' -test_expect_success \ - 'N: reject foo/ syntax in copy source' \ - 'test_must_fail git fast-import <<-INPUT_END +test_expect_success 'N: reject foo/ syntax in copy source' ' + test_must_fail git fast-import <<-INPUT_END commit refs/heads/N5C committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE data <<COMMIT @@ -1376,11 +1344,11 @@ test_expect_success \ from refs/heads/branch^0 C file2/ file3 - INPUT_END' + INPUT_END +' -test_expect_success \ - 'N: reject foo/ syntax in rename source' \ - 'test_must_fail git fast-import <<-INPUT_END +test_expect_success 'N: reject foo/ syntax in rename source' ' + test_must_fail git fast-import <<-INPUT_END commit refs/heads/N5D committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE data <<COMMIT @@ -1389,11 +1357,11 @@ test_expect_success \ from refs/heads/branch^0 R file2/ file3 - INPUT_END' + INPUT_END +' -test_expect_success \ - 'N: reject foo/ syntax in ls argument' \ - 'test_must_fail git fast-import <<-INPUT_END +test_expect_success 'N: reject foo/ syntax in ls argument' ' + test_must_fail git fast-import <<-INPUT_END commit refs/heads/N5E committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE data <<COMMIT @@ -1402,13 +1370,13 @@ test_expect_success \ from refs/heads/branch^0 ls "file2/" - INPUT_END' + INPUT_END +' -test_expect_success \ - 'N: copy to root by id and modify' \ - 'echo "hello, world" >expect.foo && - echo hello >expect.bar && - git fast-import <<-SETUP_END && +test_expect_success 'N: copy to root by id and modify' ' + echo "hello, world" >expect.foo && + echo hello >expect.bar && + git fast-import <<-SETUP_END && commit refs/heads/N7 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE data <<COMMIT @@ -1422,8 +1390,8 @@ test_expect_success \ EOF SETUP_END - tree=$(git rev-parse --verify N7:) && - git fast-import <<-INPUT_END && + tree=$(git rev-parse --verify N7:) && + git fast-import <<-INPUT_END && commit refs/heads/N8 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE data <<COMMIT @@ -1436,15 +1404,15 @@ test_expect_success \ hello, world EOF INPUT_END - git show N8:foo/foo >actual.foo && - git show N8:foo/bar >actual.bar && - test_cmp expect.foo actual.foo && - test_cmp expect.bar actual.bar' - -test_expect_success \ - 'N: extract subtree' \ - 'branch=$(git rev-parse --verify refs/heads/branch^{tree}) && - cat >input <<-INPUT_END && + git show N8:foo/foo >actual.foo && + git show N8:foo/bar >actual.bar && + test_cmp expect.foo actual.foo && + test_cmp expect.bar actual.bar +' + +test_expect_success 'N: extract subtree' ' + branch=$(git rev-parse --verify refs/heads/branch^{tree}) && + cat >input <<-INPUT_END && commit refs/heads/N9 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE data <<COMMIT @@ -1454,14 +1422,14 @@ test_expect_success \ M 040000 $branch "" C "newdir" "" INPUT_END - git fast-import <input && - git diff --exit-code branch:newdir N9' - -test_expect_success \ - 'N: modify subtree, extract it, and modify again' \ - 'echo hello >expect.baz && - echo hello, world >expect.qux && - git fast-import <<-SETUP_END && + git fast-import <input && + git diff --exit-code branch:newdir N9 +' + +test_expect_success 'N: modify subtree, extract it, and modify again' ' + echo hello >expect.baz && + echo hello, world >expect.qux && + git fast-import <<-SETUP_END && commit refs/heads/N10 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE data <<COMMIT @@ -1475,8 +1443,8 @@ test_expect_success \ EOF SETUP_END - tree=$(git rev-parse --verify N10:) && - git fast-import <<-INPUT_END && + tree=$(git rev-parse --verify N10:) && + git fast-import <<-INPUT_END && commit refs/heads/N11 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE data <<COMMIT @@ -1491,676 +1459,692 @@ test_expect_success \ R "foo" "" C "bar/qux" "bar/quux" INPUT_END - git show N11:bar/baz >actual.baz && - git show N11:bar/qux >actual.qux && - git show N11:bar/quux >actual.quux && - test_cmp expect.baz actual.baz && - test_cmp expect.qux actual.qux && - test_cmp expect.qux actual.quux' + git show N11:bar/baz >actual.baz && + git show N11:bar/qux >actual.qux && + git show N11:bar/quux >actual.quux && + test_cmp expect.baz actual.baz && + test_cmp expect.qux actual.qux && + test_cmp expect.qux actual.quux' ### ### series O ### -cat >input <<INPUT_END -#we will -commit refs/heads/O1 -# -- ignore all of this text -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -# $GIT_COMMITTER_NAME has inserted here for his benefit. -data <<COMMIT -dirty directory copy -COMMIT - -# don't forget the import blank line! -# -# yes, we started from our usual base of branch^0. -# i like branch^0. -from refs/heads/branch^0 -# and we need to reuse file2/file5 from N3 above. -M 644 inline file2/file5 -# otherwise the tree will be different -data <<EOF -$file5_data -EOF - -# don't forget to copy file2 to file3 -C file2 file3 -# -# or to delete file5 from file2. -D file2/file5 -# are we done yet? - -INPUT_END - -test_expect_success \ - 'O: comments are all skipped' \ - 'git fast-import <input && - test `git rev-parse N3` = `git rev-parse O1`' - -cat >input <<INPUT_END -commit refs/heads/O2 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -dirty directory copy -COMMIT -from refs/heads/branch^0 -M 644 inline file2/file5 -data <<EOF -$file5_data -EOF -C file2 file3 -D file2/file5 - -INPUT_END - -test_expect_success \ - 'O: blank lines not necessary after data commands' \ - 'git fast-import <input && - test `git rev-parse N3` = `git rev-parse O2`' - -test_expect_success \ - 'O: repack before next test' \ - 'git repack -a -d' - -cat >input <<INPUT_END -commit refs/heads/O3 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -zstring -COMMIT -commit refs/heads/O3 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -zof -COMMIT -checkpoint -commit refs/heads/O3 -mark :5 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -zempty -COMMIT -checkpoint -commit refs/heads/O3 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -zcommits -COMMIT -reset refs/tags/O3-2nd -from :5 -reset refs/tags/O3-3rd -from :5 -INPUT_END - -cat >expect <<INPUT_END -string -of -empty -commits -INPUT_END -test_expect_success \ - 'O: blank lines not necessary after other commands' \ - 'git fast-import <input && - test 8 = `find .git/objects/pack -type f | wc -l` && - test `git rev-parse refs/tags/O3-2nd` = `git rev-parse O3^` && - git log --reverse --pretty=oneline O3 | sed s/^.*z// >actual && - test_cmp expect actual' - -cat >input <<INPUT_END -commit refs/heads/O4 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -zstring -COMMIT -commit refs/heads/O4 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -zof -COMMIT -progress Two commits down, 2 to go! -commit refs/heads/O4 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -zempty -COMMIT -progress Three commits down, 1 to go! -commit refs/heads/O4 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -zcommits -COMMIT -progress I'm done! -INPUT_END -test_expect_success \ - 'O: progress outputs as requested by input' \ - 'git fast-import <input >actual && - grep "progress " <input >expect && - test_cmp expect actual' +test_expect_success 'O: comments are all skipped' ' + cat >input <<-INPUT_END && + #we will + commit refs/heads/O1 + # -- ignore all of this text + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + # $GIT_COMMITTER_NAME has inserted here for his benefit. + data <<COMMIT + dirty directory copy + COMMIT + + # do not forget the import blank line! + # + # yes, we started from our usual base of branch^0. + # i like branch^0. + from refs/heads/branch^0 + # and we need to reuse file2/file5 from N3 above. + M 644 inline file2/file5 + # otherwise the tree will be different + data <<EOF + $file5_data + EOF + + # do not forget to copy file2 to file3 + C file2 file3 + # + # or to delete file5 from file2. + D file2/file5 + # are we done yet? + + INPUT_END + + git fast-import <input && + test `git rev-parse N3` = `git rev-parse O1` +' + +test_expect_success 'O: blank lines not necessary after data commands' ' + cat >input <<-INPUT_END && + commit refs/heads/O2 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + dirty directory copy + COMMIT + from refs/heads/branch^0 + M 644 inline file2/file5 + data <<EOF + $file5_data + EOF + C file2 file3 + D file2/file5 + + INPUT_END + + git fast-import <input && + test `git rev-parse N3` = `git rev-parse O2` +' + +test_expect_success 'O: repack before next test' ' + git repack -a -d +' + +test_expect_success 'O: blank lines not necessary after other commands' ' + cat >input <<-INPUT_END && + commit refs/heads/O3 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + zstring + COMMIT + commit refs/heads/O3 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + zof + COMMIT + checkpoint + commit refs/heads/O3 + mark :5 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + zempty + COMMIT + checkpoint + commit refs/heads/O3 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + zcommits + COMMIT + reset refs/tags/O3-2nd + from :5 + reset refs/tags/O3-3rd + from :5 + INPUT_END + + cat >expect <<-INPUT_END && + string + of + empty + commits + INPUT_END + + git fast-import <input && + test 8 = `find .git/objects/pack -type f | wc -l` && + test `git rev-parse refs/tags/O3-2nd` = `git rev-parse O3^` && + git log --reverse --pretty=oneline O3 | sed s/^.*z// >actual && + test_cmp expect actual +' + +test_expect_success 'O: progress outputs as requested by input' ' + cat >input <<-INPUT_END && + commit refs/heads/O4 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + zstring + COMMIT + commit refs/heads/O4 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + zof + COMMIT + progress Two commits down, 2 to go! + commit refs/heads/O4 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + zempty + COMMIT + progress Three commits down, 1 to go! + commit refs/heads/O4 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + zcommits + COMMIT + progress done! + INPUT_END + git fast-import <input >actual && + grep "progress " <input >expect && + test_cmp expect actual +' ### ### series P (gitlinks) ### -cat >input <<INPUT_END -blob -mark :1 -data 10 -test file - -reset refs/heads/sub -commit refs/heads/sub -mark :2 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data 12 -sub_initial -M 100644 :1 file - -blob -mark :3 -data <<DATAEND -[submodule "sub"] - path = sub - url = "`pwd`/sub" -DATAEND - -commit refs/heads/subuse1 -mark :4 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data 8 -initial -from refs/heads/master -M 100644 :3 .gitmodules -M 160000 :2 sub - -blob -mark :5 -data 20 -test file -more data - -commit refs/heads/sub -mark :6 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data 11 -sub_second -from :2 -M 100644 :5 file - -commit refs/heads/subuse1 -mark :7 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data 7 -second -from :4 -M 160000 :6 sub - -INPUT_END - -test_expect_success \ - 'P: superproject & submodule mix' \ - 'git fast-import <input && - git checkout subuse1 && - rm -rf sub && mkdir sub && (cd sub && - git init && - git fetch --update-head-ok .. refs/heads/sub:refs/heads/master && - git checkout master) && - git submodule init && - git submodule update' - -SUBLAST=$(git rev-parse --verify sub) -SUBPREV=$(git rev-parse --verify sub^) - -cat >input <<INPUT_END -blob -mark :1 -data <<DATAEND -[submodule "sub"] - path = sub - url = "`pwd`/sub" -DATAEND - -commit refs/heads/subuse2 -mark :2 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data 8 -initial -from refs/heads/master -M 100644 :1 .gitmodules -M 160000 $SUBPREV sub - -commit refs/heads/subuse2 -mark :3 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data 7 -second -from :2 -M 160000 $SUBLAST sub - -INPUT_END - -test_expect_success \ - 'P: verbatim SHA gitlinks' \ - 'git branch -D sub && - git gc && git prune && - git fast-import <input && - test $(git rev-parse --verify subuse2) = $(git rev-parse --verify subuse1)' - -test_tick -cat >input <<INPUT_END -commit refs/heads/subuse3 -mark :1 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -corrupt -COMMIT - -from refs/heads/subuse2 -M 160000 inline sub -data <<DATA -$SUBPREV -DATA - -INPUT_END +test_expect_success 'P: superproject & submodule mix' ' + cat >input <<-INPUT_END && + blob + mark :1 + data 10 + test file -test_expect_success 'P: fail on inline gitlink' ' - test_must_fail git fast-import <input' + reset refs/heads/sub + commit refs/heads/sub + mark :2 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data 12 + sub_initial + M 100644 :1 file -test_tick -cat >input <<INPUT_END -blob -mark :1 -data <<DATA -$SUBPREV -DATA + blob + mark :3 + data <<DATAEND + [submodule "sub"] + path = sub + url = "`pwd`/sub" + DATAEND + + commit refs/heads/subuse1 + mark :4 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data 8 + initial + from refs/heads/master + M 100644 :3 .gitmodules + M 160000 :2 sub + + blob + mark :5 + data 20 + test file + more data -commit refs/heads/subuse3 -mark :2 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -corrupt -COMMIT + commit refs/heads/sub + mark :6 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data 11 + sub_second + from :2 + M 100644 :5 file -from refs/heads/subuse2 -M 160000 :1 sub + commit refs/heads/subuse1 + mark :7 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data 7 + second + from :4 + M 160000 :6 sub + + INPUT_END -INPUT_END + git fast-import <input && + git checkout subuse1 && + rm -rf sub && + mkdir sub && + ( + cd sub && + git init && + git fetch --update-head-ok .. refs/heads/sub:refs/heads/master && + git checkout master + ) && + git submodule init && + git submodule update +' + +test_expect_success 'P: verbatim SHA gitlinks' ' + SUBLAST=$(git rev-parse --verify sub) && + SUBPREV=$(git rev-parse --verify sub^) && + + cat >input <<-INPUT_END && + blob + mark :1 + data <<DATAEND + [submodule "sub"] + path = sub + url = "`pwd`/sub" + DATAEND + + commit refs/heads/subuse2 + mark :2 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data 8 + initial + from refs/heads/master + M 100644 :1 .gitmodules + M 160000 $SUBPREV sub + + commit refs/heads/subuse2 + mark :3 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data 7 + second + from :2 + M 160000 $SUBLAST sub + + INPUT_END + + git branch -D sub && + git gc && + git prune && + git fast-import <input && + test $(git rev-parse --verify subuse2) = $(git rev-parse --verify subuse1) +' + +test_expect_success 'P: fail on inline gitlink' ' + test_tick && + cat >input <<-INPUT_END && + commit refs/heads/subuse3 + mark :1 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + corrupt + COMMIT + + from refs/heads/subuse2 + M 160000 inline sub + data <<DATA + $SUBPREV + DATA + + INPUT_END + + test_must_fail git fast-import <input +' test_expect_success 'P: fail on blob mark in gitlink' ' - test_must_fail git fast-import <input' + test_tick && + cat >input <<-INPUT_END && + blob + mark :1 + data <<DATA + $SUBPREV + DATA + + commit refs/heads/subuse3 + mark :2 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + corrupt + COMMIT + + from refs/heads/subuse2 + M 160000 :1 sub + + INPUT_END + + test_must_fail git fast-import <input +' ### ### series Q (notes) ### -note1_data="The first note for the first commit" -note2_data="The first note for the second commit" -note3_data="The first note for the third commit" -note1b_data="The second note for the first commit" -note1c_data="The third note for the first commit" -note2b_data="The second note for the second commit" - -test_tick -cat >input <<INPUT_END -blob -mark :2 -data <<EOF -$file2_data -EOF - -commit refs/heads/notes-test -mark :3 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -first (:3) -COMMIT - -M 644 :2 file2 - -blob -mark :4 -data $file4_len -$file4_data -commit refs/heads/notes-test -mark :5 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -second (:5) -COMMIT - -M 644 :4 file4 - -commit refs/heads/notes-test -mark :6 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -third (:6) -COMMIT - -M 644 inline file5 -data <<EOF -$file5_data -EOF - -M 755 inline file6 -data <<EOF -$file6_data -EOF - -blob -mark :7 -data <<EOF -$note1_data -EOF - -blob -mark :8 -data <<EOF -$note2_data -EOF - -commit refs/notes/foobar -mark :9 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -notes (:9) -COMMIT - -N :7 :3 -N :8 :5 -N inline :6 -data <<EOF -$note3_data -EOF - -commit refs/notes/foobar -mark :10 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -notes (:10) -COMMIT - -N inline :3 -data <<EOF -$note1b_data -EOF - -commit refs/notes/foobar2 -mark :11 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -notes (:11) -COMMIT - -N inline :3 -data <<EOF -$note1c_data -EOF - -commit refs/notes/foobar -mark :12 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -notes (:12) -COMMIT - -deleteall -N inline :5 -data <<EOF -$note2b_data -EOF - -INPUT_END - -test_expect_success \ - 'Q: commit notes' \ - 'git fast-import <input && - git whatchanged notes-test' +test_expect_success 'Q: commit notes' ' + note1_data="The first note for the first commit" && + note2_data="The first note for the second commit" && + note3_data="The first note for the third commit" && + note1b_data="The second note for the first commit" && + note1c_data="The third note for the first commit" && + note2b_data="The second note for the second commit" && + + test_tick && + cat >input <<-INPUT_END && + blob + mark :2 + data <<EOF + $file2_data + EOF + + commit refs/heads/notes-test + mark :3 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + first (:3) + COMMIT + + M 644 :2 file2 + + blob + mark :4 + data $file4_len + $file4_data + commit refs/heads/notes-test + mark :5 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + second (:5) + COMMIT + + M 644 :4 file4 + + commit refs/heads/notes-test + mark :6 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + third (:6) + COMMIT + + M 644 inline file5 + data <<EOF + $file5_data + EOF + + M 755 inline file6 + data <<EOF + $file6_data + EOF + + blob + mark :7 + data <<EOF + $note1_data + EOF + + blob + mark :8 + data <<EOF + $note2_data + EOF + + commit refs/notes/foobar + mark :9 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + notes (:9) + COMMIT + + N :7 :3 + N :8 :5 + N inline :6 + data <<EOF + $note3_data + EOF + + commit refs/notes/foobar + mark :10 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + notes (:10) + COMMIT + + N inline :3 + data <<EOF + $note1b_data + EOF + + commit refs/notes/foobar2 + mark :11 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + notes (:11) + COMMIT + + N inline :3 + data <<EOF + $note1c_data + EOF + + commit refs/notes/foobar + mark :12 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + notes (:12) + COMMIT + + deleteall + N inline :5 + data <<EOF + $note2b_data + EOF + + INPUT_END + + git fast-import <input && + git whatchanged notes-test +' test_expect_success 'Q: verify pack' ' verify_packs ' -commit1=$(git rev-parse notes-test~2) -commit2=$(git rev-parse notes-test^) -commit3=$(git rev-parse notes-test) - -cat >expect <<EOF -author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE - -first (:3) -EOF -test_expect_success \ - 'Q: verify first commit' \ - 'git cat-file commit notes-test~2 | sed 1d >actual && - test_cmp expect actual' - -cat >expect <<EOF -parent $commit1 -author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE - -second (:5) -EOF -test_expect_success \ - 'Q: verify second commit' \ - 'git cat-file commit notes-test^ | sed 1d >actual && - test_cmp expect actual' - -cat >expect <<EOF -parent $commit2 -author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE - -third (:6) -EOF -test_expect_success \ - 'Q: verify third commit' \ - 'git cat-file commit notes-test | sed 1d >actual && - test_cmp expect actual' - -cat >expect <<EOF -author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE - -notes (:9) -EOF -test_expect_success \ - 'Q: verify first notes commit' \ - 'git cat-file commit refs/notes/foobar~2 | sed 1d >actual && - test_cmp expect actual' - -cat >expect.unsorted <<EOF -100644 blob $commit1 -100644 blob $commit2 -100644 blob $commit3 -EOF -cat expect.unsorted | sort >expect -test_expect_success \ - 'Q: verify first notes tree' \ - 'git cat-file -p refs/notes/foobar~2^{tree} | sed "s/ [0-9a-f]* / /" >actual && - test_cmp expect actual' - -echo "$note1_data" >expect -test_expect_success \ - 'Q: verify first note for first commit' \ - 'git cat-file blob refs/notes/foobar~2:$commit1 >actual && test_cmp expect actual' - -echo "$note2_data" >expect -test_expect_success \ - 'Q: verify first note for second commit' \ - 'git cat-file blob refs/notes/foobar~2:$commit2 >actual && test_cmp expect actual' - -echo "$note3_data" >expect -test_expect_success \ - 'Q: verify first note for third commit' \ - 'git cat-file blob refs/notes/foobar~2:$commit3 >actual && test_cmp expect actual' - -cat >expect <<EOF -parent `git rev-parse --verify refs/notes/foobar~2` -author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE - -notes (:10) -EOF -test_expect_success \ - 'Q: verify second notes commit' \ - 'git cat-file commit refs/notes/foobar^ | sed 1d >actual && - test_cmp expect actual' - -cat >expect.unsorted <<EOF -100644 blob $commit1 -100644 blob $commit2 -100644 blob $commit3 -EOF -cat expect.unsorted | sort >expect -test_expect_success \ - 'Q: verify second notes tree' \ - 'git cat-file -p refs/notes/foobar^^{tree} | sed "s/ [0-9a-f]* / /" >actual && - test_cmp expect actual' - -echo "$note1b_data" >expect -test_expect_success \ - 'Q: verify second note for first commit' \ - 'git cat-file blob refs/notes/foobar^:$commit1 >actual && test_cmp expect actual' - -echo "$note2_data" >expect -test_expect_success \ - 'Q: verify first note for second commit' \ - 'git cat-file blob refs/notes/foobar^:$commit2 >actual && test_cmp expect actual' - -echo "$note3_data" >expect -test_expect_success \ - 'Q: verify first note for third commit' \ - 'git cat-file blob refs/notes/foobar^:$commit3 >actual && test_cmp expect actual' - -cat >expect <<EOF -author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE - -notes (:11) -EOF -test_expect_success \ - 'Q: verify third notes commit' \ - 'git cat-file commit refs/notes/foobar2 | sed 1d >actual && - test_cmp expect actual' - -cat >expect.unsorted <<EOF -100644 blob $commit1 -EOF -cat expect.unsorted | sort >expect -test_expect_success \ - 'Q: verify third notes tree' \ - 'git cat-file -p refs/notes/foobar2^{tree} | sed "s/ [0-9a-f]* / /" >actual && - test_cmp expect actual' - -echo "$note1c_data" >expect -test_expect_success \ - 'Q: verify third note for first commit' \ - 'git cat-file blob refs/notes/foobar2:$commit1 >actual && test_cmp expect actual' - -cat >expect <<EOF -parent `git rev-parse --verify refs/notes/foobar^` -author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE - -notes (:12) -EOF -test_expect_success \ - 'Q: verify fourth notes commit' \ - 'git cat-file commit refs/notes/foobar | sed 1d >actual && - test_cmp expect actual' - -cat >expect.unsorted <<EOF -100644 blob $commit2 -EOF -cat expect.unsorted | sort >expect -test_expect_success \ - 'Q: verify fourth notes tree' \ - 'git cat-file -p refs/notes/foobar^{tree} | sed "s/ [0-9a-f]* / /" >actual && - test_cmp expect actual' - -echo "$note2b_data" >expect -test_expect_success \ - 'Q: verify second note for second commit' \ - 'git cat-file blob refs/notes/foobar:$commit2 >actual && test_cmp expect actual' - -cat >input <<EOF -reset refs/heads/Q0 - -commit refs/heads/note-Q0 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -Note for an empty branch. -COMMIT - -N inline refs/heads/Q0 -data <<NOTE -some note -NOTE -EOF -test_expect_success \ - 'Q: deny note on empty branch' \ - 'test_must_fail git fast-import <input' +test_expect_success 'Q: verify first commit' ' + commit1=$(git rev-parse notes-test~2) && + commit2=$(git rev-parse notes-test^) && + commit3=$(git rev-parse notes-test) && + + cat >expect <<-EOF && + author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + + first (:3) + EOF + git cat-file commit notes-test~2 | sed 1d >actual && + test_cmp expect actual +' + +test_expect_success 'Q: verify second commit' ' + cat >expect <<-EOF && + parent $commit1 + author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + + second (:5) + EOF + git cat-file commit notes-test^ | sed 1d >actual && + test_cmp expect actual +' + +test_expect_success 'Q: verify third commit' ' + cat >expect <<-EOF && + parent $commit2 + author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + + third (:6) + EOF + git cat-file commit notes-test | sed 1d >actual && + test_cmp expect actual +' + +test_expect_success 'Q: verify first notes commit' ' + cat >expect <<-EOF && + author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + + notes (:9) + EOF + git cat-file commit refs/notes/foobar~2 | sed 1d >actual && + test_cmp expect actual +' + +test_expect_success 'Q: verify first notes tree' ' + cat >expect.unsorted <<-EOF && + 100644 blob $commit1 + 100644 blob $commit2 + 100644 blob $commit3 + EOF + cat expect.unsorted | sort >expect && + git cat-file -p refs/notes/foobar~2^{tree} | sed "s/ [0-9a-f]* / /" >actual && + test_cmp expect actual +' + +test_expect_success 'Q: verify first note for first commit' ' + echo "$note1_data" >expect && + git cat-file blob refs/notes/foobar~2:$commit1 >actual && + test_cmp expect actual +' + +test_expect_success 'Q: verify first note for second commit' ' + echo "$note2_data" >expect && + git cat-file blob refs/notes/foobar~2:$commit2 >actual && + test_cmp expect actual +' + +test_expect_success 'Q: verify first note for third commit' ' + echo "$note3_data" >expect && + git cat-file blob refs/notes/foobar~2:$commit3 >actual && + test_cmp expect actual +' + +test_expect_success 'Q: verify second notes commit' ' + cat >expect <<-EOF && + parent `git rev-parse --verify refs/notes/foobar~2` + author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + + notes (:10) + EOF + git cat-file commit refs/notes/foobar^ | sed 1d >actual && + test_cmp expect actual +' + +test_expect_success 'Q: verify second notes tree' ' + cat >expect.unsorted <<-EOF && + 100644 blob $commit1 + 100644 blob $commit2 + 100644 blob $commit3 + EOF + cat expect.unsorted | sort >expect && + git cat-file -p refs/notes/foobar^^{tree} | sed "s/ [0-9a-f]* / /" >actual && + test_cmp expect actual +' + +test_expect_success 'Q: verify second note for first commit' ' + echo "$note1b_data" >expect && + git cat-file blob refs/notes/foobar^:$commit1 >actual && + test_cmp expect actual +' + +test_expect_success 'Q: verify first note for second commit' ' + echo "$note2_data" >expect && + git cat-file blob refs/notes/foobar^:$commit2 >actual && + test_cmp expect actual +' + +test_expect_success 'Q: verify first note for third commit' ' + echo "$note3_data" >expect && + git cat-file blob refs/notes/foobar^:$commit3 >actual && + test_cmp expect actual +' + +test_expect_success 'Q: verify third notes commit' ' + cat >expect <<-EOF && + author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + + notes (:11) + EOF + git cat-file commit refs/notes/foobar2 | sed 1d >actual && + test_cmp expect actual +' + +test_expect_success 'Q: verify third notes tree' ' + cat >expect.unsorted <<-EOF && + 100644 blob $commit1 + EOF + cat expect.unsorted | sort >expect && + git cat-file -p refs/notes/foobar2^{tree} | sed "s/ [0-9a-f]* / /" >actual && + test_cmp expect actual +' + +test_expect_success 'Q: verify third note for first commit' ' + echo "$note1c_data" >expect && + git cat-file blob refs/notes/foobar2:$commit1 >actual && + test_cmp expect actual +' + +test_expect_success 'Q: verify fourth notes commit' ' + cat >expect <<-EOF && + parent `git rev-parse --verify refs/notes/foobar^` + author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + + notes (:12) + EOF + git cat-file commit refs/notes/foobar | sed 1d >actual && + test_cmp expect actual +' + +test_expect_success 'Q: verify fourth notes tree' ' + cat >expect.unsorted <<-EOF && + 100644 blob $commit2 + EOF + cat expect.unsorted | sort >expect && + git cat-file -p refs/notes/foobar^{tree} | sed "s/ [0-9a-f]* / /" >actual && + test_cmp expect actual +' + +test_expect_success 'Q: verify second note for second commit' ' + echo "$note2b_data" >expect && + git cat-file blob refs/notes/foobar:$commit2 >actual && + test_cmp expect actual +' + +test_expect_success 'Q: deny note on empty branch' ' + cat >input <<-EOF && + reset refs/heads/Q0 + + commit refs/heads/note-Q0 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + Note for an empty branch. + COMMIT + + N inline refs/heads/Q0 + data <<NOTE + some note + NOTE + EOF + test_must_fail git fast-import <input +' ### ### series R (feature and option) ### -cat >input <<EOF -feature no-such-feature-exists -EOF - test_expect_success 'R: abort on unsupported feature' ' + cat >input <<-EOF && + feature no-such-feature-exists + EOF + test_must_fail git fast-import <input ' -cat >input <<EOF -feature date-format=now -EOF - test_expect_success 'R: supported feature is accepted' ' + cat >input <<-EOF && + feature date-format=now + EOF + git fast-import <input ' -cat >input << EOF -blob -data 3 -hi -feature date-format=now -EOF - test_expect_success 'R: abort on receiving feature after data command' ' + cat >input <<-EOF && + blob + data 3 + hi + feature date-format=now + EOF + test_must_fail git fast-import <input ' -cat >input << EOF -feature import-marks=git.marks -feature import-marks=git2.marks -EOF - test_expect_success 'R: only one import-marks feature allowed per stream' ' + cat >input <<-EOF && + feature import-marks=git.marks + feature import-marks=git2.marks + EOF + test_must_fail git fast-import <input ' -cat >input << EOF -feature export-marks=git.marks -blob -mark :1 -data 3 -hi +test_expect_success 'R: export-marks feature results in a marks file being created' ' + cat >input <<-EOF && + feature export-marks=git.marks + blob + mark :1 + data 3 + hi -EOF + EOF -test_expect_success \ - 'R: export-marks feature results in a marks file being created' \ - 'cat input | git fast-import && - grep :1 git.marks' + cat input | git fast-import && + grep :1 git.marks +' -test_expect_success \ - 'R: export-marks options can be overridden by commandline options' \ - 'cat input | git fast-import --export-marks=other.marks && - grep :1 other.marks' +test_expect_success 'R: export-marks options can be overridden by commandline options' ' + cat input | git fast-import --export-marks=other.marks && + grep :1 other.marks +' test_expect_success 'R: catch typo in marks file name' ' test_must_fail git fast-import --import-marks=nonexistent.marks </dev/null && @@ -2258,68 +2242,68 @@ test_expect_success 'R: feature import-marks-if-exists' ' >expect && git fast-import --import-marks-if-exists=not_io.marks \ - --export-marks=io.marks <<-\EOF + --export-marks=io.marks <<-\EOF && feature import-marks-if-exists=io.marks EOF test_cmp expect io.marks ' -cat >input << EOF -feature import-marks=marks.out -feature export-marks=marks.new -EOF - -test_expect_success \ - 'R: import to output marks works without any content' \ - 'cat input | git fast-import && - test_cmp marks.out marks.new' +test_expect_success 'R: import to output marks works without any content' ' + cat >input <<-EOF && + feature import-marks=marks.out + feature export-marks=marks.new + EOF -cat >input <<EOF -feature import-marks=nonexistent.marks -feature export-marks=marks.new -EOF + cat input | git fast-import && + test_cmp marks.out marks.new +' -test_expect_success \ - 'R: import marks prefers commandline marks file over the stream' \ - 'cat input | git fast-import --import-marks=marks.out && - test_cmp marks.out marks.new' +test_expect_success 'R: import marks prefers commandline marks file over the stream' ' + cat >input <<-EOF && + feature import-marks=nonexistent.marks + feature export-marks=marks.new + EOF + cat input | git fast-import --import-marks=marks.out && + test_cmp marks.out marks.new +' -cat >input <<EOF -feature import-marks=nonexistent.marks -feature export-marks=combined.marks -EOF test_expect_success 'R: multiple --import-marks= should be honoured' ' - head -n2 marks.out > one.marks && - tail -n +3 marks.out > two.marks && - git fast-import --import-marks=one.marks --import-marks=two.marks <input && - test_cmp marks.out combined.marks -' + cat >input <<-EOF && + feature import-marks=nonexistent.marks + feature export-marks=combined.marks + EOF -cat >input <<EOF -feature relative-marks -feature import-marks=relative.in -feature export-marks=relative.out -EOF + head -n2 marks.out > one.marks && + tail -n +3 marks.out > two.marks && + git fast-import --import-marks=one.marks --import-marks=two.marks <input && + test_cmp marks.out combined.marks +' test_expect_success 'R: feature relative-marks should be honoured' ' - mkdir -p .git/info/fast-import/ && - cp marks.new .git/info/fast-import/relative.in && - git fast-import <input && - test_cmp marks.new .git/info/fast-import/relative.out -' + cat >input <<-EOF && + feature relative-marks + feature import-marks=relative.in + feature export-marks=relative.out + EOF -cat >input <<EOF -feature relative-marks -feature import-marks=relative.in -feature no-relative-marks -feature export-marks=non-relative.out -EOF + mkdir -p .git/info/fast-import/ && + cp marks.new .git/info/fast-import/relative.in && + git fast-import <input && + test_cmp marks.new .git/info/fast-import/relative.out +' test_expect_success 'R: feature no-relative-marks should be honoured' ' - git fast-import <input && - test_cmp marks.new non-relative.out + cat >input <<-EOF && + feature relative-marks + feature import-marks=relative.in + feature no-relative-marks + feature export-marks=non-relative.out + EOF + + git fast-import <input && + test_cmp marks.new non-relative.out ' test_expect_success 'R: feature ls supported' ' @@ -2336,7 +2320,7 @@ test_expect_success 'R: cat-blob-fd must be a nonnegative integer' ' test_must_fail git fast-import --cat-blob-fd=-1 </dev/null ' -test_expect_success NOT_MINGW 'R: print old blob' ' +test_expect_success !MINGW 'R: print old blob' ' blob=$(echo "yes it can" | git hash-object -w --stdin) && cat >expect <<-EOF && ${blob} blob 11 @@ -2348,7 +2332,7 @@ test_expect_success NOT_MINGW 'R: print old blob' ' test_cmp expect actual ' -test_expect_success NOT_MINGW 'R: in-stream cat-blob-fd not respected' ' +test_expect_success !MINGW 'R: in-stream cat-blob-fd not respected' ' echo hello >greeting && blob=$(git hash-object -w greeting) && cat >expect <<-EOF && @@ -2360,16 +2344,29 @@ test_expect_success NOT_MINGW 'R: in-stream cat-blob-fd not respected' ' cat-blob $blob EOF test_cmp expect actual.3 && - test_cmp empty actual.1 && + test_must_be_empty actual.1 && git fast-import 3>actual.3 >actual.1 <<-EOF && option cat-blob-fd=3 cat-blob $blob EOF - test_cmp empty actual.3 && + test_must_be_empty actual.3 && test_cmp expect actual.1 ' -test_expect_success NOT_MINGW 'R: print new blob' ' +test_expect_success !MINGW 'R: print mark for new blob' ' + echo "effluentish" | git hash-object --stdin >expect && + git fast-import --cat-blob-fd=6 6>actual <<-\EOF && + blob + mark :1 + data <<BLOB_END + effluentish + BLOB_END + get-mark :1 + EOF + test_cmp expect actual +' + +test_expect_success !MINGW 'R: print new blob' ' blob=$(echo "yep yep yep" | git hash-object --stdin) && cat >expect <<-EOF && ${blob} blob 12 @@ -2387,7 +2384,7 @@ test_expect_success NOT_MINGW 'R: print new blob' ' test_cmp expect actual ' -test_expect_success NOT_MINGW 'R: print new blob by sha1' ' +test_expect_success !MINGW 'R: print new blob by sha1' ' blob=$(echo "a new blob named by sha1" | git hash-object --stdin) && cat >expect <<-EOF && ${blob} blob 25 @@ -2566,17 +2563,17 @@ test_expect_success PIPE 'R: print staged blob within commit' ' test_cmp expect actual ' -cat >input << EOF -option git quiet -blob -data 3 -hi +test_expect_success 'R: quiet option results in no stats being output' ' + cat >input <<-EOF && + option git quiet + blob + data 3 + hi -EOF + EOF -test_expect_success 'R: quiet option results in no stats being output' ' - cat input | git fast-import 2> output && - test_cmp empty output + cat input | git fast-import 2> output && + test_must_be_empty output ' test_expect_success 'R: feature done means terminating "done" is mandatory' ' @@ -2621,16 +2618,16 @@ test_expect_success 'R: terminating "done" within commit' ' test_cmp expect actual ' -cat >input <<EOF -option git non-existing-option -EOF - test_expect_success 'R: die on unknown option' ' - test_must_fail git fast-import <input + cat >input <<-EOF && + option git non-existing-option + EOF + + test_must_fail git fast-import <input ' test_expect_success 'R: unknown commandline options are rejected' '\ - test_must_fail git fast-import --non-existing-option < /dev/null + test_must_fail git fast-import --non-existing-option < /dev/null ' test_expect_success 'R: die on invalid option argument' ' @@ -2641,41 +2638,41 @@ test_expect_success 'R: die on invalid option argument' ' test_must_fail git fast-import --depth="5 elephants" </dev/null ' -cat >input <<EOF -option non-existing-vcs non-existing-option -EOF - test_expect_success 'R: ignore non-git options' ' - git fast-import <input + cat >input <<-EOF && + option non-existing-vcs non-existing-option + EOF + + git fast-import <input ' ## ## R: very large blobs ## -blobsize=$((2*1024*1024 + 53)) -test-genrandom bar $blobsize >expect -cat >input <<INPUT_END -commit refs/heads/big-file -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -R - big file -COMMIT - -M 644 inline big1 -data $blobsize -INPUT_END -cat expect >>input -cat >>input <<INPUT_END -M 644 inline big2 -data $blobsize -INPUT_END -cat expect >>input -echo >>input - -test_expect_success \ - 'R: blob bigger than threshold' \ - 'test_create_repo R && - git --git-dir=R/.git fast-import --big-file-threshold=1 <input' +test_expect_success 'R: blob bigger than threshold' ' + blobsize=$((2*1024*1024 + 53)) && + test-genrandom bar $blobsize >expect && + cat >input <<-INPUT_END && + commit refs/heads/big-file + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + R - big file + COMMIT + + M 644 inline big1 + data $blobsize + INPUT_END + cat expect >>input && + cat >>input <<-INPUT_END && + M 644 inline big2 + data $blobsize + INPUT_END + cat expect >>input && + echo >>input && + + test_create_repo R && + git --git-dir=R/.git fast-import --big-file-threshold=1 <input +' test_expect_success 'R: verify created pack' ' ( @@ -2684,17 +2681,18 @@ test_expect_success 'R: verify created pack' ' ) ' -test_expect_success \ - 'R: verify written objects' \ - 'git --git-dir=R/.git cat-file blob big-file:big1 >actual && - test_cmp expect actual && - a=$(git --git-dir=R/.git rev-parse big-file:big1) && - b=$(git --git-dir=R/.git rev-parse big-file:big2) && - test $a = $b' -test_expect_success \ - 'R: blob appears only once' \ - 'n=$(grep $a verify | wc -l) && - test 1 = $n' +test_expect_success 'R: verify written objects' ' + git --git-dir=R/.git cat-file blob big-file:big1 >actual && + test_cmp_bin expect actual && + a=$(git --git-dir=R/.git rev-parse big-file:big1) && + b=$(git --git-dir=R/.git rev-parse big-file:big2) && + test $a = $b +' + +test_expect_success 'R: blob appears only once' ' + n=$(grep $a verify | wc -l) && + test 1 = $n +' ### ### series S @@ -2727,46 +2725,46 @@ test_expect_success \ # # Invalid dataref .. # -test_tick - -cat >input <<INPUT_END -commit refs/heads/S -mark :301 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -commit 1 -COMMIT -M 100644 inline hello.c -data <<BLOB -blob 1 -BLOB - -commit refs/heads/S -mark :302 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -commit 2 -COMMIT -from :301 -M 100644 inline hello.c -data <<BLOB -blob 2 -BLOB - -blob -mark :403 -data <<BLOB -blob 3 -BLOB - -blob -mark :202 -data <<BLOB -note 2 -BLOB -INPUT_END - test_expect_success 'S: initialize for S tests' ' + test_tick && + + cat >input <<-INPUT_END && + commit refs/heads/S + mark :301 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + commit 1 + COMMIT + M 100644 inline hello.c + data <<BLOB + blob 1 + BLOB + + commit refs/heads/S + mark :302 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + commit 2 + COMMIT + from :301 + M 100644 inline hello.c + data <<BLOB + blob 2 + BLOB + + blob + mark :403 + data <<BLOB + blob 3 + BLOB + + blob + mark :202 + data <<BLOB + note 2 + BLOB + INPUT_END + git fast-import --export-marks=marks <input ' @@ -2866,7 +2864,7 @@ test_expect_success 'S: notemodify with garbage after sha1 dataref must fail' ' # # notemodify, mark in commit-ish # -test_expect_success 'S: notemodify with garbarge after mark commit-ish must fail' ' +test_expect_success 'S: notemodify with garbage after mark commit-ish must fail' ' test_must_fail git fast-import --import-marks=marks <<-EOF 2>err && commit refs/heads/Snotes committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE @@ -2883,8 +2881,8 @@ test_expect_success 'S: notemodify with garbarge after mark commit-ish must fail # from # test_expect_success 'S: from with garbage after mark must fail' ' - # no && - git fast-import --import-marks=marks --export-marks=marks <<-EOF 2>err + test_must_fail \ + git fast-import --import-marks=marks --export-marks=marks <<-EOF 2>err && commit refs/heads/S2 mark :303 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE @@ -2895,9 +2893,6 @@ test_expect_success 'S: from with garbage after mark must fail' ' M 100644 :403 hello.c EOF - ret=$? && - echo returned $ret && - test $ret -ne 0 && # failed, but it created the commit # go create the commit, need it for merge test git fast-import --import-marks=marks --export-marks=marks <<-EOF && @@ -2999,4 +2994,126 @@ test_expect_success 'T: ls root tree' ' test_cmp expect actual ' +test_expect_success 'T: delete branch' ' + git branch to-delete && + git fast-import <<-EOF && + reset refs/heads/to-delete + from 0000000000000000000000000000000000000000 + EOF + test_must_fail git rev-parse --verify refs/heads/to-delete +' + +test_expect_success 'T: empty reset doesnt delete branch' ' + git branch not-to-delete && + git fast-import <<-EOF && + reset refs/heads/not-to-delete + EOF + git show-ref && + git rev-parse --verify refs/heads/not-to-delete +' + +### +### series U (filedelete) +### + +test_expect_success 'U: initialize for U tests' ' + cat >input <<-INPUT_END && + commit refs/heads/U + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + test setup + COMMIT + M 100644 inline hello.c + data <<BLOB + blob 1 + BLOB + M 100644 inline good/night.txt + data <<BLOB + sleep well + BLOB + M 100644 inline good/bye.txt + data <<BLOB + au revoir + BLOB + + INPUT_END + + git fast-import <input +' + +test_expect_success 'U: filedelete file succeeds' ' + cat >input <<-INPUT_END && + commit refs/heads/U + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + delete good/night.txt + COMMIT + from refs/heads/U^0 + D good/night.txt + + INPUT_END + + git fast-import <input +' + +test_expect_success 'U: validate file delete result' ' + cat >expect <<-EOF && + :100644 000000 2907ebb4bf85d91bf0716bb3bd8a68ef48d6da76 0000000000000000000000000000000000000000 D good/night.txt + EOF + + git diff-tree -M -r U^1 U >actual && + + compare_diff_raw expect actual +' + +test_expect_success 'U: filedelete directory succeeds' ' + cat >input <<-INPUT_END && + commit refs/heads/U + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + delete good dir + COMMIT + from refs/heads/U^0 + D good + + INPUT_END + + git fast-import <input +' + +test_expect_success 'U: validate directory delete result' ' + cat >expect <<-EOF && + :100644 000000 69cb75792f55123d8389c156b0b41c2ff00ed507 0000000000000000000000000000000000000000 D good/bye.txt + EOF + + git diff-tree -M -r U^1 U >actual && + + compare_diff_raw expect actual +' + +test_expect_success 'U: filedelete root succeeds' ' + cat >input <<-INPUT_END && + commit refs/heads/U + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + must succeed + COMMIT + from refs/heads/U^0 + D "" + + INPUT_END + + git fast-import <input +' + +test_expect_success 'U: validate root delete result' ' + cat >expect <<-EOF && + :100644 000000 c18147dc648481eeb65dc5e66628429a64843327 0000000000000000000000000000000000000000 D hello.c + EOF + + git diff-tree -M -r U^1 U >actual && + + compare_diff_raw expect actual +' + test_done diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh index 2312dec8f0..66c8b0a371 100755 --- a/t/t9350-fast-export.sh +++ b/t/t9350-fast-export.sh @@ -504,4 +504,22 @@ test_expect_success 'refs are updated even if no commits need to be exported' ' test_cmp expected actual ' +test_expect_success 'use refspec' ' + git fast-export --refspec refs/heads/master:refs/heads/foobar master | \ + grep "^commit " | sort | uniq > actual && + echo "commit refs/heads/foobar" > expected && + test_cmp expected actual +' + +test_expect_success 'delete refspec' ' + git branch to-delete && + git fast-export --refspec :refs/heads/to-delete to-delete ^to-delete > actual && + cat > expected <<-EOF && + reset refs/heads/to-delete + from 0000000000000000000000000000000000000000 + + EOF + test_cmp expected actual +' + test_done diff --git a/t/t9351-fast-export-anonymize.sh b/t/t9351-fast-export-anonymize.sh new file mode 100755 index 0000000000..897dc50907 --- /dev/null +++ b/t/t9351-fast-export-anonymize.sh @@ -0,0 +1,112 @@ +#!/bin/sh + +test_description='basic tests for fast-export --anonymize' +. ./test-lib.sh + +test_expect_success 'setup simple repo' ' + test_commit base && + test_commit foo && + git checkout -b other HEAD^ && + mkdir subdir && + test_commit subdir/bar && + test_commit subdir/xyzzy && + git tag -m "annotated tag" mytag +' + +test_expect_success 'export anonymized stream' ' + git fast-export --anonymize --all >stream +' + +# this also covers commit messages +test_expect_success 'stream omits path names' ' + ! grep base stream && + ! grep foo stream && + ! grep subdir stream && + ! grep bar stream && + ! grep xyzzy stream +' + +test_expect_success 'stream allows master as refname' ' + grep master stream +' + +test_expect_success 'stream omits other refnames' ' + ! grep other stream && + ! grep mytag stream +' + +test_expect_success 'stream omits identities' ' + ! grep "$GIT_COMMITTER_NAME" stream && + ! grep "$GIT_COMMITTER_EMAIL" stream && + ! grep "$GIT_AUTHOR_NAME" stream && + ! grep "$GIT_AUTHOR_EMAIL" stream +' + +test_expect_success 'stream omits tag message' ' + ! grep "annotated tag" stream +' + +# NOTE: we chdir to the new, anonymized repository +# after this. All further tests should assume this. +test_expect_success 'import stream to new repository' ' + git init new && + cd new && + git fast-import <../stream +' + +test_expect_success 'result has two branches' ' + git for-each-ref --format="%(refname)" refs/heads >branches && + test_line_count = 2 branches && + other_branch=$(grep -v refs/heads/master branches) +' + +test_expect_success 'repo has original shape and timestamps' ' + shape () { + git log --format="%m %ct" --left-right --boundary "$@" + } && + (cd .. && shape master...other) >expect && + shape master...$other_branch >actual && + test_cmp expect actual +' + +test_expect_success 'root tree has original shape' ' + # the output entries are not necessarily in the same + # order, but we know at least that we will have one tree + # and one blob, so just check the sorted order + cat >expect <<-\EOF && + blob + tree + EOF + git ls-tree $other_branch >root && + cut -d" " -f2 <root | sort >actual && + test_cmp expect actual +' + +test_expect_success 'paths in subdir ended up in one tree' ' + cat >expect <<-\EOF && + blob + blob + EOF + tree=$(grep tree root | cut -f2) && + git ls-tree $other_branch:$tree >tree && + cut -d" " -f2 <tree >actual && + test_cmp expect actual +' + +test_expect_success 'tag points to branch tip' ' + git rev-parse $other_branch >expect && + git for-each-ref --format="%(*objectname)" | grep . >actual && + test_cmp expect actual +' + +test_expect_success 'idents are shared' ' + git log --all --format="%an <%ae>" >authors && + sort -u authors >unique && + test_line_count = 1 unique && + git log --all --format="%cn <%ce>" >committers && + sort -u committers >unique && + test_line_count = 1 unique && + ! test_cmp authors committers +' + +test_done diff --git a/t/t9402-git-cvsserver-refs.sh b/t/t9402-git-cvsserver-refs.sh index 1e266effff..d00df08731 100755 --- a/t/t9402-git-cvsserver-refs.sh +++ b/t/t9402-git-cvsserver-refs.sh @@ -496,7 +496,7 @@ test_expect_success 'check [cvswork3] diff' ' ' test_expect_success 'merge early [cvswork3] b3 with b1' ' - ( cd gitwork3 && git merge "message" HEAD b1 ) && + ( cd gitwork3 && git merge -m "message" b1 ) && git fetch gitwork3 b3:b3 && git tag v3merged b3 && git push --tags gitcvs.git b3:b3 diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh index e74b9ab1e1..e94b2f147a 100755 --- a/t/t9500-gitweb-standalone-no-errors.sh +++ b/t/t9500-gitweb-standalone-no-errors.sh @@ -297,7 +297,7 @@ test_expect_success 'setup incomplete lines' ' echo "Dominus regit me," >file && echo "incomplete line" | tr -d "\\012" >>file && git commit -a -m "Change incomplete line" && - git tag incomplete_lines_chg + git tag incomplete_lines_chg && echo "Dominus regit me," >file && git commit -a -m "Remove incomplete line" && git tag incomplete_lines_rem @@ -779,7 +779,10 @@ test_expect_success \ test_expect_success \ 'unborn HEAD: "summary" page (with "heads" subview)' \ - 'git checkout orphan_branch || git checkout --orphan orphan_branch && + '{ + git checkout orphan_branch || + git checkout --orphan orphan_branch + } && test_when_finished "git checkout master" && gitweb_run "p=.git;a=summary"' diff --git a/t/t9502-gitweb-standalone-parse-output.sh b/t/t9502-gitweb-standalone-parse-output.sh index 86dfee2e4f..0796a438bc 100755 --- a/t/t9502-gitweb-standalone-parse-output.sh +++ b/t/t9502-gitweb-standalone-parse-output.sh @@ -145,9 +145,11 @@ test_expect_success 'forks: not skipped unless "forks" feature enabled' ' grep -q ">fork of .*<" gitweb.body ' -cat >>gitweb_config.perl <<\EOF && -$feature{'forks'}{'default'} = [1]; -EOF +test_expect_success 'enable forks feature' ' + cat >>gitweb_config.perl <<-\EOF + $feature{"forks"}{"default"} = [1]; + EOF +' test_expect_success 'forks: forks skipped if "forks" feature enabled' ' gitweb_run "a=project_list" && @@ -173,7 +175,7 @@ test_expect_success 'forks: can access forked repository' ' ' test_expect_success 'forks: project_index lists all projects (incl. forks)' ' - cat >expected <<-\EOF + cat >expected <<-\EOF && .git foo.bar.git foo.git diff --git a/t/t9603-cvsimport-patchsets.sh b/t/t9603-cvsimport-patchsets.sh index 52034c8f77..c4c3c49546 100755 --- a/t/t9603-cvsimport-patchsets.sh +++ b/t/t9603-cvsimport-patchsets.sh @@ -16,7 +16,7 @@ test_description='git cvsimport testing for correct patchset estimation' setup_cvs_test_repository t9603 -test_expect_failure 'import with criss cross times on revisions' ' +test_expect_failure PERL 'import with criss cross times on revisions' ' git cvsimport -p"-x" -C module-git module && (cd module-git && diff --git a/t/t9604-cvsimport-timestamps.sh b/t/t9604-cvsimport-timestamps.sh index 1fd51423ee..a4b3db24bd 100755 --- a/t/t9604-cvsimport-timestamps.sh +++ b/t/t9604-cvsimport-timestamps.sh @@ -5,7 +5,7 @@ test_description='git cvsimport timestamps' setup_cvs_test_repository t9604 -test_expect_success 'check timestamps are UTC (TZ=CST6CDT)' ' +test_expect_success PERL 'check timestamps are UTC (TZ=CST6CDT)' ' TZ=CST6CDT git cvsimport -p"-x" -C module-1 module && git cvsimport -p"-x" -C module-1 module && @@ -34,7 +34,7 @@ test_expect_success 'check timestamps are UTC (TZ=CST6CDT)' ' test_cmp actual-1 expect-1 ' -test_expect_success 'check timestamps with author-specific timezones' ' +test_expect_success PERL 'check timestamps with author-specific timezones' ' cat >cvs-authors <<-EOF && user1=User One <user1@domain.org> diff --git a/t/t9800-git-p4-basic.sh b/t/t9800-git-p4-basic.sh index 665607c9cb..0730f18d0f 100755 --- a/t/t9800-git-p4-basic.sh +++ b/t/t9800-git-p4-basic.sh @@ -131,6 +131,44 @@ test_expect_success 'clone two dirs, @all, conflicting files' ' ) ' +revision_ranges="2000/01/01,#head \ + 1,2080/01/01 \ + 2000/01/01,2080/01/01 \ + 2000/01/01,1000 \ + 1,1000" + +test_expect_success 'clone using non-numeric revision ranges' ' + test_when_finished cleanup_git && + for r in $revision_ranges + do + rm -fr "$git" && + test ! -d "$git" && + git p4 clone --dest="$git" //depot@$r && + ( + cd "$git" && + git ls-files >lines && + test_line_count = 6 lines + ) + done +' + +test_expect_success 'clone with date range, excluding some changes' ' + test_when_finished cleanup_git && + before=$(date +%Y/%m/%d:%H:%M:%S) && + sleep 2 && + ( + cd "$cli" && + :>date_range_test && + p4 add date_range_test && + p4 submit -d "Adding file" + ) && + git p4 clone --dest="$git" //depot@1,$before && + ( + cd "$git" && + test_path_is_missing date_range_test + ) +' + test_expect_success 'exit when p4 fails to produce marshaled output' ' mkdir badp4dir && test_when_finished "rm badp4dir/p4 && rmdir badp4dir" && @@ -145,7 +183,7 @@ test_expect_success 'exit when p4 fails to produce marshaled output' ' test_expect_code 1 git p4 clone --dest="$git" //depot >errs 2>&1 ) && cat errs && - ! test_i18ngrep Traceback errs + test_i18ngrep ! Traceback errs ' # Hide a file from p4d, make sure we catch its complaint. This won't fail in @@ -203,6 +241,22 @@ test_expect_success 'unresolvable host in P4PORT should display error' ' ) ' +test_expect_success 'submit from detached head' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + git checkout p4/master && + >detached_head_test && + git add detached_head_test && + git commit -m "add detached_head" && + git config git-p4.skipSubmitEdit true && + git p4 submit && + git p4 rebase && + git log p4/master | grep detached_head + ) +' + test_expect_success 'kill p4d' ' kill_p4d ' diff --git a/t/t9801-git-p4-branch.sh b/t/t9801-git-p4-branch.sh index 2bf142d09c..0aafd03334 100755 --- a/t/t9801-git-p4-branch.sh +++ b/t/t9801-git-p4-branch.sh @@ -504,6 +504,112 @@ test_expect_success 'use-client-spec detect-branches skips files in branches' ' ) ' +test_expect_success 'restart p4d' ' + kill_p4d && + start_p4d +' + +# +# 1: //depot/branch1/base/file1 +# //depot/branch1/base/file2 +# //depot/branch1/base/dir/sub_file1 +# 2: integrate //depot/branch1/base/... -> //depot/branch2/base/... +# 3: //depot/branch1/base/file3 +# 4: //depot/branch1/base/file2 (edit) +# 5: integrate //depot/branch1/base/... -> //depot/branch3/base/... +# +# Note: the client view removes the "base" folder from the workspace +# and moves sub_file1 one level up. +test_expect_success 'add simple p4 branches with common base folder on each branch' ' + ( + cd "$cli" && + client_view "//depot/branch1/base/... //client/branch1/..." \ + "//depot/branch1/base/dir/sub_file1 //client/branch1/sub_file1" \ + "//depot/branch2/base/... //client/branch2/..." \ + "//depot/branch3/base/... //client/branch3/..." && + mkdir -p branch1 && + cd branch1 && + echo file1 >file1 && + echo file2 >file2 && + mkdir dir && + echo sub_file1 >sub_file1 && + p4 add file1 file2 sub_file1 && + p4 submit -d "Create branch1" && + p4 integrate //depot/branch1/base/... //depot/branch2/base/... && + p4 submit -d "Integrate branch2 from branch1" && + echo file3 >file3 && + p4 add file3 && + p4 submit -d "add file3 in branch1" && + p4 open file2 && + echo update >>file2 && + p4 submit -d "update file2 in branch1" && + p4 integrate //depot/branch1/base/... //depot/branch3/base/... && + p4 submit -d "Integrate branch3 from branch1" + ) +' + +# Configure branches through git-config and clone them. +# All files are tested to make sure branches were cloned correctly. +# Finally, make an update to branch1 on P4 side to check if it is imported +# correctly by git p4. +# git p4 is expected to use the client view to also not include the common +# "base" folder in the imported directory structure. +test_expect_success 'git p4 clone simple branches with base folder on server side' ' + test_create_repo "$git" && + ( + cd "$git" && + git config git-p4.branchList branch1:branch2 && + git config --add git-p4.branchList branch1:branch3 && + git p4 clone --dest=. --use-client-spec --detect-branches //depot@all && + git log --all --graph --decorate --stat && + git reset --hard p4/depot/branch1 && + test -f file1 && + test -f file2 && + test -f file3 && + test -f sub_file1 && + grep update file2 && + git reset --hard p4/depot/branch2 && + test -f file1 && + test -f file2 && + test ! -f file3 && + test -f sub_file1 && + ! grep update file2 && + git reset --hard p4/depot/branch3 && + test -f file1 && + test -f file2 && + test -f file3 && + test -f sub_file1 && + grep update file2 && + cd "$cli" && + cd branch1 && + p4 edit file2 && + echo file2_ >>file2 && + p4 submit -d "update file2 in branch1" && + cd "$git" && + git reset --hard p4/depot/branch1 && + git p4 rebase && + grep file2_ file2 + ) +' + +# Now update a file in one of the branches in git and submit to P4 +test_expect_success 'Update a file in git side and submit to P4 using client view' ' + test_when_finished cleanup_git && + ( + cd "$git" && + git reset --hard p4/depot/branch1 && + echo "client spec" >> file1 && + git add -u . && + git commit -m "update file1 in branch1" && + git config git-p4.skipSubmitEdit true && + git p4 submit --verbose && + cd "$cli" && + p4 sync ... && + cd branch1 && + grep "client spec" file1 + ) +' + test_expect_success 'kill p4d' ' kill_p4d ' diff --git a/t/t9803-git-p4-shell-metachars.sh b/t/t9803-git-p4-shell-metachars.sh index fbacff34fe..d950c7d665 100755 --- a/t/t9803-git-p4-shell-metachars.sh +++ b/t/t9803-git-p4-shell-metachars.sh @@ -28,7 +28,7 @@ test_expect_success 'shell metachars in filenames' ' echo f2 >"file with spaces" && git add "file with spaces" && git commit -m "add files" && - P4EDITOR=touch git p4 submit + P4EDITOR="test-chmtime +5" git p4 submit ) && ( cd "$cli" && @@ -47,7 +47,7 @@ test_expect_success 'deleting with shell metachars' ' git rm foo\$bar && git rm file\ with\ spaces && git commit -m "remove files" && - P4EDITOR=touch git p4 submit + P4EDITOR="test-chmtime +5" git p4 submit ) && ( cd "$cli" && diff --git a/t/t9805-git-p4-skip-submit-edit.sh b/t/t9805-git-p4-skip-submit-edit.sh index 89311886db..5fbf904dc8 100755 --- a/t/t9805-git-p4-skip-submit-edit.sh +++ b/t/t9805-git-p4-skip-submit-edit.sh @@ -90,7 +90,7 @@ test_expect_success 'no config, edited' ' cd "$git" && echo line >>file1 && git commit -a -m "change 5" && - P4EDITOR="$TRASH_DIRECTORY/ed.sh" && + P4EDITOR="\"$TRASH_DIRECTORY/ed.sh\"" && export P4EDITOR && git p4 submit && p4 changes //depot/... >wc && diff --git a/t/t9807-git-p4-submit.sh b/t/t9807-git-p4-submit.sh index 4caf36e006..593152817d 100755 --- a/t/t9807-git-p4-submit.sh +++ b/t/t9807-git-p4-submit.sh @@ -389,7 +389,7 @@ test_expect_success 'description with Jobs section and bogus following text' ' ( cd "$cli" && p4 revert desc6 && - rm desc6 + rm -f desc6 ) ' @@ -403,7 +403,8 @@ test_expect_success 'submit --prepare-p4-only' ' git commit -m "prep only add" && git p4 submit --prepare-p4-only >out && test_i18ngrep "prepared for submission" out && - test_i18ngrep "must be deleted" out + test_i18ngrep "must be deleted" out && + test_i18ngrep ! "everything below this line is just the diff" out ) && ( cd "$cli" && diff --git a/t/t9809-git-p4-client-view.sh b/t/t9809-git-p4-client-view.sh index 23a827fa77..897b3c3034 100755 --- a/t/t9809-git-p4-client-view.sh +++ b/t/t9809-git-p4-client-view.sh @@ -365,7 +365,7 @@ test_expect_success 'wildcard files submit back to p4, client-spec case' ' ( cd "$git" && echo git-wild-hash >dir1/git-wild#hash && - if test_have_prereq NOT_MINGW NOT_CYGWIN + if test_have_prereq !MINGW,!CYGWIN then echo git-wild-star >dir1/git-wild\*star fi && @@ -379,7 +379,7 @@ test_expect_success 'wildcard files submit back to p4, client-spec case' ' ( cd "$cli" && test_path_is_file dir1/git-wild#hash && - if test_have_prereq NOT_MINGW NOT_CYGWIN + if test_have_prereq !MINGW,!CYGWIN then test_path_is_file dir1/git-wild\*star fi && diff --git a/t/t9811-git-p4-label-import.sh b/t/t9811-git-p4-label-import.sh index 095238fffe..decb66ba30 100755 --- a/t/t9811-git-p4-label-import.sh +++ b/t/t9811-git-p4-label-import.sh @@ -214,6 +214,51 @@ test_expect_success 'use git config to enable import/export of tags' ' ) ' +p4_head_revision() { + p4 changes -m 1 "$@" | awk '{print $2}' +} + +# Importing a label that references a P4 commit that +# has not been seen. The presence of a label on a commit +# we haven't seen should not cause git-p4 to fail. It should +# merely skip that label, and still import other labels. +test_expect_success 'importing labels with missing revisions' ' + test_when_finished cleanup_git && + ( + rm -fr "$cli" "$git" && + mkdir "$cli" && + P4CLIENT=missing-revision && + client_view "//depot/missing-revision/... //missing-revision/..." && + cd "$cli" && + >f1 && p4 add f1 && p4 submit -d "start" && + + p4 tag -l TAG_S0 ... && + + >f2 && p4 add f2 && p4 submit -d "second" && + + startrev=$(p4_head_revision //depot/missing-revision/...) && + + >f3 && p4 add f3 && p4 submit -d "third" && + + p4 edit f2 && date >f2 && p4 submit -d "change" f2 && + + endrev=$(p4_head_revision //depot/missing-revision/...) && + + p4 tag -l TAG_S1 ... && + + # we should skip TAG_S0 since it is before our startpoint, + # but pick up TAG_S1. + + git p4 clone --dest="$git" --import-labels -v \ + //depot/missing-revision/...@$startrev,$endrev && + ( + cd "$git" && + git rev-parse TAG_S1 && + ! git rev-parse TAG_S0 + ) + ) +' + test_expect_success 'kill p4d' ' kill_p4d diff --git a/t/t9812-git-p4-wildcards.sh b/t/t9812-git-p4-wildcards.sh index c7472cbf54..0206771fbb 100755 --- a/t/t9812-git-p4-wildcards.sh +++ b/t/t9812-git-p4-wildcards.sh @@ -14,7 +14,7 @@ test_expect_success 'add p4 files with wildcards in the names' ' printf "file2\nhas\nsome\nrandom\ntext\n" >file2 && p4 add file2 && echo file-wild-hash >file-wild#hash && - if test_have_prereq NOT_MINGW NOT_CYGWIN + if test_have_prereq !MINGW,!CYGWIN then echo file-wild-star >file-wild\*star fi && @@ -31,7 +31,7 @@ test_expect_success 'wildcard files git p4 clone' ' ( cd "$git" && test -f file-wild#hash && - if test_have_prereq NOT_MINGW NOT_CYGWIN + if test_have_prereq !MINGW,!CYGWIN then test -f file-wild\*star fi && @@ -46,7 +46,7 @@ test_expect_success 'wildcard files submit back to p4, add' ' ( cd "$git" && echo git-wild-hash >git-wild#hash && - if test_have_prereq NOT_MINGW NOT_CYGWIN + if test_have_prereq !MINGW,!CYGWIN then echo git-wild-star >git-wild\*star fi && @@ -60,7 +60,7 @@ test_expect_success 'wildcard files submit back to p4, add' ' ( cd "$cli" && test_path_is_file git-wild#hash && - if test_have_prereq NOT_MINGW NOT_CYGWIN + if test_have_prereq !MINGW,!CYGWIN then test_path_is_file git-wild\*star fi && @@ -75,7 +75,7 @@ test_expect_success 'wildcard files submit back to p4, modify' ' ( cd "$git" && echo new-line >>git-wild#hash && - if test_have_prereq NOT_MINGW NOT_CYGWIN + if test_have_prereq !MINGW,!CYGWIN then echo new-line >>git-wild\*star fi && @@ -89,7 +89,7 @@ test_expect_success 'wildcard files submit back to p4, modify' ' ( cd "$cli" && test_line_count = 2 git-wild#hash && - if test_have_prereq NOT_MINGW NOT_CYGWIN + if test_have_prereq !MINGW,!CYGWIN then test_line_count = 2 git-wild\*star fi && @@ -152,7 +152,7 @@ test_expect_success 'wildcard files submit back to p4, delete' ' ( cd "$cli" && test_path_is_missing git-wild#hash && - if test_have_prereq NOT_MINGW NOT_CYGWIN + if test_have_prereq !MINGW,!CYGWIN then test_path_is_missing git-wild\*star fi && diff --git a/t/t9813-git-p4-preserve-users.sh b/t/t9813-git-p4-preserve-users.sh index 166b840bfa..0fe2312807 100755 --- a/t/t9813-git-p4-preserve-users.sh +++ b/t/t9813-git-p4-preserve-users.sh @@ -53,7 +53,9 @@ test_expect_success 'preserve users' ' git commit --author "Alice <alice@example.com>" -m "a change by alice" file1 && git commit --author "Bob <bob@example.com>" -m "a change by bob" file2 && git config git-p4.skipSubmitEditCheck true && - P4EDITOR=touch P4USER=alice P4PASSWD=secret git p4 commit --preserve-user && + P4EDITOR="test-chmtime +5" P4USER=alice P4PASSWD=secret && + export P4EDITOR P4USER P4PASSWD && + git p4 commit --preserve-user && p4_check_commit_author file1 alice && p4_check_commit_author file2 bob ) @@ -69,7 +71,7 @@ test_expect_success 'refuse to preserve users without perms' ' git config git-p4.skipSubmitEditCheck true && echo "username-noperms: a change by alice" >>file1 && git commit --author "Alice <alice@example.com>" -m "perms: a change by alice" file1 && - P4EDITOR=touch P4USER=bob P4PASSWD=secret && + P4EDITOR="test-chmtime +5" P4USER=bob P4PASSWD=secret && export P4EDITOR P4USER P4PASSWD && test_must_fail git p4 commit --preserve-user && ! git diff --exit-code HEAD..p4/master @@ -87,7 +89,7 @@ test_expect_success 'preserve user where author is unknown to p4' ' git commit --author "Bob <bob@example.com>" -m "preserve: a change by bob" file1 && echo "username-unknown: a change by charlie" >>file1 && git commit --author "Charlie <charlie@example.com>" -m "preserve: a change by charlie" file1 && - P4EDITOR=touch P4USER=alice P4PASSWD=secret && + P4EDITOR="test-chmtime +5" P4USER=alice P4PASSWD=secret && export P4EDITOR P4USER P4PASSWD && test_must_fail git p4 commit --preserve-user && ! git diff --exit-code HEAD..p4/master && diff --git a/t/t9814-git-p4-rename.sh b/t/t9814-git-p4-rename.sh index be802e0e16..c89992cf95 100755 --- a/t/t9814-git-p4-rename.sh +++ b/t/t9814-git-p4-rename.sh @@ -132,6 +132,9 @@ test_expect_success 'detect copies' ' cd "$git" && git config git-p4.skipSubmitEdit true && + echo "file8" >>file2 && + git commit -a -m "Differentiate file2" && + git p4 submit && cp file2 file8 && git add file8 && git commit -a -m "Copy file2 to file8" && @@ -140,6 +143,10 @@ test_expect_success 'detect copies' ' p4 filelog //depot/file8 && p4 filelog //depot/file8 | test_must_fail grep -q "branch from" && + echo "file9" >>file2 && + git commit -a -m "Differentiate file2" && + git p4 submit && + cp file2 file9 && git add file9 && git commit -a -m "Copy file2 to file9" && @@ -149,25 +156,39 @@ test_expect_success 'detect copies' ' p4 filelog //depot/file9 && p4 filelog //depot/file9 | test_must_fail grep -q "branch from" && + echo "file10" >>file2 && + git commit -a -m "Differentiate file2" && + git p4 submit && + echo "file2" >>file2 && cp file2 file10 && git add file2 file10 && git commit -a -m "Modify and copy file2 to file10" && git diff-tree -r -C HEAD && + src=$(git diff-tree -r -C HEAD | sed 1d | sed 2d | cut -f2) && + test "$src" = file2 && git p4 submit && p4 filelog //depot/file10 && - p4 filelog //depot/file10 | grep -q "branch from //depot/file" && + p4 filelog //depot/file10 | grep -q "branch from //depot/file2" && + + echo "file11" >>file2 && + git commit -a -m "Differentiate file2" && + git p4 submit && cp file2 file11 && git add file11 && git commit -a -m "Copy file2 to file11" && git diff-tree -r -C --find-copies-harder HEAD && src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) && - test "$src" = file10 && + test "$src" = file2 && git config git-p4.detectCopiesHarder true && git p4 submit && p4 filelog //depot/file11 && - p4 filelog //depot/file11 | grep -q "branch from //depot/file" && + p4 filelog //depot/file11 | grep -q "branch from //depot/file2" && + + echo "file12" >>file2 && + git commit -a -m "Differentiate file2" && + git p4 submit && cp file2 file12 && echo "some text" >>file12 && @@ -177,12 +198,16 @@ test_expect_success 'detect copies' ' level=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/C0*//") && test -n "$level" && test "$level" -gt 0 && test "$level" -lt 98 && src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) && - test "$src" = file10 -o "$src" = file11 && + test "$src" = file2 && git config git-p4.detectCopies $(($level + 2)) && git p4 submit && p4 filelog //depot/file12 && p4 filelog //depot/file12 | test_must_fail grep -q "branch from" && + echo "file13" >>file2 && + git commit -a -m "Differentiate file2" && + git p4 submit && + cp file2 file13 && echo "different text" >>file13 && git add file13 && @@ -191,24 +216,19 @@ test_expect_success 'detect copies' ' level=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/C0*//") && test -n "$level" && test "$level" -gt 2 && test "$level" -lt 100 && src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) && - test "$src" = file10 -o "$src" = file11 -o "$src" = file12 && + test "$src" = file2 && git config git-p4.detectCopies $(($level - 2)) && git p4 submit && p4 filelog //depot/file13 && - p4 filelog //depot/file13 | grep -q "branch from //depot/file" + p4 filelog //depot/file13 | grep -q "branch from //depot/file2" ) ' # See if configurables can be set, and in particular if the run.move.allow # variable exists, which allows admins to disable the "p4 move" command. -test_expect_success 'p4 configure command and run.move.allow are available' ' - p4 configure show run.move.allow >out ; retval=$? && - test $retval = 0 && - { - egrep ^run.move.allow: out && - test_set_prereq P4D_HAVE_CONFIGURABLE_RUN_MOVE_ALLOW || - true - } || true +test_lazy_prereq P4D_HAVE_CONFIGURABLE_RUN_MOVE_ALLOW ' + p4 configure show run.move.allow >out && + egrep ^run.move.allow: out ' # If move can be disabled, turn it off and test p4 move handling diff --git a/t/t9815-git-p4-submit-fail.sh b/t/t9815-git-p4-submit-fail.sh index 1243d96092..37b42d03a2 100755 --- a/t/t9815-git-p4-submit-fail.sh +++ b/t/t9815-git-p4-submit-fail.sh @@ -417,11 +417,8 @@ test_expect_success 'cleanup chmod after submit cancel' ' ! p4 fstat -T action text && test_path_is_file text+x && ! p4 fstat -T action text+x && - if test_have_prereq NOT_CYGWIN - then - stat --format=%A text | egrep ^-r-- && - stat --format=%A text+x | egrep ^-r-x - fi + ls -l text | egrep ^-r-- && + ls -l text+x | egrep ^-r-x ) ' diff --git a/t/t9816-git-p4-locked.sh b/t/t9816-git-p4-locked.sh index e71e543343..d048bd33fa 100755 --- a/t/t9816-git-p4-locked.sh +++ b/t/t9816-git-p4-locked.sh @@ -35,13 +35,13 @@ test_expect_success 'edit with lock not taken' ' ) ' -test_expect_failure 'add with lock not taken' ' +test_expect_success 'add with lock not taken' ' test_when_finished cleanup_git && git p4 clone --dest="$git" //depot && ( cd "$git" && echo line1 >>add-lock-not-taken && - git add file2 && + git add add-lock-not-taken && git commit -m "add add-lock-not-taken" && git config git-p4.skipSubmitEdit true && git p4 submit --verbose @@ -107,7 +107,7 @@ test_expect_failure 'chmod with lock taken' ' ) ' -test_expect_failure 'copy with lock taken' ' +test_expect_success 'copy with lock taken' ' lock_in_another_client && test_when_finished cleanup_git && test_when_finished "cd \"$cli\" && p4 revert file2 && rm -f file2" && @@ -130,8 +130,8 @@ test_expect_failure 'move with lock taken' ' git p4 clone --dest="$git" //depot && ( cd "$git" && - git mv file1 file2 && - git commit -m "mv file1 to file2" && + git mv file1 file3 && + git commit -m "mv file1 to file3" && git config git-p4.skipSubmitEdit true && git config git-p4.detectRenames true && git p4 submit --verbose diff --git a/t/t9817-git-p4-exclude.sh b/t/t9817-git-p4-exclude.sh new file mode 100755 index 0000000000..aac568eadf --- /dev/null +++ b/t/t9817-git-p4-exclude.sh @@ -0,0 +1,71 @@ +#!/bin/sh + +test_description='git p4 tests for excluded paths during clone and sync' + +. ./lib-git-p4.sh + +test_expect_success 'start p4d' ' + start_p4d +' + +# Create a repo with the structure: +# +# //depot/wanted/foo +# //depot/discard/foo +# +# Check that we can exclude a subdirectory with both +# clone and sync operations. + +test_expect_success 'create exclude repo' ' + ( + cd "$cli" && + mkdir -p wanted discard && + echo wanted >wanted/foo && + echo discard >discard/foo && + p4 add wanted/foo discard/foo && + p4 submit -d "initial revision" + ) +' + +test_expect_success 'check the repo was created correctly' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot/...@all && + ( + cd "$git" && + test_path_is_file wanted/foo && + test_path_is_file discard/foo + ) +' + +test_expect_success 'clone, excluding part of repo' ' + test_when_finished cleanup_git && + git p4 clone -//depot/discard/... --dest="$git" //depot/...@all && + ( + cd "$git" && + test_path_is_file wanted/foo && + test_path_is_missing discard/foo + ) +' + +test_expect_success 'clone, then sync with exclude' ' + test_when_finished cleanup_git && + git p4 clone -//depot/discard/... --dest="$git" //depot/...@all && + ( + cd "$cli" && + p4 edit wanted/foo discard/foo && + date >>wanted/foo && + date >>discard/foo && + p4 submit -d "updating" && + + cd "$git" && + git p4 sync -//depot/discard/... && + test_path_is_file wanted/foo && + test_path_is_missing discard/foo + ) +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/t9818-git-p4-block.sh b/t/t9818-git-p4-block.sh new file mode 100755 index 0000000000..8840a183ac --- /dev/null +++ b/t/t9818-git-p4-block.sh @@ -0,0 +1,145 @@ +#!/bin/sh + +test_description='git p4 fetching changes in multiple blocks' + +. ./lib-git-p4.sh + +test_expect_success 'start p4d' ' + start_p4d +' + +create_restricted_group() { + p4 group -i <<-EOF + Group: restricted + MaxResults: 7 + MaxScanRows: 40 + Users: author + EOF +} + +test_expect_success 'Create group with limited maxrows' ' + create_restricted_group +' + +test_expect_success 'Create a repo with many changes' ' + ( + client_view "//depot/included/... //client/included/..." \ + "//depot/excluded/... //client/excluded/..." && + mkdir -p "$cli/included" "$cli/excluded" && + cd "$cli/included" && + >file.txt && + p4 add file.txt && + p4 submit -d "Add file.txt" && + for i in $(test_seq 0 5) + do + >outer$i.txt && + p4 add outer$i.txt && + p4 submit -d "Adding outer$i.txt" && + for j in $(test_seq 0 5) + do + p4 edit file.txt && + echo $i$j >file.txt && + p4 submit -d "Commit $i$j" || exit + done || exit + done + ) +' + +test_expect_success 'Default user cannot fetch changes' ' + ! p4 changes -m 1 //depot/... +' + +test_expect_success 'Clone the repo' ' + git p4 clone --dest="$git" --changes-block-size=7 --verbose //depot/included@all +' + +test_expect_success 'All files are present' ' + echo file.txt >expected && + test_write_lines outer0.txt outer1.txt outer2.txt outer3.txt outer4.txt >>expected && + test_write_lines outer5.txt >>expected && + ls "$git" >current && + test_cmp expected current +' + +test_expect_success 'file.txt is correct' ' + echo 55 >expected && + test_cmp expected "$git/file.txt" +' + +test_expect_success 'Correct number of commits' ' + (cd "$git" && git log --oneline) >log && + wc -l log && + test_line_count = 43 log +' + +test_expect_success 'Previous version of file.txt is correct' ' + (cd "$git" && git checkout HEAD^^) && + echo 53 >expected && + test_cmp expected "$git/file.txt" +' + +# Test git-p4 sync, with some files outside the client specification. + +p4_add_file() { + (cd "$cli" && + >$1 && + p4 add $1 && + p4 submit -d "Added file $1" $1 + ) +} + +test_expect_success 'Add some more files' ' + for i in $(test_seq 0 10) + do + p4_add_file "included/x$i" && + p4_add_file "excluded/x$i" + done && + for i in $(test_seq 0 10) + do + p4_add_file "excluded/y$i" + done +' + +# This should pick up the 10 new files in "included", but not be confused +# by the additional files in "excluded" +test_expect_success 'Syncing files' ' + ( + cd "$git" && + git p4 sync --changes-block-size=7 && + git checkout p4/master && + ls -l x* > log && + test_line_count = 11 log + ) +' + +# Handling of multiple depot paths: +# git p4 clone //depot/pathA //depot/pathB +# +test_expect_success 'Create a repo with multiple depot paths' ' + client_view "//depot/pathA/... //client/pathA/..." \ + "//depot/pathB/... //client/pathB/..." && + mkdir -p "$cli/pathA" "$cli/pathB" && + for p in pathA pathB + do + for i in $(test_seq 1 10) + do + p4_add_file "$p/file$p$i" + done + done +' + +test_expect_success 'Clone repo with multiple depot paths' ' + ( + cd "$git" && + git p4 clone --changes-block-size=4 //depot/pathA@all //depot/pathB@all \ + --destination=dest && + ls -1 dest >log && + test_line_count = 20 log + ) +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/t9819-git-p4-case-folding.sh b/t/t9819-git-p4-case-folding.sh new file mode 100755 index 0000000000..d808c008c1 --- /dev/null +++ b/t/t9819-git-p4-case-folding.sh @@ -0,0 +1,60 @@ +#!/bin/sh + +test_description='interaction with P4 case-folding' + +. ./lib-git-p4.sh + +if test_have_prereq CASE_INSENSITIVE_FS +then + skip_all='skipping P4 case-folding tests; case insensitive file system detected' + test_done +fi + +test_expect_success 'start p4d with case folding enabled' ' + start_p4d -C1 +' + +test_expect_success 'Create a repo, name is lowercase' ' + ( + client_view "//depot/... //client/..." && + cd "$cli" && + mkdir -p lc UC && + >lc/file.txt && >UC/file.txt && + p4 add lc/file.txt UC/file.txt && + p4 submit -d "Add initial lc and UC repos" + ) +' + +test_expect_success 'Check p4 is in case-folding mode' ' + ( + cd "$cli" && + >lc/FILE.TXT && + p4 add lc/FILE.TXT && + test_must_fail p4 submit -d "Cannot add file differing only in case" lc/FILE.TXT + ) +' + +# Check we created the repo properly +test_expect_success 'Clone lc repo using lc name' ' + git p4 clone //depot/lc/... && + test_path_is_file lc/file.txt && + git p4 clone //depot/UC/... && + test_path_is_file UC/file.txt +' + +# The clone should fail, since there is no repo called LC, but because +# we have case-insensitive p4d enabled, it appears to go ahead and work, +# but leaves an empty git repo in place. +test_expect_failure 'Clone lc repo using uc name' ' + test_must_fail git p4 clone //depot/LC/... +' + +test_expect_failure 'Clone UC repo with lc name' ' + test_must_fail git p4 clone //depot/uc/... +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/t9820-git-p4-editor-handling.sh b/t/t9820-git-p4-editor-handling.sh new file mode 100755 index 0000000000..6dc6df032e --- /dev/null +++ b/t/t9820-git-p4-editor-handling.sh @@ -0,0 +1,38 @@ +#!/bin/sh + +test_description='git p4 handling of EDITOR' + +. ./lib-git-p4.sh + +test_expect_success 'start p4d' ' + start_p4d +' + +test_expect_success 'init depot' ' + ( + cd "$cli" && + echo file1 >file1 && + p4 add file1 && + p4 submit -d "file1" + ) +' + +# Check that the P4EDITOR argument can be given command-line +# options, which git-p4 will then pass through to the shell. +test_expect_success 'EDITOR with options' ' + git p4 clone --dest="$git" //depot && + test_when_finished cleanup_git && + ( + cd "$git" && + echo change >file1 && + git commit -m "change" file1 && + P4EDITOR=": >\"$git/touched\" && test-chmtime +5" git p4 submit && + test_path_is_file "$git/touched" + ) +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/t9821-git-p4-path-variations.sh b/t/t9821-git-p4-path-variations.sh new file mode 100755 index 0000000000..81e46acfa8 --- /dev/null +++ b/t/t9821-git-p4-path-variations.sh @@ -0,0 +1,200 @@ +#!/bin/sh + +test_description='Clone repositories with path case variations' + +. ./lib-git-p4.sh + +test_expect_success 'start p4d with case folding enabled' ' + start_p4d -C1 +' + +test_expect_success 'Create a repo with path case variations' ' + client_view "//depot/... //client/..." && + ( + cd "$cli" && + + mkdir -p Path/to && + >Path/to/File2.txt && + p4 add Path/to/File2.txt && + p4 submit -d "Add file2" && + rm -rf Path && + + mkdir -p path/TO && + >path/TO/file1.txt && + p4 add path/TO/file1.txt && + p4 submit -d "Add file1" && + rm -rf path && + + mkdir -p path/to && + >path/to/file3.txt && + p4 add path/to/file3.txt && + p4 submit -d "Add file3" && + rm -rf path && + + mkdir -p x-outside-spec && + >x-outside-spec/file4.txt && + p4 add x-outside-spec/file4.txt && + p4 submit -d "Add file4" && + rm -rf x-outside-spec + ) +' + +test_expect_success 'Clone root' ' + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config core.ignorecase false && + git p4 clone --use-client-spec --destination="$git" //depot && + # This method is used instead of "test -f" to ensure the case is + # checked even if the test is executed on case-insensitive file systems. + # All files are there as expected although the path cases look random. + cat >expect <<-\EOF && + Path/to/File2.txt + path/TO/file1.txt + path/to/file3.txt + x-outside-spec/file4.txt + EOF + git ls-files >actual && + test_cmp expect actual + ) +' + +test_expect_success 'Clone root (ignorecase)' ' + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config core.ignorecase true && + git p4 clone --use-client-spec --destination="$git" //depot && + # This method is used instead of "test -f" to ensure the case is + # checked even if the test is executed on case-insensitive file systems. + # All files are there as expected although the path cases look random. + cat >expect <<-\EOF && + path/TO/File2.txt + path/TO/file1.txt + path/TO/file3.txt + x-outside-spec/file4.txt + EOF + git ls-files >actual && + test_cmp expect actual + ) +' + +test_expect_success 'Clone root and ignore one file' ' + client_view \ + "//depot/... //client/..." \ + "-//depot/path/TO/file1.txt //client/path/TO/file1.txt" && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config core.ignorecase false && + git p4 clone --use-client-spec --destination="$git" //depot && + # We ignore one file in the client spec and all path cases change from + # "TO" to "to"! + cat >expect <<-\EOF && + Path/to/File2.txt + path/to/file3.txt + x-outside-spec/file4.txt + EOF + git ls-files >actual && + test_cmp expect actual + ) +' + +test_expect_success 'Clone root and ignore one file (ignorecase)' ' + client_view \ + "//depot/... //client/..." \ + "-//depot/path/TO/file1.txt //client/path/TO/file1.txt" && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config core.ignorecase true && + git p4 clone --use-client-spec --destination="$git" //depot && + # We ignore one file in the client spec and all path cases change from + # "TO" to "to"! + cat >expect <<-\EOF && + Path/to/File2.txt + Path/to/file3.txt + x-outside-spec/file4.txt + EOF + git ls-files >actual && + test_cmp expect actual + ) +' + +test_expect_success 'Clone path' ' + client_view "//depot/Path/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config core.ignorecase false && + git p4 clone --use-client-spec --destination="$git" //depot && + cat >expect <<-\EOF && + to/File2.txt + EOF + git ls-files >actual && + test_cmp expect actual + ) +' + +test_expect_success 'Clone path (ignorecase)' ' + client_view "//depot/Path/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config core.ignorecase true && + git p4 clone --use-client-spec --destination="$git" //depot && + cat >expect <<-\EOF && + TO/File2.txt + TO/file1.txt + TO/file3.txt + EOF + git ls-files >actual && + test_cmp expect actual + ) +' + +# It looks like P4 determines the path case based on the first file in +# lexicographical order. Please note the lower case "to" directory for all +# files triggered through the addition of "File0.txt". +test_expect_success 'Add a new file and clone path with new file (ignorecase)' ' + client_view "//depot/... //client/..." && + ( + cd "$cli" && + mkdir -p Path/to && + >Path/to/File0.txt && + p4 add Path/to/File0.txt && + p4 submit -d "Add file" && + rm -rf Path + ) && + + client_view "//depot/Path/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config core.ignorecase true && + git p4 clone --use-client-spec --destination="$git" //depot && + cat >expect <<-\EOF && + to/File0.txt + to/File2.txt + to/file1.txt + to/file3.txt + EOF + git ls-files >actual && + test_cmp expect actual + ) +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/t9822-git-p4-path-encoding.sh b/t/t9822-git-p4-path-encoding.sh new file mode 100755 index 0000000000..7b83e696a9 --- /dev/null +++ b/t/t9822-git-p4-path-encoding.sh @@ -0,0 +1,58 @@ +#!/bin/sh + +test_description='Clone repositories with non ASCII paths' + +. ./lib-git-p4.sh + +UTF8_ESCAPED="a-\303\244_o-\303\266_u-\303\274.txt" +ISO8859_ESCAPED="a-\344_o-\366_u-\374.txt" + +test_expect_success 'start p4d' ' + start_p4d +' + +test_expect_success 'Create a repo containing iso8859-1 encoded paths' ' + ( + cd "$cli" && + ISO8859="$(printf "$ISO8859_ESCAPED")" && + echo content123 >"$ISO8859" && + p4 add "$ISO8859" && + p4 submit -d "test commit" + ) +' + +test_expect_failure 'Clone auto-detects depot with iso8859-1 paths' ' + git p4 clone --destination="$git" //depot && + test_when_finished cleanup_git && + ( + cd "$git" && + UTF8="$(printf "$UTF8_ESCAPED")" && + echo "$UTF8" >expect && + git -c core.quotepath=false ls-files >actual && + test_cmp expect actual + ) +' + +test_expect_success 'Clone repo containing iso8859-1 encoded paths with git-p4.pathEncoding' ' + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config git-p4.pathEncoding iso8859-1 && + git p4 clone --use-client-spec --destination="$git" //depot && + UTF8="$(printf "$UTF8_ESCAPED")" && + echo "$UTF8" >expect && + git -c core.quotepath=false ls-files >actual && + test_cmp expect actual && + + echo content123 >expect && + cat "$UTF8" >actual && + test_cmp expect actual + ) +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/t9823-git-p4-mock-lfs.sh b/t/t9823-git-p4-mock-lfs.sh new file mode 100755 index 0000000000..1f2dc369bf --- /dev/null +++ b/t/t9823-git-p4-mock-lfs.sh @@ -0,0 +1,192 @@ +#!/bin/sh + +test_description='Clone repositories and store files in Mock LFS' + +. ./lib-git-p4.sh + +test_file_is_not_in_mock_lfs () { + FILE="$1" && + CONTENT="$2" && + echo "$CONTENT" >expect_content && + test_path_is_file "$FILE" && + test_cmp expect_content "$FILE" +} + +test_file_is_in_mock_lfs () { + FILE="$1" && + CONTENT="$2" && + LOCAL_STORAGE=".git/mock-storage/local/$CONTENT" && + SERVER_STORAGE=".git/mock-storage/remote/$CONTENT" && + echo "pointer-$CONTENT" >expect_pointer && + echo "$CONTENT" >expect_content && + test_path_is_file "$FILE" && + test_path_is_file "$LOCAL_STORAGE" && + test_path_is_file "$SERVER_STORAGE" && + test_cmp expect_pointer "$FILE" && + test_cmp expect_content "$LOCAL_STORAGE" && + test_cmp expect_content "$SERVER_STORAGE" +} + +test_file_is_deleted_in_mock_lfs () { + FILE="$1" && + CONTENT="$2" && + LOCAL_STORAGE=".git/mock-storage/local/$CONTENT" && + SERVER_STORAGE=".git/mock-storage/remote/$CONTENT" && + echo "pointer-$CONTENT" >expect_pointer && + echo "$CONTENT" >expect_content && + test_path_is_missing "$FILE" && + test_path_is_file "$LOCAL_STORAGE" && + test_path_is_file "$SERVER_STORAGE" && + test_cmp expect_content "$LOCAL_STORAGE" && + test_cmp expect_content "$SERVER_STORAGE" +} + +test_file_count_in_dir () { + DIR="$1" && + EXPECTED_COUNT="$2" && + find "$DIR" -type f >actual && + test_line_count = $EXPECTED_COUNT actual +} + +test_expect_success 'start p4d' ' + start_p4d +' + +test_expect_success 'Create repo with binary files' ' + client_view "//depot/... //client/..." && + ( + cd "$cli" && + + echo "content 1 txt 23 bytes" >file1.txt && + p4 add file1.txt && + echo "content 2-3 bin 25 bytes" >file2.dat && + p4 add file2.dat && + p4 submit -d "Add text and binary file" && + + mkdir "path with spaces" && + echo "content 2-3 bin 25 bytes" >"path with spaces/file3.bin" && + p4 add "path with spaces/file3.bin" && + p4 submit -d "Add another binary file with same content and spaces in path" && + + echo "content 4 bin 26 bytes XX" >file4.bin && + p4 add file4.bin && + p4 submit -d "Add another binary file with different content" + ) +' + +test_expect_success 'Store files in Mock LFS based on size (>24 bytes)' ' + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config git-p4.useClientSpec true && + git config git-p4.largeFileSystem MockLFS && + git config git-p4.largeFileThreshold 24 && + git config git-p4.largeFilePush True && + git p4 clone --destination="$git" //depot@all && + + test_file_is_not_in_mock_lfs file1.txt "content 1 txt 23 bytes" && + test_file_is_in_mock_lfs file2.dat "content 2-3 bin 25 bytes" && + test_file_is_in_mock_lfs "path with spaces/file3.bin" "content 2-3 bin 25 bytes" && + test_file_is_in_mock_lfs file4.bin "content 4 bin 26 bytes XX" && + + test_file_count_in_dir ".git/mock-storage/local" 2 && + test_file_count_in_dir ".git/mock-storage/remote" 2 + ) +' + +test_expect_success 'Store files in Mock LFS based on extension (dat)' ' + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config git-p4.useClientSpec true && + git config git-p4.largeFileSystem MockLFS && + git config git-p4.largeFileExtensions dat && + git config git-p4.largeFilePush True && + git p4 clone --destination="$git" //depot@all && + + test_file_is_not_in_mock_lfs file1.txt "content 1 txt 23 bytes" && + test_file_is_in_mock_lfs file2.dat "content 2-3 bin 25 bytes" && + test_file_is_not_in_mock_lfs "path with spaces/file3.bin" "content 2-3 bin 25 bytes" && + test_file_is_not_in_mock_lfs file4.bin "content 4 bin 26 bytes XX" && + + test_file_count_in_dir ".git/mock-storage/local" 1 && + test_file_count_in_dir ".git/mock-storage/remote" 1 + ) +' + +test_expect_success 'Store files in Mock LFS based on extension (dat) and use git p4 sync and no client spec' ' + test_when_finished cleanup_git && + ( + cd "$git" && + git init && + git config git-p4.useClientSpec true && + git config git-p4.largeFileSystem MockLFS && + git config git-p4.largeFileExtensions dat && + git config git-p4.largeFilePush True && + git p4 sync //depot && + git checkout p4/master && + + test_file_is_not_in_mock_lfs file1.txt "content 1 txt 23 bytes" && + test_file_is_in_mock_lfs file2.dat "content 2-3 bin 25 bytes" && + test_file_is_not_in_mock_lfs "path with spaces/file3.bin" "content 2-3 bin 25 bytes" && + test_file_is_not_in_mock_lfs file4.bin "content 4 bin 26 bytes XX" && + + test_file_count_in_dir ".git/mock-storage/local" 1 && + test_file_count_in_dir ".git/mock-storage/remote" 1 + ) +' + +test_expect_success 'Remove file from repo and store files in Mock LFS based on size (>24 bytes)' ' + client_view "//depot/... //client/..." && + ( + cd "$cli" && + p4 delete file4.bin && + p4 submit -d "Remove file" + ) && + + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config git-p4.useClientSpec true && + git config git-p4.largeFileSystem MockLFS && + git config git-p4.largeFileThreshold 24 && + git config git-p4.largeFilePush True && + git p4 clone --destination="$git" //depot@all && + + test_file_is_not_in_mock_lfs file1.txt "content 1 txt 23 bytes" && + test_file_is_in_mock_lfs file2.dat "content 2-3 bin 25 bytes" && + test_file_is_in_mock_lfs "path with spaces/file3.bin" "content 2-3 bin 25 bytes" && + test_file_is_deleted_in_mock_lfs file4.bin "content 4 bin 26 bytes XX" && + + test_file_count_in_dir ".git/mock-storage/local" 2 && + test_file_count_in_dir ".git/mock-storage/remote" 2 + ) +' + +test_expect_success 'Run git p4 submit in repo configured with large file system' ' + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config git-p4.useClientSpec true && + git config git-p4.largeFileSystem MockLFS && + git config git-p4.largeFileThreshold 24 && + git config git-p4.largeFilePush True && + git p4 clone --destination="$git" //depot@all && + + test_must_fail git p4 submit + ) +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/t9824-git-p4-git-lfs.sh b/t/t9824-git-p4-git-lfs.sh new file mode 100755 index 0000000000..0b664a377c --- /dev/null +++ b/t/t9824-git-p4-git-lfs.sh @@ -0,0 +1,288 @@ +#!/bin/sh + +test_description='Clone repositories and store files in Git LFS' + +. ./lib-git-p4.sh + +git lfs help >/dev/null 2>&1 || { + skip_all='skipping git p4 Git LFS tests; Git LFS not found' + test_done +} + +test_file_in_lfs () { + FILE="$1" && + SIZE="$2" && + EXPECTED_CONTENT="$3" && + cat "$FILE" | grep "size $SIZE" && + HASH=$(cat "$FILE" | grep "oid sha256:" | sed -e "s/oid sha256://g") && + LFS_FILE=".git/lfs/objects/$(echo "$HASH" | cut -c1-2)/$(echo "$HASH" | cut -c3-4)/$HASH" && + echo $EXPECTED_CONTENT >expect && + test_path_is_file "$FILE" && + test_path_is_file "$LFS_FILE" && + test_cmp expect "$LFS_FILE" +} + +test_file_count_in_dir () { + DIR="$1" && + EXPECTED_COUNT="$2" && + find "$DIR" -type f >actual && + test_line_count = $EXPECTED_COUNT actual +} + +test_expect_success 'start p4d' ' + start_p4d +' + +test_expect_success 'Create repo with binary files' ' + client_view "//depot/... //client/..." && + ( + cd "$cli" && + + echo "content 1 txt 23 bytes" >file1.txt && + p4 add file1.txt && + echo "content 2-3 bin 25 bytes" >file2.dat && + p4 add file2.dat && + p4 submit -d "Add text and binary file" && + + mkdir "path with spaces" && + echo "content 2-3 bin 25 bytes" >"path with spaces/file3.bin" && + p4 add "path with spaces/file3.bin" && + p4 submit -d "Add another binary file with same content and spaces in path" && + + echo "content 4 bin 26 bytes XX" >file4.bin && + p4 add file4.bin && + p4 submit -d "Add another binary file with different content" + ) +' + +test_expect_success 'Store files in LFS based on size (>24 bytes)' ' + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config git-p4.useClientSpec true && + git config git-p4.largeFileSystem GitLFS && + git config git-p4.largeFileThreshold 24 && + git p4 clone --destination="$git" //depot@all && + + test_file_in_lfs file2.dat 25 "content 2-3 bin 25 bytes" && + test_file_in_lfs "path with spaces/file3.bin" 25 "content 2-3 bin 25 bytes" && + test_file_in_lfs file4.bin 26 "content 4 bin 26 bytes XX" && + + test_file_count_in_dir ".git/lfs/objects" 2 && + + cat >expect <<-\EOF && + + # + # Git LFS (see https://git-lfs.github.com/) + # + /file2.dat filter=lfs -text + /file4.bin filter=lfs -text + /path[[:space:]]with[[:space:]]spaces/file3.bin filter=lfs -text + EOF + test_path_is_file .gitattributes && + test_cmp expect .gitattributes + ) +' + +test_expect_success 'Store files in LFS based on size (>25 bytes)' ' + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config git-p4.useClientSpec true && + git config git-p4.largeFileSystem GitLFS && + git config git-p4.largeFileThreshold 25 && + git p4 clone --destination="$git" //depot@all && + + test_file_in_lfs file4.bin 26 "content 4 bin 26 bytes XX" && + test_file_count_in_dir ".git/lfs/objects" 1 && + + cat >expect <<-\EOF && + + # + # Git LFS (see https://git-lfs.github.com/) + # + /file4.bin filter=lfs -text + EOF + test_path_is_file .gitattributes && + test_cmp expect .gitattributes + ) +' + +test_expect_success 'Store files in LFS based on extension (dat)' ' + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config git-p4.useClientSpec true && + git config git-p4.largeFileSystem GitLFS && + git config git-p4.largeFileExtensions dat && + git p4 clone --destination="$git" //depot@all && + + test_file_in_lfs file2.dat 25 "content 2-3 bin 25 bytes" && + test_file_count_in_dir ".git/lfs/objects" 1 && + + cat >expect <<-\EOF && + + # + # Git LFS (see https://git-lfs.github.com/) + # + *.dat filter=lfs -text + EOF + test_path_is_file .gitattributes && + test_cmp expect .gitattributes + ) +' + +test_expect_success 'Store files in LFS based on size (>25 bytes) and extension (dat)' ' + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config git-p4.useClientSpec true && + git config git-p4.largeFileSystem GitLFS && + git config git-p4.largeFileExtensions dat && + git config git-p4.largeFileThreshold 25 && + git p4 clone --destination="$git" //depot@all && + + test_file_in_lfs file2.dat 25 "content 2-3 bin 25 bytes" && + test_file_in_lfs file4.bin 26 "content 4 bin 26 bytes XX" && + test_file_count_in_dir ".git/lfs/objects" 2 && + + cat >expect <<-\EOF && + + # + # Git LFS (see https://git-lfs.github.com/) + # + *.dat filter=lfs -text + /file4.bin filter=lfs -text + EOF + test_path_is_file .gitattributes && + test_cmp expect .gitattributes + ) +' + +test_expect_success 'Remove file from repo and store files in LFS based on size (>24 bytes)' ' + client_view "//depot/... //client/..." && + ( + cd "$cli" && + p4 delete file4.bin && + p4 submit -d "Remove file" + ) && + + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config git-p4.useClientSpec true && + git config git-p4.largeFileSystem GitLFS && + git config git-p4.largeFileThreshold 24 && + git p4 clone --destination="$git" //depot@all && + + test_file_in_lfs file2.dat 25 "content 2-3 bin 25 bytes" && + test_file_in_lfs "path with spaces/file3.bin" 25 "content 2-3 bin 25 bytes" && + test_path_is_missing file4.bin && + test_file_count_in_dir ".git/lfs/objects" 2 && + + cat >expect <<-\EOF && + + # + # Git LFS (see https://git-lfs.github.com/) + # + /file2.dat filter=lfs -text + /path[[:space:]]with[[:space:]]spaces/file3.bin filter=lfs -text + EOF + test_path_is_file .gitattributes && + test_cmp expect .gitattributes + ) +' + +test_expect_success 'Add .gitattributes and store files in LFS based on size (>24 bytes)' ' + client_view "//depot/... //client/..." && + ( + cd "$cli" && + echo "*.txt text" >.gitattributes && + p4 add .gitattributes && + p4 submit -d "Add .gitattributes" + ) && + + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config git-p4.useClientSpec true && + git config git-p4.largeFileSystem GitLFS && + git config git-p4.largeFileThreshold 24 && + git p4 clone --destination="$git" //depot@all && + + test_file_in_lfs file2.dat 25 "content 2-3 bin 25 bytes" && + test_file_in_lfs "path with spaces/file3.bin" 25 "content 2-3 bin 25 bytes" && + test_path_is_missing file4.bin && + test_file_count_in_dir ".git/lfs/objects" 2 && + + cat >expect <<-\EOF && + *.txt text + + # + # Git LFS (see https://git-lfs.github.com/) + # + /file2.dat filter=lfs -text + /path[[:space:]]with[[:space:]]spaces/file3.bin filter=lfs -text + EOF + test_path_is_file .gitattributes && + test_cmp expect .gitattributes + ) +' + +test_expect_success 'Add big files to repo and store files in LFS based on compressed size (>28 bytes)' ' + client_view "//depot/... //client/..." && + ( + cd "$cli" && + echo "content 5 bin 40 bytes XXXXXXXXXXXXXXXX" >file5.bin && + p4 add file5.bin && + p4 submit -d "Add file with small footprint after compression" && + + echo "content 6 bin 39 bytes XXXXXYYYYYZZZZZ" >file6.bin && + p4 add file6.bin && + p4 submit -d "Add file with large footprint after compression" + ) && + + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config git-p4.useClientSpec true && + git config git-p4.largeFileSystem GitLFS && + git config git-p4.largeFileCompressedThreshold 28 && + # We only import HEAD here ("@all" is missing!) + git p4 clone --destination="$git" //depot && + + test_file_in_lfs file6.bin 13 "content 6 bin 39 bytes XXXXXYYYYYZZZZZ" + test_file_count_in_dir ".git/lfs/objects" 1 && + + cat >expect <<-\EOF && + *.txt text + + # + # Git LFS (see https://git-lfs.github.com/) + # + /file6.bin filter=lfs -text + EOF + test_path_is_file .gitattributes && + test_cmp expect .gitattributes + ) +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/t9825-git-p4-handle-utf16-without-bom.sh b/t/t9825-git-p4-handle-utf16-without-bom.sh new file mode 100755 index 0000000000..1551845dc1 --- /dev/null +++ b/t/t9825-git-p4-handle-utf16-without-bom.sh @@ -0,0 +1,50 @@ +#!/bin/sh + +test_description='git p4 handling of UTF-16 files without BOM' + +. ./lib-git-p4.sh + +UTF16="\227\000\227\000" + +test_expect_success 'start p4d' ' + start_p4d +' + +test_expect_success 'init depot with UTF-16 encoded file and artificially remove BOM' ' + ( + cd "$cli" && + printf "$UTF16" >file1 && + p4 add -t utf16 file1 && + p4 submit -d "file1" + ) && + + ( + cd db && + p4d -jc && + # P4D automatically adds a BOM. Remove it here to make the file invalid. + sed -e "\$d" depot/file1,v >depot/file1,v.new && + mv depot/file1,v.new depot/file1,v && + printf "@$UTF16@" >>depot/file1,v && + p4d -jrF checkpoint.1 + ) +' + +test_expect_success 'clone depot with invalid UTF-16 file in verbose mode' ' + git p4 clone --dest="$git" --verbose //depot && + test_when_finished cleanup_git && + ( + cd "$git" && + printf "$UTF16" >expect && + test_cmp_bin expect file1 + ) +' + +test_expect_failure 'clone depot with invalid UTF-16 file in non-verbose mode' ' + git p4 clone --dest="$git" //depot +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/t9826-git-p4-keep-empty-commits.sh b/t/t9826-git-p4-keep-empty-commits.sh new file mode 100755 index 0000000000..be12960d39 --- /dev/null +++ b/t/t9826-git-p4-keep-empty-commits.sh @@ -0,0 +1,134 @@ +#!/bin/sh + +test_description='Clone repositories and keep empty commits' + +. ./lib-git-p4.sh + +test_expect_success 'start p4d' ' + start_p4d +' + +test_expect_success 'Create a repo' ' + client_view "//depot/... //client/..." && + ( + cd "$cli" && + + mkdir -p subdir && + + >subdir/file1.txt && + p4 add subdir/file1.txt && + p4 submit -d "Add file 1" && + + >file2.txt && + p4 add file2.txt && + p4 submit -d "Add file 2" && + + >subdir/file3.txt && + p4 add subdir/file3.txt && + p4 submit -d "Add file 3" && + + >file4.txt && + p4 add file4.txt && + p4 submit -d "Add file 4" && + + p4 delete subdir/file3.txt && + p4 submit -d "Remove file 3" && + + p4 delete file4.txt && + p4 submit -d "Remove file 4" + ) +' + +test_expect_success 'Clone repo root path with all history' ' + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git p4 clone --use-client-spec --destination="$git" //depot@all && + cat >expect <<-\EOF && +Remove file 4 +[git-p4: depot-paths = "//depot/": change = 6] + +Remove file 3 +[git-p4: depot-paths = "//depot/": change = 5] + +Add file 4 +[git-p4: depot-paths = "//depot/": change = 4] + +Add file 3 +[git-p4: depot-paths = "//depot/": change = 3] + +Add file 2 +[git-p4: depot-paths = "//depot/": change = 2] + +Add file 1 +[git-p4: depot-paths = "//depot/": change = 1] + + EOF + git log --format=%B >actual && + test_cmp expect actual + ) +' + +test_expect_success 'Clone repo subdir with all history but keep empty commits' ' + client_view "//depot/subdir/... //client/subdir/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git config git-p4.keepEmptyCommits true && + git p4 clone --use-client-spec --destination="$git" //depot@all && + cat >expect <<-\EOF && +Remove file 4 +[git-p4: depot-paths = "//depot/": change = 6] + +Remove file 3 +[git-p4: depot-paths = "//depot/": change = 5] + +Add file 4 +[git-p4: depot-paths = "//depot/": change = 4] + +Add file 3 +[git-p4: depot-paths = "//depot/": change = 3] + +Add file 2 +[git-p4: depot-paths = "//depot/": change = 2] + +Add file 1 +[git-p4: depot-paths = "//depot/": change = 1] + + EOF + git log --format=%B >actual && + test_cmp expect actual + ) +' + +test_expect_success 'Clone repo subdir with all history' ' + client_view "//depot/subdir/... //client/subdir/..." && + test_when_finished cleanup_git && + ( + cd "$git" && + git init . && + git p4 clone --use-client-spec --destination="$git" --verbose //depot@all && + cat >expect <<-\EOF && +Remove file 3 +[git-p4: depot-paths = "//depot/": change = 5] + +Add file 3 +[git-p4: depot-paths = "//depot/": change = 3] + +Add file 1 +[git-p4: depot-paths = "//depot/": change = 1] + + EOF + git log --format=%B >actual && + test_cmp expect actual + ) +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index 2d4beb5e50..2ba62fbc17 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -212,9 +212,18 @@ test_expect_success '__gitdir - non-existing $GIT_DIR' ' ) ' +function pwd_P_W () { + if test_have_prereq MINGW + then + pwd -W + else + pwd -P + fi +} + test_expect_success '__gitdir - gitfile in cwd' ' - echo "$(pwd -P)/otherrepo/.git" >expected && - echo "gitdir: $TRASH_DIRECTORY/otherrepo/.git" >subdir/.git && + echo "$(pwd_P_W)/otherrepo/.git" >expected && + echo "gitdir: $(pwd_P_W)/otherrepo/.git" >subdir/.git && test_when_finished "rm -f subdir/.git" && ( cd subdir && @@ -224,8 +233,8 @@ test_expect_success '__gitdir - gitfile in cwd' ' ' test_expect_success '__gitdir - gitfile in parent' ' - echo "$(pwd -P)/otherrepo/.git" >expected && - echo "gitdir: $TRASH_DIRECTORY/otherrepo/.git" >subdir/.git && + echo "$(pwd_P_W)/otherrepo/.git" >expected && + echo "gitdir: $(pwd_P_W)/otherrepo/.git" >subdir/.git && test_when_finished "rm -f subdir/.git" && ( cd subdir/subsubdir && @@ -342,6 +351,59 @@ test_expect_success '__gitcomp_nl - doesnt fail because of invalid variable name __gitcomp_nl "$invalid_variable_name" ' +test_expect_success '__git_remotes - list remotes from $GIT_DIR/remotes and from config file' ' + cat >expect <<-EOF && + remote_from_file_1 + remote_from_file_2 + remote_in_config_1 + remote_in_config_2 + EOF + test_when_finished "rm -rf .git/remotes" && + mkdir -p .git/remotes && + >.git/remotes/remote_from_file_1 && + >.git/remotes/remote_from_file_2 && + test_when_finished "git remote remove remote_in_config_1" && + git remote add remote_in_config_1 git://remote_1 && + test_when_finished "git remote remove remote_in_config_2" && + git remote add remote_in_config_2 git://remote_2 && + __git_remotes >actual && + test_cmp expect actual +' + +test_expect_success '__git_get_config_variables' ' + cat >expect <<-EOF && + name-1 + name-2 + EOF + test_config interesting.name-1 good && + test_config interesting.name-2 good && + test_config subsection.interesting.name-3 bad && + __git_get_config_variables interesting >actual && + test_cmp expect actual +' + +test_expect_success '__git_pretty_aliases' ' + cat >expect <<-EOF && + author + hash + EOF + test_config pretty.author "%an %ae" && + test_config pretty.hash %H && + __git_pretty_aliases >actual && + test_cmp expect actual +' + +test_expect_success '__git_aliases' ' + cat >expect <<-EOF && + ci + co + EOF + test_config alias.ci commit && + test_config alias.co checkout && + __git_aliases >actual && + test_cmp expect actual +' + test_expect_success 'basic' ' run_completion "git " && # built-in @@ -540,7 +602,7 @@ test_expect_success 'complete files' ' test_completion "git commit " "modified" && : TODO .gitignore should not be here && - test_completion "git ls-files " <<-\EOF + test_completion "git ls-files " <<-\EOF && .gitignore dir modified @@ -550,6 +612,33 @@ test_expect_success 'complete files' ' test_completion "git add mom" "momified" ' +test_expect_success "completion uses <cmd> completion for alias: !sh -c 'git <cmd> ...'" ' + test_config alias.co "!sh -c '"'"'git checkout ...'"'"'" && + test_completion "git co m" <<-\EOF + master Z + mybranch Z + mytag Z + EOF +' + +test_expect_success 'completion uses <cmd> completion for alias: !f () { VAR=val git <cmd> ... }' ' + test_config alias.co "!f () { VAR=val git checkout ... ; } f" && + test_completion "git co m" <<-\EOF + master Z + mybranch Z + mytag Z + EOF +' + +test_expect_success 'completion used <cmd> completion for alias: !f() { : git <cmd> ; ... }' ' + test_config alias.co "!f() { : git checkout ; if ... } f" && + test_completion "git co m" <<-\EOF + master Z + mybranch Z + mytag Z + EOF +' + test_expect_failure 'complete with tilde expansion' ' git init tmp && cd tmp && test_when_finished "cd .. && rm -rf tmp" && diff --git a/t/t9903-bash-prompt.sh b/t/t9903-bash-prompt.sh index 9150984184..af82049f82 100755 --- a/t/t9903-bash-prompt.sh +++ b/t/t9903-bash-prompt.sh @@ -35,6 +35,8 @@ test_expect_success 'setup for prompt tests' ' git commit -m "another b2" file && echo 000 >file && git commit -m "yet another b2" file && + mkdir ignored_dir && + echo "ignored_dir/" >>.gitignore && git checkout master ' @@ -164,7 +166,7 @@ test_expect_success 'prompt - inside bare repository' ' ' test_expect_success 'prompt - interactive rebase' ' - printf " (b1|REBASE-i 2/3)" >expected + printf " (b1|REBASE-i 2/3)" >expected && write_script fake_editor.sh <<-\EOF && echo "exec echo" >"$1" echo "edit $(git log -1 --format="%h")" >>"$1" @@ -271,11 +273,36 @@ test_expect_success 'prompt - dirty status indicator - dirty index and worktree' test_cmp expected "$actual" ' -test_expect_success 'prompt - dirty status indicator - before root commit' ' - printf " (master #)" >expected && +test_expect_success 'prompt - dirty status indicator - orphan branch - clean' ' + printf " (orphan #)" >expected && + test_when_finished "git checkout master" && + git checkout --orphan orphan && + git reset --hard && + ( + GIT_PS1_SHOWDIRTYSTATE=y && + __git_ps1 >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - dirty status indicator - orphan branch - dirty index' ' + printf " (orphan +)" >expected && + test_when_finished "git checkout master" && + git checkout --orphan orphan && + ( + GIT_PS1_SHOWDIRTYSTATE=y && + __git_ps1 >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - dirty status indicator - orphan branch - dirty index and worktree' ' + printf " (orphan *+)" >expected && + test_when_finished "git checkout master" && + git checkout --orphan orphan && + >file && ( GIT_PS1_SHOWDIRTYSTATE=y && - cd otherrepo && __git_ps1 >"$actual" ) && test_cmp expected "$actual" @@ -395,6 +422,42 @@ test_expect_success 'prompt - untracked files status indicator - untracked files test_cmp expected "$actual" ' +test_expect_success 'prompt - untracked files status indicator - empty untracked dir' ' + printf " (master)" >expected && + mkdir otherrepo/untracked-dir && + test_when_finished "rm -rf otherrepo/untracked-dir" && + ( + GIT_PS1_SHOWUNTRACKEDFILES=y && + cd otherrepo && + __git_ps1 >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - untracked files status indicator - non-empty untracked dir' ' + printf " (master %%)" >expected && + mkdir otherrepo/untracked-dir && + test_when_finished "rm -rf otherrepo/untracked-dir" && + >otherrepo/untracked-dir/untracked-file && + ( + GIT_PS1_SHOWUNTRACKEDFILES=y && + cd otherrepo && + __git_ps1 >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - untracked files status indicator - untracked files outside cwd' ' + printf " (master %%)" >expected && + ( + mkdir -p ignored_dir && + cd ignored_dir && + GIT_PS1_SHOWUNTRACKEDFILES=y && + __git_ps1 >"$actual" + ) && + test_cmp expected "$actual" +' + test_expect_success 'prompt - untracked files status indicator - shell variable unset with config disabled' ' printf " (master)" >expected && test_config bash.showUntrackedFiles false && @@ -588,4 +651,108 @@ test_expect_success 'prompt - zsh color pc mode' ' test_cmp expected "$actual" ' +test_expect_success 'prompt - hide if pwd ignored - env var unset, config disabled' ' + printf " (master)" >expected && + test_config bash.hideIfPwdIgnored false && + ( + cd ignored_dir && + __git_ps1 >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - hide if pwd ignored - env var unset, config disabled, pc mode' ' + printf "BEFORE: (\${__git_ps1_branch_name}):AFTER" >expected && + test_config bash.hideIfPwdIgnored false && + ( + cd ignored_dir && + __git_ps1 "BEFORE:" ":AFTER" && + printf "%s" "$PS1" >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - hide if pwd ignored - env var unset, config unset' ' + printf " (master)" >expected && + ( + cd ignored_dir && + __git_ps1 >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - hide if pwd ignored - env var unset, config unset, pc mode' ' + printf "BEFORE: (\${__git_ps1_branch_name}):AFTER" >expected && + ( + cd ignored_dir && + __git_ps1 "BEFORE:" ":AFTER" && + printf "%s" "$PS1" >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - hide if pwd ignored - env var set, config disabled' ' + printf " (master)" >expected && + test_config bash.hideIfPwdIgnored false && + ( + cd ignored_dir && + GIT_PS1_HIDE_IF_PWD_IGNORED=y && + __git_ps1 >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - hide if pwd ignored - env var set, config disabled, pc mode' ' + printf "BEFORE: (\${__git_ps1_branch_name}):AFTER" >expected && + test_config bash.hideIfPwdIgnored false && + ( + cd ignored_dir && + GIT_PS1_HIDE_IF_PWD_IGNORED=y && + __git_ps1 "BEFORE:" ":AFTER" && + printf "%s" "$PS1" >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - hide if pwd ignored - env var set, config unset' ' + printf "" >expected && + ( + cd ignored_dir && + GIT_PS1_HIDE_IF_PWD_IGNORED=y && + __git_ps1 >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - hide if pwd ignored - env var set, config unset, pc mode' ' + printf "BEFORE::AFTER" >expected && + ( + cd ignored_dir && + GIT_PS1_HIDE_IF_PWD_IGNORED=y && + __git_ps1 "BEFORE:" ":AFTER" && + printf "%s" "$PS1" >"$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - hide if pwd ignored - inside gitdir (stdout)' ' + printf " (GIT_DIR!)" >expected && + ( + GIT_PS1_HIDE_IF_PWD_IGNORED=y && + cd .git && + __git_ps1 >"$actual" 2>/dev/null + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - hide if pwd ignored - inside gitdir (stderr)' ' + printf "" >expected && + ( + GIT_PS1_HIDE_IF_PWD_IGNORED=y && + cd .git && + __git_ps1 >/dev/null 2>"$actual" + ) && + test_cmp expected "$actual" +' + test_done diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh index cf7b41f66d..c64e5a5025 100644 --- a/t/test-lib-functions.sh +++ b/t/test-lib-functions.sh @@ -145,6 +145,14 @@ test_pause () { fi } +# Wrap git in gdb. Adding this to a command can make it easier to +# understand what is going on in a failing test. +# +# Example: "debug git checkout master". +debug () { + GIT_TEST_GDB=1 "$@" +} + # Call test_commit with the arguments "<message> [<file> [<contents> [<tag>]]]" # # This will commit a file with the given contents and the given commit @@ -201,7 +209,14 @@ test_chmod () { # Unset a configuration variable, but don't fail if it doesn't exist. test_unconfig () { - git config --unset-all "$@" + config_dir= + if test "$1" = -C + then + shift + config_dir=$1 + shift + fi + git ${config_dir:+-C "$config_dir"} config --unset-all "$@" config_status=$? case "$config_status" in 5) # ok, nothing to unset @@ -213,8 +228,15 @@ test_unconfig () { # Set git config, automatically unsetting it after the test is over. test_config () { - test_when_finished "test_unconfig '$1'" && - git config "$@" + config_dir= + if test "$1" = -C + then + shift + config_dir=$1 + shift + fi + test_when_finished "test_unconfig ${config_dir:+-C '$config_dir'} '$1'" && + git ${config_dir:+-C "$config_dir"} config "$@" } test_config_global () { @@ -348,11 +370,18 @@ test_declared_prereq () { return 1 } +test_verify_prereq () { + test -z "$test_prereq" || + expr >/dev/null "$test_prereq" : '[A-Z0-9_,!]*$' || + error "bug in the test script: '$test_prereq' does not look like a prereq" +} + test_expect_failure () { test_start_ test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq= test "$#" = 2 || error "bug in the test script: not 2 or 3 parameters to test-expect-failure" + test_verify_prereq export test_prereq if ! test_skip "$@" then @@ -372,6 +401,7 @@ test_expect_success () { test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq= test "$#" = 2 || error "bug in the test script: not 2 or 3 parameters to test-expect-success" + test_verify_prereq export test_prereq if ! test_skip "$@" then @@ -400,6 +430,7 @@ test_external () { error >&5 "bug in the test script: not 3 or 4 parameters to test_external" descr="$1" shift + test_verify_prereq export test_prereq if ! test_skip "$descr" "$@" then @@ -413,7 +444,7 @@ test_external () { # test_run_, but keep its stdout on our stdout even in # non-verbose mode. "$@" 2>&4 - if [ "$?" = 0 ] + if test "$?" = 0 then if test $test_external_has_tap -eq 0; then test_ok_ "$descr" @@ -440,11 +471,12 @@ test_external_without_stderr () { tmp=${TMPDIR:-/tmp} stderr="$tmp/git-external-stderr.$$.tmp" test_external "$@" 4> "$stderr" - [ -f "$stderr" ] || error "Internal error: $stderr disappeared." + test -f "$stderr" || error "Internal error: $stderr disappeared." descr="no stderr: $1" shift say >&3 "# expecting no stderr from previous command" - if [ ! -s "$stderr" ]; then + if test ! -s "$stderr" + then rm "$stderr" if test $test_external_has_tap -eq 0; then @@ -454,8 +486,9 @@ test_external_without_stderr () { test_success=$(($test_success + 1)) fi else - if [ "$verbose" = t ]; then - output=`echo; echo "# Stderr is:"; cat "$stderr"` + if test "$verbose" = t + then + output=$(echo; echo "# Stderr is:"; cat "$stderr") else output= fi @@ -474,27 +507,39 @@ test_external_without_stderr () { # The commands test the existence or non-existence of $1. $2 can be # given to provide a more precise diagnosis. test_path_is_file () { - if ! [ -f "$1" ] + if ! test -f "$1" then - echo "File $1 doesn't exist. $*" + echo "File $1 doesn't exist. $2" false fi } test_path_is_dir () { - if ! [ -d "$1" ] + if ! test -d "$1" then - echo "Directory $1 doesn't exist. $*" + echo "Directory $1 doesn't exist. $2" false fi } +# Check if the directory exists and is empty as expected, barf otherwise. +test_dir_is_empty () { + test_path_is_dir "$1" && + if test -n "$(ls -a1 "$1" | egrep -v '^\.\.?$')" + then + echo "Directory '$1' is not empty, it contains:" + ls -la "$1" + return 1 + fi +} + test_path_is_missing () { - if [ -e "$1" ] + if test -e "$1" then echo "Path exists:" ls -ld "$1" - if [ $# -ge 1 ]; then + if test $# -ge 1 + then echo "$*" fi false @@ -524,6 +569,21 @@ test_line_count () { fi } +# Returns success if a comma separated string of keywords ($1) contains a +# given keyword ($2). +# Examples: +# `list_contains "foo,bar" bar` returns 0 +# `list_contains "foo" bar` returns 1 + +list_contains () { + case ",$1," in + *,$2,*) + return 0 + ;; + esac + return 1 +} + # This is not among top-level (test_expect_success | test_expect_failure) # but is a prefix that can be used in the test script, like: # @@ -537,18 +597,34 @@ test_line_count () { # the failure could be due to a segv. We want a controlled failure. test_must_fail () { + case "$1" in + ok=*) + _test_ok=${1#ok=} + shift + ;; + *) + _test_ok= + ;; + esac "$@" exit_code=$? - if test $exit_code = 0; then + if test $exit_code -eq 0 && ! list_contains "$_test_ok" success + then echo >&2 "test_must_fail: command succeeded: $*" return 1 - elif test $exit_code -gt 129 -a $exit_code -le 192; then + elif test $exit_code -eq 141 && list_contains "$_test_ok" sigpipe + then + return 0 + elif test $exit_code -gt 129 && test $exit_code -le 192 + then echo >&2 "test_must_fail: died by signal: $*" return 1 - elif test $exit_code = 127; then + elif test $exit_code -eq 127 + then echo >&2 "test_must_fail: command not found: $*" return 1 - elif test $exit_code = 126; then + elif test $exit_code -eq 126 + then echo >&2 "test_must_fail: valgrind error: $*" return 1 fi @@ -567,16 +643,7 @@ test_must_fail () { # because we want to notice if it fails due to segv. test_might_fail () { - "$@" - exit_code=$? - if test $exit_code -gt 129 -a $exit_code -le 192; then - echo >&2 "test_might_fail: died by signal: $*" - return 1 - elif test $exit_code = 127; then - echo >&2 "test_might_fail: command not found: $*" - return 1 - fi - return 0 + test_must_fail ok=success "$@" } # Similar to test_must_fail and test_might_fail, but check that a @@ -623,6 +690,15 @@ test_cmp_bin() { cmp "$@" } +# Call any command "$@" but be more verbose about its +# failure. This is handy for commands like "test" which do +# not output anything when they fail. +verbose () { + "$@" && return 0 + echo >&2 "command failed: $(git rev-parse --sq-quote "$@")" + return 1 +} + # Check if the file expected to be empty is indeed empty, and barfs # otherwise. @@ -646,9 +722,12 @@ test_cmp_rev () { # similar to GNU seq(1), but the latter might not be available # everywhere (and does not do letters). It may be used like: # -# for i in `test_seq 100`; do -# for j in `test_seq 10 20`; do -# for k in `test_seq a z`; do +# for i in $(test_seq 100) +# do +# for j in $(test_seq 10 20) +# do +# for k in $(test_seq a z) +# do # echo $i-$j-$k # done # done @@ -687,6 +766,11 @@ test_seq () { # what went wrong. test_when_finished () { + # We cannot detect when we are in a subshell in general, but by + # doing so on Bash is better than nothing (the test will + # silently pass on other shells). + test "${BASH_SUBSHELL-0}" = 0 || + error "bug in test script: test_when_finished does nothing in a subshell" test_cleanup="{ $* } && (exit \"\$eval_ret\"); eval_ret=\$?; $test_cleanup" } @@ -719,10 +803,17 @@ test_ln_s_add () { else printf '%s' "$1" >"$2" && ln_s_obj=$(git hash-object -w "$2") && - git update-index --add --cacheinfo 120000 $ln_s_obj "$2" + git update-index --add --cacheinfo 120000 $ln_s_obj "$2" && + # pick up stat info from the file + git update-index "$2" fi } +# This function writes out its parameters, one per line +test_write_lines () { + printf "%s\n" "$@" +} + perl () { command "$PERL_PATH" "$@" } diff --git a/t/test-lib.sh b/t/test-lib.sh index e0266f0357..bd4b02e9db 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -15,9 +15,6 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/ . -# Keep the original TERM for say_color -ORIGINAL_TERM=$TERM - # Test the binaries we have just built. The tests are kept in # t/ subdirectory and are run in 'trash directory' subdirectory. if test -z "$TEST_DIRECTORY" @@ -68,12 +65,12 @@ done,*) esac # For repeatability, reset the environment to known value. +# TERM is sanitized below, after saving color control sequences. LANG=C LC_ALL=C PAGER=cat TZ=UTC -TERM=dumb -export LANG LC_ALL PAGER TERM TZ +export LANG LC_ALL PAGER TZ EDITOR=: # A call to "unset" with no arguments causes at least Solaris 10 # /usr/xpg4/bin/sh and /bin/ksh to bail out. So keep the unsets @@ -91,6 +88,7 @@ unset VISUAL EMAIL LANGUAGE COLUMNS $("$PERL_PATH" -e ' VALGRIND UNZIP PERF_ + CURL_VERBOSE )); my @vars = grep(/^GIT_/ && !/^GIT_($ok)/o, @env); print join("\n", @vars); @@ -108,6 +106,10 @@ export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME export GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME export EDITOR +# Tests using GIT_TRACE typically don't want <timestamp> <file>:<line> output +GIT_TRACE_BARE=1 +export GIT_TRACE_BARE + if test -n "${TEST_GIT_INDEX_VERSION:+isset}" then GIT_INDEX_VERSION="$TEST_GIT_INDEX_VERSION" @@ -135,6 +137,9 @@ else } fi +: ${ASAN_OPTIONS=detect_leaks=0} +export ASAN_OPTIONS + # Protect ourselves from common misconfiguration to export # CDPATH into the environment unset CDPATH @@ -144,10 +149,7 @@ unset UNZIP case $(echo $GIT_TRACE |tr "[A-Z]" "[a-z]") in 1|2|true) - echo "* warning: Some tests will not work if GIT_TRACE" \ - "is set as to trace on STDERR ! *" - echo "* warning: Please set GIT_TRACE to something" \ - "other than 1, 2 or true ! *" + GIT_TRACE=4 ;; esac @@ -176,10 +178,8 @@ export _x05 _x40 _z40 LF u200c # This test checks if command xyzzy does the right thing... # ' # . ./test-lib.sh -[ "x$ORIGINAL_TERM" != "xdumb" ] && ( - TERM=$ORIGINAL_TERM && - export TERM && - [ -t 1 ] && +test "x$TERM" != "xdumb" && ( + test -t 1 && tput bold >/dev/null 2>&1 && tput setaf 1 >/dev/null 2>&1 && tput sgr0 >/dev/null 2>&1 @@ -195,6 +195,14 @@ do immediate=t; shift ;; -l|--l|--lo|--lon|--long|--long-|--long-t|--long-te|--long-tes|--long-test|--long-tests) GIT_TEST_LONG=t; export GIT_TEST_LONG; shift ;; + -r) + shift; test "$#" -ne 0 || { + echo 'error: -r requires an argument' >&2; + exit 1; + } + run_list=$1; shift ;; + --run=*) + run_list=$(expr "z$1" : 'z[^=]*=\(.*\)'); shift ;; -h|--h|--he|--hel|--help) help=t; shift ;; -v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose) @@ -224,6 +232,16 @@ do --root=*) root=$(expr "z$1" : 'z[^=]*=\(.*\)') shift ;; + --chain-lint) + GIT_TEST_CHAIN_LINT=1 + shift ;; + --no-chain-lint) + GIT_TEST_CHAIN_LINT=0 + shift ;; + -x) + trace=t + verbose=t + shift ;; *) echo "error: unknown test option '$1'" >&2; exit 1 ;; esac @@ -240,29 +258,30 @@ fi if test -n "$color" then + # Save the color control sequences now rather than run tput + # each time say_color() is called. This is done for two + # reasons: + # * TERM will be changed to dumb + # * HOME will be changed to a temporary directory and tput + # might need to read ~/.terminfo from the original HOME + # directory to get the control sequences + # Note: This approach assumes the control sequences don't end + # in a newline for any terminal of interest (command + # substitutions strip trailing newlines). Given that most + # (all?) terminals in common use are related to ECMA-48, this + # shouldn't be a problem. + say_color_error=$(tput bold; tput setaf 1) # bold red + say_color_skip=$(tput setaf 4) # blue + say_color_warn=$(tput setaf 3) # brown/yellow + say_color_pass=$(tput setaf 2) # green + say_color_info=$(tput setaf 6) # cyan + say_color_reset=$(tput sgr0) + say_color_="" # no formatting for normal text say_color () { - ( - TERM=$ORIGINAL_TERM - export TERM - case "$1" in - error) - tput bold; tput setaf 1;; # bold red - skip) - tput setaf 4;; # blue - warn) - tput setaf 3;; # brown/yellow - pass) - tput setaf 2;; # green - info) - tput setaf 6;; # cyan - *) - test -n "$quiet" && return;; - esac + test -z "$1" && test -n "$quiet" && return + eval "say_color_color=\$say_color_$1" shift - printf "%s" "$*" - tput sgr0 - echo - ) + printf "%s\\n" "$say_color_color$*$say_color_reset" } else say_color() { @@ -272,6 +291,9 @@ else } fi +TERM=dumb +export TERM + error () { say_color error "error: $*" GIT_EXIT_OK=t @@ -321,6 +343,7 @@ die () { GIT_EXIT_OK= trap 'die' EXIT +trap 'exit $?' INT # The user-facing functions are loaded from a separate file so that # test_perf subshells can have them too @@ -370,6 +393,99 @@ match_pattern_list () { return 1 } +match_test_selector_list () { + title="$1" + shift + arg="$1" + shift + test -z "$1" && return 0 + + # Both commas and whitespace are accepted as separators. + OLDIFS=$IFS + IFS=' ,' + set -- $1 + IFS=$OLDIFS + + # If the first selector is negative we include by default. + include= + case "$1" in + !*) include=t ;; + esac + + for selector + do + orig_selector=$selector + + positive=t + case "$selector" in + !*) + positive= + selector=${selector##?} + ;; + esac + + test -z "$selector" && continue + + case "$selector" in + *-*) + if expr "z${selector%%-*}" : "z[0-9]*[^0-9]" >/dev/null + then + echo "error: $title: invalid non-numeric in range" \ + "start: '$orig_selector'" >&2 + exit 1 + fi + if expr "z${selector#*-}" : "z[0-9]*[^0-9]" >/dev/null + then + echo "error: $title: invalid non-numeric in range" \ + "end: '$orig_selector'" >&2 + exit 1 + fi + ;; + *) + if expr "z$selector" : "z[0-9]*[^0-9]" >/dev/null + then + echo "error: $title: invalid non-numeric in test" \ + "selector: '$orig_selector'" >&2 + exit 1 + fi + esac + + # Short cut for "obvious" cases + test -z "$include" && test -z "$positive" && continue + test -n "$include" && test -n "$positive" && continue + + case "$selector" in + -*) + if test $arg -le ${selector#-} + then + include=$positive + fi + ;; + *-) + if test $arg -ge ${selector%-} + then + include=$positive + fi + ;; + *-*) + if test ${selector%%-*} -le $arg \ + && test $arg -le ${selector#*-} + then + include=$positive + fi + ;; + *) + if test $arg -eq $selector + then + include=$positive + fi + ;; + esac + done + + test -n "$include" +} + maybe_teardown_verbose () { test -z "$verbose_only" && return exec 4>/dev/null 3>/dev/null @@ -415,21 +531,70 @@ maybe_setup_valgrind () { fi } +want_trace () { + test "$trace" = t && test "$verbose" = t +} + +# This is a separate function because some tests use +# "return" to end a test_expect_success block early +# (and we want to make sure we run any cleanup like +# "set +x"). +test_eval_inner_ () { + # Do not add anything extra (including LF) after '$*' + eval " + want_trace && set -x + $*" +} + test_eval_ () { - # This is a separate function because some tests use - # "return" to end a test_expect_success block early. - eval </dev/null >&3 2>&4 "$*" + # We run this block with stderr redirected to avoid extra cruft + # during a "-x" trace. Once in "set -x" mode, we cannot prevent + # the shell from printing the "set +x" to turn it off (nor the saving + # of $? before that). But we can make sure that the output goes to + # /dev/null. + # + # The test itself is run with stderr put back to &4 (so either to + # /dev/null, or to the original stderr if --verbose was used). + { + test_eval_inner_ "$@" </dev/null >&3 2>&4 + test_eval_ret_=$? + if want_trace + then + set +x + if test "$test_eval_ret_" != 0 + then + say_color error >&4 "error: last command exited with \$?=$test_eval_ret_" + fi + fi + } 2>/dev/null + return $test_eval_ret_ } test_run_ () { test_cleanup=: expecting_failure=$2 + + if test "${GIT_TEST_CHAIN_LINT:-1}" != 0; then + # turn off tracing for this test-eval, as it simply creates + # confusing noise in the "-x" output + trace_tmp=$trace + trace= + # 117 is magic because it is unlikely to match the exit + # code of other programs + test_eval_ "(exit 117) && $1" + if test "$?" != 117; then + error "bug in the test script: broken &&-chain: $1" + fi + trace=$trace_tmp + fi + setup_malloc_check test_eval_ "$1" eval_ret=$? teardown_malloc_check - if test -z "$immediate" || test $eval_ret = 0 || test -n "$expecting_failure" + if test -z "$immediate" || test $eval_ret = 0 || + test -n "$expecting_failure" && test "$test_cleanup" != ":" then setup_malloc_check test_eval_ "$test_cleanup" @@ -456,25 +621,35 @@ test_finish_ () { test_skip () { to_skip= + skipped_reason= if match_pattern_list $this_test.$test_count $GIT_SKIP_TESTS then to_skip=t + skipped_reason="GIT_SKIP_TESTS" fi if test -z "$to_skip" && test -n "$test_prereq" && ! test_have_prereq "$test_prereq" then to_skip=t - fi - case "$to_skip" in - t) + of_prereq= if test "$missing_prereq" != "$test_prereq" then of_prereq=" of $test_prereq" fi + skipped_reason="missing $missing_prereq${of_prereq}" + fi + if test -z "$to_skip" && test -n "$run_list" && + ! match_test_selector_list '--run' $test_count "$run_list" + then + to_skip=t + skipped_reason="--run" + fi + case "$to_skip" in + t) say_color skip >&3 "skipping test: $@" - say_color skip "ok $test_count # skip $1 (missing $missing_prereq${of_prereq})" + say_color skip "ok $test_count # skip $1 ($skipped_reason)" : true ;; *) @@ -531,7 +706,7 @@ test_done () { then error "Can't use skip_all after running some tests" fi - [ -z "$skip_all" ] || skip_all=" # SKIP $skip_all" + test -z "$skip_all" || skip_all=" # SKIP $skip_all" if test $test_external_has_tap -eq 0 then @@ -701,7 +876,8 @@ rm -fr "$TRASH_DIRECTORY" || { } HOME="$TRASH_DIRECTORY" -export HOME +GNUPGHOME="$HOME/gnupg-home-not-used" +export HOME GNUPGHOME if test -z "$TEST_NO_CREATE_REPO" then @@ -758,7 +934,7 @@ case $(uname -s) in # backslashes in pathspec are converted to '/' # exec does not inherit the PID test_set_prereq MINGW - test_set_prereq NOT_CYGWIN + test_set_prereq NATIVE_CRLF test_set_prereq SED_STRIPS_CR test_set_prereq GREP_STRIPS_CR GIT_TEST_CMP=mingw_test_cmp @@ -766,7 +942,6 @@ case $(uname -s) in *CYGWIN*) test_set_prereq POSIXPERM test_set_prereq EXECKEEPSPID - test_set_prereq NOT_MINGW test_set_prereq CYGWIN test_set_prereq SED_STRIPS_CR test_set_prereq GREP_STRIPS_CR @@ -775,8 +950,6 @@ case $(uname -s) in test_set_prereq POSIXPERM test_set_prereq BSLASHPSPEC test_set_prereq EXECKEEPSPID - test_set_prereq NOT_MINGW - test_set_prereq NOT_CYGWIN ;; esac @@ -868,12 +1041,58 @@ test_lazy_prereq AUTOIDENT ' git var GIT_AUTHOR_IDENT ' -# When the tests are run as root, permission tests will report that -# things are writable when they shouldn't be. -test -w / || test_set_prereq SANITY +test_lazy_prereq EXPENSIVE ' + test -n "$GIT_TEST_LONG" +' + +test_lazy_prereq USR_BIN_TIME ' + test -x /usr/bin/time +' + +test_lazy_prereq NOT_ROOT ' + uid=$(id -u) && + test "$uid" != 0 +' + +# SANITY is about "can you correctly predict what the filesystem would +# do by only looking at the permission bits of the files and +# directories?" A typical example of !SANITY is running the test +# suite as root, where a test may expect "chmod -r file && cat file" +# to fail because file is supposed to be unreadable after a successful +# chmod. In an environment (i.e. combination of what filesystem is +# being used and who is running the tests) that lacks SANITY, you may +# be able to delete or create a file when the containing directory +# doesn't have write permissions, or access a file even if the +# containing directory doesn't have read or execute permissions. + +test_lazy_prereq SANITY ' + mkdir SANETESTD.1 SANETESTD.2 && + + chmod +w SANETESTD.1 SANETESTD.2 && + >SANETESTD.1/x 2>SANETESTD.2/x && + chmod -w SANETESTD.1 && + chmod -r SANETESTD.1/x && + chmod -rx SANETESTD.2 || + error "bug in test sript: cannot prepare SANETESTD" + + ! test -r SANETESTD.1/x && + ! rm SANETESTD.1/x && ! test -f SANETESTD.2/x + status=$? + + chmod +rwx SANETESTD.1 SANETESTD.2 && + rm -rf SANETESTD.1 SANETESTD.2 || + error "bug in test sript: cannot clean SANETESTD" + return $status +' GIT_UNZIP=${GIT_UNZIP:-unzip} test_lazy_prereq UNZIP ' "$GIT_UNZIP" -v test $? -ne 127 ' + +run_with_limited_cmdline () { + (ulimit -s 128 && "$@") +} + +test_lazy_prereq CMDLINE_LIMIT 'run_with_limited_cmdline true' diff --git a/t/test-terminal.perl b/t/test-terminal.perl index 1fb373f25b..96b6a03e1c 100755 --- a/t/test-terminal.perl +++ b/t/test-terminal.perl @@ -5,15 +5,17 @@ use warnings; use IO::Pty; use File::Copy; -# Run @$argv in the background with stdio redirected to $out and $err. +# Run @$argv in the background with stdio redirected to $in, $out and $err. sub start_child { - my ($argv, $out, $err) = @_; + my ($argv, $in, $out, $err) = @_; my $pid = fork; if (not defined $pid) { die "fork failed: $!" } elsif ($pid == 0) { + open STDIN, "<&", $in; open STDOUT, ">&", $out; open STDERR, ">&", $err; + close $in; close $out; exec(@$argv) or die "cannot exec '$argv->[0]': $!" } @@ -49,6 +51,17 @@ sub xsendfile { copy($in, $out, 4096) or $!{EIO} or die "cannot copy from child: $!"; } +sub copy_stdin { + my ($in) = @_; + my $pid = fork; + if (!$pid) { + xsendfile($in, \*STDIN); + exit 0; + } + close($in); + return $pid; +} + sub copy_stdio { my ($out, $err) = @_; my $pid = fork; @@ -67,14 +80,25 @@ sub copy_stdio { if ($#ARGV < 1) { die "usage: test-terminal program args"; } +my $master_in = new IO::Pty; my $master_out = new IO::Pty; my $master_err = new IO::Pty; +$master_in->set_raw(); $master_out->set_raw(); $master_err->set_raw(); +$master_in->slave->set_raw(); $master_out->slave->set_raw(); $master_err->slave->set_raw(); -my $pid = start_child(\@ARGV, $master_out->slave, $master_err->slave); +my $pid = start_child(\@ARGV, $master_in->slave, $master_out->slave, $master_err->slave); +close $master_in->slave; close $master_out->slave; close $master_err->slave; +my $in_pid = copy_stdin($master_in); copy_stdio($master_out, $master_err); -exit(finish_child($pid)); +my $ret = finish_child($pid); +# If the child process terminates before our copy_stdin() process is able to +# write all of its data to $master_in, the copy_stdin() process could stall. +# Send SIGTERM to it to ensure it terminates. +kill 'TERM', $in_pid; +finish_child($in_pid); +exit($ret); |