diff options
author | Máximo Cuadros <mcuadros@gmail.com> | 2017-04-11 04:41:16 +0200 |
---|---|---|
committer | Máximo Cuadros <mcuadros@gmail.com> | 2017-04-11 04:41:16 +0200 |
commit | 116fed7ea746255805f5664d9b6fd7cdb1b52663 (patch) | |
tree | c2fa3a6520f4254550eaf17af83a54526864db3f /worktree_status.go | |
parent | aa818a3f77e6ff06765cf8c246f8708df3d190a7 (diff) | |
download | go-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.go | 133 |
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()) +} |