diff options
181 files changed, 4397 insertions, 5819 deletions
diff --git a/.gitignore b/.gitignore index 3dd6ef7d2..c460c6676 100644 --- a/.gitignore +++ b/.gitignore @@ -170,6 +170,7 @@ /test-index-version /test-line-buffer /test-match-trees +/test-mktemp /test-obj-pool /test-parse-options /test-path-utils diff --git a/Documentation/RelNotes/1.7.4.1.txt b/Documentation/RelNotes/1.7.4.1.txt new file mode 100644 index 000000000..79923a6d2 --- /dev/null +++ b/Documentation/RelNotes/1.7.4.1.txt @@ -0,0 +1,27 @@ +Git v1.7.4.1 Release Notes +========================== + +Fixes since v1.7.4 +------------------ + + * On Windows platform, the codepath to spawn a new child process forgot + to first flush the output buffer. + + * "git bundle" did not use OFS_DELTA encoding, making its output a few + per-cent larger than necessarily. + + * The option to tell "git clone" to recurse into the submodules was + misspelled with an underscore "--recurse_submodules". + + * "git diff --cached HEAD" before the first commit does what an end user + would expect (namely, show what would be committed without further "git + add"). + + * "git fast-import" didn't accept the command to ask for "notes" feature + to be present in its input stream, even though it was capable of the + feature. + + * "git fsck" gave up scanning loose object files in directories with + garbage files. + +And other minor fixes and documentation updates. diff --git a/Documentation/RelNotes/1.7.4.txt b/Documentation/RelNotes/1.7.4.txt index 055c1ca2b..d5bca731b 100644 --- a/Documentation/RelNotes/1.7.4.txt +++ b/Documentation/RelNotes/1.7.4.txt @@ -1,5 +1,5 @@ -Git v1.7.4 Release Notes (draft) -================================ +Git v1.7.4 Release Notes +======================== Updates since v1.7.3 -------------------- @@ -15,7 +15,7 @@ Updates since v1.7.3 themselves. The name of a branch cannot begin with a dash now. * System-wide fallback default attributes can be stored in - /etc/gitattributes; core.attributesfile configuration variable can + /etc/gitattributes; the core.attributesfile configuration variable can be used to customize the path to this file. * The thread structure generated by "git send-email" has changed @@ -25,39 +25,39 @@ Updates since v1.7.3 cover letter of the previous series; this has been changed to make the patches in the new series replies to the new cover letter. - * Bash completion script in contrib/ has been adjusted to be usable with - Bash 4 (options with '=value' didn't complete) It has been also made + * The Bash completion script in contrib/ has been adjusted to be usable with + Bash 4 (options with '=value' didn't complete). It has been also made usable with zsh. * Different pagers can be chosen depending on which subcommand is - being run under the pager, using "pager.<subcommand>" variable. + being run under the pager, using the "pager.<subcommand>" variable. - * The hardcoded tab-width of 8 used in whitespace breakage checks is now + * The hardcoded tab-width of 8 that is used in whitespace breakage checks is now configurable via the attributes mechanism. * Support of case insensitive filesystems (i.e. "core.ignorecase") has been improved. For example, the gitignore mechanism didn't pay attention - to the case insensitivity. + to case insensitivity. - * The <tree>:<path> syntax to name a blob in a tree, and :<path> - syntax to name a blob in the index (e.g. "master:Makefile", + * The <tree>:<path> syntax for naming a blob in a tree, and the :<path> + syntax for naming a blob in the index (e.g. "master:Makefile", ":hello.c") have been extended. You can start <path> with "./" to implicitly have the (sub)directory you are in prefixed to the lookup. Similarly, ":../Makefile" from a subdirectory would mean "the Makefile of the parent directory in the index". - * "git blame" learned --show-email option to display the e-mail + * "git blame" learned the --show-email option to display the e-mail addresses instead of the names of authors. - * "git commit" learned --fixup and --squash options to help later invocation - of the interactive rebase. + * "git commit" learned the --fixup and --squash options to help later invocation + of interactive rebase. * Command line options to "git cvsimport" whose names are in capital letters (-A, -M, -R and -S) can now be specified as the default in the .git/config file by their longer names (cvsimport.authorsFile, cvsimport.mergeRegex, cvsimport.trackRevisions, cvsimport.ignorePaths). - * "git daemon" can be built in MinGW environment. + * "git daemon" can be built in the MinGW environment. * "git daemon" can take more than one --listen option to listen to multiple addresses. @@ -65,13 +65,13 @@ Updates since v1.7.3 * "git describe --exact-match" was optimized not to read commit objects unnecessarily. - * "git diff" and "git grep" learned how functions and subroutines - in Fortran look like. + * "git diff" and "git grep" learned what functions and subroutines + in Fortran, Pascal and Perl look like. - * "git fetch" learned "--recurse-submodules" option. + * "git fetch" learned the "--recurse-submodules" option. - * "git mergetool" tells vim/gvim to show three-way diff by default - (use vimdiff2/gvimdiff2 as the tool name for old behaviour). + * "git mergetool" tells vim/gvim to show a three-way diff by default + (use vimdiff2/gvimdiff2 as the tool name for old behavior). * "git log -G<pattern>" limits the output to commits whose change has added or deleted lines that match the given pattern. @@ -91,12 +91,20 @@ Updates since v1.7.3 directory in one branch while a new file is created in place of that directory in the other branch. - * "git rebase --autosquash" can use SHA-1 object names to name which - commit to fix up (e.g. "fixup! e83c5163"). + * "git merge" learned the "--abort" option, synonymous to + "git reset --merge" when a merge is in progress. - * The default "recursive" merge strategy learned --rename-threshold + * "git notes" learned the "merge" subcommand to merge notes refs. + In addition to the default manual conflict resolution, there are + also several notes merge strategies for automatically resolving + notes merge conflicts. + + * "git rebase --autosquash" can use SHA-1 object names to name the + commit which is to be fixed up (e.g. "fixup! e83c5163"). + + * The default "recursive" merge strategy learned the --rename-threshold option to influence the rename detection, similar to the -M option - of "git diff". From "git merge" frontend, "-X<strategy option>" + of "git diff". From the "git merge" frontend, the "-X<strategy option>" interface, e.g. "git merge -Xrename-threshold=50% ...", can be used to trigger this. @@ -104,21 +112,21 @@ Updates since v1.7.3 changes; the most notable is -Xignore-space-at-eol. * "git send-email" learned "--to-cmd", similar to "--cc-cmd", to read - recipient list from a command output. + the recipient list from a command output. * "git send-email" learned to read and use "To:" from its input files. * you can extend "git shell", which is often used on boxes that allow - git-only login over ssh as login shell, with custom set of + git-only login over ssh as login shell, with a custom set of commands. * The current branch name in "git status" output can be colored differently - from the generic header color by setting "color.status.branch" variable. + from the generic header color by setting the "color.status.branch" variable. * "git submodule sync" updates metainformation for all submodules, not just the ones that have been checked out. - * gitweb can use custom 'highlight' command with its configuration file. + * gitweb can use a custom 'highlight' command with its configuration file. * other gitweb updates. @@ -129,7 +137,7 @@ Also contains various documentation updates. Fixes since v1.7.3 ------------------ -All of the fixes in v1.7.3.X maintenance series are included in this +All of the fixes in the v1.7.3.X maintenance series are included in this release, unless otherwise noted. * "git log --author=me --author=her" did not find commits written by @@ -138,14 +146,11 @@ release, unless otherwise noted. * "git push --progress" shows progress indicators now. + * "git rebase -i" showed a confusing error message when given a + branch name that does not exist. + * "git repack" places its temporary packs under $GIT_OBJECT_DIRECTORY/pack instead of $GIT_OBJECT_DIRECTORY/ to avoid cross directory renames. * "git submodule update --recursive --other-flags" passes flags down to its subinvocations. - ---- -exec >/var/tmp/1 -O=v1.7.4-rc1 -echo O=$(git describe master) -git shortlog --no-merges ^maint ^$O master diff --git a/Documentation/config.txt b/Documentation/config.txt index ff7c22546..c5e183516 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -317,17 +317,26 @@ false), while all other repositories are assumed to be bare (bare = true). core.worktree:: - Set the path to the working tree. The value will not be - used in combination with repositories found automatically in - a .git directory (i.e. $GIT_DIR is not set). + Set the path to the root of the working tree. This can be overridden by the GIT_WORK_TREE environment - variable and the '--work-tree' command line option. It can be - an absolute path or relative path to the directory specified by - --git-dir or GIT_DIR. - Note: If --git-dir or GIT_DIR are specified but none of + variable and the '--work-tree' command line option. + The value can an absolute path or relative to the path to + the .git directory, which is either specified by --git-dir + or GIT_DIR, or automatically discovered. + If --git-dir or GIT_DIR is specified but none of --work-tree, GIT_WORK_TREE and core.worktree is specified, - the current working directory is regarded as the top directory + the current working directory is regarded as the top level of your working tree. ++ +Note that this variable is honored even when set in a configuration +file in a ".git" subdirectory of a directory and its value differs +from the latter directory (e.g. "/path/to/.git/config" has +core.worktree set to "/different/path"), which is most likely a +misconfiguration. Running git commands in the "/path/to" directory will +still use "/different/path" as the root of the work tree and can cause +confusion unless you know what you are doing (e.g. you are creating a +read-only snapshot of the same index to a location different from the +repository's usual working tree). core.logAllRefUpdates:: Enable the reflog. Updates to a ref <ref> is logged to the file diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt index 695696da1..f37276e5a 100644 --- a/Documentation/fetch-options.txt +++ b/Documentation/fetch-options.txt @@ -64,13 +64,11 @@ ifndef::git-pull[] downloaded. The default behavior for a remote may be specified with the remote.<name>.tagopt setting. See linkgit:git-config[1]. -endif::git-pull[] --[no-]recurse-submodules:: This option controls if new commits of all populated submodules should be fetched too (see linkgit:git-config[1] and linkgit:gitmodules[5]). -ifndef::git-pull[] --submodule-prefix=<path>:: Prepend <path> to paths printed in informative messages such as "Fetching submodule foo". This option is used diff --git a/Documentation/git-archive.txt b/Documentation/git-archive.txt index 4163a1bcb..bf5037ab2 100644 --- a/Documentation/git-archive.txt +++ b/Documentation/git-archive.txt @@ -116,7 +116,7 @@ Note that attributes are by default taken from the `.gitattributes` files in the tree that is being archived. If you want to tweak the way the output is generated after the fact (e.g. you committed without adding an appropriate export-ignore in its `.gitattributes`), adjust the checked out -`.gitattributes` file as necessary and use `--work-tree-attributes` +`.gitattributes` file as necessary and use `--worktree-attributes` option. Alternatively you can keep necessary attributes that should apply while archiving any tree in your `$GIT_DIR/info/attributes` file. diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt index 880763d39..396f4cc15 100644 --- a/Documentation/git-checkout.txt +++ b/Documentation/git-checkout.txt @@ -9,6 +9,7 @@ SYNOPSIS -------- [verse] 'git checkout' [-q] [-f] [-m] [<branch>] +'git checkout' [-q] [-f] [-m] [--detach] [<commit>] 'git checkout' [-q] [-f] [-m] [[-b|-B|--orphan] <new_branch>] [<start_point>] 'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>... 'git checkout' --patch [<tree-ish>] [--] [<paths>...] @@ -22,9 +23,10 @@ branch. 'git checkout' [<branch>]:: 'git checkout' -b|-B <new_branch> [<start point>]:: +'git checkout' [--detach] [<commit>]:: This form switches branches by updating the index, working - tree, and HEAD to reflect the specified branch. + tree, and HEAD to reflect the specified branch or commit. + If `-b` is given, a new branch is created as if linkgit:git-branch[1] were called and then checked out; in this case you can @@ -115,6 +117,13 @@ explicitly give a name with '-b' in such a case. Create the new branch's reflog; see linkgit:git-branch[1] for details. +--detach:: + Rather than checking out a branch to work on it, check out a + commit for inspection and discardable experiments. + This is the default behavior of "git checkout <commit>" when + <commit> is not a branch name. See the "DETACHED HEAD" section + below for details. + --orphan:: Create a new 'orphan' branch, named <new_branch>, started from <start_point> and switch to it. The first commit made on this @@ -204,42 +213,140 @@ leave out at most one of `A` and `B`, in which case it defaults to `HEAD`. -Detached HEAD +DETACHED HEAD ------------- +HEAD normally refers to a named branch (e.g. 'master'). Meanwhile, each +branch refers to a specific commit. Let's look at a repo with three +commits, one of them tagged, and with branch 'master' checked out: + +------------ + HEAD (refers to branch 'master') + | + v +a---b---c branch 'master' (refers to commit 'c') + ^ + | + tag 'v2.0' (refers to commit 'b') +------------ -It is sometimes useful to be able to 'checkout' a commit that is -not at the tip of one of your branches. The most obvious -example is to check out the commit at a tagged official release -point, like this: +When a commit is created in this state, the branch is updated to refer to +the new commit. Specifically, 'git commit' creates a new commit 'd', whose +parent is commit 'c', and then updates branch 'master' to refer to new +commit 'd'. HEAD still refers to branch 'master' and so indirectly now refers +to commit 'd': ------------ -$ git checkout v2.6.18 +$ edit; git add; git commit + + HEAD (refers to branch 'master') + | + v +a---b---c---d branch 'master' (refers to commit 'd') + ^ + | + tag 'v2.0' (refers to commit 'b') ------------ -Earlier versions of git did not allow this and asked you to -create a temporary branch using the `-b` option, but starting from -version 1.5.0, the above command 'detaches' your HEAD from the -current branch and directly points at the commit named by the tag -(`v2.6.18` in the example above). +It is sometimes useful to be able to checkout a commit that is not at +the tip of any named branch, or even to create a new commit that is not +referenced by a named branch. Let's look at what happens when we +checkout commit 'b' (here we show two ways this may be done): -You can use all git commands while in this state. You can use -`git reset --hard $othercommit` to further move around, for -example. You can make changes and create a new commit on top of -a detached HEAD. You can even create a merge by using `git -merge $othercommit`. +------------ +$ git checkout v2.0 # or +$ git checkout master^^ + + HEAD (refers to commit 'b') + | + v +a---b---c---d branch 'master' (refers to commit 'd') + ^ + | + tag 'v2.0' (refers to commit 'b') +------------ -The state you are in while your HEAD is detached is not recorded -by any branch (which is natural --- you are not on any branch). -What this means is that you can discard your temporary commits -and merges by switching back to an existing branch (e.g. `git -checkout master`), and a later `git prune` or `git gc` would -garbage-collect them. If you did this by mistake, you can ask -the reflog for HEAD where you were, e.g. +Notice that regardless of which checkout command we use, HEAD now refers +directly to commit 'b'. This is known as being in detached HEAD state. +It means simply that HEAD refers to a specific commit, as opposed to +referring to a named branch. Let's see what happens when we create a commit: ------------ -$ git log -g -2 HEAD +$ edit; git add; git commit + + HEAD (refers to commit 'e') + | + v + e + / +a---b---c---d branch 'master' (refers to commit 'd') + ^ + | + tag 'v2.0' (refers to commit 'b') +------------ + +There is now a new commit 'e', but it is referenced only by HEAD. We can +of course add yet another commit in this state: + +------------ +$ edit; git add; git commit + + HEAD (refers to commit 'f') + | + v + e---f + / +a---b---c---d branch 'master' (refers to commit 'd') + ^ + | + tag 'v2.0' (refers to commit 'b') +------------ + +In fact, we can perform all the normal git operations. But, let's look +at what happens when we then checkout master: + +------------ +$ git checkout master + + HEAD (refers to branch 'master') + e---f | + / v +a---b---c---d branch 'master' (refers to commit 'd') + ^ + | + tag 'v2.0' (refers to commit 'b') ------------ +It is important to realize that at this point nothing refers to commit +'f'. Eventually commit 'f' (and by extension commit 'e') will be deleted +by the routine git garbage collection process, unless we create a reference +before that happens. If we have not yet moved away from commit 'f', +any of these will create a reference to it: + +------------ +$ git checkout -b foo <1> +$ git branch foo <2> +$ git tag foo <3> +------------ + +<1> creates a new branch 'foo', which refers to commit 'f', and then +updates HEAD to refer to branch 'foo'. In other words, we'll no longer +be in detached HEAD state after this command. + +<2> similarly creates a new branch 'foo', which refers to commit 'f', +but leaves HEAD detached. + +<3> creates a new tag 'foo', which refers to commit 'f', +leaving HEAD detached. + +If we have moved away from commit 'f', then we must first recover its object +name (typically by using git reflog), and then we can create a reference to +it. For example, to see the last two commits to which HEAD referred, we +can use either of these commands: + +------------ +$ git reflog -2 HEAD # or +$ git log -g -2 HEAD +------------ EXAMPLES -------- diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt index 73008705e..749d68a72 100644 --- a/Documentation/git-cherry-pick.txt +++ b/Documentation/git-cherry-pick.txt @@ -79,6 +79,16 @@ effect to your index in a row. cherry-pick'ed commit, then a fast forward to this commit will be performed. +--strategy=<strategy>:: + Use the given merge strategy. Should only be used once. + See the MERGE STRATEGIES section in linkgit:git-merge[1] + for details. + +-X<option>:: +--strategy-option=<option>:: + Pass the merge strategy-specific option through to the + merge strategy. See linkgit:git-merge[1] for details. + EXAMPLES -------- git cherry-pick master:: @@ -120,6 +130,28 @@ git rev-list --reverse master \-- README | git cherry-pick -n --stdin:: so the result can be inspected and made into a single new commit if suitable. +The following sequence attempts to backport a patch, bails out because +the code the patch applies to has changed too much, and then tries +again, this time exercising more care about matching up context lines. + +------------ +$ git cherry-pick topic^ <1> +$ git diff <2> +$ git reset --merge ORIG_HEAD <3> +$ git cherry-pick -Xpatience topic^ <4> +------------ +<1> apply the change that would be shown by `git show topic^`. +In this example, the patch does not apply cleanly, so +information about the conflict is written to the index and +working tree and no new commit results. +<2> summarize changes to be reconciled +<3> cancel the cherry-pick. In other words, return to the +pre-cherry-pick state, preserving any local modifications you had in +the working tree. +<4> try to apply the change introduced by `topic^` again, +spending extra time to avoid mistakes based on incorrectly matching +context lines. + Author ------ Written by Junio C Hamano <gitster@pobox.com> diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt index b586c0f44..8f89f6f08 100644 --- a/Documentation/git-commit.txt +++ b/Documentation/git-commit.txt @@ -214,10 +214,11 @@ FROM UPSTREAM REBASE" section in linkgit:git-rebase[1].) -u[<mode>]:: --untracked-files[=<mode>]:: - Show untracked files (Default: 'all'). + Show untracked files. + -The mode parameter is optional, and is used to specify -the handling of untracked files. +The mode parameter is optional (defaults to 'all'), and is used to +specify the handling of untracked files; when -u is not used, the +default is 'normal', i.e. show untracked files and directories. + The possible options are: + @@ -225,9 +226,8 @@ The possible options are: - 'normal' - Shows untracked files and directories - 'all' - Also shows individual files in untracked directories. + -See linkgit:git-config[1] for configuration variable -used to change the default for when the option is not -specified. +The default can be changed using the status.showUntrackedFiles +configuration variable documented in linkgit:git-config[1]. -v:: --verbose:: diff --git a/Documentation/git-diff.txt b/Documentation/git-diff.txt index f6ac84750..49105102d 100644 --- a/Documentation/git-diff.txt +++ b/Documentation/git-diff.txt @@ -38,6 +38,8 @@ directories. This behavior can be forced by --no-index. commit relative to the named <commit>. Typically you would want comparison with the latest commit, so if you do not give <commit>, it defaults to HEAD. + If HEAD does not exist (e.g. unborned branches) and + <commit> is not given, it shows all staged changes. --staged is a synonym of --cached. 'git diff' [--options] <commit> [--] [<path>...]:: diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt index f56dfcabb..c3a2766b2 100644 --- a/Documentation/git-fast-import.txt +++ b/Documentation/git-fast-import.txt @@ -78,6 +78,10 @@ OPTIONS set of marks. If a mark is defined to different values, the last file wins. +--import-marks-if-exists=<file>:: + Like --import-marks but instead of erroring out, silently + skips the file if it does not exist. + --relative-marks:: After specifying --relative-marks= the paths specified with --import-marks= and --export-marks= are relative @@ -534,9 +538,6 @@ start with double quote (`"`). If an `LF` or double quote must be encoded into `<path>` shell-style quoting should be used, e.g. `"path/with\n and \" in it"`. -Additionally, in `040000` mode, `<path>` may also be an empty string -(`""`) to specify the root of the tree. - The value of `<path>` must be in canonical form. That is it must not: * contain an empty directory component (e.g. `foo//bar` is invalid), @@ -545,6 +546,8 @@ The value of `<path>` must be in canonical form. That is it must not: * contain the special component `.` or `..` (e.g. `foo/./bar` and `foo/../bar` are invalid). +The root of the tree can be represented by an empty string as `<path>`. + It is recommended that `<path>` always be encoded using UTF-8. `filedelete` @@ -905,7 +908,7 @@ The `<dataref>` can be either a mark reference (`:<idnum>`) set previously or a full 40-byte SHA-1 of a Git blob, preexisting or ready to be written. -output uses the same format as `git cat-file --batch`: +Output uses the same format as `git cat-file --batch`: ==== <sha1> SP 'blob' SP <size> LF @@ -949,6 +952,13 @@ cat-blob:: rather than wasting time on the early part of an import before the unsupported command is detected. +notes:: + Require that the backend support the 'notemodify' (N) + subcommand to the 'commit' command. + Versions of fast-import not supporting notes will exit + with a message indicating so. + + `option` ~~~~~~~~ Processes the specified option so that git fast-import behaves in a diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt index 30466917d..b33e6be87 100644 --- a/Documentation/git-pull.txt +++ b/Documentation/git-pull.txt @@ -84,6 +84,15 @@ must be given before the options meant for 'git fetch'. --verbose:: Pass --verbose to git-fetch and git-merge. +--[no-]recurse-submodules:: + This option controls if new commits of all populated submodules should + be fetched too (see linkgit:git-config[1] and linkgit:gitmodules[5]). + That might be necessary to get the data needed for merging submodule + commits, a feature git learned in 1.7.3. Notice that the result of a + merge will not be checked out in the submodule, "git submodule update" + has to be called afterwards to bring the work tree up to date with the + merge result. + Options related to merging ~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/Documentation/git-reset.txt b/Documentation/git-reset.txt index fd7297637..927ecee2f 100644 --- a/Documentation/git-reset.txt +++ b/Documentation/git-reset.txt @@ -76,15 +76,10 @@ In other words, --merge does something like a 'git read-tree -u -m <commit>', but carries forward unmerged index entries. --keep:: - Resets the index, updates files in the working tree that are - different between <commit> and HEAD, but keeps those - which are different between HEAD and the working tree (i.e. - which have local changes). + Resets index entries and updates files in the working tree that are + different between <commit> and HEAD. If a file that is different between <commit> and HEAD has local changes, reset is aborted. -+ -In other words, --keep does a 2-way merge between <commit> and HEAD followed by -'git reset --mixed <commit>'. -- If you want to undo a commit other than the latest on a branch, diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt index 752fc88e7..45be85175 100644 --- a/Documentation/git-revert.txt +++ b/Documentation/git-revert.txt @@ -80,6 +80,16 @@ effect to your index in a row. --signoff:: Add Signed-off-by line at the end of the commit message. +--strategy=<strategy>:: + Use the given merge strategy. Should only be used once. + See the MERGE STRATEGIES section in linkgit:git-merge[1] + for details. + +-X<option>:: +--strategy-option=<option>:: + Pass the merge strategy-specific option through to the + merge strategy. See linkgit:git-merge[1] for details. + EXAMPLES -------- git revert HEAD~3:: diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt index dae190a5f..5102a23f8 100644 --- a/Documentation/git-status.txt +++ b/Documentation/git-status.txt @@ -38,20 +38,20 @@ OPTIONS -u[<mode>]:: --untracked-files[=<mode>]:: - Show untracked files (Default: 'all'). + Show untracked files. + -The mode parameter is optional, and is used to specify -the handling of untracked files. The possible options are: +The mode parameter is optional (defaults to 'all'), and is used to +specify the handling of untracked files; when -u is not used, the +default is 'normal', i.e. show untracked files and directories. ++ +The possible options are: + --- - 'no' - Show no untracked files - 'normal' - Shows untracked files and directories - 'all' - Also shows individual files in untracked directories. --- + -See linkgit:git-config[1] for configuration variable -used to change the default for when the option is not -specified. +The default can be changed using the status.showUntrackedFiles +configuration variable documented in linkgit:git-config[1]. --ignore-submodules[=<when>]:: Ignore changes to submodules when looking for changes. <when> can be diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt index 254d0441b..0ade2ce54 100644 --- a/Documentation/git-svn.txt +++ b/Documentation/git-svn.txt @@ -729,8 +729,11 @@ have each person clone that repository with 'git clone': cd project git init git remote add origin server:/pub/project - git config --add remote.origin.fetch '+refs/remotes/*:refs/remotes/*' + git config --replace-all remote.origin.fetch '+refs/remotes/*:refs/remotes/*' git fetch +# Prevent fetch/pull from remote git server in the future, +# we only want to use git svn for future updates + git config --remove-section remote.origin # Create a local branch from one of the branches just fetched git checkout -b master FETCH_HEAD # Initialize 'git svn' locally (be sure to use the same URL and -T/-b/-t options as were used on server) diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt index 8b169e364..65f76c544 100644 --- a/Documentation/git-tag.txt +++ b/Documentation/git-tag.txt @@ -18,21 +18,22 @@ SYNOPSIS DESCRIPTION ----------- -Adds a tag reference in `.git/refs/tags/`. +Add a tag reference in `.git/refs/tags/`, unless `-d/-l/-v` is given +to delete, list or verify tags. -Unless `-f` is given, the tag must not yet exist in +Unless `-f` is given, the tag to be created must not yet exist in the `.git/refs/tags/` directory. If one of `-a`, `-s`, or `-u <key-id>` is passed, the command -creates a 'tag' object, and requires the tag message. Unless +creates a 'tag' object, and requires a tag message. Unless `-m <msg>` or `-F <file>` is given, an editor is started for the user to type in the tag message. If `-m <msg>` or `-F <file>` is given and `-a`, `-s`, and `-u <key-id>` are absent, `-a` is implied. -Otherwise just the SHA1 object name of the commit object is -written (i.e. a lightweight tag). +Otherwise just a tag reference for the SHA1 object name of the commit object is +created (i.e. a lightweight tag). A GnuPG signed tag object will be created when `-s` or `-u <key-id>` is used. When `-u <key-id>` is not used, the diff --git a/Documentation/git.txt b/Documentation/git.txt index 4e5fe4d4b..0c32d4524 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -44,6 +44,12 @@ unreleased) version of git, that is available from 'master' branch of the `git.git` repository. Documentation for older releases are available here: +* link:v1.7.4.1/git.html[documentation for release 1.7.4.1] + +* release notes for + link:RelNotes/1.7.4.1.txt[1.7.4.1], + link:RelNotes/1.7.4.txt[1.7.4]. + * link:v1.7.3.5/git.html[documentation for release 1.7.3.5] * release notes for @@ -291,17 +297,12 @@ help ...`. path or relative path to current working directory. --work-tree=<path>:: - Set the path to the working tree. The value will not be - used in combination with repositories found automatically in - a .git directory (i.e. $GIT_DIR is not set). + Set the path to the working tree. It can be an absolute path + or a path relative to the current working directory. This can also be controlled by setting the GIT_WORK_TREE environment variable and the core.worktree configuration - variable. It can be an absolute path or relative path to - current working directory. - Note: If --git-dir or GIT_DIR are specified but none of - --work-tree, GIT_WORK_TREE and core.worktree is specified, - the current working directory is regarded as the top directory - of your working tree. + variable (see core.worktree in linkgit:git-config[1] for a + more detailed discussion). --bare:: Treat the repository as a bare repository. If GIT_DIR diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt index 22b85825a..7e7e12168 100644 --- a/Documentation/gitattributes.txt +++ b/Documentation/gitattributes.txt @@ -504,6 +504,8 @@ patterns are available: - `pascal` suitable for source code in the Pascal/Delphi language. +- `perl` suitable for source code in the Perl language. + - `php` suitable for source code in the PHP language. - `python` suitable for source code in the Python language. @@ -591,6 +593,39 @@ and now produces better output), you can remove the cache manually with `git update-ref -d refs/notes/textconv/jpg` (where "jpg" is the name of the diff driver, as in the example above). +Marking files as binary +^^^^^^^^^^^^^^^^^^^^^^^ + +Git usually guesses correctly whether a blob contains text or binary +data by examining the beginning of the contents. However, sometimes you +may want to override its decision, either because a blob contains binary +data later in the file, or because the content, while technically +composed of text characters, is opaque to a human reader. For example, +many postscript files contain only ascii characters, but produce noisy +and meaningless diffs. + +The simplest way to mark a file as binary is to unset the diff +attribute in the `.gitattributes` file: + +------------------------ +*.ps -diff +------------------------ + +This will cause git to generate `Binary files differ` (or a binary +patch, if binary patches are enabled) instead of a regular diff. + +However, one may also want to specify other diff driver attributes. For +example, you might want to use `textconv` to convert postscript files to +an ascii representation for human viewing, but otherwise treat them as +binary files. You cannot specify both `-diff` and `diff=ps` attributes. +The solution is to use the `diff.*.binary` config option: + +------------------------ +[diff "ps"] + textconv = ps2ascii + binary = true +------------------------ + Performing a three-way merge ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt index 7183aa9ab..28edefa20 100644 --- a/Documentation/githooks.txt +++ b/Documentation/githooks.txt @@ -350,10 +350,6 @@ rebase:: The commits are guaranteed to be listed in the order that they were processed by rebase. -There is no default 'post-rewrite' hook, but see the -`post-receive-copy-notes` script in `contrib/hooks` for an example -that copies your git-notes to the rewritten commits. - GIT --- diff --git a/Documentation/glossary-content.txt b/Documentation/glossary-content.txt index f04b48ef0..33716a31d 100644 --- a/Documentation/glossary-content.txt +++ b/Documentation/glossary-content.txt @@ -273,6 +273,29 @@ This commit is referred to as a "merge commit", or sometimes just a <<def_pack,pack>>, to assist in efficiently accessing the contents of a pack. +[[def_pathspec]]pathspec:: + Pattern used to specify paths. ++ +Pathspecs are used on the command line of "git ls-files", "git +ls-tree", "git grep", "git checkout", and many other commands to +limit the scope of operations to some subset of the tree or +worktree. See the documentation of each command for whether +paths are relative to the current directory or toplevel. The +pathspec syntax is as follows: + +* any path matches itself +* the pathspec up to the last slash represents a + directory prefix. The scope of that pathspec is + limited to that subtree. +* the rest of the pathspec is a pattern for the remainder + of the pathname. Paths relative to the directory + prefix will be matched against that pattern using fnmatch(3); + in particular, '*' and '?' _can_ match directory separators. ++ +For example, Documentation/*.jpg will match all .jpg files +in the Documentation subtree, +including Documentation/chapter_1/figure_1.jpg. + [[def_parent]]parent:: A <<def_commit_object,commit object>> contains a (possibly empty) list of the logical predecessor(s) in the line of development, i.e. its diff --git a/Documentation/howto/using-merge-subtree.txt b/Documentation/howto/using-merge-subtree.txt index 0953a50b6..293305612 100644 --- a/Documentation/howto/using-merge-subtree.txt +++ b/Documentation/howto/using-merge-subtree.txt @@ -71,5 +71,5 @@ Additional tips relevant parts of your tree. - Please note that if the other project merges from you, then it will - connects its history to yours, which can be something they don't want + connect its history to yours, which can be something they don't want to. diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index c29b94447..92fe7a59d 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v1.7.4-rc1 +DEF_VER=v1.7.4 LF=' ' @@ -435,6 +435,7 @@ TEST_PROGRAMS_NEED_X += test-subprocess TEST_PROGRAMS_NEED_X += test-svn-fe TEST_PROGRAMS_NEED_X += test-treap TEST_PROGRAMS_NEED_X += test-index-version +TEST_PROGRAMS_NEED_X += test-mktemp TEST_PROGRAMS = $(patsubst %,%$X,$(TEST_PROGRAMS_NEED_X)) diff --git a/aclocal.m4 b/aclocal.m4 index d399de267..f11bc7ed7 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -13,7 +13,7 @@ AC_DEFUN([TYPE_SOCKLEN_T], git_cv_socklen_t_equiv= for arg2 in "struct sockaddr" void; do for t in int size_t unsigned long "unsigned long"; do - AC_TRY_COMPILE([ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #include <sys/types.h> #include <sys/socket.h> @@ -21,7 +21,7 @@ AC_DEFUN([TYPE_SOCKLEN_T], ],[ $t len; getpeername(0,0,&len); - ],[ + ])],[ git_cv_socklen_t_equiv="$t" break 2 ]) @@ -57,6 +57,7 @@ extern int cmd_clone(int argc, const char **argv, const char *prefix); extern int cmd_clean(int argc, const char **argv, const char *prefix); extern int cmd_commit(int argc, const char **argv, const char *prefix); extern int cmd_commit_tree(int argc, const char **argv, const char *prefix); +extern int cmd_config(int argc, const char **argv, const char *prefix); extern int cmd_count_objects(int argc, const char **argv, const char *prefix); extern int cmd_describe(int argc, const char **argv, const char *prefix); extern int cmd_diff_files(int argc, const char **argv, const char *prefix); @@ -110,7 +111,7 @@ extern int cmd_reflog(int argc, const char **argv, const char *prefix); extern int cmd_remote(int argc, const char **argv, const char *prefix); extern int cmd_remote_ext(int argc, const char **argv, const char *prefix); extern int cmd_remote_fd(int argc, const char **argv, const char *prefix); -extern int cmd_config(int argc, const char **argv, const char *prefix); +extern int cmd_repo_config(int argc, const char **argv, const char *prefix); extern int cmd_rerere(int argc, const char **argv, const char *prefix); extern int cmd_reset(int argc, const char **argv, const char *prefix); extern int cmd_rev_list(int argc, const char **argv, const char *prefix); diff --git a/builtin/add.c b/builtin/add.c index 12b964e64..f7a17e43f 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -86,7 +86,7 @@ int add_files_to_cache(const char *prefix, const char **pathspec, int flags) struct rev_info rev; init_revisions(&rev, prefix); setup_revisions(0, NULL, &rev, NULL); - rev.prune_data = pathspec; + init_pathspec(&rev.prune_data, pathspec); rev.diffopt.output_format = DIFF_FORMAT_CALLBACK; rev.diffopt.format_callback = update_callback; data.flags = flags; @@ -317,12 +317,12 @@ static struct option builtin_add_options[] = { OPT__VERBOSE(&verbose, "be verbose"), OPT_GROUP(""), OPT_BOOLEAN('i', "interactive", &add_interactive, "interactive picking"), - OPT_BOOLEAN('p', "patch", &patch_interactive, "interactive patching"), + OPT_BOOLEAN('p', "patch", &patch_interactive, "select hunks interactively"), OPT_BOOLEAN('e', "edit", &edit_interactive, "edit current diff and apply"), OPT__FORCE(&ignored_too, "allow adding otherwise ignored files"), OPT_BOOLEAN('u', "update", &take_worktree_changes, "update tracked files"), OPT_BOOLEAN('N', "intent-to-add", &intent_to_add, "record only the fact that the path will be added later"), - OPT_BOOLEAN('A', "all", &addremove, "add all, noticing removal of tracked files"), + OPT_BOOLEAN('A', "all", &addremove, "add changes from all tracked and untracked files"), OPT_BOOLEAN( 0 , "refresh", &refresh_only, "don't add, only refresh the index"), OPT_BOOLEAN( 0 , "ignore-errors", &ignore_add_errors, "just skip files which cannot be added because of errors"), OPT_BOOLEAN( 0 , "ignore-missing", &ignore_missing, "check if - even missing - files are ignored in dry run"), diff --git a/builtin/branch.c b/builtin/branch.c index 9e546e4a8..fe8f2fcd5 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -134,7 +134,7 @@ static int branch_merged(int kind, const char *name, in_merge_bases(rev, &head_rev, 1) != merged) { if (merged) warning("deleting branch '%s' that has been merged to\n" - " '%s', but it is not yet merged to HEAD.", + " '%s', but not yet been merged to HEAD.", name, reference_name); else warning("not deleting branch '%s' that is not yet merged to\n" diff --git a/builtin/checkout.c b/builtin/checkout.c index 757f9a08d..cc97dbc30 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -30,6 +30,7 @@ struct checkout_opts { int quiet; int merge; int force; + int force_detach; int writeout_stage; int writeout_error; @@ -297,7 +298,7 @@ static void show_local_changes(struct object *head, struct diff_options *opts) run_diff_index(&rev, 0); } -static void describe_detached_head(char *msg, struct commit *commit) +static void describe_detached_head(const char *msg, struct commit *commit) { struct strbuf sb = STRBUF_INIT; struct pretty_print_context ctx = {0}; @@ -404,7 +405,7 @@ static int merge_working_tree(struct checkout_opts *opts, topts.dir->exclude_per_dir = ".gitignore"; tree = parse_tree_indirect(old->commit ? old->commit->object.sha1 : - (unsigned char *)EMPTY_TREE_SHA1_BIN); + EMPTY_TREE_SHA1_BIN); init_tree_desc(&trees[0], tree->buffer, tree->size); tree = parse_tree_indirect(new->commit->object.sha1); init_tree_desc(&trees[1], tree->buffer, tree->size); @@ -541,7 +542,17 @@ static void update_refs_for_switch(struct checkout_opts *opts, strbuf_addf(&msg, "checkout: moving from %s to %s", old_desc ? old_desc : "(invalid)", new->name); - if (new->path) { + if (!strcmp(new->name, "HEAD") && !new->path && !opts->force_detach) { + /* Nothing to do. */ + } else if (opts->force_detach || !new->path) { /* No longer on any branch. */ + update_ref(msg.buf, "HEAD", new->commit->object.sha1, NULL, + REF_NODEREF, DIE_ON_ERR); + if (!opts->quiet) { + if (old->path && advice_detached_head) + detach_advice(old->path, new->name); + describe_detached_head("HEAD is now at", new->commit); + } + } else if (new->path) { /* Switch branches. */ create_symref("HEAD", new->path, msg.buf); if (!opts->quiet) { if (old->path && !strcmp(new->path, old->path)) @@ -563,18 +574,11 @@ static void update_refs_for_switch(struct checkout_opts *opts, if (!file_exists(ref_file) && file_exists(log_file)) remove_path(log_file); } - } else if (strcmp(new->name, "HEAD")) { - update_ref(msg.buf, "HEAD", new->commit->object.sha1, NULL, - REF_NODEREF, DIE_ON_ERR); - if (!opts->quiet) { - if (old->path && advice_detached_head) - detach_advice(old->path, new->name); - describe_detached_head("HEAD is now at", new->commit); - } } remove_branch_state(); strbuf_release(&msg); - if (!opts->quiet && (new->path || !strcmp(new->name, "HEAD"))) + if (!opts->quiet && + (new->path || (!opts->force_detach && !strcmp(new->name, "HEAD")))) report_tracking(new); } @@ -675,11 +679,123 @@ static const char *unique_tracking_name(const char *name) return NULL; } +static int parse_branchname_arg(int argc, const char **argv, + int dwim_new_local_branch_ok, + struct branch_info *new, + struct tree **source_tree, + unsigned char rev[20], + const char **new_branch) +{ + int argcount = 0; + unsigned char branch_rev[20]; + const char *arg; + int has_dash_dash; + + /* + * case 1: git checkout <ref> -- [<paths>] + * + * <ref> must be a valid tree, everything after the '--' must be + * a path. + * + * case 2: git checkout -- [<paths>] + * + * everything after the '--' must be paths. + * + * case 3: git checkout <something> [<paths>] + * + * With no paths, if <something> is a commit, that is to + * switch to the branch or detach HEAD at it. As a special case, + * if <something> is A...B (missing A or B means HEAD but you can + * omit at most one side), and if there is a unique merge base + * between A and B, A...B names that merge base. + * + * With no paths, if <something> is _not_ a commit, no -t nor -b + * was given, and there is a tracking branch whose name is + * <something> in one and only one remote, then this is a short-hand + * to fork local <something> from that remote-tracking branch. + * + * Otherwise <something> shall not be ambiguous. + * - If it's *only* a reference, treat it like case (1). + * - If it's only a path, treat it like case (2). + * - else: fail. + * + */ + if (!argc) + return 0; + + if (!strcmp(argv[0], "--")) /* case (2) */ + return 1; + + arg = argv[0]; + has_dash_dash = (argc > 1) && !strcmp(argv[1], "--"); + + if (!strcmp(arg, "-")) + arg = "@{-1}"; + + if (get_sha1_mb(arg, rev)) { + if (has_dash_dash) /* case (1) */ + die("invalid reference: %s", arg); + if (dwim_new_local_branch_ok && + !check_filename(NULL, arg) && + argc == 1) { + const char *remote = unique_tracking_name(arg); + if (!remote || get_sha1(remote, rev)) + return argcount; + *new_branch = arg; + arg = remote; + /* DWIMmed to create local branch */ + } else { + return argcount; + } + } + + /* we can't end up being in (2) anymore, eat the argument */ + argcount++; + argv++; + argc--; + + new->name = arg; + setup_branch_path(new); + + if (check_ref_format(new->path) == CHECK_REF_FORMAT_OK && + resolve_ref(new->path, branch_rev, 1, NULL)) + hashcpy(rev, branch_rev); + else + new->path = NULL; /* not an existing branch */ + + new->commit = lookup_commit_reference_gently(rev, 1); + if (!new->commit) { + /* not a commit */ + *source_tree = parse_tree_indirect(rev); + } else { + parse_commit(new->commit); + *source_tree = new->commit->tree; + } + + if (!*source_tree) /* case (1): want a tree */ + die("reference is not a tree: %s", arg); + if (!has_dash_dash) {/* case (3 -> 1) */ + /* + * Do not complain the most common case + * git checkout branch + * even if there happen to be a file called 'branch'; + * it would be extremely annoying. + */ + if (argc) + verify_non_filename(NULL, arg); + } else { + argcount++; + argv++; + argc--; + } + + return argcount; +} + int cmd_checkout(int argc, const char **argv, const char *prefix) { struct checkout_opts opts; unsigned char rev[20]; - const char *arg; struct branch_info new; struct tree *source_tree = NULL; char *conflict_style = NULL; @@ -692,6 +808,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) OPT_STRING('B', NULL, &opts.new_branch_force, "branch", "create/reset and checkout a branch"), OPT_BOOLEAN('l', NULL, &opts.new_branch_log, "create reflog for new branch"), + OPT_BOOLEAN(0, "detach", &opts.force_detach, "detach the HEAD at named commit"), OPT_SET_INT('t', "track", &opts.track, "set upstream info for new branch", BRANCH_TRACK_EXPLICIT), OPT_STRING(0, "orphan", &opts.new_orphan_branch, "new branch", "new unparented branch"), @@ -709,7 +826,6 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) PARSE_OPT_NOARG | PARSE_OPT_HIDDEN }, OPT_END(), }; - int has_dash_dash; memset(&opts, 0, sizeof(opts)); memset(&new, 0, sizeof(new)); @@ -731,9 +847,15 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) opts.new_branch = opts.new_branch_force; if (patch_mode && (opts.track > 0 || opts.new_branch - || opts.new_branch_log || opts.merge || opts.force)) + || opts.new_branch_log || opts.merge || opts.force + || opts.force_detach)) die ("--patch is incompatible with all other options"); + if (opts.force_detach && (opts.new_branch || opts.new_orphan_branch)) + die("--detach cannot be used with -b/-B/--orphan"); + if (opts.force_detach && 0 < opts.track) + die("--detach cannot be used with -t"); + /* --track without -b should DWIM */ if (0 < opts.track && !opts.new_branch) { const char *argv0 = argv[0]; @@ -766,105 +888,30 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) die("git checkout: -f and -m are incompatible"); /* - * case 1: git checkout <ref> -- [<paths>] - * - * <ref> must be a valid tree, everything after the '--' must be - * a path. - * - * case 2: git checkout -- [<paths>] - * - * everything after the '--' must be paths. - * - * case 3: git checkout <something> [<paths>] - * - * With no paths, if <something> is a commit, that is to - * switch to the branch or detach HEAD at it. As a special case, - * if <something> is A...B (missing A or B means HEAD but you can - * omit at most one side), and if there is a unique merge base - * between A and B, A...B names that merge base. + * Extract branch name from command line arguments, so + * all that is left is pathspecs. * - * With no paths, if <something> is _not_ a commit, no -t nor -b - * was given, and there is a remote-tracking branch whose name is - * <something> in one and only one remote, then this is a short-hand - * to fork local <something> from that remote-tracking branch. + * Handle * - * Otherwise <something> shall not be ambiguous. - * - If it's *only* a reference, treat it like case (1). - * - If it's only a path, treat it like case (2). - * - else: fail. + * 1) git checkout <tree> -- [<paths>] + * 2) git checkout -- [<paths>] + * 3) git checkout <something> [<paths>] * + * including "last branch" syntax and DWIM-ery for names of + * remote branches, erroring out for invalid or ambiguous cases. */ if (argc) { - if (!strcmp(argv[0], "--")) { /* case (2) */ - argv++; - argc--; - goto no_reference; - } - - arg = argv[0]; - has_dash_dash = (argc > 1) && !strcmp(argv[1], "--"); - - if (!strcmp(arg, "-")) - arg = "@{-1}"; - - if (get_sha1_mb(arg, rev)) { - if (has_dash_dash) /* case (1) */ - die("invalid reference: %s", arg); - if (!patch_mode && - dwim_new_local_branch && - opts.track == BRANCH_TRACK_UNSPECIFIED && - !opts.new_branch && - !check_filename(NULL, arg) && - argc == 1) { - const char *remote = unique_tracking_name(arg); - if (!remote || get_sha1(remote, rev)) - goto no_reference; - opts.new_branch = arg; - arg = remote; - /* DWIMmed to create local branch */ - } - else - goto no_reference; - } - - /* we can't end up being in (2) anymore, eat the argument */ - argv++; - argc--; - - new.name = arg; - if ((new.commit = lookup_commit_reference_gently(rev, 1))) { - setup_branch_path(&new); - - if ((check_ref_format(new.path) == CHECK_REF_FORMAT_OK) && - resolve_ref(new.path, rev, 1, NULL)) - ; - else - new.path = NULL; - parse_commit(new.commit); - source_tree = new.commit->tree; - } else - source_tree = parse_tree_indirect(rev); - - if (!source_tree) /* case (1): want a tree */ - die("reference is not a tree: %s", arg); - if (!has_dash_dash) {/* case (3 -> 1) */ - /* - * Do not complain the most common case - * git checkout branch - * even if there happen to be a file called 'branch'; - * it would be extremely annoying. - */ - if (argc) - verify_non_filename(NULL, arg); - } - else { - argv++; - argc--; - } + int dwim_ok = + !patch_mode && + dwim_new_local_branch && + opts.track == BRANCH_TRACK_UNSPECIFIED && + !opts.new_branch; + int n = parse_branchname_arg(argc, argv, dwim_ok, + &new, &source_tree, rev, &opts.new_branch); + argv += n; + argc -= n; } -no_reference: - if (opts.track == BRANCH_TRACK_UNSPECIFIED) opts.track = git_branch_track; @@ -886,6 +933,9 @@ no_reference: } } + if (opts.force_detach) + die("git checkout: --detach does not take a path argument"); + if (1 < !!opts.writeout_stage + !!opts.force + !!opts.merge) die("git checkout: --ours/--theirs, --force and --merge are incompatible when\nchecking out of the index."); diff --git a/builtin/clone.c b/builtin/clone.c index 61e0989b5..60d9a6428 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -66,10 +66,10 @@ static struct option builtin_clone_options[] = { "setup as shared repository"), OPT_BOOLEAN(0, "recursive", &option_recursive, "initialize submodules in the clone"), - OPT_BOOLEAN(0, "recurse_submodules", &option_recursive, + OPT_BOOLEAN(0, "recurse-submodules", &option_recursive, "initialize submodules in the clone"), - OPT_STRING(0, "template", &option_template, "path", - "path the template repository"), + OPT_STRING(0, "template", &option_template, "template-directory", + "directory from which templates will be used"), OPT_STRING(0, "reference", &option_reference, "repo", "reference repository"), OPT_STRING('o', "origin", &option_origin, "branch", diff --git a/builtin/commit.c b/builtin/commit.c index 22ba54f9b..d7f55e3d4 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -45,9 +45,9 @@ static const char implicit_ident_advice[] = " git config --global user.name \"Your Name\"\n" " git config --global user.email you@example.com\n" "\n" -"If the identity used for this commit is wrong, you can fix it with:\n" +"After doing this, you may fix the identity used for this commit with:\n" "\n" -" git commit --amend --author='Your Name <you@example.com>'\n"; +" git commit --amend --reset-author\n"; static const char empty_amend_advice[] = "You asked to amend the most recent commit, but doing so would make\n" @@ -118,10 +118,10 @@ static struct option builtin_commit_options[] = { OPT__VERBOSE(&verbose, "show diff in commit message template"), OPT_GROUP("Commit message options"), - OPT_FILENAME('F', "file", &logfile, "read log from file"), + OPT_FILENAME('F', "file", &logfile, "read message from file"), OPT_STRING(0, "author", &force_author, "AUTHOR", "override author for commit"), OPT_STRING(0, "date", &force_date, "DATE", "override date for commit"), - OPT_CALLBACK('m', "message", &message, "MESSAGE", "specify commit message", opt_parse_m), + OPT_CALLBACK('m', "message", &message, "MESSAGE", "commit message", opt_parse_m), OPT_STRING('c', "reedit-message", &edit_message, "COMMIT", "reuse and edit message from specified commit"), OPT_STRING('C', "reuse-message", &use_message, "COMMIT", "reuse message from specified commit"), OPT_STRING(0, "fixup", &fixup_message, "COMMIT", "use autosquash formatted message to fixup specified commit"), @@ -145,12 +145,12 @@ static struct option builtin_commit_options[] = { STATUS_FORMAT_SHORT), OPT_BOOLEAN(0, "branch", &status_show_branch, "show branch information"), OPT_SET_INT(0, "porcelain", &status_format, - "show porcelain output format", STATUS_FORMAT_PORCELAIN), + "machine-readable output", STATUS_FORMAT_PORCELAIN), OPT_BOOLEAN('z', "null", &null_termination, "terminate entries with NUL"), OPT_BOOLEAN(0, "amend", &amend, "amend previous commit"), OPT_BOOLEAN(0, "no-post-rewrite", &no_post_rewrite, "bypass post-rewrite hook"), - { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, "mode", "show untracked files, optional modes: all, normal, no (Default: all)", PARSE_OPT_OPTARG, NULL, (intptr_t)"all" }, + { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, "mode", "show untracked files, optional modes: all, normal, no. (Default: all)", PARSE_OPT_OPTARG, NULL, (intptr_t)"all" }, /* end commit contents options */ { OPTION_BOOLEAN, 0, "allow-empty", &allow_empty, NULL, @@ -1092,7 +1092,7 @@ int cmd_status(int argc, const char **argv, const char *prefix) OPT_BOOLEAN('b', "branch", &status_show_branch, "show branch information"), OPT_SET_INT(0, "porcelain", &status_format, - "show porcelain output format", + "machine-readable output", STATUS_FORMAT_PORCELAIN), OPT_BOOLEAN('z', "null", &null_termination, "terminate entries with NUL"), diff --git a/builtin/config.c b/builtin/config.c index ca4a0db4a..dad86fecf 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -500,3 +500,9 @@ int cmd_config(int argc, const char **argv, const char *prefix) return 0; } + +int cmd_repo_config(int argc, const char **argv, const char *prefix) +{ + fprintf(stderr, "WARNING: git repo-config is deprecated in favor of git config.\n"); + return cmd_config(argc, argv, prefix); +} diff --git a/builtin/diff-files.c b/builtin/diff-files.c index 951c7c899..46085f862 100644 --- a/builtin/diff-files.c +++ b/builtin/diff-files.c @@ -61,7 +61,7 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix) (rev.diffopt.output_format & DIFF_FORMAT_PATCH)) rev.combine_merges = rev.dense_combined_merges = 1; - if (read_cache_preload(rev.diffopt.paths) < 0) { + if (read_cache_preload(rev.diffopt.pathspec.raw) < 0) { perror("read_cache_preload"); return -1; } diff --git a/builtin/diff.c b/builtin/diff.c index 945e7583a..4c9deb28e 100644 --- a/builtin/diff.c +++ b/builtin/diff.c @@ -135,7 +135,7 @@ static int builtin_diff_index(struct rev_info *revs, revs->max_count != -1 || revs->min_age != -1 || revs->max_age != -1) usage(builtin_diff_usage); - if (read_cache_preload(revs->diffopt.paths) < 0) { + if (read_cache_preload(revs->diffopt.pathspec.raw) < 0) { perror("read_cache_preload"); return -1; } @@ -237,7 +237,7 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv revs->combine_merges = revs->dense_combined_merges = 1; setup_work_tree(); - if (read_cache_preload(revs->diffopt.paths) < 0) { + if (read_cache_preload(revs->diffopt.pathspec.raw) < 0) { perror("read_cache_preload"); return -1; } @@ -330,8 +330,11 @@ int cmd_diff(int argc, const char **argv, const char *prefix) else if (!strcmp(arg, "--cached") || !strcmp(arg, "--staged")) { add_head_to_pending(&rev); - if (!rev.pending.nr) - die("No HEAD commit to compare with (yet)"); + if (!rev.pending.nr) { + struct tree *tree; + tree = lookup_tree((const unsigned char*)EMPTY_TREE_SHA1_BIN); + add_pending_object(&rev, &tree->object, "HEAD"); + } break; } } @@ -371,14 +374,10 @@ int cmd_diff(int argc, const char **argv, const char *prefix) } die("unhandled object '%s' given.", name); } - if (rev.prune_data) { - const char **pathspec = rev.prune_data; - while (*pathspec) { - if (!path) - path = *pathspec; - paths++; - pathspec++; - } + if (rev.prune_data.nr) { + if (!path) + path = rev.prune_data.items[0].match; + paths += rev.prune_data.nr; } /* diff --git a/builtin/fast-export.c b/builtin/fast-export.c index c8fd46b87..ba57457cc 100644 --- a/builtin/fast-export.c +++ b/builtin/fast-export.c @@ -651,7 +651,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix) if (import_filename) import_marks(import_filename); - if (import_filename && revs.prune_data) + if (import_filename && revs.prune_data.nr) full_tree = 1; get_tags_and_duplicates(&revs.pending, &extra_refs); diff --git a/builtin/fsck.c b/builtin/fsck.c index 6d5ebca7a..795aba087 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -74,7 +74,13 @@ static int mark_object(struct object *obj, int type, void *data) { struct object *parent = data; + /* + * The only case data is NULL or type is OBJ_ANY is when + * mark_object_reachable() calls us. All the callers of + * that function has non-NULL obj hence ... + */ if (!obj) { + /* ... these references to parent->fld are safe here */ printf("broken link from %7s %s\n", typename(parent->type), sha1_to_hex(parent->sha1)); printf("broken link from %7s %s\n", @@ -84,6 +90,7 @@ static int mark_object(struct object *obj, int type, void *data) } if (type != OBJ_ANY && obj->type != type) + /* ... and the reference to parent is safe here */ objerror(parent, "wrong object type in link"); if (obj->flags & REACHABLE) @@ -109,7 +116,7 @@ static void mark_object_reachable(struct object *obj) mark_object(obj, OBJ_ANY, NULL); } -static int traverse_one_object(struct object *obj, struct object *parent) +static int traverse_one_object(struct object *obj) { int result; struct tree *tree = NULL; @@ -138,7 +145,7 @@ static int traverse_reachable(void) entry = pending.objects + --pending.nr; obj = entry->item; parent = (struct object *) entry->name; - result |= traverse_one_object(obj, parent); + result |= traverse_one_object(obj); } return !!result; } @@ -385,10 +392,20 @@ static void add_sha1_list(unsigned char *sha1, unsigned long ino) sha1_list.nr = ++nr; } +static inline int is_loose_object_file(struct dirent *de, + char *name, unsigned char *sha1) +{ + if (strlen(de->d_name) != 38) + return 0; + memcpy(name + 2, de->d_name, 39); + return !get_sha1_hex(name, sha1); +} + static void fsck_dir(int i, char *path) { DIR *dir = opendir(path); struct dirent *de; + char name[100]; if (!dir) return; @@ -396,17 +413,13 @@ static void fsck_dir(int i, char *path) if (verbose) fprintf(stderr, "Checking directory %s\n", path); + sprintf(name, "%02x", i); while ((de = readdir(dir)) != NULL) { - char name[100]; unsigned char sha1[20]; if (is_dot_or_dotdot(de->d_name)) continue; - if (strlen(de->d_name) == 38) { - sprintf(name, "%02x", i); - memcpy(name+2, de->d_name, 39); - if (get_sha1_hex(name, sha1) < 0) - break; + if (is_loose_object_file(de, name, sha1)) { add_sha1_list(sha1, DIRENT_SORT_HINT(de)); continue; } @@ -556,8 +569,8 @@ static int fsck_cache_tree(struct cache_tree *it) sha1_to_hex(it->sha1)); return 1; } - mark_object_reachable(obj); obj->used = 1; + mark_object_reachable(obj); if (obj->type != OBJ_TREE) err |= objerror(obj, "non-tree in cache-tree"); } diff --git a/builtin/grep.c b/builtin/grep.c index fdf7131ef..c3af8760c 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -329,106 +329,6 @@ static int grep_config(const char *var, const char *value, void *cb) return 0; } -/* - * Return non-zero if max_depth is negative or path has no more then max_depth - * slashes. - */ -static int accept_subdir(const char *path, int max_depth) -{ - if (max_depth < 0) - return 1; - - while ((path = strchr(path, '/')) != NULL) { - max_depth--; - if (max_depth < 0) - return 0; - path++; - } - return 1; -} - -/* - * Return non-zero if name is a subdirectory of match and is not too deep. - */ -static int is_subdir(const char *name, int namelen, - const char *match, int matchlen, int max_depth) -{ - if (matchlen > namelen || strncmp(name, match, matchlen)) - return 0; - - if (name[matchlen] == '\0') /* exact match */ - return 1; - - if (!matchlen || match[matchlen-1] == '/' || name[matchlen] == '/') - return accept_subdir(name + matchlen + 1, max_depth); - - return 0; -} - -/* - * git grep pathspecs are somewhat different from diff-tree pathspecs; - * pathname wildcards are allowed. - */ -static int pathspec_matches(const char **paths, const char *name, int max_depth) -{ - int namelen, i; - if (!paths || !*paths) - return accept_subdir(name, max_depth); - namelen = strlen(name); - for (i = 0; paths[i]; i++) { - const char *match = paths[i]; - int matchlen = strlen(match); - const char *cp, *meta; - - if (is_subdir(name, namelen, match, matchlen, max_depth)) - return 1; - if (!fnmatch(match, name, 0)) - return 1; - if (name[namelen-1] != '/') - continue; - - /* We are being asked if the directory ("name") is worth - * descending into. - * - * Find the longest leading directory name that does - * not have metacharacter in the pathspec; the name - * we are looking at must overlap with that directory. - */ - for (cp = match, meta = NULL; cp - match < matchlen; cp++) { - char ch = *cp; - if (ch == '*' || ch == '[' || ch == '?') { - meta = cp; - break; - } - } - if (!meta) - meta = cp; /* fully literal */ - - if (namelen <= meta - match) { - /* Looking at "Documentation/" and - * the pattern says "Documentation/howto/", or - * "Documentation/diff*.txt". The name we - * have should match prefix. - */ - if (!memcmp(match, name, namelen)) - return 1; - continue; - } - - if (meta - match < namelen) { - /* Looking at "Documentation/howto/" and - * the pattern says "Documentation/h*"; - * match up to "Do.../h"; this avoids descending - * into "Documentation/technical/". - */ - if (!memcmp(match, name, meta - match)) - return 1; - continue; - } - } - return 0; -} - static void *lock_and_read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size) { void *data; @@ -581,7 +481,7 @@ static void run_pager(struct grep_opt *opt, const char *prefix) free(argv); } -static int grep_cache(struct grep_opt *opt, const char **paths, int cached) +static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int cached) { int hit = 0; int nr; @@ -591,7 +491,7 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached) struct cache_entry *ce = active_cache[nr]; if (!S_ISREG(ce->ce_mode)) continue; - if (!pathspec_matches(paths, ce->name, opt->max_depth)) + if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL)) continue; /* * If CE_VALID is on, we assume worktree file and its cache entry @@ -618,44 +518,29 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached) return hit; } -static int grep_tree(struct grep_opt *opt, const char **paths, - struct tree_desc *tree, - const char *tree_name, const char *base) +static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, + struct tree_desc *tree, struct strbuf *base, int tn_len) { - int len; - int hit = 0; + int hit = 0, matched = 0; struct name_entry entry; - char *down; - int tn_len = strlen(tree_name); - struct strbuf pathbuf; - - strbuf_init(&pathbuf, PATH_MAX + tn_len); - - if (tn_len) { - strbuf_add(&pathbuf, tree_name, tn_len); - strbuf_addch(&pathbuf, ':'); - tn_len = pathbuf.len; - } - strbuf_addstr(&pathbuf, base); - len = pathbuf.len; + int old_baselen = base->len; while (tree_entry(tree, &entry)) { int te_len = tree_entry_len(entry.path, entry.sha1); - pathbuf.len = len; - strbuf_add(&pathbuf, entry.path, te_len); - - if (S_ISDIR(entry.mode)) - /* Match "abc/" against pathspec to - * decide if we want to descend into "abc" - * directory. - */ - strbuf_addch(&pathbuf, '/'); - - down = pathbuf.buf + tn_len; - if (!pathspec_matches(paths, down, opt->max_depth)) - ; - else if (S_ISREG(entry.mode)) - hit |= grep_sha1(opt, entry.sha1, pathbuf.buf, tn_len); + + if (matched != 2) { + matched = tree_entry_interesting(&entry, base, tn_len, pathspec); + if (matched == -1) + break; /* no more matches */ + if (!matched) + continue; + } + + strbuf_add(base, entry.path, te_len); + + if (S_ISREG(entry.mode)) { + hit |= grep_sha1(opt, entry.sha1, base->buf, tn_len); + } else if (S_ISDIR(entry.mode)) { enum object_type type; struct tree_desc sub; @@ -666,18 +551,21 @@ static int grep_tree(struct grep_opt *opt, const char **paths, if (!data) die("unable to read tree (%s)", sha1_to_hex(entry.sha1)); + + strbuf_addch(base, '/'); init_tree_desc(&sub, data, size); - hit |= grep_tree(opt, paths, &sub, tree_name, down); + hit |= grep_tree(opt, pathspec, &sub, base, tn_len); free(data); } + strbuf_setlen(base, old_baselen); + if (hit && opt->status_only) break; } - strbuf_release(&pathbuf); return hit; } -static int grep_object(struct grep_opt *opt, const char **paths, +static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec, struct object *obj, const char *name) { if (obj->type == OBJ_BLOB) @@ -686,20 +574,30 @@ static int grep_object(struct grep_opt *opt, const char **paths, struct tree_desc tree; void *data; unsigned long size; - int hit; + struct strbuf base; + int hit, len; + data = read_object_with_reference(obj->sha1, tree_type, &size, NULL); if (!data) die("unable to read tree (%s)", sha1_to_hex(obj->sha1)); + + len = name ? strlen(name) : 0; + strbuf_init(&base, PATH_MAX + len + 1); + if (len) { + strbuf_add(&base, name, len); + strbuf_addch(&base, ':'); + } init_tree_desc(&tree, data, size); - hit = grep_tree(opt, paths, &tree, name, ""); + hit = grep_tree(opt, pathspec, &tree, &base, base.len); + strbuf_release(&base); free(data); return hit; } die("unable to grep from object of type %s", typename(obj->type)); } -static int grep_objects(struct grep_opt *opt, const char **paths, +static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec, const struct object_array *list) { unsigned int i; @@ -709,7 +607,7 @@ static int grep_objects(struct grep_opt *opt, const char **paths, for (i = 0; i < nr; i++) { struct object *real_obj; real_obj = deref_tag(list->objects[i].item, NULL, 0); - if (grep_object(opt, paths, real_obj, list->objects[i].name)) { + if (grep_object(opt, pathspec, real_obj, list->objects[i].name)) { hit = 1; if (opt->status_only) break; @@ -718,7 +616,7 @@ static int grep_objects(struct grep_opt *opt, const char **paths, return hit; } -static int grep_directory(struct grep_opt *opt, const char **paths) +static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec) { struct dir_struct dir; int i, hit = 0; @@ -726,7 +624,7 @@ static int grep_directory(struct grep_opt *opt, const char **paths) memset(&dir, 0, sizeof(dir)); setup_standard_excludes(&dir); - fill_directory(&dir, paths); + fill_directory(&dir, pathspec->raw); for (i = 0; i < dir.nr; i++) { hit |= grep_file(opt, dir.entries[i]->name); if (hit && opt->status_only) @@ -832,6 +730,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) struct grep_opt opt; struct object_array list = OBJECT_ARRAY_INIT; const char **paths = NULL; + struct pathspec pathspec; struct string_list path_list = STRING_LIST_INIT_NODUP; int i; int dummy; @@ -1059,6 +958,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix) paths[0] = prefix; paths[1] = NULL; } + init_pathspec(&pathspec, paths); + pathspec.max_depth = opt.max_depth; + pathspec.recursive = 1; if (show_in_pager && (cached || list.nr)) die("--open-files-in-pager only works on the worktree"); @@ -1089,16 +991,16 @@ int cmd_grep(int argc, const char **argv, const char *prefix) die("--cached cannot be used with --no-index."); if (list.nr) die("--no-index cannot be used with revs."); - hit = grep_directory(&opt, paths); + hit = grep_directory(&opt, &pathspec); } else if (!list.nr) { if (!cached) setup_work_tree(); - hit = grep_cache(&opt, paths, cached); + hit = grep_cache(&opt, &pathspec, cached); } else { if (cached) die("both --cached and trees are given."); - hit = grep_objects(&opt, paths, &list); + hit = grep_objects(&opt, &pathspec, &list); } if (use_threads) diff --git a/builtin/hash-object.c b/builtin/hash-object.c index 080af1a01..c90acddcb 100644 --- a/builtin/hash-object.c +++ b/builtin/hash-object.c @@ -15,7 +15,7 @@ static void hash_fd(int fd, const char *type, int write_object, const char *path struct stat st; unsigned char sha1[20]; if (fstat(fd, &st) < 0 || - index_fd(sha1, fd, &st, write_object, type_from_string(type), path)) + index_fd(sha1, fd, &st, write_object, type_from_string(type), path, 1)) die(write_object ? "Unable to add %s to database" : "Unable to hash %s", path); diff --git a/builtin/init-db.c b/builtin/init-db.c index e3af9eaa8..4f5348eec 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -419,7 +419,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix) unsigned int flags = 0; const struct option init_db_options[] = { OPT_STRING(0, "template", &template_dir, "template-directory", - "provide the directory from which templates will be used"), + "directory from which templates will be used"), OPT_SET_INT(0, "bare", &is_bare_repository_cfg, "create a bare repository", 1), { OPTION_CALLBACK, 0, "shared", &init_shared_repository, diff --git a/builtin/log.c b/builtin/log.c index d8c6c28d2..f5ed690c4 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -89,7 +89,7 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix, rev->always_show_header = 0; if (DIFF_OPT_TST(&rev->diffopt, FOLLOW_RENAMES)) { rev->always_show_header = 0; - if (rev->diffopt.nr_paths != 1) + if (rev->diffopt.pathspec.nr != 1) usage("git logs can only follow renames on one pathname at a time"); } for (i = 1; i < argc; i++) { diff --git a/builtin/merge.c b/builtin/merge.c index 42fff387e..9b8c163c8 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -194,8 +194,8 @@ static struct option builtin_merge_options[] = { "merge strategy to use", option_parse_strategy), OPT_CALLBACK('X', "strategy-option", &xopts, "option=value", "option for selected merge strategy", option_parse_x), - OPT_CALLBACK('m', "message", &merge_msg, "message", - "message to be used for the merge commit (if any)", + OPT_CALLBACK('m', "message", &merge_msg, "MESSAGE", + "merge commit message (for a non-fast-forward merge)", option_parse_message), OPT__VERBOSITY(&verbosity), OPT_BOOLEAN(0, "abort", &abort_current_merge, @@ -582,7 +582,8 @@ static void write_tree_trivial(unsigned char *sha1) die("git write-tree failed to write a tree"); } -int try_merge_command(const char *strategy, struct commit_list *common, +int try_merge_command(const char *strategy, size_t xopts_nr, + const char **xopts, struct commit_list *common, const char *head_arg, struct commit_list *remotes) { const char **args; @@ -680,7 +681,8 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common, rollback_lock_file(lock); return clean ? 0 : 1; } else { - return try_merge_command(strategy, common, head_arg, remoteheads); + return try_merge_command(strategy, xopts_nr, xopts, + common, head_arg, remoteheads); } } @@ -795,6 +797,32 @@ static void add_strategies(const char *string, unsigned attr) } +static void write_merge_msg(void) +{ + int fd = open(git_path("MERGE_MSG"), O_WRONLY | O_CREAT, 0666); + if (fd < 0) + die_errno("Could not open '%s' for writing", + git_path("MERGE_MSG")); + if (write_in_full(fd, merge_msg.buf, merge_msg.len) != merge_msg.len) + die_errno("Could not write to '%s'", git_path("MERGE_MSG")); + close(fd); +} + +static void read_merge_msg(void) +{ + strbuf_reset(&merge_msg); + if (strbuf_read_file(&merge_msg, git_path("MERGE_MSG"), 0) < 0) + die_errno("Could not read from '%s'", git_path("MERGE_MSG")); +} + +static void run_prepare_commit_msg(void) +{ + write_merge_msg(); + run_hook(get_index_file(), "prepare-commit-msg", + git_path("MERGE_MSG"), "merge", NULL, NULL); + read_merge_msg(); +} + static int merge_trivial(void) { unsigned char result_tree[20], result_commit[20]; @@ -806,6 +834,7 @@ static int merge_trivial(void) parent->next = xmalloc(sizeof(*parent->next)); parent->next->item = remoteheads->item; parent->next->next = NULL; + run_prepare_commit_msg(); commit_tree(merge_msg.buf, result_tree, parent, result_commit, NULL); finish(result_commit, "In-index merge"); drop_save(); @@ -835,6 +864,7 @@ static int finish_automerge(struct commit_list *common, } free_commit_list(remoteheads); strbuf_addch(&merge_msg, '\n'); + run_prepare_commit_msg(); commit_tree(merge_msg.buf, result_tree, parents, result_commit, NULL); strbuf_addf(&buf, "Merge made by %s.", wt_strategy); finish(result_commit, buf.buf); @@ -1316,14 +1346,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) die_errno("Could not write to '%s'", git_path("MERGE_HEAD")); close(fd); strbuf_addch(&merge_msg, '\n'); - fd = open(git_path("MERGE_MSG"), O_WRONLY | O_CREAT, 0666); - if (fd < 0) - die_errno("Could not open '%s' for writing", - git_path("MERGE_MSG")); - if (write_in_full(fd, merge_msg.buf, merge_msg.len) != - merge_msg.len) - die_errno("Could not write to '%s'", git_path("MERGE_MSG")); - close(fd); + write_merge_msg(); fd = open(git_path("MERGE_MODE"), O_WRONLY | O_CREAT | O_TRUNC, 0666); if (fd < 0) die_errno("Could not open '%s' for writing", diff --git a/builtin/remote-ext.c b/builtin/remote-ext.c index 1f773171c..ea71977c8 100644 --- a/builtin/remote-ext.c +++ b/builtin/remote-ext.c @@ -212,16 +212,16 @@ static int command_loop(const char *child) char buffer[MAXCOMMAND]; while (1) { - size_t length; + size_t i; if (!fgets(buffer, MAXCOMMAND - 1, stdin)) { if (ferror(stdin)) die("Comammand input error"); exit(0); } /* Strip end of line characters. */ - length = strlen(buffer); - while (isspace((unsigned char)buffer[length - 1])) - buffer[--length] = 0; + i = strlen(buffer); + while (i > 0 && isspace(buffer[i - 1])) + buffer[--i] = 0; if (!strcmp(buffer, "capabilities")) { printf("*connect\n\n"); diff --git a/builtin/revert.c b/builtin/revert.c index bb6e9e83b..dc1b702ed 100644 --- a/builtin/revert.c +++ b/builtin/revert.c @@ -44,7 +44,11 @@ static const char **commit_argv; static int allow_rerere_auto; static const char *me; + +/* Merge strategy. */ static const char *strategy; +static const char **xopts; +static size_t xopts_nr, xopts_alloc; #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION" @@ -55,6 +59,17 @@ static const char * const *revert_or_cherry_pick_usage(void) return action == REVERT ? revert_usage : cherry_pick_usage; } +static int option_parse_x(const struct option *opt, + const char *arg, int unset) +{ + if (unset) + return 0; + + ALLOC_GROW(xopts, xopts_nr + 1, xopts_alloc); + xopts[xopts_nr++] = xstrdup(arg); + return 0; +} + static void parse_args(int argc, const char **argv) { const char * const * usage_str = revert_or_cherry_pick_usage(); @@ -67,6 +82,8 @@ static void parse_args(int argc, const char **argv) OPT_INTEGER('m', "mainline", &mainline, "parent number"), OPT_RERERE_AUTOUPDATE(&allow_rerere_auto), OPT_STRING(0, "strategy", &strategy, "strategy", "merge strategy"), + OPT_CALLBACK('X', "strategy-option", &xopts, "option", + "option for merge strategy", option_parse_x), OPT_END(), OPT_END(), OPT_END(), @@ -311,18 +328,13 @@ static int do_recursive_merge(struct commit *base, struct commit *next, struct merge_options o; struct tree *result, *next_tree, *base_tree, *head_tree; int clean, index_fd; + const char **xopt; static struct lock_file index_lock; index_fd = hold_locked_index(&index_lock, 1); read_cache(); - /* - * NEEDSWORK: cherry-picking between branches with - * different end-of-line normalization is a pain; - * plumb in an option to set o.renormalize? - * (or better: arbitrary -X options) - */ init_merge_options(&o); o.ancestor = base ? base_label : "(empty tree)"; o.branch1 = "HEAD"; @@ -332,6 +344,9 @@ static int do_recursive_merge(struct commit *base, struct commit *next, next_tree = next ? next->tree : empty_tree(); base_tree = base ? base->tree : empty_tree(); + for (xopt = xopts; xopt != xopts + xopts_nr; xopt++) + parse_merge_opt(&o, *xopt); + clean = merge_trees(&o, head_tree, next_tree, base_tree, &result); @@ -503,7 +518,7 @@ static int do_pick_commit(void) commit_list_insert(base, &common); commit_list_insert(next, &remotes); - res = try_merge_command(strategy, common, + res = try_merge_command(strategy, xopts_nr, xopts, common, sha1_to_hex(head), remotes); free_commit_list(common); free_commit_list(remotes); diff --git a/builtin/tag.c b/builtin/tag.c index aa1f87d47..246a2bc72 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -376,9 +376,9 @@ int cmd_tag(int argc, const char **argv, const char *prefix) OPT_GROUP("Tag creation options"), OPT_BOOLEAN('a', NULL, &annotate, "annotated tag, needs a message"), - OPT_CALLBACK('m', NULL, &msg, "msg", - "message for the tag", parse_msg_arg), - OPT_FILENAME('F', NULL, &msgfile, "message in a file"), + OPT_CALLBACK('m', NULL, &msg, "MESSAGE", + "tag message", parse_msg_arg), + OPT_FILENAME('F', NULL, &msgfile, "read message from file"), OPT_BOOLEAN('s', NULL, &sign, "annotated and GPG-signed tag"), OPT_STRING('u', NULL, &keyid, "key-id", "use another key to sign the tag"), diff --git a/builtin/update-index.c b/builtin/update-index.c index 56baf27fb..d7850c630 100644 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@ -546,7 +546,10 @@ static int do_reupdate(int ac, const char **av, */ int pos; int has_head = 1; - const char **pathspec = get_pathspec(prefix, av + 1); + const char **paths = get_pathspec(prefix, av + 1); + struct pathspec pathspec; + + init_pathspec(&pathspec, paths); if (read_ref("HEAD", head_sha1)) /* If there is no HEAD, that means it is an initial @@ -559,7 +562,7 @@ static int do_reupdate(int ac, const char **av, struct cache_entry *old = NULL; int save_nr; - if (ce_stage(ce) || !ce_path_match(ce, pathspec)) + if (ce_stage(ce) || !ce_path_match(ce, &pathspec)) continue; if (has_head) old = read_one_ent(NULL, head_sha1, @@ -578,6 +581,7 @@ static int do_reupdate(int ac, const char **av, if (save_nr != active_nr) goto redo; } + free_pathspec(&pathspec); return 0; } @@ -200,7 +200,7 @@ int create_bundle(struct bundle_header *header, const char *path, int bundle_fd = -1; int bundle_to_stdout; const char **argv_boundary = xmalloc((argc + 4) * sizeof(const char *)); - const char **argv_pack = xmalloc(5 * sizeof(const char *)); + const char **argv_pack = xmalloc(6 * sizeof(const char *)); int i, ref_count = 0; char buffer[1024]; struct rev_info revs; @@ -346,7 +346,8 @@ int create_bundle(struct bundle_header *header, const char *path, argv_pack[1] = "--all-progress-implied"; argv_pack[2] = "--stdout"; argv_pack[3] = "--thin"; - argv_pack[4] = NULL; + argv_pack[4] = "--delta-base-offset"; + argv_pack[5] = NULL; memset(&rls, 0, sizeof(rls)); rls.argv = argv_pack; rls.in = -1; @@ -500,8 +500,23 @@ extern int index_name_is_other(const struct index_state *, const char *, int); extern int ie_match_stat(const struct index_state *, struct cache_entry *, struct stat *, unsigned int); extern int ie_modified(const struct index_state *, struct cache_entry *, struct stat *, unsigned int); -extern int ce_path_match(const struct cache_entry *ce, const char **pathspec); -extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path); +struct pathspec { + const char **raw; /* get_pathspec() result, not freed by free_pathspec() */ + int nr; + int has_wildcard:1; + int recursive:1; + int max_depth; + struct pathspec_item { + const char *match; + int len; + int has_wildcard:1; + } *items; +}; + +extern int init_pathspec(struct pathspec *, const char **); +extern void free_pathspec(struct pathspec *); +extern int ce_path_match(const struct cache_entry *ce, const struct pathspec *pathspec); +extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path, int format_check); extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object); extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st); @@ -511,7 +526,7 @@ extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st); #define REFRESH_IGNORE_MISSING 0x0008 /* ignore non-existent */ #define REFRESH_IGNORE_SUBMODULES 0x0010 /* ignore submodules */ #define REFRESH_IN_PORCELAIN 0x0020 /* user friendly output, not "needs update" */ -extern int refresh_index(struct index_state *, unsigned int flags, const char **pathspec, char *seen, char *header_msg); +extern int refresh_index(struct index_state *, unsigned int flags, const char **pathspec, char *seen, const char *header_msg); struct lock_file { struct lock_file *next; @@ -676,9 +691,11 @@ static inline void hashclr(unsigned char *hash) #define EMPTY_TREE_SHA1_HEX \ "4b825dc642cb6eb9a060e54bf8d69288fbee4904" -#define EMPTY_TREE_SHA1_BIN \ +#define EMPTY_TREE_SHA1_BIN_LITERAL \ "\x4b\x82\x5d\xc6\x42\xcb\x6e\xb9\xa0\x60" \ "\xe5\x4b\xf8\xd6\x92\x88\xfb\xee\x49\x04" +#define EMPTY_TREE_SHA1_BIN \ + ((const unsigned char *) EMPTY_TREE_SHA1_BIN_LITERAL) int git_mkstemp(char *path, size_t n, const char *template); @@ -245,10 +245,10 @@ int unregister_shallow(const unsigned char *sha1) return 0; } -int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size) +int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long size) { - char *tail = buffer; - char *bufptr = buffer; + const char *tail = buffer; + const char *bufptr = buffer; unsigned char parent[20]; struct commit_list **pptr; struct commit_graft *graft; @@ -38,7 +38,7 @@ struct commit *lookup_commit_reference_gently(const unsigned char *sha1, int quiet); struct commit *lookup_commit_reference_by_name(const char *name); -int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size); +int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long size); int parse_commit(struct commit *item); /* Find beginning and length of commit subject. */ diff --git a/compat/mingw.c b/compat/mingw.c index bee605441..878b1de97 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -2,6 +2,9 @@ #include "win32.h" #include <conio.h> #include "../strbuf.h" +#include "../run-command.h" + +static const int delay[] = { 0, 1, 10, 20, 40 }; int err_win_to_posix(DWORD winerr) { @@ -116,6 +119,165 @@ int err_win_to_posix(DWORD winerr) return error; } +static inline int is_file_in_use_error(DWORD errcode) +{ + switch (errcode) { + case ERROR_SHARING_VIOLATION: + case ERROR_ACCESS_DENIED: + return 1; + } + + return 0; +} + +static int read_yes_no_answer(void) +{ + char answer[1024]; + + if (fgets(answer, sizeof(answer), stdin)) { + size_t answer_len = strlen(answer); + int got_full_line = 0, c; + + /* remove the newline */ + if (answer_len >= 2 && answer[answer_len-2] == '\r') { + answer[answer_len-2] = '\0'; + got_full_line = 1; + } else if (answer_len >= 1 && answer[answer_len-1] == '\n') { + answer[answer_len-1] = '\0'; + got_full_line = 1; + } + /* flush the buffer in case we did not get the full line */ + if (!got_full_line) + while ((c = getchar()) != EOF && c != '\n') + ; + } else + /* we could not read, return the + * default answer which is no */ + return 0; + + if (tolower(answer[0]) == 'y' && !answer[1]) + return 1; + if (!strncasecmp(answer, "yes", sizeof(answer))) + return 1; + if (tolower(answer[0]) == 'n' && !answer[1]) + return 0; + if (!strncasecmp(answer, "no", sizeof(answer))) + return 0; + + /* did not find an answer we understand */ + return -1; +} + +static int ask_yes_no_if_possible(const char *format, ...) +{ + char question[4096]; + const char *retry_hook[] = { NULL, NULL, NULL }; + va_list args; + + va_start(args, format); + vsnprintf(question, sizeof(question), format, args); + va_end(args); + + if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) { + retry_hook[1] = question; + return !run_command_v_opt(retry_hook, 0); + } + + if (!isatty(_fileno(stdin)) || !isatty(_fileno(stderr))) + return 0; + + while (1) { + int answer; + fprintf(stderr, "%s (y/n) ", question); + + if ((answer = read_yes_no_answer()) >= 0) + return answer; + + fprintf(stderr, "Sorry, I did not understand your answer. " + "Please type 'y' or 'n'\n"); + } +} + +#undef unlink +int mingw_unlink(const char *pathname) +{ + int ret, tries = 0; + + /* read-only files cannot be removed */ + chmod(pathname, 0666); + while ((ret = unlink(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (!is_file_in_use_error(GetLastError())) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + while (ret == -1 && is_file_in_use_error(GetLastError()) && + ask_yes_no_if_possible("Unlink of file '%s' failed. " + "Should I try again?", pathname)) + ret = unlink(pathname); + return ret; +} + +static int is_dir_empty(const char *path) +{ + struct strbuf buf = STRBUF_INIT; + WIN32_FIND_DATAA findbuf; + HANDLE handle; + + strbuf_addf(&buf, "%s\\*", path); + handle = FindFirstFileA(buf.buf, &findbuf); + if (handle == INVALID_HANDLE_VALUE) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + + while (!strcmp(findbuf.cFileName, ".") || + !strcmp(findbuf.cFileName, "..")) + if (!FindNextFile(handle, &findbuf)) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + FindClose(handle); + strbuf_release(&buf); + return 0; +} + +#undef rmdir +int mingw_rmdir(const char *pathname) +{ + int ret, tries = 0; + + while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (!is_file_in_use_error(GetLastError())) + break; + if (!is_dir_empty(pathname)) { + errno = ENOTEMPTY; + break; + } + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + while (ret == -1 && is_file_in_use_error(GetLastError()) && + ask_yes_no_if_possible("Deletion of directory '%s' failed. " + "Should I try again?", pathname)) + ret = rmdir(pathname); + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { @@ -1249,7 +1411,6 @@ int mingw_rename(const char *pold, const char *pnew) { DWORD attrs, gle; int tries = 0; - static const int delay[] = { 0, 1, 10, 20, 40 }; /* * Try native rename() first to get errno right. @@ -1291,6 +1452,11 @@ repeat: tries++; goto repeat; } + if (gle == ERROR_ACCESS_DENIED && + ask_yes_no_if_possible("Rename from '%s' to '%s' failed. " + "Should I try again?", pold, pnew)) + goto repeat; + errno = EACCES; return -1; } diff --git a/compat/mingw.h b/compat/mingw.h index cafc1eb08..fe6ba3404 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -119,14 +119,6 @@ static inline int mingw_mkdir(const char *path, int mode) } #define mkdir mingw_mkdir -static inline int mingw_unlink(const char *pathname) -{ - /* read-only files cannot be removed */ - chmod(pathname, 0666); - return unlink(pathname); -} -#define unlink mingw_unlink - #define WNOHANG 1 pid_t waitpid(pid_t pid, int *status, unsigned options); @@ -174,6 +166,12 @@ int link(const char *oldpath, const char *newpath); * replacements of existing functions */ +int mingw_unlink(const char *pathname); +#define unlink mingw_unlink + +int mingw_rmdir(const char *path); +#define rmdir mingw_rmdir + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open diff --git a/configure.ac b/configure.ac index 5792425a4..20039c546 100644 --- a/configure.ac +++ b/configure.ac @@ -345,7 +345,7 @@ esac AC_CACHE_CHECK([if linker supports -R], git_cv_ld_dashr, [ SAVE_LDFLAGS="${LDFLAGS}" LDFLAGS="${SAVE_LDFLAGS} -R /" - AC_LINK_IFELSE(AC_LANG_PROGRAM([], []), [git_cv_ld_dashr=yes], [git_cv_ld_dashr=no]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])], [git_cv_ld_dashr=yes], [git_cv_ld_dashr=no]) LDFLAGS="${SAVE_LDFLAGS}" ]) if test "$git_cv_ld_dashr" = "yes"; then @@ -354,7 +354,7 @@ else AC_CACHE_CHECK([if linker supports -Wl,-rpath,], git_cv_ld_wl_rpath, [ SAVE_LDFLAGS="${LDFLAGS}" LDFLAGS="${SAVE_LDFLAGS} -Wl,-rpath,/" - AC_LINK_IFELSE(AC_LANG_PROGRAM([], []), [git_cv_ld_wl_rpath=yes], [git_cv_ld_wl_rpath=no]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])], [git_cv_ld_wl_rpath=yes], [git_cv_ld_wl_rpath=no]) LDFLAGS="${SAVE_LDFLAGS}" ]) if test "$git_cv_ld_wl_rpath" = "yes"; then @@ -363,7 +363,7 @@ else AC_CACHE_CHECK([if linker supports -rpath], git_cv_ld_rpath, [ SAVE_LDFLAGS="${LDFLAGS}" LDFLAGS="${SAVE_LDFLAGS} -rpath /" - AC_LINK_IFELSE(AC_LANG_PROGRAM([], []), [git_cv_ld_rpath=yes], [git_cv_ld_rpath=no]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])], [git_cv_ld_rpath=yes], [git_cv_ld_rpath=no]) LDFLAGS="${SAVE_LDFLAGS}" ]) if test "$git_cv_ld_rpath" = "yes"; then @@ -472,15 +472,9 @@ if test -z "$NO_ICONV"; then GIT_STASH_FLAGS($ICONVDIR) -AC_DEFUN([ICONVTEST_SRC], [ -#include <iconv.h> - -int main(void) -{ - iconv_open("", ""); - return 0; -} -]) +AC_DEFUN([ICONVTEST_SRC], +[AC_LANG_PROGRAM([#include <iconv.h>], + [iconv_open("", "");])]) if test -n "$ICONVDIR"; then lib_order="-liconv -lc" @@ -500,7 +494,7 @@ for l in $lib_order; do old_LIBS="$LIBS" LIBS="$LIBS $l" AC_MSG_CHECKING([for iconv in $l]) - AC_LINK_IFELSE(ICONVTEST_SRC, + AC_LINK_IFELSE([ICONVTEST_SRC], [AC_MSG_RESULT([yes]) NO_ICONV= break], @@ -528,18 +522,12 @@ fi GIT_STASH_FLAGS($ZLIB_PATH) AC_DEFUN([ZLIBTEST_SRC], [ -#include <zlib.h> - -int main(void) -{ - deflateBound(0, 0); - return 0; -} -]) +AC_LANG_PROGRAM([#include <zlib.h>], + [deflateBound(0, 0);])]) AC_MSG_CHECKING([for deflateBound in -lz]) old_LIBS="$LIBS" LIBS="$LIBS -lz" -AC_LINK_IFELSE(ZLIBTEST_SRC, +AC_LINK_IFELSE([ZLIBTEST_SRC], [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no]) NO_DEFLATE_BOUND=yes]) @@ -631,23 +619,19 @@ AC_SUBST(NO_INTTYPES_H) # # Define OLD_ICONV if your library has an old iconv(), where the second # (input buffer pointer) parameter is declared with type (const char **). -AC_DEFUN([OLDICONVTEST_SRC], [[ +AC_DEFUN([OLDICONVTEST_SRC], [ +AC_LANG_PROGRAM([[ #include <iconv.h> extern size_t iconv(iconv_t cd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft); - -int main(void) -{ - return 0; -} -]]) +]], [])]) GIT_STASH_FLAGS($ICONVDIR) AC_MSG_CHECKING([for old iconv()]) -AC_COMPILE_IFELSE(OLDICONVTEST_SRC, +AC_COMPILE_IFELSE([OLDICONVTEST_SRC], [AC_MSG_RESULT([no])], [AC_MSG_RESULT([yes]) OLD_ICONV=UnfortunatelyYes]) @@ -931,18 +915,16 @@ AC_SUBST(NO_INITGROUPS) # # Define PTHREAD_LIBS to the linker flag used for Pthread support. AC_DEFUN([PTHREADTEST_SRC], [ +AC_LANG_PROGRAM([[ #include <pthread.h> - -int main(void) -{ +]], [[ pthread_mutex_t test_mutex; int retcode = 0; retcode |= pthread_mutex_init(&test_mutex,(void *)0); retcode |= pthread_mutex_lock(&test_mutex); retcode |= pthread_mutex_unlock(&test_mutex); return retcode; -} -]) +]])]) dnl AC_LANG_CONFTEST([AC_LANG_PROGRAM( dnl [[#include <pthread.h>]], @@ -962,7 +944,7 @@ elif test -z "$PTHREAD_CFLAGS"; then old_CFLAGS="$CFLAGS" CFLAGS="$opt $CFLAGS" AC_MSG_CHECKING([Checking for POSIX Threads with '$opt']) - AC_LINK_IFELSE(PTHREADTEST_SRC, + AC_LINK_IFELSE([PTHREADTEST_SRC], [AC_MSG_RESULT([yes]) NO_PTHREADS= PTHREAD_LIBS="$opt" @@ -982,7 +964,7 @@ else old_CFLAGS="$CFLAGS" CFLAGS="$PTHREAD_CFLAGS $CFLAGS" AC_MSG_CHECKING([Checking for POSIX Threads with '$PTHREAD_CFLAGS']) - AC_LINK_IFELSE(PTHREADTEST_SRC, + AC_LINK_IFELSE([PTHREADTEST_SRC], [AC_MSG_RESULT([yes]) NO_PTHREADS= PTHREAD_LIBS="$PTHREAD_CFLAGS" diff --git a/contrib/examples/git-revert.sh b/contrib/examples/git-revert.sh index 60a05a8b9..6bf155cbd 100755 --- a/contrib/examples/git-revert.sh +++ b/contrib/examples/git-revert.sh @@ -26,6 +26,7 @@ require_work_tree cd_to_toplevel no_commit= +xopt= while case "$#" in 0) break ;; esac do case "$1" in @@ -44,6 +45,16 @@ do -x|--i-really-want-to-expose-my-private-commit-object-name) replay= ;; + -X?*) + xopt="$xopt$(git rev-parse --sq-quote "--${1#-X}")" + ;; + --strategy-option=*) + xopt="$xopt$(git rev-parse --sq-quote "--${1#--strategy-option=}")" + ;; + -X|--strategy-option) + shift + xopt="$xopt$(git rev-parse --sq-quote "--$1")" + ;; -*) usage ;; @@ -159,7 +170,7 @@ export GITHEAD_$head GITHEAD_$next # and $prev on top of us (when reverting), or the change between # $prev and $commit on top of us (when cherry-picking or replaying). -git-merge-recursive $base -- $head $next && +eval "git merge-recursive $xopt $base -- $head $next" && result=$(git-write-tree 2>/dev/null) || { mv -f .msg "$GIT_DIR/MERGE_MSG" { diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4 index 04ce7e3b0..a4f440d11 100755 --- a/contrib/fast-import/git-p4 +++ b/contrib/fast-import/git-p4 @@ -543,13 +543,13 @@ class P4Submit(Command): self.options = [ optparse.make_option("--verbose", dest="verbose", action="store_true"), optparse.make_option("--origin", dest="origin"), - optparse.make_option("-M", dest="detectRename", action="store_true"), + optparse.make_option("-M", dest="detectRenames", action="store_true"), ] self.description = "Submit changes from git to the perforce depot." self.usage += " [name of git branch to submit into perforce depot]" self.interactive = True self.origin = "" - self.detectRename = False + self.detectRenames = False self.verbose = False self.isWindows = (platform.system() == "Windows") @@ -613,7 +613,22 @@ class P4Submit(Command): def applyCommit(self, id): print "Applying %s" % (read_pipe("git log --max-count=1 --pretty=oneline %s" % id)) - diffOpts = ("", "-M")[self.detectRename] + + if not self.detectRenames: + # If not explicitly set check the config variable + self.detectRenames = gitConfig("git-p4.detectRenames").lower() == "true" + + if self.detectRenames: + diffOpts = "-M" + else: + diffOpts = "" + + if gitConfig("git-p4.detectCopies").lower() == "true": + diffOpts += " -C" + + if gitConfig("git-p4.detectCopiesHarder").lower() == "true": + diffOpts += " --find-copies-harder" + diff = read_pipe_lines("git diff-tree -r %s \"%s^\" \"%s\"" % (diffOpts, id, id)) filesToAdd = set() filesToDelete = set() @@ -637,11 +652,23 @@ class P4Submit(Command): filesToDelete.add(path) if path in filesToAdd: filesToAdd.remove(path) + elif modifier == "C": + src, dest = diff['src'], diff['dst'] + p4_system("integrate -Dt \"%s\" \"%s\"" % (src, dest)) + if diff['src_sha1'] != diff['dst_sha1']: + p4_system("edit \"%s\"" % (dest)) + if isModeExecChanged(diff['src_mode'], diff['dst_mode']): + p4_system("edit \"%s\"" % (dest)) + filesToChangeExecBit[dest] = diff['dst_mode'] + os.unlink(dest) + editedFiles.add(dest) elif modifier == "R": src, dest = diff['src'], diff['dst'] p4_system("integrate -Dt \"%s\" \"%s\"" % (src, dest)) - p4_system("edit \"%s\"" % (dest)) + if diff['src_sha1'] != diff['dst_sha1']: + p4_system("edit \"%s\"" % (dest)) if isModeExecChanged(diff['src_mode'], diff['dst_mode']): + p4_system("edit \"%s\"" % (dest)) filesToChangeExecBit[dest] = diff['dst_mode'] os.unlink(dest) editedFiles.add(dest) @@ -834,6 +861,8 @@ class P4Submit(Command): return True class P4Sync(Command): + delete_actions = ( "delete", "move/delete", "purge" ) + def __init__(self): Command.__init__(self) self.options = [ @@ -882,6 +911,23 @@ class P4Sync(Command): if gitConfig("git-p4.syncFromOrigin") == "false": self.syncWithOrigin = False + # + # P4 wildcards are not allowed in filenames. P4 complains + # if you simply add them, but you can force it with "-f", in + # which case it translates them into %xx encoding internally. + # Search for and fix just these four characters. Do % last so + # that fixing it does not inadvertently create new %-escapes. + # + def wildcard_decode(self, path): + # Cannot have * in a filename in windows; untested as to + # what p4 would do in such a case. + if not self.isWindows: + path = path.replace("%2A", "*") + path = path.replace("%23", "#") \ + .replace("%40", "@") \ + .replace("%25", "%") + return path + def extractFilesFromCommit(self, commit): self.cloneExclude = [re.sub(r"\.\.\.$", "", path) for path in self.cloneExclude] @@ -910,6 +956,22 @@ class P4Sync(Command): return files def stripRepoPath(self, path, prefixes): + if self.useClientSpec: + + # if using the client spec, we use the output directory + # specified in the client. For example, a view + # //depot/foo/branch/... //client/branch/foo/... + # will end up putting all foo/branch files into + # branch/foo/ + for val in self.clientSpecDirs: + if path.startswith(val[0]): + # replace the depot path with the client path + path = path.replace(val[0], val[1][1]) + # now strip out the client (//client/...) + path = re.sub("^(//[^/]+/)", '', path) + # the rest is all path + return path + if self.keepRepoPath: prefixes = [re.sub("^(//[^/]+/).*", r'\1', prefixes[0])] @@ -960,6 +1022,7 @@ class P4Sync(Command): return relPath = self.stripRepoPath(file['depotFile'], self.branchPrefixes) + relPath = self.wildcard_decode(relPath) if verbose: sys.stderr.write("%s\n" % relPath) @@ -1032,16 +1095,16 @@ class P4Sync(Command): includeFile = True for val in self.clientSpecDirs: if f['path'].startswith(val[0]): - if val[1] <= 0: + if val[1][0] <= 0: includeFile = False break if includeFile: filesForCommit.append(f) - if f['action'] not in ('delete', 'move/delete', 'purge'): - filesToRead.append(f) - else: + if f['action'] in self.delete_actions: filesToDelete.append(f) + else: + filesToRead.append(f) # deleted files... for f in filesToDelete: @@ -1127,7 +1190,7 @@ class P4Sync(Command): cleanedFiles = {} for info in files: - if info["action"] in ("delete", "purge"): + if info["action"] in self.delete_actions: continue cleanedFiles[info["depotFile"]] = info["rev"] @@ -1429,7 +1492,7 @@ class P4Sync(Command): print "Doing initial import of %s from revision %s into %s" % (' '.join(self.depotPaths), revision, self.branch) details = { "user" : "git perforce import user", "time" : int(time.time()) } - details["desc"] = ("Initial import of %s from the state at revision %s" + details["desc"] = ("Initial import of %s from the state at revision %s\n" % (' '.join(self.depotPaths), revision)) details["change"] = revision newestRevision = 0 @@ -1440,9 +1503,16 @@ class P4Sync(Command): % (p, revision) for p in self.depotPaths])): - if info['code'] == 'error': + if 'code' in info and info['code'] == 'error': sys.stderr.write("p4 returned an error: %s\n" % info['data']) + if info['data'].find("must refer to client") >= 0: + sys.stderr.write("This particular p4 error is misleading.\n") + sys.stderr.write("Perhaps the depot path was misspelled.\n"); + sys.stderr.write("Depot path: %s\n" % " ".join(self.depotPaths)) + sys.exit(1) + if 'p4ExitCode' in info: + sys.stderr.write("p4 exitcode: %s\n" % info['p4ExitCode']) sys.exit(1) @@ -1450,7 +1520,7 @@ class P4Sync(Command): if change > newestRevision: newestRevision = change - if info["action"] in ("delete", "purge"): + if info["action"] in self.delete_actions: # don't increase the file cnt, otherwise details["depotFile123"] will have gaps! #fileCnt = fileCnt + 1 continue @@ -1475,19 +1545,45 @@ class P4Sync(Command): for entry in specList: for k,v in entry.iteritems(): if k.startswith("View"): + + # p4 has these %%1 to %%9 arguments in specs to + # reorder paths; which we can't handle (yet :) + if re.match('%%\d', v) != None: + print "Sorry, can't handle %%n arguments in client specs" + sys.exit(1) + if v.startswith('"'): start = 1 else: start = 0 index = v.find("...") + + # save the "client view"; i.e the RHS of the view + # line that tells the client where to put the + # files for this view. + cv = v[index+3:].strip() # +3 to remove previous '...' + + # if the client view doesn't end with a + # ... wildcard, then we're going to mess up the + # output directory, so fail gracefully. + if not cv.endswith('...'): + print 'Sorry, client view in "%s" needs to end with wildcard' % (k) + sys.exit(1) + cv=cv[:-3] + + # now save the view; +index means included, -index + # means it should be filtered out. v = v[start:index] if v.startswith("-"): v = v[1:] - temp[v] = -len(v) + include = -len(v) else: - temp[v] = len(v) + include = len(v) + + temp[v] = (include, cv) + self.clientSpecDirs = temp.items() - self.clientSpecDirs.sort( lambda x, y: abs( y[1] ) - abs( x[1] ) ) + self.clientSpecDirs.sort( lambda x, y: abs( y[1][0] ) - abs( x[1][0] ) ) def run(self, args): self.depotPaths = [] @@ -1667,6 +1763,8 @@ class P4Sync(Command): changes.sort() else: + if not self.p4BranchesInGit: + die("No remote p4 branches. Perhaps you never did \"git p4 clone\" in here."); if self.verbose: print "Getting p4 changes for %s...%s" % (', '.join(self.depotPaths), self.changeRange) @@ -1747,10 +1845,13 @@ class P4Clone(P4Sync): help="where to leave result of the clone"), optparse.make_option("-/", dest="cloneExclude", action="append", type="string", - help="exclude depot path") + help="exclude depot path"), + optparse.make_option("--bare", dest="cloneBare", + action="store_true", default=False), ] self.cloneDestination = None self.needsGit = False + self.cloneBare = False # This is required for the "append" cloneExclude action def ensure_value(self, attr, value): @@ -1790,11 +1891,16 @@ class P4Clone(P4Sync): self.cloneDestination = self.defaultDestination(args) print "Importing from %s into %s" % (', '.join(depotPaths), self.cloneDestination) + if not os.path.exists(self.cloneDestination): os.makedirs(self.cloneDestination) chdir(self.cloneDestination) - system("git init") - self.gitdir = os.getcwd() + "/.git" + + init_cmd = [ "git", "init" ] + if self.cloneBare: + init_cmd.append("--bare") + subprocess.check_call(init_cmd) + if not P4Sync.run(self, depotPaths): return False if self.branch != "master": @@ -1804,7 +1910,8 @@ class P4Clone(P4Sync): masterbranch = "refs/heads/p4/master" if gitBranchExists(masterbranch): system("git branch master %s" % masterbranch) - system("git checkout -f") + if not self.cloneBare: + system("git checkout -f") else: print "Could not detect main branch. No checkout/master branch created." diff --git a/contrib/fast-import/git-p4.txt b/contrib/fast-import/git-p4.txt index 49b335921..e09da445b 100644 --- a/contrib/fast-import/git-p4.txt +++ b/contrib/fast-import/git-p4.txt @@ -191,6 +191,11 @@ git-p4.useclientspec git config [--global] git-p4.useclientspec false +The P4CLIENT environment variable should be correctly set for p4 to be +able to find the relevant client. This client spec will be used to +both filter the files cloned by git and set the directory layout as +specified in the client (this implies --keep-path style semantics). + Implementation Details... ========================= diff --git a/contrib/hooks/post-receive-email b/contrib/hooks/post-receive-email index f99ea9585..21989fc6a 100755 --- a/contrib/hooks/post-receive-email +++ b/contrib/hooks/post-receive-email @@ -709,7 +709,7 @@ if [ -z "$GIT_DIR" ]; then exit 1 fi -projectdesc=$(sed -ne '1p' "$GIT_DIR/description") +projectdesc=$(sed -ne '1p' "$GIT_DIR/description" 2>/dev/null) # Check if the description is unchanged from it's default, and shorten it to # a more manageable length if it is if expr "$projectdesc" : "Unnamed repository.*$" >/dev/null diff --git a/contrib/svn-fe/svn-fe.txt b/contrib/svn-fe/svn-fe.txt index 35f84bd9e..cd075b96c 100644 --- a/contrib/svn-fe/svn-fe.txt +++ b/contrib/svn-fe/svn-fe.txt @@ -18,6 +18,9 @@ Subversion repository mirrored on the local disk. Remote Subversion repositories can be mirrored on local disk using the `svnsync` command. +Note: this tool is very young. The details of its commandline +interface may change in backward incompatible ways. + INPUT FORMAT ------------ Subversion's repository dump format is documented in full in diff --git a/diff-lib.c b/diff-lib.c index 392ce2bef..1e22992cb 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -106,7 +106,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option) DIFF_OPT_TST(&revs->diffopt, HAS_CHANGES)) break; - if (!ce_path_match(ce, revs->prune_data)) + if (!ce_path_match(ce, &revs->prune_data)) continue; if (ce_stage(ce)) { @@ -427,7 +427,7 @@ static int oneway_diff(struct cache_entry **src, struct unpack_trees_options *o) if (tree == o->df_conflict_entry) tree = NULL; - if (ce_path_match(idx ? idx : tree, revs->prune_data)) + if (ce_path_match(idx ? idx : tree, &revs->prune_data)) do_oneway_diff(o, idx, tree); return 0; @@ -501,7 +501,7 @@ int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt) active_nr = dst - active_cache; init_revisions(&revs, NULL); - revs.prune_data = opt->paths; + init_pathspec(&revs.prune_data, opt->pathspec.raw); tree = parse_tree_indirect(tree_sha1); if (!tree) die("bad tree object %s", sha1_to_hex(tree_sha1)); diff --git a/diff-no-index.c b/diff-no-index.c index ce9e78340..3a3614468 100644 --- a/diff-no-index.c +++ b/diff-no-index.c @@ -231,8 +231,9 @@ void diff_no_index(struct rev_info *revs, if (prefix) { int len = strlen(prefix); + const char *paths[3]; + memset(paths, 0, sizeof(paths)); - revs->diffopt.paths = xcalloc(2, sizeof(char *)); for (i = 0; i < 2; i++) { const char *p = argv[argc - 2 + i]; /* @@ -242,12 +243,12 @@ void diff_no_index(struct rev_info *revs, p = (strcmp(p, "-") ? xstrdup(prefix_filename(prefix, len, p)) : p); - revs->diffopt.paths[i] = p; + paths[i] = p; } + diff_tree_setup_paths(paths, &revs->diffopt); } else - revs->diffopt.paths = argv + argc - 2; - revs->diffopt.nr_paths = 2; + diff_tree_setup_paths(argv + argc - 2, &revs->diffopt); revs->diffopt.skip_stat_unmatch = 1; if (!revs->diffopt.output_format) revs->diffopt.output_format = DIFF_FORMAT_PATCH; @@ -259,8 +260,8 @@ void diff_no_index(struct rev_info *revs, if (diff_setup_done(&revs->diffopt) < 0) die("diff_setup_done failed"); - if (queue_diff(&revs->diffopt, revs->diffopt.paths[0], - revs->diffopt.paths[1])) + if (queue_diff(&revs->diffopt, revs->diffopt.pathspec.raw[0], + revs->diffopt.pathspec.raw[1])) exit(1); diff_set_mnemonic_prefix(&revs->diffopt, "1/", "2/"); diffcore_std(&revs->diffopt); @@ -133,9 +133,7 @@ struct diff_options { FILE *file; int close_file; - int nr_paths; - const char **paths; - int *pathlens; + struct pathspec pathspec; change_fn_t change; add_remove_fn_t add_remove; diff_format_fn_t format_callback; @@ -87,6 +87,21 @@ int fill_directory(struct dir_struct *dir, const char **pathspec) return len; } +int within_depth(const char *name, int namelen, + int depth, int max_depth) +{ + const char *cp = name, *cpe = name + namelen; + + while (cp < cpe) { + if (*cp++ != '/') + continue; + depth++; + if (depth > max_depth) + return 0; + } + return 1; +} + /* * Does 'match' match the given name? * A match is found if @@ -184,6 +199,95 @@ int match_pathspec(const char **pathspec, const char *name, int namelen, return retval; } +/* + * Does 'match' match the given name? + * A match is found if + * + * (1) the 'match' string is leading directory of 'name', or + * (2) the 'match' string is a wildcard and matches 'name', or + * (3) the 'match' string is exactly the same as 'name'. + * + * and the return value tells which case it was. + * + * It returns 0 when there is no match. + */ +static int match_pathspec_item(const struct pathspec_item *item, int prefix, + const char *name, int namelen) +{ + /* name/namelen has prefix cut off by caller */ + const char *match = item->match + prefix; + int matchlen = item->len - prefix; + + /* If the match was just the prefix, we matched */ + if (!*match) + return MATCHED_RECURSIVELY; + + if (matchlen <= namelen && !strncmp(match, name, matchlen)) { + if (matchlen == namelen) + return MATCHED_EXACTLY; + + if (match[matchlen-1] == '/' || name[matchlen] == '/') + return MATCHED_RECURSIVELY; + } + + if (item->has_wildcard && !fnmatch(match, name, 0)) + return MATCHED_FNMATCH; + + return 0; +} + +/* + * Given a name and a list of pathspecs, see if the name matches + * any of the pathspecs. The caller is also interested in seeing + * all pathspec matches some names it calls this function with + * (otherwise the user could have mistyped the unmatched pathspec), + * and a mark is left in seen[] array for pathspec element that + * actually matched anything. + */ +int match_pathspec_depth(const struct pathspec *ps, + const char *name, int namelen, + int prefix, char *seen) +{ + int i, retval = 0; + + if (!ps->nr) { + if (!ps->recursive || ps->max_depth == -1) + return MATCHED_RECURSIVELY; + + if (within_depth(name, namelen, 0, ps->max_depth)) + return MATCHED_EXACTLY; + else + return 0; + } + + name += prefix; + namelen -= prefix; + + for (i = ps->nr - 1; i >= 0; i--) { + int how; + if (seen && seen[i] == MATCHED_EXACTLY) + continue; + how = match_pathspec_item(ps->items+i, prefix, name, namelen); + if (ps->recursive && ps->max_depth != -1 && + how && how != MATCHED_FNMATCH) { + int len = ps->items[i].len; + if (name[len] == '/') + len++; + if (within_depth(name+len, namelen-len, 0, ps->max_depth)) + how = MATCHED_EXACTLY; + else + how = 0; + } + if (how) { + if (retval < how) + retval = how; + if (seen && seen[i] < how) + seen[i] = how; + } + } + return retval; +} + static int no_wildcard(const char *string) { return string[strcspn(string, "*?[{\\")] == '\0'; @@ -1151,3 +1255,50 @@ int remove_path(const char *name) return 0; } +static int pathspec_item_cmp(const void *a_, const void *b_) +{ + struct pathspec_item *a, *b; + + a = (struct pathspec_item *)a_; + b = (struct pathspec_item *)b_; + return strcmp(a->match, b->match); +} + +int init_pathspec(struct pathspec *pathspec, const char **paths) +{ + const char **p = paths; + int i; + + memset(pathspec, 0, sizeof(*pathspec)); + if (!p) + return 0; + while (*p) + p++; + pathspec->raw = paths; + pathspec->nr = p - paths; + if (!pathspec->nr) + return 0; + + pathspec->items = xmalloc(sizeof(struct pathspec_item)*pathspec->nr); + for (i = 0; i < pathspec->nr; i++) { + struct pathspec_item *item = pathspec->items+i; + const char *path = paths[i]; + + item->match = path; + item->len = strlen(path); + item->has_wildcard = !no_wildcard(path); + if (item->has_wildcard) + pathspec->has_wildcard = 1; + } + + qsort(pathspec->items, pathspec->nr, + sizeof(struct pathspec_item), pathspec_item_cmp); + + return 0; +} + +void free_pathspec(struct pathspec *pathspec) +{ + free(pathspec->items); + pathspec->items = NULL; +} @@ -65,6 +65,10 @@ struct dir_struct { #define MATCHED_FNMATCH 2 #define MATCHED_EXACTLY 3 extern int match_pathspec(const char **pathspec, const char *name, int namelen, int prefix, char *seen); +extern int match_pathspec_depth(const struct pathspec *pathspec, + const char *name, int namelen, + int prefix, char *seen); +extern int within_depth(const char *name, int namelen, int depth, int max_depth); extern int fill_directory(struct dir_struct *dir, const char **pathspec); extern int read_directory(struct dir_struct *, const char *path, int len, const char **pathspec); diff --git a/exec_cmd.c b/exec_cmd.c index bf225706e..38545e8bf 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -3,7 +3,6 @@ #include "quote.h" #define MAX_ARGS 32 -extern char **environ; static const char *argv_exec_path; static const char *argv0_path; diff --git a/fast-import.c b/fast-import.c index 785776086..3886a1b46 100644 --- a/fast-import.c +++ b/fast-import.c @@ -329,6 +329,7 @@ static struct mark_set *marks; static const char *export_marks_file; static const char *import_marks_file; static int import_marks_file_from_stream; +static int import_marks_file_ignore_missing; static int relative_marks_paths; /* Our last blob */ @@ -1795,7 +1796,11 @@ static void read_marks(void) { char line[512]; FILE *f = fopen(import_marks_file, "r"); - if (!f) + if (f) + ; + else if (import_marks_file_ignore_missing && errno == ENOENT) + return; /* Marks file does not exist */ + else die_errno("cannot read '%s'", import_marks_file); while (fgets(line, sizeof(line), f)) { uintmax_t mark; @@ -2231,6 +2236,12 @@ static void file_change_m(struct branch *b) p = uq.buf; } + /* Git does not track empty, non-toplevel directories. */ + if (S_ISDIR(mode) && !memcmp(sha1, EMPTY_TREE_SHA1_BIN, 20) && *p) { + tree_content_remove(&b->branch_tree, p, NULL); + return; + } + if (S_ISGITLINK(mode)) { if (inline_data) die("Git links cannot be specified 'inline': %s", @@ -2861,7 +2872,8 @@ static char* make_fast_import_path(const char *path) return strbuf_detach(&abs_path, NULL); } -static void option_import_marks(const char *marks, int from_stream) +static void option_import_marks(const char *marks, + int from_stream, int ignore_missing) { if (import_marks_file) { if (from_stream) @@ -2875,6 +2887,7 @@ static void option_import_marks(const char *marks, int from_stream) import_marks_file = make_fast_import_path(marks); safe_create_leading_directories_const(import_marks_file); import_marks_file_from_stream = from_stream; + import_marks_file_ignore_missing = ignore_missing; } static void option_date_format(const char *fmt) @@ -2974,7 +2987,10 @@ static int parse_one_feature(const char *feature, int from_stream) if (!prefixcmp(feature, "date-format=")) { option_date_format(feature + 12); } else if (!prefixcmp(feature, "import-marks=")) { - option_import_marks(feature + 13, from_stream); + option_import_marks(feature + 13, from_stream, 0); + } else if (!prefixcmp(feature, "import-marks-if-exists=")) { + option_import_marks(feature + strlen("import-marks-if-exists="), + from_stream, 1); } else if (!prefixcmp(feature, "export-marks=")) { option_export_marks(feature + 13); } else if (!strcmp(feature, "cat-blob")) { @@ -2985,6 +3001,8 @@ static int parse_one_feature(const char *feature, int from_stream) relative_marks_paths = 0; } else if (!prefixcmp(feature, "force")) { force_update = 1; + } else if (!strcmp(feature, "notes")) { + ; /* do nothing; we have the feature */ } else { return 0; } diff --git a/git-compat-util.h b/git-compat-util.h index d6d269f13..9c23622ed 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -31,6 +31,9 @@ #define maximum_signed_value_of_type(a) \ (INTMAX_MAX >> (bitsizeof(intmax_t) - bitsizeof(a))) +#define maximum_unsigned_value_of_type(a) \ + (UINTMAX_MAX >> (bitsizeof(uintmax_t) - bitsizeof(a))) + /* * Signed integer overflow is undefined in C, so here's a helper macro * to detect if the sum of two integers will overflow. @@ -40,6 +43,9 @@ #define signed_add_overflows(a, b) \ ((b) > maximum_signed_value_of_type(a) - (a)) +#define unsigned_add_overflows(a, b) \ + ((b) > maximum_unsigned_value_of_type(a) - (a)) + #ifdef __GNUC__ #define TYPEOF(x) (__typeof__(x)) #else diff --git a/git-pull.sh b/git-pull.sh index eb87f4906..f6b7b8404 100755 --- a/git-pull.sh +++ b/git-pull.sh @@ -114,7 +114,7 @@ do --d|--dr|--dry|--dry-|--dry-r|--dry-ru|--dry-run) dry_run=--dry-run ;; - -h|--h|--he|--hel|--help) + -h|--h|--he|--hel|--help|--help-|--help-a|--help-al|--help-all) usage ;; *) diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index a5ffd9a31..5873ba4bc 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -894,7 +894,7 @@ first and then run 'git rebase --continue' again." if test ! -z "$1" then - output git checkout "$1" || + output git checkout "$1" -- || die "Could not checkout $1" fi @@ -1021,7 +1021,7 @@ first and then run 'git rebase --continue' again." # e, edit = use commit, but stop for amending # s, squash = use commit, but meld into previous commit # f, fixup = like "squash", but discard this commit's log message -# x <cmd>, exec <cmd> = Run a shell command <cmd>, and stop if it fails +# x, exec = run command (the rest of the line) using shell # # If you remove a line here THAT COMMIT WILL BE LOST. # However, if you remove everything, the rebase will be aborted. diff --git a/git-rebase.sh b/git-rebase.sh index d8e190302..cbb0ea90e 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -482,6 +482,7 @@ case "$#" in then head_name="detached HEAD" else + echo >&2 "fatal: no such branch: $1" usage fi ;; @@ -513,7 +514,7 @@ then if test -z "$force_rebase" then # Lazily switch to the target branch if needed... - test -z "$switch_to" || git checkout "$switch_to" + test -z "$switch_to" || git checkout "$switch_to" -- say "Current branch $branch_name is up to date." exit 0 else diff --git a/git-submodule.sh b/git-submodule.sh index c21b77aee..8b9058971 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -37,12 +37,24 @@ resolve_relative_url () die "remote ($remote) does not have a url defined in .git/config" url="$1" remoteurl=${remoteurl%/} + sep=/ while test -n "$url" do case "$url" in ../*) url="${url#../}" - remoteurl="${remoteurl%/*}" + case "$remoteurl" in + */*) + remoteurl="${remoteurl%/*}" + ;; + *:*) + remoteurl="${remoteurl%:*}" + sep=: + ;; + *) + die "cannot strip one component off url '$remoteurl'" + ;; + esac ;; ./*) url="${url#./}" @@ -51,7 +63,7 @@ resolve_relative_url () break;; esac done - echo "$remoteurl/${url%/}" + echo "$remoteurl$sep${url%/}" } # @@ -177,24 +177,24 @@ static int handle_alias(int *argcp, const char ***argv) alias_string = alias_lookup(alias_command); if (alias_string) { if (alias_string[0] == '!') { + const char **alias_argv; + int argc = *argcp, i; + commit_pager_choice(); - if (*argcp > 1) { - struct strbuf buf; - - strbuf_init(&buf, PATH_MAX); - strbuf_addstr(&buf, alias_string); - sq_quote_argv(&buf, (*argv) + 1, PATH_MAX); - free(alias_string); - alias_string = buf.buf; - } - trace_printf("trace: alias to shell cmd: %s => %s\n", - alias_command, alias_string + 1); - ret = system(alias_string + 1); - if (ret >= 0 && WIFEXITED(ret) && - WEXITSTATUS(ret) != 127) - exit(WEXITSTATUS(ret)); - die("Failed to run '%s' when expanding alias '%s'", - alias_string + 1, alias_command); + + /* build alias_argv */ + alias_argv = xmalloc(sizeof(*alias_argv) * (argc + 1)); + alias_argv[0] = alias_string + 1; + for (i = 1; i < argc; ++i) + alias_argv[i] = (*argv)[i]; + alias_argv[argc] = NULL; + + ret = run_command_v_opt(alias_argv, RUN_USING_SHELL); + if (ret >= 0) /* normal exit */ + exit(ret); + + die_errno("While expanding alias '%s': '%s'", + alias_command, alias_string + 1); } count = split_cmdline(alias_string, &new_argv); if (count < 0) @@ -313,7 +313,6 @@ static void handle_internal_command(int argc, const char **argv) const char *cmd = argv[0]; static struct cmd_struct commands[] = { { "add", cmd_add, RUN_SETUP | NEED_WORK_TREE }, - { "stage", cmd_add, RUN_SETUP | NEED_WORK_TREE }, { "annotate", cmd_annotate, RUN_SETUP }, { "apply", cmd_apply, RUN_SETUP_GENTLY }, { "archive", cmd_archive }, @@ -322,15 +321,15 @@ static void handle_internal_command(int argc, const char **argv) { "branch", cmd_branch, RUN_SETUP }, { "bundle", cmd_bundle, RUN_SETUP_GENTLY }, { "cat-file", cmd_cat_file, RUN_SETUP }, + { "check-attr", cmd_check_attr, RUN_SETUP }, + { "check-ref-format", cmd_check_ref_format }, { "checkout", cmd_checkout, RUN_SETUP | NEED_WORK_TREE }, { "checkout-index", cmd_checkout_index, RUN_SETUP | NEED_WORK_TREE}, - { "check-ref-format", cmd_check_ref_format }, - { "check-attr", cmd_check_attr, RUN_SETUP }, { "cherry", cmd_cherry, RUN_SETUP }, { "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE }, - { "clone", cmd_clone }, { "clean", cmd_clean, RUN_SETUP | NEED_WORK_TREE }, + { "clone", cmd_clone }, { "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE }, { "commit-tree", cmd_commit_tree, RUN_SETUP }, { "config", cmd_config, RUN_SETUP_GENTLY }, @@ -358,8 +357,8 @@ static void handle_internal_command(int argc, const char **argv) { "init-db", cmd_init_db }, { "log", cmd_log, RUN_SETUP }, { "ls-files", cmd_ls_files, RUN_SETUP }, - { "ls-tree", cmd_ls_tree, RUN_SETUP }, { "ls-remote", cmd_ls_remote, RUN_SETUP_GENTLY }, + { "ls-tree", cmd_ls_tree, RUN_SETUP }, { "mailinfo", cmd_mailinfo }, { "mailsplit", cmd_mailsplit }, { "merge", cmd_merge, RUN_SETUP | NEED_WORK_TREE }, @@ -379,6 +378,7 @@ static void handle_internal_command(int argc, const char **argv) { "notes", cmd_notes, RUN_SETUP }, { "pack-objects", cmd_pack_objects, RUN_SETUP }, { "pack-redundant", cmd_pack_redundant, RUN_SETUP }, + { "pack-refs", cmd_pack_refs, RUN_SETUP }, { "patch-id", cmd_patch_id }, { "peek-remote", cmd_ls_remote, RUN_SETUP_GENTLY }, { "pickaxe", cmd_blame, RUN_SETUP }, @@ -392,7 +392,7 @@ static void handle_internal_command(int argc, const char **argv) { "remote-ext", cmd_remote_ext }, { "remote-fd", cmd_remote_fd }, { "replace", cmd_replace, RUN_SETUP }, - { "repo-config", cmd_config, RUN_SETUP_GENTLY }, + { "repo-config", cmd_repo_config, RUN_SETUP_GENTLY }, { "rerere", cmd_rerere, RUN_SETUP }, { "reset", cmd_reset, RUN_SETUP }, { "rev-list", cmd_rev_list, RUN_SETUP }, @@ -401,8 +401,10 @@ static void handle_internal_command(int argc, const char **argv) { "rm", cmd_rm, RUN_SETUP }, { "send-pack", cmd_send_pack, RUN_SETUP }, { "shortlog", cmd_shortlog, RUN_SETUP_GENTLY | USE_PAGER }, - { "show-branch", cmd_show_branch, RUN_SETUP }, { "show", cmd_show, RUN_SETUP }, + { "show-branch", cmd_show_branch, RUN_SETUP }, + { "show-ref", cmd_show_ref, RUN_SETUP }, + { "stage", cmd_add, RUN_SETUP | NEED_WORK_TREE }, { "status", cmd_status, RUN_SETUP | NEED_WORK_TREE }, { "stripspace", cmd_stripspace }, { "symbolic-ref", cmd_symbolic_ref, RUN_SETUP }, @@ -415,13 +417,11 @@ static void handle_internal_command(int argc, const char **argv) { "update-server-info", cmd_update_server_info, RUN_SETUP }, { "upload-archive", cmd_upload_archive }, { "var", cmd_var, RUN_SETUP_GENTLY }, + { "verify-pack", cmd_verify_pack }, { "verify-tag", cmd_verify_tag, RUN_SETUP }, { "version", cmd_version }, { "whatchanged", cmd_whatchanged, RUN_SETUP }, { "write-tree", cmd_write_tree, RUN_SETUP }, - { "verify-pack", cmd_verify_pack }, - { "show-ref", cmd_show_ref, RUN_SETUP }, - { "pack-refs", cmd_pack_refs, RUN_SETUP }, }; int i; static const char ext[] = STRIP_EXTENSION; diff --git a/gitk-git/gitk b/gitk-git/gitk index e82c6bfed..e82c6bfed 100644..100755 --- a/gitk-git/gitk +++ b/gitk-git/gitk diff --git a/gitweb/INSTALL b/gitweb/INSTALL index 823053173..4964a679b 100644 --- a/gitweb/INSTALL +++ b/gitweb/INSTALL @@ -237,6 +237,12 @@ Requirements - Perl modules: CGI, Encode, Fcntl, File::Find, File::Basename. - web server +The following optional Perl modules are required for extra features + - Digest::MD5 - for gravatar support + - CGI::Fast and FCGI - for running gitweb as FastCGI script + - HTML::TagCloud - for fancy tag cloud in project list view + - HTTP::Date or Time::ParseDate - to support If-Modified-Since for feeds + Example web server configuration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index c65af1a00..1b9369d1a 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -250,13 +250,14 @@ our %highlight_ext = ( # main extensions, defining name of syntax; # see files in /usr/share/highlight/langDefs/ directory map { $_ => $_ } - qw(py c cpp rb java css php sh pl js tex bib xml awk bat ini spec tcl), + qw(py c cpp rb java css php sh pl js tex bib xml awk bat ini spec tcl sql make), # alternate extensions, see /etc/highlight/filetypes.conf 'h' => 'c', + map { $_ => 'sh' } qw(bash zsh ksh), map { $_ => 'cpp' } qw(cxx c++ cc), - map { $_ => 'php' } qw(php3 php4), + map { $_ => 'php' } qw(php3 php4 php5 phps), map { $_ => 'pl' } qw(perl pm), # perhaps also 'cgi' - 'mak' => 'make', + map { $_ => 'make'} qw(mak mk), map { $_ => 'xml' } qw(xhtml html htm), ); @@ -3464,11 +3465,10 @@ sub run_highlighter { my ($fd, $highlight, $syntax) = @_; return $fd unless ($highlight && defined $syntax); - close $fd - or die_error(404, "Reading blob failed"); + close $fd; open $fd, quote_command(git_cmd(), "cat-file", "blob", $hash)." | ". quote_command($highlight_bin). - " --xhtml --fragment --syntax $syntax |" + " --fragment --syntax $syntax |" or die_error(500, "Couldn't open file or run syntax highlighter"); return $fd; } @@ -3501,7 +3501,7 @@ sub print_feed_meta { $href_params{'-title'} = 'log'; } - foreach my $format qw(RSS Atom) { + foreach my $format (qw(RSS Atom)) { my $type = lc($format); my %link_attr = ( '-rel' => 'alternate', @@ -3601,10 +3601,15 @@ EOF insert_file($site_header); } - print "<div class=\"page_header\">\n" . - $cgi->a({-href => esc_url($logo_url), - -title => $logo_label}, - qq(<img src=").esc_url($logo).qq(" width="72" height="27" alt="git" class="logo"/>)); + print "<div class=\"page_header\">\n"; + if (defined $logo) { + print $cgi->a({-href => esc_url($logo_url), + -title => $logo_label}, + $cgi->img({-src => esc_url($logo), + -width => 72, -height => 27, + -alt => "git", + -class => "logo"})); + } print $cgi->a({-href => esc_url($home_link)}, $home_link_str) . " / "; if (defined $project) { print $cgi->a({-href => href(action=>"summary")}, esc_html($project)); @@ -3677,7 +3682,7 @@ sub git_footer_html { } $href_params{'-title'} ||= 'log'; - foreach my $format qw(RSS Atom) { + foreach my $format (qw(RSS Atom)) { $href_params{'action'} = lc($format); print $cgi->a({-href => href(%href_params), -title => "$href_params{'-title'} $format feed", @@ -4407,7 +4412,7 @@ sub git_difftree_body { } if ($diff->{'from_mode'} ne ('0' x 6)) { $from_mode_oct = oct $diff->{'from_mode'}; - if (S_ISREG($to_mode_oct)) { # only for regular file + if (S_ISREG($from_mode_oct)) { # only for regular file $from_mode_str = sprintf("%04o", $from_mode_oct & 0777); # permission bits } $from_file_type = file_type($diff->{'from_mode'}); diff --git a/list-objects.c b/list-objects.c index 8953548c0..61f6cc98d 100644 --- a/list-objects.c +++ b/list-objects.c @@ -61,12 +61,15 @@ static void process_tree(struct rev_info *revs, struct tree *tree, show_object_fn show, struct name_path *path, + struct strbuf *base, const char *name) { struct object *obj = &tree->object; struct tree_desc desc; struct name_entry entry; struct name_path me; + int all_interesting = (revs->diffopt.pathspec.nr == 0); + int baselen = base->len; if (!revs->tree_objects) return; @@ -82,13 +85,32 @@ static void process_tree(struct rev_info *revs, me.elem = name; me.elem_len = strlen(name); + if (!all_interesting) { + strbuf_addstr(base, name); + if (base->len) + strbuf_addch(base, '/'); + } + init_tree_desc(&desc, tree->buffer, tree->size); while (tree_entry(&desc, &entry)) { + if (!all_interesting) { + int showit = tree_entry_interesting(&entry, + base, 0, + &revs->diffopt.pathspec); + + if (showit < 0) + break; + else if (!showit) + continue; + else if (showit == 2) + all_interesting = 1; + } + if (S_ISDIR(entry.mode)) process_tree(revs, lookup_tree(entry.sha1), - show, &me, entry.path); + show, &me, base, entry.path); else if (S_ISGITLINK(entry.mode)) process_gitlink(revs, entry.sha1, show, &me, entry.path); @@ -97,6 +119,7 @@ static void process_tree(struct rev_info *revs, lookup_blob(entry.sha1), show, &me, entry.path); } + strbuf_setlen(base, baselen); free(tree->buffer); tree->buffer = NULL; } @@ -146,7 +169,9 @@ void traverse_commit_list(struct rev_info *revs, { int i; struct commit *commit; + struct strbuf base; + strbuf_init(&base, PATH_MAX); while ((commit = get_revision(revs)) != NULL) { add_pending_tree(revs, commit->tree); show_commit(commit, data); @@ -164,7 +189,7 @@ void traverse_commit_list(struct rev_info *revs, } if (obj->type == OBJ_TREE) { process_tree(revs, (struct tree *)obj, show_object, - NULL, name); + NULL, &base, name); continue; } if (obj->type == OBJ_BLOB) { @@ -181,4 +206,5 @@ void traverse_commit_list(struct rev_info *revs, revs->pending.alloc = 0; revs->pending.objects = NULL; } + strbuf_release(&base); } diff --git a/ll-merge.c b/ll-merge.c index 007dd3e4d..6ce512efc 100644 --- a/ll-merge.c +++ b/ll-merge.c @@ -351,16 +351,13 @@ int ll_merge(mmbuffer_t *result_buf, const struct ll_merge_options *opts) { static struct git_attr_check check[2]; + static const struct ll_merge_options default_opts; const char *ll_driver_name = NULL; int marker_size = DEFAULT_CONFLICT_MARKER_SIZE; const struct ll_merge_driver *driver; - if (!opts) { - struct ll_merge_options default_opts = {0}; - return ll_merge(result_buf, path, ancestor, ancestor_label, - ours, our_label, theirs, their_label, - &default_opts); - } + if (!opts) + opts = &default_opts; if (opts->renormalize) { normalize_file(ancestor, path); diff --git a/merge-recursive.h b/merge-recursive.h index c8135b0ec..981ed6ac9 100644 --- a/merge-recursive.h +++ b/merge-recursive.h @@ -57,6 +57,8 @@ struct tree *write_tree_from_memory(struct merge_options *o); int parse_merge_opt(struct merge_options *out, const char *s); /* builtin/merge.c */ -int try_merge_command(const char *strategy, struct commit_list *common, const char *head_arg, struct commit_list *remotes); +int try_merge_command(const char *strategy, size_t xopts_nr, + const char **xopts, struct commit_list *common, + const char *head_arg, struct commit_list *remotes); #endif diff --git a/notes-merge.c b/notes-merge.c index 71c4d45fc..1467ad317 100644 --- a/notes-merge.c +++ b/notes-merge.c @@ -615,7 +615,7 @@ int notes_merge(struct notes_merge_options *o, bases = get_merge_bases(local, remote, 1); if (!bases) { base_sha1 = null_sha1; - base_tree_sha1 = (unsigned char *)EMPTY_TREE_SHA1_BIN; + base_tree_sha1 = EMPTY_TREE_SHA1_BIN; OUTPUT(o, 4, "No merge base found; doing history-less merge"); } else if (!bases->next) { base_sha1 = bases->item->object.sha1; diff --git a/patch-delta.c b/patch-delta.c index d218faa02..56e0a5ede 100644 --- a/patch-delta.c +++ b/patch-delta.c @@ -48,7 +48,7 @@ void *patch_delta(const void *src_buf, unsigned long src_size, if (cmd & 0x20) cp_size |= (*data++ << 8); if (cmd & 0x40) cp_size |= (*data++ << 16); if (cp_size == 0) cp_size = 0x10000; - if (cp_off + cp_size < cp_size || + if (unsigned_add_overflows(cp_off, cp_size) || cp_off + cp_size > src_size || cp_size > size) break; diff --git a/perl/Git.pm b/perl/Git.pm index 205e48aa3..a86ab709c 100644 --- a/perl/Git.pm +++ b/perl/Git.pm @@ -99,7 +99,7 @@ increase notwithstanding). use Carp qw(carp croak); # but croak is bad - throw instead use Error qw(:try); -use Cwd qw(abs_path); +use Cwd qw(abs_path cwd); use IPC::Open2 qw(open2); use Fcntl qw(SEEK_SET SEEK_CUR); } @@ -396,7 +396,16 @@ See C<command_close_bidi_pipe()> for details. sub command_bidi_pipe { my ($pid, $in, $out); + my ($self) = _maybe_self(@_); + local %ENV = %ENV; + my $cwd_save = undef; + if ($self) { + shift; + $cwd_save = cwd(); + _setup_git_cmd_env($self); + } $pid = open2($in, $out, 'git', @_); + chdir($cwd_save) if $cwd_save; return ($pid, $in, $out, join(' ', @_)); } @@ -843,7 +852,7 @@ sub _open_hash_and_insert_object_if_needed { ($self->{hash_object_pid}, $self->{hash_object_in}, $self->{hash_object_out}, $self->{hash_object_ctx}) = - command_bidi_pipe(qw(hash-object -w --stdin-paths --no-filters)); + $self->command_bidi_pipe(qw(hash-object -w --stdin-paths --no-filters)); } sub _close_hash_and_insert_object { @@ -932,7 +941,7 @@ sub _open_cat_blob_if_needed { ($self->{cat_blob_pid}, $self->{cat_blob_in}, $self->{cat_blob_out}, $self->{cat_blob_ctx}) = - command_bidi_pipe(qw(cat-file --batch)); + $self->command_bidi_pipe(qw(cat-file --batch)); } sub _close_cat_blob { @@ -1279,6 +1288,14 @@ sub _command_common_pipe { # for the given repository and execute the git command. sub _cmd_exec { my ($self, @args) = @_; + _setup_git_cmd_env($self); + _execv_git_cmd(@args); + die qq[exec "@args" failed: $!]; +} + +# set up the appropriate state for git command +sub _setup_git_cmd_env { + my $self = shift; if ($self) { $self->repo_path() and $ENV{'GIT_DIR'} = $self->repo_path(); $self->repo_path() and $self->wc_path() @@ -1286,8 +1303,6 @@ sub _cmd_exec { $self->wc_path() and chdir($self->wc_path()); $self->wc_subdir() and chdir($self->wc_subdir()); } - _execv_git_cmd(@args); - die qq[exec "@args" failed: $!]; } # Execute the given Git command ($_[0]) with arguments ($_[1..]) diff --git a/preload-index.c b/preload-index.c index e3d0bda31..49cb08df9 100644 --- a/preload-index.c +++ b/preload-index.c @@ -35,7 +35,9 @@ static void *preload_thread(void *_data) struct index_state *index = p->index; struct cache_entry **cep = index->cache + p->offset; struct cache_def cache; + struct pathspec pathspec; + init_pathspec(&pathspec, p->pathspec); memset(&cache, 0, sizeof(cache)); nr = p->nr; if (nr + p->offset > index->cache_nr) @@ -51,7 +53,7 @@ static void *preload_thread(void *_data) continue; if (ce_uptodate(ce)) continue; - if (!ce_path_match(ce, p->pathspec)) + if (!ce_path_match(ce, &pathspec)) continue; if (threaded_has_symlink_leading_path(&cache, ce->name, ce_namelen(ce))) continue; @@ -61,6 +63,7 @@ static void *preload_thread(void *_data) continue; ce_mark_uptodate(ce); } while (--nr > 0); + free_pathspec(&pathspec); return NULL; } @@ -1,8 +1,7 @@ #ifndef QUOTE_H #define QUOTE_H -#include <stddef.h> -#include <stdio.h> +struct strbuf; /* Help to copy the thing properly quoted for the shell safety. * any single quote is replaced with '\'', any exclamation point diff --git a/read-cache.c b/read-cache.c index 4f2e890b0..98d526bd4 100644 --- a/read-cache.c +++ b/read-cache.c @@ -92,7 +92,7 @@ static int ce_compare_data(struct cache_entry *ce, struct stat *st) if (fd >= 0) { unsigned char sha1[20]; - if (!index_fd(sha1, fd, st, 0, OBJ_BLOB, ce->name)) + if (!index_fd(sha1, fd, st, 0, OBJ_BLOB, ce->name, 0)) match = hashcmp(sha1, ce->sha1); /* index_fd() closed the file descriptor already */ } @@ -706,30 +706,9 @@ int ce_same_name(struct cache_entry *a, struct cache_entry *b) return ce_namelen(b) == len && !memcmp(a->name, b->name, len); } -int ce_path_match(const struct cache_entry *ce, const char **pathspec) +int ce_path_match(const struct cache_entry *ce, const struct pathspec *pathspec) { - const char *match, *name; - int len; - - if (!pathspec) - return 1; - - len = ce_namelen(ce); - name = ce->name; - while ((match = *pathspec++) != NULL) { - int matchlen = strlen(match); - if (matchlen > len) - continue; - if (memcmp(name, match, matchlen)) - continue; - if (matchlen && name[matchlen-1] == '/') - return 1; - if (name[matchlen] == '/' || !name[matchlen]) - return 1; - if (!matchlen) - return 1; - } - return 0; + return match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL); } /* @@ -1104,7 +1083,7 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate, } static void show_file(const char * fmt, const char * name, int in_porcelain, - int * first, char *header_msg) + int * first, const char *header_msg) { if (in_porcelain && *first && header_msg) { printf("%s\n", header_msg); @@ -1114,7 +1093,7 @@ static void show_file(const char * fmt, const char * name, int in_porcelain, } int refresh_index(struct index_state *istate, unsigned int flags, const char **pathspec, - char *seen, char *header_msg) + char *seen, const char *header_msg) { int i; int has_errors = 0; diff --git a/remote-curl.c b/remote-curl.c index 04d4813e4..d0fb0a044 100644 --- a/remote-curl.c +++ b/remote-curl.c @@ -356,14 +356,59 @@ static size_t rpc_in(const void *ptr, size_t eltsize, return size; } +static int run_slot(struct active_request_slot *slot) +{ + int err = 0; + struct slot_results results; + + slot->results = &results; + slot->curl_result = curl_easy_perform(slot->curl); + finish_active_slot(slot); + + if (results.curl_result != CURLE_OK) { + err |= error("RPC failed; result=%d, HTTP code = %ld", + results.curl_result, results.http_code); + } + + return err; +} + +static int probe_rpc(struct rpc_state *rpc) +{ + struct active_request_slot *slot; + struct curl_slist *headers = NULL; + struct strbuf buf = STRBUF_INIT; + int err; + + slot = get_active_slot(); + + headers = curl_slist_append(headers, rpc->hdr_content_type); + headers = curl_slist_append(headers, rpc->hdr_accept); + + curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0); + curl_easy_setopt(slot->curl, CURLOPT_POST, 1); + curl_easy_setopt(slot->curl, CURLOPT_URL, rpc->service_url); + curl_easy_setopt(slot->curl, CURLOPT_ENCODING, ""); + curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, "0000"); + curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE, 4); + curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer); + curl_easy_setopt(slot->curl, CURLOPT_FILE, &buf); + + err = run_slot(slot); + + curl_slist_free_all(headers); + strbuf_release(&buf); + return err; +} + static int post_rpc(struct rpc_state *rpc) { struct active_request_slot *slot; - struct slot_results results; struct curl_slist *headers = NULL; int use_gzip = rpc->gzip_request; char *gzip_body = NULL; - int err = 0, large_request = 0; + int err, large_request = 0; /* Try to load the entire request, if we can fit it into the * allocated buffer space we can use HTTP/1.0 and avoid the @@ -386,8 +431,13 @@ static int post_rpc(struct rpc_state *rpc) rpc->len += n; } + if (large_request) { + err = probe_rpc(rpc); + if (err) + return err; + } + slot = get_active_slot(); - slot->results = &results; curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0); curl_easy_setopt(slot->curl, CURLOPT_POST, 1); @@ -401,7 +451,7 @@ static int post_rpc(struct rpc_state *rpc) /* The request body is large and the size cannot be predicted. * We must use chunked encoding to send it. */ - headers = curl_slist_append(headers, "Expect: 100-continue"); + headers = curl_slist_append(headers, "Expect:"); headers = curl_slist_append(headers, "Transfer-Encoding: chunked"); rpc->initial_buffer = 1; curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, rpc_out); @@ -475,13 +525,7 @@ static int post_rpc(struct rpc_state *rpc) curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, rpc_in); curl_easy_setopt(slot->curl, CURLOPT_FILE, rpc); - slot->curl_result = curl_easy_perform(slot->curl); - finish_active_slot(slot); - - if (results.curl_result != CURLE_OK) { - err |= error("RPC failed; result=%d, HTTP code = %ld", - results.curl_result, results.http_code); - } + err = run_slot(slot); curl_slist_free_all(headers); free(gzip_body); diff --git a/revision.c b/revision.c index 7b9eaefae..86d247048 100644 --- a/revision.c +++ b/revision.c @@ -323,7 +323,7 @@ static int rev_compare_tree(struct rev_info *revs, struct commit *parent, struct * tagged commit by specifying both --simplify-by-decoration * and pathspec. */ - if (!revs->prune_data) + if (!revs->prune_data.nr) return REV_TREE_SAME; } @@ -553,11 +553,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs) left_first = left_count < right_count; init_patch_ids(&ids); - if (revs->diffopt.nr_paths) { - ids.diffopts.nr_paths = revs->diffopt.nr_paths; - ids.diffopts.paths = revs->diffopt.paths; - ids.diffopts.pathlens = revs->diffopt.pathlens; - } + ids.diffopts.pathspec = revs->diffopt.pathspec; /* Compute patch-ids for one side */ for (p = list; p; p = p->next) { @@ -973,7 +969,7 @@ static void prepare_show_merge(struct rev_info *revs) struct cache_entry *ce = active_cache[i]; if (!ce_stage(ce)) continue; - if (ce_path_match(ce, revs->prune_data)) { + if (ce_path_match(ce, &revs->prune_data)) { prune_num++; prune = xrealloc(prune, sizeof(*prune) * prune_num); prune[prune_num-2] = ce->name; @@ -983,7 +979,8 @@ static void prepare_show_merge(struct rev_info *revs) ce_same_name(ce, active_cache[i+1])) i++; } - revs->prune_data = prune; + free_pathspec(&revs->prune_data); + init_pathspec(&revs->prune_data, prune); revs->limited = 1; } @@ -1620,7 +1617,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s } if (prune_data) - revs->prune_data = get_pathspec(revs->prefix, prune_data); + init_pathspec(&revs->prune_data, get_pathspec(revs->prefix, prune_data)); if (revs->def == NULL) revs->def = opt ? opt->def : NULL; @@ -1651,13 +1648,13 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s if (revs->topo_order) revs->limited = 1; - if (revs->prune_data) { - diff_tree_setup_paths(revs->prune_data, &revs->pruning); + if (revs->prune_data.nr) { + diff_tree_setup_paths(revs->prune_data.raw, &revs->pruning); /* Can't prune commits with rename following: the paths change.. */ if (!DIFF_OPT_TST(&revs->diffopt, FOLLOW_RENAMES)) revs->prune = 1; if (!revs->full_diff) - diff_tree_setup_paths(revs->prune_data, &revs->diffopt); + diff_tree_setup_paths(revs->prune_data.raw, &revs->diffopt); } if (revs->combine_merges) revs->ignore_merges = 0; diff --git a/revision.h b/revision.h index 05659c64a..82509dd1d 100644 --- a/revision.h +++ b/revision.h @@ -34,7 +34,7 @@ struct rev_info { /* Basic information */ const char *prefix; const char *def; - void *prune_data; + struct pathspec prune_data; unsigned int early_output; /* Traversal flags */ diff --git a/run-command.c b/run-command.c index 2a1041ef6..f91e446c8 100644 --- a/run-command.c +++ b/run-command.c @@ -194,6 +194,7 @@ fail_pipe: } trace_argv_printf(cmd->argv, "trace: run_command:"); + fflush(NULL); #ifndef WIN32 { @@ -201,7 +202,6 @@ fail_pipe: if (pipe(notify_pipe)) notify_pipe[0] = notify_pipe[1] = -1; - fflush(NULL); cmd->pid = fork(); if (!cmd->pid) { /* @@ -7,10 +7,13 @@ static int inside_work_tree = -1; char *prefix_path(const char *prefix, int len, const char *path) { const char *orig = path; - char *sanitized = xmalloc(len + strlen(path) + 1); - if (is_absolute_path(orig)) - strcpy(sanitized, path); - else { + char *sanitized; + if (is_absolute_path(orig)) { + const char *temp = make_absolute_path(path); + sanitized = xmalloc(len + strlen(temp) + 1); + strcpy(sanitized, temp); + } else { + sanitized = xmalloc(len + strlen(path) + 1); if (len) memcpy(sanitized, prefix, len); strcpy(sanitized + len, path); @@ -411,6 +414,15 @@ static const char *setup_discovered_git_dir(const char *gitdir, if (check_repository_format_gently(gitdir, nongit_ok)) return NULL; + /* --work-tree is set without --git-dir; use discovered one */ + if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) { + if (offset != len && !is_absolute_path(gitdir)) + gitdir = xstrdup(make_absolute_path(gitdir)); + if (chdir(cwd)) + die_errno("Could not come back to cwd"); + return setup_explicit_git_dir(gitdir, cwd, len, nongit_ok); + } + /* #16.2, #17.2, #20.2, #21.2, #24, #25, #28, #29 (see t1510) */ if (is_bare_repository_cfg > 0) { set_git_dir(offset == len ? gitdir : make_absolute_path(gitdir)); @@ -443,6 +455,16 @@ static const char *setup_bare_git_dir(char *cwd, int offset, int len, int *nongi if (check_repository_format_gently(".", nongit_ok)) return NULL; + /* --work-tree is set without --git-dir; use discovered one */ + if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) { + const char *gitdir; + + gitdir = offset == len ? "." : xmemdupz(cwd, offset); + if (chdir(cwd)) + die_errno("Could not come back to cwd"); + return setup_explicit_git_dir(gitdir, cwd, len, nongit_ok); + } + inside_git_dir = 1; inside_work_tree = 0; if (offset != len) { diff --git a/sha1_file.c b/sha1_file.c index 1cafdfa61..d949b35c3 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -13,6 +13,7 @@ #include "commit.h" #include "tag.h" #include "tree.h" +#include "tree-walk.h" #include "refs.h" #include "pack-revindex.h" #include "sha1-lookup.h" @@ -37,6 +38,41 @@ const unsigned char null_sha1[20]; static int git_open_noatime(const char *name, struct packed_git *p); +/* + * This is meant to hold a *small* number of objects that you would + * want read_sha1_file() to be able to return, but yet you do not want + * to write them into the object store (e.g. a browse-only + * application). + */ +static struct cached_object { + unsigned char sha1[20]; + enum object_type type; + void *buf; + unsigned long size; +} *cached_objects; +static int cached_object_nr, cached_object_alloc; + +static struct cached_object empty_tree = { + EMPTY_TREE_SHA1_BIN_LITERAL, + OBJ_TREE, + "", + 0 +}; + +static struct cached_object *find_cached_object(const unsigned char *sha1) +{ + int i; + struct cached_object *co = cached_objects; + + for (i = 0; i < cached_object_nr; i++, co++) { + if (!hashcmp(co->sha1, sha1)) + return co; + } + if (!hashcmp(sha1, empty_tree.sha1)) + return &empty_tree; + return NULL; +} + int safe_create_leading_directories(char *path) { char *pos = path + offset_1st_component(path); @@ -1985,9 +2021,17 @@ static int sha1_loose_object_info(const unsigned char *sha1, unsigned long *size int sha1_object_info(const unsigned char *sha1, unsigned long *sizep) { + struct cached_object *co; struct pack_entry e; int status; + co = find_cached_object(sha1); + if (co) { + if (sizep) + *sizep = co->size; + return co->type; + } + if (!find_pack_entry(sha1, &e)) { /* Most likely it's a loose object. */ status = sha1_loose_object_info(sha1, sizep); @@ -2033,41 +2077,6 @@ static void *read_packed_sha1(const unsigned char *sha1, return data; } -/* - * This is meant to hold a *small* number of objects that you would - * want read_sha1_file() to be able to return, but yet you do not want - * to write them into the object store (e.g. a browse-only - * application). - */ -static struct cached_object { - unsigned char sha1[20]; - enum object_type type; - void *buf; - unsigned long size; -} *cached_objects; -static int cached_object_nr, cached_object_alloc; - -static struct cached_object empty_tree = { - EMPTY_TREE_SHA1_BIN, - OBJ_TREE, - "", - 0 -}; - -static struct cached_object *find_cached_object(const unsigned char *sha1) -{ - int i; - struct cached_object *co = cached_objects; - - for (i = 0; i < cached_object_nr; i++, co++) { - if (!hashcmp(co->sha1, sha1)) - return co; - } - if (!hashcmp(sha1, empty_tree.sha1)) - return &empty_tree; - return NULL; -} - int pretend_sha1_file(void *buf, unsigned long len, enum object_type type, unsigned char *sha1) { @@ -2141,7 +2150,7 @@ void *read_sha1_file_repl(const unsigned char *sha1, return data; } - if (errno != ENOENT) + if (errno && errno != ENOENT) die_errno("failed to read object %s", sha1_to_hex(sha1)); /* die if we replaced an object with one that does not exist */ @@ -2471,8 +2480,37 @@ int has_sha1_file(const unsigned char *sha1) return has_loose_object(sha1); } +static void check_tree(const void *buf, size_t size) +{ + struct tree_desc desc; + struct name_entry entry; + + init_tree_desc(&desc, buf, size); + while (tree_entry(&desc, &entry)) + /* do nothing + * tree_entry() will die() on malformed entries */ + ; +} + +static void check_commit(const void *buf, size_t size) +{ + struct commit c; + memset(&c, 0, sizeof(c)); + if (parse_commit_buffer(&c, buf, size)) + die("corrupt commit"); +} + +static void check_tag(const void *buf, size_t size) +{ + struct tag t; + memset(&t, 0, sizeof(t)); + if (parse_tag_buffer(&t, buf, size)) + die("corrupt tag"); +} + static int index_mem(unsigned char *sha1, void *buf, size_t size, - int write_object, enum object_type type, const char *path) + int write_object, enum object_type type, + const char *path, int format_check) { int ret, re_allocated = 0; @@ -2490,6 +2528,14 @@ static int index_mem(unsigned char *sha1, void *buf, size_t size, re_allocated = 1; } } + if (format_check) { + if (type == OBJ_TREE) + check_tree(buf, size); + if (type == OBJ_COMMIT) + check_commit(buf, size); + if (type == OBJ_TAG) + check_tag(buf, size); + } if (write_object) ret = write_sha1_file(buf, size, typename(type), sha1); @@ -2503,7 +2549,7 @@ static int index_mem(unsigned char *sha1, void *buf, size_t size, #define SMALL_FILE_SIZE (32*1024) int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, - enum object_type type, const char *path) + enum object_type type, const char *path, int format_check) { int ret; size_t size = xsize_t(st->st_size); @@ -2512,23 +2558,25 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, struct strbuf sbuf = STRBUF_INIT; if (strbuf_read(&sbuf, fd, 4096) >= 0) ret = index_mem(sha1, sbuf.buf, sbuf.len, write_object, - type, path); + type, path, format_check); else ret = -1; strbuf_release(&sbuf); } else if (!size) { - ret = index_mem(sha1, NULL, size, write_object, type, path); + ret = index_mem(sha1, NULL, size, write_object, type, path, + format_check); } else if (size <= SMALL_FILE_SIZE) { char *buf = xmalloc(size); if (size == read_in_full(fd, buf, size)) ret = index_mem(sha1, buf, size, write_object, type, - path); + path, format_check); else ret = error("short read %s", strerror(errno)); free(buf); } else { void *buf = xmmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); - ret = index_mem(sha1, buf, size, write_object, type, path); + ret = index_mem(sha1, buf, size, write_object, type, path, + format_check); munmap(buf, size); } close(fd); @@ -2546,7 +2594,7 @@ int index_path(unsigned char *sha1, const char *path, struct stat *st, int write if (fd < 0) return error("open(\"%s\"): %s", path, strerror(errno)); - if (index_fd(sha1, fd, st, write_object, OBJ_BLOB, path) < 0) + if (index_fd(sha1, fd, st, write_object, OBJ_BLOB, path, 0) < 0) return error("%s: failed to insert into database", path); break; @@ -63,7 +63,8 @@ void strbuf_attach(struct strbuf *sb, void *buf, size_t len, size_t alloc) void strbuf_grow(struct strbuf *sb, size_t extra) { - if (sb->len + extra + 1 <= sb->len) + if (unsigned_add_overflows(extra, 1) || + unsigned_add_overflows(sb->len, extra + 1)) die("you want to use way too much memory"); if (!sb->alloc) sb->buf = NULL; @@ -152,7 +153,7 @@ int strbuf_cmp(const struct strbuf *a, const struct strbuf *b) void strbuf_splice(struct strbuf *sb, size_t pos, size_t len, const void *data, size_t dlen) { - if (pos + len < pos) + if (unsigned_add_overflows(pos, len)) die("you want to use way too much memory"); if (pos > sb->len) die("`pos' is too far after the end of the buffer"); diff --git a/string-list.c b/string-list.c index 9b023a258..51681189e 100644 --- a/string-list.c +++ b/string-list.c @@ -153,6 +153,7 @@ struct string_list_item *string_list_append(struct string_list *list, const char ALLOC_GROW(list->items, list->nr + 1, list->alloc); list->items[list->nr].string = list->strdup_strings ? xstrdup(string) : (char *)string; + list->items[list->nr].util = NULL; return list->items + list->nr++; } @@ -283,6 +283,12 @@ Do: Tests that are likely to smoke out future regressions are better than tests that just inflate the coverage metrics. + - When a test checks for an absolute path that a git command generated, + construct the expected value using $(pwd) rather than $PWD, + $TEST_DIRECTORY, or $TRASH_DIRECTORY. It makes a difference on + Windows, where the shell (MSYS bash) mangles absolute path names. + For details, see the commit message of 4114156ae9. + Don't: - exit() within a <script> part. diff --git a/t/gitweb-lib.sh b/t/gitweb-lib.sh index b9bb95fea..143eb1f24 100644 --- a/t/gitweb-lib.sh +++ b/t/gitweb-lib.sh @@ -82,7 +82,12 @@ gitweb_run () { } close O; ' gitweb.output && - if grep '^[[]' gitweb.log >/dev/null 2>&1; then false; else true; fi + if grep '^[[]' gitweb.log >/dev/null 2>&1; then + test_debug 'cat gitweb.log >&2' && + false + else + true + fi # gitweb.log is left for debugging # gitweb.output is used to parse HTTP output diff --git a/t/lib-git-svn.sh b/t/lib-git-svn.sh index 6a9d97572..199f22c23 100644 --- a/t/lib-git-svn.sh +++ b/t/lib-git-svn.sh @@ -68,8 +68,7 @@ svn_cmd () { svn "$orig_svncmd" --config-dir "$svnconf" "$@" } -if test -n "$SVN_HTTPD_PORT" -then +prepare_httpd () { for d in \ "$SVN_HTTPD_PATH" \ /usr/sbin/apache2 \ @@ -83,8 +82,8 @@ then done if test -z "$SVN_HTTPD_PATH" then - skip_all='skipping git svn tests, Apache not found' - test_done + echo >&2 '*** error: Apache not found' + return 1 fi for d in \ "$SVN_HTTPD_MODULE_PATH" \ @@ -99,23 +98,16 @@ then done if test -z "$SVN_HTTPD_MODULE_PATH" then - skip_all='skipping git svn tests, Apache module dir not found' - test_done - fi -fi - -start_httpd () { - repo_base_path="$1" - if test -z "$SVN_HTTPD_PORT" - then - echo >&2 'SVN_HTTPD_PORT is not defined!' - return + echo >&2 '*** error: Apache module dir not found' + return 1 fi - if test -z "$repo_base_path" + if test ! -f "$SVN_HTTPD_MODULE_PATH/mod_dav_svn.so" then - repo_base_path=svn + echo >&2 '*** error: Apache module "mod_dav_svn" not found' + return 1 fi + repo_base_path="${1-svn}" mkdir "$GIT_DIR"/logs cat > "$GIT_DIR/httpd.conf" <<EOF @@ -132,12 +124,24 @@ LoadModule dav_svn_module $SVN_HTTPD_MODULE_PATH/mod_dav_svn.so SVNPath "$rawsvnrepo" </Location> EOF +} + +start_httpd () { + if test -z "$SVN_HTTPD_PORT" + then + echo >&2 'SVN_HTTPD_PORT is not defined!' + return + fi + + prepare_httpd "$1" || return 1 + "$SVN_HTTPD_PATH" -f "$GIT_DIR"/httpd.conf -k start svnrepo="http://127.0.0.1:$SVN_HTTPD_PORT/$repo_base_path" } stop_httpd () { test -z "$SVN_HTTPD_PORT" && return + test ! -f "$GIT_DIR/httpd.conf" && return "$SVN_HTTPD_PATH" -f "$GIT_DIR"/httpd.conf -k stop } diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh index 2f7002a5e..8deec75c3 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -80,11 +80,11 @@ EOF chmod +x passing-todo.sh && ./passing-todo.sh >out 2>err && ! test -s err && -cat >expect <<EOF && -ok 1 - pretend we have fixed a known breakage # TODO known breakage -# fixed 1 known breakage(s) -# passed all 1 test(s) -1..1 +sed -e 's/^> //' >expect <<EOF && +> ok 1 - pretend we have fixed a known breakage # TODO known breakage +> # fixed 1 known breakage(s) +> # passed all 1 test(s) +> 1..1 EOF test_cmp expect out) " @@ -164,19 +164,19 @@ EOF test_must_fail ./failing-cleanup.sh >out 2>err && ! test -s err && ! test -f \"trash directory.failing-cleanup/clean-after-failure\" && -sed -e 's/Z$//' >expect <<\EOF && -not ok - 1 tests clean up even after a failure -# Z -# touch clean-after-failure && -# test_when_finished rm clean-after-failure && -# (exit 1) -# Z -not ok - 2 failure to clean up causes the test to fail -# Z -# test_when_finished \"(exit 2)\" -# Z -# failed 2 among 2 test(s) -1..2 +sed -e 's/Z$//' -e 's/^> //' >expect <<\EOF && +> not ok - 1 tests clean up even after a failure +> # Z +> # touch clean-after-failure && +> # test_when_finished rm clean-after-failure && +> # (exit 1) +> # Z +> not ok - 2 failure to clean up causes the test to fail +> # Z +> # test_when_finished \"(exit 2)\" +> # Z +> # failed 2 among 2 test(s) +> 1..2 EOF test_cmp expect out) " diff --git a/t/t0001-init.sh b/t/t0001-init.sh index af8b9c52a..f68499321 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -35,7 +35,7 @@ test_expect_success 'plain' ' test_expect_success 'plain nested in bare' ' ( - unset GIT_DIR GIT_WORK_TREE && + sane_unset GIT_DIR GIT_WORK_TREE && git init --bare bare-ancestor.git && cd bare-ancestor.git && mkdir plain-nested && @@ -47,7 +47,7 @@ test_expect_success 'plain nested in bare' ' test_expect_success 'plain through aliased command, outside any git repo' ' ( - unset GIT_DIR GIT_WORK_TREE GIT_CONFIG_NOGLOBAL && + sane_unset GIT_DIR GIT_WORK_TREE GIT_CONFIG_NOGLOBAL && HOME=$(pwd)/alias-config && export HOME && mkdir alias-config && @@ -65,7 +65,7 @@ test_expect_success 'plain through aliased command, outside any git repo' ' test_expect_failure 'plain nested through aliased command' ' ( - unset GIT_DIR GIT_WORK_TREE && + sane_unset GIT_DIR GIT_WORK_TREE && git init plain-ancestor-aliased && cd plain-ancestor-aliased && echo "[alias] aliasedinit = init" >>.git/config && @@ -78,7 +78,7 @@ test_expect_failure 'plain nested through aliased command' ' test_expect_failure 'plain nested in bare through aliased command' ' ( - unset GIT_DIR GIT_WORK_TREE && + sane_unset GIT_DIR GIT_WORK_TREE && git init --bare bare-ancestor-aliased.git && cd bare-ancestor-aliased.git && echo "[alias] aliasedinit = init" >>config && diff --git a/t/t0070-fundamental.sh b/t/t0070-fundamental.sh index 680d7d686..9bee8bfd2 100755 --- a/t/t0070-fundamental.sh +++ b/t/t0070-fundamental.sh @@ -12,4 +12,17 @@ test_expect_success 'character classes (isspace, isalpha etc.)' ' test-ctype ' +test_expect_success 'mktemp to nonexistent directory prints filename' ' + test_must_fail test-mktemp doesnotexist/testXXXXXX 2>err && + grep "doesnotexist/test" err +' + +test_expect_success POSIXPERM 'mktemp to unwritable directory prints filename' ' + mkdir cannotwrite && + chmod -w cannotwrite && + test_when_finished "chmod +w cannotwrite" && + test_must_fail test-mktemp cannotwrite/testXXXXXX 2>err && + grep "cannotwrite/test" err +' + test_done diff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh index dd32432d6..6d52b824b 100755 --- a/t/t1007-hash-object.sh +++ b/t/t1007-hash-object.sh @@ -188,4 +188,17 @@ for args in "-w --stdin-paths" "--stdin-paths -w"; do pop_repo done +test_expect_success 'corrupt tree' ' + echo abc >malformed-tree + test_must_fail git hash-object -t tree malformed-tree +' + +test_expect_success 'corrupt commit' ' + test_must_fail git hash-object -t commit --stdin </dev/null +' + +test_expect_success 'corrupt tag' ' + test_must_fail git hash-object -t tag --stdin </dev/null +' + test_done diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh index f072a8ed4..da6252b11 100755 --- a/t/t1501-worktree.sh +++ b/t/t1501-worktree.sh @@ -343,7 +343,7 @@ test_expect_success 'make_relative_path handles double slashes in GIT_DIR' ' test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' ' GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work \ test-subprocess --setup-work-tree rev-parse --show-toplevel >actual && - echo "$TRASH_DIRECTORY/repo.git/work" >expected && + echo "$(pwd)/repo.git/work" >expected && test_cmp expected actual ' diff --git a/t/t1510-repo-setup.sh b/t/t1510-repo-setup.sh index 500ffafc2..15101d5e0 100755 --- a/t/t1510-repo-setup.sh +++ b/t/t1510-repo-setup.sh @@ -1,4532 +1,776 @@ #!/bin/sh -test_description='Tests of cwd/prefix/worktree/gitdir setup in all cases' +test_description="Tests of cwd/prefix/worktree/gitdir setup in all cases -. ./test-lib.sh - -# -# A few rules for repo setup: -# -# 1. GIT_DIR is relative to user's cwd. --git-dir is equivalent to -# GIT_DIR. -# -# 2. .git file is relative to parent directory. .git file is basically -# symlink in disguise. The directory where .git file points to will -# become new git_dir. -# -# 3. core.worktree is relative to git_dir. -# -# 4. GIT_WORK_TREE is relative to user's cwd. --work-tree is -# equivalent to GIT_WORK_TREE. -# -# 5. GIT_WORK_TREE/core.worktree is only effective if GIT_DIR is set -# Uneffective worktree settings should be warned. -# -# 6. Effective GIT_WORK_TREE overrides core.worktree and core.bare -# -# 7. Effective core.worktree conflicts with core.bare -# -# 8. If GIT_DIR is set but neither worktree nor bare setting is given, -# original cwd becomes worktree. -# -# 9. If .git discovery is done inside a repo, the repo becomes a bare -# repo. .git discovery is performed if GIT_DIR is not set. -# -# 10. If no worktree is available, cwd remains unchanged, prefix is -# NULL. -# -# 11. When user's cwd is outside worktree, cwd remains unchanged, -# prefix is NULL. -# - -test_repo() { - ( - cd "$1" && - if test -n "$2"; then GIT_DIR="$2" && export GIT_DIR; fi && - if test -n "$3"; then GIT_WORK_TREE="$3" && export GIT_WORK_TREE; fi && - rm -f trace && - GIT_TRACE="`pwd`/trace" git symbolic-ref HEAD >/dev/null && - grep '^setup: ' trace >result && - test_cmp expected result - ) -} - -# Bit 0 = GIT_WORK_TREE -# Bit 1 = GIT_DIR -# Bit 2 = core.worktree -# Bit 3 = .git is a file -# Bit 4 = bare repo -# Case# = encoding of the above 5 bits - -# -# Case #0 -# -############################################################ -# -# Input: -# -# - GIT_WORK_TREE is not set -# - GIT_DIR is not set -# - core.worktree is not set -# - .git is a directory -# - core.bare is not set, cwd is outside .git -# -# Output: -# -# - worktree is .git's parent directory -# - cwd is at worktree root dir -# - prefix is calculated -# - git_dir is set to ".git" -# - cwd can't be outside worktree - -test_expect_success '#0: setup' ' - unset GIT_DIR GIT_WORK_TREE && - mkdir 0 0/sub && - cd 0 && git init && cd .. -' - -test_expect_success '#0: at root' ' - cat >0/expected <<EOF && -setup: git_dir: .git -setup: worktree: $TRASH_DIRECTORY/0 -setup: cwd: $TRASH_DIRECTORY/0 -setup: prefix: (null) -EOF - test_repo 0 -' - -test_expect_success '#0: in subdir' ' - cat >0/sub/expected <<EOF && -setup: git_dir: .git -setup: worktree: $TRASH_DIRECTORY/0 -setup: cwd: $TRASH_DIRECTORY/0 -setup: prefix: sub/ -EOF - test_repo 0/sub -' - -# -# case #1 -# -############################################################ -# -# Input: -# -# - GIT_WORK_TREE is set -# - GIT_DIR is not set -# - core.worktree is not set -# - .git is a directory -# - core.bare is not set, cwd is outside .git -# -# Output: -# -# GIT_WORK_TREE is ignored -> #0 - -test_expect_success '#1: setup' ' - unset GIT_DIR GIT_WORK_TREE && - mkdir 1 1/sub 1.wt 1.wt/sub 1/wt 1/wt/sub && - cd 1 && - git init && - GIT_WORK_TREE=non-existent && - export GIT_WORK_TREE && - cd .. -' - -test_expect_success '#1: at root' ' - cat >1/expected <<EOF && -setup: git_dir: .git -setup: worktree: $TRASH_DIRECTORY/1 -setup: cwd: $TRASH_DIRECTORY/1 -setup: prefix: (null) -EOF - test_repo 1 -' - -test_expect_success '#1: in subdir' ' - cat >1/sub/expected <<EOF && -setup: git_dir: .git -setup: worktree: $TRASH_DIRECTORY/1 -setup: cwd: $TRASH_DIRECTORY/1 -setup: prefix: sub/ -EOF - test_repo 1/sub -' - -# -# case #2 -# -############################################################ -# -# Input: -# -# - GIT_WORK_TREE is not set -# - GIT_DIR is set -# - core.worktree is not set -# - .git is a directory -# - core.bare is not set, cwd is outside .git -# -# Output: -# -# - worktree is at original cwd -# - cwd is unchanged -# - prefix is NULL -# - git_dir is set to $GIT_DIR -# - cwd can't be outside worktree - -test_expect_success '#2: setup' ' - unset GIT_DIR GIT_WORK_TREE && - mkdir 2 2/sub && - cd 2 && git init && cd .. -' - -test_expect_success '#2: at root' ' - cat >2/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/2/.git -setup: worktree: $TRASH_DIRECTORY/2 -setup: cwd: $TRASH_DIRECTORY/2 -setup: prefix: (null) -EOF - test_repo 2 "$TRASH_DIRECTORY/2/.git" -' - -test_expect_success '#2: in subdir' ' - cat >2/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/2/.git -setup: worktree: $TRASH_DIRECTORY/2/sub -setup: cwd: $TRASH_DIRECTORY/2/sub -setup: prefix: (null) -EOF - test_repo 2/sub "$TRASH_DIRECTORY/2/.git" -' - -test_expect_success '#2: relative GIT_DIR at root' ' - cat >2/expected <<EOF && -setup: git_dir: .git -setup: worktree: $TRASH_DIRECTORY/2 -setup: cwd: $TRASH_DIRECTORY/2 -setup: prefix: (null) -EOF - test_repo 2 .git -' - -test_expect_success '#2: relative GIT_DIR in subdir' ' - cat >2/sub/expected <<EOF && -setup: git_dir: ../.git -setup: worktree: $TRASH_DIRECTORY/2/sub -setup: cwd: $TRASH_DIRECTORY/2/sub -setup: prefix: (null) -EOF - test_repo 2/sub ../.git -' - -# -# case #3 -# -############################################################ -# -# Input: -# -# - GIT_WORK_TREE is set -# - GIT_DIR is set -# - core.worktree is not set -# - .git is a directory -# - core.bare is not set, cwd is outside .git -# -# Output: -# -# - worktree is set to $GIT_WORK_TREE -# - cwd is at worktree root -# - prefix is calculated -# - git_dir is set to $GIT_DIR -# - cwd can be outside worktree - -test_expect_success '#3: setup' ' - unset GIT_DIR GIT_WORK_TREE && - mkdir 3 3/sub 3/sub/sub 3.wt 3.wt/sub 3/wt 3/wt/sub && - cd 3 && git init && cd .. -' - -test_expect_success '#3: GIT_DIR(rel), GIT_WORK_TREE=root at root' ' - cat >3/expected <<EOF && -setup: git_dir: .git -setup: worktree: $TRASH_DIRECTORY/3 -setup: cwd: $TRASH_DIRECTORY/3 -setup: prefix: (null) -EOF - test_repo 3 .git "$TRASH_DIRECTORY/3" -' - -test_expect_success '#3: GIT_DIR(rel), GIT_WORK_TREE=root(rel) at root' ' - cat >3/expected <<EOF && -setup: git_dir: .git -setup: worktree: $TRASH_DIRECTORY/3 -setup: cwd: $TRASH_DIRECTORY/3 -setup: prefix: (null) -EOF - test_repo 3 .git . -' - -test_expect_success '#3: GIT_DIR, GIT_WORK_TREE=root at root' ' - cat >3/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/3/.git -setup: worktree: $TRASH_DIRECTORY/3 -setup: cwd: $TRASH_DIRECTORY/3 -setup: prefix: (null) -EOF - test_repo 3 "$TRASH_DIRECTORY/3/.git" "$TRASH_DIRECTORY/3" -' - -test_expect_success '#3: GIT_DIR, GIT_WORK_TREE=root(rel) at root' ' - cat >3/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/3/.git -setup: worktree: $TRASH_DIRECTORY/3 -setup: cwd: $TRASH_DIRECTORY/3 -setup: prefix: (null) -EOF - test_repo 3 "$TRASH_DIRECTORY/3/.git" . -' - -test_expect_success '#3: GIT_DIR(rel), GIT_WORKTREE=root in subdir' ' - cat >3/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/3/.git -setup: worktree: $TRASH_DIRECTORY/3 -setup: cwd: $TRASH_DIRECTORY/3 -setup: prefix: sub/sub/ -EOF - test_repo 3/sub/sub ../../.git "$TRASH_DIRECTORY/3" -' - -test_expect_success '#3: GIT_DIR(rel), GIT_WORKTREE=root(rel) in subdir' ' - cat >3/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/3/.git -setup: worktree: $TRASH_DIRECTORY/3 -setup: cwd: $TRASH_DIRECTORY/3 -setup: prefix: sub/sub/ -EOF - test_repo 3/sub/sub ../../.git ../.. -' - -test_expect_success '#3: GIT_DIR, GIT_WORKTREE=root in subdir' ' - cat >3/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/3/.git -setup: worktree: $TRASH_DIRECTORY/3 -setup: cwd: $TRASH_DIRECTORY/3 -setup: prefix: sub/ -EOF - test_repo 3/sub "$TRASH_DIRECTORY/3/.git" "$TRASH_DIRECTORY/3" -' - -test_expect_success '#3: GIT_DIR, GIT_WORKTREE=root(rel) in subdir' ' - cat >3/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/3/.git -setup: worktree: $TRASH_DIRECTORY/3 -setup: cwd: $TRASH_DIRECTORY/3 -setup: prefix: sub/sub/ -EOF - test_repo 3/sub/sub "$TRASH_DIRECTORY/3/.git" ../.. -' - -test_expect_success '#3: GIT_DIR(rel), GIT_WORK_TREE=wt at root' ' - cat >3/expected <<EOF && -setup: git_dir: .git -setup: worktree: $TRASH_DIRECTORY/3/wt -setup: cwd: $TRASH_DIRECTORY/3 -setup: prefix: (null) -EOF - test_repo 3 .git "$TRASH_DIRECTORY/3/wt" -' - -test_expect_success '#3: GIT_DIR(rel), GIT_WORK_TREE=wt(rel) at root' ' - cat >3/expected <<EOF && -setup: git_dir: .git -setup: worktree: $TRASH_DIRECTORY/3/wt -setup: cwd: $TRASH_DIRECTORY/3 -setup: prefix: (null) -EOF - test_repo 3 .git wt -' - -test_expect_success '#3: GIT_DIR, GIT_WORK_TREE=wt(rel) at root' ' - cat >3/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/3/.git -setup: worktree: $TRASH_DIRECTORY/3/wt -setup: cwd: $TRASH_DIRECTORY/3 -setup: prefix: (null) -EOF - test_repo 3 "$TRASH_DIRECTORY/3/.git" wt -' - -test_expect_success '#3: GIT_DIR, GIT_WORK_TREE=wt at root' ' - cat >3/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/3/.git -setup: worktree: $TRASH_DIRECTORY/3/wt -setup: cwd: $TRASH_DIRECTORY/3 -setup: prefix: (null) -EOF - test_repo 3 "$TRASH_DIRECTORY/3/.git" "$TRASH_DIRECTORY/3/wt" -' - -test_expect_success '#3: GIT_DIR(rel), GIT_WORK_TREE=wt in subdir' ' - cat >3/sub/sub/expected <<EOF && -setup: git_dir: ../../.git -setup: worktree: $TRASH_DIRECTORY/3/wt -setup: cwd: $TRASH_DIRECTORY/3/sub/sub -setup: prefix: (null) -EOF - test_repo 3/sub/sub ../../.git "$TRASH_DIRECTORY/3/wt" -' - -test_expect_success '#3: GIT_DIR(rel), GIT_WORK_TREE=wt(rel) in subdir' ' - cat >3/sub/sub/expected <<EOF && -setup: git_dir: ../../.git -setup: worktree: $TRASH_DIRECTORY/3/wt -setup: cwd: $TRASH_DIRECTORY/3/sub/sub -setup: prefix: (null) -EOF - test_repo 3/sub/sub ../../.git ../../wt -' - -test_expect_success '#3: GIT_DIR, GIT_WORK_TREE=wt(rel) in subdir' ' - cat >3/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/3/.git -setup: worktree: $TRASH_DIRECTORY/3/wt -setup: cwd: $TRASH_DIRECTORY/3/sub/sub -setup: prefix: (null) -EOF - test_repo 3/sub/sub "$TRASH_DIRECTORY/3/.git" ../../wt -' - -test_expect_success '#3: GIT_DIR, GIT_WORK_TREE=wt in subdir' ' - cat >3/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/3/.git -setup: worktree: $TRASH_DIRECTORY/3/wt -setup: cwd: $TRASH_DIRECTORY/3/sub/sub -setup: prefix: (null) -EOF - test_repo 3/sub/sub "$TRASH_DIRECTORY/3/.git" "$TRASH_DIRECTORY/3/wt" -' - -test_expect_success '#3: GIT_DIR(rel), GIT_WORK_TREE=.. at root' ' - cat >3/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/3/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 3/ -EOF - test_repo 3 .git "$TRASH_DIRECTORY" -' - -test_expect_success '#3: GIT_DIR(rel), GIT_WORK_TREE=..(rel) at root' ' - cat >3/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/3/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 3/ -EOF - test_repo 3 .git .. -' - -test_expect_success '#3: GIT_DIR, GIT_WORK_TREE=..(rel) at root' ' - cat >3/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/3/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 3/ -EOF - test_repo 3 "$TRASH_DIRECTORY/3/.git" .. -' - -test_expect_success '#3: GIT_DIR, GIT_WORK_TREE=.. at root' ' - cat >3/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/3/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 3/ -EOF - test_repo 3 "$TRASH_DIRECTORY/3/.git" "$TRASH_DIRECTORY" -' - -test_expect_success '#3: GIT_DIR(rel), GIT_WORK_TREE=.. in subdir' ' - cat >3/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/3/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 3/sub/sub/ -EOF - test_repo 3/sub/sub ../../.git "$TRASH_DIRECTORY" -' - -test_expect_success '#3: GIT_DIR(rel), GIT_WORK_TREE=..(rel) in subdir' ' - cat >3/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/3/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 3/sub/sub/ -EOF - test_repo 3/sub/sub ../../.git ../../.. -' - -test_expect_success '#3: GIT_DIR, GIT_WORK_TREE=..(rel) in subdir' ' - cat >3/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/3/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 3/sub/sub/ -EOF - test_repo 3/sub/sub "$TRASH_DIRECTORY/3/.git" ../../../ -' - -test_expect_success '#3: GIT_DIR, GIT_WORK_TREE=.. in subdir' ' - cat >3/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/3/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 3/sub/sub/ -EOF - test_repo 3/sub/sub "$TRASH_DIRECTORY/3/.git" "$TRASH_DIRECTORY" -' - -# -# case #4 -# -############################################################ -# -# Input: -# -# - GIT_WORK_TREE is not set -# - GIT_DIR is not set -# - core.worktree is set -# - .git is a directory -# - core.bare is not set, cwd is outside .git -# -# Output: -# -# core.worktree is ignored -> #0 - -test_expect_success '#4: setup' ' - unset GIT_DIR GIT_WORK_TREE && - mkdir 4 4/sub && - cd 4 && - git init && - git config core.worktree non-existent && - cd .. -' - -test_expect_success '#4: at root' ' - cat >4/expected <<EOF && -setup: git_dir: .git -setup: worktree: $TRASH_DIRECTORY/4 -setup: cwd: $TRASH_DIRECTORY/4 -setup: prefix: (null) -EOF - test_repo 4 -' - -test_expect_success '#4: in subdir' ' - cat >4/sub/expected <<EOF && -setup: git_dir: .git -setup: worktree: $TRASH_DIRECTORY/4 -setup: cwd: $TRASH_DIRECTORY/4 -setup: prefix: sub/ -EOF - test_repo 4/sub -' - -# -# case #5 -# -############################################################ -# -# Input: -# -# - GIT_WORK_TREE is set -# - GIT_DIR is not set -# - core.worktree is set -# - .git is a directory -# - core.bare is not set, cwd is outside .git -# -# Output: -# -# GIT_WORK_TREE/core.worktree are ignored -> #0 - -test_expect_success '#5: setup' ' - unset GIT_DIR GIT_WORK_TREE && - mkdir 5 5/sub && - cd 5 && - git init && - git config core.worktree non-existent && - GIT_WORK_TREE=non-existent-too && - export GIT_WORK_TREE && - cd .. -' +A few rules for repo setup: -test_expect_success '#5: at root' ' - cat >5/expected <<EOF && -setup: git_dir: .git -setup: worktree: $TRASH_DIRECTORY/5 -setup: cwd: $TRASH_DIRECTORY/5 -setup: prefix: (null) -EOF - test_repo 5 -' +1. GIT_DIR is relative to user's cwd. --git-dir is equivalent to + GIT_DIR. -test_expect_success '#5: in subdir' ' - cat >5/sub/expected <<EOF && -setup: git_dir: .git -setup: worktree: $TRASH_DIRECTORY/5 -setup: cwd: $TRASH_DIRECTORY/5 -setup: prefix: sub/ -EOF - test_repo 5/sub -' +2. .git file is relative to parent directory. .git file is basically + symlink in disguise. The directory where .git file points to will + become new git_dir. -# -# case #6 -# -############################################################ -# -# Input: -# -# - GIT_WORK_TREE is not set -# - GIT_DIR is set -# - core.worktree is set -# - .git is a directory -# - core.bare is not set, cwd is outside .git -# -# Output: -# -# - worktree is at core.worktree -# - cwd is at worktree root -# - prefix is calculated -# - git_dir is at $GIT_DIR -# - cwd can be outside worktree +3. core.worktree is relative to git_dir. -test_expect_success '#6: setup' ' - unset GIT_DIR GIT_WORK_TREE && - mkdir 6 6/sub 6/sub/sub 6.wt 6.wt/sub 6/wt 6/wt/sub && - cd 6 && git init && cd .. -' +4. GIT_WORK_TREE is relative to user's cwd. --work-tree is + equivalent to GIT_WORK_TREE. -test_expect_success '#6: GIT_DIR(rel), core.worktree=.. at root' ' - cat >6/expected <<EOF && -setup: git_dir: .git -setup: worktree: $TRASH_DIRECTORY/6 -setup: cwd: $TRASH_DIRECTORY/6 -setup: prefix: (null) -EOF - git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree "$TRASH_DIRECTORY/6" && - test_repo 6 .git -' +5. GIT_WORK_TREE/core.worktree was originally meant to work only if + GIT_DIR is set, but earlier git didn't enforce it, and some scripts + depend on the implementation that happened to first discover .git by + going up from the users $cwd and then using the specified working tree + that may or may not have any relation to where .git was found in. This + historical behaviour must be kept. -test_expect_success '#6: GIT_DIR(rel), core.worktree=..(rel) at root' ' - cat >6/expected <<EOF && -setup: git_dir: .git -setup: worktree: $TRASH_DIRECTORY/6 -setup: cwd: $TRASH_DIRECTORY/6 -setup: prefix: (null) -EOF - git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree .. && - test_repo 6 .git -' +6. Effective GIT_WORK_TREE overrides core.worktree and core.bare -test_expect_success '#6: GIT_DIR, core.worktree=.. at root' ' - cat >6/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/6/.git -setup: worktree: $TRASH_DIRECTORY/6 -setup: cwd: $TRASH_DIRECTORY/6 -setup: prefix: (null) -EOF - git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree "$TRASH_DIRECTORY/6" && - test_repo 6 "$TRASH_DIRECTORY/6/.git" -' +7. Effective core.worktree conflicts with core.bare -test_expect_success '#6: GIT_DIR, core.worktree=..(rel) at root' ' - cat >6/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/6/.git -setup: worktree: $TRASH_DIRECTORY/6 -setup: cwd: $TRASH_DIRECTORY/6 -setup: prefix: (null) -EOF - git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree .. && - test_repo 6 "$TRASH_DIRECTORY/6/.git" -' +8. If GIT_DIR is set but neither worktree nor bare setting is given, + original cwd becomes worktree. -test_expect_success '#6: GIT_DIR(rel), core.worktree=.. in subdir' ' - cat >6/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/6/.git -setup: worktree: $TRASH_DIRECTORY/6 -setup: cwd: $TRASH_DIRECTORY/6 -setup: prefix: sub/sub/ -EOF - git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree "$TRASH_DIRECTORY/6" && - test_repo 6/sub/sub ../../.git -' +9. If .git discovery is done inside a repo, the repo becomes a bare + repo. .git discovery is performed if GIT_DIR is not set. -test_expect_success '#6: GIT_DIR(rel), core.worktree=..(rel) in subdir' ' - cat >6/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/6/.git -setup: worktree: $TRASH_DIRECTORY/6 -setup: cwd: $TRASH_DIRECTORY/6 -setup: prefix: sub/sub/ -EOF - git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree .. && - test_repo 6/sub/sub ../../.git -' +10. If no worktree is available, cwd remains unchanged, prefix is + NULL. -test_expect_success '#6: GIT_DIR, core.worktree=.. in subdir' ' - cat >6/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/6/.git -setup: worktree: $TRASH_DIRECTORY/6 -setup: cwd: $TRASH_DIRECTORY/6 -setup: prefix: sub/ -EOF - git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree "$TRASH_DIRECTORY/6" && - test_repo 6/sub "$TRASH_DIRECTORY/6/.git" -' +11. When user's cwd is outside worktree, cwd remains unchanged, + prefix is NULL. +" +. ./test-lib.sh -test_expect_success '#6: GIT_DIR, core.worktree=..(rel) in subdir' ' - cat >6/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/6/.git -setup: worktree: $TRASH_DIRECTORY/6 -setup: cwd: $TRASH_DIRECTORY/6 -setup: prefix: sub/sub/ -EOF - git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree .. && - test_repo 6/sub/sub "$TRASH_DIRECTORY/6/.git" -' +here=$(pwd) -test_expect_success '#6: GIT_DIR(rel), core.worktree=../wt at root' ' - cat >6/expected <<EOF && -setup: git_dir: .git -setup: worktree: $TRASH_DIRECTORY/6/wt -setup: cwd: $TRASH_DIRECTORY/6 -setup: prefix: (null) -EOF - git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree "$TRASH_DIRECTORY/6/wt" && - test_repo 6 .git -' +test_repo () { + ( + cd "$1" && + if test -n "$2" + then + GIT_DIR="$2" && + export GIT_DIR + fi && + if test -n "$3" + then + GIT_WORK_TREE="$3" && + export GIT_WORK_TREE + fi && + rm -f trace && + GIT_TRACE="$(pwd)/trace" git symbolic-ref HEAD >/dev/null && + grep '^setup: ' trace >result && + test_cmp expected result + ) +} -test_expect_success '#6: GIT_DIR(rel), core.worktree=../wt(rel) at root' ' - cat >6/expected <<EOF && -setup: git_dir: .git -setup: worktree: $TRASH_DIRECTORY/6/wt -setup: cwd: $TRASH_DIRECTORY/6 -setup: prefix: (null) -EOF - git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree ../wt && - test_repo 6 .git -' +maybe_config () { + file=$1 var=$2 value=$3 && + if test "$value" != unset + then + git config --file="$file" "$var" "$value" + fi +} -test_expect_success '#6: GIT_DIR, core.worktree=../wt(rel) at root' ' - cat >6/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/6/.git -setup: worktree: $TRASH_DIRECTORY/6/wt -setup: cwd: $TRASH_DIRECTORY/6 -setup: prefix: (null) -EOF - git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree ../wt && - test_repo 6 "$TRASH_DIRECTORY/6/.git" -' +setup_repo () { + name=$1 worktreecfg=$2 gitfile=$3 barecfg=$4 && + sane_unset GIT_DIR GIT_WORK_TREE && -test_expect_success '#6: GIT_DIR, core.worktree=../wt at root' ' - cat >6/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/6/.git -setup: worktree: $TRASH_DIRECTORY/6/wt -setup: cwd: $TRASH_DIRECTORY/6 -setup: prefix: (null) -EOF - git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree "$TRASH_DIRECTORY/6/wt" && - test_repo 6 "$TRASH_DIRECTORY/6/.git" -' + git init "$name" && + maybe_config "$name/.git/config" core.worktree "$worktreecfg" && + maybe_config "$name/.git/config" core.bare "$barecfg" && + mkdir -p "$name/sub/sub" && -test_expect_success '#6: GIT_DIR(rel), core.worktree=../wt in subdir' ' - cat >6/sub/sub/expected <<EOF && -setup: git_dir: ../../.git -setup: worktree: $TRASH_DIRECTORY/6/wt -setup: cwd: $TRASH_DIRECTORY/6/sub/sub -setup: prefix: (null) -EOF - git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree "$TRASH_DIRECTORY/6/wt" && - test_repo 6/sub/sub ../../.git -' + if test "${gitfile:+set}" + then + mv "$name/.git" "$name.git" && + echo "gitdir: ../$name.git" >"$name/.git" + fi +} -test_expect_success '#6: GIT_DIR(rel), core.worktree=../wt(rel) in subdir' ' - cat >6/sub/sub/expected <<EOF && -setup: git_dir: ../../.git -setup: worktree: $TRASH_DIRECTORY/6/wt -setup: cwd: $TRASH_DIRECTORY/6/sub/sub -setup: prefix: (null) -EOF - git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree ../wt && - test_repo 6/sub/sub ../../.git -' +maybe_set () { + var=$1 value=$2 && + if test "$value" != unset + then + eval "$var=\$value" && + export $var + fi +} -test_expect_success '#6: GIT_DIR, core.worktree=../wt(rel) in subdir' ' - cat >6/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/6/.git -setup: worktree: $TRASH_DIRECTORY/6/wt -setup: cwd: $TRASH_DIRECTORY/6/sub/sub -setup: prefix: (null) -EOF - git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree ../wt && - test_repo 6/sub/sub "$TRASH_DIRECTORY/6/.git" -' +setup_env () { + worktreenv=$1 gitdirenv=$2 && + sane_unset GIT_DIR GIT_WORK_TREE && + maybe_set GIT_DIR "$gitdirenv" && + maybe_set GIT_WORK_TREE "$worktreeenv" +} -test_expect_success '#6: GIT_DIR, core.worktree=../wt in subdir' ' - cat >6/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/6/.git -setup: worktree: $TRASH_DIRECTORY/6/wt -setup: cwd: $TRASH_DIRECTORY/6/sub/sub -setup: prefix: (null) -EOF - git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree "$TRASH_DIRECTORY/6/wt" && - test_repo 6/sub/sub "$TRASH_DIRECTORY/6/.git" -' +expect () { + cat >"$1/expected" <<-EOF + setup: git_dir: $2 + setup: worktree: $3 + setup: cwd: $4 + setup: prefix: $5 + EOF +} -test_expect_success '#6: GIT_DIR(rel), core.worktree=../.. at root' ' - cat >6/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/6/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 6/ -EOF - git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree "$TRASH_DIRECTORY" && - test_repo 6 .git -' +try_case () { + name=$1 worktreeenv=$2 gitdirenv=$3 && + setup_env "$worktreeenv" "$gitdirenv" && + expect "$name" "$4" "$5" "$6" "$7" && + test_repo "$name" +} -test_expect_success '#6: GIT_DIR(rel), core.worktree=../..(rel) at root' ' - cat >6/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/6/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 6/ -EOF - git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree ../../ && - test_repo 6 .git -' +run_wt_tests () { + N=$1 gitfile=$2 + + absgit="$here/$N/.git" + dotgit=.git + dotdotgit=../../.git + + if test "$gitfile" + then + absgit="$here/$N.git" + dotgit=$absgit dotdotgit=$absgit + fi + + test_expect_success "#$N: explicit GIT_WORK_TREE and GIT_DIR at toplevel" ' + try_case $N "$here/$N" .git \ + "$dotgit" "$here/$N" "$here/$N" "(null)" && + try_case $N . .git \ + "$dotgit" "$here/$N" "$here/$N" "(null)" && + try_case $N "$here/$N" "$here/$N/.git" \ + "$absgit" "$here/$N" "$here/$N" "(null)" && + try_case $N . "$here/$N/.git" \ + "$absgit" "$here/$N" "$here/$N" "(null)" + ' + + test_expect_success "#$N: explicit GIT_WORK_TREE and GIT_DIR in subdir" ' + try_case $N/sub/sub "$here/$N" ../../.git \ + "$absgit" "$here/$N" "$here/$N" sub/sub/ && + try_case $N/sub/sub ../.. ../../.git \ + "$absgit" "$here/$N" "$here/$N" sub/sub/ && + try_case $N/sub/sub "$here/$N" "$here/$N/.git" \ + "$absgit" "$here/$N" "$here/$N" sub/sub/ && + try_case $N/sub/sub ../.. "$here/$N/.git" \ + "$absgit" "$here/$N" "$here/$N" sub/sub/ + ' + + test_expect_success "#$N: explicit GIT_WORK_TREE from parent of worktree" ' + try_case $N "$here/$N/wt" .git \ + "$dotgit" "$here/$N/wt" "$here/$N" "(null)" && + try_case $N wt .git \ + "$dotgit" "$here/$N/wt" "$here/$N" "(null)" && + try_case $N wt "$here/$N/.git" \ + "$absgit" "$here/$N/wt" "$here/$N" "(null)" && + try_case $N "$here/$N/wt" "$here/$N/.git" \ + "$absgit" "$here/$N/wt" "$here/$N" "(null)" + ' + + test_expect_success "#$N: explicit GIT_WORK_TREE from nephew of worktree" ' + try_case $N/sub/sub "$here/$N/wt" ../../.git \ + "$dotdotgit" "$here/$N/wt" "$here/$N/sub/sub" "(null)" && + try_case $N/sub/sub ../../wt ../../.git \ + "$dotdotgit" "$here/$N/wt" "$here/$N/sub/sub" "(null)" && + try_case $N/sub/sub ../../wt "$here/$N/.git" \ + "$absgit" "$here/$N/wt" "$here/$N/sub/sub" "(null)" && + try_case $N/sub/sub "$here/$N/wt" "$here/$N/.git" \ + "$absgit" "$here/$N/wt" "$here/$N/sub/sub" "(null)" + ' + + test_expect_success "#$N: chdir_to_toplevel uses worktree, not git dir" ' + try_case $N "$here" .git \ + "$absgit" "$here" "$here" $N/ && + try_case $N .. .git \ + "$absgit" "$here" "$here" $N/ && + try_case $N .. "$here/$N/.git" \ + "$absgit" "$here" "$here" $N/ && + try_case $N "$here" "$here/$N/.git" \ + "$absgit" "$here" "$here" $N/ + ' + + test_expect_success "#$N: chdir_to_toplevel uses worktree (from subdir)" ' + try_case $N/sub/sub "$here" ../../.git \ + "$absgit" "$here" "$here" $N/sub/sub/ && + try_case $N/sub/sub ../../.. ../../.git \ + "$absgit" "$here" "$here" $N/sub/sub/ && + try_case $N/sub/sub ../../../ "$here/$N/.git" \ + "$absgit" "$here" "$here" $N/sub/sub/ && + try_case $N/sub/sub "$here" "$here/$N/.git" \ + "$absgit" "$here" "$here" $N/sub/sub/ + ' +} -test_expect_success '#6: GIT_DIR, core.worktree=../..(rel) at root' ' - cat >6/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/6/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 6/ -EOF - git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree ../../ && - test_repo 6 "$TRASH_DIRECTORY/6/.git" -' +# try_repo #c GIT_WORK_TREE GIT_DIR core.worktree .gitfile? core.bare \ +# (git dir) (work tree) (cwd) (prefix) \ <-- at toplevel +# (git dir) (work tree) (cwd) (prefix) <-- from subdir +try_repo () { + name=$1 worktreeenv=$2 gitdirenv=$3 && + setup_repo "$name" "$4" "$5" "$6" && + shift 6 && + try_case "$name" "$worktreeenv" "$gitdirenv" \ + "$1" "$2" "$3" "$4" && + shift 4 && + case "$gitdirenv" in + /* | ?:/* | unset) ;; + *) + gitdirenv=../$gitdirenv ;; + esac && + try_case "$name/sub" "$worktreeenv" "$gitdirenv" \ + "$1" "$2" "$3" "$4" +} -test_expect_success '#6: GIT_DIR, core.worktree=../.. at root' ' - cat >6/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/6/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 6/ -EOF - git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree "$TRASH_DIRECTORY" && - test_repo 6 "$TRASH_DIRECTORY/6/.git" -' +# Bit 0 = GIT_WORK_TREE +# Bit 1 = GIT_DIR +# Bit 2 = core.worktree +# Bit 3 = .git is a file +# Bit 4 = bare repo +# Case# = encoding of the above 5 bits -test_expect_success '#6: GIT_DIR(rel), core.worktree=../.. in subdir' ' - cat >6/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/6/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 6/sub/sub/ -EOF - git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree "$TRASH_DIRECTORY" && - test_repo 6/sub/sub ../../.git +test_expect_success '#0: nonbare repo, no explicit configuration' ' + try_repo 0 unset unset unset "" unset \ + .git "$here/0" "$here/0" "(null)" \ + .git "$here/0" "$here/0" sub/ 2>message && + ! test -s message ' -test_expect_success '#6: GIT_DIR(rel), core.worktree=../..(rel) in subdir' ' - cat >6/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/6/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 6/sub/sub/ -EOF - git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree ../.. && - test_repo 6/sub/sub ../../.git +test_expect_success '#1: GIT_WORK_TREE without explicit GIT_DIR is accepted' ' + mkdir -p wt && + try_repo 1 "$here" unset unset "" unset \ + "$here/1/.git" "$here" "$here" 1/ \ + "$here/1/.git" "$here" "$here" 1/sub/ 2>message && + ! test -s message ' -test_expect_success '#6: GIT_DIR, core.worktree=../..(rel) in subdir' ' - cat >6/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/6/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 6/sub/sub/ -EOF - git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree ../.. && - test_repo 6/sub/sub "$TRASH_DIRECTORY/6/.git" +test_expect_success '#2: worktree defaults to cwd with explicit GIT_DIR' ' + try_repo 2 unset "$here/2/.git" unset "" unset \ + "$here/2/.git" "$here/2" "$here/2" "(null)" \ + "$here/2/.git" "$here/2/sub" "$here/2/sub" "(null)" ' -test_expect_success '#6: GIT_DIR, core.worktree=../.. in subdir' ' - cat >6/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/6/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 6/sub/sub/ -EOF - git config --file="$TRASH_DIRECTORY/6/.git/config" core.worktree "$TRASH_DIRECTORY" && - test_repo 6/sub/sub "$TRASH_DIRECTORY/6/.git" +test_expect_success '#2b: relative GIT_DIR' ' + try_repo 2b unset ".git" unset "" unset \ + ".git" "$here/2b" "$here/2b" "(null)" \ + "../.git" "$here/2b/sub" "$here/2b/sub" "(null)" ' -# -# case #7 -# -############################################################ -# -# Input: -# -# - GIT_WORK_TREE is set -# - GIT_DIR is set -# - core.worktree is set -# - .git is a directory -# - core.bare is not set, cwd is outside .git -# -# Output: -# -# core.worktree is overridden by GIT_WORK_TREE -> #3 - +test_expect_success '#3: setup' ' + setup_repo 3 unset "" unset && + mkdir -p 3/sub/sub 3/wt/sub +' +run_wt_tests 3 + +test_expect_success '#4: core.worktree without GIT_DIR set is accepted' ' + setup_repo 4 ../sub "" unset && + mkdir -p 4/sub sub && + try_case 4 unset unset \ + .git "$here/4/sub" "$here/4" "(null)" \ + "$here/4/.git" "$here/4/sub" "$here/4/sub" "(null)" 2>message && + ! test -s message +' + +test_expect_success '#5: core.worktree + GIT_WORK_TREE is accepted' ' + # or: you cannot intimidate away the lack of GIT_DIR setting + try_repo 5 "$here" unset "$here/5" "" unset \ + "$here/5/.git" "$here" "$here" 5/ \ + "$here/5/.git" "$here" "$here" 5/sub/ 2>message && + try_repo 5a .. unset "$here/5a" "" unset \ + "$here/5a/.git" "$here" "$here" 5a/ \ + "$here/5a/.git" "$here/5a" "$here/5a" sub/ && + ! test -s message +' + +test_expect_success '#6: setting GIT_DIR brings core.worktree to life' ' + setup_repo 6 "$here/6" "" unset && + try_case 6 unset .git \ + .git "$here/6" "$here/6" "(null)" && + try_case 6 unset "$here/6/.git" \ + "$here/6/.git" "$here/6" "$here/6" "(null)" && + try_case 6/sub/sub unset ../../.git \ + "$here/6/.git" "$here/6" "$here/6" sub/sub/ && + try_case 6/sub/sub unset "$here/6/.git" \ + "$here/6/.git" "$here/6" "$here/6" sub/sub/ +' + +test_expect_success '#6b: GIT_DIR set, core.worktree relative' ' + setup_repo 6b .. "" unset && + try_case 6b unset .git \ + .git "$here/6b" "$here/6b" "(null)" && + try_case 6b unset "$here/6b/.git" \ + "$here/6b/.git" "$here/6b" "$here/6b" "(null)" && + try_case 6b/sub/sub unset ../../.git \ + "$here/6b/.git" "$here/6b" "$here/6b" sub/sub/ && + try_case 6b/sub/sub unset "$here/6b/.git" \ + "$here/6b/.git" "$here/6b" "$here/6b" sub/sub/ +' + +test_expect_success '#6c: GIT_DIR set, core.worktree=../wt (absolute)' ' + setup_repo 6c "$here/6c/wt" "" unset && + mkdir -p 6c/wt/sub && + + try_case 6c unset .git \ + .git "$here/6c/wt" "$here/6c" "(null)" && + try_case 6c unset "$here/6c/.git" \ + "$here/6c/.git" "$here/6c/wt" "$here/6c" "(null)" && + try_case 6c/sub/sub unset ../../.git \ + ../../.git "$here/6c/wt" "$here/6c/sub/sub" "(null)" && + try_case 6c/sub/sub unset "$here/6c/.git" \ + "$here/6c/.git" "$here/6c/wt" "$here/6c/sub/sub" "(null)" +' + +test_expect_success '#6d: GIT_DIR set, core.worktree=../wt (relative)' ' + setup_repo 6d "$here/6d/wt" "" unset && + mkdir -p 6d/wt/sub && + + try_case 6d unset .git \ + .git "$here/6d/wt" "$here/6d" "(null)" && + try_case 6d unset "$here/6d/.git" \ + "$here/6d/.git" "$here/6d/wt" "$here/6d" "(null)" && + try_case 6d/sub/sub unset ../../.git \ + ../../.git "$here/6d/wt" "$here/6d/sub/sub" "(null)" && + try_case 6d/sub/sub unset "$here/6d/.git" \ + "$here/6d/.git" "$here/6d/wt" "$here/6d/sub/sub" "(null)" +' + +test_expect_success '#6e: GIT_DIR set, core.worktree=../.. (absolute)' ' + setup_repo 6e "$here" "" unset && + try_case 6e unset .git \ + "$here/6e/.git" "$here" "$here" 6e/ && + try_case 6e unset "$here/6e/.git" \ + "$here/6e/.git" "$here" "$here" 6e/ && + try_case 6e/sub/sub unset ../../.git \ + "$here/6e/.git" "$here" "$here" 6e/sub/sub/ && + try_case 6e/sub/sub unset "$here/6e/.git" \ + "$here/6e/.git" "$here" "$here" 6e/sub/sub/ +' + +test_expect_success '#6f: GIT_DIR set, core.worktree=../.. (relative)' ' + setup_repo 6f ../../ "" unset && + try_case 6f unset .git \ + "$here/6f/.git" "$here" "$here" 6f/ && + try_case 6f unset "$here/6f/.git" \ + "$here/6f/.git" "$here" "$here" 6f/ && + try_case 6f/sub/sub unset ../../.git \ + "$here/6f/.git" "$here" "$here" 6f/sub/sub/ && + try_case 6f/sub/sub unset "$here/6f/.git" \ + "$here/6f/.git" "$here" "$here" 6f/sub/sub/ +' + +# case #7: GIT_WORK_TREE overrides core.worktree. test_expect_success '#7: setup' ' - unset GIT_DIR GIT_WORK_TREE && - mkdir 7 7/sub 7/sub/sub 7.wt 7.wt/sub 7/wt 7/wt/sub && - cd 7 && - git init && - git config core.worktree non-existent && - cd .. -' - -test_expect_success '#7: GIT_DIR(rel), GIT_WORK_TREE=root at root' ' - cat >7/expected <<EOF && -setup: git_dir: .git -setup: worktree: $TRASH_DIRECTORY/7 -setup: cwd: $TRASH_DIRECTORY/7 -setup: prefix: (null) -EOF - test_repo 7 .git "$TRASH_DIRECTORY/7" -' - -test_expect_success '#7: GIT_DIR(rel), GIT_WORK_TREE=root(rel) at root' ' - cat >7/expected <<EOF && -setup: git_dir: .git -setup: worktree: $TRASH_DIRECTORY/7 -setup: cwd: $TRASH_DIRECTORY/7 -setup: prefix: (null) -EOF - test_repo 7 .git . -' - -test_expect_success '#7: GIT_DIR, GIT_WORK_TREE=root at root' ' - cat >7/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/7/.git -setup: worktree: $TRASH_DIRECTORY/7 -setup: cwd: $TRASH_DIRECTORY/7 -setup: prefix: (null) -EOF - test_repo 7 "$TRASH_DIRECTORY/7/.git" "$TRASH_DIRECTORY/7" -' - -test_expect_success '#7: GIT_DIR, GIT_WORK_TREE=root(rel) at root' ' - cat >7/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/7/.git -setup: worktree: $TRASH_DIRECTORY/7 -setup: cwd: $TRASH_DIRECTORY/7 -setup: prefix: (null) -EOF - test_repo 7 "$TRASH_DIRECTORY/7/.git" . -' - -test_expect_success '#7: GIT_DIR(rel), GIT_WORKTREE=root in subdir' ' - cat >7/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/7/.git -setup: worktree: $TRASH_DIRECTORY/7 -setup: cwd: $TRASH_DIRECTORY/7 -setup: prefix: sub/sub/ -EOF - test_repo 7/sub/sub ../../.git "$TRASH_DIRECTORY/7" -' - -test_expect_success '#7: GIT_DIR(rel), GIT_WORKTREE=root(rel) in subdir' ' - cat >7/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/7/.git -setup: worktree: $TRASH_DIRECTORY/7 -setup: cwd: $TRASH_DIRECTORY/7 -setup: prefix: sub/sub/ -EOF - test_repo 7/sub/sub ../../.git ../.. -' - -test_expect_success '#7: GIT_DIR, GIT_WORKTREE=root in subdir' ' - cat >7/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/7/.git -setup: worktree: $TRASH_DIRECTORY/7 -setup: cwd: $TRASH_DIRECTORY/7 -setup: prefix: sub/ -EOF - test_repo 7/sub "$TRASH_DIRECTORY/7/.git" "$TRASH_DIRECTORY/7" -' - -test_expect_success '#7: GIT_DIR, GIT_WORKTREE=root(rel) in subdir' ' - cat >7/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/7/.git -setup: worktree: $TRASH_DIRECTORY/7 -setup: cwd: $TRASH_DIRECTORY/7 -setup: prefix: sub/sub/ -EOF - test_repo 7/sub/sub "$TRASH_DIRECTORY/7/.git" ../.. -' - -test_expect_success '#7: GIT_DIR(rel), GIT_WORK_TREE=wt at root' ' - cat >7/expected <<EOF && -setup: git_dir: .git -setup: worktree: $TRASH_DIRECTORY/7/wt -setup: cwd: $TRASH_DIRECTORY/7 -setup: prefix: (null) -EOF - test_repo 7 .git "$TRASH_DIRECTORY/7/wt" -' - -test_expect_success '#7: GIT_DIR(rel), GIT_WORK_TREE=wt(rel) at root' ' - cat >7/expected <<EOF && -setup: git_dir: .git -setup: worktree: $TRASH_DIRECTORY/7/wt -setup: cwd: $TRASH_DIRECTORY/7 -setup: prefix: (null) -EOF - test_repo 7 .git wt -' - -test_expect_success '#7: GIT_DIR, GIT_WORK_TREE=wt(rel) at root' ' - cat >7/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/7/.git -setup: worktree: $TRASH_DIRECTORY/7/wt -setup: cwd: $TRASH_DIRECTORY/7 -setup: prefix: (null) -EOF - test_repo 7 "$TRASH_DIRECTORY/7/.git" wt -' - -test_expect_success '#7: GIT_DIR, GIT_WORK_TREE=wt at root' ' - cat >7/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/7/.git -setup: worktree: $TRASH_DIRECTORY/7/wt -setup: cwd: $TRASH_DIRECTORY/7 -setup: prefix: (null) -EOF - test_repo 7 "$TRASH_DIRECTORY/7/.git" "$TRASH_DIRECTORY/7/wt" -' - -test_expect_success '#7: GIT_DIR(rel), GIT_WORK_TREE=wt in subdir' ' - cat >7/sub/sub/expected <<EOF && -setup: git_dir: ../../.git -setup: worktree: $TRASH_DIRECTORY/7/wt -setup: cwd: $TRASH_DIRECTORY/7/sub/sub -setup: prefix: (null) -EOF - test_repo 7/sub/sub ../../.git "$TRASH_DIRECTORY/7/wt" -' - -test_expect_success '#7: GIT_DIR(rel), GIT_WORK_TREE=wt(rel) in subdir' ' - cat >7/sub/sub/expected <<EOF && -setup: git_dir: ../../.git -setup: worktree: $TRASH_DIRECTORY/7/wt -setup: cwd: $TRASH_DIRECTORY/7/sub/sub -setup: prefix: (null) -EOF - test_repo 7/sub/sub ../../.git ../../wt -' - -test_expect_success '#7: GIT_DIR, GIT_WORK_TREE=wt(rel) in subdir' ' - cat >7/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/7/.git -setup: worktree: $TRASH_DIRECTORY/7/wt -setup: cwd: $TRASH_DIRECTORY/7/sub/sub -setup: prefix: (null) -EOF - test_repo 7/sub/sub "$TRASH_DIRECTORY/7/.git" ../../wt -' - -test_expect_success '#7: GIT_DIR, GIT_WORK_TREE=wt in subdir' ' - cat >7/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/7/.git -setup: worktree: $TRASH_DIRECTORY/7/wt -setup: cwd: $TRASH_DIRECTORY/7/sub/sub -setup: prefix: (null) -EOF - test_repo 7/sub/sub "$TRASH_DIRECTORY/7/.git" "$TRASH_DIRECTORY/7/wt" -' - -test_expect_success '#7: GIT_DIR(rel), GIT_WORK_TREE=.. at root' ' - cat >7/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/7/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 7/ -EOF - test_repo 7 .git "$TRASH_DIRECTORY" -' - -test_expect_success '#7: GIT_DIR(rel), GIT_WORK_TREE=..(rel) at root' ' - cat >7/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/7/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 7/ -EOF - test_repo 7 .git .. -' - -test_expect_success '#7: GIT_DIR, GIT_WORK_TREE=..(rel) at root' ' - cat >7/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/7/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 7/ -EOF - test_repo 7 "$TRASH_DIRECTORY/7/.git" .. -' - -test_expect_success '#7: GIT_DIR, GIT_WORK_TREE=.. at root' ' - cat >7/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/7/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 7/ -EOF - test_repo 7 "$TRASH_DIRECTORY/7/.git" "$TRASH_DIRECTORY" -' - -test_expect_success '#7: GIT_DIR(rel), GIT_WORK_TREE=.. in subdir' ' - cat >7/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/7/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 7/sub/sub/ -EOF - test_repo 7/sub/sub ../../.git "$TRASH_DIRECTORY" -' - -test_expect_success '#7: GIT_DIR(rel), GIT_WORK_TREE=..(rel) in subdir' ' - cat >7/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/7/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 7/sub/sub/ -EOF - test_repo 7/sub/sub ../../.git ../../.. -' - -test_expect_success '#7: GIT_DIR, GIT_WORK_TREE=..(rel) in subdir' ' - cat >7/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/7/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 7/sub/sub/ -EOF - test_repo 7/sub/sub "$TRASH_DIRECTORY/7/.git" ../../../ -' - -test_expect_success '#7: GIT_DIR, GIT_WORK_TREE=.. in subdir' ' - cat >7/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/7/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 7/sub/sub/ -EOF - test_repo 7/sub/sub "$TRASH_DIRECTORY/7/.git" "$TRASH_DIRECTORY" -' - -# -# case #8 -# -############################################################ -# -# Input: -# -# - GIT_WORK_TREE is not set -# - GIT_DIR is not set -# - core.worktree is not set -# - .git is a file -# - core.bare is not set, cwd is outside .git -# -# Output: -# -# #0 except that git_dir is set by .git file - -test_expect_success '#8: setup' ' - unset GIT_DIR GIT_WORK_TREE && - mkdir 8 8/sub && - cd 8 && - git init && - mv .git ../8.git && - echo gitdir: ../8.git >.git && - cd .. -' - -test_expect_success '#8: at root' ' - cat >8/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/8.git -setup: worktree: $TRASH_DIRECTORY/8 -setup: cwd: $TRASH_DIRECTORY/8 -setup: prefix: (null) -EOF - test_repo 8 -' - -test_expect_success '#8: in subdir' ' - cat >8/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/8.git -setup: worktree: $TRASH_DIRECTORY/8 -setup: cwd: $TRASH_DIRECTORY/8 -setup: prefix: sub/ -EOF - test_repo 8/sub -' - -# -# case #9 -# -############################################################ -# -# Input: -# -# - GIT_WORK_TREE is set -# - GIT_DIR is not set -# - core.worktree is not set -# - .git is a file -# - core.bare is not set, cwd is outside .git -# -# Output: -# -# #1 except that git_dir is set by .git file - -test_expect_success '#9: setup' ' - unset GIT_DIR GIT_WORK_TREE && - mkdir 9 9/sub 9.wt 9.wt/sub 9/wt 9/wt/sub && - cd 9 && - git init && - mv .git ../9.git && - echo gitdir: ../9.git >.git && - GIT_WORK_TREE=non-existent && - export GIT_WORK_TREE && - cd .. -' - -test_expect_success '#9: at root' ' - cat >9/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/9.git -setup: worktree: $TRASH_DIRECTORY/9 -setup: cwd: $TRASH_DIRECTORY/9 -setup: prefix: (null) -EOF - test_repo 9 -' - -test_expect_success '#9: in subdir' ' - cat >9/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/9.git -setup: worktree: $TRASH_DIRECTORY/9 -setup: cwd: $TRASH_DIRECTORY/9 -setup: prefix: sub/ -EOF - test_repo 9/sub -' - -# -# case #10 -# -############################################################ -# -# Input: -# -# - GIT_WORK_TREE is not set -# - GIT_DIR is set -# - core.worktree is not set -# - .git is a file -# - core.bare is not set, cwd is outside .git -# -# Output: -# -# #2 except that git_dir is set by .git file - -test_expect_success '#10: setup' ' - unset GIT_DIR GIT_WORK_TREE && - mkdir 10 10/sub && - cd 10 && - git init && - mv .git ../10.git && - echo gitdir: ../10.git >.git && - cd .. + setup_repo 7 non-existent "" unset && + mkdir -p 7/sub/sub 7/wt/sub ' +run_wt_tests 7 -test_expect_success '#10: at root' ' - cat >10/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/10.git -setup: worktree: $TRASH_DIRECTORY/10 -setup: cwd: $TRASH_DIRECTORY/10 -setup: prefix: (null) -EOF - test_repo 10 "$TRASH_DIRECTORY/10/.git" +test_expect_success '#8: gitfile, easy case' ' + try_repo 8 unset unset unset gitfile unset \ + "$here/8.git" "$here/8" "$here/8" "(null)" \ + "$here/8.git" "$here/8" "$here/8" sub/ ' -test_expect_success '#10: in subdir' ' - cat >10/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/10.git -setup: worktree: $TRASH_DIRECTORY/10/sub -setup: cwd: $TRASH_DIRECTORY/10/sub -setup: prefix: (null) -EOF - test_repo 10/sub "$TRASH_DIRECTORY/10/.git" +test_expect_success '#9: GIT_WORK_TREE accepted with gitfile' ' + mkdir -p 9/wt && + try_repo 9 wt unset unset gitfile unset \ + "$here/9.git" "$here/9/wt" "$here/9" "(null)" \ + "$here/9.git" "$here/9/sub/wt" "$here/9/sub" "(null)" 2>message && + ! test -s message ' -test_expect_success '#10: relative GIT_DIR at root' ' - cat >10/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/10.git -setup: worktree: $TRASH_DIRECTORY/10 -setup: cwd: $TRASH_DIRECTORY/10 -setup: prefix: (null) -EOF - test_repo 10 .git +test_expect_success '#10: GIT_DIR can point to gitfile' ' + try_repo 10 unset "$here/10/.git" unset gitfile unset \ + "$here/10.git" "$here/10" "$here/10" "(null)" \ + "$here/10.git" "$here/10/sub" "$here/10/sub" "(null)" ' -test_expect_success '#10: relative GIT_DIR in subdir' ' - cat >10/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/10.git -setup: worktree: $TRASH_DIRECTORY/10/sub -setup: cwd: $TRASH_DIRECTORY/10/sub -setup: prefix: (null) -EOF - test_repo 10/sub ../.git +test_expect_success '#10b: relative GIT_DIR can point to gitfile' ' + try_repo 10b unset .git unset gitfile unset \ + "$here/10b.git" "$here/10b" "$here/10b" "(null)" \ + "$here/10b.git" "$here/10b/sub" "$here/10b/sub" "(null)" ' -# -# case #11 -# -############################################################ -# -# Input: -# -# - GIT_WORK_TREE is set -# - GIT_DIR is set -# - core.worktree is not set -# - .git is a file -# - core.bare is not set, cwd is outside .git -# -# Output: -# -# #3 except that git_dir is set by .git file - +# case #11: GIT_WORK_TREE works, gitfile case. test_expect_success '#11: setup' ' - unset GIT_DIR GIT_WORK_TREE && - mkdir 11 11/sub 11/sub/sub 11.wt 11.wt/sub 11/wt 11/wt/sub && - cd 11 && - git init && - mv .git ../11.git && - echo gitdir: ../11.git >.git && - cd .. -' - -test_expect_success '#11: GIT_DIR(rel), GIT_WORK_TREE=root at root' ' - cat >11/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/11.git -setup: worktree: $TRASH_DIRECTORY/11 -setup: cwd: $TRASH_DIRECTORY/11 -setup: prefix: (null) -EOF - test_repo 11 .git "$TRASH_DIRECTORY/11" -' - -test_expect_success '#11: GIT_DIR(rel), GIT_WORK_TREE=root(rel) at root' ' - cat >11/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/11.git -setup: worktree: $TRASH_DIRECTORY/11 -setup: cwd: $TRASH_DIRECTORY/11 -setup: prefix: (null) -EOF - test_repo 11 .git . -' - -test_expect_success '#11: GIT_DIR, GIT_WORK_TREE=root at root' ' - cat >11/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/11.git -setup: worktree: $TRASH_DIRECTORY/11 -setup: cwd: $TRASH_DIRECTORY/11 -setup: prefix: (null) -EOF - test_repo 11 "$TRASH_DIRECTORY/11/.git" "$TRASH_DIRECTORY/11" -' - -test_expect_success '#11: GIT_DIR, GIT_WORK_TREE=root(rel) at root' ' - cat >11/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/11.git -setup: worktree: $TRASH_DIRECTORY/11 -setup: cwd: $TRASH_DIRECTORY/11 -setup: prefix: (null) -EOF - test_repo 11 "$TRASH_DIRECTORY/11/.git" . -' - -test_expect_success '#11: GIT_DIR(rel), GIT_WORKTREE=root in subdir' ' - cat >11/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/11.git -setup: worktree: $TRASH_DIRECTORY/11 -setup: cwd: $TRASH_DIRECTORY/11 -setup: prefix: sub/sub/ -EOF - test_repo 11/sub/sub ../../.git "$TRASH_DIRECTORY/11" -' - -test_expect_success '#11: GIT_DIR(rel), GIT_WORKTREE=root(rel) in subdir' ' - cat >11/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/11.git -setup: worktree: $TRASH_DIRECTORY/11 -setup: cwd: $TRASH_DIRECTORY/11 -setup: prefix: sub/sub/ -EOF - test_repo 11/sub/sub ../../.git ../.. -' - -test_expect_success '#11: GIT_DIR, GIT_WORKTREE=root in subdir' ' - cat >11/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/11.git -setup: worktree: $TRASH_DIRECTORY/11 -setup: cwd: $TRASH_DIRECTORY/11 -setup: prefix: sub/ -EOF - test_repo 11/sub "$TRASH_DIRECTORY/11/.git" "$TRASH_DIRECTORY/11" -' - -test_expect_success '#11: GIT_DIR, GIT_WORKTREE=root(rel) in subdir' ' - cat >11/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/11.git -setup: worktree: $TRASH_DIRECTORY/11 -setup: cwd: $TRASH_DIRECTORY/11 -setup: prefix: sub/sub/ -EOF - test_repo 11/sub/sub "$TRASH_DIRECTORY/11/.git" ../.. -' - -test_expect_success '#11: GIT_DIR(rel), GIT_WORK_TREE=wt at root' ' - cat >11/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/11.git -setup: worktree: $TRASH_DIRECTORY/11/wt -setup: cwd: $TRASH_DIRECTORY/11 -setup: prefix: (null) -EOF - test_repo 11 .git "$TRASH_DIRECTORY/11/wt" -' - -test_expect_success '#11: GIT_DIR(rel), GIT_WORK_TREE=wt(rel) at root' ' - cat >11/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/11.git -setup: worktree: $TRASH_DIRECTORY/11/wt -setup: cwd: $TRASH_DIRECTORY/11 -setup: prefix: (null) -EOF - test_repo 11 .git wt -' - -test_expect_success '#11: GIT_DIR, GIT_WORK_TREE=wt(rel) at root' ' - cat >11/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/11.git -setup: worktree: $TRASH_DIRECTORY/11/wt -setup: cwd: $TRASH_DIRECTORY/11 -setup: prefix: (null) -EOF - test_repo 11 "$TRASH_DIRECTORY/11/.git" wt -' - -test_expect_success '#11: GIT_DIR, GIT_WORK_TREE=wt at root' ' - cat >11/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/11.git -setup: worktree: $TRASH_DIRECTORY/11/wt -setup: cwd: $TRASH_DIRECTORY/11 -setup: prefix: (null) -EOF - test_repo 11 "$TRASH_DIRECTORY/11/.git" "$TRASH_DIRECTORY/11/wt" -' - -test_expect_success '#11: GIT_DIR(rel), GIT_WORK_TREE=wt in subdir' ' - cat >11/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/11.git -setup: worktree: $TRASH_DIRECTORY/11/wt -setup: cwd: $TRASH_DIRECTORY/11/sub/sub -setup: prefix: (null) -EOF - test_repo 11/sub/sub ../../.git "$TRASH_DIRECTORY/11/wt" -' - -test_expect_success '#11: GIT_DIR(rel), GIT_WORK_TREE=wt(rel) in subdir' ' - cat >11/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/11.git -setup: worktree: $TRASH_DIRECTORY/11/wt -setup: cwd: $TRASH_DIRECTORY/11/sub/sub -setup: prefix: (null) -EOF - test_repo 11/sub/sub ../../.git ../../wt -' - -test_expect_success '#11: GIT_DIR, GIT_WORK_TREE=wt(rel) in subdir' ' - cat >11/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/11.git -setup: worktree: $TRASH_DIRECTORY/11/wt -setup: cwd: $TRASH_DIRECTORY/11/sub/sub -setup: prefix: (null) -EOF - test_repo 11/sub/sub "$TRASH_DIRECTORY/11/.git" ../../wt -' - -test_expect_success '#11: GIT_DIR, GIT_WORK_TREE=wt in subdir' ' - cat >11/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/11.git -setup: worktree: $TRASH_DIRECTORY/11/wt -setup: cwd: $TRASH_DIRECTORY/11/sub/sub -setup: prefix: (null) -EOF - test_repo 11/sub/sub "$TRASH_DIRECTORY/11/.git" "$TRASH_DIRECTORY/11/wt" -' - -test_expect_success '#11: GIT_DIR(rel), GIT_WORK_TREE=.. at root' ' - cat >11/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/11.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 11/ -EOF - test_repo 11 .git "$TRASH_DIRECTORY" -' - -test_expect_success '#11: GIT_DIR(rel), GIT_WORK_TREE=..(rel) at root' ' - cat >11/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/11.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 11/ -EOF - test_repo 11 .git .. -' - -test_expect_success '#11: GIT_DIR, GIT_WORK_TREE=..(rel) at root' ' - cat >11/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/11.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 11/ -EOF - test_repo 11 "$TRASH_DIRECTORY/11/.git" .. -' - -test_expect_success '#11: GIT_DIR, GIT_WORK_TREE=.. at root' ' - cat >11/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/11.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 11/ -EOF - test_repo 11 "$TRASH_DIRECTORY/11/.git" "$TRASH_DIRECTORY" -' - -test_expect_success '#11: GIT_DIR(rel), GIT_WORK_TREE=.. in subdir' ' - cat >11/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/11.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 11/sub/sub/ -EOF - test_repo 11/sub/sub ../../.git "$TRASH_DIRECTORY" -' - -test_expect_success '#11: GIT_DIR(rel), GIT_WORK_TREE=..(rel) in subdir' ' - cat >11/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/11.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 11/sub/sub/ -EOF - test_repo 11/sub/sub ../../.git ../../.. -' - -test_expect_success '#11: GIT_DIR, GIT_WORK_TREE=..(rel) in subdir' ' - cat >11/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/11.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 11/sub/sub/ -EOF - test_repo 11/sub/sub "$TRASH_DIRECTORY/11/.git" ../../../ -' - -test_expect_success '#11: GIT_DIR, GIT_WORK_TREE=.. in subdir' ' - cat >11/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/11.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 11/sub/sub/ -EOF - test_repo 11/sub/sub "$TRASH_DIRECTORY/11/.git" "$TRASH_DIRECTORY" -' - -# -# case #12 -# -############################################################ -# -# Input: -# -# - GIT_WORK_TREE is not set -# - GIT_DIR is not set -# - core.worktree is set -# - .git is a file -# - core.bare is not set, cwd is outside .git -# -# Output: -# -# #4 except that git_dir is set by .git file - - -test_expect_success '#12: setup' ' - unset GIT_DIR GIT_WORK_TREE && - mkdir 12 12/sub 12/sub/sub 12.wt 12.wt/sub 12/wt 12/wt/sub && - cd 12 && - git init && - git config core.worktree non-existent && - mv .git ../12.git && - echo gitdir: ../12.git >.git && - cd .. -' - -test_expect_success '#12: at root' ' - cat >12/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/12.git -setup: worktree: $TRASH_DIRECTORY/12 -setup: cwd: $TRASH_DIRECTORY/12 -setup: prefix: (null) -EOF - test_repo 12 -' - -test_expect_success '#12: in subdir' ' - cat >12/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/12.git -setup: worktree: $TRASH_DIRECTORY/12 -setup: cwd: $TRASH_DIRECTORY/12 -setup: prefix: sub/ -EOF - test_repo 12/sub -' - -# -# case #13 -# -############################################################ -# -# Input: -# -# - GIT_WORK_TREE is set -# - GIT_DIR is not set -# - core.worktree is set -# - .git is a file -# - core.bare is not set, cwd is outside .git -# -# Output: -# -# #5 except that git_dir is set by .git file - -test_expect_success '#13: setup' ' - unset GIT_DIR GIT_WORK_TREE && - mkdir 13 13/sub 13/sub/sub 13.wt 13.wt/sub 13/wt 13/wt/sub && - cd 13 && - git init && - git config core.worktree non-existent && - GIT_WORK_TREE=non-existent-too && - export GIT_WORK_TREE && - mv .git ../13.git && - echo gitdir: ../13.git >.git && - cd .. -' - -test_expect_success '#13: at root' ' - cat >13/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/13.git -setup: worktree: $TRASH_DIRECTORY/13 -setup: cwd: $TRASH_DIRECTORY/13 -setup: prefix: (null) -EOF - test_repo 13 -' - -test_expect_success '#13: in subdir' ' - cat >13/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/13.git -setup: worktree: $TRASH_DIRECTORY/13 -setup: cwd: $TRASH_DIRECTORY/13 -setup: prefix: sub/ -EOF - test_repo 13/sub -' - -# -# case #14 -# -############################################################ -# -# Input: -# -# - GIT_WORK_TREE is not set -# - GIT_DIR is set -# - core.worktree is set -# - .git is a file -# - core.bare is not set, cwd is outside .git -# -# Output: -# -# #6 except that git_dir is set by .git file - -test_expect_success '#14: setup' ' - unset GIT_DIR GIT_WORK_TREE && - mkdir 14 14/sub 14/sub/sub 14.wt 14.wt/sub 14/wt 14/wt/sub && - cd 14 && - git init && - mv .git ../14.git && - echo gitdir: ../14.git >.git && - cd .. -' - -test_expect_success '#14: GIT_DIR(rel), core.worktree=../14 at root' ' - cat >14/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/14.git -setup: worktree: $TRASH_DIRECTORY/14 -setup: cwd: $TRASH_DIRECTORY/14 -setup: prefix: (null) -EOF - git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree "$TRASH_DIRECTORY/14" && - test_repo 14 .git -' - -test_expect_success '#14: GIT_DIR(rel), core.worktree=../14(rel) at root' ' - cat >14/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/14.git -setup: worktree: $TRASH_DIRECTORY/14 -setup: cwd: $TRASH_DIRECTORY/14 -setup: prefix: (null) -EOF - git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree ../14 && - test_repo 14 .git -' - -test_expect_success '#14: GIT_DIR, core.worktree=../14 at root' ' - cat >14/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/14.git -setup: worktree: $TRASH_DIRECTORY/14 -setup: cwd: $TRASH_DIRECTORY/14 -setup: prefix: (null) -EOF - git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree "$TRASH_DIRECTORY/14" && - test_repo 14 "$TRASH_DIRECTORY/14/.git" -' - -test_expect_success '#14: GIT_DIR, core.worktree=../14(rel) at root' ' - cat >14/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/14.git -setup: worktree: $TRASH_DIRECTORY/14 -setup: cwd: $TRASH_DIRECTORY/14 -setup: prefix: (null) -EOF - git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree ../14 && - test_repo 14 "$TRASH_DIRECTORY/14/.git" -' - -test_expect_success '#14: GIT_DIR(rel), core.worktree=../14 in subdir' ' - cat >14/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/14.git -setup: worktree: $TRASH_DIRECTORY/14 -setup: cwd: $TRASH_DIRECTORY/14 -setup: prefix: sub/sub/ -EOF - git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree "$TRASH_DIRECTORY/14" && - test_repo 14/sub/sub ../../.git -' - -test_expect_success '#14: GIT_DIR(rel), core.worktree=../14(rel) in subdir' ' - cat >14/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/14.git -setup: worktree: $TRASH_DIRECTORY/14 -setup: cwd: $TRASH_DIRECTORY/14 -setup: prefix: sub/sub/ -EOF - git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree ../14 && - test_repo 14/sub/sub ../../.git -' - -test_expect_success '#14: GIT_DIR, core.worktree=../14 in subdir' ' - cat >14/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/14.git -setup: worktree: $TRASH_DIRECTORY/14 -setup: cwd: $TRASH_DIRECTORY/14 -setup: prefix: sub/ -EOF - git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree "$TRASH_DIRECTORY/14" && - test_repo 14/sub "$TRASH_DIRECTORY/14/.git" -' - -test_expect_success '#14: GIT_DIR, core.worktree=../14(rel) in subdir' ' - cat >14/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/14.git -setup: worktree: $TRASH_DIRECTORY/14 -setup: cwd: $TRASH_DIRECTORY/14 -setup: prefix: sub/sub/ -EOF - git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree ../14 && - test_repo 14/sub/sub "$TRASH_DIRECTORY/14/.git" -' - -test_expect_success '#14: GIT_DIR(rel), core.worktree=../14/wt at root' ' - cat >14/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/14.git -setup: worktree: $TRASH_DIRECTORY/14/wt -setup: cwd: $TRASH_DIRECTORY/14 -setup: prefix: (null) -EOF - git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree "$TRASH_DIRECTORY/14/wt" && - test_repo 14 .git -' - -test_expect_success '#14: GIT_DIR(rel), core.worktree=../14/wt(rel) at root' ' - cat >14/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/14.git -setup: worktree: $TRASH_DIRECTORY/14/wt -setup: cwd: $TRASH_DIRECTORY/14 -setup: prefix: (null) -EOF - git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree ../14/wt && - test_repo 14 .git -' - -test_expect_success '#14: GIT_DIR, core.worktree=../14/wt(rel) at root' ' - cat >14/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/14.git -setup: worktree: $TRASH_DIRECTORY/14/wt -setup: cwd: $TRASH_DIRECTORY/14 -setup: prefix: (null) -EOF - git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree ../14/wt && - test_repo 14 "$TRASH_DIRECTORY/14/.git" -' - -test_expect_success '#14: GIT_DIR, core.worktree=../14/wt at root' ' - cat >14/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/14.git -setup: worktree: $TRASH_DIRECTORY/14/wt -setup: cwd: $TRASH_DIRECTORY/14 -setup: prefix: (null) -EOF - git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree "$TRASH_DIRECTORY/14/wt" && - test_repo 14 "$TRASH_DIRECTORY/14/.git" -' - -test_expect_success '#14: GIT_DIR(rel), core.worktree=../14/wt in subdir' ' - cat >14/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/14.git -setup: worktree: $TRASH_DIRECTORY/14/wt -setup: cwd: $TRASH_DIRECTORY/14/sub/sub -setup: prefix: (null) -EOF - git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree "$TRASH_DIRECTORY/14/wt" && - test_repo 14/sub/sub ../../.git -' - -test_expect_success '#14: GIT_DIR(rel), core.worktree=../14/wt(rel) in subdir' ' - cat >14/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/14.git -setup: worktree: $TRASH_DIRECTORY/14/wt -setup: cwd: $TRASH_DIRECTORY/14/sub/sub -setup: prefix: (null) -EOF - git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree ../14/wt && - test_repo 14/sub/sub ../../.git -' - -test_expect_success '#14: GIT_DIR, core.worktree=../14/wt(rel) in subdir' ' - cat >14/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/14.git -setup: worktree: $TRASH_DIRECTORY/14/wt -setup: cwd: $TRASH_DIRECTORY/14/sub/sub -setup: prefix: (null) -EOF - git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree ../14/wt && - test_repo 14/sub/sub "$TRASH_DIRECTORY/14/.git" -' - -test_expect_success '#14: GIT_DIR, core.worktree=../14/wt in subdir' ' - cat >14/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/14.git -setup: worktree: $TRASH_DIRECTORY/14/wt -setup: cwd: $TRASH_DIRECTORY/14/sub/sub -setup: prefix: (null) -EOF - git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree "$TRASH_DIRECTORY/14/wt" && - test_repo 14/sub/sub "$TRASH_DIRECTORY/14/.git" -' - -test_expect_success '#14: GIT_DIR(rel), core.worktree=.. at root' ' - cat >14/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/14.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 14/ -EOF - git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree "$TRASH_DIRECTORY" && - test_repo 14 .git -' - -test_expect_success '#14: GIT_DIR(rel), core.worktree=..(rel) at root' ' - cat >14/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/14.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 14/ -EOF - git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree .. && - test_repo 14 .git -' - -test_expect_success '#14: GIT_DIR, core.worktree=..(rel) at root' ' - cat >14/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/14.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 14/ -EOF - git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree .. && - test_repo 14 "$TRASH_DIRECTORY/14/.git" -' - -test_expect_success '#14: GIT_DIR, core.worktree=.. at root' ' - cat >14/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/14.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 14/ -EOF - git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree "$TRASH_DIRECTORY" && - test_repo 14 "$TRASH_DIRECTORY/14/.git" -' - -test_expect_success '#14: GIT_DIR(rel), core.worktree=.. in subdir' ' - cat >14/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/14.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 14/sub/sub/ -EOF - git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree "$TRASH_DIRECTORY" && - test_repo 14/sub/sub ../../.git -' - -test_expect_success '#14: GIT_DIR(rel), core.worktree=..(rel) in subdir' ' - cat >14/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/14.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 14/sub/sub/ -EOF - git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree .. && - test_repo 14/sub/sub ../../.git -' - -test_expect_success '#14: GIT_DIR, core.worktree=..(rel) in subdir' ' - cat >14/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/14.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 14/sub/sub/ -EOF - git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree .. && - test_repo 14/sub/sub "$TRASH_DIRECTORY/14/.git" -' - -test_expect_success '#14: GIT_DIR, core.worktree=.. in subdir' ' - cat >14/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/14.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 14/sub/sub/ -EOF - git config --file="$TRASH_DIRECTORY/14.git/config" core.worktree "$TRASH_DIRECTORY" && - test_repo 14/sub/sub "$TRASH_DIRECTORY/14/.git" -' - -# -# case #15 -# -############################################################ -# -# Input: -# -# - GIT_WORK_TREE is set -# - GIT_DIR is set -# - core.worktree is set -# - .git is a file -# - core.bare is not set, cwd is outside .git -# -# Output: -# -# #7 except that git_dir is set by .git file - + setup_repo 11 unset gitfile unset && + mkdir -p 11/sub/sub 11/wt/sub +' +run_wt_tests 11 gitfile + +test_expect_success '#12: core.worktree with gitfile is accepted' ' + try_repo 12 unset unset "$here/12" gitfile unset \ + "$here/12.git" "$here/12" "$here/12" "(null)" \ + "$here/12.git" "$here/12" "$here/12" sub/ 2>message && + ! test -s message +' + +test_expect_success '#13: core.worktree+GIT_WORK_TREE accepted (with gitfile)' ' + # or: you cannot intimidate away the lack of GIT_DIR setting + try_repo 13 non-existent-too unset non-existent gitfile unset \ + "$here/13.git" "$here/13/non-existent-too" "$here/13" "(null)" \ + "$here/13.git" "$here/13/sub/non-existent-too" "$here/13/sub" "(null)" 2>message && + ! test -s message +' + +# case #14. +# If this were more table-driven, it could share code with case #6. + +test_expect_success '#14: core.worktree with GIT_DIR pointing to gitfile' ' + setup_repo 14 "$here/14" gitfile unset && + try_case 14 unset .git \ + "$here/14.git" "$here/14" "$here/14" "(null)" && + try_case 14 unset "$here/14/.git" \ + "$here/14.git" "$here/14" "$here/14" "(null)" && + try_case 14/sub/sub unset ../../.git \ + "$here/14.git" "$here/14" "$here/14" sub/sub/ && + try_case 14/sub/sub unset "$here/14/.git" \ + "$here/14.git" "$here/14" "$here/14" sub/sub/ && + + setup_repo 14c "$here/14c/wt" gitfile unset && + mkdir -p 14c/wt/sub && + + try_case 14c unset .git \ + "$here/14c.git" "$here/14c/wt" "$here/14c" "(null)" && + try_case 14c unset "$here/14c/.git" \ + "$here/14c.git" "$here/14c/wt" "$here/14c" "(null)" && + try_case 14c/sub/sub unset ../../.git \ + "$here/14c.git" "$here/14c/wt" "$here/14c/sub/sub" "(null)" && + try_case 14c/sub/sub unset "$here/14c/.git" \ + "$here/14c.git" "$here/14c/wt" "$here/14c/sub/sub" "(null)" && + + setup_repo 14d "$here/14d/wt" gitfile unset && + mkdir -p 14d/wt/sub && + + try_case 14d unset .git \ + "$here/14d.git" "$here/14d/wt" "$here/14d" "(null)" && + try_case 14d unset "$here/14d/.git" \ + "$here/14d.git" "$here/14d/wt" "$here/14d" "(null)" && + try_case 14d/sub/sub unset ../../.git \ + "$here/14d.git" "$here/14d/wt" "$here/14d/sub/sub" "(null)" && + try_case 14d/sub/sub unset "$here/14d/.git" \ + "$here/14d.git" "$here/14d/wt" "$here/14d/sub/sub" "(null)" && + + setup_repo 14e "$here" gitfile unset && + try_case 14e unset .git \ + "$here/14e.git" "$here" "$here" 14e/ && + try_case 14e unset "$here/14e/.git" \ + "$here/14e.git" "$here" "$here" 14e/ && + try_case 14e/sub/sub unset ../../.git \ + "$here/14e.git" "$here" "$here" 14e/sub/sub/ && + try_case 14e/sub/sub unset "$here/14e/.git" \ + "$here/14e.git" "$here" "$here" 14e/sub/sub/ +' + +test_expect_success '#14b: core.worktree is relative to actual git dir' ' + setup_repo 14b ../14b gitfile unset && + try_case 14b unset .git \ + "$here/14b.git" "$here/14b" "$here/14b" "(null)" && + try_case 14b unset "$here/14b/.git" \ + "$here/14b.git" "$here/14b" "$here/14b" "(null)" && + try_case 14b/sub/sub unset ../../.git \ + "$here/14b.git" "$here/14b" "$here/14b" sub/sub/ && + try_case 14b/sub/sub unset "$here/14b/.git" \ + "$here/14b.git" "$here/14b" "$here/14b" sub/sub/ && + + setup_repo 14f ../ gitfile unset && + try_case 14f unset .git \ + "$here/14f.git" "$here" "$here" 14f/ && + try_case 14f unset "$here/14f/.git" \ + "$here/14f.git" "$here" "$here" 14f/ && + try_case 14f/sub/sub unset ../../.git \ + "$here/14f.git" "$here" "$here" 14f/sub/sub/ && + try_case 14f/sub/sub unset "$here/14f/.git" \ + "$here/14f.git" "$here" "$here" 14f/sub/sub/ +' + +# case #15: GIT_WORK_TREE overrides core.worktree (gitfile case). test_expect_success '#15: setup' ' - unset GIT_DIR GIT_WORK_TREE && - mkdir 15 15/sub 15/sub/sub 15.wt 15.wt/sub 15/wt 15/wt/sub && - cd 15 && - git init && - git config core.worktree non-existent && - mv .git ../15.git && - echo gitdir: ../15.git >.git && - cd .. -' - -test_expect_success '#15: GIT_DIR(rel), GIT_WORK_TREE=root at root' ' - cat >15/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/15.git -setup: worktree: $TRASH_DIRECTORY/15 -setup: cwd: $TRASH_DIRECTORY/15 -setup: prefix: (null) -EOF - test_repo 15 .git "$TRASH_DIRECTORY/15" -' - -test_expect_success '#15: GIT_DIR(rel), GIT_WORK_TREE=root(rel) at root' ' - cat >15/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/15.git -setup: worktree: $TRASH_DIRECTORY/15 -setup: cwd: $TRASH_DIRECTORY/15 -setup: prefix: (null) -EOF - test_repo 15 .git . -' - -test_expect_success '#15: GIT_DIR, GIT_WORK_TREE=root at root' ' - cat >15/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/15.git -setup: worktree: $TRASH_DIRECTORY/15 -setup: cwd: $TRASH_DIRECTORY/15 -setup: prefix: (null) -EOF - test_repo 15 "$TRASH_DIRECTORY/15/.git" "$TRASH_DIRECTORY/15" -' - -test_expect_success '#15: GIT_DIR, GIT_WORK_TREE=root(rel) at root' ' - cat >15/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/15.git -setup: worktree: $TRASH_DIRECTORY/15 -setup: cwd: $TRASH_DIRECTORY/15 -setup: prefix: (null) -EOF - test_repo 15 "$TRASH_DIRECTORY/15/.git" . -' - -test_expect_success '#15: GIT_DIR(rel), GIT_WORKTREE=root in subdir' ' - cat >15/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/15.git -setup: worktree: $TRASH_DIRECTORY/15 -setup: cwd: $TRASH_DIRECTORY/15 -setup: prefix: sub/sub/ -EOF - test_repo 15/sub/sub ../../.git "$TRASH_DIRECTORY/15" -' - -test_expect_success '#15: GIT_DIR(rel), GIT_WORKTREE=root(rel) in subdir' ' - cat >15/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/15.git -setup: worktree: $TRASH_DIRECTORY/15 -setup: cwd: $TRASH_DIRECTORY/15 -setup: prefix: sub/sub/ -EOF - test_repo 15/sub/sub ../../.git ../.. -' - -test_expect_success '#15: GIT_DIR, GIT_WORKTREE=root in subdir' ' - cat >15/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/15.git -setup: worktree: $TRASH_DIRECTORY/15 -setup: cwd: $TRASH_DIRECTORY/15 -setup: prefix: sub/ -EOF - test_repo 15/sub "$TRASH_DIRECTORY/15/.git" "$TRASH_DIRECTORY/15" -' - -test_expect_success '#15: GIT_DIR, GIT_WORKTREE=root(rel) in subdir' ' - cat >15/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/15.git -setup: worktree: $TRASH_DIRECTORY/15 -setup: cwd: $TRASH_DIRECTORY/15 -setup: prefix: sub/sub/ -EOF - test_repo 15/sub/sub "$TRASH_DIRECTORY/15/.git" ../.. -' - -test_expect_success '#15: GIT_DIR(rel), GIT_WORK_TREE=wt at root' ' - cat >15/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/15.git -setup: worktree: $TRASH_DIRECTORY/15/wt -setup: cwd: $TRASH_DIRECTORY/15 -setup: prefix: (null) -EOF - test_repo 15 .git "$TRASH_DIRECTORY/15/wt" -' - -test_expect_success '#15: GIT_DIR(rel), GIT_WORK_TREE=wt(rel) at root' ' - cat >15/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/15.git -setup: worktree: $TRASH_DIRECTORY/15/wt -setup: cwd: $TRASH_DIRECTORY/15 -setup: prefix: (null) -EOF - test_repo 15 .git wt -' - -test_expect_success '#15: GIT_DIR, GIT_WORK_TREE=wt(rel) at root' ' - cat >15/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/15.git -setup: worktree: $TRASH_DIRECTORY/15/wt -setup: cwd: $TRASH_DIRECTORY/15 -setup: prefix: (null) -EOF - test_repo 15 "$TRASH_DIRECTORY/15/.git" wt -' - -test_expect_success '#15: GIT_DIR, GIT_WORK_TREE=wt at root' ' - cat >15/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/15.git -setup: worktree: $TRASH_DIRECTORY/15/wt -setup: cwd: $TRASH_DIRECTORY/15 -setup: prefix: (null) -EOF - test_repo 15 "$TRASH_DIRECTORY/15/.git" "$TRASH_DIRECTORY/15/wt" -' - -test_expect_success '#15: GIT_DIR(rel), GIT_WORK_TREE=wt in subdir' ' - cat >15/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/15.git -setup: worktree: $TRASH_DIRECTORY/15/wt -setup: cwd: $TRASH_DIRECTORY/15/sub/sub -setup: prefix: (null) -EOF - test_repo 15/sub/sub ../../.git "$TRASH_DIRECTORY/15/wt" -' - -test_expect_success '#15: GIT_DIR(rel), GIT_WORK_TREE=wt(rel) in subdir' ' - cat >15/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/15.git -setup: worktree: $TRASH_DIRECTORY/15/wt -setup: cwd: $TRASH_DIRECTORY/15/sub/sub -setup: prefix: (null) -EOF - test_repo 15/sub/sub ../../.git ../../wt -' - -test_expect_success '#15: GIT_DIR, GIT_WORK_TREE=wt(rel) in subdir' ' - cat >15/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/15.git -setup: worktree: $TRASH_DIRECTORY/15/wt -setup: cwd: $TRASH_DIRECTORY/15/sub/sub -setup: prefix: (null) -EOF - test_repo 15/sub/sub "$TRASH_DIRECTORY/15/.git" ../../wt -' - -test_expect_success '#15: GIT_DIR, GIT_WORK_TREE=wt in subdir' ' - cat >15/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/15.git -setup: worktree: $TRASH_DIRECTORY/15/wt -setup: cwd: $TRASH_DIRECTORY/15/sub/sub -setup: prefix: (null) -EOF - test_repo 15/sub/sub "$TRASH_DIRECTORY/15/.git" "$TRASH_DIRECTORY/15/wt" -' - -test_expect_success '#15: GIT_DIR(rel), GIT_WORK_TREE=.. at root' ' - cat >15/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/15.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 15/ -EOF - test_repo 15 .git "$TRASH_DIRECTORY" -' - -test_expect_success '#15: GIT_DIR(rel), GIT_WORK_TREE=..(rel) at root' ' - cat >15/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/15.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 15/ -EOF - test_repo 15 .git .. -' - -test_expect_success '#15: GIT_DIR, GIT_WORK_TREE=..(rel) at root' ' - cat >15/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/15.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 15/ -EOF - test_repo 15 "$TRASH_DIRECTORY/15/.git" .. -' - -test_expect_success '#15: GIT_DIR, GIT_WORK_TREE=.. at root' ' - cat >15/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/15.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 15/ -EOF - test_repo 15 "$TRASH_DIRECTORY/15/.git" "$TRASH_DIRECTORY" -' - -test_expect_success '#15: GIT_DIR(rel), GIT_WORK_TREE=.. in subdir' ' - cat >15/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/15.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 15/sub/sub/ -EOF - test_repo 15/sub/sub ../../.git "$TRASH_DIRECTORY" -' - -test_expect_success '#15: GIT_DIR(rel), GIT_WORK_TREE=..(rel) in subdir' ' - cat >15/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/15.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 15/sub/sub/ -EOF - test_repo 15/sub/sub ../../.git ../../.. -' - -test_expect_success '#15: GIT_DIR, GIT_WORK_TREE=..(rel) in subdir' ' - cat >15/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/15.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 15/sub/sub/ -EOF - test_repo 15/sub/sub "$TRASH_DIRECTORY/15/.git" ../../../ -' - -test_expect_success '#15: GIT_DIR, GIT_WORK_TREE=.. in subdir' ' - cat >15/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/15.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 15/sub/sub/ -EOF - test_repo 15/sub/sub "$TRASH_DIRECTORY/15/.git" "$TRASH_DIRECTORY" -' - -# -# case #16.1 -# -############################################################ -# -# Input: -# -# - GIT_WORK_TREE is not set -# - GIT_DIR is not set -# - core.worktree is not set -# - .git is a directory -# - cwd is inside .git -# -# Output: -# -# - no worktree -# - cwd is unchanged -# - prefix is NULL -# - git_dir is set -# - cwd can't be outside worktree - -test_expect_success '#16.1: setup' ' - unset GIT_DIR GIT_WORK_TREE && - mkdir 16 16/sub && - cd 16 && - git init && - mkdir .git/wt .git/wt/sub && - cd .. -' - -test_expect_success '#16.1: at .git' ' - cat >16/.git/expected <<EOF && -setup: git_dir: . -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/16/.git -setup: prefix: (null) -EOF - test_repo 16/.git -' - -test_expect_success '#16.1: in .git/wt' ' - cat >16/.git/wt/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/16/.git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/16/.git/wt -setup: prefix: (null) -EOF - test_repo 16/.git/wt -' - -test_expect_success '#16.1: in .git/wt/sub' ' - cat >16/.git/wt/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/16/.git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/16/.git/wt/sub -setup: prefix: (null) -EOF - test_repo 16/.git/wt/sub -' - -# -# case #16.2 -# -############################################################ -# -# Input: -# -# - GIT_WORK_TREE is not set -# - GIT_DIR is not set -# - core.worktree is not set -# - .git is a directory -# - core.bare is set -# -# Output: -# -# - no worktree -# - cwd is unchanged -# - prefix is NULL -# - git_dir is set -# - cwd can't be outside worktree - -test_expect_success '#16.2: setup' ' - git config --file="$TRASH_DIRECTORY/16/.git/config" core.bare true -' - -test_expect_success '#16.2: at .git' ' - cat >16/.git/expected <<EOF && -setup: git_dir: . -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/16/.git -setup: prefix: (null) -EOF - test_repo 16/.git -' - -test_expect_success '#16.2: in .git/wt' ' - cat >16/.git/wt/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/16/.git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/16/.git/wt -setup: prefix: (null) -EOF - test_repo 16/.git/wt -' - -test_expect_success '#16.2: in .git/wt/sub' ' - cat >16/.git/wt/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/16/.git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/16/.git/wt/sub -setup: prefix: (null) -EOF - test_repo 16/.git/wt/sub -' - -test_expect_success '#16.2: at root' ' - cat >16/expected <<EOF && -setup: git_dir: .git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/16 -setup: prefix: (null) -EOF - test_repo 16 -' - -test_expect_success '#16.2: in subdir' ' - cat >16/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/16/.git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/16/sub -setup: prefix: (null) -EOF - test_repo 16/sub -' - -# -# case #17.1 -# -############################################################ -# -# Input: -# -# - GIT_WORK_TREE is set -# - GIT_DIR is not set -# - core.worktree is not set -# - .git is a directory -# - cwd is inside .git -# -# Output: -# -# GIT_WORK_TREE is ignored -> #16.1 (with warnings perhaps) - -test_expect_success '#17.1: setup' ' - unset GIT_DIR GIT_WORK_TREE && - mkdir 17 17/sub && - cd 17 && - git init && - mkdir .git/wt .git/wt/sub && - GIT_WORK_TREE=non-existent && - export GIT_WORK_TREE && - cd .. -' - -test_expect_success '#17.1: at .git' ' - cat >17/.git/expected <<EOF && -setup: git_dir: . -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/17/.git -setup: prefix: (null) -EOF - test_repo 17/.git -' - -test_expect_success '#17.1: in .git/wt' ' - cat >17/.git/wt/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/17/.git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/17/.git/wt -setup: prefix: (null) -EOF - test_repo 17/.git/wt -' - -test_expect_success '#17.1: in .git/wt/sub' ' - cat >17/.git/wt/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/17/.git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/17/.git/wt/sub -setup: prefix: (null) -EOF - test_repo 17/.git/wt/sub -' - -# -# case #17.2 -# -############################################################ -# -# Input: -# -# - GIT_WORK_TREE is set -# - GIT_DIR is not set -# - core.worktree is not set -# - .git is a directory -# - core.bare is set -# -# Output: -# -# GIT_WORK_TREE is ignored -> #16.2 (with warnings perhaps) - -test_expect_success '#17.2: setup' ' - git config --file="$TRASH_DIRECTORY/17/.git/config" core.bare true -' - -test_expect_success '#17.2: at .git' ' - cat >17/.git/expected <<EOF && -setup: git_dir: . -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/17/.git -setup: prefix: (null) -EOF - test_repo 17/.git -' - -test_expect_success '#17.2: in .git/wt' ' - cat >17/.git/wt/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/17/.git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/17/.git/wt -setup: prefix: (null) -EOF - test_repo 17/.git/wt -' - -test_expect_success '#17.2: in .git/wt/sub' ' - cat >17/.git/wt/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/17/.git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/17/.git/wt/sub -setup: prefix: (null) -EOF - test_repo 17/.git/wt/sub -' - -test_expect_success '#17.2: at root' ' - cat >17/expected <<EOF && -setup: git_dir: .git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/17 -setup: prefix: (null) -EOF - test_repo 17 -' - -test_expect_success '#17.2: in subdir' ' - cat >17/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/17/.git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/17/sub -setup: prefix: (null) -EOF - test_repo 17/sub -' - -# -# case #18 -# -############################################################ -# -# Input: -# -# - GIT_WORK_TREE is not set -# - GIT_DIR is set -# - core.worktree is not set -# - .git is a directory -# - core.bare is set -# -# Output: -# -# - no worktree (rule #8) -# - cwd is unchanged -# - prefix is NULL -# - git_dir is set to $GIT_DIR -# - cwd can't be outside worktree - -test_expect_success '#18: setup' ' - unset GIT_DIR GIT_WORK_TREE && - mkdir 18 18/sub && - cd 18 && - git init && - mkdir .git/wt .git/wt/sub && - git config core.bare true && - cd .. -' - -test_expect_success '#18: (rel) at root' ' - cat >18/expected <<EOF && -setup: git_dir: .git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/18 -setup: prefix: (null) -EOF - test_repo 18 .git -' - -test_expect_success '#18: at root' ' - cat >18/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/18/.git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/18 -setup: prefix: (null) -EOF - test_repo 18 "$TRASH_DIRECTORY/18/.git" -' - -test_expect_success '#18: (rel) in subdir' ' - cat >18/sub/expected <<EOF && -setup: git_dir: ../.git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/18/sub -setup: prefix: (null) -EOF - test_repo 18/sub ../.git -' - -test_expect_success '#18: in subdir' ' - cat >18/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/18/.git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/18/sub -setup: prefix: (null) -EOF - test_repo 18/sub "$TRASH_DIRECTORY/18/.git" -' - -# -# case #19 -# -############################################################ -# -# Input: -# -# - GIT_WORK_TREE is set -# - GIT_DIR is set -# - .git is a directory -# - core.worktree is not set -# - core.bare is set -# -# Output: -# -# bare repo is overridden by GIT_WORK_TREE -> #3 - + setup_repo 15 non-existent gitfile unset && + mkdir -p 15/sub/sub 15/wt/sub +' +run_wt_tests 15 gitfile + +test_expect_success '#16a: implicitly bare repo (cwd inside .git dir)' ' + setup_repo 16a unset "" unset && + mkdir -p 16a/.git/wt/sub && + + try_case 16a/.git unset unset \ + . "(null)" "$here/16a/.git" "(null)" && + try_case 16a/.git/wt unset unset \ + "$here/16a/.git" "(null)" "$here/16a/.git/wt" "(null)" && + try_case 16a/.git/wt/sub unset unset \ + "$here/16a/.git" "(null)" "$here/16a/.git/wt/sub" "(null)" +' + +test_expect_success '#16b: bare .git (cwd inside .git dir)' ' + setup_repo 16b unset "" true && + mkdir -p 16b/.git/wt/sub && + + try_case 16b/.git unset unset \ + . "(null)" "$here/16b/.git" "(null)" && + try_case 16b/.git/wt unset unset \ + "$here/16b/.git" "(null)" "$here/16b/.git/wt" "(null)" && + try_case 16b/.git/wt/sub unset unset \ + "$here/16b/.git" "(null)" "$here/16b/.git/wt/sub" "(null)" +' + +test_expect_success '#16c: bare .git has no worktree' ' + try_repo 16c unset unset unset "" true \ + .git "(null)" "$here/16c" "(null)" \ + "$here/16c/.git" "(null)" "$here/16c/sub" "(null)" +' + +test_expect_success '#17: GIT_WORK_TREE without explicit GIT_DIR is accepted (bare case)' ' + # Just like #16. + setup_repo 17a unset "" true && + setup_repo 17b unset "" true && + mkdir -p 17a/.git/wt/sub && + mkdir -p 17b/.git/wt/sub && + + try_case 17a/.git "$here/17a" unset \ + "$here/17a/.git" "$here/17a" "$here/17a" .git/ \ + 2>message && + try_case 17a/.git/wt "$here/17a" unset \ + "$here/17a/.git" "$here/17a" "$here/17a" .git/wt/ && + try_case 17a/.git/wt/sub "$here/17a" unset \ + "$here/17a/.git" "$here/17a" "$here/17a" .git/wt/sub/ && + + try_case 17b/.git "$here/17b" unset \ + "$here/17b/.git" "$here/17b" "$here/17b" .git/ && + try_case 17b/.git/wt "$here/17b" unset \ + "$here/17b/.git" "$here/17b" "$here/17b" .git/wt/ && + try_case 17b/.git/wt/sub "$here/17b" unset \ + "$here/17b/.git" "$here/17b" "$here/17b" .git/wt/sub/ && + + try_repo 17c "$here/17c" unset unset "" true \ + .git "$here/17c" "$here/17c" "(null)" \ + "$here/17c/.git" "$here/17c" "$here/17c" sub/ 2>message && + ! test -s message +' + +test_expect_success '#18: bare .git named by GIT_DIR has no worktree' ' + try_repo 18 unset .git unset "" true \ + .git "(null)" "$here/18" "(null)" \ + ../.git "(null)" "$here/18/sub" "(null)" && + try_repo 18b unset "$here/18b/.git" unset "" true \ + "$here/18b/.git" "(null)" "$here/18b" "(null)" \ + "$here/18b/.git" "(null)" "$here/18b/sub" "(null)" +' + +# Case #19: GIT_DIR + GIT_WORK_TREE suppresses bareness. test_expect_success '#19: setup' ' - unset GIT_DIR GIT_WORK_TREE && - mkdir 19 19/sub 19/sub/sub 19.wt 19.wt/sub 19/wt 19/wt/sub && - cd 19 && - git init && - git config core.bare true && - cd .. -' - -test_expect_success '#19: GIT_DIR(rel), GIT_WORK_TREE=root at root' ' - cat >19/expected <<EOF && -setup: git_dir: .git -setup: worktree: $TRASH_DIRECTORY/19 -setup: cwd: $TRASH_DIRECTORY/19 -setup: prefix: (null) -EOF - test_repo 19 .git "$TRASH_DIRECTORY/19" -' - -test_expect_success '#19: GIT_DIR(rel), GIT_WORK_TREE=root(rel) at root' ' - cat >19/expected <<EOF && -setup: git_dir: .git -setup: worktree: $TRASH_DIRECTORY/19 -setup: cwd: $TRASH_DIRECTORY/19 -setup: prefix: (null) -EOF - test_repo 19 .git . -' - -test_expect_success '#19: GIT_DIR, GIT_WORK_TREE=root at root' ' - cat >19/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/19/.git -setup: worktree: $TRASH_DIRECTORY/19 -setup: cwd: $TRASH_DIRECTORY/19 -setup: prefix: (null) -EOF - test_repo 19 "$TRASH_DIRECTORY/19/.git" "$TRASH_DIRECTORY/19" -' - -test_expect_success '#19: GIT_DIR, GIT_WORK_TREE=root(rel) at root' ' - cat >19/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/19/.git -setup: worktree: $TRASH_DIRECTORY/19 -setup: cwd: $TRASH_DIRECTORY/19 -setup: prefix: (null) -EOF - test_repo 19 "$TRASH_DIRECTORY/19/.git" . -' - -test_expect_success '#19: GIT_DIR(rel), GIT_WORKTREE=root in subdir' ' - cat >19/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/19/.git -setup: worktree: $TRASH_DIRECTORY/19 -setup: cwd: $TRASH_DIRECTORY/19 -setup: prefix: sub/sub/ -EOF - test_repo 19/sub/sub ../../.git "$TRASH_DIRECTORY/19" -' - -test_expect_success '#19: GIT_DIR(rel), GIT_WORKTREE=root(rel) in subdir' ' - cat >19/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/19/.git -setup: worktree: $TRASH_DIRECTORY/19 -setup: cwd: $TRASH_DIRECTORY/19 -setup: prefix: sub/sub/ -EOF - test_repo 19/sub/sub ../../.git ../.. -' - -test_expect_success '#19: GIT_DIR, GIT_WORKTREE=root in subdir' ' - cat >19/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/19/.git -setup: worktree: $TRASH_DIRECTORY/19 -setup: cwd: $TRASH_DIRECTORY/19 -setup: prefix: sub/ -EOF - test_repo 19/sub "$TRASH_DIRECTORY/19/.git" "$TRASH_DIRECTORY/19" -' - -test_expect_success '#19: GIT_DIR, GIT_WORKTREE=root(rel) in subdir' ' - cat >19/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/19/.git -setup: worktree: $TRASH_DIRECTORY/19 -setup: cwd: $TRASH_DIRECTORY/19 -setup: prefix: sub/sub/ -EOF - test_repo 19/sub/sub "$TRASH_DIRECTORY/19/.git" ../.. -' - -test_expect_success '#19: GIT_DIR(rel), GIT_WORK_TREE=wt at root' ' - cat >19/expected <<EOF && -setup: git_dir: .git -setup: worktree: $TRASH_DIRECTORY/19/wt -setup: cwd: $TRASH_DIRECTORY/19 -setup: prefix: (null) -EOF - test_repo 19 .git "$TRASH_DIRECTORY/19/wt" -' - -test_expect_success '#19: GIT_DIR(rel), GIT_WORK_TREE=wt(rel) at root' ' - cat >19/expected <<EOF && -setup: git_dir: .git -setup: worktree: $TRASH_DIRECTORY/19/wt -setup: cwd: $TRASH_DIRECTORY/19 -setup: prefix: (null) -EOF - test_repo 19 .git wt -' - -test_expect_success '#19: GIT_DIR, GIT_WORK_TREE=wt(rel) at root' ' - cat >19/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/19/.git -setup: worktree: $TRASH_DIRECTORY/19/wt -setup: cwd: $TRASH_DIRECTORY/19 -setup: prefix: (null) -EOF - test_repo 19 "$TRASH_DIRECTORY/19/.git" wt -' - -test_expect_success '#19: GIT_DIR, GIT_WORK_TREE=wt at root' ' - cat >19/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/19/.git -setup: worktree: $TRASH_DIRECTORY/19/wt -setup: cwd: $TRASH_DIRECTORY/19 -setup: prefix: (null) -EOF - test_repo 19 "$TRASH_DIRECTORY/19/.git" "$TRASH_DIRECTORY/19/wt" -' - -test_expect_success '#19: GIT_DIR(rel), GIT_WORK_TREE=wt in subdir' ' - cat >19/sub/sub/expected <<EOF && -setup: git_dir: ../../.git -setup: worktree: $TRASH_DIRECTORY/19/wt -setup: cwd: $TRASH_DIRECTORY/19/sub/sub -setup: prefix: (null) -EOF - test_repo 19/sub/sub ../../.git "$TRASH_DIRECTORY/19/wt" -' - -test_expect_success '#19: GIT_DIR(rel), GIT_WORK_TREE=wt(rel) in subdir' ' - cat >19/sub/sub/expected <<EOF && -setup: git_dir: ../../.git -setup: worktree: $TRASH_DIRECTORY/19/wt -setup: cwd: $TRASH_DIRECTORY/19/sub/sub -setup: prefix: (null) -EOF - test_repo 19/sub/sub ../../.git ../../wt -' - -test_expect_success '#19: GIT_DIR, GIT_WORK_TREE=wt(rel) in subdir' ' - cat >19/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/19/.git -setup: worktree: $TRASH_DIRECTORY/19/wt -setup: cwd: $TRASH_DIRECTORY/19/sub/sub -setup: prefix: (null) -EOF - test_repo 19/sub/sub "$TRASH_DIRECTORY/19/.git" ../../wt -' - -test_expect_success '#19: GIT_DIR, GIT_WORK_TREE=wt in subdir' ' - cat >19/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/19/.git -setup: worktree: $TRASH_DIRECTORY/19/wt -setup: cwd: $TRASH_DIRECTORY/19/sub/sub -setup: prefix: (null) -EOF - test_repo 19/sub/sub "$TRASH_DIRECTORY/19/.git" "$TRASH_DIRECTORY/19/wt" -' - -test_expect_success '#19: GIT_DIR(rel), GIT_WORK_TREE=.. at root' ' - cat >19/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/19/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 19/ -EOF - test_repo 19 .git "$TRASH_DIRECTORY" -' - -test_expect_success '#19: GIT_DIR(rel), GIT_WORK_TREE=..(rel) at root' ' - cat >19/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/19/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 19/ -EOF - test_repo 19 .git .. -' - -test_expect_success '#19: GIT_DIR, GIT_WORK_TREE=..(rel) at root' ' - cat >19/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/19/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 19/ -EOF - test_repo 19 "$TRASH_DIRECTORY/19/.git" .. -' - -test_expect_success '#19: GIT_DIR, GIT_WORK_TREE=.. at root' ' - cat >19/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/19/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 19/ -EOF - test_repo 19 "$TRASH_DIRECTORY/19/.git" "$TRASH_DIRECTORY" -' - -test_expect_success '#19: GIT_DIR(rel), GIT_WORK_TREE=.. in subdir' ' - cat >19/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/19/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 19/sub/sub/ -EOF - test_repo 19/sub/sub ../../.git "$TRASH_DIRECTORY" -' - -test_expect_success '#19: GIT_DIR(rel), GIT_WORK_TREE=..(rel) in subdir' ' - cat >19/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/19/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 19/sub/sub/ -EOF - test_repo 19/sub/sub ../../.git ../../.. -' - -test_expect_success '#19: GIT_DIR, GIT_WORK_TREE=..(rel) in subdir' ' - cat >19/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/19/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 19/sub/sub/ -EOF - test_repo 19/sub/sub "$TRASH_DIRECTORY/19/.git" ../../../ -' - -test_expect_success '#19: GIT_DIR, GIT_WORK_TREE=.. in subdir' ' - cat >19/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/19/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 19/sub/sub/ -EOF - test_repo 19/sub/sub "$TRASH_DIRECTORY/19/.git" "$TRASH_DIRECTORY" -' - -# -# case #20.1 -# -############################################################ -# -# Input: -# -# - GIT_WORK_TREE is not set -# - GIT_DIR is not set -# - core.worktree is set -# - .git is a directory -# - cwd is inside .git -# -# Output: -# -# core.worktree is ignored -> #16.1 - -test_expect_success '#20.1: setup' ' - unset GIT_DIR GIT_WORK_TREE && - mkdir 20 20/sub && - cd 20 && - git init && - git config core.worktree non-existent && - mkdir .git/wt .git/wt/sub && - cd .. -' - -test_expect_success '#20.1: at .git' ' - cat >20/.git/expected <<EOF && -setup: git_dir: . -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/20/.git -setup: prefix: (null) -EOF - test_repo 20/.git -' - -test_expect_success '#20.1: in .git/wt' ' - cat >20/.git/wt/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/20/.git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/20/.git/wt -setup: prefix: (null) -EOF - test_repo 20/.git/wt -' - -test_expect_success '#20.1: in .git/wt/sub' ' - cat >20/.git/wt/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/20/.git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/20/.git/wt/sub -setup: prefix: (null) -EOF - test_repo 20/.git/wt/sub -' - -# -# case #20.2 -# -############################################################ -# -# Input: -# -# - GIT_WORK_TREE is not set -# - GIT_DIR is not set -# - core.worktree is set -# - .git is a directory -# - core.bare is set -# -# Output: -# -# core.worktree is ignored -> #16.2 - -test_expect_success '#20.2: setup' ' - git config --file="$TRASH_DIRECTORY/20/.git/config" core.bare true -' - -test_expect_success '#20.2: at .git' ' - cat >20/.git/expected <<EOF && -setup: git_dir: . -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/20/.git -setup: prefix: (null) -EOF - test_repo 20/.git -' - -test_expect_success '#20.2: in .git/wt' ' - cat >20/.git/wt/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/20/.git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/20/.git/wt -setup: prefix: (null) -EOF - test_repo 20/.git/wt -' - -test_expect_success '#20.2: in .git/wt/sub' ' - cat >20/.git/wt/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/20/.git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/20/.git/wt/sub -setup: prefix: (null) -EOF - test_repo 20/.git/wt/sub -' - -test_expect_success '#20.2: at root' ' - cat >20/expected <<EOF && -setup: git_dir: .git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/20 -setup: prefix: (null) -EOF - test_repo 20 -' - -test_expect_success '#20.2: in subdir' ' - cat >20/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/20/.git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/20/sub -setup: prefix: (null) -EOF - test_repo 20/sub -' - -# -# case #21.1 -# -############################################################ -# -# Input: -# -# - GIT_WORK_TREE is set -# - GIT_DIR is not set -# - core.worktree is set -# - .git is a directory -# - cwd is inside .git -# -# Output: -# -# GIT_WORK_TREE/core.worktree are ignored -> #20.1 - -test_expect_success '#21.1: setup' ' - unset GIT_DIR GIT_WORK_TREE && - mkdir 21 21/sub && - cd 21 && - git init && - git config core.worktree non-existent && - GIT_WORK_TREE=non-existent-too && - export GIT_WORK_TREE && - mkdir .git/wt .git/wt/sub && - cd .. -' - -test_expect_success '#21.1: at .git' ' - cat >21/.git/expected <<EOF && -setup: git_dir: . -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/21/.git -setup: prefix: (null) -EOF - test_repo 21/.git -' - -test_expect_success '#21.1: in .git/wt' ' - cat >21/.git/wt/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/21/.git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/21/.git/wt -setup: prefix: (null) -EOF - test_repo 21/.git/wt -' - -test_expect_success '#21.1: in .git/wt/sub' ' - cat >21/.git/wt/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/21/.git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/21/.git/wt/sub -setup: prefix: (null) -EOF - test_repo 21/.git/wt/sub -' - -# -# case #21.2 -# -############################################################ -# -# Input: -# -# - GIT_WORK_TREE is set -# - GIT_DIR is not set -# - core.worktree is set -# - .git is a directory -# - core.bare is set -# -# Output: -# -# GIT_WORK_TREE/core.worktree are ignored -> #20.2 - -test_expect_success '#21.2: setup' ' - git config --file="$TRASH_DIRECTORY/21/.git/config" core.bare true -' - -test_expect_success '#21.2: at .git' ' - cat >21/.git/expected <<EOF && -setup: git_dir: . -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/21/.git -setup: prefix: (null) -EOF - test_repo 21/.git -' - -test_expect_success '#21.2: in .git/wt' ' - cat >21/.git/wt/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/21/.git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/21/.git/wt -setup: prefix: (null) -EOF - test_repo 21/.git/wt -' - -test_expect_success '#21.2: in .git/wt/sub' ' - cat >21/.git/wt/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/21/.git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/21/.git/wt/sub -setup: prefix: (null) -EOF - test_repo 21/.git/wt/sub -' - -test_expect_success '#21.2: at root' ' - cat >21/expected <<EOF && -setup: git_dir: .git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/21 -setup: prefix: (null) -EOF - test_repo 21 -' - -test_expect_success '#21.2: in subdir' ' - cat >21/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/21/.git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/21/sub -setup: prefix: (null) -EOF - test_repo 21/sub -' - -# -# case #22.1 -# -############################################################ -# -# Input: -# -# - GIT_WORK_TREE is not set -# - GIT_DIR is set -# - core.worktree is set -# - .git is a directory -# - cwd is inside .git -# -# Output: -# -# bare attribute is ignored -# -# - worktree is at core.worktree -# - cwd is at worktree root -# - prefix is calculated -# - git_dir is at $GIT_DIR -# - cwd can be outside worktree - -test_expect_success '#22.1: setup' ' - unset GIT_DIR GIT_WORK_TREE && - mkdir 22 && - cd 22 && - git init && - mkdir .git/sub .git/wt .git/wt/sub && - cd .. -' - -test_expect_success '#22.1: GIT_DIR(rel), core.worktree=. at .git' ' - cat >22/.git/expected <<EOF && -setup: git_dir: . -setup: worktree: $TRASH_DIRECTORY/22/.git -setup: cwd: $TRASH_DIRECTORY/22/.git -setup: prefix: (null) -EOF - git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree "$TRASH_DIRECTORY/22/.git" && - test_repo 22/.git . -' - -test_expect_success '#22.1: GIT_DIR(rel), core.worktree=.(rel) at .git' ' - cat >22/.git/expected <<EOF && -setup: git_dir: . -setup: worktree: $TRASH_DIRECTORY/22/.git -setup: cwd: $TRASH_DIRECTORY/22/.git -setup: prefix: (null) -EOF - git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree . && - test_repo 22/.git . -' - -test_expect_success '#22.1: GIT_DIR, core.worktree=. at .git' ' - cat >22/.git/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/22/.git -setup: worktree: $TRASH_DIRECTORY/22/.git -setup: cwd: $TRASH_DIRECTORY/22/.git -setup: prefix: (null) -EOF - git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree "$TRASH_DIRECTORY/22/.git" && - test_repo 22/.git "$TRASH_DIRECTORY/22/.git" -' - -test_expect_success '#22.1: GIT_DIR, core.worktree=.(rel) at root' ' - cat >22/.git/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/22/.git -setup: worktree: $TRASH_DIRECTORY/22/.git -setup: cwd: $TRASH_DIRECTORY/22/.git -setup: prefix: (null) -EOF - git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree . && - test_repo 22/.git "$TRASH_DIRECTORY/22/.git" -' - -test_expect_success '#22.1: GIT_DIR(rel), core.worktree=. in .git/sub' ' - cat >22/.git/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/22/.git -setup: worktree: $TRASH_DIRECTORY/22/.git -setup: cwd: $TRASH_DIRECTORY/22/.git -setup: prefix: sub/ -EOF - git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree "$TRASH_DIRECTORY/22/.git" && - test_repo 22/.git/sub .. -' - -test_expect_success '#22.1: GIT_DIR(rel), core.worktree=.(rel) in .git/sub' ' - cat >22/.git/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/22/.git -setup: worktree: $TRASH_DIRECTORY/22/.git -setup: cwd: $TRASH_DIRECTORY/22/.git -setup: prefix: sub/ -EOF - git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree . && - test_repo 22/.git/sub/ .. -' - -test_expect_success '#22.1: GIT_DIR, core.worktree=. in .git/sub' ' - cat >22/.git/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/22/.git -setup: worktree: $TRASH_DIRECTORY/22/.git -setup: cwd: $TRASH_DIRECTORY/22/.git -setup: prefix: sub/ -EOF - git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree "$TRASH_DIRECTORY/22/.git" && - test_repo 22/.git/sub "$TRASH_DIRECTORY/22/.git" -' - -test_expect_success '#22.1: GIT_DIR, core.worktree=.(rel) in .git/sub' ' - cat >22/.git/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/22/.git -setup: worktree: $TRASH_DIRECTORY/22/.git -setup: cwd: $TRASH_DIRECTORY/22/.git -setup: prefix: sub/ -EOF - git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree . && - test_repo 22/.git/sub "$TRASH_DIRECTORY/22/.git" -' - -test_expect_success '#22.1: GIT_DIR(rel), core.worktree=wt at .git' ' - cat >22/.git/expected <<EOF && -setup: git_dir: . -setup: worktree: $TRASH_DIRECTORY/22/.git/wt -setup: cwd: $TRASH_DIRECTORY/22/.git -setup: prefix: (null) -EOF - git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree "$TRASH_DIRECTORY/22/.git/wt" && - test_repo 22/.git . -' - -test_expect_success '#22.1: GIT_DIR(rel), core.worktree=wt(rel) at .git' ' - cat >22/.git/expected <<EOF && -setup: git_dir: . -setup: worktree: $TRASH_DIRECTORY/22/.git/wt -setup: cwd: $TRASH_DIRECTORY/22/.git -setup: prefix: (null) -EOF - git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree wt && - test_repo 22/.git . -' - -test_expect_success '#22.1: GIT_DIR, core.worktree=wt(rel) at .git' ' - cat >22/.git/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/22/.git -setup: worktree: $TRASH_DIRECTORY/22/.git/wt -setup: cwd: $TRASH_DIRECTORY/22/.git -setup: prefix: (null) -EOF - git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree wt && - test_repo 22/.git "$TRASH_DIRECTORY/22/.git" -' - -test_expect_success '#22.1: GIT_DIR, core.worktree=wt at .git' ' - cat >22/.git/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/22/.git -setup: worktree: $TRASH_DIRECTORY/22/.git/wt -setup: cwd: $TRASH_DIRECTORY/22/.git -setup: prefix: (null) -EOF - git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree "$TRASH_DIRECTORY/22/.git/wt" && - test_repo 22/.git "$TRASH_DIRECTORY/22/.git" -' - -test_expect_success '#22.1: GIT_DIR(rel), core.worktree=wt in .git/sub' ' - cat >22/.git/sub/expected <<EOF && -setup: git_dir: .. -setup: worktree: $TRASH_DIRECTORY/22/.git/wt -setup: cwd: $TRASH_DIRECTORY/22/.git/sub -setup: prefix: (null) -EOF - git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree "$TRASH_DIRECTORY/22/.git/wt" && - test_repo 22/.git/sub .. -' - -test_expect_success '#22.1: GIT_DIR(rel), core.worktree=wt(rel) in .git/sub' ' - cat >22/.git/sub/expected <<EOF && -setup: git_dir: .. -setup: worktree: $TRASH_DIRECTORY/22/.git/wt -setup: cwd: $TRASH_DIRECTORY/22/.git/sub -setup: prefix: (null) -EOF - git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree wt && - test_repo 22/.git/sub .. -' - -test_expect_success '#22.1: GIT_DIR, core.worktree=wt(rel) in .git/sub' ' - cat >22/.git/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/22/.git -setup: worktree: $TRASH_DIRECTORY/22/.git/wt -setup: cwd: $TRASH_DIRECTORY/22/.git/sub -setup: prefix: (null) -EOF - git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree wt && - test_repo 22/.git/sub "$TRASH_DIRECTORY/22/.git" -' - -test_expect_success '#22.1: GIT_DIR, core.worktree=wt in .git/sub' ' - cat >22/.git/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/22/.git -setup: worktree: $TRASH_DIRECTORY/22/.git/wt -setup: cwd: $TRASH_DIRECTORY/22/.git/sub -setup: prefix: (null) -EOF - git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree "$TRASH_DIRECTORY/22/.git/wt" && - test_repo 22/.git/sub "$TRASH_DIRECTORY/22/.git" -' - -test_expect_success '#22.1: GIT_DIR(rel), core.worktree=.. at .git' ' - cat >22/.git/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/22/.git -setup: worktree: $TRASH_DIRECTORY/22 -setup: cwd: $TRASH_DIRECTORY/22 -setup: prefix: .git/ -EOF - git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree "$TRASH_DIRECTORY/22" && - test_repo 22/.git . -' - -test_expect_success '#22.1: GIT_DIR(rel), core.worktree=..(rel) at .git' ' - cat >22/.git/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/22/.git -setup: worktree: $TRASH_DIRECTORY/22 -setup: cwd: $TRASH_DIRECTORY/22 -setup: prefix: .git/ -EOF - git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree .. && - test_repo 22/.git . -' - -test_expect_success '#22.1: GIT_DIR, core.worktree=..(rel) at .git' ' - cat >22/.git/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/22/.git -setup: worktree: $TRASH_DIRECTORY/22 -setup: cwd: $TRASH_DIRECTORY/22 -setup: prefix: .git/ -EOF - git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree .. && - test_repo 22/.git "$TRASH_DIRECTORY/22/.git" -' - -test_expect_success '#22.1: GIT_DIR, core.worktree=.. at .git' ' - cat >22/.git/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/22/.git -setup: worktree: $TRASH_DIRECTORY/22 -setup: cwd: $TRASH_DIRECTORY/22 -setup: prefix: .git/ -EOF - git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree "$TRASH_DIRECTORY/22" && - test_repo 22/.git "$TRASH_DIRECTORY/22/.git" -' - -test_expect_success '#22.1: GIT_DIR(rel), core.worktree=.. in .git/sub' ' - cat >22/.git/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/22/.git -setup: worktree: $TRASH_DIRECTORY/22 -setup: cwd: $TRASH_DIRECTORY/22 -setup: prefix: .git/sub/ -EOF - git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree "$TRASH_DIRECTORY/22" && - test_repo 22/.git/sub .. -' - -test_expect_success '#22.1: GIT_DIR(rel), core.worktree=..(rel) in .git/sub' ' - cat >22/.git/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/22/.git -setup: worktree: $TRASH_DIRECTORY/22 -setup: cwd: $TRASH_DIRECTORY/22 -setup: prefix: .git/sub/ -EOF - git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree .. && - test_repo 22/.git/sub .. -' - -test_expect_success '#22.1: GIT_DIR, core.worktree=..(rel) in .git/sub' ' - cat >22/.git/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/22/.git -setup: worktree: $TRASH_DIRECTORY/22 -setup: cwd: $TRASH_DIRECTORY/22 -setup: prefix: .git/sub/ -EOF - git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree .. && - test_repo 22/.git/sub "$TRASH_DIRECTORY/22/.git" -' - -test_expect_success '#22.1: GIT_DIR, core.worktree=.. in .git/sub' ' - cat >22/.git/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/22/.git -setup: worktree: $TRASH_DIRECTORY/22 -setup: cwd: $TRASH_DIRECTORY/22 -setup: prefix: .git/sub/ -EOF - git config --file="$TRASH_DIRECTORY/22/.git/config" core.worktree "$TRASH_DIRECTORY/22" && - test_repo 22/.git/sub "$TRASH_DIRECTORY/22/.git" -' - -# -# case #22.2 -# -############################################################ -# -# Input: -# -# - GIT_WORK_TREE is not set -# - GIT_DIR is set -# - core.worktree is set -# - .git is a directory -# - core.bare is set -# -# Output: -# -# core.worktree and core.bare conflict, won't fly. - -test_expect_success '#22.2: setup' ' - git config --file="$TRASH_DIRECTORY/22/.git/config" core.bare true -' - -test_expect_success '#22.2: at .git' ' + setup_repo 19 unset "" true && + mkdir -p 19/sub/sub 19/wt/sub +' +run_wt_tests 19 + +test_expect_success '#20a: core.worktree without GIT_DIR accepted (inside .git)' ' + # Unlike case #16a. + setup_repo 20a "$here/20a" "" unset && + mkdir -p 20a/.git/wt/sub && + try_case 20a/.git unset unset \ + "$here/20a/.git" "$here/20a" "$here/20a" .git/ 2>message && + try_case 20a/.git/wt unset unset \ + "$here/20a/.git" "$here/20a" "$here/20a" .git/wt/ && + try_case 20a/.git/wt/sub unset unset \ + "$here/20a/.git" "$here/20a" "$here/20a" .git/wt/sub/ && + ! test -s message +' + +test_expect_success '#20b/c: core.worktree and core.bare conflict' ' + setup_repo 20b non-existent "" true && + mkdir -p 20b/.git/wt/sub && ( - cd 22/.git && - GIT_DIR=. && - export GIT_DIR && - test_must_fail git symbolic-ref HEAD 2>result && - grep "core.bare and core.worktree do not make sense" result - ) + cd 20b/.git && + test_must_fail git symbolic-ref HEAD >/dev/null + ) 2>message && + grep "core.bare and core.worktree" message ' -test_expect_success '#22.2: at root' ' +# 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 && + mkdir -p 21/.git/wt/sub && ( - cd 22 && - GIT_DIR=.git && - export GIT_DIR && - test_must_fail git symbolic-ref HEAD 2>result && - grep "core.bare and core.worktree do not make sense" result - ) + cd 21/.git && + GIT_WORK_TREE="$here/21" && + export GIT_WORK_TREE && + git symbolic-ref HEAD >/dev/null + ) 2>message && + ! test -s message + +' +run_wt_tests 21 + +test_expect_success '#22a: core.worktree = GIT_DIR = .git dir' ' + # like case #6. + + setup_repo 22a "$here/22a/.git" "" unset && + setup_repo 22ab . "" unset + mkdir -p 22a/.git/sub 22a/sub && + mkdir -p 22ab/.git/sub 22ab/sub && + try_case 22a/.git unset . \ + . "$here/22a/.git" "$here/22a/.git" "(null)" && + try_case 22a/.git unset "$here/22a/.git" \ + "$here/22a/.git" "$here/22a/.git" "$here/22a/.git" "(null)" && + try_case 22a/.git/sub unset .. \ + "$here/22a/.git" "$here/22a/.git" "$here/22a/.git" sub/ && + try_case 22a/.git/sub unset "$here/22a/.git" \ + "$here/22a/.git" "$here/22a/.git" "$here/22a/.git" sub/ && + + try_case 22ab/.git unset . \ + . "$here/22ab/.git" "$here/22ab/.git" "(null)" && + try_case 22ab/.git unset "$here/22ab/.git" \ + "$here/22ab/.git" "$here/22ab/.git" "$here/22ab/.git" "(null)" && + try_case 22ab/.git/sub unset .. \ + "$here/22ab/.git" "$here/22ab/.git" "$here/22ab/.git" sub/ && + try_case 22ab/.git unset "$here/22ab/.git" \ + "$here/22ab/.git" "$here/22ab/.git" "$here/22ab/.git" "(null)" +' + +test_expect_success '#22b: core.worktree child of .git, GIT_DIR=.git' ' + setup_repo 22b "$here/22b/.git/wt" "" unset && + setup_repo 22bb wt "" unset && + mkdir -p 22b/.git/sub 22b/sub 22b/.git/wt/sub 22b/wt/sub && + mkdir -p 22bb/.git/sub 22bb/sub 22bb/.git/wt 22bb/wt && + + try_case 22b/.git unset . \ + . "$here/22b/.git/wt" "$here/22b/.git" "(null)" && + try_case 22b/.git unset "$here/22b/.git" \ + "$here/22b/.git" "$here/22b/.git/wt" "$here/22b/.git" "(null)" && + try_case 22b/.git/sub unset .. \ + .. "$here/22b/.git/wt" "$here/22b/.git/sub" "(null)" && + try_case 22b/.git/sub unset "$here/22b/.git" \ + "$here/22b/.git" "$here/22b/.git/wt" "$here/22b/.git/sub" "(null)" && + + try_case 22bb/.git unset . \ + . "$here/22bb/.git/wt" "$here/22bb/.git" "(null)" && + try_case 22bb/.git unset "$here/22bb/.git" \ + "$here/22bb/.git" "$here/22bb/.git/wt" "$here/22bb/.git" "(null)" && + try_case 22bb/.git/sub unset .. \ + .. "$here/22bb/.git/wt" "$here/22bb/.git/sub" "(null)" && + try_case 22bb/.git/sub unset "$here/22bb/.git" \ + "$here/22bb/.git" "$here/22bb/.git/wt" "$here/22bb/.git/sub" "(null)" +' + +test_expect_success '#22c: core.worktree = .git/.., GIT_DIR=.git' ' + setup_repo 22c "$here/22c" "" unset && + setup_repo 22cb .. "" unset && + mkdir -p 22c/.git/sub 22c/sub && + mkdir -p 22cb/.git/sub 22cb/sub && + + try_case 22c/.git unset . \ + "$here/22c/.git" "$here/22c" "$here/22c" .git/ && + try_case 22c/.git unset "$here/22c/.git" \ + "$here/22c/.git" "$here/22c" "$here/22c" .git/ && + try_case 22c/.git/sub unset .. \ + "$here/22c/.git" "$here/22c" "$here/22c" .git/sub/ && + try_case 22c/.git/sub unset "$here/22c/.git" \ + "$here/22c/.git" "$here/22c" "$here/22c" .git/sub/ && + + try_case 22cb/.git unset . \ + "$here/22cb/.git" "$here/22cb" "$here/22cb" .git/ && + try_case 22cb/.git unset "$here/22cb/.git" \ + "$here/22cb/.git" "$here/22cb" "$here/22cb" .git/ && + try_case 22cb/.git/sub unset .. \ + "$here/22cb/.git" "$here/22cb" "$here/22cb" .git/sub/ && + try_case 22cb/.git/sub unset "$here/22cb/.git" \ + "$here/22cb/.git" "$here/22cb" "$here/22cb" .git/sub/ +' + +test_expect_success '#22.2: core.worktree and core.bare conflict' ' + setup_repo 22 "$here/22" "" true && + ( + cd 22/.git && + GIT_DIR=. && + export GIT_DIR && + test_must_fail git symbolic-ref HEAD 2>result + ) && + ( + cd 22 && + GIT_DIR=.git && + export GIT_DIR && + test_must_fail git symbolic-ref HEAD 2>result + ) && + grep "core.bare and core.worktree" 22/.git/result && + grep "core.bare and core.worktree" 22/result ' -# -# case #23 -# -############################################################ -# -# Input: -# -# - GIT_WORK_TREE is set -# - GIT_DIR is set -# - core.worktree is set -# - .git is a directory -# - core.bare is set -# -# Output: -# -# core.worktree is overridden by GIT_WORK_TREE -> #19 - +# Case #23: GIT_DIR + GIT_WORK_TREE(+core.worktree) suppresses bareness. test_expect_success '#23: setup' ' - unset GIT_DIR GIT_WORK_TREE && - mkdir 23 23/sub 23/sub/sub 23.wt 23.wt/sub 23/wt 23/wt/sub && - cd 23 && - git init && - git config core.bare true && - git config core.worktree non-existent && - cd .. -' - -test_expect_success '#23: GIT_DIR(rel), GIT_WORK_TREE=root at root' ' - cat >23/expected <<EOF && -setup: git_dir: .git -setup: worktree: $TRASH_DIRECTORY/23 -setup: cwd: $TRASH_DIRECTORY/23 -setup: prefix: (null) -EOF - test_repo 23 .git "$TRASH_DIRECTORY/23" -' - -test_expect_success '#23: GIT_DIR(rel), GIT_WORK_TREE=root(rel) at root' ' - cat >23/expected <<EOF && -setup: git_dir: .git -setup: worktree: $TRASH_DIRECTORY/23 -setup: cwd: $TRASH_DIRECTORY/23 -setup: prefix: (null) -EOF - test_repo 23 .git . -' - -test_expect_success '#23: GIT_DIR, GIT_WORK_TREE=root at root' ' - cat >23/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/23/.git -setup: worktree: $TRASH_DIRECTORY/23 -setup: cwd: $TRASH_DIRECTORY/23 -setup: prefix: (null) -EOF - test_repo 23 "$TRASH_DIRECTORY/23/.git" "$TRASH_DIRECTORY/23" -' - -test_expect_success '#23: GIT_DIR, GIT_WORK_TREE=root(rel) at root' ' - cat >23/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/23/.git -setup: worktree: $TRASH_DIRECTORY/23 -setup: cwd: $TRASH_DIRECTORY/23 -setup: prefix: (null) -EOF - test_repo 23 "$TRASH_DIRECTORY/23/.git" . -' - -test_expect_success '#23: GIT_DIR(rel), GIT_WORKTREE=root in subdir' ' - cat >23/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/23/.git -setup: worktree: $TRASH_DIRECTORY/23 -setup: cwd: $TRASH_DIRECTORY/23 -setup: prefix: sub/sub/ -EOF - test_repo 23/sub/sub ../../.git "$TRASH_DIRECTORY/23" -' - -test_expect_success '#23: GIT_DIR(rel), GIT_WORKTREE=root(rel) in subdir' ' - cat >23/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/23/.git -setup: worktree: $TRASH_DIRECTORY/23 -setup: cwd: $TRASH_DIRECTORY/23 -setup: prefix: sub/sub/ -EOF - test_repo 23/sub/sub ../../.git ../.. -' - -test_expect_success '#23: GIT_DIR, GIT_WORKTREE=root in subdir' ' - cat >23/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/23/.git -setup: worktree: $TRASH_DIRECTORY/23 -setup: cwd: $TRASH_DIRECTORY/23 -setup: prefix: sub/ -EOF - test_repo 23/sub "$TRASH_DIRECTORY/23/.git" "$TRASH_DIRECTORY/23" -' - -test_expect_success '#23: GIT_DIR, GIT_WORKTREE=root(rel) in subdir' ' - cat >23/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/23/.git -setup: worktree: $TRASH_DIRECTORY/23 -setup: cwd: $TRASH_DIRECTORY/23 -setup: prefix: sub/sub/ -EOF - test_repo 23/sub/sub "$TRASH_DIRECTORY/23/.git" ../.. -' - -test_expect_success '#23: GIT_DIR(rel), GIT_WORK_TREE=wt at root' ' - cat >23/expected <<EOF && -setup: git_dir: .git -setup: worktree: $TRASH_DIRECTORY/23/wt -setup: cwd: $TRASH_DIRECTORY/23 -setup: prefix: (null) -EOF - test_repo 23 .git "$TRASH_DIRECTORY/23/wt" -' - -test_expect_success '#23: GIT_DIR(rel), GIT_WORK_TREE=wt(rel) at root' ' - cat >23/expected <<EOF && -setup: git_dir: .git -setup: worktree: $TRASH_DIRECTORY/23/wt -setup: cwd: $TRASH_DIRECTORY/23 -setup: prefix: (null) -EOF - test_repo 23 .git wt -' - -test_expect_success '#23: GIT_DIR, GIT_WORK_TREE=wt(rel) at root' ' - cat >23/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/23/.git -setup: worktree: $TRASH_DIRECTORY/23/wt -setup: cwd: $TRASH_DIRECTORY/23 -setup: prefix: (null) -EOF - test_repo 23 "$TRASH_DIRECTORY/23/.git" wt -' - -test_expect_success '#23: GIT_DIR, GIT_WORK_TREE=wt at root' ' - cat >23/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/23/.git -setup: worktree: $TRASH_DIRECTORY/23/wt -setup: cwd: $TRASH_DIRECTORY/23 -setup: prefix: (null) -EOF - test_repo 23 "$TRASH_DIRECTORY/23/.git" "$TRASH_DIRECTORY/23/wt" -' - -test_expect_success '#23: GIT_DIR(rel), GIT_WORK_TREE=wt in subdir' ' - cat >23/sub/sub/expected <<EOF && -setup: git_dir: ../../.git -setup: worktree: $TRASH_DIRECTORY/23/wt -setup: cwd: $TRASH_DIRECTORY/23/sub/sub -setup: prefix: (null) -EOF - test_repo 23/sub/sub ../../.git "$TRASH_DIRECTORY/23/wt" -' - -test_expect_success '#23: GIT_DIR(rel), GIT_WORK_TREE=wt(rel) in subdir' ' - cat >23/sub/sub/expected <<EOF && -setup: git_dir: ../../.git -setup: worktree: $TRASH_DIRECTORY/23/wt -setup: cwd: $TRASH_DIRECTORY/23/sub/sub -setup: prefix: (null) -EOF - test_repo 23/sub/sub ../../.git ../../wt -' - -test_expect_success '#23: GIT_DIR, GIT_WORK_TREE=wt(rel) in subdir' ' - cat >23/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/23/.git -setup: worktree: $TRASH_DIRECTORY/23/wt -setup: cwd: $TRASH_DIRECTORY/23/sub/sub -setup: prefix: (null) -EOF - test_repo 23/sub/sub "$TRASH_DIRECTORY/23/.git" ../../wt -' - -test_expect_success '#23: GIT_DIR, GIT_WORK_TREE=wt in subdir' ' - cat >23/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/23/.git -setup: worktree: $TRASH_DIRECTORY/23/wt -setup: cwd: $TRASH_DIRECTORY/23/sub/sub -setup: prefix: (null) -EOF - test_repo 23/sub/sub "$TRASH_DIRECTORY/23/.git" "$TRASH_DIRECTORY/23/wt" -' - -test_expect_success '#23: GIT_DIR(rel), GIT_WORK_TREE=.. at root' ' - cat >23/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/23/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 23/ -EOF - test_repo 23 .git "$TRASH_DIRECTORY" -' - -test_expect_success '#23: GIT_DIR(rel), GIT_WORK_TREE=..(rel) at root' ' - cat >23/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/23/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 23/ -EOF - test_repo 23 .git .. -' - -test_expect_success '#23: GIT_DIR, GIT_WORK_TREE=..(rel) at root' ' - cat >23/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/23/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 23/ -EOF - test_repo 23 "$TRASH_DIRECTORY/23/.git" .. -' - -test_expect_success '#23: GIT_DIR, GIT_WORK_TREE=.. at root' ' - cat >23/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/23/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 23/ -EOF - test_repo 23 "$TRASH_DIRECTORY/23/.git" "$TRASH_DIRECTORY" -' - -test_expect_success '#23: GIT_DIR(rel), GIT_WORK_TREE=.. in subdir' ' - cat >23/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/23/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 23/sub/sub/ -EOF - test_repo 23/sub/sub ../../.git "$TRASH_DIRECTORY" -' - -test_expect_success '#23: GIT_DIR(rel), GIT_WORK_TREE=..(rel) in subdir' ' - cat >23/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/23/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 23/sub/sub/ -EOF - test_repo 23/sub/sub ../../.git ../../.. -' - -test_expect_success '#23: GIT_DIR, GIT_WORK_TREE=..(rel) in subdir' ' - cat >23/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/23/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 23/sub/sub/ -EOF - test_repo 23/sub/sub "$TRASH_DIRECTORY/23/.git" ../../../ -' - -test_expect_success '#23: GIT_DIR, GIT_WORK_TREE=.. in subdir' ' - cat >23/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/23/.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 23/sub/sub/ -EOF - test_repo 23/sub/sub "$TRASH_DIRECTORY/23/.git" "$TRASH_DIRECTORY" -' - -# -# case #24 -# -############################################################ -# -# Input: -# -# - GIT_WORK_TREE is not set -# - GIT_DIR is not set -# - core.worktree is not set -# - .git is a file -# - core.bare is set -# -# Output: -# -# #16.2 except git_dir is set according to .git file - -test_expect_success '#24: setup' ' - unset GIT_DIR GIT_WORK_TREE && - mkdir 24 24/sub && - cd 24 && - git init && - git config core.bare true && - mv .git ../24.git && - echo gitdir: ../24.git >.git && - cd .. -' - -test_expect_success '#24: at root' ' - cat >24/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/24.git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/24 -setup: prefix: (null) -EOF - test_repo 24 -' - -test_expect_success '#24: in subdir' ' - cat >24/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/24.git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/24/sub -setup: prefix: (null) -EOF - test_repo 24/sub -' - -# -# case #25 -# -############################################################ -# -# Input: -# -# - GIT_WORK_TREE is set -# - GIT_DIR is not set -# - core.worktree is not set -# - .git is a file -# - core.bare is set -# -# Output: -# -# #17.2 except git_dir is set according to .git file - -test_expect_success '#25: setup' ' - unset GIT_DIR GIT_WORK_TREE && - mkdir 25 25/sub && - cd 25 && - git init && - git config core.bare true && - GIT_WORK_TREE=non-existent && - export GIT_WORK_TREE && - mv .git ../25.git && - echo gitdir: ../25.git >.git && - cd .. -' - -test_expect_success '#25: at root' ' - cat >25/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/25.git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/25 -setup: prefix: (null) -EOF - test_repo 25 -' - -test_expect_success '#25: in subdir' ' - cat >25/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/25.git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/25/sub -setup: prefix: (null) -EOF - test_repo 25/sub -' - -# -# case #26 -# -############################################################ -# -# Input: -# -# - GIT_WORK_TREE is not set -# - GIT_DIR is set -# - core.worktree is not set -# - .git is a file -# - core.bare is set -# -# Output: -# -# #18 except git_dir is set according to .git file - -test_expect_success '#26: setup' ' - unset GIT_DIR GIT_WORK_TREE && - mkdir 26 26/sub && - cd 26 && - git init && - git config core.bare true && - mv .git ../26.git && - echo gitdir: ../26.git >.git && - cd .. -' - -test_expect_success '#26: (rel) at root' ' - cat >26/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/26.git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/26 -setup: prefix: (null) -EOF - test_repo 26 .git + setup_repo 23 non-existent "" true && + mkdir -p 23/sub/sub 23/wt/sub ' +run_wt_tests 23 -test_expect_success '#26: at root' ' - cat >26/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/26.git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/26 -setup: prefix: (null) -EOF - test_repo 26 "$TRASH_DIRECTORY/26/.git" +test_expect_success '#24: bare repo has no worktree (gitfile case)' ' + try_repo 24 unset unset unset gitfile true \ + "$here/24.git" "(null)" "$here/24" "(null)" \ + "$here/24.git" "(null)" "$here/24/sub" "(null)" ' -test_expect_success '#26: (rel) in subdir' ' - cat >26/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/26.git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/26/sub -setup: prefix: (null) -EOF - test_repo 26/sub ../.git +test_expect_success '#25: GIT_WORK_TREE accepted if GIT_DIR unset (bare gitfile case)' ' + try_repo 25 "$here/25" unset unset gitfile true \ + "$here/25.git" "$here/25" "$here/25" "(null)" \ + "$here/25.git" "$here/25" "$here/25" "sub/" 2>message && + ! test -s message ' -test_expect_success '#26: in subdir' ' - cat >26/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/26.git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/26/sub -setup: prefix: (null) -EOF - test_repo 26/sub "$TRASH_DIRECTORY/26/.git" +test_expect_success '#26: bare repo has no worktree (GIT_DIR -> gitfile case)' ' + try_repo 26 unset "$here/26/.git" unset gitfile true \ + "$here/26.git" "(null)" "$here/26" "(null)" \ + "$here/26.git" "(null)" "$here/26/sub" "(null)" && + try_repo 26b unset .git unset gitfile true \ + "$here/26b.git" "(null)" "$here/26b" "(null)" \ + "$here/26b.git" "(null)" "$here/26b/sub" "(null)" ' -# -# case #27 -# -############################################################ -# -# Input: -# -# - GIT_WORK_TREE is set -# - GIT_DIR is set -# - .git is a file -# - core.worktree is not set -# - core.bare is set -# -# Output: -# -# #19 except git_dir is set according to .git file - +# Case #27: GIT_DIR + GIT_WORK_TREE suppresses bareness (with gitfile). test_expect_success '#27: setup' ' - unset GIT_DIR GIT_WORK_TREE && - mkdir 27 27/sub 27/sub/sub 27.wt 27.wt/sub 27/wt 27/wt/sub && - cd 27 && - git init && - git config core.bare true && - mv .git ../27.git && - echo gitdir: ../27.git >.git && - cd .. -' - -test_expect_success '#27: GIT_DIR(rel), GIT_WORK_TREE=root at root' ' - cat >27/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/27.git -setup: worktree: $TRASH_DIRECTORY/27 -setup: cwd: $TRASH_DIRECTORY/27 -setup: prefix: (null) -EOF - test_repo 27 .git "$TRASH_DIRECTORY/27" -' - -test_expect_success '#27: GIT_DIR(rel), GIT_WORK_TREE=root(rel) at root' ' - cat >27/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/27.git -setup: worktree: $TRASH_DIRECTORY/27 -setup: cwd: $TRASH_DIRECTORY/27 -setup: prefix: (null) -EOF - test_repo 27 .git . -' - -test_expect_success '#27: GIT_DIR, GIT_WORK_TREE=root at root' ' - cat >27/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/27.git -setup: worktree: $TRASH_DIRECTORY/27 -setup: cwd: $TRASH_DIRECTORY/27 -setup: prefix: (null) -EOF - test_repo 27 "$TRASH_DIRECTORY/27/.git" "$TRASH_DIRECTORY/27" -' - -test_expect_success '#27: GIT_DIR, GIT_WORK_TREE=root(rel) at root' ' - cat >27/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/27.git -setup: worktree: $TRASH_DIRECTORY/27 -setup: cwd: $TRASH_DIRECTORY/27 -setup: prefix: (null) -EOF - test_repo 27 "$TRASH_DIRECTORY/27/.git" . -' - -test_expect_success '#27: GIT_DIR(rel), GIT_WORKTREE=root in subdir' ' - cat >27/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/27.git -setup: worktree: $TRASH_DIRECTORY/27 -setup: cwd: $TRASH_DIRECTORY/27 -setup: prefix: sub/sub/ -EOF - test_repo 27/sub/sub ../../.git "$TRASH_DIRECTORY/27" -' - -test_expect_success '#27: GIT_DIR(rel), GIT_WORKTREE=root(rel) in subdir' ' - cat >27/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/27.git -setup: worktree: $TRASH_DIRECTORY/27 -setup: cwd: $TRASH_DIRECTORY/27 -setup: prefix: sub/sub/ -EOF - test_repo 27/sub/sub ../../.git ../.. -' - -test_expect_success '#27: GIT_DIR, GIT_WORKTREE=root in subdir' ' - cat >27/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/27.git -setup: worktree: $TRASH_DIRECTORY/27 -setup: cwd: $TRASH_DIRECTORY/27 -setup: prefix: sub/ -EOF - test_repo 27/sub "$TRASH_DIRECTORY/27/.git" "$TRASH_DIRECTORY/27" -' - -test_expect_success '#27: GIT_DIR, GIT_WORKTREE=root(rel) in subdir' ' - cat >27/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/27.git -setup: worktree: $TRASH_DIRECTORY/27 -setup: cwd: $TRASH_DIRECTORY/27 -setup: prefix: sub/sub/ -EOF - test_repo 27/sub/sub "$TRASH_DIRECTORY/27/.git" ../.. -' - -test_expect_success '#27: GIT_DIR(rel), GIT_WORK_TREE=wt at root' ' - cat >27/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/27.git -setup: worktree: $TRASH_DIRECTORY/27/wt -setup: cwd: $TRASH_DIRECTORY/27 -setup: prefix: (null) -EOF - test_repo 27 .git "$TRASH_DIRECTORY/27/wt" -' - -test_expect_success '#27: GIT_DIR(rel), GIT_WORK_TREE=wt(rel) at root' ' - cat >27/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/27.git -setup: worktree: $TRASH_DIRECTORY/27/wt -setup: cwd: $TRASH_DIRECTORY/27 -setup: prefix: (null) -EOF - test_repo 27 .git wt -' - -test_expect_success '#27: GIT_DIR, GIT_WORK_TREE=wt(rel) at root' ' - cat >27/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/27.git -setup: worktree: $TRASH_DIRECTORY/27/wt -setup: cwd: $TRASH_DIRECTORY/27 -setup: prefix: (null) -EOF - test_repo 27 "$TRASH_DIRECTORY/27/.git" wt -' - -test_expect_success '#27: GIT_DIR, GIT_WORK_TREE=wt at root' ' - cat >27/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/27.git -setup: worktree: $TRASH_DIRECTORY/27/wt -setup: cwd: $TRASH_DIRECTORY/27 -setup: prefix: (null) -EOF - test_repo 27 "$TRASH_DIRECTORY/27/.git" "$TRASH_DIRECTORY/27/wt" -' - -test_expect_success '#27: GIT_DIR(rel), GIT_WORK_TREE=wt in subdir' ' - cat >27/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/27.git -setup: worktree: $TRASH_DIRECTORY/27/wt -setup: cwd: $TRASH_DIRECTORY/27/sub/sub -setup: prefix: (null) -EOF - test_repo 27/sub/sub ../../.git "$TRASH_DIRECTORY/27/wt" -' - -test_expect_success '#27: GIT_DIR(rel), GIT_WORK_TREE=wt(rel) in subdir' ' - cat >27/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/27.git -setup: worktree: $TRASH_DIRECTORY/27/wt -setup: cwd: $TRASH_DIRECTORY/27/sub/sub -setup: prefix: (null) -EOF - test_repo 27/sub/sub ../../.git ../../wt -' - -test_expect_success '#27: GIT_DIR, GIT_WORK_TREE=wt(rel) in subdir' ' - cat >27/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/27.git -setup: worktree: $TRASH_DIRECTORY/27/wt -setup: cwd: $TRASH_DIRECTORY/27/sub/sub -setup: prefix: (null) -EOF - test_repo 27/sub/sub "$TRASH_DIRECTORY/27/.git" ../../wt -' - -test_expect_success '#27: GIT_DIR, GIT_WORK_TREE=wt in subdir' ' - cat >27/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/27.git -setup: worktree: $TRASH_DIRECTORY/27/wt -setup: cwd: $TRASH_DIRECTORY/27/sub/sub -setup: prefix: (null) -EOF - test_repo 27/sub/sub "$TRASH_DIRECTORY/27/.git" "$TRASH_DIRECTORY/27/wt" -' - -test_expect_success '#27: GIT_DIR(rel), GIT_WORK_TREE=.. at root' ' - cat >27/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/27.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 27/ -EOF - test_repo 27 .git "$TRASH_DIRECTORY" -' - -test_expect_success '#27: GIT_DIR(rel), GIT_WORK_TREE=..(rel) at root' ' - cat >27/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/27.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 27/ -EOF - test_repo 27 .git .. -' - -test_expect_success '#27: GIT_DIR, GIT_WORK_TREE=..(rel) at root' ' - cat >27/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/27.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 27/ -EOF - test_repo 27 "$TRASH_DIRECTORY/27/.git" .. -' - -test_expect_success '#27: GIT_DIR, GIT_WORK_TREE=.. at root' ' - cat >27/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/27.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 27/ -EOF - test_repo 27 "$TRASH_DIRECTORY/27/.git" "$TRASH_DIRECTORY" -' - -test_expect_success '#27: GIT_DIR(rel), GIT_WORK_TREE=.. in subdir' ' - cat >27/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/27.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 27/sub/sub/ -EOF - test_repo 27/sub/sub ../../.git "$TRASH_DIRECTORY" -' - -test_expect_success '#27: GIT_DIR(rel), GIT_WORK_TREE=..(rel) in subdir' ' - cat >27/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/27.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 27/sub/sub/ -EOF - test_repo 27/sub/sub ../../.git ../../.. -' - -test_expect_success '#27: GIT_DIR, GIT_WORK_TREE=..(rel) in subdir' ' - cat >27/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/27.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 27/sub/sub/ -EOF - test_repo 27/sub/sub "$TRASH_DIRECTORY/27/.git" ../../../ -' - -test_expect_success '#27: GIT_DIR, GIT_WORK_TREE=.. in subdir' ' - cat >27/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/27.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 27/sub/sub/ -EOF - test_repo 27/sub/sub "$TRASH_DIRECTORY/27/.git" "$TRASH_DIRECTORY" -' - -# -# case #28 -# -############################################################ -# -# Input: -# -# - GIT_WORK_TREE is not set -# - GIT_DIR is not set -# - core.worktree is set -# - .git is a file -# - core.bare is set -# -# Output: -# -# core.worktree is ignored -> #24 - -test_expect_success '#28: setup' ' - unset GIT_DIR GIT_WORK_TREE && - mkdir 28 28/sub && - cd 28 && - git init && - git config core.bare true && - git config core.worktree non-existent && - mv .git ../28.git && - echo gitdir: ../28.git >.git && - cd .. -' - -test_expect_success '#28: at root' ' - cat >28/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/28.git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/28 -setup: prefix: (null) -EOF - test_repo 28 + setup_repo 27 unset gitfile true && + mkdir -p 27/sub/sub 27/wt/sub ' +run_wt_tests 27 gitfile -test_expect_success '#28: in subdir' ' - cat >28/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/28.git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/28/sub -setup: prefix: (null) -EOF - test_repo 28/sub +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 + ) 2>message && + ! grep "^warning:" message && + grep "core.bare and core.worktree" message ' -# -# case #29 -# -############################################################ -# -# Input: -# -# - GIT_WORK_TREE is set -# - GIT_DIR is not set -# - core.worktree is set -# - .git is a file -# - core.bare is set -# -# Output: -# -# GIT_WORK_TREE/core.worktree are ignored -> #28 - +# Case #29: GIT_WORK_TREE(+core.worktree) overrides core.bare (gitfile case). test_expect_success '#29: setup' ' - unset GIT_DIR GIT_WORK_TREE && - mkdir 29 29/sub && - cd 29 && - git init && - git config core.bare true && - GIT_WORK_TREE=non-existent && - export GIT_WORK_TREE && - mv .git ../29.git && - echo gitdir: ../29.git >.git && - cd .. -' - -test_expect_success '#29: at root' ' - cat >29/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/29.git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/29 -setup: prefix: (null) -EOF - test_repo 29 -' - -test_expect_success '#29: in subdir' ' - cat >29/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/29.git -setup: worktree: (null) -setup: cwd: $TRASH_DIRECTORY/29/sub -setup: prefix: (null) -EOF - test_repo 29/sub -' - -# -# case #30 -# -############################################################ -# -# Input: -# -# - GIT_WORK_TREE is not set -# - GIT_DIR is set -# - core.worktree is set -# - .git is a file -# - core.bare is set -# -# Output: -# -# core.worktree and core.bare conflict, won't fly. - -test_expect_success '#30: setup' ' - unset GIT_DIR GIT_WORK_TREE && - mkdir 30 && - cd 30 && - git init && - git config core.bare true && - git config core.worktree non-existent && - mv .git ../30.git && - echo gitdir: ../30.git >.git && - cd .. -' - -test_expect_success '#30: at root' ' + setup_repo 29 non-existent gitfile true && + mkdir -p 29/sub/sub 29/wt/sub ( - cd 30 && - GIT_DIR=.git && - export GIT_DIR && - test_must_fail git symbolic-ref HEAD 2>result && - grep "core.bare and core.worktree do not make sense" result - ) + cd 29 && + GIT_WORK_TREE="$here/29" && + export GIT_WORK_TREE && + git symbolic-ref HEAD >/dev/null + ) 2>message && + ! test -s message +' +run_wt_tests 29 gitfile + +test_expect_success '#30: core.worktree and core.bare conflict (gitfile version)' ' + # Just like case #22. + setup_repo 30 "$here/30" gitfile true && + ( + cd 30 && + GIT_DIR=.git && + export GIT_DIR && + test_must_fail git symbolic-ref HEAD 2>result + ) && + grep "core.bare and core.worktree" 30/result ' -# -# case #31 -# -############################################################ -# -# Input: -# -# - GIT_WORK_TREE is set -# - GIT_DIR is set -# - core.worktree is set -# - .git is a file -# - core.bare is set -# -# Output: -# -# #23 except git_dir is set according to .git file - +# Case #31: GIT_DIR + GIT_WORK_TREE(+core.worktree) suppresses +# bareness (gitfile version). test_expect_success '#31: setup' ' - unset GIT_DIR GIT_WORK_TREE && - mkdir 31 31/sub 31/sub/sub 31.wt 31.wt/sub 31/wt 31/wt/sub && - cd 31 && - git init && - git config core.bare true && - git config core.worktree non-existent && - mv .git ../31.git && - echo gitdir: ../31.git >.git && - cd .. -' - -test_expect_success '#31: GIT_DIR(rel), GIT_WORK_TREE=root at root' ' - cat >31/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/31.git -setup: worktree: $TRASH_DIRECTORY/31 -setup: cwd: $TRASH_DIRECTORY/31 -setup: prefix: (null) -EOF - test_repo 31 .git "$TRASH_DIRECTORY/31" -' - -test_expect_success '#31: GIT_DIR(rel), GIT_WORK_TREE=root(rel) at root' ' - cat >31/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/31.git -setup: worktree: $TRASH_DIRECTORY/31 -setup: cwd: $TRASH_DIRECTORY/31 -setup: prefix: (null) -EOF - test_repo 31 .git . -' - -test_expect_success '#31: GIT_DIR, GIT_WORK_TREE=root at root' ' - cat >31/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/31.git -setup: worktree: $TRASH_DIRECTORY/31 -setup: cwd: $TRASH_DIRECTORY/31 -setup: prefix: (null) -EOF - test_repo 31 "$TRASH_DIRECTORY/31/.git" "$TRASH_DIRECTORY/31" -' - -test_expect_success '#31: GIT_DIR, GIT_WORK_TREE=root(rel) at root' ' - cat >31/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/31.git -setup: worktree: $TRASH_DIRECTORY/31 -setup: cwd: $TRASH_DIRECTORY/31 -setup: prefix: (null) -EOF - test_repo 31 "$TRASH_DIRECTORY/31/.git" . -' - -test_expect_success '#31: GIT_DIR(rel), GIT_WORKTREE=root in subdir' ' - cat >31/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/31.git -setup: worktree: $TRASH_DIRECTORY/31 -setup: cwd: $TRASH_DIRECTORY/31 -setup: prefix: sub/sub/ -EOF - test_repo 31/sub/sub ../../.git "$TRASH_DIRECTORY/31" -' - -test_expect_success '#31: GIT_DIR(rel), GIT_WORKTREE=root(rel) in subdir' ' - cat >31/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/31.git -setup: worktree: $TRASH_DIRECTORY/31 -setup: cwd: $TRASH_DIRECTORY/31 -setup: prefix: sub/sub/ -EOF - test_repo 31/sub/sub ../../.git ../.. -' - -test_expect_success '#31: GIT_DIR, GIT_WORKTREE=root in subdir' ' - cat >31/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/31.git -setup: worktree: $TRASH_DIRECTORY/31 -setup: cwd: $TRASH_DIRECTORY/31 -setup: prefix: sub/ -EOF - test_repo 31/sub "$TRASH_DIRECTORY/31/.git" "$TRASH_DIRECTORY/31" -' - -test_expect_success '#31: GIT_DIR, GIT_WORKTREE=root(rel) in subdir' ' - cat >31/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/31.git -setup: worktree: $TRASH_DIRECTORY/31 -setup: cwd: $TRASH_DIRECTORY/31 -setup: prefix: sub/sub/ -EOF - test_repo 31/sub/sub "$TRASH_DIRECTORY/31/.git" ../.. -' - -test_expect_success '#31: GIT_DIR(rel), GIT_WORK_TREE=wt at root' ' - cat >31/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/31.git -setup: worktree: $TRASH_DIRECTORY/31/wt -setup: cwd: $TRASH_DIRECTORY/31 -setup: prefix: (null) -EOF - test_repo 31 .git "$TRASH_DIRECTORY/31/wt" -' - -test_expect_success '#31: GIT_DIR(rel), GIT_WORK_TREE=wt(rel) at root' ' - cat >31/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/31.git -setup: worktree: $TRASH_DIRECTORY/31/wt -setup: cwd: $TRASH_DIRECTORY/31 -setup: prefix: (null) -EOF - test_repo 31 .git wt -' - -test_expect_success '#31: GIT_DIR, GIT_WORK_TREE=wt(rel) at root' ' - cat >31/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/31.git -setup: worktree: $TRASH_DIRECTORY/31/wt -setup: cwd: $TRASH_DIRECTORY/31 -setup: prefix: (null) -EOF - test_repo 31 "$TRASH_DIRECTORY/31/.git" wt -' - -test_expect_success '#31: GIT_DIR, GIT_WORK_TREE=wt at root' ' - cat >31/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/31.git -setup: worktree: $TRASH_DIRECTORY/31/wt -setup: cwd: $TRASH_DIRECTORY/31 -setup: prefix: (null) -EOF - test_repo 31 "$TRASH_DIRECTORY/31/.git" "$TRASH_DIRECTORY/31/wt" -' - -test_expect_success '#31: GIT_DIR(rel), GIT_WORK_TREE=wt in subdir' ' - cat >31/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/31.git -setup: worktree: $TRASH_DIRECTORY/31/wt -setup: cwd: $TRASH_DIRECTORY/31/sub/sub -setup: prefix: (null) -EOF - test_repo 31/sub/sub ../../.git "$TRASH_DIRECTORY/31/wt" -' - -test_expect_success '#31: GIT_DIR(rel), GIT_WORK_TREE=wt(rel) in subdir' ' - cat >31/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/31.git -setup: worktree: $TRASH_DIRECTORY/31/wt -setup: cwd: $TRASH_DIRECTORY/31/sub/sub -setup: prefix: (null) -EOF - test_repo 31/sub/sub ../../.git ../../wt -' - -test_expect_success '#31: GIT_DIR, GIT_WORK_TREE=wt(rel) in subdir' ' - cat >31/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/31.git -setup: worktree: $TRASH_DIRECTORY/31/wt -setup: cwd: $TRASH_DIRECTORY/31/sub/sub -setup: prefix: (null) -EOF - test_repo 31/sub/sub "$TRASH_DIRECTORY/31/.git" ../../wt -' - -test_expect_success '#31: GIT_DIR, GIT_WORK_TREE=wt in subdir' ' - cat >31/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/31.git -setup: worktree: $TRASH_DIRECTORY/31/wt -setup: cwd: $TRASH_DIRECTORY/31/sub/sub -setup: prefix: (null) -EOF - test_repo 31/sub/sub "$TRASH_DIRECTORY/31/.git" "$TRASH_DIRECTORY/31/wt" -' - -test_expect_success '#31: GIT_DIR(rel), GIT_WORK_TREE=.. at root' ' - cat >31/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/31.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 31/ -EOF - test_repo 31 .git "$TRASH_DIRECTORY" -' - -test_expect_success '#31: GIT_DIR(rel), GIT_WORK_TREE=..(rel) at root' ' - cat >31/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/31.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 31/ -EOF - test_repo 31 .git .. -' - -test_expect_success '#31: GIT_DIR, GIT_WORK_TREE=..(rel) at root' ' - cat >31/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/31.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 31/ -EOF - test_repo 31 "$TRASH_DIRECTORY/31/.git" .. -' - -test_expect_success '#31: GIT_DIR, GIT_WORK_TREE=.. at root' ' - cat >31/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/31.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 31/ -EOF - test_repo 31 "$TRASH_DIRECTORY/31/.git" "$TRASH_DIRECTORY" -' - -test_expect_success '#31: GIT_DIR(rel), GIT_WORK_TREE=.. in subdir' ' - cat >31/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/31.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 31/sub/sub/ -EOF - test_repo 31/sub/sub ../../.git "$TRASH_DIRECTORY" -' - -test_expect_success '#31: GIT_DIR(rel), GIT_WORK_TREE=..(rel) in subdir' ' - cat >31/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/31.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 31/sub/sub/ -EOF - test_repo 31/sub/sub ../../.git ../../.. -' - -test_expect_success '#31: GIT_DIR, GIT_WORK_TREE=..(rel) in subdir' ' - cat >31/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/31.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 31/sub/sub/ -EOF - test_repo 31/sub/sub "$TRASH_DIRECTORY/31/.git" ../../../ -' - -test_expect_success '#31: GIT_DIR, GIT_WORK_TREE=.. in subdir' ' - cat >31/sub/sub/expected <<EOF && -setup: git_dir: $TRASH_DIRECTORY/31.git -setup: worktree: $TRASH_DIRECTORY -setup: cwd: $TRASH_DIRECTORY -setup: prefix: 31/sub/sub/ -EOF - test_repo 31/sub/sub "$TRASH_DIRECTORY/31/.git" "$TRASH_DIRECTORY" + setup_repo 31 non-existent gitfile true && + mkdir -p 31/sub/sub 31/wt/sub ' +run_wt_tests 31 gitfile test_done diff --git a/t/t2019-checkout-ambiguous-ref.sh b/t/t2019-checkout-ambiguous-ref.sh new file mode 100755 index 000000000..943541d40 --- /dev/null +++ b/t/t2019-checkout-ambiguous-ref.sh @@ -0,0 +1,59 @@ +#!/bin/sh + +test_description='checkout handling of ambiguous (branch/tag) refs' +. ./test-lib.sh + +test_expect_success 'setup ambiguous refs' ' + test_commit branch file && + git branch ambiguity && + git branch vagueness && + test_commit tag file && + git tag ambiguity && + git tag vagueness HEAD:file && + test_commit other file +' + +test_expect_success 'checkout ambiguous ref succeeds' ' + git checkout ambiguity >stdout 2>stderr +' + +test_expect_success 'checkout produces ambiguity warning' ' + grep "warning.*ambiguous" stderr +' + +test_expect_success 'checkout chooses branch over tag' ' + echo refs/heads/ambiguity >expect && + git symbolic-ref HEAD >actual && + test_cmp expect actual && + echo branch >expect && + test_cmp expect file +' + +test_expect_success 'checkout reports switch to branch' ' + grep "Switched to branch" stderr && + ! grep "^HEAD is now at" stderr +' + +test_expect_success 'checkout vague ref succeeds' ' + git checkout vagueness >stdout 2>stderr && + test_set_prereq VAGUENESS_SUCCESS +' + +test_expect_success VAGUENESS_SUCCESS 'checkout produces ambiguity warning' ' + grep "warning.*ambiguous" stderr +' + +test_expect_success VAGUENESS_SUCCESS 'checkout chooses branch over tag' ' + echo refs/heads/vagueness >expect && + git symbolic-ref HEAD >actual && + test_cmp expect actual && + echo branch >expect && + test_cmp expect file +' + +test_expect_success VAGUENESS_SUCCESS 'checkout reports switch to branch' ' + grep "Switched to branch" stderr && + ! grep "^HEAD is now at" stderr +' + +test_done diff --git a/t/t2020-checkout-detach.sh b/t/t2020-checkout-detach.sh new file mode 100755 index 000000000..00421453b --- /dev/null +++ b/t/t2020-checkout-detach.sh @@ -0,0 +1,95 @@ +#!/bin/sh + +test_description='checkout into detached HEAD state' +. ./test-lib.sh + +check_detached () { + test_must_fail git symbolic-ref -q HEAD >/dev/null +} + +check_not_detached () { + git symbolic-ref -q HEAD >/dev/null +} + +reset () { + git checkout master && + check_not_detached +} + +test_expect_success 'setup' ' + test_commit one && + test_commit two && + git branch branch && + git tag tag +' + +test_expect_success 'checkout branch does not detach' ' + reset && + git checkout branch && + check_not_detached +' + +test_expect_success 'checkout tag detaches' ' + reset && + git checkout tag && + check_detached +' + +test_expect_success 'checkout branch by full name detaches' ' + reset && + git checkout refs/heads/branch && + check_detached +' + +test_expect_success 'checkout non-ref detaches' ' + reset && + git checkout branch^ && + check_detached +' + +test_expect_success 'checkout ref^0 detaches' ' + reset && + git checkout branch^0 && + check_detached +' + +test_expect_success 'checkout --detach detaches' ' + reset && + git checkout --detach branch && + check_detached +' + +test_expect_success 'checkout --detach without branch name' ' + reset && + git checkout --detach && + check_detached +' + +test_expect_success 'checkout --detach errors out for non-commit' ' + reset && + test_must_fail git checkout --detach one^{tree} && + check_not_detached +' + +test_expect_success 'checkout --detach errors out for extra argument' ' + reset && + git checkout master && + test_must_fail git checkout --detach tag one.t && + check_not_detached +' + +test_expect_success 'checkout --detached and -b are incompatible' ' + reset && + test_must_fail git checkout --detach -b newbranch tag && + check_not_detached +' + +test_expect_success 'checkout --detach moves HEAD' ' + reset && + git checkout one && + git checkout --detach two && + git diff --exit-code HEAD && + git diff --exit-code two +' + +test_done diff --git a/t/t3032-merge-recursive-options.sh b/t/t3032-merge-recursive-options.sh index 229379755..2b17311cb 100755 --- a/t/t3032-merge-recursive-options.sh +++ b/t/t3032-merge-recursive-options.sh @@ -13,16 +13,19 @@ test_description='merge-recursive options . ./test-lib.sh +test_have_prereq SED_STRIPS_CR && SED_OPTIONS=-b +test_have_prereq MINGW && export GREP_OPTIONS=-U + test_expect_success 'setup' ' conflict_hunks () { - sed -n -e " - /^<<<</ b inconflict + sed $SED_OPTIONS -n -e " + /^<<<</ b conflict b - : inconflict + : conflict p /^>>>>/ b n - b inconflict + b conflict " "$@" } && @@ -107,6 +110,20 @@ test_expect_success '--ignore-space-change makes merge succeed' ' git merge-recursive --ignore-space-change HEAD^ -- HEAD remote ' +test_expect_success 'naive cherry-pick fails' ' + git read-tree --reset -u HEAD && + test_must_fail git cherry-pick --no-commit remote && + git read-tree --reset -u HEAD && + test_must_fail git cherry-pick remote && + test_must_fail git update-index --refresh && + grep "<<<<<<" text.txt +' + +test_expect_success '-Xignore-space-change makes cherry-pick succeed' ' + git read-tree --reset -u HEAD && + git cherry-pick --no-commit -Xignore-space-change remote +' + test_expect_success '--ignore-space-change: our w/s-only change wins' ' q_to_cr <<-\EOF >expected && justice and holiness and is the nurse of his age and theQ diff --git a/t/t3301-notes.sh b/t/t3301-notes.sh index dc2e04a01..1921ca3a7 100755 --- a/t/t3301-notes.sh +++ b/t/t3301-notes.sh @@ -1067,7 +1067,7 @@ test_expect_success 'git notes copy diagnoses too many or too few parameters' ' test_expect_success 'git notes get-ref (no overrides)' ' git config --unset core.notesRef && - unset GIT_NOTES_REF && + sane_unset GIT_NOTES_REF && test "$(git notes get-ref)" = "refs/notes/commits" ' diff --git a/t/t3509-cherry-pick-merge-df.sh b/t/t3509-cherry-pick-merge-df.sh index 948ca1bce..df921d1f3 100755 --- a/t/t3509-cherry-pick-merge-df.sh +++ b/t/t3509-cherry-pick-merge-df.sh @@ -3,12 +3,14 @@ test_description='Test cherry-pick with directory/file conflicts' . ./test-lib.sh -test_expect_success SYMLINKS 'Setup rename across paths each below D/F conflicts' ' +test_expect_success 'Initialize repository' ' mkdir a && >a/f && git add a && - git commit -m a && + git commit -m a +' +test_expect_success SYMLINKS 'Setup rename across paths each below D/F conflicts' ' mkdir b && ln -s ../a b/a && git add b && diff --git a/t/t4010-diff-pathspec.sh b/t/t4010-diff-pathspec.sh index 94df7ae53..fbc8cd8f0 100755 --- a/t/t4010-diff-pathspec.sh +++ b/t/t4010-diff-pathspec.sh @@ -70,4 +70,36 @@ test_expect_success 'diff-tree pathspec' ' test_cmp expected current ' +EMPTY_TREE=4b825dc642cb6eb9a060e54bf8d69288fbee4904 + +test_expect_success 'diff-tree with wildcard shows dir also matches' ' + git diff-tree --name-only $EMPTY_TREE $tree -- "f*" >result && + echo file0 >expected && + test_cmp expected result +' + +test_expect_success 'diff-tree -r with wildcard' ' + git diff-tree -r --name-only $EMPTY_TREE $tree -- "*file1" >result && + echo path1/file1 >expected && + test_cmp expected result +' + +test_expect_success 'diff-tree with wildcard shows dir also matches' ' + git diff-tree --name-only $tree $tree2 -- "path1/f*" >result && + echo path1 >expected && + test_cmp expected result +' + +test_expect_success 'diff-tree -r with wildcard from beginning' ' + git diff-tree -r --name-only $tree $tree2 -- "path1/*file1" >result && + echo path1/file1 >expected && + test_cmp expected result +' + +test_expect_success 'diff-tree -r with wildcard' ' + git diff-tree -r --name-only $tree $tree2 -- "path1/f*" >result && + echo path1/file1 >expected && + test_cmp expected result +' + test_done diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh index 9a6652058..b8f81d07c 100755 --- a/t/t4013-diff-various.sh +++ b/t/t4013-diff-various.sh @@ -290,4 +290,15 @@ test_expect_success 'log -S requires an argument' ' test_must_fail git log -S ' +test_expect_success 'diff --cached on unborn branch' ' + echo ref: refs/heads/unborn >.git/HEAD && + git diff --cached >result && + test_cmp "$TEST_DIRECTORY/t4013/diff.diff_--cached" result +' + +test_expect_success 'diff --cached -- file on unborn branch' ' + git diff --cached -- file0 >result && + test_cmp "$TEST_DIRECTORY/t4013/diff.diff_--cached_--_file0" result +' + test_done diff --git a/t/t4013/diff.diff_--cached b/t/t4013/diff.diff_--cached new file mode 100644 index 000000000..ff16e83e7 --- /dev/null +++ b/t/t4013/diff.diff_--cached @@ -0,0 +1,38 @@ +diff --git a/dir/sub b/dir/sub +new file mode 100644 +index 0000000..992913c +--- /dev/null ++++ b/dir/sub +@@ -0,0 +1,8 @@ ++A ++B ++C ++D ++E ++F ++1 ++2 +diff --git a/file0 b/file0 +new file mode 100644 +index 0000000..10a8a9f +--- /dev/null ++++ b/file0 +@@ -0,0 +1,9 @@ ++1 ++2 ++3 ++4 ++5 ++6 ++A ++B ++C +diff --git a/file1 b/file1 +new file mode 100644 +index 0000000..b1e6722 +--- /dev/null ++++ b/file1 +@@ -0,0 +1,3 @@ ++A ++B ++C diff --git a/t/t4013/diff.diff_--cached_--_file0 b/t/t4013/diff.diff_--cached_--_file0 new file mode 100644 index 000000000..b9bb858a0 --- /dev/null +++ b/t/t4013/diff.diff_--cached_--_file0 @@ -0,0 +1,15 @@ +diff --git a/file0 b/file0 +new file mode 100644 +index 0000000..10a8a9f +--- /dev/null ++++ b/file0 +@@ -0,0 +1,9 @@ ++1 ++2 ++3 ++4 ++5 ++6 ++A ++B ++C diff --git a/t/t4018-diff-funcname.sh b/t/t4018-diff-funcname.sh index 0a61b57b5..364693062 100755 --- a/t/t4018-diff-funcname.sh +++ b/t/t4018-diff-funcname.sh @@ -32,7 +32,7 @@ EOF sed 's/beer\\/beer,\\/' < Beer.java > Beer-correct.java -builtin_patterns="bibtex cpp csharp fortran html java objc pascal php python ruby tex" +builtin_patterns="bibtex cpp csharp fortran html java objc pascal perl php python ruby tex" for p in $builtin_patterns do test_expect_success "builtin $p pattern compiles" ' diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh index 8096d8a33..37aeab0d5 100755 --- a/t/t4034-diff-words.sh +++ b/t/t4034-diff-words.sh @@ -4,331 +4,307 @@ test_description='word diff colors' . ./test-lib.sh -test_expect_success setup ' - - git config diff.color.old red && - git config diff.color.new green && - git config diff.color.func magenta +cat >pre.simple <<-\EOF + h(4) -' + a = b + c +EOF +cat >post.simple <<-\EOF + h(4),hh[44] -word_diff () { - test_must_fail git diff --no-index "$@" pre post > output && - test_decode_color <output >output.decrypted && - test_cmp expect output.decrypted -} + a = b + c -cat > pre <<\EOF -h(4) + aa = a -a = b + c + aeff = aeff * ( aaa ) EOF +cat >expect.letter-runs-are-words <<-\EOF + <BOLD>diff --git a/pre b/post<RESET> + <BOLD>index 330b04f..5ed8eff 100644<RESET> + <BOLD>--- a/pre<RESET> + <BOLD>+++ b/post<RESET> + <CYAN>@@ -1,3 +1,7 @@<RESET> + h(4),<GREEN>hh<RESET>[44] -cat > post <<\EOF -h(4),hh[44] - -a = b + c + a = b + c<RESET> -aa = a + <GREEN>aa = a<RESET> -aeff = aeff * ( aaa ) + <GREEN>aeff = aeff * ( aaa<RESET> ) EOF +cat >expect.non-whitespace-is-word <<-\EOF + <BOLD>diff --git a/pre b/post<RESET> + <BOLD>index 330b04f..5ed8eff 100644<RESET> + <BOLD>--- a/pre<RESET> + <BOLD>+++ b/post<RESET> + <CYAN>@@ -1,3 +1,7 @@<RESET> + h(4)<GREEN>,hh[44]<RESET> -cat > expect <<\EOF -<BOLD>diff --git a/pre b/post<RESET> -<BOLD>index 330b04f..5ed8eff 100644<RESET> -<BOLD>--- a/pre<RESET> -<BOLD>+++ b/post<RESET> -<CYAN>@@ -1,3 +1,7 @@<RESET> -<RED>h(4)<RESET><GREEN>h(4),hh[44]<RESET> + a = b + c<RESET> -a = b + c<RESET> + <GREEN>aa = a<RESET> -<GREEN>aa = a<RESET> - -<GREEN>aeff = aeff * ( aaa )<RESET> + <GREEN>aeff = aeff * ( aaa )<RESET> EOF -test_expect_success 'word diff with runs of whitespace' ' +word_diff () { + test_must_fail git diff --no-index "$@" pre post >output && + test_decode_color <output >output.decrypted && + test_cmp expect output.decrypted +} - word_diff --color-words +test_language_driver () { + lang=$1 + test_expect_success "diff driver '$lang'" ' + cp "$TEST_DIRECTORY/t4034/'"$lang"'/pre" \ + "$TEST_DIRECTORY/t4034/'"$lang"'/post" \ + "$TEST_DIRECTORY/t4034/'"$lang"'/expect" . && + echo "* diff='"$lang"'" >.gitattributes && + word_diff --color-words + ' +} +test_expect_success setup ' + git config diff.color.old red && + git config diff.color.new green && + git config diff.color.func magenta ' -test_expect_success '--word-diff=color' ' - - word_diff --word-diff=color - +test_expect_success 'set up pre and post with runs of whitespace' ' + cp pre.simple pre && + cp post.simple post ' -test_expect_success '--color --word-diff=color' ' - +test_expect_success 'word diff with runs of whitespace' ' + cat >expect <<-\EOF && + <BOLD>diff --git a/pre b/post<RESET> + <BOLD>index 330b04f..5ed8eff 100644<RESET> + <BOLD>--- a/pre<RESET> + <BOLD>+++ b/post<RESET> + <CYAN>@@ -1,3 +1,7 @@<RESET> + <RED>h(4)<RESET><GREEN>h(4),hh[44]<RESET> + + a = b + c<RESET> + + <GREEN>aa = a<RESET> + + <GREEN>aeff = aeff * ( aaa )<RESET> + EOF + word_diff --color-words && + word_diff --word-diff=color && word_diff --color --word-diff=color - ' -sed 's/#.*$//' > expect <<EOF -diff --git a/pre b/post -index 330b04f..5ed8eff 100644 ---- a/pre -+++ b/post -@@ -1,3 +1,7 @@ --h(4) -+h(4),hh[44] -~ - # significant space -~ - a = b + c -~ -~ -+aa = a -~ -~ -+aeff = aeff * ( aaa ) -~ -EOF - test_expect_success '--word-diff=porcelain' ' - + sed 's/#.*$//' >expect <<-\EOF && + diff --git a/pre b/post + index 330b04f..5ed8eff 100644 + --- a/pre + +++ b/post + @@ -1,3 +1,7 @@ + -h(4) + +h(4),hh[44] + ~ + # significant space + ~ + a = b + c + ~ + ~ + +aa = a + ~ + ~ + +aeff = aeff * ( aaa ) + ~ + EOF word_diff --word-diff=porcelain - ' -cat > expect <<EOF -diff --git a/pre b/post -index 330b04f..5ed8eff 100644 ---- a/pre -+++ b/post -@@ -1,3 +1,7 @@ -[-h(4)-]{+h(4),hh[44]+} - -a = b + c - -{+aa = a+} - -{+aeff = aeff * ( aaa )+} -EOF - test_expect_success '--word-diff=plain' ' + cat >expect <<-\EOF && + diff --git a/pre b/post + index 330b04f..5ed8eff 100644 + --- a/pre + +++ b/post + @@ -1,3 +1,7 @@ + [-h(4)-]{+h(4),hh[44]+} - word_diff --word-diff=plain - -' + a = b + c -test_expect_success '--word-diff=plain --no-color' ' + {+aa = a+} + {+aeff = aeff * ( aaa )+} + EOF + word_diff --word-diff=plain && word_diff --word-diff=plain --no-color - ' -cat > expect <<EOF -<BOLD>diff --git a/pre b/post<RESET> -<BOLD>index 330b04f..5ed8eff 100644<RESET> -<BOLD>--- a/pre<RESET> -<BOLD>+++ b/post<RESET> -<CYAN>@@ -1,3 +1,7 @@<RESET> -<RED>[-h(4)-]<RESET><GREEN>{+h(4),hh[44]+}<RESET> - -a = b + c<RESET> - -<GREEN>{+aa = a+}<RESET> +test_expect_success '--word-diff=plain --color' ' + cat >expect <<-\EOF && + <BOLD>diff --git a/pre b/post<RESET> + <BOLD>index 330b04f..5ed8eff 100644<RESET> + <BOLD>--- a/pre<RESET> + <BOLD>+++ b/post<RESET> + <CYAN>@@ -1,3 +1,7 @@<RESET> + <RED>[-h(4)-]<RESET><GREEN>{+h(4),hh[44]+}<RESET> -<GREEN>{+aeff = aeff * ( aaa )+}<RESET> -EOF + a = b + c<RESET> -test_expect_success '--word-diff=plain --color' ' + <GREEN>{+aa = a+}<RESET> + <GREEN>{+aeff = aeff * ( aaa )+}<RESET> + EOF word_diff --word-diff=plain --color - ' -cat > expect <<\EOF -<BOLD>diff --git a/pre b/post<RESET> -<BOLD>index 330b04f..5ed8eff 100644<RESET> -<BOLD>--- a/pre<RESET> -<BOLD>+++ b/post<RESET> -<CYAN>@@ -1 +1 @@<RESET> -<RED>h(4)<RESET><GREEN>h(4),hh[44]<RESET> -<CYAN>@@ -3,0 +4,4 @@<RESET> <RESET><MAGENTA>a = b + c<RESET> - -<GREEN>aa = a<RESET> - -<GREEN>aeff = aeff * ( aaa )<RESET> -EOF - test_expect_success 'word diff without context' ' - + cat >expect <<-\EOF && + <BOLD>diff --git a/pre b/post<RESET> + <BOLD>index 330b04f..5ed8eff 100644<RESET> + <BOLD>--- a/pre<RESET> + <BOLD>+++ b/post<RESET> + <CYAN>@@ -1 +1 @@<RESET> + <RED>h(4)<RESET><GREEN>h(4),hh[44]<RESET> + <CYAN>@@ -3,0 +4,4 @@<RESET> <RESET><MAGENTA>a = b + c<RESET> + + <GREEN>aa = a<RESET> + + <GREEN>aeff = aeff * ( aaa )<RESET> + EOF word_diff --color-words --unified=0 - ' -cat > expect <<\EOF -<BOLD>diff --git a/pre b/post<RESET> -<BOLD>index 330b04f..5ed8eff 100644<RESET> -<BOLD>--- a/pre<RESET> -<BOLD>+++ b/post<RESET> -<CYAN>@@ -1,3 +1,7 @@<RESET> -h(4),<GREEN>hh<RESET>[44] - -a = b + c<RESET> - -<GREEN>aa = a<RESET> - -<GREEN>aeff = aeff * ( aaa<RESET> ) -EOF -cp expect expect.letter-runs-are-words - test_expect_success 'word diff with a regular expression' ' - + cp expect.letter-runs-are-words expect && word_diff --color-words="[a-z]+" - ' -test_expect_success 'set a diff driver' ' +test_expect_success 'set up a diff driver' ' git config diff.testdriver.wordRegex "[^[:space:]]" && - cat <<EOF > .gitattributes -pre diff=testdriver -post diff=testdriver -EOF + cat <<-\EOF >.gitattributes + pre diff=testdriver + post diff=testdriver + EOF ' test_expect_success 'option overrides .gitattributes' ' - + cp expect.letter-runs-are-words expect && word_diff --color-words="[a-z]+" - ' -cat > expect <<\EOF -<BOLD>diff --git a/pre b/post<RESET> -<BOLD>index 330b04f..5ed8eff 100644<RESET> -<BOLD>--- a/pre<RESET> -<BOLD>+++ b/post<RESET> -<CYAN>@@ -1,3 +1,7 @@<RESET> -h(4)<GREEN>,hh[44]<RESET> - -a = b + c<RESET> - -<GREEN>aa = a<RESET> - -<GREEN>aeff = aeff * ( aaa )<RESET> -EOF -cp expect expect.non-whitespace-is-word - test_expect_success 'use regex supplied by driver' ' - + cp expect.non-whitespace-is-word expect && word_diff --color-words - ' -test_expect_success 'set diff.wordRegex option' ' +test_expect_success 'set up diff.wordRegex option' ' git config diff.wordRegex "[[:alnum:]]+" ' -cp expect.letter-runs-are-words expect - test_expect_success 'command-line overrides config' ' + cp expect.letter-runs-are-words expect && word_diff --color-words="[a-z]+" ' -cat > expect <<\EOF -<BOLD>diff --git a/pre b/post<RESET> -<BOLD>index 330b04f..5ed8eff 100644<RESET> -<BOLD>--- a/pre<RESET> -<BOLD>+++ b/post<RESET> -<CYAN>@@ -1,3 +1,7 @@<RESET> -h(4),<GREEN>{+hh+}<RESET>[44] - -a = b + c<RESET> +test_expect_success 'command-line overrides config: --word-diff-regex' ' + cat >expect <<-\EOF && + <BOLD>diff --git a/pre b/post<RESET> + <BOLD>index 330b04f..5ed8eff 100644<RESET> + <BOLD>--- a/pre<RESET> + <BOLD>+++ b/post<RESET> + <CYAN>@@ -1,3 +1,7 @@<RESET> + h(4),<GREEN>{+hh+}<RESET>[44] -<GREEN>{+aa = a+}<RESET> + a = b + c<RESET> -<GREEN>{+aeff = aeff * ( aaa+}<RESET> ) -EOF + <GREEN>{+aa = a+}<RESET> -test_expect_success 'command-line overrides config: --word-diff-regex' ' + <GREEN>{+aeff = aeff * ( aaa+}<RESET> ) + EOF word_diff --color --word-diff-regex="[a-z]+" ' -cp expect.non-whitespace-is-word expect - test_expect_success '.gitattributes override config' ' + cp expect.non-whitespace-is-word expect && word_diff --color-words ' -test_expect_success 'remove diff driver regex' ' - git config --unset diff.testdriver.wordRegex +test_expect_success 'setup: remove diff driver regex' ' + test_might_fail git config --unset diff.testdriver.wordRegex ' -cat > expect <<\EOF -<BOLD>diff --git a/pre b/post<RESET> -<BOLD>index 330b04f..5ed8eff 100644<RESET> -<BOLD>--- a/pre<RESET> -<BOLD>+++ b/post<RESET> -<CYAN>@@ -1,3 +1,7 @@<RESET> -h(4),<GREEN>hh[44<RESET>] - -a = b + c<RESET> +test_expect_success 'use configured regex' ' + cat >expect <<-\EOF && + <BOLD>diff --git a/pre b/post<RESET> + <BOLD>index 330b04f..5ed8eff 100644<RESET> + <BOLD>--- a/pre<RESET> + <BOLD>+++ b/post<RESET> + <CYAN>@@ -1,3 +1,7 @@<RESET> + h(4),<GREEN>hh[44<RESET>] -<GREEN>aa = a<RESET> + a = b + c<RESET> -<GREEN>aeff = aeff * ( aaa<RESET> ) -EOF + <GREEN>aa = a<RESET> -test_expect_success 'use configured regex' ' + <GREEN>aeff = aeff * ( aaa<RESET> ) + EOF word_diff --color-words ' -echo 'aaa (aaa)' > pre -echo 'aaa (aaa) aaa' > post - -cat > expect <<\EOF -<BOLD>diff --git a/pre b/post<RESET> -<BOLD>index c29453b..be22f37 100644<RESET> -<BOLD>--- a/pre<RESET> -<BOLD>+++ b/post<RESET> -<CYAN>@@ -1 +1 @@<RESET> -aaa (aaa) <GREEN>aaa<RESET> -EOF - test_expect_success 'test parsing words for newline' ' - + echo "aaa (aaa)" >pre && + echo "aaa (aaa) aaa" >post && + cat >expect <<-\EOF && + <BOLD>diff --git a/pre b/post<RESET> + <BOLD>index c29453b..be22f37 100644<RESET> + <BOLD>--- a/pre<RESET> + <BOLD>+++ b/post<RESET> + <CYAN>@@ -1 +1 @@<RESET> + aaa (aaa) <GREEN>aaa<RESET> + EOF word_diff --color-words="a+" - - ' -echo '(:' > pre -echo '(' > post - -cat > expect <<\EOF -<BOLD>diff --git a/pre b/post<RESET> -<BOLD>index 289cb9d..2d06f37 100644<RESET> -<BOLD>--- a/pre<RESET> -<BOLD>+++ b/post<RESET> -<CYAN>@@ -1 +1 @@<RESET> -(<RED>:<RESET> -EOF - test_expect_success 'test when words are only removed at the end' ' - + echo "(:" >pre && + echo "(" >post && + cat >expect <<-\EOF && + <BOLD>diff --git a/pre b/post<RESET> + <BOLD>index 289cb9d..2d06f37 100644<RESET> + <BOLD>--- a/pre<RESET> + <BOLD>+++ b/post<RESET> + <CYAN>@@ -1 +1 @@<RESET> + (<RED>:<RESET> + EOF word_diff --color-words=. - ' -cat > expect <<\EOF -diff --git a/pre b/post -index 289cb9d..2d06f37 100644 ---- a/pre -+++ b/post -@@ -1 +1 @@ --(: -+( -EOF - test_expect_success '--word-diff=none' ' - + echo "(:" >pre && + echo "(" >post && + cat >expect <<-\EOF && + diff --git a/pre b/post + index 289cb9d..2d06f37 100644 + --- a/pre + +++ b/post + @@ -1 +1 @@ + -(: + +( + EOF word_diff --word-diff=plain --word-diff=none - ' +test_language_driver bibtex +test_language_driver cpp +test_language_driver csharp +test_language_driver fortran +test_language_driver html +test_language_driver java +test_language_driver objc +test_language_driver pascal +test_language_driver perl +test_language_driver php +test_language_driver python +test_language_driver ruby +test_language_driver tex + test_done diff --git a/t/t4034/bibtex/expect b/t/t4034/bibtex/expect new file mode 100644 index 000000000..a157774f9 --- /dev/null +++ b/t/t4034/bibtex/expect @@ -0,0 +1,15 @@ +<BOLD>diff --git a/pre b/post<RESET> +<BOLD>index 95cd55b..ddcba9b 100644<RESET> +<BOLD>--- a/pre<RESET> +<BOLD>+++ b/post<RESET> +<CYAN>@@ -1,9 +1,10 @@<RESET> +@article{aldous1987uie,<RESET> + title={{Ultimate instability of exponential back-off protocol for acknowledgment-based transmission control of random access communication channels}},<RESET> + author={Aldous, <RED>D.<RESET><GREEN>David<RESET>}, + journal={Information Theory, IEEE Transactions on},<RESET> + volume={<RED>33<RESET><GREEN>Bogus.<RESET>}, + number={<RED>2<RESET><GREEN>4<RESET>}, + pages={219--223},<RESET> + year=<GREEN>1987,<RESET> +<GREEN> note={This is in fact a rather funny read since ethernet works well in practice. The<RESET> {<RED>1987<RESET><GREEN>\em pre} reference is the right one, however.<RESET>}<RED>,<RESET> +}<RESET> diff --git a/t/t4034/bibtex/post b/t/t4034/bibtex/post new file mode 100644 index 000000000..ddcba9b2f --- /dev/null +++ b/t/t4034/bibtex/post @@ -0,0 +1,10 @@ +@article{aldous1987uie, + title={{Ultimate instability of exponential back-off protocol for acknowledgment-based transmission control of random access communication channels}}, + author={Aldous, David}, + journal={Information Theory, IEEE Transactions on}, + volume={Bogus.}, + number={4}, + pages={219--223}, + year=1987, + note={This is in fact a rather funny read since ethernet works well in practice. The {\em pre} reference is the right one, however.} +} diff --git a/t/t4034/bibtex/pre b/t/t4034/bibtex/pre new file mode 100644 index 000000000..95cd55bd7 --- /dev/null +++ b/t/t4034/bibtex/pre @@ -0,0 +1,9 @@ +@article{aldous1987uie, + title={{Ultimate instability of exponential back-off protocol for acknowledgment-based transmission control of random access communication channels}}, + author={Aldous, D.}, + journal={Information Theory, IEEE Transactions on}, + volume={33}, + number={2}, + pages={219--223}, + year={1987}, +} diff --git a/t/t4034/cpp/expect b/t/t4034/cpp/expect new file mode 100644 index 000000000..37d1ea258 --- /dev/null +++ b/t/t4034/cpp/expect @@ -0,0 +1,36 @@ +<BOLD>diff --git a/pre b/post<RESET> +<BOLD>index 23d5c8a..7e8c026 100644<RESET> +<BOLD>--- a/pre<RESET> +<BOLD>+++ b/post<RESET> +<CYAN>@@ -1,19 +1,19 @@<RESET> +Foo() : x(0<RED>&&1<RESET><GREEN>&42<RESET>) { <GREEN>bar(x);<RESET> } +cout<<"Hello World<RED>!<RESET><GREEN>?<RESET>\n"<<endl; +<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>' +[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET> +!<RED>a<RESET><GREEN>x<RESET> ~<RED>a a<RESET><GREEN>x x<RESET>++ <RED>a<RESET><GREEN>x<RESET>-- <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET><<<RED>b a<RESET><GREEN>y x<RESET>>><RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>^<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>|<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>&&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>||<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>?<RED>b<RESET><GREEN>y<RESET>:z +<RED>a<RESET><GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>,y +<RED>a<RESET><GREEN>x<RESET>::<RED>b<RESET><GREEN>y<RESET> diff --git a/t/t4034/cpp/post b/t/t4034/cpp/post new file mode 100644 index 000000000..7e8c026ce --- /dev/null +++ b/t/t4034/cpp/post @@ -0,0 +1,19 @@ +Foo() : x(0&42) { bar(x); } +cout<<"Hello World?\n"<<endl; +(1) (-1e10) (0xabcdef) 'y' +[x] x->y x.y +!x ~x x++ x-- x*y x&y +x*y x/y x%y +x+y x-y +x<<y x>>y +x<y x<=y x>y x>=y +x==y x!=y +x&y +x^y +x|y +x&&y +x||y +x?y:z +x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y +x,y +x::y diff --git a/t/t4034/cpp/pre b/t/t4034/cpp/pre new file mode 100644 index 000000000..23d5c8adf --- /dev/null +++ b/t/t4034/cpp/pre @@ -0,0 +1,19 @@ +Foo():x(0&&1){} +cout<<"Hello World!\n"<<endl; +1 -1e10 0xabcdef 'x' +[a] a->b a.b +!a ~a a++ a-- a*b a&b +a*b a/b a%b +a+b a-b +a<<b a>>b +a<b a<=b a>b a>=b +a==b a!=b +a&b +a^b +a|b +a&&b +a||b +a?b:z +a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b +a,y +a::b diff --git a/t/t4034/csharp/expect b/t/t4034/csharp/expect new file mode 100644 index 000000000..e5d1dd2b3 --- /dev/null +++ b/t/t4034/csharp/expect @@ -0,0 +1,35 @@ +<BOLD>diff --git a/pre b/post<RESET> +<BOLD>index 9106d63..dd5f421 100644<RESET> +<BOLD>--- a/pre<RESET> +<BOLD>+++ b/post<RESET> +<CYAN>@@ -1,18 +1,18 @@<RESET> +Foo() : x(0<RED>&&1<RESET><GREEN>&42<RESET>) { <GREEN>bar(x);<RESET> } +cout<<"Hello World<RED>!<RESET><GREEN>?<RESET>\n"<<endl; +<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>' +[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET> +!<RED>a<RESET><GREEN>x<RESET> ~<RED>a a<RESET><GREEN>x x<RESET>++ <RED>a<RESET><GREEN>x<RESET>-- <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET><<<RED>b a<RESET><GREEN>y x<RESET>>><RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>^<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>|<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>&&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>||<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>?<RED>b<RESET><GREEN>y<RESET>:z +<RED>a<RESET><GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>,y diff --git a/t/t4034/csharp/post b/t/t4034/csharp/post new file mode 100644 index 000000000..dd5f4218a --- /dev/null +++ b/t/t4034/csharp/post @@ -0,0 +1,18 @@ +Foo() : x(0&42) { bar(x); } +cout<<"Hello World?\n"<<endl; +(1) (-1e10) (0xabcdef) 'y' +[x] x->y x.y +!x ~x x++ x-- x*y x&y +x*y x/y x%y +x+y x-y +x<<y x>>y +x<y x<=y x>y x>=y +x==y x!=y +x&y +x^y +x|y +x&&y +x||y +x?y:z +x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y +x,y diff --git a/t/t4034/csharp/pre b/t/t4034/csharp/pre new file mode 100644 index 000000000..9106d63e8 --- /dev/null +++ b/t/t4034/csharp/pre @@ -0,0 +1,18 @@ +Foo():x(0&&1){} +cout<<"Hello World!\n"<<endl; +1 -1e10 0xabcdef 'x' +[a] a->b a.b +!a ~a a++ a-- a*b a&b +a*b a/b a%b +a+b a-b +a<<b a>>b +a<b a<=b a>b a>=b +a==b a!=b +a&b +a^b +a|b +a&&b +a||b +a?b:z +a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b +a,y diff --git a/t/t4034/fortran/expect b/t/t4034/fortran/expect new file mode 100644 index 000000000..b233dbd62 --- /dev/null +++ b/t/t4034/fortran/expect @@ -0,0 +1,10 @@ +<BOLD>diff --git a/pre b/post<RESET> +<BOLD>index 87f0d0b..d308da2 100644<RESET> +<BOLD>--- a/pre<RESET> +<BOLD>+++ b/post<RESET> +<CYAN>@@ -1,5 +1,5 @@<RESET> +print *, "Hello World<RED>!<RESET><GREEN>?<RESET>" + +DO10I = 1,10<RESET> +<RED>DO10I<RESET><GREEN>DO 10 I<RESET> = 1,10 +<RED>DO10I<RESET><GREEN>DO 1 0 I<RESET> = 1,10 diff --git a/t/t4034/fortran/post b/t/t4034/fortran/post new file mode 100644 index 000000000..d308da2ad --- /dev/null +++ b/t/t4034/fortran/post @@ -0,0 +1,5 @@ +print *, "Hello World?" + +DO10I = 1,10 +DO 10 I = 1,10 +DO 1 0 I = 1,10 diff --git a/t/t4034/fortran/pre b/t/t4034/fortran/pre new file mode 100644 index 000000000..87f0d0b03 --- /dev/null +++ b/t/t4034/fortran/pre @@ -0,0 +1,5 @@ +print *, "Hello World!" + +DO10I = 1,10 +DO10I = 1,10 +DO10I = 1,10 diff --git a/t/t4034/html/expect b/t/t4034/html/expect new file mode 100644 index 000000000..447b49ab6 --- /dev/null +++ b/t/t4034/html/expect @@ -0,0 +1,8 @@ +<BOLD>diff --git a/pre b/post<RESET> +<BOLD>index 8ca4aea..46921e5 100644<RESET> +<BOLD>--- a/pre<RESET> +<BOLD>+++ b/post<RESET> +<CYAN>@@ -1,3 +1,3 @@<RESET> +<tag <GREEN>newattr="newvalue"<RESET>><GREEN>added<RESET> content</tag> +<tag attr=<RED>"value"<RESET><GREEN>"newvalue"<RESET>><RED>content<RESET><GREEN>changed<RESET></tag> +<<RED>tag<RESET><GREEN>newtag<RESET>>content <RED>&entity;<RESET><GREEN>&newentity;<RESET><<RED>/tag<RESET><GREEN>/newtag<RESET>> diff --git a/t/t4034/html/post b/t/t4034/html/post new file mode 100644 index 000000000..46921e586 --- /dev/null +++ b/t/t4034/html/post @@ -0,0 +1,3 @@ +<tag newattr="newvalue">added content</tag> +<tag attr="newvalue">changed</tag> +<newtag>content &newentity;</newtag> diff --git a/t/t4034/html/pre b/t/t4034/html/pre new file mode 100644 index 000000000..8ca4aeae8 --- /dev/null +++ b/t/t4034/html/pre @@ -0,0 +1,3 @@ +<tag>content</tag> +<tag attr="value">content</tag> +<tag>content &entity;</tag> diff --git a/t/t4034/java/expect b/t/t4034/java/expect new file mode 100644 index 000000000..37d1ea258 --- /dev/null +++ b/t/t4034/java/expect @@ -0,0 +1,36 @@ +<BOLD>diff --git a/pre b/post<RESET> +<BOLD>index 23d5c8a..7e8c026 100644<RESET> +<BOLD>--- a/pre<RESET> +<BOLD>+++ b/post<RESET> +<CYAN>@@ -1,19 +1,19 @@<RESET> +Foo() : x(0<RED>&&1<RESET><GREEN>&42<RESET>) { <GREEN>bar(x);<RESET> } +cout<<"Hello World<RED>!<RESET><GREEN>?<RESET>\n"<<endl; +<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>' +[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET> +!<RED>a<RESET><GREEN>x<RESET> ~<RED>a a<RESET><GREEN>x x<RESET>++ <RED>a<RESET><GREEN>x<RESET>-- <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET><<<RED>b a<RESET><GREEN>y x<RESET>>><RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>^<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>|<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>&&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>||<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>?<RED>b<RESET><GREEN>y<RESET>:z +<RED>a<RESET><GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>,y +<RED>a<RESET><GREEN>x<RESET>::<RED>b<RESET><GREEN>y<RESET> diff --git a/t/t4034/java/post b/t/t4034/java/post new file mode 100644 index 000000000..7e8c026ce --- /dev/null +++ b/t/t4034/java/post @@ -0,0 +1,19 @@ +Foo() : x(0&42) { bar(x); } +cout<<"Hello World?\n"<<endl; +(1) (-1e10) (0xabcdef) 'y' +[x] x->y x.y +!x ~x x++ x-- x*y x&y +x*y x/y x%y +x+y x-y +x<<y x>>y +x<y x<=y x>y x>=y +x==y x!=y +x&y +x^y +x|y +x&&y +x||y +x?y:z +x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y +x,y +x::y diff --git a/t/t4034/java/pre b/t/t4034/java/pre new file mode 100644 index 000000000..23d5c8adf --- /dev/null +++ b/t/t4034/java/pre @@ -0,0 +1,19 @@ +Foo():x(0&&1){} +cout<<"Hello World!\n"<<endl; +1 -1e10 0xabcdef 'x' +[a] a->b a.b +!a ~a a++ a-- a*b a&b +a*b a/b a%b +a+b a-b +a<<b a>>b +a<b a<=b a>b a>=b +a==b a!=b +a&b +a^b +a|b +a&&b +a||b +a?b:z +a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b +a,y +a::b diff --git a/t/t4034/objc/expect b/t/t4034/objc/expect new file mode 100644 index 000000000..e5d1dd2b3 --- /dev/null +++ b/t/t4034/objc/expect @@ -0,0 +1,35 @@ +<BOLD>diff --git a/pre b/post<RESET> +<BOLD>index 9106d63..dd5f421 100644<RESET> +<BOLD>--- a/pre<RESET> +<BOLD>+++ b/post<RESET> +<CYAN>@@ -1,18 +1,18 @@<RESET> +Foo() : x(0<RED>&&1<RESET><GREEN>&42<RESET>) { <GREEN>bar(x);<RESET> } +cout<<"Hello World<RED>!<RESET><GREEN>?<RESET>\n"<<endl; +<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>' +[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET> +!<RED>a<RESET><GREEN>x<RESET> ~<RED>a a<RESET><GREEN>x x<RESET>++ <RED>a<RESET><GREEN>x<RESET>-- <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET><<<RED>b a<RESET><GREEN>y x<RESET>>><RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>^<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>|<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>&&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>||<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>?<RED>b<RESET><GREEN>y<RESET>:z +<RED>a<RESET><GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>,y diff --git a/t/t4034/objc/post b/t/t4034/objc/post new file mode 100644 index 000000000..dd5f4218a --- /dev/null +++ b/t/t4034/objc/post @@ -0,0 +1,18 @@ +Foo() : x(0&42) { bar(x); } +cout<<"Hello World?\n"<<endl; +(1) (-1e10) (0xabcdef) 'y' +[x] x->y x.y +!x ~x x++ x-- x*y x&y +x*y x/y x%y +x+y x-y +x<<y x>>y +x<y x<=y x>y x>=y +x==y x!=y +x&y +x^y +x|y +x&&y +x||y +x?y:z +x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y +x,y diff --git a/t/t4034/objc/pre b/t/t4034/objc/pre new file mode 100644 index 000000000..9106d63e8 --- /dev/null +++ b/t/t4034/objc/pre @@ -0,0 +1,18 @@ +Foo():x(0&&1){} +cout<<"Hello World!\n"<<endl; +1 -1e10 0xabcdef 'x' +[a] a->b a.b +!a ~a a++ a-- a*b a&b +a*b a/b a%b +a+b a-b +a<<b a>>b +a<b a<=b a>b a>=b +a==b a!=b +a&b +a^b +a|b +a&&b +a||b +a?b:z +a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b +a,y diff --git a/t/t4034/pascal/expect b/t/t4034/pascal/expect new file mode 100644 index 000000000..2ce423095 --- /dev/null +++ b/t/t4034/pascal/expect @@ -0,0 +1,35 @@ +<BOLD>diff --git a/pre b/post<RESET> +<BOLD>index 077046c..8865e6b 100644<RESET> +<BOLD>--- a/pre<RESET> +<BOLD>+++ b/post<RESET> +<CYAN>@@ -1,18 +1,18 @@<RESET> +writeln("Hello World<RED>!<RESET><GREEN>?<RESET>"); +<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>' +[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET> +!<RED>a<RESET><GREEN>x<RESET> ~<RED>a a<RESET><GREEN>x x<RESET>++ <RED>a<RESET><GREEN>x<RESET>-- <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET><<<RED>b a<RESET><GREEN>y x<RESET>>><RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>^<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>|<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>&&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>||<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>?<RED>b<RESET><GREEN>y<RESET>:z +<RED>a<RESET><GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>,y +<RED>a<RESET><GREEN>x<RESET>::<RED>b<RESET><GREEN>y<RESET> diff --git a/t/t4034/pascal/post b/t/t4034/pascal/post new file mode 100644 index 000000000..8865e6bdd --- /dev/null +++ b/t/t4034/pascal/post @@ -0,0 +1,18 @@ +writeln("Hello World?"); +(1) (-1e10) (0xabcdef) 'y' +[x] x->y x.y +!x ~x x++ x-- x*y x&y +x*y x/y x%y +x+y x-y +x<<y x>>y +x<y x<=y x>y x>=y +x==y x!=y +x&y +x^y +x|y +x&&y +x||y +x?y:z +x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y +x,y +x::y diff --git a/t/t4034/pascal/pre b/t/t4034/pascal/pre new file mode 100644 index 000000000..077046c83 --- /dev/null +++ b/t/t4034/pascal/pre @@ -0,0 +1,18 @@ +writeln("Hello World!"); +1 -1e10 0xabcdef 'x' +[a] a->b a.b +!a ~a a++ a-- a*b a&b +a*b a/b a%b +a+b a-b +a<<b a>>b +a<b a<=b a>b a>=b +a==b a!=b +a&b +a^b +a|b +a&&b +a||b +a?b:z +a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b +a,y +a::b diff --git a/t/t4034/perl/expect b/t/t4034/perl/expect new file mode 100644 index 000000000..a1deb6b6a --- /dev/null +++ b/t/t4034/perl/expect @@ -0,0 +1,13 @@ +<BOLD>diff --git a/pre b/post<RESET> +<BOLD>index f6610d3..e8b72ef 100644<RESET> +<BOLD>--- a/pre<RESET> +<BOLD>+++ b/post<RESET> +<CYAN>@@ -4,8 +4,8 @@<RESET> + +package Frotz;<RESET> +sub new {<RESET> + my <GREEN>(<RESET>$class<GREEN>, %opts)<RESET> = <RED>shift<RESET><GREEN>@_<RESET>; + return bless { <GREEN>xyzzy => "nitfol", %opts<RESET> }, $class; +}<RESET> + +__END__<RESET> diff --git a/t/t4034/perl/post b/t/t4034/perl/post new file mode 100644 index 000000000..e8b72ef5d --- /dev/null +++ b/t/t4034/perl/post @@ -0,0 +1,22 @@ +#!/usr/bin/perl + +use strict; + +package Frotz; +sub new { + my ($class, %opts) = @_; + return bless { xyzzy => "nitfol", %opts }, $class; +} + +__END__ +=head1 NAME + +frotz - Frotz + +=head1 SYNOPSIS + + use frotz; + + $nitfol = new Frotz(); + +=cut diff --git a/t/t4034/perl/pre b/t/t4034/perl/pre new file mode 100644 index 000000000..f6610d37b --- /dev/null +++ b/t/t4034/perl/pre @@ -0,0 +1,22 @@ +#!/usr/bin/perl + +use strict; + +package Frotz; +sub new { + my $class = shift; + return bless {}, $class; +} + +__END__ +=head1 NAME + +frotz - Frotz + +=head1 SYNOPSIS + + use frotz; + + $nitfol = new Frotz(); + +=cut diff --git a/t/t4034/php/expect b/t/t4034/php/expect new file mode 100644 index 000000000..040440860 --- /dev/null +++ b/t/t4034/php/expect @@ -0,0 +1,35 @@ +<BOLD>diff --git a/pre b/post<RESET> +<BOLD>index cf6e06b..4420a49 100644<RESET> +<BOLD>--- a/pre<RESET> +<BOLD>+++ b/post<RESET> +<CYAN>@@ -1,18 +1,18 @@<RESET> +<GREEN>(<RESET>$var<GREEN>)<RESET> $ var +<?="Hello World<RED>!<RESET><GREEN>?<RESET>"?> +<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>' +[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET> +!<RED>a<RESET><GREEN>x<RESET> ~<RED>a a<RESET><GREEN>x x<RESET>++ <RED>a<RESET><GREEN>x<RESET>-- <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET><<<RED>b a<RESET><GREEN>y x<RESET>>><RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>^<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>|<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>&&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>||<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>?<RED>b<RESET><GREEN>y<RESET>:z +<RED>a<RESET><GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>,y diff --git a/t/t4034/php/post b/t/t4034/php/post new file mode 100644 index 000000000..4420a4919 --- /dev/null +++ b/t/t4034/php/post @@ -0,0 +1,18 @@ +($var) $ var +<?="Hello World?"?> +(1) (-1e10) (0xabcdef) 'y' +[x] x->y x.y +!x ~x x++ x-- x*y x&y +x*y x/y x%y +x+y x-y +x<<y x>>y +x<y x<=y x>y x>=y +x==y x!=y +x&y +x^y +x|y +x&&y +x||y +x?y:z +x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y +x,y diff --git a/t/t4034/php/pre b/t/t4034/php/pre new file mode 100644 index 000000000..cf6e06bc2 --- /dev/null +++ b/t/t4034/php/pre @@ -0,0 +1,18 @@ +$var $var +<?= "Hello World!" ?> +1 -1e10 0xabcdef 'x' +[a] a->b a.b +!a ~a a++ a-- a*b a&b +a*b a/b a%b +a+b a-b +a<<b a>>b +a<b a<=b a>b a>=b +a==b a!=b +a&b +a^b +a|b +a&&b +a||b +a?b:z +a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b +a,y diff --git a/t/t4034/python/expect b/t/t4034/python/expect new file mode 100644 index 000000000..8abb8a48b --- /dev/null +++ b/t/t4034/python/expect @@ -0,0 +1,34 @@ +<BOLD>diff --git a/pre b/post<RESET> +<BOLD>index 438f776..68baf34 100644<RESET> +<BOLD>--- a/pre<RESET> +<BOLD>+++ b/post<RESET> +<CYAN>@@ -1,17 +1,17 @@<RESET> +print<RED>u<RESET> "Hello World<RED>!<RESET><GREEN>?<RESET>\n"<GREEN>; print<RESET> +<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>) u<RESET>'<RED>x<RESET><GREEN>y<RESET>' +[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET> +!<RED>a<RESET><GREEN>x<RESET> ~<RED>a a<RESET><GREEN>x x<RESET>++ <RED>a<RESET><GREEN>x<RESET>-- <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET><<<RED>b a<RESET><GREEN>y x<RESET>>><RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>^<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>|<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>&&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>||<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>?<RED>b<RESET><GREEN>y<RESET>:z +<RED>a<RESET><GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>,y diff --git a/t/t4034/python/post b/t/t4034/python/post new file mode 100644 index 000000000..68baf34f0 --- /dev/null +++ b/t/t4034/python/post @@ -0,0 +1,17 @@ +print "Hello World?\n"; print +(1) (-1e10) (0xabcdef) u'y' +[x] x->y x.y +!x ~x x++ x-- x*y x&y +x*y x/y x%y +x+y x-y +x<<y x>>y +x<y x<=y x>y x>=y +x==y x!=y +x&y +x^y +x|y +x&&y +x||y +x?y:z +x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y +x,y diff --git a/t/t4034/python/pre b/t/t4034/python/pre new file mode 100644 index 000000000..438f77687 --- /dev/null +++ b/t/t4034/python/pre @@ -0,0 +1,17 @@ +print u"Hello World!\n" +1 -1e10 0xabcdef 'x' +[a] a->b a.b +!a ~a a++ a-- a*b a&b +a*b a/b a%b +a+b a-b +a<<b a>>b +a<b a<=b a>b a>=b +a==b a!=b +a&b +a^b +a|b +a&&b +a||b +a?b:z +a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b +a,y diff --git a/t/t4034/ruby/expect b/t/t4034/ruby/expect new file mode 100644 index 000000000..16e1dd567 --- /dev/null +++ b/t/t4034/ruby/expect @@ -0,0 +1,34 @@ +<BOLD>diff --git a/pre b/post<RESET> +<BOLD>index 30ed9a1..7678f14 100644<RESET> +<BOLD>--- a/pre<RESET> +<BOLD>+++ b/post<RESET> +<CYAN>@@ -1,17 +1,17 @@<RESET> +10.downto(1) {|<RED>x<RESET><GREEN>y<RESET>| puts <RED>x<RESET><GREEN>y<RESET>} +<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>' +[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET> +!<RED>a<RESET><GREEN>x<RESET> ~<RED>a a<RESET><GREEN>x x<RESET>++ <RED>a<RESET><GREEN>x<RESET>-- <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET><<<RED>b a<RESET><GREEN>y x<RESET>>><RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>^<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>|<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>&&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>||<RED>b<RESET> +<RED>a?b<RESET><GREEN>y<RESET> +<GREEN>x?y<RESET>:z +<RED>a<RESET><GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>,y diff --git a/t/t4034/ruby/post b/t/t4034/ruby/post new file mode 100644 index 000000000..7678f14e1 --- /dev/null +++ b/t/t4034/ruby/post @@ -0,0 +1,17 @@ +10.downto(1) {|y| puts y} +(1) (-1e10) (0xabcdef) 'y' +[x] x->y x.y +!x ~x x++ x-- x*y x&y +x*y x/y x%y +x+y x-y +x<<y x>>y +x<y x<=y x>y x>=y +x==y x!=y +x&y +x^y +x|y +x&&y +x||y +x?y:z +x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y +x,y diff --git a/t/t4034/ruby/pre b/t/t4034/ruby/pre new file mode 100644 index 000000000..30ed9a159 --- /dev/null +++ b/t/t4034/ruby/pre @@ -0,0 +1,17 @@ +10.downto(1) {|x| puts x} +1 -1e10 0xabcdef 'x' +[a] a->b a.b +!a ~a a++ a-- a*b a&b +a*b a/b a%b +a+b a-b +a<<b a>>b +a<b a<=b a>b a>=b +a==b a!=b +a&b +a^b +a|b +a&&b +a||b +a?b:z +a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b +a,y diff --git a/t/t4034/tex/expect b/t/t4034/tex/expect new file mode 100644 index 000000000..604969bcd --- /dev/null +++ b/t/t4034/tex/expect @@ -0,0 +1,9 @@ +<BOLD>diff --git a/pre b/post<RESET> +<BOLD>index 2b2dfcb..65cab61 100644<RESET> +<BOLD>--- a/pre<RESET> +<BOLD>+++ b/post<RESET> +<CYAN>@@ -1,4 +1,4 @@<RESET> +\section{Something <GREEN>new<RESET>} +<RED>\emph<RESET><GREEN>\textbf<RESET>{Macro style} +{<RED>\em<RESET><GREEN>\bfseries<RESET> State toggle style} +\\[<RED>1em<RESET><GREEN>1cm<RESET>] diff --git a/t/t4034/tex/post b/t/t4034/tex/post new file mode 100644 index 000000000..65cab61a1 --- /dev/null +++ b/t/t4034/tex/post @@ -0,0 +1,4 @@ +\section{Something new} +\textbf{Macro style} +{\bfseries State toggle style} +\\[1cm] diff --git a/t/t4034/tex/pre b/t/t4034/tex/pre new file mode 100644 index 000000000..2b2dfcb65 --- /dev/null +++ b/t/t4034/tex/pre @@ -0,0 +1,4 @@ +\section{Something} +\emph{Macro style} +{\em State toggle style} +\\[1em] diff --git a/t/t4120-apply-popt.sh b/t/t4120-apply-popt.sh index 579c9e610..a33d510bf 100755 --- a/t/t4120-apply-popt.sh +++ b/t/t4120-apply-popt.sh @@ -6,6 +6,7 @@ test_description='git apply -p handling.' . ./test-lib.sh +. "$TEST_DIRECTORY"/lib-prereq-FILEMODE.sh test_expect_success setup ' mkdir sub && @@ -62,8 +63,12 @@ test_expect_success 'apply (-p2) diff, mode change only' ' old mode 100644 new mode 100755 EOF - chmod 644 file1 && - git apply -p2 patch.chmod && + test_chmod -x file1 && + git apply --index -p2 patch.chmod && + case $(git ls-files -s file1) in 100755*) : good;; *) false;; esac +' + +test_expect_success FILEMODE 'file mode was changed' ' test -x file1 ' diff --git a/t/t5526-fetch-submodules.sh b/t/t5526-fetch-submodules.sh index 884a5e567..a5f458533 100755 --- a/t/t5526-fetch-submodules.sh +++ b/t/t5526-fetch-submodules.sh @@ -124,7 +124,7 @@ test_expect_success "--recurse-submodules overrides fetchRecurseSubmodules setti ( cd downstream && git fetch --recurse-submodules >../actual.out 2>../actual.err && - git config -f --unset .gitmodules submodule.submodule.fetchRecurseSubmodules true && + git config --unset -f .gitmodules submodule.submodule.fetchRecurseSubmodules && git config --unset submodule.submodule.fetchRecurseSubmodules ) && test_cmp expect.out actual.out && diff --git a/t/t6000-rev-list-misc.sh b/t/t6000-rev-list-misc.sh new file mode 100755 index 000000000..b10685af4 --- /dev/null +++ b/t/t6000-rev-list-misc.sh @@ -0,0 +1,51 @@ +#!/bin/sh + +test_description='miscellaneous rev-list tests' + +. ./test-lib.sh + +test_expect_success setup ' + echo content1 >wanted_file && + echo content2 >unwanted_file && + git add wanted_file unwanted_file && + git commit -m one +' + +test_expect_success 'rev-list --objects heeds pathspecs' ' + git rev-list --objects HEAD -- wanted_file >output && + grep wanted_file output && + ! grep unwanted_file output +' + +test_expect_success 'rev-list --objects with pathspecs and deeper paths' ' + mkdir foo && + >foo/file && + git add foo/file && + git commit -m two && + + git rev-list --objects HEAD -- foo >output && + grep foo/file output && + + git rev-list --objects HEAD -- foo/file >output && + grep foo/file output && + ! grep unwanted_file output +' + +test_expect_success 'rev-list --objects with pathspecs and copied files' ' + git checkout --orphan junio-testcase && + git rm -rf . && + + mkdir two && + echo frotz >one && + cp one two/three && + git add one two/three && + test_tick && + git commit -m that && + + ONE=$(git rev-parse HEAD:one) + git rev-list --objects HEAD two >output && + grep "$ONE two/three" output && + ! grep one output +' + +test_done diff --git a/t/t6004-rev-list-path-optim.sh b/t/t6004-rev-list-path-optim.sh index 5dabf1c5e..3e8c42ee0 100755 --- a/t/t6004-rev-list-path-optim.sh +++ b/t/t6004-rev-list-path-optim.sh @@ -1,51 +1,96 @@ #!/bin/sh -test_description='git rev-list trivial path optimization test' +test_description='git rev-list trivial path optimization test + + d/z1 + b0 b1 + o------------------------*----o master + / / + o---------o----o----o----o side + a0 c0 c1 a1 c2 + d/f0 d/f1 + d/z0 + +' . ./test-lib.sh test_expect_success setup ' -echo Hello > a && -git add a && -git commit -m "Initial commit" a && -initial=$(git rev-parse --verify HEAD) + echo Hello >a && + mkdir d && + echo World >d/f && + echo World >d/z && + git add a d && + test_tick && + git commit -m "Initial commit" && + git rev-parse --verify HEAD && + git tag initial ' test_expect_success path-optimization ' - commit=$(echo "Unchanged tree" | git commit-tree "HEAD^{tree}" -p HEAD) && - test $(git rev-list $commit | wc -l) = 2 && - test $(git rev-list $commit -- . | wc -l) = 1 + test_tick && + commit=$(echo "Unchanged tree" | git commit-tree "HEAD^{tree}" -p HEAD) && + test $(git rev-list $commit | wc -l) = 2 && + test $(git rev-list $commit -- . | wc -l) = 1 ' test_expect_success 'further setup' ' git checkout -b side && echo Irrelevant >c && - git add c && + echo Irrelevant >d/f && + git add c d/f && + test_tick && git commit -m "Side makes an irrelevant commit" && + git tag side_c0 && echo "More Irrelevancy" >c && git add c && + test_tick && git commit -m "Side makes another irrelevant commit" && echo Bye >a && git add a && + test_tick && git commit -m "Side touches a" && - side=$(git rev-parse --verify HEAD) && + git tag side_a1 && echo "Yet more Irrelevancy" >c && git add c && + test_tick && git commit -m "Side makes yet another irrelevant commit" && git checkout master && echo Another >b && - git add b && + echo Munged >d/z && + git add b d/z && + test_tick && git commit -m "Master touches b" && + git tag master_b0 && git merge side && echo Touched >b && git add b && + test_tick && git commit -m "Master touches b again" ' test_expect_success 'path optimization 2' ' - ( echo "$side"; echo "$initial" ) >expected && + git rev-parse side_a1 initial >expected && git rev-list HEAD -- a >actual && test_cmp expected actual ' +test_expect_success 'pathspec with leading path' ' + git rev-parse master^ master_b0 side_c0 initial >expected && + git rev-list HEAD -- d >actual && + test_cmp expected actual +' + +test_expect_success 'pathspec with glob (1)' ' + git rev-parse master^ master_b0 side_c0 initial >expected && + git rev-list HEAD -- "d/*" >actual && + test_cmp expected actual +' + +test_expect_success 'pathspec with glob (2)' ' + git rev-parse side_c0 initial >expected && + git rev-list HEAD -- "d/[a-m]*" >actual && + test_cmp expected actual +' + test_done diff --git a/t/t6038-merge-text-auto.sh b/t/t6038-merge-text-auto.sh index 460bf741b..d9c2d386d 100755 --- a/t/t6038-merge-text-auto.sh +++ b/t/t6038-merge-text-auto.sh @@ -14,7 +14,7 @@ test_description='CRLF merge conflict across text=auto change . ./test-lib.sh -test_have_prereq MINGW && SED_OPTIONS=-b +test_have_prereq SED_STRIPS_CR && SED_OPTIONS=-b test_expect_success setup ' git config core.autocrlf false && diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh index 2c49db9f6..874279e32 100755 --- a/t/t7400-submodule-basic.sh +++ b/t/t7400-submodule-basic.sh @@ -446,4 +446,42 @@ test_expect_success 'add should fail when path is used by an existing directory' ) ' +test_expect_success 'set up for relative path tests' ' + mkdir reltest && + ( + cd reltest && + git init && + mkdir sub && + ( + cd sub && + git init && + test_commit foo + ) && + git add sub && + git config -f .gitmodules submodule.sub.path sub && + git config -f .gitmodules submodule.sub.url ../subrepo && + cp .git/config pristine-.git-config + ) +' + +test_expect_success 'relative path works with URL' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + git config remote.origin.url ssh://hostname/repo && + git submodule init && + test "$(git config submodule.sub.url)" = ssh://hostname/subrepo + ) +' + +test_expect_success 'relative path works with user@host:path' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + git config remote.origin.url user@host:repo && + git submodule init && + test "$(git config submodule.sub.url)" = user@host:subrepo + ) +' + test_done diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh index d8ad25036..e5be13c27 100755 --- a/t/t7407-submodule-foreach.sh +++ b/t/t7407-submodule-foreach.sh @@ -238,6 +238,10 @@ test_expect_success 'ensure "status --cached --recursive" preserves the --cached ) && git submodule status --cached --recursive -- nested1 > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' diff --git a/t/t7500-commit.sh b/t/t7500-commit.sh index 162527c21..d551b77ce 100755 --- a/t/t7500-commit.sh +++ b/t/t7500-commit.sh @@ -10,7 +10,12 @@ Tests for selected commit options.' . ./test-lib.sh commit_msg_is () { - test "`git log --pretty=format:%s%b -1`" = "$1" + expect=commit_msg_is.expect + actual=commit_msg_is.actual + + printf "%s" "$(git log --pretty=format:%s%b -1)" >$expect && + printf "%s" "$1" >$actual && + test_cmp $expect $actual } # A sanity check to see if commit is working at all. diff --git a/t/t7505-prepare-commit-msg-hook.sh b/t/t7505-prepare-commit-msg-hook.sh index ff189624d..5b4b694f1 100755 --- a/t/t7505-prepare-commit-msg-hook.sh +++ b/t/t7505-prepare-commit-msg-hook.sh @@ -132,6 +132,18 @@ test_expect_success 'with hook (-c)' ' ' +test_expect_success 'with hook (merge)' ' + + head=`git rev-parse HEAD` && + git checkout -b other HEAD@{1} && + echo "more" >> file && + git add file && + git commit -m other && + git checkout - && + git merge other && + test "`git log -1 --pretty=format:%s`" = merge +' + cat > "$HOOK" <<'EOF' #!/bin/sh exit 1 diff --git a/t/t7607-merge-overwrite.sh b/t/t7607-merge-overwrite.sh index 4d5ce4e68..5f731a117 100755 --- a/t/t7607-merge-overwrite.sh +++ b/t/t7607-merge-overwrite.sh @@ -156,4 +156,20 @@ test_expect_success 'will not overwrite untracked file on unborn branch' ' test_cmp important c0.c ' +test_expect_success 'set up unborn branch and content' ' + git symbolic-ref HEAD refs/heads/unborn && + rm -f .git/index && + echo foo > tracked-file && + git add tracked-file && + echo bar > untracked-file +' + +test_expect_failure 'will not clobber WT/index when merging into unborn' ' + git merge master && + grep foo tracked-file && + git show :tracked-file >expect && + grep foo expect && + grep bar untracked-file +' + test_done diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh index c8777589c..8a7788dc3 100755 --- a/t/t7810-grep.sh +++ b/t/t7810-grep.sh @@ -182,6 +182,24 @@ do test_cmp expected actual ' + test_expect_success "grep --max-depth 0 -- . t $L" ' + { + echo ${HC}t/v:1:vvv + echo ${HC}v:1:vvv + } >expected && + git grep --max-depth 0 -n -e vvv $H -- . t >actual && + test_cmp expected actual + ' + + test_expect_success "grep --max-depth 0 -- t . $L" ' + { + echo ${HC}t/v:1:vvv + echo ${HC}v:1:vvv + } >expected && + git grep --max-depth 0 -n -e vvv $H -- t . >actual && + test_cmp expected actual + ' + done cat >expected <<EOF diff --git a/t/t9010-svn-fe.sh b/t/t9010-svn-fe.sh index c96bf2f5c..88a9751dd 100755 --- a/t/t9010-svn-fe.sh +++ b/t/t9010-svn-fe.sh @@ -4,22 +4,6 @@ test_description='check svn dumpfile importer' . ./test-lib.sh -if ! svnadmin -h >/dev/null 2>&1 -then - skip_all='skipping svn-fe tests, svn not available' - test_done -fi - -svnconf=$PWD/svnconf -export svnconf - -svn_cmd () { - subcommand=$1 && - shift && - mkdir -p "$svnconf" && - svn "$subcommand" --config-dir "$svnconf" "$@" -} - reinit_git () { rm -fr .git && git init @@ -41,10 +25,21 @@ test_expect_success 'v3 dumps not supported' ' test_cmp empty stream ' -test_expect_success 't9135/svn.dump' ' - svnadmin create simple-svn && - svnadmin load simple-svn <"$TEST_DIRECTORY/t9135/svn.dump" && - svn_cmd export "file://$PWD/simple-svn" simple-svnco && +test_expect_success 'set up svn repo' ' + svnconf=$PWD/svnconf && + mkdir -p "$svnconf" && + + if + svnadmin -h >/dev/null 2>&1 && + svnadmin create simple-svn && + svnadmin load simple-svn <"$TEST_DIRECTORY/t9135/svn.dump" && + svn export --config-dir "$svnconf" "file://$PWD/simple-svn" simple-svnco + then + test_set_prereq SVNREPO + fi +' + +test_expect_success SVNREPO 't9135/svn.dump' ' git init simple-git && test-svn-fe "$TEST_DIRECTORY/t9135/svn.dump" >simple.fe && ( diff --git a/t/t9157-git-svn-fetch-merge.sh b/t/t9157-git-svn-fetch-merge.sh index da582c538..991d2aa1b 100755 --- a/t/t9157-git-svn-fetch-merge.sh +++ b/t/t9157-git-svn-fetch-merge.sh @@ -6,6 +6,14 @@ test_description='git svn merge detection' . ./lib-git-svn.sh +svn_ver="$(svn --version --quiet)" +case $svn_ver in +0.* | 1.[0-4].*) + skip_all="skipping git-svn test - SVN too old ($svn_ver)" + test_done + ;; +esac + test_expect_success 'initialize source svn repo' ' svn_cmd mkdir -m x "$svnrepo"/trunk && svn_cmd mkdir -m x "$svnrepo"/branches && diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index 222d1059e..52ac0e56d 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -920,6 +920,48 @@ test_expect_success \ compare_diff_raw expect actual' 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 && + commit refs/heads/N-delete + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + collect data to be deleted + COMMIT + + deleteall + M 100644 inline foo/bar/baz + data <<DATA_END + hello + DATA_END + C "foo/bar/baz" "foo/bar/qux" + C "foo/bar/baz" "foo/bar/quux/1" + C "foo/bar/baz" "foo/bar/quuux" + M 040000 $empty_tree foo/bar/quux + M 040000 $empty_tree foo/bar/quuux + + commit refs/heads/N-delete + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + delete subdirectory + COMMIT + + M 040000 $empty_tree foo/bar/qux + INPUT_END + 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_expect_success \ 'N: modify copied tree' \ 'cat >expect <<-\EOF && :100644 100644 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 C100 newdir/interesting file3/file5 @@ -1706,6 +1748,61 @@ test_expect_success \ '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 && + echo "feature import-marks=nonexistent.marks" | + test_must_fail git fast-import +' + +test_expect_success 'R: import and output marks can be the same file' ' + rm -f io.marks && + blob=$(echo hi | git hash-object --stdin) && + cat >expect <<-EOF && + :1 $blob + :2 $blob + EOF + git fast-import --export-marks=io.marks <<-\EOF && + blob + mark :1 + data 3 + hi + + EOF + git fast-import --import-marks=io.marks --export-marks=io.marks <<-\EOF && + blob + mark :2 + data 3 + hi + + EOF + test_cmp expect io.marks +' + +test_expect_success 'R: --import-marks=foo --output-marks=foo to create foo fails' ' + rm -f io.marks && + test_must_fail git fast-import --import-marks=io.marks --export-marks=io.marks <<-\EOF + blob + mark :1 + data 3 + hi + + EOF +' + +test_expect_success 'R: --import-marks-if-exists' ' + rm -f io.marks && + blob=$(echo hi | git hash-object --stdin) && + echo ":1 $blob" >expect && + git fast-import --import-marks-if-exists=io.marks --export-marks=io.marks <<-\EOF && + blob + mark :1 + data 3 + hi + + EOF + test_cmp expect io.marks +' + cat >input << EOF feature import-marks=marks.out feature export-marks=marks.new diff --git a/t/t9301-fast-import-notes.sh b/t/t9301-fast-import-notes.sh index 7cf8cd8a2..463254c72 100755 --- a/t/t9301-fast-import-notes.sh +++ b/t/t9301-fast-import-notes.sh @@ -120,6 +120,7 @@ test_expect_success 'add notes with simple M command' ' test_tick cat >input <<INPUT_END +feature notes commit refs/notes/test committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE data <<COMMIT diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh index 21cd286bb..afac5b56a 100755 --- a/t/t9500-gitweb-standalone-no-errors.sh +++ b/t/t9500-gitweb-standalone-no-errors.sh @@ -18,42 +18,34 @@ or warnings to log.' test_expect_success \ 'no commits: projects_list (implicit)' \ 'gitweb_run' -test_debug 'cat gitweb.log' test_expect_success \ 'no commits: projects_index' \ 'gitweb_run "a=project_index"' -test_debug 'cat gitweb.log' test_expect_success \ 'no commits: .git summary (implicit)' \ 'gitweb_run "p=.git"' -test_debug 'cat gitweb.log' test_expect_success \ 'no commits: .git commit (implicit HEAD)' \ 'gitweb_run "p=.git;a=commit"' -test_debug 'cat gitweb.log' test_expect_success \ 'no commits: .git commitdiff (implicit HEAD)' \ 'gitweb_run "p=.git;a=commitdiff"' -test_debug 'cat gitweb.log' test_expect_success \ 'no commits: .git tree (implicit HEAD)' \ 'gitweb_run "p=.git;a=tree"' -test_debug 'cat gitweb.log' test_expect_success \ 'no commits: .git heads' \ 'gitweb_run "p=.git;a=heads"' -test_debug 'cat gitweb.log' test_expect_success \ 'no commits: .git tags' \ 'gitweb_run "p=.git;a=tags"' -test_debug 'cat gitweb.log' # ---------------------------------------------------------------------- @@ -69,52 +61,42 @@ test_expect_success \ test_expect_success \ 'projects_list (implicit)' \ 'gitweb_run' -test_debug 'cat gitweb.log' test_expect_success \ 'projects_index' \ 'gitweb_run "a=project_index"' -test_debug 'cat gitweb.log' test_expect_success \ '.git summary (implicit)' \ 'gitweb_run "p=.git"' -test_debug 'cat gitweb.log' test_expect_success \ '.git commit (implicit HEAD)' \ 'gitweb_run "p=.git;a=commit"' -test_debug 'cat gitweb.log' test_expect_success \ '.git commitdiff (implicit HEAD, root commit)' \ 'gitweb_run "p=.git;a=commitdiff"' -test_debug 'cat gitweb.log' test_expect_success \ '.git commitdiff_plain (implicit HEAD, root commit)' \ 'gitweb_run "p=.git;a=commitdiff_plain"' -test_debug 'cat gitweb.log' test_expect_success \ '.git commit (HEAD)' \ 'gitweb_run "p=.git;a=commit;h=HEAD"' -test_debug 'cat gitweb.log' test_expect_success \ '.git tree (implicit HEAD)' \ 'gitweb_run "p=.git;a=tree"' -test_debug 'cat gitweb.log' test_expect_success \ '.git blob (file)' \ 'gitweb_run "p=.git;a=blob;f=file"' -test_debug 'cat gitweb.log' test_expect_success \ '.git blob_plain (file)' \ 'gitweb_run "p=.git;a=blob_plain;f=file"' -test_debug 'cat gitweb.log' # ---------------------------------------------------------------------- # nonexistent objects @@ -122,37 +104,30 @@ test_debug 'cat gitweb.log' test_expect_success \ '.git commit (non-existent)' \ 'gitweb_run "p=.git;a=commit;h=non-existent"' -test_debug 'cat gitweb.log' test_expect_success \ '.git commitdiff (non-existent)' \ 'gitweb_run "p=.git;a=commitdiff;h=non-existent"' -test_debug 'cat gitweb.log' test_expect_success \ '.git commitdiff (non-existent vs HEAD)' \ 'gitweb_run "p=.git;a=commitdiff;hp=non-existent;h=HEAD"' -test_debug 'cat gitweb.log' test_expect_success \ '.git tree (0000000000000000000000000000000000000000)' \ 'gitweb_run "p=.git;a=tree;h=0000000000000000000000000000000000000000"' -test_debug 'cat gitweb.log' test_expect_success \ '.git tag (0000000000000000000000000000000000000000)' \ 'gitweb_run "p=.git;a=tag;h=0000000000000000000000000000000000000000"' -test_debug 'cat gitweb.log' test_expect_success \ '.git blob (non-existent)' \ 'gitweb_run "p=.git;a=blob;f=non-existent"' -test_debug 'cat gitweb.log' test_expect_success \ '.git blob_plain (non-existent)' \ 'gitweb_run "p=.git;a=blob_plain;f=non-existent"' -test_debug 'cat gitweb.log' # ---------------------------------------------------------------------- @@ -161,7 +136,6 @@ test_debug 'cat gitweb.log' test_expect_success \ 'commitdiff(0): root' \ 'gitweb_run "p=.git;a=commitdiff"' -test_debug 'cat gitweb.log' test_expect_success \ 'commitdiff(0): file added' \ @@ -169,21 +143,18 @@ test_expect_success \ git add new_file && git commit -a -m "File added." && gitweb_run "p=.git;a=commitdiff"' -test_debug 'cat gitweb.log' test_expect_success \ 'commitdiff(0): mode change' \ 'test_chmod +x new_file && git commit -a -m "Mode changed." && gitweb_run "p=.git;a=commitdiff"' -test_debug 'cat gitweb.log' test_expect_success \ 'commitdiff(0): file renamed' \ 'git mv new_file renamed_file && git commit -a -m "File renamed." && gitweb_run "p=.git;a=commitdiff"' -test_debug 'cat gitweb.log' test_expect_success SYMLINKS \ 'commitdiff(0): file to symlink' \ @@ -191,7 +162,6 @@ test_expect_success SYMLINKS \ ln -s file renamed_file && git commit -a -m "File to symlink." && gitweb_run "p=.git;a=commitdiff"' -test_debug 'cat gitweb.log' test_expect_success \ 'commitdiff(0): file deleted' \ @@ -199,7 +169,6 @@ test_expect_success \ rm -f renamed_file && git commit -a -m "File removed." && gitweb_run "p=.git;a=commitdiff"' -test_debug 'cat gitweb.log' test_expect_success \ 'commitdiff(0): file copied / new file' \ @@ -207,7 +176,6 @@ test_expect_success \ git add file2 && git commit -a -m "File copied." && gitweb_run "p=.git;a=commitdiff"' -test_debug 'cat gitweb.log' test_expect_success \ 'commitdiff(0): mode change and modified' \ @@ -215,7 +183,6 @@ test_expect_success \ test_chmod +x file2 && git commit -a -m "Mode change and modification." && gitweb_run "p=.git;a=commitdiff"' -test_debug 'cat gitweb.log' test_expect_success \ 'commitdiff(0): renamed and modified' \ @@ -233,7 +200,6 @@ EOF echo "Propter nomen suum." >> file3 && git commit -a -m "File rename and modification." && gitweb_run "p=.git;a=commitdiff"' -test_debug 'cat gitweb.log' test_expect_success \ 'commitdiff(0): renamed, mode change and modified' \ @@ -242,7 +208,6 @@ test_expect_success \ test_chmod +x file2 && git commit -a -m "File rename, mode change and modification." && gitweb_run "p=.git;a=commitdiff"' -test_debug 'cat gitweb.log' # ---------------------------------------------------------------------- # commitdiff testing (taken from t4114-apply-typechange.sh) @@ -279,42 +244,34 @@ test_expect_success SYMLINKS 'setup typechange commits' ' test_expect_success \ 'commitdiff(2): file renamed from foo to foo/baz' \ 'gitweb_run "p=.git;a=commitdiff;hp=initial;h=foo-baz-renamed-from-foo"' -test_debug 'cat gitweb.log' test_expect_success \ 'commitdiff(2): file renamed from foo/baz to foo' \ 'gitweb_run "p=.git;a=commitdiff;hp=foo-baz-renamed-from-foo;h=initial"' -test_debug 'cat gitweb.log' test_expect_success \ 'commitdiff(2): directory becomes file' \ 'gitweb_run "p=.git;a=commitdiff;hp=foo-becomes-a-directory;h=initial"' -test_debug 'cat gitweb.log' test_expect_success \ 'commitdiff(2): file becomes directory' \ 'gitweb_run "p=.git;a=commitdiff;hp=initial;h=foo-becomes-a-directory"' -test_debug 'cat gitweb.log' test_expect_success \ 'commitdiff(2): file becomes symlink' \ 'gitweb_run "p=.git;a=commitdiff;hp=initial;h=foo-symlinked-to-bar"' -test_debug 'cat gitweb.log' test_expect_success \ 'commitdiff(2): symlink becomes file' \ 'gitweb_run "p=.git;a=commitdiff;hp=foo-symlinked-to-bar;h=foo-back-to-file"' -test_debug 'cat gitweb.log' test_expect_success \ 'commitdiff(2): symlink becomes directory' \ 'gitweb_run "p=.git;a=commitdiff;hp=foo-symlinked-to-bar;h=foo-becomes-a-directory"' -test_debug 'cat gitweb.log' test_expect_success \ 'commitdiff(2): directory becomes symlink' \ 'gitweb_run "p=.git;a=commitdiff;hp=foo-becomes-a-directory;h=foo-symlinked-to-bar"' -test_debug 'cat gitweb.log' # ---------------------------------------------------------------------- # commit, commitdiff: merge, large @@ -330,12 +287,10 @@ test_expect_success \ test_expect_success \ 'commit(0): merge commit' \ 'gitweb_run "p=.git;a=commit"' -test_debug 'cat gitweb.log' test_expect_success \ 'commitdiff(0): merge commit' \ 'gitweb_run "p=.git;a=commitdiff"' -test_debug 'cat gitweb.log' test_expect_success \ 'Prepare large commit' \ @@ -371,12 +326,10 @@ test_expect_success \ test_expect_success \ 'commit(1): large commit' \ 'gitweb_run "p=.git;a=commit;h=b"' -test_debug 'cat gitweb.log' test_expect_success \ 'commitdiff(1): large commit' \ 'gitweb_run "p=.git;a=commitdiff;h=b"' -test_debug 'cat gitweb.log' # ---------------------------------------------------------------------- # tags testing @@ -394,17 +347,14 @@ test_expect_success \ git tag lightweight/tag-tree HEAD^{tree} && git tag lightweight/tag-blob HEAD:file && gitweb_run "p=.git;a=tags"' -test_debug 'cat gitweb.log' test_expect_success \ 'tag: Tag to commit object' \ 'gitweb_run "p=.git;a=tag;h=tag-commit"' -test_debug 'cat gitweb.log' test_expect_success \ 'tag: on lightweight tag (invalid)' \ 'gitweb_run "p=.git;a=tag;h=lightweight/tag-commit"' -test_debug 'cat gitweb.log' # ---------------------------------------------------------------------- # logs @@ -412,22 +362,18 @@ test_debug 'cat gitweb.log' test_expect_success \ 'logs: log (implicit HEAD)' \ 'gitweb_run "p=.git;a=log"' -test_debug 'cat gitweb.log' test_expect_success \ 'logs: shortlog (implicit HEAD)' \ 'gitweb_run "p=.git;a=shortlog"' -test_debug 'cat gitweb.log' test_expect_success \ 'logs: history (implicit HEAD, file)' \ 'gitweb_run "p=.git;a=history;f=file"' -test_debug 'cat gitweb.log' test_expect_success \ 'logs: history (implicit HEAD, non-existent file)' \ 'gitweb_run "p=.git;a=history;f=non-existent"' -test_debug 'cat gitweb.log' test_expect_success \ 'logs: history (implicit HEAD, deleted file)' \ @@ -438,55 +384,45 @@ test_expect_success \ git rm deleted_file && git commit -m "Delete file" && gitweb_run "p=.git;a=history;f=deleted_file"' -test_debug 'cat gitweb.log' # ---------------------------------------------------------------------- # path_info links test_expect_success \ 'path_info: project' \ 'gitweb_run "" "/.git"' -test_debug 'cat gitweb.log' test_expect_success \ 'path_info: project/branch' \ 'gitweb_run "" "/.git/b"' -test_debug 'cat gitweb.log' test_expect_success \ 'path_info: project/branch:file' \ 'gitweb_run "" "/.git/master:file"' -test_debug 'cat gitweb.log' test_expect_success \ 'path_info: project/branch:dir/' \ 'gitweb_run "" "/.git/master:foo/"' -test_debug 'cat gitweb.log' test_expect_success \ 'path_info: project/branch:file (non-existent)' \ 'gitweb_run "" "/.git/master:non-existent"' -test_debug 'cat gitweb.log' test_expect_success \ 'path_info: project/branch:dir/ (non-existent)' \ 'gitweb_run "" "/.git/master:non-existent/"' -test_debug 'cat gitweb.log' test_expect_success \ 'path_info: project/branch:/file' \ 'gitweb_run "" "/.git/master:/file"' -test_debug 'cat gitweb.log' test_expect_success \ 'path_info: project/:/file (implicit HEAD)' \ 'gitweb_run "" "/.git/:/file"' -test_debug 'cat gitweb.log' test_expect_success \ 'path_info: project/:/ (implicit HEAD, top tree)' \ 'gitweb_run "" "/.git/:/"' -test_debug 'cat gitweb.log' # ---------------------------------------------------------------------- @@ -495,17 +431,14 @@ test_debug 'cat gitweb.log' test_expect_success \ 'feeds: OPML' \ 'gitweb_run "a=opml"' -test_debug 'cat gitweb.log' test_expect_success \ 'feed: RSS' \ 'gitweb_run "p=.git;a=rss"' -test_debug 'cat gitweb.log' test_expect_success \ 'feed: Atom' \ 'gitweb_run "p=.git;a=atom"' -test_debug 'cat gitweb.log' # ---------------------------------------------------------------------- # encoding/decoding @@ -513,27 +446,28 @@ test_debug 'cat gitweb.log' test_expect_success \ 'encode(commit): utf8' \ '. "$TEST_DIRECTORY"/t3901-utf8.txt && + test_when_finished "GIT_AUTHOR_NAME=\"A U Thor\"" && + test_when_finished "GIT_COMMITTER_NAME=\"C O Mitter\"" && echo "UTF-8" >> file && git add file && git commit -F "$TEST_DIRECTORY"/t3900/1-UTF-8.txt && gitweb_run "p=.git;a=commit"' -test_debug 'cat gitweb.log' test_expect_success \ 'encode(commit): iso-8859-1' \ '. "$TEST_DIRECTORY"/t3901-8859-1.txt && + test_when_finished "GIT_AUTHOR_NAME=\"A U Thor\"" && + test_when_finished "GIT_COMMITTER_NAME=\"C O Mitter\"" && echo "ISO-8859-1" >> file && git add file && git config i18n.commitencoding ISO-8859-1 && + test_when_finished "git config --unset i18n.commitencoding" && git commit -F "$TEST_DIRECTORY"/t3900/ISO8859-1.txt && - git config --unset i18n.commitencoding && gitweb_run "p=.git;a=commit"' -test_debug 'cat gitweb.log' test_expect_success \ 'encode(log): utf-8 and iso-8859-1' \ 'gitweb_run "p=.git;a=log"' -test_debug 'cat gitweb.log' # ---------------------------------------------------------------------- # extra options @@ -541,27 +475,22 @@ test_debug 'cat gitweb.log' test_expect_success \ 'opt: log --no-merges' \ 'gitweb_run "p=.git;a=log;opt=--no-merges"' -test_debug 'cat gitweb.log' test_expect_success \ 'opt: atom --no-merges' \ 'gitweb_run "p=.git;a=log;opt=--no-merges"' -test_debug 'cat gitweb.log' test_expect_success \ 'opt: "file" history --no-merges' \ 'gitweb_run "p=.git;a=history;f=file;opt=--no-merges"' -test_debug 'cat gitweb.log' test_expect_success \ 'opt: log --no-such-option (invalid option)' \ 'gitweb_run "p=.git;a=log;opt=--no-such-option"' -test_debug 'cat gitweb.log' test_expect_success \ 'opt: tree --no-merges (invalid option for action)' \ 'gitweb_run "p=.git;a=tree;opt=--no-merges"' -test_debug 'cat gitweb.log' # ---------------------------------------------------------------------- # testing config_to_multi / cloneurl @@ -569,14 +498,12 @@ test_debug 'cat gitweb.log' test_expect_success \ 'URL: no project URLs, no base URL' \ 'gitweb_run "p=.git;a=summary"' -test_debug 'cat gitweb.log' test_expect_success \ 'URL: project URLs via gitweb.url' \ 'git config --add gitweb.url git://example.com/git/trash.git && git config --add gitweb.url http://example.com/git/trash.git && gitweb_run "p=.git;a=summary"' -test_debug 'cat gitweb.log' cat >.git/cloneurl <<\EOF git://example.com/git/trash.git @@ -586,7 +513,6 @@ EOF test_expect_success \ 'URL: project URLs via cloneurl file' \ 'gitweb_run "p=.git;a=summary"' -test_debug 'cat gitweb.log' # ---------------------------------------------------------------------- # gitweb config and repo config @@ -604,12 +530,10 @@ EOF test_expect_success \ 'config override: projects list (implicit)' \ 'gitweb_run' -test_debug 'cat gitweb.log' test_expect_success \ 'config override: tree view, features not overridden in repo config' \ 'gitweb_run "p=.git;a=tree"' -test_debug 'cat gitweb.log' test_expect_success \ 'config override: tree view, features disabled in repo config' \ @@ -617,14 +541,12 @@ test_expect_success \ git config gitweb.snapshot none && git config gitweb.avatar gravatar && gitweb_run "p=.git;a=tree"' -test_debug 'cat gitweb.log' test_expect_success \ 'config override: tree view, features enabled in repo config (1)' \ 'git config gitweb.blame yes && git config gitweb.snapshot "zip,tgz, tbz2" && gitweb_run "p=.git;a=tree"' -test_debug 'cat gitweb.log' cat >.git/config <<\EOF # testing noval and alternate separator @@ -635,7 +557,6 @@ EOF test_expect_success \ 'config override: tree view, features enabled in repo config (2)' \ 'gitweb_run "p=.git;a=tree"' -test_debug 'cat gitweb.log' # ---------------------------------------------------------------------- # non-ASCII in README.html @@ -645,7 +566,6 @@ test_expect_success \ 'echo "<b>UTF-8 example:</b><br />" > .git/README.html && cat "$TEST_DIRECTORY"/t3900/1-UTF-8.txt >> .git/README.html && gitweb_run "p=.git;a=summary"' -test_debug 'cat gitweb.log' # ---------------------------------------------------------------------- # syntax highlighting @@ -666,7 +586,6 @@ test_expect_success HIGHLIGHT \ 'syntax highlighting (no highlight, unknown syntax)' \ 'git config gitweb.highlight yes && gitweb_run "p=.git;a=blob;f=file"' -test_debug 'cat gitweb.log' test_expect_success HIGHLIGHT \ 'syntax highlighting (highlighted, shell script)' \ @@ -675,6 +594,5 @@ test_expect_success HIGHLIGHT \ git add test.sh && git commit -m "Add test.sh" && gitweb_run "p=.git;a=blob;f=test.sh"' -test_debug 'cat gitweb.log' test_done diff --git a/t/t9501-gitweb-standalone-http-status.sh b/t/t9501-gitweb-standalone-http-status.sh index 18825aff8..26102ee9b 100755 --- a/t/t9501-gitweb-standalone-http-status.sh +++ b/t/t9501-gitweb-standalone-http-status.sh @@ -126,7 +126,6 @@ test_expect_success 'load checking: load too high (default action)' ' grep "Status: 503 Service Unavailable" gitweb.headers && grep "503 - The load average on the server is too high" gitweb.body ' -test_debug 'cat gitweb.log' # just in case test_debug 'cat gitweb.headers' # turn off load checking diff --git a/t/t9700/test.pl b/t/t9700/test.pl index c15ca2d64..13ba96e21 100755 --- a/t/t9700/test.pl +++ b/t/t9700/test.pl @@ -113,6 +113,16 @@ like($last_commit, qr/^[0-9a-fA-F]{40}$/, 'rev-parse returned hash'); my $dir_commit = $r2->command_oneline('log', '-n1', '--pretty=format:%H', '.'); isnt($last_commit, $dir_commit, 'log . does not show last commit'); +# commands outside working tree +chdir($abs_repo_dir . '/..'); +my $r3 = Git->repository(Directory => $abs_repo_dir); +my $tmpfile3 = "$abs_repo_dir/file3.tmp"; +open TEMPFILE3, "+>$tmpfile3" or die "Can't open $tmpfile3: $!"; +is($r3->cat_blob($file1hash, \*TEMPFILE3), 15, "cat_blob(outside): size"); +close TEMPFILE3; +unlink $tmpfile3; +chdir($abs_repo_dir); + printf "1..%d\n", Test::More->builder->current_test; my $is_passing = eval { Test::More->is_passing }; diff --git a/t/t9800-git-p4.sh b/t/t9800-git-p4.sh new file mode 100755 index 000000000..1969e6b9d --- /dev/null +++ b/t/t9800-git-p4.sh @@ -0,0 +1,100 @@ +#!/bin/sh + +test_description='git-p4 tests' + +. ./test-lib.sh + +( p4 -h && p4d -h ) >/dev/null 2>&1 || { + skip_all='skipping git-p4 tests; no p4 or p4d' + test_done +} + +GITP4=$GIT_BUILD_DIR/contrib/fast-import/git-p4 +P4DPORT=10669 + +db="$TRASH_DIRECTORY/db" +cli="$TRASH_DIRECTORY/cli" +git="$TRASH_DIRECTORY/git" + +test_debug 'echo p4d -q -d -r "$db" -p $P4DPORT' +test_expect_success setup ' + mkdir -p "$db" && + p4d -q -d -r "$db" -p $P4DPORT && + mkdir -p "$cli" && + mkdir -p "$git" && + export P4PORT=localhost:$P4DPORT +' + +test_expect_success 'add p4 files' ' + cd "$cli" && + p4 client -i <<-EOF && + Client: client + Description: client + Root: $cli + View: //depot/... //client/... + EOF + export P4CLIENT=client && + echo file1 >file1 && + p4 add file1 && + p4 submit -d "file1" && + cd "$TRASH_DIRECTORY" +' + +test_expect_success 'basic git-p4 clone' ' + "$GITP4" clone --dest="$git" //depot && + rm -rf "$git" && mkdir "$git" +' + +test_expect_success 'exit when p4 fails to produce marshaled output' ' + badp4dir="$TRASH_DIRECTORY/badp4dir" && + mkdir -p "$badp4dir" && + cat >"$badp4dir"/p4 <<-EOF && + #!$SHELL_PATH + exit 1 + EOF + chmod 755 "$badp4dir"/p4 && + PATH="$badp4dir:$PATH" "$GITP4" clone --dest="$git" //depot >errs 2>&1 ; retval=$? && + test $retval -eq 1 && + test_must_fail grep -q Traceback errs +' + +test_expect_success 'add p4 files with wildcards in the names' ' + cd "$cli" && + echo file-wild-hash >file-wild#hash && + echo file-wild-star >file-wild\*star && + echo file-wild-at >file-wild@at && + echo file-wild-percent >file-wild%percent && + p4 add -f file-wild* && + p4 submit -d "file wildcards" && + cd "$TRASH_DIRECTORY" +' + +test_expect_success 'wildcard files git-p4 clone' ' + "$GITP4" clone --dest="$git" //depot && + cd "$git" && + test -f file-wild#hash && + test -f file-wild\*star && + test -f file-wild@at && + test -f file-wild%percent && + cd "$TRASH_DIRECTORY" && + rm -rf "$git" && mkdir "$git" +' + +test_expect_success 'clone bare' ' + "$GITP4" clone --dest="$git" --bare //depot && + cd "$git" && + test ! -d .git && + bare=`git config --get core.bare` && + test "$bare" = true && + cd "$TRASH_DIRECTORY" && + rm -rf "$git" && mkdir "$git" +' + +test_expect_success 'shutdown' ' + pid=`pgrep -f p4d` && + test -n "$pid" && + test_debug "ps wl `echo $pid`" && + kill $pid +' + +test_done diff --git a/t/test-lib.sh b/t/test-lib.sh index cb1ca973a..0fdc541a7 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -70,6 +70,9 @@ unset GIT_NOTES_REF unset GIT_NOTES_DISPLAY_REF unset GIT_NOTES_REWRITE_REF unset GIT_NOTES_REWRITE_MODE +unset GIT_REFLOG_ACTION +unset GIT_CHERRY_PICK_HELP +unset GIT_QUIET GIT_MERGE_VERBOSITY=5 export GIT_MERGE_VERBOSITY export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME @@ -1057,6 +1060,13 @@ case $(uname -s) in # backslashes in pathspec are converted to '/' # exec does not inherit the PID test_set_prereq MINGW + test_set_prereq SED_STRIPS_CR + ;; +*CYGWIN*) + test_set_prereq POSIXPERM + test_set_prereq EXECKEEPSPID + test_set_prereq NOT_MINGW + test_set_prereq SED_STRIPS_CR ;; *) test_set_prereq POSIXPERM @@ -56,7 +56,7 @@ static unsigned long parse_tag_date(const char *buf, const char *tail) return strtoul(dateptr, NULL, 10); } -int parse_tag_buffer(struct tag *item, void *data, unsigned long size) +int parse_tag_buffer(struct tag *item, const void *data, unsigned long size) { unsigned char sha1[20]; char type[20]; @@ -97,7 +97,9 @@ int parse_tag_buffer(struct tag *item, void *data, unsigned long size) item->tagged = NULL; } - if (prefixcmp(bufptr, "tag ")) + if (bufptr + 4 < tail && !prefixcmp(bufptr, "tag ")) + ; /* good */ + else return -1; bufptr += 4; nl = memchr(bufptr, '\n', tail - bufptr); @@ -106,7 +108,7 @@ int parse_tag_buffer(struct tag *item, void *data, unsigned long size) item->tag = xmemdupz(bufptr, nl - bufptr); bufptr = nl + 1; - if (!prefixcmp(bufptr, "tagger ")) + if (bufptr + 7 < tail && !prefixcmp(bufptr, "tagger ")) item->date = parse_tag_date(bufptr, tail); else item->date = 0; @@ -13,7 +13,7 @@ struct tag { }; extern struct tag *lookup_tag(const unsigned char *sha1); -extern int parse_tag_buffer(struct tag *item, void *data, unsigned long size); +extern int parse_tag_buffer(struct tag *item, const void *data, unsigned long size); extern int parse_tag(struct tag *item); extern struct object *deref_tag(struct object *, const char *, int); extern size_t parse_signature(const char *buf, unsigned long size); diff --git a/test-mktemp.c b/test-mktemp.c new file mode 100644 index 000000000..c8c54213a --- /dev/null +++ b/test-mktemp.c @@ -0,0 +1,14 @@ +/* + * test-mktemp.c: code to exercise the creation of temporary files + */ +#include "git-compat-util.h" + +int main(int argc, char *argv[]) +{ + if (argc != 2) + usage("Expected 1 parameter defining the temporary file template"); + + xmkstemp(xstrdup(argv[1])); + + return 0; +} @@ -154,6 +154,7 @@ static const char *quote_crnl(const char *path) /* FIXME: move prefix to startup_info struct and get rid of this arg */ void trace_repo_setup(const char *prefix) { + const char *git_work_tree; char cwd[PATH_MAX]; char *trace = getenv("GIT_TRACE"); @@ -164,8 +165,14 @@ void trace_repo_setup(const char *prefix) if (!getcwd(cwd, PATH_MAX)) die("Unable to get current working directory"); + if (!(git_work_tree = get_git_work_tree())) + git_work_tree = "(null)"; + + if (!prefix) + prefix = "(null)"; + trace_printf("setup: git_dir: %s\n", quote_crnl(get_git_dir())); - trace_printf("setup: worktree: %s\n", quote_crnl(get_git_work_tree())); + trace_printf("setup: worktree: %s\n", quote_crnl(git_work_tree)); trace_printf("setup: cwd: %s\n", quote_crnl(cwd)); trace_printf("setup: prefix: %s\n", quote_crnl(prefix)); } diff --git a/tree-diff.c b/tree-diff.c index 12c9a8888..3954281f5 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -6,34 +6,18 @@ #include "diffcore.h" #include "tree.h" -static char *malloc_base(const char *base, int baselen, const char *path, int pathlen) -{ - char *newbase = xmalloc(baselen + pathlen + 2); - memcpy(newbase, base, baselen); - memcpy(newbase + baselen, path, pathlen); - memcpy(newbase + baselen + pathlen, "/", 2); - return newbase; -} +static void show_entry(struct diff_options *opt, const char *prefix, + struct tree_desc *desc, struct strbuf *base); -static char *malloc_fullname(const char *base, int baselen, const char *path, int pathlen) -{ - char *fullname = xmalloc(baselen + pathlen + 1); - memcpy(fullname, base, baselen); - memcpy(fullname + baselen, path, pathlen); - fullname[baselen + pathlen] = 0; - return fullname; -} - -static void show_entry(struct diff_options *opt, const char *prefix, struct tree_desc *desc, - const char *base, int baselen); - -static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const char *base, int baselen, struct diff_options *opt) +static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, + struct strbuf *base, struct diff_options *opt) { unsigned mode1, mode2; const char *path1, *path2; const unsigned char *sha1, *sha2; int cmp, pathlen1, pathlen2; - char *fullname; + int old_baselen = base->len; + int retval = 0; sha1 = tree_entry_extract(t1, &path1, &mode1); sha2 = tree_entry_extract(t2, &path2, &mode2); @@ -42,11 +26,11 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const pathlen2 = tree_entry_len(path2, sha2); cmp = base_name_compare(path1, pathlen1, mode1, path2, pathlen2, mode2); if (cmp < 0) { - show_entry(opt, "-", t1, base, baselen); + show_entry(opt, "-", t1, base); return -1; } if (cmp > 0) { - show_entry(opt, "+", t2, base, baselen); + show_entry(opt, "+", t2, base); return 1; } if (!DIFF_OPT_TST(opt, FIND_COPIES_HARDER) && !hashcmp(sha1, sha2) && mode1 == mode2) @@ -57,149 +41,29 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const * file, we need to consider it a remove and an add. */ if (S_ISDIR(mode1) != S_ISDIR(mode2)) { - show_entry(opt, "-", t1, base, baselen); - show_entry(opt, "+", t2, base, baselen); + show_entry(opt, "-", t1, base); + show_entry(opt, "+", t2, base); return 0; } + strbuf_add(base, path1, pathlen1); if (DIFF_OPT_TST(opt, RECURSIVE) && S_ISDIR(mode1)) { - int retval; - char *newbase = malloc_base(base, baselen, path1, pathlen1); if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE)) { - newbase[baselen + pathlen1] = 0; opt->change(opt, mode1, mode2, - sha1, sha2, newbase, 0, 0); - newbase[baselen + pathlen1] = '/'; + sha1, sha2, base->buf, 0, 0); } - retval = diff_tree_sha1(sha1, sha2, newbase, opt); - free(newbase); - return retval; + strbuf_addch(base, '/'); + retval = diff_tree_sha1(sha1, sha2, base->buf, opt); + } else { + opt->change(opt, mode1, mode2, sha1, sha2, base->buf, 0, 0); } - - fullname = malloc_fullname(base, baselen, path1, pathlen1); - opt->change(opt, mode1, mode2, sha1, sha2, fullname, 0, 0); - free(fullname); + strbuf_setlen(base, old_baselen); return 0; } -/* - * Is a tree entry interesting given the pathspec we have? - * - * Pre-condition: baselen == 0 || base[baselen-1] == '/' - * - * Return: - * - 2 for "yes, and all subsequent entries will be" - * - 1 for yes - * - zero for no - * - negative for "no, and no subsequent entries will be either" - */ -static int tree_entry_interesting(struct tree_desc *desc, const char *base, int baselen, struct diff_options *opt) -{ - const char *path; - const unsigned char *sha1; - unsigned mode; - int i; - int pathlen; - int never_interesting = -1; - - if (!opt->nr_paths) - return 2; - - sha1 = tree_entry_extract(desc, &path, &mode); - - pathlen = tree_entry_len(path, sha1); - - for (i = 0; i < opt->nr_paths; i++) { - const char *match = opt->paths[i]; - int matchlen = opt->pathlens[i]; - int m = -1; /* signals that we haven't called strncmp() */ - - if (baselen >= matchlen) { - /* If it doesn't match, move along... */ - if (strncmp(base, match, matchlen)) - continue; - - /* - * If the base is a subdirectory of a path which - * was specified, all of them are interesting. - */ - if (!matchlen || - base[matchlen] == '/' || - match[matchlen - 1] == '/') - return 2; - - /* Just a random prefix match */ - continue; - } - - /* Does the base match? */ - if (strncmp(base, match, baselen)) - continue; - - match += baselen; - matchlen -= baselen; - - if (never_interesting) { - /* - * We have not seen any match that sorts later - * than the current path. - */ - - /* - * Does match sort strictly earlier than path - * with their common parts? - */ - m = strncmp(match, path, - (matchlen < pathlen) ? matchlen : pathlen); - if (m < 0) - continue; - - /* - * If we come here even once, that means there is at - * least one pathspec that would sort equal to or - * later than the path we are currently looking at. - * In other words, if we have never reached this point - * after iterating all pathspecs, it means all - * pathspecs are either outside of base, or inside the - * base but sorts strictly earlier than the current - * one. In either case, they will never match the - * subsequent entries. In such a case, we initialized - * the variable to -1 and that is what will be - * returned, allowing the caller to terminate early. - */ - never_interesting = 0; - } - - if (pathlen > matchlen) - continue; - - if (matchlen > pathlen) { - if (match[pathlen] != '/') - continue; - if (!S_ISDIR(mode)) - continue; - } - - if (m == -1) - /* - * we cheated and did not do strncmp(), so we do - * that here. - */ - m = strncmp(match, path, pathlen); - - /* - * If common part matched earlier then it is a hit, - * because we rejected the case where path is not a - * leading directory and is shorter than match. - */ - if (!m) - return 1; - } - return never_interesting; /* No matches */ -} - /* A whole sub-tree went away or appeared */ -static void show_tree(struct diff_options *opt, const char *prefix, struct tree_desc *desc, const char *base, int baselen) +static void show_tree(struct diff_options *opt, const char *prefix, + struct tree_desc *desc, struct strbuf *base) { int all_interesting = 0; while (desc->size) { @@ -208,31 +72,32 @@ static void show_tree(struct diff_options *opt, const char *prefix, struct tree_ if (all_interesting) show = 1; else { - show = tree_entry_interesting(desc, base, baselen, - opt); + show = tree_entry_interesting(&desc->entry, base, 0, + &opt->pathspec); if (show == 2) all_interesting = 1; } if (show < 0) break; if (show) - show_entry(opt, prefix, desc, base, baselen); + show_entry(opt, prefix, desc, base); update_tree_entry(desc); } } /* A file entry went away or appeared */ -static void show_entry(struct diff_options *opt, const char *prefix, struct tree_desc *desc, - const char *base, int baselen) +static void show_entry(struct diff_options *opt, const char *prefix, + struct tree_desc *desc, struct strbuf *base) { unsigned mode; const char *path; const unsigned char *sha1 = tree_entry_extract(desc, &path, &mode); int pathlen = tree_entry_len(path, sha1); + int old_baselen = base->len; + strbuf_add(base, path, pathlen); if (DIFF_OPT_TST(opt, RECURSIVE) && S_ISDIR(mode)) { enum object_type type; - char *newbase = malloc_base(base, baselen, path, pathlen); struct tree_desc inner; void *tree; unsigned long size; @@ -241,28 +106,25 @@ static void show_entry(struct diff_options *opt, const char *prefix, struct tree if (!tree || type != OBJ_TREE) die("corrupt tree sha %s", sha1_to_hex(sha1)); - if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE)) { - newbase[baselen + pathlen] = 0; - opt->add_remove(opt, *prefix, mode, sha1, newbase, 0); - newbase[baselen + pathlen] = '/'; - } + if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE)) + opt->add_remove(opt, *prefix, mode, sha1, base->buf, 0); - init_tree_desc(&inner, tree, size); - show_tree(opt, prefix, &inner, newbase, baselen + 1 + pathlen); + strbuf_addch(base, '/'); + init_tree_desc(&inner, tree, size); + show_tree(opt, prefix, &inner, base); free(tree); - free(newbase); - } else { - char *fullname = malloc_fullname(base, baselen, path, pathlen); - opt->add_remove(opt, prefix[0], mode, sha1, fullname, 0); - free(fullname); - } + } else + opt->add_remove(opt, prefix[0], mode, sha1, base->buf, 0); + + strbuf_setlen(base, old_baselen); } -static void skip_uninteresting(struct tree_desc *t, const char *base, int baselen, struct diff_options *opt, int *all_interesting) +static void skip_uninteresting(struct tree_desc *t, struct strbuf *base, + struct diff_options *opt, int *all_interesting) { while (t->size) { - int show = tree_entry_interesting(t, base, baselen, opt); + int show = tree_entry_interesting(&t->entry, base, 0, &opt->pathspec); if (show == 2) *all_interesting = 1; if (!show) { @@ -276,37 +138,44 @@ static void skip_uninteresting(struct tree_desc *t, const char *base, int basele } } -int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, struct diff_options *opt) +int diff_tree(struct tree_desc *t1, struct tree_desc *t2, + const char *base_str, struct diff_options *opt) { - int baselen = strlen(base); + struct strbuf base; + int baselen = strlen(base_str); int all_t1_interesting = 0; int all_t2_interesting = 0; + /* Enable recursion indefinitely */ + opt->pathspec.recursive = DIFF_OPT_TST(opt, RECURSIVE); + opt->pathspec.max_depth = -1; + + strbuf_init(&base, PATH_MAX); + strbuf_add(&base, base_str, baselen); + for (;;) { if (DIFF_OPT_TST(opt, QUICK) && DIFF_OPT_TST(opt, HAS_CHANGES)) break; - if (opt->nr_paths) { + if (opt->pathspec.nr) { if (!all_t1_interesting) - skip_uninteresting(t1, base, baselen, opt, - &all_t1_interesting); + skip_uninteresting(t1, &base, opt, &all_t1_interesting); if (!all_t2_interesting) - skip_uninteresting(t2, base, baselen, opt, - &all_t2_interesting); + skip_uninteresting(t2, &base, opt, &all_t2_interesting); } if (!t1->size) { if (!t2->size) break; - show_entry(opt, "+", t2, base, baselen); + show_entry(opt, "+", t2, &base); update_tree_entry(t2); continue; } if (!t2->size) { - show_entry(opt, "-", t1, base, baselen); + show_entry(opt, "-", t1, &base); update_tree_entry(t1); continue; } - switch (compare_tree_entry(t1, t2, base, baselen, opt)) { + switch (compare_tree_entry(t1, t2, &base, opt)) { case -1: update_tree_entry(t1); continue; @@ -319,6 +188,8 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, stru } die("git diff-tree: internal error"); } + + strbuf_release(&base); return 0; } @@ -349,7 +220,7 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co DIFF_OPT_SET(&diff_opts, RECURSIVE); DIFF_OPT_SET(&diff_opts, FIND_COPIES_HARDER); diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT; - diff_opts.single_follow = opt->paths[0]; + diff_opts.single_follow = opt->pathspec.raw[0]; diff_opts.break_opt = opt->break_opt; paths[0] = NULL; diff_tree_setup_paths(paths, &diff_opts); @@ -369,15 +240,16 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co * diff_queued_diff, we will also use that as the path in * the future! */ - if ((p->status == 'R' || p->status == 'C') && !strcmp(p->two->path, opt->paths[0])) { + if ((p->status == 'R' || p->status == 'C') && + !strcmp(p->two->path, opt->pathspec.raw[0])) { /* Switch the file-pairs around */ q->queue[i] = choice; choice = p; /* Update the path we use from now on.. */ diff_tree_release_paths(opt); - opt->paths[0] = xstrdup(p->one->path); - diff_tree_setup_paths(opt->paths, opt); + opt->pathspec.raw[0] = xstrdup(p->one->path); + diff_tree_setup_paths(opt->pathspec.raw, opt); /* * The caller expects us to return a set of vanilla @@ -452,36 +324,12 @@ int diff_root_tree_sha1(const unsigned char *new, const char *base, struct diff_ return retval; } -static int count_paths(const char **paths) -{ - int i = 0; - while (*paths++) - i++; - return i; -} - void diff_tree_release_paths(struct diff_options *opt) { - free(opt->pathlens); + free_pathspec(&opt->pathspec); } void diff_tree_setup_paths(const char **p, struct diff_options *opt) { - opt->nr_paths = 0; - opt->pathlens = NULL; - opt->paths = NULL; - - if (p) { - int i; - - opt->paths = p; - opt->nr_paths = count_paths(p); - if (opt->nr_paths == 0) { - opt->pathlens = NULL; - return; - } - opt->pathlens = xmalloc(opt->nr_paths * sizeof(int)); - for (i=0; i < opt->nr_paths; i++) - opt->pathlens[i] = strlen(p[i]); - } + init_pathspec(&opt->pathspec, p); } diff --git a/tree-walk.c b/tree-walk.c index a9bbf4e23..322becc3b 100644 --- a/tree-walk.c +++ b/tree-walk.c @@ -1,6 +1,7 @@ #include "cache.h" #include "tree-walk.h" #include "unpack-trees.h" +#include "dir.h" #include "tree.h" static const char *get_mode(const char *str, unsigned int *modep) @@ -455,3 +456,186 @@ int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned ch free(tree); return retval; } + +static int match_entry(const struct name_entry *entry, int pathlen, + const char *match, int matchlen, + int *never_interesting) +{ + int m = -1; /* signals that we haven't called strncmp() */ + + if (*never_interesting) { + /* + * We have not seen any match that sorts later + * than the current path. + */ + + /* + * Does match sort strictly earlier than path + * with their common parts? + */ + m = strncmp(match, entry->path, + (matchlen < pathlen) ? matchlen : pathlen); + if (m < 0) + return 0; + + /* + * If we come here even once, that means there is at + * least one pathspec that would sort equal to or + * later than the path we are currently looking at. + * In other words, if we have never reached this point + * after iterating all pathspecs, it means all + * pathspecs are either outside of base, or inside the + * base but sorts strictly earlier than the current + * one. In either case, they will never match the + * subsequent entries. In such a case, we initialized + * the variable to -1 and that is what will be + * returned, allowing the caller to terminate early. + */ + *never_interesting = 0; + } + + if (pathlen > matchlen) + return 0; + + if (matchlen > pathlen) { + if (match[pathlen] != '/') + return 0; + if (!S_ISDIR(entry->mode)) + return 0; + } + + if (m == -1) + /* + * we cheated and did not do strncmp(), so we do + * that here. + */ + m = strncmp(match, entry->path, pathlen); + + /* + * If common part matched earlier then it is a hit, + * because we rejected the case where path is not a + * leading directory and is shorter than match. + */ + if (!m) + return 1; + + return 0; +} + +static int match_dir_prefix(const char *base, int baselen, + const char *match, int matchlen) +{ + if (strncmp(base, match, matchlen)) + return 0; + + /* + * If the base is a subdirectory of a path which + * was specified, all of them are interesting. + */ + if (!matchlen || + base[matchlen] == '/' || + match[matchlen - 1] == '/') + return 1; + + /* Just a random prefix match */ + return 0; +} + +/* + * Is a tree entry interesting given the pathspec we have? + * + * Pre-condition: either baselen == base_offset (i.e. empty path) + * or base[baselen-1] == '/' (i.e. with trailing slash). + * + * Return: + * - 2 for "yes, and all subsequent entries will be" + * - 1 for yes + * - zero for no + * - negative for "no, and no subsequent entries will be either" + */ +int tree_entry_interesting(const struct name_entry *entry, + struct strbuf *base, int base_offset, + const struct pathspec *ps) +{ + int i; + int pathlen, baselen = base->len - base_offset; + int never_interesting = ps->has_wildcard ? 0 : -1; + + if (!ps->nr) { + if (!ps->recursive || ps->max_depth == -1) + return 2; + return !!within_depth(base->buf + base_offset, baselen, + !!S_ISDIR(entry->mode), + ps->max_depth); + } + + pathlen = tree_entry_len(entry->path, entry->sha1); + + for (i = ps->nr - 1; i >= 0; i--) { + const struct pathspec_item *item = ps->items+i; + const char *match = item->match; + const char *base_str = base->buf + base_offset; + int matchlen = item->len; + + if (baselen >= matchlen) { + /* If it doesn't match, move along... */ + if (!match_dir_prefix(base_str, baselen, match, matchlen)) + goto match_wildcards; + + if (!ps->recursive || ps->max_depth == -1) + return 2; + + return !!within_depth(base_str + matchlen + 1, + baselen - matchlen - 1, + !!S_ISDIR(entry->mode), + ps->max_depth); + } + + /* Does the base match? */ + if (!strncmp(base_str, match, baselen)) { + if (match_entry(entry, pathlen, + match + baselen, matchlen - baselen, + &never_interesting)) + return 1; + + if (ps->items[i].has_wildcard) { + if (!fnmatch(match + baselen, entry->path, 0)) + return 1; + + /* + * Match all directories. We'll try to + * match files later on. + */ + if (ps->recursive && S_ISDIR(entry->mode)) + return 1; + } + + continue; + } + +match_wildcards: + if (!ps->items[i].has_wildcard) + continue; + + /* + * Concatenate base and entry->path into one and do + * fnmatch() on it. + */ + + strbuf_add(base, entry->path, pathlen); + + if (!fnmatch(match, base->buf + base_offset, 0)) { + strbuf_setlen(base, base_offset + baselen); + return 1; + } + strbuf_setlen(base, base_offset + baselen); + + /* + * Match all directories. We'll try to match files + * later on. + */ + if (ps->recursive && S_ISDIR(entry->mode)) + return 1; + } + return never_interesting; /* No matches */ +} diff --git a/tree-walk.h b/tree-walk.h index 7e3e0b5ad..39524b7db 100644 --- a/tree-walk.h +++ b/tree-walk.h @@ -60,4 +60,6 @@ static inline int traverse_path_len(const struct traverse_info *info, const stru return info->pathlen + tree_entry_len(n->path, n->sha1); } +extern int tree_entry_interesting(const struct name_entry *, struct strbuf *, int, const struct pathspec *ps); + #endif diff --git a/unpack-trees.c b/unpack-trees.c index 1ca41b1a6..b68ec820d 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -381,7 +381,7 @@ static void add_same_unmerged(struct cache_entry *ce, static int unpack_index_entry(struct cache_entry *ce, struct unpack_trees_options *o) { - struct cache_entry *src[5] = { NULL }; + struct cache_entry *src[MAX_UNPACK_TREES + 1] = { NULL, }; int ret; src[0] = ce; @@ -427,7 +427,10 @@ static int switch_cache_bottom(struct traverse_info *info) return ret; } -static int traverse_trees_recursive(int n, unsigned long dirmask, unsigned long df_conflicts, struct name_entry *names, struct traverse_info *info) +static int traverse_trees_recursive(int n, unsigned long dirmask, + unsigned long df_conflicts, + struct name_entry *names, + struct traverse_info *info) { int i, ret, bottom; struct tree_desc t[MAX_UNPACK_TREES]; @@ -1105,6 +1108,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options } if (o->result.cache_nr && empty_worktree) { + /* dubious---why should this fail??? */ ret = unpack_failed(o, "Sparse checkout leaves no entry on working directory"); goto done; } @@ -1374,16 +1378,22 @@ static int verify_absent_1(struct cache_entry *ce, char path[PATH_MAX + 1]; memcpy(path, ce->name, len); path[len] = 0; - lstat(path, &st); + if (lstat(path, &st)) + return error("cannot stat '%s': %s", path, + strerror(errno)); return check_ok_to_remove(path, len, DT_UNKNOWN, NULL, &st, error_type, o); - } else if (!lstat(ce->name, &st)) + } else if (lstat(ce->name, &st)) { + if (errno != ENOENT) + return error("cannot stat '%s': %s", ce->name, + strerror(errno)); + return 0; + } else { return check_ok_to_remove(ce->name, ce_namelen(ce), - ce_to_dtype(ce), ce, &st, - error_type, o); - - return 0; + ce_to_dtype(ce), ce, &st, + error_type, o); + } } static int verify_absent(struct cache_entry *ce, diff --git a/userdiff.c b/userdiff.c index 2d5453697..1ff47977d 100644 --- a/userdiff.c +++ b/userdiff.c @@ -8,9 +8,11 @@ static int ndrivers; static int drivers_alloc; #define PATTERNS(name, pattern, word_regex) \ - { name, NULL, -1, { pattern, REG_EXTENDED }, word_regex } + { name, NULL, -1, { pattern, REG_EXTENDED }, \ + word_regex "|[^[:space:]]|[\xc0-\xff][\x80-\xbf]+" } #define IPATTERN(name, pattern, word_regex) \ - { name, NULL, -1, { pattern, REG_EXTENDED | REG_ICASE }, word_regex } + { name, NULL, -1, { pattern, REG_EXTENDED | REG_ICASE }, \ + word_regex "|[^[:space:]]|[\xc0-\xff][\x80-\xbf]+" } static struct userdiff_driver builtin_drivers[] = { IPATTERN("fortran", "!^([C*]|[ \t]*!)\n" @@ -24,10 +26,9 @@ IPATTERN("fortran", * Don't worry about format statements without leading digits since * they would have been matched above as a variable anyway. */ "|[-+]?[0-9.]+([AaIiDdEeFfLlTtXx][Ss]?[-+]?[0-9.]*)?(_[a-zA-Z0-9][a-zA-Z0-9_]*)?" - "|//|\\*\\*|::|[/<>=]=" - "|[^[:space:]]|[\x80-\xff]+"), + "|//|\\*\\*|::|[/<>=]="), PATTERNS("html", "^[ \t]*(<[Hh][1-6][ \t].*>.*)$", - "[^<>= \t]+|[^[:space:]]|[\x80-\xff]+"), + "[^<>= \t]+"), PATTERNS("java", "!^[ \t]*(catch|do|for|if|instanceof|new|return|switch|throw|while)\n" "^[ \t]*(([A-Za-z_][A-Za-z_0-9]*[ \t]+)+[A-Za-z_][A-Za-z_0-9]*[ \t]*\\([^;]*)$", @@ -35,8 +36,7 @@ PATTERNS("java", "[a-zA-Z_][a-zA-Z0-9_]*" "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?" "|[-+*/<>%&^|=!]=" - "|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|" - "|[^[:space:]]|[\x80-\xff]+"), + "|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|"), PATTERNS("objc", /* Negate C statements that can look like functions */ "!^[ \t]*(do|for|if|else|return|switch|while)\n" @@ -49,43 +49,54 @@ PATTERNS("objc", /* -- */ "[a-zA-Z_][a-zA-Z0-9_]*" "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?" - "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->" - "|[^[:space:]]|[\x80-\xff]+"), + "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->"), PATTERNS("pascal", - "^((procedure|function|constructor|destructor|interface|" + "^(((class[ \t]+)?(procedure|function)|constructor|destructor|interface|" "implementation|initialization|finalization)[ \t]*.*)$" "\n" "^(.*=[ \t]*(class|record).*)$", /* -- */ "[a-zA-Z_][a-zA-Z0-9_]*" "|[-+0-9.e]+|0[xXbB]?[0-9a-fA-F]+" - "|<>|<=|>=|:=|\\.\\." - "|[^[:space:]]|[\x80-\xff]+"), + "|<>|<=|>=|:=|\\.\\."), +PATTERNS("perl", + "^[ \t]*package .*;\n" + "^[ \t]*sub .* \\{\n" + "^[A-Z]+ \\{\n" /* BEGIN, END, ... */ + "^=head[0-9] ", /* POD */ + /* -- */ + "[[:alpha:]_'][[:alnum:]_']*" + "|0[xb]?[0-9a-fA-F_]*" + /* taking care not to interpret 3..5 as (3.)(.5) */ + "|[0-9a-fA-F_]+(\\.[0-9a-fA-F_]+)?([eE][-+]?[0-9_]+)?" + "|=>|-[rwxoRWXOezsfdlpSugkbctTBMAC>]|~~|::" + "|&&=|\\|\\|=|//=|\\*\\*=" + "|&&|\\|\\||//|\\+\\+|--|\\*\\*|\\.\\.\\.?" + "|[-+*/%.^&<>=!|]=" + "|=~|!~" + "|<<|<>|<=>|>>"), PATTERNS("php", "^[\t ]*(((public|protected|private|static)[\t ]+)*function.*)$\n" "^[\t ]*(class.*)$", /* -- */ "[a-zA-Z_][a-zA-Z0-9_]*" "|[-+0-9.e]+|0[xXbB]?[0-9a-fA-F]+" - "|[-+*/<>%&^|=!.]=|--|\\+\\+|<<=?|>>=?|===|&&|\\|\\||::|->" - "|[^[:space:]]|[\x80-\xff]+"), + "|[-+*/<>%&^|=!.]=|--|\\+\\+|<<=?|>>=?|===|&&|\\|\\||::|->"), PATTERNS("python", "^[ \t]*((class|def)[ \t].*)$", /* -- */ "[a-zA-Z_][a-zA-Z0-9_]*" "|[-+0-9.e]+[jJlL]?|0[xX]?[0-9a-fA-F]+[lL]?" - "|[-+*/<>%&^|=!]=|//=?|<<=?|>>=?|\\*\\*=?" - "|[^[:space:]]|[\x80-\xff]+"), + "|[-+*/<>%&^|=!]=|//=?|<<=?|>>=?|\\*\\*=?"), /* -- */ PATTERNS("ruby", "^[ \t]*((class|module|def)[ \t].*)$", /* -- */ "(@|@@|\\$)?[a-zA-Z_][a-zA-Z0-9_]*" "|[-+0-9.e]+|0[xXbB]?[0-9a-fA-F]+|\\?(\\\\C-)?(\\\\M-)?." - "|//=?|[-+*/<>%&^|=!]=|<<=?|>>=?|===|\\.{1,3}|::|[!=]~" - "|[^[:space:]]|[\x80-\xff]+"), + "|//=?|[-+*/<>%&^|=!]=|<<=?|>>=?|===|\\.{1,3}|::|[!=]~"), PATTERNS("bibtex", "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$", "[={}\"]|[^={}\" \t]+"), PATTERNS("tex", "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$", - "\\\\[a-zA-Z@]+|\\\\.|[a-zA-Z0-9\x80-\xff]+|[^[:space:]]"), + "\\\\[a-zA-Z@]+|\\\\.|[a-zA-Z0-9\x80-\xff]+"), PATTERNS("cpp", /* Jump targets or access declarations */ "!^[ \t]*[A-Za-z_][A-Za-z_0-9]*:.*$\n" @@ -96,8 +107,7 @@ PATTERNS("cpp", /* -- */ "[a-zA-Z_][a-zA-Z0-9_]*" "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?" - "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->" - "|[^[:space:]]|[\x80-\xff]+"), + "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->"), PATTERNS("csharp", /* Keywords */ "!^[ \t]*(do|while|for|if|else|instanceof|new|return|switch|case|throw|catch|using)\n" @@ -112,8 +122,7 @@ PATTERNS("csharp", /* -- */ "[a-zA-Z_][a-zA-Z0-9_]*" "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?" - "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->" - "|[^[:space:]]|[\x80-\xff]+"), + "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->"), { "default", NULL, -1, { NULL, 0 } }, }; #undef PATTERNS diff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c index fa580e62d..2ad2c307d 100644 --- a/vcs-svn/svndump.c +++ b/vcs-svn/svndump.c @@ -211,7 +211,7 @@ void svndump_read(const char *url) if (key == keys.svn_fs_dump_format_version) { dump_ctx.version = atoi(val); if (dump_ctx.version > 2) - die("expected svn dump format version <= 2, found %d", + die("expected svn dump format version <= 2, found %"PRIu32, dump_ctx.version); } else if (key == keys.uuid) { dump_ctx.uuid = pool_intern(val); @@ -53,7 +53,7 @@ void *xmalloc(size_t size) void *xmallocz(size_t size) { void *ret; - if (size + 1 < size) + if (unsigned_add_overflows(size, 1)) die("Data too large to fit into virtual memory space."); ret = xmalloc(size + 1); ((char*)ret)[size] = 0; @@ -198,10 +198,22 @@ FILE *xfdopen(int fd, const char *mode) int xmkstemp(char *template) { int fd; + char origtemplate[PATH_MAX]; + strlcpy(origtemplate, template, sizeof(origtemplate)); fd = mkstemp(template); - if (fd < 0) - die_errno("Unable to create temporary file"); + if (fd < 0) { + int saved_errno = errno; + const char *nonrelative_template; + + if (!template[0]) + template = origtemplate; + + nonrelative_template = make_nonrelative_path(template); + errno = saved_errno; + die_errno("Unable to create temporary file '%s'", + nonrelative_template); + } return fd; } @@ -321,10 +333,22 @@ int gitmkstemps(char *pattern, int suffix_len) int xmkstemp_mode(char *template, int mode) { int fd; + char origtemplate[PATH_MAX]; + strlcpy(origtemplate, template, sizeof(origtemplate)); fd = git_mkstemp_mode(template, mode); - if (fd < 0) - die_errno("Unable to create temporary file"); + if (fd < 0) { + int saved_errno = errno; + const char *nonrelative_template; + + if (!template[0]) + template = origtemplate; + + nonrelative_template = make_nonrelative_path(template); + errno = saved_errno; + die_errno("Unable to create temporary file '%s'", + nonrelative_template); + } return fd; } diff --git a/wt-status.c b/wt-status.c index 123582b6c..a82b11d34 100644 --- a/wt-status.c +++ b/wt-status.c @@ -323,7 +323,7 @@ static void wt_status_collect_changes_worktree(struct wt_status *s) } rev.diffopt.format_callback = wt_status_collect_changed_cb; rev.diffopt.format_callback_data = s; - rev.prune_data = s->pathspec; + init_pathspec(&rev.prune_data, s->pathspec); run_diff_files(&rev, 0); } @@ -348,20 +348,22 @@ static void wt_status_collect_changes_index(struct wt_status *s) rev.diffopt.detect_rename = 1; rev.diffopt.rename_limit = 200; rev.diffopt.break_opt = 0; - rev.prune_data = s->pathspec; + init_pathspec(&rev.prune_data, s->pathspec); run_diff_index(&rev, 1); } static void wt_status_collect_changes_initial(struct wt_status *s) { + struct pathspec pathspec; int i; + init_pathspec(&pathspec, s->pathspec); for (i = 0; i < active_nr; i++) { struct string_list_item *it; struct wt_status_change_data *d; struct cache_entry *ce = active_cache[i]; - if (!ce_path_match(ce, s->pathspec)) + if (!ce_path_match(ce, &pathspec)) continue; it = string_list_insert(&s->change, ce->name); d = it->util; @@ -376,6 +378,7 @@ static void wt_status_collect_changes_initial(struct wt_status *s) else d->index_status = DIFF_STATUS_ADDED; } + free_pathspec(&pathspec); } static void wt_status_collect_untracked(struct wt_status *s) |