Skip to content
This repository was archived by the owner on Jan 22, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## [Unreleased]

- `git pkgs init` now installs git hooks by default (use `--no-hooks` to skip)
- Fix N+1 queries in `blame`, `stale`, `stats`, and `log` commands

## [0.4.0] - 2026-01-04

Expand Down
2 changes: 1 addition & 1 deletion lib/git/pkgs/analyzer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ def parse_manifest_before_commit(rugged_commit, manifest_path)
end

def parse_manifest_by_oid(blob_oid, manifest_path)
cache_key = "#{blob_oid}:#{manifest_path}"
cache_key = [blob_oid, manifest_path]

if @blob_cache.key?(cache_key)
@blob_cache[cache_key][:hits] += 1
Expand Down
30 changes: 24 additions & 6 deletions lib/git/pkgs/commands/blame.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,34 @@ def run
return
end

# Batch fetch all "added" changes for current dependencies
snapshot_keys = snapshots.map { |s| [s.name, s.manifest_id] }.to_set
manifest_ids = snapshots.map(&:manifest_id).uniq
names = snapshots.map(&:name).uniq

all_added_changes = Models::DependencyChange
.includes(:commit)
.added
.where(manifest_id: manifest_ids, name: names)
.to_a

# Group by (name, manifest_id) and find earliest by committed_at
added_by_key = {}
all_added_changes.each do |change|
key = [change.name, change.manifest_id]
next unless snapshot_keys.include?(key)

existing = added_by_key[key]
if existing.nil? || change.commit.committed_at < existing.commit.committed_at
added_by_key[key] = change
end
end

# For each current dependency, find who added it
blame_data = []

snapshots.each do |snapshot|
added_change = Models::DependencyChange
.includes(:commit)
.where(name: snapshot.name, manifest: snapshot.manifest)
.added
.order("commits.committed_at ASC")
.first
added_change = added_by_key[[snapshot.name, snapshot.manifest_id]]

next unless added_change

Expand Down
2 changes: 1 addition & 1 deletion lib/git/pkgs/commands/list.rb
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ def compute_dependencies_at_commit(target_commit, repo)
# Replay changes from snapshot to target
if snapshot_commit && snapshot_commit.id != target_commit.id
changes = Models::DependencyChange
.joins(:commit, :manifest)
.joins(:commit)
.where(commits: { id: branch.commit_ids })
.where("commits.committed_at > ? AND commits.committed_at <= ?",
snapshot_commit.committed_at, target_commit.committed_at)
Expand Down
9 changes: 5 additions & 4 deletions lib/git/pkgs/commands/log.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ def run
Database.connect(repo.git_dir)

commits = Models::Commit
.includes(:dependency_changes)
.where(has_dependency_changes: true)
.order(committed_at: :desc)

Expand All @@ -42,8 +43,8 @@ def run

def output_text(commits)
commits.each do |commit|
changes = commit.dependency_changes
changes = changes.where(ecosystem: @options[:ecosystem]) if @options[:ecosystem]
changes = commit.dependency_changes.to_a
changes = changes.select { |c| c.ecosystem == @options[:ecosystem] } if @options[:ecosystem]
next if changes.empty?

puts "#{commit.short_sha} #{commit.message&.lines&.first&.strip}"
Expand Down Expand Up @@ -75,8 +76,8 @@ def output_json(commits)
require "json"

data = commits.map do |commit|
changes = commit.dependency_changes
changes = changes.where(ecosystem: @options[:ecosystem]) if @options[:ecosystem]
changes = commit.dependency_changes.to_a
changes = changes.select { |c| c.ecosystem == @options[:ecosystem] } if @options[:ecosystem]

{
sha: commit.sha,
Expand Down
31 changes: 25 additions & 6 deletions lib/git/pkgs/commands/stale.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,38 @@ def run
return
end

# Batch fetch all changes for current dependencies
snapshot_keys = snapshots.map { |s| [s.name, s.manifest_id] }.to_set
manifest_ids = snapshots.map(&:manifest_id).uniq
names = snapshots.map(&:name).uniq

all_changes = Models::DependencyChange
.includes(:commit)
.where(manifest_id: manifest_ids, name: names)
.to_a

# Group by (name, manifest_id) and find latest by committed_at
latest_by_key = {}
all_changes.each do |change|
key = [change.name, change.manifest_id]
next unless snapshot_keys.include?(key)

existing = latest_by_key[key]
if existing.nil? || change.commit.committed_at > existing.commit.committed_at
latest_by_key[key] = change
end
end

# Find last update for each dependency
outdated_data = []
now = Time.now

snapshots.each do |snapshot|
last_change = Models::DependencyChange
.includes(:commit)
.where(name: snapshot.name, manifest: snapshot.manifest)
.order("commits.committed_at DESC")
.first
last_change = latest_by_key[[snapshot.name, snapshot.manifest_id]]

next unless last_change

days_since_update = ((Time.now - last_change.commit.committed_at) / 86400).to_i
days_since_update = ((now - last_change.commit.committed_at) / 86400).to_i

outdated_data << {
name: snapshot.name,
Expand Down
13 changes: 9 additions & 4 deletions lib/git/pkgs/commands/stats.rb
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,16 @@ def collect_stats(branch, branch_name)
manifests = Models::Manifest.all
manifests = manifests.where(ecosystem: ecosystem) if ecosystem

manifest_ids = manifests.pluck(:id)
change_counts_query = Models::DependencyChange
.joins(:commit)
.where(manifest_id: manifest_ids)
change_counts_query = change_counts_query.where("commits.committed_at >= ?", since_time) if since_time
change_counts_query = change_counts_query.where("commits.committed_at <= ?", until_time) if until_time
change_counts = change_counts_query.group(:manifest_id).count

data[:manifests] = manifests.map do |manifest|
manifest_changes = manifest.dependency_changes.joins(:commit)
manifest_changes = manifest_changes.where("commits.committed_at >= ?", since_time) if since_time
manifest_changes = manifest_changes.where("commits.committed_at <= ?", until_time) if until_time
{ path: manifest.path, ecosystem: manifest.ecosystem, changes: manifest_changes.count }
{ path: manifest.path, ecosystem: manifest.ecosystem, changes: change_counts[manifest.id] || 0 }
end

data
Expand Down