Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Show history of a single file across all branches

Tags:

git

git-log

How can I show the complete history of a single file in Git? When I use git log <filename> or gitk <filename>, I only get merges. I want to see the commits from the merged branches that affect the file. I've tried --follow and other flags and can't find a way.

like image 305
Juliana Peña Avatar asked Jul 21 '14 22:07

Juliana Peña


People also ask

How do you check the history of a file in git?

Use --follow option in git log to view a file's history 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.

How can you view all the commits for a single file in git?

Use git log --all <filename> to view the commits influencing <filename> in all branches.

Which command is used to see the graphical history of all the changes?

gitk and git-gui gitk is a graphical history viewer. Think of it like a powerful GUI shell over git log and git grep . This is the tool to use when you're trying to find something that happened in the past, or visualize your project's history.

How can I tell which commits changed a file?

To find out which files changed in a given commit, use the git log --raw command. It's the fastest and simplest way to get insight into which files a commit affects.


2 Answers

TL;DR summary: --all

First, let me tackle one general item that applies to many git commands.

git log looks at the revision(s) you specify, using git rev-list to handle them. The reason you normally see many commits is that git rev-list "walks history", unless told not to:

$ git rev-list --no-walk HEAD
d1574b852963482d4b482992ad6343691082412f
$ git rev-list HEAD
d1574b852963482d4b482992ad6343691082412f
b9491ea160d12ddfd69a9ddc79ebd264cda20679
676699a0e0cdfd97521f3524c763222f1c30a094
[snip]

However, the revisions visited by git rev-list start from the point(s) you specify (with default = HEAD). So any revisions that are not already part of the point(s) you specified, or its history, are omitted:

        C - D           <-- branchA
      /
A - B - E - F - G       <-- branchB
      \
        H - I - J - M   <-- HEAD=branchC
          \       /
            K - L

In this diagram I've put in three branch names, and shown that HEAD is branchC. Each single letter represents a commit (an SHA-1). Any commit's parents are those to the left of it, either directly left or moving up or down along the parent-commit links that go between commits.

At this point, git log will show you commits M, L, K, J, I, H, B, and A, because git log (and git rev-list) will start at HEAD and walk backwards. (The precise order of these commits depends on additional arguments.)

On the other hand, git log branchB will show you commits G, F, E, B, and A, because starting at commit G and walking backwards selects those commits (and no others). Similarly, git log branchA starts with D and walks back to A.

If you ask git rev-list to look at --all, it will start at all references (all branches, all tags, all remote-branches, and all other refs in the refs/ namespace) and walk backwards. In this case, all branches alone suffices to select every commit. In repositories with tags, --branches might get you less than --all, since there might be some line(s) that are tagged but not marked with a branch. See the (rather overwhelming) git rev-list documentation to see all available options here.


Adding a file name to git log makes it skip the printing of some (many or most) of the commits it visits, through what is described in the documentation as "History Simplification". That is, git log first selects all the commits selected by your git rev-list arguments, but then it only shows a smaller number.

Adding --follow makes git log attempt to notice cases where a file is renamed across a particular commit, and in those cases, switch selected revisions to those with the previous name once it transitions across such commits in its history-walk. In other words, it tries to adjust the history simplification to correct for name changes. This rename discovery is performed dynamically (re-tested for every pair of commits). It works only when stepping backwards—the code is just not there for handling other commit-orders.

When using git diff, you have more control over what is recognized as a rename; with git log's --follow, you're stuck with the compiled-in default of a 50% match.

like image 71
torek Avatar answered Sep 18 '22 13:09

torek


This will show all versions of the file (merges or not):

gitk --all <filename>
like image 34
Martin G Avatar answered Sep 21 '22 13:09

Martin G