git-lfs/t/t-migrate-import.sh
brian m. carlson a5d20de4a8
t: avoid incorrect negated commands
When `set -e` is enabled, not all commands trigger an error exit if they
return false.  For example, it's clear that commands in an `if` or
`while` statement don't cause an error if they are false.

What is less obvious, however, is that negated commands and negated
pipelines also have no effect on `set -e`.  From POSIX 1003.1-2017 (on
`sh -e`):

    When this option is on, if a simple command fails for any of the
    reasons listed in Consequences of Shell Errors or returns an exit
    status value >0, and is not part of the compound list following a
    while, until, or if keyword, and is not a part of an AND or OR list,
    and is not a pipeline preceded by the ! reserved word, then the
    shell shall immediately exit.

As such, writing something like `! grep` will never fail.  Fortunately,
we can append `&& exit 1` instead of the `!` and that will work
correctly.

To make this work, run the following command to make the code properly
check the exit status of our commands:

  git grep -l '! [a-z]' t | \
    xargs ruby -pi -e '$_.gsub!(/^(\s+)! ([a-z].*)$/, "\\1\\2 && exit 1")'

Because such a command will still have a non-zero exit status, even if
it doesn't trigger `set -e`, add a `true` if this is the last statement
in a block, so that the test exits successfully and therefore passes.
2023-02-22 14:57:29 +00:00

1158 lines
34 KiB
Bash
Executable File

#!/usr/bin/env bash
. "$(dirname "$0")/fixtures/migrate.sh"
. "$(dirname "$0")/testlib.sh"
begin_test "migrate import (default branch)"
(
set -e
setup_multiple_local_branches
md_oid="$(calc_oid "$(git cat-file -p :a.md)")"
txt_oid="$(calc_oid "$(git cat-file -p :a.txt)")"
md_feature_oid="$(calc_oid "$(git cat-file -p my-feature:a.md)")"
git lfs migrate import
assert_pointer "refs/heads/main" "a.md" "$md_oid" "140"
assert_pointer "refs/heads/main" "a.txt" "$txt_oid" "120"
assert_local_object "$md_oid" "140"
assert_local_object "$txt_oid" "120"
refute_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")"
[ ! $(git cat-file -p "$feature:.gitattributes") ]
echo "$main_attrs" | grep -q "*.md filter=lfs diff=lfs merge=lfs"
echo "$main_attrs" | grep -q "*.txt filter=lfs diff=lfs merge=lfs"
# Ensure that hooks are installed. If we find 'git-lfs' somewhere in
# .git/hooks/pre-push we assume that the rest went correctly, too.
grep -q "git-lfs" .git/hooks/pre-push
)
end_test
begin_test "migrate import (bare repository)"
(
set -e
setup_multiple_remote_branches
git lfs migrate import --everything
)
end_test
begin_test "migrate import (given branch)"
(
set -e
setup_multiple_local_branches
md_oid="$(calc_oid "$(git cat-file -p :a.md)")"
txt_oid="$(calc_oid "$(git cat-file -p :a.txt)")"
md_feature_oid="$(calc_oid "$(git cat-file -p my-feature:a.md)")"
git lfs migrate import my-feature
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"
assert_local_object "$md_oid" "140"
assert_local_object "$md_feature_oid" "30"
assert_local_object "$txt_oid" "120"
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 filter=lfs diff=lfs merge=lfs"
echo "$main_attrs" | grep -q "*.txt filter=lfs diff=lfs merge=lfs"
echo "$feature_attrs" | grep -q "*.md filter=lfs diff=lfs merge=lfs"
echo "$feature_attrs" | grep -q "*.txt filter=lfs diff=lfs merge=lfs"
)
end_test
begin_test "migrate import (default branch with filter)"
(
set -e
setup_multiple_local_branches
md_oid="$(calc_oid "$(git cat-file -p :a.md)")"
txt_oid="$(calc_oid "$(git cat-file -p :a.txt)")"
md_feature_oid="$(calc_oid "$(git cat-file -p my-feature:a.md)")"
git lfs migrate import --include "*.md"
assert_pointer "refs/heads/main" "a.md" "$md_oid" "140"
assert_local_object "$md_oid" "140"
refute_local_object "$txt_oid" "120"
refute_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")"
[ ! $(git cat-file -p "$feature:.gitattributes") ]
echo "$main_attrs" | grep -q "*.md filter=lfs diff=lfs merge=lfs"
echo "$main_attrs" | grep -vq "*.txt filter=lfs diff=lfs merge=lfs"
)
end_test
begin_test "migrate import (given branch with filter)"
(
set -e
setup_multiple_local_branches
md_oid="$(calc_oid "$(git cat-file -p :a.md)")"
txt_oid="$(calc_oid "$(git cat-file -p :a.txt)")"
md_feature_oid="$(calc_oid "$(git cat-file -p my-feature:a.md)")"
git lfs migrate import --include "*.md" my-feature
assert_pointer "refs/heads/my-feature" "a.md" "$md_feature_oid" "30"
assert_pointer "refs/heads/my-feature~1" "a.md" "$md_oid" "140"
assert_local_object "$md_oid" "140"
assert_local_object "$md_feature_oid" "30"
refute_local_object "$txt_oid" "120"
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 filter=lfs diff=lfs merge=lfs"
echo "$main_attrs" | grep -vq "*.txt filter=lfs diff=lfs merge=lfs"
echo "$feature_attrs" | grep -q "*.md filter=lfs diff=lfs merge=lfs"
echo "$feature_attrs" | grep -vq "*.txt filter=lfs diff=lfs merge=lfs"
)
end_test
begin_test "migrate import (default branch, exclude remote refs)"
(
set -e
setup_single_remote_branch
md_remote_oid="$(calc_oid "$(git cat-file -p "refs/remotes/origin/main:a.md")")"
txt_remote_oid="$(calc_oid "$(git cat-file -p "refs/remotes/origin/main:a.txt")")"
md_oid="$(calc_oid "$(git cat-file -p "refs/heads/main:a.md")")"
txt_oid="$(calc_oid "$(git cat-file -p "refs/heads/main:a.txt")")"
git lfs migrate import
assert_pointer "refs/heads/main" "a.md" "$md_oid" "50"
assert_pointer "refs/heads/main" "a.txt" "$txt_oid" "30"
assert_local_object "$md_oid" "50"
assert_local_object "$txt_oid" "30"
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")"
[ ! $(git cat-file -p "$remote:.gitattributes") ]
echo "$main_attrs" | grep -q "*.md filter=lfs diff=lfs merge=lfs"
echo "$main_attrs" | grep -vq "*.txt filter=lfs diff=lfs merge=lfs"
)
end_test
begin_test "migrate import (given branch, exclude remote refs)"
(
set -e
setup_multiple_remote_branches
md_main_oid="$(calc_oid "$(git cat-file -p "refs/heads/main:a.md")")"
md_remote_oid="$(calc_oid "$(git cat-file -p "refs/remotes/origin/main:a.md")")"
md_feature_oid="$(calc_oid "$(git cat-file -p "refs/heads/my-feature:a.md")")"
txt_main_oid="$(calc_oid "$(git cat-file -p "refs/heads/main:a.txt")")"
txt_remote_oid="$(calc_oid "$(git cat-file -p "refs/remotes/origin/main:a.txt")")"
txt_feature_oid="$(calc_oid "$(git cat-file -p "refs/heads/my-feature:a.txt")")"
git lfs migrate import my-feature
assert_pointer "refs/heads/main" "a.md" "$md_main_oid" "21"
assert_pointer "refs/heads/my-feature" "a.md" "$md_feature_oid" "31"
assert_pointer "refs/heads/main" "a.txt" "$txt_main_oid" "20"
assert_pointer "refs/heads/my-feature" "a.txt" "$txt_feature_oid" "30"
assert_local_object "$md_feature_oid" "31"
assert_local_object "$md_main_oid" "21"
assert_local_object "$txt_feature_oid" "30"
assert_local_object "$txt_main_oid" "20"
refute_local_object "$md_remote_oid" "11"
refute_local_object "$txt_remote_oid" "10"
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")"
[ ! $(git cat-file -p "$remote:.gitattributes") ]
feature_attrs="$(git cat-file -p "$feature:.gitattributes")"
echo "$main_attrs" | grep -q "*.md filter=lfs diff=lfs merge=lfs"
echo "$main_attrs" | grep -q "*.txt filter=lfs diff=lfs merge=lfs"
echo "$feature_attrs" | grep -q "*.md filter=lfs diff=lfs merge=lfs"
echo "$feature_attrs" | grep -vq "*.txt filter=lfs diff=lfs merge=lfs"
)
end_test
begin_test "migrate import (given ref, --skip-fetch)"
(
set -e
setup_single_remote_branch
md_main_oid="$(calc_oid "$(git cat-file -p "refs/heads/main:a.md")")"
md_remote_oid="$(calc_oid "$(git cat-file -p "refs/remotes/origin/main:a.md")")"
txt_main_oid="$(calc_oid "$(git cat-file -p "refs/heads/main:a.txt")")"
txt_remote_oid="$(calc_oid "$(git cat-file -p "refs/remotes/origin/main:a.txt")")"
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
git lfs migrate import --skip-fetch
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"
assert_local_object "$md_main_oid" "50"
assert_local_object "$txt_main_oid" "30"
assert_local_object "$md_remote_oid" "140"
assert_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 filter=lfs diff=lfs merge=lfs"
echo "$main_attrs" | grep -q "*.txt filter=lfs diff=lfs merge=lfs"
echo "$remote_attrs" | grep -q "*.md filter=lfs diff=lfs merge=lfs"
echo "$remote_attrs" | grep -q "*.txt filter=lfs diff=lfs merge=lfs"
)
end_test
begin_test "migrate import (un-annotated tags)"
(
set -e
setup_single_local_branch_with_tags
txt_main_oid="$(calc_oid "$(git cat-file -p "refs/heads/main:a.txt")")"
git lfs migrate import --everything
assert_pointer "refs/heads/main" "a.txt" "$txt_main_oid" "2"
assert_local_object "$txt_main_oid" "2"
git tag --points-at "$(git rev-parse HEAD)" | grep -q "v1.0.0"
)
end_test
begin_test "migrate import (annotated tags)"
(
set -e
setup_single_local_branch_with_annotated_tags
txt_main_oid="$(calc_oid "$(git cat-file -p "refs/heads/main:a.txt")")"
git lfs migrate import --everything
assert_pointer "refs/heads/main" "a.txt" "$txt_main_oid" "2"
assert_local_object "$txt_main_oid" "2"
git tag --points-at "$(git rev-parse HEAD)" | grep -q "v1.0.0"
)
end_test
begin_test "migrate import (include/exclude ref)"
(
set -e
setup_multiple_remote_branches
md_main_oid="$(calc_oid "$(git cat-file -p "refs/heads/main:a.md")")"
md_remote_oid="$(calc_oid "$(git cat-file -p "refs/remotes/origin/main:a.md")")"
md_feature_oid="$(calc_oid "$(git cat-file -p "refs/heads/my-feature:a.md")")"
txt_main_oid="$(calc_oid "$(git cat-file -p "refs/heads/main:a.txt")")"
txt_remote_oid="$(calc_oid "$(git cat-file -p "refs/remotes/origin/main:a.txt")")"
txt_feature_oid="$(calc_oid "$(git cat-file -p "refs/heads/my-feature:a.txt")")"
git lfs migrate import \
--include-ref=refs/heads/my-feature \
--exclude-ref=refs/heads/main
assert_pointer "refs/heads/my-feature" "a.md" "$md_feature_oid" "31"
assert_pointer "refs/heads/my-feature" "a.txt" "$txt_feature_oid" "30"
assert_local_object "$md_feature_oid" "31"
refute_local_object "$md_main_oid" "21"
assert_local_object "$txt_feature_oid" "30"
refute_local_object "$txt_main_oid" "20"
refute_local_object "$md_remote_oid" "11"
refute_local_object "$txt_remote_oid" "10"
main="$(git rev-parse refs/heads/main)"
feature="$(git rev-parse refs/heads/my-feature)"
remote="$(git rev-parse refs/remotes/origin/main)"
[ ! $(git cat-file -p "$main:.gitattributes") ]
[ ! $(git cat-file -p "$remote:.gitattributes") ]
feature_attrs="$(git cat-file -p "$feature:.gitattributes")"
echo "$feature_attrs" | grep -q "*.md filter=lfs diff=lfs merge=lfs"
echo "$feature_attrs" | grep -q "*.txt filter=lfs diff=lfs merge=lfs"
)
end_test
begin_test "migrate import (include/exclude ref args)"
(
set -e
setup_multiple_remote_branches
md_main_oid="$(calc_oid "$(git cat-file -p "refs/heads/main:a.md")")"
md_remote_oid="$(calc_oid "$(git cat-file -p "refs/remotes/origin/main:a.md")")"
md_feature_oid="$(calc_oid "$(git cat-file -p "refs/heads/my-feature:a.md")")"
txt_main_oid="$(calc_oid "$(git cat-file -p "refs/heads/main:a.txt")")"
txt_remote_oid="$(calc_oid "$(git cat-file -p "refs/remotes/origin/main:a.txt")")"
txt_feature_oid="$(calc_oid "$(git cat-file -p "refs/heads/my-feature:a.txt")")"
git lfs migrate import my-feature ^main
assert_pointer "refs/heads/my-feature" "a.md" "$md_feature_oid" "31"
assert_pointer "refs/heads/my-feature" "a.txt" "$txt_feature_oid" "30"
assert_local_object "$md_feature_oid" "31"
refute_local_object "$md_main_oid" "21"
assert_local_object "$txt_feature_oid" "30"
refute_local_object "$txt_main_oid" "20"
refute_local_object "$md_remote_oid" "11"
refute_local_object "$txt_remote_oid" "10"
main="$(git rev-parse refs/heads/main)"
feature="$(git rev-parse refs/heads/my-feature)"
remote="$(git rev-parse refs/remotes/origin/main)"
[ ! $(git cat-file -p "$main:.gitattributes") ]
[ ! $(git cat-file -p "$remote:.gitattributes") ]
feature_attrs="$(git cat-file -p "$feature:.gitattributes")"
echo "$feature_attrs" | grep -q "*.md filter=lfs diff=lfs merge=lfs"
echo "$feature_attrs" | grep -q "*.txt filter=lfs diff=lfs merge=lfs"
)
end_test
begin_test "migrate import (include/exclude ref with filter)"
(
set -e
setup_multiple_remote_branches
md_main_oid="$(calc_oid "$(git cat-file -p "refs/heads/main:a.md")")"
md_remote_oid="$(calc_oid "$(git cat-file -p "refs/remotes/origin/main:a.md")")"
md_feature_oid="$(calc_oid "$(git cat-file -p "refs/heads/my-feature:a.md")")"
txt_main_oid="$(calc_oid "$(git cat-file -p "refs/heads/main:a.txt")")"
txt_remote_oid="$(calc_oid "$(git cat-file -p "refs/remotes/origin/main:a.txt")")"
txt_feature_oid="$(calc_oid "$(git cat-file -p "refs/heads/my-feature:a.txt")")"
git lfs migrate import \
--include="*.txt" \
--include-ref=refs/heads/my-feature \
--exclude-ref=refs/heads/main
assert_pointer "refs/heads/my-feature" "a.txt" "$txt_feature_oid" "30"
refute_local_object "$md_feature_oid" "31"
refute_local_object "$md_main_oid" "21"
assert_local_object "$txt_feature_oid" "30"
refute_local_object "$txt_main_oid" "20"
refute_local_object "$md_remote_oid" "11"
refute_local_object "$txt_remote_oid" "10"
main="$(git rev-parse refs/heads/main)"
feature="$(git rev-parse refs/heads/my-feature)"
remote="$(git rev-parse refs/remotes/origin/main)"
[ ! $(git cat-file -p "$main:.gitattributes") ]
[ ! $(git cat-file -p "$remote:.gitattributes") ]
feature_attrs="$(git cat-file -p "$feature:.gitattributes")"
echo "$feature_attrs" | grep -vq "*.md filter=lfs diff=lfs merge=lfs"
echo "$feature_attrs" | grep -q "*.txt filter=lfs diff=lfs merge=lfs"
)
end_test
begin_test "migrate import (above)"
(
set -e
setup_single_local_branch_untracked
md_main_oid="$(calc_oid "$(git cat-file -p "refs/heads/main:a.md")")"
txt_main_oid="$(calc_oid "$(git cat-file -p "refs/heads/main:a.txt")")"
git lfs migrate import --above 121B
# Ensure that 'a.md', whose size is above our 121 byte threshold
# was converted into a git-lfs pointer by the migration.
assert_local_object "$md_main_oid" "140"
assert_pointer "refs/heads/main" "a.md" "$md_main_oid" "140"
refute_pointer "refs/heads/main" "a.txt" "$txt_main_oid" "120"
refute_local_object "$txt_main_oid" "120"
# The migration should have identified that *.md files are now
# tracked because it migrated a.md
main_attrs="$(git cat-file -p "$main:.gitattributes")"
echo "$main_attrs" | grep -q "/a.md filter=lfs diff=lfs merge=lfs"
echo "$main_attrs" | grep -vq "/a.txt filter=lfs diff=lfs merge=lfs"
git check-attr filter -- a.txt | grep -vq lfs
)
end_test
begin_test "migrate import (above without extension)"
(
set -e
setup_single_local_branch_untracked "just-b"
b_main_oid="$(calc_oid "$(git cat-file -p "refs/heads/main:just-b")")"
txt_main_oid="$(calc_oid "$(git cat-file -p "refs/heads/main:a.txt")")"
git lfs migrate import --above 121B
# Ensure that 'b', whose size is above our 121 byte threshold
# was converted into a git-lfs pointer by the migration.
assert_local_object "$b_main_oid" "140"
assert_pointer "refs/heads/main" "just-b" "$b_main_oid" "140"
refute_pointer "refs/heads/main" "a.txt" "$txt_main_oid" "120"
refute_local_object "$txt_main_oid" "120"
# The migration should have identified that /b is now tracked
# because it migrated it.
main_attrs="$(git cat-file -p "$main:.gitattributes")"
echo "$main_attrs" | grep -q "/just-b filter=lfs diff=lfs merge=lfs"
echo "$main_attrs" | grep -vq "/a.txt filter=lfs diff=lfs merge=lfs"
git check-attr filter -- a.txt | grep -vq lfs
)
end_test
begin_test "migrate import (above with multiple files)"
(
set -e
# It is important that this file sort after "a.txt".
setup_single_local_branch_untracked "b.txt"
a_main_oid="$(calc_oid "$(git cat-file -p "refs/heads/main:a.txt")")"
b_main_oid="$(calc_oid "$(git cat-file -p "refs/heads/main:b.txt")")"
git lfs migrate import --above 121B
# Ensure that 'a.md', whose size is above our 121 byte threshold
# was converted into a git-lfs pointer by the migration.
assert_local_object "$b_main_oid" "140"
assert_pointer "refs/heads/main" "b.txt" "$b_main_oid" "140"
refute_pointer "refs/heads/main" "a.txt" "$a_main_oid" "120"
refute_local_object "$a_main_oid" "120"
# The migration should have identified that *.md files are now
# tracked because it migrated a.md
main_attrs="$(git cat-file -p "$main:.gitattributes")"
echo "$main_attrs" | grep -q "/b.txt filter=lfs diff=lfs merge=lfs"
git check-attr filter -- a.txt | grep -vq lfs
)
end_test
begin_test "migrate import (above with include or exclude)"
(
set -e
setup_single_local_branch_untracked
md_main_oid="$(calc_oid "$(git cat-file -p "refs/heads/main:a.md")")"
txt_main_oid="$(calc_oid "$(git cat-file -p "refs/heads/main:a.txt")")"
git lfs migrate import --above 121B --include "*.md" && exit 1
git lfs migrate import --above 121B --exclude "*.txt" && exit 1
git lfs migrate import --above 121B --fixup && exit 1
true
)
end_test
begin_test "migrate import (existing .gitattributes)"
(
set -e
setup_local_branch_with_gitattrs
main="$(git rev-parse refs/heads/main)"
txt_main_oid="$(calc_oid "$(git cat-file -p "$main:a.txt")")"
git lfs migrate import --yes --include-ref=refs/heads/main --include="*.txt"
assert_local_object "$txt_main_oid" "120"
main="$(git rev-parse refs/heads/main)"
prev="$(git rev-parse refs/heads/main^1)"
diff -u <(git cat-file -p $main:.gitattributes) <(cat <<-EOF
*.txt filter=lfs diff=lfs merge=lfs -text
*.other filter=lfs diff=lfs merge=lfs -text
EOF)
diff -u <(git cat-file -p $prev:.gitattributes) <(cat <<-EOF
*.txt filter=lfs diff=lfs merge=lfs -text
EOF)
)
end_test
begin_test "migrate import (--exclude with existing .gitattributes)"
(
set -e
setup_local_branch_with_gitattrs
main="$(git rev-parse refs/heads/main)"
txt_main_oid="$(calc_oid "$(git cat-file -p "$main:a.txt")")"
git lfs migrate import --yes --include-ref=refs/heads/main --include="*.txt" --exclude="*.bin"
assert_local_object "$txt_main_oid" "120"
main="$(git rev-parse refs/heads/main)"
prev="$(git rev-parse refs/heads/main^1)"
diff -u <(git cat-file -p $main:.gitattributes) <(cat <<-EOF
*.txt filter=lfs diff=lfs merge=lfs -text
*.other filter=lfs diff=lfs merge=lfs -text
*.bin !text -filter -merge -diff
EOF)
diff -u <(git cat-file -p $prev:.gitattributes) <(cat <<-EOF
*.txt filter=lfs diff=lfs merge=lfs -text
*.bin !text -filter -merge -diff
EOF)
)
end_test
begin_test "migrate import (existing .gitattributes with different permissions)"
(
set -e
# Windows lacks POSIX permissions.
[ "$IS_WINDOWS" -eq 1 ] && exit 0
setup_local_branch_with_gitattrs 0755
main="$(git rev-parse refs/heads/main)"
txt_main_oid="$(calc_oid "$(git cat-file -p "$main:a.txt")")"
[ -x .gitattributes ]
git lfs migrate import --yes --include-ref=refs/heads/main --include="*.txt"
[ ! -x .gitattributes ]
assert_local_object "$txt_main_oid" "120"
main="$(git rev-parse refs/heads/main)"
prev="$(git rev-parse refs/heads/main^1)"
diff -u <(git cat-file -p $main:.gitattributes) <(cat <<-EOF
*.txt filter=lfs diff=lfs merge=lfs -text
*.other filter=lfs diff=lfs merge=lfs -text
EOF
)
diff -u <(git cat-file -p $prev:.gitattributes) <(cat <<-EOF
*.txt filter=lfs diff=lfs merge=lfs -text
EOF
)
attrs_main_sha="$(git show $main:.gitattributes | 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 $txt_main_sha a.txt
EOF
)
)
end_test
begin_test "migrate import (existing .gitattributes symlink)"
(
set -e
setup_local_branch_with_gitattrs link
git lfs migrate import --yes --include-ref=refs/heads/main --include="*.txt" 2>&1 | tee migrate.log
if [ ${PIPESTATUS[0]} -eq 0 ]; then
echo >&2 "fatal: expected git lfs migrate import to fail, didn't"
exit 1
fi
grep "migrate: expected '.gitattributes' to be a file, got a symbolic link" migrate.log
main="$(git rev-parse refs/heads/main)"
attrs_main_sha="$(git show $main:.gitattributes | git hash-object --stdin)"
diff -u <(git ls-tree $main -- .gitattributes) <(cat <<-EOF
120000 blob $attrs_main_sha .gitattributes
EOF
)
)
end_test
begin_test "migrate import (identical contents, different permissions)"
(
set -e
# Windows lacks POSIX permissions.
[ "$IS_WINDOWS" -eq 1 ] && exit 0
setup_multiple_local_branches
git checkout main
echo "foo" >foo.dat
git add .
git commit -m "add file"
chmod u+x foo.dat
git add .
git commit -m "make file executable"
# Verify we have executable permissions.
[ -x foo.dat ]
git lfs migrate import --everything --include="*.dat"
# Verify we have executable permissions.
[ -x foo.dat ]
)
end_test
begin_test "migrate import (tags with same name as branches)"
(
set -e
setup_multiple_local_branches
git checkout main
contents="hello"
oid=$(calc_oid "$contents")
printf "$contents" >hello.dat
git add .
git commit -m "add file"
git branch foo
git tag foo
git tag bar
git lfs migrate import --everything --include="*.dat"
[ "$(git rev-parse refs/heads/foo)" = "$(git rev-parse refs/tags/foo)" ]
[ "$(git rev-parse refs/heads/foo)" = "$(git rev-parse refs/tags/bar)" ]
assert_pointer "refs/heads/foo" hello.dat "$oid" 5
)
end_test
begin_test "migrate import (bare repository)"
(
set -e
setup_multiple_local_branches
make_bare
git lfs migrate import \
--include-ref=main
)
end_test
begin_test "migrate import (nested sub-trees, no filter)"
(
set -e
setup_single_local_branch_deep_trees
oid="$(calc_oid "$(git cat-file -p :foo/bar/baz/a.txt)")"
size="$(git cat-file -p :foo/bar/baz/a.txt | wc -c | awk '{ print $1 }')"
git lfs migrate import --everything
assert_local_object "$oid" "$size"
)
end_test
begin_test "migrate import (prefix include(s))"
(
set -e
includes="foo/bar/baz/** foo/**/baz/a.txt *.txt"
for include in $includes; do
setup_single_local_branch_deep_trees
oid="$(calc_oid "$(git cat-file -p :foo/bar/baz/a.txt)")"
git lfs migrate import --include="$include"
assert_local_object "$oid" 120
cd ..
done
)
end_test
begin_test "migrate import (--everything)"
(
set -e
setup_multiple_local_branches
git checkout main
main_txt_oid="$(calc_oid "$(git cat-file -p :a.txt)")"
main_md_oid="$(calc_oid "$(git cat-file -p :a.md)")"
feature_md_oid="$(calc_oid "$(git cat-file -p my-feature:a.md)")"
main_txt_size="$(git cat-file -p :a.txt | wc -c | awk '{ print $1 }')"
main_md_size="$(git cat-file -p :a.md | wc -c | awk '{ print $1 }')"
feature_md_size="$(git cat-file -p my-feature:a.md | wc -c | awk '{ print $1 }')"
git lfs migrate import --everything
assert_pointer "main" "a.txt" "$main_txt_oid" "$main_txt_size"
assert_pointer "main" "a.md" "$main_md_oid" "$main_md_size"
assert_pointer "my-feature" "a.md" "$feature_md_oid" "$feature_md_size"
)
end_test
begin_test "migrate import (ambiguous reference)"
(
set -e
setup_multiple_local_branches
# Create an ambiguously named reference sharing the name as the SHA-1 of
# "HEAD".
sha="$(git rev-parse HEAD)"
git tag "$sha"
git lfs migrate import --everything
)
end_test
begin_test "migrate import (--everything with args)"
(
set -e
setup_multiple_local_branches
[ "$(git lfs migrate import --everything main 2>&1)" = \
"Cannot use --everything with explicit reference arguments" ]
)
end_test
begin_test "migrate import (--everything with --include-ref)"
(
set -e
setup_multiple_local_branches
[ "$(git lfs migrate import --everything --include-ref=refs/heads/main 2>&1)" = \
"Cannot use --everything with --include-ref or --exclude-ref" ]
)
end_test
begin_test "migrate import (--everything with --exclude-ref)"
(
set -e
setup_multiple_local_branches
[ "$(git lfs migrate import --everything --exclude-ref=refs/heads/main 2>&1)" = \
"Cannot use --everything with --include-ref or --exclude-ref" ]
)
end_test
begin_test "migrate import (--everything and --include with glob pattern)"
(
set -e
setup_multiple_local_branches
md_main_oid="$(calc_oid "$(git cat-file -p "refs/heads/main:a.md")")"
txt_main_oid="$(calc_oid "$(git cat-file -p "refs/heads/main:a.txt")")"
md_feature_oid="$(calc_oid "$(git cat-file -p "refs/heads/my-feature:a.md")")"
txt_feature_oid="$(calc_oid "$(git cat-file -p "refs/heads/my-feature:a.txt")")"
git lfs migrate import --verbose --everything --include='*.[mM][dD]'
assert_pointer "refs/heads/main" "a.md" "$md_main_oid" "140"
assert_pointer "refs/heads/my-feature" "a.md" "$md_feature_oid" "30"
assert_local_object "$md_main_oid" "140"
assert_local_object "$md_feature_oid" "30"
refute_local_object "$txt_main_oid"
refute_local_object "$txt_feature_oid"
)
end_test
begin_test "migrate import (--everything with tag pointing to tag)"
(
set -e
setup_multiple_local_branches
md_main_oid="$(calc_oid "$(git cat-file -p "refs/heads/main:a.md")")"
txt_main_oid="$(calc_oid "$(git cat-file -p "refs/heads/main:a.txt")")"
md_feature_oid="$(calc_oid "$(git cat-file -p "refs/heads/my-feature:a.md")")"
txt_feature_oid="$(calc_oid "$(git cat-file -p "refs/heads/my-feature:a.txt")")"
git tag -a -m abc abc refs/heads/main
git tag -a -m def def refs/tags/abc
git lfs migrate import --verbose --everything --include='*.[mM][dD]'
assert_pointer "refs/heads/main" "a.md" "$md_main_oid" "140"
assert_pointer "refs/tags/abc" "a.md" "$md_main_oid" "140"
assert_pointer "refs/tags/def" "a.md" "$md_main_oid" "140"
assert_pointer "refs/heads/my-feature" "a.md" "$md_feature_oid" "30"
git tag --points-at refs/tags/abc | grep -q def
git tag --points-at refs/tags/def | grep -q abc && exit 1
assert_local_object "$md_main_oid" "140"
assert_local_object "$md_feature_oid" "30"
refute_local_object "$txt_main_oid"
refute_local_object "$txt_feature_oid"
)
end_test
begin_test "migrate import (nested sub-trees and --include with wildcard)"
(
set -e
setup_single_local_branch_deep_trees
oid="$(calc_oid "$(git cat-file -p :foo/bar/baz/a.txt)")"
size="$(git cat-file -p :foo/bar/baz/a.txt | wc -c | awk '{ print $1 }')"
git lfs migrate import --include="**/*ar/**"
assert_pointer "refs/heads/main" "foo/bar/baz/a.txt" "$oid" "$size"
assert_local_object "$oid" "$size"
)
end_test
begin_test "migrate import (handle copies of files)"
(
set -e
setup_single_local_branch_deep_trees
# add the object from the sub-tree to the root directory
cp foo/bar/baz/a.txt a.txt
git add a.txt
git commit -m "duplicated file"
oid_root="$(calc_oid "$(git cat-file -p :a.txt)")"
oid_tree="$(calc_oid "$(git cat-file -p :foo/bar/baz/a.txt)")"
size="$(git cat-file -p :foo/bar/baz/a.txt | wc -c | awk '{ print $1 }')"
# only import objects under "foo"
git lfs migrate import --include="foo/**"
assert_pointer "refs/heads/main" "foo/bar/baz/a.txt" "$oid_tree" "$size"
assert_local_object "$oid_tree" "$size"
# "a.txt" is not under "foo" and therefore should not be in LFS
oid_root_after_migration="$(calc_oid "$(git cat-file -p :a.txt)")"
[ "$oid_root" = "$oid_root_after_migration" ]
)
end_test
begin_test "migrate import (filter matches files only)"
(
set -e
setup_single_local_branch_same_file_tree_ext
txt_root_oid="$(calc_oid "$(git cat-file -p :a.txt)")"
txt_foo_oid="$(calc_oid "$(git cat-file -p :foo/a.txt)")"
md_bar_oid="$(calc_oid "$(git cat-file -p :bar.txt/b.md)")"
txt_bar_oid="$(calc_oid "$(git cat-file -p :bar.txt/b.txt)")"
git lfs migrate import --include="*.txt"
assert_local_object "$txt_root_oid" "120"
assert_local_object "$txt_foo_oid" "120"
assert_local_object "$txt_bar_oid" "120"
refute_local_object "$md_bar_oid"
)
end_test
begin_test "migrate import (--object-map)"
(
set -e
setup_multiple_local_branches
output_dir=$(mktemp -d)
git log --all --pretty='format:%H' > "${output_dir}/old_sha.txt"
git lfs migrate import --everything --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 import (--include with space)"
(
set -e
setup_local_branch_with_space
oid="$(calc_oid "$(git cat-file -p :"a file.txt")")"
git lfs migrate import --include "a file.txt"
assert_pointer "refs/heads/main" "a file.txt" "$oid" 50
cat .gitattributes
if [ 1 -ne "$(grep -c "a\[\[:space:\]\]file.txt" .gitattributes)" ]; then
echo >&2 "fatal: expected \"a[[:space:]]file.txt\" to appear in .gitattributes"
echo >&2 "fatal: got"
sed -e 's/^/ /g' < .gitattributes >&2
exit 1
fi
)
end_test
begin_test "migrate import (handle symbolic link)"
(
set -e
setup_local_branch_with_symlink
txt_oid="$(calc_oid "$(git cat-file -p :a.txt)")"
link_oid="$(calc_oid "$(git cat-file -p :link.txt)")"
git lfs migrate import --include="*.txt"
assert_pointer "refs/heads/main" "a.txt" "$txt_oid" "120"
assert_local_object "$txt_oid" "120"
# "link.txt" is a symbolic link so it should be not in LFS
refute_local_object "$link_oid" "5"
)
end_test
begin_test "migrate import (commit --allow-empty)"
(
set -e
reponame="migrate---allow-empty"
git init "$reponame"
cd "$reponame"
git commit --allow-empty -m "initial commit"
original_head="$(git rev-parse HEAD)"
git lfs migrate import --everything
migrated_head="$(git rev-parse HEAD)"
assert_ref_unmoved "HEAD" "$original_head" "$migrated_head"
)
end_test
begin_test "migrate import (multiple remotes)"
(
set -e
setup_multiple_remotes
original_main="$(git rev-parse main)"
git lfs migrate import
migrated_main="$(git rev-parse main)"
assert_ref_unmoved "main" "$original_main" "$migrated_main"
)
end_test
begin_test "migrate import (dirty copy, default negative answer)"
(
set -e
setup_local_branch_with_dirty_copy
original_main="$(git rev-parse main)"
echo | git lfs migrate import --everything 2>&1 | tee migrate.log
grep "migrate: working copy must not be dirty" migrate.log
migrated_main="$(git rev-parse main)"
assert_ref_unmoved "main" "$original_main" "$migrated_main"
)
end_test
begin_test "migrate import (dirty copy, negative answer)"
(
set -e
setup_local_branch_with_dirty_copy
original_main="$(git rev-parse main)"
echo "n" | git lfs migrate import --everything 2>&1 | tee migrate.log
grep "migrate: working copy must not be dirty" migrate.log
migrated_main="$(git rev-parse main)"
assert_ref_unmoved "main" "$original_main" "$migrated_main"
)
end_test
begin_test "migrate import (dirty copy, unknown then negative answer)"
(
set -e
setup_local_branch_with_dirty_copy
original_main="$(git rev-parse main)"
echo "x\nn" | git lfs migrate import --everything 2>&1 | tee migrate.log
cat migrate.log
[ "2" -eq "$(grep -o "override changes in your working copy" migrate.log \
| wc -l | awk '{ print $1 }')" ]
grep "migrate: working copy must not be dirty" migrate.log
migrated_main="$(git rev-parse main)"
assert_ref_unmoved "main" "$original_main" "$migrated_main"
)
end_test
begin_test "migrate import (dirty copy, positive answer)"
(
set -e
setup_local_branch_with_dirty_copy
oid="$(calc_oid "$(git cat-file -p :a.txt)")"
echo "y" | git lfs migrate import --everything 2>&1 | tee migrate.log
grep "migrate: changes in your working copy will be overridden ..." \
migrate.log
assert_pointer "refs/heads/main" "a.txt" "$oid" "5"
assert_local_object "$oid" "5"
)
end_test
begin_test "migrate import (non-standard refs)"
(
set -e
setup_multiple_local_branches_non_standard
md_oid="$(calc_oid "$(git cat-file -p :a.md)")"
txt_oid="$(calc_oid "$(git cat-file -p :a.txt)")"
md_feature_oid="$(calc_oid "$(git cat-file -p my-feature:a.md)")"
git lfs migrate import --everything
assert_pointer "refs/heads/main" "a.md" "$md_oid" "140"
assert_pointer "refs/heads/main" "a.txt" "$txt_oid" "120"
assert_pointer "refs/pull/1/base" "a.md" "$md_oid" "140"
assert_pointer "refs/pull/1/base" "a.txt" "$txt_oid" "120"
assert_pointer "refs/heads/my-feature" "a.txt" "$txt_oid" "120"
assert_pointer "refs/pull/1/head" "a.txt" "$txt_oid" "120"
assert_local_object "$md_oid" "140"
assert_local_object "$txt_oid" "120"
assert_local_object "$md_feature_oid" "30"
)
end_test
begin_test "migrate import (copied file)"
(
set -e
setup_local_branch_with_copied_file
git lfs migrate import --above=1b
# Expect attributes for "/dir/a" and "/a"
if ! grep -q "^/dir/a.txt" ./.gitattributes || ! grep -q "^/a.txt" ./.gitattributes; then
exit 1
fi
)
end_test
begin_test "migrate import (copied file with only a single path)"
(
set -e
setup_local_branch_with_copied_file
oid="$(calc_oid "$(git cat-file -p :a.txt)")"
# Prevent MSYS from rewriting /a.txt into a Windows path.
MSYS_NO_PATHCONV=1 git lfs migrate import --include="/a.txt" --everything
# Expect attribute for only "/a.txt".
if grep -q "^/dir/a.txt" ./.gitattributes || ! grep -q "^/a.txt" ./.gitattributes; then
exit 1
fi
refute_pointer "refs/heads/main" "dir/a.txt" "$oid" 5
)
end_test
begin_test "migrate import (filename special characters)"
(
set -e
setup_local_branch_with_special_character_files
git lfs migrate import --above=1b
# Windows does not allow creation of files with '*', so expect 2 files, not 3
if [ "$IS_WINDOWS" -eq "1" ] ; then
test "$(git check-attr filter -- *.bin |grep lfs | wc -l)" -eq 2 || exit 1
else
test "$(git check-attr filter -- *.bin |grep lfs | wc -l)" -eq 3 || exit 1
fi
)
end_test