hiiro 0.1.93 → 0.1.94
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CLAUDE.md +25 -9
- data/bin/h-branch +230 -291
- data/bin/h-buffer +136 -121
- data/bin/h-commit +33 -35
- data/bin/h-link +144 -150
- data/bin/h-pane +148 -87
- data/bin/h-plugin +29 -35
- data/bin/h-pr +223 -227
- data/bin/h-project +134 -142
- data/bin/h-session +114 -60
- data/bin/h-sha +10 -13
- data/bin/h-todo +214 -215
- data/bin/h-window +124 -75
- data/bin/h-wtree +13 -14
- data/lib/hiiro/tmux/buffer.rb +63 -0
- data/lib/hiiro/tmux/buffers.rb +58 -0
- data/lib/hiiro/tmux/pane.rb +122 -0
- data/lib/hiiro/tmux/panes.rb +81 -0
- data/lib/hiiro/tmux/session.rb +86 -0
- data/lib/hiiro/tmux/sessions.rb +61 -0
- data/lib/hiiro/tmux/window.rb +94 -0
- data/lib/hiiro/tmux/windows.rb +73 -0
- data/lib/hiiro/tmux.rb +318 -0
- data/lib/hiiro/version.rb +1 -1
- data/lib/hiiro.rb +5 -0
- metadata +11 -3
- data/plugins/tmux.rb +0 -27
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 215c78065501f35e2e1e6534dd08a3adfc9d58b62650bf65be84c32004bcf651
|
|
4
|
+
data.tar.gz: b27dcfdb0aba3dc63d2d102c0d62dc67a4bc8176f304499e49574c7db28ea340
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 361003e1b599d031c386aaad3f4fb476267f336193f89ae113dd9e5d96a3a609385068b29ba41c9d8bd8dd7899aa0ca10dbf639a4a05295cee10e38a011a375b
|
|
7
|
+
data.tar.gz: 1d1aa957c67ff43adc4194397e5e4ff8e789e76792e2a2f758139903bb8f5934856115f122755e0ba92fa87a1f229a5a57d69896b808de77effc511563633cfd
|
data/CLAUDE.md
CHANGED
|
@@ -69,12 +69,14 @@ Plugins auto-load from `~/.config/hiiro/plugins/`. Load order matters when plugi
|
|
|
69
69
|
|
|
70
70
|
### Global Values Pattern
|
|
71
71
|
|
|
72
|
-
Values passed to `Hiiro.
|
|
72
|
+
Values passed to `Hiiro.run()` are available in subcommand handlers:
|
|
73
73
|
|
|
74
74
|
```ruby
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
75
|
+
Hiiro.run(*ARGV, cwd: Dir.pwd) do
|
|
76
|
+
add_subcmd(:pwd) { |*args|
|
|
77
|
+
cwd = get_value(:cwd)
|
|
78
|
+
puts cwd
|
|
79
|
+
}
|
|
78
80
|
end
|
|
79
81
|
```
|
|
80
82
|
|
|
@@ -126,10 +128,10 @@ end
|
|
|
126
128
|
def self.build_hiiro(parent_hiiro, tm)
|
|
127
129
|
bin_name = [parent_hiiro.bin, parent_hiiro.subcmd || ''].join('-')
|
|
128
130
|
|
|
129
|
-
Hiiro.
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
131
|
+
Hiiro.run(bin_name:, args: parent_hiiro.args) do
|
|
132
|
+
add_subcmd(:list) { tm.list }
|
|
133
|
+
add_subcmd(:start) { |name| tm.start_task(name) }
|
|
134
|
+
add_subcmd(:switch) { |name=nil|
|
|
133
135
|
name ||= tm.select_task_interactive
|
|
134
136
|
tm.switch_to_task(tm.task_by_name(name))
|
|
135
137
|
}
|
|
@@ -150,7 +152,7 @@ The `lib/hiiro.rb` file and `lib/hiiro/` directory contain the core framework cl
|
|
|
150
152
|
|
|
151
153
|
Main entry point with class methods:
|
|
152
154
|
- `Hiiro.run(*ARGV, plugins: [...]) { ... }` - Initialize and run immediately
|
|
153
|
-
- `Hiiro.init(*ARGV, plugins: [...]) { ... }` - Initialize without running (returns hiiro instance)
|
|
155
|
+
- `Hiiro.init(*ARGV, plugins: [...]) { ... }` - Initialize without running (returns hiiro instance). **NEVER USE THIS** without a good reason, always favor `Hiiro.run`
|
|
154
156
|
|
|
155
157
|
Instance methods available in subcommand blocks:
|
|
156
158
|
- `git` - Returns `Hiiro::Git` instance for git operations
|
|
@@ -264,3 +266,17 @@ All config lives in `~/.config/hiiro/`:
|
|
|
264
266
|
- `tasks/` - Task metadata for worktree management
|
|
265
267
|
- `projects.yml` - Project directory aliases
|
|
266
268
|
- `apps.yml` - App directory mappings for task plugin
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
# Groups of files
|
|
272
|
+
|
|
273
|
+
## tmux-related files
|
|
274
|
+
|
|
275
|
+
- bin/h-buffer
|
|
276
|
+
- bin/h-pane
|
|
277
|
+
- bin/h-window
|
|
278
|
+
- bin/h-session
|
|
279
|
+
- lib/hiiro/tmux.rb
|
|
280
|
+
- lib/hiiro/tmux/*
|
|
281
|
+
|
|
282
|
+
|
data/bin/h-branch
CHANGED
|
@@ -5,7 +5,6 @@ require "fileutils"
|
|
|
5
5
|
require "yaml"
|
|
6
6
|
|
|
7
7
|
Hiiro.load_env
|
|
8
|
-
hiiro = Hiiro.init(*ARGV, plugins: [Tasks])
|
|
9
8
|
|
|
10
9
|
class BranchManager
|
|
11
10
|
attr_reader :hiiro
|
|
@@ -117,344 +116,284 @@ class BranchManager
|
|
|
117
116
|
end
|
|
118
117
|
end
|
|
119
118
|
|
|
120
|
-
|
|
119
|
+
Hiiro.run(*ARGV, plugins: [Tasks]) do
|
|
120
|
+
manager = BranchManager.new(self)
|
|
121
121
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
hiiro.add_subcmd(:select) do |*args|
|
|
127
|
-
branches = hiiro.git.branches(sort_by: 'authordate', ignore_case: true)
|
|
122
|
+
add_subcmd(:edit) { system(ENV['EDITOR'] || 'nvim', __FILE__) }
|
|
123
|
+
add_subcmd(:save) { manager.save }
|
|
124
|
+
add_subcmd(:current) { print `git branch --show-current` }
|
|
125
|
+
add_subcmd(:info) { manager.current }
|
|
128
126
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
if args.any?
|
|
134
|
-
lines = hash_matches?(lines, *args)
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
require 'open3'
|
|
138
|
-
selected, status = Open3.capture2('sk', '--no-sort', '--tac', stdin_data: lines.keys.join("\n"))
|
|
139
|
-
|
|
140
|
-
if status.success? && !selected.strip.empty?
|
|
141
|
-
puts lines[selected.chomp]
|
|
142
|
-
end
|
|
143
|
-
end
|
|
127
|
+
add_subcmd(:select) do |*select_args|
|
|
128
|
+
branches = git.branches(sort_by: 'authordate', ignore_case: true)
|
|
144
129
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
# Use sk to select a branch
|
|
148
|
-
branches = hiiro.git.branches(sort_by: 'authordate', ignore_case: true)
|
|
149
|
-
require 'open3'
|
|
150
|
-
selected, status = Open3.capture2('sk', '--no-sort', '--tac', stdin_data: branches.join("\n"))
|
|
151
|
-
unless status.success? && !selected.strip.empty?
|
|
152
|
-
puts "No branch selected"
|
|
153
|
-
next
|
|
130
|
+
lines = branches.each_with_object({}) do |name, h|
|
|
131
|
+
h[" #{name}"] = name
|
|
154
132
|
end
|
|
155
|
-
branch = selected.strip
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
system('git', 'checkout', branch, *args)
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
hiiro.add_subcmd(:checkout, &checkout_branch)
|
|
162
|
-
hiiro.add_subcmd(:co, &checkout_branch)
|
|
163
133
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
# Use sk to select a branch
|
|
167
|
-
branches = hiiro.git.branches(sort_by: 'authordate', ignore_case: true)
|
|
168
|
-
require 'open3'
|
|
169
|
-
selected, status = Open3.capture2('sk', '--no-sort', '--tac', stdin_data: branches.join("\n"))
|
|
170
|
-
unless status.success? && !selected.strip.empty?
|
|
171
|
-
puts "No branch selected"
|
|
172
|
-
next
|
|
134
|
+
if select_args.any?
|
|
135
|
+
lines = hash_matches?(lines, *select_args)
|
|
173
136
|
end
|
|
174
|
-
branch = selected.strip
|
|
175
|
-
end
|
|
176
137
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
hiiro.add_subcmd(:remove, &remove_branch)
|
|
181
|
-
hiiro.add_subcmd(:rm, &remove_branch)
|
|
138
|
+
require 'open3'
|
|
139
|
+
selected, status = Open3.capture2('sk', '--no-sort', '--tac', stdin_data: lines.keys.join("\n"))
|
|
182
140
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
puts " Creates a copy of source_branch (or current branch) as new_name"
|
|
187
|
-
next
|
|
141
|
+
if status.success? && !selected.strip.empty?
|
|
142
|
+
puts lines[selected.chomp]
|
|
143
|
+
end
|
|
188
144
|
end
|
|
189
145
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
end
|
|
146
|
+
checkout_branch = lambda { |branch = nil, *checkout_args|
|
|
147
|
+
unless branch
|
|
148
|
+
# Use sk to select a branch
|
|
149
|
+
branches = git.branches(sort_by: 'authordate', ignore_case: true)
|
|
150
|
+
require 'open3'
|
|
151
|
+
selected, status = Open3.capture2('sk', '--no-sort', '--tac', stdin_data: branches.join("\n"))
|
|
152
|
+
unless status.success? && !selected.strip.empty?
|
|
153
|
+
puts "No branch selected"
|
|
154
|
+
next
|
|
155
|
+
end
|
|
156
|
+
branch = selected.strip
|
|
157
|
+
end
|
|
203
158
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
return
|
|
207
|
-
end
|
|
159
|
+
system('git', 'checkout', branch, *checkout_args)
|
|
160
|
+
}
|
|
208
161
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
option :from, short: 'f', desc: 'Local branch or commit to push'
|
|
225
|
-
option :to, short: 't', desc: 'Remote branch name'
|
|
226
|
-
flag :force, short: 'F', desc: 'Force push'
|
|
227
|
-
flag :set_upstream, short: 'u', desc: 'Set upstream tracking'
|
|
228
|
-
end
|
|
162
|
+
add_subcmd(:checkout, &checkout_branch)
|
|
163
|
+
add_subcmd(:co, &checkout_branch)
|
|
164
|
+
|
|
165
|
+
remove_branch = lambda { |branch = nil, *remove_args|
|
|
166
|
+
unless branch
|
|
167
|
+
# Use sk to select a branch
|
|
168
|
+
branches = git.branches(sort_by: 'authordate', ignore_case: true)
|
|
169
|
+
require 'open3'
|
|
170
|
+
selected, status = Open3.capture2('sk', '--no-sort', '--tac', stdin_data: branches.join("\n"))
|
|
171
|
+
unless status.success? && !selected.strip.empty?
|
|
172
|
+
puts "No branch selected"
|
|
173
|
+
next
|
|
174
|
+
end
|
|
175
|
+
branch = selected.strip
|
|
176
|
+
end
|
|
229
177
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
git_args = ['git', 'push']
|
|
234
|
-
git_args << '--force' if opts[:force]
|
|
235
|
-
git_args << '-u' if opts[:set_upstream]
|
|
236
|
-
git_args << opts[:remote]
|
|
237
|
-
git_args << "#{local_ref}:#{remote_branch}"
|
|
238
|
-
|
|
239
|
-
puts "Pushing #{local_ref} to #{opts[:remote]}/#{remote_branch}..."
|
|
240
|
-
system(*git_args)
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
hiiro.add_subcmd(:diff) { |*args|
|
|
244
|
-
case args.length
|
|
245
|
-
when 0
|
|
246
|
-
# Compare current branch to main/master
|
|
247
|
-
base = %w[main master].find { |b| system("git rev-parse --verify #{b} >/dev/null 2>&1") } || 'HEAD~1'
|
|
248
|
-
range = "#{base}..HEAD"
|
|
249
|
-
when 1
|
|
250
|
-
# Compare current branch to specified ref
|
|
251
|
-
range = "#{args[0]}..HEAD"
|
|
252
|
-
else
|
|
253
|
-
# Compare two refs (from..to or from...to based on args)
|
|
254
|
-
from, to = args[0..1]
|
|
255
|
-
range = "#{from}..#{to}"
|
|
256
|
-
end
|
|
178
|
+
system('git', 'branch', '-d', branch, *remove_args)
|
|
179
|
+
}
|
|
257
180
|
|
|
258
|
-
|
|
259
|
-
|
|
181
|
+
add_subcmd(:remove, &remove_branch)
|
|
182
|
+
add_subcmd(:rm, &remove_branch)
|
|
260
183
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
184
|
+
add_subcmd(:duplicate) { |new_name = nil, source = nil|
|
|
185
|
+
unless new_name
|
|
186
|
+
puts "Usage: h branch duplicate <new_name> [source_branch]"
|
|
187
|
+
puts " Creates a copy of source_branch (or current branch) as new_name"
|
|
188
|
+
next
|
|
189
|
+
end
|
|
264
190
|
|
|
265
|
-
|
|
266
|
-
system(
|
|
191
|
+
source ||= git.branch
|
|
192
|
+
system('git', 'branch', new_name, source)
|
|
193
|
+
puts "Created branch '#{new_name}' from '#{source}'"
|
|
267
194
|
}
|
|
268
195
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
196
|
+
add_subcmd(:test) { |*test_args|
|
|
197
|
+
opts = Hiiro::Options.parse(test_args) do
|
|
198
|
+
option :remote, short: 'r', default: 'origin', desc: 'Remote name'
|
|
199
|
+
option :from, short: 'f', desc: 'Local branch or commit to push'
|
|
200
|
+
option :to, short: 't', desc: 'Remote branch name'
|
|
201
|
+
flag :force, short: 'F', desc: 'Force push'
|
|
202
|
+
flag :set_upstream, short: 'u', desc: 'Set upstream tracking'
|
|
203
|
+
end
|
|
273
204
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
205
|
+
if opts.help?
|
|
206
|
+
help(opts)
|
|
207
|
+
return
|
|
208
|
+
end
|
|
278
209
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
210
|
+
{
|
|
211
|
+
remote_as_method: opts.remote,
|
|
212
|
+
remote_as_sym_key: opts[:remote],
|
|
213
|
+
remote_as_string_key: opts['remote'],
|
|
214
|
+
force_as_method: opts.force,
|
|
215
|
+
force_as_sym_key: opts[:force],
|
|
216
|
+
force_as_string_key: opts['force'],
|
|
217
|
+
}.each do |k,v|
|
|
218
|
+
puts "#{k} => #{v}"
|
|
219
|
+
end
|
|
220
|
+
}
|
|
283
221
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
case args.length
|
|
293
|
-
when 0
|
|
294
|
-
base = %w[main master].find { |b| system("git rev-parse --verify #{b} >/dev/null 2>&1") } || 'HEAD~1'
|
|
295
|
-
ahead_of = base
|
|
296
|
-
branch = 'HEAD'
|
|
297
|
-
when 1
|
|
298
|
-
ahead_of = args[0]
|
|
299
|
-
branch = 'HEAD'
|
|
300
|
-
else
|
|
301
|
-
ahead_of, branch = args[0..1]
|
|
302
|
-
end
|
|
222
|
+
add_subcmd(:push) { |*push_args|
|
|
223
|
+
opts = Hiiro::Options.parse(push_args) do
|
|
224
|
+
option :remote, short: 'r', default: 'origin', desc: 'Remote name'
|
|
225
|
+
option :from, short: 'f', desc: 'Local branch or commit to push'
|
|
226
|
+
option :to, short: 't', desc: 'Remote branch name'
|
|
227
|
+
flag :force, short: 'F', desc: 'Force push'
|
|
228
|
+
flag :set_upstream, short: 'u', desc: 'Set upstream tracking'
|
|
229
|
+
end
|
|
303
230
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
hiiro.add_subcmd(:behind) { |*args|
|
|
309
|
-
case args.length
|
|
310
|
-
when 0
|
|
311
|
-
base = %w[main master].find { |b| system("git rev-parse --verify #{b} >/dev/null 2>&1") } || 'HEAD~1'
|
|
312
|
-
behind_of = base
|
|
313
|
-
branch = 'HEAD'
|
|
314
|
-
when 1
|
|
315
|
-
behind_of = args[0]
|
|
316
|
-
branch = 'HEAD'
|
|
317
|
-
else
|
|
318
|
-
behind_of, branch = args[0..1]
|
|
319
|
-
end
|
|
231
|
+
local_ref = opts[:from] || git.branch
|
|
232
|
+
remote_branch = opts[:to] || local_ref
|
|
320
233
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
234
|
+
git_args = ['git', 'push']
|
|
235
|
+
git_args << '--force' if opts[:force]
|
|
236
|
+
git_args << '-u' if opts[:set_upstream]
|
|
237
|
+
git_args << opts[:remote]
|
|
238
|
+
git_args << "#{local_ref}:#{remote_branch}"
|
|
324
239
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
system("git rev-parse --verify #{ref} >/dev/null 2>&1")
|
|
240
|
+
puts "Pushing #{local_ref} to #{opts[:remote]}/#{remote_branch}..."
|
|
241
|
+
system(*git_args)
|
|
328
242
|
}
|
|
329
243
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
244
|
+
add_subcmd(:diff) { |*diff_args|
|
|
245
|
+
case diff_args.length
|
|
246
|
+
when 0
|
|
247
|
+
# Compare current branch to main/master
|
|
248
|
+
base = %w[main master].find { |b| system("git rev-parse --verify #{b} >/dev/null 2>&1") } || 'HEAD~1'
|
|
249
|
+
range = "#{base}..HEAD"
|
|
250
|
+
when 1
|
|
251
|
+
# Compare current branch to specified ref
|
|
252
|
+
range = "#{diff_args[0]}..HEAD"
|
|
253
|
+
else
|
|
254
|
+
# Compare two refs (from..to or from...to based on args)
|
|
255
|
+
from, to = diff_args[0..1]
|
|
256
|
+
range = "#{from}..#{to}"
|
|
257
|
+
end
|
|
339
258
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
next
|
|
343
|
-
end
|
|
259
|
+
system('git', 'log', '--oneline', '--decorate', range)
|
|
260
|
+
}
|
|
344
261
|
|
|
345
|
-
|
|
346
|
-
|
|
262
|
+
add_subcmd(:changed) { |*changed_args|
|
|
263
|
+
show_all = changed_args.delete('-a') || changed_args.delete('--all')
|
|
264
|
+
upstream = changed_args.first
|
|
347
265
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
system("git rev-parse --verify #{ref} >/dev/null 2>&1")
|
|
352
|
-
}
|
|
266
|
+
upstream ||= %w[origin/master master origin/main main].find { |ref|
|
|
267
|
+
system("git rev-parse --verify #{ref} >/dev/null 2>&1")
|
|
268
|
+
}
|
|
353
269
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
270
|
+
unless upstream
|
|
271
|
+
puts "Cannot find master or origin/master"
|
|
272
|
+
next
|
|
273
|
+
end
|
|
358
274
|
|
|
359
|
-
|
|
275
|
+
forkpoint = `git merge-base --fork-point #{upstream} HEAD 2>/dev/null`.strip
|
|
276
|
+
if forkpoint.empty?
|
|
277
|
+
forkpoint = `git merge-base #{upstream} HEAD 2>/dev/null`.strip
|
|
278
|
+
end
|
|
360
279
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
280
|
+
if forkpoint.empty?
|
|
281
|
+
puts "Could not find fork point"
|
|
282
|
+
next
|
|
283
|
+
end
|
|
365
284
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
}
|
|
285
|
+
if show_all
|
|
286
|
+
system('git', 'diff', '--name-only', "#{forkpoint}...HEAD")
|
|
287
|
+
else
|
|
288
|
+
system('git', 'diff', '--name-only', '--relative', "#{forkpoint}...HEAD")
|
|
289
|
+
end
|
|
290
|
+
}
|
|
372
291
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
292
|
+
add_subcmd(:ahead) { |*ahead_args|
|
|
293
|
+
case ahead_args.length
|
|
294
|
+
when 0
|
|
295
|
+
base = %w[main master].find { |b| system("git rev-parse --verify #{b} >/dev/null 2>&1") } || 'HEAD~1'
|
|
296
|
+
ahead_of = base
|
|
297
|
+
branch = 'HEAD'
|
|
298
|
+
when 1
|
|
299
|
+
ahead_of = ahead_args[0]
|
|
300
|
+
branch = 'HEAD'
|
|
301
|
+
else
|
|
302
|
+
ahead_of, branch = ahead_args[0..1]
|
|
303
|
+
end
|
|
376
304
|
|
|
377
|
-
|
|
378
|
-
|
|
305
|
+
count = `git rev-list --count #{ahead_of}..#{branch}`.strip.to_i
|
|
306
|
+
puts "#{branch} is #{count} commit(s) ahead of #{ahead_of}"
|
|
379
307
|
}
|
|
380
308
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
309
|
+
add_subcmd(:behind) { |*behind_args|
|
|
310
|
+
case behind_args.length
|
|
311
|
+
when 0
|
|
312
|
+
base = %w[main master].find { |b| system("git rev-parse --verify #{b} >/dev/null 2>&1") } || 'HEAD~1'
|
|
313
|
+
behind_of = base
|
|
314
|
+
branch = 'HEAD'
|
|
315
|
+
when 1
|
|
316
|
+
behind_of = behind_args[0]
|
|
317
|
+
branch = 'HEAD'
|
|
318
|
+
else
|
|
319
|
+
behind_of, branch = behind_args[0..1]
|
|
320
|
+
end
|
|
385
321
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
end
|
|
322
|
+
count = `git rev-list --count #{branch}..#{behind_of}`.strip.to_i
|
|
323
|
+
puts "#{branch} is #{count} commit(s) behind #{behind_of}"
|
|
324
|
+
}
|
|
390
325
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
326
|
+
add_subcmd(:log) { |upstream = nil|
|
|
327
|
+
upstream ||= %w[origin/master master origin/main main].find { |ref|
|
|
328
|
+
system("git rev-parse --verify #{ref} >/dev/null 2>&1")
|
|
329
|
+
}
|
|
395
330
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
end
|
|
401
|
-
}
|
|
331
|
+
unless upstream
|
|
332
|
+
puts "Cannot find master or origin/master"
|
|
333
|
+
next
|
|
334
|
+
end
|
|
402
335
|
|
|
336
|
+
forkpoint = `git merge-base --fork-point #{upstream} HEAD 2>/dev/null`.strip
|
|
337
|
+
if forkpoint.empty?
|
|
338
|
+
forkpoint = `git merge-base #{upstream} HEAD 2>/dev/null`.strip
|
|
339
|
+
end
|
|
403
340
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
341
|
+
if forkpoint.empty?
|
|
342
|
+
puts "Could not find fork point"
|
|
343
|
+
next
|
|
344
|
+
end
|
|
407
345
|
|
|
408
|
-
|
|
409
|
-
system("git rev-parse --verify #{ref} >/dev/null 2>&1")
|
|
346
|
+
system('git', 'log', '--oneline', '--decorate', "#{forkpoint}..HEAD")
|
|
410
347
|
}
|
|
411
348
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
349
|
+
add_subcmd(:forkpoint) { |upstream = nil, branch = nil|
|
|
350
|
+
branch ||= 'HEAD'
|
|
351
|
+
upstream ||= %w[origin/master master origin/main main].find { |ref|
|
|
352
|
+
system("git rev-parse --verify #{ref} >/dev/null 2>&1")
|
|
353
|
+
}
|
|
416
354
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
355
|
+
unless upstream
|
|
356
|
+
puts "Cannot find master or origin/master"
|
|
357
|
+
next
|
|
358
|
+
end
|
|
421
359
|
|
|
422
|
-
|
|
423
|
-
puts "Could not find fork point"
|
|
424
|
-
next
|
|
425
|
-
end
|
|
360
|
+
forkpoint = `git merge-base --fork-point #{upstream} #{branch} 2>/dev/null`.strip
|
|
426
361
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
system('git', 'diff', '--name-only', '--relative', "#{forkpoint}...HEAD")
|
|
431
|
-
end
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
hiiro.add_subcmd(:ancestor) { |*args|
|
|
435
|
-
case args.length
|
|
436
|
-
when 0
|
|
437
|
-
# Check if main/master is ancestor of HEAD
|
|
438
|
-
base = %w[main master].find { |b| system("git rev-parse --verify #{b} >/dev/null 2>&1") }
|
|
439
|
-
unless base
|
|
440
|
-
puts "Cannot find main or master branch"
|
|
441
|
-
next
|
|
362
|
+
if forkpoint.empty?
|
|
363
|
+
# Fallback to regular merge-base if fork-point fails
|
|
364
|
+
forkpoint = `git merge-base #{upstream} #{branch} 2>/dev/null`.strip
|
|
442
365
|
end
|
|
443
|
-
ancestor = base
|
|
444
|
-
descendant = 'HEAD'
|
|
445
|
-
when 1
|
|
446
|
-
# Check if arg is ancestor of HEAD
|
|
447
|
-
ancestor = args[0]
|
|
448
|
-
descendant = 'HEAD'
|
|
449
|
-
else
|
|
450
|
-
ancestor, descendant = args[0..1]
|
|
451
|
-
end
|
|
452
366
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
}
|
|
367
|
+
if forkpoint.empty?
|
|
368
|
+
puts "Could not find fork point between #{upstream} and #{branch}"
|
|
369
|
+
else
|
|
370
|
+
puts forkpoint
|
|
371
|
+
end
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
add_subcmd(:ancestor) { |*ancestor_args|
|
|
375
|
+
case ancestor_args.length
|
|
376
|
+
when 0
|
|
377
|
+
# Check if main/master is ancestor of HEAD
|
|
378
|
+
base = %w[main master].find { |b| system("git rev-parse --verify #{b} >/dev/null 2>&1") }
|
|
379
|
+
unless base
|
|
380
|
+
puts "Cannot find main or master branch"
|
|
381
|
+
next
|
|
382
|
+
end
|
|
383
|
+
ancestor = base
|
|
384
|
+
descendant = 'HEAD'
|
|
385
|
+
when 1
|
|
386
|
+
# Check if arg is ancestor of HEAD
|
|
387
|
+
ancestor = ancestor_args[0]
|
|
388
|
+
descendant = 'HEAD'
|
|
389
|
+
else
|
|
390
|
+
ancestor, descendant = ancestor_args[0..1]
|
|
391
|
+
end
|
|
459
392
|
|
|
460
|
-
|
|
393
|
+
if system("git merge-base --is-ancestor #{ancestor} #{descendant}")
|
|
394
|
+
puts "Yes, #{ancestor} is an ancestor of #{descendant}"
|
|
395
|
+
else
|
|
396
|
+
puts "No, #{ancestor} is NOT an ancestor of #{descendant}"
|
|
397
|
+
end
|
|
398
|
+
}
|
|
399
|
+
end
|