@@ -25,11 +25,12 @@ import (
25
25
)
26
26
27
27
var (
28
- ErrWorktreeNotClean = errors .New ("worktree is not clean" )
29
- ErrSubmoduleNotFound = errors .New ("submodule not found" )
30
- ErrUnstagedChanges = errors .New ("worktree contains unstaged changes" )
31
- ErrGitModulesSymlink = errors .New (gitmodulesFile + " is a symlink" )
32
- ErrNonFastForwardUpdate = errors .New ("non-fast-forward update" )
28
+ ErrWorktreeNotClean = errors .New ("worktree is not clean" )
29
+ ErrSubmoduleNotFound = errors .New ("submodule not found" )
30
+ ErrUnstagedChanges = errors .New ("worktree contains unstaged changes" )
31
+ ErrGitModulesSymlink = errors .New (gitmodulesFile + " is a symlink" )
32
+ ErrNonFastForwardUpdate = errors .New ("non-fast-forward update" )
33
+ ErrRestoreWorktreeOnlyNotSupported = errors .New ("worktree only is not supported" )
33
34
)
34
35
35
36
// Worktree represents a git worktree.
@@ -307,26 +308,61 @@ func (w *Worktree) ResetSparsely(opts *ResetOptions, dirs []string) error {
307
308
}
308
309
309
310
if opts .Mode == MixedReset || opts .Mode == MergeReset || opts .Mode == HardReset {
310
- if err := w .resetIndex (t , dirs ); err != nil {
311
+ if err := w .resetIndex (t , dirs , opts . Files ); err != nil {
311
312
return err
312
313
}
313
314
}
314
315
315
316
if opts .Mode == MergeReset || opts .Mode == HardReset {
316
- if err := w .resetWorktree (t ); err != nil {
317
+ if err := w .resetWorktree (t , opts . Files ); err != nil {
317
318
return err
318
319
}
319
320
}
320
321
321
322
return nil
322
323
}
323
324
325
+ // Restore restores specified files in the working tree or stage with contents from
326
+ // a restore source. If a path is tracked but does not exist in the restore,
327
+ // source, it will be removed to match the source.
328
+ //
329
+ // If Staged and Worktree are true, then the restore source will be the index.
330
+ // If only Staged is true, then the restore source will be HEAD.
331
+ // If only Worktree is true or neither Staged nor Worktree are true, will
332
+ // result in ErrRestoreWorktreeOnlyNotSupported because restoring the working
333
+ // tree while leaving the stage untouched is not currently supported.
334
+ //
335
+ // Restore with no files specified will return ErrNoRestorePaths.
336
+ func (w * Worktree ) Restore (o * RestoreOptions ) error {
337
+ if err := o .Validate (); err != nil {
338
+ return err
339
+ }
340
+
341
+ if o .Staged {
342
+ opts := & ResetOptions {
343
+ Files : o .Files ,
344
+ }
345
+
346
+ if o .Worktree {
347
+ // If we are doing both Worktree and Staging then it is a hard reset
348
+ opts .Mode = HardReset
349
+ } else {
350
+ // If we are doing just staging then it is a mixed reset
351
+ opts .Mode = MixedReset
352
+ }
353
+
354
+ return w .Reset (opts )
355
+ }
356
+
357
+ return ErrRestoreWorktreeOnlyNotSupported
358
+ }
359
+
324
360
// Reset the worktree to a specified state.
325
361
func (w * Worktree ) Reset (opts * ResetOptions ) error {
326
362
return w .ResetSparsely (opts , nil )
327
363
}
328
364
329
- func (w * Worktree ) resetIndex (t * object.Tree , dirs []string ) error {
365
+ func (w * Worktree ) resetIndex (t * object.Tree , dirs []string , files [] string ) error {
330
366
idx , err := w .r .Storer .Index ()
331
367
if len (dirs ) > 0 {
332
368
idx .SkipUnless (dirs )
@@ -362,6 +398,13 @@ func (w *Worktree) resetIndex(t *object.Tree, dirs []string) error {
362
398
name = ch .From .String ()
363
399
}
364
400
401
+ if len (files ) > 0 {
402
+ contains := inFiles (files , name )
403
+ if ! contains {
404
+ continue
405
+ }
406
+ }
407
+
365
408
b .Remove (name )
366
409
if e == nil {
367
410
continue
@@ -379,7 +422,17 @@ func (w *Worktree) resetIndex(t *object.Tree, dirs []string) error {
379
422
return w .r .Storer .SetIndex (idx )
380
423
}
381
424
382
- func (w * Worktree ) resetWorktree (t * object.Tree ) error {
425
+ func inFiles (files []string , v string ) bool {
426
+ for _ , s := range files {
427
+ if s == v {
428
+ return true
429
+ }
430
+ }
431
+
432
+ return false
433
+ }
434
+
435
+ func (w * Worktree ) resetWorktree (t * object.Tree , files []string ) error {
383
436
changes , err := w .diffStagingWithWorktree (true , false )
384
437
if err != nil {
385
438
return err
@@ -395,6 +448,25 @@ func (w *Worktree) resetWorktree(t *object.Tree) error {
395
448
if err := w .validChange (ch ); err != nil {
396
449
return err
397
450
}
451
+
452
+ if len (files ) > 0 {
453
+ file := ""
454
+ if ch .From != nil {
455
+ file = ch .From .Name ()
456
+ } else if ch .To != nil {
457
+ file = ch .To .Name ()
458
+ }
459
+
460
+ if file == "" {
461
+ continue
462
+ }
463
+
464
+ contains := inFiles (files , file )
465
+ if ! contains {
466
+ continue
467
+ }
468
+ }
469
+
398
470
if err := w .checkoutChange (ch , t , b ); err != nil {
399
471
return err
400
472
}
0 commit comments