Reputation: 19345
With the git command
git log --follow --pretty='format %H %ae %ai' foo.c
I get a list of changes that affected the file foo.c
. Then, given a hash H from the git log output, I can run
git show H:foo.c
to see the file's contents at that point of time.
This doesn't work if the file has been renamed; git complains:
fatal: Path 'foo.c' exists on disk, but not in '34cd81d75f398ee455e61969b118639dacbfd7a6'.
What is the most efficient way obtain the renamed file's contents?
Upvotes: 2
Views: 55
Reputation: 488183
EDIT: I just realized, you can add the --diff-filter=R
to the git log --follow
command. (I've edited this into the answer.) This cuts down the number of hashes to inspect, to just those that rename the file in question. However, one still must extract the file-rename separately.
Here's the above comment turned into a script ... no claims about how pretty it is or is not. :-) It needs more work to be turned into a real command.
#! /bin/sh
# Find git commits that rename the given path.
identify()
{
local path="$1"
local IFS=$'\t'
# 1) log with follow to extract hashes that rename the file
#
# 2) diff-tree each hash to get the actual rename involved
#
# 3) extract the hash and :<...>R line with old/new paths
git log --follow --pretty='format:%H' --diff-filter=R -- "$path" |
while read hash; do
echo $hash
git diff-tree -M -r --diff-filter=R $hash
done |
while read line; do
case "$line" in
:*)
set -- $line
# $2 is oldname, $3 is new name
# we already have the new name, we need to back
# up to the old one.
[ "$3" != "$path" ] && continue
# at and before this commit, use $2, the old name
echo at and before $hash use $2
path=$2;;
*)
hash=$line;;
esac
done
}
identify builtin/var.c
Upvotes: 2