aboutsummaryrefslogtreecommitdiffstats
path: root/worktree_status.go
diff options
context:
space:
mode:
authorMáximo Cuadros <mcuadros@gmail.com>2017-04-11 04:41:16 +0200
committerMáximo Cuadros <mcuadros@gmail.com>2017-04-11 04:41:16 +0200
commit116fed7ea746255805f5664d9b6fd7cdb1b52663 (patch)
treec2fa3a6520f4254550eaf17af83a54526864db3f /worktree_status.go
parentaa818a3f77e6ff06765cf8c246f8708df3d190a7 (diff)
downloadgo-git-116fed7ea746255805f5664d9b6fd7cdb1b52663.tar.gz
worktree, status implementation based on merkletrie and reset and checkout implementations
Diffstat (limited to 'worktree_status.go')
-rw-r--r--worktree_status.go133
1 files changed, 133 insertions, 0 deletions
diff --git a/worktree_status.go b/worktree_status.go
new file mode 100644
index 0000000..d472fde
--- /dev/null
+++ b/worktree_status.go
@@ -0,0 +1,133 @@
+package git
+
+import (
+ "bytes"
+
+ "gopkg.in/src-d/go-git.v4/plumbing"
+ "gopkg.in/src-d/go-git.v4/plumbing/object"
+ "gopkg.in/src-d/go-git.v4/utils/merkletrie"
+ "gopkg.in/src-d/go-git.v4/utils/merkletrie/filesystem"
+ "gopkg.in/src-d/go-git.v4/utils/merkletrie/index"
+ "gopkg.in/src-d/go-git.v4/utils/merkletrie/noder"
+)
+
+// Status returns the working tree status
+func (w *Worktree) Status() (Status, error) {
+ ref, err := w.r.Head()
+ if err == plumbing.ErrReferenceNotFound {
+ return nil, nil
+ }
+
+ if err != nil {
+ return nil, err
+ }
+
+ return w.status(ref.Hash())
+}
+
+func (w *Worktree) status(commit plumbing.Hash) (Status, error) {
+ s := make(Status, 0)
+
+ right, err := w.diffStagingWithWorktree()
+ if err != nil {
+ return nil, err
+ }
+
+ for _, ch := range right {
+ a, err := ch.Action()
+ if err != nil {
+ return nil, err
+ }
+
+ switch a {
+ case merkletrie.Delete:
+ s.File(ch.From.String()).Worktree = Deleted
+ case merkletrie.Insert:
+ s.File(ch.To.String()).Worktree = Untracked
+ s.File(ch.To.String()).Staging = Untracked
+ case merkletrie.Modify:
+ s.File(ch.To.String()).Worktree = Modified
+ }
+ }
+
+ left, err := w.diffCommitWithStaging(commit, false)
+ if err != nil {
+ return nil, err
+ }
+
+ for _, ch := range left {
+ a, err := ch.Action()
+ if err != nil {
+ return nil, err
+ }
+
+ switch a {
+ case merkletrie.Delete:
+ s.File(ch.From.String()).Staging = Deleted
+ case merkletrie.Insert:
+ s.File(ch.To.String()).Staging = Added
+ case merkletrie.Modify:
+ s.File(ch.To.String()).Staging = Modified
+ }
+ }
+
+ return s, nil
+}
+
+func (w *Worktree) diffStagingWithWorktree() (merkletrie.Changes, error) {
+ idx, err := w.r.Storer.Index()
+ if err != nil {
+ return nil, err
+ }
+
+ from, err := index.NewRootNode(idx)
+ if err != nil {
+ return nil, err
+ }
+
+ to, err := filesystem.NewRootNode(w.fs)
+ if err != nil {
+ return nil, err
+ }
+
+ return merkletrie.DiffTree(from, to, IsEquals)
+}
+
+func (w *Worktree) diffCommitWithStaging(commit plumbing.Hash, reverse bool) (merkletrie.Changes, error) {
+ idx, err := w.r.Storer.Index()
+ if err != nil {
+ return nil, err
+ }
+
+ to, err := index.NewRootNode(idx)
+ if err != nil {
+ return nil, err
+ }
+
+ c, err := w.r.CommitObject(commit)
+ if err != nil {
+ return nil, err
+ }
+
+ t, err := c.Tree()
+ if err != nil {
+ return nil, err
+ }
+
+ from := object.NewTreeRootNode(t)
+ if reverse {
+ return merkletrie.DiffTree(to, from, IsEquals)
+ }
+
+ return merkletrie.DiffTree(from, to, IsEquals)
+}
+
+func IsEquals(a, b noder.Hasher) bool {
+ pathA := a.(noder.Path)
+ pathB := b.(noder.Path)
+ if pathA[len(pathA)-1].IsDir() || pathB[len(pathB)-1].IsDir() {
+ return false
+ }
+
+ return bytes.Equal(a.Hash(), b.Hash())
+}