aboutsummaryrefslogtreecommitdiffstats
path: root/remote.go
diff options
context:
space:
mode:
Diffstat (limited to 'remote.go')
-rw-r--r--remote.go78
1 files changed, 64 insertions, 14 deletions
diff --git a/remote.go b/remote.go
index 412eb61..7ebb843 100644
--- a/remote.go
+++ b/remote.go
@@ -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 {