Created
May 5, 2026 12:28
-
-
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).
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 | |
| 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