diff --git a/docs.json b/docs.json
index 4254115..e6e6af5 100644
--- a/docs.json
+++ b/docs.json
@@ -151,6 +151,12 @@
"docs/commands/background"
]
},
+ {
+ "group": "Git",
+ "pages": [
+ "docs/git"
+ ]
+ },
{
"group": "MCP Gateway",
"pages": [
@@ -323,4 +329,4 @@
"permanent": true
}
]
-}
\ No newline at end of file
+}
diff --git a/docs/git.mdx b/docs/git.mdx
new file mode 100644
index 0000000..a0355a0
--- /dev/null
+++ b/docs/git.mdx
@@ -0,0 +1,421 @@
+---
+title: "Git"
+sidebarTitle: Overview
+---
+
+Use the `sandbox.git` methods to run common git operations inside a sandbox.
+
+### Authentication & Identity
+
+#### Passing credentials inline
+
+For private repositories over HTTP(S), pass `username` and `password` (token) directly to commands that need authentication. A username is required whenever you pass a password/token.
+
+
+```js JavaScript & TypeScript
+const repoPath = '/home/user/repo'
+
+await sandbox.git.push(repoPath, {
+ username: process.env.GIT_USERNAME,
+ password: process.env.GIT_TOKEN,
+})
+
+await sandbox.git.pull(repoPath, {
+ username: process.env.GIT_USERNAME,
+ password: process.env.GIT_TOKEN,
+})
+```
+```python Python
+import os
+
+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"),
+)
+```
+
+
+#### Credential helper (authenticate once)
+
+To avoid passing credentials on each command, store them in the git credential helper inside the sandbox using `dangerouslyAuthenticate()` / `dangerously_authenticate()`.
+
+
+Stores credentials on disk inside the sandbox. Any process or agent with access to the sandbox can read them. Use only when you understand the risk.
+
+
+
+```js JavaScript & TypeScript
+// Default (GitHub)
+await sandbox.git.dangerouslyAuthenticate({
+ username: process.env.GIT_USERNAME,
+ password: process.env.GIT_TOKEN,
+})
+
+// Custom host (self-hosted)
+await sandbox.git.dangerouslyAuthenticate({
+ username: process.env.GIT_USERNAME,
+ password: process.env.GIT_TOKEN,
+ host: 'git.example.com',
+ protocol: 'https',
+})
+
+// After this, HTTPS git operations use the stored credentials
+await sandbox.git.clone('https://git.example.com/org/repo.git', { path: '/home/user/repo' })
+await sandbox.git.push('/home/user/repo')
+```
+```python Python
+import os
+
+# Default (GitHub)
+sandbox.git.dangerously_authenticate(
+ username=os.environ.get("GIT_USERNAME"),
+ password=os.environ.get("GIT_TOKEN"),
+)
+
+# Custom host (self-hosted)
+sandbox.git.dangerously_authenticate(
+ username=os.environ.get("GIT_USERNAME"),
+ password=os.environ.get("GIT_TOKEN"),
+ host="git.example.com",
+ protocol="https",
+)
+
+# After this, HTTPS git operations use the stored credentials
+sandbox.git.clone("https://git.example.com/org/repo.git", path="/home/user/repo")
+sandbox.git.push("/home/user/repo")
+```
+
+
+#### Keep credentials in the remote URL
+
+By default, credentials are stripped from the remote URL after cloning. To keep credentials in the remote URL (stored in `.git/config`), set `dangerouslyStoreCredentials` / `dangerously_store_credentials`.
+
+
+Storing credentials in the remote URL persists them in the repo config. Any process or agent with access to the sandbox can read them. Only use this when required.
+
+
+
+```js JavaScript & TypeScript
+// Default: credentials are stripped from the remote URL
+await sandbox.git.clone('https://git.example.com/org/repo.git', {
+ path: '/home/user/repo',
+ username: process.env.GIT_USERNAME,
+ password: process.env.GIT_TOKEN,
+})
+
+// Keep credentials in the remote URL
+await sandbox.git.clone('https://git.example.com/org/repo.git', {
+ path: '/home/user/repo',
+ username: process.env.GIT_USERNAME,
+ password: process.env.GIT_TOKEN,
+ dangerouslyStoreCredentials: true,
+})
+```
+```python Python
+import os
+
+# Default: credentials are stripped from the remote 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"),
+)
+
+# Keep credentials in the remote 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,
+)
+```
+
+
+#### Configure git identity
+
+Set the git author name and email for commits. Configure globally or per-repository.
+
+
+```js JavaScript & TypeScript
+const repoPath = '/home/user/repo'
+
+// Global config
+await sandbox.git.configureUser('E2B Bot', 'bot@example.com')
+
+// Repo-local config
+await sandbox.git.configureUser('E2B Bot', 'bot@example.com', {
+ scope: 'local',
+ path: repoPath
+})
+```
+```python Python
+repo_path = "/home/user/repo"
+
+# Global config
+sandbox.git.configure_user("E2B Bot", "bot@example.com")
+
+# Repo-local config
+sandbox.git.configure_user(
+ "E2B Bot",
+ "bot@example.com",
+ scope="local",
+ path=repo_path
+)
+```
+
+
+### Clone a repository
+
+See [Authentication & Identity](#authentication--identity) for how to authenticate with private repositories.
+
+
+```js JavaScript & TypeScript
+const repoUrl = 'https://git.example.com/org/repo.git'
+const repoPath = '/home/user/repo'
+
+// Default clone
+await sandbox.git.clone(repoUrl, { path: repoPath })
+
+// Clone a specific branch
+await sandbox.git.clone(repoUrl, { path: repoPath, branch: 'main' })
+
+// Shallow clone
+await sandbox.git.clone(repoUrl, { path: repoPath, depth: 1 })
+```
+```python Python
+repo_url = "https://git.example.com/org/repo.git"
+repo_path = "/home/user/repo"
+
+# Default clone
+sandbox.git.clone(repo_url, path=repo_path)
+
+# Clone a specific branch
+sandbox.git.clone(repo_url, path=repo_path, branch="main")
+
+# Shallow clone
+sandbox.git.clone(repo_url, path=repo_path, depth=1)
+```
+
+
+### Check status and branches
+
+`status()` returns a structured object with branch, ahead/behind, and file status details. `branches()` returns the branch list and the current branch.
+
+
+```js JavaScript & TypeScript
+const repoPath = '/home/user/repo'
+
+const status = await sandbox.git.status(repoPath)
+console.log(status.currentBranch, status.ahead, status.behind)
+console.log(status.fileStatus)
+
+const branches = await sandbox.git.branches(repoPath)
+console.log(branches.currentBranch)
+console.log(branches.branches)
+```
+```python Python
+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)
+```
+
+
+### Create and manage branches
+
+
+```js JavaScript & TypeScript
+const repoPath = '/home/user/repo'
+
+// Create and switch to a new branch
+await sandbox.git.createBranch(repoPath, 'feature/new-docs')
+
+// Check out an existing branch
+await sandbox.git.checkoutBranch(repoPath, 'main')
+
+// Delete a branch
+await sandbox.git.deleteBranch(repoPath, 'feature/old-docs')
+
+// Force delete a branch
+await sandbox.git.deleteBranch(repoPath, 'feature/stale-docs', { force: true })
+```
+```python Python
+repo_path = "/home/user/repo"
+
+# Create and switch to a new branch
+sandbox.git.create_branch(repo_path, "feature/new-docs")
+
+# Check out an existing branch
+sandbox.git.checkout_branch(repo_path, "main")
+
+# Delete a branch
+sandbox.git.delete_branch(repo_path, "feature/old-docs")
+
+# Force delete a branch
+sandbox.git.delete_branch(repo_path, "feature/stale-docs", force=True)
+```
+
+
+### Stage and commit
+
+
+```js JavaScript & TypeScript
+const repoPath = '/home/user/repo'
+
+// Default: stage all changes, commit with repo config
+await sandbox.git.add(repoPath)
+await sandbox.git.commit(repoPath, 'Initial commit')
+
+// Stage specific files
+await sandbox.git.add(repoPath, { files: ['README.md', 'src/index.ts'] })
+
+// Allow empty commit and override author
+await sandbox.git.commit(repoPath, 'Docs sync', {
+ authorName: 'E2B Bot',
+ authorEmail: 'bot@example.com',
+ allowEmpty: true,
+})
+```
+```python Python
+repo_path = "/home/user/repo"
+
+# Default: stage all changes, commit with repo config
+sandbox.git.add(repo_path)
+sandbox.git.commit(repo_path, "Initial commit")
+
+# Stage specific files
+sandbox.git.add(repo_path, files=["README.md", "src/index.ts"])
+
+# Allow empty commit and override author
+sandbox.git.commit(
+ repo_path,
+ "Docs sync",
+ author_name="E2B Bot",
+ author_email="bot@example.com",
+ allow_empty=True,
+)
+```
+
+
+### Pull and push
+
+See [Authentication & Identity](#authentication--identity) for how to authenticate with private repositories.
+
+
+```js JavaScript & TypeScript
+const repoPath = '/home/user/repo'
+
+// Default (uses upstream when set)
+await sandbox.git.push(repoPath)
+await sandbox.git.pull(repoPath)
+
+// Target a specific remote/branch and set upstream
+await sandbox.git.push(repoPath, {
+ remote: 'origin',
+ branch: 'main',
+ setUpstream: true,
+})
+
+await sandbox.git.pull(repoPath, {
+ remote: 'origin',
+ branch: 'main',
+})
+```
+```python Python
+repo_path = "/home/user/repo"
+
+# Default (uses upstream when set)
+sandbox.git.push(repo_path)
+sandbox.git.pull(repo_path)
+
+# Target a specific remote/branch and set upstream
+sandbox.git.push(
+ repo_path,
+ remote="origin",
+ branch="main",
+ set_upstream=True,
+)
+
+sandbox.git.pull(
+ repo_path,
+ remote="origin",
+ branch="main",
+)
+```
+
+
+### Manage remotes
+
+
+```js JavaScript & TypeScript
+const repoPath = '/home/user/repo'
+const repoUrl = 'https://git.example.com/org/repo.git'
+
+// Default
+await sandbox.git.remoteAdd(repoPath, 'origin', repoUrl)
+
+// Fetch after adding the remote
+await sandbox.git.remoteAdd(repoPath, 'origin', repoUrl, { fetch: true })
+
+// Overwrite the remote URL if it already exists
+await sandbox.git.remoteAdd(repoPath, 'origin', repoUrl, { overwrite: true })
+```
+```python Python
+repo_path = "/home/user/repo"
+repo_url = "https://git.example.com/org/repo.git"
+
+# Default
+sandbox.git.remote_add(repo_path, "origin", repo_url)
+
+# Fetch after adding the remote
+sandbox.git.remote_add(repo_path, "origin", repo_url, fetch=True)
+
+# Overwrite the remote URL if it already exists
+sandbox.git.remote_add(repo_path, "origin", repo_url, overwrite=True)
+```
+
+
+### Git config
+
+Set and get git configuration values. See [Configure git identity](#configure-git-identity) for configuring the commit author.
+
+
+```js JavaScript & TypeScript
+const repoPath = '/home/user/repo'
+
+// Global config
+await sandbox.git.setConfig('pull.rebase', 'false')
+const rebase = await sandbox.git.getConfig('pull.rebase')
+
+// Repo-local config
+await sandbox.git.setConfig('pull.rebase', 'false', { scope: 'local', path: repoPath })
+const localRebase = await sandbox.git.getConfig('pull.rebase', { scope: 'local', path: repoPath })
+```
+```python Python
+repo_path = "/home/user/repo"
+
+# Global config
+sandbox.git.set_config("pull.rebase", "false")
+rebase = sandbox.git.get_config("pull.rebase")
+
+# Repo-local config
+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)
+```
+