Skip to content

Conversation

@matthewlouisbrockman
Copy link
Contributor

@matthewlouisbrockman matthewlouisbrockman commented Jan 27, 2026

Sandbox Git Commands

Adds Git support to the sandbox class. This allows the sandbox to manage git via standard clone, checkout, branch, add, pull, and push commands without needing to use commands.run. The API mirrors common Git workflows while handling sandbox-specific concerns like auth injection and safe remote handling.

Python example

from e2b import Sandbox

sandbox = Sandbox.create()
repo_path = '/home/user/my-repo'

# Optional: set author for commits
sandbox.git.configure_user('Your Name', '[email protected]')

# Clone or init
sandbox.git.clone('https://github.com/org/repo.git', path=repo_path)
# or
sandbox.git.init(repo_path, initial_branch='main')

# Make a change
sandbox.files.write(f'{repo_path}/README.md', '# Hello\n')

# Commit
sandbox.git.add(repo_path, files=['README.md'])
sandbox.git.commit(repo_path, message='Initial commit')

# Branching
sandbox.git.create_branch(repo_path, 'feature1')
# or
sandbox.git.checkout_branch(repo_path, 'main')

# Push
sandbox.git.remote_add(repo_path, 'origin', 'https://github.com/org/repo.git', overwrite=True)
sandbox.git.push(repo_path, remote='origin', branch='main', set_upstream=True)

JavaScript / TypeScript example

import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create()
const repoPath = '/home/user/my-repo'

await sandbox.git.configureUser('Your Name', '[email protected]')

await sandbox.git.clone('https://github.com/org/repo.git', { path: repoPath })
// or
await sandbox.git.init(repoPath, { initialBranch: 'main' })

await sandbox.files.write(`${repoPath}/README.md`, '# Hello\n')

await sandbox.git.add(repoPath, { files: ['README.md'] })
await sandbox.git.commit(repoPath, { message: 'Initial commit' })

await sandbox.git.createBranch(repoPath, 'feature1')
await sandbox.git.checkoutBranch(repoPath, 'main')

await sandbox.git.remoteAdd(repoPath, 'origin', 'https://github.com/org/repo.git', {
  overwrite: true,
})
await sandbox.git.push(repoPath, { remote: 'origin', branch: 'main', setUpstream: true })

Main commands

  • clone: Clone a repo into the sandbox. Supports branch, depth, optional username + password for private repos, and dangerously_store_credentials / dangerouslyStoreCredentials to keep credentials in the remote URL.
  • init: Initialize a new repo. Supports initial_branch / initialBranch and bare.
  • status: Get parsed git status --porcelain -b info.
  • branches: List branches and current branch.
  • create_branch / createBranch: Create and check out a new branch.
  • checkout_branch / checkoutBranch: Switch to an existing branch.
  • delete_branch / deleteBranch: Delete a branch. Supports force.
  • add: Stage files. Supports explicit files or all.
  • commit: Create a commit. Supports author override and allow_empty.
  • reset / reset: Reset HEAD (supports modes like soft, mixed, hard, etc.) and optional paths.
  • restore / restore: Restore files or unstage changes (worktree / staged) from a source ref.
  • pull: Pull from a remote. Supports remote, branch, and optional auth.
  • push: Push to a remote. Supports remote, branch, set_upstream, and optional auth.
  • remote_add / remoteAdd: Add a remote. Supports overwrite and fetch.
  • remote_get / remoteGet: Read a remote URL.
  • set_config / setConfig: Set a git config value. Supports scope (global, local, system), and path for local scope.
  • get_config / getConfig: Read a git config value. Supports the same scope options and returns None / undefined if unset.
  • dangerously_authenticate / dangerouslyAuthenticate: Persist credentials via the git credential helper (global).
  • configure_user / configureUser: Set default user.name and user.email for commits.
  • create_github_repo (Python only): Create a GitHub repo from inside the sandbox and optionally add it as a remote.

Status shape

  • status returns a GitStatus with current_branch / currentBranch, upstream, ahead, behind, detached, and file_status / fileStatus.
  • file_status entries include name, status, index_status / indexStatus, working_tree_status / workingTreeStatus, staged, and optional renamed_from / renamedFrom.
  • Convenience helpers include: is_clean / isClean, has_changes / hasChanges, has_staged / hasStaged, has_untracked / hasUntracked, has_conflicts / hasConflicts, plus counts (total_count / totalCount, staged_count / stagedCount, unstaged_count / unstagedCount, untracked_count / untrackedCount, conflict_count / conflictCount). In Python these are properties on the GitStatus object; in JS they are fields on the returned object.

Notes

  • For private HTTPS remotes, pass username + password (token) on clone, pull, or push.
  • Use remote_add / remoteAdd with overwrite=True to update an existing remote URL and fetch=True to fetch after.
  • Use dangerously_authenticate / dangerouslyAuthenticate only when you want to persist credentials globally on the sandbox.

@changeset-bot
Copy link

changeset-bot bot commented Jan 27, 2026

🦋 Changeset detected

Latest commit: 3f2c972

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@e2b/python-sdk Minor
e2b Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@matthewlouisbrockman matthewlouisbrockman added the feature New feature or request label Jan 27, 2026
@linear
Copy link

linear bot commented Jan 27, 2026

Copy link
Member

@mishushakov mishushakov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think all looking good, here some tips:

  • move some utility functions into utils if they're not dependent on another other private method like runShell or runGitCommand
  • I am still unsure about this.runShell, whether we need a whole separate function only to fill the env variables, think just calling this.commands.run() with the env vars would be enough since there's no other logic... up to you
  • in some places we do buildGitCommand and then runShell, but in most places we do runGitCommand, idk. maybe there's some way to make it more uniform?
  • lets put some tests into the same file, like remote add/get
  • in tests, let's not explicitly specify when we have defaults like all: true and setUpstream: true

@matthewlouisbrockman matthewlouisbrockman merged commit 77b08f5 into main Jan 29, 2026
15 checks passed
@matthewlouisbrockman matthewlouisbrockman deleted the feat/sandbox-first-class-git-support branch January 29, 2026 19:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants