Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save franklinharvey/5ffade0a4c0474d233001671dd5977af to your computer and use it in GitHub Desktop.
Save franklinharvey/5ffade0a4c0474d233001671dd5977af to your computer and use it in GitHub Desktop.
Git replay vs. commit tree
#!/bin/bash
set -e
# Clean up any existing test repo
rm -rf /tmp/git-repro-test
mkdir -p /tmp/git-repro-test
cd /tmp/git-repro-test
# Initialize repo
git init --initial-branch=main
git config user.name "Test User"
git config user.email "[email protected]"
echo "=== Setting up test scenario ==="
# Create initial commit on main
echo "Initial content" > file.txt
git add file.txt
git commit -m "Initial commit"
INITIAL_COMMIT=$(git rev-parse HEAD)
echo "Initial commit: $INITIAL_COMMIT"
# Create some progress on main
echo "Progress 1" >> file.txt
git add file.txt
git commit -m "Progress 1"
PROGRESS_1_COMMIT=$(git rev-parse HEAD)
echo "Progress 2" >> file.txt
git add file.txt
git commit -m "Progress 2"
echo "Progress 3" >> file.txt
git add file.txt
git commit -m "Progress 3"
MAIN_HEAD=$(git rev-parse HEAD)
echo "Main HEAD: $MAIN_HEAD"
# Create a feature branch from Progress 1 (not the root)
git checkout $PROGRESS_1_COMMIT
git checkout -b feature-branch
echo "Feature work" >> file1.txt
git add file1.txt
git commit -m "Feature work"
FEATURE_COMMIT=$(git rev-parse HEAD)
echo "Feature commit: $FEATURE_COMMIT"
# Now we can replay from Progress 1 to Feature commit
FEATURE_BASE=$PROGRESS_1_COMMIT
# Show current state
echo "=== Current state ==="
echo "Main branch content:"
git show main:file.txt | sed 's/^/ /'
echo ""
echo "Feature branch content:"
git show HEAD:file.txt | sed 's/^/ /'
echo ""
echo "============================================================"
echo "BROKEN APPROACH: Using original commit tree"
echo "============================================================"
git checkout main >/dev/null 2>&1
echo "Before broken commit-tree:"
cat file.txt | sed 's/^/ /'
echo ""
# Create commit using the feature's tree directly (THIS IS BROKEN)
BROKEN_COMMIT=$(git commit-tree $FEATURE_COMMIT^{tree} -p HEAD -m "BROKEN: Feature work transplanted")
echo "Created broken commit: $BROKEN_COMMIT"
# Apply the broken commit
git reset --hard $BROKEN_COMMIT >/dev/null 2>&1
echo "After broken commit-tree:"
cat file.txt | sed 's/^/ /'
echo ""
echo "^ Notice: Progress 2 and Progress 3 are missing"
echo ""
echo "============================================================"
echo "CORRECT APPROACH: Using git replay"
echo "============================================================"
# Reset back to main
git reset --hard $MAIN_HEAD >/dev/null 2>&1
echo "Before correct approach:"
cat file.txt | sed 's/^/ /'
echo ""
# Use git replay to properly merge the feature work
echo "Running git replay..."
echo "Command: git replay --onto HEAD $FEATURE_BASE..$FEATURE_COMMIT"
# Check what commits would be replayed first
echo "Checking what commits would be replayed:"
git rev-list $FEATURE_BASE..$FEATURE_COMMIT
# Try git replay
echo "Executing git replay..."
if git replay --onto HEAD $FEATURE_BASE..$FEATURE_COMMIT; then
echo "Replay succeeded with no conflicts!"
# Get the new commit SHA - git replay should output it
NEW_COMMIT=$(git log -1 --format=%H)
echo "New commit from replay: $NEW_COMMIT"
else
REPLAY_EXIT_CODE=$?
echo "Git replay failed with exit code: $REPLAY_EXIT_CODE"
if [ $REPLAY_EXIT_CODE -eq 1 ]; then
echo "This indicates conflicts during replay."
echo "Let's check what files have conflicts:"
git status
echo ""
echo "For demonstration purposes, this shows why using the old tree"
echo "with commit-tree was wrong - it bypassed this conflict resolution"
echo "that should have happened."
NEW_COMMIT="(conflicts - would need manual resolution)"
else
echo "This indicates some other error with replay."
NEW_COMMIT="(replay failed)"
fi
fi
echo ""
echo "============================================================"
echo "SUMMARY"
echo "============================================================"
echo "The broken approach reverts commits because it uses the original feature"
echo "commit's tree, which is based on an older state of main."
echo ""
echo "The git replay command properly handles conflicts and merging, which is"
echo "why using commit-tree with the old tree was dangerous - it bypassed"
echo "all conflict resolution that should have happened."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment