Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export interface BaseWorkspaceMeta {
hasUnpushedChanges: boolean;
gitFilePath: string | null;
gitFileLastSyncTime: number | null;
gitFileLastSyncHash: string | null;
}

export type WorkspaceMeta = BaseWorkspaceMeta & BaseModel;
Expand All @@ -35,6 +36,7 @@ export function init(): BaseWorkspaceMeta {
gitRepositoryId: null,
gitFilePath: null,
gitFileLastSyncTime: null,
gitFileLastSyncHash: null,
parentId: null,
pushSnapshotOnInitialize: false,
hasUncommittedChanges: false,
Expand Down
34 changes: 26 additions & 8 deletions packages/insomnia/src/sync/git/repo-file-watcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,13 @@ class RepoFileWatcher {
this.lastKnownGitFilePath.set(workspace._id, absPath);
const stat = await fs.promises.stat(absPath);
this.lastSyncMtime.set(absPath, stat.mtimeMs);

// Persist tracking state so the maps can be restored after a restart
const workspaceMeta = meta ?? (await services.workspaceMeta.getOrCreateByParentId(workspace._id));
await services.workspaceMeta.update(workspaceMeta, {
Comment on lines +429 to +431
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gitFileLastSyncHash/gitFileLastSyncTime are persisted here, but gitFilePath is not. If meta.gitFilePath is null/undefined (which can happen for DB-created workspaces before any FS→DB import), loadKnownGitFilePaths() will ignore this meta record and the persisted hash/time won’t be restored on restart. Consider persisting gitFilePath (e.g. the computed default/rel path) when it’s missing, or adjusting the restore logic to fall back to the default filename when gitFilePath is null.

Suggested change
// Persist tracking state so the maps can be restored after a restart
const workspaceMeta = meta ?? (await services.workspaceMeta.getOrCreateByParentId(workspace._id));
await services.workspaceMeta.update(workspaceMeta, {
// Persist tracking state so the maps can be restored after a restart.
// Store the resolved gitFilePath as well so workspaces that previously
// had no explicit meta.gitFilePath can restore their last sync state.
const workspaceMeta = meta ?? (await services.workspaceMeta.getOrCreateByParentId(workspace._id));
await services.workspaceMeta.update(workspaceMeta, {
gitFilePath,

Copilot uses AI. Check for mistakes.
gitFileLastSyncHash: hash,
gitFileLastSyncTime: stat.mtimeMs,
});
} catch (err) {
console.warn('[repo-file-watcher] Could not flush workspace to disk:', workspace._id, err);
}
Expand Down Expand Up @@ -534,7 +541,7 @@ class RepoFileWatcher {
}

await this.deleteOrphans(docs);
await this.upsertDocs(absPath, normalised, result.mtimeMs, docs);
await this.upsertDocs(absPath, normalised, result.mtimeMs, result.hash, docs);

this.notifyRenderer();
}
Expand Down Expand Up @@ -649,6 +656,7 @@ class RepoFileWatcher {
absPath: string,
normalised: string,
syncTime: number,
hash: string,
docs: NonNullable<ReturnType<typeof tryImportV5Data>['data']>,
): Promise<void> {
const bufferId = await db.bufferChanges();
Expand All @@ -660,6 +668,7 @@ class RepoFileWatcher {
await services.workspaceMeta.update(workspaceMeta, {
gitFilePath: this.toPosixRelPath(absPath),
gitFileLastSyncTime: syncTime,
gitFileLastSyncHash: hash,
});
this.lastKnownGitFilePath.set(doc._id, normalised);
}
Expand Down Expand Up @@ -818,21 +827,30 @@ class RepoFileWatcher {
}

/**
* Load existing workspace → gitFilePath mappings from the DB so rename
* detection works from the start.
* Load existing workspace → gitFilePath mappings from the DB and restore
* persisted tracking state (mtime + hash) so that the initial
* {@link importAllFiles} call can skip files that haven't changed since
* the last session.
*
* Note: we intentionally do NOT pre-scan file mtimes here. The initial
* {@link importAllFiles} call in {@link create} populates both
* `lastSyncMtime` and `lastWrittenHash` as a side-effect of importing.
* Pre-scanning mtimes would cause `importAllFiles` to skip files it
* hasn't actually imported yet.
* Note: pre-seeding `lastWrittenHash` here is safe because
* `importAllFiles` uses `forceRead=true`, which bypasses the mtime
* fast-path but still runs the hash check in {@link readIfChanged}.
* Files whose content matches the persisted hash will be skipped,
* preventing unnecessary workspace re-imports (and modified-timestamp
* changes) on every app restart.
*/
private async loadKnownGitFilePaths(): Promise<void> {
const entries = await this.getWorkspacesWithMeta();
for (const { workspace, meta } of entries) {
if (meta?.gitFilePath) {
const absPath = path.normalize(path.join(this.repoDir, meta.gitFilePath));
this.lastKnownGitFilePath.set(workspace._id, absPath);
if (meta.gitFileLastSyncTime != null) {
this.lastSyncMtime.set(absPath, meta.gitFileLastSyncTime);
}
if (meta.gitFileLastSyncHash != null) {
this.lastWrittenHash.set(absPath, meta.gitFileLastSyncHash);
}
}
}
}
Expand Down
Loading