Question

In some of the repositories that I'm working with, I found git subtree does not behave as expected when sharing repos.

Here's the scenario:

  1. I own main repo X and push it to origin.
  2. My colleague pulls repo X from origin, adds a subtree pointing to another repo Y, makes the commit, and pushes X back to origin.
  3. I pull X and see the changes my colleague has made. However, in my local repo, the folder containing subtree Y is just another file. I can't pull changes from repo Y even after adding repo Y as a remote. Git subtree always says that the folder already exists whenever I do a git subtree add and says that it can not find the commit when I do git subtree merge.

Does anyone know the best way to deal with this situation? Ideally I would like to also be able to pull changes from repo Y even though I am not the user adding repo Y as a subtree of repo X. Is this possible? If not, what is the best way to share repositories having subtrees?

Was it helpful?

Solution

Use git subtree pull.

git subtree add adds a history of another repository as a new subtree -- in your case, this has been done by your colleague, so it won't work

git subtree merge merges the changes up to a given local commit into the subtree -- as you have not pulled those changes yet, it won't work either

git subtree pull pulls the changes from another repo and then merges them into the subtree. Tested with the following command sequence (uses the 'master' branch of the subtree repository, adjust if needed).

~ $ mkdir subrepo
~ $ cd subrepo
~/subrepo $ git init
Initialized empty Git repository in ~/subrepo/.git/
~/subrepo $ touch file
~/subrepo $ git add file
[master (root-commit) 03a9f75] file added
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 file
~/subrepo $ cd ..
~ $ mkdir repo1
~ $ cd repo1
~/repo1 $ git init
Initialized empty Git repository in ~/repo1/.git/
~/repo1 $ git commit --allow-empty -m "initial commit"
[master (root-commit) ec7e1c5] initial commit
~/repo1 $ git subtree add --prefix=sub ../subrepo master
git fetch ../subrepo master
warning: no common commits
remote: Counting objects: 3, done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From ../subrepo
 * branch            master     -> FETCH_HEAD
Added dir 'sub'
~/repo1 $ cd ..
~ $ git clone repo1 repo2
~ $ cd subrepo
~/subrepo $ echo 'new version' > file
~/subrepo $ git add file
~/subrepo $ git commit -m "file changed"
[master c72ac6e] file changed
 1 file changed, 1 insertion(+)
~/subrepo $ cd ../repo2
~/repo2 $ git subtree pull --prefix=sub ../subrepo master
remote: Counting objects: 5, done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From ../subrepo
 * branch            master     -> FETCH_HEAD
Merge made by the 'recursive' strategy.
 sub/file | 1 +
 1 file changed, 1 insertion(+)
~/repo2 $ cat sub/file
new version

OTHER TIPS

Normally these commands should fulfill all your needs; unless you messed things up underway. Note issues with Squash on this site

add a repository as subtree in another

cd super
git remote add sub git@gitlab:chris.maes/sub.git
git fetch sub #or use: git fetch --all
git subtree add -P subdir -m "add sub as subtree in subdir" sub/master

merge changes in subproject into superproject

git fetch sub (or git fetch --all)
git subtree merge -P subdir -m "merged changes of sub" sub/master

push changes made in superproject to subproject

git subtree split -P subdir -b backport
git push sub backport:master
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top