Skip to content

feat: initialize git repository when running pdm init #3483

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 18, 2025
Merged
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
33 changes: 33 additions & 0 deletions src/pdm/cli/commands/init.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,32 @@
def __init__(self) -> None:
self.interactive = True

def initialize_git(self, project: Project) -> None:
"""Initialize a git repository if git is available and .git doesn't exist."""
import shutil
import subprocess

if (project.root / ".git").exists():
project.core.ui.info("Git repository already exists, skipping initialization.")
return

Check warning on line 46 in src/pdm/cli/commands/init.py

View check run for this annotation

Codecov / codecov/patch

src/pdm/cli/commands/init.py#L45-L46

Added lines #L45 - L46 were not covered by tests

git_command = shutil.which("git")
if not git_command:
project.core.ui.info("Git command not found, skipping initialization.")
return

Check warning on line 51 in src/pdm/cli/commands/init.py

View check run for this annotation

Codecov / codecov/patch

src/pdm/cli/commands/init.py#L50-L51

Added lines #L50 - L51 were not covered by tests

try:
subprocess.run(
[git_command, "init"],
cwd=project.root,
check=True,
capture_output=True,
encoding="utf-8",
)
project.core.ui.info("Git repository initialized successfully.")
except subprocess.CalledProcessError as e:
project.core.ui.error(f"Failed to initialize Git repository: {e.stderr}")

Check warning on line 63 in src/pdm/cli/commands/init.py

View check run for this annotation

Codecov / codecov/patch

src/pdm/cli/commands/init.py#L62-L63

Added lines #L62 - L63 were not covered by tests

def do_init(self, project: Project, options: argparse.Namespace) -> None:
"""Bootstrap the project and create a pyproject.toml"""
hooks = HookManager(project, options.skip)
Expand All @@ -46,6 +72,10 @@
else:
self.set_python(project, options.python, hooks)
self._init_builtin(project, options)

if options.init_git:
self.initialize_git(project)

hooks.try_emit("post_init")

def _init_copier(self, project: Project, options: argparse.Namespace) -> None:
Expand Down Expand Up @@ -221,6 +251,9 @@
group.add_argument("--license", help="Specify the license (SPDX name)")
group.add_argument("--name", help="Specify the project name")
group.add_argument("--project-version", help="Specify the project's version")
group.add_argument(
"--no-git", dest="init_git", action="store_false", default=True, help="Do not initialize a git repository"
)
parser.add_argument(
"template", nargs="?", help="Specify the project template, which can be a local path or a Git URL"
)
Expand Down
8 changes: 6 additions & 2 deletions src/pdm/cli/completions/pdm.bash
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ _pdm_a919b69078acdf0a_complete()
;;

(init)
opts="--backend --cookiecutter --copier --dist --global --help --license --non-interactive --overwrite --project --project-version --python --quiet --skip --verbose"
opts="--backend --cookiecutter --copier --dist --global --help --license --name --no-git --non-interactive --overwrite --project --project-version --python --quiet --skip --verbose"
;;

(install)
Expand All @@ -80,6 +80,10 @@ _pdm_a919b69078acdf0a_complete()
opts="--append --check --config-setting --dev --exclude-newer --global --group --help --implementation --lockfile --no-cross-platform --no-default --no-isolation --no-static-urls --override --platform --production --project --python --quiet --refresh --skip --static-urls --strategy --update-reuse --update-reuse-installed --verbose --without"
;;

(new)
opts="--backend --dist --help --license --name --no-git --non-interactive --overwrite --project-version --python --quiet --skip --verbose"
;;

(outdated)
opts="--global --help --include-sub --json --project --quiet --verbose"
;;
Expand Down Expand Up @@ -146,7 +150,7 @@ _pdm_a919b69078acdf0a_complete()

# completing for a command
if [[ $cur == $com ]]; then
coms="add build cache completion config export fix import info init install list lock outdated plugin publish py python remove run search self show sync update use venv"
coms="add build cache completion config export fix import info init install list lock new outdated plugin publish py python remove run search self show sync update use venv"

COMPREPLY=($(compgen -W "${coms}" -- ${cur}))
__ltrim_colon_completions "$cur"
Expand Down
22 changes: 20 additions & 2 deletions src/pdm/cli/completions/pdm.fish
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

function __fish_pdm_a919b69078acdf0a_complete_no_subcommand
for i in (commandline -opc)
if contains -- $i add build cache completion config export fix import info init install list lock outdated plugin publish py python remove run search self show sync update use venv
if contains -- $i add build cache completion config export fix import info init install list lock new outdated plugin publish py python remove run search self show sync update use venv
return 1
end
end
Expand Down Expand Up @@ -122,7 +122,7 @@ complete -c pdm -f -n '__fish_pdm_a919b69078acdf0a_complete_no_subcommand' -a ex
complete -c pdm -A -n '__fish_seen_subcommand_from export' -l dev -d 'Select dev dependencies'
complete -c pdm -A -n '__fish_seen_subcommand_from export' -l editable-self -d 'Include the project itself as an editable dependency'
complete -c pdm -A -n '__fish_seen_subcommand_from export' -l expandvars -d 'Expand environment variables in requirements'
complete -c pdm -A -n '__fish_seen_subcommand_from export' -l format -d 'Only requirements.txt is supported for now.'
complete -c pdm -A -n '__fish_seen_subcommand_from export' -l format -d 'Export to requirements.txt format or pylock.toml format'
complete -c pdm -A -n '__fish_seen_subcommand_from export' -l global -d 'Use the global project, supply the project root with `-p` option'
complete -c pdm -A -n '__fish_seen_subcommand_from export' -l group -d 'Select group of optional-dependencies separated by comma or dependency-groups (with `-d`). Can be supplied multiple times, use ":all" to include all groups under the same species.'
complete -c pdm -A -n '__fish_seen_subcommand_from export' -l help -d 'Show this help message and exit.'
Expand Down Expand Up @@ -188,6 +188,8 @@ complete -c pdm -A -n '__fish_seen_subcommand_from init' -l dist -d 'Create a pa
complete -c pdm -A -n '__fish_seen_subcommand_from init' -l global -d 'Use the global project, supply the project root with `-p` option'
complete -c pdm -A -n '__fish_seen_subcommand_from init' -l help -d 'Show this help message and exit.'
complete -c pdm -A -n '__fish_seen_subcommand_from init' -l license -d 'Specify the license (SPDX name)'
complete -c pdm -A -n '__fish_seen_subcommand_from init' -l name -d 'Specify the project name'
complete -c pdm -A -n '__fish_seen_subcommand_from init' -l no-git -d 'Do not initialize a git repository'
complete -c pdm -A -n '__fish_seen_subcommand_from init' -l non-interactive -d 'Don\'t ask questions but use default values'
complete -c pdm -A -n '__fish_seen_subcommand_from init' -l overwrite -d 'Overwrite existing files'
complete -c pdm -A -n '__fish_seen_subcommand_from init' -l project -d 'Specify another path as the project root, which changes the base of pyproject.toml and __pypackages__ [env var: PDM_PROJECT]'
Expand Down Expand Up @@ -274,6 +276,22 @@ complete -c pdm -A -n '__fish_seen_subcommand_from lock' -l update-reuse-install
complete -c pdm -A -n '__fish_seen_subcommand_from lock' -l verbose -d 'Use `-v` for detailed output and `-vv` for more detailed'
complete -c pdm -A -n '__fish_seen_subcommand_from lock' -l without -d 'Exclude groups of optional-dependencies or dependency-groups'

# new
complete -c pdm -f -n '__fish_pdm_a919b69078acdf0a_complete_no_subcommand' -a new -d 'Create a new Python project at <project_path>'
complete -c pdm -A -n '__fish_seen_subcommand_from new' -l backend -d 'Specify the build backend, which implies --dist'
complete -c pdm -A -n '__fish_seen_subcommand_from new' -l dist -d 'Create a package for distribution'
complete -c pdm -A -n '__fish_seen_subcommand_from new' -l help -d 'Show this help message and exit.'
complete -c pdm -A -n '__fish_seen_subcommand_from new' -l license -d 'Specify the license (SPDX name)'
complete -c pdm -A -n '__fish_seen_subcommand_from new' -l name -d 'Specify the project name'
complete -c pdm -A -n '__fish_seen_subcommand_from new' -l no-git -d 'Do not initialize a git repository'
complete -c pdm -A -n '__fish_seen_subcommand_from new' -l non-interactive -d 'Don\'t ask questions but use default values'
complete -c pdm -A -n '__fish_seen_subcommand_from new' -l overwrite -d 'Overwrite existing files'
complete -c pdm -A -n '__fish_seen_subcommand_from new' -l project-version -d 'Specify the project\'s version'
complete -c pdm -A -n '__fish_seen_subcommand_from new' -l python -d 'Specify the Python version/path to use'
complete -c pdm -A -n '__fish_seen_subcommand_from new' -l quiet -d 'Suppress output'
complete -c pdm -A -n '__fish_seen_subcommand_from new' -l skip -d 'Skip some tasks and/or hooks by their comma-separated names. Can be supplied multiple times. Use ":all" to skip all hooks. Use ":pre" and ":post" to skip all pre or post hooks.'
complete -c pdm -A -n '__fish_seen_subcommand_from new' -l verbose -d 'Use `-v` for detailed output and `-vv` for more detailed'

# outdated
complete -c pdm -f -n '__fish_pdm_a919b69078acdf0a_complete_no_subcommand' -a outdated -d 'Check for outdated packages and list the latest versions on indexes.'
complete -c pdm -A -n '__fish_seen_subcommand_from outdated' -l global -d 'Use the global project, supply the project root with `-p` option'
Expand Down
3 changes: 2 additions & 1 deletion src/pdm/cli/completions/pdm.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -286,12 +286,13 @@ function TabExpansion($line, $lastWord) {
))
break
}
"new" {}
"init" {
$completer.AddOpts(
@(
[Option]::new(@(
"-g", "--global", "--non-interactive", "-n", "--python", "--dist", "--lib", "--copier",
"--cookiecutter", "--overwrite", "--license", "--project-version"
"--cookiecutter", "--overwrite", "--license", "--project-version", "--name", "--no-git"
)),
$projectOption,
$skipOption,
Expand Down
5 changes: 4 additions & 1 deletion src/pdm/cli/completions/pdm.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ _pdm() {
'import:Import project metadata from other formats'
'info:Show the project information'
'init:Initialize a pyproject.toml for PDM'
'new:Create a new Python project at project_path'
'install:Install dependencies from lock file'
'list:List packages installed in the current working set'
'lock:Resolve and lock dependencies'
Expand Down Expand Up @@ -195,7 +196,7 @@ _pdm() {
'--venv[Run the command in the virtual environment with the given key. \[env var: PDM_IN_VENV\]]:venv:'
)
;;
init)
new|init)
arguments+=(
{-g,--global}'[Use the global project, supply the project root with `-p` option]'
{-n,--non-interactive}"[Don't ask questions but use default values]"
Expand All @@ -207,6 +208,8 @@ _pdm() {
'--copier[Use Copier to generate project]'
'--cookiecutter[Use Cookiecutter to generate project]'
'--license[Specify the license (SPDX name)]:license:'
'--name[Specify the project name]:name:'
'--no-git[Do not initialize a git repository]'
"--project-version[Specify the project's version]:project_version:"
'1:template:'
)
Expand Down
6 changes: 6 additions & 0 deletions src/pdm/cli/templates/minimal/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.py[cod]
__pycache__/
.mypy_cache/
.pytest_cache/
.ruff_cache/
.pdm-python