Skip to content
This repository was archived by the owner on Sep 11, 2020. It is now read-only.

Worktree.Reset refactor and Soft, Merge, Hard and Mixed modes #572

Merged
merged 1 commit into from
Sep 1, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions options.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,13 +238,13 @@ func (o *CheckoutOptions) Validate() error {
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
MixedReset ResetMode = iota
// HardReset resets the index and working tree. Any changes to tracked files
// in the working tree are discarded.
HardReset
// 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
Expand All @@ -253,6 +253,10 @@ const (
// If a file that is different between Commit and the index has unstaged
// changes, reset is aborted.
MergeReset
// SoftReset does not touch the index file or the working tree at all (but
// resets the head to <commit>, just like all modes do). This leaves all
// your changed files "Changes to be committed", as git status would put it.
SoftReset
)

// ResetOptions describes how a reset operation should be performed.
Expand Down
5 changes: 4 additions & 1 deletion repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,10 @@ func (r *Repository) clone(ctx context.Context, o *CloneOptions) error {
return err
}

if err := w.Reset(&ResetOptions{Commit: head.Hash()}); err != nil {
if err := w.Reset(&ResetOptions{
Mode: MergeReset,
Commit: head.Hash(),
}); err != nil {
return err
}

Expand Down
11 changes: 7 additions & 4 deletions submodule.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,17 @@ func (s *Submodule) Status() (*SubmoduleStatus, error) {
}

func (s *Submodule) status(idx *index.Index) (*SubmoduleStatus, error) {
status := &SubmoduleStatus{
Path: s.c.Path,
}

e, err := idx.Entry(s.c.Path)
if err != nil {
if err != nil && err != index.ErrEntryNotFound {
return nil, err
}

status := &SubmoduleStatus{
Path: s.c.Path,
Expected: e.Hash,
if e != nil {
status.Expected = e.Hash
}

if !s.initialized {
Expand Down
188 changes: 115 additions & 73 deletions worktree.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,10 @@ func (w *Worktree) PullContext(ctx context.Context, o *PullOptions) error {
return err
}

if err := w.Reset(&ResetOptions{Commit: ref.Hash()}); err != nil {
if err := w.Reset(&ResetOptions{
Mode: MergeReset,
Commit: ref.Hash(),
}); err != nil {
return err
}

Expand Down Expand Up @@ -270,65 +273,99 @@ func (w *Worktree) Reset(opts *ResetOptions) error {
}
}

changes, err := w.diffCommitWithStaging(opts.Commit, true)
if err != nil {
if err := w.setHEADCommit(opts.Commit); err != nil {
return err
}

idx, err := w.r.Storer.Index()
if err != nil {
return err
if opts.Mode == SoftReset {
return nil
}

t, err := w.getTreeFromCommitHash(opts.Commit)
if err != nil {
return err
}

for _, ch := range changes {
if err := w.checkoutChange(ch, t, idx); err != nil {
if opts.Mode == MixedReset || opts.Mode == MergeReset || opts.Mode == HardReset {
if err := w.resetIndex(t); err != nil {
return err
}
}

if err := w.r.Storer.SetIndex(idx); err != nil {
return err
if opts.Mode == MergeReset || opts.Mode == HardReset {
if err := w.resetWorktree(t); err != nil {
return err
}
}

return w.setHEADCommit(opts.Commit)
return nil
}

func (w *Worktree) containsUnstagedChanges() (bool, error) {
ch, err := w.diffStagingWithWorktree()
func (w *Worktree) resetIndex(t *object.Tree) error {
idx, err := w.r.Storer.Index()
if err != nil {
return false, err
return err
}

return len(ch) != 0, nil
}

func (w *Worktree) setHEADCommit(commit plumbing.Hash) error {
head, err := w.r.Reference(plumbing.HEAD, false)
changes, err := w.diffTreeWithStaging(t, true)
if err != nil {
return err
}

if head.Type() == plumbing.HashReference {
head = plumbing.NewHashReference(plumbing.HEAD, commit)
return w.r.Storer.SetReference(head)
for _, ch := range changes {
a, err := ch.Action()
if err != nil {
return err
}

var name string
var e *object.TreeEntry

switch a {
case merkletrie.Modify, merkletrie.Insert:
name = ch.To.String()
e, err = t.FindEntry(name)
if err != nil {
return err
}
case merkletrie.Delete:
name = ch.From.String()
}

_, _ = idx.Remove(name)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this operation fail? If so, should we leave it unhandled?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the only error returned by Remove, is ErrEntryNotFound and we don't care about it.

if e == nil {
continue
}

idx.Entries = append(idx.Entries, &index.Entry{
Name: name,
Hash: e.Hash,
Mode: e.Mode,
})

}

branch, err := w.r.Reference(head.Target(), false)
return w.r.Storer.SetIndex(idx)
}

func (w *Worktree) resetWorktree(t *object.Tree) error {
changes, err := w.diffStagingWithWorktree(true)
if err != nil {
return err
}

if !branch.Name().IsBranch() {
return fmt.Errorf("invalid HEAD target should be a branch, found %s", branch.Type())
idx, err := w.r.Storer.Index()
if err != nil {
return err
}

branch = plumbing.NewHashReference(branch.Name(), commit)
return w.r.Storer.SetReference(branch)
for _, ch := range changes {
if err := w.checkoutChange(ch, t, idx); err != nil {
return err
}
}

return w.r.Storer.SetIndex(idx)
}

func (w *Worktree) checkoutChange(ch merkletrie.Change, t *object.Tree, idx *index.Index) error {
Expand All @@ -351,13 +388,7 @@ func (w *Worktree) checkoutChange(ch merkletrie.Change, t *object.Tree, idx *ind

isSubmodule = e.Mode == filemode.Submodule
case merkletrie.Delete:
name = ch.From.String()
ie, err := idx.Entry(name)
if err != nil {
return err
}

isSubmodule = ie.Mode == filemode.Submodule
return rmFileAndDirIfEmpty(w.Filesystem, ch.From.String())
}

if isSubmodule {
Expand All @@ -367,6 +398,52 @@ func (w *Worktree) checkoutChange(ch merkletrie.Change, t *object.Tree, idx *ind
return w.checkoutChangeRegularFile(name, a, t, e, idx)
}

func (w *Worktree) containsUnstagedChanges() (bool, error) {
ch, err := w.diffStagingWithWorktree(false)
if err != nil {
return false, err
}

for _, c := range ch {
a, err := c.Action()
if err != nil {
return false, err
}

if a == merkletrie.Insert {
continue
}

return true, nil
}

return false, nil
}

func (w *Worktree) setHEADCommit(commit plumbing.Hash) error {
head, err := w.r.Reference(plumbing.HEAD, false)
if err != nil {
return err
}

if head.Type() == plumbing.HashReference {
head = plumbing.NewHashReference(plumbing.HEAD, commit)
return w.r.Storer.SetReference(head)
}

branch, err := w.r.Reference(head.Target(), false)
if err != nil {
return err
}

if !branch.Name().IsBranch() {
return fmt.Errorf("invalid HEAD target should be a branch, found %s", branch.Type())
}

branch = plumbing.NewHashReference(branch.Name(), commit)
return w.r.Storer.SetReference(branch)
}

func (w *Worktree) checkoutChangeSubmodule(name string,
a merkletrie.Action,
e *object.TreeEntry,
Expand All @@ -383,17 +460,7 @@ func (w *Worktree) checkoutChangeSubmodule(name string,
return nil
}

if err := w.rmIndexFromFile(name, idx); err != nil {
return err
}

if err := w.addIndexFromTreeEntry(name, e, idx); err != nil {
return err
}

// TODO: the submodule update should be reviewed as reported at:
// https://github.com/src-d/go-git/issues/415
return sub.update(context.TODO(), &SubmoduleUpdateOptions{}, e.Hash)
return w.addIndexFromTreeEntry(name, e, idx)
case merkletrie.Insert:
mode, err := e.Mode.ToOSFileMode()
if err != nil {
Expand All @@ -405,12 +472,6 @@ func (w *Worktree) checkoutChangeSubmodule(name string,
}

return w.addIndexFromTreeEntry(name, e, idx)
case merkletrie.Delete:
if err := rmFileAndDirIfEmpty(w.Filesystem, name); err != nil {
return err
}

return w.rmIndexFromFile(name, idx)
}

return nil
Expand All @@ -424,9 +485,7 @@ func (w *Worktree) checkoutChangeRegularFile(name string,
) error {
switch a {
case merkletrie.Modify:
if err := w.rmIndexFromFile(name, idx); err != nil {
return err
}
_, _ = idx.Remove(name)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same, should we ignore this error?


// to apply perm changes the file is deleted, billy doesn't implement
// chmod
Expand All @@ -446,12 +505,6 @@ func (w *Worktree) checkoutChangeRegularFile(name string,
}

return w.addIndexFromFile(name, e.Hash, idx)
case merkletrie.Delete:
if err := rmFileAndDirIfEmpty(w.Filesystem, name); err != nil {
return err
}

return w.rmIndexFromFile(name, idx)
}

return nil
Expand Down Expand Up @@ -503,6 +556,7 @@ func (w *Worktree) checkoutFileSymlink(f *object.File) (err error) {
}

func (w *Worktree) addIndexFromTreeEntry(name string, f *object.TreeEntry, idx *index.Index) error {
_, _ = idx.Remove(name)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

idx.Entries = append(idx.Entries, &index.Entry{
Hash: f.Hash,
Name: name,
Expand All @@ -513,6 +567,7 @@ func (w *Worktree) addIndexFromTreeEntry(name string, f *object.TreeEntry, idx *
}

func (w *Worktree) addIndexFromFile(name string, h plumbing.Hash, idx *index.Index) error {
_, _ = idx.Remove(name)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

fi, err := w.Filesystem.Lstat(name)
if err != nil {
return err
Expand Down Expand Up @@ -541,19 +596,6 @@ func (w *Worktree) addIndexFromFile(name string, h plumbing.Hash, idx *index.Ind
return nil
}

func (w *Worktree) rmIndexFromFile(name string, idx *index.Index) error {
for i, e := range idx.Entries {
if e.Name != name {
continue
}

idx.Entries = append(idx.Entries[:i], idx.Entries[i+1:]...)
return nil
}

return nil
}

func (w *Worktree) getTreeFromCommitHash(commit plumbing.Hash) (*object.Tree, error) {
c, err := w.r.CommitObject(commit)
if err != nil {
Expand Down
Loading