Skip to content

Instantly share code, notes, and snippets.

@basilevs
Last active May 19, 2026 19:21
Show Gist options
  • Select an option

  • Save basilevs/0b83f0fb13303235bc7788c8068f51ae to your computer and use it in GitHub Desktop.

Select an option

Save basilevs/0b83f0fb13303235bc7788c8068f51ae to your computer and use it in GitHub Desktop.
replace_squash.sh
#!/bin/bash
# Replaces current HEAD (last commit of active branch) with squashed content of a branch merge/<current_branch>.
# Leave the original commit message inteact (ignore all messages from the squashed commits)
# This script in intended for interaction with OSS projects which only accept single commit in a PR
set -euo pipefail
# Ensure we're in a git repo
if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
echo "Error: not inside a Git repository" >&2
exit 1
fi
current_branch="$(git rev-parse --abbrev-ref HEAD)"
branch="merge/$current_branch"
# Ensure the branch exists
if ! git rev-parse --verify "$branch" >/dev/null 2>&1; then
echo "Error: branch '$branch' does not exist" >&2
exit 1
fi
# Save the original HEAD so we can revert on failure
original_head="$(git rev-parse HEAD)"
# Save the current commit message
commit_msg="$(git log -1 --format=%B)"
# Determine the upstream branch name
if git rev-parse --verify main >/dev/null 2>&1; then
upstream=main
elif git rev-parse --verify master >/dev/null 2>&1; then
upstream=master
else
echo "Error: neither 'main' nor 'master' branch exists" >&2
exit 1
fi
# Update upstream without relying on explicit remote name
git switch "$upstream"
git pull
# Maintain the merge bracnh to avoid discrepancies after squash
git switch "$branch"
git merge --no-edit "$upstream"
# Hard-reset HEAD to discard the last commit entirely
git switch "$current_branch"
git reset --hard "$upstream"
# Merge the branch's content into the index (squash, no commit)
git merge --squash "$branch"
# Commit everything with the original message
git commit --no-edit -m "$commit_msg"
# Verify the squashed commit tree matches the branch tree exactly
if [ "$(git rev-parse HEAD^{tree})" != "$(git rev-parse "$branch"^{tree})" ]; then
echo "Error: tree content differs between squashed commit and $branch" >&2
git reset --hard "$original_head"
exit 1
fi
# Record a merge on the branch so it knows about the squashed commit
squashed_commit="$(git rev-parse HEAD)"
git checkout "$branch"
git merge --no-ff -m "Merge squashed commit from $current_branch" "$squashed_commit"
git checkout "$current_branch"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment