Is it possible to get a list of files changed in the latest commit in a shallow-clone repository (clone depth = 1)?
In my CI server I would like to fetch only the latest commit, due to performance reasons, and take further actions based on locations of files changed in the latest commit. This is to improve CI's responsiveness by avoiding unnecessary steps.
Currently I am doing fetch with depth of 2, and using the following to detect changes in dir_a
:
diff_dir_a=$( git diff --name-only HEAD^ HEAD -- dir_a )
if [ ${#diff_dir_a} -gt 1 ]; then changes_dir_a=true; else changes_dir_a=false; fi
Depth of 2 is needed to have an ancestor to diff against.
After reading some docs I have found out that I can change the first line to:
diff_dir_a=$( git show --diff-merges=1 --pretty='' --name-only -- dir_a )
I'm using --pretty=''
to suppress the commit information and --diff-merges=1
to show changes agains first parent in case of merge commits.
The second version produces the same output for normal clones, but to my surprise for shallow clone with depth of 1, it lists all files contained in the directory, regardless of whether they were changed in the latest commit.
Is there a way to overcome this?
Is this just a quirk in git's way of handling shallow clones, or is it a bug? I find this misleading that git show
command gives different output for the same commit SHA for repositories cloned with different options.
git
doesn't store diffs, it stores the complete content of each commit.
When git
displays a diff (or a list of changed files, or ...) between two commits, it doesn't output something it has kept in its storage, it computes it by comparing the 2 contents.
Commands that apparently look at 1 commit, like git show
or git log -1
, actually need to also have access to the commit's parent(s) if you want to display "the commit's diff" correctly.
This is the reason why you need at least --depth=2
, and why --depth=1
won't work in your situation.