I have the following problem:
We have a large product which is in master branch. Also we have other branches that have only few files, the files that are specific to this branch only. Each of those branches represent a plugin to the main product. So for example when you get the main product, you receive lots of files, install them, etc. and later when you decide to get a plugin, you receive a package containing several files only and by uploading these file (and replacing the original ones) you get the plugin installed.
Let's I have payment.php in master branch (as well as many other files). And I have paypal branch which has one file only which is payment.php. Now I fix a bug in master's payment.php and want to merge this fix in paypal branch. However when I run merge, absolutely all files get added to that branch. So in the end paypal branch has all the files from master branch. Do you by chance know how this can be fixed? I want GIT to merge the files that exist in this branch only, so in the example above the paypal branch should still have one file only (payment.php) with the bug fix merged in.
This is why it's important to manage your branches well, in particular to use topic branches and to merge upwards.
You should make that fix on a topic branch, forked from a common ancestor of all branches which will need the fix, and then merge it into both master and paypal:
x - x - x - x ------------- X (master)
|\ |
| x - x - x ---- X (paypal) |
\ / /
x (bugfix) ---------------
If you have already made your bugfix, and you mistakenly made it on master instead of from the appropriate merge base, and the history on master hasn't been published, you should cherry-pick or rebase it to the right place:
# If the bugfix commit is not at the tip of master, you can rebase to get it there:
git rebase -i <commit before the bugfix> master
# rearrange the list of commits to put the bugfix at the tip, save and quit
# Now either cherry-pick or rebase the commit to the right place
# (rebase is easier if the bugfix is actually several commits)
# Cherry-pick
# make a branch and cherry-pick
git checkout -b bugfix <SHA1 of merge base>
git cherry-pick <SHA1 of bugfix>
# remove the commit from master, assuming it's still on the tip
git checkout master
git reset --hard master^
# or rebase
# make the bugfix branch (assuming it's still on the tip)
git branch bugfix master
# and remove the commit from master (assuming it's still on the tip)
git checkout master
git reset --hard master^ # or if the bugfix is composed of n commits, master~n
# rebase the bugfix branch to the right place
git rebase --onto <SHA1 of merge base> master bugfix
If the history has been published, all you can do is cherry-pick the bugfix onto the paypal branch, and remember to do it right the next time:
git checkout paypal
git cherry-pick <SHA1 of bugfix>
Why don't your other branches contain all the files that are part of the master branch? You're just making things harder on yourself by going through the trouble of removing all the other files. Especially if you later end up needing to change some other file that you already removed.
You're doing it wrong. You're supposed to have all the files in the branch.
It's Git's job to keep track of which files differ between the branches, not yours.
That's sort of one of the points of using a VCS.
If you want to distribute just the files that differ between branches, those can easily be extracted by a script.
You can do something similar to this: http://nvie.com/git-model
(I hope this works)
master
will continue to be your main branch. You create a second branch off master called bugfix
. You create a third branch off bugfix called plugin-foo
.
In plugin-foo you delete all the files that are not needed. Now, whenever you make a change to the files that are not in the plugin branch, you do those on the master branch. All bugfixes go into the bugfix branch. You periodically merge the bugfix branch into both master and the plugin branches. Which leads to bugfixes going into both of those branches.
Isolating your plugins in their own git repo allows you to make evolutions on them independently on a parent project.
If, however, you need them directly included in your project, recent Git releases (git1.7.11 ,June 2012), includes the git subtree script (previously developed on GitHub by apenwarr, now merged into mainline git)
That way, you can merge one repo (and its history) in another, keeping the option to extract its history later on (as opposed to the subtree merge).
That could be seen as an alternative to git submodules.
Another alternative is git slave, to keep parent repo and submodules tightly in sync.