diff --git a/docs/guide/create.md b/docs/guide/create.md index ce3fbcb831..5baf1ee475 100644 --- a/docs/guide/create.md +++ b/docs/guide/create.md @@ -45,6 +45,8 @@ Run `vp create --list` to see the built-in templates and the common shorthand te - `--directory ` writes the generated project into a specific target directory - `--agent ` creates agent instructions files during scaffolding - `--editor ` writes editor config files +- `--git` initialize a git repository +- `--no-git` skips git repository initialization - `--hooks` enables pre-commit hook setup - `--no-hooks` skips hook setup - `--no-interactive` runs without prompts diff --git a/packages/cli/snap-tests-global/command-create-help/snap.txt b/packages/cli/snap-tests-global/command-create-help/snap.txt index c70972a1bf..ff6448a159 100644 --- a/packages/cli/snap-tests-global/command-create-help/snap.txt +++ b/packages/cli/snap-tests-global/command-create-help/snap.txt @@ -14,6 +14,8 @@ Options: --directory DIR Target directory for the generated project. --agent NAME Write coding agent instructions to AGENTS.md, CLAUDE.md, etc. --editor NAME Write editor config files for the specified editor. + --git Initialize a git repository with an initial commit + --no-git Skip git repository initialization --hooks Set up pre-commit hooks (default in non-interactive mode) --no-hooks Skip pre-commit hooks setup --package-manager NAME Use specified package manager (pnpm, npm, yarn, bun) @@ -68,6 +70,8 @@ Options: --directory DIR Target directory for the generated project. --agent NAME Write coding agent instructions to AGENTS.md, CLAUDE.md, etc. --editor NAME Write editor config files for the specified editor. + --git Initialize a git repository with an initial commit + --no-git Skip git repository initialization --hooks Set up pre-commit hooks (default in non-interactive mode) --no-hooks Skip pre-commit hooks setup --package-manager NAME Use specified package manager (pnpm, npm, yarn, bun) @@ -122,6 +126,8 @@ Options: --directory DIR Target directory for the generated project. --agent NAME Write coding agent instructions to AGENTS.md, CLAUDE.md, etc. --editor NAME Write editor config files for the specified editor. + --git Initialize a git repository with an initial commit + --no-git Skip git repository initialization --hooks Set up pre-commit hooks (default in non-interactive mode) --no-hooks Skip pre-commit hooks setup --package-manager NAME Use specified package manager (pnpm, npm, yarn, bun) diff --git a/packages/cli/snap-tests-global/new-check/snap.txt b/packages/cli/snap-tests-global/new-check/snap.txt index 729eb1f044..b5257f5487 100644 --- a/packages/cli/snap-tests-global/new-check/snap.txt +++ b/packages/cli/snap-tests-global/new-check/snap.txt @@ -14,6 +14,8 @@ Options: --directory DIR Target directory for the generated project. --agent NAME Write coding agent instructions to AGENTS.md, CLAUDE.md, etc. --editor NAME Write editor config files for the specified editor. + --git Initialize a git repository with an initial commit + --no-git Skip git repository initialization --hooks Set up pre-commit hooks (default in non-interactive mode) --no-hooks Skip pre-commit hooks setup --package-manager NAME Use specified package manager (pnpm, npm, yarn, bun) diff --git a/packages/cli/src/create/bin.ts b/packages/cli/src/create/bin.ts index 059c3358bb..9af718d2f1 100644 --- a/packages/cli/src/create/bin.ts +++ b/packages/cli/src/create/bin.ts @@ -27,6 +27,7 @@ import { writeAgentInstructions, } from '../utils/agent.ts'; import { detectExistingEditors, selectEditors, writeEditorConfigs } from '../utils/editor.ts'; +import { createInitialCommit, initGitRepository } from '../utils/git.ts'; import { renderCliDoc } from '../utils/help.ts'; import { displayRelative } from '../utils/path.ts'; import { @@ -34,6 +35,7 @@ import { defaultInteractive, downloadPackageManager, promptGitHooks, + promptGitInit, runViteFmt, runViteInstall, selectPackageManager, @@ -95,6 +97,8 @@ const helpMessage = renderCliDoc({ label: '--editor NAME', description: 'Write editor config files for the specified editor.', }, + { label: '--git', description: 'Initialize a git repository with an initial commit' }, + { label: '--no-git', description: 'Skip git repository initialization' }, { label: '--hooks', description: 'Set up pre-commit hooks (default in non-interactive mode)', @@ -220,11 +224,12 @@ function parseArgs() { verbose?: boolean; agent?: string | string[] | false; editor?: string; + git?: boolean; hooks?: boolean; 'package-manager'?: string; }>(viteArgs, { alias: { h: 'help' }, - boolean: ['help', 'list', 'all', 'interactive', 'hooks', 'verbose'], + boolean: ['help', 'list', 'all', 'interactive', 'hooks', 'verbose', 'git'], string: ['directory', 'agent', 'editor', 'package-manager'], default: { interactive: defaultInteractive() }, }); @@ -241,6 +246,7 @@ function parseArgs() { verbose: parsed.verbose || false, agent: parsed.agent, editor: parsed.editor, + git: parsed.git, hooks: parsed.hooks, packageManager: parsed['package-manager'], } as Options, @@ -696,6 +702,7 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h onCancel: () => cancelAndExit(), })); + const shouldSetupGit = await promptGitInit(options); if (!isMonorepo) { shouldSetupHooks = await promptGitHooks(options); } @@ -811,6 +818,10 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h workspaceInfo.rootDir = fullPath; updateCreateProgress('Integrating monorepo'); rewriteMonorepo(workspaceInfo, undefined, compactOutput); + if (shouldSetupGit) { + updateCreateProgress('Initializing git repository'); + await initGitRepository(fullPath); + } if (shouldSetupHooks) { installGitHooks(fullPath, compactOutput); } @@ -820,6 +831,10 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h }); updateCreateProgress('Formatting code'); await runViteFmt(fullPath, options.interactive, undefined, { silent: compactOutput }); + if (shouldSetupGit) { + updateCreateProgress('Creating initial commit'); + await createInitialCommit(fullPath); + } clearCreateProgress(); showCreateSummary({ description: describeScaffold(selectedTemplateName, selectedTemplateArgs), @@ -1021,6 +1036,11 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h await runViteFmt(workspaceInfo.rootDir, options.interactive, [projectDir], { silent: compactOutput, }); + if (shouldSetupGit) { + updateCreateProgress('Creating initial commit'); + await initGitRepository(workspaceInfo.rootDir); + await createInitialCommit(workspaceInfo.rootDir); + } } else { if (shouldMigrateLintFmtTools) { await installAndMigrate(fullPath); @@ -1032,6 +1052,10 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h addFrameworkShim(fullPath, framework); } } + if (shouldSetupGit) { + updateCreateProgress('Initializing git repository'); + await initGitRepository(fullPath); + } if (shouldSetupHooks) { installGitHooks(fullPath, compactOutput); } @@ -1041,6 +1065,10 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h }); updateCreateProgress('Formatting code'); await runViteFmt(fullPath, options.interactive, undefined, { silent: compactOutput }); + if (shouldSetupGit) { + updateCreateProgress('Creating initial commit'); + await createInitialCommit(fullPath); + } } clearCreateProgress(); diff --git a/packages/cli/src/utils/git.ts b/packages/cli/src/utils/git.ts new file mode 100644 index 0000000000..d58de4c090 --- /dev/null +++ b/packages/cli/src/utils/git.ts @@ -0,0 +1,27 @@ +import { runCommandSilently } from './command.ts'; + +export async function initGitRepository(cwd: string): Promise { + const result = await runCommandSilently({ + command: 'git', + args: ['init'], + cwd, + envs: process.env, + }); + return result.exitCode === 0; +} + +export async function createInitialCommit(cwd: string): Promise { + await runCommandSilently({ + command: 'git', + args: ['add', '-A'], + cwd, + envs: process.env, + }); + const result = await runCommandSilently({ + command: 'git', + args: ['commit', '-m', 'Initial commit from Vite+'], + cwd, + envs: process.env, + }); + return result.exitCode === 0; +} diff --git a/packages/cli/src/utils/prompts.ts b/packages/cli/src/utils/prompts.ts index 3d6408dd53..aa3b68d224 100644 --- a/packages/cli/src/utils/prompts.ts +++ b/packages/cli/src/utils/prompts.ts @@ -180,6 +180,30 @@ export async function promptGitHooks(options: { return true; // non-interactive default } +export async function promptGitInit(options: { + git?: boolean; + interactive: boolean; +}): Promise { + if (options.git === false) { + return false; + } + if (options.git === true) { + return true; + } + if (options.interactive) { + const selected = await prompts.confirm({ + message: 'Initialize a git repository with an initial commit?', + initialValue: false, + }); + if (prompts.isCancel(selected)) { + cancelAndExit(); + return false; + } + return selected; + } + return false; // non-interactive default +} + export function defaultInteractive() { // If CI environment, use non-interactive mode by default return !process.env.CI && process.stdin.isTTY;