diff options
Diffstat (limited to 'remote.go')
-rw-r--r-- | remote.go | 78 |
1 files changed, 64 insertions, 14 deletions
@@ -21,7 +21,10 @@ import ( "gopkg.in/src-d/go-git.v4/utils/ioutil" ) -var NoErrAlreadyUpToDate = errors.New("already up-to-date") +var ( + NoErrAlreadyUpToDate = errors.New("already up-to-date") + ErrDeleteRefNotSupported = errors.New("server does not support delete-refs") +) // Remote represents a connection to a remote repository. type Remote struct { @@ -56,7 +59,6 @@ func (r *Remote) Fetch(o *FetchOptions) error { // Push performs a push to the remote. Returns NoErrAlreadyUpToDate if the // remote was already up-to-date. func (r *Remote) Push(o *PushOptions) (err error) { - // TODO: Support deletes. // TODO: Sideband support if o.RemoteName == "" { @@ -88,6 +90,18 @@ func (r *Remote) Push(o *PushOptions) (err error) { return err } + isDelete := false + for _, rs := range o.RefSpecs { + if rs.IsDelete() { + isDelete = true + break + } + } + + if isDelete && !ar.Capabilities.Supports(capability.DeleteRefs) { + return ErrDeleteRefNotSupported + } + req := packp.NewReferenceUpdateRequestFromCapabilities(ar.Capabilities) if err := r.addReferencesToUpdate(o.RefSpecs, remoteRefs, req); err != nil { return err @@ -238,24 +252,60 @@ func (r *Remote) addReferencesToUpdate(refspecs []config.RefSpec, req *packp.ReferenceUpdateRequest) error { for _, rs := range refspecs { - iter, err := r.s.IterReferences() - if err != nil { - return err - } - - err = iter.ForEach(func(ref *plumbing.Reference) error { - return r.addReferenceIfRefSpecMatches( - rs, remoteRefs, ref, req, - ) - }) - if err != nil { - return err + if rs.IsDelete() { + if err := r.deleteReferences(rs, remoteRefs, req); err != nil { + return err + } + } else { + if err := r.addOrUpdateReferences(rs, remoteRefs, req); err != nil { + return err + } } } return nil } +func (r *Remote) addOrUpdateReferences(rs config.RefSpec, + remoteRefs storer.ReferenceStorer, req *packp.ReferenceUpdateRequest) error { + iter, err := r.s.IterReferences() + if err != nil { + return err + } + + return iter.ForEach(func(ref *plumbing.Reference) error { + return r.addReferenceIfRefSpecMatches( + rs, remoteRefs, ref, req, + ) + }) +} + +func (r *Remote) deleteReferences(rs config.RefSpec, + remoteRefs storer.ReferenceStorer, req *packp.ReferenceUpdateRequest) error { + iter, err := remoteRefs.IterReferences() + if err != nil { + return err + } + + return iter.ForEach(func(ref *plumbing.Reference) error { + if ref.Type() != plumbing.HashReference { + return nil + } + + if rs.Dst("") != ref.Name() { + return nil + } + + cmd := &packp.Command{ + Name: ref.Name(), + Old: ref.Hash(), + New: plumbing.ZeroHash, + } + req.Commands = append(req.Commands, cmd) + return nil + }) +} + func (r *Remote) addReferenceIfRefSpecMatches(rs config.RefSpec, remoteRefs storer.ReferenceStorer, localRef *plumbing.Reference, req *packp.ReferenceUpdateRequest) error { |