8000 Redesign Git::Log for explicit execution · Issue #813 · ruby-git/ruby-git · GitHub
[go: up one dir, main page]

Skip to content
Redesign Git::Log for explicit execution #813
Open
@jcouball

Description

@jcouball

Refactor fluent builder object Git::Log to use explicit execution via a new #execute method, improving API clarity and predictability.

Problem and Motivation

Currently, objects like Git::Log are fluent builders that build a command whose data fetched using a lazy-loading pattern. It is lazy-loading because the actual git command is executed implicitly when a data-access method (each, size, first, etc.) is called.

This is managed by an internal @dirty_flag that must be checked by every accessor method. This design has several drawbacks:

  • It's complex: The object must track its state (builder vs. result set) and the dirty flag logic must be implemented perfectly in every relevant method.
  • It's hard to maintain: Adding new accessor methods is error-prone, as each must remember to check the dirty flag.
  • It's unpredictable: Users may not realize when an expensive git command is being executed, which could lead to unexpected performance issues.

Proposed Solution

I propose we refactor these fluent interfaces to use explicit execution. This separates the query-building responsibility from the result-handling.

  1. The Git::Log object would become a pure query building object. Its methods (since, author, etc.) would only configure the command.
  2. A new method, #execute, would be added. This method is the only one that runs the git command.
  3. The #execute method would return a new, immutable result object.
  4. All data-access methods (each, size, first, last, etc.) would be moved to this new result object, operating on a static collection of commits.

Before:

# `git log` is run implicitly inside .size and .each
log = g.log.since('2 weeks ago').author('Scott')
puts "Found #{log.size} commits" 
log.each do |commit|
  # ...
end

After:

query = g.log.since('2 weeks ago').author('Scott')
results = query.execute
puts "Found #{results.size} commits" 
results.each do |commit|
  # ...
end

Benefits of This Change

  • Predictable Performance: The developer knows exactly when the expensive git command is run.
  • Clarity: The API becomes easier to reason about. You build a query, you execute it, you get results.
  • Simpler Implementation: The complex and brittle dirty flag logic can be completely removed.
  • Safer, Immutable Results: The result set is a stable snapshot and won't change unexpectedly.

Affected Classes

  • Git::Log

BREAKING CHANGE

This is a breaking API change and would require a major version bump (e.g., to v4.0.0). The benefits in terms of API robustness, predictability, and maintainability justify the change for a new major release.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0