git-sync-tui 0.1.7 → 0.1.8

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 (2) hide show
  1. package/dist/cli.js +47 -49
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -1,17 +1,11 @@
1
1
  #!/usr/bin/env node
2
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
3
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
4
- }) : x)(function(x) {
5
- if (typeof require !== "undefined") return require.apply(this, arguments);
6
- throw Error('Dynamic require of "' + x + '" is not supported');
7
- });
8
2
 
9
3
  // src/cli.tsx
10
4
  import { render } from "ink";
11
5
  import meow from "meow";
12
6
 
13
7
  // src/app.tsx
14
- import { useState as useState9, useEffect as useEffect7, useRef as useRef5, useCallback as useCallback3 } from "react";
8
+ import { useState as useState9, useEffect as useEffect7, useRef as useRef5, useCallback as useCallback4 } from "react";
15
9
  import { Box as Box11, useApp } from "ink";
16
10
  import { Spinner as Spinner7 } from "@inkjs/ui";
17
11
 
@@ -140,11 +134,13 @@ import { Spinner } from "@inkjs/ui";
140
134
  // src/utils/git.ts
141
135
  import simpleGit from "simple-git";
142
136
  import { existsSync, writeFileSync, unlinkSync, readFileSync } from "fs";
137
+ import { execSync } from "child_process";
143
138
  import { join } from "path";
144
139
  var gitInstance = null;
145
140
  function getGit(cwd) {
146
- if (!gitInstance || cwd) {
147
- gitInstance = simpleGit(cwd);
141
+ if (cwd) return simpleGit(cwd);
142
+ if (!gitInstance) {
143
+ gitInstance = simpleGit();
148
144
  }
149
145
  return gitInstance;
150
146
  }
@@ -227,13 +223,14 @@ async function getMultiCommitStat(hashes) {
227
223
  if (hashes.length === 0) return "";
228
224
  const git = getGit();
229
225
  try {
230
- const stats = [];
231
- for (const hash of hashes) {
232
- const result = await git.raw(["diff-tree", "--stat", "--no-commit-id", "-r", hash]);
233
- if (result.trim()) stats.push(`${hash.substring(0, 7)}:
234
- ${result.trim()}`);
235
- }
236
- return stats.join("\n\n");
226
+ const results = await Promise.all(
227
+ hashes.map(async (hash) => {
228
+ const result = await git.raw(["diff-tree", "--stat", "--no-commit-id", "-r", hash]);
229
+ return result.trim() ? `${hash.substring(0, 7)}:
230
+ ${result.trim()}` : "";
231
+ })
232
+ );
233
+ return results.filter(Boolean).join("\n\n");
237
234
  } catch {
238
235
  return "(\u65E0\u6CD5\u83B7\u53D6 stat \u4FE1\u606F)";
239
236
  }
@@ -454,8 +451,7 @@ async function removeStashGuard() {
454
451
  }
455
452
  function removeStashGuardSync() {
456
453
  try {
457
- const { execSync: execSync2 } = __require("child_process");
458
- const gitDir = String(execSync2("git rev-parse --git-dir", { encoding: "utf-8" })).trim();
454
+ const gitDir = String(execSync("git rev-parse --git-dir", { encoding: "utf-8" })).trim();
459
455
  const guardPath = join(gitDir, STASH_GUARD_FILE);
460
456
  if (existsSync(guardPath)) {
461
457
  unlinkSync(guardPath);
@@ -542,10 +538,12 @@ function useAsync(fn, deps = []) {
542
538
  loading: true,
543
539
  error: null
544
540
  });
541
+ const fnRef = useRef(fn);
542
+ fnRef.current = fn;
545
543
  const load = useCallback(async () => {
546
544
  setState({ data: null, loading: true, error: null });
547
545
  try {
548
- const data = await fn();
546
+ const data = await fnRef.current();
549
547
  setState({ data, loading: false, error: null });
550
548
  } catch (err) {
551
549
  setState({ data: null, loading: false, error: err.message });
@@ -612,20 +610,23 @@ function useCommits(remote2, branch2, pageSize = 100) {
612
610
  function useCommitStat(hashes) {
613
611
  const [stat, setStat] = useState2("");
614
612
  const [loading, setLoading] = useState2(false);
613
+ const hashKey = hashes.join(",");
614
+ const stableHashes = useRef(hashes);
615
+ stableHashes.current = hashes;
615
616
  useEffect2(() => {
616
- if (hashes.length === 0) {
617
+ if (stableHashes.current.length === 0) {
617
618
  setStat("");
618
619
  return;
619
620
  }
620
621
  setLoading(true);
621
- getMultiCommitStat(hashes).then((s) => {
622
+ getMultiCommitStat(stableHashes.current).then((s) => {
622
623
  setStat(s);
623
624
  setLoading(false);
624
625
  }).catch(() => {
625
626
  setStat("(\u83B7\u53D6\u5931\u8D25)");
626
627
  setLoading(false);
627
628
  });
628
- }, [hashes.join(",")]);
629
+ }, [hashKey]);
629
630
  return { stat, loading };
630
631
  }
631
632
 
@@ -1180,6 +1181,8 @@ function BranchCheck({ targetBranch, onContinue, onBack }) {
1180
1181
  const [error2, setError] = useState6(null);
1181
1182
  const [matched, setMatched] = useState6(false);
1182
1183
  const autoCreated = useRef3(false);
1184
+ const onContinueRef = useRef3(onContinue);
1185
+ onContinueRef.current = onContinue;
1183
1186
  useEffect4(() => {
1184
1187
  getCurrentBranch().then((branch2) => {
1185
1188
  setCurrentBranch(branch2);
@@ -1189,7 +1192,7 @@ function BranchCheck({ targetBranch, onContinue, onBack }) {
1189
1192
  });
1190
1193
  }, [targetBranch]);
1191
1194
  useEffect4(() => {
1192
- if (matched) onContinue();
1195
+ if (matched) onContinueRef.current();
1193
1196
  }, [matched]);
1194
1197
  useEffect4(() => {
1195
1198
  if (currentBranch === null || matched || autoCreated.current) return;
@@ -1197,7 +1200,7 @@ function BranchCheck({ targetBranch, onContinue, onBack }) {
1197
1200
  autoCreated.current = true;
1198
1201
  setCreating(true);
1199
1202
  createBranchFrom(targetBranch, currentBranch).then(() => {
1200
- onContinue();
1203
+ onContinueRef.current();
1201
1204
  }).catch((err) => {
1202
1205
  setCreating(false);
1203
1206
  setError(err.message);
@@ -1333,7 +1336,7 @@ function ConfirmPanel({ commits: commits2, selectedHashes, hasMerge, useMainline
1333
1336
  }
1334
1337
 
1335
1338
  // src/components/result-panel.tsx
1336
- import { useState as useState7, useEffect as useEffect5, useCallback as useCallback2, useRef as useRef4 } from "react";
1339
+ import { useState as useState7, useEffect as useEffect5, useCallback as useCallback3, useRef as useRef4 } from "react";
1337
1340
  import { Box as Box9, Text as Text9, useInput as useInput8 } from "ink";
1338
1341
  import { Spinner as Spinner6 } from "@inkjs/ui";
1339
1342
  import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
@@ -1349,7 +1352,7 @@ function ResultPanel({ selectedHashes, useMainline, noCommit, stashed, onStashRe
1349
1352
  const remainingRef = useRef4([]);
1350
1353
  const backupBranchRef = useRef4("");
1351
1354
  const orderedHashes = useRef4([...selectedHashes].reverse());
1352
- const tryRestoreStash = useCallback2(async () => {
1355
+ const tryRestoreStash = useCallback3(async () => {
1353
1356
  if (!stashed) return true;
1354
1357
  setPhase("restoring");
1355
1358
  const ok = await stashPop();
@@ -1357,7 +1360,7 @@ function ResultPanel({ selectedHashes, useMainline, noCommit, stashed, onStashRe
1357
1360
  if (ok) onStashRestored();
1358
1361
  return ok;
1359
1362
  }, [stashed, onStashRestored]);
1360
- const finishAll = useCallback2(async () => {
1363
+ const finishAll = useCallback3(async () => {
1361
1364
  if (noCommit) {
1362
1365
  const stat = await getStagedStat();
1363
1366
  setStagedStat(stat);
@@ -1368,7 +1371,7 @@ function ResultPanel({ selectedHashes, useMainline, noCommit, stashed, onStashRe
1368
1371
  await tryRestoreStash();
1369
1372
  setPhase("done");
1370
1373
  }, [noCommit, tryRestoreStash]);
1371
- const executeFrom = useCallback2(async (startIndex) => {
1374
+ const executeFrom = useCallback3(async (startIndex) => {
1372
1375
  const hashes = orderedHashes.current;
1373
1376
  for (let i = startIndex; i < hashes.length; i++) {
1374
1377
  setCurrentIndex(i);
@@ -1389,7 +1392,7 @@ function ResultPanel({ selectedHashes, useMainline, noCommit, stashed, onStashRe
1389
1392
  executeFrom(0);
1390
1393
  });
1391
1394
  }, []);
1392
- const continueRemaining = useCallback2(async () => {
1395
+ const continueRemaining = useCallback3(async () => {
1393
1396
  const remaining = remainingRef.current;
1394
1397
  if (remaining.length === 0) {
1395
1398
  await finishAll();
@@ -1409,7 +1412,7 @@ function ResultPanel({ selectedHashes, useMainline, noCommit, stashed, onStashRe
1409
1412
  }
1410
1413
  await finishAll();
1411
1414
  }, [useMainline, noCommit, finishAll]);
1412
- const handleContinue = useCallback2(async () => {
1415
+ const handleContinue = useCallback3(async () => {
1413
1416
  const conflicts = await getConflictFiles();
1414
1417
  if (conflicts.length > 0) {
1415
1418
  setConflictFiles(conflicts);
@@ -1442,14 +1445,14 @@ function ResultPanel({ selectedHashes, useMainline, noCommit, stashed, onStashRe
1442
1445
  await continueRemaining();
1443
1446
  }
1444
1447
  }, [noCommit, continueRemaining]);
1445
- const handleSkip = useCallback2(async () => {
1448
+ const handleSkip = useCallback3(async () => {
1446
1449
  setPhase("continuing");
1447
1450
  setErrorMsg("");
1448
1451
  await skipCherryPick();
1449
1452
  setSkippedCount((c) => c + 1);
1450
1453
  await continueRemaining();
1451
1454
  }, [continueRemaining]);
1452
- const handleAbort = useCallback2(async () => {
1455
+ const handleAbort = useCallback3(async () => {
1453
1456
  setPhase("aborting");
1454
1457
  await abortCherryPick();
1455
1458
  if (backupBranchRef.current) {
@@ -1741,11 +1744,9 @@ function UpdateBanner({ currentVersion }) {
1741
1744
  }
1742
1745
 
1743
1746
  // src/app.tsx
1744
- import { execSync } from "child_process";
1745
- import { createRequire } from "module";
1747
+ import { execSync as execSync2 } from "child_process";
1746
1748
  import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
1747
- var require2 = createRequire(import.meta.url);
1748
- var { version: APP_VERSION } = require2("../package.json");
1749
+ var APP_VERSION = "0.1.8";
1749
1750
  var STEP_NUMBER = {
1750
1751
  checking: 0,
1751
1752
  "stash-recovery": 0,
@@ -1776,7 +1777,7 @@ function App({ initialRemote, initialBranch }) {
1776
1777
  const stashRestoredRef = useRef5(false);
1777
1778
  const mountedRef = useRef5(true);
1778
1779
  const debounceTimer = useRef5(null);
1779
- const setStep = useCallback3((newStep) => {
1780
+ const setStep = useCallback4((newStep) => {
1780
1781
  setInputReady(false);
1781
1782
  setStepRaw(newStep);
1782
1783
  if (debounceTimer.current) clearTimeout(debounceTimer.current);
@@ -1784,10 +1785,10 @@ function App({ initialRemote, initialBranch }) {
1784
1785
  if (mountedRef.current) setInputReady(true);
1785
1786
  }, STEP_DEBOUNCE);
1786
1787
  }, []);
1787
- const restoreStashSync = useCallback3(() => {
1788
+ const restoreStashSync = useCallback4(() => {
1788
1789
  if (stashedRef.current && !stashRestoredRef.current) {
1789
1790
  try {
1790
- execSync("git stash pop", { stdio: "ignore" });
1791
+ execSync2("git stash pop", { stdio: "ignore" });
1791
1792
  stashRestoredRef.current = true;
1792
1793
  removeStashGuardSync();
1793
1794
  } catch {
@@ -1798,7 +1799,7 @@ function App({ initialRemote, initialBranch }) {
1798
1799
  }
1799
1800
  }
1800
1801
  }, []);
1801
- const markStashRestored = useCallback3(() => {
1802
+ const markStashRestored = useCallback4(() => {
1802
1803
  stashRestoredRef.current = true;
1803
1804
  removeStashGuard();
1804
1805
  }, []);
@@ -1857,7 +1858,7 @@ function App({ initialRemote, initialBranch }) {
1857
1858
  const clean = await isWorkingDirClean();
1858
1859
  if (mountedRef.current) setStep(clean ? entryStep : "stash-prompt");
1859
1860
  };
1860
- const goBack = useCallback3((fromStep) => {
1861
+ const goBack = useCallback4((fromStep) => {
1861
1862
  const backMap = {
1862
1863
  branch: "remote",
1863
1864
  "branch-check": "branch",
@@ -1924,9 +1925,11 @@ function App({ initialRemote, initialBranch }) {
1924
1925
  {
1925
1926
  remote: remote2,
1926
1927
  branch: branch2,
1927
- onSelect: (hashes, loadedCommits) => {
1928
+ onSelect: async (hashes, loadedCommits) => {
1928
1929
  setSelectedHashes(hashes);
1929
1930
  setCommits(loadedCommits);
1931
+ const merge = await hasMergeCommits(hashes);
1932
+ setHasMerge(merge);
1930
1933
  setStep("confirm");
1931
1934
  },
1932
1935
  onBack: () => goBack("commits")
@@ -1966,18 +1969,13 @@ function App({ initialRemote, initialBranch }) {
1966
1969
 
1967
1970
  // src/cli-runner.ts
1968
1971
  import { createInterface } from "readline";
1969
- import { createRequire as createRequire2 } from "module";
1970
- var require3 = createRequire2(import.meta.url);
1971
- var { version: APP_VERSION2 } = require3("../package.json");
1972
+ var APP_VERSION2 = "0.1.8";
1972
1973
  function log(msg) {
1973
1974
  process.stdout.write(msg + "\n");
1974
1975
  }
1975
1976
  function error(msg) {
1976
1977
  process.stderr.write(msg + "\n");
1977
1978
  }
1978
- function padEnd(str, len) {
1979
- return str.length >= len ? str : str + " ".repeat(len - str.length);
1980
- }
1981
1979
  async function confirm(message) {
1982
1980
  const rl = createInterface({ input: process.stdin, output: process.stdout });
1983
1981
  return new Promise((resolve) => {
@@ -2039,7 +2037,7 @@ async function validateBranch(remote2, branch2) {
2039
2037
  log(`\u2714 \u5206\u652F '${remote2}/${branch2}'`);
2040
2038
  }
2041
2039
  function formatCommitLine(c) {
2042
- return ` ${c.shortHash} ${padEnd(c.message.slice(0, 60), 62)} ${padEnd(c.author, 16)} ${c.date}`;
2040
+ return ` ${c.shortHash} ${c.message.slice(0, 60).padEnd(62)} ${c.author.padEnd(16)} ${c.date}`;
2043
2041
  }
2044
2042
  async function runList(opts) {
2045
2043
  await validateRemote(opts.remote);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "git-sync-tui",
3
3
  "type": "module",
4
- "version": "0.1.7",
4
+ "version": "0.1.8",
5
5
  "packageManager": "pnpm@10.32.1",
6
6
  "description": "Interactive TUI tool for cross-repo git commit synchronization (cherry-pick --no-commit)",
7
7
  "author": "KiWi233333",