Posts
Git read-tree: Carbon-Copy without Merge Hell
On this page
Have you ever tried to merge a branch, knowing it would end in merge hell, when all you actually wanted was the code itself?
Maybe you’re working on a feature and realized you went down a rabbit hole. You want to reset your project state to match a clean branch, but you don’t want to lose your current commit history or switch branches. Or perhaps you want to bring in a massive set of changes from a colleague, but you want them staged as a single file update rather than a messy merge history.
Most developers wrestle with git merge or git cherry-pick for this. But there is a simpler, sharper tool for the job: git read-tree.
git read-tree is a photocopier. It copies the state of another branch directly into your staging area. It doesn’t care about history, ancestors, or shared code. It just puts the files where you want them.
(And best of all, it’s already included with git, so there’s nothing else to download or install.)
It’s often considered a “plumbing” command (meant for scripts), but if you understand how it handles the staging area, it becomes one of the fastest ways to force-sync your code.
Note: This does not come without caveats to the original code authors! Any code you borrow from another branch that’s not already in the branch you plan on merging to will wind up being attributed to you, as if you’re the original writer.
How to Use It
Before you begin, and this is very important, you will want to ensure your branch is not currently dirty! That means that you have either committed or stashed away your current copies, and there is nothing in the staging area!
Here is the scenario: You are currently on feature-branch, and you need code from another branch, and there’s not a clean way to merge it without fixing a lot of merge conflicts, but you want to stay on feature-branch, and you want to ensure you have non-breaking changes!
The Simplified git read-tree Workflow:
# Update your branch with the remote branch
git read-tree <other-branch>
You will see a list of files that are both Staged (Green) and Unstaged (Red).
Here is how to read that status output:
- The Staged Changes (Green):
These are the changes that did take effect in the Index. Git is comparing your current HEAD to the new Index (which now looks like main). It is saying: “If you commit right now, we will add all these files from Main.” - The Unstaged Changes (Red):
These are the “changes” that would effectively wipe out what you just staged. Git is comparing the new Index (main) to your old Working Directory (feature-branch). It sees your old files on disk and thinks: “Hey, the file on your disk doesn’t match this new Index. If you add this file now, you’ll revert back to the old version.”
This is the “limbo” state. You have the new code ready to go in the staging area, but your old code is still visible in your uncommitted changes.
To complete the merge, just discard the uncommitted changes! (This is why it is very important to start off without staged or uncommitted changes.)
Why use git read-tree instead of git merge?
In the vast majority of scenarios, you should probably not use git read-tree. The git merge command is the standard, safe, and most comprehensive tool for integrating changes from one branch into another, and it explicitly retains the full, traceable history of both branches.
However, git read-tree serves a very niche, specific purpose. It is essentially a low-level plumbing command that allows you to quickly grab the file contents from another branch and place them directly into your current index—your staging area—without recording the transfer as a standard merge commit.
The Primary Use Case: Code, Not History
The core reason to reach for git read-tree is when all you need is the code from another branch, and you have no need (or desire) to track the lineage or history of that transfer. This is a “surgical” operation, focusing purely on the filesystem state defined by the other branch’s tree object,
The Key Advantage: Conflict Avoidance
The most compelling practical reason for using git read-tree is to sidestep the automatic merge conflict detection process that git merge initiates.
- How
git mergeworks:git mergeattempts a three-way merge, comparing the common ancestor, your branch, and the target branch. If the same lines of code have been changed in both branches since the common ancestor, it flags a conflict and stops, requiring manual resolution. - How
git read-treeworks: When you rungit read-tree <other-branch>, Git simply reads the files from that branch and inserts them into your index. It essentially overwrites what was in your index with the state of the other branch’s files. Because it is not performing a merge analysis, it does not detect or report merge conflicts.
This can be useful if you know that the changes in the target branch are meant to completely supersede the files in your current branch, or if you are deliberately performing a non-standard integration where the merge logic would unnecessarily complicate things.
Caveats and Additional Info
Because git read-tree bypasses standard merge logic and history tracking, it is a destructive and potentially confusing operation if not used with precision.
- History is Lost: The operation itself is not recorded as a merge. If you commit after using
read-tree, the commit will simply look like a normal snapshot with no indication of where the code originated. This makes debugging and rollbacks significantly harder. - No Safety Net: If you use
read-treeon top of existing work, the files from the source branch will overwrite files in your index, potentially discarding your unstaged changes without warning. So long as you start with a clean state, without any staged or uncommited changes, you can easily roll back before committing the new code. - Intermediate Utility:
read-treeis often used by advanced Git users or script writers as a building block for more complex operations, rather than as a primary command for daily workflow.