Working with branches in Git
Introduction
Why use branches?
Branches help separate different projects so that it is easy to push out only finished projects. Branches also tend to be easier than cloned directories for pulling in changes and for sharing changes across multiple projects.
http://www-cs-students.stanford.edu/~blynn/gitmagic/ch04.html had this to say about branches in git:
You might wonder if branches are worth the bother. After all, clones are almost as fast, and you can switch between them with cd instead of esoteric Git commands.
Consider web browsers. Why support multiple tabs as well as multiple windows? Because allowing both accommodates a wide variety of styles. Some users like to keep only one browser window open, and use tabs for multiple webpages. Others might insist on the other extreme: multiple windows with no tabs anywhere. Others still prefer something in between.
Branching is like tabs for your working directory, and cloning is like opening a new browser window. These operations are fast and local, so why not experiment to find the combination that best suits you? Git lets you work exactly how you want.
Branches also have the added benefit of allowing users to share a development branch and so work together on a project without disturbing the master branch, which is something we have occasion to do on our project frequently. And keep in mind, ease of branching was one of the reasons we chose git over other source code control systems.
How we use branches in our group
It is recommended that you leave your master branch clean of any but the shortest of projects. This is primarily because it provides users a clean branch to use to make minor changes without worrying about accidentally pushing out half-baked projects. It also has the added benefit of simplifying how to use git pull and git push when you have more than one branch. This page is presented assuming that you are following this paradigm.
The steps
- Make a branch
- Work in your branch
- Build to your own sandbox
- Test in your sandbox
- Write and run unit tests
- Merge the master repository into your branch every couple of days or so to (1) minimize the number of conflicts that you will need to resolve when you finally merge your branch back into the master repository and, (2) pick up others' ongoing changes. Read about how to keep your branch up to date.
- If you need feedback from QA before you merge your development branch back into the master branch, then build onto demoN (to build into the demo1..5 sandbox, just change your username to demoN and do a make) and let QA know.
- Once you and/or QA are convinced that all is well, your unit tests are passing, and you're ready to share your code with the rest of the project, then merge the master back into your branch one last time, resolve any conflicts, then finally merge your branch into the master repository and do a final test there.
Three types of projects you might to do in a development branch
- A large development project that will take more than one release cycle to complete, or will be worked on by more than one developer, or will touch many parts of the code (see how to share a branch).
- A smaller project that you will want feedback from a QAer before you check into the master branch.
- A smaller project (anything more than a half-day or so) that you'd like to test in your own sandbox before checking into the master branch.
The types of projects that aren't necessary to do in a development branch
- Any small bug or feature that you know is isolated to only one part of the code and will only take a short amount of time to fix.
- Small changes to docs and trackDb.ra.
Things to know
How do I make a branch?
git checkout -b <new_branch>
As noted above, make sure that your new branch name is prefaced with your user name, unless you intend to share this branch with other users.
It is important to note that when making a new branch, git will take all changes in your working directory and staging area with you. This is useful if you start a project, realize it is bigger than expected, and then decide to store these changes on a branch.
Some Examples:
git checkout -b UserA-NewBranch #This will make a new branch that has the same state as the master branch. git checkout -b UserA-NewBranch UserA-otherBranch #This will make a new branch that has the same state as otherBranch. git checkout -b UserA-NewBranch 1b6d #This will make a branch that has the same state of the commit beginning with 1b6d.
How many working directories/staging areas/commit histories do I have?
Git's paradigm for branches is that there is one working directory, one staging area, and multiple commit histories. One way to think about this is when you switch between branches you are populating your working directory with the files for that particular branch.
How do I move between branches?
git checkout <branch_name>
Note that git will try to take any changes in your working directory and staging area with you to the new branch. This can lead to conflicts that can be difficult to resolve; thus it is recommended that you commit all changes in your working directory (see: Committing Changes) before moving to a different branch.
How do I know which branch am I on?
git branch
This command will list all the branches you have made. The branch you are currently on will be prefaced by a "*".
Example output:
UserA-awesomeProject UserA-coolProject * master
In this example the user is on the master branch.
You can get the branch state into your bash shell prompt. Create a shell script file in your $HOME/bin/whichBranch
#!/bin/sh G=`git branch 2>&1 | head -1 | sed -e 's/* //'` NB=`echo $G | grep "Not a git repository" | wc -l` if [ $NB -eq 1 ]; then echo "nab" else echo $G fi
Then, in your PS1 prompt string, include a `whichBranch` command as part of the string. For example
export PS1='[$LOGNAME@$HOST `whichBranch` ${PWD##}] '
produces a prompt such as:
[logname@host beta /scratch/some/clone/kent/src]
How do I delete a branch?
To delete a branch you must not be on that branch. There are two ways of deleting:
git branch -d <branch_name>
In the above example the branch must be fully merged with the master branch
git branch -D <branch_name>
In the above example, the branch is deleted regardless of merge properties
How do I commit only to the branch I am working on?
Commits work like they do currently, except you commit to a given branch instead of the master branch. All that is necessary to ensure that a commit is only recorded for one branch is to make that commit while you are on that branch.
How do I push out my changes back into the main development branch (master)?
You will need to first merge changes from branch to master and then push from master to origin/master. Note that this will transfer your entire commit history on the branch to the master branch. It is recommended that you view your commit history before pushing your changes out to make sure you are only pushing out changes related to your intended project.
Ex:
git checkout master git pull git merge UserA-awesomeProject git pull # if needed git push
In this example the user first switches to the master branch. They then merge in the changes in the branch 'UserA-awesomeProject' into the master branch. They then push those changes out.
In order to share your branch with other users you will need to push your development branch to the main repository. We do this by creating a tag, similar to the way we tag our master branch with different release versions, thereby allowing everyone access to the new branch-tag after they do a 'git pull'. This is different from the scenario above because you are sharing your branch with other users before merging these changes in the master branch.
First make sure that you are on your branch:
git checkout awesomeSharedProject
Next do push command specifying your branch name in the shared repository and creating a tag:
git push origin awesomeSharedProject
It is recommended, but not necessary, that you merge in changes from the master branch before pushing to the main repository since this will make future merges easier (see keeping a branch up to date).
Note that there is potential for branch-tag name conflicts between shared repository branch-tags and private branch-tags - try to choose a descriptive and unique name. Once a shared branch-tag goes out to the shared repository, it can exist forever and is difficult to delete.
Users who want to now download and follow this new shared branch-tag should do this:
git fetch or git pull # to get all the updates and symbols from origin git checkout -t -b awesomeSharedProject origin/awesomeSharedProject
This creates a new local branch, which we named the same name as the branch-tag, and set up the local branch so that it only pulls in changes from the shared branch-tag. This is called setting up tracking, which is the way to show the system the connection between your local branch awesomeSharedProject and the shared branch origin/awesomeSharedProject. Now, when ever the user does a git pull, it will update both the master branch and awesomeSharedProject branch
The original author of the shared branch-tag must manually setup tracking for him/herself:
git config branch.awesomeSharedProject.remote origin git config branch.awesomeSharedProject.merge refs/heads/awesomeSharedProject
How do I keep my branch up to date?
You will first pull in the latest changes into the master branch and then merge these changes into the development branch.
Ex:
git checkout master git pull git checkout UserA-awesomeProject git merge master
In this example the user first switches to the master branch and pulls in the latest changes from the shared repository. They then switch to their branch 'UserA-awesomeProject' and merges those latest changes with their branch.
What do I do if I'm in the middle of a project on another branch and I need to make some minor change to the main branch (master)?
You may use git stash to save your changes and reset your working directory to the tip of the branch that you are working on.
Ex:
git stash git checkout master # edit, test, commit, push on small change git checkout UserA-awesomeProject git stash pop # continue to work on changes ...
In this example, the user is working on the branch "UserA-awesomeProject". They first stash their changes and then move to the master branch. They then make their minor change, go back to the UserA-awesomeProject branch and un-stash their working directory changes.
What do I do if I'm part way through a project and need to stop? How do I make sure that I keep my work without making a commit that I don't want others to see?
If you want to keep your changes, you will need to commit no matter what. However, what you can do is when you come back to your branch you can revert your last half-baked commit (Reverting changes) and then proceed as normal with your changes only existing in the working directory and/or staging area.
Other people prefer to keep their half-baked commits and work from there - either method is fine.