-.- --. .-. --..

Use --follow option in git log to view a file's history

I’ve always used the following command to check the history of a particular file in a repo:

$ git log --stat -p -- src/somefile.ts

b209931 (HEAD -> master) Use teypescript to avoid typos
    src/somefile.ts | 5 +++++
    1 file changed, 5 insertions(+)

diff --git src/somefile.ts src/somefile.ts
new file mode 100644
index 0000000..2c4d652
--- /dev/null
+++ src/somefile.ts
@@ -0,0 +1,5 @@
+function helloWorld(): void {
+  console.log('hello world');
+}
+
+helloWorld();

But imagine that this file used to be a plain JS file sometime in the past, and had got renamed to TS. In this case, the first commit would be a single file-creation commit, even though a mostly-similar file had existed before. In these cases, I’d change the command to something like this:

$ git log -p -- src/somefile.ts src/somefile.js

9afc0e4 (HEAD -> master) Use teypescript to avoid typos
    src/{somefile.js => somefile.ts} | 2 +-
    1 file changed, 1 insertion(+), 1 deletion(-)
b8290b9 Fix type!
    src/somefile.js | 2 +-
    1 file changed, 1 insertion(+), 1 deletion(-)
b1d2717 Fix typo
    src/somefile.js | 2 +-
    1 file changed, 1 insertion(+), 1 deletion(-)
f0ed690 Wait, log is not a function?
    src/somefile.js | 2 +-
    1 file changed, 1 insertion(+), 1 deletion(-)
42f5d2c First commit! Beginnings of a great app
    src/somefile.js | 3 +++
    1 file changed, 3 insertions(+)

This lists out the commits of both the files. Still, the first commit of the TS file would be a single creation commit, and the last commit of the JS file would be a single deletion one.

A better way to make git log follow the history of a particular file is to use the command-line switch…er…--follow and turn on the --find-renames (or -M shorthand) option:

$ git log --oneline -M --stat --follow -- src/somefile.ts

9afc0e4 (HEAD -> master) Use teypescript to avoid typos
    src/{somefile.js => somefile.ts} | 2 +-
    1 file changed, 1 insertion(+), 1 deletion(-)
b8290b9 Fix type!
    src/somefile.js | 2 +-
    1 file changed, 1 insertion(+), 1 deletion(-)
b1d2717 Fix typo
    src/somefile.js | 2 +-
    1 file changed, 1 insertion(+), 1 deletion(-)
f0ed690 Wait, log is not a function?
    src/somefile.js | 2 +-
    1 file changed, 1 insertion(+), 1 deletion(-)
42f5d2c First commit! Beginnings of a great app
    src/somefile.js | 3 +++
    1 file changed, 3 insertions(+)

Sometimes the changes are too much for git to detect a particular change as a rename. In those cases, you can further hint to Git specifying the similarity of a change to be considered as a rename. This is passed as a percentage to the -M/--find-renames option.

It’s kind of fascinating the things I get to learn every day in Git, even if I think/feel I’m pretty fluent in it. I had been using a command that did most of what I wanted to do, but one more flag would’ve made it much easier!

← Git fetch's --prune option cleans up notes! Promise.race, fetch and avoiding memory leaks →