## Git

```python
class Git()
```

Provides Git operations within a Sandbox.

**Example**:

```python
# Clone a repository

sandbox.git.clone(

url="https://github.com/user/repo.git",

path="workspace/repo"
)

# Check repository status

status = sandbox.git.status("workspace/repo")

print(f"Modified files: {status.modified}")

# Stage and commit changes

sandbox.git.add("workspace/repo", ["file.txt"])

sandbox.git.commit(

path="workspace/repo",

message="Update file",

author="John Doe",

email="john@example.com"
)
```

#### Git.__init__

```python
def __init__(api_client: GitApi)
```

Initializes a new Git handler instance.

**Arguments**:

- `api_client` _GitApi_ \- API client for Sandbox Git operations.

#### Git.add

```python
@intercept_errors(message_prefix="Failed to add files: ")
@with_instrumentation()

def add(path: str,

files: list[str],

request_timeout: float | None = None) -> None
```

Stages the specified files for the next commit, similar to running ‘git add’ on the command line.

**Arguments**:

- `path` _str_ \- Path to the Git repository root. Relative paths are resolved based on the sandbox working directory.
- `files` _list[str]_ \- List of file paths or directories to stage, relative to the repository root.
- `request_timeout` _float | None_ \- Optional client-side request timeout in seconds.

**Example**:

```python
# Stage a single file

sandbox.git.add("workspace/repo", ["file.txt"])

# Stage multiple files

sandbox.git.add("workspace/repo", [

"src/main.py",

"tests/test_main.py",

"README.md"
])
```

#### Git.branches

```python
@intercept_errors(message_prefix="Failed to list branches: ")
@with_instrumentation()

def branches(path: str,

request_timeout: float | None = None) -> ListBranchResponse
```

Lists branches in the repository.

**Arguments**:

- `path` _str_ \- Path to the Git repository root.
- `request_timeout` _float | None_ \- Optional client-side request timeout in seconds.

**Returns**:

- `ListBranchResponse` \- List of branches in the repository.

**Example**:

```python
response = sandbox.git.branches("workspace/repo")

print(f"Branches: {response.branches}")
```

#### Git.clone

```python
@intercept_errors(message_prefix="Failed to clone repository: ")
@with_instrumentation()

def clone(url: str,

path: str,

branch: str | None = None,

commit_id: str | None = None,

username: str | None = None,

password: str | None = None,

insecure_skip_tls: bool | None = None,

depth: int | None = None,

request_timeout: float | None = None) -> None
```

Clones a Git repository into the specified path.

**Arguments**:

- `url` _str_ \- Repository URL to clone from.
- `path` _str_ \- Path where the repository should be cloned.
- `branch` _str | None_ \- Specific branch to clone.
- `commit_id` _str | None_ \- Specific commit to clone.
- `username` _str | None_ \- Git username for authentication.
- `password` _str | None_ \- Git password or token for authentication.
- `insecure_skip_tls` _bool | None_ \- Skip TLS certificate verification (insecure).
- `depth` _int | None_ \- Create a shallow clone.
- `request_timeout` _float | None_ \- Optional client-side request timeout in seconds.

**Example**:

```python
# Clone the default branch

sandbox.git.clone(

url="https://github.com/user/repo.git",

path="workspace/repo"
)

# Clone a specific branch with authentication

sandbox.git.clone(

url="https://github.com/user/private-repo.git",

path="workspace/private",

branch="develop",

username="user",

password="token"
)

# Clone a specific commit

sandbox.git.clone(

url="https://github.com/user/repo.git",

path="workspace/repo-old",

commit_id="abc123"
)
```

#### Git.commit

```python
@intercept_errors(message_prefix="Failed to commit changes: ")
@with_instrumentation()

def commit(path: str,
           message: str,
           author: str,
           email: str,
           allow_empty: bool = False,
           request_timeout: float | None = None) -> GitCommitResponse
```

Creates a new commit with the staged changes.

**Arguments**:

- `path` _str_ \- Path to the Git repository root.
- `message` _str_ \- Commit message describing the changes.
- `author` _str_ \- Name of the commit author.
- `email` _str_ \- Email address of the commit author.
- `allow_empty` _bool, optional_ \- Allow creating an empty commit when no changes are staged.
- `request_timeout` _float | None_ \- Optional client-side request timeout.

**Example**:

```python
# Stage and commit changes

sandbox.git.add("workspace/repo", ["README.md"])

sandbox.git.commit(

path="workspace/repo",

message="Update documentation",

author="John Doe",

email="john@example.com",

allow_empty=True
)
```

#### Git.push

```python
@intercept_errors(message_prefix="Failed to push changes: ")
@with_instrumentation()

def push(path: str,
         username: str | None = None,
         password: str | None = None,
         branch: str | None = None,
         remote: str | None = None,
         set_upstream: bool = False,
         request_timeout: float | None = None) -> None
```

Pushes all local commits on the current branch to the remote repository.

**Arguments**:

- `path` _str_ \- Path to the Git repository root.
- `username` _str | None_ \- Git username for authentication.
- `password` _str | None_ \- Git password or token for authentication.
- `branch` _str | None_ \- Branch to push.
- `remote` _str | None_ \- Remote to push to.
- `set_upstream` _bool, optional_ \- Record the pushed branch as the upstream tracking branch.
- `request_timeout` _float | None_ \- Optional client-side request timeout in seconds.

**Example**:

```python
# Push without authentication (for public repos or SSH)

sandbox.git.push("workspace/repo")

# Push with authentication

sandbox.git.push(

path="workspace/repo",

username="user",

password="github_token"
)

# Push a new branch and set its upstream

sandbox.git.push("workspace/repo", branch="feature", set_upstream=True)
```

#### Git.pull

```python
@intercept_errors(message_prefix="Failed to pull changes: ")
@with_instrumentation()

def pull(path: str,
         username: str | None = None,
         password: str | None = None,
         branch: str | None = None,
         remote: str | None = None,
         request_timeout: float | None = None) -> None
```

Pulls changes from the remote repository.

**Arguments**:

- `path` _str_ \- Path to the Git repository root.
- `username` _str | None_ \- Git username for authentication.
- `password` _str | None_ \- Git password or token for authentication.
- `branch` _str | None_ \- Branch to pull.
- `remote` _str | None_ \- Remote to pull from.
- `request_timeout` _float | None_ \- Optional client-side request timeout in seconds.

**Example**:

```python
# Pull without authentication

sandbox.git.pull("workspace/repo")

# Pull with authentication

sandbox.git.pull(

path="workspace/repo",

username="user",

password="github_token"
)

# Pull a specific branch from a specific remote

sandbox.git.pull("workspace/repo", remote="upstream", branch="main")
```

#### Git.status

```python
@intercept_errors(message_prefix="Failed to get status: ")
@with_instrumentation()

def status(path: str, request_timeout: float | None = None) -> GitStatus
```

Gets the current Git repository status.

**Arguments**:

- `path` _str_ \- Path to the Git repository root.
- `request_timeout` _float | None_ \- Optional client-side request timeout in seconds.

**Returns**:

- `GitStatus`\- Repository status information including:
  - current_branch: Current branch name
  - file_status: List of file statuses
  - ahead: Number of local commits not pushed to remote
  - behind: Number of remote commits not pulled locally
  - branch_published: Whether the branch has been published to the remote repository

**Example**:

```python
status = sandbox.git.status("workspace/repo")

print(f"On branch: {status.current_branch}")

print(f"Commits ahead: {status.ahead}")

print(f"Commits behind: {status.behind}")
```

#### Git.checkout_branch

```python
@intercept_errors(message_prefix="Failed to checkout branch: ")
@with_instrumentation()

def checkout_branch(path: str,
                    branch: str,
                    request_timeout: float | None = None) -> None
```

Checkout branch in the repository.

**Arguments**:

- `path` _str_ \- Path to the Git repository root.
- `branch` _str_ \- Name of the branch to checkout
- `request_timeout` _float | None_ \- Optional client-side request timeout in seconds.

**Example**:

```python
# Checkout a branch

sandbox.git.checkout_branch("workspace/repo", "feature-branch")
```

#### Git.create_branch

```python
@intercept_errors(message_prefix="Failed to create branch: ")
@with_instrumentation()

def create_branch(path: str,
                  name: str,
                  request_timeout: float | None = None) -> None
```

Create branch in the repository.

**Arguments**:

- `path` _str_ \- Path to the Git repository root.
- `name` _str_ \- Name of the new branch to create
- `request_timeout` _float | None_ \- Optional client-side request timeout in seconds.

**Example**:

```python
# Create a new branch

sandbox.git.create_branch("workspace/repo", "new-feature")
```

#### Git.delete_branch

```python
@intercept_errors(message_prefix="Failed to delete branch: ")
@with_instrumentation()

def delete_branch(path: str,
                  name: str,
                  request_timeout: float | None = None) -> None
```

Delete branch in the repository.

**Arguments**:

- `path` _str_ \- Path to the Git repository root.
- `name` _str_ \- Name of the branch to delete
- `request_timeout` _float | None_ \- Optional client-side request timeout in seconds.

**Example**:

```python
# Delete a branch

sandbox.git.delete_branch("workspace/repo", "old-feature")
```

#### Git.init

```python
@intercept_errors(message_prefix="Failed to initialize repository: ")
@with_instrumentation()

def init(path: str,
         bare: bool = False,
         initial_branch: str | None = None,
         request_timeout: float | None = None) -> None
```

Initializes a new Git repository at the specified path.

**Arguments**:

- `path` _str_ \- Path where the repository should be initialized.
- `bare` _bool, optional_ \- Create a bare repository without a working tree.
- `initial_branch` _str | None_ \- Name of the initial branch.
- `request_timeout` _float | None_ \- Optional client-side request timeout in seconds.

**Example**:

```python
sandbox.git.init("workspace/repo", initial_branch="main")
```

#### Git.reset

```python
@intercept_errors(message_prefix="Failed to reset: ")
@with_instrumentation()

def reset(path: str,
          mode: str | None = None,
          target: str | None = None,
          files: list[str] | None = None,
          request_timeout: float | None = None) -> None
```

Resets the current HEAD to the specified state.

**Arguments**:

- `path` _str_ \- Path to the Git repository root.
- `mode` _str | None_ \- Reset mode.
- `target` _str | None_ \- Revision to reset to.
- `files` _list[str] | None_ \- Constrain the reset to the given paths.
- `request_timeout` _float | None_ \- Optional client-side request timeout in seconds.

**Example**:

```python
# Unstage all changes (mixed reset to HEAD)

sandbox.git.reset("workspace/repo")

# Hard reset to a previous commit

sandbox.git.reset("workspace/repo", mode="hard", target="HEAD~1")
```

#### Git.restore

```python
@intercept_errors(message_prefix="Failed to restore files: ")
@with_instrumentation()

def restore(path: str,
            files: list[str],
            staged: bool | None = None,
            worktree: bool | None = None,
            source: str | None = None,
            request_timeout: float | None = None) -> None
```

Restores working tree files or unstages changes.

**Arguments**:

- `path` _str_ \- Path to the Git repository root.
- `files` _list[str]_ \- File paths to restore.
- `staged` _bool | None_ \- Restore the staging index for the given files.
- `worktree` _bool | None_ \- Restore the working tree for the given files.
- `source` _str | None_ \- Restore file contents from the given revision instead of the index.
- `request_timeout` _float | None_ \- Optional client-side request timeout in seconds.

**Example**:

```python
# Discard working tree changes

sandbox.git.restore("workspace/repo", ["file.txt"])

# Unstage changes

sandbox.git.restore("workspace/repo", ["file.txt"], staged=True)
```

#### Git.remote_add

```python
@intercept_errors(message_prefix="Failed to add remote: ")
@with_instrumentation()

def remote_add(path: str,
               name: str,
               url: str,
               fetch: bool = False,
               overwrite: bool = False,
               request_timeout: float | None = None) -> None
```

Adds (or overwrites) a remote in the repository.

**Arguments**:

- `path` _str_ \- Path to the Git repository root.
- `name` _str_ \- Name of the remote.
- `url` _str_ \- URL of the remote.
- `fetch` _bool, optional_ \- Fetch from the remote immediately after adding it.
- `overwrite` _bool, optional_ \- Replace an existing remote with the same name.
- `request_timeout` _float | None_ \- Optional client-side request timeout in seconds.

**Example**:

```python
sandbox.git.remote_add("workspace/repo", "origin", "https://github.com/user/repo.git")
```

#### Git.remotes

```python
@intercept_errors(message_prefix="Failed to list remotes: ")
@with_instrumentation()

def remotes(path: str,
            request_timeout: float | None = None) -> ListRemotesResponse
```

Lists the remotes configured in the repository.

**Arguments**:

- `path` _str_ \- Path to the Git repository root.
- `request_timeout` _float | None_ \- Optional client-side request timeout in seconds.

**Returns**:

- `ListRemotesResponse` \- The configured remotes (name + URL).

**Example**:

```python
response = sandbox.git.remotes("workspace/repo")

for remote in response.remotes:

print(f"{remote.name}: {remote.url}")
```

#### Git.remote_get

```python
@intercept_errors(message_prefix="Failed to get remote: ")
@with_instrumentation()

def remote_get(path: str,
               name: str,
               request_timeout: float | None = None) -> str | None
```

Gets the URL of a remote, or None when it does not exist.

**Arguments**:

- `path` _str_ \- Path to the Git repository root.
- `name` _str_ \- Name of the remote.
- `request_timeout` _float | None_ \- Optional client-side request timeout in seconds.

**Returns**:

str | None: The remote URL, or None when the remote does not exist.

**Example**:

```python
url = sandbox.git.remote_get("workspace/repo", "origin")
```

#### Git.set_config

```python
@intercept_errors(message_prefix="Failed to set config: ")
@with_instrumentation()

def set_config(key: str,
               value: str,
               scope: str = "global",
               path: str | None = None,
               request_timeout: float | None = None) -> None
```

Sets a Git config value at the given scope.

**Arguments**:

- `key` _str_ \- Config key in dotted form.
- `value` _str_ \- Config value.
- `scope` _str, optional_ \- Config scope.
- `path` _str | None_ \- Repository path, required when scope is "local".
- `request_timeout` _float | None_ \- Optional client-side request timeout in seconds.

**Example**:

```python
sandbox.git.set_config("user.name", "John Doe")
```

#### Git.get_config

```python
@intercept_errors(message_prefix="Failed to get config: ")
@with_instrumentation()

def get_config(key: str,
               scope: str = "global",
               path: str | None = None,
               request_timeout: float | None = None) -> str | None
```

Gets a Git config value at the given scope, or None when unset.

**Arguments**:

- `key` _str_ \- Config key in dotted form.
- `scope` _str, optional_ \- Config scope.
- `path` _str | None_ \- Repository path, required when scope is "local".
- `request_timeout` _float | None_ \- Optional client-side request timeout in seconds.

**Returns**:

str | None: The config value, or None when the key is not set.

**Example**:

```python
name = sandbox.git.get_config("user.name")
```

#### Git.configure_user

```python
@intercept_errors(message_prefix="Failed to configure user: ")
@with_instrumentation()

def configure_user(name: str,
                   email: str,
                   scope: str = "global",
                   path: str | None = None,
                   request_timeout: float | None = None) -> None
```

Configures the Git user name and email at the given scope.

**Arguments**:

- `name` _str_ \- User name (user.name).
- `email` _str_ \- User email (user.email).
- `scope` _str, optional_ \- Config scope.
- `path` _str | None_ \- Repository path, required when scope is "local".
- `request_timeout` _float | None_ \- Optional client-side request timeout in seconds.

**Example**:

```python
sandbox.git.configure_user("John Doe", "john@example.com")
```

#### Git.dangerously_authenticate

```python
@intercept_errors(message_prefix="Failed to authenticate: ")
@with_instrumentation()

def dangerously_authenticate(username: str,
                             password: str,
                             host: str | None = None,
                             protocol: str | None = None,
                             request_timeout: float | None = None) -> None
```

Persists Git credentials globally so that subsequent operations against the given host authenticate automatically.

**Warnings**:
This stores the password in plaintext on disk via the Git credential store.

**Arguments**:

- `username` _str_ \- Git username.
- `password` _str_ \- Git password or token.
- `host` _str | None_ \- Host to authenticate against.
- `protocol` _str | None_ \- Protocol to authenticate against.
- `request_timeout` _float | None_ \- Optional client-side request timeout in seconds.

**Example**:

```python
sandbox.git.dangerously_authenticate("user", "github_token")
```

## GitCommitResponse

```python
class GitCommitResponse()
```

Response from the git commit.

**Attributes**:

- `sha` _str_ \- The SHA of the commit
