( url: string, targetPath: string, subdirPath: string, ref?: string, sha?: string, )
| 716 | * the plugin files with no .git directory. |
| 717 | */ |
| 718 | export async function installFromGitSubdir( |
| 719 | url: string, |
| 720 | targetPath: string, |
| 721 | subdirPath: string, |
| 722 | ref?: string, |
| 723 | sha?: string, |
| 724 | ): Promise<string | undefined> { |
| 725 | if (!(await checkGitAvailable())) { |
| 726 | throw new Error( |
| 727 | 'git-subdir plugin source requires git to be installed and on PATH. ' + |
| 728 | 'Install git (version 2.25 or later for sparse-checkout cone mode) and try again.', |
| 729 | ) |
| 730 | } |
| 731 | |
| 732 | const gitUrl = resolveGitSubdirUrl(url) |
| 733 | // Clone into a sibling temp dir (same filesystem → rename works, no EXDEV). |
| 734 | const cloneDir = `${targetPath}.clone` |
| 735 | |
| 736 | const cloneArgs = [ |
| 737 | 'clone', |
| 738 | '--depth', |
| 739 | '1', |
| 740 | '--filter=tree:0', |
| 741 | '--no-checkout', |
| 742 | ] |
| 743 | if (ref) { |
| 744 | cloneArgs.push('--branch', ref) |
| 745 | } |
| 746 | cloneArgs.push(gitUrl, cloneDir) |
| 747 | |
| 748 | const cloneResult = await execFileNoThrow(gitExe(), cloneArgs) |
| 749 | if (cloneResult.code !== 0) { |
| 750 | throw new Error( |
| 751 | `Failed to clone repository for git-subdir source: ${cloneResult.stderr}`, |
| 752 | ) |
| 753 | } |
| 754 | |
| 755 | try { |
| 756 | const sparseResult = await execFileNoThrowWithCwd( |
| 757 | gitExe(), |
| 758 | ['sparse-checkout', 'set', '--cone', '--', subdirPath], |
| 759 | { cwd: cloneDir }, |
| 760 | ) |
| 761 | if (sparseResult.code !== 0) { |
| 762 | throw new Error( |
| 763 | `git sparse-checkout set failed (git >= 2.25 required for cone mode): ${sparseResult.stderr}`, |
| 764 | ) |
| 765 | } |
| 766 | |
| 767 | // Capture the resolved commit SHA before discarding the clone. The |
| 768 | // extracted subdir has no .git, so the caller can't rev-parse it later. |
| 769 | // If the source specified a full 40-char sha we already know it; otherwise |
| 770 | // read HEAD (which points to ref's tip after --branch, or the remote |
| 771 | // default branch if no ref was given). |
| 772 | let resolvedSha: string | undefined |
| 773 | |
| 774 | if (sha) { |
| 775 | const fetchSha = await execFileNoThrowWithCwd( |
no test coverage detected