Skip to content

Instantly share code, notes, and snippets.

@glowinthedark
Last active June 6, 2026 14:18
Show Gist options
  • Select an option

  • Save glowinthedark/ae6bfbd0624caafa5123a6a688ba944c to your computer and use it in GitHub Desktop.

Select an option

Save glowinthedark/ae6bfbd0624caafa5123a6a688ba944c to your computer and use it in GitHub Desktop.
git-repository-truncate-to-single-commit.sh
#!/usr/bin/env bash
# git_truncate.sh
# Truncates current branch to a single commit (squashes all history)
# and force-pushes to origin.
# Usage: ./git_truncate.sh [remote_name]
# Default remote: origin
set -euo pipefail
REMOTE="${1:-origin}"
BRANCH="$(git rev-parse --abbrev-ref HEAD)"
REPO_ROOT="$(git rev-parse --show-toplevel)"
REPO_NAME="$(basename "$REPO_ROOT")"
BACKUP_PATH="$(dirname "$REPO_ROOT")/${REPO_NAME}_ORIGINAL"
echo ""
echo "⚠️ WARNING: This will PERMANENTLY and IRRECOVERABLY rewrite $REPO_ROOT and force-push to $REMOTE/$BRANCH."
read -rp " Create a backup at ${BACKUP_PATH}? [y/N]: " CONFIRM_BACKUP
if [[ "$CONFIRM_BACKUP" =~ ^[Yy]$ ]]; then
echo "[0] Backing up repo to $BACKUP_PATH ..."
cp -r "$REPO_ROOT" "$BACKUP_PATH"
echo "[0] Backup complete."
else
echo "[0] Skipping backup."
fi
echo "[1] Current branch: $BRANCH | Remote: $REMOTE"
# Capture the current tree state and author/committer info
TREE=$(git write-tree)
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
COMMITTER_NAME=$(git config user.name 2>/dev/null || echo "Truncated")
COMMITTER_EMAIL=$(git config user.email 2>/dev/null || echo "truncated@localhost")
echo "[2] Writing orphan commit over current tree..."
# Create a new root commit with no parents, pointing at current working tree
NEW_COMMIT=$(git commit-tree "$TREE" -m "Initial commit (history truncated on $TIMESTAMP)")
echo "[3] New root commit: $NEW_COMMIT"
# Move HEAD and branch ref to the new orphan commit
git reset --hard "$NEW_COMMIT"
echo "[4] Local branch reset to single commit."
# Force push — rewrites remote history
echo ""
echo "⚠️ DESTRUCTIVE: about to force-push to $REMOTE/$BRANCH — all remote history will be permanently lost."
read -rp " Type '$BRANCH' to confirm: " CONFIRM
if [ "$CONFIRM" != "$BRANCH" ]; then
echo "Aborted. Local repo has already been reset; remote is untouched."
exit 1
fi
echo "[5] Force pushing to $REMOTE/$BRANCH ..."
git push "$REMOTE" "$BRANCH" --force
echo ""
echo "Done. Repo now has exactly $(git rev-list --count HEAD) commit(s) on $BRANCH."
git --no-pager log --oneline
echo 'IMPORTANT: Everyone who cloned the original repo NOW MUST RUN:
git fetch origin
git reset --hard origin/master
^^^^ !!! THIS WILL ZAP ALL LOCAL UNCOMMITTED OR COMMITTED (BUT UNPUSHED) CHANGES
'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment