-
Notifications
You must be signed in to change notification settings - Fork 537
worktree, status and reset implementation based on merkletrie #339
Changes from 5 commits
6a00b30
9e0ae96
af4f25d
aa818a3
116fed7
7a428a9
e14ee7a
63f2348
5bcf802
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -177,3 +177,55 @@ type SubmoduleUpdateOptions struct { | |
// submodules (and so on). Until the SubmoduleRescursivity is reached. | ||
RecurseSubmodules SubmoduleRescursivity | ||
} | ||
|
||
// CheckoutOptions describes how a checkout operation should be performed. | ||
type CheckoutOptions struct { | ||
// Branch to be checked out, if empty uses `master` | ||
Branch plumbing.ReferenceName | ||
Hash plumbing.Hash | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing documentation. |
||
// RemoteName is the name of the remote to be pushed to. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This comment does not match any code. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is godoc for RemoteName and the variable is Force, copypasta? |
||
Force bool | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing documentation. |
||
} | ||
|
||
// Validate validates the fields and sets the default values. | ||
func (o *CheckoutOptions) Validate() error { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why does this method return an error? On top of that, maybe validate is not the best name for this method, when validating you return true or false according to some checks, while this method overwrites some attributes (and only some of them, leaving other invalid values untouched) probably because there is not constructor or setters to this properly. Maybe a better name will be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was already discussed on previous PRs, and is not related to this PR There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are right, it was in #178. I'll open an issue, as we agreed back then. |
||
if o.Branch == "" { | ||
o.Branch = plumbing.Master | ||
} | ||
|
||
return nil | ||
} | ||
|
||
type ResetMode int | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing documentation. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. StatusCode below is an int8, but this is an int. Maybe we should use the same criteria in both cases. |
||
|
||
const ( | ||
// HardReset resets the index and working tree. Any changes to tracked files | ||
// in the working tree are discarded. | ||
HardReset ResetMode = iota | ||
// MixedReset Resets the index but not the working tree (i.e., the changed | ||
// files are preserved but not marked for commit) and reports what has not | ||
// been updated. This is the default action. | ||
MixedReset | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
) | ||
|
||
// ResetOptions describes how a reset operation should be performed. | ||
type ResetOptions struct { | ||
// Commit, if commit is pressent set the current branch head (HEAD) to it. | ||
Commit plumbing.Hash | ||
// Mode | ||
Mode ResetMode | ||
} | ||
|
||
// Validate validates the fields and sets the default values. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The same as before, maybe |
||
func (o *ResetOptions) Validate(r *Repository) error { | ||
if o.Commit == plumbing.ZeroHash { | ||
ref, err := r.Head() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
o.Commit = ref.Hash() | ||
} | ||
|
||
return nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ package index | |
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"time" | ||
|
||
"gopkg.in/src-d/go-git.v4/plumbing" | ||
|
@@ -47,6 +48,16 @@ type Index struct { | |
ResolveUndo *ResolveUndo | ||
} | ||
|
||
// String is equivalent to `git ls-files --stage --debug` | ||
func (i *Index) String() string { | ||
var o string | ||
for _, e := range i.Entries { | ||
o += e.String() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Even though efficiency is not important here, but my spider sense is tingling: with strings of this size, string concatenation is about 2000 times slower than using |
||
} | ||
|
||
return o | ||
} | ||
|
||
// Entry represents a single file (or stage of a file) in the cache. An entry | ||
// represents exactly one stage of a file. If a file path is unmerged then | ||
// multiple Entry instances may appear for the same path name. | ||
|
@@ -78,6 +89,18 @@ type Entry struct { | |
IntentToAdd bool | ||
} | ||
|
||
func (e Entry) String() string { | ||
var o string | ||
o += fmt.Sprintf("%06o %s %d\t%s\n", e.Mode, e.Hash, e.Stage, e.Name) | ||
o += fmt.Sprintf(" ctime: %d:%d\n", e.CreatedAt.Unix(), e.CreatedAt.Nanosecond()) | ||
o += fmt.Sprintf(" mtime: %d:%d\n", e.ModifiedAt.Unix(), e.ModifiedAt.Nanosecond()) | ||
o += fmt.Sprintf(" dev: %d\tino: %d\n", e.Dev, e.Inode) | ||
o += fmt.Sprintf(" uid: %d\tgid: %d\n", e.UID, e.GID) | ||
o += fmt.Sprintf(" size: %d\tflags: %x\n", e.Size, 0) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same things here with string concatenation. |
||
|
||
return o | ||
} | ||
|
||
// Tree contains pre-computed hashes for trees that can be derived from the | ||
// index. It helps speed up tree object generation from index for a new commit. | ||
type Tree struct { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -67,7 +67,7 @@ type TreeEntry struct { | |
// File returns the hash of the file identified by the `path` argument. | ||
// The path is interpreted as relative to the tree receiver. | ||
func (t *Tree) File(path string) (*File, error) { | ||
e, err := t.findEntry(path) | ||
e, err := t.FindEntry(path) | ||
if err != nil { | ||
return nil, ErrFileNotFound | ||
} | ||
|
@@ -86,7 +86,7 @@ func (t *Tree) File(path string) (*File, error) { | |
// Tree returns the tree identified by the `path` argument. | ||
// The path is interpreted as relative to the tree receiver. | ||
func (t *Tree) Tree(path string) (*Tree, error) { | ||
e, err := t.findEntry(path) | ||
e, err := t.FindEntry(path) | ||
if err != nil { | ||
return nil, ErrDirectoryNotFound | ||
} | ||
|
@@ -109,7 +109,8 @@ func (t *Tree) TreeEntryFile(e *TreeEntry) (*File, error) { | |
return NewFile(e.Name, e.Mode, blob), nil | ||
} | ||
|
||
func (t *Tree) findEntry(path string) (*TreeEntry, error) { | ||
// FindEntry search a TreeEntry in this tree or any subtree | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add a full stop at the end of the sentence. |
||
func (t *Tree) FindEntry(path string) (*TreeEntry, error) { | ||
pathParts := strings.Split(path, "/") | ||
|
||
var tree *Tree | ||
|
@@ -146,6 +147,7 @@ func (t *Tree) entry(baseName string) (*TreeEntry, error) { | |
if t.m == nil { | ||
t.buildMap() | ||
} | ||
|
||
entry, ok := t.m[baseName] | ||
if !ok { | ||
return nil, errEntryNotFound | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,10 +21,11 @@ type treeNoder struct { | |
name string // empty string for the root node | ||
mode filemode.FileMode | ||
hash plumbing.Hash | ||
children []noder.Noder // memoized | ||
children []noder.Noder // memorized | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. memoized was actually the right term ;-) |
||
} | ||
|
||
func newTreeNoder(t *Tree) *treeNoder { | ||
// NewTreeRootNode returns the root node of a Tree | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add a full stop at the end of the sentence. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add a full stop at the end of the sentence. |
||
func NewTreeRootNode(t *Tree) *treeNoder { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This change of name is weird. For once, the type this is constructing is treeNoder, not treeRootNode. Then, a root is always a node, so RootNode is redundant, also my trees are always roots, so TreeRoot is also redundant. Maybe if you explain what you want to do here we can find a better name for this ctor (and its associated type). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't this be just |
||
if t == nil { | ||
return &treeNoder{} | ||
} | ||
|
@@ -74,7 +75,7 @@ func (t *treeNoder) Children() ([]noder.Noder, error) { | |
return noder.NoChildren, nil | ||
} | ||
|
||
// children are memoized for efficiency | ||
// children are memorized for efficiency | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as before, children are memoized for efficiency. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. s/memorized/memoized/ |
||
if t.children != nil { | ||
return t.children, nil | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
package git | ||
|
||
import "fmt" | ||
|
||
// Status current status of a Worktree | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add a verb and a full stop to this sentence. Can you explain what do you mean by status, the comment right now is useless. Also explain what do the keys represent in the map. |
||
type Status map[string]*FileStatus | ||
|
||
func (s Status) File(filename string) *FileStatus { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Document the method. Does this receive paths of filenames? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You were documented moved code. This doesn't bellow to this PR |
||
if _, ok := (s)[filename]; !ok { | ||
s[filename] = &FileStatus{} | ||
} | ||
|
||
return s[filename] | ||
|
||
} | ||
|
||
func (s Status) IsClean() bool { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Document the method. |
||
for _, status := range s { | ||
if status.Worktree != Unmodified || status.Staging != Unmodified { | ||
return false | ||
} | ||
} | ||
|
||
return true | ||
} | ||
|
||
func (s Status) String() string { | ||
var names []string | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe paths and path are better names instead of names and name. |
||
for name := range s { | ||
names = append(names, name) | ||
} | ||
|
||
var output string | ||
for _, name := range names { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see the point of generating the list of keys (names) and then iterating it to go over all values. Why don't you iterate over the map directly? Were you thinking in sorting by name? (it would make sense for a string method) but it would be better to generate a unsorted slice of results and then sort it by name. |
||
status := s[name] | ||
if status.Staging == 0 && status.Worktree == 0 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't use magic numbers. |
||
continue | ||
} | ||
|
||
if status.Staging == Renamed { | ||
name = fmt.Sprintf("%s -> %s", name, status.Extra) | ||
} | ||
|
||
output += fmt.Sprintf("%s%s %s\n", status.Staging, status.Worktree, name) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as before, use a bytes.Buffer. |
||
} | ||
|
||
return output | ||
} | ||
|
||
// FileStatus status of a file in the Worktree | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add a verb and a full stop to this comment. |
||
type FileStatus struct { | ||
Staging StatusCode | ||
Worktree StatusCode | ||
Extra string | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Document this. |
||
} | ||
|
||
// StatusCode status code of a file in the Worktree | ||
type StatusCode int8 | ||
|
||
const ( | ||
Unmodified StatusCode = iota | ||
Untracked | ||
Modified | ||
Added | ||
Deleted | ||
Renamed | ||
Copied | ||
UpdatedButUnmerged | ||
) | ||
|
||
func (c StatusCode) String() string { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it will be simpler if declare StatusCode as a rune or a string instead of an int8? |
||
switch c { | ||
case Unmodified: | ||
return " " | ||
case Modified: | ||
return "M" | ||
case Added: | ||
return "A" | ||
case Deleted: | ||
return "D" | ||
case Renamed: | ||
return "R" | ||
case Copied: | ||
return "C" | ||
case UpdatedButUnmerged: | ||
return "U" | ||
case Untracked: | ||
return "?" | ||
default: | ||
return "-" | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
End the sentence with a full stop.