Skip to content

Instantly share code, notes, and snippets.

@JackNoordhuis
Created May 5, 2026 12:28
Show Gist options
  • Select an option

  • Save JackNoordhuis/8f7a7dfe616bef16d47a90e5c1df8385 to your computer and use it in GitHub Desktop.

Select an option

Save JackNoordhuis/8f7a7dfe616bef16d47a90e5c1df8385 to your computer and use it in GitHub Desktop.
Push a branch to a remote in commit-sized chunks (default: 50 commits per push).
#!/usr/bin/env bash
set -euo pipefail
# Push a branch to a remote in commit-sized chunks (default: 50 commits per push).
# Usage: ./push_in_chunks.sh [remote] [branch] [chunk_size]
remote="${1:-origin}"
branch="${2:-$(git rev-parse --abbrev-ref HEAD)}"
chunk_size="${3:-50}"
if ! [[ "$chunk_size" =~ ^[0-9]+$ ]] || [ "$chunk_size" -lt 1 ]; then
echo "Error: chunk_size must be a positive integer." >&2
exit 1
fi
if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
echo "Error: run this script inside a git repository." >&2
exit 1
fi
if ! git remote get-url "$remote" >/dev/null 2>&1; then
echo "Error: remote '$remote' does not exist." >&2
exit 1
fi
if ! git show-ref --verify --quiet "refs/heads/$branch"; then
echo "Error: local branch '$branch' does not exist." >&2
exit 1
fi
git fetch "$remote" --quiet || true
if git show-ref --verify --quiet "refs/remotes/$remote/$branch"; then
range="$remote/$branch..$branch"
else
range="$branch"
fi
mapfile -t commits < <(git rev-list --reverse --first-parent "$range")
total=${#commits[@]}
if [ "$total" -eq 0 ]; then
echo "Nothing to push. '$branch' is already up to date on '$remote'."
exit 0
fi
echo "Force-pushing $total commit(s) from '$branch' to '$remote/$branch' in chunks of $chunk_size..."
last_pushed_index=-1
for ((i = chunk_size - 1; i < total; i += chunk_size)); do
target_commit="${commits[$i]}"
echo " -> pushing through commit $((i + 1))/$total ($target_commit)"
git push --force "$remote" "$target_commit:refs/heads/$branch"
last_pushed_index=$i
done
if [ "$last_pushed_index" -ne $((total - 1)) ]; then
final_commit="${commits[$((total - 1))]}"
echo " -> pushing final commit $total/$total ($final_commit)"
git push --force "$remote" "$final_commit:refs/heads/$branch"
fi
echo "Done. '$remote/$branch' is now at local '$branch'."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment