Git Tutorial - Part 2
Contents |
Motivations
If you've followed the material in the first tutorial, at this point you know how to track changes on a set of files. If it's a software project, this means that you have a nice, linear history of all your tweaks and improvements. But as anyone who has actually developed software knows, real development doesn't work that way. It can be a mess of false starts and backtracking, and you will often need to throw out or save "bad" ideas for later. Git has tools and features for all of these circumstances.
Here is a short list of key ideas and terms that will be useful in this tutorial:
- branch - An alternate version of your project stored in the git repository
- merge - To combine 2 or more branches into one version, accepting changes from each.
- rebase - To rearrange or change commits and their order in the tree. More on this later...
- tracking - a local branch tracks a remote branch if git understands that they should be the same branch. Usually (but not always) the local branch has the same name.
- reset - Roll back changes on your local branch with this command.
Branches
A git repository can best be thought of as a tree of commits, growing from the root (initial) commit. So far, your tree has only had one branch, called (by default) the master branch. In general, this branch should represent the "best" version of your project, and always be in a working state.
Create a new branch
What if you want to work on an experimental feature? You can create another branch, then switch to that branch using checkout:
git checkout -b <branchname>
The -b switch creates a new branch with the given name, then switches your working tree to that branch. In other words, you are now working with the "branchname" version of your code. Other versions are safely stored away in the git repository, and you can switch back at any time.
See what branches exist
If you want to know what branches exist in your repository, run this command to list them:
git branch
If you want to see branches on the remote repository as well, add the -a switch. The remote branches will be listed in a different color to distinguish them. This is useful to know what branches you can checkout and work with.
git branch -a
Delete a branch
If you are done with a branch, and want to get rid of it, all you need is a simple switch:
git branch -d <branchname>
This deletes a branch that has been merged back into another branch (more on this later). To use the nuclear option and delete it regardless, use a capital D:
git branch -D <branchname>
Merging
What if you have 2 different versions of your project, and want to merge them together? Without version control, you would have to do this by hand, making sure that all the changes matched up. With git, however, all of the differences are automatically merged together (most of the time). In the case that git cannot figure out how to merge a specific set of changes, it highlights the differences for you.
To initiate a merge between to branches, run git merge in the branch to be merged into:
git checkout master git merge experimental
For more information, see excellent page of the Git Book.
Tutorial Exercise
The goal of this project is to plot and animate simple coordinate transforms using MATLAB. Rotation matrix definitions of coordinate transforms can be very tricky to understand without seeing a visual representation, so this project will be very useful for robotics students.
Preparations
Clone the repository from the skeleton project available on github:
git clone git://github.com/daslrobotics/branchingExample.git
Project files
baseScript.m is the main script file for this project. The master version of this code looks like this:
%% Animate a rotating coordinate system % Visualizing rotation matrices can be very difficult, so it can be helpful to % see what a given rotation actually looks like. This example will show a simple animation of rotations about each axis. %% Demonstrate rotation matrices as functions % Each of these functions need to be written to output the rotation matrix for % each axis, given an angle input (see skeleton code). % These rotation matrices are local to global transforms. Rx(pi/6) Ry(pi/12) Rz(pi/4) %% Multiply rotation matrices together Rx(pi/3)*Ry(pi/6) %% Display a given coordinate system using plotting tools: theta=.2 %some angle R=Rx(theta); line(0,R(1,1),0,R(1,2)0,R(1,3),'r'); % line(...) % y axis % line(...) % z axis %% Animate this rotation % animateRotation(R)
You will need to define 4 additional functions to run this script:
- Rx(theta), which returns a rotation matrix for a rotation theta about the X axis
- Ry(theta), same about Y
- Rz(theta), same about Z
- animateRotation(rHandle,theta,time), which animates a given rotation function over angle theta, for the given time. See the file animateRotation.m for a skeletal structure.
Each of these functions can be developed separately. Working in groups of 2, each team member should make an experimental branch for themselves to work in. To work on the rotation matrix functions, make this branch:
git checkout -b rotMat
To work on the animation function, create another branch:
git checkout -b animation
Now, each person can work independently on these parts of the code. Once you are in your branch, you can make changes to files, create and add new files, and commit your results. You can make 1 big commit, or several small commits if need be. In the beginning, try to commit often to get a fine history of your work.
Make a repository on the server
To combine your two branches, you need to be able to work froma common repository. Make your own version of this repository in your folder on the server.
ssh user@dasl.mem.drexel.edu git init --bare --shared=group repos/branchExample.git
Quit this ssh session so that you are back on your PC. Now, we need to set up your local git repository to talk to this new remote repository. You will also set up a reference to your partner's repository:
git remote add mycopy user@dasl.mem.drexel.edu:~/repos/branchExample.git git remote add partner user@dasl.mem.drexel.edu:/home/partnersName/repos/branchExample.git
Just like origin, which is the default remote repository, you have just created a new remote called mycopy. If you want to see information about a given remote, use this command:
git remote show <remotename>
Now, push your local branch to this new remote:
git push mycopy <branchname>
Merge your work
Now that you have (hopefully) working code for each part, you need to merge your work into the master branch.
git checkout master git merge mybranch --no-commit
Git merge combines the changes from your partner's branch, and adds them to the staging area. The --no-commit option does not automatically commit these changes, so that you can look around and make sure everything works. If you have to make any tweaks to your code, you can do so now, then commit the result.
Merge your partner's work
Now, it's time to get your partner's work from his repository. Use git fetch to copy all of his data to your local repository. The fetch command does not alter your local branches, so you can safely do this without changing your work. Then, checkout his branch to a local copy:
git fetch partner git checkout -t partner/<hisbranch>
The command checkout -t creates a local branch with the same name that "tracks" your partner's branch. It also configures your git repository so that the pull command automatically looks at your partner's branch. Now, you can make your own changes and contributions. This procedure is almost always what you need to do if you want to work with a given branch.
Look at your partner's work and verify that the code is good. While you are working in his branch, you can make and commit changes if it is not up to your standards. When you're done, switch back to the master branch to prepare for the merge:
git checkout master git merge <hisbranch>
Check that this merged version of the code works. If it does, then you are ready to push the final, working version of your code to your local repository.
git push mycopy master
Solving merge issues
What if you both changed the same file? git may not be able to tell if your changes are independent, so the merge fails. In this case, git does not create a merge commit. Git marks the spots in each file where it doesn't know what to do:
this is line 1 this is line 2 this is line 3 <<<<<<<<<<<<<<<< this is line 4 that I changed I added this line - - - - - - - - - - - - line 4 that my partner changed >>>>>>>>>>>>>>> this is line 5
You need to look for each of these occurrences, manually fix them, and then save the result. Now, commit all of the changes that git has made to complete the merge:
git add editedFile1 editedFile2 git commit
This will create a merge commit. This is especially helpful to visualize using gitg or gitk on your repository.