Last active
September 4, 2018 08:03
-
-
Save jonico/eed8f560f774cf71f7d0aff28f944966 to your computer and use it in GitHub Desktop.
Example how to compute diffs of more than 300 files between branches/commits/tags server side using a pre-receive hook in GitHub Enterprise
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# Client side script to trigger pre-receive hook and scan its output | |
# usage: diff-branches-client.sh <repo URL> <compare branch> [base branch] [magic trigger branch] | |
# Examples: | |
# diff-branches.client.sh https://[email protected]/jonico/large-branch-diff-with-prereceive-hook.git compare-branch feature-branch # diffs compare-branch with feature branch | |
# diff-branches.client.sh https://[email protected]/jonico/large-branch-diff-with-prereceive-hook.git compare-branch # diffs compare-branch with master | |
# diff-branches.client.sh https://[email protected]/jonico/large-branch-diff-with-prereceive-hook.git f75b18abbb06 f75b18abbb06^1 # diffs commit f75b18abbb06 with its parent | |
# diff-branches.client.sh https://[email protected]/jonico/large-branch-diff-with-prereceive-hook.git master master~2 # diffs latest commit on master with its grandparent | |
if [ "$#" -lt "2" ]; then | |
echo "Usage: diff-branches-client.sh <repo URL> <compare branch> [base branch] [magic trigger branch]" | |
exit 1 | |
fi | |
WORK_DIR=`mktemp -d` | |
repo=$1 | |
compareBranch=$2 | |
baseBranch=${3:-master} | |
magicTrigger=${4:-diff-branches} | |
# check if tmp dir was created | |
if [[ ! "$WORK_DIR" || ! -d "$WORK_DIR" ]]; then | |
echo "Could not create temp dir" | |
exit 1 | |
fi | |
# deletes the temp directory | |
function cleanup { | |
rm -rf "$WORK_DIR" | |
} | |
# register the cleanup function to be called on the EXIT signal | |
trap cleanup EXIT | |
cd $WORK_DIR | |
git init --quiet | |
echo "Commit to trigger something" >> trigger.txt | |
git add trigger.txt | |
git commit --quiet -am "Trigger pre-receive hook" | |
git push -f "${repo}" "HEAD:${magicTrigger}" "--push-option=${compareBranch}" "--push-option=${baseBranch}" 2>rawOutput | |
startMarker="${magicTrigger}: Starting diff" | |
endMarker="${magicTrigger}: Finished diff" | |
grep -q "$endMarker" rawOutput | |
if [ $? -ne "0" ]; then | |
echo Could not find magic marker. | |
echo Printing output from git push "${repo}" "HEAD:${magicTrigger}" "--push-option=${compareBranch}" "--push-option=${baseBranch}": | |
cat rawOutput | |
exit 1 | |
fi | |
# Extract everything between start and end marker and remove "remote: " - prefix | |
awkPattern='/remote: /{sub("remote: ","")'"}/$startMarker/"'{flag=1;next}'"/$endMarker/"'{flag=0}flag' | |
awk "$awkPattern" rawOutput |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# | |
# Pre-receive hook that will show the output of the diff of two branches computed server side | |
# | |
# Most GitHub API calls are designed to limit their output to a number of objects for performance reasons. | |
# For instance, https://developer.github.com/enterprise/v3/pulls/#list-pull-requests-files or | |
# https://developer.github.com/v3/repos/commits/#get-a-single-commit | |
# are paged with a batch size of 30 and will not list more than 300 files. | |
# | |
# If GitHub Enterprise customers need to diff branches/commits/tags with more than 300 files changed and understand the impact this has on the load of their instance, this script shows how to do it. | |
# This script intercepts pushes to a magic branch, called diff-large-branch (can be changed) and will output the files changed between two (real) branches of the same repository | |
# The two branche/commits/tags to compare can be specified using --push-options (see usage example) | |
# | |
# If no base branch is specified, master is assumed | |
# What you actually push does not matter as it will be rejected anyways | |
# | |
# Usage: git push origin HEAD:diff-branches --push-option=<compareBranch> [--push-option=<baseBranch>] | |
# | |
# Examples: | |
# git push origin HEAD:diff-branches --push-option=compare-branch --push-option=feature-branch # compare compare-branch with feature-branch | |
# git push origin HEAD:diff-branches --push-option=compare-branch # compare compare-branch with master | |
# git push origin HEAD:diff-branches --push-option=master --push-option=master^1 # compare latest commit on master with its parent | |
# git push origin HEAD:diff-branches --push-option=f75b18abbb06 --push-option=f75b18abbb06^1 # compare commit f75b18abbb06 with its parent | |
# | |
# If you do not like the idea of pushing to a magic branch, you could also use a magic trigger as first --push-option | |
# | |
# More details on pre-receive hooks and how to apply them can be found on | |
# https://help.github.com/enterprise/admin/guides/developer-workflow/managing-pre-receive-hooks-on-the-github-enterprise-appliance/ | |
# | |
# trigger branch to push to so that this hook gets active | |
trigger="diff-branches" | |
while read oldrev newrev refname; do | |
if [ "$refname" = "refs/heads/$trigger" ]; then | |
if [ "$GIT_PUSH_OPTION_COUNT" -lt "1" ]; then | |
echo $trigger: "Usage: git push origin HEAD:$trigger --push-option=<compareBranch> [--push-option=<baseBranch>]" | |
exit 1 | |
fi | |
compareBranch=$GIT_PUSH_OPTION_0 | |
baseBranch=${GIT_PUSH_OPTION_1:-master} | |
echo $trigger: "Starting diff from ${baseBranch} to ${compareBranch}" | |
git diff --name-status "$baseBranch" "$compareBranch" | |
echo $trigger: "Finished diff" | |
exit 42 | |
else | |
continue | |
fi | |
done | |
exit 0 |
Example usage for client script (does not need any local clone of the repository):
$ ./diff-branches-client.sh https://[email protected]/jonico/large-branch-diff-with-prereceive-hook.git compare-branch
A 100.binary
A 101.binary
... 800+ lines omitted ...
A 997.binary
A 998.binary
A 999.binary
M README.md
M block_file_extensions.sh
D diff-large-branches.sh
Example on how to diff a specific commit:
$ ./diff-branches-client.sh https://[email protected]/jonico/large-branch-diff-with-prereceive-hook.git f75b18abbb06 f75b18abbb06^1
M README.md
Example on how to diff the latest commit on master with its predecessor:
$ ./diff-branches-client.sh https://[email protected]/jonico/large-branch-diff-with-prereceive-hook.git master master^1
A diff-branches-client.sh
M diff-large-branches.sh
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Example usage: