git-lfs/commands/command_ls_files.go
brian m. carlson 0245ce5aa6
commands: don't honor lfs.fetch* for ls-files
Currently, if a user runs git lfs ls-files with lfs.fetchexclude set to
*, then all files are excluded from the output.  This doesn't make much
sense, since the lfs.fetchinclude and lfs.fetchexclude options are
documented to work only on fetches.  Let's ensure that we don't load the
fetch filters by default when performing a non-fetch operation so that
git lfs ls-files isn't affected by these exclusions.
2020-03-31 13:55:24 +00:00

168 lines
4.1 KiB
Go

package commands
import (
"os"
"strings"
"github.com/git-lfs/git-lfs/git"
"github.com/git-lfs/git-lfs/lfs"
"github.com/git-lfs/git-lfs/tools/humanize"
"github.com/spf13/cobra"
)
var (
longOIDs = false
lsFilesScanAll = false
lsFilesScanDeleted = false
lsFilesShowSize = false
lsFilesShowNameOnly = false
debug = false
)
func lsFilesCommand(cmd *cobra.Command, args []string) {
requireInRepo()
var ref string
var otherRef string
var scanRange = false
if len(args) > 0 {
if lsFilesScanAll {
Exit("fatal: cannot use --all with explicit reference")
} else if args[0] == "--all" {
// Since --all is a valid argument to "git rev-parse",
// if we try to give it to git.ResolveRef below, we'll
// get an unexpected result.
//
// So, let's check early that the caller invoked the
// command correctly.
Exit("fatal: did you mean \"git lfs ls-files --all --\" ?")
}
ref = args[0]
if len(args) > 1 {
if lsFilesScanDeleted {
Exit("fatal: cannot use --deleted with reference range")
}
otherRef = args[1]
scanRange = true
}
} else {
fullref, err := git.CurrentRef()
if err != nil {
ref = git.RefBeforeFirstCommit
} else {
ref = fullref.Sha
}
}
showOidLen := 10
if longOIDs {
showOidLen = 64
}
seen := make(map[string]struct{})
gitscanner := lfs.NewGitScanner(cfg, func(p *lfs.WrappedPointer, err error) {
if err != nil {
Exit("Could not scan for Git LFS tree: %s", err)
return
}
if !lsFilesScanAll && !scanRange {
if _, ok := seen[p.Name]; ok {
return
}
}
if debug {
Print(
"filepath: %s\n"+
" size: %d\n"+
"checkout: %v\n"+
"download: %v\n"+
" oid: %s %s\n"+
" version: %s\n",
p.Name,
p.Size,
fileExistsOfSize(p),
cfg.LFSObjectExists(p.Oid, p.Size),
p.OidType,
p.Oid,
p.Version)
} else {
msg := []string{p.Oid[:showOidLen], lsFilesMarker(p), p.Name}
if lsFilesShowNameOnly {
msg = []string{p.Name}
}
if lsFilesShowSize {
size := humanize.FormatBytes(uint64(p.Size))
msg = append(msg, "("+size+")")
}
Print(strings.Join(msg, " "))
}
seen[p.Name] = struct{}{}
})
defer gitscanner.Close()
includeArg, excludeArg := getIncludeExcludeArgs(cmd)
gitscanner.Filter = buildFilepathFilter(cfg, includeArg, excludeArg, false)
if len(args) == 0 {
// Only scan the index when "git lfs ls-files" was invoked with
// no arguments.
//
// Do so to avoid showing "mixed" results, e.g., ls-files output
// from a specific historical revision, and the index.
if err := gitscanner.ScanIndex(ref, nil); err != nil {
Exit("Could not scan for Git LFS index: %s", err)
}
}
if lsFilesScanAll {
if err := gitscanner.ScanAll(nil); err != nil {
Exit("Could not scan for Git LFS history: %s", err)
}
} else {
var err error
if lsFilesScanDeleted {
err = gitscanner.ScanRefWithDeleted(ref, nil)
} else if scanRange {
err = gitscanner.ScanRefRange(otherRef, ref, nil)
} else {
err = gitscanner.ScanTree(ref)
}
if err != nil {
Exit("Could not scan for Git LFS tree: %s", err)
}
}
}
// Returns true if a pointer appears to be properly smudge on checkout
func fileExistsOfSize(p *lfs.WrappedPointer) bool {
path := cfg.Filesystem().DecodePathname(p.Name)
info, err := os.Stat(path)
return err == nil && info.Size() == p.Size
}
func lsFilesMarker(p *lfs.WrappedPointer) string {
if fileExistsOfSize(p) {
return "*"
}
return "-"
}
func init() {
RegisterCommand("ls-files", lsFilesCommand, func(cmd *cobra.Command) {
cmd.Flags().BoolVarP(&longOIDs, "long", "l", false, "")
cmd.Flags().BoolVarP(&lsFilesShowSize, "size", "s", false, "")
cmd.Flags().BoolVarP(&lsFilesShowNameOnly, "name-only", "n", false, "")
cmd.Flags().BoolVarP(&debug, "debug", "d", false, "")
cmd.Flags().BoolVarP(&lsFilesScanAll, "all", "a", false, "")
cmd.Flags().BoolVar(&lsFilesScanDeleted, "deleted", false, "")
cmd.Flags().StringVarP(&includeArg, "include", "I", "", "Include a list of paths")
cmd.Flags().StringVarP(&excludeArg, "exclude", "X", "", "Exclude a list of paths")
})
}