Skip to content

Commit 988097f

Browse files
committed
fix(scripts): keep submodules on the pinned commit in setup-worktree
- move existing submodule checkouts to the commit the branch pins, so re-running setup after a submodule bump updates the assets; checkouts on a branch or with local changes are left alone with a warning - warn and continue when a pinned submodule commit cannot be fetched, matching the behaviour when a submodule cannot be cloned
1 parent 27d6ed5 commit 988097f

1 file changed

Lines changed: 71 additions & 7 deletions

File tree

‎apps/scripts/src/setup-worktree.js‎

Lines changed: 71 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
* 1. Links `config.json` / `config.js` from the main checkout
1515
* 2. Checks out each asset submodule at the commit this branch pins, as a git
1616
* worktree of the main checkout's submodule repo (no network, no re-clone)
17+
* and moves existing clean, detached checkouts to the pinned commit
1718
* 3. Links the ignored minecraft texture pack from the main checkout
1819
* 4. Installs dependencies (this also blurs the public backgrounds)
1920
* 5. Restores the blurred private backgrounds from a cache, or generates them
@@ -130,12 +131,78 @@ function submodulePaths() {
130131
return output.split("\n").map((line) => line.split(" ")[1]);
131132
}
132133

134+
/**
135+
* Checks that a submodule repo has a commit, fetching it when it is missing.
136+
* @param {string[]} repo git arguments that select the submodule repo
137+
* @param {string} sha
138+
* @returns {boolean} whether the commit is available
139+
*/
140+
function hasCommit(repo, sha) {
141+
const exists = () => {
142+
try {
143+
git([...repo, "cat-file", "-e", `${sha}^{commit}`]);
144+
return true;
145+
} catch {
146+
return false;
147+
}
148+
};
149+
150+
if (exists()) return true;
151+
152+
try {
153+
run("git", [...repo, "fetch", "origin"]);
154+
} catch {
155+
return false;
156+
}
157+
158+
return exists();
159+
}
160+
161+
/**
162+
* Moves an existing submodule checkout to the commit this branch pins, unless it is
163+
* on a branch or has local changes.
164+
* @param {string} path
165+
* @param {string} sha
166+
*/
167+
function updateSubmodule(path, sha) {
168+
const target = join(ROOT, path);
169+
const head = git(["rev-parse", "HEAD"], target);
170+
if (head === sha) return;
171+
172+
let onBranch = true;
173+
174+
try {
175+
git(["symbolic-ref", "-q", "HEAD"], target);
176+
} catch {
177+
onBranch = false;
178+
}
179+
180+
if (onBranch || git(["status", "--porcelain"], target) !== "") {
181+
log(
182+
"Submodule",
183+
`${path} is at ${head.slice(0, 8)} but this branch pins ${sha.slice(0, 8)}, leaving it because it is on a branch or has local changes`,
184+
);
185+
return;
186+
}
187+
188+
if (!hasCommit(["-C", target], sha)) {
189+
log("Submodule", `could not fetch ${path} at ${sha.slice(0, 8)}`);
190+
return;
191+
}
192+
193+
git(["checkout", "--detach", sha], target);
194+
log("Submodule", `updated ${path} to ${sha.slice(0, 8)}`);
195+
}
196+
133197
/**
134198
* @param {string} path
135199
*/
136200
function setupSubmodule(path) {
137201
const target = join(ROOT, path);
138-
if (existsSync(join(target, ".git"))) return;
202+
const sha = git(["ls-tree", "HEAD", path]).split(/\s+/)[2];
203+
if (!sha) return;
204+
205+
if (existsSync(join(target, ".git"))) return updateSubmodule(path, sha);
139206

140207
const moduleDir = join(COMMON_DIR, "modules", path);
141208

@@ -149,12 +216,9 @@ function setupSubmodule(path) {
149216
return;
150217
}
151218

152-
const sha = git(["ls-tree", "HEAD", path]).split(/\s+/)[2];
153-
154-
try {
155-
git(["--git-dir", moduleDir, "cat-file", "-e", `${sha}^{commit}`]);
156-
} catch {
157-
run("git", ["--git-dir", moduleDir, "fetch", "origin"]);
219+
if (!hasCommit(["--git-dir", moduleDir], sha)) {
220+
log("Submodule", `could not fetch ${path}, continuing without it`);
221+
return;
158222
}
159223

160224
// Worktrees that were deleted without `git worktree remove` leave stale entries behind

0 commit comments

Comments
 (0)