git for svn users

Source code control the way it was meant to be!

— Linus Torvalds

Presentation by Ivan Kuchin (PH-EDU/GS-AIS-GDI)

Plan

Main points

Hands-on

What is git?

Commands

Why git?

Cons

Dos and don'ts

Resources

Main points

Distributed — everything is in your repo

Easy branching and merging

Small and fast

Commit is a SHA1 hash of content and meta info

Staging area — know what you commit

Hands-on

A bit of config

~$ git config --global user.name 'Ivan Kuchin'
~$ git config --global user.email ivan.kuchin@cern.ch
~$ git config --global color.ui auto

And ancient bash magic:

~$ GIT_PS1_SHOWDIRTYSTATE=true
~$ GIT_PS1_SHOWSTASHSTATE=true
~$ GIT_PS1_SHOWUNTRACKEDFILES=true
~$ GIT_PS1_SHOWUPSTREAM=auto
~$ PS1='\[\e[m\e[1;33m\]\w$(__git_ps1 "\[\e[0;1m\]×\[\e[1;36m\]%s")\[\e[0;1m\]\$\[\e[m\] '

Hands-on

Create new repository

~$ mkdir hello-world
~$ cd hello-world
~/hello-world$ git init
Initialized empty Git repository in /Users/ikuchin/hello-world/.git/

Status

~/hello-world×master #$ git status
# On branch master
#
# Initial commit
#
nothing to commit (create/copy files and use "git add" to track)

Hands-on

Create readme

Create file README with content:

Prints "Hello, World".

Status

~/hello-world×master #%$ git status
# On branch master
#
# Initial commit
#
# Untracked files:
# (use "git add ..." to include in what will be committed)
#
# README
nothing added to commit but untracked files present (use "git add" to track)

Hands-on

Stage first file

Stage README

~/hello-world×master #%$ git add README

Status

~/hello-world×master #$ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
# (use "git rm --cached ..." to unstage)
#
# new file: README
#

Hands-on

Commit first file

Commit

~/hello-world×master #$ git commit --message 'README'
[master (root-commit) a195791] README
1 file changed, 1 insertion(+)
create mode 100644 README

Status

~/hello-world×master$ git status
# On branch master
nothing to commit, working directory clean

Hands-on

Checkout new branch

git branch abc && git checkout abc == git checkout -b abc

~/hello-world×master$ git checkout -b implementation
Switched to a new branch 'implementation'

Status

~/hello-world×implementation$ git status
# On branch implementation
nothing to commit, working directory clean

Hands-on

Start implementing

Create file HelloWorld.java with content:

public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World")
}
}

Stage

~/hello-world×implementation %$ git add HelloWorld.java

Commit

~/hello-world×implementation +$ git commit --message 'Implemented HelloWorld'
[implementation 901c38c] Implemented HelloWorld
1 file changed, 5 insertions(+)
create mode 100644 HelloWorld.java

Hands-on

Test and fix

Oops…

~/hello-world×implementation$ javac HelloWorld.java
HelloWorld.java:3: ';' expected
System.out.println("Hello, World")
^
1 error

Fix HelloWorld.java:

System.out.println("Hello, World!");

It works!

~/hello-world×implementation *$ javac HelloWorld.java && java HelloWorld
Hello, World!

Hands-on

Show diff

~/hello-world×implementation *%$ git diff
diff --git a/HelloWorld.java b/HelloWorld.java
index e41a5a3..4065c10 100644
--- a/HelloWorld.java
+++ b/HelloWorld.java
@@ -1,5 +1,5 @@
public class HelloWorld {
public static void main(String[] args) {
- System.out.println("Hello, World")
+ System.out.println("Hello, World!");
}
}

Hands-on

Check status

~/hello-world×implementation *%$ git status
# On branch implementation
# Changes not staged for commit:
# (use "git add ..." to update what will be committed)
# (use "git checkout -- ..." to discard changes in working directory)
#
# modified: HelloWorld.java
#
# Untracked files:
# (use "git add ..." to include in what will be committed)
#
# HelloWorld.class
no changes added to commit (use "git add" and/or "git commit -a")

Hands-on

Ignore build results

Create file .gitignore with content:

*.class

Check status

~/hello-world×implementation *%$ git status
# On branch implementation
# Changes not staged for commit:
# (use "git add ..." to update what will be committed)
# (use "git checkout -- ..." to discard changes in working directory)
#
# modified: HelloWorld.java
#
# Untracked files:
# (use "git add ..." to include in what will be committed)
#
# .gitignore
no changes added to commit (use "git add" and/or "git commit -a")

Hands-on

Commit changes separately

Amend last commit with fix

~/hello-world×implementation *%$ git add HelloWorld.java

commit --amend — enhance last commit with staged changes + change message

~/hello-world×implementation +%$ git commit --amend --message 'Implemented HelloWorld'
[implementation abb7cf3] Implemented HelloWorld
1 file changed, 5 insertions(+)
create mode 100644 HelloWorld.java

Commit ignore pattern

~/hello-world×implementation %$ git add .gitignore
~/hello-world×implementation +$ git commit --message 'ignore *.class'
[implementation cd60fe8] ignore *.class
1 file changed, 1 insertion(+)
create mode 100644 .gitignore

Hands-on

Merge branch

Switch to master

~/hello-world×implementation$ git co master
Switched to branch 'master'

--no-ff — create merge commit even if fast forward can be used

~/hello-world×master %$ git merge --no-ff implementation --message 'merge initial implementation'
Merge made by the 'recursive' strategy.
.gitignore | 1 +
HelloWorld.java | 5 +++++
2 files changed, 6 insertions(+)
create mode 100644 .gitignore
create mode 100644 HelloWorld.java

Hands-on

Show history

~/hello-world×master$ git log --graph --all --format=format:'%C(bold yellow)%h%C(reset) - %C(white)%s%C(reset) %C(bold white)— %an%C(reset)%C(bold yellow)%d%C(reset)%n'
* f11464c - merge initial implementation — Ivan Kuchin (HEAD, master)
|\
| |
| * cd60fe8 - ignore *.class — Ivan Kuchin (implementation)
| |
| * abb7cf3 - Implemented HelloWorld — Ivan Kuchin
|/
|
* a195791 - README — Ivan Kuchin

Hands-on

Resulting files

~/hello-world×master$ git ls-files
.gitignore
HelloWorld.java
README
~/hello-world×master$ git show HEAD:.gitignore
*.class
~/hello-world×master$ git show HEAD:HelloWorld.java
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
~/hello-world×master$ git show HEAD:README
Prints "Hello, World".

What is git?

Terms 1/2

Workspace — directory associated with repository

Staging area (or Index) — changes registered for commit

Repository — commits, branches, tags, HEAD

Remote repository — name for linked repository like origin or central

What is git?

Terms 2/2

Commit — snapshot of repository, parent commit(s), message, author, date

Branch — named reference to a commit like master or dev

Tag — also reference to a commit but not moving

HEAD — reference to current branch or to current commmit

Remote branch — local reference to the state of remote branch

Advanced: objects, gitrevisions

What is git?

Merging 1/2

Merge feature to master:

                   C---D feature
                  /
             A---B master

Fast-forward:

             A---B---C---D master, feature

No fast-forward:

                   C---D feature
                  /     \
             A---B-------M master

What is git?

Merging 2/2

Merge non fast-forward feature to master:

                   C---D feature
                  /
             A---B---E master

Merge:

                   C---D feature
                  /     \
             A---B---E---M master

What is git?

Rebasing

Move commits on top of master:

                   C---D feature
                  /
             A---B---E master

Rebase:

                       C'--D' feature
                      /
             A---B---E master

What is git?

Cherry picking

Copy change to master:

                   C---X---E feature
                  /
             A---B master

Cherry-pick:

                   C---X---E feature
                  /
             A---B---X' master

Rebase skips change:

                       C'--E' feature
                      /
             A---B---X' master

What is git?

Ignore patterns

*.zip
/stacktrace.log
/target/
/out/
  • .gitignore — for team, tracked, can be in subdirectories
  • .git/info/exclude — for you
  • ~/.gitignore — for all your repos (name specified in ~/.gitconfig)

Commands

Essential 1/2

help

init — init repository [svnadmin]

clone — clone repository [svn checkout]

status — show status of workspace and stage area

add, mv, rm or just add -A — stage changes

commit — create commit

log — show commit history

diff — show changes

merge — join histories

rebase — move history changes [svn]

cherry-pick — copy history changes [svn merge -c]

Commands

Essential 2/2

checkout — checkout branch or paths [svn revert|switch]

reset — reset current HEAD, workspace, stage area [svn]

branch — create, list, delete branches

tag — create, list, delete tags

remote — create, list, delete remotes [svn]

fetch — fetch remote refs and objects [svn]

pull — fetch and merge from remote [svn update]

push — update remote refs and upload objects [part of svn commit]

Commands

Helpful

revert — commit reverting change

clean — remove untracked files [svn]

show — show objects [svn cat|list|log|diff]

blame — show author of changes

stash — put aside your work [svn]

bisect — find the bad guy commit introducing bug [svn]

and advanced

svn — work with svn repository

submodule, subtree — attach foreign repositories

filter-branch — rewrite history using filters

Commands

porcelain (high level)

Main: add am archive bisect branch bundle checkout cherry-pick citool clean clone commit describe diff fetch format-patch gc grep gui init log merge mv notes pull push rebase reset revert rm shortlog show stash status submodule tag gitk

Ancillary: annotate archimport blame cherry config count-objects cvsexportcommit cvsimport cvsserver difftool fast-export fast-import filter-branch fsck get-tar-commit-id help imap-send instaweb merge-tree mergetool p4 pack-refs prune quiltimport reflog relink remote repack replace request-pull rerere rev-parse send-email show-branch svn verify-tag whatchanged

plumbing (low level)

apply cat-file check-attr check-ignore check-ref-format checkout-index column commit-tree credential credential-cache credential-store daemon diff-files diff-index diff-tree fetch-pack fmt-merge-msg for-each-ref hash-object http-backend http-fetch http-push index-pack ls-files ls-remote ls-tree mailinfo mailsplit merge-base merge-file merge-index merge-one-file mktag mktree name-rev pack-objects pack-redundant parse-remote patch-id prune-packed read-tree receive-pack rev-list send-pack sh-i18n sh-setup shell show-index show-ref stripspace symbolic-ref unpack-file unpack-objects update-index update-ref update-server-info upload-archive upload-pack var verify-pack write-tree

Commands

Customize

Define aliases

[alias]
	s = status
	ci = commit
	a = add --all
	d = diff --ignore-space-change
	wd = diff --color-words
	lg = log --graph --all --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(bold white)— %an%C(reset)%C(bold yellow)%d%C(reset)' --abbrev-commit --date=relative

Create your commands

Everything in PATH like git-* can be called like git *

Why git?

Branching and merging

Distributed

Small and fast

Robust

Staging area

Why git?

Branching and merging

Branches are cheap

Just named references, no copying or linking files, no history entry

Create branch for every feature, test or experiment

Easily switch branches

Merge worthwhile and delete unsuccessful

No obligation to share branches

Why git?

Distributed VCS

Every repository is self-contained and works as a backup

Commit early, commit often, commit without disturbing others helps to merge

Commit before merge rather than update then commit

Server is not required until you need to share/publish work

Different workflows (git flow, pull requests, …)

Workflow depends on your team, not on your VCS

git init is enough when you need source control

Why git?

Small and fast

Nearly all operations run locally

Even network operations are several times faster than SVN (except clone)

Was built for speed, performance and handling big projects from start

An example:

po/.svn — 4.1M — 1 revision

po/.git — 3.2M — 1839 commits

Why git?

Robust

Simple data model with integrity using SHA1 hashes

Tracks content rather than differences/files

Tries its best to protect your data

Allows changing history (Ministry of Truth is satisfied)

But makes it obviously alternative (Ministry of Truth is furious)

Why git?

Staging area

Prepare and review changes before committing

Easily split changes to multiple commits (also in one file)

Commit while still working

Cons

No subtree checkout

Commmits are not sequentially numbered

Higher learning curve

Directories are not tracked

Limited file mode tracking

Dos and don'ts

Commit early and often

Choose a workflow and agree upon it with your team

Create branches

Make useful commit messages

Keep up to date (sync early, sync often)

Enforce standards

Don't change official published history

Don't change tags

Resources

Guis

so, git?

Online: toy.github.io/reveal-git

Source: github.com/toy/reveal-git

Created using: reveal.js, HAML, SASS, Ruby, Shell script, Markdown and git :)