Take your Git practice to the next level

Baptiste Mathus <batmat@batmat.net>, Michaël Pailloncy <michael.pailloncy@gmail.com>

About us

avatar michael

Michaël Pailloncy

avatar baptiste

Baptiste Mathus

Working Together @MiPih as ToolSmiths

#jenkins #java #maven #nexus #sonarqube #build #docker #passion

Agenda

This is a workshop. So there will be manipulation, don’t worry !

  • Some History
  • The Git Data Model
  • Understanding the .git directory
  • Basic concepts & commands reminder

    • Merge vs. Rebase
    • What’s a Fast-Forward?
    • The Working Copy, The Index And The Commit

  • Reviewing (and rewriting) changes
  • Tips & tricks
  • Repository lifecycle

    • granularity
    • aggregate
    • split

  • EGit & JGit
  • Git workflows discussion

    • Git flow
    • Gerrit

Some History

  • 1991 → 2002 : Linux development uses tarball
For the first 10 years of kernel maintenance, we literally used tarballs and patches, which is a much superior source control management system than CVS is – Linus Torvalds
Linus Torvalds
  • 2002 → April 2005 : Using BitKeeper

Closed-source DVCS. Free licenses provided to the project.

⇒ Revocation triggered by Andrew Tridgell’s BitKeeper protocol reverse-engineering

  • 7, April 2005 : First version of Git
I’m an egotistical bastard, and I name all my projects after myself. First Linux, now git.
Linus Torvalds

Basics

  • DVCS
  • Decentralized
  • Technically, no server required
  • Whole project history present locally

    • Only pushing & fetching new commits requires network

Fast, Git ?

  • Performances, the origins
If it takes half a minute to apply a patch […] then a series of 250 emails […] takes two hours.
  • Content oriented
  • Storing snapshots, not deltas
snapshots vs delta

The Index

The Index
add

adds to the index (-p lets you choose the parts of your file you actually want to add)

index

staging area (a sweet place to lovingly craft your commits)

commit

Captures the state of the index.

Quiz: git add

What content has been committed for the theFile file? (1) or (2)?
echo "dingdingdingbabababaaaaa" >> theFile # (1)
git add theFile
echo "blah" > theFile # (2)
git commit -m "done"

Right answer: (1)

The Index

(note: difference with svn ⇒ (2))

Let’s dig a bit deeper now

Git Data Model: The 4 Object Types

blob

File content, identified by a hash

object blob
tree

List of pointers to blob, or tree, identified by a hash

object tree
commit

References the (root) tree + metadata, 0 to n parent commits, identified by a hash

object commit

Identified by a SHA-1 hash : 53b8 = 53b89fc7bb117aee396285f9bc6ce913599a6574 (short version ≥ 4 chars)

Possibly: Author ≠ Committer

DAG : Directed Acyclic Graph

dag illustration
tag

Name associated with a commit (+ potential metadata)

object tag

Git Data Model : wrap up

git objects types

Back to basics

Step back

Quiz: what does this?

$ git init pouet && cd pouet
$ git commit -m "initial commit" --allow-empty
$ echo abc > .git/refs/heads/paf

Creates a branch! That’s right!

$ git init pouet && cd pouet
$ git commit -m "initial commit" --allow-empty
$ echo abc > .git/refs/heads/paf
$ git branch
* master
  paf
applause

So…​ What are branches again?

Git branches

  • Simple pointer to a given commit (symlink, kind of)
  • Git only references heads
  • Unreferenced commits will be garbaged eventually

    • Dangling or detached HEAD
    • Each time you rebase (without fast-forward)

Pointers?

  • HEAD: shorthand to the latest commit of the current branch
  • HEAD~N: N commit before the last one

    • (N=1 if omitted)

  • master (or any branch): automatically bumped when new commit is done on it
pointers HEAD and co

Resetting

git reset [--soft|--mixed|--hard] <TARGET>

  • Works on the current branch pointer.
soft

keep all local changes

mixed (default)

keep working but reset index

hard

discard all working copy changes

The Index

Example:

git reset HEAD~
  • Latest commit becomes the previous one (kind of: HEAD=HEAD~).
  • Index is empty
  • Working copy is intact

Example:

git reset --hard HEAD~2
  • HEAD=HEAD~2
  • Index is empty
  • Working copy at the HEAD~2 state (any uncommitted change is lost)

Merge vs. Rebase

What is it? How to choose one or another?

What do you want to do?

Step back, what do you want to actually do?

Git lets you express what you did.

Correction

Git lets you express what you wanted to do.

Here’s what it’s all about:

Good SCM history reveals intentions.

Like good code.

OK, back to Merge vs. Rebase

What you want to express :

Rebase

when you don’t want your local history to be seen as side/sub-work

Merge

it was side/sub-work

Git Rebase!

Rebase

(on feature) git rebase master

rebase before

Rewinding:

rebase rewind1

Rewinding:

rebase rewind2

Replaying:

rebase replayed1

Replayed:

rebase replayed2

Rebased:

rebase after

Merge

(on master) git merge feature

rebase before

After (merge commit created):

merge

Fast-Forward — Remember pointers?

  • When possible, Git will NOT create merge-commits and just fast-forward: bumping the branch pointer
  • You can prevent it using the git merge --no-ff option
Fast-forward illustration

Using Merge

Using Rebase

$ git checkout master
$ git merge feature
Updating 38d98a8..d92c9b5
Fast-forward
$ git checkout master
$ git rebase feature
First, rewinding head to replay your work on top of it...
Fast-forwarded master to feature.

Tips & tricks

Git reflog can save your a$$: keeps track of everywhere you went by

help

Example:

$ git reflog
f7d3b1 HEAD@{0}: commit (amend): Added reset + compulsory lolcat
440a3bf HEAD@{1}: commit (amend): Added reset + details
c830885 HEAD@{2}: commit: Ajout reset
36b4dce HEAD@{3}: commit: Passe sur les ajustements: ff, intro...
5ef0aa8 HEAD@{4}: commit (amend): On sa mis dacor
8e51635 HEAD@{5}: rebase -i (finish): returning to refs/heads/master
8e51635 HEAD@{6}: rebase -i (fixup): On s'a mis dacor
b6d8c99 HEAD@{7}: rebase -i (pick): On s'a mis dacor

What if you know you introduced a bug between one commit and another?

But there’s 1000 commits between them?

How to find out the offending one?

  • Git bisect: search bug by dichotomy (binary search)!

Repository lifecycle & manipulations

Granularity

One repository, one lifecycle.

  • One version number
  • If many parts, everything released each time

How to aggregate many repositories afterwards? Just merge!

git init repo1 && cd repo1 && git commit -m "Initial 1" --allow-empty && cd ..
git init repo2 && cd repo2 && git commit -m "Initial 2" --allow-empty
git remote add other file://$PWD/../repo1
git fetch other
git merge other/master -m "let's merge them"
git log --oneline --graph
*   c2be901 let's merge them
|\
| * 1763514 Initial 1
* 8208b0a Initial 2

How to explode one repository into multiple ones, remove some file from all commits…​

filter-branch is your friend.

EGit & JGit

  • EGit is the Git Plugin for Eclipse
  • JGit is the library in pure Java implementing the Git Version Control System

EGit has been pretty buggy in the past, but now has become definitely usable.

Even supports some of the features where GUI actually makes a lot of sense: staging interactively the lines you want.

egit add p

JGit provides (among others) a fluent API to interact with Git repositories:

git clone example
Git.cloneRepository()
   .setDirectory("/path/to/git/repository")
   .setURI("git://gitserver/somerepo.git")
   .setBare(false)
   .call();
git fetch example
Git.open("/some/repository")
   .fetch()
   .setRemoveDeletedRefs(true)
   .setTagOpt(TagOpt.FETCH_TAGS)
   .call();

Enough talk, let’s practice!

Conclusion & Recommentations

  • Git can be simple when used like Subversion
  • But can become complex to master when using it thoroughly
  • In case of errors or just logs, really read the output!
  • With Git, always know where you’re in the graph and what you want to do
Tell me and I forget, teach me and I may remember, involve me and I learn.
Benjamin Franklin

/