Distributed Source Code Management with git

An introduction to distributed source code management with git.
created by on 2013-02-15

git Logo


Source Code Management / Version Control


What do you want from source code management systems?


An overview of git


What is git?

A distributed version control (DVC) and source code management (SCM) system


The git command-line

Git is a powerful command-line tool you can use on Linux, Mac OS and Windows:

$ git

Screenshot of the git command line


History of git

Developed by Linus Torvalds for the Linux kernel development in 2005 as an replacement for BitKeeper.

There is a good Google Tech Talk with Linus Torvalds where he talks about the history and motivation behind git:


git today

Screenshot of the Git Contributors Page at github.com


Why the name “git”?

git := British slang meaning “a rotten person”

I’m an egotistical bastard, and I name all my projects after myself. First Linux, now git.”
- Linus Torvals


Key features of git


Distributed Version Control

Being distributed very much means that you do not have one central
location that keeps track of your data. No single place is more
important than any other single place.
- Linus Torvals


Distributed development workflows

git supports all kinds of developement workflows and branching strategries (because of its distributed nature):

Subversion-Style workflow

One central repository where one or more developers pull from and commit to:

Illustration of the Subversion-Style workflow

Integration Manager Workflow

One single person (the “integration manager”) pulls changes from different sources/developers, combines them in his or her repository and pushes the combined commits to a central “blessed” repository:

Illustration of the Integration Manager Workflow

Dictator and Lieutenants Workflow

In this network of trust a “dictator” pulls from the repositories of her or her trusted “lieutenants” which on their side pull from their trusted developers. The dictator integrates the changes from the lieutenants and then pushes to a central blessed repository.

Illustration of the Dictator and Lieutenants Workflow

source: http://git-scm.com/about/distributed


How does git cover the things you expect from a SCM?

Experimenting without loosing changes

Documentation

Backup

Collaboration

No overhead


What distinguishes git from centralized SCMs …

… such as Team Foundation Server or SVN (Apache Subversion):


Why do I think we could benefit from using git ?

With our centralized version control system branching and merging is so painful for us that we hardly do it.

A healthy branching strategy would look something like this:
Illustration of a health branching strategy which utilizes multiple branches

But opposed to that, this is how our unhealthy branching “strategy” looks like … because branching and merging is (considered) hard:
Illustration of an ubhealth development strategy which does not use branching


Other distributed version control systems

There are other distributed SCMs out there, but not that many …

Mercurial

BitKeeper

Bazaar

Monotone


Basics


Terminology


Setting up git on Windows


Installation on Windows


Installation Wizard

For the installation of git goto http://git-scm.com and download the latest version for Windows and execute the installer.

Screenshot of the git installation wizard start screen


Installation Wizard - Components

In the “Select Components” dialog I suggest that you uncheck

Screenshot of the git installation wizard - Adjusting your PATH environment


Installation Wizard - PATH Variable

The installation wizard asks you how it should integrate with your system. Please check “Run Git from the Windows Command Prompt”. This will make the “git.exe” avaiable from everywhere in your system.

Screenshot of the git installation wizard - Select Components


Installation Wizard - Line Ending Conversion

Because git comes from a Unix background, git uses Unix-style instead of Windows-style line-endings.
You should select the “Checkout Windows-style, commit Unix-style line endings” option.

Windows-style line ending

Windows uses a carriage return charachter and a line feed character for its line endings:

"\r\n"

Unix-style line ending

Unix just uses a single line feed charachter for indicating new lines:

"\n"

Screenshot of the git installation wizard - Line Ending Conversion

Scott Hanselman - You’re just another carriage return line feed in the wall


Installation - bin folder

The git intaller installs a bunch of Windows-compatible Linux commands.

Screenshot of the git installation - Bin Folder


Installation - cmd folder

The cmd-folder contains the git.exe and a script which sets the PATH to the bin folder and then launches a new command prompt.

Screenshot of the git installation - Bin Folder


Testing the installation

When the installation was successful when you can execute “git.exe” from all locations on your system:

Screenshot of the git installation - Command Prompt


Configuration


Configuration: Username and Email


Global Config File (.gitconfig)

The global git configuration is located in a file called .gitconfig in your home directory

> %UserProfile%\.gitconfig


Set Username and Email

In order to set your Username and Email adress for future commits you can either edit the “%UserProfile%.gitconfig” file in an editor of your choice or use git config command with the --global flag:

> git config --global user.name "Your Name"
> git config --global user.email "[email protected]"

Screenshot set username and email - Set Username and Email with git


Configuration: Merge and Diff Tool

By default git does not ship with much GUI tools and everything is handled in the command-line:

Screenshot of the gits command-line based diff viewer

But you can configure git to use other diff and merge tools (but this isn’t that easy on Windows if you don’t use tools which are supported out of the box).


Configuring KDiff3 on Windows

I couldn’t get my perferred merging tool WinMerge to work with git on Windows, but KDiff3 is also quite nice and can be easily configured to work with git.

Step 1 - Download and install KDiff3

http://kdiff3.sourceforge.net

Step 2 - Extend your .gitconfig

[merge]
    tool = kdiff3

[mergetool]
    prompt = false

[mergetool "kdiff3"]
    prompt = false
    path = c:/Program Files (x86)/KDiff3/kdiff3.exe

[diff]
    tool = kdiff3
    guitool = kdiff3

[difftool]
    prompt = false

[difftool "kdiff3"]
    path = c:/Program Files (x86)/KDiff3/kdiff3.exe

Screenshot of the KDiff3 as the diff and merge tool for git

It is supposed to be easy to integrate any other merge tool with git. And it is - at least on Unix based systems. But on Windows I haven’t found a way yet.


Working with git


Typical workflows with git


Using the built-in help

Git comes with a comprehensive help documentation which ships with every installation.

Display an help overview

> git help

Get a detailed list of all git commands

> git help -a

Help about a specific git command

> git help <command>

Screenshot of the git help command result


Creating a repository - git init

You can initialize a repository in any directory by using the init command:

> git init

The init command then creates a hidden subdirectory named “.git” that contains all necessary repository meta-data.


The .git metadata folder

The .git folder is where all you commits, branches and tags will be stored, but for now you don’t need to bother with the contents of this folder:

Screenshot of the content of a .git metadata folder


Checking the status of your repository with git status

You can quickly check which the status of files in your repository/index by using the status command:

> git status

Using git status to check the index of a repository


Adding files to the index

Once you have initialized a repository you can create, modify files and add the new files to the index / staging area.

Add one or more files to the index

> git add <filename1> <filename2>

> git add .
Add all files (in the current directory) to the index

Index / Staging Area

The index aka “staging area” is a file that contains the files that will go into your next commit.

Screenshot of a git repository where a new README.txt file has been added to the Index aka Staging Area


Removing files from the index

You can remove files from the staging area if you have added it accidentally. This means will will not go in your next commit, but the file itself will remain untouched in the folder.

> git rm --cached <filename>

Screenshot removing a file from the staging area


Commiting changes

By commiting you can save all staged files to your (local) repository.

> git commit -m "A first commit"

Screenshot of a first commit

Once you have executed the commit, all changes are recorded to your repository.


Viewing the commit history

Every commit to a repository is recording and the global history of a repository can be viewed with the “log” command.

> git log

Screenshot of results of git log

If you only want to see latest n-commits you can use the -n flag for the log command:

Show only the latest 3 commits
<!– language: lang-sh –>

> git log -n 3

Results of git log -n 3 as a screenshot

Or you can use gitk to a view a graphical representation of your commit history:

Using gitk to view the local commit history


Undoing your last local commit

If you have accidentally committed a change you can undo your change by using the “reset” command:

On Windows:
<!– language: lang-sh –>

> git reset --soft HEAD~1

On Linux:
<!– language: lang-sh –>

> git reset --soft HEAD^

Note: this does not work for your first commit 😉

more details


Correcting a commit message

If you want to change the message of your last commit you can simply type:

> git commit --amend

This command opens up a text editor in which you can simple change the text of your last commit message. Or you can use the -m parameter to enter the message directly:

> git commit --amend -m "Your new commit message text"

Note: Changing the commit message will change the hash of your commit. Therefor you should use this technique carefully if you already pushed your repository to a remote location that is used by other developers.

more details


Reverting a public commit

If you want to take back a commit which has already been pushed to another location can cannot simply “undo” it, because public history cannot be changed. But you can add a commit which reverts another commit.

> git revert <hash of the commit to revert>

git revert applies the inverse of a given commit.

Screenshot of the text editor window that is displayed when a revert is being performed

Result of git revert


Comparing commits

In order to visualize the changes between two commits you can use the diff command:

> git diff <commit-A> <commit-B>

The command will display the differences between the two commits directly in the command line:

Screenshot of git diff in action

If you prefer a nice visualization of the differences between two commits you can use the difftool command instead. The command will open the diff tool you have configured in your .gitconfig.

Screenshot of git diff in action


Git ignore files

If you want to make sure certain files are never added to your index and therefor never commited you can list these files in a file called “.gitignore”.

Example: Ignoring .html files

*.html

Screenshot of an git ignore file


An ignore file for .NET projects

The content of an ingore file for .NET projects typically looks something like this:

[Oo]bj
[Bb]in
*.user
*.suo
*.[Cc]ache
*.bak
*.ncb
*.log 
*.DS_Store
[Tt]humbs.db 
_ReSharper.*
*.resharper

All files which match the patterns specified here will not be added to the index when using “git add .”

more details


Show a list of local branches

The default branch in git is called “master”. To display a list of all branches in your current repository use the “branch” command:

> git branch

Show local branches

The branch that is marked with an asterisk (*) is the branch you are currently on.


Show al list of all branches

To display a complete list of all local and remote branches you can use the -a flag.

> git branch -a

Show all branches


Creating a branch

To create a new branch use the “branch” command with the name of your new branch:

> git branch <branch-name>

Create a new branch


Switching between branches

To switch your current repository context to another branch you can use the “checkout” command:

> git checkout <branch-name>

Switching a branch


Merging branches without no conflicts

To merge a branch into another use the “merge” command:

> git merge <branch-name>

Switching a branch

If the merge can be performed without conflicts you will see the commits from the merged branch in your current branch.


Merging branches with conflicts

If git cannot decide on how to merge changes you will get a merge conflict which needs to be resolved and committed:

> git merge <branch-name>
CONFLICT (content): Merge conflict in ...
Automatic merge failed; fix conflicts and then commit the result

Screenshot of a merge with results in a conflict

You can resolve the conflict with the “mergetool” command:

> git mergetool

Screenshot of the mergetool resolving a conflict

After you have resolved the conflict, you need to stage the changes and commit them:

> git add <file-with-conflict>
> git commit -m "Merged with branch xy"

Results of a branch merge with conflicts after the conflict has been resovled


Deleting a local branch

Local branches can be easily deleted:

> git branch -d <name-of-the-branch>

Deleting a local branch with git branch -d branchname


Deleting a remote branch

In order to delete a branch which has been pushed to a remote location you need to use a different command:

> git push origin --delete <branchName>

or

> git push origin :<branchName>

Deleting a remote branch with git push origin --delete branchname

more details


Cloning a repository

In order to retrieve a copy of an existing repository you can use the clone command:

> git clone <Path-or-URL>

This will clone the repository behind the specified URL or path into a new directory in the current location.

For example you can clone the repository of this presentation from github:

> git clone https://github.com/andreaskoch/Introduction-to-Distributed-Source-Code-Management-with-git.git

Cloning a repository from github


Pulling from another repository

Instead of cloning another repository you can also pull from it into your existing repository.

> mkdir NewRepo
> cd NewRepo
> git init
> git pull <Path-or-URL>

Pulling changes into an existing repository


Pushing changes to a remote repository

If you want to publish your changes to a remote repository you can use the push command:

> git push <name of the remote> <branchname>

Remote := A remote is a version of a project that is located at another location.


Display a list of all remotes

> git remote -v

List all remotes of a repository


Adding a remote

> git remote add <name of the remote> <Path-or-URL-of-the-Repository>

Adding a remote repository


Pulling changes from a remote location

> git pull <name of the remote> <branchname>

Fetching changes from a remote location

git pull will downlaod all changes from the remote respository and merge them with your current branch. If you only want to download the changes without merging them you can use fetch instead of pull:

> git fetch <name of the remote> <branchname>

Cleaning up a repository

If you want to delete all files from your current repository which are not part of your repository and have not been added to the index / stating area you can use the clean command:

> git clean -df

Screenshot of git clean in action


Changing the author info of one or more commits

Sometimes you commit changes with the wrong username or email address configured.

If you want to correct this mistake you can use the “filter-branch” command in a “small” shell script to replace the author info of all commits with the wrong email address with a new email address:

#!/bin/sh

git filter-branch --env-filter '

an="$GIT_AUTHOR_NAME"
am="$GIT_AUTHOR_EMAIL"
cn="$GIT_COMMITTER_NAME"
cm="$GIT_COMMITTER_EMAIL"

if [ "$GIT_COMMITTER_EMAIL" = "[email protected]" ]
then
    cn="Andreas Koch"
    cm="[email protected]"
fi
if [ "$GIT_AUTHOR_EMAIL" = "[email protected]" ]
then
    an="Andreas Koch"
    am="[email protected]"
fi

export GIT_AUTHOR_NAME="$an"
export GIT_AUTHOR_EMAIL="$am"
export GIT_COMMITTER_NAME="$cn"
export GIT_COMMITTER_EMAIL="$cm"
'

Warning: This will be a bit of a problem if you already shared your repository with others - because the SHA1 hashes will change.

Links


Hosting


Useful Resources


Official git website

Official git website at git-scm.com


Interactive Online Tutorial

Github has created a fun online course for learning git:

http://try.github.com

Screenshot of githubs interactive git course website


Pro Git eBook

The “Pro Git” eBook is available for free on the git website.

Pro Git Online / Pro Git PDF

Screenshot of the online version of the Pro Git eBook


Videos


Other Resources

Tags:
Fork allmark on GitHub