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
Source code control the way it was meant to be!
— Linus Torvalds
Presentation by Ivan Kuchin (PH-EDU/GS-AIS-GDI)
Main points
Hands-on
What is git?
Commands
Why git?
Cons
Dos and don'ts
Resources
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
~$ 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\] '
~$ 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)
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)
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
#
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
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
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
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!
~/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!");
}
}
~/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")
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")
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
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
~/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
~/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".
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
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
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
Merge non fast-forward feature to master:
C---D feature
/
A---B---E master
Merge:
C---D feature
/ \
A---B---E---M master
Move commits on top of master:
C---D feature
/
A---B---E master
Rebase:
C'--D' feature
/
A---B---E master
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
*.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
)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
]
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
]
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]
svn
— work with svn repository
submodule
, subtree
— attach foreign repositories
filter-branch
— rewrite history using filters
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
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
[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
Everything in PATH like git-*
can be called like git *
Branching and merging
Distributed
Small and fast
Robust
Staging area
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
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
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
po/.svn — 4.1M — 1 revision
po/.git — 3.2M — 1839 commits
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)
Prepare and review changes before committing
Easily split changes to multiple commits (also in one file)
Commit while still working
No subtree checkout
Commmits are not sequentially numbered
Higher learning curve
Directories are not tracked
Limited file mode tracking
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
git gui
and gitk
Online: toy.github.io/reveal-git
Source: github.com/toy/reveal-git
Created using: reveal.js, HAML, SASS, Ruby, Shell script, Markdown and git :)