fork of go-git with some jj specific features
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.8.0 1054 lines 23 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) (err 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, r.useRefDeltas(ar)) 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) useRefDeltas(ar *packp.AdvRefs) bool { 171 return !ar.Capabilities.Supports(capability.OFSDelta) 172} 173 174func (r *Remote) newReferenceUpdateRequest( 175 o *PushOptions, 176 localRefs []*plumbing.Reference, 177 remoteRefs storer.ReferenceStorer, 178 ar *packp.AdvRefs, 179) (*packp.ReferenceUpdateRequest, error) { 180 req := packp.NewReferenceUpdateRequestFromCapabilities(ar.Capabilities) 181 182 if o.Progress != nil { 183 req.Progress = o.Progress 184 if ar.Capabilities.Supports(capability.Sideband64k) { 185 req.Capabilities.Set(capability.Sideband64k) 186 } else if ar.Capabilities.Supports(capability.Sideband) { 187 req.Capabilities.Set(capability.Sideband) 188 } 189 } 190 191 if err := r.addReferencesToUpdate(o.RefSpecs, localRefs, remoteRefs, req); err != nil { 192 return nil, err 193 } 194 195 return req, nil 196} 197 198func (r *Remote) updateRemoteReferenceStorage( 199 req *packp.ReferenceUpdateRequest, 200 result *packp.ReportStatus, 201) error { 202 203 for _, spec := range r.c.Fetch { 204 for _, c := range req.Commands { 205 if !spec.Match(c.Name) { 206 continue 207 } 208 209 local := spec.Dst(c.Name) 210 ref := plumbing.NewHashReference(local, c.New) 211 switch c.Action() { 212 case packp.Create, packp.Update: 213 if err := r.s.SetReference(ref); err != nil { 214 return err 215 } 216 case packp.Delete: 217 if err := r.s.RemoveReference(local); err != nil { 218 return err 219 } 220 } 221 } 222 } 223 224 return nil 225} 226 227// FetchContext fetches references along with the objects necessary to complete 228// their histories. 229// 230// Returns nil if the operation is successful, NoErrAlreadyUpToDate if there are 231// no changes to be fetched, or an error. 232// 233// The provided Context must be non-nil. If the context expires before the 234// operation is complete, an error is returned. The context only affects to the 235// transport operations. 236func (r *Remote) FetchContext(ctx context.Context, o *FetchOptions) error { 237 _, err := r.fetch(ctx, o) 238 return err 239} 240 241// Fetch fetches references along with the objects necessary to complete their 242// histories. 243// 244// Returns nil if the operation is successful, NoErrAlreadyUpToDate if there are 245// no changes to be fetched, or an error. 246func (r *Remote) Fetch(o *FetchOptions) error { 247 return r.FetchContext(context.Background(), o) 248} 249 250func (r *Remote) fetch(ctx context.Context, o *FetchOptions) (sto storer.ReferenceStorer, err error) { 251 if o.RemoteName == "" { 252 o.RemoteName = r.c.Name 253 } 254 255 if err = o.Validate(); err != nil { 256 return nil, err 257 } 258 259 if len(o.RefSpecs) == 0 { 260 o.RefSpecs = r.c.Fetch 261 } 262 263 s, err := newUploadPackSession(r.c.URLs[0], o.Auth) 264 if err != nil { 265 return nil, err 266 } 267 268 defer ioutil.CheckClose(s, &err) 269 270 ar, err := s.AdvertisedReferences() 271 if err != nil { 272 return nil, err 273 } 274 275 req, err := r.newUploadPackRequest(o, ar) 276 if err != nil { 277 return nil, err 278 } 279 280 remoteRefs, err := ar.AllReferences() 281 if err != nil { 282 return nil, err 283 } 284 285 localRefs, err := r.references() 286 if err != nil { 287 return nil, err 288 } 289 290 refs, err := calculateRefs(o.RefSpecs, remoteRefs, o.Tags) 291 if err != nil { 292 return nil, err 293 } 294 295 req.Wants, err = getWants(r.s, refs) 296 if len(req.Wants) > 0 { 297 req.Haves, err = getHaves(localRefs, remoteRefs, r.s) 298 if err != nil { 299 return nil, err 300 } 301 302 if err = r.fetchPack(ctx, o, s, req); err != nil { 303 return nil, err 304 } 305 } 306 307 updated, err := r.updateLocalReferenceStorage(o.RefSpecs, refs, remoteRefs, o.Tags, o.Force) 308 if err != nil { 309 return nil, err 310 } 311 312 if !updated { 313 return remoteRefs, NoErrAlreadyUpToDate 314 } 315 316 return remoteRefs, nil 317} 318 319func newUploadPackSession(url string, auth transport.AuthMethod) (transport.UploadPackSession, error) { 320 c, ep, err := newClient(url) 321 if err != nil { 322 return nil, err 323 } 324 325 return c.NewUploadPackSession(ep, auth) 326} 327 328func newSendPackSession(url string, auth transport.AuthMethod) (transport.ReceivePackSession, error) { 329 c, ep, err := newClient(url) 330 if err != nil { 331 return nil, err 332 } 333 334 return c.NewReceivePackSession(ep, auth) 335} 336 337func newClient(url string) (transport.Transport, *transport.Endpoint, error) { 338 ep, err := transport.NewEndpoint(url) 339 if err != nil { 340 return nil, nil, err 341 } 342 343 c, err := client.NewClient(ep) 344 if err != nil { 345 return nil, nil, err 346 } 347 348 return c, ep, err 349} 350 351func (r *Remote) fetchPack(ctx context.Context, o *FetchOptions, s transport.UploadPackSession, 352 req *packp.UploadPackRequest) (err error) { 353 354 reader, err := s.UploadPack(ctx, req) 355 if err != nil { 356 return err 357 } 358 359 defer ioutil.CheckClose(reader, &err) 360 361 if err = r.updateShallow(o, reader); err != nil { 362 return err 363 } 364 365 if err = packfile.UpdateObjectStorage(r.s, 366 buildSidebandIfSupported(req.Capabilities, reader, o.Progress), 367 ); err != nil { 368 return err 369 } 370 371 return err 372} 373 374func (r *Remote) addReferencesToUpdate( 375 refspecs []config.RefSpec, 376 localRefs []*plumbing.Reference, 377 remoteRefs storer.ReferenceStorer, 378 req *packp.ReferenceUpdateRequest, 379) error { 380 // This references dictionary will be used to search references by name. 381 refsDict := make(map[string]*plumbing.Reference) 382 for _, ref := range localRefs { 383 refsDict[ref.Name().String()] = ref 384 } 385 386 for _, rs := range refspecs { 387 if rs.IsDelete() { 388 if err := r.deleteReferences(rs, remoteRefs, req); err != nil { 389 return err 390 } 391 } else { 392 err := r.addOrUpdateReferences(rs, localRefs, refsDict, remoteRefs, req) 393 if err != nil { 394 return err 395 } 396 } 397 } 398 399 return nil 400} 401 402func (r *Remote) addOrUpdateReferences( 403 rs config.RefSpec, 404 localRefs []*plumbing.Reference, 405 refsDict map[string]*plumbing.Reference, 406 remoteRefs storer.ReferenceStorer, 407 req *packp.ReferenceUpdateRequest, 408) error { 409 // If it is not a wilcard refspec we can directly search for the reference 410 // in the references dictionary. 411 if !rs.IsWildcard() { 412 ref, ok := refsDict[rs.Src()] 413 if !ok { 414 return nil 415 } 416 417 return r.addReferenceIfRefSpecMatches(rs, remoteRefs, ref, req) 418 } 419 420 for _, ref := range localRefs { 421 err := r.addReferenceIfRefSpecMatches(rs, remoteRefs, ref, req) 422 if err != nil { 423 return err 424 } 425 } 426 427 return nil 428} 429 430func (r *Remote) deleteReferences(rs config.RefSpec, 431 remoteRefs storer.ReferenceStorer, req *packp.ReferenceUpdateRequest) error { 432 iter, err := remoteRefs.IterReferences() 433 if err != nil { 434 return err 435 } 436 437 return iter.ForEach(func(ref *plumbing.Reference) error { 438 if ref.Type() != plumbing.HashReference { 439 return nil 440 } 441 442 if rs.Dst("") != ref.Name() { 443 return nil 444 } 445 446 cmd := &packp.Command{ 447 Name: ref.Name(), 448 Old: ref.Hash(), 449 New: plumbing.ZeroHash, 450 } 451 req.Commands = append(req.Commands, cmd) 452 return nil 453 }) 454} 455 456func (r *Remote) addReferenceIfRefSpecMatches(rs config.RefSpec, 457 remoteRefs storer.ReferenceStorer, localRef *plumbing.Reference, 458 req *packp.ReferenceUpdateRequest) error { 459 460 if localRef.Type() != plumbing.HashReference { 461 return nil 462 } 463 464 if !rs.Match(localRef.Name()) { 465 return nil 466 } 467 468 cmd := &packp.Command{ 469 Name: rs.Dst(localRef.Name()), 470 Old: plumbing.ZeroHash, 471 New: localRef.Hash(), 472 } 473 474 remoteRef, err := remoteRefs.Reference(cmd.Name) 475 if err == nil { 476 if remoteRef.Type() != plumbing.HashReference { 477 //TODO: check actual git behavior here 478 return nil 479 } 480 481 cmd.Old = remoteRef.Hash() 482 } else if err != plumbing.ErrReferenceNotFound { 483 return err 484 } 485 486 if cmd.Old == cmd.New { 487 return nil 488 } 489 490 if !rs.IsForceUpdate() { 491 if err := checkFastForwardUpdate(r.s, remoteRefs, cmd); err != nil { 492 return err 493 } 494 } 495 496 req.Commands = append(req.Commands, cmd) 497 return nil 498} 499 500func (r *Remote) references() ([]*plumbing.Reference, error) { 501 var localRefs []*plumbing.Reference 502 iter, err := r.s.IterReferences() 503 if err != nil { 504 return nil, err 505 } 506 507 for { 508 ref, err := iter.Next() 509 if err == io.EOF { 510 break 511 } 512 513 if err != nil { 514 return nil, err 515 } 516 517 localRefs = append(localRefs, ref) 518 } 519 520 return localRefs, nil 521} 522 523func getRemoteRefsFromStorer(remoteRefStorer storer.ReferenceStorer) ( 524 map[plumbing.Hash]bool, error) { 525 remoteRefs := map[plumbing.Hash]bool{} 526 iter, err := remoteRefStorer.IterReferences() 527 if err != nil { 528 return nil, err 529 } 530 err = iter.ForEach(func(ref *plumbing.Reference) error { 531 if ref.Type() != plumbing.HashReference { 532 return nil 533 } 534 remoteRefs[ref.Hash()] = true 535 return nil 536 }) 537 if err != nil { 538 return nil, err 539 } 540 return remoteRefs, nil 541} 542 543// getHavesFromRef populates the given `haves` map with the given 544// reference, and up to `maxHavesToVisitPerRef` ancestor commits. 545func getHavesFromRef( 546 ref *plumbing.Reference, 547 remoteRefs map[plumbing.Hash]bool, 548 s storage.Storer, 549 haves map[plumbing.Hash]bool, 550) error { 551 h := ref.Hash() 552 if haves[h] { 553 return nil 554 } 555 556 // No need to load the commit if we know the remote already 557 // has this hash. 558 if remoteRefs[h] { 559 haves[h] = true 560 return nil 561 } 562 563 commit, err := object.GetCommit(s, h) 564 if err != nil { 565 // Ignore the error if this isn't a commit. 566 haves[ref.Hash()] = true 567 return nil 568 } 569 570 // Until go-git supports proper commit negotiation during an 571 // upload pack request, include up to `maxHavesToVisitPerRef` 572 // commits from the history of each ref. 573 walker := object.NewCommitPreorderIter(commit, haves, nil) 574 toVisit := maxHavesToVisitPerRef 575 return walker.ForEach(func(c *object.Commit) error { 576 haves[c.Hash] = true 577 toVisit-- 578 // If toVisit starts out at 0 (indicating there is no 579 // max), then it will be negative here and we won't stop 580 // early. 581 if toVisit == 0 || remoteRefs[c.Hash] { 582 return storer.ErrStop 583 } 584 return nil 585 }) 586} 587 588func getHaves( 589 localRefs []*plumbing.Reference, 590 remoteRefStorer storer.ReferenceStorer, 591 s storage.Storer, 592) ([]plumbing.Hash, error) { 593 haves := map[plumbing.Hash]bool{} 594 595 // Build a map of all the remote references, to avoid loading too 596 // many parent commits for references we know don't need to be 597 // transferred. 598 remoteRefs, err := getRemoteRefsFromStorer(remoteRefStorer) 599 if err != nil { 600 return nil, err 601 } 602 603 for _, ref := range localRefs { 604 if haves[ref.Hash()] { 605 continue 606 } 607 608 if ref.Type() != plumbing.HashReference { 609 continue 610 } 611 612 err = getHavesFromRef(ref, remoteRefs, s, haves) 613 if err != nil { 614 return nil, err 615 } 616 } 617 618 var result []plumbing.Hash 619 for h := range haves { 620 result = append(result, h) 621 } 622 623 return result, nil 624} 625 626const refspecAllTags = "+refs/tags/*:refs/tags/*" 627 628func calculateRefs( 629 spec []config.RefSpec, 630 remoteRefs storer.ReferenceStorer, 631 tagMode TagMode, 632) (memory.ReferenceStorage, error) { 633 if tagMode == AllTags { 634 spec = append(spec, refspecAllTags) 635 } 636 637 refs := make(memory.ReferenceStorage) 638 for _, s := range spec { 639 if err := doCalculateRefs(s, remoteRefs, refs); err != nil { 640 return nil, err 641 } 642 } 643 644 return refs, nil 645} 646 647func doCalculateRefs( 648 s config.RefSpec, 649 remoteRefs storer.ReferenceStorer, 650 refs memory.ReferenceStorage, 651) error { 652 iter, err := remoteRefs.IterReferences() 653 if err != nil { 654 return err 655 } 656 657 var matched bool 658 err = iter.ForEach(func(ref *plumbing.Reference) error { 659 if !s.Match(ref.Name()) { 660 return nil 661 } 662 663 if ref.Type() == plumbing.SymbolicReference { 664 target, err := storer.ResolveReference(remoteRefs, ref.Name()) 665 if err != nil { 666 return err 667 } 668 669 ref = plumbing.NewHashReference(ref.Name(), target.Hash()) 670 } 671 672 if ref.Type() != plumbing.HashReference { 673 return nil 674 } 675 676 matched = true 677 if err := refs.SetReference(ref); err != nil { 678 return err 679 } 680 681 if !s.IsWildcard() { 682 return storer.ErrStop 683 } 684 685 return nil 686 }) 687 688 if !matched && !s.IsWildcard() { 689 return fmt.Errorf("couldn't find remote ref %q", s.Src()) 690 } 691 692 return err 693} 694 695func getWants(localStorer storage.Storer, refs memory.ReferenceStorage) ([]plumbing.Hash, error) { 696 wants := map[plumbing.Hash]bool{} 697 for _, ref := range refs { 698 hash := ref.Hash() 699 exists, err := objectExists(localStorer, ref.Hash()) 700 if err != nil { 701 return nil, err 702 } 703 704 if !exists { 705 wants[hash] = true 706 } 707 } 708 709 var result []plumbing.Hash 710 for h := range wants { 711 result = append(result, h) 712 } 713 714 return result, nil 715} 716 717func objectExists(s storer.EncodedObjectStorer, h plumbing.Hash) (bool, error) { 718 _, err := s.EncodedObject(plumbing.AnyObject, h) 719 if err == plumbing.ErrObjectNotFound { 720 return false, nil 721 } 722 723 return true, err 724} 725 726func checkFastForwardUpdate(s storer.EncodedObjectStorer, remoteRefs storer.ReferenceStorer, cmd *packp.Command) error { 727 if cmd.Old == plumbing.ZeroHash { 728 _, err := remoteRefs.Reference(cmd.Name) 729 if err == plumbing.ErrReferenceNotFound { 730 return nil 731 } 732 733 if err != nil { 734 return err 735 } 736 737 return fmt.Errorf("non-fast-forward update: %s", cmd.Name.String()) 738 } 739 740 ff, err := isFastForward(s, cmd.Old, cmd.New) 741 if err != nil { 742 return err 743 } 744 745 if !ff { 746 return fmt.Errorf("non-fast-forward update: %s", cmd.Name.String()) 747 } 748 749 return nil 750} 751 752func isFastForward(s storer.EncodedObjectStorer, old, new plumbing.Hash) (bool, error) { 753 c, err := object.GetCommit(s, new) 754 if err != nil { 755 return false, err 756 } 757 758 found := false 759 iter := object.NewCommitPreorderIter(c, nil, nil) 760 err = iter.ForEach(func(c *object.Commit) error { 761 if c.Hash != old { 762 return nil 763 } 764 765 found = true 766 return storer.ErrStop 767 }) 768 return found, err 769} 770 771func (r *Remote) newUploadPackRequest(o *FetchOptions, 772 ar *packp.AdvRefs) (*packp.UploadPackRequest, error) { 773 774 req := packp.NewUploadPackRequestFromCapabilities(ar.Capabilities) 775 776 if o.Depth != 0 { 777 req.Depth = packp.DepthCommits(o.Depth) 778 if err := req.Capabilities.Set(capability.Shallow); err != nil { 779 return nil, err 780 } 781 } 782 783 if o.Progress == nil && ar.Capabilities.Supports(capability.NoProgress) { 784 if err := req.Capabilities.Set(capability.NoProgress); err != nil { 785 return nil, err 786 } 787 } 788 789 isWildcard := true 790 for _, s := range o.RefSpecs { 791 if !s.IsWildcard() { 792 isWildcard = false 793 break 794 } 795 } 796 797 if isWildcard && o.Tags == TagFollowing && ar.Capabilities.Supports(capability.IncludeTag) { 798 if err := req.Capabilities.Set(capability.IncludeTag); err != nil { 799 return nil, err 800 } 801 } 802 803 return req, nil 804} 805 806func buildSidebandIfSupported(l *capability.List, reader io.Reader, p sideband.Progress) io.Reader { 807 var t sideband.Type 808 809 switch { 810 case l.Supports(capability.Sideband): 811 t = sideband.Sideband 812 case l.Supports(capability.Sideband64k): 813 t = sideband.Sideband64k 814 default: 815 return reader 816 } 817 818 d := sideband.NewDemuxer(t, reader) 819 d.Progress = p 820 821 return d 822} 823 824func (r *Remote) updateLocalReferenceStorage( 825 specs []config.RefSpec, 826 fetchedRefs, remoteRefs memory.ReferenceStorage, 827 tagMode TagMode, 828 force bool, 829) (updated bool, err error) { 830 isWildcard := true 831 forceNeeded := false 832 833 for _, spec := range specs { 834 if !spec.IsWildcard() { 835 isWildcard = false 836 } 837 838 for _, ref := range fetchedRefs { 839 if !spec.Match(ref.Name()) { 840 continue 841 } 842 843 if ref.Type() != plumbing.HashReference { 844 continue 845 } 846 847 localName := spec.Dst(ref.Name()) 848 old, _ := storer.ResolveReference(r.s, localName) 849 new := plumbing.NewHashReference(localName, ref.Hash()) 850 851 // If the ref exists locally as a branch and force is not specified, 852 // only update if the new ref is an ancestor of the old 853 if old != nil && old.Name().IsBranch() && !force && !spec.IsForceUpdate() { 854 ff, err := isFastForward(r.s, old.Hash(), new.Hash()) 855 if err != nil { 856 return updated, err 857 } 858 859 if !ff { 860 forceNeeded = true 861 continue 862 } 863 } 864 865 refUpdated, err := checkAndUpdateReferenceStorerIfNeeded(r.s, new, old) 866 if err != nil { 867 return updated, err 868 } 869 870 if refUpdated { 871 updated = true 872 } 873 } 874 } 875 876 if tagMode == NoTags { 877 return updated, nil 878 } 879 880 tags := fetchedRefs 881 if isWildcard { 882 tags = remoteRefs 883 } 884 tagUpdated, err := r.buildFetchedTags(tags) 885 if err != nil { 886 return updated, err 887 } 888 889 if tagUpdated { 890 updated = true 891 } 892 893 if err == nil && forceNeeded { 894 err = ErrForceNeeded 895 } 896 897 return 898} 899 900func (r *Remote) buildFetchedTags(refs memory.ReferenceStorage) (updated bool, err error) { 901 for _, ref := range refs { 902 if !ref.Name().IsTag() { 903 continue 904 } 905 906 _, err := r.s.EncodedObject(plumbing.AnyObject, ref.Hash()) 907 if err == plumbing.ErrObjectNotFound { 908 continue 909 } 910 911 if err != nil { 912 return false, err 913 } 914 915 refUpdated, err := updateReferenceStorerIfNeeded(r.s, ref) 916 if err != nil { 917 return updated, err 918 } 919 920 if refUpdated { 921 updated = true 922 } 923 } 924 925 return 926} 927 928// List the references on the remote repository. 929func (r *Remote) List(o *ListOptions) (rfs []*plumbing.Reference, err error) { 930 s, err := newUploadPackSession(r.c.URLs[0], o.Auth) 931 if err != nil { 932 return nil, err 933 } 934 935 defer ioutil.CheckClose(s, &err) 936 937 ar, err := s.AdvertisedReferences() 938 if err != nil { 939 return nil, err 940 } 941 942 allRefs, err := ar.AllReferences() 943 if err != nil { 944 return nil, err 945 } 946 947 refs, err := allRefs.IterReferences() 948 if err != nil { 949 return nil, err 950 } 951 952 var resultRefs []*plumbing.Reference 953 refs.ForEach(func(ref *plumbing.Reference) error { 954 resultRefs = append(resultRefs, ref) 955 return nil 956 }) 957 958 return resultRefs, nil 959} 960 961func objectsToPush(commands []*packp.Command) []plumbing.Hash { 962 var objects []plumbing.Hash 963 for _, cmd := range commands { 964 if cmd.New == plumbing.ZeroHash { 965 continue 966 } 967 968 objects = append(objects, cmd.New) 969 } 970 return objects 971} 972 973func referencesToHashes(refs storer.ReferenceStorer) ([]plumbing.Hash, error) { 974 iter, err := refs.IterReferences() 975 if err != nil { 976 return nil, err 977 } 978 979 var hs []plumbing.Hash 980 err = iter.ForEach(func(ref *plumbing.Reference) error { 981 if ref.Type() != plumbing.HashReference { 982 return nil 983 } 984 985 hs = append(hs, ref.Hash()) 986 return nil 987 }) 988 if err != nil { 989 return nil, err 990 } 991 992 return hs, nil 993} 994 995func pushHashes( 996 ctx context.Context, 997 sess transport.ReceivePackSession, 998 s storage.Storer, 999 req *packp.ReferenceUpdateRequest, 1000 hs []plumbing.Hash, 1001 useRefDeltas bool, 1002) (*packp.ReportStatus, error) { 1003 1004 rd, wr := io.Pipe() 1005 req.Packfile = rd 1006 config, err := s.Config() 1007 if err != nil { 1008 return nil, err 1009 } 1010 done := make(chan error) 1011 go func() { 1012 e := packfile.NewEncoder(wr, s, useRefDeltas) 1013 if _, err := e.Encode(hs, config.Pack.Window); err != nil { 1014 done <- wr.CloseWithError(err) 1015 return 1016 } 1017 1018 done <- wr.Close() 1019 }() 1020 1021 rs, err := sess.ReceivePack(ctx, req) 1022 if err != nil { 1023 return nil, err 1024 } 1025 1026 if err := <-done; err != nil { 1027 return nil, err 1028 } 1029 1030 return rs, nil 1031} 1032 1033func (r *Remote) updateShallow(o *FetchOptions, resp *packp.UploadPackResponse) error { 1034 if o.Depth == 0 || len(resp.Shallows) == 0 { 1035 return nil 1036 } 1037 1038 shallows, err := r.s.Shallow() 1039 if err != nil { 1040 return err 1041 } 1042 1043outer: 1044 for _, s := range resp.Shallows { 1045 for _, oldS := range shallows { 1046 if s == oldS { 1047 continue outer 1048 } 1049 } 1050 shallows = append(shallows, s) 1051 } 1052 1053 return r.s.SetShallow(shallows) 1054}