# Git 集成
<subtitle>在沙箱内克隆仓库、管理分支、提交并推送代码。</subtitle>

您可以通过 `sandbox.git` 方法在沙箱内执行常见 Git 操作，包括克隆仓库、配置身份、查看状态、管理分支、提交、拉取、推送以及管理远程仓库。

## 认证与身份配置

### 在命令中传入凭据

如果需要通过 HTTP(S) 访问私有仓库，可以在需要认证的操作中直接传入 `username` 和 `password`。这里的 `password` 通常是访问令牌。只要传入 `password`，就必须同时传入 `username`。

```python
import os
from ucloud_sandbox import Sandbox

sandbox = Sandbox.create()
repo_path = "/home/user/repo"

sandbox.git.push(
    repo_path,
    username=os.environ.get("GIT_USERNAME"),
    password=os.environ.get("GIT_TOKEN"),
)

sandbox.git.pull(
    repo_path,
    username=os.environ.get("GIT_USERNAME"),
    password=os.environ.get("GIT_TOKEN"),
)
```

### 使用凭据助手

如果不想在每次操作时都传入凭据，可以使用 `dangerously_authenticate()` 将凭据写入沙箱内的 Git credential helper。

> 凭据会被存储在沙箱磁盘中。任何能访问该沙箱的进程或 Agent 都可能读取这些凭据。请只在理解风险后使用。

```python
import os
from ucloud_sandbox import Sandbox

sandbox = Sandbox.create()

# 默认用于 GitHub
sandbox.git.dangerously_authenticate(
    username=os.environ.get("GIT_USERNAME"),
    password=os.environ.get("GIT_TOKEN"),
)

# 自托管 Git 服务
sandbox.git.dangerously_authenticate(
    username=os.environ.get("GIT_USERNAME"),
    password=os.environ.get("GIT_TOKEN"),
    host="git.example.com",
    protocol="https",
)

# 之后的 HTTPS Git 操作会使用已保存的凭据
sandbox.git.clone("https://git.example.com/org/repo.git", path="/home/user/repo")
sandbox.git.push("/home/user/repo")
```

### 将凭据保留在远程 URL 中

默认情况下，克隆完成后，凭据会从远程 URL 中移除。如果确实需要将凭据保留在远程 URL 中，也就是写入仓库的 `.git/config`，可以设置 `dangerously_store_credentials=True`。

> 将凭据保留在远程 URL 中会让它们持久化到仓库配置里。任何能访问该沙箱或仓库目录的进程或 Agent 都可能读取这些凭据。仅在确有必要时使用。

```python
import os
from ucloud_sandbox import Sandbox

sandbox = Sandbox.create()

# 默认行为：克隆后从远程 URL 中移除凭据
sandbox.git.clone(
    "https://git.example.com/org/repo.git",
    path="/home/user/repo",
    username=os.environ.get("GIT_USERNAME"),
    password=os.environ.get("GIT_TOKEN"),
)

# 将凭据保留在远程 URL 中
sandbox.git.clone(
    "https://git.example.com/org/repo.git",
    path="/home/user/repo",
    username=os.environ.get("GIT_USERNAME"),
    password=os.environ.get("GIT_TOKEN"),
    dangerously_store_credentials=True,
)
```

### 配置提交身份

提交前通常需要设置 Git author 的名称和邮箱。您可以配置为全局身份，也可以只配置某个仓库的本地身份。

```python
from ucloud_sandbox import Sandbox

sandbox = Sandbox.create()
repo_path = "/home/user/repo"

# 全局配置
sandbox.git.configure_user("UCloud Bot", "bot@example.com")

# 仓库本地配置
sandbox.git.configure_user(
    "UCloud Bot",
    "bot@example.com",
    scope="local",
    path=repo_path,
)
```

## 克隆仓库

私有仓库的认证方式请参考 [认证与身份配置](#认证与身份配置)。

```python
from ucloud_sandbox import Sandbox

sandbox = Sandbox.create()
repo_url = "https://git.example.com/org/repo.git"
repo_path = "/home/user/repo"

# 默认克隆
sandbox.git.clone(repo_url, path=repo_path)

# 克隆指定分支
sandbox.git.clone(repo_url, path=repo_path, branch="main")

# 浅克隆
sandbox.git.clone(repo_url, path=repo_path, depth=1)
```

## 查看状态与分支

`status()` 会返回结构化对象，包含当前分支、ahead/behind 计数和文件状态。`branches()` 会返回分支列表和当前分支。

```python
from ucloud_sandbox import Sandbox

sandbox = Sandbox.create()
repo_path = "/home/user/repo"

status = sandbox.git.status(repo_path)
print(status.current_branch, status.ahead, status.behind)
print(status.file_status)

branches = sandbox.git.branches(repo_path)
print(branches.current_branch)
print(branches.branches)
```

## 创建和管理分支

```python
from ucloud_sandbox import Sandbox

sandbox = Sandbox.create()
repo_path = "/home/user/repo"

# 创建并切换到新分支
sandbox.git.create_branch(repo_path, "feature/new-docs")

# 切换到已有分支
sandbox.git.checkout_branch(repo_path, "main")

# 删除分支
sandbox.git.delete_branch(repo_path, "feature/old-docs")

# 强制删除分支
sandbox.git.delete_branch(repo_path, "feature/stale-docs", force=True)
```

## 暂存与提交

```python
from ucloud_sandbox import Sandbox

sandbox = Sandbox.create()
repo_path = "/home/user/repo"

# 默认暂存所有变更，并使用仓库配置提交
sandbox.git.add(repo_path)
sandbox.git.commit(repo_path, "Initial commit")

# 暂存指定文件
sandbox.git.add(repo_path, files=["README.md", "src/index.py"])

# 允许空提交，并覆盖提交作者
sandbox.git.commit(
    repo_path,
    "Docs sync",
    author_name="UCloud Bot",
    author_email="bot@example.com",
    allow_empty=True,
)
```

## 拉取与推送

私有仓库的认证方式请参考 [认证与身份配置](#认证与身份配置)。

```python
from ucloud_sandbox import Sandbox

sandbox = Sandbox.create()
repo_path = "/home/user/repo"

# 默认行为：如果已设置 upstream，则使用 upstream
sandbox.git.push(repo_path)
sandbox.git.pull(repo_path)

# 指定 remote/branch，并设置 upstream
sandbox.git.push(
    repo_path,
    remote="origin",
    branch="main",
    set_upstream=True,
)

sandbox.git.pull(
    repo_path,
    remote="origin",
    branch="main",
)
```

## 管理远程仓库

```python
from ucloud_sandbox import Sandbox

sandbox = Sandbox.create()
repo_path = "/home/user/repo"
repo_url = "https://git.example.com/org/repo.git"

# 添加远程仓库
sandbox.git.remote_add(repo_path, "origin", repo_url)

# 添加远程仓库后执行 fetch
sandbox.git.remote_add(repo_path, "origin", repo_url, fetch=True)

# 如果远程仓库已存在，则覆盖远程 URL
sandbox.git.remote_add(repo_path, "origin", repo_url, overwrite=True)
```

## Git 配置

您可以设置和读取 Git 配置项。如果要配置提交作者，请参考 [配置提交身份](#配置提交身份)。

```python
from ucloud_sandbox import Sandbox

sandbox = Sandbox.create()
repo_path = "/home/user/repo"

# 全局配置
sandbox.git.set_config("pull.rebase", "false")
rebase = sandbox.git.get_config("pull.rebase")

# 仓库本地配置
sandbox.git.set_config("pull.rebase", "false", scope="local", path=repo_path)
local_rebase = sandbox.git.get_config("pull.rebase", scope="local", path=repo_path)
```
