How do I find the most recent git commit that modified a file?
I want to find the most recent commit that modified a source file.
I can use git blame
to see all the dates for commits by each line, but it’s difficult to see exactly which commit was the last one to touch the file.
How can I find the last commit that touched a given file in my git repository?
Solution 1:
git log
supports looking at the history of specific files (and directories), so you can call it like this:
git log my/file.c
If you really only want to list the one most recent commit, for example to use it in a script, use the -n 1
option:
git log -n 1 --pretty=format:%H -- my/file.c
--pretty=format:%h
tells git log
to show only the commit hash. The --
separater stops the file name from getting interpreted as a commit name, just in case it's ambiguous.
Solution 2:
If you just want to find the most recent commit, then you don't want git-log
, you want git-rev-list
, which lists the commit objects changing that file, in that commit path, starting with the most recent one (chronologically). Simply put:
git rev-list -1 <commit> <filename>
For git-rev-list
in your case, you just supply:
- The number of commits to include, or -1 for only the most recent,
- The branch (or commit id) to start looking back from, HEAD if you are already on it, or --all if you want all known commits, and
- The relative path to your file.
This just returns the most recent commit ID in the current branch to alter that file, ex: 215095e2e338525be0baeeebdf66bfbb304e7270
For a more complex example, you can use tag names, and even remote references, and include relative path names with wildcards, for ex:
git rev-list origin/user/bob/testbranch -1 src/bfiles/*.txt
...Which would tell you what the most recent change was to the wildcard match in that branch's history. The options for rev-list are extreme, it is one of the most important plumbing commands, so you can include or exclude by just about any criteria you can imagine.
Of course, refer to the git-rev-list(1) Manual Page.
Solution 3:
If you want to just get the hash of the latest commit to modify a specific set of files (and want to avoid awk
) you can use:
git log -n 1 --pretty=format:%h -- <path>
This can be useful for getting the commit hash for subsequently using with git describe
.
For example (in case it's useful for anyone)…
I create a current version id by considering the latest commit to change any source file (assuming you mark versions with tags like mycode-1.2.1
):
COMMIT=$(git log -n 1 --pretty=format:%h -- *.c *.h)
if VN=$(git describe --always --abbrev=5 --match "mycode-*" $COMMIT 2>/dev/null) &&
case "$VN" in
mycode-*)
git update-index -q --refresh
test -z "$(git diff-index --name-only HEAD *.c *.h)" ||
VN="$VN-mod" ;;
*) VN="mycode-unknown-g$VN" ;;
esac
then
continue
else
VN="mycode-unknown"
fi
This produces ids like:
-
mycode-1.2.1
- when the current state of the source files corresponds to a tagged version -
mycode-1.2.1-g3k7s2
- when the current state of the source files corresponds to commit following a tagged version -
mycode-1.2.1-g3k7s2-mod
- when the current state of the source files have been modified since the last commit following a tagged version -
mycode-unknown
- when there has not yet been a version tag created