git-talk



git-talk

2 0


git-talk


On Github nathantypanski / git-talk

Outline

  • General Concepts
  • What is Git, what's the point?
  • Technical advantages
  • Workflows
  • Tools
  • Subversion migration

These slides

These slides

Authors

  • Nathan Typanski
  • Bryan Kinney

This work is licensed under a Creative Commons Attribution 4.0 International License.

Concepts

  • Processes and tools for managing versions/revisions
  • CM->SCM
  • VCS->DVCS

Configuration Management (CM)

  • Practice of handling changes systematically so that a system maintains its integrity over time.
    • Policies, procedures, techniques, and tools
    • Manage, evaluate proposed changes, track the status of changes
    • Maintain Inventory of system and support documents as the system changes
  • Information Technology Infrastructure Library (ITIL)

Software CM (SCM)

  • CM applied to software
  • Track and controll changes in the software
  • Revision Control and the establishment of baselines

Centralized VCS

  • Everyone stores history on a central repository
  • Only the central repo gets a full copy of the history

  • Version Control System (VCS)

    • Tracks and provides control over changes to source code
    • Versions/Revisions: Baseline, Branch, Tag, etc
    • Single authoritative data store
    • (Client/Server)

Centralized VCS

Distributed Version Control

  • Team members send changes to each other
  • Everyone can work offline

  • Distributed VCS (DVCS)

    • Each working copy functions as fully functional backup
    • Peer-To-Peer

Distributed Version Control

What?

Git is revision control software.

  • Distributed VCS
  • History tracking
  • Automatic merging
  • Bisecting bugs

History

  • Written by Linus Torvalds in 2005 to meet the needs of the Linux kernel developers.

  • Now maintained by Junio Hamano.

Benchmarks

torial @ StackOverflow:

"anything greater than a 1 second delay broke people out of the zone"

  • That was about compile times.
  • I'm pretty sure it applies to version control.

Git is fast.

oak.homeunix.org/~marcel

oak.homeunix.org/~marcel

oak.homeunix.org/~marcel

oak.homeunix.org/~marcel

Linux Kernel Wiki

Storage

  • Git repos are tiny.
  • Storage is cheap.
  • Just clone the whole history!

Mozilla repo

  • CVS: 2.7 GiB
  • SVN: 8.2 GiB
  • Git: 450 MiB

keithp

Mozilla repo

  • SVN:
    • partial history
    • 350 MiB
  • Git
    • entire history
    • 450 MiB

keithp

Django

  • SVN: 61 MiB
  • bzr: 64 MiB
  • Hg: 53 MiB
  • Git: 43 MiB

why git is better

KDE

  • SVN: 34 GiB
  • Git: 6.7 GiB

KDE mailing list

Getting Git

Homebrew:

$ brew update
$ brew install git

Debian-based:

$ sudo apt-get install git

Otherwise: http://git-scm.com/download/

Basics

Learning

The hardest part of Git is the jargon.

  • commit
  • staging area
  • working directory
  • HEAD
  • heads
  • checkout
  • clone
  • push
  • remote

Staging area

The staging area holds changes that are about to be committed.

  • Commits are multi-step:
    • Change the file.
    • Add your changes (to the staging area).
    • Commit them.

from the Git book.

Create a new repo:

$ git init
Initialized empty Git repository in /home/nathan/devel/git-demo/.git/

Make a file:

$ touch README.md
$ ls -a
. .. .git README.md

By default, this new file is untracked:

$ git ls-files
$ git status
On branch master

Initial commit

Untracked files:

    README.md

Files need to be added with git add before Git knows about them:

$ git add README.md

Then they show up in the staging area:

$ git status
On branch master

Initial commit

Changes to be committed:

    new file:   README.md
$ git ls-files
README.md
$ git commit -m ‘initial commit’
[master (root-commit) 104ea88] initial commit
 1 file changed, 0 insertions(+), 0 deletions(-)

Commits move files from the staging area into the log.

Commits

  • Identified by their SHA1 hash.
    • e.g., f3d19df9968f4260c6bfde8c1d71e0e00ef9f00e
    • globally unique identifier.
  • Commits contain changes to file contents.
    • History is preserved through renames.

Trees

  • Commits build on each other, so each one refers backwards to all the others.
  • This forms a tree.

Trees

  • Their hashes are hashes of this entire history, not the individual changes.
  • The same hash always refers to exactly the same history of the same tree.

Branches

$ git checkout -b hotfix

Branches

  • A branch is a pointer to a commit.
  • No, really:
filer$ cd .git/refs/heads
heads$ ll
total 12
drwxr-xr-x 1 nathan nathan 28 Jun 16 09:06 cleanup
-rw-r--r-- 1 nathan nathan 41 May 30 14:56 cython
-rw-r--r-- 1 nathan nathan 41 Jul  8 11:43 develop
drwxr-xr-x 1 nathan nathan 40 Jun  3 09:27 feature
drwxr-xr-x 1 nathan nathan 28 May 27 10:30 hotfix
-rw-r--r-- 1 nathan nathan 41 Jul  7 10:21 master
heads$ cat master
9326780e3cde95034a6a402ee39a47e66e9c2398

Conventional names

  • First branch
  • Created automatically by Git

Remotes

Remotes can be anywhere.

Folder on the same machine
$ git clone /opt/git/project.git
Server somewhere
$ git clone user@server:project.git

Conventional names

  • origin The first remote that you add.
    • "Where your code came from."

Clone this repo!

$ git clone git@github.com:nathantypanski/git-talk.git
Cloning into 'git-talk'...
remote: Counting objects: 312, done.
remote: Compressing objects: 100% (205/205), done.
remote: Total 312 (delta 136), reused 270 (delta 94)
Receiving objects: 100% (312/312), 1.69 MiB | 0 bytes/s, done.
Resolving deltas: 100% (136/136), done.
Checking connectivity... done.

If you have an account: fork this repo, then clone your fork:

$ git remote add kjb https://github.com/kinneyjb/git-talk.git
git-talk$ git fetch kjb
remote: Counting objects: 9, done.
remote: Compressing objects: 100% (1/1), done.
remote: Total 4 (delta 3), reused 3 (delta 3)
Unpacking objects: 100% (4/4), done.
From https://github.com/kinneyjb/git-talk
 * [new branch]      gh-pages   -> kjb/gh-pages
 * [new branch]      jkinney-what -> kjb/jkinney-what
 * [new branch]      master     -> kjb/master
  • You want to add a remote for your own code, and any code you might wish to download.
  • Push code to your own fork, then send a pull request.

Fixing mistakes

$ mkdir demo
$ cd demo
demo$ git init
Initialized empty Git repository in ~/demo/.git/
demo$ la
.  ..  .git
demo$ vim helloworld.py
import sys

def main():
    if len(sys.argv) == 1:
        print('Hello, world')
    else:
        print(str.format('hello {}', ' '.join(sys.argv[1:])))

if __name__ == '__main__':
    main()
demo$ python3 helloworld.py
Hello, world
demo$ python3 helloworld.py nathan
hello nathan
demo$ git add helloworld.py
demo$ git commit -m 'initial commit'
[master (root-commit) 62b720a] initial commit
 1 file changed, 10 insertions(+)
 create mode 100644 helloworld.py

To show branches:

demo$ git branch
* master
$ vim helloworld.py
$ git diff
diff --git a/helloworld.py b/helloworld.py
index 328978e..b2c550a 100644
--- a/helloworld.py
+++ b/helloworld.py
@@ -1,10 +1,16 @@
 import sys
+from datetime import date

 def main():
+    today = datetime.today()
     if len(sys.argv) == 1:
         print('Hello, world')
     else:
         print(str.format('hello {}', ' '.join(sys.argv[1:])))
+    print(str.format('Today is {}-{}-{}',
+                     today.year,
+                     today.month,
+                     today.day()))

 if __name__ == '__main__':
     main()
demo$ git commit helloworld.py -m 'add date to helloworld'
[date 58fba34] add date to helloworld
 1 file changed, 6 insertions(+)
demo$ python3 helloworld.py Nathan
Traceback (most recent call last):
  File "helloworld.py", line 16, in <module>
    main()
  File "helloworld.py", line 5, in main
    today = datetime.today()
NameError: name 'datetime' is not defined

Darn! Should've tested before I committed that ...

Luckily, Git lets us amend our work before we send it anywhere.

$ vim helloworld.py
$ git diff
diff --git a/helloworld.py b/helloworld.py
index b2c550a..fd28150 100644
--- a/helloworld.py
+++ b/helloworld.py
@@ -2,7 +2,7 @@ import sys
 from datetime import date

 def main():
-    today = datetime.today()
+    today = date.today()
     if len(sys.argv) == 1:
         print('Hello, world')
     else:
@@ -10,7 +10,7 @@ def main():
     print(str.format('Today is {}-{}-{}',
                      today.year,
                      today.month,
-                     today.day()))
+                     today.day))

 if __name__ == '__main__':
     main()
demo$ python3 helloworld.py Nathan
hello Nathan
Today is 2014-7-14
demo$ git commit --amend helloworld.py

Great! It works. Let's amend that commit ...

add date to helloworld

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# Explicit paths specified without -i or -o; assuming --only paths...
# On branch date
# Changes to be committed:
#    modified:   helloworld.py
#
demo$ git commit --amend helloworld.py 
[date a497198] add date to helloworld
 1 file changed, 6 insertions(+)
demo$ git log
a497198 Nathan Typanski add date to helloworld
62b720a Nathan Typanski initial commit

This is safe, since every user basically has their own local branch by default.

Changes don't go anywhere unless you explicitly send them to a server.

Bigger mistakes

Fix bigger mistakes with git rebase.

  • Commits out of order
  • Forgot to add files 4 commits back
  • etc.

Bigger mistakes

Working on this repo, I forgot to add an image that was referenced in one of the markdown files.

That was 3 commits ago. I can't just --amend it.

git-talk$ git rebase -i origin/master

origin/master is a remote branch.

It means I'm allowed to change things up until the history known on origin's master branch.

git-talk$ git rebase -i origin/master

Reorder and fixup (combine) the commits:

[detached HEAD 4344a8d] add gitlab ci
 2 files changed, 9 insertions(+), 1 deletion(-)
 create mode 100644 img/gitlab-ci-preview.png
Successfully rebased and updated refs/heads/master.

Now my history looks like this:

2014-07-14 13:48 Unknown            o Unstaged changes
2014-07-14 13:32 Nathan Typanski    o [master] more branching
2014-07-14 13:32 Nathan Typanski    o expand tool descriptions
2014-07-14 13:31 Nathan Typanski    o add gitlab ci
2014-07-14 13:31 Nathan Typanski    o tweak formatting
2014-07-14 12:42 Nathan Typanski    o add link to gitbook
2014-07-14 12:37 Nathan Typanski    o [gh-pages] [origin/HEAD] [origin/gh-pages]
                                      [origin/master] remotes before merging
2014-07-14 12:36 Nathan Typanski    o add slides on cloning/forking repo

But wait! That's rewriting history!

  • No, it's rewriting my history.
  • Commits are not "sacred" until someone besides you starts using them.
  • This encourages good version control practices:
    • Commit early,
    • Commit often.

Merging

$ git merge hotfix master

To merge changes from local branch hotfix into local branch master:

$ git merge hotfix master

Merge changes from remote origin branch master into local branch master

$ git pull origin master

Often, you'll want to inspect a merge before it happens.

Use git fetch:

git-talk$ git fetch kinneyjb
remote: Counting objects: 4, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 4 (delta 0), reused 1 (delta 0)
Unpacking objects: 100% (4/4), done.
From https://github.com/kinneyjb/git-talk
 * [new branch]      gh-pages   -> kinneyjb/gh-pages
 * [new branch]      master     -> kinneyjb/master

If you have local changes, do git stash to save them away:

git-talk$ git status
On branch master
Your branch is ahead of 'origin/master' by 1 commit.

Changes not staged for commit:

    modified:   slides/merging.md

no changes added to commit (use "git add" and/or "git commit -a")
git-talk$ git stash
Saved working directory and index state
    WIP on master: 633c37b merging: fill out sections
HEAD is now at 633c37b merging: fill out sections

Sometimes I'll make a new branch for the merge:

git-talk$ git checkout -b kjb
Switched to a new branch 'kjb'

Merge a fetched remote branch with remotename/branchname:

git-talk$ git merge kinneyjb/master
Merge made by the 'recursive' strategy.
 slides/benchmarks.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
$ git log --graph --pretty=format:'%h %an %s'
*   5e2788f Nathan Typanski Merge remote-tracking branch
                            'kinneyjb/master' into kjb
|\
| * b332517 kinneyjb fixed typos closes #2
* | 633c37b Nathan Typanski merging: fill out sections
* | 4d2ac1f Nathan Typanski fade transition for backgrounds - easier to follow
* | 25a4087 Nathan Typanski expand branches/remotes/ci
* | 3ed07e5 Nathan Typanski more branching
* | 5e1b3ab Nathan Typanski expand tool descriptions
* | 4344a8d Nathan Typanski add gitlab ci
* | 6a339e0 Nathan Typanski tweak formatting
* | 2ba91f4 Nathan Typanski add link to gitbook
* | 3965c22 Nathan Typanski remotes before merging
* | a1dcf95 Nathan Typanski add slides on cloning/forking repo
* | 221c3fe Nathan Typanski wider quotes, non-italic
* | 0a8bf2e Nathan Typanski fill out "tracking changes"
* | 19259c9 Nathan Typanski stop hyphenating titles
* | ecf9034 Nathan Typanski add ci section
* | b404b21 Nathan Typanski join slides for remotes
|/

Now, put the changes back in master:

git-talk$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)

Merging with --ff-only means "don't give me a merge commit; just put the new changes on top of HEAD:

git-talk$ git merge --ff-only kjb
Updating 633c37b..5e2788f
Fast-forward
 slides/benchmarks.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

Reapply my old work:

git-talk$ git stash apply
On branch master
Your branch is ahead of 'origin/master' by 3 commits.
git-talk$ git show --pretty=medium 5e2788f
commit 5e2788f44c6db845c5a7456a2cace6d22f9fe809
Merge: 633c37b b332517
Author: Nathan Typanski <ntypanski@gmail.com>
Date:   Sat Jul 19 13:37:43 2014 -0400

    Merge remote-tracking branch 'kinneyjb/master' into kjb
git-talk$ git show -c b332517
b332517 kinneyjb fixed typos closes #2

diff --git a/slides/benchmarks.md b/slides/benchmarks.md
index 27930fd..a626042 100644
--- a/slides/benchmarks.md
+++ b/slides/benchmarks.md
@@ -70,7 +70,7 @@
   - **350 MiB**
 - **Git**
   - entire history
-  - **450**.
+  - **450 MiB**

 [keithp](http://keithp.com/blog/Repository_Formats_Matter/)

@@ -81,7 +81,7 @@
 - **SVN**: 61 MiB
 - **bzr**: 64 MiB
 - **Hg**: 53 MiB
-- **Git**: 43 Mib
+- **Git**: 43 MiB

 [why git is better](http://thkoch2001.github.io/whygitisbetter/#git-is-small)

Strategies

Fast forward

  • Changes go directly on top of the target branch.

Recursive

  • Default for everything that's not fast-forward.
  • Common ancestors get joined.
  • Handles renames.

Advanced topics

  • Different merge strategies
  • git-rerere

More Strategies

Octopus

  • Merge several trees (instead of a sequence of branch merges)

More Strategies

Ours

  • Not really a merge
  • Keeps your history, but puts other branch history in the tree

More Strategies

Subtree

  • Merge an independent project into a subdirectory

rerere

$ git config --global rerere.enabled true
  • Secret Git merge sauce.
  • Memorizes how you did a merge so you don't repeat it.
  • Not in the book!
  • Don't do this unless you know what you're doing.

Tracking changes

$ git log
$ git blame
$ git grep
$ git bisect

git log

git-talk$ git log --graph --pretty=format:'%h %an %s'
* bfd7061 Nathan Typanski remotes: change slide to use generic titlebg
* 5418ad7 Nathan Typanski concepts:shorten title
* 6e0aed4 Nathan Typanski whitespace nitpick fixup
* e169333 Nathan Typanski add readme
* 837fc50 Nathan Typanski rm extra slide
*   7b4245f Nathan Typanski Merge branch 'jkinney-what' of ...
|\
| *   524abf7 kinneyjb Merge branch 'jkinney-what' of ...
| |\
| | * 9975749 kinneyjb Split out the notes from what into ...
| * | 9f933af kinneyjb Split out the notes from what into ...
| |/
| * 40790cb kinneyjb Some notes for the what section, ...
* | 32330ac Nathan Typanski add section for remotes
|/
* 66f5fdd Nathan Typanski stop lying about fast-forward merges

For these reasons, the "summary" must be no more than 70-75 characters, and it must describe both what the patch changes, as well as why the patch might be necessary. It is challenging to be both succinct and descriptive, but that is what a well-written summary should do.

Linux kernel: Documentation/SubmittingPatches

git blame

$ git blame slides/concepts.md
9f933af3 (kinneyjb        2014-07-10)  - (Client/Server)
9f933af3 (kinneyjb        2014-07-10) 
9f933af3 (kinneyjb        2014-07-10) ---
9f933af3 (kinneyjb        2014-07-10) 
9f933af3 (kinneyjb        2014-07-10) ### Centralized VCS
75f6b977 (Nathan Typanski 2014-07-10) <img src="img/centralized-vcs.svg" />
9f933af3 (kinneyjb        2014-07-10) 
9f933af3 (kinneyjb        2014-07-10) ---
9f933af3 (kinneyjb        2014-07-10) 
9f933af3 (kinneyjb        2014-07-10) ### Distributed Version Control
9f933af3 (kinneyjb        2014-07-10) 
9f933af3 (kinneyjb        2014-07-10) - Team members send changes to each
9f933af3 (kinneyjb        2014-07-10) - Everyone can work offline

git grep

Use it with --cached to grep only files Git knows about:

git-flow$ git grep --cached --break --heading --line-number "Linux"

(the other arguments are just for pretty output)

slides/benchmarks.md
44:[Linux Kernel Wiki](https://git.wiki.kernel.org/index.php/GitBenchmarks)

slides/what.md
17:- Written by Linus Torvalds in 2005 to meet the needs of the Linux kernel
developers.

slides/workflows.md
29:- Linux kernel.

git bisect

Tools

tig

magit

gitg

gitflow

Workflows

  • Git lets you use whatever workflow you want.
  • Structure is still helpful.

Centralized

  • Basically SVN.

Integration manager

  • Good for small teams.

Dictator and lieutentants

  • Linux kernel.

Git Flow

"A successful Git branching model"

master

  • Deployment branch
  • Commits are deployments
  • Each commit gets a tag
  • Each commit should be a merge commit

develop

  • Where work happens
  • Main staging tree for master

Release branches

  • e.g., release-1.2
  • only bugfixes
  • merge into master and develop

Hotfix branches

  • Patches to master branch
  • Merge back into develop

Continuous Integration

travis.ci

GitLab CI

Jenkins project

Mistakes

No, really, it's not GitHub

Detached HEAD state

  • Calm down.
  • You checked out a commit.
  • Check out a branch to “fix” this.
0