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;
+}