1 of 58

How did that happen?!

or, Navigating Your Git Repository

Gemma Lynn / @ellotheth

2 of 58

Do I have to care?

3 of 58

Storytime!

4 of 58

Storytime!

ellotheth @ pnwphp $ git show --no-patch

commit 6fbbac497a4f1d63a0b8a1982745b62e11835e30

Author: ellotheth <ellotheth@pnwphp>

Date: Sat Mar 14 22:03:33 2015 -0500

added another lne

5 of 58

Storytime!

6 of 58

Storytime!

7 of 58

Storytime!

ellotheth @ pnwphp $ git commit --amend -m "added another line"

ellotheth @ pnwphp $ git show --no-patch

commit afce570cf7c622660fd679bfbc0bac4447b5d619

Author: ellotheth <ellotheth@pnwphp>

Date: Sun Mar 15 08:24:53 2015 -0500

added another line

8 of 58

Storytime!

ellotheth @ pnwphp $ git push

To origin

! [rejected] main -> main (non-fast-forward)

error: failed to push some refs to 'origin'

hint: Updates were rejected because the tip of your current branch is behind

hint: its remote counterpart. Integrate the remote changes (e.g.

hint: 'git pull ...') before pushing again.

hint: See the 'Note about fast-forwards' in 'git push --help' for details.

9 of 58

Storytime!

10 of 58

Storytime!

ellotheth @ pnwphp $ git pull

ellotheth @ pnwphp $ git log --oneline --graph --decorate

* c1a184d (HEAD, main) Merge branch 'main' of origin

|\

| * 6fbbac4 (origin/main, origin/HEAD) added another lne

* | afce570 added another line

|/

* 72d4576 Merge branch 'foo'

11 of 58

Let’s talk about Subversion

12 of 58

Centralized access

  • You get a working copy
  • No local access to repository history
  • No local access to anything not in your working copy (branches, tags, etc.)
  • Work stops when your internet dies

13 of 58

File-based repository model

  • Branches are copied directories
  • Tags are copied directories
  • Local working copies are explicitly tied to repository directories

14 of 58

Delta commits

  • One revision is the diff of the current change against the previous revision
  • Repository-wide, cross-branch, cross-tag
  • Context-free

15 of 58

Let’s talk about Git

16 of 58

Git is similar...

$ git status

$ git log

$ git diff

$ git add

$ git commit

$ git rm

$ svn status

$ svn log |less

$ svn diff

$ svn add

$ svn commit

$ svn rm

17 of 58

...but not the same

$ git branch

$ git merge

$ git rebase

$ git pull

$ git push

$ svn copy?

$ svn it-hurts-me

$ svn wat?

$ svn sort-of-up-ish

$ svn nope

18 of 58

Distributed access

  • You get (clone) the whole repository
  • Almost every operation is local
  • Centralization is a process convention, not a tool restriction

19 of 58

Graph-based repository model

20 of 58

DSA Detour!

21 of 58

This is a graph.

node

node

node

edge

edge

edge

22 of 58

This is a directed graph.

node

node

node

edge

edge

edge

Edges only go in one direction

23 of 58

This is a directed acyclic graph.

node

node

node

edge

edge

node

edge

edge

Following the edges won’t take you all the way around the graph

24 of 58

This is a Git repository.

a0f56

71c1f

b3fd8

commit

1b88f

commit

commit

commit

25 of 58

Subversion

Git

a0f56

71c1f

b3fd8

commit

1b88f

commit

commit

commit

26 of 58

Snapshot commits

A Git commit is a snapshot of repository content at a given point in time.

a0f56

commit

27 of 58

Snapshot commits

  • It knows about itself (like a delta commit)
  • It knows where it came from
  • It never changes

a0f56

b3fd8

commit

itself

where it came from (previous commit)

28 of 58

Snapshot commits

If every commit knows about itself and its parents...

...then you can trace a path from any commit back to the first.

a0f56

b3fd8

first ever!

commit

29 of 58

Snapshot commits

a0f56

71c1f

b3fd8

first commit ever!

1b88f

commit

commit

commit

knows about

knows about

knows about

knows about

30 of 58

Naming the graph

A branch is a dynamic name (reference) for a path through the repository graph

a0f56

71c1f

commit

1b88f

commit

commit

main

foo

31 of 58

Naming the graph

A tag is a static name (reference) for a specific commit

a0f56

71c1f

commit

1b88f

commit

commit

main

foo

v5.3

32 of 58

Naming the graph

  • Branches move when the path grows
  • Tags don’t

a0f56

commit

main

c97ff

commit

v5.3

71c1f

1b88f

commit

commit

foo

33 of 58

Kent Beck nails it again (mostly)

34 of 58

Committing: Adding to the graph

$ git commit

a0f56

commit

main

35 of 58

Committing: Adding to the graph

$ git commit

$ git commit

a0f56

commit

c97ff

commit

main

main

36 of 58

Branching: Defining a new path

$ git branch foo a0f56

a0f56

commit

c97ff

commit

main

foo

37 of 58

Branching: Defining a new path

$ git branch foo a0f56

$ git checkout foo

$ git commit

$ git commit

a0f56

commit

c97ff

commit

main

1b88f

commit

commit

foo

71c1f

foo

38 of 58

Merging: Combining paths

$ git checkout main

$ git merge foo

a0f56

commit

c97ff

commit

main

1b88f

commit

commit

foo

71c1f

31f9c

commit

main

39 of 58

Rebasing: Redefining a path

$ git checkout foo

$ git rebase main

a0f56

commit

c97ff

commit

main

1b88’

commit

commit

foo

71c1’

1b88f

commit

commit

foo

71c1f

40 of 58

Rebasing: Redefining a path

$ git checkout foo

$ git rebase main

a0f56

commit

c97ff

commit

main

1b88’

commit

commit

foo

71c1’

Copies of the original commits, not the same!

41 of 58

Amending: Redefining a path

$ git commit

$ git commit --amend

a0f56

commit

c97ff

commit

main

commit

c97ff’

main

The original is still here!

42 of 58

Wait, where am I?

43 of 58

Navigating the repository

You can checkout any commit

into your working directory.

In other words,

You can visit any node

in the repository graph.

44 of 58

Navigating the repository

  • Git’s where-am-i tracker is a special tag called HEAD
  • As you move around the repository, HEAD moves with you.

a0f56

commit

c97ff

commit

main

1b88f

commit

commit

foo

71c1f

HEAD

45 of 58

Navigating the repository

$ git checkout main

Switch your working directory to main

a0f56

commit

c97ff

commit

main

1b88f

commit

commit

foo

71c1f

HEAD

HEAD

46 of 58

Navigating the repository

$ git reset main

Switch your working directory to main, and bring your current branch along for the ride

a0f56

commit

c97ff

commit

main

1b88f

commit

commit

foo

71c1f

HEAD

HEAD

foo

47 of 58

Navigating the repository

This blue path looks awfully bare...

a0f56

commit

c97ff

commit

main

1b88f

commit

commit

71c1f

HEAD

foo

48 of 58

Navigating the repository

Commits are “reachable” if they have a name, or if they are in the same path as a commit that has a name.

a0f56

commit

c97ff

commit

main

1b88f

commit

commit

71c1f

HEAD

foo

49 of 58

Navigating the repository

Commits are “reachable” if they have a name, or if they are in the same path as a commit that has a name.

a0f56

commit

c97ff

commit

1b88f

commit

commit

71c1f

v5.3

foo

HEAD

main

50 of 58

Navigating the repository

Reachable commits

  • are stored in the repository indefinitely
  • are listed in git log

Unreachable commits

  • are garbage-collected after 30 days
  • are not listed in git log
  • are only accessible if you know the SHA

51 of 58

Navigating the repository

Resetting or rebasing or amending a branch will make its old location unreachable...

a0f56

commit

c97ff

commit

main

1b88f

commit

commit

foo

71c1f

HEAD

HEAD

foo

52 of 58

Navigating the repository

...but if you keep track of the SHA, you can get back to it

$ git checkout 1b88f

a0f56

commit

c97ff

commit

main

1b88f

commit

commit

71c1f

HEAD

foo

HEAD

53 of 58

Navigating the repository

Git keeps track of the SHA for you!

$ git reflog

72d4576 HEAD@{0}: checkout: moving from 3cf4a04307ab96f6364fe82baad993bbd7fcaea5 to main

3cf4a04 HEAD@{1}: checkout: moving from foo to HEAD~

181c484 HEAD@{2}: checkout: moving from main to foo

72d4576 HEAD@{3}: commit (merge): Merge branch 'foo'

13945ea HEAD@{4}: checkout: moving from foo to main

181c484 HEAD@{5}: commit: second on foo

54 of 58

Do. Not. Redefine. Shared. Branches.

55 of 58

It’s private until you push it

$ git commit

$ git push

...time passes…

$ git commit --amend

$ git commit

a0f56

commit

c97ff

commit

fred/main

commit

c97ff’

e1f4f

commit

2f811

origin/main

your/main

commit

56 of 58

Things I didn’t talk about

  • Merge conflicts
  • The staging area
  • Sharing worfklow for remote repositories
  • (alltheotherthings)

57 of 58

Places with more learning

58 of 58

These awesome slides!