git-lfs/t/t-status.sh
Taylor Blau 934ae52066 commands/command_status.go: require a working copy
'git lfs status' is functional in a non-work tree repository only some
of the time. Particularly, when there is nothing to report (and
therefore no files to open), 'git lfs status' work as expected.

However, when there are files changed in the index, Git LFS tries to
open them to see what their hash was before/after the change, and in
particular, if they are/were/remain Git LFS pointers. This feature is
used to power the "Git <sha-1> -> LFS <sha-256>" output of 'git lfs
status'.

When in a bare repository and in the aforementioned scenario, the above
operation will fail to open a file that does not exist, for the
repository is bare and thus does not contain a working tree.

In order to bring about a more consistent experience when using 'git lfs
status', let's match the behavior upstream and exit immediately with the
message:

    $ git lfs status
    This operation must be run in a work tree.
2018-11-13 10:33:48 -08:00

467 lines
9.6 KiB
Bash
Executable File

#!/usr/bin/env bash
. "$(dirname "$0")/testlib.sh"
begin_test "status"
(
set -e
mkdir repo-1
cd repo-1
git init
git lfs track "*.dat"
file_1="some data"
file_1_oid="$(calc_oid "$file_1")"
file_1_oid_short="$(echo "$file_1_oid" | head -c 7)"
printf "%s" "$file_1" > file1.dat
git add file1.dat
git commit -m "file1.dat"
file_1_new="other data"
file_1_new_oid="$(calc_oid "$file_1_new")"
file_1_new_oid_short="$(echo "$file_1_new_oid" | head -c 7)"
printf "%s" "$file_1_new" > file1.dat
file_2="file2 data"
file_2_oid="$(calc_oid "$file_2")"
file_2_oid_short="$(echo "$file_2_oid" | head -c 7)"
printf "%s" "$file_2" > file2.dat
git add file2.dat
file_3="file3 data"
file_3_oid="$(calc_oid "$file_3")"
file_3_oid_short="$(echo "$file_3_oid" | head -c 7)"
printf "%s" "$file_3" > file3.dat
git add file3.dat
file_3_new="file3 other data"
file_3_new_oid="$(calc_oid "$file_3_new")"
file_3_new_oid_short="$(echo "$file_3_new_oid" | head -c 7)"
printf "%s" "$file_3_new" > file3.dat
expected="On branch master
Git LFS objects to be committed:
file2.dat (LFS: $file_2_oid_short)
file3.dat (LFS: $file_3_oid_short)
Git LFS objects not staged for commit:
file1.dat (LFS: $file_1_oid_short -> File: $file_1_new_oid_short)
file3.dat (File: $file_3_new_oid_short)"
[ "$expected" = "$(git lfs status)" ]
)
end_test
begin_test "status --porcelain"
(
set -e
mkdir repo-2
cd repo-2
git init
git lfs track "*.dat"
echo "some data" > file1.dat
git add file1.dat
git commit -m "file1.dat"
echo "other data" > file1.dat
echo "file2 data" > file2.dat
git add file2.dat
echo "file3 data" > file3.dat
git add file3.dat
echo "file3 other data" > file3.dat
expected=" M file1.dat
A file3.dat
A file2.dat"
[ "$expected" = "$(git lfs status --porcelain)" ]
)
end_test
begin_test "status --json"
(
set -e
mkdir repo-3
cd repo-3
git init
git lfs track "*.dat"
echo "some data" > file1.dat
git add file1.dat
git commit -m "file1.dat"
echo "other data" > file1.dat
expected='{"files":{"file1.dat":{"status":"M"}}}'
[ "$expected" = "$(git lfs status --json)" ]
git add file1.dat
git commit -m "file1.dat changed"
git mv file1.dat file2.dat
expected='{"files":{"file2.dat":{"status":"R","from":"file1.dat"}}}'
[ "$expected" = "$(git lfs status --json)" ]
git commit -m "file1.dat -> file2.dat"
# Ensure status --json does not include non-lfs files
echo hi > test1.txt
git add test1.txt
expected='{"files":{}}'
[ "$expected" = "$(git lfs status --json)" ]
)
end_test
begin_test "status in a sub-directory"
(
set -e
reponame="status-sub-directory"
git init "$reponame"
cd "$reponame"
git lfs track "*.dat"
printf "asdf" > file.dat
mkdir -p dir
git add .gitattributes file.dat
git commit -m "initial commit"
printf "ASDF" > file.dat
expected="On branch master
Git LFS objects to be committed:
Git LFS objects not staged for commit:
../file.dat (LFS: f0e4c2f -> File: 99b3bcf)"
[ "$expected" = "$(cd dir && git lfs status)" ]
)
end_test
begin_test "status: outside git repository"
(
set +e
git lfs status 2>&1 > status.log
res=$?
set -e
if [ "$res" = "0" ]; then
echo "Passes because $GIT_LFS_TEST_DIR is unset."
exit 0
fi
[ "$res" = "128" ]
grep "Not in a git repository" status.log
)
end_test
begin_test "status - before initial commit"
(
set -e
git init repo-initial
cd repo-initial
git lfs track "*.dat"
# should not fail when nothing to display (ignore output, will be blank)
git lfs status
contents="some data"
contents_oid="$(calc_oid "$contents")"
contents_oid_short="$(echo "$contents_oid" | head -c 7)"
printf "%s" "$contents" > file1.dat
git add file1.dat
expected="
Git LFS objects to be committed:
file1.dat (LFS: $contents_oid_short)
Git LFS objects not staged for commit:"
[ "$expected" = "$(git lfs status)" ]
)
end_test
begin_test "status shows multiple files with identical contents"
(
set -e
reponame="uniq-status"
mkdir "$reponame"
cd "$reponame"
git init
git lfs track "*.dat"
contents="contents"
printf "%s" "$contents" > a.dat
printf "%s" "$contents" > b.dat
git add --all .
git lfs status | tee status.log
[ "1" -eq "$(grep -c "a.dat" status.log)" ]
[ "1" -eq "$(grep -c "b.dat" status.log)" ]
)
end_test
begin_test "status shows multiple copies of partially staged files"
(
set -e
reponame="status-partially-staged"
git init "$reponame"
cd "$reponame"
git lfs track "*.dat"
git add .gitattributes
git commit -m "initial commit"
contents_1="part 1"
contents_1_oid="$(calc_oid "$contents_1")"
contents_1_oid_short="$(echo "$contents_1_oid" | head -c 7)"
printf "%s" "$contents_1" > a.dat
# "$contents_1" changes are staged
git add a.dat
# "$contents_2" changes are unstaged
contents_2="part 2"
contents_2_oid="$(calc_oid "$contents_2")"
contents_2_oid_short="$(echo "$contents_2_oid" | head -c 7)"
printf "%s" "$contents_2" > a.dat
expected="On branch master
Git LFS objects to be committed:
a.dat (LFS: $contents_1_oid_short)
Git LFS objects not staged for commit:
a.dat (File: $contents_2_oid_short)"
actual="$(git lfs status)"
diff -u <(echo "$expected") <(echo "$actual")
)
end_test
begin_test "status: LFS to LFS change"
(
set -e
reponame="status-lfs-to-lfs-change"
setup_remote_repo "$reponame"
clone_repo "$reponame" "$reponame"
contents="contents"
contents_oid="$(calc_oid "$contents")"
contents_oid_short="$(echo "$contents_oid" | head -c 7)"
git lfs track "*.dat"
git add .gitattributes
git commit -m "track *.dat files"
printf "%s" "$contents" > a.dat
git add a.dat
git commit -m "add a.dat"
contents_new="$contents +extra"
contents_new_oid="$(calc_oid "$contents_new")"
contents_new_oid_short="$(echo $contents_new_oid | head -c 7)"
printf "%s" "$contents_new" > a.dat
git add a.dat
expected="On branch master
Git LFS objects to be committed:
a.dat (LFS: $contents_oid_short -> LFS: $contents_new_oid_short)
Git LFS objects not staged for commit:"
actual="$(git lfs status)"
[ "$expected" = "$actual" ]
)
end_test
begin_test "status: Git to LFS change"
(
set -e
reponame="status-git-to-lfs-change"
setup_remote_repo "$reponame"
clone_repo "$reponame" "$reponame"
contents="contents"
contents_oid="$(calc_oid "$contents")"
contents_oid_short="$(echo "$contents_oid" | head -c 7)"
printf "%s" "$contents" > a.dat
git add a.dat
git commit -m "add a.dat"
git lfs track "*.dat"
git add .gitattributes
git commit -m "track *.dat files"
contents_new="$contents +extra"
contents_new_oid="$(calc_oid "$contents_new")"
contents_new_oid_short="$(echo $contents_new_oid | head -c 7)"
printf "%s" "$contents_new" > a.dat
git add a.dat
expected="On branch master
Git LFS objects to be committed:
a.dat (Git: $contents_oid_short -> LFS: $contents_new_oid_short)
Git LFS objects not staged for commit:"
actual="$(git lfs status)"
[ "$expected" = "$actual" ]
)
end_test
begin_test "status: Git to LFS conversion"
(
set -e
reponame="status-git-to-lfs-conversion"
setup_remote_repo "$reponame"
clone_repo "$reponame" "$reponame"
contents="contents"
contents_oid="$(calc_oid "$contents")"
contents_oid_short="$(echo "$contents_oid" | head -c 7)"
printf "%s" "$contents" > a.dat
git add a.dat
git commit -m "add a.dat"
git lfs track "*.dat"
git add .gitattributes
git commit -m "track *.dat"
git push origin master
pushd "$TRASHDIR" > /dev/null
clone_repo "$reponame" "$reponame-2"
git add a.dat
git lfs status 2>&1 | tee status.log
if [ "0" -ne "${PIPESTATUS[0]}" ]; then
echo >&2 "git lfs status should have succeeded, didn't ..."
exit 1
fi
expected="On branch master
Git LFS objects to be pushed to origin/master:
Git LFS objects to be committed:
a.dat (Git: $contents_oid_short -> LFS: $contents_oid_short)
Git LFS objects not staged for commit:"
actual="$(cat status.log)"
[ "$expected" = "$actual" ]
popd > /dev/null
)
end_test
begin_test "status (missing objects)"
(
set -e
reponame="status-missing-objects"
git init "$reponame"
cd "$reponame"
git lfs track "*.dat"
printf "a" > a.dat
git add .gitattributes a.dat
git commit -m "initial commit"
# Remove the original object "a.dat" (ensure '--no-filters' is not given).
oid="$(git hash-object -t blob -- a.dat)"
rm -rf ".git/objects/${oid:0:2}/${oid:2}"
# Create an unstaged change against a source file that doesn't exist.
printf "b" > a.dat
git add a.dat
git lfs status \
| grep "a.dat (?: <missing> -> LFS: $(calc_oid b | head -c 7))"
)
end_test
begin_test "status (unpushed objects)"
(
set -e
reponame="status-unpushed-objects"
setup_remote_repo "$reponame"
clone_repo "$reponame" "$reponame"
git lfs track "*.dat"
git add .gitattributes
git commit -m "initial commit"
git push origin master
contents="a"
oid="$(calc_oid "$contents")"
printf "%s" "$contents" > a.dat
git add a.dat
git commit -m "add a large file"
expected="On branch master
Git LFS objects to be pushed to origin/master:
a.dat ($oid)
Git LFS objects to be committed:
Git LFS objects not staged for commit:"
[ "$expected" = "$(git lfs status)" ]
)
end_test
begin_test "status (without a working copy)"
(
reponame="status-no-working-copy.git"
git init --bare "$reponame"
cd "$reponame"
git lfs status 2>&1 | tee status.log
if [ "0" -eq "${PIPESTATUS[0]}" ]; then
echo >&2 "git lfs status should have failed, didn't ..."
exit 1
fi
[ "This operation must be run in a work tree." = "$(cat status.log)" ]
)
end_test