From 779c8e8766547878c57770330273f2f9b2492f75 Mon Sep 17 00:00:00 2001 From: ryohidaka <39184410+ryohidaka@users.noreply.github.com> Date: Mon, 27 Apr 2026 09:48:33 +0900 Subject: [PATCH 1/2] feat(cli): add flag to initialize a git repository --- docs/guide/create.md | 2 ++ .../command-create-help/snap.txt | 6 +++++ .../cli/snap-tests-global/new-check/snap.txt | 2 ++ packages/cli/src/create/bin.ts | 20 +++++++++++++++- packages/cli/src/utils/git.ts | 11 +++++++++ packages/cli/src/utils/prompts.ts | 24 +++++++++++++++++++ 6 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 packages/cli/src/utils/git.ts 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..ed3fae5434 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 { 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); } @@ -1021,6 +1032,9 @@ 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) { + await initGitRepository(workspaceInfo.rootDir); + } } else { if (shouldMigrateLintFmtTools) { await installAndMigrate(fullPath); @@ -1032,6 +1046,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); } diff --git a/packages/cli/src/utils/git.ts b/packages/cli/src/utils/git.ts new file mode 100644 index 0000000000..fa16710397 --- /dev/null +++ b/packages/cli/src/utils/git.ts @@ -0,0 +1,11 @@ +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; +} 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; From d1fb08e666cd4fe98271af60cd0c00dc31653b7a Mon Sep 17 00:00:00 2001 From: ryohidaka <39184410+ryohidaka@users.noreply.github.com> Date: Mon, 27 Apr 2026 09:54:57 +0900 Subject: [PATCH 2/2] feat(cli): create initial commit after scaffold completes --- packages/cli/src/create/bin.ts | 12 +++++++++++- packages/cli/src/utils/git.ts | 16 ++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/packages/cli/src/create/bin.ts b/packages/cli/src/create/bin.ts index ed3fae5434..9af718d2f1 100644 --- a/packages/cli/src/create/bin.ts +++ b/packages/cli/src/create/bin.ts @@ -27,7 +27,7 @@ import { writeAgentInstructions, } from '../utils/agent.ts'; import { detectExistingEditors, selectEditors, writeEditorConfigs } from '../utils/editor.ts'; -import { initGitRepository } from '../utils/git.ts'; +import { createInitialCommit, initGitRepository } from '../utils/git.ts'; import { renderCliDoc } from '../utils/help.ts'; import { displayRelative } from '../utils/path.ts'; import { @@ -831,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), @@ -1033,7 +1037,9 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h silent: compactOutput, }); if (shouldSetupGit) { + updateCreateProgress('Creating initial commit'); await initGitRepository(workspaceInfo.rootDir); + await createInitialCommit(workspaceInfo.rootDir); } } else { if (shouldMigrateLintFmtTools) { @@ -1059,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 index fa16710397..d58de4c090 100644 --- a/packages/cli/src/utils/git.ts +++ b/packages/cli/src/utils/git.ts @@ -9,3 +9,19 @@ export async function initGitRepository(cwd: string): Promise { }); 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; +}