-
Notifications
You must be signed in to change notification settings - Fork 534
worktree, status and reset implementation based on merkletrie #339
Changes from 8 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 |
---|---|---|
|
@@ -178,6 +178,72 @@ type SubmoduleUpdateOptions struct { | |
RecurseSubmodules SubmoduleRescursivity | ||
} | ||
|
||
// CheckoutOptions describes how a checkout 31operation should be performed. | ||
type CheckoutOptions struct { | ||
// Hash to be checked out, if used HEAD will in detached mode. Branch and | ||
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 a verb: |
||
// Hash are mutual exclusive. | ||
Hash plumbing.Hash | ||
// Branch to be checked out, if Branch and Hash are empty is set to `master`. | ||
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 subject: |
||
Branch plumbing.ReferenceName | ||
// Force, if true when switching branches, proceed even if the index or the | ||
// working tree differs from HEAD. This is used to throw away local changes | ||
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. End the sentence with a full stop. |
||
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 | ||
} | ||
|
||
// ResetMode defines the mode of a reset operation. | ||
type ResetMode int8 | ||
|
||
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.
|
||
// MergeReset resets the index and updates the files in the working tree | ||
// that are different between Commit and HEAD, but keeps those which are | ||
// different between the index and working tree (i.e. which have changes | ||
// which have not been added). | ||
// | ||
// If a file that is different between Commit and the index has unstaged | ||
// changes, reset is aborted. | ||
MergeReset | ||
) | ||
|
||
// 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, form resets the current branch head to Commit and possibly updates | ||
// the index (resetting it to the tree of Commit) and the working tree | ||
// depending on Mode. If empty MixedReset is used. | ||
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 | ||
} | ||
|
||
// LogOptions describes how a log action should be performed. | ||
type LogOptions struct { | ||
// When the From option is set the log will only contain commits | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,5 @@ | ||
package object | ||
|
||
// A treenoder is a helper type that wraps git trees into merkletrie | ||
// noders. | ||
// | ||
// As a merkletrie noder doesn't understand the concept of modes (e.g. | ||
// file permissions), the treenoder includes the mode of the git tree in | ||
// the hash, so changes in the modes will be detected as modifications | ||
// to the file contents by the merkletrie difftree algorithm. This is | ||
// consistent with how the "git diff-tree" command works. | ||
import ( | ||
"io" | ||
|
||
|
@@ -16,6 +8,14 @@ import ( | |
"gopkg.in/src-d/go-git.v4/utils/merkletrie/noder" | ||
) | ||
|
||
// A treenoder is a helper type that wraps git trees into merkletrie | ||
// noders. | ||
// | ||
// As a merkletrie noder doesn't understand the concept of modes (e.g. | ||
// file permissions), the treenoder includes the mode of the git tree in | ||
// the hash, so changes in the modes will be detected as modifications | ||
// to the file contents by the merkletrie difftree algorithm. This is | ||
// consistent with how the "git diff-tree" command works. | ||
type treeNoder struct { | ||
parent *Tree // the root node is its own parent | ||
name string // empty string for the root node | ||
|
@@ -24,7 +24,8 @@ type treeNoder struct { | |
children []noder.Noder // memoized | ||
} | ||
|
||
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) noder.Noder { | ||
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 you may have skipped some comments, I copy them here for reference: 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). |
||
if t == nil { | ||
return &treeNoder{} | ||
} | ||
|
@@ -45,13 +46,6 @@ func (t *treeNoder) String() string { | |
return "treeNoder <" + t.name + ">" | ||
} | ||
|
||
// The hash of a treeNoder is the result of concatenating the hash of | ||
// its contents and its mode; that way the difftree algorithm will | ||
// detect changes in the contents of files and also in their mode. | ||
// | ||
// Files with Regular and Deprecated file modes are considered the same | ||
// for the purpose of difftree, so Regular will be used as the mode for | ||
// Deprecated files here. | ||
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 do you remove the notice explaining why deprecated files are handled differently than the rest of the files? |
||
func (t *treeNoder) Hash() []byte { | ||
if t.mode == filemode.Deprecated { | ||
return append(t.hash[:], filemode.Regular.Bytes()...) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package git | ||
|
||
import "fmt" | ||
import "bytes" | ||
|
||
// Status represents the current status of a Worktree. | ||
// The key of the map is the path of the file. | ||
type Status map[string]*FileStatus | ||
|
||
// File returns the FileStatus for a given path, if the FileStatus doesn't | ||
// exists a new FileStatus is added to the map using the path as key. | ||
func (s Status) File(path string) *FileStatus { | ||
if _, ok := (s)[path]; !ok { | ||
s[path] = &FileStatus{Worktree: Unmodified, Staging: Unmodified} | ||
} | ||
|
||
return s[path] | ||
} | ||
|
||
// IsClean returns true if all the files aren't in Unmodified status. | ||
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 { | ||
buf := bytes.NewBuffer(nil) | ||
for path, status := range s { | ||
if status.Staging == Unmodified && status.Worktree == Unmodified { | ||
continue | ||
} | ||
|
||
if status.Staging == Renamed { | ||
path = fmt.Sprintf("%s -> %s", path, status.Extra) | ||
} | ||
|
||
fmt.Fprintf(buf, "%c%c %s\n", status.Staging, status.Worktree, path) | ||
} | ||
|
||
return buf.String() | ||
} | ||
|
||
// FileStatus contains the 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 full stop at the end of the comment, and the same for the next 3 comments. |
||
type FileStatus struct { | ||
// Staging is the status of a file in the staging area | ||
Staging StatusCode | ||
// Worktree is the status of a file in the worktree | ||
Worktree StatusCode | ||
// Extra contains extra information, such as the previous name in a rename | ||
Extra string | ||
} | ||
|
||
// StatusCode status code of a file in the Worktree | ||
type StatusCode byte | ||
|
||
const ( | ||
Unmodified StatusCode = ' ' | ||
Untracked StatusCode = '?' | ||
Modified StatusCode = 'M' | ||
Added StatusCode = 'A' | ||
Deleted StatusCode = 'D' | ||
Renamed StatusCode = 'R' | ||
Copied StatusCode = 'C' | ||
UpdatedButUnmerged StatusCode = 'U' | ||
) |
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.
s/31//