I have been playing around to create a `subtree`.
RepoFolderSrc RepoFolderTarget RepoAnother | | | develop sfcc------------------sfcc18 | | | | |-someFolder1 | |-someFolder2----------featureBranch
I want to copy the `someFolder1` and `someFolder2` from `RepoFolderSrc` to `RepoFolderTarget`. I want to retain all the history for the folder `someFolder1` and `someFolder2` when it is copied over to the `featureBranch`.
A few of the solutions I have seen requires deleting the `origin` from `RepoFolderSrc`. I should not make any changes to the `RepoFolderSrc` and I should not create any additional branch or commits on the folder.
Is there a way by which I can copy over the folder by only playing around with the `RepoFoldertarget`. I do have push and pull permissions for all repositories.
Solved! Solved! Go to Solution.
If you're referring to the solution described in this blog post, as one of the ones you've seen but disliked how it worked because it made changes to the source repository, then I'm afraid to say that it is the canonical solution for getting done what you're describing. I also think you're misunderstanding when you say that the solution requires "deleting the `origin`" or "create additional branch or commits". Let me see if I can rephrase the solution more clearly.
The goal here is to copy from a repo named `source` to a repo named `destination` only the contents of folder `foo`, including all history that touches folder `foo`. In order to do that, because Git doesn't track folders per se but tracks commits, we'll have to filter the commit history of the `source` repo to only contain the commits that touch folder `foo`. The way we'll do that is via the `git filter-branch` command using the `--subdirectory-filter` filter. First, we'll need to create a local copy of the `source` repo separate from any local copy you already have. You can do this by doing the following:
mkdir backup cd backup git clone https://github.com/user/source.git cd source
Now, we are in the directory `backup/source` which is a completely new local copy of the `source` repo separate from any local copy you already have. Additionally, we want to protect https://github.com/user/source from being accidentally changed by our process here. We do that by deleting the `origin` remote, but only in this new local copy.
git remote rm origin
Next, we want to filter the commit history of the `source` repo to only contain the commits that touch folder `foo`. We do that by issuing the `filter-branch` command:
git filter-branch --subdirectory-filter foo -- --all
But, as you'll notice in the documentation for the `git filter-branch --subdirectory-filter` command, it states:
The result will contain that directory (and only that) as its project root.
This means that everything that was in `foo` is now in the root of the repo. So, in order to put it all back in folder `foo`, we have to add one commit to this local only temporary working repository that we're going to throw away soon:
mkdir foo mv * foo git add . git commit
Now we have a local repository that contains only the files and history that we want. We're halfway there! 🎉And remember, this is just a temporary place to store some work. It is completely separated from your normal local `source` repository and from https://github.com/user/source, so any changes we make here are not permanent. It's like making a temporary backup of a file so that you can revert back to the original if you screw something up.
Now, in order to merge this new history that we've created into the destination repository, let's assume that the destination repository is already cloned locally in `projects/destination` from https://github.com/user/destination. So we need to:
in order to move from `backup/source` to `projects/destination`. Then we issue the following commands:
git remote add modified-source ../../backup/source git pull modified-source master --allow-unrelated-histories
This pulls all of the commit history of our temporary `source` repo into the `master` branch of our local copy of the `destination` repo. Then all that is needed is to clean things up:
git remote rm modified-source
This removes the link between our local `destination` repo and the temporary `source` repo. And when you're sure everything worked correctly, you can delete the modified local `source` repo whenever you feel like.
I hope that helps explain things a bit better! Let me know if you have any questions.
Really good answer. From my understanding, this will copy the most recent commit and the history for the specific subfolder. Is there a way to keep the source remote, and thus the hability to sync only that folder?
You can't keep the source remote and sync only that folder, no. But, you could remove the source folder from the original repository and add the new repository back to the original one as a submodule. I believe this would provide essentially the functionality you're looking for.
I hope that helps!
Hello @lee-dohm ,
If I want to wrap your answer in a batch file, is there any way to revert the old repo to its original state before running this batch file?
I'm not sure I understand the question @agwatic. The whole point of my answer is for it to not change the original repo in any way, so I'm not sure what there would be to revert?
After making your tutorial I didn't manage to get back to the old state of the repo. How can I get back to the old state before extracting the directory from the repo?
As I said before, the process I described does not change the original repository. If your original repository was changed, can you tell me how exactly it was changed?
git filter-branch --subdirectory-filter foo -- --all
We had a similar issue, and used your solution but ended up losing part of history.
The folder we wanted to move to another repo was carried from different directory one year ago. In current repository we are able to see whole history but when I use filter-branch and extract the folder, the history before directory change was carried out is gone.
Do you have any ideas how we can keep whole history for this folder?