commands/fsck: allow scanning revision ranges
Currently, git lfs fsck operates only on the HEAD and index. For objects, this is usually the right decision, since only objects for HEAD are checked out. However, for pointers, this may not be desired. A user may want to check pointers for a range of commits, such as during a CI job. To deal with these cases, let a user specify a revision or a simple range of revisions to operate on, and process those revisions. Note that we don't currently process the index with --pointers because this requires a completely different set of scanners which are not yet implemented. We can implement such a feature in a future revision if desired. In the tests, refactor out our setup code into a function for reuse in multiple tests.
This commit is contained in:
parent
cca4977b23
commit
e6c9d1de19
@ -7,6 +7,7 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/git-lfs/git-lfs/errors"
|
||||
"github.com/git-lfs/git-lfs/filepathfilter"
|
||||
@ -45,9 +46,30 @@ func fsckCommand(cmd *cobra.Command, args []string) {
|
||||
installHooks(false)
|
||||
setupRepository()
|
||||
|
||||
ref, err := git.CurrentRef()
|
||||
if err != nil {
|
||||
ExitWithError(err)
|
||||
useIndex := false
|
||||
start := ""
|
||||
end := "HEAD"
|
||||
|
||||
switch len(args) {
|
||||
case 0:
|
||||
useIndex = true
|
||||
ref, err := git.CurrentRef()
|
||||
if err != nil {
|
||||
ExitWithError(err)
|
||||
}
|
||||
end = ref.Sha
|
||||
case 1:
|
||||
pieces := strings.SplitN(args[0], "..", 2)
|
||||
refs, err := git.ResolveRefs(pieces)
|
||||
if err != nil {
|
||||
ExitWithError(err)
|
||||
}
|
||||
if len(refs) == 2 {
|
||||
start = refs[0].Sha
|
||||
end = refs[1].Sha
|
||||
} else {
|
||||
end = refs[0].Sha
|
||||
}
|
||||
}
|
||||
|
||||
if !fsckPointers && !fsckObjects {
|
||||
@ -93,7 +115,7 @@ func fsckCommand(cmd *cobra.Command, args []string) {
|
||||
}
|
||||
|
||||
// doFsckObjects checks that the objects in the given ref are correct and exist.
|
||||
func doFsckObjects(ref *git.Ref) []string {
|
||||
func doFsckObjects(start, end string, useIndex bool) []string {
|
||||
var corruptOids []string
|
||||
gitscanner := lfs.NewGitScanner(cfg, func(p *lfs.WrappedPointer, err error) {
|
||||
if err == nil {
|
||||
@ -116,12 +138,20 @@ func doFsckObjects(ref *git.Ref) []string {
|
||||
// Attach a filepathfilter to avoid _only_ the excluded paths.
|
||||
gitscanner.Filter = filepathfilter.New(nil, cfg.FetchExcludePaths())
|
||||
|
||||
if err := gitscanner.ScanRef(ref.Sha, nil); err != nil {
|
||||
ExitWithError(err)
|
||||
if start == "" {
|
||||
if err := gitscanner.ScanRef(end, nil); err != nil {
|
||||
ExitWithError(err)
|
||||
}
|
||||
} else {
|
||||
if err := gitscanner.ScanRefRange(start, end, nil); err != nil {
|
||||
ExitWithError(err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := gitscanner.ScanIndex("HEAD", nil); err != nil {
|
||||
ExitWithError(err)
|
||||
if useIndex {
|
||||
if err := gitscanner.ScanIndex("HEAD", nil); err != nil {
|
||||
ExitWithError(err)
|
||||
}
|
||||
}
|
||||
|
||||
gitscanner.Close()
|
||||
@ -161,8 +191,14 @@ func doFsckPointers(start, end string) []corruptPointer {
|
||||
}
|
||||
})
|
||||
|
||||
if err := gitscanner.ScanRefByTree(ref.Sha, nil); err != nil {
|
||||
ExitWithError(err)
|
||||
if start == "" {
|
||||
if err := gitscanner.ScanRefByTree(end, nil); err != nil {
|
||||
ExitWithError(err)
|
||||
}
|
||||
} else {
|
||||
if err := gitscanner.ScanRefRangeByTree(start, end, nil); err != nil {
|
||||
ExitWithError(err)
|
||||
}
|
||||
}
|
||||
|
||||
gitscanner.Close()
|
||||
|
@ -3,7 +3,7 @@ git-lfs-fsck(1) -- Check GIT LFS files for consistency
|
||||
|
||||
## SYNOPSIS
|
||||
|
||||
`git lfs fsck` [options]
|
||||
`git lfs fsck` [options] [revisions]
|
||||
|
||||
## DESCRIPTION
|
||||
|
||||
|
@ -140,6 +140,20 @@ func (s *GitScanner) ScanRefRange(left, right string, cb GitScannerFoundPointer)
|
||||
return scanLeftRightToChan(s, callback, left, right, s.cfg.GitEnv(), s.cfg.OSEnv(), opts)
|
||||
}
|
||||
|
||||
// ScanRefRangeByTree scans through all trees from the given left and right
|
||||
// refs.
|
||||
func (s *GitScanner) ScanRefRangeByTree(left, right string, cb GitScannerFoundPointer) error {
|
||||
callback, err := firstGitScannerCallback(cb, s.FoundPointer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
opts := s.opts(ScanRefsMode)
|
||||
opts.SkipDeletedBlobs = false
|
||||
opts.CommitsOnly = true
|
||||
return scanRefsByTree(s, callback, []string{right}, []string{left}, s.cfg.GitEnv(), s.cfg.OSEnv(), opts)
|
||||
}
|
||||
|
||||
// ScanRefWithDeleted scans through all objects in the given ref, including
|
||||
// git objects that have been modified or deleted.
|
||||
func (s *GitScanner) ScanRefWithDeleted(ref string, cb GitScannerFoundPointer) error {
|
||||
|
44
t/t-fsck.sh
44
t/t-fsck.sh
@ -138,11 +138,7 @@ begin_test "fsck: outside git repository"
|
||||
)
|
||||
end_test
|
||||
|
||||
begin_test "fsck detects invalid pointers"
|
||||
(
|
||||
set -e
|
||||
|
||||
reponame="fsck-pointers"
|
||||
setup_invalid_pointers () {
|
||||
git init $reponame
|
||||
cd $reponame
|
||||
|
||||
@ -151,6 +147,7 @@ begin_test "fsck detects invalid pointers"
|
||||
echo "test data" > a.dat
|
||||
echo "test data 2" > b.dat
|
||||
git add .gitattributes *.dat
|
||||
git commit -m "first commit"
|
||||
|
||||
git cat-file blob :a.dat | awk '{ sub(/$/, "\r"); print }' >crlf.dat
|
||||
base64 /dev/urandom | head -c 1025 > large.dat
|
||||
@ -158,8 +155,16 @@ begin_test "fsck detects invalid pointers"
|
||||
-c "filter.lfs.process=" \
|
||||
-c "filter.lfs.clean=cat" \
|
||||
-c "filter.lfs.required=false" \
|
||||
add *.dat
|
||||
git commit -m "first commit"
|
||||
add crlf.dat large.dat
|
||||
git commit -m "second commit"
|
||||
}
|
||||
|
||||
begin_test "fsck detects invalid pointers"
|
||||
(
|
||||
set -e
|
||||
|
||||
reponame="fsck-pointers"
|
||||
setup_invalid_pointers
|
||||
|
||||
set +e
|
||||
git lfs fsck >test.log 2>&1
|
||||
@ -174,3 +179,28 @@ begin_test "fsck detects invalid pointers"
|
||||
[ $(grep -c 'pointer: unexpectedGitObject: "large.dat".*should have been a pointer but was not' test.log) -eq 2 ]
|
||||
)
|
||||
end_test
|
||||
|
||||
begin_test "fsck operates on specified refs"
|
||||
(
|
||||
set -e
|
||||
|
||||
reponame="fsck-refs"
|
||||
setup_invalid_pointers
|
||||
|
||||
git rm -f crlf.dat large.dat
|
||||
git commit -m 'third commit'
|
||||
|
||||
git commit --allow-empty -m 'fourth commit'
|
||||
|
||||
# Should succeed. (HEAD and index).
|
||||
git lfs fsck
|
||||
git lfs fsck HEAD
|
||||
git lfs fsck HEAD^^ && exit 1
|
||||
git lfs fsck HEAD^
|
||||
git lfs fsck HEAD^..HEAD
|
||||
git lfs fsck HEAD^^^..HEAD && exit 1
|
||||
git lfs fsck HEAD^^^..HEAD^ && exit 1
|
||||
# Make the result of the subshell a success.
|
||||
true
|
||||
)
|
||||
end_test
|
||||
|
Loading…
Reference in New Issue
Block a user