From b0f131a48cd4e72d641fcfb3c73fd6eeddafb931 Mon Sep 17 00:00:00 2001 From: Máximo Cuadros Date: Wed, 26 Jul 2017 16:19:06 +0200 Subject: remote: pull refactor to match default behaviour --- worktree.go | 49 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 3 deletions(-) (limited to 'worktree.go') diff --git a/worktree.go b/worktree.go index 5768888..01f8b01 100644 --- a/worktree.go +++ b/worktree.go @@ -15,6 +15,7 @@ import ( "gopkg.in/src-d/go-git.v4/plumbing/filemode" "gopkg.in/src-d/go-git.v4/plumbing/format/index" "gopkg.in/src-d/go-git.v4/plumbing/object" + "gopkg.in/src-d/go-git.v4/plumbing/storer" "gopkg.in/src-d/go-git.v4/utils/ioutil" "gopkg.in/src-d/go-git.v4/utils/merkletrie" @@ -36,6 +37,8 @@ type Worktree struct { // Pull incorporates changes from a remote repository into the current branch. // Returns nil if the operation is successful, NoErrAlreadyUpToDate if there are // no changes to be fetched, or an error. +// +// Pull only supports merges where the can be resolved as a fast-forward. func (w *Worktree) Pull(o *PullOptions) error { return w.PullContext(context.Background(), o) } @@ -44,6 +47,8 @@ func (w *Worktree) Pull(o *PullOptions) error { // branch. Returns nil if the operation is successful, NoErrAlreadyUpToDate if // there are no changes to be fetched, or an error. // +// Pull only supports merges where the can be resolved as a fast-forward. +// // The provided Context must be non-nil. If the context expires before the // operation is complete, an error is returned. The context only affects to the // transport operations. @@ -52,17 +57,55 @@ func (w *Worktree) PullContext(ctx context.Context, o *PullOptions) error { return err } - head, err := w.r.fetchAndUpdateReferences(ctx, &FetchOptions{ + remote, err := w.r.Remote(o.RemoteName) + if err != nil { + return err + } + + fetchHead, err := remote.fetch(ctx, &FetchOptions{ RemoteName: o.RemoteName, Depth: o.Depth, Auth: o.Auth, Progress: o.Progress, - }, o.ReferenceName) + }) + + updated := true + if err == NoErrAlreadyUpToDate { + updated = false + } else if err != nil { + return err + } + + ref, err := storer.ResolveReference(fetchHead, o.ReferenceName) if err != nil { return err } - if err := w.Reset(&ResetOptions{Commit: head.Hash()}); err != nil { + head, err := w.r.Head() + if err == nil { + if !updated && head.Hash() == ref.Hash() { + return NoErrAlreadyUpToDate + } + + ff, err := isFastForward(w.r.Storer, head.Hash(), ref.Hash()) + if err != nil { + return err + } + + if !ff { + return fmt.Errorf("non-fast-forward update") + } + } + + if err != nil && err != plumbing.ErrReferenceNotFound { + return err + } + + if err := w.updateHEAD(ref.Hash()); err != nil { + return err + } + + if err := w.Reset(&ResetOptions{Commit: ref.Hash()}); err != nil { return err } -- cgit