A powerful tool for managing and rebasing chains of dependent Git branches (stacked branches).
When working on complex features, developers often create a series of branches where each branch builds upon the previous one. For example:
I---J---K feature-2
/
E---F---G feature-1
/
A---B---C---D master
When new changes are added to the master branch, updating all branches in the chain becomes tedious and error-prone:
feature-1 onto the updated masterfeature-2 onto the updated feature-1Git Chain automates this entire process. It keeps track of relationships between branches and handles the rebasing for you.
main or master) that the chain ultimately merges into.Note: - A branch can belong to at most one chain. - The root branch is not part of the chain, but serves as its foundation.
Git Chain stores branch relationships in your repository's Git config, tracking: - Which chain a branch belongs to - The order of branches within a chain - Each branch's root branch
Git Chain offers two strategies for updating branches: 1. Rebase: Rewrites branch history by replaying commits on top of the updated parent branch 2. Merge: Preserves branch history by creating merge commits that incorporate changes from the parent branch
When operating on chains, Git Chain:
1. Determines the correct fork-point for each branch using git merge-base --fork-point
2. Updates each branch in sequence, preserving the dependency order
3. Handles edge cases like squash merges and chain reorganization
When you run git chain rebase, git-chain intelligently updates each branch in your chain to incorporate changes from its parent branch. Think of it like moving your work to sit on top of the latest version of your parent branch. This rewrites commit history, giving a cleaner, linear history but generating new commit hashes.
Order Matters: Branches are updated in the order they appear in the chain, starting from the one closest to the root branch. This ensures each branch builds upon an already-updated parent.
Finding the Right Starting Point: For each branch, git-chain determines where your branch originally split from its parent. This point (called a "fork-point") is crucial for keeping only your changes when rebasing.
What is a fork-point? A fork-point is the specific commit where you originally created your branch from its parent. It's more intelligent than just finding a common ancestor - Git uses its reflog (a history of where branch tips have been) to determine the exact point where your branch's history forked from the parent branch. This is especially useful when the parent branch has been rebased or reorganized since you created your branch. When rebasing, Git needs to know this point to correctly identify which commits belong to your branch (and should be moved) versus which commits were already in the parent branch (and should be left alone).
Note on the Fallback Mechanism: Sometimes Git can't determine the fork-point, particularly in these situations: - When older reflog entries have been cleaned up by
git gc- If you created your branch from an older commit (not the tip) of the parent branch - After certain operations that affect repository historyWhen Git's fork-point detection fails, git-chain automatically falls back to using
git merge-base, which finds the most recent common ancestor between two branches. While this ensures rebasing can proceed, it might be less precise than using the true fork-point.
Handling Squash Merges: If you've squash-merged a branch into its parent (combining all commits into one), git-chain detects this and prevents duplicate changes.
The Actual Rebasing: For each branch, git-chain runs a command similar to:
git rebase --keep-empty --onto <parent_branch> <fork_point> <branch>
This moves your changes to sit on top of the updated parent branch.
To read more about fork-point, see: https://git-scm.com/docs/git-merge-base#_discussion_on_fork_point_mode
Git Chain's rebase command offers customization through its flags:
--step, -s: Rebase one branch at a time, requiring manual confirmation between steps
git chain rebase --step
Perfect for carefully managing complex rebases where conflicts might occur.
--ignore-root, -i: Skip rebasing the first branch onto the root branch
git chain rebase --ignore-root
Useful when you want to update relationships between chain branches without incorporating root branch changes.
git chain rebase)Here are some common scenarios and how to handle them with git-chain rebase:
Scenario: You want to update all branches in the chain to incorporate changes from their parent branches.
Solution:
git chain rebase
This rebases all branches in the chain sequentially, starting from the one closest to the root branch.
Scenario: You want to update only relationships between branches in a chain, not incorporating new root branch changes.
Solution:
git chain rebase --ignore-root
This skips rebasing the first branch onto the root branch.
Scenario: You anticipate conflicts and want to handle each branch separately.
Solution:
git chain rebase --step
This rebases one branch at a time, waiting for your confirmation between steps.
When rebasing branches in a chain, conflicts can sometimes occur. Git Chain handles conflicts as follows:
May create automatic backup branches if conflicts are detected
Resolution Process:
<<<<<<<, =======, >>>>>>>)git add <file>Continue the rebase with git rebase --continue
Continuing After Resolution:
git chain rebaseGit Chain will pick up where it left off, continuing with the remaining branches
Aborting a Problematic Rebase:
git rebase --abortgit checkout branch-name
git reset --hard branch-name-backupExample Conflict Workflow:
$ git chain rebase
Rebasing branch feature/auth onto master...
Auto-merging src/auth.js
CONFLICT (content): Merge conflict in src/auth.js
error: could not apply 1a2b3c4... Add authentication feature
# Resolve the conflict
$ vim src/auth.js
$ git add src/auth.js
$ git rebase --continue
Successfully rebased branch feature/auth
Rebasing branch feature/profiles onto feature/auth...
# Continues with remaining branches
If a rebase goes wrong, Git Chain provides several recovery options:
Backup Branches: If you used --backup, you can restore using:
git checkout branch-name
git reset --hard branch-name-backup
Reflog: Even without backups, you can recover using Git's reflog:
git checkout branch-name
git reflog
git reset --hard branch-name@{1} # Reset to previous state
Abort In-Progress Rebase: If a rebase is still in progress:
git rebase --abort
When you run git chain merge, git-chain cascades merges through your branch chain by merging each parent branch into its child branch. Unlike rebasing, merging preserves the original commit history by creating merge commits that link branches together.
Order Matters: Branches are updated in the order they appear in the chain, starting from the one closest to the root branch. Each branch incorporates changes from its parent through a merge.
Finding the Right Starting Point: Git Chain uses the same intelligent fork-point detection as in rebasing to identify the best common ancestor for each merge.
Smart Detection: Git Chain checks for special cases:
If there are merge conflicts that need manual resolution
The Actual Merging: For each branch, git-chain runs a command similar to:
git checkout <branch>
git merge <parent_branch>
This incorporates all changes from the parent branch while preserving the branch's original commit history.
Git Chain's merge command offers extensive customization through various flags and options:
--verbose, -v: Provides detailed output during the merging process
git chain merge --verbose
Shows exactly what's happening with each branch, including Git's merge output.
--ignore-root, -i: Skips merging the root branch into the first branch
git chain merge --ignore-root
Useful when you want to update relationships between branches in the chain without incorporating root branch changes.
--stay: Don't return to the original branch after merging
git chain merge --stay
By default, git-chain returns you to your starting branch. Use this flag to remain on the last merged branch.
--chain=<name>: Operate on a specific chain other than the current one
git chain merge --chain=feature-x
Allows you to merge a chain even when you're not on a branch that belongs to it.
--simple, -s: Use simple merge mode without advanced detection
git chain merge --simple
Disables fork-point detection and squashed merge handling for a faster, simpler merge process.
--fork-point, -f: Use Git's fork-point detection (default behavior)
git chain merge --fork-point
Explicitly enables fork-point detection for finding better merge bases.
--no-fork-point: Disable fork-point detection, use regular merge-base
git chain merge --no-fork-point
Can be faster but potentially less accurate. Useful for repositories with limited reflog history.
--squashed-merge=<mode>: How to handle branches that appear squash-merged
git chain merge --squashed-merge=reset # Default: reset to match parent branch
git chain merge --squashed-merge=skip # Skip branches that appear squashed
git chain merge --squashed-merge=merge # Force merge despite the detection
Controls behavior when Git Chain detects that a branch appears to have been squash-merged into its parent.
Fast-forward behavior:
git chain merge --ff # Allow fast-forward if possible (default)
git chain merge --no-ff # Always create a merge commit
git chain merge --ff-only # Only allow fast-forward merges
Controls how Git handles cases where a branch can be fast-forwarded.
--squash: Create a single commit instead of a merge commit
git chain merge --squash
Combines all changes from the source branch into a single commit.
--strategy=<strategy>: Use a specific Git merge strategy
git chain merge --strategy=recursive
git chain merge --strategy=ours
Specifies which Git merge strategy to use (e.g., recursive, resolve, octopus).
--strategy-option=<option>: Pass strategy-specific options
git chain merge --strategy=recursive --strategy-option=ignore-space-change
git chain merge --strategy=recursive --strategy-option=patience
Customizes the behavior of the selected merge strategy.
git chain merge --report-level=minimal # Basic success/failure messages
git chain merge --report-level=standard # Summary with counts (default)
git chain merge --report-level=detailed # Comprehensive per-branch details
git chain merge --no-report # Suppress merge summary report
git chain merge --detailed-report # Same as --report-level=detailed
Controls how much information is displayed after the merge completes.git chain merge)Here are some common scenarios and how to handle them with git-chain merge:
Scenario: You have multiple PRs open,
$ claude mcp add git-chain \
-- python -m otcore.mcp_server <graph>