sync-worktrees 1.7.4 → 1.8.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 +6 -1
- package/dist/constants.d.ts +54 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +66 -0
- package/dist/constants.js.map +1 -0
- package/dist/errors/index.d.ts +51 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +119 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/services/git.service.d.ts +2 -0
- package/dist/services/git.service.d.ts.map +1 -1
- package/dist/services/git.service.js +52 -40
- package/dist/services/git.service.js.map +1 -1
- package/dist/services/path-resolution.service.d.ts +7 -0
- package/dist/services/path-resolution.service.d.ts.map +1 -0
- package/dist/services/path-resolution.service.js +58 -0
- package/dist/services/path-resolution.service.js.map +1 -0
- package/dist/services/worktree-metadata.service.d.ts +12 -0
- package/dist/services/worktree-metadata.service.d.ts.map +1 -1
- package/dist/services/worktree-metadata.service.js +162 -3
- package/dist/services/worktree-metadata.service.js.map +1 -1
- package/dist/services/worktree-status.service.d.ts +28 -0
- package/dist/services/worktree-status.service.d.ts.map +1 -0
- package/dist/services/worktree-status.service.js +229 -0
- package/dist/services/worktree-status.service.js.map +1 -0
- package/dist/services/worktree-sync.service.d.ts +1 -0
- package/dist/services/worktree-sync.service.d.ts.map +1 -1
- package/dist/services/worktree-sync.service.js +37 -21
- package/dist/services/worktree-sync.service.js.map +1 -1
- package/dist/utils/lfs-error.d.ts +6 -0
- package/dist/utils/lfs-error.d.ts.map +1 -1
- package/dist/utils/lfs-error.js +16 -14
- package/dist/utils/lfs-error.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -252,7 +252,12 @@ sync-worktrees intelligently handles branches that have been rebased or force-pu
|
|
|
252
252
|
- Automatically resets the worktree to match the upstream
|
|
253
253
|
- No data loss since the content is the same
|
|
254
254
|
|
|
255
|
-
2. **Diverged branches** - When
|
|
255
|
+
2. **Diverged branches with NO local changes** - When someone force-pushes but you haven't made local commits:
|
|
256
|
+
- Automatically resets to the new upstream state
|
|
257
|
+
- No move to `.diverged` since you have no work to preserve
|
|
258
|
+
- Keeps `.diverged` clean by only preserving actual user work
|
|
259
|
+
|
|
260
|
+
3. **Diverged branches WITH local changes** - When a branch has different content AND you've made local commits:
|
|
256
261
|
- Moves the worktree to `.diverged` directory within your worktrees folder
|
|
257
262
|
- Preserves all your local changes and commits
|
|
258
263
|
- Creates a fresh worktree from the upstream branch
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export declare const GIT_CONSTANTS: {
|
|
2
|
+
readonly REMOTE_PREFIX: "origin/";
|
|
3
|
+
readonly REMOTE_NAME: "origin";
|
|
4
|
+
readonly HEAD_REF: "/HEAD";
|
|
5
|
+
readonly DEFAULT_BRANCH: "main";
|
|
6
|
+
readonly BARE_DIR_NAME: ".bare";
|
|
7
|
+
readonly DIVERGED_DIR_NAME: ".diverged";
|
|
8
|
+
readonly REFS: {
|
|
9
|
+
readonly HEADS: "refs/heads/";
|
|
10
|
+
readonly REMOTES: "refs/remotes/origin";
|
|
11
|
+
readonly REMOTES_ORIGIN: "refs/remotes/origin/*";
|
|
12
|
+
};
|
|
13
|
+
readonly FETCH_CONFIG: "+refs/heads/*:refs/remotes/origin/*";
|
|
14
|
+
};
|
|
15
|
+
export declare const GIT_OPERATIONS: {
|
|
16
|
+
readonly MERGE_HEAD: "MERGE_HEAD";
|
|
17
|
+
readonly CHERRY_PICK_HEAD: "CHERRY_PICK_HEAD";
|
|
18
|
+
readonly REVERT_HEAD: "REVERT_HEAD";
|
|
19
|
+
readonly BISECT_LOG: "BISECT_LOG";
|
|
20
|
+
readonly REBASE_MERGE: "rebase-merge";
|
|
21
|
+
readonly REBASE_APPLY: "rebase-apply";
|
|
22
|
+
};
|
|
23
|
+
export declare const DEFAULT_CONFIG: {
|
|
24
|
+
readonly CRON_SCHEDULE: "0 * * * *";
|
|
25
|
+
readonly RETRY: {
|
|
26
|
+
readonly MAX_ATTEMPTS: 3;
|
|
27
|
+
readonly MAX_LFS_RETRIES: 2;
|
|
28
|
+
readonly INITIAL_DELAY_MS: 1000;
|
|
29
|
+
readonly MAX_DELAY_MS: 30000;
|
|
30
|
+
readonly BACKOFF_MULTIPLIER: 2;
|
|
31
|
+
};
|
|
32
|
+
readonly UPDATE_EXISTING_WORKTREES: true;
|
|
33
|
+
};
|
|
34
|
+
export declare const ERROR_MESSAGES: {
|
|
35
|
+
readonly GIT_NOT_INITIALIZED: "Git service not initialized. Call initialize() first.";
|
|
36
|
+
readonly ALREADY_EXISTS: "already exists";
|
|
37
|
+
readonly ALREADY_REGISTERED: "already registered worktree";
|
|
38
|
+
readonly FAST_FORWARD_FAILED: readonly ["Not possible to fast-forward", "fatal: Not possible to fast-forward, aborting", "cannot fast-forward"];
|
|
39
|
+
readonly NO_UPSTREAM: readonly ["fatal: no upstream configured", "no upstream configured for branch", "fatal: ambiguous argument", "unknown revision or path"];
|
|
40
|
+
readonly LFS_ERROR: readonly ["smudge filter lfs failed", "git-lfs", "LFS"];
|
|
41
|
+
readonly EXDEV: "EXDEV";
|
|
42
|
+
};
|
|
43
|
+
export declare const TEST_TIMEOUT: {
|
|
44
|
+
readonly DEFAULT: 10000;
|
|
45
|
+
readonly E2E: 60000;
|
|
46
|
+
};
|
|
47
|
+
export declare const PATH_CONSTANTS: {
|
|
48
|
+
readonly GIT_DIR: ".git";
|
|
49
|
+
readonly README: "README";
|
|
50
|
+
};
|
|
51
|
+
export declare const METADATA_CONSTANTS: {
|
|
52
|
+
readonly MAX_HISTORY_ENTRIES: 10;
|
|
53
|
+
};
|
|
54
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa;;;;;;;;;;;;;CAahB,CAAC;AAEX,eAAO,MAAM,cAAc;;;;;;;CAOjB,CAAC;AAEX,eAAO,MAAM,cAAc;;;;;;;;;;CAUjB,CAAC;AAEX,eAAO,MAAM,cAAc;;;;;;;;CAiBjB,CAAC;AAEX,eAAO,MAAM,YAAY;;;CAGf,CAAC;AAEX,eAAO,MAAM,cAAc;;;CAGjB,CAAC;AAEX,eAAO,MAAM,kBAAkB;;CAErB,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.METADATA_CONSTANTS = exports.PATH_CONSTANTS = exports.TEST_TIMEOUT = exports.ERROR_MESSAGES = exports.DEFAULT_CONFIG = exports.GIT_OPERATIONS = exports.GIT_CONSTANTS = void 0;
|
|
4
|
+
exports.GIT_CONSTANTS = {
|
|
5
|
+
REMOTE_PREFIX: "origin/",
|
|
6
|
+
REMOTE_NAME: "origin",
|
|
7
|
+
HEAD_REF: "/HEAD",
|
|
8
|
+
DEFAULT_BRANCH: "main",
|
|
9
|
+
BARE_DIR_NAME: ".bare",
|
|
10
|
+
DIVERGED_DIR_NAME: ".diverged",
|
|
11
|
+
REFS: {
|
|
12
|
+
HEADS: "refs/heads/",
|
|
13
|
+
REMOTES: "refs/remotes/origin",
|
|
14
|
+
REMOTES_ORIGIN: "refs/remotes/origin/*",
|
|
15
|
+
},
|
|
16
|
+
FETCH_CONFIG: "+refs/heads/*:refs/remotes/origin/*",
|
|
17
|
+
};
|
|
18
|
+
exports.GIT_OPERATIONS = {
|
|
19
|
+
MERGE_HEAD: "MERGE_HEAD",
|
|
20
|
+
CHERRY_PICK_HEAD: "CHERRY_PICK_HEAD",
|
|
21
|
+
REVERT_HEAD: "REVERT_HEAD",
|
|
22
|
+
BISECT_LOG: "BISECT_LOG",
|
|
23
|
+
REBASE_MERGE: "rebase-merge",
|
|
24
|
+
REBASE_APPLY: "rebase-apply",
|
|
25
|
+
};
|
|
26
|
+
exports.DEFAULT_CONFIG = {
|
|
27
|
+
CRON_SCHEDULE: "0 * * * *",
|
|
28
|
+
RETRY: {
|
|
29
|
+
MAX_ATTEMPTS: 3,
|
|
30
|
+
MAX_LFS_RETRIES: 2,
|
|
31
|
+
INITIAL_DELAY_MS: 1000,
|
|
32
|
+
MAX_DELAY_MS: 30000,
|
|
33
|
+
BACKOFF_MULTIPLIER: 2,
|
|
34
|
+
},
|
|
35
|
+
UPDATE_EXISTING_WORKTREES: true,
|
|
36
|
+
};
|
|
37
|
+
exports.ERROR_MESSAGES = {
|
|
38
|
+
GIT_NOT_INITIALIZED: "Git service not initialized. Call initialize() first.",
|
|
39
|
+
ALREADY_EXISTS: "already exists",
|
|
40
|
+
ALREADY_REGISTERED: "already registered worktree",
|
|
41
|
+
FAST_FORWARD_FAILED: [
|
|
42
|
+
"Not possible to fast-forward",
|
|
43
|
+
"fatal: Not possible to fast-forward, aborting",
|
|
44
|
+
"cannot fast-forward",
|
|
45
|
+
],
|
|
46
|
+
NO_UPSTREAM: [
|
|
47
|
+
"fatal: no upstream configured",
|
|
48
|
+
"no upstream configured for branch",
|
|
49
|
+
"fatal: ambiguous argument",
|
|
50
|
+
"unknown revision or path",
|
|
51
|
+
],
|
|
52
|
+
LFS_ERROR: ["smudge filter lfs failed", "git-lfs", "LFS"],
|
|
53
|
+
EXDEV: "EXDEV",
|
|
54
|
+
};
|
|
55
|
+
exports.TEST_TIMEOUT = {
|
|
56
|
+
DEFAULT: 10000,
|
|
57
|
+
E2E: 60000,
|
|
58
|
+
};
|
|
59
|
+
exports.PATH_CONSTANTS = {
|
|
60
|
+
GIT_DIR: ".git",
|
|
61
|
+
README: "README",
|
|
62
|
+
};
|
|
63
|
+
exports.METADATA_CONSTANTS = {
|
|
64
|
+
MAX_HISTORY_ENTRIES: 10,
|
|
65
|
+
};
|
|
66
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,aAAa,GAAG;IAC3B,aAAa,EAAE,SAAS;IACxB,WAAW,EAAE,QAAQ;IACrB,QAAQ,EAAE,OAAO;IACjB,cAAc,EAAE,MAAM;IACtB,aAAa,EAAE,OAAO;IACtB,iBAAiB,EAAE,WAAW;IAC9B,IAAI,EAAE;QACJ,KAAK,EAAE,aAAa;QACpB,OAAO,EAAE,qBAAqB;QAC9B,cAAc,EAAE,uBAAuB;KACxC;IACD,YAAY,EAAE,qCAAqC;CAC3C,CAAC;AAEE,QAAA,cAAc,GAAG;IAC5B,UAAU,EAAE,YAAY;IACxB,gBAAgB,EAAE,kBAAkB;IACpC,WAAW,EAAE,aAAa;IAC1B,UAAU,EAAE,YAAY;IACxB,YAAY,EAAE,cAAc;IAC5B,YAAY,EAAE,cAAc;CACpB,CAAC;AAEE,QAAA,cAAc,GAAG;IAC5B,aAAa,EAAE,WAAW;IAC1B,KAAK,EAAE;QACL,YAAY,EAAE,CAAC;QACf,eAAe,EAAE,CAAC;QAClB,gBAAgB,EAAE,IAAI;QACtB,YAAY,EAAE,KAAK;QACnB,kBAAkB,EAAE,CAAC;KACtB;IACD,yBAAyB,EAAE,IAAI;CACvB,CAAC;AAEE,QAAA,cAAc,GAAG;IAC5B,mBAAmB,EAAE,uDAAuD;IAC5E,cAAc,EAAE,gBAAgB;IAChC,kBAAkB,EAAE,6BAA6B;IACjD,mBAAmB,EAAE;QACnB,8BAA8B;QAC9B,+CAA+C;QAC/C,qBAAqB;KACtB;IACD,WAAW,EAAE;QACX,+BAA+B;QAC/B,mCAAmC;QACnC,2BAA2B;QAC3B,0BAA0B;KAC3B;IACD,SAAS,EAAE,CAAC,0BAA0B,EAAE,SAAS,EAAE,KAAK,CAAC;IACzD,KAAK,EAAE,OAAO;CACN,CAAC;AAEE,QAAA,YAAY,GAAG;IAC1B,OAAO,EAAE,KAAK;IACd,GAAG,EAAE,KAAK;CACF,CAAC;AAEE,QAAA,cAAc,GAAG;IAC5B,OAAO,EAAE,MAAM;IACf,MAAM,EAAE,QAAQ;CACR,CAAC;AAEE,QAAA,kBAAkB,GAAG;IAChC,mBAAmB,EAAE,EAAE;CACf,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export declare class SyncWorktreesError extends Error {
|
|
2
|
+
readonly code: string;
|
|
3
|
+
readonly cause?: Error | undefined;
|
|
4
|
+
constructor(message: string, code: string, cause?: Error | undefined);
|
|
5
|
+
}
|
|
6
|
+
export declare class GitError extends SyncWorktreesError {
|
|
7
|
+
constructor(message: string, code: string, cause?: Error);
|
|
8
|
+
}
|
|
9
|
+
export declare class GitNotInitializedError extends GitError {
|
|
10
|
+
constructor();
|
|
11
|
+
}
|
|
12
|
+
export declare class GitOperationError extends GitError {
|
|
13
|
+
constructor(operation: string, details: string, cause?: Error);
|
|
14
|
+
}
|
|
15
|
+
export declare class FastForwardError extends GitError {
|
|
16
|
+
readonly branchName: string;
|
|
17
|
+
constructor(branchName: string, cause?: Error);
|
|
18
|
+
}
|
|
19
|
+
export declare class WorktreeError extends SyncWorktreesError {
|
|
20
|
+
constructor(message: string, code: string, cause?: Error);
|
|
21
|
+
}
|
|
22
|
+
export declare class WorktreeAlreadyExistsError extends WorktreeError {
|
|
23
|
+
readonly path: string;
|
|
24
|
+
readonly branchName: string;
|
|
25
|
+
constructor(path: string, branchName: string);
|
|
26
|
+
}
|
|
27
|
+
export declare class WorktreeNotCleanError extends WorktreeError {
|
|
28
|
+
readonly path: string;
|
|
29
|
+
readonly reasons: string[];
|
|
30
|
+
constructor(path: string, reasons: string[]);
|
|
31
|
+
}
|
|
32
|
+
export declare class ConfigError extends SyncWorktreesError {
|
|
33
|
+
constructor(message: string, code: string, cause?: Error);
|
|
34
|
+
}
|
|
35
|
+
export declare class ConfigValidationError extends ConfigError {
|
|
36
|
+
readonly field: string;
|
|
37
|
+
readonly reason: string;
|
|
38
|
+
constructor(field: string, reason: string);
|
|
39
|
+
}
|
|
40
|
+
export declare class PathResolutionError extends SyncWorktreesError {
|
|
41
|
+
readonly path: string;
|
|
42
|
+
readonly reason: string;
|
|
43
|
+
constructor(path: string, reason: string);
|
|
44
|
+
}
|
|
45
|
+
export declare class LfsError extends GitError {
|
|
46
|
+
constructor(message: string, cause?: Error);
|
|
47
|
+
}
|
|
48
|
+
export declare function isLfsError(error: Error | string): boolean;
|
|
49
|
+
export declare function isFastForwardError(error: Error | string): boolean;
|
|
50
|
+
export declare function isNoUpstreamError(error: Error | string): boolean;
|
|
51
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/errors/index.ts"],"names":[],"mappings":"AAEA,qBAAa,kBAAmB,SAAQ,KAAK;aAGzB,IAAI,EAAE,MAAM;aACZ,KAAK,CAAC,EAAE,KAAK;gBAF7B,OAAO,EAAE,MAAM,EACC,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,KAAK,YAAA;CAShC;AAED,qBAAa,QAAS,SAAQ,kBAAkB;gBAClC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;CAGzD;AAED,qBAAa,sBAAuB,SAAQ,QAAQ;;CAInD;AAED,qBAAa,iBAAkB,SAAQ,QAAQ;gBACjC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;CAG9D;AAED,qBAAa,gBAAiB,SAAQ,QAAQ;aAE1B,UAAU,EAAE,MAAM;gBAAlB,UAAU,EAAE,MAAM,EAClC,KAAK,CAAC,EAAE,KAAK;CAIhB;AAED,qBAAa,aAAc,SAAQ,kBAAkB;gBACvC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;CAGzD;AAED,qBAAa,0BAA2B,SAAQ,aAAa;aAEzC,IAAI,EAAE,MAAM;aACZ,UAAU,EAAE,MAAM;gBADlB,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM;CAIrC;AAED,qBAAa,qBAAsB,SAAQ,aAAa;aAEpC,IAAI,EAAE,MAAM;aACZ,OAAO,EAAE,MAAM,EAAE;gBADjB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EAAE;CAIpC;AAED,qBAAa,WAAY,SAAQ,kBAAkB;gBACrC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;CAGzD;AAED,qBAAa,qBAAsB,SAAQ,WAAW;aAElC,KAAK,EAAE,MAAM;aACb,MAAM,EAAE,MAAM;gBADd,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM;CAIjC;AAED,qBAAa,mBAAoB,SAAQ,kBAAkB;aAEvC,IAAI,EAAE,MAAM;aACZ,MAAM,EAAE,MAAM;gBADd,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM;CAIjC;AAED,qBAAa,QAAS,SAAQ,QAAQ;gBACxB,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;CAG3C;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,CAGzD;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,CAGjE;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,CAGhE"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LfsError = exports.PathResolutionError = exports.ConfigValidationError = exports.ConfigError = exports.WorktreeNotCleanError = exports.WorktreeAlreadyExistsError = exports.WorktreeError = exports.FastForwardError = exports.GitOperationError = exports.GitNotInitializedError = exports.GitError = exports.SyncWorktreesError = void 0;
|
|
4
|
+
exports.isLfsError = isLfsError;
|
|
5
|
+
exports.isFastForwardError = isFastForwardError;
|
|
6
|
+
exports.isNoUpstreamError = isNoUpstreamError;
|
|
7
|
+
const constants_1 = require("../constants");
|
|
8
|
+
class SyncWorktreesError extends Error {
|
|
9
|
+
code;
|
|
10
|
+
cause;
|
|
11
|
+
constructor(message, code, cause) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.code = code;
|
|
14
|
+
this.cause = cause;
|
|
15
|
+
this.name = this.constructor.name;
|
|
16
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
17
|
+
if (cause && cause.stack) {
|
|
18
|
+
this.stack = `${this.stack}\nCaused by: ${cause.stack}`;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
exports.SyncWorktreesError = SyncWorktreesError;
|
|
23
|
+
class GitError extends SyncWorktreesError {
|
|
24
|
+
constructor(message, code, cause) {
|
|
25
|
+
super(message, `GIT_${code}`, cause);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
exports.GitError = GitError;
|
|
29
|
+
class GitNotInitializedError extends GitError {
|
|
30
|
+
constructor() {
|
|
31
|
+
super(constants_1.ERROR_MESSAGES.GIT_NOT_INITIALIZED, "NOT_INITIALIZED");
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
exports.GitNotInitializedError = GitNotInitializedError;
|
|
35
|
+
class GitOperationError extends GitError {
|
|
36
|
+
constructor(operation, details, cause) {
|
|
37
|
+
super(`Git operation '${operation}' failed: ${details}`, "OPERATION_FAILED", cause);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
exports.GitOperationError = GitOperationError;
|
|
41
|
+
class FastForwardError extends GitError {
|
|
42
|
+
branchName;
|
|
43
|
+
constructor(branchName, cause) {
|
|
44
|
+
super(`Cannot fast-forward branch '${branchName}'`, "FAST_FORWARD_FAILED", cause);
|
|
45
|
+
this.branchName = branchName;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.FastForwardError = FastForwardError;
|
|
49
|
+
class WorktreeError extends SyncWorktreesError {
|
|
50
|
+
constructor(message, code, cause) {
|
|
51
|
+
super(message, `WORKTREE_${code}`, cause);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
exports.WorktreeError = WorktreeError;
|
|
55
|
+
class WorktreeAlreadyExistsError extends WorktreeError {
|
|
56
|
+
path;
|
|
57
|
+
branchName;
|
|
58
|
+
constructor(path, branchName) {
|
|
59
|
+
super(`Worktree already exists at '${path}' for branch '${branchName}'`, "ALREADY_EXISTS");
|
|
60
|
+
this.path = path;
|
|
61
|
+
this.branchName = branchName;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
exports.WorktreeAlreadyExistsError = WorktreeAlreadyExistsError;
|
|
65
|
+
class WorktreeNotCleanError extends WorktreeError {
|
|
66
|
+
path;
|
|
67
|
+
reasons;
|
|
68
|
+
constructor(path, reasons) {
|
|
69
|
+
super(`Worktree at '${path}' is not clean: ${reasons.join(", ")}`, "NOT_CLEAN");
|
|
70
|
+
this.path = path;
|
|
71
|
+
this.reasons = reasons;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
exports.WorktreeNotCleanError = WorktreeNotCleanError;
|
|
75
|
+
class ConfigError extends SyncWorktreesError {
|
|
76
|
+
constructor(message, code, cause) {
|
|
77
|
+
super(message, `CONFIG_${code}`, cause);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
exports.ConfigError = ConfigError;
|
|
81
|
+
class ConfigValidationError extends ConfigError {
|
|
82
|
+
field;
|
|
83
|
+
reason;
|
|
84
|
+
constructor(field, reason) {
|
|
85
|
+
super(`Invalid configuration for '${field}': ${reason}`, "VALIDATION_FAILED");
|
|
86
|
+
this.field = field;
|
|
87
|
+
this.reason = reason;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
exports.ConfigValidationError = ConfigValidationError;
|
|
91
|
+
class PathResolutionError extends SyncWorktreesError {
|
|
92
|
+
path;
|
|
93
|
+
reason;
|
|
94
|
+
constructor(path, reason) {
|
|
95
|
+
super(`Path resolution failed for '${path}': ${reason}`, "PATH_RESOLUTION_FAILED");
|
|
96
|
+
this.path = path;
|
|
97
|
+
this.reason = reason;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
exports.PathResolutionError = PathResolutionError;
|
|
101
|
+
class LfsError extends GitError {
|
|
102
|
+
constructor(message, cause) {
|
|
103
|
+
super(`LFS operation failed: ${message}`, "LFS_ERROR", cause);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
exports.LfsError = LfsError;
|
|
107
|
+
function isLfsError(error) {
|
|
108
|
+
const message = typeof error === "string" ? error : error.message;
|
|
109
|
+
return constants_1.ERROR_MESSAGES.LFS_ERROR.some((pattern) => message.includes(pattern));
|
|
110
|
+
}
|
|
111
|
+
function isFastForwardError(error) {
|
|
112
|
+
const message = typeof error === "string" ? error : error.message;
|
|
113
|
+
return constants_1.ERROR_MESSAGES.FAST_FORWARD_FAILED.some((pattern) => message.includes(pattern));
|
|
114
|
+
}
|
|
115
|
+
function isNoUpstreamError(error) {
|
|
116
|
+
const message = typeof error === "string" ? error : error.message;
|
|
117
|
+
return constants_1.ERROR_MESSAGES.NO_UPSTREAM.some((pattern) => message.includes(pattern));
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/errors/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Config } from "../types";
|
|
2
|
+
import type { SyncMetadata } from "../types/sync-metadata";
|
|
2
3
|
import type { SimpleGit } from "simple-git";
|
|
3
4
|
export declare class GitService {
|
|
4
5
|
private config;
|
|
@@ -44,6 +45,7 @@ export declare class GitService {
|
|
|
44
45
|
resetToUpstream(worktreePath: string, branch: string): Promise<void>;
|
|
45
46
|
getCurrentCommit(worktreePath: string): Promise<string>;
|
|
46
47
|
getRemoteCommit(ref: string): Promise<string>;
|
|
48
|
+
getWorktreeMetadata(worktreePath: string): Promise<SyncMetadata | null>;
|
|
47
49
|
private getWorktreesFromBare;
|
|
48
50
|
}
|
|
49
51
|
//# sourceMappingURL=git.service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git.service.d.ts","sourceRoot":"","sources":["../../src/services/git.service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"git.service.d.ts","sourceRoot":"","sources":["../../src/services/git.service.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,qBAAa,UAAU;IAOT,OAAO,CAAC,MAAM;IAN1B,OAAO,CAAC,GAAG,CAA0B;IACrC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,aAAa,CAAkB;IACvC,OAAO,CAAC,eAAe,CAA0B;gBAE7B,MAAM,EAAE,MAAM;IAM5B,UAAU,IAAI,OAAO,CAAC,SAAS,CAAC;IA6HtC,MAAM,IAAI,SAAS;IAOnB,gBAAgB,IAAI,MAAM;IAIpB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAWzB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAW9C,iBAAiB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAStC,6BAA6B,IAAI,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,IAAI,CAAA;KAAE,EAAE,CAAC;YAkC1E,sBAAsB;IAsB9B,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA8HpE,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAcnD,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAM/B,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;YAMnD,cAAc;IAStB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAyC1D,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAkEvD,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAYzD,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAW7D,sBAAsB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IA+B9D,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC;YAM3B,mBAAmB;IAsCjC,OAAO,CAAC,gBAAgB;IAIlB,YAAY,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAK3D,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAsBxD,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgCnD,kBAAkB,CAAC,YAAY,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAmBlF,cAAc,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAmBtE,kBAAkB,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAe1E,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAsBpE,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAMvD,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAO7C,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;YAI/D,oBAAoB;CAiCnC"}
|
|
@@ -41,6 +41,7 @@ const fs = __importStar(require("fs/promises"));
|
|
|
41
41
|
const path = __importStar(require("path"));
|
|
42
42
|
const simple_git_1 = __importDefault(require("simple-git"));
|
|
43
43
|
const git_url_1 = require("../utils/git-url");
|
|
44
|
+
const lfs_error_1 = require("../utils/lfs-error");
|
|
44
45
|
const worktree_metadata_service_1 = require("./worktree-metadata.service");
|
|
45
46
|
class GitService {
|
|
46
47
|
config;
|
|
@@ -132,7 +133,7 @@ class GitService {
|
|
|
132
133
|
}
|
|
133
134
|
}
|
|
134
135
|
catch (error) {
|
|
135
|
-
const errorMessage =
|
|
136
|
+
const errorMessage = (0, lfs_error_1.getErrorMessage)(error);
|
|
136
137
|
// Check if error is because directory already exists
|
|
137
138
|
if (errorMessage.includes("already exists")) {
|
|
138
139
|
console.log(`${this.defaultBranch} worktree directory already exists at '${absoluteWorktreePath}', skipping creation.`);
|
|
@@ -144,7 +145,7 @@ class GitService {
|
|
|
144
145
|
await bareGit.raw(["worktree", "add", absoluteWorktreePath, this.defaultBranch]);
|
|
145
146
|
}
|
|
146
147
|
catch (fallbackError) {
|
|
147
|
-
const fallbackErrorMessage =
|
|
148
|
+
const fallbackErrorMessage = (0, lfs_error_1.getErrorMessage)(fallbackError);
|
|
148
149
|
if (fallbackErrorMessage.includes("already exists")) {
|
|
149
150
|
console.log(`${this.defaultBranch} worktree directory already exists at '${absoluteWorktreePath}', skipping creation.`);
|
|
150
151
|
}
|
|
@@ -242,10 +243,11 @@ class GitService {
|
|
|
242
243
|
: (0, simple_git_1.default)(worktreePath);
|
|
243
244
|
const currentCommit = await worktreeGit.revparse(["HEAD"]);
|
|
244
245
|
const parentCommit = await bareGit.revparse([this.defaultBranch]);
|
|
245
|
-
await this.metadataService.
|
|
246
|
+
await this.metadataService.createInitialMetadataFromPath(this.bareRepoPath, worktreePath, currentCommit.trim(), `origin/${branchName}`, this.defaultBranch, parentCommit.trim());
|
|
246
247
|
}
|
|
247
248
|
catch (metadataError) {
|
|
248
|
-
console.
|
|
249
|
+
console.error(` - ❌ Failed to create metadata for '${branchName}': ${metadataError}`);
|
|
250
|
+
throw new Error(`Metadata creation failed for ${branchName}. This worktree cannot be auto-managed.`);
|
|
249
251
|
}
|
|
250
252
|
}
|
|
251
253
|
async addWorktree(branchName, worktreePath) {
|
|
@@ -303,7 +305,11 @@ class GitService {
|
|
|
303
305
|
await this.createWorktreeMetadata(bareGit, absoluteWorktreePath, branchName);
|
|
304
306
|
}
|
|
305
307
|
catch (error) {
|
|
306
|
-
const errorMessage =
|
|
308
|
+
const errorMessage = (0, lfs_error_1.getErrorMessage)(error);
|
|
309
|
+
// Re-throw metadata creation errors - these are fatal and should not fall back
|
|
310
|
+
if (errorMessage.includes("Metadata creation failed")) {
|
|
311
|
+
throw error;
|
|
312
|
+
}
|
|
307
313
|
// Check if this is an "already registered" error
|
|
308
314
|
if (errorMessage.includes("already registered worktree")) {
|
|
309
315
|
console.warn(` - Worktree already registered but missing. Pruning and retrying...`);
|
|
@@ -365,27 +371,14 @@ class GitService {
|
|
|
365
371
|
}
|
|
366
372
|
async removeWorktree(worktreePath) {
|
|
367
373
|
const bareGit = (0, simple_git_1.default)(this.bareRepoPath);
|
|
368
|
-
// Try to get branch name before removing worktree
|
|
369
|
-
let branchName = null;
|
|
370
|
-
try {
|
|
371
|
-
const worktrees = await this.getWorktreesFromBare(bareGit);
|
|
372
|
-
const worktree = worktrees.find((w) => path.resolve(w.path) === path.resolve(worktreePath));
|
|
373
|
-
branchName = worktree?.branch || null;
|
|
374
|
-
}
|
|
375
|
-
catch {
|
|
376
|
-
// If we can't get the branch name, extract from path as fallback
|
|
377
|
-
branchName = path.basename(worktreePath);
|
|
378
|
-
}
|
|
379
374
|
await bareGit.raw(["worktree", "remove", worktreePath, "--force"]);
|
|
380
375
|
console.log(` - ✅ Safely removed stale worktree at '${worktreePath}'.`);
|
|
381
|
-
// Clean up metadata
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
console.warn(`Failed to delete metadata for worktree: ${metadataError}`);
|
|
388
|
-
}
|
|
376
|
+
// Clean up metadata using the worktree path
|
|
377
|
+
try {
|
|
378
|
+
await this.metadataService.deleteMetadataFromPath(this.bareRepoPath, worktreePath);
|
|
379
|
+
}
|
|
380
|
+
catch (metadataError) {
|
|
381
|
+
console.warn(`Failed to delete metadata for worktree: ${metadataError}`);
|
|
389
382
|
}
|
|
390
383
|
}
|
|
391
384
|
async pruneWorktrees() {
|
|
@@ -420,8 +413,8 @@ class GitService {
|
|
|
420
413
|
// Check if upstream is gone
|
|
421
414
|
const upstreamGone = await this.hasUpstreamGone(worktreePath);
|
|
422
415
|
if (upstreamGone) {
|
|
423
|
-
// Load metadata to check for commits after last sync
|
|
424
|
-
const metadata = await this.metadataService.
|
|
416
|
+
// Load metadata to check for commits after last sync (use path-based method)
|
|
417
|
+
const metadata = await this.metadataService.loadMetadataFromPath(this.bareRepoPath, worktreePath);
|
|
425
418
|
if (metadata?.lastSyncCommit) {
|
|
426
419
|
try {
|
|
427
420
|
// Check for commits after last sync
|
|
@@ -461,22 +454,38 @@ class GitService {
|
|
|
461
454
|
return !remoteBranches.all.includes(upstream.trim());
|
|
462
455
|
}
|
|
463
456
|
catch (error) {
|
|
464
|
-
|
|
465
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
466
|
-
// Match specific Git error messages for missing upstream
|
|
457
|
+
const errorMessage = (0, lfs_error_1.getErrorMessage)(error);
|
|
467
458
|
if (errorMessage.includes("fatal: no upstream configured") ||
|
|
468
|
-
errorMessage.includes("no upstream configured for branch")
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
459
|
+
errorMessage.includes("no upstream configured for branch")) {
|
|
460
|
+
return false;
|
|
461
|
+
}
|
|
462
|
+
if (errorMessage.includes("fatal: ambiguous argument") || errorMessage.includes("unknown revision or path")) {
|
|
463
|
+
try {
|
|
464
|
+
const branchSummary = await worktreeGit.branch();
|
|
465
|
+
const currentBranch = branchSummary.current;
|
|
466
|
+
const remoteResult = await worktreeGit
|
|
467
|
+
.raw(["config", "--get", `branch.${currentBranch}.remote`])
|
|
468
|
+
.catch(() => "");
|
|
469
|
+
const mergeResult = await worktreeGit
|
|
470
|
+
.raw(["config", "--get", `branch.${currentBranch}.merge`])
|
|
471
|
+
.catch(() => "");
|
|
472
|
+
const remote = remoteResult.trim();
|
|
473
|
+
const merge = mergeResult.trim();
|
|
474
|
+
if (remote && merge) {
|
|
475
|
+
const remoteBranchName = merge.replace("refs/heads/", "");
|
|
476
|
+
const expectedUpstream = `${remote}/${remoteBranchName}`;
|
|
477
|
+
const remoteBranches = await worktreeGit.branch(["-r"]);
|
|
478
|
+
return !remoteBranches.all.includes(expectedUpstream);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
catch {
|
|
482
|
+
// Can't determine config, be conservative
|
|
483
|
+
}
|
|
472
484
|
return false;
|
|
473
485
|
}
|
|
474
|
-
// Log unexpected errors that don't match known patterns
|
|
475
486
|
console.error(`Unexpected error checking upstream status for ${worktreePath}. ` +
|
|
476
487
|
`This might indicate a real issue rather than a missing upstream. ` +
|
|
477
488
|
`Error: ${errorMessage}`);
|
|
478
|
-
// Return false to be safe - we don't want to accidentally delete worktrees
|
|
479
|
-
// due to transient errors
|
|
480
489
|
return false;
|
|
481
490
|
}
|
|
482
491
|
}
|
|
@@ -619,10 +628,10 @@ class GitService {
|
|
|
619
628
|
if (isMainWorktree) {
|
|
620
629
|
return;
|
|
621
630
|
}
|
|
622
|
-
// Update metadata after successful update
|
|
631
|
+
// Update metadata after successful update (use path-based method)
|
|
623
632
|
try {
|
|
624
633
|
const currentCommit = await worktreeGit.revparse(["HEAD"]);
|
|
625
|
-
await this.metadataService.
|
|
634
|
+
await this.metadataService.updateLastSyncFromPath(this.bareRepoPath, worktreePath, currentCommit.trim(), "updated", this.defaultBranch);
|
|
626
635
|
}
|
|
627
636
|
catch (metadataError) {
|
|
628
637
|
console.warn(`Failed to update metadata for worktree: ${metadataError}`);
|
|
@@ -681,10 +690,10 @@ class GitService {
|
|
|
681
690
|
? (0, simple_git_1.default)(worktreePath).env({ GIT_LFS_SKIP_SMUDGE: "1" })
|
|
682
691
|
: (0, simple_git_1.default)(worktreePath);
|
|
683
692
|
await worktreeGit.reset(["--hard", `origin/${branch}`]);
|
|
684
|
-
// Update metadata after reset
|
|
693
|
+
// Update metadata after reset (use path-based method)
|
|
685
694
|
try {
|
|
686
695
|
const currentCommit = await worktreeGit.revparse(["HEAD"]);
|
|
687
|
-
await this.metadataService.
|
|
696
|
+
await this.metadataService.updateLastSyncFromPath(this.bareRepoPath, worktreePath, currentCommit.trim(), "updated", this.defaultBranch);
|
|
688
697
|
}
|
|
689
698
|
catch (metadataError) {
|
|
690
699
|
console.warn(`Failed to update metadata after reset: ${metadataError}`);
|
|
@@ -701,6 +710,9 @@ class GitService {
|
|
|
701
710
|
const commit = await git.revparse([ref]);
|
|
702
711
|
return commit.trim();
|
|
703
712
|
}
|
|
713
|
+
async getWorktreeMetadata(worktreePath) {
|
|
714
|
+
return this.metadataService.loadMetadataFromPath(this.bareRepoPath, worktreePath);
|
|
715
|
+
}
|
|
704
716
|
async getWorktreesFromBare(bareGit) {
|
|
705
717
|
const result = await bareGit.raw(["worktree", "list", "--porcelain"]);
|
|
706
718
|
const worktrees = [];
|