···11741174/// ```
11751175///
11761176/// For a package in a subdirectory of its repository the repository is
11771177-/// instead cloned into `build/git/<repo-name>-<hash>` without ever populating
11781178-/// its worktree, and the package is checked out into a transient staging
11771177+/// instead cloned into `build/git/<repo-name>-<hash>` as a bare repository
11781178+/// with no work tree, and the package is checked out into a transient staging
11791179/// worktree which the subdirectory is hard-linked out of:
11801180///
11811181/// ```sh
11821182-/// git init
11821182+/// git init --bare
11831183/// git remote remove origin
11841184/// git remote add origin <repo>
11851185/// git fetch origin
···12321232 project_paths: &ProjectPaths,
12331233) -> Result<GitCheckout, Error> {
12341234 let clone_path = project_paths.build_packages_package(package_name);
12351235- prepare_git_clone(&clone_path, repo)?;
12351235+ prepare_git_clone(&clone_path, repo, false)?;
12361236 let _ = execute_command(git_command(&clone_path).arg("checkout").arg(ref_))?;
12371237 let output = execute_command(git_command(&clone_path).arg("rev-parse").arg("HEAD"))?;
12381238 let commit = git_stdout(output);
···12481248 subdir: &Utf8Path,
12491249) -> Result<GitCheckout, Error> {
12501250 let clone_path = project_paths.build_git_repo(&git_repo_dir_name(repo));
12511251- prepare_git_clone(&clone_path, repo)?;
12511251+ prepare_git_clone(&clone_path, repo, true)?;
1252125212531253 let commit = resolve_git_ref(&clone_path, repo, ref_)?;
12541254···12921292}
1293129312941294/// Initialise (or reuse) a git clone at the given path and fetch from the
12951295-/// remote repository.
12961296-fn prepare_git_clone(clone_path: &Utf8Path, repo: &str) -> Result<()> {
12971297- // If the clone path exists but is not inside a git work tree, we need to
12981298- // remove the directory because running `git init` in a non-empty directory
12991299- // followed by `git checkout ...` is an error. See
13001300- // https://github.com/gleam-lang/gleam/issues/4488 for details.
13011301- if !fs::is_git_work_tree_root(clone_path) {
12951295+/// remote repository. When `bare` is set the clone is a bare repository with
12961296+/// no work tree.
12971297+fn prepare_git_clone(clone_path: &Utf8Path, repo: &str, bare: bool) -> Result<()> {
12981298+ // If the clone path exists but is not the kind of git repo we expect, we
12991299+ // need to remove the directory.
13001300+ let reusable = if bare {
13011301+ fs::is_bare_git_repo_root(clone_path)
13021302+ } else {
13031303+ fs::is_git_work_tree_root(clone_path)
13041304+ };
13051305+13061306+ if !reusable {
13021307 fs::delete_directory(clone_path)?;
13031308 }
1304130913051310 fs::mkdir(clone_path)?;
1306131113071307- let _ = execute_command(git_command(clone_path).arg("init"))?;
13121312+ let mut init = git_command(clone_path);
13131313+ let _ = init.arg("init");
13141314+ if bare {
13151315+ let _ = init.arg("--bare");
13161316+ }
13171317+ let _ = execute_command(&mut init)?;
1308131813091319 // If this directory already exists, but the remote URL has been edited in
13101320 // `gleam.toml` without a `gleam clean`, `git remote add` will fail, causing
···833833 exists(path.join(".git")).unwrap_or(false)
834834}
835835836836+pub(crate) fn is_bare_git_repo_root(path: &Utf8Path) -> bool {
837837+ tracing::debug!(path=?path, "checking_for_bare_git_repo_root");
838838+ exists(path.join("HEAD")).unwrap_or(false) && exists(path.join("objects")).unwrap_or(false)
839839+}
840840+836841/// Run `git init` in the given path.
837842/// If git is not installed then we do nothing.
838843pub fn git_init(path: &Utf8Path) -> Result<(), Error> {