shadow-git 1.0.3 → 1.1.1

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.
Files changed (79) hide show
  1. package/CLAUDE.md +5 -1
  2. package/README.md +13 -0
  3. package/dist/cli.js +498 -75
  4. package/package.json +1 -1
  5. package/src/cli.ts +69 -5
  6. package/src/commands/forward.ts +3 -3
  7. package/src/commands/track/add.ts +6 -4
  8. package/src/commands/track/clone.ts +16 -1
  9. package/src/commands/track/destroy.ts +5 -0
  10. package/src/commands/track/ignore.ts +2 -2
  11. package/src/commands/track/index.ts +12 -0
  12. package/src/commands/track/init.ts +5 -1
  13. package/src/commands/track/remove.ts +3 -2
  14. package/src/commands/track/swap.ts +61 -0
  15. package/src/commands/track/sync.ts +9 -6
  16. package/src/commands/track/unswap.ts +49 -0
  17. package/src/commands/track/verify.ts +11 -9
  18. package/src/core/errors.ts +31 -1
  19. package/src/core/exclude.ts +2 -2
  20. package/src/core/gitignore.ts +18 -3
  21. package/src/core/repository.ts +8 -0
  22. package/src/core/swap-mode.ts +83 -0
  23. package/src/core/update-check.ts +214 -0
  24. package/src/utils/logger.ts +20 -0
  25. package/tests/commands/forward.test.ts +6 -6
  26. package/tests/commands/track/add.test.ts +6 -6
  27. package/tests/commands/track/swap.test.ts +266 -0
  28. package/tests/commands/track/verify.test.ts +16 -16
  29. package/tests/core/exclude.test.ts +10 -10
  30. package/tests/core/gitignore.test.ts +30 -30
  31. package/tests/core/update-check.test.ts +494 -0
  32. package/tests/helpers/guard-child.mjs +2 -2
  33. package/.claude/settings.local.json +0 -43
  34. package/.temp/.sgit/COMMIT_EDITMSG +0 -1
  35. package/.temp/.sgit/HEAD +0 -1
  36. package/.temp/.sgit/config +0 -8
  37. package/.temp/.sgit/description +0 -1
  38. package/.temp/.sgit/hooks/applypatch-msg.sample +0 -15
  39. package/.temp/.sgit/hooks/commit-msg.sample +0 -24
  40. package/.temp/.sgit/hooks/fsmonitor-watchman.sample +0 -174
  41. package/.temp/.sgit/hooks/post-update.sample +0 -8
  42. package/.temp/.sgit/hooks/pre-applypatch.sample +0 -14
  43. package/.temp/.sgit/hooks/pre-commit +0 -6
  44. package/.temp/.sgit/hooks/pre-commit.sample +0 -49
  45. package/.temp/.sgit/hooks/pre-merge-commit.sample +0 -13
  46. package/.temp/.sgit/hooks/pre-push.sample +0 -53
  47. package/.temp/.sgit/hooks/pre-rebase.sample +0 -169
  48. package/.temp/.sgit/hooks/pre-receive.sample +0 -24
  49. package/.temp/.sgit/hooks/prepare-commit-msg.sample +0 -42
  50. package/.temp/.sgit/hooks/push-to-checkout.sample +0 -78
  51. package/.temp/.sgit/hooks/sendemail-validate.sample +0 -77
  52. package/.temp/.sgit/hooks/update.sample +0 -128
  53. package/.temp/.sgit/index +0 -0
  54. package/.temp/.sgit/info/exclude +0 -20
  55. package/.temp/.sgit/logs/HEAD +0 -1
  56. package/.temp/.sgit/logs/refs/heads/master +0 -1
  57. package/.temp/.sgit/objects/03/7f4e37a02573e40ab78b35dd4b442cc6110bae +0 -0
  58. package/.temp/.sgit/objects/2f/f0fd85dec20039eef6ff63ead905778a88843f +0 -0
  59. package/.temp/.sgit/objects/34/b3190a8a836593fb568a56c073a416a56fbf6d +0 -0
  60. package/.temp/.sgit/objects/70/ad6bbbfefd330d72a43dc2a810e6ef42269911 +0 -0
  61. package/.temp/.sgit/objects/90/4e09c7aadaa32d2426ab5464a975d5151ef195 +0 -0
  62. package/.temp/.sgit/objects/a4/6358feef49515d5f85d1d3a64e929182da7149 +0 -3
  63. package/.temp/.sgit/objects/c3/2432f724b666f647fe21a1ce16535cd7693f74 +0 -0
  64. package/.temp/.sgit/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 +0 -0
  65. package/.temp/.sgit/objects/e8/0f4253888cdadda1e3d810f6a3cb3c68c20b50 +0 -0
  66. package/.temp/.sgit/objects/ee/9dd32cca3b134623d184eb4de5805704c493e3 +0 -0
  67. package/.temp/.sgit/refs/heads/master +0 -1
  68. package/.temp/.sgit.json +0 -10
  69. package/.temp/README.md +0 -0
  70. package/.temp/docs/guide.md +0 -10
  71. package/.temp/lib/__init__.py +0 -1
  72. package/.temp/lib/utils.py +0 -5
  73. package/.temp/rec1/rec2/test +0 -0
  74. package/.temp/src/config.py +0 -3
  75. package/.temp/src/main.py +0 -5
  76. package/.temp/temp/shouldnt-track +0 -0
  77. package/.temp/temp.md +0 -3
  78. package/.temp/test/1 +0 -0
  79. package/.temp/tests/test_utils.py +0 -7
@@ -46,25 +46,25 @@ describe('track verify', () => {
46
46
  expect(result.valid).toBe(true);
47
47
  });
48
48
 
49
- it('blocks stale .gitignore-sgit.bat when no guard is active', async () => {
49
+ it('blocks stale .gitignore.sgit-parked when no guard is active', async () => {
50
50
  await mkdir(join(tempDir, 'docs'), { recursive: true });
51
51
  await writeFile(join(tempDir, 'docs', 'file.md'), 'content');
52
52
  await trackAdd(['docs']);
53
53
 
54
- // Create a stale .gitignore-sgit.bat
54
+ // Create a stale .gitignore.sgit-parked
55
55
  await writeFile(
56
- join(tempDir, 'docs', '.gitignore-sgit.bat'),
56
+ join(tempDir, 'docs', '.gitignore.sgit-parked'),
57
57
  'stale\n',
58
58
  );
59
59
 
60
60
  const result = await verifyMain(tempDir);
61
61
  expect(result.valid).toBe(false);
62
62
  expect(
63
- result.violations.some((v) => v.includes('.gitignore-sgit.bat')),
63
+ result.violations.some((v) => v.includes('.gitignore.sgit-parked')),
64
64
  ).toBe(true);
65
65
  });
66
66
 
67
- it('skips stale .gitignore-sgit.bat check when guard is active', async () => {
67
+ it('skips stale .gitignore.sgit-parked check when guard is active', async () => {
68
68
  await mkdir(join(tempDir, 'docs'), { recursive: true });
69
69
  await writeFile(join(tempDir, 'docs', 'file.md'), 'content');
70
70
  await trackAdd(['docs']);
@@ -74,13 +74,13 @@ describe('track verify', () => {
74
74
  String(process.pid),
75
75
  );
76
76
  await writeFile(
77
- join(tempDir, 'docs', '.gitignore-sgit.bat'),
77
+ join(tempDir, 'docs', '.gitignore.sgit-parked'),
78
78
  'managed by guard\n',
79
79
  );
80
80
 
81
81
  const result = await verifyMain(tempDir);
82
82
  expect(
83
- result.violations.some((v) => v.includes('.gitignore-sgit.bat')),
83
+ result.violations.some((v) => v.includes('.gitignore.sgit-parked')),
84
84
  ).toBe(false);
85
85
 
86
86
  unlinkSync(join(tempDir, '.sgit', '.gitignore-guard'));
@@ -147,43 +147,43 @@ describe('track verify', () => {
147
147
  expect(result.violations.some((v) => v.includes('.sgit.json') && v.includes('cannot delete'))).toBe(true);
148
148
  });
149
149
 
150
- it('blocks stale .gitignore-sgit.bat when no guard is active', async () => {
150
+ it('blocks stale .gitignore.sgit-parked when no guard is active', async () => {
151
151
  await mkdir(join(tempDir, 'docs'), { recursive: true });
152
152
  await writeFile(join(tempDir, 'docs', 'file.md'), 'content');
153
153
  await trackAdd(['docs']);
154
154
 
155
- // Create a stale .gitignore-sgit.bat
155
+ // Create a stale .gitignore.sgit-parked
156
156
  await writeFile(
157
- join(tempDir, 'docs', '.gitignore-sgit.bat'),
157
+ join(tempDir, 'docs', '.gitignore.sgit-parked'),
158
158
  'stale\n',
159
159
  );
160
160
 
161
161
  const result = await verifyShadow(tempDir);
162
162
  expect(result.valid).toBe(false);
163
163
  expect(
164
- result.violations.some((v) => v.includes('.gitignore-sgit.bat')),
164
+ result.violations.some((v) => v.includes('.gitignore.sgit-parked')),
165
165
  ).toBe(true);
166
166
  });
167
167
 
168
- it('skips stale .gitignore-sgit.bat check when guard is active', async () => {
168
+ it('skips stale .gitignore.sgit-parked check when guard is active', async () => {
169
169
  await mkdir(join(tempDir, 'docs'), { recursive: true });
170
170
  await writeFile(join(tempDir, 'docs', 'file.md'), 'content');
171
171
  await trackAdd(['docs']);
172
172
 
173
- // Simulate active guard: create lock with current PID + stale .bat
173
+ // Simulate active guard: create lock with current PID + stale .gitignore.sgit-parked
174
174
  writeFileSync(
175
175
  join(tempDir, '.sgit', '.gitignore-guard'),
176
176
  String(process.pid),
177
177
  );
178
178
  await writeFile(
179
- join(tempDir, 'docs', '.gitignore-sgit.bat'),
179
+ join(tempDir, 'docs', '.gitignore.sgit-parked'),
180
180
  'managed by guard\n',
181
181
  );
182
182
 
183
183
  const result = await verifyShadow(tempDir);
184
- // Should not report .bat files as violations when guard is active
184
+ // Should not report stale files as violations when guard is active
185
185
  expect(
186
- result.violations.some((v) => v.includes('.gitignore-sgit.bat')),
186
+ result.violations.some((v) => v.includes('.gitignore.sgit-parked')),
187
187
  ).toBe(false);
188
188
 
189
189
  // Cleanup
@@ -50,17 +50,17 @@ describe('generateMainExclude', () => {
50
50
  expect(result).toContain('notes/todo.md\n');
51
51
  });
52
52
 
53
- it('includes .gitignore-sgit.bat in managed block', () => {
53
+ it('includes .gitignore.sgit-parked in managed block', () => {
54
54
  const result = generateMainExclude('', ['notes.md']);
55
- expect(result).toContain('.gitignore-sgit.bat\n');
55
+ expect(result).toContain('.gitignore.sgit-parked\n');
56
56
  });
57
57
 
58
- it('orders entries: .sgit, .sgit.json, .gitignore-sgit.bat, then manifest paths', () => {
58
+ it('orders entries: .sgit, .sgit.json, .gitignore.sgit-parked, then manifest paths', () => {
59
59
  const result = generateMainExclude('', ['z.txt', 'a.txt']);
60
60
  const lines = result.split('\n');
61
61
  const sgitLine = lines.indexOf('.sgit');
62
62
  const sgitJsonLine = lines.indexOf('.sgit.json');
63
- const batLine = lines.indexOf('.gitignore-sgit.bat');
63
+ const batLine = lines.indexOf('.gitignore.sgit-parked');
64
64
  const zLine = lines.indexOf('z.txt');
65
65
  const aLine = lines.indexOf('a.txt');
66
66
  expect(sgitLine).toBeLessThan(sgitJsonLine);
@@ -158,19 +158,19 @@ describe('generateShadowExclude', () => {
158
158
  expect(lines).not.toContain('!./');
159
159
  });
160
160
 
161
- it('re-ignores .gitignore-sgit.bat after allow-list', () => {
161
+ it('re-ignores .gitignore.sgit-parked after allow-list', () => {
162
162
  const result = generateShadowExclude(['docs/']);
163
163
  const lines = result.split('\n');
164
164
  const allowLine = lines.indexOf('!docs/**');
165
- const batLine = lines.indexOf('.gitignore-sgit.bat');
165
+ const batLine = lines.indexOf('.gitignore.sgit-parked');
166
166
  expect(batLine).toBeGreaterThan(-1);
167
167
  expect(batLine).toBeGreaterThan(allowLine);
168
168
  });
169
169
 
170
- it('includes .gitignore-sgit.bat even for empty manifest', () => {
170
+ it('includes .gitignore.sgit-parked even for empty manifest', () => {
171
171
  const result = generateShadowExclude([]);
172
172
  const lines = result.split('\n');
173
- expect(lines).toContain('.gitignore-sgit.bat');
173
+ expect(lines).toContain('.gitignore.sgit-parked');
174
174
  });
175
175
 
176
176
  it('has no per-path comment lines', () => {
@@ -186,12 +186,12 @@ describe('generateShadowExclude', () => {
186
186
  expect(lines).toContain('temp2/cache/');
187
187
  });
188
188
 
189
- it('places ignore rules after un-ignore and before .gitignore-sgit.bat', () => {
189
+ it('places ignore rules after un-ignore and before .gitignore.sgit-parked', () => {
190
190
  const result = generateShadowExclude(['docs/'], ['docs/cache/']);
191
191
  const lines = result.split('\n');
192
192
  const unignoreLine = lines.indexOf('!docs/**');
193
193
  const ignoreLine = lines.indexOf('docs/cache/');
194
- const batLine = lines.indexOf('.gitignore-sgit.bat');
194
+ const batLine = lines.indexOf('.gitignore.sgit-parked');
195
195
  expect(ignoreLine).toBeGreaterThan(unignoreLine);
196
196
  expect(ignoreLine).toBeLessThan(batLine);
197
197
  });
@@ -57,11 +57,11 @@ describe('gitignore manipulator', () => {
57
57
  // disableGitignores
58
58
  // ---------------------------------------------------------------
59
59
  describe('disableGitignores', () => {
60
- it('renames .gitignore to .gitignore-sgit.bat in tracked directory', () => {
60
+ it('renames .gitignore to .gitignore.sgit-parked in tracked directory', () => {
61
61
  const disabled = disableGitignores(tempDir, ['secret/']);
62
62
  expect(disabled).toContain('secret/.gitignore');
63
63
  expect(fileExists(join(tempDir, 'secret', '.gitignore'))).toBe(false);
64
- expect(fileExists(join(tempDir, 'secret', '.gitignore-sgit.bat'))).toBe(
64
+ expect(fileExists(join(tempDir, 'secret', '.gitignore.sgit-parked'))).toBe(
65
65
  true,
66
66
  );
67
67
  });
@@ -139,9 +139,9 @@ describe('gitignore manipulator', () => {
139
139
  expect(disabled).toEqual([]);
140
140
  });
141
141
 
142
- it('throws StaleGitignoreError when .gitignore-sgit.bat already exists', async () => {
142
+ it('throws StaleGitignoreError when .gitignore.sgit-parked already exists', async () => {
143
143
  await writeFile(
144
- join(tempDir, 'secret', '.gitignore-sgit.bat'),
144
+ join(tempDir, 'secret', '.gitignore.sgit-parked'),
145
145
  'stale\n',
146
146
  );
147
147
  expect(() => disableGitignores(tempDir, ['secret/'])).toThrow(
@@ -212,12 +212,12 @@ describe('gitignore manipulator', () => {
212
212
  // enableGitignores
213
213
  // ---------------------------------------------------------------
214
214
  describe('enableGitignores', () => {
215
- it('renames .gitignore-sgit.bat back to .gitignore', () => {
215
+ it('renames .gitignore.sgit-parked back to .gitignore', () => {
216
216
  disableGitignores(tempDir, ['secret/']);
217
217
  const enabled = enableGitignores(tempDir, ['secret/']);
218
218
  expect(enabled).toHaveLength(1);
219
219
  expect(fileExists(join(tempDir, 'secret', '.gitignore'))).toBe(true);
220
- expect(fileExists(join(tempDir, 'secret', '.gitignore-sgit.bat'))).toBe(
220
+ expect(fileExists(join(tempDir, 'secret', '.gitignore.sgit-parked'))).toBe(
221
221
  false,
222
222
  );
223
223
  });
@@ -255,28 +255,28 @@ describe('gitignore manipulator', () => {
255
255
  // findStaleGitignores
256
256
  // ---------------------------------------------------------------
257
257
  describe('findStaleGitignores', () => {
258
- it('finds .gitignore-sgit.bat in tracked dirs', async () => {
258
+ it('finds .gitignore.sgit-parked in tracked dirs', async () => {
259
259
  await writeFile(
260
- join(tempDir, 'secret', '.gitignore-sgit.bat'),
260
+ join(tempDir, 'secret', '.gitignore.sgit-parked'),
261
261
  'stale\n',
262
262
  );
263
263
  const stale = findStaleGitignores(tempDir, ['secret/']);
264
- expect(stale).toEqual(['secret/.gitignore-sgit.bat']);
264
+ expect(stale).toEqual(['secret/.gitignore.sgit-parked']);
265
265
  });
266
266
 
267
- it('finds .gitignore-sgit.bat in ancestor dirs for file entries', async () => {
267
+ it('finds .gitignore.sgit-parked in ancestor dirs for file entries', async () => {
268
268
  await writeFile(
269
- join(tempDir, 'secret', '.gitignore-sgit.bat'),
269
+ join(tempDir, 'secret', '.gitignore.sgit-parked'),
270
270
  'stale\n',
271
271
  );
272
272
  const stale = findStaleGitignores(tempDir, ['secret/data.txt']);
273
- expect(stale).toContain('secret/.gitignore-sgit.bat');
273
+ expect(stale).toContain('secret/.gitignore.sgit-parked');
274
274
  });
275
275
 
276
- it('finds .gitignore-sgit.bat at root', async () => {
277
- await writeFile(join(tempDir, '.gitignore-sgit.bat'), 'stale\n');
276
+ it('finds .gitignore.sgit-parked at root', async () => {
277
+ await writeFile(join(tempDir, '.gitignore.sgit-parked'), 'stale\n');
278
278
  const stale = findStaleGitignores(tempDir, ['secret/']);
279
- expect(stale).toContain('.gitignore-sgit.bat');
279
+ expect(stale).toContain('.gitignore.sgit-parked');
280
280
  });
281
281
 
282
282
  it('returns empty when no stale files exist', () => {
@@ -314,7 +314,7 @@ describe('gitignore manipulator', () => {
314
314
  it('disables gitignores and returns cleanup function', () => {
315
315
  const cleanup = setupGitignoreGuard(tempDir, ['secret/']);
316
316
  expect(fileExists(join(tempDir, 'secret', '.gitignore'))).toBe(false);
317
- expect(fileExists(join(tempDir, 'secret', '.gitignore-sgit.bat'))).toBe(
317
+ expect(fileExists(join(tempDir, 'secret', '.gitignore.sgit-parked'))).toBe(
318
318
  true,
319
319
  );
320
320
  expect(fileExists(join(tempDir, '.sgit', '.gitignore-guard'))).toBe(true);
@@ -322,7 +322,7 @@ describe('gitignore manipulator', () => {
322
322
  cleanup();
323
323
 
324
324
  expect(fileExists(join(tempDir, 'secret', '.gitignore'))).toBe(true);
325
- expect(fileExists(join(tempDir, 'secret', '.gitignore-sgit.bat'))).toBe(
325
+ expect(fileExists(join(tempDir, 'secret', '.gitignore.sgit-parked'))).toBe(
326
326
  false,
327
327
  );
328
328
  expect(fileExists(join(tempDir, '.sgit', '.gitignore-guard'))).toBe(
@@ -365,10 +365,10 @@ describe('gitignore manipulator', () => {
365
365
  unlinkSync(lockPath);
366
366
  });
367
367
 
368
- it('auto-cleans stale .bat files from a crashed process', () => {
368
+ it('auto-cleans stale .gitignore.sgit-parked files from a crashed process', () => {
369
369
  renameSync(
370
370
  join(tempDir, 'secret', '.gitignore'),
371
- join(tempDir, 'secret', '.gitignore-sgit.bat'),
371
+ join(tempDir, 'secret', '.gitignore.sgit-parked'),
372
372
  );
373
373
  writeFileSync(
374
374
  join(tempDir, '.sgit', '.gitignore-guard'),
@@ -376,8 +376,8 @@ describe('gitignore manipulator', () => {
376
376
  );
377
377
 
378
378
  const cleanup = setupGitignoreGuard(tempDir, ['secret/']);
379
- // Guard should have restored stale .bat, then re-disabled
380
- expect(fileExists(join(tempDir, 'secret', '.gitignore-sgit.bat'))).toBe(
379
+ // Guard should have restored stale .gitignore.sgit-parked, then re-disabled
380
+ expect(fileExists(join(tempDir, 'secret', '.gitignore.sgit-parked'))).toBe(
381
381
  true,
382
382
  );
383
383
  cleanup();
@@ -401,7 +401,7 @@ describe('gitignore manipulator', () => {
401
401
  cleanup();
402
402
  }
403
403
  expect(fileExists(join(tempDir, 'secret', '.gitignore'))).toBe(true);
404
- expect(fileExists(join(tempDir, 'secret', '.gitignore-sgit.bat'))).toBe(
404
+ expect(fileExists(join(tempDir, 'secret', '.gitignore.sgit-parked'))).toBe(
405
405
  false,
406
406
  );
407
407
  });
@@ -458,9 +458,9 @@ describe('gitignore manipulator', () => {
458
458
  });
459
459
 
460
460
  // ---------------------------------------------------------------
461
- // .gitignore-sgit.bat must never persist
461
+ // .gitignore.sgit-parked must never persist
462
462
  // ---------------------------------------------------------------
463
- describe('.gitignore-sgit.bat must not exist after any sgit command', () => {
463
+ describe('.gitignore.sgit-parked must not exist after any sgit command', () => {
464
464
  it('does not exist after successful guard lifecycle', () => {
465
465
  const cleanup = setupGitignoreGuard(tempDir, ['secret/']);
466
466
  cleanup();
@@ -479,23 +479,23 @@ describe('gitignore manipulator', () => {
479
479
  expect(findStaleGitignores(tempDir, ['secret/'])).toEqual([]);
480
480
  });
481
481
 
482
- it('disableGitignores throws when .gitignore-sgit.bat already exists', async () => {
482
+ it('disableGitignores throws when .gitignore.sgit-parked already exists', async () => {
483
483
  await writeFile(
484
- join(tempDir, 'secret', '.gitignore-sgit.bat'),
484
+ join(tempDir, 'secret', '.gitignore.sgit-parked'),
485
485
  'stale content\n',
486
486
  );
487
487
  expect(() => disableGitignores(tempDir, ['secret/'])).toThrow(
488
488
  StaleGitignoreError,
489
489
  );
490
490
  expect(() => disableGitignores(tempDir, ['secret/'])).toThrow(
491
- /stale .gitignore-sgit.bat/,
491
+ /stale .gitignore.sgit-parked/,
492
492
  );
493
493
  });
494
494
 
495
495
  it('guard auto-recovers stale files then proceeds normally', () => {
496
496
  renameSync(
497
497
  join(tempDir, 'secret', '.gitignore'),
498
- join(tempDir, 'secret', '.gitignore-sgit.bat'),
498
+ join(tempDir, 'secret', '.gitignore.sgit-parked'),
499
499
  );
500
500
  writeFileSync(
501
501
  join(tempDir, '.sgit', '.gitignore-guard'),
@@ -506,7 +506,7 @@ describe('gitignore manipulator', () => {
506
506
  cleanup();
507
507
 
508
508
  expect(fileExists(join(tempDir, 'secret', '.gitignore'))).toBe(true);
509
- expect(fileExists(join(tempDir, 'secret', '.gitignore-sgit.bat'))).toBe(
509
+ expect(fileExists(join(tempDir, 'secret', '.gitignore.sgit-parked'))).toBe(
510
510
  false,
511
511
  );
512
512
  expect(findStaleGitignores(tempDir, ['secret/'])).toEqual([]);
@@ -518,7 +518,7 @@ describe('gitignore manipulator', () => {
518
518
 
519
519
  function assertGitignoreRestored(root: string): void {
520
520
  expect(fileExists(join(root, 'secret', '.gitignore'))).toBe(true);
521
- expect(fileExists(join(root, 'secret', '.gitignore-sgit.bat'))).toBe(false);
521
+ expect(fileExists(join(root, 'secret', '.gitignore.sgit-parked'))).toBe(false);
522
522
  expect(fileExists(join(root, '.sgit', '.gitignore-guard'))).toBe(false);
523
523
  }
524
524