@ogpoyraz/wtx 0.8.2 → 0.8.3

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.mjs +68 -3
  2. package/package.json +1 -1
package/dist/cli.mjs CHANGED
@@ -27971,7 +27971,7 @@ function App({ opts }) {
27971
27971
  `Branch will be renamed and the checkout moved to:`,
27972
27972
  getWorktreePathFor(modal.row.repoName, modal.to),
27973
27973
  "",
27974
- "The old directory will be removed.",
27974
+ "Uncommitted changes and synced files move with it.",
27975
27975
  "Proceed?"
27976
27976
  ].join(`
27977
27977
  `)
@@ -31982,6 +31982,27 @@ async function getUpstream(wtPath) {
31982
31982
  return null;
31983
31983
  }
31984
31984
  }
31985
+ async function getDirtyEntries(wtPath) {
31986
+ try {
31987
+ const out = await gitExec(["-C", wtPath, "status", "--porcelain"], {});
31988
+ return out.split(`
31989
+ `).map((line) => line.trimEnd()).filter((line) => line.length > 0);
31990
+ } catch {
31991
+ return [];
31992
+ }
31993
+ }
31994
+ function touchesEntry(porcelainLine, entry) {
31995
+ const entryPath = porcelainLine.slice(3);
31996
+ return entryPath === entry || entryPath.startsWith(`${entry}/`);
31997
+ }
31998
+ async function isTrackedInWorktree(wtPath, entry) {
31999
+ try {
32000
+ await gitExec(["-C", wtPath, "ls-files", "--error-unmatch", "--", entry], {});
32001
+ return true;
32002
+ } catch {
32003
+ return false;
32004
+ }
32005
+ }
31985
32006
  async function planRename(repo, oldBranch, newBranch, opts) {
31986
32007
  const list = await getWorktreeList(repo.mainPath);
31987
32008
  const candidatePath = getWorktreePath(repo, oldBranch);
@@ -32005,6 +32026,7 @@ async function renameWorktree(params) {
32005
32026
  const { repo, oldBranch, newBranch, opts } = params;
32006
32027
  const planned = await planRename(repo, oldBranch, newBranch, opts);
32007
32028
  const cleanedDirs = [];
32029
+ const dirtyBefore = await getDirtyEntries(planned.worktreePath);
32008
32030
  if (opts.dryRun) {
32009
32031
  return {
32010
32032
  oldBranch,
@@ -32012,7 +32034,11 @@ async function renameWorktree(params) {
32012
32034
  oldPath: planned.worktreePath,
32013
32035
  newPath: planned.newPath,
32014
32036
  upstream: planned.upstream,
32015
- cleanedDirs
32037
+ cleanedDirs,
32038
+ dirtyFiles: dirtyBefore,
32039
+ lostDirtyFiles: [],
32040
+ resyncedFiles: [],
32041
+ keptLocalSyncFiles: []
32016
32042
  };
32017
32043
  }
32018
32044
  await gitExec(["-C", planned.worktreePath, "branch", "-m", oldBranch, newBranch], opts);
@@ -32030,13 +32056,40 @@ async function renameWorktree(params) {
32030
32056
  for (const dir of cleanupEmptyParents(repo.wtRoot, repo.mainPath, planned.worktreePath)) {
32031
32057
  cleanedDirs.push(dir);
32032
32058
  }
32059
+ const dirtyAfter = await getDirtyEntries(planned.newPath);
32060
+ const lostDirtyFiles = dirtyBefore.filter((line) => !dirtyAfter.includes(line));
32061
+ const resyncedFiles = [];
32062
+ const keptLocalSyncFiles = [];
32063
+ for (const entry of repo.config.sync_files ?? []) {
32064
+ if (!fs28.existsSync(path33.join(repo.mainPath, entry)))
32065
+ continue;
32066
+ const destPath = path33.join(planned.newPath, entry);
32067
+ if (!fs28.existsSync(destPath)) {
32068
+ if (syncEntry(repo.mainPath, planned.newPath, entry)) {
32069
+ resyncedFiles.push(entry);
32070
+ }
32071
+ continue;
32072
+ }
32073
+ const tracked = await isTrackedInWorktree(planned.newPath, entry);
32074
+ if (tracked && !dirtyAfter.some((line) => touchesEntry(line, entry))) {
32075
+ if (syncEntry(repo.mainPath, planned.newPath, entry)) {
32076
+ resyncedFiles.push(entry);
32077
+ }
32078
+ continue;
32079
+ }
32080
+ keptLocalSyncFiles.push(entry);
32081
+ }
32033
32082
  return {
32034
32083
  oldBranch,
32035
32084
  newBranch,
32036
32085
  oldPath: planned.worktreePath,
32037
32086
  newPath: planned.newPath,
32038
32087
  upstream: planned.upstream,
32039
- cleanedDirs
32088
+ cleanedDirs,
32089
+ dirtyFiles: dirtyAfter,
32090
+ lostDirtyFiles,
32091
+ resyncedFiles,
32092
+ keptLocalSyncFiles
32040
32093
  };
32041
32094
  }
32042
32095
 
@@ -32082,6 +32135,18 @@ function registerRenameCommand(program2) {
32082
32135
  stepSuccess("Cleaned up empty directory", path34.relative(repo.wtRoot, dir) + "/");
32083
32136
  }
32084
32137
  stepSuccess("Renamed", `${outcome.oldPath} → ${outcome.newPath}`);
32138
+ if (outcome.dirtyFiles.length > 0) {
32139
+ stepSuccess("Carried uncommitted files", `${outcome.dirtyFiles.length} entr${outcome.dirtyFiles.length === 1 ? "y" : "ies"} moved with the checkout`);
32140
+ }
32141
+ if (outcome.lostDirtyFiles.length > 0) {
32142
+ stepError("Uncommitted changes missing after rename", outcome.lostDirtyFiles.join(", "));
32143
+ }
32144
+ if (outcome.resyncedFiles.length > 0) {
32145
+ stepSuccess("Synced files", outcome.resyncedFiles.join(", "));
32146
+ }
32147
+ for (const entry of outcome.keptLocalSyncFiles) {
32148
+ indented(`Kept local version of ${entry} — it has uncommitted edits`);
32149
+ }
32085
32150
  if (outcome.upstream) {
32086
32151
  indented(`Upstream still tracks '${outcome.upstream}' — after pushing run: git push -u origin ${newBranch}`);
32087
32152
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ogpoyraz/wtx",
3
- "version": "0.8.2",
3
+ "version": "0.8.3",
4
4
  "description": "Multi-repo git worktree manager",
5
5
  "type": "module",
6
6
  "bin": {