Reputation: 527
I want to see a historical version of a given file: .zshrc
This will show me all commits where this file changed:
git log .zshrc
...
...
Now for given commit, I want to see the whole file. But the following actually does not show the file. It shows a diff between that commit and previous commit:
git show bbac89168a2fbbaaa6ef31dc50616dd236c8b5d4 .zshrc
This does not work at all:
git show bbac89168a2fbbaaa6ef31dc50616dd236c8b5d4:.zshrc
fatal: Path 'test/.zshrc' exists, but not '.zshrc'.
Did you mean 'bbac89168a2fbbaaa6ef31dc50616dd236c8b5d4:test/.zshrc' aka '2c0989168a2fbbaaa6ef31dc50616dd236c8b5d4:./.zshrc'?
And finally, this behaves as expected. It will "cat" given version of file
git show bbac89168a2fbbaaa6ef31dc50616dd236c8b5d4:./.zshrc
But why is the behavior of git show
so illogical and confusing?
Why is git show bbac89168a2fbbaaa6ef31dc50616dd236c8b5d4 .zshrc
different from git show bbac89168a2fbbaaa6ef31dc50616dd236c8b5d4:.zshrc
Also, why does git show bbac89168a2fbbaaa6ef31dc50616dd236c8b5d4:.zshrc
not work, even though git clearly understand, and suggests, I should use: bbac89168a2fbbaaa6ef31dc50616dd236c8b5d4:test/.zshrc
?
Why can't I use relative path :.zshrc
and instead must use completely unnecessary construct :./.zshrc
?
Upvotes: 0
Views: 82
Reputation: 52111
When you use the notation <commit hash>:<path>
, you may think of <path>
as an absolute path starting from the root of the repository.
This will work in any context : in a bare repository, when working with external worktrees ...
Starting your path with ./
is one way to name relative paths, it actually indicates to git : "try to make out what tree to inspect in the commit from my current working directory" -- which does have an intuitive meaning when you have a regular clone of a repo, but may fail in other contexts.
Note that the behavior of git show <commit> <path>
is also very different from git show <commit>:<path>
:
git show <commit> <path>
will display a diff :<commit>
, limited to only what affects <path>
. It will also display information about commit <commit>
.git show <commit>:<path>
will display a content :<path>
for commit <commit>
.<path>
points to a file ("a blob" in git terms), you will get the full content of that file ; if <path>
points to a directory ("a tree" in git terms), you will get the listing for that directory.Note that git
does have illogical and contradictory choices in how two different commands interpret their arguments, or how one same command interprets different arguments.
Most of these choices are the result of :
Upvotes: 2
Reputation: 312410
Why is git show bbac89168a2fbbaaa6ef31dc50616dd236c8b5d4 .zshrc different from git show bbac89168a2fbbaaa6ef31dc50616dd236c8b5d4:.zshrc
Because you're running git show <thing>
, and in the first case <thing>
is just a commit. The filename acts as a filter on the commit diff, so you only see the diff for that particular file.
In the second case (<commit>:<path>
), <thing>
is a file in a commit, so you get that instead.
Also, why does git show bbac89168a2fbbaaa6ef31dc50616dd236c8b5d4:.zshrc not work...
I can't reproduce that particular problem (with git 2.31.1). If I have a file named .zshrc
at the top level of the repository, I can run git show <commit>:.zshrc
and git shows me the file contents.
But why is the behavior of git show so illogical and confusing?
Some of these commands have been around for a long time and people have grown to rely on the behavior, confusing though it may be. There have been efforts in recent years to offer more modern alternatives to some commands (see e.g. git switch
, which tries to provide a more obvious interface for some actions that were previously part of git checkout
. I don't know if git show
has been the target of this sort of work.
Upvotes: 1