How to use git filter-branch to move a directory from one repository to the other including its history of commits
- Original repository:
- Other repository:
- Directory in
Athat we need to copy with commit history:
- Directory in
Bthat we need to copy into the files and commits from
A: git root directory
- Local path:
Suppose, you want to move a directory from a repository
A to be merged into
B. The noob approach would be just to copy the contents
of the said directory from
A to (that of)
That however, will render all efforts of commits made in the direcotry in
to just one commit in
B. This is something we want to avoid especially to
open source projects where commit history is important to the developers who
made them, and to the company they work in as credits.
Suppose, you want to retain git commit history made in repository
A in that
particular directory. This can be done by one-by-one re-committing changes
made in that directory in
Soon you will realize that you re-wrote the commit history made in the said
B with you as the committer, author, and the dates of the
commits were done just now, not on the date those commits were originally made
That can be solved, by setting up the env variable for git committer name, author name, and the date committed. This however, would be very tedious.
Let’s use git’s
A. Let’s clone it in
/var/www/demo/. Any path will do. I would suggest to clone a new one, than to use existing one where you currently work on.
git clone A-git-url
Checkout to the branch you want. E.g.,
Let’s remove the remote origin. This is to make sure we don’t accidentally push changes we will about to make.
git remote remove origin
Now, let’s do the filter-branch. This process will move the directory set in the filter-branch command, to the root of the repository. This means, all other files will be removed, and the ones that are left are the ones in the branch set in filter-branch.
git filter-branch --subdirectory-filter www/modules/custom/sms_gateway -- --all
Now, before we go ahead and merge the files and commit history to
B, we need to have a new clone repository
Bfirst. Same with
A, it’s better that we clone a new one, than working on the existing one.
git clone B-git-url
Bgit checkout to the branch of your choice and then branch out to a new branch to do the merging of commits there. You can do this to the original branch, but it’s better to branch out to a different branch. There is no need to remove the remote origin from the newly cloned
B. Let’s say, you branched out to
Badd a new remote to be named to whatever you want, e.g.,
from-A. Confirm remotes, with
git remote -v. You should see, aside from
from-A. The remote url would be the local path of the newly cloned
Aearlier. The easiest way to do this is to go to /path/to/A and then
pwdin its root.
cd /path/to/A pwd cd /path/to/B git remote add from-A /path/to/A
pwdabove, just note or copy the its result as you need this in the last command to be substituted for
Again, in the last command, the
from-Ais the alias of the remote you just added.
/path/to/Ais the local path of you newly cloned
Ayou did a while ago. Note that you should do this inside the newly cloned
Now, let’s do the merging.
git fetch from-A git merge from-A/feature-commits-from-A
If you encounter some error related to unrelated histories, you should add
--allow-unrelated-historiesin the second command.
git merge from-A/feature-commits-from-A --allow-unrelated-histories
Confirm commit histories. In
git logand see the commits. You can check back in
If you are satisfied, merge back branch
feature-commits-from-Ato the original branch, e.g,
8.x-1.x- to the branch where
feature-commits-from-Awas branched out.
git checkout 8.x-1.x git merge feature-commits-from-A git log
After all of the above, we now need to push to
B. This is just a simple push.
git push origin 8.x-1.x
Below are all commands used.
# Go to the local path where we want to do stuff. cd /var/www/demo/ # Clone repos. git clone A-git-url git clone B-git-url # In A. cd /path/to/A git checkout develop git remote remove origin git filter-branch --subdirectory-filter www/modules/custom/sms_gateway -- --all # In B. cd /path/to/B git checkout 8.x-1.x git checkout -b feature-commits-from-A git remote add from-A /path/to/A git fetch from-A git merge from-A/feature-commits-from-A --allow-unrelated-histories git checkout 8.x-1.x git merge feature-commits-from-A git log git push origin 8.x-1.x
For clarification(s), and/or question(s), please let me know.