fork of go-git with some jj specific features
at v4.2.0 21 kB view raw
1package git 2 3import ( 4 "context" 5 "errors" 6 "fmt" 7 "io" 8 9 "gopkg.in/src-d/go-git.v4/config" 10 "gopkg.in/src-d/go-git.v4/plumbing" 11 "gopkg.in/src-d/go-git.v4/plumbing/format/packfile" 12 "gopkg.in/src-d/go-git.v4/plumbing/object" 13 "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp" 14 "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/capability" 15 "gopkg.in/src-d/go-git.v4/plumbing/protocol/packp/sideband" 16 "gopkg.in/src-d/go-git.v4/plumbing/revlist" 17 "gopkg.in/src-d/go-git.v4/plumbing/storer" 18 "gopkg.in/src-d/go-git.v4/plumbing/transport" 19 "gopkg.in/src-d/go-git.v4/plumbing/transport/client" 20 "gopkg.in/src-d/go-git.v4/storage" 21 "gopkg.in/src-d/go-git.v4/storage/memory" 22 "gopkg.in/src-d/go-git.v4/utils/ioutil" 23) 24 25var ( 26 NoErrAlreadyUpToDate = errors.New("already up-to-date") 27 ErrDeleteRefNotSupported = errors.New("server does not support delete-refs") 28 ErrForceNeeded = errors.New("some refs were not updated") 29) 30 31const ( 32 // This describes the maximum number of commits to walk when 33 // computing the haves to send to a server, for each ref in the 34 // repo containing this remote, when not using the multi-ack 35 // protocol. Setting this to 0 means there is no limit. 36 maxHavesToVisitPerRef = 100 37) 38 39// Remote represents a connection to a remote repository. 40type Remote struct { 41 c *config.RemoteConfig 42 s storage.Storer 43} 44 45func newRemote(s storage.Storer, c *config.RemoteConfig) *Remote { 46 return &Remote{s: s, c: c} 47} 48 49// Config returns the RemoteConfig object used to instantiate this Remote. 50func (r *Remote) Config() *config.RemoteConfig { 51 return r.c 52} 53 54func (r *Remote) String() string { 55 var fetch, push string 56 if len(r.c.URLs) > 0 { 57 fetch = r.c.URLs[0] 58 push = r.c.URLs[0] 59 } 60 61 return fmt.Sprintf("%s\t%s (fetch)\n%[1]s\t%[3]s (push)", r.c.Name, fetch, push) 62} 63 64// Push performs a push to the remote. Returns NoErrAlreadyUpToDate if the 65// remote was already up-to-date. 66func (r *Remote) Push(o *PushOptions) error { 67 return r.PushContext(context.Background(), o) 68} 69 70// PushContext performs a push to the remote. Returns NoErrAlreadyUpToDate if 71// the remote was already up-to-date. 72// 73// The provided Context must be non-nil. If the context expires before the 74// operation is complete, an error is returned. The context only affects to the 75// transport operations. 76func (r *Remote) PushContext(ctx context.Context, o *PushOptions) error { 77 if err := o.Validate(); err != nil { 78 return err 79 } 80 81 if o.RemoteName != r.c.Name { 82 return fmt.Errorf("remote names don't match: %s != %s", o.RemoteName, r.c.Name) 83 } 84 85 s, err := newSendPackSession(r.c.URLs[0], o.Auth) 86 if err != nil { 87 return err 88 } 89 90 defer ioutil.CheckClose(s, &err) 91 92 ar, err := s.AdvertisedReferences() 93 if err != nil { 94 return err 95 } 96 97 remoteRefs, err := ar.AllReferences() 98 if err != nil { 99 return err 100 } 101 102 isDelete := false 103 allDelete := true 104 for _, rs := range o.RefSpecs { 105 if rs.IsDelete() { 106 isDelete = true 107 } else { 108 allDelete = false 109 } 110 if isDelete && !allDelete { 111 break 112 } 113 } 114 115 if isDelete && !ar.Capabilities.Supports(capability.DeleteRefs) { 116 return ErrDeleteRefNotSupported 117 } 118 119 localRefs, err := r.references() 120 if err != nil { 121 return err 122 } 123 124 req, err := r.newReferenceUpdateRequest(o, localRefs, remoteRefs, ar) 125 if err != nil { 126 return err 127 } 128 129 if len(req.Commands) == 0 { 130 return NoErrAlreadyUpToDate 131 } 132 133 objects := objectsToPush(req.Commands) 134 135 haves, err := referencesToHashes(remoteRefs) 136 if err != nil { 137 return err 138 } 139 140 stop, err := r.s.Shallow() 141 if err != nil { 142 return err 143 } 144 145 // if we have shallow we should include this as part of the objects that 146 // we are aware. 147 haves = append(haves, stop...) 148 149 var hashesToPush []plumbing.Hash 150 // Avoid the expensive revlist operation if we're only doing deletes. 151 if !allDelete { 152 hashesToPush, err = revlist.Objects(r.s, objects, haves) 153 if err != nil { 154 return err 155 } 156 } 157 158 rs, err := pushHashes(ctx, s, r.s, req, hashesToPush) 159 if err != nil { 160 return err 161 } 162 163 if err = rs.Error(); err != nil { 164 return err 165 } 166 167 return r.updateRemoteReferenceStorage(req, rs) 168} 169 170func (r *Remote) newReferenceUpdateRequest( 171 o *PushOptions, 172 localRefs []*plumbing.Reference, 173 remoteRefs storer.ReferenceStorer, 174 ar *packp.AdvRefs, 175) (*packp.ReferenceUpdateRequest, error) { 176 req := packp.NewReferenceUpdateRequestFromCapabilities(ar.Capabilities) 177 178 if o.Progress != nil { 179 req.Progress = o.Progress 180 if ar.Capabilities.Supports(capability.Sideband64k) { 181 req.Capabilities.Set(capability.Sideband64k) 182 } else if ar.Capabilities.Supports(capability.Sideband) { 183 req.Capabilities.Set(capability.Sideband) 184 } 185 } 186 187 if err := r.addReferencesToUpdate(o.RefSpecs, localRefs, remoteRefs, req); err != nil { 188 return nil, err 189 } 190 191 return req, nil 192} 193 194func (r *Remote) updateRemoteReferenceStorage( 195 req *packp.ReferenceUpdateRequest, 196 result *packp.ReportStatus, 197) error { 198 199 for _, spec := range r.c.Fetch { 200 for _, c := range req.Commands { 201 if !spec.Match(c.Name) { 202 continue 203 } 204 205 local := spec.Dst(c.Name) 206 ref := plumbing.NewHashReference(local, c.New) 207 switch c.Action() { 208 case packp.Create, packp.Update: 209 if err := r.s.SetReference(ref); err != nil { 210 return err 211 } 212 case packp.Delete: 213 if err := r.s.RemoveReference(local); err != nil { 214 return err 215 } 216 } 217 } 218 } 219 220 return nil 221} 222 223// FetchContext fetches references along with the objects necessary to complete 224// their histories. 225// 226// Returns nil if the operation is successful, NoErrAlreadyUpToDate if there are 227// no changes to be fetched, or an error. 228// 229// The provided Context must be non-nil. If the context expires before the 230// operation is complete, an error is returned. The context only affects to the 231// transport operations. 232func (r *Remote) FetchContext(ctx context.Context, o *FetchOptions) error { 233 _, err := r.fetch(ctx, o) 234 return err 235} 236 237// Fetch fetches references along with the objects necessary to complete their 238// histories. 239// 240// Returns nil if the operation is successful, NoErrAlreadyUpToDate if there are 241// no changes to be fetched, or an error. 242func (r *Remote) Fetch(o *FetchOptions) error { 243 return r.FetchContext(context.Background(), o) 244} 245 246func (r *Remote) fetch(ctx context.Context, o *FetchOptions) (storer.ReferenceStorer, error) { 247 if o.RemoteName == "" { 248 o.RemoteName = r.c.Name 249 } 250 251 if err := o.Validate(); err != nil { 252 return nil, err 253 } 254 255 if len(o.RefSpecs) == 0 { 256 o.RefSpecs = r.c.Fetch 257 } 258 259 s, err := newUploadPackSession(r.c.URLs[0], o.Auth) 260 if err != nil { 261 return nil, err 262 } 263 264 defer ioutil.CheckClose(s, &err) 265 266 ar, err := s.AdvertisedReferences() 267 if err != nil { 268 return nil, err 269 } 270 271 req, err := r.newUploadPackRequest(o, ar) 272 if err != nil { 273 return nil, err 274 } 275 276 remoteRefs, err := ar.AllReferences() 277 if err != nil { 278 return nil, err 279 } 280 281 localRefs, err := r.references() 282 if err != nil { 283 return nil, err 284 } 285 286 refs, err := calculateRefs(o.RefSpecs, remoteRefs, o.Tags) 287 if err != nil { 288 return nil, err 289 } 290 291 req.Wants, err = getWants(r.s, refs) 292 if len(req.Wants) > 0 { 293 req.Haves, err = getHaves(localRefs, remoteRefs, r.s) 294 if err != nil { 295 return nil, err 296 } 297 298 if err := r.fetchPack(ctx, o, s, req); err != nil { 299 return nil, err 300 } 301 } 302 303 updated, err := r.updateLocalReferenceStorage(o.RefSpecs, refs, remoteRefs, o.Tags, o.Force) 304 if err != nil { 305 return nil, err 306 } 307 308 if !updated { 309 return remoteRefs, NoErrAlreadyUpToDate 310 } 311 312 return remoteRefs, nil 313} 314 315func newUploadPackSession(url string, auth transport.AuthMethod) (transport.UploadPackSession, error) { 316 c, ep, err := newClient(url) 317 if err != nil { 318 return nil, err 319 } 320 321 return c.NewUploadPackSession(ep, auth) 322} 323 324func newSendPackSession(url string, auth transport.AuthMethod) (transport.ReceivePackSession, error) { 325 c, ep, err := newClient(url) 326 if err != nil { 327 return nil, err 328 } 329 330 return c.NewReceivePackSession(ep, auth) 331} 332 333func newClient(url string) (transport.Transport, *transport.Endpoint, error) { 334 ep, err := transport.NewEndpoint(url) 335 if err != nil { 336 return nil, nil, err 337 } 338 339 c, err := client.NewClient(ep) 340 if err != nil { 341 return nil, nil, err 342 } 343 344 return c, ep, err 345} 346 347func (r *Remote) fetchPack(ctx context.Context, o *FetchOptions, s transport.UploadPackSession, 348 req *packp.UploadPackRequest) (err error) { 349 350 reader, err := s.UploadPack(ctx, req) 351 if err != nil { 352 return err 353 } 354 355 defer ioutil.CheckClose(reader, &err) 356 357 if err := r.updateShallow(o, reader); err != nil { 358 return err 359 } 360 361 if err = packfile.UpdateObjectStorage(r.s, 362 buildSidebandIfSupported(req.Capabilities, reader, o.Progress), 363 ); err != nil { 364 return err 365 } 366 367 return err 368} 369 370func (r *Remote) addReferencesToUpdate( 371 refspecs []config.RefSpec, 372 localRefs []*plumbing.Reference, 373 remoteRefs storer.ReferenceStorer, 374 req *packp.ReferenceUpdateRequest) error { 375 for _, rs := range refspecs { 376 if rs.IsDelete() { 377 if err := r.deleteReferences(rs, remoteRefs, req); err != nil { 378 return err 379 } 380 } else { 381 if err := r.addOrUpdateReferences(rs, localRefs, remoteRefs, req); err != nil { 382 return err 383 } 384 } 385 } 386 387 return nil 388} 389 390func (r *Remote) addOrUpdateReferences( 391 rs config.RefSpec, 392 localRefs []*plumbing.Reference, 393 remoteRefs storer.ReferenceStorer, 394 req *packp.ReferenceUpdateRequest, 395) error { 396 for _, ref := range localRefs { 397 err := r.addReferenceIfRefSpecMatches(rs, remoteRefs, ref, req) 398 if err != nil { 399 return err 400 } 401 } 402 403 return nil 404} 405 406func (r *Remote) deleteReferences(rs config.RefSpec, 407 remoteRefs storer.ReferenceStorer, req *packp.ReferenceUpdateRequest) error { 408 iter, err := remoteRefs.IterReferences() 409 if err != nil { 410 return err 411 } 412 413 return iter.ForEach(func(ref *plumbing.Reference) error { 414 if ref.Type() != plumbing.HashReference { 415 return nil 416 } 417 418 if rs.Dst("") != ref.Name() { 419 return nil 420 } 421 422 cmd := &packp.Command{ 423 Name: ref.Name(), 424 Old: ref.Hash(), 425 New: plumbing.ZeroHash, 426 } 427 req.Commands = append(req.Commands, cmd) 428 return nil 429 }) 430} 431 432func (r *Remote) addReferenceIfRefSpecMatches(rs config.RefSpec, 433 remoteRefs storer.ReferenceStorer, localRef *plumbing.Reference, 434 req *packp.ReferenceUpdateRequest) error { 435 436 if localRef.Type() != plumbing.HashReference { 437 return nil 438 } 439 440 if !rs.Match(localRef.Name()) { 441 return nil 442 } 443 444 cmd := &packp.Command{ 445 Name: rs.Dst(localRef.Name()), 446 Old: plumbing.ZeroHash, 447 New: localRef.Hash(), 448 } 449 450 remoteRef, err := remoteRefs.Reference(cmd.Name) 451 if err == nil { 452 if remoteRef.Type() != plumbing.HashReference { 453 //TODO: check actual git behavior here 454 return nil 455 } 456 457 cmd.Old = remoteRef.Hash() 458 } else if err != plumbing.ErrReferenceNotFound { 459 return err 460 } 461 462 if cmd.Old == cmd.New { 463 return nil 464 } 465 466 if !rs.IsForceUpdate() { 467 if err := checkFastForwardUpdate(r.s, remoteRefs, cmd); err != nil { 468 return err 469 } 470 } 471 472 req.Commands = append(req.Commands, cmd) 473 return nil 474} 475 476func (r *Remote) references() ([]*plumbing.Reference, error) { 477 var localRefs []*plumbing.Reference 478 iter, err := r.s.IterReferences() 479 if err != nil { 480 return nil, err 481 } 482 483 for { 484 ref, err := iter.Next() 485 if err == io.EOF { 486 break 487 } 488 489 if err != nil { 490 return nil, err 491 } 492 493 localRefs = append(localRefs, ref) 494 } 495 496 return localRefs, nil 497} 498 499func getRemoteRefsFromStorer(remoteRefStorer storer.ReferenceStorer) ( 500 map[plumbing.Hash]bool, error) { 501 remoteRefs := map[plumbing.Hash]bool{} 502 iter, err := remoteRefStorer.IterReferences() 503 if err != nil { 504 return nil, err 505 } 506 err = iter.ForEach(func(ref *plumbing.Reference) error { 507 if ref.Type() != plumbing.HashReference { 508 return nil 509 } 510 remoteRefs[ref.Hash()] = true 511 return nil 512 }) 513 if err != nil { 514 return nil, err 515 } 516 return remoteRefs, nil 517} 518 519// getHavesFromRef populates the given `haves` map with the given 520// reference, and up to `maxHavesToVisitPerRef` ancestor commits. 521func getHavesFromRef( 522 ref *plumbing.Reference, 523 remoteRefs map[plumbing.Hash]bool, 524 s storage.Storer, 525 haves map[plumbing.Hash]bool, 526) error { 527 h := ref.Hash() 528 if haves[h] { 529 return nil 530 } 531 532 // No need to load the commit if we know the remote already 533 // has this hash. 534 if remoteRefs[h] { 535 haves[h] = true 536 return nil 537 } 538 539 commit, err := object.GetCommit(s, h) 540 if err != nil { 541 // Ignore the error if this isn't a commit. 542 haves[ref.Hash()] = true 543 return nil 544 } 545 546 // Until go-git supports proper commit negotiation during an 547 // upload pack request, include up to `maxHavesToVisitPerRef` 548 // commits from the history of each ref. 549 walker := object.NewCommitPreorderIter(commit, haves, nil) 550 toVisit := maxHavesToVisitPerRef 551 return walker.ForEach(func(c *object.Commit) error { 552 haves[c.Hash] = true 553 toVisit-- 554 // If toVisit starts out at 0 (indicating there is no 555 // max), then it will be negative here and we won't stop 556 // early. 557 if toVisit == 0 || remoteRefs[c.Hash] { 558 return storer.ErrStop 559 } 560 return nil 561 }) 562} 563 564func getHaves( 565 localRefs []*plumbing.Reference, 566 remoteRefStorer storer.ReferenceStorer, 567 s storage.Storer, 568) ([]plumbing.Hash, error) { 569 haves := map[plumbing.Hash]bool{} 570 571 // Build a map of all the remote references, to avoid loading too 572 // many parent commits for references we know don't need to be 573 // transferred. 574 remoteRefs, err := getRemoteRefsFromStorer(remoteRefStorer) 575 if err != nil { 576 return nil, err 577 } 578 579 for _, ref := range localRefs { 580 if haves[ref.Hash()] { 581 continue 582 } 583 584 if ref.Type() != plumbing.HashReference { 585 continue 586 } 587 588 err = getHavesFromRef(ref, remoteRefs, s, haves) 589 if err != nil { 590 return nil, err 591 } 592 } 593 594 var result []plumbing.Hash 595 for h := range haves { 596 result = append(result, h) 597 } 598 599 return result, nil 600} 601 602const refspecTag = "+refs/tags/*:refs/tags/*" 603 604func calculateRefs( 605 spec []config.RefSpec, 606 remoteRefs storer.ReferenceStorer, 607 tagMode TagMode, 608) (memory.ReferenceStorage, error) { 609 if tagMode == AllTags { 610 spec = append(spec, refspecTag) 611 } 612 613 iter, err := remoteRefs.IterReferences() 614 if err != nil { 615 return nil, err 616 } 617 618 refs := make(memory.ReferenceStorage) 619 return refs, iter.ForEach(func(ref *plumbing.Reference) error { 620 if !config.MatchAny(spec, ref.Name()) { 621 return nil 622 } 623 624 if ref.Type() == plumbing.SymbolicReference { 625 target, err := storer.ResolveReference(remoteRefs, ref.Name()) 626 if err != nil { 627 return err 628 } 629 630 ref = plumbing.NewHashReference(ref.Name(), target.Hash()) 631 } 632 633 if ref.Type() != plumbing.HashReference { 634 return nil 635 } 636 637 return refs.SetReference(ref) 638 }) 639} 640 641func getWants(localStorer storage.Storer, refs memory.ReferenceStorage) ([]plumbing.Hash, error) { 642 wants := map[plumbing.Hash]bool{} 643 for _, ref := range refs { 644 hash := ref.Hash() 645 exists, err := objectExists(localStorer, ref.Hash()) 646 if err != nil { 647 return nil, err 648 } 649 650 if !exists { 651 wants[hash] = true 652 } 653 } 654 655 var result []plumbing.Hash 656 for h := range wants { 657 result = append(result, h) 658 } 659 660 return result, nil 661} 662 663func objectExists(s storer.EncodedObjectStorer, h plumbing.Hash) (bool, error) { 664 _, err := s.EncodedObject(plumbing.AnyObject, h) 665 if err == plumbing.ErrObjectNotFound { 666 return false, nil 667 } 668 669 return true, err 670} 671 672func checkFastForwardUpdate(s storer.EncodedObjectStorer, remoteRefs storer.ReferenceStorer, cmd *packp.Command) error { 673 if cmd.Old == plumbing.ZeroHash { 674 _, err := remoteRefs.Reference(cmd.Name) 675 if err == plumbing.ErrReferenceNotFound { 676 return nil 677 } 678 679 if err != nil { 680 return err 681 } 682 683 return fmt.Errorf("non-fast-forward update: %s", cmd.Name.String()) 684 } 685 686 ff, err := isFastForward(s, cmd.Old, cmd.New) 687 if err != nil { 688 return err 689 } 690 691 if !ff { 692 return fmt.Errorf("non-fast-forward update: %s", cmd.Name.String()) 693 } 694 695 return nil 696} 697 698func isFastForward(s storer.EncodedObjectStorer, old, new plumbing.Hash) (bool, error) { 699 c, err := object.GetCommit(s, new) 700 if err != nil { 701 return false, err 702 } 703 704 found := false 705 iter := object.NewCommitPreorderIter(c, nil, nil) 706 err = iter.ForEach(func(c *object.Commit) error { 707 if c.Hash != old { 708 return nil 709 } 710 711 found = true 712 return storer.ErrStop 713 }) 714 return found, err 715} 716 717func (r *Remote) newUploadPackRequest(o *FetchOptions, 718 ar *packp.AdvRefs) (*packp.UploadPackRequest, error) { 719 720 req := packp.NewUploadPackRequestFromCapabilities(ar.Capabilities) 721 722 if o.Depth != 0 { 723 req.Depth = packp.DepthCommits(o.Depth) 724 if err := req.Capabilities.Set(capability.Shallow); err != nil { 725 return nil, err 726 } 727 } 728 729 if o.Progress == nil && ar.Capabilities.Supports(capability.NoProgress) { 730 if err := req.Capabilities.Set(capability.NoProgress); err != nil { 731 return nil, err 732 } 733 } 734 735 isWildcard := true 736 for _, s := range o.RefSpecs { 737 if !s.IsWildcard() { 738 isWildcard = false 739 break 740 } 741 } 742 743 if isWildcard && o.Tags == TagFollowing && ar.Capabilities.Supports(capability.IncludeTag) { 744 if err := req.Capabilities.Set(capability.IncludeTag); err != nil { 745 return nil, err 746 } 747 } 748 749 return req, nil 750} 751 752func buildSidebandIfSupported(l *capability.List, reader io.Reader, p sideband.Progress) io.Reader { 753 var t sideband.Type 754 755 switch { 756 case l.Supports(capability.Sideband): 757 t = sideband.Sideband 758 case l.Supports(capability.Sideband64k): 759 t = sideband.Sideband64k 760 default: 761 return reader 762 } 763 764 d := sideband.NewDemuxer(t, reader) 765 d.Progress = p 766 767 return d 768} 769 770func (r *Remote) updateLocalReferenceStorage( 771 specs []config.RefSpec, 772 fetchedRefs, remoteRefs memory.ReferenceStorage, 773 tagMode TagMode, 774 force bool, 775) (updated bool, err error) { 776 isWildcard := true 777 forceNeeded := false 778 779 for _, spec := range specs { 780 if !spec.IsWildcard() { 781 isWildcard = false 782 } 783 784 for _, ref := range fetchedRefs { 785 if !spec.Match(ref.Name()) { 786 continue 787 } 788 789 if ref.Type() != plumbing.HashReference { 790 continue 791 } 792 793 localName := spec.Dst(ref.Name()) 794 old, _ := storer.ResolveReference(r.s, localName) 795 new := plumbing.NewHashReference(localName, ref.Hash()) 796 797 // If the ref exists locally as a branch and force is not specified, 798 // only update if the new ref is an ancestor of the old 799 if old != nil && old.Name().IsBranch() && !force && !spec.IsForceUpdate() { 800 ff, err := isFastForward(r.s, old.Hash(), new.Hash()) 801 if err != nil { 802 return updated, err 803 } 804 805 if !ff { 806 forceNeeded = true 807 continue 808 } 809 } 810 811 refUpdated, err := checkAndUpdateReferenceStorerIfNeeded(r.s, new, old) 812 if err != nil { 813 return updated, err 814 } 815 816 if refUpdated { 817 updated = true 818 } 819 } 820 } 821 822 if tagMode == NoTags { 823 return updated, nil 824 } 825 826 tags := fetchedRefs 827 if isWildcard { 828 tags = remoteRefs 829 } 830 tagUpdated, err := r.buildFetchedTags(tags) 831 if err != nil { 832 return updated, err 833 } 834 835 if tagUpdated { 836 updated = true 837 } 838 839 if err == nil && forceNeeded { 840 err = ErrForceNeeded 841 } 842 843 return 844} 845 846func (r *Remote) buildFetchedTags(refs memory.ReferenceStorage) (updated bool, err error) { 847 for _, ref := range refs { 848 if !ref.Name().IsTag() { 849 continue 850 } 851 852 _, err := r.s.EncodedObject(plumbing.AnyObject, ref.Hash()) 853 if err == plumbing.ErrObjectNotFound { 854 continue 855 } 856 857 if err != nil { 858 return false, err 859 } 860 861 refUpdated, err := updateReferenceStorerIfNeeded(r.s, ref) 862 if err != nil { 863 return updated, err 864 } 865 866 if refUpdated { 867 updated = true 868 } 869 } 870 871 return 872} 873 874// List the references on the remote repository. 875func (r *Remote) List(o *ListOptions) ([]*plumbing.Reference, error) { 876 s, err := newUploadPackSession(r.c.URLs[0], o.Auth) 877 if err != nil { 878 return nil, err 879 } 880 881 defer ioutil.CheckClose(s, &err) 882 883 ar, err := s.AdvertisedReferences() 884 if err != nil { 885 return nil, err 886 } 887 888 allRefs, err := ar.AllReferences() 889 if err != nil { 890 return nil, err 891 } 892 893 refs, err := allRefs.IterReferences() 894 if err != nil { 895 return nil, err 896 } 897 898 var resultRefs []*plumbing.Reference 899 refs.ForEach(func(ref *plumbing.Reference) error { 900 resultRefs = append(resultRefs, ref) 901 return nil 902 }) 903 904 return resultRefs, nil 905} 906 907func objectsToPush(commands []*packp.Command) []plumbing.Hash { 908 var objects []plumbing.Hash 909 for _, cmd := range commands { 910 if cmd.New == plumbing.ZeroHash { 911 continue 912 } 913 914 objects = append(objects, cmd.New) 915 } 916 return objects 917} 918 919func referencesToHashes(refs storer.ReferenceStorer) ([]plumbing.Hash, error) { 920 iter, err := refs.IterReferences() 921 if err != nil { 922 return nil, err 923 } 924 925 var hs []plumbing.Hash 926 err = iter.ForEach(func(ref *plumbing.Reference) error { 927 if ref.Type() != plumbing.HashReference { 928 return nil 929 } 930 931 hs = append(hs, ref.Hash()) 932 return nil 933 }) 934 if err != nil { 935 return nil, err 936 } 937 938 return hs, nil 939} 940 941func pushHashes( 942 ctx context.Context, 943 sess transport.ReceivePackSession, 944 s storage.Storer, 945 req *packp.ReferenceUpdateRequest, 946 hs []plumbing.Hash, 947) (*packp.ReportStatus, error) { 948 949 rd, wr := io.Pipe() 950 req.Packfile = rd 951 config, err := s.Config() 952 if err != nil { 953 return nil, err 954 } 955 done := make(chan error) 956 go func() { 957 e := packfile.NewEncoder(wr, s, false) 958 if _, err := e.Encode(hs, config.Pack.Window); err != nil { 959 done <- wr.CloseWithError(err) 960 return 961 } 962 963 done <- wr.Close() 964 }() 965 966 rs, err := sess.ReceivePack(ctx, req) 967 if err != nil { 968 return nil, err 969 } 970 971 if err := <-done; err != nil { 972 return nil, err 973 } 974 975 return rs, nil 976} 977 978func (r *Remote) updateShallow(o *FetchOptions, resp *packp.UploadPackResponse) error { 979 if o.Depth == 0 { 980 return nil 981 } 982 983 return r.s.SetShallow(resp.Shallows) 984}