Craig
Craig

Reputation: 2366

Show git log for a file from a specific branch

I'm resolving some merge conflicts for a file and I'd like to see the evolution of the file on the master branch versus its evolution on my branch. I can't switch branches to look at the log history while I'm resolving the conflict. This how I view the log history typically:

git log --color --graph -- <path_to_file>

Now I'd like to include the branch as a command line argument like:

git log --color --graph --branch master -- <path_to_file>

Is something like this possible without having to checkout the branch?

Upvotes: 3

Views: 2253

Answers (3)

jthill
jthill

Reputation: 60255

git log --first-parent -m --patch ...master -- that.file

will show you all changes to that.file on master since it diverged from your checkout, folding in the entirety of any changes brought in by merges (which the header will identify for you so you can easily explore further if you want).

Upvotes: 0

Dušan Stokić
Dušan Stokić

Reputation: 171

You can observe log history of all branches and their commits calling:

gitk --all

Upvotes: 1

torek
torek

Reputation: 487993

There's a fundamental (albeit tiny) glitch in the question itself, but you can get what you probably want very simply:

git log --color --graph master -- <path-to-file>

The double hyphen -- here separates the non-file arguments from the file (technically pathspec) arguments. It's not always required, but it is never a bad idea.

The rest of this answer is optional reading.

Long: details about the above

I said there's a glitch in the question itself. Here's why:

I'd like to see the evolution of the file on the master branch versus its evolution on my branch.

The "evolution of the file", as you put it, happens in commits and commits are on more than one branch at a time. Some commits in which the file evolved will be only on master; some will be only on the current branch. Some will be on both branches.

A nice way to split things up is to examine only those commits that are only on master, and only those commits that are only on the current branch. To do that, we would want to use Git's "symmetric difference" operator, spelled with three dots:

git log [options] master...HEAD [-- pathspecs]

Now, by itself (without --graph or some other option) this still has a big problem: you can't tell, here, which branch the commit was found on. Using --graph does fix that, but is a bit intrusive. An alternative is to use --left-right. You might also want to add --topo-order (because --graph sets --topo-order on its own): the --left-right option marks each commit, with < or >, depending on whether it's found via the left side name—master, in this case—or the right-side name, here HEAD.

So, this ends up being:

git log --left-right master...HEAD -- <path-to-file>

or:

git log --left-right --topo-order master...HEAD -- <path-to-file>

Now the master-side commits will be marked with <, and the HEAD/current-branch-side commits will be marked with >.

You might still want to add -m, if there are any merge commits in the range defined by the three-dot master...HEAD syntax. See below for why. (You can also drop the name HEAD entirely—it will be implied by the three-dot syntax—or use the one-character @ synonym, if you like.)

When -- is required

When you run a command like:

git log zorg

Git has a fundamental problem: is zorg a branch or tag name, or a file name? If it's the former, the output from git log will start at the commit identified by the branch or tag name, but if it's the latter, git log will start at HEAD, and turn on History Simplification and look only for commits that modify the specified file (skipping merge commits unless you add -m).

Git decides whether zorg is a branch or file name by the simple expedient of testing it as one or both. If there is a file (or many files within some directory) named zorg in Git's index right now, zorg can be a file name ("pathspec", really). If there is a branch or tag named zorg, zorg can be the branch or tag name. If it's both, well, bad things happen in some cases and some versions of Git.1

If there's no file named zorg in Git's index, git log zorg tries to use it as a branch name, even if you're looking for the commit that deleted the file. You must use git log -- zorg to force Git to treat it as a file name (pathspec).

If it's ambiguous, the presence of the -- ensures that Git treats the name correctly, even if you have an old version of Git (see footnote 1).


1In particular, with git checkout in Git versions predating Git 2.23, Git treats it as a file or directory name, not a branch name. This invokes the git checkout mode that means destroy any uncommitted work in this file, which Git cheerfully does.

Upvotes: 3

Related Questions