diff options
author | Junio C Hamano <gitster@pobox.com> | 2015-05-11 14:23:39 -0700 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2015-05-11 14:23:39 -0700 |
commit | 68a2e6a2c80303144807c8c91a087427e3c8e727 (patch) | |
tree | 96f1e79d314e0250141fe7bc88995361ebd21c18 /t | |
parent | Merge branch 'pt/credential-xdg' (diff) | |
parent | prune --worktrees: fix expire vs worktree existence condition (diff) | |
download | tgif-68a2e6a2c80303144807c8c91a087427e3c8e727.tar.xz |
Merge branch 'nd/multiple-work-trees'
A replacement for contrib/workdir/git-new-workdir that does not
rely on symbolic links and make sharing of objects and refs safer
by making the borrowee and borrowers aware of each other.
* nd/multiple-work-trees: (41 commits)
prune --worktrees: fix expire vs worktree existence condition
t1501: fix test with split index
t2026: fix broken &&-chain
t2026 needs procondition SANITY
git-checkout.txt: a note about multiple checkout support for submodules
checkout: add --ignore-other-wortrees
checkout: pass whole struct to parse_branchname_arg instead of individual flags
git-common-dir: make "modules/" per-working-directory directory
checkout: do not fail if target is an empty directory
t2025: add a test to make sure grafts is working from a linked checkout
checkout: don't require a work tree when checking out into a new one
git_path(): keep "info/sparse-checkout" per work-tree
count-objects: report unused files in $GIT_DIR/worktrees/...
gc: support prune --worktrees
gc: factor out gc.pruneexpire parsing code
gc: style change -- no SP before closing parenthesis
checkout: clean up half-prepared directories in --to mode
checkout: reject if the branch is already checked out elsewhere
prune: strategies for linked checkouts
checkout: support checking out into a new working directory
...
Diffstat (limited to 't')
-rwxr-xr-x | t/t0060-path-utils.sh | 36 | ||||
-rwxr-xr-x | t/t1501-worktree.sh | 77 | ||||
-rwxr-xr-x | t/t1510-repo-setup.sh | 1 | ||||
-rwxr-xr-x | t/t2025-checkout-to.sh | 129 | ||||
-rwxr-xr-x | t/t2026-prune-linked-checkouts.sh | 96 | ||||
-rwxr-xr-x | t/t7410-submodule-checkout-to.sh | 50 |
6 files changed, 389 insertions, 0 deletions
diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh index c0143a0a70..93605f42f2 100755 --- a/t/t0060-path-utils.sh +++ b/t/t0060-path-utils.sh @@ -19,6 +19,14 @@ relative_path() { "test \"\$(test-path-utils relative_path '$1' '$2')\" = '$expected'" } +test_git_path() { + test_expect_success "git-path $1 $2 => $3" " + $1 git rev-parse --git-path $2 >actual && + echo $3 >expect && + test_cmp expect actual + " +} + # On Windows, we are using MSYS's bash, which mangles the paths. # Absolute paths are anchored at the MSYS installation directory, # which means that the path / accounts for this many characters: @@ -244,4 +252,32 @@ relative_path "<null>" "<empty>" ./ relative_path "<null>" "<null>" ./ relative_path "<null>" /foo/a/b ./ +test_git_path A=B info/grafts .git/info/grafts +test_git_path GIT_GRAFT_FILE=foo info/grafts foo +test_git_path GIT_GRAFT_FILE=foo info/////grafts foo +test_git_path GIT_INDEX_FILE=foo index foo +test_git_path GIT_INDEX_FILE=foo index/foo .git/index/foo +test_git_path GIT_INDEX_FILE=foo index2 .git/index2 +test_expect_success 'setup fake objects directory foo' 'mkdir foo' +test_git_path GIT_OBJECT_DIRECTORY=foo objects foo +test_git_path GIT_OBJECT_DIRECTORY=foo objects/foo foo/foo +test_git_path GIT_OBJECT_DIRECTORY=foo objects2 .git/objects2 +test_expect_success 'setup common repository' 'git --git-dir=bar init' +test_git_path GIT_COMMON_DIR=bar index .git/index +test_git_path GIT_COMMON_DIR=bar HEAD .git/HEAD +test_git_path GIT_COMMON_DIR=bar logs/HEAD .git/logs/HEAD +test_git_path GIT_COMMON_DIR=bar objects bar/objects +test_git_path GIT_COMMON_DIR=bar objects/bar bar/objects/bar +test_git_path GIT_COMMON_DIR=bar info/exclude bar/info/exclude +test_git_path GIT_COMMON_DIR=bar info/grafts bar/info/grafts +test_git_path GIT_COMMON_DIR=bar info/sparse-checkout .git/info/sparse-checkout +test_git_path GIT_COMMON_DIR=bar remotes/bar bar/remotes/bar +test_git_path GIT_COMMON_DIR=bar branches/bar bar/branches/bar +test_git_path GIT_COMMON_DIR=bar logs/refs/heads/master bar/logs/refs/heads/master +test_git_path GIT_COMMON_DIR=bar refs/heads/master bar/refs/heads/master +test_git_path GIT_COMMON_DIR=bar hooks/me bar/hooks/me +test_git_path GIT_COMMON_DIR=bar config bar/config +test_git_path GIT_COMMON_DIR=bar packed-refs bar/packed-refs +test_git_path GIT_COMMON_DIR=bar shallow bar/shallow + test_done diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh index 8f36aa9fc4..cc5b870e58 100755 --- a/t/t1501-worktree.sh +++ b/t/t1501-worktree.sh @@ -346,4 +346,81 @@ test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' ' test_cmp expected actual ' +test_expect_success 'Multi-worktree setup' ' + mkdir work && + mkdir -p repo.git/repos/foo && + cp repo.git/HEAD repo.git/index repo.git/repos/foo && + test_might_fail cp repo.git/sharedindex.* repo.git/repos/foo && + sane_unset GIT_DIR GIT_CONFIG GIT_WORK_TREE +' + +test_expect_success 'GIT_DIR set (1)' ' + echo "gitdir: repo.git/repos/foo" >gitfile && + echo ../.. >repo.git/repos/foo/commondir && + ( + cd work && + GIT_DIR=../gitfile git rev-parse --git-common-dir >actual && + test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect && + test_cmp expect actual + ) +' + +test_expect_success 'GIT_DIR set (2)' ' + echo "gitdir: repo.git/repos/foo" >gitfile && + echo "$(pwd)/repo.git" >repo.git/repos/foo/commondir && + ( + cd work && + GIT_DIR=../gitfile git rev-parse --git-common-dir >actual && + test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect && + test_cmp expect actual + ) +' + +test_expect_success 'Auto discovery' ' + echo "gitdir: repo.git/repos/foo" >.git && + echo ../.. >repo.git/repos/foo/commondir && + ( + cd work && + git rev-parse --git-common-dir >actual && + test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect && + test_cmp expect actual && + echo haha >data1 && + git add data1 && + git ls-files --full-name :/ | grep data1 >actual && + echo work/data1 >expect && + test_cmp expect actual + ) +' + +test_expect_success '$GIT_DIR/common overrides core.worktree' ' + mkdir elsewhere && + git --git-dir=repo.git config core.worktree "$TRASH_DIRECTORY/elsewhere" && + echo "gitdir: repo.git/repos/foo" >.git && + echo ../.. >repo.git/repos/foo/commondir && + ( + cd work && + git rev-parse --git-common-dir >actual && + test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect && + test_cmp expect actual && + echo haha >data2 && + git add data2 && + git ls-files --full-name :/ | grep data2 >actual && + echo work/data2 >expect && + test_cmp expect actual + ) +' + +test_expect_success '$GIT_WORK_TREE overrides $GIT_DIR/common' ' + echo "gitdir: repo.git/repos/foo" >.git && + echo ../.. >repo.git/repos/foo/commondir && + ( + cd work && + echo haha >data3 && + git --git-dir=../.git --work-tree=. add data3 && + git ls-files --full-name -- :/ | grep data3 >actual && + echo data3 >expect && + test_cmp expect actual + ) +' + test_done diff --git a/t/t1510-repo-setup.sh b/t/t1510-repo-setup.sh index e1b2a99f10..33c1a587b3 100755 --- a/t/t1510-repo-setup.sh +++ b/t/t1510-repo-setup.sh @@ -106,6 +106,7 @@ setup_env () { expect () { cat >"$1/expected" <<-EOF setup: git_dir: $2 + setup: git_common_dir: $2 setup: worktree: $3 setup: cwd: $4 setup: prefix: $5 diff --git a/t/t2025-checkout-to.sh b/t/t2025-checkout-to.sh new file mode 100755 index 0000000000..f8e4df4818 --- /dev/null +++ b/t/t2025-checkout-to.sh @@ -0,0 +1,129 @@ +#!/bin/sh + +test_description='test git checkout --to' + +. ./test-lib.sh + +test_expect_success 'setup' ' + test_commit init +' + +test_expect_success 'checkout --to not updating paths' ' + test_must_fail git checkout --to -- init.t +' + +test_expect_success 'checkout --to an existing worktree' ' + mkdir -p existing/subtree && + test_must_fail git checkout --detach --to existing master +' + +test_expect_success 'checkout --to an existing empty worktree' ' + mkdir existing_empty && + git checkout --detach --to existing_empty master +' + +test_expect_success 'checkout --to refuses to checkout locked branch' ' + test_must_fail git checkout --to zere master && + ! test -d zere && + ! test -d .git/worktrees/zere +' + +test_expect_success 'checkout --to a new worktree' ' + git rev-parse HEAD >expect && + git checkout --detach --to here master && + ( + cd here && + test_cmp ../init.t init.t && + test_must_fail git symbolic-ref HEAD && + git rev-parse HEAD >actual && + test_cmp ../expect actual && + git fsck + ) +' + +test_expect_success 'checkout --to a new worktree from a subdir' ' + ( + mkdir sub && + cd sub && + git checkout --detach --to here master && + cd here && + test_cmp ../../init.t init.t + ) +' + +test_expect_success 'checkout --to from a linked checkout' ' + ( + cd here && + git checkout --detach --to nested-here master && + cd nested-here && + git fsck + ) +' + +test_expect_success 'checkout --to a new worktree creating new branch' ' + git checkout --to there -b newmaster master && + ( + cd there && + test_cmp ../init.t init.t && + git symbolic-ref HEAD >actual && + echo refs/heads/newmaster >expect && + test_cmp expect actual && + git fsck + ) +' + +test_expect_success 'die the same branch is already checked out' ' + ( + cd here && + test_must_fail git checkout newmaster + ) +' + +test_expect_success 'not die the same branch is already checked out' ' + ( + cd here && + git checkout --ignore-other-worktrees --to anothernewmaster newmaster + ) +' + +test_expect_success 'not die on re-checking out current branch' ' + ( + cd there && + git checkout newmaster + ) +' + +test_expect_success 'checkout --to from a bare repo' ' + ( + git clone --bare . bare && + cd bare && + git checkout --to ../there2 -b bare-master master + ) +' + +test_expect_success 'checkout from a bare repo without --to' ' + ( + cd bare && + test_must_fail git checkout master + ) +' + +test_expect_success 'checkout with grafts' ' + test_when_finished rm .git/info/grafts && + test_commit abc && + SHA1=`git rev-parse HEAD` && + test_commit def && + test_commit xyz && + echo "`git rev-parse HEAD` $SHA1" >.git/info/grafts && + cat >expected <<-\EOF && + xyz + abc + EOF + git log --format=%s -2 >actual && + test_cmp expected actual && + git checkout --detach --to grafted master && + git --git-dir=grafted/.git log --format=%s -2 >actual && + test_cmp expected actual +' + +test_done diff --git a/t/t2026-prune-linked-checkouts.sh b/t/t2026-prune-linked-checkouts.sh new file mode 100755 index 0000000000..1821a480c5 --- /dev/null +++ b/t/t2026-prune-linked-checkouts.sh @@ -0,0 +1,96 @@ +#!/bin/sh + +test_description='prune $GIT_DIR/worktrees' + +. ./test-lib.sh + +test_expect_success initialize ' + git commit --allow-empty -m init +' + +test_expect_success 'prune --worktrees on normal repo' ' + git prune --worktrees && + test_must_fail git prune --worktrees abc +' + +test_expect_success 'prune files inside $GIT_DIR/worktrees' ' + mkdir .git/worktrees && + : >.git/worktrees/abc && + git prune --worktrees --verbose >actual && + cat >expect <<EOF && +Removing worktrees/abc: not a valid directory +EOF + test_i18ncmp expect actual && + ! test -f .git/worktrees/abc && + ! test -d .git/worktrees +' + +test_expect_success 'prune directories without gitdir' ' + mkdir -p .git/worktrees/def/abc && + : >.git/worktrees/def/def && + cat >expect <<EOF && +Removing worktrees/def: gitdir file does not exist +EOF + git prune --worktrees --verbose >actual && + test_i18ncmp expect actual && + ! test -d .git/worktrees/def && + ! test -d .git/worktrees +' + +test_expect_success SANITY 'prune directories with unreadable gitdir' ' + mkdir -p .git/worktrees/def/abc && + : >.git/worktrees/def/def && + : >.git/worktrees/def/gitdir && + chmod u-r .git/worktrees/def/gitdir && + git prune --worktrees --verbose >actual && + test_i18ngrep "Removing worktrees/def: unable to read gitdir file" actual && + ! test -d .git/worktrees/def && + ! test -d .git/worktrees +' + +test_expect_success 'prune directories with invalid gitdir' ' + mkdir -p .git/worktrees/def/abc && + : >.git/worktrees/def/def && + : >.git/worktrees/def/gitdir && + git prune --worktrees --verbose >actual && + test_i18ngrep "Removing worktrees/def: invalid gitdir file" actual && + ! test -d .git/worktrees/def && + ! test -d .git/worktrees +' + +test_expect_success 'prune directories with gitdir pointing to nowhere' ' + mkdir -p .git/worktrees/def/abc && + : >.git/worktrees/def/def && + echo "$(pwd)"/nowhere >.git/worktrees/def/gitdir && + git prune --worktrees --verbose >actual && + test_i18ngrep "Removing worktrees/def: gitdir file points to non-existent location" actual && + ! test -d .git/worktrees/def && + ! test -d .git/worktrees +' + +test_expect_success 'not prune locked checkout' ' + test_when_finished rm -r .git/worktrees && + mkdir -p .git/worktrees/ghi && + : >.git/worktrees/ghi/locked && + git prune --worktrees && + test -d .git/worktrees/ghi +' + +test_expect_success 'not prune recent checkouts' ' + test_when_finished rm -r .git/worktrees && + mkdir zz && + mkdir -p .git/worktrees/jlm && + echo "$(pwd)"/zz >.git/worktrees/jlm/gitdir && + rmdir zz && + git prune --worktrees --verbose --expire=2.days.ago && + test -d .git/worktrees/jlm +' + +test_expect_success 'not prune proper checkouts' ' + test_when_finished rm -r .git/worktrees && + git checkout "--to=$PWD/nop" --detach master && + git prune --worktrees && + test -d .git/worktrees/nop +' + +test_done diff --git a/t/t7410-submodule-checkout-to.sh b/t/t7410-submodule-checkout-to.sh new file mode 100755 index 0000000000..8f30aed6cc --- /dev/null +++ b/t/t7410-submodule-checkout-to.sh @@ -0,0 +1,50 @@ +#!/bin/sh + +test_description='Combination of submodules and multiple workdirs' + +. ./test-lib.sh + +base_path=$(pwd -P) + +test_expect_success 'setup: make origin' \ + 'mkdir -p origin/sub && ( cd origin/sub && git init && + echo file1 >file1 && + git add file1 && + git commit -m file1 ) && + mkdir -p origin/main && ( cd origin/main && git init && + git submodule add ../sub && + git commit -m "add sub" ) && + ( cd origin/sub && + echo file1updated >file1 && + git add file1 && + git commit -m "file1 updated" ) && + ( cd origin/main/sub && git pull ) && + ( cd origin/main && + git add sub && + git commit -m "sub updated" )' + +test_expect_success 'setup: clone' \ + 'mkdir clone && ( cd clone && + git clone --recursive "$base_path/origin/main")' + +rev1_hash_main=$(git --git-dir=origin/main/.git show --pretty=format:%h -q "HEAD~1") +rev1_hash_sub=$(git --git-dir=origin/sub/.git show --pretty=format:%h -q "HEAD~1") + +test_expect_success 'checkout main' \ + 'mkdir default_checkout && + (cd clone/main && + git checkout --to "$base_path/default_checkout/main" "$rev1_hash_main")' + +test_expect_failure 'can see submodule diffs just after checkout' \ + '(cd default_checkout/main && git diff --submodule master"^!" | grep "file1 updated")' + +test_expect_success 'checkout main and initialize independed clones' \ + 'mkdir fully_cloned_submodule && + (cd clone/main && + git checkout --to "$base_path/fully_cloned_submodule/main" "$rev1_hash_main") && + (cd fully_cloned_submodule/main && git submodule update)' + +test_expect_success 'can see submodule diffs after independed cloning' \ + '(cd fully_cloned_submodule/main && git diff --submodule master"^!" | grep "file1 updated")' + +test_done |