git log --follow: Tracking a File's History Across Renames
AI generated
git
HEAD
Git
git log --follow
Tracking a file's history across renames

A renamed file looks like a brand new file to git log. With --follow the full history stays visible, but only under certain conditions.

9 min read Git History Debugging

1. Why git log stops at a rename

When a file is renamed or moved into another directory, its path formally changes as far as Git is concerned. A plain call to git log with the current file path as the argument afterward only shows commits created under that path.

Every commit before the rename disappears from the output, even though the content of the file stayed continuous throughout. For anyone trying to trace the full history of a central class, that is a real problem.

The reason lies in how Git works internally: renames are not stored as a distinct operation, they are only detected afterward, when displaying history, through a similarity comparison between deleted and newly added files.


# Shows only commits since the rename, older history is missing
git log -- app/code/Vendor/Module/Model/PriceCalculator.php

# The previous file had a different name, it does not show up here
git log -- app/code/Vendor/Module/Model/Calculator.php

2. How Git actually detects renames

Git stores the full state of the repository at every commit, not a chain of diffs. There is no internal field that explicitly marks a rename as such, unlike in some other version control systems.

When generating a diff between two commits, Git instead compares every deleted file against every newly added file and computes a similarity index. If that index exceeds a threshold, Git reports the two files as a rename, even though technically one file was deleted and another was newly created.

This after the fact detection is why rename tracking does not behave the same everywhere. Tools that do not perform a similarity comparison only ever see a deletion and a creation, never the rename itself.


# Show the similarity index for a commit
git show --stat -M <commit-sha>
# R087  Model/Calculator.php  Model/PriceCalculator.php
# R087 means 87 percent similarity between the old and new file

3. git log --follow: basics and syntax

The --follow option tells Git to keep searching a single file's history across detected renames. As soon as Git finds a past commit that marks the file as a rename, the search automatically jumps to the previous path and continues from there.

The important restriction is that it works with exactly one file path. --follow only functions when filtering by a single file, not multiple paths or directories at once. If more than one path is given, Git silently ignores the option.

The result is one continuous history across every detected rename, including commits that predate the very first rename, all the way back to the original creation of the file under any of its earlier names.


# Full history including every detected rename
git log --follow -- app/code/Vendor/Module/Model/PriceCalculator.php

# More compact, one line per commit
git log --follow --oneline -- app/code/Vendor/Module/Model/PriceCalculator.php

4. Combining follow with patch output

Plain commit metadata is often not enough when tracing how a file's content actually changed. Combining --follow with -p additionally shows the full diff for every commit, even across rename boundaries.

At the point where the rename happened, the diff shows both the old and new file name, often alongside content changes made in the same commit. That reveals whether a rename happened in isolation or as part of a larger refactoring.

For very long histories, using --stat instead of the full patch first helps to see only the size of each change and then select individual commits for the full diff.


# Full diff across every detected rename
git log --follow -p -- app/code/Vendor/Module/Model/PriceCalculator.php

# Just the stats per commit, a compact overview
git log --follow --stat -- app/code/Vendor/Module/Model/PriceCalculator.php

5. Limits of --follow

The most important limitation was already mentioned: --follow only works with exactly one file path. Anyone tracing the history of several moved files at once has to run the command separately for each one.

For merge commits, rename detection can become unreliable, especially when a file was renamed on one branch and heavily rewritten on the other. The similarity index then falls below the threshold and Git no longer sees a connection.

Multiple renames happening close together, combined with substantial content changes at the same time, can also break the chain. The more similar the file content stays across versions, the more reliably --follow works.


# Does NOT work: multiple paths at once with --follow
git log --follow -- Model/PriceCalculator.php Model/TaxCalculator.php
# --follow is silently ignored here

# Run separately instead
git log --follow -- Model/PriceCalculator.php
git log --follow -- Model/TaxCalculator.php

6. git blame and rename detection

While --follow applies to git log, git blame has its own approach. By default, blame only detects renames within the currently viewed file's history in a limited way, but tracks them actively via the -C option.

The -C option tells blame to also search for lines that originally lived in a different file, for example when code was copied or moved from one file to another. Passing -C -C extends the search further, to every file touched in the same commit.

For simply tracking a rename chain, a single -C combined with -M, which explicitly enables rename detection within a file, is usually enough, even when additional content changes happened in the same commit.


# Blame with rename and copy detection enabled
git blame -C -M app/code/Vendor/Module/Model/PriceCalculator.php

# Blame for a specific line, including the commit before the rename
git blame -C -M -L 42,42 app/code/Vendor/Module/Model/PriceCalculator.php

7. Adjusting the similarity threshold

The default threshold for rename detection is 50 percent similarity. For most cases that is a reasonable compromise, but for files that were heavily reworked at the same time they were renamed, the value can be too high.

Using -M with an explicit percentage lets you lower the threshold manually, for example to 30 percent, to also catch renames combined with more extensive content changes. Too low a value, though, produces false positive rename matches between completely unrelated files.

The parameter can be set for git log, git diff, and git blame alike, and directly affects the quality of rename detection in each of those outputs.


# Lower the threshold to 30 percent, more renames get detected
git log --follow -M30% -- app/code/Vendor/Module/Model/PriceCalculator.php

# Show the threshold directly in a diff
git diff -M30% HEAD~5 HEAD

8. Practical example: a file renamed multiple times

In a typical Magento module, a central model class often moves more than once: first renamed within the same directory, later moved into a new subdirectory during a refactor. --follow reconstructs that entire chain with a single command.

In practice you start from the current path of the file and let Git find the older history on its own, instead of manually searching for earlier file names. Only when --follow hits a detectable boundary, for example because the similarity index for a particular rename is too low, do you need to manually search for the suspected earlier name.

A proven approach combines --follow for the automated part with a targeted git log --diff-filter=D using a name pattern, to manually find deleted files with a similar name when automatic detection reaches its limits.


# Reconstruct the full chain, current path as the starting point
git log --follow --oneline --name-status -- app/code/Vendor/Module/Model/PriceCalculator.php

# If the chain breaks: search deliberately for deleted similar files
git log --diff-filter=D --oneline --name-only -- '*Calculator*'

9. Alternatives and complementary tools

For the history of an entire directory rather than a single file, --follow offers no solution. The only option here is a manual reconstruction using several git log --diff-filter=R calls that deliberately search for rename commits within the relevant timeframe.

git log --all --full-history does show every commit that ever touched a file, but it does not automatically follow renames and therefore has to be combined with the correct path valid at each point in time.

For a visual view, GUI tools like GitKraken or the history view in PhpStorm can help, since they often render rename chains as a single continuous line, which makes understanding complex file movements much easier.


# Every commit marked as a rename across the whole repository
git log --all --diff-filter=R --summary --oneline

# Full history without follow, with an explicit full-history flag
git log --full-history --oneline -- app/code/Vendor/Module/
Command Rename detection Use case Limitation
git log None Current history from the latest path Stops at every rename
git log --follow Automatic, one path Complete file history Only one path at a time
git blame -C -M Active, line based Trace the origin of individual lines Slower on large repositories
git log --diff-filter=R Lists rename commits Manually searching for renames No automatic following

Mironsoft

Git workflows, branching strategies, and CI hooks

Chaotic Git history and unclear branching rules across the team?

We set up clean Git workflows, clarify branching strategies for the team, and automate quality checks via Git hooks and CI pipelines so the history stays traceable.

Workflow Audit

Review the existing branching strategy and merge practice for weak spots.

Hook Automation

Set up pre-commit and pre-push hooks for linting, tests, and commit conventions.

Team Training

Teach rebase, cherry-pick, and conflict resolution hands-on across the team.

10. Summary

git log --follow

Core command

git log --follow with exactly one file path

Limitation

Only works with exactly one file path

For lines

git blame -C -M complements --follow at the line level

Threshold

Default 50 percent, adjustable via -M

11. FAQ: git log --follow

1Why does git log not show the full history of a renamed file?
Because renames are not explicitly stored in Git, they have to be detected afterward through a similarity comparison. Without the --follow option, the search stops at the current file path.
2What exactly does the --follow option do in git log?
It tells Git to automatically jump to the previous file path whenever a rename is detected and continue the search from there, so the complete history across every rename becomes visible.
3Can I use --follow for multiple files at once?
No, --follow only works when exactly one file path is given. With multiple paths, Git silently ignores the option and shows the normal, incomplete history instead.
4How do I combine --follow with diff output?
Adding the -p option alongside --follow makes Git show the full diff for every commit, including at the point of a rename, so content and structural changes become visible together.
5What is the difference between git log --follow and git blame -C?
git log --follow traces the history of an entire file across renames, while git blame -C finds the origin of individual lines, even when code was copied or moved between different files.
6Why does Git fail to detect some renames?
If a file's content changes too much at the same time it is renamed, the similarity index falls below the threshold and Git treats the change as a plain deletion plus creation rather than a rename.
7How do I adjust the threshold for rename detection?
Using the -M option with an explicit percentage, for example -M30%, makes detection more sensitive. A value that is too low, though, increases the risk of false positive rename matches.
8Does --follow work reliably on merge commits too?
Not always. On merge commits, especially when a file was renamed on one branch and heavily changed on the other, automatic detection can fail and the chain can break.
9How do I find the history of an entire directory across renames?
There is no direct --follow option for that. A manual reconstruction using git log --diff-filter=R for the relevant timeframe is the practical way to trace directory renames.
10Are there graphical alternatives to git log --follow?
Yes, many GUI tools such as GitKraken or the built in history view in PhpStorm display rename chains visually, which makes understanding files that moved multiple times much easier.