diff options
author | Junio C Hamano <gitster@pobox.com> | 2010-08-31 16:23:19 -0700 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2010-08-31 16:23:19 -0700 |
commit | 693fefe3d022767975eec7585561bfe178b873f4 (patch) | |
tree | 052a0be20d04a5b79f1bc1f166003a33470e5991 | |
parent | Merge branch 'en/fast-export-fix' (diff) | |
parent | setup: split off a function to handle ordinary .git directories (diff) | |
download | tgif-693fefe3d022767975eec7585561bfe178b873f4.tar.xz |
Merge branch 'jn/maint-setup-fix'
* jn/maint-setup-fix:
setup: split off a function to handle ordinary .git directories
Revert "rehabilitate 'git index-pack' inside the object store"
setup: do not forget working dir from subdir of gitdir
t4111 (apply): refresh index before applying patches to it
setup: split off get_device_or_die helper
setup: split off a function to handle hitting ceiling in repo search
setup: split off code to handle stumbling upon a repository
setup: split off a function to checks working dir for .git file
setup: split off $GIT_DIR-set case from setup_git_directory_gently
tests: try git apply from subdir of toplevel
t1501 (rev-parse): clarify
Conflicts:
builtin/index-pack.c
-rw-r--r-- | builtin/index-pack.c | 24 | ||||
-rw-r--r-- | setup.c | 214 | ||||
-rwxr-xr-x | t/t1501-worktree.sh | 483 | ||||
-rwxr-xr-x | t/t4111-apply-subdir.sh | 142 |
4 files changed, 581 insertions, 282 deletions
diff --git a/builtin/index-pack.c b/builtin/index-pack.c index fad76bf7a8..96333d48cd 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -880,31 +880,17 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix) char *index_name_buf = NULL, *keep_name_buf = NULL; struct pack_idx_entry **idx_objects; unsigned char pack_sha1[20]; + int nongit; if (argc == 2 && !strcmp(argv[1], "-h")) usage(index_pack_usage); read_replace_refs = 0; - /* - * We wish to read the repository's config file if any, and - * for that it is necessary to call setup_git_directory_gently(). - * However if the cwd was inside .git/objects/pack/ then we need - * to go back there or all the pack name arguments will be wrong. - * And in that case we cannot rely on any prefix returned by - * setup_git_directory_gently() either. - */ - { - char cwd[PATH_MAX+1]; - int nongit; - - if (!getcwd(cwd, sizeof(cwd)-1)) - die("Unable to get current working directory"); - setup_git_directory_gently(&nongit); - git_config(git_index_pack_config, NULL); - if (chdir(cwd)) - die("Cannot come back to cwd"); - } + prefix = setup_git_directory_gently(&nongit); + git_config(git_index_pack_config, NULL); + if (prefix && chdir(prefix)) + die("Cannot come back to cwd"); for (i = 1; i < argc; i++) { const char *arg = argv[i]; @@ -313,6 +313,115 @@ const char *read_gitfile_gently(const char *path) return path; } +static const char *setup_explicit_git_dir(const char *gitdirenv, + const char *work_tree_env, int *nongit_ok) +{ + static char buffer[1024 + 1]; + const char *retval; + + if (PATH_MAX - 40 < strlen(gitdirenv)) + die("'$%s' too big", GIT_DIR_ENVIRONMENT); + if (!is_git_directory(gitdirenv)) { + if (nongit_ok) { + *nongit_ok = 1; + return NULL; + } + die("Not a git repository: '%s'", gitdirenv); + } + if (!work_tree_env) { + retval = set_work_tree(gitdirenv); + /* config may override worktree */ + if (check_repository_format_gently(nongit_ok)) + return NULL; + return retval; + } + if (check_repository_format_gently(nongit_ok)) + return NULL; + retval = get_relative_cwd(buffer, sizeof(buffer) - 1, + get_git_work_tree()); + if (!retval || !*retval) + return NULL; + set_git_dir(make_absolute_path(gitdirenv)); + if (chdir(work_tree_env) < 0) + die_errno ("Could not chdir to '%s'", work_tree_env); + strcat(buffer, "/"); + return retval; +} + +static int cwd_contains_git_dir(const char **gitfile_dirp) +{ + const char *gitfile_dir = read_gitfile_gently(DEFAULT_GIT_DIR_ENVIRONMENT); + *gitfile_dirp = gitfile_dir; + if (gitfile_dir) { + if (set_git_dir(gitfile_dir)) + die("Repository setup failed"); + return 1; + } + return is_git_directory(DEFAULT_GIT_DIR_ENVIRONMENT); +} + +static const char *setup_discovered_git_dir(const char *work_tree_env, + int offset, int len, char *cwd, int *nongit_ok) +{ + int root_len; + + inside_git_dir = 0; + if (!work_tree_env) + inside_work_tree = 1; + root_len = offset_1st_component(cwd); + git_work_tree_cfg = xstrndup(cwd, offset > root_len ? offset : root_len); + if (check_repository_format_gently(nongit_ok)) + return NULL; + if (offset == len) + return NULL; + + /* Make "offset" point to past the '/', and add a '/' at the end */ + offset++; + cwd[len++] = '/'; + cwd[len] = 0; + return cwd + offset; +} + +static const char *setup_bare_git_dir(const char *work_tree_env, + int offset, int len, char *cwd, int *nongit_ok) +{ + int root_len; + + inside_git_dir = 1; + if (!work_tree_env) + inside_work_tree = 0; + if (offset != len) { + if (chdir(cwd)) + die_errno("Cannot come back to cwd"); + root_len = offset_1st_component(cwd); + cwd[offset > root_len ? offset : root_len] = '\0'; + set_git_dir(cwd); + } else + set_git_dir("."); + check_repository_format_gently(nongit_ok); + return NULL; +} + +static const char *setup_nongit(const char *cwd, int *nongit_ok) +{ + if (!nongit_ok) + die("Not a git repository (or any of the parent directories): %s", DEFAULT_GIT_DIR_ENVIRONMENT); + if (chdir(cwd)) + die_errno("Cannot come back to cwd"); + *nongit_ok = 1; + return NULL; +} + +static dev_t get_device_or_die(const char *path, const char *prefix) +{ + struct stat buf; + if (stat(path, &buf)) + die_errno("failed to stat '%s%s%s'", + prefix ? prefix : "", + prefix ? "/" : "", path); + return buf.st_dev; +} + /* * We cannot decide in this function whether we are in the work tree or * not, since the config can only be read _after_ this function was called. @@ -324,10 +433,9 @@ const char *setup_git_directory_gently(int *nongit_ok) static char cwd[PATH_MAX+1]; const char *gitdirenv; const char *gitfile_dir; - int len, offset, ceil_offset, root_len; + int len, offset, ceil_offset; dev_t current_device = 0; int one_filesystem = 1; - struct stat buf; /* * Let's assume that we are in a git repository. @@ -343,38 +451,8 @@ const char *setup_git_directory_gently(int *nongit_ok) * validation. */ gitdirenv = getenv(GIT_DIR_ENVIRONMENT); - if (gitdirenv) { - if (PATH_MAX - 40 < strlen(gitdirenv)) - die("'$%s' too big", GIT_DIR_ENVIRONMENT); - if (is_git_directory(gitdirenv)) { - static char buffer[1024 + 1]; - const char *retval; - - if (!work_tree_env) { - retval = set_work_tree(gitdirenv); - /* config may override worktree */ - if (check_repository_format_gently(nongit_ok)) - return NULL; - return retval; - } - if (check_repository_format_gently(nongit_ok)) - return NULL; - retval = get_relative_cwd(buffer, sizeof(buffer) - 1, - get_git_work_tree()); - if (!retval || !*retval) - return NULL; - set_git_dir(make_absolute_path(gitdirenv)); - if (chdir(work_tree_env) < 0) - die_errno ("Could not chdir to '%s'", work_tree_env); - strcat(buffer, "/"); - return retval; - } - if (nongit_ok) { - *nongit_ok = 1; - return NULL; - } - die("Not a git repository: '%s'", gitdirenv); - } + if (gitdirenv) + return setup_explicit_git_dir(gitdirenv, work_tree_env, nongit_ok); if (!getcwd(cwd, sizeof(cwd)-1)) die_errno("Unable to read current working directory"); @@ -396,49 +474,21 @@ const char *setup_git_directory_gently(int *nongit_ok) */ offset = len = strlen(cwd); one_filesystem = !git_env_bool("GIT_DISCOVERY_ACROSS_FILESYSTEM", 0); - if (one_filesystem) { - if (stat(".", &buf)) - die_errno("failed to stat '.'"); - current_device = buf.st_dev; - } + if (one_filesystem) + current_device = get_device_or_die(".", NULL); for (;;) { - gitfile_dir = read_gitfile_gently(DEFAULT_GIT_DIR_ENVIRONMENT); - if (gitfile_dir) { - if (set_git_dir(gitfile_dir)) - die("Repository setup failed"); - break; - } - if (is_git_directory(DEFAULT_GIT_DIR_ENVIRONMENT)) - break; - if (is_git_directory(".")) { - inside_git_dir = 1; - if (!work_tree_env) - inside_work_tree = 0; - if (offset != len) { - root_len = offset_1st_component(cwd); - cwd[offset > root_len ? offset : root_len] = '\0'; - set_git_dir(cwd); - } else - set_git_dir("."); - check_repository_format_gently(nongit_ok); - return NULL; - } + if (cwd_contains_git_dir(&gitfile_dir)) + return setup_discovered_git_dir(work_tree_env, offset, + len, cwd, nongit_ok); + if (is_git_directory(".")) + return setup_bare_git_dir(work_tree_env, offset, + len, cwd, nongit_ok); while (--offset > ceil_offset && cwd[offset] != '/'); - if (offset <= ceil_offset) { - if (nongit_ok) { - if (chdir(cwd)) - die_errno("Cannot come back to cwd"); - *nongit_ok = 1; - return NULL; - } - die("Not a git repository (or any of the parent directories): %s", DEFAULT_GIT_DIR_ENVIRONMENT); - } + if (offset <= ceil_offset) + return setup_nongit(cwd, nongit_ok); if (one_filesystem) { - if (stat("..", &buf)) { - cwd[offset] = '\0'; - die_errno("failed to stat '%s/..'", cwd); - } - if (buf.st_dev != current_device) { + dev_t parent_device = get_device_or_die("..", cwd); + if (parent_device != current_device) { if (nongit_ok) { if (chdir(cwd)) die_errno("Cannot come back to cwd"); @@ -455,22 +505,6 @@ const char *setup_git_directory_gently(int *nongit_ok) die_errno("Cannot change to '%s/..'", cwd); } } - - inside_git_dir = 0; - if (!work_tree_env) - inside_work_tree = 1; - root_len = offset_1st_component(cwd); - git_work_tree_cfg = xstrndup(cwd, offset > root_len ? offset : root_len); - if (check_repository_format_gently(nongit_ok)) - return NULL; - if (offset == len) - return NULL; - - /* Make "offset" point to past the '/', and add a '/' at the end */ - offset++; - cwd[len++] = '/'; - cwd[len] = 0; - return cwd + offset; } int git_config_perm(const char *var, const char *value) diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh index bd8b60732b..2c8f01f668 100755 --- a/t/t1501-worktree.sh +++ b/t/t1501-worktree.sh @@ -3,183 +3,320 @@ test_description='test separate work tree' . ./test-lib.sh -test_rev_parse() { - name=$1 - shift - - test_expect_success "$name: is-bare-repository" \ - "test '$1' = \"\$(git rev-parse --is-bare-repository)\"" - shift - [ $# -eq 0 ] && return - - test_expect_success "$name: is-inside-git-dir" \ - "test '$1' = \"\$(git rev-parse --is-inside-git-dir)\"" - shift - [ $# -eq 0 ] && return - - test_expect_success "$name: is-inside-work-tree" \ - "test '$1' = \"\$(git rev-parse --is-inside-work-tree)\"" - shift - [ $# -eq 0 ] && return - - test_expect_success "$name: prefix" \ - "test '$1' = \"\$(git rev-parse --show-prefix)\"" - shift - [ $# -eq 0 ] && return -} - -EMPTY_TREE=$(git write-tree) -mkdir -p work/sub/dir || exit 1 -mkdir -p work2 || exit 1 -mv .git repo.git || exit 1 - -say "core.worktree = relative path" -GIT_DIR=repo.git -GIT_CONFIG="$(pwd)"/$GIT_DIR/config -export GIT_DIR GIT_CONFIG -unset GIT_WORK_TREE -git config core.worktree ../work -test_rev_parse 'outside' false false false -cd work || exit 1 -GIT_DIR=../repo.git -GIT_CONFIG="$(pwd)"/$GIT_DIR/config -test_rev_parse 'inside' false false true '' -cd sub/dir || exit 1 -GIT_DIR=../../../repo.git -GIT_CONFIG="$(pwd)"/$GIT_DIR/config -test_rev_parse 'subdirectory' false false true sub/dir/ -cd ../../.. || exit 1 - -say "core.worktree = absolute path" -GIT_DIR=$(pwd)/repo.git -GIT_CONFIG=$GIT_DIR/config -git config core.worktree "$(pwd)/work" -test_rev_parse 'outside' false false false -cd work2 -test_rev_parse 'outside2' false false false -cd ../work || exit 1 -test_rev_parse 'inside' false false true '' -cd sub/dir || exit 1 -test_rev_parse 'subdirectory' false false true sub/dir/ -cd ../../.. || exit 1 - -say "GIT_WORK_TREE=relative path (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_WORK_TREE -test_rev_parse 'outside' false false false -cd work2 -test_rev_parse 'outside' false false false -cd ../work || exit 1 -GIT_WORK_TREE=. -test_rev_parse 'inside' false false true '' -cd sub/dir || exit 1 -GIT_WORK_TREE=../.. -test_rev_parse 'subdirectory' false false true sub/dir/ -cd ../../.. || exit 1 - -mv work repo.git/work -mv work2 repo.git/work2 - -say "GIT_WORK_TREE=absolute path, work tree below git dir" -GIT_DIR=$(pwd)/repo.git -GIT_CONFIG=$GIT_DIR/config -GIT_WORK_TREE=$(pwd)/repo.git/work -test_rev_parse 'outside' false false false -cd repo.git || exit 1 -test_rev_parse 'in repo.git' false true false -cd objects || exit 1 -test_rev_parse 'in repo.git/objects' false true false -cd ../work2 || exit 1 -test_rev_parse 'in repo.git/work2' false true false -cd ../work || exit 1 -test_rev_parse 'in repo.git/work' false true true '' -cd sub/dir || exit 1 -test_rev_parse 'in repo.git/sub/dir' false true true sub/dir/ -cd ../../../.. || exit 1 - -test_expect_success 'repo finds its work tree' ' - (cd repo.git && - : > work/sub/dir/untracked && - test sub/dir/untracked = "$(git ls-files --others)") -' - -test_expect_success 'repo finds its work tree from work tree, too' ' - (cd repo.git/work/sub/dir && - : > tracked && - git --git-dir=../../.. add tracked && - cd ../../.. && - test sub/dir/tracked = "$(git ls-files)") +test_expect_success 'setup' ' + EMPTY_TREE=$(git write-tree) && + EMPTY_BLOB=$(git hash-object -t blob --stdin </dev/null) && + CHANGED_BLOB=$(echo changed | git hash-object -t blob --stdin) && + ZEROES=0000000000000000000000000000000000000000 && + EMPTY_BLOB7=$(echo $EMPTY_BLOB | sed "s/\(.......\).*/\1/") && + CHANGED_BLOB7=$(echo $CHANGED_BLOB | sed "s/\(.......\).*/\1/") && + + mkdir -p work/sub/dir && + mkdir -p work2 && + mv .git repo.git +' + +test_expect_success 'setup: helper for testing rev-parse' ' + test_rev_parse() { + echo $1 >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' ' + 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_failure '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' ' + 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= \ + ( + 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 && - ! GIT_DIR=../../.. GIT_WORK_TREE=../.. GIT_PAGER= \ - git diff --exit-code tracked) -' -cat > diff-index-cached.expected <<\EOF -:000000 100644 0000000000000000000000000000000000000000 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 A sub/dir/tracked -EOF -cat > diff-index.expected <<\EOF -:000000 100644 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 A sub/dir/tracked -EOF - - -test_expect_success 'git diff-index' ' - GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work git diff-index $EMPTY_TREE > result && - test_cmp diff-index.expected result && - GIT_DIR=repo.git git diff-index --cached $EMPTY_TREE > result && - test_cmp diff-index-cached.expected result -' -cat >diff-files.expected <<\EOF -:100644 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0000000000000000000000000000000000000000 M sub/dir/tracked -EOF - -test_expect_success 'git diff-files' ' - GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work git diff-files > result && - test_cmp diff-files.expected result -' - -cat >diff-TREE.expected <<\EOF -diff --git a/sub/dir/tracked b/sub/dir/tracked -new file mode 100644 -index 0000000..5ea2ed4 ---- /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..e69de29 -EOF -cat >diff-FILES.expected <<\EOF -diff --git a/sub/dir/tracked b/sub/dir/tracked -index e69de29..5ea2ed4 100644 ---- a/sub/dir/tracked -+++ b/sub/dir/tracked -@@ -0,0 +1 @@ -+changed -EOF - -test_expect_success 'git diff' ' - GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work git diff $EMPTY_TREE > result && - test_cmp diff-TREE.expected result && - GIT_DIR=repo.git git diff --cached $EMPTY_TREE > result && - test_cmp diff-TREE-cached.expected result && - GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work git diff > result && - test_cmp diff-FILES.expected result + 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 $ZEROES $EMPTY_BLOB A sub/dir/tracked + EOF + cat >diff-index.expected <<-EOF && + :000000 100644 $ZEROES $ZEROES 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 $ZEROES 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' ' - (cd repo.git/work/sub && - GIT_DIR=../.. GIT_WORK_TREE=.. git grep -l changed | grep dir/tracked) + 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' ' @@ -191,14 +328,14 @@ test_expect_success 'git commit' ' test_expect_success 'absolute pathspec should fail gracefully' ' ( - cd repo.git || exit 1 - git config --unset core.worktree + 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 + >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 ' diff --git a/t/t4111-apply-subdir.sh b/t/t4111-apply-subdir.sh new file mode 100755 index 0000000000..a52d94ae21 --- /dev/null +++ b/t/t4111-apply-subdir.sh @@ -0,0 +1,142 @@ +#!/bin/sh + +test_description='patching from inconvenient places' + +. ./test-lib.sh + +test_expect_success 'setup' ' + cat >patch <<-\EOF && + diff file.orig file + --- a/file.orig + +++ b/file + @@ -1 +1,2 @@ + 1 + +2 + EOF + patch="$(pwd)/patch" && + + echo 1 >preimage && + printf "%s\n" 1 2 >postimage && + echo 3 >other && + + test_tick && + git commit --allow-empty -m basis +' + +test_expect_success 'setup: subdir' ' + reset_subdir() { + git reset && + mkdir -p sub/dir/b && + mkdir -p objects && + cp "$1" file && + cp "$1" objects/file && + cp "$1" sub/dir/file && + cp "$1" sub/dir/b/file && + git add file sub/dir/file sub/dir/b/file objects/file && + cp "$2" file && + cp "$2" sub/dir/file && + cp "$2" sub/dir/b/file && + cp "$2" objects/file && + test_might_fail git update-index --refresh -q + } +' + +test_expect_success 'apply from subdir of toplevel' ' + cp postimage expected && + reset_subdir other preimage && + ( + cd sub/dir && + git apply "$patch" + ) && + test_cmp expected sub/dir/file +' + +test_expect_success 'apply --cached from subdir of toplevel' ' + cp postimage expected && + cp other expected.working && + reset_subdir preimage other && + ( + cd sub/dir && + git apply --cached "$patch" + ) && + git show :sub/dir/file >actual && + test_cmp expected actual && + test_cmp expected.working sub/dir/file +' + +test_expect_success 'apply --index from subdir of toplevel' ' + cp postimage expected && + reset_subdir preimage other && + ( + cd sub/dir && + test_must_fail git apply --index "$patch" + ) && + reset_subdir other preimage && + ( + cd sub/dir && + test_must_fail git apply --index "$patch" + ) && + reset_subdir preimage preimage && + ( + cd sub/dir && + git apply --index "$patch" + ) && + git show :sub/dir/file >actual && + test_cmp expected actual && + test_cmp expected sub/dir/file +' + +test_expect_success 'apply from .git dir' ' + cp postimage expected && + cp preimage .git/file && + cp preimage .git/objects/file + ( + cd .git && + git apply "$patch" + ) && + test_cmp expected .git/file +' + +test_expect_success 'apply from subdir of .git dir' ' + cp postimage expected && + cp preimage .git/file && + cp preimage .git/objects/file + ( + cd .git/objects && + git apply "$patch" + ) && + test_cmp expected .git/objects/file +' + +test_expect_success 'apply --cached from .git dir' ' + cp postimage expected && + cp other expected.working && + cp other .git/file && + reset_subdir preimage other && + ( + cd .git && + git apply --cached "$patch" + ) && + git show :file >actual && + test_cmp expected actual && + test_cmp expected.working file && + test_cmp expected.working .git/file +' + +test_expect_success 'apply --cached from subdir of .git dir' ' + cp postimage expected && + cp preimage expected.subdir && + cp other .git/file && + cp other .git/objects/file && + reset_subdir preimage other && + ( + cd .git/objects && + git apply --cached "$patch" + ) && + git show :file >actual && + git show :objects/file >actual.subdir && + test_cmp expected actual && + test_cmp expected.subdir actual.subdir +' + +test_done |