Created
June 30, 2025 13:11
-
-
Save franklinharvey/5ffade0a4c0474d233001671dd5977af to your computer and use it in GitHub Desktop.
Git replay vs. commit tree
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
| #!/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