-
Notifications
You must be signed in to change notification settings - Fork 0
Git subtree evaluation for Pharo
The main setup of the evaluation will be a ''parent'' repository that will contain a ''child'' repository as subtree. For most of the questions (e.g., commit, push, pull) it is enough having both of them as a git repository in your github user. Pull requests will require some extra work: for example, with @tesonep we created a fork of the repositories in each his own github account to emulate the real use case where people will want to change things in Pharo.
- Create a parent repository (e.g., pharo)
# in https://github.com/guillep/Subtree_experiment_parent
git clone git@github.com:guillep/Subtree_experiment_parent.git- Create a child repository (e.g., glamour)
# in https://github.com/guillep/Subtree_experiment_child
git clone git@github.com:guillep/Subtree_experiment_child.git- Install child as subtree of parent
$ git subtree add --prefix=child git@github.com:guillep/Subtree_experiment_child.git master git fetch git@github.com:guillep/Subtree_experiment_child.git master
warning: no common commits
remote: Counting objects: 3, done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.
From github.com:guillep/Subtree_experiment_child
* branch master -> FETCH_HEAD
Added dir 'child'This will load the child into parent, and create a couple of commits: first it is the initial commit imported from the child repo into ours; second is the commit that merges or includes the child into our parent repository.
Check for resulting repository:
https://github.com/guillep/Subtree_experiment_parent/tree/0ceaea21e3e21354df5f6d63a07333f6576af4e6
https://github.com/guillep/Subtree_experiment_parent/commits/0ceaea21e3e21354df5f6d63a07333f6576af4e6
This simple (the simplest) scenario just changes the parent without modifying the child project.
#in parent directory
touch newfile
git add newfile
git commit -m "test"
git pushCommitting and pushing from parent works as usual. No extra work is required. The relationship between parent and child still works ok.
This scenario checks whether add and commit operations work recursively or not in subtrees. For that we create and add a file in the child subtree:
$ cd child
$ touch newfile2Going to the parent and checking git status will show that the parent knows exactly what files changed in the child.
$ cd ..
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Untracked files:
(use "git add <file>..." to include in what will be committed)
child/newfile2
nothing added to commit but untracked files present (use "git add" to track)git add works from the parent
$ git add child/newfile2Checking the status again to see that git will still see correctly changes in child.
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: child/newfile2Finally, we can push the change from the parent.
$ git push
Counting objects: 3, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 373 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@github.com:guillep/Subtree_experiment_parent.git
05a9248..d12a264 master -> masterThis push will effectively change the child project inside parent but not the original child project, and we will be able to see it in e.g., github's UI.
- https://github.com/guillep/Subtree_experiment_parent/tree/d12a26477983f28ff1cee148c5b437bf933f7ddb/child
- https://github.com/guillep/Subtree_experiment_child
This shows that child behaves as a normal subfolder. Operations add, commit and push are recursive in subtrees.
Subtrees work as normal directories for operations such as add, commit, pull and push. These operations will work recursively on subdirectories as in any normal git repository. A parent evolves together with its subtrees.
This scenario evaluates what steps are to be done when cloning a repository with subtrees. For this, we clone in a separate directory the repository and then we check the status of the subtree.
$ git clone git@github.com:guillep/Subtree_experiment_parent.git parent2
$ cd parent2/child
$ ls
newfile README.md
$ git remote -v origin git@github.com:guillep/Subtree_experiment_parent.git (fetch)
origin git@github.com:guillep/Subtree_experiment_parent.git (push)This shows that:
- the required commit was loaded as demanded, as we have the expected files
- however, the git remotes show that while using normal git commands, we are going through the parent. Thus, we are not just pulling and pushing to the original child's repository (as it happened with submodules).
This scenario checks if the link between parent and child really is versioned. For this we take and old version of the parent repository that should point to an old version of the child repository, and we check that what is fetched in the child is the correct commit.
$ git clone ... or git init, fetch, pull...
$ git reset --hard 05a9248541e347454e873fcc7ae4d64b86987b04
$ ls
README.mdAgain, here the loaded commit is the correct one.
Getting/Fetching/Cloning a repository with subtrees works as using any normal subdirectory. There is no extra bookeeping as it was required with submodules. This also avoids inconsistencies (e.g., pushed the parent but not the child) which removes corner case scenarios.
This scenario checks whether pulling a parent with changes creates some conflict.
#in parent in a second cloned repository
touch newfiletopull
git add newfiletopull
git commit -m "newfiletopull"
git push#in parent in first repository
git pullPulling a parent project just works as a normal project and shows no problems.
This scenario checks what happens when we change a child submodule and we pull that change from parent in a separate directory.
#in child in second cloned repository
touch newfiletopull
git add newfiletopull
git commit -m "newfiletopull"
git push#in parent in second cloned repository
$ git pull
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory cleanThis shows that pulling will update children directly as any other sub directory.
This scenario checks the co-evolution of projects. A subtree can be cloned independently of the parent from its original repository, be changed and have new commits. What happens in the parent if a subtree has changes.
#in child in second cloned repository
$ touch newfiletopull
$ git add newfiletopull
$ git commit -m "newfiletopull"
$ git pushWe will see that doing a git pull from the parent will not change the child subtree.
#in parent in second cloned repository
$ git status #=> does not realize changes in child. This is normal
$ git pull #=> does nothingIf we want to update the child, we need to do a subtree pull from the correct repository/branch where the updates are.
$ git subtree pull --prefix=child git@github.com:guillep/Subtree_experiment_child.git masterThis will import the commit from the remote repository and do the according merge (if possible). Take into account that a subtree pull cannot be done if the working directory is dirty.
Updating subtrees is simple when we are managing a single repository. However, keeping the synchronized with external repositories requires a git subtree pull operation instead of a normal git pull.
This scenario checks what happens in the child if we create a branch in the parent.
#in parent
$ git checkout -b test
$ cd child
$ git branch #=> testAs subtrees are managed as normal directories, the branch in the parent means that the code in the child is branched too. It is a normal subdirectory.
This scenario checks what happens in the parent when a branch is created in the child.
$ cd child
$ git checkout -b test2
# go to parent
$ cd ..
$ git branch #=> test2We see again that the parent shares the branch with the child.
In subtrees, branching works as if the subtree is a normal subdirectory. Thus the child is branched along with the parent.
This scenario works as with any other github repository.
Pull requests cannot be directly done from a the original child repository to the parent's subtree. Both the subtree and the child original repository evolve separately. We can pull and push between them as long as we have permissions.
Having pull requests in a subtree based repository works well in the simple scenario of forking the entire repository (Scenario 5.1). This has no difference with making the sub-project a normal subdirectory.
However, forking just the child and then contributing back to the parent (Scenario 5.2) is not as simple. We would require some extra work in here. Imagine that we have the following projects:
- Pharo\Pharo-core
- GT\Glamour
In Scenario 5.1 if GT\Glamour is imported as a subtree in Pharo\Pharo-Core this works well. To make Scenario 5.2, we should however, change it slightly:
- Pharo\Pharo-Core
- Pharo\Glamour
- GT\Glamour (fork of Pharo\Glamour or the inverse).
And Pharo\Glamour subtree of Pharo\Pharo-Core.
This setup has:
- all the advantages of scenario 1. We may work with Pharo as a single entity and do transversal commits that affect pharo-core and glamour together.
- This allows Glamour to evolve independently in a separate repository without dragging all pharo libraries with it.
- A pull request may be issued from GT\Glamour to Pharo\Glamour and vice-versa.
However, pull requests cannot be yet done from Pharo\Pharo-Core to Pharo\Glamour, nor vice-versa. This means that these two should be synchronized (via subtree pull and subtree push) with the corresponding repositories.