As we all know, git can be a bit fickle from time to time. My scenario was the following:
My repository (letâs call it âextensionâ) is a fork of another repository that Iâm adding functionality to (letâs call this one âframeworkâ). When Iâm finished developing my extension, Iâll merge it back into framework, so I want to keep up with the changes that are being made to framework while Iâm working on extension. This is generally a good idea if you want to avoid hour-long merge conflict hassle when youâre finally ready for merging (smaller increments - faster resolution). So to keep the extension repo up to date with the framework repo, I imported framework as a subtree into extension, in itâs own branch. These are the commands you need for that:
git remote add <framework repo> <url to other repo> git fetch <framework repo> git checkout -b <framework branch> <framework repo>/master git pull
Now I have a branch thatâs set up to follow the master branch of framework. Since I donât want to put the contents of framework in a subfolder in extension like you see in many subtree tutorials (because extension is basically framework + extra content), Iâm not doing the read-tree command, but this doesnât change the workflow. Once someone adds a commit to framework, you can pull it into your branch with a normal git pull. Now you want to add whatever has happened in framework to your master branch of extension:
git checkout <framework branch> git pull # newest changes from framework git checkout master git merge -Xsubtree=<framework branch> --squash --no-commit <framework branch>
The --squashoption keeps the extension repo clean by not showing all of frameworkâs commits in extensionâs log. This makes sense because you want to keep track of your own changes and not of whatever changed in framework. The --no-commit option makes the merge stop before committing, so after your merge you have to git commit once.
This procedure can go very well or... not so well. Especially if itâs been a while since you updated extension to frameworkâs changes, there can be a lot of merge conflicts resulting from things like deleted empty lines etc. In this case you probably donât want to go through every file that has been modified since your last update and resolve the conflicts manually. What you most likely want is to tell git to use the new file versions from framework and ignore whatever is still in your master branch. You would achieve that like this:
git merge -X theirs -Xsubtree=<framework branch> --squash --no-commit <framework branch>
BUT THIS IS A BAD IDEA. This will override all changes you made to files that have also been changed in framework. So no, really bad idea. You can do this, however, if youâre absolutely sure that you havenât modified any of the files that framework modified, but Iâd advise you to take a look at the diff before you do that. Itâs easy to forget that you added a minor detail to a class you didnât use otherwise. What you can do instead is the following:
>git merge -Xsubtree=<framework branch> --squash --no-commit <framework branch> # some/a lot of conflicts grep -lr '<<<<<<<' .
The last command shows you a list of all the files that have merge conflicts. Now you go through them one by one. If it is a file you modified, open a text editor and resolve the conflict manually. If you havenât touched the file (again, check the diff to be sure), execute the following command for this file:
git checkout --theirs <path/to/file>
The --theirs option will simply replace the version of the file in extension with that in framework. In other words, this is a manual, file by file command for the version shown above.
After youâve finished going through your list of files, git add them all (or maybe add them after resolving the conflict to be sure not to forget one). Now commit your changes:
git commit -m âMerged with current version of <framework>â
Phew. This is the time to check if your code still compiles or if you somehow missed a conflict and need to resolve it. If thatâs the case, do that for all conflicts and then
git add <all files you changed> git commit --amend
to pretend this never happened and you did all this already during your merge.
Chances are, you have a branch your developing a new feature on, letâs call it âfeaturebranchâ. You want to get this branch up to date with your master branch so, again, merging it later will not be such a pain in the ass. What you want to do now is rebase featurebranch onto master. This will make it seem as if you only branched off master after you updated it to frameworkâs changes.
git checkout featurebranch git rebase master
Again, you might get some merge conflicts that you can resolve the same way you did before. But be careful: the --theirs option will now mean whatever you did on featurebranch, so to accept changes from master youâll want to exchange it with --ours.
If you did all this youâre ready to go! You updated both your master branch and your feature branch to the changes made in framework and now have whatever bugfixes or new features were added to it. If you do this often enough, you should have no trouble merging your extension back into framework once you are done.













