Skip to content

replay Git Command Guide

The git replay command (EXPERIMENTAL) takes ranges of commits and replays them onto a new location. It leaves the working tree and index untouched, and outputs commands suitable for git update-ref —stdin to update references.

Terminal window
git replay ([--contained] --onto <newbase> | --advance <branch>) <revision-range>...
OptionDescription
--onto <newbase>Replay onto new base commit
--advance <branch>Advance specific branch
--containedInclude only fully contained branches
ParameterDescription
<newbase>New base commit for replay
<branch>Branch to advance
<revision-range>Commit ranges to replay
⚠️ EXPERIMENTAL COMMAND ⚠️
├── Behavior may change in future versions
├── Not recommended for production use
├── Requires careful testing and validation
├── Best used by experienced Git users
└── Always backup repositories before use
When to Use Replay:
├── Repository restructuring without rebase
├── Bare repository operations
├── Complex branch reorganizations
├── Automated repository surgery
└── Advanced Git workflow automation
Replay Workflow:
1. Analyze revision ranges to replay
2. Create new commits on target base
3. Preserve commit metadata (author, date, message)
4. Generate update-ref commands for output
5. Leave working tree and index unchanged
6. Require manual application of changes
Output Format:
├── Commands for git update-ref --stdin
├── Reference updates for replayed branches
├── Preserves branch relationships
└── Safe for manual review before application
Replay vs Rebase:
├── git replay: Works with bare repos, outputs commands
├── git rebase: Interactive, modifies working tree
├── git replay: Batch operations, no working tree changes
├── git rebase: Single branch operations
├── git replay: Multiple branch updates
└── git rebase: Immediate reference updates
Terminal window
# Replay commits onto new base
git replay --onto <new-base> <revision-range>
# Replay feature branch onto main
git replay --onto main feature-branch
# Replay multiple ranges
git replay --onto main branch1 branch2 branch3
# Replay with contained branches
git replay --contained --onto main feature-branch
Terminal window
# Advance branch to new location
git replay --advance <branch> <revision-range>
# Advance main branch
git replay --advance main upstream/main
# Advance with multiple ranges
git replay --advance develop feature-a feature-b
Terminal window
# Capture replay output
git replay --onto main feature > replay-commands.txt
# Review commands before applying
cat replay-commands.txt
# Apply changes
git update-ref --stdin < replay-commands.txt
# Verify changes
git log --oneline --graph --all
Terminal window
# Restructure repository with replay
restructure_repo() {
local new_base="$1"
local branches_to_replay="$2"
echo "Restructuring repository onto $new_base"
# Generate replay commands
replay_commands=$(git replay --onto "$new_base" $branches_to_replay)
# Review changes
echo "Proposed changes:"
echo "$replay_commands"
# Apply with confirmation
read -p "Apply these changes? (y/N): " confirm
if [[ "$confirm" == "y" ]]; then
echo "$replay_commands" | git update-ref --stdin
echo "Repository restructured"
else
echo "Changes not applied"
fi
}
restructure_repo "new-foundation" "feature-a feature-b feature-c"
Terminal window
# Work with bare repositories
bare_repo_replay() {
local bare_repo="$1"
local new_base="$2"
local branches="$3"
echo "Replaying in bare repository: $bare_repo"
# Execute in bare repo context
GIT_DIR="$bare_repo" git replay --onto "$new_base" $branches > commands.txt
# Apply changes
GIT_DIR="$bare_repo" git update-ref --stdin < commands.txt
echo "Bare repository replay complete"
}
bare_repo_replay "/path/to/bare.git" "main" "develop feature"
Terminal window
# Update multiple branches at once
batch_branch_update() {
local new_base="$1"
shift
local branches=("$@")
echo "Batch updating branches onto $new_base"
# Generate combined replay
all_commands=""
for branch in "${branches[@]}"; do
branch_commands=$(git replay --onto "$new_base" "$branch")
all_commands="${all_commands}${branch_commands}"
done
# Apply all at once
echo "$all_commands" | git update-ref --stdin
echo "Batch update complete"
}
batch_branch_update "main" "feature-a" "feature-b" "bugfix-123"
Terminal window
# Configure replay behavior (experimental)
git config replay.experimental true
# Configure update-ref safety
git config core.logAllRefUpdates true
# Configure reflog for safety
git config core.logAllRefUpdates true
Terminal window
# Always backup before replay operations
git branch backup-before-replay
git tag backup-$(date +%Y%m%d-%H%M%S)
# Test replay commands before applying
git replay --onto <base> <range> | head -10
# Verify replay results
git log --oneline --graph --all | head -20
# Use dry-run mentality
# Review all commands before piping to update-ref
# Document replay operations
echo "$(date): Replayed $ranges onto $base" >> .git/REPLAY_LOG
Terminal window
# Validate replay results
validate_replay() {
local original_refs="$1"
local replay_commands="$2"
echo "Validating replay commands..."
# Check command syntax
echo "$replay_commands" | while read -r line; do
if [[ "$line" == update\ refs/* ]]; then
# Valid update-ref command
continue
else
echo "Invalid command: $line"
return 1
fi
done
# Check reference existence
echo "$replay_commands" | grep "update refs/" | cut -d' ' -f2 | while read -r ref; do
if ! git show-ref --verify --quiet "$ref" 2>/dev/null; then
echo "Warning: Reference $ref does not exist"
fi
done
echo "Validation complete"
}
validate_replay "original-refs.txt" "$(cat replay-commands.txt)"
#!/bin/bash
# Automated repository surgery with replay
automated_surgery() {
local surgery_type="$1"
local target_branch="$2"
echo "Performing automated surgery: $surgery_type on $target_branch"
case "$surgery_type" in
"branch-rebase")
# Rebase branch without changing working tree
replay_commands=$(git replay --onto main "$target_branch")
echo "$replay_commands" | git update-ref --stdin
echo "Branch rebased without working tree changes"
;;
"merge-squash")
# Squash merge multiple branches
temp_base=$(git commit-tree -m "Temporary base" main^{tree})
replay_commands=$(git replay --onto "$temp_base" branch1 branch2 branch3)
echo "$replay_commands" | git update-ref --stdin
echo "Branches squashed"
;;
"history-rewrite")
# Rewrite history without rebase
new_base=$(git commit-tree -m "New history start" main^{tree})
replay_commands=$(git replay --onto "$new_base" --contained "$target_branch")
echo "$replay_commands" | git update-ref --stdin
echo "History rewritten"
;;
esac
}
automated_surgery "branch-rebase" "feature/complex"
Terminal window
# CI/CD pipeline with replay
ci_replay_integration() {
echo "CI/CD replay integration"
# Get branches to replay
branches_to_replay=$(git for-each-ref --format='%(refname:short)' refs/heads/feature/*)
# Replay onto main
replay_commands=$(git replay --onto main $branches_to_replay)
# Validate commands
if validate_replay_commands "$replay_commands"; then
# Apply in CI
echo "$replay_commands" | git update-ref --stdin
# Run tests on replayed branches
for branch in $branches_to_replay; do
git checkout "$branch"
run-tests.sh || exit 1
done
echo "CI replay integration successful"
else
echo "Replay validation failed"
exit 1
fi
}
ci_replay_integration
Terminal window
# Aid repository migration with replay
migration_replay() {
local source_repo="$1"
local target_repo="$2"
echo "Aiding migration from $source_repo to $target_repo"
# Get branches from source
source_branches=$(GIT_DIR="$source_repo" git for-each-ref --format='%(refname:short)' refs/heads/)
# Replay branches in target
for branch in $source_branches; do
echo "Replaying $branch..."
# Create replay commands
replay_commands=$(GIT_DIR="$target_repo" git replay --onto main "$branch")
# Apply in target repo
echo "$replay_commands" | GIT_DIR="$target_repo" git update-ref --stdin
done
echo "Migration replay complete"
}
migration_replay "/source/repo.git" "/target/repo.git"
Terminal window
# Fix revision range issues
debug_revision_ranges() {
local ranges="$1"
echo "Debugging revision ranges: $ranges"
# Check range validity
for range in $ranges; do
if ! git rev-parse --verify "$range" >/dev/null 2>&1; then
echo "Invalid range: $range"
# Try to find valid alternatives
git branch -a | grep "$range"
git tag | grep "$range"
fi
done
# Test replay command
if git replay --onto main $ranges >/dev/null 2>&1; then
echo "Ranges are valid"
else
echo "Ranges validation failed"
fi
}
debug_revision_ranges "feature-a feature-b"
Terminal window
# Handle update-ref command problems
fix_update_ref_issues() {
local commands_file="$1"
echo "Fixing update-ref command issues"
# Validate command format
while read -r line; do
if [[ "$line" =~ ^update\ refs/[^[:space:]]+\ [a-f0-9]{40}\ [a-f0-9]{40}$ ]]; then
echo "Valid command: $line"
else
echo "Invalid command format: $line"
return 1
fi
done < "$commands_file"
# Check reference locks
git update-ref --stdin < "$commands_file" 2>&1 | grep -i error
echo "Update-ref validation complete"
}
fix_update_ref_issues "replay-commands.txt"
Terminal window
# Handle bare repository problems
fix_bare_repo_issues() {
local repo_path="$1"
echo "Fixing bare repository issues: $repo_path"
# Verify it's bare
if [ ! -f "$repo_path/HEAD" ] || ! grep -q "bare = true" "$repo_path/config" 2>/dev/null; then
echo "Not a bare repository: $repo_path"
return 1
fi
# Check permissions
if [ ! -w "$repo_path" ]; then
echo "No write permission for repository"
return 1
fi
# Test replay capability
GIT_DIR="$repo_path" git replay --help >/dev/null 2>&1 || {
echo "Replay command not available in this Git version"
return 1
}
echo "Bare repository ready for replay"
}
fix_bare_repo_issues "/path/to/bare.git"
Terminal window
# Optimize replay performance
optimize_replay_performance() {
echo "Optimizing replay performance"
# Use contained mode when possible
git replay --contained --onto main large-range
# Process in smaller batches
# Instead of: git replay --onto main branch1 branch2 branch3
# Use separate calls for large operations
# Clean repository before replay
git gc --quiet
git repack -a -d
# Monitor memory usage
/usr/bin/time -v git replay --onto main large-branch
echo "Performance optimization complete"
}
optimize_replay_performance
Terminal window
# Recover from failed replay operations
recover_failed_replay() {
echo "Recovering from failed replay"
# Check reflog for recovery
git reflog --all | head -20
# Restore from backup
if git show-ref --verify --quiet refs/heads/backup-before-replay; then
git reset --hard backup-before-replay
echo "Restored from backup"
fi
# Clean up partial changes
git update-ref --stdin << EOF
delete refs/heads/partial-replay
EOF
# Verify repository integrity
git fsck --full
echo "Recovery complete"
}
recover_failed_replay
#!/bin/bash
# Consolidate repository branches with replay
consolidate_branches() {
local target_branch="$1"
local branches_to_consolidate="$2"
echo "Consolidating branches into $target_branch"
# Create consolidation base
consolidation_base=$(git commit-tree -m "Branch consolidation base" -p "$target_branch" "$target_branch^{tree}")
# Replay branches onto consolidation base
replay_commands=$(git replay --onto "$consolidation_base" $branches_to_consolidate)
# Review consolidation
echo "Consolidation commands:"
echo "$replay_commands"
# Apply consolidation
echo "$replay_commands" | git update-ref --stdin
# Update target branch
git update-ref "$target_branch" "$consolidation_base"
echo "Branch consolidation complete"
}
consolidate_branches "main" "feature-a feature-b feature-c"
Terminal window
# Automated release branching with replay
automated_release_branching() {
local release_version="$1"
local source_branches="$2"
echo "Creating release $release_version from branches: $source_branches"
# Create release base
release_base=$(git commit-tree -m "Release $release_version base" main^{tree})
# Replay source branches onto release base
replay_commands=$(git replay --onto "$release_base" $source_branches)
# Create release branch
git update-ref "refs/heads/release/$release_version" "$release_base"
# Apply branch updates
echo "$replay_commands" | git update-ref --stdin
# Tag release
git tag -a "v$release_version" "release/$release_version" -m "Release version $release_version"
echo "Release $release_version created"
}
automated_release_branching "2.1.0" "feature-x feature-y"
Terminal window
# Repository surgery for history cleanup
history_cleanup_surgery() {
local bad_commits="$1"
local cleanup_reason="$2"
echo "Performing history cleanup surgery: $cleanup_reason"
# Find commits to remove
commits_to_remove=""
for bad_commit in $bad_commits; do
if git cat-file -t "$bad_commit" >/dev/null 2>&1; then
commits_to_remove="$commits_to_remove $bad_commit"
fi
done
if [ -z "$commits_to_remove" ]; then
echo "No valid commits to remove"
return 1
fi
# Create new history without bad commits
# This is complex and requires careful analysis
echo "Analyzing commit relationships..."
# For each affected branch, replay without bad commits
affected_branches=$(git for-each-ref --contains="$bad_commits" --format='%(refname:short)' refs/heads/)
for branch in $affected_branches; do
echo "Processing branch: $branch"
# Find good base (last good commit)
branch_commits=$(git rev-list "$branch")
good_base=""
for commit in $branch_commits; do
if [[ ! " $bad_commits " =~ " $commit " ]]; then
good_base="$commit"
break
fi
done
if [ -n "$good_base" ]; then
# Replay branch from good base
replay_commands=$(git replay --onto "$good_base" "$branch")
echo "$replay_commands" | git update-ref --stdin
echo "Branch $branch cleaned"
fi
done
echo "History cleanup surgery complete"
}
history_cleanup_surgery "bad123 bad456" "Remove sensitive data"
Terminal window
# Complex repository restructuring
complex_restructure() {
local restructure_plan="$1"
echo "Performing complex repository restructuring"
# Parse restructure plan (simplified example)
# Plan format: "source-branch -> target-base"
while IFS=' -> ' read -r source target; do
echo "Restructuring $source onto $target"
# Validate targets exist
if ! git rev-parse --verify "$target" >/dev/null 2>&1; then
echo "Target $target does not exist"
continue
fi
# Perform replay
replay_commands=$(git replay --onto "$target" "$source")
# Apply changes
echo "$replay_commands" | git update-ref --stdin
echo "Restructured $source onto $target"
done < "$restructure_plan"
echo "Complex restructuring complete"
}
# Create restructure plan
cat > restructure-plan.txt << EOF
feature-a -> main
feature-b -> develop
bugfix-123 -> release/v1.0
EOF
complex_restructure "restructure-plan.txt"
Terminal window
# Disaster recovery using replay
disaster_recovery() {
local backup_repo="$1"
local recovery_branches="$2"
echo "Performing disaster recovery with replay"
# Validate backup repository
if [ ! -d "$backup_repo" ]; then
echo "Backup repository not found: $backup_repo"
return 1
fi
# Get current state
current_refs=$(git for-each-ref --format='%(refname) %(objectname)')
# Replay from backup
for branch in $recovery_branches; do
echo "Recovering branch: $branch"
# Get branch from backup
backup_commit=$(GIT_DIR="$backup_repo" git rev-parse --verify "$branch" 2>/dev/null)
if [ -n "$backup_commit" ]; then
# Replay branch from backup
replay_commands=$(git replay --onto "$backup_commit" "$branch" 2>/dev/null || echo "")
if [ -n "$replay_commands" ]; then
echo "$replay_commands" | git update-ref --stdin
echo "Branch $branch recovered"
else
echo "Could not replay branch $branch"
fi
else
echo "Branch $branch not found in backup"
fi
done
# Verify recovery
git fsck --full
echo "Disaster recovery complete"
}
disaster_recovery "/path/to/backup.git" "main develop"
Terminal window
# Automated repository synchronization
repo_sync_replay() {
local source_repo="$1"
local target_repo="$2"
local sync_branches="$3"
echo "Synchronizing repositories with replay"
# Get branches to sync
for branch in $sync_branches; do
echo "Syncing branch: $branch"
# Get source commit
source_commit=$(GIT_DIR="$source_repo" git rev-parse --verify "$branch" 2>/dev/null)
if [ -n "$source_commit" ]; then
# Check if target needs update
target_commit=$(GIT_DIR="$target_repo" git rev-parse --verify "$branch" 2>/dev/null || echo "")
if [ "$source_commit" != "$target_commit" ]; then
# Replay branch in target
replay_commands=$(GIT_DIR="$target_repo" git replay --onto "$source_commit" "$branch" 2>/dev/null || echo "")
if [ -n "$replay_commands" ]; then
echo "$replay_commands" | GIT_DIR="$target_repo" git update-ref --stdin
echo "Branch $branch synchronized"
fi
else
echo "Branch $branch already in sync"
fi
else
echo "Branch $branch not found in source"
fi
done
echo "Repository synchronization complete"
}
repo_sync_replay "/source/repo.git" "/target/repo.git" "main develop feature"

What’s the difference between replay and rebase?

Section titled “What’s the difference between replay and rebase?”

replay works with bare repositories and outputs update-ref commands; rebase modifies the working tree directly. replay is designed for batch operations and repository surgery.

Yes, replay is specifically designed to work with bare repositories, unlike rebase which requires a working tree.

Pipe the output to git update-ref —stdin: git replay —onto | git update-ref —stdin

Replay is experimental - always backup repositories and test commands before applying. The behavior may change in future Git versions.

—contained includes only branches that are fully contained within the specified revision range, avoiding partial updates.

Can replay update multiple branches at once?

Section titled “Can replay update multiple branches at once?”

Yes, specify multiple revision ranges and replay will generate update commands for all affected branches.

Run replay without applying output, then review the generated update-ref commands before piping to git update-ref —stdin.

No, replay leaves the working tree and index untouched, only generating reference update commands.

Replay works within a single repository. For cross-repository operations, use fetch/push or manual object copying.

What’s the difference between —onto and —advance?

Section titled “What’s the difference between —onto and —advance?”

—onto replays onto any commit; —advance specifically advances a named branch to new commits.

Check reflog for recovery points, restore from backup branches/tags, or use git fsck to verify repository integrity.

Yes, replay preserves merge commit structure and parent relationships during replay operations.

What’s the performance impact of replay?

Section titled “What’s the performance impact of replay?”

Replay can be intensive for large repositories with many branches. Use —contained and limit ranges for better performance.

Yes, but with caution due to experimental nature. Use for automated repository maintenance and branch management.

Parse the output to ensure valid update-ref command format and verify target references exist.

No, replay is designed for automated/batch operations. Use rebase for interactive history modification.

Yes, as long as the remote branches exist locally. Use fetch to ensure remote branches are available.

  1. Repository Surgery: Complex branch reorganizations without working tree changes
  2. Bare Repository Operations: Work with repositories without working directories
  3. Batch Branch Updates: Update multiple branches simultaneously
  4. Automated Workflows: CI/CD integration for repository maintenance
  5. Disaster Recovery: Restore repository state from backups
  6. History Restructuring: Reorganize commit history without rebase conflicts