Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/guide/create.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ Run `vp create --list` to see the built-in templates and the common shorthand te
- `--directory <dir>` writes the generated project into a specific target directory
- `--agent <name>` creates agent instructions files during scaffolding
- `--editor <name>` 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
Expand Down
6 changes: 6 additions & 0 deletions packages/cli/snap-tests-global/command-create-help/snap.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,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)
Expand Down Expand Up @@ -78,6 +80,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)
Expand Down Expand Up @@ -139,6 +143,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)
Expand Down
2 changes: 2 additions & 0 deletions packages/cli/snap-tests-global/new-check/snap.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,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)
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/snap-tests-global/new-vite-monorepo-bun/snap.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
> vp create vite:monorepo --no-interactive --package-manager bun # create monorepo with bun
> vp create vite:monorepo --no-interactive --package-manager bun --git # create monorepo with bun
> ls vite-plus-monorepo | LC_ALL=C sort # check files created
AGENTS.md
README.md
Expand Down Expand Up @@ -48,7 +48,7 @@ No pnpm-workspace.yaml
> test ! -f vite-plus-monorepo/.yarnrc.yml && echo 'No .yarnrc.yml' || echo 'ERROR: .yarnrc.yml exists' # verify no yarn config
No .yarnrc.yml

> test -d vite-plus-monorepo/.git && echo 'Git initialized' || echo 'No git' # check git init
> test -d vite-plus-monorepo/.git && echo 'Git initialized' # check git init
Git initialized

> ls vite-plus-monorepo/apps # check apps directory
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
"ignoredPlatforms": ["win32"],
"commands": [
{
"command": "vp create vite:monorepo --no-interactive --package-manager bun # create monorepo with bun",
"command": "vp create vite:monorepo --no-interactive --package-manager bun --git # create monorepo with bun",
"ignoreOutput": true
},
"ls vite-plus-monorepo | LC_ALL=C sort # check files created",
"cat vite-plus-monorepo/package.json # check package.json with catalog",
"test ! -f vite-plus-monorepo/pnpm-workspace.yaml && echo 'No pnpm-workspace.yaml' || echo 'ERROR: pnpm-workspace.yaml exists' # verify no pnpm config",
"test ! -f vite-plus-monorepo/.yarnrc.yml && echo 'No .yarnrc.yml' || echo 'ERROR: .yarnrc.yml exists' # verify no yarn config",
"test -d vite-plus-monorepo/.git && echo 'Git initialized' || echo 'No git' # check git init",
"test -d vite-plus-monorepo/.git && echo 'Git initialized' # check git init",
"ls vite-plus-monorepo/apps # check apps directory",
"cat vite-plus-monorepo/apps/website/package.json # check website uses catalog:"
]
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/snap-tests-global/new-vite-monorepo/snap.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
> vp create vite:monorepo --no-interactive # create monorepo with default values
> vp create vite:monorepo --no-interactive --git # create monorepo with default values
> ls vite-plus-monorepo | LC_ALL=C sort # check files created
AGENTS.md
README.md
Expand Down Expand Up @@ -74,7 +74,7 @@ peerDependencyRules:
> test ! -f vite-plus-monorepo/.yarnrc.yml && echo 'No .yarnrc.yml' || echo 'ERROR: .yarnrc.yml exists' # verify no yarn config for pnpm
No .yarnrc.yml

> test -d vite-plus-monorepo/.git && echo 'Git initialized' || echo 'No git' # check git init
> test -d vite-plus-monorepo/.git && echo 'Git initialized' # check git init
Git initialized

> ls vite-plus-monorepo/apps # check apps directory created
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/snap-tests-global/new-vite-monorepo/steps.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"ignoredPlatforms": ["win32"],
"commands": [
{
"command": "vp create vite:monorepo --no-interactive # create monorepo with default values",
"command": "vp create vite:monorepo --no-interactive --git # create monorepo with default values",
"ignoreOutput": true
},
"ls vite-plus-monorepo | LC_ALL=C sort # check files created",
Expand All @@ -11,7 +11,7 @@
"cat vite-plus-monorepo/pnpm-workspace.yaml # check workspace config",
"test -f vite-plus-monorepo/.gitignore && echo '.gitignore exists' || echo 'ERROR: .gitignore missing' # verify gitignore renamed from _gitignore",
"test ! -f vite-plus-monorepo/.yarnrc.yml && echo 'No .yarnrc.yml' || echo 'ERROR: .yarnrc.yml exists' # verify no yarn config for pnpm",
"test -d vite-plus-monorepo/.git && echo 'Git initialized' || echo 'No git' # check git init",
"test -d vite-plus-monorepo/.git && echo 'Git initialized' # check git init",
"ls vite-plus-monorepo/apps # check apps directory created",
"ls vite-plus-monorepo/apps/website/package.json # check website package.json",
{
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/snap-tests/create-org-bundled-monorepo/snap.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
> node $SNAP_CASES_DIR/.shared/mock-npm-registry.mjs -- vp create @your-org:workspace --no-interactive --directory my-mono # bundled monorepo: extract tarball, scaffold, inject create.defaultTemplate
> node $SNAP_CASES_DIR/.shared/mock-npm-registry.mjs -- vp create @your-org:workspace --no-interactive --directory my-mono --git # bundled monorepo: extract tarball, scaffold, inject create.defaultTemplate
◇ Scaffolded my-mono
• Node <semver> pnpm <semver>
→ Next: cd my-mono && vp run
Expand Down Expand Up @@ -35,7 +35,7 @@ peerDependencyRules:
vite: "*"
vitest: "*"

> test -d my-mono/.git && echo 'Git initialized' || echo 'No git' # git-init prompt covers bundled monorepo path
> test -d my-mono/.git && echo 'Git initialized' # git-init prompt covers bundled monorepo path
Git initialized

> cat my-mono/.gitignore # node_modules excluded even though tarball shipped no .gitignore
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"commands": [
"node $SNAP_CASES_DIR/.shared/mock-npm-registry.mjs -- vp create @your-org:workspace --no-interactive --directory my-mono # bundled monorepo: extract tarball, scaffold, inject create.defaultTemplate",
"node $SNAP_CASES_DIR/.shared/mock-npm-registry.mjs -- vp create @your-org:workspace --no-interactive --directory my-mono --git # bundled monorepo: extract tarball, scaffold, inject create.defaultTemplate",
"cat my-mono/vite.config.ts # create.defaultTemplate auto-set to @your-org",
"cat my-mono/pnpm-workspace.yaml # workspace markers preserved",
"test -d my-mono/.git && echo 'Git initialized' || echo 'No git' # git-init prompt covers bundled monorepo path",
"test -d my-mono/.git && echo 'Git initialized' # git-init prompt covers bundled monorepo path",
"cat my-mono/.gitignore # node_modules excluded even though tarball shipped no .gitignore"
]
}
40 changes: 37 additions & 3 deletions packages/cli/src/create/bin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,15 @@ 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 {
type CommandRunSummary,
defaultInteractive,
downloadPackageManager,
promptGitHooks,
promptGitInit,
runViteFmt,
runViteInstall,
selectPackageManager,
Expand Down Expand Up @@ -106,6 +108,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)',
Expand Down Expand Up @@ -235,11 +239,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() },
});
Expand All @@ -256,6 +261,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,
Expand Down Expand Up @@ -747,6 +753,7 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h
onCancel: () => cancelAndExit(),
}));

const shouldSetupGit = await promptGitInit(options);
Comment thread
fengmk2 marked this conversation as resolved.
if (!isMonorepo) {
shouldSetupHooks = await promptGitHooks(options);
}
Expand Down Expand Up @@ -827,7 +834,7 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h
// #region Handle monorepo template
if (templateInfo.command === BuiltinTemplate.monorepo || isBundledMonorepo) {
// Ask up-front so the prompt isn't buried under scaffold output.
let shouldInitGit = true;
let shouldInitGit = shouldSetupGit;
if (options.interactive && !compactOutput) {
pauseCreateProgress();
const selected = await prompts.confirm({
Expand All @@ -841,7 +848,7 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h
} else {
shouldInitGit = selected;
}
} else if (!compactOutput) {
} else if (shouldInitGit && !compactOutput) {
prompts.log.info('Initializing git repository (default: yes)');
}

Expand Down Expand Up @@ -902,6 +909,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 (bundled?.monorepo) {
// Wire `create.defaultTemplate: '<scope>'` into the new workspace's
// vite.config.ts so a bare `vp create` from inside it opens the
Expand All @@ -922,6 +933,13 @@ 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');
const committed = await createInitialCommit(fullPath);
if (!committed) {
prompts.log.warn('Initial commit failed. Check your git user.name/user.email config');
}
}
clearCreateProgress();
showCreateSummary({
description: describeScaffold(selectedTemplateName, selectedTemplateArgs),
Expand Down Expand Up @@ -1137,6 +1155,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);
Comment on lines +1160 to +1161
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Limit initial commits to generated files

In an existing monorepo, opting into --git runs the commit from workspaceInfo.rootDir; createInitialCommit does git add -A, which stages every tracked/untracked change in that repo (confirmed via git add -h). If the user has unrelated dirty work anywhere in the monorepo, vp create ... --git will include it in the scaffold's "Initial commit" rather than only the new project/workspace edits.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that no action is required about this either, for the reasons below.

#1484 (comment)

Comment thread
fengmk2 marked this conversation as resolved.
}
} else {
if (shouldMigrateLintFmtTools) {
await installAndMigrate(fullPath);
Expand All @@ -1148,6 +1171,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);
}
Comment thread
fengmk2 marked this conversation as resolved.
if (shouldSetupHooks) {
installGitHooks(fullPath, compactOutput);
}
Expand All @@ -1159,6 +1186,13 @@ 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');
const committed = await createInitialCommit(fullPath);
if (!committed) {
prompts.log.warn('Initial commit failed. Check your git user.name/user.email config');
}
}
}

clearCreateProgress();
Expand Down
27 changes: 27 additions & 0 deletions packages/cli/src/utils/git.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { runCommandSilently } from './command.ts';

export async function initGitRepository(cwd: string): Promise<boolean> {
const result = await runCommandSilently({
command: 'git',
args: ['init'],
cwd,
envs: process.env,
});
return result.exitCode === 0;
}

export async function createInitialCommit(cwd: string): Promise<boolean> {
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;
}
24 changes: 24 additions & 0 deletions packages/cli/src/utils/prompts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,30 @@ export async function promptGitHooks(options: {
return true; // non-interactive default
}

export async function promptGitInit(options: {
git?: boolean;
interactive: boolean;
}): Promise<boolean> {
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;
Expand Down