-
Notifications
You must be signed in to change notification settings - Fork 137
Topic Branch
This page is based on Topic_Branches by Wincent Colaiuta and has been adapted to suit the Gourmet project.
A “topic” branch is a separate branch that you use when working on a single “topic” (a bug fix, a new feature, or an experimental idea). Working on a topic branch instead of directly on top of “master” is recommended because:
- it allows you to work on multiple, separate topics simultaneously without having them all jumbled together in a single branch
- topic branches are easily updated, which means that if the remote “master” evolves while you are working on your topic it is easy to incorporate those changes into your local topic branch before submitting (which in turn will make your topic apply cleanly on top of the current “master”)
- if you receive feedback on your pull request, having all the related changes grouped together in a topic makes it easy to tweak them and resubmit
- working on a topic branch makes it easy to refactor a patch series into a logical, clear, clean sequence, which in turn makes your contribution easier to review and more likely to be included
Let’s assume you are working in a clone of the Gourmet repository. If you set this up using a standard "git clone" then your local "master" branch will be set up to track the remote “master” branch automatically.
Gourmet's source code is hosted at GitHub. You can clone it by opening a command prompt and typing:
git clone https://github.com/<username>/gourmet.git
# make sure that you're on your local "master" branch git checkout master # integrate latest changes from upstream git pull # create and switch to new topic branch named "my_topic_branch" # (obviously you'd pick a more descriptive name) git checkout -b my_topic_branch # now work on your submission: edit, stage and commit your changes along the way git status # View the state of the repo git add <some_file> # Stage a file git commit # Commit a file ... # when ready, push your changes to GitHub git push origin my_topic_branch
- go to https://github.com/your-name/gourmet
- check that your new "my_topic_branch" exists
- switch to the new topic branch and check that your latest changes are in it
When you’ve made all the changes, submit a pull request from your GitHub topic branch (i.e. "my_topic_branch") and not from your "master".
If your topic is long-lived then you can use git rebase
to keep it up to date and massage it into shape. Imagine that the remote master has three commits at the time you start working:
A--B--CYou make a topic branch with three new commits:
A--B--C \ X--Y--ZMeanwhile, the remote “master” continues to evolve and has three commits of its own:
A--B--C--D--E--F \ X--Y--ZWithout
git rebase
, the only way to get your changes into the “master” branch is for the integrator to perform a merge, creating a new merge commit, M:
A--B--C--D--E--F--M \ / X--Y--Z-With
git rebase
your changes can be “rebased” on top of the current remote “master”. Git actually removes your three commits (X, Y and Z), “fast forwards” your topic branch to incorporate the latest commits from upstream (D, E and F) and then replays your commits on top of the new HEAD.
A--B--C--D--E--F \ X'--Y'--Z'In this way when you submit your patches they can be applied using a simple “fast forward” merge which yields a nice, linear history:
A--B--C--D--E--F--X'--Y'--Z'The content of the commits is the same but I’ve used the X’, Y’, Z’ notation to indicate that the SHA-1 hashes for them will be different (because any change in their ancestry will bubble up and change their identifying hashes).
There is no merge, so your patches are guaranteed to apply without merge conflicts. If there are any merge conflicts you will have already resolved them when you ran git rebase
. (This appropriately shifts the burden of resolving merge conflicts away from the central integrator onto the contributor; in this way the project can scale to have many contributors without the integrator becoming a bottleneck.)
To make use of all this, all you have to do is:
# integrate the latest upstream changes into your "master" git checkout master git pull # make sure that you're on your topic branch git checkout my_topic_branch # do the rebase git rebase master
git rebase
can do more than just keep your topic branch up-to-date.
Given our example commits X, Y and Z you might want clean up the history to make it easier to review (because the easier to review, the more likely it is to be accepted, you’ll receive better feedback, and bugs are more likely to be caught). By running git rebase --interactive
you can:
- remove a commit from a series (you realize that commit “Y” doesn’t really belong in the series)
- amend a commit (you realize that the commit message for “X” isn’t quite right)
- insert a commit into the series (you realize that you actually need a “W” commit before “X”)
- “squash” several commits into one (you realize that “X” and “Y” just make the same change in two different files, and so they logically belong in a single commit)
- re-order commits (you realize that the series will be easier to understand if “Z” comes before “X” and “Y”)
git rebase --interactive
you’ll see an editor window that allows you to perform all of the above operations in a simple fashion; you are presented with a list of commits which you can transform as follows:
- delete a line to drop that commit
- use “pick” (the default) for commits which you want to appear in the rebased history
- change “pick” to “edit” for each commit you wish to amend (or perform additional commits) along the way
- change “pick” to “squash” for each commit which you want melded into the previous commit
- reorder the lines to reorder the commits
git rebase --continue