Source Code Management / Version Control
What do you want from source code management systems?
- Experimentation without risk of loosing data
- Documentation of the development process
- Easy backup
- Easy collaboration with (remote) co-workers
- No overhead (file cluttering, file locks, server management)
An overview of git
What is git?
A distributed version control (DVC) and source code management (SCM) system
- A content(!) tracker, not a file tracker.
- A command line tool
- Available for all platforms
- Free and open software
The git command-line
Git is a powerful command-line tool you can use on Linux, Mac OS and Windows:
History of git
Developed by Linus Torvalds for the Linux kernel development in 2005 as an replacement for BitKeeper.
- The initial version of git has been written by Torvalds in two weeks.
- Created out of necessity and frustration about the existing source code control sytems (such as CVS).
There is a good Google Tech Talk with Linus Torvalds where he talks about the history and motivation behind git:
- The git code is publicly available and is tracked with … git (available at github.com/git)
- The code is activly maintained by > 50 developers
- In 2012 git has been used by 27% of all professional software developers (see: Eclipse Foundation Survey#Adoption))
- Github one of the largest git hosters has reached 3 milliion users in Januar 2013.
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
- Git does not track single files but a whole filesystem/folder structure by its content
- Git is distributed without a central server
- Every repository contains the complete history
- Git is optimized for rapid branching and merging
- Easy synchronization with other repositories over existing protocols such as http, ftp, rsync or ssh
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
- no central server
- no central repository
- no special permission
Distributed development workflows
git supports all kinds of developement workflows and branching strategries (because of its distributed nature):
One central repository where one or more developers pull from and commit to:
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:
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.
How does git cover the things you expect from a SCM?
Experimenting without loosing changes
- Git allows you to have multiple experimentation or feature branches which do not interfere with the master branch.
- You can keep your experiments for yourself - your co-workers don’t need to know about your experiments if you don’t want to
- You can switch between branches very quickly
- Git encourages developers to commit early and often
- Every developer has a full-copy of the repository
- Every repository contains the full history
- Just copy to the repository folder to another location and you are done
- Every developer can work on his or her own branch
- Easy exchange of commits
- Branches and even single commits can be easily exchanged and merged
- All git needs is a “.git” folder in your repository
- Git does not hold file-locks
- Developers don’t have do asks for permission before editing a file
- You don’t need special infrastructure to exchange commits - all you need is HTTP or SSH
What distinguishes git from centralized SCMs …
… such as Team Foundation Server or SVN (Apache Subversion):
- no need for a server
- no central database
- no need for permission management
- no special infrastructure
- no need to be afraid of branching and merging
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:
But opposed to that, this is how our unhealthy branching “strategy” looks like … because branching and merging is (considered) hard:
Other distributed version control systems
There are other distributed SCMs out there, but not that many …
- Mercurial is quite similar to git
- Written in Python
- I think the GUI tools for Mercurial are much better than those for git
- Mercurial is not as fast as git (at least this is my experience)
- commercial product
- has been used by for the kernel development until 2005
- developed by Canonical
- written in Python
- git is influenced by Monotone
- is not as widely used as Mercurial or Bazaar
- SSH Authentication
- How git works
- Working Tree
- Branch and tags
Setting up git on Windows
- Username, Email
- Merge Tools
- Username, Email
Installation on Windows
For the installation of git goto http://git-scm.com and download the latest version for Windows and execute the installer.
Installation Wizard - Components
In the “Select Components” dialog I suggest that you uncheck
- Additional icons and
- Windows Explorer Integration
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.
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:
Unix-style line ending
Unix just uses a single line feed charachter for indicating new lines:
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.
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.
Testing the installation
When the installation was successful when you can execute “git.exe” from all locations on your system:
Configuration: Username and Email
Global Config File (.gitconfig)
The global git configuration is located in a file called .gitconfig in your home directory
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
> git config --global user.name "Your Name" > git config --global user.email "[email protected]"
Configuration: Merge and Diff Tool
By default git does not ship with much GUI tools and everything is handled in the command-line:
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
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
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
- Creating a repository
- Getting help
- Cloning a repository
- Comparing Commits
- Working with .gitignore files
- Tracking a .NET project
- Tracking a .NET project
- Rebasing a single commit on top of another (Cherry Picking)
- Creating a branch
- Committing changes
- Undoing commits
- Reverting changes
- Merging conflicts
- Merging branches
- Pushing changes to a remote location
- Rewriting history
- Rebasing Repositories
- Managing identities
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>
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:
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
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.
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>
By commiting you can save all staged files to your (local) repository.
> git commit -m "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
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
Or you can use gitk to a view a graphical representation of your commit history:
Undoing your last local commit
If you have accidentally committed a change you can undo your change by using the “reset” command:
<!– language: lang-sh –>
> git reset --soft HEAD~1
<!– language: lang-sh –>
> git reset --soft HEAD^
Note: this does not work for your first commit 😉
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.
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.
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:
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.
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
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 .”
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
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
> git branch -a
Creating a branch
To create a new branch use the “branch” command with the name of your new branch:
> git branch <branch-name>
Switching between branches
To switch your current repository context to another branch you can use the “checkout” command:
> git checkout <branch-name>
Merging branches without no conflicts
To merge a branch into another use the “merge” command:
> git merge <branch-name>
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
You can resolve the conflict with the “mergetool” command:
> git mergetool
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"
Deleting a local branch
Local branches can be easily deleted:
> git branch -d <name-of-the-branch>
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>
> git push origin :<branchName>
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
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>
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
Adding a remote
> git remote add <name of the remote> <Path-or-URL-of-the-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
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.
- github:help - Changing author info
- stackoverflow.com - How do I change the author of a commit in git?
Official git website
Official git website at git-scm.com
Interactive Online Tutorial
Github has created a fun online course for learning git:
Pro Git eBook
The “Pro Git” eBook is available for free on the git website.
Pro Git Online / Pro Git PDF
- Google Tech Talk: Linus Torvals on git
- Git Basics Videos
- Tekpub: Mastering Git
- Pluralsight: Git Fundamentals