From fc688759b95e6888bb1dc4c4d00d27dca4e59ddb Mon Sep 17 00:00:00 2001 From: Jonathan Nieder Date: Sat, 24 Jul 2010 06:16:35 -0500 Subject: t1501 (rev-parse): clarify MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tweak the style of these tests to make them easier to read. - Replace test_rev_parse() which produced multiple mini-tests with a simple function that can be used with the test body. - Combine multiple mini-tests into larger chunks that are easier to read. - Do not hard-code object IDs. We may use a different hash some day. - Use test_cmp in preference to the test builtin. The former produces useful output when tests are run with the "-v" option. - Guard all test code with test_expect_success. This makes it much easier to visually scan through the test and find code of interest. - Use subshells to make the current directory easier to track. Outside of any subshell, the current directory is always $TEST_DIRECTORY now. Also add a new test demonstrating a possible bug noticed in the process of cleaning up: “git rev-parse --show-prefix” leaves out the trailing newline after an empty prefix when cwd is at the toplevel of the work tree. Signed-off-by: Jonathan Nieder Signed-off-by: Junio C Hamano --- t/t1501-worktree.sh | 483 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 310 insertions(+), 173 deletions(-) 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 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 ' -- cgit v1.2.3 From 9f41a91a7d100055fbd527f35b8cddae0bd91cac Mon Sep 17 00:00:00 2001 From: Jonathan Nieder Date: Sat, 24 Jul 2010 06:18:38 -0500 Subject: tests: try git apply from subdir of toplevel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make sure git apply can apply patches with paths relative to the toplevel of a work tree, a subdirectory, or within the repository metadata directory. Relative paths are broken for most commands when run from a subdirectory of $GIT_DIR, "git apply" being no exception. The other tests are meant to keep the demonstration of that company. Based on a test by Duy. Cc: Nguyễn Thái Ngọc Duy Signed-off-by: Jonathan Nieder Signed-off-by: Junio C Hamano --- t/t4111-apply-subdir.sh | 141 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100755 t/t4111-apply-subdir.sh diff --git a/t/t4111-apply-subdir.sh b/t/t4111-apply-subdir.sh new file mode 100755 index 0000000000..60c223750f --- /dev/null +++ b/t/t4111-apply-subdir.sh @@ -0,0 +1,141 @@ +#!/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_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_failure '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 -- cgit v1.2.3 From e4e303479b62e474c52ee1f9edd265d7333117d9 Mon Sep 17 00:00:00 2001 From: Jonathan Nieder Date: Sat, 24 Jul 2010 06:19:44 -0500 Subject: setup: split off $GIT_DIR-set case from setup_git_directory_gently If $GIT_DIR is set, setup_git_directory_gently does not have to do any repository discovery at all. Split off a function for the validation it still does do, in the hope that this will make setup_git_directory_gently proper less daunting to read. Signed-off-by: Jonathan Nieder Signed-off-by: Junio C Hamano --- setup.c | 69 +++++++++++++++++++++++++++++++++++------------------------------ 1 file changed, 37 insertions(+), 32 deletions(-) diff --git a/setup.c b/setup.c index 2769160527..16bee6d485 100644 --- a/setup.c +++ b/setup.c @@ -313,6 +313,41 @@ 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; +} + /* * 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. @@ -343,38 +378,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"); -- cgit v1.2.3 From 93a00542eaeb40c31b4de2497f5413a2fc0f36f4 Mon Sep 17 00:00:00 2001 From: Jonathan Nieder Date: Sat, 24 Jul 2010 06:20:15 -0500 Subject: setup: split off a function to checks working dir for .git file The repository discovery procedure looks something like this: while (same filesystem) { check .git in working dir check . chdir(..) } Add a function for the first step to make the actual code look a bit closer to that pseudocode. Signed-off-by: Jonathan Nieder Signed-off-by: Junio C Hamano --- setup.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/setup.c b/setup.c index 16bee6d485..3d25d0f205 100644 --- a/setup.c +++ b/setup.c @@ -348,6 +348,18 @@ static const char *setup_explicit_git_dir(const char *gitdirenv, 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); +} + /* * 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. @@ -407,13 +419,7 @@ const char *setup_git_directory_gently(int *nongit_ok) current_device = buf.st_dev; } 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)) + if (cwd_contains_git_dir(&gitfile_dir)) break; if (is_git_directory(".")) { inside_git_dir = 1; -- cgit v1.2.3 From 68698da540acb0c891b810396d704fef3643c576 Mon Sep 17 00:00:00 2001 From: Jonathan Nieder Date: Sat, 24 Jul 2010 06:25:32 -0500 Subject: setup: split off code to handle stumbling upon a repository If a repository is found as an ancestor of the original working directory, it is assumed by default to be bare. Handle this case with its own function. Signed-off-by: Jonathan Nieder Signed-off-by: Junio C Hamano --- setup.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/setup.c b/setup.c index 3d25d0f205..ec11c46266 100644 --- a/setup.c +++ b/setup.c @@ -360,6 +360,24 @@ static int cwd_contains_git_dir(const char **gitfile_dirp) return is_git_directory(DEFAULT_GIT_DIR_ENVIRONMENT); } +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) { + 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; +} + /* * 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. @@ -421,19 +439,9 @@ const char *setup_git_directory_gently(int *nongit_ok) for (;;) { if (cwd_contains_git_dir(&gitfile_dir)) 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 (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) { -- cgit v1.2.3 From f161edebb64f08bfc615fd9c28ebae3333255e2e Mon Sep 17 00:00:00 2001 From: Jonathan Nieder Date: Sat, 24 Jul 2010 06:26:41 -0500 Subject: setup: split off a function to handle hitting ceiling in repo search Perhaps some day, other similar conditions (hitting the mount point, hitting the root of the file system) will share this code. Signed-off-by: Jonathan Nieder Signed-off-by: Junio C Hamano --- setup.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/setup.c b/setup.c index ec11c46266..9fc05e2c0a 100644 --- a/setup.c +++ b/setup.c @@ -378,6 +378,16 @@ static const char *setup_bare_git_dir(const char *work_tree_env, 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; +} + /* * 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. @@ -443,15 +453,8 @@ const char *setup_git_directory_gently(int *nongit_ok) 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'; -- cgit v1.2.3 From 60c98d1e80a65c9a893733f7bceda463ef3cb6f7 Mon Sep 17 00:00:00 2001 From: Jonathan Nieder Date: Sat, 24 Jul 2010 06:27:58 -0500 Subject: setup: split off get_device_or_die helper This does not eliminate any code, but it skims some off of the main loop of setup_git_directory_gently so that can be understood more easily. Signed-off-by: Jonathan Nieder Signed-off-by: Junio C Hamano --- setup.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/setup.c b/setup.c index 9fc05e2c0a..5fb9c54ba6 100644 --- a/setup.c +++ b/setup.c @@ -388,6 +388,16 @@ static const char *setup_nongit(const char *cwd, int *nongit_ok) 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. @@ -402,7 +412,6 @@ const char *setup_git_directory_gently(int *nongit_ok) int len, offset, ceil_offset, root_len; dev_t current_device = 0; int one_filesystem = 1; - struct stat buf; /* * Let's assume that we are in a git repository. @@ -441,11 +450,8 @@ 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 (;;) { if (cwd_contains_git_dir(&gitfile_dir)) break; @@ -456,11 +462,8 @@ const char *setup_git_directory_gently(int *nongit_ok) 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"); -- cgit v1.2.3 From 60f20d4bb4f56ae90967d810ffb042e9f76b310d Mon Sep 17 00:00:00 2001 From: Jonathan Nieder Date: Fri, 30 Jul 2010 13:31:22 -0500 Subject: t4111 (apply): refresh index before applying patches to it "git apply", like most plumbing, does not automatically refresh the index file even if it is only stat-dirty. So unless the two "cp" commands in reset_preimage() for a given file happen to have the same time stamp, there will be a spurious error: sub/dir/file: does not match index Refresh the index to eliminate this timing dependency. Noticed by running the test with --valgrind (which slows things down a lot). Reported-by: Thomas Rast Signed-off-by: Jonathan Nieder Signed-off-by: Junio C Hamano --- t/t4111-apply-subdir.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/t/t4111-apply-subdir.sh b/t/t4111-apply-subdir.sh index 60c223750f..d6271ae34b 100755 --- a/t/t4111-apply-subdir.sh +++ b/t/t4111-apply-subdir.sh @@ -36,7 +36,8 @@ test_expect_success 'setup: subdir' ' cp "$2" file && cp "$2" sub/dir/file && cp "$2" sub/dir/b/file && - cp "$2" objects/file + cp "$2" objects/file && + test_might_fail git update-index --refresh -q } ' -- cgit v1.2.3 From 8fc0ae80f6938e409e0efa45d6d504c6137744e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sat, 24 Jul 2010 06:29:41 -0500 Subject: setup: do not forget working dir from subdir of gitdir MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v1.6.1.3~4^2 (Fix gitdir detection when in subdir of gitdir, 2009-01-16) did not go far enough: when a git directory is an ancestor of the original working directory, not only should GIT_DIR be set to point to the .git directory, but the original working directory should be restored before carrying out the relevant command. This way, the effect of running a git command from a subdir of .git will be the same whether or not GIT_DIR is explicitly set. Noticed while investigating v1.6.0.3~1 (rehabilitate 'git index-pack' inside the object store, 2008-10-20). Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Jonathan Nieder Signed-off-by: Junio C Hamano --- setup.c | 2 ++ t/t4111-apply-subdir.sh | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/setup.c b/setup.c index 5fb9c54ba6..5734a1f1c1 100644 --- a/setup.c +++ b/setup.c @@ -369,6 +369,8 @@ static const char *setup_bare_git_dir(const char *work_tree_env, 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); diff --git a/t/t4111-apply-subdir.sh b/t/t4111-apply-subdir.sh index d6271ae34b..a52d94ae21 100755 --- a/t/t4111-apply-subdir.sh +++ b/t/t4111-apply-subdir.sh @@ -97,7 +97,7 @@ test_expect_success 'apply from .git dir' ' test_cmp expected .git/file ' -test_expect_failure 'apply from subdir of .git dir' ' +test_expect_success 'apply from subdir of .git dir' ' cp postimage expected && cp preimage .git/file && cp preimage .git/objects/file -- cgit v1.2.3 From 3f8099fce7779631fe8827a8979d7b57629a36de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sat, 24 Jul 2010 06:30:49 -0500 Subject: Revert "rehabilitate 'git index-pack' inside the object store" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now setup_git_directory_gently behaves sanely even from subdirs of .git, so simplify index-pack by no longer protecting against that. This reverts commit a672ea6ac5a1b876bc7adfe6534b16fa2a32c94b (excluding tests). Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Jonathan Nieder Signed-off-by: Junio C Hamano --- builtin/index-pack.c | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/builtin/index-pack.c b/builtin/index-pack.c index a89ae831dd..89a1f12d61 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -880,29 +880,15 @@ 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); - /* - * 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]; -- cgit v1.2.3