Просмотр исходного кода

Performance improvement for uncommitted files (#463)

* attempt to use 'git status' when scanning uncommitted files

* fix comment

* correct copy/rename handling

* use 'git status' for unstaged changes
Matt Bartel 5 лет назад
Родитель
Сommit
af26553292
1 измененных файлов с 33 добавлено и 1 удалено
  1. 33 1
      scan/unstaged.go

+ 33 - 1
scan/unstaged.go

@@ -4,6 +4,7 @@ import (
 	"bytes"
 	"fmt"
 	"io"
+	"os/exec"
 	"strings"
 	"time"
 
@@ -90,7 +91,7 @@ func (us *UnstagedScanner) Scan() (report.Report, error) {
 		return scannerReport, err
 	}
 
-	status, err := wt.Status()
+	status, err := gitStatus(wt)
 	if err != nil {
 		return scannerReport, err
 	}
@@ -188,3 +189,34 @@ func diffPrettyText(diffs []diffmatchpatch.Diff) string {
 	}
 	return buff.String()
 }
+
+// gitStatus returns the status of modified files in the worktree. It will attempt to execute 'git status'
+// and will fall back to git.Worktree.Status() if that fails.
+func gitStatus(wt *git.Worktree) (git.Status, error) {
+	c := exec.Command("git", "status", "--porcelain", "-z")
+	c.Dir = wt.Filesystem.Root()
+	output, err := c.Output()
+	if err != nil {
+		stat, err := wt.Status()
+		return stat, err
+	}
+
+	lines := strings.Split(string(output), "\000")
+	stat := make(map[string]*git.FileStatus, len(lines))
+	for _, line := range lines {
+		if len(line) == 0 {
+			continue
+		}
+
+		// For copy/rename the output looks like
+		//   R  destination\000source
+		// Which means we can split on space and ignore anything with only one result
+		parts := strings.SplitN(strings.TrimLeft(line, " "), " ", 2)
+		if len(parts) == 2 {
+			stat[strings.Trim(parts[1], " ")] = &git.FileStatus{
+				Staging: git.StatusCode([]byte(parts[0])[0]),
+			}
+		}
+	}
+	return stat, err
+}