Skip to content
Kward Search API index

Class: Kward::GitWorktreeManager

Inherits:
Object
  • Object
show all
Defined in:
lib/kward/git_worktree_manager.rb

Overview

Performs safe, structured operations on linked Git worktrees.

Defined Under Namespace

Classes: Error, GitStatus, MergeResult, WorktreeInfo

Instance Method Summary collapse

Instance Method Details

#abort_merge(path) ⇒ Object

Raises:



136
137
138
139
140
141
# File 'lib/kward/git_worktree_manager.rb', line 136

def abort_merge(path)
  raise Error, "No merge is in progress." unless merge_in_progress?(path)

  run_git(path, "merge", "--abort")
  true
end

#create(repository_root:, origin_root:, path:, branch:, base: "HEAD") ⇒ Object



143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/kward/git_worktree_manager.rb', line 143

def create(repository_root:, origin_root:, path:, branch:, base: "HEAD")
  repository_root = canonical_existing_path(repository_root)
  origin_root = canonical_existing_path(origin_root)
  path = planned_path(path)
  branch = branch.to_s.strip
  base = base.to_s.strip
  validate_creation!(repository_root, origin_root, path, branch, base)

  run_git(repository_root, "worktree", "add", "-b", branch, path, base)
  GitWorktreeBinding.new(
    repository_root: repository_root,
    origin_root: origin_root,
    path: path,
    branch: branch,
    base_revision: revision_for(repository_root, base),
    active: true,
    owned: true
  )
end

#current_branch(path) ⇒ Object



108
109
110
# File 'lib/kward/git_worktree_manager.rb', line 108

def current_branch(path)
  run_git(path, "branch", "--show-current").strip
end

#current_revision(path) ⇒ Object



104
105
106
# File 'lib/kward/git_worktree_manager.rb', line 104

def current_revision(path)
  run_git(path, "rev-parse", "HEAD").strip
end

#inspect(repository_root:, path:) ⇒ Object

Raises:



163
164
165
166
167
168
169
170
# File 'lib/kward/git_worktree_manager.rb', line 163

def inspect(repository_root:, path:)
  repository_root = canonical_existing_path(repository_root)
  expected_path = planned_path(path)
  worktree = list(repository_root).find { |entry| same_path?(entry.path, expected_path) }
  raise Error, "Git worktree is not registered: #{expected_path}" unless worktree

  worktree
end

#list(repository_root) ⇒ Object



172
173
174
175
# File 'lib/kward/git_worktree_manager.rb', line 172

def list(repository_root)
  output = run_git(repository_root, "worktree", "list", "--porcelain")
  parse_worktree_list(output)
end

#merge(repository_root:, target_path:, source_branch:) ⇒ Object

Raises:



112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/kward/git_worktree_manager.rb', line 112

def merge(repository_root:, target_path:, source_branch:)
  repository_root = canonical_existing_path(repository_root)
  target_path = canonical_existing_path(target_path)
  source_branch = source_branch.to_s.strip
  validate_merge!(repository_root, target_path, source_branch)

  output, status = capture_git(target_path, "merge", "--no-edit", source_branch)
  return MergeResult.new(status: :merged, output: output, conflicts: []) if status.success?

  conflicts = unmerged_paths(target_path)
  return MergeResult.new(status: :conflicted, output: output, conflicts: conflicts) if merge_in_progress?(target_path)

  raise Error, git_error("merge", output)
end

#merge_in_progress?(path) ⇒ Boolean

Returns:

  • (Boolean)


127
128
129
130
# File 'lib/kward/git_worktree_manager.rb', line 127

def merge_in_progress?(path)
  _output, status = capture_git(path, "rev-parse", "-q", "--verify", "MERGE_HEAD")
  status.success?
end

#remove(repository_root:, path:, force: false) ⇒ Object



177
178
179
180
181
182
183
184
185
186
# File 'lib/kward/git_worktree_manager.rb', line 177

def remove(repository_root:, path:, force: false)
  repository_root = canonical_existing_path(repository_root)
  expected_path = planned_path(path)
  inspect(repository_root: repository_root, path: expected_path)
  arguments = ["worktree", "remove"]
  arguments << "--force" if force
  arguments << expected_path
  run_git(repository_root, *arguments)
  true
end

#repository_root(path) ⇒ Object



92
93
94
95
96
97
# File 'lib/kward/git_worktree_manager.rb', line 92

def repository_root(path)
  output = run_git(path, "rev-parse", "--show-toplevel")
  canonical_existing_path(output.strip)
rescue Error
  raise Error, "Not a Git repository: #{path}"
end

#status(path) ⇒ Object



99
100
101
102
# File 'lib/kward/git_worktree_manager.rb', line 99

def status(path)
  output = run_git(path, "status", "--porcelain=v1", "--untracked-files=all")
  GitStatus.new(entries: output.lines(chomp: true))
end

#unmerged_paths(path) ⇒ Object



132
133
134
# File 'lib/kward/git_worktree_manager.rb', line 132

def unmerged_paths(path)
  run_git(path, "diff", "--name-only", "--diff-filter=U").lines(chomp: true)
end