@@ -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
334371func (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+
370447func (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
505558func (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
515569func (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-
557599func (w * Worktree ) getTreeFromCommitHash (commit plumbing.Hash ) (* object.Tree , error ) {
558600 c , err := w .r .CommitObject (commit )
559601 if err != nil {
0 commit comments