@@ -587,69 +587,16 @@ func (e *Executor) getOrUpdateMirrorDir(ctx context.Context, repository string)
587587 return e .updateGitMirror (ctx , repository )
588588}
589589
590- // defaultCheckoutPhase is called by the CheckoutPhase if no global or plugin checkout
591- // hook exists. It performs the default checkout on the Repository provided in the config
592- func (e * Executor ) defaultCheckoutPhase (ctx context.Context ) error {
593- span , _ := tracetools .StartSpanFromContext (ctx , "repo-checkout" , e .TracingBackend )
594- span .AddAttributes (map [string ]string {
595- "checkout.repo_name" : e .Repository ,
596- "checkout.refspec" : e .RefSpec ,
597- "checkout.commit" : e .Commit ,
598- })
599- var err error
600- defer func () { span .FinishWithError (err ) }()
601-
602- if e .SSHKeyscan {
603- addRepositoryHostToSSHKnownHosts (ctx , e .shell , e .Repository )
604- }
605-
606- var mirrorDir string
607-
608- // If we can, get a mirror of the git repository to use for reference later
609- if e .GitMirrorsPath != "" && e .Repository != "" {
610- span .AddAttributes (map [string ]string {"checkout.is_using_git_mirrors" : "true" })
611- mirrorDir , err = e .getOrUpdateMirrorDir (ctx , e .Repository )
612- if err != nil {
613- return fmt .Errorf ("getting/updating git mirror: %w" , err )
614- }
615-
616- e .shell .Env .Set ("BUILDKITE_REPO_MIRROR" , mirrorDir )
617- }
618-
619- // Make sure the build directory exists and that we change directory into it
620- if err := e .createCheckoutDir (); err != nil {
621- return fmt .Errorf ("creating checkout dir: %w" , err )
622- }
623-
624- gitCloneFlags := e .GitCloneFlags
625- if mirrorDir != "" {
626- gitCloneFlags += fmt .Sprintf (" --reference %q" , mirrorDir )
627- }
628-
629- // Does the git directory exist?
630- existingGitDir := filepath .Join (e .shell .Getwd (), ".git" )
631- if osutil .FileExists (existingGitDir ) {
632- // Update the origin of the repository so we can gracefully handle
633- // repository renames
634- if _ , err := e .updateRemoteURL (ctx , "" , e .Repository ); err != nil {
635- return fmt .Errorf ("setting origin: %w" , err )
636- }
637- } else {
638- if err := gitClone (ctx , e .shell , gitCloneFlags , e .Repository , "." ); err != nil {
639- return fmt .Errorf ("cloning git repository: %w" , err )
640- }
641- }
642-
643- // Git clean prior to checkout, we do this even if submodules have been
644- // disabled to ensure previous submodules are cleaned up
645- if hasGitSubmodules (e .shell ) {
646- if err := gitCleanSubmodules (ctx , e .shell , e .GitCleanFlags ); err != nil {
647- return fmt .Errorf ("cleaning git submodules: %w" , err )
648- }
649- }
650-
651- if err := gitClean (ctx , e .shell , e .GitCleanFlags ); err != nil {
652- return fmt .Errorf ("cleaning git repository: %w" , err )
590+ // fetchSource fetches the git source for the job. If GitSkipFetchExistingCommits is
591+ // enabled and the commit already exists locally, the fetch is skipped entirely.
592+ func (e * Executor ) fetchSource (ctx context.Context ) error {
593+ // If configured, skip the fetch when the commit already exists locally.
594+ // This is useful when a pre-populated git mirror is used with --reference,
595+ // as the commit objects are already reachable and fetching is redundant.
596+ if e .GitSkipFetchExistingCommits && e .Commit != "HEAD" &&
597+ hasGitCommit (ctx , e .shell , ".git" , e .Commit ) {
598+ e .shell .Commentf ("Commit %q already exists locally, skipping fetch" , e .Commit )
599+ return nil
653600 }
654601
655602 gitFetchFlags := e .GitFetchFlags
@@ -738,6 +685,78 @@ func (e *Executor) defaultCheckoutPhase(ctx context.Context) error {
738685 }
739686 }
740687
688+ return nil
689+ }
690+
691+ // defaultCheckoutPhase is called by the CheckoutPhase if no global or plugin checkout
692+ // hook exists. It performs the default checkout on the Repository provided in the config
693+ func (e * Executor ) defaultCheckoutPhase (ctx context.Context ) error {
694+ span , _ := tracetools .StartSpanFromContext (ctx , "repo-checkout" , e .TracingBackend )
695+ span .AddAttributes (map [string ]string {
696+ "checkout.repo_name" : e .Repository ,
697+ "checkout.refspec" : e .RefSpec ,
698+ "checkout.commit" : e .Commit ,
699+ })
700+ var err error
701+ defer func () { span .FinishWithError (err ) }()
702+
703+ if e .SSHKeyscan {
704+ addRepositoryHostToSSHKnownHosts (ctx , e .shell , e .Repository )
705+ }
706+
707+ var mirrorDir string
708+
709+ // If we can, get a mirror of the git repository to use for reference later
710+ if e .GitMirrorsPath != "" && e .Repository != "" {
711+ span .AddAttributes (map [string ]string {"checkout.is_using_git_mirrors" : "true" })
712+ mirrorDir , err = e .getOrUpdateMirrorDir (ctx , e .Repository )
713+ if err != nil {
714+ return fmt .Errorf ("getting/updating git mirror: %w" , err )
715+ }
716+
717+ e .shell .Env .Set ("BUILDKITE_REPO_MIRROR" , mirrorDir )
718+ }
719+
720+ // Make sure the build directory exists and that we change directory into it
721+ if err := e .createCheckoutDir (); err != nil {
722+ return fmt .Errorf ("creating checkout dir: %w" , err )
723+ }
724+
725+ gitCloneFlags := e .GitCloneFlags
726+ if mirrorDir != "" {
727+ gitCloneFlags += fmt .Sprintf (" --reference %q" , mirrorDir )
728+ }
729+
730+ // Does the git directory exist?
731+ existingGitDir := filepath .Join (e .shell .Getwd (), ".git" )
732+ if osutil .FileExists (existingGitDir ) {
733+ // Update the origin of the repository so we can gracefully handle
734+ // repository renames
735+ if _ , err := e .updateRemoteURL (ctx , "" , e .Repository ); err != nil {
736+ return fmt .Errorf ("setting origin: %w" , err )
737+ }
738+ } else {
739+ if err := gitClone (ctx , e .shell , gitCloneFlags , e .Repository , "." ); err != nil {
740+ return fmt .Errorf ("cloning git repository: %w" , err )
741+ }
742+ }
743+
744+ // Git clean prior to checkout, we do this even if submodules have been
745+ // disabled to ensure previous submodules are cleaned up
746+ if hasGitSubmodules (e .shell ) {
747+ if err := gitCleanSubmodules (ctx , e .shell , e .GitCleanFlags ); err != nil {
748+ return fmt .Errorf ("cleaning git submodules: %w" , err )
749+ }
750+ }
751+
752+ if err := gitClean (ctx , e .shell , e .GitCleanFlags ); err != nil {
753+ return fmt .Errorf ("cleaning git repository: %w" , err )
754+ }
755+
756+ if err := e .fetchSource (ctx ); err != nil {
757+ return err
758+ }
759+
741760 gitCheckoutFlags := e .GitCheckoutFlags
742761
743762 if e .Commit == "HEAD" {
0 commit comments