From: Junio C Hamano Date: Thu, 10 Mar 2016 19:13:38 +0000 (-0800) Subject: Merge branch 'ps/config-error' into maint X-Git-Tag: v2.7.3~18 X-Git-Url: https://www.git.lorimer.id.au/gitweb.git/diff_plain/2d5ff66c134681d846e5102a9a62ec99c2178fe1?hp=3d1806487af395fb33d1de92633e96571b296305 Merge branch 'ps/config-error' into maint Many codepaths forget to check return value from git_config_set(); the function is made to die() to make sure we do not proceed when setting a configuration variable failed. * ps/config-error: config: rename git_config_set_or_die to git_config_set config: rename git_config_set to git_config_set_gently compat: die when unable to set core.precomposeunicode sequencer: die on config error when saving replay opts init-db: die on config errors when initializing empty repo clone: die on config error in cmd_clone remote: die on config error when manipulating remotes remote: die on config error when setting/adding branches remote: die on config error when setting URL submodule--helper: die on config error when cloning module submodule: die on config error when linking modules branch: die on config error when editing branch description branch: die on config error when unsetting upstream branch: report errors in tracking branch setup config: introduce set_or_die wrappers --- diff --git a/Documentation/RelNotes/2.7.2.txt b/Documentation/RelNotes/2.7.2.txt new file mode 100644 index 0000000000..4feef76704 --- /dev/null +++ b/Documentation/RelNotes/2.7.2.txt @@ -0,0 +1,41 @@ +Git v2.7.2 Release Notes +======================== + +Fixes since v2.7.1 +------------------ + + * The low-level merge machinery has been taught to use CRLF line + termination when inserting conflict markers to merged contents that + are themselves CRLF line-terminated. + + * "git worktree" had a broken code that attempted to auto-fix + possible inconsistency that results from end-users moving a + worktree to different places without telling Git (the original + repository needs to maintain backpointers to its worktrees, but + "mv" run by end-users who are not familiar with that fact will + obviously not adjust them), which actually made things worse + when triggered. + + * "git push --force-with-lease" has been taught to report if the push + needed to force (or fast-forwarded). + + * The emulated "yes" command used in our test scripts has been + tweaked not to spend too much time generating unnecessary output + that is not used, to help those who test on Windows where it would + not stop until it fills the pipe buffer due to lack of SIGPIPE. + + * The vimdiff backend for "git mergetool" has been tweaked to arrange + and number buffers in the order that would match the expectation of + majority of people who read left to right, then top down and assign + buffers 1 2 3 4 "mentally" to local base remote merge windows based + on that order. + + * The documentation for "git clean" has been corrected; it mentioned + that .git/modules/* are removed by giving two "-f", which has never + been the case. + + * Paths that have been told the index about with "add -N" are not + quite yet in the index, but a few commands behaved as if they + already are in a harmful way. + +Also includes tiny documentation and test updates. diff --git a/Documentation/git-clean.txt b/Documentation/git-clean.txt index 641681f61a..51a7e26a8e 100644 --- a/Documentation/git-clean.txt +++ b/Documentation/git-clean.txt @@ -37,9 +37,7 @@ OPTIONS to false, 'git clean' will refuse to delete files or directories unless given -f, -n or -i. Git will refuse to delete directories with .git sub directory or file unless a second -f - is given. This affects also git submodules where the storage area - of the removed submodule under .git/modules/ is not removed until - -f is given twice. + is given. -i:: --interactive:: diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt index 5b9ad0429c..62c76c1c89 100644 --- a/Documentation/git-worktree.txt +++ b/Documentation/git-worktree.txt @@ -32,11 +32,9 @@ The working tree's administrative files in the repository (see `git worktree prune` in the main or any linked working tree to clean up any stale administrative files. -If you move a linked working tree to another file system, or -within a file system that does not support hard links, you need to run -at least one git command inside the linked working tree -(e.g. `git status`) in order to update its administrative files in the -repository so that they do not get automatically pruned. +If you move a linked working tree, you need to manually update the +administrative files so that they do not get pruned automatically. See +section "DETAILS" for more information. If a linked working tree is stored on a portable device or network share which is not always mounted, you can prevent its administrative files from @@ -137,6 +135,13 @@ thumb is do not make any assumption about whether a path belongs to $GIT_DIR or $GIT_COMMON_DIR when you need to directly access something inside $GIT_DIR. Use `git rev-parse --git-path` to get the final path. +If you move a linked working tree, you need to update the 'gitdir' file +in the entry's directory. For example, if a linked working tree is moved +to `/newpath/test-next` and its `.git` file points to +`/path/main/.git/worktrees/test-next`, then update +`/path/main/.git/worktrees/test-next/gitdir` to reference `/newpath/test-next` +instead. + To prevent a $GIT_DIR/worktrees entry from being pruned (which can be useful in some situations, such as when the entry's working tree is stored on a portable device), add a file named diff --git a/Documentation/git.txt b/Documentation/git.txt index d987ad20c9..68a71b46c9 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -43,9 +43,10 @@ unreleased) version of Git, that is available from the 'master' branch of the `git.git` repository. Documentation for older releases are available here: -* link:v2.7.1/git.html[documentation for release 2.7.1] +* link:v2.7.2/git.html[documentation for release 2.7.2] * release notes for + link:RelNotes/2.7.2.txt[2.7.2], link:RelNotes/2.7.1.txt[2.7.1], link:RelNotes/2.7.0.txt[2.7]. diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 330b339d1c..d7ab24e356 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v2.7.1 +DEF_VER=v2.7.2 LF=' ' diff --git a/RelNotes b/RelNotes index 213c0d0850..64e8170aa2 120000 --- a/RelNotes +++ b/RelNotes @@ -1 +1 @@ -Documentation/RelNotes/2.7.1.txt \ No newline at end of file +Documentation/RelNotes/2.7.2.txt \ No newline at end of file diff --git a/builtin/blame.c b/builtin/blame.c index 1df13cf7f4..5265f79edc 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -2392,11 +2392,6 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt, ce->ce_mode = create_ce_mode(mode); add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE); - /* - * We are not going to write this out, so this does not matter - * right now, but someday we might optimize diff-index --cached - * with cache-tree information. - */ cache_tree_invalidate_path(&the_index, path); return commit; diff --git a/builtin/grep.c b/builtin/grep.c index 4229cae390..3ba35ecf93 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -375,7 +375,7 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int for (nr = 0; nr < active_nr; nr++) { const struct cache_entry *ce = active_cache[nr]; - if (!S_ISREG(ce->ce_mode)) + if (!S_ISREG(ce->ce_mode) || ce_intent_to_add(ce)) continue; if (!ce_path_match(ce, pathspec, NULL)) continue; diff --git a/builtin/rm.c b/builtin/rm.c index 80b972f92f..8829b09d0b 100644 --- a/builtin/rm.c +++ b/builtin/rm.c @@ -211,7 +211,7 @@ static int check_local_mod(unsigned char *head, int index_only) * "intent to add" entry. */ if (local_changes && staged_changes) { - if (!index_only || !(ce->ce_flags & CE_INTENT_TO_ADD)) + if (!index_only || !ce_intent_to_add(ce)) string_list_append(&files_staged, name); } else if (!index_only) { diff --git a/builtin/stripspace.c b/builtin/stripspace.c index 7ff8434f7c..15e716ef43 100644 --- a/builtin/stripspace.c +++ b/builtin/stripspace.c @@ -35,7 +35,7 @@ int cmd_stripspace(int argc, const char **argv, const char *prefix) N_("skip and remove all lines starting with comment character"), STRIP_COMMENTS), OPT_CMDMODE('c', "comment-lines", &mode, - N_("prepend comment character and blank to each line"), + N_("prepend comment character and space to each line"), COMMENT_LINES), OPT_END() }; diff --git a/cache-tree.c b/cache-tree.c index a59e6f1e1f..20ee7b52df 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -377,7 +377,7 @@ static int update_one(struct cache_tree *it, * they are not part of generated trees. Invalidate up * to root to force cache-tree users to read elsewhere. */ - if (ce->ce_flags & CE_INTENT_TO_ADD) { + if (ce_intent_to_add(ce)) { to_invalidate = 1; continue; } diff --git a/cache.h b/cache.h index dd39270f93..e2e64d188e 100644 --- a/cache.h +++ b/cache.h @@ -259,6 +259,7 @@ static inline unsigned create_ce_flags(unsigned stage) #define ce_uptodate(ce) ((ce)->ce_flags & CE_UPTODATE) #define ce_skip_worktree(ce) ((ce)->ce_flags & CE_SKIP_WORKTREE) #define ce_mark_uptodate(ce) ((ce)->ce_flags |= CE_UPTODATE) +#define ce_intent_to_add(ce) ((ce)->ce_flags & CE_INTENT_TO_ADD) #define ce_permissions(mode) (((mode) & 0100) ? 0755 : 0644) static inline unsigned int create_ce_mode(unsigned int mode) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 63f5c046a2..00d729996f 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -2413,8 +2413,8 @@ _git_stash () show,--*|branch,--*) ;; branch,*) - if [ $cword -eq 3 ]; then - __gitcomp_nl "$(__git_refs)"; + if [ $cword -eq 3 ]; then + __gitcomp_nl "$(__git_refs)"; else __gitcomp_nl "$(git --git-dir="$(__gitdir)" stash list \ | sed -n -e 's/:.*//p')" diff --git a/git-cvsserver.perl b/git-cvsserver.perl index 95e69b19a7..02c0445be1 100755 --- a/git-cvsserver.perl +++ b/git-cvsserver.perl @@ -2664,7 +2664,7 @@ sub argsfromdir # co # Obtain list directly. # remove # HERE: TEST: MAYBE client does the recursion for us, # # since it only makes sense to remove stuff already in - # # the sandobx? + # # the sandbox? # ci # HERE: Similar to remove... # # Don't try to implement the confusing/weird # # ci -r bug er.."feature". diff --git a/mergetools/vimdiff b/mergetools/vimdiff index 1ddfbfcd78..74ea6d5479 100644 --- a/mergetools/vimdiff +++ b/mergetools/vimdiff @@ -9,8 +9,8 @@ merge_cmd () { gvimdiff|vimdiff) if $base_present then - "$merge_tool_path" -f -d -c 'wincmd J' \ - "$MERGED" "$LOCAL" "$BASE" "$REMOTE" + "$merge_tool_path" -f -d -c '4wincmd w | wincmd J' \ + "$LOCAL" "$BASE" "$REMOTE" "$MERGED" else "$merge_tool_path" -f -d -c 'wincmd l' \ "$LOCAL" "$MERGED" "$REMOTE" diff --git a/read-cache.c b/read-cache.c index 84616c8e21..5be7cd1dbf 100644 --- a/read-cache.c +++ b/read-cache.c @@ -327,7 +327,7 @@ int ie_match_stat(const struct index_state *istate, * by definition never matches what is in the work tree until it * actually gets added. */ - if (ce->ce_flags & CE_INTENT_TO_ADD) + if (ce_intent_to_add(ce)) return DATA_CHANGED | TYPE_CHANGED | MODE_CHANGED; changed = ce_match_stat_basic(ce, st); @@ -1237,7 +1237,7 @@ int refresh_index(struct index_state *istate, unsigned int flags, if (cache_errno == ENOENT) fmt = deleted_fmt; - else if (ce->ce_flags & CE_INTENT_TO_ADD) + else if (ce_intent_to_add(ce)) fmt = added_fmt; /* must be before other checks */ else if (changed & TYPE_CHANGED) fmt = typechange_fmt; diff --git a/remote-curl.c b/remote-curl.c index f404faf0f4..e114f24448 100644 --- a/remote-curl.c +++ b/remote-curl.c @@ -439,8 +439,20 @@ static int run_slot(struct active_request_slot *slot, err = run_one_slot(slot, results); if (err != HTTP_OK && err != HTTP_REAUTH) { - error("RPC failed; result=%d, HTTP code = %ld", - results->curl_result, results->http_code); + struct strbuf msg = STRBUF_INIT; + if (results->http_code && results->http_code != 200) + strbuf_addf(&msg, "HTTP %ld", results->http_code); + if (results->curl_result != CURLE_OK) { + if (msg.len) + strbuf_addch(&msg, ' '); + strbuf_addf(&msg, "curl %d", results->curl_result); + if (curl_errorstr[0]) { + strbuf_addch(&msg, ' '); + strbuf_addstr(&msg, curl_errorstr); + } + } + error("RPC failed; %s", msg.buf); + strbuf_release(&msg); } return err; diff --git a/remote.c b/remote.c index 9d34b5a5da..3ceac07620 100644 --- a/remote.c +++ b/remote.c @@ -1545,11 +1545,8 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror, } /* - * Bypass the usual "must fast-forward" check but - * replace it with a weaker "the old value must be - * this value we observed". If the remote ref has - * moved and is now different from what we expect, - * reject any push. + * If the remote ref has moved and is now different + * from what we expect, reject any push. * * It also is an error if the user told us to check * with the remote-tracking branch to find the value @@ -1560,10 +1557,14 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror, if (ref->expect_old_no_trackback || oidcmp(&ref->old_oid, &ref->old_oid_expect)) reject_reason = REF_STATUS_REJECT_STALE; + else + /* If the ref isn't stale then force the update. */ + force_ref_update = 1; } /* - * The usual "must fast-forward" rules. + * If the update isn't already rejected then check + * the usual "must fast-forward" rules. * * Decide whether an individual refspec A:B can be * pushed. The push will succeed if any of the @@ -1582,7 +1583,7 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror, * passing the --force argument */ - else if (!ref->deletion && !is_null_oid(&ref->old_oid)) { + if (!reject_reason && !ref->deletion && !is_null_oid(&ref->old_oid)) { if (starts_with(ref->name, "refs/tags/")) reject_reason = REF_STATUS_REJECT_ALREADY_EXISTS; else if (!has_object_file(&ref->old_oid)) diff --git a/setup.c b/setup.c index 2c4b22c845..0deb02238b 100644 --- a/setup.c +++ b/setup.c @@ -451,17 +451,6 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok) return ret; } -static void update_linked_gitdir(const char *gitfile, const char *gitdir) -{ - struct strbuf path = STRBUF_INIT; - struct stat st; - - strbuf_addf(&path, "%s/gitdir", gitdir); - if (stat(path.buf, &st) || st.st_mtime + 24 * 3600 < time(NULL)) - write_file(path.buf, "%s", gitfile); - strbuf_release(&path); -} - /* * Try to read the location of the git directory from the .git file, * return path to git directory if found. @@ -531,7 +520,6 @@ const char *read_gitfile_gently(const char *path, int *return_error_code) error_code = READ_GITFILE_ERR_NOT_A_REPO; goto cleanup_return; } - update_linked_gitdir(path, dir); path = real_path(dir); cleanup_return: diff --git a/t/t1501-work-tree.sh b/t/t1501-work-tree.sh new file mode 100755 index 0000000000..cc5b870e58 --- /dev/null +++ b/t/t1501-work-tree.sh @@ -0,0 +1,426 @@ +#!/bin/sh + +test_description='test separate work tree' +. ./test-lib.sh + +test_expect_success 'setup' ' + EMPTY_TREE=$(git write-tree) && + EMPTY_BLOB=$(git hash-object -t blob --stdin expected.bare && + echo $2 >expected.inside-git && + echo $3 >expected.inside-worktree && + if test $# -ge 4 + then + echo $4 >expected.prefix + fi && + + git rev-parse --is-bare-repository >actual.bare && + git rev-parse --is-inside-git-dir >actual.inside-git && + git rev-parse --is-inside-work-tree >actual.inside-worktree && + if test $# -ge 4 + then + git rev-parse --show-prefix >actual.prefix + fi && + + test_cmp expected.bare actual.bare && + test_cmp expected.inside-git actual.inside-git && + test_cmp expected.inside-worktree actual.inside-worktree && + if test $# -ge 4 + then + # rev-parse --show-prefix should output + # a single newline when at the top of the work tree, + # but we test for that separately. + test -z "$4" && ! test -s actual.prefix || + test_cmp expected.prefix actual.prefix + fi + } +' + +test_expect_success 'setup: core.worktree = relative path' ' + sane_unset GIT_WORK_TREE && + GIT_DIR=repo.git && + GIT_CONFIG="$(pwd)"/$GIT_DIR/config && + export GIT_DIR GIT_CONFIG && + git config core.worktree ../work +' + +test_expect_success 'outside' ' + test_rev_parse false false false +' + +test_expect_success 'inside work tree' ' + ( + cd work && + GIT_DIR=../repo.git && + GIT_CONFIG="$(pwd)"/$GIT_DIR/config && + test_rev_parse false false true "" + ) +' + +test_expect_success 'empty prefix is actually written out' ' + echo >expected && + ( + cd work && + GIT_DIR=../repo.git && + GIT_CONFIG="$(pwd)"/$GIT_DIR/config && + git rev-parse --show-prefix >../actual + ) && + test_cmp expected actual +' + +test_expect_success 'subdir of work tree' ' + ( + cd work/sub/dir && + GIT_DIR=../../../repo.git && + GIT_CONFIG="$(pwd)"/$GIT_DIR/config && + test_rev_parse false false true sub/dir/ + ) +' + +test_expect_success 'setup: core.worktree = absolute path' ' + sane_unset GIT_WORK_TREE && + GIT_DIR=$(pwd)/repo.git && + GIT_CONFIG=$GIT_DIR/config && + export GIT_DIR GIT_CONFIG && + git config core.worktree "$(pwd)/work" +' + +test_expect_success 'outside' ' + test_rev_parse false false false && + ( + cd work2 && + test_rev_parse false false false + ) +' + +test_expect_success 'inside work tree' ' + ( + cd work && + test_rev_parse false false true "" + ) +' + +test_expect_success 'subdir of work tree' ' + ( + cd work/sub/dir && + test_rev_parse false false true sub/dir/ + ) +' + +test_expect_success 'setup: GIT_WORK_TREE=relative (override core.worktree)' ' + GIT_DIR=$(pwd)/repo.git && + GIT_CONFIG=$GIT_DIR/config && + git config core.worktree non-existent && + GIT_WORK_TREE=work && + export GIT_DIR GIT_CONFIG GIT_WORK_TREE +' + +test_expect_success 'outside' ' + test_rev_parse false false false && + ( + cd work2 && + test_rev_parse false false false + ) +' + +test_expect_success 'inside work tree' ' + ( + cd work && + GIT_WORK_TREE=. && + test_rev_parse false false true "" + ) +' + +test_expect_success 'subdir of work tree' ' + ( + cd work/sub/dir && + GIT_WORK_TREE=../.. && + test_rev_parse false false true sub/dir/ + ) +' + +test_expect_success 'setup: GIT_WORK_TREE=absolute, below git dir' ' + mv work repo.git/work && + mv work2 repo.git/work2 && + GIT_DIR=$(pwd)/repo.git && + GIT_CONFIG=$GIT_DIR/config && + GIT_WORK_TREE=$(pwd)/repo.git/work && + export GIT_DIR GIT_CONFIG GIT_WORK_TREE +' + +test_expect_success 'outside' ' + echo outside && + test_rev_parse false false false +' + +test_expect_success 'in repo.git' ' + ( + cd repo.git && + test_rev_parse false true false + ) && + ( + cd repo.git/objects && + test_rev_parse false true false + ) && + ( + cd repo.git/work2 && + test_rev_parse false true false + ) +' + +test_expect_success 'inside work tree' ' + ( + cd repo.git/work && + test_rev_parse false true true "" + ) +' + +test_expect_success 'subdir of work tree' ' + ( + cd repo.git/work/sub/dir && + test_rev_parse false true true sub/dir/ + ) +' + +test_expect_success 'find work tree from repo' ' + echo sub/dir/untracked >expected && + cat <<-\EOF >repo.git/work/.gitignore && + expected.* + actual.* + .gitignore + EOF + >repo.git/work/sub/dir/untracked && + ( + cd repo.git && + git ls-files --others --exclude-standard >../actual + ) && + test_cmp expected actual +' + +test_expect_success 'find work tree from work tree' ' + echo sub/dir/tracked >expected && + >repo.git/work/sub/dir/tracked && + ( + cd repo.git/work/sub/dir && + git --git-dir=../../.. add tracked + ) && + ( + cd repo.git && + git ls-files >../actual + ) && + test_cmp expected actual +' + +test_expect_success '_gently() groks relative GIT_DIR & GIT_WORK_TREE' ' + ( + cd repo.git/work/sub/dir && + GIT_DIR=../../.. && + GIT_WORK_TREE=../.. && + GIT_PAGER= && + export GIT_DIR GIT_WORK_TREE GIT_PAGER && + + git diff --exit-code tracked && + echo changed >tracked && + test_must_fail git diff --exit-code tracked + ) +' + +test_expect_success 'diff-index respects work tree under .git dir' ' + cat >diff-index-cached.expected <<-EOF && + :000000 100644 $_z40 $EMPTY_BLOB A sub/dir/tracked + EOF + cat >diff-index.expected <<-EOF && + :000000 100644 $_z40 $_z40 A sub/dir/tracked + EOF + + ( + GIT_DIR=repo.git && + GIT_WORK_TREE=repo.git/work && + export GIT_DIR GIT_WORK_TREE && + git diff-index $EMPTY_TREE >diff-index.actual && + git diff-index --cached $EMPTY_TREE >diff-index-cached.actual + ) && + test_cmp diff-index.expected diff-index.actual && + test_cmp diff-index-cached.expected diff-index-cached.actual +' + +test_expect_success 'diff-files respects work tree under .git dir' ' + cat >diff-files.expected <<-EOF && + :100644 100644 $EMPTY_BLOB $_z40 M sub/dir/tracked + EOF + + ( + GIT_DIR=repo.git && + GIT_WORK_TREE=repo.git/work && + export GIT_DIR GIT_WORK_TREE && + git diff-files >diff-files.actual + ) && + test_cmp diff-files.expected diff-files.actual +' + +test_expect_success 'git diff respects work tree under .git dir' ' + cat >diff-TREE.expected <<-EOF && + diff --git a/sub/dir/tracked b/sub/dir/tracked + new file mode 100644 + index 0000000..$CHANGED_BLOB7 + --- /dev/null + +++ b/sub/dir/tracked + @@ -0,0 +1 @@ + +changed + EOF + cat >diff-TREE-cached.expected <<-EOF && + diff --git a/sub/dir/tracked b/sub/dir/tracked + new file mode 100644 + index 0000000..$EMPTY_BLOB7 + EOF + cat >diff-FILES.expected <<-EOF && + diff --git a/sub/dir/tracked b/sub/dir/tracked + index $EMPTY_BLOB7..$CHANGED_BLOB7 100644 + --- a/sub/dir/tracked + +++ b/sub/dir/tracked + @@ -0,0 +1 @@ + +changed + EOF + + ( + GIT_DIR=repo.git && + GIT_WORK_TREE=repo.git/work && + export GIT_DIR GIT_WORK_TREE && + git diff $EMPTY_TREE >diff-TREE.actual && + git diff --cached $EMPTY_TREE >diff-TREE-cached.actual && + git diff >diff-FILES.actual + ) && + test_cmp diff-TREE.expected diff-TREE.actual && + test_cmp diff-TREE-cached.expected diff-TREE-cached.actual && + test_cmp diff-FILES.expected diff-FILES.actual +' + +test_expect_success 'git grep' ' + echo dir/tracked >expected.grep && + ( + cd repo.git/work/sub && + GIT_DIR=../.. && + GIT_WORK_TREE=.. && + export GIT_DIR GIT_WORK_TREE && + git grep -l changed >../../../actual.grep + ) && + test_cmp expected.grep actual.grep +' + +test_expect_success 'git commit' ' + ( + cd repo.git && + GIT_DIR=. GIT_WORK_TREE=work git commit -a -m done + ) +' + +test_expect_success 'absolute pathspec should fail gracefully' ' + ( + cd repo.git && + test_might_fail git config --unset core.worktree && + test_must_fail git log HEAD -- /home + ) +' + +test_expect_success 'make_relative_path handles double slashes in GIT_DIR' ' + >dummy_file && + echo git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file && + git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file +' + +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 "$(pwd)/repo.git/work" >expected && + test_cmp expected actual +' + +test_expect_success 'Multi-worktree setup' ' + mkdir work && + mkdir -p repo.git/repos/foo && + cp repo.git/HEAD repo.git/index repo.git/repos/foo && + test_might_fail cp repo.git/sharedindex.* repo.git/repos/foo && + sane_unset GIT_DIR GIT_CONFIG GIT_WORK_TREE +' + +test_expect_success 'GIT_DIR set (1)' ' + echo "gitdir: repo.git/repos/foo" >gitfile && + echo ../.. >repo.git/repos/foo/commondir && + ( + cd work && + GIT_DIR=../gitfile git rev-parse --git-common-dir >actual && + test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect && + test_cmp expect actual + ) +' + +test_expect_success 'GIT_DIR set (2)' ' + echo "gitdir: repo.git/repos/foo" >gitfile && + echo "$(pwd)/repo.git" >repo.git/repos/foo/commondir && + ( + cd work && + GIT_DIR=../gitfile git rev-parse --git-common-dir >actual && + test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect && + test_cmp expect actual + ) +' + +test_expect_success 'Auto discovery' ' + echo "gitdir: repo.git/repos/foo" >.git && + echo ../.. >repo.git/repos/foo/commondir && + ( + cd work && + git rev-parse --git-common-dir >actual && + test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect && + test_cmp expect actual && + echo haha >data1 && + git add data1 && + git ls-files --full-name :/ | grep data1 >actual && + echo work/data1 >expect && + test_cmp expect actual + ) +' + +test_expect_success '$GIT_DIR/common overrides core.worktree' ' + mkdir elsewhere && + git --git-dir=repo.git config core.worktree "$TRASH_DIRECTORY/elsewhere" && + echo "gitdir: repo.git/repos/foo" >.git && + echo ../.. >repo.git/repos/foo/commondir && + ( + cd work && + git rev-parse --git-common-dir >actual && + test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect && + test_cmp expect actual && + echo haha >data2 && + git add data2 && + git ls-files --full-name :/ | grep data2 >actual && + echo work/data2 >expect && + test_cmp expect actual + ) +' + +test_expect_success '$GIT_WORK_TREE overrides $GIT_DIR/common' ' + echo "gitdir: repo.git/repos/foo" >.git && + echo ../.. >repo.git/repos/foo/commondir && + ( + cd work && + echo haha >data3 && + git --git-dir=../.git --work-tree=. add data3 && + git ls-files --full-name -- :/ | grep data3 >actual && + echo data3 >expect && + test_cmp expect actual + ) +' + +test_done diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh deleted file mode 100755 index cc5b870e58..0000000000 --- a/t/t1501-worktree.sh +++ /dev/null @@ -1,426 +0,0 @@ -#!/bin/sh - -test_description='test separate work tree' -. ./test-lib.sh - -test_expect_success 'setup' ' - EMPTY_TREE=$(git write-tree) && - EMPTY_BLOB=$(git hash-object -t blob --stdin expected.bare && - echo $2 >expected.inside-git && - echo $3 >expected.inside-worktree && - if test $# -ge 4 - then - echo $4 >expected.prefix - fi && - - git rev-parse --is-bare-repository >actual.bare && - git rev-parse --is-inside-git-dir >actual.inside-git && - git rev-parse --is-inside-work-tree >actual.inside-worktree && - if test $# -ge 4 - then - git rev-parse --show-prefix >actual.prefix - fi && - - test_cmp expected.bare actual.bare && - test_cmp expected.inside-git actual.inside-git && - test_cmp expected.inside-worktree actual.inside-worktree && - if test $# -ge 4 - then - # rev-parse --show-prefix should output - # a single newline when at the top of the work tree, - # but we test for that separately. - test -z "$4" && ! test -s actual.prefix || - test_cmp expected.prefix actual.prefix - fi - } -' - -test_expect_success 'setup: core.worktree = relative path' ' - sane_unset GIT_WORK_TREE && - GIT_DIR=repo.git && - GIT_CONFIG="$(pwd)"/$GIT_DIR/config && - export GIT_DIR GIT_CONFIG && - git config core.worktree ../work -' - -test_expect_success 'outside' ' - test_rev_parse false false false -' - -test_expect_success 'inside work tree' ' - ( - cd work && - GIT_DIR=../repo.git && - GIT_CONFIG="$(pwd)"/$GIT_DIR/config && - test_rev_parse false false true "" - ) -' - -test_expect_success 'empty prefix is actually written out' ' - echo >expected && - ( - cd work && - GIT_DIR=../repo.git && - GIT_CONFIG="$(pwd)"/$GIT_DIR/config && - git rev-parse --show-prefix >../actual - ) && - test_cmp expected actual -' - -test_expect_success 'subdir of work tree' ' - ( - cd work/sub/dir && - GIT_DIR=../../../repo.git && - GIT_CONFIG="$(pwd)"/$GIT_DIR/config && - test_rev_parse false false true sub/dir/ - ) -' - -test_expect_success 'setup: core.worktree = absolute path' ' - sane_unset GIT_WORK_TREE && - GIT_DIR=$(pwd)/repo.git && - GIT_CONFIG=$GIT_DIR/config && - export GIT_DIR GIT_CONFIG && - git config core.worktree "$(pwd)/work" -' - -test_expect_success 'outside' ' - test_rev_parse false false false && - ( - cd work2 && - test_rev_parse false false false - ) -' - -test_expect_success 'inside work tree' ' - ( - cd work && - test_rev_parse false false true "" - ) -' - -test_expect_success 'subdir of work tree' ' - ( - cd work/sub/dir && - test_rev_parse false false true sub/dir/ - ) -' - -test_expect_success 'setup: GIT_WORK_TREE=relative (override core.worktree)' ' - GIT_DIR=$(pwd)/repo.git && - GIT_CONFIG=$GIT_DIR/config && - git config core.worktree non-existent && - GIT_WORK_TREE=work && - export GIT_DIR GIT_CONFIG GIT_WORK_TREE -' - -test_expect_success 'outside' ' - test_rev_parse false false false && - ( - cd work2 && - test_rev_parse false false false - ) -' - -test_expect_success 'inside work tree' ' - ( - cd work && - GIT_WORK_TREE=. && - test_rev_parse false false true "" - ) -' - -test_expect_success 'subdir of work tree' ' - ( - cd work/sub/dir && - GIT_WORK_TREE=../.. && - test_rev_parse false false true sub/dir/ - ) -' - -test_expect_success 'setup: GIT_WORK_TREE=absolute, below git dir' ' - mv work repo.git/work && - mv work2 repo.git/work2 && - GIT_DIR=$(pwd)/repo.git && - GIT_CONFIG=$GIT_DIR/config && - GIT_WORK_TREE=$(pwd)/repo.git/work && - export GIT_DIR GIT_CONFIG GIT_WORK_TREE -' - -test_expect_success 'outside' ' - echo outside && - test_rev_parse false false false -' - -test_expect_success 'in repo.git' ' - ( - cd repo.git && - test_rev_parse false true false - ) && - ( - cd repo.git/objects && - test_rev_parse false true false - ) && - ( - cd repo.git/work2 && - test_rev_parse false true false - ) -' - -test_expect_success 'inside work tree' ' - ( - cd repo.git/work && - test_rev_parse false true true "" - ) -' - -test_expect_success 'subdir of work tree' ' - ( - cd repo.git/work/sub/dir && - test_rev_parse false true true sub/dir/ - ) -' - -test_expect_success 'find work tree from repo' ' - echo sub/dir/untracked >expected && - cat <<-\EOF >repo.git/work/.gitignore && - expected.* - actual.* - .gitignore - EOF - >repo.git/work/sub/dir/untracked && - ( - cd repo.git && - git ls-files --others --exclude-standard >../actual - ) && - test_cmp expected actual -' - -test_expect_success 'find work tree from work tree' ' - echo sub/dir/tracked >expected && - >repo.git/work/sub/dir/tracked && - ( - cd repo.git/work/sub/dir && - git --git-dir=../../.. add tracked - ) && - ( - cd repo.git && - git ls-files >../actual - ) && - test_cmp expected actual -' - -test_expect_success '_gently() groks relative GIT_DIR & GIT_WORK_TREE' ' - ( - cd repo.git/work/sub/dir && - GIT_DIR=../../.. && - GIT_WORK_TREE=../.. && - GIT_PAGER= && - export GIT_DIR GIT_WORK_TREE GIT_PAGER && - - git diff --exit-code tracked && - echo changed >tracked && - test_must_fail git diff --exit-code tracked - ) -' - -test_expect_success 'diff-index respects work tree under .git dir' ' - cat >diff-index-cached.expected <<-EOF && - :000000 100644 $_z40 $EMPTY_BLOB A sub/dir/tracked - EOF - cat >diff-index.expected <<-EOF && - :000000 100644 $_z40 $_z40 A sub/dir/tracked - EOF - - ( - GIT_DIR=repo.git && - GIT_WORK_TREE=repo.git/work && - export GIT_DIR GIT_WORK_TREE && - git diff-index $EMPTY_TREE >diff-index.actual && - git diff-index --cached $EMPTY_TREE >diff-index-cached.actual - ) && - test_cmp diff-index.expected diff-index.actual && - test_cmp diff-index-cached.expected diff-index-cached.actual -' - -test_expect_success 'diff-files respects work tree under .git dir' ' - cat >diff-files.expected <<-EOF && - :100644 100644 $EMPTY_BLOB $_z40 M sub/dir/tracked - EOF - - ( - GIT_DIR=repo.git && - GIT_WORK_TREE=repo.git/work && - export GIT_DIR GIT_WORK_TREE && - git diff-files >diff-files.actual - ) && - test_cmp diff-files.expected diff-files.actual -' - -test_expect_success 'git diff respects work tree under .git dir' ' - cat >diff-TREE.expected <<-EOF && - diff --git a/sub/dir/tracked b/sub/dir/tracked - new file mode 100644 - index 0000000..$CHANGED_BLOB7 - --- /dev/null - +++ b/sub/dir/tracked - @@ -0,0 +1 @@ - +changed - EOF - cat >diff-TREE-cached.expected <<-EOF && - diff --git a/sub/dir/tracked b/sub/dir/tracked - new file mode 100644 - index 0000000..$EMPTY_BLOB7 - EOF - cat >diff-FILES.expected <<-EOF && - diff --git a/sub/dir/tracked b/sub/dir/tracked - index $EMPTY_BLOB7..$CHANGED_BLOB7 100644 - --- a/sub/dir/tracked - +++ b/sub/dir/tracked - @@ -0,0 +1 @@ - +changed - EOF - - ( - GIT_DIR=repo.git && - GIT_WORK_TREE=repo.git/work && - export GIT_DIR GIT_WORK_TREE && - git diff $EMPTY_TREE >diff-TREE.actual && - git diff --cached $EMPTY_TREE >diff-TREE-cached.actual && - git diff >diff-FILES.actual - ) && - test_cmp diff-TREE.expected diff-TREE.actual && - test_cmp diff-TREE-cached.expected diff-TREE-cached.actual && - test_cmp diff-FILES.expected diff-FILES.actual -' - -test_expect_success 'git grep' ' - echo dir/tracked >expected.grep && - ( - cd repo.git/work/sub && - GIT_DIR=../.. && - GIT_WORK_TREE=.. && - export GIT_DIR GIT_WORK_TREE && - git grep -l changed >../../../actual.grep - ) && - test_cmp expected.grep actual.grep -' - -test_expect_success 'git commit' ' - ( - cd repo.git && - GIT_DIR=. GIT_WORK_TREE=work git commit -a -m done - ) -' - -test_expect_success 'absolute pathspec should fail gracefully' ' - ( - cd repo.git && - test_might_fail git config --unset core.worktree && - test_must_fail git log HEAD -- /home - ) -' - -test_expect_success 'make_relative_path handles double slashes in GIT_DIR' ' - >dummy_file && - echo git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file && - git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file -' - -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 "$(pwd)/repo.git/work" >expected && - test_cmp expected actual -' - -test_expect_success 'Multi-worktree setup' ' - mkdir work && - mkdir -p repo.git/repos/foo && - cp repo.git/HEAD repo.git/index repo.git/repos/foo && - test_might_fail cp repo.git/sharedindex.* repo.git/repos/foo && - sane_unset GIT_DIR GIT_CONFIG GIT_WORK_TREE -' - -test_expect_success 'GIT_DIR set (1)' ' - echo "gitdir: repo.git/repos/foo" >gitfile && - echo ../.. >repo.git/repos/foo/commondir && - ( - cd work && - GIT_DIR=../gitfile git rev-parse --git-common-dir >actual && - test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect && - test_cmp expect actual - ) -' - -test_expect_success 'GIT_DIR set (2)' ' - echo "gitdir: repo.git/repos/foo" >gitfile && - echo "$(pwd)/repo.git" >repo.git/repos/foo/commondir && - ( - cd work && - GIT_DIR=../gitfile git rev-parse --git-common-dir >actual && - test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect && - test_cmp expect actual - ) -' - -test_expect_success 'Auto discovery' ' - echo "gitdir: repo.git/repos/foo" >.git && - echo ../.. >repo.git/repos/foo/commondir && - ( - cd work && - git rev-parse --git-common-dir >actual && - test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect && - test_cmp expect actual && - echo haha >data1 && - git add data1 && - git ls-files --full-name :/ | grep data1 >actual && - echo work/data1 >expect && - test_cmp expect actual - ) -' - -test_expect_success '$GIT_DIR/common overrides core.worktree' ' - mkdir elsewhere && - git --git-dir=repo.git config core.worktree "$TRASH_DIRECTORY/elsewhere" && - echo "gitdir: repo.git/repos/foo" >.git && - echo ../.. >repo.git/repos/foo/commondir && - ( - cd work && - git rev-parse --git-common-dir >actual && - test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect && - test_cmp expect actual && - echo haha >data2 && - git add data2 && - git ls-files --full-name :/ | grep data2 >actual && - echo work/data2 >expect && - test_cmp expect actual - ) -' - -test_expect_success '$GIT_WORK_TREE overrides $GIT_DIR/common' ' - echo "gitdir: repo.git/repos/foo" >.git && - echo ../.. >repo.git/repos/foo/commondir && - ( - cd work && - echo haha >data3 && - git --git-dir=../.git --work-tree=. add data3 && - git ls-files --full-name -- :/ | grep data3 >actual && - echo data3 >expect && - test_cmp expect actual - ) -' - -test_done diff --git a/t/t1509-root-work-tree.sh b/t/t1509-root-work-tree.sh new file mode 100755 index 0000000000..553a3f601b --- /dev/null +++ b/t/t1509-root-work-tree.sh @@ -0,0 +1,258 @@ +#!/bin/sh + +test_description='Test Git when git repository is located at root + +This test requires write access in root. Do not bother if you do not +have a throwaway chroot or VM. + +Script t1509/prepare-chroot.sh may help you setup chroot, then you +can chroot in and execute this test from there. +' + +. ./test-lib.sh + +test_cmp_val() { + echo "$1" > expected + echo "$2" > result + test_cmp expected result +} + +test_vars() { + test_expect_success "$1: gitdir" ' + test_cmp_val "'"$2"'" "$(git rev-parse --git-dir)" + ' + + test_expect_success "$1: worktree" ' + test_cmp_val "'"$3"'" "$(git rev-parse --show-toplevel)" + ' + + test_expect_success "$1: prefix" ' + test_cmp_val "'"$4"'" "$(git rev-parse --show-prefix)" + ' +} + +test_foobar_root() { + test_expect_success 'add relative' ' + test -z "$(cd / && git ls-files)" && + git add foo/foome && + git add foo/bar/barme && + git add me && + ( cd / && git ls-files --stage ) > result && + test_cmp /ls.expected result && + rm "$(git rev-parse --git-dir)/index" + ' + + test_expect_success 'add absolute' ' + test -z "$(cd / && git ls-files)" && + git add /foo/foome && + git add /foo/bar/barme && + git add /me && + ( cd / && git ls-files --stage ) > result && + test_cmp /ls.expected result && + rm "$(git rev-parse --git-dir)/index" + ' + +} + +test_foobar_foo() { + test_expect_success 'add relative' ' + test -z "$(cd / && git ls-files)" && + git add foome && + git add bar/barme && + git add ../me && + ( cd / && git ls-files --stage ) > result && + test_cmp /ls.expected result && + rm "$(git rev-parse --git-dir)/index" + ' + + test_expect_success 'add absolute' ' + test -z "$(cd / && git ls-files)" && + git add /foo/foome && + git add /foo/bar/barme && + git add /me && + ( cd / && git ls-files --stage ) > result && + test_cmp /ls.expected result && + rm "$(git rev-parse --git-dir)/index" + ' +} + +test_foobar_foobar() { + test_expect_success 'add relative' ' + test -z "$(cd / && git ls-files)" && + git add ../foome && + git add barme && + git add ../../me && + ( cd / && git ls-files --stage ) > result && + test_cmp /ls.expected result && + rm "$(git rev-parse --git-dir)/index" + ' + + test_expect_success 'add absolute' ' + test -z "$(cd / && git ls-files)" && + git add /foo/foome && + git add /foo/bar/barme && + git add /me && + ( cd / && git ls-files --stage ) > result && + test_cmp /ls.expected result && + rm "$(git rev-parse --git-dir)/index" + ' +} + +if ! test -w / +then + skip_all="Test requiring writable / skipped. Read this test if you want to run it" + test_done +fi + +if test -e /refs || test -e /objects || test -e /info || test -e /hooks || + test -e /.git || test -e /foo || test -e /me +then + skip_all="Skip test that clobbers existing files in /" + test_done +fi + +if [ "$IKNOWWHATIAMDOING" != "YES" ]; then + skip_all="You must set env var IKNOWWHATIAMDOING=YES in order to run this test" + test_done +fi + +if ! test_have_prereq NOT_ROOT +then + skip_all="No you can't run this as root" + test_done +fi + +ONE_SHA1=d00491fd7e5bb6fa28c517a0bb32b8b506539d4d + +test_expect_success 'setup' ' + rm -rf /foo && + mkdir /foo && + mkdir /foo/bar && + echo 1 > /foo/foome && + echo 1 > /foo/bar/barme && + echo 1 > /me +' + +say "GIT_DIR absolute, GIT_WORK_TREE set" + +test_expect_success 'go to /' 'cd /' + +cat >ls.expected < expected && + git init > result && + test_cmp expected result +' + +test_vars 'auto gitdir, root' ".git" "/" "" +test_foobar_root + +test_expect_success 'go to /foo' 'cd /foo' +test_vars 'auto gitdir, foo' "/.git" "/" "foo/" +test_foobar_foo + +test_expect_success 'go to /foo/bar' 'cd /foo/bar' +test_vars 'auto gitdir, foo/bar' "/.git" "/" "foo/bar/" +test_foobar_foobar + +test_expect_success 'cleanup' 'rm -rf /.git' + +say "auto bare gitdir" + +# DESTROYYYYY!!!!! +test_expect_success 'setup' ' + rm -rf /refs /objects /info /hooks && + rm -f /expected /ls.expected /me /result && + cd / && + echo "Initialized empty Git repository in /" > expected && + git init --bare > result && + test_cmp expected result +' + +test_vars 'auto gitdir, root' "." "" "" + +test_expect_success 'go to /foo' 'cd /foo' + +test_vars 'auto gitdir, root' "/" "" "" + +test_done diff --git a/t/t1509-root-worktree.sh b/t/t1509-root-worktree.sh deleted file mode 100755 index 553a3f601b..0000000000 --- a/t/t1509-root-worktree.sh +++ /dev/null @@ -1,258 +0,0 @@ -#!/bin/sh - -test_description='Test Git when git repository is located at root - -This test requires write access in root. Do not bother if you do not -have a throwaway chroot or VM. - -Script t1509/prepare-chroot.sh may help you setup chroot, then you -can chroot in and execute this test from there. -' - -. ./test-lib.sh - -test_cmp_val() { - echo "$1" > expected - echo "$2" > result - test_cmp expected result -} - -test_vars() { - test_expect_success "$1: gitdir" ' - test_cmp_val "'"$2"'" "$(git rev-parse --git-dir)" - ' - - test_expect_success "$1: worktree" ' - test_cmp_val "'"$3"'" "$(git rev-parse --show-toplevel)" - ' - - test_expect_success "$1: prefix" ' - test_cmp_val "'"$4"'" "$(git rev-parse --show-prefix)" - ' -} - -test_foobar_root() { - test_expect_success 'add relative' ' - test -z "$(cd / && git ls-files)" && - git add foo/foome && - git add foo/bar/barme && - git add me && - ( cd / && git ls-files --stage ) > result && - test_cmp /ls.expected result && - rm "$(git rev-parse --git-dir)/index" - ' - - test_expect_success 'add absolute' ' - test -z "$(cd / && git ls-files)" && - git add /foo/foome && - git add /foo/bar/barme && - git add /me && - ( cd / && git ls-files --stage ) > result && - test_cmp /ls.expected result && - rm "$(git rev-parse --git-dir)/index" - ' - -} - -test_foobar_foo() { - test_expect_success 'add relative' ' - test -z "$(cd / && git ls-files)" && - git add foome && - git add bar/barme && - git add ../me && - ( cd / && git ls-files --stage ) > result && - test_cmp /ls.expected result && - rm "$(git rev-parse --git-dir)/index" - ' - - test_expect_success 'add absolute' ' - test -z "$(cd / && git ls-files)" && - git add /foo/foome && - git add /foo/bar/barme && - git add /me && - ( cd / && git ls-files --stage ) > result && - test_cmp /ls.expected result && - rm "$(git rev-parse --git-dir)/index" - ' -} - -test_foobar_foobar() { - test_expect_success 'add relative' ' - test -z "$(cd / && git ls-files)" && - git add ../foome && - git add barme && - git add ../../me && - ( cd / && git ls-files --stage ) > result && - test_cmp /ls.expected result && - rm "$(git rev-parse --git-dir)/index" - ' - - test_expect_success 'add absolute' ' - test -z "$(cd / && git ls-files)" && - git add /foo/foome && - git add /foo/bar/barme && - git add /me && - ( cd / && git ls-files --stage ) > result && - test_cmp /ls.expected result && - rm "$(git rev-parse --git-dir)/index" - ' -} - -if ! test -w / -then - skip_all="Test requiring writable / skipped. Read this test if you want to run it" - test_done -fi - -if test -e /refs || test -e /objects || test -e /info || test -e /hooks || - test -e /.git || test -e /foo || test -e /me -then - skip_all="Skip test that clobbers existing files in /" - test_done -fi - -if [ "$IKNOWWHATIAMDOING" != "YES" ]; then - skip_all="You must set env var IKNOWWHATIAMDOING=YES in order to run this test" - test_done -fi - -if ! test_have_prereq NOT_ROOT -then - skip_all="No you can't run this as root" - test_done -fi - -ONE_SHA1=d00491fd7e5bb6fa28c517a0bb32b8b506539d4d - -test_expect_success 'setup' ' - rm -rf /foo && - mkdir /foo && - mkdir /foo/bar && - echo 1 > /foo/foome && - echo 1 > /foo/bar/barme && - echo 1 > /me -' - -say "GIT_DIR absolute, GIT_WORK_TREE set" - -test_expect_success 'go to /' 'cd /' - -cat >ls.expected < expected && - git init > result && - test_cmp expected result -' - -test_vars 'auto gitdir, root' ".git" "/" "" -test_foobar_root - -test_expect_success 'go to /foo' 'cd /foo' -test_vars 'auto gitdir, foo' "/.git" "/" "foo/" -test_foobar_foo - -test_expect_success 'go to /foo/bar' 'cd /foo/bar' -test_vars 'auto gitdir, foo/bar' "/.git" "/" "foo/bar/" -test_foobar_foobar - -test_expect_success 'cleanup' 'rm -rf /.git' - -say "auto bare gitdir" - -# DESTROYYYYY!!!!! -test_expect_success 'setup' ' - rm -rf /refs /objects /info /hooks && - rm -f /expected /ls.expected /me /result && - cd / && - echo "Initialized empty Git repository in /" > expected && - git init --bare > result && - test_cmp expected result -' - -test_vars 'auto gitdir, root' "." "" "" - -test_expect_success 'go to /foo' 'cd /foo' - -test_vars 'auto gitdir, root' "/" "" "" - -test_done diff --git a/t/t5533-push-cas.sh b/t/t5533-push-cas.sh index c402d8d3d7..c7320121ec 100755 --- a/t/t5533-push-cas.sh +++ b/t/t5533-push-cas.sh @@ -25,7 +25,8 @@ test_expect_success 'push to update (protected)' ' ( cd dst && test_commit D && - test_must_fail git push --force-with-lease=master:master origin master + test_must_fail git push --force-with-lease=master:master origin master 2>err && + grep "stale info" err ) && git ls-remote . refs/heads/master >expect && git ls-remote src refs/heads/master >actual && @@ -37,7 +38,8 @@ test_expect_success 'push to update (protected, forced)' ' ( cd dst && test_commit D && - git push --force --force-with-lease=master:master origin master + git push --force --force-with-lease=master:master origin master 2>err && + grep "forced update" err ) && git ls-remote dst refs/heads/master >expect && git ls-remote src refs/heads/master >actual && @@ -101,7 +103,8 @@ test_expect_success 'push to update (allowed, tracking)' ' ( cd dst && test_commit D && - git push --force-with-lease=master origin master + git push --force-with-lease=master origin master 2>err && + ! grep "forced update" err ) && git ls-remote dst refs/heads/master >expect && git ls-remote src refs/heads/master >actual && @@ -114,7 +117,8 @@ test_expect_success 'push to update (allowed even though no-ff)' ' cd dst && git reset --hard HEAD^ && test_commit D && - git push --force-with-lease=master origin master + git push --force-with-lease=master origin master 2>err && + grep "forced update" err ) && git ls-remote dst refs/heads/master >expect && git ls-remote src refs/heads/master >actual && @@ -147,7 +151,8 @@ test_expect_success 'push to delete (allowed)' ' setup_srcdst_basic && ( cd dst && - git push --force-with-lease=master origin :master + git push --force-with-lease=master origin :master 2>err && + grep deleted err ) && >expect && git ls-remote src refs/heads/master >actual && diff --git a/t/t6023-merge-file.sh b/t/t6023-merge-file.sh index 190ee903cf..20aee43f95 100755 --- a/t/t6023-merge-file.sh +++ b/t/t6023-merge-file.sh @@ -346,4 +346,17 @@ test_expect_success 'conflict at EOF without LF resolved by --union' \ printf "line1\nline2\nline3x\nline3y" >expect.txt && test_cmp expect.txt output.txt' +test_expect_success 'conflict sections match existing line endings' ' + printf "1\\r\\n2\\r\\n3" >crlf-orig.txt && + printf "1\\r\\n2\\r\\n4" >crlf-diff1.txt && + printf "1\\r\\n2\\r\\n5" >crlf-diff2.txt && + test_must_fail git -c core.eol=crlf merge-file -p \ + crlf-diff1.txt crlf-orig.txt crlf-diff2.txt >crlf.txt && + test $(tr "\015" Q ].*Q$" | wc -l) = 3 && + test $(tr "\015" Q nolf.txt && + test $(tr "\015" Q ].*Q$" | wc -l) = 0 +' + test_done diff --git a/t/t7409-submodule-detached-work-tree.sh b/t/t7409-submodule-detached-work-tree.sh new file mode 100755 index 0000000000..c20717181e --- /dev/null +++ b/t/t7409-submodule-detached-work-tree.sh @@ -0,0 +1,84 @@ +#!/bin/sh +# +# Copyright (c) 2012 Daniel Graña +# + +test_description='Test submodules on detached working tree + +This test verifies that "git submodule" initialization, update and addition works +on detahced working trees +' + +TEST_NO_CREATE_REPO=1 +. ./test-lib.sh + +test_expect_success 'submodule on detached working tree' ' + git init --bare remote && + test_create_repo bundle1 && + ( + cd bundle1 && + test_commit "shoot" && + git rev-parse --verify HEAD >../expect + ) && + mkdir home && + ( + cd home && + GIT_WORK_TREE="$(pwd)" && + GIT_DIR="$(pwd)/.dotfiles" && + export GIT_WORK_TREE GIT_DIR && + git clone --bare ../remote .dotfiles && + git submodule add ../bundle1 .vim/bundle/sogood && + test_commit "sogood" && + ( + unset GIT_WORK_TREE GIT_DIR && + cd .vim/bundle/sogood && + git rev-parse --verify HEAD >actual && + test_cmp ../../../../expect actual + ) && + git push origin master + ) && + mkdir home2 && + ( + cd home2 && + git clone --bare ../remote .dotfiles && + GIT_WORK_TREE="$(pwd)" && + GIT_DIR="$(pwd)/.dotfiles" && + export GIT_WORK_TREE GIT_DIR && + git checkout master && + git submodule update --init && + ( + unset GIT_WORK_TREE GIT_DIR && + cd .vim/bundle/sogood && + git rev-parse --verify HEAD >actual && + test_cmp ../../../../expect actual + ) + ) +' + +test_expect_success 'submodule on detached working pointed by core.worktree' ' + mkdir home3 && + ( + cd home3 && + GIT_DIR="$(pwd)/.dotfiles" && + export GIT_DIR && + git clone --bare ../remote "$GIT_DIR" && + git config core.bare false && + git config core.worktree .. && + git checkout master && + git submodule add ../bundle1 .vim/bundle/dupe && + test_commit "dupe" && + git push origin master + ) && + ( + cd home && + GIT_DIR="$(pwd)/.dotfiles" && + export GIT_DIR && + git config core.bare false && + git config core.worktree .. && + git pull && + git submodule update --init && + test -f .vim/bundle/dupe/shoot.t + ) +' + +test_done diff --git a/t/t7409-submodule-detached-worktree.sh b/t/t7409-submodule-detached-worktree.sh deleted file mode 100755 index c20717181e..0000000000 --- a/t/t7409-submodule-detached-worktree.sh +++ /dev/null @@ -1,84 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2012 Daniel Graña -# - -test_description='Test submodules on detached working tree - -This test verifies that "git submodule" initialization, update and addition works -on detahced working trees -' - -TEST_NO_CREATE_REPO=1 -. ./test-lib.sh - -test_expect_success 'submodule on detached working tree' ' - git init --bare remote && - test_create_repo bundle1 && - ( - cd bundle1 && - test_commit "shoot" && - git rev-parse --verify HEAD >../expect - ) && - mkdir home && - ( - cd home && - GIT_WORK_TREE="$(pwd)" && - GIT_DIR="$(pwd)/.dotfiles" && - export GIT_WORK_TREE GIT_DIR && - git clone --bare ../remote .dotfiles && - git submodule add ../bundle1 .vim/bundle/sogood && - test_commit "sogood" && - ( - unset GIT_WORK_TREE GIT_DIR && - cd .vim/bundle/sogood && - git rev-parse --verify HEAD >actual && - test_cmp ../../../../expect actual - ) && - git push origin master - ) && - mkdir home2 && - ( - cd home2 && - git clone --bare ../remote .dotfiles && - GIT_WORK_TREE="$(pwd)" && - GIT_DIR="$(pwd)/.dotfiles" && - export GIT_WORK_TREE GIT_DIR && - git checkout master && - git submodule update --init && - ( - unset GIT_WORK_TREE GIT_DIR && - cd .vim/bundle/sogood && - git rev-parse --verify HEAD >actual && - test_cmp ../../../../expect actual - ) - ) -' - -test_expect_success 'submodule on detached working pointed by core.worktree' ' - mkdir home3 && - ( - cd home3 && - GIT_DIR="$(pwd)/.dotfiles" && - export GIT_DIR && - git clone --bare ../remote "$GIT_DIR" && - git config core.bare false && - git config core.worktree .. && - git checkout master && - git submodule add ../bundle1 .vim/bundle/dupe && - test_commit "dupe" && - git push origin master - ) && - ( - cd home && - GIT_DIR="$(pwd)/.dotfiles" && - export GIT_DIR && - git config core.bare false && - git config core.worktree .. && - git pull && - git submodule update --init && - test -f .vim/bundle/dupe/shoot.t - ) -' - -test_done diff --git a/t/test-lib.sh b/t/test-lib.sh index bd4b02e9db..51e4a88c33 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -907,9 +907,11 @@ yes () { y="$*" fi - while echo "$y" + i=0 + while test $i -lt 99 do - : + echo "$y" + i=$(($i+1)) done } diff --git a/worktree.c b/worktree.c index 981f810e80..6181a66f1e 100644 --- a/worktree.c +++ b/worktree.c @@ -176,10 +176,10 @@ struct worktree **get_worktrees(void) if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) continue; - if ((linked = get_linked_worktree(d->d_name))) { - ALLOC_GROW(list, counter + 1, alloc); - list[counter++] = linked; - } + if ((linked = get_linked_worktree(d->d_name))) { + ALLOC_GROW(list, counter + 1, alloc); + list[counter++] = linked; + } } closedir(dir); } diff --git a/xdiff/xmerge.c b/xdiff/xmerge.c index 625198e058..d98f430c91 100644 --- a/xdiff/xmerge.c +++ b/xdiff/xmerge.c @@ -109,7 +109,7 @@ static int xdl_merge_cmp_lines(xdfenv_t *xe1, int i1, xdfenv_t *xe2, int i2, return 0; } -static int xdl_recs_copy_0(int use_orig, xdfenv_t *xe, int i, int count, int add_nl, char *dest) +static int xdl_recs_copy_0(int use_orig, xdfenv_t *xe, int i, int count, int needs_cr, int add_nl, char *dest) { xrecord_t **recs; int size = 0; @@ -125,6 +125,12 @@ static int xdl_recs_copy_0(int use_orig, xdfenv_t *xe, int i, int count, int add if (add_nl) { i = recs[count - 1]->size; if (i == 0 || recs[count - 1]->ptr[i - 1] != '\n') { + if (needs_cr) { + if (dest) + dest[size] = '\r'; + size++; + } + if (dest) dest[size] = '\n'; size++; @@ -133,14 +139,58 @@ static int xdl_recs_copy_0(int use_orig, xdfenv_t *xe, int i, int count, int add return size; } -static int xdl_recs_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest) +static int xdl_recs_copy(xdfenv_t *xe, int i, int count, int needs_cr, int add_nl, char *dest) +{ + return xdl_recs_copy_0(0, xe, i, count, needs_cr, add_nl, dest); +} + +static int xdl_orig_copy(xdfenv_t *xe, int i, int count, int needs_cr, int add_nl, char *dest) +{ + return xdl_recs_copy_0(1, xe, i, count, needs_cr, add_nl, dest); +} + +/* + * Returns 1 if the i'th line ends in CR/LF (if it is the last line and + * has no eol, the preceding line, if any), 0 if it ends in LF-only, and + * -1 if the line ending cannot be determined. + */ +static int is_eol_crlf(xdfile_t *file, int i) { - return xdl_recs_copy_0(0, xe, i, count, add_nl, dest); + long size; + + if (i < file->nrec - 1) + /* All lines before the last *must* end in LF */ + return (size = file->recs[i]->size) > 1 && + file->recs[i]->ptr[size - 2] == '\r'; + if (!file->nrec) + /* Cannot determine eol style from empty file */ + return -1; + if ((size = file->recs[i]->size) && + file->recs[i]->ptr[size - 1] == '\n') + /* Last line; ends in LF; Is it CR/LF? */ + return size > 1 && + file->recs[i]->ptr[size - 2] == '\r'; + if (!i) + /* The only line has no eol */ + return -1; + /* Determine eol from second-to-last line */ + return (size = file->recs[i - 1]->size) > 1 && + file->recs[i - 1]->ptr[size - 2] == '\r'; } -static int xdl_orig_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest) +static int is_cr_needed(xdfenv_t *xe1, xdfenv_t *xe2, xdmerge_t *m) { - return xdl_recs_copy_0(1, xe, i, count, add_nl, dest); + int needs_cr; + + /* Match post-images' preceding, or first, lines' end-of-line style */ + needs_cr = is_eol_crlf(&xe1->xdf2, m->i1 ? m->i1 - 1 : 0); + if (needs_cr) + needs_cr = is_eol_crlf(&xe2->xdf2, m->i2 ? m->i2 - 1 : 0); + /* Look at pre-image's first line, unless we already settled on LF */ + if (needs_cr) + needs_cr = is_eol_crlf(&xe1->xdf1, 0); + /* If still undecided, use LF-only */ + return needs_cr < 0 ? 0 : needs_cr; } static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1, @@ -152,16 +202,17 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1, int marker1_size = (name1 ? strlen(name1) + 1 : 0); int marker2_size = (name2 ? strlen(name2) + 1 : 0); int marker3_size = (name3 ? strlen(name3) + 1 : 0); + int needs_cr = is_cr_needed(xe1, xe2, m); if (marker_size <= 0) marker_size = DEFAULT_CONFLICT_MARKER_SIZE; /* Before conflicting part */ - size += xdl_recs_copy(xe1, i, m->i1 - i, 0, + size += xdl_recs_copy(xe1, i, m->i1 - i, 0, 0, dest ? dest + size : NULL); if (!dest) { - size += marker_size + 1 + marker1_size; + size += marker_size + 1 + needs_cr + marker1_size; } else { memset(dest + size, '<', marker_size); size += marker_size; @@ -170,17 +221,19 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1, memcpy(dest + size + 1, name1, marker1_size - 1); size += marker1_size; } + if (needs_cr) + dest[size++] = '\r'; dest[size++] = '\n'; } /* Postimage from side #1 */ - size += xdl_recs_copy(xe1, m->i1, m->chg1, 1, + size += xdl_recs_copy(xe1, m->i1, m->chg1, needs_cr, 1, dest ? dest + size : NULL); if (style == XDL_MERGE_DIFF3) { /* Shared preimage */ if (!dest) { - size += marker_size + 1 + marker3_size; + size += marker_size + 1 + needs_cr + marker3_size; } else { memset(dest + size, '|', marker_size); size += marker_size; @@ -189,25 +242,29 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1, memcpy(dest + size + 1, name3, marker3_size - 1); size += marker3_size; } + if (needs_cr) + dest[size++] = '\r'; dest[size++] = '\n'; } - size += xdl_orig_copy(xe1, m->i0, m->chg0, 1, + size += xdl_orig_copy(xe1, m->i0, m->chg0, needs_cr, 1, dest ? dest + size : NULL); } if (!dest) { - size += marker_size + 1; + size += marker_size + 1 + needs_cr; } else { memset(dest + size, '=', marker_size); size += marker_size; + if (needs_cr) + dest[size++] = '\r'; dest[size++] = '\n'; } /* Postimage from side #2 */ - size += xdl_recs_copy(xe2, m->i2, m->chg2, 1, + size += xdl_recs_copy(xe2, m->i2, m->chg2, needs_cr, 1, dest ? dest + size : NULL); if (!dest) { - size += marker_size + 1 + marker2_size; + size += marker_size + 1 + needs_cr + marker2_size; } else { memset(dest + size, '>', marker_size); size += marker_size; @@ -216,6 +273,8 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1, memcpy(dest + size + 1, name2, marker2_size - 1); size += marker2_size; } + if (needs_cr) + dest[size++] = '\r'; dest[size++] = '\n'; } return size; @@ -241,21 +300,24 @@ static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1, marker_size); else if (m->mode & 3) { /* Before conflicting part */ - size += xdl_recs_copy(xe1, i, m->i1 - i, 0, + size += xdl_recs_copy(xe1, i, m->i1 - i, 0, 0, dest ? dest + size : NULL); /* Postimage from side #1 */ - if (m->mode & 1) - size += xdl_recs_copy(xe1, m->i1, m->chg1, (m->mode & 2), + if (m->mode & 1) { + int needs_cr = is_cr_needed(xe1, xe2, m); + + size += xdl_recs_copy(xe1, m->i1, m->chg1, needs_cr, (m->mode & 2), dest ? dest + size : NULL); + } /* Postimage from side #2 */ if (m->mode & 2) - size += xdl_recs_copy(xe2, m->i2, m->chg2, 0, + size += xdl_recs_copy(xe2, m->i2, m->chg2, 0, 0, dest ? dest + size : NULL); } else continue; i = m->i1 + m->chg1; } - size += xdl_recs_copy(xe1, i, xe1->xdf2.nrec - i, 0, + size += xdl_recs_copy(xe1, i, xe1->xdf2.nrec - i, 0, 0, dest ? dest + size : NULL); return size; }