This procedure merges two Git repositories while preserving the complete commit history of both repositories.
Goal
We have:
- Repo A — the final/main repository
- Repo B — the repository being imported
- Repo B should appear inside Repo A under the
priorwork/directory - Both repositories use the
mainbranch
The final layout should look like:
repo-A/
├── existing files from Repo A
└── priorwork/
├── files from Repo B
└── ...
Both repositories' Git histories will be preserved.
1. Start with a fresh clone of Repo B
Do not run git filter-repo inside Repo A.
Clone Repo B into a separate directory:
git clone <REPO-B-URL> repo-B
cd repo-B
Make sure you are on Repo B's main branch:
git checkout main
2. Rewrite Repo B so its files live under priorwork/
Run this command inside the fresh Repo B clone:
git filter-repo --to-subdirectory-filter priorwork
Because this is a fresh clone, you should not need --force.
Verify the result:
git ls-tree -r HEAD --name-only | head -20
You should see paths like:
priorwork/.gitignore
priorwork/README.md
priorwork/file1...
priorwork/src/...
This confirms that Repo B's files have been moved under priorwork/ in its history.
3. Go to Repo A
Switch to the final repository:
cd ../repo-A
Make sure you are on the branch that should receive Repo B:
git checkout main
Check that your working tree is clean:
git status
Ideally, Git should report:
nothing to commit, working tree clean
4. Add the rewritten Repo B as a remote
From inside Repo A:
git remote add priorwork ../repo-B
Verify:
git remote -v
You should see something similar to:
origin <REPO-A-URL>
priorwork ../repo-B
Here, priorwork is simply the name of the Git remote. It is not a directory in the working tree.
5. Fetch Repo B's rewritten history
Run:
git fetch priorwork
This downloads Repo B's Git history into Repo A's .git directory.
It does not create a priorwork/ directory in the working tree yet.
Verify that Repo B's files are stored under the desired path:
git ls-tree -r priorwork/main --name-only | head -20
You should see:
priorwork/.gitignore
priorwork/README.md
priorwork/file1...
priorwork/src/...
This confirms that Repo B was correctly rewritten before the merge.
6. Merge the two histories
Now merge Repo B into Repo A:
git merge priorwork/main --allow-unrelated-histories
The --allow-unrelated-histories option is required because Repo A and Repo B originally had independent Git histories.
If there are no conflicts, the merge should complete successfully.
The working tree should now look approximately like:
repo-A/
├── .git/
├── <Repo A files>
├── ...
└── priorwork/
├── .gitignore
├── README.md
├── file1...
└── src/
├── ...
└── ...
7. Verify that both histories were preserved
View the complete commit graph:
git log --graph --oneline --all --decorate
You should see the two independent histories joining at the merge commit.
You can also inspect Repo B's history:
git log --oneline priorwork/main
And inspect all history:
git log --oneline --all
8. Push the combined repository
Once everything has been verified:
git push origin main
The remote Repo A repository will now contain:
- Repo A's original files
- Repo B's files under
priorwork/ - Repo A's complete Git history
- Repo B's complete Git history
- A merge commit connecting the two histories
Important Concept
The overall process is:
Rewrite Repo B
Repo B ───────────────────────────►
Repo B'
priorwork/
│
│
Repo A ───────────────────────────────►│
merge │
▼
Combined Repo A
├── Repo A files
└── priorwork/
└── Repo B files
The most important rule is:
Run
git filter-repoon a fresh clone of Repo B, not on Repo A.
Quick Command Summary
Repo B
git clone <REPO-B-URL> repo-B
cd repo-B
git checkout main
git filter-repo --to-subdirectory-filter priorwork
git ls-tree -r HEAD --name-only | head -20
Repo A
cd ../repo-A
git checkout main
git status
git remote add priorwork ../repo-B
git fetch priorwork
git ls-tree -r priorwork/main --name-only | head -20
git merge priorwork/main --allow-unrelated-histories
Verify and push
git log --graph --oneline --all --decorate
git push origin main
Expected Result
repo-A/
├── files originally belonging to Repo A
└── priorwork/
└── files originally belonging to Repo B
Both repositories' commit histories are preserved.
No comments:
Post a Comment