vde-worktree 0.0.10 → 0.0.12
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/dist/index.mjs +287 -25
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -601,6 +601,143 @@ const readNumberFromEnvOrDefault = ({ rawValue, defaultValue }) => {
|
|
|
601
601
|
return rawValue;
|
|
602
602
|
};
|
|
603
603
|
|
|
604
|
+
//#endregion
|
|
605
|
+
//#region src/core/worktree-merge-lifecycle.ts
|
|
606
|
+
const lifecycleFilePath = (repoRoot, branch) => {
|
|
607
|
+
return join(getStateDirectoryPath(repoRoot), "branches", `${branchToWorktreeId(branch)}.json`);
|
|
608
|
+
};
|
|
609
|
+
const hasStateDirectory = async (repoRoot) => {
|
|
610
|
+
try {
|
|
611
|
+
await access(getStateDirectoryPath(repoRoot), constants.F_OK);
|
|
612
|
+
return true;
|
|
613
|
+
} catch {
|
|
614
|
+
return false;
|
|
615
|
+
}
|
|
616
|
+
};
|
|
617
|
+
const parseLifecycle = (content) => {
|
|
618
|
+
try {
|
|
619
|
+
const parsed = JSON.parse(content);
|
|
620
|
+
if (parsed.schemaVersion !== 1 || typeof parsed.branch !== "string" || typeof parsed.worktreeId !== "string" || typeof parsed.baseBranch !== "string" || typeof parsed.createdHead !== "string" || parsed.createdHead.length === 0 || typeof parsed.createdAt !== "string" || typeof parsed.updatedAt !== "string") return {
|
|
621
|
+
valid: false,
|
|
622
|
+
record: null
|
|
623
|
+
};
|
|
624
|
+
return {
|
|
625
|
+
valid: true,
|
|
626
|
+
record: parsed
|
|
627
|
+
};
|
|
628
|
+
} catch {
|
|
629
|
+
return {
|
|
630
|
+
valid: false,
|
|
631
|
+
record: null
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
};
|
|
635
|
+
const writeJsonAtomically$1 = async ({ filePath, payload }) => {
|
|
636
|
+
await mkdir(dirname(filePath), { recursive: true });
|
|
637
|
+
const tmpPath = `${filePath}.tmp-${String(process.pid)}-${String(Date.now())}`;
|
|
638
|
+
await writeFile(tmpPath, `${JSON.stringify(payload)}\n`, "utf8");
|
|
639
|
+
await rename(tmpPath, filePath);
|
|
640
|
+
};
|
|
641
|
+
const readWorktreeMergeLifecycle = async ({ repoRoot, branch }) => {
|
|
642
|
+
const path = lifecycleFilePath(repoRoot, branch);
|
|
643
|
+
try {
|
|
644
|
+
await access(path, constants.F_OK);
|
|
645
|
+
} catch {
|
|
646
|
+
return {
|
|
647
|
+
path,
|
|
648
|
+
exists: false,
|
|
649
|
+
valid: true,
|
|
650
|
+
record: null
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
try {
|
|
654
|
+
return {
|
|
655
|
+
path,
|
|
656
|
+
exists: true,
|
|
657
|
+
...parseLifecycle(await readFile(path, "utf8"))
|
|
658
|
+
};
|
|
659
|
+
} catch {
|
|
660
|
+
return {
|
|
661
|
+
path,
|
|
662
|
+
exists: true,
|
|
663
|
+
valid: false,
|
|
664
|
+
record: null
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
};
|
|
668
|
+
const upsertWorktreeMergeLifecycle = async ({ repoRoot, branch, baseBranch, createdHead }) => {
|
|
669
|
+
if (await hasStateDirectory(repoRoot) !== true) {
|
|
670
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
671
|
+
return {
|
|
672
|
+
schemaVersion: 1,
|
|
673
|
+
branch,
|
|
674
|
+
worktreeId: branchToWorktreeId(branch),
|
|
675
|
+
baseBranch,
|
|
676
|
+
createdHead,
|
|
677
|
+
createdAt: now,
|
|
678
|
+
updatedAt: now
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
const current = await readWorktreeMergeLifecycle({
|
|
682
|
+
repoRoot,
|
|
683
|
+
branch
|
|
684
|
+
});
|
|
685
|
+
if (current.valid && current.record !== null && current.record.baseBranch === baseBranch) return current.record;
|
|
686
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
687
|
+
const next = {
|
|
688
|
+
schemaVersion: 1,
|
|
689
|
+
branch,
|
|
690
|
+
worktreeId: branchToWorktreeId(branch),
|
|
691
|
+
baseBranch,
|
|
692
|
+
createdHead: current.record?.createdHead ?? createdHead,
|
|
693
|
+
createdAt: current.record?.createdAt ?? now,
|
|
694
|
+
updatedAt: now
|
|
695
|
+
};
|
|
696
|
+
await writeJsonAtomically$1({
|
|
697
|
+
filePath: current.path,
|
|
698
|
+
payload: next
|
|
699
|
+
});
|
|
700
|
+
return next;
|
|
701
|
+
};
|
|
702
|
+
const moveWorktreeMergeLifecycle = async ({ repoRoot, fromBranch, toBranch, baseBranch, createdHead }) => {
|
|
703
|
+
if (await hasStateDirectory(repoRoot) !== true) {
|
|
704
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
705
|
+
return {
|
|
706
|
+
schemaVersion: 1,
|
|
707
|
+
branch: toBranch,
|
|
708
|
+
worktreeId: branchToWorktreeId(toBranch),
|
|
709
|
+
baseBranch,
|
|
710
|
+
createdHead,
|
|
711
|
+
createdAt: now,
|
|
712
|
+
updatedAt: now
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
const source = await readWorktreeMergeLifecycle({
|
|
716
|
+
repoRoot,
|
|
717
|
+
branch: fromBranch
|
|
718
|
+
});
|
|
719
|
+
const targetPath = lifecycleFilePath(repoRoot, toBranch);
|
|
720
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
721
|
+
const next = {
|
|
722
|
+
schemaVersion: 1,
|
|
723
|
+
branch: toBranch,
|
|
724
|
+
worktreeId: branchToWorktreeId(toBranch),
|
|
725
|
+
baseBranch,
|
|
726
|
+
createdHead: source.record?.createdHead ?? createdHead,
|
|
727
|
+
createdAt: source.record?.createdAt ?? now,
|
|
728
|
+
updatedAt: now
|
|
729
|
+
};
|
|
730
|
+
await writeJsonAtomically$1({
|
|
731
|
+
filePath: targetPath,
|
|
732
|
+
payload: next
|
|
733
|
+
});
|
|
734
|
+
if (source.path !== targetPath) await rm(source.path, { force: true });
|
|
735
|
+
return next;
|
|
736
|
+
};
|
|
737
|
+
const deleteWorktreeMergeLifecycle = async ({ repoRoot, branch }) => {
|
|
738
|
+
await rm(lifecycleFilePath(repoRoot, branch), { force: true });
|
|
739
|
+
};
|
|
740
|
+
|
|
604
741
|
//#endregion
|
|
605
742
|
//#region src/core/worktree-lock.ts
|
|
606
743
|
const parseLock = (content) => {
|
|
@@ -707,8 +844,9 @@ const parseMergedResult = (raw) => {
|
|
|
707
844
|
return null;
|
|
708
845
|
}
|
|
709
846
|
};
|
|
710
|
-
const resolveMergedByPr = async ({ repoRoot, branch, enabled = true, runGh = defaultRunGh }) => {
|
|
847
|
+
const resolveMergedByPr = async ({ repoRoot, branch, baseBranch, enabled = true, runGh = defaultRunGh }) => {
|
|
711
848
|
if (enabled !== true) return null;
|
|
849
|
+
if (baseBranch === null) return null;
|
|
712
850
|
try {
|
|
713
851
|
const result = await runGh({
|
|
714
852
|
cwd: repoRoot,
|
|
@@ -719,6 +857,8 @@ const resolveMergedByPr = async ({ repoRoot, branch, enabled = true, runGh = def
|
|
|
719
857
|
"merged",
|
|
720
858
|
"--head",
|
|
721
859
|
branch,
|
|
860
|
+
"--base",
|
|
861
|
+
baseBranch,
|
|
722
862
|
"--limit",
|
|
723
863
|
"1",
|
|
724
864
|
"--json",
|
|
@@ -878,7 +1018,7 @@ const resolveLockState = async ({ repoRoot, branch }) => {
|
|
|
878
1018
|
};
|
|
879
1019
|
}
|
|
880
1020
|
};
|
|
881
|
-
const resolveMergedState = async ({ repoRoot, branch, baseBranch, enableGh }) => {
|
|
1021
|
+
const resolveMergedState = async ({ repoRoot, branch, head, baseBranch, enableGh }) => {
|
|
882
1022
|
if (branch === null) return {
|
|
883
1023
|
byAncestry: null,
|
|
884
1024
|
byPR: null,
|
|
@@ -902,21 +1042,35 @@ const resolveMergedState = async ({ repoRoot, branch, baseBranch, enableGh }) =>
|
|
|
902
1042
|
const byPR = await resolveMergedByPr({
|
|
903
1043
|
repoRoot,
|
|
904
1044
|
branch,
|
|
1045
|
+
baseBranch,
|
|
905
1046
|
enabled: enableGh
|
|
906
1047
|
});
|
|
1048
|
+
let byLifecycle = null;
|
|
1049
|
+
if (baseBranch !== null) {
|
|
1050
|
+
const lifecycle = await upsertWorktreeMergeLifecycle({
|
|
1051
|
+
repoRoot,
|
|
1052
|
+
branch,
|
|
1053
|
+
baseBranch,
|
|
1054
|
+
createdHead: head
|
|
1055
|
+
});
|
|
1056
|
+
if (byAncestry === true) byLifecycle = lifecycle.createdHead !== head;
|
|
1057
|
+
else if (byAncestry === false) byLifecycle = false;
|
|
1058
|
+
}
|
|
907
1059
|
return {
|
|
908
1060
|
byAncestry,
|
|
909
1061
|
byPR,
|
|
910
1062
|
overall: resolveMergedOverall({
|
|
911
1063
|
byAncestry,
|
|
912
|
-
byPR
|
|
1064
|
+
byPR,
|
|
1065
|
+
byLifecycle
|
|
913
1066
|
})
|
|
914
1067
|
};
|
|
915
1068
|
};
|
|
916
|
-
const resolveMergedOverall = ({ byAncestry, byPR }) => {
|
|
917
|
-
if (byPR === true) return true;
|
|
918
|
-
if (
|
|
919
|
-
return
|
|
1069
|
+
const resolveMergedOverall = ({ byAncestry, byPR, byLifecycle }) => {
|
|
1070
|
+
if (byPR === true || byLifecycle === true) return true;
|
|
1071
|
+
if (byAncestry === false) return false;
|
|
1072
|
+
if (byPR === false || byLifecycle === false) return false;
|
|
1073
|
+
return null;
|
|
920
1074
|
};
|
|
921
1075
|
const resolveUpstreamState = async (worktreePath) => {
|
|
922
1076
|
const upstreamRef = await runGitCommand({
|
|
@@ -968,6 +1122,7 @@ const enrichWorktree = async ({ repoRoot, worktree, baseBranch, enableGh }) => {
|
|
|
968
1122
|
resolveMergedState({
|
|
969
1123
|
repoRoot,
|
|
970
1124
|
branch: worktree.branch,
|
|
1125
|
+
head: worktree.head,
|
|
971
1126
|
baseBranch,
|
|
972
1127
|
enableGh
|
|
973
1128
|
}),
|
|
@@ -1690,6 +1845,22 @@ const resolveBaseBranch = async (repoRoot) => {
|
|
|
1690
1845
|
for (const candidate of ["main", "master"]) if (await doesGitRefExist(repoRoot, `refs/heads/${candidate}`)) return candidate;
|
|
1691
1846
|
throw createCliError("INVALID_ARGUMENT", { message: "Unable to resolve base branch. Configure vde-worktree.baseBranch." });
|
|
1692
1847
|
};
|
|
1848
|
+
const resolveBranchHead = async ({ repoRoot, branch }) => {
|
|
1849
|
+
const resolved = await runGitCommand({
|
|
1850
|
+
cwd: repoRoot,
|
|
1851
|
+
args: [
|
|
1852
|
+
"rev-parse",
|
|
1853
|
+
"--verify",
|
|
1854
|
+
branch
|
|
1855
|
+
],
|
|
1856
|
+
reject: false
|
|
1857
|
+
});
|
|
1858
|
+
if (resolved.exitCode !== 0 || resolved.stdout.trim().length === 0) throw createCliError("INVALID_ARGUMENT", {
|
|
1859
|
+
message: `Failed to resolve branch head: ${branch}`,
|
|
1860
|
+
details: { branch }
|
|
1861
|
+
});
|
|
1862
|
+
return resolved.stdout.trim();
|
|
1863
|
+
};
|
|
1693
1864
|
const ensureTargetPathWritable = async (targetPath) => {
|
|
1694
1865
|
try {
|
|
1695
1866
|
await access(targetPath, constants.F_OK);
|
|
@@ -2818,6 +2989,15 @@ const createCli = (options = {}) => {
|
|
|
2818
2989
|
baseBranch
|
|
2819
2990
|
]
|
|
2820
2991
|
});
|
|
2992
|
+
await upsertWorktreeMergeLifecycle({
|
|
2993
|
+
repoRoot,
|
|
2994
|
+
branch,
|
|
2995
|
+
baseBranch,
|
|
2996
|
+
createdHead: await resolveBranchHead({
|
|
2997
|
+
repoRoot,
|
|
2998
|
+
branch
|
|
2999
|
+
})
|
|
3000
|
+
});
|
|
2821
3001
|
await runPostHook({
|
|
2822
3002
|
name: "new",
|
|
2823
3003
|
context: hookContext
|
|
@@ -2848,12 +3028,27 @@ const createCli = (options = {}) => {
|
|
|
2848
3028
|
});
|
|
2849
3029
|
const branch = commandArgs[0];
|
|
2850
3030
|
const result = await runWriteOperation(async () => {
|
|
2851
|
-
const
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
3031
|
+
const snapshot = await collectWorktreeSnapshot(repoRoot);
|
|
3032
|
+
const existing = snapshot.worktrees.find((worktree) => worktree.branch === branch);
|
|
3033
|
+
if (existing !== void 0) {
|
|
3034
|
+
if (snapshot.baseBranch !== null) {
|
|
3035
|
+
const branchHead = await resolveBranchHead({
|
|
3036
|
+
repoRoot,
|
|
3037
|
+
branch
|
|
3038
|
+
});
|
|
3039
|
+
await upsertWorktreeMergeLifecycle({
|
|
3040
|
+
repoRoot,
|
|
3041
|
+
branch,
|
|
3042
|
+
baseBranch: snapshot.baseBranch,
|
|
3043
|
+
createdHead: branchHead
|
|
3044
|
+
});
|
|
3045
|
+
}
|
|
3046
|
+
return {
|
|
3047
|
+
status: "existing",
|
|
3048
|
+
branch,
|
|
3049
|
+
path: existing.path
|
|
3050
|
+
};
|
|
3051
|
+
}
|
|
2857
3052
|
const targetPath = branchToWorktreePath(repoRoot, branch);
|
|
2858
3053
|
await ensureTargetPathWritable(targetPath);
|
|
2859
3054
|
const hookContext = createHookContext({
|
|
@@ -2868,6 +3063,7 @@ const createCli = (options = {}) => {
|
|
|
2868
3063
|
name: "switch",
|
|
2869
3064
|
context: hookContext
|
|
2870
3065
|
});
|
|
3066
|
+
let lifecycleBaseBranch = snapshot.baseBranch;
|
|
2871
3067
|
if (await doesGitRefExist(repoRoot, `refs/heads/${branch}`)) await runGitCommand({
|
|
2872
3068
|
cwd: repoRoot,
|
|
2873
3069
|
args: [
|
|
@@ -2877,17 +3073,33 @@ const createCli = (options = {}) => {
|
|
|
2877
3073
|
branch
|
|
2878
3074
|
]
|
|
2879
3075
|
});
|
|
2880
|
-
else
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
3076
|
+
else {
|
|
3077
|
+
const baseBranch = await resolveBaseBranch(repoRoot);
|
|
3078
|
+
lifecycleBaseBranch = baseBranch;
|
|
3079
|
+
await runGitCommand({
|
|
3080
|
+
cwd: repoRoot,
|
|
3081
|
+
args: [
|
|
3082
|
+
"worktree",
|
|
3083
|
+
"add",
|
|
3084
|
+
"-b",
|
|
3085
|
+
branch,
|
|
3086
|
+
targetPath,
|
|
3087
|
+
baseBranch
|
|
3088
|
+
]
|
|
3089
|
+
});
|
|
3090
|
+
}
|
|
3091
|
+
if (lifecycleBaseBranch !== null) {
|
|
3092
|
+
const branchHead = await resolveBranchHead({
|
|
3093
|
+
repoRoot,
|
|
3094
|
+
branch
|
|
3095
|
+
});
|
|
3096
|
+
await upsertWorktreeMergeLifecycle({
|
|
3097
|
+
repoRoot,
|
|
2886
3098
|
branch,
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
}
|
|
3099
|
+
baseBranch: lifecycleBaseBranch,
|
|
3100
|
+
createdHead: branchHead
|
|
3101
|
+
});
|
|
3102
|
+
}
|
|
2891
3103
|
await runPostHook({
|
|
2892
3104
|
name: "switch",
|
|
2893
3105
|
context: hookContext
|
|
@@ -2987,6 +3199,19 @@ const createCli = (options = {}) => {
|
|
|
2987
3199
|
newPath
|
|
2988
3200
|
]
|
|
2989
3201
|
});
|
|
3202
|
+
if (snapshot.baseBranch !== null) {
|
|
3203
|
+
const branchHead = await resolveBranchHead({
|
|
3204
|
+
repoRoot,
|
|
3205
|
+
branch: newBranch
|
|
3206
|
+
});
|
|
3207
|
+
await moveWorktreeMergeLifecycle({
|
|
3208
|
+
repoRoot,
|
|
3209
|
+
fromBranch: oldBranch,
|
|
3210
|
+
toBranch: newBranch,
|
|
3211
|
+
baseBranch: snapshot.baseBranch,
|
|
3212
|
+
createdHead: branchHead
|
|
3213
|
+
});
|
|
3214
|
+
}
|
|
2990
3215
|
await runPostHook({
|
|
2991
3216
|
name: "mv",
|
|
2992
3217
|
context: hookContext
|
|
@@ -3076,6 +3301,10 @@ const createCli = (options = {}) => {
|
|
|
3076
3301
|
repoRoot,
|
|
3077
3302
|
branch: target.branch
|
|
3078
3303
|
});
|
|
3304
|
+
await deleteWorktreeMergeLifecycle({
|
|
3305
|
+
repoRoot,
|
|
3306
|
+
branch: target.branch
|
|
3307
|
+
});
|
|
3079
3308
|
await runPostHook({
|
|
3080
3309
|
name: "del",
|
|
3081
3310
|
context: hookContext
|
|
@@ -3107,7 +3336,7 @@ const createCli = (options = {}) => {
|
|
|
3107
3336
|
if (parsedArgs.apply === true && parsedArgs.dryRun === true) throw createCliError("INVALID_ARGUMENT", { message: "Cannot use --apply and --dry-run together" });
|
|
3108
3337
|
const dryRun = parsedArgs.apply !== true;
|
|
3109
3338
|
const execute = async () => {
|
|
3110
|
-
const candidates = (await collectWorktreeSnapshot(repoRoot)).worktrees.filter((worktree) => worktree.branch !== null).filter((worktree) => worktree.path !== repoRoot).filter((worktree) => worktree.dirty === false).filter((worktree) => worktree.locked.value === false).filter((worktree) => worktree.merged.
|
|
3339
|
+
const candidates = (await collectWorktreeSnapshot(repoRoot)).worktrees.filter((worktree) => worktree.branch !== null).filter((worktree) => worktree.path !== repoRoot).filter((worktree) => worktree.dirty === false).filter((worktree) => worktree.locked.value === false).filter((worktree) => worktree.merged.overall === true).map((worktree) => worktree.branch);
|
|
3111
3340
|
if (dryRun) return {
|
|
3112
3341
|
deleted: [],
|
|
3113
3342
|
candidates,
|
|
@@ -3150,6 +3379,10 @@ const createCli = (options = {}) => {
|
|
|
3150
3379
|
repoRoot,
|
|
3151
3380
|
branch
|
|
3152
3381
|
});
|
|
3382
|
+
await deleteWorktreeMergeLifecycle({
|
|
3383
|
+
repoRoot,
|
|
3384
|
+
branch
|
|
3385
|
+
});
|
|
3153
3386
|
deleted.push(branch);
|
|
3154
3387
|
}
|
|
3155
3388
|
await runPostHook({
|
|
@@ -3239,8 +3472,19 @@ const createCli = (options = {}) => {
|
|
|
3239
3472
|
`${remote}/${branch}`
|
|
3240
3473
|
]
|
|
3241
3474
|
});
|
|
3242
|
-
const
|
|
3475
|
+
const snapshot = await collectWorktreeSnapshot(repoRoot);
|
|
3476
|
+
const lifecycleBaseBranch = snapshot.baseBranch;
|
|
3477
|
+
const existing = snapshot.worktrees.find((worktree) => worktree.branch === branch);
|
|
3243
3478
|
if (existing !== void 0) {
|
|
3479
|
+
if (lifecycleBaseBranch !== null) await upsertWorktreeMergeLifecycle({
|
|
3480
|
+
repoRoot,
|
|
3481
|
+
branch,
|
|
3482
|
+
baseBranch: lifecycleBaseBranch,
|
|
3483
|
+
createdHead: await resolveBranchHead({
|
|
3484
|
+
repoRoot,
|
|
3485
|
+
branch
|
|
3486
|
+
})
|
|
3487
|
+
});
|
|
3244
3488
|
await runPostHook({
|
|
3245
3489
|
name: "get",
|
|
3246
3490
|
context: hookContext
|
|
@@ -3262,6 +3506,15 @@ const createCli = (options = {}) => {
|
|
|
3262
3506
|
branch
|
|
3263
3507
|
]
|
|
3264
3508
|
});
|
|
3509
|
+
if (lifecycleBaseBranch !== null) await upsertWorktreeMergeLifecycle({
|
|
3510
|
+
repoRoot,
|
|
3511
|
+
branch,
|
|
3512
|
+
baseBranch: lifecycleBaseBranch,
|
|
3513
|
+
createdHead: await resolveBranchHead({
|
|
3514
|
+
repoRoot,
|
|
3515
|
+
branch
|
|
3516
|
+
})
|
|
3517
|
+
});
|
|
3265
3518
|
await runPostHook({
|
|
3266
3519
|
name: "get",
|
|
3267
3520
|
context: hookContext
|
|
@@ -3368,6 +3621,15 @@ const createCli = (options = {}) => {
|
|
|
3368
3621
|
branch
|
|
3369
3622
|
]
|
|
3370
3623
|
});
|
|
3624
|
+
await upsertWorktreeMergeLifecycle({
|
|
3625
|
+
repoRoot,
|
|
3626
|
+
branch,
|
|
3627
|
+
baseBranch,
|
|
3628
|
+
createdHead: await resolveBranchHead({
|
|
3629
|
+
repoRoot,
|
|
3630
|
+
branch
|
|
3631
|
+
})
|
|
3632
|
+
});
|
|
3371
3633
|
if (stashOid !== null) {
|
|
3372
3634
|
if ((await runGitCommand({
|
|
3373
3635
|
cwd: targetPath,
|