Git Operations
Daytona provides built-in Git support through the git module in sandboxes.
Basic operations
Section titled “Basic operations”Daytona provides methods to clone, check status, and manage Git repositories in sandboxes.
Git operations assume you are operating in the sandbox user’s home directory (e.g. workspace implies /home/[username]/workspace). Use a leading / when providing absolute paths.
Clone repositories
Section titled “Clone repositories”Clone a Git repository into a sandbox by providing the URL and path to clone it to. You can clone public or private repositories, specific branches or commits, and authenticate using personal access tokens.
# Basic clonesandbox.git.clone( url="https://github.com/user/repo.git", path="workspace/repo")
# Clone with authenticationsandbox.git.clone( url="https://github.com/user/repo.git", path="workspace/repo", username="git", password="personal_access_token")
# Clone specific branchsandbox.git.clone( url="https://github.com/user/repo.git", path="workspace/repo", branch="develop")
# Clone a specific commit (detached HEAD)sandbox.git.clone( url="https://github.com/user/repo.git", path="workspace/repo-old", commit_id="abc123def456")
# Clone from a self-signed internal Git server (insecure)sandbox.git.clone( url="https://internal-git.example.com/org/repo.git", path="workspace/repo", insecure_skip_tls=True)// Basic cloneawait sandbox.git.clone( "https://github.com/user/repo.git", "workspace/repo");
// Clone with authenticationawait sandbox.git.clone( "https://github.com/user/repo.git", "workspace/repo", undefined, undefined, "git", "personal_access_token");
// Clone specific branchawait sandbox.git.clone( "https://github.com/user/repo.git", "workspace/repo", "develop");
// Clone a specific commit (detached HEAD)await sandbox.git.clone( "https://github.com/user/repo.git", "workspace/repo-old", undefined, "abc123def456");
// Clone from a self-signed internal Git server (insecure)await sandbox.git.clone( "https://internal-git.example.com/org/repo.git", "workspace/repo", undefined, undefined, undefined, undefined, true);# Basic clonesandbox.git.clone( url: 'https://github.com/user/repo.git', path: 'workspace/repo')
# Clone with authenticationsandbox.git.clone( url: 'https://github.com/user/repo.git', path: 'workspace/repo', username: 'git', password: 'personal_access_token')
# Clone specific branchsandbox.git.clone( url: 'https://github.com/user/repo.git', path: 'workspace/repo', branch: 'develop')
# Clone a specific commit (detached HEAD)sandbox.git.clone( url: 'https://github.com/user/repo.git', path: 'workspace/repo-old', commit_id: 'abc123def456')
# Clone from a self-signed internal Git server (insecure)sandbox.git.clone( url: 'https://internal-git.example.com/org/repo.git', path: 'workspace/repo', insecure_skip_tls: true)// Basic cloneerr := sandbox.Git.Clone(ctx, "https://github.com/user/repo.git", "workspace/repo")if err != nil { log.Fatal(err)}
// Clone with authenticationerr = sandbox.Git.Clone(ctx, "https://github.com/user/repo.git", "workspace/repo", options.WithUsername("git"), options.WithPassword("personal_access_token"),)if err != nil { log.Fatal(err)}
// Clone specific brancherr = sandbox.Git.Clone(ctx, "https://github.com/user/repo.git", "workspace/repo", options.WithBranch("develop"),)if err != nil { log.Fatal(err)}
// Clone a specific commit (detached HEAD)err = sandbox.Git.Clone(ctx, "https://github.com/user/repo.git", "workspace/repo-old", options.WithCommitId("abc123def456"),)if err != nil { log.Fatal(err)}
// Clone from a self-signed internal Git server (insecure)err = sandbox.Git.Clone(ctx, "https://internal-git.example.com/org/repo.git", "workspace/repo", options.WithInsecureSkipTLS(true),)if err != nil { log.Fatal(err)}// Basic clonesandbox.git.clone("https://github.com/user/repo.git", "workspace/repo");
// Clone with authenticationsandbox.git.clone( "https://github.com/user/repo.git", "workspace/repo", null, null, "git", "personal_access_token");
// Clone specific branchsandbox.git.clone( "https://github.com/user/repo.git", "workspace/repo", "develop", null, null, null);
// Clone a specific commit (detached HEAD)sandbox.git.clone( "https://github.com/user/repo.git", "workspace/repo-old", null, "abc123def456", null, null);
// Clone from a self-signed internal Git server (insecure)sandbox.git.clone( "https://internal-git.example.com/org/repo.git", "workspace/repo", null, null, null, null, true);curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/git/clone' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "branch": "", "commit_id": "", "depth": 0, "insecure_skip_tls": false, "password": "", "path": "", "url": "", "username": ""}'Get repository status
Section titled “Get repository status”Get the status of a Git repository by providing the path to the repository.
You can get the current branch, modified files, and the number of commits ahead and behind the upstream tracking branch. When no upstream is configured, ahead and behind are zero and branch_published is false. The response also includes upstream (for example origin/main) and detached when HEAD is not on a branch.
# Get repository statusstatus = sandbox.git.status("workspace/repo")print(f"Current branch: {status.current_branch}")print(f"Upstream: {status.upstream}")print(f"Detached HEAD: {status.detached}")print(f"Commits ahead: {status.ahead}")print(f"Commits behind: {status.behind}")for file in status.file_status: print(f"File: {file.name}")
# List branchesresponse = sandbox.git.branches("workspace/repo")print(f"Checked out branch: {response.current}")for branch in response.branches: print(f"Branch: {branch}")// Get repository statusconst status = await sandbox.git.status("workspace/repo");console.log(`Current branch: ${status.currentBranch}`);console.log(`Upstream: ${status.upstream}`);console.log(`Detached HEAD: ${status.detached}`);console.log(`Commits ahead: ${status.ahead}`);console.log(`Commits behind: ${status.behind}`);status.fileStatus.forEach(file => { console.log(`File: ${file.name}`);});
// List branchesconst response = await sandbox.git.branches("workspace/repo");console.log(`Checked out branch: ${response.current}`);response.branches.forEach(branch => { console.log(`Branch: ${branch}`);});# Get repository statusstatus = sandbox.git.status('workspace/repo')puts "Current branch: #{status.current_branch}"puts "Upstream: #{status.upstream}"puts "Detached HEAD: #{status.detached}"puts "Commits ahead: #{status.ahead}"puts "Commits behind: #{status.behind}"status.file_status.each do |file| puts "File: #{file.name}"end
# List branchesresponse = sandbox.git.branches('workspace/repo')puts "Checked out branch: #{response.current}"response.branches.each do |branch| puts "Branch: #{branch}"end// Get repository statusstatus, err := sandbox.Git.Status(ctx, "workspace/repo")if err != nil { log.Fatal(err)}fmt.Printf("Current branch: %s\n", status.CurrentBranch)fmt.Printf("Commits ahead: %d\n", status.Ahead)fmt.Printf("Commits behind: %d\n", status.Behind)for _, file := range status.FileStatus { fmt.Printf("File: %s\n", file.Path)}
// List branchesbranches, err := sandbox.Git.Branches(ctx, "workspace/repo")if err != nil { log.Fatal(err)}for _, branch := range branches { fmt.Printf("Branch: %s\n", branch)}import io.daytona.sdk.model.GitStatus;import java.util.List;
// Get repository statusGitStatus status = sandbox.git.status("workspace/repo");System.out.println("Current branch: " + status.getCurrentBranch());System.out.println("Commits ahead: " + status.getAhead());System.out.println("Commits behind: " + status.getBehind());for (GitStatus.FileStatus file : status.getFileStatus()) { System.out.println("File: " + file.getName());}
// List branchesObject rawBranches = sandbox.git.branches("workspace/repo").get("branches");if (rawBranches instanceof List<?> branchList) { for (Object branch : branchList) { System.out.println("Branch: " + branch); }}# Get repository statuscurl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/git/status?path=workspace/repo'
# List branchescurl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/git/branches?path=workspace/repo'Branch operations
Section titled “Branch operations”Daytona provides methods to manage branches in Git repositories. You can create, switch, and delete branches. Checkout accepts a branch name or a commit SHA.
Create branches
Section titled “Create branches”Create a new branch by providing the path to the repository and the name of the new branch.
# Create a new branchsandbox.git.create_branch("workspace/repo", "new-feature")// Create new branchawait sandbox.git.createBranch('workspace/repo', 'new-feature');# Create a new branchsandbox.git.create_branch('workspace/repo', 'new-feature')// Create a new brancherr := sandbox.Git.CreateBranch(ctx, "workspace/repo", "new-feature")if err != nil { log.Fatal(err)}curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/git/branches' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "name": "", "path": ""}'Checkout branches or commits
Section titled “Checkout branches or commits”Checkout a branch or commit by providing the path to the repository and the name of the branch or commit SHA. Pass a commit SHA to enter detached HEAD state.
# Checkout a branchsandbox.git.checkout_branch("workspace/repo", "feature-branch")
# Checkout a commit (detached HEAD)sandbox.git.checkout_branch("workspace/repo", "abc123def456")// Checkout a branchawait sandbox.git.checkoutBranch('workspace/repo', 'feature-branch');
// Checkout a commit (detached HEAD)await sandbox.git.checkoutBranch('workspace/repo', 'abc123def456');# Checkout a branchsandbox.git.checkout_branch('workspace/repo', 'feature-branch')
# Checkout a commit (detached HEAD)sandbox.git.checkout_branch('workspace/repo', 'abc123def456')// Checkout a brancherr := sandbox.Git.Checkout(ctx, "workspace/repo", "feature-branch")if err != nil { log.Fatal(err)}
// Checkout a commit (detached HEAD)err = sandbox.Git.Checkout(ctx, "workspace/repo", "abc123def456")if err != nil { log.Fatal(err)}curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/git/checkout' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "branch": "", "path": ""}'Delete branches
Section titled “Delete branches”Delete a branch by providing the path to the repository and the name of the branch.
# Delete a branchsandbox.git.delete_branch("workspace/repo", "old-feature")// Delete a branchawait sandbox.git.deleteBranch('workspace/repo', 'old-feature');# Delete a branchsandbox.git.delete_branch('workspace/repo', 'old-feature')// Delete a brancherr := sandbox.Git.DeleteBranch(ctx, "workspace/repo", "old-feature")if err != nil { log.Fatal(err)}
// Force delete an unmerged brancherr = sandbox.Git.DeleteBranch(ctx, "workspace/repo", "old-feature", options.WithForce(true),)if err != nil { log.Fatal(err)}curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/git/branches' \ --request DELETE \ --header 'Content-Type: application/json' \ --data '{ "name": "", "path": ""}'Stage changes
Section titled “Stage changes”Stage specific files, all changes, or the whole repository by providing the path to the repository and the files to stage.
# Stage a single filesandbox.git.add("workspace/repo", ["file.txt"])
# Stage multiple filessandbox.git.add("workspace/repo", [ "src/main.py", "tests/test_main.py", "README.md"])// Stage a single fileawait sandbox.git.add('workspace/repo', ['file.txt']);
// Stage multiple filesawait sandbox.git.add('workspace/repo', [ 'src/main.ts', 'tests/main.test.ts', 'README.md',]);
// Stage whole repositoryawait sandbox.git.add('workspace/repo', ['.']);# Stage a single filesandbox.git.add('workspace/repo', ['file.txt'])// Stage a single fileerr := sandbox.Git.Add(ctx, "workspace/repo", []string{"file.txt"})if err != nil { log.Fatal(err)}
// Stage multiple fileserr = sandbox.Git.Add(ctx, "workspace/repo", []string{ "src/main.py", "tests/test_main.py", "README.md",})if err != nil { log.Fatal(err)}
// Stage whole repositoryerr = sandbox.Git.Add(ctx, "workspace/repo", []string{"."})if err != nil { log.Fatal(err)}import java.util.List;
// Stage a single filesandbox.git.add("workspace/repo", List.of("file.txt"));
// Stage multiple filessandbox.git.add( "workspace/repo", List.of("src/main.py", "tests/test_main.py", "README.md"));
// Stage whole repositorysandbox.git.add("workspace/repo", List.of("."));curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/git/add' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "files": [ "" ], "path": ""}'Commit changes
Section titled “Commit changes”Commit changes by providing the path to the repository, the message, author, and email.
# Stage and commit changessandbox.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)// Stage and commit changesawait sandbox.git.add('workspace/repo', ['README.md']);await sandbox.git.commit( 'workspace/repo', 'Update documentation', 'John Doe', 'john@example.com', true);# Stage and commit changessandbox.git.add('workspace/repo', ['README.md'])sandbox.git.commit('workspace/repo', 'Update documentation', 'John Doe', 'john@example.com', true)// Stage and commit changeserr := sandbox.Git.Add(ctx, "workspace/repo", []string{"README.md"})if err != nil { log.Fatal(err)}
response, err := sandbox.Git.Commit(ctx, "workspace/repo", "Update documentation", "John Doe", "john@example.com", options.WithAllowEmpty(true),)if err != nil { log.Fatal(err)}fmt.Printf("Commit SHA: %s\n", response.SHA)import io.daytona.sdk.model.GitCommitResponse;import java.util.List;
// Stage and commit changessandbox.git.add("workspace/repo", List.of("README.md"));GitCommitResponse response = sandbox.git.commit( "workspace/repo", "Update documentation", "John Doe", "john@example.com");System.out.println("Commit hash: " + response.getHash());curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/git/commit' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "allow_empty": true, "author": "", "email": "", "message": "", "path": ""}'Remote operations
Section titled “Remote operations”Daytona provides methods to work with remote repositories in Git. You can push and pull changes from remote repositories.
Push changes
Section titled “Push changes”Push changes to a remote repository by providing the path to the repository and the username and password to authenticate.
# Push without authentication (for public repos or SSH)sandbox.git.push("workspace/repo")
# Push with authenticationsandbox.git.push( path="workspace/repo", username="user", password="github_token")// Push to a public repositoryawait sandbox.git.push('workspace/repo');
// Push to a private repositoryawait sandbox.git.push( 'workspace/repo', 'user', 'token');# Push without authentication (for public repos or SSH)sandbox.git.push('workspace/repo')
# Push with authenticationsandbox.git.push( path: 'workspace/repo', username: 'user', password: 'github_token')// Push without authentication (for public repos or SSH)err := sandbox.Git.Push(ctx, "workspace/repo")if err != nil { log.Fatal(err)}
// Push with authenticationerr = sandbox.Git.Push(ctx, "workspace/repo", options.WithPushUsername("user"), options.WithPushPassword("github_token"),)if err != nil { log.Fatal(err)}// Push without authentication (for public repos or SSH)sandbox.git.push("workspace/repo");curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/git/push' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "password": "", "path": "", "username": ""}'The branch, remote, and set_upstream parameters are available on the toolbox API only.
Pull changes
Section titled “Pull changes”Pull changes from a remote repository by providing the path to the repository and the username and password to authenticate.
# Pull without authenticationsandbox.git.pull("workspace/repo")
# Pull with authenticationsandbox.git.pull( path="workspace/repo", username="user", password="github_token")// Pull from a public repositoryawait sandbox.git.pull('workspace/repo');
// Pull from a private repositoryawait sandbox.git.pull( 'workspace/repo', 'user', 'token');# Pull without authenticationsandbox.git.pull('workspace/repo')
# Pull with authenticationsandbox.git.pull( path: 'workspace/repo', username: 'user', password: 'github_token')// Pull without authenticationerr := sandbox.Git.Pull(ctx, "workspace/repo")if err != nil { log.Fatal(err)}
// Pull with authenticationerr = sandbox.Git.Pull(ctx, "workspace/repo", options.WithPullUsername("user"), options.WithPullPassword("github_token"),)if err != nil { log.Fatal(err)}// Pull without authenticationsandbox.git.pull("workspace/repo");curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/git/pull' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "password": "", "path": "", "username": ""}'The branch and remote parameters are available on the toolbox API only.
Advanced operations
Section titled “Advanced operations”Daytona provides additional Git operations through the Toolbox API.
Initialize a repository
Section titled “Initialize a repository”Initialize a new Git repository by providing the path to the repository and the name of the first branch. Set bare to create a repository without a working tree.
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/git/init' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "bare": false, "initial_branch": "main", "path": "workspace/repo"}'Reset changes
Section titled “Reset changes”Reset the current HEAD to the specified state by providing the path to the repository, the mode and the target revision to reset to. Pass files to constrain the reset to specific paths.
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/git/reset' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "files": [], "mode": "mixed", "path": "workspace/repo", "target": "HEAD~1"}'Restore files
Section titled “Restore files”Restore working tree files or unstage changes by providing the path to the repository, the files to restore, the source revision, and whether to restore from the staged index or working tree.
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/git/restore' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "files": ["src/main.py"], "path": "workspace/repo", "source": "", "staged": false, "worktree": true}'Get commit history
Section titled “Get commit history”Return the commit log for a repository.
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/git/history?path=workspace/repo'Manage remotes
Section titled “Manage remotes”List configured remotes or add (and optionally overwrite) a remote by providing the path to the repository, the name of the remote, the URL of the remote, and whether to fetch from the remote immediately after adding it.
# List remotescurl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/git/remotes?path=workspace/repo'
# Add a remotecurl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/git/remotes' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "fetch": false, "name": "origin", "overwrite": false, "path": "workspace/repo", "url": "https://github.com/user/repo.git"}'Configure Git
Section titled “Configure Git”Read or write Git config values, or set the user name and email at a given scope by providing the path to the repository, the key to get or set, and the value to set.
Scope: global (default), local, or system.
# Get a config valuecurl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/git/config?key=user.name&scope=global'
# Set a config valuecurl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/git/config' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "key": "core.editor", "path": "", "scope": "global", "value": "vim"}'
# Configure user name and emailcurl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/git/config/user' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "email": "john@example.com", "name": "John Doe", "path": "", "scope": "global"}'Authenticate credentials
Section titled “Authenticate credentials”Persist Git credentials globally via the credential store by providing the host, protocol, username, and password. Credentials are stored in plaintext on disk.
curl 'https://proxy.app.daytona.io/toolbox/{sandboxId}/git/credentials' \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "host": "github.com", "password": "personal_access_token", "protocol": "https", "username": "git"}'