···44 "bytes"
55 "fmt"
66 "path/filepath"
77+88+ mindex "github.com/go-git/go-git/v5/utils/merkletrie/index"
99+ "github.com/go-git/go-git/v5/utils/merkletrie/noder"
710)
811912// Status represents the current status of a Worktree.
···7780 Copied StatusCode = 'C'
7881 UpdatedButUnmerged StatusCode = 'U'
7982)
8383+8484+// StatusStrategy defines the different types of strategies when processing
8585+// the worktree status.
8686+type StatusStrategy int
8787+8888+const (
8989+ // TODO: (V6) Review the default status strategy.
9090+ // TODO: (V6) Review the type used to represent Status, to enable lazy
9191+ // processing of statuses going direct to the backing filesystem.
9292+ defaultStatusStrategy = Empty
9393+9494+ // Empty starts its status map from empty. Missing entries for a given
9595+ // path means that the file is untracked. This causes a known issue (#119)
9696+ // whereby unmodified files can be incorrectly reported as untracked.
9797+ //
9898+ // This can be used when returning the changed state within a modified Worktree.
9999+ // For example, to check whether the current worktree is clean.
100100+ Empty StatusStrategy = 0
101101+ // Preload goes through all existing nodes from the index and add them to the
102102+ // status map as unmodified. This is currently the most reliable strategy
103103+ // although it comes at a performance cost in large repositories.
104104+ //
105105+ // This method is recommended when fetching the status of unmodified files.
106106+ // For example, to confirm the status of a specific file that is either
107107+ // untracked or unmodified.
108108+ Preload StatusStrategy = 1
109109+)
110110+111111+func (s StatusStrategy) new(w *Worktree) (Status, error) {
112112+ switch s {
113113+ case Preload:
114114+ return preloadStatus(w)
115115+ case Empty:
116116+ return make(Status), nil
117117+ }
118118+ return nil, fmt.Errorf("%w: %+v", ErrUnsupportedStatusStrategy, s)
119119+}
120120+121121+func preloadStatus(w *Worktree) (Status, error) {
122122+ idx, err := w.r.Storer.Index()
123123+ if err != nil {
124124+ return nil, err
125125+ }
126126+127127+ idxRoot := mindex.NewRootNode(idx)
128128+ nodes := []noder.Noder{idxRoot}
129129+130130+ status := make(Status)
131131+ for len(nodes) > 0 {
132132+ var node noder.Noder
133133+ node, nodes = nodes[0], nodes[1:]
134134+ if node.IsDir() {
135135+ children, err := node.Children()
136136+ if err != nil {
137137+ return nil, err
138138+ }
139139+ nodes = append(nodes, children...)
140140+ continue
141141+ }
142142+ fs := status.File(node.Name())
143143+ fs.Worktree = Unmodified
144144+ fs.Staging = Unmodified
145145+ }
146146+147147+ return status, nil
148148+}
+19-3
worktree_status.go
···2929 // ErrGlobNoMatches in an AddGlob if the glob pattern does not match any
3030 // files in the worktree.
3131 ErrGlobNoMatches = errors.New("glob pattern did not match any files")
3232+ // ErrUnsupportedStatusStrategy occurs when an invalid StatusStrategy is used
3333+ // when processing the Worktree status.
3434+ ErrUnsupportedStatusStrategy = errors.New("unsupported status strategy")
3235)
33363437// Status returns the working tree status.
3538func (w *Worktree) Status() (Status, error) {
3939+ return w.StatusWithOptions(StatusOptions{Strategy: defaultStatusStrategy})
4040+}
4141+4242+// StatusOptions defines the options for Worktree.StatusWithOptions().
4343+type StatusOptions struct {
4444+ Strategy StatusStrategy
4545+}
4646+4747+// StatusWithOptions returns the working tree status.
4848+func (w *Worktree) StatusWithOptions(o StatusOptions) (Status, error) {
3649 var hash plumbing.Hash
37503851 ref, err := w.r.Head()
···4457 hash = ref.Hash()
4558 }
46594747- return w.status(hash)
6060+ return w.status(o.Strategy, hash)
4861}
49625050-func (w *Worktree) status(commit plumbing.Hash) (Status, error) {
5151- s := make(Status)
6363+func (w *Worktree) status(ss StatusStrategy, commit plumbing.Hash) (Status, error) {
6464+ s, err := ss.new(w)
6565+ if err != nil {
6666+ return nil, err
6767+ }
52685369 left, err := w.diffCommitWithStaging(commit, false)
5470 if err != nil {