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

Commit 8ce9f5f

Browse files
authored
Merge pull request #572 from mcuadros/reset
Worktree.Reset refactor and Soft, Merge, Hard and Mixed modes
2 parents 3ca3702 + f1e58e0 commit 8ce9f5f

File tree

6 files changed

+277
-130
lines changed

6 files changed

+277
-130
lines changed

options.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -238,13 +238,13 @@ func (o *CheckoutOptions) Validate() error {
238238
type ResetMode int8
239239

240240
const (
241-
// HardReset resets the index and working tree. Any changes to tracked files
242-
// in the working tree are discarded.
243-
HardReset ResetMode = iota
244241
// MixedReset resets the index but not the working tree (i.e., the changed
245242
// files are preserved but not marked for commit) and reports what has not
246243
// been updated. This is the default action.
247-
MixedReset
244+
MixedReset ResetMode = iota
245+
// HardReset resets the index and working tree. Any changes to tracked files
246+
// in the working tree are discarded.
247+
HardReset
248248
// MergeReset resets the index and updates the files in the working tree
249249
// that are different between Commit and HEAD, but keeps those which are
250250
// different between the index and working tree (i.e. which have changes
@@ -253,6 +253,10 @@ const (
253253
// If a file that is different between Commit and the index has unstaged
254254
// changes, reset is aborted.
255255
MergeReset
256+
// SoftReset does not touch the index file or the working tree at all (but
257+
// resets the head to <commit>, just like all modes do). This leaves all
258+
// your changed files "Changes to be committed", as git status would put it.
259+
SoftReset
256260
)
257261

258262
// ResetOptions describes how a reset operation should be performed.

repository.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,10 @@ func (r *Repository) clone(ctx context.Context, o *CloneOptions) error {
456456
return err
457457
}
458458

459-
if err := w.Reset(&ResetOptions{Commit: head.Hash()}); err != nil {
459+
if err := w.Reset(&ResetOptions{
460+
Mode: MergeReset,
461+
Commit: head.Hash(),
462+
}); err != nil {
460463
return err
461464
}
462465

submodule.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,17 @@ func (s *Submodule) Status() (*SubmoduleStatus, error) {
6262
}
6363

6464
func (s *Submodule) status(idx *index.Index) (*SubmoduleStatus, error) {
65+
status := &SubmoduleStatus{
66+
Path: s.c.Path,
67+
}
68+
6569
e, err := idx.Entry(s.c.Path)
66-
if err != nil {
70+
if err != nil && err != index.ErrEntryNotFound {
6771
return nil, err
6872
}
6973

70-
status := &SubmoduleStatus{
71-
Path: s.c.Path,
72-
Expected: e.Hash,
74+
if e != nil {
75+
status.Expected = e.Hash
7376
}
7477

7578
if !s.initialized {

worktree.go

Lines changed: 115 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,10 @@ func (w *Worktree) PullContext(ctx context.Context, o *PullOptions) error {
107107
return err
108108
}
109109

110-
if err := w.Reset(&ResetOptions{Commit: ref.Hash()}); err != nil {
110+
if err := w.Reset(&ResetOptions{
111+
Mode: MergeReset,
112+
Commit: ref.Hash(),
113+
}); err != nil {
111114
return err
112115
}
113116

@@ -270,65 +273,99 @@ func (w *Worktree) Reset(opts *ResetOptions) error {
270273
}
271274
}
272275

273-
changes, err := w.diffCommitWithStaging(opts.Commit, true)
274-
if err != nil {
276+
if err := w.setHEADCommit(opts.Commit); err != nil {
275277
return err
276278
}
277279

278-
idx, err := w.r.Storer.Index()
279-
if err != nil {
280-
return err
280+
if opts.Mode == SoftReset {
281+
return nil
281282
}
282283

283284
t, err := w.getTreeFromCommitHash(opts.Commit)
284285
if err != nil {
285286
return err
286287
}
287288

288-
for _, ch := range changes {
289-
if err := w.checkoutChange(ch, t, idx); err != nil {
289+
if opts.Mode == MixedReset || opts.Mode == MergeReset || opts.Mode == HardReset {
290+
if err := w.resetIndex(t); err != nil {
290291
return err
291292
}
292293
}
293294

294-
if err := w.r.Storer.SetIndex(idx); err != nil {
295-
return err
295+
if opts.Mode == MergeReset || opts.Mode == HardReset {
296+
if err := w.resetWorktree(t); err != nil {
297+
return err
298+
}
296299
}
297300

298-
return w.setHEADCommit(opts.Commit)
301+
return nil
299302
}
300303

301-
func (w *Worktree) containsUnstagedChanges() (bool, error) {
302-
ch, err := w.diffStagingWithWorktree()
304+
func (w *Worktree) resetIndex(t *object.Tree) error {
305+
idx, err := w.r.Storer.Index()
303306
if err != nil {
304-
return false, err
307+
return err
305308
}
306309

307-
return len(ch) != 0, nil
308-
}
309-
310-
func (w *Worktree) setHEADCommit(commit plumbing.Hash) error {
311-
head, err := w.r.Reference(plumbing.HEAD, false)
310+
changes, err := w.diffTreeWithStaging(t, true)
312311
if err != nil {
313312
return err
314313
}
315314

316-
if head.Type() == plumbing.HashReference {
317-
head = plumbing.NewHashReference(plumbing.HEAD, commit)
318-
return w.r.Storer.SetReference(head)
315+
for _, ch := range changes {
316+
a, err := ch.Action()
317+
if err != nil {
318+
return err
319+
}
320+
321+
var name string
322+
var e *object.TreeEntry
323+
324+
switch a {
325+
case merkletrie.Modify, merkletrie.Insert:
326+
name = ch.To.String()
327+
e, err = t.FindEntry(name)
328+
if err != nil {
329+
return err
330+
}
331+
case merkletrie.Delete:
332+
name = ch.From.String()
333+
}
334+
335+
_, _ = idx.Remove(name)
336+
if e == nil {
337+
continue
338+
}
339+
340+
idx.Entries = append(idx.Entries, &index.Entry{
341+
Name: name,
342+
Hash: e.Hash,
343+
Mode: e.Mode,
344+
})
345+
319346
}
320347

321-
branch, err := w.r.Reference(head.Target(), false)
348+
return w.r.Storer.SetIndex(idx)
349+
}
350+
351+
func (w *Worktree) resetWorktree(t *object.Tree) error {
352+
changes, err := w.diffStagingWithWorktree(true)
322353
if err != nil {
323354
return err
324355
}
325356

326-
if !branch.Name().IsBranch() {
327-
return fmt.Errorf("invalid HEAD target should be a branch, found %s", branch.Type())
357+
idx, err := w.r.Storer.Index()
358+
if err != nil {
359+
return err
328360
}
329361

330-
branch = plumbing.NewHashReference(branch.Name(), commit)
331-
return w.r.Storer.SetReference(branch)
362+
for _, ch := range changes {
363+
if err := w.checkoutChange(ch, t, idx); err != nil {
364+
return err
365+
}
366+
}
367+
368+
return w.r.Storer.SetIndex(idx)
332369
}
333370

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

352389
isSubmodule = e.Mode == filemode.Submodule
353390
case merkletrie.Delete:
354-
name = ch.From.String()
355-
ie, err := idx.Entry(name)
356-
if err != nil {
357-
return err
358-
}
359-
360-
isSubmodule = ie.Mode == filemode.Submodule
391+
return rmFileAndDirIfEmpty(w.Filesystem, ch.From.String())
361392
}
362393

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

401+
func (w *Worktree) containsUnstagedChanges() (bool, error) {
402+
ch, err := w.diffStagingWithWorktree(false)
403+
if err != nil {
404+
return false, err
405+
}
406+
407+
for _, c := range ch {
408+
a, err := c.Action()
409+
if err != nil {
410+
return false, err
411+
}
412+
413+
if a == merkletrie.Insert {
414+
continue
415+
}
416+
417+
return true, nil
418+
}
419+
420+
return false, nil
421+
}
422+
423+
func (w *Worktree) setHEADCommit(commit plumbing.Hash) error {
424+
head, err := w.r.Reference(plumbing.HEAD, false)
425+
if err != nil {
426+
return err
427+
}
428+
429+
if head.Type() == plumbing.HashReference {
430+
head = plumbing.NewHashReference(plumbing.HEAD, commit)
431+
return w.r.Storer.SetReference(head)
432+
}
433+
434+
branch, err := w.r.Reference(head.Target(), false)
435+
if err != nil {
436+
return err
437+
}
438+
439+
if !branch.Name().IsBranch() {
440+
return fmt.Errorf("invalid HEAD target should be a branch, found %s", branch.Type())
441+
}
442+
443+
branch = plumbing.NewHashReference(branch.Name(), commit)
444+
return w.r.Storer.SetReference(branch)
445+
}
446+
370447
func (w *Worktree) checkoutChangeSubmodule(name string,
371448
a merkletrie.Action,
372449
e *object.TreeEntry,
@@ -383,17 +460,7 @@ func (w *Worktree) checkoutChangeSubmodule(name string,
383460
return nil
384461
}
385462

386-
if err := w.rmIndexFromFile(name, idx); err != nil {
387-
return err
388-
}
389-
390-
if err := w.addIndexFromTreeEntry(name, e, idx); err != nil {
391-
return err
392-
}
393-
394-
// TODO: the submodule update should be reviewed as reported at:
395-
// https://github.com/src-d/go-git/issues/415
396-
return sub.update(context.TODO(), &SubmoduleUpdateOptions{}, e.Hash)
463+
return w.addIndexFromTreeEntry(name, e, idx)
397464
case merkletrie.Insert:
398465
mode, err := e.Mode.ToOSFileMode()
399466
if err != nil {
@@ -405,12 +472,6 @@ func (w *Worktree) checkoutChangeSubmodule(name string,
405472
}
406473

407474
return w.addIndexFromTreeEntry(name, e, idx)
408-
case merkletrie.Delete:
409-
if err := rmFileAndDirIfEmpty(w.Filesystem, name); err != nil {
410-
return err
411-
}
412-
413-
return w.rmIndexFromFile(name, idx)
414475
}
415476

416477
return nil
@@ -424,9 +485,7 @@ func (w *Worktree) checkoutChangeRegularFile(name string,
424485
) error {
425486
switch a {
426487
case merkletrie.Modify:
427-
if err := w.rmIndexFromFile(name, idx); err != nil {
428-
return err
429-
}
488+
_, _ = idx.Remove(name)
430489

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

448507
return w.addIndexFromFile(name, e.Hash, idx)
449-
case merkletrie.Delete:
450-
if err := rmFileAndDirIfEmpty(w.Filesystem, name); err != nil {
451-
return err
452-
}
453-
454-
return w.rmIndexFromFile(name, idx)
455508
}
456509

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

505558
func (w *Worktree) addIndexFromTreeEntry(name string, f *object.TreeEntry, idx *index.Index) error {
559+
_, _ = idx.Remove(name)
506560
idx.Entries = append(idx.Entries, &index.Entry{
507561
Hash: f.Hash,
508562
Name: name,
@@ -513,6 +567,7 @@ func (w *Worktree) addIndexFromTreeEntry(name string, f *object.TreeEntry, idx *
513567
}
514568

515569
func (w *Worktree) addIndexFromFile(name string, h plumbing.Hash, idx *index.Index) error {
570+
_, _ = idx.Remove(name)
516571
fi, err := w.Filesystem.Lstat(name)
517572
if err != nil {
518573
return err
@@ -541,19 +596,6 @@ func (w *Worktree) addIndexFromFile(name string, h plumbing.Hash, idx *index.Ind
541596
return nil
542597
}
543598

544-
func (w *Worktree) rmIndexFromFile(name string, idx *index.Index) error {
545-
for i, e := range idx.Entries {
546-
if e.Name != name {
547-
continue
548-
}
549-
550-
idx.Entries = append(idx.Entries[:i], idx.Entries[i+1:]...)
551-
return nil
552-
}
553-
554-
return nil
555-
}
556-
557599
func (w *Worktree) getTreeFromCommitHash(commit plumbing.Hash) (*object.Tree, error) {
558600
c, err := w.r.CommitObject(commit)
559601
if err != nil {

0 commit comments

Comments
 (0)