@@ -15,6 +15,7 @@ import (
1515 "gopkg.in/src-d/go-git.v4/plumbing/filemode"
1616 "gopkg.in/src-d/go-git.v4/plumbing/format/index"
1717 "gopkg.in/src-d/go-git.v4/plumbing/object"
18+ "gopkg.in/src-d/go-git.v4/plumbing/storer"
1819 "gopkg.in/src-d/go-git.v4/utils/ioutil"
1920 "gopkg.in/src-d/go-git.v4/utils/merkletrie"
2021
@@ -36,6 +37,8 @@ type Worktree struct {
3637// Pull incorporates changes from a remote repository into the current branch.
3738// Returns nil if the operation is successful, NoErrAlreadyUpToDate if there are
3839// no changes to be fetched, or an error.
40+ //
41+ // Pull only supports merges where the can be resolved as a fast-forward.
3942func (w * Worktree ) Pull (o * PullOptions ) error {
4043 return w .PullContext (context .Background (), o )
4144}
@@ -44,6 +47,8 @@ func (w *Worktree) Pull(o *PullOptions) error {
4447// branch. Returns nil if the operation is successful, NoErrAlreadyUpToDate if
4548// there are no changes to be fetched, or an error.
4649//
50+ // Pull only supports merges where the can be resolved as a fast-forward.
51+ //
4752// The provided Context must be non-nil. If the context expires before the
4853// operation is complete, an error is returned. The context only affects to the
4954// transport operations.
@@ -52,17 +57,55 @@ func (w *Worktree) PullContext(ctx context.Context, o *PullOptions) error {
5257 return err
5358 }
5459
55- head , err := w .r .fetchAndUpdateReferences (ctx , & FetchOptions {
60+ remote , err := w .r .Remote (o .RemoteName )
61+ if err != nil {
62+ return err
63+ }
64+
65+ fetchHead , err := remote .fetch (ctx , & FetchOptions {
5666 RemoteName : o .RemoteName ,
5767 Depth : o .Depth ,
5868 Auth : o .Auth ,
5969 Progress : o .Progress ,
60- }, o .ReferenceName )
70+ })
71+
72+ updated := true
73+ if err == NoErrAlreadyUpToDate {
74+ updated = false
75+ } else if err != nil {
76+ return err
77+ }
78+
79+ ref , err := storer .ResolveReference (fetchHead , o .ReferenceName )
6180 if err != nil {
6281 return err
6382 }
6483
65- if err := w .Reset (& ResetOptions {Commit : head .Hash ()}); err != nil {
84+ head , err := w .r .Head ()
85+ if err == nil {
86+ if ! updated && head .Hash () == ref .Hash () {
87+ return NoErrAlreadyUpToDate
88+ }
89+
90+ ff , err := isFastForward (w .r .Storer , head .Hash (), ref .Hash ())
91+ if err != nil {
92+ return err
93+ }
94+
95+ if ! ff {
96+ return fmt .Errorf ("non-fast-forward update" )
97+ }
98+ }
99+
100+ if err != nil && err != plumbing .ErrReferenceNotFound {
101+ return err
102+ }
103+
104+ if err := w .updateHEAD (ref .Hash ()); err != nil {
105+ return err
106+ }
107+
108+ if err := w .Reset (& ResetOptions {Commit : ref .Hash ()}); err != nil {
66109 return err
67110 }
68111
0 commit comments