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