Git Guide
Here is a quick guide to git usage.
Installation
You need to install the git-core
, git-gui
and gitk
packages. On recent
distributions, git-core
is a transitional package which depends on git
package.
sudo apt-get install git-core git-gui gitk
Basic usage
Tell your name and address to git:
$ git config --global user.name "Luke Skywalker"
$ git config --global user.email luke.skywalker@apbteam.org
Clone a git repository
Clone the git repository using:
$ git clone http://git.ni.fr.eu.org/apbteam.git
Once this is done, you will get a apbteam
directory with all project files.
Git stores its metadata in the .git
directory. A git clone contains a full
copy of the remote repository with full history and all branches.
You can list local branches using:
$ git branch
* master
Here, there is a single branch named master which is the checked out one.
You can list available branches fetched from the server using:
$ git branch -r
origin/HEAD
origin/master
(-r
means remote)
You can work on our local branch, doing commits, and examining history.
Submodules
Submodules allow foreign repositories to be embedded within a dedicated subdirectory of the source tree, always pointed at a particular commit.
As we use submodules in our repository, this requires an additional setup after the original clone operation:
$ git submodule init
If git responds with {{{remote (origin) does not have a url defined in .git/config}}}, you should setup this url used as base URL for submodules:
$ git config remote.origin.url git://apbteam.org/apbteam.git
$ git submodule init
Now you will be able to update submodules using:
$ git submodule update
Work on local repository
All your commits are local to your repository. Once happy with them, you will be able to push these commits to the remote repository.
Unknown files must be added so that git know them.
$ git add my_new_file.h
You can make a commit with every modified files:
$ git commit -a
Or with modified file in a single directory:
$ git commit my_directory
Or you can stage your changes for the next commit:
$ git add my_modified_file.h
$ git add -u my_updated_directory
$ git rm a_removed_file.c
$ git commit
You can also use git citool
if you prefer a GUI. It will present you all
modified and unknown files so that you can select what will go in the commit.
You can even select parts of files.
You can inspect the current repository state:
$ git status
And issue diff commands to review changes:
$ git diff
$ git diff --cached # To see changes in the stage area (index)
$ git diff origin/master
You can also use gitk
to review changes with a GUI.
Update local repository
To fetch changes from the origin repository, use:
$ git fetch
This will update remote branches. You may use gitk --all
to review changes
using a GUI.
You could merge changes from the origin repository using:
$ git merge origin/master # Do not do this!
But WAIT! This is called an downstream merge and considered bad practice. Usually, you will prefer to rebase your work, this means to pretend your work is based on what you have just fetched. This will ensure a clean, merge-free history, avoiding spaghetti history. This is simple also:
$ git rebase origin/master
If there is conflicts, git will guide you how to solve them, just read carefully its instructions.
You can fetch and rebase with one command:
$ git pull --rebase origin master
Push changes to the remote repository
As simple as:
$ git push origin master
This will push commits you have on your local branch master
to the remote
branch with the same name.
If a push would not result in a fast forward of the remote branch, then it will fail with an error like:
error: remote 'refs/heads/master' is not an ancestor of
local 'refs/heads/master'.
Maybe you are not up-to-date and need to pull first?
This means that either you messed with your history (you changed commits which were published yet) or that you need to fetch changes from the remote repository (more probable).
Please do not do any non fast-forward push!
You can also specify explicit source and destination branches:
$ git push origin my_branch:master
This will push commits you have on your local branch my_branch
to the remote
branch master
.
History rewrite
If you made rubbish with your last commit, fix it, then use the
git commit --amend
to change your last commit.
You can also use git rebase --interactive
to changes previous commits.
But WAIT! NEVER NEVER NEVER change commits which are pushed to another repository. This will result in a non-fast-forward push which will be considered very rude by other developers.
Feature branch work flow
As a general rule, you should try to split your changes into small logical steps, and commit each of them. They should be consistent, working independently of any later commits, pass the test suite, etc. This makes the review process much easier, and the history much more useful for later inspection and analysis, for example with git-blame and git-bisect.
First, and while in your master branch (git checkout master
), pull in the
most recent changes:
$ git checkout master
$ git pull origin master
This should never create a merge commit because we are never working directly in master.
Then, check out a new feature branch, with a short and descriptive name:
$ git checkout -b my_new_feature
Do some work on this branch, committing early and often (for instance, whenever your tests pass). Rebase against the upstream frequently to prevent your branch from diverging significantly:
$ git fetch
$ git rebase origin/master
Once work on the feature is complete, you will have a branch with a lot of small commits like "add new circle command", "fix angle computation", "add missing #include", "oh crap – add angle tests" and so on. This is useful while developing but larger, incremental commits are more easier to maintain. We will use an interactive rebase to squash them together.
We want the rebase to affect only the commits we've made to this branch, not the commits that exist on the upstream. To ensure that we only deal with the "local" commits, use:
git rebase -i origin/master
Git will display an editor window with a list of the commits to be modified, something like:
pick 3dcd585 add new circle command
pick 9f5c362 fix angle computation
pick dcd4813 add missing #include
pick 977a754 oh crap - add angle tests
Now we tell git what we to do. Change these lines to:
pick 3dcd585 add new circle command
squash dcd4813 add missing #include
pick 9f5c362 fix angle computation
squash 977a754 oh crap - add angle tests
Save and close the file. This will squash commits together and present us with a new editor window where we can give the new commit a message.
These commits are now ready to be merged back into upstream. First rebase against any recent changes in the upstream, then push your changes:
$ git fetch
$ git rebase origin/master
$ git push origin my_new_feature:master
(text copied/inspired from http://reinh.com/blog/2009/03/02/a-git-workflow-for-agile-teams.html)
More documentation
See: