a7d666a7ef
We currently generate incorrect duplicate .gitattributes entries when performing an import or export migration if an existing .gitattributes file has execute file permissions. As we intend to fix this behaviour, we first add a pair of tests for it, which check for a single .gitattributes file after migration and therefore will fail until we resolve the problem.
514 lines
15 KiB
Bash
Executable File
514 lines
15 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
. "$(dirname "$0")/fixtures/migrate.sh"
|
|
. "$(dirname "$0")/testlib.sh"
|
|
|
|
begin_test "migrate export (default branch)"
|
|
(
|
|
set -e
|
|
|
|
setup_multiple_local_branches_tracked
|
|
|
|
# Add b.md, a pointer existing only on main
|
|
base64 < /dev/urandom | head -c 160 > b.md
|
|
git add b.md
|
|
git commit -m "add b.md"
|
|
|
|
md_oid="$(calc_oid "$(cat a.md)")"
|
|
txt_oid="$(calc_oid "$(cat a.txt)")"
|
|
b_md_oid="$(calc_oid "$(cat b.md)")"
|
|
|
|
git checkout my-feature
|
|
md_feature_oid="$(calc_oid "$(cat a.md)")"
|
|
git checkout main
|
|
|
|
assert_pointer "refs/heads/main" "a.md" "$md_oid" "140"
|
|
assert_pointer "refs/heads/main" "a.txt" "$txt_oid" "120"
|
|
assert_pointer "refs/heads/main" "b.md" "$b_md_oid" "160"
|
|
assert_pointer "refs/heads/my-feature" "a.md" "$md_feature_oid" "30"
|
|
|
|
git lfs migrate export --include="*.md, *.txt"
|
|
|
|
refute_pointer "refs/heads/main" "a.md"
|
|
refute_pointer "refs/heads/main" "a.txt"
|
|
refute_pointer "refs/heads/main" "b.md"
|
|
assert_pointer "refs/heads/my-feature" "a.md" "$md_feature_oid" "30"
|
|
|
|
# b.md should be pruned as no pointer exists to reference it
|
|
refute_local_object "$b_md_oid" "160"
|
|
|
|
# Other objects should not be pruned as they're still referenced in `feature`
|
|
# by pointers
|
|
assert_local_object "$md_oid" "140"
|
|
assert_local_object "$txt_oid" "120"
|
|
assert_local_object "$md_feature_oid" "30"
|
|
|
|
main="$(git rev-parse refs/heads/main)"
|
|
feature="$(git rev-parse refs/heads/my-feature)"
|
|
|
|
main_attrs="$(git cat-file -p "$main:.gitattributes")"
|
|
feature_attrs="$(git cat-file -p "$feature:.gitattributes")"
|
|
|
|
echo "$main_attrs" | grep -q "*.md !text !filter !merge !diff"
|
|
echo "$main_attrs" | grep -q "*.txt !text !filter !merge !diff"
|
|
|
|
[ ! $(echo "$feature_attrs" | grep -q "*.md !text !filter !merge !diff") ]
|
|
[ ! $(echo "$feature_attrs" | grep -q "*.txt !text !filter !merge !diff") ]
|
|
)
|
|
end_test
|
|
|
|
begin_test "migrate export (with remote)"
|
|
(
|
|
set -e
|
|
|
|
setup_single_remote_branch_tracked
|
|
|
|
git push origin main
|
|
|
|
md_oid="$(calc_oid "$(cat a.md)")"
|
|
txt_oid="$(calc_oid "$(cat a.txt)")"
|
|
|
|
assert_pointer "refs/heads/main" "a.md" "$md_oid" "50"
|
|
assert_pointer "refs/heads/main" "a.txt" "$txt_oid" "30"
|
|
|
|
assert_pointer "refs/remotes/origin/main" "a.md" "$md_oid" "50"
|
|
assert_pointer "refs/remotes/origin/main" "a.txt" "$txt_oid" "30"
|
|
|
|
# Flush the cache to ensure all objects have to be downloaded
|
|
rm -rf .git/lfs/objects
|
|
|
|
git lfs migrate export --everything --include="*.md, *.txt"
|
|
|
|
refute_pointer "refs/heads/main" "a.md"
|
|
refute_pointer "refs/heads/main" "a.txt"
|
|
|
|
# All pointers have been exported, so all objects should be pruned
|
|
refute_local_object "$md_oid" "50"
|
|
refute_local_object "$txt_oid" "30"
|
|
|
|
main="$(git rev-parse refs/heads/main)"
|
|
main_attrs="$(git cat-file -p "$main:.gitattributes")"
|
|
|
|
echo "$main_attrs" | grep -q "*.md !text !filter !merge !diff"
|
|
echo "$main_attrs" | grep -q "*.txt !text !filter !merge !diff"
|
|
)
|
|
end_test
|
|
|
|
begin_test "migrate export (include/exclude args)"
|
|
(
|
|
set -e
|
|
|
|
setup_single_local_branch_tracked
|
|
|
|
md_oid="$(calc_oid "$(cat a.md)")"
|
|
txt_oid="$(calc_oid "$(cat a.txt)")"
|
|
|
|
assert_pointer "refs/heads/main" "a.txt" "$txt_oid" "120"
|
|
assert_pointer "refs/heads/main" "a.md" "$md_oid" "140"
|
|
|
|
git lfs migrate export --include="*" --exclude="a.md"
|
|
|
|
refute_pointer "refs/heads/main" "a.txt"
|
|
assert_pointer "refs/heads/main" "a.md" "$md_oid" "140"
|
|
|
|
refute_local_object "$txt_oid" "120"
|
|
assert_local_object "$md_oid" "140"
|
|
|
|
main="$(git rev-parse refs/heads/main)"
|
|
|
|
main_attrs="$(git cat-file -p "$main:.gitattributes")"
|
|
|
|
echo "$main_attrs" | grep -q "* !text !filter !merge !diff"
|
|
echo "$main_attrs" | grep -q "a.md filter=lfs diff=lfs merge=lfs"
|
|
)
|
|
end_test
|
|
|
|
begin_test "migrate export (bare repository)"
|
|
(
|
|
set -e
|
|
|
|
setup_single_remote_branch_tracked
|
|
git push origin main
|
|
|
|
md_oid="$(calc_oid "$(cat a.md)")"
|
|
txt_oid="$(calc_oid "$(cat a.txt)")"
|
|
|
|
make_bare
|
|
|
|
assert_pointer "refs/heads/main" "a.txt" "$txt_oid" "30"
|
|
assert_pointer "refs/heads/main" "a.md" "$md_oid" "50"
|
|
|
|
git lfs migrate export --everything --include="*"
|
|
|
|
refute_pointer "refs/heads/main" "a.md"
|
|
refute_pointer "refs/heads/main" "a.txt"
|
|
|
|
# All pointers have been exported, so all objects should be pruned
|
|
refute_local_object "$md_oid" "50"
|
|
refute_local_object "$txt_oid" "30"
|
|
)
|
|
end_test
|
|
|
|
begin_test "migrate export (given branch)"
|
|
(
|
|
set -e
|
|
|
|
setup_multiple_local_branches_tracked
|
|
|
|
md_oid="$(calc_oid "$(cat a.md)")"
|
|
txt_oid="$(calc_oid "$(cat a.txt)")"
|
|
|
|
git checkout my-feature
|
|
md_feature_oid="$(calc_oid "$(cat a.md)")"
|
|
git checkout main
|
|
|
|
assert_pointer "refs/heads/my-feature" "a.md" "$md_feature_oid" "30"
|
|
assert_pointer "refs/heads/my-feature" "a.txt" "$txt_oid" "120"
|
|
assert_pointer "refs/heads/main" "a.md" "$md_oid" "140"
|
|
assert_pointer "refs/heads/main" "a.txt" "$txt_oid" "120"
|
|
|
|
git lfs migrate export --include="*.md,*.txt" my-feature
|
|
|
|
refute_pointer "refs/heads/my-feature" "a.md"
|
|
refute_pointer "refs/heads/my-feature" "a.txt"
|
|
refute_pointer "refs/heads/main" "a.md"
|
|
refute_pointer "refs/heads/main" "a.txt"
|
|
|
|
# No pointers left, so all objects should be pruned
|
|
refute_local_object "$md_feature_oid" "30"
|
|
refute_local_object "$txt_oid" "120"
|
|
refute_local_object "$md_oid" "140"
|
|
|
|
main="$(git rev-parse refs/heads/main)"
|
|
feature="$(git rev-parse refs/heads/my-feature)"
|
|
|
|
main_attrs="$(git cat-file -p "$main:.gitattributes")"
|
|
feature_attrs="$(git cat-file -p "$feature:.gitattributes")"
|
|
|
|
echo "$main_attrs" | grep -q "*.md !text !filter !merge !diff"
|
|
echo "$main_attrs" | grep -q "*.txt !text !filter !merge !diff"
|
|
echo "$feature_attrs" | grep -q "*.md !text !filter !merge !diff"
|
|
echo "$feature_attrs" | grep -q "*.txt !text !filter !merge !diff"
|
|
)
|
|
end_test
|
|
|
|
begin_test "migrate export (no filter)"
|
|
(
|
|
set -e
|
|
|
|
setup_multiple_local_branches_tracked
|
|
|
|
git lfs migrate export --yes 2>&1 | tee migrate.log
|
|
if [ ${PIPESTATUS[0]} -eq 0 ]; then
|
|
echo >&2 "fatal: expected git lfs migrate export to fail, didn't"
|
|
exit 1
|
|
fi
|
|
|
|
grep "One or more files must be specified with --include" migrate.log
|
|
)
|
|
end_test
|
|
|
|
begin_test "migrate export (exclude remote refs)"
|
|
(
|
|
set -e
|
|
|
|
setup_single_remote_branch_tracked
|
|
|
|
md_oid="$(calc_oid "$(cat a.md)")"
|
|
txt_oid="$(calc_oid "$(cat a.txt)")"
|
|
|
|
git checkout refs/remotes/origin/main
|
|
md_remote_oid="$(calc_oid "$(cat a.md)")"
|
|
txt_remote_oid="$(calc_oid "$(cat a.txt)")"
|
|
git checkout main
|
|
|
|
assert_pointer "refs/heads/main" "a.md" "$md_oid" "50"
|
|
assert_pointer "refs/heads/main" "a.txt" "$txt_oid" "30"
|
|
|
|
assert_pointer "refs/remotes/origin/main" "a.md" "$md_remote_oid" "140"
|
|
assert_pointer "refs/remotes/origin/main" "a.txt" "$txt_remote_oid" "120"
|
|
|
|
git lfs migrate export --include="*.md,*.txt"
|
|
|
|
refute_pointer "refs/heads/main" "a.md"
|
|
refute_pointer "refs/heads/main" "a.txt"
|
|
|
|
refute_local_object "$md_oid" "50"
|
|
refute_local_object "$txt_oid" "30"
|
|
|
|
assert_pointer "refs/remotes/origin/main" "a.md" "$md_remote_oid" "140"
|
|
assert_pointer "refs/remotes/origin/main" "a.txt" "$txt_remote_oid" "120"
|
|
|
|
# Since these two objects exist on the remote, they should be removed with
|
|
# our prune operation
|
|
refute_local_object "$md_remote_oid" "140"
|
|
refute_local_object "$txt_remote_oid" "120"
|
|
|
|
main="$(git rev-parse refs/heads/main)"
|
|
remote="$(git rev-parse refs/remotes/origin/main)"
|
|
|
|
main_attrs="$(git cat-file -p "$main:.gitattributes")"
|
|
remote_attrs="$(git cat-file -p "$remote:.gitattributes")"
|
|
|
|
echo "$main_attrs" | grep -q "*.md !text !filter !merge !diff"
|
|
echo "$main_attrs" | grep -q "*.txt !text !filter !merge !diff"
|
|
|
|
[ ! $(echo "$remote_attrs" | grep -q "*.md !text !filter !merge !diff") ]
|
|
[ ! $(echo "$remote_attrs" | grep -q "*.txt !text !filter !merge !diff") ]
|
|
)
|
|
end_test
|
|
|
|
begin_test "migrate export (--skip-fetch)"
|
|
(
|
|
set -e
|
|
|
|
setup_single_remote_branch_tracked
|
|
|
|
md_main_oid="$(calc_oid "$(cat a.md)")"
|
|
txt_main_oid="$(calc_oid "$(cat a.txt)")"
|
|
|
|
git checkout refs/remotes/origin/main
|
|
md_remote_oid="$(calc_oid "$(cat a.md)")"
|
|
txt_remote_oid="$(calc_oid "$(cat a.txt)")"
|
|
git checkout main
|
|
|
|
git tag pseudo-remote "$(git rev-parse refs/remotes/origin/main)"
|
|
# Remove the refs/remotes/origin/main ref, and instruct 'git lfs migrate' to
|
|
# not fetch it.
|
|
git update-ref -d refs/remotes/origin/main
|
|
|
|
assert_pointer "refs/heads/main" "a.md" "$md_main_oid" "50"
|
|
assert_pointer "pseudo-remote" "a.md" "$md_remote_oid" "140"
|
|
assert_pointer "refs/heads/main" "a.txt" "$txt_main_oid" "30"
|
|
assert_pointer "pseudo-remote" "a.txt" "$txt_remote_oid" "120"
|
|
|
|
git lfs migrate export --skip-fetch --include="*.md,*.txt"
|
|
|
|
refute_pointer "refs/heads/main" "a.md"
|
|
refute_pointer "pseudo-remote" "a.md"
|
|
refute_pointer "refs/heads/main" "a.txt"
|
|
refute_pointer "pseudo-remote" "a.txt"
|
|
|
|
refute_local_object "$md_main_oid" "50"
|
|
refute_local_object "$md_remote_oid" "140"
|
|
refute_local_object "$txt_main_oid" "30"
|
|
refute_local_object "$txt_remote_oid" "120"
|
|
|
|
main="$(git rev-parse refs/heads/main)"
|
|
remote="$(git rev-parse pseudo-remote)"
|
|
|
|
main_attrs="$(git cat-file -p "$main:.gitattributes")"
|
|
remote_attrs="$(git cat-file -p "$remote:.gitattributes")"
|
|
|
|
echo "$main_attrs" | grep -q "*.md !text !filter !merge !diff"
|
|
echo "$main_attrs" | grep -q "*.txt !text !filter !merge !diff"
|
|
echo "$remote_attrs" | grep -q "*.md !text !filter !merge !diff"
|
|
echo "$remote_attrs" | grep -q "*.txt !text !filter !merge !diff"
|
|
)
|
|
end_test
|
|
|
|
begin_test "migrate export (include/exclude ref)"
|
|
(
|
|
set -e
|
|
|
|
setup_multiple_remote_branches_gitattrs
|
|
|
|
md_main_oid="$(calc_oid "$(cat a.md)")"
|
|
txt_main_oid="$(calc_oid "$(cat a.txt)")"
|
|
|
|
git checkout refs/remotes/origin/main
|
|
md_remote_oid="$(calc_oid "$(cat a.md)")"
|
|
txt_remote_oid="$(calc_oid "$(cat a.txt)")"
|
|
|
|
git checkout my-feature
|
|
md_feature_oid="$(calc_oid "$(cat a.md)")"
|
|
txt_feature_oid="$(calc_oid "$(cat a.txt)")"
|
|
|
|
git checkout main
|
|
|
|
git lfs migrate export \
|
|
--include="*.txt" \
|
|
--include-ref=refs/heads/my-feature \
|
|
--exclude-ref=refs/heads/main
|
|
|
|
assert_pointer "refs/heads/main" "a.md" "$md_main_oid" "21"
|
|
assert_pointer "refs/heads/main" "a.txt" "$txt_main_oid" "20"
|
|
|
|
assert_pointer "refs/remotes/origin/main" "a.md" "$md_remote_oid" "11"
|
|
assert_pointer "refs/remotes/origin/main" "a.txt" "$txt_remote_oid" "10"
|
|
|
|
assert_pointer "refs/heads/my-feature" "a.md" "$md_feature_oid" "31"
|
|
refute_pointer "refs/heads/my-feature" "a.txt"
|
|
|
|
# Master objects should not be pruned as they exist in unpushed commits
|
|
assert_local_object "$md_main_oid" "21"
|
|
assert_local_object "$txt_main_oid" "20"
|
|
|
|
# Remote main objects should be pruned as they exist in the remote
|
|
refute_local_object "$md_remote_oid" "11"
|
|
refute_local_object "$txt_remote_oid" "10"
|
|
|
|
# txt_feature_oid should be pruned as it's no longer a pointer, but
|
|
# md_feature_oid should remain as it's still a pointer in unpushed commits
|
|
assert_local_object "$md_feature_oid" "31"
|
|
refute_local_object "$txt_feature_oid" "30"
|
|
|
|
main="$(git rev-parse refs/heads/main)"
|
|
feature="$(git rev-parse refs/heads/my-feature)"
|
|
remote="$(git rev-parse refs/remotes/origin/main)"
|
|
|
|
main_attrs="$(git cat-file -p "$main:.gitattributes")"
|
|
remote_attrs="$(git cat-file -p "$remote:.gitattributes")"
|
|
feature_attrs="$(git cat-file -p "$feature:.gitattributes")"
|
|
|
|
[ ! $(echo "$main_attrs" | grep -q "*.txt !text !filter !merge !diff") ]
|
|
[ ! $(echo "$remote_attrs" | grep -q "*.txt !text !filter !merge !diff") ]
|
|
echo "$feature_attrs" | grep -q "*.txt !text !filter !merge !diff"
|
|
)
|
|
end_test
|
|
|
|
begin_test "migrate export (.gitattributes with different permissions)"
|
|
(
|
|
set -e
|
|
|
|
# Windows lacks POSIX permissions.
|
|
[ "$IS_WINDOWS" -eq 1 ] && exit 0
|
|
|
|
setup_single_local_branch_tracked 0755
|
|
|
|
md_oid="$(calc_oid "$(cat a.md)")"
|
|
txt_oid="$(calc_oid "$(cat a.txt)")"
|
|
|
|
assert_pointer "refs/heads/main" "a.txt" "$txt_oid" "120"
|
|
assert_pointer "refs/heads/main" "a.md" "$md_oid" "140"
|
|
|
|
[ -x .gitattributes ]
|
|
|
|
git lfs migrate export --include="*.txt"
|
|
|
|
[ ! -x .gitattributes ]
|
|
|
|
refute_pointer "refs/heads/main" "a.txt"
|
|
assert_pointer "refs/heads/main" "a.md" "$md_oid" "140"
|
|
|
|
refute_local_object "$txt_oid" "120"
|
|
assert_local_object "$md_oid" "140"
|
|
|
|
main="$(git rev-parse refs/heads/main)"
|
|
|
|
main_attrs="$(git cat-file -p "$main:.gitattributes")"
|
|
|
|
echo "$main_attrs" | grep -q "*.txt !text !filter !merge !diff"
|
|
|
|
attrs_main_sha="$(git show $main:.gitattributes | git hash-object --stdin)"
|
|
md_main_sha="$(git show $main:a.md | git hash-object --stdin)"
|
|
txt_main_sha="$(git show $main:a.txt | git hash-object --stdin)"
|
|
|
|
diff -u <(git ls-tree $main) <(cat <<-EOF
|
|
100644 blob $attrs_main_sha .gitattributes
|
|
100644 blob $md_main_sha a.md
|
|
100644 blob $txt_main_sha a.txt
|
|
EOF
|
|
)
|
|
)
|
|
end_test
|
|
|
|
begin_test "migrate export (--object-map)"
|
|
(
|
|
set -e
|
|
|
|
setup_multiple_local_branches_tracked
|
|
|
|
output_dir=$(mktemp -d)
|
|
|
|
git log --all --pretty='format:%H' > "${output_dir}/old_sha.txt"
|
|
git lfs migrate export --everything --include="*" --object-map "${output_dir}/object-map.txt"
|
|
git log --all --pretty='format:%H' > "${output_dir}/new_sha.txt"
|
|
paste -d',' "${output_dir}/old_sha.txt" "${output_dir}/new_sha.txt" > "${output_dir}/expected-map.txt"
|
|
|
|
diff -u <(sort "${output_dir}/expected-map.txt") <(sort "${output_dir}/object-map.txt")
|
|
)
|
|
end_test
|
|
|
|
begin_test "migrate export (--verbose)"
|
|
(
|
|
set -e
|
|
|
|
setup_multiple_local_branches_tracked
|
|
|
|
git lfs migrate export --everything --include="*" --verbose 2>&1 | grep -q "migrate: commit "
|
|
)
|
|
end_test
|
|
|
|
begin_test "migrate export (--remote)"
|
|
(
|
|
set -e
|
|
|
|
setup_single_remote_branch_tracked
|
|
|
|
git push origin main
|
|
|
|
md_oid="$(calc_oid "$(cat a.md)")"
|
|
txt_oid="$(calc_oid "$(cat a.txt)")"
|
|
|
|
assert_pointer "refs/heads/main" "a.md" "$md_oid" "50"
|
|
assert_pointer "refs/heads/main" "a.txt" "$txt_oid" "30"
|
|
|
|
# Flush the cache to ensure all objects have to be downloaded
|
|
rm -rf .git/lfs/objects
|
|
|
|
# Setup a new remote and invalidate the default
|
|
remote_url="$(git config --get remote.origin.url)"
|
|
git remote add zeta "$remote_url"
|
|
git remote set-url origin ""
|
|
|
|
git lfs migrate export --everything --remote="zeta" --include="*.md, *.txt"
|
|
|
|
refute_pointer "refs/heads/main" "a.md"
|
|
refute_pointer "refs/heads/main" "a.txt"
|
|
|
|
refute_local_object "$md_oid" "50"
|
|
refute_local_object "$txt_oid" "30"
|
|
)
|
|
end_test
|
|
|
|
begin_test "migrate export (invalid --remote)"
|
|
(
|
|
set -e
|
|
|
|
setup_single_remote_branch_tracked
|
|
|
|
git lfs migrate export --include="*" --remote="zz" --yes 2>&1 \
|
|
| tee migrate.log
|
|
if [ ${PIPESTATUS[0]} -eq 0 ]; then
|
|
echo >&2 "fatal: expected git lfs migrate export to fail, didn't"
|
|
exit 1
|
|
fi
|
|
|
|
grep "Invalid remote zz provided" migrate.log
|
|
)
|
|
end_test
|
|
|
|
begin_test "migrate export (invalid pointer)"
|
|
(
|
|
set -e
|
|
|
|
git init repo1
|
|
git init repo2
|
|
|
|
cd repo1
|
|
echo "git-lfs" > problematic_file
|
|
git add .
|
|
git commit -m "create repo"
|
|
|
|
git lfs migrate export --include="*" --everything --yes
|
|
|
|
cd ../repo2
|
|
echo "not git-lfs" > problematic_file
|
|
git add .
|
|
git commit -m "create repo"
|
|
|
|
git lfs migrate export --include="*" --everything --yes
|
|
)
|
|
end_test
|