worktree-add 1.2.0 → 1.3.0
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/README.md +59 -23
- package/dist/app/get-unsafe-app-name-reason.d.ts +11 -0
- package/dist/app/get-unsafe-app-name-reason.js +21 -0
- package/dist/app/resolve-apps.d.ts +6 -0
- package/dist/app/resolve-apps.js +31 -0
- package/dist/cli/cleanup-worktree.d.ts +2 -0
- package/dist/cli/cleanup-worktree.js +13 -0
- package/dist/cli/open-worktree-apps.d.ts +5 -0
- package/dist/cli/open-worktree-apps.js +33 -0
- package/dist/cli/register-sigint-handler.d.ts +8 -0
- package/dist/cli/register-sigint-handler.js +19 -0
- package/dist/cli/resolve-worktree-context.d.ts +6 -0
- package/dist/cli/resolve-worktree-context.js +22 -0
- package/dist/cli/run-worktree-add.d.ts +9 -0
- package/dist/cli/run-worktree-add.js +100 -0
- package/dist/cli.d.ts +0 -6
- package/dist/cli.js +38 -70
- package/dist/git/create-worktree.d.ts +9 -0
- package/dist/git/create-worktree.js +39 -0
- package/dist/git/extract-diagnostic-line.d.ts +1 -0
- package/dist/git/extract-diagnostic-line.js +13 -0
- package/dist/git/fetch-remote-branch.d.ts +9 -0
- package/dist/git/fetch-remote-branch.js +102 -0
- package/dist/git/git.d.ts +22 -0
- package/dist/git/git.js +63 -9
- package/dist/git/remove-worktree.d.ts +1 -0
- package/dist/git/remove-worktree.js +4 -0
- package/dist/output/create-status-logger.d.ts +13 -0
- package/dist/output/create-status-logger.js +32 -0
- package/dist/output/get-status-logger.d.ts +2 -0
- package/dist/output/get-status-logger.js +12 -0
- package/dist/project/install-commands.js +2 -2
- package/dist/project/next.d.ts +4 -1
- package/dist/project/next.js +2 -2
- package/dist/project/package-manager.d.ts +7 -1
- package/dist/project/package-manager.js +12 -3
- package/dist/project/setup.d.ts +5 -1
- package/dist/project/setup.js +15 -7
- package/dist/worktree/destination-directory.d.ts +10 -3
- package/dist/worktree/destination-directory.js +94 -16
- package/dist/worktree/untracked-file-copy.d.ts +5 -1
- package/dist/worktree/untracked-file-copy.js +51 -9
- package/package.json +24 -31
- package/dist/git/worktree-creation.d.ts +0 -13
- package/dist/git/worktree-creation.js +0 -38
|
@@ -7,29 +7,71 @@ import * as fs from "node:fs/promises";
|
|
|
7
7
|
import path from "node:path";
|
|
8
8
|
import { git } from "../git/git.js";
|
|
9
9
|
import { EXTRA_IGNORED_PATTERNS, globToRegExp, toPosixPath, } from "./file-patterns.js";
|
|
10
|
+
import { getStatusLogger } from "../output/get-status-logger.js";
|
|
10
11
|
/**
|
|
11
12
|
* Copy untracked files from source to destination, excluding ignored patterns
|
|
12
13
|
*/
|
|
13
|
-
export async function copyUntrackedFiles(repoRoot, destinationDirectory) {
|
|
14
|
+
export async function copyUntrackedFiles(repoRoot, destinationDirectory, options) {
|
|
15
|
+
const logger = getStatusLogger(options?.logger);
|
|
16
|
+
const dryRun = options?.dryRun ?? false;
|
|
14
17
|
const extraIgnoredRegexes = EXTRA_IGNORED_PATTERNS.map((pattern) => globToRegExp(pattern));
|
|
15
|
-
const untrackedEntries =
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
const untrackedEntries = new Set();
|
|
19
|
+
// Combine untracked-not-ignored (`--others`) and untracked-ignored (`--others --ignored`) entries.
|
|
20
|
+
// These sets should be disjoint, but we dedupe defensively.
|
|
21
|
+
const untrackedPaths = [
|
|
22
|
+
...git("ls-files", "--others", "--exclude-standard", "--full-name", "-z", // null-separated output for safe parsing
|
|
23
|
+
{ cwd: repoRoot })
|
|
24
|
+
.split("\0")
|
|
25
|
+
.filter(Boolean),
|
|
26
|
+
...git("ls-files", "--others", "--ignored", "--exclude-standard", "--full-name", "-z", // null-separated output for safe parsing
|
|
27
|
+
{ cwd: repoRoot })
|
|
28
|
+
.split("\0")
|
|
29
|
+
.filter(Boolean),
|
|
30
|
+
];
|
|
31
|
+
for (const entry of untrackedPaths) {
|
|
32
|
+
untrackedEntries.add(entry);
|
|
33
|
+
}
|
|
21
34
|
for (const relativePath of untrackedEntries) {
|
|
35
|
+
const resolvedSourcePath = path.resolve(repoRoot, relativePath);
|
|
36
|
+
const relativeToRoot = path.relative(repoRoot, resolvedSourcePath);
|
|
37
|
+
const escapesRepoRoot = path.isAbsolute(relativeToRoot) ||
|
|
38
|
+
relativeToRoot === ".." ||
|
|
39
|
+
relativeToRoot.startsWith(`..${path.sep}`);
|
|
40
|
+
if (escapesRepoRoot) {
|
|
41
|
+
logger.warn(`Skipping ${relativePath} (path escapes repo root).`);
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
22
44
|
const posixPath = toPosixPath(relativePath);
|
|
23
45
|
if (extraIgnoredRegexes.some((regex) => regex.test(posixPath))) {
|
|
24
46
|
continue;
|
|
25
47
|
}
|
|
26
|
-
const sourcePath =
|
|
48
|
+
const sourcePath = resolvedSourcePath;
|
|
27
49
|
const destinationPath = path.join(destinationDirectory, relativePath);
|
|
50
|
+
const destinationExists = await fs
|
|
51
|
+
.stat(destinationPath)
|
|
52
|
+
.then(() => true)
|
|
53
|
+
.catch((error) => {
|
|
54
|
+
if (error &&
|
|
55
|
+
typeof error === "object" &&
|
|
56
|
+
"code" in error &&
|
|
57
|
+
error.code === "ENOENT") {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
throw error;
|
|
61
|
+
});
|
|
62
|
+
if (destinationExists) {
|
|
63
|
+
logger.detail(`Skipped ${relativePath} (destination already exists).`);
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
if (dryRun) {
|
|
67
|
+
logger.detail(`Would copy ${relativePath}`);
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
28
70
|
await fs.mkdir(path.dirname(destinationPath), { recursive: true });
|
|
29
71
|
await fs.cp(sourcePath, destinationPath, {
|
|
30
72
|
recursive: true,
|
|
31
73
|
errorOnExist: false,
|
|
32
74
|
});
|
|
33
|
-
|
|
75
|
+
logger.detail(`Copied ${relativePath}`);
|
|
34
76
|
}
|
|
35
77
|
}
|
package/package.json
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
"name": "worktree-add",
|
|
3
3
|
"author": "Łukasz Jerciński",
|
|
4
4
|
"license": "MIT",
|
|
5
|
-
"version": "1.
|
|
6
|
-
"description": "Create a Git worktree next to your current repo for a branch, copy useful local files, install deps, and open it in your
|
|
5
|
+
"version": "1.3.0",
|
|
6
|
+
"description": "Create a Git worktree next to your current repo for a branch, copy useful local files, install deps, and open it in your apps.",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
9
|
"url": "git+https://github.com/Jercik/worktree-add.git"
|
|
@@ -23,21 +23,21 @@
|
|
|
23
23
|
"LICENSE"
|
|
24
24
|
],
|
|
25
25
|
"scripts": {
|
|
26
|
-
"
|
|
26
|
+
"prepare": "git config core.hooksPath .githooks",
|
|
27
|
+
"prepublishOnly": "pnpm run rebuild",
|
|
27
28
|
"build": "tsc -p tsconfig.app.json",
|
|
28
29
|
"clean": "rm -rf dist *.tsbuildinfo",
|
|
29
|
-
"rebuild": "pnpm run clean && pnpm run build",
|
|
30
|
-
"prepare": "husky",
|
|
31
|
-
"prepublishOnly": "pnpm run rebuild",
|
|
32
|
-
"typecheck": "tsc -b --noEmit",
|
|
33
30
|
"format": "prettier --write .",
|
|
34
31
|
"format:check": "prettier --check .",
|
|
32
|
+
"fta": "fta-check",
|
|
33
|
+
"knip": "knip",
|
|
35
34
|
"lint": "eslint",
|
|
35
|
+
"rebuild": "pnpm run clean && pnpm run build",
|
|
36
|
+
"start": "pnpm run rebuild && node bin/worktree-add",
|
|
36
37
|
"test": "vitest run",
|
|
37
|
-
"test:watch": "vitest",
|
|
38
38
|
"test:coverage": "vitest run --coverage",
|
|
39
|
-
"
|
|
40
|
-
"
|
|
39
|
+
"test:watch": "vitest",
|
|
40
|
+
"typecheck": "tsc -b --noEmit"
|
|
41
41
|
},
|
|
42
42
|
"keywords": [
|
|
43
43
|
"git",
|
|
@@ -47,36 +47,29 @@
|
|
|
47
47
|
"git-worktree",
|
|
48
48
|
"development"
|
|
49
49
|
],
|
|
50
|
-
"packageManager": "pnpm@10.
|
|
50
|
+
"packageManager": "pnpm@10.25.0",
|
|
51
51
|
"engines": {
|
|
52
52
|
"node": ">=22.14.0"
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
|
+
"@commander-js/extra-typings": "^14.0.0",
|
|
55
56
|
"commander": "^14.0.2",
|
|
56
|
-
"
|
|
57
|
-
"
|
|
57
|
+
"open": "^11.0.0",
|
|
58
|
+
"package-manager-detector": "^1.6.0",
|
|
59
|
+
"trash": "^10.0.1"
|
|
58
60
|
},
|
|
59
61
|
"devDependencies": {
|
|
60
|
-
"@commitlint/cli": "^20.1.0",
|
|
61
|
-
"@commitlint/config-conventional": "^20.0.0",
|
|
62
|
-
"@eslint/compat": "^1.3.2",
|
|
63
|
-
"@eslint/js": "^9.31.0",
|
|
64
62
|
"@total-typescript/ts-reset": "^0.6.1",
|
|
65
|
-
"@types/node": "^
|
|
66
|
-
"@vitest/coverage-v8": "^
|
|
67
|
-
"
|
|
68
|
-
"eslint": "^
|
|
69
|
-
"
|
|
70
|
-
"eslint-plugin-unicorn": "^62.0.0",
|
|
71
|
-
"fta-check": "^1.1.0",
|
|
63
|
+
"@types/node": "^25.0.10",
|
|
64
|
+
"@vitest/coverage-v8": "^4.0.18",
|
|
65
|
+
"eslint": "^9.39.2",
|
|
66
|
+
"eslint-config-axkit": "^1.1.0",
|
|
67
|
+
"fta-check": "^1.5.1",
|
|
72
68
|
"fta-cli": "^3.0.0",
|
|
73
|
-
"
|
|
74
|
-
"
|
|
75
|
-
"knip": "^5.66.4",
|
|
76
|
-
"prettier": "3.6.2",
|
|
69
|
+
"knip": "^5.82.1",
|
|
70
|
+
"prettier": "3.7.4",
|
|
77
71
|
"semantic-release": "^25.0.2",
|
|
78
|
-
"typescript": "^5.
|
|
79
|
-
"
|
|
80
|
-
"vitest": "^3.2.4"
|
|
72
|
+
"typescript": "^5.9.3",
|
|
73
|
+
"vitest": "^4.0.18"
|
|
81
74
|
}
|
|
82
75
|
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* worktree-creation.ts
|
|
3
|
-
*
|
|
4
|
-
* Utilities for creating Git worktrees
|
|
5
|
-
*/
|
|
6
|
-
/**
|
|
7
|
-
* Fetch a remote branch if it exists locally but not remotely
|
|
8
|
-
*/
|
|
9
|
-
export declare function fetchRemoteBranch(branch: string): void;
|
|
10
|
-
/**
|
|
11
|
-
* Create a worktree for the given branch at the specified destination
|
|
12
|
-
*/
|
|
13
|
-
export declare function createWorktree(branch: string, destinationDirectory: string): void;
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* worktree-creation.ts
|
|
3
|
-
*
|
|
4
|
-
* Utilities for creating Git worktrees
|
|
5
|
-
*/
|
|
6
|
-
import { spawnSync } from "node:child_process";
|
|
7
|
-
import { git, localBranchExists, remoteBranchExists } from "./git.js";
|
|
8
|
-
/**
|
|
9
|
-
* Fetch a remote branch if it exists locally but not remotely
|
|
10
|
-
*/
|
|
11
|
-
export function fetchRemoteBranch(branch) {
|
|
12
|
-
if (!localBranchExists(branch) && remoteBranchExists(branch)) {
|
|
13
|
-
console.log(`➤ Fetching origin/${branch} …`);
|
|
14
|
-
spawnSync("git", ["fetch", "origin", branch], {
|
|
15
|
-
stdio: "inherit",
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Create a worktree for the given branch at the specified destination
|
|
21
|
-
*/
|
|
22
|
-
export function createWorktree(branch, destinationDirectory) {
|
|
23
|
-
if (localBranchExists(branch)) {
|
|
24
|
-
// Reuse existing local branch
|
|
25
|
-
console.log(`➤ git worktree add ${destinationDirectory} ${branch}`);
|
|
26
|
-
git("worktree", "add", destinationDirectory, branch);
|
|
27
|
-
}
|
|
28
|
-
else if (remoteBranchExists(branch)) {
|
|
29
|
-
// Create new local branch tracking the remote branch
|
|
30
|
-
console.log(`➤ git worktree add --track -b ${branch} ${destinationDirectory} origin/${branch}`);
|
|
31
|
-
git("worktree", "add", "--track", "-b", branch, destinationDirectory, `origin/${branch}`);
|
|
32
|
-
}
|
|
33
|
-
else {
|
|
34
|
-
// Create new branch in the worktree from current HEAD
|
|
35
|
-
console.log(`➤ git worktree add -b ${branch} ${destinationDirectory}`);
|
|
36
|
-
git("worktree", "add", "-b", branch, destinationDirectory);
|
|
37
|
-
}
|
|
38
|
-
}
|