Skip to content

Git Squash to Single Commit

Create a fresh repository with a single commit, preserving current state

Metadata

  • Author: Wei
  • Version: 1.0.0
  • Dependencies: git

This will completely remove all Git history!

Code

bash
#!/bin/bash
# @title Git Squash to Single Commit
# @description Create a fresh repository with a single commit, preserving current state
# @author Wei
# @version 1.0.0
#
# This script creates a completely new Git history with just one commit containing
# all current files. This is useful when you want to start fresh without any history.
#
# @example
# Usage:
#   ./git-squash-to-single-commit.sh [commit-message]
#   ./git-squash-to-single-commit.sh "Initial commit"
#
# @requires git
# @note This will completely remove all Git history!

set -e

# Color codes for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# Configuration
NEW_AUTHOR_NAME="Wei Guo"
NEW_AUTHOR_EMAIL="wei.guo@moodys.com"
DEFAULT_MESSAGE="Initial commit - consolidated history"

# Function to print colored messages
print_info() {
    echo -e "${GREEN}[INFO]${NC} $1"
}

print_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

print_warning() {
    echo -e "${YELLOW}[WARNING]${NC} $1"
}

print_step() {
    echo -e "${BLUE}[STEP]${NC} $1"
}

# Get commit message from argument or use default
COMMIT_MESSAGE="${1:-$DEFAULT_MESSAGE}"

# Check if we're in a git repository
if ! git rev-parse --git-dir > /dev/null 2>&1; then
    print_error "Not a git repository"
    exit 1
fi

# Check if there are uncommitted changes
if ! git diff-index --quiet HEAD -- 2>/dev/null; then
    print_error "You have uncommitted changes. Please commit or stash them first."
    exit 1
fi

# Get current branch
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
print_info "Current branch: $CURRENT_BRANCH"

echo ""
print_warning "This will:"
echo "  1. Delete ALL Git history"
echo "  2. Create a single new commit with all current files"
echo "  3. Use author: $NEW_AUTHOR_NAME <$NEW_AUTHOR_EMAIL>"
echo "  4. Commit message: $COMMIT_MESSAGE"
echo ""
print_warning "This operation CANNOT be easily undone!"
echo ""

# Ask for confirmation
read -p "Are you sure you want to continue? (yes/no): " -r
echo
if [[ ! $REPLY =~ ^[Yy][Ee][Ss]$ ]]; then
    print_info "Operation cancelled"
    exit 0
fi

# Create backup branch
BACKUP_BRANCH="backup-before-squash-$(date +%Y%m%d-%H%M%S)"
print_step "Creating backup branch: $BACKUP_BRANCH"
git branch "$BACKUP_BRANCH"
print_info "Backup created at: $BACKUP_BRANCH"

# Store the current tree
print_step "Saving current state..."
TREE=$(git write-tree)

# Create a new commit with the current tree
print_step "Creating new commit..."
export GIT_AUTHOR_NAME="$NEW_AUTHOR_NAME"
export GIT_AUTHOR_EMAIL="$NEW_AUTHOR_EMAIL"
export GIT_COMMITTER_NAME="$NEW_AUTHOR_NAME"
export GIT_COMMITTER_EMAIL="$NEW_AUTHOR_EMAIL"

NEW_COMMIT=$(git commit-tree "$TREE" -m "$COMMIT_MESSAGE")

# Reset current branch to the new commit
print_step "Resetting branch to new commit..."
git reset --hard "$NEW_COMMIT"

# Clean up
unset GIT_AUTHOR_NAME
unset GIT_AUTHOR_EMAIL
unset GIT_COMMITTER_NAME
unset GIT_COMMITTER_EMAIL

echo ""
print_info "Successfully created fresh history!"
echo ""
print_step "New commit details:"
git log --format=fuller -1

echo ""
print_warning "Next steps:"
echo "  1. Review the changes: git log"
echo "  2. If satisfied, force push: git push --force-with-lease"
echo "  3. If you need to undo, restore backup: git reset --hard $BACKUP_BRANCH"
echo "  4. Delete backup branch when done: git branch -D $BACKUP_BRANCH"
echo ""

exit 0

File Information

  • Filename: git-squash-to-single-commit.sh
  • Category: git
  • Language: BASH

View on GitHub