fix: Follow file renames on the commits page

🎉 in !256643 (merged) we got gitaly 19.4 merged, with ListCommits.follow support 👍

Why

#628900 (closed) describes a bug where on the commits page we stopped following file renames. This was caused by refactor that moved the page off the REST/FindCommits path onto a GraphQL query resolved by Resolvers::Repositories::CommitsResolver, which calls Repository#list_commits and thus Gitaly's ListCommits RPC, which had no rename-following.

What

Make the commits page follow file renames again. Threads a follow: keyword down the existing chain (CommitService#list_commits -> Gitlab::Git::Repository#list_commits -> Repository#list_commits) and opts in from CommitsResolver only for the safe case.

fix details

thread a follow: keyword down the existing chain and opts in from CommitsResolver only for the safe case:

  • a single scalar path
  • the new list_commits_follow feature flag enabled for the project
  • the existing remove_file_commit_history_following ops flag OFF

reverse stays hardcoded false and skip is never forwarded on this path, because gitaly rejects follow combined with reverse, multiple paths, or skip.

Feature flag

New gitlab_com_derisk flag list_commits_follow, default_enabled: false, milestone 19.5.

Completes the Rails half of #595517 (closed) (page path).

LLM friendly Local validation steps

Click to expand

MR: !256649 (merged) What it does: The commits page (file-history view) now follows file renames. A follow: flag is threaded from the GraphQL commits resolver down to the Gitaly ListCommits RPC, gated behind the new list_commits_follow feature flag.

These steps let a reviewer confirm the behavior against a local GDK. They cover the main paths only — the edge cases (guardrails against follow+reverse/skip, per-layer defaulting, the ops-flag override, pagination internals) are already covered by the specs added in this MR, so there's no need to reproduce them by hand.


Prerequisites

  1. A running GDK checked out on this MR's branch.
  2. Gitaly 19.4+. The follow support ships with the Gitaly 19.4 gem bump (the first commit on this branch). If your GDK's Gitaly is older, the follow field is silently ignored and the "after" results below will look like the "before" results. gdk update (or rebuilding Gitaly) ensures you're current.
  3. Test fixtures — already present in every GDK seed, nothing to create:
    • Project: gitlab-org/gitlab-test
    • Branch: blame-on-renamed
    • Renamed path: files/plain_text/renamed

Feature flag

Flag Type Default Restart needed after flip?
list_commits_follow gitlab_com_derisk (Ruby, per-request) OFF No — read per request; the next query sees the new value

Flip it from the Rails console (gdk rails console / bin/rails console):

# Enable
Feature.enable(:list_commits_follow)

# Disable (restore default)
Feature.disable(:list_commits_follow)

There is also an existing kill-switch, remove_file_commit_history_following (ops flag, default OFF). Leave it at its default for these steps — its override behavior is covered by specs.


Option A — Rails console (fewest moving parts)

Everything below runs in gdk rails console. This exercises the same Repository#list_commits(follow:) path the GraphQL resolver uses.

project = Project.find_by_full_path('gitlab-org/gitlab-test')
repo    = project.repository
ref     = 'blame-on-renamed'
path    = 'files/plain_text/renamed'

# Baseline — history dead-ends at the rename
literal = repo.list_commits(ref: ref, path: path, follow: false).commits.map(&:id)
literal.size
# => 2   (the bug: pre-rename history is missing)

# The fix — following the rename adds the pre-rename commits
followed = repo.list_commits(ref: ref, path: path, follow: true).commits.map(&:id)
followed.size
# => 4

followed - literal      # the 2 pre-rename commits that were previously missing
followed & literal == literal   # => true (followed is a strict superset of literal)

Expected: follow: false → 2 commits; follow: true → 4 commits, containing all of the literal 2 plus 2 pre-rename commits. That difference is the entire fix.

To confirm the feature-flag gating end-to-end (resolver level), toggle the flag and re-run the GraphQL query in Option B.


Option B — GraphQL (the real commits-page path)

Use the GraphiQL explorer at /-/graphql-explorer on your GDK, or any GraphQL client authenticated to your GDK. This is the exact query the commits page issues.

Step 1 — Baseline: flag OFF reproduces the bug

Ensure the flag is OFF (default), then run:

{
  project(fullPath: "gitlab-org/gitlab-test") {
    repository {
      commits(ref: "blame-on-renamed", path: "files/plain_text/renamed", first: 100) {
        nodes { sha }
      }
    }
  }
}

Expected: exactly 2 nodes (post-rename history only) — the bug this MR fixes.

Step 2 — Enable the flag

In the Rails console: Feature.enable(:list_commits_follow). No restart required.

Step 3 — Flag ON follows the rename (the fix)

Re-run the identical query from Step 1.

Expected: 4 nodes — the 2 from Step 1 plus 2 pre-rename commits that were previously missing. This is the fix working end-to-end through the real commits-page resolver.

Step 4 — Sanity check: no path still works

With the flag still ON, query a branch with no path:

{
  project(fullPath: "gitlab-org/gitlab-test") {
    repository {
      commits(ref: "blame-on-renamed", first: 3) {
        nodes { sha }
        pageInfo { hasNextPage }
      }
    }
  }
}

Expected: normal branch history (3 nodes, hasNextPage: true), no errors in the response — confirming follow is not requested when there's no path.


Optional — confirm the UI

Enable the flag, then open the commits page for the renamed file in the browser:

/gitlab-org/gitlab-test/-/commits/blame-on-renamed/files/plain_text/renamed

Expected: with the flag ON, the list now shows the pre-rename commits (the history continues past the rename); with it OFF, it stops at the rename.


Cleanup — restore the flag

In the Rails console:

Feature.disable(:list_commits_follow)

Re-run the Step 1 query (or Option A baseline) to confirm you're back to 2 commits.


Summary of expected results

Scenario Flag Path Expected
Baseline OFF renamed path 2 commits (bug: dead-ends at rename)
The fix ON renamed path 4 commits (follows rename)
No path ON none normal history, no error

Edge cases (per-layer defaulting, follow+reverse/skip guardrails, the remove_file_commit_history_following override, pagination cursor internals) are covered by the specs added in this MR and don't need manual reproduction.

Before merging

  • Merge !256643 (merged) first
  • Retarget this MR to master
  • Confirm feature/Capybara behaviour in CI/QA
  • Run the full pipeline (un-draft)
Edited by Hunter Stewart

Merge request reports

Loading
Loading