diff options
author | Máximo Cuadros <mcuadros@gmail.com> | 2017-07-26 16:19:06 +0200 |
---|---|---|
committer | Máximo Cuadros <mcuadros@gmail.com> | 2017-07-26 16:19:06 +0200 |
commit | b0f131a48cd4e72d641fcfb3c73fd6eeddafb931 (patch) | |
tree | a9ebfdfb6b8316773145c7727af3a92a9847d72d | |
parent | e19163e22eb19b352dd022f6edc9d81e1cd7a7ed (diff) | |
download | go-git-b0f131a48cd4e72d641fcfb3c73fd6eeddafb931.tar.gz |
remote: pull refactor to match default behaviour
-rw-r--r-- | COMPATIBILITY.md | 6 | ||||
-rw-r--r-- | worktree.go | 49 | ||||
-rw-r--r-- | worktree_test.go | 60 |
3 files changed, 109 insertions, 6 deletions
diff --git a/COMPATIBILITY.md b/COMPATIBILITY.md index 948eb14..fa998bf 100644 --- a/COMPATIBILITY.md +++ b/COMPATIBILITY.md @@ -10,7 +10,7 @@ is supported by go-git. | config | ✔ | Reading and modifying per-repository configuration (`.git/config`) is supported. Global configuration (`$HOME/.gitconfig`) is not. | | **getting and creating repositories** | | init | ✔ | Plain init and `--bare` are supported. Flags `--template`, `--separate-git-dir` and `--shared` are not. | -| clone | ✔ | Plain clone and equivalents to `--progress`, `--single-branch`, `--depth`, `--origin`, `--recurse-submodules` are supported. Others are not. | +| clone | ✔ | Plain clone and equivalents to `--progress`, `--single-branch`, `--depth`, `--origin`, `--recurse-submodules` are supported. Others are not. | | **basic snapshotting** | | add | ✔ | Plain add is supported. Any other flag aren't supported | | status | ✔ | @@ -27,7 +27,7 @@ is supported by go-git. | tag | ✔ | | **sharing and updating projects** | | fetch | ✔ | -| pull | ✔ | +| pull | ✔ | Only supports merges where the merge can be resolved as a fast-forward. | | push | ✔ | | remote | ✔ | | submodule | ✔ | @@ -108,4 +108,4 @@ is supported by go-git. | gitattributes | ✖ | | index version | | | packfile version | | -| push-certs | ✖ |
\ No newline at end of file +| push-certs | ✖ | 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 } diff --git a/worktree_test.go b/worktree_test.go index 150176f..c565e29 100644 --- a/worktree_test.go +++ b/worktree_test.go @@ -51,6 +51,66 @@ func (s *WorktreeSuite) TestPullCheckout(c *C) { c.Assert(fi, HasLen, 8) } +func (s *WorktreeSuite) TestPullFastForward(c *C) { + url := c.MkDir() + path := fixtures.Basic().ByTag("worktree").One().Worktree().Root() + + server, err := PlainClone(url, false, &CloneOptions{ + URL: path, + }) + + r, err := PlainClone(c.MkDir(), false, &CloneOptions{ + URL: url, + }) + + w, err := server.Worktree() + c.Assert(err, IsNil) + err = ioutil.WriteFile(filepath.Join(path, "foo"), []byte("foo"), 0755) + c.Assert(err, IsNil) + hash, err := w.Commit("foo", &CommitOptions{Author: defaultSignature()}) + c.Assert(err, IsNil) + + w, err = r.Worktree() + c.Assert(err, IsNil) + + err = w.Pull(&PullOptions{}) + c.Assert(err, IsNil) + + head, err := r.Head() + c.Assert(err, IsNil) + c.Assert(head.Hash(), Equals, hash) +} + +func (s *WorktreeSuite) TestPullNonFastForward(c *C) { + url := c.MkDir() + path := fixtures.Basic().ByTag("worktree").One().Worktree().Root() + + server, err := PlainClone(url, false, &CloneOptions{ + URL: path, + }) + + r, err := PlainClone(c.MkDir(), false, &CloneOptions{ + URL: url, + }) + + w, err := server.Worktree() + c.Assert(err, IsNil) + err = ioutil.WriteFile(filepath.Join(path, "foo"), []byte("foo"), 0755) + c.Assert(err, IsNil) + _, err = w.Commit("foo", &CommitOptions{Author: defaultSignature()}) + c.Assert(err, IsNil) + + w, err = r.Worktree() + c.Assert(err, IsNil) + err = ioutil.WriteFile(filepath.Join(path, "bar"), []byte("bar"), 0755) + c.Assert(err, IsNil) + _, err = w.Commit("bar", &CommitOptions{Author: defaultSignature()}) + c.Assert(err, IsNil) + + err = w.Pull(&PullOptions{}) + c.Assert(err, ErrorMatches, "non-fast-forward update") +} + func (s *WorktreeSuite) TestPullUpdateReferencesIfNeeded(c *C) { r, _ := Init(memory.NewStorage(), memfs.New()) r.CreateRemote(&config.RemoteConfig{ |