Domanda

I actually have two repositories:

  • main
  • external

The main repository was merged after some time into external/main directory (as subtree). Now I'd like to migrate the changes made to external/main back to main repository, but only these commits and no other unrelated commits like to external/<anything-else>.

I've actually tried the classical:

git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter main -- --all

but that removes all the commits made to the initial main repository too and only leaves the ones which were made in the external git repository.


So: how to retain only the commits:

a) made to the initial main repository

and

b) made to the subtree of external (external/main)


When I try git pull -s subtree ../external, the commits are all merged, including commits which didn't change anything in the subtree. I'd like to have only the commits which actually changed something in the subtree and there also only the information about files from the subtree.

È stato utile?

Soluzione

You should be able to limit the commits rewritten by filter-branch using --not --remotes in the <rev-list options> section of your command:

git filter-branch --tag-name-filter cat --prune-empty
    --subdirectory-filter main -- --all --not --remotes

This will cause filter-branch not to include commits reachable from your remote branches. If you have multiple remotes, you can use something like --remotes=origin to specify which one to consider.

Altri suggerimenti

In order to bring into main all the relevant changes that happened in external two things will need to happen:

  • Isolate the original main
  • Bring into main it all commits that happened in external

For the first, Isolate the original main:

Seems like you probably have main in its own repository.

If not it could be retrieved from the external repository as long as the original main commits where set as a parent of the commit that created the external/main subdirectory. An example of such is the process outlined in Git Book Subtree Merging page

Commits where subtree where introduced can be found as described in this answer.

And then it is just a matter of grabbing the whole set of commits that are the base of main and make a repository out of it.


For the second, Bring into main it all commits that happened in external:

You already have isolated the commits that contain changes in the exteral/main subfolder, but as you state it does not include the original main commits.

git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter main -- --all

This is because filter-branch will only check for the files in the specific subdirectory location, without knowing how to handle more complex operations like the read-tree that created the subdirectory.

After the filter-branch operation, you will be left with a set of commits that contain all changes that happened in main/external. Lets assume that this set of commits can be reached in the filteredMain branch.

Since the contents were moved from the subdirectory to the root the location of the files is now the same again as in the contents in the main repository. This will allow for both trees to be joined. Since this two trees, main's master branch and filterBranch have no history in common they can be joined by a rebase replaying the changes of the commits.

# in the main repository

# bring the external repository and get the branch
git remote add external /path/to/external
git fetch external filteredMain
git checkout filteredMain

# We need the first commit of this tree for the rebase command
firstCommit=$(git rev-list --max-parents=0 HEAD)

# run the rebase
git rebase --onto master $firstCommit filteredMain

After this the filteredMain branch should contain all the changes that happened in external/main replayed on top of the original master branch in the main repository.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top