Git Tutorial

1. Git
1.1. What is Git?

Git is a distributed version control system (dvcs) written in C. A version control system allows that you can create a history for a collection of files with the possibility to revert them to another state. These collection of files is usually called "source code". In a distributed version control system everyone has a complete copy of the source code (including the complete history of the source code) and can perform version control operations against this local copy. The usage of a dvcs does not require a central code repository.

Git supports branching, e.g. you can have different versions of your source code, for example if you want to develop a new feature you may open a branch in your source code and make the changes in this branch without affecting the main line of your code. Git keeps track of all versions. If you have done some changes which should be keept in the version control system you mark them as relevant (staging) and then you commit these changes to git.

Git allows local commits to your repository and you can later merge these changes with remote repositories. If you want to get the source code from a repository you clone the repository. Once the repository is cloned it is possible to commit changes to the clone. Owners of repositories can merge changes via push (transfer changes to a remote repository) or via pull (getting changes from a remote repository).

Git can be used from the command line; this approach will be described in this tutorial. You also find graphical tools for example EGit for the Eclipse IDE .
1.2. Important terminology

Table 1. Git Terminology Term    Definition
Repository    A repository contains the history, the different versions over time and all different branches and tags. In Git each copy of the repository is again a complete repository. The repository allows to retrieve revisions into your working copy.
Branches and Tags     A Git repository contains always all branches and tags. One of the branches is the default (normally named master). The user checkout a version branch to work in this branch, this is called the "working copy".
Commit     You commit your changes into a repository. This is create a new revision which can be later retrieved, for example if you want to see the source code of an older version. Each commit contains the author and commiter fields which identifies how create the change and who commited it.
URL    An URL in Git determines the location of the repository.
Revision    Represents a version of the source code. Git identifies revisions with SHA1 ids. SHA1 ids are 160-bit long and are represented in hexadecimal. The latest version can be address via "HEAD", the version before that via "HEAD~1" and so on.


1.3. Staging index

Git requires you to mark changes explicit to be relevant for committing them to the repository. For example if you what to have a file or changes in a file being relevant for the next change you have to add them to the so called "staging index" via git "add file". For files which were already committed once you can use the the "-a" flag during a commit. The staging index will be a complete snapshot of the changes.
2. Installation

On Ubuntu you can install the Git command line tool via "sudo apt-get install git-core". A windows version of git can be found on the msysgit Project site
3. Setup
3.1. User Configuration

Configure your user and your email for git via the following command.

               
# Config the user which will be used by git
# Of course you should use your name
git config --global user.name "Lars Vogel"
# Same for the email addess
git config --global user.email "Lars.Vogel@gmail.com"
# Set default so that always all changes are pushed to the repository
git config --global push.default "matching"

           


To query your git settings via:

               
git config --list

           
3.2. Ignore certain files

You can tell git to ignore files via the ".gitignore" file. This file can be in any directory and can contain pattern for files. For example you can tell git to ignore the directory "bin" via the following ".gitignore" in the main directory.

               
bin


Git has also the global setting "core.excludesfile" for specifying global excludes.

4. Getting started with Git

The following will guide you though a typical Git workflow. You will create a few files, create a local Git repository and commit your file into this repository. Afterwards you clone the repository and push and pull some changes between the repositories. Open a command line / shell for the operations. The comments before the commands try to explain the action your are performing.
4.1. Create content

Create some content which we later put under version control.

               
#Switch to home
cd ~/
# create a directory
mkdir ~/repo01.git
# switch into it
cd repo01.git
# create a new directory
mkdir datafiles
# Create a few files
touch test01
touch test02
touch test03
touch datafiles/data.txt
# put a little text into the first file
ls >test01

           

4.2. Create repository, add and commit

Create a Git repository, add the files to the repository and commit your changes.

               
# Initialize the local Git repository
git init
# Add all (files and directory) to the Git repository
git add .
# Make a commit of your file to the local repository
git commit -m "Initial commit"
# Show the log file
git log


           


Every git repository is stored in the .git folder of the root directory. This directory contains in the .git/config the local configuration for the repository and the complete history of the repo.
4.3. Commit changes

Make some changes to the file, see the differences and commit them again to the repository.

               
# Make some changes in the file
echo "This is a change" > test01
echo "and this is another change" > test02

# Check the changes via the diff command
git diff

# commit the changes, -a will commit changes for modified files
# but will not add automatically new files
git commit -a -m "These are new changes - typo in the commit message"


           

4.4. Correct commit message - git amend

In the above example the commit message was incorrect. You can change the last commit message via the --amend parameter.

               
git commit --amend -m "These are new changes"
           

4.5. Delete files

If you delete a file which is under version control "git add ." will not pick this file up. You need to use the git commit command with the -a flag or to use the -u flag in the git add command.

               
# Create a file and put it under version control
touch nonsense.txt
git add . && git commit -m "a new file has been created"
# Remove the file
rm nosense.txt
# Try standard way of committing -> will not work
git add . && git commit -m "a new file has been created"
# Now commit with the -a flag
git commit -a -m"File nosense.txt is now removed"
# Alternatively you could add deleted files to the staging index via
git add -u .

           

4.6. Setting up a remote git repository

We will now create a remote git repository. Git allows to store this remote repository either on the network or locally. For simplification we will a local remote git repository. A standard git repository is different from a remote git repository. A standard git repository contains the source code and the git repository. You can work directly in this directory, e.g. the repo contains the working copy for all files Remote repositories do not contain working copies of the files, they only contain repository files. To create such are repository such the "--bare" flag.

               
# Switch to first repository
cd ~/repo01.git
#
git clone --bare . ../remote-repository.git

# Check the content, is be equal to the .git directory in repo01.git
ls ~//remote-repository.git

           

4.7. Push changes to another repository

Do some changes and push them from your first repository to the remote repository via the following commands.

               
# Make some change in the first repos
cd ~/repo01

# Make some changes in the file
echo "Hello, hello. Turn your radio on" > test01
echo "Bye, bye. Turn your radio off" > test02

# commit the changes, -a will commit changes for modified files
# but will not add automatically new files
git commit -a -m "Some changes"

# push the changes
git push ../remote-repository.git

           

4.8. Add remote

You can always push to a git repository via the full URL to it. But you can also add a "shortname" to a repository via the "git remote add" command. "origin" is a special name which is usually automatically used if you clone a git repository. Origin indicates the original repository from which you started. As we started from scratch this name is still available.

               
# Add ../remote-repository.git with the name origin
git remote add origin ../remote-repository.git

# Again some changes
echo "I added a remote repo" > test02
# commit
git commit -a -m "This is a test for the new remote origin"
# If you don't label a repo it will push to origin
git push origin


           

4.9. Clone your repository

Checkout a new version of your repository into a new directory via the following commands.

               
# Switch to home
cd ~
# make new directory
mkdir repo02.git

# Switch to new directory
cd ~/repo02.git
#
git clone ../remote-repository.git .

           

4.10. Push and pull some changes

Pull allows you to get the latest changes from another repository. In your new repository, make some changes, push them to your remote repository and pull these changes from your first repository.

               
# Switch to home
cd ~

# Switch to second directory
cd ~/repo02.git
# Make changes
echo "A change" > test01
# Commit
git commit -a -m "A change"
# Push changes to remote repository
# origin is automatically maintained as we cloned from this repo
git push origin
# Switch to the first repository can pull in the changes
cd ~/repo01.git
git pull ../remote-repository.git/
# Check the changes
less test01

           

5. Revert Changes

If you create files in your working copy which you don't want to commit you can discard them.

           
# Create a new file with content
touch test04
echo "this is trash" > test04

# Make a dry-run to see what would happen
# -n is the same as --dry-run
git clean -n

# Now delete
git clean -f


       


You can checkout older revisions of your source code via the commit name.

           
# Switch to home
cd ~/repo01.git
# get the log
git log

# Copy one of the older commits and checkout the older revision via
git checkout commit_name


       

If you have not added the changes to the staging index you can also directly revert the changes.

           
#Some stupid change
echo "stupid change" > test01
# Not added to the staging index therefore we can just checkout the old version
git checkout test01
#check the result
cat test01
# Another stupid change
echo "another stupid change" > test01
# We add the file to the staging index
git add test01
# restore the file in the staging index
git reset HEAD test01
# get the old version from the staging index
git checkout test01
       


You can also revert commits via.

           
#Revert a commit
git revert commit_name

       

If you deleted a file but you have not yet added it to the index or commited the change you can checkout the file again.

You can also revert commits via.

           
// Delete a file
rm test01
// Revert the deletion
git checkout test01

       


If you added a file to the index but don't want to commit the file you can remove it from the index via git reset file

           
// create a file
touch incorrect.txt
// accicently add it to the index
git add .
// remove it from the index
git reset incorrect.txt
// delete the file
rm incorrect.txt

       
6. Tagging in Git

Git has the option to tag certain versions in the history so that you later find then easier. Most commonly this is used to tag a certain version which has been released.

You can list the available tags via:

           
git tag
       


You can create a new tag via:

           
git tag -a version1.6 -m 'version 1.6'

       

If you want to use the code associated with the tag, use:

           
git checkout <tag_name>
       

7. Branches and Merging
7.1. Branches

Git allows to create branches, e.g. independent copies of the source code which can be changed independently from each other. The default branch is called "master". Git allows to create branches very fast and cheap in the sense of resource consumption. Developers are encouraged to use branches frequently.

The following command lists all available branches. The currently active branch is marked with "*".

               
git branch
           


You can create a new branch via the following.

               
# Syntax: git branch <name> <hash>
# hash is optional if not specified the last commit will be used
git branch testing
# Switch to your new branch
git checkout testing
# Some changes
echo "Cool new feature in this branch" > test01
git commit -a -m "new feature"
#Switch the master branch
git checkout master
# Check that the content if test01 is the old one
cat test01


           
7.2. Merging

Merge allows to combine the changes of two branches. Merge does perform a three way merge between the latest snapshot of two branches based on the most recent common ancestor of both. As a result you have a new snapshot. You can merge changes from one branch to the current active one via the following command.

               
# Syntax: git merge <branch-name.
git merge testing

           


If a merge conflict occurs Git will mark the conflict in the file and the programmer has to manually fix the conflict. After resolving it he can add the file to the staging index and commit the change.
7.3. Delete a branch

To delete a branch which is not needed anymore you can use the following command.

               
#Delete branch testing
git branch -d testing
# Check if branch has been deleted
git branch

           

8. Solving merge conflicts

Git allows to solve merge conflicts. The following will create a merge conflict.

           
# Switch to first directory
cd ~/repo01.git
# Make changes
touch mergeconflict.txt
echo "Change in the first repo" > mergeconflict.txt
# Stage and commit
git add . && git commit -a -m "Will create merge conflict repo1"
# Switch to second directory
cd ~/repo02.git
# Make changes
touch mergeconflict.txt
echo "Change in the second repo" > mergeconflict.txt
# Stage and commit
git add . && git commit -a -m "Will create merge conflict repo2"
# Try to push to the master repo
git push
# Switch to first directory
cd ~/repo01.git
# Try to push --> you will get an error message
git push
# Get the changes
git pull master origin





       


Git marks the conflict in the affected file. This file looks like the following.

           
<<<<<<< HEAD
Change in the first repo
=======
Change in the second repo
>>>>>>> b29196692f5ebfd10d8a9ca1911c8b08127c85f8

       

The above part is the part from your repo and the below one from the remote repository. You could now edit the file manually and then commit the changes. Alternatively you could use "git mergetool" which would use a configurable merge tool which displays the changes in a split screen.

           
# Either edit the file manually or use
git mergetool
# You will be prompted which merge tool you want to use
# on Ubuntu I use meld
# After manually merging the changes, commit them
git commit -m "merged changes"
       

9. Rebase

In addition to merge, Git allow also to use rebase. As described merge does combine the changes of two branches. Rebase takes the changes of a branch, creates a patch and apply it to another branch. The end result is the same as with merge but the commit history is cleaner; the history appears to be linear.

           
# Create new branch
git branch testing
# Checkout the branch
git checkout experiment
# Do some changes
echo "This will be rebased to master" > test01
# Commit into testing branch
git commit -a -m "New feature in branch"
# Rebase the master
git rebase master

       

10. Working with Git

Of course Git allows more then just committing and push and pulling. The following demonstrates how to work with branches and how to create patches.
10.1. Status and change log

The following helps you to see the changes in your repository.


                   
// See the status
git status
// Shows a log file of the commits
git log
// This start a nice graphical view of the changes
gitk --all

               

10.2. Create and apply patch

The following creates a branch, makes some changes in this branch, creates a patch and applies the patch to the master.


                   
# Create a new branch
git branch mybranch
# Use this new branch
git checkout mybranch
# Do some changes
touch test05
# Change some content in an existing file
echo "New content for test01" >test01
# Commit these to the branch
git add .
git commit -a -m "First commit in the branch"
# Create a patch --> git format-patch master
git format-patch origin/master
# Creates patch 0001-First-commit-in-the-branch.patch
# Switch to the master
git checkout master
# Apply the patch
git apply 0001-First-commit-in-the-branch.patch
# Do your normal commit in the master
git add .
git commit -a -m "Applied patch"
# delete the patch
rm 0001-First-commit-in-the-branch.patch
               

11. Remote repository
11.1. Cloning remote repositories

Git allows of courses also remote operations. Git supports several transport types, the native one of Git is the "git protocol".

               
git clone git://dev.eclipse.org/org.eclipse.jface/org.eclipse.jface.snippets.git
           


Alternatively you could clone the same repository via a the http protocol.

               
git clone http://dev.eclipse.org/git/org.eclipse.jface/org.eclipse.jface.snippets.git
           
11.2. Add more remotes

If you clone a remote repository the original repository will automatically stored as "origan" and if you have write access to the remote repository you can send your changes to it via "git push origin" You can add more remotes repositories to your repository via "git remote add name gitrepo". For example if you cloned the repository from above via the git protocol you could add the http protocol via:

               
// Add the http protocol
git remote add githttp http://dev.eclipse.org/git/org.eclipse.jface/org.eclipse.jface.snippets.git

           

11.3. Remote operations via http and a proxy

It is possible to use the HTTP protocol to clone Git repositories. That is especially helpful if your firewall blocks everything expect http. Git also support a proxy. For example the following command could clone a Eclipse project via http and a proxy. You can either set the proxy variable in general for all applications or set it only for git.

This example uses environment variables.

               
// Linux
export http_proxy=http://proxy:8080
// On Windows
// set http_proxy=http://proxy:8080
git clone http://dev.eclipse.org/git/org.eclipse.jface/org.eclipse.jface.snippets.git
// push back to the origin using https
git push origin
           


This example uses the git config settings.

               
// Set proxy for git globally
 git config --global http.proxy http://proxy:8080
// To check the proxy settings
git config --get http.proxy
// Just in case you need to you can also revoke the proxy settings
git config --global --unset http.proxy


           
12. Installating a git server

As described you don't need a server, you can just use a file system or a public git provider, as Github . But sometimes is it conviniant to have your own server and installing it under Ubuntu is very easy.

First make sure you have ssh installed.

           
apt-get install ssh
       


If you have not yet installed git then you need to do this also.

               
sudo apt-get install git-core
           

Create a new user for git.

           
sudo adduser git

       


Now logon to the git user and create a bare repository.

           
# login to server
# to test use localhost
ssh git@IP_ADDRESS_OF_SERVER

# Create repository
mkdir example.git
cd example.git
git --bare init

       

Now you can commit to the remote repository.

           
mkdir gitexample
cd gitexample
git init
touch README
git add README
git commit -m 'first commit'
git remote add origin git@IP_ADDRESS_OF_SERVER:example.git
git push origin master

       

13. GitHub

So far all operations we done have been done without a server. To use a server you can use the free hosting offering from Github .

Github requires you to create a ssh key. For creating such a key in Ubuntu please see ssh key creation in Ubuntu . For windows please see msysgit ssh key generation

Create an account at Github and create a repository. After creating a repository at GitHub you get a description which commands to run to upload for project. Follow these instructions.
14. Git and svn

Git provides the "git-svn" command line tool to run git against a svn repository. A good explanation for this can be found Git and svn .
15. Graphical UI's for Git
15.1. UI for Git

git ships with two graphical tools. "gitk" shows the history and "git gui" show an editor which allows to perform git operations.
15.2. TortoiseGit for Microsoft

Similar to TortoiseSVN you can use TortoiseGit to have a integration into the file explorer under Windows.
15.3. Eclipse and EGit

The Eclipse EGit project provides Git integration into Eclipse. See Git with Eclipse for details.









Comments