diff options
author | Nick Thomas <nick@gitlab.com> | 2017-07-22 09:50:40 +0100 |
---|---|---|
committer | Jeremy Stribling <strib@alum.mit.edu> | 2017-11-27 11:38:14 -0800 |
commit | 702718fd59be0aa4b8bf8492403c465107ca17af (patch) | |
tree | 00724b2409b9dee0f9fe5fc6b86d9da2cf91f0ce | |
parent | 147a1b7d2e8a08d5c6228de0f98b3f5a1497f95a (diff) | |
download | go-git-702718fd59be0aa4b8bf8492403c465107ca17af.tar.gz |
Support non-force fetches
-rw-r--r-- | options.go | 6 | ||||
-rw-r--r-- | remote.go | 28 | ||||
-rw-r--r-- | worktree.go | 1 |
3 files changed, 33 insertions, 2 deletions
@@ -95,6 +95,9 @@ type PullOptions struct { // stored, if nil nothing is stored and the capability (if supported) // no-progress, is sent to the server to avoid send this information. Progress sideband.Progress + // Force allows the pull to update a local branch even when the remote + // branch does not descend from it. + Force bool } // Validate validates the fields and sets the default values. @@ -142,6 +145,9 @@ type FetchOptions struct { // Tags describe how the tags will be fetched from the remote repository, // by default is TagFollowing. Tags TagMode + // Force allows the fetch to update a local branch even when the remote + // branch does not descend from it. + Force bool } // Validate validates the fields and sets the default values. @@ -25,6 +25,7 @@ import ( var ( NoErrAlreadyUpToDate = errors.New("already up-to-date") ErrDeleteRefNotSupported = errors.New("server does not support delete-refs") + ErrForceNeeded = errors.New("some refs were not updated") ) const ( @@ -302,7 +303,7 @@ func (r *Remote) fetch(ctx context.Context, o *FetchOptions) (storer.ReferenceSt } } - updated, err := r.updateLocalReferenceStorage(o.RefSpecs, refs, remoteRefs, o.Tags) + updated, err := r.updateLocalReferenceStorage(o.RefSpecs, refs, remoteRefs, o.Tags, o.Force) if err != nil { return nil, err } @@ -773,8 +774,11 @@ func (r *Remote) updateLocalReferenceStorage( specs []config.RefSpec, fetchedRefs, remoteRefs memory.ReferenceStorage, tagMode TagMode, + force bool, ) (updated bool, err error) { isWildcard := true + forceNeeded := false + for _, spec := range specs { if !spec.IsWildcard() { isWildcard = false @@ -789,7 +793,23 @@ func (r *Remote) updateLocalReferenceStorage( continue } - new := plumbing.NewHashReference(spec.Dst(ref.Name()), ref.Hash()) + localName := spec.Dst(ref.Name()) + old, _ := storer.ResolveReference(r.s, localName) + new := plumbing.NewHashReference(localName, ref.Hash()) + + // If the ref exists locally as a branch and force is not specified, + // only update if the new ref is an ancestor of the old + if old != nil && old.Name().IsBranch() && !force { + ff, err := isFastForward(r.s, old.Hash(), new.Hash()) + if err != nil { + return updated, err + } + + if !ff { + forceNeeded = true + continue + } + } refUpdated, err := updateReferenceStorerIfNeeded(r.s, new) if err != nil { @@ -819,6 +839,10 @@ func (r *Remote) updateLocalReferenceStorage( updated = true } + if err == nil && forceNeeded { + err = ErrForceNeeded + } + return } diff --git a/worktree.go b/worktree.go index 8ababfa..67d7f08 100644 --- a/worktree.go +++ b/worktree.go @@ -69,6 +69,7 @@ func (w *Worktree) PullContext(ctx context.Context, o *PullOptions) error { Depth: o.Depth, Auth: o.Auth, Progress: o.Progress, + Force: o.Force, }) updated := true |