1. Main Approach
Taken from a discussion on mihini-dev mailing list, kudos to ffleutot.
There are 3 families of Git workflows: merge, rebase, and pull requests.
- Merge workflows show branching and merging in the public repository. They represent the way we develop more truthfully, but they tend to turn into an unreadable spaghetti mess.
- In rebase workflows, before committing a set of changes, we graft them onto the top of the master branch *at commit time*, rather than when the feature's development started. It forces to rewrite history, but rewritten history is more readable.
- Finally, pull requests is the Linux way: there's only one integrator per authoritative repo, he pulls changes from development repos when he receives pull requests. To me, it seems both over-engineered for a project of our size, and at odds with Eclipse's habits of trusting several committers on a project.
Our Choice: We want our Git history to be welcoming to other people, i.e. readable. The normal workflow should be the rebase one, and each commit should make sense by itself functionally (fixing one bug, providing one feature). In exceptional cases, where long developments went on in parallel for a long time, it makes sense to show the parallelism through a merge, but this should be the exception, not the rule.
2. Concrete Examples
2.1. Create local branch and then rebase it on master
# create and switch to a new branch to develop a new feature, fix a bug etc > git checkout -b newfeature # do your dev in the new branch ... # fetch the changes which occurred on master > git fetch origin # graft our commits on top of updated master state: # first, in branch newfeature, import the new commits from master (our commits will be applied on top of it) > git rebase master # switch back to master > git checkout master; # get our new commits from newfeature branch in master branch > git merge newfeature # send the new commits to the repo > git push
2.2. Exchanging/backporting commits between branches
Say a bug fix has already been pushed into a specific branch, but it is not on the branch you are working on and you need it too, but you don't want to merge the whole branch.
Git cherry-pick can be very useful.
Here is a simple example:
- let's say the fixes are on *master* branch
- let's say you need the fixes to be imported into *topicA* branch
# check out the repo if needed. > git clone ssh://git.eclipse.org/gitroot/mihini/org.eclipse.mihini.git # 1: go on the branch where existing commits are: > git checkout master #now find the commit from master branch you need, keep commit id(s). #You can pick up several commits. # 2: switch to the branch where you want to apply the commits.: > git checkout topicA # 3: Apply the commit(s) in the topicA branch: > git cherry-pick 9662c1ac6d07adb440295ae5146f986fc8449b3b > git cherry-pick ... # 4: If you need to review the changes before pushing them to that branch on the remote repo, # you can share a patch containing those changes: > git format-patch origin/topicA --stdout > backport_bugfix_in_topicA.patch # 5: Send the backported commits to the remote repo on the topicA branch. > git push
# Create the local branch for bug id 123456 git checkout -b bugs/123456 # Do modifications to fix bug 123456 git add ... git commit ... # Push local branch on public repository # (Be sure current branch is bugs/123456) # -u is to be able to push/pull with branch easily git push -u origin bugs/123456