isomorphic-jj 1.4.0 → 1.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "isomorphic-jj",
3
- "version": "1.4.0",
3
+ "version": "1.4.2",
4
4
  "description": "A pure-JavaScript library that brings Jujutsu (jj) version control semantics to Node.js and browsers",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1089,8 +1089,8 @@ export async function createJJ(options) {
1089
1089
  change.metadata = args.metadata;
1090
1090
  }
1091
1091
 
1092
- // Only snapshot files if describing working copy
1093
- if (isWorkingCopy) {
1092
+ // Only snapshot files if describing working copy AND preserveSnapshot is not true
1093
+ if (isWorkingCopy && !args.preserveSnapshot) {
1094
1094
  // Snapshot current file contents for conflict detection
1095
1095
  // This allows us to load file contents during merge/rebase
1096
1096
  const fileSnapshot = {};
@@ -1323,16 +1323,19 @@ export async function createJJ(options) {
1323
1323
  await workingCopy.load();
1324
1324
  await userConfig.load();
1325
1325
 
1326
- // Snapshot filesystem BEFORE operation (for undo)
1327
- const fileSnapshot = await snapshotFilesystem();
1326
+ // Snapshot filesystem BEFORE operation (for undo) unless preserveSnapshot is true
1327
+ let fileSnapshot;
1328
+ if (!args.preserveSnapshot) {
1329
+ fileSnapshot = await snapshotFilesystem();
1328
1330
 
1329
- // Update current working copy change with the file snapshot
1330
- // This ensures files written before jj.new() are captured
1331
- const currentChangeId = workingCopy.getCurrentChangeId();
1332
- const currentChange = await graph.getChange(currentChangeId);
1333
- if (currentChange && fileSnapshot) {
1334
- currentChange.fileSnapshot = fileSnapshot;
1335
- await graph.updateChange(currentChange);
1331
+ // Update current working copy change with the file snapshot
1332
+ // This ensures files written before jj.new() are captured
1333
+ const currentChangeId = workingCopy.getCurrentChangeId();
1334
+ const currentChange = await graph.getChange(currentChangeId);
1335
+ if (currentChange && fileSnapshot) {
1336
+ currentChange.fileSnapshot = fileSnapshot;
1337
+ await graph.updateChange(currentChange);
1338
+ }
1336
1339
  }
1337
1340
 
1338
1341
  // Determine parents
@@ -1697,8 +1700,16 @@ export async function createJJ(options) {
1697
1700
  * @returns {Promise<Object>} The newly created change
1698
1701
  */
1699
1702
  async commit(args = {}) {
1700
- await this.describe({ message: args.message, author: args.author, metadata: args.metadata });
1701
- return await this.new({ message: args.nextMessage });
1703
+ await this.describe({
1704
+ message: args.message,
1705
+ author: args.author,
1706
+ metadata: args.metadata,
1707
+ preserveSnapshot: args.preserveSnapshot
1708
+ });
1709
+ return await this.new({
1710
+ message: args.nextMessage,
1711
+ preserveSnapshot: args.preserveSnapshot
1712
+ });
1702
1713
  },
1703
1714
 
1704
1715
  /**
@@ -1734,16 +1745,34 @@ export async function createJJ(options) {
1734
1745
 
1735
1746
  const previousChangeId = workingCopy.getCurrentChangeId();
1736
1747
 
1737
- // Snapshot current filesystem into current change before switching
1738
- // This preserves any uncommitted modifications
1748
+ // CRITICAL FIX: Clean working directory BEFORE snapshotting to prevent cross-branch pollution
1749
+ // Remove files that don't belong to the current changeId before we snapshot it
1739
1750
  if (previousChangeId !== args.changeId) {
1751
+ const previousChange = await graph.getChange(previousChangeId);
1752
+ if (previousChange) {
1753
+ const previousSnapshot = previousChange.fileSnapshot || {};
1754
+ const workingDirFiles = await workingCopy.listFiles();
1755
+
1756
+ // Delete files that exist in working dir but NOT in previous changeId's snapshot
1757
+ // This removes pollution from other branches that were previously checked out
1758
+ for (const filePath of workingDirFiles) {
1759
+ if (!previousSnapshot[filePath]) {
1760
+ try {
1761
+ const fullPath = path.join(dir, filePath);
1762
+ await fs.promises.unlink(fullPath);
1763
+ await workingCopy.untrackFile(filePath);
1764
+ } catch (error) {
1765
+ // Ignore errors - file might already be deleted or inaccessible
1766
+ }
1767
+ }
1768
+ }
1769
+ }
1770
+
1771
+ // Now snapshot the CLEAN working directory (no pollution!)
1740
1772
  const currentSnapshot = await snapshotFilesystem();
1741
1773
  if (currentSnapshot && Object.keys(currentSnapshot).length > 0) {
1742
- const previousChange = await graph.getChange(previousChangeId);
1743
- if (previousChange) {
1744
- previousChange.fileSnapshot = currentSnapshot;
1745
- await graph.updateChange(previousChange);
1746
- }
1774
+ previousChange.fileSnapshot = currentSnapshot;
1775
+ await graph.updateChange(previousChange);
1747
1776
  }
1748
1777
  }
1749
1778
 
package/src/types.d.ts CHANGED
@@ -386,6 +386,7 @@ export interface WriteStreamArgs {
386
386
  export interface DescribeArgs {
387
387
  message?: string;
388
388
  author?: User;
389
+ metadata?: Record<string, any>;
389
390
  }
390
391
 
391
392
  /**
@@ -412,6 +413,7 @@ export interface AmendArgs {
412
413
  export interface CommitArgs {
413
414
  message?: string;
414
415
  author?: User;
416
+ metadata?: Record<string, any>;
415
417
  nextMessage?: string;
416
418
  }
417
419