Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit c057f6e

Browse files
NicolasIRAGNEiburelCopilot
authored
feat: use gitpython for git stuff (#504)
Co-authored-by: Iwan Burel <iwan.burel@gmail.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent c9fff75 commit c057f6e

File tree

9 files changed

+455
-394
lines changed

9 files changed

+455
-394
lines changed

‎.pre-commit-config.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ repos:
117117
boto3>=1.28.0,
118118
click>=8.0.0,
119119
'fastapi[standard]>=0.109.1',
120+
gitpython>=3.1.0,
120121
httpx,
121122
loguru>=0.7.0,
122123
pathspec>=0.12.1,
@@ -144,6 +145,7 @@ repos:
144145
boto3>=1.28.0,
145146
click>=8.0.0,
146147
'fastapi[standard]>=0.109.1',
148+
gitpython>=3.1.0,
147149
httpx,
148150
loguru>=0.7.0,
149151
pathspec>=0.12.1,

‎Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ COPY src/ ./src/
1313

1414
RUN set -eux; \
1515
pip install --no-cache-dir --upgrade pip; \
16-
pip install --no-cache-dir --timeout 1000 .[server]
16+
pip install --no-cache-dir --timeout 1000 .[server,mcp]
1717

1818
# Stage 2: Runtime image
1919
FROM python:3.13.5-slim@sha256:4c2cf9917bd1cbacc5e9b07320025bdb7cdf2df7b0ceaccb55e9dd7e30987419

‎pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ readme = {file = "README.md", content-type = "text/markdown" }
66
requires-python = ">= 3.8"
77
dependencies = [
88
"click>=8.0.0",
9+
"gitpython>=3.1.0",
910
"httpx",
1011
"loguru>=0.7.0",
1112
"pathspec>=0.12.1",

‎src/gitingest/clone.py

Lines changed: 83 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,17 @@
55
from pathlib import Path
66
from typing import TYPE_CHECKING
77

8+
import git
9+
810
from gitingest.config import DEFAULT_TIMEOUT
911
from gitingest.utils.git_utils import (
1012
check_repo_exists,
1113
checkout_partial_clone,
12-
create_git_auth_header,
13-
create_git_command,
14+
create_git_repo,
1415
ensure_git_installed,
16+
git_auth_context,
1517
is_github_host,
1618
resolve_commit,
17-
run_command,
1819
)
1920
from gitingest.utils.logging_config import get_logger
2021
from gitingest.utils.os_utils import ensure_directory_exists_or_create
@@ -46,6 +47,8 @@ async def clone_repo(config: CloneConfig, *, token: str | None = None) -> None:
4647
------
4748
ValueError
4849
If the repository is not found, if the provided URL is invalid, or if the token format is invalid.
50+
RuntimeError
51+
If Git operations fail during the cloning process.
4952
5053
"""
5154
# Extract and validate query parameters
@@ -83,41 +86,91 @@ async def clone_repo(config: CloneConfig, *, token: str | None = None) -> None:
8386
commit = await resolve_commit(config, token=token)
8487
logger.debug("Resolved commit", extra={"commit": commit})
8588

86-
clone_cmd = ["git"]
87-
if token and is_github_host(url):
88-
clone_cmd += ["-c", create_git_auth_header(token, url=url)]
89-
90-
clone_cmd += ["clone", "--single-branch", "--no-checkout", "--depth=1"]
91-
if partial_clone:
92-
clone_cmd += ["--filter=blob:none", "--sparse"]
93-
94-
clone_cmd += [url, local_path]
95-
96-
# Clone the repository
97-
logger.info("Executing git clone command", extra={"command": " ".join([*clone_cmd[:-1], "<url>", local_path])})
98-
await run_command(*clone_cmd)
99-
logger.info("Git clone completed successfully")
89+
# Clone the repository using GitPython with proper authentication
90+
logger.info("Executing git clone operation", extra={"url": "<redacted>", "local_path": local_path})
91+
try:
92+
clone_kwargs = {
93+
"single_branch": True,
94+
"no_checkout": True,
95+
"depth": 1,
96+
}
97+
98+
with git_auth_context(url, token) as (git_cmd, auth_url):
99+
if partial_clone:
100+
# For partial clones, use git.Git() with filter and sparse options
101+
cmd_args = ["--single-branch", "--no-checkout", "--depth=1"]
102+
cmd_args.extend(["--filter=blob:none", "--sparse"])
103+
cmd_args.extend([auth_url, local_path])
104+
git_cmd.clone(*cmd_args)
105+
elif token and is_github_host(url):
106+
# For authenticated GitHub repos, use git_cmd with auth URL
107+
cmd_args = ["--single-branch", "--no-checkout", "--depth=1", auth_url, local_path]
108+
git_cmd.clone(*cmd_args)
109+
else:
110+
# For non-authenticated repos, use the standard GitPython method
111+
git.Repo.clone_from(url, local_path, **clone_kwargs)
112+
113+
logger.info("Git clone completed successfully")
114+
except git.GitCommandError as exc:
115+
msg = f"Git clone failed: {exc}"
116+
raise RuntimeError(msg) from exc
100117

101118
# Checkout the subpath if it is a partial clone
102119
if partial_clone:
103120
logger.info("Setting up partial clone for subpath", extra={"subpath": config.subpath})
104121
await checkout_partial_clone(config, token=token)
105122
logger.debug("Partial clone setup completed")
106123

107-
git = create_git_command(["git"], local_path, url, token)
124+
# Perform post-clone operations
125+
await _perform_post_clone_operations(config, local_path, url, token, commit)
108126

109-
# Ensure the commit is locally available
110-
logger.debug("Fetching specific commit", extra={"commit": commit})
111-
await run_command(*git, "fetch", "--depth=1", "origin", commit)
127+
logger.info("Git clone operation completed successfully", extra={"local_path": local_path})
112128

113-
# Write the work-tree at that commit
114-
logger.info("Checking out commit", extra={"commit": commit})
115-
await run_command(*git, "checkout", commit)
116129

117-
# Update submodules
118-
if config.include_submodules:
119-
logger.info("Updating submodules")
120-
await run_command(*git, "submodule", "update", "--init", "--recursive", "--depth=1")
121-
logger.debug("Submodules updated successfully")
130+
async def _perform_post_clone_operations(
131+
config: CloneConfig,
132+
local_path: str,
133+
url: str,
134+
token: str | None,
135+
commit: str,
136+
) -> None:
137+
"""Perform post-clone operations like fetching, checkout, and submodule updates.
122138
123-
logger.info("Git clone operation completed successfully", extra={"local_path": local_path})
139+
Parameters
140+
----------
141+
config : CloneConfig
142+
The configuration for cloning the repository.
143+
local_path : str
144+
The local path where the repository was cloned.
145+
url : str
146+
The repository URL.
147+
token : str | None
148+
GitHub personal access token (PAT) for accessing private repositories.
149+
commit : str
150+
The commit SHA to checkout.
151+
152+
Raises
153+
------
154+
RuntimeError
155+
If any Git operation fails.
156+
157+
"""
158+
try:
159+
repo = create_git_repo(local_path, url, token)
160+
161+
# Ensure the commit is locally available
162+
logger.debug("Fetching specific commit", extra={"commit": commit})
163+
repo.git.fetch("--depth=1", "origin", commit)
164+
165+
# Write the work-tree at that commit
166+
logger.info("Checking out commit", extra={"commit": commit})
167+
repo.git.checkout(commit)
168+
169+
# Update submodules
170+
if config.include_submodules:
171+
logger.info("Updating submodules")
172+
repo.git.submodule("update", "--init", "--recursive", "--depth=1")
173+
logger.debug("Submodules updated successfully")
174+
except git.GitCommandError as exc:
175+
msg = f"Git operation failed: {exc}"
176+
raise RuntimeError(msg) from exc

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /