Git

(FS and DVCS)

by Michal Jurosz (mj41)
generated: 8.6.2015

Git FS

"I really really designed it coming at the problem from the viewpoint of a filesystem person (hey, kernels is what I do), and I actually have absolutely zero interest in creating a traditional SCM system."

-- Linus Torvals

Git

  • a content-addressable filesystem
  • manages tree snapshots (joined by commits) over time
  • distributed version control system

Why Git? Linux

  • 2002 - 2005 proprietary BitKeeper
  • Apr 7, Linus Torvals - based on BitKeeper concepts

    Msg:    Initial revision of "git", the information manager
            from hell
    Author: Linus Torvalds <torvalds@ppc970.osdl.org>
    Date:   Thu Apr 7 15:13:13 2005 -0700
    Files:  cat-file.c, commit-tree.c, show-diff.c, ...
    
  • May 26 - Linux 2.6.12 - the first release with Git

  • December 21 - Git 1.0

Linux needs

  • distributed, fast, many files, robust
  • effective storage - full history
  • non-linear development, trial branches, complex merges
  • toolkit-based design, pluggable merge strategies
  • cryptographic authentication of history

Annual Linux Development Report

  • by Linux Foundation - April 3, 2012
  • Linux 3.2 release - Apr 1, 2012
    • 15,004,006 lines of code
  • 72 days since 3.1.
    • 11,881 patches, 6.88 per hour
    • 1,316 developers from 226 organizations
  • 2005-2015
    • 12,000 developers from 1200 organizations

No Silver Bullet

  • permissions, ownership, empty directories, ...
  • individual files (not project's files)
  • large binary files (GitHub: Git LFS)

  • complexity - commit/push, checkout/clone
  • no subtree of repository checkout
  • no sequentially revision numbers

  • CVS 10%, Git 38%, Subversion 46% - ohloh.net

Pit stop 1

  • short intro

Questions?

git help


> git help
usage: git [--version] [--help] [-C <path>] [-c name=value]
           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
           [-p|--paginate|--no-pager] [--no-replace-objects] [--bare]
           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
           <command> [<args>]

The most commonly used git commands are:
   add        Add file contents to the index
   bisect     Find by binary search the change that introduced a bug
   branch     List, create, or delete branches
   checkout   Checkout a branch or paths to the working tree
   clone      Clone a repository into a new directory
   commit     Record changes to the repository
   diff       Show changes between commits, commit and working tree, etc
   fetch      Download objects and refs from another repository
   grep       Print lines matching a pattern
   init       Create an empty Git repository or reinitialize an existing one
   log        Show commit logs
   merge      Join two or more development histories together
   mv         Move or rename a file, a directory, or a symlink
   pull       Fetch from and integrate with another repository or a local branch
   push       Update remote refs along with associated objects
   rebase     Forward-port local commits to the updated upstream head
   reset      Reset current HEAD to the specified state
   rm         Remove files from the working tree and from the index
   show       Show various types of objects
   status     Show the working tree status
   tag        Create, list, delete or verify a tag object signed with GPG

'git help -a' and 'git help -g' lists available subcommands and some
concept guides. See 'git help <command>' or 'git help <concept>'
to read about a specific subcommand or concept.

Porcelain/plumbing

  • porcelain
    • high level
    • user
  • plumbing
    • low level
    • scripts (e.g. null string separators)
    • upward compatible

git help -a


> git help -a
usage: git [--version] [--help] [-C <path>] [-c name=value]
           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
           [-p|--paginate|--no-pager] [--no-replace-objects] [--bare]
           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
           <command> [<args>]

available git commands in '/usr/libexec/git-core'

  add                       merge-one-file
  add--interactive          merge-ours
  am                        merge-recursive
  annotate                  merge-resolve
  apply                     merge-subtree
  archive                   merge-tree
  bisect                    mergetool
  bisect--helper            mktag
  blame                     mktree
  branch                    mv
  bundle                    name-rev
  cat-file                  notes
  check-attr                pack-objects
  check-ignore              pack-redundant
  check-mailmap             pack-refs
  check-ref-format          patch-id
  checkout                  prune
  checkout-index            prune-packed
  cherry                    pull
  cherry-pick               push
  clean                     quiltimport
  clone                     read-tree
  column                    rebase
  commit                    receive-pack
  commit-tree               reflog
  config                    relink
  count-objects             remote
  credential                remote-ext
  credential-cache          remote-fd
  credential-cache--daemon  remote-ftp
  credential-gnome-keyring  remote-ftps
  credential-store          remote-http
  describe                  remote-https
  diff                      repack
  diff-files                replace
  diff-index                request-pull
  diff-tree                 rerere
  difftool                  reset
  difftool--helper          rev-list
  fast-export               rev-parse
  fast-import               revert
  fetch                     rm
  fetch-pack                send-pack
  filter-branch             sh-i18n--envsubst
  fmt-merge-msg             shell
  for-each-ref              shortlog
  format-patch              show
  fsck                      show-branch
  fsck-objects              show-index
  gc                        show-ref
  get-tar-commit-id         stage
  grep                      stash
  hash-object               status
  help                      stripspace
  http-backend              submodule
  http-fetch                subtree
  http-push                 symbolic-ref
  imap-send                 tag
  index-pack                unpack-file
  init                      unpack-objects
  init-db                   update-index
  instaweb                  update-ref
  log                       update-server-info
  ls-files                  upload-archive
  ls-remote                 upload-pack
  ls-tree                   var
  mailinfo                  verify-commit
  mailsplit                 verify-pack
  merge                     verify-tag
  merge-base                web--browse
  merge-file                whatchanged
  merge-index               write-tree
  merge-octopus

'git help -a' and 'git help -g' lists available subcommands and some
concept guides. See 'git help <command>' or 'git help <concept>'
to read about a specific subcommand or concept.

git init


> cd ~/git-tt

> mkdir repo-MJ

> cd repo-MJ

> git init
Initialized empty Git repository in /home/linus/git-tt-1433775564-435/repo-MJ/.git/

> ls -a
.
..
.git

Git files (empty)


> tree -aF .git
.git
|-- HEAD
|-- branches/
|-- config*
|-- description
|-- hooks/
|-- info/
|   `-- exclude
|-- objects/
|   |-- info/
|   `-- pack/
`-- refs/
    |-- heads/
    `-- tags/

9 directories, 4 files

The three trees 1/2

  • "HEAD tree" (in local repository)
    • HEAD - the snapshot of your last commit
  • index - cache, staging area
    • proposed next commit snapshot
  • working directory (working tree)
    • sandbox, files you see

Working directory


> pwd
/home/linus/git-tt-1433775564-435/repo-MJ

> echo "textA line 1" > fileA.txt

> echo "textB line 1" > fileB.txt

> ls -a
.
..
.git
fileA.txt
fileB.txt

git status


> git status
On branch master

Initial commit

Untracked files:
  (use "git add <file>..." to include in what will be committed)

	fileA.txt
	fileB.txt

nothing added to commit but untracked files present (use "git add" to track)

> git status --short
?? fileA.txt
?? fileB.txt

Index (stage, cache)


NAME
       git-ls-files - Show information about files in the index and
       the working tree

> git ls-files --cached

> git add fileA.txt

> git ls-files --cached
fileA.txt

git status (again)


> git status
On branch master

Initial commit

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

	new file:   fileA.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)

	fileB.txt

> git status --short
A  fileA.txt
?? fileB.txt

Add to index (stage, cache)

  • objects - blob, tree, commit, tag
    • type, size, content
  • SHA-1 hash/checksum - 160-bit, 20 bytes
    • 40 hexadecimal number - e.g. 8e4b68ee140cfbeaee5d38671cb03c83d1b6f2a4
    • default 7 shown- e.g. 8e4b68e
    • minimum 4 required - e.g. 8e4b


> git hash-object fileA.txt
8e4b68ee140cfbeaee5d38671cb03c83d1b6f2a4

.git after index change 1/4


> find .git/objects -type f
.git/objects/8e/4b68ee140cfbeaee5d38671cb03c83d1b6f2a4

> git add fileA.txt

> find .git/objects -type f
.git/objects/8e/4b68ee140cfbeaee5d38671cb03c83d1b6f2a4

> tree -aF .git

.git after index change 2/4


.git                         .git
|-- HEAD                     |-- HEAD
|-- branches/                |-- branches/
|-- config*                  |-- config*
|-- description              |-- description
|-- hooks/                   |-- hooks/
                           > |-- index
|-- info/                    |-- info/
|   `-- exclude              |   `-- exclude
|-- objects/                 |-- objects/
                           > |   |-- 8e/
                           > |   |   `-- 4b68ee140cfbea
|   |-- info/                |   |-- info/
|   `-- pack/                |   `-- pack/
`-- refs/                    `-- refs/
    |-- heads/                   |-- heads/
    `-- tags/                    `-- tags/

.git after index change 3/4


> hexdump .git/objects/8e/4b68ee140cfbeaee5d38671cb03c83d1b6f2a4 | head -n1
0000000 0178 ca4b 4fc9 3052 6634 4928 28ad 5471

       git-cat-file - Provide content or type and size information

> git cat-file -p 8e4b68ee140cfbeaee5d38671cb03c83d1b6f2a4
textA line 1

> git cat-file -t 8e4b68ee140cfbeaee5d38671cb03c83d1b6f2a4
blob

> git cat-file -s 8e4b68ee140cfbeaee5d38671cb03c83d1b6f2a4
13

.git after index change 4/4


> git hash-object fileA.txt
8e4b68ee140cfbeaee5d38671cb03c83d1b6f2a4

> git cat-file -t 8e4b68ee140cfbeaee5d38671cb03c83d1b6f2a4
blob

> file .git/index
.git/index: Git index, version 2, 1 entries

> git ls-files --cached
fileA.txt

> find .git/objects -type f | head -n 5
.git/objects/8e/4b68ee140cfbeaee5d38671cb03c83d1b6f2a4

Git objects

  • blob
  • tree
  • commit
  • tag

Git objects: blob, tree

  • a blob object - content of a file
    • no file name, time stamps, or other metadata
  • a tree object - the equivalent of a directory
    • describes a snapshot of the source tree
    • names of blob and tree objects (type bits)

Git objects: commit

  • a commit object
    • links tree objects together into a history
    • the name of a tree object (of the top-level source directory)
    • a time stamp, a log message
    • the names of zero or more parent commit objects

Git objects: tag

  • a tag object
    • a container that contains reference to another object
    • and can hold additional meta-data

First commit (attempt)


> git commit -m"commit 01 message"
[master (root-commit) 7d6e090] commit 01 message
 1 file changed, 1 insertion(+)
 create mode 100644 fileA.txt

Config --global (user)


> cat ~/.gitconfig
[user]
	email = mj@mj41.cz
	name = Michal Jurosz
[alias]
	st = status
	ci = commit
	co = checkout
	br = branch

> git config --global user.email "mj@mj41.cz"

> git config --global user.name "Michal Jurosz"

> cat ~/.gitconfig
[user]
	email = mj@mj41.cz
	name = Michal Jurosz
[alias]
	st = status
	ci = commit
	co = checkout
	br = branch

Config --local (directory)


> git config --local git-course-conf.local-var1 mj41

> git config git-course-conf.local-var1 mj41

> grep git-course-conf -A 2 .git/config
[git-course-conf]
	local-var1 = mj41

> git config --remove-section git-course-conf

> grep git-course-conf -A 2 .git/config

Config --system (/etc)


> sudo git config --system git-course-conf.system-var1 system-mj41

> cat /etc/gitconfig
cat: /etc/gitconfig: No such file or directory

git aliases


> git config --global alias.st status

> git config --global alias.ci commit

> git config --global alias.co checkout

> git config --global alias.br branch

First commit (finally)


> git commit -m"commit 01 message"
On branch master
Untracked files:
	fileB.txt

nothing added to commit but untracked files present

> git log
commit 7d6e09068aa3db89e331ab902a86438b4b929941
Author: Michal Jurosz <mj@mj41.cz>
Date:   Mon Jun 8 10:59:24 2015 -0400

    commit 01 message

> git log --oneline --decorate
7d6e090 (HEAD, master) commit 01 message

.git after first commit 1/5


> tree -aF .git

.git                         .git
                           > |-- COMMIT_EDITMSG
|-- HEAD                     |-- HEAD
|-- branches/                |-- branches/
|-- config*                  |-- config*
|-- description              |-- description
|-- hooks/                   |-- hooks/
|-- index                    |-- index
|-- info/                    |-- info/
|   `-- exclude              |   `-- exclude
                           > |-- logs/
                           > |   |-- HEAD
                           > |   `-- refs/
                           > |       `-- heads/
                           > |           `-- master
|-- objects/                 |-- objects/

.git after first commit 2/5


|-- objects/                 |-- objects/
                           > |   |-- 4a/
                           > |   |   `-- f19c541178897f
                           > |   |-- 7d/
                           > |   |   `-- 6e09068aa3db89
|   |-- 8e/                  |   |-- 8e/
|   |   `-- 4b68ee140cfbea   |   |   `-- 4b68ee140cfbea
|   |-- info/                |   |-- info/
|   `-- pack/                |   `-- pack/
`-- refs/                    `-- refs/
    |-- heads/                   |-- heads/
                           >     |   `-- master
    `-- tags/                    `-- tags/

.git after first commit 3/5


> cat .git/COMMIT_EDITMSG
commit 01 message

> find .git/objects -type f
.git/objects/7d/6e09068aa3db89e331ab902a86438b4b929941
.git/objects/4a/f19c541178897fb76436c785b2b86d8e9fb9f7
.git/objects/8e/4b68ee140cfbeaee5d38671cb03c83d1b6f2a4

tree object


> git cat-file -t 4af19c541178897fb76436c785b2b86d8e9fb9f7
tree

> git cat-file -p 4af19c541178897fb76436c785b2b86d8e9fb9f7
100644 blob 8e4b68ee140cfbeaee5d38671cb03c83d1b6f2a4	fileA.txt

commit object


> git cat-file -t 7d6e09068aa3db89e331ab902a86438b4b929941
commit

> git cat-file -p 7d6e09068aa3db89e331ab902a86438b4b929941
tree 4af19c541178897fb76436c785b2b86d8e9fb9f7
author Michal Jurosz <mj@mj41.cz> 1433775564 -0400
committer Michal Jurosz <mj@mj41.cz> 1433775564 -0400

commit 01 message

> git log -n1
commit 7d6e09068aa3db89e331ab902a86438b4b929941
Author: Michal Jurosz <mj@mj41.cz>
Date:   Mon Jun 8 10:59:24 2015 -0400

    commit 01 message

.gitignore 1/2


> touch tempf.tmp

> mkdir -p tmp ; touch tmp/tf.txt

> git status --short
?? fileB.txt
?? tempf.tmp
?? tmp/

.gitignore 2/2


> echo 'tmp/' > .gitignore

> echo '*.tmp' >> .gitignore

> git status --short
?? .gitignore
?? fileB.txt

> git add .gitignore

Second commit


> cat fileB.txt
textB line 1

> git add fileB.txt

> git commit -m"commit 02 message"
[master ec23b35] commit 02 message
 2 files changed, 3 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 fileB.txt

> git log --decorate --graph --pretty=format:'%h -%d %s <%ae>' --all
* ec23b35 - (HEAD, master) commit 02 message <mj@mj41.cz>
* 7d6e090 - commit 01 message <mj@mj41.cz>

> git branch BRc2

Third commit 1/3


> echo "textB line 2" >> fileB.txt

> cat fileB.txt
textB line 1
textB line 2

> mkdir dirH

> echo "textHC line 1" > dirH/fileHC.txt

Third commit 2/3


> git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

	modified:   fileB.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)

	dirH/

no changes added to commit (use "git add" and/or "git commit -a")

Third commit 3/3


> git add fileB.txt

> git add dirH

> git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	new file:   dirH/fileHC.txt
	modified:   fileB.txt

> git commit -m"commit 03 message"
[master fcb9538] commit 03 message
 2 files changed, 2 insertions(+)
 create mode 100644 dirH/fileHC.txt

Fourth commit (-a)


> echo "textHC line 2" >> dirH/fileHC.txt

> git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

	modified:   dirH/fileHC.txt

no changes added to commit (use "git add" and/or "git commit -a")

> git commit -a -m"commit 04 message"
[master e4d63af] commit 04 message
 1 file changed, 1 insertion(+)

cat tree (the real one) 1/2


> git cat-file -t 2afe2cf674f123661ecbf68b698f1ffd4a1f5f23
tree

> git cat-file -p 2afe2cf674f123661ecbf68b698f1ffd4a1f5f23
100644 blob 60d6882bff469b815a3ba2334520ee7987f0bc92	.gitignore
040000 tree f584e5928a3315c4dc8dcf09b46d3e4d8d711f83	dirH
100644 blob 8e4b68ee140cfbeaee5d38671cb03c83d1b6f2a4	fileA.txt
100644 blob 3d67da922cae213e0ba10593c31c763543c97fee	fileB.txt

> git cat-file -t f584e5928a3315c4dc8dcf09b46d3e4d8d711f83
tree

> git cat-file -p f584e5928a3315c4dc8dcf09b46d3e4d8d711f83
100644 blob 7dd188dd69574eee96bc02f5783a01eceb30f8c3	fileHC.txt

cat tree (the real one) 2/2


> git cat-file -t 7dd188dd69574eee96bc02f5783a01eceb30f8c3
blob

> git cat-file -p 7dd188dd69574eee96bc02f5783a01eceb30f8c3
textHC line 1
textHC line 2

Cryptographic

  • the last commit - sha1
  • cryptographic authentication of history
  • commit
    • -> working tree -> trees + blobs
    • -> parent commit(s)
      • -> working tree(s) ...
      • ...
        • the first commit (without any parent)

clean index


> git status --short

> git ls-files -s
100644 60d6882bff469b815a3ba2334520ee7987f0bc92 0	.gitignore
100644 7dd188dd69574eee96bc02f5783a01eceb30f8c3 0	dirH/fileHC.txt
100644 8e4b68ee140cfbeaee5d38671cb03c83d1b6f2a4 0	fileA.txt
100644 3d67da922cae213e0ba10593c31c763543c97fee 0	fileB.txt

> echo "textHC line 3" >> dirH/fileHC.txt

> git add -A ; git status --short
M  dirH/fileHC.txt

> git ls-files -s
100644 60d6882bff469b815a3ba2334520ee7987f0bc92 0	.gitignore
100644 69694edab7d1f25fc6565ce60c6818dd615833e1 0	dirH/fileHC.txt
100644 8e4b68ee140cfbeaee5d38671cb03c83d1b6f2a4 0	fileA.txt
100644 3d67da922cae213e0ba10593c31c763543c97fee 0	fileB.txt

symbolic-ref (HEAD), refs


> git log --oneline --decorate -n2
e4d63af (HEAD, master) commit 04 message
fcb9538 commit 03 message

> cat .git/HEAD
ref: refs/heads/master

> git symbolic-ref HEAD
refs/heads/master

> cat .git/refs/heads/master
e4d63afacf3d1d5782aacc97158092b5e4a1b096

> git rev-parse --short refs/heads/master
e4d63af

Pit stop 2

  • working dir, index, object database (repository)
  • blob, tree, commit, tag
  • master, HEAD

Questions?

Garbage

  • Garbage accumulates unless collected
  • Periodic explicit object packing

Objects (after commits)


> find .git/objects -type f | wc -l
17

> du -hs .git/objects
140K	.git/objects

> find .git/objects -type f | head -n 10
.git/objects/fc/b953879a566ea607d58948a0f520b1f75ad277
.git/objects/44/dba16a657baed8a09f68312c985dff84e3134c
.git/objects/ec/23b35681d22f0c6d6f14572cab119bbebbac85
.git/objects/f5/84e5928a3315c4dc8dcf09b46d3e4d8d711f83
.git/objects/7d/d188dd69574eee96bc02f5783a01eceb30f8c3
.git/objects/7d/6e09068aa3db89e331ab902a86438b4b929941
.git/objects/e4/d63afacf3d1d5782aacc97158092b5e4a1b096
.git/objects/69/694edab7d1f25fc6565ce60c6818dd615833e1
.git/objects/8c/87fa6ad6c88318d1a528e99b810a6a49c65ffe
.git/objects/4a/f19c541178897fb76436c785b2b86d8e9fb9f7

git gc 1/2


> git gc --aggressive --prune

> tree -aF .git/objects
.git/objects
|-- 69/
|   `-- 694edab7d1f25fc6565ce60c6818dd615833e1
|-- info/
|   `-- packs
`-- pack/
    |-- pack-df426cfa7c95a7dbaeca9659a3f9e11f4453a6f7.idx
    `-- pack-df426cfa7c95a7dbaeca9659a3f9e11f4453a6f7.pack

3 directories, 4 files

> du -hs .git/objects
32K	.git/objects

git gc 2/2


> git cat-file -p 7dd188dd69574eee96bc02f5783a01eceb30f8c3
textHC line 1
textHC line 2

> tree -aF .git/refs
.git/refs
|-- heads/
`-- tags/

2 directories, 0 files

> cat .git/packed-refs
# pack-refs with: peeled fully-peeled 
ec23b35681d22f0c6d6f14572cab119bbebbac85 refs/heads/BRc2
e4d63afacf3d1d5782aacc97158092b5e4a1b096 refs/heads/master

add after git gc


> echo "textA line 2" >> fileA.txt ; git add -A

> tree --noreport -aF .git | grep -A 100 'objects/'
|-- objects/
|   |-- 69/
|   |   `-- 694edab7d1f25fc6565ce60c6818dd615833e1
|   |-- e3/
|   |   `-- 1d478f6c73239c2452b571b9b07c33d568d330
|   |-- info/
|   |   `-- packs
|   `-- pack/
|       |-- pack-df426cfa7c95a7dbaeca9659a3f9e11f4453a6f7.idx
|       `-- pack-df426cfa7c95a7dbaeca9659a3f9e11f4453a6f7.pack
|-- packed-refs
`-- refs/
    |-- heads/
    `-- tags/

git diff (prepare)


> git reset --hard HEAD
HEAD is now at e4d63af commit 04 message

> echo "textA line 2" >> fileA.txt

> git add -A

> echo "textA line 3" >> fileA.txt

git diff (intro)

git diff


> git diff
diff --git a/fileA.txt b/fileA.txt
index e31d478..abd231e 100644
--- a/fileA.txt
+++ b/fileA.txt
@@ -1,2 +1,3 @@
 textA line 1
 textA line 2
+textA line 3

git diff --cached


> git diff --cached
diff --git a/fileA.txt b/fileA.txt
index 8e4b68e..e31d478 100644
--- a/fileA.txt
+++ b/fileA.txt
@@ -1 +1,2 @@
 textA line 1
+textA line 2

git diff HEAD


> git diff HEAD
diff --git a/fileA.txt b/fileA.txt
index 8e4b68e..abd231e 100644
--- a/fileA.txt
+++ b/fileA.txt
@@ -1 +1,3 @@
 textA line 1
+textA line 2
+textA line 3

git diff <ref1> <ref2>


> git diff HEAD~3 HEAD~2
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..60d6882
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+tmp/
+*.tmp
diff --git a/fileB.txt b/fileB.txt
new file mode 100644
index 0000000..44dba16
--- /dev/null
+++ b/fileB.txt
@@ -0,0 +1 @@
+textB line 1

revisions - <rev> 1/3

  • <sha1> - e.g. 8e4b68e
  • <refname> - e.g. HEAD, master, origin/master
    • .git/<refname>
    • .git/refs<refname>
    • .git/tags/<refname>
    • .git/heads/<refname>
    • .git/remotes/<refname>
    • ...
  • ...

revisions - <rev> 2/3

<rev>~<n> - e.g. master~3


> git log -n3 --oneline --decorate
e4d63af (HEAD, master) commit 04 message
fcb9538 commit 03 message
ec23b35 (BRc2) commit 02 message

> git rev-parse --short HEAD ; git rev-parse --short HEAD
e4d63af
e4d63af

> git rev-parse --short HEAD~2
ec23b35

> git cat-file -t ec23b35
commit

revisions - <rev> 3/3

<rev>:<path>, e.g. HEAD:dirH/fileHC.txt


> git rev-parse --short HEAD~1:dirH/fileHC.txt
5df063b

> git cat-file -t 5df063b
blob

revisions ranges 1/3

  • <rev> - reachable from <rev>


> git log --oneline
e4d63af commit 04 message
fcb9538 commit 03 message
ec23b35 commit 02 message
7d6e090 commit 01 message

> git log HEAD~2 --oneline
ec23b35 commit 02 message
7d6e090 commit 01 message

> git log 'master^{/commit 03}' --oneline
fcb9538 commit 03 message
ec23b35 commit 02 message
7d6e090 commit 01 message

revisions ranges 2/3

  • <rev1>..<rev2>
    • include commits reachable from <rev2>
    • exclude commits reachable from <rev1>
  • <rev1>...<rev2>
    • include commits reachable from either <rev1> or <rev2>
    • exclude reachable from both

revisions ranges 3/3


> git log 'master^{/01}'..'master^{/03}' --oneline
fcb9538 commit 03 message
ec23b35 commit 02 message

> git log 'master^{/03}'...'master^{/01}' --oneline
fcb9538 commit 03 message
ec23b35 commit 02 message

git grep

  • look for specified patterns in the tracked files
    • in the work tree
    • blobs in given tree objects


> git grep -n 'line 3'
fileA.txt:3:textA line 3

> git grep -n -e 'line 2' HEAD~1 HEAD~2
HEAD~1:fileB.txt:2:textB line 2

git grep --cached

  • look for specified patterns in the tracked files
    • blobs registered in the index file


> git grep -n --cached 'line 3'

> git grep -n --cached 'line 2'
dirH/fileHC.txt:2:textHC line 2
fileA.txt:2:textA line 2
fileB.txt:2:textB line 2

git log -- <paths>

  • commits modifying the given are selected
  • gitk -- <string>


> git log --oneline -- dirH
e4d63af commit 04 message
fcb9538 commit 03 message

git log -S <string> 1/2

  • ... introduce or remove an instance of <string>
  • gitk -S <string>

git log -S <string> 2/2


> git log -S 'line 2' --oneline
e4d63af commit 04 message
fcb9538 commit 03 message

> git show e4d63af
commit e4d63afacf3d1d5782aacc97158092b5e4a1b096
Author: Michal Jurosz <mj@mj41.cz>
Date:   Mon Jun 8 10:59:25 2015 -0400

    commit 04 message

diff --git a/dirH/fileHC.txt b/dirH/fileHC.txt
index 5df063b..7dd188d 100644
--- a/dirH/fileHC.txt
+++ b/dirH/fileHC.txt
@@ -1 +1,2 @@
 textHC line 1
+textHC line 2

git blame

  • last change of each line
  • git gui blame


> git blame dirH/fileHC.txt
fcb95387 (Michal Jurosz 2015-06-08 10:59:24 -0400 1) textHC line 1
e4d63afa (Michal Jurosz 2015-06-08 10:59:25 -0400 2) textHC line 2

reset and checkout

  • the three trees
    • working directory
    • index
    • HEAD

git reset --hard <rev>

  • move HEAD (and the branch)
  • reset index
  • reset working tree

git reset [--mixed] <rev>

  • move HEAD (and the branch)
  • reset index
  • reset working tree

git reset --soft <rev>

  • move HEAD (and the branch)
  • reset index
  • reset working tree

git checkout/reset -- files

Pit stop 3

  • git diff
  • <rev> - sha1, HEAD, master, moje-branchA
  • gitk, git gui blame
    • git grep, git log -S 'use utf8', git blame
  • git reset --hard

Questions?

branches


> git branch -v
  BRc2   ec23b35 commit 02 message
* master e4d63af commit 04 message

> git branch mj-test

> git branch -v
  BRc2    ec23b35 commit 02 message
* master  e4d63af commit 04 message
  mj-test e4d63af commit 04 message

> git show-ref --head --abbrev
e4d63af HEAD
ec23b35 refs/heads/BRc2
e4d63af refs/heads/master
e4d63af refs/heads/mj-test

git checkout <branch>

  • move only HEAD (switch branch)
  • reset index
    • reset not modified files
    • merge modified
  • reset working tree
    • reset not modified files
    • merge modified

git checkout BRc2 1/2


> git branch -v
  BRc2    ec23b35 commit 02 message
* master  e4d63af commit 04 message
  mj-test e4d63af commit 04 message

> git reset --hard master
HEAD is now at e4d63af commit 04 message

> cat fileA.txt
textA line 1

> echo "textA line 2" >> fileA.txt

> git add -A

> echo "textA line 3" >> fileA.txt

git checkout BRc2 2/2


> git checkout BRc2
Switched to branch 'BRc2'
M	fileA.txt

> git status --short
MM fileA.txt

> git diff --cached | grep '+textA'
+textA line 2

> git diff | grep '+textA'
+textA line 3

new branch


> git branch BRc2-pokus

> git branch -v | grep '*'
* BRc2       ec23b35 commit 02 message

> git checkout BRc2-pokus
Switched to branch 'BRc2-pokus'
M	fileA.txt

> git branch -v | grep '*'
* BRc2-pokus ec23b35 commit 02 message

> cat .git/HEAD
ref: refs/heads/BRc2-pokus

checkout -b (new branch)


> git checkout -b BRc2-mod
Switched to a new branch 'BRc2-mod'
M	fileA.txt

> git branch -d BRc2-pokus
Deleted branch BRc2-pokus (was ec23b35).

> git branch -v
  BRc2     ec23b35 commit 02 message
* BRc2-mod ec23b35 commit 02 message
  master   e4d63af commit 04 message
  mj-test  e4d63af commit 04 message

new branch commits 1/2


> git ci -m"branch c2-mod commit A"
[BRc2-mod 4956cc7] branch c2-mod commit A
 1 file changed, 1 insertion(+)

> git ci -a -m"branch c2-mod commit B"
[BRc2-mod b3c71e7] branch c2-mod commit B
 1 file changed, 1 insertion(+)

> echo "textX line 1" >> fileX.txt

> git add fileX.txt

> git ci -a -m"branch c2-mod commit C - add fileX"
[BRc2-mod 791c5fe] branch c2-mod commit C - add fileX
 1 file changed, 1 insertion(+)
 create mode 100644 fileX.txt

new branch commits 2/2


> git log --all --graph --date-order --decorate --oneline
* 791c5fe (HEAD, BRc2-mod) branch c2-mod commit C - add fileX
* b3c71e7 branch c2-mod commit B
* 4956cc7 branch c2-mod commit A
| * e4d63af (mj-test, master) commit 04 message
| * fcb9538 commit 03 message
|/  
* ec23b35 (BRc2) commit 02 message
* 7d6e090 commit 01 message

> git branch -D mj-test
Deleted branch mj-test (was e4d63af).

merge


> git checkout master
Switched to branch 'master'

> git merge BRc2-mod
Merge made by the 'recursive' strategy.
 fileA.txt | 2 ++
 fileX.txt | 1 +
 2 files changed, 3 insertions(+)
 create mode 100644 fileX.txt

> git log --all --graph --date-order --decorate --oneline
*   b89ef4a (HEAD, master) Merge branch 'BRc2-mod'
|\  
| * 791c5fe (BRc2-mod) branch c2-mod commit C - add fileX
| * b3c71e7 branch c2-mod commit B
| * 4956cc7 branch c2-mod commit A
* | e4d63af commit 04 message
* | fcb9538 commit 03 message
|/  
* ec23b35 (BRc2) commit 02 message
* 7d6e090 commit 01 message

GitHub

  • a web-based hosting service
  • A16Z investment - July 2012, $100 million USD
  • a pastebin-style site called Gist
  • private
    • US$7/month for five repositories
    • up to US$200/month for 125 repositories
  • Bitbucket, Gitorious, SourceForge, CodePlex, Google Code, Launchpad

git init --bare


> cd ~/git-tt

> git init git-tut-origin --bare
Initialized empty Git repository in /home/linus/git-tt-1433775564-435/git-tut-origin/

> ls git-tut-origin
HEAD
branches
config
description
hooks
info
objects
refs

git remote - origin


> cd ~/git-tt/repo-MJ

> git remote add origin file:///home/linus/git-tt-1433775564-435/git-tut-origin

> git push origin HEAD
To file:///home/linus/git-tt-1433775564-435/git-tut-origin
 * [new branch]      HEAD -> master

> git log --decorate --oneline
b89ef4a (HEAD, origin/master, master) Merge branch 'BRc2-mod'
791c5fe (BRc2-mod) branch c2-mod commit C - add fileX
b3c71e7 branch c2-mod commit B
4956cc7 branch c2-mod commit A
e4d63af commit 04 message
ec23b35 (BRc2) commit 02 message
fcb9538 commit 03 message
7d6e090 commit 01 message

git fetch


> cd ~/git-tt/repo-MJ

> git remote -v
origin	file:///home/linus/git-tt-1433775564-435/git-tut-origin (fetch)
origin	file:///home/linus/git-tt-1433775564-435/git-tut-origin (push)

       git-fetch - Download objects and refs from another repository

> git fetch

[Pepa] git clone 1/2


> cd ~/git-tt

> git clone file:///home/linus/git-tt-1433775564-435/git-tut-origin repo-Pepy
Cloning into 'repo-Pepy'...

> cd repo-Pepy

> git remote -v
origin	file:///home/linus/git-tt-1433775564-435/git-tut-origin (fetch)
origin	file:///home/linus/git-tt-1433775564-435/git-tut-origin (push)

> ls
dirH
fileA.txt
fileB.txt
fileX.txt

[Pepa] git clone 2/2


> ls
dirH
fileA.txt
fileB.txt
fileX.txt

> git branch -a
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/master

[Pepa] git log


> git log --decorate --oneline --graph --all
*   b89ef4a (HEAD, origin/master, origin/HEAD, master) Merge branch 'BRc2-mod'
|\  
| * 791c5fe branch c2-mod commit C - add fileX
| * b3c71e7 branch c2-mod commit B
| * 4956cc7 branch c2-mod commit A
* | e4d63af commit 04 message
* | fcb9538 commit 03 message
|/  
* ec23b35 commit 02 message
* 7d6e090 commit 01 message

git remote - upstream


> cd ../repo-MJ

> git remote add upstream git@github.com:mj41/git-fsdvcs-up.git

> git fetch upstream

git remote - configuration


> git remote -v
origin	file:///home/linus/git-tt-1433775564-435/git-tut-origin (fetch)
origin	file:///home/linus/git-tt-1433775564-435/git-tut-origin (push)
upstream	git@github.com:mj41/git-fsdvcs-up.git (fetch)
upstream	git@github.com:mj41/git-fsdvcs-up.git (push)

> git config --local --list | grep remote
remote.origin.url=file:///home/linus/git-tt-1433775564-435/git-tut-origin
remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
remote.upstream.url=git@github.com:mj41/git-fsdvcs-up.git
remote.upstream.fetch=+refs/heads/*:refs/remotes/upstream/*

git push


> git checkout -b BRnp
Switched to a new branch 'BRnp'

> echo "textA line 4 - BRnp" >> fileA.txt

> git commit -a -m"branch np commit k"
[BRnp 957ee02] branch np commit k
 1 file changed, 1 insertion(+)

> git push origin HEAD
To file:///home/linus/git-tt-1433775564-435/git-tut-origin
 * [new branch]      HEAD -> BRnp

git push --force

  • please no to master
  • your topic branche
    • use fixups
    • do it once before merging

[Pepa] git fetch


> cd ../repo-Pepy

> git fetch
From file:///home/linus/git-tt-1433775564-435/git-tut-origin
 * [new branch]      BRnp       -> origin/BRnp

> git log --decorate --oneline --graph
*   b89ef4a (HEAD, origin/master, origin/HEAD, master) Merge branch 'BRc2-mod'
|\  
| * 791c5fe branch c2-mod commit C - add fileX
| * b3c71e7 branch c2-mod commit B
| * 4956cc7 branch c2-mod commit A
* | e4d63af commit 04 message
* | fcb9538 commit 03 message
|/  
* ec23b35 commit 02 message
* 7d6e090 commit 01 message

git reset --hard origin/... 1/2


> cd ../repo-MJ

> git checkout master
Switched to branch 'master'

> git log --decorate --oneline --all --graph | head -n5
* 957ee02 (origin/BRnp, BRnp) branch np commit k
*   b89ef4a (HEAD, origin/master, master) Merge branch 'BRc2-mod'
|\  
| * 791c5fe (BRc2-mod) branch c2-mod commit C - add fileX
| * b3c71e7 branch c2-mod commit B

git reset --hard origin/... 2/2


> git reset --hard origin/BRnp
HEAD is now at 957ee02 branch np commit k

> git log --decorate --oneline --all --graph | head -n5
* 957ee02 (HEAD, origin/BRnp, master, BRnp) branch np commit k
*   b89ef4a (origin/master) Merge branch 'BRc2-mod'
|\  
| * 791c5fe (BRc2-mod) branch c2-mod commit C - add fileX
| * b3c71e7 branch c2-mod commit B

> git push origin HEAD
To file:///home/linus/git-tt-1433775564-435/git-tut-origin
   b89ef4a..957ee02  HEAD -> master

Pit stop 4

  • git checkout
  • remote repositories
  • git push
  • git fetch

Questions?

GUI

  • gitk --all --date-order
  • git gui
    • git gui blame
  • Windows: TortoiseGit
  • MAC: GitX, GitNub

Git more 1/2

  • git clean
  • git commit --amend
  • git ci --fixup
  • git rebase -i
  • git cherry-pick
  • git revert
  • git tag

Git more 2/2

  • git bisec
  • git reflog
  • git filter-branch
  • git gc
  • git fsck
  • ...

Links

Thank you

Michal Jurosz (mj41)
www.GoodData.com

Generated from github.com/mj41/git-course-mj41 source
by Presentation::Builder inside prbuilder Docker container.

Powered by reveal.js.

Questions?