Class: Daytona::Git

Inherits:
Object
  • Object
show all
Includes:
Instrumentation
Defined in:
lib/daytona/git.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Instrumentation

included

Constructor Details

#initialize(sandbox_id:, toolbox_api:, otel_state: nil) ⇒ Git

Initializes a new Git handler instance.

Parameters:

  • sandbox_id (String)

    The Sandbox ID.

  • toolbox_api (DaytonaToolboxApiClient::GitApi)

    API client for Sandbox operations.

  • otel_state (Daytona::OtelState, nil) (defaults to: nil)


21
22
23
24
25
# File 'lib/daytona/git.rb', line 21

def initialize(sandbox_id:, toolbox_api:, otel_state: nil)
  @sandbox_id = sandbox_id
  @toolbox_api = toolbox_api
  @otel_state = otel_state
end

Instance Attribute Details

#sandbox_idString (readonly)

Returns The Sandbox ID.

Returns:

  • (String)

    The Sandbox ID



11
12
13
# File 'lib/daytona/git.rb', line 11

def sandbox_id
  @sandbox_id
end

#toolbox_apiDaytonaToolboxApiClient::GitApi (readonly)

Returns API client for Sandbox operations.

Returns:

  • (DaytonaToolboxApiClient::GitApi)

    API client for Sandbox operations



14
15
16
# File 'lib/daytona/git.rb', line 14

def toolbox_api
  @toolbox_api
end

Instance Method Details

#add(path, files) ⇒ void

This method returns an undefined value.

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

Examples:

# Stage a single file
sandbox.git.add("workspace/repo", ["file.txt"])

# Stage multiple files
sandbox.git.add("workspace/repo", [
  "src/main.rb",
  "spec/main_spec.rb",
  "README.md"
])

Parameters:

  • path (String)

    Path to the Git repository root. Relative paths are resolved based on the sandbox working directory.

  • files (Array<String>)

    List of file paths or directories to stage, relative to the repository root.

Raises:



46
47
48
49
50
51
52
# File 'lib/daytona/git.rb', line 46

def add(path, files)
  toolbox_api.add_files(DaytonaToolboxApiClient::GitAddRequest.new(path:, files:))
rescue DaytonaToolboxApiClient::ApiError => e
  raise map_api_error(e, 'Failed to add files')
rescue StandardError => e
  raise Sdk::Error, "Failed to add files: #{e.message}"
end

#branches(path) ⇒ DaytonaApiClient::ListBranchResponse

Lists branches in the repository.

Examples:

response = sandbox.git.branches("workspace/repo")
puts "Branches: #{response.branches}"

Parameters:

  • path (String)

    Path to the Git repository root. Relative paths are resolved based on the sandbox working directory.

Returns:

  • (DaytonaApiClient::ListBranchResponse)

    List of branches in the repository.

Raises:



64
65
66
67
68
69
70
# File 'lib/daytona/git.rb', line 64

def branches(path)
  toolbox_api.list_branches(path)
rescue DaytonaToolboxApiClient::ApiError => e
  raise map_api_error(e, 'Failed to list branches')
rescue StandardError => e
  raise Sdk::Error, "Failed to list branches: #{e.message}"
end

#checkout_branch(path, branch) ⇒ void

This method returns an undefined value.

Checkout branch in the repository.

Examples:

# Checkout a branch
sandbox.git.checkout_branch("workspace/repo", "feature-branch")

Parameters:

  • path (String)

    Path to the Git repository root. Relative paths are resolved based on the sandbox working directory.

  • branch (String)

    Name of the branch to checkout

Raises:



270
271
272
273
274
275
276
277
278
# File 'lib/daytona/git.rb', line 270

def checkout_branch(path, branch)
  toolbox_api.checkout_branch(
    DaytonaToolboxApiClient::GitCheckoutRequest.new(path:, branch:)
  )
rescue DaytonaToolboxApiClient::ApiError => e
  raise map_api_error(e, 'Failed to checkout branch')
rescue StandardError => e
  raise Sdk::Error, "Failed to checkout branch: #{e.message}"
end

#clone(url:, path:, branch: nil, commit_id: nil, username: nil, password: nil, insecure_skip_tls: nil, depth: nil) ⇒ void

This method returns an undefined value.

Clones a Git repository into the specified path. It supports cloning specific branches or commits, and can authenticate with the remote repository if credentials are provided.

Examples:

# 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"
)

Parameters:

  • url (String)

    Repository URL to clone from.

  • path (String)

    Path where the repository should be cloned. Relative paths are resolved based on the sandbox working directory.

  • branch (String, nil) (defaults to: nil)

    Specific branch to clone. If not specified, clones the default branch.

  • commit_id (String, nil) (defaults to: nil)

    Specific commit to clone. If specified, the repository will be left in a detached HEAD state at this commit.

  • username (String, nil) (defaults to: nil)

    Git username for authentication.

  • password (String, nil) (defaults to: nil)

    Git password or token for authentication.

  • insecure_skip_tls (Boolean, nil) (defaults to: nil)

    Skip TLS certificate verification (insecure). Use only for trusted internal Git servers with self-signed or private-CA certs; credentials, if supplied, are transmitted over an unverified TLS connection.

  • depth (Integer, nil) (defaults to: nil)

    Create a shallow clone truncated to the given number of commits.

Raises:



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/daytona/git.rb', line 114

def clone(url:, path:, branch: nil, commit_id: nil, username: nil, password: nil, insecure_skip_tls: nil, depth: nil) # rubocop:disable Metrics/MethodLength, Metrics/ParameterLists, Layout/LineLength
  toolbox_api.clone_repository(
    DaytonaToolboxApiClient::GitCloneRequest.new(
      url: url,
      branch: branch,
      path: path,
      username: username,
      password: password,
      commit_id: commit_id,
      insecure_skip_tls: insecure_skip_tls,
      depth: depth
    )
  )
rescue DaytonaToolboxApiClient::ApiError => e
  raise map_api_error(e, 'Failed to clone repository')
rescue StandardError => e
  raise Sdk::Error, "Failed to clone repository: #{e.message}"
end

#commit(path:, message:, author:, email:, allow_empty: false) ⇒ GitCommitResponse

Creates a new commit with the staged changes. Make sure to stage changes using the add() method before committing.

Examples:

# Stage and commit changes
sandbox.git.add("workspace/repo", ["README.md"])
commit_response = sandbox.git.commit(
  path: "workspace/repo",
  message: "Update documentation",
  author: "John Doe",
  email: "john@example.com",
  allow_empty: true
)
puts "Commit SHA: #{commit_response.sha}"

Parameters:

  • path (String)

    Path to the Git repository root. Relative paths are resolved based on the sandbox working directory.

  • message (String)

    Commit message describing the changes.

  • author (String)

    Name of the commit author.

  • email (String)

    Email address of the commit author.

  • allow_empty (Boolean) (defaults to: false)

    Allow creating an empty commit when no changes are staged. Defaults to false.

Returns:

Raises:



156
157
158
159
160
161
162
163
164
165
# File 'lib/daytona/git.rb', line 156

def commit(path:, message:, author:, email:, allow_empty: false)
  response = toolbox_api.commit_changes(
    DaytonaToolboxApiClient::GitCommitRequest.new(path:, message:, author:, email:, allow_empty:)
  )
  GitCommitResponse.new(sha: response._hash)
rescue DaytonaToolboxApiClient::ApiError => e
  raise map_api_error(e, 'Failed to commit changes')
rescue StandardError => e
  raise Sdk::Error, "Failed to commit changes: #{e.message}"
end

#configure_user(name, email, scope: 'global', path: nil) ⇒ void

This method returns an undefined value.

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

Examples:

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

Parameters:

  • name (String)

    User name (user.name).

  • email (String)

    User email (user.email).

  • scope (String) (defaults to: 'global')

    Config scope, one of "global" (default), "local" or "system".

  • path (String, nil) (defaults to: nil)

    Repository path, required when scope is "local".

Raises:



501
502
503
504
505
506
507
508
509
# File 'lib/daytona/git.rb', line 501

def configure_user(name, email, scope: 'global', path: nil)
  toolbox_api.configure_user(
    DaytonaToolboxApiClient::GitConfigureUserRequest.new(name:, email:, scope:, path:)
  )
rescue DaytonaToolboxApiClient::ApiError => e
  raise map_api_error(e, 'Failed to configure user')
rescue StandardError => e
  raise Sdk::Error, "Failed to configure user: #{e.message}"
end

#create_branch(path, name) ⇒ void

This method returns an undefined value.

Create branch in the repository.

Examples:

# Create a new branch
sandbox.git.create_branch("workspace/repo", "new-feature")

Parameters:

  • path (String)

    Path to the Git repository root. Relative paths are resolved based on the sandbox working directory.

  • name (String)

    Name of the new branch to create

Raises:



292
293
294
295
296
297
298
299
300
# File 'lib/daytona/git.rb', line 292

def create_branch(path, name)
  toolbox_api.create_branch(
    DaytonaToolboxApiClient::GitBranchRequest.new(path:, name:)
  )
rescue DaytonaToolboxApiClient::ApiError => e
  raise map_api_error(e, 'Failed to create branch')
rescue StandardError => e
  raise Sdk::Error, "Failed to create branch: #{e.message}"
end

#dangerously_authenticate(username, password, host: nil, protocol: nil) ⇒ void

This method returns an undefined value.

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

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

Examples:

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

Parameters:

  • username (String)

    Git username.

  • password (String)

    Git password or token.

  • host (String, nil) (defaults to: nil)

    Host to authenticate against. Defaults to "github.com".

  • protocol (String, nil) (defaults to: nil)

    Protocol to authenticate against. Defaults to "https".

Raises:



525
526
527
528
529
530
531
532
533
# File 'lib/daytona/git.rb', line 525

def dangerously_authenticate(username, password, host: nil, protocol: nil)
  toolbox_api.authenticate(
    DaytonaToolboxApiClient::GitAuthenticateRequest.new(username:, password:, host:, protocol:)
  )
rescue DaytonaToolboxApiClient::ApiError => e
  raise map_api_error(e, 'Failed to authenticate')
rescue StandardError => e
  raise Sdk::Error, "Failed to authenticate: #{e.message}"
end

#delete_branch(path, name) ⇒ void

This method returns an undefined value.

Delete branch in the repository.

Examples:

# Delete a branch
sandbox.git.delete_branch("workspace/repo", "old-feature")

Parameters:

  • path (String)

    Path to the Git repository root. Relative paths are resolved based on the sandbox working directory.

  • name (String)

    Name of the branch to delete

Raises:



313
314
315
316
317
318
319
320
321
# File 'lib/daytona/git.rb', line 313

def delete_branch(path, name)
  toolbox_api.delete_branch(
    DaytonaToolboxApiClient::GitDeleteBranchRequest.new(path:, name:)
  )
rescue DaytonaToolboxApiClient::ApiError => e
  raise map_api_error(e, 'Failed to delete branch')
rescue StandardError => e
  raise Sdk::Error, "Failed to delete branch: #{e.message}"
end

#get_config(key, scope: 'global', path: nil) ⇒ String?

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

Examples:

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

Parameters:

  • key (String)

    Config key in dotted form (e.g. "user.name").

  • scope (String) (defaults to: 'global')

    Config scope, one of "global" (default), "local" or "system".

  • path (String, nil) (defaults to: nil)

    Repository path, required when scope is "local".

Returns:

  • (String, nil)

    The config value, or nil when the key is not set.

Raises:



482
483
484
485
486
487
488
# File 'lib/daytona/git.rb', line 482

def get_config(key, scope: 'global', path: nil)
  toolbox_api.get_git_config(key, scope: scope, path: path).value
rescue DaytonaToolboxApiClient::ApiError => e
  raise map_api_error(e, 'Failed to get config')
rescue StandardError => e
  raise Sdk::Error, "Failed to get config: #{e.message}"
end

#init(path, bare: false, initial_branch: nil) ⇒ void

This method returns an undefined value.

Initializes a new Git repository at the specified path.

Examples:

sandbox.git.init("workspace/repo", initial_branch: "main")

Parameters:

  • path (String)

    Path where the repository should be initialized.

  • bare (Boolean) (defaults to: false)

    Create a bare repository without a working tree. Defaults to false.

  • initial_branch (String, nil) (defaults to: nil)

    Name of the initial branch. If not specified, uses the Git default.

Raises:



333
334
335
336
337
338
339
340
341
# File 'lib/daytona/git.rb', line 333

def init(path, bare: false, initial_branch: nil)
  toolbox_api.init_repository(
    DaytonaToolboxApiClient::GitInitRequest.new(path:, bare:, initial_branch:)
  )
rescue DaytonaToolboxApiClient::ApiError => e
  raise map_api_error(e, 'Failed to initialize repository')
rescue StandardError => e
  raise Sdk::Error, "Failed to initialize repository: #{e.message}"
end

#pull(path:, username: nil, password: nil, branch: nil, remote: nil) ⇒ void

This method returns an undefined value.

Pulls changes from the remote repository. If the remote repository requires authentication, provide username and password/token.

Examples:

# 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(path: "workspace/repo", remote: "upstream", branch: "main")

Parameters:

  • path (String)

    Path to the Git repository root. Relative paths are resolved based on the sandbox working directory.

  • username (String, nil) (defaults to: nil)

    Git username for authentication.

  • password (String, nil) (defaults to: nil)

    Git password or token for authentication.

  • branch (String, nil) (defaults to: nil)

    Branch to pull. Defaults to the current branch's upstream.

  • remote (String, nil) (defaults to: nil)

    Remote to pull from. Defaults to "origin".

Raises:



229
230
231
232
233
234
235
236
237
# File 'lib/daytona/git.rb', line 229

def pull(path:, username: nil, password: nil, branch: nil, remote: nil)
  toolbox_api.pull_changes(
    DaytonaToolboxApiClient::GitPullRequest.new(path:, username:, password:, branch:, remote:)
  )
rescue DaytonaToolboxApiClient::ApiError => e
  raise map_api_error(e, 'Failed to pull changes')
rescue StandardError => e
  raise Sdk::Error, "Failed to pull changes: #{e.message}"
end

#push(path:, username: nil, password: nil, branch: nil, remote: nil, set_upstream: false) ⇒ void

This method returns an undefined value.

Pushes all local commits on the current branch to the remote repository. If the remote repository requires authentication, provide username and password/token.

Examples:

# 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(path: "workspace/repo", branch: "feature", set_upstream: true)

Parameters:

  • path (String)

    Path to the Git repository root. Relative paths are resolved based on the sandbox working directory.

  • username (String, nil) (defaults to: nil)

    Git username for authentication.

  • password (String, nil) (defaults to: nil)

    Git password or token for authentication.

  • branch (String, nil) (defaults to: nil)

    Branch to push. Defaults to the current branch.

  • remote (String, nil) (defaults to: nil)

    Remote to push to. Defaults to "origin".

  • set_upstream (Boolean) (defaults to: false)

    Record the pushed branch as the upstream tracking branch. Defaults to false.

Raises:



194
195
196
197
198
199
200
201
202
# File 'lib/daytona/git.rb', line 194

def push(path:, username: nil, password: nil, branch: nil, remote: nil, set_upstream: false) # rubocop:disable Metrics/ParameterLists
  toolbox_api.push_changes(
    DaytonaToolboxApiClient::GitPushRequest.new(path:, username:, password:, branch:, remote:, set_upstream:)
  )
rescue DaytonaToolboxApiClient::ApiError => e
  raise map_api_error(e, 'Failed to push changes')
rescue StandardError => e
  raise Sdk::Error, "Failed to push changes: #{e.message}"
end

#remote_add(path, name, url, fetch: false, overwrite: false) ⇒ void

This method returns an undefined value.

Adds (or overwrites) a remote in the repository.

Examples:

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

Parameters:

  • path (String)

    Path to the Git repository root.

  • name (String)

    Name of the remote.

  • url (String)

    URL of the remote.

  • fetch (Boolean) (defaults to: false)

    Fetch from the remote immediately after adding it. Defaults to false.

  • overwrite (Boolean) (defaults to: false)

    Replace an existing remote with the same name. Defaults to false.

Raises:



407
408
409
410
411
412
413
414
415
# File 'lib/daytona/git.rb', line 407

def remote_add(path, name, url, fetch: false, overwrite: false)
  toolbox_api.add_remote(
    DaytonaToolboxApiClient::GitAddRemoteRequest.new(path:, name:, url:, fetch:, overwrite:)
  )
rescue DaytonaToolboxApiClient::ApiError => e
  raise map_api_error(e, 'Failed to add remote')
rescue StandardError => e
  raise Sdk::Error, "Failed to add remote: #{e.message}"
end

#remote_get(path, name) ⇒ String?

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

Examples:

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

Parameters:

  • path (String)

    Path to the Git repository root.

  • name (String)

    Name of the remote.

Returns:

  • (String, nil)

    The remote URL, or nil when the remote does not exist.

Raises:



443
444
445
446
447
448
449
# File 'lib/daytona/git.rb', line 443

def remote_get(path, name)
  toolbox_api.list_remotes(path).remotes.find { |r| r.name == name }&.url
rescue DaytonaToolboxApiClient::ApiError => e
  raise map_api_error(e, 'Failed to get remote')
rescue StandardError => e
  raise Sdk::Error, "Failed to get remote: #{e.message}"
end

#remotes(path) ⇒ DaytonaToolboxApiClient::ListRemotesResponse

Lists the remotes configured in the repository.

Examples:

response = sandbox.git.remotes("workspace/repo")
response.remotes.each { |r| puts "#{r.name}: #{r.url}" }

Parameters:

  • path (String)

    Path to the Git repository root.

Returns:

  • (DaytonaToolboxApiClient::ListRemotesResponse)

    The configured remotes (name + URL).

Raises:



426
427
428
429
430
431
432
# File 'lib/daytona/git.rb', line 426

def remotes(path)
  toolbox_api.list_remotes(path)
rescue DaytonaToolboxApiClient::ApiError => e
  raise map_api_error(e, 'Failed to list remotes')
rescue StandardError => e
  raise Sdk::Error, "Failed to list remotes: #{e.message}"
end

#reset(path, mode: nil, target: nil, files: nil) ⇒ void

This method returns an undefined value.

Resets the current HEAD to the specified state.

Examples:

# 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")

Parameters:

  • path (String)

    Path to the Git repository root.

  • mode (String, nil) (defaults to: nil)

    Reset mode, one of "soft", "mixed" (default), "hard", "merge" or "keep".

  • target (String, nil) (defaults to: nil)

    Revision to reset to. Defaults to HEAD.

  • files (Array<String>, nil) (defaults to: nil)

    Constrain the reset to the given paths.

Raises:



358
359
360
361
362
363
364
365
366
# File 'lib/daytona/git.rb', line 358

def reset(path, mode: nil, target: nil, files: nil)
  toolbox_api.reset_changes(
    DaytonaToolboxApiClient::GitResetRequest.new(path:, mode:, target:, files:)
  )
rescue DaytonaToolboxApiClient::ApiError => e
  raise map_api_error(e, 'Failed to reset')
rescue StandardError => e
  raise Sdk::Error, "Failed to reset: #{e.message}"
end

#restore(path, files, staged: nil, worktree: nil, source: nil) ⇒ void

This method returns an undefined value.

Restores working tree files or unstages changes.

Examples:

# Discard working tree changes
sandbox.git.restore("workspace/repo", ["file.txt"])

# Unstage changes
sandbox.git.restore("workspace/repo", ["file.txt"], staged: true)

Parameters:

  • path (String)

    Path to the Git repository root.

  • files (Array<String>)

    File paths to restore.

  • staged (Boolean, nil) (defaults to: nil)

    Restore the staging index for the given files.

  • worktree (Boolean, nil) (defaults to: nil)

    Restore the working tree for the given files. Defaults to true when neither staged nor worktree is provided.

  • source (String, nil) (defaults to: nil)

    Restore file contents from the given revision instead of the index.

Raises:



385
386
387
388
389
390
391
392
393
# File 'lib/daytona/git.rb', line 385

def restore(path, files, staged: nil, worktree: nil, source: nil)
  toolbox_api.restore_files(
    DaytonaToolboxApiClient::GitRestoreRequest.new(path:, files:, staged:, worktree:, source:)
  )
rescue DaytonaToolboxApiClient::ApiError => e
  raise map_api_error(e, 'Failed to restore files')
rescue StandardError => e
  raise Sdk::Error, "Failed to restore files: #{e.message}"
end

#set_config(key, value, scope: 'global', path: nil) ⇒ void

This method returns an undefined value.

Sets a Git config value at the given scope.

Examples:

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

Parameters:

  • key (String)

    Config key in dotted form (e.g. "user.name").

  • value (String)

    Config value.

  • scope (String) (defaults to: 'global')

    Config scope, one of "global" (default), "local" or "system".

  • path (String, nil) (defaults to: nil)

    Repository path, required when scope is "local".

Raises:



462
463
464
465
466
467
468
469
470
# File 'lib/daytona/git.rb', line 462

def set_config(key, value, scope: 'global', path: nil)
  toolbox_api.set_git_config(
    DaytonaToolboxApiClient::GitSetConfigRequest.new(key:, value:, scope:, path:)
  )
rescue DaytonaToolboxApiClient::ApiError => e
  raise map_api_error(e, 'Failed to set config')
rescue StandardError => e
  raise Sdk::Error, "Failed to set config: #{e.message}"
end

#status(path) ⇒ DaytonaToolboxApiClient::GitStatus

Gets the current Git repository status.

Examples:

status = sandbox.git.status("workspace/repo")
puts "On branch: #{status.current_branch}"
puts "Commits ahead: #{status.ahead}"
puts "Commits behind: #{status.behind}"

Parameters:

  • path (String)

    Path to the Git repository root. Relative paths are resolved based on the sandbox working directory.

Returns:

  • (DaytonaToolboxApiClient::GitStatus)

    Repository status information including:

Raises:



251
252
253
254
255
256
257
# File 'lib/daytona/git.rb', line 251

def status(path)
  toolbox_api.get_status(path)
rescue DaytonaToolboxApiClient::ApiError => e
  raise map_api_error(e, 'Failed to get status')
rescue StandardError => e
  raise Sdk::Error, "Failed to get status: #{e.message}"
end