Skip to content

Commit 46142a3

Browse files
jwiegleyclaude
andcommitted
Fix stack overflow in git-find script (fixes #3)
This commit fixes two issues in the git-find script: 1. Stack overflow in assign_name method: Converted from recursive to iterative implementation using a queue-based approach. This prevents stack overflow when processing commits with very deep parent chains or complex histories. The iterative version can handle arbitrarily deep chains without hitting Ruby's stack limit. 2. ARGV handling bug: Fixed incorrect treatment of ARGV[0] as an array. Changed ARGV[0] to ARGV on lines 186 and 243 to properly handle command line arguments. These changes resolve the SystemStackError reported when running git-find on repositories with complex commit histories like the official Git repo. Tested successfully on the Git repository with 78k+ commits using: git find bd40d252ec1ed2716ac9e6bbeab48b3b40bd0d58 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent fd9f3cb commit 46142a3

File tree

1 file changed

+32
-18
lines changed

1 file changed

+32
-18
lines changed

git-find

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -80,25 +80,39 @@ class Commit < GitObject
8080
end
8181

8282
def assign_name(name)
83-
if @names.include?(name)
84-
return
85-
end
86-
puts name
87-
add_name(name)
88-
89-
offset = 0
90-
@parents.each do |parent|
91-
if offset == 0
92-
if name =~ /(.+?)~([0-9]+)$/
93-
child_name = $1 + "~" + ($2.to_i + 1).to_s
83+
# Use iterative approach with a queue to avoid stack overflow
84+
queue = [[self, name]]
85+
visited = {}
86+
87+
while !queue.empty?
88+
commit, commit_name = queue.shift
89+
90+
# Skip if we've already assigned a name to this commit
91+
next if commit.names.include?(commit_name)
92+
93+
# Skip if we've already visited this commit with this specific name pattern
94+
visit_key = "#{commit.ident}:#{commit_name}"
95+
next if visited[visit_key]
96+
visited[visit_key] = true
97+
98+
puts commit_name
99+
commit.add_name(commit_name)
100+
101+
# Add parents to the queue
102+
offset = 0
103+
commit.parents.each do |parent|
104+
if offset == 0
105+
if commit_name =~ /(.+?)~([0-9]+)$/
106+
child_name = $1 + "~" + ($2.to_i + 1).to_s
107+
else
108+
child_name = commit_name + "~1"
109+
end
94110
else
95-
child_name = name + "~1"
111+
child_name = commit_name + "^" + (offset + 1).to_s
96112
end
97-
else
98-
child_name = name + "^" + (offset + 1).to_s
113+
queue.push([parent, child_name])
114+
offset += 1
99115
end
100-
parent.assign_name(child_name)
101-
offset += 1
102116
end
103117
end
104118
end
@@ -183,7 +197,7 @@ puts "Processing refs history ..."
183197
$refs.each { |ref| get_ref_history(ref) }
184198
$refs.each { |ref| process_names(ref) }
185199

186-
$hashes = ARGV[0].map { |ref| `git rev-parse #{ref}`.chomp }
200+
$hashes = ARGV.map { |ref| `git rev-parse #{ref}`.chomp }
187201

188202
$search_reflogs = false
189203
$hashes.each do |hash|
@@ -240,7 +254,7 @@ if $search_dangling
240254
end
241255
end
242256

243-
ARGV[0].each do |ref|
257+
ARGV.each do |ref|
244258
hash = `git rev-parse #{ref}`.chomp
245259

246260
object = $objects[hash]

0 commit comments

Comments
 (0)