@@ -18,7 +18,7 @@ type BatchOutcome = 'done' | 'unchanged' | 'conflict';
1818type PlanClassification = { kind : 'addition' | 'modification' | 'move' | 'unchanged' | 'conflict' | 'skip' ; movedFrom ?: string } ;
1919
2020/** A file classified as needing a push, queued for the grouped batch-commit call. */
21- type ToPushEntry = { path : string ; name : string ; repoPath : string ; content : string | ArrayBuffer ; existingSha ?: string } ;
21+ type ToPushEntry = { path : string ; name : string ; repoPath : string ; content : string | ArrayBuffer ; existingSha ?: string ; existingRevision ?: string } ;
2222
2323/** A renamed file classified as a safe move, queued for the grouped batch-commit call. */
2424type ToMoveEntry = { path : string ; name : string ; repoPath : string ; oldPath : string ; oldRepoPath : string ; content : string | ArrayBuffer } ;
@@ -195,15 +195,15 @@ export class SyncManager {
195195
196196 const lastSynced = this . settings . syncMetadata [ path ] ;
197197
198- if ( remote . sha && lastSynced && remote . sha !== lastSynced . lastSyncedSha ) {
198+ if ( remote . sha && lastSynced && ! this . isSameBaseline ( lastSynced . lastSyncedSha , remote ) ) {
199199 this . openPushConflictModal ( fileOrPath , { path, name } , content , remote ) ;
200200 return undefined ;
201201 }
202202
203203 const confirmed = await this . confirmPlan ( this . singleEntryPlan ( remote . sha ? 'modification' : 'addition' , path , name ) , 'push' ) ;
204204 if ( ! confirmed ) return undefined ;
205205
206- const sha = await this . performPush ( { path, name } , content , remote . sha ) ;
206+ const sha = await this . performPush ( { path, name } , content , remote . sha , remote . revision ) ;
207207 return { sha } ;
208208 } catch ( e ) {
209209 this . handleError ( `Failed to push ${ name } to ${ this . serviceName } ` , e ) ;
@@ -259,7 +259,7 @@ export class SyncManager {
259259 try {
260260 const fileRep = typeof fileOrPath === 'string' ? file : fileOrPath ;
261261 if ( choice === 'local' ) {
262- await this . performPush ( file , content , remote . sha ) ;
262+ await this . performPush ( file , content , remote . sha , remote . revision ) ;
263263 } else {
264264 await this . performPull ( fileRep , remote . content , remote . sha , false , this . symlinkPullTarget ( remote ) ) ;
265265 }
@@ -367,7 +367,7 @@ export class SyncManager {
367367 }
368368
369369 const remoteAtOldPath = await this . gitService . getFile ( oldRepoPath , this . settings . branch ) ;
370- const safeToDeleteOld = ! remoteAtOldPath . sha || ! metadata ?. lastSyncedSha || remoteAtOldPath . sha === metadata . lastSyncedSha ;
370+ const safeToDeleteOld = ! remoteAtOldPath . sha || ! metadata ?. lastSyncedSha || this . isSameBaseline ( metadata . lastSyncedSha , remoteAtOldPath ) ;
371371
372372 const newSha = await this . commitMove ( repoPath , oldRepoPath , content , safeToDeleteOld && ! ! remoteAtOldPath . sha ) ;
373373
@@ -405,14 +405,15 @@ export class SyncManager {
405405 return newSha ;
406406 }
407407
408- private async performPush ( file : { path : string , name : string } , content : string | ArrayBuffer , existingSha ?: string , silent = false ) : Promise < string | undefined > {
408+ private async performPush ( file : { path : string , name : string } , content : string | ArrayBuffer , existingSha ?: string , existingRevision ?: string , silent = false ) : Promise < string | undefined > {
409409 const repoPath = this . getNormalizedPath ( file . path ) ;
410410 const result = await this . gitService . pushFile (
411411 repoPath ,
412412 content ,
413413 this . settings . branch ,
414414 `Update ${ file . name } from Obsidian` ,
415- existingSha
415+ existingSha ,
416+ existingRevision
416417 ) ;
417418
418419 // Update metadata
@@ -474,13 +475,13 @@ export class SyncManager {
474475 }
475476
476477 // Conflict detection for pull (only if local exists)
477- if ( exists && remote . sha && lastSynced && remote . sha !== lastSynced . lastSyncedSha ) {
478+ if ( exists && remote . sha && lastSynced && ! this . isSameBaseline ( lastSynced . lastSyncedSha , remote ) ) {
478479 new SyncConflictModal ( this . app , name , ( localContent as string ) || '' , remote . content as string , ( choice ) => {
479480 void ( async ( ) => {
480481 try {
481482 const fileRep = typeof fileOrPath === 'string' ? { path, name } : fileOrPath ;
482483 if ( choice === 'local' ) {
483- await this . performPush ( fileRep , localContent || '' , remote . sha ) ;
484+ await this . performPush ( fileRep , localContent || '' , remote . sha , remote . revision ) ;
484485 } else {
485486 await this . performPull ( fileRep , remote . content , remote . sha , false , this . symlinkPullTarget ( remote ) ) ;
486487 }
@@ -506,6 +507,11 @@ export class SyncManager {
506507 return contentsEqual ( a , b ) ;
507508 }
508509
510+ /** Check if remote baseline matches metadata, supporting lazy migration of old metadata. */
511+ private isSameBaseline ( lastSyncedSha : string , remoteFile : GitFile ) : boolean {
512+ return lastSyncedSha === remoteFile . sha || lastSyncedSha === remoteFile . revision ;
513+ }
514+
509515 private isBinary ( path : string ) : boolean {
510516 return isBinaryPath ( path ) ;
511517 }
@@ -1034,7 +1040,7 @@ export class SyncManager {
10341040 private async pushSequentialFallback ( toPush : ToPushEntry [ ] , results : PushResults ) : Promise < void > {
10351041 for ( const f of toPush ) {
10361042 try {
1037- const sha = await this . performPush ( { path : f . path , name : f . name } , f . content , f . existingSha , true ) ;
1043+ const sha = await this . performPush ( { path : f . path , name : f . name } , f . content , f . existingSha , f . existingRevision , true ) ;
10381044 results . success ++ ;
10391045 results . syncedPaths . push ( { path : f . path , sha } ) ;
10401046 } catch ( e ) {
@@ -1220,7 +1226,7 @@ export class SyncManager {
12201226
12211227 // Same conflict check as the single-file flow (see processSingleBatchPush).
12221228 const lastSynced = this . settings . syncMetadata [ path ] ;
1223- if ( lastSynced && remote . sha !== lastSynced . lastSyncedSha ) {
1229+ if ( lastSynced && ! this . isSameBaseline ( lastSynced . lastSyncedSha , remote ) ) {
12241230 return 'conflict' ;
12251231 }
12261232 }
0 commit comments