@@ -90,6 +90,42 @@ export class GitRepository {
9090 }
9191 }
9292
93+ /**
94+ * Checks if the remote repository is empty (has no branches).
95+ * This is useful for migration scenarios where we want to push to an empty external repo.
96+ */
97+ private async isRemoteEmpty ( ) : Promise < boolean > {
98+ try {
99+ // git ls-remote --heads returns nothing if no branches exist
100+ const result = await this . git . listRemote ( [ '--heads' , 'origin' ] )
101+ const isEmpty = result . trim ( ) === ''
102+ if ( isEmpty ) {
103+ this . d . info ( 'Remote repository is empty (no branches found)' )
104+ }
105+ return isEmpty
106+ } catch ( error ) {
107+ // If ls-remote fails, assume remote is not empty to avoid accidental pushes
108+ this . d . warn ( 'Failed to check if remote is empty, assuming not empty:' , getErrorMessage ( error ) )
109+ return false
110+ }
111+ }
112+
113+ /**
114+ * Pushes local content to an empty remote repository.
115+ * Used during migration from internal Gitea to external Git.
116+ */
117+ private async pushToEmptyRemote ( ) : Promise < void > {
118+ try {
119+ this . d . info ( 'Pushing local content to empty remote repository...' )
120+ // Push current branch (main) to origin, setting upstream
121+ await this . git . push ( [ '--set-upstream' , 'origin' , 'main' ] )
122+ this . d . info ( 'Successfully pushed local content to remote repository' )
123+ } catch ( error ) {
124+ this . d . error ( 'Failed to push to empty remote:' , getErrorMessage ( error ) )
125+ throw new OperatorError ( 'Push to empty remote failed' , error as Error )
126+ }
127+ }
128+
93129 private async getChangedFiles ( fromRevision : string , toRevision : string ) : Promise < string [ ] > {
94130 const diffResult = await this . git . diff ( [ `${ fromRevision } ..${ toRevision } ` , '--name-only' ] )
95131 return diffResult . split ( '\n' ) . filter ( ( file ) => file . trim ( ) . length > 0 )
@@ -131,6 +167,21 @@ export class GitRepository {
131167
132168 async syncAndAnalyzeChanges ( ) : Promise < { hasChangesToApply : boolean ; applyTeamsOnly : boolean } > {
133169 try {
170+ // Check if remote is empty (migration to new external repo scenario)
171+ // If empty, push local content to it first
172+ const remoteIsEmpty = await this . isRemoteEmpty ( )
173+ if ( remoteIsEmpty ) {
174+ this . d . info ( 'Detected empty remote repository - pushing local content for migration' )
175+ await this . pushToEmptyRemote ( )
176+ // After pushing, the remote now has our content, continue with normal flow
177+ // Return no changes since we just pushed our current state
178+ this . _lastRevision = await this . getCurrentRevision ( )
179+ return {
180+ hasChangesToApply : false ,
181+ applyTeamsOnly : false ,
182+ }
183+ }
184+
134185 const previousRevision = this . _lastRevision
135186
136187 const newRevision = await this . pull ( )
0 commit comments