How to Retrieve Only the File Differences in a Specific Folder from a Pull Request Using a Command
This article is a translated version of my original post on Qiita. Original (Japanese): https://qiita.com/segur/items/14170af605225119be08
How to Retrieve Only the File Differences in a Specific Folder from a Pull Request Using a Command
I intend to create a GitHub Actions workflow that triggers build, test, and deploy only when there are differences in specific folders. I think you've encountered such a situation before!
To solve this issue, I explored scripts to get file differences in a branch. Here's the script I finally came up with!
# Get the base commit of the branch
baseCommit=$( \
{ diff -u <(git rev-list --first-parent ${BRANCH_NAME}) <(git rev-list --first-parent ${TARGET_BRANCH}) || true; } | \
sed -ne 's/^ //p' | \
head -1 \
)
# Get the head commit of the branch
headCommit=`git rev-parse ${BRANCH_NAME}`
# Compare commits and get file differences
git diff ${headCommit} ${baseCommit} --name-only --relative=${DIRECTORY}
BRANCH_NAMEis the branch of the pull request.TARGET_BRANCHis the target branch for merging the pull request.DIRECTORYis the specified directory.
Let me explain this script step by step.
Command to Get the Base Commit of a Branch
The following command allows you to find the commit where the branch diverged.
baseCommit=$( \
{ diff -u <(git rev-list --first-parent ${BRANCH_NAME}) <(git rev-list --first-parent ${TARGET_BRANCH}) || true; } | \
sed -ne 's/^ //p' | \
head -1 \
)
Let's break this down.
First, you can retrieve the commit log of a specified branch using git rev-list, like this:
$ git rev-list --first-parent origin/${BRANCH_NAME}
62d58bf10bd6dd391142311de5f0122fcc13669a
4336e8bed15c4c991703abe67769562c9ea8d9fa
c56fc286b45c61d00e3616c619555fbb21bce95a
108f8ebbf6233ae2d63d088c620611f5b1bb4daa
71b752b3aed0d6ec8b73fe620eb343cad3af469a
(Note: The commit hashes above are fictional.)
Next, we use the diff command to compare the commit logs.
The exit code may result in an error, which can be problematic when using GitHub Actions, so we ensure it always exits with true.
$ { diff -u <(〇〇〇) <(〇〇〇) || true; }
--- /dev/fd/63 2022-04-15 16:49:28.000000000 +0900
+++ /dev/fd/62 2022-04-15 16:49:28.000000000 +0900
@@ -1,4 +1,4 @@
+fddb596c92b46d87dae58969c6b9aa0881a17bda
4336e8bed15c4c991703abe67769562c9ea8d9fa
c56fc286b45c61d00e3616c619555fbb21bce95a
108f8ebbf6233ae2d63d088c620611f5b1bb4daa
Then, using the sed command, you extract lines that do not start with +, -, or @. This fetches a list of common commits between the two branches, as shown below.
$ 〇〇〇 | sed -ne 's/^ //p'
4336e8bed15c4c991703abe67769562c9ea8d9fa
c56fc286b45c61d00e3616c619555fbb21bce95a
108f8ebbf6233ae2d63d088c620611f5b1bb4daa
Finally, using the head command, you obtain the top commit from the list of common commits. This is considered the branch point (i.e., the root of the PR branch).
$ 〇〇〇 | head -1
4336e8bed15c4c991703abe67769562c9ea8d9fe
With this, you've successfully identified the base commit where the branch diverged!
Command to Get the Head Commit of a Branch
Execute the following command to retrieve the hash of the latest commit.
headCommit=`git rev-parse ${BRANCH_NAME}`
Command to Fetch File Differences Between Two Commits
By executing the following command, you can list the file differences between two commits.
git diff ${headCommit} ${baseCommit} --name-only
Command to Fetch File Differences in a Specific Folder Between Two Commits
Adding the relative option to the above command allows you to list only those related to a specific folder!
git diff ${headCommit} ${baseCommit} --name-only --relative=${DIRECTORY}
Bonus: Command to Count the Number of File Differences
To count the number of file differences, use the command below!
count=$( \
git diff ${headCommit} ${baseCommit} --name-only --relative=${DIRECTORY} | \
wc -l \
)
If ${count} is 0, there are no file differences; if it's 1 or more, then there are file differences!
You can integrate this into a GitHub Actions expression to create workflows that execute build, test, and deploy only when there are differences in the specified folder.
Conclusion
In preparing this article, I referred to the following resources. Thank you for the helpful insights.